@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/worker.mjs
ADDED
|
@@ -0,0 +1,1615 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeSha256,
|
|
3
|
+
getArgs,
|
|
4
|
+
getIpcPath,
|
|
5
|
+
resolveBaseDir,
|
|
6
|
+
resolveWasmDir
|
|
7
|
+
} from "./chunk-QCCN7OZH.mjs";
|
|
8
|
+
|
|
9
|
+
// src/worker.ts
|
|
10
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
11
|
+
|
|
12
|
+
// src/shared/worker-daemon/functions/read-config.function.ts
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
|
|
16
|
+
// src/shared/worker-daemon/constants/daemon-defaults.constant.ts
|
|
17
|
+
var DEFAULT_ITEM_LIMIT = 1e3;
|
|
18
|
+
var DEFAULT_INDEX_LIMIT = 100;
|
|
19
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
20
|
+
var DEFAULT_ITEM_TTL_MS = 6e4;
|
|
21
|
+
var WORKER_TOML_FILENAME = "worker.toml";
|
|
22
|
+
var DB_FORMAT_VERSION = 1;
|
|
23
|
+
|
|
24
|
+
// src/shared/worker-daemon/functions/read-config.function.ts
|
|
25
|
+
function readConfig(contextPath) {
|
|
26
|
+
const configPath = join(contextPath, WORKER_TOML_FILENAME);
|
|
27
|
+
try {
|
|
28
|
+
const text = readFileSync(configPath, "utf-8");
|
|
29
|
+
return parseWorkerToml(text, contextPath);
|
|
30
|
+
} catch {
|
|
31
|
+
return {
|
|
32
|
+
contextPath,
|
|
33
|
+
itemLimit: DEFAULT_ITEM_LIMIT,
|
|
34
|
+
indexLimit: DEFAULT_INDEX_LIMIT,
|
|
35
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
36
|
+
itemTtlMs: DEFAULT_ITEM_TTL_MS
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function parseWorkerToml(text, contextPath) {
|
|
41
|
+
const config = {
|
|
42
|
+
contextPath,
|
|
43
|
+
itemLimit: DEFAULT_ITEM_LIMIT,
|
|
44
|
+
indexLimit: DEFAULT_INDEX_LIMIT,
|
|
45
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
46
|
+
itemTtlMs: DEFAULT_ITEM_TTL_MS
|
|
47
|
+
};
|
|
48
|
+
const result = { ...config };
|
|
49
|
+
for (const line of text.split("\n")) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (trimmed.startsWith("#") || !trimmed.includes("=")) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const eqIdx = trimmed.indexOf("=");
|
|
55
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
56
|
+
const value = trimmed.slice(eqIdx + 1).trim();
|
|
57
|
+
switch (key) {
|
|
58
|
+
case "item_limit":
|
|
59
|
+
result.itemLimit = parseInt(value, 10) || DEFAULT_ITEM_LIMIT;
|
|
60
|
+
break;
|
|
61
|
+
case "index_limit":
|
|
62
|
+
result.indexLimit = parseInt(value, 10) || DEFAULT_INDEX_LIMIT;
|
|
63
|
+
break;
|
|
64
|
+
case "timeout_ms":
|
|
65
|
+
result.timeoutMs = parseInt(value, 10) || DEFAULT_TIMEOUT_MS;
|
|
66
|
+
break;
|
|
67
|
+
case "item_ttl_ms":
|
|
68
|
+
result.itemTtlMs = parseInt(value, 10) || DEFAULT_ITEM_TTL_MS;
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/shared/worker-daemon/functions/start-daemon.function.ts
|
|
78
|
+
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
79
|
+
import { join as join5 } from "node:path";
|
|
80
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
81
|
+
|
|
82
|
+
// src/shared/worker-daemon/classes/worker-daemon.class.ts
|
|
83
|
+
import {
|
|
84
|
+
existsSync as existsSync2,
|
|
85
|
+
readFileSync as readFileSync4,
|
|
86
|
+
accessSync,
|
|
87
|
+
writeFileSync as writeFileSync2,
|
|
88
|
+
unlinkSync as unlinkSync2,
|
|
89
|
+
constants
|
|
90
|
+
} from "node:fs";
|
|
91
|
+
import { join as join4 } from "node:path";
|
|
92
|
+
import { tmpdir } from "node:os";
|
|
93
|
+
|
|
94
|
+
// src/shared/worker-daemon/functions/load-wasm-modules.function.ts
|
|
95
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
96
|
+
import { join as join3 } from "node:path";
|
|
97
|
+
|
|
98
|
+
// src/shared/worker-daemon/functions/create-host-imports.function.ts
|
|
99
|
+
import {
|
|
100
|
+
readFileSync as readFileSync2,
|
|
101
|
+
writeFileSync,
|
|
102
|
+
renameSync,
|
|
103
|
+
unlinkSync,
|
|
104
|
+
readdirSync,
|
|
105
|
+
mkdirSync,
|
|
106
|
+
existsSync
|
|
107
|
+
} from "node:fs";
|
|
108
|
+
import { join as join2 } from "node:path";
|
|
109
|
+
var nodeFsAdapter = {
|
|
110
|
+
readFileSync: (p) => readFileSync2(p),
|
|
111
|
+
writeFileSync: (p, d) => {
|
|
112
|
+
writeFileSync(p, d);
|
|
113
|
+
},
|
|
114
|
+
renameSync: (o, n) => {
|
|
115
|
+
renameSync(o, n);
|
|
116
|
+
},
|
|
117
|
+
unlinkSync: (p) => {
|
|
118
|
+
unlinkSync(p);
|
|
119
|
+
},
|
|
120
|
+
readdirSync: (p) => readdirSync(p),
|
|
121
|
+
mkdirSync: (p) => {
|
|
122
|
+
mkdirSync(p, { recursive: true });
|
|
123
|
+
},
|
|
124
|
+
existsSync: (p) => existsSync(p)
|
|
125
|
+
};
|
|
126
|
+
var nullMemory = { memory: null };
|
|
127
|
+
var nullAllocator = { alloc: null };
|
|
128
|
+
function createHostImports(contextPath, memoryRef = nullMemory, fs = nodeFsAdapter, allocator = nullAllocator) {
|
|
129
|
+
function getBuffer() {
|
|
130
|
+
if (!memoryRef.memory) {
|
|
131
|
+
throw new Error("WASM memory not initialized");
|
|
132
|
+
}
|
|
133
|
+
return memoryRef.memory.buffer;
|
|
134
|
+
}
|
|
135
|
+
function readPathArg(ptr, len) {
|
|
136
|
+
const bytes = new Uint8Array(getBuffer(), ptr, len);
|
|
137
|
+
const relative = new TextDecoder().decode(bytes);
|
|
138
|
+
return join2(contextPath, relative);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
/**
|
|
142
|
+
* Reads a file at the path encoded in shared memory and writes
|
|
143
|
+
* the result back via the out-pointer protocol.
|
|
144
|
+
*
|
|
145
|
+
* `outPtr` and `outLen` are WASM linear-memory addresses. On
|
|
146
|
+
* success, the host allocates a buffer via `allocator.alloc`,
|
|
147
|
+
* copies the file data there, and writes the allocated pointer
|
|
148
|
+
* as a LE u32 to `outPtr` and the data length as a LE u32 to
|
|
149
|
+
* `outLen`. Returns 0 on success, -1 on error or when the
|
|
150
|
+
* allocator is not yet available.
|
|
151
|
+
*/
|
|
152
|
+
host_read_file(pathPtr, pathLen, outPtr, outLen) {
|
|
153
|
+
try {
|
|
154
|
+
if (!allocator.alloc) return -1;
|
|
155
|
+
const filePath = readPathArg(pathPtr, pathLen);
|
|
156
|
+
const data = fs.readFileSync(filePath);
|
|
157
|
+
const dataLen = data.byteLength;
|
|
158
|
+
const dv = new DataView(getBuffer());
|
|
159
|
+
if (dataLen === 0) {
|
|
160
|
+
dv.setUint32(outPtr, 0, true);
|
|
161
|
+
dv.setUint32(outLen, 0, true);
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
const dataPtr = allocator.alloc(dataLen);
|
|
165
|
+
if (dataPtr === 0) return -1;
|
|
166
|
+
const memView = new Uint8Array(getBuffer());
|
|
167
|
+
memView.set(
|
|
168
|
+
new Uint8Array(
|
|
169
|
+
data.buffer,
|
|
170
|
+
data.byteOffset,
|
|
171
|
+
data.byteLength
|
|
172
|
+
),
|
|
173
|
+
dataPtr
|
|
174
|
+
);
|
|
175
|
+
dv.setUint32(outPtr, dataPtr, true);
|
|
176
|
+
dv.setUint32(outLen, dataLen, true);
|
|
177
|
+
return 0;
|
|
178
|
+
} catch {
|
|
179
|
+
return -1;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* Writes bytes from shared memory (`dataPtr`, `dataLen`) to the
|
|
184
|
+
* file at the path encoded in shared memory. Returns 0 on
|
|
185
|
+
* success, -1 on error.
|
|
186
|
+
*/
|
|
187
|
+
host_write_file(pathPtr, pathLen, dataPtr, dataLen) {
|
|
188
|
+
try {
|
|
189
|
+
const filePath = readPathArg(pathPtr, pathLen);
|
|
190
|
+
const data = new Uint8Array(getBuffer(), dataPtr, dataLen);
|
|
191
|
+
fs.writeFileSync(filePath, data);
|
|
192
|
+
return 0;
|
|
193
|
+
} catch {
|
|
194
|
+
return -1;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Renames the file at `oldPtr/oldLen` to `newPtr/newLen`.
|
|
199
|
+
* Both paths are resolved relative to `contextPath`. Returns 0
|
|
200
|
+
* on success, -1 on error.
|
|
201
|
+
*/
|
|
202
|
+
host_rename(oldPtr, oldLen, newPtr, newLen) {
|
|
203
|
+
try {
|
|
204
|
+
const oldPath = readPathArg(oldPtr, oldLen);
|
|
205
|
+
const newPath = readPathArg(newPtr, newLen);
|
|
206
|
+
fs.renameSync(oldPath, newPath);
|
|
207
|
+
return 0;
|
|
208
|
+
} catch {
|
|
209
|
+
return -1;
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
/**
|
|
213
|
+
* Deletes the file at the path encoded in shared memory.
|
|
214
|
+
* Returns 0 on success, -1 on error.
|
|
215
|
+
*/
|
|
216
|
+
host_remove_file(pathPtr, pathLen) {
|
|
217
|
+
try {
|
|
218
|
+
const filePath = readPathArg(pathPtr, pathLen);
|
|
219
|
+
fs.unlinkSync(filePath);
|
|
220
|
+
return 0;
|
|
221
|
+
} catch {
|
|
222
|
+
return -1;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
/**
|
|
226
|
+
* Lists the directory at the path encoded in shared memory and
|
|
227
|
+
* writes the result back via the out-pointer protocol.
|
|
228
|
+
*
|
|
229
|
+
* `outPtr` and `outLen` are WASM linear-memory addresses. On
|
|
230
|
+
* success, the host allocates a buffer via `allocator.alloc`,
|
|
231
|
+
* copies a newline-delimited UTF-8 listing there, and writes
|
|
232
|
+
* the allocated pointer as a LE u32 to `outPtr` and the byte
|
|
233
|
+
* length as a LE u32 to `outLen`. Returns 0 on success, -1 on
|
|
234
|
+
* error or when the allocator is not yet available.
|
|
235
|
+
*/
|
|
236
|
+
host_list_dir(pathPtr, pathLen, outPtr, outLen) {
|
|
237
|
+
try {
|
|
238
|
+
if (!allocator.alloc) return -1;
|
|
239
|
+
const dirPath = readPathArg(pathPtr, pathLen);
|
|
240
|
+
const entries = fs.readdirSync(dirPath);
|
|
241
|
+
const text = entries.join("\n");
|
|
242
|
+
const encoded = new TextEncoder().encode(text);
|
|
243
|
+
const dv = new DataView(getBuffer());
|
|
244
|
+
if (encoded.length === 0) {
|
|
245
|
+
dv.setUint32(outPtr, 0, true);
|
|
246
|
+
dv.setUint32(outLen, 0, true);
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
249
|
+
const dataPtr = allocator.alloc(encoded.length);
|
|
250
|
+
if (dataPtr === 0) return -1;
|
|
251
|
+
new Uint8Array(getBuffer(), dataPtr, encoded.length).set(
|
|
252
|
+
encoded
|
|
253
|
+
);
|
|
254
|
+
dv.setUint32(outPtr, dataPtr, true);
|
|
255
|
+
dv.setUint32(outLen, encoded.length, true);
|
|
256
|
+
return 0;
|
|
257
|
+
} catch {
|
|
258
|
+
return -1;
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
/**
|
|
262
|
+
* Creates the directory at the path encoded in shared memory,
|
|
263
|
+
* including any missing parent directories (recursive). Returns
|
|
264
|
+
* 0 on success, -1 on error.
|
|
265
|
+
*/
|
|
266
|
+
host_mkdir(pathPtr, pathLen) {
|
|
267
|
+
try {
|
|
268
|
+
const dirPath = readPathArg(pathPtr, pathLen);
|
|
269
|
+
fs.mkdirSync(dirPath);
|
|
270
|
+
return 0;
|
|
271
|
+
} catch {
|
|
272
|
+
return -1;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
/**
|
|
276
|
+
* Checks whether the file at the path encoded in shared memory
|
|
277
|
+
* exists. Returns 1 if it exists, 0 if it does not.
|
|
278
|
+
*/
|
|
279
|
+
host_file_exists(pathPtr, pathLen) {
|
|
280
|
+
const filePath = readPathArg(pathPtr, pathLen);
|
|
281
|
+
return fs.existsSync(filePath) ? 1 : 0;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/shared/worker-daemon/functions/load-wasm-modules.function.ts
|
|
287
|
+
async function loadWasmModules(config, wasmDir2) {
|
|
288
|
+
const memoryRef = { memory: null };
|
|
289
|
+
const allocator = { alloc: null };
|
|
290
|
+
const hostImports = createHostImports(
|
|
291
|
+
config.contextPath,
|
|
292
|
+
memoryRef,
|
|
293
|
+
void 0,
|
|
294
|
+
allocator
|
|
295
|
+
);
|
|
296
|
+
const wkPath = join3(wasmDir2, "kb-worker", "kbdb_worker_bg.wasm");
|
|
297
|
+
const wkBytes = readWasmFileOrThrow(wkPath, "kb-worker");
|
|
298
|
+
let wkModule;
|
|
299
|
+
try {
|
|
300
|
+
wkModule = await WebAssembly.compile(wkBytes);
|
|
301
|
+
} catch (err) {
|
|
302
|
+
rethrow("compile", "kb-worker", err);
|
|
303
|
+
}
|
|
304
|
+
let kbWorker;
|
|
305
|
+
try {
|
|
306
|
+
kbWorker = await WebAssembly.instantiate(wkModule, {
|
|
307
|
+
env: { ...hostImports }
|
|
308
|
+
});
|
|
309
|
+
} catch (err) {
|
|
310
|
+
rethrow("instantiate", "kb-worker", err);
|
|
311
|
+
}
|
|
312
|
+
const memory = kbWorker.exports["memory"];
|
|
313
|
+
memoryRef.memory = memory;
|
|
314
|
+
allocator.alloc = (size) => {
|
|
315
|
+
const fn_ = kbWorker.exports["kbdb_alloc"];
|
|
316
|
+
if (typeof fn_ !== "function") return 0;
|
|
317
|
+
return fn_(size);
|
|
318
|
+
};
|
|
319
|
+
return { memory, kbWorker };
|
|
320
|
+
}
|
|
321
|
+
function readWasmFileOrThrow(path, label) {
|
|
322
|
+
try {
|
|
323
|
+
const buf = readFileSync3(path);
|
|
324
|
+
return buf.buffer.slice(
|
|
325
|
+
buf.byteOffset,
|
|
326
|
+
buf.byteOffset + buf.byteLength
|
|
327
|
+
);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
rethrow("load", label, err, path);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function rethrow(stage, label, err, path) {
|
|
333
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
334
|
+
const suffix = path ? ` (path: ${path})` : "";
|
|
335
|
+
const message = `failed to ${stage} ${label} WASM: ${detail}${suffix}`;
|
|
336
|
+
console.error(`kbdb-worker: ${message}`);
|
|
337
|
+
throw new Error(message, { cause: err });
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/shared/worker-daemon/functions/create-ipc-server.function.ts
|
|
341
|
+
import { createServer } from "node:net";
|
|
342
|
+
function createIpcServer(socketPath, handler) {
|
|
343
|
+
const server = createServer((socket) => {
|
|
344
|
+
let buffer = "";
|
|
345
|
+
socket.on("data", (chunk) => {
|
|
346
|
+
buffer += chunk.toString();
|
|
347
|
+
const lines = buffer.split("\n");
|
|
348
|
+
buffer = lines.pop() ?? "";
|
|
349
|
+
for (const line of lines) {
|
|
350
|
+
if (!line.trim()) continue;
|
|
351
|
+
void handleLine(line, handler, socket);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
socket.on("error", (err) => {
|
|
355
|
+
console.error(
|
|
356
|
+
`kbdb-worker: ipc connection error: ${err.message}`
|
|
357
|
+
);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
server.on("error", (err) => {
|
|
361
|
+
console.error(`kbdb-worker: ipc server error: ${err.message}`);
|
|
362
|
+
});
|
|
363
|
+
server.listen(socketPath);
|
|
364
|
+
return server;
|
|
365
|
+
}
|
|
366
|
+
function bigintReplacer(_key, value) {
|
|
367
|
+
return typeof value === "bigint" ? Number(value) : value;
|
|
368
|
+
}
|
|
369
|
+
async function handleLine(line, handler, socket) {
|
|
370
|
+
let response;
|
|
371
|
+
try {
|
|
372
|
+
const request = JSON.parse(line);
|
|
373
|
+
response = await handler(request);
|
|
374
|
+
} catch {
|
|
375
|
+
response = {
|
|
376
|
+
jsonrpc: "2.0",
|
|
377
|
+
id: 0,
|
|
378
|
+
error: {
|
|
379
|
+
code: -32700,
|
|
380
|
+
message: "Parse error"
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
socket.write(JSON.stringify(response, bigintReplacer) + "\n");
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/shared/wasm-codec/functions/encode-string.function.ts
|
|
388
|
+
var encoder = new TextEncoder();
|
|
389
|
+
function encodeString(value) {
|
|
390
|
+
const utf8 = encoder.encode(value);
|
|
391
|
+
const result = new Uint8Array(4 + utf8.length);
|
|
392
|
+
new DataView(result.buffer).setUint32(0, utf8.length, true);
|
|
393
|
+
result.set(utf8, 4);
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/shared/wasm-codec/functions/encode-u32.function.ts
|
|
398
|
+
function encodeU32(value) {
|
|
399
|
+
const result = new Uint8Array(4);
|
|
400
|
+
new DataView(result.buffer).setUint32(0, value, true);
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/shared/wasm-codec/functions/encode-option-string.function.ts
|
|
405
|
+
function encodeOptionString(value) {
|
|
406
|
+
if (value == null) {
|
|
407
|
+
return new Uint8Array([0]);
|
|
408
|
+
}
|
|
409
|
+
const encoded = encodeString(value);
|
|
410
|
+
const result = new Uint8Array(1 + encoded.length);
|
|
411
|
+
result[0] = 1;
|
|
412
|
+
result.set(encoded, 1);
|
|
413
|
+
return result;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/shared/wasm-codec/functions/encode-section-type.function.ts
|
|
417
|
+
function encodeSectionType(kind, mimeType) {
|
|
418
|
+
if (kind === "text") {
|
|
419
|
+
return new Uint8Array([0]);
|
|
420
|
+
}
|
|
421
|
+
const tag = kind === "code" ? 1 : 2;
|
|
422
|
+
const mime = mimeType ?? "text/plain";
|
|
423
|
+
const encoded = encodeString(mime);
|
|
424
|
+
const result = new Uint8Array(1 + encoded.length);
|
|
425
|
+
result[0] = tag;
|
|
426
|
+
result.set(encoded, 1);
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/shared/wasm-codec/functions/encode-add-section-params.function.ts
|
|
431
|
+
function encodeAddSectionParams(params) {
|
|
432
|
+
const parts = [
|
|
433
|
+
encodeSectionType(params.sectionType, params.mimeType),
|
|
434
|
+
encodeString(params.content),
|
|
435
|
+
encodeOptionString(params.title),
|
|
436
|
+
encodeOptionString(params.description),
|
|
437
|
+
encodeOptionString(params.docid),
|
|
438
|
+
encodeOptionString(params.typeName)
|
|
439
|
+
];
|
|
440
|
+
const totalLen = parts.reduce((sum, p) => sum + p.length, 0);
|
|
441
|
+
const result = new Uint8Array(totalLen);
|
|
442
|
+
let offset = 0;
|
|
443
|
+
for (const part of parts) {
|
|
444
|
+
result.set(part, offset);
|
|
445
|
+
offset += part.length;
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/shared/wasm-codec/functions/encode-update-section-params.function.ts
|
|
451
|
+
function encodeUpdateSectionParams(oldKbid, params) {
|
|
452
|
+
const kbidBytes = encodeString(oldKbid);
|
|
453
|
+
const paramBytes = encodeAddSectionParams(params);
|
|
454
|
+
const result = new Uint8Array(kbidBytes.length + paramBytes.length);
|
|
455
|
+
result.set(kbidBytes, 0);
|
|
456
|
+
result.set(paramBytes, kbidBytes.length);
|
|
457
|
+
return result;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/shared/wasm-codec/functions/encode-kbid-list.function.ts
|
|
461
|
+
function encodeKbidList(kbids) {
|
|
462
|
+
if (kbids.length === 0) {
|
|
463
|
+
return new Uint8Array(0);
|
|
464
|
+
}
|
|
465
|
+
const parts = [encodeU32(kbids.length), ...kbids.map(encodeString)];
|
|
466
|
+
const totalLen = parts.reduce((sum, p) => sum + p.length, 0);
|
|
467
|
+
const result = new Uint8Array(totalLen);
|
|
468
|
+
let offset = 0;
|
|
469
|
+
for (const part of parts) {
|
|
470
|
+
result.set(part, offset);
|
|
471
|
+
offset += part.length;
|
|
472
|
+
}
|
|
473
|
+
return result;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/shared/wasm-codec/functions/encode-group-params.function.ts
|
|
477
|
+
function encodeGroupParams(title, kbids, docType = "") {
|
|
478
|
+
const titleBytes = encodeString(title);
|
|
479
|
+
const listBytes = encodeKbidList(kbids);
|
|
480
|
+
const docTypeBytes = encodeString(docType);
|
|
481
|
+
const result = new Uint8Array(
|
|
482
|
+
titleBytes.length + listBytes.length + docTypeBytes.length
|
|
483
|
+
);
|
|
484
|
+
result.set(titleBytes, 0);
|
|
485
|
+
result.set(listBytes, titleBytes.length);
|
|
486
|
+
result.set(docTypeBytes, titleBytes.length + listBytes.length);
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/shared/wasm-codec/functions/encode-identifier-list.function.ts
|
|
491
|
+
function encodeIdentifierList(ids) {
|
|
492
|
+
if (ids.length === 0) {
|
|
493
|
+
return new Uint8Array(0);
|
|
494
|
+
}
|
|
495
|
+
const parts = [encodeU32(ids.length), ...ids.map(encodeString)];
|
|
496
|
+
const totalLen = parts.reduce((sum, p) => sum + p.length, 0);
|
|
497
|
+
const result = new Uint8Array(totalLen);
|
|
498
|
+
let offset = 0;
|
|
499
|
+
for (const part of parts) {
|
|
500
|
+
result.set(part, offset);
|
|
501
|
+
offset += part.length;
|
|
502
|
+
}
|
|
503
|
+
return result;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/shared/wasm-codec/functions/encode-search-params.function.ts
|
|
507
|
+
var encoder2 = new TextEncoder();
|
|
508
|
+
function encodeSearchParams(query, mode = "and", limit = 20) {
|
|
509
|
+
return encoder2.encode(`${query}
|
|
510
|
+
${mode}
|
|
511
|
+
${String(limit)}`);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/shared/wasm-codec/functions/encode-type-filter-param.function.ts
|
|
515
|
+
function encodeTypeFilterParam(typeStr) {
|
|
516
|
+
return new TextEncoder().encode(typeStr);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/shared/wasm-codec/functions/decode-string.function.ts
|
|
520
|
+
var decoder = new TextDecoder();
|
|
521
|
+
function decodeString(bytes, offset) {
|
|
522
|
+
const view = new DataView(
|
|
523
|
+
bytes.buffer,
|
|
524
|
+
bytes.byteOffset,
|
|
525
|
+
bytes.byteLength
|
|
526
|
+
);
|
|
527
|
+
const len = view.getUint32(offset, true);
|
|
528
|
+
const value = decoder.decode(
|
|
529
|
+
bytes.subarray(offset + 4, offset + 4 + len)
|
|
530
|
+
);
|
|
531
|
+
return { value, bytesRead: 4 + len };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/shared/wasm-codec/functions/decode-u32.function.ts
|
|
535
|
+
function decodeU32(bytes, offset) {
|
|
536
|
+
const view = new DataView(
|
|
537
|
+
bytes.buffer,
|
|
538
|
+
bytes.byteOffset,
|
|
539
|
+
bytes.byteLength
|
|
540
|
+
);
|
|
541
|
+
return {
|
|
542
|
+
value: view.getUint32(offset, true),
|
|
543
|
+
bytesRead: 4
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/shared/wasm-codec/functions/decode-f32.function.ts
|
|
548
|
+
function decodeF32(bytes, offset) {
|
|
549
|
+
const view = new DataView(
|
|
550
|
+
bytes.buffer,
|
|
551
|
+
bytes.byteOffset,
|
|
552
|
+
bytes.byteLength
|
|
553
|
+
);
|
|
554
|
+
return {
|
|
555
|
+
value: view.getFloat32(offset, true),
|
|
556
|
+
bytesRead: 4
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/shared/wasm-codec/functions/decode-u64.function.ts
|
|
561
|
+
function decodeU64(bytes, offset) {
|
|
562
|
+
const view = new DataView(
|
|
563
|
+
bytes.buffer,
|
|
564
|
+
bytes.byteOffset,
|
|
565
|
+
bytes.byteLength
|
|
566
|
+
);
|
|
567
|
+
return {
|
|
568
|
+
value: view.getBigUint64(offset, true),
|
|
569
|
+
bytesRead: 8
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/shared/wasm-codec/functions/decode-scored-results.function.ts
|
|
574
|
+
function decodeScoredResults(bytes) {
|
|
575
|
+
let offset = 0;
|
|
576
|
+
const count = decodeU32(bytes, offset);
|
|
577
|
+
offset += count.bytesRead;
|
|
578
|
+
const results = [];
|
|
579
|
+
for (let i = 0; i < count.value; i++) {
|
|
580
|
+
const kbid = decodeString(bytes, offset);
|
|
581
|
+
offset += kbid.bytesRead;
|
|
582
|
+
const score = decodeF32(bytes, offset);
|
|
583
|
+
offset += score.bytesRead;
|
|
584
|
+
const matchCount = decodeU32(bytes, offset);
|
|
585
|
+
offset += matchCount.bytesRead;
|
|
586
|
+
const matches = [];
|
|
587
|
+
for (let j = 0; j < matchCount.value; j++) {
|
|
588
|
+
const term = decodeString(bytes, offset);
|
|
589
|
+
offset += term.bytesRead;
|
|
590
|
+
const freq = decodeF32(bytes, offset);
|
|
591
|
+
offset += freq.bytesRead;
|
|
592
|
+
matches.push({
|
|
593
|
+
term: term.value,
|
|
594
|
+
frequency: freq.value
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
results.push({
|
|
598
|
+
kbid: kbid.value,
|
|
599
|
+
score: score.value,
|
|
600
|
+
matches
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return results;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/shared/wasm-codec/functions/decode-section-records.function.ts
|
|
607
|
+
function decodeOptionString(bytes, offset) {
|
|
608
|
+
const tag = bytes[offset];
|
|
609
|
+
if (tag === 0) {
|
|
610
|
+
return { value: null, bytesRead: 1 };
|
|
611
|
+
}
|
|
612
|
+
const str = decodeString(bytes, offset + 1);
|
|
613
|
+
return { value: str.value, bytesRead: 1 + str.bytesRead };
|
|
614
|
+
}
|
|
615
|
+
function decodeSectionType(bytes, offset) {
|
|
616
|
+
const tag = bytes[offset];
|
|
617
|
+
if (tag === 0) {
|
|
618
|
+
return { sectionType: "text", bytesRead: 1 };
|
|
619
|
+
}
|
|
620
|
+
const mime = decodeString(bytes, offset + 1);
|
|
621
|
+
const kind = tag === 1 ? "code" : "image";
|
|
622
|
+
return {
|
|
623
|
+
sectionType: kind,
|
|
624
|
+
mimeType: mime.value,
|
|
625
|
+
bytesRead: 1 + mime.bytesRead
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function decodeSectionRecords(bytes) {
|
|
629
|
+
let offset = 0;
|
|
630
|
+
const count = decodeU32(bytes, offset);
|
|
631
|
+
offset += count.bytesRead;
|
|
632
|
+
const records = [];
|
|
633
|
+
for (let i = 0; i < count.value; i++) {
|
|
634
|
+
const kbid = decodeString(bytes, offset);
|
|
635
|
+
offset += kbid.bytesRead;
|
|
636
|
+
const docid = decodeOptionString(bytes, offset);
|
|
637
|
+
offset += docid.bytesRead;
|
|
638
|
+
const st = decodeSectionType(bytes, offset);
|
|
639
|
+
offset += st.bytesRead;
|
|
640
|
+
const title = decodeOptionString(bytes, offset);
|
|
641
|
+
offset += title.bytesRead;
|
|
642
|
+
const description = decodeOptionString(bytes, offset);
|
|
643
|
+
offset += description.bytesRead;
|
|
644
|
+
const content = decodeString(bytes, offset);
|
|
645
|
+
offset += content.bytesRead;
|
|
646
|
+
const size = decodeU32(bytes, offset);
|
|
647
|
+
offset += size.bytesRead;
|
|
648
|
+
const createdAt = decodeU64(bytes, offset);
|
|
649
|
+
offset += createdAt.bytesRead;
|
|
650
|
+
const checksum = decodeString(bytes, offset);
|
|
651
|
+
offset += checksum.bytesRead;
|
|
652
|
+
const tokenCount = decodeU32(bytes, offset);
|
|
653
|
+
offset += tokenCount.bytesRead;
|
|
654
|
+
const headingTokenCount = decodeU32(bytes, offset);
|
|
655
|
+
offset += headingTokenCount.bytesRead;
|
|
656
|
+
const bodyTokenCount = decodeU32(bytes, offset);
|
|
657
|
+
offset += bodyTokenCount.bytesRead;
|
|
658
|
+
const codeTokenCount = decodeU32(bytes, offset);
|
|
659
|
+
offset += codeTokenCount.bytesRead;
|
|
660
|
+
const typeName = decodeString(bytes, offset);
|
|
661
|
+
offset += typeName.bytesRead;
|
|
662
|
+
const record = {
|
|
663
|
+
kbid: kbid.value,
|
|
664
|
+
docid: docid.value,
|
|
665
|
+
sectionType: st.sectionType,
|
|
666
|
+
title: title.value,
|
|
667
|
+
description: description.value,
|
|
668
|
+
content: content.value,
|
|
669
|
+
size: size.value,
|
|
670
|
+
createdAt: createdAt.value,
|
|
671
|
+
checksum: checksum.value,
|
|
672
|
+
tokenCount: tokenCount.value,
|
|
673
|
+
headingTokenCount: headingTokenCount.value,
|
|
674
|
+
bodyTokenCount: bodyTokenCount.value,
|
|
675
|
+
codeTokenCount: codeTokenCount.value,
|
|
676
|
+
typeName: typeName.value
|
|
677
|
+
};
|
|
678
|
+
if (st.mimeType !== void 0) {
|
|
679
|
+
record.mimeType = st.mimeType;
|
|
680
|
+
}
|
|
681
|
+
records.push(record);
|
|
682
|
+
}
|
|
683
|
+
return records;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/shared/wasm-codec/functions/decode-section-record-list.function.ts
|
|
687
|
+
function decodeSectionRecordList(bytes) {
|
|
688
|
+
return decodeSectionRecords(bytes);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/shared/wasm-codec/functions/decode-document-manifest.function.ts
|
|
692
|
+
function decodeDocumentManifest(bytes) {
|
|
693
|
+
let offset = 0;
|
|
694
|
+
const docid = decodeString(bytes, offset);
|
|
695
|
+
offset += docid.bytesRead;
|
|
696
|
+
const title = decodeString(bytes, offset);
|
|
697
|
+
offset += title.bytesRead;
|
|
698
|
+
const createdAt = decodeU64(bytes, offset);
|
|
699
|
+
offset += createdAt.bytesRead;
|
|
700
|
+
const docType = decodeString(bytes, offset);
|
|
701
|
+
offset += docType.bytesRead;
|
|
702
|
+
const count = decodeU32(bytes, offset);
|
|
703
|
+
offset += count.bytesRead;
|
|
704
|
+
const sections = [];
|
|
705
|
+
for (let i = 0; i < count.value; i++) {
|
|
706
|
+
const kbid = decodeString(bytes, offset);
|
|
707
|
+
offset += kbid.bytesRead;
|
|
708
|
+
const position = decodeU32(bytes, offset);
|
|
709
|
+
offset += position.bytesRead;
|
|
710
|
+
sections.push({
|
|
711
|
+
kbid: kbid.value,
|
|
712
|
+
position: position.value
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
docid: docid.value,
|
|
717
|
+
title: title.value,
|
|
718
|
+
createdAt: createdAt.value,
|
|
719
|
+
docType: docType.value,
|
|
720
|
+
sections
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/shared/wasm-codec/functions/decode-document-manifest-list.function.ts
|
|
725
|
+
function decodeDocumentManifestList(bytes) {
|
|
726
|
+
let offset = 0;
|
|
727
|
+
const count = decodeU32(bytes, offset);
|
|
728
|
+
offset += count.bytesRead;
|
|
729
|
+
const manifests = [];
|
|
730
|
+
for (let i = 0; i < count.value; i++) {
|
|
731
|
+
const docid = decodeString(bytes, offset);
|
|
732
|
+
offset += docid.bytesRead;
|
|
733
|
+
const title = decodeString(bytes, offset);
|
|
734
|
+
offset += title.bytesRead;
|
|
735
|
+
const createdAt = decodeU64(bytes, offset);
|
|
736
|
+
offset += createdAt.bytesRead;
|
|
737
|
+
const docType = decodeString(bytes, offset);
|
|
738
|
+
offset += docType.bytesRead;
|
|
739
|
+
const secCount = decodeU32(bytes, offset);
|
|
740
|
+
offset += secCount.bytesRead;
|
|
741
|
+
const sections = [];
|
|
742
|
+
for (let j = 0; j < secCount.value; j++) {
|
|
743
|
+
const kbid = decodeString(bytes, offset);
|
|
744
|
+
offset += kbid.bytesRead;
|
|
745
|
+
const position = decodeU32(bytes, offset);
|
|
746
|
+
offset += position.bytesRead;
|
|
747
|
+
sections.push({
|
|
748
|
+
kbid: kbid.value,
|
|
749
|
+
position: position.value
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
manifests.push({
|
|
753
|
+
docid: docid.value,
|
|
754
|
+
title: title.value,
|
|
755
|
+
createdAt: createdAt.value,
|
|
756
|
+
docType: docType.value,
|
|
757
|
+
sections
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
return manifests;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/shared/wasm-codec/functions/decode-compose-output.function.ts
|
|
764
|
+
function decodeComposeOutput(bytes) {
|
|
765
|
+
const md = decodeString(bytes, 0);
|
|
766
|
+
const totalChars = decodeU64(bytes, md.bytesRead);
|
|
767
|
+
return {
|
|
768
|
+
markdown: md.value,
|
|
769
|
+
totalChars: totalChars.value
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/shared/wasm-codec/functions/decode-key-value-text.function.ts
|
|
774
|
+
function decodeKeyValueText(text) {
|
|
775
|
+
const result = {};
|
|
776
|
+
for (const line of text.split("\n")) {
|
|
777
|
+
const idx = line.indexOf("=");
|
|
778
|
+
if (idx < 0) continue;
|
|
779
|
+
const key = line.slice(0, idx);
|
|
780
|
+
const value = line.slice(idx + 1);
|
|
781
|
+
if (key) {
|
|
782
|
+
result[key] = value;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
return result;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// src/shared/wasm-codec/functions/decode-remove-flag.function.ts
|
|
789
|
+
function decodeRemoveFlag(bytes) {
|
|
790
|
+
return bytes.length > 0 && bytes[0] === 1;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/shared/worker-daemon/classes/worker-daemon.class.ts
|
|
794
|
+
var WASM_METHOD_MAP = {
|
|
795
|
+
search: "worker_search",
|
|
796
|
+
addSection: "worker_add_section",
|
|
797
|
+
add_section: "worker_add_section",
|
|
798
|
+
updateSection: "worker_update_section",
|
|
799
|
+
update_section: "worker_update_section",
|
|
800
|
+
removeSection: "worker_remove_section",
|
|
801
|
+
remove_section: "worker_remove_section",
|
|
802
|
+
readSections: "worker_read_sections",
|
|
803
|
+
read_sections: "worker_read_sections",
|
|
804
|
+
groupSections: "worker_group_sections",
|
|
805
|
+
group_sections: "worker_group_sections",
|
|
806
|
+
removeGrouping: "worker_remove_grouping",
|
|
807
|
+
remove_grouping: "worker_remove_grouping",
|
|
808
|
+
retrieveDocument: "worker_retrieve_doc",
|
|
809
|
+
retrieve_doc: "worker_retrieve_doc",
|
|
810
|
+
content: "worker_compose",
|
|
811
|
+
compose: "worker_compose",
|
|
812
|
+
integrity_check: "worker_check_integrity",
|
|
813
|
+
integrityCheck: "worker_check_integrity",
|
|
814
|
+
gc: "worker_garbage_collect",
|
|
815
|
+
rebuild_indexes: "worker_rebuild_indexes",
|
|
816
|
+
rebuildIndexes: "worker_rebuild_indexes",
|
|
817
|
+
init_directory: "worker_init_directory",
|
|
818
|
+
initDirectory: "worker_init_directory",
|
|
819
|
+
migrateDatabase: "worker_migrate",
|
|
820
|
+
query: "worker_query",
|
|
821
|
+
get_result_status: "worker_result_status",
|
|
822
|
+
get_result: "worker_get_result",
|
|
823
|
+
invalidate: "worker_invalidate",
|
|
824
|
+
invalidate_all: "worker_invalidate_all",
|
|
825
|
+
invalidateAll: "worker_invalidate_all",
|
|
826
|
+
db_status: "worker_status",
|
|
827
|
+
dbStatus: "worker_status",
|
|
828
|
+
listByType: "worker_list_by_type",
|
|
829
|
+
list_by_type: "worker_list_by_type",
|
|
830
|
+
listDocumentsByType: "worker_list_docs_by_type",
|
|
831
|
+
list_docs_by_type: "worker_list_docs_by_type"
|
|
832
|
+
};
|
|
833
|
+
var CONFIG_PREFIX = "config_";
|
|
834
|
+
var CONFIG_KEY_MAP = {
|
|
835
|
+
timeout_ms: "timeoutMs",
|
|
836
|
+
item_ttl_ms: "itemTtlMs",
|
|
837
|
+
item_limit: "itemLimit",
|
|
838
|
+
index_limit: "indexLimit"
|
|
839
|
+
};
|
|
840
|
+
var IpcError = class extends Error {
|
|
841
|
+
/** JSON-RPC error code. */
|
|
842
|
+
code;
|
|
843
|
+
constructor(code, message) {
|
|
844
|
+
super(message);
|
|
845
|
+
this.code = code;
|
|
846
|
+
this.name = "IpcError";
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
var WorkerDaemon = class {
|
|
850
|
+
/** Context ID (16-character hex SHA-256 prefix). */
|
|
851
|
+
ctx;
|
|
852
|
+
/** Absolute path to the `.kbdb` directory. */
|
|
853
|
+
targetDir;
|
|
854
|
+
/** Parsed daemon configuration from `worker.toml`. */
|
|
855
|
+
config;
|
|
856
|
+
/** Number of currently active IPC client connections. */
|
|
857
|
+
get connectionCount() {
|
|
858
|
+
return this._connectionCount;
|
|
859
|
+
}
|
|
860
|
+
_connectionCount = 0;
|
|
861
|
+
_wasmModules = null;
|
|
862
|
+
_idleAt = 0;
|
|
863
|
+
_idleTimer = null;
|
|
864
|
+
_server = null;
|
|
865
|
+
_wasmDir;
|
|
866
|
+
/**
|
|
867
|
+
* @param ctx - context ID (16-hex characters), the first 16 of
|
|
868
|
+
* the SHA-256 hash of `targetDir`
|
|
869
|
+
* @param targetDir - absolute path to the `.kbdb` directory
|
|
870
|
+
* @param config - parsed daemon configuration
|
|
871
|
+
* @param wasmDir - path to the WASM build output directory
|
|
872
|
+
*/
|
|
873
|
+
constructor(ctx, targetDir, config, wasmDir2) {
|
|
874
|
+
this.ctx = ctx;
|
|
875
|
+
this.targetDir = targetDir;
|
|
876
|
+
this.config = config;
|
|
877
|
+
this._wasmDir = wasmDir2 ?? "";
|
|
878
|
+
}
|
|
879
|
+
// -----------------------------------------------------------------------
|
|
880
|
+
// Public API
|
|
881
|
+
// -----------------------------------------------------------------------
|
|
882
|
+
/**
|
|
883
|
+
* Validates startup preconditions before WASM module loading.
|
|
884
|
+
*
|
|
885
|
+
* Checks that the database directory exists, is readable and
|
|
886
|
+
* writable, and that `catalog.toml` reports a compatible version.
|
|
887
|
+
*
|
|
888
|
+
* @throws {Error} if any precondition fails -- `startDaemon`
|
|
889
|
+
* catches this, prints to stderr, and exits with code 1
|
|
890
|
+
*/
|
|
891
|
+
checkPreconditions() {
|
|
892
|
+
if (!existsSync2(this.targetDir)) {
|
|
893
|
+
throw new Error(
|
|
894
|
+
`database directory not found: ${this.targetDir}`
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
try {
|
|
898
|
+
accessSync(
|
|
899
|
+
this.targetDir,
|
|
900
|
+
constants.R_OK | constants.W_OK
|
|
901
|
+
);
|
|
902
|
+
} catch {
|
|
903
|
+
throw new Error(
|
|
904
|
+
`cannot access database directory: ${this.targetDir} -- permission denied`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
this.checkCatalogVersion();
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Starts the daemon: loads WASM modules, writes the PID file,
|
|
911
|
+
* creates the IPC socket, and begins listening for connections.
|
|
912
|
+
*
|
|
913
|
+
* Call `checkPreconditions()` before `start()` to validate the
|
|
914
|
+
* database directory. The daemon will not start if any precondition
|
|
915
|
+
* fails.
|
|
916
|
+
*
|
|
917
|
+
* @throws when WASM module loading fails or the IPC socket cannot
|
|
918
|
+
* be created
|
|
919
|
+
*/
|
|
920
|
+
async start() {
|
|
921
|
+
const wasmModules = await loadWasmModules(
|
|
922
|
+
this.config,
|
|
923
|
+
this._wasmDir
|
|
924
|
+
);
|
|
925
|
+
this._wasmModules = wasmModules;
|
|
926
|
+
this.initWorkerContext();
|
|
927
|
+
const pidPath = join4(tmpdir(), `kbdb-${this.ctx}.pid`);
|
|
928
|
+
writeFileSync2(pidPath, process.pid.toString());
|
|
929
|
+
const ipcPath = getIpcPath(this.ctx);
|
|
930
|
+
if (existsSync2(ipcPath)) {
|
|
931
|
+
try {
|
|
932
|
+
unlinkSync2(ipcPath);
|
|
933
|
+
} catch {
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
const handler = (req) => this.handleRequest(req);
|
|
937
|
+
this._server = createIpcServer(ipcPath, handler);
|
|
938
|
+
this._server.on("connection", () => {
|
|
939
|
+
this.incrementConnections();
|
|
940
|
+
this.resetIdleTimer();
|
|
941
|
+
});
|
|
942
|
+
this._server.on("close", () => {
|
|
943
|
+
this.decrementConnections();
|
|
944
|
+
if (this._connectionCount === 0) {
|
|
945
|
+
this.resetIdleTimer();
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
this.resetIdleTimer();
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Gracefully shuts down the daemon.
|
|
952
|
+
*
|
|
953
|
+
* Stops accepting new connections, clears the idle timer, purges
|
|
954
|
+
* WASM state, removes the PID file and IPC socket file, then exits
|
|
955
|
+
* the process.
|
|
956
|
+
*/
|
|
957
|
+
stop() {
|
|
958
|
+
if (this._idleTimer !== null) {
|
|
959
|
+
clearTimeout(this._idleTimer);
|
|
960
|
+
this._idleTimer = null;
|
|
961
|
+
}
|
|
962
|
+
if (this._server !== null) {
|
|
963
|
+
this._server.close();
|
|
964
|
+
this._server = null;
|
|
965
|
+
}
|
|
966
|
+
this._wasmModules = null;
|
|
967
|
+
const pidPath = join4(tmpdir(), `kbdb-${this.ctx}.pid`);
|
|
968
|
+
try {
|
|
969
|
+
unlinkSync2(pidPath);
|
|
970
|
+
} catch {
|
|
971
|
+
}
|
|
972
|
+
const ipcPath = getIpcPath(this.ctx);
|
|
973
|
+
try {
|
|
974
|
+
unlinkSync2(ipcPath);
|
|
975
|
+
} catch {
|
|
976
|
+
}
|
|
977
|
+
const crashPath = join4(tmpdir(), `kbdb-${this.ctx}.crash`);
|
|
978
|
+
try {
|
|
979
|
+
unlinkSync2(crashPath);
|
|
980
|
+
} catch {
|
|
981
|
+
}
|
|
982
|
+
process.exit(0);
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Handles a single JSON-RPC 2.0 request.
|
|
986
|
+
*
|
|
987
|
+
* Validates context, then routes to a daemon-state handler or a
|
|
988
|
+
* WASM export. Requests whose `ctx` param does not match the
|
|
989
|
+
* daemon's context ID are rejected with error code `-32001`.
|
|
990
|
+
*
|
|
991
|
+
* @param request - incoming JSON-RPC request
|
|
992
|
+
* @returns the JSON-RPC response
|
|
993
|
+
*/
|
|
994
|
+
async handleRequest(request) {
|
|
995
|
+
const params = request.params;
|
|
996
|
+
if (params === void 0 || params.ctx !== this.ctx) {
|
|
997
|
+
return this.errorResponse(
|
|
998
|
+
request.id,
|
|
999
|
+
-32001,
|
|
1000
|
+
"context mismatch"
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
this.resetIdleTimer();
|
|
1004
|
+
try {
|
|
1005
|
+
const result = await this.dispatch(request.method, params);
|
|
1006
|
+
this._idleAt = Math.floor(Date.now() / 1e3);
|
|
1007
|
+
return {
|
|
1008
|
+
jsonrpc: "2.0",
|
|
1009
|
+
id: request.id,
|
|
1010
|
+
result
|
|
1011
|
+
};
|
|
1012
|
+
} catch (err) {
|
|
1013
|
+
this._idleAt = Math.floor(Date.now() / 1e3);
|
|
1014
|
+
if (err instanceof IpcError) {
|
|
1015
|
+
return this.errorResponse(
|
|
1016
|
+
request.id,
|
|
1017
|
+
err.code,
|
|
1018
|
+
err.message
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1022
|
+
return this.errorResponse(request.id, -32e3, message);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Increments the active connection count.
|
|
1027
|
+
*
|
|
1028
|
+
* Call when a new IPC client connects.
|
|
1029
|
+
*/
|
|
1030
|
+
incrementConnections() {
|
|
1031
|
+
this._connectionCount++;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Decrements the active connection count, clamped to zero.
|
|
1035
|
+
*
|
|
1036
|
+
* Call when an IPC client disconnects.
|
|
1037
|
+
*/
|
|
1038
|
+
decrementConnections() {
|
|
1039
|
+
if (this._connectionCount > 0) {
|
|
1040
|
+
this._connectionCount--;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Injects pre-built WASM modules for unit testing.
|
|
1045
|
+
*
|
|
1046
|
+
* This method exists solely to support unit tests that cannot
|
|
1047
|
+
* load real WASM binaries. It must not be called in production
|
|
1048
|
+
* code -- production code uses `start()` to load modules.
|
|
1049
|
+
*
|
|
1050
|
+
* @param modules - pre-built WASM module instances
|
|
1051
|
+
* @internal
|
|
1052
|
+
*/
|
|
1053
|
+
injectModulesForTesting(modules) {
|
|
1054
|
+
this._wasmModules = modules;
|
|
1055
|
+
}
|
|
1056
|
+
// -----------------------------------------------------------------------
|
|
1057
|
+
// Private helpers
|
|
1058
|
+
// -----------------------------------------------------------------------
|
|
1059
|
+
/** Resets the idle timer; triggers stop() when it fires. */
|
|
1060
|
+
resetIdleTimer() {
|
|
1061
|
+
if (this._idleTimer !== null) {
|
|
1062
|
+
clearTimeout(this._idleTimer);
|
|
1063
|
+
}
|
|
1064
|
+
if (this._connectionCount === 0) {
|
|
1065
|
+
this._idleTimer = setTimeout(() => {
|
|
1066
|
+
this.stop();
|
|
1067
|
+
}, this.config.timeoutMs);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
/** Reads catalog.toml and validates the version field. */
|
|
1071
|
+
checkCatalogVersion() {
|
|
1072
|
+
const catalogPath = join4(this.targetDir, "catalog.toml");
|
|
1073
|
+
let text;
|
|
1074
|
+
try {
|
|
1075
|
+
text = readFileSync4(catalogPath, "utf-8");
|
|
1076
|
+
} catch {
|
|
1077
|
+
throw new Error(
|
|
1078
|
+
`cannot read database directory: ${this.targetDir} -- permission denied`
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
const version = parseCatalogVersion(text);
|
|
1082
|
+
if (version === null) {
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
"database version 0 requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon"
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
if (version > DB_FORMAT_VERSION) {
|
|
1088
|
+
throw new Error(
|
|
1089
|
+
"database version " + String(version) + " is newer than kbdb version " + String(DB_FORMAT_VERSION) + " -- upgrade kbdb to open this database"
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
if (version < DB_FORMAT_VERSION) {
|
|
1093
|
+
throw new Error(
|
|
1094
|
+
"database version " + String(version) + " requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon"
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
/** Builds a JSON-RPC error response. */
|
|
1099
|
+
errorResponse(id, code, message) {
|
|
1100
|
+
return {
|
|
1101
|
+
jsonrpc: "2.0",
|
|
1102
|
+
id,
|
|
1103
|
+
error: { code, message }
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Dispatches a request method to the appropriate handler.
|
|
1108
|
+
*
|
|
1109
|
+
* Handles daemon-state methods (`status`, `idle_at`,
|
|
1110
|
+
* `config_{key}`) inline and routes WASM methods to the
|
|
1111
|
+
* correct calling convention for each export.
|
|
1112
|
+
*/
|
|
1113
|
+
dispatch(method, params) {
|
|
1114
|
+
if (method === "status") {
|
|
1115
|
+
return this._connectionCount > 0 ? "busy" : "idle";
|
|
1116
|
+
}
|
|
1117
|
+
if (method === "idle_at") {
|
|
1118
|
+
return this._idleAt;
|
|
1119
|
+
}
|
|
1120
|
+
if (method === "checkVersion") {
|
|
1121
|
+
return this.handleCheckVersion(params);
|
|
1122
|
+
}
|
|
1123
|
+
if (method.startsWith(CONFIG_PREFIX)) {
|
|
1124
|
+
return this.handleConfigMethod(method);
|
|
1125
|
+
}
|
|
1126
|
+
const wasmMethod = WASM_METHOD_MAP[method];
|
|
1127
|
+
if (wasmMethod !== void 0) {
|
|
1128
|
+
return this.dispatchWasm(method, wasmMethod, params);
|
|
1129
|
+
}
|
|
1130
|
+
throw new IpcError(-32601, `Method not found: ${method}`);
|
|
1131
|
+
}
|
|
1132
|
+
dispatchWasm(method, wasmExport, params) {
|
|
1133
|
+
if (method === "search" || method === "query") {
|
|
1134
|
+
return this.handleSearch(params);
|
|
1135
|
+
}
|
|
1136
|
+
if (method === "addSection" || method === "add_section") {
|
|
1137
|
+
return this.handleAddSection(params);
|
|
1138
|
+
}
|
|
1139
|
+
if (method === "updateSection" || method === "update_section") {
|
|
1140
|
+
return this.handleUpdateSection(params);
|
|
1141
|
+
}
|
|
1142
|
+
if (method === "removeSection" || method === "remove_section") {
|
|
1143
|
+
return this.handleRemoveSection(params);
|
|
1144
|
+
}
|
|
1145
|
+
if (method === "readSections" || method === "read_sections") {
|
|
1146
|
+
return this.handleReadSections(params);
|
|
1147
|
+
}
|
|
1148
|
+
if (method === "retrieveDocument" || method === "retrieve_doc") {
|
|
1149
|
+
return this.handleRetrieveDoc(params);
|
|
1150
|
+
}
|
|
1151
|
+
if (method === "groupSections" || method === "group_sections") {
|
|
1152
|
+
return this.handleGroupSections(params);
|
|
1153
|
+
}
|
|
1154
|
+
if (method === "removeGrouping" || method === "remove_grouping") {
|
|
1155
|
+
return this.handleRemoveGrouping(params);
|
|
1156
|
+
}
|
|
1157
|
+
if (method === "content" || method === "compose") {
|
|
1158
|
+
return this.handleCompose(params);
|
|
1159
|
+
}
|
|
1160
|
+
if (method === "integrityCheck" || method === "integrity_check") {
|
|
1161
|
+
return this.handleIntegrityCheck();
|
|
1162
|
+
}
|
|
1163
|
+
if (method === "gc") {
|
|
1164
|
+
return this.handleGc();
|
|
1165
|
+
}
|
|
1166
|
+
if (method === "rebuildIndexes" || method === "rebuild_indexes") {
|
|
1167
|
+
return this.handleRebuild();
|
|
1168
|
+
}
|
|
1169
|
+
if (method === "dbStatus" || method === "db_status") {
|
|
1170
|
+
return this.handleDbStatus();
|
|
1171
|
+
}
|
|
1172
|
+
if (method === "initDirectory" || method === "init_directory") {
|
|
1173
|
+
return this.handleInitDirectory(params);
|
|
1174
|
+
}
|
|
1175
|
+
if (method === "invalidate") {
|
|
1176
|
+
return this.handleInvalidate(params);
|
|
1177
|
+
}
|
|
1178
|
+
if (method === "invalidateAll" || method === "invalidate_all") {
|
|
1179
|
+
return this.handleInvalidateAll();
|
|
1180
|
+
}
|
|
1181
|
+
if (method === "get_result_status") {
|
|
1182
|
+
return this.handleResultStatus(params);
|
|
1183
|
+
}
|
|
1184
|
+
if (method === "get_result") {
|
|
1185
|
+
return this.handleGetResult(params);
|
|
1186
|
+
}
|
|
1187
|
+
if (method === "migrateDatabase") {
|
|
1188
|
+
throw new IpcError(
|
|
1189
|
+
-32601,
|
|
1190
|
+
"migrateDatabase is not yet supported"
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
if (method === "listByType" || method === "list_by_type") {
|
|
1194
|
+
return this.handleListByType(params);
|
|
1195
|
+
}
|
|
1196
|
+
if (method === "listDocumentsByType" || method === "list_docs_by_type") {
|
|
1197
|
+
return this.handleListDocsByType(params);
|
|
1198
|
+
}
|
|
1199
|
+
return this.invokeWasmRaw(wasmExport, new Uint8Array(0));
|
|
1200
|
+
}
|
|
1201
|
+
// -- Search/query (token-based async) --
|
|
1202
|
+
handleSearch(params) {
|
|
1203
|
+
const query = params["query"] ?? "";
|
|
1204
|
+
const mode = params["mode"] ?? "and";
|
|
1205
|
+
const limit = Number(params["limit"] ?? 20);
|
|
1206
|
+
const encoded = encodeSearchParams(query, mode, limit);
|
|
1207
|
+
const searchFn = this.getExport("worker_search");
|
|
1208
|
+
const ptr = this.wasmAlloc(encoded.length);
|
|
1209
|
+
this.wasmWrite(ptr, encoded);
|
|
1210
|
+
const token = searchFn(ptr, encoded.length);
|
|
1211
|
+
this.wasmFree(ptr, encoded.length);
|
|
1212
|
+
const statusFn = this.getExport("worker_result_status");
|
|
1213
|
+
const status = statusFn(token);
|
|
1214
|
+
if (status === 3) {
|
|
1215
|
+
const getResultFn2 = this.getExport("worker_get_result");
|
|
1216
|
+
getResultFn2(token);
|
|
1217
|
+
const errBytes = this.readReturnSlot();
|
|
1218
|
+
const errMsg = new TextDecoder().decode(errBytes);
|
|
1219
|
+
throw new IpcError(-32e3, errMsg);
|
|
1220
|
+
}
|
|
1221
|
+
const getResultFn = this.getExport("worker_get_result");
|
|
1222
|
+
const rc = getResultFn(token);
|
|
1223
|
+
if (rc === -1) {
|
|
1224
|
+
const errBytes = this.readReturnSlot();
|
|
1225
|
+
throw new IpcError(-32e3, new TextDecoder().decode(errBytes));
|
|
1226
|
+
}
|
|
1227
|
+
const resultBytes = this.readReturnSlot();
|
|
1228
|
+
return decodeScoredResults(resultBytes);
|
|
1229
|
+
}
|
|
1230
|
+
// -- Token status/result (u32 direct params) --
|
|
1231
|
+
handleResultStatus(params) {
|
|
1232
|
+
const token = Number(params["token"] ?? 0);
|
|
1233
|
+
const fn = this.getExport("worker_result_status");
|
|
1234
|
+
const status = fn(token);
|
|
1235
|
+
return { status };
|
|
1236
|
+
}
|
|
1237
|
+
handleGetResult(params) {
|
|
1238
|
+
const token = Number(params["token"] ?? 0);
|
|
1239
|
+
const fn = this.getExport("worker_get_result");
|
|
1240
|
+
const rc = fn(token);
|
|
1241
|
+
if (rc === -1) {
|
|
1242
|
+
const errBytes = this.readReturnSlot();
|
|
1243
|
+
throw new IpcError(-32e3, new TextDecoder().decode(errBytes));
|
|
1244
|
+
}
|
|
1245
|
+
const bytes = this.readReturnSlot();
|
|
1246
|
+
return decodeScoredResults(bytes);
|
|
1247
|
+
}
|
|
1248
|
+
// -- Binary-encoded input methods --
|
|
1249
|
+
handleAddSection(params) {
|
|
1250
|
+
const sectionType = params["sectionType"] ?? "text";
|
|
1251
|
+
const semanticType = sectionType === "text" || sectionType === "code" || sectionType === "image" ? sectionType : "text";
|
|
1252
|
+
const typeName = sectionType !== semanticType ? sectionType : null;
|
|
1253
|
+
const input = {
|
|
1254
|
+
sectionType: semanticType,
|
|
1255
|
+
mimeType: params["mimeType"],
|
|
1256
|
+
content: params["content"] ?? "",
|
|
1257
|
+
title: params["title"] ?? null,
|
|
1258
|
+
description: params["description"] ?? null,
|
|
1259
|
+
docid: params["docid"] ?? null,
|
|
1260
|
+
typeName
|
|
1261
|
+
};
|
|
1262
|
+
const encoded = encodeAddSectionParams(input);
|
|
1263
|
+
const bytes = this.callWasmSync("worker_add_section", encoded);
|
|
1264
|
+
const kbid = new TextDecoder().decode(bytes);
|
|
1265
|
+
return { kbid };
|
|
1266
|
+
}
|
|
1267
|
+
handleUpdateSection(params) {
|
|
1268
|
+
const oldKbid = params["kbid"] ?? "";
|
|
1269
|
+
const updSectionType = params["sectionType"] ?? "text";
|
|
1270
|
+
const updSemanticType = updSectionType === "text" || updSectionType === "code" || updSectionType === "image" ? updSectionType : "text";
|
|
1271
|
+
const updTypeName = updSectionType !== updSemanticType ? updSectionType : null;
|
|
1272
|
+
const input = {
|
|
1273
|
+
sectionType: updSemanticType,
|
|
1274
|
+
mimeType: params["mimeType"],
|
|
1275
|
+
content: params["content"] ?? "",
|
|
1276
|
+
title: params["title"] ?? null,
|
|
1277
|
+
description: params["description"] ?? null,
|
|
1278
|
+
docid: params["docid"] ?? null,
|
|
1279
|
+
typeName: updTypeName
|
|
1280
|
+
};
|
|
1281
|
+
const encoded = encodeUpdateSectionParams(oldKbid, input);
|
|
1282
|
+
const bytes = this.callWasmSync("worker_update_section", encoded);
|
|
1283
|
+
const newKbid = new TextDecoder().decode(bytes);
|
|
1284
|
+
return { kbid: newKbid };
|
|
1285
|
+
}
|
|
1286
|
+
handleReadSections(params) {
|
|
1287
|
+
const kbids = params["kbids"] ?? [];
|
|
1288
|
+
const encoded = encodeKbidList(kbids);
|
|
1289
|
+
const bytes = this.callWasmSync("worker_read_sections", encoded);
|
|
1290
|
+
return decodeSectionRecords(bytes);
|
|
1291
|
+
}
|
|
1292
|
+
handleGroupSections(params) {
|
|
1293
|
+
const title = params["title"] ?? "";
|
|
1294
|
+
const kbids = params["kbids"] ?? [];
|
|
1295
|
+
const docType = params["docType"] ?? "";
|
|
1296
|
+
const encoded = encodeGroupParams(title, kbids, docType);
|
|
1297
|
+
const bytes = this.callWasmSync("worker_group_sections", encoded);
|
|
1298
|
+
const docid = new TextDecoder().decode(bytes);
|
|
1299
|
+
return { docid };
|
|
1300
|
+
}
|
|
1301
|
+
handleCompose(params) {
|
|
1302
|
+
const ids = params["ids"] ?? [];
|
|
1303
|
+
const encoded = encodeIdentifierList(ids);
|
|
1304
|
+
const bytes = this.callWasmSync("worker_compose", encoded);
|
|
1305
|
+
const output = decodeComposeOutput(bytes);
|
|
1306
|
+
return {
|
|
1307
|
+
data: output.markdown,
|
|
1308
|
+
total: Number(output.totalChars)
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
// -- Raw UTF-8 string input methods --
|
|
1312
|
+
handleRemoveSection(params) {
|
|
1313
|
+
const kbid = params["kbid"] ?? "";
|
|
1314
|
+
const encoded = new TextEncoder().encode(kbid);
|
|
1315
|
+
const bytes = this.callWasmSync("worker_remove_section", encoded);
|
|
1316
|
+
return { removed: decodeRemoveFlag(bytes) };
|
|
1317
|
+
}
|
|
1318
|
+
handleRetrieveDoc(params) {
|
|
1319
|
+
const docid = params["docid"] ?? "";
|
|
1320
|
+
const encoded = new TextEncoder().encode(docid);
|
|
1321
|
+
const bytes = this.callWasmSync("worker_retrieve_doc", encoded);
|
|
1322
|
+
return decodeDocumentManifest(bytes);
|
|
1323
|
+
}
|
|
1324
|
+
handleRemoveGrouping(params) {
|
|
1325
|
+
const docid = params["docid"] ?? "";
|
|
1326
|
+
const encoded = new TextEncoder().encode(docid);
|
|
1327
|
+
this.callWasmSync("worker_remove_grouping", encoded);
|
|
1328
|
+
return { ok: true };
|
|
1329
|
+
}
|
|
1330
|
+
handleInitDirectory(params) {
|
|
1331
|
+
const path = params["path"] ?? this.targetDir;
|
|
1332
|
+
const encoded = new TextEncoder().encode(path);
|
|
1333
|
+
this.callWasmSync("worker_init_directory", encoded);
|
|
1334
|
+
return { ok: true };
|
|
1335
|
+
}
|
|
1336
|
+
handleInvalidate(params) {
|
|
1337
|
+
const kbid = params["kbid"] ?? "";
|
|
1338
|
+
const encoded = new TextEncoder().encode(kbid);
|
|
1339
|
+
this.callWasmSync("worker_invalidate", encoded);
|
|
1340
|
+
return { ok: true };
|
|
1341
|
+
}
|
|
1342
|
+
handleListByType(params) {
|
|
1343
|
+
const typeStr = params["sectionType"] ?? "";
|
|
1344
|
+
const encoded = encodeTypeFilterParam(typeStr);
|
|
1345
|
+
const bytes = this.callWasmSync("worker_list_by_type", encoded);
|
|
1346
|
+
return decodeSectionRecordList(bytes);
|
|
1347
|
+
}
|
|
1348
|
+
handleListDocsByType(params) {
|
|
1349
|
+
const typeStr = params["docType"] ?? "";
|
|
1350
|
+
const encoded = encodeTypeFilterParam(typeStr);
|
|
1351
|
+
const bytes = this.callWasmSync(
|
|
1352
|
+
"worker_list_docs_by_type",
|
|
1353
|
+
encoded
|
|
1354
|
+
);
|
|
1355
|
+
return decodeDocumentManifestList(bytes);
|
|
1356
|
+
}
|
|
1357
|
+
// -- Zero-arg methods --
|
|
1358
|
+
handleInvalidateAll() {
|
|
1359
|
+
this.callWasmZeroArg("worker_invalidate_all");
|
|
1360
|
+
return { ok: true };
|
|
1361
|
+
}
|
|
1362
|
+
handleDbStatus() {
|
|
1363
|
+
this.callWasmZeroArg("worker_status");
|
|
1364
|
+
const bytes = this.readReturnSlot();
|
|
1365
|
+
const text = new TextDecoder().decode(bytes);
|
|
1366
|
+
return decodeKeyValueText(text);
|
|
1367
|
+
}
|
|
1368
|
+
handleIntegrityCheck() {
|
|
1369
|
+
this.callWasmZeroArg("worker_check_integrity");
|
|
1370
|
+
const bytes = this.readReturnSlot();
|
|
1371
|
+
const text = new TextDecoder().decode(bytes);
|
|
1372
|
+
return decodeKeyValueText(text);
|
|
1373
|
+
}
|
|
1374
|
+
handleGc() {
|
|
1375
|
+
this.callWasmZeroArg("worker_garbage_collect");
|
|
1376
|
+
const bytes = this.readReturnSlot();
|
|
1377
|
+
const text = new TextDecoder().decode(bytes);
|
|
1378
|
+
return decodeKeyValueText(text);
|
|
1379
|
+
}
|
|
1380
|
+
handleRebuild() {
|
|
1381
|
+
this.callWasmZeroArg("worker_rebuild_indexes");
|
|
1382
|
+
return { ok: true };
|
|
1383
|
+
}
|
|
1384
|
+
// -- WASM lifecycle --
|
|
1385
|
+
initWorkerContext() {
|
|
1386
|
+
const pathBytes = new TextEncoder().encode(".");
|
|
1387
|
+
this.callWasmSync("worker_init", pathBytes);
|
|
1388
|
+
}
|
|
1389
|
+
// -- WASM bridge primitives --
|
|
1390
|
+
getExport(name) {
|
|
1391
|
+
if (this._wasmModules === null) {
|
|
1392
|
+
throw new Error("WASM modules not loaded");
|
|
1393
|
+
}
|
|
1394
|
+
const fn = this._wasmModules.kbWorker.exports[name];
|
|
1395
|
+
if (typeof fn !== "function") {
|
|
1396
|
+
throw new Error(`WASM export not found: ${name}`);
|
|
1397
|
+
}
|
|
1398
|
+
return fn;
|
|
1399
|
+
}
|
|
1400
|
+
wasmAlloc(size) {
|
|
1401
|
+
if (size === 0) return 0;
|
|
1402
|
+
const allocFn = this._wasmModules?.kbWorker.exports["kbdb_alloc"];
|
|
1403
|
+
if (typeof allocFn !== "function") return 0;
|
|
1404
|
+
return allocFn(size);
|
|
1405
|
+
}
|
|
1406
|
+
wasmFree(ptr, size) {
|
|
1407
|
+
if (ptr === 0 || size === 0) return;
|
|
1408
|
+
const freeFn = this._wasmModules?.kbWorker.exports["kbdb_free"];
|
|
1409
|
+
if (typeof freeFn === "function") {
|
|
1410
|
+
freeFn(ptr, size);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
wasmWrite(ptr, data) {
|
|
1414
|
+
if (data.length === 0) return;
|
|
1415
|
+
const memory = this._wasmModules?.memory;
|
|
1416
|
+
if (!memory) return;
|
|
1417
|
+
const memView = new Uint8Array(memory.buffer);
|
|
1418
|
+
if (ptr + data.length > memView.length) {
|
|
1419
|
+
throw new Error("WASM memory overflow");
|
|
1420
|
+
}
|
|
1421
|
+
memView.set(data, ptr);
|
|
1422
|
+
}
|
|
1423
|
+
readReturnSlot() {
|
|
1424
|
+
const getPtrFn = this._wasmModules?.kbWorker.exports["get_return_ptr"];
|
|
1425
|
+
const getLenFn = this._wasmModules?.kbWorker.exports["get_return_len"];
|
|
1426
|
+
if (typeof getPtrFn !== "function" || typeof getLenFn !== "function") {
|
|
1427
|
+
return new Uint8Array(0);
|
|
1428
|
+
}
|
|
1429
|
+
const ptr = getPtrFn();
|
|
1430
|
+
const len = getLenFn();
|
|
1431
|
+
if (ptr === 0 || len === 0) {
|
|
1432
|
+
return new Uint8Array(0);
|
|
1433
|
+
}
|
|
1434
|
+
const memory = this._wasmModules?.memory;
|
|
1435
|
+
if (!memory) return new Uint8Array(0);
|
|
1436
|
+
const data = new Uint8Array(memory.buffer, ptr, len).slice();
|
|
1437
|
+
this.wasmFree(ptr, len);
|
|
1438
|
+
return data;
|
|
1439
|
+
}
|
|
1440
|
+
callWasmSync(exportName, input) {
|
|
1441
|
+
const fn = this.getExport(exportName);
|
|
1442
|
+
const ptr = this.wasmAlloc(input.length);
|
|
1443
|
+
this.wasmWrite(ptr, input);
|
|
1444
|
+
const rc = fn(ptr, input.length);
|
|
1445
|
+
this.wasmFree(ptr, input.length);
|
|
1446
|
+
if (rc === -1) {
|
|
1447
|
+
const errBytes = this.readReturnSlot();
|
|
1448
|
+
const errMsg = new TextDecoder().decode(errBytes);
|
|
1449
|
+
throw new IpcError(-32e3, errMsg || exportName + " failed");
|
|
1450
|
+
}
|
|
1451
|
+
return this.readReturnSlot();
|
|
1452
|
+
}
|
|
1453
|
+
callWasmZeroArg(exportName) {
|
|
1454
|
+
const fn = this.getExport(exportName);
|
|
1455
|
+
const rc = fn();
|
|
1456
|
+
if (rc === -1) {
|
|
1457
|
+
const errBytes = this.readReturnSlot();
|
|
1458
|
+
const errMsg = new TextDecoder().decode(errBytes);
|
|
1459
|
+
throw new IpcError(-32e3, errMsg || exportName + " failed");
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
invokeWasmRaw(exportName, input) {
|
|
1463
|
+
return this.callWasmSync(exportName, input);
|
|
1464
|
+
}
|
|
1465
|
+
handleCheckVersion(params) {
|
|
1466
|
+
const targetPath = typeof params.targetPath === "string" ? params.targetPath : this.targetDir;
|
|
1467
|
+
const catalogPath = join4(targetPath, "catalog.toml");
|
|
1468
|
+
let text;
|
|
1469
|
+
try {
|
|
1470
|
+
text = readFileSync4(catalogPath, "utf-8");
|
|
1471
|
+
} catch {
|
|
1472
|
+
return {
|
|
1473
|
+
status: "needs_migration",
|
|
1474
|
+
currentVersion: 0,
|
|
1475
|
+
requiredVersion: DB_FORMAT_VERSION
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
const version = parseCatalogVersion(text);
|
|
1479
|
+
if (version === null) {
|
|
1480
|
+
return {
|
|
1481
|
+
status: "needs_migration",
|
|
1482
|
+
currentVersion: 0,
|
|
1483
|
+
requiredVersion: DB_FORMAT_VERSION
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
if (version > DB_FORMAT_VERSION) {
|
|
1487
|
+
return {
|
|
1488
|
+
status: "too_new",
|
|
1489
|
+
currentVersion: version,
|
|
1490
|
+
requiredVersion: DB_FORMAT_VERSION
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
if (version < DB_FORMAT_VERSION) {
|
|
1494
|
+
return {
|
|
1495
|
+
status: "needs_migration",
|
|
1496
|
+
currentVersion: version,
|
|
1497
|
+
requiredVersion: DB_FORMAT_VERSION
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
return {
|
|
1501
|
+
status: "compatible",
|
|
1502
|
+
currentVersion: version,
|
|
1503
|
+
requiredVersion: DB_FORMAT_VERSION
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
/** Returns a daemon config value by config method name. */
|
|
1507
|
+
handleConfigMethod(method) {
|
|
1508
|
+
const key = method.slice(CONFIG_PREFIX.length);
|
|
1509
|
+
const prop = CONFIG_KEY_MAP[key];
|
|
1510
|
+
if (prop === void 0) {
|
|
1511
|
+
throw new IpcError(-32601, `Method not found: ${method}`);
|
|
1512
|
+
}
|
|
1513
|
+
return this.config[prop];
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
function parseCatalogVersion(text) {
|
|
1517
|
+
for (const line of text.split("\n")) {
|
|
1518
|
+
const trimmed = line.trim();
|
|
1519
|
+
if (trimmed.startsWith("#")) continue;
|
|
1520
|
+
const match = /^version\s*=\s*(\d+)/.exec(trimmed);
|
|
1521
|
+
if (match?.[1] !== void 0) {
|
|
1522
|
+
return parseInt(match[1], 10);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// src/shared/worker-daemon/functions/start-daemon.function.ts
|
|
1529
|
+
async function startDaemon(contextPath, wasmDir2) {
|
|
1530
|
+
const config = readConfig(contextPath);
|
|
1531
|
+
const hash = await computeSha256(contextPath);
|
|
1532
|
+
const contextId = hash.slice(0, 16);
|
|
1533
|
+
const daemon = new WorkerDaemon(
|
|
1534
|
+
contextId,
|
|
1535
|
+
contextPath,
|
|
1536
|
+
config,
|
|
1537
|
+
wasmDir2
|
|
1538
|
+
);
|
|
1539
|
+
try {
|
|
1540
|
+
daemon.checkPreconditions();
|
|
1541
|
+
} catch (err) {
|
|
1542
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1543
|
+
console.error(`kbdb-worker: ${message}`);
|
|
1544
|
+
writeCrashLog(contextId, message);
|
|
1545
|
+
process.exit(1);
|
|
1546
|
+
}
|
|
1547
|
+
try {
|
|
1548
|
+
await daemon.start();
|
|
1549
|
+
} catch (err) {
|
|
1550
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1551
|
+
console.error(`kbdb-worker: ${message}`);
|
|
1552
|
+
writeCrashLog(contextId, message);
|
|
1553
|
+
process.exit(1);
|
|
1554
|
+
}
|
|
1555
|
+
process.on("SIGTERM", () => {
|
|
1556
|
+
daemon.stop();
|
|
1557
|
+
});
|
|
1558
|
+
process.on("SIGINT", () => {
|
|
1559
|
+
daemon.stop();
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
function writeCrashLog(contextId, message) {
|
|
1563
|
+
try {
|
|
1564
|
+
const crashPath = join5(tmpdir2(), `kbdb-${contextId}.crash`);
|
|
1565
|
+
const payload = JSON.stringify({
|
|
1566
|
+
error: message,
|
|
1567
|
+
timestamp: Date.now()
|
|
1568
|
+
});
|
|
1569
|
+
writeFileSync3(crashPath, payload);
|
|
1570
|
+
} catch {
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
// src/shared/worker-daemon/functions/run-worker.function.ts
|
|
1575
|
+
import { resolve } from "node:path";
|
|
1576
|
+
async function runWorker(argv, deps) {
|
|
1577
|
+
const contextPath = argv[0];
|
|
1578
|
+
if (!contextPath) {
|
|
1579
|
+
return {
|
|
1580
|
+
error: "usage: kbdb-worker <context-path>",
|
|
1581
|
+
exitCode: 1
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
const resolved = resolve(contextPath);
|
|
1585
|
+
if (!deps.existsSync(resolved)) {
|
|
1586
|
+
return {
|
|
1587
|
+
error: `error: path not found: ${resolved}`,
|
|
1588
|
+
exitCode: 1
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
await deps.startDaemon(resolved, deps.wasmDir);
|
|
1592
|
+
return { exitCode: 0 };
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// src/worker.ts
|
|
1596
|
+
var baseDir = resolveBaseDir(import.meta.url, import.meta.dirname);
|
|
1597
|
+
var wasmDir = resolveWasmDir(baseDir.scriptDir);
|
|
1598
|
+
async function main() {
|
|
1599
|
+
const result = await runWorker(getArgs(), {
|
|
1600
|
+
existsSync: existsSync3,
|
|
1601
|
+
startDaemon,
|
|
1602
|
+
wasmDir
|
|
1603
|
+
});
|
|
1604
|
+
if (result.error) {
|
|
1605
|
+
console.error(result.error);
|
|
1606
|
+
}
|
|
1607
|
+
if (result.exitCode !== 0) {
|
|
1608
|
+
process.exitCode = result.exitCode;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
main().catch((err) => {
|
|
1612
|
+
console.error(err);
|
|
1613
|
+
process.exitCode = 1;
|
|
1614
|
+
});
|
|
1615
|
+
//# sourceMappingURL=worker.mjs.map
|