vellum 0.0.16 → 0.2.0
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/.dockerignore +27 -0
- package/.env.example +22 -0
- package/Dockerfile +99 -0
- package/Dockerfile.sandbox +5 -0
- package/README.md +150 -3
- package/bun.lock +1768 -0
- package/bunfig.toml +2 -0
- package/docs/skills.md +158 -0
- package/drizzle/0000_dizzy_maggott.sql +301 -0
- package/drizzle/meta/0000_snapshot.json +1999 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/eslint.config.mjs +17 -0
- package/hook-templates/debug-prompt-logger/hook.json +7 -0
- package/hook-templates/debug-prompt-logger/run.sh +68 -0
- package/knip.json +9 -0
- package/package.json +60 -10
- package/scripts/ipc/check-contract-inventory.ts +104 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +163 -0
- package/scripts/ipc/generate-swift.ts +492 -0
- package/scripts/test-filesystem-tools.sh +48 -0
- package/scripts/test.sh +122 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2079 -0
- package/src/__tests__/account-registry.test.ts +244 -0
- package/src/__tests__/active-skill-tools.test.ts +378 -0
- package/src/__tests__/agent-loop-thinking.test.ts +81 -0
- package/src/__tests__/agent-loop.test.ts +1135 -0
- package/src/__tests__/anthropic-provider.test.ts +778 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
- package/src/__tests__/app-bundler.test.ts +313 -0
- package/src/__tests__/app-executors.test.ts +613 -0
- package/src/__tests__/app-open-proxy.test.ts +62 -0
- package/src/__tests__/asset-materialize-tool.test.ts +451 -0
- package/src/__tests__/asset-search-tool.test.ts +476 -0
- package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
- package/src/__tests__/assistant-attachments.test.ts +437 -0
- package/src/__tests__/assistant-event-hub.test.ts +226 -0
- package/src/__tests__/assistant-event.test.ts +123 -0
- package/src/__tests__/attachments-store.test.ts +547 -0
- package/src/__tests__/attachments.test.ts +134 -0
- package/src/__tests__/audit-log-rotation.test.ts +154 -0
- package/src/__tests__/browser-fill-credential.test.ts +309 -0
- package/src/__tests__/browser-manager.test.ts +203 -0
- package/src/__tests__/browser-runtime-check.test.ts +55 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +67 -0
- package/src/__tests__/browser-skill-endstate.test.ts +198 -0
- package/src/__tests__/bundle-scanner.test.ts +313 -0
- package/src/__tests__/checker.test.ts +3856 -0
- package/src/__tests__/clarification-resolver.test.ts +159 -0
- package/src/__tests__/classifier.test.ts +67 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
- package/src/__tests__/cli-discover.test.ts +85 -0
- package/src/__tests__/cli.test.ts +81 -0
- package/src/__tests__/clipboard.test.ts +80 -0
- package/src/__tests__/commit-guarantee.test.ts +335 -0
- package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
- package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
- package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
- package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
- package/src/__tests__/config-schema.test.ts +720 -0
- package/src/__tests__/conflict-store.test.ts +329 -0
- package/src/__tests__/connection-policy.test.ts +102 -0
- package/src/__tests__/context-memory-e2e.test.ts +434 -0
- package/src/__tests__/context-token-estimator.test.ts +135 -0
- package/src/__tests__/context-window-manager.test.ts +376 -0
- package/src/__tests__/contradiction-checker.test.ts +216 -0
- package/src/__tests__/conversation-store.test.ts +614 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
- package/src/__tests__/credential-broker-server-use.test.ts +554 -0
- package/src/__tests__/credential-broker.test.ts +167 -0
- package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
- package/src/__tests__/credential-metadata-store.test.ts +779 -0
- package/src/__tests__/credential-policy-validate.test.ts +121 -0
- package/src/__tests__/credential-resolve.test.ts +328 -0
- package/src/__tests__/credential-security-e2e.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +563 -0
- package/src/__tests__/credential-selection.test.ts +354 -0
- package/src/__tests__/credential-vault.test.ts +852 -0
- package/src/__tests__/daemon-assistant-events.test.ts +164 -0
- package/src/__tests__/daemon-server-session-init.test.ts +522 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
- package/src/__tests__/diff.test.ts +121 -0
- package/src/__tests__/domain-normalize.test.ts +112 -0
- package/src/__tests__/domain-policy.test.ts +124 -0
- package/src/__tests__/doordash-client.test.ts +186 -0
- package/src/__tests__/doordash-session.test.ts +143 -0
- package/src/__tests__/dynamic-page-surface.test.ts +91 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
- package/src/__tests__/edit-engine.test.ts +180 -0
- package/src/__tests__/email-cli.test.ts +283 -0
- package/src/__tests__/encrypted-store.test.ts +332 -0
- package/src/__tests__/entity-extractor.test.ts +190 -0
- package/src/__tests__/ephemeral-permissions.test.ts +312 -0
- package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
- package/src/__tests__/event-bus.test.ts +222 -0
- package/src/__tests__/file-edit-tool.test.ts +122 -0
- package/src/__tests__/file-ops-service.test.ts +330 -0
- package/src/__tests__/file-read-tool.test.ts +75 -0
- package/src/__tests__/file-write-tool.test.ts +113 -0
- package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
- package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
- package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
- package/src/__tests__/fuzzy-match-property.test.ts +216 -0
- package/src/__tests__/fuzzy-match.test.ts +138 -0
- package/src/__tests__/gemini-image-service.test.ts +261 -0
- package/src/__tests__/gemini-provider.test.ts +651 -0
- package/src/__tests__/get-weather.test.ts +318 -0
- package/src/__tests__/gmail-integration.test.ts +73 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +351 -0
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +190 -0
- package/src/__tests__/handlers-slack-config.test.ts +199 -0
- package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
- package/src/__tests__/headless-browser-interactions.test.ts +536 -0
- package/src/__tests__/headless-browser-navigate.test.ts +211 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
- package/src/__tests__/history-repair-observability.test.ts +56 -0
- package/src/__tests__/history-repair.test.ts +510 -0
- package/src/__tests__/home-base-bootstrap.test.ts +77 -0
- package/src/__tests__/hooks-blocking.test.ts +128 -0
- package/src/__tests__/hooks-cli.test.ts +144 -0
- package/src/__tests__/hooks-config.test.ts +93 -0
- package/src/__tests__/hooks-discovery.test.ts +199 -0
- package/src/__tests__/hooks-integration.test.ts +189 -0
- package/src/__tests__/hooks-manager.test.ts +187 -0
- package/src/__tests__/hooks-runner.test.ts +178 -0
- package/src/__tests__/hooks-settings.test.ts +154 -0
- package/src/__tests__/hooks-templates.test.ts +137 -0
- package/src/__tests__/hooks-ts-runner.test.ts +125 -0
- package/src/__tests__/hooks-watch.test.ts +100 -0
- package/src/__tests__/host-file-edit-tool.test.ts +104 -0
- package/src/__tests__/host-file-read-tool.test.ts +61 -0
- package/src/__tests__/host-file-write-tool.test.ts +77 -0
- package/src/__tests__/host-shell-tool.test.ts +311 -0
- package/src/__tests__/intent-routing.test.ts +255 -0
- package/src/__tests__/ipc-blob-store.test.ts +315 -0
- package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
- package/src/__tests__/ipc-contract.test.ts +74 -0
- package/src/__tests__/ipc-protocol.test.ts +113 -0
- package/src/__tests__/ipc-snapshot.test.ts +1560 -0
- package/src/__tests__/ipc-validate.test.ts +357 -0
- package/src/__tests__/key-migration.test.ts +183 -0
- package/src/__tests__/keychain.test.ts +258 -0
- package/src/__tests__/llm-usage-store.test.ts +226 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
- package/src/__tests__/managed-store.test.ts +608 -0
- package/src/__tests__/media-generate-image.test.ts +238 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
- package/src/__tests__/media-visibility-policy.test.ts +141 -0
- package/src/__tests__/memory-context-benchmark.test.ts +235 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
- package/src/__tests__/memory-query-builder.test.ts +59 -0
- package/src/__tests__/memory-recall-quality.test.ts +846 -0
- package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
- package/src/__tests__/memory-regressions.test.ts +4238 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
- package/src/__tests__/migration-cli-flows.test.ts +169 -0
- package/src/__tests__/migration-ordering.test.ts +249 -0
- package/src/__tests__/mock-signup-server.test.ts +528 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +166 -0
- package/src/__tests__/onboarding-template-contract.test.ts +58 -0
- package/src/__tests__/openai-provider.test.ts +753 -0
- package/src/__tests__/parser.test.ts +472 -0
- package/src/__tests__/path-classifier.test.ts +73 -0
- package/src/__tests__/path-policy.test.ts +435 -0
- package/src/__tests__/platform-move-helper.test.ts +99 -0
- package/src/__tests__/platform-socket-path.test.ts +52 -0
- package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
- package/src/__tests__/platform.test.ts +131 -0
- package/src/__tests__/prebuilt-home-base-seed.test.ts +71 -0
- package/src/__tests__/pricing.test.ts +256 -0
- package/src/__tests__/profile-compiler.test.ts +373 -0
- package/src/__tests__/provider-registry-ollama.test.ts +16 -0
- package/src/__tests__/proxy-approval-callback.test.ts +601 -0
- package/src/__tests__/ratelimit.test.ts +297 -0
- package/src/__tests__/registry.test.ts +487 -0
- package/src/__tests__/reminder-store.test.ts +220 -0
- package/src/__tests__/reminder.test.ts +263 -0
- package/src/__tests__/request-file-tool.test.ts +158 -0
- package/src/__tests__/run-orchestrator.test.ts +200 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +190 -0
- package/src/__tests__/runtime-runs-http.test.ts +451 -0
- package/src/__tests__/runtime-runs.test.ts +273 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
- package/src/__tests__/sandbox-host-parity.test.ts +950 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
- package/src/__tests__/script-proxy-certs.test.ts +90 -0
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
- package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
- package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
- package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
- package/src/__tests__/script-proxy-policy.test.ts +310 -0
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
- package/src/__tests__/script-proxy-router.test.ts +180 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
- package/src/__tests__/secret-allowlist.test.ts +229 -0
- package/src/__tests__/secret-ingress-handler.test.ts +99 -0
- package/src/__tests__/secret-onetime-send.test.ts +130 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
- package/src/__tests__/secret-response-routing.test.ts +93 -0
- package/src/__tests__/secret-scanner-executor.test.ts +348 -0
- package/src/__tests__/secret-scanner.test.ts +857 -0
- package/src/__tests__/secure-keys.test.ts +323 -0
- package/src/__tests__/server-history-render.test.ts +430 -0
- package/src/__tests__/session-abort-tool-results.test.ts +240 -0
- package/src/__tests__/session-conflict-gate.test.ts +697 -0
- package/src/__tests__/session-error.test.ts +341 -0
- package/src/__tests__/session-evictor.test.ts +188 -0
- package/src/__tests__/session-load-history-repair.test.ts +222 -0
- package/src/__tests__/session-pre-run-repair.test.ts +213 -0
- package/src/__tests__/session-profile-injection.test.ts +444 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
- package/src/__tests__/session-queue.test.ts +1462 -0
- package/src/__tests__/session-runtime-assembly.test.ts +315 -0
- package/src/__tests__/session-runtime-workspace.test.ts +183 -0
- package/src/__tests__/session-skill-tools.test.ts +2431 -0
- package/src/__tests__/session-slash-known.test.ts +368 -0
- package/src/__tests__/session-slash-queue.test.ts +288 -0
- package/src/__tests__/session-slash-unknown.test.ts +271 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
- package/src/__tests__/session-undo.test.ts +75 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
- package/src/__tests__/session-workspace-injection.test.ts +327 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
- package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
- package/src/__tests__/shell-credential-ref.test.ts +187 -0
- package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
- package/src/__tests__/shell-parser-property.test.ts +433 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
- package/src/__tests__/signup-e2e.test.ts +352 -0
- package/src/__tests__/size-guard.test.ts +117 -0
- package/src/__tests__/skill-include-graph.test.ts +303 -0
- package/src/__tests__/skill-load-tool.test.ts +409 -0
- package/src/__tests__/skill-script-runner-host.test.ts +489 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
- package/src/__tests__/skill-tool-factory.test.ts +252 -0
- package/src/__tests__/skill-tool-manifest.test.ts +658 -0
- package/src/__tests__/skill-version-hash.test.ts +182 -0
- package/src/__tests__/skills.test.ts +597 -0
- package/src/__tests__/slash-commands-catalog.test.ts +86 -0
- package/src/__tests__/slash-commands-parser.test.ts +119 -0
- package/src/__tests__/slash-commands-resolver.test.ts +193 -0
- package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
- package/src/__tests__/starter-bundle.test.ts +136 -0
- package/src/__tests__/starter-task-flow.test.ts +143 -0
- package/src/__tests__/subagent-manager-notify.test.ts +372 -0
- package/src/__tests__/subagent-tools.test.ts +118 -0
- package/src/__tests__/subagent-types.test.ts +78 -0
- package/src/__tests__/swarm-orchestrator.test.ts +428 -0
- package/src/__tests__/swarm-plan-validator.test.ts +330 -0
- package/src/__tests__/swarm-recursion.test.ts +165 -0
- package/src/__tests__/swarm-router-planner.test.ts +208 -0
- package/src/__tests__/swarm-session-integration.test.ts +274 -0
- package/src/__tests__/swarm-tool.test.ts +145 -0
- package/src/__tests__/swarm-worker-backend.test.ts +129 -0
- package/src/__tests__/swarm-worker-runner.test.ts +272 -0
- package/src/__tests__/system-prompt.test.ts +461 -0
- package/src/__tests__/task-compiler.test.ts +283 -0
- package/src/__tests__/task-runner.test.ts +215 -0
- package/src/__tests__/task-scheduler.test.ts +216 -0
- package/src/__tests__/task-tools.test.ts +602 -0
- package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
- package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
- package/src/__tests__/terminal-sandbox.test.ts +202 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
- package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
- package/src/__tests__/tool-audit-listener.test.ts +112 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +251 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
- package/src/__tests__/tool-executor-redaction.test.ts +289 -0
- package/src/__tests__/tool-executor.test.ts +1971 -0
- package/src/__tests__/tool-metrics-listener.test.ts +225 -0
- package/src/__tests__/tool-notification-listener.test.ts +49 -0
- package/src/__tests__/tool-policy.test.ts +54 -0
- package/src/__tests__/tool-profiling-listener.test.ts +268 -0
- package/src/__tests__/tool-result-truncation.test.ts +217 -0
- package/src/__tests__/tool-trace-listener.test.ts +226 -0
- package/src/__tests__/top-level-renderer.test.ts +121 -0
- package/src/__tests__/top-level-scanner.test.ts +141 -0
- package/src/__tests__/trace-emitter.test.ts +173 -0
- package/src/__tests__/trust-store.test.ts +2030 -0
- package/src/__tests__/turn-commit.test.ts +219 -0
- package/src/__tests__/url-safety.test.ts +418 -0
- package/src/__tests__/weather-skill-regression.test.ts +225 -0
- package/src/__tests__/web-fetch.test.ts +869 -0
- package/src/__tests__/web-search.test.ts +584 -0
- package/src/__tests__/workspace-git-service.test.ts +750 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +347 -0
- package/src/__tests__/workspace-lifecycle.test.ts +292 -0
- package/src/agent/attachments.ts +35 -0
- package/src/agent/loop.ts +500 -0
- package/src/agent/message-types.ts +17 -0
- package/src/autonomy/autonomy-resolver.ts +60 -0
- package/src/autonomy/autonomy-store.ts +122 -0
- package/src/autonomy/disposition-mapper.ts +31 -0
- package/src/autonomy/index.ts +11 -0
- package/src/autonomy/types.ts +39 -0
- package/src/bundler/app-bundler.ts +274 -0
- package/src/bundler/bundle-scanner.ts +535 -0
- package/src/bundler/bundle-signer.ts +124 -0
- package/src/bundler/manifest.ts +21 -0
- package/src/bundler/signature-verifier.ts +184 -0
- package/src/cli/autonomy.ts +188 -0
- package/src/cli/contacts.ts +149 -0
- package/src/cli/doordash.ts +824 -0
- package/src/cli/email-guardrails.ts +200 -0
- package/src/cli/email.ts +405 -0
- package/src/cli/main-screen.tsx +155 -0
- package/src/cli.ts +935 -0
- package/src/config/bundled-skills/.gitkeep +0 -0
- package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
- package/src/config/bundled-skills/agentmail/icon.svg +21 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1348 -0
- package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
- package/src/config/bundled-skills/app-builder/icon.svg +9 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
- package/src/config/bundled-skills/browser/SKILL.md +28 -0
- package/src/config/bundled-skills/browser/TOOLS.json +234 -0
- package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
- package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
- package/src/config/bundled-skills/google-calendar/types.ts +97 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +137 -0
- package/src/config/bundled-skills/messaging/SKILL.md +126 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +124 -0
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +29 -0
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +27 -0
- package/src/config/bundled-skills/messaging/tools/shared.ts +71 -0
- package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
- package/src/config/bundled-skills/self-upgrade/SKILL.md +74 -0
- package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
- package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
- package/src/config/bundled-skills/weather/SKILL.md +37 -0
- package/src/config/bundled-skills/weather/TOOLS.json +32 -0
- package/src/config/bundled-skills/weather/icon.svg +24 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
- package/src/config/computer-use-prompt.ts +97 -0
- package/src/config/defaults.ts +186 -0
- package/src/config/loader.ts +336 -0
- package/src/config/schema.ts +1004 -0
- package/src/config/skill-state.ts +95 -0
- package/src/config/skills.ts +972 -0
- package/src/config/system-prompt.ts +927 -0
- package/src/config/templates/BOOTSTRAP.md +70 -0
- package/src/config/templates/IDENTITY.md +18 -0
- package/src/config/templates/LOOKS.md +25 -0
- package/src/config/templates/SOUL.md +37 -0
- package/src/config/templates/USER.md +19 -0
- package/src/config/types.ts +32 -0
- package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
- package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +194 -0
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +147 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +105 -0
- package/src/contacts/contact-store.ts +410 -0
- package/src/contacts/index.ts +11 -0
- package/src/contacts/types.ts +28 -0
- package/src/context/token-estimator.ts +108 -0
- package/src/context/tool-result-truncation.ts +128 -0
- package/src/context/window-manager.ts +531 -0
- package/src/daemon/assistant-attachments.ts +679 -0
- package/src/daemon/classifier.ts +108 -0
- package/src/daemon/computer-use-session.ts +900 -0
- package/src/daemon/connection-policy.ts +41 -0
- package/src/daemon/handlers/apps.ts +446 -0
- package/src/daemon/handlers/computer-use.ts +181 -0
- package/src/daemon/handlers/config.ts +434 -0
- package/src/daemon/handlers/diagnostics.ts +334 -0
- package/src/daemon/handlers/documents.ts +184 -0
- package/src/daemon/handlers/home-base.ts +73 -0
- package/src/daemon/handlers/index.ts +355 -0
- package/src/daemon/handlers/misc.ts +323 -0
- package/src/daemon/handlers/open-bundle-handler.ts +80 -0
- package/src/daemon/handlers/publish.ts +182 -0
- package/src/daemon/handlers/sessions.ts +486 -0
- package/src/daemon/handlers/shared.ts +533 -0
- package/src/daemon/handlers/skills.ts +487 -0
- package/src/daemon/handlers/subagents.ts +122 -0
- package/src/daemon/handlers/work-items.ts +176 -0
- package/src/daemon/handlers.ts +17 -0
- package/src/daemon/history-repair.ts +214 -0
- package/src/daemon/ipc-blob-store.ts +231 -0
- package/src/daemon/ipc-contract-inventory.json +407 -0
- package/src/daemon/ipc-contract-inventory.ts +126 -0
- package/src/daemon/ipc-contract.ts +2102 -0
- package/src/daemon/ipc-protocol.ts +70 -0
- package/src/daemon/ipc-validate.ts +171 -0
- package/src/daemon/lifecycle.ts +503 -0
- package/src/daemon/main.ts +15 -0
- package/src/daemon/media-visibility-policy.ts +57 -0
- package/src/daemon/ride-shotgun-handler.ts +244 -0
- package/src/daemon/server.ts +1085 -0
- package/src/daemon/session-attachments.ts +173 -0
- package/src/daemon/session-conflict-gate.ts +219 -0
- package/src/daemon/session-dynamic-profile.ts +63 -0
- package/src/daemon/session-error.ts +269 -0
- package/src/daemon/session-evictor.ts +196 -0
- package/src/daemon/session-history.ts +437 -0
- package/src/daemon/session-memory.ts +212 -0
- package/src/daemon/session-process.ts +264 -0
- package/src/daemon/session-queue-manager.ts +81 -0
- package/src/daemon/session-runtime-assembly.ts +395 -0
- package/src/daemon/session-skill-tools.ts +237 -0
- package/src/daemon/session-slash.ts +302 -0
- package/src/daemon/session-surfaces.ts +624 -0
- package/src/daemon/session-tool-setup.ts +286 -0
- package/src/daemon/session-usage.ts +74 -0
- package/src/daemon/session-workspace.ts +19 -0
- package/src/daemon/session.ts +1651 -0
- package/src/daemon/trace-emitter.ts +82 -0
- package/src/daemon/watch-handler.ts +274 -0
- package/src/doordash/client.ts +905 -0
- package/src/doordash/queries.ts +1312 -0
- package/src/doordash/query-extractor.ts +93 -0
- package/src/doordash/session.ts +82 -0
- package/src/email/provider.ts +117 -0
- package/src/email/providers/agentmail.ts +317 -0
- package/src/email/providers/index.ts +58 -0
- package/src/email/service.ts +303 -0
- package/src/email/types.ts +126 -0
- package/src/events/bus.ts +157 -0
- package/src/events/domain-events.ts +83 -0
- package/src/events/index.ts +18 -0
- package/src/events/tool-audit-listener.ts +80 -0
- package/src/events/tool-domain-event-publisher.ts +111 -0
- package/src/events/tool-metrics-listener.ts +159 -0
- package/src/events/tool-notification-listener.ts +17 -0
- package/src/events/tool-profiling-listener.ts +158 -0
- package/src/events/tool-trace-listener.ts +75 -0
- package/src/export/formatter.ts +96 -0
- package/src/followups/followup-store.ts +166 -0
- package/src/followups/index.ts +10 -0
- package/src/followups/types.ts +23 -0
- package/src/gallery/default-gallery.ts +795 -0
- package/src/gallery/gallery-manifest.ts +24 -0
- package/src/home-base/app-link-store.ts +82 -0
- package/src/home-base/bootstrap.ts +66 -0
- package/src/home-base/prebuilt/index.html +662 -0
- package/src/home-base/prebuilt/seed-metadata.json +21 -0
- package/src/home-base/prebuilt/seed.ts +101 -0
- package/src/home-base/prebuilt-home-base-updater.ts +30 -0
- package/src/hooks/cli.ts +163 -0
- package/src/hooks/config.ts +88 -0
- package/src/hooks/discovery.ts +110 -0
- package/src/hooks/manager.ts +128 -0
- package/src/hooks/runner.ts +123 -0
- package/src/hooks/templates.ts +52 -0
- package/src/hooks/types.ts +72 -0
- package/src/index.ts +1194 -0
- package/src/instrument.ts +60 -0
- package/src/logfire.ts +99 -0
- package/src/media/gemini-image-service.ts +136 -0
- package/src/memory/account-store.ts +108 -0
- package/src/memory/admin.ts +211 -0
- package/src/memory/app-store.ts +556 -0
- package/src/memory/attachments-store.ts +453 -0
- package/src/memory/channel-delivery-store.ts +368 -0
- package/src/memory/checkpoints.ts +52 -0
- package/src/memory/clarification-resolver.ts +297 -0
- package/src/memory/conflict-store.ts +342 -0
- package/src/memory/contradiction-checker.ts +329 -0
- package/src/memory/conversation-key-store.ts +127 -0
- package/src/memory/conversation-store.ts +469 -0
- package/src/memory/db.ts +1105 -0
- package/src/memory/embedding-backend.ts +229 -0
- package/src/memory/embedding-gemini.ts +52 -0
- package/src/memory/embedding-local.ts +75 -0
- package/src/memory/embedding-ollama.ts +55 -0
- package/src/memory/embedding-openai.ts +25 -0
- package/src/memory/entity-extractor.ts +471 -0
- package/src/memory/fingerprint.ts +20 -0
- package/src/memory/indexer.ts +156 -0
- package/src/memory/items-extractor.ts +460 -0
- package/src/memory/job-handlers/backfill.ts +139 -0
- package/src/memory/job-handlers/cleanup.ts +58 -0
- package/src/memory/job-handlers/conflict.ts +99 -0
- package/src/memory/job-handlers/embedding.ts +61 -0
- package/src/memory/job-handlers/extraction.ts +123 -0
- package/src/memory/job-handlers/index-maintenance.ts +54 -0
- package/src/memory/job-handlers/summarization.ts +286 -0
- package/src/memory/job-utils.ts +170 -0
- package/src/memory/jobs-store.ts +400 -0
- package/src/memory/jobs-worker.ts +274 -0
- package/src/memory/llm-request-log-store.ts +45 -0
- package/src/memory/llm-usage-store.ts +62 -0
- package/src/memory/message-content.ts +54 -0
- package/src/memory/profile-compiler.ts +160 -0
- package/src/memory/published-pages-store.ts +137 -0
- package/src/memory/qdrant-client.ts +366 -0
- package/src/memory/qdrant-manager.ts +242 -0
- package/src/memory/query-builder.ts +45 -0
- package/src/memory/retrieval-budget.ts +30 -0
- package/src/memory/retriever.ts +653 -0
- package/src/memory/runs-store.ts +211 -0
- package/src/memory/schema.ts +529 -0
- package/src/memory/search/entity.ts +298 -0
- package/src/memory/search/formatting.ts +207 -0
- package/src/memory/search/lexical.ts +227 -0
- package/src/memory/search/ranking.ts +401 -0
- package/src/memory/search/semantic.ts +121 -0
- package/src/memory/search/types.ts +137 -0
- package/src/memory/segmenter.ts +68 -0
- package/src/memory/shared-app-links-store.ts +138 -0
- package/src/memory/tool-usage-store.ts +62 -0
- package/src/messaging/activity-analyzer.ts +76 -0
- package/src/messaging/draft-store.ts +88 -0
- package/src/messaging/index.ts +3 -0
- package/src/messaging/provider-types.ts +80 -0
- package/src/messaging/provider.ts +43 -0
- package/src/messaging/providers/gmail/adapter.ts +193 -0
- package/src/messaging/providers/gmail/client.ts +204 -0
- package/src/messaging/providers/gmail/types.ts +90 -0
- package/src/messaging/providers/slack/adapter.ts +202 -0
- package/src/messaging/providers/slack/client.ts +198 -0
- package/src/messaging/providers/slack/types.ts +119 -0
- package/src/messaging/registry.ts +34 -0
- package/src/messaging/style-analyzer.ts +158 -0
- package/src/messaging/thread-summarizer.ts +310 -0
- package/src/messaging/triage-engine.ts +321 -0
- package/src/messaging/types.ts +55 -0
- package/src/permissions/checker.ts +636 -0
- package/src/permissions/defaults.ts +243 -0
- package/src/permissions/prompter.ts +102 -0
- package/src/permissions/secret-prompter.ts +114 -0
- package/src/permissions/trust-store.ts +584 -0
- package/src/permissions/types.ts +62 -0
- package/src/playbooks/index.ts +2 -0
- package/src/playbooks/playbook-compiler.ts +90 -0
- package/src/playbooks/types.ts +55 -0
- package/src/providers/anthropic/client.ts +751 -0
- package/src/providers/failover.ts +129 -0
- package/src/providers/fireworks/client.ts +20 -0
- package/src/providers/gemini/client.ts +285 -0
- package/src/providers/ollama/client.ts +30 -0
- package/src/providers/openai/client.ts +337 -0
- package/src/providers/ratelimit.ts +93 -0
- package/src/providers/registry.ts +138 -0
- package/src/providers/retry.ts +106 -0
- package/src/providers/stream-timeout.ts +38 -0
- package/src/providers/types.ts +109 -0
- package/src/runtime/assistant-event-hub.ts +120 -0
- package/src/runtime/assistant-event.ts +82 -0
- package/src/runtime/http-server.ts +478 -0
- package/src/runtime/http-types.ts +68 -0
- package/src/runtime/routes/app-routes.ts +174 -0
- package/src/runtime/routes/attachment-routes.ts +134 -0
- package/src/runtime/routes/channel-routes.ts +342 -0
- package/src/runtime/routes/conversation-routes.ts +349 -0
- package/src/runtime/routes/run-routes.ts +223 -0
- package/src/runtime/routes/secret-routes.ts +76 -0
- package/src/runtime/run-orchestrator.ts +206 -0
- package/src/schedule/schedule-store.ts +452 -0
- package/src/schedule/scheduler.ts +168 -0
- package/src/security/encrypted-store.ts +238 -0
- package/src/security/keychain.ts +252 -0
- package/src/security/oauth2.ts +241 -0
- package/src/security/redaction.ts +89 -0
- package/src/security/secret-allowlist.ts +118 -0
- package/src/security/secret-ingress.ts +57 -0
- package/src/security/secret-scanner.ts +543 -0
- package/src/security/secure-keys.ts +180 -0
- package/src/security/token-manager.ts +141 -0
- package/src/services/published-app-updater.ts +69 -0
- package/src/services/vercel-deploy.ts +73 -0
- package/src/skills/active-skill-tools.ts +81 -0
- package/src/skills/clawhub.ts +414 -0
- package/src/skills/include-graph.ts +146 -0
- package/src/skills/managed-store.ts +233 -0
- package/src/skills/path-classifier.ts +128 -0
- package/src/skills/slash-commands.ts +174 -0
- package/src/skills/tool-manifest.ts +165 -0
- package/src/skills/version-hash.ts +110 -0
- package/src/slack/slack-webhook.ts +61 -0
- package/src/subagent/index.ts +19 -0
- package/src/subagent/manager.ts +477 -0
- package/src/subagent/types.ts +69 -0
- package/src/swarm/backend-claude-code.ts +90 -0
- package/src/swarm/index.ts +44 -0
- package/src/swarm/limits.ts +37 -0
- package/src/swarm/orchestrator.ts +279 -0
- package/src/swarm/plan-validator.ts +151 -0
- package/src/swarm/router-planner.ts +100 -0
- package/src/swarm/router-prompts.ts +36 -0
- package/src/swarm/synthesizer.ts +62 -0
- package/src/swarm/types.ts +62 -0
- package/src/swarm/worker-backend.ts +121 -0
- package/src/swarm/worker-prompts.ts +78 -0
- package/src/swarm/worker-runner.ts +164 -0
- package/src/tasks/SPEC.md +133 -0
- package/src/tasks/candidate-store.ts +86 -0
- package/src/tasks/ephemeral-permissions.ts +41 -0
- package/src/tasks/task-compiler.ts +198 -0
- package/src/tasks/task-runner.ts +85 -0
- package/src/tasks/task-scheduler.ts +20 -0
- package/src/tasks/task-store.ts +127 -0
- package/src/tools/apps/definitions.ts +59 -0
- package/src/tools/apps/executors.ts +313 -0
- package/src/tools/apps/open-proxy.ts +43 -0
- package/src/tools/apps/registry.ts +16 -0
- package/src/tools/assets/materialize.ts +218 -0
- package/src/tools/assets/search.ts +396 -0
- package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
- package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
- package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
- package/src/tools/browser/auth-cache.ts +149 -0
- package/src/tools/browser/auth-detector.ts +347 -0
- package/src/tools/browser/browser-execution.ts +979 -0
- package/src/tools/browser/browser-handoff.ts +79 -0
- package/src/tools/browser/browser-manager.ts +715 -0
- package/src/tools/browser/browser-screencast.ts +217 -0
- package/src/tools/browser/headless-browser.ts +450 -0
- package/src/tools/browser/jit-auth.ts +51 -0
- package/src/tools/browser/network-recorder.ts +348 -0
- package/src/tools/browser/network-recording-types.ts +49 -0
- package/src/tools/browser/recording-store.ts +49 -0
- package/src/tools/browser/runtime-check.ts +43 -0
- package/src/tools/claude-code/claude-code.ts +232 -0
- package/src/tools/computer-use/definitions.ts +443 -0
- package/src/tools/computer-use/registry.ts +22 -0
- package/src/tools/computer-use/request-computer-control.ts +53 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
- package/src/tools/contacts/contact-merge.ts +87 -0
- package/src/tools/contacts/contact-search.ts +102 -0
- package/src/tools/contacts/contact-upsert.ts +137 -0
- package/src/tools/contacts/index.ts +4 -0
- package/src/tools/credentials/account-registry.ts +127 -0
- package/src/tools/credentials/broker-types.ts +107 -0
- package/src/tools/credentials/broker.ts +372 -0
- package/src/tools/credentials/domain-policy.ts +51 -0
- package/src/tools/credentials/host-pattern-match.ts +60 -0
- package/src/tools/credentials/metadata-store.ts +335 -0
- package/src/tools/credentials/policy-types.ts +52 -0
- package/src/tools/credentials/policy-validate.ts +80 -0
- package/src/tools/credentials/resolve.ts +122 -0
- package/src/tools/credentials/selection.ts +159 -0
- package/src/tools/credentials/tool-policy.ts +25 -0
- package/src/tools/credentials/vault.ts +641 -0
- package/src/tools/document/document-tool.ts +165 -0
- package/src/tools/document/editor-template.ts +237 -0
- package/src/tools/document/index.ts +5 -0
- package/src/tools/executor.ts +825 -0
- package/src/tools/filesystem/edit.ts +127 -0
- package/src/tools/filesystem/fuzzy-match.ts +202 -0
- package/src/tools/filesystem/read.ts +71 -0
- package/src/tools/filesystem/view-image.ts +199 -0
- package/src/tools/filesystem/write.ts +79 -0
- package/src/tools/followups/followup_create.ts +118 -0
- package/src/tools/followups/followup_list.ts +100 -0
- package/src/tools/followups/followup_resolve.ts +91 -0
- package/src/tools/followups/index.ts +3 -0
- package/src/tools/host-filesystem/edit.ts +125 -0
- package/src/tools/host-filesystem/read.ts +80 -0
- package/src/tools/host-filesystem/write.ts +76 -0
- package/src/tools/host-terminal/cli-discover.ts +179 -0
- package/src/tools/host-terminal/host-shell.ts +181 -0
- package/src/tools/memory/definitions.ts +69 -0
- package/src/tools/memory/handlers.ts +245 -0
- package/src/tools/memory/register.ts +66 -0
- package/src/tools/network/domain-normalize.ts +85 -0
- package/src/tools/network/script-proxy/certs.ts +237 -0
- package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
- package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
- package/src/tools/network/script-proxy/index.ts +28 -0
- package/src/tools/network/script-proxy/logging.ts +196 -0
- package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
- package/src/tools/network/script-proxy/policy.ts +152 -0
- package/src/tools/network/script-proxy/router.ts +60 -0
- package/src/tools/network/script-proxy/server.ts +136 -0
- package/src/tools/network/script-proxy/session-manager.ts +534 -0
- package/src/tools/network/script-proxy/types.ts +125 -0
- package/src/tools/network/url-safety.ts +227 -0
- package/src/tools/network/web-fetch.ts +701 -0
- package/src/tools/network/web-search.ts +319 -0
- package/src/tools/playbooks/index.ts +5 -0
- package/src/tools/playbooks/playbook-create.ts +140 -0
- package/src/tools/playbooks/playbook-delete.ts +76 -0
- package/src/tools/playbooks/playbook-list.ts +101 -0
- package/src/tools/playbooks/playbook-update.ts +159 -0
- package/src/tools/registry.ts +297 -0
- package/src/tools/reminder/reminder-store.ts +148 -0
- package/src/tools/reminder/reminder.ts +153 -0
- package/src/tools/schedule/create.ts +86 -0
- package/src/tools/schedule/delete.ts +54 -0
- package/src/tools/schedule/list.ts +88 -0
- package/src/tools/schedule/update.ts +97 -0
- package/src/tools/shared/filesystem/edit-engine.ts +56 -0
- package/src/tools/shared/filesystem/errors.ts +85 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
- package/src/tools/shared/filesystem/format-diff.ts +35 -0
- package/src/tools/shared/filesystem/path-policy.ts +125 -0
- package/src/tools/shared/filesystem/size-guard.ts +41 -0
- package/src/tools/shared/filesystem/types.ts +80 -0
- package/src/tools/shared/shell-output.ts +52 -0
- package/src/tools/skills/delete-managed.ts +60 -0
- package/src/tools/skills/load.ts +139 -0
- package/src/tools/skills/sandbox-runner.ts +279 -0
- package/src/tools/skills/scaffold-managed.ts +150 -0
- package/src/tools/skills/script-contract.ts +6 -0
- package/src/tools/skills/skill-script-runner.ts +86 -0
- package/src/tools/skills/skill-tool-factory.ts +64 -0
- package/src/tools/skills/vellum-catalog.ts +217 -0
- package/src/tools/subagent/abort.ts +62 -0
- package/src/tools/subagent/index.ts +5 -0
- package/src/tools/subagent/message.ts +72 -0
- package/src/tools/subagent/read.ts +98 -0
- package/src/tools/subagent/spawn.ts +85 -0
- package/src/tools/subagent/status.ts +74 -0
- package/src/tools/swarm/delegate.ts +182 -0
- package/src/tools/system/request-permission.ts +98 -0
- package/src/tools/tasks/index.ts +25 -0
- package/src/tools/tasks/task-delete.ts +69 -0
- package/src/tools/tasks/task-list.ts +65 -0
- package/src/tools/tasks/task-run.ts +125 -0
- package/src/tools/tasks/task-save.ts +79 -0
- package/src/tools/tasks/work-item-enqueue.ts +176 -0
- package/src/tools/tasks/work-item-list.ts +86 -0
- package/src/tools/terminal/backends/docker.ts +372 -0
- package/src/tools/terminal/backends/native.ts +188 -0
- package/src/tools/terminal/backends/types.ts +26 -0
- package/src/tools/terminal/evaluate-typescript.ts +275 -0
- package/src/tools/terminal/parser.ts +393 -0
- package/src/tools/terminal/safe-env.ts +37 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
- package/src/tools/terminal/sandbox.ts +44 -0
- package/src/tools/terminal/shell.ts +257 -0
- package/src/tools/tool-manifest.ts +250 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/ui-surface/definitions.ts +232 -0
- package/src/tools/ui-surface/registry.ts +14 -0
- package/src/tools/watch/screen-watch.ts +128 -0
- package/src/tools/watch/watch-state.ts +119 -0
- package/src/tools/watcher/create.ts +110 -0
- package/src/tools/watcher/delete.ts +53 -0
- package/src/tools/watcher/digest.ts +84 -0
- package/src/tools/watcher/list.ts +90 -0
- package/src/tools/watcher/update.ts +102 -0
- package/src/tools/weather/service.ts +551 -0
- package/src/usage/actors.ts +24 -0
- package/src/usage/types.ts +38 -0
- package/src/util/clipboard.ts +33 -0
- package/src/util/content-id.ts +16 -0
- package/src/util/diff.ts +181 -0
- package/src/util/errors.ts +129 -0
- package/src/util/logger.ts +243 -0
- package/src/util/platform.ts +607 -0
- package/src/util/pricing.ts +150 -0
- package/src/util/spinner.ts +51 -0
- package/src/util/time.ts +16 -0
- package/src/util/xml.ts +4 -0
- package/src/version.ts +3 -0
- package/src/watcher/constants.ts +11 -0
- package/src/watcher/engine.ts +199 -0
- package/src/watcher/provider-registry.ts +15 -0
- package/src/watcher/provider-types.ts +48 -0
- package/src/watcher/providers/gmail.ts +198 -0
- package/src/watcher/providers/google-calendar.ts +228 -0
- package/src/watcher/providers/slack.ts +128 -0
- package/src/watcher/watcher-store.ts +418 -0
- package/src/work-items/work-item-store.ts +91 -0
- package/src/workspace/git-service.ts +620 -0
- package/src/workspace/heartbeat-service.ts +288 -0
- package/src/workspace/top-level-renderer.ts +19 -0
- package/src/workspace/top-level-scanner.ts +41 -0
- package/src/workspace/turn-commit.ts +122 -0
- package/tsconfig.json +21 -0
- package/LICENSE +0 -674
- package/dist/cli.js +0 -569
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterAll, mock } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
const testDir = mkdtempSync(join(tmpdir(), 'conv-store-test-'));
|
|
7
|
+
|
|
8
|
+
mock.module('../util/platform.js', () => ({
|
|
9
|
+
getDataDir: () => testDir,
|
|
10
|
+
isMacOS: () => process.platform === 'darwin',
|
|
11
|
+
isLinux: () => process.platform === 'linux',
|
|
12
|
+
isWindows: () => process.platform === 'win32',
|
|
13
|
+
getSocketPath: () => join(testDir, 'test.sock'),
|
|
14
|
+
getPidPath: () => join(testDir, 'test.pid'),
|
|
15
|
+
getDbPath: () => join(testDir, 'test.db'),
|
|
16
|
+
getLogPath: () => join(testDir, 'test.log'),
|
|
17
|
+
ensureDataDir: () => {},
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
mock.module('../util/logger.js', () => ({
|
|
21
|
+
getLogger: () => new Proxy({} as Record<string, unknown>, {
|
|
22
|
+
get: () => () => {},
|
|
23
|
+
}),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import { initializeDb, getDb } from '../memory/db.js';
|
|
27
|
+
import {
|
|
28
|
+
createConversation,
|
|
29
|
+
getConversation,
|
|
30
|
+
getConversationThreadType,
|
|
31
|
+
getConversationMemoryScopeId,
|
|
32
|
+
addMessage,
|
|
33
|
+
getMessages,
|
|
34
|
+
deleteLastExchange,
|
|
35
|
+
isLastUserMessageToolResult,
|
|
36
|
+
clearAll,
|
|
37
|
+
} from '../memory/conversation-store.js';
|
|
38
|
+
import {
|
|
39
|
+
uploadAttachment,
|
|
40
|
+
linkAttachmentToMessage,
|
|
41
|
+
getAttachmentsForMessage,
|
|
42
|
+
getAttachmentById,
|
|
43
|
+
getAttachmentsForMessageUnscoped,
|
|
44
|
+
} from '../memory/attachments-store.js';
|
|
45
|
+
|
|
46
|
+
// Initialize db once before all tests
|
|
47
|
+
initializeDb();
|
|
48
|
+
|
|
49
|
+
afterAll(() => {
|
|
50
|
+
try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('deleteLastExchange', () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
// Reset database between tests by dropping and recreating tables
|
|
56
|
+
const db = getDb();
|
|
57
|
+
db.run(`DELETE FROM messages`);
|
|
58
|
+
db.run(`DELETE FROM conversations`);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('deletes last user message and subsequent assistant messages', () => {
|
|
62
|
+
const conv = createConversation('test');
|
|
63
|
+
addMessage(conv.id, 'user', 'first question');
|
|
64
|
+
addMessage(conv.id, 'assistant', 'first answer');
|
|
65
|
+
addMessage(conv.id, 'user', 'second question');
|
|
66
|
+
addMessage(conv.id, 'assistant', 'second answer');
|
|
67
|
+
|
|
68
|
+
const deleted = deleteLastExchange(conv.id);
|
|
69
|
+
expect(deleted).toBe(2);
|
|
70
|
+
|
|
71
|
+
const remaining = getMessages(conv.id);
|
|
72
|
+
expect(remaining).toHaveLength(2);
|
|
73
|
+
expect(remaining[0].content).toBe('first question');
|
|
74
|
+
expect(remaining[1].content).toBe('first answer');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('returns 0 when no user messages exist', () => {
|
|
78
|
+
const conv = createConversation('test');
|
|
79
|
+
addMessage(conv.id, 'assistant', 'hello');
|
|
80
|
+
|
|
81
|
+
const deleted = deleteLastExchange(conv.id);
|
|
82
|
+
expect(deleted).toBe(0);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('returns 0 for empty conversation', () => {
|
|
86
|
+
const conv = createConversation('test');
|
|
87
|
+
const deleted = deleteLastExchange(conv.id);
|
|
88
|
+
expect(deleted).toBe(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('uses rowid ordering so same-timestamp messages are handled correctly', () => {
|
|
92
|
+
const conv = createConversation('test');
|
|
93
|
+
const db = getDb();
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
|
|
96
|
+
// Insert three user messages with the exact same timestamp.
|
|
97
|
+
// rowid order determines which is "last", not timestamp.
|
|
98
|
+
db.run(
|
|
99
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES ('m1', '${conv.id}', 'user', 'first', ${now})`,
|
|
100
|
+
);
|
|
101
|
+
db.run(
|
|
102
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES ('m2', '${conv.id}', 'assistant', 'reply1', ${now})`,
|
|
103
|
+
);
|
|
104
|
+
db.run(
|
|
105
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES ('m3', '${conv.id}', 'user', 'second', ${now})`,
|
|
106
|
+
);
|
|
107
|
+
db.run(
|
|
108
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES ('m4', '${conv.id}', 'assistant', 'reply2', ${now})`,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// deleteLastExchange should find m3 (the last user message by rowid),
|
|
112
|
+
// then delete m3 and m4 (everything at rowid >= m3's rowid).
|
|
113
|
+
const deleted = deleteLastExchange(conv.id);
|
|
114
|
+
expect(deleted).toBe(2);
|
|
115
|
+
|
|
116
|
+
const remaining = getMessages(conv.id);
|
|
117
|
+
expect(remaining).toHaveLength(2);
|
|
118
|
+
expect(remaining[0].content).toBe('first');
|
|
119
|
+
expect(remaining[1].content).toBe('reply1');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('isLastUserMessageToolResult', () => {
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
const db = getDb();
|
|
126
|
+
db.run(`DELETE FROM messages`);
|
|
127
|
+
db.run(`DELETE FROM conversations`);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('returns true when last user message is tool_result only', () => {
|
|
131
|
+
const conv = createConversation('test');
|
|
132
|
+
addMessage(conv.id, 'user', 'hello');
|
|
133
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'tool_use', id: 'tu1', name: 'bash', input: {} }]));
|
|
134
|
+
addMessage(conv.id, 'user', JSON.stringify([{ type: 'tool_result', tool_use_id: 'tu1', content: 'ok' }]));
|
|
135
|
+
|
|
136
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('returns false when last user message is plain text', () => {
|
|
140
|
+
const conv = createConversation('test');
|
|
141
|
+
addMessage(conv.id, 'user', 'hello');
|
|
142
|
+
|
|
143
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('returns false when no user messages exist', () => {
|
|
147
|
+
const conv = createConversation('test');
|
|
148
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(false);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('returns false when last user message has mixed content types', () => {
|
|
152
|
+
const conv = createConversation('test');
|
|
153
|
+
addMessage(conv.id, 'user', JSON.stringify([
|
|
154
|
+
{ type: 'text', text: 'hello' },
|
|
155
|
+
{ type: 'tool_result', tool_use_id: 'tu1', content: 'ok' },
|
|
156
|
+
]));
|
|
157
|
+
|
|
158
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('deleteLastExchange with tool_result messages', () => {
|
|
163
|
+
beforeEach(() => {
|
|
164
|
+
const db = getDb();
|
|
165
|
+
db.run(`DELETE FROM messages`);
|
|
166
|
+
db.run(`DELETE FROM conversations`);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('looping deleteLastExchange cleans up tool_result user messages', () => {
|
|
170
|
+
const conv = createConversation('test');
|
|
171
|
+
// Simulate: user asks question -> assistant uses tool -> tool_result -> assistant responds
|
|
172
|
+
addMessage(conv.id, 'user', 'What files are in /tmp?');
|
|
173
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'tool_use', id: 'tu1', name: 'bash', input: { command: 'ls /tmp' } }]));
|
|
174
|
+
addMessage(conv.id, 'user', JSON.stringify([{ type: 'tool_result', tool_use_id: 'tu1', content: 'file1.txt' }]));
|
|
175
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'text', text: 'There is file1.txt in /tmp' }]));
|
|
176
|
+
|
|
177
|
+
// First deleteLastExchange removes the tool_result user msg + final assistant msg
|
|
178
|
+
let deleted = deleteLastExchange(conv.id);
|
|
179
|
+
expect(deleted).toBe(2);
|
|
180
|
+
|
|
181
|
+
// After deleting the tool_result user + assistant, the remaining are:
|
|
182
|
+
// user: "What files are in /tmp?" and assistant: tool_use
|
|
183
|
+
let remaining = getMessages(conv.id);
|
|
184
|
+
expect(remaining).toHaveLength(2);
|
|
185
|
+
|
|
186
|
+
// The last user message is the real one, so isLastUserMessageToolResult should be false
|
|
187
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(false);
|
|
188
|
+
|
|
189
|
+
// Now delete again to remove the real user message + tool_use assistant
|
|
190
|
+
deleted = deleteLastExchange(conv.id);
|
|
191
|
+
expect(deleted).toBe(2);
|
|
192
|
+
|
|
193
|
+
remaining = getMessages(conv.id);
|
|
194
|
+
expect(remaining).toHaveLength(0);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('looping pattern handles multiple tool uses in sequence', () => {
|
|
198
|
+
const conv = createConversation('test');
|
|
199
|
+
// user -> assistant(tool_use) -> user(tool_result) -> assistant(tool_use) -> user(tool_result) -> assistant(text)
|
|
200
|
+
addMessage(conv.id, 'user', 'Do two things');
|
|
201
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'tool_use', id: 'tu1', name: 'bash', input: {} }]));
|
|
202
|
+
addMessage(conv.id, 'user', JSON.stringify([{ type: 'tool_result', tool_use_id: 'tu1', content: 'result1' }]));
|
|
203
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'tool_use', id: 'tu2', name: 'bash', input: {} }]));
|
|
204
|
+
addMessage(conv.id, 'user', JSON.stringify([{ type: 'tool_result', tool_use_id: 'tu2', content: 'result2' }]));
|
|
205
|
+
addMessage(conv.id, 'assistant', JSON.stringify([{ type: 'text', text: 'Done both' }]));
|
|
206
|
+
|
|
207
|
+
// First delete: removes last tool_result user (row 5) + final assistant (row 6)
|
|
208
|
+
deleteLastExchange(conv.id);
|
|
209
|
+
// Last user is now row 3 (tool_result tu1)
|
|
210
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(true);
|
|
211
|
+
|
|
212
|
+
// Second delete: removes tool_result user (row 3) + assistant tool_use (row 4)
|
|
213
|
+
deleteLastExchange(conv.id);
|
|
214
|
+
// Last user is now row 1 (real user message)
|
|
215
|
+
expect(isLastUserMessageToolResult(conv.id)).toBe(false);
|
|
216
|
+
|
|
217
|
+
// Final delete removes the real user message + assistant tool_use
|
|
218
|
+
deleteLastExchange(conv.id);
|
|
219
|
+
|
|
220
|
+
const remaining = getMessages(conv.id);
|
|
221
|
+
expect(remaining).toHaveLength(0);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('attachment orphan cleanup', () => {
|
|
226
|
+
beforeEach(() => {
|
|
227
|
+
const db = getDb();
|
|
228
|
+
db.run('DELETE FROM message_attachments');
|
|
229
|
+
db.run('DELETE FROM attachments');
|
|
230
|
+
db.run('DELETE FROM messages');
|
|
231
|
+
db.run('DELETE FROM conversations');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('deleteLastExchange cleans up orphaned attachments', () => {
|
|
235
|
+
const conv = createConversation('test');
|
|
236
|
+
addMessage(conv.id, 'user', 'hello');
|
|
237
|
+
const assistantMsg = addMessage(conv.id, 'assistant', 'Here is a file');
|
|
238
|
+
|
|
239
|
+
const stored = uploadAttachment('ast-1', 'chart.png', 'image/png', 'iVBOR');
|
|
240
|
+
linkAttachmentToMessage(assistantMsg.id, stored.id, 0);
|
|
241
|
+
|
|
242
|
+
// Verify attachment is linked
|
|
243
|
+
expect(getAttachmentsForMessageUnscoped(assistantMsg.id)).toHaveLength(1);
|
|
244
|
+
|
|
245
|
+
// Delete the exchange — should also clean up orphaned attachments
|
|
246
|
+
deleteLastExchange(conv.id);
|
|
247
|
+
|
|
248
|
+
// Attachment row should be gone
|
|
249
|
+
const raw = (getDb() as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
250
|
+
const remaining = raw.query('SELECT COUNT(*) AS c FROM attachments').get() as { c: number };
|
|
251
|
+
expect(remaining.c).toBe(0);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('deleteLastExchange preserves attachments still linked to other messages', () => {
|
|
255
|
+
const conv = createConversation('test');
|
|
256
|
+
const msg1 = addMessage(conv.id, 'assistant', 'first');
|
|
257
|
+
addMessage(conv.id, 'user', 'question');
|
|
258
|
+
const msg2 = addMessage(conv.id, 'assistant', 'second');
|
|
259
|
+
|
|
260
|
+
const shared = uploadAttachment('ast-1', 'shared.png', 'image/png', 'AAAA');
|
|
261
|
+
linkAttachmentToMessage(msg1.id, shared.id, 0);
|
|
262
|
+
linkAttachmentToMessage(msg2.id, shared.id, 0);
|
|
263
|
+
|
|
264
|
+
// Delete last exchange (removes msg2 + user question)
|
|
265
|
+
deleteLastExchange(conv.id);
|
|
266
|
+
|
|
267
|
+
// Attachment should survive because msg1 still links to it
|
|
268
|
+
const raw = (getDb() as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
269
|
+
const remaining = raw.query('SELECT COUNT(*) AS c FROM attachments').get() as { c: number };
|
|
270
|
+
expect(remaining.c).toBe(1);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test('clearAll removes all attachments', () => {
|
|
274
|
+
const conv = createConversation('test');
|
|
275
|
+
const msg = addMessage(conv.id, 'assistant', 'file');
|
|
276
|
+
const stored = uploadAttachment('ast-1', 'doc.pdf', 'application/pdf', 'JVBER');
|
|
277
|
+
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
278
|
+
|
|
279
|
+
clearAll();
|
|
280
|
+
|
|
281
|
+
const raw = (getDb() as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
282
|
+
const attachmentCount = raw.query('SELECT COUNT(*) AS c FROM attachments').get() as { c: number };
|
|
283
|
+
const linkCount = raw.query('SELECT COUNT(*) AS c FROM message_attachments').get() as { c: number };
|
|
284
|
+
expect(attachmentCount.c).toBe(0);
|
|
285
|
+
expect(linkCount.c).toBe(0);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('deleteLastExchange does not delete unlinked user uploads', () => {
|
|
289
|
+
const conv = createConversation('test');
|
|
290
|
+
addMessage(conv.id, 'user', 'hello');
|
|
291
|
+
const assistantMsg = addMessage(conv.id, 'assistant', 'Here is a file');
|
|
292
|
+
|
|
293
|
+
// An attachment linked to the assistant message (should be cleaned up)
|
|
294
|
+
const linked = uploadAttachment('ast-1', 'chart.png', 'image/png', 'iVBOR');
|
|
295
|
+
linkAttachmentToMessage(assistantMsg.id, linked.id, 0);
|
|
296
|
+
|
|
297
|
+
// A freshly uploaded attachment not linked to any message (should survive)
|
|
298
|
+
uploadAttachment('ast-1', 'pending.png', 'image/png', 'AAAA');
|
|
299
|
+
|
|
300
|
+
deleteLastExchange(conv.id);
|
|
301
|
+
|
|
302
|
+
const raw = (getDb() as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
303
|
+
const remaining = raw.query('SELECT COUNT(*) AS c FROM attachments').get() as { c: number };
|
|
304
|
+
expect(remaining.c).toBe(1); // only the unlinked upload survives
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe('conversation thread metadata defaults', () => {
|
|
309
|
+
beforeEach(() => {
|
|
310
|
+
const db = getDb();
|
|
311
|
+
db.run(`DELETE FROM messages`);
|
|
312
|
+
db.run(`DELETE FROM conversations`);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('new conversation has threadType defaulting to standard', () => {
|
|
316
|
+
const conv = createConversation('test');
|
|
317
|
+
expect(conv.threadType).toBe('standard');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test('new conversation has memoryScopeId defaulting to default', () => {
|
|
321
|
+
const conv = createConversation('test');
|
|
322
|
+
expect(conv.memoryScopeId).toBe('default');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test('defaults are persisted and retrievable from DB', () => {
|
|
326
|
+
const conv = createConversation('test');
|
|
327
|
+
const loaded = getConversation(conv.id);
|
|
328
|
+
expect(loaded).not.toBeNull();
|
|
329
|
+
expect(loaded!.threadType).toBe('standard');
|
|
330
|
+
expect(loaded!.memoryScopeId).toBe('default');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test('existing conversations without explicit values get defaults via migration', () => {
|
|
334
|
+
// Insert a conversation row directly without the new columns
|
|
335
|
+
// (simulates a pre-migration row — the ALTER TABLE DEFAULT handles it)
|
|
336
|
+
const db = getDb();
|
|
337
|
+
const now = Date.now();
|
|
338
|
+
const id = 'legacy-conv-' + now;
|
|
339
|
+
db.run(
|
|
340
|
+
`INSERT INTO conversations (id, title, created_at, updated_at) VALUES ('${id}', 'legacy', ${now}, ${now})`,
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
const loaded = getConversation(id);
|
|
344
|
+
expect(loaded).not.toBeNull();
|
|
345
|
+
expect(loaded!.threadType).toBe('standard');
|
|
346
|
+
expect(loaded!.memoryScopeId).toBe('default');
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
describe('createConversation with thread type option', () => {
|
|
351
|
+
beforeEach(() => {
|
|
352
|
+
const db = getDb();
|
|
353
|
+
db.run(`DELETE FROM messages`);
|
|
354
|
+
db.run(`DELETE FROM conversations`);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('standard create with string title uses defaults', () => {
|
|
358
|
+
const conv = createConversation('hello');
|
|
359
|
+
expect(conv.title).toBe('hello');
|
|
360
|
+
expect(conv.threadType).toBe('standard');
|
|
361
|
+
expect(conv.memoryScopeId).toBe('default');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('standard create with options object uses defaults', () => {
|
|
365
|
+
const conv = createConversation({ title: 'hello', threadType: 'standard' });
|
|
366
|
+
expect(conv.threadType).toBe('standard');
|
|
367
|
+
expect(conv.memoryScopeId).toBe('default');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test('private create sets threadType and derives memoryScopeId', () => {
|
|
371
|
+
const conv = createConversation({ title: 'secret', threadType: 'private' });
|
|
372
|
+
expect(conv.threadType).toBe('private');
|
|
373
|
+
expect(conv.memoryScopeId).toBe(`private:${conv.id}`);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('private create memoryScopeId is persisted', () => {
|
|
377
|
+
const conv = createConversation({ threadType: 'private' });
|
|
378
|
+
const loaded = getConversation(conv.id);
|
|
379
|
+
expect(loaded).not.toBeNull();
|
|
380
|
+
expect(loaded!.threadType).toBe('private');
|
|
381
|
+
expect(loaded!.memoryScopeId).toBe(`private:${conv.id}`);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('no-arg create uses defaults', () => {
|
|
385
|
+
const conv = createConversation();
|
|
386
|
+
expect(conv.threadType).toBe('standard');
|
|
387
|
+
expect(conv.memoryScopeId).toBe('default');
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
describe('conversation metadata read helpers', () => {
|
|
392
|
+
beforeEach(() => {
|
|
393
|
+
const db = getDb();
|
|
394
|
+
db.run(`DELETE FROM messages`);
|
|
395
|
+
db.run(`DELETE FROM conversations`);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test('getConversationThreadType returns standard for standard conversation', () => {
|
|
399
|
+
const conv = createConversation('test');
|
|
400
|
+
expect(getConversationThreadType(conv.id)).toBe('standard');
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('getConversationThreadType returns private for private conversation', () => {
|
|
404
|
+
const conv = createConversation({ threadType: 'private' });
|
|
405
|
+
expect(getConversationThreadType(conv.id)).toBe('private');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test('getConversationThreadType returns standard for missing conversation', () => {
|
|
409
|
+
expect(getConversationThreadType('nonexistent-id')).toBe('standard');
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test('getConversationMemoryScopeId returns default for standard conversation', () => {
|
|
413
|
+
const conv = createConversation('test');
|
|
414
|
+
expect(getConversationMemoryScopeId(conv.id)).toBe('default');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('getConversationMemoryScopeId returns private scope for private conversation', () => {
|
|
418
|
+
const conv = createConversation({ threadType: 'private' });
|
|
419
|
+
expect(getConversationMemoryScopeId(conv.id)).toBe(`private:${conv.id}`);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('getConversationMemoryScopeId returns default for missing conversation', () => {
|
|
423
|
+
expect(getConversationMemoryScopeId('nonexistent-id')).toBe('default');
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// ---------------------------------------------------------------------------
|
|
428
|
+
// Baseline: attachment reuse across threads
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
|
|
431
|
+
describe('attachment reuse across thread lifecycles', () => {
|
|
432
|
+
beforeEach(() => {
|
|
433
|
+
const db = getDb();
|
|
434
|
+
db.run('DELETE FROM message_attachments');
|
|
435
|
+
db.run('DELETE FROM attachments');
|
|
436
|
+
db.run('DELETE FROM messages');
|
|
437
|
+
db.run('DELETE FROM conversations');
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test('attachment uploaded in conversation A is retrievable by ID without any conversation reference', () => {
|
|
441
|
+
const convA = createConversation('Thread A');
|
|
442
|
+
const msgA = addMessage(convA.id, 'assistant', 'Here is a file');
|
|
443
|
+
const stored = uploadAttachment('ast-1', 'report.pdf', 'application/pdf', 'JVBER');
|
|
444
|
+
linkAttachmentToMessage(msgA.id, stored.id, 0);
|
|
445
|
+
|
|
446
|
+
// Create a completely separate conversation
|
|
447
|
+
const convB = createConversation('Thread B');
|
|
448
|
+
addMessage(convB.id, 'user', 'hello');
|
|
449
|
+
|
|
450
|
+
// The attachment is retrievable by ID regardless of which conversation is active.
|
|
451
|
+
// getAttachmentById only scopes by assistantId, not conversationId.
|
|
452
|
+
const fetched = getAttachmentById('ast-1', stored.id);
|
|
453
|
+
expect(fetched).not.toBeNull();
|
|
454
|
+
expect(fetched!.id).toBe(stored.id);
|
|
455
|
+
expect(fetched!.originalFilename).toBe('report.pdf');
|
|
456
|
+
expect(fetched!.dataBase64).toBe('JVBER');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test('attachment can be linked to messages in different conversations', () => {
|
|
460
|
+
const convA = createConversation('Thread A');
|
|
461
|
+
const convB = createConversation('Thread B');
|
|
462
|
+
|
|
463
|
+
const msgA = addMessage(convA.id, 'assistant', 'Original file');
|
|
464
|
+
const msgB = addMessage(convB.id, 'assistant', 'Reused file');
|
|
465
|
+
|
|
466
|
+
// Upload once, link to both conversations
|
|
467
|
+
const stored = uploadAttachment('ast-1', 'shared.png', 'image/png', 'iVBORw0K');
|
|
468
|
+
linkAttachmentToMessage(msgA.id, stored.id, 0);
|
|
469
|
+
linkAttachmentToMessage(msgB.id, stored.id, 0);
|
|
470
|
+
|
|
471
|
+
// Both messages see the attachment
|
|
472
|
+
const linkedA = getAttachmentsForMessage(msgA.id, 'ast-1');
|
|
473
|
+
expect(linkedA).toHaveLength(1);
|
|
474
|
+
expect(linkedA[0].id).toBe(stored.id);
|
|
475
|
+
|
|
476
|
+
const linkedB = getAttachmentsForMessage(msgB.id, 'ast-1');
|
|
477
|
+
expect(linkedB).toHaveLength(1);
|
|
478
|
+
expect(linkedB[0].id).toBe(stored.id);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test('deleting conversation A does not orphan attachment reused in conversation B', () => {
|
|
482
|
+
const convA = createConversation('Thread A');
|
|
483
|
+
const convB = createConversation('Thread B');
|
|
484
|
+
|
|
485
|
+
// deleteLastExchange deletes from the last user message onward,
|
|
486
|
+
// so we need a user message before the assistant message that carries the attachment.
|
|
487
|
+
addMessage(convA.id, 'user', 'Please generate a chart');
|
|
488
|
+
const msgA = addMessage(convA.id, 'assistant', 'Original');
|
|
489
|
+
addMessage(convB.id, 'user', 'Show me the chart');
|
|
490
|
+
const msgB = addMessage(convB.id, 'assistant', 'Reused');
|
|
491
|
+
|
|
492
|
+
const stored = uploadAttachment('ast-1', 'chart.png', 'image/png', 'AAAA');
|
|
493
|
+
linkAttachmentToMessage(msgA.id, stored.id, 0);
|
|
494
|
+
linkAttachmentToMessage(msgB.id, stored.id, 0);
|
|
495
|
+
|
|
496
|
+
// Delete conversation A's exchange
|
|
497
|
+
deleteLastExchange(convA.id);
|
|
498
|
+
|
|
499
|
+
// Attachment survives because convB still references it
|
|
500
|
+
const fetched = getAttachmentById('ast-1', stored.id);
|
|
501
|
+
expect(fetched).not.toBeNull();
|
|
502
|
+
|
|
503
|
+
// convB's message still has the attachment linked
|
|
504
|
+
const linkedB = getAttachmentsForMessage(msgB.id, 'ast-1');
|
|
505
|
+
expect(linkedB).toHaveLength(1);
|
|
506
|
+
expect(linkedB[0].id).toBe(stored.id);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test('content-hash dedup works across conversations', () => {
|
|
510
|
+
const convA = createConversation('Thread A');
|
|
511
|
+
const convB = createConversation('Thread B');
|
|
512
|
+
|
|
513
|
+
addMessage(convA.id, 'user', 'upload in A');
|
|
514
|
+
addMessage(convB.id, 'user', 'upload in B');
|
|
515
|
+
|
|
516
|
+
// Same content uploaded in two different conversation contexts
|
|
517
|
+
const first = uploadAttachment('ast-1', 'photo.png', 'image/png', 'DEDUPCROSS');
|
|
518
|
+
const second = uploadAttachment('ast-1', 'photo.png', 'image/png', 'DEDUPCROSS');
|
|
519
|
+
|
|
520
|
+
// Dedup returns the same attachment row
|
|
521
|
+
expect(second.id).toBe(first.id);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// ---------------------------------------------------------------------------
|
|
526
|
+
// Baseline: no private-thread visibility boundary for attachments
|
|
527
|
+
// ---------------------------------------------------------------------------
|
|
528
|
+
|
|
529
|
+
describe('no private-thread attachment visibility boundary', () => {
|
|
530
|
+
beforeEach(() => {
|
|
531
|
+
const db = getDb();
|
|
532
|
+
db.run('DELETE FROM message_attachments');
|
|
533
|
+
db.run('DELETE FROM attachments');
|
|
534
|
+
db.run('DELETE FROM messages');
|
|
535
|
+
db.run('DELETE FROM conversations');
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test('attachment from a private thread is visible via getAttachmentById (no thread scoping)', () => {
|
|
539
|
+
const privateConv = createConversation({ title: 'Secret', threadType: 'private' });
|
|
540
|
+
expect(privateConv.threadType).toBe('private');
|
|
541
|
+
|
|
542
|
+
const msg = addMessage(privateConv.id, 'assistant', 'Private content');
|
|
543
|
+
const stored = uploadAttachment('ast-1', 'secret.pdf', 'application/pdf', 'JVBER');
|
|
544
|
+
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
545
|
+
|
|
546
|
+
// Attachment is globally visible by ID — no thread-type filter exists
|
|
547
|
+
const fetched = getAttachmentById('ast-1', stored.id);
|
|
548
|
+
expect(fetched).not.toBeNull();
|
|
549
|
+
expect(fetched!.originalFilename).toBe('secret.pdf');
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test('attachment from private thread can be linked to a standard thread message', () => {
|
|
553
|
+
const privateConv = createConversation({ title: 'Private', threadType: 'private' });
|
|
554
|
+
const standardConv = createConversation({ title: 'Standard', threadType: 'standard' });
|
|
555
|
+
|
|
556
|
+
const privateMsg = addMessage(privateConv.id, 'assistant', 'Private file');
|
|
557
|
+
const standardMsg = addMessage(standardConv.id, 'assistant', 'Reusing private file');
|
|
558
|
+
|
|
559
|
+
const stored = uploadAttachment('ast-1', 'private-doc.png', 'image/png', 'PRIVDATA');
|
|
560
|
+
linkAttachmentToMessage(privateMsg.id, stored.id, 0);
|
|
561
|
+
linkAttachmentToMessage(standardMsg.id, stored.id, 0);
|
|
562
|
+
|
|
563
|
+
// Both threads can see the attachment
|
|
564
|
+
const linkedPrivate = getAttachmentsForMessage(privateMsg.id, 'ast-1');
|
|
565
|
+
expect(linkedPrivate).toHaveLength(1);
|
|
566
|
+
|
|
567
|
+
const linkedStandard = getAttachmentsForMessage(standardMsg.id, 'ast-1');
|
|
568
|
+
expect(linkedStandard).toHaveLength(1);
|
|
569
|
+
expect(linkedStandard[0].id).toBe(stored.id);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test('getAttachmentsForMessageUnscoped returns private thread attachments', () => {
|
|
573
|
+
const privateConv = createConversation({ title: 'Private', threadType: 'private' });
|
|
574
|
+
const msg = addMessage(privateConv.id, 'assistant', 'Private media');
|
|
575
|
+
const stored = uploadAttachment('ast-1', 'photo.jpg', 'image/jpeg', 'AAAA');
|
|
576
|
+
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
577
|
+
|
|
578
|
+
// Unscoped retrieval has no thread-type filter
|
|
579
|
+
const linked = getAttachmentsForMessageUnscoped(msg.id);
|
|
580
|
+
expect(linked).toHaveLength(1);
|
|
581
|
+
expect(linked[0].id).toBe(stored.id);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
test('content-hash dedup works across private and standard threads', () => {
|
|
585
|
+
createConversation({ title: 'Private', threadType: 'private' });
|
|
586
|
+
createConversation({ title: 'Standard', threadType: 'standard' });
|
|
587
|
+
|
|
588
|
+
// Same content uploaded in private and standard contexts
|
|
589
|
+
const fromPrivate = uploadAttachment('ast-1', 'file.png', 'image/png', 'CROSSTHREAD');
|
|
590
|
+
const fromStandard = uploadAttachment('ast-1', 'file.png', 'image/png', 'CROSSTHREAD');
|
|
591
|
+
|
|
592
|
+
// Dedup returns the same row — no thread-type isolation
|
|
593
|
+
expect(fromStandard.id).toBe(fromPrivate.id);
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
test('clearAll removes attachments from both private and standard threads', () => {
|
|
597
|
+
const privateConv = createConversation({ title: 'Private', threadType: 'private' });
|
|
598
|
+
const standardConv = createConversation({ title: 'Standard', threadType: 'standard' });
|
|
599
|
+
|
|
600
|
+
const privateMsg = addMessage(privateConv.id, 'assistant', 'Private file');
|
|
601
|
+
const standardMsg = addMessage(standardConv.id, 'assistant', 'Standard file');
|
|
602
|
+
|
|
603
|
+
const att1 = uploadAttachment('ast-1', 'private.png', 'image/png', 'PRIV');
|
|
604
|
+
const att2 = uploadAttachment('ast-1', 'standard.png', 'image/png', 'STD');
|
|
605
|
+
linkAttachmentToMessage(privateMsg.id, att1.id, 0);
|
|
606
|
+
linkAttachmentToMessage(standardMsg.id, att2.id, 0);
|
|
607
|
+
|
|
608
|
+
clearAll();
|
|
609
|
+
|
|
610
|
+
const raw = (getDb() as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
611
|
+
const attachmentCount = raw.query('SELECT COUNT(*) AS c FROM attachments').get() as { c: number };
|
|
612
|
+
expect(attachmentCount.c).toBe(0);
|
|
613
|
+
});
|
|
614
|
+
});
|