vellum 0.2.0 → 0.2.2
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/README.md +15 -2
- package/bun.lock +5 -2
- package/package.json +4 -2
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +161 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/app-bundler.test.ts +12 -33
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +5 -8
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +454 -0
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-state.test.ts +133 -0
- package/src/__tests__/call-store.test.ts +691 -0
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +348 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/doordash-session.test.ts +9 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +96 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +17 -10
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +222 -0
- package/src/__tests__/run-orchestrator.test.ts +7 -7
- package/src/__tests__/runtime-attachment-metadata.test.ts +19 -20
- package/src/__tests__/runtime-runs-http.test.ts +5 -23
- package/src/__tests__/runtime-runs.test.ts +11 -11
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +89 -16
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +273 -2
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +403 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +141 -2
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +35 -14
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +48 -0
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +390 -0
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-state.ts +64 -0
- package/src/calls/call-store.ts +416 -0
- package/src/calls/relay-server.ts +335 -0
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +34 -0
- package/src/calls/twilio-provider.ts +173 -0
- package/src/calls/twilio-routes.ts +250 -0
- package/src/calls/types.ts +37 -0
- package/src/calls/voice-provider.ts +14 -0
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +256 -25
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +246 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +163 -0
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -24
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +44 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +218 -1
- package/src/config/system-prompt.ts +100 -6
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +5 -0
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +192 -4
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -271
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +495 -39
- package/src/daemon/ipc-contract-inventory.json +40 -4
- package/src/daemon/ipc-contract.ts +185 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +48 -5
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +144 -29
- package/src/daemon/session-agent-loop.ts +887 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +222 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1365
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1151
- package/src/media/gemini-image-service.ts +1 -1
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +362 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +65 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/http-server.ts +277 -25
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/routes/attachment-routes.ts +5 -6
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +12 -19
- package/src/runtime/routes/conversation-routes.ts +5 -9
- package/src/runtime/routes/run-routes.ts +4 -8
- package/src/runtime/run-orchestrator.ts +39 -6
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +220 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +67 -0
- package/src/tools/calls/call-start.ts +73 -0
- package/src/tools/calls/call-status.ts +81 -0
- package/src/tools/claude-code/claude-code.ts +77 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +21 -5
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/registry.ts +2 -4
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -6
- package/src/tools/tasks/task-delete.ts +69 -56
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +74 -102
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +192 -134
- package/src/tools/tasks/work-item-list.ts +33 -78
- package/src/tools/tasks/work-item-remove.ts +60 -0
- package/src/tools/tasks/work-item-update.ts +114 -0
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +20 -74
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +236 -2
- package/src/workspace/commit-message-enrichment-service.ts +284 -0
- package/src/workspace/commit-message-provider.ts +95 -0
- package/src/workspace/git-service.ts +272 -52
- package/src/workspace/heartbeat-service.ts +70 -13
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +100 -51
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -36,7 +36,7 @@ mock.module('../config/loader.js', () => ({
|
|
|
36
36
|
}),
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
|
-
import { initializeDb, getDb } from '../memory/db.js';
|
|
39
|
+
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
40
40
|
import { uploadAttachment, linkAttachmentToMessage } from '../memory/attachments-store.js';
|
|
41
41
|
import { createConversation, addMessage } from '../memory/conversation-store.js';
|
|
42
42
|
import { assetMaterializeTool } from '../tools/assets/materialize.js';
|
|
@@ -49,6 +49,7 @@ import { mkdirSync } from 'node:fs';
|
|
|
49
49
|
mkdirSync(sandboxDir, { recursive: true });
|
|
50
50
|
|
|
51
51
|
afterAll(() => {
|
|
52
|
+
resetDb();
|
|
52
53
|
try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
|
|
53
54
|
});
|
|
54
55
|
|
|
@@ -103,7 +104,7 @@ describe('AssetMaterializeTool sandbox path enforcement', () => {
|
|
|
103
104
|
beforeEach(resetTables);
|
|
104
105
|
|
|
105
106
|
test('rejects path that escapes sandbox via ../', async () => {
|
|
106
|
-
const stored = uploadAttachment('
|
|
107
|
+
const stored = uploadAttachment('test.png', 'image/png', 'AAAA');
|
|
107
108
|
const result = await assetMaterializeTool.execute(
|
|
108
109
|
{ attachment_id: stored.id, destination_path: '../../etc/evil.png' },
|
|
109
110
|
dummyContext,
|
|
@@ -113,7 +114,7 @@ describe('AssetMaterializeTool sandbox path enforcement', () => {
|
|
|
113
114
|
});
|
|
114
115
|
|
|
115
116
|
test('rejects absolute path outside sandbox', async () => {
|
|
116
|
-
const stored = uploadAttachment('
|
|
117
|
+
const stored = uploadAttachment('test.png', 'image/png', 'AAAA');
|
|
117
118
|
const result = await assetMaterializeTool.execute(
|
|
118
119
|
{ attachment_id: stored.id, destination_path: '/tmp/outside-sandbox/evil.png' },
|
|
119
120
|
dummyContext,
|
|
@@ -123,7 +124,7 @@ describe('AssetMaterializeTool sandbox path enforcement', () => {
|
|
|
123
124
|
});
|
|
124
125
|
|
|
125
126
|
test('accepts relative path inside sandbox', async () => {
|
|
126
|
-
const stored = uploadAttachment('
|
|
127
|
+
const stored = uploadAttachment('test.png', 'image/png', 'AAAA');
|
|
127
128
|
const result = await assetMaterializeTool.execute(
|
|
128
129
|
{ attachment_id: stored.id, destination_path: 'output.png' },
|
|
129
130
|
dummyContext,
|
|
@@ -133,7 +134,7 @@ describe('AssetMaterializeTool sandbox path enforcement', () => {
|
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
test('accepts nested path inside sandbox with auto-created subdirs', async () => {
|
|
136
|
-
const stored = uploadAttachment('
|
|
137
|
+
const stored = uploadAttachment('test.png', 'image/png', 'AAAA');
|
|
137
138
|
const result = await assetMaterializeTool.execute(
|
|
138
139
|
{ attachment_id: stored.id, destination_path: 'subdir/deep/output.png' },
|
|
139
140
|
dummyContext,
|
|
@@ -172,7 +173,7 @@ describe('AssetMaterializeTool materialization', () => {
|
|
|
172
173
|
const originalContent = 'Hello, World!';
|
|
173
174
|
const base64Content = Buffer.from(originalContent).toString('base64');
|
|
174
175
|
|
|
175
|
-
const stored = uploadAttachment('
|
|
176
|
+
const stored = uploadAttachment('hello.txt', 'text/plain', base64Content);
|
|
176
177
|
|
|
177
178
|
const destPath = 'materialized-hello.txt';
|
|
178
179
|
const result = await assetMaterializeTool.execute(
|
|
@@ -194,7 +195,7 @@ describe('AssetMaterializeTool materialization', () => {
|
|
|
194
195
|
const binaryBytes = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
|
|
195
196
|
const base64Content = binaryBytes.toString('base64');
|
|
196
197
|
|
|
197
|
-
const stored = uploadAttachment('
|
|
198
|
+
const stored = uploadAttachment('tiny.png', 'image/png', base64Content);
|
|
198
199
|
|
|
199
200
|
const result = await assetMaterializeTool.execute(
|
|
200
201
|
{ attachment_id: stored.id, destination_path: 'images/tiny.png' },
|
|
@@ -209,7 +210,7 @@ describe('AssetMaterializeTool materialization', () => {
|
|
|
209
210
|
|
|
210
211
|
test('result includes resolved path', async () => {
|
|
211
212
|
const base64Content = Buffer.from('test').toString('base64');
|
|
212
|
-
const stored = uploadAttachment('
|
|
213
|
+
const stored = uploadAttachment('doc.txt', 'text/plain', base64Content);
|
|
213
214
|
|
|
214
215
|
const result = await assetMaterializeTool.execute(
|
|
215
216
|
{ attachment_id: stored.id, destination_path: 'output/doc.txt' },
|
|
@@ -222,7 +223,7 @@ describe('AssetMaterializeTool materialization', () => {
|
|
|
222
223
|
|
|
223
224
|
test('result includes filename, MIME type and size info', async () => {
|
|
224
225
|
const base64Content = Buffer.from('some data here').toString('base64');
|
|
225
|
-
const stored = uploadAttachment('
|
|
226
|
+
const stored = uploadAttachment('report.pdf', 'application/pdf', base64Content);
|
|
226
227
|
|
|
227
228
|
const result = await assetMaterializeTool.execute(
|
|
228
229
|
{ attachment_id: stored.id, destination_path: 'report.pdf' },
|
|
@@ -307,7 +308,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
307
308
|
test('materializing from a standard thread works from any context', async () => {
|
|
308
309
|
const standardConv = createConversation({ title: 'standard-conv' });
|
|
309
310
|
const base64Content = Buffer.from('standard content').toString('base64');
|
|
310
|
-
const attachment = uploadAttachment('
|
|
311
|
+
const attachment = uploadAttachment('public.txt', 'text/plain', base64Content);
|
|
311
312
|
const msg = addMessage(standardConv.id, 'user', 'standard message');
|
|
312
313
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
313
314
|
|
|
@@ -330,7 +331,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
330
331
|
test('materializing from a private thread works within the same private thread', async () => {
|
|
331
332
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
332
333
|
const base64Content = Buffer.from('private content').toString('base64');
|
|
333
|
-
const attachment = uploadAttachment('
|
|
334
|
+
const attachment = uploadAttachment('secret.txt', 'text/plain', base64Content);
|
|
334
335
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
335
336
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
336
337
|
|
|
@@ -352,7 +353,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
352
353
|
test('materializing from a private thread is REJECTED from a different conversation', async () => {
|
|
353
354
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
354
355
|
const base64Content = Buffer.from('private content').toString('base64');
|
|
355
|
-
const attachment = uploadAttachment('
|
|
356
|
+
const attachment = uploadAttachment('secret.txt', 'text/plain', base64Content);
|
|
356
357
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
357
358
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
358
359
|
|
|
@@ -376,7 +377,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
376
377
|
test('error message is user-actionable', async () => {
|
|
377
378
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
378
379
|
const base64Content = Buffer.from('private content').toString('base64');
|
|
379
|
-
const attachment = uploadAttachment('
|
|
380
|
+
const attachment = uploadAttachment('confidential.pdf', 'application/pdf', base64Content);
|
|
380
381
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
381
382
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
382
383
|
|
|
@@ -402,7 +403,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
402
403
|
test('materializing from a different private thread is REJECTED', async () => {
|
|
403
404
|
const privateConv1 = createConversation({ title: 'private-conv-1', threadType: 'private' });
|
|
404
405
|
const base64Content = Buffer.from('private content').toString('base64');
|
|
405
|
-
const attachment = uploadAttachment('
|
|
406
|
+
const attachment = uploadAttachment('secret.txt', 'text/plain', base64Content);
|
|
406
407
|
const msg = addMessage(privateConv1.id, 'user', 'private message');
|
|
407
408
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
408
409
|
|
|
@@ -426,7 +427,7 @@ describe('AssetMaterializeTool visibility policy', () => {
|
|
|
426
427
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
427
428
|
const standardConv = createConversation({ title: 'standard-conv' });
|
|
428
429
|
const base64Content = Buffer.from('shared content').toString('base64');
|
|
429
|
-
const attachment = uploadAttachment('
|
|
430
|
+
const attachment = uploadAttachment('shared.txt', 'text/plain', base64Content);
|
|
430
431
|
|
|
431
432
|
const msg1 = addMessage(privateConv.id, 'user', 'private message');
|
|
432
433
|
const msg2 = addMessage(standardConv.id, 'user', 'standard message');
|
|
@@ -35,7 +35,7 @@ mock.module('../config/loader.js', () => ({
|
|
|
35
35
|
}),
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
|
-
import { initializeDb, getDb } from '../memory/db.js';
|
|
38
|
+
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
39
39
|
import { uploadAttachment, linkAttachmentToMessage } from '../memory/attachments-store.js';
|
|
40
40
|
import { createConversation, addMessage } from '../memory/conversation-store.js';
|
|
41
41
|
import { searchAttachments } from '../tools/assets/search.js';
|
|
@@ -45,6 +45,7 @@ import type { ToolContext } from '../tools/types.js';
|
|
|
45
45
|
initializeDb();
|
|
46
46
|
|
|
47
47
|
afterAll(() => {
|
|
48
|
+
resetDb();
|
|
48
49
|
try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
|
|
49
50
|
});
|
|
50
51
|
|
|
@@ -66,10 +67,10 @@ function seedAttachments() {
|
|
|
66
67
|
// Force createdAt by uploading then manipulating the DB
|
|
67
68
|
const db = getDb();
|
|
68
69
|
|
|
69
|
-
const png1 = uploadAttachment('
|
|
70
|
-
const jpg1 = uploadAttachment('
|
|
71
|
-
const pdf1 = uploadAttachment('
|
|
72
|
-
const png2 = uploadAttachment('
|
|
70
|
+
const png1 = uploadAttachment('selfie.png', 'image/png', 'AAAA');
|
|
71
|
+
const jpg1 = uploadAttachment('photo.jpg', 'image/jpeg', 'BBBB');
|
|
72
|
+
const pdf1 = uploadAttachment('report.pdf', 'application/pdf', 'CCCC');
|
|
73
|
+
const png2 = uploadAttachment('screenshot.png', 'image/png', 'DDDD');
|
|
73
74
|
|
|
74
75
|
// Backdate some attachments for recency testing
|
|
75
76
|
db.run(`UPDATE attachments SET created_at = ${oneDayAgo} WHERE id = '${jpg1.id}'`);
|
|
@@ -217,8 +218,8 @@ describe('searchAttachments with conversation_id', () => {
|
|
|
217
218
|
beforeEach(resetTables);
|
|
218
219
|
|
|
219
220
|
test('returns only attachments linked to the specified conversation', () => {
|
|
220
|
-
const png1 = uploadAttachment('
|
|
221
|
-
const png2 = uploadAttachment('
|
|
221
|
+
const png1 = uploadAttachment('in-conv.png', 'image/png', 'AAAA');
|
|
222
|
+
const png2 = uploadAttachment('other-conv.png', 'image/png', 'BBBB');
|
|
222
223
|
|
|
223
224
|
const conv1 = createConversation();
|
|
224
225
|
const conv2 = createConversation();
|
|
@@ -234,7 +235,7 @@ describe('searchAttachments with conversation_id', () => {
|
|
|
234
235
|
});
|
|
235
236
|
|
|
236
237
|
test('returns empty when conversation has no attachments', () => {
|
|
237
|
-
uploadAttachment('
|
|
238
|
+
uploadAttachment('orphan.png', 'image/png', 'AAAA');
|
|
238
239
|
const conv = createConversation();
|
|
239
240
|
addMessage(conv.id, 'user', 'No attachments here');
|
|
240
241
|
|
|
@@ -243,14 +244,14 @@ describe('searchAttachments with conversation_id', () => {
|
|
|
243
244
|
});
|
|
244
245
|
|
|
245
246
|
test('returns empty for nonexistent conversation_id', () => {
|
|
246
|
-
uploadAttachment('
|
|
247
|
+
uploadAttachment('file.png', 'image/png', 'AAAA');
|
|
247
248
|
const results = searchAttachments({ conversation_id: 'conv-nonexistent' });
|
|
248
249
|
expect(results.length).toBe(0);
|
|
249
250
|
});
|
|
250
251
|
|
|
251
252
|
test('combines conversation_id with mime_type filter', () => {
|
|
252
|
-
const png = uploadAttachment('
|
|
253
|
-
const pdf = uploadAttachment('
|
|
253
|
+
const png = uploadAttachment('image.png', 'image/png', 'AAAA');
|
|
254
|
+
const pdf = uploadAttachment('doc.pdf', 'application/pdf', 'BBBB');
|
|
254
255
|
|
|
255
256
|
const conv = createConversation();
|
|
256
257
|
const msg = addMessage(conv.id, 'user', 'Both types');
|
|
@@ -264,8 +265,8 @@ describe('searchAttachments with conversation_id', () => {
|
|
|
264
265
|
});
|
|
265
266
|
|
|
266
267
|
test('combines conversation_id with filename filter', () => {
|
|
267
|
-
const a = uploadAttachment('
|
|
268
|
-
const b = uploadAttachment('
|
|
268
|
+
const a = uploadAttachment('target.png', 'image/png', 'AAAA');
|
|
269
|
+
const b = uploadAttachment('other.png', 'image/png', 'BBBB');
|
|
269
270
|
|
|
270
271
|
const conv = createConversation();
|
|
271
272
|
const msg = addMessage(conv.id, 'user', 'Both');
|
|
@@ -294,7 +295,7 @@ describe('AssetSearchTool.execute', () => {
|
|
|
294
295
|
});
|
|
295
296
|
|
|
296
297
|
test('returns formatted results for matching assets', async () => {
|
|
297
|
-
uploadAttachment('
|
|
298
|
+
uploadAttachment('selfie.png', 'image/png', 'AAAA');
|
|
298
299
|
const result = await tool.execute({}, dummyContext);
|
|
299
300
|
expect(result.isError).toBe(false);
|
|
300
301
|
expect(result.content).toContain('selfie.png');
|
|
@@ -320,14 +321,14 @@ describe('AssetSearchTool.execute', () => {
|
|
|
320
321
|
});
|
|
321
322
|
|
|
322
323
|
test('includes attachment ID in output', async () => {
|
|
323
|
-
const stored = uploadAttachment('
|
|
324
|
+
const stored = uploadAttachment('chart.png', 'image/png', 'AAAA');
|
|
324
325
|
const result = await tool.execute({}, dummyContext);
|
|
325
326
|
expect(result.isError).toBe(false);
|
|
326
327
|
expect(result.content).toContain(stored.id);
|
|
327
328
|
});
|
|
328
329
|
|
|
329
330
|
test('includes MIME type and kind in output', async () => {
|
|
330
|
-
uploadAttachment('
|
|
331
|
+
uploadAttachment('chart.png', 'image/png', 'AAAA');
|
|
331
332
|
const result = await tool.execute({}, dummyContext);
|
|
332
333
|
expect(result.isError).toBe(false);
|
|
333
334
|
expect(result.content).toContain('image/png');
|
|
@@ -363,7 +364,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
363
364
|
|
|
364
365
|
test('attachments from standard threads are visible from any context', async () => {
|
|
365
366
|
const standardConv = createConversation({ title: 'standard-conv' });
|
|
366
|
-
const attachment = uploadAttachment('
|
|
367
|
+
const attachment = uploadAttachment('public.png', 'image/png', 'AAAA');
|
|
367
368
|
const msg = addMessage(standardConv.id, 'user', 'standard message');
|
|
368
369
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
369
370
|
|
|
@@ -382,7 +383,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
382
383
|
|
|
383
384
|
test('attachments from private threads are visible within the same private thread', async () => {
|
|
384
385
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
385
|
-
const attachment = uploadAttachment('
|
|
386
|
+
const attachment = uploadAttachment('secret.png', 'image/png', 'AAAA');
|
|
386
387
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
387
388
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
388
389
|
|
|
@@ -400,7 +401,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
400
401
|
|
|
401
402
|
test('attachments from private threads are NOT visible from a different conversation', async () => {
|
|
402
403
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
403
|
-
const attachment = uploadAttachment('
|
|
404
|
+
const attachment = uploadAttachment('secret.png', 'image/png', 'AAAA');
|
|
404
405
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
405
406
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
406
407
|
|
|
@@ -419,7 +420,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
419
420
|
|
|
420
421
|
test('attachments from private threads are NOT visible from standard threads', async () => {
|
|
421
422
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
422
|
-
const attachment = uploadAttachment('
|
|
423
|
+
const attachment = uploadAttachment('secret.png', 'image/png', 'AAAA');
|
|
423
424
|
const msg = addMessage(privateConv.id, 'user', 'private message');
|
|
424
425
|
linkAttachmentToMessage(msg.id, attachment.id, 0);
|
|
425
426
|
|
|
@@ -439,7 +440,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
439
440
|
test('attachment linked to both private and standard threads is visible everywhere', async () => {
|
|
440
441
|
const privateConv = createConversation({ title: 'private-conv', threadType: 'private' });
|
|
441
442
|
const standardConv = createConversation({ title: 'standard-conv' });
|
|
442
|
-
const attachment = uploadAttachment('
|
|
443
|
+
const attachment = uploadAttachment('shared.png', 'image/png', 'AAAA');
|
|
443
444
|
|
|
444
445
|
const msg1 = addMessage(privateConv.id, 'user', 'private message');
|
|
445
446
|
const msg2 = addMessage(standardConv.id, 'user', 'standard message');
|
|
@@ -460,7 +461,7 @@ describe('AssetSearchTool visibility policy', () => {
|
|
|
460
461
|
});
|
|
461
462
|
|
|
462
463
|
test('orphan attachments (no message linkage) remain visible', async () => {
|
|
463
|
-
uploadAttachment('
|
|
464
|
+
uploadAttachment('orphan.png', 'image/png', 'AAAA');
|
|
464
465
|
|
|
465
466
|
const conv = createConversation({ title: 'any-conv' });
|
|
466
467
|
const context: ToolContext = {
|