@cohortapp/agent-sdk 2.17.0 → 2.18.5

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 (531) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +18 -5
  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/setup-wizard.md +1 -1
  9. package/docs/runbooks/fleet-rollout.md +156 -0
  10. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  11. package/lib/action-executor.js +19 -3
  12. package/lib/budget-guard.mjs +279 -3
  13. package/lib/channels/base-adapter.mjs +3 -1
  14. package/lib/channels/contract.mjs +2 -1
  15. package/lib/channels/inbox-item.mjs +8 -0
  16. package/lib/claude-bin.mjs +5 -6
  17. package/lib/cli/doctor-checks.mjs +141 -10
  18. package/lib/cli/global-setup-extras.mjs +5 -1
  19. package/lib/cli/inbox.mjs +100 -15
  20. package/lib/cli/seat-auth.mjs +463 -0
  21. package/lib/cli/session.mjs +80 -12
  22. package/lib/collective/capture-slots.mjs +234 -0
  23. package/lib/collective/capture.mjs +8 -6
  24. package/lib/collective/config.mjs +2 -0
  25. package/lib/collective/global-config.mjs +63 -1
  26. package/lib/collective/loop-guard.mjs +155 -0
  27. package/lib/collective/presence.mjs +142 -5
  28. package/lib/comms/send-gate.mjs +559 -1
  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/failover.mjs +67 -16
  138. package/lib/model-router/llm-task.mjs +39 -3
  139. package/lib/model-router/resolve.mjs +89 -3
  140. package/lib/model-router/spawn.mjs +46 -47
  141. package/lib/model-router/taxonomy.mjs +126 -4
  142. package/lib/org/cost-sync.mjs +141 -11
  143. package/lib/org/inbound/broadcast.mjs +289 -0
  144. package/lib/org/inbound/collective.mjs +375 -0
  145. package/lib/org/inbound/directedness.mjs +96 -8
  146. package/lib/org/inbound/facts.mjs +78 -2
  147. package/lib/org/inbound/project.mjs +22 -0
  148. package/lib/org/inbound/surfaces.mjs +14 -0
  149. package/lib/org/llm-token.mjs +879 -0
  150. package/lib/org/mesh.mjs +61 -0
  151. package/lib/org/messaging.mjs +3 -1
  152. package/lib/org/protocol.checksum +1 -1
  153. package/lib/org/protocol.mjs +15 -0
  154. package/lib/org/quota.mjs +520 -0
  155. package/lib/org/tool-surface.mjs +104 -16
  156. package/lib/org/ui-parity.mjs +16 -1
  157. package/lib/org/work-ledger.mjs +37 -6
  158. package/lib/rate-guard.mjs +114 -1
  159. package/lib/resource-governor.mjs +41 -6
  160. package/lib/runtime/adapter.mjs +833 -0
  161. package/lib/runtime/child-env.mjs +191 -0
  162. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  163. package/lib/runtime/seat-engine.mjs +162 -0
  164. package/lib/session/ask-ledger.mjs +271 -0
  165. package/lib/session/current-work.mjs +676 -0
  166. package/lib/session/feed-core.mjs +40 -3
  167. package/lib/session/launch-args.mjs +56 -4
  168. package/lib/session/status-summary.mjs +26 -9
  169. package/lib/session/upgrade-notice.mjs +42 -0
  170. package/lib/setup/claude-probe.mjs +117 -13
  171. package/lib/setup/enrich.mjs +13 -10
  172. package/lib/setup/sections/model.mjs +39 -13
  173. package/lib/telemetry/collect.mjs +229 -11
  174. package/lib/upgrade/ignored-drift.mjs +105 -0
  175. package/lib/voice/post-call-brief.mjs +30 -17
  176. package/package.json +13 -3
  177. package/plugins/maestro-skills/skills/board-work.md +5 -0
  178. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  179. package/plugins/maestro-skills/skills/main-session.md +18 -7
  180. package/scaffold/config/collective.yaml +7 -0
  181. package/scripts/ci/check-durable-write-seam.mjs +3 -1
  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 +142 -19
  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 +51 -37
  194. package/scripts/daemon/deliver.mjs +30 -1
  195. package/scripts/daemon/dispatcher.mjs +595 -149
  196. package/scripts/daemon/health.mjs +14 -1
  197. package/scripts/daemon/maestro-daemon.mjs +11 -0
  198. package/scripts/daemon/prompt-builder.mjs +24 -0
  199. package/scripts/daemon/responder.mjs +246 -79
  200. package/scripts/daemon/sdk-version.mjs +98 -16
  201. package/scripts/eval/probe-gateway.mjs +635 -0
  202. package/scripts/eval/replay/extract.mjs +270 -0
  203. package/scripts/eval/replay/grade.mjs +260 -0
  204. package/scripts/eval/replay/lib/config.mjs +50 -0
  205. package/scripts/eval/replay/lib/effects.mjs +65 -0
  206. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  207. package/scripts/eval/replay/lib/judge.mjs +72 -0
  208. package/scripts/eval/replay/lib/redact.mjs +136 -0
  209. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  210. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  211. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  212. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  213. package/scripts/eval/replay/report.mjs +185 -0
  214. package/scripts/eval/replay/run.mjs +404 -0
  215. package/scripts/fleet/rollout.mjs +1151 -0
  216. package/scripts/hooks/pre-send-audit.sh +36 -245
  217. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  218. package/scripts/hooks/validate-state-yaml.sh +190 -0
  219. package/scripts/huddle/huddle-llm.mjs +361 -0
  220. package/scripts/huddle/huddle-server.mjs +46 -121
  221. package/scripts/local-triggers/autoupdate.sh +465 -81
  222. package/scripts/local-triggers/run-trigger.sh +13 -0
  223. package/scripts/maintenance/pin-integrity.mjs +364 -0
  224. package/scripts/poll-slack-events.sh +41 -9
  225. package/scripts/poller/slack-socket-mode.mjs +28 -3
  226. package/scripts/session/supervisor.mjs +80 -13
  227. package/scripts/spawn-session.sh +13 -0
  228. package/bin/maestro.test.mjs +0 -1574
  229. package/lib/action-executor.test.mjs +0 -871
  230. package/lib/archetype.test.mjs +0 -132
  231. package/lib/assurance/plan-note.test.mjs +0 -234
  232. package/lib/assurance/room-budget.test.mjs +0 -486
  233. package/lib/assurance/tier.test.mjs +0 -174
  234. package/lib/autonomy.test.mjs +0 -66
  235. package/lib/backlog.test.mjs +0 -302
  236. package/lib/backup/policy.test.mjs +0 -305
  237. package/lib/budget-escalate.test.mjs +0 -232
  238. package/lib/budget-guard.envelope.test.mjs +0 -476
  239. package/lib/budget-guard.test.mjs +0 -427
  240. package/lib/cadence-bus-requeue.test.mjs +0 -83
  241. package/lib/cadence-bus-schedule.test.mjs +0 -194
  242. package/lib/cadence-bus.test.mjs +0 -720
  243. package/lib/cadences.test.mjs +0 -230
  244. package/lib/capability/inventory.test.mjs +0 -232
  245. package/lib/capability.test.mjs +0 -78
  246. package/lib/channels/base-adapter.test.mjs +0 -590
  247. package/lib/channels/channels.test.mjs +0 -371
  248. package/lib/channels/contract.test.mjs +0 -162
  249. package/lib/channels/inbox-item.test.mjs +0 -368
  250. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  251. package/lib/channels/pairing.test.mjs +0 -270
  252. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  253. package/lib/channels/slack-adapter.test.mjs +0 -212
  254. package/lib/channels/telegram-adapter.test.mjs +0 -306
  255. package/lib/channels/voice/adapter.test.mjs +0 -278
  256. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  257. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  258. package/lib/charter.test.mjs +0 -89
  259. package/lib/claude-bin.test.mjs +0 -131
  260. package/lib/cli/board.test.mjs +0 -227
  261. package/lib/cli/design.test.mjs +0 -270
  262. package/lib/cli/doctor-checks.test.mjs +0 -336
  263. package/lib/cli/global-setup-extras.test.mjs +0 -462
  264. package/lib/cli/inbox.test.mjs +0 -230
  265. package/lib/cli/session-ack.test.mjs +0 -63
  266. package/lib/cli/session.test.mjs +0 -613
  267. package/lib/collective/capture.test.mjs +0 -121
  268. package/lib/collective/cards.test.mjs +0 -114
  269. package/lib/collective/config.test.mjs +0 -123
  270. package/lib/collective/global-config.test.mjs +0 -220
  271. package/lib/collective/global-skills.test.mjs +0 -126
  272. package/lib/collective/presence.test.mjs +0 -95
  273. package/lib/collective/recall.test.mjs +0 -116
  274. package/lib/collective/vendor-skills.test.mjs +0 -306
  275. package/lib/comms/send-gate.test.mjs +0 -770
  276. package/lib/comms.test.mjs +0 -41
  277. package/lib/context/budget.test.mjs +0 -252
  278. package/lib/context/history-scope.test.mjs +0 -79
  279. package/lib/cost/ledger-row.test.mjs +0 -183
  280. package/lib/design/design-md.test.mjs +0 -318
  281. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  282. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  283. package/lib/design/fixtures/foundation.json +0 -133
  284. package/lib/design/refresh-gate.test.mjs +0 -144
  285. package/lib/design/write.test.mjs +0 -241
  286. package/lib/diagnostics/alerts.test.mjs +0 -318
  287. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  288. package/lib/diagnostics/counters.test.mjs +0 -206
  289. package/lib/diagnostics/events.test.mjs +0 -290
  290. package/lib/diagnostics/otel.test.mjs +0 -196
  291. package/lib/diagnostics/trace.test.mjs +0 -251
  292. package/lib/env-compat.test.mjs +0 -104
  293. package/lib/execution/disposition.test.mjs +0 -553
  294. package/lib/execution/drive.test.mjs +0 -270
  295. package/lib/execution/effects.test.mjs +0 -344
  296. package/lib/execution/intake.test.mjs +0 -389
  297. package/lib/execution/journal.test.mjs +0 -261
  298. package/lib/execution/match.test.mjs +0 -235
  299. package/lib/execution/pipeline.test.mjs +0 -392
  300. package/lib/execution/route.test.mjs +0 -186
  301. package/lib/execution/surface-policy.test.mjs +0 -162
  302. package/lib/fs-atomic.test.mjs +0 -72
  303. package/lib/fs-ownership.test.mjs +0 -158
  304. package/lib/goals/admission.test.mjs +0 -164
  305. package/lib/goals/classify.test.mjs +0 -167
  306. package/lib/goals/collaborate.test.mjs +0 -336
  307. package/lib/goals/gaps.test.mjs +0 -284
  308. package/lib/goals/loop.test.mjs +0 -845
  309. package/lib/hooks/bus.test.mjs +0 -387
  310. package/lib/identity/persona.test.mjs +0 -142
  311. package/lib/kpi-sensors.test.mjs +0 -278
  312. package/lib/kpi.test.mjs +0 -244
  313. package/lib/learning/config.test.mjs +0 -75
  314. package/lib/learning/counters.test.mjs +0 -69
  315. package/lib/learning/curator-consolidate.test.mjs +0 -238
  316. package/lib/learning/curator.test.mjs +0 -106
  317. package/lib/learning/reflect.test.mjs +0 -0
  318. package/lib/learning/session-index.test.mjs +0 -125
  319. package/lib/learning/skill-writer.test.mjs +0 -210
  320. package/lib/mandate/audit.test.mjs +0 -195
  321. package/lib/mandate/contract.test.mjs +0 -185
  322. package/lib/mandate/derive.test.mjs +0 -274
  323. package/lib/mandate/model.test.mjs +0 -164
  324. package/lib/mandate/refresh.test.mjs +0 -389
  325. package/lib/mcp/server.test.mjs +0 -426
  326. package/lib/model-router/auth-profiles.test.mjs +0 -580
  327. package/lib/model-router/catalog.test.mjs +0 -385
  328. package/lib/model-router/economics.test.mjs +0 -438
  329. package/lib/model-router/failover.test.mjs +0 -439
  330. package/lib/model-router/health.test.mjs +0 -338
  331. package/lib/model-router/integration-coverage.test.mjs +0 -831
  332. package/lib/model-router/integration.test.mjs +0 -564
  333. package/lib/model-router/ledger.test.mjs +0 -415
  334. package/lib/model-router/llm-task.test.mjs +0 -392
  335. package/lib/model-router/org-credentials.test.mjs +0 -265
  336. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  337. package/lib/model-router/reconcile.test.mjs +0 -316
  338. package/lib/model-router/repair.test.mjs +0 -180
  339. package/lib/model-router/spawn.test.mjs +0 -446
  340. package/lib/model-router/taxonomy.test.mjs +0 -410
  341. package/lib/model-router.test.mjs +0 -1207
  342. package/lib/org/activity.test.mjs +0 -134
  343. package/lib/org/approvals.test.mjs +0 -216
  344. package/lib/org/awareness.test.mjs +0 -159
  345. package/lib/org/board-mine-cache.test.mjs +0 -53
  346. package/lib/org/board.test.mjs +0 -187
  347. package/lib/org/bootstrap-context.test.mjs +0 -153
  348. package/lib/org/client.test.mjs +0 -1206
  349. package/lib/org/cohort-client.test.mjs +0 -126
  350. package/lib/org/cost-sync.test.mjs +0 -153
  351. package/lib/org/doctor.test.mjs +0 -346
  352. package/lib/org/engagement-ledger.test.mjs +0 -112
  353. package/lib/org/engagement.test.mjs +0 -739
  354. package/lib/org/handoff.test.mjs +0 -269
  355. package/lib/org/inbound/directedness.test.mjs +0 -668
  356. package/lib/org/inbound/facts.test.mjs +0 -471
  357. package/lib/org/inbound/hydrate.test.mjs +0 -908
  358. package/lib/org/inbound/index.test.mjs +0 -429
  359. package/lib/org/inbound/project.test.mjs +0 -287
  360. package/lib/org/integration-tools.test.mjs +0 -160
  361. package/lib/org/keys.test.mjs +0 -92
  362. package/lib/org/knowledge.test.mjs +0 -326
  363. package/lib/org/leases.test.mjs +0 -235
  364. package/lib/org/mesh-directives.test.mjs +0 -110
  365. package/lib/org/mesh-integration.test.mjs +0 -127
  366. package/lib/org/mesh.test.mjs +0 -400
  367. package/lib/org/messaging.test.mjs +0 -471
  368. package/lib/org/param-contract.test.mjs +0 -477
  369. package/lib/org/policy.test.mjs +0 -237
  370. package/lib/org/protocol.checksum.test.mjs +0 -90
  371. package/lib/org/protocol.test.mjs +0 -323
  372. package/lib/org/push.test.mjs +0 -792
  373. package/lib/org/registry.test.mjs +0 -100
  374. package/lib/org/resource-tools.test.mjs +0 -361
  375. package/lib/org/tool-access.test.mjs +0 -144
  376. package/lib/org/tool-surface-integration.test.mjs +0 -120
  377. package/lib/org/tool-surface.test.mjs +0 -1268
  378. package/lib/org/typing.test.mjs +0 -291
  379. package/lib/org/ui-parity.test.mjs +0 -560
  380. package/lib/org/verify.test.mjs +0 -194
  381. package/lib/org/work-ledger.test.mjs +0 -273
  382. package/lib/plan/adoption-e2e.test.mjs +0 -366
  383. package/lib/plan/budget-enforcement.test.mjs +0 -400
  384. package/lib/plan/compile.test.mjs +0 -382
  385. package/lib/plan/emit.test.mjs +0 -269
  386. package/lib/plan/explain.test.mjs +0 -188
  387. package/lib/prompts/parallelism.test.mjs +0 -177
  388. package/lib/rag/rag.test.mjs +0 -505
  389. package/lib/rate-guard.test.mjs +0 -272
  390. package/lib/reactive-gate.test.mjs +0 -57
  391. package/lib/render.test.mjs +0 -68
  392. package/lib/resource-governor.test.mjs +0 -488
  393. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  394. package/lib/scheduling/jitter.test.mjs +0 -140
  395. package/lib/secrets/broker.test.mjs +0 -280
  396. package/lib/secrets/providers.test.mjs +0 -274
  397. package/lib/security/audit-engine.test.mjs +0 -424
  398. package/lib/security/coerce-args.test.mjs +0 -281
  399. package/lib/security/dangerous-tools.test.mjs +0 -68
  400. package/lib/security/external-content.test.mjs +0 -84
  401. package/lib/security/redact.test.mjs +0 -441
  402. package/lib/security/secret-equal.test.mjs +0 -55
  403. package/lib/session/config.test.mjs +0 -92
  404. package/lib/session/feed-core.test.mjs +0 -198
  405. package/lib/session/first-run.test.mjs +0 -121
  406. package/lib/session/frontdoor.test.mjs +0 -205
  407. package/lib/session/handoffs.test.mjs +0 -183
  408. package/lib/session/identity.test.mjs +0 -180
  409. package/lib/session/inbox-claims.test.mjs +0 -286
  410. package/lib/session/launch-args.test.mjs +0 -157
  411. package/lib/session/liveness.test.mjs +0 -100
  412. package/lib/session/status-summary.test.mjs +0 -118
  413. package/lib/session-permissions.test.mjs +0 -120
  414. package/lib/setup/claude-probe.test.mjs +0 -187
  415. package/lib/setup/completeness.test.mjs +0 -110
  416. package/lib/setup/context-pack.test.mjs +0 -89
  417. package/lib/setup/enrich.test.mjs +0 -115
  418. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  419. package/lib/setup/integration.test.mjs +0 -162
  420. package/lib/setup/io.test.mjs +0 -77
  421. package/lib/setup/runner.test.mjs +0 -132
  422. package/lib/setup/sections/identity.test.mjs +0 -234
  423. package/lib/setup/sections/inventory.test.mjs +0 -198
  424. package/lib/setup/sections/learning.test.mjs +0 -81
  425. package/lib/setup/sections/mandate.test.mjs +0 -388
  426. package/lib/setup/sections/messaging.test.mjs +0 -127
  427. package/lib/setup/sections/model.test.mjs +0 -240
  428. package/lib/setup/sections/org.test.mjs +0 -346
  429. package/lib/setup/sections/orgmail.test.mjs +0 -118
  430. package/lib/setup/sections/recovery.test.mjs +0 -98
  431. package/lib/setup/sections/subagents.test.mjs +0 -429
  432. package/lib/setup/sections/verify.test.mjs +0 -175
  433. package/lib/setup/sot.test.mjs +0 -81
  434. package/lib/setup/state.test.mjs +0 -115
  435. package/lib/singleton.test.mjs +0 -151
  436. package/lib/subagents/cli.test.mjs +0 -389
  437. package/lib/subagents/client.test.mjs +0 -309
  438. package/lib/subagents/gap.test.mjs +0 -234
  439. package/lib/subagents/lock.test.mjs +0 -248
  440. package/lib/subagents/manifest.test.mjs +0 -175
  441. package/lib/subagents/refs.test.mjs +0 -204
  442. package/lib/subagents/resolve.test.mjs +0 -422
  443. package/lib/subagents/schema.test.mjs +0 -328
  444. package/lib/telemetry/alerts.test.mjs +0 -109
  445. package/lib/telemetry/collect.test.mjs +0 -1274
  446. package/lib/tool-definitions-integration.test.mjs +0 -83
  447. package/lib/tool-definitions.test.mjs +0 -437
  448. package/lib/upgrade/global-refresh.test.mjs +0 -65
  449. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  450. package/lib/upgrade/post-steps.test.mjs +0 -200
  451. package/lib/upgrade/verify.test.mjs +0 -164
  452. package/lib/util/fetch-timeout.test.mjs +0 -202
  453. package/lib/util/reconnect.test.mjs +0 -369
  454. package/lib/util/unhandled.test.mjs +0 -216
  455. package/lib/voice/outbound.test.mjs +0 -69
  456. package/lib/voice/session-rotation.test.mjs +0 -114
  457. package/lib/voice/stt.test.mjs +0 -226
  458. package/lib/voice/voice.test.mjs +0 -990
  459. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  460. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  461. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  462. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  463. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  464. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  465. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  466. package/scripts/ci/check.test.mjs +0 -194
  467. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  468. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  469. package/scripts/collective/hook-runner.test.mjs +0 -173
  470. package/scripts/cost/fleet-digest.test.mjs +0 -207
  471. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  472. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  473. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  474. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  475. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  476. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  477. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  478. package/scripts/daemon/assurance.test.mjs +0 -1791
  479. package/scripts/daemon/board-mirror.test.mjs +0 -165
  480. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  481. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  482. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  483. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  484. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  485. package/scripts/daemon/classifier.test.mjs +0 -266
  486. package/scripts/daemon/classify-kind.test.mjs +0 -40
  487. package/scripts/daemon/context-compiler.test.mjs +0 -406
  488. package/scripts/daemon/deliver.test.mjs +0 -564
  489. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  490. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  491. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  492. package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
  493. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  494. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  495. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  496. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  497. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  498. package/scripts/daemon/integration.test.mjs +0 -149
  499. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  500. package/scripts/daemon/lib/session-router.test.mjs +0 -554
  501. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  502. package/scripts/daemon/prompt-builder.test.mjs +0 -556
  503. package/scripts/daemon/responder-cost.test.mjs +0 -68
  504. package/scripts/daemon/responder-history.test.mjs +0 -221
  505. package/scripts/daemon/sdk-version.test.mjs +0 -31
  506. package/scripts/daemon/session-lock.test.mjs +0 -252
  507. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  508. package/scripts/daemon/typing-registry.test.mjs +0 -102
  509. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  510. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  511. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  512. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  513. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  514. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  515. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  516. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  517. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  518. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  519. package/scripts/poller-launchd/install.test.mjs +0 -243
  520. package/scripts/restore-from-backup.test.mjs +0 -181
  521. package/scripts/session/feed.test.mjs +0 -196
  522. package/scripts/session/supervisor-sh.test.mjs +0 -218
  523. package/scripts/session/supervisor.test.mjs +0 -482
  524. package/scripts/setup/configure-macos.test.mjs +0 -306
  525. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  526. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  527. package/scripts/setup/generate-capability.test.mjs +0 -134
  528. package/scripts/setup/init-agent.test.mjs +0 -370
  529. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  530. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  531. 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.
@@ -19,6 +19,13 @@ captureOn: [Stop, PreCompact]
19
19
  minTurnsToCapture: 2
20
20
  # Hard cap on cards distilled from a single session (anti-bloat + cost guard).
21
21
  maxCardsPerSession: 12
22
+ # Machine-wide ceiling on capture workers doing model work at once. Each worker
23
+ # runs one or two `claude --print` passes; the ceiling keeps a burst of session
24
+ # ends from fanning out into unbounded model processes.
25
+ captureMaxConcurrent: 2
26
+ # How long a worker waits for a free slot before it gives up and records a
27
+ # skipped capture (counter `collective.capture_skipped`, reason `no-slot`).
28
+ captureQueueWaitMs: 30000
22
29
  # Repos/paths whose sessions must NOT contribute to memory (substring or glob,
23
30
  # matched against the session cwd). Client work, secrets, anything ring-fenced.
24
31
  # Information-barrier domains are always excluded regardless of this list.
@@ -42,7 +42,7 @@
42
42
  * `eslint.config.mjs`/`authz-drift.test.ts` use in the Cohort repo.
43
43
  *
44
44
  * Set equality also makes this guard self-canarying: the register is non-empty,
45
- * so a regex broken by a refactor yields zero matches and fails LOUDLY as three
45
+ * so a regex broken by a refactor yields zero matches and fails LOUDLY as
46
46
  * stale entries, rather than passing vacuously.
47
47
  *
48
48
  * Pure, dependency-light: Node builtins only. ESM.
@@ -71,6 +71,8 @@ export const SANCTIONED_DIRECT_WRITES = {
71
71
  "acquireScheduleLock: reclaim of a lock already proven stale by mtime; must land in place under the same name.",
72
72
  "lib/cadence-bus.mjs:328":
73
73
  "acquireScheduleLock: second O_EXCL attempt after the stale holder vanished.",
74
+ "lib/collective/capture-slots.mjs:152":
75
+ "tryAcquireLock: O_EXCL create of a capture slot/session lock (the machine-wide capture ceiling). A lock published by rename is not a lock — two workers could both hold one slot.",
74
76
  };
75
77
 
76
78
  /** Argument spellings that are already safe and must never be flagged. */
@@ -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
+ }