@desplega.ai/agent-swarm 1.158.0 → 1.160.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
  3. package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
  4. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
  5. package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
  6. package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
  7. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
  8. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
  9. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
  10. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
  11. package/dist/boot-seeds-gsetbs5y.js +28 -0
  12. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
  13. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
  14. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
  15. package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
  16. package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
  17. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  18. package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
  19. package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
  20. package/dist/cli-0x01kwrd.js +491 -0
  21. package/dist/cli-0xqde53b.js +176 -0
  22. package/dist/cli-10nhj6xq.js +8355 -0
  23. package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
  24. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  25. package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
  26. package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
  27. package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
  28. package/dist/cli-3qhyh31j.js +166 -0
  29. package/dist/cli-447dt1h3.js +3828 -0
  30. package/dist/cli-4derpgyk.js +115 -0
  31. package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
  32. package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
  33. package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
  34. package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
  35. package/dist/cli-741yb0xx.js +1027 -0
  36. package/dist/cli-74h9hscv.js +69 -0
  37. package/dist/cli-7cxw8b60.js +14910 -0
  38. package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
  39. package/dist/cli-7kyk9jr3.js +22 -0
  40. package/dist/cli-89s4ngw3.js +183 -0
  41. package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
  42. package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
  43. package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
  44. package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
  45. package/dist/cli-br0qdrnp.js +2150 -0
  46. package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
  47. package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
  48. package/dist/cli-cpvsaqsw.js +333 -0
  49. package/dist/cli-d5czme6m.js +17805 -0
  50. package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
  51. package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
  52. package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
  53. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  54. package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
  55. package/dist/cli-gt4hxb8p.js +99 -0
  56. package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
  57. package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
  58. package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
  59. package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
  60. package/dist/cli-kmcpfwn2.js +333856 -0
  61. package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
  62. package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
  63. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  64. package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
  65. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  66. package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
  67. package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
  68. package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
  69. package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
  70. package/dist/cli-rb9m6rpe.js +4980 -0
  71. package/dist/cli-rykfmgwg.js +102 -0
  72. package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
  73. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  74. package/dist/cli-tfky2838.js +756 -0
  75. package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
  76. package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
  77. package/dist/cli-trc24wk2.js +143 -0
  78. package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
  79. package/dist/cli-v7fn5gms.js +1425 -0
  80. package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
  81. package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
  82. package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
  83. package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
  84. package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
  85. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  86. package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
  87. package/dist/cli-zpep9q5e.js +491 -0
  88. package/dist/cli.js +41 -32
  89. package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
  90. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
  91. package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
  92. package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
  93. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
  94. package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
  95. package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
  96. package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
  97. package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
  98. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
  99. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  100. package/dist/execute-6e7qeyk4.js +1017 -0
  101. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
  102. package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
  103. package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
  104. package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
  105. package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
  106. package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
  107. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  108. package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
  109. package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
  110. package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
  111. package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
  112. package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
  113. package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
  114. package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
  115. package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
  116. package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
  117. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
  118. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
  119. package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
  120. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
  121. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
  122. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
  123. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
  124. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
  125. package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
  126. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  127. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
  128. package/dist/pricing-refresh-wx0tp7cb.js +39 -0
  129. package/dist/quickjs-r1pq2107.wasm +0 -0
  130. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
  131. package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
  132. package/dist/runtime-zyssgse0.js +24 -0
  133. package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
  134. package/dist/typesafe-system-one-2ef30pec.js +27 -0
  135. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
  136. package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
  137. package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
  138. package/openapi.json +1314 -91
  139. package/package.json +12 -11
  140. package/src/be/db/agents.ts +20 -0
  141. package/src/be/db/api-keys.ts +70 -0
  142. package/src/be/db/tasks/human-free.ts +442 -0
  143. package/src/be/db/tasks/read.ts +56 -1
  144. package/src/be/db/tasks/write.ts +107 -11
  145. package/src/be/db.ts +274 -188
  146. package/src/be/harness-model-support.ts +182 -0
  147. package/src/be/human-free-drain.ts +67 -0
  148. package/src/be/memory/providers/sqlite-store.ts +51 -15
  149. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  150. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  151. package/src/be/migrations/184_model_catalog.sql +120 -0
  152. package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
  153. package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
  154. package/src/be/model-catalog-store.ts +644 -0
  155. package/src/be/model-tier-keys.ts +46 -0
  156. package/src/be/model-tier-resolution.ts +534 -0
  157. package/src/be/model-validation.ts +188 -0
  158. package/src/be/models-catalog.ts +61 -7
  159. package/src/be/modelsdev-cache.json +82 -0
  160. package/src/be/modelsdev-cache.ts +2 -0
  161. package/src/be/pricing-refresh.ts +154 -12
  162. package/src/be/scripts/typecheck.ts +15 -0
  163. package/src/be/seed/runner.ts +18 -12
  164. package/src/be/seed/types.ts +1 -0
  165. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  166. package/src/be/swarm-config-guard.ts +8 -0
  167. package/src/cli.tsx +10 -0
  168. package/src/commands/claude-managed-setup.ts +3 -1
  169. package/src/commands/codex-login.ts +67 -0
  170. package/src/commands/credential-outcome-report.ts +191 -0
  171. package/src/commands/rate-limit-outcome.ts +34 -4
  172. package/src/commands/runner.ts +357 -186
  173. package/src/commands/seat-mismatch-report.ts +46 -0
  174. package/src/extensions/apply-task-create.ts +27 -1
  175. package/src/extensions/contract-types.generated.ts +1 -1
  176. package/src/heartbeat/heartbeat.ts +79 -17
  177. package/src/heartbeat/templates.ts +2 -2
  178. package/src/http/agents.ts +62 -1
  179. package/src/http/api-keys.ts +140 -2
  180. package/src/http/codex-oauth-keep-warm.ts +3 -5
  181. package/src/http/index.ts +8 -0
  182. package/src/http/memory.ts +12 -5
  183. package/src/http/models-catalog.ts +357 -8
  184. package/src/http/poll.ts +54 -3
  185. package/src/http/schedules.ts +51 -6
  186. package/src/http/script-runs.ts +12 -0
  187. package/src/http/session-data.ts +2 -5
  188. package/src/http/stats.ts +6 -8
  189. package/src/http/status.ts +15 -1
  190. package/src/http/tasks.ts +90 -7
  191. package/src/http/usage-cache.ts +56 -15
  192. package/src/http/workflows.ts +46 -8
  193. package/src/mcp-client/http-client.ts +5 -0
  194. package/src/memory/recall-query.ts +74 -0
  195. package/src/prompts/base-prompt.ts +15 -4
  196. package/src/prompts/session-templates.ts +23 -1
  197. package/src/providers/acp-adapter.ts +1 -0
  198. package/src/providers/claude-adapter.ts +14 -5
  199. package/src/providers/claude-managed-adapter.ts +1 -0
  200. package/src/providers/claude-managed-models.ts +47 -161
  201. package/src/providers/claude-sdk-session.ts +3 -1
  202. package/src/providers/codex-adapter.ts +14 -14
  203. package/src/providers/codex-models.ts +65 -198
  204. package/src/providers/devin-adapter.ts +1 -0
  205. package/src/providers/dsh-adapter.ts +2 -1
  206. package/src/providers/harness-version.ts +83 -7
  207. package/src/providers/opencode-adapter.ts +53 -1
  208. package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
  209. package/src/providers/pi-codemode-runtime.ts +17 -0
  210. package/src/providers/pi-mono-adapter.ts +361 -83
  211. package/src/providers/pi-mono-extension.ts +16 -1
  212. package/src/providers/reasoning-effort.ts +44 -140
  213. package/src/providers/types.ts +8 -0
  214. package/src/rbac/legacy-policy.ts +43 -0
  215. package/src/rbac/permissions.ts +15 -0
  216. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  217. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  218. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  219. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  220. package/src/server.ts +6 -0
  221. package/src/slack/assistant.ts +13 -0
  222. package/src/slack/message-text.ts +56 -2
  223. package/src/slack/render-v2.ts +87 -37
  224. package/src/slack/session-status.ts +541 -0
  225. package/src/slack/thread-buffer.ts +10 -2
  226. package/src/tasks/sibling-awareness.ts +3 -2
  227. package/src/telemetry.ts +5 -4
  228. package/src/templates.d.ts +6 -0
  229. package/src/tests/agents-list-model-display.test.ts +4 -6
  230. package/src/tests/api-key-auth-failure-route.test.ts +142 -0
  231. package/src/tests/api-key-tracking.test.ts +368 -1
  232. package/src/tests/base-prompt.test.ts +43 -2
  233. package/src/tests/claude-adapter.test.ts +68 -0
  234. package/src/tests/claude-managed-adapter.test.ts +12 -18
  235. package/src/tests/codex-adapter.test.ts +2 -1
  236. package/src/tests/codex-auth-failure.test.ts +52 -0
  237. package/src/tests/codex-gpt6-release.test.ts +66 -5
  238. package/src/tests/codex-login.test.ts +116 -0
  239. package/src/tests/context-window.test.ts +7 -5
  240. package/src/tests/credential-exhaustion-policy.test.ts +118 -3
  241. package/src/tests/credential-outcome-report.test.ts +171 -0
  242. package/src/tests/credential-status-api.test.ts +103 -2
  243. package/src/tests/db-extraction-contract.test.ts +1 -0
  244. package/src/tests/db-task-read-contract.test.ts +10 -1
  245. package/src/tests/db-task-write-contract.test.ts +535 -2
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/dokploy-deploy.test.ts +315 -0
  248. package/src/tests/dsh-adapter.test.ts +1 -1
  249. package/src/tests/explicit-model-validation.test.ts +583 -0
  250. package/src/tests/extensions-pre-task.test.ts +73 -0
  251. package/src/tests/fetch-resolved-env.test.ts +46 -0
  252. package/src/tests/hang-watchdog-worker.ts +47 -0
  253. package/src/tests/hang-watchdog.test.ts +45 -0
  254. package/src/tests/hang-watchdog.ts +30 -0
  255. package/src/tests/harness-model-guard.test.ts +123 -0
  256. package/src/tests/harness-model-support.test.ts +374 -0
  257. package/src/tests/harness-version.test.ts +70 -3
  258. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  259. package/src/tests/heartbeat-checklist.test.ts +4 -2
  260. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  261. package/src/tests/http-task-write-ownership.test.ts +172 -0
  262. package/src/tests/human-free-flag.test.ts +279 -0
  263. package/src/tests/human-free-oracle.ts +57 -0
  264. package/src/tests/human-free-reclassify.test.ts +669 -0
  265. package/src/tests/memory-fts-populate.test.ts +139 -0
  266. package/src/tests/memory-http-recall-gating.test.ts +125 -1
  267. package/src/tests/migration-046-budgets.test.ts +3 -3
  268. package/src/tests/model-catalog-migration.test.ts +134 -0
  269. package/src/tests/model-catalog-table.test.ts +249 -0
  270. package/src/tests/model-catalog-write-access.test.ts +387 -0
  271. package/src/tests/model-rate-limit-windows.test.ts +19 -0
  272. package/src/tests/model-tier-resolution.test.ts +611 -0
  273. package/src/tests/models-catalog.test.ts +1 -1
  274. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  275. package/src/tests/opencode-adapter.test.ts +157 -2
  276. package/src/tests/package-publish.test.ts +137 -36
  277. package/src/tests/pi-codemode.test.ts +246 -0
  278. package/src/tests/pi-mono-adapter.test.ts +3 -0
  279. package/src/tests/pi-native-mcp.test.ts +193 -0
  280. package/src/tests/pi-tool-exposure.test.ts +374 -0
  281. package/src/tests/preload.ts +3 -0
  282. package/src/tests/pricing-routes.test.ts +2 -2
  283. package/src/tests/prompt-template-session.test.ts +5 -3
  284. package/src/tests/rate-limit-event.test.ts +65 -0
  285. package/src/tests/rate-limit-outcome.test.ts +90 -0
  286. package/src/tests/rbac-engine.test.ts +77 -3
  287. package/src/tests/reasoning-effort.test.ts +109 -0
  288. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  289. package/src/tests/runner-key-completion-outcome.test.ts +112 -0
  290. package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
  291. package/src/tests/runner-registration-retry.test.ts +149 -0
  292. package/src/tests/runtime-model-catalog.test.ts +86 -0
  293. package/src/tests/script-connections.test.ts +9 -0
  294. package/src/tests/seat-mismatch-report.test.ts +85 -0
  295. package/src/tests/seed-scripts.test.ts +138 -0
  296. package/src/tests/seed.test.ts +25 -0
  297. package/src/tests/session-costs.test.ts +14 -11
  298. package/src/tests/slack-message-text.test.ts +101 -0
  299. package/src/tests/slack-render-v2.test.ts +96 -0
  300. package/src/tests/slack-session-status.test.ts +626 -0
  301. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  302. package/src/tests/status.test.ts +29 -0
  303. package/src/tests/steering-promotion.test.ts +51 -0
  304. package/src/tests/store-progress-ownership.test.ts +136 -0
  305. package/src/tests/subscription-plans.test.ts +28 -0
  306. package/src/tests/task-cascade-fail.test.ts +148 -2
  307. package/src/tests/task-citations.test.ts +3 -2
  308. package/src/tests/tool-annotations.test.ts +1 -1
  309. package/src/tests/usage-cache.test.ts +166 -0
  310. package/src/tests/workflow-agent-task.test.ts +30 -0
  311. package/src/tests/workflow-executors.test.ts +5 -2
  312. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  313. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  314. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  315. package/src/tests/workflow-triggers-v2.test.ts +320 -0
  316. package/src/tools/model-catalog/index.ts +137 -0
  317. package/src/tools/schedules/create-schedule.ts +17 -2
  318. package/src/tools/schedules/patch-schedule.ts +31 -1
  319. package/src/tools/schedules/update-schedule.ts +31 -1
  320. package/src/tools/send-task.ts +18 -1
  321. package/src/tools/store-progress.ts +49 -4
  322. package/src/tools/task-action.ts +14 -1
  323. package/src/tools/tool-config.ts +3 -1
  324. package/src/tools/workflows/create-workflow.ts +17 -4
  325. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  326. package/src/tools/workflows/patch-workflow.ts +9 -2
  327. package/src/tools/workflows/update-workflow.ts +17 -4
  328. package/src/types.ts +41 -1
  329. package/src/utils/codex-auth-failure.ts +34 -0
  330. package/src/utils/context-window.ts +47 -53
  331. package/src/utils/credentials.ts +72 -30
  332. package/src/utils/error-tracker.ts +80 -0
  333. package/src/utils/harness-cli-version.ts +115 -0
  334. package/src/utils/harness-model-error.ts +33 -0
  335. package/src/utils/model-rate-limit-windows.ts +12 -0
  336. package/src/utils/runtime-model-catalog.ts +152 -0
  337. package/src/utils/spawn-model-guard.ts +43 -0
  338. package/src/utils/subscription-plans.ts +22 -0
  339. package/src/workflows/approval-resolution.ts +39 -0
  340. package/src/workflows/definition.ts +7 -0
  341. package/src/workflows/engine.ts +69 -1
  342. package/src/workflows/executors/agent-task.ts +16 -6
  343. package/src/workflows/executors/base.ts +53 -0
  344. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  345. package/src/workflows/executors/index.ts +1 -0
  346. package/src/workflows/executors/registry.ts +2 -0
  347. package/src/workflows/executors/system-one-decision.ts +1232 -0
  348. package/src/workflows/executors/system-one-providers.ts +301 -0
  349. package/src/workflows/executors/workflow-llm.ts +13 -1
  350. package/src/workflows/model-validation.ts +45 -0
  351. package/src/workflows/patch-definition.ts +5 -0
  352. package/src/workflows/readiness.ts +86 -0
  353. package/src/workflows/recovery.ts +12 -12
  354. package/src/workflows/resume.ts +23 -9
  355. package/src/workflows/triggers.ts +85 -0
  356. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  357. package/templates/skills/agent-browser/SKILL.md +6 -5
  358. package/templates/skills/agent-browser/content.md +6 -5
  359. package/templates/skills/heartbeat-runbook/config.json +1 -1
  360. package/templates/skills/heartbeat-runbook/content.md +2 -2
  361. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  362. package/templates/skills/swarm-scripts/content.md +1 -1
  363. package/templates/skills/workflow-iterate/content.md +82 -1
  364. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  365. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  366. package/dist/boot-seeds-s3q01xj3.js +0 -26
  367. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  368. package/dist/cli-0xjkj1j7.js +0 -61
  369. package/dist/cli-20cj37vt.js +0 -335561
  370. package/dist/cli-2djtr51b.js +0 -48
  371. package/dist/cli-65hjmev5.js +0 -1141
  372. package/dist/cli-aw1jwp1r.js +0 -14075
  373. package/dist/cli-h967nb6r.js +0 -6603
  374. package/dist/cli-vapyk8sw.js +0 -20
  375. package/dist/cli-ws6rqycm.js +0 -247
  376. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  377. package/src/providers/modelsdev-reasoning.json +0 -6453
  378. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -0,0 +1,139 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { closeDb, createAgent, getDb, getDbClient, initDb } from "../be/db";
4
+ import {
5
+ FTS_DELETE_EXTRA_SQL,
6
+ FTS_MISSING_IDS_SQL,
7
+ SqliteMemoryStore,
8
+ } from "../be/memory/providers/sqlite-store";
9
+
10
+ const TEST_DB_PATH = "./test-memory-fts-populate.sqlite";
11
+ const agentId = "aaaa0000-0000-4000-8000-000000000171";
12
+
13
+ // The pre-fix backfill. Kept here as the positive control for the plan check:
14
+ // if SQLite ever stops reporting it as CORRELATED, the assertion below would
15
+ // pass vacuously, so the control has to fail first.
16
+ const QUADRATIC_BACKFILL_SQL = `INSERT INTO memory_fts(memory_id, name, content)
17
+ SELECT m.id, m.name, m.content
18
+ FROM agent_memory m
19
+ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.memory_id = m.id)`;
20
+
21
+ // EXPLAIN goes through a prepared statement that is finalized right away: the
22
+ // client's cached `db.query()` statement for an EXPLAIN stays "in progress" and
23
+ // wedges the connection's next COMMIT.
24
+ function planOf(sql: string): string[] {
25
+ const stmt = getDb().prepare(`EXPLAIN QUERY PLAN ${sql}`);
26
+ try {
27
+ return (stmt.all() as { detail: string }[]).map((row) => row.detail);
28
+ } finally {
29
+ stmt.finalize();
30
+ }
31
+ }
32
+
33
+ async function count(sql: string, params: string[] = []): Promise<number> {
34
+ return (await getDbClient().get<{ count: number }>(sql, params))?.count ?? -1;
35
+ }
36
+
37
+ describe("memory_fts boot backfill", () => {
38
+ let store: SqliteMemoryStore;
39
+
40
+ beforeAll(async () => {
41
+ for (const suffix of ["", "-wal", "-shm"]) {
42
+ try {
43
+ await unlink(TEST_DB_PATH + suffix);
44
+ } catch {}
45
+ }
46
+ initDb(TEST_DB_PATH);
47
+ await createAgent({ id: agentId, name: "FTS Populate Agent", isLead: false, status: "idle" });
48
+ store = new SqliteMemoryStore();
49
+ await store.whenFtsPopulated();
50
+ });
51
+
52
+ afterAll(async () => {
53
+ closeDb();
54
+ for (const suffix of ["", "-wal", "-shm"]) {
55
+ try {
56
+ await unlink(TEST_DB_PATH + suffix);
57
+ } catch {}
58
+ }
59
+ });
60
+
61
+ test("diff queries are not correlated against the UNINDEXED memory_id", async () => {
62
+ // Positive control: the old anti-join scans memory_fts once per memory.
63
+ expect(planOf(QUADRATIC_BACKFILL_SQL).join(" | ")).toContain("CORRELATED");
64
+
65
+ for (const sql of [FTS_MISSING_IDS_SQL, FTS_DELETE_EXTRA_SQL]) {
66
+ const plan = planOf(sql).join(" | ");
67
+ expect(plan).not.toContain("CORRELATED");
68
+ // Exactly one pass over memory_fts per statement.
69
+ expect(plan.match(/SCAN memory_fts/g)?.length).toBe(1);
70
+ }
71
+ });
72
+
73
+ test("a new store backfills missing rows across batches and drops orphans", async () => {
74
+ const total = 1050; // crosses two 500-row batch boundaries
75
+ const seed = await store.store({
76
+ agentId,
77
+ scope: "agent",
78
+ name: "fts backfill 0",
79
+ content: "backfill-token-0",
80
+ source: "manual",
81
+ });
82
+ // Clone the seed row in one statement: 1,050 store() calls outrun the
83
+ // default test timeout, and the backfill only reads id/name/content.
84
+ const columns = (
85
+ await getDbClient().query<{ name: string }>("PRAGMA table_info(agent_memory)")
86
+ ).map((col) => col.name);
87
+ const projection = columns
88
+ .map((col) => {
89
+ if (col === "id") return "'clone-' || n.i";
90
+ if (col === "name") return "'fts backfill ' || n.i";
91
+ if (col === "content") return "'backfill-token-' || n.i";
92
+ if (col === "key") return "'fts-backfill-' || n.i";
93
+ return `s."${col}"`;
94
+ })
95
+ .join(", ");
96
+ await getDbClient().run(
97
+ `WITH RECURSIVE n(i) AS (SELECT 1 UNION ALL SELECT i + 1 FROM n WHERE i < ?)
98
+ INSERT INTO agent_memory(${columns.map((col) => `"${col}"`).join(", ")})
99
+ SELECT ${projection} FROM n, agent_memory s WHERE s.id = ?`,
100
+ [total - 1, seed.id],
101
+ );
102
+ const ids = [seed.id];
103
+ expect(await count("SELECT COUNT(*) AS count FROM agent_memory")).toBe(total);
104
+ // Only the seed went through store(), so only it is indexed so far.
105
+ expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(1);
106
+ await getDbClient().run(
107
+ "INSERT INTO memory_fts(memory_id, name, content) SELECT id, name, content FROM agent_memory WHERE id != ?",
108
+ [seed.id],
109
+ );
110
+ expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(total);
111
+
112
+ // Simulate an index that lost most of its rows and gained an orphan.
113
+ await getDbClient().run("DELETE FROM memory_fts WHERE memory_id != ?", [ids[0] as string]);
114
+ await getDbClient().run(
115
+ "INSERT INTO memory_fts(memory_id, name, content) VALUES ('orphan-id', 'orphan', 'orphan')",
116
+ );
117
+
118
+ const rebuilt = new SqliteMemoryStore();
119
+ await rebuilt.whenFtsPopulated();
120
+
121
+ expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(total);
122
+ expect(await count("SELECT COUNT(DISTINCT memory_id) AS count FROM memory_fts")).toBe(total);
123
+ expect(
124
+ await count("SELECT COUNT(*) AS count FROM memory_fts WHERE memory_id = 'orphan-id'"),
125
+ ).toBe(0);
126
+ expect(
127
+ await count("SELECT COUNT(*) AS count FROM memory_fts WHERE memory_fts MATCH ?", [
128
+ '"backfill-token-1049"',
129
+ ]),
130
+ ).toBe(1);
131
+ });
132
+
133
+ test("a steady-state boot inserts nothing", async () => {
134
+ const before = await count("SELECT COUNT(*) AS count FROM memory_fts");
135
+ const again = new SqliteMemoryStore();
136
+ await again.whenFtsPopulated();
137
+ expect(await count("SELECT COUNT(*) AS count FROM memory_fts")).toBe(before);
138
+ });
139
+ });
@@ -5,6 +5,9 @@ import type { IncomingMessage, ServerResponse } from "node:http";
5
5
  import { Readable } from "node:stream";
6
6
  import { closeDb, createAgent, getDbClient, initDb } from "../be/db";
7
7
  import * as realMemoryModule from "../be/memory";
8
+ import { buildRecallQuery } from "../memory/recall-query";
9
+ import { getTemplateDefinition } from "../prompts/registry";
10
+ import "../tools/templates";
8
11
  import { SIMILARITY_THRESHOLD } from "../prompts/memories";
9
12
  import type { AgentMemory } from "../types";
10
13
 
@@ -72,11 +75,17 @@ function candidate(memoryFixture: AgentMemory, similarity: number) {
72
75
  };
73
76
  }
74
77
 
78
+ let embeddedQuery = "";
79
+ let searchedQuery = "";
80
+
75
81
  mock.module("../be/memory", () => ({
76
82
  getEmbeddingProvider: () => ({
77
83
  name: "test-embedding",
78
84
  dimensions: 3,
79
- embed: async () => new Float32Array([1, 0, 0]),
85
+ embed: async (query: string) => {
86
+ embeddedQuery = query;
87
+ return new Float32Array([1, 0, 0]);
88
+ },
80
89
  embedBatch: async (texts: string[]) => texts.map(() => new Float32Array([1, 0, 0])),
81
90
  }),
82
91
  getMemoryStore: () => ({
@@ -104,6 +113,7 @@ mock.module("../be/memory", () => ({
104
113
  _agentId: string,
105
114
  options: import("../be/memory/types").MemorySearchOptions,
106
115
  ) => {
116
+ searchedQuery = options.queryText ?? "";
107
117
  if (options.queryText === "document recall") {
108
118
  return [candidate(memory, 0.95), candidate(memoryChunk, 0.9)];
109
119
  }
@@ -324,3 +334,117 @@ describe("memory HTTP recall capture gating", () => {
324
334
  expect(await countRetrievals()).toBe(0);
325
335
  });
326
336
  });
337
+
338
+ function workerWrapper(event: "completed" | "failed", task = "", output = ""): string {
339
+ return getTemplateDefinition(`task.worker.${event}`)!.defaultBody.replace(
340
+ /{{(\w+)}}/g,
341
+ (_, key) =>
342
+ ({ task_desc: task, output_summary: output, failure_reason: output })[key as "task_desc"] ??
343
+ "",
344
+ );
345
+ }
346
+
347
+ describe("pre-task recall query", () => {
348
+ for (const event of ["completed", "failed"] as const) {
349
+ test(`${event} wrapper retains only task and output`, () => {
350
+ expect(buildRecallQuery(workerWrapper(event, "Fix memory recall", "Fixed the query"))).toBe(
351
+ "Fix memory recall\n\nFixed the query",
352
+ );
353
+ expect(buildRecallQuery(workerWrapper(event))).toBe("");
354
+ });
355
+ }
356
+
357
+ test("preserves output headings and embedded thread context once", () => {
358
+ const output =
359
+ "Result\n\nIMPORTANT: actual output heading\n<thread_context>Context</thread_context>";
360
+ expect(buildRecallQuery(workerWrapper("completed", "Task", output))).toBe(`Task\n\n${output}`);
361
+ expect(
362
+ buildRecallQuery(
363
+ workerWrapper(
364
+ "failed",
365
+ "Task",
366
+ "Reason\n\nDecide whether to reassign, retry, or handle the failure. Actual result",
367
+ ),
368
+ ),
369
+ ).toContain("Actual result");
370
+ });
371
+
372
+ test("creator instructions do not become recall content", () => {
373
+ for (const event of ["completed", "failed"] as const) {
374
+ const wrapper = workerWrapper(event).replace(
375
+ event === "completed" ? "Output:\n" : "Failure reason: ",
376
+ `${event === "completed" ? "Output:\n" : "Failure reason: "}\nAdditional instructions from the task creator:\nReview quickly\n`,
377
+ );
378
+ expect(buildRecallQuery(wrapper)).toBe("");
379
+ }
380
+ });
381
+
382
+ test("removes sibling context and preserves thread context", () => {
383
+ const thread = "<thread_context>Earlier user intent</thread_context>";
384
+ const query = `<sibling_tasks_in_progress>Unrelated task</sibling_tasks_in_progress>\n\n${workerWrapper("completed", "Fix recall", "Done")}\n\n${thread}`;
385
+ expect(buildRecallQuery(query)).toBe(`Fix recall\n\nDone\n\n${thread}`);
386
+ expect(buildRecallQuery(`User request\n${thread}`)).toBe(`User request\n${thread}`);
387
+ expect(buildRecallQuery("Worker task completed — partial text")).toBe(
388
+ "Worker task completed — partial text",
389
+ );
390
+ });
391
+
392
+ test("bounds long ASCII and multilingual queries without splitting code points", () => {
393
+ expect(buildRecallQuery("a".repeat(40000))).toBe("a".repeat(8191));
394
+ const query = buildRecallQuery("你好🙂مرحبا".repeat(10000));
395
+ expect(Buffer.byteLength(query)).toBeLessThanOrEqual(8191);
396
+ expect(query).not.toContain("�");
397
+ expect(Buffer.from(query).toString("utf8")).toBe(query);
398
+ });
399
+
400
+ test("bounds malformed near-wrappers before parsing", () => {
401
+ const malformed = workerWrapper("completed", "Task", '"\n\nOutput:\n'.repeat(200000)).replace(
402
+ '" for full details.',
403
+ '" missing suffix.',
404
+ );
405
+ const bounded = malformed.slice(0, 65536);
406
+ expect(buildRecallQuery(malformed)).toBe(buildRecallQuery(bounded));
407
+ expect(Buffer.byteLength(buildRecallQuery(malformed))).toBeLessThanOrEqual(8191);
408
+ });
409
+
410
+ test("long valid wrappers preserve content and truncate the embedding query", () => {
411
+ expect(buildRecallQuery(workerWrapper("completed", "Task", "a".repeat(20000)))).toBe(
412
+ `Task\n\n${"a".repeat(8185)}`,
413
+ );
414
+ });
415
+
416
+ test("HTTP prompt recall uses content for embedding and text search only", async () => {
417
+ const original = workerWrapper("completed", "Fix recall", "Done");
418
+ await callMemoryRoute(
419
+ "POST",
420
+ "/api/memory/search",
421
+ ["api", "memory", "search"],
422
+ { query: original },
423
+ { "x-memory-consumption": "prompt" },
424
+ );
425
+ expect(embeddedQuery).toBe("Fix recall\n\nDone");
426
+ expect(searchedQuery).toBe(embeddedQuery);
427
+ await callMemoryRoute("POST", "/api/memory/search", ["api", "memory", "search"], {
428
+ query: original,
429
+ });
430
+ expect(embeddedQuery).toBe(original);
431
+ expect(searchedQuery).toBe(original);
432
+ });
433
+
434
+ test("blank wrapper skips search and retrieval records", async () => {
435
+ embeddedQuery = "untouched";
436
+ searchedQuery = "untouched";
437
+ const before = await countRetrievals();
438
+ const response = await callMemoryRoute(
439
+ "POST",
440
+ "/api/memory/search",
441
+ ["api", "memory", "search"],
442
+ { query: workerWrapper("completed"), intent: "pre-task memory recall" },
443
+ { "x-memory-consumption": "prompt", "x-source-task-id": sourceTaskId },
444
+ );
445
+ expect(response.body.results).toEqual([]);
446
+ expect(embeddedQuery).toBe("untouched");
447
+ expect(searchedQuery).toBe("untouched");
448
+ expect(await countRetrievals()).toBe(before);
449
+ });
450
+ });
@@ -3,7 +3,7 @@ import { unlink } from "node:fs/promises";
3
3
  import { closeDb, getDbClient, initDb } from "../be/db";
4
4
  import { loadModelsDevCache } from "../be/modelsdev-cache";
5
5
  import { seedPricingFromModelsDev } from "../be/seed-pricing";
6
- import { CODEX_MODEL_PRICING } from "../providers/codex-models";
6
+ import { codexModelPricingTable } from "../providers/codex-models";
7
7
 
8
8
  const TEST_DB_PATH = "./test-migration-046.sqlite";
9
9
 
@@ -133,7 +133,7 @@ describe("migration 046 — budgets and pricing", () => {
133
133
  });
134
134
 
135
135
  test("pricing seed includes every known Codex model/token class at effective_from=0", async () => {
136
- const minimumCodexRows = Object.keys(CODEX_MODEL_PRICING).length * 3;
136
+ const minimumCodexRows = Object.keys(codexModelPricingTable()).length * 3;
137
137
 
138
138
  const seedRows = await getDbClient().get<CountRow>(
139
139
  "SELECT COUNT(*) as cnt FROM pricing WHERE provider = 'codex' AND effective_from = 0",
@@ -151,7 +151,7 @@ describe("migration 046 — budgets and pricing", () => {
151
151
  // time comes from newer effective_from rows (runtime refresh); the
152
152
  // worker-local table is advisory and agentswarm.cost.drift.usd is the
153
153
  // watchdog. This test pins seed COVERAGE, not rate sync.
154
- for (const model of Object.keys(CODEX_MODEL_PRICING)) {
154
+ for (const model of Object.keys(codexModelPricingTable())) {
155
155
  for (const tokenClass of ["input", "cached_input", "output"] as const) {
156
156
  const row = await client.get<PricingRow>(
157
157
  "SELECT * FROM pricing WHERE provider = 'codex' AND model = ? AND token_class = ? AND effective_from = ?",
@@ -0,0 +1,134 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { afterEach, describe, expect, test } from "bun:test";
3
+ import { runMigrations } from "../be/migrations/runner";
4
+
5
+ const DB_PATH = "./test-model-catalog-migration.sqlite";
6
+
7
+ async function removeDb(): Promise<void> {
8
+ for (const suffix of ["", "-wal", "-shm"]) {
9
+ try {
10
+ await Bun.file(DB_PATH + suffix).delete();
11
+ } catch (error) {
12
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
13
+ }
14
+ }
15
+ }
16
+
17
+ afterEach(removeDb);
18
+
19
+ function columnNames(db: Database, table: string): string[] {
20
+ return db
21
+ .query<{ name: string }, []>(`PRAGMA table_info(${table})`)
22
+ .all()
23
+ .map((column) => column.name);
24
+ }
25
+
26
+ function tableExists(db: Database, table: string): boolean {
27
+ return (
28
+ db
29
+ .query<{ name: string }, [string]>(
30
+ "SELECT name FROM sqlite_master WHERE type='table' AND name = ?",
31
+ )
32
+ .get(table) !== null
33
+ );
34
+ }
35
+
36
+ describe("migration 184 model catalog, tier resolution and harness support", () => {
37
+ test("upgrades a pre-184 database in place and keeps existing agent and task rows", async () => {
38
+ await removeDb();
39
+ const db = new Database(DB_PATH, { create: true });
40
+ try {
41
+ runMigrations(db);
42
+
43
+ // Roll the database back to the state before migration 184.
44
+ for (const table of [
45
+ "model_catalog",
46
+ "model_catalog_overlay",
47
+ "model_catalog_meta",
48
+ "model_alias_resolutions",
49
+ "harness_model_support",
50
+ ]) {
51
+ db.run(`DROP TABLE ${table}`);
52
+ }
53
+ for (const column of ["resolvedModel", "modelSource", "modelAlias"]) {
54
+ db.run(`ALTER TABLE agent_tasks DROP COLUMN ${column}`);
55
+ }
56
+ for (const column of ["modelTierOverrides", "harnessCliVersion"]) {
57
+ db.run(`ALTER TABLE agents DROP COLUMN ${column}`);
58
+ }
59
+ db.run("DELETE FROM _migrations WHERE version = 184");
60
+
61
+ db.run(
62
+ `INSERT INTO agents (id, name, status, createdAt, lastUpdatedAt)
63
+ VALUES ('agent-1', 'worker', 'idle', '2026-09-01', '2026-09-01')`,
64
+ );
65
+ db.run(
66
+ `INSERT INTO agent_tasks (id, task, status, createdAt, lastUpdatedAt)
67
+ VALUES ('task-1', 'existing task', 'pending', '2026-09-01', '2026-09-01')`,
68
+ );
69
+
70
+ runMigrations(db);
71
+
72
+ expect(
73
+ db
74
+ .query<{ version: number }, []>("SELECT version FROM _migrations WHERE version = 184")
75
+ .get(),
76
+ ).not.toBeNull();
77
+ for (const table of [
78
+ "model_catalog",
79
+ "model_catalog_overlay",
80
+ "model_catalog_meta",
81
+ "model_alias_resolutions",
82
+ "harness_model_support",
83
+ ]) {
84
+ expect(tableExists(db, table)).toBe(true);
85
+ }
86
+ expect(columnNames(db, "agent_tasks")).toEqual(
87
+ expect.arrayContaining(["resolvedModel", "modelSource", "modelAlias"]),
88
+ );
89
+ expect(columnNames(db, "agents")).toEqual(
90
+ expect.arrayContaining(["modelTierOverrides", "harnessCliVersion"]),
91
+ );
92
+
93
+ const task = db
94
+ .query<Record<string, unknown>, []>(
95
+ "SELECT task, resolvedModel, modelSource, modelAlias FROM agent_tasks WHERE id = 'task-1'",
96
+ )
97
+ .get();
98
+ expect(task).toEqual({
99
+ task: "existing task",
100
+ resolvedModel: null,
101
+ modelSource: null,
102
+ modelAlias: null,
103
+ });
104
+ const agent = db
105
+ .query<Record<string, unknown>, []>(
106
+ "SELECT name, modelTierOverrides, harnessCliVersion FROM agents WHERE id = 'agent-1'",
107
+ )
108
+ .get();
109
+ expect(agent).toEqual({ name: "worker", modelTierOverrides: null, harnessCliVersion: null });
110
+ } finally {
111
+ db.close();
112
+ }
113
+ });
114
+
115
+ test("harness_model_support only accepts ok, unsupported and unknown", async () => {
116
+ await removeDb();
117
+ const db = new Database(DB_PATH, { create: true });
118
+ try {
119
+ runMigrations(db);
120
+ const insert = (status: string) =>
121
+ db.run(
122
+ `INSERT INTO harness_model_support (harness, cliVersion, modelId, status, checkedAt)
123
+ VALUES ('claude', '2.1.0', ?, ?, 1)`,
124
+ [`m-${status}`, status],
125
+ );
126
+ expect(() => insert("ok")).not.toThrow();
127
+ expect(() => insert("unsupported")).not.toThrow();
128
+ expect(() => insert("unknown")).not.toThrow();
129
+ expect(() => insert("maybe")).toThrow(/CHECK/);
130
+ } finally {
131
+ db.close();
132
+ }
133
+ });
134
+ });