@andre.li/memoark 0.3.1 → 0.3.2
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/README.en.md +388 -69
- package/README.md +674 -309
- package/README.zh-CN.md +816 -0
- package/bin/memoark.mjs +7 -2
- package/dist/adapters/store.d.ts.map +1 -1
- package/dist/adapters/store.js +6 -5
- package/dist/adapters/store.js.map +1 -1
- package/dist/cli-helpers.d.ts +12 -0
- package/dist/cli-helpers.d.ts.map +1 -0
- package/dist/cli-helpers.js +11 -0
- package/dist/cli-helpers.js.map +1 -0
- package/dist/cli.js +682 -126
- package/dist/cli.js.map +1 -1
- package/dist/collectors/feishu/chat-name-resolver.d.ts +33 -0
- package/dist/collectors/feishu/chat-name-resolver.d.ts.map +1 -0
- package/dist/collectors/feishu/chat-name-resolver.js +63 -0
- package/dist/collectors/feishu/chat-name-resolver.js.map +1 -0
- package/dist/collectors/feishu/collector.d.ts +4 -0
- package/dist/collectors/feishu/collector.d.ts.map +1 -1
- package/dist/collectors/feishu/collector.js +27 -4
- package/dist/collectors/feishu/collector.js.map +1 -1
- package/dist/collectors/feishu/docs/blocks.d.ts +25 -0
- package/dist/collectors/feishu/docs/blocks.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/blocks.js +34 -0
- package/dist/collectors/feishu/docs/blocks.js.map +1 -0
- package/dist/collectors/feishu/docs/candidate.d.ts +17 -0
- package/dist/collectors/feishu/docs/candidate.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/candidate.js +36 -0
- package/dist/collectors/feishu/docs/candidate.js.map +1 -0
- package/dist/collectors/feishu/docs/config.d.ts +41 -0
- package/dist/collectors/feishu/docs/config.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/config.js +30 -0
- package/dist/collectors/feishu/docs/config.js.map +1 -0
- package/dist/collectors/feishu/docs/decision.d.ts +14 -0
- package/dist/collectors/feishu/docs/decision.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/decision.js +43 -0
- package/dist/collectors/feishu/docs/decision.js.map +1 -0
- package/dist/collectors/feishu/docs/full-builder.d.ts +17 -0
- package/dist/collectors/feishu/docs/full-builder.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/full-builder.js +136 -0
- package/dist/collectors/feishu/docs/full-builder.js.map +1 -0
- package/dist/collectors/feishu/docs/hash.d.ts +8 -0
- package/dist/collectors/feishu/docs/hash.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/hash.js +15 -0
- package/dist/collectors/feishu/docs/hash.js.map +1 -0
- package/dist/collectors/feishu/docs/ingest.d.ts +54 -0
- package/dist/collectors/feishu/docs/ingest.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/ingest.js +120 -0
- package/dist/collectors/feishu/docs/ingest.js.map +1 -0
- package/dist/collectors/feishu/docs/llm-json.d.ts +13 -0
- package/dist/collectors/feishu/docs/llm-json.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/llm-json.js +40 -0
- package/dist/collectors/feishu/docs/llm-json.js.map +1 -0
- package/dist/collectors/feishu/docs/pointer-builder.d.ts +7 -0
- package/dist/collectors/feishu/docs/pointer-builder.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/pointer-builder.js +11 -0
- package/dist/collectors/feishu/docs/pointer-builder.js.map +1 -0
- package/dist/collectors/feishu/docs/render.d.ts +8 -0
- package/dist/collectors/feishu/docs/render.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/render.js +105 -0
- package/dist/collectors/feishu/docs/render.js.map +1 -0
- package/dist/collectors/feishu/docs/run.d.ts +37 -0
- package/dist/collectors/feishu/docs/run.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/run.js +143 -0
- package/dist/collectors/feishu/docs/run.js.map +1 -0
- package/dist/collectors/feishu/docs/status.d.ts +16 -0
- package/dist/collectors/feishu/docs/status.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/status.js +24 -0
- package/dist/collectors/feishu/docs/status.js.map +1 -0
- package/dist/collectors/feishu/docs/store-writer.d.ts +32 -0
- package/dist/collectors/feishu/docs/store-writer.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/store-writer.js +71 -0
- package/dist/collectors/feishu/docs/store-writer.js.map +1 -0
- package/dist/collectors/feishu/docs/toc.d.ts +3 -0
- package/dist/collectors/feishu/docs/toc.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/toc.js +19 -0
- package/dist/collectors/feishu/docs/toc.js.map +1 -0
- package/dist/collectors/feishu/docs/triggers.d.ts +7 -0
- package/dist/collectors/feishu/docs/triggers.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/triggers.js +31 -0
- package/dist/collectors/feishu/docs/triggers.js.map +1 -0
- package/dist/collectors/feishu/docs/types.d.ts +109 -0
- package/dist/collectors/feishu/docs/types.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/types.js +2 -0
- package/dist/collectors/feishu/docs/types.js.map +1 -0
- package/dist/collectors/feishu/docs/upgrade-queue.d.ts +19 -0
- package/dist/collectors/feishu/docs/upgrade-queue.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/upgrade-queue.js +36 -0
- package/dist/collectors/feishu/docs/upgrade-queue.js.map +1 -0
- package/dist/collectors/feishu/docs/url-parser.d.ts +3 -0
- package/dist/collectors/feishu/docs/url-parser.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/url-parser.js +39 -0
- package/dist/collectors/feishu/docs/url-parser.js.map +1 -0
- package/dist/collectors/feishu/docs/walkers.d.ts +24 -0
- package/dist/collectors/feishu/docs/walkers.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/walkers.js +90 -0
- package/dist/collectors/feishu/docs/walkers.js.map +1 -0
- package/dist/collectors/feishu/docs/wiki-resolver.d.ts +15 -0
- package/dist/collectors/feishu/docs/wiki-resolver.d.ts.map +1 -0
- package/dist/collectors/feishu/docs/wiki-resolver.js +24 -0
- package/dist/collectors/feishu/docs/wiki-resolver.js.map +1 -0
- package/dist/collectors/feishu/lark-cli-client.d.ts +12 -0
- package/dist/collectors/feishu/lark-cli-client.d.ts.map +1 -1
- package/dist/collectors/feishu/lark-cli-client.js +37 -2
- package/dist/collectors/feishu/lark-cli-client.js.map +1 -1
- package/dist/collectors/feishu/lark-cli-identity-backend.d.ts +28 -0
- package/dist/collectors/feishu/lark-cli-identity-backend.d.ts.map +1 -0
- package/dist/collectors/feishu/lark-cli-identity-backend.js +110 -0
- package/dist/collectors/feishu/lark-cli-identity-backend.js.map +1 -0
- package/dist/collectors/feishu/self-open-id.d.ts +20 -0
- package/dist/collectors/feishu/self-open-id.d.ts.map +1 -0
- package/dist/collectors/feishu/self-open-id.js +31 -0
- package/dist/collectors/feishu/self-open-id.js.map +1 -0
- package/dist/collectors/feishu/sources/dm.d.ts.map +1 -1
- package/dist/collectors/feishu/sources/dm.js +4 -0
- package/dist/collectors/feishu/sources/dm.js.map +1 -1
- package/dist/collectors/feishu/sources/mail.d.ts.map +1 -1
- package/dist/collectors/feishu/sources/mail.js +18 -20
- package/dist/collectors/feishu/sources/mail.js.map +1 -1
- package/dist/collectors/feishu/sources/messages.d.ts +2 -0
- package/dist/collectors/feishu/sources/messages.d.ts.map +1 -1
- package/dist/collectors/feishu/sources/messages.js +28 -1
- package/dist/collectors/feishu/sources/messages.js.map +1 -1
- package/dist/collectors/feishu/types.d.ts +37 -3
- package/dist/collectors/feishu/types.d.ts.map +1 -1
- package/dist/collectors/feishu/types.js.map +1 -1
- package/dist/config-center/connection-checks.d.ts.map +1 -1
- package/dist/config-center/connection-checks.js +1 -1
- package/dist/config-center/connection-checks.js.map +1 -1
- package/dist/config-center/schema.d.ts.map +1 -1
- package/dist/config-center/schema.js +77 -0
- package/dist/config-center/schema.js.map +1 -1
- package/dist/consolidator/consolidator.d.ts +13 -1
- package/dist/consolidator/consolidator.d.ts.map +1 -1
- package/dist/consolidator/consolidator.js +12 -2
- package/dist/consolidator/consolidator.js.map +1 -1
- package/dist/core/canonicalize.js +5 -1
- package/dist/core/canonicalize.js.map +1 -1
- package/dist/core/config.d.ts +52 -9
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +86 -24
- package/dist/core/config.js.map +1 -1
- package/dist/core/env-validation.d.ts +9 -0
- package/dist/core/env-validation.d.ts.map +1 -0
- package/dist/core/env-validation.js +94 -0
- package/dist/core/env-validation.js.map +1 -0
- package/dist/core/identity-resolver.d.ts +24 -3
- package/dist/core/identity-resolver.d.ts.map +1 -1
- package/dist/core/identity-resolver.js +147 -2
- package/dist/core/identity-resolver.js.map +1 -1
- package/dist/core/person-identity.d.ts +124 -0
- package/dist/core/person-identity.d.ts.map +1 -0
- package/dist/core/person-identity.js +342 -0
- package/dist/core/person-identity.js.map +1 -0
- package/dist/core/person-slug.d.ts +21 -0
- package/dist/core/person-slug.d.ts.map +1 -0
- package/dist/core/person-slug.js +93 -0
- package/dist/core/person-slug.js.map +1 -0
- package/dist/core/pipeline-factory.d.ts +1 -1
- package/dist/core/pipeline-factory.d.ts.map +1 -1
- package/dist/core/pipeline-factory.js +8 -3
- package/dist/core/pipeline-factory.js.map +1 -1
- package/dist/core/pipeline.d.ts +16 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +49 -1
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -0
- package/dist/core/resource-loader.js +12 -0
- package/dist/core/resource-loader.js.map +1 -0
- package/dist/core/schemas.d.ts +2981 -309
- package/dist/core/schemas.d.ts.map +1 -1
- package/dist/core/schemas.js +27 -0
- package/dist/core/schemas.js.map +1 -1
- package/dist/core/signal-scoring.d.ts.map +1 -1
- package/dist/core/signal-scoring.js +5 -1
- package/dist/core/signal-scoring.js.map +1 -1
- package/dist/core/source-ref.d.ts +4 -0
- package/dist/core/source-ref.d.ts.map +1 -0
- package/dist/core/source-ref.js +24 -0
- package/dist/core/source-ref.js.map +1 -0
- package/dist/core/state.d.ts +1 -1
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +3 -2
- package/dist/core/state.js.map +1 -1
- package/dist/core/types.d.ts +34 -6
- package/dist/core/types.d.ts.map +1 -1
- package/dist/daemon/reload-manager.d.ts +27 -0
- package/dist/daemon/reload-manager.d.ts.map +1 -0
- package/dist/daemon/reload-manager.js +67 -0
- package/dist/daemon/reload-manager.js.map +1 -0
- package/dist/daemon/scheduler.d.ts +9 -1
- package/dist/daemon/scheduler.d.ts.map +1 -1
- package/dist/daemon/scheduler.js +113 -38
- package/dist/daemon/scheduler.js.map +1 -1
- package/dist/daemon/serve-runtime.d.ts +31 -0
- package/dist/daemon/serve-runtime.d.ts.map +1 -0
- package/dist/daemon/serve-runtime.js +230 -0
- package/dist/daemon/serve-runtime.js.map +1 -0
- package/dist/embedded-assets.generated.d.ts.map +1 -1
- package/dist/embedded-assets.generated.js +3 -3
- package/dist/embedded-assets.generated.js.map +1 -1
- package/dist/extractors/playbook-extractor.d.ts +35 -0
- package/dist/extractors/playbook-extractor.d.ts.map +1 -0
- package/dist/extractors/playbook-extractor.js +98 -0
- package/dist/extractors/playbook-extractor.js.map +1 -0
- package/dist/extractors/prompts/examples/agent-session.md +257 -0
- package/dist/extractors/prompts/signal-extract.md +199 -0
- package/dist/extractors/prompts/system.md +45 -0
- package/dist/extractors/signal-extractor.d.ts +2 -1
- package/dist/extractors/signal-extractor.d.ts.map +1 -1
- package/dist/extractors/signal-extractor.js +99 -7
- package/dist/extractors/signal-extractor.js.map +1 -1
- package/dist/hooks/handlers.d.ts +21 -0
- package/dist/hooks/handlers.d.ts.map +1 -0
- package/dist/hooks/handlers.js +22 -0
- package/dist/hooks/handlers.js.map +1 -0
- package/dist/hooks/inject.d.ts +7 -0
- package/dist/hooks/inject.d.ts.map +1 -0
- package/dist/hooks/inject.js +18 -0
- package/dist/hooks/inject.js.map +1 -0
- package/dist/hooks/install.d.ts +14 -0
- package/dist/hooks/install.d.ts.map +1 -0
- package/dist/hooks/install.js +34 -0
- package/dist/hooks/install.js.map +1 -0
- package/dist/hooks/output.d.ts +19 -0
- package/dist/hooks/output.d.ts.map +1 -0
- package/dist/hooks/output.js +13 -0
- package/dist/hooks/output.js.map +1 -0
- package/dist/hooks/recall-client.d.ts +25 -0
- package/dist/hooks/recall-client.d.ts.map +1 -0
- package/dist/hooks/recall-client.js +56 -0
- package/dist/hooks/recall-client.js.map +1 -0
- package/dist/hooks/run-event.d.ts +13 -0
- package/dist/hooks/run-event.d.ts.map +1 -0
- package/dist/hooks/run-event.js +20 -0
- package/dist/hooks/run-event.js.map +1 -0
- package/dist/hooks/settings-edit.d.ts +10 -0
- package/dist/hooks/settings-edit.d.ts.map +1 -0
- package/dist/hooks/settings-edit.js +44 -0
- package/dist/hooks/settings-edit.js.map +1 -0
- package/dist/hooks/writeback.d.ts +12 -0
- package/dist/hooks/writeback.d.ts.map +1 -0
- package/dist/hooks/writeback.js +48 -0
- package/dist/hooks/writeback.js.map +1 -0
- package/dist/install/clients/claude-code.d.ts +3 -0
- package/dist/install/clients/claude-code.d.ts.map +1 -0
- package/dist/install/clients/claude-code.js +30 -0
- package/dist/install/clients/claude-code.js.map +1 -0
- package/dist/install/clients/claude-desktop.d.ts +3 -0
- package/dist/install/clients/claude-desktop.d.ts.map +1 -0
- package/dist/install/clients/claude-desktop.js +31 -0
- package/dist/install/clients/claude-desktop.js.map +1 -0
- package/dist/install/clients/codex.d.ts +3 -0
- package/dist/install/clients/codex.d.ts.map +1 -0
- package/dist/install/clients/codex.js +32 -0
- package/dist/install/clients/codex.js.map +1 -0
- package/dist/install/clients/cursor.d.ts +3 -0
- package/dist/install/clients/cursor.d.ts.map +1 -0
- package/dist/install/clients/cursor.js +35 -0
- package/dist/install/clients/cursor.js.map +1 -0
- package/dist/install/clients/hermes.d.ts +3 -0
- package/dist/install/clients/hermes.d.ts.map +1 -0
- package/dist/install/clients/hermes.js +35 -0
- package/dist/install/clients/hermes.js.map +1 -0
- package/dist/install/clients/index.d.ts +4 -0
- package/dist/install/clients/index.d.ts.map +1 -0
- package/dist/install/clients/index.js +18 -0
- package/dist/install/clients/index.js.map +1 -0
- package/dist/install/clients/windsurf.d.ts +3 -0
- package/dist/install/clients/windsurf.d.ts.map +1 -0
- package/dist/install/clients/windsurf.js +32 -0
- package/dist/install/clients/windsurf.js.map +1 -0
- package/dist/install/command.d.ts +14 -0
- package/dist/install/command.d.ts.map +1 -0
- package/dist/install/command.js +34 -0
- package/dist/install/command.js.map +1 -0
- package/dist/install/directive.d.ts +7 -0
- package/dist/install/directive.d.ts.map +1 -0
- package/dist/install/directive.js +31 -0
- package/dist/install/directive.js.map +1 -0
- package/dist/install/index.d.ts +26 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +117 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/json-config.d.ts +11 -0
- package/dist/install/json-config.d.ts.map +1 -0
- package/dist/install/json-config.js +39 -0
- package/dist/install/json-config.js.map +1 -0
- package/dist/install/marked-block.d.ts +11 -0
- package/dist/install/marked-block.d.ts.map +1 -0
- package/dist/install/marked-block.js +34 -0
- package/dist/install/marked-block.js.map +1 -0
- package/dist/install/skill.d.ts +4 -0
- package/dist/install/skill.d.ts.map +1 -0
- package/dist/install/skill.js +61 -0
- package/dist/install/skill.js.map +1 -0
- package/dist/install/toml-config.d.ts +4 -0
- package/dist/install/toml-config.d.ts.map +1 -0
- package/dist/install/toml-config.js +51 -0
- package/dist/install/toml-config.js.map +1 -0
- package/dist/install/types.d.ts +37 -0
- package/dist/install/types.d.ts.map +1 -0
- package/dist/install/types.js +4 -0
- package/dist/install/types.js.map +1 -0
- package/dist/install/yaml-config.d.ts +4 -0
- package/dist/install/yaml-config.d.ts.map +1 -0
- package/dist/install/yaml-config.js +18 -0
- package/dist/install/yaml-config.js.map +1 -0
- package/dist/processors/privacy.d.ts +4 -1
- package/dist/processors/privacy.d.ts.map +1 -1
- package/dist/processors/privacy.js +5 -3
- package/dist/processors/privacy.js.map +1 -1
- package/dist/profile/accumulate.d.ts +28 -0
- package/dist/profile/accumulate.d.ts.map +1 -0
- package/dist/profile/accumulate.js +48 -0
- package/dist/profile/accumulate.js.map +1 -0
- package/dist/profile/behavior.d.ts +32 -0
- package/dist/profile/behavior.d.ts.map +1 -0
- package/dist/profile/behavior.js +122 -0
- package/dist/profile/behavior.js.map +1 -0
- package/dist/profile/four-color.d.ts +12 -0
- package/dist/profile/four-color.d.ts.map +1 -0
- package/dist/profile/four-color.js +39 -0
- package/dist/profile/four-color.js.map +1 -0
- package/dist/profile/profile-synth.d.ts +27 -0
- package/dist/profile/profile-synth.d.ts.map +1 -0
- package/dist/profile/profile-synth.js +174 -0
- package/dist/profile/profile-synth.js.map +1 -0
- package/dist/profile/types.d.ts +84 -0
- package/dist/profile/types.d.ts.map +1 -0
- package/dist/profile/types.js +11 -0
- package/dist/profile/types.js.map +1 -0
- package/dist/server/api.d.ts +8 -2
- package/dist/server/api.d.ts.map +1 -1
- package/dist/server/api.js +69 -34
- package/dist/server/api.js.map +1 -1
- package/dist/server/backfill-routes.d.ts.map +1 -1
- package/dist/server/backfill-routes.js +14 -1
- package/dist/server/backfill-routes.js.map +1 -1
- package/dist/server/chat-name-refresh-job.d.ts +33 -0
- package/dist/server/chat-name-refresh-job.d.ts.map +1 -0
- package/dist/server/chat-name-refresh-job.js +120 -0
- package/dist/server/chat-name-refresh-job.js.map +1 -0
- package/dist/server/chat-name-routes.d.ts +13 -0
- package/dist/server/chat-name-routes.d.ts.map +1 -0
- package/dist/server/chat-name-routes.js +81 -0
- package/dist/server/chat-name-routes.js.map +1 -0
- package/dist/server/config-routes.d.ts +2 -0
- package/dist/server/config-routes.d.ts.map +1 -1
- package/dist/server/config-routes.js +2 -1
- package/dist/server/config-routes.js.map +1 -1
- package/dist/server/mcp-http.d.ts +26 -0
- package/dist/server/mcp-http.d.ts.map +1 -0
- package/dist/server/mcp-http.js +102 -0
- package/dist/server/mcp-http.js.map +1 -0
- package/dist/server/mcp.d.ts +191 -25
- package/dist/server/mcp.d.ts.map +1 -1
- package/dist/server/mcp.js +1111 -68
- package/dist/server/mcp.js.map +1 -1
- package/dist/server/open-browser.d.ts +3 -0
- package/dist/server/open-browser.d.ts.map +1 -0
- package/dist/server/open-browser.js +12 -0
- package/dist/server/open-browser.js.map +1 -0
- package/dist/server/runtime.d.ts +13 -0
- package/dist/server/runtime.d.ts.map +1 -0
- package/dist/server/runtime.js +27 -0
- package/dist/server/runtime.js.map +1 -0
- package/dist/server/setup-server.d.ts.map +1 -1
- package/dist/server/setup-server.js +8 -11
- package/dist/server/setup-server.js.map +1 -1
- package/dist/setup/connection-tests.d.ts +1 -1
- package/dist/setup/connection-tests.d.ts.map +1 -1
- package/dist/setup/connection-tests.js +4 -2
- package/dist/setup/connection-tests.js.map +1 -1
- package/dist/setup/generate-config.d.ts.map +1 -1
- package/dist/setup/generate-config.js +31 -1
- package/dist/setup/generate-config.js.map +1 -1
- package/dist/setup/init-wizard.d.ts +1 -0
- package/dist/setup/init-wizard.d.ts.map +1 -1
- package/dist/setup/init-wizard.js +38 -21
- package/dist/setup/init-wizard.js.map +1 -1
- package/dist/setup/validate-config.d.ts +5 -1
- package/dist/setup/validate-config.d.ts.map +1 -1
- package/dist/setup/validate-config.js +18 -0
- package/dist/setup/validate-config.js.map +1 -1
- package/dist/store/data-dir-lock.d.ts +15 -0
- package/dist/store/data-dir-lock.d.ts.map +1 -0
- package/dist/store/data-dir-lock.js +96 -0
- package/dist/store/data-dir-lock.js.map +1 -0
- package/dist/store/database.d.ts +2 -0
- package/dist/store/database.d.ts.map +1 -1
- package/dist/store/database.js +23 -10
- package/dist/store/database.js.map +1 -1
- package/dist/store/graph.d.ts +22 -0
- package/dist/store/graph.d.ts.map +1 -1
- package/dist/store/graph.js +97 -7
- package/dist/store/graph.js.map +1 -1
- package/dist/store/migrations/index.d.ts.map +1 -1
- package/dist/store/migrations/index.js +52 -0
- package/dist/store/migrations/index.js.map +1 -1
- package/dist/store/pages.d.ts +7 -0
- package/dist/store/pages.d.ts.map +1 -1
- package/dist/store/pages.js +56 -1
- package/dist/store/pages.js.map +1 -1
- package/dist/store/person-behavior.d.ts +28 -0
- package/dist/store/person-behavior.d.ts.map +1 -0
- package/dist/store/person-behavior.js +127 -0
- package/dist/store/person-behavior.js.map +1 -0
- package/dist/store/pglite-assets.d.ts +15 -0
- package/dist/store/pglite-assets.d.ts.map +1 -0
- package/dist/store/pglite-assets.js +47 -0
- package/dist/store/pglite-assets.js.map +1 -0
- package/dist/store/query-rewrite.d.ts +28 -0
- package/dist/store/query-rewrite.d.ts.map +1 -0
- package/dist/store/query-rewrite.js +97 -0
- package/dist/store/query-rewrite.js.map +1 -0
- package/dist/store/schema.sql +107 -0
- package/dist/store/search.d.ts +36 -8
- package/dist/store/search.d.ts.map +1 -1
- package/dist/store/search.js +188 -76
- package/dist/store/search.js.map +1 -1
- package/dist/store/tags.d.ts.map +1 -1
- package/dist/store/tags.js +6 -2
- package/dist/store/tags.js.map +1 -1
- package/dist/store/timeline.d.ts +13 -1
- package/dist/store/timeline.d.ts.map +1 -1
- package/dist/store/timeline.js +134 -4
- package/dist/store/timeline.js.map +1 -1
- package/dist/store/trgm-search.d.ts +13 -0
- package/dist/store/trgm-search.d.ts.map +1 -0
- package/dist/store/trgm-search.js +53 -0
- package/dist/store/trgm-search.js.map +1 -0
- package/dist/store/wikilink.d.ts +17 -0
- package/dist/store/wikilink.d.ts.map +1 -0
- package/dist/store/wikilink.js +58 -0
- package/dist/store/wikilink.js.map +1 -0
- package/dist/sync/obsidian.d.ts.map +1 -1
- package/dist/sync/obsidian.js +5 -1
- package/dist/sync/obsidian.js.map +1 -1
- package/dist/synth/cache.d.ts +17 -0
- package/dist/synth/cache.d.ts.map +1 -0
- package/dist/synth/cache.js +67 -0
- package/dist/synth/cache.js.map +1 -0
- package/dist/synth/citations.d.ts +12 -0
- package/dist/synth/citations.d.ts.map +1 -0
- package/dist/synth/citations.js +28 -0
- package/dist/synth/citations.js.map +1 -0
- package/dist/synth/context.d.ts +10 -0
- package/dist/synth/context.d.ts.map +1 -0
- package/dist/synth/context.js +67 -0
- package/dist/synth/context.js.map +1 -0
- package/dist/synth/engine.d.ts +16 -0
- package/dist/synth/engine.d.ts.map +1 -0
- package/dist/synth/engine.js +111 -0
- package/dist/synth/engine.js.map +1 -0
- package/dist/synth/gaps.d.ts +17 -0
- package/dist/synth/gaps.d.ts.map +1 -0
- package/dist/synth/gaps.js +57 -0
- package/dist/synth/gaps.js.map +1 -0
- package/dist/synth/index.d.ts +6 -0
- package/dist/synth/index.d.ts.map +1 -0
- package/dist/synth/index.js +6 -0
- package/dist/synth/index.js.map +1 -0
- package/dist/synth/intent.d.ts +6 -0
- package/dist/synth/intent.d.ts.map +1 -0
- package/dist/synth/intent.js +13 -0
- package/dist/synth/intent.js.map +1 -0
- package/dist/synth/intents/daily-report.d.ts +7 -0
- package/dist/synth/intents/daily-report.d.ts.map +1 -0
- package/dist/synth/intents/daily-report.js +37 -0
- package/dist/synth/intents/daily-report.js.map +1 -0
- package/dist/synth/intents/index.d.ts +2 -0
- package/dist/synth/intents/index.d.ts.map +1 -0
- package/dist/synth/intents/index.js +12 -0
- package/dist/synth/intents/index.js.map +1 -0
- package/dist/synth/intents/person-strategy.d.ts +40 -0
- package/dist/synth/intents/person-strategy.d.ts.map +1 -0
- package/dist/synth/intents/person-strategy.js +66 -0
- package/dist/synth/intents/person-strategy.js.map +1 -0
- package/dist/synth/intents/recall.d.ts +8 -0
- package/dist/synth/intents/recall.d.ts.map +1 -0
- package/dist/synth/intents/recall.js +26 -0
- package/dist/synth/intents/recall.js.map +1 -0
- package/dist/synth/intents/troubleshoot.d.ts +11 -0
- package/dist/synth/intents/troubleshoot.d.ts.map +1 -0
- package/dist/synth/intents/troubleshoot.js +66 -0
- package/dist/synth/intents/troubleshoot.js.map +1 -0
- package/dist/synth/scope.d.ts +13 -0
- package/dist/synth/scope.d.ts.map +1 -0
- package/dist/synth/scope.js +139 -0
- package/dist/synth/scope.js.map +1 -0
- package/dist/synth/types.d.ts +117 -0
- package/dist/synth/types.d.ts.map +1 -0
- package/dist/synth/types.js +2 -0
- package/dist/synth/types.js.map +1 -0
- package/package.json +18 -6
package/dist/cli.js
CHANGED
|
@@ -1,28 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { resolve } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
7
|
import { Command } from "commander";
|
|
8
|
+
import { planStartup, shouldOpenBrowserOnServe } from "./cli-helpers.js";
|
|
9
|
+
import { normalizeDocsConfig } from "./collectors/feishu/docs/config.js";
|
|
10
|
+
import { FullCardBuilder } from "./collectors/feishu/docs/full-builder.js";
|
|
11
|
+
import { runDocSource } from "./collectors/feishu/docs/run.js";
|
|
12
|
+
import { failedCards, summarizeCards } from "./collectors/feishu/docs/status.js";
|
|
13
|
+
import { loadExistingCard, writeCard } from "./collectors/feishu/docs/store-writer.js";
|
|
14
|
+
import { LarkCliHttpClient } from "./collectors/feishu/lark-cli-client.js";
|
|
15
|
+
import { resolveSelfOpenId } from "./collectors/feishu/self-open-id.js";
|
|
7
16
|
import { createClaudeCodeCollector, createCodexCollector, createFeishuCollector, createHermesCollector, getAllCollectors, getCollector, registerCollector, resetRegistry, } from "./collectors/index.js";
|
|
8
17
|
import { Consolidator } from "./consolidator/consolidator.js";
|
|
9
|
-
import { loadConfig } from "./core/config.js";
|
|
18
|
+
import { loadConfig, resolveConfigPath, } from "./core/config.js";
|
|
19
|
+
import { CursorStore } from "./core/cursors.js";
|
|
20
|
+
import { getMissingEnvVarsForCommand, validateEnvForCommand } from "./core/env-validation.js";
|
|
21
|
+
import { PersonIdentityStore } from "./core/person-identity.js";
|
|
10
22
|
import { runPipeline } from "./core/pipeline.js";
|
|
23
|
+
import { buildPipelineConfig } from "./core/pipeline-factory.js";
|
|
11
24
|
import { ensureStateDir, statePath } from "./core/state.js";
|
|
12
|
-
import {
|
|
25
|
+
import { ReloadManager } from "./daemon/reload-manager.js";
|
|
26
|
+
import { buildServeRuntime, ServeRuntimeHolder } from "./daemon/serve-runtime.js";
|
|
13
27
|
import { VERSION } from "./embedded-assets.generated.js";
|
|
14
28
|
import { createLLMProvider, createMockProvider } from "./extractors/providers/index.js";
|
|
29
|
+
import { hooksInstall, hooksUninstall } from "./hooks/install.js";
|
|
30
|
+
import { runHookEvent } from "./hooks/run-event.js";
|
|
31
|
+
import { runInstall, runUninstall } from "./install/index.js";
|
|
32
|
+
import { scaffoldSkill } from "./install/skill.js";
|
|
15
33
|
import { createApiApp } from "./server/api.js";
|
|
34
|
+
import { getSessionContext } from "./server/context.js";
|
|
16
35
|
import { createMcpServer } from "./server/mcp.js";
|
|
36
|
+
import { createMcpHttpApp } from "./server/mcp-http.js";
|
|
37
|
+
import { openBrowser } from "./server/open-browser.js";
|
|
38
|
+
import { startServer } from "./server/runtime.js";
|
|
17
39
|
import { ChunkStore } from "./store/chunks.js";
|
|
18
40
|
import { Database } from "./store/database.js";
|
|
19
41
|
import { EmbeddingService } from "./store/embedding.js";
|
|
20
42
|
import { GraphStore } from "./store/graph.js";
|
|
21
43
|
import { PageStore } from "./store/pages.js";
|
|
44
|
+
import { PersonBehaviorStore } from "./store/person-behavior.js";
|
|
22
45
|
import { SearchEngine } from "./store/search.js";
|
|
23
46
|
import { TagStore } from "./store/tags.js";
|
|
24
47
|
import { TimelineStore } from "./store/timeline.js";
|
|
25
|
-
function
|
|
48
|
+
function resolveProjectPath(path, projectRoot) {
|
|
49
|
+
if (!path)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (path.startsWith("~/"))
|
|
52
|
+
return resolve(homedir(), path.slice(2));
|
|
53
|
+
if (path === "~")
|
|
54
|
+
return homedir();
|
|
55
|
+
if (isAbsolute(path))
|
|
56
|
+
return path;
|
|
57
|
+
return resolve(projectRoot, path);
|
|
58
|
+
}
|
|
59
|
+
function bootstrapCollectors(sources, projectRoot) {
|
|
26
60
|
resetRegistry();
|
|
27
61
|
const agentConfigs = {
|
|
28
62
|
"claude-code": { factory: createClaudeCodeCollector, config: sources["claude-code"] },
|
|
@@ -31,22 +65,33 @@ function bootstrapCollectors(sources) {
|
|
|
31
65
|
};
|
|
32
66
|
for (const [_id, { factory, config }] of Object.entries(agentConfigs)) {
|
|
33
67
|
if (config?.enabled !== false) {
|
|
34
|
-
registerCollector(factory(config?.base_dir));
|
|
68
|
+
registerCollector(factory(resolveProjectPath(config?.base_dir, projectRoot)));
|
|
35
69
|
}
|
|
36
70
|
}
|
|
37
71
|
if (sources.feishu?.enabled !== false && sources.feishu?.app_id) {
|
|
38
72
|
registerCollector(createFeishuCollector(sources.feishu));
|
|
39
73
|
}
|
|
40
74
|
}
|
|
41
|
-
function expandDataDir(dir) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
75
|
+
function expandDataDir(dir, projectRoot) {
|
|
76
|
+
return resolveProjectPath(dir, projectRoot) ?? dir;
|
|
77
|
+
}
|
|
78
|
+
// Try to extract feishu.lark_bin from an existing config so the setup UI's
|
|
79
|
+
// "Feishu — Test Connection" button doesn't fall through to the hardcoded
|
|
80
|
+
// ~/.local/bin/lark path. Silent on missing file or parse errors (the wizard
|
|
81
|
+
// may be running because the YAML doesn't exist yet).
|
|
82
|
+
function readLarkBinFromConfig(configPath) {
|
|
83
|
+
const path = configPath ?? resolve(process.cwd(), "memoark.yaml");
|
|
84
|
+
if (!existsSync(path))
|
|
85
|
+
return undefined;
|
|
86
|
+
try {
|
|
87
|
+
return loadConfig(path).sources?.feishu?.lark_bin;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
47
92
|
}
|
|
48
93
|
async function createStores(config) {
|
|
49
|
-
const dataDir = expandDataDir(config.store.data_dir);
|
|
94
|
+
const dataDir = expandDataDir(config.store.data_dir, config.__context.projectRoot);
|
|
50
95
|
mkdirSync(dataDir, { recursive: true });
|
|
51
96
|
const db = await Database.create(dataDir, {
|
|
52
97
|
embeddingDimensions: config.embedding.dimensions,
|
|
@@ -60,7 +105,13 @@ async function createStores(config) {
|
|
|
60
105
|
apiKey: config.embedding.api_key ?? process.env.OPENAI_API_KEY,
|
|
61
106
|
baseUrl: config.embedding.base_url,
|
|
62
107
|
});
|
|
63
|
-
const search = new SearchEngine(db.pg, {
|
|
108
|
+
const search = new SearchEngine(db.pg, {
|
|
109
|
+
embedText: (q) => embedding.embedText(q),
|
|
110
|
+
search: {
|
|
111
|
+
pool_by_page: config.search.pool_by_page,
|
|
112
|
+
llm_rewrite: config.search.llm_rewrite,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
64
115
|
return {
|
|
65
116
|
db,
|
|
66
117
|
pages,
|
|
@@ -72,6 +123,20 @@ async function createStores(config) {
|
|
|
72
123
|
embedding,
|
|
73
124
|
};
|
|
74
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Lightweight store for identity operations: opens only the Database + a
|
|
128
|
+
* PersonIdentityStore. Deliberately avoids EmbeddingService so that person
|
|
129
|
+
* alias/merge/rename never requires an LLM or embedding API key.
|
|
130
|
+
*/
|
|
131
|
+
async function openIdentityStore(config) {
|
|
132
|
+
const dataDir = expandDataDir(config.store.data_dir, config.__context.projectRoot);
|
|
133
|
+
mkdirSync(dataDir, { recursive: true });
|
|
134
|
+
const db = await Database.create(dataDir, {
|
|
135
|
+
embeddingDimensions: config.embedding.dimensions,
|
|
136
|
+
});
|
|
137
|
+
const identity = new PersonIdentityStore(db.pg, { pages: new PageStore(db.pg) }, { behavior: new PersonBehaviorStore(db.pg) });
|
|
138
|
+
return { db, identity };
|
|
139
|
+
}
|
|
75
140
|
const program = new Command();
|
|
76
141
|
program
|
|
77
142
|
.name("memoark")
|
|
@@ -88,7 +153,10 @@ program
|
|
|
88
153
|
.action(async (options) => {
|
|
89
154
|
if (options.web) {
|
|
90
155
|
const { startSetupServer } = await import("./server/setup-server.js");
|
|
91
|
-
await startSetupServer({
|
|
156
|
+
await startSetupServer({
|
|
157
|
+
configPath: options.config,
|
|
158
|
+
larkBin: readLarkBinFromConfig(options.config),
|
|
159
|
+
});
|
|
92
160
|
return;
|
|
93
161
|
}
|
|
94
162
|
try {
|
|
@@ -123,10 +191,11 @@ program
|
|
|
123
191
|
try {
|
|
124
192
|
// Load configuration
|
|
125
193
|
const config = loadConfig(options.config);
|
|
194
|
+
const { projectRoot } = config.__context;
|
|
126
195
|
// Ensure state directory exists
|
|
127
|
-
ensureStateDir();
|
|
196
|
+
ensureStateDir(projectRoot);
|
|
128
197
|
// Bootstrap collectors from config
|
|
129
|
-
bootstrapCollectors(config.sources);
|
|
198
|
+
bootstrapCollectors(config.sources, projectRoot);
|
|
130
199
|
// Determine which sources to process
|
|
131
200
|
let sourceIds;
|
|
132
201
|
if (options.source === "all") {
|
|
@@ -138,6 +207,7 @@ program
|
|
|
138
207
|
// Create LLM provider based on config (shared across all sources)
|
|
139
208
|
let provider;
|
|
140
209
|
if (!options.dryRun) {
|
|
210
|
+
validateEnvForCommand(config, "extract");
|
|
141
211
|
const llmConfig = config.llm;
|
|
142
212
|
const envKey = llmConfig.provider === "anthropic"
|
|
143
213
|
? process.env.ANTHROPIC_API_KEY
|
|
@@ -156,16 +226,7 @@ program
|
|
|
156
226
|
provider = createMockProvider(new Map());
|
|
157
227
|
}
|
|
158
228
|
// Build pipeline configuration
|
|
159
|
-
const pipelineConfig =
|
|
160
|
-
dedup_checkpoint: statePath("dedup.jsonl"),
|
|
161
|
-
cursor_checkpoint: statePath("cursors.yaml"),
|
|
162
|
-
block_gap_minutes: config.block_builder.block_gap_minutes,
|
|
163
|
-
max_block_tokens: config.block_builder.max_block_tokens,
|
|
164
|
-
max_block_messages: config.block_builder.max_block_messages,
|
|
165
|
-
privacy: config.privacy,
|
|
166
|
-
output_dir: options.output || process.cwd(),
|
|
167
|
-
block_concurrency: config.pipeline?.block_concurrency,
|
|
168
|
-
};
|
|
229
|
+
const pipelineConfig = buildPipelineConfig(config, options.output || process.cwd(), projectRoot);
|
|
169
230
|
// Parse options
|
|
170
231
|
const format = ["json", "markdown"].includes(options.format) ? options.format : "json";
|
|
171
232
|
const adapter = ["store", "file", "gbrain", "stdout"].includes(options.adapter)
|
|
@@ -276,7 +337,7 @@ program
|
|
|
276
337
|
const warnings = [];
|
|
277
338
|
const ok = [];
|
|
278
339
|
// Check config file
|
|
279
|
-
const configPath = options.config
|
|
340
|
+
const configPath = resolveConfigPath(options.config);
|
|
280
341
|
let config = null;
|
|
281
342
|
if (existsSync(configPath)) {
|
|
282
343
|
ok.push(`Configuration file found: ${configPath}`);
|
|
@@ -293,7 +354,8 @@ program
|
|
|
293
354
|
warnings.push("Create one with: memoark init");
|
|
294
355
|
}
|
|
295
356
|
// Check state directory
|
|
296
|
-
const
|
|
357
|
+
const projectRoot = config?.__context.projectRoot ?? dirname(configPath);
|
|
358
|
+
const stateDir = resolve(projectRoot, ".memoark");
|
|
297
359
|
if (existsSync(stateDir)) {
|
|
298
360
|
ok.push(`State directory exists: ${stateDir}`);
|
|
299
361
|
}
|
|
@@ -301,12 +363,23 @@ program
|
|
|
301
363
|
warnings.push(`State directory does not exist: ${stateDir}`);
|
|
302
364
|
warnings.push("It will be created automatically on first extract");
|
|
303
365
|
}
|
|
366
|
+
const cwdStateDir = resolve(process.cwd(), ".memoark");
|
|
367
|
+
if (cwdStateDir !== stateDir && existsSync(cwdStateDir)) {
|
|
368
|
+
warnings.push(`Legacy state directory found at current cwd: ${cwdStateDir}`);
|
|
369
|
+
warnings.push(`Current config-root state directory is: ${stateDir}`);
|
|
370
|
+
warnings.push("Move cursor/dedup files manually if you intended to reuse the old state.");
|
|
371
|
+
}
|
|
304
372
|
// Check LLM configuration
|
|
305
373
|
if (config) {
|
|
374
|
+
const missingEnvVars = getMissingEnvVarsForCommand(config, "doctor");
|
|
375
|
+
if (missingEnvVars.length > 0) {
|
|
376
|
+
warnings.push(`Missing environment variables: ${missingEnvVars.join(", ")}`);
|
|
377
|
+
warnings.push(`Referenced by: ${config.__context.configPath}`);
|
|
378
|
+
}
|
|
306
379
|
if (config.llm?.provider && config.llm?.model) {
|
|
307
380
|
ok.push(`LLM provider configured: ${config.llm.provider} / ${config.llm.model}`);
|
|
308
381
|
const envKey = config.llm.provider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
309
|
-
if (
|
|
382
|
+
if (!missingEnvVars.includes(envKey)) {
|
|
310
383
|
ok.push(`${config.llm.provider} API key configured`);
|
|
311
384
|
}
|
|
312
385
|
else {
|
|
@@ -318,7 +391,7 @@ program
|
|
|
318
391
|
issues.push("LLM provider or model not configured");
|
|
319
392
|
}
|
|
320
393
|
// Check sources
|
|
321
|
-
bootstrapCollectors(config.sources);
|
|
394
|
+
bootstrapCollectors(config.sources, config.__context.projectRoot);
|
|
322
395
|
for (const collector of getAllCollectors()) {
|
|
323
396
|
const health = await collector.healthCheck();
|
|
324
397
|
if (health.ok) {
|
|
@@ -385,9 +458,13 @@ configCmd
|
|
|
385
458
|
.command("edit")
|
|
386
459
|
.description("Edit configuration in browser UI")
|
|
387
460
|
.option("--web", "Launch browser-based settings UI (default behavior)")
|
|
388
|
-
.
|
|
461
|
+
.option("-c, --config <path>", "Path to config file (default: memoark.yaml)")
|
|
462
|
+
.action(async (options) => {
|
|
389
463
|
const { startSetupServer } = await import("./server/setup-server.js");
|
|
390
|
-
await startSetupServer(
|
|
464
|
+
await startSetupServer({
|
|
465
|
+
configPath: options.config,
|
|
466
|
+
larkBin: readLarkBinFromConfig(options.config),
|
|
467
|
+
});
|
|
391
468
|
});
|
|
392
469
|
/**
|
|
393
470
|
* Sources subcommand group
|
|
@@ -399,7 +476,7 @@ sourcesCmd
|
|
|
399
476
|
.option("-c, --config <path>", "Path to config file")
|
|
400
477
|
.action((options) => {
|
|
401
478
|
const config = loadConfig(options.config);
|
|
402
|
-
bootstrapCollectors(config.sources);
|
|
479
|
+
bootstrapCollectors(config.sources, config.__context.projectRoot);
|
|
403
480
|
const collectors = getAllCollectors();
|
|
404
481
|
console.log("Available sources:\n");
|
|
405
482
|
for (const c of collectors) {
|
|
@@ -415,7 +492,7 @@ sourcesCmd
|
|
|
415
492
|
.action(async (name, options) => {
|
|
416
493
|
try {
|
|
417
494
|
const config = loadConfig(options.config);
|
|
418
|
-
bootstrapCollectors(config.sources);
|
|
495
|
+
bootstrapCollectors(config.sources, config.__context.projectRoot);
|
|
419
496
|
const collector = getCollector(name);
|
|
420
497
|
if (!collector) {
|
|
421
498
|
console.error(`Error: Unknown source '${name}'`);
|
|
@@ -436,104 +513,321 @@ sourcesCmd
|
|
|
436
513
|
process.exit(1);
|
|
437
514
|
}
|
|
438
515
|
});
|
|
516
|
+
async function runServe(options) {
|
|
517
|
+
{
|
|
518
|
+
const serveConfigPath = options.config ?? resolve(process.cwd(), "memoark.yaml");
|
|
519
|
+
if (!existsSync(serveConfigPath)) {
|
|
520
|
+
console.error("No configuration file found.\n" +
|
|
521
|
+
"Run `memoark start` for one-step setup + launch, or `memoark init --web` to configure first.");
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
const config = loadConfig(options.config);
|
|
525
|
+
// Anchor the .memoark state dir to the config's project root, not process.cwd().
|
|
526
|
+
// A Finder-launched sidecar has cwd=/, so the default would try to mkdir /.memoark
|
|
527
|
+
// (EROFS on macOS). projectRoot = dirname(configPath), so it lives beside the config.
|
|
528
|
+
const stateDir = ensureStateDir(config.__context.projectRoot);
|
|
529
|
+
const missingEnvVars = getMissingEnvVarsForCommand(config, "serve");
|
|
530
|
+
if (missingEnvVars.length > 0) {
|
|
531
|
+
console.warn(`[warn] Missing env vars: ${missingEnvVars.join(", ")} (referenced by ${config.__context.configPath})`);
|
|
532
|
+
}
|
|
533
|
+
const stores = await createStores(config);
|
|
534
|
+
const initialRuntime = await buildServeRuntime(config, stores, stateDir);
|
|
535
|
+
const holder = new ServeRuntimeHolder(initialRuntime);
|
|
536
|
+
if (config.scheduler?.enabled)
|
|
537
|
+
await holder.current.scheduler?.start();
|
|
538
|
+
const reloadManager = new ReloadManager({
|
|
539
|
+
holder,
|
|
540
|
+
// only read once at construction for the initial signature; ReloadManager tracks lastConfig internally afterward
|
|
541
|
+
currentConfig: () => config,
|
|
542
|
+
buildRuntime: (next) => buildServeRuntime(next, stores, stateDir),
|
|
543
|
+
});
|
|
544
|
+
const storesWithDaemon = {
|
|
545
|
+
...stores,
|
|
546
|
+
getDaemonStatus: () => holder.current.getDaemonStatus(),
|
|
547
|
+
// getter: always reads the current runtime, so a Tier-2 swap is seen by routes
|
|
548
|
+
get chatNameRefreshJob() {
|
|
549
|
+
return holder.current.chatNameRefreshJob;
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
let shuttingDown = false;
|
|
553
|
+
const shutdown = async () => {
|
|
554
|
+
if (shuttingDown)
|
|
555
|
+
return; // 防重入:连按 Ctrl-C 不会二次 db.close()
|
|
556
|
+
shuttingDown = true;
|
|
557
|
+
await holder.current.dispose();
|
|
558
|
+
try {
|
|
559
|
+
await stores.db.close(); // 触发锁 release
|
|
560
|
+
}
|
|
561
|
+
finally {
|
|
562
|
+
process.exit(0); // db.close() 抛错也必须退出
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
process.on("SIGTERM", shutdown);
|
|
566
|
+
process.on("SIGINT", shutdown);
|
|
567
|
+
if (options.mcp) {
|
|
568
|
+
const llmConfig = { ...config.llm };
|
|
569
|
+
const envKey = llmConfig.provider === "anthropic"
|
|
570
|
+
? process.env.ANTHROPIC_API_KEY
|
|
571
|
+
: process.env.OPENAI_API_KEY;
|
|
572
|
+
if (!llmConfig.api_key && envKey)
|
|
573
|
+
llmConfig.api_key = envKey;
|
|
574
|
+
const synthProvider = llmConfig.api_key
|
|
575
|
+
? createLLMProvider(llmConfig)
|
|
576
|
+
: createMockProvider(new Map());
|
|
577
|
+
let ingestDeps;
|
|
578
|
+
const feishu = config.sources.feishu;
|
|
579
|
+
if (feishu?.enabled && feishu.sources?.docs?.enabled) {
|
|
580
|
+
const client = new LarkCliHttpClient(feishu.lark_bin);
|
|
581
|
+
ingestDeps = {
|
|
582
|
+
client,
|
|
583
|
+
stores: storesWithDaemon,
|
|
584
|
+
provider: synthProvider,
|
|
585
|
+
model: feishu.sources.docs.llm?.model ?? llmConfig.model,
|
|
586
|
+
nowIso: () => new Date().toISOString(),
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const server = createMcpServer(storesWithDaemon, { provider: synthProvider, synthModel: llmConfig.model }, ingestDeps);
|
|
590
|
+
await server.connect(new StdioServerTransport());
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if (options.mcpHttp ||
|
|
594
|
+
config.mcp.http.enabled ||
|
|
595
|
+
config.server.mcp_transport === "streamable_http") {
|
|
596
|
+
const tokenEnv = config.mcp.http.auth_token_env;
|
|
597
|
+
const app = createMcpHttpApp(storesWithDaemon, {
|
|
598
|
+
allowedOrigins: config.mcp.http.allowed_origins,
|
|
599
|
+
allowedHosts: config.mcp.http.allowed_hosts,
|
|
600
|
+
authToken: tokenEnv ? process.env[tokenEnv] : undefined,
|
|
601
|
+
exposeLegacyTools: config.mcp.expose_legacy_tools,
|
|
602
|
+
readOnly: config.mcp.http.read_only,
|
|
603
|
+
});
|
|
604
|
+
const server = await startServer(app, {
|
|
605
|
+
hostname: config.mcp.http.bind_host,
|
|
606
|
+
port: config.mcp.http.port,
|
|
607
|
+
});
|
|
608
|
+
console.log(`Memoark MCP Streamable HTTP listening on http://${server.hostname}:${server.port}/mcp`);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const app = createApiApp(storesWithDaemon, {
|
|
612
|
+
onConfigSaved: () => {
|
|
613
|
+
try {
|
|
614
|
+
void reloadManager.run(loadConfig(options.config)).catch((err) => {
|
|
615
|
+
console.error("[reload] Runtime reload failed:", err);
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
catch (err) {
|
|
619
|
+
console.error("[reload] Failed to load config after save:", err);
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
// In a `bun --compile` sidecar, import.meta.url lives under $bunfs and web/dist is
|
|
624
|
+
// NOT embedded, so the default path can't be served. The Tauri shell ships web/dist
|
|
625
|
+
// as a resource and injects its real path via MEMOARK_WEB_DIST (mirrors pglite-assets).
|
|
626
|
+
const webDist = process.env.MEMOARK_WEB_DIST ?? join(fileURLToPath(import.meta.url), "../../web/dist");
|
|
627
|
+
// `--port 0` (used by the Tauri shell) binds an OS-assigned free port so the desktop
|
|
628
|
+
// app never collides with a CLI `memoark serve`, a stale instance, or anything else
|
|
629
|
+
// on the default port. The actual port is reported below for the webview to read.
|
|
630
|
+
const requestedPort = options.port !== undefined ? Number(options.port) : config.server.http_port;
|
|
631
|
+
const server = Bun.serve({
|
|
632
|
+
port: requestedPort,
|
|
633
|
+
fetch: async (req) => {
|
|
634
|
+
const url = new URL(req.url);
|
|
635
|
+
if (url.pathname.startsWith("/api"))
|
|
636
|
+
return app.fetch(req);
|
|
637
|
+
const filePath = url.pathname === "/" ? "index.html" : url.pathname.replace(/^\//, "");
|
|
638
|
+
const candidate = Bun.file(join(webDist, filePath));
|
|
639
|
+
if (await candidate.exists())
|
|
640
|
+
return new Response(candidate);
|
|
641
|
+
return new Response(Bun.file(join(webDist, "index.html")));
|
|
642
|
+
},
|
|
643
|
+
});
|
|
644
|
+
console.log(`Memoark HTTP API listening on http://localhost:${server.port}`);
|
|
645
|
+
// Stdout contract for the Tauri shell: the URL after the marker is where the webview
|
|
646
|
+
// navigates (the port may be OS-assigned, so report the real one — never hardcode).
|
|
647
|
+
console.log(`MEMOARK_READY http://localhost:${server.port}`);
|
|
648
|
+
if (shouldOpenBrowserOnServe({
|
|
649
|
+
open: options.open !== false,
|
|
650
|
+
mcp: !!options.mcp,
|
|
651
|
+
mcpHttp: !!options.mcpHttp,
|
|
652
|
+
})) {
|
|
653
|
+
openBrowser(`http://localhost:${server.port}`);
|
|
654
|
+
}
|
|
655
|
+
const activeScheduler = holder.current.scheduler;
|
|
656
|
+
if (activeScheduler && config.scheduler?.enabled) {
|
|
657
|
+
console.log(`Scheduler running — tick every ${config.scheduler.tick_interval_secs}s, sources: ${activeScheduler.getSourceIds().join(", ")}`);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
439
661
|
program
|
|
440
662
|
.command("serve")
|
|
441
663
|
.description("Start Memoark HTTP API or MCP stdio server")
|
|
442
664
|
.option("-c, --config <path>", "Path to config file")
|
|
443
665
|
.option("--mcp", "Run MCP stdio transport instead of HTTP")
|
|
444
|
-
.
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
:
|
|
465
|
-
const pipelineConfig = {
|
|
466
|
-
dedup_checkpoint: statePath("dedup.jsonl"),
|
|
467
|
-
cursor_checkpoint: statePath("cursors.yaml"),
|
|
468
|
-
block_gap_minutes: config.block_builder.block_gap_minutes,
|
|
469
|
-
max_block_tokens: config.block_builder.max_block_tokens,
|
|
470
|
-
max_block_messages: config.block_builder.max_block_messages,
|
|
471
|
-
privacy: config.privacy,
|
|
472
|
-
output_dir: process.cwd(),
|
|
473
|
-
block_concurrency: config.pipeline?.block_concurrency,
|
|
474
|
-
};
|
|
475
|
-
scheduler = new Scheduler(config.scheduler, stateDir);
|
|
476
|
-
scheduler.setRunSource(async (sourceId) => {
|
|
477
|
-
const collector = getCollector(sourceId);
|
|
478
|
-
if (!collector)
|
|
479
|
-
throw new Error(`Unknown source: ${sourceId}`);
|
|
480
|
-
return runPipeline(pipelineConfig, {
|
|
481
|
-
source: collector,
|
|
482
|
-
provider,
|
|
483
|
-
format: "json",
|
|
484
|
-
adapter: "store",
|
|
485
|
-
stores,
|
|
486
|
-
dryRun: false,
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
|
-
scheduler.setOnTick((sourceId, result, duration_ms) => {
|
|
490
|
-
const status = result.fatal ? "failed" : "ok";
|
|
491
|
-
console.log(`[scheduler] ${sourceId}: ${status} (${duration_ms}ms)`);
|
|
666
|
+
.option("--mcp-http", "Run MCP Streamable HTTP transport instead of the HTTP API")
|
|
667
|
+
.option("--no-open", "Do not auto-open the browser after starting")
|
|
668
|
+
.option("--pglite-assets <dir>", "Directory holding bundled PGLite assets (compiled-sidecar mode; injected by the Tauri shell)")
|
|
669
|
+
.option("--web-dist <dir>", "Directory holding the built web UI (compiled-sidecar mode; injected by the Tauri shell)")
|
|
670
|
+
.option("--port <n>", "Override the HTTP port; 0 binds an OS-assigned free port (used by the Tauri shell)")
|
|
671
|
+
.action((options) => {
|
|
672
|
+
if (options.pgliteAssets)
|
|
673
|
+
process.env.MEMOARK_PGLITE_ASSETS = options.pgliteAssets;
|
|
674
|
+
if (options.webDist)
|
|
675
|
+
process.env.MEMOARK_WEB_DIST = options.webDist;
|
|
676
|
+
return runServe(options);
|
|
677
|
+
});
|
|
678
|
+
async function runStart(options) {
|
|
679
|
+
const configPath = options.config ?? resolve(process.cwd(), "memoark.yaml");
|
|
680
|
+
const plan = planStartup(existsSync(configPath));
|
|
681
|
+
if (plan.runSetup) {
|
|
682
|
+
console.log("No configuration found — launching setup wizard...");
|
|
683
|
+
const { startSetupServer } = await import("./server/setup-server.js");
|
|
684
|
+
await startSetupServer({
|
|
685
|
+
configPath: options.config,
|
|
686
|
+
larkBin: readLarkBinFromConfig(options.config),
|
|
492
687
|
});
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
if (s.last_run_at !== null && (lastRunAt === null || s.last_run_at > lastRunAt)) {
|
|
506
|
-
lastRunAt = s.last_run_at;
|
|
507
|
-
}
|
|
508
|
-
const next = s.last_run_at !== null ? s.last_run_at + s.interval_secs * 1000 : now;
|
|
509
|
-
if (nextAt === null || next < nextAt)
|
|
510
|
-
nextAt = next;
|
|
511
|
-
}
|
|
512
|
-
return {
|
|
513
|
-
running: true,
|
|
514
|
-
uptime_seconds: Math.floor((now - (hb?.daemon_started_at ?? now)) / 1000),
|
|
515
|
-
last_run: lastRunAt ? new Date(lastRunAt).toISOString() : null,
|
|
516
|
-
next_scheduled: nextAt !== null ? new Date(nextAt).toISOString() : null,
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
: undefined;
|
|
520
|
-
const storesWithDaemon = { ...stores, getDaemonStatus };
|
|
521
|
-
const shutdown = () => {
|
|
522
|
-
scheduler?.stop();
|
|
523
|
-
};
|
|
524
|
-
process.on("SIGTERM", shutdown);
|
|
525
|
-
process.on("SIGINT", shutdown);
|
|
526
|
-
if (options.mcp) {
|
|
527
|
-
const server = createMcpServer(storesWithDaemon);
|
|
528
|
-
await server.connect(new StdioServerTransport());
|
|
688
|
+
}
|
|
689
|
+
await runServe({ config: options.config });
|
|
690
|
+
}
|
|
691
|
+
program
|
|
692
|
+
.command("start")
|
|
693
|
+
.description("One-step launch: setup if needed, then serve + open browser")
|
|
694
|
+
.option("-c, --config <path>", "Path to config file")
|
|
695
|
+
.action((options) => runStart(options));
|
|
696
|
+
program.action(() => runStart({}));
|
|
697
|
+
function reportPlan(planned, verb, dryRun) {
|
|
698
|
+
if (planned.length === 0) {
|
|
699
|
+
console.log("No AI agents detected. Specify one with --agent <id> (claude-code, claude-desktop, cursor, codex, windsurf).");
|
|
529
700
|
return;
|
|
530
701
|
}
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
702
|
+
for (const client of planned) {
|
|
703
|
+
console.log(`\n${verb} → ${client.displayName}:`);
|
|
704
|
+
for (const op of client.ops) {
|
|
705
|
+
const where = "path" in op ? op.path : `cli: ${op.args.join(" ")}`;
|
|
706
|
+
console.log(` - ${op.kind} ${op.action} ${where}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (!dryRun)
|
|
710
|
+
console.log("\nRestart / reopen your agent for changes to take effect.");
|
|
711
|
+
}
|
|
712
|
+
program
|
|
713
|
+
.command("install")
|
|
714
|
+
.description("Register Memoark (MCP config + memory directive) into your AI agents")
|
|
715
|
+
.option("--agent <ids...>", "Target client(s): claude-code, claude-desktop, cursor, codex, windsurf (default: all detected)")
|
|
716
|
+
.option("--project", "Install into the current project instead of globally")
|
|
717
|
+
.option("--http", "Register the Streamable HTTP transport instead of stdio")
|
|
718
|
+
.option("--dry-run", "Preview changes without writing")
|
|
719
|
+
.action((options) => {
|
|
720
|
+
const scope = options.project ? "project" : "global";
|
|
721
|
+
const planned = runInstall({
|
|
722
|
+
agent: options.agent,
|
|
723
|
+
scope,
|
|
724
|
+
http: !!options.http,
|
|
725
|
+
dryRun: !!options.dryRun,
|
|
726
|
+
});
|
|
727
|
+
reportPlan(planned, options.dryRun ? "Would install" : "Installed", !!options.dryRun);
|
|
728
|
+
});
|
|
729
|
+
program
|
|
730
|
+
.command("uninstall")
|
|
731
|
+
.description("Remove Memoark MCP config + memory directive from your AI agents")
|
|
732
|
+
.option("--agent <ids...>", "Target client(s) (default: all detected)")
|
|
733
|
+
.option("--project", "Operate on the current project instead of globally")
|
|
734
|
+
.option("--dry-run", "Preview changes without writing")
|
|
735
|
+
.action((options) => {
|
|
736
|
+
const scope = options.project ? "project" : "global";
|
|
737
|
+
const planned = runUninstall({ agent: options.agent, scope, dryRun: !!options.dryRun });
|
|
738
|
+
reportPlan(planned, options.dryRun ? "Would remove" : "Removed", !!options.dryRun);
|
|
739
|
+
});
|
|
740
|
+
const hooksCmd = program
|
|
741
|
+
.command("hooks")
|
|
742
|
+
.description("Manage Claude Code hooks for automatic recall / write-back");
|
|
743
|
+
hooksCmd
|
|
744
|
+
.command("install")
|
|
745
|
+
.description("Install SessionStart + UserPromptSubmit (read) hooks; write-back is opt-in")
|
|
746
|
+
.option("--write-back", "Also install the SessionEnd auto write-back hook (opt-in)")
|
|
747
|
+
.option("--project", "Write to ./.claude/settings.json instead of the global one")
|
|
748
|
+
.option("--dry-run", "Preview without writing")
|
|
749
|
+
.action((options) => {
|
|
750
|
+
const res = hooksInstall({
|
|
751
|
+
writeBack: !!options.writeBack,
|
|
752
|
+
project: !!options.project,
|
|
753
|
+
dryRun: !!options.dryRun,
|
|
754
|
+
});
|
|
755
|
+
console.log(`${options.dryRun ? "Would install" : "Installed"} hooks [${res.events.join(", ")}] → ${res.path}`);
|
|
756
|
+
if (!options.writeBack) {
|
|
757
|
+
console.log("Tip: add --write-back to also auto-capture memory at session end (opt-in).");
|
|
758
|
+
}
|
|
759
|
+
if (!options.dryRun)
|
|
760
|
+
console.log("Reopen Claude Code for the hooks to take effect.");
|
|
761
|
+
});
|
|
762
|
+
hooksCmd
|
|
763
|
+
.command("uninstall")
|
|
764
|
+
.description("Remove all Memoark hooks from settings.json")
|
|
765
|
+
.option("--project", "Operate on ./.claude/settings.json instead of the global one")
|
|
766
|
+
.option("--dry-run", "Preview without writing")
|
|
767
|
+
.action((options) => {
|
|
768
|
+
const res = hooksUninstall({ project: !!options.project, dryRun: !!options.dryRun });
|
|
769
|
+
console.log(`${options.dryRun ? "Would remove" : "Removed"} Memoark hooks → ${res.path}`);
|
|
770
|
+
});
|
|
771
|
+
const skillCmd = program.command("skill").description("Manage the Memoark agent skill");
|
|
772
|
+
skillCmd
|
|
773
|
+
.command("scaffold")
|
|
774
|
+
.description("Write the memoark skill (SKILL.md) into a skills directory")
|
|
775
|
+
.option("--dir <path>", "Target skills directory (default: ./.claude/skills)")
|
|
776
|
+
.action((options) => {
|
|
777
|
+
const dir = options.dir ?? join(process.cwd(), ".claude", "skills");
|
|
778
|
+
const path = scaffoldSkill(dir);
|
|
779
|
+
console.log(`Wrote ${path}`);
|
|
780
|
+
});
|
|
781
|
+
async function readStdinJson() {
|
|
782
|
+
const chunks = [];
|
|
783
|
+
for await (const chunk of process.stdin)
|
|
784
|
+
chunks.push(chunk);
|
|
785
|
+
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
786
|
+
if (!raw)
|
|
787
|
+
return {};
|
|
788
|
+
try {
|
|
789
|
+
return JSON.parse(raw);
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
return {};
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
program
|
|
796
|
+
.command("hook <event>")
|
|
797
|
+
.description("Internal: Claude Code hook entrypoint (session-start|user-prompt|session-end)")
|
|
798
|
+
.action(async (event) => {
|
|
799
|
+
try {
|
|
800
|
+
const input = await readStdinJson();
|
|
801
|
+
const config = loadConfig(undefined);
|
|
802
|
+
const port = config.server.http_port;
|
|
803
|
+
const out = await runHookEvent(event, input, {
|
|
804
|
+
port,
|
|
805
|
+
sessionContext: async () => {
|
|
806
|
+
const stores = await createStores(config);
|
|
807
|
+
try {
|
|
808
|
+
return await getSessionContext(stores);
|
|
809
|
+
}
|
|
810
|
+
finally {
|
|
811
|
+
await stores.db.close();
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
ftsSearch: async (q, opts) => {
|
|
815
|
+
const stores = await createStores(config);
|
|
816
|
+
try {
|
|
817
|
+
return await stores.search.search(q, opts);
|
|
818
|
+
}
|
|
819
|
+
finally {
|
|
820
|
+
await stores.db.close();
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
if (out && Object.keys(out).length > 0)
|
|
825
|
+
process.stdout.write(JSON.stringify(out));
|
|
826
|
+
}
|
|
827
|
+
catch {
|
|
828
|
+
// Never break the host session: emit nothing on any failure.
|
|
536
829
|
}
|
|
830
|
+
process.exit(0);
|
|
537
831
|
});
|
|
538
832
|
program
|
|
539
833
|
.command("search <query>")
|
|
@@ -542,7 +836,9 @@ program
|
|
|
542
836
|
.option("--mode <mode>", "Search mode (hybrid|fts)", "hybrid")
|
|
543
837
|
.option("--limit <n>", "Limit results", "20")
|
|
544
838
|
.action(async (query, options) => {
|
|
545
|
-
const
|
|
839
|
+
const config = loadConfig(options.config);
|
|
840
|
+
validateEnvForCommand(config, "search", { searchMode: options.mode });
|
|
841
|
+
const stores = await createStores(config);
|
|
546
842
|
const limit = Number(options.limit);
|
|
547
843
|
const results = options.mode === "fts"
|
|
548
844
|
? await stores.search.search(query, { limit })
|
|
@@ -558,7 +854,9 @@ program
|
|
|
558
854
|
.option("-c, --config <path>", "Path to config file")
|
|
559
855
|
.option("--limit <n>", "Limit chunks")
|
|
560
856
|
.action(async (options) => {
|
|
561
|
-
const
|
|
857
|
+
const config = loadConfig(options.config);
|
|
858
|
+
validateEnvForCommand(config, "embed");
|
|
859
|
+
const stores = await createStores(config);
|
|
562
860
|
const result = await stores.embedding.embedStale({
|
|
563
861
|
limit: options.limit ? Number(options.limit) : undefined,
|
|
564
862
|
});
|
|
@@ -666,7 +964,15 @@ program
|
|
|
666
964
|
graph: stores.graph,
|
|
667
965
|
tags: stores.tags,
|
|
668
966
|
timeline: stores.timeline,
|
|
669
|
-
}, llmProvider
|
|
967
|
+
}, llmProvider, {
|
|
968
|
+
profile: config.profile,
|
|
969
|
+
profileStores: {
|
|
970
|
+
pages: stores.pages,
|
|
971
|
+
graph: stores.graph,
|
|
972
|
+
timeline: stores.timeline,
|
|
973
|
+
behavior: new PersonBehaviorStore(stores.db.pg),
|
|
974
|
+
},
|
|
975
|
+
});
|
|
670
976
|
const mode = options.hot
|
|
671
977
|
? "hot"
|
|
672
978
|
: options.warm
|
|
@@ -683,6 +989,7 @@ program
|
|
|
683
989
|
console.log(` warm→cold pages archived: ${result.warmToCold}`);
|
|
684
990
|
console.log(` dead links checked: ${result.deadLinksChecked}`);
|
|
685
991
|
console.log(` preferences inferred: ${result.preferencesInferred}`);
|
|
992
|
+
console.log(` profiles synthesized: ${result.profilesSynthesized}`);
|
|
686
993
|
await stores.db.close();
|
|
687
994
|
}
|
|
688
995
|
catch (error) {
|
|
@@ -690,5 +997,254 @@ program
|
|
|
690
997
|
process.exit(1);
|
|
691
998
|
}
|
|
692
999
|
});
|
|
1000
|
+
// ── Person identity (Layer 1: aliases / merge / rename) ────────────────────
|
|
1001
|
+
const HANDLE_KINDS = ["feishu_open_id", "email", "name", "nickname", "slug"];
|
|
1002
|
+
const identityCmd = program
|
|
1003
|
+
.command("identity")
|
|
1004
|
+
.description("Manage person identity: aliases, merge, and rename");
|
|
1005
|
+
identityCmd
|
|
1006
|
+
.command("alias <canonical_slug> <kind> <value>")
|
|
1007
|
+
.description(`Attach an alias/handle to a person. kind: ${HANDLE_KINDS.join(" | ")}`)
|
|
1008
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1009
|
+
.option("--strong", "Force strong strength (auto-resolvable)")
|
|
1010
|
+
.option("--weak", "Force weak strength (explicit-only)")
|
|
1011
|
+
.action(async (canonicalSlug, kind, value, options) => {
|
|
1012
|
+
if (!HANDLE_KINDS.includes(kind)) {
|
|
1013
|
+
console.error(`Error: invalid kind '${kind}'. Expected one of: ${HANDLE_KINDS.join(", ")}`);
|
|
1014
|
+
process.exit(1);
|
|
1015
|
+
}
|
|
1016
|
+
const { db, identity } = await openIdentityStore(loadConfig(options.config));
|
|
1017
|
+
try {
|
|
1018
|
+
const strength = options.strong ? "strong" : options.weak ? "weak" : undefined;
|
|
1019
|
+
await identity.addAlias(canonicalSlug, kind, value, strength);
|
|
1020
|
+
console.log(`Linked ${kind}:${value} → ${canonicalSlug}`);
|
|
1021
|
+
for (const h of await identity.listHandles(canonicalSlug)) {
|
|
1022
|
+
console.log(` ${h.kind}\t${h.value}\t(${h.strength})`);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
catch (error) {
|
|
1026
|
+
console.error("alias failed:", error instanceof Error ? error.message : String(error));
|
|
1027
|
+
process.exit(1);
|
|
1028
|
+
}
|
|
1029
|
+
finally {
|
|
1030
|
+
await db.close();
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
identityCmd
|
|
1034
|
+
.command("handles <canonical_slug>")
|
|
1035
|
+
.description("List all handles/aliases attached to a person")
|
|
1036
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1037
|
+
.action(async (canonicalSlug, options) => {
|
|
1038
|
+
const { db, identity } = await openIdentityStore(loadConfig(options.config));
|
|
1039
|
+
try {
|
|
1040
|
+
const handles = await identity.listHandles(canonicalSlug);
|
|
1041
|
+
if (handles.length === 0) {
|
|
1042
|
+
console.log(`No handles for ${canonicalSlug}`);
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
for (const h of handles)
|
|
1046
|
+
console.log(`${h.kind}\t${h.value}\t(${h.strength})`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
finally {
|
|
1050
|
+
await db.close();
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
identityCmd
|
|
1054
|
+
.command("merge <from> <into>")
|
|
1055
|
+
.description("Merge person page <from> into <into> (re-points links/timeline/tags + aliases)")
|
|
1056
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1057
|
+
.action(async (from, into, options) => {
|
|
1058
|
+
const { db, identity } = await openIdentityStore(loadConfig(options.config));
|
|
1059
|
+
try {
|
|
1060
|
+
await identity.merge(from, into);
|
|
1061
|
+
console.log(`Merged ${from} → ${into}`);
|
|
1062
|
+
console.log("Note: run `memoark embed` to re-embed the folded content.");
|
|
1063
|
+
}
|
|
1064
|
+
catch (error) {
|
|
1065
|
+
console.error("merge failed:", error instanceof Error ? error.message : String(error));
|
|
1066
|
+
process.exit(1);
|
|
1067
|
+
}
|
|
1068
|
+
finally {
|
|
1069
|
+
await db.close();
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
identityCmd
|
|
1073
|
+
.command("rename <from> <to>")
|
|
1074
|
+
.description("Rename a person's canonical slug (correct a wrong canonicalization)")
|
|
1075
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1076
|
+
.action(async (from, to, options) => {
|
|
1077
|
+
const { db, identity } = await openIdentityStore(loadConfig(options.config));
|
|
1078
|
+
try {
|
|
1079
|
+
await identity.recanonicalize(from, to);
|
|
1080
|
+
console.log(`Renamed ${from} → ${to}`);
|
|
1081
|
+
}
|
|
1082
|
+
catch (error) {
|
|
1083
|
+
console.error("rename failed:", error instanceof Error ? error.message : String(error));
|
|
1084
|
+
process.exit(1);
|
|
1085
|
+
}
|
|
1086
|
+
finally {
|
|
1087
|
+
await db.close();
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
const docsCmd = program.command("docs").description("Feishu doc summary cards (DocSource v2)");
|
|
1091
|
+
docsCmd
|
|
1092
|
+
.command("sync")
|
|
1093
|
+
.description("Scan Feishu docs, build pointer cards, upgrade triggered docs to full cards")
|
|
1094
|
+
.option("-c, --config <path>", "Path to config file (default: memoark.yaml)")
|
|
1095
|
+
.action(async (options) => {
|
|
1096
|
+
try {
|
|
1097
|
+
const config = loadConfig(options.config);
|
|
1098
|
+
ensureStateDir();
|
|
1099
|
+
const feishu = config.sources.feishu;
|
|
1100
|
+
if (!feishu?.enabled || !feishu.sources?.docs?.enabled) {
|
|
1101
|
+
console.error("Feishu docs source is not enabled in config (sources.feishu.sources.docs.enabled).");
|
|
1102
|
+
process.exit(1);
|
|
1103
|
+
}
|
|
1104
|
+
const stores = await createStores(config);
|
|
1105
|
+
const client = new LarkCliHttpClient(feishu.lark_bin);
|
|
1106
|
+
const docsConfig = normalizeDocsConfig(feishu.sources.docs);
|
|
1107
|
+
// self_open_id: config override else resolve via lark-cli whoami helper used elsewhere
|
|
1108
|
+
const selfOpenId = docsConfig.self_open_id ??
|
|
1109
|
+
(await resolveSelfOpenId(client, feishu.sources?.dm?.self_open_id)) ??
|
|
1110
|
+
"";
|
|
1111
|
+
const llmConfig = { ...config.llm };
|
|
1112
|
+
if (docsConfig.llm.model)
|
|
1113
|
+
llmConfig.model = docsConfig.llm.model;
|
|
1114
|
+
const envKey = llmConfig.provider === "anthropic"
|
|
1115
|
+
? process.env.ANTHROPIC_API_KEY
|
|
1116
|
+
: process.env.OPENAI_API_KEY;
|
|
1117
|
+
if (!llmConfig.api_key && envKey)
|
|
1118
|
+
llmConfig.api_key = envKey;
|
|
1119
|
+
const provider = llmConfig.api_key
|
|
1120
|
+
? createLLMProvider(llmConfig)
|
|
1121
|
+
: createMockProvider(new Map());
|
|
1122
|
+
const cursor = new CursorStore(statePath("cursors.yaml"));
|
|
1123
|
+
cursor.load();
|
|
1124
|
+
// Identity layer for canonicalizing action_item owners → person slugs and
|
|
1125
|
+
// detecting self-ownership, so doc/meeting action_items become task signals
|
|
1126
|
+
// the daily report can surface (Spec 9 §3.3).
|
|
1127
|
+
const identity = new PersonIdentityStore(stores.db.pg, { pages: stores.pages }, { behavior: new PersonBehaviorStore(stores.db.pg) });
|
|
1128
|
+
const stats = await runDocSource({
|
|
1129
|
+
client,
|
|
1130
|
+
stores,
|
|
1131
|
+
provider,
|
|
1132
|
+
config: docsConfig,
|
|
1133
|
+
cursor,
|
|
1134
|
+
selfOpenId,
|
|
1135
|
+
nowMs: Date.now(),
|
|
1136
|
+
nowIso: () => new Date().toISOString(),
|
|
1137
|
+
actionItemDeps: {
|
|
1138
|
+
graph: stores.graph,
|
|
1139
|
+
resolveOwner: async (ownerRaw) => {
|
|
1140
|
+
if (!ownerRaw)
|
|
1141
|
+
return null;
|
|
1142
|
+
// best-effort: map a name/@mention to a canonical person slug
|
|
1143
|
+
return ((await identity.resolveHandle("name", ownerRaw)) ??
|
|
1144
|
+
(await identity.resolveHandle("nickname", ownerRaw)) ??
|
|
1145
|
+
null);
|
|
1146
|
+
},
|
|
1147
|
+
isMe: (slug) => identity.isMe(slug),
|
|
1148
|
+
},
|
|
1149
|
+
});
|
|
1150
|
+
console.log(`[docs] scanned=${stats.candidates_scanned} pointer=${stats.pointer_saved} full=${stats.full_card_generated} skipped=${stats.skipped} queue=${stats.upgrade_queue_size} llm_failed=${stats.llm_failed}`);
|
|
1151
|
+
await stores.db.close();
|
|
1152
|
+
}
|
|
1153
|
+
catch (error) {
|
|
1154
|
+
console.error("docs sync failed:", error instanceof Error ? error.message : String(error));
|
|
1155
|
+
process.exit(1);
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
docsCmd
|
|
1159
|
+
.command("status")
|
|
1160
|
+
.description("Show Feishu doc card counts")
|
|
1161
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1162
|
+
.option("--failed", "List cards whose last extraction failed")
|
|
1163
|
+
.action(async (options) => {
|
|
1164
|
+
try {
|
|
1165
|
+
const config = loadConfig(options.config);
|
|
1166
|
+
const stores = await createStores(config);
|
|
1167
|
+
const pages = await stores.pages.listPages({ type: "feishu_doc_card", limit: 100000 });
|
|
1168
|
+
if (options.failed) {
|
|
1169
|
+
for (const f of failedCards(pages))
|
|
1170
|
+
console.log(`${f.doc_token}\t${f.error}`);
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
const s = summarizeCards(pages);
|
|
1174
|
+
console.log(`total=${s.total} full=${s.full} pointer=${s.pointer} failed=${s.failed}`);
|
|
1175
|
+
}
|
|
1176
|
+
await stores.db.close();
|
|
1177
|
+
}
|
|
1178
|
+
catch (error) {
|
|
1179
|
+
console.error("docs status failed:", error instanceof Error ? error.message : String(error));
|
|
1180
|
+
process.exit(1);
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
docsCmd
|
|
1184
|
+
.command("retry [doc_token]")
|
|
1185
|
+
.description("Retry full-card extraction for a failed doc (or --all-failed)")
|
|
1186
|
+
.option("-c, --config <path>", "Path to config file")
|
|
1187
|
+
.option("--all-failed", "Retry every card with an extract_error")
|
|
1188
|
+
.action(async (docToken, options) => {
|
|
1189
|
+
try {
|
|
1190
|
+
const config = loadConfig(options.config);
|
|
1191
|
+
const feishu = config.sources.feishu;
|
|
1192
|
+
if (!feishu?.sources?.docs?.enabled) {
|
|
1193
|
+
console.error("Feishu docs source not enabled.");
|
|
1194
|
+
process.exit(1);
|
|
1195
|
+
}
|
|
1196
|
+
const stores = await createStores(config);
|
|
1197
|
+
const client = new LarkCliHttpClient(feishu.lark_bin);
|
|
1198
|
+
const docsConfig = normalizeDocsConfig(feishu.sources.docs);
|
|
1199
|
+
const llmConfig = { ...config.llm };
|
|
1200
|
+
if (docsConfig.llm.model)
|
|
1201
|
+
llmConfig.model = docsConfig.llm.model;
|
|
1202
|
+
const envKey = llmConfig.provider === "anthropic"
|
|
1203
|
+
? process.env.ANTHROPIC_API_KEY
|
|
1204
|
+
: process.env.OPENAI_API_KEY;
|
|
1205
|
+
if (!llmConfig.api_key && envKey)
|
|
1206
|
+
llmConfig.api_key = envKey;
|
|
1207
|
+
const provider = llmConfig.api_key
|
|
1208
|
+
? createLLMProvider(llmConfig)
|
|
1209
|
+
: createMockProvider(new Map());
|
|
1210
|
+
const builder = new FullCardBuilder(client, provider, docsConfig.llm.model ?? "unknown", () => new Date().toISOString());
|
|
1211
|
+
const tokens = [];
|
|
1212
|
+
if (options.allFailed) {
|
|
1213
|
+
const pages = await stores.pages.listPages({ type: "feishu_doc_card", limit: 100000 });
|
|
1214
|
+
for (const f of failedCards(pages))
|
|
1215
|
+
tokens.push(f.doc_token);
|
|
1216
|
+
}
|
|
1217
|
+
else if (docToken) {
|
|
1218
|
+
tokens.push(docToken);
|
|
1219
|
+
}
|
|
1220
|
+
else {
|
|
1221
|
+
console.error("Provide a doc_token or --all-failed.");
|
|
1222
|
+
process.exit(1);
|
|
1223
|
+
}
|
|
1224
|
+
for (const token of tokens) {
|
|
1225
|
+
const existing = await loadExistingCard(stores, token);
|
|
1226
|
+
if (!existing) {
|
|
1227
|
+
console.warn(`skip ${token}: no existing card`);
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
// retry intentionally re-evaluates the gate (no force); short/empty docs
|
|
1231
|
+
// stay pointers by design — unlike MCP ingest which forces.
|
|
1232
|
+
const card = await builder.build(existing);
|
|
1233
|
+
await writeCard(stores, card);
|
|
1234
|
+
if (card.extract_level === "pointer") {
|
|
1235
|
+
const reason = card.extract_error ?? card.extract_skipped ?? "unknown";
|
|
1236
|
+
console.log(`${token}: pointer (not upgraded — ${reason})`);
|
|
1237
|
+
}
|
|
1238
|
+
else {
|
|
1239
|
+
console.log(`${token}: full`);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
await stores.db.close();
|
|
1243
|
+
}
|
|
1244
|
+
catch (error) {
|
|
1245
|
+
console.error("docs retry failed:", error instanceof Error ? error.message : String(error));
|
|
1246
|
+
process.exit(1);
|
|
1247
|
+
}
|
|
1248
|
+
});
|
|
693
1249
|
program.parse(process.argv);
|
|
694
1250
|
//# sourceMappingURL=cli.js.map
|