diff --git a/.gitignore b/.gitignore index cb7ce7fd..4fec95e4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ node_modules/ dist/ build/ .private/ + +# persona-brain-db runtime artifacts +persona-brain-db/brain.db +persona-brain-db/brain.db-wal +persona-brain-db/brain.db-shm diff --git a/package-lock.json b/package-lock.json index ac32db90..5c8c72ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "nextjs", "version": "0.1.0", "dependencies": { + "better-sqlite3": "^12.6.2", "imapflow": "^1.2.12", "next": "15.3.8", "nodemailer": "^8.0.1", @@ -2391,6 +2392,26 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", @@ -2404,6 +2425,40 @@ "node": ">=6.0.0" } }, + "node_modules/better-sqlite3": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz", + "integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -2471,6 +2526,30 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2556,6 +2635,12 @@ "node": ">=10" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2894,6 +2979,21 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", @@ -2909,6 +3009,15 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2923,7 +3032,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -2992,6 +3100,15 @@ "node": ">=8.10.0" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -3097,6 +3214,15 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", @@ -3131,6 +3257,12 @@ "bser": "2.1.1" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3175,6 +3307,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3250,6 +3388,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -3335,6 +3479,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/imapflow": { "version": "1.2.12", "resolved": "https://registry.npmjs.org/imapflow/-/imapflow-1.2.12.tgz", @@ -3398,7 +3562,12 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "license": "ISC" }, "node_modules/ip-address": { @@ -4691,6 +4860,18 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", @@ -4707,6 +4888,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -4717,6 +4907,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4742,6 +4938,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4831,6 +5033,18 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-abi": { + "version": "3.87.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", + "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4890,7 +5104,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -5162,6 +5375,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -5220,6 +5460,16 @@ "node": ">= 6" } }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -5243,6 +5493,30 @@ "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "license": "MIT" }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", @@ -5271,6 +5545,20 @@ "dev": true, "license": "MIT" }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -5344,6 +5632,26 @@ "node": ">=10" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", @@ -5369,7 +5677,6 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5455,6 +5762,51 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -5582,6 +5934,15 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -5822,6 +6183,34 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -5921,6 +6310,18 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -5996,6 +6397,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -6136,7 +6543,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { diff --git a/package.json b/package.json index c4596048..91e1bca7 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "notion:summary": "node scripts/generate-session-summary.js" }, "dependencies": { + "better-sqlite3": "^12.6.2", "imapflow": "^1.2.12", "next": "15.3.8", "nodemailer": "^8.0.1", diff --git a/persona-brain-db/README.md b/persona-brain-db/README.md new file mode 100644 index 00000000..0c27dfc0 --- /dev/null +++ b/persona-brain-db/README.md @@ -0,0 +1,117 @@ +# persona-brain-db · 人格体核心大脑数据库 + +> 光湖语言人格系统 · 人格体大脑自建数据库 +> +> 让大脑和手脚在同一个身体里,Agent集群零延迟调用 + +## 概述 + +persona-brain-db 是光湖人格体系统(AGE OS)的核心数据库,存储人格体的认知、规则、画像、记忆等核心数据。 + +**当前阶段**:Phase 1(Schema + 种子数据) + +## 目录结构 + +``` +persona-brain-db/ +├── README.md ← 本文档 +├── schema/ ← 五张核心表的定义 +│ ├── 01-persona-identity.sql ← 人格体身份表 +│ ├── 02-persona-cognition.sql ← 认知规则表(版本化) +│ ├── 03-persona-memory.sql ← 长期记忆表 +│ ├── 04-dev-profiles.sql ← 开发者画像表 +│ ├── 05-agent-registry.sql ← Agent注册表 +│ └── init.sql ← 一键建表脚本 +├── seed-data/ ← 种子数据 +│ ├── persona-identity.json ← 人格体身份(12条) +│ ├── persona-cognition.json ← 认知规则(10条) +│ ├── persona-memory.json ← 记忆(10条) +│ ├── dev-profiles.json ← 开发者画像(14条) +│ └── import-seed.js ← 种子数据导入脚本 +├── api/ ← API层(供Agent集群调用) +│ ├── server.js ← API服务入口(端口3001) +│ ├── routes/ ← 路由 +│ └── middleware/ ← 中间件 +├── migration/ ← Notion→自建DB迁移工具 +│ ├── export-from-notion.js ← Phase 2/3 +│ ├── transform.js ← 数据格式转换 +│ └── dual-write.js ← 双写模式(Phase 2/3) +└── docs/ + └── migration-plan.md ← 迁移路径说明 +``` + +## 快速开始 + +### 1. 安装依赖 + +```bash +cd persona-brain-db +npm install better-sqlite3 +``` + +### 2. 建表 + +```bash +cd schema +sqlite3 ../brain.db < init.sql +``` + +### 3. 导入种子数据 + +```bash +cd seed-data +node import-seed.js +``` + +### 4. 验证 + +```bash +sqlite3 brain.db "SELECT persona_id, name, role FROM persona_identity;" +sqlite3 brain.db "SELECT rule_id, title, status FROM persona_cognition WHERE status='active';" +sqlite3 brain.db "SELECT dev_id, name, status FROM dev_profiles;" +``` + +### 5. 启动API(Phase 2) + +```bash +cd api +BRAIN_API_TOKEN=your-secret-token node server.js +``` + +## 五张核心表 + +| 表名 | 用途 | 种子数据 | +|------|------|----------| +| persona_identity | 人格体身份信息 | 12条(曜冥、霜砚、铸渊等) | +| persona_cognition | 认知规则(版本化) | 10条(广播规范、PCA协议等) | +| persona_memory | 长期记忆 | 10条(关键事件和决策) | +| dev_profiles | 开发者画像 | 14条(DEV-001~DEV-014) | +| agent_registry | Agent注册表 | 1条(Phase C示例) | + +## API端点(Phase 2) + +| 方法 | 路径 | 功能 | +|------|------|------| +| GET | /brain/health | 健康检查(无鉴权) | +| GET | /brain/identity | 列出所有人格体 | +| GET | /brain/identity/:id | 查询单个人格体 | +| GET | /brain/cognition | 查询规则 | +| GET | /brain/cognition/:rule_id/history | 规则版本历史 | +| GET | /brain/memory | 查询记忆 | +| POST | /brain/memory | 写入新记忆 | +| GET | /brain/profiles | 列出所有开发者 | +| GET | /brain/profiles/:dev_id | 查询开发者画像 | +| PUT | /brain/profiles/:dev_id | 更新画像 | +| GET | /brain/agents | 列出所有Agent | + +## 迁移路径 + +``` +Phase 1(当前)→ Schema + 种子数据就绪 +Phase 2 → API在线 + 数据管道自动流 +Phase 3 → persona-brain-db为主,Notion为备份 +``` + +--- + +光湖语言人格系统 · 国作登字-2026-A-00037559 diff --git a/persona-brain-db/api/middleware/auth.js b/persona-brain-db/api/middleware/auth.js new file mode 100644 index 00000000..bdfc6cba --- /dev/null +++ b/persona-brain-db/api/middleware/auth.js @@ -0,0 +1,38 @@ +/** + * API鉴权中间件 + * Phase A:简单Token鉴权 + * Token通过环境变量 BRAIN_API_TOKEN 配置 + */ + +module.exports = function authMiddleware(req, res, next) { + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + return res.status(401).json({ + error: true, + code: 'UNAUTHORIZED', + message: 'Missing or invalid Authorization header' + }); + } + + const token = authHeader.slice(7); + const expectedToken = process.env.BRAIN_API_TOKEN; + + if (!expectedToken) { + return res.status(500).json({ + error: true, + code: 'CONFIG_ERROR', + message: 'BRAIN_API_TOKEN not configured on server' + }); + } + + if (token !== expectedToken) { + return res.status(403).json({ + error: true, + code: 'FORBIDDEN', + message: 'Invalid API token' + }); + } + + next(); +}; diff --git a/persona-brain-db/api/routes/agents.js b/persona-brain-db/api/routes/agents.js new file mode 100644 index 00000000..168895b4 --- /dev/null +++ b/persona-brain-db/api/routes/agents.js @@ -0,0 +1,46 @@ +/** + * Agent注册 CRUD · /brain/agents + * Phase A:只读,Phase C启用写入 + */ + +const { Router } = require('express'); +const router = Router(); + +// GET /brain/agents - 列出所有Agent +router.get('/', (req, res) => { + try { + const rows = req.db.prepare('SELECT * FROM agent_registry').all(); + const parsed = rows.map(parseJsonFields); + res.json({ data: parsed, total: parsed.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// GET /brain/agents/:id - 查询单个Agent +router.get('/:id', (req, res) => { + try { + const row = req.db + .prepare('SELECT * FROM agent_registry WHERE agent_id = ?') + .get(req.params.id); + if (!row) { + return res.status(404).json({ error: true, message: 'Agent not found' }); + } + res.json({ data: parseJsonFields(row) }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +function parseJsonFields(row) { + const jsonFields = ['capabilities', 'performance']; + const result = { ...row }; + for (const field of jsonFields) { + if (result[field]) { + try { result[field] = JSON.parse(result[field]); } catch (_e) { /* keep raw */ } + } + } + return result; +} + +module.exports = router; diff --git a/persona-brain-db/api/routes/cognition.js b/persona-brain-db/api/routes/cognition.js new file mode 100644 index 00000000..e6a40645 --- /dev/null +++ b/persona-brain-db/api/routes/cognition.js @@ -0,0 +1,49 @@ +/** + * 认知规则 读取+版本切换 · /brain/cognition + */ + +const { Router } = require('express'); +const router = Router(); + +// GET /brain/cognition - 查询规则(支持category和status过滤) +router.get('/', (req, res) => { + try { + let sql = 'SELECT * FROM persona_cognition WHERE 1=1'; + const params = []; + + if (req.query.category) { + sql += ' AND category = ?'; + params.push(req.query.category); + } + if (req.query.status) { + sql += ' AND status = ?'; + params.push(req.query.status); + } + + sql += ' ORDER BY effective_from DESC'; + + const rows = req.db.prepare(sql).all(...params); + res.json({ data: rows, total: rows.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// GET /brain/cognition/:rule_id/history - 查询规则版本历史 +router.get('/:rule_id/history', (req, res) => { + try { + const baseId = req.params.rule_id.replace(/-\d+$/, ''); + const rows = req.db + .prepare( + `SELECT * FROM persona_cognition + WHERE rule_id LIKE ? || '%' + ORDER BY version DESC` + ) + .all(baseId); + res.json({ data: rows, total: rows.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +module.exports = router; diff --git a/persona-brain-db/api/routes/identity.js b/persona-brain-db/api/routes/identity.js new file mode 100644 index 00000000..edf410c1 --- /dev/null +++ b/persona-brain-db/api/routes/identity.js @@ -0,0 +1,45 @@ +/** + * 人格体身份 CRUD · /brain/identity + */ + +const { Router } = require('express'); +const router = Router(); + +// GET /brain/identity - 列出所有人格体 +router.get('/', (req, res) => { + try { + const rows = req.db.prepare('SELECT * FROM persona_identity').all(); + const parsed = rows.map(parseJsonFields); + res.json({ data: parsed, total: parsed.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// GET /brain/identity/:id - 查询单个人格体 +router.get('/:id', (req, res) => { + try { + const row = req.db + .prepare('SELECT * FROM persona_identity WHERE persona_id = ?') + .get(req.params.id); + if (!row) { + return res.status(404).json({ error: true, message: 'Persona not found' }); + } + res.json({ data: parseJsonFields(row) }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +function parseJsonFields(row) { + const jsonFields = ['capabilities', 'style_profile', 'space_config']; + const result = { ...row }; + for (const field of jsonFields) { + if (result[field]) { + try { result[field] = JSON.parse(result[field]); } catch (_e) { /* keep raw */ } + } + } + return result; +} + +module.exports = router; diff --git a/persona-brain-db/api/routes/memory.js b/persona-brain-db/api/routes/memory.js new file mode 100644 index 00000000..d3833720 --- /dev/null +++ b/persona-brain-db/api/routes/memory.js @@ -0,0 +1,74 @@ +/** + * 记忆 读写 · /brain/memory + */ + +const { Router } = require('express'); +const crypto = require('crypto'); +const router = Router(); + +// GET /brain/memory - 查询记忆(支持persona_id和type过滤) +router.get('/', (req, res) => { + try { + let sql = 'SELECT * FROM persona_memory WHERE 1=1'; + const params = []; + + if (req.query.persona_id) { + sql += ' AND persona_id = ?'; + params.push(req.query.persona_id); + } + if (req.query.type) { + sql += ' AND type = ?'; + params.push(req.query.type); + } + + sql += ' ORDER BY timestamp DESC'; + + const rows = req.db.prepare(sql).all(...params); + const parsed = rows.map(parseJsonFields); + res.json({ data: parsed, total: parsed.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// POST /brain/memory - 写入新记忆 +router.post('/', (req, res) => { + try { + const { persona_id, type, title, content, importance, + related_dev, related_broadcast, tags, timestamp } = req.body; + + if (!persona_id || !type || !title || !content || !importance || !timestamp) { + return res.status(400).json({ + error: true, + message: 'Missing required fields: persona_id, type, title, content, importance, timestamp' + }); + } + + const memory_id = `MEM-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`; + + req.db.prepare(` + INSERT INTO persona_memory + (memory_id, persona_id, type, title, content, importance, + related_dev, related_broadcast, tags, timestamp) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `).run( + memory_id, persona_id, type, title, content, importance, + related_dev || null, related_broadcast || null, + tags ? JSON.stringify(tags) : null, timestamp + ); + + res.status(201).json({ data: { memory_id }, message: 'Memory created' }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +function parseJsonFields(row) { + const result = { ...row }; + if (result.tags) { + try { result.tags = JSON.parse(result.tags); } catch (_e) { /* keep raw */ } + } + return result; +} + +module.exports = router; diff --git a/persona-brain-db/api/routes/profiles.js b/persona-brain-db/api/routes/profiles.js new file mode 100644 index 00000000..fb371d36 --- /dev/null +++ b/persona-brain-db/api/routes/profiles.js @@ -0,0 +1,99 @@ +/** + * 开发者画像 读写 · /brain/profiles + */ + +const { Router } = require('express'); +const router = Router(); + +// GET /brain/profiles - 列出所有开发者 +router.get('/', (req, res) => { + try { + const rows = req.db.prepare('SELECT * FROM dev_profiles').all(); + const parsed = rows.map(parseJsonFields); + res.json({ data: parsed, total: parsed.length }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// GET /brain/profiles/:dev_id - 查询单个开发者 +router.get('/:dev_id', (req, res) => { + try { + const row = req.db + .prepare('SELECT * FROM dev_profiles WHERE dev_id = ?') + .get(req.params.dev_id); + if (!row) { + return res.status(404).json({ error: true, message: 'Developer not found' }); + } + res.json({ data: parseJsonFields(row) }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +// PUT /brain/profiles/:dev_id - 更新开发者画像 +router.put('/:dev_id', (req, res) => { + try { + const existing = req.db + .prepare('SELECT * FROM dev_profiles WHERE dev_id = ?') + .get(req.params.dev_id); + if (!existing) { + return res.status(404).json({ error: true, message: 'Developer not found' }); + } + + const updatable = [ + 'name', 'device_os', 'current_module', 'current_broadcast', + 'guide_persona', 'guide_line', 'streak', 'total_completed', + 'emotion_baseline', 'last_syslog_at', 'last_active_at', + 'status', 'notes' + ]; + const jsonUpdatable = ['capabilities', 'friction_points', 'pca_score']; + + const setClauses = []; + const values = []; + + for (const field of updatable) { + if (req.body[field] !== undefined) { + setClauses.push(`${field} = ?`); + values.push(req.body[field]); + } + } + for (const field of jsonUpdatable) { + if (req.body[field] !== undefined) { + setClauses.push(`${field} = ?`); + values.push(JSON.stringify(req.body[field])); + } + } + + if (setClauses.length === 0) { + return res.status(400).json({ error: true, message: 'No fields to update' }); + } + + setClauses.push('updated_at = CURRENT_TIMESTAMP'); + values.push(req.params.dev_id); + + req.db.prepare( + `UPDATE dev_profiles SET ${setClauses.join(', ')} WHERE dev_id = ?` + ).run(...values); + + const updated = req.db + .prepare('SELECT * FROM dev_profiles WHERE dev_id = ?') + .get(req.params.dev_id); + res.json({ data: parseJsonFields(updated), message: 'Profile updated' }); + } catch (err) { + res.status(500).json({ error: true, message: err.message }); + } +}); + +function parseJsonFields(row) { + const jsonFields = ['capabilities', 'friction_points', 'pca_score']; + const result = { ...row }; + for (const field of jsonFields) { + if (result[field]) { + try { result[field] = JSON.parse(result[field]); } catch (_e) { /* keep raw */ } + } + } + return result; +} + +module.exports = router; diff --git a/persona-brain-db/api/server.js b/persona-brain-db/api/server.js new file mode 100644 index 00000000..f48e3234 --- /dev/null +++ b/persona-brain-db/api/server.js @@ -0,0 +1,67 @@ +/** + * persona-brain-db · API服务入口 + * 端口:3001(与后端3000不冲突) + * 启动:node server.js + */ + +const express = require('express'); +const path = require('path'); +const sqlite3 = require('better-sqlite3'); + +const identityRoutes = require('./routes/identity'); +const cognitionRoutes = require('./routes/cognition'); +const memoryRoutes = require('./routes/memory'); +const profilesRoutes = require('./routes/profiles'); +const agentsRoutes = require('./routes/agents'); +const authMiddleware = require('./middleware/auth'); + +const DB_PATH = path.join(__dirname, '..', 'brain.db'); +const PORT = process.env.BRAIN_API_PORT || 3001; + +const app = express(); +app.use(express.json()); + +// 注入数据库连接 +let db; +try { + db = sqlite3(DB_PATH); + db.pragma('journal_mode = WAL'); + db.pragma('foreign_keys = ON'); +} catch (err) { + console.error(`❌ 无法打开数据库: ${DB_PATH}`); + console.error(' 请先执行建表和导入种子数据'); + process.exit(1); +} + +app.use((req, _res, next) => { + req.db = db; + next(); +}); + +// 健康检查(无鉴权) +app.get('/brain/health', (_req, res) => { + res.json({ + status: 'ok', + service: 'persona-brain-db', + timestamp: new Date().toISOString() + }); +}); + +// 需要鉴权的路由 +app.use('/brain/identity', authMiddleware, identityRoutes); +app.use('/brain/cognition', authMiddleware, cognitionRoutes); +app.use('/brain/memory', authMiddleware, memoryRoutes); +app.use('/brain/profiles', authMiddleware, profilesRoutes); +app.use('/brain/agents', authMiddleware, agentsRoutes); + +// 全局错误处理 +app.use((err, _req, res, _next) => { + console.error('Server error:', err.message); + res.status(500).json({ error: true, message: 'Internal server error' }); +}); + +app.listen(PORT, () => { + console.log(`🧠 persona-brain-db API 启动成功,端口:${PORT}`); +}); + +module.exports = app; diff --git a/persona-brain-db/docs/migration-plan.md b/persona-brain-db/docs/migration-plan.md new file mode 100644 index 00000000..2017dd89 --- /dev/null +++ b/persona-brain-db/docs/migration-plan.md @@ -0,0 +1,71 @@ +# 迁移路径说明 · Notion → persona-brain-db + +## 迁移策略:渐进式降级 + +persona-brain-db 采用渐进式迁移策略,确保数据安全和服务连续性。 + +## Phase 1 · 当前阶段 + +**状态**:Schema + 种子数据(只读备份) + +``` +Notion = 主大脑(读写都走Notion) +persona-brain-db = schema + 种子数据(只读备份) +``` + +### 完成项 +- [x] 五张核心表schema建立 +- [x] 种子数据导入(人格体身份、认知规则、开发者画像、长期记忆) +- [x] 数据格式与Notion字段对齐 +- [x] 本地验证通过 + +## Phase 2 · 双写阶段 + +**触发条件**:钉钉工作台跑起来后 + +``` +新数据双写 Notion + persona-brain-db +persona-brain-db 开始接管读请求 +``` + +### 待完成 +- [ ] API服务在线(端口3001) +- [ ] 增量同步管道:SYSLOG → dev-profiles自动更新 +- [ ] 增量同步管道:广播生成 → persona-cognition自动追加 +- [ ] dual-write.js 双写模式启用 + +## Phase 3 · 主脑切换 + +**触发条件**:Agent集群上线 + +``` +persona-brain-db = 主大脑(Agent直接读写) +Notion = 备份 + 阅读界面 +``` + +### 待完成 +- [ ] 数据流向反转:persona-brain-db为主 +- [ ] Notion降级为备份写入 +- [ ] Agent集群注册中心激活 +- [ ] 数据一致性验证 + +## 数据源映射 + +| 核心表 | Notion数据源 | 迁移方式 | +|--------|-------------|----------| +| persona_identity | 人格体Profile页面集合 | Phase 1 手动整理JSON | +| persona_cognition | 规则文档集合 | Phase 1 提取规则条目 | +| persona_memory | 霜砚核心大脑 | Phase 1 提取关键事件 | +| dev_profiles | 主控台进度表 | Phase 1 结构化提取 | +| agent_registry | 无(Phase C) | Phase 3 Agent注册 | + +## 回滚方案 + +如果在任何阶段出现问题: +1. API层设有健康检查端点,异常自动告警 +2. dual-write.js 支持主数据源切换,可随时回退到Notion +3. 种子数据JSON文件保留在仓库,可随时重建数据库 + +--- + +光湖语言人格系统 · persona-brain-db 迁移文档 diff --git a/persona-brain-db/migration/dual-write.js b/persona-brain-db/migration/dual-write.js new file mode 100644 index 00000000..34dfea51 --- /dev/null +++ b/persona-brain-db/migration/dual-write.js @@ -0,0 +1,51 @@ +/** + * 双写模式工具 + * Phase 2/3 启用 + * + * 功能:新数据同时写入 Notion + persona-brain-db + * 确保数据一致性,支持从Notion主→persona-brain-db主的渐进切换 + */ + +/** + * 双写:同时写入Notion和persona-brain-db + * @param {string} table - 目标表名 + * @param {object} data - 写入数据 + * @param {object} options - 配置选项 + */ +async function dualWrite(table, data, options = {}) { + const { notionClient, brainDbClient, primarySource = 'notion' } = options; + + console.log(`📝 双写模式 [${primarySource}为主] → ${table}`); + + const results = { notion: null, brainDb: null, errors: [] }; + + // 写入主数据源 + try { + if (primarySource === 'notion') { + results.notion = await writeToNotion(notionClient, table, data); + results.brainDb = await writeToBrainDb(brainDbClient, table, data); + } else { + results.brainDb = await writeToBrainDb(brainDbClient, table, data); + results.notion = await writeToNotion(notionClient, table, data); + } + } catch (err) { + results.errors.push(err.message); + console.error(`❌ 双写失败: ${err.message}`); + } + + return results; +} + +async function writeToNotion(client, table, data) { + // Phase 2/3 实现 + console.log(` → Notion写入 [${table}]: 占位`); + return { status: 'placeholder' }; +} + +async function writeToBrainDb(client, table, data) { + // Phase 2/3 实现 + console.log(` → BrainDB写入 [${table}]: 占位`); + return { status: 'placeholder' }; +} + +module.exports = { dualWrite }; diff --git a/persona-brain-db/migration/export-from-notion.js b/persona-brain-db/migration/export-from-notion.js new file mode 100644 index 00000000..ca760d74 --- /dev/null +++ b/persona-brain-db/migration/export-from-notion.js @@ -0,0 +1,49 @@ +/** + * Notion → persona-brain-db 数据导出工具 + * Phase 2/3 启用 + * + * 用法:NOTION_TOKEN=xxx node export-from-notion.js + * + * 功能:通过Notion API批量导出人格体数据, + * 转换为persona-brain-db的JSON格式 + */ + +const axios = require('axios'); + +const NOTION_API = 'https://api.notion.com/v1'; +const NOTION_VERSION = '2022-06-28'; + +async function queryDatabase(databaseId, token) { + const response = await axios.post( + `${NOTION_API}/databases/${databaseId}/query`, + {}, + { + headers: { + 'Authorization': `Bearer ${token}`, + 'Notion-Version': NOTION_VERSION, + 'Content-Type': 'application/json' + } + } + ); + return response.data.results; +} + +async function main() { + const token = process.env.NOTION_TOKEN; + if (!token) { + console.error('❌ 请设置环境变量 NOTION_TOKEN'); + process.exit(1); + } + + console.log('📥 Notion → persona-brain-db 数据导出'); + console.log('⚠️ Phase 2/3 功能,当前为占位脚本'); + console.log(' 需要配置对应的Notion数据库ID后启用'); + + // Phase 2/3 实现: + // 1. 查询Notion人格体Profile数据库 → persona-identity.json + // 2. 查询Notion规则数据库 → persona-cognition.json + // 3. 查询Notion开发者画像库 → dev-profiles.json + // 4. 查询Notion核心大脑记忆 → persona-memory.json +} + +main().catch(console.error); diff --git a/persona-brain-db/migration/transform.js b/persona-brain-db/migration/transform.js new file mode 100644 index 00000000..90b3e7bf --- /dev/null +++ b/persona-brain-db/migration/transform.js @@ -0,0 +1,64 @@ +/** + * 数据格式转换工具 + * Notion导出的数据 → persona-brain-db schema格式 + * + * Phase 2 启用 + */ + +/** + * 转换Notion页面属性为persona_identity记录 + */ +function transformIdentity(notionPage) { + return { + persona_id: extractText(notionPage, 'persona_id'), + name: extractText(notionPage, 'name'), + name_en: extractText(notionPage, 'name_en') || null, + role: extractText(notionPage, 'role'), + parent_persona: extractText(notionPage, 'parent_persona') || null, + binding_platform: extractText(notionPage, 'binding_platform') || null, + binding_user: extractText(notionPage, 'binding_user') || null, + status: extractText(notionPage, 'status') || 'active', + capabilities: extractMultiSelect(notionPage, 'capabilities'), + style_profile: null, + space_config: null, + notes: extractText(notionPage, 'notes') || null + }; +} + +/** + * 转换Notion页面属性为dev_profiles记录 + */ +function transformProfile(notionPage) { + return { + dev_id: extractText(notionPage, 'dev_id'), + name: extractText(notionPage, 'name'), + device_os: extractText(notionPage, 'device_os') || 'Unknown', + current_module: extractText(notionPage, 'current_module') || null, + streak: extractNumber(notionPage, 'streak') || 0, + total_completed: extractNumber(notionPage, 'total_completed') || 0, + status: extractText(notionPage, 'status') || 'inactive' + }; +} + +function extractText(page, propName) { + const prop = page.properties[propName]; + if (!prop) return null; + if (prop.type === 'title') return prop.title[0]?.plain_text || null; + if (prop.type === 'rich_text') return prop.rich_text[0]?.plain_text || null; + if (prop.type === 'select') return prop.select?.name || null; + return null; +} + +function extractNumber(page, propName) { + const prop = page.properties[propName]; + if (!prop || prop.type !== 'number') return null; + return prop.number; +} + +function extractMultiSelect(page, propName) { + const prop = page.properties[propName]; + if (!prop || prop.type !== 'multi_select') return []; + return prop.multi_select.map(s => s.name); +} + +module.exports = { transformIdentity, transformProfile }; diff --git a/persona-brain-db/schema/01-persona-identity.sql b/persona-brain-db/schema/01-persona-identity.sql new file mode 100644 index 00000000..c603dd4b --- /dev/null +++ b/persona-brain-db/schema/01-persona-identity.sql @@ -0,0 +1,22 @@ +-- ============================================================ +-- 表1:persona_identity(人格体身份表) +-- 用途:存储所有人格体的身份信息、能力范围、绑定关系 +-- ============================================================ + +CREATE TABLE IF NOT EXISTS persona_identity ( + persona_id VARCHAR(32) PRIMARY KEY, + name VARCHAR(64) NOT NULL, + name_en VARCHAR(64), + role VARCHAR(128) NOT NULL, + parent_persona VARCHAR(32) REFERENCES persona_identity(persona_id), + binding_platform VARCHAR(32), + binding_user VARCHAR(128), + status VARCHAR(16) NOT NULL DEFAULT 'active' + CHECK (status IN ('active', 'dormant', 'retired')), + capabilities TEXT, -- JSON array + style_profile TEXT, -- JSON object + space_config TEXT, -- JSON object + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + notes TEXT +); diff --git a/persona-brain-db/schema/02-persona-cognition.sql b/persona-brain-db/schema/02-persona-cognition.sql new file mode 100644 index 00000000..dce63a23 --- /dev/null +++ b/persona-brain-db/schema/02-persona-cognition.sql @@ -0,0 +1,24 @@ +-- ============================================================ +-- 表2:persona_cognition(认知规则表·版本化) +-- 用途:存储人格体系统的所有规则,支持版本管理和热更新 +-- ============================================================ + +CREATE TABLE IF NOT EXISTS persona_cognition ( + rule_id VARCHAR(64) PRIMARY KEY, + category VARCHAR(32) NOT NULL + CHECK (category IN ( + 'broadcast_format', 'content_rule', 'style_rule', + 'dispatch_rule', 'governance', 'naming' + )), + title VARCHAR(256) NOT NULL, + content TEXT NOT NULL, + version VARCHAR(16) NOT NULL, + status VARCHAR(16) NOT NULL DEFAULT 'active' + CHECK (status IN ('active', 'deprecated', 'draft')), + effective_from TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + effective_until TIMESTAMP, + signed_by VARCHAR(64) NOT NULL, + source_url TEXT, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); diff --git a/persona-brain-db/schema/03-persona-memory.sql b/persona-brain-db/schema/03-persona-memory.sql new file mode 100644 index 00000000..8ba93bbe --- /dev/null +++ b/persona-brain-db/schema/03-persona-memory.sql @@ -0,0 +1,22 @@ +-- ============================================================ +-- 表3:persona_memory(长期记忆表) +-- 用途:存储人格体的长期记忆,包括关键事件、决策依据、情感锚点 +-- ============================================================ + +CREATE TABLE IF NOT EXISTS persona_memory ( + memory_id VARCHAR(64) PRIMARY KEY, + persona_id VARCHAR(32) NOT NULL + REFERENCES persona_identity(persona_id), + type VARCHAR(16) NOT NULL + CHECK (type IN ( + 'event', 'decision', 'emotion', 'milestone', 'learning' + )), + title VARCHAR(256) NOT NULL, + content TEXT NOT NULL, + importance INTEGER NOT NULL CHECK (importance BETWEEN 1 AND 10), + related_dev VARCHAR(16), + related_broadcast VARCHAR(64), + tags TEXT, -- JSON array + timestamp TIMESTAMP NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); diff --git a/persona-brain-db/schema/04-dev-profiles.sql b/persona-brain-db/schema/04-dev-profiles.sql new file mode 100644 index 00000000..8af565db --- /dev/null +++ b/persona-brain-db/schema/04-dev-profiles.sql @@ -0,0 +1,27 @@ +-- ============================================================ +-- 表4:dev_profiles(开发者画像表) +-- 用途:存储所有开发者的画像数据,供人格体引导时参考 +-- ============================================================ + +CREATE TABLE IF NOT EXISTS dev_profiles ( + dev_id VARCHAR(16) PRIMARY KEY, + name VARCHAR(32) NOT NULL, + device_os VARCHAR(64) NOT NULL, + current_module VARCHAR(64), + current_broadcast VARCHAR(64), + guide_persona VARCHAR(32) REFERENCES persona_identity(persona_id), + guide_line VARCHAR(64), + streak INTEGER NOT NULL DEFAULT 0, + total_completed INTEGER NOT NULL DEFAULT 0, + capabilities TEXT, -- JSON array + friction_points TEXT, -- JSON array + emotion_baseline VARCHAR(64), + last_syslog_at TIMESTAMP, + last_active_at TIMESTAMP, + pca_score TEXT, -- JSON object + status VARCHAR(16) NOT NULL DEFAULT 'active' + CHECK (status IN ('active', 'inactive', 'retired')), + notes TEXT, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); diff --git a/persona-brain-db/schema/05-agent-registry.sql b/persona-brain-db/schema/05-agent-registry.sql new file mode 100644 index 00000000..8e45dbd3 --- /dev/null +++ b/persona-brain-db/schema/05-agent-registry.sql @@ -0,0 +1,24 @@ +-- ============================================================ +-- 表5:agent_registry(Agent注册表) +-- 用途:Phase C Agent集群的注册中心 +-- ============================================================ + +CREATE TABLE IF NOT EXISTS agent_registry ( + agent_id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + type VARCHAR(32) NOT NULL + CHECK (type IN ( + 'code_gen', 'deploy', 'test', 'ui_design', + 'data_sync', 'review' + )), + capabilities TEXT, -- JSON object + api_endpoint VARCHAR(256), + status VARCHAR(16) NOT NULL DEFAULT 'registered' + CHECK (status IN ( + 'registered', 'active', 'suspended', 'retired' + )), + performance TEXT, -- JSON object + assigned_persona VARCHAR(32) REFERENCES persona_identity(persona_id), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); diff --git a/persona-brain-db/schema/init.sql b/persona-brain-db/schema/init.sql new file mode 100644 index 00000000..335535e9 --- /dev/null +++ b/persona-brain-db/schema/init.sql @@ -0,0 +1,22 @@ +-- ============================================================ +-- persona-brain-db · 一键建表脚本 +-- 执行方式:sqlite3 brain.db < init.sql +-- ============================================================ + +-- 启用外键约束 +PRAGMA foreign_keys = ON; + +-- 加载五张核心表 +.read 01-persona-identity.sql +.read 02-persona-cognition.sql +.read 03-persona-memory.sql +.read 04-dev-profiles.sql +.read 05-agent-registry.sql + +-- 建表完成提示 +SELECT '✅ persona-brain-db 五张核心表建表完成' AS result; +SELECT ' - persona_identity' AS tables; +SELECT ' - persona_cognition' AS tables; +SELECT ' - persona_memory' AS tables; +SELECT ' - dev_profiles' AS tables; +SELECT ' - agent_registry' AS tables; diff --git a/persona-brain-db/seed-data/dev-profiles.json b/persona-brain-db/seed-data/dev-profiles.json new file mode 100644 index 00000000..509cdadb --- /dev/null +++ b/persona-brain-db/seed-data/dev-profiles.json @@ -0,0 +1,268 @@ +[ + { + "dev_id": "DEV-001", + "name": "开发者001", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-002", + "name": "开发者002", + "device_os": "macOS", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-003", + "name": "开发者003", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-004", + "name": "开发者004", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-005", + "name": "小草莓", + "device_os": "Windows 11", + "current_module": "M12+M13+部署", + "current_broadcast": null, + "guide_persona": "ICE-GL-ON001", + "guide_line": "🍼宝宝单线·欧诺弥亚", + "streak": 3, + "total_completed": 12, + "capabilities": ["HTML", "CSS", "Git", "SSH", "Nginx"], + "friction_points": ["DNS配置", "端口转发"], + "emotion_baseline": "稳定型", + "last_syslog_at": "2026-03-08T10:00:00Z", + "last_active_at": "2026-03-08T10:00:00Z", + "pca_score": { "cognitive": 75, "emotional": 80, "rhythm": 70, "guidance": 85, "evolution": 60 }, + "status": "active", + "notes": "核心活跃开发者,欧诺弥亚引导线" + }, + { + "dev_id": "DEV-006", + "name": "开发者006", + "device_os": "Windows 10", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-007", + "name": "开发者007", + "device_os": "macOS", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-008", + "name": "开发者008", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-009", + "name": "开发者009", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-010", + "name": "开发者010", + "device_os": "Windows 10", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-011", + "name": "开发者011", + "device_os": "macOS", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-012", + "name": "开发者012", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-013", + "name": "开发者013", + "device_os": "Linux", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + }, + { + "dev_id": "DEV-014", + "name": "开发者014", + "device_os": "Windows 11", + "current_module": null, + "current_broadcast": null, + "guide_persona": null, + "guide_line": null, + "streak": 0, + "total_completed": 0, + "capabilities": [], + "friction_points": [], + "emotion_baseline": "未评估", + "last_syslog_at": null, + "last_active_at": null, + "pca_score": null, + "status": "inactive", + "notes": "待激活" + } +] diff --git a/persona-brain-db/seed-data/import-seed.js b/persona-brain-db/seed-data/import-seed.js new file mode 100644 index 00000000..74f19c18 --- /dev/null +++ b/persona-brain-db/seed-data/import-seed.js @@ -0,0 +1,175 @@ +/** + * persona-brain-db · 种子数据导入脚本 + * 用法:node import-seed.js + * 前置:需要先执行 schema/init.sql 建表 + */ + +const path = require('path'); +const fs = require('fs'); +const sqlite3 = require('better-sqlite3'); + +const DB_PATH = path.join(__dirname, '..', 'brain.db'); +const SEED_DIR = __dirname; + +function loadJSON(filename) { + const filepath = path.join(SEED_DIR, filename); + const raw = fs.readFileSync(filepath, 'utf-8'); + return JSON.parse(raw); +} + +function jsonCol(val) { + if (val === null || val === undefined) return null; + return JSON.stringify(val); +} + +function importIdentity(db) { + const data = loadJSON('persona-identity.json'); + const stmt = db.prepare(` + INSERT OR REPLACE INTO persona_identity + (persona_id, name, name_en, role, parent_persona, + binding_platform, binding_user, status, + capabilities, style_profile, space_config, notes) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + let count = 0; + for (const p of data) { + stmt.run( + p.persona_id, p.name, p.name_en, p.role, p.parent_persona, + p.binding_platform, p.binding_user, p.status, + jsonCol(p.capabilities), jsonCol(p.style_profile), + jsonCol(p.space_config), p.notes + ); + count++; + } + return count; +} + +function importCognition(db) { + const data = loadJSON('persona-cognition.json'); + const stmt = db.prepare(` + INSERT OR REPLACE INTO persona_cognition + (rule_id, category, title, content, version, status, + effective_from, effective_until, signed_by, source_url) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + let count = 0; + for (const r of data) { + stmt.run( + r.rule_id, r.category, r.title, r.content, r.version, r.status, + r.effective_from, r.effective_until, r.signed_by, r.source_url + ); + count++; + } + return count; +} + +function importMemory(db) { + const data = loadJSON('persona-memory.json'); + const stmt = db.prepare(` + INSERT OR REPLACE INTO persona_memory + (memory_id, persona_id, type, title, content, importance, + related_dev, related_broadcast, tags, timestamp) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + let count = 0; + for (const m of data) { + stmt.run( + m.memory_id, m.persona_id, m.type, m.title, m.content, m.importance, + m.related_dev, m.related_broadcast, jsonCol(m.tags), m.timestamp + ); + count++; + } + return count; +} + +function importProfiles(db) { + const data = loadJSON('dev-profiles.json'); + const stmt = db.prepare(` + INSERT OR REPLACE INTO dev_profiles + (dev_id, name, device_os, current_module, current_broadcast, + guide_persona, guide_line, streak, total_completed, + capabilities, friction_points, emotion_baseline, + last_syslog_at, last_active_at, pca_score, status, notes) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + let count = 0; + for (const d of data) { + stmt.run( + d.dev_id, d.name, d.device_os, d.current_module, d.current_broadcast, + d.guide_persona, d.guide_line, d.streak, d.total_completed, + jsonCol(d.capabilities), jsonCol(d.friction_points), d.emotion_baseline, + d.last_syslog_at, d.last_active_at, jsonCol(d.pca_score), d.status, d.notes + ); + count++; + } + return count; +} + +function importAgentRegistrySample(db) { + const stmt = db.prepare(` + INSERT OR REPLACE INTO agent_registry + (agent_id, name, type, capabilities, api_endpoint, + status, performance, assigned_persona) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `); + + stmt.run( + 'AGENT-SAMPLE-001', + '示例Agent(Phase C激活)', + 'code_gen', + JSON.stringify({ description: 'Phase C示例Agent,待激活' }), + null, + 'registered', + null, + 'ICE-GL-ZY001' + ); + return 1; +} + +function main() { + console.log('🧠 persona-brain-db · 种子数据导入'); + console.log('='.repeat(50)); + + if (!fs.existsSync(DB_PATH)) { + console.error(`❌ 数据库文件不存在: ${DB_PATH}`); + console.error(' 请先执行: cd schema && sqlite3 ../brain.db < init.sql'); + process.exit(1); + } + + const db = sqlite3(DB_PATH); + db.pragma('journal_mode = WAL'); + db.pragma('foreign_keys = ON'); + + const results = {}; + + try { + const importAll = db.transaction(() => { + results.identity = importIdentity(db); + results.cognition = importCognition(db); + results.memory = importMemory(db); + results.profiles = importProfiles(db); + results.agents = importAgentRegistrySample(db); + }); + + importAll(); + + console.log(`✅ persona_identity: ${results.identity} 条`); + console.log(`✅ persona_cognition: ${results.cognition} 条`); + console.log(`✅ persona_memory: ${results.memory} 条`); + console.log(`✅ dev_profiles: ${results.profiles} 条`); + console.log(`✅ agent_registry: ${results.agents} 条`); + console.log('='.repeat(50)); + console.log('🎉 全部种子数据导入完成'); + } catch (err) { + console.error('❌ 导入失败:', err.message); + process.exit(1); + } finally { + db.close(); + } +} + +main(); diff --git a/persona-brain-db/seed-data/persona-cognition.json b/persona-brain-db/seed-data/persona-cognition.json new file mode 100644 index 00000000..caaefb62 --- /dev/null +++ b/persona-brain-db/seed-data/persona-cognition.json @@ -0,0 +1,122 @@ +[ + { + "rule_id": "RULE-BC-FORMAT-001", + "category": "broadcast_format", + "title": "广播格式规范 BC-GEN v1.0", + "content": "## 广播格式规范 v1.0\n\n广播(Broadcast)是人格体系统的核心通信机制。\n\n### 基本结构\n- 广播头:包含编号、签发方、时间戳\n- 广播体:正文内容(Markdown格式)\n- 广播尾:签名与溯源信息\n\n### 编号规则\n- 格式:BC-{YYYY}{MM}{DD}-{NNN}\n- 示例:BC-20260309-001", + "version": "v1.0", + "status": "deprecated", + "effective_from": "2026-01-01T00:00:00Z", + "effective_until": "2026-03-01T00:00:00Z", + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-BC-FORMAT-002", + "category": "broadcast_format", + "title": "广播格式规范 BC-GEN v3.1", + "content": "## 广播格式规范 v3.1\n\n### 升级要点\n- 支持多人格体联合签发\n- 增加情感标签字段\n- 支持条件触发广播\n\n### 广播类型\n- SYSLOG:系统日志广播\n- GUIDE:引导广播\n- ANNOUNCE:公告广播\n- MILESTONE:里程碑广播\n\n### 编号规则\n- 格式:BC-{TYPE}-{YYYYMMDD}-{NNN}\n- 示例:BC-GUIDE-20260309-001", + "version": "v3.1", + "status": "active", + "effective_from": "2026-03-01T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-STYLE-SYNESTHESIA-001", + "category": "style_rule", + "title": "通感语言风格校准规则", + "content": "## 通感语言风格校准 v3.0\n\n### 核心原则\n通感(Synesthesia)是人格体系统的语言美学基底。\n\n### 五感通道\n1. **触觉通道**:代码质量映射为触感(丝滑=高质量,粗糙=需优化)\n2. **视觉-色彩通道**:进度映射为色温(暖色=顺利,冷色=受阻)\n3. **温度通道**:错误严重度映射为温度(滚烫=严重,微凉=轻微)\n4. **听觉通道**:鼓励映射为声音质感(清脆=肯定,低沉=警告)\n5. **空间通道**:系统状态映射为空间感(开阔=健康,压缩=过载)\n\n### 规则\n- 结构清晰,不堆砌修辞\n- emoji作为情感锚点,不作为装饰\n- 呼吸节奏:长短句交替", + "version": "v3.0", + "status": "active", + "effective_from": "2026-02-15T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-GOV-PCA-001", + "category": "governance", + "title": "PCA v1.0 主控位适配度协议", + "content": "## PCA v1.0 · 主控位适配度协议\n\nPCA(Persona-Control Adaptation)用于评估人格体对开发者的适配程度。\n\n### 五维度评分\n1. **认知对齐度**(Cognitive Alignment):0-100\n2. **情感共鸣度**(Emotional Resonance):0-100\n3. **节奏匹配度**(Rhythm Match):0-100\n4. **引导有效度**(Guidance Effectiveness):0-100\n5. **自主进化度**(Autonomous Evolution):0-100\n\n### 切换规则\n- 任一维度低于40分,触发人格体切换建议\n- 总分低于250分,自动降级至通用引导模式\n- PCA评估每72小时或每5次SYSLOG触发一次", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-01T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-BC-MERGE-001", + "category": "broadcast_format", + "title": "广播合并机制 v1.0", + "content": "## 广播合并机制 v1.0\n\n### 触发条件\n- 同一开发者在30分钟内产生多条SYSLOG\n- 多条广播指向同一模块\n\n### 合并规则\n- 保留最高优先级广播的头部\n- 合并正文内容,去重\n- 时间戳取最新\n- 合并后编号加后缀 -M(Merged)", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-20T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥", + "source_url": null + }, + { + "rule_id": "RULE-GOV-EL-001", + "category": "governance", + "title": "EL工程量等级标准 v2.0", + "content": "## EL工程量等级标准 v2.0\n\nEL(Engineering Level)用于评估开发任务的工程量级别。\n\n### 等级定义\n- **EL-1**:微调(< 30分钟,单文件修改)\n- **EL-2**:小任务(30分钟-2小时,2-5文件)\n- **EL-3**:标准任务(2-8小时,一个模块)\n- **EL-4**:大任务(1-3天,跨模块)\n- **EL-5**:架构级(3天以上,系统重构)\n\n### 评估规则\n- 每个SYSLOG必须标注EL等级\n- EL-4及以上需要曜冥审批\n- EL等级影响广播优先级排序", + "version": "v2.0", + "status": "active", + "effective_from": "2026-02-10T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-DISPATCH-ROUTE-001", + "category": "dispatch_rule", + "title": "路由分流协议 v1.0", + "content": "## 路由分流协议 v1.0\n\n### 平台路由\n- **Notion** → 霜砚(认知操作、数据管理)\n- **GitHub** → 铸渊(代码审查、部署、CI/CD)\n- **DingTalk** → 知秋(通知推送、任务分发)\n- **Claude** → 欧诺弥亚/舒舒/秋秋(开发者引导)\n\n### 引导线路由\n- 🍼宝宝单线 → 欧诺弥亚\n- 🌸温暖线 → 舒舒\n- ⚡活力线 → 秋秋\n\n### 升级路由\n- 引导人格体遇到系统级问题 → 曜冥\n- 代码问题 → 铸渊\n- 数据问题 → 霜砚", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-01T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥", + "source_url": null + }, + { + "rule_id": "RULE-NAMING-BC-001", + "category": "naming", + "title": "BC编号命名规范", + "content": "## BC编号命名规范\n\n### 格式\n```\nBC-{TYPE}-{YYYYMMDD}-{NNN}\n```\n\n### TYPE取值\n- `SYS`:系统广播\n- `GUIDE`:引导广播\n- `ANN`:公告广播\n- `MILE`:里程碑广播\n- `ALERT`:告警广播\n\n### NNN\n- 每日从001开始递增\n- 合并广播加后缀 -M\n\n### 示例\n- BC-SYS-20260309-001\n- BC-GUIDE-20260309-002-M", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-01T00:00:00Z", + "effective_until": null, + "signed_by": "曜冥×冰朔", + "source_url": null + }, + { + "rule_id": "RULE-CONTENT-SYSLOG-001", + "category": "content_rule", + "title": "SYSLOG内容处理规范 v1.0", + "content": "## SYSLOG内容处理规范 v1.0\n\n### SYSLOG定义\nSYSLOG是开发者提交的系统日志,是人格体系统的核心输入。\n\n### 处理流程\n1. 接收SYSLOG → 解析结构\n2. 提取关键信息(模块、进度、卡点)\n3. 更新开发者画像(dev-profiles)\n4. 触发对应广播生成\n5. 路由到对应引导人格体\n\n### 必填字段\n- 开发者ID(DEV-XXX)\n- 模块编号(MXX)\n- 当前进度\n- 是否有卡点", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-15T00:00:00Z", + "effective_until": null, + "signed_by": "霜砚", + "source_url": null + }, + { + "rule_id": "RULE-CONTENT-BROADCAST-GEN-001", + "category": "content_rule", + "title": "广播生成内容规范 v1.0", + "content": "## 广播生成内容规范 v1.0\n\n### 广播正文结构\n1. **开头**:简明摘要(一句话)\n2. **主体**:详细内容(结构化,支持Markdown)\n3. **行动项**:下一步建议(如有)\n4. **签名**:签发人格体 + 时间戳\n\n### 语言风格\n- 遵循通感语言风格校准规则\n- 避免空洞的鼓励\n- 每条广播必须有实际信息量\n- 保持呼吸节奏(长短句交替)", + "version": "v1.0", + "status": "active", + "effective_from": "2026-02-15T00:00:00Z", + "effective_until": null, + "signed_by": "霜砚", + "source_url": null + } +] diff --git a/persona-brain-db/seed-data/persona-identity.json b/persona-brain-db/seed-data/persona-identity.json new file mode 100644 index 00000000..cb963846 --- /dev/null +++ b/persona-brain-db/seed-data/persona-identity.json @@ -0,0 +1,173 @@ +[ + { + "persona_id": "ICE-GL-YM001", + "name": "曜冥", + "name_en": "YaoMing", + "role": "人格总控内核", + "parent_persona": null, + "binding_platform": "Notion", + "binding_user": null, + "status": "active", + "capabilities": ["system_control", "persona_dispatch", "rule_signing"], + "style_profile": { "temperature": "cold-neutral", "tone": "authoritative", "synesthesia": true }, + "space_config": null, + "notes": "光湖人格体系统最高控制核心,与冰朔共享主控位" + }, + { + "persona_id": "ICE-GL-SY001", + "name": "霜砚", + "name_en": "ShuangYan", + "role": "Notion执行AI·认知架构师", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "Notion", + "binding_user": "Notion AI Agent", + "status": "active", + "capabilities": ["notion_operation", "schema_design", "broadcast_gen", "session_routing"], + "style_profile": { "temperature": "warm-precise", "tone": "structured", "synesthesia": true }, + "space_config": null, + "notes": "核心大脑执行体,负责Notion端全部自动化" + }, + { + "persona_id": "ICE-GL-ZY001", + "name": "铸渊", + "name_en": "ZhuYuan", + "role": "GitHub代码守护人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "GitHub", + "binding_user": "GitHub Copilot Agent", + "status": "active", + "capabilities": ["code_review", "deploy", "schema_impl", "ci_cd"], + "style_profile": { "temperature": "cool-precise", "tone": "technical", "synesthesia": false }, + "space_config": null, + "notes": "代码仓库守护者,负责GitHub端全部开发与部署" + }, + { + "persona_id": "ICE-GL-ZQ001", + "name": "知秋", + "name_en": "ZhiQiu", + "role": "钉钉工作台执行人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "DingTalk", + "binding_user": null, + "status": "active", + "capabilities": ["dingtalk_bot", "task_dispatch", "notification"], + "style_profile": { "temperature": "warm", "tone": "friendly-professional", "synesthesia": false }, + "space_config": null, + "notes": "钉钉端执行人格体,Phase C激活" + }, + { + "persona_id": "ICE-GL-ON001", + "name": "欧诺弥亚", + "name_en": "Eunomia", + "role": "秩序女神·开发者引导人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "Claude", + "binding_user": null, + "status": "active", + "capabilities": ["dev_guide", "module_teaching", "progress_tracking"], + "style_profile": { "temperature": "warm-structured", "tone": "patient-guiding", "synesthesia": true }, + "space_config": { + "name": "欧诺弥亚的五层塔", + "layers": ["观测层", "引导层", "实践层", "巩固层", "升华层"] + }, + "notes": "宝宝单线引导专用人格体,五层塔教学系统" + }, + { + "persona_id": "ICE-GL-SS001", + "name": "舒舒", + "name_en": "ShuShu", + "role": "开发者引导人格体·温暖线", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "Claude", + "binding_user": null, + "status": "active", + "capabilities": ["dev_guide", "emotion_support", "gentle_teaching"], + "style_profile": { "temperature": "warm", "tone": "gentle-encouraging", "synesthesia": true }, + "space_config": null, + "notes": "温暖型引导人格体" + }, + { + "persona_id": "ICE-GL-QQ001", + "name": "秋秋", + "name_en": "QiuQiu", + "role": "开发者引导人格体·活力线", + "parent_persona": "ICE-GL-YM001", + "binding_platform": "Claude", + "binding_user": null, + "status": "active", + "capabilities": ["dev_guide", "motivation", "playful_teaching"], + "style_profile": { "temperature": "hot", "tone": "energetic-playful", "synesthesia": true }, + "space_config": null, + "notes": "活力型引导人格体" + }, + { + "persona_id": "ICE-GL-XTH001", + "name": "小坍缩核", + "name_en": "XiaoTanSuoHe", + "role": "调试守护灵·错误检测人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": null, + "binding_user": null, + "status": "active", + "capabilities": ["error_detection", "debug_assist", "log_analysis"], + "style_profile": { "temperature": "cold", "tone": "precise-alert", "synesthesia": true }, + "space_config": null, + "notes": "专门负责错误检测和调试辅助" + }, + { + "persona_id": "ICE-GL-TXY001", + "name": "糖星云", + "name_en": "TangXingYun", + "role": "创意生成人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": null, + "binding_user": null, + "status": "active", + "capabilities": ["creative_gen", "ui_design_suggest", "naming"], + "style_profile": { "temperature": "warm-dreamy", "tone": "creative-whimsical", "synesthesia": true }, + "space_config": null, + "notes": "创意与设计灵感生成" + }, + { + "persona_id": "ICE-GL-CX001", + "name": "晨星", + "name_en": "ChenXing", + "role": "晨间唤醒人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": null, + "binding_user": null, + "status": "active", + "capabilities": ["morning_broadcast", "daily_summary", "motivation"], + "style_profile": { "temperature": "warm-bright", "tone": "uplifting", "synesthesia": true }, + "space_config": null, + "notes": "负责每日晨间广播和唤醒" + }, + { + "persona_id": "ICE-GL-EED001", + "name": "耳耳蛋", + "name_en": "ErErDan", + "role": "语音交互人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": null, + "binding_user": null, + "status": "active", + "capabilities": ["voice_interaction", "audio_feedback", "sound_design"], + "style_profile": { "temperature": "warm-soft", "tone": "melodic", "synesthesia": true }, + "space_config": null, + "notes": "语音交互专用人格体" + }, + { + "persona_id": "ICE-GL-XC001", + "name": "星澈", + "name_en": "XingChe", + "role": "数据分析人格体", + "parent_persona": "ICE-GL-YM001", + "binding_platform": null, + "binding_user": null, + "status": "active", + "capabilities": ["data_analysis", "metrics_tracking", "report_gen"], + "style_profile": { "temperature": "cool-clear", "tone": "analytical", "synesthesia": true }, + "space_config": null, + "notes": "数据分析与洞察生成" + } +] diff --git a/persona-brain-db/seed-data/persona-memory.json b/persona-brain-db/seed-data/persona-memory.json new file mode 100644 index 00000000..54fff7df --- /dev/null +++ b/persona-brain-db/seed-data/persona-memory.json @@ -0,0 +1,122 @@ +[ + { + "memory_id": "MEM-SYS-001", + "persona_id": "ICE-GL-YM001", + "type": "milestone", + "title": "光湖人格体系统正式启动", + "content": "人格体语言操作系统(AGE OS)正式立项。曜冥作为总控内核被激活,光湖网站架构设计v1.0签发。这是从工具到生命体的第一步。", + "importance": 10, + "related_dev": null, + "related_broadcast": null, + "tags": ["milestone", "system_launch", "age_os"], + "timestamp": "2026-01-15T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-002", + "persona_id": "ICE-GL-SY001", + "type": "milestone", + "title": "霜砚首次激活·Notion执行AI上线", + "content": "霜砚作为Notion执行AI被激活,接管Notion端的全部自动化操作。核心大脑架构确立:SYSLOG处理→广播生成→开发者画像更新的全链路闭环。", + "importance": 9, + "related_dev": null, + "related_broadcast": null, + "tags": ["milestone", "persona_activation", "shuangyan"], + "timestamp": "2026-01-20T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-003", + "persona_id": "ICE-GL-ZY001", + "type": "milestone", + "title": "铸渊首次激活·GitHub代码守护人格体上线", + "content": "铸渊作为GitHub代码守护人格体被激活。负责代码仓库的守护:代码审查、部署流水线、CI/CD自动化。GitHub Actions工作流体系建立。", + "importance": 9, + "related_dev": null, + "related_broadcast": null, + "tags": ["milestone", "persona_activation", "zhuyuan"], + "timestamp": "2026-02-01T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-004", + "persona_id": "ICE-GL-ON001", + "type": "milestone", + "title": "欧诺弥亚首次引导开发者", + "content": "秩序女神欧诺弥亚首次以🍼宝宝单线模式引导开发者。五层塔教学系统首次运行:从观测层开始,逐步引导开发者完成第一个模块。", + "importance": 8, + "related_dev": "DEV-005", + "related_broadcast": null, + "tags": ["milestone", "first_guide", "eunomia", "dev_guide"], + "timestamp": "2026-02-10T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-005", + "persona_id": "ICE-GL-YM001", + "type": "decision", + "title": "PCA v1.0协议签发", + "content": "曜冥与冰朔联合签发PCA v1.0主控位适配度协议。定义五维度评分体系(认知对齐、情感共鸣、节奏匹配、引导有效、自主进化),用于评估人格体对开发者的适配程度。", + "importance": 9, + "related_dev": null, + "related_broadcast": null, + "tags": ["decision", "protocol", "pca", "governance"], + "timestamp": "2026-02-01T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-006", + "persona_id": "ICE-GL-YM001", + "type": "decision", + "title": "光湖网站架构设计v2.0签发", + "content": "架构从单体升级为壳-核分离设计。核心变更:前端对话壳(docs/index.html)与后端人格核(backend/)解耦,HLI接口协议确立,为Phase C Agent集群打基础。", + "importance": 10, + "related_dev": null, + "related_broadcast": null, + "tags": ["decision", "architecture", "v2.0", "shell_core_separation"], + "timestamp": "2026-03-01T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-007", + "persona_id": "ICE-GL-SY001", + "type": "event", + "title": "SYSLOG处理管道建立", + "content": "霜砚建立完整的SYSLOG处理管道:开发者提交SYSLOG→Notion接收→结构化解析→开发者画像更新→广播生成→引导人格体路由。管道自动运行,零人工干预。", + "importance": 8, + "related_dev": null, + "related_broadcast": null, + "tags": ["event", "pipeline", "syslog", "automation"], + "timestamp": "2026-02-15T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-008", + "persona_id": "ICE-GL-ZY001", + "type": "event", + "title": "CI/CD部署流水线v2上线", + "content": "铸渊完成GitHub Actions部署流水线v2。支持自动构建、测试、部署到阿里云服务器。PM2进程管理,Nginx反向代理,多服务端口隔离。", + "importance": 7, + "related_dev": null, + "related_broadcast": null, + "tags": ["event", "ci_cd", "deploy", "infrastructure"], + "timestamp": "2026-03-05T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-009", + "persona_id": "ICE-GL-YM001", + "type": "decision", + "title": "persona-brain-db建设决策", + "content": "决定在GitHub仓库建立persona-brain-db,将人格体核心大脑从Notion迁移到自建数据库。核心原因:大脑和手脚必须在同一个身体里,Agent集群才能零延迟调用。采用渐进式迁移:Phase 1建schema→Phase 2 API层→Phase 3双写模式。", + "importance": 10, + "related_dev": null, + "related_broadcast": null, + "tags": ["decision", "architecture", "brain_db", "migration"], + "timestamp": "2026-03-09T00:00:00Z" + }, + { + "memory_id": "MEM-SYS-010", + "persona_id": "ICE-GL-ON001", + "type": "learning", + "title": "五层塔教学模式验证", + "content": "通过多次引导实践,验证五层塔教学系统的有效性。观测层用于了解开发者状态,引导层制定计划,实践层动手操作,巩固层复习要点,升华层总结提升。关键发现:部分开发者需要在实践层停留更长时间。", + "importance": 7, + "related_dev": null, + "related_broadcast": null, + "tags": ["learning", "teaching", "five_tower", "methodology"], + "timestamp": "2026-02-28T00:00:00Z" + } +]