laminark 2.21.9 → 2.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +3 -2
- package/plugin/.repair-log +6 -0
- package/plugin/CLAUDE.md +57 -8
- package/plugin/dist/hooks/handler.d.ts.map +1 -1
- package/plugin/dist/hooks/handler.js +49 -5
- package/plugin/dist/hooks/handler.js.map +1 -1
- package/plugin/dist/index.js +27 -25
- package/plugin/dist/index.js.map +1 -1
- package/plugin/dist/{tool-registry-D8un_AcG.mjs → tool-registry-Bi1Zdqkm.mjs} +62 -31
- package/plugin/dist/tool-registry-Bi1Zdqkm.mjs.map +1 -0
- package/plugin/node_modules/.bin/node-which +52 -0
- package/plugin/node_modules/.bin/prebuild-install +78 -0
- package/plugin/node_modules/.bin/rc +4 -0
- package/plugin/node_modules/.bin/semver +191 -0
- package/plugin/node_modules/.package-lock.json +2153 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/LICENSE.md +1 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/README.md +44 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/bun.lock +21 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/cli.js +12421 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/manifest.json +46 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/manifest.zst.json +46 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/package.json +42 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/resvg.wasm +0 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/sdk-tools.d.ts +2367 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts +2153 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs +59 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/tree-sitter-bash.wasm +0 -0
- package/plugin/node_modules/@anthropic-ai/claude-agent-sdk/tree-sitter.wasm +0 -0
- package/plugin/node_modules/@hono/node-server/README.md +357 -0
- package/plugin/node_modules/@hono/node-server/package.json +103 -0
- package/plugin/node_modules/@huggingface/jinja/LICENSE +21 -0
- package/plugin/node_modules/@huggingface/jinja/README.md +78 -0
- package/plugin/node_modules/@huggingface/jinja/package.json +54 -0
- package/plugin/node_modules/@huggingface/jinja/tsconfig.json +20 -0
- package/plugin/node_modules/@huggingface/transformers/LICENSE +202 -0
- package/plugin/node_modules/@huggingface/transformers/README.md +467 -0
- package/plugin/node_modules/@huggingface/transformers/package.json +90 -0
- package/plugin/node_modules/@img/colour/LICENSE.md +82 -0
- package/plugin/node_modules/@img/colour/README.md +15 -0
- package/plugin/node_modules/@img/colour/color.cjs +1594 -0
- package/plugin/node_modules/@img/colour/index.cjs +1 -0
- package/plugin/node_modules/@img/colour/package.json +45 -0
- package/plugin/node_modules/@img/sharp-libvips-linux-x64/README.md +46 -0
- package/plugin/node_modules/@img/sharp-libvips-linux-x64/package.json +42 -0
- package/plugin/node_modules/@img/sharp-libvips-linux-x64/versions.json +30 -0
- package/plugin/node_modules/@img/sharp-linux-x64/LICENSE +191 -0
- package/plugin/node_modules/@img/sharp-linux-x64/README.md +18 -0
- package/plugin/node_modules/@img/sharp-linux-x64/package.json +46 -0
- package/plugin/node_modules/@isaacs/fs-minipass/LICENSE +15 -0
- package/plugin/node_modules/@isaacs/fs-minipass/README.md +71 -0
- package/plugin/node_modules/@isaacs/fs-minipass/package.json +72 -0
- package/plugin/node_modules/@modelcontextprotocol/sdk/LICENSE +21 -0
- package/plugin/node_modules/@modelcontextprotocol/sdk/README.md +170 -0
- package/plugin/node_modules/@modelcontextprotocol/sdk/package.json +155 -0
- package/plugin/node_modules/@protobufjs/aspromise/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/aspromise/README.md +13 -0
- package/plugin/node_modules/@protobufjs/aspromise/index.d.ts +13 -0
- package/plugin/node_modules/@protobufjs/aspromise/index.js +52 -0
- package/plugin/node_modules/@protobufjs/aspromise/package.json +21 -0
- package/plugin/node_modules/@protobufjs/base64/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/base64/README.md +19 -0
- package/plugin/node_modules/@protobufjs/base64/index.d.ts +32 -0
- package/plugin/node_modules/@protobufjs/base64/index.js +139 -0
- package/plugin/node_modules/@protobufjs/base64/package.json +21 -0
- package/plugin/node_modules/@protobufjs/codegen/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/codegen/README.md +49 -0
- package/plugin/node_modules/@protobufjs/codegen/index.d.ts +31 -0
- package/plugin/node_modules/@protobufjs/codegen/index.js +99 -0
- package/plugin/node_modules/@protobufjs/codegen/package.json +13 -0
- package/plugin/node_modules/@protobufjs/eventemitter/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/eventemitter/README.md +22 -0
- package/plugin/node_modules/@protobufjs/eventemitter/index.d.ts +43 -0
- package/plugin/node_modules/@protobufjs/eventemitter/index.js +76 -0
- package/plugin/node_modules/@protobufjs/eventemitter/package.json +21 -0
- package/plugin/node_modules/@protobufjs/fetch/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/fetch/README.md +13 -0
- package/plugin/node_modules/@protobufjs/fetch/index.d.ts +56 -0
- package/plugin/node_modules/@protobufjs/fetch/index.js +115 -0
- package/plugin/node_modules/@protobufjs/fetch/package.json +25 -0
- package/plugin/node_modules/@protobufjs/float/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/float/README.md +102 -0
- package/plugin/node_modules/@protobufjs/float/index.d.ts +83 -0
- package/plugin/node_modules/@protobufjs/float/index.js +335 -0
- package/plugin/node_modules/@protobufjs/float/package.json +26 -0
- package/plugin/node_modules/@protobufjs/inquire/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/inquire/README.md +13 -0
- package/plugin/node_modules/@protobufjs/inquire/index.d.ts +9 -0
- package/plugin/node_modules/@protobufjs/inquire/index.js +17 -0
- package/plugin/node_modules/@protobufjs/inquire/package.json +21 -0
- package/plugin/node_modules/@protobufjs/path/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/path/README.md +19 -0
- package/plugin/node_modules/@protobufjs/path/index.d.ts +22 -0
- package/plugin/node_modules/@protobufjs/path/index.js +65 -0
- package/plugin/node_modules/@protobufjs/path/package.json +21 -0
- package/plugin/node_modules/@protobufjs/pool/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/pool/README.md +13 -0
- package/plugin/node_modules/@protobufjs/pool/index.d.ts +32 -0
- package/plugin/node_modules/@protobufjs/pool/index.js +48 -0
- package/plugin/node_modules/@protobufjs/pool/package.json +21 -0
- package/plugin/node_modules/@protobufjs/utf8/LICENSE +26 -0
- package/plugin/node_modules/@protobufjs/utf8/README.md +20 -0
- package/plugin/node_modules/@protobufjs/utf8/index.d.ts +24 -0
- package/plugin/node_modules/@protobufjs/utf8/index.js +105 -0
- package/plugin/node_modules/@protobufjs/utf8/package.json +21 -0
- package/plugin/node_modules/@types/node/LICENSE +21 -0
- package/plugin/node_modules/@types/node/README.md +15 -0
- package/plugin/node_modules/@types/node/assert.d.ts +955 -0
- package/plugin/node_modules/@types/node/async_hooks.d.ts +623 -0
- package/plugin/node_modules/@types/node/buffer.buffer.d.ts +466 -0
- package/plugin/node_modules/@types/node/buffer.d.ts +1810 -0
- package/plugin/node_modules/@types/node/child_process.d.ts +1428 -0
- package/plugin/node_modules/@types/node/cluster.d.ts +486 -0
- package/plugin/node_modules/@types/node/console.d.ts +151 -0
- package/plugin/node_modules/@types/node/constants.d.ts +20 -0
- package/plugin/node_modules/@types/node/crypto.d.ts +4065 -0
- package/plugin/node_modules/@types/node/dgram.d.ts +564 -0
- package/plugin/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/plugin/node_modules/@types/node/dns.d.ts +922 -0
- package/plugin/node_modules/@types/node/domain.d.ts +166 -0
- package/plugin/node_modules/@types/node/events.d.ts +1054 -0
- package/plugin/node_modules/@types/node/fs.d.ts +4676 -0
- package/plugin/node_modules/@types/node/globals.d.ts +150 -0
- package/plugin/node_modules/@types/node/globals.typedarray.d.ts +101 -0
- package/plugin/node_modules/@types/node/http.d.ts +2167 -0
- package/plugin/node_modules/@types/node/http2.d.ts +2480 -0
- package/plugin/node_modules/@types/node/https.d.ts +405 -0
- package/plugin/node_modules/@types/node/index.d.ts +115 -0
- package/plugin/node_modules/@types/node/inspector.d.ts +224 -0
- package/plugin/node_modules/@types/node/inspector.generated.d.ts +4226 -0
- package/plugin/node_modules/@types/node/module.d.ts +819 -0
- package/plugin/node_modules/@types/node/net.d.ts +933 -0
- package/plugin/node_modules/@types/node/os.d.ts +507 -0
- package/plugin/node_modules/@types/node/package.json +155 -0
- package/plugin/node_modules/@types/node/path.d.ts +187 -0
- package/plugin/node_modules/@types/node/perf_hooks.d.ts +643 -0
- package/plugin/node_modules/@types/node/process.d.ts +2161 -0
- package/plugin/node_modules/@types/node/punycode.d.ts +117 -0
- package/plugin/node_modules/@types/node/querystring.d.ts +152 -0
- package/plugin/node_modules/@types/node/quic.d.ts +910 -0
- package/plugin/node_modules/@types/node/readline.d.ts +541 -0
- package/plugin/node_modules/@types/node/repl.d.ts +415 -0
- package/plugin/node_modules/@types/node/sea.d.ts +162 -0
- package/plugin/node_modules/@types/node/sqlite.d.ts +955 -0
- package/plugin/node_modules/@types/node/stream.d.ts +1760 -0
- package/plugin/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/plugin/node_modules/@types/node/test.d.ts +2240 -0
- package/plugin/node_modules/@types/node/timers.d.ts +159 -0
- package/plugin/node_modules/@types/node/tls.d.ts +1198 -0
- package/plugin/node_modules/@types/node/trace_events.d.ts +197 -0
- package/plugin/node_modules/@types/node/tty.d.ts +250 -0
- package/plugin/node_modules/@types/node/url.d.ts +519 -0
- package/plugin/node_modules/@types/node/util.d.ts +1662 -0
- package/plugin/node_modules/@types/node/v8.d.ts +983 -0
- package/plugin/node_modules/@types/node/vm.d.ts +1208 -0
- package/plugin/node_modules/@types/node/wasi.d.ts +202 -0
- package/plugin/node_modules/@types/node/worker_threads.d.ts +717 -0
- package/plugin/node_modules/@types/node/zlib.d.ts +618 -0
- package/plugin/node_modules/accepts/HISTORY.md +250 -0
- package/plugin/node_modules/accepts/LICENSE +23 -0
- package/plugin/node_modules/accepts/README.md +140 -0
- package/plugin/node_modules/accepts/index.js +238 -0
- package/plugin/node_modules/accepts/package.json +47 -0
- package/plugin/node_modules/ajv/.runkit_example.js +23 -0
- package/plugin/node_modules/ajv/LICENSE +22 -0
- package/plugin/node_modules/ajv/README.md +207 -0
- package/plugin/node_modules/ajv/dist/2019.js +61 -0
- package/plugin/node_modules/ajv/dist/2020.js +55 -0
- package/plugin/node_modules/ajv/dist/ajv.js +50 -0
- package/plugin/node_modules/ajv/dist/core.js +618 -0
- package/plugin/node_modules/ajv/lib/2019.ts +81 -0
- package/plugin/node_modules/ajv/lib/2020.ts +75 -0
- package/plugin/node_modules/ajv/lib/ajv.ts +70 -0
- package/plugin/node_modules/ajv/lib/core.ts +892 -0
- package/plugin/node_modules/ajv/lib/jtd.ts +132 -0
- package/plugin/node_modules/ajv/package.json +127 -0
- package/plugin/node_modules/ajv-formats/LICENSE +21 -0
- package/plugin/node_modules/ajv-formats/README.md +125 -0
- package/plugin/node_modules/ajv-formats/dist/formats.d.ts +9 -0
- package/plugin/node_modules/ajv-formats/dist/formats.js +208 -0
- package/plugin/node_modules/ajv-formats/dist/formats.js.map +1 -0
- package/plugin/node_modules/ajv-formats/dist/index.d.ts +15 -0
- package/plugin/node_modules/ajv-formats/dist/index.js +37 -0
- package/plugin/node_modules/ajv-formats/dist/index.js.map +1 -0
- package/plugin/node_modules/ajv-formats/dist/limit.d.ts +10 -0
- package/plugin/node_modules/ajv-formats/dist/limit.js +69 -0
- package/plugin/node_modules/ajv-formats/dist/limit.js.map +1 -0
- package/plugin/node_modules/ajv-formats/package.json +74 -0
- package/plugin/node_modules/ajv-formats/src/formats.ts +269 -0
- package/plugin/node_modules/ajv-formats/src/index.ts +62 -0
- package/plugin/node_modules/ajv-formats/src/limit.ts +99 -0
- package/plugin/node_modules/base64-js/LICENSE +21 -0
- package/plugin/node_modules/base64-js/README.md +34 -0
- package/plugin/node_modules/base64-js/base64js.min.js +1 -0
- package/plugin/node_modules/base64-js/index.d.ts +3 -0
- package/plugin/node_modules/base64-js/index.js +150 -0
- package/plugin/node_modules/base64-js/package.json +47 -0
- package/plugin/node_modules/better-sqlite3/LICENSE +21 -0
- package/plugin/node_modules/better-sqlite3/README.md +99 -0
- package/plugin/node_modules/better-sqlite3/binding.gyp +38 -0
- package/plugin/node_modules/better-sqlite3/deps/common.gypi +68 -0
- package/plugin/node_modules/better-sqlite3/deps/copy.js +31 -0
- package/plugin/node_modules/better-sqlite3/deps/defines.gypi +41 -0
- package/plugin/node_modules/better-sqlite3/deps/download.sh +122 -0
- package/plugin/node_modules/better-sqlite3/deps/sqlite3.gyp +80 -0
- package/plugin/node_modules/better-sqlite3/deps/test_extension.c +21 -0
- package/plugin/node_modules/better-sqlite3/lib/database.js +90 -0
- package/plugin/node_modules/better-sqlite3/lib/index.js +3 -0
- package/plugin/node_modules/better-sqlite3/lib/sqlite-error.js +20 -0
- package/plugin/node_modules/better-sqlite3/lib/util.js +12 -0
- package/plugin/node_modules/better-sqlite3/package.json +59 -0
- package/plugin/node_modules/better-sqlite3/src/addon.cpp +47 -0
- package/plugin/node_modules/better-sqlite3/src/better_sqlite3.cpp +74 -0
- package/plugin/node_modules/bindings/LICENSE.md +22 -0
- package/plugin/node_modules/bindings/README.md +98 -0
- package/plugin/node_modules/bindings/bindings.js +221 -0
- package/plugin/node_modules/bindings/package.json +28 -0
- package/plugin/node_modules/bl/.travis.yml +17 -0
- package/plugin/node_modules/bl/BufferList.js +396 -0
- package/plugin/node_modules/bl/LICENSE.md +13 -0
- package/plugin/node_modules/bl/README.md +247 -0
- package/plugin/node_modules/bl/bl.js +84 -0
- package/plugin/node_modules/bl/package.json +37 -0
- package/plugin/node_modules/body-parser/LICENSE +23 -0
- package/plugin/node_modules/body-parser/README.md +494 -0
- package/plugin/node_modules/body-parser/index.js +71 -0
- package/plugin/node_modules/body-parser/package.json +52 -0
- package/plugin/node_modules/boolean/.eslintrc.json +3 -0
- package/plugin/node_modules/boolean/.npmpackagejsonlintrc.json +3 -0
- package/plugin/node_modules/boolean/.releaserc.json +3 -0
- package/plugin/node_modules/boolean/CHANGELOG.md +70 -0
- package/plugin/node_modules/boolean/LICENSE.txt +8 -0
- package/plugin/node_modules/boolean/README.md +95 -0
- package/plugin/node_modules/boolean/licenseCheck.json +16 -0
- package/plugin/node_modules/boolean/package.json +46 -0
- package/plugin/node_modules/boolean/tsconfig.json +19 -0
- package/plugin/node_modules/buffer/AUTHORS.md +70 -0
- package/plugin/node_modules/buffer/LICENSE +21 -0
- package/plugin/node_modules/buffer/README.md +410 -0
- package/plugin/node_modules/buffer/index.d.ts +186 -0
- package/plugin/node_modules/buffer/index.js +1817 -0
- package/plugin/node_modules/buffer/package.json +96 -0
- package/plugin/node_modules/bytes/History.md +97 -0
- package/plugin/node_modules/bytes/LICENSE +23 -0
- package/plugin/node_modules/bytes/Readme.md +152 -0
- package/plugin/node_modules/bytes/index.js +170 -0
- package/plugin/node_modules/bytes/package.json +42 -0
- package/plugin/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
- package/plugin/node_modules/call-bind-apply-helpers/.nycrc +9 -0
- package/plugin/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
- package/plugin/node_modules/call-bind-apply-helpers/LICENSE +21 -0
- package/plugin/node_modules/call-bind-apply-helpers/README.md +62 -0
- package/plugin/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
- package/plugin/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
- package/plugin/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
- package/plugin/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
- package/plugin/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
- package/plugin/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
- package/plugin/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
- package/plugin/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
- package/plugin/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
- package/plugin/node_modules/call-bind-apply-helpers/index.js +15 -0
- package/plugin/node_modules/call-bind-apply-helpers/package.json +85 -0
- package/plugin/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
- package/plugin/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
- package/plugin/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
- package/plugin/node_modules/call-bound/.eslintrc +13 -0
- package/plugin/node_modules/call-bound/.nycrc +9 -0
- package/plugin/node_modules/call-bound/CHANGELOG.md +42 -0
- package/plugin/node_modules/call-bound/LICENSE +21 -0
- package/plugin/node_modules/call-bound/README.md +53 -0
- package/plugin/node_modules/call-bound/index.d.ts +94 -0
- package/plugin/node_modules/call-bound/index.js +19 -0
- package/plugin/node_modules/call-bound/package.json +99 -0
- package/plugin/node_modules/call-bound/tsconfig.json +10 -0
- package/plugin/node_modules/chownr/LICENSE.md +63 -0
- package/plugin/node_modules/chownr/README.md +3 -0
- package/plugin/node_modules/chownr/package.json +69 -0
- package/plugin/node_modules/content-disposition/HISTORY.md +72 -0
- package/plugin/node_modules/content-disposition/LICENSE +22 -0
- package/plugin/node_modules/content-disposition/README.md +142 -0
- package/plugin/node_modules/content-disposition/index.js +458 -0
- package/plugin/node_modules/content-disposition/package.json +43 -0
- package/plugin/node_modules/content-type/HISTORY.md +29 -0
- package/plugin/node_modules/content-type/LICENSE +22 -0
- package/plugin/node_modules/content-type/README.md +94 -0
- package/plugin/node_modules/content-type/index.js +225 -0
- package/plugin/node_modules/content-type/package.json +42 -0
- package/plugin/node_modules/cookie/LICENSE +24 -0
- package/plugin/node_modules/cookie/README.md +317 -0
- package/plugin/node_modules/cookie/SECURITY.md +25 -0
- package/plugin/node_modules/cookie/index.js +335 -0
- package/plugin/node_modules/cookie/package.json +44 -0
- package/plugin/node_modules/cookie-signature/History.md +70 -0
- package/plugin/node_modules/cookie-signature/LICENSE +22 -0
- package/plugin/node_modules/cookie-signature/Readme.md +23 -0
- package/plugin/node_modules/cookie-signature/index.js +47 -0
- package/plugin/node_modules/cookie-signature/package.json +24 -0
- package/plugin/node_modules/cors/LICENSE +22 -0
- package/plugin/node_modules/cors/README.md +277 -0
- package/plugin/node_modules/cors/package.json +42 -0
- package/plugin/node_modules/cross-spawn/LICENSE +21 -0
- package/plugin/node_modules/cross-spawn/README.md +89 -0
- package/plugin/node_modules/cross-spawn/index.js +39 -0
- package/plugin/node_modules/cross-spawn/package.json +73 -0
- package/plugin/node_modules/debug/LICENSE +20 -0
- package/plugin/node_modules/debug/README.md +481 -0
- package/plugin/node_modules/debug/package.json +64 -0
- package/plugin/node_modules/decompress-response/index.d.ts +22 -0
- package/plugin/node_modules/decompress-response/index.js +58 -0
- package/plugin/node_modules/decompress-response/license +9 -0
- package/plugin/node_modules/decompress-response/package.json +56 -0
- package/plugin/node_modules/decompress-response/readme.md +48 -0
- package/plugin/node_modules/deep-extend/CHANGELOG.md +46 -0
- package/plugin/node_modules/deep-extend/LICENSE +20 -0
- package/plugin/node_modules/deep-extend/README.md +91 -0
- package/plugin/node_modules/deep-extend/index.js +1 -0
- package/plugin/node_modules/deep-extend/package.json +62 -0
- package/plugin/node_modules/define-data-property/.eslintrc +24 -0
- package/plugin/node_modules/define-data-property/.nycrc +13 -0
- package/plugin/node_modules/define-data-property/CHANGELOG.md +70 -0
- package/plugin/node_modules/define-data-property/LICENSE +21 -0
- package/plugin/node_modules/define-data-property/README.md +67 -0
- package/plugin/node_modules/define-data-property/index.d.ts +12 -0
- package/plugin/node_modules/define-data-property/index.js +56 -0
- package/plugin/node_modules/define-data-property/package.json +106 -0
- package/plugin/node_modules/define-data-property/tsconfig.json +59 -0
- package/plugin/node_modules/define-properties/.editorconfig +13 -0
- package/plugin/node_modules/define-properties/.eslintrc +19 -0
- package/plugin/node_modules/define-properties/.nycrc +9 -0
- package/plugin/node_modules/define-properties/CHANGELOG.md +91 -0
- package/plugin/node_modules/define-properties/LICENSE +21 -0
- package/plugin/node_modules/define-properties/README.md +84 -0
- package/plugin/node_modules/define-properties/index.js +47 -0
- package/plugin/node_modules/define-properties/package.json +88 -0
- package/plugin/node_modules/depd/History.md +103 -0
- package/plugin/node_modules/depd/LICENSE +22 -0
- package/plugin/node_modules/depd/Readme.md +280 -0
- package/plugin/node_modules/depd/index.js +538 -0
- package/plugin/node_modules/depd/package.json +45 -0
- package/plugin/node_modules/detect-libc/LICENSE +201 -0
- package/plugin/node_modules/detect-libc/README.md +163 -0
- package/plugin/node_modules/detect-libc/index.d.ts +14 -0
- package/plugin/node_modules/detect-libc/package.json +44 -0
- package/plugin/node_modules/detect-node/LICENSE +21 -0
- package/plugin/node_modules/detect-node/Readme.md +30 -0
- package/plugin/node_modules/detect-node/browser.js +2 -0
- package/plugin/node_modules/detect-node/index.esm.js +2 -0
- package/plugin/node_modules/detect-node/index.js +2 -0
- package/plugin/node_modules/detect-node/package.json +25 -0
- package/plugin/node_modules/dunder-proto/.eslintrc +5 -0
- package/plugin/node_modules/dunder-proto/.nycrc +13 -0
- package/plugin/node_modules/dunder-proto/CHANGELOG.md +24 -0
- package/plugin/node_modules/dunder-proto/LICENSE +21 -0
- package/plugin/node_modules/dunder-proto/README.md +54 -0
- package/plugin/node_modules/dunder-proto/get.d.ts +5 -0
- package/plugin/node_modules/dunder-proto/get.js +30 -0
- package/plugin/node_modules/dunder-proto/package.json +76 -0
- package/plugin/node_modules/dunder-proto/set.d.ts +5 -0
- package/plugin/node_modules/dunder-proto/set.js +35 -0
- package/plugin/node_modules/dunder-proto/tsconfig.json +9 -0
- package/plugin/node_modules/ee-first/LICENSE +22 -0
- package/plugin/node_modules/ee-first/README.md +80 -0
- package/plugin/node_modules/ee-first/index.js +95 -0
- package/plugin/node_modules/ee-first/package.json +29 -0
- package/plugin/node_modules/encodeurl/LICENSE +22 -0
- package/plugin/node_modules/encodeurl/README.md +109 -0
- package/plugin/node_modules/encodeurl/index.js +60 -0
- package/plugin/node_modules/encodeurl/package.json +40 -0
- package/plugin/node_modules/end-of-stream/LICENSE +21 -0
- package/plugin/node_modules/end-of-stream/README.md +54 -0
- package/plugin/node_modules/end-of-stream/index.js +96 -0
- package/plugin/node_modules/end-of-stream/package.json +37 -0
- package/plugin/node_modules/es-define-property/.eslintrc +13 -0
- package/plugin/node_modules/es-define-property/.nycrc +9 -0
- package/plugin/node_modules/es-define-property/CHANGELOG.md +29 -0
- package/plugin/node_modules/es-define-property/LICENSE +21 -0
- package/plugin/node_modules/es-define-property/README.md +49 -0
- package/plugin/node_modules/es-define-property/index.d.ts +3 -0
- package/plugin/node_modules/es-define-property/index.js +14 -0
- package/plugin/node_modules/es-define-property/package.json +81 -0
- package/plugin/node_modules/es-define-property/tsconfig.json +10 -0
- package/plugin/node_modules/es-errors/.eslintrc +5 -0
- package/plugin/node_modules/es-errors/CHANGELOG.md +40 -0
- package/plugin/node_modules/es-errors/LICENSE +21 -0
- package/plugin/node_modules/es-errors/README.md +55 -0
- package/plugin/node_modules/es-errors/eval.d.ts +3 -0
- package/plugin/node_modules/es-errors/eval.js +4 -0
- package/plugin/node_modules/es-errors/index.d.ts +3 -0
- package/plugin/node_modules/es-errors/index.js +4 -0
- package/plugin/node_modules/es-errors/package.json +80 -0
- package/plugin/node_modules/es-errors/range.d.ts +3 -0
- package/plugin/node_modules/es-errors/range.js +4 -0
- package/plugin/node_modules/es-errors/ref.d.ts +3 -0
- package/plugin/node_modules/es-errors/ref.js +4 -0
- package/plugin/node_modules/es-errors/syntax.d.ts +3 -0
- package/plugin/node_modules/es-errors/syntax.js +4 -0
- package/plugin/node_modules/es-errors/tsconfig.json +49 -0
- package/plugin/node_modules/es-errors/type.d.ts +3 -0
- package/plugin/node_modules/es-errors/type.js +4 -0
- package/plugin/node_modules/es-errors/uri.d.ts +3 -0
- package/plugin/node_modules/es-errors/uri.js +4 -0
- package/plugin/node_modules/es-object-atoms/.eslintrc +16 -0
- package/plugin/node_modules/es-object-atoms/CHANGELOG.md +37 -0
- package/plugin/node_modules/es-object-atoms/LICENSE +21 -0
- package/plugin/node_modules/es-object-atoms/README.md +63 -0
- package/plugin/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
- package/plugin/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
- package/plugin/node_modules/es-object-atoms/ToObject.d.ts +7 -0
- package/plugin/node_modules/es-object-atoms/ToObject.js +10 -0
- package/plugin/node_modules/es-object-atoms/index.d.ts +3 -0
- package/plugin/node_modules/es-object-atoms/index.js +4 -0
- package/plugin/node_modules/es-object-atoms/isObject.d.ts +3 -0
- package/plugin/node_modules/es-object-atoms/isObject.js +6 -0
- package/plugin/node_modules/es-object-atoms/package.json +80 -0
- package/plugin/node_modules/es-object-atoms/tsconfig.json +6 -0
- package/plugin/node_modules/es6-error/CHANGELOG.md +26 -0
- package/plugin/node_modules/es6-error/LICENSE.md +21 -0
- package/plugin/node_modules/es6-error/README.md +59 -0
- package/plugin/node_modules/es6-error/package.json +48 -0
- package/plugin/node_modules/escape-html/LICENSE +24 -0
- package/plugin/node_modules/escape-html/Readme.md +43 -0
- package/plugin/node_modules/escape-html/index.js +78 -0
- package/plugin/node_modules/escape-html/package.json +24 -0
- package/plugin/node_modules/escape-string-regexp/index.d.ts +18 -0
- package/plugin/node_modules/escape-string-regexp/index.js +13 -0
- package/plugin/node_modules/escape-string-regexp/license +9 -0
- package/plugin/node_modules/escape-string-regexp/package.json +38 -0
- package/plugin/node_modules/escape-string-regexp/readme.md +34 -0
- package/plugin/node_modules/etag/HISTORY.md +83 -0
- package/plugin/node_modules/etag/LICENSE +22 -0
- package/plugin/node_modules/etag/README.md +159 -0
- package/plugin/node_modules/etag/index.js +131 -0
- package/plugin/node_modules/etag/package.json +47 -0
- package/plugin/node_modules/eventsource/LICENSE +22 -0
- package/plugin/node_modules/eventsource/README.md +167 -0
- package/plugin/node_modules/eventsource/package.json +130 -0
- package/plugin/node_modules/eventsource-parser/LICENSE +21 -0
- package/plugin/node_modules/eventsource-parser/README.md +126 -0
- package/plugin/node_modules/eventsource-parser/package.json +115 -0
- package/plugin/node_modules/eventsource-parser/stream.js +2 -0
- package/plugin/node_modules/expand-template/.travis.yml +6 -0
- package/plugin/node_modules/expand-template/LICENSE +21 -0
- package/plugin/node_modules/expand-template/README.md +43 -0
- package/plugin/node_modules/expand-template/index.js +26 -0
- package/plugin/node_modules/expand-template/package.json +29 -0
- package/plugin/node_modules/expand-template/test.js +67 -0
- package/plugin/node_modules/express/LICENSE +24 -0
- package/plugin/node_modules/express/Readme.md +276 -0
- package/plugin/node_modules/express/index.js +11 -0
- package/plugin/node_modules/express/package.json +99 -0
- package/plugin/node_modules/express-rate-limit/license.md +20 -0
- package/plugin/node_modules/express-rate-limit/package.json +112 -0
- package/plugin/node_modules/express-rate-limit/readme.md +151 -0
- package/plugin/node_modules/express-rate-limit/tsconfig.json +8 -0
- package/plugin/node_modules/fast-deep-equal/LICENSE +21 -0
- package/plugin/node_modules/fast-deep-equal/README.md +96 -0
- package/plugin/node_modules/fast-deep-equal/index.d.ts +4 -0
- package/plugin/node_modules/fast-deep-equal/index.js +46 -0
- package/plugin/node_modules/fast-deep-equal/package.json +61 -0
- package/plugin/node_modules/fast-deep-equal/react.d.ts +2 -0
- package/plugin/node_modules/fast-deep-equal/react.js +53 -0
- package/plugin/node_modules/fast-uri/.gitattributes +2 -0
- package/plugin/node_modules/fast-uri/LICENSE +32 -0
- package/plugin/node_modules/fast-uri/README.md +143 -0
- package/plugin/node_modules/fast-uri/eslint.config.js +6 -0
- package/plugin/node_modules/fast-uri/index.js +340 -0
- package/plugin/node_modules/fast-uri/package.json +69 -0
- package/plugin/node_modules/fast-uri/tsconfig.json +9 -0
- package/plugin/node_modules/file-uri-to-path/.travis.yml +30 -0
- package/plugin/node_modules/file-uri-to-path/History.md +21 -0
- package/plugin/node_modules/file-uri-to-path/LICENSE +20 -0
- package/plugin/node_modules/file-uri-to-path/README.md +74 -0
- package/plugin/node_modules/file-uri-to-path/index.d.ts +2 -0
- package/plugin/node_modules/file-uri-to-path/index.js +66 -0
- package/plugin/node_modules/file-uri-to-path/package.json +32 -0
- package/plugin/node_modules/finalhandler/HISTORY.md +239 -0
- package/plugin/node_modules/finalhandler/LICENSE +22 -0
- package/plugin/node_modules/finalhandler/README.md +150 -0
- package/plugin/node_modules/finalhandler/index.js +293 -0
- package/plugin/node_modules/finalhandler/package.json +47 -0
- package/plugin/node_modules/flatbuffers/LICENSE +202 -0
- package/plugin/node_modules/flatbuffers/README.md +116 -0
- package/plugin/node_modules/flatbuffers/package.json +53 -0
- package/plugin/node_modules/forwarded/HISTORY.md +21 -0
- package/plugin/node_modules/forwarded/LICENSE +22 -0
- package/plugin/node_modules/forwarded/README.md +57 -0
- package/plugin/node_modules/forwarded/index.js +90 -0
- package/plugin/node_modules/forwarded/package.json +45 -0
- package/plugin/node_modules/fresh/HISTORY.md +80 -0
- package/plugin/node_modules/fresh/LICENSE +23 -0
- package/plugin/node_modules/fresh/README.md +117 -0
- package/plugin/node_modules/fresh/index.js +136 -0
- package/plugin/node_modules/fresh/package.json +46 -0
- package/plugin/node_modules/fs-constants/LICENSE +21 -0
- package/plugin/node_modules/fs-constants/README.md +26 -0
- package/plugin/node_modules/fs-constants/browser.js +1 -0
- package/plugin/node_modules/fs-constants/index.js +1 -0
- package/plugin/node_modules/fs-constants/package.json +19 -0
- package/plugin/node_modules/function-bind/.eslintrc +21 -0
- package/plugin/node_modules/function-bind/.nycrc +13 -0
- package/plugin/node_modules/function-bind/CHANGELOG.md +136 -0
- package/plugin/node_modules/function-bind/LICENSE +20 -0
- package/plugin/node_modules/function-bind/README.md +46 -0
- package/plugin/node_modules/function-bind/implementation.js +84 -0
- package/plugin/node_modules/function-bind/index.js +5 -0
- package/plugin/node_modules/function-bind/package.json +87 -0
- package/plugin/node_modules/get-intrinsic/.eslintrc +42 -0
- package/plugin/node_modules/get-intrinsic/.nycrc +9 -0
- package/plugin/node_modules/get-intrinsic/CHANGELOG.md +186 -0
- package/plugin/node_modules/get-intrinsic/LICENSE +21 -0
- package/plugin/node_modules/get-intrinsic/README.md +71 -0
- package/plugin/node_modules/get-intrinsic/index.js +378 -0
- package/plugin/node_modules/get-intrinsic/package.json +97 -0
- package/plugin/node_modules/get-proto/.eslintrc +10 -0
- package/plugin/node_modules/get-proto/.nycrc +9 -0
- package/plugin/node_modules/get-proto/CHANGELOG.md +21 -0
- package/plugin/node_modules/get-proto/LICENSE +21 -0
- package/plugin/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
- package/plugin/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
- package/plugin/node_modules/get-proto/README.md +50 -0
- package/plugin/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
- package/plugin/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
- package/plugin/node_modules/get-proto/index.d.ts +5 -0
- package/plugin/node_modules/get-proto/index.js +27 -0
- package/plugin/node_modules/get-proto/package.json +81 -0
- package/plugin/node_modules/get-proto/tsconfig.json +9 -0
- package/plugin/node_modules/github-from-package/.travis.yml +4 -0
- package/plugin/node_modules/github-from-package/LICENSE +18 -0
- package/plugin/node_modules/github-from-package/index.js +17 -0
- package/plugin/node_modules/github-from-package/package.json +30 -0
- package/plugin/node_modules/github-from-package/readme.markdown +53 -0
- package/plugin/node_modules/global-agent/.flowconfig +3 -0
- package/plugin/node_modules/global-agent/LICENSE +24 -0
- package/plugin/node_modules/global-agent/README.md +239 -0
- package/plugin/node_modules/global-agent/bootstrap.js +1 -0
- package/plugin/node_modules/global-agent/package.json +105 -0
- package/plugin/node_modules/globalthis/.eslintrc +18 -0
- package/plugin/node_modules/globalthis/.nycrc +10 -0
- package/plugin/node_modules/globalthis/CHANGELOG.md +109 -0
- package/plugin/node_modules/globalthis/LICENSE +21 -0
- package/plugin/node_modules/globalthis/README.md +70 -0
- package/plugin/node_modules/globalthis/auto.js +3 -0
- package/plugin/node_modules/globalthis/implementation.browser.js +11 -0
- package/plugin/node_modules/globalthis/implementation.js +3 -0
- package/plugin/node_modules/globalthis/index.js +19 -0
- package/plugin/node_modules/globalthis/package.json +99 -0
- package/plugin/node_modules/globalthis/polyfill.js +10 -0
- package/plugin/node_modules/globalthis/shim.js +29 -0
- package/plugin/node_modules/gopd/.eslintrc +16 -0
- package/plugin/node_modules/gopd/CHANGELOG.md +45 -0
- package/plugin/node_modules/gopd/LICENSE +21 -0
- package/plugin/node_modules/gopd/README.md +40 -0
- package/plugin/node_modules/gopd/gOPD.d.ts +1 -0
- package/plugin/node_modules/gopd/gOPD.js +4 -0
- package/plugin/node_modules/gopd/index.d.ts +5 -0
- package/plugin/node_modules/gopd/index.js +15 -0
- package/plugin/node_modules/gopd/package.json +77 -0
- package/plugin/node_modules/gopd/tsconfig.json +9 -0
- package/plugin/node_modules/guid-typescript/README.md +39 -0
- package/plugin/node_modules/guid-typescript/package.json +37 -0
- package/plugin/node_modules/has-property-descriptors/.eslintrc +13 -0
- package/plugin/node_modules/has-property-descriptors/.nycrc +9 -0
- package/plugin/node_modules/has-property-descriptors/CHANGELOG.md +35 -0
- package/plugin/node_modules/has-property-descriptors/LICENSE +21 -0
- package/plugin/node_modules/has-property-descriptors/README.md +43 -0
- package/plugin/node_modules/has-property-descriptors/index.js +22 -0
- package/plugin/node_modules/has-property-descriptors/package.json +77 -0
- package/plugin/node_modules/has-symbols/.eslintrc +11 -0
- package/plugin/node_modules/has-symbols/.nycrc +9 -0
- package/plugin/node_modules/has-symbols/CHANGELOG.md +91 -0
- package/plugin/node_modules/has-symbols/LICENSE +21 -0
- package/plugin/node_modules/has-symbols/README.md +46 -0
- package/plugin/node_modules/has-symbols/index.d.ts +3 -0
- package/plugin/node_modules/has-symbols/index.js +14 -0
- package/plugin/node_modules/has-symbols/package.json +111 -0
- package/plugin/node_modules/has-symbols/shams.d.ts +3 -0
- package/plugin/node_modules/has-symbols/shams.js +45 -0
- package/plugin/node_modules/has-symbols/tsconfig.json +10 -0
- package/plugin/node_modules/hasown/.eslintrc +5 -0
- package/plugin/node_modules/hasown/.nycrc +13 -0
- package/plugin/node_modules/hasown/CHANGELOG.md +40 -0
- package/plugin/node_modules/hasown/LICENSE +21 -0
- package/plugin/node_modules/hasown/README.md +40 -0
- package/plugin/node_modules/hasown/index.d.ts +3 -0
- package/plugin/node_modules/hasown/index.js +8 -0
- package/plugin/node_modules/hasown/package.json +92 -0
- package/plugin/node_modules/hasown/tsconfig.json +6 -0
- package/plugin/node_modules/hono/LICENSE +21 -0
- package/plugin/node_modules/hono/README.md +85 -0
- package/plugin/node_modules/hono/dist/compose.js +46 -0
- package/plugin/node_modules/hono/dist/context.js +412 -0
- package/plugin/node_modules/hono/dist/hono-base.js +378 -0
- package/plugin/node_modules/hono/dist/hono.js +21 -0
- package/plugin/node_modules/hono/dist/http-exception.js +35 -0
- package/plugin/node_modules/hono/dist/index.js +5 -0
- package/plugin/node_modules/hono/dist/request.js +301 -0
- package/plugin/node_modules/hono/dist/router.js +14 -0
- package/plugin/node_modules/hono/dist/types.js +6 -0
- package/plugin/node_modules/hono/package.json +691 -0
- package/plugin/node_modules/http-errors/HISTORY.md +186 -0
- package/plugin/node_modules/http-errors/LICENSE +23 -0
- package/plugin/node_modules/http-errors/README.md +169 -0
- package/plugin/node_modules/http-errors/index.js +290 -0
- package/plugin/node_modules/http-errors/package.json +54 -0
- package/plugin/node_modules/iconv-lite/LICENSE +21 -0
- package/plugin/node_modules/iconv-lite/README.md +138 -0
- package/plugin/node_modules/iconv-lite/package.json +70 -0
- package/plugin/node_modules/ieee754/LICENSE +11 -0
- package/plugin/node_modules/ieee754/README.md +51 -0
- package/plugin/node_modules/ieee754/index.d.ts +10 -0
- package/plugin/node_modules/ieee754/index.js +85 -0
- package/plugin/node_modules/ieee754/package.json +52 -0
- package/plugin/node_modules/inherits/LICENSE +16 -0
- package/plugin/node_modules/inherits/README.md +42 -0
- package/plugin/node_modules/inherits/inherits.js +9 -0
- package/plugin/node_modules/inherits/inherits_browser.js +27 -0
- package/plugin/node_modules/inherits/package.json +29 -0
- package/plugin/node_modules/ini/LICENSE +15 -0
- package/plugin/node_modules/ini/README.md +102 -0
- package/plugin/node_modules/ini/ini.js +206 -0
- package/plugin/node_modules/ini/package.json +33 -0
- package/plugin/node_modules/ip-address/LICENSE +19 -0
- package/plugin/node_modules/ip-address/README.md +105 -0
- package/plugin/node_modules/ip-address/package.json +78 -0
- package/plugin/node_modules/ipaddr.js/LICENSE +19 -0
- package/plugin/node_modules/ipaddr.js/README.md +233 -0
- package/plugin/node_modules/ipaddr.js/ipaddr.min.js +1 -0
- package/plugin/node_modules/ipaddr.js/package.json +35 -0
- package/plugin/node_modules/is-promise/LICENSE +19 -0
- package/plugin/node_modules/is-promise/index.d.ts +2 -0
- package/plugin/node_modules/is-promise/index.js +6 -0
- package/plugin/node_modules/is-promise/index.mjs +3 -0
- package/plugin/node_modules/is-promise/package.json +30 -0
- package/plugin/node_modules/is-promise/readme.md +33 -0
- package/plugin/node_modules/isexe/LICENSE +15 -0
- package/plugin/node_modules/isexe/README.md +51 -0
- package/plugin/node_modules/isexe/index.js +57 -0
- package/plugin/node_modules/isexe/mode.js +41 -0
- package/plugin/node_modules/isexe/package.json +31 -0
- package/plugin/node_modules/isexe/windows.js +42 -0
- package/plugin/node_modules/jose/LICENSE.md +21 -0
- package/plugin/node_modules/jose/README.md +153 -0
- package/plugin/node_modules/jose/package.json +200 -0
- package/plugin/node_modules/json-schema-traverse/.eslintrc.yml +27 -0
- package/plugin/node_modules/json-schema-traverse/LICENSE +21 -0
- package/plugin/node_modules/json-schema-traverse/README.md +95 -0
- package/plugin/node_modules/json-schema-traverse/index.d.ts +40 -0
- package/plugin/node_modules/json-schema-traverse/index.js +93 -0
- package/plugin/node_modules/json-schema-traverse/package.json +43 -0
- package/plugin/node_modules/json-schema-typed/LICENSE.md +57 -0
- package/plugin/node_modules/json-schema-typed/README.md +108 -0
- package/plugin/node_modules/json-schema-typed/draft_07.d.ts +882 -0
- package/plugin/node_modules/json-schema-typed/draft_07.js +328 -0
- package/plugin/node_modules/json-schema-typed/draft_2019_09.d.ts +1247 -0
- package/plugin/node_modules/json-schema-typed/draft_2019_09.js +349 -0
- package/plugin/node_modules/json-schema-typed/draft_2020_12.d.ts +1239 -0
- package/plugin/node_modules/json-schema-typed/draft_2020_12.js +352 -0
- package/plugin/node_modules/json-schema-typed/package.json +44 -0
- package/plugin/node_modules/json-stringify-safe/CHANGELOG.md +14 -0
- package/plugin/node_modules/json-stringify-safe/LICENSE +15 -0
- package/plugin/node_modules/json-stringify-safe/Makefile +35 -0
- package/plugin/node_modules/json-stringify-safe/README.md +52 -0
- package/plugin/node_modules/json-stringify-safe/package.json +31 -0
- package/plugin/node_modules/json-stringify-safe/stringify.js +27 -0
- package/plugin/node_modules/long/LICENSE +202 -0
- package/plugin/node_modules/long/README.md +286 -0
- package/plugin/node_modules/long/index.d.ts +2 -0
- package/plugin/node_modules/long/index.js +1581 -0
- package/plugin/node_modules/long/package.json +58 -0
- package/plugin/node_modules/long/types.d.ts +474 -0
- package/plugin/node_modules/matcher/index.d.ts +85 -0
- package/plugin/node_modules/matcher/index.js +77 -0
- package/plugin/node_modules/matcher/license +9 -0
- package/plugin/node_modules/matcher/package.json +54 -0
- package/plugin/node_modules/matcher/readme.md +120 -0
- package/plugin/node_modules/math-intrinsics/.eslintrc +16 -0
- package/plugin/node_modules/math-intrinsics/CHANGELOG.md +24 -0
- package/plugin/node_modules/math-intrinsics/LICENSE +21 -0
- package/plugin/node_modules/math-intrinsics/README.md +50 -0
- package/plugin/node_modules/math-intrinsics/abs.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/abs.js +4 -0
- package/plugin/node_modules/math-intrinsics/floor.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/floor.js +4 -0
- package/plugin/node_modules/math-intrinsics/isFinite.d.ts +3 -0
- package/plugin/node_modules/math-intrinsics/isFinite.js +12 -0
- package/plugin/node_modules/math-intrinsics/isInteger.d.ts +3 -0
- package/plugin/node_modules/math-intrinsics/isInteger.js +16 -0
- package/plugin/node_modules/math-intrinsics/isNaN.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/isNaN.js +6 -0
- package/plugin/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
- package/plugin/node_modules/math-intrinsics/isNegativeZero.js +6 -0
- package/plugin/node_modules/math-intrinsics/max.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/max.js +4 -0
- package/plugin/node_modules/math-intrinsics/min.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/min.js +4 -0
- package/plugin/node_modules/math-intrinsics/mod.d.ts +3 -0
- package/plugin/node_modules/math-intrinsics/mod.js +9 -0
- package/plugin/node_modules/math-intrinsics/package.json +86 -0
- package/plugin/node_modules/math-intrinsics/pow.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/pow.js +4 -0
- package/plugin/node_modules/math-intrinsics/round.d.ts +1 -0
- package/plugin/node_modules/math-intrinsics/round.js +4 -0
- package/plugin/node_modules/math-intrinsics/sign.d.ts +3 -0
- package/plugin/node_modules/math-intrinsics/sign.js +11 -0
- package/plugin/node_modules/math-intrinsics/tsconfig.json +3 -0
- package/plugin/node_modules/media-typer/HISTORY.md +50 -0
- package/plugin/node_modules/media-typer/LICENSE +22 -0
- package/plugin/node_modules/media-typer/README.md +93 -0
- package/plugin/node_modules/media-typer/index.js +143 -0
- package/plugin/node_modules/media-typer/package.json +33 -0
- package/plugin/node_modules/merge-descriptors/index.d.ts +11 -0
- package/plugin/node_modules/merge-descriptors/index.js +26 -0
- package/plugin/node_modules/merge-descriptors/license +11 -0
- package/plugin/node_modules/merge-descriptors/package.json +50 -0
- package/plugin/node_modules/merge-descriptors/readme.md +55 -0
- package/plugin/node_modules/mime-db/HISTORY.md +541 -0
- package/plugin/node_modules/mime-db/LICENSE +23 -0
- package/plugin/node_modules/mime-db/README.md +109 -0
- package/plugin/node_modules/mime-db/db.json +9342 -0
- package/plugin/node_modules/mime-db/index.js +12 -0
- package/plugin/node_modules/mime-db/package.json +56 -0
- package/plugin/node_modules/mime-types/HISTORY.md +428 -0
- package/plugin/node_modules/mime-types/LICENSE +23 -0
- package/plugin/node_modules/mime-types/README.md +126 -0
- package/plugin/node_modules/mime-types/index.js +211 -0
- package/plugin/node_modules/mime-types/mimeScore.js +57 -0
- package/plugin/node_modules/mime-types/package.json +49 -0
- package/plugin/node_modules/mimic-response/index.d.ts +17 -0
- package/plugin/node_modules/mimic-response/index.js +77 -0
- package/plugin/node_modules/mimic-response/license +9 -0
- package/plugin/node_modules/mimic-response/package.json +42 -0
- package/plugin/node_modules/mimic-response/readme.md +78 -0
- package/plugin/node_modules/minimist/.eslintrc +29 -0
- package/plugin/node_modules/minimist/.nycrc +14 -0
- package/plugin/node_modules/minimist/CHANGELOG.md +298 -0
- package/plugin/node_modules/minimist/LICENSE +18 -0
- package/plugin/node_modules/minimist/README.md +121 -0
- package/plugin/node_modules/minimist/index.js +263 -0
- package/plugin/node_modules/minimist/package.json +75 -0
- package/plugin/node_modules/minipass/LICENSE.md +55 -0
- package/plugin/node_modules/minipass/README.md +825 -0
- package/plugin/node_modules/minipass/package.json +77 -0
- package/plugin/node_modules/minizlib/LICENSE +26 -0
- package/plugin/node_modules/minizlib/README.md +64 -0
- package/plugin/node_modules/minizlib/package.json +80 -0
- package/plugin/node_modules/mkdirp-classic/LICENSE +21 -0
- package/plugin/node_modules/mkdirp-classic/README.md +18 -0
- package/plugin/node_modules/mkdirp-classic/index.js +98 -0
- package/plugin/node_modules/mkdirp-classic/package.json +18 -0
- package/plugin/node_modules/ms/index.js +162 -0
- package/plugin/node_modules/ms/license.md +21 -0
- package/plugin/node_modules/ms/package.json +38 -0
- package/plugin/node_modules/ms/readme.md +59 -0
- package/plugin/node_modules/napi-build-utils/LICENSE +21 -0
- package/plugin/node_modules/napi-build-utils/README.md +52 -0
- package/plugin/node_modules/napi-build-utils/index.js +214 -0
- package/plugin/node_modules/napi-build-utils/index.md +0 -0
- package/plugin/node_modules/napi-build-utils/package.json +42 -0
- package/plugin/node_modules/negotiator/HISTORY.md +114 -0
- package/plugin/node_modules/negotiator/LICENSE +24 -0
- package/plugin/node_modules/negotiator/README.md +212 -0
- package/plugin/node_modules/negotiator/index.js +83 -0
- package/plugin/node_modules/negotiator/package.json +43 -0
- package/plugin/node_modules/node-abi/LICENSE +21 -0
- package/plugin/node_modules/node-abi/README.md +54 -0
- package/plugin/node_modules/node-abi/abi_registry.json +432 -0
- package/plugin/node_modules/node-abi/index.js +179 -0
- package/plugin/node_modules/node-abi/package.json +45 -0
- package/plugin/node_modules/object-assign/index.js +90 -0
- package/plugin/node_modules/object-assign/license +21 -0
- package/plugin/node_modules/object-assign/package.json +42 -0
- package/plugin/node_modules/object-assign/readme.md +61 -0
- package/plugin/node_modules/object-inspect/.eslintrc +53 -0
- package/plugin/node_modules/object-inspect/.nycrc +13 -0
- package/plugin/node_modules/object-inspect/CHANGELOG.md +424 -0
- package/plugin/node_modules/object-inspect/LICENSE +21 -0
- package/plugin/node_modules/object-inspect/index.js +544 -0
- package/plugin/node_modules/object-inspect/package-support.json +20 -0
- package/plugin/node_modules/object-inspect/package.json +105 -0
- package/plugin/node_modules/object-inspect/readme.markdown +84 -0
- package/plugin/node_modules/object-inspect/test-core-js.js +26 -0
- package/plugin/node_modules/object-inspect/util.inspect.js +1 -0
- package/plugin/node_modules/object-keys/.editorconfig +13 -0
- package/plugin/node_modules/object-keys/.eslintrc +17 -0
- package/plugin/node_modules/object-keys/.travis.yml +277 -0
- package/plugin/node_modules/object-keys/CHANGELOG.md +232 -0
- package/plugin/node_modules/object-keys/LICENSE +21 -0
- package/plugin/node_modules/object-keys/README.md +76 -0
- package/plugin/node_modules/object-keys/implementation.js +122 -0
- package/plugin/node_modules/object-keys/index.js +32 -0
- package/plugin/node_modules/object-keys/isArguments.js +17 -0
- package/plugin/node_modules/object-keys/package.json +88 -0
- package/plugin/node_modules/on-finished/HISTORY.md +98 -0
- package/plugin/node_modules/on-finished/LICENSE +23 -0
- package/plugin/node_modules/on-finished/README.md +162 -0
- package/plugin/node_modules/on-finished/index.js +234 -0
- package/plugin/node_modules/on-finished/package.json +39 -0
- package/plugin/node_modules/once/LICENSE +15 -0
- package/plugin/node_modules/once/README.md +79 -0
- package/plugin/node_modules/once/once.js +42 -0
- package/plugin/node_modules/once/package.json +33 -0
- package/plugin/node_modules/onnxruntime-common/README.md +13 -0
- package/plugin/node_modules/onnxruntime-common/package.json +35 -0
- package/plugin/node_modules/onnxruntime-node/README.md +51 -0
- package/plugin/node_modules/onnxruntime-node/dist/backend.d.ts +9 -0
- package/plugin/node_modules/onnxruntime-node/dist/backend.js +79 -0
- package/plugin/node_modules/onnxruntime-node/dist/backend.js.map +1 -0
- package/plugin/node_modules/onnxruntime-node/dist/binding.d.ts +40 -0
- package/plugin/node_modules/onnxruntime-node/dist/binding.js +41 -0
- package/plugin/node_modules/onnxruntime-node/dist/binding.js.map +1 -0
- package/plugin/node_modules/onnxruntime-node/dist/index.d.ts +2 -0
- package/plugin/node_modules/onnxruntime-node/dist/index.js +31 -0
- package/plugin/node_modules/onnxruntime-node/dist/index.js.map +1 -0
- package/plugin/node_modules/onnxruntime-node/dist/version.d.ts +1 -0
- package/plugin/node_modules/onnxruntime-node/dist/version.js +9 -0
- package/plugin/node_modules/onnxruntime-node/dist/version.js.map +1 -0
- package/plugin/node_modules/onnxruntime-node/lib/backend.ts +81 -0
- package/plugin/node_modules/onnxruntime-node/lib/binding.ts +84 -0
- package/plugin/node_modules/onnxruntime-node/lib/index.ts +15 -0
- package/plugin/node_modules/onnxruntime-node/lib/version.ts +7 -0
- package/plugin/node_modules/onnxruntime-node/package.json +56 -0
- package/plugin/node_modules/onnxruntime-node/script/build.js +148 -0
- package/plugin/node_modules/onnxruntime-node/script/build.ts +130 -0
- package/plugin/node_modules/onnxruntime-node/script/install.js +199 -0
- package/plugin/node_modules/onnxruntime-node/script/prepack.js +42 -0
- package/plugin/node_modules/onnxruntime-node/script/prepack.ts +20 -0
- package/plugin/node_modules/onnxruntime-web/README.md +74 -0
- package/plugin/node_modules/onnxruntime-web/__commit.txt +1 -0
- package/plugin/node_modules/onnxruntime-web/package.json +109 -0
- package/plugin/node_modules/onnxruntime-web/types.d.ts +22 -0
- package/plugin/node_modules/parseurl/HISTORY.md +58 -0
- package/plugin/node_modules/parseurl/LICENSE +24 -0
- package/plugin/node_modules/parseurl/README.md +133 -0
- package/plugin/node_modules/parseurl/index.js +158 -0
- package/plugin/node_modules/parseurl/package.json +40 -0
- package/plugin/node_modules/path-key/index.d.ts +40 -0
- package/plugin/node_modules/path-key/index.js +16 -0
- package/plugin/node_modules/path-key/license +9 -0
- package/plugin/node_modules/path-key/package.json +39 -0
- package/plugin/node_modules/path-key/readme.md +61 -0
- package/plugin/node_modules/path-to-regexp/LICENSE +21 -0
- package/plugin/node_modules/path-to-regexp/Readme.md +224 -0
- package/plugin/node_modules/path-to-regexp/package.json +64 -0
- package/plugin/node_modules/pkce-challenge/CHANGELOG.md +114 -0
- package/plugin/node_modules/pkce-challenge/LICENSE +21 -0
- package/plugin/node_modules/pkce-challenge/README.md +55 -0
- package/plugin/node_modules/pkce-challenge/package.json +59 -0
- package/plugin/node_modules/platform/LICENSE +21 -0
- package/plugin/node_modules/platform/README.md +76 -0
- package/plugin/node_modules/platform/package.json +30 -0
- package/plugin/node_modules/platform/platform.js +1260 -0
- package/plugin/node_modules/prebuild-install/CHANGELOG.md +131 -0
- package/plugin/node_modules/prebuild-install/CONTRIBUTING.md +6 -0
- package/plugin/node_modules/prebuild-install/LICENSE +21 -0
- package/plugin/node_modules/prebuild-install/README.md +163 -0
- package/plugin/node_modules/prebuild-install/asset.js +44 -0
- package/plugin/node_modules/prebuild-install/bin.js +78 -0
- package/plugin/node_modules/prebuild-install/download.js +142 -0
- package/plugin/node_modules/prebuild-install/error.js +14 -0
- package/plugin/node_modules/prebuild-install/help.txt +16 -0
- package/plugin/node_modules/prebuild-install/index.js +1 -0
- package/plugin/node_modules/prebuild-install/log.js +33 -0
- package/plugin/node_modules/prebuild-install/package.json +67 -0
- package/plugin/node_modules/prebuild-install/proxy.js +35 -0
- package/plugin/node_modules/prebuild-install/rc.js +64 -0
- package/plugin/node_modules/prebuild-install/util.js +143 -0
- package/plugin/node_modules/protobufjs/LICENSE +39 -0
- package/plugin/node_modules/protobufjs/README.md +727 -0
- package/plugin/node_modules/protobufjs/index.d.ts +2799 -0
- package/plugin/node_modules/protobufjs/index.js +4 -0
- package/plugin/node_modules/protobufjs/light.d.ts +2 -0
- package/plugin/node_modules/protobufjs/light.js +4 -0
- package/plugin/node_modules/protobufjs/minimal.d.ts +2 -0
- package/plugin/node_modules/protobufjs/minimal.js +4 -0
- package/plugin/node_modules/protobufjs/package.json +114 -0
- package/plugin/node_modules/protobufjs/tsconfig.json +8 -0
- package/plugin/node_modules/proxy-addr/HISTORY.md +161 -0
- package/plugin/node_modules/proxy-addr/LICENSE +22 -0
- package/plugin/node_modules/proxy-addr/README.md +139 -0
- package/plugin/node_modules/proxy-addr/index.js +327 -0
- package/plugin/node_modules/proxy-addr/package.json +47 -0
- package/plugin/node_modules/pump/.travis.yml +5 -0
- package/plugin/node_modules/pump/LICENSE +21 -0
- package/plugin/node_modules/pump/README.md +74 -0
- package/plugin/node_modules/pump/SECURITY.md +5 -0
- package/plugin/node_modules/pump/index.js +86 -0
- package/plugin/node_modules/pump/package.json +24 -0
- package/plugin/node_modules/pump/test-browser.js +66 -0
- package/plugin/node_modules/pump/test-node.js +53 -0
- package/plugin/node_modules/qs/.editorconfig +46 -0
- package/plugin/node_modules/qs/.nycrc +13 -0
- package/plugin/node_modules/qs/CHANGELOG.md +806 -0
- package/plugin/node_modules/qs/LICENSE.md +29 -0
- package/plugin/node_modules/qs/README.md +758 -0
- package/plugin/node_modules/qs/eslint.config.mjs +56 -0
- package/plugin/node_modules/qs/package.json +94 -0
- package/plugin/node_modules/range-parser/HISTORY.md +56 -0
- package/plugin/node_modules/range-parser/LICENSE +23 -0
- package/plugin/node_modules/range-parser/README.md +84 -0
- package/plugin/node_modules/range-parser/index.js +162 -0
- package/plugin/node_modules/range-parser/package.json +44 -0
- package/plugin/node_modules/raw-body/LICENSE +22 -0
- package/plugin/node_modules/raw-body/README.md +223 -0
- package/plugin/node_modules/raw-body/index.d.ts +85 -0
- package/plugin/node_modules/raw-body/index.js +336 -0
- package/plugin/node_modules/raw-body/package.json +46 -0
- package/plugin/node_modules/rc/LICENSE.APACHE2 +15 -0
- package/plugin/node_modules/rc/LICENSE.BSD +26 -0
- package/plugin/node_modules/rc/LICENSE.MIT +24 -0
- package/plugin/node_modules/rc/README.md +227 -0
- package/plugin/node_modules/rc/browser.js +7 -0
- package/plugin/node_modules/rc/cli.js +4 -0
- package/plugin/node_modules/rc/index.js +53 -0
- package/plugin/node_modules/rc/package.json +29 -0
- package/plugin/node_modules/readable-stream/CONTRIBUTING.md +38 -0
- package/plugin/node_modules/readable-stream/GOVERNANCE.md +136 -0
- package/plugin/node_modules/readable-stream/LICENSE +47 -0
- package/plugin/node_modules/readable-stream/README.md +106 -0
- package/plugin/node_modules/readable-stream/errors-browser.js +127 -0
- package/plugin/node_modules/readable-stream/errors.js +116 -0
- package/plugin/node_modules/readable-stream/experimentalWarning.js +17 -0
- package/plugin/node_modules/readable-stream/package.json +68 -0
- package/plugin/node_modules/readable-stream/readable-browser.js +9 -0
- package/plugin/node_modules/readable-stream/readable.js +16 -0
- package/plugin/node_modules/require-from-string/index.js +34 -0
- package/plugin/node_modules/require-from-string/license +21 -0
- package/plugin/node_modules/require-from-string/package.json +28 -0
- package/plugin/node_modules/require-from-string/readme.md +56 -0
- package/plugin/node_modules/roarr/LICENSE +24 -0
- package/plugin/node_modules/roarr/README.md +689 -0
- package/plugin/node_modules/roarr/package.json +93 -0
- package/plugin/node_modules/router/HISTORY.md +228 -0
- package/plugin/node_modules/router/LICENSE +23 -0
- package/plugin/node_modules/router/README.md +416 -0
- package/plugin/node_modules/router/index.js +748 -0
- package/plugin/node_modules/router/package.json +44 -0
- package/plugin/node_modules/safe-buffer/LICENSE +21 -0
- package/plugin/node_modules/safe-buffer/README.md +584 -0
- package/plugin/node_modules/safe-buffer/index.d.ts +187 -0
- package/plugin/node_modules/safe-buffer/index.js +65 -0
- package/plugin/node_modules/safe-buffer/package.json +51 -0
- package/plugin/node_modules/safer-buffer/LICENSE +21 -0
- package/plugin/node_modules/safer-buffer/Porting-Buffer.md +268 -0
- package/plugin/node_modules/safer-buffer/Readme.md +156 -0
- package/plugin/node_modules/safer-buffer/dangerous.js +58 -0
- package/plugin/node_modules/safer-buffer/package.json +34 -0
- package/plugin/node_modules/safer-buffer/safer.js +77 -0
- package/plugin/node_modules/safer-buffer/tests.js +406 -0
- package/plugin/node_modules/semver/LICENSE +15 -0
- package/plugin/node_modules/semver/README.md +665 -0
- package/plugin/node_modules/semver/index.js +91 -0
- package/plugin/node_modules/semver/package.json +78 -0
- package/plugin/node_modules/semver/preload.js +4 -0
- package/plugin/node_modules/semver/range.bnf +16 -0
- package/plugin/node_modules/semver-compare/.travis.yml +6 -0
- package/plugin/node_modules/semver-compare/LICENSE +18 -0
- package/plugin/node_modules/semver-compare/index.js +13 -0
- package/plugin/node_modules/semver-compare/package.json +31 -0
- package/plugin/node_modules/semver-compare/readme.markdown +77 -0
- package/plugin/node_modules/send/LICENSE +23 -0
- package/plugin/node_modules/send/README.md +317 -0
- package/plugin/node_modules/send/index.js +997 -0
- package/plugin/node_modules/send/package.json +63 -0
- package/plugin/node_modules/serialize-error/index.d.ts +58 -0
- package/plugin/node_modules/serialize-error/index.js +101 -0
- package/plugin/node_modules/serialize-error/license +9 -0
- package/plugin/node_modules/serialize-error/package.json +41 -0
- package/plugin/node_modules/serialize-error/readme.md +55 -0
- package/plugin/node_modules/serve-static/LICENSE +25 -0
- package/plugin/node_modules/serve-static/README.md +253 -0
- package/plugin/node_modules/serve-static/index.js +208 -0
- package/plugin/node_modules/serve-static/package.json +44 -0
- package/plugin/node_modules/setprototypeof/LICENSE +13 -0
- package/plugin/node_modules/setprototypeof/README.md +31 -0
- package/plugin/node_modules/setprototypeof/index.d.ts +2 -0
- package/plugin/node_modules/setprototypeof/index.js +17 -0
- package/plugin/node_modules/setprototypeof/package.json +38 -0
- package/plugin/node_modules/sharp/LICENSE +191 -0
- package/plugin/node_modules/sharp/README.md +118 -0
- package/plugin/node_modules/sharp/install/build.js +38 -0
- package/plugin/node_modules/sharp/install/check.js +14 -0
- package/plugin/node_modules/sharp/lib/channel.js +177 -0
- package/plugin/node_modules/sharp/lib/colour.js +195 -0
- package/plugin/node_modules/sharp/lib/composite.js +212 -0
- package/plugin/node_modules/sharp/lib/constructor.js +499 -0
- package/plugin/node_modules/sharp/lib/index.d.ts +1971 -0
- package/plugin/node_modules/sharp/lib/index.js +16 -0
- package/plugin/node_modules/sharp/lib/input.js +809 -0
- package/plugin/node_modules/sharp/lib/is.js +143 -0
- package/plugin/node_modules/sharp/lib/libvips.js +207 -0
- package/plugin/node_modules/sharp/lib/operation.js +1016 -0
- package/plugin/node_modules/sharp/lib/output.js +1666 -0
- package/plugin/node_modules/sharp/lib/resize.js +595 -0
- package/plugin/node_modules/sharp/lib/sharp.js +121 -0
- package/plugin/node_modules/sharp/lib/utility.js +291 -0
- package/plugin/node_modules/sharp/package.json +202 -0
- package/plugin/node_modules/sharp/src/binding.gyp +298 -0
- package/plugin/node_modules/sharp/src/common.cc +1130 -0
- package/plugin/node_modules/sharp/src/common.h +402 -0
- package/plugin/node_modules/sharp/src/metadata.cc +346 -0
- package/plugin/node_modules/sharp/src/metadata.h +90 -0
- package/plugin/node_modules/sharp/src/operations.cc +499 -0
- package/plugin/node_modules/sharp/src/operations.h +137 -0
- package/plugin/node_modules/sharp/src/pipeline.cc +1814 -0
- package/plugin/node_modules/sharp/src/pipeline.h +408 -0
- package/plugin/node_modules/sharp/src/sharp.cc +43 -0
- package/plugin/node_modules/sharp/src/stats.cc +186 -0
- package/plugin/node_modules/sharp/src/stats.h +62 -0
- package/plugin/node_modules/sharp/src/utilities.cc +288 -0
- package/plugin/node_modules/sharp/src/utilities.h +22 -0
- package/plugin/node_modules/shebang-command/index.js +19 -0
- package/plugin/node_modules/shebang-command/license +9 -0
- package/plugin/node_modules/shebang-command/package.json +34 -0
- package/plugin/node_modules/shebang-command/readme.md +34 -0
- package/plugin/node_modules/shebang-regex/index.d.ts +22 -0
- package/plugin/node_modules/shebang-regex/index.js +2 -0
- package/plugin/node_modules/shebang-regex/license +9 -0
- package/plugin/node_modules/shebang-regex/package.json +35 -0
- package/plugin/node_modules/shebang-regex/readme.md +33 -0
- package/plugin/node_modules/side-channel/.editorconfig +9 -0
- package/plugin/node_modules/side-channel/.eslintrc +12 -0
- package/plugin/node_modules/side-channel/.nycrc +13 -0
- package/plugin/node_modules/side-channel/CHANGELOG.md +110 -0
- package/plugin/node_modules/side-channel/LICENSE +21 -0
- package/plugin/node_modules/side-channel/README.md +61 -0
- package/plugin/node_modules/side-channel/index.d.ts +14 -0
- package/plugin/node_modules/side-channel/index.js +43 -0
- package/plugin/node_modules/side-channel/package.json +85 -0
- package/plugin/node_modules/side-channel/tsconfig.json +9 -0
- package/plugin/node_modules/side-channel-list/.editorconfig +9 -0
- package/plugin/node_modules/side-channel-list/.eslintrc +11 -0
- package/plugin/node_modules/side-channel-list/.nycrc +13 -0
- package/plugin/node_modules/side-channel-list/CHANGELOG.md +15 -0
- package/plugin/node_modules/side-channel-list/LICENSE +21 -0
- package/plugin/node_modules/side-channel-list/README.md +62 -0
- package/plugin/node_modules/side-channel-list/index.d.ts +13 -0
- package/plugin/node_modules/side-channel-list/index.js +113 -0
- package/plugin/node_modules/side-channel-list/list.d.ts +14 -0
- package/plugin/node_modules/side-channel-list/package.json +77 -0
- package/plugin/node_modules/side-channel-list/tsconfig.json +9 -0
- package/plugin/node_modules/side-channel-map/.editorconfig +9 -0
- package/plugin/node_modules/side-channel-map/.eslintrc +11 -0
- package/plugin/node_modules/side-channel-map/.nycrc +13 -0
- package/plugin/node_modules/side-channel-map/CHANGELOG.md +22 -0
- package/plugin/node_modules/side-channel-map/LICENSE +21 -0
- package/plugin/node_modules/side-channel-map/README.md +62 -0
- package/plugin/node_modules/side-channel-map/index.d.ts +15 -0
- package/plugin/node_modules/side-channel-map/index.js +68 -0
- package/plugin/node_modules/side-channel-map/package.json +80 -0
- package/plugin/node_modules/side-channel-map/tsconfig.json +9 -0
- package/plugin/node_modules/side-channel-weakmap/.editorconfig +9 -0
- package/plugin/node_modules/side-channel-weakmap/.eslintrc +12 -0
- package/plugin/node_modules/side-channel-weakmap/.nycrc +13 -0
- package/plugin/node_modules/side-channel-weakmap/CHANGELOG.md +28 -0
- package/plugin/node_modules/side-channel-weakmap/LICENSE +21 -0
- package/plugin/node_modules/side-channel-weakmap/README.md +62 -0
- package/plugin/node_modules/side-channel-weakmap/index.d.ts +15 -0
- package/plugin/node_modules/side-channel-weakmap/index.js +84 -0
- package/plugin/node_modules/side-channel-weakmap/package.json +87 -0
- package/plugin/node_modules/side-channel-weakmap/tsconfig.json +9 -0
- package/plugin/node_modules/simple-concat/.travis.yml +3 -0
- package/plugin/node_modules/simple-concat/LICENSE +20 -0
- package/plugin/node_modules/simple-concat/README.md +44 -0
- package/plugin/node_modules/simple-concat/index.js +15 -0
- package/plugin/node_modules/simple-concat/package.json +47 -0
- package/plugin/node_modules/simple-get/LICENSE +20 -0
- package/plugin/node_modules/simple-get/README.md +333 -0
- package/plugin/node_modules/simple-get/index.js +108 -0
- package/plugin/node_modules/simple-get/package.json +67 -0
- package/plugin/node_modules/sprintf-js/CONTRIBUTORS.md +26 -0
- package/plugin/node_modules/sprintf-js/LICENSE +24 -0
- package/plugin/node_modules/sprintf-js/README.md +143 -0
- package/plugin/node_modules/sprintf-js/package.json +35 -0
- package/plugin/node_modules/sqlite-vec/README.md +1 -0
- package/plugin/node_modules/sqlite-vec/index.cjs +58 -0
- package/plugin/node_modules/sqlite-vec/index.d.ts +17 -0
- package/plugin/node_modules/sqlite-vec/index.mjs +58 -0
- package/plugin/node_modules/sqlite-vec/package.json +1 -0
- package/plugin/node_modules/sqlite-vec-linux-x64/README.md +1 -0
- package/plugin/node_modules/sqlite-vec-linux-x64/package.json +1 -0
- package/plugin/node_modules/sqlite-vec-linux-x64/vec0.so +0 -0
- package/plugin/node_modules/statuses/HISTORY.md +87 -0
- package/plugin/node_modules/statuses/LICENSE +23 -0
- package/plugin/node_modules/statuses/README.md +139 -0
- package/plugin/node_modules/statuses/codes.json +65 -0
- package/plugin/node_modules/statuses/index.js +146 -0
- package/plugin/node_modules/statuses/package.json +49 -0
- package/plugin/node_modules/string_decoder/LICENSE +48 -0
- package/plugin/node_modules/string_decoder/README.md +47 -0
- package/plugin/node_modules/string_decoder/package.json +34 -0
- package/plugin/node_modules/strip-json-comments/index.js +70 -0
- package/plugin/node_modules/strip-json-comments/license +21 -0
- package/plugin/node_modules/strip-json-comments/package.json +42 -0
- package/plugin/node_modules/strip-json-comments/readme.md +64 -0
- package/plugin/node_modules/tar/LICENSE.md +55 -0
- package/plugin/node_modules/tar/README.md +1145 -0
- package/plugin/node_modules/tar/package.json +292 -0
- package/plugin/node_modules/tar-fs/.travis.yml +6 -0
- package/plugin/node_modules/tar-fs/LICENSE +21 -0
- package/plugin/node_modules/tar-fs/README.md +165 -0
- package/plugin/node_modules/tar-fs/index.js +363 -0
- package/plugin/node_modules/tar-fs/package.json +41 -0
- package/plugin/node_modules/tar-stream/LICENSE +21 -0
- package/plugin/node_modules/tar-stream/README.md +168 -0
- package/plugin/node_modules/tar-stream/extract.js +257 -0
- package/plugin/node_modules/tar-stream/headers.js +295 -0
- package/plugin/node_modules/tar-stream/index.js +2 -0
- package/plugin/node_modules/tar-stream/pack.js +255 -0
- package/plugin/node_modules/tar-stream/package.json +58 -0
- package/plugin/node_modules/tar-stream/sandbox.js +11 -0
- package/plugin/node_modules/toidentifier/HISTORY.md +9 -0
- package/plugin/node_modules/toidentifier/LICENSE +21 -0
- package/plugin/node_modules/toidentifier/README.md +61 -0
- package/plugin/node_modules/toidentifier/index.js +32 -0
- package/plugin/node_modules/toidentifier/package.json +38 -0
- package/plugin/node_modules/tunnel-agent/LICENSE +55 -0
- package/plugin/node_modules/tunnel-agent/README.md +4 -0
- package/plugin/node_modules/tunnel-agent/index.js +244 -0
- package/plugin/node_modules/tunnel-agent/package.json +22 -0
- package/plugin/node_modules/type-fest/index.d.ts +29 -0
- package/plugin/node_modules/type-fest/license +9 -0
- package/plugin/node_modules/type-fest/package.json +45 -0
- package/plugin/node_modules/type-fest/readme.md +642 -0
- package/plugin/node_modules/type-is/HISTORY.md +292 -0
- package/plugin/node_modules/type-is/LICENSE +23 -0
- package/plugin/node_modules/type-is/README.md +198 -0
- package/plugin/node_modules/type-is/index.js +250 -0
- package/plugin/node_modules/type-is/package.json +47 -0
- package/plugin/node_modules/undici-types/LICENSE +21 -0
- package/plugin/node_modules/undici-types/README.md +6 -0
- package/plugin/node_modules/undici-types/agent.d.ts +32 -0
- package/plugin/node_modules/undici-types/api.d.ts +43 -0
- package/plugin/node_modules/undici-types/balanced-pool.d.ts +30 -0
- package/plugin/node_modules/undici-types/cache-interceptor.d.ts +173 -0
- package/plugin/node_modules/undici-types/cache.d.ts +36 -0
- package/plugin/node_modules/undici-types/client-stats.d.ts +15 -0
- package/plugin/node_modules/undici-types/client.d.ts +108 -0
- package/plugin/node_modules/undici-types/connector.d.ts +34 -0
- package/plugin/node_modules/undici-types/content-type.d.ts +21 -0
- package/plugin/node_modules/undici-types/cookies.d.ts +30 -0
- package/plugin/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/plugin/node_modules/undici-types/dispatcher.d.ts +276 -0
- package/plugin/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/plugin/node_modules/undici-types/errors.d.ts +161 -0
- package/plugin/node_modules/undici-types/eventsource.d.ts +66 -0
- package/plugin/node_modules/undici-types/fetch.d.ts +211 -0
- package/plugin/node_modules/undici-types/formdata.d.ts +108 -0
- package/plugin/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/plugin/node_modules/undici-types/global-origin.d.ts +7 -0
- package/plugin/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/plugin/node_modules/undici-types/handlers.d.ts +15 -0
- package/plugin/node_modules/undici-types/header.d.ts +160 -0
- package/plugin/node_modules/undici-types/index.d.ts +88 -0
- package/plugin/node_modules/undici-types/interceptors.d.ts +73 -0
- package/plugin/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/plugin/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/plugin/node_modules/undici-types/mock-client.d.ts +27 -0
- package/plugin/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/plugin/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/plugin/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/plugin/node_modules/undici-types/package.json +55 -0
- package/plugin/node_modules/undici-types/patch.d.ts +29 -0
- package/plugin/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/plugin/node_modules/undici-types/pool.d.ts +41 -0
- package/plugin/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/plugin/node_modules/undici-types/readable.d.ts +68 -0
- package/plugin/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/plugin/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/plugin/node_modules/undici-types/round-robin-pool.d.ts +41 -0
- package/plugin/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/plugin/node_modules/undici-types/util.d.ts +18 -0
- package/plugin/node_modules/undici-types/utility.d.ts +7 -0
- package/plugin/node_modules/undici-types/webidl.d.ts +341 -0
- package/plugin/node_modules/undici-types/websocket.d.ts +186 -0
- package/plugin/node_modules/unpipe/HISTORY.md +4 -0
- package/plugin/node_modules/unpipe/LICENSE +22 -0
- package/plugin/node_modules/unpipe/README.md +43 -0
- package/plugin/node_modules/unpipe/index.js +69 -0
- package/plugin/node_modules/unpipe/package.json +27 -0
- package/plugin/node_modules/util-deprecate/History.md +16 -0
- package/plugin/node_modules/util-deprecate/LICENSE +24 -0
- package/plugin/node_modules/util-deprecate/README.md +53 -0
- package/plugin/node_modules/util-deprecate/browser.js +67 -0
- package/plugin/node_modules/util-deprecate/node.js +6 -0
- package/plugin/node_modules/util-deprecate/package.json +27 -0
- package/plugin/node_modules/vary/HISTORY.md +39 -0
- package/plugin/node_modules/vary/LICENSE +22 -0
- package/plugin/node_modules/vary/README.md +101 -0
- package/plugin/node_modules/vary/index.js +149 -0
- package/plugin/node_modules/vary/package.json +43 -0
- package/plugin/node_modules/which/CHANGELOG.md +166 -0
- package/plugin/node_modules/which/LICENSE +15 -0
- package/plugin/node_modules/which/README.md +54 -0
- package/plugin/node_modules/which/package.json +43 -0
- package/plugin/node_modules/which/which.js +125 -0
- package/plugin/node_modules/wrappy/LICENSE +15 -0
- package/plugin/node_modules/wrappy/README.md +36 -0
- package/plugin/node_modules/wrappy/package.json +29 -0
- package/plugin/node_modules/wrappy/wrappy.js +33 -0
- package/plugin/node_modules/yallist/LICENSE.md +63 -0
- package/plugin/node_modules/yallist/README.md +205 -0
- package/plugin/node_modules/yallist/package.json +68 -0
- package/plugin/node_modules/zod/LICENSE +21 -0
- package/plugin/node_modules/zod/README.md +208 -0
- package/plugin/node_modules/zod/index.cjs +33 -0
- package/plugin/node_modules/zod/index.d.cts +4 -0
- package/plugin/node_modules/zod/index.d.ts +4 -0
- package/plugin/node_modules/zod/index.js +4 -0
- package/plugin/node_modules/zod/package.json +135 -0
- package/plugin/node_modules/zod-to-json-schema/.prettierrc.json +1 -0
- package/plugin/node_modules/zod-to-json-schema/LICENSE +15 -0
- package/plugin/node_modules/zod-to-json-schema/README.md +390 -0
- package/plugin/node_modules/zod-to-json-schema/changelog.md +82 -0
- package/plugin/node_modules/zod-to-json-schema/contributing.md +9 -0
- package/plugin/node_modules/zod-to-json-schema/createIndex.ts +32 -0
- package/plugin/node_modules/zod-to-json-schema/package.json +78 -0
- package/plugin/node_modules/zod-to-json-schema/postcjs.ts +3 -0
- package/plugin/node_modules/zod-to-json-schema/postesm.ts +3 -0
- package/plugin/package-lock.json +2654 -0
- package/plugin/scripts/dev-sync.sh +26 -8
- package/plugin/scripts/doctor.sh +235 -0
- package/plugin/scripts/ensure-deps.sh +82 -2
- package/plugin/scripts/install.sh +87 -45
- package/plugin/scripts/local-install.sh +112 -84
- package/plugin/scripts/repair.sh +71 -0
- package/plugin/scripts/uninstall.sh +74 -47
- package/plugin/scripts/update.sh +29 -4
- package/plugin/scripts/verify-install.sh +87 -35
- package/plugin/skills/doctor/SKILL.md +16 -0
- package/plugin/dist/tool-registry-D8un_AcG.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry-Bi1Zdqkm.mjs","names":["up","graphTablesDDL","projectHashIndexDDL"],"sources":["../../src/shared/debug.ts","../../src/storage/migrations.ts","../../src/storage/database.ts","../../src/shared/types.ts","../../src/storage/observations.ts","../../src/storage/sessions.ts","../../src/storage/search.ts","../../src/search/hybrid.ts","../../src/shared/similarity.ts","../../src/hooks/save-guard.ts","../../src/graph/migrations/001-graph-tables.ts","../../src/graph/migrations/002-project-hash-index.ts","../../src/graph/schema.ts","../../src/graph/staleness.ts","../../src/config/hygiene-config.ts","../../src/graph/hygiene-analyzer.ts","../../src/hooks/tool-name-parser.ts","../../src/branches/branch-repository.ts","../../src/storage/research-buffer.ts","../../src/storage/notifications.ts","../../src/paths/schema.ts","../../src/paths/path-repository.ts","../../src/storage/tool-registry.ts"],"sourcesContent":["import { isDebugEnabled } from './config.js';\n\n/**\n * Internal cached state for debug mode.\n * Resolved on first call and never changes (debug mode is process-lifetime).\n */\nlet _enabled: boolean | null = null;\n\nfunction enabled(): boolean {\n if (_enabled === null) {\n _enabled = isDebugEnabled();\n }\n return _enabled;\n}\n\n/**\n * Logs a debug message to stderr when debug mode is active.\n *\n * When debug is disabled (the default), this is a near-zero-cost no-op after the\n * first call -- the cached flag short-circuits immediately.\n *\n * Format: `[ISO_TIMESTAMP] [LAMINARK:category] message {json_data}`\n *\n * @param category - Debug category (e.g., 'db', 'obs', 'search', 'session')\n * @param message - Human-readable log message\n * @param data - Optional structured data to include (keep lightweight -- no large payloads)\n */\nexport function debug(\n category: string,\n message: string,\n data?: Record<string, unknown>,\n): void {\n if (!enabled()) {\n return;\n }\n\n const timestamp = new Date().toISOString();\n let line = `[${timestamp}] [LAMINARK:${category}] ${message}`;\n if (data !== undefined) {\n line += ` ${JSON.stringify(data)}`;\n }\n process.stderr.write(line + '\\n');\n}\n\n/**\n * Wraps a synchronous function with timing instrumentation.\n *\n * When debug is disabled, calls `fn()` directly with zero overhead --\n * no timing measurement, no wrapping.\n *\n * @param category - Debug category for the log line\n * @param message - Description of the operation being timed\n * @param fn - Synchronous function to execute and time\n * @returns The return value of `fn()`\n */\nexport function debugTimed<T>(\n category: string,\n message: string,\n fn: () => T,\n): T {\n if (!enabled()) {\n return fn();\n }\n\n const start = performance.now();\n const result = fn();\n const duration = (performance.now() - start).toFixed(2);\n debug(category, `${message} (${duration}ms)`);\n return result;\n}\n","import type BetterSqlite3 from 'better-sqlite3';\n\n/**\n * A versioned schema migration.\n * Migrations are applied in order and tracked in the _migrations table.\n */\nexport interface Migration {\n version: number;\n name: string;\n up: string | ((db: BetterSqlite3.Database) => void); // SQL string or function\n}\n\n/**\n * All schema migrations in order.\n *\n * Migration 001: Observations table with INTEGER PRIMARY KEY AUTOINCREMENT\n * (critical for FTS5 content_rowid stability across VACUUM).\n * Migration 002: Sessions table for session lifecycle tracking.\n * Migration 003: FTS5 external content table with porter+unicode61 tokenizer\n * and three sync triggers (INSERT, UPDATE, DELETE).\n * Migration 004: sqlite-vec vec0 table for 384-dim embeddings (conditional).\n * Migration 005: Add title column to observations and rebuild FTS5 with\n * title+content dual-column indexing.\n * Migration 006: Recreate vec0 table with cosine distance metric (conditional).\n * Migration 007: Context stashes table for topic detection thread snapshots.\n * Migration 008: Threshold history table for EWMA adaptive threshold seeding.\n * Migration 009: Shift decisions table for topic shift decision logging.\n * Migration 010: Project metadata table for project selector UI.\n * Migration 011: Add project_hash to graph tables and backfill from observations.\n * Migration 012: Add classification and classified_at columns for LLM-based observation classification.\n * Migration 013: Research buffer table for exploration tool event buffering.\n * Migration 014: Add kind column to observations with backfill from source field.\n * Migration 015: Update graph taxonomy -- remove Tool/Person nodes, tighten CHECK constraints.\n * Migration 016: Tool registry table for discovered tools with scope-aware uniqueness.\n * Migration 017: Tool usage events table for per-event temporal tracking.\n * Migration 018: Tool registry FTS5 + vec0 tables for hybrid search on tool descriptions.\n * Migration 019: Add status column (active/stale/demoted) to tool_registry for staleness management.\n * Migration 020: Debug path tables (debug_paths + path_waypoints) for resolution path tracking.\n * Migration 021: Thought branch tables for coherent work unit tracking.\n * Migration 022: Add trigger_hints column to tool_registry for proactive suggestion matching.\n */\nexport const MIGRATIONS: Migration[] = [\n {\n version: 1,\n name: 'create_observations',\n up: `\n CREATE TABLE observations (\n rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE DEFAULT (lower(hex(randomblob(16)))),\n project_hash TEXT NOT NULL,\n content TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'unknown',\n session_id TEXT,\n embedding BLOB,\n embedding_model TEXT,\n embedding_version TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n deleted_at TEXT\n );\n\n CREATE INDEX idx_observations_project ON observations(project_hash);\n CREATE INDEX idx_observations_session ON observations(session_id);\n CREATE INDEX idx_observations_created ON observations(created_at);\n CREATE INDEX idx_observations_deleted ON observations(deleted_at) WHERE deleted_at IS NOT NULL;\n `,\n },\n {\n version: 2,\n name: 'create_sessions',\n up: `\n CREATE TABLE sessions (\n id TEXT PRIMARY KEY,\n project_hash TEXT NOT NULL,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n ended_at TEXT,\n summary TEXT\n );\n\n CREATE INDEX idx_sessions_project ON sessions(project_hash);\n CREATE INDEX idx_sessions_started ON sessions(started_at);\n `,\n },\n {\n version: 3,\n name: 'create_fts5_observations',\n up: `\n CREATE VIRTUAL TABLE observations_fts USING fts5(\n content,\n content='observations',\n content_rowid='rowid',\n tokenize='porter unicode61'\n );\n\n -- Sync trigger: INSERT\n CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN\n INSERT INTO observations_fts(rowid, content)\n VALUES (new.rowid, new.content);\n END;\n\n -- Sync trigger: UPDATE (delete old entry, insert new)\n CREATE TRIGGER observations_au AFTER UPDATE ON observations BEGIN\n INSERT INTO observations_fts(observations_fts, rowid, content)\n VALUES('delete', old.rowid, old.content);\n INSERT INTO observations_fts(rowid, content)\n VALUES (new.rowid, new.content);\n END;\n\n -- Sync trigger: DELETE\n CREATE TRIGGER observations_ad AFTER DELETE ON observations BEGIN\n INSERT INTO observations_fts(observations_fts, rowid, content)\n VALUES('delete', old.rowid, old.content);\n END;\n `,\n },\n {\n version: 4,\n name: 'create_vec0_embeddings',\n up: `\n CREATE VIRTUAL TABLE IF NOT EXISTS observation_embeddings USING vec0(\n observation_id TEXT PRIMARY KEY,\n embedding float[384]\n );\n `,\n },\n {\n version: 5,\n name: 'add_observation_title',\n up: `\n ALTER TABLE observations ADD COLUMN title TEXT;\n\n DROP TRIGGER observations_ai;\n DROP TRIGGER observations_au;\n DROP TRIGGER observations_ad;\n DROP TABLE observations_fts;\n\n CREATE VIRTUAL TABLE observations_fts USING fts5(\n title,\n content,\n content='observations',\n content_rowid='rowid',\n tokenize='porter unicode61'\n );\n\n CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN\n INSERT INTO observations_fts(rowid, title, content)\n VALUES (new.rowid, new.title, new.content);\n END;\n\n CREATE TRIGGER observations_au AFTER UPDATE ON observations BEGIN\n INSERT INTO observations_fts(observations_fts, rowid, title, content)\n VALUES('delete', old.rowid, old.title, old.content);\n INSERT INTO observations_fts(rowid, title, content)\n VALUES (new.rowid, new.title, new.content);\n END;\n\n CREATE TRIGGER observations_ad AFTER DELETE ON observations BEGIN\n INSERT INTO observations_fts(observations_fts, rowid, title, content)\n VALUES('delete', old.rowid, old.title, old.content);\n END;\n\n INSERT INTO observations_fts(observations_fts) VALUES('rebuild');\n `,\n },\n {\n version: 6,\n name: 'recreate_vec0_cosine_distance',\n up: `\n DROP TABLE IF EXISTS observation_embeddings;\n CREATE VIRTUAL TABLE IF NOT EXISTS observation_embeddings USING vec0(\n observation_id TEXT PRIMARY KEY,\n embedding float[384] distance_metric=cosine\n );\n `,\n },\n {\n version: 7,\n name: 'create_context_stashes',\n up: `\n CREATE TABLE context_stashes (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n topic_label TEXT NOT NULL,\n summary TEXT NOT NULL,\n observation_snapshots TEXT NOT NULL,\n observation_ids TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'stashed',\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n resumed_at TEXT\n );\n\n CREATE INDEX idx_stashes_project_status_created\n ON context_stashes(project_id, status, created_at DESC);\n\n CREATE INDEX idx_stashes_session\n ON context_stashes(session_id);\n `,\n },\n {\n version: 8,\n name: 'create_threshold_history',\n up: `\n CREATE TABLE threshold_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n final_ewma_distance REAL NOT NULL,\n final_ewma_variance REAL NOT NULL,\n observation_count INTEGER NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX idx_threshold_history_project\n ON threshold_history(project_id, created_at DESC);\n `,\n },\n {\n version: 9,\n name: 'create_shift_decisions',\n up: `\n CREATE TABLE shift_decisions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n observation_id TEXT,\n distance REAL NOT NULL,\n threshold REAL NOT NULL,\n ewma_distance REAL,\n ewma_variance REAL,\n sensitivity_multiplier REAL,\n shifted INTEGER NOT NULL,\n confidence REAL,\n stash_id TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX idx_shift_decisions_session\n ON shift_decisions(project_id, session_id, created_at DESC);\n\n CREATE INDEX idx_shift_decisions_shifted\n ON shift_decisions(shifted, created_at DESC);\n `,\n },\n {\n version: 10,\n name: 'create_project_metadata',\n up: `\n CREATE TABLE IF NOT EXISTS project_metadata (\n project_hash TEXT PRIMARY KEY,\n project_path TEXT NOT NULL,\n display_name TEXT,\n last_seen_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n `,\n },\n {\n version: 11,\n name: 'add_project_hash_to_graph_tables',\n up: (db: BetterSqlite3.Database) => {\n // Graph tables are created by initGraphSchema() (separate from main migrations).\n // They may or may not exist, and may or may not already have project_hash.\n const tableExists = (name: string) =>\n !!db.prepare(\"SELECT 1 FROM sqlite_master WHERE type='table' AND name=?\").get(name);\n\n const columnExists = (table: string, column: string) => {\n const cols = db.prepare(`PRAGMA table_info('${table}')`).all() as Array<{ name: string }>;\n return cols.some(c => c.name === column);\n };\n\n if (tableExists('graph_nodes') && !columnExists('graph_nodes', 'project_hash')) {\n db.exec('ALTER TABLE graph_nodes ADD COLUMN project_hash TEXT');\n\n // Backfill from linked observations\n db.exec(`\n UPDATE graph_nodes SET project_hash = (\n SELECT o.project_hash FROM observations o\n WHERE o.id IN (\n SELECT value FROM json_each(graph_nodes.observation_ids)\n )\n LIMIT 1\n ) WHERE project_hash IS NULL\n `);\n }\n\n if (tableExists('graph_edges') && !columnExists('graph_edges', 'project_hash')) {\n db.exec('ALTER TABLE graph_edges ADD COLUMN project_hash TEXT');\n\n // Backfill from source node\n db.exec(`\n UPDATE graph_edges SET project_hash = (\n SELECT gn.project_hash FROM graph_nodes gn\n WHERE gn.id = graph_edges.source_id\n ) WHERE project_hash IS NULL\n `);\n }\n\n // Indexes are safe with IF NOT EXISTS\n if (tableExists('graph_nodes')) {\n db.exec('CREATE INDEX IF NOT EXISTS idx_graph_nodes_project ON graph_nodes(project_hash)');\n }\n if (tableExists('graph_edges')) {\n db.exec('CREATE INDEX IF NOT EXISTS idx_graph_edges_project ON graph_edges(project_hash)');\n }\n },\n },\n {\n version: 12,\n name: 'add_observation_classification',\n up: `\n ALTER TABLE observations ADD COLUMN classification TEXT;\n ALTER TABLE observations ADD COLUMN classified_at TEXT;\n CREATE INDEX idx_observations_classification\n ON observations(classification) WHERE classification IS NOT NULL;\n `,\n },\n {\n version: 13,\n name: 'create_research_buffer',\n up: `\n CREATE TABLE research_buffer (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_hash TEXT NOT NULL,\n session_id TEXT,\n tool_name TEXT NOT NULL,\n target TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE INDEX idx_research_buffer_session ON research_buffer(session_id, created_at DESC);\n `,\n },\n {\n version: 14,\n name: 'add_observation_kind',\n up: (db: BetterSqlite3.Database) => {\n // Add kind column\n db.exec(\"ALTER TABLE observations ADD COLUMN kind TEXT DEFAULT 'finding'\");\n\n // Backfill from source field\n db.exec(`\n UPDATE observations SET kind = 'change'\n WHERE source LIKE 'hook:Write' OR source LIKE 'hook:Edit'\n `);\n db.exec(`\n UPDATE observations SET kind = 'verification'\n WHERE source LIKE 'hook:Bash'\n `);\n db.exec(`\n UPDATE observations SET kind = 'reference'\n WHERE source LIKE 'hook:WebFetch' OR source LIKE 'hook:WebSearch'\n `);\n db.exec(`\n UPDATE observations SET kind = 'finding'\n WHERE source IN ('mcp:save_memory', 'manual', 'slash:remember')\n AND kind = 'finding'\n `);\n\n // Soft-delete old noise observations from Read/Glob/Grep hooks\n db.exec(`\n UPDATE observations\n SET deleted_at = datetime('now'), updated_at = datetime('now')\n WHERE (source LIKE 'hook:Read' OR source LIKE 'hook:Glob' OR source LIKE 'hook:Grep')\n AND deleted_at IS NULL\n `);\n\n // Index for kind-based queries\n db.exec('CREATE INDEX idx_observations_kind ON observations(kind)');\n },\n },\n {\n version: 15,\n name: 'update_graph_taxonomy',\n up: (db: BetterSqlite3.Database) => {\n // Check if graph tables exist\n const tableExists = (name: string) =>\n !!db.prepare(\"SELECT 1 FROM sqlite_master WHERE type='table' AND name=?\").get(name);\n\n if (!tableExists('graph_nodes')) return;\n\n // Delete old Tool and Person nodes (and their connected edges via CASCADE)\n db.exec(\"DELETE FROM graph_nodes WHERE type IN ('Tool', 'Person')\");\n\n // Delete old relationship types that no longer exist\n db.exec(\"DELETE FROM graph_edges WHERE type IN ('uses', 'depends_on', 'decided_by', 'part_of')\");\n\n // Recreate graph_nodes with updated CHECK constraint\n db.exec(`\n CREATE TABLE graph_nodes_new (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('Project','File','Decision','Problem','Solution','Reference')),\n name TEXT NOT NULL,\n metadata TEXT DEFAULT '{}',\n observation_ids TEXT DEFAULT '[]',\n project_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n INSERT INTO graph_nodes_new SELECT * FROM graph_nodes;\n\n DROP TABLE graph_nodes;\n ALTER TABLE graph_nodes_new RENAME TO graph_nodes;\n\n CREATE INDEX idx_graph_nodes_type ON graph_nodes(type);\n CREATE INDEX idx_graph_nodes_name ON graph_nodes(name);\n CREATE INDEX IF NOT EXISTS idx_graph_nodes_project ON graph_nodes(project_hash);\n `);\n\n // Recreate graph_edges with updated CHECK constraint\n db.exec(`\n CREATE TABLE graph_edges_new (\n id TEXT PRIMARY KEY,\n source_id TEXT NOT NULL REFERENCES graph_nodes(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES graph_nodes(id) ON DELETE CASCADE,\n type TEXT NOT NULL CHECK(type IN ('related_to','solved_by','caused_by','modifies','informed_by','references','verified_by','preceded_by')),\n weight REAL NOT NULL DEFAULT 1.0 CHECK(weight >= 0.0 AND weight <= 1.0),\n metadata TEXT DEFAULT '{}',\n project_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n INSERT INTO graph_edges_new SELECT * FROM graph_edges;\n\n DROP TABLE graph_edges;\n ALTER TABLE graph_edges_new RENAME TO graph_edges;\n\n CREATE INDEX idx_graph_edges_source ON graph_edges(source_id);\n CREATE INDEX idx_graph_edges_target ON graph_edges(target_id);\n CREATE INDEX idx_graph_edges_type ON graph_edges(type);\n CREATE UNIQUE INDEX idx_graph_edges_unique ON graph_edges(source_id, target_id, type);\n CREATE INDEX IF NOT EXISTS idx_graph_edges_project ON graph_edges(project_hash);\n `);\n },\n },\n {\n version: 16,\n name: 'create_tool_registry',\n up: `\n CREATE TABLE tool_registry (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n tool_type TEXT NOT NULL,\n scope TEXT NOT NULL,\n source TEXT NOT NULL,\n project_hash TEXT,\n description TEXT,\n server_name TEXT,\n usage_count INTEGER NOT NULL DEFAULT 0,\n last_used_at TEXT,\n discovered_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE UNIQUE INDEX idx_tool_registry_name_project\n ON tool_registry(name, COALESCE(project_hash, ''));\n CREATE INDEX idx_tool_registry_scope\n ON tool_registry(scope);\n CREATE INDEX idx_tool_registry_project\n ON tool_registry(project_hash) WHERE project_hash IS NOT NULL;\n CREATE INDEX idx_tool_registry_usage\n ON tool_registry(usage_count DESC, last_used_at DESC);\n `,\n },\n {\n version: 17,\n name: 'create_tool_usage_events',\n up: `\n CREATE TABLE tool_usage_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n tool_name TEXT NOT NULL,\n session_id TEXT,\n project_hash TEXT,\n success INTEGER NOT NULL DEFAULT 1,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX idx_tool_usage_events_tool\n ON tool_usage_events(tool_name, created_at DESC);\n CREATE INDEX idx_tool_usage_events_session\n ON tool_usage_events(session_id) WHERE session_id IS NOT NULL;\n CREATE INDEX idx_tool_usage_events_project_time\n ON tool_usage_events(project_hash, created_at DESC);\n `,\n },\n {\n version: 18,\n name: 'create_tool_registry_search',\n up: (db: BetterSqlite3.Database) => {\n // FTS5 external content table for tool registry (always created)\n db.exec(`\n CREATE VIRTUAL TABLE tool_registry_fts USING fts5(\n name,\n description,\n content='tool_registry',\n content_rowid='id',\n tokenize='porter unicode61'\n );\n\n -- Sync trigger: INSERT\n CREATE TRIGGER tool_registry_ai AFTER INSERT ON tool_registry BEGIN\n INSERT INTO tool_registry_fts(rowid, name, description)\n VALUES (new.id, new.name, new.description);\n END;\n\n -- Sync trigger: UPDATE (delete old entry, insert new)\n CREATE TRIGGER tool_registry_au AFTER UPDATE ON tool_registry BEGIN\n INSERT INTO tool_registry_fts(tool_registry_fts, rowid, name, description)\n VALUES('delete', old.id, old.name, old.description);\n INSERT INTO tool_registry_fts(rowid, name, description)\n VALUES (new.id, new.name, new.description);\n END;\n\n -- Sync trigger: DELETE\n CREATE TRIGGER tool_registry_ad AFTER DELETE ON tool_registry BEGIN\n INSERT INTO tool_registry_fts(tool_registry_fts, rowid, name, description)\n VALUES('delete', old.id, old.name, old.description);\n END;\n\n -- Rebuild to index existing tool_registry rows\n INSERT INTO tool_registry_fts(tool_registry_fts) VALUES('rebuild');\n `);\n\n // vec0 table for tool embeddings (conditional on sqlite-vec availability)\n try {\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS tool_registry_embeddings USING vec0(\n tool_id INTEGER PRIMARY KEY,\n embedding float[384] distance_metric=cosine\n );\n `);\n } catch {\n // sqlite-vec not available -- skip silently, vector search will degrade gracefully\n }\n },\n },\n {\n version: 19,\n name: 'add_tool_registry_status',\n up: `\n ALTER TABLE tool_registry ADD COLUMN status TEXT NOT NULL DEFAULT 'active';\n CREATE INDEX idx_tool_registry_status ON tool_registry(status);\n `,\n },\n {\n version: 20,\n name: 'create_debug_path_tables',\n up: `\n CREATE TABLE IF NOT EXISTS debug_paths (\n id TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'resolved', 'abandoned')),\n trigger_summary TEXT NOT NULL,\n resolution_summary TEXT,\n kiss_summary TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n resolved_at TEXT,\n project_hash TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS path_waypoints (\n id TEXT PRIMARY KEY,\n path_id TEXT NOT NULL REFERENCES debug_paths(id) ON DELETE CASCADE,\n observation_id TEXT,\n waypoint_type TEXT NOT NULL CHECK(waypoint_type IN ('error', 'attempt', 'failure', 'success', 'pivot', 'revert', 'discovery', 'resolution')),\n sequence_order INTEGER NOT NULL,\n summary TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_debug_paths_project_status\n ON debug_paths(project_hash, status);\n\n CREATE INDEX IF NOT EXISTS idx_debug_paths_started\n ON debug_paths(started_at DESC);\n\n CREATE INDEX IF NOT EXISTS idx_path_waypoints_path_order\n ON path_waypoints(path_id, sequence_order);\n `,\n },\n {\n version: 21,\n name: 'create_thought_branch_tables',\n up: `\n CREATE TABLE IF NOT EXISTS thought_branches (\n id TEXT PRIMARY KEY,\n project_hash TEXT NOT NULL,\n session_id TEXT,\n status TEXT NOT NULL DEFAULT 'active'\n CHECK(status IN ('active', 'completed', 'abandoned', 'merged')),\n branch_type TEXT NOT NULL DEFAULT 'unknown'\n CHECK(branch_type IN ('investigation', 'bug_fix', 'feature', 'refactor', 'research', 'unknown')),\n arc_stage TEXT NOT NULL DEFAULT 'investigation'\n CHECK(arc_stage IN ('investigation', 'diagnosis', 'planning', 'execution', 'verification', 'completed')),\n title TEXT,\n summary TEXT,\n parent_branch_id TEXT REFERENCES thought_branches(id),\n linked_debug_path_id TEXT,\n trigger_source TEXT,\n trigger_observation_id TEXT,\n observation_count INTEGER NOT NULL DEFAULT 0,\n tool_pattern TEXT DEFAULT '{}',\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n ended_at TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS branch_observations (\n branch_id TEXT NOT NULL REFERENCES thought_branches(id) ON DELETE CASCADE,\n observation_id TEXT NOT NULL,\n sequence_order INTEGER NOT NULL,\n tool_name TEXT,\n arc_stage_at_add TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (branch_id, observation_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_thought_branches_project_status\n ON thought_branches(project_hash, status);\n CREATE INDEX IF NOT EXISTS idx_thought_branches_session\n ON thought_branches(session_id);\n CREATE INDEX IF NOT EXISTS idx_thought_branches_started\n ON thought_branches(started_at DESC);\n CREATE INDEX IF NOT EXISTS idx_branch_observations_obs\n ON branch_observations(observation_id);\n `,\n },\n {\n version: 22,\n name: 'add_tool_registry_trigger_hints',\n up: `\n ALTER TABLE tool_registry ADD COLUMN trigger_hints TEXT;\n `,\n },\n];\n\n/**\n * Applies unapplied schema migrations in order.\n *\n * Creates a _migrations tracking table if it does not exist, then applies\n * each migration whose version exceeds the current max applied version.\n * Each migration runs inside a transaction for atomicity.\n *\n * Migrations 004 and 006 (vec0 tables) are only applied when hasVectorSupport\n * is true. If sqlite-vec is not available, they are silently skipped and will\n * be applied on a future run when the extension becomes available.\n *\n * @param db - An open better-sqlite3 database connection\n * @param hasVectorSupport - Whether sqlite-vec loaded successfully\n */\nexport function runMigrations(\n db: BetterSqlite3.Database,\n hasVectorSupport: boolean,\n): void {\n // Create tracking table\n db.exec(`\n CREATE TABLE IF NOT EXISTS _migrations (\n version INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `);\n\n // Get current max applied version\n const maxVersion = db.prepare(\n 'SELECT COALESCE(MAX(version), 0) FROM _migrations',\n ).pluck().get() as number;\n\n // Prepare insert statement\n const insertMigration = db.prepare(\n 'INSERT INTO _migrations (version, name) VALUES (?, ?)',\n );\n\n // Apply each unapplied migration in a transaction\n const applyMigration = db.transaction((m: Migration) => {\n if (typeof m.up === 'function') {\n m.up(db);\n } else {\n db.exec(m.up);\n }\n insertMigration.run(m.version, m.name);\n });\n\n for (const migration of MIGRATIONS) {\n if (migration.version <= maxVersion) {\n continue;\n }\n\n // Skip vec0 migrations if sqlite-vec is not available\n if ((migration.version === 4 || migration.version === 6) && !hasVectorSupport) {\n continue;\n }\n\n applyMigration(migration);\n }\n}\n","import Database from 'better-sqlite3';\nimport * as sqliteVec from 'sqlite-vec';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { debug } from '../shared/debug.js';\nimport type { DatabaseConfig } from '../shared/types.js';\nimport { runMigrations } from './migrations.js';\n\n/**\n * Wrapper around a configured better-sqlite3 database instance.\n * Provides lifecycle methods (close, checkpoint) and tracks whether\n * the sqlite-vec extension loaded successfully.\n */\nexport interface LaminarkDatabase {\n db: Database.Database;\n hasVectorSupport: boolean;\n close(): void;\n checkpoint(): void;\n}\n\n/**\n * Opens a SQLite database with WAL mode, correct PRAGMA order,\n * optional sqlite-vec extension loading, and schema migrations.\n *\n * Single connection per process by design -- better-sqlite3 is synchronous,\n * so connection pooling adds zero benefit.\n *\n * @param config - Database path and busy timeout configuration\n * @returns A configured LaminarkDatabase instance\n */\nexport function openDatabase(config: DatabaseConfig): LaminarkDatabase {\n // 1. Ensure directory exists\n mkdirSync(dirname(config.dbPath), { recursive: true });\n\n // 2. Create connection\n const db = new Database(config.dbPath);\n\n // 3. Set PRAGMAs in correct order (order matters per research)\n // WAL mode MUST be first -- synchronous = NORMAL is only safe with WAL\n const journalMode = db.pragma('journal_mode = WAL', {\n simple: true,\n }) as string;\n if (journalMode !== 'wal') {\n console.warn(\n `WARNING: WAL mode not active (got '${journalMode}'). ` +\n 'Database may be on a read-only filesystem or otherwise restricted.',\n );\n }\n\n // busy_timeout -- per-connection, must set every time\n db.pragma(`busy_timeout = ${config.busyTimeout}`);\n\n // synchronous NORMAL -- safe ONLY with WAL, faster than FULL\n db.pragma('synchronous = NORMAL');\n\n // cache_size -- negative = KiB (64MB)\n db.pragma('cache_size = -64000');\n\n // foreign_keys -- per-connection, not persistent\n db.pragma('foreign_keys = ON');\n\n // temp_store -- temp tables in memory\n db.pragma('temp_store = MEMORY');\n\n // wal_autocheckpoint -- explicit default, prevents WAL growth\n db.pragma('wal_autocheckpoint = 1000');\n\n debug('db', 'PRAGMAs configured', { journalMode, busyTimeout: config.busyTimeout });\n\n // 4. Load sqlite-vec with graceful degradation\n let hasVectorSupport = false;\n try {\n sqliteVec.load(db);\n hasVectorSupport = true;\n } catch {\n // Vector search unavailable -- keyword-only mode\n }\n\n debug('db', hasVectorSupport ? 'sqlite-vec loaded' : 'sqlite-vec unavailable, keyword-only mode');\n\n // 5. Run migrations\n runMigrations(db, hasVectorSupport);\n\n debug('db', 'Database opened', { path: config.dbPath, hasVectorSupport });\n\n // 6. Return LaminarkDatabase\n return {\n db,\n hasVectorSupport,\n\n close(): void {\n try {\n // Flush WAL before shutdown\n db.pragma('wal_checkpoint(PASSIVE)');\n } catch {\n // If checkpoint fails (e.g., locked), still close\n }\n debug('db', 'Database closed');\n db.close();\n },\n\n checkpoint(): void {\n db.pragma('wal_checkpoint(PASSIVE)');\n },\n };\n}\n","import { z } from 'zod';\n\n// =============================================================================\n// Project Hash Reference (cross-project isolation)\n// =============================================================================\n\n/**\n * Mutable reference to the active project hash.\n *\n * The MCP server's process.cwd() returns the plugin install path, NOT the\n * user's project directory. The correct hash is only known after the\n * SessionStart hook writes to `project_metadata`. This ref auto-refreshes\n * from the database so that tool handlers always resolve the current project.\n */\nexport interface ProjectHashRef {\n /** Current project hash — reads may trigger a DB refresh. */\n readonly current: string;\n}\n\n// =============================================================================\n// Database Layer Types (snake_case, matches SQL columns)\n// =============================================================================\n\n/**\n * ObservationRow -- the raw database row shape.\n * Uses snake_case to match SQL column names directly.\n * rowid is INTEGER PRIMARY KEY AUTOINCREMENT for FTS5 content_rowid compatibility.\n */\nexport const ObservationRowSchema = z.object({\n rowid: z.number(),\n id: z.string(),\n project_hash: z.string(),\n content: z.string(),\n title: z.string().nullable(),\n source: z.string(),\n session_id: z.string().nullable(),\n embedding: z.instanceof(Buffer).nullable(),\n embedding_model: z.string().nullable(),\n embedding_version: z.string().nullable(),\n kind: z.string().default('finding'),\n classification: z.string().nullable(),\n classified_at: z.string().nullable(),\n created_at: z.string(),\n updated_at: z.string(),\n deleted_at: z.string().nullable(),\n});\n\nexport type ObservationRow = z.infer<typeof ObservationRowSchema>;\n\n// =============================================================================\n// Application Layer Types (camelCase)\n// =============================================================================\n\n/**\n * Observation -- the application-layer shape.\n * Uses camelCase for idiomatic TypeScript.\n * embedding is Float32Array (converted from Buffer during mapping).\n */\nexport type ObservationClassification = 'discovery' | 'problem' | 'solution' | 'noise';\n\nexport type ObservationKind = 'change' | 'reference' | 'finding' | 'decision' | 'verification';\n\nexport interface Observation {\n rowid: number;\n id: string;\n projectHash: string;\n content: string;\n title: string | null;\n source: string;\n sessionId: string | null;\n kind: ObservationKind;\n embedding: Float32Array | null;\n embeddingModel: string | null;\n embeddingVersion: string | null;\n classification: ObservationClassification | null;\n classifiedAt: string | null;\n createdAt: string;\n updatedAt: string;\n deletedAt: string | null;\n}\n\n// =============================================================================\n// Input Types (validated with Zod)\n// =============================================================================\n\n/**\n * ObservationInsert -- input for creating observations.\n * Validated at runtime via Zod schema.\n */\nexport const ObservationInsertSchema = z.object({\n content: z.string().min(1).max(100_000),\n title: z.string().max(200).nullable().default(null),\n source: z.string().default('unknown'),\n kind: z.string().default('finding'),\n sessionId: z.string().nullable().default(null),\n embedding: z.instanceof(Float32Array).nullable().default(null),\n embeddingModel: z.string().nullable().default(null),\n embeddingVersion: z.string().nullable().default(null),\n});\n\nexport type ObservationInsert = z.input<typeof ObservationInsertSchema>;\n\n// =============================================================================\n// Session Types\n// =============================================================================\n\nexport interface Session {\n id: string;\n projectHash: string;\n startedAt: string;\n endedAt: string | null;\n summary: string | null;\n}\n\n// =============================================================================\n// Search Types\n// =============================================================================\n\nexport interface SearchResult {\n observation: Observation;\n score: number;\n matchType: 'fts' | 'vector' | 'hybrid';\n snippet: string;\n}\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\nexport interface DatabaseConfig {\n dbPath: string;\n busyTimeout: number;\n}\n\n// =============================================================================\n// Mapping Helpers\n// =============================================================================\n\n/**\n * Maps a snake_case ObservationRow (from SQLite) to a camelCase Observation.\n * Converts embedding Buffer to Float32Array for application use.\n */\nexport function rowToObservation(row: ObservationRow): Observation {\n return {\n rowid: row.rowid,\n id: row.id,\n projectHash: row.project_hash,\n content: row.content,\n title: row.title,\n source: row.source,\n sessionId: row.session_id,\n kind: (row.kind ?? 'finding') as ObservationKind,\n embedding: row.embedding\n ? new Float32Array(\n row.embedding.buffer,\n row.embedding.byteOffset,\n row.embedding.byteLength / 4,\n )\n : null,\n embeddingModel: row.embedding_model,\n embeddingVersion: row.embedding_version,\n classification: row.classification as ObservationClassification | null,\n classifiedAt: row.classified_at,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n deletedAt: row.deleted_at,\n };\n}\n","import type BetterSqlite3 from 'better-sqlite3';\nimport { randomBytes } from 'node:crypto';\n\nimport { debug } from '../shared/debug.js';\nimport {\n ObservationInsertSchema,\n rowToObservation,\n type Observation,\n type ObservationClassification,\n type ObservationInsert,\n type ObservationRow,\n} from '../shared/types.js';\n\n/**\n * Repository for observation CRUD operations.\n *\n * Every query is scoped to the projectHash provided at construction time.\n * Callers cannot accidentally query the wrong project -- project isolation\n * is baked into every prepared statement.\n *\n * All SQL statements are prepared once in the constructor and reused for\n * every call (better-sqlite3 performance best practice).\n */\nexport class ObservationRepository {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n // Prepared statements (prepared once, reused for every call)\n private readonly stmtInsert: BetterSqlite3.Statement;\n private readonly stmtGetById: BetterSqlite3.Statement;\n private readonly stmtGetByIdIncludingDeleted: BetterSqlite3.Statement;\n private readonly stmtSoftDelete: BetterSqlite3.Statement;\n private readonly stmtRestore: BetterSqlite3.Statement;\n private readonly stmtCount: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n\n this.stmtInsert = db.prepare(`\n INSERT INTO observations (id, project_hash, content, title, source, kind, session_id, embedding, embedding_model, embedding_version)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n this.stmtGetById = db.prepare(`\n SELECT * FROM observations\n WHERE id = ? AND project_hash = ? AND deleted_at IS NULL\n `);\n\n this.stmtGetByIdIncludingDeleted = db.prepare(`\n SELECT * FROM observations\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtSoftDelete = db.prepare(`\n UPDATE observations\n SET deleted_at = datetime('now'), updated_at = datetime('now')\n WHERE id = ? AND project_hash = ? AND deleted_at IS NULL\n `);\n\n this.stmtRestore = db.prepare(`\n UPDATE observations\n SET deleted_at = NULL, updated_at = datetime('now')\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtCount = db.prepare(`\n SELECT COUNT(*) AS count FROM observations\n WHERE project_hash = ? AND deleted_at IS NULL\n `);\n\n debug('obs', 'ObservationRepository initialized', { projectHash });\n }\n\n /**\n * Creates a new observation scoped to this repository's project.\n * Validates input with Zod at runtime.\n */\n create(input: ObservationInsert): Observation {\n const validated = ObservationInsertSchema.parse(input);\n\n const id = randomBytes(16).toString('hex');\n const embeddingBuffer = validated.embedding\n ? Buffer.from(\n validated.embedding.buffer,\n validated.embedding.byteOffset,\n validated.embedding.byteLength,\n )\n : null;\n\n debug('obs', 'Creating observation', { source: validated.source, contentLength: validated.content.length });\n\n this.stmtInsert.run(\n id,\n this.projectHash,\n validated.content,\n validated.title,\n validated.source,\n validated.kind,\n validated.sessionId,\n embeddingBuffer,\n validated.embeddingModel,\n validated.embeddingVersion,\n );\n\n // Fetch the created row (includes generated timestamps and rowid)\n const row = this.stmtGetById.get(id, this.projectHash) as\n | ObservationRow\n | undefined;\n\n if (!row) {\n throw new Error('Failed to retrieve newly created observation');\n }\n\n debug('obs', 'Observation created', { id });\n\n return rowToObservation(row);\n }\n\n /**\n * Resolves a full or prefix ID to the full 32-char ID.\n * Observation IDs are 32-char hex strings. Search results display only the\n * first 8 chars via shortId(). This method allows callers to pass either\n * a full ID or an 8-char (or any-length) prefix and get the full ID back.\n * Returns null if no unique match is found.\n */\n private resolveId(id: string): string | null {\n const FULL_ID_LENGTH = 32;\n if (id.length === FULL_ID_LENGTH) {\n return id; // Already a full ID, no prefix resolution needed\n }\n // Prefix search: find observations whose ID starts with the given prefix\n const rows = this.db\n .prepare(\n \"SELECT id FROM observations WHERE project_hash = ? AND id LIKE ? ESCAPE '\\\\' LIMIT 2\",\n )\n .all(this.projectHash, id.replace(/[%_\\\\]/g, '\\\\$&') + '%') as { id: string }[];\n if (rows.length === 1) {\n return rows[0].id;\n }\n if (rows.length > 1) {\n debug('obs', 'Ambiguous ID prefix - multiple matches', { prefix: id, count: rows.length });\n }\n return null;\n }\n\n /**\n * Gets an observation by ID, scoped to this project.\n * Accepts full 32-char IDs or shorter prefix strings (e.g. the 8-char\n * display IDs shown in search results).\n * Returns null if not found or soft-deleted.\n */\n getById(id: string): Observation | null {\n const resolvedId = this.resolveId(id);\n if (!resolvedId) return null;\n const row = this.stmtGetById.get(resolvedId, this.projectHash) as\n | ObservationRow\n | undefined;\n return row ? rowToObservation(row) : null;\n }\n\n /**\n * Lists observations for this project, ordered by created_at DESC.\n * Excludes soft-deleted observations.\n */\n list(options?: {\n limit?: number;\n offset?: number;\n sessionId?: string;\n since?: string;\n kind?: string;\n includeUnclassified?: boolean;\n }): Observation[] {\n debug('obs', 'Listing observations', { ...options });\n\n const limit = options?.limit ?? 50;\n const offset = options?.offset ?? 0;\n const includeUnclassified = options?.includeUnclassified ?? false;\n\n let sql =\n 'SELECT * FROM observations WHERE project_hash = ? AND deleted_at IS NULL';\n const params: unknown[] = [this.projectHash];\n\n if (!includeUnclassified) {\n sql += \" AND ((classification IS NOT NULL AND classification != 'noise') OR created_at >= datetime('now', '-60 seconds'))\";\n }\n\n if (options?.kind) {\n sql += ' AND kind = ?';\n params.push(options.kind);\n }\n\n if (options?.sessionId) {\n sql += ' AND session_id = ?';\n params.push(options.sessionId);\n }\n\n if (options?.since) {\n sql += ' AND created_at >= ?';\n params.push(options.since);\n }\n\n sql += ' ORDER BY created_at DESC, rowid DESC LIMIT ? OFFSET ?';\n params.push(limit, offset);\n\n const rows = this.db.prepare(sql).all(...params) as ObservationRow[];\n\n debug('obs', 'Listed observations', { count: rows.length });\n\n return rows.map(rowToObservation);\n }\n\n /**\n * Updates an observation's content, embedding fields, or both.\n * Always sets updated_at to current time.\n * Scoped to this project; returns null if not found or soft-deleted.\n */\n update(\n id: string,\n updates: Partial<\n Pick<\n Observation,\n 'content' | 'embedding' | 'embeddingModel' | 'embeddingVersion'\n >\n >,\n ): Observation | null {\n debug('obs', 'Updating observation', { id });\n\n const setClauses: string[] = [\"updated_at = datetime('now')\"];\n const params: unknown[] = [];\n\n if (updates.content !== undefined) {\n setClauses.push('content = ?');\n params.push(updates.content);\n }\n\n if (updates.embedding !== undefined) {\n setClauses.push('embedding = ?');\n params.push(\n updates.embedding\n ? Buffer.from(\n updates.embedding.buffer,\n updates.embedding.byteOffset,\n updates.embedding.byteLength,\n )\n : null,\n );\n }\n\n if (updates.embeddingModel !== undefined) {\n setClauses.push('embedding_model = ?');\n params.push(updates.embeddingModel);\n }\n\n if (updates.embeddingVersion !== undefined) {\n setClauses.push('embedding_version = ?');\n params.push(updates.embeddingVersion);\n }\n\n params.push(id, this.projectHash);\n\n const sql = `UPDATE observations SET ${setClauses.join(', ')} WHERE id = ? AND project_hash = ? AND deleted_at IS NULL`;\n const result = this.db.prepare(sql).run(...params);\n\n if (result.changes === 0) {\n debug('obs', 'Observation not found for update', { id });\n return null;\n }\n\n debug('obs', 'Observation updated', { id });\n\n return this.getById(id);\n }\n\n /**\n * Soft-deletes an observation by setting deleted_at.\n * Accepts full 32-char IDs or shorter prefix strings (e.g. the 8-char\n * display IDs shown in search results).\n * Returns true if the observation was found and deleted.\n */\n softDelete(id: string): boolean {\n debug('obs', 'Soft-deleting observation', { id });\n const resolvedId = this.resolveId(id) ?? id;\n const result = this.stmtSoftDelete.run(resolvedId, this.projectHash);\n debug('obs', result.changes > 0 ? 'Observation soft-deleted' : 'Observation not found for delete', { id: resolvedId });\n return result.changes > 0;\n }\n\n /**\n * Restores a soft-deleted observation by clearing deleted_at.\n * Accepts full 32-char IDs or shorter prefix strings (e.g. the 8-char\n * display IDs shown in search results).\n * Returns true if the observation was found and restored.\n */\n restore(id: string): boolean {\n const resolvedId = this.resolveId(id) ?? id;\n const result = this.stmtRestore.run(resolvedId, this.projectHash);\n return result.changes > 0;\n }\n\n /**\n * Updates the classification of an observation.\n * Sets classified_at to current time. Returns true if found and updated.\n */\n updateClassification(\n id: string,\n classification: ObservationClassification,\n ): boolean {\n debug('obs', 'Updating classification', { id, classification });\n const sql = `\n UPDATE observations\n SET classification = ?, classified_at = datetime('now'), updated_at = datetime('now')\n WHERE id = ? AND project_hash = ? AND deleted_at IS NULL\n `;\n const result = this.db.prepare(sql).run(classification, id, this.projectHash);\n return result.changes > 0;\n }\n\n /**\n * Creates an observation with an initial classification (bypasses classifier).\n * Used for explicit user saves that should be immediately visible.\n */\n createClassified(input: ObservationInsert, classification: ObservationClassification): Observation {\n const obs = this.create(input);\n this.updateClassification(obs.id, classification);\n // Re-fetch to get the updated classification fields\n return this.getById(obs.id)!;\n }\n\n /**\n * Fetches unclassified observations for the background classifier.\n * Returns observations ordered by created_at ASC (oldest first).\n */\n listUnclassified(limit: number = 20): Observation[] {\n const sql = `\n SELECT * FROM observations\n WHERE project_hash = ? AND classification IS NULL AND deleted_at IS NULL\n ORDER BY created_at ASC\n LIMIT ?\n `;\n const rows = this.db.prepare(sql).all(this.projectHash, limit) as ObservationRow[];\n return rows.map(rowToObservation);\n }\n\n /**\n * Lists unclassified observations across ALL projects.\n * Used by HaikuProcessor to avoid missing observations from other projects.\n */\n static listAllUnclassified(db: import('better-sqlite3').Database, limit: number = 20): Observation[] {\n const sql = `\n SELECT * FROM observations\n WHERE classification IS NULL AND deleted_at IS NULL\n ORDER BY created_at ASC\n LIMIT ?\n `;\n const rows = db.prepare(sql).all(limit) as ObservationRow[];\n return rows.map(rowToObservation);\n }\n\n /**\n * Fetches observations surrounding a given timestamp for classification context.\n * Returns observations regardless of classification status.\n */\n listContext(aroundTime: string, windowSize: number = 5): Observation[] {\n // Get N observations before\n const beforeSql = `\n SELECT * FROM observations\n WHERE project_hash = ? AND deleted_at IS NULL AND created_at <= ?\n ORDER BY created_at DESC, rowid DESC\n LIMIT ?\n `;\n const beforeRows = this.db.prepare(beforeSql).all(\n this.projectHash, aroundTime, windowSize + 1,\n ) as ObservationRow[];\n\n // Get N observations after\n const afterSql = `\n SELECT * FROM observations\n WHERE project_hash = ? AND deleted_at IS NULL AND created_at > ?\n ORDER BY created_at ASC, rowid ASC\n LIMIT ?\n `;\n const afterRows = this.db.prepare(afterSql).all(\n this.projectHash, aroundTime, windowSize,\n ) as ObservationRow[];\n\n // Combine in chronological order (before is DESC, so reverse it)\n const allRows = [...beforeRows.reverse(), ...afterRows];\n // Deduplicate by id\n const seen = new Set<string>();\n const unique = allRows.filter(r => {\n if (seen.has(r.id)) return false;\n seen.add(r.id);\n return true;\n });\n return unique.map(rowToObservation);\n }\n\n /**\n * Counts non-deleted observations for this project.\n */\n count(): number {\n const row = this.stmtCount.get(this.projectHash) as { count: number };\n return row.count;\n }\n\n /**\n * Gets an observation by ID, including soft-deleted observations.\n * Accepts full 32-char IDs or shorter prefix strings (e.g. the 8-char\n * display IDs shown in search results).\n * Used by the recall tool for restore operations (must find purged items).\n */\n getByIdIncludingDeleted(id: string): Observation | null {\n debug('obs', 'Getting observation including deleted', { id });\n // resolveId only queries non-deleted; for deleted items we need a wider search\n const FULL_ID_LENGTH = 32;\n let resolvedId: string;\n if (id.length === FULL_ID_LENGTH) {\n resolvedId = id;\n } else {\n const rows = this.db\n .prepare(\n \"SELECT id FROM observations WHERE project_hash = ? AND id LIKE ? ESCAPE '\\\\' LIMIT 2\",\n )\n .all(this.projectHash, id.replace(/[%_\\\\]/g, '\\\\$&') + '%') as { id: string }[];\n if (rows.length === 0) return null;\n if (rows.length > 1) {\n debug('obs', 'Ambiguous ID prefix for getByIdIncludingDeleted', { prefix: id, count: rows.length });\n return null;\n }\n resolvedId = rows[0].id;\n }\n const row = this.stmtGetByIdIncludingDeleted.get(resolvedId, this.projectHash) as\n | ObservationRow\n | undefined;\n return row ? rowToObservation(row) : null;\n }\n\n /**\n * Lists observations for this project, including soft-deleted ones.\n * Used by recall with include_purged: true to show all items.\n */\n listIncludingDeleted(options?: {\n limit?: number;\n offset?: number;\n }): Observation[] {\n const limit = options?.limit ?? 50;\n const offset = options?.offset ?? 0;\n\n debug('obs', 'Listing observations including deleted', { limit, offset });\n\n const sql =\n 'SELECT * FROM observations WHERE project_hash = ? ORDER BY created_at DESC, rowid DESC LIMIT ? OFFSET ?';\n const rows = this.db\n .prepare(sql)\n .all(this.projectHash, limit, offset) as ObservationRow[];\n\n debug('obs', 'Listed observations including deleted', {\n count: rows.length,\n });\n\n return rows.map(rowToObservation);\n }\n\n /**\n * Searches observations by title substring (partial match via LIKE).\n * Optionally includes soft-deleted items.\n */\n getByTitle(\n title: string,\n options?: { limit?: number; includePurged?: boolean },\n ): Observation[] {\n const limit = options?.limit ?? 20;\n const includePurged = options?.includePurged ?? false;\n\n debug('obs', 'Searching by title', { title, limit, includePurged });\n\n let sql = 'SELECT * FROM observations WHERE project_hash = ? AND title LIKE ?';\n if (!includePurged) {\n sql += ' AND deleted_at IS NULL';\n }\n sql += \" AND classification IS NOT NULL AND classification != 'noise'\";\n sql += ' ORDER BY created_at DESC, rowid DESC LIMIT ?';\n\n const rows = this.db\n .prepare(sql)\n .all(this.projectHash, `%${title}%`, limit) as ObservationRow[];\n\n debug('obs', 'Title search completed', { count: rows.length });\n\n return rows.map(rowToObservation);\n }\n}\n","import type BetterSqlite3 from 'better-sqlite3';\n\nimport { debug } from '../shared/debug.js';\nimport type { Session } from '../shared/types.js';\n\n/**\n * Raw session row from SQLite (snake_case column names).\n */\ninterface SessionRow {\n id: string;\n project_hash: string;\n started_at: string;\n ended_at: string | null;\n summary: string | null;\n}\n\n/**\n * Maps a snake_case SessionRow to a camelCase Session interface.\n */\nfunction rowToSession(row: SessionRow): Session {\n return {\n id: row.id,\n projectHash: row.project_hash,\n startedAt: row.started_at,\n endedAt: row.ended_at,\n summary: row.summary,\n };\n}\n\n/**\n * Repository for session lifecycle management.\n *\n * Every query is scoped to the projectHash provided at construction time.\n * All SQL statements are prepared once in the constructor.\n */\nexport class SessionRepository {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n // Prepared statements\n private readonly stmtCreate: BetterSqlite3.Statement;\n private readonly stmtGetById: BetterSqlite3.Statement;\n private readonly stmtGetActive: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n\n this.stmtCreate = db.prepare(`\n INSERT INTO sessions (id, project_hash)\n VALUES (?, ?)\n `);\n\n this.stmtGetById = db.prepare(`\n SELECT * FROM sessions\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtGetActive = db.prepare(`\n SELECT * FROM sessions\n WHERE ended_at IS NULL AND project_hash = ?\n ORDER BY started_at DESC\n LIMIT 1\n `);\n\n debug('session', 'SessionRepository initialized', { projectHash });\n }\n\n /**\n * Creates a new session with the given ID, scoped to this project.\n */\n create(id: string): Session {\n this.stmtCreate.run(id, this.projectHash);\n\n const row = this.stmtGetById.get(id, this.projectHash) as\n | SessionRow\n | undefined;\n\n if (!row) {\n throw new Error('Failed to retrieve newly created session');\n }\n\n debug('session', 'Session created', { id });\n\n return rowToSession(row);\n }\n\n /**\n * Ends a session by setting ended_at and optionally a summary.\n * Returns the updated session or null if not found.\n */\n end(id: string, summary?: string): Session | null {\n const setClauses = [\"ended_at = datetime('now')\"];\n const params: unknown[] = [];\n\n if (summary !== undefined) {\n setClauses.push('summary = ?');\n params.push(summary);\n }\n\n params.push(id, this.projectHash);\n\n const sql = `UPDATE sessions SET ${setClauses.join(', ')} WHERE id = ? AND project_hash = ?`;\n const result = this.db.prepare(sql).run(...params);\n\n if (result.changes === 0) {\n return null;\n }\n\n debug('session', 'Session ended', { id, hasSummary: !!summary });\n\n return this.getById(id);\n }\n\n /**\n * Gets a session by ID, scoped to this project.\n */\n getById(id: string): Session | null {\n const row = this.stmtGetById.get(id, this.projectHash) as\n | SessionRow\n | undefined;\n return row ? rowToSession(row) : null;\n }\n\n /**\n * Gets the most recent sessions for this project, ordered by started_at DESC.\n */\n getLatest(limit?: number): Session[] {\n const effectiveLimit = limit ?? 10;\n const rows = this.db\n .prepare(\n `SELECT * FROM sessions WHERE project_hash = ? ORDER BY started_at DESC, rowid DESC LIMIT ?`,\n )\n .all(this.projectHash, effectiveLimit) as SessionRow[];\n return rows.map(rowToSession);\n }\n\n /**\n * Gets the currently active (not ended) session for this project.\n * Returns the most recently started active session, or null if none.\n */\n getActive(): Session | null {\n const row = this.stmtGetActive.get(this.projectHash) as\n | SessionRow\n | undefined;\n return row ? rowToSession(row) : null;\n }\n\n /**\n * Updates the summary column on an existing session row.\n * Sets updated_at (via ended_at preservation) to track when the summary was written.\n *\n * Used by the curation module after compressing session observations.\n */\n updateSessionSummary(sessionId: string, summary: string): void {\n const result = this.db\n .prepare(\n `UPDATE sessions SET summary = ? WHERE id = ? AND project_hash = ?`,\n )\n .run(summary, sessionId, this.projectHash);\n\n if (result.changes === 0) {\n debug('session', 'Session not found for summary update', {\n sessionId,\n });\n return;\n }\n\n debug('session', 'Session summary updated', {\n sessionId,\n summaryLength: summary.length,\n });\n }\n}\n","import type BetterSqlite3 from 'better-sqlite3';\n\nimport { debug, debugTimed } from '../shared/debug.js';\nimport {\n rowToObservation,\n type ObservationRow,\n type SearchResult,\n} from '../shared/types.js';\n\n/**\n * FTS5 search engine with BM25 ranking, snippet extraction, and strict project scoping.\n *\n * All queries are scoped to the projectHash provided at construction time.\n * Queries are sanitized to prevent FTS5 syntax errors and injection.\n */\nexport class SearchEngine {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n }\n\n /**\n * Full-text search with BM25 ranking and snippet extraction.\n *\n * bm25() returns NEGATIVE values where more negative = more relevant.\n * ORDER BY rank (ascending) puts best matches first.\n *\n * @param query - User's search query (sanitized for FTS5 safety)\n * @param options - Optional limit and sessionId filter\n * @returns SearchResult[] ordered by relevance (best match first)\n */\n searchKeyword(\n query: string,\n options?: { limit?: number; sessionId?: string },\n ): SearchResult[] {\n const sanitized = this.sanitizeQuery(query);\n if (!sanitized) {\n return [];\n }\n\n const limit = options?.limit ?? 20;\n\n let sql = `\n SELECT\n o.*,\n bm25(observations_fts, 2.0, 1.0) AS rank,\n snippet(observations_fts, 1, '<mark>', '</mark>', '...', 32) AS snippet\n FROM observations_fts\n JOIN observations o ON o.rowid = observations_fts.rowid\n WHERE observations_fts MATCH ?\n AND o.project_hash = ?\n AND o.deleted_at IS NULL\n AND (o.classification IS NULL OR o.classification != 'noise')\n `;\n const params: unknown[] = [sanitized, this.projectHash];\n\n if (options?.sessionId) {\n sql += ' AND o.session_id = ?';\n params.push(options.sessionId);\n }\n\n sql += ' ORDER BY rank LIMIT ?';\n params.push(limit);\n\n const results = debugTimed('search', 'FTS5 keyword search', () => {\n const rows = this.db.prepare(sql).all(...params) as (ObservationRow & {\n rank: number;\n snippet: string;\n })[];\n\n return rows.map((row) => ({\n observation: rowToObservation(row),\n score: Math.abs(row.rank),\n matchType: 'fts' as const,\n snippet: row.snippet,\n }));\n });\n\n debug('search', 'Keyword search completed', { query: sanitized, resultCount: results.length });\n\n return results;\n }\n\n /**\n * Prefix search for autocomplete-style matching.\n * Appends `*` to each word for prefix matching.\n */\n searchByPrefix(prefix: string, limit?: number): SearchResult[] {\n const words = prefix.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) {\n return [];\n }\n\n // Sanitize each word and append * for prefix matching\n const sanitizedWords = words\n .map((w) => this.sanitizeWord(w))\n .filter(Boolean);\n if (sanitizedWords.length === 0) {\n return [];\n }\n\n const ftsQuery = sanitizedWords.map((w) => `${w}*`).join(' ');\n const effectiveLimit = limit ?? 20;\n\n const sql = `\n SELECT\n o.*,\n bm25(observations_fts, 2.0, 1.0) AS rank,\n snippet(observations_fts, 1, '<mark>', '</mark>', '...', 32) AS snippet\n FROM observations_fts\n JOIN observations o ON o.rowid = observations_fts.rowid\n WHERE observations_fts MATCH ?\n AND o.project_hash = ?\n AND o.deleted_at IS NULL\n AND (o.classification IS NULL OR o.classification != 'noise')\n ORDER BY rank\n LIMIT ?\n `;\n\n const results = debugTimed('search', 'FTS5 prefix search', () => {\n const rows = this.db\n .prepare(sql)\n .all(ftsQuery, this.projectHash, effectiveLimit) as (ObservationRow & {\n rank: number;\n snippet: string;\n })[];\n\n return rows.map((row) => ({\n observation: rowToObservation(row),\n score: Math.abs(row.rank),\n matchType: 'fts' as const,\n snippet: row.snippet,\n }));\n });\n\n debug('search', 'Prefix search completed', { prefix, resultCount: results.length });\n\n return results;\n }\n\n /**\n * Rebuild the FTS5 index if it gets out of sync.\n */\n rebuildIndex(): void {\n debug('search', 'Rebuilding FTS5 index');\n this.db.exec(\n \"INSERT INTO observations_fts(observations_fts) VALUES('rebuild')\",\n );\n }\n\n /**\n * Sanitizes a user query for safe FTS5 MATCH usage.\n * Removes FTS5 operators and special characters.\n * Returns null if the query is empty after sanitization.\n */\n private sanitizeQuery(query: string): string | null {\n const words = query.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) {\n return null;\n }\n\n const sanitizedWords = words\n .map((w) => this.sanitizeWord(w))\n .filter(Boolean);\n\n if (sanitizedWords.length === 0) {\n return null;\n }\n\n // FTS5 defaults to implicit AND for space-separated words\n return sanitizedWords.join(' ');\n }\n\n /**\n * Sanitizes a single word for FTS5 safety.\n * Removes quotes, parentheses, asterisks, and FTS5 operator keywords.\n */\n private sanitizeWord(word: string): string {\n // Remove FTS5 special characters\n let cleaned = word.replace(/[\"*()^{}[\\]]/g, '');\n\n // Remove FTS5 operator keywords (case-insensitive, only when the whole word is an operator)\n if (/^(NEAR|OR|AND|NOT)$/i.test(cleaned)) {\n return '';\n }\n\n // Remove any remaining non-alphanumeric characters except hyphens and underscores\n cleaned = cleaned.replace(/[^\\w\\-]/g, '');\n\n return cleaned;\n }\n}\n","/**\n * Hybrid search combining FTS5 keyword results and vec0 vector results\n * using reciprocal rank fusion (RRF).\n *\n * When both keyword and vector results are available, RRF merges the two\n * ranked lists into a single score-sorted list. When only keyword results\n * are available (worker not ready, no embeddings), falls back transparently.\n */\n\nimport { debug, debugTimed } from '../shared/debug.js';\nimport type { SearchResult } from '../shared/types.js';\nimport type { SearchEngine } from '../storage/search.js';\nimport type { EmbeddingStore, EmbeddingSearchResult } from '../storage/embeddings.js';\nimport type { AnalysisWorker } from '../analysis/worker-bridge.js';\nimport { ObservationRepository } from '../storage/observations.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface RankedItem {\n id: string;\n [key: string]: unknown;\n}\n\ninterface FusedResult {\n id: string;\n fusedScore: number;\n}\n\nexport interface HybridSearchParams {\n searchEngine: SearchEngine;\n embeddingStore: EmbeddingStore;\n worker: AnalysisWorker | null;\n query: string;\n db: import('better-sqlite3').Database;\n projectHash: string;\n options?: { limit?: number; sessionId?: string };\n}\n\n// ---------------------------------------------------------------------------\n// Reciprocal Rank Fusion\n// ---------------------------------------------------------------------------\n\n/**\n * Merges multiple ranked lists into a single fused ranking using RRF.\n *\n * For each document across all lists, computes:\n * fusedScore = sum(1 / (k + rank + 1))\n * where rank is the 0-based position in each list.\n *\n * @param rankedLists - Arrays of ranked items, each with an `id` field\n * @param k - Smoothing constant (default 60, standard RRF value)\n * @returns Fused results sorted by fusedScore descending\n */\nexport function reciprocalRankFusion(\n rankedLists: Array<Array<RankedItem>>,\n k = 60,\n): FusedResult[] {\n const scores = new Map<string, number>();\n\n for (const list of rankedLists) {\n for (let rank = 0; rank < list.length; rank++) {\n const item = list[rank];\n const current = scores.get(item.id) ?? 0;\n scores.set(item.id, current + 1 / (k + rank + 1));\n }\n }\n\n const results: FusedResult[] = [];\n for (const [id, fusedScore] of scores) {\n results.push({ id, fusedScore });\n }\n\n results.sort((a, b) => b.fusedScore - a.fusedScore);\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Hybrid Search\n// ---------------------------------------------------------------------------\n\n/**\n * Combines FTS5 keyword search and vec0 vector search using RRF.\n *\n * Falls back to keyword-only when:\n * - Worker is null or not ready\n * - Query embedding fails\n * - No vector results returned\n *\n * @returns SearchResult[] with matchType indicating source(s)\n */\nexport async function hybridSearch(\n params: HybridSearchParams,\n): Promise<SearchResult[]> {\n const { searchEngine, embeddingStore, worker, query, db, projectHash, options } = params;\n const limit = options?.limit ?? 20;\n\n return debugTimed('search', 'Hybrid search', async () => {\n // Step 1: Always run keyword search\n const keywordResults = searchEngine.searchKeyword(query, {\n limit,\n sessionId: options?.sessionId,\n });\n\n debug('search', 'Keyword results', { count: keywordResults.length });\n\n // Step 2: Attempt vector search if worker is available\n let vectorResults: EmbeddingSearchResult[] = [];\n\n if (worker && worker.isReady()) {\n const queryEmbedding = await worker.embed(query);\n\n if (queryEmbedding) {\n // Fetch more vector results than limit to improve fusion quality\n vectorResults = embeddingStore.search(queryEmbedding, limit * 2);\n debug('search', 'Vector results', { count: vectorResults.length });\n } else {\n debug('search', 'Query embedding failed, keyword-only');\n }\n } else {\n debug('search', 'Worker not ready, keyword-only');\n }\n\n // Step 3: Keyword-only fallback\n if (vectorResults.length === 0) {\n debug('search', 'Returning keyword-only results', { count: keywordResults.length });\n return keywordResults;\n }\n\n // Step 4: Fuse keyword + vector results with RRF\n const keywordRanked: RankedItem[] = keywordResults.map((r) => ({\n id: r.observation.id,\n }));\n\n const vectorRanked: RankedItem[] = vectorResults.map((r) => ({\n id: r.observationId,\n }));\n\n const fused = reciprocalRankFusion([keywordRanked, vectorRanked]);\n\n // Build lookup maps\n const keywordMap = new Map<string, SearchResult>();\n for (const r of keywordResults) {\n keywordMap.set(r.observation.id, r);\n }\n\n const vectorIdSet = new Set(vectorResults.map((r) => r.observationId));\n\n // We need an ObservationRepository to look up vector-only observations\n const obsRepo = new ObservationRepository(db, projectHash);\n\n // Merge results\n const merged: SearchResult[] = [];\n\n for (const item of fused) {\n if (merged.length >= limit) break;\n\n const fromKeyword = keywordMap.get(item.id);\n const fromVector = vectorIdSet.has(item.id);\n\n if (fromKeyword && fromVector) {\n // In both: hybrid match, use keyword snippet\n merged.push({\n observation: fromKeyword.observation,\n score: item.fusedScore,\n matchType: 'hybrid',\n snippet: fromKeyword.snippet,\n });\n } else if (fromKeyword) {\n // Keyword only\n merged.push({\n observation: fromKeyword.observation,\n score: item.fusedScore,\n matchType: 'fts',\n snippet: fromKeyword.snippet,\n });\n } else if (fromVector) {\n // Vector only -- need to load observation\n const obs = obsRepo.getById(item.id);\n if (obs) {\n const snippet = (obs.content ?? '').replace(/\\n/g, ' ').slice(0, 100);\n merged.push({\n observation: obs,\n score: item.fusedScore,\n matchType: 'vector',\n snippet,\n });\n }\n }\n }\n\n debug('search', 'Hybrid search complete', {\n keyword: keywordResults.length,\n vector: vectorResults.length,\n fused: merged.length,\n hybrid: merged.filter((r) => r.matchType === 'hybrid').length,\n });\n\n return merged;\n });\n}\n","/**\n * Text similarity utilities shared across modules.\n */\n\n/**\n * Computes Jaccard similarity between two texts based on tokenized words.\n * Words are lowercased and split on whitespace/punctuation.\n */\nexport function jaccardSimilarity(textA: string, textB: string): number {\n const tokenize = (t: string): Set<string> =>\n new Set(\n t\n .toLowerCase()\n .split(/[\\s,.!?;:'\"()\\[\\]{}<>\\/\\\\|@#$%^&*+=~`]+/)\n .filter((w) => w.length > 0),\n );\n\n const setA = tokenize(textA);\n const setB = tokenize(textB);\n\n if (setA.size === 0 && setB.size === 0) return 1;\n if (setA.size === 0 || setB.size === 0) return 0;\n\n let intersection = 0;\n for (const w of setA) {\n if (setB.has(w)) intersection++;\n }\n\n const union = setA.size + setB.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n","/**\n * Pre-save gate for duplicate detection.\n *\n * Two operating modes:\n * - Fast (hook path): Jaccard text similarity against recent observations. <5ms.\n * - Full (MCP path): Embedding-based KNN via EmbeddingStore.search() + text fallback. <100ms.\n *\n * Prevents database bloat by rejecting near-duplicate observations\n * before they hit storage, across both the hook auto-capture and MCP save_memory paths.\n *\n * Relevance scoring is handled by the background ObservationClassifier (LLM-based).\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\nimport type { AnalysisWorker } from '../analysis/worker-bridge.js';\nimport type { EmbeddingStore } from '../storage/embeddings.js';\nimport { ObservationRepository } from '../storage/observations.js';\nimport { jaccardSimilarity } from '../shared/similarity.js';\nimport { debug } from '../shared/debug.js';\n\nexport interface SaveDecision {\n save: boolean;\n reason?: string;\n duplicateOf?: string;\n}\n\nexport interface SaveGuardOptions {\n worker?: AnalysisWorker | null;\n embeddingStore?: EmbeddingStore | null;\n duplicateThreshold?: number;\n vectorDistanceThreshold?: number;\n recentWindow?: number;\n}\n\nexport class SaveGuard {\n private readonly obsRepo: ObservationRepository;\n private readonly worker: AnalysisWorker | null;\n private readonly embeddingStore: EmbeddingStore | null;\n private readonly duplicateThreshold: number;\n private readonly vectorDistanceThreshold: number;\n private readonly recentWindow: number;\n\n /**\n * Construct from db + projectHash (creates internal ObservationRepository),\n * or from an existing ObservationRepository.\n */\n constructor(\n dbOrRepo: BetterSqlite3.Database | ObservationRepository,\n projectHashOrOpts?: string | SaveGuardOptions,\n opts?: SaveGuardOptions,\n ) {\n if (dbOrRepo instanceof ObservationRepository) {\n this.obsRepo = dbOrRepo;\n const resolvedOpts = (projectHashOrOpts as SaveGuardOptions | undefined) ?? {};\n this.worker = resolvedOpts.worker ?? null;\n this.embeddingStore = resolvedOpts.embeddingStore ?? null;\n this.duplicateThreshold = resolvedOpts.duplicateThreshold ?? 0.85;\n this.vectorDistanceThreshold = resolvedOpts.vectorDistanceThreshold ?? 0.08;\n this.recentWindow = resolvedOpts.recentWindow ?? 20;\n } else {\n this.obsRepo = new ObservationRepository(dbOrRepo, projectHashOrOpts as string);\n this.worker = opts?.worker ?? null;\n this.embeddingStore = opts?.embeddingStore ?? null;\n this.duplicateThreshold = opts?.duplicateThreshold ?? 0.85;\n this.vectorDistanceThreshold = opts?.vectorDistanceThreshold ?? 0.08;\n this.recentWindow = opts?.recentWindow ?? 20;\n }\n }\n\n /**\n * Synchronous evaluation for the hook path (text-only, no embeddings).\n * Only checks for duplicates — relevance is handled by the background classifier.\n */\n evaluateSync(content: string, _source: string): SaveDecision {\n const dupResult = this.checkTextDuplicates(content);\n if (dupResult) return dupResult;\n return { save: true, reason: 'ok' };\n }\n\n /**\n * Async evaluation for the MCP path (embeddings + text fallback).\n * Only checks for duplicates — relevance is handled by the background classifier.\n */\n async evaluate(content: string, _source: string): Promise<SaveDecision> {\n // 1a. Vector duplicate detection (if worker + embeddingStore available)\n if (this.worker?.isReady() && this.embeddingStore) {\n const embedding = await this.worker.embed(content);\n if (embedding) {\n const results = this.embeddingStore.search(embedding, 5);\n for (const result of results) {\n if (result.distance < this.vectorDistanceThreshold) {\n debug('save-guard', 'Vector duplicate detected', {\n distance: result.distance,\n duplicateOf: result.observationId,\n });\n return {\n save: false,\n reason: 'duplicate',\n duplicateOf: result.observationId,\n };\n }\n }\n }\n }\n\n // 1b. Text-based fallback\n const dupResult = this.checkTextDuplicates(content);\n if (dupResult) return dupResult;\n\n return { save: true, reason: 'ok' };\n }\n\n private checkTextDuplicates(content: string): SaveDecision | null {\n const recent = this.obsRepo.list({ limit: this.recentWindow, includeUnclassified: true });\n\n for (const obs of recent) {\n const sim = jaccardSimilarity(content, obs.content);\n if (sim >= this.duplicateThreshold) {\n debug('save-guard', 'Text duplicate detected', {\n similarity: sim,\n duplicateOf: obs.id,\n });\n return {\n save: false,\n reason: 'duplicate',\n duplicateOf: obs.id,\n };\n }\n }\n\n return null;\n }\n}\n","/**\n * Migration 001: Create graph_nodes and graph_edges tables.\n *\n * Graph tables are managed separately from the main observation/session tables\n * because the knowledge graph is a distinct subsystem that operates\n * on extracted entities rather than raw observations.\n *\n * Tables:\n * - graph_nodes: entities with type-checked taxonomy (6 types)\n * - graph_edges: directed relationships with type-checked taxonomy (8 types),\n * weight confidence, and unique constraint on (source_id, target_id, type)\n *\n * Indexes:\n * - Nodes: type, name\n * - Edges: source_id, target_id, type, unique(source_id, target_id, type)\n */\n\nexport const up = `\n CREATE TABLE IF NOT EXISTS graph_nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('Project','File','Decision','Problem','Solution','Reference')),\n name TEXT NOT NULL,\n metadata TEXT DEFAULT '{}',\n observation_ids TEXT DEFAULT '[]',\n project_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS graph_edges (\n id TEXT PRIMARY KEY,\n source_id TEXT NOT NULL REFERENCES graph_nodes(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES graph_nodes(id) ON DELETE CASCADE,\n type TEXT NOT NULL CHECK(type IN ('related_to','solved_by','caused_by','modifies','informed_by','references','verified_by','preceded_by')),\n weight REAL NOT NULL DEFAULT 1.0 CHECK(weight >= 0.0 AND weight <= 1.0),\n metadata TEXT DEFAULT '{}',\n project_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_graph_nodes_type ON graph_nodes(type);\n CREATE INDEX IF NOT EXISTS idx_graph_nodes_name ON graph_nodes(name);\n CREATE INDEX IF NOT EXISTS idx_graph_edges_source ON graph_edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_graph_edges_target ON graph_edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_graph_edges_type ON graph_edges(type);\n CREATE UNIQUE INDEX IF NOT EXISTS idx_graph_edges_unique ON graph_edges(source_id, target_id, type);\n`;\n\nexport const down = `\n DROP INDEX IF EXISTS idx_graph_edges_unique;\n DROP INDEX IF EXISTS idx_graph_edges_type;\n DROP INDEX IF EXISTS idx_graph_edges_target;\n DROP INDEX IF EXISTS idx_graph_edges_source;\n DROP INDEX IF EXISTS idx_graph_nodes_name;\n DROP INDEX IF EXISTS idx_graph_nodes_type;\n DROP TABLE IF EXISTS graph_edges;\n DROP TABLE IF EXISTS graph_nodes;\n`;\n","/**\n * Migration 002: Add indexes on project_hash for graph tables.\n *\n * Supports project-scoped queries that filter by project_hash.\n */\n\nexport const up = `\n CREATE INDEX IF NOT EXISTS idx_graph_nodes_project ON graph_nodes(project_hash);\n CREATE INDEX IF NOT EXISTS idx_graph_edges_project ON graph_edges(project_hash);\n`;\n\nexport const down = `\n DROP INDEX IF EXISTS idx_graph_edges_project;\n DROP INDEX IF EXISTS idx_graph_nodes_project;\n`;\n","/**\n * Knowledge graph schema initialization and query builders.\n *\n * All functions accept a better-sqlite3 Database handle and use prepared\n * statements for performance. Metadata and observation_ids are stored as\n * JSON TEXT in SQLite and parsed on read.\n *\n * Traversal uses recursive CTEs for efficient subgraph extraction up to\n * a configurable depth.\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\nimport { randomBytes } from 'node:crypto';\n\nimport type {\n EntityType,\n RelationshipType,\n GraphNode,\n GraphEdge,\n} from './types.js';\nimport { up as graphTablesDDL } from './migrations/001-graph-tables.js';\nimport { up as projectHashIndexDDL } from './migrations/002-project-hash-index.js';\n\n// =============================================================================\n// Raw Row Types (snake_case, matches SQL columns)\n// =============================================================================\n\ninterface NodeRow {\n id: string;\n type: string;\n name: string;\n metadata: string; // JSON string\n observation_ids: string; // JSON string\n created_at: string;\n updated_at: string;\n}\n\ninterface EdgeRow {\n id: string;\n source_id: string;\n target_id: string;\n type: string;\n weight: number;\n metadata: string; // JSON string\n created_at: string;\n}\n\ninterface TraversalRow {\n // Node columns (prefixed n_)\n n_id: string;\n n_type: string;\n n_name: string;\n n_metadata: string;\n n_observation_ids: string;\n n_created_at: string;\n n_updated_at: string;\n // Edge columns (prefixed e_) -- nullable for starting node\n e_id: string | null;\n e_source_id: string | null;\n e_target_id: string | null;\n e_type: string | null;\n e_weight: number | null;\n e_metadata: string | null;\n e_created_at: string | null;\n // Traversal depth\n depth: number;\n}\n\n// =============================================================================\n// Row Mapping\n// =============================================================================\n\nfunction rowToNode(row: NodeRow): GraphNode {\n return {\n id: row.id,\n type: row.type as EntityType,\n name: row.name,\n metadata: JSON.parse(row.metadata) as Record<string, unknown>,\n observation_ids: JSON.parse(row.observation_ids) as string[],\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n}\n\nfunction rowToEdge(row: EdgeRow): GraphEdge {\n return {\n id: row.id,\n source_id: row.source_id,\n target_id: row.target_id,\n type: row.type as RelationshipType,\n weight: row.weight,\n metadata: JSON.parse(row.metadata) as Record<string, unknown>,\n created_at: row.created_at,\n };\n}\n\n// =============================================================================\n// Traversal Result\n// =============================================================================\n\nexport interface TraversalResult {\n node: GraphNode;\n edge: GraphEdge | null;\n depth: number;\n}\n\n// =============================================================================\n// Schema Initialization\n// =============================================================================\n\n/**\n * Initializes graph tables if they do not exist.\n * Uses CREATE TABLE IF NOT EXISTS so it is safe to call multiple times.\n */\nexport function initGraphSchema(db: BetterSqlite3.Database): void {\n db.exec(graphTablesDDL);\n db.exec(projectHashIndexDDL);\n}\n\n// =============================================================================\n// Traversal Queries\n// =============================================================================\n\n/**\n * Traverses the graph from a starting node using a recursive CTE.\n *\n * Supports directional traversal:\n * - 'outgoing': follows edges where source_id matches (default)\n * - 'incoming': follows edges where target_id matches\n * - 'both': follows edges in either direction\n *\n * Returns nodes and the edges that connect them, up to the specified depth.\n * The starting node itself is NOT included in results (depth > 0 filter).\n *\n * @param db - better-sqlite3 Database handle\n * @param nodeId - starting node ID\n * @param opts - traversal options (depth, edgeTypes, direction)\n * @returns Array of { node, edge, depth } for each reachable node\n */\nexport function traverseFrom(\n db: BetterSqlite3.Database,\n nodeId: string,\n opts: {\n depth?: number;\n edgeTypes?: RelationshipType[];\n direction?: 'outgoing' | 'incoming' | 'both';\n projectHash: string | null;\n },\n): TraversalResult[] {\n const maxDepth = opts.depth ?? 2;\n const direction = opts.direction ?? 'outgoing';\n\n // Build edge type filter clause\n let edgeTypeFilter = '';\n\n if (opts.edgeTypes && opts.edgeTypes.length > 0) {\n const placeholders = opts.edgeTypes.map(() => '?').join(', ');\n edgeTypeFilter = `AND e.type IN (${placeholders})`;\n }\n\n // Project isolation: filter edges by project_hash to prevent cross-project traversal\n const projectFilter = opts.projectHash ? 'AND e.project_hash = ?' : '';\n\n // Build the recursive step based on direction\n let recursiveStep: string;\n\n if (direction === 'outgoing') {\n recursiveStep = `\n SELECT e.target_id, t.depth + 1, e.id\n FROM graph_edges e\n JOIN traverse t ON e.source_id = t.node_id\n WHERE t.depth < ?\n ${edgeTypeFilter}\n ${projectFilter}\n `;\n } else if (direction === 'incoming') {\n recursiveStep = `\n SELECT e.source_id, t.depth + 1, e.id\n FROM graph_edges e\n JOIN traverse t ON e.target_id = t.node_id\n WHERE t.depth < ?\n ${edgeTypeFilter}\n ${projectFilter}\n `;\n } else {\n // both directions\n recursiveStep = `\n SELECT e.target_id, t.depth + 1, e.id\n FROM graph_edges e\n JOIN traverse t ON e.source_id = t.node_id\n WHERE t.depth < ?\n ${edgeTypeFilter}\n ${projectFilter}\n UNION ALL\n SELECT e.source_id, t.depth + 1, e.id\n FROM graph_edges e\n JOIN traverse t ON e.target_id = t.node_id\n WHERE t.depth < ?\n ${edgeTypeFilter}\n ${projectFilter}\n `;\n }\n\n const sql = `\n WITH RECURSIVE traverse(node_id, depth, edge_id) AS (\n SELECT ?, 0, NULL\n UNION ALL\n ${recursiveStep}\n )\n SELECT DISTINCT\n n.id AS n_id, n.type AS n_type, n.name AS n_name,\n n.metadata AS n_metadata, n.observation_ids AS n_observation_ids,\n n.created_at AS n_created_at, n.updated_at AS n_updated_at,\n e.id AS e_id, e.source_id AS e_source_id, e.target_id AS e_target_id,\n e.type AS e_type, e.weight AS e_weight, e.metadata AS e_metadata,\n e.created_at AS e_created_at,\n t.depth\n FROM traverse t\n JOIN graph_nodes n ON n.id = t.node_id\n LEFT JOIN graph_edges e ON e.id = t.edge_id\n WHERE t.depth > 0\n `;\n\n // Helper to push params for one recursive branch\n const pushBranchParams = (params: unknown[]) => {\n params.push(maxDepth);\n if (opts.edgeTypes) params.push(...opts.edgeTypes);\n if (opts.projectHash) params.push(opts.projectHash);\n };\n\n // Build parameter list depending on direction\n const queryParams: unknown[] = [nodeId]; // initial SELECT ?\n\n if (direction === 'both') {\n pushBranchParams(queryParams);\n pushBranchParams(queryParams);\n } else {\n pushBranchParams(queryParams);\n }\n\n const rows = db.prepare(sql).all(...queryParams) as TraversalRow[];\n\n return rows.map((row) => ({\n node: {\n id: row.n_id,\n type: row.n_type as EntityType,\n name: row.n_name,\n metadata: JSON.parse(row.n_metadata) as Record<string, unknown>,\n observation_ids: JSON.parse(row.n_observation_ids) as string[],\n created_at: row.n_created_at,\n updated_at: row.n_updated_at,\n },\n edge: row.e_id\n ? {\n id: row.e_id,\n source_id: row.e_source_id!,\n target_id: row.e_target_id!,\n type: row.e_type as RelationshipType,\n weight: row.e_weight!,\n metadata: JSON.parse(row.e_metadata!) as Record<string, unknown>,\n created_at: row.e_created_at!,\n }\n : null,\n depth: row.depth,\n }));\n}\n\n// =============================================================================\n// Node Queries\n// =============================================================================\n\n/**\n * Returns all nodes of a given entity type.\n */\nexport function getNodesByType(\n db: BetterSqlite3.Database,\n type: EntityType,\n projectHash: string | null,\n): GraphNode[] {\n if (projectHash) {\n const rows = db\n .prepare('SELECT * FROM graph_nodes WHERE type = ? AND project_hash = ?')\n .all(type, projectHash) as NodeRow[];\n return rows.map(rowToNode);\n }\n const rows = db\n .prepare('SELECT * FROM graph_nodes WHERE type = ?')\n .all(type) as NodeRow[];\n return rows.map(rowToNode);\n}\n\n/**\n * Looks up a node by name and type (composite natural key).\n * Returns null if no matching node exists.\n */\nexport function getNodeByNameAndType(\n db: BetterSqlite3.Database,\n name: string,\n type: EntityType,\n projectHash: string | null,\n): GraphNode | null {\n if (projectHash) {\n const row = db\n .prepare('SELECT * FROM graph_nodes WHERE name = ? AND type = ? AND project_hash = ?')\n .get(name, type, projectHash) as NodeRow | undefined;\n return row ? rowToNode(row) : null;\n }\n const row = db\n .prepare('SELECT * FROM graph_nodes WHERE name = ? AND type = ?')\n .get(name, type) as NodeRow | undefined;\n return row ? rowToNode(row) : null;\n}\n\n// =============================================================================\n// Edge Queries\n// =============================================================================\n\n/**\n * Returns edges connected to a node, filtered by direction.\n *\n * @param direction - 'outgoing' (source), 'incoming' (target), or 'both' (default: 'both')\n */\nexport function getEdgesForNode(\n db: BetterSqlite3.Database,\n nodeId: string,\n opts: { direction?: 'outgoing' | 'incoming' | 'both'; projectHash: string | null },\n): GraphEdge[] {\n const direction = opts.direction ?? 'both';\n const pFilter = opts.projectHash ? ' AND project_hash = ?' : '';\n\n let sql: string;\n let params: unknown[];\n\n if (direction === 'outgoing') {\n sql = `SELECT * FROM graph_edges WHERE source_id = ?${pFilter}`;\n params = opts.projectHash ? [nodeId, opts.projectHash] : [nodeId];\n } else if (direction === 'incoming') {\n sql = `SELECT * FROM graph_edges WHERE target_id = ?${pFilter}`;\n params = opts.projectHash ? [nodeId, opts.projectHash] : [nodeId];\n } else {\n sql = `SELECT * FROM graph_edges WHERE (source_id = ? OR target_id = ?)${pFilter}`;\n params = opts.projectHash ? [nodeId, nodeId, opts.projectHash] : [nodeId, nodeId];\n }\n\n const rows = db.prepare(sql).all(...params) as EdgeRow[];\n return rows.map(rowToEdge);\n}\n\n/**\n * Returns the total number of edges connected to a node (both directions).\n * Used for degree enforcement (MAX_NODE_DEGREE constraint).\n */\nexport function countEdgesForNode(\n db: BetterSqlite3.Database,\n nodeId: string,\n projectHash: string | null,\n): number {\n if (projectHash) {\n const result = db\n .prepare(\n 'SELECT COUNT(*) as cnt FROM graph_edges WHERE (source_id = ? OR target_id = ?) AND project_hash = ?',\n )\n .get(nodeId, nodeId, projectHash) as { cnt: number };\n return result.cnt;\n }\n const result = db\n .prepare(\n 'SELECT COUNT(*) as cnt FROM graph_edges WHERE source_id = ? OR target_id = ?',\n )\n .get(nodeId, nodeId) as { cnt: number };\n return result.cnt;\n}\n\n// =============================================================================\n// Mutations\n// =============================================================================\n\n/**\n * Inserts or updates a node by name+type composite key.\n *\n * If a node with the same name and type already exists, updates its metadata\n * and merges observation_ids. Otherwise, inserts a new node with a generated UUID.\n *\n * @returns The upserted GraphNode\n */\nexport function upsertNode(\n db: BetterSqlite3.Database,\n node: Omit<GraphNode, 'id' | 'created_at' | 'updated_at'> & { id?: string; project_hash: string | null },\n): GraphNode {\n const existing = getNodeByNameAndType(db, node.name, node.type, node.project_hash);\n\n if (existing) {\n // Merge observation_ids (deduplicated)\n const mergedObsIds = [\n ...new Set([...existing.observation_ids, ...node.observation_ids]),\n ];\n\n // Merge metadata (new values override existing)\n const mergedMetadata = { ...existing.metadata, ...node.metadata };\n\n db.prepare(\n `UPDATE graph_nodes\n SET metadata = ?, observation_ids = ?, updated_at = datetime('now')\n WHERE id = ?`,\n ).run(\n JSON.stringify(mergedMetadata),\n JSON.stringify(mergedObsIds),\n existing.id,\n );\n\n const updated = db\n .prepare('SELECT * FROM graph_nodes WHERE id = ?')\n .get(existing.id) as NodeRow;\n return rowToNode(updated);\n }\n\n // Insert new node\n const id = node.id ?? randomBytes(16).toString('hex');\n db.prepare(\n `INSERT INTO graph_nodes (id, type, name, metadata, observation_ids, project_hash)\n VALUES (?, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n node.type,\n node.name,\n JSON.stringify(node.metadata),\n JSON.stringify(node.observation_ids),\n node.project_hash,\n );\n\n const inserted = db\n .prepare('SELECT * FROM graph_nodes WHERE id = ?')\n .get(id) as NodeRow;\n return rowToNode(inserted);\n}\n\n/**\n * Inserts an edge. On conflict (same source_id, target_id, type),\n * updates the weight to the maximum of existing and new values.\n *\n * @returns The inserted or updated GraphEdge\n */\nexport function insertEdge(\n db: BetterSqlite3.Database,\n edge: Omit<GraphEdge, 'id' | 'created_at'> & { id?: string; project_hash: string | null },\n): GraphEdge {\n const id = edge.id ?? randomBytes(16).toString('hex');\n\n db.prepare(\n `INSERT INTO graph_edges (id, source_id, target_id, type, weight, metadata, project_hash)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (source_id, target_id, type) DO UPDATE SET\n weight = MAX(graph_edges.weight, excluded.weight),\n metadata = excluded.metadata`,\n ).run(\n id,\n edge.source_id,\n edge.target_id,\n edge.type,\n edge.weight,\n JSON.stringify(edge.metadata),\n edge.project_hash,\n );\n\n // Retrieve the actual row (may be the existing row if conflict occurred)\n const inserted = db\n .prepare(\n 'SELECT * FROM graph_edges WHERE source_id = ? AND target_id = ? AND type = ?',\n )\n .get(edge.source_id, edge.target_id, edge.type) as EdgeRow;\n return rowToEdge(inserted);\n}\n","/**\n * Staleness detection for the knowledge graph.\n *\n * Detects contradictions between observations linked to the same entity\n * using pattern matching (negation, replacement, status change). Stale\n * observations are FLAGGED but NEVER deleted -- the system surfaces both\n * observations and lets the user decide.\n *\n * This module is detection-only on the read path (detectStaleness) and\n * provides advisory flagging on the write path (flagStaleObservation).\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\n\nimport type { Observation, ObservationRow } from '../shared/types.js';\nimport { rowToObservation } from '../shared/types.js';\nimport type { EntityType } from './types.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * A staleness report documenting a detected contradiction between\n * two observations about the same entity.\n */\nexport interface StalenessReport {\n entityId: string;\n entityName: string;\n entityType: EntityType;\n newerObservation: { id: string; text: string; created_at: string };\n olderObservation: { id: string; text: string; created_at: string };\n reason: string;\n detectedAt: string;\n}\n\n/**\n * A flagged stale observation with its staleness metadata.\n */\nexport interface StalenessFlag {\n observation_id: string;\n flagged_at: string;\n reason: string;\n resolved: boolean;\n}\n\n// =============================================================================\n// Staleness Detection Patterns\n// =============================================================================\n\n/**\n * Negation patterns: newer observation negates older one.\n * Matches when newer text contains negation keywords absent in older text\n * and both discuss similar subjects.\n */\nconst NEGATION_KEYWORDS = [\n 'not',\n \"don't\",\n 'no longer',\n 'stopped',\n 'never',\n \"doesn't\",\n \"won't\",\n \"isn't\",\n \"aren't\",\n 'discontinued',\n] as const;\n\n/**\n * Replacement patterns: newer observation explicitly replaces older approach.\n */\nconst REPLACEMENT_PATTERNS = [\n /switched\\s+(?:from\\s+\\S+\\s+)?to\\b/i,\n /migrated\\s+(?:from\\s+\\S+\\s+)?to\\b/i,\n /replaced\\s+(?:\\S+\\s+)?with\\b/i,\n /changed\\s+from\\b/i,\n /moved\\s+(?:from\\s+\\S+\\s+)?to\\b/i,\n /upgraded\\s+(?:from\\s+\\S+\\s+)?to\\b/i,\n /swapped\\s+(?:\\S+\\s+)?(?:for|with)\\b/i,\n] as const;\n\n/**\n * Status change patterns: newer observation marks something as inactive.\n */\nconst STATUS_CHANGE_KEYWORDS = [\n 'removed',\n 'deleted',\n 'deprecated',\n 'archived',\n 'dropped',\n 'disabled',\n 'decommissioned',\n 'sunset',\n 'abandoned',\n] as const;\n\n// =============================================================================\n// Schema Initialization\n// =============================================================================\n\n/**\n * Creates the staleness_flags table if it doesn't exist.\n * Uses a separate table rather than modifying the observations table,\n * keeping staleness metadata decoupled from core observation storage.\n */\nexport function initStalenessSchema(db: BetterSqlite3.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS staleness_flags (\n observation_id TEXT PRIMARY KEY,\n flagged_at TEXT NOT NULL DEFAULT (datetime('now')),\n reason TEXT NOT NULL,\n resolved INTEGER NOT NULL DEFAULT 0\n );\n CREATE INDEX IF NOT EXISTS idx_staleness_resolved ON staleness_flags(resolved);\n `);\n}\n\n// =============================================================================\n// Detection\n// =============================================================================\n\n/**\n * Detects potential staleness (contradictions) between observations\n * linked to a specific entity.\n *\n * Compares consecutive observation pairs chronologically and checks for:\n * 1. Negation patterns (newer negates older)\n * 2. Replacement patterns (newer replaces older approach)\n * 3. Status change patterns (newer marks something as inactive)\n *\n * This is DETECTION ONLY -- no data is modified.\n *\n * @param db - better-sqlite3 Database handle\n * @param entityId - Graph node ID to check observations for\n * @returns Array of StalenessReport for each detected contradiction\n */\nexport function detectStaleness(\n db: BetterSqlite3.Database,\n entityId: string,\n): StalenessReport[] {\n // Get entity info\n const node = db\n .prepare('SELECT id, name, type, observation_ids FROM graph_nodes WHERE id = ?')\n .get(entityId) as\n | { id: string; name: string; type: string; observation_ids: string }\n | undefined;\n\n if (!node) return [];\n\n const obsIds = JSON.parse(node.observation_ids) as string[];\n if (obsIds.length < 2) return [];\n\n // Fetch observations and sort by created_at\n const placeholders = obsIds.map(() => '?').join(', ');\n const rows = db\n .prepare(\n `SELECT * FROM observations WHERE id IN (${placeholders}) AND deleted_at IS NULL ORDER BY created_at ASC`,\n )\n .all(...obsIds) as ObservationRow[];\n\n const observations = rows.map(rowToObservation);\n if (observations.length < 2) return [];\n\n const reports: StalenessReport[] = [];\n const now = new Date().toISOString();\n\n // Compare consecutive pairs\n for (let i = 0; i < observations.length - 1; i++) {\n const older = observations[i];\n const newer = observations[i + 1];\n\n const reason = detectContradiction(older.content, newer.content);\n if (reason) {\n reports.push({\n entityId: node.id,\n entityName: node.name,\n entityType: node.type as EntityType,\n newerObservation: {\n id: newer.id,\n text: newer.content,\n created_at: newer.createdAt,\n },\n olderObservation: {\n id: older.id,\n text: older.content,\n created_at: older.createdAt,\n },\n reason,\n detectedAt: now,\n });\n }\n }\n\n return reports;\n}\n\n/**\n * Detects contradiction between two observation texts.\n * Returns a human-readable reason string, or null if no contradiction found.\n */\nfunction detectContradiction(\n olderText: string,\n newerText: string,\n): string | null {\n const olderLower = olderText.toLowerCase();\n const newerLower = newerText.toLowerCase();\n\n // Check negation patterns\n const negationResult = detectNegation(olderLower, newerLower);\n if (negationResult) return negationResult;\n\n // Check replacement patterns\n const replacementResult = detectReplacement(newerLower);\n if (replacementResult) return replacementResult;\n\n // Check status change patterns\n const statusResult = detectStatusChange(olderLower, newerLower);\n if (statusResult) return statusResult;\n\n return null;\n}\n\n/**\n * Detects negation: newer text contains negation keywords that are absent\n * in the older text, suggesting the newer observation contradicts the older.\n */\nfunction detectNegation(\n olderLower: string,\n newerLower: string,\n): string | null {\n for (const keyword of NEGATION_KEYWORDS) {\n if (newerLower.includes(keyword) && !olderLower.includes(keyword)) {\n return `Newer observation contains negation (\"${keyword}\") not present in older observation`;\n }\n }\n return null;\n}\n\n/**\n * Detects replacement: newer text explicitly mentions switching/replacing.\n */\nfunction detectReplacement(newerLower: string): string | null {\n for (const pattern of REPLACEMENT_PATTERNS) {\n const match = newerLower.match(pattern);\n if (match) {\n return `Newer observation indicates replacement (\"${match[0].trim()}\")`;\n }\n }\n return null;\n}\n\n/**\n * Detects status change: newer text marks something as removed/deprecated\n * when the older text described it as active/present.\n */\nfunction detectStatusChange(\n olderLower: string,\n newerLower: string,\n): string | null {\n for (const keyword of STATUS_CHANGE_KEYWORDS) {\n if (newerLower.includes(keyword) && !olderLower.includes(keyword)) {\n return `Newer observation indicates status change (\"${keyword}\")`;\n }\n }\n return null;\n}\n\n// =============================================================================\n// Flagging\n// =============================================================================\n\n/**\n * Flags an observation as stale with an advisory reason.\n *\n * This flag is advisory -- search can use it to deprioritize but never hide\n * the observation. The observation remains fully queryable.\n *\n * Uses INSERT OR REPLACE to allow re-flagging with an updated reason.\n *\n * @param db - better-sqlite3 Database handle\n * @param observationId - ID of the observation to flag\n * @param reason - Human-readable explanation of why it's stale\n */\nexport function flagStaleObservation(\n db: BetterSqlite3.Database,\n observationId: string,\n reason: string,\n): void {\n initStalenessSchema(db);\n\n db.prepare(\n `INSERT OR REPLACE INTO staleness_flags (observation_id, reason, resolved)\n VALUES (?, ?, 0)`,\n ).run(observationId, reason);\n}\n\n// =============================================================================\n// Querying Flagged Observations\n// =============================================================================\n\n/**\n * Retrieves observations that have been flagged as stale.\n *\n * Optionally filtered by entity (via graph_nodes.observation_ids) or\n * resolution status.\n *\n * @param db - better-sqlite3 Database handle\n * @param opts - Filter options: entityId, resolved status\n * @returns Array of observation + staleness report pairs\n */\nexport function getStaleObservations(\n db: BetterSqlite3.Database,\n opts?: { entityId?: string; resolved?: boolean },\n): Array<{ observation: Observation; flag: StalenessFlag }> {\n initStalenessSchema(db);\n\n // Get candidate observation IDs (optionally scoped to entity)\n let candidateIds: string[] | null = null;\n if (opts?.entityId) {\n const node = db\n .prepare('SELECT observation_ids FROM graph_nodes WHERE id = ?')\n .get(opts.entityId) as { observation_ids: string } | undefined;\n\n if (!node) return [];\n candidateIds = JSON.parse(node.observation_ids) as string[];\n if (candidateIds.length === 0) return [];\n }\n\n // Build query\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (candidateIds) {\n const placeholders = candidateIds.map(() => '?').join(', ');\n conditions.push(`sf.observation_id IN (${placeholders})`);\n params.push(...candidateIds);\n }\n\n if (opts?.resolved !== undefined) {\n conditions.push('sf.resolved = ?');\n params.push(opts.resolved ? 1 : 0);\n }\n\n const whereClause =\n conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n\n const sql = `\n SELECT o.*, sf.observation_id AS sf_observation_id, sf.flagged_at AS sf_flagged_at,\n sf.reason AS sf_reason, sf.resolved AS sf_resolved\n FROM staleness_flags sf\n JOIN observations o ON o.id = sf.observation_id\n ${whereClause}\n ORDER BY sf.flagged_at DESC\n `;\n\n interface StaleRow extends ObservationRow {\n sf_observation_id: string;\n sf_flagged_at: string;\n sf_reason: string;\n sf_resolved: number;\n }\n\n const rows = db.prepare(sql).all(...params) as StaleRow[];\n\n return rows.map((row) => ({\n observation: rowToObservation(row),\n flag: {\n observation_id: row.sf_observation_id,\n flagged_at: row.sf_flagged_at,\n reason: row.sf_reason,\n resolved: row.sf_resolved === 1,\n },\n }));\n}\n","/**\n * Database Hygiene Configuration\n *\n * Controls signal weights and tier thresholds used by the hygiene\n * analyzer to score observations for deletion candidacy.\n *\n * Configuration is loaded from .laminark/hygiene.json with\n * a 5-second cache to avoid repeated disk reads.\n */\n\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { debug } from '../shared/debug.js';\nimport { getConfigDir } from '../shared/config.js';\n\nexport interface AutoCleanupConfig {\n enabled: boolean;\n tier: 'high' | 'medium' | 'all';\n maxOrphanNodes: number;\n}\n\nexport interface HygieneConfig {\n signalWeights: {\n orphaned: number;\n islandNode: number;\n noiseClassified: number;\n shortContent: number;\n autoCaptured: number;\n stale: number;\n };\n tierThresholds: {\n high: number;\n medium: number;\n };\n shortContentThreshold: number;\n autoCleanup: AutoCleanupConfig;\n}\n\nconst DEFAULT_AUTO_CLEANUP: AutoCleanupConfig = {\n enabled: true,\n tier: 'high',\n maxOrphanNodes: 500,\n};\n\nconst DEFAULTS: HygieneConfig = {\n signalWeights: {\n orphaned: 0.30,\n islandNode: 0.25,\n noiseClassified: 0.25,\n shortContent: 0.10,\n autoCaptured: 0.10,\n stale: 0.10,\n },\n tierThresholds: {\n high: 0.70,\n medium: 0.50,\n },\n shortContentThreshold: 50,\n autoCleanup: { ...DEFAULT_AUTO_CLEANUP },\n};\n\nconst CACHE_TTL_MS = 5000;\n\nlet cachedConfig: HygieneConfig | null = null;\nlet cachedAt = 0;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction validate(raw: Record<string, unknown>): HygieneConfig {\n const config = { ...DEFAULTS };\n\n if (raw.signalWeights && typeof raw.signalWeights === 'object' && !Array.isArray(raw.signalWeights)) {\n const sw = raw.signalWeights as Record<string, unknown>;\n const weights = { ...DEFAULTS.signalWeights };\n for (const key of Object.keys(DEFAULTS.signalWeights) as (keyof typeof DEFAULTS.signalWeights)[]) {\n if (typeof sw[key] === 'number') {\n weights[key] = clamp(sw[key] as number, 0, 1);\n }\n }\n config.signalWeights = weights;\n }\n\n if (raw.tierThresholds && typeof raw.tierThresholds === 'object' && !Array.isArray(raw.tierThresholds)) {\n const tt = raw.tierThresholds as Record<string, unknown>;\n let high = typeof tt.high === 'number' ? clamp(tt.high as number, 0, 1) : DEFAULTS.tierThresholds.high;\n let medium = typeof tt.medium === 'number' ? clamp(tt.medium as number, 0, 1) : DEFAULTS.tierThresholds.medium;\n // Enforce medium < high\n if (medium >= high) {\n medium = Math.max(0, high - 0.1);\n }\n config.tierThresholds = { high, medium };\n }\n\n if (typeof raw.shortContentThreshold === 'number') {\n config.shortContentThreshold = Math.max(0, Math.round(raw.shortContentThreshold as number));\n }\n\n if (raw.autoCleanup && typeof raw.autoCleanup === 'object' && !Array.isArray(raw.autoCleanup)) {\n const ac = raw.autoCleanup as Record<string, unknown>;\n const cleanup = { ...DEFAULT_AUTO_CLEANUP };\n if (typeof ac.enabled === 'boolean') cleanup.enabled = ac.enabled;\n if (ac.tier === 'high' || ac.tier === 'medium' || ac.tier === 'all') cleanup.tier = ac.tier;\n if (typeof ac.maxOrphanNodes === 'number') cleanup.maxOrphanNodes = Math.max(0, Math.round(ac.maxOrphanNodes));\n config.autoCleanup = cleanup;\n }\n\n return config;\n}\n\n/**\n * Loads hygiene configuration from disk with a 5-second cache.\n */\nexport function loadHygieneConfig(): HygieneConfig {\n const now = Date.now();\n if (cachedConfig && now - cachedAt < CACHE_TTL_MS) {\n return cachedConfig;\n }\n\n const configPath = join(getConfigDir(), 'hygiene.json');\n try {\n const content = readFileSync(configPath, 'utf-8');\n const raw = JSON.parse(content) as Record<string, unknown>;\n cachedConfig = validate(raw);\n debug('config', 'Loaded hygiene config', { ...cachedConfig });\n } catch {\n cachedConfig = { ...DEFAULTS, signalWeights: { ...DEFAULTS.signalWeights }, tierThresholds: { ...DEFAULTS.tierThresholds } };\n }\n\n cachedAt = now;\n return cachedConfig;\n}\n\n/**\n * Saves hygiene configuration to disk and invalidates cache.\n */\nexport function saveHygieneConfig(config: HygieneConfig): void {\n const configPath = join(getConfigDir(), 'hygiene.json');\n writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');\n cachedConfig = config;\n cachedAt = Date.now();\n}\n\n/**\n * Resets hygiene config to defaults by invalidating cache.\n */\nexport function resetHygieneConfig(): HygieneConfig {\n cachedConfig = null;\n cachedAt = 0;\n return { ...DEFAULTS, signalWeights: { ...DEFAULTS.signalWeights }, tierThresholds: { ...DEFAULTS.tierThresholds }, autoCleanup: { ...DEFAULT_AUTO_CLEANUP } };\n}\n","/**\n * Database hygiene analyzer.\n *\n * Scores observations on multiple deletion signals and produces a\n * simulation report of candidates for cleanup. No side effects in\n * analyze mode — purging is handled by the MCP tool layer.\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\n\nimport type { HygieneConfig, AutoCleanupConfig } from '../config/hygiene-config.js';\nimport { loadHygieneConfig } from '../config/hygiene-config.js';\nimport { debug } from '../shared/debug.js';\nimport { initStalenessSchema } from './staleness.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface HygieneCandidate {\n id: string;\n shortId: string;\n sessionId: string | null;\n kind: string;\n source: string;\n contentPreview: string;\n createdAt: string;\n signals: {\n orphaned: boolean;\n islandNode: boolean;\n noiseClassified: boolean;\n shortContent: boolean;\n autoCaptured: boolean;\n stale: boolean;\n };\n confidence: number;\n tier: 'high' | 'medium' | 'low';\n}\n\nexport interface OrphanNode {\n id: string;\n type: string;\n name: string;\n reason: string;\n}\n\nexport interface HygieneReport {\n analyzedAt: string;\n totalObservations: number;\n candidates: HygieneCandidate[];\n orphanNodes: OrphanNode[];\n summary: {\n high: number;\n medium: number;\n low: number;\n orphanNodeCount: number;\n };\n}\n\nexport interface FindAnalysisReport {\n total: number;\n bySignal: {\n orphaned: number;\n islandNode: number;\n noiseClassified: number;\n shortContent: number;\n autoCaptured: number;\n stale: number;\n };\n distribution: { range: string; count: number }[];\n islandNodes: {\n total: number;\n minConfidence: number;\n maxConfidence: number;\n medianConfidence: number;\n capturedAtCurrentThresholds: { high: number; medium: number; all: number };\n };\n}\n\n// =============================================================================\n// Internal Row Types\n// =============================================================================\n\ninterface ObsRow {\n id: string;\n content: string;\n title: string | null;\n source: string;\n kind: string;\n session_id: string | null;\n classification: string | null;\n created_at: string;\n}\n\ninterface GraphNodeRow {\n id: string;\n type: string;\n name: string;\n observation_ids: string; // JSON array\n}\n\n// =============================================================================\n// Shared: build signal lookups\n// =============================================================================\n\ninterface SignalLookups {\n linkedObsIds: Set<string>;\n islandObsIds: Set<string>;\n staleIds: Set<string>;\n allNodes: GraphNodeRow[];\n edgeCounts: Map<string, number>;\n}\n\nfunction buildSignalLookups(db: BetterSqlite3.Database, projectHash: string | null): SignalLookups {\n const linkedObsIds = new Set<string>();\n const islandObsIds = new Set<string>();\n\n const allNodes = projectHash\n ? db.prepare(\n 'SELECT id, type, name, observation_ids FROM graph_nodes WHERE project_hash = ?',\n ).all(projectHash) as GraphNodeRow[]\n : db.prepare(\n 'SELECT id, type, name, observation_ids FROM graph_nodes',\n ).all() as GraphNodeRow[];\n\n const edgeCounts = new Map<string, number>();\n const edgeRows = projectHash\n ? db.prepare(\n `SELECT source_id AS nid, COUNT(*) AS cnt FROM graph_edges WHERE project_hash = ? GROUP BY source_id\n UNION ALL\n SELECT target_id AS nid, COUNT(*) AS cnt FROM graph_edges WHERE project_hash = ? GROUP BY target_id`,\n ).all(projectHash, projectHash) as { nid: string; cnt: number }[]\n : db.prepare(\n `SELECT source_id AS nid, COUNT(*) AS cnt FROM graph_edges GROUP BY source_id\n UNION ALL\n SELECT target_id AS nid, COUNT(*) AS cnt FROM graph_edges GROUP BY target_id`,\n ).all() as { nid: string; cnt: number }[];\n for (const row of edgeRows) {\n edgeCounts.set(row.nid, (edgeCounts.get(row.nid) ?? 0) + row.cnt);\n }\n\n for (const node of allNodes) {\n let obsIds: string[];\n try {\n obsIds = JSON.parse(node.observation_ids) as string[];\n } catch {\n continue;\n }\n\n const degree = edgeCounts.get(node.id) ?? 0;\n\n for (const oid of obsIds) {\n linkedObsIds.add(oid);\n if (degree === 0) {\n islandObsIds.add(oid);\n }\n }\n }\n\n const staleIds = new Set<string>();\n try {\n initStalenessSchema(db);\n const staleRows = db.prepare(\n 'SELECT observation_id FROM staleness_flags WHERE resolved = 0',\n ).all() as { observation_id: string }[];\n for (const row of staleRows) {\n staleIds.add(row.observation_id);\n }\n } catch {\n // staleness_flags may not exist\n }\n\n return { linkedObsIds, islandObsIds, staleIds, allNodes, edgeCounts };\n}\n\nfunction scoreObservation(\n obs: ObsRow,\n lookups: SignalLookups,\n config: HygieneConfig,\n): { signals: HygieneCandidate['signals']; confidence: number; tier: 'high' | 'medium' | 'low' } {\n const weights = config.signalWeights;\n const thresholds = config.tierThresholds;\n\n const signals = {\n orphaned: !lookups.linkedObsIds.has(obs.id),\n islandNode: lookups.islandObsIds.has(obs.id),\n noiseClassified: obs.classification === 'noise',\n shortContent: obs.content.length < config.shortContentThreshold,\n autoCaptured: obs.source.startsWith('hook:'),\n stale: lookups.staleIds.has(obs.id),\n };\n\n const confidence =\n (signals.orphaned ? weights.orphaned : 0) +\n (signals.islandNode ? weights.islandNode : 0) +\n (signals.noiseClassified ? weights.noiseClassified : 0) +\n (signals.shortContent ? weights.shortContent : 0) +\n (signals.autoCaptured ? weights.autoCaptured : 0) +\n (signals.stale ? weights.stale : 0);\n\n const tier: 'high' | 'medium' | 'low' =\n confidence >= thresholds.high ? 'high' : confidence >= thresholds.medium ? 'medium' : 'low';\n\n return { signals, confidence: Math.round(confidence * 100) / 100, tier };\n}\n\n// =============================================================================\n// Analysis\n// =============================================================================\n\nexport interface AnalyzeOptions {\n sessionId?: string;\n limit?: number;\n minTier?: 'high' | 'medium' | 'low';\n config?: HygieneConfig;\n}\n\n/**\n * Analyzes all active observations and scores each on deletion signals.\n * Pure read-only — no data is modified.\n */\nexport function analyzeObservations(\n db: BetterSqlite3.Database,\n projectHash: string,\n opts?: AnalyzeOptions,\n): HygieneReport {\n const limit = opts?.limit ?? 50;\n const minTier = opts?.minTier ?? 'medium';\n const config = opts?.config ?? loadHygieneConfig();\n\n debug('hygiene', 'Starting analysis', { projectHash, sessionId: opts?.sessionId });\n\n // 1. Fetch all active observations for this project\n let obsSql = `\n SELECT id, content, title, source, kind, session_id, classification, created_at\n FROM observations\n WHERE project_hash = ? AND deleted_at IS NULL\n `;\n const obsParams: unknown[] = [projectHash];\n\n if (opts?.sessionId) {\n obsSql += ' AND session_id = ?';\n obsParams.push(opts.sessionId);\n }\n\n obsSql += ' ORDER BY created_at DESC';\n const observations = db.prepare(obsSql).all(...obsParams) as ObsRow[];\n\n // 2. Build lookup sets for signal detection\n const lookups = buildSignalLookups(db, projectHash);\n\n // 3. Score each observation\n const allCandidates: HygieneCandidate[] = [];\n\n for (const obs of observations) {\n const { signals, confidence, tier } = scoreObservation(obs, lookups, config);\n\n // Filter by minimum tier\n if (minTier === 'high' && tier !== 'high') continue;\n if (minTier === 'medium' && tier === 'low') continue;\n\n const preview = obs.content.length > 80\n ? obs.content.substring(0, 80) + '...'\n : obs.content;\n\n allCandidates.push({\n id: obs.id,\n shortId: obs.id.substring(0, 8),\n sessionId: obs.session_id,\n kind: obs.kind,\n source: obs.source,\n contentPreview: preview,\n createdAt: obs.created_at,\n signals,\n confidence,\n tier,\n });\n }\n\n // Sort by confidence descending\n allCandidates.sort((a, b) => b.confidence - a.confidence);\n\n // 4. Find orphan graph nodes (zero edges AND all observation refs dead/missing)\n const activeObsIds = new Set(observations.map(o => o.id));\n const orphanNodes: OrphanNode[] = [];\n\n for (const node of lookups.allNodes) {\n const degree = lookups.edgeCounts.get(node.id) ?? 0;\n if (degree > 0) continue;\n\n let obsIds: string[];\n try {\n obsIds = JSON.parse(node.observation_ids) as string[];\n } catch {\n continue;\n }\n\n // Zero-edge nodes are island nodes — they add no graph connectivity.\n // Flag them all as orphans regardless of whether observation refs are alive.\n const allDead = obsIds.length === 0 || obsIds.every(oid => !activeObsIds.has(oid));\n orphanNodes.push({\n id: node.id,\n type: node.type,\n name: node.name,\n reason: allDead ? 'zero edges, dead observation refs' : 'zero edges (island node)',\n });\n }\n\n // 5. Build summary\n const limited = allCandidates.slice(0, limit);\n const highCount = allCandidates.filter(c => c.tier === 'high').length;\n const mediumCount = allCandidates.filter(c => c.tier === 'medium').length;\n const lowCount = allCandidates.filter(c => c.tier === 'low').length;\n\n debug('hygiene', 'Analysis complete', {\n total: observations.length,\n high: highCount,\n medium: mediumCount,\n orphanNodes: orphanNodes.length,\n });\n\n return {\n analyzedAt: new Date().toISOString(),\n totalObservations: observations.length,\n candidates: limited,\n orphanNodes: orphanNodes.slice(0, limit),\n summary: {\n high: highCount,\n medium: mediumCount,\n low: lowCount,\n orphanNodeCount: orphanNodes.length,\n },\n };\n}\n\n// =============================================================================\n// Find Analysis\n// =============================================================================\n\n/**\n * Produces a score distribution report across all observations.\n * Shows signal counts, confidence histogram, and island node summary\n * so users can tune thresholds to catch the right candidates.\n */\nexport function findAnalysis(\n db: BetterSqlite3.Database,\n projectHash: string,\n config?: HygieneConfig,\n): FindAnalysisReport {\n const cfg = config ?? loadHygieneConfig();\n\n const observations = db.prepare(`\n SELECT id, content, title, source, kind, session_id, classification, created_at\n FROM observations\n WHERE project_hash = ? AND deleted_at IS NULL\n ORDER BY created_at DESC\n `).all(projectHash) as ObsRow[];\n\n const lookups = buildSignalLookups(db, projectHash);\n\n const bySignal = {\n orphaned: 0,\n islandNode: 0,\n noiseClassified: 0,\n shortContent: 0,\n autoCaptured: 0,\n stale: 0,\n };\n\n // 10 histogram buckets: 0.0-0.1, 0.1-0.2, ... 0.9-1.0\n const buckets = new Array(10).fill(0) as number[];\n\n // Track island-linked observation confidences\n const islandConfidences: number[] = [];\n\n for (const obs of observations) {\n const { signals, confidence } = scoreObservation(obs, lookups, cfg);\n\n if (signals.orphaned) bySignal.orphaned++;\n if (signals.islandNode) bySignal.islandNode++;\n if (signals.noiseClassified) bySignal.noiseClassified++;\n if (signals.shortContent) bySignal.shortContent++;\n if (signals.autoCaptured) bySignal.autoCaptured++;\n if (signals.stale) bySignal.stale++;\n\n const bucketIdx = Math.min(Math.floor(confidence * 10), 9);\n buckets[bucketIdx]++;\n\n if (signals.islandNode) {\n islandConfidences.push(confidence);\n }\n }\n\n const distribution = buckets.map((count, i) => ({\n range: `${(i / 10).toFixed(1)}-${((i + 1) / 10).toFixed(1)}`,\n count,\n }));\n\n // Island node summary\n islandConfidences.sort((a, b) => a - b);\n const islandTotal = islandConfidences.length;\n const minConf = islandTotal > 0 ? islandConfidences[0] : 0;\n const maxConf = islandTotal > 0 ? islandConfidences[islandTotal - 1] : 0;\n const medianConf = islandTotal > 0\n ? islandConfidences[Math.floor(islandTotal / 2)]\n : 0;\n\n const capturedHigh = islandConfidences.filter(c => c >= cfg.tierThresholds.high).length;\n const capturedMedium = islandConfidences.filter(c => c >= cfg.tierThresholds.medium).length;\n\n return {\n total: observations.length,\n bySignal,\n distribution,\n islandNodes: {\n total: islandTotal,\n minConfidence: Math.round(minConf * 100) / 100,\n maxConfidence: Math.round(maxConf * 100) / 100,\n medianConfidence: Math.round(medianConf * 100) / 100,\n capturedAtCurrentThresholds: {\n high: capturedHigh,\n medium: capturedMedium,\n all: islandTotal,\n },\n },\n };\n}\n\n// =============================================================================\n// Purge Execution\n// =============================================================================\n\nexport interface PurgeResult {\n observationsPurged: number;\n orphanNodesRemoved: number;\n}\n\n/**\n * Soft-deletes observations matching the given tier threshold and removes\n * dead orphan graph nodes. Returns counts of affected records.\n */\nexport interface AutoCleanupResult {\n skipped: boolean;\n reason?: string;\n observationsPurged: number;\n orphanNodesRemoved: number;\n}\n\n/**\n * Runs automatic hygiene cleanup at session end.\n *\n * Analyzes observations and purges candidates matching the configured tier.\n * Orphan graph node removal is capped by autoCleanup.maxOrphanNodes.\n * Safe to call on every session end — skips quickly if disabled.\n */\nexport function runAutoCleanup(\n db: BetterSqlite3.Database,\n projectHash: string,\n config?: HygieneConfig,\n): AutoCleanupResult {\n const cfg = config ?? loadHygieneConfig();\n const auto = cfg.autoCleanup;\n\n if (!auto.enabled) {\n return { skipped: true, reason: 'disabled', observationsPurged: 0, orphanNodesRemoved: 0 };\n }\n\n debug('hygiene', 'Auto-cleanup starting', { tier: auto.tier, maxOrphanNodes: auto.maxOrphanNodes });\n\n const minTier = auto.tier === 'all' ? 'low' as const : auto.tier;\n const report = analyzeObservations(db, projectHash, {\n limit: 200,\n minTier,\n config: cfg,\n });\n\n // Cap orphan node removal\n if (report.orphanNodes.length > auto.maxOrphanNodes) {\n report.orphanNodes = report.orphanNodes.slice(0, auto.maxOrphanNodes);\n }\n\n const totalWork = report.candidates.length + report.orphanNodes.length;\n if (totalWork === 0) {\n debug('hygiene', 'Auto-cleanup: nothing to clean');\n return { skipped: false, observationsPurged: 0, orphanNodesRemoved: 0 };\n }\n\n const result = executePurge(db, projectHash, report, auto.tier);\n\n debug('hygiene', 'Auto-cleanup complete', {\n observationsPurged: result.observationsPurged,\n orphanNodesRemoved: result.orphanNodesRemoved,\n });\n\n return { skipped: false, ...result };\n}\n\nexport function executePurge(\n db: BetterSqlite3.Database,\n projectHash: string,\n report: HygieneReport,\n tier: 'high' | 'medium' | 'all',\n): PurgeResult {\n const candidateIds = report.candidates\n .filter(c => {\n if (tier === 'high') return c.tier === 'high';\n if (tier === 'medium') return c.tier === 'high' || c.tier === 'medium';\n return true; // 'all'\n })\n .map(c => c.id);\n\n debug('hygiene', 'Executing purge', { tier, candidates: candidateIds.length });\n\n let observationsPurged = 0;\n\n // Soft-delete observations in batches\n const softDeleteStmt = db.prepare(`\n UPDATE observations\n SET deleted_at = datetime('now'), updated_at = datetime('now')\n WHERE id = ? AND project_hash = ? AND deleted_at IS NULL\n `);\n\n const purgeTransaction = db.transaction(() => {\n for (const id of candidateIds) {\n const result = softDeleteStmt.run(id, projectHash);\n observationsPurged += result.changes;\n }\n\n // Remove dead orphan graph nodes\n let orphanNodesRemoved = 0;\n const deleteNodeStmt = db.prepare('DELETE FROM graph_nodes WHERE id = ?');\n for (const node of report.orphanNodes) {\n const result = deleteNodeStmt.run(node.id);\n orphanNodesRemoved += result.changes;\n }\n\n return { observationsPurged, orphanNodesRemoved };\n });\n\n return purgeTransaction();\n}\n","import type { ToolType, ToolScope } from '../shared/tool-types.js';\n\n/**\n * Infers the tool type from a tool name seen in PostToolUse.\n *\n * - MCP tools have the `mcp__` prefix\n * - Built-in tools are PascalCase single words (Write, Edit, Bash, Read, etc.)\n * - Anything else is unknown\n */\nexport function inferToolType(toolName: string): ToolType {\n if (toolName.startsWith('mcp__')) {\n return 'mcp_tool';\n }\n if (/^[A-Z][a-zA-Z]+$/.test(toolName)) {\n return 'builtin';\n }\n return 'unknown';\n}\n\n/**\n * Infers the scope of a tool from its name.\n *\n * - Plugin MCP tools (mcp__plugin_*) are plugin-scoped\n * - Other MCP tools default to project-scoped (conservative; may be global but unknown from name alone)\n * - Non-MCP tools (builtins) are always global\n */\nexport function inferScope(toolName: string): ToolScope {\n if (toolName.startsWith('mcp__plugin_')) {\n return 'plugin';\n }\n if (toolName.startsWith('mcp__')) {\n return 'project';\n }\n return 'global';\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n *\n * Plugin MCP tools: `mcp__plugin_<pluginName>_<serverName>__<tool>`\n * Example: `mcp__plugin_laminark_laminark__recall` -> server is `laminark`\n *\n * Project MCP tools: `mcp__<serverName>__<tool>`\n * Example: `mcp__playwright__browser_screenshot` -> server is `playwright`\n *\n * Returns null for non-MCP tools.\n */\nexport function extractServerName(toolName: string): string | null {\n // Plugin MCP tools: mcp__plugin_<pluginName>_<serverName>__<tool>\n const pluginMatch = toolName.match(\n /^mcp__plugin_([^_]+(?:_[^_]+)*)_([^_]+(?:_[^_]+)*)__/,\n );\n if (pluginMatch) {\n return pluginMatch[2];\n }\n\n // Project MCP tools: mcp__<serverName>__<tool>\n const projectMatch = toolName.match(/^mcp__([^_]+(?:_[^_]+)*)__/);\n if (projectMatch) {\n return projectMatch[1];\n }\n\n return null;\n}\n","/**\n * Repository for thought branch CRUD operations.\n *\n * Every query is scoped to the projectHash provided at construction time.\n * All SQL statements are prepared once in the constructor and reused for\n * every call (same pattern as PathRepository).\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\nimport { randomBytes } from 'node:crypto';\n\nimport type {\n ThoughtBranch,\n BranchObservation,\n BranchStatus,\n BranchType,\n ArcStage,\n TriggerSource,\n} from './types.js';\n\nexport class BranchRepository {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n // Prepared statements — branch lifecycle\n private readonly stmtCreate: BetterSqlite3.Statement;\n private readonly stmtComplete: BetterSqlite3.Statement;\n private readonly stmtAbandon: BetterSqlite3.Statement;\n private readonly stmtGetActive: BetterSqlite3.Statement;\n private readonly stmtGetById: BetterSqlite3.Statement;\n private readonly stmtList: BetterSqlite3.Statement;\n private readonly stmtListByStatus: BetterSqlite3.Statement;\n private readonly stmtListByType: BetterSqlite3.Statement;\n\n // Prepared statements — branch updates\n private readonly stmtUpdateArcStage: BetterSqlite3.Statement;\n private readonly stmtUpdateToolPattern: BetterSqlite3.Statement;\n private readonly stmtUpdateClassification: BetterSqlite3.Statement;\n private readonly stmtUpdateSummary: BetterSqlite3.Statement;\n private readonly stmtIncrementObsCount: BetterSqlite3.Statement;\n private readonly stmtLinkDebugPath: BetterSqlite3.Statement;\n\n // Prepared statements — observations\n private readonly stmtAddObservation: BetterSqlite3.Statement;\n private readonly stmtGetObservations: BetterSqlite3.Statement;\n private readonly stmtMaxSequence: BetterSqlite3.Statement;\n\n // Prepared statements — maintenance\n private readonly stmtFindStale: BetterSqlite3.Statement;\n private readonly stmtFindUnclassified: BetterSqlite3.Statement;\n private readonly stmtFindRecentCompleted: BetterSqlite3.Statement;\n private readonly stmtFindRecentActive: BetterSqlite3.Statement;\n private readonly stmtListRecent: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n\n // --- Branch lifecycle ---\n\n this.stmtCreate = db.prepare(`\n INSERT INTO thought_branches\n (id, project_hash, session_id, status, trigger_source, trigger_observation_id, started_at)\n VALUES (?, ?, ?, 'active', ?, ?, datetime('now'))\n `);\n\n this.stmtComplete = db.prepare(`\n UPDATE thought_branches\n SET status = 'completed', arc_stage = 'completed', ended_at = datetime('now')\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtAbandon = db.prepare(`\n UPDATE thought_branches\n SET status = 'abandoned', ended_at = datetime('now')\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtGetActive = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND status = 'active'\n ORDER BY started_at DESC\n LIMIT 1\n `);\n\n this.stmtGetById = db.prepare(`\n SELECT * FROM thought_branches\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtList = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ?\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n this.stmtListByStatus = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND status = ?\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n this.stmtListByType = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND branch_type = ?\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n // --- Branch updates ---\n\n this.stmtUpdateArcStage = db.prepare(`\n UPDATE thought_branches SET arc_stage = ? WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtUpdateToolPattern = db.prepare(`\n UPDATE thought_branches SET tool_pattern = ? WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtUpdateClassification = db.prepare(`\n UPDATE thought_branches SET branch_type = ?, title = ? WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtUpdateSummary = db.prepare(`\n UPDATE thought_branches SET summary = ? WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtIncrementObsCount = db.prepare(`\n UPDATE thought_branches SET observation_count = observation_count + 1 WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtLinkDebugPath = db.prepare(`\n UPDATE thought_branches SET linked_debug_path_id = ? WHERE id = ? AND project_hash = ?\n `);\n\n // --- Observations ---\n\n this.stmtAddObservation = db.prepare(`\n INSERT OR IGNORE INTO branch_observations\n (branch_id, observation_id, sequence_order, tool_name, arc_stage_at_add)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n this.stmtGetObservations = db.prepare(`\n SELECT * FROM branch_observations\n WHERE branch_id = ?\n ORDER BY sequence_order ASC\n `);\n\n this.stmtMaxSequence = db.prepare(`\n SELECT COALESCE(MAX(sequence_order), 0) AS max_seq FROM branch_observations\n WHERE branch_id = ?\n `);\n\n // --- Maintenance ---\n\n this.stmtFindStale = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND status = 'active'\n AND started_at < datetime('now', '-24 hours')\n `);\n\n this.stmtFindUnclassified = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND branch_type = 'unknown'\n AND observation_count >= 3\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n this.stmtFindRecentCompleted = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND status = 'completed' AND summary IS NULL\n AND ended_at > datetime('now', '-1 hour')\n ORDER BY ended_at DESC\n LIMIT ?\n `);\n\n this.stmtFindRecentActive = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ? AND status = 'active'\n AND started_at > datetime('now', '-24 hours')\n ORDER BY started_at DESC\n LIMIT 1\n `);\n\n this.stmtListRecent = db.prepare(`\n SELECT * FROM thought_branches\n WHERE project_hash = ?\n AND started_at > datetime('now', ? || ' hours')\n ORDER BY started_at DESC\n `);\n }\n\n // ===========================================================================\n // Branch Lifecycle\n // ===========================================================================\n\n createBranch(\n sessionId: string | null,\n triggerSource: TriggerSource,\n triggerObservationId?: string,\n ): ThoughtBranch {\n const id = randomBytes(16).toString('hex');\n this.stmtCreate.run(\n id,\n this.projectHash,\n sessionId,\n triggerSource,\n triggerObservationId ?? null,\n );\n return this.getBranch(id)!;\n }\n\n completeBranch(branchId: string): void {\n this.stmtComplete.run(branchId, this.projectHash);\n }\n\n abandonBranch(branchId: string): void {\n this.stmtAbandon.run(branchId, this.projectHash);\n }\n\n getActiveBranch(): ThoughtBranch | null {\n const row = this.stmtGetActive.get(this.projectHash) as BranchRow | undefined;\n return row ? rowToBranch(row) : null;\n }\n\n getBranch(branchId: string): ThoughtBranch | null {\n const row = this.stmtGetById.get(branchId, this.projectHash) as BranchRow | undefined;\n return row ? rowToBranch(row) : null;\n }\n\n listBranches(limit: number = 20): ThoughtBranch[] {\n const rows = this.stmtList.all(this.projectHash, limit) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n listByStatus(status: BranchStatus, limit: number = 20): ThoughtBranch[] {\n const rows = this.stmtListByStatus.all(this.projectHash, status, limit) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n listByType(branchType: BranchType, limit: number = 20): ThoughtBranch[] {\n const rows = this.stmtListByType.all(this.projectHash, branchType, limit) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n // ===========================================================================\n // Branch Updates\n // ===========================================================================\n\n updateArcStage(branchId: string, stage: ArcStage): void {\n this.stmtUpdateArcStage.run(stage, branchId, this.projectHash);\n }\n\n updateToolPattern(branchId: string, pattern: Record<string, number>): void {\n this.stmtUpdateToolPattern.run(JSON.stringify(pattern), branchId, this.projectHash);\n }\n\n updateClassification(branchId: string, branchType: BranchType, title: string): void {\n this.stmtUpdateClassification.run(branchType, title, branchId, this.projectHash);\n }\n\n updateSummary(branchId: string, summary: string): void {\n this.stmtUpdateSummary.run(summary, branchId, this.projectHash);\n }\n\n linkDebugPath(branchId: string, debugPathId: string): void {\n this.stmtLinkDebugPath.run(debugPathId, branchId, this.projectHash);\n }\n\n // ===========================================================================\n // Observation Management\n // ===========================================================================\n\n addObservation(\n branchId: string,\n observationId: string,\n toolName: string | null,\n arcStage: ArcStage | null,\n ): void {\n const { max_seq } = this.stmtMaxSequence.get(branchId) as { max_seq: number };\n this.stmtAddObservation.run(\n branchId,\n observationId,\n max_seq + 1,\n toolName,\n arcStage,\n );\n this.stmtIncrementObsCount.run(branchId, this.projectHash);\n }\n\n getObservations(branchId: string): BranchObservation[] {\n const rows = this.stmtGetObservations.all(branchId) as BranchObservationRow[];\n return rows.map(rowToBranchObservation);\n }\n\n // ===========================================================================\n // Maintenance Queries\n // ===========================================================================\n\n findStaleBranches(): ThoughtBranch[] {\n const rows = this.stmtFindStale.all(this.projectHash) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n findUnclassifiedBranches(limit: number = 5): ThoughtBranch[] {\n const rows = this.stmtFindUnclassified.all(this.projectHash, limit) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n findRecentCompletedUnsummarized(limit: number = 3): ThoughtBranch[] {\n const rows = this.stmtFindRecentCompleted.all(this.projectHash, limit) as BranchRow[];\n return rows.map(rowToBranch);\n }\n\n findRecentActiveBranch(): ThoughtBranch | null {\n const row = this.stmtFindRecentActive.get(this.projectHash) as BranchRow | undefined;\n return row ? rowToBranch(row) : null;\n }\n\n listRecentBranches(hours: number): ThoughtBranch[] {\n const rows = this.stmtListRecent.all(this.projectHash, `-${hours}`) as BranchRow[];\n return rows.map(rowToBranch);\n }\n}\n\n// =============================================================================\n// Raw Row Types\n// =============================================================================\n\ninterface BranchRow {\n id: string;\n project_hash: string;\n session_id: string | null;\n status: string;\n branch_type: string;\n arc_stage: string;\n title: string | null;\n summary: string | null;\n parent_branch_id: string | null;\n linked_debug_path_id: string | null;\n trigger_source: string | null;\n trigger_observation_id: string | null;\n observation_count: number;\n tool_pattern: string;\n started_at: string;\n ended_at: string | null;\n created_at: string;\n}\n\ninterface BranchObservationRow {\n branch_id: string;\n observation_id: string;\n sequence_order: number;\n tool_name: string | null;\n arc_stage_at_add: string | null;\n created_at: string;\n}\n\n// =============================================================================\n// Row Mapping\n// =============================================================================\n\nfunction rowToBranch(row: BranchRow): ThoughtBranch {\n let toolPattern: Record<string, number> = {};\n try {\n toolPattern = JSON.parse(row.tool_pattern);\n } catch {\n // Default to empty\n }\n\n return {\n id: row.id,\n project_hash: row.project_hash,\n session_id: row.session_id,\n status: row.status as BranchStatus,\n branch_type: row.branch_type as BranchType,\n arc_stage: row.arc_stage as ArcStage,\n title: row.title,\n summary: row.summary,\n parent_branch_id: row.parent_branch_id,\n linked_debug_path_id: row.linked_debug_path_id,\n trigger_source: row.trigger_source as TriggerSource | null,\n trigger_observation_id: row.trigger_observation_id,\n observation_count: row.observation_count,\n tool_pattern: toolPattern,\n started_at: row.started_at,\n ended_at: row.ended_at,\n created_at: row.created_at,\n };\n}\n\nfunction rowToBranchObservation(row: BranchObservationRow): BranchObservation {\n return {\n branch_id: row.branch_id,\n observation_id: row.observation_id,\n sequence_order: row.sequence_order,\n tool_name: row.tool_name,\n arc_stage_at_add: row.arc_stage_at_add as ArcStage | null,\n created_at: row.created_at,\n };\n}\n","import type BetterSqlite3 from 'better-sqlite3';\n\nimport { debug } from '../shared/debug.js';\n\n/**\n * Lightweight buffer for exploration tool events (Read, Glob, Grep).\n *\n * Instead of creating full observations for these low-signal tools,\n * they are stored in a temporary buffer. When a Write/Edit observation\n * is created, the recent buffer entries are attached as research context,\n * creating provenance links between exploration and changes.\n *\n * Buffer entries are flushed after 30 minutes.\n */\nexport class ResearchBufferRepository {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n private readonly stmtInsert: BetterSqlite3.Statement;\n private readonly stmtGetRecent: BetterSqlite3.Statement;\n private readonly stmtFlush: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n\n this.stmtInsert = db.prepare(`\n INSERT INTO research_buffer (project_hash, session_id, tool_name, target)\n VALUES (?, ?, ?, ?)\n `);\n\n this.stmtGetRecent = db.prepare(`\n SELECT tool_name, target, created_at FROM research_buffer\n WHERE session_id = ? AND project_hash = ?\n AND created_at >= datetime('now', '-' || ? || ' minutes')\n ORDER BY created_at DESC\n `);\n\n this.stmtFlush = db.prepare(`\n DELETE FROM research_buffer\n WHERE created_at < datetime('now', '-' || ? || ' minutes')\n `);\n\n debug('research-buffer', 'ResearchBufferRepository initialized', { projectHash });\n }\n\n /**\n * Records a research tool event in the buffer.\n */\n add(entry: {\n sessionId: string | null;\n toolName: string;\n target: string;\n }): void {\n this.stmtInsert.run(\n this.projectHash,\n entry.sessionId,\n entry.toolName,\n entry.target,\n );\n debug('research-buffer', 'Buffered research event', {\n tool: entry.toolName,\n target: entry.target,\n });\n }\n\n /**\n * Returns recent buffer entries for a session within a time window.\n */\n getRecent(\n sessionId: string,\n windowMinutes: number = 5,\n ): Array<{ toolName: string; target: string; createdAt: string }> {\n const rows = this.stmtGetRecent.all(\n sessionId,\n this.projectHash,\n windowMinutes,\n ) as Array<{ tool_name: string; target: string; created_at: string }>;\n\n return rows.map(r => ({\n toolName: r.tool_name,\n target: r.target,\n createdAt: r.created_at,\n }));\n }\n\n /**\n * Deletes buffer entries older than the specified number of minutes.\n */\n flush(olderThanMinutes: number = 30): number {\n const result = this.stmtFlush.run(olderThanMinutes);\n if (result.changes > 0) {\n debug('research-buffer', 'Flushed old entries', { deleted: result.changes });\n }\n return result.changes;\n }\n}\n","import type BetterSqlite3 from 'better-sqlite3';\nimport { randomBytes } from 'node:crypto';\nimport { debug } from '../shared/debug.js';\n\nexport interface PendingNotification {\n id: string;\n projectId: string;\n message: string;\n createdAt: string;\n}\n\nexport class NotificationStore {\n private readonly stmtInsert: BetterSqlite3.Statement;\n private readonly stmtConsume: BetterSqlite3.Statement;\n private readonly stmtSelect: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database) {\n // Create table inline (no migration needed -- simple transient store)\n db.exec(`\n CREATE TABLE IF NOT EXISTS pending_notifications (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n message TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `);\n\n this.stmtInsert = db.prepare(\n 'INSERT INTO pending_notifications (id, project_id, message) VALUES (?, ?, ?)'\n );\n this.stmtSelect = db.prepare(\n 'SELECT * FROM pending_notifications WHERE project_id = ? ORDER BY created_at ASC LIMIT 10'\n );\n this.stmtConsume = db.prepare(\n 'DELETE FROM pending_notifications WHERE project_id = ?'\n );\n debug('db', 'NotificationStore initialized');\n }\n\n add(projectId: string, message: string): void {\n const id = randomBytes(16).toString('hex');\n this.stmtInsert.run(id, projectId, message);\n debug('db', 'Notification added', { projectId });\n }\n\n /** Fetch and delete all pending notifications for a project (consume pattern). */\n consumePending(projectId: string): PendingNotification[] {\n const rows = this.stmtSelect.all(projectId) as Array<{\n id: string; project_id: string; message: string; created_at: string;\n }>;\n if (rows.length > 0) {\n this.stmtConsume.run(projectId);\n }\n return rows.map(r => ({\n id: r.id,\n projectId: r.project_id,\n message: r.message,\n createdAt: r.created_at,\n }));\n }\n}\n","/**\n * Debug path schema initialization.\n *\n * Creates debug_paths and path_waypoints tables with indexes.\n * Uses CREATE TABLE IF NOT EXISTS for idempotent initialization\n * (same pattern as graph/schema.ts initGraphSchema).\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\n\nconst PATH_SCHEMA_DDL = `\n CREATE TABLE IF NOT EXISTS debug_paths (\n id TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'resolved', 'abandoned')),\n trigger_summary TEXT NOT NULL,\n resolution_summary TEXT,\n kiss_summary TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n resolved_at TEXT,\n project_hash TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS path_waypoints (\n id TEXT PRIMARY KEY,\n path_id TEXT NOT NULL REFERENCES debug_paths(id) ON DELETE CASCADE,\n observation_id TEXT,\n waypoint_type TEXT NOT NULL CHECK(waypoint_type IN ('error', 'attempt', 'failure', 'success', 'pivot', 'revert', 'discovery', 'resolution')),\n sequence_order INTEGER NOT NULL,\n summary TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_debug_paths_project_status\n ON debug_paths(project_hash, status);\n\n CREATE INDEX IF NOT EXISTS idx_debug_paths_started\n ON debug_paths(started_at DESC);\n\n CREATE INDEX IF NOT EXISTS idx_path_waypoints_path_order\n ON path_waypoints(path_id, sequence_order);\n`;\n\n/**\n * Initializes debug path tables if they do not exist.\n * Safe to call multiple times (all statements use IF NOT EXISTS).\n */\nexport function initPathSchema(db: BetterSqlite3.Database): void {\n db.exec(PATH_SCHEMA_DDL);\n}\n","/**\n * Repository for debug path CRUD operations.\n *\n * Every query is scoped to the projectHash provided at construction time.\n * All SQL statements are prepared once in the constructor and reused for\n * every call (same pattern as ObservationRepository).\n */\n\nimport type BetterSqlite3 from 'better-sqlite3';\nimport { randomBytes } from 'node:crypto';\n\nimport type { DebugPath, PathStatus, PathWaypoint, WaypointType } from './types.js';\n\nexport class PathRepository {\n private readonly db: BetterSqlite3.Database;\n private readonly projectHash: string;\n\n // Prepared statements — path lifecycle\n private readonly stmtCreatePath: BetterSqlite3.Statement;\n private readonly stmtResolvePath: BetterSqlite3.Statement;\n private readonly stmtAbandonPath: BetterSqlite3.Statement;\n private readonly stmtGetActivePath: BetterSqlite3.Statement;\n private readonly stmtGetPath: BetterSqlite3.Statement;\n private readonly stmtListPaths: BetterSqlite3.Statement;\n\n // Prepared statements — KISS summary\n private readonly stmtUpdateKiss: BetterSqlite3.Statement;\n\n // Prepared statements — cross-session linking\n private readonly stmtFindRecentActive: BetterSqlite3.Statement;\n private readonly stmtListByStatus: BetterSqlite3.Statement;\n\n // Prepared statements — waypoint management\n private readonly stmtAddWaypoint: BetterSqlite3.Statement;\n private readonly stmtGetWaypoints: BetterSqlite3.Statement;\n private readonly stmtCountWaypoints: BetterSqlite3.Statement;\n private readonly stmtMaxSequence: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database, projectHash: string) {\n this.db = db;\n this.projectHash = projectHash;\n\n // --- Path lifecycle statements ---\n\n this.stmtCreatePath = db.prepare(`\n INSERT INTO debug_paths (id, status, trigger_summary, started_at, project_hash)\n VALUES (?, 'active', ?, datetime('now'), ?)\n `);\n\n this.stmtResolvePath = db.prepare(`\n UPDATE debug_paths\n SET status = 'resolved', resolution_summary = ?, resolved_at = datetime('now')\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtAbandonPath = db.prepare(`\n UPDATE debug_paths\n SET status = 'abandoned', resolved_at = datetime('now')\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtGetActivePath = db.prepare(`\n SELECT * FROM debug_paths\n WHERE project_hash = ? AND status = 'active'\n ORDER BY started_at DESC\n LIMIT 1\n `);\n\n this.stmtGetPath = db.prepare(`\n SELECT * FROM debug_paths\n WHERE id = ? AND project_hash = ?\n `);\n\n this.stmtListPaths = db.prepare(`\n SELECT * FROM debug_paths\n WHERE project_hash = ?\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n // --- Cross-session linking statements ---\n\n this.stmtFindRecentActive = db.prepare(`\n SELECT * FROM debug_paths\n WHERE project_hash = ? AND status = 'active'\n AND started_at > datetime('now', '-24 hours')\n ORDER BY started_at DESC\n LIMIT 1\n `);\n\n this.stmtListByStatus = db.prepare(`\n SELECT * FROM debug_paths\n WHERE project_hash = ? AND status = ?\n ORDER BY started_at DESC\n LIMIT ?\n `);\n\n // --- KISS summary statement ---\n\n this.stmtUpdateKiss = db.prepare(`\n UPDATE debug_paths SET kiss_summary = ? WHERE id = ? AND project_hash = ?\n `);\n\n // --- Waypoint statements ---\n\n this.stmtAddWaypoint = db.prepare(`\n INSERT INTO path_waypoints (id, path_id, observation_id, waypoint_type, sequence_order, summary, created_at)\n VALUES (?, ?, ?, ?, ?, ?, datetime('now'))\n `);\n\n this.stmtGetWaypoints = db.prepare(`\n SELECT * FROM path_waypoints\n WHERE path_id = ?\n ORDER BY sequence_order ASC\n `);\n\n this.stmtCountWaypoints = db.prepare(`\n SELECT COUNT(*) AS count FROM path_waypoints\n WHERE path_id = ?\n `);\n\n this.stmtMaxSequence = db.prepare(`\n SELECT COALESCE(MAX(sequence_order), 0) AS max_seq FROM path_waypoints\n WHERE path_id = ?\n `);\n }\n\n // ===========================================================================\n // Path Lifecycle\n // ===========================================================================\n\n /**\n * Creates a new active debug path.\n * Generates a UUID id, sets status='active' and started_at=now.\n */\n createPath(triggerSummary: string): DebugPath {\n const id = randomBytes(16).toString('hex');\n this.stmtCreatePath.run(id, triggerSummary, this.projectHash);\n return this.getPath(id)!;\n }\n\n /**\n * Resolves a debug path with a resolution summary.\n * Sets status='resolved', resolved_at=now.\n */\n resolvePath(pathId: string, resolutionSummary: string): void {\n this.stmtResolvePath.run(resolutionSummary, pathId, this.projectHash);\n }\n\n /**\n * Abandons a debug path.\n * Sets status='abandoned', resolved_at=now.\n */\n abandonPath(pathId: string): void {\n this.stmtAbandonPath.run(pathId, this.projectHash);\n }\n\n /**\n * Returns the active path for this project (at most one active at a time).\n * Returns null if no active path exists.\n */\n getActivePath(): DebugPath | null {\n const row = this.stmtGetActivePath.get(this.projectHash) as DebugPathRow | undefined;\n return row ? rowToDebugPath(row) : null;\n }\n\n /**\n * Gets a debug path by ID, scoped to this project.\n * Returns null if not found.\n */\n getPath(pathId: string): DebugPath | null {\n const row = this.stmtGetPath.get(pathId, this.projectHash) as DebugPathRow | undefined;\n return row ? rowToDebugPath(row) : null;\n }\n\n /**\n * Lists recent paths for this project, ordered by started_at DESC.\n * Default limit is 20.\n */\n listPaths(limit: number = 20): DebugPath[] {\n const rows = this.stmtListPaths.all(this.projectHash, limit) as DebugPathRow[];\n return rows.map(rowToDebugPath);\n }\n\n /**\n * Finds a recently active path (started within the last 24 hours).\n * Used for cross-session path linking — detects paths that may need\n * continuation from a prior session.\n */\n findRecentActivePath(): DebugPath | null {\n const row = this.stmtFindRecentActive.get(this.projectHash) as DebugPathRow | undefined;\n return row ? rowToDebugPath(row) : null;\n }\n\n /**\n * Lists paths filtered by status, ordered by started_at DESC.\n * Useful for filtering to resolved/active/abandoned paths specifically.\n */\n listPathsByStatus(status: PathStatus, limit: number = 20): DebugPath[] {\n const rows = this.stmtListByStatus.all(this.projectHash, status, limit) as DebugPathRow[];\n return rows.map(rowToDebugPath);\n }\n\n // ===========================================================================\n // KISS Summary\n // ===========================================================================\n\n /**\n * Updates the kiss_summary column for a resolved debug path.\n * Stores the full KissSummary JSON string.\n */\n updateKissSummary(pathId: string, kissSummary: string): void {\n this.stmtUpdateKiss.run(kissSummary, pathId, this.projectHash);\n }\n\n // ===========================================================================\n // Waypoint Management\n // ===========================================================================\n\n /**\n * Adds a waypoint to a debug path.\n * Auto-increments sequence_order based on existing waypoints.\n */\n addWaypoint(\n pathId: string,\n type: WaypointType,\n summary: string,\n observationId?: string,\n ): PathWaypoint {\n const id = randomBytes(16).toString('hex');\n const { max_seq } = this.stmtMaxSequence.get(pathId) as { max_seq: number };\n const sequenceOrder = max_seq + 1;\n\n this.stmtAddWaypoint.run(\n id,\n pathId,\n observationId ?? null,\n type,\n sequenceOrder,\n summary,\n );\n\n return this.getWaypoints(pathId).find(w => w.id === id)!;\n }\n\n /**\n * Returns all waypoints for a path, ordered by sequence_order ASC.\n */\n getWaypoints(pathId: string): PathWaypoint[] {\n const rows = this.stmtGetWaypoints.all(pathId) as PathWaypointRow[];\n return rows.map(rowToPathWaypoint);\n }\n\n /**\n * Counts waypoints for a path. Used for cap enforcement (max 30 per path).\n */\n countWaypoints(pathId: string): number {\n const row = this.stmtCountWaypoints.get(pathId) as { count: number };\n return row.count;\n }\n}\n\n// =============================================================================\n// Raw Row Types (snake_case, matches SQL columns)\n// =============================================================================\n\ninterface DebugPathRow {\n id: string;\n status: string;\n trigger_summary: string;\n resolution_summary: string | null;\n kiss_summary: string | null;\n started_at: string;\n resolved_at: string | null;\n project_hash: string;\n}\n\ninterface PathWaypointRow {\n id: string;\n path_id: string;\n observation_id: string | null;\n waypoint_type: string;\n sequence_order: number;\n summary: string;\n created_at: string;\n}\n\n// =============================================================================\n// Row Mapping\n// =============================================================================\n\nfunction rowToDebugPath(row: DebugPathRow): DebugPath {\n return {\n id: row.id,\n status: row.status as DebugPath['status'],\n trigger_summary: row.trigger_summary,\n resolution_summary: row.resolution_summary,\n kiss_summary: row.kiss_summary,\n started_at: row.started_at,\n resolved_at: row.resolved_at,\n project_hash: row.project_hash,\n };\n}\n\nfunction rowToPathWaypoint(row: PathWaypointRow): PathWaypoint {\n return {\n id: row.id,\n path_id: row.path_id,\n observation_id: row.observation_id,\n waypoint_type: row.waypoint_type as PathWaypoint['waypoint_type'],\n sequence_order: row.sequence_order,\n summary: row.summary,\n created_at: row.created_at,\n };\n}\n","import type BetterSqlite3 from 'better-sqlite3';\n\nimport { debug } from '../shared/debug.js';\nimport type { DiscoveredTool, ToolRegistryRow, ToolSearchResult, ToolUsageStats } from '../shared/tool-types.js';\nimport { reciprocalRankFusion } from '../search/hybrid.js';\n\n/**\n * Repository for tool registry CRUD operations.\n *\n * Unlike ObservationRepository, this is NOT scoped to a single project --\n * the tool registry spans all scopes (global, project, plugin) and is\n * queried cross-project for tool discovery and routing.\n *\n * All SQL statements are prepared once in the constructor and reused for\n * every call (better-sqlite3 performance best practice).\n */\nexport class ToolRegistryRepository {\n private readonly db: BetterSqlite3.Database;\n\n // Prepared statements (prepared once, reused for every call)\n private readonly stmtUpsert: BetterSqlite3.Statement;\n private readonly stmtRecordUsage: BetterSqlite3.Statement;\n private readonly stmtGetByScope: BetterSqlite3.Statement;\n private readonly stmtGetByName: BetterSqlite3.Statement;\n private readonly stmtGetAll: BetterSqlite3.Statement;\n private readonly stmtCount: BetterSqlite3.Statement;\n private readonly stmtGetAvailableForSession: BetterSqlite3.Statement;\n private readonly stmtInsertEvent: BetterSqlite3.Statement;\n private readonly stmtGetUsageForTool: BetterSqlite3.Statement;\n private readonly stmtGetUsageForSession: BetterSqlite3.Statement;\n private readonly stmtGetUsageSince: BetterSqlite3.Statement;\n private readonly stmtGetRecentUsage: BetterSqlite3.Statement;\n private readonly stmtMarkStale: BetterSqlite3.Statement;\n private readonly stmtMarkDemoted: BetterSqlite3.Statement;\n private readonly stmtMarkActive: BetterSqlite3.Statement;\n private readonly stmtGetConfigSourced: BetterSqlite3.Statement;\n private readonly stmtGetRecentEventsForTool: BetterSqlite3.Statement;\n\n constructor(db: BetterSqlite3.Database) {\n this.db = db;\n\n try {\n this.stmtUpsert = db.prepare(`\n INSERT INTO tool_registry (name, tool_type, scope, source, project_hash, description, server_name, trigger_hints, discovered_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))\n ON CONFLICT (name, COALESCE(project_hash, ''))\n DO UPDATE SET\n description = COALESCE(excluded.description, tool_registry.description),\n trigger_hints = COALESCE(excluded.trigger_hints, tool_registry.trigger_hints),\n source = excluded.source,\n status = 'active',\n updated_at = datetime('now')\n `);\n\n this.stmtRecordUsage = db.prepare(`\n UPDATE tool_registry\n SET usage_count = usage_count + 1,\n last_used_at = datetime('now'),\n updated_at = datetime('now')\n WHERE name = ? AND COALESCE(project_hash, '') = COALESCE(?, '')\n `);\n\n this.stmtGetByScope = db.prepare(`\n SELECT * FROM tool_registry\n WHERE scope = 'global' OR project_hash = ?\n ORDER BY usage_count DESC, discovered_at DESC\n `);\n\n this.stmtGetByName = db.prepare(`\n SELECT * FROM tool_registry\n WHERE name = ?\n ORDER BY usage_count DESC\n LIMIT 1\n `);\n\n this.stmtGetAll = db.prepare(`\n SELECT * FROM tool_registry\n ORDER BY usage_count DESC, discovered_at DESC\n `);\n\n this.stmtCount = db.prepare(`\n SELECT COUNT(*) AS count FROM tool_registry\n `);\n\n this.stmtGetAvailableForSession = db.prepare(`\n SELECT * FROM tool_registry\n WHERE\n scope = 'global'\n OR (scope = 'project' AND project_hash = ?)\n OR (scope = 'plugin' AND (project_hash IS NULL OR project_hash = ?))\n ORDER BY\n CASE status\n WHEN 'active' THEN 0\n WHEN 'stale' THEN 1\n WHEN 'demoted' THEN 2\n ELSE 3\n END,\n CASE tool_type\n WHEN 'mcp_server' THEN 0\n WHEN 'slash_command' THEN 1\n WHEN 'skill' THEN 2\n WHEN 'plugin' THEN 3\n ELSE 4\n END,\n usage_count DESC,\n discovered_at DESC\n `);\n\n this.stmtInsertEvent = db.prepare(`\n INSERT INTO tool_usage_events (tool_name, session_id, project_hash, success)\n VALUES (?, ?, ?, ?)\n `);\n\n this.stmtGetUsageForTool = db.prepare(`\n SELECT tool_name, COUNT(*) as usage_count, MAX(created_at) as last_used\n FROM tool_usage_events\n WHERE tool_name = ? AND project_hash = ?\n AND created_at >= datetime('now', ?)\n GROUP BY tool_name\n `);\n\n this.stmtGetUsageForSession = db.prepare(`\n SELECT tool_name, COUNT(*) as usage_count, MAX(created_at) as last_used\n FROM tool_usage_events\n WHERE session_id = ?\n GROUP BY tool_name\n ORDER BY usage_count DESC\n `);\n\n this.stmtGetUsageSince = db.prepare(`\n SELECT tool_name, COUNT(*) as usage_count, MAX(created_at) as last_used\n FROM tool_usage_events\n WHERE project_hash = ?\n AND created_at >= datetime('now', ?)\n GROUP BY tool_name\n ORDER BY usage_count DESC\n `);\n\n this.stmtGetRecentUsage = db.prepare(`\n SELECT tool_name, COUNT(*) as usage_count, MAX(created_at) as last_used\n FROM (\n SELECT tool_name, created_at\n FROM tool_usage_events\n WHERE project_hash = ?\n ORDER BY created_at DESC\n LIMIT ?\n )\n GROUP BY tool_name\n ORDER BY usage_count DESC\n `);\n\n this.stmtMarkStale = db.prepare(`\n UPDATE tool_registry\n SET status = 'stale', updated_at = datetime('now')\n WHERE name = ? AND COALESCE(project_hash, '') = COALESCE(?, '')\n AND status != 'stale'\n `);\n\n this.stmtMarkDemoted = db.prepare(`\n UPDATE tool_registry\n SET status = 'demoted', updated_at = datetime('now')\n WHERE name = ? AND COALESCE(project_hash, '') = COALESCE(?, '')\n `);\n\n this.stmtMarkActive = db.prepare(`\n UPDATE tool_registry\n SET status = 'active', updated_at = datetime('now')\n WHERE name = ? AND COALESCE(project_hash, '') = COALESCE(?, '')\n AND status != 'active'\n `);\n\n this.stmtGetConfigSourced = db.prepare(`\n SELECT * FROM tool_registry\n WHERE source LIKE 'config:%'\n AND status = 'active'\n AND (project_hash = ? OR project_hash IS NULL)\n `);\n\n this.stmtGetRecentEventsForTool = db.prepare(`\n SELECT success FROM tool_usage_events\n WHERE tool_name = ? AND project_hash = ?\n ORDER BY created_at DESC\n LIMIT ?\n `);\n\n debug('tool-registry', 'ToolRegistryRepository initialized');\n } catch (err) {\n // Table may not exist if database is pre-migration-16.\n // Callers should catch this gracefully.\n throw err;\n }\n }\n\n /**\n * Inserts or updates a discovered tool in the registry.\n * On conflict (same name + project_hash), updates description and source.\n */\n upsert(tool: DiscoveredTool): void {\n try {\n this.stmtUpsert.run(\n tool.name,\n tool.toolType,\n tool.scope,\n tool.source,\n tool.projectHash,\n tool.description,\n tool.serverName,\n tool.triggerHints,\n );\n debug('tool-registry', 'Upserted tool', { name: tool.name, scope: tool.scope });\n } catch (err) {\n debug('tool-registry', 'Failed to upsert tool', { name: tool.name, error: String(err) });\n }\n }\n\n /**\n * Increments usage_count and updates last_used_at for a tool.\n * Called from organic PostToolUse discovery to track usage.\n */\n recordUsage(name: string, projectHash: string | null): void {\n try {\n this.stmtRecordUsage.run(name, projectHash);\n debug('tool-registry', 'Recorded usage', { name });\n } catch (err) {\n debug('tool-registry', 'Failed to record usage', { name, error: String(err) });\n }\n }\n\n /**\n * Records usage for an existing tool, or creates it if not yet in the registry.\n * This is the entry point for organic discovery -- an upsert-and-increment-if-exists pattern.\n *\n * First tries recordUsage. If the tool is not in the registry (changes === 0),\n * calls upsert with the full tool info, which initializes it with usage_count = 0.\n */\n recordOrCreate(\n name: string,\n defaults: Omit<DiscoveredTool, 'name'>,\n sessionId?: string | null,\n success?: boolean,\n ): void {\n try {\n const result = this.stmtRecordUsage.run(name, defaults.projectHash);\n if (result.changes === 0) {\n // Tool not yet in registry -- create it\n this.upsert({ name, ...defaults });\n }\n // Insert usage event with session context (UTRK-02)\n if (sessionId !== undefined) {\n this.stmtInsertEvent.run(name, sessionId, defaults.projectHash, success === false ? 0 : 1);\n }\n debug('tool-registry', 'recordOrCreate completed', { name, created: result.changes === 0 });\n } catch (err) {\n debug('tool-registry', 'Failed recordOrCreate', { name, error: String(err) });\n }\n }\n\n /**\n * Returns global tools plus project-specific tools for the given project.\n */\n getForProject(projectHash: string): ToolRegistryRow[] {\n return this.stmtGetByScope.all(projectHash) as ToolRegistryRow[];\n }\n\n /**\n * Returns tools available in the resolved scope for a given project.\n * Implements SCOP-01/SCOP-02/SCOP-03 scope resolution rules.\n */\n getAvailableForSession(projectHash: string): ToolRegistryRow[] {\n return this.stmtGetAvailableForSession.all(projectHash, projectHash) as ToolRegistryRow[];\n }\n\n /**\n * Returns the top-usage entry for a given tool name.\n */\n getByName(name: string): ToolRegistryRow | null {\n const row = this.stmtGetByName.get(name) as ToolRegistryRow | undefined;\n return row ?? null;\n }\n\n /**\n * Returns all tools in the registry (for debugging/admin).\n */\n getAll(): ToolRegistryRow[] {\n return this.stmtGetAll.all() as ToolRegistryRow[];\n }\n\n /**\n * Returns total number of tools in the registry.\n */\n count(): number {\n const row = this.stmtCount.get() as { count: number };\n return row.count;\n }\n\n /**\n * Returns usage stats for a specific tool within a time window.\n * @param timeModifier - SQLite datetime modifier, e.g., '-7 days', '-30 days'\n */\n getUsageForTool(toolName: string, projectHash: string, timeModifier: string = '-7 days'): ToolUsageStats | null {\n const row = this.stmtGetUsageForTool.get(toolName, projectHash, timeModifier) as ToolUsageStats | undefined;\n return row ?? null;\n }\n\n /**\n * Returns per-tool usage stats for a specific session.\n */\n getUsageForSession(sessionId: string): ToolUsageStats[] {\n return this.stmtGetUsageForSession.all(sessionId) as ToolUsageStats[];\n }\n\n /**\n * Returns per-tool usage stats since a time offset for a project.\n * @param timeModifier - SQLite datetime modifier, e.g., '-7 days', '-30 days'\n */\n getUsageSince(projectHash: string, timeModifier: string = '-7 days'): ToolUsageStats[] {\n return this.stmtGetUsageSince.all(projectHash, timeModifier) as ToolUsageStats[];\n }\n\n /**\n * Returns per-tool usage stats from the last N events for a project.\n * Event-count-based window instead of time-based — immune to usage gaps.\n * @param limit - Number of recent events to consider (default 200)\n */\n getRecentUsage(projectHash: string, limit: number = 200): ToolUsageStats[] {\n return this.stmtGetRecentUsage.all(projectHash, limit) as ToolUsageStats[];\n }\n\n // ---------------------------------------------------------------------------\n // Staleness management methods\n // ---------------------------------------------------------------------------\n\n /**\n * Marks a tool as stale (no longer in config but still in registry).\n * Idempotent -- no-op if already stale.\n */\n markStale(name: string, projectHash: string | null): void {\n try {\n this.stmtMarkStale.run(name, projectHash);\n debug('tool-registry', 'Marked tool stale', { name });\n } catch (err) {\n debug('tool-registry', 'Failed to mark tool stale', { name, error: String(err) });\n }\n }\n\n /**\n * Marks a tool as demoted (high failure rate detected).\n */\n markDemoted(name: string, projectHash: string | null): void {\n try {\n this.stmtMarkDemoted.run(name, projectHash);\n debug('tool-registry', 'Marked tool demoted', { name });\n } catch (err) {\n debug('tool-registry', 'Failed to mark tool demoted', { name, error: String(err) });\n }\n }\n\n /**\n * Marks a tool as active (restored from stale/demoted).\n * Idempotent -- no-op if already active.\n */\n markActive(name: string, projectHash: string | null): void {\n try {\n this.stmtMarkActive.run(name, projectHash);\n debug('tool-registry', 'Marked tool active', { name });\n } catch (err) {\n debug('tool-registry', 'Failed to mark tool active', { name, error: String(err) });\n }\n }\n\n /**\n * Returns all config-sourced active tools for a given project (or global).\n * Used by staleness detection to compare against current config state.\n */\n getConfigSourcedTools(projectHash: string): ToolRegistryRow[] {\n try {\n return this.stmtGetConfigSourced.all(projectHash) as ToolRegistryRow[];\n } catch (err) {\n debug('tool-registry', 'Failed to get config-sourced tools', { error: String(err) });\n return [];\n }\n }\n\n /**\n * Returns recent success/failure events for a specific tool.\n * Used by failure-driven demotion to check failure rate.\n * @param limit - Number of recent events to check (default 5)\n */\n getRecentEventsForTool(toolName: string, projectHash: string, limit: number = 5): Array<{ success: number }> {\n try {\n return this.stmtGetRecentEventsForTool.all(toolName, projectHash, limit) as Array<{ success: number }>;\n } catch (err) {\n debug('tool-registry', 'Failed to get recent events for tool', { toolName, error: String(err) });\n return [];\n }\n }\n\n // ---------------------------------------------------------------------------\n // Search methods (FTS5 + vector + hybrid)\n // ---------------------------------------------------------------------------\n\n /**\n * Sanitizes a user query for safe FTS5 MATCH usage.\n * Removes FTS5 operators and special characters to prevent syntax errors.\n * Returns null if the query is empty after sanitization.\n */\n private sanitizeQuery(query: string): string | null {\n const words = query.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return null;\n const sanitized = words\n .map(w => {\n let cleaned = w.replace(/[\"*()^{}[\\]]/g, '');\n if (/^(NEAR|OR|AND|NOT)$/i.test(cleaned)) return '';\n cleaned = cleaned.replace(/[^\\w\\-]/g, '');\n return cleaned;\n })\n .filter(Boolean);\n if (sanitized.length === 0) return null;\n return sanitized.join(' ');\n }\n\n /**\n * FTS5 keyword search on tool_registry_fts (name + description).\n * Returns ranked results using BM25 with name weighted 2x over description.\n */\n searchByKeyword(query: string, options?: { scope?: string; limit?: number }): ToolSearchResult[] {\n const sanitized = this.sanitizeQuery(query);\n if (!sanitized) return [];\n const limit = options?.limit ?? 20;\n\n let sql = `\n SELECT tr.*, bm25(tool_registry_fts, 2.0, 1.0) AS rank\n FROM tool_registry_fts\n JOIN tool_registry tr ON tr.id = tool_registry_fts.rowid\n WHERE tool_registry_fts MATCH ?\n `;\n const params: unknown[] = [sanitized];\n\n if (options?.scope) {\n sql += ' AND tr.scope = ?';\n params.push(options.scope);\n }\n\n sql += ' ORDER BY rank LIMIT ?';\n params.push(limit);\n\n try {\n const rows = this.db.prepare(sql).all(...params) as (ToolRegistryRow & { rank: number })[];\n return rows.map(({ rank, ...toolFields }) => ({\n tool: toolFields as ToolRegistryRow,\n score: Math.abs(rank),\n matchType: 'fts' as const,\n }));\n } catch (err) {\n debug('tool-registry', 'FTS5 search failed', { error: String(err) });\n return [];\n }\n }\n\n /**\n * Vector similarity search on tool_registry_embeddings using vec0 KNN.\n * Returns tool IDs and distances sorted by cosine similarity.\n */\n searchByVector(queryEmbedding: Float32Array, options?: { scope?: string; limit?: number }): Array<{ tool_id: number; distance: number }> {\n const limit = options?.limit ?? 40;\n try {\n let sql: string;\n const params: unknown[] = [queryEmbedding];\n\n if (options?.scope) {\n sql = `\n SELECT tre.tool_id, tre.distance\n FROM tool_registry_embeddings tre\n JOIN tool_registry tr ON tr.id = tre.tool_id\n WHERE tre.embedding MATCH ? AND tr.scope = ?\n ORDER BY tre.distance LIMIT ?\n `;\n params.push(options.scope);\n } else {\n sql = `\n SELECT tre.tool_id, tre.distance\n FROM tool_registry_embeddings tre\n WHERE tre.embedding MATCH ?\n ORDER BY tre.distance LIMIT ?\n `;\n }\n\n params.push(limit);\n return this.db.prepare(sql).all(...params) as Array<{ tool_id: number; distance: number }>;\n } catch (err) {\n debug('tool-registry', 'Vector search failed', { error: String(err) });\n return [];\n }\n }\n\n /**\n * Hybrid search combining FTS5 keyword and vec0 vector results via\n * reciprocal rank fusion (RRF). Falls back to FTS5-only when vector\n * search is unavailable (no worker, no sqlite-vec, no embeddings).\n */\n async searchTools(\n query: string,\n options?: {\n scope?: string;\n limit?: number;\n worker?: { isReady(): boolean; embed(text: string): Promise<Float32Array | null> } | null;\n hasVectorSupport?: boolean;\n },\n ): Promise<ToolSearchResult[]> {\n const limit = options?.limit ?? 20;\n\n // Step 1: FTS5 keyword search\n const ftsResults = this.searchByKeyword(query, { scope: options?.scope, limit });\n\n // Step 2: Vector search (if available)\n let vectorResults: Array<{ tool_id: number; distance: number }> = [];\n if (options?.worker?.isReady() && options?.hasVectorSupport) {\n const queryEmbedding = await options.worker.embed(query);\n if (queryEmbedding) {\n vectorResults = this.searchByVector(queryEmbedding, { scope: options?.scope, limit: limit * 2 });\n }\n }\n\n // Step 3: FTS-only fallback\n if (vectorResults.length === 0) {\n return ftsResults.slice(0, limit);\n }\n\n // Step 4: Fuse with RRF\n const ftsRanked = ftsResults.map(r => ({ id: String(r.tool.id) }));\n const vecRanked = vectorResults.map(r => ({ id: String(r.tool_id) }));\n const fused = reciprocalRankFusion([ftsRanked, vecRanked]);\n\n // Build lookup maps\n const ftsMap = new Map<string, ToolSearchResult>();\n for (const r of ftsResults) {\n ftsMap.set(String(r.tool.id), r);\n }\n const vecIds = new Set(vectorResults.map(r => String(r.tool_id)));\n\n // Assemble results\n const results: ToolSearchResult[] = [];\n for (const item of fused) {\n if (results.length >= limit) break;\n const fromFts = ftsMap.get(item.id);\n const fromVec = vecIds.has(item.id);\n\n if (fromFts) {\n results.push({\n tool: fromFts.tool,\n score: item.fusedScore,\n matchType: fromFts && fromVec ? 'hybrid' : 'fts',\n });\n } else if (fromVec) {\n // Vector-only: look up the full tool row\n const toolRow = this.db.prepare('SELECT * FROM tool_registry WHERE id = ?').get(Number(item.id)) as ToolRegistryRow | undefined;\n if (toolRow) {\n results.push({\n tool: toolRow,\n score: item.fusedScore,\n matchType: 'vector',\n });\n }\n }\n }\n\n return results;\n }\n\n /**\n * Stores an embedding vector for a tool in tool_registry_embeddings.\n * Used by the background embedding loop to index tool descriptions.\n */\n storeEmbedding(toolId: number, embedding: Float32Array): void {\n try {\n this.db.prepare(\n 'INSERT OR REPLACE INTO tool_registry_embeddings(tool_id, embedding) VALUES (?, ?)'\n ).run(toolId, embedding);\n } catch (err) {\n debug('tool-registry', 'Failed to store tool embedding', { toolId, error: String(err) });\n }\n }\n\n /**\n * Returns tools that have descriptions but no embedding yet.\n * Used by the background embedding loop to find work.\n */\n findUnembeddedTools(limit: number = 5): Array<{ id: number; name: string; description: string }> {\n try {\n return this.db.prepare(`\n SELECT id, name, description FROM tool_registry\n WHERE description IS NOT NULL\n AND id NOT IN (SELECT tool_id FROM tool_registry_embeddings)\n LIMIT ?\n `).all(limit) as Array<{ id: number; name: string; description: string }>;\n } catch (err) {\n debug('tool-registry', 'Failed to find unembedded tools', { error: String(err) });\n return [];\n }\n }\n}\n"],"mappings":"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"}
|