@cohortapp/agent-sdk 2.16.0 → 2.18.4

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 (529) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +23 -7
  3. package/README.md +1 -0
  4. package/bin/maestro.mjs +62 -0
  5. package/docs/guides/billing-console-keys.md +60 -0
  6. package/docs/guides/front-door-session.md +54 -9
  7. package/docs/guides/mac-mini.md +20 -25
  8. package/docs/guides/poller-daemon-setup.md +4 -1
  9. package/docs/guides/setup-wizard.md +1 -1
  10. package/docs/runbooks/fleet-rollout.md +156 -0
  11. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  12. package/lib/action-executor.js +19 -3
  13. package/lib/budget-guard.mjs +279 -3
  14. package/lib/channels/base-adapter.mjs +3 -1
  15. package/lib/channels/contract.mjs +2 -1
  16. package/lib/channels/inbox-item.mjs +8 -0
  17. package/lib/claude-bin.mjs +5 -6
  18. package/lib/cli/doctor-checks.mjs +141 -10
  19. package/lib/cli/global-setup-extras.mjs +5 -1
  20. package/lib/cli/inbox.mjs +100 -15
  21. package/lib/cli/seat-auth.mjs +463 -0
  22. package/lib/cli/session.mjs +80 -12
  23. package/lib/collective/capture.mjs +8 -6
  24. package/lib/collective/global-config.mjs +63 -1
  25. package/lib/collective/presence.mjs +142 -5
  26. package/lib/comms/send-gate.mjs +559 -1
  27. package/lib/context/budget.mjs +327 -0
  28. package/lib/context/history-scope.mjs +138 -0
  29. package/lib/diagnostics/alerts.mjs +49 -0
  30. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  31. package/lib/engine/agents/definitions.mjs +343 -0
  32. package/lib/engine/agents/persist.mjs +275 -0
  33. package/lib/engine/agents/runtime.mjs +748 -0
  34. package/lib/engine/agents/usage.mjs +95 -0
  35. package/lib/engine/auth-status.mjs +139 -0
  36. package/lib/engine/budget.mjs +194 -0
  37. package/lib/engine/cli.mjs +1204 -0
  38. package/lib/engine/commands/index.mjs +269 -0
  39. package/lib/engine/context/budget.mjs +219 -0
  40. package/lib/engine/context/cache.mjs +125 -0
  41. package/lib/engine/context/child-env.mjs +215 -0
  42. package/lib/engine/context/compaction.mjs +342 -0
  43. package/lib/engine/context/images.mjs +90 -0
  44. package/lib/engine/context/instructions.mjs +327 -0
  45. package/lib/engine/context/lazy-instructions.mjs +169 -0
  46. package/lib/engine/context/manager.mjs +182 -0
  47. package/lib/engine/context/real-path.mjs +91 -0
  48. package/lib/engine/context/secret-values.mjs +163 -0
  49. package/lib/engine/context/settings.mjs +274 -0
  50. package/lib/engine/context/stream-input.mjs +159 -0
  51. package/lib/engine/guard.mjs +152 -0
  52. package/lib/engine/hooks.mjs +713 -0
  53. package/lib/engine/loop.mjs +560 -0
  54. package/lib/engine/mcp/client.mjs +254 -0
  55. package/lib/engine/mcp/config.mjs +301 -0
  56. package/lib/engine/mcp/http.mjs +201 -0
  57. package/lib/engine/mcp/index.mjs +146 -0
  58. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  59. package/lib/engine/mcp/naming.mjs +66 -0
  60. package/lib/engine/mcp/resources.mjs +89 -0
  61. package/lib/engine/mcp/results.mjs +133 -0
  62. package/lib/engine/mcp/stdio.mjs +137 -0
  63. package/lib/engine/mcp/supervisor.mjs +116 -0
  64. package/lib/engine/messages.mjs +104 -0
  65. package/lib/engine/output/json.mjs +164 -0
  66. package/lib/engine/output/stream-json.mjs +266 -0
  67. package/lib/engine/permissions.mjs +845 -0
  68. package/lib/engine/process-identity.mjs +164 -0
  69. package/lib/engine/process-tree.mjs +551 -0
  70. package/lib/engine/prompt.mjs +60 -0
  71. package/lib/engine/session/store.mjs +299 -0
  72. package/lib/engine/session-runtime/args.mjs +97 -0
  73. package/lib/engine/session-runtime/host.mjs +143 -0
  74. package/lib/engine/session-runtime/inbox.mjs +122 -0
  75. package/lib/engine/session-runtime/notifications.mjs +129 -0
  76. package/lib/engine/session-runtime/registry.mjs +328 -0
  77. package/lib/engine/session-runtime/runner.mjs +344 -0
  78. package/lib/engine/session-runtime/socket.mjs +212 -0
  79. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  80. package/lib/engine/skills/index.mjs +321 -0
  81. package/lib/engine/tools/bash-background.mjs +533 -0
  82. package/lib/engine/tools/bash.mjs +216 -0
  83. package/lib/engine/tools/edit.mjs +97 -0
  84. package/lib/engine/tools/glob.mjs +81 -0
  85. package/lib/engine/tools/grep.mjs +224 -0
  86. package/lib/engine/tools/index.mjs +84 -0
  87. package/lib/engine/tools/list-agents.mjs +32 -0
  88. package/lib/engine/tools/ls.mjs +127 -0
  89. package/lib/engine/tools/monitor.mjs +82 -0
  90. package/lib/engine/tools/notebook-edit.mjs +218 -0
  91. package/lib/engine/tools/read.mjs +103 -0
  92. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  93. package/lib/engine/tools/schema.mjs +144 -0
  94. package/lib/engine/tools/send-message.mjs +77 -0
  95. package/lib/engine/tools/session.mjs +70 -0
  96. package/lib/engine/tools/todo.mjs +144 -0
  97. package/lib/engine/tools/toolsearch.mjs +217 -0
  98. package/lib/engine/tools/walk.mjs +193 -0
  99. package/lib/engine/tools/web-switch.mjs +31 -0
  100. package/lib/engine/tools/webfetch-html.mjs +387 -0
  101. package/lib/engine/tools/webfetch-net.mjs +340 -0
  102. package/lib/engine/tools/webfetch.mjs +198 -0
  103. package/lib/engine/tools/websearch.mjs +91 -0
  104. package/lib/engine/tools/workflow.mjs +95 -0
  105. package/lib/engine/tools/write.mjs +76 -0
  106. package/lib/engine/tui/line-editor.mjs +137 -0
  107. package/lib/engine/tui/render.mjs +86 -0
  108. package/lib/engine/tui/tui.mjs +274 -0
  109. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  110. package/lib/engine/wire/effort.mjs +36 -0
  111. package/lib/engine/wire/errors.mjs +496 -0
  112. package/lib/engine/wire/http.mjs +441 -0
  113. package/lib/engine/wire/index.mjs +76 -0
  114. package/lib/engine/wire/openai-chat.mjs +332 -0
  115. package/lib/engine/wire/prompt-cache.mjs +79 -0
  116. package/lib/engine/wire/search.mjs +140 -0
  117. package/lib/engine/wire/sse.mjs +114 -0
  118. package/lib/engine/wire/stall.mjs +349 -0
  119. package/lib/engine/wire/token-provider.mjs +175 -0
  120. package/lib/engine/wire/usage.mjs +192 -0
  121. package/lib/engine/workflow/host.mjs +524 -0
  122. package/lib/engine/workflow/journal.mjs +188 -0
  123. package/lib/engine/workflow/json-schema.mjs +171 -0
  124. package/lib/engine/workflow/meta.mjs +329 -0
  125. package/lib/engine/workflow/notifications.mjs +52 -0
  126. package/lib/engine/workflow/runtime.mjs +447 -0
  127. package/lib/engine/workflow/sandbox.mjs +534 -0
  128. package/lib/engine/workflow/worker.mjs +141 -0
  129. package/lib/engine/workflow/worktree.mjs +74 -0
  130. package/lib/execution/disposition.mjs +1 -1
  131. package/lib/execution/intake.mjs +10 -0
  132. package/lib/execution/surface-policy.mjs +15 -0
  133. package/lib/learning/curator.mjs +8 -6
  134. package/lib/learning/reflect.mjs +8 -6
  135. package/lib/model-router/catalog/cohort.yaml +137 -0
  136. package/lib/model-router/catalog.mjs +118 -1
  137. package/lib/model-router/economics.mjs +9 -0
  138. package/lib/model-router/failover.mjs +67 -16
  139. package/lib/model-router/llm-task.mjs +39 -3
  140. package/lib/model-router/resolve.mjs +95 -3
  141. package/lib/model-router/spawn.mjs +46 -47
  142. package/lib/model-router/taxonomy.mjs +126 -4
  143. package/lib/org/cost-sync.mjs +141 -11
  144. package/lib/org/inbound/broadcast.mjs +289 -0
  145. package/lib/org/inbound/collective.mjs +375 -0
  146. package/lib/org/inbound/directedness.mjs +96 -8
  147. package/lib/org/inbound/facts.mjs +82 -4
  148. package/lib/org/inbound/hydrate.mjs +555 -51
  149. package/lib/org/inbound/project.mjs +22 -0
  150. package/lib/org/inbound/surfaces.mjs +14 -0
  151. package/lib/org/llm-token.mjs +879 -0
  152. package/lib/org/mesh.mjs +61 -0
  153. package/lib/org/messaging.mjs +3 -1
  154. package/lib/org/protocol.checksum +1 -1
  155. package/lib/org/protocol.mjs +15 -0
  156. package/lib/org/quota.mjs +520 -0
  157. package/lib/org/tool-surface.mjs +104 -16
  158. package/lib/org/ui-parity.mjs +16 -1
  159. package/lib/org/work-ledger.mjs +37 -6
  160. package/lib/rate-guard.mjs +114 -1
  161. package/lib/resource-governor.mjs +41 -6
  162. package/lib/runtime/adapter.mjs +823 -0
  163. package/lib/runtime/child-env.mjs +191 -0
  164. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  165. package/lib/runtime/seat-engine.mjs +162 -0
  166. package/lib/session/ask-ledger.mjs +271 -0
  167. package/lib/session/current-work.mjs +676 -0
  168. package/lib/session/feed-core.mjs +40 -3
  169. package/lib/session/launch-args.mjs +56 -4
  170. package/lib/session/status-summary.mjs +26 -9
  171. package/lib/session/upgrade-notice.mjs +42 -0
  172. package/lib/setup/claude-probe.mjs +117 -13
  173. package/lib/setup/enrich.mjs +13 -10
  174. package/lib/setup/sections/model.mjs +39 -13
  175. package/lib/telemetry/collect.mjs +208 -9
  176. package/lib/upgrade/ignored-drift.mjs +105 -0
  177. package/lib/voice/post-call-brief.mjs +30 -17
  178. package/package.json +15 -3
  179. package/plugins/maestro-skills/skills/board-work.md +5 -0
  180. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  181. package/plugins/maestro-skills/skills/main-session.md +18 -7
  182. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  183. package/scripts/ci/run-tests.mjs +47 -19
  184. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  185. package/scripts/collective/hook-runner.mjs +29 -2
  186. package/scripts/continuous-monitor.sh +13 -0
  187. package/scripts/cost/track-claude-usage.mjs +15 -0
  188. package/scripts/daemon/agent-daemon.mjs +408 -20
  189. package/scripts/daemon/assurance.mjs +48 -12
  190. package/scripts/daemon/cadence-consumer.mjs +218 -68
  191. package/scripts/daemon/cadence-handlers.mjs +73 -4
  192. package/scripts/daemon/classifier.mjs +75 -26
  193. package/scripts/daemon/context-compiler.mjs +104 -59
  194. package/scripts/daemon/deliver.mjs +30 -1
  195. package/scripts/daemon/dispatcher.mjs +804 -157
  196. package/scripts/daemon/health.mjs +14 -1
  197. package/scripts/daemon/lib/session-router.mjs +310 -42
  198. package/scripts/daemon/maestro-daemon.mjs +11 -0
  199. package/scripts/daemon/prompt-builder.mjs +121 -12
  200. package/scripts/daemon/responder.mjs +315 -146
  201. package/scripts/daemon/sdk-version.mjs +98 -16
  202. package/scripts/eval/probe-gateway.mjs +635 -0
  203. package/scripts/eval/replay/extract.mjs +270 -0
  204. package/scripts/eval/replay/grade.mjs +260 -0
  205. package/scripts/eval/replay/lib/config.mjs +50 -0
  206. package/scripts/eval/replay/lib/effects.mjs +65 -0
  207. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  208. package/scripts/eval/replay/lib/judge.mjs +72 -0
  209. package/scripts/eval/replay/lib/redact.mjs +136 -0
  210. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  211. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  212. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  213. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  214. package/scripts/eval/replay/report.mjs +185 -0
  215. package/scripts/eval/replay/run.mjs +404 -0
  216. package/scripts/fleet/rollout.mjs +1094 -0
  217. package/scripts/hooks/pre-send-audit.sh +36 -245
  218. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  219. package/scripts/hooks/validate-state-yaml.sh +190 -0
  220. package/scripts/huddle/huddle-llm.mjs +361 -0
  221. package/scripts/huddle/huddle-server.mjs +46 -121
  222. package/scripts/local-triggers/autoupdate.sh +448 -78
  223. package/scripts/local-triggers/run-trigger.sh +13 -0
  224. package/scripts/maintenance/pin-integrity.mjs +364 -0
  225. package/scripts/poll-slack-events.sh +41 -9
  226. package/scripts/poller/slack-socket-mode.mjs +28 -3
  227. package/scripts/session/supervisor.mjs +80 -13
  228. package/scripts/spawn-session.sh +13 -0
  229. package/bin/maestro.test.mjs +0 -1574
  230. package/lib/action-executor.test.mjs +0 -871
  231. package/lib/archetype.test.mjs +0 -132
  232. package/lib/assurance/plan-note.test.mjs +0 -234
  233. package/lib/assurance/room-budget.test.mjs +0 -486
  234. package/lib/assurance/tier.test.mjs +0 -174
  235. package/lib/autonomy.test.mjs +0 -66
  236. package/lib/backlog.test.mjs +0 -302
  237. package/lib/backup/policy.test.mjs +0 -305
  238. package/lib/budget-escalate.test.mjs +0 -232
  239. package/lib/budget-guard.envelope.test.mjs +0 -476
  240. package/lib/budget-guard.test.mjs +0 -427
  241. package/lib/cadence-bus-requeue.test.mjs +0 -83
  242. package/lib/cadence-bus-schedule.test.mjs +0 -194
  243. package/lib/cadence-bus.test.mjs +0 -720
  244. package/lib/cadences.test.mjs +0 -230
  245. package/lib/capability/inventory.test.mjs +0 -232
  246. package/lib/capability.test.mjs +0 -78
  247. package/lib/channels/base-adapter.test.mjs +0 -590
  248. package/lib/channels/channels.test.mjs +0 -371
  249. package/lib/channels/contract.test.mjs +0 -162
  250. package/lib/channels/inbox-item.test.mjs +0 -368
  251. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  252. package/lib/channels/pairing.test.mjs +0 -270
  253. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  254. package/lib/channels/slack-adapter.test.mjs +0 -212
  255. package/lib/channels/telegram-adapter.test.mjs +0 -306
  256. package/lib/channels/voice/adapter.test.mjs +0 -278
  257. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  258. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  259. package/lib/charter.test.mjs +0 -89
  260. package/lib/claude-bin.test.mjs +0 -131
  261. package/lib/cli/board.test.mjs +0 -227
  262. package/lib/cli/design.test.mjs +0 -270
  263. package/lib/cli/doctor-checks.test.mjs +0 -336
  264. package/lib/cli/global-setup-extras.test.mjs +0 -462
  265. package/lib/cli/inbox.test.mjs +0 -230
  266. package/lib/cli/session-ack.test.mjs +0 -63
  267. package/lib/cli/session.test.mjs +0 -613
  268. package/lib/collective/capture.test.mjs +0 -121
  269. package/lib/collective/cards.test.mjs +0 -114
  270. package/lib/collective/config.test.mjs +0 -123
  271. package/lib/collective/global-config.test.mjs +0 -220
  272. package/lib/collective/global-skills.test.mjs +0 -126
  273. package/lib/collective/presence.test.mjs +0 -95
  274. package/lib/collective/recall.test.mjs +0 -116
  275. package/lib/collective/vendor-skills.test.mjs +0 -306
  276. package/lib/comms/send-gate.test.mjs +0 -770
  277. package/lib/comms.test.mjs +0 -41
  278. package/lib/cost/ledger-row.test.mjs +0 -183
  279. package/lib/design/design-md.test.mjs +0 -318
  280. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  281. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  282. package/lib/design/fixtures/foundation.json +0 -133
  283. package/lib/design/refresh-gate.test.mjs +0 -144
  284. package/lib/design/write.test.mjs +0 -241
  285. package/lib/diagnostics/alerts.test.mjs +0 -318
  286. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  287. package/lib/diagnostics/counters.test.mjs +0 -206
  288. package/lib/diagnostics/events.test.mjs +0 -290
  289. package/lib/diagnostics/otel.test.mjs +0 -196
  290. package/lib/diagnostics/trace.test.mjs +0 -251
  291. package/lib/env-compat.test.mjs +0 -104
  292. package/lib/execution/disposition.test.mjs +0 -553
  293. package/lib/execution/drive.test.mjs +0 -270
  294. package/lib/execution/effects.test.mjs +0 -344
  295. package/lib/execution/intake.test.mjs +0 -389
  296. package/lib/execution/journal.test.mjs +0 -261
  297. package/lib/execution/match.test.mjs +0 -235
  298. package/lib/execution/pipeline.test.mjs +0 -392
  299. package/lib/execution/route.test.mjs +0 -186
  300. package/lib/execution/surface-policy.test.mjs +0 -162
  301. package/lib/fs-atomic.test.mjs +0 -72
  302. package/lib/fs-ownership.test.mjs +0 -158
  303. package/lib/goals/admission.test.mjs +0 -164
  304. package/lib/goals/classify.test.mjs +0 -167
  305. package/lib/goals/collaborate.test.mjs +0 -336
  306. package/lib/goals/gaps.test.mjs +0 -284
  307. package/lib/goals/loop.test.mjs +0 -845
  308. package/lib/hooks/bus.test.mjs +0 -387
  309. package/lib/identity/persona.test.mjs +0 -142
  310. package/lib/kpi-sensors.test.mjs +0 -278
  311. package/lib/kpi.test.mjs +0 -244
  312. package/lib/learning/config.test.mjs +0 -75
  313. package/lib/learning/counters.test.mjs +0 -69
  314. package/lib/learning/curator-consolidate.test.mjs +0 -238
  315. package/lib/learning/curator.test.mjs +0 -106
  316. package/lib/learning/reflect.test.mjs +0 -0
  317. package/lib/learning/session-index.test.mjs +0 -125
  318. package/lib/learning/skill-writer.test.mjs +0 -210
  319. package/lib/mandate/audit.test.mjs +0 -195
  320. package/lib/mandate/contract.test.mjs +0 -185
  321. package/lib/mandate/derive.test.mjs +0 -274
  322. package/lib/mandate/model.test.mjs +0 -164
  323. package/lib/mandate/refresh.test.mjs +0 -389
  324. package/lib/mcp/server.test.mjs +0 -426
  325. package/lib/model-router/auth-profiles.test.mjs +0 -580
  326. package/lib/model-router/catalog.test.mjs +0 -385
  327. package/lib/model-router/economics.test.mjs +0 -438
  328. package/lib/model-router/failover.test.mjs +0 -439
  329. package/lib/model-router/health.test.mjs +0 -338
  330. package/lib/model-router/integration-coverage.test.mjs +0 -831
  331. package/lib/model-router/integration.test.mjs +0 -564
  332. package/lib/model-router/ledger.test.mjs +0 -415
  333. package/lib/model-router/llm-task.test.mjs +0 -392
  334. package/lib/model-router/org-credentials.test.mjs +0 -265
  335. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  336. package/lib/model-router/reconcile.test.mjs +0 -316
  337. package/lib/model-router/repair.test.mjs +0 -180
  338. package/lib/model-router/spawn.test.mjs +0 -446
  339. package/lib/model-router/taxonomy.test.mjs +0 -410
  340. package/lib/model-router.test.mjs +0 -1207
  341. package/lib/org/activity.test.mjs +0 -134
  342. package/lib/org/approvals.test.mjs +0 -216
  343. package/lib/org/awareness.test.mjs +0 -159
  344. package/lib/org/board-mine-cache.test.mjs +0 -53
  345. package/lib/org/board.test.mjs +0 -187
  346. package/lib/org/bootstrap-context.test.mjs +0 -153
  347. package/lib/org/client.test.mjs +0 -1206
  348. package/lib/org/cohort-client.test.mjs +0 -126
  349. package/lib/org/cost-sync.test.mjs +0 -153
  350. package/lib/org/doctor.test.mjs +0 -346
  351. package/lib/org/engagement-ledger.test.mjs +0 -112
  352. package/lib/org/engagement.test.mjs +0 -739
  353. package/lib/org/handoff.test.mjs +0 -269
  354. package/lib/org/inbound/directedness.test.mjs +0 -668
  355. package/lib/org/inbound/facts.test.mjs +0 -471
  356. package/lib/org/inbound/hydrate.test.mjs +0 -453
  357. package/lib/org/inbound/index.test.mjs +0 -429
  358. package/lib/org/inbound/project.test.mjs +0 -287
  359. package/lib/org/integration-tools.test.mjs +0 -160
  360. package/lib/org/keys.test.mjs +0 -92
  361. package/lib/org/knowledge.test.mjs +0 -326
  362. package/lib/org/leases.test.mjs +0 -235
  363. package/lib/org/mesh-directives.test.mjs +0 -110
  364. package/lib/org/mesh-integration.test.mjs +0 -127
  365. package/lib/org/mesh.test.mjs +0 -400
  366. package/lib/org/messaging.test.mjs +0 -471
  367. package/lib/org/param-contract.test.mjs +0 -477
  368. package/lib/org/policy.test.mjs +0 -237
  369. package/lib/org/protocol.checksum.test.mjs +0 -90
  370. package/lib/org/protocol.test.mjs +0 -323
  371. package/lib/org/push.test.mjs +0 -792
  372. package/lib/org/registry.test.mjs +0 -100
  373. package/lib/org/resource-tools.test.mjs +0 -361
  374. package/lib/org/tool-access.test.mjs +0 -144
  375. package/lib/org/tool-surface-integration.test.mjs +0 -120
  376. package/lib/org/tool-surface.test.mjs +0 -1268
  377. package/lib/org/typing.test.mjs +0 -291
  378. package/lib/org/ui-parity.test.mjs +0 -560
  379. package/lib/org/verify.test.mjs +0 -194
  380. package/lib/org/work-ledger.test.mjs +0 -273
  381. package/lib/plan/adoption-e2e.test.mjs +0 -366
  382. package/lib/plan/budget-enforcement.test.mjs +0 -400
  383. package/lib/plan/compile.test.mjs +0 -382
  384. package/lib/plan/emit.test.mjs +0 -269
  385. package/lib/plan/explain.test.mjs +0 -188
  386. package/lib/prompts/parallelism.test.mjs +0 -177
  387. package/lib/rag/rag.test.mjs +0 -505
  388. package/lib/rate-guard.test.mjs +0 -272
  389. package/lib/reactive-gate.test.mjs +0 -57
  390. package/lib/render.test.mjs +0 -68
  391. package/lib/resource-governor.test.mjs +0 -488
  392. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  393. package/lib/scheduling/jitter.test.mjs +0 -140
  394. package/lib/secrets/broker.test.mjs +0 -280
  395. package/lib/secrets/providers.test.mjs +0 -274
  396. package/lib/security/audit-engine.test.mjs +0 -424
  397. package/lib/security/coerce-args.test.mjs +0 -281
  398. package/lib/security/dangerous-tools.test.mjs +0 -68
  399. package/lib/security/external-content.test.mjs +0 -84
  400. package/lib/security/redact.test.mjs +0 -441
  401. package/lib/security/secret-equal.test.mjs +0 -55
  402. package/lib/session/config.test.mjs +0 -92
  403. package/lib/session/feed-core.test.mjs +0 -198
  404. package/lib/session/first-run.test.mjs +0 -121
  405. package/lib/session/frontdoor.test.mjs +0 -205
  406. package/lib/session/handoffs.test.mjs +0 -183
  407. package/lib/session/identity.test.mjs +0 -180
  408. package/lib/session/inbox-claims.test.mjs +0 -286
  409. package/lib/session/launch-args.test.mjs +0 -157
  410. package/lib/session/liveness.test.mjs +0 -100
  411. package/lib/session/status-summary.test.mjs +0 -118
  412. package/lib/session-permissions.test.mjs +0 -120
  413. package/lib/setup/claude-probe.test.mjs +0 -187
  414. package/lib/setup/completeness.test.mjs +0 -110
  415. package/lib/setup/context-pack.test.mjs +0 -89
  416. package/lib/setup/enrich.test.mjs +0 -115
  417. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  418. package/lib/setup/integration.test.mjs +0 -162
  419. package/lib/setup/io.test.mjs +0 -77
  420. package/lib/setup/runner.test.mjs +0 -132
  421. package/lib/setup/sections/identity.test.mjs +0 -234
  422. package/lib/setup/sections/inventory.test.mjs +0 -198
  423. package/lib/setup/sections/learning.test.mjs +0 -81
  424. package/lib/setup/sections/mandate.test.mjs +0 -388
  425. package/lib/setup/sections/messaging.test.mjs +0 -127
  426. package/lib/setup/sections/model.test.mjs +0 -240
  427. package/lib/setup/sections/org.test.mjs +0 -346
  428. package/lib/setup/sections/orgmail.test.mjs +0 -118
  429. package/lib/setup/sections/recovery.test.mjs +0 -98
  430. package/lib/setup/sections/subagents.test.mjs +0 -429
  431. package/lib/setup/sections/verify.test.mjs +0 -175
  432. package/lib/setup/sot.test.mjs +0 -81
  433. package/lib/setup/state.test.mjs +0 -115
  434. package/lib/singleton.test.mjs +0 -151
  435. package/lib/subagents/cli.test.mjs +0 -389
  436. package/lib/subagents/client.test.mjs +0 -309
  437. package/lib/subagents/gap.test.mjs +0 -234
  438. package/lib/subagents/lock.test.mjs +0 -248
  439. package/lib/subagents/manifest.test.mjs +0 -175
  440. package/lib/subagents/refs.test.mjs +0 -204
  441. package/lib/subagents/resolve.test.mjs +0 -422
  442. package/lib/subagents/schema.test.mjs +0 -328
  443. package/lib/telemetry/alerts.test.mjs +0 -109
  444. package/lib/telemetry/collect.test.mjs +0 -1274
  445. package/lib/tool-definitions-integration.test.mjs +0 -83
  446. package/lib/tool-definitions.test.mjs +0 -437
  447. package/lib/upgrade/global-refresh.test.mjs +0 -65
  448. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  449. package/lib/upgrade/post-steps.test.mjs +0 -200
  450. package/lib/upgrade/verify.test.mjs +0 -164
  451. package/lib/util/fetch-timeout.test.mjs +0 -202
  452. package/lib/util/reconnect.test.mjs +0 -369
  453. package/lib/util/unhandled.test.mjs +0 -216
  454. package/lib/voice/outbound.test.mjs +0 -69
  455. package/lib/voice/session-rotation.test.mjs +0 -114
  456. package/lib/voice/stt.test.mjs +0 -226
  457. package/lib/voice/voice.test.mjs +0 -990
  458. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  459. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  460. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  461. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  462. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  463. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  464. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  465. package/scripts/ci/check.test.mjs +0 -194
  466. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  467. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  468. package/scripts/collective/hook-runner.test.mjs +0 -173
  469. package/scripts/cost/fleet-digest.test.mjs +0 -207
  470. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  471. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  472. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  473. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  474. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  475. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  476. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  477. package/scripts/daemon/assurance.test.mjs +0 -1791
  478. package/scripts/daemon/board-mirror.test.mjs +0 -165
  479. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  480. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  481. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  482. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  483. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  484. package/scripts/daemon/classifier.test.mjs +0 -266
  485. package/scripts/daemon/classify-kind.test.mjs +0 -40
  486. package/scripts/daemon/context-compiler.test.mjs +0 -300
  487. package/scripts/daemon/deliver.test.mjs +0 -564
  488. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  489. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  490. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  491. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  492. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  493. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  494. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  495. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  496. package/scripts/daemon/integration.test.mjs +0 -149
  497. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  498. package/scripts/daemon/lib/session-router.test.mjs +0 -295
  499. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  500. package/scripts/daemon/prompt-builder.test.mjs +0 -344
  501. package/scripts/daemon/responder-cost.test.mjs +0 -68
  502. package/scripts/daemon/responder-history.test.mjs +0 -185
  503. package/scripts/daemon/sdk-version.test.mjs +0 -31
  504. package/scripts/daemon/session-lock.test.mjs +0 -252
  505. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  506. package/scripts/daemon/typing-registry.test.mjs +0 -102
  507. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  508. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  509. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  510. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  511. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  512. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  513. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  514. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  515. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  516. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  517. package/scripts/poller-launchd/install.test.mjs +0 -243
  518. package/scripts/restore-from-backup.test.mjs +0 -181
  519. package/scripts/session/feed.test.mjs +0 -196
  520. package/scripts/session/supervisor-sh.test.mjs +0 -218
  521. package/scripts/session/supervisor.test.mjs +0 -482
  522. package/scripts/setup/configure-macos.test.mjs +0 -306
  523. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  524. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  525. package/scripts/setup/generate-capability.test.mjs +0 -134
  526. package/scripts/setup/init-agent.test.mjs +0 -370
  527. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  528. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  529. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -31,6 +31,10 @@ a slower reply, never a dropped one.
31
31
  counts open handoffs and board items from `state/org/board-mine.json`, the
32
32
  daemon's five-minute cache — when that file is missing the count is 0 and
33
33
  you run `maestro board mine` yourself.
34
+ `maestro session status` (and the `session_status` tool) also carries
35
+ `currentWork` — what is running, queued and blocked across your sessions on
36
+ this machine; a "what are you doing right now?" is answered from that, not
37
+ from memory.
34
38
 
35
39
  3. Drain what is already waiting: `maestro inbox list --new`, then
36
40
  `maestro session handoffs` — anything there arrived while you were down.
@@ -43,12 +47,14 @@ Each line is a JSON object with a `type`. Handle it in the turn it arrives.
43
47
 
44
48
  - `inbound` — `{id, surface, topic, from, channelId, threadId, preview, path}`.
45
49
  `maestro inbox show <id>` for the full item, then follow the
46
- `inbound-triage` skill: reply now, or `maestro board track <id> --stage
47
- accepted` + work it, or spawn a peer. Saying something BEFORE the answer is
48
- the exception, not the rule — see that skill's one-interim rule. Claim it first
49
- (`maestro inbox claim <id>`) so the daemon's sweep does not re-deliver it,
50
- reply with `maestro inbox reply <id> --text "…"`, and close with
51
- `maestro inbox done <id>`. The reply command is the reply lane: it runs the
50
+ `inbound-triage` skill: reply now, work it here, or spawn a peer. Saying
51
+ something BEFORE the answer is the exception, not the rule — see that skill's
52
+ one-interim rule. Claim it first (`maestro inbox claim <id>`) so the daemon's
53
+ sweep does not re-deliver it, reply with `maestro inbox reply <id> --text "…"`,
54
+ and close with `maestro inbox done <id>`. Those four commands ALSO write the
55
+ ask's board row — open, running, closed, channel tagged — so there is no
56
+ separate `board track` step to remember; the server's gate decides whether a
57
+ given ask earns a row at all. The reply command is the reply lane: it runs the
52
58
  outbound gate — banned phrases, disclosure, barriers and the persona check —
53
59
  in-process before anything is sent. In the agent directory the
54
60
  `messaging_send` tool is blocked by the repo's own hook; do not try to route
@@ -62,7 +68,12 @@ Each line is a JSON object with a `type`. Handle it in the turn it arrives.
62
68
  the old way, so ack promptly and never twice.
63
69
  - `directive` — `restart`: finish the current turn, then `maestro session
64
70
  restart` (the supervisor brings you back on the same session id).
65
- `upgrade-available`: same, at the next idle moment. `daemon-stale`: the
71
+ `upgrade-available`: same, at the next idle moment. `daemon-unhealthy`:
72
+ NOT a restart cue — the hourly autoupdate is reporting the daemon unhealthy
73
+ on the version already installed (`detail.notice.reason` says why: crash
74
+ loop, fatal line, or the org rejecting its beat); there is nothing to
75
+ restart onto, so keep your context, tell your principal and run `maestro
76
+ doctor`. `daemon-stale`: the
66
77
  daemon has not beaten for 5 minutes; say so to your principal if it persists
67
78
  past a second event, and keep working — the feed still delivers what is on
68
79
  disk.
@@ -16,6 +16,12 @@
16
16
  * pack/install; cf. the broken `validate_outbound.py` cross-tenant link).
17
17
  * 3. Requireability — the package main (exports["."], default lib/index.js)
18
18
  * is present in the extracted tree, so a consumer's `import` resolves.
19
+ * 4. No tests or fixtures (CF-15) — `*.test.mjs`, `fixtures/`, `test-fixtures/`,
20
+ * `test/` and the replay examples are negated in files[] and must not ship;
21
+ * every relative import/require/`new URL(…, import.meta.url)` in the
22
+ * packaged JS that names a file in the source tree names a packaged file;
23
+ * and every exports[] module and lib/**\/index imports from the extracted
24
+ * tarball (with the source tree's node_modules linked in after the walk).
19
25
  *
20
26
  * This is a SLOW check (it shells out to `npm pack` and `tar`), so it is wired
21
27
  * as its own opt-in npm script (`npm run test:pack`) and is NOT part of the
@@ -37,6 +43,7 @@ import {
37
43
  readdirSync,
38
44
  lstatSync,
39
45
  existsSync,
46
+ symlinkSync,
40
47
  } from "node:fs";
41
48
  import { tmpdir } from "node:os";
42
49
  import path from "node:path";
@@ -50,8 +57,98 @@ export const FORBIDDEN_PATTERNS = [
50
57
  { label: "python bytecode (*.pyc)", re: /\.pyc$/ },
51
58
  { label: "python bytecode (*.pyo)", re: /\.pyo$/ },
52
59
  { label: "bytecode cache dir (__pycache__)", re: /(^|\/)__pycache__(\/|$)/ },
60
+ // CF-15 (W5): tests and their fixtures are not runtime; package.json files[] negates them.
61
+ { label: "test file (*.test.mjs / *.test.js)", re: /\.test\.(mjs|js|cjs)$/ },
62
+ { label: "test fixture directory", re: /(^|\/)(fixtures|test-fixtures|__fixtures__)\// },
63
+ { label: "test directory (test/)", re: /^test\// },
64
+ { label: "eval example fixtures", re: /^scripts\/eval\/replay\/examples\// },
53
65
  ];
54
66
 
67
+ /**
68
+ * Relative module and file references in a JS source: static `import`/`export … from`,
69
+ * literal `import("…")` and `require("…")`, and `new URL("…", import.meta.url)` naming a
70
+ * file (with an extension). Pure.
71
+ * @param {string} source
72
+ * @returns {string[]} the relative specifiers, as written
73
+ */
74
+ export function relativeReferences(source) {
75
+ const out = new Set();
76
+ const patterns = [
77
+ /\b(?:import|export)\s[^'"`;]*?\bfrom\s*["'](\.{1,2}\/[^"']+)["']/g,
78
+ /\bimport\s*["'](\.{1,2}\/[^"']+)["']/g,
79
+ /\bimport\(\s*["'](\.{1,2}\/[^"']+)["']\s*\)/g,
80
+ /\brequire\(\s*["'](\.{1,2}\/[^"']+)["']\s*\)/g,
81
+ /\bnew URL\(\s*["'](\.{1,2}\/[^"']*\.[A-Za-z0-9]+)["']\s*,\s*import\.meta\.url\s*\)/g,
82
+ ];
83
+ for (const re of patterns) for (const m of source.matchAll(re)) out.add(m[1]);
84
+ return [...out];
85
+ }
86
+
87
+ /**
88
+ * Every relative reference in the packaged JS that resolves to a file present in
89
+ * the source tree but absent from the tarball — a runtime path the packaging
90
+ * cut off. References that do not resolve in the source tree either (optional,
91
+ * generated or seat-local files) are not a packaging fault and are not reported.
92
+ * Comment lines are skipped. Pure over its inputs.
93
+ * @param {{files:string[], read:(rel:string)=>string, existsInSource:(rel:string)=>boolean}} p
94
+ * @returns {Array<{file:string, ref:string, target:string}>}
95
+ */
96
+ export function brokenPackagedReferences({ files, read, existsInSource }) {
97
+ const shipped = new Set(files);
98
+ const broken = [];
99
+ for (const file of files) {
100
+ if (!/\.(mjs|js|cjs)$/.test(file)) continue;
101
+ const source = read(file)
102
+ .split("\n")
103
+ .filter((l) => !/^\s*(\/\/|\*|\/\*)/.test(l))
104
+ .join("\n");
105
+ for (const ref of relativeReferences(source)) {
106
+ const target = path.posix.normalize(path.posix.join(path.posix.dirname(file), ref));
107
+ if (shipped.has(target) || !existsInSource(target)) continue;
108
+ broken.push({ file, ref, target });
109
+ }
110
+ }
111
+ return broken;
112
+ }
113
+
114
+ /**
115
+ * The modules a consumer (or the CLI) imports by name: every exports[] target
116
+ * that is JavaScript, and every lib/**\/index.(mjs|js). Pure.
117
+ * @param {object} pkg @param {string[]} files
118
+ */
119
+ export function smokeImportTargets(pkg, files) {
120
+ const fromExports = Object.values((pkg && pkg.exports) || {})
121
+ .map((v) => (typeof v === "string" ? v : v && (v.import || v.default)))
122
+ .filter((v) => typeof v === "string" && /\.(mjs|js)$/.test(v))
123
+ .map((v) => v.replace(/^\.\//, ""));
124
+ const indexes = files.filter((f) => /^lib\/(.+\/)?index\.(mjs|js)$/.test(f));
125
+ return [...new Set([...fromExports, ...indexes])].sort();
126
+ }
127
+
128
+ /**
129
+ * Import each module in a child node process run in `root`; returns the ones that
130
+ * failed, with the first line of the error. Bounded by `timeoutMs`.
131
+ * @param {string} root @param {string[]} modules @param {number} [timeoutMs]
132
+ * @returns {Array<{module:string, error:string}>}
133
+ */
134
+ export function smokeImport(root, modules, timeoutMs = 180_000) {
135
+ const script = [
136
+ "const mods = JSON.parse(process.argv[1]);",
137
+ "const failed = [];",
138
+ "for (const m of mods) { try { await import(new URL(m, 'file://' + process.cwd() + '/').href); } catch (e) { failed.push({ module: m, error: String((e && e.message) || e).split('\\n')[0] }); } }",
139
+ "process.stdout.write(JSON.stringify(failed));",
140
+ "process.exit(0);",
141
+ ].join("\n");
142
+ const env = { PATH: process.env.PATH || "/usr/bin:/bin", HOME: mkdtempSync(path.join(tmpdir(), "maestro-pack-home-")), NODE_ENV: "production" };
143
+ try {
144
+ const out = execFileSync(process.execPath, ["--input-type=module", "-e", script, JSON.stringify(modules)], { cwd: root, env, encoding: "utf8", timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
145
+ const last = out.trim().split("\n").pop() || "[]";
146
+ return JSON.parse(last);
147
+ } finally {
148
+ try { rmSync(env.HOME, { recursive: true, force: true }); } catch { /* */ }
149
+ }
150
+ }
151
+
55
152
  /**
56
153
  * The "main" file a consumer's bare `import "@cohortapp/agent-sdk"` resolves to.
57
154
  * Falls back to lib/index.js (the documented default) when exports["."] is odd.
@@ -146,9 +243,11 @@ export function checkTarball(opts = {}) {
146
243
 
147
244
  // 4) Completeness — every files[] entry must be represented. A directory
148
245
  // entry (e.g. "lib/") is satisfied by any packaged path beneath it; a
149
- // file entry must appear verbatim.
246
+ // file entry must appear verbatim. A negation ("!**/*.test.mjs") removes
247
+ // paths rather than declaring them (CF-15), so it has nothing to find.
150
248
  const missing = [];
151
249
  for (const decl of filesAllowlist) {
250
+ if (typeof decl !== "string" || decl.startsWith("!")) continue;
152
251
  const norm = decl.replace(/^\.\//, "").replace(/\/+$/, "");
153
252
  const asDirPrefix = norm + "/";
154
253
  const present = filePaths.some(
@@ -162,12 +261,37 @@ export function checkTarball(opts = {}) {
162
261
  missing.push(`${mainEntry} (package main / exports["."])`);
163
262
  }
164
263
 
264
+ // 6) CF-15: no packaged module points at a file the packaging left out.
265
+ const broken = brokenPackagedReferences({
266
+ files: filePaths,
267
+ read: (rel) => readFileSync(path.join(pkgRoot, rel), "utf8"),
268
+ existsInSource: (rel) => existsSync(path.join(cwd, rel)),
269
+ });
270
+ for (const b of broken) missing.push(`${b.target} (referenced as "${b.ref}" by ${b.file}, excluded from the tarball)`);
271
+
272
+ // 7) CF-15: every exported entry and lib/**/index imports from the extracted
273
+ // tarball (dependencies from the source tree's node_modules). A module that
274
+ // also fails from the source tree is not a packaging fault.
275
+ let smoked = 0;
276
+ if (opts.smoke !== false) {
277
+ const targets = smokeImportTargets(pkg, filePaths);
278
+ const sourceModules = path.join(cwd, "node_modules");
279
+ if (existsSync(sourceModules)) symlinkSync(sourceModules, path.join(pkgRoot, "node_modules"), "dir");
280
+ const failedPacked = smokeImport(pkgRoot, targets);
281
+ const failedSource = failedPacked.length > 0 ? new Set(smokeImport(cwd, failedPacked.map((f) => f.module)).map((f) => f.module)) : new Set();
282
+ for (const f of failedPacked) {
283
+ if (!failedSource.has(f.module)) missing.push(`${f.module} (does not import from the tarball: ${f.error})`);
284
+ }
285
+ smoked = targets.length;
286
+ }
287
+
165
288
  return {
166
289
  ok: offenders.length === 0 && missing.length === 0,
167
290
  offenders,
168
291
  missing,
169
292
  tarballFiles: filePaths.length,
170
293
  mainEntry,
294
+ smoked,
171
295
  };
172
296
  } finally {
173
297
  try { rmSync(work, { recursive: true, force: true }); } catch { /* */ }
@@ -184,7 +308,7 @@ export async function run(cwd = REPO_ROOT) {
184
308
  return 2;
185
309
  }
186
310
  if (res.ok) {
187
- console.log(`check-tarball-fidelity: OK (${res.tarballFiles} files; main "${res.mainEntry}" present; no node_modules/.pyc/symlinks)`);
311
+ console.log(`check-tarball-fidelity: OK (${res.tarballFiles} files; main "${res.mainEntry}" present; no node_modules/.pyc/symlinks/tests/fixtures; every relative reference resolves; ${res.smoked} entry modules import from the tarball)`);
188
312
  return 0;
189
313
  }
190
314
  if (res.missing.length) {
@@ -10,24 +10,31 @@
10
10
  *
11
11
  * Node builtins only (maestro is "type":"module", near-zero-dep by design).
12
12
  *
13
- * Usage: `node scripts/ci/run-tests.mjs`
13
+ * Usage: `node scripts/ci/run-tests.mjs [--list]`
14
14
  * exit 0 → all tests passed; non-zero → at least one failed (or none found).
15
+ * `--list` prints the discovered files and runs nothing. It exists so that
16
+ * "what does the suite cover?" has ONE answer. `package.json` used to answer
17
+ * it a second time with a hand-enumerated `test:list`, which had drifted to
18
+ * 46 of 82 files by the time an audit caught it (L25) and was still missing
19
+ * newly added suites afterwards — a second source of truth about coverage
20
+ * that lies is worse than none, because it reads like an inventory.
15
21
  *
16
22
  * @module scripts/ci/run-tests
17
23
  */
18
24
 
19
25
  import { readdirSync } from "node:fs";
20
- import { join, dirname } from "node:path";
26
+ import { join, dirname, relative, resolve } from "node:path";
21
27
  import { fileURLToPath } from "node:url";
22
28
  import { spawnSync } from "node:child_process";
23
29
 
24
30
  const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
25
- const ROOTS = ["lib", "scripts", "bin", "services"];
31
+ const ROOTS = ["lib", "scripts", "bin", "services", "test"];
26
32
  const SKIP_DIRS = new Set(["node_modules", ".git", "state", "logs", "audit"]);
27
33
 
28
34
  /**
29
- * Recursively collect `*.test.mjs` files under `dir` (absolute), returning
30
- * paths relative to REPO_ROOT for stable, readable output.
35
+ * Recursively collect `*.test.mjs` files under `dir`, returning ABSOLUTE
36
+ * paths — `node --test` is spawned with cwd REPO_ROOT, but absolute paths
37
+ * survive a caller that is not. `--list` relativises them for readability.
31
38
  * @param {string} dir
32
39
  * @returns {string[]}
33
40
  */
@@ -50,22 +57,43 @@ function findTests(dir) {
50
57
  return out;
51
58
  }
52
59
 
53
- const files = ROOTS.flatMap((r) => findTests(join(REPO_ROOT, r))).sort();
54
-
55
- if (files.length === 0) {
56
- console.error("run-tests: no *.test.mjs files found — refusing to report success.");
57
- process.exit(1);
60
+ /**
61
+ * Every test file the suite runs, repo-relative and sorted. The single source
62
+ * of truth about what `npm test` covers.
63
+ * @returns {string[]}
64
+ */
65
+ export function discoverTests() {
66
+ return ROOTS.flatMap((r) => findTests(join(REPO_ROOT, r))).sort();
58
67
  }
59
68
 
60
- console.log(`run-tests: discovered ${files.length} test file(s).`);
69
+ function main(argv) {
70
+ const files = discoverTests();
71
+
72
+ if (files.length === 0) {
73
+ console.error("run-tests: no *.test.mjs files found — refusing to report success.");
74
+ return 1;
75
+ }
76
+
77
+ if (argv.includes("--list")) {
78
+ for (const f of files) console.log(relative(REPO_ROOT, f));
79
+ console.error(`run-tests: ${files.length} test file(s) discovered (nothing was run).`);
80
+ return 0;
81
+ }
82
+
83
+ console.log(`run-tests: discovered ${files.length} test file(s).`);
61
84
 
62
- const result = spawnSync(process.execPath, ["--test", ...files], {
63
- cwd: REPO_ROOT,
64
- stdio: "inherit",
65
- });
85
+ const result = spawnSync(process.execPath, ["--test", ...files], {
86
+ cwd: REPO_ROOT,
87
+ stdio: "inherit",
88
+ });
89
+
90
+ if (result.error) {
91
+ console.error("run-tests: failed to launch node --test:", result.error.message);
92
+ return 1;
93
+ }
94
+ return result.status ?? 1;
95
+ }
66
96
 
67
- if (result.error) {
68
- console.error("run-tests: failed to launch node --test:", result.error.message);
69
- process.exit(1);
97
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
98
+ process.exit(main(process.argv.slice(2)));
70
99
  }
71
- process.exit(result.status ?? 1);
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/cohort-llm/api-key-helper.mjs — Claude Code `apiKeyHelper` for a
4
+ * seat retargeted to cohort-llm (the internal "Path B" testbed, design C1).
5
+ *
6
+ * Claude Code runs this in /bin/sh and sends stdout as the request credential
7
+ * (public docs, code.claude.com/docs/en/iam: `apiKeyHelper` ranks below
8
+ * ANTHROPIC_AUTH_TOKEN, so a cohort retarget carries NO auth token and lets this
9
+ * helper supply — and, every CLAUDE_CODE_API_KEY_HELPER_TTL_MS, refresh — the
10
+ * seat token for the whole life of a long session).
11
+ *
12
+ * node scripts/cohort-llm/api-key-helper.mjs [--agent-root <dir>]
13
+ *
14
+ * stdout: exactly one fresh `cst_…` token and a newline. Nothing else ever goes
15
+ * to stdout — anything printed there would be sent as the credential.
16
+ * failure: exit 1 with one line on stderr naming the typed error. The token and
17
+ * the seat's key never appear on stderr.
18
+ *
19
+ * Key resolution: the cached token (state/cohort-llm/token.json) when it is
20
+ * before its refresh point; otherwise the seat's OrgApiKey from config/org.yaml,
21
+ * the environment, or the agent's .env (a retarget child's env is scrubbed of
22
+ * credentials, so the .env is the usual source here).
23
+ *
24
+ * @module scripts/cohort-llm/api-key-helper
25
+ */
26
+
27
+ import { resolve } from "node:path";
28
+ import { realpathSync } from "node:fs";
29
+ import { pathToFileURL } from "node:url";
30
+
31
+ import { seatTokenManager, redactSecrets, REJECTED_TOKEN_FP_ENV } from "../../lib/org/llm-token.mjs";
32
+
33
+ /** @param {string[]} argv */
34
+ export function parseHelperArgs(argv) {
35
+ const out = { agentRoot: null };
36
+ for (let i = 0; i < argv.length; i++) {
37
+ const a = argv[i];
38
+ if (a === "--agent-root") out.agentRoot = argv[++i] || null;
39
+ else if (a.startsWith("--agent-root=")) out.agentRoot = a.slice("--agent-root=".length) || null;
40
+ }
41
+ return out;
42
+ }
43
+
44
+ /**
45
+ * @param {object} [deps]
46
+ * @param {string[]} [deps.argv]
47
+ * @param {object} [deps.env]
48
+ * @param {{write:(s:string)=>unknown}} [deps.stdout]
49
+ * @param {{write:(s:string)=>unknown}} [deps.stderr]
50
+ * @param {typeof fetch} [deps.fetchImpl]
51
+ * @param {() => number} [deps.now]
52
+ * @param {object} [deps.cfg]
53
+ * @returns {Promise<number>} exit code
54
+ */
55
+ export async function main(deps = {}) {
56
+ const env = deps.env || process.env;
57
+ const stdout = deps.stdout || process.stdout;
58
+ const stderr = deps.stderr || process.stderr;
59
+ const args = parseHelperArgs(deps.argv || process.argv.slice(2));
60
+ const agentRoot = resolve(args.agentRoot || env.AGENT_ROOT || env.AGENT_DIR || process.cwd());
61
+ try {
62
+ const manager = seatTokenManager({ agentRoot, env, cfg: deps.cfg, readDotEnv: true, fetchImpl: deps.fetchImpl, now: deps.now });
63
+ // The engine re-runs this helper after a 401 and names the refused token by
64
+ // fingerprint: the manager serves a replacement if one exists, else re-mints
65
+ // under its per-window cap. A plain run (TTL refresh) never forces a mint.
66
+ const rejectedFp = typeof env[REJECTED_TOKEN_FP_ENV] === "string" ? env[REJECTED_TOKEN_FP_ENV].trim() : "";
67
+ const r = await manager.getToken(rejectedFp ? { rejectedFp } : {});
68
+ if (r.ok && typeof r.token === "string" && r.token) {
69
+ stdout.write(`${r.token}\n`);
70
+ return 0;
71
+ }
72
+ const e = (r && r.error) || { code: "cohort_unavailable", message: "no token" };
73
+ stderr.write(`cohort-llm api-key-helper: ${e.code}: ${redactSecrets(e.message)}\n`);
74
+ return 1;
75
+ } catch (err) {
76
+ stderr.write(`cohort-llm api-key-helper: cohort_unavailable: ${redactSecrets(err && err.message ? err.message : err)}\n`);
77
+ return 1;
78
+ }
79
+ }
80
+
81
+ function isEntrypoint() {
82
+ if (!process.argv[1]) return false;
83
+ try {
84
+ return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
85
+ } catch {
86
+ return false;
87
+ }
88
+ }
89
+
90
+ if (isEntrypoint()) {
91
+ process.exitCode = await main();
92
+ }
@@ -77,7 +77,7 @@ async function main() {
77
77
 
78
78
  if (event === "prime") {
79
79
  const kind = classifyKind(input);
80
- try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind }); } catch { /* */ }
80
+ try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind, ...ownerFields(presence) }); } catch { /* */ }
81
81
  if (denied) return; // never inject agent memory (or the persona) into a ring-fenced/client session
82
82
  const parts = [];
83
83
  try {
@@ -111,7 +111,15 @@ async function main() {
111
111
  }
112
112
 
113
113
  if (event === "beat") {
114
- try { presence.heartbeat(SELF_ROOT, sessionId); } catch { /* */ }
114
+ // A beat on a session with no record re-registers it: a session that was
115
+ // running before this hook learned to record its OWNER pid (see
116
+ // ownerFields) was reaped on every read, and would otherwise stay
117
+ // invisible until it restarts.
118
+ let beaten = false;
119
+ try { beaten = presence.heartbeat(SELF_ROOT, sessionId); } catch { beaten = false; }
120
+ if (!beaten) {
121
+ try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind: classifyKind(input), ...ownerFields(presence) }); } catch { /* */ }
122
+ }
115
123
  // WS3: nudge the self-learning loop's tool-use counter. Cheap, fail-open,
116
124
  // and only when the layer is enabled + the repo isn't denylisted.
117
125
  if (!denied) {
@@ -151,6 +159,25 @@ function buildFrontDoorPrimer(agentRoot) {
151
159
  mod.buildPrimerContext({ agentJson, agentRoot, status: mod.readSessionStatus(agentRoot, { now: Date.now() }) }));
152
160
  }
153
161
 
162
+ /**
163
+ * The pid, `--name` and process start of the session that RAN this hook.
164
+ * Without this the record carried the hook's own pid, which is dead by the
165
+ * time anyone reads it, so `list()` reaped every interactive session on its
166
+ * first read (see lib/collective/presence.mjs `owningSession`). `pid: null`
167
+ * when the walk finds nothing — liveness then rests on the heartbeat. The
168
+ * start time is the owner's `ps etime`, so a session re-registered by a late
169
+ * beat still says when it OPENED, not when the beat happened.
170
+ */
171
+ function ownerFields(presence) {
172
+ try {
173
+ if (typeof presence.resolveOwner !== "function") return {};
174
+ const o = presence.resolveOwner();
175
+ return { pid: o.pid, agentName: o.name || "", ...(o.startedAt ? { startedAt: o.startedAt } : {}) };
176
+ } catch {
177
+ return {};
178
+ }
179
+ }
180
+
154
181
  function classifyKind(input) {
155
182
  const src = String(input.source || "").toLowerCase();
156
183
  if (src.includes("daemon") || process.env.MAESTRO_DAEMON === "1") return "daemon";
@@ -9,6 +9,19 @@ set -e
9
9
 
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  AGENT_REPO_DIR="${AGENT_DIR:-$(dirname "$SCRIPT_DIR")}"
12
+
13
+ # Retired on engine-cohort seats (W4-E1): this lane runs claude outside the
14
+ # runtime adapter. The guard exits 3 with the reason when runtime.engine is cohort.
15
+ # Fail closed: when the guard cannot run (no node on PATH — launchd's
16
+ # /usr/bin:/bin — or the guard file is missing), config/agent.json is checked
17
+ # here and an engine-cohort seat is refused all the same.
18
+ LEGACY_GUARD="$(dirname "$SCRIPT_DIR")/lib/runtime/legacy-shell-guard.mjs"
19
+ if [ -f "$LEGACY_GUARD" ] && command -v node >/dev/null 2>&1; then
20
+ node "$LEGACY_GUARD" continuous-monitor.sh "$AGENT_REPO_DIR" || exit $?
21
+ elif [ -f "$AGENT_REPO_DIR/config/agent.json" ] && grep -Eq '"engine"[[:space:]]*:[[:space:]]*"cohort"' "$AGENT_REPO_DIR/config/agent.json"; then
22
+ echo "continuous-monitor.sh is retired on this seat: runtime.engine is \"cohort\", and this legacy lane runs the claude binary directly, outside the runtime adapter (the engine guard could not run: node or $LEGACY_GUARD is unavailable)." >&2
23
+ exit 3
24
+ fi
12
25
  # Load agent identity for the LLM prompt
13
26
  if [ -f "$AGENT_REPO_DIR/config/agent.env" ]; then
14
27
  # shellcheck disable=SC1091
@@ -22,6 +22,13 @@
22
22
  * That writes measurement:"unknown" with NULL tokens. It must never write
23
23
  * zeros — see "MEASURED, UNKNOWN, N/A" below.
24
24
  *
25
+ * A session cohort-llm served (engine cohort, or claude retargeted to the
26
+ * cohort provider) is already metered by the gateway; mark it so org
27
+ * cost-sync does not report it a second time:
28
+ *
29
+ * node scripts/cost/track-claude-usage.mjs record ... \
30
+ * --billed-by cohort-llm --request-ids req_1,req_2
31
+ *
25
32
  * 2. `summarise` — Rollup the last N days into state/dashboards/cost-summary.yaml.
26
33
  * Called daily (cadence: nightly-cost-rollup) and on demand.
27
34
  *
@@ -266,6 +273,14 @@ function recordCmd(flags) {
266
273
  };
267
274
  if (unmeasuredReason) row.unmeasured_reason = unmeasuredReason;
268
275
  if (flags["decision-id"]) row.decision_id = String(flags["decision-id"]);
276
+ // Who metered this session. "cohort-llm": the gateway billed it; the row is
277
+ // kept for the seat's own view and reconciliation, and skipped by org
278
+ // cost-sync (lib/org/cost-sync.mjs) so it is never counted twice.
279
+ if (flags["billed-by"] && flags["billed-by"] !== "true") row.billed_by = String(flags["billed-by"]);
280
+ if (flags["request-ids"] && flags["request-ids"] !== "true") {
281
+ const ids = String(flags["request-ids"]).split(",").map((x) => x.trim()).filter(Boolean);
282
+ if (ids.length) row.gateway_request_ids = ids;
283
+ }
269
284
 
270
285
  if (measurement === "measured") {
271
286
  // Cache tokens are billed at their own rates (read 0.1x, write 1.25x) and