@vellumai/assistant 0.6.5 → 0.6.6
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 +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
import { recordRequestLog } from "../memory/llm-request-log-store.js";
|
|
2
|
-
import {
|
|
3
|
-
extractText,
|
|
4
|
-
getConfiguredProvider,
|
|
5
|
-
userMessage,
|
|
6
|
-
} from "../providers/provider-send-message.js";
|
|
7
|
-
import type {
|
|
8
|
-
WatchObservationEntry,
|
|
9
|
-
WatchSession,
|
|
10
|
-
} from "../tools/watch/watch-state.js";
|
|
11
|
-
import {
|
|
12
|
-
addObservation,
|
|
13
|
-
fireWatchCommentaryNotifier,
|
|
14
|
-
fireWatchCompletionNotifier,
|
|
15
|
-
watchSessions,
|
|
16
|
-
} from "../tools/watch/watch-state.js";
|
|
17
|
-
import { getLogger } from "../util/logger.js";
|
|
18
|
-
import type { HandlerContext } from "./handlers/shared.js";
|
|
19
|
-
import type { WatchObservation } from "./message-protocol.js";
|
|
20
|
-
|
|
21
|
-
const log = getLogger("watch-handler");
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Module-level maps to store commentary/summary text (and associated LLM log
|
|
25
|
-
* IDs) so that session notifier callbacks can retrieve them from the
|
|
26
|
-
* WatchSession's conversationId and link logs to the persisted message.
|
|
27
|
-
*/
|
|
28
|
-
export interface WatchResult {
|
|
29
|
-
text: string;
|
|
30
|
-
logIds: string[];
|
|
31
|
-
}
|
|
32
|
-
export const lastCommentaryByConversation = new Map<string, WatchResult>();
|
|
33
|
-
export const lastSummaryByConversation = new Map<string, WatchResult>();
|
|
34
|
-
|
|
35
|
-
export async function handleWatchObservation(
|
|
36
|
-
msg: WatchObservation,
|
|
37
|
-
_ctx: HandlerContext,
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
try {
|
|
40
|
-
log.debug(
|
|
41
|
-
{
|
|
42
|
-
watchId: msg.watchId,
|
|
43
|
-
captureIndex: msg.captureIndex,
|
|
44
|
-
appName: msg.appName,
|
|
45
|
-
ocrLen: msg.ocrText?.length ?? 0,
|
|
46
|
-
},
|
|
47
|
-
"Received watch_observation from client",
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
// 1. Find the WatchSession by watchId
|
|
51
|
-
const session = watchSessions.get(msg.watchId);
|
|
52
|
-
|
|
53
|
-
// 2. If not found or not active (and not completing), log warning and return
|
|
54
|
-
if (!session) {
|
|
55
|
-
log.warn(
|
|
56
|
-
{ watchId: msg.watchId, knownWatchIds: [...watchSessions.keys()] },
|
|
57
|
-
"Watch session not found for observation",
|
|
58
|
-
);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (session.status !== "active" && session.status !== "completing") {
|
|
62
|
-
log.warn(
|
|
63
|
-
{ watchId: msg.watchId, status: session.status },
|
|
64
|
-
"Watch session not active",
|
|
65
|
-
);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 3. Create a WatchObservationEntry and add it
|
|
70
|
-
const entry: WatchObservationEntry = {
|
|
71
|
-
ocrText: msg.ocrText,
|
|
72
|
-
appName: msg.appName,
|
|
73
|
-
windowTitle: msg.windowTitle,
|
|
74
|
-
bundleIdentifier: msg.bundleIdentifier,
|
|
75
|
-
timestamp: msg.timestamp,
|
|
76
|
-
captureIndex: msg.captureIndex,
|
|
77
|
-
};
|
|
78
|
-
addObservation(msg.watchId, entry);
|
|
79
|
-
log.debug(
|
|
80
|
-
{
|
|
81
|
-
watchId: msg.watchId,
|
|
82
|
-
totalObservations: session.observations.length,
|
|
83
|
-
status: session.status,
|
|
84
|
-
},
|
|
85
|
-
"Observation added to watch session",
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// 4. Every 3 observations: call the LLM for live commentary
|
|
89
|
-
if (session.observations.length % 3 === 0) {
|
|
90
|
-
log.debug(
|
|
91
|
-
{ watchId: msg.watchId, observationCount: session.observations.length },
|
|
92
|
-
"Triggering commentary generation (every 3rd observation)",
|
|
93
|
-
);
|
|
94
|
-
await generateCommentary(session);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 5. If session is completing, generate final summary
|
|
98
|
-
if (session.status === "completing") {
|
|
99
|
-
log.debug(
|
|
100
|
-
{ watchId: msg.watchId },
|
|
101
|
-
"Watch session completing — generating summary from observation handler",
|
|
102
|
-
);
|
|
103
|
-
session.status = "completed";
|
|
104
|
-
await generateSummary(session);
|
|
105
|
-
}
|
|
106
|
-
} catch (err) {
|
|
107
|
-
log.error(
|
|
108
|
-
{ err, watchId: msg.watchId },
|
|
109
|
-
"Error handling watch observation",
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function generateCommentary(session: WatchSession): Promise<void> {
|
|
115
|
-
try {
|
|
116
|
-
const provider = await getConfiguredProvider("watchCommentary");
|
|
117
|
-
if (!provider) {
|
|
118
|
-
log.warn(
|
|
119
|
-
{ watchId: session.watchId },
|
|
120
|
-
"Configured provider unavailable for commentary generation",
|
|
121
|
-
);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const lastThree = session.observations.slice(-3);
|
|
125
|
-
const previousResult = lastCommentaryByConversation.get(
|
|
126
|
-
session.conversationId,
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const userContent = [
|
|
130
|
-
`Focus area: ${session.focusArea}`,
|
|
131
|
-
"",
|
|
132
|
-
previousResult
|
|
133
|
-
? `Previous commentary: "${previousResult.text}"`
|
|
134
|
-
: "No previous commentary yet.",
|
|
135
|
-
"",
|
|
136
|
-
...lastThree.map(
|
|
137
|
-
(obs, i) =>
|
|
138
|
-
`Observation ${i + 1}:\n- App: ${
|
|
139
|
-
obs.appName ?? "unknown"
|
|
140
|
-
}\n- Window: ${obs.windowTitle ?? "unknown"}\n- Screen text: ${
|
|
141
|
-
obs.ocrText
|
|
142
|
-
}`,
|
|
143
|
-
),
|
|
144
|
-
].join("\n\n");
|
|
145
|
-
|
|
146
|
-
const systemPrompt = [
|
|
147
|
-
"You are a casual, friendly observer watching someone work on their computer in real time.",
|
|
148
|
-
`They asked you to watch them and focus on: "${session.focusArea}".`,
|
|
149
|
-
"",
|
|
150
|
-
"Your job is to provide brief, natural live commentary — like a friend glancing over their shoulder.",
|
|
151
|
-
"",
|
|
152
|
-
"Guidelines:",
|
|
153
|
-
"- Write 1-2 sentences max. Be concise and conversational.",
|
|
154
|
-
"- Comment on what they are doing, patterns you notice, or interesting transitions.",
|
|
155
|
-
"- Reference specific apps or content you see when relevant.",
|
|
156
|
-
"- If they seem to be context-switching a lot, gently note it.",
|
|
157
|
-
"- Do NOT repeat your previous commentary. Say something new or say nothing.",
|
|
158
|
-
'- If nothing interesting or meaningfully different has happened since the last observations, respond with exactly "SKIP" (no quotes, no extra text).',
|
|
159
|
-
].join("\n");
|
|
160
|
-
|
|
161
|
-
const response = await provider.sendMessage(
|
|
162
|
-
[userMessage(userContent)],
|
|
163
|
-
undefined,
|
|
164
|
-
systemPrompt,
|
|
165
|
-
{
|
|
166
|
-
config: {
|
|
167
|
-
callSite: "watchCommentary",
|
|
168
|
-
max_tokens: 200,
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const logIds: string[] = [];
|
|
174
|
-
if (response.rawRequest && response.rawResponse) {
|
|
175
|
-
try {
|
|
176
|
-
const logId = recordRequestLog(
|
|
177
|
-
session.conversationId,
|
|
178
|
-
JSON.stringify(response.rawRequest),
|
|
179
|
-
JSON.stringify(response.rawResponse),
|
|
180
|
-
undefined,
|
|
181
|
-
response.actualProvider ?? provider.name,
|
|
182
|
-
);
|
|
183
|
-
logIds.push(logId);
|
|
184
|
-
} catch (err) {
|
|
185
|
-
log.warn({ err }, "Failed to persist watch commentary LLM log");
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const commentaryText = extractText(response);
|
|
190
|
-
|
|
191
|
-
if (commentaryText && commentaryText !== "SKIP") {
|
|
192
|
-
lastCommentaryByConversation.set(session.conversationId, {
|
|
193
|
-
text: commentaryText,
|
|
194
|
-
logIds,
|
|
195
|
-
});
|
|
196
|
-
fireWatchCommentaryNotifier(session.conversationId, session);
|
|
197
|
-
session.commentaryCount++;
|
|
198
|
-
}
|
|
199
|
-
} catch (err) {
|
|
200
|
-
log.error(
|
|
201
|
-
{ err, watchId: session.watchId },
|
|
202
|
-
"Error generating watch commentary",
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export async function generateSummary(session: WatchSession): Promise<void> {
|
|
208
|
-
// Guard against concurrent calls (timeout + last observation race)
|
|
209
|
-
if (session.summaryInFlight) {
|
|
210
|
-
log.debug(
|
|
211
|
-
{ watchId: session.watchId },
|
|
212
|
-
"generateSummary already in flight — skipping duplicate call",
|
|
213
|
-
);
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
session.summaryInFlight = true;
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
log.debug(
|
|
220
|
-
{
|
|
221
|
-
watchId: session.watchId,
|
|
222
|
-
conversationId: session.conversationId,
|
|
223
|
-
observationCount: session.observations.length,
|
|
224
|
-
commentaryCount: session.commentaryCount,
|
|
225
|
-
},
|
|
226
|
-
"generateSummary starting — calling LLM",
|
|
227
|
-
);
|
|
228
|
-
const provider = await getConfiguredProvider("watchSummary");
|
|
229
|
-
if (!provider) {
|
|
230
|
-
log.warn(
|
|
231
|
-
{ watchId: session.watchId },
|
|
232
|
-
"Configured provider unavailable for summary generation",
|
|
233
|
-
);
|
|
234
|
-
lastSummaryByConversation.set(session.conversationId, {
|
|
235
|
-
text: "[error] Configured provider unavailable. Check your settings.",
|
|
236
|
-
logIds: [],
|
|
237
|
-
});
|
|
238
|
-
fireWatchCompletionNotifier(session.conversationId, session);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Build observations text with truncation (keep most recent if >50K chars)
|
|
243
|
-
let observations = session.observations;
|
|
244
|
-
const totalChars = observations.reduce(
|
|
245
|
-
(sum, obs) => sum + obs.ocrText.length,
|
|
246
|
-
0,
|
|
247
|
-
);
|
|
248
|
-
let wasTruncated = false;
|
|
249
|
-
|
|
250
|
-
if (totalChars > 50_000) {
|
|
251
|
-
const trimmed: WatchObservationEntry[] = [];
|
|
252
|
-
let charCount = 0;
|
|
253
|
-
for (let i = observations.length - 1; i >= 0; i--) {
|
|
254
|
-
charCount += observations[i].ocrText.length;
|
|
255
|
-
if (charCount > 50_000) break;
|
|
256
|
-
trimmed.unshift(observations[i]);
|
|
257
|
-
}
|
|
258
|
-
wasTruncated = trimmed.length < observations.length;
|
|
259
|
-
observations = trimmed;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const elapsedMinutes = Math.round(
|
|
263
|
-
(Date.now() - session.startedAt) / 60_000,
|
|
264
|
-
);
|
|
265
|
-
const expectedMinutes = Math.round(session.durationSeconds / 60);
|
|
266
|
-
const wasCancelled = elapsedMinutes < expectedMinutes - 1;
|
|
267
|
-
|
|
268
|
-
const userContent = [
|
|
269
|
-
`Focus area: ${session.focusArea}`,
|
|
270
|
-
`Observation period: ${elapsedMinutes} minute(s) (planned: ${expectedMinutes} minute(s))`,
|
|
271
|
-
`Total observations: ${session.observations.length}`,
|
|
272
|
-
...(wasTruncated
|
|
273
|
-
? [
|
|
274
|
-
`Note: Older observations were trimmed due to size. Showing the most recent ${observations.length} of ${session.observations.length} total.`,
|
|
275
|
-
]
|
|
276
|
-
: []),
|
|
277
|
-
...(wasCancelled
|
|
278
|
-
? [
|
|
279
|
-
"Note: The observation period was ended early by the user. Provide your best analysis based on the data available.",
|
|
280
|
-
]
|
|
281
|
-
: []),
|
|
282
|
-
"",
|
|
283
|
-
"--- Observations ---",
|
|
284
|
-
"",
|
|
285
|
-
...observations.map(
|
|
286
|
-
(obs) =>
|
|
287
|
-
`[${new Date(obs.timestamp).toISOString()}] App: ${
|
|
288
|
-
obs.appName ?? "unknown"
|
|
289
|
-
} | Window: ${obs.windowTitle ?? "unknown"}\n${obs.ocrText}`,
|
|
290
|
-
),
|
|
291
|
-
].join("\n\n");
|
|
292
|
-
|
|
293
|
-
const systemPrompt = [
|
|
294
|
-
"You are a productivity analyst reviewing a series of screen observations captured from a user's computer.",
|
|
295
|
-
`The user asked you to watch their workflow with this focus: "${session.focusArea}".`,
|
|
296
|
-
"",
|
|
297
|
-
"Analyze the observations and produce a structured report using exactly these markdown sections:",
|
|
298
|
-
"",
|
|
299
|
-
"## Workflow Summary",
|
|
300
|
-
"A high-level description (2-4 sentences) of what the user did during the observation period.",
|
|
301
|
-
"",
|
|
302
|
-
"## App Usage",
|
|
303
|
-
"List which applications were used and roughly how much time was spent in each. Use the timestamps to estimate durations. Present as a bullet list.",
|
|
304
|
-
"",
|
|
305
|
-
"## Context Switching",
|
|
306
|
-
"Analyze how often the user switched between different apps or tasks. Note any patterns — were switches frequent and disruptive, or natural and purposeful?",
|
|
307
|
-
"",
|
|
308
|
-
"## Tasks & Action Items",
|
|
309
|
-
"Based on what you observed on screen, describe what tasks the user worked on. Note anything that appeared unfinished or in-progress when the session ended.",
|
|
310
|
-
"",
|
|
311
|
-
"## Suggestions",
|
|
312
|
-
"Provide 3-5 specific, actionable things the assistant could help with based on what you observed. These should be concrete offers, not generic advice.",
|
|
313
|
-
'Examples: "I could draft that email you started in Gmail", "Want me to summarize the Slack thread you were reading?", "I could help outline the document you were working on in Google Docs".',
|
|
314
|
-
"",
|
|
315
|
-
"Important:",
|
|
316
|
-
"- Base your analysis strictly on what you can see in the observations. Do not invent details.",
|
|
317
|
-
"- Reference specific apps, window titles, and content when possible.",
|
|
318
|
-
"- Keep the tone helpful and professional, not judgmental.",
|
|
319
|
-
...(wasCancelled
|
|
320
|
-
? [
|
|
321
|
-
"- The observation period was cut short. Acknowledge this briefly and provide the best analysis you can with the available data.",
|
|
322
|
-
]
|
|
323
|
-
: []),
|
|
324
|
-
].join("\n");
|
|
325
|
-
|
|
326
|
-
const response = await provider.sendMessage(
|
|
327
|
-
[userMessage(userContent)],
|
|
328
|
-
undefined,
|
|
329
|
-
systemPrompt,
|
|
330
|
-
{
|
|
331
|
-
config: {
|
|
332
|
-
callSite: "watchSummary",
|
|
333
|
-
max_tokens: 2000,
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
const logIds: string[] = [];
|
|
339
|
-
if (response.rawRequest && response.rawResponse) {
|
|
340
|
-
try {
|
|
341
|
-
const logId = recordRequestLog(
|
|
342
|
-
session.conversationId,
|
|
343
|
-
JSON.stringify(response.rawRequest),
|
|
344
|
-
JSON.stringify(response.rawResponse),
|
|
345
|
-
undefined,
|
|
346
|
-
response.actualProvider ?? provider.name,
|
|
347
|
-
);
|
|
348
|
-
logIds.push(logId);
|
|
349
|
-
} catch (err) {
|
|
350
|
-
log.warn({ err }, "Failed to persist watch summary LLM log");
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
log.debug(
|
|
355
|
-
{ watchId: session.watchId },
|
|
356
|
-
"LLM API call completed successfully",
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
const summaryText = extractText(response);
|
|
360
|
-
|
|
361
|
-
log.debug(
|
|
362
|
-
{ watchId: session.watchId, summaryLength: summaryText.length },
|
|
363
|
-
"Summary result from Sonnet",
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
if (summaryText) {
|
|
367
|
-
lastSummaryByConversation.set(session.conversationId, {
|
|
368
|
-
text: summaryText,
|
|
369
|
-
logIds,
|
|
370
|
-
});
|
|
371
|
-
log.debug(
|
|
372
|
-
{ watchId: session.watchId, conversationId: session.conversationId },
|
|
373
|
-
"Firing completion notifier with summary",
|
|
374
|
-
);
|
|
375
|
-
fireWatchCompletionNotifier(session.conversationId, session);
|
|
376
|
-
} else {
|
|
377
|
-
log.warn(
|
|
378
|
-
{ watchId: session.watchId },
|
|
379
|
-
"Summary was empty from API response",
|
|
380
|
-
);
|
|
381
|
-
lastSummaryByConversation.set(session.conversationId, {
|
|
382
|
-
text: "[error] The API returned an empty summary. This may indicate a service issue.",
|
|
383
|
-
logIds,
|
|
384
|
-
});
|
|
385
|
-
fireWatchCompletionNotifier(session.conversationId, session);
|
|
386
|
-
}
|
|
387
|
-
} catch (err) {
|
|
388
|
-
log.error(
|
|
389
|
-
{ err, watchId: session.watchId },
|
|
390
|
-
"Error generating watch summary — LLM API call failed",
|
|
391
|
-
);
|
|
392
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
393
|
-
lastSummaryByConversation.set(session.conversationId, {
|
|
394
|
-
text: `[error] Summary generation failed: ${message}`,
|
|
395
|
-
logIds: [],
|
|
396
|
-
});
|
|
397
|
-
fireWatchCompletionNotifier(session.conversationId, session);
|
|
398
|
-
}
|
|
399
|
-
}
|
package/src/hooks/cli.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { chmodSync, cpSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
-
import { join, resolve, sep } from "node:path";
|
|
3
|
-
|
|
4
|
-
import { Command } from "commander";
|
|
5
|
-
|
|
6
|
-
import { pathExists } from "../util/fs.js";
|
|
7
|
-
import { getCliLogger } from "../util/logger.js";
|
|
8
|
-
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
9
|
-
import { ensureHookInConfig, removeHook, setHookEnabled } from "./config.js";
|
|
10
|
-
import { discoverHooks, isValidInstallManifest } from "./discovery.js";
|
|
11
|
-
|
|
12
|
-
const log = getCliLogger("hooks");
|
|
13
|
-
|
|
14
|
-
export function registerHooksCommand(program: Command): void {
|
|
15
|
-
const hooks = program.command("hooks").description("Manage hooks");
|
|
16
|
-
|
|
17
|
-
hooks.addHelpText(
|
|
18
|
-
"after",
|
|
19
|
-
`
|
|
20
|
-
Hooks are user-installed scripts that run in response to assistant lifecycle
|
|
21
|
-
events (e.g. tool invocations, message sends). Each hook is a directory
|
|
22
|
-
containing a hook.json manifest and a script file. Hooks are stored in
|
|
23
|
-
$VELLUM_WORKSPACE_DIR/hooks/ and must be explicitly enabled after installation.
|
|
24
|
-
|
|
25
|
-
Examples:
|
|
26
|
-
$ assistant hooks list
|
|
27
|
-
$ assistant hooks install ./my-hook
|
|
28
|
-
$ assistant hooks enable my-hook
|
|
29
|
-
$ assistant hooks disable my-hook`,
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
hooks
|
|
33
|
-
.command("list")
|
|
34
|
-
.description("List all installed hooks")
|
|
35
|
-
.addHelpText(
|
|
36
|
-
"after",
|
|
37
|
-
`
|
|
38
|
-
Displays a table of all installed hooks with their name, subscribed events,
|
|
39
|
-
enabled status, and version.
|
|
40
|
-
|
|
41
|
-
Examples:
|
|
42
|
-
$ assistant hooks list`,
|
|
43
|
-
)
|
|
44
|
-
.action(() => {
|
|
45
|
-
const discovered = discoverHooks();
|
|
46
|
-
if (discovered.length === 0) {
|
|
47
|
-
log.info("No hooks installed");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const nameW = 24;
|
|
52
|
-
const eventsW = 24;
|
|
53
|
-
const enabledW = 10;
|
|
54
|
-
log.info(
|
|
55
|
-
"Name".padEnd(nameW) +
|
|
56
|
-
"Events".padEnd(eventsW) +
|
|
57
|
-
"Enabled".padEnd(enabledW) +
|
|
58
|
-
"Version",
|
|
59
|
-
);
|
|
60
|
-
log.info("-".repeat(nameW + eventsW + enabledW + 10));
|
|
61
|
-
|
|
62
|
-
for (const hook of discovered) {
|
|
63
|
-
const events = hook.manifest.events.join(", ");
|
|
64
|
-
const eventsTrunc =
|
|
65
|
-
events.length > eventsW - 2
|
|
66
|
-
? events.slice(0, eventsW - 4) + ".."
|
|
67
|
-
: events;
|
|
68
|
-
log.info(
|
|
69
|
-
hook.name.slice(0, nameW - 2).padEnd(nameW) +
|
|
70
|
-
eventsTrunc.padEnd(eventsW) +
|
|
71
|
-
(hook.enabled ? "yes" : "no").padEnd(enabledW) +
|
|
72
|
-
(hook.manifest.version ?? "-"),
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
hooks
|
|
78
|
-
.command("enable <name>")
|
|
79
|
-
.description("Enable a hook")
|
|
80
|
-
.addHelpText(
|
|
81
|
-
"after",
|
|
82
|
-
`
|
|
83
|
-
Arguments:
|
|
84
|
-
name Hook name as shown by 'assistant hooks list'
|
|
85
|
-
|
|
86
|
-
Enables a previously installed hook so it runs on matching events.
|
|
87
|
-
|
|
88
|
-
Examples:
|
|
89
|
-
$ assistant hooks enable my-hook`,
|
|
90
|
-
)
|
|
91
|
-
.action((name: string) => {
|
|
92
|
-
const discovered = discoverHooks();
|
|
93
|
-
const hook = discovered.find((h) => h.name === name);
|
|
94
|
-
if (!hook) {
|
|
95
|
-
log.error(`Hook not found: ${name}`);
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
setHookEnabled(name, true);
|
|
99
|
-
log.info(`Enabled hook: ${name}`);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
hooks
|
|
103
|
-
.command("disable <name>")
|
|
104
|
-
.description("Disable a hook")
|
|
105
|
-
.addHelpText(
|
|
106
|
-
"after",
|
|
107
|
-
`
|
|
108
|
-
Arguments:
|
|
109
|
-
name Hook name as shown by 'assistant hooks list'
|
|
110
|
-
|
|
111
|
-
Disables a hook so it no longer runs on events. The hook remains installed
|
|
112
|
-
and can be re-enabled later.
|
|
113
|
-
|
|
114
|
-
Examples:
|
|
115
|
-
$ assistant hooks disable my-hook`,
|
|
116
|
-
)
|
|
117
|
-
.action((name: string) => {
|
|
118
|
-
const discovered = discoverHooks();
|
|
119
|
-
const hook = discovered.find((h) => h.name === name);
|
|
120
|
-
if (!hook) {
|
|
121
|
-
log.error(`Hook not found: ${name}`);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
setHookEnabled(name, false);
|
|
125
|
-
log.info(`Disabled hook: ${name}`);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
hooks
|
|
129
|
-
.command("install <path>")
|
|
130
|
-
.description("Install a hook from a directory")
|
|
131
|
-
.addHelpText(
|
|
132
|
-
"after",
|
|
133
|
-
`
|
|
134
|
-
Arguments:
|
|
135
|
-
path Path to a directory containing a hook.json manifest and a script file.
|
|
136
|
-
The manifest must have name, script, description, version, and at
|
|
137
|
-
least one valid event.
|
|
138
|
-
|
|
139
|
-
Copies the hook directory into $VELLUM_WORKSPACE_DIR/hooks/<name>/ and registers it as
|
|
140
|
-
disabled by default. Run 'assistant hooks enable <name>' to activate.
|
|
141
|
-
|
|
142
|
-
Examples:
|
|
143
|
-
$ assistant hooks install ./my-hook
|
|
144
|
-
$ assistant hooks install /path/to/custom-hook`,
|
|
145
|
-
)
|
|
146
|
-
.action((hookPath: string) => {
|
|
147
|
-
const srcDir = resolve(hookPath);
|
|
148
|
-
if (!pathExists(srcDir)) {
|
|
149
|
-
log.error(`Directory not found: ${srcDir}`);
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const manifestPath = join(srcDir, "hook.json");
|
|
154
|
-
if (!pathExists(manifestPath)) {
|
|
155
|
-
log.error(`No hook.json found in ${srcDir}`);
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let manifest: unknown;
|
|
160
|
-
try {
|
|
161
|
-
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
162
|
-
} catch {
|
|
163
|
-
log.error(`Failed to parse hook.json in ${srcDir}`);
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (!isValidInstallManifest(manifest)) {
|
|
168
|
-
log.error(
|
|
169
|
-
"Invalid hook.json: must have a non-empty name, script, description (string), version (string), and at least one valid event",
|
|
170
|
-
);
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const hooksDir = getWorkspaceHooksDir();
|
|
175
|
-
const resolvedHooksDir = resolve(hooksDir);
|
|
176
|
-
const targetDir = resolve(join(hooksDir, manifest.name));
|
|
177
|
-
if (!targetDir.startsWith(resolvedHooksDir + sep)) {
|
|
178
|
-
log.error(
|
|
179
|
-
`Invalid hook name: "${manifest.name}" would escape the hooks directory`,
|
|
180
|
-
);
|
|
181
|
-
process.exit(1);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const scriptPath = resolve(join(targetDir, manifest.script));
|
|
185
|
-
if (!scriptPath.startsWith(targetDir + sep)) {
|
|
186
|
-
log.error(
|
|
187
|
-
`Invalid hook script: "${manifest.script}" would escape the hook directory`,
|
|
188
|
-
);
|
|
189
|
-
process.exit(1);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (pathExists(targetDir)) {
|
|
193
|
-
log.error(`Hook already installed: ${manifest.name}`);
|
|
194
|
-
process.exit(1);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
cpSync(srcDir, targetDir, { recursive: true });
|
|
198
|
-
|
|
199
|
-
// Make script executable
|
|
200
|
-
if (pathExists(scriptPath)) {
|
|
201
|
-
chmodSync(scriptPath, 0o755);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
ensureHookInConfig(manifest.name, { enabled: false });
|
|
205
|
-
log.info(`Installed hook: ${manifest.name} (disabled by default)`);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
hooks
|
|
209
|
-
.command("remove <name>")
|
|
210
|
-
.description("Remove an installed hook")
|
|
211
|
-
.addHelpText(
|
|
212
|
-
"after",
|
|
213
|
-
`
|
|
214
|
-
Arguments:
|
|
215
|
-
name Hook name as shown by 'assistant hooks list'
|
|
216
|
-
|
|
217
|
-
Permanently deletes the hook directory and removes it from configuration.
|
|
218
|
-
Prompts for confirmation before proceeding.
|
|
219
|
-
|
|
220
|
-
Examples:
|
|
221
|
-
$ assistant hooks remove my-hook`,
|
|
222
|
-
)
|
|
223
|
-
.action(async (name: string) => {
|
|
224
|
-
const discovered = discoverHooks();
|
|
225
|
-
const hook = discovered.find((h) => h.name === name);
|
|
226
|
-
if (!hook) {
|
|
227
|
-
log.error(`Hook not found: ${name}`);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const readline = await import("node:readline");
|
|
232
|
-
const rl = readline.createInterface({
|
|
233
|
-
input: process.stdin,
|
|
234
|
-
output: process.stdout,
|
|
235
|
-
});
|
|
236
|
-
const answer = await new Promise<string>((resolve) => {
|
|
237
|
-
rl.question(
|
|
238
|
-
`Remove hook "${name}" and delete its files? (y/N) `,
|
|
239
|
-
resolve,
|
|
240
|
-
);
|
|
241
|
-
});
|
|
242
|
-
rl.close();
|
|
243
|
-
|
|
244
|
-
if (answer.toLowerCase() !== "y") {
|
|
245
|
-
log.info("Cancelled");
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
rmSync(hook.dir, { recursive: true, force: true });
|
|
250
|
-
removeHook(name);
|
|
251
|
-
log.info(`Removed hook: ${name}`);
|
|
252
|
-
});
|
|
253
|
-
}
|