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.
Files changed (838) hide show
  1. package/.dockerignore +27 -0
  2. package/.env.example +22 -0
  3. package/Dockerfile +99 -0
  4. package/Dockerfile.sandbox +5 -0
  5. package/README.md +150 -3
  6. package/bun.lock +1768 -0
  7. package/bunfig.toml +2 -0
  8. package/docs/skills.md +158 -0
  9. package/drizzle/0000_dizzy_maggott.sql +301 -0
  10. package/drizzle/meta/0000_snapshot.json +1999 -0
  11. package/drizzle/meta/_journal.json +13 -0
  12. package/drizzle.config.ts +7 -0
  13. package/eslint.config.mjs +17 -0
  14. package/hook-templates/debug-prompt-logger/hook.json +7 -0
  15. package/hook-templates/debug-prompt-logger/run.sh +68 -0
  16. package/knip.json +9 -0
  17. package/package.json +60 -10
  18. package/scripts/ipc/check-contract-inventory.ts +104 -0
  19. package/scripts/ipc/check-swift-decoder-drift.ts +163 -0
  20. package/scripts/ipc/generate-swift.ts +492 -0
  21. package/scripts/test-filesystem-tools.sh +48 -0
  22. package/scripts/test.sh +122 -0
  23. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2079 -0
  24. package/src/__tests__/account-registry.test.ts +244 -0
  25. package/src/__tests__/active-skill-tools.test.ts +378 -0
  26. package/src/__tests__/agent-loop-thinking.test.ts +81 -0
  27. package/src/__tests__/agent-loop.test.ts +1135 -0
  28. package/src/__tests__/anthropic-provider.test.ts +778 -0
  29. package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
  30. package/src/__tests__/app-bundler.test.ts +313 -0
  31. package/src/__tests__/app-executors.test.ts +613 -0
  32. package/src/__tests__/app-open-proxy.test.ts +62 -0
  33. package/src/__tests__/asset-materialize-tool.test.ts +451 -0
  34. package/src/__tests__/asset-search-tool.test.ts +476 -0
  35. package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
  36. package/src/__tests__/assistant-attachments.test.ts +437 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +226 -0
  38. package/src/__tests__/assistant-event.test.ts +123 -0
  39. package/src/__tests__/attachments-store.test.ts +547 -0
  40. package/src/__tests__/attachments.test.ts +134 -0
  41. package/src/__tests__/audit-log-rotation.test.ts +154 -0
  42. package/src/__tests__/browser-fill-credential.test.ts +309 -0
  43. package/src/__tests__/browser-manager.test.ts +203 -0
  44. package/src/__tests__/browser-runtime-check.test.ts +55 -0
  45. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +67 -0
  46. package/src/__tests__/browser-skill-endstate.test.ts +198 -0
  47. package/src/__tests__/bundle-scanner.test.ts +313 -0
  48. package/src/__tests__/checker.test.ts +3856 -0
  49. package/src/__tests__/clarification-resolver.test.ts +159 -0
  50. package/src/__tests__/classifier.test.ts +67 -0
  51. package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
  52. package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
  53. package/src/__tests__/cli-discover.test.ts +85 -0
  54. package/src/__tests__/cli.test.ts +81 -0
  55. package/src/__tests__/clipboard.test.ts +80 -0
  56. package/src/__tests__/commit-guarantee.test.ts +335 -0
  57. package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
  58. package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
  59. package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
  60. package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
  61. package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
  62. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
  63. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
  64. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
  65. package/src/__tests__/config-schema.test.ts +720 -0
  66. package/src/__tests__/conflict-store.test.ts +329 -0
  67. package/src/__tests__/connection-policy.test.ts +102 -0
  68. package/src/__tests__/context-memory-e2e.test.ts +434 -0
  69. package/src/__tests__/context-token-estimator.test.ts +135 -0
  70. package/src/__tests__/context-window-manager.test.ts +376 -0
  71. package/src/__tests__/contradiction-checker.test.ts +216 -0
  72. package/src/__tests__/conversation-store.test.ts +614 -0
  73. package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
  74. package/src/__tests__/credential-broker-server-use.test.ts +554 -0
  75. package/src/__tests__/credential-broker.test.ts +167 -0
  76. package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
  77. package/src/__tests__/credential-metadata-store.test.ts +779 -0
  78. package/src/__tests__/credential-policy-validate.test.ts +121 -0
  79. package/src/__tests__/credential-resolve.test.ts +328 -0
  80. package/src/__tests__/credential-security-e2e.test.ts +352 -0
  81. package/src/__tests__/credential-security-invariants.test.ts +563 -0
  82. package/src/__tests__/credential-selection.test.ts +354 -0
  83. package/src/__tests__/credential-vault.test.ts +852 -0
  84. package/src/__tests__/daemon-assistant-events.test.ts +164 -0
  85. package/src/__tests__/daemon-server-session-init.test.ts +522 -0
  86. package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
  87. package/src/__tests__/diff.test.ts +121 -0
  88. package/src/__tests__/domain-normalize.test.ts +112 -0
  89. package/src/__tests__/domain-policy.test.ts +124 -0
  90. package/src/__tests__/doordash-client.test.ts +186 -0
  91. package/src/__tests__/doordash-session.test.ts +143 -0
  92. package/src/__tests__/dynamic-page-surface.test.ts +91 -0
  93. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
  94. package/src/__tests__/edit-engine.test.ts +180 -0
  95. package/src/__tests__/email-cli.test.ts +283 -0
  96. package/src/__tests__/encrypted-store.test.ts +332 -0
  97. package/src/__tests__/entity-extractor.test.ts +190 -0
  98. package/src/__tests__/ephemeral-permissions.test.ts +312 -0
  99. package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
  100. package/src/__tests__/event-bus.test.ts +222 -0
  101. package/src/__tests__/file-edit-tool.test.ts +122 -0
  102. package/src/__tests__/file-ops-service.test.ts +330 -0
  103. package/src/__tests__/file-read-tool.test.ts +75 -0
  104. package/src/__tests__/file-write-tool.test.ts +113 -0
  105. package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
  106. package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
  107. package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
  108. package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
  109. package/src/__tests__/fuzzy-match-property.test.ts +216 -0
  110. package/src/__tests__/fuzzy-match.test.ts +138 -0
  111. package/src/__tests__/gemini-image-service.test.ts +261 -0
  112. package/src/__tests__/gemini-provider.test.ts +651 -0
  113. package/src/__tests__/get-weather.test.ts +318 -0
  114. package/src/__tests__/gmail-integration.test.ts +73 -0
  115. package/src/__tests__/handlers-cu-observation-blob.test.ts +351 -0
  116. package/src/__tests__/handlers-ipc-blob-probe.test.ts +190 -0
  117. package/src/__tests__/handlers-slack-config.test.ts +199 -0
  118. package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
  119. package/src/__tests__/headless-browser-interactions.test.ts +536 -0
  120. package/src/__tests__/headless-browser-navigate.test.ts +211 -0
  121. package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
  122. package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
  123. package/src/__tests__/history-repair-observability.test.ts +56 -0
  124. package/src/__tests__/history-repair.test.ts +510 -0
  125. package/src/__tests__/home-base-bootstrap.test.ts +77 -0
  126. package/src/__tests__/hooks-blocking.test.ts +128 -0
  127. package/src/__tests__/hooks-cli.test.ts +144 -0
  128. package/src/__tests__/hooks-config.test.ts +93 -0
  129. package/src/__tests__/hooks-discovery.test.ts +199 -0
  130. package/src/__tests__/hooks-integration.test.ts +189 -0
  131. package/src/__tests__/hooks-manager.test.ts +187 -0
  132. package/src/__tests__/hooks-runner.test.ts +178 -0
  133. package/src/__tests__/hooks-settings.test.ts +154 -0
  134. package/src/__tests__/hooks-templates.test.ts +137 -0
  135. package/src/__tests__/hooks-ts-runner.test.ts +125 -0
  136. package/src/__tests__/hooks-watch.test.ts +100 -0
  137. package/src/__tests__/host-file-edit-tool.test.ts +104 -0
  138. package/src/__tests__/host-file-read-tool.test.ts +61 -0
  139. package/src/__tests__/host-file-write-tool.test.ts +77 -0
  140. package/src/__tests__/host-shell-tool.test.ts +311 -0
  141. package/src/__tests__/intent-routing.test.ts +255 -0
  142. package/src/__tests__/ipc-blob-store.test.ts +315 -0
  143. package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
  144. package/src/__tests__/ipc-contract.test.ts +74 -0
  145. package/src/__tests__/ipc-protocol.test.ts +113 -0
  146. package/src/__tests__/ipc-snapshot.test.ts +1560 -0
  147. package/src/__tests__/ipc-validate.test.ts +357 -0
  148. package/src/__tests__/key-migration.test.ts +183 -0
  149. package/src/__tests__/keychain.test.ts +258 -0
  150. package/src/__tests__/llm-usage-store.test.ts +226 -0
  151. package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
  152. package/src/__tests__/managed-store.test.ts +608 -0
  153. package/src/__tests__/media-generate-image.test.ts +238 -0
  154. package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
  155. package/src/__tests__/media-visibility-policy.test.ts +141 -0
  156. package/src/__tests__/memory-context-benchmark.test.ts +235 -0
  157. package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
  158. package/src/__tests__/memory-query-builder.test.ts +59 -0
  159. package/src/__tests__/memory-recall-quality.test.ts +846 -0
  160. package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
  161. package/src/__tests__/memory-regressions.test.ts +4238 -0
  162. package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
  163. package/src/__tests__/migration-cli-flows.test.ts +169 -0
  164. package/src/__tests__/migration-ordering.test.ts +249 -0
  165. package/src/__tests__/mock-signup-server.test.ts +528 -0
  166. package/src/__tests__/onboarding-starter-tasks.test.ts +166 -0
  167. package/src/__tests__/onboarding-template-contract.test.ts +58 -0
  168. package/src/__tests__/openai-provider.test.ts +753 -0
  169. package/src/__tests__/parser.test.ts +472 -0
  170. package/src/__tests__/path-classifier.test.ts +73 -0
  171. package/src/__tests__/path-policy.test.ts +435 -0
  172. package/src/__tests__/platform-move-helper.test.ts +99 -0
  173. package/src/__tests__/platform-socket-path.test.ts +52 -0
  174. package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
  175. package/src/__tests__/platform.test.ts +131 -0
  176. package/src/__tests__/prebuilt-home-base-seed.test.ts +71 -0
  177. package/src/__tests__/pricing.test.ts +256 -0
  178. package/src/__tests__/profile-compiler.test.ts +373 -0
  179. package/src/__tests__/provider-registry-ollama.test.ts +16 -0
  180. package/src/__tests__/proxy-approval-callback.test.ts +601 -0
  181. package/src/__tests__/ratelimit.test.ts +297 -0
  182. package/src/__tests__/registry.test.ts +487 -0
  183. package/src/__tests__/reminder-store.test.ts +220 -0
  184. package/src/__tests__/reminder.test.ts +263 -0
  185. package/src/__tests__/request-file-tool.test.ts +158 -0
  186. package/src/__tests__/run-orchestrator.test.ts +200 -0
  187. package/src/__tests__/runtime-attachment-metadata.test.ts +190 -0
  188. package/src/__tests__/runtime-runs-http.test.ts +451 -0
  189. package/src/__tests__/runtime-runs.test.ts +273 -0
  190. package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
  191. package/src/__tests__/sandbox-host-parity.test.ts +950 -0
  192. package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
  193. package/src/__tests__/script-proxy-certs.test.ts +90 -0
  194. package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
  195. package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
  196. package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
  197. package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
  198. package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
  199. package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
  200. package/src/__tests__/script-proxy-policy.test.ts +310 -0
  201. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
  202. package/src/__tests__/script-proxy-router.test.ts +180 -0
  203. package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
  204. package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
  205. package/src/__tests__/secret-allowlist.test.ts +229 -0
  206. package/src/__tests__/secret-ingress-handler.test.ts +99 -0
  207. package/src/__tests__/secret-onetime-send.test.ts +130 -0
  208. package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
  209. package/src/__tests__/secret-response-routing.test.ts +93 -0
  210. package/src/__tests__/secret-scanner-executor.test.ts +348 -0
  211. package/src/__tests__/secret-scanner.test.ts +857 -0
  212. package/src/__tests__/secure-keys.test.ts +323 -0
  213. package/src/__tests__/server-history-render.test.ts +430 -0
  214. package/src/__tests__/session-abort-tool-results.test.ts +240 -0
  215. package/src/__tests__/session-conflict-gate.test.ts +697 -0
  216. package/src/__tests__/session-error.test.ts +341 -0
  217. package/src/__tests__/session-evictor.test.ts +188 -0
  218. package/src/__tests__/session-load-history-repair.test.ts +222 -0
  219. package/src/__tests__/session-pre-run-repair.test.ts +213 -0
  220. package/src/__tests__/session-profile-injection.test.ts +444 -0
  221. package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
  222. package/src/__tests__/session-queue.test.ts +1462 -0
  223. package/src/__tests__/session-runtime-assembly.test.ts +315 -0
  224. package/src/__tests__/session-runtime-workspace.test.ts +183 -0
  225. package/src/__tests__/session-skill-tools.test.ts +2431 -0
  226. package/src/__tests__/session-slash-known.test.ts +368 -0
  227. package/src/__tests__/session-slash-queue.test.ts +288 -0
  228. package/src/__tests__/session-slash-unknown.test.ts +271 -0
  229. package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
  230. package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
  231. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
  232. package/src/__tests__/session-undo.test.ts +75 -0
  233. package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
  234. package/src/__tests__/session-workspace-injection.test.ts +327 -0
  235. package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
  236. package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
  237. package/src/__tests__/shell-credential-ref.test.ts +187 -0
  238. package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
  239. package/src/__tests__/shell-parser-property.test.ts +433 -0
  240. package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
  241. package/src/__tests__/signup-e2e.test.ts +352 -0
  242. package/src/__tests__/size-guard.test.ts +117 -0
  243. package/src/__tests__/skill-include-graph.test.ts +303 -0
  244. package/src/__tests__/skill-load-tool.test.ts +409 -0
  245. package/src/__tests__/skill-script-runner-host.test.ts +489 -0
  246. package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
  247. package/src/__tests__/skill-tool-factory.test.ts +252 -0
  248. package/src/__tests__/skill-tool-manifest.test.ts +658 -0
  249. package/src/__tests__/skill-version-hash.test.ts +182 -0
  250. package/src/__tests__/skills.test.ts +597 -0
  251. package/src/__tests__/slash-commands-catalog.test.ts +86 -0
  252. package/src/__tests__/slash-commands-parser.test.ts +119 -0
  253. package/src/__tests__/slash-commands-resolver.test.ts +193 -0
  254. package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
  255. package/src/__tests__/starter-bundle.test.ts +136 -0
  256. package/src/__tests__/starter-task-flow.test.ts +143 -0
  257. package/src/__tests__/subagent-manager-notify.test.ts +372 -0
  258. package/src/__tests__/subagent-tools.test.ts +118 -0
  259. package/src/__tests__/subagent-types.test.ts +78 -0
  260. package/src/__tests__/swarm-orchestrator.test.ts +428 -0
  261. package/src/__tests__/swarm-plan-validator.test.ts +330 -0
  262. package/src/__tests__/swarm-recursion.test.ts +165 -0
  263. package/src/__tests__/swarm-router-planner.test.ts +208 -0
  264. package/src/__tests__/swarm-session-integration.test.ts +274 -0
  265. package/src/__tests__/swarm-tool.test.ts +145 -0
  266. package/src/__tests__/swarm-worker-backend.test.ts +129 -0
  267. package/src/__tests__/swarm-worker-runner.test.ts +272 -0
  268. package/src/__tests__/system-prompt.test.ts +461 -0
  269. package/src/__tests__/task-compiler.test.ts +283 -0
  270. package/src/__tests__/task-runner.test.ts +215 -0
  271. package/src/__tests__/task-scheduler.test.ts +216 -0
  272. package/src/__tests__/task-tools.test.ts +602 -0
  273. package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
  274. package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
  275. package/src/__tests__/terminal-sandbox.test.ts +202 -0
  276. package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
  277. package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
  278. package/src/__tests__/tool-audit-listener.test.ts +112 -0
  279. package/src/__tests__/tool-domain-event-publisher.test.ts +251 -0
  280. package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
  281. package/src/__tests__/tool-executor-redaction.test.ts +289 -0
  282. package/src/__tests__/tool-executor.test.ts +1971 -0
  283. package/src/__tests__/tool-metrics-listener.test.ts +225 -0
  284. package/src/__tests__/tool-notification-listener.test.ts +49 -0
  285. package/src/__tests__/tool-policy.test.ts +54 -0
  286. package/src/__tests__/tool-profiling-listener.test.ts +268 -0
  287. package/src/__tests__/tool-result-truncation.test.ts +217 -0
  288. package/src/__tests__/tool-trace-listener.test.ts +226 -0
  289. package/src/__tests__/top-level-renderer.test.ts +121 -0
  290. package/src/__tests__/top-level-scanner.test.ts +141 -0
  291. package/src/__tests__/trace-emitter.test.ts +173 -0
  292. package/src/__tests__/trust-store.test.ts +2030 -0
  293. package/src/__tests__/turn-commit.test.ts +219 -0
  294. package/src/__tests__/url-safety.test.ts +418 -0
  295. package/src/__tests__/weather-skill-regression.test.ts +225 -0
  296. package/src/__tests__/web-fetch.test.ts +869 -0
  297. package/src/__tests__/web-search.test.ts +584 -0
  298. package/src/__tests__/workspace-git-service.test.ts +750 -0
  299. package/src/__tests__/workspace-heartbeat-service.test.ts +347 -0
  300. package/src/__tests__/workspace-lifecycle.test.ts +292 -0
  301. package/src/agent/attachments.ts +35 -0
  302. package/src/agent/loop.ts +500 -0
  303. package/src/agent/message-types.ts +17 -0
  304. package/src/autonomy/autonomy-resolver.ts +60 -0
  305. package/src/autonomy/autonomy-store.ts +122 -0
  306. package/src/autonomy/disposition-mapper.ts +31 -0
  307. package/src/autonomy/index.ts +11 -0
  308. package/src/autonomy/types.ts +39 -0
  309. package/src/bundler/app-bundler.ts +274 -0
  310. package/src/bundler/bundle-scanner.ts +535 -0
  311. package/src/bundler/bundle-signer.ts +124 -0
  312. package/src/bundler/manifest.ts +21 -0
  313. package/src/bundler/signature-verifier.ts +184 -0
  314. package/src/cli/autonomy.ts +188 -0
  315. package/src/cli/contacts.ts +149 -0
  316. package/src/cli/doordash.ts +824 -0
  317. package/src/cli/email-guardrails.ts +200 -0
  318. package/src/cli/email.ts +405 -0
  319. package/src/cli/main-screen.tsx +155 -0
  320. package/src/cli.ts +935 -0
  321. package/src/config/bundled-skills/.gitkeep +0 -0
  322. package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
  323. package/src/config/bundled-skills/agentmail/icon.svg +21 -0
  324. package/src/config/bundled-skills/app-builder/SKILL.md +1348 -0
  325. package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
  326. package/src/config/bundled-skills/app-builder/icon.svg +9 -0
  327. package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
  328. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
  329. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
  330. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
  331. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
  332. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
  333. package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
  334. package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
  335. package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
  336. package/src/config/bundled-skills/browser/SKILL.md +28 -0
  337. package/src/config/bundled-skills/browser/TOOLS.json +234 -0
  338. package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
  339. package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
  340. package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
  341. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
  342. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
  343. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
  344. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
  345. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
  346. package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
  347. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
  348. package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
  349. package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
  350. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
  351. package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
  352. package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
  353. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
  354. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
  355. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
  356. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
  357. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
  358. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
  359. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
  360. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
  361. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
  362. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
  363. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
  364. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
  365. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
  366. package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
  367. package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
  368. package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
  369. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
  370. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
  371. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
  372. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
  373. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
  374. package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
  375. package/src/config/bundled-skills/google-calendar/types.ts +97 -0
  376. package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
  377. package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
  378. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +137 -0
  379. package/src/config/bundled-skills/messaging/SKILL.md +126 -0
  380. package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
  381. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
  382. package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
  383. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
  384. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
  385. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
  386. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
  387. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
  388. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
  389. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +124 -0
  390. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
  391. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
  392. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
  393. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
  394. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
  395. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +29 -0
  396. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
  397. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +27 -0
  398. package/src/config/bundled-skills/messaging/tools/shared.ts +71 -0
  399. package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
  400. package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
  401. package/src/config/bundled-skills/self-upgrade/SKILL.md +74 -0
  402. package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
  403. package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
  404. package/src/config/bundled-skills/weather/SKILL.md +37 -0
  405. package/src/config/bundled-skills/weather/TOOLS.json +32 -0
  406. package/src/config/bundled-skills/weather/icon.svg +24 -0
  407. package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
  408. package/src/config/computer-use-prompt.ts +97 -0
  409. package/src/config/defaults.ts +186 -0
  410. package/src/config/loader.ts +336 -0
  411. package/src/config/schema.ts +1004 -0
  412. package/src/config/skill-state.ts +95 -0
  413. package/src/config/skills.ts +972 -0
  414. package/src/config/system-prompt.ts +927 -0
  415. package/src/config/templates/BOOTSTRAP.md +70 -0
  416. package/src/config/templates/IDENTITY.md +18 -0
  417. package/src/config/templates/LOOKS.md +25 -0
  418. package/src/config/templates/SOUL.md +37 -0
  419. package/src/config/templates/USER.md +19 -0
  420. package/src/config/types.ts +32 -0
  421. package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
  422. package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
  423. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +194 -0
  424. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +147 -0
  425. package/src/config/vellum-skills/telegram-setup/SKILL.md +105 -0
  426. package/src/contacts/contact-store.ts +410 -0
  427. package/src/contacts/index.ts +11 -0
  428. package/src/contacts/types.ts +28 -0
  429. package/src/context/token-estimator.ts +108 -0
  430. package/src/context/tool-result-truncation.ts +128 -0
  431. package/src/context/window-manager.ts +531 -0
  432. package/src/daemon/assistant-attachments.ts +679 -0
  433. package/src/daemon/classifier.ts +108 -0
  434. package/src/daemon/computer-use-session.ts +900 -0
  435. package/src/daemon/connection-policy.ts +41 -0
  436. package/src/daemon/handlers/apps.ts +446 -0
  437. package/src/daemon/handlers/computer-use.ts +181 -0
  438. package/src/daemon/handlers/config.ts +434 -0
  439. package/src/daemon/handlers/diagnostics.ts +334 -0
  440. package/src/daemon/handlers/documents.ts +184 -0
  441. package/src/daemon/handlers/home-base.ts +73 -0
  442. package/src/daemon/handlers/index.ts +355 -0
  443. package/src/daemon/handlers/misc.ts +323 -0
  444. package/src/daemon/handlers/open-bundle-handler.ts +80 -0
  445. package/src/daemon/handlers/publish.ts +182 -0
  446. package/src/daemon/handlers/sessions.ts +486 -0
  447. package/src/daemon/handlers/shared.ts +533 -0
  448. package/src/daemon/handlers/skills.ts +487 -0
  449. package/src/daemon/handlers/subagents.ts +122 -0
  450. package/src/daemon/handlers/work-items.ts +176 -0
  451. package/src/daemon/handlers.ts +17 -0
  452. package/src/daemon/history-repair.ts +214 -0
  453. package/src/daemon/ipc-blob-store.ts +231 -0
  454. package/src/daemon/ipc-contract-inventory.json +407 -0
  455. package/src/daemon/ipc-contract-inventory.ts +126 -0
  456. package/src/daemon/ipc-contract.ts +2102 -0
  457. package/src/daemon/ipc-protocol.ts +70 -0
  458. package/src/daemon/ipc-validate.ts +171 -0
  459. package/src/daemon/lifecycle.ts +503 -0
  460. package/src/daemon/main.ts +15 -0
  461. package/src/daemon/media-visibility-policy.ts +57 -0
  462. package/src/daemon/ride-shotgun-handler.ts +244 -0
  463. package/src/daemon/server.ts +1085 -0
  464. package/src/daemon/session-attachments.ts +173 -0
  465. package/src/daemon/session-conflict-gate.ts +219 -0
  466. package/src/daemon/session-dynamic-profile.ts +63 -0
  467. package/src/daemon/session-error.ts +269 -0
  468. package/src/daemon/session-evictor.ts +196 -0
  469. package/src/daemon/session-history.ts +437 -0
  470. package/src/daemon/session-memory.ts +212 -0
  471. package/src/daemon/session-process.ts +264 -0
  472. package/src/daemon/session-queue-manager.ts +81 -0
  473. package/src/daemon/session-runtime-assembly.ts +395 -0
  474. package/src/daemon/session-skill-tools.ts +237 -0
  475. package/src/daemon/session-slash.ts +302 -0
  476. package/src/daemon/session-surfaces.ts +624 -0
  477. package/src/daemon/session-tool-setup.ts +286 -0
  478. package/src/daemon/session-usage.ts +74 -0
  479. package/src/daemon/session-workspace.ts +19 -0
  480. package/src/daemon/session.ts +1651 -0
  481. package/src/daemon/trace-emitter.ts +82 -0
  482. package/src/daemon/watch-handler.ts +274 -0
  483. package/src/doordash/client.ts +905 -0
  484. package/src/doordash/queries.ts +1312 -0
  485. package/src/doordash/query-extractor.ts +93 -0
  486. package/src/doordash/session.ts +82 -0
  487. package/src/email/provider.ts +117 -0
  488. package/src/email/providers/agentmail.ts +317 -0
  489. package/src/email/providers/index.ts +58 -0
  490. package/src/email/service.ts +303 -0
  491. package/src/email/types.ts +126 -0
  492. package/src/events/bus.ts +157 -0
  493. package/src/events/domain-events.ts +83 -0
  494. package/src/events/index.ts +18 -0
  495. package/src/events/tool-audit-listener.ts +80 -0
  496. package/src/events/tool-domain-event-publisher.ts +111 -0
  497. package/src/events/tool-metrics-listener.ts +159 -0
  498. package/src/events/tool-notification-listener.ts +17 -0
  499. package/src/events/tool-profiling-listener.ts +158 -0
  500. package/src/events/tool-trace-listener.ts +75 -0
  501. package/src/export/formatter.ts +96 -0
  502. package/src/followups/followup-store.ts +166 -0
  503. package/src/followups/index.ts +10 -0
  504. package/src/followups/types.ts +23 -0
  505. package/src/gallery/default-gallery.ts +795 -0
  506. package/src/gallery/gallery-manifest.ts +24 -0
  507. package/src/home-base/app-link-store.ts +82 -0
  508. package/src/home-base/bootstrap.ts +66 -0
  509. package/src/home-base/prebuilt/index.html +662 -0
  510. package/src/home-base/prebuilt/seed-metadata.json +21 -0
  511. package/src/home-base/prebuilt/seed.ts +101 -0
  512. package/src/home-base/prebuilt-home-base-updater.ts +30 -0
  513. package/src/hooks/cli.ts +163 -0
  514. package/src/hooks/config.ts +88 -0
  515. package/src/hooks/discovery.ts +110 -0
  516. package/src/hooks/manager.ts +128 -0
  517. package/src/hooks/runner.ts +123 -0
  518. package/src/hooks/templates.ts +52 -0
  519. package/src/hooks/types.ts +72 -0
  520. package/src/index.ts +1194 -0
  521. package/src/instrument.ts +60 -0
  522. package/src/logfire.ts +99 -0
  523. package/src/media/gemini-image-service.ts +136 -0
  524. package/src/memory/account-store.ts +108 -0
  525. package/src/memory/admin.ts +211 -0
  526. package/src/memory/app-store.ts +556 -0
  527. package/src/memory/attachments-store.ts +453 -0
  528. package/src/memory/channel-delivery-store.ts +368 -0
  529. package/src/memory/checkpoints.ts +52 -0
  530. package/src/memory/clarification-resolver.ts +297 -0
  531. package/src/memory/conflict-store.ts +342 -0
  532. package/src/memory/contradiction-checker.ts +329 -0
  533. package/src/memory/conversation-key-store.ts +127 -0
  534. package/src/memory/conversation-store.ts +469 -0
  535. package/src/memory/db.ts +1105 -0
  536. package/src/memory/embedding-backend.ts +229 -0
  537. package/src/memory/embedding-gemini.ts +52 -0
  538. package/src/memory/embedding-local.ts +75 -0
  539. package/src/memory/embedding-ollama.ts +55 -0
  540. package/src/memory/embedding-openai.ts +25 -0
  541. package/src/memory/entity-extractor.ts +471 -0
  542. package/src/memory/fingerprint.ts +20 -0
  543. package/src/memory/indexer.ts +156 -0
  544. package/src/memory/items-extractor.ts +460 -0
  545. package/src/memory/job-handlers/backfill.ts +139 -0
  546. package/src/memory/job-handlers/cleanup.ts +58 -0
  547. package/src/memory/job-handlers/conflict.ts +99 -0
  548. package/src/memory/job-handlers/embedding.ts +61 -0
  549. package/src/memory/job-handlers/extraction.ts +123 -0
  550. package/src/memory/job-handlers/index-maintenance.ts +54 -0
  551. package/src/memory/job-handlers/summarization.ts +286 -0
  552. package/src/memory/job-utils.ts +170 -0
  553. package/src/memory/jobs-store.ts +400 -0
  554. package/src/memory/jobs-worker.ts +274 -0
  555. package/src/memory/llm-request-log-store.ts +45 -0
  556. package/src/memory/llm-usage-store.ts +62 -0
  557. package/src/memory/message-content.ts +54 -0
  558. package/src/memory/profile-compiler.ts +160 -0
  559. package/src/memory/published-pages-store.ts +137 -0
  560. package/src/memory/qdrant-client.ts +366 -0
  561. package/src/memory/qdrant-manager.ts +242 -0
  562. package/src/memory/query-builder.ts +45 -0
  563. package/src/memory/retrieval-budget.ts +30 -0
  564. package/src/memory/retriever.ts +653 -0
  565. package/src/memory/runs-store.ts +211 -0
  566. package/src/memory/schema.ts +529 -0
  567. package/src/memory/search/entity.ts +298 -0
  568. package/src/memory/search/formatting.ts +207 -0
  569. package/src/memory/search/lexical.ts +227 -0
  570. package/src/memory/search/ranking.ts +401 -0
  571. package/src/memory/search/semantic.ts +121 -0
  572. package/src/memory/search/types.ts +137 -0
  573. package/src/memory/segmenter.ts +68 -0
  574. package/src/memory/shared-app-links-store.ts +138 -0
  575. package/src/memory/tool-usage-store.ts +62 -0
  576. package/src/messaging/activity-analyzer.ts +76 -0
  577. package/src/messaging/draft-store.ts +88 -0
  578. package/src/messaging/index.ts +3 -0
  579. package/src/messaging/provider-types.ts +80 -0
  580. package/src/messaging/provider.ts +43 -0
  581. package/src/messaging/providers/gmail/adapter.ts +193 -0
  582. package/src/messaging/providers/gmail/client.ts +204 -0
  583. package/src/messaging/providers/gmail/types.ts +90 -0
  584. package/src/messaging/providers/slack/adapter.ts +202 -0
  585. package/src/messaging/providers/slack/client.ts +198 -0
  586. package/src/messaging/providers/slack/types.ts +119 -0
  587. package/src/messaging/registry.ts +34 -0
  588. package/src/messaging/style-analyzer.ts +158 -0
  589. package/src/messaging/thread-summarizer.ts +310 -0
  590. package/src/messaging/triage-engine.ts +321 -0
  591. package/src/messaging/types.ts +55 -0
  592. package/src/permissions/checker.ts +636 -0
  593. package/src/permissions/defaults.ts +243 -0
  594. package/src/permissions/prompter.ts +102 -0
  595. package/src/permissions/secret-prompter.ts +114 -0
  596. package/src/permissions/trust-store.ts +584 -0
  597. package/src/permissions/types.ts +62 -0
  598. package/src/playbooks/index.ts +2 -0
  599. package/src/playbooks/playbook-compiler.ts +90 -0
  600. package/src/playbooks/types.ts +55 -0
  601. package/src/providers/anthropic/client.ts +751 -0
  602. package/src/providers/failover.ts +129 -0
  603. package/src/providers/fireworks/client.ts +20 -0
  604. package/src/providers/gemini/client.ts +285 -0
  605. package/src/providers/ollama/client.ts +30 -0
  606. package/src/providers/openai/client.ts +337 -0
  607. package/src/providers/ratelimit.ts +93 -0
  608. package/src/providers/registry.ts +138 -0
  609. package/src/providers/retry.ts +106 -0
  610. package/src/providers/stream-timeout.ts +38 -0
  611. package/src/providers/types.ts +109 -0
  612. package/src/runtime/assistant-event-hub.ts +120 -0
  613. package/src/runtime/assistant-event.ts +82 -0
  614. package/src/runtime/http-server.ts +478 -0
  615. package/src/runtime/http-types.ts +68 -0
  616. package/src/runtime/routes/app-routes.ts +174 -0
  617. package/src/runtime/routes/attachment-routes.ts +134 -0
  618. package/src/runtime/routes/channel-routes.ts +342 -0
  619. package/src/runtime/routes/conversation-routes.ts +349 -0
  620. package/src/runtime/routes/run-routes.ts +223 -0
  621. package/src/runtime/routes/secret-routes.ts +76 -0
  622. package/src/runtime/run-orchestrator.ts +206 -0
  623. package/src/schedule/schedule-store.ts +452 -0
  624. package/src/schedule/scheduler.ts +168 -0
  625. package/src/security/encrypted-store.ts +238 -0
  626. package/src/security/keychain.ts +252 -0
  627. package/src/security/oauth2.ts +241 -0
  628. package/src/security/redaction.ts +89 -0
  629. package/src/security/secret-allowlist.ts +118 -0
  630. package/src/security/secret-ingress.ts +57 -0
  631. package/src/security/secret-scanner.ts +543 -0
  632. package/src/security/secure-keys.ts +180 -0
  633. package/src/security/token-manager.ts +141 -0
  634. package/src/services/published-app-updater.ts +69 -0
  635. package/src/services/vercel-deploy.ts +73 -0
  636. package/src/skills/active-skill-tools.ts +81 -0
  637. package/src/skills/clawhub.ts +414 -0
  638. package/src/skills/include-graph.ts +146 -0
  639. package/src/skills/managed-store.ts +233 -0
  640. package/src/skills/path-classifier.ts +128 -0
  641. package/src/skills/slash-commands.ts +174 -0
  642. package/src/skills/tool-manifest.ts +165 -0
  643. package/src/skills/version-hash.ts +110 -0
  644. package/src/slack/slack-webhook.ts +61 -0
  645. package/src/subagent/index.ts +19 -0
  646. package/src/subagent/manager.ts +477 -0
  647. package/src/subagent/types.ts +69 -0
  648. package/src/swarm/backend-claude-code.ts +90 -0
  649. package/src/swarm/index.ts +44 -0
  650. package/src/swarm/limits.ts +37 -0
  651. package/src/swarm/orchestrator.ts +279 -0
  652. package/src/swarm/plan-validator.ts +151 -0
  653. package/src/swarm/router-planner.ts +100 -0
  654. package/src/swarm/router-prompts.ts +36 -0
  655. package/src/swarm/synthesizer.ts +62 -0
  656. package/src/swarm/types.ts +62 -0
  657. package/src/swarm/worker-backend.ts +121 -0
  658. package/src/swarm/worker-prompts.ts +78 -0
  659. package/src/swarm/worker-runner.ts +164 -0
  660. package/src/tasks/SPEC.md +133 -0
  661. package/src/tasks/candidate-store.ts +86 -0
  662. package/src/tasks/ephemeral-permissions.ts +41 -0
  663. package/src/tasks/task-compiler.ts +198 -0
  664. package/src/tasks/task-runner.ts +85 -0
  665. package/src/tasks/task-scheduler.ts +20 -0
  666. package/src/tasks/task-store.ts +127 -0
  667. package/src/tools/apps/definitions.ts +59 -0
  668. package/src/tools/apps/executors.ts +313 -0
  669. package/src/tools/apps/open-proxy.ts +43 -0
  670. package/src/tools/apps/registry.ts +16 -0
  671. package/src/tools/assets/materialize.ts +218 -0
  672. package/src/tools/assets/search.ts +396 -0
  673. package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
  674. package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
  675. package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
  676. package/src/tools/browser/auth-cache.ts +149 -0
  677. package/src/tools/browser/auth-detector.ts +347 -0
  678. package/src/tools/browser/browser-execution.ts +979 -0
  679. package/src/tools/browser/browser-handoff.ts +79 -0
  680. package/src/tools/browser/browser-manager.ts +715 -0
  681. package/src/tools/browser/browser-screencast.ts +217 -0
  682. package/src/tools/browser/headless-browser.ts +450 -0
  683. package/src/tools/browser/jit-auth.ts +51 -0
  684. package/src/tools/browser/network-recorder.ts +348 -0
  685. package/src/tools/browser/network-recording-types.ts +49 -0
  686. package/src/tools/browser/recording-store.ts +49 -0
  687. package/src/tools/browser/runtime-check.ts +43 -0
  688. package/src/tools/claude-code/claude-code.ts +232 -0
  689. package/src/tools/computer-use/definitions.ts +443 -0
  690. package/src/tools/computer-use/registry.ts +22 -0
  691. package/src/tools/computer-use/request-computer-control.ts +53 -0
  692. package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
  693. package/src/tools/contacts/contact-merge.ts +87 -0
  694. package/src/tools/contacts/contact-search.ts +102 -0
  695. package/src/tools/contacts/contact-upsert.ts +137 -0
  696. package/src/tools/contacts/index.ts +4 -0
  697. package/src/tools/credentials/account-registry.ts +127 -0
  698. package/src/tools/credentials/broker-types.ts +107 -0
  699. package/src/tools/credentials/broker.ts +372 -0
  700. package/src/tools/credentials/domain-policy.ts +51 -0
  701. package/src/tools/credentials/host-pattern-match.ts +60 -0
  702. package/src/tools/credentials/metadata-store.ts +335 -0
  703. package/src/tools/credentials/policy-types.ts +52 -0
  704. package/src/tools/credentials/policy-validate.ts +80 -0
  705. package/src/tools/credentials/resolve.ts +122 -0
  706. package/src/tools/credentials/selection.ts +159 -0
  707. package/src/tools/credentials/tool-policy.ts +25 -0
  708. package/src/tools/credentials/vault.ts +641 -0
  709. package/src/tools/document/document-tool.ts +165 -0
  710. package/src/tools/document/editor-template.ts +237 -0
  711. package/src/tools/document/index.ts +5 -0
  712. package/src/tools/executor.ts +825 -0
  713. package/src/tools/filesystem/edit.ts +127 -0
  714. package/src/tools/filesystem/fuzzy-match.ts +202 -0
  715. package/src/tools/filesystem/read.ts +71 -0
  716. package/src/tools/filesystem/view-image.ts +199 -0
  717. package/src/tools/filesystem/write.ts +79 -0
  718. package/src/tools/followups/followup_create.ts +118 -0
  719. package/src/tools/followups/followup_list.ts +100 -0
  720. package/src/tools/followups/followup_resolve.ts +91 -0
  721. package/src/tools/followups/index.ts +3 -0
  722. package/src/tools/host-filesystem/edit.ts +125 -0
  723. package/src/tools/host-filesystem/read.ts +80 -0
  724. package/src/tools/host-filesystem/write.ts +76 -0
  725. package/src/tools/host-terminal/cli-discover.ts +179 -0
  726. package/src/tools/host-terminal/host-shell.ts +181 -0
  727. package/src/tools/memory/definitions.ts +69 -0
  728. package/src/tools/memory/handlers.ts +245 -0
  729. package/src/tools/memory/register.ts +66 -0
  730. package/src/tools/network/domain-normalize.ts +85 -0
  731. package/src/tools/network/script-proxy/certs.ts +237 -0
  732. package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
  733. package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
  734. package/src/tools/network/script-proxy/index.ts +28 -0
  735. package/src/tools/network/script-proxy/logging.ts +196 -0
  736. package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
  737. package/src/tools/network/script-proxy/policy.ts +152 -0
  738. package/src/tools/network/script-proxy/router.ts +60 -0
  739. package/src/tools/network/script-proxy/server.ts +136 -0
  740. package/src/tools/network/script-proxy/session-manager.ts +534 -0
  741. package/src/tools/network/script-proxy/types.ts +125 -0
  742. package/src/tools/network/url-safety.ts +227 -0
  743. package/src/tools/network/web-fetch.ts +701 -0
  744. package/src/tools/network/web-search.ts +319 -0
  745. package/src/tools/playbooks/index.ts +5 -0
  746. package/src/tools/playbooks/playbook-create.ts +140 -0
  747. package/src/tools/playbooks/playbook-delete.ts +76 -0
  748. package/src/tools/playbooks/playbook-list.ts +101 -0
  749. package/src/tools/playbooks/playbook-update.ts +159 -0
  750. package/src/tools/registry.ts +297 -0
  751. package/src/tools/reminder/reminder-store.ts +148 -0
  752. package/src/tools/reminder/reminder.ts +153 -0
  753. package/src/tools/schedule/create.ts +86 -0
  754. package/src/tools/schedule/delete.ts +54 -0
  755. package/src/tools/schedule/list.ts +88 -0
  756. package/src/tools/schedule/update.ts +97 -0
  757. package/src/tools/shared/filesystem/edit-engine.ts +56 -0
  758. package/src/tools/shared/filesystem/errors.ts +85 -0
  759. package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
  760. package/src/tools/shared/filesystem/format-diff.ts +35 -0
  761. package/src/tools/shared/filesystem/path-policy.ts +125 -0
  762. package/src/tools/shared/filesystem/size-guard.ts +41 -0
  763. package/src/tools/shared/filesystem/types.ts +80 -0
  764. package/src/tools/shared/shell-output.ts +52 -0
  765. package/src/tools/skills/delete-managed.ts +60 -0
  766. package/src/tools/skills/load.ts +139 -0
  767. package/src/tools/skills/sandbox-runner.ts +279 -0
  768. package/src/tools/skills/scaffold-managed.ts +150 -0
  769. package/src/tools/skills/script-contract.ts +6 -0
  770. package/src/tools/skills/skill-script-runner.ts +86 -0
  771. package/src/tools/skills/skill-tool-factory.ts +64 -0
  772. package/src/tools/skills/vellum-catalog.ts +217 -0
  773. package/src/tools/subagent/abort.ts +62 -0
  774. package/src/tools/subagent/index.ts +5 -0
  775. package/src/tools/subagent/message.ts +72 -0
  776. package/src/tools/subagent/read.ts +98 -0
  777. package/src/tools/subagent/spawn.ts +85 -0
  778. package/src/tools/subagent/status.ts +74 -0
  779. package/src/tools/swarm/delegate.ts +182 -0
  780. package/src/tools/system/request-permission.ts +98 -0
  781. package/src/tools/tasks/index.ts +25 -0
  782. package/src/tools/tasks/task-delete.ts +69 -0
  783. package/src/tools/tasks/task-list.ts +65 -0
  784. package/src/tools/tasks/task-run.ts +125 -0
  785. package/src/tools/tasks/task-save.ts +79 -0
  786. package/src/tools/tasks/work-item-enqueue.ts +176 -0
  787. package/src/tools/tasks/work-item-list.ts +86 -0
  788. package/src/tools/terminal/backends/docker.ts +372 -0
  789. package/src/tools/terminal/backends/native.ts +188 -0
  790. package/src/tools/terminal/backends/types.ts +26 -0
  791. package/src/tools/terminal/evaluate-typescript.ts +275 -0
  792. package/src/tools/terminal/parser.ts +393 -0
  793. package/src/tools/terminal/safe-env.ts +37 -0
  794. package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
  795. package/src/tools/terminal/sandbox.ts +44 -0
  796. package/src/tools/terminal/shell.ts +257 -0
  797. package/src/tools/tool-manifest.ts +250 -0
  798. package/src/tools/types.ts +177 -0
  799. package/src/tools/ui-surface/definitions.ts +232 -0
  800. package/src/tools/ui-surface/registry.ts +14 -0
  801. package/src/tools/watch/screen-watch.ts +128 -0
  802. package/src/tools/watch/watch-state.ts +119 -0
  803. package/src/tools/watcher/create.ts +110 -0
  804. package/src/tools/watcher/delete.ts +53 -0
  805. package/src/tools/watcher/digest.ts +84 -0
  806. package/src/tools/watcher/list.ts +90 -0
  807. package/src/tools/watcher/update.ts +102 -0
  808. package/src/tools/weather/service.ts +551 -0
  809. package/src/usage/actors.ts +24 -0
  810. package/src/usage/types.ts +38 -0
  811. package/src/util/clipboard.ts +33 -0
  812. package/src/util/content-id.ts +16 -0
  813. package/src/util/diff.ts +181 -0
  814. package/src/util/errors.ts +129 -0
  815. package/src/util/logger.ts +243 -0
  816. package/src/util/platform.ts +607 -0
  817. package/src/util/pricing.ts +150 -0
  818. package/src/util/spinner.ts +51 -0
  819. package/src/util/time.ts +16 -0
  820. package/src/util/xml.ts +4 -0
  821. package/src/version.ts +3 -0
  822. package/src/watcher/constants.ts +11 -0
  823. package/src/watcher/engine.ts +199 -0
  824. package/src/watcher/provider-registry.ts +15 -0
  825. package/src/watcher/provider-types.ts +48 -0
  826. package/src/watcher/providers/gmail.ts +198 -0
  827. package/src/watcher/providers/google-calendar.ts +228 -0
  828. package/src/watcher/providers/slack.ts +128 -0
  829. package/src/watcher/watcher-store.ts +418 -0
  830. package/src/work-items/work-item-store.ts +91 -0
  831. package/src/workspace/git-service.ts +620 -0
  832. package/src/workspace/heartbeat-service.ts +288 -0
  833. package/src/workspace/top-level-renderer.ts +19 -0
  834. package/src/workspace/top-level-scanner.ts +41 -0
  835. package/src/workspace/turn-commit.ts +122 -0
  836. package/tsconfig.json +21 -0
  837. package/LICENSE +0 -674
  838. package/dist/cli.js +0 -569
@@ -0,0 +1,535 @@
1
+ /**
2
+ * BundleScanner — Security validation and static analysis for .vellumapp bundles.
3
+ *
4
+ * Validates zip bundles before they are opened, returning structured results
5
+ * with block-level (reject) and warn-level (flag) findings.
6
+ */
7
+
8
+ import JSZip from "jszip";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Public types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export interface ScanFinding {
15
+ category: "archive" | "html" | "asset";
16
+ code: string;
17
+ message: string;
18
+ level: "block" | "warn";
19
+ }
20
+
21
+ export interface ScanResult {
22
+ passed: boolean;
23
+ findings: ScanFinding[];
24
+ }
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Constants
28
+ // ---------------------------------------------------------------------------
29
+
30
+ const MAX_DECOMPRESSED_SIZE = 25 * 1024 * 1024; // 25 MB
31
+ const MAX_FILE_COUNT = 50;
32
+ const MAX_COMPRESSION_RATIO = 100;
33
+ const OBFUSCATION_LINE_LENGTH = 10_000; // 10 KB single line threshold
34
+
35
+ const BLOCKED_EXTENSIONS = new Set([
36
+ ".exe",
37
+ ".sh",
38
+ ".command",
39
+ ".app",
40
+ ".dylib",
41
+ ".so",
42
+ ".scpt",
43
+ ]);
44
+
45
+ const REQUIRED_MANIFEST_FIELDS = [
46
+ "format_version",
47
+ "name",
48
+ "created_at",
49
+ "created_by",
50
+ "entry",
51
+ "capabilities",
52
+ ] as const;
53
+
54
+ // Magic byte signatures for image validation
55
+ const IMAGE_SIGNATURES: Record<string, { bytes: number[]; offset?: number }[]> = {
56
+ ".png": [{ bytes: [0x89, 0x50, 0x4e, 0x47] }], // \x89PNG
57
+ ".jpg": [{ bytes: [0xff, 0xd8, 0xff] }],
58
+ ".jpeg": [{ bytes: [0xff, 0xd8, 0xff] }],
59
+ ".gif": [{ bytes: [0x47, 0x49, 0x46, 0x38] }], // GIF8
60
+ ".webp": [
61
+ { bytes: [0x52, 0x49, 0x46, 0x46] }, // RIFF at offset 0
62
+ // bytes 8-11 should be WEBP — checked separately
63
+ ],
64
+ };
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Main entry point
68
+ // ---------------------------------------------------------------------------
69
+
70
+ export async function scanBundle(zipPath: string): Promise<ScanResult> {
71
+ const findings: ScanFinding[] = [];
72
+
73
+ const fileData = await Bun.file(zipPath).arrayBuffer();
74
+ let zip: JSZip;
75
+ try {
76
+ zip = await JSZip.loadAsync(fileData);
77
+ } catch {
78
+ findings.push({
79
+ category: "archive",
80
+ code: "invalid_zip",
81
+ message: "File is not a valid zip archive",
82
+ level: "block",
83
+ });
84
+ return { passed: false, findings };
85
+ }
86
+
87
+ // Run all scan phases
88
+ const manifest = await scanArchiveStructure(zip, fileData.byteLength, findings);
89
+ if (manifest) {
90
+ await scanHtmlEntry(zip, manifest.entry as string, findings);
91
+ }
92
+ const entryName = manifest ? (manifest.entry as string | undefined) : undefined;
93
+ await scanAssets(zip, findings, entryName);
94
+
95
+ const passed = !findings.some((f) => f.level === "block");
96
+ return { passed, findings };
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Phase 1: Archive structure scan
101
+ // ---------------------------------------------------------------------------
102
+
103
+ async function scanArchiveStructure(
104
+ zip: JSZip,
105
+ compressedSize: number,
106
+ findings: ScanFinding[],
107
+ ): Promise<Record<string, unknown> | null> {
108
+ const entries = Object.keys(zip.files);
109
+ const fileEntries = entries.filter((e) => !zip.files[e].dir);
110
+
111
+ // File count check
112
+ if (fileEntries.length > MAX_FILE_COUNT) {
113
+ findings.push({
114
+ category: "archive",
115
+ code: "too_many_files",
116
+ message: `Bundle contains ${fileEntries.length} files (max ${MAX_FILE_COUNT})`,
117
+ level: "block",
118
+ });
119
+ }
120
+
121
+ // Path traversal & blocked extensions
122
+ for (const name of entries) {
123
+ if (name.includes("../") || name.startsWith("/")) {
124
+ findings.push({
125
+ category: "archive",
126
+ code: "path_traversal",
127
+ message: `Zip entry contains path traversal: ${name}`,
128
+ level: "block",
129
+ });
130
+ }
131
+
132
+ const lowerName = name.toLowerCase();
133
+ for (const ext of BLOCKED_EXTENSIONS) {
134
+ if (lowerName.endsWith(ext)) {
135
+ findings.push({
136
+ category: "archive",
137
+ code: "blocked_file_type",
138
+ message: `Blocked file type ${ext}: ${name}`,
139
+ level: "block",
140
+ });
141
+ break;
142
+ }
143
+ }
144
+ }
145
+
146
+ // Compute total decompressed size and compression ratio (bail out early to
147
+ // avoid decompressing the entire archive if limits are exceeded).
148
+ let totalDecompressed = 0;
149
+ for (const name of fileEntries) {
150
+ const entry = zip.files[name];
151
+ const data = await entry.async("uint8array");
152
+ totalDecompressed += data.byteLength;
153
+ if (totalDecompressed > MAX_DECOMPRESSED_SIZE) break;
154
+ if (compressedSize > 0 && totalDecompressed / compressedSize > MAX_COMPRESSION_RATIO) break;
155
+ }
156
+
157
+ if (totalDecompressed > MAX_DECOMPRESSED_SIZE) {
158
+ findings.push({
159
+ category: "archive",
160
+ code: "too_large",
161
+ message: `Total decompressed size ${(totalDecompressed / 1024 / 1024).toFixed(1)} MB exceeds ${MAX_DECOMPRESSED_SIZE / 1024 / 1024} MB limit`,
162
+ level: "block",
163
+ });
164
+ }
165
+
166
+ if (compressedSize > 0 && totalDecompressed / compressedSize > MAX_COMPRESSION_RATIO) {
167
+ findings.push({
168
+ category: "archive",
169
+ code: "zip_bomb",
170
+ message: `Compression ratio ${(totalDecompressed / compressedSize).toFixed(0)}:1 exceeds ${MAX_COMPRESSION_RATIO}:1 limit`,
171
+ level: "block",
172
+ });
173
+ }
174
+
175
+ // Manifest validation
176
+ const manifestFile = zip.file("manifest.json");
177
+ if (!manifestFile) {
178
+ findings.push({
179
+ category: "archive",
180
+ code: "manifest_missing",
181
+ message: "manifest.json is missing from the bundle",
182
+ level: "block",
183
+ });
184
+ return null;
185
+ }
186
+
187
+ let manifest: Record<string, unknown>;
188
+ try {
189
+ const manifestText = await manifestFile.async("text");
190
+ manifest = JSON.parse(manifestText) as Record<string, unknown>;
191
+ } catch {
192
+ findings.push({
193
+ category: "archive",
194
+ code: "manifest_malformed",
195
+ message: "manifest.json is not valid JSON",
196
+ level: "block",
197
+ });
198
+ return null;
199
+ }
200
+
201
+ for (const field of REQUIRED_MANIFEST_FIELDS) {
202
+ if (!(field in manifest)) {
203
+ findings.push({
204
+ category: "archive",
205
+ code: "manifest_malformed",
206
+ message: `manifest.json is missing required field: ${field}`,
207
+ level: "block",
208
+ });
209
+ }
210
+ }
211
+
212
+ // Entry file check
213
+ const entryName = manifest.entry;
214
+ if (typeof entryName === "string" && !zip.file(entryName)) {
215
+ findings.push({
216
+ category: "archive",
217
+ code: "entry_missing",
218
+ message: `Entry file "${entryName}" specified in manifest is missing`,
219
+ level: "block",
220
+ });
221
+ }
222
+
223
+ return manifest;
224
+ }
225
+
226
+ // ---------------------------------------------------------------------------
227
+ // Phase 2: HTML / JS static analysis
228
+ // ---------------------------------------------------------------------------
229
+
230
+ async function scanHtmlEntry(
231
+ zip: JSZip,
232
+ entryName: string,
233
+ findings: ScanFinding[],
234
+ ): Promise<void> {
235
+ const entryFile = zip.file(entryName);
236
+ if (!entryFile) return;
237
+
238
+ const html = await entryFile.async("text");
239
+
240
+ // --- Block-level: external resource references ---
241
+
242
+ // <script src="..."> with external origin (quoted and unquoted)
243
+ const scriptSrcRe = /<script[^>]+src\s*=\s*(?:["']([^"']+)["']|([^\s>]+))/gi;
244
+ for (const m of html.matchAll(scriptSrcRe)) {
245
+ const url = m[1] ?? m[2];
246
+ if (isExternalUrl(url)) {
247
+ findings.push({
248
+ category: "html",
249
+ code: "external_script",
250
+ message: `External script source: ${url}`,
251
+ level: "block",
252
+ });
253
+ }
254
+ }
255
+
256
+ // <link href="..."> with external origin (quoted and unquoted)
257
+ const linkHrefRe = /<link[^>]+href\s*=\s*(?:["']([^"']+)["']|([^\s>]+))/gi;
258
+ for (const m of html.matchAll(linkHrefRe)) {
259
+ const url = m[1] ?? m[2];
260
+ if (isExternalUrl(url)) {
261
+ findings.push({
262
+ category: "html",
263
+ code: "external_link",
264
+ message: `External link href: ${url}`,
265
+ level: "block",
266
+ });
267
+ }
268
+ }
269
+
270
+ // <iframe src="..."> with external origin (quoted and unquoted)
271
+ const iframeSrcRe = /<iframe[^>]+src\s*=\s*(?:["']([^"']+)["']|([^\s>]+))/gi;
272
+ for (const m of html.matchAll(iframeSrcRe)) {
273
+ const url = m[1] ?? m[2];
274
+ if (isExternalUrl(url)) {
275
+ findings.push({
276
+ category: "html",
277
+ code: "external_iframe",
278
+ message: `External iframe source: ${url}`,
279
+ level: "block",
280
+ });
281
+ }
282
+ }
283
+
284
+ // <meta http-equiv="refresh"> with external URL
285
+ const metaRefreshRe = /<meta[^>]+http-equiv\s*=\s*["']refresh["'][^>]+content\s*=\s*["'][^"']*url\s*=\s*([^"'\s;]+)/gi;
286
+ for (const m of html.matchAll(metaRefreshRe)) {
287
+ if (isExternalUrl(m[1])) {
288
+ findings.push({
289
+ category: "html",
290
+ code: "external_meta_refresh",
291
+ message: `Meta refresh redirects to external URL: ${m[1]}`,
292
+ level: "block",
293
+ });
294
+ }
295
+ }
296
+
297
+ // --- Block-level: iframe srcdoc ---
298
+ if (/srcdoc\s*=/i.test(html)) {
299
+ findings.push({
300
+ category: "html",
301
+ code: "iframe_srcdoc",
302
+ message: "iframe srcdoc attribute can embed executable HTML",
303
+ level: "block",
304
+ });
305
+ }
306
+
307
+ // --- Block-level: formaction attribute ---
308
+ if (/formaction\s*=\s*["']https?:\/\//i.test(html)) {
309
+ findings.push({
310
+ category: "html",
311
+ code: "formaction_external",
312
+ message: "formaction attribute with external URL bypasses form restrictions",
313
+ level: "block",
314
+ });
315
+ }
316
+
317
+ // --- Warn-level: suspicious JS patterns ---
318
+
319
+ const warnPatterns: { pattern: RegExp; code: string; message: string }[] = [
320
+ { pattern: /\bfetch\s*\(/g, code: "network_fetch", message: "Uses fetch() for network requests \u2014 could send or receive data from external servers" },
321
+ { pattern: /\bXMLHttpRequest\b/g, code: "network_xhr", message: "Uses XMLHttpRequest for network requests \u2014 could send or receive data from external servers" },
322
+ { pattern: /\bnew\s+WebSocket\b/g, code: "network_websocket", message: "Uses WebSocket connections \u2014 could maintain persistent communication with a server" },
323
+ { pattern: /\bEventSource\b/g, code: "network_eventsource", message: "Uses server-sent events \u2014 could receive live data from a server" },
324
+ { pattern: /\bdocument\.cookie\b/g, code: "cookie_access", message: "Accesses browser cookies \u2014 could read or store tracking data" },
325
+ { pattern: /\beval\s*\(/g, code: "eval_usage", message: "Uses eval() for dynamic code execution \u2014 could run code not visible in the source" },
326
+ { pattern: /\bFunction\s*\(/g, code: "function_constructor", message: "Uses Function() constructor for dynamic code execution \u2014 could run code not visible in the source" },
327
+ {
328
+ pattern: /\bsetTimeout\s*\(\s*["'`]/g,
329
+ code: "settimeout_string",
330
+ message: "Uses setTimeout() with string for code execution \u2014 could run code not visible in the source",
331
+ },
332
+ {
333
+ pattern: /\bsetInterval\s*\(\s*["'`]/g,
334
+ code: "setinterval_string",
335
+ message: "Uses setInterval() with string for code execution \u2014 could run code not visible in the source",
336
+ },
337
+ { pattern: /\bwindow\.open\s*\(/g, code: "window_open", message: "Opens new windows \u2014 could navigate to external sites" },
338
+ {
339
+ pattern: /\bwindow\.location\s*=/g,
340
+ code: "window_location_assign",
341
+ message: "Redirects the page \u2014 could navigate away from the app",
342
+ },
343
+ {
344
+ pattern: /\bon(?:error|load|focus|blur|mouseover|mouseout|click|dblclick|submit|input|change|keydown|keyup|keypress)\s*=/g,
345
+ code: "html_event_handler",
346
+ message: "Uses inline event handlers \u2014 standard for interactive apps",
347
+ },
348
+ {
349
+ pattern: /@import\s+(?:url\s*\(|['"]https?:\/\/)/g,
350
+ code: "css_import",
351
+ message: "Loads external stylesheet \u2014 could connect to an external server",
352
+ },
353
+ {
354
+ pattern: /url\s*\(\s*['"]?https?:\/\//g,
355
+ code: "css_external_url",
356
+ message: "References external URL in CSS \u2014 could load resources from an external server",
357
+ },
358
+ {
359
+ pattern: /(?:src|href)\s*=\s*["']data:/g,
360
+ code: "data_uri",
361
+ message: "Uses embedded data URI \u2014 contains inline encoded content",
362
+ },
363
+ {
364
+ pattern: /(?:href|src|action)\s*=\s*["']javascript:/g,
365
+ code: "javascript_uri",
366
+ message: "Uses javascript: URI \u2014 could execute code on interaction",
367
+ },
368
+ ];
369
+
370
+ for (const { pattern, code, message } of warnPatterns) {
371
+ if (pattern.test(html)) {
372
+ findings.push({ category: "html", code, message, level: "warn" });
373
+ }
374
+ }
375
+
376
+ // Obfuscation detection: single lines > 10KB or high hex/unicode escape density
377
+ const lines = html.split("\n");
378
+ for (let i = 0; i < lines.length; i++) {
379
+ const line = lines[i];
380
+ if (line.length > OBFUSCATION_LINE_LENGTH) {
381
+ findings.push({
382
+ category: "html",
383
+ code: "obfuscated_js",
384
+ message: `Possible obfuscated JS: line ${i + 1} is ${(line.length / 1024).toFixed(1)} KB`,
385
+ level: "warn",
386
+ });
387
+ break; // one finding is enough
388
+ }
389
+ }
390
+
391
+ // High density of hex/unicode escapes
392
+ const escapeMatches = html.match(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/g);
393
+ if (escapeMatches && escapeMatches.length > 50) {
394
+ findings.push({
395
+ category: "html",
396
+ code: "obfuscated_js",
397
+ message: `High density of hex/unicode escapes detected (${escapeMatches.length} occurrences)`,
398
+ level: "warn",
399
+ });
400
+ }
401
+ }
402
+
403
+ function isExternalUrl(url: string): boolean {
404
+ const lower = url.toLowerCase();
405
+ return lower.startsWith("http://") || lower.startsWith("https://") || url.startsWith("//");
406
+ }
407
+
408
+ // ---------------------------------------------------------------------------
409
+ // Phase 3: Asset scan
410
+ // ---------------------------------------------------------------------------
411
+
412
+ async function scanAssets(zip: JSZip, findings: ScanFinding[], manifestEntry?: string): Promise<void> {
413
+ const allowedRootFiles = new Set(["index.html", "manifest.json", "signature.json"]);
414
+ if (manifestEntry) {
415
+ allowedRootFiles.add(manifestEntry);
416
+ }
417
+
418
+ for (const [name, entry] of Object.entries(zip.files)) {
419
+ if (entry.dir) continue;
420
+
421
+ // Double extension check — only flag when a known content/media extension
422
+ // appears before the final extension (e.g. file.jpg.exe, file.png.sh),
423
+ // which is a common technique to disguise executables. Legitimate multi-dot
424
+ // filenames like app.min.js or vendor.module.css are not flagged.
425
+ const basename = name.split("/").pop() ?? name;
426
+ const dotParts = basename.split(".");
427
+ if (dotParts.length > 2) {
428
+ const suspiciousInnerExts = new Set([
429
+ "jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico",
430
+ "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx",
431
+ "html", "htm", "txt", "rtf", "zip", "tar", "gz",
432
+ ]);
433
+ // Check if any non-final extension segment is a known content type
434
+ const innerParts = dotParts.slice(1, -1); // extensions between first dot and last dot
435
+ const hasSuspiciousInner = innerParts.some((p) => suspiciousInnerExts.has(p.toLowerCase()));
436
+ if (hasSuspiciousInner) {
437
+ findings.push({
438
+ category: "asset",
439
+ code: "double_extension",
440
+ message: `File has suspicious double extension: ${name}`,
441
+ level: "block",
442
+ });
443
+ }
444
+ }
445
+
446
+ // Files outside assets/ that aren't allowed root files
447
+ if (!name.startsWith("assets/") && !allowedRootFiles.has(name)) {
448
+ findings.push({
449
+ category: "asset",
450
+ code: "unexpected_file",
451
+ message: `Unexpected file outside assets/ directory: ${name}`,
452
+ level: "warn",
453
+ });
454
+ }
455
+
456
+ // Magic bytes validation for image files
457
+ const ext = getExtension(name);
458
+ const signatures = IMAGE_SIGNATURES[ext];
459
+ if (signatures) {
460
+ const data = await entry.async("uint8array");
461
+ const valid = validateImageMagicBytes(data, ext);
462
+ if (!valid) {
463
+ findings.push({
464
+ category: "asset",
465
+ code: "magic_bytes_mismatch",
466
+ message: `File ${name} has extension ${ext} but magic bytes don't match`,
467
+ level: "block",
468
+ });
469
+ }
470
+ }
471
+
472
+ // SVG: should start with < or <?xml
473
+ if (ext === ".svg") {
474
+ const data = await entry.async("text");
475
+ const trimmed = data.trimStart();
476
+ if (!trimmed.startsWith("<")) {
477
+ findings.push({
478
+ category: "asset",
479
+ code: "magic_bytes_mismatch",
480
+ message: `File ${name} has extension .svg but does not appear to be valid SVG`,
481
+ level: "block",
482
+ });
483
+ }
484
+
485
+ // SVG <script> tags — block-level
486
+ if (/<script/i.test(data)) {
487
+ findings.push({
488
+ category: "asset",
489
+ code: "svg_script",
490
+ message: `SVG file contains <script> tag: ${name}`,
491
+ level: "block",
492
+ });
493
+ }
494
+
495
+ // SVG event handlers — warn-level
496
+ if (/\bon\w+\s*=/i.test(data)) {
497
+ findings.push({
498
+ category: "asset",
499
+ code: "svg_event_handler",
500
+ message: `SVG file contains event handler attribute: ${name}`,
501
+ level: "warn",
502
+ });
503
+ }
504
+ }
505
+ }
506
+ }
507
+
508
+ function getExtension(name: string): string {
509
+ const dot = name.lastIndexOf(".");
510
+ if (dot === -1) return "";
511
+ return name.slice(dot).toLowerCase();
512
+ }
513
+
514
+ function validateImageMagicBytes(data: Uint8Array, ext: string): boolean {
515
+ const sigs = IMAGE_SIGNATURES[ext];
516
+ if (!sigs) return true;
517
+
518
+ // Check primary signature
519
+ const primary = sigs[0];
520
+ if (data.length < primary.bytes.length) return false;
521
+ for (let i = 0; i < primary.bytes.length; i++) {
522
+ if (data[i] !== primary.bytes[i]) return false;
523
+ }
524
+
525
+ // WebP needs additional check: bytes 8-11 should be "WEBP"
526
+ if (ext === ".webp") {
527
+ if (data.length < 12) return false;
528
+ const webp = [0x57, 0x45, 0x42, 0x50]; // WEBP
529
+ for (let i = 0; i < 4; i++) {
530
+ if (data[8 + i] !== webp[i]) return false;
531
+ }
532
+ }
533
+
534
+ return true;
535
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Bundle signing for .vellumapp archives.
3
+ *
4
+ * Computes content hashes, constructs a canonical signing payload,
5
+ * and requests an Ed25519 signature from the Swift client via IPC.
6
+ */
7
+
8
+ import { createHash } from 'node:crypto';
9
+ import { readFile } from 'node:fs/promises';
10
+ import JSZip from 'jszip';
11
+
12
+ export interface SignatureJson {
13
+ algorithm: 'ed25519';
14
+ signer: {
15
+ key_id: string;
16
+ display_name: string;
17
+ account?: string;
18
+ };
19
+ content_hashes: Record<string, string>;
20
+ signature: string; // base64-encoded
21
+ }
22
+
23
+ /**
24
+ * Callback type for requesting a signature from the Swift client via IPC.
25
+ * The caller provides this so the signer doesn't need to know about IPC details.
26
+ */
27
+ export type SigningCallback = (payload: string) => Promise<{
28
+ signature: string; // base64-encoded
29
+ keyId: string;
30
+ publicKey: string;
31
+ }>;
32
+
33
+ /**
34
+ * Recursively sort object keys alphabetically for canonical JSON.
35
+ */
36
+ function sortKeysDeep(obj: unknown): unknown {
37
+ if (obj === null || obj === undefined || typeof obj !== 'object') {
38
+ return obj;
39
+ }
40
+ if (Array.isArray(obj)) {
41
+ return obj.map(sortKeysDeep);
42
+ }
43
+ const sorted: Record<string, unknown> = {};
44
+ for (const key of Object.keys(obj as Record<string, unknown>).sort()) {
45
+ sorted[key] = sortKeysDeep((obj as Record<string, unknown>)[key]);
46
+ }
47
+ return sorted;
48
+ }
49
+
50
+ /**
51
+ * Compute SHA-256 hashes of all files in a zip archive, excluding signature.json.
52
+ */
53
+ async function computeContentHashes(zip: JSZip): Promise<Record<string, string>> {
54
+ const hashes: Record<string, string> = {};
55
+ const entries: string[] = [];
56
+
57
+ zip.forEach((relativePath, _file) => {
58
+ if (relativePath !== 'signature.json') {
59
+ entries.push(relativePath);
60
+ }
61
+ });
62
+
63
+ // Sort for deterministic ordering
64
+ entries.sort();
65
+
66
+ for (const entryPath of entries) {
67
+ const file = zip.file(entryPath);
68
+ if (!file || file.dir) continue;
69
+ const content = await file.async('nodebuffer');
70
+ const hash = createHash('sha256').update(content).digest('hex');
71
+ hashes[entryPath] = hash;
72
+ }
73
+
74
+ return hashes;
75
+ }
76
+
77
+ /**
78
+ * Sign a .vellumapp bundle.
79
+ *
80
+ * @param bundlePath - Path to the .vellumapp zip archive.
81
+ * @param requestSignature - Callback to request a signature from the Swift client.
82
+ * @returns The SignatureJson to embed in the archive.
83
+ */
84
+ export async function signBundle(
85
+ bundlePath: string,
86
+ requestSignature: SigningCallback,
87
+ ): Promise<SignatureJson> {
88
+ const zipBuffer = await readFile(bundlePath);
89
+ const zip = await JSZip.loadAsync(zipBuffer);
90
+
91
+ // 1. Compute content hashes
92
+ const contentHashes = await computeContentHashes(zip);
93
+
94
+ // 2. Read manifest
95
+ const manifestFile = zip.file('manifest.json');
96
+ if (!manifestFile) {
97
+ throw new Error('Bundle is missing manifest.json');
98
+ }
99
+ const manifestText = await manifestFile.async('text');
100
+ const manifest = JSON.parse(manifestText) as Record<string, unknown>;
101
+
102
+ // 3. Construct canonical signing payload with sorted keys
103
+ const signingPayload = sortKeysDeep({
104
+ content_hashes: contentHashes,
105
+ manifest,
106
+ });
107
+ const canonicalPayload = JSON.stringify(signingPayload);
108
+
109
+ // 4. Request signature from Swift via IPC
110
+ const { signature, keyId } = await requestSignature(canonicalPayload);
111
+
112
+ // 5. Build SignatureJson
113
+ const signatureJson: SignatureJson = {
114
+ algorithm: 'ed25519',
115
+ signer: {
116
+ key_id: keyId,
117
+ display_name: 'Local Signer',
118
+ },
119
+ content_hashes: contentHashes,
120
+ signature,
121
+ };
122
+
123
+ return signatureJson;
124
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Types and serialization for .vellumapp manifest files.
3
+ */
4
+
5
+ export interface AppManifest {
6
+ format_version: number; // always 1
7
+ name: string;
8
+ description?: string;
9
+ icon?: string; // single emoji
10
+ preview?: string; // base64-encoded PNG thumbnail, max ~50KB
11
+ created_at: string; // ISO 8601
12
+ created_by: string; // "vellum-assistant/{version}"
13
+ entry: string; // "index.html"
14
+ capabilities: string[]; // empty for MVP
15
+ version?: string; // semver, defaults to "1.0.0"
16
+ content_id?: string; // SHA-256 of "created_by:name", 16 hex chars
17
+ }
18
+
19
+ export function serializeManifest(manifest: AppManifest): string {
20
+ return JSON.stringify(manifest, null, 2);
21
+ }