@vellumai/assistant 0.3.5 → 0.3.7

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 (487) hide show
  1. package/README.md +51 -0
  2. package/eslint.config.mjs +31 -0
  3. package/package.json +1 -1
  4. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  5. package/scripts/ipc/generate-swift.ts +18 -2
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
  7. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  8. package/src/__tests__/browser-manager.test.ts +1 -0
  9. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  10. package/src/__tests__/call-orchestrator.test.ts +752 -271
  11. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  12. package/src/__tests__/call-recovery.test.ts +3 -0
  13. package/src/__tests__/call-routes-http.test.ts +5 -0
  14. package/src/__tests__/call-store.test.ts +3 -0
  15. package/src/__tests__/channel-approval-routes.test.ts +1260 -85
  16. package/src/__tests__/channel-approval.test.ts +37 -0
  17. package/src/__tests__/channel-approvals.test.ts +4 -65
  18. package/src/__tests__/channel-guardian.test.ts +556 -0
  19. package/src/__tests__/channel-readiness-service.test.ts +74 -7
  20. package/src/__tests__/checker.test.ts +14 -7
  21. package/src/__tests__/clarification-resolver.test.ts +44 -24
  22. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  23. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  24. package/src/__tests__/config-schema.test.ts +12 -7
  25. package/src/__tests__/context-window-manager.test.ts +30 -2
  26. package/src/__tests__/contradiction-checker.test.ts +20 -5
  27. package/src/__tests__/credential-security-invariants.test.ts +6 -2
  28. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  29. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  30. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  31. package/src/__tests__/guardian-action-store.test.ts +123 -0
  32. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  33. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  34. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  35. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  36. package/src/__tests__/handlers-twilio-config.test.ts +126 -0
  37. package/src/__tests__/intent-routing.test.ts +2 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +228 -1
  39. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  40. package/src/__tests__/model-intents.test.ts +96 -0
  41. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  42. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  43. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  44. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  45. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  46. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  47. package/src/__tests__/qdrant-manager.test.ts +27 -20
  48. package/src/__tests__/relay-server.test.ts +779 -40
  49. package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
  50. package/src/__tests__/run-orchestrator.test.ts +20 -4
  51. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  52. package/src/__tests__/runtime-runs.test.ts +16 -0
  53. package/src/__tests__/schedule-store.test.ts +18 -4
  54. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  55. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  56. package/src/__tests__/session-agent-loop.test.ts +857 -0
  57. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  58. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  59. package/src/__tests__/session-profile-injection.test.ts +6 -0
  60. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  61. package/src/__tests__/session-queue.test.ts +6 -0
  62. package/src/__tests__/session-runtime-assembly.test.ts +237 -13
  63. package/src/__tests__/session-slash-known.test.ts +6 -0
  64. package/src/__tests__/session-slash-queue.test.ts +6 -0
  65. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  66. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  67. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  68. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  69. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  70. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  71. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  72. package/src/__tests__/skills.test.ts +2 -0
  73. package/src/__tests__/sms-messaging-provider.test.ts +2 -1
  74. package/src/__tests__/starter-task-flow.test.ts +2 -0
  75. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  76. package/src/__tests__/system-prompt.test.ts +2 -0
  77. package/src/__tests__/task-management-tools.test.ts +2 -2
  78. package/src/__tests__/task-runner.test.ts +14 -4
  79. package/src/__tests__/terminal-tools.test.ts +25 -19
  80. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  81. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  82. package/src/__tests__/tool-executor.test.ts +23 -24
  83. package/src/__tests__/trust-store.test.ts +3 -3
  84. package/src/__tests__/twilio-rest.test.ts +29 -0
  85. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  86. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  87. package/src/__tests__/twilio-routes.test.ts +141 -21
  88. package/src/__tests__/user-reference.test.ts +2 -0
  89. package/src/__tests__/voice-quality.test.ts +222 -0
  90. package/src/__tests__/web-search.test.ts +45 -29
  91. package/src/agent/loop.ts +1 -1
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  93. package/src/amazon/client.ts +1418 -0
  94. package/src/amazon/request-extractor.ts +135 -0
  95. package/src/amazon/session.ts +109 -0
  96. package/src/autonomy/autonomy-store.ts +5 -5
  97. package/src/browser-extension-relay/client.ts +124 -0
  98. package/src/browser-extension-relay/protocol.ts +63 -0
  99. package/src/browser-extension-relay/server.ts +177 -0
  100. package/src/bundler/app-bundler.ts +3 -3
  101. package/src/bundler/bundle-signer.ts +1 -1
  102. package/src/bundler/signature-verifier.ts +1 -1
  103. package/src/calls/call-conversation-messages.ts +33 -0
  104. package/src/calls/call-domain.ts +106 -5
  105. package/src/calls/call-orchestrator.ts +252 -54
  106. package/src/calls/call-pointer-messages.ts +53 -0
  107. package/src/calls/call-recovery.ts +3 -8
  108. package/src/calls/call-store.ts +69 -87
  109. package/src/calls/elevenlabs-config.ts +3 -2
  110. package/src/calls/guardian-action-sweep.ts +105 -0
  111. package/src/calls/guardian-dispatch.ts +203 -0
  112. package/src/calls/guardian-question-copy.ts +133 -0
  113. package/src/calls/relay-server.ts +466 -8
  114. package/src/calls/speaker-identification.ts +1 -1
  115. package/src/calls/twilio-config.ts +7 -5
  116. package/src/calls/twilio-provider.ts +6 -4
  117. package/src/calls/twilio-rest.ts +40 -15
  118. package/src/calls/twilio-routes.ts +60 -45
  119. package/src/calls/types.ts +3 -1
  120. package/src/channels/types.ts +25 -0
  121. package/src/cli/amazon.ts +815 -0
  122. package/src/cli/config-commands.ts +2 -2
  123. package/src/cli/core-commands.ts +4 -3
  124. package/src/cli/influencer.ts +244 -0
  125. package/src/cli/map.ts +89 -6
  126. package/src/cli.ts +1 -1
  127. package/src/config/agent-schema.ts +171 -0
  128. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  129. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  130. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  131. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  132. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  133. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  134. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  135. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  136. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  137. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  138. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  139. package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
  140. package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
  141. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  142. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  143. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  144. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  145. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  146. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  147. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  148. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
  149. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  150. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
  151. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
  152. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  153. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
  154. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
  155. package/src/config/bundled-skills/messaging/SKILL.md +12 -2
  156. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  157. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  158. package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
  159. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  160. package/src/config/bundled-tool-registry.ts +310 -0
  161. package/src/config/calls-schema.ts +181 -0
  162. package/src/config/core-schema.ts +309 -0
  163. package/src/config/defaults.ts +27 -3
  164. package/src/config/env-registry.ts +169 -0
  165. package/src/config/env.ts +175 -0
  166. package/src/config/loader.ts +6 -6
  167. package/src/config/memory-schema.ts +528 -0
  168. package/src/config/sandbox-schema.ts +55 -0
  169. package/src/config/schema.ts +157 -1138
  170. package/src/config/skill-state.ts +1 -1
  171. package/src/config/skills-schema.ts +32 -0
  172. package/src/config/skills.ts +35 -24
  173. package/src/config/system-prompt.ts +107 -56
  174. package/src/config/templates/SOUL.md +1 -1
  175. package/src/config/types.ts +1 -0
  176. package/src/config/user-reference.ts +4 -9
  177. package/src/config/vellum-skills/catalog.json +0 -7
  178. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  179. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
  180. package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
  181. package/src/context/window-manager.ts +27 -7
  182. package/src/daemon/approval-generators.ts +186 -0
  183. package/src/daemon/approved-devices-store.ts +140 -0
  184. package/src/daemon/assistant-attachments.ts +1 -1
  185. package/src/daemon/classifier.ts +35 -32
  186. package/src/daemon/config-watcher.ts +1 -1
  187. package/src/daemon/daemon-control.ts +254 -0
  188. package/src/daemon/handlers/apps.ts +2 -3
  189. package/src/daemon/handlers/config-channels.ts +158 -0
  190. package/src/daemon/handlers/config-inbox.ts +540 -0
  191. package/src/daemon/handlers/config-ingress.ts +231 -0
  192. package/src/daemon/handlers/config-integrations.ts +258 -0
  193. package/src/daemon/handlers/config-model.ts +143 -0
  194. package/src/daemon/handlers/config-parental.ts +163 -0
  195. package/src/daemon/handlers/config-scheduling.ts +172 -0
  196. package/src/daemon/handlers/config-slack.ts +92 -0
  197. package/src/daemon/handlers/config-telegram.ts +301 -0
  198. package/src/daemon/handlers/config-tools.ts +177 -0
  199. package/src/daemon/handlers/config-trust.ts +104 -0
  200. package/src/daemon/handlers/config-twilio.ts +1080 -0
  201. package/src/daemon/handlers/config.ts +53 -2463
  202. package/src/daemon/handlers/diagnostics.ts +1 -1
  203. package/src/daemon/handlers/dictation.ts +4 -6
  204. package/src/daemon/handlers/documents.ts +18 -32
  205. package/src/daemon/handlers/index.ts +9 -0
  206. package/src/daemon/handlers/misc.ts +3 -5
  207. package/src/daemon/handlers/pairing.ts +98 -0
  208. package/src/daemon/handlers/sessions.ts +74 -5
  209. package/src/daemon/handlers/shared.ts +3 -1
  210. package/src/daemon/handlers/skills.ts +1 -1
  211. package/src/daemon/handlers/twitter-auth.ts +2 -0
  212. package/src/daemon/handlers/work-items.ts +2 -2
  213. package/src/daemon/handlers/workspace-files.ts +4 -3
  214. package/src/daemon/install-cli-launchers.ts +113 -0
  215. package/src/daemon/ipc-contract/apps.ts +356 -0
  216. package/src/daemon/ipc-contract/browser.ts +74 -0
  217. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  218. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  219. package/src/daemon/ipc-contract/documents.ts +74 -0
  220. package/src/daemon/ipc-contract/inbox.ts +209 -0
  221. package/src/daemon/ipc-contract/integrations.ts +284 -0
  222. package/src/daemon/ipc-contract/memory.ts +48 -0
  223. package/src/daemon/ipc-contract/messages.ts +211 -0
  224. package/src/daemon/ipc-contract/pairing.ts +45 -0
  225. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  226. package/src/daemon/ipc-contract/schedules.ts +97 -0
  227. package/src/daemon/ipc-contract/sessions.ts +321 -0
  228. package/src/daemon/ipc-contract/shared.ts +42 -0
  229. package/src/daemon/ipc-contract/skills.ts +120 -0
  230. package/src/daemon/ipc-contract/subagents.ts +58 -0
  231. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  232. package/src/daemon/ipc-contract/trust.ts +60 -0
  233. package/src/daemon/ipc-contract/work-items.ts +225 -0
  234. package/src/daemon/ipc-contract/workspace.ts +113 -0
  235. package/src/daemon/ipc-contract-inventory.json +62 -0
  236. package/src/daemon/ipc-contract-inventory.ts +55 -29
  237. package/src/daemon/ipc-contract.ts +227 -2527
  238. package/src/daemon/ipc-protocol.ts +1 -1
  239. package/src/daemon/ipc-validate.ts +7 -0
  240. package/src/daemon/lifecycle.ts +97 -379
  241. package/src/daemon/pairing-store.ts +177 -0
  242. package/src/daemon/providers-setup.ts +43 -0
  243. package/src/daemon/ride-shotgun-handler.ts +67 -2
  244. package/src/daemon/server.ts +60 -44
  245. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  246. package/src/daemon/session-agent-loop.ts +113 -275
  247. package/src/daemon/session-dynamic-profile.ts +1 -1
  248. package/src/daemon/session-history.ts +1 -1
  249. package/src/daemon/session-media-retry.ts +1 -1
  250. package/src/daemon/session-messaging.ts +37 -2
  251. package/src/daemon/session-notifiers.ts +5 -25
  252. package/src/daemon/session-process.ts +99 -59
  253. package/src/daemon/session-queue-manager.ts +98 -4
  254. package/src/daemon/session-runtime-assembly.ts +149 -15
  255. package/src/daemon/session-surfaces.ts +26 -4
  256. package/src/daemon/session-tool-setup.ts +28 -30
  257. package/src/daemon/session-workspace.ts +1 -1
  258. package/src/daemon/session.ts +24 -1
  259. package/src/daemon/shutdown-handlers.ts +122 -0
  260. package/src/daemon/trace-emitter.ts +1 -1
  261. package/src/daemon/watch-handler.ts +36 -33
  262. package/src/doordash/cart-queries.ts +787 -0
  263. package/src/doordash/client.ts +144 -127
  264. package/src/doordash/order-queries.ts +85 -0
  265. package/src/doordash/queries.ts +10 -1308
  266. package/src/doordash/search-queries.ts +203 -0
  267. package/src/doordash/session.ts +3 -2
  268. package/src/doordash/store-queries.ts +246 -0
  269. package/src/doordash/types.ts +367 -0
  270. package/src/email/providers/agentmail.ts +2 -1
  271. package/src/email/providers/index.ts +3 -2
  272. package/src/email/service.ts +3 -2
  273. package/src/errors.ts +43 -0
  274. package/src/home-base/prebuilt/seed.ts +1 -1
  275. package/src/hooks/cli.ts +6 -5
  276. package/src/hooks/config.ts +6 -8
  277. package/src/hooks/discovery.ts +6 -5
  278. package/src/hooks/manager.ts +4 -3
  279. package/src/hooks/runner.ts +2 -2
  280. package/src/hooks/templates.ts +5 -5
  281. package/src/inbound/public-ingress-urls.ts +3 -1
  282. package/src/index.ts +4 -2
  283. package/src/influencer/client.ts +1104 -0
  284. package/src/instrument.ts +4 -3
  285. package/src/logfire.ts +4 -3
  286. package/src/memory/admin.ts +25 -35
  287. package/src/memory/attachments-store.ts +4 -7
  288. package/src/memory/channel-delivery-store.ts +30 -1
  289. package/src/memory/channel-guardian-store.ts +200 -1
  290. package/src/memory/clarification-resolver.ts +37 -33
  291. package/src/memory/conflict-store.ts +67 -61
  292. package/src/memory/contradiction-checker.ts +141 -117
  293. package/src/memory/conversation-store.ts +335 -51
  294. package/src/memory/db-connection.ts +27 -4
  295. package/src/memory/db-init.ts +121 -4
  296. package/src/memory/db.ts +14 -1
  297. package/src/memory/embedding-backend.ts +27 -5
  298. package/src/memory/embedding-ollama.ts +2 -1
  299. package/src/memory/entity-extractor.ts +38 -35
  300. package/src/memory/guardian-action-store.ts +430 -0
  301. package/src/memory/inbox-escalation-projection.ts +59 -0
  302. package/src/memory/inbox-thread-store.ts +218 -0
  303. package/src/memory/ingress-invite-store.ts +338 -0
  304. package/src/memory/ingress-member-store.ts +350 -0
  305. package/src/memory/items-extractor.ts +91 -97
  306. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  307. package/src/memory/job-handlers/media-processing.ts +11 -42
  308. package/src/memory/job-handlers/summarization.ts +32 -26
  309. package/src/memory/job-utils.ts +3 -10
  310. package/src/memory/jobs-store.ts +6 -9
  311. package/src/memory/jobs-worker.ts +51 -36
  312. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  313. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  314. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  315. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  316. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  317. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  318. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  319. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  320. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  321. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  322. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  323. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  324. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  325. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  326. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  327. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  328. package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
  329. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  330. package/src/memory/migrations/index.ts +24 -0
  331. package/src/memory/migrations/registry.ts +79 -0
  332. package/src/memory/migrations/validate-migration-state.ts +69 -0
  333. package/src/memory/qdrant-manager.ts +49 -8
  334. package/src/memory/query-builder.ts +1 -1
  335. package/src/memory/raw-query.ts +119 -0
  336. package/src/memory/recall-cache.ts +4 -1
  337. package/src/memory/retriever.ts +163 -47
  338. package/src/memory/schema-migration.ts +25 -984
  339. package/src/memory/schema.ts +130 -7
  340. package/src/memory/search/entity.ts +10 -19
  341. package/src/memory/search/lexical.ts +81 -52
  342. package/src/memory/search/ranking.ts +21 -22
  343. package/src/memory/search/semantic.ts +157 -19
  344. package/src/memory/shared-app-links-store.ts +4 -5
  345. package/src/memory/validation.ts +19 -0
  346. package/src/messaging/draft-store.ts +5 -6
  347. package/src/messaging/providers/sms/adapter.ts +3 -6
  348. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  349. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  350. package/src/messaging/providers/whatsapp/client.ts +67 -0
  351. package/src/messaging/style-analyzer.ts +5 -4
  352. package/src/messaging/thread-summarizer.ts +61 -69
  353. package/src/messaging/triage-engine.ts +62 -71
  354. package/src/migrations/config-merge.ts +53 -0
  355. package/src/migrations/data-layout.ts +68 -0
  356. package/src/migrations/data-merge.ts +33 -0
  357. package/src/migrations/hooks-merge.ts +90 -0
  358. package/src/migrations/index.ts +6 -0
  359. package/src/migrations/log.ts +23 -0
  360. package/src/migrations/skills-merge.ts +33 -0
  361. package/src/migrations/workspace-layout.ts +79 -0
  362. package/src/permissions/checker.ts +126 -11
  363. package/src/permissions/prompter.ts +14 -0
  364. package/src/permissions/shell-identity.ts +31 -1
  365. package/src/permissions/trust-store.ts +21 -1
  366. package/src/providers/anthropic/client.ts +4 -4
  367. package/src/providers/failover.ts +2 -2
  368. package/src/providers/model-intents.ts +70 -0
  369. package/src/providers/ollama/client.ts +2 -1
  370. package/src/providers/provider-send-message.ts +176 -0
  371. package/src/providers/registry.ts +71 -30
  372. package/src/providers/retry.ts +35 -1
  373. package/src/providers/types.ts +12 -1
  374. package/src/runtime/approval-conversation-turn.ts +97 -0
  375. package/src/runtime/approval-message-composer.ts +115 -5
  376. package/src/runtime/assistant-event-hub.ts +3 -1
  377. package/src/runtime/channel-approval-parser.ts +36 -2
  378. package/src/runtime/channel-approvals.ts +0 -21
  379. package/src/runtime/channel-guardian-service.ts +48 -7
  380. package/src/runtime/channel-readiness-service.ts +160 -34
  381. package/src/runtime/channel-readiness-types.ts +10 -4
  382. package/src/runtime/channel-retry-sweep.ts +184 -0
  383. package/src/runtime/guardian-context-resolver.ts +108 -0
  384. package/src/runtime/http-server.ts +289 -745
  385. package/src/runtime/http-types.ts +56 -3
  386. package/src/runtime/middleware/auth.ts +116 -0
  387. package/src/runtime/middleware/error-handler.ts +33 -0
  388. package/src/runtime/middleware/twilio-validation.ts +127 -0
  389. package/src/runtime/routes/app-routes.ts +1 -1
  390. package/src/runtime/routes/call-routes.ts +49 -6
  391. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  392. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  393. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  394. package/src/runtime/routes/channel-route-shared.ts +144 -0
  395. package/src/runtime/routes/channel-routes.ts +32 -1634
  396. package/src/runtime/routes/conversation-routes.ts +50 -7
  397. package/src/runtime/routes/events-routes.ts +2 -2
  398. package/src/runtime/routes/identity-routes.ts +126 -0
  399. package/src/runtime/routes/pairing-routes.ts +144 -0
  400. package/src/runtime/routes/run-routes.ts +15 -1
  401. package/src/runtime/run-orchestrator.ts +52 -34
  402. package/src/schedule/schedule-store.ts +36 -32
  403. package/src/schedule/scheduler.ts +3 -3
  404. package/src/security/encrypted-store.ts +5 -7
  405. package/src/security/oauth2.ts +45 -15
  406. package/src/security/parental-control-store.ts +183 -0
  407. package/src/security/secret-allowlist.ts +4 -3
  408. package/src/security/secret-scanner.ts +5 -5
  409. package/src/security/secure-keys.ts +1 -1
  410. package/src/security/token-manager.ts +3 -2
  411. package/src/services/vercel-deploy.ts +6 -2
  412. package/src/skills/tool-manifest.ts +3 -3
  413. package/src/skills/vellum-catalog-remote.ts +75 -16
  414. package/src/slack/slack-webhook.ts +2 -1
  415. package/src/swarm/orchestrator.ts +92 -1
  416. package/src/swarm/router-planner.ts +6 -9
  417. package/src/swarm/worker-prompts.ts +9 -12
  418. package/src/tasks/task-compiler.ts +19 -28
  419. package/src/tasks/task-runner.ts +1 -1
  420. package/src/tools/assets/search.ts +15 -14
  421. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  422. package/src/tools/browser/auto-navigate.ts +1 -0
  423. package/src/tools/browser/browser-execution.ts +13 -1
  424. package/src/tools/browser/browser-manager.ts +119 -4
  425. package/src/tools/browser/network-recorder.ts +5 -0
  426. package/src/tools/credentials/broker.ts +11 -2
  427. package/src/tools/credentials/metadata-store.ts +18 -14
  428. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  429. package/src/tools/credentials/vault.ts +49 -23
  430. package/src/tools/executor.ts +80 -18
  431. package/src/tools/host-terminal/cli-discover.ts +1 -1
  432. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  433. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  434. package/src/tools/network/script-proxy/server.ts +1 -1
  435. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  436. package/src/tools/network/web-fetch.ts +18 -2
  437. package/src/tools/network/web-search.ts +7 -3
  438. package/src/tools/reminder/reminder-store.ts +14 -15
  439. package/src/tools/schedule/create.ts +1 -0
  440. package/src/tools/schedule/list.ts +2 -1
  441. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  442. package/src/tools/skills/skill-script-runner.ts +24 -9
  443. package/src/tools/skills/skill-tool-factory.ts +1 -0
  444. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  445. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  446. package/src/tools/terminal/parser.ts +50 -0
  447. package/src/tools/watcher/delete.ts +6 -0
  448. package/src/tools/weather/service.ts +1 -1
  449. package/src/twitter/client.ts +190 -24
  450. package/src/twitter/session.ts +4 -3
  451. package/src/util/clipboard.ts +1 -1
  452. package/src/util/errors.ts +65 -8
  453. package/src/util/fs.ts +40 -0
  454. package/src/util/json.ts +10 -0
  455. package/src/util/log-redact.ts +189 -0
  456. package/src/util/logger.ts +25 -18
  457. package/src/util/object.ts +3 -0
  458. package/src/util/platform.ts +72 -365
  459. package/src/util/pricing.ts +1 -1
  460. package/src/util/promise-guard.ts +1 -1
  461. package/src/util/retry.ts +19 -0
  462. package/src/util/row-mapper.ts +79 -0
  463. package/src/util/silently.ts +21 -0
  464. package/src/watcher/engine.ts +5 -1
  465. package/src/watcher/provider-types.ts +20 -0
  466. package/src/watcher/providers/github.ts +156 -0
  467. package/src/watcher/providers/gmail.ts +1 -0
  468. package/src/watcher/providers/google-calendar.ts +1 -0
  469. package/src/watcher/providers/linear.ts +460 -0
  470. package/src/watcher/providers/slack.ts +1 -0
  471. package/src/work-items/work-item-runner.ts +1 -1
  472. package/src/workspace/git-service.ts +1 -1
  473. package/src/workspace/provider-commit-message-generator.ts +51 -22
  474. package/src/__tests__/call-bridge.test.ts +0 -517
  475. package/src/__tests__/session-process-bridge.test.ts +0 -244
  476. package/src/calls/call-bridge.ts +0 -168
  477. package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
  478. package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
  479. package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
  480. package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
  481. package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
  482. package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
  483. package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
  484. package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
  485. package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
  486. package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
  487. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -1,244 +0,0 @@
1
- import { describe, test, expect, beforeEach, mock } from 'bun:test';
2
- import { mkdtempSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
-
6
- const testDir = mkdtempSync(join(tmpdir(), 'session-process-bridge-test-'));
7
-
8
- // ── Platform + logger mocks ─────────────────────────────────────────
9
-
10
- mock.module('../util/platform.js', () => ({
11
- getDataDir: () => testDir,
12
- isMacOS: () => process.platform === 'darwin',
13
- isLinux: () => process.platform === 'linux',
14
- isWindows: () => process.platform === 'win32',
15
- getSocketPath: () => join(testDir, 'test.sock'),
16
- getPidPath: () => join(testDir, 'test.pid'),
17
- getDbPath: () => join(testDir, 'test.db'),
18
- getLogPath: () => join(testDir, 'test.log'),
19
- ensureDataDir: () => {},
20
- }));
21
-
22
- mock.module('../util/logger.js', () => ({
23
- getLogger: () =>
24
- new Proxy({} as Record<string, unknown>, {
25
- get: () => () => {},
26
- }),
27
- }));
28
-
29
- mock.module('../config/loader.js', () => ({
30
- getConfig: () => ({
31
- apiKeys: { anthropic: 'test-key' },
32
- model: 'claude-sonnet-4-20250514',
33
- provider: 'anthropic',
34
- memory: { enabled: false },
35
- calls: { enabled: false },
36
- contextWindow: { maxInputTokens: 200000 },
37
- }),
38
- }));
39
-
40
- // ── Mock the call bridge ─────────────────────────────────────────────
41
-
42
- import type { CallBridgeResult } from '../calls/call-bridge.js';
43
-
44
- const mockTryRouteCallMessage = mock(
45
- (_convId: string, _text: string, _msgId?: string): Promise<CallBridgeResult> =>
46
- Promise.resolve({ handled: false, reason: 'no_active_call' }),
47
- );
48
-
49
- mock.module('../calls/call-bridge.js', () => ({
50
- tryRouteCallMessage: (...args: [string, string, string?]) => mockTryRouteCallMessage(...args),
51
- }));
52
-
53
- // ── Mock slash resolution ────────────────────────────────────────────
54
-
55
- mock.module('./session-slash.js', () => ({
56
- resolveSlash: (content: string) => ({ kind: 'passthrough' as const, content }),
57
- }));
58
-
59
- // ── Import after mocks ──────────────────────────────────────────────
60
-
61
- import type { ServerMessage } from '../daemon/ipc-protocol.js';
62
- import type { ProcessSessionContext } from '../daemon/session-process.js';
63
- import { processMessage, drainQueue } from '../daemon/session-process.js';
64
- import { MessageQueue } from '../daemon/session-queue-manager.js';
65
-
66
- // ── Session mock factory ─────────────────────────────────────────────
67
-
68
- function createMockSession(overrides?: Partial<ProcessSessionContext>): ProcessSessionContext {
69
- return {
70
- conversationId: 'test-conv',
71
- messages: [],
72
- processing: false,
73
- abortController: null,
74
- currentRequestId: undefined,
75
- queue: new MessageQueue(),
76
- traceEmitter: {
77
- emit: () => {},
78
- } as unknown as ProcessSessionContext['traceEmitter'],
79
- usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
80
- persistUserMessage: mock((_content: string, _attachments: unknown[], _requestId?: string) => 'mock-msg-id'),
81
- runAgentLoop: mock(async () => {}),
82
- ...overrides,
83
- };
84
- }
85
-
86
- // ── Tests ────────────────────────────────────────────────────────────
87
-
88
- describe('session-process bridge consumption', () => {
89
- beforeEach(() => {
90
- mockTryRouteCallMessage.mockReset();
91
- });
92
-
93
- // ── Direct processMessage path ───────────────────────────────
94
-
95
- test('processMessage emits assistant_text_delta + message_complete when bridge consumes with userFacingText', async () => {
96
- mockTryRouteCallMessage.mockResolvedValue({
97
- handled: true,
98
- userFacingText: 'Instruction relayed to active call.',
99
- });
100
-
101
- const events: ServerMessage[] = [];
102
- const onEvent = (msg: ServerMessage) => events.push(msg);
103
- const session = createMockSession();
104
-
105
- await processMessage(session, 'ask about pricing', [], onEvent);
106
-
107
- // Should have emitted text delta then message_complete
108
- const textDelta = events.find((e) => e.type === 'assistant_text_delta');
109
- expect(textDelta).toBeDefined();
110
- expect((textDelta as { text: string }).text).toBe('Instruction relayed to active call.');
111
-
112
- const complete = events.find((e) => e.type === 'message_complete');
113
- expect(complete).toBeDefined();
114
-
115
- // Should NOT have called runAgentLoop
116
- expect(session.runAgentLoop).not.toHaveBeenCalled();
117
- });
118
-
119
- test('processMessage emits failure text when bridge consumes with failure userFacingText', async () => {
120
- mockTryRouteCallMessage.mockResolvedValue({
121
- handled: true,
122
- reason: 'instruction_relay_failed',
123
- userFacingText: 'Failed to relay instruction to the active call.',
124
- });
125
-
126
- const events: ServerMessage[] = [];
127
- const onEvent = (msg: ServerMessage) => events.push(msg);
128
- const session = createMockSession();
129
-
130
- await processMessage(session, 'change the topic', [], onEvent);
131
-
132
- const textDelta = events.find((e) => e.type === 'assistant_text_delta');
133
- expect(textDelta).toBeDefined();
134
- expect((textDelta as { text: string }).text).toBe('Failed to relay instruction to the active call.');
135
-
136
- const complete = events.find((e) => e.type === 'message_complete');
137
- expect(complete).toBeDefined();
138
-
139
- // Only one message_complete
140
- const completeCount = events.filter((e) => e.type === 'message_complete').length;
141
- expect(completeCount).toBe(1);
142
-
143
- expect(session.runAgentLoop).not.toHaveBeenCalled();
144
- });
145
-
146
- test('processMessage skips text delta when bridge consumes without userFacingText', async () => {
147
- mockTryRouteCallMessage.mockResolvedValue({
148
- handled: true,
149
- });
150
-
151
- const events: ServerMessage[] = [];
152
- const onEvent = (msg: ServerMessage) => events.push(msg);
153
- const session = createMockSession();
154
-
155
- await processMessage(session, 'hello', [], onEvent);
156
-
157
- const textDelta = events.find((e) => e.type === 'assistant_text_delta');
158
- expect(textDelta).toBeUndefined();
159
-
160
- const complete = events.find((e) => e.type === 'message_complete');
161
- expect(complete).toBeDefined();
162
-
163
- expect(session.runAgentLoop).not.toHaveBeenCalled();
164
- });
165
-
166
- test('processMessage falls through to agent loop when bridge does not consume', async () => {
167
- mockTryRouteCallMessage.mockResolvedValue({
168
- handled: false,
169
- reason: 'no_active_call',
170
- });
171
-
172
- const events: ServerMessage[] = [];
173
- const onEvent = (msg: ServerMessage) => events.push(msg);
174
- const session = createMockSession();
175
-
176
- await processMessage(session, 'normal message', [], onEvent);
177
-
178
- expect(session.runAgentLoop).toHaveBeenCalled();
179
- });
180
-
181
- // ── Queued routeOrProcess path ───────────────────────────────
182
-
183
- test('drainQueue emits assistant_text_delta + message_complete for bridge-consumed queued message', async () => {
184
- mockTryRouteCallMessage.mockResolvedValue({
185
- handled: true,
186
- userFacingText: 'Instruction relayed to active call.',
187
- });
188
-
189
- const events: ServerMessage[] = [];
190
- const onEvent = (msg: ServerMessage) => events.push(msg);
191
- const session = createMockSession({ processing: true });
192
-
193
- // Enqueue a message
194
- session.queue.push({
195
- content: 'ask about pricing',
196
- attachments: [],
197
- requestId: 'req-1',
198
- onEvent,
199
- });
200
-
201
- drainQueue(session);
202
-
203
- // Wait for async routeOrProcess
204
- await new Promise((r) => setTimeout(r, 50));
205
-
206
- const textDelta = events.find((e) => e.type === 'assistant_text_delta');
207
- expect(textDelta).toBeDefined();
208
- expect((textDelta as { text: string }).text).toBe('Instruction relayed to active call.');
209
-
210
- // message_complete (from dequeue + bridge consumption — only one expected for this request)
211
- const completeEvents = events.filter((e) => e.type === 'message_complete');
212
- expect(completeEvents.length).toBe(1);
213
-
214
- expect(session.runAgentLoop).not.toHaveBeenCalled();
215
- });
216
-
217
- test('drainQueue emits failure text for bridge-consumed queued message with relay failure', async () => {
218
- mockTryRouteCallMessage.mockResolvedValue({
219
- handled: true,
220
- reason: 'instruction_relay_failed',
221
- userFacingText: 'Failed to relay instruction to the active call.',
222
- });
223
-
224
- const events: ServerMessage[] = [];
225
- const onEvent = (msg: ServerMessage) => events.push(msg);
226
- const session = createMockSession({ processing: true });
227
-
228
- session.queue.push({
229
- content: 'change the topic',
230
- attachments: [],
231
- requestId: 'req-2',
232
- onEvent,
233
- });
234
-
235
- drainQueue(session);
236
- await new Promise((r) => setTimeout(r, 50));
237
-
238
- const textDelta = events.find((e) => e.type === 'assistant_text_delta');
239
- expect(textDelta).toBeDefined();
240
- expect((textDelta as { text: string }).text).toBe('Failed to relay instruction to the active call.');
241
-
242
- expect(session.runAgentLoop).not.toHaveBeenCalled();
243
- });
244
- });
@@ -1,168 +0,0 @@
1
- /**
2
- * Call message bridge: intercepts user messages in-thread and routes them
3
- * to the live call orchestrator — either as answers to pending questions
4
- * or as mid-call steering instructions.
5
- *
6
- * Decision priority:
7
- * 1. If a pending question exists → answer path (existing behavior).
8
- * 2. If no pending question but an active call exists → instruction path.
9
- *
10
- * When the bridge consumes a message it returns `{ handled: true }` so
11
- * the caller can skip agent processing.
12
- */
13
-
14
- import { getLogger } from '../util/logger.js';
15
- import {
16
- getActiveCallSessionForConversation,
17
- getPendingQuestion,
18
- answerPendingQuestion,
19
- recordCallEvent,
20
- getCallSession,
21
- } from './call-store.js';
22
- import { getCallOrchestrator } from './call-state.js';
23
- import { relayInstruction } from './call-domain.js';
24
- import * as conversationStore from '../memory/conversation-store.js';
25
-
26
- const log = getLogger('call-bridge');
27
-
28
- export interface CallBridgeResult {
29
- handled: boolean;
30
- reason?: string;
31
- /** User-facing text persisted in-thread by the bridge (success ack or failure notice). */
32
- userFacingText?: string;
33
- }
34
-
35
- /**
36
- * Attempt to route a user message to an active call — as an answer to
37
- * a pending question (priority) or as a mid-call steering instruction.
38
- *
39
- * @param conversationId - The conversation the message belongs to.
40
- * @param userText - The user's message text.
41
- * @param _userMessageId - The persisted message ID (reserved for future use).
42
- * @returns `{ handled: true }` if the message was consumed by the call system,
43
- * `{ handled: false, reason }` otherwise.
44
- */
45
- export async function tryRouteCallMessage(
46
- conversationId: string,
47
- userText: string,
48
- _userMessageId?: string,
49
- ): Promise<CallBridgeResult> {
50
- // 1. Find an active call for this conversation
51
- const callSession = getActiveCallSessionForConversation(conversationId);
52
- if (!callSession) {
53
- return { handled: false, reason: 'no_active_call' };
54
- }
55
-
56
- // 2. Check for a pending question — answer path takes priority
57
- const pendingQuestion = getPendingQuestion(callSession.id);
58
- if (pendingQuestion) {
59
- return handleAnswer(conversationId, callSession.id, pendingQuestion, userText);
60
- }
61
-
62
- // 3. No pending question — instruction path
63
- return handleInstruction(conversationId, callSession.id, userText);
64
- }
65
-
66
- /** @deprecated Use `tryRouteCallMessage` instead. */
67
- export const tryHandlePendingCallAnswer = tryRouteCallMessage;
68
-
69
- // ── Answer path ─────────────────────────────────────────────────────
70
-
71
- async function handleAnswer(
72
- conversationId: string,
73
- callSessionId: string,
74
- pendingQuestion: { id: string; questionText: string },
75
- userText: string,
76
- ): Promise<CallBridgeResult> {
77
- // Empty text (e.g. attachment-only messages) should not be consumed as
78
- // an answer — fall through to normal processing so attachments are handled.
79
- if (!userText.trim()) {
80
- return { handled: false, reason: 'empty_answer_text' };
81
- }
82
-
83
- const orchestrator = getCallOrchestrator(callSessionId);
84
- if (!orchestrator) {
85
- // The call may have ended between the question being asked and the
86
- // user replying. Persist a follow-up message so the user knows.
87
- const freshSession = getCallSession(callSessionId);
88
- const ended = freshSession && (freshSession.status === 'completed' || freshSession.status === 'failed');
89
- if (ended) {
90
- conversationStore.addMessage(
91
- conversationId,
92
- 'assistant',
93
- JSON.stringify([{
94
- type: 'text',
95
- text: 'The call ended before your answer could be relayed to the caller.',
96
- }]),
97
- );
98
- }
99
- return { handled: false, reason: 'orchestrator_not_found' };
100
- }
101
-
102
- if (orchestrator.getState() !== 'waiting_on_user') {
103
- return { handled: false, reason: 'orchestrator_not_waiting' };
104
- }
105
-
106
- const accepted = await orchestrator.handleUserAnswer(userText);
107
- if (!accepted) {
108
- return { handled: false, reason: 'orchestrator_rejected' };
109
- }
110
-
111
- answerPendingQuestion(pendingQuestion.id, userText);
112
- recordCallEvent(callSessionId, 'user_answered', { answer: userText });
113
-
114
- log.info(
115
- { conversationId, callSessionId, questionId: pendingQuestion.id },
116
- 'User reply routed as call answer via bridge',
117
- );
118
-
119
- return { handled: true };
120
- }
121
-
122
- // ── Instruction path ────────────────────────────────────────────────
123
-
124
- async function handleInstruction(
125
- conversationId: string,
126
- callSessionId: string,
127
- userText: string,
128
- ): Promise<CallBridgeResult> {
129
- // Empty text (e.g. attachment-only messages) should not be relayed —
130
- // fall through to normal processing so attachments are handled.
131
- if (!userText.trim()) {
132
- return { handled: false, reason: 'empty_instruction_text' };
133
- }
134
-
135
- const result = await relayInstruction({ callSessionId, instructionText: userText });
136
-
137
- if (!result.ok) {
138
- log.warn(
139
- { conversationId, callSessionId, error: result.error },
140
- 'Instruction relay failed via bridge',
141
- );
142
-
143
- const failureText = 'Failed to relay instruction to the active call.';
144
- conversationStore.addMessage(
145
- conversationId,
146
- 'assistant',
147
- JSON.stringify([{ type: 'text', text: failureText }]),
148
- );
149
-
150
- // Consumed: caller should NOT fall through to the agent loop
151
- return { handled: true, reason: 'instruction_relay_failed', userFacingText: failureText };
152
- }
153
-
154
- // Persist a concise acknowledgement so the user sees confirmation
155
- const ackText = 'Instruction relayed to active call.';
156
- conversationStore.addMessage(
157
- conversationId,
158
- 'assistant',
159
- JSON.stringify([{ type: 'text', text: ackText }]),
160
- );
161
-
162
- log.info(
163
- { conversationId, callSessionId },
164
- 'User message routed as call instruction via bridge',
165
- );
166
-
167
- return { handled: true, userFacingText: ackText };
168
- }
@@ -1,137 +0,0 @@
1
- /**
2
- * Generic capability registry with tier-based classification.
3
- *
4
- * The registry is domain-agnostic: any domain (sports, surveillance, lecture
5
- * recording, etc.) can register its own capabilities. Basketball-specific
6
- * capabilities are registered as one example via `registerDefaults()`.
7
- */
8
-
9
- import type { CapabilityTier } from '../../../../memory/media-store.js';
10
-
11
- // ---------------------------------------------------------------------------
12
- // Types
13
- // ---------------------------------------------------------------------------
14
-
15
- export interface Capability {
16
- /** Unique name used as the key in tracking profiles (e.g. 'turnover'). */
17
- name: string;
18
- /** Human-readable description of what this capability detects/tracks. */
19
- description: string;
20
- /** Maturity tier governing confidence disclaimers and default inclusion. */
21
- tier: CapabilityTier;
22
- /** Domain this capability belongs to (e.g. 'basketball', 'surveillance'). */
23
- domain: string;
24
- /** Granularity level (e.g. 'team', 'per-player'). */
25
- granularity?: string;
26
- }
27
-
28
- // ---------------------------------------------------------------------------
29
- // Registry (singleton in-memory Map)
30
- // ---------------------------------------------------------------------------
31
-
32
- const registry = new Map<string, Capability>();
33
-
34
- /**
35
- * Register a capability. Overwrites any existing capability with the same name.
36
- */
37
- export function registerCapability(cap: Capability): void {
38
- registry.set(cap.name, cap);
39
- }
40
-
41
- /**
42
- * Get all registered capabilities, optionally filtered by domain.
43
- */
44
- export function getCapabilities(domain?: string): Capability[] {
45
- const all = Array.from(registry.values());
46
- if (!domain) return all;
47
- return all.filter((c) => c.domain === domain);
48
- }
49
-
50
- /**
51
- * Get capabilities filtered by tier.
52
- */
53
- export function getCapabilitiesByTier(tier: CapabilityTier): Capability[] {
54
- return Array.from(registry.values()).filter((c) => c.tier === tier);
55
- }
56
-
57
- /**
58
- * Look up a single capability by name.
59
- */
60
- export function getCapabilityByName(name: string): Capability | undefined {
61
- return registry.get(name);
62
- }
63
-
64
- /**
65
- * Get all unique domain names in the registry.
66
- */
67
- export function getRegisteredDomains(): string[] {
68
- const domains = new Set<string>();
69
- for (const cap of registry.values()) {
70
- domains.add(cap.domain);
71
- }
72
- return Array.from(domains);
73
- }
74
-
75
- // ---------------------------------------------------------------------------
76
- // Default registrations — basketball as one example domain
77
- // ---------------------------------------------------------------------------
78
-
79
- /**
80
- * Register the default basketball capabilities as an example domain.
81
- * Other domains should call `registerCapability()` with their own entries.
82
- */
83
- export function registerDefaults(): void {
84
- // Ready tier: production-quality detection
85
- registerCapability({
86
- name: 'turnover',
87
- description: 'Team-level turnover detection',
88
- tier: 'ready',
89
- domain: 'basketball',
90
- granularity: 'team',
91
- });
92
-
93
- // Beta tier: functional but may have accuracy gaps
94
- registerCapability({
95
- name: 'field_goal',
96
- description: 'Team-level field goal detection',
97
- tier: 'beta',
98
- domain: 'basketball',
99
- granularity: 'team',
100
- });
101
-
102
- registerCapability({
103
- name: 'rebound',
104
- description: 'Team-level rebound detection',
105
- tier: 'beta',
106
- domain: 'basketball',
107
- granularity: 'team',
108
- });
109
-
110
- registerCapability({
111
- name: 'turnover_per_player',
112
- description: 'Per-player turnover attribution',
113
- tier: 'beta',
114
- domain: 'basketball',
115
- granularity: 'per-player',
116
- });
117
-
118
- // Experimental tier: early-stage, expect noise
119
- registerCapability({
120
- name: 'field_goal_per_player',
121
- description: 'Per-player field goal attribution',
122
- tier: 'experimental',
123
- domain: 'basketball',
124
- granularity: 'per-player',
125
- });
126
-
127
- registerCapability({
128
- name: 'rebound_per_player',
129
- description: 'Per-player rebound attribution',
130
- tier: 'experimental',
131
- domain: 'basketball',
132
- granularity: 'per-player',
133
- });
134
- }
135
-
136
- // Auto-register defaults on first import
137
- registerDefaults();