@desplega.ai/agent-swarm 1.157.0 → 1.158.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 (256) hide show
  1. package/dist/{acp-adapter-qhqrk4q0.js → acp-adapter-xaq4n6pc.js} +1 -1
  2. package/dist/{actions-9rrg0zxm.js → actions-p9hz5yat.js} +15 -15
  3. package/dist/{app-enysy1zd.js → app-g26wdcz6.js} +4 -4
  4. package/dist/{artifact-td4q4dch.js → artifact-3v5t9jtg.js} +1 -1
  5. package/dist/{assistant-zegamy48.js → assistant-wydfqkb3.js} +16 -16
  6. package/dist/{boot-reembed-r6shx5qx.js → boot-reembed-g5ckg9yb.js} +6 -6
  7. package/dist/{boot-reembed-zfxb937k.js → boot-reembed-se8zmdcp.js} +5 -5
  8. package/dist/{boot-scrub-logs-k5y0se6r.js → boot-scrub-logs-wfxqan61.js} +3 -3
  9. package/dist/{seed-pricing-vqxa06qf.js → boot-seeds-s3q01xj3.js} +10 -10
  10. package/dist/{claude-adapter-5yc7hxwv.js → claude-adapter-tv2x4f36.js} +7 -7
  11. package/dist/{claude-managed-adapter-ea2aga6w.js → claude-managed-adapter-41b2s7fd.js} +2 -2
  12. package/dist/{claude-sdk-session-j4ywn3xf.js → claude-sdk-session-t442qz6f.js} +8 -8
  13. package/dist/{cli-e781c6f9.js → cli-0xjkj1j7.js} +1 -0
  14. package/dist/{cli-58rgvkt4.js → cli-1hkrch3k.js} +2 -2
  15. package/dist/{cli-yscm6cv8.js → cli-20cj37vt.js} +1866 -9
  16. package/dist/{cli-h0wdadsx.js → cli-4198qc9v.js} +7 -3
  17. package/dist/{cli-awwphhcs.js → cli-47m6dkd3.js} +362 -126
  18. package/dist/{cli-wb2zvbfg.js → cli-53sz8gkz.js} +1 -1
  19. package/dist/{cli-005pze6s.js → cli-5d10vd2m.js} +1 -1
  20. package/dist/{cli-v53rbqp3.js → cli-65hjmev5.js} +57 -17
  21. package/dist/{cli-scwq51gn.js → cli-68w09sjw.js} +7 -1
  22. package/dist/{cli-s98skd5r.js → cli-7gtvvpbh.js} +4 -4
  23. package/dist/{cli-y3nxwx0t.js → cli-7s3syk22.js} +18 -11
  24. package/dist/{cli-74h6f2bp.js → cli-8qmme6vd.js} +2 -2
  25. package/dist/{cli-wsed24mk.js → cli-987hg0aa.js} +2 -2
  26. package/dist/{cli-9n76jszt.js → cli-9httdpyq.js} +1 -1
  27. package/dist/{cli-f3va018d.js → cli-aky8tctm.js} +26 -93
  28. package/dist/{cli-sgyqyyxe.js → cli-c07r9a2m.js} +2 -1
  29. package/dist/{cli-c41wjx0r.js → cli-fgqxwrpv.js} +291 -12
  30. package/dist/{cli-01vfmq8c.js → cli-ftfvggzx.js} +607 -164
  31. package/dist/{cli-ytxs7mn1.js → cli-g8djp6qe.js} +17 -0
  32. package/dist/{cli-avkd6mqv.js → cli-h967nb6r.js} +551 -0
  33. package/dist/{cli-r9ee9c4w.js → cli-j55n64b6.js} +23 -22
  34. package/dist/{cli-9p33cz9h.js → cli-j57qkrpq.js} +86 -28
  35. package/dist/{cli-tjmghmm5.js → cli-q67y4wzm.js} +6 -3
  36. package/dist/{cli-n6zq3kbd.js → cli-rj19hc34.js} +1 -1
  37. package/dist/{cli-jytrw2na.js → cli-rjehvrts.js} +4 -4
  38. package/dist/{cli-tpv97m71.js → cli-rqz8qbw7.js} +245 -75
  39. package/dist/{cli-p37sg0a9.js → cli-s8eet254.js} +1 -1
  40. package/dist/cli-t1ze64h3.js +811 -0
  41. package/dist/{cli-6jjzxv3b.js → cli-ws6rqycm.js} +3 -2
  42. package/dist/{cli-xf5b7y1f.js → cli-wscdvcqz.js} +13 -5
  43. package/dist/{cli-5j7bm4tb.js → cli-x24pshtq.js} +5 -5
  44. package/dist/{cli-nbp6m6gp.js → cli-xberxa1r.js} +51 -26
  45. package/dist/{cli-vx9p3qdt.js → cli-xhaeg2nc.js} +1 -1
  46. package/dist/cli.js +29 -15
  47. package/dist/{codex-adapter-gns3s6c3.js → codex-adapter-cnm8wk11.js} +5 -5
  48. package/dist/{codex-session-runner-gqnxys5w.js → codex-session-runner-gfg547zj.js} +5 -5
  49. package/dist/{commands-hxy2y2sp.js → commands-e3bn0p75.js} +3 -3
  50. package/dist/{db-w8ghhsgf.js → db-03v9kzr2.js} +17 -3
  51. package/dist/{dispatcher-cp1rknjz.js → dispatcher-nrmg8yht.js} +14 -14
  52. package/dist/{dsh-adapter-1dwg97zv.js → dsh-adapter-k03nfqa6.js} +2 -2
  53. package/dist/{handlers-egfhr351.js → handlers-aqcedbyb.js} +17 -17
  54. package/dist/{hook-x4kftwzt.js → hook-7vkskkre.js} +19 -11
  55. package/dist/{hook-fbxjqfjz.js → hook-ybvmrmhq.js} +4 -4
  56. package/dist/{http-c7jfx990.js → http-2eqa8t24.js} +432 -195
  57. package/dist/{index-4k9hct21.js → index-1yks3qcr.js} +14 -14
  58. package/dist/{index-jtvpgb8f.js → index-a3vn96n8.js} +30 -27
  59. package/dist/{index-dc2ek6bw.js → index-c6zsv1bd.js} +5 -5
  60. package/dist/{index-yy07ef2s.js → index-chgdkq36.js} +14 -14
  61. package/dist/{index-r6bty6tb.js → index-x71bvq0p.js} +15 -15
  62. package/dist/{keepalive-f7ekefyc.js → keepalive-vtkf5n99.js} +5 -5
  63. package/dist/{lead-h053syts.js → lead-h3sp357x.js} +26 -26
  64. package/dist/{maintenance-a3w6zs54.js → maintenance-jzeqtk3q.js} +6 -6
  65. package/dist/{oauth-refresh-sweep-vra1dhkd.js → oauth-refresh-sweep-qp3dzmdp.js} +4 -4
  66. package/dist/{onboard-mfgzeqxs.js → onboard-tmsp0qbz.js} +278 -81
  67. package/dist/{opencode-adapter-z64xjzec.js → opencode-adapter-x6x2da1z.js} +3 -3
  68. package/dist/{otel-impl-2ez6xk57.js → otel-impl-9mz73q65.js} +416 -301
  69. package/dist/{pi-mono-adapter-2b7mw16r.js → pi-mono-adapter-m6dvv0dz.js} +2 -2
  70. package/dist/{pricing-refresh-6sw65tck.js → pricing-refresh-v1cbr9te.js} +5 -5
  71. package/dist/{rbac-roles-nm6924sy.js → rbac-roles-c9wqz83x.js} +4 -4
  72. package/dist/{render-v2-f026j6c4.js → render-v2-gryrh9h8.js} +4 -4
  73. package/dist/{setup-w606fr1q.js → setup-q9720bt6.js} +2 -2
  74. package/dist/{virtual-modules-8qheft18.js → virtual-modules-3htpgn8x.js} +1 -1
  75. package/dist/{work-objects-ezmggdne.js → work-objects-b76x7deb.js} +17 -17
  76. package/dist/{worker-1mbyv29k.js → worker-6vrxbv41.js} +26 -26
  77. package/openapi.json +1626 -629
  78. package/package.json +2 -1
  79. package/src/apps/catalog.generated.json +229 -0
  80. package/src/apps/page-validator.ts +71 -16
  81. package/src/apps/row-store.ts +66 -11
  82. package/src/apps/sync.ts +59 -17
  83. package/src/artifact-sdk/browser-sdk.ts +436 -2
  84. package/src/be/approval-sweeps.ts +109 -0
  85. package/src/be/boot-seeds.ts +40 -0
  86. package/src/be/chunking.ts +1 -1
  87. package/src/be/db/agents.ts +20 -0
  88. package/src/be/db/approvals.ts +78 -0
  89. package/src/be/db/tasks/read.ts +197 -39
  90. package/src/be/db/tasks/write.ts +41 -9
  91. package/src/be/db-client.ts +107 -48
  92. package/src/be/db.ts +219 -76
  93. package/src/be/events.ts +33 -1
  94. package/src/be/memory/graph-expansion.ts +10 -3
  95. package/src/be/memory/providers/sqlite-store.ts +55 -13
  96. package/src/be/memory/raters/retrieval.ts +5 -2
  97. package/src/be/memory/reranker.ts +26 -2
  98. package/src/be/memory/types.ts +2 -0
  99. package/src/be/migrations/166_approval_request_auto_cancellation.sql +9 -0
  100. package/src/be/migrations/171_memory_retrieval_relevance.sql +8 -0
  101. package/src/be/migrations/175_workflow_runs_list_index.sql +11 -0
  102. package/src/be/migrations/177_events_event_agent_created_index.sql +11 -0
  103. package/src/be/models-catalog.ts +2 -0
  104. package/src/be/modelsdev-cache.json +1857 -0
  105. package/src/be/modelsdev-cache.ts +14 -1
  106. package/src/be/pricing-normalize.ts +2 -0
  107. package/src/be/scripts/typecheck.ts +1 -0
  108. package/src/be/seed-pricing.ts +3 -1
  109. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  110. package/src/be/steering.ts +53 -3
  111. package/src/be/swarm-config-guard.ts +3 -0
  112. package/src/be/task-citations.ts +29 -0
  113. package/src/cli.tsx +14 -1
  114. package/src/commands/onboard/compose-generator.ts +8 -3
  115. package/src/commands/onboard/container-engine.ts +220 -0
  116. package/src/commands/onboard/manifest.ts +1 -0
  117. package/src/commands/onboard/steps/health-check.tsx +4 -1
  118. package/src/commands/onboard/steps/prereq-check.tsx +50 -54
  119. package/src/commands/onboard/steps/start.tsx +31 -16
  120. package/src/commands/onboard/types.ts +7 -2
  121. package/src/commands/onboard.tsx +39 -4
  122. package/src/commands/profile-sync.ts +79 -26
  123. package/src/commands/runner.ts +8 -1
  124. package/src/extensions/catalog.generated.json +17 -0
  125. package/src/extensions/contract-types.generated.ts +1 -1
  126. package/src/heartbeat/heartbeat.ts +263 -103
  127. package/src/hooks/hook.ts +21 -12
  128. package/src/http/agents.ts +35 -0
  129. package/src/http/approval-requests.ts +136 -64
  130. package/src/http/apps.ts +14 -3
  131. package/src/http/config.ts +15 -1
  132. package/src/http/events.ts +62 -2
  133. package/src/http/index.ts +6 -4
  134. package/src/http/memory.ts +21 -7
  135. package/src/http/schedules.ts +1 -1
  136. package/src/http/session-data.ts +9 -4
  137. package/src/http/sessions.ts +25 -18
  138. package/src/http/stats.ts +19 -7
  139. package/src/http/status.ts +11 -1
  140. package/src/http/tasks.ts +40 -8
  141. package/src/http/webhooks.ts +67 -46
  142. package/src/http/workflows.ts +15 -20
  143. package/src/linear/outbound.ts +37 -15
  144. package/src/otel-impl.ts +151 -1
  145. package/src/otel.ts +14 -3
  146. package/src/prompts/memories.ts +19 -2
  147. package/src/providers/claude-managed-models.ts +8 -0
  148. package/src/providers/modelsdev-reasoning.json +551 -0
  149. package/src/rbac/legacy-policy.ts +16 -0
  150. package/src/rbac/permissions.ts +4 -0
  151. package/src/scheduler/schedule-task.ts +3 -0
  152. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  153. package/src/scripts-runtime/swarm-sdk.ts +9 -0
  154. package/src/scripts-runtime/types/stdlib.d.ts +1 -0
  155. package/src/scripts-runtime/types/swarm-extension.d.ts +1 -0
  156. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
  157. package/src/server.ts +12 -7
  158. package/src/slack/app.ts +35 -4
  159. package/src/slack/connection-state.ts +17 -0
  160. package/src/tasks/context-key.ts +1 -0
  161. package/src/tasks/worker-follow-up.ts +6 -2
  162. package/src/tests/agent-task-activity.test.ts +74 -0
  163. package/src/tests/agents-list-model-display.test.ts +6 -1
  164. package/src/tests/approval-auto-cancellation-migration.test.ts +104 -0
  165. package/src/tests/approval-requests.test.ts +395 -0
  166. package/src/tests/approval-sweeps-config.test.ts +47 -0
  167. package/src/tests/approval-sweeps.test.ts +508 -0
  168. package/src/tests/apps-kibo-blocks.test.ts +77 -0
  169. package/src/tests/apps-spike.test.ts +56 -1
  170. package/src/tests/apps-sync-engine.test.ts +20 -9
  171. package/src/tests/boot-seeds.test.ts +170 -0
  172. package/src/tests/cancel-approval-request-tool.test.ts +115 -0
  173. package/src/tests/claude-managed-adapter.test.ts +6 -0
  174. package/src/tests/config-key-filter.test.ts +80 -0
  175. package/src/tests/context-window.test.ts +1 -0
  176. package/src/tests/db-client-busy-retry.test.ts +96 -0
  177. package/src/tests/db-client.test.ts +60 -1
  178. package/src/tests/db-task-read-contract.test.ts +10 -0
  179. package/src/tests/db-task-write-contract.test.ts +9 -0
  180. package/src/tests/docs-index-footprint.test.js +3 -3
  181. package/src/tests/events-http.test.ts +103 -0
  182. package/src/tests/extensions-catalog.test.ts +22 -17
  183. package/src/tests/extensions-pre-task.test.ts +107 -0
  184. package/src/tests/fixtures/kibo-blocks-definition.json.txt +105 -0
  185. package/src/tests/follow-up-config-inheritance.test.ts +260 -0
  186. package/src/tests/heartbeat-orphan-resume.test.ts +84 -0
  187. package/src/tests/heartbeat-reboot-live.test.ts +95 -0
  188. package/src/tests/heartbeat-stall-cas.test.ts +80 -0
  189. package/src/tests/heartbeat.test.ts +99 -3
  190. package/src/tests/hook-mcp-config.test.ts +29 -0
  191. package/src/tests/http-api-integration.test.ts +16 -2
  192. package/src/tests/kv-storage.test.ts +62 -0
  193. package/src/tests/linear-outbound-sync.test.ts +120 -5
  194. package/src/tests/list-endpoint-slimming.test.ts +91 -0
  195. package/src/tests/memory-graph-organic-route.test.ts +155 -0
  196. package/src/tests/memory-http-recall-gating.test.ts +14 -4
  197. package/src/tests/memory-hybrid.test.ts +161 -1
  198. package/src/tests/memory-prompt-recall-crowdout.test.ts +297 -0
  199. package/src/tests/memory.test.ts +22 -0
  200. package/src/tests/onboard-container-engine.test.ts +240 -0
  201. package/src/tests/otel-event-loop-and-logs.test.ts +99 -0
  202. package/src/tests/pricing-routes.test.ts +14 -0
  203. package/src/tests/profile-sync-warning.test.ts +8 -4
  204. package/src/tests/promote-draft-task-route.test.ts +19 -0
  205. package/src/tests/provider-registration.test.ts +296 -42
  206. package/src/tests/rbac-engine.test.ts +30 -0
  207. package/src/tests/reasoning-effort.test.ts +8 -0
  208. package/src/tests/script-connections.test.ts +7 -0
  209. package/src/tests/sdk-allowlist.test.ts +39 -0
  210. package/src/tests/session-costs-model-key-normalize.test.ts +1 -0
  211. package/src/tests/sessions-detail-batch.test.ts +250 -0
  212. package/src/tests/sessions.test.ts +118 -0
  213. package/src/tests/slack-config.test.ts +22 -0
  214. package/src/tests/sonnet-5-5-registry.test.ts +44 -0
  215. package/src/tests/status.test.ts +36 -1
  216. package/src/tests/swarm-diff.test.ts +316 -10
  217. package/src/tests/task-completion-idempotency.test.ts +2 -1
  218. package/src/tests/tasks-requested-by-filter.test.ts +3 -1
  219. package/src/tests/tool-annotations.test.ts +1 -1
  220. package/src/tests/ui-list-slim-projections.test.ts +158 -0
  221. package/src/tests/webhooks-task-blocked.test.ts +127 -0
  222. package/src/tests/workflow-approval-recovery.test.ts +203 -0
  223. package/src/tests/workflow-hitl-routing.test.ts +22 -1
  224. package/src/tests/workflow-hitl-slack-card.test.ts +52 -0
  225. package/src/tests/workflow-http-v2.test.ts +99 -8
  226. package/src/tests/workflow-retry-validation.test.ts +56 -0
  227. package/src/tests/workflow-tla-races.test.ts +389 -0
  228. package/src/tests/workflow-validation-port-routing.test.ts +113 -1
  229. package/src/tools/cancel-approval-request.ts +57 -0
  230. package/src/tools/memory-search.ts +1 -0
  231. package/src/tools/request-human-input.ts +4 -2
  232. package/src/tools/send-task.ts +4 -0
  233. package/src/tools/templates.ts +19 -0
  234. package/src/tools/tool-config.ts +2 -1
  235. package/src/tools/workflows/list-workflow-runs.ts +1 -0
  236. package/src/types.ts +38 -0
  237. package/src/utils/context-window.ts +1 -0
  238. package/src/workflows/approval-cancel.ts +152 -0
  239. package/src/workflows/approval-notifications.ts +84 -0
  240. package/src/workflows/checkpoint.ts +10 -5
  241. package/src/workflows/definition.ts +21 -0
  242. package/src/workflows/engine.ts +152 -21
  243. package/src/workflows/executors/human-in-the-loop.ts +1 -1
  244. package/src/workflows/recovery.ts +100 -45
  245. package/src/workflows/resume.ts +49 -18
  246. package/src/workflows/retry-poller.ts +71 -21
  247. package/templates/extensions/README.md +1 -0
  248. package/templates/extensions/github-sender-allowlist/README.md +18 -0
  249. package/templates/extensions/github-sender-allowlist/hooks.ts +55 -0
  250. package/templates/extensions/github-sender-allowlist/manifest.json +8 -0
  251. package/templates/skills/apps/content.md +20 -1
  252. package/templates/skills/code-quality/content.md +26 -1
  253. package/templates/skills/pages/content.md +16 -4
  254. package/templates/skills/pages/files/examples/multiplayer-board.html +3 -12
  255. package/dist/cli-2daksqps.js +0 -378
  256. package/dist/rbac-roles-3gxmnb20.js +0 -37
@@ -41,6 +41,7 @@ const baseFacade = `type:AgentMailInboxMapping
41
41
  type:ApiKeyStatus
42
42
  type:AppVersion
43
43
  type:ApprovalRequest
44
+ type:ApprovalRequestSummary
44
45
  type:AssetSummaryFilters
45
46
  type:AttributionByPersonRow
46
47
  type:AvailableKeyIndicesResult
@@ -64,6 +65,7 @@ type:InboxSummary
64
65
  type:InsertPricingRowInput
65
66
  type:InsertTaskAttachmentInput
66
67
  type:KeyCostSummary
68
+ type:KvJsonFieldEquals
67
69
  type:McpServerFilters
68
70
  type:McpServerInsert
69
71
  type:MentionPreview
@@ -113,6 +115,7 @@ value:autoEncryptLegacyPlaintextSecrets
113
115
  value:backfillSupersedeTaskResumeTaskId
114
116
  value:bindSlackMessageTimestamp
115
117
  value:buildRoutingAffinityFromAgent
118
+ value:cancelApprovalRequestById
116
119
  value:cancelPendingApprovalRequestsForRun
117
120
  value:cancelPendingSteeringForTask
118
121
  value:cancelTask
@@ -223,6 +226,7 @@ value:getActiveSessions
223
226
  value:getActiveTaskCount
224
227
  value:getAgentById
225
228
  value:getAgentCurrentTask
229
+ value:getAgentDailyTaskCounts
226
230
  value:getAgentHarnessProviders
227
231
  value:getAgentMailInboxMapping
228
232
  value:getAgentMailInboxMappingsByAgent
@@ -265,6 +269,7 @@ value:getContextSnapshotsByTaskId
265
269
  value:getContextSummaryByTaskId
266
270
  value:getContextVersion
267
271
  value:getContextVersionHistory
272
+ value:getCurrentStepForNode
268
273
  value:getDailySpendForAgent
269
274
  value:getDailySpendForUser
270
275
  value:getDailySpendGlobal
@@ -370,6 +375,7 @@ value:getSlackTasksMissingTree
370
375
  value:getSlackTreeMessage
371
376
  value:getSlackTreeMessageByThread
372
377
  value:getSlackTreeMessages
378
+ value:getStaleApprovalRequests
373
379
  value:getStalePinnedResumes
374
380
  value:getStaleUnassignedAffinityTasks
375
381
  value:getStalledInProgressTasks
@@ -380,6 +386,7 @@ value:getStepCountForNode
380
386
  value:getStuckApprovalRuns
381
387
  value:getStuckWaitRuns
382
388
  value:getStuckWorkflowRuns
389
+ value:getSupersededTasksWithoutResume
383
390
  value:getSwarmConfigById
384
391
  value:getSwarmConfigLookupById
385
392
  value:getSwarmConfigs
@@ -436,9 +443,11 @@ value:isPendingSlackMessage
436
443
  value:isPoolAffinityEnforcementEnabled
437
444
  value:isSettledSlackMessage
438
445
  value:isSqliteVecAvailable
446
+ value:kvPrefixUpperBound
439
447
  value:listAgentsWithCredStatusByProvider
440
448
  value:listAllMetrics
441
449
  value:listAllPages
450
+ value:listApprovalRequestSummaries
442
451
  value:listApprovalRequests
443
452
  value:listAssetSummaries
444
453
  value:listCancelledApprovalRequestsForRun
@@ -595,6 +604,7 @@ value:getMostRecentTaskInThread
595
604
  value:getPendingSlackRelayTasks
596
605
  value:getRecentlyFinishedWorkerTasks
597
606
  value:getSlackTasksMissingTree
607
+ value:getSupersededTasksWithoutResume
598
608
  value:getTaskById
599
609
  value:getTaskStats
600
610
  value:getTasksByAgentId
@@ -42,6 +42,7 @@ const baseFacade = `type:AgentMailInboxMapping
42
42
  type:ApiKeyStatus
43
43
  type:AppVersion
44
44
  type:ApprovalRequest
45
+ type:ApprovalRequestSummary
45
46
  type:AssetSummaryFilters
46
47
  type:AttributionByPersonRow
47
48
  type:AvailableKeyIndicesResult
@@ -65,6 +66,7 @@ type:InboxSummary
65
66
  type:InsertPricingRowInput
66
67
  type:InsertTaskAttachmentInput
67
68
  type:KeyCostSummary
69
+ type:KvJsonFieldEquals
68
70
  type:McpServerFilters
69
71
  type:McpServerInsert
70
72
  type:MentionPreview
@@ -114,6 +116,7 @@ value:autoEncryptLegacyPlaintextSecrets
114
116
  value:backfillSupersedeTaskResumeTaskId
115
117
  value:bindSlackMessageTimestamp
116
118
  value:buildRoutingAffinityFromAgent
119
+ value:cancelApprovalRequestById
117
120
  value:cancelPendingApprovalRequestsForRun
118
121
  value:cancelPendingSteeringForTask
119
122
  value:cancelTask
@@ -224,6 +227,7 @@ value:getActiveSessions
224
227
  value:getActiveTaskCount
225
228
  value:getAgentById
226
229
  value:getAgentCurrentTask
230
+ value:getAgentDailyTaskCounts
227
231
  value:getAgentHarnessProviders
228
232
  value:getAgentMailInboxMapping
229
233
  value:getAgentMailInboxMappingsByAgent
@@ -266,6 +270,7 @@ value:getContextSnapshotsByTaskId
266
270
  value:getContextSummaryByTaskId
267
271
  value:getContextVersion
268
272
  value:getContextVersionHistory
273
+ value:getCurrentStepForNode
269
274
  value:getDailySpendForAgent
270
275
  value:getDailySpendForUser
271
276
  value:getDailySpendGlobal
@@ -371,6 +376,7 @@ value:getSlackTasksMissingTree
371
376
  value:getSlackTreeMessage
372
377
  value:getSlackTreeMessageByThread
373
378
  value:getSlackTreeMessages
379
+ value:getStaleApprovalRequests
374
380
  value:getStalePinnedResumes
375
381
  value:getStaleUnassignedAffinityTasks
376
382
  value:getStalledInProgressTasks
@@ -381,6 +387,7 @@ value:getStepCountForNode
381
387
  value:getStuckApprovalRuns
382
388
  value:getStuckWaitRuns
383
389
  value:getStuckWorkflowRuns
390
+ value:getSupersededTasksWithoutResume
384
391
  value:getSwarmConfigById
385
392
  value:getSwarmConfigLookupById
386
393
  value:getSwarmConfigs
@@ -437,9 +444,11 @@ value:isPendingSlackMessage
437
444
  value:isPoolAffinityEnforcementEnabled
438
445
  value:isSettledSlackMessage
439
446
  value:isSqliteVecAvailable
447
+ value:kvPrefixUpperBound
440
448
  value:listAgentsWithCredStatusByProvider
441
449
  value:listAllMetrics
442
450
  value:listAllPages
451
+ value:listApprovalRequestSummaries
443
452
  value:listApprovalRequests
444
453
  value:listAssetSummaries
445
454
  value:listCancelledApprovalRequestsForRun
@@ -78,7 +78,7 @@ describe("docs API index footprint", () => {
78
78
  expect(tasks).toContain('"path":"/api/task-templates","method":"get"');
79
79
  });
80
80
 
81
- test("OpenAPI and generated pages keep all 381 operations", async () => {
81
+ test("OpenAPI and generated pages keep all 383 operations", async () => {
82
82
  const spec = await Bun.file(resolve(repoRoot, "openapi.json")).json();
83
83
  const operationKeys = [];
84
84
  const tags = new Set();
@@ -103,8 +103,8 @@ describe("docs API index footprint", () => {
103
103
  expect(spec.paths["/api/agents/{id}/runtime"]?.get).toBeDefined();
104
104
 
105
105
  const generatedKeys = await generatedOperationKeys();
106
- expect(operationKeys).toHaveLength(381);
107
- expect(generatedKeys).toHaveLength(381);
106
+ expect(operationKeys).toHaveLength(383);
107
+ expect(generatedKeys).toHaveLength(383);
108
108
  expect(new Set(generatedKeys)).toEqual(new Set(operationKeys));
109
109
  });
110
110
 
@@ -1,6 +1,7 @@
1
1
  import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
2
  import { unlink } from "node:fs/promises";
3
3
  import type { Subprocess } from "bun";
4
+ import { fetchProfileSyncRejectionBanner } from "../commands/profile-sync";
4
5
  import { getFreePort, SERVER_BOOT_HOOK_TIMEOUT_MS } from "./test-net";
5
6
 
6
7
  let TEST_PORT = 0;
@@ -270,6 +271,108 @@ describe("GET /api/events", () => {
270
271
  });
271
272
  });
272
273
 
274
+ describe("GET /api/events — latestPerDataField", () => {
275
+ const AGENT = "profile-sync-latest-agent";
276
+ const ids: Record<string, string> = {};
277
+
278
+ beforeAll(async () => {
279
+ const seed: [string, string, string][] = [
280
+ ["tools-old", "system.profile_sync_rejected", "toolsMd"],
281
+ ["claude-rejected", "system.profile_sync_rejected", "claudeMd"],
282
+ ["soul-reconciled", "system.profile_sync_reconciled", "soulMd"],
283
+ ["tools-new", "system.profile_sync_rejected", "toolsMd"],
284
+ ["claude-reconciled", "system.profile_sync_reconciled", "claudeMd"],
285
+ ["soul-rejected", "system.profile_sync_rejected", "soulMd"],
286
+ ];
287
+ for (const [key, event, field] of seed) {
288
+ const { body } = await post("/api/events", {
289
+ category: "system",
290
+ event,
291
+ status: event.endsWith("rejected") ? "error" : "ok",
292
+ source: "api",
293
+ agentId: AGENT,
294
+ data: { field, diskSize: 30_000, dbSize: 19_000, budget: 20_000, delta: 11_000 },
295
+ });
296
+ ids[key] = (body.event as { id: string }).id;
297
+ // createdAt has millisecond precision: keep the seed strictly ordered.
298
+ await Bun.sleep(5);
299
+ }
300
+ await post("/api/events", {
301
+ category: "system",
302
+ event: "system.profile_sync_conflict",
303
+ source: "api",
304
+ agentId: AGENT,
305
+ data: { field: "toolsMd" },
306
+ });
307
+ });
308
+
309
+ test("returns the newest event per (event, data.field) and confirms the mode", async () => {
310
+ const { status, body } = await get(
311
+ `/api/events?events=system.profile_sync_rejected,system.profile_sync_reconciled&dataFields=soulMd,claudeMd,toolsMd,identityMd&agentId=${AGENT}&latestPerDataField=true`,
312
+ );
313
+ expect(status).toBe(200);
314
+ expect(body.latestPerDataField).toBe(true);
315
+ const returned = (body.events as { id: string }[]).map((event) => event.id);
316
+ expect(returned).toEqual([
317
+ ids["soul-rejected"],
318
+ ids["claude-reconciled"],
319
+ ids["tools-new"],
320
+ ids["soul-reconciled"],
321
+ ids["claude-rejected"],
322
+ ]);
323
+ });
324
+
325
+ test("a single-event request keeps today's response shape", async () => {
326
+ const { status, body } = await get(
327
+ `/api/events?event=system.profile_sync_rejected&agentId=${AGENT}&dataField=toolsMd&limit=1`,
328
+ );
329
+ expect(status).toBe(200);
330
+ expect(Object.keys(body)).toEqual(["events"]);
331
+ expect((body.events as { id: string }[]).map((event) => event.id)).toEqual([ids["tools-new"]]);
332
+ });
333
+
334
+ test("rejects an unknown name in events", async () => {
335
+ const { status } = await get("/api/events?events=system.profile_sync_rejected,not.an.event");
336
+ expect(status).toBe(400);
337
+ });
338
+
339
+ test("rejects latestPerDataField without dataFields", async () => {
340
+ const { status } = await get(
341
+ "/api/events?events=system.profile_sync_rejected&latestPerDataField=true",
342
+ );
343
+ expect(status).toBe(400);
344
+ });
345
+
346
+ test("the profile-sync banner is identical through one batched call and 8 lookups", async () => {
347
+ const config = { apiUrl: BASE, apiKey: TEST_API_KEY, agentId: AGENT };
348
+ const eventRequests: string[] = [];
349
+ const recording = (async (input: string | URL | Request, init?: RequestInit) => {
350
+ const url = new URL(String(input));
351
+ if (url.pathname === "/api/events") eventRequests.push(url.search);
352
+ return fetch(input, init);
353
+ }) as typeof fetch;
354
+ // Simulates an API that predates latestPerDataField: drop the confirmation.
355
+ const legacy = (async (input: string | URL | Request, init?: RequestInit) => {
356
+ const response = await recording(input, init);
357
+ if (!new URL(String(input)).searchParams.has("latestPerDataField")) return response;
358
+ const { latestPerDataField: _dropped, ...rest } = await response.json();
359
+ return new Response(JSON.stringify(rest), { status: response.status });
360
+ }) as typeof fetch;
361
+
362
+ const batched = await fetchProfileSyncRejectionBanner(config, recording);
363
+ const batchedCalls = eventRequests.length;
364
+ eventRequests.length = 0;
365
+ const perField = await fetchProfileSyncRejectionBanner(config, legacy);
366
+
367
+ expect(batchedCalls).toBe(1);
368
+ expect(eventRequests).toHaveLength(9);
369
+ expect(batched).toContain(ids["tools-new"] ?? "missing");
370
+ expect(batched).toContain(ids["soul-rejected"] ?? "missing");
371
+ expect(batched).not.toContain(ids["claude-rejected"] ?? "missing");
372
+ expect(batched).toBe(perField);
373
+ });
374
+ });
375
+
273
376
  describe("GET /api/events/counts", () => {
274
377
  test("returns counts grouped by event name", async () => {
275
378
  const { status, body } = await get("/api/events/counts");
@@ -32,23 +32,28 @@ afterEach(async () => {
32
32
  });
33
33
 
34
34
  describe("predefined extension catalog", () => {
35
- test("every bundled entry passes the manifest schema and bundle validation", async () => {
36
- const catalog = getExtensionCatalog();
37
- expect(Object.keys(catalog).sort()).toEqual([
38
- "notify-on-complete",
39
- "require-ticket-ref",
40
- "require-verification-note",
41
- "task-digest",
42
- ]);
43
- for (const [name, entry] of Object.entries(catalog)) {
44
- expect(entry.manifest.name).toBe(name);
45
- expect(ExtensionManifestSchema.safeParse(entry.manifest).success).toBe(true);
46
- const result = await validateBundle({ manifest: entry.manifest, files: entry.files });
47
- expect(result).toMatchObject({ ok: true });
48
- }
49
- expect(getCatalogEntry("task-digest")?.manifestFile).toBe("manifest.yaml");
50
- expect(getCatalogEntry("toString")).toBeNull();
51
- });
35
+ test(
36
+ "every bundled entry passes the manifest schema and bundle validation",
37
+ async () => {
38
+ const catalog = getExtensionCatalog();
39
+ expect(Object.keys(catalog).sort()).toEqual([
40
+ "github-sender-allowlist",
41
+ "notify-on-complete",
42
+ "require-ticket-ref",
43
+ "require-verification-note",
44
+ "task-digest",
45
+ ]);
46
+ for (const [name, entry] of Object.entries(catalog)) {
47
+ expect(entry.manifest.name).toBe(name);
48
+ expect(ExtensionManifestSchema.safeParse(entry.manifest).success).toBe(true);
49
+ const result = await validateBundle({ manifest: entry.manifest, files: entry.files });
50
+ expect(result).toMatchObject({ ok: true });
51
+ }
52
+ expect(getCatalogEntry("task-digest")?.manifestFile).toBe("manifest.yaml");
53
+ expect(getCatalogEntry("toString")).toBeNull();
54
+ },
55
+ { timeout: 15_000 },
56
+ );
52
57
 
53
58
  test("the generator reads YAML and JSON templates and their referenced files", async () => {
54
59
  const dir = await templatesDir({
@@ -20,6 +20,7 @@ import {
20
20
  import * as dbClient from "../be/db-client";
21
21
  import type { InstallExtensionArgs as ExtensionInstallBody } from "../be/extensions/db";
22
22
  import { installExtension, listExtensionRuns } from "../be/extensions/db";
23
+ import { getCatalogEntry } from "../extensions/catalog";
23
24
  import { disableExtension, enableExtension, stopExtensionRuntime } from "../extensions/lifecycle";
24
25
  import { handleTasks } from "../http/tasks";
25
26
  import { dispatchScheduleTarget } from "../scheduler/scheduler";
@@ -168,6 +169,112 @@ describe("extension task boundaries", () => {
168
169
  expect(retried.status).toBe(201);
169
170
  });
170
171
 
172
+ test("GitHub sender allowlist separates internal and external senders", async () => {
173
+ const template = getCatalogEntry("github-sender-allowlist");
174
+ if (!template) throw new Error("github-sender-allowlist is missing from the catalog");
175
+ const installed = await installExtension({
176
+ manifest: template.manifest,
177
+ files: template.files,
178
+ config: {
179
+ internal: ["tarasyarema", "harlequinetcie"],
180
+ external: ["fuvidani", "capchase-bot"],
181
+ reviewBots: ["review-bot"],
182
+ },
183
+ });
184
+ await enableExtension(installed.extension.id);
185
+
186
+ const createFromGitHub = (
187
+ description: string,
188
+ vcsAuthor: string,
189
+ taskType: string,
190
+ vcsUrl: string,
191
+ source: "github" | "api" = "github",
192
+ ) =>
193
+ createTaskWithSiblingAwareness(
194
+ description,
195
+ { source, vcsAuthor, taskType, vcsUrl },
196
+ { origin: "webhook" },
197
+ );
198
+
199
+ await createFromGitHub(
200
+ "internal sender issue",
201
+ "HARLEQUINETCIE",
202
+ "github-issue",
203
+ "https://github.com/acme/project/issues/1",
204
+ );
205
+ await createFromGitHub(
206
+ "internal sender review",
207
+ "tarasyarema",
208
+ "github-review",
209
+ "https://github.com/acme/project/pull/2",
210
+ );
211
+ await createFromGitHub(
212
+ "external sender PR comment",
213
+ "FuViDaNi",
214
+ "github-comment",
215
+ "https://github.com/acme/project/pull/2",
216
+ );
217
+ await createFromGitHub(
218
+ "external sender PR assignment",
219
+ "capchase-bot",
220
+ "github-pr",
221
+ "https://github.com/acme/project/pull/3",
222
+ );
223
+ await createFromGitHub(
224
+ "external sender PR review",
225
+ "fuvidani",
226
+ "github-review",
227
+ "https://github.com/acme/project/pull/4",
228
+ );
229
+
230
+ await expect(
231
+ createFromGitHub(
232
+ "external sender issue comment",
233
+ "fuvidani",
234
+ "github-comment",
235
+ "https://github.com/acme/project/issues/5",
236
+ ),
237
+ ).rejects.toThrow('GitHub sender "fuvidani" is blocked: external senders are allowed only');
238
+ await expect(
239
+ createFromGitHub(
240
+ "unknown sender issue",
241
+ "unknown-user",
242
+ "github-issue",
243
+ "https://github.com/acme/project/issues/6",
244
+ ),
245
+ ).rejects.toThrow('GitHub sender "unknown-user" is blocked: sender is not on the internal');
246
+
247
+ await expect(
248
+ createFromGitHub(
249
+ "unknown sender review",
250
+ "unknown-user",
251
+ "github-review",
252
+ "https://github.com/acme/project/pull/7",
253
+ ),
254
+ ).rejects.toThrow('GitHub sender "unknown-user" is blocked: sender is not on the internal');
255
+ await createFromGitHub(
256
+ "review bot review",
257
+ "REVIEW-BOT",
258
+ "github-review",
259
+ "https://github.com/acme/project/pull/8",
260
+ );
261
+ await expect(
262
+ createFromGitHub(
263
+ "review bot PR comment",
264
+ "review-bot",
265
+ "github-comment",
266
+ "https://github.com/acme/project/pull/9",
267
+ ),
268
+ ).rejects.toThrow('GitHub sender "review-bot" is blocked: review bots are allowed only');
269
+ await createFromGitHub(
270
+ "non-GitHub source",
271
+ "unknown-user",
272
+ "github-issue",
273
+ "https://github.com/acme/project/issues/10",
274
+ "api",
275
+ );
276
+ });
277
+
171
278
  test("scheduler and workflow executor provide their task creation origins", async () => {
172
279
  const extension = await installSource(
173
280
  "record-task-origin",
@@ -0,0 +1,105 @@
1
+ {
2
+ "models": {
3
+ "deal": {
4
+ "columns": {
5
+ "title": { "kind": "string", "required": true },
6
+ "stage": { "kind": "enum", "enum": ["lead", "qualified", "won", "lost"], "default": "lead" },
7
+ "owner": { "kind": "string" },
8
+ "value": { "kind": "number" },
9
+ "closeDate": { "kind": "date" }
10
+ }
11
+ }
12
+ },
13
+ "queries": {
14
+ "deals": { "model": "deal", "sort": { "column": "createdAt", "dir": "desc" } },
15
+ "dealById": { "model": "deal", "filter": { "id": { "$param": "deal" } } }
16
+ },
17
+ "pages": {
18
+ "main": {
19
+ "params": { "deal": { "kind": "string" } },
20
+ "root": "root",
21
+ "elements": {
22
+ "root": {
23
+ "type": "Stack",
24
+ "props": { "gap": "lg" },
25
+ "children": ["board", "calendars", "activity", "dealDrawer"]
26
+ },
27
+ "board": {
28
+ "type": "Kanban",
29
+ "props": {
30
+ "data": { "$state": "/queries/deals/data" },
31
+ "loading": { "$state": "/queries/deals/loading" },
32
+ "columnField": "stage",
33
+ "columns": ["lead", "qualified", { "id": "won", "label": "Won" }, { "id": "lost", "label": "Lost" }],
34
+ "titleField": "title",
35
+ "cardFields": [
36
+ { "key": "owner", "label": "Owner" },
37
+ { "key": "value", "label": "Value", "kind": "number" }
38
+ ],
39
+ "onMove": [
40
+ {
41
+ "action": "app.mutate",
42
+ "params": {
43
+ "model": "deal",
44
+ "op": "update",
45
+ "rowId": { "$row": "id" },
46
+ "values": { "stage": { "$row": "stage" } }
47
+ }
48
+ }
49
+ ],
50
+ "onCardClick": [
51
+ { "action": "app.navigate", "params": { "page": "main", "params": { "deal": { "$row": "id" } } } }
52
+ ]
53
+ }
54
+ },
55
+ "calendars": { "type": "Grid", "props": { "columns": 2 }, "children": ["closeCalendar", "createdCalendar"] },
56
+ "closeCalendar": {
57
+ "type": "Calendar",
58
+ "props": {
59
+ "data": { "$state": "/queries/deals/data" },
60
+ "startField": "closeDate",
61
+ "titleField": "title",
62
+ "onSelect": [
63
+ { "action": "app.navigate", "params": { "page": "main", "params": { "deal": { "$row": "id" } } } }
64
+ ]
65
+ }
66
+ },
67
+ "createdCalendar": {
68
+ "type": "Calendar",
69
+ "props": {
70
+ "data": { "$state": "/queries/deals/data" },
71
+ "startField": "createdAt",
72
+ "endField": "closeDate",
73
+ "titleField": "title"
74
+ }
75
+ },
76
+ "activity": {
77
+ "type": "ContributionGraph",
78
+ "props": {
79
+ "data": { "$state": "/queries/deals/data" },
80
+ "dateField": "createdAt",
81
+ "countField": "value",
82
+ "days": 180
83
+ }
84
+ },
85
+ "dealDrawer": {
86
+ "type": "Drawer",
87
+ "props": { "param": "deal", "title": "Deal" },
88
+ "children": ["dealDetail"]
89
+ },
90
+ "dealDetail": {
91
+ "type": "DetailList",
92
+ "props": {
93
+ "data": { "$state": "/queries/dealById/data/0" },
94
+ "fields": [
95
+ { "key": "title" },
96
+ { "key": "stage", "kind": "badge" },
97
+ { "key": "closeDate", "kind": "date" }
98
+ ]
99
+ }
100
+ }
101
+ }
102
+ }
103
+ },
104
+ "defaultPage": "main"
105
+ }