@vellumai/assistant 0.8.0 → 0.8.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/AGENTS.md +11 -0
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +80 -5
- package/README.md +2 -2
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +21 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +4462 -991
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +135 -14
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +129 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +137 -2
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +35 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +278 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +159 -18
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -4
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +93 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +80 -3
- package/src/__tests__/conversation-fork-crud.test.ts +323 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +54 -18
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +297 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +25 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +80 -13
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -8
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +482 -0
- package/src/__tests__/filing-service.test.ts +163 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +42 -69
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +162 -0
- package/src/__tests__/host-app-control-proxy.test.ts +365 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +156 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +410 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +248 -0
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +157 -39
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +107 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +190 -2
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +222 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +145 -14
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +863 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +48 -19
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +41 -38
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +31 -4
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -18
- package/src/__tests__/plugin-types.test.ts +15 -23
- package/src/__tests__/process-message-background-slack.test.ts +53 -0
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +20 -12
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +151 -0
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +208 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +12 -4
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -12
- package/src/__tests__/skill-load-tool.test.ts +29 -93
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +143 -5
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +108 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +170 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +241 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/image-optimize.ts +13 -5
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +74 -36
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +109 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +578 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +478 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +429 -434
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +342 -304
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +40 -6
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -2
- package/src/config/feature-flag-registry.json +57 -1
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +140 -52
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +8 -7
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +81 -0
- package/src/config/schemas/llm.ts +55 -2
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/config/skills.ts +3 -96
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1334
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +113 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +183 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +26 -30
- package/src/daemon/config-watcher.ts +94 -29
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +293 -103
- package/src/daemon/conversation-error.ts +188 -33
- package/src/daemon/conversation-lifecycle.ts +80 -26
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +85 -31
- package/src/daemon/conversation-runtime-assembly.ts +30 -6
- package/src/daemon/conversation-slash.ts +184 -25
- package/src/daemon/conversation-store.ts +24 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +63 -21
- package/src/daemon/conversation.ts +81 -10
- package/src/daemon/external-plugins-bootstrap.ts +231 -185
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +13 -130
- package/src/daemon/handlers/config-slack-channel.ts +25 -10
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +166 -84
- package/src/daemon/history-repair.ts +61 -7
- package/src/daemon/host-app-control-proxy.ts +129 -29
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +79 -70
- package/src/daemon/meet-host-supervisor.ts +20 -19
- package/src/daemon/memory-v2-startup.ts +58 -2
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +37 -9
- package/src/daemon/message-types/messages.ts +70 -1
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +61 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +77 -26
- package/src/daemon/server.ts +34 -20
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +79 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +444 -0
- package/src/heartbeat/heartbeat-run-store.ts +3 -1
- package/src/heartbeat/heartbeat-service.ts +189 -127
- package/src/home/__tests__/feed-types.test.ts +99 -127
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +41 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +2 -3
- package/src/index.ts +18 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +264 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +318 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +211 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +80 -8
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +17 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +368 -22
- package/src/memory/conversation-queries.ts +116 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +20 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +6 -5
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +92 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +45 -6
- package/src/memory/indexer.ts +51 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +86 -15
- package/src/memory/jobs/embed-concept-page.ts +65 -20
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +57 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +324 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +64 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +175 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +107 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +19 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +13 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +36 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +27 -0
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -12
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +726 -18
- package/src/memory/v2/__tests__/migration.test.ts +94 -3
- package/src/memory/v2/__tests__/page-index.test.ts +360 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +309 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +138 -3
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +531 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +445 -11
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -109
- package/src/memory/v2/migration.ts +147 -20
- package/src/memory/v2/page-index.ts +221 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +195 -0
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +234 -93
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +323 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +204 -30
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +4 -3
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +48 -2
- package/src/notifications/home-feed-side-effect.ts +165 -0
- package/src/notifications/signal.ts +8 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +14 -0
- package/src/permissions/ipc-risk-types.ts +3 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +46 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +144 -0
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +55 -6
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +367 -0
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +74 -53
- package/src/plugins/user-loader.ts +85 -43
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +49 -9
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +117 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +72 -154
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +303 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +123 -54
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +170 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +210 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +401 -0
- package/src/providers/inference/resolve-auth.ts +73 -0
- package/src/providers/model-catalog.ts +386 -6
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +151 -159
- package/src/providers/retry.ts +65 -11
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +64 -7
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +311 -9
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +3 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +21 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +268 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +319 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +280 -4
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +70 -3
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +12 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +156 -0
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +233 -0
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +47 -85
- package/src/runtime/routes/conversation-query-routes.ts +350 -97
- package/src/runtime/routes/conversation-routes.ts +121 -21
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +248 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +118 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +42 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +285 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +84 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +361 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +7 -13
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +3 -1
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1097 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +79 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +93 -1
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +117 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +208 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/sequence/engine.ts +38 -40
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +28 -15
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +29 -14
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +14 -6
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +323 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +94 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +94 -5
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +117 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +95 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +46 -5
- package/src/workspace/migrations/types.ts +17 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/context-window-manager.test.ts +0 -2093
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -31,7 +31,7 @@ import type { Provider } from "../../providers/types.js";
|
|
|
31
31
|
import { getLogger } from "../../util/logger.js";
|
|
32
32
|
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
33
33
|
import { enqueueMemoryJob } from "../jobs-store.js";
|
|
34
|
-
import { slugify, writePage } from "./page-store.js";
|
|
34
|
+
import { deletePage, listPages, slugify, writePage } from "./page-store.js";
|
|
35
35
|
import type { ConceptPage } from "./types.js";
|
|
36
36
|
|
|
37
37
|
const log = getLogger("memory-v2-migration");
|
|
@@ -111,6 +111,9 @@ export function gatherV1State(
|
|
|
111
111
|
// domain layer (which v2 will eventually replace). We only need id /
|
|
112
112
|
// content / type / significance / event_date — everything else is unused
|
|
113
113
|
// by the migration.
|
|
114
|
+
// Soft-deleted nodes (`fidelity = 'gone'`) are excluded so deleted memories
|
|
115
|
+
// don't get resurrected into v2 concept pages. The rest of the codebase uses
|
|
116
|
+
// the same filter when reading live graph state.
|
|
114
117
|
const nodeRows = raw
|
|
115
118
|
.query<
|
|
116
119
|
{
|
|
@@ -122,10 +125,12 @@ export function gatherV1State(
|
|
|
122
125
|
},
|
|
123
126
|
[]
|
|
124
127
|
>(
|
|
125
|
-
/*sql*/ `SELECT id, content, type, significance, event_date FROM memory_graph_nodes`,
|
|
128
|
+
/*sql*/ `SELECT id, content, type, significance, event_date FROM memory_graph_nodes WHERE fidelity != 'gone'`,
|
|
126
129
|
)
|
|
127
130
|
.all();
|
|
131
|
+
const liveNodeIds = new Set<string>();
|
|
128
132
|
for (const row of nodeRows) {
|
|
133
|
+
liveNodeIds.add(row.id);
|
|
129
134
|
items.push({
|
|
130
135
|
id: row.id,
|
|
131
136
|
text: row.content,
|
|
@@ -138,16 +143,23 @@ export function gatherV1State(
|
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
// -- Graph edges --
|
|
146
|
+
// Edges with either endpoint pointing at a soft-deleted node are dropped to
|
|
147
|
+
// stay consistent with the node filter above.
|
|
141
148
|
const edgeRows = raw
|
|
142
149
|
.query<
|
|
143
150
|
{ source_node_id: string; target_node_id: string },
|
|
144
151
|
[]
|
|
145
152
|
>(/*sql*/ `SELECT source_node_id, target_node_id FROM memory_graph_edges`)
|
|
146
153
|
.all();
|
|
147
|
-
const edges: V1Edge[] =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
const edges: V1Edge[] = [];
|
|
155
|
+
for (const row of edgeRows) {
|
|
156
|
+
if (!liveNodeIds.has(row.source_node_id)) continue;
|
|
157
|
+
if (!liveNodeIds.has(row.target_node_id)) continue;
|
|
158
|
+
edges.push({
|
|
159
|
+
sourceNodeId: row.source_node_id,
|
|
160
|
+
targetNodeId: row.target_node_id,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
151
163
|
|
|
152
164
|
// -- PKB content --
|
|
153
165
|
const pkbDir = join(workspaceDir, "pkb");
|
|
@@ -234,10 +246,10 @@ export interface Cluster {
|
|
|
234
246
|
/**
|
|
235
247
|
* Group v1 items into proposed concept pages.
|
|
236
248
|
*
|
|
237
|
-
* The heuristic is intentionally simple — embedding-
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
249
|
+
* The heuristic is intentionally simple — embedding-based clustering is a
|
|
250
|
+
* planned follow-up. For the v1-of-v2 cutover, file-based grouping for PKB
|
|
251
|
+
* plus per-graph-node singletons gives a reasonable starting set that the LLM
|
|
252
|
+
* can refine in stage 3:
|
|
241
253
|
*
|
|
242
254
|
* - Each `pkb_topic` file becomes its own cluster (slug derived from
|
|
243
255
|
* filename — that's literally what topic files were already keyed on).
|
|
@@ -333,7 +345,7 @@ export async function synthesizeConceptPage(
|
|
|
333
345
|
|
|
334
346
|
return {
|
|
335
347
|
slug: slugify(cluster.slugHint),
|
|
336
|
-
frontmatter: { edges: [], ref_files: [] },
|
|
348
|
+
frontmatter: { edges: [], ref_files: [], ref_urls: [] },
|
|
337
349
|
body: body.endsWith("\n") ? body : `${body}\n`,
|
|
338
350
|
};
|
|
339
351
|
}
|
|
@@ -447,13 +459,23 @@ export function collapseEdges(
|
|
|
447
459
|
// ---------------------------------------------------------------------------
|
|
448
460
|
|
|
449
461
|
/**
|
|
450
|
-
* Enqueue an `embed_concept_page` job for each newly-written slug. The
|
|
451
|
-
*
|
|
462
|
+
* Enqueue an `embed_concept_page` job for each newly-written slug. The handler
|
|
463
|
+
* is implemented separately — we just stage the queue here so the embeddings
|
|
452
464
|
* are ready by the time activation needs them.
|
|
465
|
+
*
|
|
466
|
+
* `database` is threaded through to `enqueueMemoryJob` as the override DB
|
|
467
|
+
* handle. Without this, jobs would be written to the global `getDb()` instead
|
|
468
|
+
* of the migration's DB — which is wrong for tests, isolated runners, and
|
|
469
|
+
* multi-workspace processes that pass an explicit `database`.
|
|
453
470
|
*/
|
|
454
|
-
export function enqueueEmbeds(slugs: string[]): number {
|
|
471
|
+
export function enqueueEmbeds(slugs: string[], database: DrizzleDb): number {
|
|
455
472
|
for (const slug of slugs) {
|
|
456
|
-
enqueueMemoryJob(
|
|
473
|
+
enqueueMemoryJob(
|
|
474
|
+
"embed_concept_page",
|
|
475
|
+
{ slug },
|
|
476
|
+
undefined,
|
|
477
|
+
database as never,
|
|
478
|
+
);
|
|
457
479
|
}
|
|
458
480
|
return slugs.length;
|
|
459
481
|
}
|
|
@@ -570,15 +592,37 @@ export async function runMemoryV2Migration(
|
|
|
570
592
|
};
|
|
571
593
|
});
|
|
572
594
|
|
|
595
|
+
// On force-rerun, drop pre-existing pages whose slugs aren't produced by
|
|
596
|
+
// this run. `writePage` is an atomic per-slug overwrite, so without this
|
|
597
|
+
// step a force rerun would leave orphan pages on disk from earlier slugs
|
|
598
|
+
// that no longer match any v1 cluster.
|
|
599
|
+
if (force) {
|
|
600
|
+
const newSlugs = new Set(finalizedPages.map((p) => p.slug));
|
|
601
|
+
const existingSlugs = await listPages(workspaceDir);
|
|
602
|
+
await Promise.all(
|
|
603
|
+
existingSlugs
|
|
604
|
+
.filter((slug) => !newSlugs.has(slug))
|
|
605
|
+
.map((slug) => deletePage(workspaceDir, slug)),
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
573
609
|
// Page writes hit different filenames so they're safe to fan out.
|
|
574
610
|
await Promise.all(
|
|
575
611
|
finalizedPages.map((page) => writePage(workspaceDir, page)),
|
|
576
612
|
);
|
|
577
613
|
|
|
578
614
|
const promotions = derivePromotions(items);
|
|
615
|
+
if (force) {
|
|
616
|
+
// Strip any prior migration block so force-reruns re-emit fresh
|
|
617
|
+
// promotions instead of being skipped by the in-file marker guard.
|
|
618
|
+
await stripPromotionMarkerBlocks(workspaceDir);
|
|
619
|
+
}
|
|
579
620
|
await appendPromotions(workspaceDir, promotions);
|
|
580
621
|
|
|
581
|
-
const embedsEnqueued = enqueueEmbeds(
|
|
622
|
+
const embedsEnqueued = enqueueEmbeds(
|
|
623
|
+
finalizedPages.map((p) => p.slug),
|
|
624
|
+
database,
|
|
625
|
+
);
|
|
582
626
|
|
|
583
627
|
await writeSentinel(workspaceDir);
|
|
584
628
|
|
|
@@ -598,10 +642,21 @@ export async function runMemoryV2Migration(
|
|
|
598
642
|
};
|
|
599
643
|
}
|
|
600
644
|
|
|
645
|
+
/**
|
|
646
|
+
* Paired HTML markers wrapped around each appended block. The opening marker
|
|
647
|
+
* also serves as the idempotency guard: `appendLines` is a read-modify-write,
|
|
648
|
+
* and without it a crash between `appendPromotions` and `writeSentinel` would
|
|
649
|
+
* let the next boot duplicate every promotion line. The closing marker
|
|
650
|
+
* delimits the migration-inserted region so a force-rerun strip can remove
|
|
651
|
+
* exactly that block without touching user/assistant edits appended below.
|
|
652
|
+
*/
|
|
653
|
+
const PROMOTION_MARKER_OPEN = "<!-- migration:v1-to-v2 -->";
|
|
654
|
+
const PROMOTION_MARKER_CLOSE = "<!-- /migration:v1-to-v2 -->";
|
|
655
|
+
|
|
601
656
|
/**
|
|
602
657
|
* Append each promotion bucket to its target file. Files are created if
|
|
603
|
-
* absent — the
|
|
604
|
-
*
|
|
658
|
+
* absent — the `060-memory-v2-init` workspace migration seeds empty
|
|
659
|
+
* placeholders, so this is mostly belt-and-suspenders.
|
|
605
660
|
*/
|
|
606
661
|
async function appendPromotions(
|
|
607
662
|
workspaceDir: string,
|
|
@@ -626,7 +681,11 @@ async function appendPromotions(
|
|
|
626
681
|
}
|
|
627
682
|
}
|
|
628
683
|
|
|
629
|
-
/**
|
|
684
|
+
/**
|
|
685
|
+
* Append `lines` to `path`, creating it (with a trailing newline) if absent.
|
|
686
|
+
* If the file already contains `PROMOTION_MARKER_OPEN`, the append is skipped
|
|
687
|
+
* — a prior partially-completed migration already wrote this block.
|
|
688
|
+
*/
|
|
630
689
|
async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
631
690
|
let existing = "";
|
|
632
691
|
try {
|
|
@@ -634,8 +693,76 @@ async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
|
634
693
|
} catch (err) {
|
|
635
694
|
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
636
695
|
}
|
|
696
|
+
if (existing.includes(PROMOTION_MARKER_OPEN)) return;
|
|
637
697
|
const trailing = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
638
|
-
const
|
|
698
|
+
const block = `${PROMOTION_MARKER_OPEN}\n${lines.join("\n")}\n${PROMOTION_MARKER_CLOSE}\n`;
|
|
699
|
+
const next = `${existing}${trailing}${block}`;
|
|
700
|
+
await writeFile(path, next, "utf-8");
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Strip any prior migration-block from each promotion target. Called on
|
|
705
|
+
* force-reruns so the marker guard in `appendLines` doesn't skip the new
|
|
706
|
+
* promotions.
|
|
707
|
+
*/
|
|
708
|
+
async function stripPromotionMarkerBlocks(workspaceDir: string): Promise<void> {
|
|
709
|
+
const memoryDir = join(workspaceDir, "memory");
|
|
710
|
+
const candidates: string[] = [
|
|
711
|
+
join(memoryDir, "essentials.md"),
|
|
712
|
+
join(memoryDir, "threads.md"),
|
|
713
|
+
];
|
|
714
|
+
const archiveDir = join(memoryDir, "archive");
|
|
715
|
+
if (existsSync(archiveDir)) {
|
|
716
|
+
for (const name of readdirSync(archiveDir)) {
|
|
717
|
+
if (name.startsWith("migrated-") && name.endsWith(".md")) {
|
|
718
|
+
candidates.push(join(archiveDir, name));
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
await Promise.all(candidates.map(stripMarkerBlock));
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Remove the migration-inserted block from `path` while preserving content
|
|
727
|
+
* outside it. The block is identified by the
|
|
728
|
+
* `PROMOTION_MARKER_OPEN ... PROMOTION_MARKER_CLOSE` envelope.
|
|
729
|
+
*
|
|
730
|
+
* If an opening marker is present without a matching close, strip from the
|
|
731
|
+
* opening marker to the next blank line, or to EOF if none is found. Content
|
|
732
|
+
* appended after such an unclosed block without a blank-line separator can
|
|
733
|
+
* be dropped on that fallback path.
|
|
734
|
+
*/
|
|
735
|
+
async function stripMarkerBlock(path: string): Promise<void> {
|
|
736
|
+
let existing: string;
|
|
737
|
+
try {
|
|
738
|
+
existing = await readFile(path, "utf-8");
|
|
739
|
+
} catch (err) {
|
|
740
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
741
|
+
throw err;
|
|
742
|
+
}
|
|
743
|
+
const openIdx = existing.indexOf(PROMOTION_MARKER_OPEN);
|
|
744
|
+
if (openIdx === -1) return;
|
|
745
|
+
|
|
746
|
+
let endIdx: number;
|
|
747
|
+
const closeIdx = existing.indexOf(PROMOTION_MARKER_CLOSE, openIdx);
|
|
748
|
+
if (closeIdx !== -1) {
|
|
749
|
+
endIdx = closeIdx + PROMOTION_MARKER_CLOSE.length;
|
|
750
|
+
if (existing[endIdx] === "\n") endIdx += 1;
|
|
751
|
+
} else {
|
|
752
|
+
const blankIdx = existing.indexOf("\n\n", openIdx);
|
|
753
|
+
endIdx = blankIdx === -1 ? existing.length : blankIdx + 2;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const head = existing.slice(0, openIdx).replace(/\n+$/, "");
|
|
757
|
+
const tail = existing.slice(endIdx);
|
|
758
|
+
let next: string;
|
|
759
|
+
if (head.length === 0) {
|
|
760
|
+
next = tail;
|
|
761
|
+
} else if (tail.length === 0) {
|
|
762
|
+
next = `${head}\n`;
|
|
763
|
+
} else {
|
|
764
|
+
next = `${head}\n${tail}`;
|
|
765
|
+
}
|
|
639
766
|
await writeFile(path, next, "utf-8");
|
|
640
767
|
}
|
|
641
768
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v2 — Numbered page index for the router prompt.
|
|
3
|
+
*
|
|
4
|
+
* Renders a compact catalog of every concept page plus every seeded skill
|
|
5
|
+
* entry, sorted by slug ASCII for deterministic IDs, with each entry's
|
|
6
|
+
* outgoing edges resolved to numeric IDs. The router prompt consumes the
|
|
7
|
+
* pre-rendered block to choose which slugs to activate per turn.
|
|
8
|
+
*
|
|
9
|
+
* Skill entries (those in the `skills/<id>` namespace) participate alongside
|
|
10
|
+
* concept pages so the router can reach them through the same mechanism.
|
|
11
|
+
* Skill entries always have `edges: []` — the cross-page edge graph is a
|
|
12
|
+
* concept-page-only construct.
|
|
13
|
+
*
|
|
14
|
+
* The build is cached module-locally per `workspaceDir`, mirroring
|
|
15
|
+
* `edge-index.ts`. Callers must invalidate via `invalidatePageIndex` when
|
|
16
|
+
* concept pages or seeded skill entries change.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { getLogger } from "../../util/logger.js";
|
|
20
|
+
import { listPages, readPage } from "./page-store.js";
|
|
21
|
+
|
|
22
|
+
// Dynamic import for `./skill-store.js` happens inside `getPageIndex` so that
|
|
23
|
+
// modules that only need `invalidatePageIndex` (page-store.ts,
|
|
24
|
+
// tool-side-effects.ts) don't transitively pull in the embedding-backend
|
|
25
|
+
// chain via skill-store. Loading it at call time keeps the invalidation hook
|
|
26
|
+
// cheap and avoids cross-module import cycles in tests that mock jobs-store
|
|
27
|
+
// or embedding-backend.
|
|
28
|
+
|
|
29
|
+
const log = getLogger("memory-v2-page-index");
|
|
30
|
+
|
|
31
|
+
const SUMMARY_MAX_LENGTH = 200;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Collapse every run of whitespace (including embedded newlines and tabs) to a
|
|
35
|
+
* single space and trim. The router prompt renders one entry per line, so an
|
|
36
|
+
* embedded newline anywhere in `summary` would split that entry across lines
|
|
37
|
+
* and corrupt the format the router parses.
|
|
38
|
+
*/
|
|
39
|
+
function normalizeSummary(raw: string): string {
|
|
40
|
+
return raw.replace(/\s+/g, " ").trim().slice(0, SUMMARY_MAX_LENGTH);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* One row in the rendered page index. `id` is a 1-based dense integer that is
|
|
45
|
+
* stable within a single index version (i.e. a single build). It changes when
|
|
46
|
+
* the index is rebuilt because IDs are derived from the slug-sorted position;
|
|
47
|
+
* callers must not persist them across builds.
|
|
48
|
+
*/
|
|
49
|
+
export interface PageIndexEntry {
|
|
50
|
+
/** 1-based dense numeric id, stable within an index version. */
|
|
51
|
+
id: number;
|
|
52
|
+
/** Concept-page slug or `skills/<id>`. */
|
|
53
|
+
slug: string;
|
|
54
|
+
/** Truncated to {@link SUMMARY_MAX_LENGTH} characters. */
|
|
55
|
+
summary: string;
|
|
56
|
+
/** Numeric IDs of outgoing edges, in sorted order. */
|
|
57
|
+
edges: number[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Snapshot of the page index for one workspace. `entries` is sorted by slug
|
|
62
|
+
* ASCII so IDs are deterministic across rebuilds with the same input. The
|
|
63
|
+
* `bySlug` and `byId` maps are convenience lookups; `rendered` is the prompt
|
|
64
|
+
* block consumed by the router.
|
|
65
|
+
*/
|
|
66
|
+
export interface PageIndex {
|
|
67
|
+
entries: PageIndexEntry[];
|
|
68
|
+
bySlug: Map<string, PageIndexEntry>;
|
|
69
|
+
byId: Map<number, PageIndexEntry>;
|
|
70
|
+
rendered: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface CachedIndex {
|
|
74
|
+
workspaceDir: string;
|
|
75
|
+
index: PageIndex;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let cache: CachedIndex | null = null;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Return a `PageIndex` for `workspaceDir`. Cached module-locally; the cache
|
|
82
|
+
* is invalidated by `invalidatePageIndex` (called by daemon-side hooks when
|
|
83
|
+
* concept pages or skill entries change).
|
|
84
|
+
*
|
|
85
|
+
* Cold builds list every concept page in parallel, drop pages whose read
|
|
86
|
+
* rejects, append seeded skill entries from `listSkillEntries()`, sort by
|
|
87
|
+
* slug for deterministic IDs, then resolve outgoing edges to numeric IDs.
|
|
88
|
+
*/
|
|
89
|
+
export async function getPageIndex(workspaceDir: string): Promise<PageIndex> {
|
|
90
|
+
if (cache && cache.workspaceDir === workspaceDir) {
|
|
91
|
+
return cache.index;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const slugs = await listPages(workspaceDir);
|
|
95
|
+
|
|
96
|
+
// Read pages in parallel; pages whose read rejects are dropped with a warn
|
|
97
|
+
// so a single broken page never blocks the rest of the index.
|
|
98
|
+
const settled = await Promise.allSettled(
|
|
99
|
+
slugs.map((slug) => readPage(workspaceDir, slug)),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Intermediate shape used while we still need the raw outgoing slugs to
|
|
103
|
+
// resolve into numeric IDs after sorting.
|
|
104
|
+
interface DraftEntry {
|
|
105
|
+
slug: string;
|
|
106
|
+
summary: string;
|
|
107
|
+
outgoingSlugs: string[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const { listSkillEntries, SKILL_SLUG_PREFIX } =
|
|
111
|
+
await import("./skill-store.js");
|
|
112
|
+
|
|
113
|
+
// Build the skill-slug set first so we can drop colliding concept pages.
|
|
114
|
+
// Collision policy: **skill entries win**. Skill rows are seeded from the
|
|
115
|
+
// curated catalog and the router needs them to be reachable under their
|
|
116
|
+
// canonical slugs; a hand-authored page sitting under `skills/<id>` is
|
|
117
|
+
// either a stale leftover from a prior write or a user mistake. `bySlug`
|
|
118
|
+
// is last-writer-wins, so without explicit dedupe one side would silently
|
|
119
|
+
// shadow the other depending on iteration order.
|
|
120
|
+
const skillEntries = listSkillEntries();
|
|
121
|
+
const skillSlugs = new Set(
|
|
122
|
+
skillEntries.map((entry) => `${SKILL_SLUG_PREFIX}${entry.id}`),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const drafts: DraftEntry[] = [];
|
|
126
|
+
for (let i = 0; i < settled.length; i++) {
|
|
127
|
+
const result = settled[i];
|
|
128
|
+
const slug = slugs[i];
|
|
129
|
+
if (result.status === "rejected") {
|
|
130
|
+
log.warn(
|
|
131
|
+
{ slug, err: result.reason },
|
|
132
|
+
"Dropping concept page from index — read failed",
|
|
133
|
+
);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const page = result.value;
|
|
137
|
+
if (!page) continue;
|
|
138
|
+
if (skillSlugs.has(slug)) {
|
|
139
|
+
log.warn(
|
|
140
|
+
{ slug },
|
|
141
|
+
"Dropping concept page from index — slug collides with a seeded skill entry; skill wins",
|
|
142
|
+
);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const summarySource = page.frontmatter.summary?.trim() || page.body.trim();
|
|
146
|
+
drafts.push({
|
|
147
|
+
slug,
|
|
148
|
+
summary: normalizeSummary(summarySource),
|
|
149
|
+
outgoingSlugs: page.frontmatter.edges,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
for (const entry of skillEntries) {
|
|
154
|
+
drafts.push({
|
|
155
|
+
slug: `${SKILL_SLUG_PREFIX}${entry.id}`,
|
|
156
|
+
summary: normalizeSummary(entry.content),
|
|
157
|
+
outgoingSlugs: [],
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
drafts.sort((a, b) => (a.slug < b.slug ? -1 : a.slug > b.slug ? 1 : 0));
|
|
162
|
+
|
|
163
|
+
// Assign 1-based dense IDs in sort order so entries[i].id === i + 1.
|
|
164
|
+
const bySlug = new Map<string, PageIndexEntry>();
|
|
165
|
+
const byId = new Map<number, PageIndexEntry>();
|
|
166
|
+
const entries: PageIndexEntry[] = drafts.map((draft, i) => {
|
|
167
|
+
const entry: PageIndexEntry = {
|
|
168
|
+
id: i + 1,
|
|
169
|
+
slug: draft.slug,
|
|
170
|
+
summary: draft.summary,
|
|
171
|
+
edges: [],
|
|
172
|
+
};
|
|
173
|
+
bySlug.set(entry.slug, entry);
|
|
174
|
+
byId.set(entry.id, entry);
|
|
175
|
+
return entry;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Edges whose target slug isn't in the index are dropped silently — the
|
|
179
|
+
// frontmatter sweep is responsible for surfacing those as warnings.
|
|
180
|
+
for (let i = 0; i < entries.length; i++) {
|
|
181
|
+
const draft = drafts[i];
|
|
182
|
+
const resolved: number[] = [];
|
|
183
|
+
for (const targetSlug of draft.outgoingSlugs) {
|
|
184
|
+
const target = bySlug.get(targetSlug);
|
|
185
|
+
if (target) resolved.push(target.id);
|
|
186
|
+
}
|
|
187
|
+
resolved.sort((a, b) => a - b);
|
|
188
|
+
entries[i].edges = resolved;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const rendered = renderIndex(entries);
|
|
192
|
+
const index: PageIndex = { entries, bySlug, byId, rendered };
|
|
193
|
+
cache = { workspaceDir, index };
|
|
194
|
+
return index;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Clear the cached index. Pass `workspaceDir` to scope invalidation to a
|
|
199
|
+
* specific cache entry; omit it to clear unconditionally.
|
|
200
|
+
*/
|
|
201
|
+
export function invalidatePageIndex(workspaceDir?: string): void {
|
|
202
|
+
if (!cache) return;
|
|
203
|
+
if (workspaceDir === undefined || cache.workspaceDir === workspaceDir) {
|
|
204
|
+
cache = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Render the prompt block: one line per entry shaped
|
|
210
|
+
* `[id] slug — summary (edges: a, b, c)`. Lines without outgoing edges drop
|
|
211
|
+
* the parenthetical entirely. Trailing newline so the block can be
|
|
212
|
+
* concatenated into a larger prompt without manual padding.
|
|
213
|
+
*/
|
|
214
|
+
function renderIndex(entries: readonly PageIndexEntry[]): string {
|
|
215
|
+
const lines = entries.map((entry) => {
|
|
216
|
+
const head = `[${entry.id}] ${entry.slug} — ${entry.summary}`;
|
|
217
|
+
if (entry.edges.length === 0) return head;
|
|
218
|
+
return `${head} (edges: ${entry.edges.join(", ")})`;
|
|
219
|
+
});
|
|
220
|
+
return lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
221
|
+
}
|
|
@@ -33,6 +33,7 @@ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
|
33
33
|
|
|
34
34
|
import { FRONTMATTER_REGEX } from "../../skills/frontmatter.js";
|
|
35
35
|
import { invalidateEdgeIndex } from "./edge-index.js";
|
|
36
|
+
import { invalidatePageIndex } from "./page-index.js";
|
|
36
37
|
import { type ConceptPage, ConceptPageFrontmatterSchema } from "./types.js";
|
|
37
38
|
|
|
38
39
|
/** Filename suffix for concept pages. */
|
|
@@ -287,6 +288,7 @@ export async function writePage(
|
|
|
287
288
|
throw err;
|
|
288
289
|
}
|
|
289
290
|
invalidateEdgeIndex(workspaceDir);
|
|
291
|
+
invalidatePageIndex(workspaceDir);
|
|
290
292
|
}
|
|
291
293
|
|
|
292
294
|
/**
|
|
@@ -397,6 +399,7 @@ export async function deletePage(
|
|
|
397
399
|
throw err;
|
|
398
400
|
}
|
|
399
401
|
invalidateEdgeIndex(workspaceDir);
|
|
402
|
+
invalidatePageIndex(workspaceDir);
|
|
400
403
|
}
|
|
401
404
|
|
|
402
405
|
/**
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* runs with its full system prompt + tool surface; the text below is supplied
|
|
7
7
|
* as the wake hint.
|
|
8
8
|
*
|
|
9
|
-
* The single placeholder `{{CUTOFF}}` is substituted at runtime with
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
9
|
+
* The single placeholder `{{CUTOFF}}` is substituted at runtime with a
|
|
10
|
+
* timestamp captured at job dispatch in the same `Mon D, h:mm AM/PM` shape
|
|
11
|
+
* that `buffer.md` entries use, so the agent's "timestamp ≥ cutoff" check
|
|
12
|
+
* compares like-with-like. Anything appended after that minute is the next
|
|
13
|
+
* pass's problem.
|
|
12
14
|
*
|
|
13
15
|
* Kept under `prompts/` rather than inlined in `consolidation-job.ts` so the
|
|
14
16
|
* prompt body is reviewable on its own and the job module stays focused on
|
|
@@ -432,10 +434,10 @@ For each article you touched:
|
|
|
432
434
|
This is the engine that decides who you are tomorrow. Be ORGANIZED. Care, judgment, voice. Your voice. Your wiki.`;
|
|
433
435
|
|
|
434
436
|
/**
|
|
435
|
-
* Resolve `CONSOLIDATION_PROMPT` with `{{CUTOFF}}` substituted. The
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
437
|
+
* Resolve `CONSOLIDATION_PROMPT` with `{{CUTOFF}}` substituted. The prompt
|
|
438
|
+
* treats the cutoff as opaque text — callers pass a `Mon D, h:mm AM/PM`
|
|
439
|
+
* timestamp matching the `buffer.md` entry format so the agent compares
|
|
440
|
+
* like-with-like.
|
|
439
441
|
*/
|
|
440
442
|
export function renderConsolidationPrompt(cutoff: string): string {
|
|
441
443
|
return CONSOLIDATION_PROMPT.replaceAll(CUTOFF_PLACEHOLDER, cutoff);
|