@vellumai/assistant 0.10.1 → 0.10.2-dev.202606241651.2d2b40d
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/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/openapi.yaml +74 -1
- package/package.json +1 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-guardian.test.ts +94 -58
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/computer-use-tools.test.ts +13 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/contacts-relay-reads.test.ts +13 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +65 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +10 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +75 -10
- package/src/__tests__/guardian-dispatch.test.ts +95 -1
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +1 -7
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-proxy.test.ts +299 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +167 -8
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +43 -0
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +189 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-bootstrap.test.ts +3 -73
- package/src/__tests__/plugin-route-contribution.test.ts +4 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -18
- package/src/__tests__/plugin-types.test.ts +0 -2
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +694 -25
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +2 -0
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +56 -0
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +262 -4
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +17 -1
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +167 -50
- package/src/calls/relay-setup-router.ts +37 -7
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +75 -3
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -1
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/loader.ts +36 -5
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +14 -5
- package/src/config/skills.ts +27 -5
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/daemon/conversation-agent-loop.ts +9 -0
- package/src/daemon/conversation-process.ts +39 -17
- package/src/daemon/conversation-surfaces.ts +8 -0
- package/src/daemon/conversation-tool-setup.ts +49 -16
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +4 -34
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -0
- package/src/daemon/handlers/__tests__/config-channels.test.ts +225 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +78 -22
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/host-cu-proxy.ts +102 -11
- package/src/daemon/lifecycle.ts +4 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/conversation-crud.ts +38 -0
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +36 -502
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +58 -0
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +9 -8
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -27
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +130 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +90 -6
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +101 -66
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +573 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/emit-signal.ts +39 -14
- package/src/onboarding/checkin-event.test.ts +220 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +3 -5
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +161 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +110 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +10 -11
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +12 -20
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/mtime-cache.ts +7 -2
- package/src/plugins/types.ts +0 -2
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +4 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/retry.ts +4 -0
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +4 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +335 -3
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/invite-redemption-service.ts +50 -18
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +212 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +93 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +215 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +8 -32
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-routes.ts +74 -81
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -49
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +51 -55
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +7 -9
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +85 -9
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/computer-use/definitions.ts +8 -2
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +18 -0
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/types.ts +17 -2
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/platform.ts +5 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `assistant memory worker` CLI subgroup.
|
|
3
|
+
*
|
|
4
|
+
* Validates:
|
|
5
|
+
* - Subcommand registration (start, stop, status) under `memory worker`.
|
|
6
|
+
* - `status` reports running/not_running via PID-file liveness.
|
|
7
|
+
* - `stop` sends SIGTERM to a live worker and errors when none is running.
|
|
8
|
+
* - `start` refuses to spawn when a worker is already running, and reports
|
|
9
|
+
* the PID once the spawned process writes its PID file.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
16
|
+
|
|
17
|
+
import { Command } from "commander";
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Mock state
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
let tmpDir: string;
|
|
24
|
+
let pidPath: string;
|
|
25
|
+
let logOutput: string[] = [];
|
|
26
|
+
|
|
27
|
+
/** Records (pid, signal) pairs passed to the mocked process.kill. */
|
|
28
|
+
let killCalls: Array<{ pid: number; signal: string | number }> = [];
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Mocks
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
mock.module("../../../../util/platform.js", () => ({
|
|
35
|
+
getMemoryWorkerPidPath: () => pidPath,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const capture = (...args: unknown[]) => {
|
|
39
|
+
logOutput.push(args.map(String).join(" "));
|
|
40
|
+
};
|
|
41
|
+
const fakeLogger = {
|
|
42
|
+
info: capture,
|
|
43
|
+
warn: capture,
|
|
44
|
+
error: capture,
|
|
45
|
+
debug: () => {},
|
|
46
|
+
};
|
|
47
|
+
mock.module("../../../../util/logger.js", () => ({
|
|
48
|
+
getLogger: () => fakeLogger,
|
|
49
|
+
getCliLogger: () => fakeLogger,
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Import module under test (after mocks)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
const { registerMemoryWorkerCommand } = await import("../worker.js");
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Test helpers
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
function buildProgram(): Command {
|
|
63
|
+
const program = new Command();
|
|
64
|
+
program.exitOverride();
|
|
65
|
+
program.configureOutput({
|
|
66
|
+
writeErr: () => {},
|
|
67
|
+
writeOut: () => {},
|
|
68
|
+
});
|
|
69
|
+
const memory = program.command("memory");
|
|
70
|
+
registerMemoryWorkerCommand(memory);
|
|
71
|
+
return program;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function runCommand(
|
|
75
|
+
args: string[],
|
|
76
|
+
): Promise<{ stdout: string; exitCode: number }> {
|
|
77
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
78
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
79
|
+
const stdoutChunks: string[] = [];
|
|
80
|
+
|
|
81
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
82
|
+
stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
|
|
83
|
+
return true;
|
|
84
|
+
}) as typeof process.stdout.write;
|
|
85
|
+
|
|
86
|
+
process.stderr.write = (() => true) as typeof process.stderr.write;
|
|
87
|
+
|
|
88
|
+
process.exitCode = 0;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const program = buildProgram();
|
|
92
|
+
await program.parseAsync(["node", "assistant", ...args]);
|
|
93
|
+
} catch {
|
|
94
|
+
if (process.exitCode === 0) process.exitCode = 1;
|
|
95
|
+
} finally {
|
|
96
|
+
process.stdout.write = originalStdoutWrite;
|
|
97
|
+
process.stderr.write = originalStderrWrite;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const exitCode = process.exitCode ?? 0;
|
|
101
|
+
process.exitCode = 0;
|
|
102
|
+
|
|
103
|
+
return { exitCode, stdout: stdoutChunks.join("") };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Replace process.kill with a recording stub. `signal 0` is the liveness
|
|
108
|
+
* probe: it resolves for `livePids` and throws ESRCH otherwise. Other signals
|
|
109
|
+
* are recorded and no-oped so the test runner is never actually signalled.
|
|
110
|
+
*/
|
|
111
|
+
function stubProcessKill(livePids: Set<number>): () => void {
|
|
112
|
+
const original = process.kill.bind(process);
|
|
113
|
+
killCalls = [];
|
|
114
|
+
process.kill = ((pid: number, signal?: string | number) => {
|
|
115
|
+
const sig = signal ?? 0;
|
|
116
|
+
if (sig === 0) {
|
|
117
|
+
if (livePids.has(pid)) return true;
|
|
118
|
+
const err = new Error("kill ESRCH") as NodeJS.ErrnoException;
|
|
119
|
+
err.code = "ESRCH";
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
killCalls.push({ pid, signal: sig });
|
|
123
|
+
return true;
|
|
124
|
+
}) as typeof process.kill;
|
|
125
|
+
return () => {
|
|
126
|
+
process.kill = original;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Setup
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
tmpDir = mkdtempSync(join(tmpdir(), "memory-worker-test-"));
|
|
136
|
+
pidPath = join(tmpDir, "memory-worker.pid");
|
|
137
|
+
logOutput = [];
|
|
138
|
+
killCalls = [];
|
|
139
|
+
process.exitCode = 0;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
afterEach(() => {
|
|
143
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// Subcommand registration
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
describe("subcommand registration", () => {
|
|
151
|
+
test("registers worker under memory with start/stop/status", () => {
|
|
152
|
+
const program = buildProgram();
|
|
153
|
+
const memory = program.commands.find((c) => c.name() === "memory");
|
|
154
|
+
expect(memory).toBeDefined();
|
|
155
|
+
const worker = memory!.commands.find((c) => c.name() === "worker");
|
|
156
|
+
expect(worker).toBeDefined();
|
|
157
|
+
const subcommandNames = worker!.commands.map((c) => c.name()).sort();
|
|
158
|
+
expect(subcommandNames).toEqual(["start", "status", "stop"]);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// status
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
describe("memory worker status", () => {
|
|
167
|
+
test("reports not_running when no PID file exists", async () => {
|
|
168
|
+
const { exitCode, stdout } = await runCommand([
|
|
169
|
+
"memory",
|
|
170
|
+
"worker",
|
|
171
|
+
"status",
|
|
172
|
+
"--json",
|
|
173
|
+
]);
|
|
174
|
+
expect(exitCode).toBe(0);
|
|
175
|
+
expect(JSON.parse(stdout)).toEqual({ status: "not_running" });
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("reports running when PID file points at a live process", async () => {
|
|
179
|
+
writeFileSync(pidPath, String(process.pid));
|
|
180
|
+
const restore = stubProcessKill(new Set([process.pid]));
|
|
181
|
+
try {
|
|
182
|
+
const { exitCode, stdout } = await runCommand([
|
|
183
|
+
"memory",
|
|
184
|
+
"worker",
|
|
185
|
+
"status",
|
|
186
|
+
"--json",
|
|
187
|
+
]);
|
|
188
|
+
expect(exitCode).toBe(0);
|
|
189
|
+
expect(JSON.parse(stdout)).toEqual({
|
|
190
|
+
status: "running",
|
|
191
|
+
pid: process.pid,
|
|
192
|
+
});
|
|
193
|
+
} finally {
|
|
194
|
+
restore();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("treats a stale PID file as not_running and cleans it up", async () => {
|
|
199
|
+
writeFileSync(pidPath, "999999");
|
|
200
|
+
const restore = stubProcessKill(new Set());
|
|
201
|
+
try {
|
|
202
|
+
const { exitCode, stdout } = await runCommand([
|
|
203
|
+
"memory",
|
|
204
|
+
"worker",
|
|
205
|
+
"status",
|
|
206
|
+
"--json",
|
|
207
|
+
]);
|
|
208
|
+
expect(exitCode).toBe(0);
|
|
209
|
+
expect(JSON.parse(stdout)).toEqual({ status: "not_running" });
|
|
210
|
+
expect(existsSync(pidPath)).toBe(false);
|
|
211
|
+
} finally {
|
|
212
|
+
restore();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// stop
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
describe("memory worker stop", () => {
|
|
222
|
+
test("errors with exit 1 when no worker is running", async () => {
|
|
223
|
+
const { exitCode, stdout } = await runCommand([
|
|
224
|
+
"memory",
|
|
225
|
+
"worker",
|
|
226
|
+
"stop",
|
|
227
|
+
"--json",
|
|
228
|
+
]);
|
|
229
|
+
expect(exitCode).toBe(1);
|
|
230
|
+
expect(JSON.parse(stdout)).toMatchObject({ ok: false });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("sends SIGTERM to a running worker", async () => {
|
|
234
|
+
writeFileSync(pidPath, String(process.pid));
|
|
235
|
+
const restore = stubProcessKill(new Set([process.pid]));
|
|
236
|
+
try {
|
|
237
|
+
const { exitCode, stdout } = await runCommand([
|
|
238
|
+
"memory",
|
|
239
|
+
"worker",
|
|
240
|
+
"stop",
|
|
241
|
+
"--json",
|
|
242
|
+
]);
|
|
243
|
+
expect(exitCode).toBe(0);
|
|
244
|
+
expect(JSON.parse(stdout)).toEqual({ ok: true, pid: process.pid });
|
|
245
|
+
expect(killCalls).toContainEqual({
|
|
246
|
+
pid: process.pid,
|
|
247
|
+
signal: "SIGTERM",
|
|
248
|
+
});
|
|
249
|
+
} finally {
|
|
250
|
+
restore();
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// start
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
describe("memory worker start", () => {
|
|
260
|
+
test("refuses to start when a worker is already running", async () => {
|
|
261
|
+
writeFileSync(pidPath, String(process.pid));
|
|
262
|
+
const restore = stubProcessKill(new Set([process.pid]));
|
|
263
|
+
try {
|
|
264
|
+
const { exitCode, stdout } = await runCommand([
|
|
265
|
+
"memory",
|
|
266
|
+
"worker",
|
|
267
|
+
"start",
|
|
268
|
+
"--json",
|
|
269
|
+
]);
|
|
270
|
+
expect(exitCode).toBe(1);
|
|
271
|
+
expect(JSON.parse(stdout)).toMatchObject({
|
|
272
|
+
ok: false,
|
|
273
|
+
pid: process.pid,
|
|
274
|
+
});
|
|
275
|
+
} finally {
|
|
276
|
+
restore();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("spawns the worker and reports the PID it writes", async () => {
|
|
281
|
+
const restore = stubProcessKill(new Set());
|
|
282
|
+
const originalSpawn = Bun.spawn;
|
|
283
|
+
// Simulate the spawned worker writing its PID file on startup.
|
|
284
|
+
(Bun as { spawn: typeof Bun.spawn }).spawn = (() => {
|
|
285
|
+
writeFileSync(pidPath, "424242");
|
|
286
|
+
return { unref: () => {}, pid: 424242 };
|
|
287
|
+
}) as unknown as typeof Bun.spawn;
|
|
288
|
+
try {
|
|
289
|
+
const { exitCode, stdout } = await runCommand([
|
|
290
|
+
"memory",
|
|
291
|
+
"worker",
|
|
292
|
+
"start",
|
|
293
|
+
"--json",
|
|
294
|
+
]);
|
|
295
|
+
expect(exitCode).toBe(0);
|
|
296
|
+
expect(JSON.parse(stdout)).toMatchObject({ ok: true, pid: 424242 });
|
|
297
|
+
} finally {
|
|
298
|
+
(Bun as { spawn: typeof Bun.spawn }).spawn = originalSpawn;
|
|
299
|
+
restore();
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
});
|
|
@@ -4,6 +4,7 @@ import { registerCommand } from "../../lib/register-command.js";
|
|
|
4
4
|
import { registerMemoryRetrospectiveCommand } from "./memory-retrospective.js";
|
|
5
5
|
import { registerMemoryV2Command } from "./memory-v2.js";
|
|
6
6
|
import { registerMemoryV3Command } from "./memory-v3.js";
|
|
7
|
+
import { registerMemoryWorkerCommand } from "./worker.js";
|
|
7
8
|
|
|
8
9
|
export function registerMemoryCommand(program: Command): void {
|
|
9
10
|
registerCommand(program, {
|
|
@@ -27,6 +28,7 @@ Examples:
|
|
|
27
28
|
registerMemoryV2Command(memory);
|
|
28
29
|
registerMemoryV3Command(memory);
|
|
29
30
|
registerMemoryRetrospectiveCommand(memory);
|
|
31
|
+
registerMemoryWorkerCommand(memory);
|
|
30
32
|
},
|
|
31
33
|
});
|
|
32
34
|
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assistant memory worker` CLI subgroup.
|
|
3
|
+
*
|
|
4
|
+
* Manages the memory jobs worker as its own OS process — separate from the
|
|
5
|
+
* daemon's main event loop. This prevents long-running embedding jobs from
|
|
6
|
+
* blocking user-facing HTTP traffic.
|
|
7
|
+
*
|
|
8
|
+
* Subcommands:
|
|
9
|
+
*
|
|
10
|
+
* - `start` — spawn the worker process (detached, background).
|
|
11
|
+
* - `stop` — send SIGTERM to the running worker process.
|
|
12
|
+
* - `status` — report whether the worker process is running.
|
|
13
|
+
*
|
|
14
|
+
* All three run directly in the CLI process (transport: "local") — no IPC
|
|
15
|
+
* round-trip to the daemon.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Command } from "commander";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
probeMemoryWorker,
|
|
22
|
+
spawnMemoryWorkerProcess,
|
|
23
|
+
} from "../../../memory/worker-control.js";
|
|
24
|
+
import { getMemoryWorkerPidPath } from "../../../util/platform.js";
|
|
25
|
+
import { registerCommand } from "../../lib/register-command.js";
|
|
26
|
+
import { log } from "../../logger.js";
|
|
27
|
+
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// `start`
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
async function startWorker(
|
|
34
|
+
opts: { json?: boolean },
|
|
35
|
+
cmd: Command,
|
|
36
|
+
): Promise<void> {
|
|
37
|
+
let result: { pid: number; alreadyRunning: boolean };
|
|
38
|
+
try {
|
|
39
|
+
result = await spawnMemoryWorkerProcess();
|
|
40
|
+
} catch (err) {
|
|
41
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
42
|
+
if (shouldOutputJson(cmd)) {
|
|
43
|
+
writeOutput(cmd, { ok: false, error: msg });
|
|
44
|
+
} else {
|
|
45
|
+
log.error(msg);
|
|
46
|
+
}
|
|
47
|
+
process.exitCode = 1;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (result.alreadyRunning) {
|
|
52
|
+
const msg = `Memory worker is already running (PID ${result.pid})`;
|
|
53
|
+
if (shouldOutputJson(cmd)) {
|
|
54
|
+
writeOutput(cmd, { ok: false, error: msg, pid: result.pid });
|
|
55
|
+
} else {
|
|
56
|
+
log.error(msg);
|
|
57
|
+
}
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (shouldOutputJson(cmd)) {
|
|
63
|
+
writeOutput(cmd, {
|
|
64
|
+
ok: true,
|
|
65
|
+
pid: result.pid,
|
|
66
|
+
pidPath: getMemoryWorkerPidPath(),
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
log.info(`Memory worker started (PID ${result.pid})`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// `stop`
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
function stopWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
78
|
+
const current = probeMemoryWorker();
|
|
79
|
+
if (current.status !== "running" || current.pid == null) {
|
|
80
|
+
const msg = "Memory worker is not running";
|
|
81
|
+
if (shouldOutputJson(cmd)) {
|
|
82
|
+
writeOutput(cmd, { ok: false, error: msg });
|
|
83
|
+
} else {
|
|
84
|
+
log.error(msg);
|
|
85
|
+
}
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const pid = current.pid;
|
|
91
|
+
try {
|
|
92
|
+
process.kill(pid, "SIGTERM");
|
|
93
|
+
} catch (err) {
|
|
94
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
95
|
+
if (shouldOutputJson(cmd)) {
|
|
96
|
+
writeOutput(cmd, { ok: false, error: msg, pid });
|
|
97
|
+
} else {
|
|
98
|
+
log.error(`Failed to stop memory worker (PID ${pid}): ${msg}`);
|
|
99
|
+
}
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (shouldOutputJson(cmd)) {
|
|
105
|
+
writeOutput(cmd, { ok: true, pid });
|
|
106
|
+
} else {
|
|
107
|
+
log.info(`Memory worker stop signal sent (PID ${pid})`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// `status`
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
function statusWorker(opts: { json?: boolean }, cmd: Command): void {
|
|
116
|
+
const result = probeMemoryWorker();
|
|
117
|
+
if (shouldOutputJson(cmd)) {
|
|
118
|
+
writeOutput(cmd, result);
|
|
119
|
+
} else {
|
|
120
|
+
if (result.status === "running") {
|
|
121
|
+
log.info(`Memory worker is running (PID ${result.pid})`);
|
|
122
|
+
} else {
|
|
123
|
+
log.info("Memory worker is not running");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Registration
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
export function registerMemoryWorkerCommand(memory: Command): void {
|
|
133
|
+
registerCommand(memory, {
|
|
134
|
+
name: "worker",
|
|
135
|
+
transport: "local",
|
|
136
|
+
description: "Manage the memory jobs worker process (start/stop/status)",
|
|
137
|
+
build: (worker) => {
|
|
138
|
+
worker.addHelpText(
|
|
139
|
+
"after",
|
|
140
|
+
`
|
|
141
|
+
The memory worker processes embedding, consolidation, and cleanup jobs in a
|
|
142
|
+
separate OS process so they do not block the daemon's main event loop.
|
|
143
|
+
|
|
144
|
+
Examples:
|
|
145
|
+
$ assistant memory worker start
|
|
146
|
+
$ assistant memory worker status
|
|
147
|
+
$ assistant memory worker stop`,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
worker
|
|
151
|
+
.command("start")
|
|
152
|
+
.description("Start the memory worker as a background process")
|
|
153
|
+
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
154
|
+
.action(async (opts: { json?: boolean }, cmd: Command) => {
|
|
155
|
+
await startWorker(opts, cmd);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
worker
|
|
159
|
+
.command("stop")
|
|
160
|
+
.description("Stop the running memory worker process")
|
|
161
|
+
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
162
|
+
.action((opts: { json?: boolean }, cmd: Command) => {
|
|
163
|
+
stopWorker(opts, cmd);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
worker
|
|
167
|
+
.command("status")
|
|
168
|
+
.description("Check whether the memory worker process is running")
|
|
169
|
+
.option("--json", "Emit raw JSON instead of a formatted summary")
|
|
170
|
+
.action((opts: { json?: boolean }, cmd: Command) => {
|
|
171
|
+
statusWorker(opts, cmd);
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
@@ -29,7 +29,11 @@ import {
|
|
|
29
29
|
PluginAlreadyInstalledError,
|
|
30
30
|
PluginNotFoundError,
|
|
31
31
|
} from "../lib/install-from-github.js";
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
type AllPluginInfo,
|
|
34
|
+
listAllPlugins,
|
|
35
|
+
listInstalledPlugins,
|
|
36
|
+
} from "../lib/list-installed-plugins.js";
|
|
33
37
|
import type { FingerprintComparison } from "../lib/plugin-fingerprint.js";
|
|
34
38
|
import {
|
|
35
39
|
DEFAULT_PIN_HISTORY_LIMIT,
|
|
@@ -85,6 +89,8 @@ Examples:
|
|
|
85
89
|
$ assistant plugins install example --pin <sha> --force
|
|
86
90
|
$ assistant plugins list
|
|
87
91
|
$ assistant plugins list --json
|
|
92
|
+
$ assistant plugins list --all
|
|
93
|
+
$ assistant plugins list --all --json
|
|
88
94
|
$ assistant plugins inspect example
|
|
89
95
|
$ assistant plugins inspect example --json
|
|
90
96
|
$ assistant plugins diff example
|
|
@@ -239,9 +245,63 @@ Examples:
|
|
|
239
245
|
|
|
240
246
|
plugins
|
|
241
247
|
.command("list")
|
|
242
|
-
.description(
|
|
248
|
+
.description(
|
|
249
|
+
"List plugins installed in your workspace.",
|
|
250
|
+
)
|
|
243
251
|
.option("--json", "Emit machine-readable JSON instead of a table")
|
|
244
|
-
.
|
|
252
|
+
.option(
|
|
253
|
+
"--all",
|
|
254
|
+
"Include first-party default plugins and disabled plugins in the listing",
|
|
255
|
+
)
|
|
256
|
+
.action((opts: { json?: boolean; all?: boolean }) => {
|
|
257
|
+
if (opts.all) {
|
|
258
|
+
const all = listAllPlugins();
|
|
259
|
+
|
|
260
|
+
if (opts.json) {
|
|
261
|
+
process.stdout.write(JSON.stringify(all, null, 2) + "\n");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (all.length === 0) {
|
|
266
|
+
console.log("No plugins found.");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const rows = all.map((p) => ({
|
|
271
|
+
name: p.name,
|
|
272
|
+
version: p.packageJson?.version ?? "—",
|
|
273
|
+
source: p.source,
|
|
274
|
+
status: formatAllPluginStatus(p),
|
|
275
|
+
}));
|
|
276
|
+
const nameW = Math.max(4, ...rows.map((r) => r.name.length));
|
|
277
|
+
const versionW = Math.max(7, ...rows.map((r) => r.version.length));
|
|
278
|
+
const sourceW = Math.max(6, ...rows.map((r) => r.source.length));
|
|
279
|
+
const pad = (s: string, w: number) =>
|
|
280
|
+
s + " ".repeat(w - s.length);
|
|
281
|
+
console.log(
|
|
282
|
+
`${pad("NAME", nameW)} ${pad("VERSION", versionW)} ${pad("SOURCE", sourceW)} STATUS`,
|
|
283
|
+
);
|
|
284
|
+
for (const r of rows) {
|
|
285
|
+
console.log(
|
|
286
|
+
`${pad(r.name, nameW)} ${pad(r.version, versionW)} ${pad(r.source, sourceW)} ${r.status}`,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const userCount = all.filter((p) => p.source === "user").length;
|
|
291
|
+
const defaultCount = all.length - userCount;
|
|
292
|
+
const disabledCount = all.filter((p) => p.disabled).length;
|
|
293
|
+
console.log("");
|
|
294
|
+
console.log(
|
|
295
|
+
`${all.length} plugin${all.length === 1 ? "" : "s"} ` +
|
|
296
|
+
`(${userCount} user, ${defaultCount} default` +
|
|
297
|
+
(disabledCount > 0
|
|
298
|
+
? `, ${disabledCount} disabled`
|
|
299
|
+
: "") +
|
|
300
|
+
`).`,
|
|
301
|
+
);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
245
305
|
const installed = listInstalledPlugins();
|
|
246
306
|
|
|
247
307
|
if (opts.json) {
|
|
@@ -757,6 +817,18 @@ function formatTimestamp(iso: string | null): string {
|
|
|
757
817
|
return new Date(ms).toISOString().slice(0, 19);
|
|
758
818
|
}
|
|
759
819
|
|
|
820
|
+
/**
|
|
821
|
+
* Build a human-readable status string for a plugin in the `--all` listing.
|
|
822
|
+
* Combines disabled state with any structural issues.
|
|
823
|
+
*/
|
|
824
|
+
function formatAllPluginStatus(p: AllPluginInfo): string {
|
|
825
|
+
const parts: string[] = [];
|
|
826
|
+
if (p.disabled) parts.push("disabled");
|
|
827
|
+
if (p.issues.length > 0) parts.push(p.issues.join("; "));
|
|
828
|
+
if (parts.length === 0) parts.push("enabled");
|
|
829
|
+
return parts.join(", ");
|
|
830
|
+
}
|
|
831
|
+
|
|
760
832
|
/** Human-readable status line for an inspection result. The from/to revisions
|
|
761
833
|
* now live in the installed/remote blocks, so the status itself is just words. */
|
|
762
834
|
function statusLine(status: PluginInspection["status"]): string {
|