@vellumai/assistant 0.6.4 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +32 -36
- package/Dockerfile +12 -0
- package/README.md +3 -4
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +123 -11
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +428 -501
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +427 -114
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +530 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
- package/src/__tests__/conversation-agent-loop.test.ts +412 -82
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
- package/src/__tests__/conversation-queue.test.ts +41 -26
- package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +34 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/model-intents.test.ts +9 -83
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/oauth-store.test.ts +10 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +50 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor.test.ts +60 -94
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -13
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +209 -17
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +14 -1
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +23 -4
- package/src/cli.ts +0 -37
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -175
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +30 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +53 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +2 -2
- package/src/context/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/window-manager.ts +229 -25
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
- package/src/daemon/conversation-agent-loop.ts +462 -80
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-lifecycle.ts +30 -6
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-process.ts +10 -4
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +760 -29
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +10 -5
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +118 -30
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +2 -2
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +76 -14
- package/src/daemon/message-types/conversations.ts +14 -0
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +117 -9
- package/src/daemon/tool-side-effects.ts +0 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +76 -28
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +4 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +56 -2
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +4 -4
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +17 -1
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +103 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +173 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +230 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/oauth/oauth-store.ts +1 -0
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/seed-providers.ts +4 -2
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +217 -708
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +26 -78
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -16
- package/src/platform/client.ts +19 -1
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +501 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +76 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +52 -1
- package/src/runtime/http-types.ts +23 -1
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +133 -27
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/migration-routes.ts +720 -124
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +28 -6
- package/src/schedule/scheduler.ts +8 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
- package/src/tools/browser/browser-execution.ts +65 -38
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +12 -3
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +2 -2
- package/src/util/pricing.ts +15 -5
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assistant ui` CLI namespace.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - `assistant ui request` — Present an arbitrary interactive surface to
|
|
6
|
+
* the user and block until they respond. Input is a JSON payload
|
|
7
|
+
* describing the surface (via `--payload` or stdin).
|
|
8
|
+
* - `assistant ui confirm` — Convenience wrapper that presents a yes/no
|
|
9
|
+
* confirmation prompt and exits 0 on confirm, 1 on deny/cancel/timeout.
|
|
10
|
+
*
|
|
11
|
+
* Both commands delegate to the daemon's `ui_request` IPC method, which
|
|
12
|
+
* manages the surface lifecycle on the active conversation.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
|
|
17
|
+
import type { Command } from "commander";
|
|
18
|
+
|
|
19
|
+
import { cliIpcCall } from "../../ipc/cli-client.js";
|
|
20
|
+
import {
|
|
21
|
+
type InteractiveUiAction,
|
|
22
|
+
type InteractiveUiResult,
|
|
23
|
+
RESERVED_ACTION_IDS,
|
|
24
|
+
} from "../../runtime/interactive-ui.js";
|
|
25
|
+
import { log } from "../logger.js";
|
|
26
|
+
|
|
27
|
+
// ── Constants ─────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Default request timeout in milliseconds (5 minutes). This is the time
|
|
31
|
+
* the daemon will wait for the user to respond before the surface
|
|
32
|
+
* auto-cancels with `status: "timed_out"`.
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 5 * 60 * 1000; // 5m
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extra buffer added to the IPC call timeout beyond the request timeout
|
|
38
|
+
* so the IPC socket stays open long enough for the daemon to resolve the
|
|
39
|
+
* surface and send the response.
|
|
40
|
+
*/
|
|
41
|
+
const IPC_TIMEOUT_BUFFER_MS = 10_000; // 10s
|
|
42
|
+
|
|
43
|
+
// ── Conversation ID resolution ────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the conversation ID by precedence:
|
|
47
|
+
* 1. Explicit `--conversation-id` flag
|
|
48
|
+
* 2. `__SKILL_CONTEXT_JSON` env var (set by skill sandbox runner)
|
|
49
|
+
* 3. `__CONVERSATION_ID` env var (set by bash tool subprocess)
|
|
50
|
+
* 4. Fail with an actionable error
|
|
51
|
+
*/
|
|
52
|
+
function resolveConversationId(explicit?: string): string {
|
|
53
|
+
if (explicit) return explicit;
|
|
54
|
+
|
|
55
|
+
const contextJson = process.env.__SKILL_CONTEXT_JSON;
|
|
56
|
+
if (contextJson) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(contextJson);
|
|
59
|
+
if (parsed.conversationId && typeof parsed.conversationId === "string") {
|
|
60
|
+
return parsed.conversationId;
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
// Fall through
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const envConvId = process.env.__CONVERSATION_ID;
|
|
68
|
+
if (envConvId && typeof envConvId === "string") {
|
|
69
|
+
return envConvId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
throw new Error(
|
|
73
|
+
"No conversation ID available.\n" +
|
|
74
|
+
"Provide --conversation-id explicitly (run 'assistant conversations list' to find it),\n" +
|
|
75
|
+
"or run this command from a skill or bash tool context.",
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Payload parsing ───────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Read a JSON payload from either the `--payload` flag or stdin.
|
|
83
|
+
* Returns the parsed object. Throws on invalid input.
|
|
84
|
+
*/
|
|
85
|
+
function readPayload(payloadFlag?: string): Record<string, unknown> {
|
|
86
|
+
if (payloadFlag) {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(payloadFlag);
|
|
89
|
+
if (
|
|
90
|
+
typeof parsed !== "object" ||
|
|
91
|
+
parsed === null ||
|
|
92
|
+
Array.isArray(parsed)
|
|
93
|
+
) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
"--payload must be a JSON object (not array or primitive).",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return parsed as Record<string, unknown>;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof SyntaxError) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Invalid JSON in --payload: ${err.message}\n` +
|
|
103
|
+
' Example: --payload \'{"message":"Are you sure?"}\'',
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Read from stdin
|
|
111
|
+
if (process.stdin.isTTY) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
"No payload provided. Use --payload <json> or pipe JSON into stdin.\n" +
|
|
114
|
+
' Example: echo \'{"message":"Are you sure?"}\' | assistant ui request',
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let raw: string;
|
|
119
|
+
try {
|
|
120
|
+
raw = readFileSync("/dev/stdin", "utf-8");
|
|
121
|
+
} catch (err) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Failed to read stdin: ${err instanceof Error ? err.message : String(err)}`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!raw.trim()) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"Empty input on stdin. Provide a valid JSON object.\n" +
|
|
130
|
+
' Example: echo \'{"message":"Are you sure?"}\' | assistant ui request',
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const parsed = JSON.parse(raw);
|
|
136
|
+
if (
|
|
137
|
+
typeof parsed !== "object" ||
|
|
138
|
+
parsed === null ||
|
|
139
|
+
Array.isArray(parsed)
|
|
140
|
+
) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"Stdin payload must be a JSON object (not array or primitive).",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return parsed as Record<string, unknown>;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (err instanceof SyntaxError) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Invalid JSON on stdin: ${err.message}\n` +
|
|
150
|
+
' Example: echo \'{"message":"Are you sure?"}\' | assistant ui request',
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Action parsing ────────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
/** Valid variant values for action buttons. */
|
|
160
|
+
const VALID_VARIANTS = new Set(["primary", "danger", "secondary"]);
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Parse and validate the `--actions` JSON flag.
|
|
164
|
+
*
|
|
165
|
+
* Expected shape: an array of objects, each with:
|
|
166
|
+
* - `id` (string, required, non-empty)
|
|
167
|
+
* - `label` (string, required, non-empty)
|
|
168
|
+
* - `variant` (optional: "primary" | "danger" | "secondary")
|
|
169
|
+
*
|
|
170
|
+
* Returns the validated array, or throws with an actionable CLI error.
|
|
171
|
+
*/
|
|
172
|
+
function parseActions(raw: string): InteractiveUiAction[] {
|
|
173
|
+
let parsed: unknown;
|
|
174
|
+
try {
|
|
175
|
+
parsed = JSON.parse(raw);
|
|
176
|
+
} catch (err) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Invalid JSON in --actions: ${err instanceof SyntaxError ? err.message : String(err)}\n` +
|
|
179
|
+
" --actions must be a JSON array of action objects.\n" +
|
|
180
|
+
' Example: --actions \'[{"id":"approve","label":"Approve"},{"id":"reject","label":"Reject","variant":"danger"}]\'',
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!Array.isArray(parsed)) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
"--actions must be a JSON array of action objects.\n" +
|
|
187
|
+
' Example: --actions \'[{"id":"approve","label":"Approve"}]\'',
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (parsed.length === 0) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
"--actions must contain at least one action.\n" +
|
|
194
|
+
' Example: --actions \'[{"id":"approve","label":"Approve"}]\'',
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const actions: InteractiveUiAction[] = [];
|
|
199
|
+
for (let i = 0; i < parsed.length; i++) {
|
|
200
|
+
const item = parsed[i];
|
|
201
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`--actions[${i}]: each action must be a JSON object with "id" and "label" fields.\n` +
|
|
204
|
+
' Example: {"id":"approve","label":"Approve"}',
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const obj = item as Record<string, unknown>;
|
|
209
|
+
|
|
210
|
+
if (typeof obj.id !== "string" || obj.id.length === 0) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`--actions[${i}]: "id" is required and must be a non-empty string.\n` +
|
|
213
|
+
' Example: {"id":"approve","label":"Approve"}',
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (RESERVED_ACTION_IDS.has(obj.id)) {
|
|
218
|
+
const reserved = [...RESERVED_ACTION_IDS].sort().join(", ");
|
|
219
|
+
throw new Error(
|
|
220
|
+
`--actions[${i}]: id "${obj.id}" is reserved for internal use. Reserved IDs: ${reserved}`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (typeof obj.label !== "string" || obj.label.length === 0) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
`--actions[${i}]: "label" is required and must be a non-empty string.\n` +
|
|
227
|
+
' Example: {"id":"approve","label":"Approve"}',
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const action: InteractiveUiAction = { id: obj.id, label: obj.label };
|
|
232
|
+
|
|
233
|
+
if (obj.variant !== undefined) {
|
|
234
|
+
if (typeof obj.variant !== "string" || !VALID_VARIANTS.has(obj.variant)) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`--actions[${i}]: "variant" must be one of "primary", "danger", or "secondary" (got ${JSON.stringify(obj.variant)}).\n` +
|
|
237
|
+
' Example: {"id":"delete","label":"Delete","variant":"danger"}',
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
action.variant = obj.variant as InteractiveUiAction["variant"];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
actions.push(action);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return actions;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ── Strict integer parsing ────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Parse a string as a strict positive integer. Rejects inputs like
|
|
253
|
+
* `"1e3"`, `"30s"`, `"12.5"` that `parseInt` would silently truncate.
|
|
254
|
+
* Returns the parsed integer or `NaN` on any non-pure-integer input.
|
|
255
|
+
*/
|
|
256
|
+
function parseStrictPositiveInt(value: string): number {
|
|
257
|
+
if (!/^\d+$/.test(value)) return NaN;
|
|
258
|
+
return Number(value);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ── Registration ──────────────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
export function registerUiCommand(program: Command): void {
|
|
264
|
+
const ui = program
|
|
265
|
+
.command("ui")
|
|
266
|
+
.description("Present interactive UI surfaces to the user");
|
|
267
|
+
|
|
268
|
+
ui.addHelpText(
|
|
269
|
+
"after",
|
|
270
|
+
`
|
|
271
|
+
Script-facing commands that present interactive surfaces (confirmations,
|
|
272
|
+
forms) to the user via the running assistant and block until the user
|
|
273
|
+
responds or the request times out.
|
|
274
|
+
|
|
275
|
+
The conversation ID is resolved automatically when running inside a skill
|
|
276
|
+
or bash tool context (__SKILL_CONTEXT_JSON or __CONVERSATION_ID).
|
|
277
|
+
Override with --conversation-id if needed.
|
|
278
|
+
|
|
279
|
+
Examples:
|
|
280
|
+
$ echo '{"message":"Delete all logs?"}' | assistant ui request --json
|
|
281
|
+
$ assistant ui confirm --title "Deploy to production?" --message "This will push to prod."
|
|
282
|
+
$ assistant ui confirm --message "Are you sure?" --json`,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// ── ui request ───────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
ui.command("request")
|
|
288
|
+
.description(
|
|
289
|
+
"Present an interactive surface and block until the user responds",
|
|
290
|
+
)
|
|
291
|
+
.option("--payload <json>", "JSON object describing the surface data")
|
|
292
|
+
.option(
|
|
293
|
+
"--surface-type <type>",
|
|
294
|
+
'Surface type: "confirmation" or "form"',
|
|
295
|
+
"confirmation",
|
|
296
|
+
)
|
|
297
|
+
.option("--title <title>", "Title displayed on the surface")
|
|
298
|
+
.option(
|
|
299
|
+
"--actions <json>",
|
|
300
|
+
"JSON array of action objects defining custom buttons/options",
|
|
301
|
+
)
|
|
302
|
+
.option(
|
|
303
|
+
"--conversation-id <id>",
|
|
304
|
+
"Conversation ID — run 'assistant conversations list' to find it (auto-resolved from skill or bash tool context if omitted)",
|
|
305
|
+
)
|
|
306
|
+
.option(
|
|
307
|
+
"--timeout <ms>",
|
|
308
|
+
"Request timeout in milliseconds",
|
|
309
|
+
String(DEFAULT_REQUEST_TIMEOUT_MS),
|
|
310
|
+
)
|
|
311
|
+
.option("--json", "Output result as machine-readable JSON")
|
|
312
|
+
.addHelpText(
|
|
313
|
+
"after",
|
|
314
|
+
`
|
|
315
|
+
Sends a UI interaction request to the running assistant and blocks until
|
|
316
|
+
the user responds or the timeout elapses. The payload describes the
|
|
317
|
+
surface content and can be provided via --payload or piped through stdin.
|
|
318
|
+
|
|
319
|
+
The response includes the user's action (submitted, cancelled, timed_out)
|
|
320
|
+
and any submitted data.
|
|
321
|
+
|
|
322
|
+
Custom actions can be defined via --actions to control the buttons shown
|
|
323
|
+
on the surface. Each action requires an "id" and "label", with an optional
|
|
324
|
+
"variant" hint ("primary", "danger", or "secondary").
|
|
325
|
+
|
|
326
|
+
Arguments:
|
|
327
|
+
(none — payload via --payload flag or stdin)
|
|
328
|
+
|
|
329
|
+
Options:
|
|
330
|
+
--payload <json> JSON object with surface data
|
|
331
|
+
--surface-type <type> "confirmation" (default) or "form"
|
|
332
|
+
--title <title> Surface title
|
|
333
|
+
--actions <json> JSON array of custom action objects
|
|
334
|
+
--conversation-id <id> Explicit conversation ID
|
|
335
|
+
--timeout <ms> Request timeout in milliseconds (default: 300000)
|
|
336
|
+
--json Output as JSON
|
|
337
|
+
|
|
338
|
+
Examples:
|
|
339
|
+
$ echo '{"message":"Proceed?"}' | assistant ui request
|
|
340
|
+
$ assistant ui request --payload '{"message":"Proceed?"}' --json
|
|
341
|
+
$ assistant ui request --payload '{"fields":[]}' --surface-type form --json
|
|
342
|
+
$ assistant ui request --payload '{"message":"Choose an option"}' \\
|
|
343
|
+
--actions '[{"id":"approve","label":"Approve","variant":"primary"},{"id":"reject","label":"Reject","variant":"danger"}]'`,
|
|
344
|
+
)
|
|
345
|
+
.action(
|
|
346
|
+
async (opts: {
|
|
347
|
+
payload?: string;
|
|
348
|
+
surfaceType?: string;
|
|
349
|
+
title?: string;
|
|
350
|
+
actions?: string;
|
|
351
|
+
conversationId?: string;
|
|
352
|
+
timeout?: string;
|
|
353
|
+
json?: boolean;
|
|
354
|
+
}) => {
|
|
355
|
+
// Parse payload
|
|
356
|
+
let data: Record<string, unknown>;
|
|
357
|
+
try {
|
|
358
|
+
data = readPayload(opts.payload);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
361
|
+
if (opts.json) {
|
|
362
|
+
process.stdout.write(
|
|
363
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
364
|
+
);
|
|
365
|
+
} else {
|
|
366
|
+
log.error(msg);
|
|
367
|
+
}
|
|
368
|
+
process.exitCode = 1;
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Resolve conversation ID
|
|
373
|
+
let conversationId: string;
|
|
374
|
+
try {
|
|
375
|
+
conversationId = resolveConversationId(opts.conversationId);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
378
|
+
if (opts.json) {
|
|
379
|
+
process.stdout.write(
|
|
380
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
381
|
+
);
|
|
382
|
+
} else {
|
|
383
|
+
log.error(msg);
|
|
384
|
+
}
|
|
385
|
+
process.exitCode = 1;
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Parse actions (if provided)
|
|
390
|
+
let actions: InteractiveUiAction[] | undefined;
|
|
391
|
+
if (opts.actions !== undefined) {
|
|
392
|
+
try {
|
|
393
|
+
actions = parseActions(opts.actions);
|
|
394
|
+
} catch (err) {
|
|
395
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
396
|
+
if (opts.json) {
|
|
397
|
+
process.stdout.write(
|
|
398
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
399
|
+
);
|
|
400
|
+
} else {
|
|
401
|
+
log.error(msg);
|
|
402
|
+
}
|
|
403
|
+
process.exitCode = 1;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Parse timeout
|
|
409
|
+
const rawTimeout = opts.timeout ?? String(DEFAULT_REQUEST_TIMEOUT_MS);
|
|
410
|
+
const requestTimeoutMs = parseStrictPositiveInt(rawTimeout);
|
|
411
|
+
if (isNaN(requestTimeoutMs) || requestTimeoutMs <= 0) {
|
|
412
|
+
const msg = `Invalid --timeout value "${opts.timeout}". Must be a positive integer (milliseconds).`;
|
|
413
|
+
if (opts.json) {
|
|
414
|
+
process.stdout.write(
|
|
415
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
416
|
+
);
|
|
417
|
+
} else {
|
|
418
|
+
log.error(msg);
|
|
419
|
+
}
|
|
420
|
+
process.exitCode = 1;
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Build IPC params
|
|
425
|
+
const ipcParams: Record<string, unknown> = {
|
|
426
|
+
conversationId,
|
|
427
|
+
surfaceType: opts.surfaceType ?? "confirmation",
|
|
428
|
+
data,
|
|
429
|
+
timeoutMs: requestTimeoutMs,
|
|
430
|
+
};
|
|
431
|
+
if (opts.title) {
|
|
432
|
+
ipcParams.title = opts.title;
|
|
433
|
+
}
|
|
434
|
+
if (actions) {
|
|
435
|
+
ipcParams.actions = actions;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Call IPC with timeout budget = request timeout + buffer
|
|
439
|
+
const ipcTimeoutMs = requestTimeoutMs + IPC_TIMEOUT_BUFFER_MS;
|
|
440
|
+
const result = await cliIpcCall<InteractiveUiResult>(
|
|
441
|
+
"ui_request",
|
|
442
|
+
ipcParams,
|
|
443
|
+
{
|
|
444
|
+
timeoutMs: ipcTimeoutMs,
|
|
445
|
+
},
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
if (!result.ok) {
|
|
449
|
+
if (opts.json) {
|
|
450
|
+
process.stdout.write(
|
|
451
|
+
JSON.stringify({ ok: false, error: result.error }) + "\n",
|
|
452
|
+
);
|
|
453
|
+
} else {
|
|
454
|
+
log.error(`Error: ${result.error}`);
|
|
455
|
+
}
|
|
456
|
+
process.exitCode = 1;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (opts.json) {
|
|
461
|
+
process.stdout.write(
|
|
462
|
+
JSON.stringify({ ok: true, ...result.result }) + "\n",
|
|
463
|
+
);
|
|
464
|
+
} else {
|
|
465
|
+
const r = result.result!;
|
|
466
|
+
if (r.status === "submitted") {
|
|
467
|
+
log.info(
|
|
468
|
+
`User responded: ${r.actionId ?? "submitted"}${r.summary ? ` — ${r.summary}` : ""}`,
|
|
469
|
+
);
|
|
470
|
+
} else if (r.status === "timed_out") {
|
|
471
|
+
log.info("Request timed out without a response.");
|
|
472
|
+
} else {
|
|
473
|
+
log.info("Request was cancelled.");
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
// ── ui confirm ──────────────────────────────────────────────────
|
|
480
|
+
|
|
481
|
+
ui.command("confirm")
|
|
482
|
+
.description(
|
|
483
|
+
"Present a yes/no confirmation prompt; exits 0 on confirm, 1 on deny/cancel/timeout",
|
|
484
|
+
)
|
|
485
|
+
.option("--title <title>", "Title displayed on the confirmation prompt")
|
|
486
|
+
.option(
|
|
487
|
+
"--message <message>",
|
|
488
|
+
"Message body shown in the confirmation prompt",
|
|
489
|
+
)
|
|
490
|
+
.option(
|
|
491
|
+
"--confirm-label <label>",
|
|
492
|
+
'Label for the confirm button (default: "Confirm")',
|
|
493
|
+
"Confirm",
|
|
494
|
+
)
|
|
495
|
+
.option(
|
|
496
|
+
"--deny-label <label>",
|
|
497
|
+
'Label for the deny button (default: "Deny")',
|
|
498
|
+
"Deny",
|
|
499
|
+
)
|
|
500
|
+
.option(
|
|
501
|
+
"--conversation-id <id>",
|
|
502
|
+
"Conversation ID — run 'assistant conversations list' to find it (auto-resolved from skill or bash tool context if omitted)",
|
|
503
|
+
)
|
|
504
|
+
.option(
|
|
505
|
+
"--timeout <ms>",
|
|
506
|
+
"Request timeout in milliseconds",
|
|
507
|
+
String(DEFAULT_REQUEST_TIMEOUT_MS),
|
|
508
|
+
)
|
|
509
|
+
.option("--json", "Output result as machine-readable JSON")
|
|
510
|
+
.addHelpText(
|
|
511
|
+
"after",
|
|
512
|
+
`
|
|
513
|
+
Ergonomic wrapper around "ui request" for binary yes/no gating. Presents
|
|
514
|
+
a confirmation surface to the user and blocks until they respond.
|
|
515
|
+
|
|
516
|
+
Exit codes:
|
|
517
|
+
0 — User confirmed
|
|
518
|
+
1 — User denied, cancelled, or the request timed out
|
|
519
|
+
|
|
520
|
+
The --json flag outputs the full interaction result for scripts that need
|
|
521
|
+
to inspect the response details.
|
|
522
|
+
|
|
523
|
+
Options:
|
|
524
|
+
--title <title> Prompt title
|
|
525
|
+
--message <message> Prompt body text
|
|
526
|
+
--confirm-label <label> Confirm button label (default: "Confirm")
|
|
527
|
+
--deny-label <label> Deny button label (default: "Deny")
|
|
528
|
+
--conversation-id <id> Explicit conversation ID
|
|
529
|
+
--timeout <ms> Request timeout in ms (default: 300000)
|
|
530
|
+
--json Output as JSON
|
|
531
|
+
|
|
532
|
+
Examples:
|
|
533
|
+
$ assistant ui confirm --message "Delete all data?"
|
|
534
|
+
$ assistant ui confirm --title "Deploy" --message "Push to prod?" --json
|
|
535
|
+
$ assistant ui confirm --message "Proceed?" --confirm-label "Yes" --deny-label "No"`,
|
|
536
|
+
)
|
|
537
|
+
.action(
|
|
538
|
+
async (opts: {
|
|
539
|
+
title?: string;
|
|
540
|
+
message?: string;
|
|
541
|
+
confirmLabel?: string;
|
|
542
|
+
denyLabel?: string;
|
|
543
|
+
conversationId?: string;
|
|
544
|
+
timeout?: string;
|
|
545
|
+
json?: boolean;
|
|
546
|
+
}) => {
|
|
547
|
+
// Resolve conversation ID
|
|
548
|
+
let conversationId: string;
|
|
549
|
+
try {
|
|
550
|
+
conversationId = resolveConversationId(opts.conversationId);
|
|
551
|
+
} catch (err) {
|
|
552
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
553
|
+
if (opts.json) {
|
|
554
|
+
process.stdout.write(
|
|
555
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
556
|
+
);
|
|
557
|
+
} else {
|
|
558
|
+
log.error(msg);
|
|
559
|
+
}
|
|
560
|
+
process.exitCode = 1;
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Parse timeout
|
|
565
|
+
const rawTimeout = opts.timeout ?? String(DEFAULT_REQUEST_TIMEOUT_MS);
|
|
566
|
+
const requestTimeoutMs = parseStrictPositiveInt(rawTimeout);
|
|
567
|
+
if (isNaN(requestTimeoutMs) || requestTimeoutMs <= 0) {
|
|
568
|
+
const msg = `Invalid --timeout value "${opts.timeout}". Must be a positive integer (milliseconds).`;
|
|
569
|
+
if (opts.json) {
|
|
570
|
+
process.stdout.write(
|
|
571
|
+
JSON.stringify({ ok: false, error: msg }) + "\n",
|
|
572
|
+
);
|
|
573
|
+
} else {
|
|
574
|
+
log.error(msg);
|
|
575
|
+
}
|
|
576
|
+
process.exitCode = 1;
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Build confirmation surface data
|
|
581
|
+
const confirmLabel = opts.confirmLabel ?? "Confirm";
|
|
582
|
+
const denyLabel = opts.denyLabel ?? "Deny";
|
|
583
|
+
const data: Record<string, unknown> = {};
|
|
584
|
+
if (opts.message) data.message = opts.message;
|
|
585
|
+
// Pass custom labels via data payload so the renderer reads them
|
|
586
|
+
// from ConfirmationSurfaceData.confirmLabel / .cancelLabel.
|
|
587
|
+
data.confirmLabel = confirmLabel;
|
|
588
|
+
data.cancelLabel = denyLabel;
|
|
589
|
+
|
|
590
|
+
// Build IPC params
|
|
591
|
+
const ipcParams: Record<string, unknown> = {
|
|
592
|
+
conversationId,
|
|
593
|
+
surfaceType: "confirmation",
|
|
594
|
+
data,
|
|
595
|
+
actions: [
|
|
596
|
+
{
|
|
597
|
+
id: "confirm",
|
|
598
|
+
label: confirmLabel,
|
|
599
|
+
variant: "primary",
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
id: "deny",
|
|
603
|
+
label: denyLabel,
|
|
604
|
+
variant: "secondary",
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
timeoutMs: requestTimeoutMs,
|
|
608
|
+
};
|
|
609
|
+
if (opts.title) {
|
|
610
|
+
ipcParams.title = opts.title;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Call IPC with timeout budget
|
|
614
|
+
const ipcTimeoutMs = requestTimeoutMs + IPC_TIMEOUT_BUFFER_MS;
|
|
615
|
+
const result = await cliIpcCall<InteractiveUiResult>(
|
|
616
|
+
"ui_request",
|
|
617
|
+
ipcParams,
|
|
618
|
+
{
|
|
619
|
+
timeoutMs: ipcTimeoutMs,
|
|
620
|
+
},
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
if (!result.ok) {
|
|
624
|
+
if (opts.json) {
|
|
625
|
+
process.stdout.write(
|
|
626
|
+
JSON.stringify({ ok: false, error: result.error }) + "\n",
|
|
627
|
+
);
|
|
628
|
+
} else {
|
|
629
|
+
log.error(`Error: ${result.error}`);
|
|
630
|
+
}
|
|
631
|
+
process.exitCode = 1;
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const r = result.result!;
|
|
636
|
+
const confirmed = r.status === "submitted" && r.actionId === "confirm";
|
|
637
|
+
|
|
638
|
+
if (opts.json) {
|
|
639
|
+
const jsonOut: Record<string, unknown> = {
|
|
640
|
+
ok: true,
|
|
641
|
+
confirmed,
|
|
642
|
+
status: r.status,
|
|
643
|
+
actionId: r.actionId,
|
|
644
|
+
surfaceId: r.surfaceId,
|
|
645
|
+
};
|
|
646
|
+
if (r.decisionToken !== undefined) {
|
|
647
|
+
jsonOut.decisionToken = r.decisionToken;
|
|
648
|
+
}
|
|
649
|
+
if (r.summary !== undefined) {
|
|
650
|
+
jsonOut.summary = r.summary;
|
|
651
|
+
}
|
|
652
|
+
process.stdout.write(JSON.stringify(jsonOut) + "\n");
|
|
653
|
+
} else {
|
|
654
|
+
if (confirmed) {
|
|
655
|
+
log.info("Confirmed.");
|
|
656
|
+
} else if (r.status === "timed_out") {
|
|
657
|
+
log.info("Confirmation timed out.");
|
|
658
|
+
} else if (r.status === "cancelled") {
|
|
659
|
+
log.info("Confirmation cancelled.");
|
|
660
|
+
} else {
|
|
661
|
+
log.info("Denied.");
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (!confirmed) {
|
|
666
|
+
process.exitCode = 1;
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
);
|
|
670
|
+
}
|