@vellumai/assistant 0.4.43 → 0.4.45
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 +4 -0
- package/ARCHITECTURE.md +46 -44
- package/README.md +15 -16
- package/bun.lock +10 -35
- package/docs/architecture/integrations.md +102 -215
- package/docs/architecture/keychain-broker.md +1 -1
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/scheduling.md +1 -1
- package/docs/architecture/security.md +11 -11
- package/docs/error-handling.md +1 -1
- package/docs/trusted-contact-access.md +3 -3
- package/drizzle/meta/0000_snapshot.json +34 -100
- package/drizzle/meta/_journal.json +1 -1
- package/drizzle.config.ts +4 -4
- package/package.json +3 -2
- package/scripts/capture-x-graphql.ts +237 -141
- package/scripts/generate-bundled-tool-registry.ts +223 -0
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/actor-token-service.test.ts +23 -24
- package/src/__tests__/agent-loop.test.ts +0 -131
- package/src/__tests__/always-loaded-tools-guard.test.ts +71 -0
- package/src/__tests__/amazon-cdp-integration.test.ts +11 -9
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +11 -3
- package/src/__tests__/asset-materialize-tool.test.ts +0 -1
- package/src/__tests__/asset-search-tool.test.ts +0 -1
- package/src/__tests__/assistant-attachment-directive.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-hardening.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +70 -18
- package/src/__tests__/assistant-id-boundary-guard.test.ts +6 -6
- package/src/__tests__/attachments-store.test.ts +0 -1
- package/src/__tests__/avatar-e2e.test.ts +74 -115
- package/src/__tests__/avatar-router.test.ts +25 -62
- package/src/__tests__/browser-manager.test.ts +24 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +4 -3
- package/src/__tests__/browser-skill-endstate.test.ts +8 -11
- package/src/__tests__/btw-routes.test.ts +326 -0
- package/src/__tests__/bundled-asset.test.ts +1 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +23 -9
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-conversation-messages.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +0 -1
- package/src/__tests__/call-pointer-messages.test.ts +0 -1
- package/src/__tests__/call-recovery.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/call-store.test.ts +0 -1
- package/src/__tests__/canonical-guardian-store.test.ts +0 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +5 -7
- package/src/__tests__/channel-retry-sweep.test.ts +0 -1
- package/src/__tests__/checker.test.ts +32 -36
- package/src/__tests__/compaction.benchmark.test.ts +16 -14
- package/src/__tests__/computer-use-session-lifecycle.test.ts +10 -11
- package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +35 -31
- package/src/__tests__/config-schema.test.ts +11 -15
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conflict-store.test.ts +0 -1
- package/src/__tests__/connection-policy.test.ts +4 -7
- package/src/__tests__/contacts-tools.test.ts +0 -1
- package/src/__tests__/context-memory-e2e.test.ts +2 -4
- package/src/__tests__/context-overflow-reducer.test.ts +2 -4
- package/src/__tests__/context-window-manager.test.ts +147 -60
- package/src/__tests__/contradiction-checker.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +31 -7
- package/src/__tests__/conversation-routes-slash-commands.test.ts +381 -0
- package/src/__tests__/conversation-store.test.ts +0 -1
- package/src/__tests__/conversation-unread-route.test.ts +1 -2
- package/src/__tests__/credential-security-invariants.test.ts +8 -8
- package/src/__tests__/cross-provider-web-search.test.ts +353 -0
- package/src/__tests__/daemon-assistant-events.test.ts +6 -7
- package/src/__tests__/db-schedule-syntax-migration.test.ts +15 -3
- package/src/__tests__/delete-managed-skill-tool.test.ts +5 -9
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
- package/src/__tests__/diagnostics-export.test.ts +189 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/entity-extractor.test.ts +0 -1
- package/src/__tests__/entity-search.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +2 -4
- package/src/__tests__/error-handler-friendly-messages.test.ts +46 -0
- package/src/__tests__/file-read-tool.test.ts +86 -0
- package/src/__tests__/followup-tools.test.ts +0 -1
- package/src/__tests__/frontmatter.test.ts +77 -34
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/gateway-only-guard.test.ts +1 -1
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -1
- package/src/__tests__/guardian-action-store.test.ts +0 -1
- package/src/__tests__/guardian-action-sweep.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +0 -1
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +1 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +3 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +28 -426
- package/src/__tests__/host-bash-proxy.test.ts +335 -0
- package/src/__tests__/host-file-proxy.test.ts +374 -0
- package/src/__tests__/host-shell-tool.test.ts +147 -1
- package/src/__tests__/http-user-message-parity.test.ts +361 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
- package/src/__tests__/integration-status.test.ts +3 -8
- package/src/__tests__/intent-routing.test.ts +7 -46
- package/src/__tests__/invite-redemption-service.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +0 -1
- package/src/__tests__/llm-usage-store.test.ts +0 -1
- package/src/__tests__/managed-avatar-client.test.ts +101 -55
- package/src/__tests__/managed-skill-lifecycle.test.ts +9 -18
- package/src/__tests__/managed-store.test.ts +94 -21
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +2 -4
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -1
- package/src/__tests__/memory-recall-quality.test.ts +0 -1
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -1
- package/src/__tests__/memory-regressions.test.ts +0 -1
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +0 -1
- package/src/__tests__/messaging-send-tool.test.ts +35 -0
- package/src/__tests__/messaging-skill-split.test.ts +138 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
- package/src/__tests__/migration-export-http.test.ts +2 -3
- package/src/__tests__/migration-import-commit-http.test.ts +1 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -2
- package/src/__tests__/migration-validate-http.test.ts +1 -2
- package/src/__tests__/native-web-search.test.ts +475 -0
- package/src/__tests__/navigate-settings-tab.test.ts +84 -0
- package/src/__tests__/non-member-access-request.test.ts +0 -1
- package/src/__tests__/notification-broadcaster.test.ts +15 -15
- package/src/__tests__/notification-decision-strategy.test.ts +6 -6
- package/src/__tests__/notification-deep-link.test.ts +7 -7
- package/src/__tests__/notification-guardian-path.test.ts +2 -3
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -1
- package/src/__tests__/notification-thread-candidates.test.ts +4 -4
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +0 -10
- package/src/__tests__/playbook-execution.test.ts +0 -1
- package/src/__tests__/playbook-tools.test.ts +0 -1
- package/src/__tests__/profile-compiler.test.ts +0 -1
- package/src/__tests__/provider-fail-open-selection.test.ts +12 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +25 -0
- package/src/__tests__/qdrant-collection-migration.test.ts +223 -0
- package/src/__tests__/recording-handler.test.ts +30 -94
- package/src/__tests__/registry.test.ts +28 -35
- package/src/__tests__/relay-server.test.ts +0 -1
- package/src/__tests__/ride-shotgun-handler.test.ts +4 -20
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +0 -1
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +30 -28
- package/src/__tests__/schedule-store.test.ts +441 -1
- package/src/__tests__/schedule-tools.test.ts +468 -7
- package/src/__tests__/scheduler-recurrence.test.ts +196 -23
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +6 -3
- package/src/__tests__/secret-response-routing.test.ts +4 -1
- package/src/__tests__/send-endpoint-busy.test.ts +14 -5
- package/src/__tests__/send-notification-tool.test.ts +0 -7
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/server-history-render.test.ts +1 -2
- package/src/__tests__/session-abort-tool-results.test.ts +0 -1
- package/src/__tests__/session-agent-loop.test.ts +46 -6
- package/src/__tests__/session-confirmation-signals.test.ts +7 -46
- package/src/__tests__/session-conflict-gate.test.ts +2 -6
- package/src/__tests__/session-error.test.ts +5 -14
- package/src/__tests__/session-init.benchmark.test.ts +3 -5
- package/src/__tests__/session-load-history-repair.test.ts +0 -1
- package/src/__tests__/session-media-retry.test.ts +12 -74
- package/src/__tests__/session-pre-run-repair.test.ts +0 -1
- package/src/__tests__/session-profile-injection.test.ts +2 -6
- package/src/__tests__/session-provider-retry-repair.test.ts +2 -6
- package/src/__tests__/session-queue.test.ts +94 -139
- package/src/__tests__/session-skill-tools.test.ts +115 -115
- package/src/__tests__/session-slash-known.test.ts +0 -1
- package/src/__tests__/session-slash-queue.test.ts +0 -1
- package/src/__tests__/session-slash-unknown.test.ts +0 -1
- package/src/__tests__/session-surfaces-task-progress.test.ts +34 -0
- package/src/__tests__/session-usage.test.ts +0 -1
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -6
- package/src/__tests__/session-workspace-injection.test.ts +2 -6
- package/src/__tests__/session-workspace-tool-tracking.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +180 -184
- package/src/__tests__/skill-feature-flags.test.ts +125 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -2
- package/src/__tests__/skill-load-tool.test.ts +194 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +27 -16
- package/src/__tests__/skill-projection.benchmark.test.ts +15 -14
- package/src/__tests__/skills.test.ts +14 -53
- package/src/__tests__/slack-channel-config.test.ts +0 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -1
- package/src/__tests__/slack-skill.test.ts +1 -1
- package/src/__tests__/starter-task-flow.test.ts +9 -19
- package/src/__tests__/subagent-tools.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +7 -7
- package/src/__tests__/task-compiler.test.ts +0 -1
- package/src/__tests__/task-management-tools.test.ts +0 -1
- package/src/__tests__/task-memory-cleanup.test.ts +0 -1
- package/src/__tests__/task-runner.test.ts +0 -1
- package/src/__tests__/task-scheduler.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +0 -1
- package/src/__tests__/test-support/computer-use-skill-harness.ts +2 -4
- package/src/__tests__/thread-seed-composer.test.ts +5 -5
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +8 -86
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/tool-notification-listener.test.ts +1 -1
- package/src/__tests__/tool-preview-lifecycle.test.ts +416 -0
- package/src/__tests__/trust-store.test.ts +84 -8
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/trusted-contact-verification.test.ts +0 -1
- package/src/__tests__/twilio-provider.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/{request-file-tool.test.ts → ui-file-upload-surface.test.ts} +11 -72
- package/src/__tests__/update-bulletin.test.ts +0 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -1
- package/src/__tests__/usage-routes.test.ts +0 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -4
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/__tests__/voice-session-bridge.test.ts +9 -1
- package/src/__tests__/web-fetch.test.ts +57 -0
- package/src/__tests__/workspace-git-service.test.ts +5 -14
- package/src/__tests__/workspace-policy.test.ts +0 -1
- package/src/agent/loop.ts +22 -34
- package/src/bundler/bundle-signer.ts +4 -4
- package/src/calls/call-controller.ts +1 -1
- package/src/calls/relay-server.ts +1 -1
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/voice-session-bridge.ts +3 -1
- package/src/cli/__tests__/notifications.test.ts +3 -4
- package/src/cli/commands/map.ts +2 -6
- package/src/cli/commands/mcp.ts +73 -15
- package/src/cli/commands/notifications.ts +4 -4
- package/src/cli/commands/sessions.ts +9 -1
- package/src/cli/commands/skills.ts +6 -10
- package/src/cli/http-client.ts +2 -3
- package/src/cli/main-screen.tsx +10 -10
- package/src/cli/program.ts +0 -4
- package/src/cli/reference.ts +0 -2
- package/src/cli.ts +15 -9
- package/src/config/__tests__/bundled-tool-registry-guard.test.ts +120 -0
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +11 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +6 -7
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -4
- package/src/config/bundled-skills/browser/SKILL.md +6 -1
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +5 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -69
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +10 -1
- package/src/config/bundled-skills/contacts/SKILL.md +10 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +35 -0
- package/src/config/bundled-skills/{messaging → contacts}/tools/google-contacts.ts +9 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -1
- package/src/config/bundled-skills/doordash/SKILL.md +8 -2
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +1 -82
- package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -28
- package/src/config/bundled-skills/doordash/lib/session.ts +21 -17
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +4 -1
- package/src/config/bundled-skills/followups/SKILL.md +4 -1
- package/src/config/bundled-skills/gmail/SKILL.md +180 -0
- package/src/config/bundled-skills/gmail/TOOLS.json +506 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +149 -0
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +110 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +50 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-outreach-scan.ts +8 -90
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-sender-digest.ts +2 -2
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/shared.ts +47 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +5 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -1
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -1
- package/src/config/bundled-skills/media-processing/SKILL.md +7 -13
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -22
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +12 -1
- package/src/config/bundled-skills/messaging/SKILL.md +23 -139
- package/src/config/bundled-skills/messaging/TOOLS.json +33 -1215
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +42 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +165 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +1 -13
- package/src/config/bundled-skills/messaging/tools/shared.ts +81 -34
- package/src/config/bundled-skills/notifications/SKILL.md +5 -1
- package/src/config/bundled-skills/orchestration/SKILL.md +30 -0
- package/src/config/bundled-skills/orchestration/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-cancel.ts → orchestration/tools/swarm-delegate.ts} +3 -3
- package/src/config/bundled-skills/phone-calls/SKILL.md +9 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +4 -1
- package/src/config/bundled-skills/schedule/SKILL.md +70 -9
- package/src/config/bundled-skills/schedule/TOOLS.json +38 -6
- package/src/config/bundled-skills/screen-watch/SKILL.md +28 -0
- package/src/config/bundled-skills/screen-watch/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-create.ts → screen-watch/tools/start-screen-watch.ts} +3 -3
- package/src/config/bundled-skills/sequences/SKILL.md +47 -0
- package/src/config/bundled-skills/sequences/TOOLS.json +340 -0
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +128 -0
- package/src/config/bundled-skills/sequences/tools/shared.ts +9 -0
- package/src/config/bundled-skills/settings/SKILL.md +12 -0
- package/src/config/bundled-skills/settings/TOOLS.json +112 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +43 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +52 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-right-click.ts → settings/tools/set-avatar.ts} +2 -6
- package/src/{tools/system/voice-config.ts → config/bundled-skills/settings/tools/voice-config-update.ts} +59 -96
- package/src/config/bundled-skills/skill-management/SKILL.md +18 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +90 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-double-click.ts → skill-management/tools/delete-managed.ts} +2 -6
- package/src/config/bundled-skills/skill-management/tools/scaffold-managed.ts +12 -0
- package/src/config/bundled-skills/slack/SKILL.md +5 -1
- package/src/config/bundled-skills/subagent/SKILL.md +4 -1
- package/src/config/bundled-skills/tasks/SKILL.md +5 -2
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -1
- package/src/config/bundled-skills/watcher/SKILL.md +4 -1
- package/src/config/bundled-tool-registry.ts +118 -107
- package/src/config/env.ts +5 -2
- package/src/config/feature-flag-registry.json +33 -9
- package/src/config/loader.ts +10 -2
- package/src/config/schema.ts +19 -16
- package/src/config/schemas/inference.ts +12 -22
- package/src/config/schemas/memory-storage.ts +19 -1
- package/src/config/schemas/platform.ts +0 -16
- package/src/config/skill-state.ts +11 -8
- package/src/config/skills.ts +83 -32
- package/src/context/token-estimator.ts +11 -0
- package/src/context/window-manager.ts +180 -151
- package/src/daemon/computer-use-session.ts +11 -43
- package/src/daemon/daemon-control.ts +4 -1
- package/src/daemon/handlers/config-channels.ts +5 -9
- package/src/daemon/handlers/config-ingress.ts +0 -4
- package/src/daemon/handlers/config-model.ts +7 -13
- package/src/daemon/handlers/config-telegram.ts +4 -8
- package/src/daemon/handlers/config-voice.ts +2 -5
- package/src/daemon/handlers/dictation.ts +2 -12
- package/src/daemon/handlers/identity.ts +0 -105
- package/src/daemon/handlers/recording.ts +3 -23
- package/src/daemon/handlers/session-history.ts +42 -10
- package/src/daemon/handlers/sessions.ts +53 -72
- package/src/daemon/handlers/shared.ts +7 -28
- package/src/daemon/handlers/skills.ts +31 -27
- package/src/daemon/host-bash-proxy.ts +148 -0
- package/src/daemon/host-file-proxy.ts +135 -0
- package/src/daemon/lifecycle.ts +53 -41
- package/src/daemon/mcp-reload-service.ts +123 -0
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/apps.ts +0 -25
- package/src/daemon/message-types/browser.ts +1 -1
- package/src/daemon/message-types/computer-use.ts +1 -4
- package/src/daemon/message-types/guardian-actions.ts +1 -1
- package/src/daemon/message-types/host-bash.ts +18 -0
- package/src/daemon/message-types/host-file.ts +44 -0
- package/src/daemon/message-types/integrations.ts +1 -73
- package/src/daemon/message-types/messages.ts +15 -0
- package/src/daemon/message-types/schedules.ts +11 -27
- package/src/daemon/message-types/sessions.ts +8 -2
- package/src/daemon/message-types/settings.ts +1 -1
- package/src/daemon/message-types/shared.ts +1 -1
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/ride-shotgun-handler.ts +35 -43
- package/src/daemon/seed-files.ts +3 -27
- package/src/daemon/server.ts +45 -28
- package/src/daemon/session-agent-loop-handlers.ts +72 -9
- package/src/daemon/session-agent-loop.ts +97 -66
- package/src/daemon/session-attachments.ts +1 -1
- package/src/daemon/session-error.ts +17 -16
- package/src/daemon/session-lifecycle.ts +20 -1
- package/src/daemon/session-media-retry.ts +1 -15
- package/src/daemon/session-messaging.ts +14 -6
- package/src/daemon/session-process.ts +36 -7
- package/src/daemon/session-queue-manager.ts +62 -103
- package/src/daemon/session-runtime-assembly.ts +27 -7
- package/src/daemon/session-skill-tools.ts +12 -11
- package/src/daemon/session-slash.ts +7 -0
- package/src/daemon/session-surfaces.ts +192 -118
- package/src/daemon/session-tool-setup.ts +146 -6
- package/src/daemon/session.ts +75 -37
- package/src/errors.ts +0 -2
- package/src/export/formatter.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +1 -3
- package/src/media/avatar-router.ts +20 -28
- package/src/media/avatar-types.ts +7 -14
- package/src/media/managed-avatar-client.ts +70 -34
- package/src/memory/app-store.ts +0 -18
- package/src/memory/conversation-title-service.ts +1 -2
- package/src/memory/db-init.ts +16 -0
- package/src/memory/embedding-backend.ts +129 -27
- package/src/memory/embedding-gemini.test.ts +256 -0
- package/src/memory/embedding-gemini.ts +47 -13
- package/src/memory/embedding-local.ts +14 -2
- package/src/memory/embedding-ollama.ts +15 -2
- package/src/memory/embedding-openai.ts +15 -2
- package/src/memory/embedding-types.test.ts +116 -0
- package/src/memory/embedding-types.ts +61 -0
- package/src/memory/fingerprint.ts +1 -1
- package/src/memory/indexer.ts +25 -1
- package/src/memory/job-handlers/embedding.test.ts +258 -0
- package/src/memory/job-handlers/embedding.ts +81 -1
- package/src/memory/job-handlers/index-maintenance.ts +35 -1
- package/src/memory/job-handlers/media-processing.ts +11 -1
- package/src/memory/job-utils.ts +21 -6
- package/src/memory/jobs-store.ts +5 -1
- package/src/memory/jobs-worker.ts +8 -0
- package/src/memory/message-content.ts +66 -0
- package/src/memory/migrations/100-core-tables.ts +1 -31
- package/src/memory/migrations/104-core-indexes.ts +0 -11
- package/src/memory/migrations/145-drop-accounts-table.ts +19 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +94 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +129 -0
- package/src/memory/migrations/148-drop-reminders-table.ts +18 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +19 -0
- package/src/memory/qdrant-client.ts +158 -43
- package/src/memory/retriever.test.ts +0 -1
- package/src/memory/retriever.ts +12 -2
- package/src/memory/schema/infrastructure.ts +5 -37
- package/src/memory/search/formatting.ts +34 -9
- package/src/memory/search/semantic.ts +57 -2
- package/src/memory/search/types.ts +2 -1
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +59 -58
- package/src/notifications/adapters/macos.ts +1 -1
- package/src/notifications/broadcaster.ts +5 -5
- package/src/notifications/copy-composer.ts +1 -1
- package/src/notifications/decision-engine.ts +2 -2
- package/src/notifications/destination-resolver.ts +2 -2
- package/src/notifications/emit-signal.ts +8 -8
- package/src/notifications/signal.ts +1 -1
- package/src/notifications/thread-seed-composer.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +1 -1
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +12 -1
- package/src/permissions/defaults.ts +13 -17
- package/src/permissions/trust-store.ts +37 -0
- package/src/permissions/workspace-policy.ts +0 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +11 -0
- package/src/prompts/computer-use-prompt.ts +1 -1
- package/src/prompts/system-prompt.ts +33 -35
- package/src/prompts/templates/BOOTSTRAP.md +0 -3
- package/src/prompts/templates/SOUL.md +1 -2
- package/src/prompts/templates/UPDATES.md +16 -7
- package/src/providers/anthropic/client.ts +87 -33
- package/src/providers/gemini/client.ts +6 -0
- package/src/providers/managed-proxy/constants.ts +5 -0
- package/src/providers/openai/client.ts +15 -0
- package/src/providers/registry.ts +4 -6
- package/src/providers/types.ts +24 -2
- package/src/runtime/AGENTS.md +18 -0
- package/src/runtime/assistant-event-hub.ts +2 -3
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/auth/__tests__/context.test.ts +5 -5
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +3 -2
- package/src/runtime/auth/__tests__/{ipc-auth-context.test.ts → local-auth-context.test.ts} +21 -21
- package/src/runtime/auth/__tests__/route-policy.test.ts +2 -2
- package/src/runtime/auth/__tests__/scopes.test.ts +9 -8
- package/src/runtime/auth/__tests__/subject.test.ts +8 -8
- package/src/runtime/auth/__tests__/token-service.test.ts +0 -1
- package/src/runtime/auth/route-policy.ts +8 -8
- package/src/runtime/auth/scopes.ts +2 -1
- package/src/runtime/auth/subject.ts +4 -4
- package/src/runtime/auth/token-service.ts +1 -24
- package/src/runtime/auth/types.ts +3 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-action-grant-minter.ts +1 -1
- package/src/runtime/guardian-action-service.ts +3 -3
- package/src/runtime/http-server.ts +15 -2
- package/src/runtime/http-types.ts +10 -0
- package/src/runtime/invite-service.ts +3 -3
- package/src/runtime/local-actor-identity.ts +17 -22
- package/src/runtime/middleware/error-handler.ts +14 -1
- package/src/runtime/pending-interactions.ts +21 -9
- package/src/runtime/routes/app-management-routes.ts +63 -67
- package/src/runtime/routes/approval-routes.ts +1 -3
- package/src/runtime/routes/brain-graph/brain-graph.html +1845 -0
- package/src/runtime/routes/brain-graph-routes.ts +4 -42
- package/src/runtime/routes/btw-routes.ts +155 -0
- package/src/runtime/routes/computer-use-routes.ts +77 -31
- package/src/runtime/routes/conversation-routes.ts +234 -47
- package/src/runtime/routes/diagnostics-routes.ts +154 -43
- package/src/runtime/routes/documents-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/host-bash-routes.ts +83 -0
- package/src/runtime/routes/host-file-routes.ts +79 -0
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +120 -0
- package/src/runtime/routes/mcp-routes.ts +20 -0
- package/src/runtime/routes/migration-routes.ts +3 -3
- package/src/runtime/routes/pairing-routes.ts +1 -1
- package/src/runtime/routes/recording-routes.ts +6 -4
- package/src/runtime/routes/schedule-routes.ts +31 -5
- package/src/runtime/routes/session-management-routes.ts +2 -6
- package/src/runtime/routes/session-query-routes.ts +18 -15
- package/src/runtime/routes/settings-routes.ts +7 -351
- package/src/runtime/routes/skills-routes.ts +7 -6
- package/src/runtime/routes/subagents-routes.ts +4 -10
- package/src/runtime/routes/surface-action-routes.ts +3 -14
- package/src/runtime/routes/surface-content-routes.ts +22 -5
- package/src/runtime/routes/work-items-routes.ts +21 -25
- package/src/runtime/routes/workspace-routes.test.ts +3 -3
- package/src/runtime/routes/workspace-utils.ts +1 -1
- package/src/runtime/telegram-streaming-delivery.ts +3 -0
- package/src/runtime/verification-outbound-actions.ts +2 -2
- package/src/schedule/integration-status.ts +0 -6
- package/src/schedule/schedule-store.ts +234 -43
- package/src/schedule/scheduler.ts +73 -74
- package/src/security/oauth2.ts +1 -1
- package/src/sequence/store.ts +12 -2
- package/src/skills/frontmatter.ts +19 -77
- package/src/skills/managed-store.ts +11 -2
- package/src/subagent/manager.ts +5 -3
- package/src/tasks/ephemeral-permissions.ts +3 -5
- package/src/tools/AGENTS.md +37 -0
- package/src/tools/apps/executors.ts +0 -6
- package/src/tools/browser/browser-manager.ts +17 -11
- package/src/tools/browser/jit-auth.ts +4 -1
- package/src/tools/claude-code/claude-code.ts +1 -1
- package/src/tools/computer-use/definitions.ts +48 -60
- package/src/tools/document/document-tool.ts +6 -6
- package/src/tools/document/editor-template.ts +10 -8
- package/src/tools/filesystem/edit.ts +2 -1
- package/src/tools/filesystem/read.ts +20 -2
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +17 -1
- package/src/tools/host-filesystem/read.ts +16 -1
- package/src/tools/host-filesystem/write.ts +15 -1
- package/src/tools/host-terminal/host-shell.ts +24 -0
- package/src/tools/memory/definitions.ts +45 -81
- package/src/tools/memory/handlers.test.ts +0 -1
- package/src/tools/memory/handlers.ts +1 -1
- package/src/tools/memory/register.ts +26 -60
- package/src/tools/network/script-proxy/session-manager.ts +6 -8
- package/src/tools/network/web-fetch.ts +7 -1
- package/src/tools/network/web-search.ts +2 -1
- package/src/tools/registry.ts +23 -0
- package/src/tools/schedule/create.ts +113 -5
- package/src/tools/schedule/list.ts +57 -15
- package/src/tools/schedule/update.ts +73 -3
- package/src/tools/shared/filesystem/image-read.ts +192 -0
- package/src/tools/side-effects.ts +1 -7
- package/src/tools/skills/delete-managed.ts +27 -64
- package/src/tools/skills/execute.ts +54 -0
- package/src/tools/skills/load.ts +127 -5
- package/src/tools/skills/scaffold-managed.ts +93 -172
- package/src/tools/subagent/message.ts +0 -7
- package/src/tools/subagent/spawn.ts +1 -1
- package/src/tools/swarm/delegate.ts +0 -3
- package/src/tools/system/avatar-generator.ts +13 -19
- package/src/tools/system/request-permission.ts +2 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +41 -47
- package/src/tools/types.ts +6 -2
- package/src/tools/ui-surface/definitions.ts +0 -55
- package/src/util/errors.ts +12 -10
- package/src/workspace/git-service.ts +0 -2
- package/src/__tests__/account-registry.test.ts +0 -258
- package/src/__tests__/email-classifier.test.ts +0 -25
- package/src/__tests__/gmail-integration.test.ts +0 -97
- package/src/__tests__/handle-user-message-secret-resume.test.ts +0 -172
- package/src/__tests__/home-base-bootstrap.test.ts +0 -84
- package/src/__tests__/managed-twitter-guardrails.test.ts +0 -353
- package/src/__tests__/prebuilt-home-base-seed.test.ts +0 -79
- package/src/__tests__/recording-intent-fallback.test.ts +0 -199
- package/src/__tests__/recording-intent.test.ts +0 -985
- package/src/__tests__/recording-state-machine.test.ts +0 -1574
- package/src/__tests__/reminder-store.test.ts +0 -350
- package/src/__tests__/reminder.test.ts +0 -337
- package/src/__tests__/scan-result-store.test.ts +0 -121
- package/src/__tests__/twitter-platform-proxy-client.test.ts +0 -450
- package/src/__tests__/view-image-tool.test.ts +0 -241
- package/src/cli/commands/amazon/cart.ts +0 -513
- package/src/cli/commands/amazon/checkout.ts +0 -394
- package/src/cli/commands/amazon/client.ts +0 -513
- package/src/cli/commands/amazon/index.ts +0 -920
- package/src/cli/commands/amazon/product-details.ts +0 -145
- package/src/cli/commands/amazon/request-extractor.ts +0 -187
- package/src/cli/commands/amazon/search.ts +0 -76
- package/src/cli/commands/amazon/session.ts +0 -116
- package/src/cli/commands/twitter/__tests__/cli-error-shaping.test.ts +0 -265
- package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +0 -483
- package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +0 -412
- package/src/cli/commands/twitter/__tests__/oauth-client.test.ts +0 -197
- package/src/cli/commands/twitter/client.ts +0 -989
- package/src/cli/commands/twitter/index.ts +0 -1160
- package/src/cli/commands/twitter/oauth-client.ts +0 -94
- package/src/cli/commands/twitter/router.ts +0 -396
- package/src/cli/commands/twitter/session.ts +0 -121
- package/src/config/bundled-skills/agentmail/SKILL.md +0 -132
- package/src/config/bundled-skills/agentmail/icon.svg +0 -21
- package/src/config/bundled-skills/amazon/SKILL.md +0 -137
- package/src/config/bundled-skills/amazon/icon.svg +0 -13
- package/src/config/bundled-skills/api-mapping/SKILL.md +0 -78
- package/src/config/bundled-skills/api-mapping/icon.svg +0 -18
- package/src/config/bundled-skills/cli-discover/SKILL.md +0 -68
- package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +0 -179
- package/src/config/bundled-skills/document-writer/SKILL.md +0 -195
- package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +0 -140
- package/src/config/bundled-skills/email-setup/SKILL.md +0 -68
- package/src/config/bundled-skills/frontend-design/SKILL.md +0 -44
- package/src/config/bundled-skills/frontend-design/icon.svg +0 -16
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +0 -452
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +0 -203
- package/src/config/bundled-skills/influencer/SKILL.md +0 -144
- package/src/config/bundled-skills/influencer/scripts/client.ts +0 -1269
- package/src/config/bundled-skills/influencer/scripts/influencer.ts +0 -267
- package/src/config/bundled-skills/macos-automation/SKILL.md +0 -65
- package/src/config/bundled-skills/macos-automation/icon.svg +0 -12
- package/src/config/bundled-skills/mcp-setup/SKILL.md +0 -75
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +0 -184
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +0 -80
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +0 -29
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +0 -56
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +0 -34
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +0 -47
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +0 -31
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +0 -67
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +0 -97
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +0 -135
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +0 -24
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +0 -201
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +0 -1
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +0 -48
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +0 -56
- package/src/config/bundled-skills/notion/SKILL.md +0 -240
- package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +0 -126
- package/src/config/bundled-skills/oauth-setup/SKILL.md +0 -143
- package/src/config/bundled-skills/public-ingress/SKILL.md +0 -258
- package/src/config/bundled-skills/reminder/SKILL.md +0 -79
- package/src/config/bundled-skills/reminder/TOOLS.json +0 -89
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +0 -12
- package/src/config/bundled-skills/restaurant-reservation/SKILL.md +0 -141
- package/src/config/bundled-skills/screen-recording/SKILL.md +0 -148
- package/src/config/bundled-skills/self-upgrade/SKILL.md +0 -69
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -78
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +0 -178
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +0 -163
- package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +0 -157
- package/src/config/bundled-skills/start-the-day/SKILL.md +0 -70
- package/src/config/bundled-skills/start-the-day/icon.svg +0 -13
- package/src/config/bundled-skills/telegram-setup/SKILL.md +0 -105
- package/src/config/bundled-skills/time-based-actions/SKILL.md +0 -142
- package/src/config/bundled-skills/twilio-setup/SKILL.md +0 -232
- package/src/config/bundled-skills/twitter/SKILL.md +0 -319
- package/src/config/bundled-skills/twitter/icon.svg +0 -14
- package/src/config/bundled-skills/typescript-eval/SKILL.md +0 -60
- package/src/config/bundled-skills/vercel-token-setup/SKILL.md +0 -214
- package/src/config/bundled-skills/voice-setup/SKILL.md +0 -131
- package/src/config/bundled-skills/voice-setup/icon.svg +0 -20
- package/src/daemon/handlers/pairing.ts +0 -119
- package/src/daemon/handlers/session-user-message.ts +0 -961
- package/src/daemon/recording-executor.ts +0 -180
- package/src/daemon/recording-intent-fallback.ts +0 -162
- package/src/daemon/recording-intent.ts +0 -493
- package/src/home-base/app-link-store.ts +0 -78
- package/src/home-base/bootstrap.ts +0 -74
- package/src/home-base/prebuilt/brain-graph.html +0 -1483
- package/src/home-base/prebuilt/index.html +0 -702
- package/src/home-base/prebuilt/seed-metadata.json +0 -21
- package/src/home-base/prebuilt/seed.ts +0 -122
- package/src/home-base/prebuilt-home-base-updater.ts +0 -36
- package/src/memory/account-store.ts +0 -117
- package/src/messaging/activity-analyzer.ts +0 -76
- package/src/messaging/email-classifier.ts +0 -208
- package/src/messaging/index.ts +0 -2
- package/src/messaging/outreach-classifier.ts +0 -185
- package/src/messaging/thread-summarizer.ts +0 -346
- package/src/messaging/types.ts +0 -17
- package/src/tools/browser/x-auto-navigate.ts +0 -254
- package/src/tools/credentials/account-registry.ts +0 -144
- package/src/tools/filesystem/view-image.ts +0 -244
- package/src/tools/reminder/reminder-store.ts +0 -194
- package/src/tools/reminder/reminder.ts +0 -158
- package/src/tools/system/navigate-settings.ts +0 -74
- package/src/tools/system/open-system-settings.ts +0 -85
- package/src/tools/system/version.ts +0 -54
- package/src/twitter/platform-proxy-client.ts +0 -405
- package/src/util/cookie-session.ts +0 -98
- /package/src/config/bundled-skills/{messaging → gmail}/tools/scan-result-store.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-analytics.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-create.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-delete.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enroll.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enrollment-list.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-get.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-import.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-list.ts +0 -0
|
@@ -1,985 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type RecordingIntentResult as _RecordingIntentResult,
|
|
5
|
-
resolveRecordingIntent,
|
|
6
|
-
} from "../daemon/recording-intent.js";
|
|
7
|
-
|
|
8
|
-
// ─── resolveRecordingIntent ─────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
describe("resolveRecordingIntent", () => {
|
|
11
|
-
// ── Start detection (covers legacy detectRecordingIntent behavior) ───────
|
|
12
|
-
|
|
13
|
-
describe("start intent detection", () => {
|
|
14
|
-
test.each([
|
|
15
|
-
"record my screen",
|
|
16
|
-
"Record My Screen",
|
|
17
|
-
"record the screen",
|
|
18
|
-
"screen recording",
|
|
19
|
-
"screen record",
|
|
20
|
-
"start recording",
|
|
21
|
-
"begin recording",
|
|
22
|
-
"capture my screen",
|
|
23
|
-
"capture my display",
|
|
24
|
-
"capture screen",
|
|
25
|
-
"make a recording",
|
|
26
|
-
])('detects start intent in "%s"', (text) => {
|
|
27
|
-
const result = resolveRecordingIntent(text);
|
|
28
|
-
expect(result.kind).toBe("start_only");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// "make a screen recording" is detected as recording intent but resolves
|
|
32
|
-
// to start_with_remainder because the strip patterns match "screen recording"
|
|
33
|
-
// first, leaving "make a" as residual text.
|
|
34
|
-
test('detects start intent in "make a screen recording" (with residual remainder)', () => {
|
|
35
|
-
const result = resolveRecordingIntent("make a screen recording");
|
|
36
|
-
expect(result.kind).toBe("start_with_remainder");
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test.each([
|
|
40
|
-
"",
|
|
41
|
-
"hello world",
|
|
42
|
-
"open Safari",
|
|
43
|
-
"take a screenshot",
|
|
44
|
-
"what time is it?",
|
|
45
|
-
"record a note",
|
|
46
|
-
"make a note",
|
|
47
|
-
"start the timer",
|
|
48
|
-
])('does not detect start intent in "%s"', (text) => {
|
|
49
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "none" });
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("is case-insensitive", () => {
|
|
53
|
-
expect(resolveRecordingIntent("RECORD MY SCREEN").kind).toBe(
|
|
54
|
-
"start_only",
|
|
55
|
-
);
|
|
56
|
-
expect(resolveRecordingIntent("Screen Recording").kind).toBe(
|
|
57
|
-
"start_only",
|
|
58
|
-
);
|
|
59
|
-
expect(resolveRecordingIntent("START RECORDING").kind).toBe("start_only");
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// ── Pure start (covers legacy isRecordingOnly behavior) ─────────────────
|
|
64
|
-
|
|
65
|
-
describe("pure start (recording-only)", () => {
|
|
66
|
-
test.each([
|
|
67
|
-
"record my screen",
|
|
68
|
-
"Record my screen",
|
|
69
|
-
"start recording",
|
|
70
|
-
"screen recording",
|
|
71
|
-
"begin recording",
|
|
72
|
-
"capture my screen",
|
|
73
|
-
"make a recording",
|
|
74
|
-
])('resolves as start_only for pure recording request "%s"', (text) => {
|
|
75
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "start_only" });
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("resolves as start_only when polite fillers surround the recording request", () => {
|
|
79
|
-
expect(resolveRecordingIntent("please record my screen")).toEqual({
|
|
80
|
-
kind: "start_only",
|
|
81
|
-
});
|
|
82
|
-
expect(resolveRecordingIntent("can you start recording")).toEqual({
|
|
83
|
-
kind: "start_only",
|
|
84
|
-
});
|
|
85
|
-
expect(
|
|
86
|
-
resolveRecordingIntent("could you record my screen please"),
|
|
87
|
-
).toEqual({ kind: "start_only" });
|
|
88
|
-
expect(resolveRecordingIntent("hey, start recording now")).toEqual({
|
|
89
|
-
kind: "start_only",
|
|
90
|
-
});
|
|
91
|
-
expect(resolveRecordingIntent("just record my screen, thanks")).toEqual({
|
|
92
|
-
kind: "start_only",
|
|
93
|
-
});
|
|
94
|
-
expect(resolveRecordingIntent("can you start recording?")).toEqual({
|
|
95
|
-
kind: "start_only",
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test.each([
|
|
100
|
-
"record my screen and then open Safari",
|
|
101
|
-
"do this task and record my screen",
|
|
102
|
-
"record my screen while I work on the document",
|
|
103
|
-
"open Chrome and start recording",
|
|
104
|
-
"record my screen and send it to Bob",
|
|
105
|
-
])('resolves as start_with_remainder for mixed-intent "%s"', (text) => {
|
|
106
|
-
expect(resolveRecordingIntent(text).kind).toBe("start_with_remainder");
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("handles punctuation in recording-only prompts", () => {
|
|
110
|
-
expect(resolveRecordingIntent("record my screen!")).toEqual({
|
|
111
|
-
kind: "start_only",
|
|
112
|
-
});
|
|
113
|
-
expect(resolveRecordingIntent("start recording.")).toEqual({
|
|
114
|
-
kind: "start_only",
|
|
115
|
-
});
|
|
116
|
-
expect(resolveRecordingIntent("screen recording?")).toEqual({
|
|
117
|
-
kind: "start_only",
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// ── Stop detection (covers legacy detectStopRecordingIntent behavior) ───
|
|
123
|
-
|
|
124
|
-
describe("stop intent detection", () => {
|
|
125
|
-
test.each([
|
|
126
|
-
"stop recording",
|
|
127
|
-
"stop the recording",
|
|
128
|
-
"end recording",
|
|
129
|
-
"end the recording",
|
|
130
|
-
"finish recording",
|
|
131
|
-
"finish the recording",
|
|
132
|
-
"halt recording",
|
|
133
|
-
"halt the recording",
|
|
134
|
-
])('detects stop intent in "%s"', (text) => {
|
|
135
|
-
expect(resolveRecordingIntent(text).kind).toBe("stop_only");
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test.each([
|
|
139
|
-
"",
|
|
140
|
-
"hello world",
|
|
141
|
-
"stop it",
|
|
142
|
-
"end it",
|
|
143
|
-
"quit",
|
|
144
|
-
"take a screenshot",
|
|
145
|
-
"stop the music",
|
|
146
|
-
])('does not detect stop intent in "%s"', (text) => {
|
|
147
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "none" });
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test("is case-insensitive", () => {
|
|
151
|
-
expect(resolveRecordingIntent("STOP RECORDING").kind).toBe("stop_only");
|
|
152
|
-
expect(resolveRecordingIntent("Stop The Recording").kind).toBe(
|
|
153
|
-
"stop_only",
|
|
154
|
-
);
|
|
155
|
-
expect(resolveRecordingIntent("END RECORDING").kind).toBe("stop_only");
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// ── Pure stop (covers legacy isStopRecordingOnly behavior) ──────────────
|
|
160
|
-
|
|
161
|
-
describe("pure stop (stop-recording-only)", () => {
|
|
162
|
-
test.each([
|
|
163
|
-
"stop recording",
|
|
164
|
-
"stop the recording",
|
|
165
|
-
"end recording",
|
|
166
|
-
"end the recording",
|
|
167
|
-
"finish recording",
|
|
168
|
-
"halt recording",
|
|
169
|
-
])('resolves as stop_only for pure stop request "%s"', (text) => {
|
|
170
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "stop_only" });
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("resolves as stop_only when polite fillers surround the stop request", () => {
|
|
174
|
-
expect(resolveRecordingIntent("please stop recording")).toEqual({
|
|
175
|
-
kind: "stop_only",
|
|
176
|
-
});
|
|
177
|
-
expect(resolveRecordingIntent("can you stop the recording?")).toEqual({
|
|
178
|
-
kind: "stop_only",
|
|
179
|
-
});
|
|
180
|
-
expect(
|
|
181
|
-
resolveRecordingIntent("could you end the recording please"),
|
|
182
|
-
).toEqual({ kind: "stop_only" });
|
|
183
|
-
expect(resolveRecordingIntent("stop the recording now")).toEqual({
|
|
184
|
-
kind: "stop_only",
|
|
185
|
-
});
|
|
186
|
-
expect(resolveRecordingIntent("just stop recording, thanks")).toEqual({
|
|
187
|
-
kind: "stop_only",
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
test("resolves as stop_with_remainder when stop has additional task", () => {
|
|
192
|
-
const r1 = resolveRecordingIntent("stop recording and open Chrome");
|
|
193
|
-
expect(r1.kind).toBe("stop_with_remainder");
|
|
194
|
-
if (r1.kind === "stop_with_remainder") {
|
|
195
|
-
expect(r1.remainder).toContain("open Chrome");
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("handles ambiguous phrases as none", () => {
|
|
200
|
-
expect(resolveRecordingIntent("end it")).toEqual({ kind: "none" });
|
|
201
|
-
expect(resolveRecordingIntent("stop")).toEqual({ kind: "none" });
|
|
202
|
-
expect(resolveRecordingIntent("quit")).toEqual({ kind: "none" });
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
test("handles punctuation", () => {
|
|
206
|
-
expect(resolveRecordingIntent("stop recording!")).toEqual({
|
|
207
|
-
kind: "stop_only",
|
|
208
|
-
});
|
|
209
|
-
expect(resolveRecordingIntent("stop recording.")).toEqual({
|
|
210
|
-
kind: "stop_only",
|
|
211
|
-
});
|
|
212
|
-
expect(resolveRecordingIntent("end the recording?")).toEqual({
|
|
213
|
-
kind: "stop_only",
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// ── Remainder extraction (covers legacy strip* behavior) ────────────────
|
|
219
|
-
|
|
220
|
-
describe("remainder extraction", () => {
|
|
221
|
-
test("extracts remainder when start intent is mixed with other task", () => {
|
|
222
|
-
const r1 = resolveRecordingIntent("open Safari and record my screen");
|
|
223
|
-
expect(r1.kind).toBe("start_with_remainder");
|
|
224
|
-
if (r1.kind === "start_with_remainder") {
|
|
225
|
-
expect(r1.remainder).toBe("open Safari");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const r2 = resolveRecordingIntent("do this task and start recording");
|
|
229
|
-
expect(r2.kind).toBe("start_with_remainder");
|
|
230
|
-
if (r2.kind === "start_with_remainder") {
|
|
231
|
-
expect(r2.remainder).toContain("do this task");
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test("extracts remainder when stop intent is mixed with other task", () => {
|
|
236
|
-
const r1 = resolveRecordingIntent("open Chrome and stop recording");
|
|
237
|
-
expect(r1.kind).toBe("stop_with_remainder");
|
|
238
|
-
if (r1.kind === "stop_with_remainder") {
|
|
239
|
-
expect(r1.remainder).toBe("open Chrome");
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const r2 = resolveRecordingIntent("save the file and end the recording");
|
|
243
|
-
expect(r2.kind).toBe("stop_with_remainder");
|
|
244
|
-
if (r2.kind === "stop_with_remainder") {
|
|
245
|
-
expect(r2.remainder).toContain("save the file");
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
test("remainder does not contain double spaces", () => {
|
|
250
|
-
const r1 = resolveRecordingIntent(
|
|
251
|
-
"open Safari and also record my screen please",
|
|
252
|
-
);
|
|
253
|
-
if (r1.kind === "start_with_remainder") {
|
|
254
|
-
expect(r1.remainder).not.toContain(" ");
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const r2 = resolveRecordingIntent(
|
|
258
|
-
"open Safari and also stop recording please",
|
|
259
|
-
);
|
|
260
|
-
if (r2.kind === "stop_with_remainder") {
|
|
261
|
-
expect(r2.remainder).not.toContain(" ");
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// ── Interrogative gate (covers legacy isInterrogative behavior) ─────────
|
|
267
|
-
|
|
268
|
-
describe("interrogative gate", () => {
|
|
269
|
-
test.each([
|
|
270
|
-
"how do I stop recording?",
|
|
271
|
-
"how do I record my screen?",
|
|
272
|
-
"what does screen recording do?",
|
|
273
|
-
"why is screen recording not working?",
|
|
274
|
-
"when should I stop recording?",
|
|
275
|
-
"where does the recording file go?",
|
|
276
|
-
"which display should I record?",
|
|
277
|
-
"What is the screen recording feature?",
|
|
278
|
-
"How do I start recording on Mac?",
|
|
279
|
-
"how can I record my screen?",
|
|
280
|
-
"why did the recording stop?",
|
|
281
|
-
])('returns none for question: "%s"', (text) => {
|
|
282
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "none" });
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
test.each([
|
|
286
|
-
"record my screen",
|
|
287
|
-
"stop recording",
|
|
288
|
-
"open Chrome and record my screen",
|
|
289
|
-
"can you record my screen?",
|
|
290
|
-
"could you stop recording please",
|
|
291
|
-
"start recording",
|
|
292
|
-
"please record my screen",
|
|
293
|
-
])('does not block command: "%s"', (text) => {
|
|
294
|
-
expect(resolveRecordingIntent(text).kind).not.toBe("none");
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
test("strips dynamic name before checking interrogative", () => {
|
|
298
|
-
expect(
|
|
299
|
-
resolveRecordingIntent("Nova, how do I stop recording?", ["Nova"]),
|
|
300
|
-
).toEqual({ kind: "none" });
|
|
301
|
-
expect(
|
|
302
|
-
resolveRecordingIntent("Nova, record my screen", ["Nova"]).kind,
|
|
303
|
-
).toBe("start_only");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("handles polite prefix before question word", () => {
|
|
307
|
-
expect(
|
|
308
|
-
resolveRecordingIntent("please, how do I stop recording?"),
|
|
309
|
-
).toEqual({ kind: "none" });
|
|
310
|
-
expect(
|
|
311
|
-
resolveRecordingIntent("hey, what does screen recording do?"),
|
|
312
|
-
).toEqual({ kind: "none" });
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Interrogative gate for new patterns
|
|
316
|
-
test("returns none for question about restart", () => {
|
|
317
|
-
expect(resolveRecordingIntent("how do I restart recording?")).toEqual({
|
|
318
|
-
kind: "none",
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
test("returns none for question about pause", () => {
|
|
323
|
-
expect(resolveRecordingIntent("how can I pause recording?")).toEqual({
|
|
324
|
-
kind: "none",
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
test("returns none for question about resume", () => {
|
|
329
|
-
expect(resolveRecordingIntent("how do I resume recording?")).toEqual({
|
|
330
|
-
kind: "none",
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
// ── Indirect informational patterns ───────────────────────────────────
|
|
335
|
-
|
|
336
|
-
test.each([
|
|
337
|
-
"can you tell me how to stop recording?",
|
|
338
|
-
"could you tell me how to stop recording?",
|
|
339
|
-
"would you tell me how to stop recording?",
|
|
340
|
-
"explain how to stop the recording",
|
|
341
|
-
"tell me how recording works",
|
|
342
|
-
"describe how screen recording works",
|
|
343
|
-
"show me how to record my screen",
|
|
344
|
-
"is there a way to stop recording?",
|
|
345
|
-
"is there a method to pause recording?",
|
|
346
|
-
"are there any ways to record my screen?",
|
|
347
|
-
"I'd like to know how to stop recording",
|
|
348
|
-
"I would like to know how to pause the recording",
|
|
349
|
-
"I want to know how to start recording",
|
|
350
|
-
"do you know how to start recording?",
|
|
351
|
-
"can I learn how to record my screen?",
|
|
352
|
-
"can you explain how to record my screen?",
|
|
353
|
-
"tell me about how screen recording works",
|
|
354
|
-
"explain to me how to stop recording",
|
|
355
|
-
"tell me what screen recording does",
|
|
356
|
-
"describe how to start a recording",
|
|
357
|
-
"please, tell me how to stop recording",
|
|
358
|
-
"hey, can you explain how to record my screen?",
|
|
359
|
-
])('returns none for indirect informational question: "%s"', (text) => {
|
|
360
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "none" });
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
test("indirect informational with dynamic name returns none", () => {
|
|
364
|
-
expect(
|
|
365
|
-
resolveRecordingIntent("Nova, can you tell me how to stop recording?", [
|
|
366
|
-
"Nova",
|
|
367
|
-
]),
|
|
368
|
-
).toEqual({ kind: "none" });
|
|
369
|
-
expect(
|
|
370
|
-
resolveRecordingIntent("Nova, explain how to record my screen", [
|
|
371
|
-
"Nova",
|
|
372
|
-
]),
|
|
373
|
-
).toEqual({ kind: "none" });
|
|
374
|
-
expect(
|
|
375
|
-
resolveRecordingIntent("hey Nova, is there a way to stop recording?", [
|
|
376
|
-
"Nova",
|
|
377
|
-
]),
|
|
378
|
-
).toEqual({ kind: "none" });
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// ── Polite imperatives that should still execute (NOT none) ──────────
|
|
382
|
-
|
|
383
|
-
test.each([
|
|
384
|
-
["can you stop recording?", "stop_only"],
|
|
385
|
-
["could you record my screen?", "start_only"],
|
|
386
|
-
["can you pause the recording?", "pause_only"],
|
|
387
|
-
["would you resume recording?", "resume_only"],
|
|
388
|
-
["please stop recording", "stop_only"],
|
|
389
|
-
["can you start recording?", "start_only"],
|
|
390
|
-
["could you stop the recording please", "stop_only"],
|
|
391
|
-
] as const)(
|
|
392
|
-
'polite imperative "%s" resolves to %s (not none)',
|
|
393
|
-
(text, expected) => {
|
|
394
|
-
expect(resolveRecordingIntent(text).kind).toBe(expected);
|
|
395
|
-
},
|
|
396
|
-
);
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
// ── Mixed-intent with remainder (regression coverage) ────────────────────
|
|
400
|
-
|
|
401
|
-
describe("mixed-intent with remainder", () => {
|
|
402
|
-
test('"stop recording and start a new one and open safari" → restart_with_remainder', () => {
|
|
403
|
-
const result = resolveRecordingIntent(
|
|
404
|
-
"stop recording and start a new one and open safari",
|
|
405
|
-
);
|
|
406
|
-
expect(result.kind).toBe("restart_with_remainder");
|
|
407
|
-
if (result.kind === "restart_with_remainder") {
|
|
408
|
-
expect(result.remainder).toContain("open safari");
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
test('"record my screen and open Chrome and go to google.com" → start_with_remainder', () => {
|
|
413
|
-
const result = resolveRecordingIntent(
|
|
414
|
-
"record my screen and open Chrome and go to google.com",
|
|
415
|
-
);
|
|
416
|
-
expect(result.kind).toBe("start_with_remainder");
|
|
417
|
-
if (result.kind === "start_with_remainder") {
|
|
418
|
-
expect(result.remainder).toContain("open Chrome");
|
|
419
|
-
expect(result.remainder).toContain("google.com");
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
test('"stop recording and send the file to Bob" → stop_with_remainder', () => {
|
|
424
|
-
const result = resolveRecordingIntent(
|
|
425
|
-
"stop recording and send the file to Bob",
|
|
426
|
-
);
|
|
427
|
-
expect(result.kind).toBe("stop_with_remainder");
|
|
428
|
-
if (result.kind === "stop_with_remainder") {
|
|
429
|
-
expect(result.remainder).toContain("send the file to Bob");
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
// ── Dynamic names ──────────────────────────────────────────────────────────
|
|
435
|
-
|
|
436
|
-
describe("dynamic name handling", () => {
|
|
437
|
-
test.each([
|
|
438
|
-
["Nova, record my screen", ["Nova"], "start_only"],
|
|
439
|
-
["hey Nova, start recording", ["Nova"], "start_only"],
|
|
440
|
-
["hey, Nova, start recording", ["Nova"], "start_only"],
|
|
441
|
-
["Nova, stop recording", ["Nova"], "stop_only"],
|
|
442
|
-
["Nova, hello", ["Nova"], "none"],
|
|
443
|
-
] as const)(
|
|
444
|
-
'"%s" with names %j resolves to %s',
|
|
445
|
-
(text, names, expected) => {
|
|
446
|
-
expect(resolveRecordingIntent(text, [...names]).kind).toBe(expected);
|
|
447
|
-
},
|
|
448
|
-
);
|
|
449
|
-
|
|
450
|
-
test("mixed intent with dynamic name extracts remainder", () => {
|
|
451
|
-
const result = resolveRecordingIntent(
|
|
452
|
-
"Nova, open Safari and record my screen",
|
|
453
|
-
["Nova"],
|
|
454
|
-
);
|
|
455
|
-
expect(result.kind).toBe("start_with_remainder");
|
|
456
|
-
if (result.kind === "start_with_remainder") {
|
|
457
|
-
expect(result.remainder).toContain("open Safari");
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
test("dynamic name stripping is case-insensitive", () => {
|
|
462
|
-
expect(
|
|
463
|
-
resolveRecordingIntent("nova, record my screen", ["Nova"]).kind,
|
|
464
|
-
).toBe("start_only");
|
|
465
|
-
expect(
|
|
466
|
-
resolveRecordingIntent("NOVA, stop recording", ["Nova"]).kind,
|
|
467
|
-
).toBe("stop_only");
|
|
468
|
-
expect(
|
|
469
|
-
resolveRecordingIntent("Hey NOVA, start recording", ["nova"]).kind,
|
|
470
|
-
).toBe("start_only");
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
test("handles multiple dynamic names", () => {
|
|
474
|
-
expect(
|
|
475
|
-
resolveRecordingIntent("Jarvis, record my screen", ["Nova", "Jarvis"])
|
|
476
|
-
.kind,
|
|
477
|
-
).toBe("start_only");
|
|
478
|
-
expect(
|
|
479
|
-
resolveRecordingIntent("Nova, stop recording", ["Nova", "Jarvis"]).kind,
|
|
480
|
-
).toBe("stop_only");
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
test("handles empty dynamic names array", () => {
|
|
484
|
-
expect(resolveRecordingIntent("record my screen", []).kind).toBe(
|
|
485
|
-
"start_only",
|
|
486
|
-
);
|
|
487
|
-
expect(resolveRecordingIntent("stop recording", []).kind).toBe(
|
|
488
|
-
"stop_only",
|
|
489
|
-
);
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
test("handles colon separator after name", () => {
|
|
493
|
-
expect(
|
|
494
|
-
resolveRecordingIntent("Nova: record my screen", ["Nova"]).kind,
|
|
495
|
-
).toBe("start_only");
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
test("interrogative with name prefix returns none", () => {
|
|
499
|
-
expect(
|
|
500
|
-
resolveRecordingIntent("hey Nova, how do I stop recording?", ["Nova"]),
|
|
501
|
-
).toEqual({ kind: "none" });
|
|
502
|
-
});
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
// ── Start + stop combined ──────────────────────────────────────────────────
|
|
506
|
-
|
|
507
|
-
describe("combined start and stop", () => {
|
|
508
|
-
test('start and stop: "stop recording and record my screen"', () => {
|
|
509
|
-
const result = resolveRecordingIntent(
|
|
510
|
-
"stop recording and record my screen",
|
|
511
|
-
);
|
|
512
|
-
expect(result.kind).toBe("start_and_stop_only");
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
test('start and stop: "stop recording and start recording"', () => {
|
|
516
|
-
const result = resolveRecordingIntent(
|
|
517
|
-
"stop recording and start recording",
|
|
518
|
-
);
|
|
519
|
-
expect(result.kind).toBe("start_and_stop_only");
|
|
520
|
-
});
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
// ── Restart compound detection ────────────────────────────────────────────
|
|
524
|
-
|
|
525
|
-
describe("restart compound detection", () => {
|
|
526
|
-
test('"restart the recording" → restart_only', () => {
|
|
527
|
-
expect(resolveRecordingIntent("restart the recording")).toEqual({
|
|
528
|
-
kind: "restart_only",
|
|
529
|
-
});
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
test('"restart recording" → restart_only', () => {
|
|
533
|
-
expect(resolveRecordingIntent("restart recording")).toEqual({
|
|
534
|
-
kind: "restart_only",
|
|
535
|
-
});
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
test('"redo the recording" → restart_only', () => {
|
|
539
|
-
expect(resolveRecordingIntent("redo the recording")).toEqual({
|
|
540
|
-
kind: "restart_only",
|
|
541
|
-
});
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
test('"stop recording and start a new one" → restart_only', () => {
|
|
545
|
-
expect(
|
|
546
|
-
resolveRecordingIntent("stop recording and start a new one"),
|
|
547
|
-
).toEqual({ kind: "restart_only" });
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
test('"stop the recording and start a new one" → restart_only', () => {
|
|
551
|
-
expect(
|
|
552
|
-
resolveRecordingIntent("stop the recording and start a new one"),
|
|
553
|
-
).toEqual({ kind: "restart_only" });
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
test('"stop the recording and begin a fresh" → restart_only', () => {
|
|
557
|
-
expect(
|
|
558
|
-
resolveRecordingIntent("stop the recording and begin a fresh"),
|
|
559
|
-
).toEqual({ kind: "restart_only" });
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
test('"stop and restart the recording" → restart_only', () => {
|
|
563
|
-
expect(resolveRecordingIntent("stop and restart the recording")).toEqual({
|
|
564
|
-
kind: "restart_only",
|
|
565
|
-
});
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
test('"stop recording and start a new" → restart_only', () => {
|
|
569
|
-
expect(resolveRecordingIntent("stop recording and start a new")).toEqual({
|
|
570
|
-
kind: "restart_only",
|
|
571
|
-
});
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
test('"stop recording and start another" → restart_only', () => {
|
|
575
|
-
expect(
|
|
576
|
-
resolveRecordingIntent("stop recording and start another"),
|
|
577
|
-
).toEqual({ kind: "restart_only" });
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
test('"stop recording and start another." → restart_only (trailing period)', () => {
|
|
581
|
-
expect(
|
|
582
|
-
resolveRecordingIntent("stop recording and start another."),
|
|
583
|
-
).toEqual({ kind: "restart_only" });
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
test('"stop recording and start a new!" → restart_only (trailing exclamation)', () => {
|
|
587
|
-
expect(resolveRecordingIntent("stop recording and start a new!")).toEqual(
|
|
588
|
-
{ kind: "restart_only" },
|
|
589
|
-
);
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
test('restart with remainder: "restart recording and open safari"', () => {
|
|
593
|
-
const result = resolveRecordingIntent(
|
|
594
|
-
"restart recording and open safari",
|
|
595
|
-
);
|
|
596
|
-
expect(result.kind).toBe("restart_with_remainder");
|
|
597
|
-
if (result.kind === "restart_with_remainder") {
|
|
598
|
-
expect(result.remainder).toContain("open safari");
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
test("restart with polite fillers resolves as restart_only", () => {
|
|
603
|
-
expect(resolveRecordingIntent("please restart the recording")).toEqual({
|
|
604
|
-
kind: "restart_only",
|
|
605
|
-
});
|
|
606
|
-
expect(resolveRecordingIntent("can you restart recording")).toEqual({
|
|
607
|
-
kind: "restart_only",
|
|
608
|
-
});
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
test("restart takes precedence over independent start/stop", () => {
|
|
612
|
-
// "stop recording and start a new one" should be restart, not start_and_stop
|
|
613
|
-
const result = resolveRecordingIntent(
|
|
614
|
-
"stop recording and start a new one",
|
|
615
|
-
);
|
|
616
|
-
expect(result.kind).toBe("restart_only");
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
test('"stop recording and start a new recording" → restart_only', () => {
|
|
620
|
-
expect(
|
|
621
|
-
resolveRecordingIntent("stop recording and start a new recording"),
|
|
622
|
-
).toEqual({ kind: "restart_only" });
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test('"stop the recording and start another recording" → restart_only', () => {
|
|
626
|
-
expect(
|
|
627
|
-
resolveRecordingIntent(
|
|
628
|
-
"stop the recording and start another recording",
|
|
629
|
-
),
|
|
630
|
-
).toEqual({ kind: "restart_only" });
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
// False positive guards: "start another/new <non-recording>" should NOT trigger restart
|
|
634
|
-
test('"stop recording and start another tab" should NOT trigger restart', () => {
|
|
635
|
-
const result = resolveRecordingIntent(
|
|
636
|
-
"stop recording and start another tab",
|
|
637
|
-
);
|
|
638
|
-
expect(result.kind).toBe("stop_with_remainder");
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
test('"stop recording and start another window" should NOT trigger restart', () => {
|
|
642
|
-
const result = resolveRecordingIntent(
|
|
643
|
-
"stop recording and start another window",
|
|
644
|
-
);
|
|
645
|
-
expect(result.kind).toBe("stop_with_remainder");
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
test('"stop recording and start a new project" should NOT trigger restart', () => {
|
|
649
|
-
const result = resolveRecordingIntent(
|
|
650
|
-
"stop recording and start a new project",
|
|
651
|
-
);
|
|
652
|
-
expect(result.kind).toBe("stop_with_remainder");
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
test('"stop the recording and begin a fresh session" should NOT trigger restart', () => {
|
|
656
|
-
const result = resolveRecordingIntent(
|
|
657
|
-
"stop the recording and begin a fresh session",
|
|
658
|
-
);
|
|
659
|
-
expect(result.kind).toBe("stop_with_remainder");
|
|
660
|
-
});
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// ── Pause detection ───────────────────────────────────────────────────────
|
|
664
|
-
|
|
665
|
-
describe("pause detection", () => {
|
|
666
|
-
test('"pause recording" → pause_only', () => {
|
|
667
|
-
expect(resolveRecordingIntent("pause recording")).toEqual({
|
|
668
|
-
kind: "pause_only",
|
|
669
|
-
});
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
test('"pause the recording" → pause_only', () => {
|
|
673
|
-
expect(resolveRecordingIntent("pause the recording")).toEqual({
|
|
674
|
-
kind: "pause_only",
|
|
675
|
-
});
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
test("pause with polite fillers resolves as pause_only", () => {
|
|
679
|
-
expect(resolveRecordingIntent("please pause the recording")).toEqual({
|
|
680
|
-
kind: "pause_only",
|
|
681
|
-
});
|
|
682
|
-
expect(resolveRecordingIntent("can you pause recording")).toEqual({
|
|
683
|
-
kind: "pause_only",
|
|
684
|
-
});
|
|
685
|
-
});
|
|
686
|
-
});
|
|
687
|
-
|
|
688
|
-
// ── Resume detection ──────────────────────────────────────────────────────
|
|
689
|
-
|
|
690
|
-
describe("resume detection", () => {
|
|
691
|
-
test('"resume recording" → resume_only', () => {
|
|
692
|
-
expect(resolveRecordingIntent("resume recording")).toEqual({
|
|
693
|
-
kind: "resume_only",
|
|
694
|
-
});
|
|
695
|
-
});
|
|
696
|
-
|
|
697
|
-
test('"resume the recording" → resume_only', () => {
|
|
698
|
-
expect(resolveRecordingIntent("resume the recording")).toEqual({
|
|
699
|
-
kind: "resume_only",
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
test('"unpause the recording" → resume_only', () => {
|
|
704
|
-
expect(resolveRecordingIntent("unpause the recording")).toEqual({
|
|
705
|
-
kind: "resume_only",
|
|
706
|
-
});
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
test("resume with polite fillers resolves as resume_only", () => {
|
|
710
|
-
expect(resolveRecordingIntent("please resume the recording")).toEqual({
|
|
711
|
-
kind: "resume_only",
|
|
712
|
-
});
|
|
713
|
-
});
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
// ── False positive guards ─────────────────────────────────────────────────
|
|
717
|
-
|
|
718
|
-
describe("false positive guards", () => {
|
|
719
|
-
test('"I recorded a restart" → none', () => {
|
|
720
|
-
expect(resolveRecordingIntent("I recorded a restart")).toEqual({
|
|
721
|
-
kind: "none",
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
test('"the pause button is broken" → none (no recording mention)', () => {
|
|
726
|
-
expect(resolveRecordingIntent("the pause button is broken")).toEqual({
|
|
727
|
-
kind: "none",
|
|
728
|
-
});
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
test('"resume my work" → none (no recording mention)', () => {
|
|
732
|
-
expect(resolveRecordingIntent("resume my work")).toEqual({
|
|
733
|
-
kind: "none",
|
|
734
|
-
});
|
|
735
|
-
});
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
// ── No recording intent ────────────────────────────────────────────────────
|
|
739
|
-
|
|
740
|
-
describe("no recording intent", () => {
|
|
741
|
-
test.each(["open Safari", "I broke the record", "", "hello world"])(
|
|
742
|
-
'returns none for "%s"',
|
|
743
|
-
(text) => {
|
|
744
|
-
expect(resolveRecordingIntent(text)).toEqual({ kind: "none" });
|
|
745
|
-
},
|
|
746
|
-
);
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
// ── Works without dynamic names parameter ──────────────────────────────────
|
|
750
|
-
|
|
751
|
-
test("works without dynamic names parameter", () => {
|
|
752
|
-
expect(resolveRecordingIntent("record my screen")).toEqual({
|
|
753
|
-
kind: "start_only",
|
|
754
|
-
});
|
|
755
|
-
expect(resolveRecordingIntent("stop recording")).toEqual({
|
|
756
|
-
kind: "stop_only",
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
// ─── executeRecordingIntent ─────────────────────────────────────────────────
|
|
762
|
-
|
|
763
|
-
describe("executeRecordingIntent", () => {
|
|
764
|
-
// Mock the recording handlers module
|
|
765
|
-
const mockHandleRecordingStart = mock(
|
|
766
|
-
(): string | null => "mock-recording-id",
|
|
767
|
-
);
|
|
768
|
-
const mockHandleRecordingStop = mock(
|
|
769
|
-
(): string | undefined => "mock-recording-id",
|
|
770
|
-
);
|
|
771
|
-
const mockHandleRecordingRestart = mock(
|
|
772
|
-
(): {
|
|
773
|
-
initiated: boolean;
|
|
774
|
-
operationToken?: string;
|
|
775
|
-
responseText: string;
|
|
776
|
-
} => ({
|
|
777
|
-
initiated: true,
|
|
778
|
-
operationToken: "mock-token",
|
|
779
|
-
responseText: "Restarting screen recording.",
|
|
780
|
-
}),
|
|
781
|
-
);
|
|
782
|
-
const mockHandleRecordingPause = mock(
|
|
783
|
-
(): string | undefined => "mock-recording-id",
|
|
784
|
-
);
|
|
785
|
-
const mockHandleRecordingResume = mock(
|
|
786
|
-
(): string | undefined => "mock-recording-id",
|
|
787
|
-
);
|
|
788
|
-
|
|
789
|
-
mock.module("../daemon/handlers/recording.js", () => ({
|
|
790
|
-
handleRecordingStart: mockHandleRecordingStart,
|
|
791
|
-
handleRecordingStop: mockHandleRecordingStop,
|
|
792
|
-
handleRecordingRestart: mockHandleRecordingRestart,
|
|
793
|
-
handleRecordingPause: mockHandleRecordingPause,
|
|
794
|
-
handleRecordingResume: mockHandleRecordingResume,
|
|
795
|
-
isRecordingIdle: () => true,
|
|
796
|
-
}));
|
|
797
|
-
|
|
798
|
-
// Dynamically import so the mock takes effect
|
|
799
|
-
let executeRecordingIntent: typeof import("../daemon/recording-executor.js").executeRecordingIntent;
|
|
800
|
-
|
|
801
|
-
// Must await the dynamic import before running tests
|
|
802
|
-
const setupPromise = import("../daemon/recording-executor.js").then((mod) => {
|
|
803
|
-
executeRecordingIntent = mod.executeRecordingIntent;
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
const mockContext = {
|
|
807
|
-
conversationId: "conv-123",
|
|
808
|
-
socket: {} as any,
|
|
809
|
-
ctx: {} as any,
|
|
810
|
-
};
|
|
811
|
-
|
|
812
|
-
beforeEach(async () => {
|
|
813
|
-
await setupPromise;
|
|
814
|
-
mockHandleRecordingStart.mockReset();
|
|
815
|
-
mockHandleRecordingStop.mockReset();
|
|
816
|
-
mockHandleRecordingRestart.mockReset();
|
|
817
|
-
mockHandleRecordingPause.mockReset();
|
|
818
|
-
mockHandleRecordingResume.mockReset();
|
|
819
|
-
// Default: start succeeds (returns recording ID)
|
|
820
|
-
mockHandleRecordingStart.mockReturnValue("mock-recording-id");
|
|
821
|
-
// Default: stop succeeds (returns recording ID)
|
|
822
|
-
mockHandleRecordingStop.mockReturnValue("mock-recording-id");
|
|
823
|
-
// Default: restart succeeds
|
|
824
|
-
mockHandleRecordingRestart.mockReturnValue({
|
|
825
|
-
initiated: true,
|
|
826
|
-
operationToken: "mock-token",
|
|
827
|
-
responseText: "Restarting screen recording.",
|
|
828
|
-
});
|
|
829
|
-
// Default: pause succeeds
|
|
830
|
-
mockHandleRecordingPause.mockReturnValue("mock-recording-id");
|
|
831
|
-
// Default: resume succeeds
|
|
832
|
-
mockHandleRecordingResume.mockReturnValue("mock-recording-id");
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
test("none → returns { handled: false }", () => {
|
|
836
|
-
const result = executeRecordingIntent({ kind: "none" }, mockContext);
|
|
837
|
-
expect(result).toEqual({ handled: false });
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
test("start_only → calls handleRecordingStart, returns handled with start text", () => {
|
|
841
|
-
const result = executeRecordingIntent({ kind: "start_only" }, mockContext);
|
|
842
|
-
expect(mockHandleRecordingStart).toHaveBeenCalledTimes(1);
|
|
843
|
-
expect(result).toEqual({
|
|
844
|
-
handled: true,
|
|
845
|
-
recordingStarted: true,
|
|
846
|
-
responseText: "Starting screen recording.",
|
|
847
|
-
});
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
test("start_only when recording already active → returns handled with already-active text", () => {
|
|
851
|
-
mockHandleRecordingStart.mockReturnValue(null);
|
|
852
|
-
const result = executeRecordingIntent({ kind: "start_only" }, mockContext);
|
|
853
|
-
expect(mockHandleRecordingStart).toHaveBeenCalledTimes(1);
|
|
854
|
-
expect(result).toEqual({
|
|
855
|
-
handled: true,
|
|
856
|
-
recordingStarted: false,
|
|
857
|
-
responseText: "A recording is already active.",
|
|
858
|
-
});
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
test("stop_only → calls handleRecordingStop, returns handled with stop text", () => {
|
|
862
|
-
const result = executeRecordingIntent({ kind: "stop_only" }, mockContext);
|
|
863
|
-
expect(mockHandleRecordingStop).toHaveBeenCalledTimes(1);
|
|
864
|
-
expect(result).toEqual({
|
|
865
|
-
handled: true,
|
|
866
|
-
responseText: "Stopping the recording.",
|
|
867
|
-
});
|
|
868
|
-
});
|
|
869
|
-
|
|
870
|
-
test("stop_only when no active recording → returns handled with no-active text", () => {
|
|
871
|
-
mockHandleRecordingStop.mockReturnValue(undefined);
|
|
872
|
-
const result = executeRecordingIntent({ kind: "stop_only" }, mockContext);
|
|
873
|
-
expect(result).toEqual({
|
|
874
|
-
handled: true,
|
|
875
|
-
responseText: "No active recording to stop.",
|
|
876
|
-
});
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
test("start_with_remainder → returns not handled with remainder and pendingStart", () => {
|
|
880
|
-
const result = executeRecordingIntent(
|
|
881
|
-
{ kind: "start_with_remainder", remainder: "open Safari" },
|
|
882
|
-
mockContext,
|
|
883
|
-
);
|
|
884
|
-
expect(result).toEqual({
|
|
885
|
-
handled: false,
|
|
886
|
-
remainderText: "open Safari",
|
|
887
|
-
pendingStart: true,
|
|
888
|
-
});
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
test("stop_with_remainder → returns not handled with remainder and pendingStop", () => {
|
|
892
|
-
const result = executeRecordingIntent(
|
|
893
|
-
{ kind: "stop_with_remainder", remainder: "open Chrome" },
|
|
894
|
-
mockContext,
|
|
895
|
-
);
|
|
896
|
-
expect(result).toEqual({
|
|
897
|
-
handled: false,
|
|
898
|
-
remainderText: "open Chrome",
|
|
899
|
-
pendingStop: true,
|
|
900
|
-
});
|
|
901
|
-
});
|
|
902
|
-
|
|
903
|
-
test("start_and_stop_only → routes through handleRecordingRestart, returns handled", () => {
|
|
904
|
-
const result = executeRecordingIntent(
|
|
905
|
-
{ kind: "start_and_stop_only" },
|
|
906
|
-
mockContext,
|
|
907
|
-
);
|
|
908
|
-
expect(mockHandleRecordingRestart).toHaveBeenCalledTimes(1);
|
|
909
|
-
expect(result).toEqual({
|
|
910
|
-
handled: true,
|
|
911
|
-
recordingStarted: true,
|
|
912
|
-
responseText: "Stopping current recording and starting a new one.",
|
|
913
|
-
});
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
test("start_and_stop_only when restart fails → returns handled with restart failure text", () => {
|
|
917
|
-
mockHandleRecordingRestart.mockReturnValue({
|
|
918
|
-
initiated: false,
|
|
919
|
-
responseText: "No active recording to restart.",
|
|
920
|
-
});
|
|
921
|
-
const result = executeRecordingIntent(
|
|
922
|
-
{ kind: "start_and_stop_only" },
|
|
923
|
-
mockContext,
|
|
924
|
-
);
|
|
925
|
-
expect(mockHandleRecordingRestart).toHaveBeenCalledTimes(1);
|
|
926
|
-
expect(result).toEqual({
|
|
927
|
-
handled: true,
|
|
928
|
-
recordingStarted: false,
|
|
929
|
-
responseText: "No active recording to restart.",
|
|
930
|
-
});
|
|
931
|
-
});
|
|
932
|
-
|
|
933
|
-
test("start_and_stop_with_remainder → returns not handled with remainder and pendingStart when idle", () => {
|
|
934
|
-
const result = executeRecordingIntent(
|
|
935
|
-
{ kind: "start_and_stop_with_remainder", remainder: "open Safari" },
|
|
936
|
-
mockContext,
|
|
937
|
-
);
|
|
938
|
-
expect(result).toEqual({
|
|
939
|
-
handled: false,
|
|
940
|
-
remainderText: "open Safari",
|
|
941
|
-
pendingStart: true,
|
|
942
|
-
});
|
|
943
|
-
});
|
|
944
|
-
|
|
945
|
-
// ── New intent kinds ──────────────────────────────────────────────────────
|
|
946
|
-
|
|
947
|
-
test("restart_only → returns handled with restart text", () => {
|
|
948
|
-
const result = executeRecordingIntent(
|
|
949
|
-
{ kind: "restart_only" },
|
|
950
|
-
mockContext,
|
|
951
|
-
);
|
|
952
|
-
expect(result).toEqual({
|
|
953
|
-
handled: true,
|
|
954
|
-
responseText: "Restarting screen recording.",
|
|
955
|
-
});
|
|
956
|
-
});
|
|
957
|
-
|
|
958
|
-
test("restart_with_remainder → returns not handled with remainder and pendingRestart", () => {
|
|
959
|
-
const result = executeRecordingIntent(
|
|
960
|
-
{ kind: "restart_with_remainder", remainder: "and open safari" },
|
|
961
|
-
mockContext,
|
|
962
|
-
);
|
|
963
|
-
expect(result).toEqual({
|
|
964
|
-
handled: false,
|
|
965
|
-
remainderText: "and open safari",
|
|
966
|
-
pendingRestart: true,
|
|
967
|
-
});
|
|
968
|
-
});
|
|
969
|
-
|
|
970
|
-
test("pause_only → returns handled with pause text", () => {
|
|
971
|
-
const result = executeRecordingIntent({ kind: "pause_only" }, mockContext);
|
|
972
|
-
expect(result).toEqual({
|
|
973
|
-
handled: true,
|
|
974
|
-
responseText: "Pausing the recording.",
|
|
975
|
-
});
|
|
976
|
-
});
|
|
977
|
-
|
|
978
|
-
test("resume_only → returns handled with resume text", () => {
|
|
979
|
-
const result = executeRecordingIntent({ kind: "resume_only" }, mockContext);
|
|
980
|
-
expect(result).toEqual({
|
|
981
|
-
handled: true,
|
|
982
|
-
responseText: "Resuming the recording.",
|
|
983
|
-
});
|
|
984
|
-
});
|
|
985
|
-
});
|