@vellumai/assistant 0.4.44 → 0.4.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (681) hide show
  1. package/.prettierignore +4 -0
  2. package/ARCHITECTURE.md +34 -31
  3. package/README.md +4 -4
  4. package/bun.lock +10 -35
  5. package/docs/architecture/integrations.md +102 -197
  6. package/docs/architecture/keychain-broker.md +1 -1
  7. package/docs/architecture/memory.md +2 -2
  8. package/docs/architecture/scheduling.md +1 -1
  9. package/docs/architecture/security.md +11 -11
  10. package/docs/error-handling.md +1 -1
  11. package/docs/trusted-contact-access.md +3 -3
  12. package/drizzle/meta/0000_snapshot.json +34 -100
  13. package/drizzle/meta/_journal.json +1 -1
  14. package/drizzle.config.ts +4 -4
  15. package/package.json +3 -2
  16. package/scripts/capture-x-graphql.ts +237 -141
  17. package/scripts/generate-bundled-tool-registry.ts +223 -0
  18. package/src/__tests__/access-request-decision.test.ts +0 -1
  19. package/src/__tests__/actor-token-service.test.ts +23 -24
  20. package/src/__tests__/agent-loop.test.ts +0 -131
  21. package/src/__tests__/always-loaded-tools-guard.test.ts +71 -0
  22. package/src/__tests__/amazon-cdp-integration.test.ts +11 -9
  23. package/src/__tests__/approval-primitive.test.ts +0 -1
  24. package/src/__tests__/approval-routes-http.test.ts +11 -1
  25. package/src/__tests__/asset-materialize-tool.test.ts +0 -1
  26. package/src/__tests__/asset-search-tool.test.ts +0 -1
  27. package/src/__tests__/assistant-attachment-directive.test.ts +1 -1
  28. package/src/__tests__/assistant-events-sse-hardening.test.ts +0 -1
  29. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +70 -18
  31. package/src/__tests__/assistant-id-boundary-guard.test.ts +6 -6
  32. package/src/__tests__/attachments-store.test.ts +0 -1
  33. package/src/__tests__/avatar-e2e.test.ts +74 -115
  34. package/src/__tests__/avatar-router.test.ts +25 -62
  35. package/src/__tests__/browser-manager.test.ts +24 -0
  36. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +4 -3
  37. package/src/__tests__/browser-skill-endstate.test.ts +8 -11
  38. package/src/__tests__/btw-routes.test.ts +326 -0
  39. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +23 -9
  40. package/src/__tests__/call-controller.test.ts +0 -1
  41. package/src/__tests__/call-conversation-messages.test.ts +0 -1
  42. package/src/__tests__/call-domain.test.ts +0 -1
  43. package/src/__tests__/call-pointer-messages.test.ts +0 -1
  44. package/src/__tests__/call-recovery.test.ts +0 -1
  45. package/src/__tests__/call-routes-http.test.ts +0 -1
  46. package/src/__tests__/call-store.test.ts +0 -1
  47. package/src/__tests__/canonical-guardian-store.test.ts +0 -1
  48. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  49. package/src/__tests__/channel-approvals.test.ts +1 -1
  50. package/src/__tests__/channel-delivery-store.test.ts +0 -1
  51. package/src/__tests__/channel-guardian.test.ts +5 -7
  52. package/src/__tests__/channel-retry-sweep.test.ts +0 -1
  53. package/src/__tests__/checker.test.ts +4 -11
  54. package/src/__tests__/compaction.benchmark.test.ts +16 -14
  55. package/src/__tests__/computer-use-session-lifecycle.test.ts +10 -11
  56. package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
  57. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +2 -5
  58. package/src/__tests__/computer-use-tools.test.ts +35 -31
  59. package/src/__tests__/config-schema.test.ts +11 -15
  60. package/src/__tests__/config-watcher.test.ts +0 -1
  61. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  62. package/src/__tests__/conflict-store.test.ts +0 -1
  63. package/src/__tests__/connection-policy.test.ts +4 -7
  64. package/src/__tests__/contacts-tools.test.ts +0 -1
  65. package/src/__tests__/context-memory-e2e.test.ts +2 -4
  66. package/src/__tests__/context-overflow-reducer.test.ts +2 -4
  67. package/src/__tests__/context-window-manager.test.ts +147 -60
  68. package/src/__tests__/contradiction-checker.test.ts +0 -1
  69. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  70. package/src/__tests__/conversation-attention-telegram.test.ts +1 -1
  71. package/src/__tests__/conversation-pairing.test.ts +2 -2
  72. package/src/__tests__/conversation-routes-guardian-reply.test.ts +25 -1
  73. package/src/__tests__/conversation-routes-slash-commands.test.ts +381 -0
  74. package/src/__tests__/conversation-store.test.ts +0 -1
  75. package/src/__tests__/conversation-unread-route.test.ts +1 -2
  76. package/src/__tests__/credential-security-invariants.test.ts +7 -8
  77. package/src/__tests__/cross-provider-web-search.test.ts +353 -0
  78. package/src/__tests__/daemon-assistant-events.test.ts +6 -7
  79. package/src/__tests__/db-schedule-syntax-migration.test.ts +15 -3
  80. package/src/__tests__/delete-managed-skill-tool.test.ts +5 -9
  81. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
  82. package/src/__tests__/diagnostics-export.test.ts +189 -0
  83. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  84. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  85. package/src/__tests__/entity-extractor.test.ts +0 -1
  86. package/src/__tests__/entity-search.test.ts +0 -1
  87. package/src/__tests__/ephemeral-permissions.test.ts +2 -4
  88. package/src/__tests__/file-read-tool.test.ts +86 -0
  89. package/src/__tests__/followup-tools.test.ts +0 -1
  90. package/src/__tests__/frontmatter.test.ts +77 -34
  91. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  92. package/src/__tests__/gateway-only-guard.test.ts +1 -1
  93. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -1
  94. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  95. package/src/__tests__/guardian-action-followup-store.test.ts +0 -1
  96. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  97. package/src/__tests__/guardian-action-late-reply.test.ts +0 -1
  98. package/src/__tests__/guardian-action-store.test.ts +0 -1
  99. package/src/__tests__/guardian-action-sweep.test.ts +0 -1
  100. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  101. package/src/__tests__/guardian-dispatch.test.ts +1 -2
  102. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  103. package/src/__tests__/guardian-outbound-http.test.ts +0 -1
  104. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -1
  105. package/src/__tests__/guardian-routing-invariants.test.ts +1 -1
  106. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  107. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  108. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +3 -5
  109. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +28 -426
  110. package/src/__tests__/host-bash-proxy.test.ts +335 -0
  111. package/src/__tests__/host-file-proxy.test.ts +374 -0
  112. package/src/__tests__/host-shell-tool.test.ts +147 -1
  113. package/src/__tests__/http-user-message-parity.test.ts +361 -0
  114. package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
  115. package/src/__tests__/integration-status.test.ts +3 -8
  116. package/src/__tests__/intent-routing.test.ts +7 -46
  117. package/src/__tests__/invite-redemption-service.test.ts +0 -1
  118. package/src/__tests__/invite-routes-http.test.ts +0 -1
  119. package/src/__tests__/llm-usage-store.test.ts +0 -1
  120. package/src/__tests__/managed-avatar-client.test.ts +101 -55
  121. package/src/__tests__/managed-skill-lifecycle.test.ts +9 -18
  122. package/src/__tests__/managed-store.test.ts +94 -21
  123. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -1
  124. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +2 -4
  125. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -1
  126. package/src/__tests__/memory-recall-quality.test.ts +0 -1
  127. package/src/__tests__/memory-regressions.experimental.test.ts +0 -1
  128. package/src/__tests__/memory-regressions.test.ts +0 -1
  129. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -1
  130. package/src/__tests__/memory-upsert-concurrency.test.ts +0 -1
  131. package/src/__tests__/messaging-send-tool.test.ts +35 -0
  132. package/src/__tests__/messaging-skill-split.test.ts +138 -0
  133. package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
  134. package/src/__tests__/migration-export-http.test.ts +2 -3
  135. package/src/__tests__/migration-import-commit-http.test.ts +1 -2
  136. package/src/__tests__/migration-import-preflight-http.test.ts +1 -2
  137. package/src/__tests__/migration-validate-http.test.ts +1 -2
  138. package/src/__tests__/native-web-search.test.ts +475 -0
  139. package/src/__tests__/navigate-settings-tab.test.ts +84 -0
  140. package/src/__tests__/non-member-access-request.test.ts +0 -1
  141. package/src/__tests__/notification-broadcaster.test.ts +15 -15
  142. package/src/__tests__/notification-decision-strategy.test.ts +6 -6
  143. package/src/__tests__/notification-deep-link.test.ts +7 -7
  144. package/src/__tests__/notification-guardian-path.test.ts +2 -3
  145. package/src/__tests__/notification-telegram-adapter.test.ts +1 -1
  146. package/src/__tests__/notification-thread-candidates.test.ts +4 -4
  147. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  148. package/src/__tests__/playbook-execution.test.ts +0 -1
  149. package/src/__tests__/playbook-tools.test.ts +0 -1
  150. package/src/__tests__/profile-compiler.test.ts +0 -1
  151. package/src/__tests__/provider-managed-proxy-integration.test.ts +25 -0
  152. package/src/__tests__/qdrant-collection-migration.test.ts +223 -0
  153. package/src/__tests__/recording-handler.test.ts +30 -94
  154. package/src/__tests__/registry.test.ts +28 -35
  155. package/src/__tests__/relay-server.test.ts +0 -1
  156. package/src/__tests__/ride-shotgun-handler.test.ts +4 -20
  157. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  158. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  159. package/src/__tests__/runtime-events-sse.test.ts +0 -1
  160. package/src/__tests__/sandbox-diagnostics.test.ts +0 -1
  161. package/src/__tests__/scaffold-managed-skill-tool.test.ts +30 -28
  162. package/src/__tests__/schedule-store.test.ts +441 -1
  163. package/src/__tests__/schedule-tools.test.ts +468 -7
  164. package/src/__tests__/scheduler-recurrence.test.ts +196 -23
  165. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  166. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  167. package/src/__tests__/secret-prompt-log-hygiene.test.ts +6 -3
  168. package/src/__tests__/secret-response-routing.test.ts +4 -1
  169. package/src/__tests__/send-endpoint-busy.test.ts +14 -2
  170. package/src/__tests__/send-notification-tool.test.ts +0 -7
  171. package/src/__tests__/sequence-store.test.ts +0 -1
  172. package/src/__tests__/server-history-render.test.ts +1 -2
  173. package/src/__tests__/session-abort-tool-results.test.ts +0 -1
  174. package/src/__tests__/session-agent-loop.test.ts +46 -6
  175. package/src/__tests__/session-confirmation-signals.test.ts +0 -1
  176. package/src/__tests__/session-conflict-gate.test.ts +2 -6
  177. package/src/__tests__/session-error.test.ts +5 -14
  178. package/src/__tests__/session-init.benchmark.test.ts +3 -5
  179. package/src/__tests__/session-load-history-repair.test.ts +0 -1
  180. package/src/__tests__/session-media-retry.test.ts +12 -74
  181. package/src/__tests__/session-pre-run-repair.test.ts +0 -1
  182. package/src/__tests__/session-profile-injection.test.ts +2 -6
  183. package/src/__tests__/session-provider-retry-repair.test.ts +2 -6
  184. package/src/__tests__/session-queue.test.ts +94 -139
  185. package/src/__tests__/session-skill-tools.test.ts +115 -115
  186. package/src/__tests__/session-slash-known.test.ts +0 -1
  187. package/src/__tests__/session-slash-queue.test.ts +0 -1
  188. package/src/__tests__/session-slash-unknown.test.ts +0 -1
  189. package/src/__tests__/session-surfaces-task-progress.test.ts +34 -0
  190. package/src/__tests__/session-usage.test.ts +0 -1
  191. package/src/__tests__/session-workspace-cache-state.test.ts +2 -6
  192. package/src/__tests__/session-workspace-injection.test.ts +2 -6
  193. package/src/__tests__/session-workspace-tool-tracking.test.ts +2 -6
  194. package/src/__tests__/skill-feature-flags-integration.test.ts +180 -184
  195. package/src/__tests__/skill-feature-flags.test.ts +125 -18
  196. package/src/__tests__/skill-load-feature-flag.test.ts +1 -2
  197. package/src/__tests__/skill-load-tool.test.ts +194 -2
  198. package/src/__tests__/skill-projection-feature-flag.test.ts +27 -16
  199. package/src/__tests__/skill-projection.benchmark.test.ts +15 -14
  200. package/src/__tests__/skills.test.ts +14 -53
  201. package/src/__tests__/slack-channel-config.test.ts +0 -1
  202. package/src/__tests__/slack-inbound-verification.test.ts +0 -1
  203. package/src/__tests__/slack-skill.test.ts +1 -1
  204. package/src/__tests__/subagent-tools.test.ts +2 -2
  205. package/src/__tests__/system-prompt.test.ts +4 -3
  206. package/src/__tests__/task-compiler.test.ts +0 -1
  207. package/src/__tests__/task-management-tools.test.ts +0 -1
  208. package/src/__tests__/task-memory-cleanup.test.ts +0 -1
  209. package/src/__tests__/task-runner.test.ts +0 -1
  210. package/src/__tests__/task-scheduler.test.ts +0 -1
  211. package/src/__tests__/terminal-tools.test.ts +0 -1
  212. package/src/__tests__/test-support/computer-use-skill-harness.ts +2 -4
  213. package/src/__tests__/thread-seed-composer.test.ts +5 -5
  214. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  215. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  216. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  217. package/src/__tests__/tool-executor.test.ts +8 -86
  218. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  219. package/src/__tests__/tool-notification-listener.test.ts +1 -1
  220. package/src/__tests__/tool-preview-lifecycle.test.ts +416 -0
  221. package/src/__tests__/trust-store.test.ts +80 -4
  222. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  223. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  224. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -1
  225. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  226. package/src/__tests__/trusted-contact-verification.test.ts +0 -1
  227. package/src/__tests__/twilio-provider.test.ts +0 -1
  228. package/src/__tests__/twilio-routes.test.ts +0 -1
  229. package/src/__tests__/{request-file-tool.test.ts → ui-file-upload-surface.test.ts} +11 -72
  230. package/src/__tests__/update-bulletin.test.ts +0 -1
  231. package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -1
  232. package/src/__tests__/usage-routes.test.ts +0 -1
  233. package/src/__tests__/verification-control-plane-policy.test.ts +4 -4
  234. package/src/__tests__/voice-invite-redemption.test.ts +0 -1
  235. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  236. package/src/__tests__/voice-session-bridge.test.ts +9 -1
  237. package/src/__tests__/web-fetch.test.ts +57 -0
  238. package/src/__tests__/workspace-git-service.test.ts +5 -14
  239. package/src/__tests__/workspace-policy.test.ts +0 -1
  240. package/src/agent/loop.ts +22 -34
  241. package/src/bundler/bundle-signer.ts +4 -4
  242. package/src/calls/call-controller.ts +1 -1
  243. package/src/calls/relay-server.ts +1 -1
  244. package/src/calls/twilio-rest.ts +1 -1
  245. package/src/calls/voice-session-bridge.ts +3 -1
  246. package/src/cli/__tests__/notifications.test.ts +3 -4
  247. package/src/cli/commands/map.ts +2 -6
  248. package/src/cli/commands/mcp.ts +73 -15
  249. package/src/cli/commands/notifications.ts +4 -4
  250. package/src/cli/commands/sessions.ts +9 -1
  251. package/src/cli/commands/skills.ts +6 -10
  252. package/src/cli/http-client.ts +2 -3
  253. package/src/cli/main-screen.tsx +10 -10
  254. package/src/cli/program.ts +0 -4
  255. package/src/cli/reference.ts +0 -2
  256. package/src/cli.ts +15 -9
  257. package/src/config/__tests__/bundled-tool-registry-guard.test.ts +120 -0
  258. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +11 -0
  259. package/src/config/bundled-skills/app-builder/SKILL.md +6 -1
  260. package/src/config/bundled-skills/browser/SKILL.md +6 -1
  261. package/src/config/bundled-skills/chatgpt-import/SKILL.md +5 -1
  262. package/src/config/bundled-skills/claude-code/SKILL.md +5 -1
  263. package/src/config/bundled-skills/computer-use/SKILL.md +6 -1
  264. package/src/config/bundled-skills/computer-use/TOOLS.json +6 -69
  265. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +10 -1
  266. package/src/config/bundled-skills/contacts/SKILL.md +10 -1
  267. package/src/config/bundled-skills/contacts/TOOLS.json +35 -0
  268. package/src/config/bundled-skills/{messaging → contacts}/tools/google-contacts.ts +9 -2
  269. package/src/config/bundled-skills/document/SKILL.md +4 -1
  270. package/src/config/bundled-skills/doordash/SKILL.md +8 -1
  271. package/src/config/bundled-skills/doordash/lib/shared/platform.ts +4 -1
  272. package/src/config/bundled-skills/followups/SKILL.md +4 -1
  273. package/src/config/bundled-skills/gmail/SKILL.md +180 -0
  274. package/src/config/bundled-skills/gmail/TOOLS.json +506 -0
  275. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +149 -0
  276. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +110 -0
  277. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-draft.ts +1 -1
  278. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-filters.ts +1 -1
  279. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-follow-up.ts +1 -1
  280. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-forward.ts +1 -1
  281. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +50 -0
  282. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-outreach-scan.ts +8 -90
  283. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-send-draft.ts +1 -1
  284. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-sender-digest.ts +2 -2
  285. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-trash.ts +1 -1
  286. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-unsubscribe.ts +1 -1
  287. package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-vacation.ts +1 -1
  288. package/src/config/bundled-skills/gmail/tools/shared.ts +47 -0
  289. package/src/config/bundled-skills/google-calendar/SKILL.md +5 -1
  290. package/src/config/bundled-skills/image-studio/SKILL.md +5 -1
  291. package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -1
  292. package/src/config/bundled-skills/media-processing/SKILL.md +7 -13
  293. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -22
  294. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +12 -1
  295. package/src/config/bundled-skills/messaging/SKILL.md +23 -139
  296. package/src/config/bundled-skills/messaging/TOOLS.json +33 -1215
  297. package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +42 -0
  298. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +165 -2
  299. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +1 -13
  300. package/src/config/bundled-skills/messaging/tools/shared.ts +81 -34
  301. package/src/config/bundled-skills/notifications/SKILL.md +5 -1
  302. package/src/config/bundled-skills/orchestration/SKILL.md +30 -0
  303. package/src/config/bundled-skills/orchestration/TOOLS.json +35 -0
  304. package/src/config/bundled-skills/{reminder/tools/reminder-create.ts → orchestration/tools/swarm-delegate.ts} +3 -3
  305. package/src/config/bundled-skills/phone-calls/SKILL.md +9 -1
  306. package/src/config/bundled-skills/playbooks/SKILL.md +4 -1
  307. package/src/config/bundled-skills/schedule/SKILL.md +70 -9
  308. package/src/config/bundled-skills/schedule/TOOLS.json +38 -6
  309. package/src/config/bundled-skills/screen-watch/SKILL.md +28 -0
  310. package/src/config/bundled-skills/screen-watch/TOOLS.json +35 -0
  311. package/src/config/bundled-skills/{reminder/tools/reminder-cancel.ts → screen-watch/tools/start-screen-watch.ts} +3 -3
  312. package/src/config/bundled-skills/sequences/SKILL.md +47 -0
  313. package/src/config/bundled-skills/sequences/TOOLS.json +340 -0
  314. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +128 -0
  315. package/src/config/bundled-skills/sequences/tools/shared.ts +9 -0
  316. package/src/config/bundled-skills/settings/SKILL.md +12 -0
  317. package/src/config/bundled-skills/settings/TOOLS.json +112 -0
  318. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +43 -0
  319. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +52 -0
  320. package/src/config/bundled-skills/{computer-use/tools/computer-use-right-click.ts → settings/tools/set-avatar.ts} +2 -6
  321. package/src/{tools/system/voice-config.ts → config/bundled-skills/settings/tools/voice-config-update.ts} +59 -96
  322. package/src/config/bundled-skills/skill-management/SKILL.md +18 -0
  323. package/src/config/bundled-skills/skill-management/TOOLS.json +90 -0
  324. package/src/config/bundled-skills/{computer-use/tools/computer-use-double-click.ts → skill-management/tools/delete-managed.ts} +2 -6
  325. package/src/config/bundled-skills/skill-management/tools/scaffold-managed.ts +12 -0
  326. package/src/config/bundled-skills/slack/SKILL.md +5 -1
  327. package/src/config/bundled-skills/subagent/SKILL.md +4 -1
  328. package/src/config/bundled-skills/tasks/SKILL.md +5 -2
  329. package/src/config/bundled-skills/transcribe/SKILL.md +4 -1
  330. package/src/config/bundled-skills/watcher/SKILL.md +4 -1
  331. package/src/config/bundled-tool-registry.ts +118 -107
  332. package/src/config/env.ts +5 -2
  333. package/src/config/feature-flag-registry.json +25 -9
  334. package/src/config/loader.ts +10 -2
  335. package/src/config/schema.ts +19 -16
  336. package/src/config/schemas/inference.ts +12 -22
  337. package/src/config/schemas/memory-storage.ts +19 -1
  338. package/src/config/schemas/platform.ts +0 -16
  339. package/src/config/skill-state.ts +11 -8
  340. package/src/config/skills.ts +83 -32
  341. package/src/context/token-estimator.ts +11 -0
  342. package/src/context/window-manager.ts +180 -151
  343. package/src/daemon/computer-use-session.ts +11 -43
  344. package/src/daemon/daemon-control.ts +4 -1
  345. package/src/daemon/handlers/config-channels.ts +5 -9
  346. package/src/daemon/handlers/config-ingress.ts +0 -4
  347. package/src/daemon/handlers/config-model.ts +7 -13
  348. package/src/daemon/handlers/config-telegram.ts +4 -8
  349. package/src/daemon/handlers/config-voice.ts +2 -5
  350. package/src/daemon/handlers/dictation.ts +2 -12
  351. package/src/daemon/handlers/identity.ts +0 -105
  352. package/src/daemon/handlers/recording.ts +3 -23
  353. package/src/daemon/handlers/session-history.ts +1 -1
  354. package/src/daemon/handlers/sessions.ts +53 -72
  355. package/src/daemon/handlers/shared.ts +7 -28
  356. package/src/daemon/handlers/skills.ts +31 -27
  357. package/src/daemon/host-bash-proxy.ts +148 -0
  358. package/src/daemon/host-file-proxy.ts +135 -0
  359. package/src/daemon/lifecycle.ts +49 -24
  360. package/src/daemon/mcp-reload-service.ts +123 -0
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/browser.ts +1 -1
  363. package/src/daemon/message-types/computer-use.ts +1 -4
  364. package/src/daemon/message-types/guardian-actions.ts +1 -1
  365. package/src/daemon/message-types/host-bash.ts +18 -0
  366. package/src/daemon/message-types/host-file.ts +44 -0
  367. package/src/daemon/message-types/integrations.ts +1 -67
  368. package/src/daemon/message-types/messages.ts +15 -0
  369. package/src/daemon/message-types/schedules.ts +11 -27
  370. package/src/daemon/message-types/sessions.ts +2 -1
  371. package/src/daemon/message-types/settings.ts +1 -1
  372. package/src/daemon/message-types/shared.ts +1 -1
  373. package/src/daemon/ride-shotgun-handler.ts +2 -42
  374. package/src/daemon/server.ts +43 -10
  375. package/src/daemon/session-agent-loop-handlers.ts +48 -7
  376. package/src/daemon/session-agent-loop.ts +97 -66
  377. package/src/daemon/session-attachments.ts +1 -1
  378. package/src/daemon/session-error.ts +17 -16
  379. package/src/daemon/session-lifecycle.ts +20 -1
  380. package/src/daemon/session-media-retry.ts +1 -15
  381. package/src/daemon/session-messaging.ts +14 -6
  382. package/src/daemon/session-process.ts +36 -7
  383. package/src/daemon/session-queue-manager.ts +62 -103
  384. package/src/daemon/session-runtime-assembly.ts +27 -0
  385. package/src/daemon/session-skill-tools.ts +12 -11
  386. package/src/daemon/session-slash.ts +7 -0
  387. package/src/daemon/session-surfaces.ts +19 -97
  388. package/src/daemon/session-tool-setup.ts +146 -6
  389. package/src/daemon/session.ts +77 -13
  390. package/src/errors.ts +0 -2
  391. package/src/export/formatter.ts +6 -0
  392. package/src/mcp/mcp-oauth-provider.ts +1 -3
  393. package/src/media/avatar-router.ts +20 -28
  394. package/src/media/avatar-types.ts +7 -14
  395. package/src/media/managed-avatar-client.ts +70 -34
  396. package/src/memory/conversation-title-service.ts +1 -2
  397. package/src/memory/db-init.ts +16 -0
  398. package/src/memory/embedding-backend.ts +129 -27
  399. package/src/memory/embedding-gemini.test.ts +256 -0
  400. package/src/memory/embedding-gemini.ts +47 -13
  401. package/src/memory/embedding-local.ts +14 -2
  402. package/src/memory/embedding-ollama.ts +15 -2
  403. package/src/memory/embedding-openai.ts +15 -2
  404. package/src/memory/embedding-types.test.ts +116 -0
  405. package/src/memory/embedding-types.ts +61 -0
  406. package/src/memory/fingerprint.ts +1 -1
  407. package/src/memory/indexer.ts +25 -1
  408. package/src/memory/job-handlers/embedding.test.ts +258 -0
  409. package/src/memory/job-handlers/embedding.ts +81 -1
  410. package/src/memory/job-handlers/index-maintenance.ts +35 -1
  411. package/src/memory/job-handlers/media-processing.ts +11 -1
  412. package/src/memory/job-utils.ts +21 -6
  413. package/src/memory/jobs-store.ts +5 -1
  414. package/src/memory/jobs-worker.ts +8 -0
  415. package/src/memory/message-content.ts +66 -0
  416. package/src/memory/migrations/100-core-tables.ts +1 -31
  417. package/src/memory/migrations/104-core-indexes.ts +0 -11
  418. package/src/memory/migrations/145-drop-accounts-table.ts +19 -0
  419. package/src/memory/migrations/146-schedule-oneshot-routing.ts +94 -0
  420. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +129 -0
  421. package/src/memory/migrations/148-drop-reminders-table.ts +18 -0
  422. package/src/memory/migrations/index.ts +4 -0
  423. package/src/memory/migrations/registry.ts +19 -0
  424. package/src/memory/qdrant-client.ts +158 -43
  425. package/src/memory/retriever.test.ts +0 -1
  426. package/src/memory/retriever.ts +12 -2
  427. package/src/memory/schema/infrastructure.ts +5 -29
  428. package/src/memory/search/formatting.ts +34 -9
  429. package/src/memory/search/semantic.ts +57 -2
  430. package/src/memory/search/types.ts +2 -1
  431. package/src/notifications/AGENTS.md +2 -2
  432. package/src/notifications/README.md +59 -58
  433. package/src/notifications/adapters/macos.ts +1 -1
  434. package/src/notifications/broadcaster.ts +5 -5
  435. package/src/notifications/copy-composer.ts +1 -1
  436. package/src/notifications/decision-engine.ts +2 -2
  437. package/src/notifications/destination-resolver.ts +2 -2
  438. package/src/notifications/emit-signal.ts +8 -8
  439. package/src/notifications/signal.ts +1 -1
  440. package/src/notifications/thread-seed-composer.ts +1 -1
  441. package/src/oauth/connect-orchestrator.ts +1 -1
  442. package/src/oauth/token-persistence.ts +1 -1
  443. package/src/permissions/checker.ts +12 -1
  444. package/src/permissions/defaults.ts +10 -14
  445. package/src/permissions/trust-store.ts +37 -0
  446. package/src/permissions/workspace-policy.ts +0 -1
  447. package/src/prompts/__tests__/build-cli-reference-section.test.ts +11 -0
  448. package/src/prompts/computer-use-prompt.ts +1 -1
  449. package/src/prompts/system-prompt.ts +29 -30
  450. package/src/prompts/templates/SOUL.md +1 -2
  451. package/src/prompts/templates/UPDATES.md +16 -7
  452. package/src/providers/anthropic/client.ts +87 -33
  453. package/src/providers/gemini/client.ts +6 -0
  454. package/src/providers/managed-proxy/constants.ts +5 -0
  455. package/src/providers/openai/client.ts +15 -0
  456. package/src/providers/registry.ts +2 -2
  457. package/src/providers/types.ts +24 -2
  458. package/src/runtime/AGENTS.md +18 -0
  459. package/src/runtime/assistant-event-hub.ts +2 -3
  460. package/src/runtime/assistant-event.ts +4 -4
  461. package/src/runtime/auth/__tests__/context.test.ts +5 -5
  462. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  463. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -2
  464. package/src/runtime/auth/__tests__/{ipc-auth-context.test.ts → local-auth-context.test.ts} +21 -21
  465. package/src/runtime/auth/__tests__/route-policy.test.ts +2 -2
  466. package/src/runtime/auth/__tests__/scopes.test.ts +7 -7
  467. package/src/runtime/auth/__tests__/subject.test.ts +8 -8
  468. package/src/runtime/auth/__tests__/token-service.test.ts +0 -1
  469. package/src/runtime/auth/route-policy.ts +8 -4
  470. package/src/runtime/auth/scopes.ts +1 -1
  471. package/src/runtime/auth/subject.ts +4 -4
  472. package/src/runtime/auth/token-service.ts +0 -23
  473. package/src/runtime/auth/types.ts +3 -3
  474. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  475. package/src/runtime/guardian-action-grant-minter.ts +1 -1
  476. package/src/runtime/guardian-action-service.ts +3 -3
  477. package/src/runtime/http-server.ts +15 -2
  478. package/src/runtime/invite-service.ts +3 -3
  479. package/src/runtime/local-actor-identity.ts +17 -22
  480. package/src/runtime/pending-interactions.ts +21 -9
  481. package/src/runtime/routes/app-management-routes.ts +2 -3
  482. package/src/runtime/routes/approval-routes.ts +1 -3
  483. package/src/runtime/routes/btw-routes.ts +155 -0
  484. package/src/runtime/routes/computer-use-routes.ts +77 -31
  485. package/src/runtime/routes/conversation-routes.ts +230 -46
  486. package/src/runtime/routes/diagnostics-routes.ts +63 -29
  487. package/src/runtime/routes/documents-routes.ts +2 -2
  488. package/src/runtime/routes/global-search-routes.ts +1 -1
  489. package/src/runtime/routes/host-bash-routes.ts +83 -0
  490. package/src/runtime/routes/host-file-routes.ts +79 -0
  491. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  492. package/src/runtime/routes/log-export-routes.ts +120 -0
  493. package/src/runtime/routes/mcp-routes.ts +20 -0
  494. package/src/runtime/routes/migration-routes.ts +3 -3
  495. package/src/runtime/routes/pairing-routes.ts +1 -1
  496. package/src/runtime/routes/recording-routes.ts +6 -4
  497. package/src/runtime/routes/schedule-routes.ts +31 -5
  498. package/src/runtime/routes/session-management-routes.ts +2 -6
  499. package/src/runtime/routes/session-query-routes.ts +18 -15
  500. package/src/runtime/routes/settings-routes.ts +7 -261
  501. package/src/runtime/routes/skills-routes.ts +7 -6
  502. package/src/runtime/routes/subagents-routes.ts +4 -10
  503. package/src/runtime/routes/surface-action-routes.ts +3 -14
  504. package/src/runtime/routes/surface-content-routes.ts +22 -5
  505. package/src/runtime/routes/work-items-routes.ts +21 -25
  506. package/src/runtime/routes/workspace-routes.test.ts +3 -3
  507. package/src/runtime/routes/workspace-utils.ts +1 -1
  508. package/src/runtime/telegram-streaming-delivery.ts +3 -0
  509. package/src/runtime/verification-outbound-actions.ts +2 -2
  510. package/src/schedule/integration-status.ts +0 -6
  511. package/src/schedule/schedule-store.ts +234 -43
  512. package/src/schedule/scheduler.ts +73 -74
  513. package/src/security/oauth2.ts +1 -1
  514. package/src/sequence/store.ts +12 -2
  515. package/src/skills/frontmatter.ts +19 -77
  516. package/src/skills/managed-store.ts +11 -2
  517. package/src/subagent/manager.ts +5 -3
  518. package/src/tasks/ephemeral-permissions.ts +3 -5
  519. package/src/tools/AGENTS.md +0 -1
  520. package/src/tools/browser/browser-manager.ts +17 -11
  521. package/src/tools/browser/jit-auth.ts +4 -1
  522. package/src/tools/claude-code/claude-code.ts +1 -1
  523. package/src/tools/computer-use/definitions.ts +48 -60
  524. package/src/tools/document/document-tool.ts +6 -6
  525. package/src/tools/filesystem/edit.ts +2 -1
  526. package/src/tools/filesystem/read.ts +20 -2
  527. package/src/tools/filesystem/write.ts +2 -1
  528. package/src/tools/host-filesystem/edit.ts +17 -1
  529. package/src/tools/host-filesystem/read.ts +16 -1
  530. package/src/tools/host-filesystem/write.ts +15 -1
  531. package/src/tools/host-terminal/host-shell.ts +24 -0
  532. package/src/tools/memory/definitions.ts +45 -81
  533. package/src/tools/memory/handlers.test.ts +0 -1
  534. package/src/tools/memory/handlers.ts +1 -1
  535. package/src/tools/memory/register.ts +26 -60
  536. package/src/tools/network/script-proxy/session-manager.ts +6 -8
  537. package/src/tools/network/web-fetch.ts +7 -1
  538. package/src/tools/network/web-search.ts +2 -1
  539. package/src/tools/registry.ts +23 -0
  540. package/src/tools/schedule/create.ts +113 -5
  541. package/src/tools/schedule/list.ts +57 -15
  542. package/src/tools/schedule/update.ts +73 -3
  543. package/src/tools/shared/filesystem/image-read.ts +192 -0
  544. package/src/tools/side-effects.ts +1 -7
  545. package/src/tools/skills/delete-managed.ts +27 -64
  546. package/src/tools/skills/execute.ts +54 -0
  547. package/src/tools/skills/load.ts +127 -5
  548. package/src/tools/skills/scaffold-managed.ts +93 -172
  549. package/src/tools/subagent/message.ts +0 -7
  550. package/src/tools/subagent/spawn.ts +1 -1
  551. package/src/tools/swarm/delegate.ts +0 -3
  552. package/src/tools/system/avatar-generator.ts +13 -19
  553. package/src/tools/system/request-permission.ts +2 -1
  554. package/src/tools/terminal/safe-env.ts +1 -0
  555. package/src/tools/tool-manifest.ts +41 -47
  556. package/src/tools/types.ts +6 -2
  557. package/src/tools/ui-surface/definitions.ts +0 -55
  558. package/src/util/errors.ts +0 -10
  559. package/src/workspace/git-service.ts +0 -2
  560. package/src/__tests__/account-registry.test.ts +0 -258
  561. package/src/__tests__/email-classifier.test.ts +0 -25
  562. package/src/__tests__/gmail-integration.test.ts +0 -97
  563. package/src/__tests__/handle-user-message-secret-resume.test.ts +0 -172
  564. package/src/__tests__/managed-twitter-guardrails.test.ts +0 -357
  565. package/src/__tests__/recording-intent-fallback.test.ts +0 -199
  566. package/src/__tests__/recording-intent.test.ts +0 -985
  567. package/src/__tests__/recording-state-machine.test.ts +0 -1574
  568. package/src/__tests__/reminder-store.test.ts +0 -350
  569. package/src/__tests__/reminder.test.ts +0 -337
  570. package/src/__tests__/scan-result-store.test.ts +0 -121
  571. package/src/__tests__/twitter-platform-proxy-client.test.ts +0 -475
  572. package/src/__tests__/view-image-tool.test.ts +0 -241
  573. package/src/cli/commands/amazon/cart.ts +0 -513
  574. package/src/cli/commands/amazon/checkout.ts +0 -394
  575. package/src/cli/commands/amazon/client.ts +0 -513
  576. package/src/cli/commands/amazon/index.ts +0 -885
  577. package/src/cli/commands/amazon/product-details.ts +0 -145
  578. package/src/cli/commands/amazon/request-extractor.ts +0 -187
  579. package/src/cli/commands/amazon/search.ts +0 -76
  580. package/src/cli/commands/amazon/session.ts +0 -108
  581. package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +0 -345
  582. package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +0 -252
  583. package/src/cli/commands/twitter/__tests__/oauth-client.test.ts +0 -151
  584. package/src/cli/commands/twitter/index.ts +0 -420
  585. package/src/cli/commands/twitter/oauth-client.ts +0 -60
  586. package/src/cli/commands/twitter/router.ts +0 -351
  587. package/src/cli/commands/twitter/types.ts +0 -30
  588. package/src/config/bundled-skills/agentmail/SKILL.md +0 -132
  589. package/src/config/bundled-skills/agentmail/icon.svg +0 -21
  590. package/src/config/bundled-skills/amazon/SKILL.md +0 -136
  591. package/src/config/bundled-skills/amazon/icon.svg +0 -13
  592. package/src/config/bundled-skills/api-mapping/SKILL.md +0 -78
  593. package/src/config/bundled-skills/api-mapping/icon.svg +0 -18
  594. package/src/config/bundled-skills/cli-discover/SKILL.md +0 -68
  595. package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +0 -179
  596. package/src/config/bundled-skills/document-writer/SKILL.md +0 -195
  597. package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +0 -140
  598. package/src/config/bundled-skills/email-setup/SKILL.md +0 -68
  599. package/src/config/bundled-skills/frontend-design/SKILL.md +0 -44
  600. package/src/config/bundled-skills/frontend-design/icon.svg +0 -16
  601. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +0 -452
  602. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +0 -203
  603. package/src/config/bundled-skills/influencer/SKILL.md +0 -144
  604. package/src/config/bundled-skills/influencer/scripts/client.ts +0 -1269
  605. package/src/config/bundled-skills/influencer/scripts/influencer.ts +0 -267
  606. package/src/config/bundled-skills/macos-automation/SKILL.md +0 -65
  607. package/src/config/bundled-skills/macos-automation/icon.svg +0 -12
  608. package/src/config/bundled-skills/mcp-setup/SKILL.md +0 -75
  609. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +0 -184
  610. package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +0 -80
  611. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +0 -29
  612. package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +0 -56
  613. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +0 -34
  614. package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +0 -47
  615. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +0 -31
  616. package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +0 -67
  617. package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +0 -97
  618. package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +0 -87
  619. package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +0 -135
  620. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +0 -24
  621. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +0 -201
  622. package/src/config/bundled-skills/messaging/tools/send-notification.ts +0 -1
  623. package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +0 -27
  624. package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +0 -48
  625. package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +0 -27
  626. package/src/config/bundled-skills/messaging/tools/sequence-update.ts +0 -56
  627. package/src/config/bundled-skills/notion/SKILL.md +0 -240
  628. package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +0 -126
  629. package/src/config/bundled-skills/oauth-setup/SKILL.md +0 -143
  630. package/src/config/bundled-skills/public-ingress/SKILL.md +0 -258
  631. package/src/config/bundled-skills/reminder/SKILL.md +0 -79
  632. package/src/config/bundled-skills/reminder/TOOLS.json +0 -89
  633. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +0 -12
  634. package/src/config/bundled-skills/restaurant-reservation/SKILL.md +0 -141
  635. package/src/config/bundled-skills/screen-recording/SKILL.md +0 -148
  636. package/src/config/bundled-skills/self-upgrade/SKILL.md +0 -69
  637. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -78
  638. package/src/config/bundled-skills/slack-app-setup/SKILL.md +0 -178
  639. package/src/config/bundled-skills/slack-digest-setup/SKILL.md +0 -163
  640. package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +0 -157
  641. package/src/config/bundled-skills/start-the-day/SKILL.md +0 -70
  642. package/src/config/bundled-skills/start-the-day/icon.svg +0 -13
  643. package/src/config/bundled-skills/telegram-setup/SKILL.md +0 -105
  644. package/src/config/bundled-skills/time-based-actions/SKILL.md +0 -142
  645. package/src/config/bundled-skills/twilio-setup/SKILL.md +0 -232
  646. package/src/config/bundled-skills/twitter/SKILL.md +0 -206
  647. package/src/config/bundled-skills/twitter/icon.svg +0 -14
  648. package/src/config/bundled-skills/typescript-eval/SKILL.md +0 -60
  649. package/src/config/bundled-skills/vercel-token-setup/SKILL.md +0 -214
  650. package/src/config/bundled-skills/voice-setup/SKILL.md +0 -131
  651. package/src/config/bundled-skills/voice-setup/icon.svg +0 -20
  652. package/src/daemon/handlers/pairing.ts +0 -119
  653. package/src/daemon/handlers/session-user-message.ts +0 -961
  654. package/src/daemon/recording-executor.ts +0 -180
  655. package/src/daemon/recording-intent-fallback.ts +0 -162
  656. package/src/daemon/recording-intent.ts +0 -493
  657. package/src/memory/account-store.ts +0 -117
  658. package/src/messaging/activity-analyzer.ts +0 -76
  659. package/src/messaging/email-classifier.ts +0 -208
  660. package/src/messaging/index.ts +0 -2
  661. package/src/messaging/outreach-classifier.ts +0 -185
  662. package/src/messaging/thread-summarizer.ts +0 -346
  663. package/src/messaging/types.ts +0 -17
  664. package/src/tools/browser/x-auto-navigate.ts +0 -254
  665. package/src/tools/credentials/account-registry.ts +0 -144
  666. package/src/tools/filesystem/view-image.ts +0 -244
  667. package/src/tools/reminder/reminder-store.ts +0 -194
  668. package/src/tools/reminder/reminder.ts +0 -158
  669. package/src/tools/system/navigate-settings.ts +0 -74
  670. package/src/tools/system/open-system-settings.ts +0 -85
  671. package/src/tools/system/version.ts +0 -54
  672. package/src/twitter/platform-proxy-client.ts +0 -408
  673. /package/src/config/bundled-skills/{messaging → gmail}/tools/scan-result-store.ts +0 -0
  674. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-analytics.ts +0 -0
  675. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-create.ts +0 -0
  676. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-delete.ts +0 -0
  677. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enroll.ts +0 -0
  678. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enrollment-list.ts +0 -0
  679. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-get.ts +0 -0
  680. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-import.ts +0 -0
  681. /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-list.ts +0 -0
@@ -18,15 +18,9 @@ mock.module("../util/logger.js", () => ({
18
18
  }),
19
19
  }));
20
20
 
21
- import { ScaffoldManagedSkillTool } from "../tools/skills/scaffold-managed.js";
21
+ import { executeScaffoldManagedSkill } from "../tools/skills/scaffold-managed.js";
22
22
  import type { ToolContext } from "../tools/types.js";
23
23
 
24
- // Use internal class directly to avoid registry side effects
25
-
26
- const tool = new (ScaffoldManagedSkillTool as any)() as InstanceType<
27
- typeof ScaffoldManagedSkillTool
28
- >;
29
-
30
24
  function makeContext(): ToolContext {
31
25
  return {
32
26
  workingDir: "/tmp",
@@ -47,7 +41,7 @@ afterEach(() => {
47
41
 
48
42
  describe("scaffold_managed_skill tool", () => {
49
43
  test("creates a valid skill and index entry", async () => {
50
- const result = await tool.execute(
44
+ const result = await executeScaffoldManagedSkill(
51
45
  {
52
46
  skill_id: "test-skill",
53
47
  name: "Test Skill",
@@ -76,7 +70,7 @@ describe("scaffold_managed_skill tool", () => {
76
70
  });
77
71
 
78
72
  test("rejects duplicate unless overwrite=true", async () => {
79
- await tool.execute(
73
+ await executeScaffoldManagedSkill(
80
74
  {
81
75
  skill_id: "dupe",
82
76
  name: "Original",
@@ -86,7 +80,7 @@ describe("scaffold_managed_skill tool", () => {
86
80
  makeContext(),
87
81
  );
88
82
 
89
- const result2 = await tool.execute(
83
+ const result2 = await executeScaffoldManagedSkill(
90
84
  {
91
85
  skill_id: "dupe",
92
86
  name: "Duplicate",
@@ -98,7 +92,7 @@ describe("scaffold_managed_skill tool", () => {
98
92
  expect(result2.isError).toBe(true);
99
93
  expect(result2.content).toContain("already exists");
100
94
 
101
- const result3 = await tool.execute(
95
+ const result3 = await executeScaffoldManagedSkill(
102
96
  {
103
97
  skill_id: "dupe",
104
98
  name: "Overwritten",
@@ -120,13 +114,13 @@ describe("scaffold_managed_skill tool", () => {
120
114
  ];
121
115
 
122
116
  for (const input of cases) {
123
- const result = await tool.execute(input, makeContext());
117
+ const result = await executeScaffoldManagedSkill(input, makeContext());
124
118
  expect(result.isError).toBe(true);
125
119
  }
126
120
  });
127
121
 
128
122
  test("sanitizes embedded newlines in name/description/emoji to prevent frontmatter injection", async () => {
129
- const result = await tool.execute(
123
+ const result = await executeScaffoldManagedSkill(
130
124
  {
131
125
  skill_id: "inject-test",
132
126
  name: 'Test\ninjected_field: "evil"',
@@ -143,17 +137,20 @@ describe("scaffold_managed_skill tool", () => {
143
137
 
144
138
  // Newlines must not appear inside frontmatter values
145
139
  const frontmatter = content.split("---")[1];
146
- const fmLines = frontmatter.split("\n").filter((l) => l.trim());
147
- // Each frontmatter line must start with a known key -- no injected keys
140
+ // Only check top-level (non-indented) keys — nested YAML under metadata: is expected
141
+ const fmLines = frontmatter
142
+ .split("\n")
143
+ .filter((l) => l.trim() && !l.match(/^\s/));
144
+ // Each top-level frontmatter line must start with a known key -- no injected keys
148
145
  for (const line of fmLines) {
149
146
  expect(line).toMatch(
150
- /^(name|description|emoji|user-invocable|disable-model-invocation|metadata):\s/,
147
+ /^(name|description|emoji|user-invocable|disable-model-invocation|metadata)(:\s|:$)/,
151
148
  );
152
149
  }
153
150
  });
154
151
 
155
152
  test("creates a skill with includes metadata", async () => {
156
- const result = await tool.execute(
153
+ const result = await executeScaffoldManagedSkill(
157
154
  {
158
155
  skill_id: "parent-skill",
159
156
  name: "Parent",
@@ -167,11 +164,13 @@ describe("scaffold_managed_skill tool", () => {
167
164
  expect(result.isError).toBe(false);
168
165
  const skillFile = join(TEST_DIR, "skills", "parent-skill", "SKILL.md");
169
166
  const content = readFileSync(skillFile, "utf-8");
170
- expect(content).toContain('"includes":["child-a","child-b"]');
167
+ expect(content).toContain(" includes:");
168
+ expect(content).toContain(" - child-a");
169
+ expect(content).toContain(" - child-b");
171
170
  });
172
171
 
173
172
  test("normalizes includes — trims and deduplicates", async () => {
174
- const result = await tool.execute(
173
+ const result = await executeScaffoldManagedSkill(
175
174
  {
176
175
  skill_id: "norm-skill",
177
176
  name: "Normalized",
@@ -185,11 +184,13 @@ describe("scaffold_managed_skill tool", () => {
185
184
  expect(result.isError).toBe(false);
186
185
  const skillFile = join(TEST_DIR, "skills", "norm-skill", "SKILL.md");
187
186
  const content = readFileSync(skillFile, "utf-8");
188
- expect(content).toContain('"includes":["child-a","child-b"]');
187
+ expect(content).toContain(" includes:");
188
+ expect(content).toContain(" - child-a");
189
+ expect(content).toContain(" - child-b");
189
190
  });
190
191
 
191
192
  test("rejects includes with non-string elements", async () => {
192
- const result = await tool.execute(
193
+ const result = await executeScaffoldManagedSkill(
193
194
  {
194
195
  skill_id: "bad-includes",
195
196
  name: "Bad",
@@ -205,7 +206,7 @@ describe("scaffold_managed_skill tool", () => {
205
206
  });
206
207
 
207
208
  test("rejects includes with empty string elements", async () => {
208
- const result = await tool.execute(
209
+ const result = await executeScaffoldManagedSkill(
209
210
  {
210
211
  skill_id: "empty-includes",
211
212
  name: "Empty",
@@ -221,7 +222,7 @@ describe("scaffold_managed_skill tool", () => {
221
222
  });
222
223
 
223
224
  test("rejects includes with whitespace-only elements", async () => {
224
- const result = await tool.execute(
225
+ const result = await executeScaffoldManagedSkill(
225
226
  {
226
227
  skill_id: "ws-includes",
227
228
  name: "Whitespace",
@@ -237,7 +238,7 @@ describe("scaffold_managed_skill tool", () => {
237
238
  });
238
239
 
239
240
  test("omits includes when not provided", async () => {
240
- const result = await tool.execute(
241
+ const result = await executeScaffoldManagedSkill(
241
242
  {
242
243
  skill_id: "no-includes",
243
244
  name: "Solo",
@@ -254,7 +255,7 @@ describe("scaffold_managed_skill tool", () => {
254
255
  });
255
256
 
256
257
  test("rejects invalid skill_id", async () => {
257
- const result = await tool.execute(
258
+ const result = await executeScaffoldManagedSkill(
258
259
  {
259
260
  skill_id: "../escape",
260
261
  name: "Bad",
@@ -269,7 +270,7 @@ describe("scaffold_managed_skill tool", () => {
269
270
  });
270
271
 
271
272
  test("e2e: scaffold child then parent with includes, verify files and index", async () => {
272
- const childResult = await tool.execute(
273
+ const childResult = await executeScaffoldManagedSkill(
273
274
  {
274
275
  skill_id: "e2e-child",
275
276
  name: "E2E Child",
@@ -280,7 +281,7 @@ describe("scaffold_managed_skill tool", () => {
280
281
  );
281
282
  expect(childResult.isError).toBe(false);
282
283
 
283
- const parentResult = await tool.execute(
284
+ const parentResult = await executeScaffoldManagedSkill(
284
285
  {
285
286
  skill_id: "e2e-parent",
286
287
  name: "E2E Parent",
@@ -295,7 +296,8 @@ describe("scaffold_managed_skill tool", () => {
295
296
  const parentSkillFile = join(TEST_DIR, "skills", "e2e-parent", "SKILL.md");
296
297
  expect(existsSync(parentSkillFile)).toBe(true);
297
298
  const parentContent = readFileSync(parentSkillFile, "utf-8");
298
- expect(parentContent).toContain('"includes":["e2e-child"]');
299
+ expect(parentContent).toContain(" includes:");
300
+ expect(parentContent).toContain(" - e2e-child");
299
301
 
300
302
  const indexContent = readFileSync(
301
303
  join(TEST_DIR, "skills", "SKILLS.md"),
@@ -11,7 +11,6 @@ mock.module("../util/platform.js", () => ({
11
11
  isMacOS: () => process.platform === "darwin",
12
12
  isLinux: () => process.platform === "linux",
13
13
  isWindows: () => process.platform === "win32",
14
- getSocketPath: () => join(testDir, "test.sock"),
15
14
  getPidPath: () => join(testDir, "test.pid"),
16
15
  getDbPath: () => join(testDir, "test.db"),
17
16
  getLogPath: () => join(testDir, "test.log"),
@@ -29,9 +28,14 @@ mock.module("../util/logger.js", () => ({
29
28
 
30
29
  import { getDb, initializeDb, resetDb } from "../memory/db.js";
31
30
  import {
31
+ cancelSchedule,
32
32
  claimDueSchedules,
33
+ completeOneShot,
33
34
  createSchedule,
35
+ describeCronExpression,
36
+ failOneShot,
34
37
  getSchedule,
38
+ listSchedules,
35
39
  updateSchedule,
36
40
  } from "../schedule/schedule-store.js";
37
41
 
@@ -569,3 +573,439 @@ describe("claimDueSchedules", () => {
569
573
  expect(second.length).toBe(0);
570
574
  });
571
575
  });
576
+
577
+ // ── One-shot schedules ──────────────────────────────────────────────
578
+
579
+ describe("createSchedule (one-shot)", () => {
580
+ beforeEach(() => {
581
+ const db = getDb();
582
+ db.run("DELETE FROM cron_runs");
583
+ db.run("DELETE FROM cron_jobs");
584
+ });
585
+
586
+ test("creates a one-shot schedule with no expression", () => {
587
+ const fireAt = Date.now() + 60_000;
588
+ const job = createSchedule({
589
+ name: "Remind me",
590
+ message: "take out the trash",
591
+ nextRunAt: fireAt,
592
+ });
593
+
594
+ expect(job.expression).toBeNull();
595
+ expect(job.cronExpression).toBeNull();
596
+ expect(job.nextRunAt).toBe(fireAt);
597
+ expect(job.enabled).toBe(true);
598
+ expect(job.status).toBe("active");
599
+ expect(job.mode).toBe("execute");
600
+ expect(job.routingIntent).toBe("all_channels");
601
+ expect(job.routingHints).toEqual({});
602
+ });
603
+
604
+ test("creates a one-shot schedule with notify mode and routing", () => {
605
+ const fireAt = Date.now() + 60_000;
606
+ const hints = { preferredChannel: "slack", threadId: "abc123" };
607
+ const job = createSchedule({
608
+ name: "Notify me",
609
+ message: "meeting in 5",
610
+ nextRunAt: fireAt,
611
+ mode: "notify",
612
+ routingIntent: "single_channel",
613
+ routingHints: hints,
614
+ });
615
+
616
+ expect(job.mode).toBe("notify");
617
+ expect(job.routingIntent).toBe("single_channel");
618
+ expect(job.routingHints).toEqual(hints);
619
+ expect(job.expression).toBeNull();
620
+ expect(job.status).toBe("active");
621
+ });
622
+
623
+ test("rejects one-shot schedule without nextRunAt", () => {
624
+ expect(() =>
625
+ createSchedule({
626
+ name: "Bad one-shot",
627
+ message: "no time",
628
+ }),
629
+ ).toThrow("One-shot schedules (no expression) require nextRunAt");
630
+ });
631
+
632
+ test("one-shot schedule persists and round-trips correctly", () => {
633
+ const fireAt = Date.now() + 120_000;
634
+ const hints = { channel: "telegram" };
635
+ const job = createSchedule({
636
+ name: "Persist test",
637
+ message: "round trip",
638
+ nextRunAt: fireAt,
639
+ mode: "notify",
640
+ routingIntent: "multi_channel",
641
+ routingHints: hints,
642
+ });
643
+
644
+ const retrieved = getSchedule(job.id);
645
+ expect(retrieved).not.toBeNull();
646
+ expect(retrieved!.expression).toBeNull();
647
+ expect(retrieved!.cronExpression).toBeNull();
648
+ expect(retrieved!.nextRunAt).toBe(fireAt);
649
+ expect(retrieved!.mode).toBe("notify");
650
+ expect(retrieved!.routingIntent).toBe("multi_channel");
651
+ expect(retrieved!.routingHints).toEqual(hints);
652
+ expect(retrieved!.status).toBe("active");
653
+ });
654
+ });
655
+
656
+ // ── One-shot claiming ───────────────────────────────────────────────
657
+
658
+ describe("claimDueSchedules (one-shot)", () => {
659
+ beforeEach(() => {
660
+ const db = getDb();
661
+ db.run("DELETE FROM cron_runs");
662
+ db.run("DELETE FROM cron_jobs");
663
+ });
664
+
665
+ test("claims one-shot schedules whose nextRunAt <= now", () => {
666
+ const job = createSchedule({
667
+ name: "Due one-shot",
668
+ message: "fire now",
669
+ nextRunAt: Date.now() - 1000,
670
+ });
671
+
672
+ const claimed = claimDueSchedules(Date.now());
673
+ expect(claimed.length).toBe(1);
674
+ expect(claimed[0].id).toBe(job.id);
675
+ expect(claimed[0].expression).toBeNull();
676
+ expect(claimed[0].status).toBe("firing");
677
+ });
678
+
679
+ test("does not claim one-shot schedules that are not yet due", () => {
680
+ createSchedule({
681
+ name: "Future one-shot",
682
+ message: "not yet",
683
+ nextRunAt: Date.now() + 60_000,
684
+ });
685
+
686
+ const claimed = claimDueSchedules(Date.now());
687
+ expect(claimed.length).toBe(0);
688
+ });
689
+
690
+ test("does not double-claim one-shot schedules", () => {
691
+ createSchedule({
692
+ name: "Once only",
693
+ message: "no double",
694
+ nextRunAt: Date.now() - 1000,
695
+ });
696
+
697
+ const first = claimDueSchedules(Date.now());
698
+ expect(first.length).toBe(1);
699
+
700
+ // Second claim should find nothing since status is now 'firing'
701
+ const second = claimDueSchedules(Date.now());
702
+ expect(second.length).toBe(0);
703
+ });
704
+
705
+ test("claims both recurring and one-shot schedules in the same tick", () => {
706
+ const recurring = createSchedule({
707
+ name: "Recurring",
708
+ cronExpression: "* * * * *",
709
+ message: "recurring",
710
+ syntax: "cron",
711
+ });
712
+ getRawDb().run("UPDATE cron_jobs SET next_run_at = ? WHERE id = ?", [
713
+ Date.now() - 1000,
714
+ recurring.id,
715
+ ]);
716
+
717
+ createSchedule({
718
+ name: "One-shot",
719
+ message: "one-shot",
720
+ nextRunAt: Date.now() - 1000,
721
+ });
722
+
723
+ const claimed = claimDueSchedules(Date.now());
724
+ expect(claimed.length).toBe(2);
725
+ const expressions = claimed.map((c) => c.expression);
726
+ expect(expressions).toContain(null); // one-shot
727
+ expect(expressions.some(Boolean)).toBe(true); // recurring
728
+ });
729
+ });
730
+
731
+ // ── One-shot lifecycle (complete, fail, cancel) ─────────────────────
732
+
733
+ describe("completeOneShot", () => {
734
+ beforeEach(() => {
735
+ const db = getDb();
736
+ db.run("DELETE FROM cron_runs");
737
+ db.run("DELETE FROM cron_jobs");
738
+ });
739
+
740
+ test("transitions firing -> fired", () => {
741
+ const job = createSchedule({
742
+ name: "Complete me",
743
+ message: "done",
744
+ nextRunAt: Date.now() - 1000,
745
+ });
746
+
747
+ // Claim first to get to 'firing' state
748
+ claimDueSchedules(Date.now());
749
+
750
+ completeOneShot(job.id);
751
+
752
+ const retrieved = getSchedule(job.id);
753
+ expect(retrieved!.status).toBe("fired");
754
+ expect(retrieved!.enabled).toBe(false);
755
+ });
756
+
757
+ test("does not transition if not in firing state", () => {
758
+ const job = createSchedule({
759
+ name: "Not firing",
760
+ message: "still active",
761
+ nextRunAt: Date.now() + 60_000,
762
+ });
763
+
764
+ completeOneShot(job.id);
765
+
766
+ const retrieved = getSchedule(job.id);
767
+ expect(retrieved!.status).toBe("active"); // unchanged
768
+ expect(retrieved!.enabled).toBe(true);
769
+ });
770
+ });
771
+
772
+ describe("failOneShot", () => {
773
+ beforeEach(() => {
774
+ const db = getDb();
775
+ db.run("DELETE FROM cron_runs");
776
+ db.run("DELETE FROM cron_jobs");
777
+ });
778
+
779
+ test("transitions firing -> active for retry", () => {
780
+ const job = createSchedule({
781
+ name: "Fail me",
782
+ message: "retry",
783
+ nextRunAt: Date.now() - 1000,
784
+ });
785
+
786
+ // Claim to get to 'firing'
787
+ claimDueSchedules(Date.now());
788
+
789
+ failOneShot(job.id);
790
+
791
+ const retrieved = getSchedule(job.id);
792
+ expect(retrieved!.status).toBe("active");
793
+ expect(retrieved!.enabled).toBe(true); // still enabled for retry
794
+ });
795
+
796
+ test("can be re-claimed after failing", () => {
797
+ const job = createSchedule({
798
+ name: "Retry",
799
+ message: "try again",
800
+ nextRunAt: Date.now() - 1000,
801
+ });
802
+
803
+ claimDueSchedules(Date.now());
804
+ failOneShot(job.id);
805
+
806
+ // Should be claimable again
807
+ const claimed = claimDueSchedules(Date.now());
808
+ expect(claimed.length).toBe(1);
809
+ expect(claimed[0].id).toBe(job.id);
810
+ });
811
+ });
812
+
813
+ describe("cancelSchedule", () => {
814
+ beforeEach(() => {
815
+ const db = getDb();
816
+ db.run("DELETE FROM cron_runs");
817
+ db.run("DELETE FROM cron_jobs");
818
+ });
819
+
820
+ test("cancels an active one-shot schedule", () => {
821
+ const job = createSchedule({
822
+ name: "Cancel me",
823
+ message: "never fire",
824
+ nextRunAt: Date.now() + 60_000,
825
+ });
826
+
827
+ const result = cancelSchedule(job.id);
828
+ expect(result).toBe(true);
829
+
830
+ const retrieved = getSchedule(job.id);
831
+ expect(retrieved!.status).toBe("cancelled");
832
+ expect(retrieved!.enabled).toBe(false);
833
+ });
834
+
835
+ test("returns false for non-active schedule", () => {
836
+ const job = createSchedule({
837
+ name: "Already done",
838
+ message: "completed",
839
+ nextRunAt: Date.now() - 1000,
840
+ });
841
+
842
+ // Claim and complete it
843
+ claimDueSchedules(Date.now());
844
+ completeOneShot(job.id);
845
+
846
+ const result = cancelSchedule(job.id);
847
+ expect(result).toBe(false);
848
+ });
849
+
850
+ test("cancelled schedule is not claimable", () => {
851
+ const job = createSchedule({
852
+ name: "Cancelled",
853
+ message: "should not fire",
854
+ nextRunAt: Date.now() - 1000,
855
+ });
856
+
857
+ cancelSchedule(job.id);
858
+
859
+ const claimed = claimDueSchedules(Date.now());
860
+ expect(claimed.length).toBe(0);
861
+ });
862
+ });
863
+
864
+ // ── Routing and mode round-trip ─────────────────────────────────────
865
+
866
+ describe("routing and mode fields", () => {
867
+ beforeEach(() => {
868
+ const db = getDb();
869
+ db.run("DELETE FROM cron_runs");
870
+ db.run("DELETE FROM cron_jobs");
871
+ });
872
+
873
+ test("recurring schedule defaults to execute mode and all_channels", () => {
874
+ const job = createSchedule({
875
+ name: "Defaults",
876
+ cronExpression: "0 9 * * *",
877
+ message: "check defaults",
878
+ syntax: "cron",
879
+ });
880
+
881
+ expect(job.mode).toBe("execute");
882
+ expect(job.routingIntent).toBe("all_channels");
883
+ expect(job.routingHints).toEqual({});
884
+ expect(job.status).toBe("active");
885
+ });
886
+
887
+ test("routing hints round-trip through create/read", () => {
888
+ const hints = { channels: ["slack", "discord"], priority: 1 };
889
+ const job = createSchedule({
890
+ name: "Routed",
891
+ cronExpression: "0 9 * * *",
892
+ message: "routed msg",
893
+ syntax: "cron",
894
+ routingIntent: "multi_channel",
895
+ routingHints: hints,
896
+ mode: "notify",
897
+ });
898
+
899
+ const retrieved = getSchedule(job.id);
900
+ expect(retrieved!.routingIntent).toBe("multi_channel");
901
+ expect(retrieved!.routingHints).toEqual(hints);
902
+ expect(retrieved!.mode).toBe("notify");
903
+ });
904
+
905
+ test("routing hints round-trip through DB raw query", () => {
906
+ const hints = { target: "sms" };
907
+ const job = createSchedule({
908
+ name: "Raw round-trip",
909
+ message: "check raw",
910
+ nextRunAt: Date.now() + 60_000,
911
+ routingIntent: "single_channel",
912
+ routingHints: hints,
913
+ });
914
+
915
+ const raw = getRawDb()
916
+ .query(
917
+ "SELECT mode, routing_intent, routing_hints_json, status FROM cron_jobs WHERE id = ?",
918
+ )
919
+ .get(job.id) as {
920
+ mode: string;
921
+ routing_intent: string;
922
+ routing_hints_json: string;
923
+ status: string;
924
+ } | null;
925
+ expect(raw).not.toBeNull();
926
+ expect(raw!.mode).toBe("execute");
927
+ expect(raw!.routing_intent).toBe("single_channel");
928
+ expect(JSON.parse(raw!.routing_hints_json)).toEqual(hints);
929
+ expect(raw!.status).toBe("active");
930
+ });
931
+
932
+ test("updateSchedule updates mode and routing fields", () => {
933
+ const job = createSchedule({
934
+ name: "Update routing",
935
+ cronExpression: "0 9 * * *",
936
+ message: "update routing",
937
+ syntax: "cron",
938
+ });
939
+
940
+ const updated = updateSchedule(job.id, {
941
+ mode: "notify",
942
+ routingIntent: "single_channel",
943
+ routingHints: { channel: "telegram" },
944
+ });
945
+
946
+ expect(updated).not.toBeNull();
947
+ expect(updated!.mode).toBe("notify");
948
+ expect(updated!.routingIntent).toBe("single_channel");
949
+ expect(updated!.routingHints).toEqual({ channel: "telegram" });
950
+ });
951
+ });
952
+
953
+ // ── listSchedules filters ───────────────────────────────────────────
954
+
955
+ describe("listSchedules filters", () => {
956
+ beforeEach(() => {
957
+ const db = getDb();
958
+ db.run("DELETE FROM cron_runs");
959
+ db.run("DELETE FROM cron_jobs");
960
+ });
961
+
962
+ test("oneShotOnly filter returns only one-shot schedules", () => {
963
+ createSchedule({
964
+ name: "Recurring",
965
+ cronExpression: "0 9 * * *",
966
+ message: "recurring",
967
+ syntax: "cron",
968
+ });
969
+ createSchedule({
970
+ name: "One-shot",
971
+ message: "one-shot",
972
+ nextRunAt: Date.now() + 60_000,
973
+ });
974
+
975
+ const oneShots = listSchedules({ oneShotOnly: true });
976
+ expect(oneShots.length).toBe(1);
977
+ expect(oneShots[0].name).toBe("One-shot");
978
+ expect(oneShots[0].expression).toBeNull();
979
+ });
980
+
981
+ test("recurringOnly filter returns only recurring schedules", () => {
982
+ createSchedule({
983
+ name: "Recurring",
984
+ cronExpression: "0 9 * * *",
985
+ message: "recurring",
986
+ syntax: "cron",
987
+ });
988
+ createSchedule({
989
+ name: "One-shot",
990
+ message: "one-shot",
991
+ nextRunAt: Date.now() + 60_000,
992
+ });
993
+
994
+ const recurring = listSchedules({ recurringOnly: true });
995
+ expect(recurring.length).toBe(1);
996
+ expect(recurring[0].name).toBe("Recurring");
997
+ expect(recurring[0].expression).not.toBeNull();
998
+ });
999
+ });
1000
+
1001
+ // ── describeCronExpression ──────────────────────────────────────────
1002
+
1003
+ describe("describeCronExpression", () => {
1004
+ test("returns 'One-time' for null expression", () => {
1005
+ expect(describeCronExpression(null)).toBe("One-time");
1006
+ });
1007
+
1008
+ test("returns description for valid cron expression", () => {
1009
+ expect(describeCronExpression("0 9 * * *")).toBe("Every day at 9:00 AM");
1010
+ });
1011
+ });