@dikolab/kbdb 0.1.0
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/LICENSE +15 -0
- package/README.md +270 -0
- package/dist/chunk-QCCN7OZH.mjs +82 -0
- package/dist/chunk-QCCN7OZH.mjs.map +7 -0
- package/dist/cli.cjs +3598 -0
- package/dist/cli.cjs.map +7 -0
- package/dist/cli.mjs +3537 -0
- package/dist/cli.mjs.map +7 -0
- package/dist/kbdb-worker.cjs +1659 -0
- package/dist/kbdb-worker.cjs.map +7 -0
- package/dist/mod.cjs +538 -0
- package/dist/mod.cjs.map +7 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.mjs +507 -0
- package/dist/mod.mjs.map +7 -0
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/shared/cli/constants/defaults.constant.d.ts +11 -0
- package/dist/src/shared/cli/constants/help-text.constant.d.ts +2 -0
- package/dist/src/shared/cli/functions/dispatch-command.function.d.ts +37 -0
- package/dist/src/shared/cli/functions/ensure-db.function.d.ts +11 -0
- package/dist/src/shared/cli/functions/error-to-message.function.d.ts +7 -0
- package/dist/src/shared/cli/functions/find-db.function.d.ts +13 -0
- package/dist/src/shared/cli/functions/format-output.function.d.ts +15 -0
- package/dist/src/shared/cli/functions/generate-help.function.d.ts +31 -0
- package/dist/src/shared/cli/functions/is-stdin-tty.function.d.ts +7 -0
- package/dist/src/shared/cli/functions/parse-args.function.d.ts +25 -0
- package/dist/src/shared/cli/functions/prompt-user.function.d.ts +13 -0
- package/dist/src/shared/cli/functions/run-agent-create.function.d.ts +58 -0
- package/dist/src/shared/cli/functions/run-agent-delete.function.d.ts +32 -0
- package/dist/src/shared/cli/functions/run-agent-get.function.d.ts +46 -0
- package/dist/src/shared/cli/functions/run-agent-list.function.d.ts +45 -0
- package/dist/src/shared/cli/functions/run-check.function.d.ts +64 -0
- package/dist/src/shared/cli/functions/run-cli.function.d.ts +39 -0
- package/dist/src/shared/cli/functions/run-content.function.d.ts +40 -0
- package/dist/src/shared/cli/functions/run-db-init.function.d.ts +23 -0
- package/dist/src/shared/cli/functions/run-db-migrate.function.d.ts +32 -0
- package/dist/src/shared/cli/functions/run-gc.function.d.ts +38 -0
- package/dist/src/shared/cli/functions/run-init.function.d.ts +27 -0
- package/dist/src/shared/cli/functions/run-learn.function.d.ts +46 -0
- package/dist/src/shared/cli/functions/run-migrate.function.d.ts +57 -0
- package/dist/src/shared/cli/functions/run-rebuild.function.d.ts +40 -0
- package/dist/src/shared/cli/functions/run-search.function.d.ts +39 -0
- package/dist/src/shared/cli/functions/run-skill-delete.function.d.ts +30 -0
- package/dist/src/shared/cli/functions/run-skill-get.function.d.ts +49 -0
- package/dist/src/shared/cli/functions/run-skill-learn.function.d.ts +36 -0
- package/dist/src/shared/cli/functions/run-skill-list.function.d.ts +43 -0
- package/dist/src/shared/cli/functions/run-status.function.d.ts +22 -0
- package/dist/src/shared/cli/functions/run-unlearn.function.d.ts +45 -0
- package/dist/src/shared/cli/index.d.ts +35 -0
- package/dist/src/shared/cli/typings/cli-options.interface.d.ts +53 -0
- package/dist/src/shared/cli/typings/command-result.model.d.ts +15 -0
- package/dist/src/shared/cli/typings/learn-result.model.d.ts +11 -0
- package/dist/src/shared/cli/typings/search-display.model.d.ts +17 -0
- package/dist/src/shared/dir-resolver/functions/resolve-base-dir.function.d.ts +3 -0
- package/dist/src/shared/dir-resolver/functions/resolve-wasm-dir.function.d.ts +1 -0
- package/dist/src/shared/dir-resolver/functions/resolve-worker-script.function.d.ts +2 -0
- package/dist/src/shared/dir-resolver/index.d.ts +4 -0
- package/dist/src/shared/dir-resolver/typings/base-dir.interface.d.ts +4 -0
- package/dist/src/shared/hash/functions/compute-sha256.d.ts +10 -0
- package/dist/src/shared/hash/index.d.ts +1 -0
- package/dist/src/shared/mcp/classes/mcp-server.class.d.ts +55 -0
- package/dist/src/shared/mcp/constants/mcp-error-codes.constant.d.ts +26 -0
- package/dist/src/shared/mcp/functions/create-mcp-server.function.d.ts +11 -0
- package/dist/src/shared/mcp/functions/create-prompt-definitions.function.d.ts +41 -0
- package/dist/src/shared/mcp/functions/create-resource-templates.function.d.ts +7 -0
- package/dist/src/shared/mcp/functions/create-tool-definitions.function.d.ts +7 -0
- package/dist/src/shared/mcp/functions/extract-skill-arguments.function.d.ts +13 -0
- package/dist/src/shared/mcp/functions/handle-agent-create.function.d.ts +29 -0
- package/dist/src/shared/mcp/functions/handle-agent-delete.function.d.ts +28 -0
- package/dist/src/shared/mcp/functions/handle-agent-get.function.d.ts +29 -0
- package/dist/src/shared/mcp/functions/handle-agent-list.function.d.ts +31 -0
- package/dist/src/shared/mcp/functions/handle-completion.function.d.ts +58 -0
- package/dist/src/shared/mcp/functions/handle-prompt-get.function.d.ts +23 -0
- package/dist/src/shared/mcp/functions/handle-resource-read.function.d.ts +26 -0
- package/dist/src/shared/mcp/functions/handle-roots-list.function.d.ts +21 -0
- package/dist/src/shared/mcp/functions/handle-tool-call.function.d.ts +26 -0
- package/dist/src/shared/mcp/functions/parse-skill-content.function.d.ts +15 -0
- package/dist/src/shared/mcp/functions/serialize-skill-content.function.d.ts +9 -0
- package/dist/src/shared/mcp/functions/should-emit-log.function.d.ts +20 -0
- package/dist/src/shared/mcp/index.d.ts +9 -0
- package/dist/src/shared/mcp/typings/agent-types.interface.d.ts +38 -0
- package/dist/src/shared/mcp/typings/log-types.interface.d.ts +17 -0
- package/dist/src/shared/mcp/typings/mcp-client.interface.d.ts +217 -0
- package/dist/src/shared/mcp/typings/mcp-types.interface.d.ts +149 -0
- package/dist/src/shared/mcp/typings/prompt-types.interface.d.ts +37 -0
- package/dist/src/shared/mcp/typings/remove-section-result.model.d.ts +10 -0
- package/dist/src/shared/mcp/typings/sampling-types.interface.d.ts +46 -0
- package/dist/src/shared/mcp/typings/skill-types.interface.d.ts +28 -0
- package/dist/src/shared/mod.d.ts +1 -0
- package/dist/src/shared/platform/functions/get-ipc-path.function.d.ts +11 -0
- package/dist/src/shared/platform/functions/get-tmpdir.function.d.ts +4 -0
- package/dist/src/shared/platform/functions/is-process-alive.function.d.ts +10 -0
- package/dist/src/shared/platform/index.d.ts +3 -0
- package/dist/src/shared/runtime/functions/detect-runtime.d.ts +8 -0
- package/dist/src/shared/runtime/functions/get-args.d.ts +7 -0
- package/dist/src/shared/runtime/index.d.ts +3 -0
- package/dist/src/shared/runtime/typings/runtime.d.ts +2 -0
- package/dist/src/shared/version/constants/version.constant.d.ts +2 -0
- package/dist/src/shared/version/index.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/decode-compose-output.function.d.ts +5 -0
- package/dist/src/shared/wasm-codec/functions/decode-document-manifest-list.function.d.ts +14 -0
- package/dist/src/shared/wasm-codec/functions/decode-document-manifest.function.d.ts +40 -0
- package/dist/src/shared/wasm-codec/functions/decode-f32.function.d.ts +2 -0
- package/dist/src/shared/wasm-codec/functions/decode-key-value-text.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/decode-remove-flag.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/decode-scored-results.function.d.ts +10 -0
- package/dist/src/shared/wasm-codec/functions/decode-section-record-list.function.d.ts +13 -0
- package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +50 -0
- package/dist/src/shared/wasm-codec/functions/decode-string.function.d.ts +5 -0
- package/dist/src/shared/wasm-codec/functions/decode-u32.function.d.ts +2 -0
- package/dist/src/shared/wasm-codec/functions/decode-u64.function.d.ts +2 -0
- package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +10 -0
- package/dist/src/shared/wasm-codec/functions/encode-group-params.function.d.ts +10 -0
- package/dist/src/shared/wasm-codec/functions/encode-identifier-list.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-kbid-list.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-option-string.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-search-params.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-section-type.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-string.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-type-filter-param.function.d.ts +11 -0
- package/dist/src/shared/wasm-codec/functions/encode-u32.function.d.ts +1 -0
- package/dist/src/shared/wasm-codec/functions/encode-update-section-params.function.d.ts +2 -0
- package/dist/src/shared/wasm-codec/index.d.ts +29 -0
- package/dist/src/shared/worker-client/classes/worker-client.class.d.ts +230 -0
- package/dist/src/shared/worker-client/functions/compute-context-id.function.d.ts +11 -0
- package/dist/src/shared/worker-client/functions/create-worker-client.function.d.ts +18 -0
- package/dist/src/shared/worker-client/functions/discover-daemon.function.d.ts +14 -0
- package/dist/src/shared/worker-client/functions/resolve-db-path.function.d.ts +11 -0
- package/dist/src/shared/worker-client/functions/spawn-daemon.function.d.ts +11 -0
- package/dist/src/shared/worker-client/functions/wait-for-daemon.function.d.ts +13 -0
- package/dist/src/shared/worker-client/index.d.ts +22 -0
- package/dist/src/shared/worker-client/typings/add-section-result.model.d.ts +22 -0
- package/dist/src/shared/worker-client/typings/content-result.model.d.ts +12 -0
- package/dist/src/shared/worker-client/typings/daemon-info.model.d.ts +7 -0
- package/dist/src/shared/worker-client/typings/gc-result.model.d.ts +12 -0
- package/dist/src/shared/worker-client/typings/integrity-check-result.model.d.ts +36 -0
- package/dist/src/shared/worker-client/typings/migrate-result.model.d.ts +11 -0
- package/dist/src/shared/worker-client/typings/rebuild-result.model.d.ts +12 -0
- package/dist/src/shared/worker-client/typings/remove-section-result.model.d.ts +7 -0
- package/dist/src/shared/worker-client/typings/search-params.model.d.ts +12 -0
- package/dist/src/shared/worker-client/typings/search-result.model.d.ts +14 -0
- package/dist/src/shared/worker-client/typings/section.model.d.ts +26 -0
- package/dist/src/shared/worker-client/typings/status-result.model.d.ts +14 -0
- package/dist/src/shared/worker-client/typings/version-status.model.d.ts +24 -0
- package/dist/src/shared/worker-client/typings/worker-client-error.interface.d.ts +8 -0
- package/dist/src/shared/worker-client/typings/worker-client-options.interface.d.ts +30 -0
- package/dist/src/shared/worker-daemon/classes/worker-daemon.class.d.ts +147 -0
- package/dist/src/shared/worker-daemon/constants/daemon-defaults.constant.d.ts +24 -0
- package/dist/src/shared/worker-daemon/functions/create-host-imports.function.d.ts +68 -0
- package/dist/src/shared/worker-daemon/functions/create-ipc-server.function.d.ts +18 -0
- package/dist/src/shared/worker-daemon/functions/load-wasm-modules.function.d.ts +19 -0
- package/dist/src/shared/worker-daemon/functions/read-config.function.d.ts +12 -0
- package/dist/src/shared/worker-daemon/functions/run-worker.function.d.ts +26 -0
- package/dist/src/shared/worker-daemon/functions/start-daemon.function.d.ts +13 -0
- package/dist/src/shared/worker-daemon/index.d.ts +9 -0
- package/dist/src/shared/worker-daemon/typings/daemon-config.interface.d.ts +13 -0
- package/dist/src/shared/worker-daemon/typings/ipc-handler.interface.d.ts +36 -0
- package/dist/src/shared/worker-daemon/typings/wasm-modules.interface.d.ts +7 -0
- package/dist/src/worker.d.ts +1 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/worker.mjs +1615 -0
- package/dist/worker.mjs.map +7 -0
- package/mod.ts +17 -0
- package/package.json +85 -0
- package/src/cli.ts +62 -0
- package/src/shared/cli/constants/defaults.constant.ts +19 -0
- package/src/shared/cli/constants/help-text.constant.ts +4 -0
- package/src/shared/cli/functions/dispatch-command.function.ts +338 -0
- package/src/shared/cli/functions/ensure-db.function.ts +21 -0
- package/src/shared/cli/functions/error-to-message.function.ts +9 -0
- package/src/shared/cli/functions/find-db.function.ts +20 -0
- package/src/shared/cli/functions/format-output.function.ts +64 -0
- package/src/shared/cli/functions/generate-help.function.ts +599 -0
- package/src/shared/cli/functions/is-stdin-tty.function.ts +12 -0
- package/src/shared/cli/functions/parse-args.function.ts +133 -0
- package/src/shared/cli/functions/prompt-user.function.ts +36 -0
- package/src/shared/cli/functions/run-agent-create.function.ts +114 -0
- package/src/shared/cli/functions/run-agent-delete.function.ts +47 -0
- package/src/shared/cli/functions/run-agent-get.function.ts +166 -0
- package/src/shared/cli/functions/run-agent-list.function.ts +58 -0
- package/src/shared/cli/functions/run-check.function.ts +78 -0
- package/src/shared/cli/functions/run-cli.function.ts +299 -0
- package/src/shared/cli/functions/run-content.function.ts +47 -0
- package/src/shared/cli/functions/run-db-init.function.ts +44 -0
- package/src/shared/cli/functions/run-db-migrate.function.ts +40 -0
- package/src/shared/cli/functions/run-gc.function.ts +45 -0
- package/src/shared/cli/functions/run-init.function.ts +91 -0
- package/src/shared/cli/functions/run-learn.function.ts +171 -0
- package/src/shared/cli/functions/run-migrate.function.ts +85 -0
- package/src/shared/cli/functions/run-rebuild.function.ts +47 -0
- package/src/shared/cli/functions/run-search.function.ts +62 -0
- package/src/shared/cli/functions/run-skill-delete.function.ts +47 -0
- package/src/shared/cli/functions/run-skill-get.function.ts +90 -0
- package/src/shared/cli/functions/run-skill-learn.function.ts +70 -0
- package/src/shared/cli/functions/run-skill-list.function.ts +74 -0
- package/src/shared/cli/functions/run-status.function.ts +29 -0
- package/src/shared/cli/functions/run-unlearn.function.ts +58 -0
- package/src/shared/cli/index.ts +48 -0
- package/src/shared/cli/typings/cli-options.interface.ts +55 -0
- package/src/shared/cli/typings/command-result.model.ts +15 -0
- package/src/shared/cli/typings/learn-result.model.ts +11 -0
- package/src/shared/cli/typings/search-display.model.ts +17 -0
- package/src/shared/dir-resolver/functions/resolve-base-dir.function.ts +25 -0
- package/src/shared/dir-resolver/functions/resolve-wasm-dir.function.ts +5 -0
- package/src/shared/dir-resolver/functions/resolve-worker-script.function.ts +13 -0
- package/src/shared/dir-resolver/index.ts +7 -0
- package/src/shared/dir-resolver/typings/base-dir.interface.ts +4 -0
- package/src/shared/hash/functions/compute-sha256.ts +17 -0
- package/src/shared/hash/index.ts +1 -0
- package/src/shared/mcp/classes/mcp-server.class.ts +448 -0
- package/src/shared/mcp/constants/mcp-error-codes.constant.ts +30 -0
- package/src/shared/mcp/functions/create-mcp-server.function.ts +14 -0
- package/src/shared/mcp/functions/create-prompt-definitions.function.ts +102 -0
- package/src/shared/mcp/functions/create-resource-templates.function.ts +23 -0
- package/src/shared/mcp/functions/create-tool-definitions.function.ts +401 -0
- package/src/shared/mcp/functions/extract-skill-arguments.function.ts +27 -0
- package/src/shared/mcp/functions/handle-agent-create.function.ts +116 -0
- package/src/shared/mcp/functions/handle-agent-delete.function.ts +50 -0
- package/src/shared/mcp/functions/handle-agent-get.function.ts +160 -0
- package/src/shared/mcp/functions/handle-agent-list.function.ts +50 -0
- package/src/shared/mcp/functions/handle-completion.function.ts +114 -0
- package/src/shared/mcp/functions/handle-prompt-get.function.ts +214 -0
- package/src/shared/mcp/functions/handle-resource-read.function.ts +56 -0
- package/src/shared/mcp/functions/handle-roots-list.function.ts +29 -0
- package/src/shared/mcp/functions/handle-tool-call.function.ts +464 -0
- package/src/shared/mcp/functions/parse-skill-content.function.ts +38 -0
- package/src/shared/mcp/functions/serialize-skill-content.function.ts +12 -0
- package/src/shared/mcp/functions/should-emit-log.function.ts +38 -0
- package/src/shared/mcp/index.ts +28 -0
- package/src/shared/mcp/typings/agent-types.interface.ts +39 -0
- package/src/shared/mcp/typings/log-types.interface.ts +26 -0
- package/src/shared/mcp/typings/mcp-client.interface.ts +252 -0
- package/src/shared/mcp/typings/mcp-types.interface.ts +158 -0
- package/src/shared/mcp/typings/prompt-types.interface.ts +39 -0
- package/src/shared/mcp/typings/remove-section-result.model.ts +10 -0
- package/src/shared/mcp/typings/sampling-types.interface.ts +48 -0
- package/src/shared/mcp/typings/skill-types.interface.ts +29 -0
- package/src/shared/mod.ts +1 -0
- package/src/shared/platform/functions/get-ipc-path.function.ts +19 -0
- package/src/shared/platform/functions/get-tmpdir.function.ts +8 -0
- package/src/shared/platform/functions/is-process-alive.function.ts +17 -0
- package/src/shared/platform/index.ts +3 -0
- package/src/shared/runtime/functions/detect-runtime.ts +14 -0
- package/src/shared/runtime/functions/get-args.ts +16 -0
- package/src/shared/runtime/index.ts +3 -0
- package/src/shared/runtime/typings/runtime.ts +2 -0
- package/src/shared/version/constants/version.constant.ts +2 -0
- package/src/shared/version/index.ts +1 -0
- package/src/shared/wasm-codec/functions/decode-compose-output.function.ts +16 -0
- package/src/shared/wasm-codec/functions/decode-document-manifest-list.function.ts +70 -0
- package/src/shared/wasm-codec/functions/decode-document-manifest.function.ts +87 -0
- package/src/shared/wasm-codec/functions/decode-f32.function.ts +16 -0
- package/src/shared/wasm-codec/functions/decode-key-value-text.function.ts +15 -0
- package/src/shared/wasm-codec/functions/decode-remove-flag.function.ts +3 -0
- package/src/shared/wasm-codec/functions/decode-scored-results.function.ts +54 -0
- package/src/shared/wasm-codec/functions/decode-section-record-list.function.ts +20 -0
- package/src/shared/wasm-codec/functions/decode-section-records.function.ts +162 -0
- package/src/shared/wasm-codec/functions/decode-string.function.ts +22 -0
- package/src/shared/wasm-codec/functions/decode-u32.function.ts +16 -0
- package/src/shared/wasm-codec/functions/decode-u64.function.ts +16 -0
- package/src/shared/wasm-codec/functions/encode-add-section-params.function.ts +34 -0
- package/src/shared/wasm-codec/functions/encode-group-params.function.ts +28 -0
- package/src/shared/wasm-codec/functions/encode-identifier-list.function.ts +17 -0
- package/src/shared/wasm-codec/functions/encode-kbid-list.function.ts +17 -0
- package/src/shared/wasm-codec/functions/encode-option-string.function.ts +14 -0
- package/src/shared/wasm-codec/functions/encode-search-params.function.ts +9 -0
- package/src/shared/wasm-codec/functions/encode-section-type.function.ts +18 -0
- package/src/shared/wasm-codec/functions/encode-string.function.ts +9 -0
- package/src/shared/wasm-codec/functions/encode-type-filter-param.function.ts +13 -0
- package/src/shared/wasm-codec/functions/encode-u32.function.ts +5 -0
- package/src/shared/wasm-codec/functions/encode-update-section-params.function.ts +16 -0
- package/src/shared/wasm-codec/index.ts +36 -0
- package/src/shared/worker-client/classes/worker-client.class.ts +427 -0
- package/src/shared/worker-client/functions/compute-context-id.function.ts +18 -0
- package/src/shared/worker-client/functions/create-worker-client.function.ts +70 -0
- package/src/shared/worker-client/functions/discover-daemon.function.ts +47 -0
- package/src/shared/worker-client/functions/resolve-db-path.function.ts +21 -0
- package/src/shared/worker-client/functions/spawn-daemon.function.ts +35 -0
- package/src/shared/worker-client/functions/wait-for-daemon.function.ts +34 -0
- package/src/shared/worker-client/index.ts +31 -0
- package/src/shared/worker-client/typings/add-section-result.model.ts +22 -0
- package/src/shared/worker-client/typings/content-result.model.ts +12 -0
- package/src/shared/worker-client/typings/daemon-info.model.ts +7 -0
- package/src/shared/worker-client/typings/gc-result.model.ts +12 -0
- package/src/shared/worker-client/typings/integrity-check-result.model.ts +43 -0
- package/src/shared/worker-client/typings/migrate-result.model.ts +11 -0
- package/src/shared/worker-client/typings/rebuild-result.model.ts +12 -0
- package/src/shared/worker-client/typings/remove-section-result.model.ts +7 -0
- package/src/shared/worker-client/typings/search-params.model.ts +12 -0
- package/src/shared/worker-client/typings/search-result.model.ts +14 -0
- package/src/shared/worker-client/typings/section.model.ts +27 -0
- package/src/shared/worker-client/typings/status-result.model.ts +14 -0
- package/src/shared/worker-client/typings/version-status.model.ts +28 -0
- package/src/shared/worker-client/typings/worker-client-error.interface.ts +8 -0
- package/src/shared/worker-client/typings/worker-client-options.interface.ts +30 -0
- package/src/shared/worker-daemon/classes/worker-daemon.class.ts +1001 -0
- package/src/shared/worker-daemon/constants/daemon-defaults.constant.ts +29 -0
- package/src/shared/worker-daemon/functions/create-host-imports.function.ts +312 -0
- package/src/shared/worker-daemon/functions/create-ipc-server.function.ts +83 -0
- package/src/shared/worker-daemon/functions/load-wasm-modules.function.ts +98 -0
- package/src/shared/worker-daemon/functions/read-config.function.ts +83 -0
- package/src/shared/worker-daemon/functions/run-worker.function.ts +57 -0
- package/src/shared/worker-daemon/functions/start-daemon.function.ts +74 -0
- package/src/shared/worker-daemon/index.ts +16 -0
- package/src/shared/worker-daemon/typings/daemon-config.interface.ts +13 -0
- package/src/shared/worker-daemon/typings/ipc-handler.interface.ts +39 -0
- package/src/shared/worker-daemon/typings/wasm-modules.interface.ts +7 -0
- package/src/worker.ts +34 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,3537 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeSha256,
|
|
3
|
+
detectRuntime,
|
|
4
|
+
getArgs,
|
|
5
|
+
getIpcPath,
|
|
6
|
+
resolveBaseDir,
|
|
7
|
+
resolveWorkerScript
|
|
8
|
+
} from "./chunk-QCCN7OZH.mjs";
|
|
9
|
+
|
|
10
|
+
// src/shared/cli/constants/defaults.constant.ts
|
|
11
|
+
var DEFAULT_LIMIT = 20;
|
|
12
|
+
var DEFAULT_FORMAT = "json";
|
|
13
|
+
var DEFAULT_MODE = "sections";
|
|
14
|
+
var SUPPORTED_EXTENSIONS = [
|
|
15
|
+
".md",
|
|
16
|
+
".txt",
|
|
17
|
+
".rst",
|
|
18
|
+
".adoc"
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// src/shared/cli/functions/parse-args.function.ts
|
|
22
|
+
function parseArgs(argv) {
|
|
23
|
+
const options = {
|
|
24
|
+
command: "",
|
|
25
|
+
format: DEFAULT_FORMAT,
|
|
26
|
+
mode: DEFAULT_MODE,
|
|
27
|
+
limit: DEFAULT_LIMIT,
|
|
28
|
+
args: []
|
|
29
|
+
};
|
|
30
|
+
let i = 0;
|
|
31
|
+
while (i < argv.length) {
|
|
32
|
+
const arg = argv[i];
|
|
33
|
+
switch (arg) {
|
|
34
|
+
case "--help":
|
|
35
|
+
case "-h":
|
|
36
|
+
if (options.command) {
|
|
37
|
+
options.args.unshift(options.command);
|
|
38
|
+
options.command = "help";
|
|
39
|
+
} else {
|
|
40
|
+
options.command = "help";
|
|
41
|
+
}
|
|
42
|
+
return options;
|
|
43
|
+
case "--version":
|
|
44
|
+
case "-v":
|
|
45
|
+
options.command = "version";
|
|
46
|
+
return options;
|
|
47
|
+
case "--init":
|
|
48
|
+
console.error(
|
|
49
|
+
'warning: --init is deprecated, use "kbdb db init"'
|
|
50
|
+
);
|
|
51
|
+
options.command = "init";
|
|
52
|
+
break;
|
|
53
|
+
case "--migrate":
|
|
54
|
+
console.error(
|
|
55
|
+
'warning: --migrate is deprecated, use "kbdb db migrate"'
|
|
56
|
+
);
|
|
57
|
+
options.command = "migrate";
|
|
58
|
+
break;
|
|
59
|
+
case "--db":
|
|
60
|
+
options.dbPath = argv[++i];
|
|
61
|
+
break;
|
|
62
|
+
case "--format":
|
|
63
|
+
case "-f":
|
|
64
|
+
options.format = argv[++i] ?? DEFAULT_FORMAT;
|
|
65
|
+
break;
|
|
66
|
+
case "--mode":
|
|
67
|
+
case "-m":
|
|
68
|
+
options.mode = argv[++i] ?? DEFAULT_MODE;
|
|
69
|
+
break;
|
|
70
|
+
case "--limit":
|
|
71
|
+
case "-l":
|
|
72
|
+
options.limit = parseInt(argv[++i] ?? "", 10) || DEFAULT_LIMIT;
|
|
73
|
+
break;
|
|
74
|
+
case "--title":
|
|
75
|
+
options.title = argv[++i];
|
|
76
|
+
break;
|
|
77
|
+
case "--description":
|
|
78
|
+
options.description = argv[++i];
|
|
79
|
+
break;
|
|
80
|
+
case "--docid":
|
|
81
|
+
options.docid = argv[++i];
|
|
82
|
+
break;
|
|
83
|
+
case "--name":
|
|
84
|
+
options.name = argv[++i];
|
|
85
|
+
break;
|
|
86
|
+
case "--persona":
|
|
87
|
+
options.persona = argv[++i];
|
|
88
|
+
break;
|
|
89
|
+
case "--body":
|
|
90
|
+
options.body = argv[++i];
|
|
91
|
+
break;
|
|
92
|
+
case "--skills":
|
|
93
|
+
options.skills = (argv[++i] ?? "").split(",");
|
|
94
|
+
break;
|
|
95
|
+
case "--content":
|
|
96
|
+
case "-c":
|
|
97
|
+
options.content = true;
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
if (!options.command) {
|
|
101
|
+
options.command = arg;
|
|
102
|
+
} else if (!options.args.length && (options.command === "db" || options.command === "skill" || options.command === "agent")) {
|
|
103
|
+
options.command = `${options.command}-${arg}`;
|
|
104
|
+
} else {
|
|
105
|
+
options.args.push(arg);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
i++;
|
|
109
|
+
}
|
|
110
|
+
return options;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/shared/cli/functions/format-output.function.ts
|
|
114
|
+
function formatOutput(results, format) {
|
|
115
|
+
switch (format) {
|
|
116
|
+
case "json":
|
|
117
|
+
return JSON.stringify(results, null, 2);
|
|
118
|
+
case "text":
|
|
119
|
+
return formatText(results);
|
|
120
|
+
case "mcp":
|
|
121
|
+
return formatMcp(results);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function formatText(results) {
|
|
125
|
+
if (results.length === 0) return "No results found.";
|
|
126
|
+
return results.map(
|
|
127
|
+
(r, i) => `${String(i + 1)}. [${r.kbid}] (score: ${r.score.toFixed(4)})
|
|
128
|
+
${r.preview}
|
|
129
|
+
matches: ${r.matches.map((m) => m.term).join(", ")}`
|
|
130
|
+
).join("\n\n");
|
|
131
|
+
}
|
|
132
|
+
function formatMcp(results) {
|
|
133
|
+
return JSON.stringify({
|
|
134
|
+
type: "text",
|
|
135
|
+
text: results.map(
|
|
136
|
+
(r) => `[${r.kbid}] score=${r.score.toFixed(4)} \u2014 ${r.preview}`
|
|
137
|
+
).join("\n")
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/shared/cli/functions/run-search.function.ts
|
|
142
|
+
async function runSearch(client, options) {
|
|
143
|
+
const query = options.args.join(" ").trim();
|
|
144
|
+
if (!query) return [];
|
|
145
|
+
const results = await client.search({
|
|
146
|
+
query,
|
|
147
|
+
mode: options.mode,
|
|
148
|
+
limit: options.limit
|
|
149
|
+
});
|
|
150
|
+
return results.map((r) => ({
|
|
151
|
+
kbid: r.kbid,
|
|
152
|
+
score: r.score,
|
|
153
|
+
preview: "",
|
|
154
|
+
matches: r.matches
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/shared/cli/functions/run-learn.function.ts
|
|
159
|
+
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
160
|
+
import { basename, extname, join } from "node:path";
|
|
161
|
+
async function runLearn(client, options, io) {
|
|
162
|
+
const results = [];
|
|
163
|
+
let stdinConsumed = false;
|
|
164
|
+
const readStdin = io?.readStdin ?? readProcessStdin;
|
|
165
|
+
for (const target of options.args) {
|
|
166
|
+
if (target === "-") {
|
|
167
|
+
if (stdinConsumed) continue;
|
|
168
|
+
stdinConsumed = true;
|
|
169
|
+
const content = await readStdin();
|
|
170
|
+
const result = await client.addSection({
|
|
171
|
+
sectionType: "text",
|
|
172
|
+
content,
|
|
173
|
+
title: options.title,
|
|
174
|
+
description: options.description,
|
|
175
|
+
docid: options.docid
|
|
176
|
+
});
|
|
177
|
+
results.push({
|
|
178
|
+
kbid: result.kbid,
|
|
179
|
+
path: "-",
|
|
180
|
+
size: content.length,
|
|
181
|
+
skipped: false
|
|
182
|
+
});
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const files = collectFiles(target);
|
|
186
|
+
for (const file of files) {
|
|
187
|
+
const content = readFileSync(file, "utf-8");
|
|
188
|
+
const result = await client.addSection({
|
|
189
|
+
sectionType: "text",
|
|
190
|
+
content,
|
|
191
|
+
title: options.title,
|
|
192
|
+
docid: options.docid
|
|
193
|
+
});
|
|
194
|
+
results.push({
|
|
195
|
+
kbid: result.kbid,
|
|
196
|
+
path: file,
|
|
197
|
+
size: content.length,
|
|
198
|
+
skipped: false
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return results;
|
|
203
|
+
}
|
|
204
|
+
function readProcessStdin() {
|
|
205
|
+
return new Promise((resolve4) => {
|
|
206
|
+
const chunks = [];
|
|
207
|
+
process.stdin.on("data", (chunk) => {
|
|
208
|
+
chunks.push(chunk);
|
|
209
|
+
});
|
|
210
|
+
process.stdin.on("end", () => {
|
|
211
|
+
resolve4(Buffer.concat(chunks).toString("utf-8"));
|
|
212
|
+
});
|
|
213
|
+
process.stdin.resume();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function collectFiles(target) {
|
|
217
|
+
try {
|
|
218
|
+
const stat = statSync(target);
|
|
219
|
+
if (stat.isFile()) {
|
|
220
|
+
return isSupportedFile(target) ? [target] : [];
|
|
221
|
+
}
|
|
222
|
+
if (stat.isDirectory()) {
|
|
223
|
+
return scanDirectory(target);
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
function scanDirectory(dir) {
|
|
230
|
+
const files = [];
|
|
231
|
+
for (const entry of readdirSync(dir)) {
|
|
232
|
+
if (entry.startsWith(".")) continue;
|
|
233
|
+
const full = join(dir, entry);
|
|
234
|
+
try {
|
|
235
|
+
const stat = statSync(full);
|
|
236
|
+
if (stat.isDirectory()) {
|
|
237
|
+
files.push(...scanDirectory(full));
|
|
238
|
+
} else if (isSupportedFile(full)) {
|
|
239
|
+
files.push(full);
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return files;
|
|
245
|
+
}
|
|
246
|
+
function isSupportedFile(path) {
|
|
247
|
+
if (basename(path).startsWith(".")) return false;
|
|
248
|
+
const ext = extname(path).toLowerCase();
|
|
249
|
+
return SUPPORTED_EXTENSIONS.includes(ext);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/shared/cli/functions/run-unlearn.function.ts
|
|
253
|
+
async function runUnlearn(client, options) {
|
|
254
|
+
const results = [];
|
|
255
|
+
for (const kbid of options.args) {
|
|
256
|
+
const result = await client.removeSection(kbid);
|
|
257
|
+
results.push({ kbid, removed: result.removed });
|
|
258
|
+
}
|
|
259
|
+
return results;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/shared/cli/functions/run-content.function.ts
|
|
263
|
+
async function runContent(client, options) {
|
|
264
|
+
return client.content(options.args);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/shared/cli/functions/run-check.function.ts
|
|
268
|
+
async function runCheck(client, _options) {
|
|
269
|
+
return client.integrityCheck();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/shared/cli/functions/run-gc.function.ts
|
|
273
|
+
async function runGc(client, _options) {
|
|
274
|
+
return client.gc();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/shared/cli/functions/run-rebuild.function.ts
|
|
278
|
+
async function runRebuild(client, _options) {
|
|
279
|
+
return client.rebuildIndexes();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/shared/cli/functions/find-db.function.ts
|
|
283
|
+
import { existsSync } from "node:fs";
|
|
284
|
+
import { join as join2, resolve } from "node:path";
|
|
285
|
+
function findDb(dbPath) {
|
|
286
|
+
const base = dbPath ? resolve(dbPath) : process.cwd();
|
|
287
|
+
const kbdbDir = join2(base, ".kbdb");
|
|
288
|
+
return existsSync(kbdbDir) ? kbdbDir : null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/shared/cli/functions/run-init.function.ts
|
|
292
|
+
import { existsSync as existsSync2, mkdirSync, writeFileSync } from "node:fs";
|
|
293
|
+
import { join as join3, resolve as resolve2 } from "node:path";
|
|
294
|
+
var DB_FORMAT_VERSION = 1;
|
|
295
|
+
var CATALOG_TOML = `version = ${DB_FORMAT_VERSION.toString()}
|
|
296
|
+
section_count = 0
|
|
297
|
+
document_count = 0
|
|
298
|
+
created_at = 0
|
|
299
|
+
updated_at = 0
|
|
300
|
+
checksum = ""
|
|
301
|
+
`;
|
|
302
|
+
var WORKER_TOML = "# kbdb worker configuration\n";
|
|
303
|
+
var GITIGNORE = [
|
|
304
|
+
"# kbdb binary indexes (auto-generated)",
|
|
305
|
+
"corpus.bin",
|
|
306
|
+
"inverted.idx",
|
|
307
|
+
"positional.idx",
|
|
308
|
+
""
|
|
309
|
+
].join("\n");
|
|
310
|
+
function createScaffold(dbDir) {
|
|
311
|
+
mkdirSync(dbDir, { recursive: true });
|
|
312
|
+
mkdirSync(join3(dbDir, "sections"));
|
|
313
|
+
mkdirSync(join3(dbDir, "documents"));
|
|
314
|
+
writeFileSync(join3(dbDir, "catalog.toml"), CATALOG_TOML);
|
|
315
|
+
writeFileSync(join3(dbDir, "corpus.bin"), "");
|
|
316
|
+
writeFileSync(join3(dbDir, "inverted.idx"), "");
|
|
317
|
+
writeFileSync(join3(dbDir, "positional.idx"), "");
|
|
318
|
+
writeFileSync(join3(dbDir, "worker.toml"), WORKER_TOML);
|
|
319
|
+
writeFileSync(join3(dbDir, ".gitignore"), GITIGNORE);
|
|
320
|
+
}
|
|
321
|
+
function runInit(options) {
|
|
322
|
+
const basePath = options.dbPath ? resolve2(options.dbPath) : process.cwd();
|
|
323
|
+
const dbDir = join3(basePath, ".kbdb");
|
|
324
|
+
try {
|
|
325
|
+
if (existsSync2(dbDir)) {
|
|
326
|
+
return {
|
|
327
|
+
ok: false,
|
|
328
|
+
targetPath: dbDir,
|
|
329
|
+
errorMessage: `database directory already exists: ${dbDir}`
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
createScaffold(dbDir);
|
|
333
|
+
return { ok: true, targetPath: dbDir };
|
|
334
|
+
} catch (err) {
|
|
335
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
336
|
+
return { ok: false, targetPath: dbDir, errorMessage };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/shared/cli/functions/error-to-message.function.ts
|
|
341
|
+
function errorToMessage(err) {
|
|
342
|
+
return err instanceof Error ? err.message : String(err);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/shared/cli/functions/is-stdin-tty.function.ts
|
|
346
|
+
function isStdinTty(stdin = process.stdin) {
|
|
347
|
+
return stdin.isTTY ?? false;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/shared/cli/functions/prompt-user.function.ts
|
|
351
|
+
import { createInterface } from "node:readline";
|
|
352
|
+
async function promptUser(question, io) {
|
|
353
|
+
const ask = io?.ask ?? askReadline;
|
|
354
|
+
const answer = await ask(question);
|
|
355
|
+
return answer.trim();
|
|
356
|
+
}
|
|
357
|
+
function askReadline(question) {
|
|
358
|
+
return new Promise((resolve4) => {
|
|
359
|
+
const rl = createInterface({
|
|
360
|
+
input: process.stdin,
|
|
361
|
+
output: process.stdout
|
|
362
|
+
});
|
|
363
|
+
rl.question(question, (answer) => {
|
|
364
|
+
rl.close();
|
|
365
|
+
resolve4(answer);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/shared/cli/functions/run-status.function.ts
|
|
371
|
+
async function runStatus(client, _options) {
|
|
372
|
+
return client.dbStatus();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/shared/cli/functions/run-db-init.function.ts
|
|
376
|
+
function runDbInit(options, runInitFn) {
|
|
377
|
+
const result = runInitFn(options);
|
|
378
|
+
if (result.ok) {
|
|
379
|
+
return {
|
|
380
|
+
output: JSON.stringify(
|
|
381
|
+
{ path: result.targetPath, created: true },
|
|
382
|
+
null,
|
|
383
|
+
2
|
|
384
|
+
),
|
|
385
|
+
exitCode: 0
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
error: result.errorMessage ?? "init failed",
|
|
390
|
+
exitCode: 1
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/shared/cli/functions/run-db-migrate.function.ts
|
|
395
|
+
async function runDbMigrate(client, options) {
|
|
396
|
+
const dbPath = options.dbPath ?? process.cwd();
|
|
397
|
+
return client.migrateDatabase(dbPath);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/shared/mcp/functions/extract-skill-arguments.function.ts
|
|
401
|
+
function extractSkillArguments(body) {
|
|
402
|
+
const seen = /* @__PURE__ */ new Set();
|
|
403
|
+
const args = [];
|
|
404
|
+
const re = /\{\{(\w+)\}\}/g;
|
|
405
|
+
let match;
|
|
406
|
+
while ((match = re.exec(body)) !== null) {
|
|
407
|
+
const name = match[1];
|
|
408
|
+
if (!seen.has(name)) {
|
|
409
|
+
seen.add(name);
|
|
410
|
+
args.push({ name, required: true });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return args;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/shared/mcp/functions/serialize-skill-content.function.ts
|
|
417
|
+
function serializeSkillContent(skill) {
|
|
418
|
+
return JSON.stringify(skill);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/shared/cli/functions/run-skill-learn.function.ts
|
|
422
|
+
async function runSkillLearn(client, options) {
|
|
423
|
+
const name = options.name;
|
|
424
|
+
if (!name) {
|
|
425
|
+
return { error: "--name is required", exitCode: 1 };
|
|
426
|
+
}
|
|
427
|
+
const body = options.body;
|
|
428
|
+
if (!body) {
|
|
429
|
+
return { error: "--body is required", exitCode: 1 };
|
|
430
|
+
}
|
|
431
|
+
const args = extractSkillArguments(body);
|
|
432
|
+
const skill = {
|
|
433
|
+
name,
|
|
434
|
+
description: options.description,
|
|
435
|
+
arguments: args.length > 0 ? args : void 0,
|
|
436
|
+
body
|
|
437
|
+
};
|
|
438
|
+
const json = serializeSkillContent(skill);
|
|
439
|
+
const result = await client.addSection({
|
|
440
|
+
sectionType: "skill",
|
|
441
|
+
content: json,
|
|
442
|
+
title: name,
|
|
443
|
+
description: options.description
|
|
444
|
+
});
|
|
445
|
+
return {
|
|
446
|
+
output: JSON.stringify(result, null, 2),
|
|
447
|
+
exitCode: 0
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/shared/cli/functions/run-skill-list.function.ts
|
|
452
|
+
async function runSkillList(client, _options) {
|
|
453
|
+
const records = await client.listByType("skill");
|
|
454
|
+
const items = records.map((r) => {
|
|
455
|
+
let argumentCount = 0;
|
|
456
|
+
try {
|
|
457
|
+
const parsed = JSON.parse(r.content);
|
|
458
|
+
if (Array.isArray(parsed["arguments"])) {
|
|
459
|
+
argumentCount = parsed["arguments"].length;
|
|
460
|
+
}
|
|
461
|
+
} catch {
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
kbid: r.kbid,
|
|
465
|
+
name: r.title,
|
|
466
|
+
description: r.description,
|
|
467
|
+
argumentCount
|
|
468
|
+
};
|
|
469
|
+
});
|
|
470
|
+
return {
|
|
471
|
+
output: JSON.stringify(items, null, 2),
|
|
472
|
+
exitCode: 0
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/shared/mcp/functions/parse-skill-content.function.ts
|
|
477
|
+
function parseSkillContent(json) {
|
|
478
|
+
const raw = JSON.parse(json);
|
|
479
|
+
if (typeof raw["name"] !== "string" || !raw["name"]) {
|
|
480
|
+
throw new Error("skill name is required");
|
|
481
|
+
}
|
|
482
|
+
if (typeof raw["body"] !== "string") {
|
|
483
|
+
throw new Error("skill body is required");
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
name: raw["name"],
|
|
487
|
+
description: typeof raw["description"] === "string" ? raw["description"] : void 0,
|
|
488
|
+
arguments: Array.isArray(raw["arguments"]) ? raw["arguments"] : void 0,
|
|
489
|
+
body: raw["body"]
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/shared/cli/functions/run-skill-get.function.ts
|
|
494
|
+
async function runSkillGet(client, options) {
|
|
495
|
+
const identifier = options.args[0] ?? options.name;
|
|
496
|
+
if (!identifier) {
|
|
497
|
+
return {
|
|
498
|
+
error: "skill name or kbid required",
|
|
499
|
+
exitCode: 1
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
let content;
|
|
503
|
+
if (/^[0-9a-f]{16,}$/i.test(identifier)) {
|
|
504
|
+
const sections = await client.readSections([identifier]);
|
|
505
|
+
if (sections.length > 0) {
|
|
506
|
+
content = sections[0]?.content;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (content === void 0) {
|
|
510
|
+
const records = await client.listByType("skill");
|
|
511
|
+
const match = records.filter((r) => r.title === identifier).pop();
|
|
512
|
+
if (match) {
|
|
513
|
+
content = match.content;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (content === void 0) {
|
|
517
|
+
return {
|
|
518
|
+
error: `skill not found: ${identifier}`,
|
|
519
|
+
exitCode: 1
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
const skill = parseSkillContent(content);
|
|
523
|
+
return {
|
|
524
|
+
output: JSON.stringify(skill, null, 2),
|
|
525
|
+
exitCode: 0
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/shared/cli/functions/run-skill-delete.function.ts
|
|
530
|
+
async function runSkillDelete(client, options) {
|
|
531
|
+
const kbid = options.args[0];
|
|
532
|
+
if (!kbid) {
|
|
533
|
+
return { error: "kbid is required", exitCode: 1 };
|
|
534
|
+
}
|
|
535
|
+
const result = await client.removeSection(kbid);
|
|
536
|
+
return {
|
|
537
|
+
output: JSON.stringify(
|
|
538
|
+
{ kbid, removed: result.removed },
|
|
539
|
+
null,
|
|
540
|
+
2
|
|
541
|
+
),
|
|
542
|
+
exitCode: 0
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/shared/cli/functions/run-agent-create.function.ts
|
|
547
|
+
async function runAgentCreate(client, options) {
|
|
548
|
+
const name = options.name;
|
|
549
|
+
if (!name) {
|
|
550
|
+
return { error: "--name is required", exitCode: 1 };
|
|
551
|
+
}
|
|
552
|
+
const persona = options.persona;
|
|
553
|
+
if (!persona) {
|
|
554
|
+
return { error: "--persona is required", exitCode: 1 };
|
|
555
|
+
}
|
|
556
|
+
const skills = options.skills ?? [];
|
|
557
|
+
if (skills.length > 0) {
|
|
558
|
+
const sections = await client.readSections(skills);
|
|
559
|
+
const found = new Set(sections.map((s) => s.kbid));
|
|
560
|
+
const missing = skills.filter((k) => !found.has(k));
|
|
561
|
+
if (missing.length > 0) {
|
|
562
|
+
return {
|
|
563
|
+
error: `skill not found: ${missing.join(", ")}`,
|
|
564
|
+
exitCode: 1
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const metadata = JSON.stringify({
|
|
569
|
+
name,
|
|
570
|
+
description: options.description ?? "",
|
|
571
|
+
persona
|
|
572
|
+
});
|
|
573
|
+
const metaResult = await client.addSection({
|
|
574
|
+
sectionType: "text",
|
|
575
|
+
content: metadata,
|
|
576
|
+
title: name,
|
|
577
|
+
description: options.description
|
|
578
|
+
});
|
|
579
|
+
const allKbids = [metaResult.kbid, ...skills];
|
|
580
|
+
const docid = await client.groupSections(name, allKbids, "agent");
|
|
581
|
+
return {
|
|
582
|
+
output: JSON.stringify(
|
|
583
|
+
{ docid, name, skillCount: skills.length },
|
|
584
|
+
null,
|
|
585
|
+
2
|
|
586
|
+
),
|
|
587
|
+
exitCode: 0
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/shared/cli/functions/run-agent-list.function.ts
|
|
592
|
+
async function runAgentList(client, _options) {
|
|
593
|
+
const docs = await client.listDocumentsByType("agent");
|
|
594
|
+
const items = docs.map((d) => ({
|
|
595
|
+
docid: d.docid,
|
|
596
|
+
name: d.title,
|
|
597
|
+
skillCount: Math.max(0, d.sections.length - 1)
|
|
598
|
+
}));
|
|
599
|
+
return {
|
|
600
|
+
output: JSON.stringify(items, null, 2),
|
|
601
|
+
exitCode: 0
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// src/shared/cli/functions/run-agent-get.function.ts
|
|
606
|
+
async function readAgentMeta(client, metaKbid, fallbackName) {
|
|
607
|
+
const sections = await client.readSections([metaKbid]);
|
|
608
|
+
const first = sections.at(0);
|
|
609
|
+
if (!first) {
|
|
610
|
+
return { name: fallbackName, description: "", persona: "" };
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
const meta = JSON.parse(first.content);
|
|
614
|
+
return {
|
|
615
|
+
name: typeof meta["name"] === "string" ? meta["name"] : fallbackName,
|
|
616
|
+
description: typeof meta["description"] === "string" ? meta["description"] : "",
|
|
617
|
+
persona: typeof meta["persona"] === "string" ? meta["persona"] : ""
|
|
618
|
+
};
|
|
619
|
+
} catch {
|
|
620
|
+
return { name: fallbackName, description: "", persona: "" };
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function resolveSkills(client, skillRefs) {
|
|
624
|
+
if (skillRefs.length === 0) {
|
|
625
|
+
return [];
|
|
626
|
+
}
|
|
627
|
+
const kbids = skillRefs.map((r) => r.kbid);
|
|
628
|
+
const sections = await client.readSections(kbids);
|
|
629
|
+
const sectionMap = new Map(sections.map((s) => [s.kbid, s]));
|
|
630
|
+
return skillRefs.map((ref) => {
|
|
631
|
+
const sec = sectionMap.get(ref.kbid);
|
|
632
|
+
if (!sec) {
|
|
633
|
+
return { kbid: ref.kbid, name: null, position: ref.position };
|
|
634
|
+
}
|
|
635
|
+
try {
|
|
636
|
+
const parsed = JSON.parse(sec.content);
|
|
637
|
+
const skillName = typeof parsed["name"] === "string" ? parsed["name"] : null;
|
|
638
|
+
return {
|
|
639
|
+
kbid: ref.kbid,
|
|
640
|
+
name: skillName,
|
|
641
|
+
position: ref.position
|
|
642
|
+
};
|
|
643
|
+
} catch {
|
|
644
|
+
return { kbid: ref.kbid, name: null, position: ref.position };
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
async function runAgentGet(client, options) {
|
|
649
|
+
const docid = options.args[0];
|
|
650
|
+
if (!docid) {
|
|
651
|
+
return { error: "docid is required", exitCode: 1 };
|
|
652
|
+
}
|
|
653
|
+
const doc = await client.retrieveDocument(docid);
|
|
654
|
+
const metaKbid = doc.sections[0]?.kbid;
|
|
655
|
+
const skillRefs = doc.sections.slice(1);
|
|
656
|
+
const { name, description, persona } = metaKbid ? await readAgentMeta(client, metaKbid, doc.title) : { name: doc.title, description: "", persona: "" };
|
|
657
|
+
const skills = await resolveSkills(client, skillRefs);
|
|
658
|
+
return {
|
|
659
|
+
output: JSON.stringify(
|
|
660
|
+
{ docid, name, description, persona, skills },
|
|
661
|
+
null,
|
|
662
|
+
2
|
|
663
|
+
),
|
|
664
|
+
exitCode: 0
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/shared/cli/functions/run-agent-delete.function.ts
|
|
669
|
+
async function runAgentDelete(client, options) {
|
|
670
|
+
const docid = options.args[0];
|
|
671
|
+
if (!docid) {
|
|
672
|
+
return { error: "docid is required", exitCode: 1 };
|
|
673
|
+
}
|
|
674
|
+
await client.removeGrouping(docid);
|
|
675
|
+
return {
|
|
676
|
+
output: JSON.stringify({ docid, removed: true }, null, 2),
|
|
677
|
+
exitCode: 0
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/shared/cli/functions/dispatch-command.function.ts
|
|
682
|
+
async function dispatchCommand(client, options, io) {
|
|
683
|
+
switch (options.command) {
|
|
684
|
+
case "learn":
|
|
685
|
+
return handleLearn(client, options, io);
|
|
686
|
+
case "unlearn":
|
|
687
|
+
return handleUnlearn(client, options);
|
|
688
|
+
case "search":
|
|
689
|
+
return handleSearch(client, options);
|
|
690
|
+
case "content":
|
|
691
|
+
return handleContent(client, options);
|
|
692
|
+
case "check":
|
|
693
|
+
return handleCheck(client, options);
|
|
694
|
+
case "gc":
|
|
695
|
+
return handleGc(client, options);
|
|
696
|
+
case "rebuild":
|
|
697
|
+
return handleRebuild(client, options);
|
|
698
|
+
case "status":
|
|
699
|
+
return handleStatus(client, options);
|
|
700
|
+
case "db-init":
|
|
701
|
+
return handleDbInit(options);
|
|
702
|
+
case "db-migrate":
|
|
703
|
+
return handleDbMigrate(client, options);
|
|
704
|
+
case "skill-learn": {
|
|
705
|
+
const result = await runSkillLearn(client, options);
|
|
706
|
+
return result;
|
|
707
|
+
}
|
|
708
|
+
case "skill-list": {
|
|
709
|
+
const result = await runSkillList(client, options);
|
|
710
|
+
return result;
|
|
711
|
+
}
|
|
712
|
+
case "skill-get": {
|
|
713
|
+
const result = await runSkillGet(client, options);
|
|
714
|
+
return result;
|
|
715
|
+
}
|
|
716
|
+
case "skill-delete": {
|
|
717
|
+
const result = await runSkillDelete(client, options);
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
case "agent-create": {
|
|
721
|
+
const result = await runAgentCreate(client, options);
|
|
722
|
+
return result;
|
|
723
|
+
}
|
|
724
|
+
case "agent-list": {
|
|
725
|
+
const result = await runAgentList(client, options);
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
case "agent-get": {
|
|
729
|
+
const result = await runAgentGet(client, options);
|
|
730
|
+
return result;
|
|
731
|
+
}
|
|
732
|
+
case "agent-delete": {
|
|
733
|
+
const result = await runAgentDelete(client, options);
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
default:
|
|
737
|
+
return {
|
|
738
|
+
error: `unknown command: ${options.command}`,
|
|
739
|
+
exitCode: 1
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
async function handleLearn(client, options, io) {
|
|
744
|
+
try {
|
|
745
|
+
const results = await runLearn(client, options, io);
|
|
746
|
+
return {
|
|
747
|
+
output: JSON.stringify(results, null, 2),
|
|
748
|
+
exitCode: 0
|
|
749
|
+
};
|
|
750
|
+
} catch (err) {
|
|
751
|
+
return {
|
|
752
|
+
error: `learn failed: ${errorToMessage(err)}`,
|
|
753
|
+
exitCode: 1
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
async function handleUnlearn(client, options) {
|
|
758
|
+
try {
|
|
759
|
+
const results = await runUnlearn(client, options);
|
|
760
|
+
return {
|
|
761
|
+
output: JSON.stringify(results, null, 2),
|
|
762
|
+
exitCode: 0
|
|
763
|
+
};
|
|
764
|
+
} catch (err) {
|
|
765
|
+
return {
|
|
766
|
+
error: `unlearn failed: ${errorToMessage(err)}`,
|
|
767
|
+
exitCode: 1
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
async function handleSearch(client, options) {
|
|
772
|
+
try {
|
|
773
|
+
const results = await runSearch(client, options);
|
|
774
|
+
if (options.content) {
|
|
775
|
+
await hydrateSearchPreviews(client, results);
|
|
776
|
+
}
|
|
777
|
+
return {
|
|
778
|
+
output: formatOutput(results, options.format),
|
|
779
|
+
exitCode: 0
|
|
780
|
+
};
|
|
781
|
+
} catch (err) {
|
|
782
|
+
return {
|
|
783
|
+
error: `search failed: ${errorToMessage(err)}`,
|
|
784
|
+
exitCode: 1
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
async function handleContent(client, options) {
|
|
789
|
+
try {
|
|
790
|
+
const result = await runContent(client, options);
|
|
791
|
+
return {
|
|
792
|
+
output: JSON.stringify(result, null, 2),
|
|
793
|
+
exitCode: 0
|
|
794
|
+
};
|
|
795
|
+
} catch (err) {
|
|
796
|
+
return {
|
|
797
|
+
error: `content failed: ${errorToMessage(err)}`,
|
|
798
|
+
exitCode: 1
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
async function handleCheck(client, options) {
|
|
803
|
+
try {
|
|
804
|
+
const result = await runCheck(client, options);
|
|
805
|
+
return {
|
|
806
|
+
output: JSON.stringify(result, null, 2),
|
|
807
|
+
exitCode: result.ok ? 0 : 1
|
|
808
|
+
};
|
|
809
|
+
} catch (err) {
|
|
810
|
+
return {
|
|
811
|
+
error: `check failed: ${errorToMessage(err)}`,
|
|
812
|
+
exitCode: 1
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
async function handleGc(client, options) {
|
|
817
|
+
try {
|
|
818
|
+
const result = await runGc(client, options);
|
|
819
|
+
return {
|
|
820
|
+
output: JSON.stringify(result, null, 2),
|
|
821
|
+
exitCode: 0
|
|
822
|
+
};
|
|
823
|
+
} catch (err) {
|
|
824
|
+
return {
|
|
825
|
+
error: `gc failed: ${errorToMessage(err)}`,
|
|
826
|
+
exitCode: 1
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
async function handleRebuild(client, options) {
|
|
831
|
+
try {
|
|
832
|
+
const result = await runRebuild(client, options);
|
|
833
|
+
return {
|
|
834
|
+
output: JSON.stringify(result, null, 2),
|
|
835
|
+
exitCode: 0
|
|
836
|
+
};
|
|
837
|
+
} catch (err) {
|
|
838
|
+
return {
|
|
839
|
+
error: `rebuild failed: ${errorToMessage(err)}`,
|
|
840
|
+
exitCode: 1
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
async function handleStatus(client, options) {
|
|
845
|
+
try {
|
|
846
|
+
const result = await runStatus(client, options);
|
|
847
|
+
return {
|
|
848
|
+
output: JSON.stringify(result, null, 2),
|
|
849
|
+
exitCode: 0
|
|
850
|
+
};
|
|
851
|
+
} catch (err) {
|
|
852
|
+
return {
|
|
853
|
+
error: `status failed: ${errorToMessage(err)}`,
|
|
854
|
+
exitCode: 1
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function handleDbInit(options) {
|
|
859
|
+
return runDbInit(options, runInit);
|
|
860
|
+
}
|
|
861
|
+
async function handleDbMigrate(client, options) {
|
|
862
|
+
try {
|
|
863
|
+
const result = await runDbMigrate(client, options);
|
|
864
|
+
return {
|
|
865
|
+
output: JSON.stringify(result, null, 2),
|
|
866
|
+
exitCode: 0
|
|
867
|
+
};
|
|
868
|
+
} catch (err) {
|
|
869
|
+
return {
|
|
870
|
+
error: `db-migrate failed: ${errorToMessage(err)}`,
|
|
871
|
+
exitCode: 1
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
async function hydrateSearchPreviews(client, results) {
|
|
876
|
+
await Promise.all(
|
|
877
|
+
results.map(async (result) => {
|
|
878
|
+
try {
|
|
879
|
+
const contentResult = await client.content([result.kbid]);
|
|
880
|
+
result.preview = contentResult.data;
|
|
881
|
+
} catch {
|
|
882
|
+
}
|
|
883
|
+
})
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// src/shared/version/constants/version.constant.ts
|
|
888
|
+
var VERSION = "0.1.0";
|
|
889
|
+
|
|
890
|
+
// src/shared/cli/functions/generate-help.function.ts
|
|
891
|
+
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
892
|
+
"learn",
|
|
893
|
+
"unlearn",
|
|
894
|
+
"search",
|
|
895
|
+
"content",
|
|
896
|
+
"check",
|
|
897
|
+
"gc",
|
|
898
|
+
"rebuild",
|
|
899
|
+
"status",
|
|
900
|
+
"mcp",
|
|
901
|
+
"db",
|
|
902
|
+
"skill",
|
|
903
|
+
"agent"
|
|
904
|
+
]);
|
|
905
|
+
var GROUP_SUBCOMMANDS = {
|
|
906
|
+
db: [
|
|
907
|
+
["init", "Initialise a new .kbdb directory"],
|
|
908
|
+
["migrate", "Migrate database to current format"]
|
|
909
|
+
],
|
|
910
|
+
skill: [
|
|
911
|
+
["learn", "Create a new skill definition"],
|
|
912
|
+
["list", "List all skills"],
|
|
913
|
+
["get", "Retrieve a skill by name or kbid"],
|
|
914
|
+
["delete", "Remove a skill"]
|
|
915
|
+
],
|
|
916
|
+
agent: [
|
|
917
|
+
["create", "Create an agent with skill refs"],
|
|
918
|
+
["list", "List all agents"],
|
|
919
|
+
["get", "Retrieve an agent by docid"],
|
|
920
|
+
["delete", "Remove an agent"]
|
|
921
|
+
]
|
|
922
|
+
};
|
|
923
|
+
function isKnownCommand(cmd) {
|
|
924
|
+
if (KNOWN_COMMANDS.has(cmd)) {
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
const dashIdx = cmd.indexOf("-");
|
|
928
|
+
if (dashIdx < 0) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
const group = cmd.slice(0, dashIdx);
|
|
932
|
+
return group in GROUP_SUBCOMMANDS;
|
|
933
|
+
}
|
|
934
|
+
function generateHelp(command, subcommand) {
|
|
935
|
+
if (!command) {
|
|
936
|
+
return generateGlobalHelp();
|
|
937
|
+
}
|
|
938
|
+
if (!subcommand && command.includes("-")) {
|
|
939
|
+
const dashIdx = command.indexOf("-");
|
|
940
|
+
const group = command.slice(0, dashIdx);
|
|
941
|
+
const sub = command.slice(dashIdx + 1);
|
|
942
|
+
if (group in GROUP_SUBCOMMANDS) {
|
|
943
|
+
return generateSubcommandHelp(group, sub);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (subcommand) {
|
|
947
|
+
return generateSubcommandHelp(command, subcommand);
|
|
948
|
+
}
|
|
949
|
+
return generateCommandHelp(command);
|
|
950
|
+
}
|
|
951
|
+
function generateGlobalHelp() {
|
|
952
|
+
return `kbdb v${VERSION} - File-based knowledge base database for AI agents
|
|
953
|
+
|
|
954
|
+
Usage: kbdb [options]
|
|
955
|
+
kbdb <command> [options] ...[parameters]
|
|
956
|
+
kbdb <command> <subcommand> [options] ...[params]
|
|
957
|
+
|
|
958
|
+
Knowledge Base:
|
|
959
|
+
learn Import content from files/stdin
|
|
960
|
+
unlearn Remove sections by kbid
|
|
961
|
+
search Query the knowledge base
|
|
962
|
+
content Compose rendered content from ids
|
|
963
|
+
|
|
964
|
+
Database:
|
|
965
|
+
db init Initialise a new .kbdb directory
|
|
966
|
+
db migrate Migrate database to current format
|
|
967
|
+
|
|
968
|
+
Maintenance:
|
|
969
|
+
check Verify knowledge base integrity
|
|
970
|
+
gc Garbage collect unreferenced
|
|
971
|
+
sections
|
|
972
|
+
rebuild Reconstruct all index files
|
|
973
|
+
status Show database status
|
|
974
|
+
|
|
975
|
+
Skills:
|
|
976
|
+
skill learn Create a new skill definition
|
|
977
|
+
skill list List all skills
|
|
978
|
+
skill get Retrieve a skill by name or kbid
|
|
979
|
+
skill delete Remove a skill
|
|
980
|
+
|
|
981
|
+
Agents:
|
|
982
|
+
agent create Create an agent with skill refs
|
|
983
|
+
agent list List all agents
|
|
984
|
+
agent get Retrieve an agent by docid
|
|
985
|
+
agent delete Remove an agent
|
|
986
|
+
|
|
987
|
+
Server:
|
|
988
|
+
mcp Start MCP server mode (stdio)
|
|
989
|
+
|
|
990
|
+
Global Options:
|
|
991
|
+
-h, --help Show this help message
|
|
992
|
+
-v, --version Show version information
|
|
993
|
+
--db <path> Path to .kbdb directory
|
|
994
|
+
--format <fmt> Output format (json|text|mcp)
|
|
995
|
+
|
|
996
|
+
Run "kbdb <command> --help" for detailed information.
|
|
997
|
+
`;
|
|
998
|
+
}
|
|
999
|
+
function generateCommandHelp(command) {
|
|
1000
|
+
if (command in GROUP_SUBCOMMANDS) {
|
|
1001
|
+
return generateGroupHelp(command);
|
|
1002
|
+
}
|
|
1003
|
+
const leaf = LEAF_HELP[command];
|
|
1004
|
+
if (leaf) {
|
|
1005
|
+
return leaf;
|
|
1006
|
+
}
|
|
1007
|
+
return `Unknown command: ${command}
|
|
1008
|
+
|
|
1009
|
+
` + generateGlobalHelp();
|
|
1010
|
+
}
|
|
1011
|
+
function generateGroupHelp(group) {
|
|
1012
|
+
const subs = GROUP_SUBCOMMANDS[group] ?? [];
|
|
1013
|
+
const subLines = subs.map(([name, desc2]) => ` ${name.padEnd(20)}${desc2}`).join("\n");
|
|
1014
|
+
const desc = GROUP_DESCRIPTIONS[group] ?? group;
|
|
1015
|
+
return `kbdb ${group} - ${desc}
|
|
1016
|
+
|
|
1017
|
+
Usage: kbdb ${group} <subcommand> [options]
|
|
1018
|
+
|
|
1019
|
+
Subcommands:
|
|
1020
|
+
${subLines}
|
|
1021
|
+
|
|
1022
|
+
Global Options:
|
|
1023
|
+
--db <path> Path to .kbdb directory
|
|
1024
|
+
-h, --help Show this help message
|
|
1025
|
+
|
|
1026
|
+
Run "kbdb ${group} <subcommand> --help" for details.
|
|
1027
|
+
`;
|
|
1028
|
+
}
|
|
1029
|
+
var GROUP_DESCRIPTIONS = {
|
|
1030
|
+
db: "Database management",
|
|
1031
|
+
skill: "Skill management",
|
|
1032
|
+
agent: "Agent management"
|
|
1033
|
+
};
|
|
1034
|
+
var LEAF_HELP = {
|
|
1035
|
+
learn: `kbdb learn - Import content from files or stdin
|
|
1036
|
+
|
|
1037
|
+
Usage: kbdb learn [options] <path | ->...
|
|
1038
|
+
|
|
1039
|
+
Arguments:
|
|
1040
|
+
<path | -> File path, directory, or - for stdin
|
|
1041
|
+
|
|
1042
|
+
Options:
|
|
1043
|
+
--title <title> Section title
|
|
1044
|
+
--description <d> Section description
|
|
1045
|
+
--docid <docid> Document ID to group under
|
|
1046
|
+
--db <path> Path to .kbdb directory
|
|
1047
|
+
|
|
1048
|
+
Output:
|
|
1049
|
+
JSON array of { kbid, path, size, skipped }
|
|
1050
|
+
|
|
1051
|
+
Examples:
|
|
1052
|
+
kbdb learn README.md
|
|
1053
|
+
kbdb learn ./docs/
|
|
1054
|
+
cat notes.txt | kbdb learn -
|
|
1055
|
+
`,
|
|
1056
|
+
unlearn: `kbdb unlearn - Remove sections by kbid
|
|
1057
|
+
|
|
1058
|
+
Usage: kbdb unlearn [options] <kbid>...
|
|
1059
|
+
|
|
1060
|
+
Arguments:
|
|
1061
|
+
<kbid> 26-character knowledge base identifier
|
|
1062
|
+
|
|
1063
|
+
Options:
|
|
1064
|
+
--db <path> Path to .kbdb directory
|
|
1065
|
+
|
|
1066
|
+
Output:
|
|
1067
|
+
JSON array of { kbid, removed }
|
|
1068
|
+
|
|
1069
|
+
Examples:
|
|
1070
|
+
kbdb unlearn abcdef1234567890abcdef1234
|
|
1071
|
+
kbdb unlearn id1 id2 id3
|
|
1072
|
+
`,
|
|
1073
|
+
search: `kbdb search - Query the knowledge base
|
|
1074
|
+
|
|
1075
|
+
Usage: kbdb search [options] <query>...
|
|
1076
|
+
|
|
1077
|
+
Arguments:
|
|
1078
|
+
<query> One or more query terms
|
|
1079
|
+
|
|
1080
|
+
Options:
|
|
1081
|
+
--mode <mode> Result granularity (sections|documents|stats)
|
|
1082
|
+
--limit <n> Max results (default: 20)
|
|
1083
|
+
--format <fmt> Output format (json|text|mcp)
|
|
1084
|
+
--content, -c Hydrate results with section content
|
|
1085
|
+
--db <path> Path to .kbdb directory
|
|
1086
|
+
|
|
1087
|
+
Output:
|
|
1088
|
+
JSON array of { kbid, score, preview, matches }
|
|
1089
|
+
|
|
1090
|
+
Examples:
|
|
1091
|
+
kbdb search "machine learning"
|
|
1092
|
+
kbdb search --limit 5 --format text query
|
|
1093
|
+
kbdb search --mode documents --content term
|
|
1094
|
+
`,
|
|
1095
|
+
content: `kbdb content - Compose rendered content from ids
|
|
1096
|
+
|
|
1097
|
+
Usage: kbdb content [options] <id>...
|
|
1098
|
+
|
|
1099
|
+
Arguments:
|
|
1100
|
+
<id> kbid or docid identifier
|
|
1101
|
+
|
|
1102
|
+
Options:
|
|
1103
|
+
--db <path> Path to .kbdb directory
|
|
1104
|
+
|
|
1105
|
+
Output:
|
|
1106
|
+
JSON { type, data, total }
|
|
1107
|
+
|
|
1108
|
+
Examples:
|
|
1109
|
+
kbdb content abcdef1234567890abcdef1234
|
|
1110
|
+
kbdb content id1 id2
|
|
1111
|
+
`,
|
|
1112
|
+
check: `kbdb check - Verify knowledge base integrity
|
|
1113
|
+
|
|
1114
|
+
Usage: kbdb check [options]
|
|
1115
|
+
|
|
1116
|
+
Options:
|
|
1117
|
+
--db <path> Path to .kbdb directory
|
|
1118
|
+
|
|
1119
|
+
Output:
|
|
1120
|
+
JSON { ok, errors }
|
|
1121
|
+
|
|
1122
|
+
Examples:
|
|
1123
|
+
kbdb check
|
|
1124
|
+
kbdb check --db /path/to/project
|
|
1125
|
+
`,
|
|
1126
|
+
gc: `kbdb gc - Garbage collect unreferenced sections
|
|
1127
|
+
|
|
1128
|
+
Usage: kbdb gc [options]
|
|
1129
|
+
|
|
1130
|
+
Options:
|
|
1131
|
+
--db <path> Path to .kbdb directory
|
|
1132
|
+
|
|
1133
|
+
Output:
|
|
1134
|
+
JSON { removed_sections, removed_bytes }
|
|
1135
|
+
|
|
1136
|
+
Examples:
|
|
1137
|
+
kbdb gc
|
|
1138
|
+
kbdb gc --db /path/to/project
|
|
1139
|
+
`,
|
|
1140
|
+
rebuild: `kbdb rebuild - Reconstruct all index files
|
|
1141
|
+
|
|
1142
|
+
Usage: kbdb rebuild [options]
|
|
1143
|
+
|
|
1144
|
+
Options:
|
|
1145
|
+
--db <path> Path to .kbdb directory
|
|
1146
|
+
|
|
1147
|
+
Output:
|
|
1148
|
+
JSON { sections_reindexed, terms_indexed }
|
|
1149
|
+
|
|
1150
|
+
Examples:
|
|
1151
|
+
kbdb rebuild
|
|
1152
|
+
kbdb rebuild --db /path/to/project
|
|
1153
|
+
`,
|
|
1154
|
+
status: `kbdb status - Show database status
|
|
1155
|
+
|
|
1156
|
+
Usage: kbdb status [options]
|
|
1157
|
+
|
|
1158
|
+
Options:
|
|
1159
|
+
--db <path> Path to .kbdb directory
|
|
1160
|
+
|
|
1161
|
+
Output:
|
|
1162
|
+
JSON database status object
|
|
1163
|
+
|
|
1164
|
+
Examples:
|
|
1165
|
+
kbdb status
|
|
1166
|
+
kbdb status --db /path/to/project
|
|
1167
|
+
`,
|
|
1168
|
+
mcp: `kbdb mcp - Start MCP server mode (stdio)
|
|
1169
|
+
|
|
1170
|
+
Usage: kbdb mcp [options]
|
|
1171
|
+
|
|
1172
|
+
Options:
|
|
1173
|
+
--db <path> Path to .kbdb directory
|
|
1174
|
+
|
|
1175
|
+
Environment:
|
|
1176
|
+
KBDB_DIR Fallback database path
|
|
1177
|
+
|
|
1178
|
+
Examples:
|
|
1179
|
+
kbdb mcp --db /path/to/project
|
|
1180
|
+
KBDB_DIR=/path/to/project kbdb mcp
|
|
1181
|
+
`
|
|
1182
|
+
};
|
|
1183
|
+
var SUBCOMMAND_HELP = {
|
|
1184
|
+
"db-init": `kbdb db init - Initialise a new .kbdb directory
|
|
1185
|
+
|
|
1186
|
+
Usage: kbdb db init [options]
|
|
1187
|
+
|
|
1188
|
+
Options:
|
|
1189
|
+
--db <path> Path to create .kbdb in
|
|
1190
|
+
(default: current directory)
|
|
1191
|
+
-h, --help Show this help message
|
|
1192
|
+
|
|
1193
|
+
Output:
|
|
1194
|
+
JSON { path, created }
|
|
1195
|
+
|
|
1196
|
+
Examples:
|
|
1197
|
+
kbdb db init
|
|
1198
|
+
kbdb db init --db /path/to/project
|
|
1199
|
+
`,
|
|
1200
|
+
"db-migrate": `kbdb db migrate - Migrate database to current format
|
|
1201
|
+
|
|
1202
|
+
Usage: kbdb db migrate [options]
|
|
1203
|
+
|
|
1204
|
+
Options:
|
|
1205
|
+
--db <path> Path containing .kbdb
|
|
1206
|
+
(default: current directory)
|
|
1207
|
+
-h, --help Show this help message
|
|
1208
|
+
|
|
1209
|
+
Output:
|
|
1210
|
+
JSON MigrateResult or "already up to date"
|
|
1211
|
+
|
|
1212
|
+
Examples:
|
|
1213
|
+
kbdb db migrate
|
|
1214
|
+
kbdb db migrate --db /path/to/project
|
|
1215
|
+
`,
|
|
1216
|
+
"skill-learn": `kbdb skill learn - Create a new skill definition
|
|
1217
|
+
|
|
1218
|
+
Usage: kbdb skill learn [options] --name <n> --body <file|->
|
|
1219
|
+
|
|
1220
|
+
Options:
|
|
1221
|
+
--name <name> Skill name (required)
|
|
1222
|
+
--description <d> Skill description
|
|
1223
|
+
--body <file|-> Template body file or stdin (required)
|
|
1224
|
+
--db <path> Path to .kbdb directory
|
|
1225
|
+
|
|
1226
|
+
Output:
|
|
1227
|
+
JSON { kbid, name, arguments }
|
|
1228
|
+
|
|
1229
|
+
Examples:
|
|
1230
|
+
kbdb skill learn --name summarize --body prompt.txt
|
|
1231
|
+
cat body.txt | kbdb skill learn --name my-skill --body -
|
|
1232
|
+
`,
|
|
1233
|
+
"skill-list": `kbdb skill list - List all skills
|
|
1234
|
+
|
|
1235
|
+
Usage: kbdb skill list [options]
|
|
1236
|
+
|
|
1237
|
+
Options:
|
|
1238
|
+
--db <path> Path to .kbdb directory
|
|
1239
|
+
|
|
1240
|
+
Output:
|
|
1241
|
+
JSON array of { kbid, name, description, argumentCount }
|
|
1242
|
+
|
|
1243
|
+
Examples:
|
|
1244
|
+
kbdb skill list
|
|
1245
|
+
kbdb skill list --db /path/to/project
|
|
1246
|
+
`,
|
|
1247
|
+
"skill-get": `kbdb skill get - Retrieve a skill by name or kbid
|
|
1248
|
+
|
|
1249
|
+
Usage: kbdb skill get [options] <name-or-kbid>
|
|
1250
|
+
|
|
1251
|
+
Arguments:
|
|
1252
|
+
<name-or-kbid> Skill name or 26-char kbid
|
|
1253
|
+
|
|
1254
|
+
Options:
|
|
1255
|
+
--db <path> Path to .kbdb directory
|
|
1256
|
+
|
|
1257
|
+
Output:
|
|
1258
|
+
JSON SkillDefinition object
|
|
1259
|
+
|
|
1260
|
+
Examples:
|
|
1261
|
+
kbdb skill get summarize-document
|
|
1262
|
+
kbdb skill get abcdef1234567890abcdef1234
|
|
1263
|
+
`,
|
|
1264
|
+
"skill-delete": `kbdb skill delete - Remove a skill
|
|
1265
|
+
|
|
1266
|
+
Usage: kbdb skill delete [options] <kbid>
|
|
1267
|
+
|
|
1268
|
+
Arguments:
|
|
1269
|
+
<kbid> 26-character kbid of the skill to remove
|
|
1270
|
+
|
|
1271
|
+
Options:
|
|
1272
|
+
--db <path> Path to .kbdb directory
|
|
1273
|
+
|
|
1274
|
+
Output:
|
|
1275
|
+
JSON { kbid, removed }
|
|
1276
|
+
|
|
1277
|
+
Examples:
|
|
1278
|
+
kbdb skill delete abcdef1234567890abcdef1234
|
|
1279
|
+
`,
|
|
1280
|
+
"agent-create": `kbdb agent create - Create an agent with skill refs
|
|
1281
|
+
|
|
1282
|
+
Usage: kbdb agent create [options] --name <n> --persona <file|-> --skills <kbid,...>
|
|
1283
|
+
|
|
1284
|
+
Options:
|
|
1285
|
+
--name <name> Agent name (required)
|
|
1286
|
+
--description <d> Agent description
|
|
1287
|
+
--persona <file|-> Persona file or stdin (required)
|
|
1288
|
+
--skills <kbid,...> Comma-separated skill kbids (required)
|
|
1289
|
+
--db <path> Path to .kbdb directory
|
|
1290
|
+
|
|
1291
|
+
Output:
|
|
1292
|
+
JSON { docid, name, skills }
|
|
1293
|
+
|
|
1294
|
+
Examples:
|
|
1295
|
+
kbdb agent create --name code-reviewer --persona ./p.txt --skills abc123
|
|
1296
|
+
cat persona.txt | kbdb agent create --name my-agent --persona - --skills abc123
|
|
1297
|
+
`,
|
|
1298
|
+
"agent-list": `kbdb agent list - List all agents
|
|
1299
|
+
|
|
1300
|
+
Usage: kbdb agent list [options]
|
|
1301
|
+
|
|
1302
|
+
Options:
|
|
1303
|
+
--db <path> Path to .kbdb directory
|
|
1304
|
+
|
|
1305
|
+
Output:
|
|
1306
|
+
JSON array of { docid, name, description, skillCount }
|
|
1307
|
+
|
|
1308
|
+
Examples:
|
|
1309
|
+
kbdb agent list
|
|
1310
|
+
kbdb agent list --db /path/to/project
|
|
1311
|
+
`,
|
|
1312
|
+
"agent-get": `kbdb agent get - Retrieve an agent by docid
|
|
1313
|
+
|
|
1314
|
+
Usage: kbdb agent get [options] <docid>
|
|
1315
|
+
|
|
1316
|
+
Arguments:
|
|
1317
|
+
<docid> Agent document identifier
|
|
1318
|
+
|
|
1319
|
+
Options:
|
|
1320
|
+
--db <path> Path to .kbdb directory
|
|
1321
|
+
|
|
1322
|
+
Output:
|
|
1323
|
+
JSON AgentDefinition object with resolved skills
|
|
1324
|
+
|
|
1325
|
+
Examples:
|
|
1326
|
+
kbdb agent get agent-code-reviewer
|
|
1327
|
+
`,
|
|
1328
|
+
"agent-delete": `kbdb agent delete - Remove an agent
|
|
1329
|
+
|
|
1330
|
+
Usage: kbdb agent delete [options] <docid>
|
|
1331
|
+
|
|
1332
|
+
Arguments:
|
|
1333
|
+
<docid> Agent document identifier
|
|
1334
|
+
|
|
1335
|
+
Options:
|
|
1336
|
+
--db <path> Path to .kbdb directory
|
|
1337
|
+
|
|
1338
|
+
Output:
|
|
1339
|
+
JSON { docid, removed }
|
|
1340
|
+
|
|
1341
|
+
Examples:
|
|
1342
|
+
kbdb agent delete agent-code-reviewer
|
|
1343
|
+
`
|
|
1344
|
+
};
|
|
1345
|
+
function generateSubcommandHelp(command, subcommand) {
|
|
1346
|
+
const key = `${command}-${subcommand}`;
|
|
1347
|
+
const text = SUBCOMMAND_HELP[key];
|
|
1348
|
+
if (text) {
|
|
1349
|
+
return text;
|
|
1350
|
+
}
|
|
1351
|
+
return generateCommandHelp(command);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// src/shared/cli/functions/run-cli.function.ts
|
|
1355
|
+
async function runCli(argv, deps2) {
|
|
1356
|
+
const options = parseArgs(argv);
|
|
1357
|
+
if (options.command === "help" || !options.command) {
|
|
1358
|
+
const helpCommand = options.args[0];
|
|
1359
|
+
const helpSubcommand = options.args[1];
|
|
1360
|
+
const helpText = generateHelp(helpCommand, helpSubcommand);
|
|
1361
|
+
if (helpCommand && !isKnownCommand(helpCommand)) {
|
|
1362
|
+
return { output: helpText, exitCode: 1 };
|
|
1363
|
+
}
|
|
1364
|
+
return { output: helpText, exitCode: 0 };
|
|
1365
|
+
}
|
|
1366
|
+
if (options.command === "version") {
|
|
1367
|
+
return { output: VERSION, exitCode: 0 };
|
|
1368
|
+
}
|
|
1369
|
+
if (options.command === "init" || options.command === "db-init") {
|
|
1370
|
+
return handleInit(options, deps2);
|
|
1371
|
+
}
|
|
1372
|
+
if (options.command === "mcp") {
|
|
1373
|
+
return handleMcp(options, deps2);
|
|
1374
|
+
}
|
|
1375
|
+
if (options.command === "migrate" || options.command === "db-migrate") {
|
|
1376
|
+
return handleMigrate(options, deps2);
|
|
1377
|
+
}
|
|
1378
|
+
return handleDataCommand(options, deps2);
|
|
1379
|
+
}
|
|
1380
|
+
function handleInit(options, deps2) {
|
|
1381
|
+
const result = deps2.runInit(options);
|
|
1382
|
+
if (result.ok) {
|
|
1383
|
+
return {
|
|
1384
|
+
output: result.targetPath,
|
|
1385
|
+
exitCode: 0
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
return {
|
|
1389
|
+
error: `error: ${result.errorMessage ?? "init failed"}`,
|
|
1390
|
+
exitCode: 1
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
async function handleMcp(options, deps2) {
|
|
1394
|
+
const rawDbPath = options.dbPath ?? process.env["KBDB_DIR"];
|
|
1395
|
+
if (!rawDbPath) {
|
|
1396
|
+
return {
|
|
1397
|
+
error: "error: --db or KBDB_DIR required in MCP mode",
|
|
1398
|
+
exitCode: 1
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
const dbDir = deps2.findDb(rawDbPath);
|
|
1402
|
+
if (!dbDir) {
|
|
1403
|
+
return {
|
|
1404
|
+
error: `error: no .kbdb database found at ${rawDbPath}`,
|
|
1405
|
+
exitCode: 1
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
let client;
|
|
1409
|
+
try {
|
|
1410
|
+
client = await deps2.createWorkerClient({
|
|
1411
|
+
contextPath: dbDir
|
|
1412
|
+
});
|
|
1413
|
+
} catch (err) {
|
|
1414
|
+
return {
|
|
1415
|
+
error: `error: ${errorToMessage(err)}`,
|
|
1416
|
+
exitCode: 1
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
try {
|
|
1420
|
+
const gateResult = await versionGate(client, dbDir);
|
|
1421
|
+
if (gateResult) return gateResult;
|
|
1422
|
+
if (deps2.startMcpServer) {
|
|
1423
|
+
await deps2.startMcpServer(dbDir);
|
|
1424
|
+
}
|
|
1425
|
+
return { exitCode: 0 };
|
|
1426
|
+
} catch (err) {
|
|
1427
|
+
return {
|
|
1428
|
+
error: `error: mcp failed: ${errorToMessage(err)}`,
|
|
1429
|
+
exitCode: 1
|
|
1430
|
+
};
|
|
1431
|
+
} finally {
|
|
1432
|
+
client.disconnect();
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
async function handleMigrate(options, deps2) {
|
|
1436
|
+
const dbDir = deps2.findDb(options.dbPath);
|
|
1437
|
+
if (!dbDir) {
|
|
1438
|
+
const basePath = options.dbPath ?? process.cwd();
|
|
1439
|
+
return {
|
|
1440
|
+
error: `error: no .kbdb database found at ${basePath}`,
|
|
1441
|
+
exitCode: 1
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
let client;
|
|
1445
|
+
try {
|
|
1446
|
+
client = await deps2.createWorkerClient({
|
|
1447
|
+
contextPath: dbDir
|
|
1448
|
+
});
|
|
1449
|
+
} catch (err) {
|
|
1450
|
+
return {
|
|
1451
|
+
error: `error: ${errorToMessage(err)}`,
|
|
1452
|
+
exitCode: 1
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
try {
|
|
1456
|
+
const versionStatus = await client.checkVersion(dbDir);
|
|
1457
|
+
if (versionStatus.status === "too_new") {
|
|
1458
|
+
return {
|
|
1459
|
+
error: `error: database version ${versionStatus.currentVersion.toString()} is newer than kbdb version ${versionStatus.requiredVersion.toString()} -- upgrade kbdb`,
|
|
1460
|
+
exitCode: 1
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
if (versionStatus.status === "needs_migration") {
|
|
1464
|
+
const migrateResult = await client.migrateDatabase(dbDir);
|
|
1465
|
+
return {
|
|
1466
|
+
output: JSON.stringify(migrateResult, null, 2),
|
|
1467
|
+
exitCode: 0
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
return { output: "already up to date", exitCode: 0 };
|
|
1471
|
+
} catch (err) {
|
|
1472
|
+
return {
|
|
1473
|
+
error: `error: migrate failed: ${errorToMessage(err)}`,
|
|
1474
|
+
exitCode: 1
|
|
1475
|
+
};
|
|
1476
|
+
} finally {
|
|
1477
|
+
client.disconnect();
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
async function handleDataCommand(options, deps2) {
|
|
1481
|
+
let dbDir = deps2.findDb(options.dbPath);
|
|
1482
|
+
if (!dbDir) {
|
|
1483
|
+
const basePath = options.dbPath ?? process.cwd();
|
|
1484
|
+
if (!deps2.isStdinTty()) {
|
|
1485
|
+
return {
|
|
1486
|
+
error: `error: no .kbdb database found at ${basePath} -- run \`kbdb --init\` to create one`,
|
|
1487
|
+
exitCode: 1
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
const answer = await deps2.promptUser(
|
|
1491
|
+
`No .kbdb database found. Create one in ${basePath}? [y/N] `
|
|
1492
|
+
);
|
|
1493
|
+
if (answer.toLowerCase() !== "y") {
|
|
1494
|
+
return {
|
|
1495
|
+
error: "aborted: no database created",
|
|
1496
|
+
exitCode: 1
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
const initResult = deps2.runInit(options);
|
|
1500
|
+
if (!initResult.ok) {
|
|
1501
|
+
return {
|
|
1502
|
+
error: `error: ${initResult.errorMessage ?? "init failed"}`,
|
|
1503
|
+
exitCode: 1
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
dbDir = initResult.targetPath;
|
|
1507
|
+
}
|
|
1508
|
+
let client;
|
|
1509
|
+
try {
|
|
1510
|
+
client = await deps2.createWorkerClient({
|
|
1511
|
+
contextPath: dbDir
|
|
1512
|
+
});
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
return {
|
|
1515
|
+
error: `error: ${errorToMessage(err)}`,
|
|
1516
|
+
exitCode: 1
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
try {
|
|
1520
|
+
const gateResult = await versionGate(client, dbDir);
|
|
1521
|
+
if (gateResult) return gateResult;
|
|
1522
|
+
return await dispatchCommand(client, options);
|
|
1523
|
+
} finally {
|
|
1524
|
+
client.disconnect();
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
async function versionGate(client, dbDir) {
|
|
1528
|
+
const versionStatus = await client.checkVersion(dbDir);
|
|
1529
|
+
if (versionStatus.status === "needs_migration") {
|
|
1530
|
+
return {
|
|
1531
|
+
error: "error: database needs migration -- run `kbdb --migrate`",
|
|
1532
|
+
exitCode: 1
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
if (versionStatus.status === "too_new") {
|
|
1536
|
+
return {
|
|
1537
|
+
error: `error: database version ${versionStatus.currentVersion.toString()} is newer than kbdb version ${versionStatus.requiredVersion.toString()} -- upgrade kbdb`,
|
|
1538
|
+
exitCode: 1
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
return null;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// src/shared/cli/constants/help-text.constant.ts
|
|
1545
|
+
var HELP_TEXT = generateHelp();
|
|
1546
|
+
|
|
1547
|
+
// src/shared/worker-client/classes/worker-client.class.ts
|
|
1548
|
+
import { connect } from "node:net";
|
|
1549
|
+
var WorkerClient = class {
|
|
1550
|
+
/**
|
|
1551
|
+
* @param socketPath - absolute path to the daemon's IPC socket
|
|
1552
|
+
* (or Windows named pipe path)
|
|
1553
|
+
* @param contextId - 16-character context identifier sent as
|
|
1554
|
+
* `ctx` in every JSON-RPC request
|
|
1555
|
+
*/
|
|
1556
|
+
constructor(socketPath, contextId) {
|
|
1557
|
+
this.socketPath = socketPath;
|
|
1558
|
+
this.contextId = contextId;
|
|
1559
|
+
}
|
|
1560
|
+
/** Underlying socket; `null` when not connected. */
|
|
1561
|
+
socket = null;
|
|
1562
|
+
/** Monotonically increasing request ID counter. */
|
|
1563
|
+
nextId = 1;
|
|
1564
|
+
/** Map of outstanding request IDs to their resolve/reject pairs. */
|
|
1565
|
+
pending = /* @__PURE__ */ new Map();
|
|
1566
|
+
/** Partial line buffer for split TCP/IPC frames. */
|
|
1567
|
+
buffer = "";
|
|
1568
|
+
/**
|
|
1569
|
+
* Establishes the IPC connection to the worker daemon.
|
|
1570
|
+
*
|
|
1571
|
+
* @throws {Error} if the connection cannot be established
|
|
1572
|
+
*/
|
|
1573
|
+
async connect() {
|
|
1574
|
+
return new Promise((resolve4, reject) => {
|
|
1575
|
+
this.socket = connect(this.socketPath, () => {
|
|
1576
|
+
resolve4();
|
|
1577
|
+
});
|
|
1578
|
+
this.socket.on("error", (err) => {
|
|
1579
|
+
reject(err);
|
|
1580
|
+
});
|
|
1581
|
+
this.socket.on("data", (chunk) => {
|
|
1582
|
+
this.handleData(chunk.toString());
|
|
1583
|
+
});
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
/** Destroys the IPC socket and clears the connection state. */
|
|
1587
|
+
disconnect() {
|
|
1588
|
+
if (this.socket) {
|
|
1589
|
+
this.socket.destroy();
|
|
1590
|
+
this.socket = null;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Searches the knowledge base.
|
|
1595
|
+
*
|
|
1596
|
+
* @param params - query parameters including the search string
|
|
1597
|
+
* @returns ranked list of matching sections
|
|
1598
|
+
*/
|
|
1599
|
+
async search(params) {
|
|
1600
|
+
return this.call("search", params);
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Adds a new section to the knowledge base.
|
|
1604
|
+
*
|
|
1605
|
+
* @param params - section content and metadata
|
|
1606
|
+
* @returns the result including the assigned knowledge-base
|
|
1607
|
+
* identifier and indexing statistics
|
|
1608
|
+
*/
|
|
1609
|
+
async addSection(params) {
|
|
1610
|
+
return this.call(
|
|
1611
|
+
"addSection",
|
|
1612
|
+
params
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Replaces an existing section's content and metadata.
|
|
1617
|
+
*
|
|
1618
|
+
* @param kbid - identifier of the section to update
|
|
1619
|
+
* @param params - new content and metadata
|
|
1620
|
+
* @returns the knowledge-base identifier of the updated section
|
|
1621
|
+
*/
|
|
1622
|
+
async updateSection(kbid, params) {
|
|
1623
|
+
return this.call("updateSection", {
|
|
1624
|
+
kbid,
|
|
1625
|
+
...params
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Removes a section from the knowledge base.
|
|
1630
|
+
*
|
|
1631
|
+
* @param kbid - identifier of the section to remove
|
|
1632
|
+
* @returns removal result with `removed` flag and elapsed time
|
|
1633
|
+
*/
|
|
1634
|
+
async removeSection(kbid) {
|
|
1635
|
+
return this.call("removeSection", {
|
|
1636
|
+
kbid
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Retrieves multiple sections by their identifiers.
|
|
1641
|
+
*
|
|
1642
|
+
* @param kbids - list of knowledge-base identifiers to fetch
|
|
1643
|
+
* @returns sections in the order their IDs were requested
|
|
1644
|
+
*/
|
|
1645
|
+
async readSections(kbids) {
|
|
1646
|
+
return this.call("readSections", {
|
|
1647
|
+
kbids
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Groups a set of sections under a named document.
|
|
1652
|
+
*
|
|
1653
|
+
* @param title - human-readable document title
|
|
1654
|
+
* @param kbids - identifiers of the sections to group
|
|
1655
|
+
* @param docType - application-level document type tag; omit or
|
|
1656
|
+
* pass an empty string for untagged documents
|
|
1657
|
+
* @returns the assigned document identifier
|
|
1658
|
+
*/
|
|
1659
|
+
async groupSections(title, kbids, docType) {
|
|
1660
|
+
const result = await this.call("groupSections", {
|
|
1661
|
+
title,
|
|
1662
|
+
kbids,
|
|
1663
|
+
docType: docType ?? ""
|
|
1664
|
+
});
|
|
1665
|
+
return typeof result === "string" ? result : result.docid;
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Removes the document grouping for the given document.
|
|
1669
|
+
*
|
|
1670
|
+
* The sections themselves are not deleted; only the grouping
|
|
1671
|
+
* record is removed.
|
|
1672
|
+
*
|
|
1673
|
+
* @param docid - identifier of the document grouping to remove
|
|
1674
|
+
*/
|
|
1675
|
+
async removeGrouping(docid) {
|
|
1676
|
+
await this.call("removeGrouping", { docid });
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Retrieves a full document record including its sections.
|
|
1680
|
+
*
|
|
1681
|
+
* @param docid - identifier of the document to retrieve
|
|
1682
|
+
* @returns the document record as returned by the daemon
|
|
1683
|
+
*/
|
|
1684
|
+
async retrieveDocument(docid) {
|
|
1685
|
+
return this.call("retrieveDocument", { docid });
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Composes a rendered Markdown document from one or more kbid
|
|
1689
|
+
* or docid identifiers.
|
|
1690
|
+
*
|
|
1691
|
+
* @param ids - list of kbid or docid identifiers (may be mixed)
|
|
1692
|
+
* @returns composed Markdown result with character count
|
|
1693
|
+
*/
|
|
1694
|
+
async content(ids) {
|
|
1695
|
+
return this.call("content", { ids });
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Runs an integrity check on the knowledge-base database.
|
|
1699
|
+
*
|
|
1700
|
+
* @returns a report of all issues found; `ok` is `true` when
|
|
1701
|
+
* no errors were detected
|
|
1702
|
+
*/
|
|
1703
|
+
async integrityCheck() {
|
|
1704
|
+
return this.call(
|
|
1705
|
+
"integrityCheck",
|
|
1706
|
+
{}
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Removes unreferenced sections from the database.
|
|
1711
|
+
*
|
|
1712
|
+
* @returns a report of sections removed and bytes freed
|
|
1713
|
+
*/
|
|
1714
|
+
async gc() {
|
|
1715
|
+
return this.call("gc", {});
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Reconstructs all index files from section files and document
|
|
1719
|
+
* manifests on disk. Text and code sections are re-tokenized;
|
|
1720
|
+
* image sections are skipped.
|
|
1721
|
+
*
|
|
1722
|
+
* @returns a report of sections and terms re-indexed
|
|
1723
|
+
*/
|
|
1724
|
+
async rebuildIndexes() {
|
|
1725
|
+
return this.call("rebuildIndexes", {});
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Invalidates the in-memory cache entry for a single section.
|
|
1729
|
+
*
|
|
1730
|
+
* @param kbid - identifier of the section to evict from cache
|
|
1731
|
+
*/
|
|
1732
|
+
async invalidate(kbid) {
|
|
1733
|
+
await this.call("invalidate", { kbid });
|
|
1734
|
+
}
|
|
1735
|
+
/** Clears all entries from the daemon's in-memory cache. */
|
|
1736
|
+
async invalidateAll() {
|
|
1737
|
+
await this.call("invalidateAll", {});
|
|
1738
|
+
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Retrieves diagnostic status information from the daemon.
|
|
1741
|
+
*
|
|
1742
|
+
* @returns current initialization state and cache statistics
|
|
1743
|
+
*/
|
|
1744
|
+
async status() {
|
|
1745
|
+
return this.call("status", {});
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Returns database metadata and status from the daemon,
|
|
1749
|
+
* including document count, section count, index size, and
|
|
1750
|
+
* cache statistics.
|
|
1751
|
+
*
|
|
1752
|
+
* @returns database metadata from the daemon's cached state
|
|
1753
|
+
*/
|
|
1754
|
+
async dbStatus() {
|
|
1755
|
+
return this.call("dbStatus", {});
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Initialises a new `.kbdb` database directory at the given path
|
|
1759
|
+
* by sending an init request to the worker daemon.
|
|
1760
|
+
*
|
|
1761
|
+
* The daemon creates all required subdirectories and seed files via
|
|
1762
|
+
* the `worker_init_directory` WASM export.
|
|
1763
|
+
*
|
|
1764
|
+
* @param targetPath - absolute path to the directory that will
|
|
1765
|
+
* contain the new `.kbdb` database
|
|
1766
|
+
* @throws {Error} if the `.kbdb` directory already exists or the
|
|
1767
|
+
* daemon cannot create the layout
|
|
1768
|
+
*/
|
|
1769
|
+
async initDirectory(targetPath) {
|
|
1770
|
+
await this.call("initDirectory", { targetPath });
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Runs all pending database migrations for the `.kbdb` directory
|
|
1774
|
+
* at the given path.
|
|
1775
|
+
*
|
|
1776
|
+
* Delegates to the `worker_migrate` WASM export on the daemon.
|
|
1777
|
+
* Each migration step updates `catalog.toml` on success, so
|
|
1778
|
+
* retrying after a partial failure is safe.
|
|
1779
|
+
*
|
|
1780
|
+
* @param targetPath - absolute path to the `.kbdb` database root
|
|
1781
|
+
* @returns migration report with old version, new version, and
|
|
1782
|
+
* number of migration steps applied
|
|
1783
|
+
*/
|
|
1784
|
+
async migrateDatabase(targetPath) {
|
|
1785
|
+
return this.call("migrateDatabase", {
|
|
1786
|
+
targetPath
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Checks the format version of the `.kbdb` database at the given
|
|
1791
|
+
* path against the version required by the current WASM engine.
|
|
1792
|
+
*
|
|
1793
|
+
* This is a read-only operation: it reads `catalog.toml` and
|
|
1794
|
+
* returns the compatibility status without making any changes.
|
|
1795
|
+
*
|
|
1796
|
+
* @param targetPath - absolute path to the `.kbdb` database root
|
|
1797
|
+
* @returns version compatibility report
|
|
1798
|
+
*/
|
|
1799
|
+
async checkVersion(targetPath) {
|
|
1800
|
+
return this.call("checkVersion", {
|
|
1801
|
+
targetPath
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Retrieves all sections whose type name matches the given string.
|
|
1806
|
+
*
|
|
1807
|
+
* @param sectionType - the application-level type name to filter by
|
|
1808
|
+
* @returns all section records with a matching type name
|
|
1809
|
+
*/
|
|
1810
|
+
async listByType(sectionType) {
|
|
1811
|
+
return this.call("listByType", {
|
|
1812
|
+
sectionType
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Retrieves all documents whose type name matches the given string.
|
|
1817
|
+
*
|
|
1818
|
+
* @param docType - the application-level document type to filter by
|
|
1819
|
+
* @returns all document manifests with a matching type name
|
|
1820
|
+
*/
|
|
1821
|
+
async listDocumentsByType(docType) {
|
|
1822
|
+
return this.call("listDocumentsByType", {
|
|
1823
|
+
docType
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Sends a JSON-RPC 2.0 request and awaits the response.
|
|
1828
|
+
*
|
|
1829
|
+
* @param method - the RPC method name
|
|
1830
|
+
* @param params - parameters to include in the request
|
|
1831
|
+
* @throws {Error} if not connected
|
|
1832
|
+
* @throws {Error} when the daemon returns an error response
|
|
1833
|
+
*/
|
|
1834
|
+
async call(method, params) {
|
|
1835
|
+
const socket = this.socket;
|
|
1836
|
+
if (!socket) {
|
|
1837
|
+
throw new Error("not connected");
|
|
1838
|
+
}
|
|
1839
|
+
const id = this.nextId++;
|
|
1840
|
+
const request = {
|
|
1841
|
+
jsonrpc: "2.0",
|
|
1842
|
+
id,
|
|
1843
|
+
method,
|
|
1844
|
+
params: { ctx: this.contextId, ...params }
|
|
1845
|
+
};
|
|
1846
|
+
return new Promise((resolve4, reject) => {
|
|
1847
|
+
this.pending.set(id, { resolve: resolve4, reject });
|
|
1848
|
+
socket.write(JSON.stringify(request) + "\n");
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Processes incoming data from the socket, splitting on newlines
|
|
1853
|
+
* and dispatching complete JSON-RPC response objects.
|
|
1854
|
+
*
|
|
1855
|
+
* @param data - raw string chunk received from the socket
|
|
1856
|
+
*/
|
|
1857
|
+
handleData(data) {
|
|
1858
|
+
this.buffer += data;
|
|
1859
|
+
const lines = this.buffer.split("\n");
|
|
1860
|
+
this.buffer = lines.pop() ?? "";
|
|
1861
|
+
for (const line of lines) {
|
|
1862
|
+
if (!line.trim()) continue;
|
|
1863
|
+
try {
|
|
1864
|
+
const response = JSON.parse(line);
|
|
1865
|
+
const pending = this.pending.get(response.id);
|
|
1866
|
+
if (pending) {
|
|
1867
|
+
this.pending.delete(response.id);
|
|
1868
|
+
if (response.error) {
|
|
1869
|
+
const err = new Error(response.error.message);
|
|
1870
|
+
err.code = response.error.code;
|
|
1871
|
+
pending.reject(err);
|
|
1872
|
+
} else {
|
|
1873
|
+
pending.resolve(response.result);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
} catch {
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
};
|
|
1881
|
+
|
|
1882
|
+
// src/shared/worker-client/functions/create-worker-client.function.ts
|
|
1883
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, unlinkSync as unlinkSync2 } from "node:fs";
|
|
1884
|
+
import { join as join7 } from "node:path";
|
|
1885
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
1886
|
+
|
|
1887
|
+
// src/shared/worker-client/functions/resolve-db-path.function.ts
|
|
1888
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
1889
|
+
import { join as join4, resolve as resolve3 } from "node:path";
|
|
1890
|
+
function resolveDbPath(targetDir) {
|
|
1891
|
+
const base = targetDir ? resolve3(targetDir) : process.cwd();
|
|
1892
|
+
const dbPath = join4(base, ".kbdb");
|
|
1893
|
+
if (!existsSync3(dbPath)) {
|
|
1894
|
+
throw new Error(`database not found: ${dbPath}`);
|
|
1895
|
+
}
|
|
1896
|
+
return dbPath;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// src/shared/worker-client/functions/compute-context-id.function.ts
|
|
1900
|
+
async function computeContextId(absolutePath) {
|
|
1901
|
+
const hash = await computeSha256(absolutePath);
|
|
1902
|
+
return hash.slice(0, 16);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
// src/shared/worker-client/functions/discover-daemon.function.ts
|
|
1906
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, unlinkSync } from "node:fs";
|
|
1907
|
+
import { join as join5 } from "node:path";
|
|
1908
|
+
import { tmpdir } from "node:os";
|
|
1909
|
+
|
|
1910
|
+
// src/shared/platform/functions/is-process-alive.function.ts
|
|
1911
|
+
function isProcessAlive(pid) {
|
|
1912
|
+
try {
|
|
1913
|
+
process.kill(pid, 0);
|
|
1914
|
+
return true;
|
|
1915
|
+
} catch {
|
|
1916
|
+
return false;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
// src/shared/worker-client/functions/discover-daemon.function.ts
|
|
1921
|
+
function discoverDaemon(contextId) {
|
|
1922
|
+
const pidPath = join5(tmpdir(), `kbdb-${contextId}.pid`);
|
|
1923
|
+
if (!existsSync4(pidPath)) return null;
|
|
1924
|
+
const pidStr = readFileSync2(pidPath, "utf-8").trim();
|
|
1925
|
+
const pid = parseInt(pidStr, 10);
|
|
1926
|
+
if (isNaN(pid) || !isProcessAlive(pid)) {
|
|
1927
|
+
try {
|
|
1928
|
+
unlinkSync(pidPath);
|
|
1929
|
+
} catch {
|
|
1930
|
+
}
|
|
1931
|
+
return null;
|
|
1932
|
+
}
|
|
1933
|
+
const socketPath = join5(tmpdir(), `kbdb-${contextId}.sock`);
|
|
1934
|
+
const crashPath = join5(tmpdir(), `kbdb-${contextId}.crash`);
|
|
1935
|
+
try {
|
|
1936
|
+
unlinkSync(crashPath);
|
|
1937
|
+
} catch {
|
|
1938
|
+
}
|
|
1939
|
+
return { pid, socketPath };
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
// src/shared/worker-client/functions/spawn-daemon.function.ts
|
|
1943
|
+
import { spawn } from "node:child_process";
|
|
1944
|
+
function spawnDaemon(contextPath, runtime2, workerScript2) {
|
|
1945
|
+
if (!workerScript2) {
|
|
1946
|
+
throw new Error(
|
|
1947
|
+
"workerScript must be provided (resolve at entry point)"
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
const execPath = runtime2 === "deno" ? "deno" : process.execPath;
|
|
1951
|
+
const args = runtime2 === "deno" ? ["run", "--allow-all", workerScript2, contextPath] : [workerScript2, contextPath];
|
|
1952
|
+
const child = spawn(execPath, args, {
|
|
1953
|
+
detached: true,
|
|
1954
|
+
stdio: "ignore"
|
|
1955
|
+
});
|
|
1956
|
+
child.unref();
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
// src/shared/worker-client/functions/wait-for-daemon.function.ts
|
|
1960
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
1961
|
+
import { join as join6 } from "node:path";
|
|
1962
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
1963
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
1964
|
+
var POLL_INTERVAL_MS = 100;
|
|
1965
|
+
async function waitForDaemon(contextId, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
1966
|
+
const pidPath = join6(tmpdir2(), `kbdb-${contextId}.pid`);
|
|
1967
|
+
const start = Date.now();
|
|
1968
|
+
while (Date.now() - start < timeoutMs) {
|
|
1969
|
+
if (existsSync5(pidPath)) return true;
|
|
1970
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1971
|
+
}
|
|
1972
|
+
return false;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
// src/shared/worker-client/functions/create-worker-client.function.ts
|
|
1976
|
+
async function createWorkerClient(options) {
|
|
1977
|
+
const dbPath = options?.contextPath ?? resolveDbPath(options?.dbPath);
|
|
1978
|
+
const contextId = await computeContextId(dbPath);
|
|
1979
|
+
const socketPath = getIpcPath(contextId);
|
|
1980
|
+
let daemon = discoverDaemon(contextId);
|
|
1981
|
+
if (!daemon && options?.autoSpawn !== false) {
|
|
1982
|
+
const runtime2 = detectRuntime();
|
|
1983
|
+
spawnDaemon(dbPath, runtime2, options?.workerScript);
|
|
1984
|
+
await waitForDaemon(contextId, options?.connectTimeoutMs);
|
|
1985
|
+
daemon = discoverDaemon(contextId);
|
|
1986
|
+
}
|
|
1987
|
+
if (!daemon) {
|
|
1988
|
+
throw new Error(
|
|
1989
|
+
`kbdb worker daemon did not start: ${readCrashReason(contextId)}`
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
const client = new WorkerClient(socketPath, contextId);
|
|
1993
|
+
await client.connect();
|
|
1994
|
+
return client;
|
|
1995
|
+
}
|
|
1996
|
+
function readCrashReason(contextId) {
|
|
1997
|
+
const crashPath = join7(tmpdir3(), `kbdb-${contextId}.crash`);
|
|
1998
|
+
if (!existsSync6(crashPath)) {
|
|
1999
|
+
return "daemon failed to start (no details available)";
|
|
2000
|
+
}
|
|
2001
|
+
try {
|
|
2002
|
+
const raw = readFileSync3(crashPath, "utf-8");
|
|
2003
|
+
const crash = JSON.parse(raw);
|
|
2004
|
+
unlinkSync2(crashPath);
|
|
2005
|
+
return crash.error ?? "unknown error (crash log empty)";
|
|
2006
|
+
} catch {
|
|
2007
|
+
return "daemon failed to start (crash log unreadable)";
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
// src/shared/mcp/classes/mcp-server.class.ts
|
|
2012
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
2013
|
+
|
|
2014
|
+
// src/shared/mcp/functions/create-tool-definitions.function.ts
|
|
2015
|
+
function createToolDefinitions() {
|
|
2016
|
+
return [
|
|
2017
|
+
{
|
|
2018
|
+
name: "search",
|
|
2019
|
+
description: "Search the knowledge base for relevant sections using natural language queries.",
|
|
2020
|
+
inputSchema: {
|
|
2021
|
+
type: "object",
|
|
2022
|
+
properties: {
|
|
2023
|
+
query: {
|
|
2024
|
+
type: "string",
|
|
2025
|
+
description: "Search query text"
|
|
2026
|
+
},
|
|
2027
|
+
mode: {
|
|
2028
|
+
type: "string",
|
|
2029
|
+
enum: ["sections", "documents", "stats"],
|
|
2030
|
+
description: "Search mode (default: sections)"
|
|
2031
|
+
},
|
|
2032
|
+
limit: {
|
|
2033
|
+
type: "number",
|
|
2034
|
+
description: "Maximum results (default: 20)"
|
|
2035
|
+
}
|
|
2036
|
+
},
|
|
2037
|
+
required: ["query"]
|
|
2038
|
+
},
|
|
2039
|
+
annotations: {
|
|
2040
|
+
title: "Search KB",
|
|
2041
|
+
readOnlyHint: true,
|
|
2042
|
+
destructiveHint: false,
|
|
2043
|
+
idempotentHint: true
|
|
2044
|
+
}
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
name: "learn",
|
|
2048
|
+
description: "Add a text section to the knowledge base.",
|
|
2049
|
+
inputSchema: {
|
|
2050
|
+
type: "object",
|
|
2051
|
+
properties: {
|
|
2052
|
+
content: {
|
|
2053
|
+
type: "string",
|
|
2054
|
+
description: "Text content to add"
|
|
2055
|
+
},
|
|
2056
|
+
type: {
|
|
2057
|
+
type: "string",
|
|
2058
|
+
description: "MIME type (default: text/markdown). Use image/* for images."
|
|
2059
|
+
},
|
|
2060
|
+
title: {
|
|
2061
|
+
type: "string",
|
|
2062
|
+
description: "Section title. Required for image/* types."
|
|
2063
|
+
},
|
|
2064
|
+
description: {
|
|
2065
|
+
type: "string",
|
|
2066
|
+
description: "Optional section description"
|
|
2067
|
+
},
|
|
2068
|
+
docid: {
|
|
2069
|
+
type: "string",
|
|
2070
|
+
description: "Document ID to group under"
|
|
2071
|
+
}
|
|
2072
|
+
},
|
|
2073
|
+
required: ["content"]
|
|
2074
|
+
},
|
|
2075
|
+
annotations: {
|
|
2076
|
+
title: "Import Content",
|
|
2077
|
+
readOnlyHint: false,
|
|
2078
|
+
destructiveHint: false,
|
|
2079
|
+
idempotentHint: true
|
|
2080
|
+
}
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
name: "unlearn",
|
|
2084
|
+
description: "Remove a section from the knowledge base by its kb-id.",
|
|
2085
|
+
inputSchema: {
|
|
2086
|
+
type: "object",
|
|
2087
|
+
properties: {
|
|
2088
|
+
kbid: {
|
|
2089
|
+
type: "string",
|
|
2090
|
+
description: "Knowledge base ID of the section"
|
|
2091
|
+
}
|
|
2092
|
+
},
|
|
2093
|
+
required: ["kbid"]
|
|
2094
|
+
},
|
|
2095
|
+
annotations: {
|
|
2096
|
+
title: "Remove Section",
|
|
2097
|
+
readOnlyHint: false,
|
|
2098
|
+
destructiveHint: true,
|
|
2099
|
+
idempotentHint: true
|
|
2100
|
+
}
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
name: "retrieve",
|
|
2104
|
+
description: "Retrieve a section or document by ID. Provide kbid or docid.",
|
|
2105
|
+
inputSchema: {
|
|
2106
|
+
type: "object",
|
|
2107
|
+
properties: {
|
|
2108
|
+
kbid: {
|
|
2109
|
+
type: "string",
|
|
2110
|
+
description: "Section kb-id"
|
|
2111
|
+
},
|
|
2112
|
+
docid: {
|
|
2113
|
+
type: "string",
|
|
2114
|
+
description: "Document ID"
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
},
|
|
2118
|
+
annotations: {
|
|
2119
|
+
title: "Fetch Content",
|
|
2120
|
+
readOnlyHint: true,
|
|
2121
|
+
destructiveHint: false,
|
|
2122
|
+
idempotentHint: true
|
|
2123
|
+
}
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
name: "status",
|
|
2127
|
+
description: "Get database metadata including document count, section count, index size, and cache statistics.",
|
|
2128
|
+
inputSchema: {
|
|
2129
|
+
type: "object",
|
|
2130
|
+
properties: {}
|
|
2131
|
+
},
|
|
2132
|
+
annotations: {
|
|
2133
|
+
title: "DB Status",
|
|
2134
|
+
readOnlyHint: true,
|
|
2135
|
+
destructiveHint: false,
|
|
2136
|
+
idempotentHint: true
|
|
2137
|
+
}
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
name: "content",
|
|
2141
|
+
description: "Compose a rendered Markdown document from one or more kbid or docid identifiers.",
|
|
2142
|
+
inputSchema: {
|
|
2143
|
+
type: "object",
|
|
2144
|
+
properties: {
|
|
2145
|
+
ids: {
|
|
2146
|
+
type: "array",
|
|
2147
|
+
items: { type: "string" },
|
|
2148
|
+
description: "One or more kbid or docid identifiers (may be mixed)"
|
|
2149
|
+
}
|
|
2150
|
+
},
|
|
2151
|
+
required: ["ids"]
|
|
2152
|
+
},
|
|
2153
|
+
annotations: {
|
|
2154
|
+
title: "Compose Content",
|
|
2155
|
+
readOnlyHint: true,
|
|
2156
|
+
destructiveHint: false,
|
|
2157
|
+
idempotentHint: true
|
|
2158
|
+
}
|
|
2159
|
+
},
|
|
2160
|
+
{
|
|
2161
|
+
name: "check",
|
|
2162
|
+
description: "Verify the integrity of the knowledge base. Reports checksum mismatches, orphan sections, broken references, and circular reference chains.",
|
|
2163
|
+
inputSchema: {
|
|
2164
|
+
type: "object",
|
|
2165
|
+
properties: {}
|
|
2166
|
+
},
|
|
2167
|
+
annotations: {
|
|
2168
|
+
title: "Integrity Check",
|
|
2169
|
+
readOnlyHint: true,
|
|
2170
|
+
destructiveHint: false,
|
|
2171
|
+
idempotentHint: true
|
|
2172
|
+
}
|
|
2173
|
+
},
|
|
2174
|
+
{
|
|
2175
|
+
name: "gc",
|
|
2176
|
+
description: "Remove unreferenced sections from the knowledge base. A section is eligible when no document manifest references it.",
|
|
2177
|
+
inputSchema: {
|
|
2178
|
+
type: "object",
|
|
2179
|
+
properties: {}
|
|
2180
|
+
},
|
|
2181
|
+
annotations: {
|
|
2182
|
+
title: "Garbage Collect",
|
|
2183
|
+
readOnlyHint: false,
|
|
2184
|
+
destructiveHint: true,
|
|
2185
|
+
idempotentHint: false
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
name: "rebuild",
|
|
2190
|
+
description: "Reconstruct all index files from section files and document manifests on disk. Use this to recover from index corruption.",
|
|
2191
|
+
inputSchema: {
|
|
2192
|
+
type: "object",
|
|
2193
|
+
properties: {}
|
|
2194
|
+
},
|
|
2195
|
+
annotations: {
|
|
2196
|
+
title: "Rebuild Indexes",
|
|
2197
|
+
readOnlyHint: false,
|
|
2198
|
+
destructiveHint: false,
|
|
2199
|
+
idempotentHint: false
|
|
2200
|
+
}
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
name: "skill-learn",
|
|
2204
|
+
description: "Create or update a skill definition. Skills are reusable AI agent capabilities with template placeholders.",
|
|
2205
|
+
inputSchema: {
|
|
2206
|
+
type: "object",
|
|
2207
|
+
properties: {
|
|
2208
|
+
name: {
|
|
2209
|
+
type: "string",
|
|
2210
|
+
description: "Skill name"
|
|
2211
|
+
},
|
|
2212
|
+
description: {
|
|
2213
|
+
type: "string",
|
|
2214
|
+
description: "Skill description"
|
|
2215
|
+
},
|
|
2216
|
+
body: {
|
|
2217
|
+
type: "string",
|
|
2218
|
+
description: "Skill body template. Use {{argName}} for placeholders."
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
required: ["name", "body"]
|
|
2222
|
+
},
|
|
2223
|
+
annotations: {
|
|
2224
|
+
title: "Create Skill",
|
|
2225
|
+
readOnlyHint: false,
|
|
2226
|
+
destructiveHint: false,
|
|
2227
|
+
idempotentHint: true
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
{
|
|
2231
|
+
name: "skill-list",
|
|
2232
|
+
description: "List all skills in the knowledge base.",
|
|
2233
|
+
inputSchema: {
|
|
2234
|
+
type: "object",
|
|
2235
|
+
properties: {}
|
|
2236
|
+
},
|
|
2237
|
+
annotations: {
|
|
2238
|
+
title: "List Skills",
|
|
2239
|
+
readOnlyHint: true,
|
|
2240
|
+
destructiveHint: false,
|
|
2241
|
+
idempotentHint: true
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
name: "skill-get",
|
|
2246
|
+
description: "Get a skill definition by name or kbid.",
|
|
2247
|
+
inputSchema: {
|
|
2248
|
+
type: "object",
|
|
2249
|
+
properties: {
|
|
2250
|
+
name: {
|
|
2251
|
+
type: "string",
|
|
2252
|
+
description: "Skill name"
|
|
2253
|
+
},
|
|
2254
|
+
kbid: {
|
|
2255
|
+
type: "string",
|
|
2256
|
+
description: "Knowledge base ID"
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
},
|
|
2260
|
+
annotations: {
|
|
2261
|
+
title: "Get Skill",
|
|
2262
|
+
readOnlyHint: true,
|
|
2263
|
+
destructiveHint: false,
|
|
2264
|
+
idempotentHint: true
|
|
2265
|
+
}
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
name: "skill-delete",
|
|
2269
|
+
description: "Delete a skill by its kbid.",
|
|
2270
|
+
inputSchema: {
|
|
2271
|
+
type: "object",
|
|
2272
|
+
properties: {
|
|
2273
|
+
kbid: {
|
|
2274
|
+
type: "string",
|
|
2275
|
+
description: "Knowledge base ID"
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
required: ["kbid"]
|
|
2279
|
+
},
|
|
2280
|
+
annotations: {
|
|
2281
|
+
title: "Delete Skill",
|
|
2282
|
+
readOnlyHint: false,
|
|
2283
|
+
destructiveHint: true,
|
|
2284
|
+
idempotentHint: true
|
|
2285
|
+
}
|
|
2286
|
+
},
|
|
2287
|
+
{
|
|
2288
|
+
name: "agent-create",
|
|
2289
|
+
description: "Create an AI agent with a persona and optional skill references.",
|
|
2290
|
+
inputSchema: {
|
|
2291
|
+
type: "object",
|
|
2292
|
+
properties: {
|
|
2293
|
+
name: {
|
|
2294
|
+
type: "string",
|
|
2295
|
+
description: "Agent name"
|
|
2296
|
+
},
|
|
2297
|
+
description: {
|
|
2298
|
+
type: "string",
|
|
2299
|
+
description: "Agent description"
|
|
2300
|
+
},
|
|
2301
|
+
persona: {
|
|
2302
|
+
type: "string",
|
|
2303
|
+
description: "Agent persona prompt"
|
|
2304
|
+
},
|
|
2305
|
+
skills: {
|
|
2306
|
+
type: "array",
|
|
2307
|
+
items: { type: "string" },
|
|
2308
|
+
description: "Skill kbid references to attach"
|
|
2309
|
+
}
|
|
2310
|
+
},
|
|
2311
|
+
required: ["name", "persona"]
|
|
2312
|
+
},
|
|
2313
|
+
annotations: {
|
|
2314
|
+
title: "Create Agent",
|
|
2315
|
+
readOnlyHint: false,
|
|
2316
|
+
destructiveHint: false,
|
|
2317
|
+
idempotentHint: true
|
|
2318
|
+
}
|
|
2319
|
+
},
|
|
2320
|
+
{
|
|
2321
|
+
name: "agent-list",
|
|
2322
|
+
description: "List all agents in the knowledge base.",
|
|
2323
|
+
inputSchema: {
|
|
2324
|
+
type: "object",
|
|
2325
|
+
properties: {}
|
|
2326
|
+
},
|
|
2327
|
+
annotations: {
|
|
2328
|
+
title: "List Agents",
|
|
2329
|
+
readOnlyHint: true,
|
|
2330
|
+
destructiveHint: false,
|
|
2331
|
+
idempotentHint: true
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
name: "agent-get",
|
|
2336
|
+
description: "Get an agent definition by document ID.",
|
|
2337
|
+
inputSchema: {
|
|
2338
|
+
type: "object",
|
|
2339
|
+
properties: {
|
|
2340
|
+
docid: {
|
|
2341
|
+
type: "string",
|
|
2342
|
+
description: "Document ID of the agent"
|
|
2343
|
+
}
|
|
2344
|
+
},
|
|
2345
|
+
required: ["docid"]
|
|
2346
|
+
},
|
|
2347
|
+
annotations: {
|
|
2348
|
+
title: "Get Agent",
|
|
2349
|
+
readOnlyHint: true,
|
|
2350
|
+
destructiveHint: false,
|
|
2351
|
+
idempotentHint: true
|
|
2352
|
+
}
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
name: "agent-delete",
|
|
2356
|
+
description: "Delete an agent by its document ID. Skill sections are not removed.",
|
|
2357
|
+
inputSchema: {
|
|
2358
|
+
type: "object",
|
|
2359
|
+
properties: {
|
|
2360
|
+
docid: {
|
|
2361
|
+
type: "string",
|
|
2362
|
+
description: "Document ID of the agent"
|
|
2363
|
+
}
|
|
2364
|
+
},
|
|
2365
|
+
required: ["docid"]
|
|
2366
|
+
},
|
|
2367
|
+
annotations: {
|
|
2368
|
+
title: "Delete Agent",
|
|
2369
|
+
readOnlyHint: false,
|
|
2370
|
+
destructiveHint: true,
|
|
2371
|
+
idempotentHint: true
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
];
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
// src/shared/mcp/functions/create-resource-templates.function.ts
|
|
2378
|
+
function createResourceTemplates() {
|
|
2379
|
+
return [
|
|
2380
|
+
{
|
|
2381
|
+
uriTemplate: "kbdb://section/{kb_id}",
|
|
2382
|
+
name: "Section",
|
|
2383
|
+
description: "A knowledge base section by its kb-id.",
|
|
2384
|
+
mimeType: "text/plain"
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
uriTemplate: "kbdb://document/{doc_id}",
|
|
2388
|
+
name: "Document",
|
|
2389
|
+
description: "A document with its ordered sections.",
|
|
2390
|
+
mimeType: "application/json"
|
|
2391
|
+
}
|
|
2392
|
+
];
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
// src/shared/mcp/functions/handle-agent-create.function.ts
|
|
2396
|
+
function asString(value, fallback) {
|
|
2397
|
+
return typeof value === "string" ? value : fallback;
|
|
2398
|
+
}
|
|
2399
|
+
function asStringArray(value) {
|
|
2400
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
2401
|
+
return value;
|
|
2402
|
+
}
|
|
2403
|
+
return [];
|
|
2404
|
+
}
|
|
2405
|
+
async function handleAgentCreate(client, args) {
|
|
2406
|
+
const name = asString(args["name"], "");
|
|
2407
|
+
const description = asString(args["description"], "");
|
|
2408
|
+
const persona = asString(args["persona"], "");
|
|
2409
|
+
const skills = asStringArray(args["skills"]);
|
|
2410
|
+
if (!name) {
|
|
2411
|
+
return {
|
|
2412
|
+
content: [{ type: "text", text: "name is required" }],
|
|
2413
|
+
isError: true
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
if (!persona) {
|
|
2417
|
+
return {
|
|
2418
|
+
content: [{ type: "text", text: "persona is required" }],
|
|
2419
|
+
isError: true
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
if (skills.length > 0) {
|
|
2423
|
+
const sections = await client.readSections(skills);
|
|
2424
|
+
const found = new Set(sections.map((s) => s.kbid));
|
|
2425
|
+
const missing = skills.filter((k) => !found.has(k));
|
|
2426
|
+
if (missing.length > 0) {
|
|
2427
|
+
return {
|
|
2428
|
+
content: [
|
|
2429
|
+
{
|
|
2430
|
+
type: "text",
|
|
2431
|
+
text: `skill not found: ${missing.join(", ")}`
|
|
2432
|
+
}
|
|
2433
|
+
],
|
|
2434
|
+
isError: true
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
const metadata = JSON.stringify({ name, description, persona });
|
|
2439
|
+
const metaResult = await client.addSection({
|
|
2440
|
+
sectionType: "text",
|
|
2441
|
+
content: metadata,
|
|
2442
|
+
title: name,
|
|
2443
|
+
description
|
|
2444
|
+
});
|
|
2445
|
+
const allKbids = [metaResult.kbid, ...skills];
|
|
2446
|
+
const docid = await client.groupSections(name, allKbids);
|
|
2447
|
+
return {
|
|
2448
|
+
content: [
|
|
2449
|
+
{
|
|
2450
|
+
type: "text",
|
|
2451
|
+
text: JSON.stringify({
|
|
2452
|
+
docid,
|
|
2453
|
+
name,
|
|
2454
|
+
skillCount: skills.length
|
|
2455
|
+
})
|
|
2456
|
+
}
|
|
2457
|
+
]
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
// src/shared/mcp/functions/handle-agent-list.function.ts
|
|
2462
|
+
async function handleAgentList(client) {
|
|
2463
|
+
const docs = await client.listDocumentsByType("agent");
|
|
2464
|
+
const items = docs.map((d) => ({
|
|
2465
|
+
docid: d.docid,
|
|
2466
|
+
name: d.title,
|
|
2467
|
+
skillCount: Math.max(0, d.sections.length - 1)
|
|
2468
|
+
}));
|
|
2469
|
+
return {
|
|
2470
|
+
content: [
|
|
2471
|
+
{
|
|
2472
|
+
type: "text",
|
|
2473
|
+
text: JSON.stringify(items, null, 2)
|
|
2474
|
+
}
|
|
2475
|
+
]
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
// src/shared/mcp/functions/handle-agent-get.function.ts
|
|
2480
|
+
async function readAgentMeta2(client, metaKbid, fallbackName) {
|
|
2481
|
+
const metaSections = await client.readSections([metaKbid]);
|
|
2482
|
+
const first = metaSections.at(0);
|
|
2483
|
+
if (!first) {
|
|
2484
|
+
return { name: fallbackName, description: "", persona: "" };
|
|
2485
|
+
}
|
|
2486
|
+
try {
|
|
2487
|
+
const meta = JSON.parse(first.content);
|
|
2488
|
+
return {
|
|
2489
|
+
name: typeof meta["name"] === "string" ? meta["name"] : fallbackName,
|
|
2490
|
+
description: typeof meta["description"] === "string" ? meta["description"] : "",
|
|
2491
|
+
persona: typeof meta["persona"] === "string" ? meta["persona"] : ""
|
|
2492
|
+
};
|
|
2493
|
+
} catch {
|
|
2494
|
+
return { name: fallbackName, description: "", persona: "" };
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
async function resolveSkillRefs(client, skillRefs) {
|
|
2498
|
+
if (skillRefs.length === 0) {
|
|
2499
|
+
return [];
|
|
2500
|
+
}
|
|
2501
|
+
const skillKbids = skillRefs.map((s) => s.kbid);
|
|
2502
|
+
const skillSections = await client.readSections(skillKbids);
|
|
2503
|
+
const sectionMap = new Map(skillSections.map((s) => [s.kbid, s]));
|
|
2504
|
+
return skillRefs.map((ref) => {
|
|
2505
|
+
const sec = sectionMap.get(ref.kbid);
|
|
2506
|
+
if (!sec) {
|
|
2507
|
+
return { kbid: ref.kbid, name: null, position: ref.position };
|
|
2508
|
+
}
|
|
2509
|
+
try {
|
|
2510
|
+
const parsed = JSON.parse(sec.content);
|
|
2511
|
+
const skillName = typeof parsed["name"] === "string" ? parsed["name"] : null;
|
|
2512
|
+
return {
|
|
2513
|
+
kbid: ref.kbid,
|
|
2514
|
+
name: skillName,
|
|
2515
|
+
position: ref.position
|
|
2516
|
+
};
|
|
2517
|
+
} catch {
|
|
2518
|
+
return { kbid: ref.kbid, name: null, position: ref.position };
|
|
2519
|
+
}
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
async function handleAgentGet(client, args) {
|
|
2523
|
+
const docid = typeof args["docid"] === "string" ? args["docid"] : "";
|
|
2524
|
+
if (!docid) {
|
|
2525
|
+
return {
|
|
2526
|
+
content: [{ type: "text", text: "docid is required" }],
|
|
2527
|
+
isError: true
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
const doc = await client.retrieveDocument(docid);
|
|
2531
|
+
const metaKbid = doc.sections[0]?.kbid;
|
|
2532
|
+
const skillRefs = doc.sections.slice(1);
|
|
2533
|
+
const { name, description, persona } = metaKbid ? await readAgentMeta2(client, metaKbid, doc.title) : { name: doc.title, description: "", persona: "" };
|
|
2534
|
+
const skills = await resolveSkillRefs(client, skillRefs);
|
|
2535
|
+
const agent = {
|
|
2536
|
+
docid,
|
|
2537
|
+
name,
|
|
2538
|
+
description,
|
|
2539
|
+
persona,
|
|
2540
|
+
skills
|
|
2541
|
+
};
|
|
2542
|
+
return {
|
|
2543
|
+
content: [
|
|
2544
|
+
{
|
|
2545
|
+
type: "text",
|
|
2546
|
+
text: JSON.stringify(agent, null, 2)
|
|
2547
|
+
}
|
|
2548
|
+
]
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
// src/shared/mcp/functions/handle-agent-delete.function.ts
|
|
2553
|
+
async function handleAgentDelete(client, args) {
|
|
2554
|
+
const docid = typeof args["docid"] === "string" ? args["docid"] : "";
|
|
2555
|
+
if (!docid) {
|
|
2556
|
+
return {
|
|
2557
|
+
content: [{ type: "text", text: "docid is required" }],
|
|
2558
|
+
isError: true
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
await client.removeGrouping(docid);
|
|
2562
|
+
return {
|
|
2563
|
+
content: [
|
|
2564
|
+
{
|
|
2565
|
+
type: "text",
|
|
2566
|
+
text: JSON.stringify({ docid, removed: true })
|
|
2567
|
+
}
|
|
2568
|
+
]
|
|
2569
|
+
};
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
// src/shared/mcp/functions/handle-tool-call.function.ts
|
|
2573
|
+
function asString2(value, fallback) {
|
|
2574
|
+
return typeof value === "string" ? value : fallback;
|
|
2575
|
+
}
|
|
2576
|
+
function asStringArray2(value) {
|
|
2577
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
2578
|
+
return value;
|
|
2579
|
+
}
|
|
2580
|
+
return [];
|
|
2581
|
+
}
|
|
2582
|
+
async function handleToolCall(client, name, args) {
|
|
2583
|
+
try {
|
|
2584
|
+
switch (name) {
|
|
2585
|
+
case "search":
|
|
2586
|
+
return await handleSearch2(client, args);
|
|
2587
|
+
case "learn":
|
|
2588
|
+
return await handleLearn2(client, args);
|
|
2589
|
+
case "unlearn":
|
|
2590
|
+
return await handleUnlearn2(client, args);
|
|
2591
|
+
case "retrieve":
|
|
2592
|
+
return await handleRetrieve(client, args);
|
|
2593
|
+
case "status":
|
|
2594
|
+
return await handleStatus2(client);
|
|
2595
|
+
case "content":
|
|
2596
|
+
return await handleContent2(client, args);
|
|
2597
|
+
case "check":
|
|
2598
|
+
return await handleCheck2(client);
|
|
2599
|
+
case "gc":
|
|
2600
|
+
return await handleGc2(client);
|
|
2601
|
+
case "rebuild":
|
|
2602
|
+
return await handleRebuild2(client);
|
|
2603
|
+
case "skill-learn":
|
|
2604
|
+
return await handleSkillLearn(client, args);
|
|
2605
|
+
case "skill-list":
|
|
2606
|
+
return await handleSkillList(client);
|
|
2607
|
+
case "skill-get":
|
|
2608
|
+
return await handleSkillGet(client, args);
|
|
2609
|
+
case "skill-delete":
|
|
2610
|
+
return await handleSkillDelete(client, args);
|
|
2611
|
+
case "agent-create":
|
|
2612
|
+
return await handleAgentCreate(client, args);
|
|
2613
|
+
case "agent-list":
|
|
2614
|
+
return await handleAgentList(client);
|
|
2615
|
+
case "agent-get":
|
|
2616
|
+
return await handleAgentGet(client, args);
|
|
2617
|
+
case "agent-delete":
|
|
2618
|
+
return await handleAgentDelete(client, args);
|
|
2619
|
+
default:
|
|
2620
|
+
return {
|
|
2621
|
+
content: [
|
|
2622
|
+
{
|
|
2623
|
+
type: "text",
|
|
2624
|
+
text: `Unknown tool: ${name}`
|
|
2625
|
+
}
|
|
2626
|
+
],
|
|
2627
|
+
isError: true
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
} catch (err) {
|
|
2631
|
+
return {
|
|
2632
|
+
content: [
|
|
2633
|
+
{
|
|
2634
|
+
type: "text",
|
|
2635
|
+
text: err instanceof Error ? err.message : String(err)
|
|
2636
|
+
}
|
|
2637
|
+
],
|
|
2638
|
+
isError: true
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
async function handleSearch2(client, args) {
|
|
2643
|
+
const results = await client.search({
|
|
2644
|
+
query: asString2(args["query"], ""),
|
|
2645
|
+
mode: args["mode"],
|
|
2646
|
+
limit: args["limit"]
|
|
2647
|
+
});
|
|
2648
|
+
return {
|
|
2649
|
+
content: [
|
|
2650
|
+
{
|
|
2651
|
+
type: "text",
|
|
2652
|
+
text: JSON.stringify(results, null, 2)
|
|
2653
|
+
}
|
|
2654
|
+
]
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
async function handleLearn2(client, args) {
|
|
2658
|
+
const sectionType = asString2(args["type"], "text/markdown");
|
|
2659
|
+
const title = typeof args["title"] === "string" ? args["title"] : void 0;
|
|
2660
|
+
const description = typeof args["description"] === "string" ? args["description"] : void 0;
|
|
2661
|
+
const docid = typeof args["docid"] === "string" ? args["docid"] : void 0;
|
|
2662
|
+
if (sectionType.startsWith("image/") && !title) {
|
|
2663
|
+
return {
|
|
2664
|
+
content: [
|
|
2665
|
+
{
|
|
2666
|
+
type: "text",
|
|
2667
|
+
text: "title is required for image/* types"
|
|
2668
|
+
}
|
|
2669
|
+
],
|
|
2670
|
+
isError: true
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
const result = await client.addSection({
|
|
2674
|
+
sectionType,
|
|
2675
|
+
content: asString2(args["content"], ""),
|
|
2676
|
+
title,
|
|
2677
|
+
description,
|
|
2678
|
+
docid
|
|
2679
|
+
});
|
|
2680
|
+
return {
|
|
2681
|
+
content: [
|
|
2682
|
+
{
|
|
2683
|
+
type: "text",
|
|
2684
|
+
text: JSON.stringify(result)
|
|
2685
|
+
}
|
|
2686
|
+
]
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
async function handleUnlearn2(client, args) {
|
|
2690
|
+
const result = await client.removeSection(
|
|
2691
|
+
asString2(args["kbid"], "")
|
|
2692
|
+
);
|
|
2693
|
+
return {
|
|
2694
|
+
content: [
|
|
2695
|
+
{
|
|
2696
|
+
type: "text",
|
|
2697
|
+
text: JSON.stringify(result)
|
|
2698
|
+
}
|
|
2699
|
+
]
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
async function handleRetrieve(client, args) {
|
|
2703
|
+
if (typeof args["kbid"] === "string") {
|
|
2704
|
+
const sections = await client.readSections([args["kbid"]]);
|
|
2705
|
+
return {
|
|
2706
|
+
content: [
|
|
2707
|
+
{
|
|
2708
|
+
type: "text",
|
|
2709
|
+
text: JSON.stringify(sections, null, 2)
|
|
2710
|
+
}
|
|
2711
|
+
]
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
if (typeof args["docid"] === "string") {
|
|
2715
|
+
const doc = await client.retrieveDocument(args["docid"]);
|
|
2716
|
+
return {
|
|
2717
|
+
content: [
|
|
2718
|
+
{
|
|
2719
|
+
type: "text",
|
|
2720
|
+
text: JSON.stringify(doc, null, 2)
|
|
2721
|
+
}
|
|
2722
|
+
]
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
return {
|
|
2726
|
+
content: [
|
|
2727
|
+
{
|
|
2728
|
+
type: "text",
|
|
2729
|
+
text: "Provide kbid or docid"
|
|
2730
|
+
}
|
|
2731
|
+
],
|
|
2732
|
+
isError: true
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
async function handleStatus2(client) {
|
|
2736
|
+
const status = await client.dbStatus();
|
|
2737
|
+
return {
|
|
2738
|
+
content: [
|
|
2739
|
+
{
|
|
2740
|
+
type: "text",
|
|
2741
|
+
text: JSON.stringify(status, null, 2)
|
|
2742
|
+
}
|
|
2743
|
+
]
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
async function handleContent2(client, args) {
|
|
2747
|
+
const ids = asStringArray2(args["ids"]);
|
|
2748
|
+
const result = await client.content(ids);
|
|
2749
|
+
return {
|
|
2750
|
+
content: [
|
|
2751
|
+
{
|
|
2752
|
+
type: "text",
|
|
2753
|
+
text: JSON.stringify(result)
|
|
2754
|
+
}
|
|
2755
|
+
]
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
async function handleCheck2(client) {
|
|
2759
|
+
const report = await client.integrityCheck();
|
|
2760
|
+
return {
|
|
2761
|
+
content: [
|
|
2762
|
+
{
|
|
2763
|
+
type: "text",
|
|
2764
|
+
text: JSON.stringify(report, null, 2)
|
|
2765
|
+
}
|
|
2766
|
+
]
|
|
2767
|
+
};
|
|
2768
|
+
}
|
|
2769
|
+
async function handleGc2(client) {
|
|
2770
|
+
const report = await client.gc();
|
|
2771
|
+
return {
|
|
2772
|
+
content: [
|
|
2773
|
+
{
|
|
2774
|
+
type: "text",
|
|
2775
|
+
text: JSON.stringify(report, null, 2)
|
|
2776
|
+
}
|
|
2777
|
+
]
|
|
2778
|
+
};
|
|
2779
|
+
}
|
|
2780
|
+
async function handleRebuild2(client) {
|
|
2781
|
+
const report = await client.rebuildIndexes();
|
|
2782
|
+
return {
|
|
2783
|
+
content: [
|
|
2784
|
+
{
|
|
2785
|
+
type: "text",
|
|
2786
|
+
text: JSON.stringify(report, null, 2)
|
|
2787
|
+
}
|
|
2788
|
+
]
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
async function handleSkillLearn(client, args) {
|
|
2792
|
+
const name = asString2(args["name"], "");
|
|
2793
|
+
if (!name) {
|
|
2794
|
+
return {
|
|
2795
|
+
content: [{ type: "text", text: "name is required" }],
|
|
2796
|
+
isError: true
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2799
|
+
const body = asString2(args["body"], "");
|
|
2800
|
+
if (!body) {
|
|
2801
|
+
return {
|
|
2802
|
+
content: [{ type: "text", text: "body is required" }],
|
|
2803
|
+
isError: true
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
const description = typeof args["description"] === "string" ? args["description"] : void 0;
|
|
2807
|
+
const skillArgs = extractSkillArguments(body);
|
|
2808
|
+
const skill = {
|
|
2809
|
+
name,
|
|
2810
|
+
description,
|
|
2811
|
+
arguments: skillArgs.length > 0 ? skillArgs : void 0,
|
|
2812
|
+
body
|
|
2813
|
+
};
|
|
2814
|
+
const json = serializeSkillContent(skill);
|
|
2815
|
+
const result = await client.addSection({
|
|
2816
|
+
sectionType: "skill",
|
|
2817
|
+
content: json,
|
|
2818
|
+
title: name,
|
|
2819
|
+
description
|
|
2820
|
+
});
|
|
2821
|
+
return {
|
|
2822
|
+
content: [
|
|
2823
|
+
{
|
|
2824
|
+
type: "text",
|
|
2825
|
+
text: JSON.stringify({ kbid: result.kbid, name })
|
|
2826
|
+
}
|
|
2827
|
+
]
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2830
|
+
async function handleSkillList(client) {
|
|
2831
|
+
const records = await client.listByType("skill");
|
|
2832
|
+
const items = records.map((r) => {
|
|
2833
|
+
let argumentCount = 0;
|
|
2834
|
+
try {
|
|
2835
|
+
const parsed = JSON.parse(r.content);
|
|
2836
|
+
if (Array.isArray(parsed["arguments"])) {
|
|
2837
|
+
argumentCount = parsed["arguments"].length;
|
|
2838
|
+
}
|
|
2839
|
+
} catch {
|
|
2840
|
+
}
|
|
2841
|
+
return {
|
|
2842
|
+
kbid: r.kbid,
|
|
2843
|
+
name: r.title,
|
|
2844
|
+
description: r.description,
|
|
2845
|
+
argumentCount
|
|
2846
|
+
};
|
|
2847
|
+
});
|
|
2848
|
+
return {
|
|
2849
|
+
content: [
|
|
2850
|
+
{
|
|
2851
|
+
type: "text",
|
|
2852
|
+
text: JSON.stringify(items, null, 2)
|
|
2853
|
+
}
|
|
2854
|
+
]
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
async function handleSkillGet(client, args) {
|
|
2858
|
+
const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
|
|
2859
|
+
const name = typeof args["name"] === "string" ? args["name"] : void 0;
|
|
2860
|
+
if (!kbid && !name) {
|
|
2861
|
+
return {
|
|
2862
|
+
content: [
|
|
2863
|
+
{
|
|
2864
|
+
type: "text",
|
|
2865
|
+
text: "name or kbid is required"
|
|
2866
|
+
}
|
|
2867
|
+
],
|
|
2868
|
+
isError: true
|
|
2869
|
+
};
|
|
2870
|
+
}
|
|
2871
|
+
let content;
|
|
2872
|
+
if (kbid) {
|
|
2873
|
+
const sections = await client.readSections([kbid]);
|
|
2874
|
+
if (sections.length > 0) {
|
|
2875
|
+
content = sections[0]?.content;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
if (content === void 0 && name) {
|
|
2879
|
+
const records = await client.listByType("skill");
|
|
2880
|
+
const match = records.filter((r) => r.title === name).pop();
|
|
2881
|
+
if (match) {
|
|
2882
|
+
content = match.content;
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
if (content === void 0) {
|
|
2886
|
+
const identifier = kbid ?? name ?? "";
|
|
2887
|
+
return {
|
|
2888
|
+
content: [
|
|
2889
|
+
{
|
|
2890
|
+
type: "text",
|
|
2891
|
+
text: `skill not found: ${identifier}`
|
|
2892
|
+
}
|
|
2893
|
+
],
|
|
2894
|
+
isError: true
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
const skill = parseSkillContent(content);
|
|
2898
|
+
return {
|
|
2899
|
+
content: [
|
|
2900
|
+
{
|
|
2901
|
+
type: "text",
|
|
2902
|
+
text: JSON.stringify(skill, null, 2)
|
|
2903
|
+
}
|
|
2904
|
+
]
|
|
2905
|
+
};
|
|
2906
|
+
}
|
|
2907
|
+
async function handleSkillDelete(client, args) {
|
|
2908
|
+
const kbid = asString2(args["kbid"], "");
|
|
2909
|
+
if (!kbid) {
|
|
2910
|
+
return {
|
|
2911
|
+
content: [{ type: "text", text: "kbid is required" }],
|
|
2912
|
+
isError: true
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
const result = await client.removeSection(kbid);
|
|
2916
|
+
return {
|
|
2917
|
+
content: [
|
|
2918
|
+
{
|
|
2919
|
+
type: "text",
|
|
2920
|
+
text: JSON.stringify({ kbid, removed: result.removed })
|
|
2921
|
+
}
|
|
2922
|
+
]
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
// src/shared/mcp/functions/handle-resource-read.function.ts
|
|
2927
|
+
async function handleResourceRead(client, uri) {
|
|
2928
|
+
const sectionMatch = uri.match(/^kbdb:\/\/section\/(.+)$/);
|
|
2929
|
+
if (sectionMatch) {
|
|
2930
|
+
const sections = await client.readSections([sectionMatch[1]]);
|
|
2931
|
+
const text = sections.length > 0 ? sections[0].content : "";
|
|
2932
|
+
return {
|
|
2933
|
+
contents: [{ uri, mimeType: "text/plain", text }]
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
const docMatch = uri.match(/^kbdb:\/\/document\/(.+)$/);
|
|
2937
|
+
if (docMatch) {
|
|
2938
|
+
const doc = await client.retrieveDocument(docMatch[1]);
|
|
2939
|
+
return {
|
|
2940
|
+
contents: [
|
|
2941
|
+
{
|
|
2942
|
+
uri,
|
|
2943
|
+
mimeType: "application/json",
|
|
2944
|
+
text: JSON.stringify(doc, null, 2)
|
|
2945
|
+
}
|
|
2946
|
+
]
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
// src/shared/mcp/functions/create-prompt-definitions.function.ts
|
|
2953
|
+
function parseSkillArguments(content) {
|
|
2954
|
+
try {
|
|
2955
|
+
const parsed = JSON.parse(content);
|
|
2956
|
+
if (!Array.isArray(parsed["arguments"])) {
|
|
2957
|
+
return void 0;
|
|
2958
|
+
}
|
|
2959
|
+
return parsed["arguments"].map(
|
|
2960
|
+
(arg) => ({
|
|
2961
|
+
name: typeof arg["name"] === "string" ? arg["name"] : "",
|
|
2962
|
+
description: typeof arg["description"] === "string" ? arg["description"] : void 0,
|
|
2963
|
+
required: typeof arg["required"] === "boolean" ? arg["required"] : void 0
|
|
2964
|
+
})
|
|
2965
|
+
);
|
|
2966
|
+
} catch {
|
|
2967
|
+
return void 0;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
function createPromptDefinitions(skills, agents) {
|
|
2971
|
+
const skillPrompts = skills.filter(
|
|
2972
|
+
(r) => r.title !== null
|
|
2973
|
+
).map((record) => {
|
|
2974
|
+
const args = parseSkillArguments(record.content);
|
|
2975
|
+
const prompt = {
|
|
2976
|
+
name: record.title,
|
|
2977
|
+
description: record.description ?? void 0,
|
|
2978
|
+
arguments: args
|
|
2979
|
+
};
|
|
2980
|
+
return prompt;
|
|
2981
|
+
});
|
|
2982
|
+
const agentPrompts = agents.map((doc) => ({
|
|
2983
|
+
name: `agent:${doc.title}`,
|
|
2984
|
+
arguments: []
|
|
2985
|
+
}));
|
|
2986
|
+
return [...skillPrompts, ...agentPrompts];
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
// src/shared/mcp/functions/handle-prompt-get.function.ts
|
|
2990
|
+
function parseAgentMeta(content) {
|
|
2991
|
+
try {
|
|
2992
|
+
const parsed = JSON.parse(content);
|
|
2993
|
+
return {
|
|
2994
|
+
persona: typeof parsed["persona"] === "string" ? parsed["persona"] : ""
|
|
2995
|
+
};
|
|
2996
|
+
} catch {
|
|
2997
|
+
return { persona: "" };
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
function buildSkillsText(skillSections) {
|
|
3001
|
+
const lines = [];
|
|
3002
|
+
for (const sec of skillSections) {
|
|
3003
|
+
try {
|
|
3004
|
+
const parsed = JSON.parse(sec.content);
|
|
3005
|
+
const name = typeof parsed["name"] === "string" ? parsed["name"] : null;
|
|
3006
|
+
if (name === null) {
|
|
3007
|
+
continue;
|
|
3008
|
+
}
|
|
3009
|
+
const description = typeof parsed["description"] === "string" ? parsed["description"] : "";
|
|
3010
|
+
lines.push(`- ${name}: ${description}`);
|
|
3011
|
+
} catch {
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
if (lines.length === 0) {
|
|
3015
|
+
return null;
|
|
3016
|
+
}
|
|
3017
|
+
return `Available skills:
|
|
3018
|
+
${lines.join("\n")}`;
|
|
3019
|
+
}
|
|
3020
|
+
async function handleAgentPrompt(name, client) {
|
|
3021
|
+
const docid = name.slice(6);
|
|
3022
|
+
const doc = await client.retrieveDocument(docid);
|
|
3023
|
+
const sections = doc.sections;
|
|
3024
|
+
const metaSection = sections.at(0);
|
|
3025
|
+
const skillRefs = sections.slice(1);
|
|
3026
|
+
let persona = "";
|
|
3027
|
+
if (metaSection !== void 0) {
|
|
3028
|
+
const metaSections = await client.readSections([
|
|
3029
|
+
metaSection.kbid
|
|
3030
|
+
]);
|
|
3031
|
+
const metaContent = metaSections.at(0);
|
|
3032
|
+
if (metaContent !== void 0) {
|
|
3033
|
+
persona = parseAgentMeta(metaContent.content).persona;
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
const messages = [
|
|
3037
|
+
{
|
|
3038
|
+
role: "assistant",
|
|
3039
|
+
content: { type: "text", text: persona }
|
|
3040
|
+
}
|
|
3041
|
+
];
|
|
3042
|
+
if (skillRefs.length === 0) {
|
|
3043
|
+
return messages;
|
|
3044
|
+
}
|
|
3045
|
+
const skillKbids = skillRefs.map((s) => s.kbid);
|
|
3046
|
+
const skillSections = await client.readSections(skillKbids);
|
|
3047
|
+
const skillsText = buildSkillsText(skillSections);
|
|
3048
|
+
if (skillsText !== null) {
|
|
3049
|
+
messages.push({
|
|
3050
|
+
role: "user",
|
|
3051
|
+
content: { type: "text", text: skillsText }
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
return messages;
|
|
3055
|
+
}
|
|
3056
|
+
async function handleSkillPrompt(name, promptArgs, client) {
|
|
3057
|
+
const sections = await client.listByType("skill");
|
|
3058
|
+
let matchContent;
|
|
3059
|
+
for (const sec of sections) {
|
|
3060
|
+
if (sec.title === name) {
|
|
3061
|
+
matchContent = sec.content;
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
if (matchContent === void 0) {
|
|
3065
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
3066
|
+
}
|
|
3067
|
+
const parsed = JSON.parse(matchContent);
|
|
3068
|
+
const body = typeof parsed["body"] === "string" ? parsed["body"] : "";
|
|
3069
|
+
const rendered = body.replace(
|
|
3070
|
+
/\{\{(\w+)\}\}/g,
|
|
3071
|
+
(_match, key) => key in promptArgs ? promptArgs[key] ?? _match : _match
|
|
3072
|
+
);
|
|
3073
|
+
return [
|
|
3074
|
+
{
|
|
3075
|
+
role: "user",
|
|
3076
|
+
content: { type: "text", text: rendered }
|
|
3077
|
+
}
|
|
3078
|
+
];
|
|
3079
|
+
}
|
|
3080
|
+
async function handlePromptGet(name, promptArgs, client) {
|
|
3081
|
+
if (name.startsWith("agent:")) {
|
|
3082
|
+
return handleAgentPrompt(name, client);
|
|
3083
|
+
}
|
|
3084
|
+
return handleSkillPrompt(name, promptArgs, client);
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
// src/shared/mcp/functions/handle-completion.function.ts
|
|
3088
|
+
async function handleCompletion(ref, argument, client) {
|
|
3089
|
+
if (ref.type !== "ref/prompt") {
|
|
3090
|
+
return { completion: { values: [], hasMore: false, total: 0 } };
|
|
3091
|
+
}
|
|
3092
|
+
const [skills, agents] = await Promise.all([
|
|
3093
|
+
client.listByType("skill"),
|
|
3094
|
+
client.listDocumentsByType("agent")
|
|
3095
|
+
]);
|
|
3096
|
+
const names = [];
|
|
3097
|
+
for (const skill of skills) {
|
|
3098
|
+
if (skill.title !== null) {
|
|
3099
|
+
names.push(skill.title);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
for (const agent of agents) {
|
|
3103
|
+
names.push(`agent:${agent.title}`);
|
|
3104
|
+
}
|
|
3105
|
+
const prefix = argument.value;
|
|
3106
|
+
function matchesPrefix(candidate) {
|
|
3107
|
+
if (prefix.length === 0) {
|
|
3108
|
+
return true;
|
|
3109
|
+
}
|
|
3110
|
+
if (candidate.startsWith(prefix)) {
|
|
3111
|
+
return true;
|
|
3112
|
+
}
|
|
3113
|
+
const AGENT_PREFIX = "agent:";
|
|
3114
|
+
if (candidate.startsWith(AGENT_PREFIX)) {
|
|
3115
|
+
return candidate.slice(AGENT_PREFIX.length).startsWith(prefix);
|
|
3116
|
+
}
|
|
3117
|
+
return false;
|
|
3118
|
+
}
|
|
3119
|
+
const values = names.filter(matchesPrefix);
|
|
3120
|
+
return {
|
|
3121
|
+
completion: {
|
|
3122
|
+
values,
|
|
3123
|
+
hasMore: false,
|
|
3124
|
+
total: values.length
|
|
3125
|
+
}
|
|
3126
|
+
};
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
// src/shared/mcp/functions/handle-roots-list.function.ts
|
|
3130
|
+
function handleRootsList(contextPath) {
|
|
3131
|
+
return [
|
|
3132
|
+
{
|
|
3133
|
+
uri: `file://${contextPath}`,
|
|
3134
|
+
name: "kbdb database"
|
|
3135
|
+
}
|
|
3136
|
+
];
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
// src/shared/mcp/functions/should-emit-log.function.ts
|
|
3140
|
+
var LOG_LEVEL_ORDER = [
|
|
3141
|
+
"debug",
|
|
3142
|
+
"info",
|
|
3143
|
+
"notice",
|
|
3144
|
+
"warning",
|
|
3145
|
+
"error",
|
|
3146
|
+
"critical",
|
|
3147
|
+
"alert",
|
|
3148
|
+
"emergency"
|
|
3149
|
+
];
|
|
3150
|
+
function shouldEmitLog(messageLevel, threshold) {
|
|
3151
|
+
const messageIndex = LOG_LEVEL_ORDER.indexOf(messageLevel);
|
|
3152
|
+
const thresholdIndex = LOG_LEVEL_ORDER.indexOf(threshold);
|
|
3153
|
+
return messageIndex >= thresholdIndex;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
// src/shared/mcp/constants/mcp-error-codes.constant.ts
|
|
3157
|
+
var PARSE_ERROR = -32700;
|
|
3158
|
+
var METHOD_NOT_FOUND = -32601;
|
|
3159
|
+
var RESOURCE_NOT_FOUND = -32002;
|
|
3160
|
+
|
|
3161
|
+
// src/shared/mcp/classes/mcp-server.class.ts
|
|
3162
|
+
var McpServer = class {
|
|
3163
|
+
client;
|
|
3164
|
+
contextPath;
|
|
3165
|
+
initialized = false;
|
|
3166
|
+
hostCapabilities = null;
|
|
3167
|
+
logLevel = null;
|
|
3168
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
3169
|
+
nextRequestId = 1;
|
|
3170
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
3171
|
+
constructor(client, contextPath) {
|
|
3172
|
+
this.client = client;
|
|
3173
|
+
this.contextPath = contextPath ?? "";
|
|
3174
|
+
}
|
|
3175
|
+
async listen() {
|
|
3176
|
+
const rl = createInterface2({
|
|
3177
|
+
input: process.stdin,
|
|
3178
|
+
terminal: false
|
|
3179
|
+
});
|
|
3180
|
+
await new Promise((resolve4) => {
|
|
3181
|
+
rl.on("line", (line) => {
|
|
3182
|
+
void this.dispatchLine(line);
|
|
3183
|
+
});
|
|
3184
|
+
rl.on("close", () => {
|
|
3185
|
+
this.client.disconnect();
|
|
3186
|
+
resolve4();
|
|
3187
|
+
});
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
async handleLineForTest(line) {
|
|
3191
|
+
return this.processLine(line);
|
|
3192
|
+
}
|
|
3193
|
+
/**
|
|
3194
|
+
* Sends a JSON-RPC notification (no `id`, no response
|
|
3195
|
+
* expected) to stdout.
|
|
3196
|
+
*/
|
|
3197
|
+
notify(method, params) {
|
|
3198
|
+
const notification = {
|
|
3199
|
+
jsonrpc: "2.0",
|
|
3200
|
+
method
|
|
3201
|
+
};
|
|
3202
|
+
if (params !== void 0) {
|
|
3203
|
+
notification["params"] = params;
|
|
3204
|
+
}
|
|
3205
|
+
process.stdout.write(JSON.stringify(notification) + "\n");
|
|
3206
|
+
}
|
|
3207
|
+
/**
|
|
3208
|
+
* Emits a log notification if the message severity meets or
|
|
3209
|
+
* exceeds the configured log level threshold.
|
|
3210
|
+
*/
|
|
3211
|
+
log(level, message, logger) {
|
|
3212
|
+
if (this.logLevel === null) return;
|
|
3213
|
+
if (!shouldEmitLog(level, this.logLevel)) return;
|
|
3214
|
+
this.notify("notifications/message", {
|
|
3215
|
+
level,
|
|
3216
|
+
logger: logger ?? "kbdb",
|
|
3217
|
+
data: message
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
/**
|
|
3221
|
+
* Sends a JSON-RPC request to the host (server-to-client)
|
|
3222
|
+
* and returns a Promise that resolves with the response
|
|
3223
|
+
* result. Times out after 30 seconds.
|
|
3224
|
+
*/
|
|
3225
|
+
sendRequest(method, params) {
|
|
3226
|
+
const id = this.nextRequestId++;
|
|
3227
|
+
const request = { jsonrpc: "2.0", id, method, params };
|
|
3228
|
+
process.stdout.write(JSON.stringify(request) + "\n");
|
|
3229
|
+
return new Promise((resolve4, reject) => {
|
|
3230
|
+
const timer = setTimeout(() => {
|
|
3231
|
+
this.pendingRequests.delete(id);
|
|
3232
|
+
reject(new Error(`Request ${method} timed out`));
|
|
3233
|
+
}, 3e4);
|
|
3234
|
+
this.pendingRequests.set(id, {
|
|
3235
|
+
resolve: resolve4,
|
|
3236
|
+
reject,
|
|
3237
|
+
timer
|
|
3238
|
+
});
|
|
3239
|
+
});
|
|
3240
|
+
}
|
|
3241
|
+
/**
|
|
3242
|
+
* Requests the host to generate text via the sampling
|
|
3243
|
+
* capability. Throws if the host did not advertise sampling
|
|
3244
|
+
* support during initialization.
|
|
3245
|
+
*/
|
|
3246
|
+
async requestSampling(messages, maxTokens) {
|
|
3247
|
+
if (!this.hostCapabilities?.["sampling"]) {
|
|
3248
|
+
throw new Error("Host does not support sampling");
|
|
3249
|
+
}
|
|
3250
|
+
return this.sendRequest("sampling/createMessage", {
|
|
3251
|
+
messages,
|
|
3252
|
+
maxTokens
|
|
3253
|
+
});
|
|
3254
|
+
}
|
|
3255
|
+
async dispatchLine(line) {
|
|
3256
|
+
const response = await this.processLine(line);
|
|
3257
|
+
if (response !== null) {
|
|
3258
|
+
this.send(response);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
async processLine(line) {
|
|
3262
|
+
if (!line.trim()) return null;
|
|
3263
|
+
let parsed;
|
|
3264
|
+
try {
|
|
3265
|
+
parsed = JSON.parse(line);
|
|
3266
|
+
} catch {
|
|
3267
|
+
return {
|
|
3268
|
+
jsonrpc: "2.0",
|
|
3269
|
+
id: 0,
|
|
3270
|
+
error: {
|
|
3271
|
+
code: PARSE_ERROR,
|
|
3272
|
+
message: "Parse error"
|
|
3273
|
+
}
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
if (parsed["id"] !== void 0 && typeof parsed["method"] !== "string") {
|
|
3277
|
+
const responseId = parsed["id"];
|
|
3278
|
+
const pending = this.pendingRequests.get(responseId);
|
|
3279
|
+
if (pending) {
|
|
3280
|
+
this.pendingRequests.delete(responseId);
|
|
3281
|
+
clearTimeout(pending.timer);
|
|
3282
|
+
if (parsed["error"]) {
|
|
3283
|
+
const err = parsed["error"];
|
|
3284
|
+
pending.reject(
|
|
3285
|
+
new Error(err.message ?? "Request failed")
|
|
3286
|
+
);
|
|
3287
|
+
} else {
|
|
3288
|
+
pending.resolve(parsed["result"]);
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
return null;
|
|
3292
|
+
}
|
|
3293
|
+
const request = parsed;
|
|
3294
|
+
if (request.id === void 0) {
|
|
3295
|
+
if (request.method === "notifications/initialized" || request.method === "notifications/cancelled") {
|
|
3296
|
+
if (request.method === "notifications/initialized") {
|
|
3297
|
+
this.initialized = true;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
return null;
|
|
3301
|
+
}
|
|
3302
|
+
const id = request.id;
|
|
3303
|
+
if (!this.initialized && request.method !== "initialize" && request.method !== "ping") {
|
|
3304
|
+
return {
|
|
3305
|
+
jsonrpc: "2.0",
|
|
3306
|
+
id,
|
|
3307
|
+
error: {
|
|
3308
|
+
code: RESOURCE_NOT_FOUND,
|
|
3309
|
+
message: "Server not initialized"
|
|
3310
|
+
}
|
|
3311
|
+
};
|
|
3312
|
+
}
|
|
3313
|
+
const response = await this.handleRequest(request);
|
|
3314
|
+
return response;
|
|
3315
|
+
}
|
|
3316
|
+
async handleRequest(request) {
|
|
3317
|
+
const id = request.id;
|
|
3318
|
+
switch (request.method) {
|
|
3319
|
+
case "initialize": {
|
|
3320
|
+
const params = request.params ?? {};
|
|
3321
|
+
const caps = params["capabilities"];
|
|
3322
|
+
this.hostCapabilities = caps ? caps : null;
|
|
3323
|
+
return {
|
|
3324
|
+
jsonrpc: "2.0",
|
|
3325
|
+
id,
|
|
3326
|
+
result: {
|
|
3327
|
+
protocolVersion: "2025-11-25",
|
|
3328
|
+
serverInfo: {
|
|
3329
|
+
name: "kbdb",
|
|
3330
|
+
version: "0.1.0"
|
|
3331
|
+
},
|
|
3332
|
+
capabilities: {
|
|
3333
|
+
tools: {},
|
|
3334
|
+
resources: { subscribe: true },
|
|
3335
|
+
prompts: {},
|
|
3336
|
+
logging: {},
|
|
3337
|
+
completions: {}
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
};
|
|
3341
|
+
}
|
|
3342
|
+
case "ping":
|
|
3343
|
+
return { jsonrpc: "2.0", id, result: {} };
|
|
3344
|
+
case "tools/list":
|
|
3345
|
+
return {
|
|
3346
|
+
jsonrpc: "2.0",
|
|
3347
|
+
id,
|
|
3348
|
+
result: {
|
|
3349
|
+
tools: createToolDefinitions()
|
|
3350
|
+
}
|
|
3351
|
+
};
|
|
3352
|
+
case "resources/list":
|
|
3353
|
+
return {
|
|
3354
|
+
jsonrpc: "2.0",
|
|
3355
|
+
id,
|
|
3356
|
+
result: { resources: [] }
|
|
3357
|
+
};
|
|
3358
|
+
case "resources/templates/list":
|
|
3359
|
+
return {
|
|
3360
|
+
jsonrpc: "2.0",
|
|
3361
|
+
id,
|
|
3362
|
+
result: {
|
|
3363
|
+
resourceTemplates: createResourceTemplates()
|
|
3364
|
+
}
|
|
3365
|
+
};
|
|
3366
|
+
case "tools/call": {
|
|
3367
|
+
const params = request.params ?? {};
|
|
3368
|
+
const rawName = params["name"];
|
|
3369
|
+
const name = typeof rawName === "string" ? rawName : "";
|
|
3370
|
+
const args = params["arguments"] ?? {};
|
|
3371
|
+
const result = await handleToolCall(
|
|
3372
|
+
this.client,
|
|
3373
|
+
name,
|
|
3374
|
+
args
|
|
3375
|
+
);
|
|
3376
|
+
return { jsonrpc: "2.0", id, result };
|
|
3377
|
+
}
|
|
3378
|
+
case "resources/read": {
|
|
3379
|
+
const params = request.params ?? {};
|
|
3380
|
+
const rawUri = params["uri"];
|
|
3381
|
+
const uri = typeof rawUri === "string" ? rawUri : "";
|
|
3382
|
+
try {
|
|
3383
|
+
const result = await handleResourceRead(
|
|
3384
|
+
this.client,
|
|
3385
|
+
uri
|
|
3386
|
+
);
|
|
3387
|
+
return { jsonrpc: "2.0", id, result };
|
|
3388
|
+
} catch (err) {
|
|
3389
|
+
return {
|
|
3390
|
+
jsonrpc: "2.0",
|
|
3391
|
+
id,
|
|
3392
|
+
error: {
|
|
3393
|
+
code: RESOURCE_NOT_FOUND,
|
|
3394
|
+
message: err instanceof Error ? err.message : String(err)
|
|
3395
|
+
}
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
case "prompts/list": {
|
|
3400
|
+
const skills = await this.client.listByType("skill");
|
|
3401
|
+
const agents = await this.client.listDocumentsByType("agent");
|
|
3402
|
+
const prompts = createPromptDefinitions(skills, agents);
|
|
3403
|
+
return {
|
|
3404
|
+
jsonrpc: "2.0",
|
|
3405
|
+
id,
|
|
3406
|
+
result: { prompts }
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
case "prompts/get": {
|
|
3410
|
+
const params = request.params ?? {};
|
|
3411
|
+
const name = typeof params["name"] === "string" ? params["name"] : "";
|
|
3412
|
+
const promptArgs = params["arguments"] ?? {};
|
|
3413
|
+
try {
|
|
3414
|
+
const messages = await handlePromptGet(
|
|
3415
|
+
name,
|
|
3416
|
+
promptArgs,
|
|
3417
|
+
this.client
|
|
3418
|
+
);
|
|
3419
|
+
return {
|
|
3420
|
+
jsonrpc: "2.0",
|
|
3421
|
+
id,
|
|
3422
|
+
result: { messages }
|
|
3423
|
+
};
|
|
3424
|
+
} catch (err) {
|
|
3425
|
+
return {
|
|
3426
|
+
jsonrpc: "2.0",
|
|
3427
|
+
id,
|
|
3428
|
+
error: {
|
|
3429
|
+
code: RESOURCE_NOT_FOUND,
|
|
3430
|
+
message: err instanceof Error ? err.message : String(err)
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
case "completion/complete": {
|
|
3436
|
+
const params = request.params ?? {};
|
|
3437
|
+
const ref = params["ref"];
|
|
3438
|
+
const argument = params["argument"] ?? {
|
|
3439
|
+
name: "",
|
|
3440
|
+
value: ""
|
|
3441
|
+
};
|
|
3442
|
+
const result = await handleCompletion(
|
|
3443
|
+
ref,
|
|
3444
|
+
argument,
|
|
3445
|
+
this.client
|
|
3446
|
+
);
|
|
3447
|
+
return { jsonrpc: "2.0", id, result };
|
|
3448
|
+
}
|
|
3449
|
+
case "roots/list": {
|
|
3450
|
+
const roots = handleRootsList(this.contextPath);
|
|
3451
|
+
return {
|
|
3452
|
+
jsonrpc: "2.0",
|
|
3453
|
+
id,
|
|
3454
|
+
result: { roots }
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
case "logging/setLevel": {
|
|
3458
|
+
const params = request.params ?? {};
|
|
3459
|
+
const level = params["level"];
|
|
3460
|
+
this.logLevel = level ?? null;
|
|
3461
|
+
return { jsonrpc: "2.0", id, result: {} };
|
|
3462
|
+
}
|
|
3463
|
+
case "resources/subscribe": {
|
|
3464
|
+
const params = request.params ?? {};
|
|
3465
|
+
const uri = typeof params["uri"] === "string" ? params["uri"] : "";
|
|
3466
|
+
this.subscriptions.add(uri);
|
|
3467
|
+
return { jsonrpc: "2.0", id, result: {} };
|
|
3468
|
+
}
|
|
3469
|
+
case "resources/unsubscribe": {
|
|
3470
|
+
const params = request.params ?? {};
|
|
3471
|
+
const uri = typeof params["uri"] === "string" ? params["uri"] : "";
|
|
3472
|
+
this.subscriptions.delete(uri);
|
|
3473
|
+
return { jsonrpc: "2.0", id, result: {} };
|
|
3474
|
+
}
|
|
3475
|
+
default:
|
|
3476
|
+
return {
|
|
3477
|
+
jsonrpc: "2.0",
|
|
3478
|
+
id,
|
|
3479
|
+
error: {
|
|
3480
|
+
code: METHOD_NOT_FOUND,
|
|
3481
|
+
message: `Method not found: ` + request.method
|
|
3482
|
+
}
|
|
3483
|
+
};
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
send(response) {
|
|
3487
|
+
const json = JSON.stringify(response);
|
|
3488
|
+
process.stdout.write(json + "\n");
|
|
3489
|
+
}
|
|
3490
|
+
};
|
|
3491
|
+
|
|
3492
|
+
// src/shared/mcp/functions/create-mcp-server.function.ts
|
|
3493
|
+
function createMcpServer(client) {
|
|
3494
|
+
return new McpServer(client);
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
// src/cli.ts
|
|
3498
|
+
var runtime = detectRuntime();
|
|
3499
|
+
var baseDir = resolveBaseDir(import.meta.url, import.meta.dirname);
|
|
3500
|
+
var workerScript = resolveWorkerScript(baseDir.scriptDir, runtime);
|
|
3501
|
+
var deps = {
|
|
3502
|
+
isStdinTty,
|
|
3503
|
+
promptUser,
|
|
3504
|
+
createWorkerClient: (opts) => createWorkerClient({ ...opts, workerScript }),
|
|
3505
|
+
findDb,
|
|
3506
|
+
runInit,
|
|
3507
|
+
startMcpServer: async (contextPath) => {
|
|
3508
|
+
const client = await createWorkerClient({
|
|
3509
|
+
contextPath,
|
|
3510
|
+
workerScript
|
|
3511
|
+
});
|
|
3512
|
+
try {
|
|
3513
|
+
const server = createMcpServer(client);
|
|
3514
|
+
await server.listen();
|
|
3515
|
+
} finally {
|
|
3516
|
+
client.disconnect();
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
};
|
|
3520
|
+
async function main() {
|
|
3521
|
+
const result = await runCli(getArgs(), deps);
|
|
3522
|
+
if (result.output) {
|
|
3523
|
+
console.log(result.output);
|
|
3524
|
+
}
|
|
3525
|
+
if (result.error) {
|
|
3526
|
+
console.error(result.error);
|
|
3527
|
+
}
|
|
3528
|
+
if (result.exitCode !== 0) {
|
|
3529
|
+
process.exitCode = result.exitCode;
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
main().catch((err) => {
|
|
3533
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3534
|
+
console.error(`error: ${msg}`);
|
|
3535
|
+
process.exitCode = 1;
|
|
3536
|
+
});
|
|
3537
|
+
//# sourceMappingURL=cli.mjs.map
|