@cohortapp/agent-sdk 2.17.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 (526) 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.mjs +8 -6
  23. package/lib/collective/global-config.mjs +63 -1
  24. package/lib/collective/presence.mjs +142 -5
  25. package/lib/comms/send-gate.mjs +559 -1
  26. package/lib/diagnostics/alerts.mjs +49 -0
  27. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  28. package/lib/engine/agents/definitions.mjs +343 -0
  29. package/lib/engine/agents/persist.mjs +275 -0
  30. package/lib/engine/agents/runtime.mjs +748 -0
  31. package/lib/engine/agents/usage.mjs +95 -0
  32. package/lib/engine/auth-status.mjs +139 -0
  33. package/lib/engine/budget.mjs +194 -0
  34. package/lib/engine/cli.mjs +1204 -0
  35. package/lib/engine/commands/index.mjs +269 -0
  36. package/lib/engine/context/budget.mjs +219 -0
  37. package/lib/engine/context/cache.mjs +125 -0
  38. package/lib/engine/context/child-env.mjs +215 -0
  39. package/lib/engine/context/compaction.mjs +342 -0
  40. package/lib/engine/context/images.mjs +90 -0
  41. package/lib/engine/context/instructions.mjs +327 -0
  42. package/lib/engine/context/lazy-instructions.mjs +169 -0
  43. package/lib/engine/context/manager.mjs +182 -0
  44. package/lib/engine/context/real-path.mjs +91 -0
  45. package/lib/engine/context/secret-values.mjs +163 -0
  46. package/lib/engine/context/settings.mjs +274 -0
  47. package/lib/engine/context/stream-input.mjs +159 -0
  48. package/lib/engine/guard.mjs +152 -0
  49. package/lib/engine/hooks.mjs +713 -0
  50. package/lib/engine/loop.mjs +560 -0
  51. package/lib/engine/mcp/client.mjs +254 -0
  52. package/lib/engine/mcp/config.mjs +301 -0
  53. package/lib/engine/mcp/http.mjs +201 -0
  54. package/lib/engine/mcp/index.mjs +146 -0
  55. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  56. package/lib/engine/mcp/naming.mjs +66 -0
  57. package/lib/engine/mcp/resources.mjs +89 -0
  58. package/lib/engine/mcp/results.mjs +133 -0
  59. package/lib/engine/mcp/stdio.mjs +137 -0
  60. package/lib/engine/mcp/supervisor.mjs +116 -0
  61. package/lib/engine/messages.mjs +104 -0
  62. package/lib/engine/output/json.mjs +164 -0
  63. package/lib/engine/output/stream-json.mjs +266 -0
  64. package/lib/engine/permissions.mjs +845 -0
  65. package/lib/engine/process-identity.mjs +164 -0
  66. package/lib/engine/process-tree.mjs +551 -0
  67. package/lib/engine/prompt.mjs +60 -0
  68. package/lib/engine/session/store.mjs +299 -0
  69. package/lib/engine/session-runtime/args.mjs +97 -0
  70. package/lib/engine/session-runtime/host.mjs +143 -0
  71. package/lib/engine/session-runtime/inbox.mjs +122 -0
  72. package/lib/engine/session-runtime/notifications.mjs +129 -0
  73. package/lib/engine/session-runtime/registry.mjs +328 -0
  74. package/lib/engine/session-runtime/runner.mjs +344 -0
  75. package/lib/engine/session-runtime/socket.mjs +212 -0
  76. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  77. package/lib/engine/skills/index.mjs +321 -0
  78. package/lib/engine/tools/bash-background.mjs +533 -0
  79. package/lib/engine/tools/bash.mjs +216 -0
  80. package/lib/engine/tools/edit.mjs +97 -0
  81. package/lib/engine/tools/glob.mjs +81 -0
  82. package/lib/engine/tools/grep.mjs +224 -0
  83. package/lib/engine/tools/index.mjs +84 -0
  84. package/lib/engine/tools/list-agents.mjs +32 -0
  85. package/lib/engine/tools/ls.mjs +127 -0
  86. package/lib/engine/tools/monitor.mjs +82 -0
  87. package/lib/engine/tools/notebook-edit.mjs +218 -0
  88. package/lib/engine/tools/read.mjs +103 -0
  89. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  90. package/lib/engine/tools/schema.mjs +144 -0
  91. package/lib/engine/tools/send-message.mjs +77 -0
  92. package/lib/engine/tools/session.mjs +70 -0
  93. package/lib/engine/tools/todo.mjs +144 -0
  94. package/lib/engine/tools/toolsearch.mjs +217 -0
  95. package/lib/engine/tools/walk.mjs +193 -0
  96. package/lib/engine/tools/web-switch.mjs +31 -0
  97. package/lib/engine/tools/webfetch-html.mjs +387 -0
  98. package/lib/engine/tools/webfetch-net.mjs +340 -0
  99. package/lib/engine/tools/webfetch.mjs +198 -0
  100. package/lib/engine/tools/websearch.mjs +91 -0
  101. package/lib/engine/tools/workflow.mjs +95 -0
  102. package/lib/engine/tools/write.mjs +76 -0
  103. package/lib/engine/tui/line-editor.mjs +137 -0
  104. package/lib/engine/tui/render.mjs +86 -0
  105. package/lib/engine/tui/tui.mjs +274 -0
  106. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  107. package/lib/engine/wire/effort.mjs +36 -0
  108. package/lib/engine/wire/errors.mjs +496 -0
  109. package/lib/engine/wire/http.mjs +441 -0
  110. package/lib/engine/wire/index.mjs +76 -0
  111. package/lib/engine/wire/openai-chat.mjs +332 -0
  112. package/lib/engine/wire/prompt-cache.mjs +79 -0
  113. package/lib/engine/wire/search.mjs +140 -0
  114. package/lib/engine/wire/sse.mjs +114 -0
  115. package/lib/engine/wire/stall.mjs +349 -0
  116. package/lib/engine/wire/token-provider.mjs +175 -0
  117. package/lib/engine/wire/usage.mjs +192 -0
  118. package/lib/engine/workflow/host.mjs +524 -0
  119. package/lib/engine/workflow/journal.mjs +188 -0
  120. package/lib/engine/workflow/json-schema.mjs +171 -0
  121. package/lib/engine/workflow/meta.mjs +329 -0
  122. package/lib/engine/workflow/notifications.mjs +52 -0
  123. package/lib/engine/workflow/runtime.mjs +447 -0
  124. package/lib/engine/workflow/sandbox.mjs +534 -0
  125. package/lib/engine/workflow/worker.mjs +141 -0
  126. package/lib/engine/workflow/worktree.mjs +74 -0
  127. package/lib/execution/disposition.mjs +1 -1
  128. package/lib/execution/intake.mjs +10 -0
  129. package/lib/execution/surface-policy.mjs +15 -0
  130. package/lib/learning/curator.mjs +8 -6
  131. package/lib/learning/reflect.mjs +8 -6
  132. package/lib/model-router/catalog/cohort.yaml +137 -0
  133. package/lib/model-router/catalog.mjs +118 -1
  134. package/lib/model-router/failover.mjs +67 -16
  135. package/lib/model-router/llm-task.mjs +39 -3
  136. package/lib/model-router/resolve.mjs +89 -3
  137. package/lib/model-router/spawn.mjs +46 -47
  138. package/lib/model-router/taxonomy.mjs +126 -4
  139. package/lib/org/cost-sync.mjs +141 -11
  140. package/lib/org/inbound/broadcast.mjs +289 -0
  141. package/lib/org/inbound/collective.mjs +375 -0
  142. package/lib/org/inbound/directedness.mjs +96 -8
  143. package/lib/org/inbound/facts.mjs +78 -2
  144. package/lib/org/inbound/project.mjs +22 -0
  145. package/lib/org/inbound/surfaces.mjs +14 -0
  146. package/lib/org/llm-token.mjs +879 -0
  147. package/lib/org/mesh.mjs +61 -0
  148. package/lib/org/messaging.mjs +3 -1
  149. package/lib/org/protocol.checksum +1 -1
  150. package/lib/org/protocol.mjs +15 -0
  151. package/lib/org/quota.mjs +520 -0
  152. package/lib/org/tool-surface.mjs +104 -16
  153. package/lib/org/ui-parity.mjs +16 -1
  154. package/lib/org/work-ledger.mjs +37 -6
  155. package/lib/rate-guard.mjs +114 -1
  156. package/lib/resource-governor.mjs +41 -6
  157. package/lib/runtime/adapter.mjs +823 -0
  158. package/lib/runtime/child-env.mjs +191 -0
  159. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  160. package/lib/runtime/seat-engine.mjs +162 -0
  161. package/lib/session/ask-ledger.mjs +271 -0
  162. package/lib/session/current-work.mjs +676 -0
  163. package/lib/session/feed-core.mjs +40 -3
  164. package/lib/session/launch-args.mjs +56 -4
  165. package/lib/session/status-summary.mjs +26 -9
  166. package/lib/session/upgrade-notice.mjs +42 -0
  167. package/lib/setup/claude-probe.mjs +117 -13
  168. package/lib/setup/enrich.mjs +13 -10
  169. package/lib/setup/sections/model.mjs +39 -13
  170. package/lib/telemetry/collect.mjs +208 -9
  171. package/lib/upgrade/ignored-drift.mjs +105 -0
  172. package/lib/voice/post-call-brief.mjs +30 -17
  173. package/package.json +13 -3
  174. package/plugins/maestro-skills/skills/board-work.md +5 -0
  175. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  176. package/plugins/maestro-skills/skills/main-session.md +18 -7
  177. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  178. package/scripts/ci/run-tests.mjs +47 -19
  179. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  180. package/scripts/collective/hook-runner.mjs +29 -2
  181. package/scripts/continuous-monitor.sh +13 -0
  182. package/scripts/cost/track-claude-usage.mjs +15 -0
  183. package/scripts/daemon/agent-daemon.mjs +408 -20
  184. package/scripts/daemon/assurance.mjs +48 -12
  185. package/scripts/daemon/cadence-consumer.mjs +218 -68
  186. package/scripts/daemon/cadence-handlers.mjs +73 -4
  187. package/scripts/daemon/classifier.mjs +75 -26
  188. package/scripts/daemon/context-compiler.mjs +51 -37
  189. package/scripts/daemon/deliver.mjs +30 -1
  190. package/scripts/daemon/dispatcher.mjs +595 -149
  191. package/scripts/daemon/health.mjs +14 -1
  192. package/scripts/daemon/maestro-daemon.mjs +11 -0
  193. package/scripts/daemon/prompt-builder.mjs +24 -0
  194. package/scripts/daemon/responder.mjs +246 -79
  195. package/scripts/daemon/sdk-version.mjs +98 -16
  196. package/scripts/eval/probe-gateway.mjs +635 -0
  197. package/scripts/eval/replay/extract.mjs +270 -0
  198. package/scripts/eval/replay/grade.mjs +260 -0
  199. package/scripts/eval/replay/lib/config.mjs +50 -0
  200. package/scripts/eval/replay/lib/effects.mjs +65 -0
  201. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  202. package/scripts/eval/replay/lib/judge.mjs +72 -0
  203. package/scripts/eval/replay/lib/redact.mjs +136 -0
  204. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  205. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  206. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  207. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  208. package/scripts/eval/replay/report.mjs +185 -0
  209. package/scripts/eval/replay/run.mjs +404 -0
  210. package/scripts/fleet/rollout.mjs +1094 -0
  211. package/scripts/hooks/pre-send-audit.sh +36 -245
  212. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  213. package/scripts/hooks/validate-state-yaml.sh +190 -0
  214. package/scripts/huddle/huddle-llm.mjs +361 -0
  215. package/scripts/huddle/huddle-server.mjs +46 -121
  216. package/scripts/local-triggers/autoupdate.sh +448 -78
  217. package/scripts/local-triggers/run-trigger.sh +13 -0
  218. package/scripts/maintenance/pin-integrity.mjs +364 -0
  219. package/scripts/poll-slack-events.sh +41 -9
  220. package/scripts/poller/slack-socket-mode.mjs +28 -3
  221. package/scripts/session/supervisor.mjs +80 -13
  222. package/scripts/spawn-session.sh +13 -0
  223. package/bin/maestro.test.mjs +0 -1574
  224. package/lib/action-executor.test.mjs +0 -871
  225. package/lib/archetype.test.mjs +0 -132
  226. package/lib/assurance/plan-note.test.mjs +0 -234
  227. package/lib/assurance/room-budget.test.mjs +0 -486
  228. package/lib/assurance/tier.test.mjs +0 -174
  229. package/lib/autonomy.test.mjs +0 -66
  230. package/lib/backlog.test.mjs +0 -302
  231. package/lib/backup/policy.test.mjs +0 -305
  232. package/lib/budget-escalate.test.mjs +0 -232
  233. package/lib/budget-guard.envelope.test.mjs +0 -476
  234. package/lib/budget-guard.test.mjs +0 -427
  235. package/lib/cadence-bus-requeue.test.mjs +0 -83
  236. package/lib/cadence-bus-schedule.test.mjs +0 -194
  237. package/lib/cadence-bus.test.mjs +0 -720
  238. package/lib/cadences.test.mjs +0 -230
  239. package/lib/capability/inventory.test.mjs +0 -232
  240. package/lib/capability.test.mjs +0 -78
  241. package/lib/channels/base-adapter.test.mjs +0 -590
  242. package/lib/channels/channels.test.mjs +0 -371
  243. package/lib/channels/contract.test.mjs +0 -162
  244. package/lib/channels/inbox-item.test.mjs +0 -368
  245. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  246. package/lib/channels/pairing.test.mjs +0 -270
  247. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  248. package/lib/channels/slack-adapter.test.mjs +0 -212
  249. package/lib/channels/telegram-adapter.test.mjs +0 -306
  250. package/lib/channels/voice/adapter.test.mjs +0 -278
  251. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  252. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  253. package/lib/charter.test.mjs +0 -89
  254. package/lib/claude-bin.test.mjs +0 -131
  255. package/lib/cli/board.test.mjs +0 -227
  256. package/lib/cli/design.test.mjs +0 -270
  257. package/lib/cli/doctor-checks.test.mjs +0 -336
  258. package/lib/cli/global-setup-extras.test.mjs +0 -462
  259. package/lib/cli/inbox.test.mjs +0 -230
  260. package/lib/cli/session-ack.test.mjs +0 -63
  261. package/lib/cli/session.test.mjs +0 -613
  262. package/lib/collective/capture.test.mjs +0 -121
  263. package/lib/collective/cards.test.mjs +0 -114
  264. package/lib/collective/config.test.mjs +0 -123
  265. package/lib/collective/global-config.test.mjs +0 -220
  266. package/lib/collective/global-skills.test.mjs +0 -126
  267. package/lib/collective/presence.test.mjs +0 -95
  268. package/lib/collective/recall.test.mjs +0 -116
  269. package/lib/collective/vendor-skills.test.mjs +0 -306
  270. package/lib/comms/send-gate.test.mjs +0 -770
  271. package/lib/comms.test.mjs +0 -41
  272. package/lib/context/budget.test.mjs +0 -252
  273. package/lib/context/history-scope.test.mjs +0 -79
  274. package/lib/cost/ledger-row.test.mjs +0 -183
  275. package/lib/design/design-md.test.mjs +0 -318
  276. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  277. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  278. package/lib/design/fixtures/foundation.json +0 -133
  279. package/lib/design/refresh-gate.test.mjs +0 -144
  280. package/lib/design/write.test.mjs +0 -241
  281. package/lib/diagnostics/alerts.test.mjs +0 -318
  282. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  283. package/lib/diagnostics/counters.test.mjs +0 -206
  284. package/lib/diagnostics/events.test.mjs +0 -290
  285. package/lib/diagnostics/otel.test.mjs +0 -196
  286. package/lib/diagnostics/trace.test.mjs +0 -251
  287. package/lib/env-compat.test.mjs +0 -104
  288. package/lib/execution/disposition.test.mjs +0 -553
  289. package/lib/execution/drive.test.mjs +0 -270
  290. package/lib/execution/effects.test.mjs +0 -344
  291. package/lib/execution/intake.test.mjs +0 -389
  292. package/lib/execution/journal.test.mjs +0 -261
  293. package/lib/execution/match.test.mjs +0 -235
  294. package/lib/execution/pipeline.test.mjs +0 -392
  295. package/lib/execution/route.test.mjs +0 -186
  296. package/lib/execution/surface-policy.test.mjs +0 -162
  297. package/lib/fs-atomic.test.mjs +0 -72
  298. package/lib/fs-ownership.test.mjs +0 -158
  299. package/lib/goals/admission.test.mjs +0 -164
  300. package/lib/goals/classify.test.mjs +0 -167
  301. package/lib/goals/collaborate.test.mjs +0 -336
  302. package/lib/goals/gaps.test.mjs +0 -284
  303. package/lib/goals/loop.test.mjs +0 -845
  304. package/lib/hooks/bus.test.mjs +0 -387
  305. package/lib/identity/persona.test.mjs +0 -142
  306. package/lib/kpi-sensors.test.mjs +0 -278
  307. package/lib/kpi.test.mjs +0 -244
  308. package/lib/learning/config.test.mjs +0 -75
  309. package/lib/learning/counters.test.mjs +0 -69
  310. package/lib/learning/curator-consolidate.test.mjs +0 -238
  311. package/lib/learning/curator.test.mjs +0 -106
  312. package/lib/learning/reflect.test.mjs +0 -0
  313. package/lib/learning/session-index.test.mjs +0 -125
  314. package/lib/learning/skill-writer.test.mjs +0 -210
  315. package/lib/mandate/audit.test.mjs +0 -195
  316. package/lib/mandate/contract.test.mjs +0 -185
  317. package/lib/mandate/derive.test.mjs +0 -274
  318. package/lib/mandate/model.test.mjs +0 -164
  319. package/lib/mandate/refresh.test.mjs +0 -389
  320. package/lib/mcp/server.test.mjs +0 -426
  321. package/lib/model-router/auth-profiles.test.mjs +0 -580
  322. package/lib/model-router/catalog.test.mjs +0 -385
  323. package/lib/model-router/economics.test.mjs +0 -438
  324. package/lib/model-router/failover.test.mjs +0 -439
  325. package/lib/model-router/health.test.mjs +0 -338
  326. package/lib/model-router/integration-coverage.test.mjs +0 -831
  327. package/lib/model-router/integration.test.mjs +0 -564
  328. package/lib/model-router/ledger.test.mjs +0 -415
  329. package/lib/model-router/llm-task.test.mjs +0 -392
  330. package/lib/model-router/org-credentials.test.mjs +0 -265
  331. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  332. package/lib/model-router/reconcile.test.mjs +0 -316
  333. package/lib/model-router/repair.test.mjs +0 -180
  334. package/lib/model-router/spawn.test.mjs +0 -446
  335. package/lib/model-router/taxonomy.test.mjs +0 -410
  336. package/lib/model-router.test.mjs +0 -1207
  337. package/lib/org/activity.test.mjs +0 -134
  338. package/lib/org/approvals.test.mjs +0 -216
  339. package/lib/org/awareness.test.mjs +0 -159
  340. package/lib/org/board-mine-cache.test.mjs +0 -53
  341. package/lib/org/board.test.mjs +0 -187
  342. package/lib/org/bootstrap-context.test.mjs +0 -153
  343. package/lib/org/client.test.mjs +0 -1206
  344. package/lib/org/cohort-client.test.mjs +0 -126
  345. package/lib/org/cost-sync.test.mjs +0 -153
  346. package/lib/org/doctor.test.mjs +0 -346
  347. package/lib/org/engagement-ledger.test.mjs +0 -112
  348. package/lib/org/engagement.test.mjs +0 -739
  349. package/lib/org/handoff.test.mjs +0 -269
  350. package/lib/org/inbound/directedness.test.mjs +0 -668
  351. package/lib/org/inbound/facts.test.mjs +0 -471
  352. package/lib/org/inbound/hydrate.test.mjs +0 -908
  353. package/lib/org/inbound/index.test.mjs +0 -429
  354. package/lib/org/inbound/project.test.mjs +0 -287
  355. package/lib/org/integration-tools.test.mjs +0 -160
  356. package/lib/org/keys.test.mjs +0 -92
  357. package/lib/org/knowledge.test.mjs +0 -326
  358. package/lib/org/leases.test.mjs +0 -235
  359. package/lib/org/mesh-directives.test.mjs +0 -110
  360. package/lib/org/mesh-integration.test.mjs +0 -127
  361. package/lib/org/mesh.test.mjs +0 -400
  362. package/lib/org/messaging.test.mjs +0 -471
  363. package/lib/org/param-contract.test.mjs +0 -477
  364. package/lib/org/policy.test.mjs +0 -237
  365. package/lib/org/protocol.checksum.test.mjs +0 -90
  366. package/lib/org/protocol.test.mjs +0 -323
  367. package/lib/org/push.test.mjs +0 -792
  368. package/lib/org/registry.test.mjs +0 -100
  369. package/lib/org/resource-tools.test.mjs +0 -361
  370. package/lib/org/tool-access.test.mjs +0 -144
  371. package/lib/org/tool-surface-integration.test.mjs +0 -120
  372. package/lib/org/tool-surface.test.mjs +0 -1268
  373. package/lib/org/typing.test.mjs +0 -291
  374. package/lib/org/ui-parity.test.mjs +0 -560
  375. package/lib/org/verify.test.mjs +0 -194
  376. package/lib/org/work-ledger.test.mjs +0 -273
  377. package/lib/plan/adoption-e2e.test.mjs +0 -366
  378. package/lib/plan/budget-enforcement.test.mjs +0 -400
  379. package/lib/plan/compile.test.mjs +0 -382
  380. package/lib/plan/emit.test.mjs +0 -269
  381. package/lib/plan/explain.test.mjs +0 -188
  382. package/lib/prompts/parallelism.test.mjs +0 -177
  383. package/lib/rag/rag.test.mjs +0 -505
  384. package/lib/rate-guard.test.mjs +0 -272
  385. package/lib/reactive-gate.test.mjs +0 -57
  386. package/lib/render.test.mjs +0 -68
  387. package/lib/resource-governor.test.mjs +0 -488
  388. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  389. package/lib/scheduling/jitter.test.mjs +0 -140
  390. package/lib/secrets/broker.test.mjs +0 -280
  391. package/lib/secrets/providers.test.mjs +0 -274
  392. package/lib/security/audit-engine.test.mjs +0 -424
  393. package/lib/security/coerce-args.test.mjs +0 -281
  394. package/lib/security/dangerous-tools.test.mjs +0 -68
  395. package/lib/security/external-content.test.mjs +0 -84
  396. package/lib/security/redact.test.mjs +0 -441
  397. package/lib/security/secret-equal.test.mjs +0 -55
  398. package/lib/session/config.test.mjs +0 -92
  399. package/lib/session/feed-core.test.mjs +0 -198
  400. package/lib/session/first-run.test.mjs +0 -121
  401. package/lib/session/frontdoor.test.mjs +0 -205
  402. package/lib/session/handoffs.test.mjs +0 -183
  403. package/lib/session/identity.test.mjs +0 -180
  404. package/lib/session/inbox-claims.test.mjs +0 -286
  405. package/lib/session/launch-args.test.mjs +0 -157
  406. package/lib/session/liveness.test.mjs +0 -100
  407. package/lib/session/status-summary.test.mjs +0 -118
  408. package/lib/session-permissions.test.mjs +0 -120
  409. package/lib/setup/claude-probe.test.mjs +0 -187
  410. package/lib/setup/completeness.test.mjs +0 -110
  411. package/lib/setup/context-pack.test.mjs +0 -89
  412. package/lib/setup/enrich.test.mjs +0 -115
  413. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  414. package/lib/setup/integration.test.mjs +0 -162
  415. package/lib/setup/io.test.mjs +0 -77
  416. package/lib/setup/runner.test.mjs +0 -132
  417. package/lib/setup/sections/identity.test.mjs +0 -234
  418. package/lib/setup/sections/inventory.test.mjs +0 -198
  419. package/lib/setup/sections/learning.test.mjs +0 -81
  420. package/lib/setup/sections/mandate.test.mjs +0 -388
  421. package/lib/setup/sections/messaging.test.mjs +0 -127
  422. package/lib/setup/sections/model.test.mjs +0 -240
  423. package/lib/setup/sections/org.test.mjs +0 -346
  424. package/lib/setup/sections/orgmail.test.mjs +0 -118
  425. package/lib/setup/sections/recovery.test.mjs +0 -98
  426. package/lib/setup/sections/subagents.test.mjs +0 -429
  427. package/lib/setup/sections/verify.test.mjs +0 -175
  428. package/lib/setup/sot.test.mjs +0 -81
  429. package/lib/setup/state.test.mjs +0 -115
  430. package/lib/singleton.test.mjs +0 -151
  431. package/lib/subagents/cli.test.mjs +0 -389
  432. package/lib/subagents/client.test.mjs +0 -309
  433. package/lib/subagents/gap.test.mjs +0 -234
  434. package/lib/subagents/lock.test.mjs +0 -248
  435. package/lib/subagents/manifest.test.mjs +0 -175
  436. package/lib/subagents/refs.test.mjs +0 -204
  437. package/lib/subagents/resolve.test.mjs +0 -422
  438. package/lib/subagents/schema.test.mjs +0 -328
  439. package/lib/telemetry/alerts.test.mjs +0 -109
  440. package/lib/telemetry/collect.test.mjs +0 -1274
  441. package/lib/tool-definitions-integration.test.mjs +0 -83
  442. package/lib/tool-definitions.test.mjs +0 -437
  443. package/lib/upgrade/global-refresh.test.mjs +0 -65
  444. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  445. package/lib/upgrade/post-steps.test.mjs +0 -200
  446. package/lib/upgrade/verify.test.mjs +0 -164
  447. package/lib/util/fetch-timeout.test.mjs +0 -202
  448. package/lib/util/reconnect.test.mjs +0 -369
  449. package/lib/util/unhandled.test.mjs +0 -216
  450. package/lib/voice/outbound.test.mjs +0 -69
  451. package/lib/voice/session-rotation.test.mjs +0 -114
  452. package/lib/voice/stt.test.mjs +0 -226
  453. package/lib/voice/voice.test.mjs +0 -990
  454. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  455. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  456. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  457. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  458. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  459. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  460. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  461. package/scripts/ci/check.test.mjs +0 -194
  462. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  463. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  464. package/scripts/collective/hook-runner.test.mjs +0 -173
  465. package/scripts/cost/fleet-digest.test.mjs +0 -207
  466. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  467. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  468. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  469. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  470. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  471. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  472. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  473. package/scripts/daemon/assurance.test.mjs +0 -1791
  474. package/scripts/daemon/board-mirror.test.mjs +0 -165
  475. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  476. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  477. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  478. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  479. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  480. package/scripts/daemon/classifier.test.mjs +0 -266
  481. package/scripts/daemon/classify-kind.test.mjs +0 -40
  482. package/scripts/daemon/context-compiler.test.mjs +0 -406
  483. package/scripts/daemon/deliver.test.mjs +0 -564
  484. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  485. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  486. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  487. package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
  488. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  489. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  490. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  491. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  492. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  493. package/scripts/daemon/integration.test.mjs +0 -149
  494. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  495. package/scripts/daemon/lib/session-router.test.mjs +0 -554
  496. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  497. package/scripts/daemon/prompt-builder.test.mjs +0 -556
  498. package/scripts/daemon/responder-cost.test.mjs +0 -68
  499. package/scripts/daemon/responder-history.test.mjs +0 -221
  500. package/scripts/daemon/sdk-version.test.mjs +0 -31
  501. package/scripts/daemon/session-lock.test.mjs +0 -252
  502. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  503. package/scripts/daemon/typing-registry.test.mjs +0 -102
  504. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  505. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  506. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  507. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  508. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  509. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  510. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  511. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  512. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  513. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  514. package/scripts/poller-launchd/install.test.mjs +0 -243
  515. package/scripts/restore-from-backup.test.mjs +0 -181
  516. package/scripts/session/feed.test.mjs +0 -196
  517. package/scripts/session/supervisor-sh.test.mjs +0 -218
  518. package/scripts/session/supervisor.test.mjs +0 -482
  519. package/scripts/setup/configure-macos.test.mjs +0 -306
  520. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  521. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  522. package/scripts/setup/generate-capability.test.mjs +0 -134
  523. package/scripts/setup/init-agent.test.mjs +0 -370
  524. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  525. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  526. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -1,234 +0,0 @@
1
- /**
2
- * identity.test.mjs — Cohort-driven setup pull in the identity section.
3
- *
4
- * Focuses on the pull seam added for Cohort-driven setup: when COHORT_API_KEY +
5
- * COHORT_ORG_ID are present, prompt()/apply() PULL the agent's record and merge
6
- * it into config/agent.json so the prompts CONFIRM (rather than start blank); a
7
- * locally-customised value is protected unless --force; absent vars leave the
8
- * manual path unchanged. The real client.fetchSelfProfile is exercised via an
9
- * injected global fetch (no network).
10
- *
11
- * Run: node --test lib/setup/sections/identity.test.mjs
12
- */
13
- "use strict";
14
-
15
- import { test } from "node:test";
16
- import assert from "node:assert/strict";
17
- import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
18
- import { tmpdir } from "node:os";
19
- import { join, dirname } from "node:path";
20
- import { fileURLToPath } from "node:url";
21
-
22
- import identity from "./identity.mjs";
23
- import { readAgentJson } from "../sot.mjs";
24
- import * as io from "../io.mjs";
25
-
26
- const MAESTRO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
27
-
28
- function tmpRoot() {
29
- const root = mkdtempSync(join(tmpdir(), "maestro-identity-"));
30
- mkdirSync(join(root, "config"), { recursive: true });
31
- return root;
32
- }
33
- function ctxFor(root, answers = {}) {
34
- return { agentRoot: root, maestroRoot: MAESTRO_ROOT, flags: { headless: true }, answers, io };
35
- }
36
- function writeAgent(root, obj) {
37
- writeFileSync(join(root, "config", "agent.json"), JSON.stringify(obj, null, 2) + "\n");
38
- }
39
-
40
- const PROFILE = {
41
- slug: "robin", kind: "agent", displayName: "Robin Vega", firstName: "Robin", lastName: "Vega",
42
- title: "VP Eng", team: "Platform", role: "engineering-lead", agentEmail: "robin@example.com",
43
- supervisor: { displayName: "Layla Al-Masri", title: "CTO", email: "layla@example.com" },
44
- };
45
-
46
- function withCohortEnv(vars, fn) {
47
- const keys = ["COHORT_API_KEY", "COHORT_ORG_ID", "COHORT_AGENT_ID", "COHORT_BASE"];
48
- const saved = Object.fromEntries(keys.map((k) => [k, process.env[k]]));
49
- for (const k of keys) delete process.env[k];
50
- Object.assign(process.env, vars);
51
- return Promise.resolve().then(fn).finally(() => {
52
- for (const k of keys) { if (saved[k] === undefined) delete process.env[k]; else process.env[k] = saved[k]; }
53
- });
54
- }
55
-
56
- function withFetch(impl, fn) {
57
- const saved = globalThis.fetch;
58
- globalThis.fetch = impl;
59
- return Promise.resolve().then(fn).finally(() => { globalThis.fetch = saved; });
60
- }
61
-
62
- const okFetch = (sink) => async (url) => {
63
- if (sink) sink.push(String(url));
64
- return { ok: true, status: 200, headers: { get: () => undefined }, json: async () => PROFILE };
65
- };
66
-
67
- test("section shape: id/order=10/hooks", () => {
68
- assert.equal(identity.id, "identity");
69
- assert.equal(identity.order, 10);
70
- for (const h of ["detect", "prompt", "apply", "verify"]) assert.equal(typeof identity[h], "function");
71
- });
72
-
73
- test("prompt: with COHORT_* env, pulls the profile into config/agent.json", async () => {
74
- const root = tmpRoot();
75
- writeAgent(root, { firstName: "UNCONFIGURED" });
76
- const urls = [];
77
- await withCohortEnv(
78
- { COHORT_API_KEY: "k", COHORT_ORG_ID: "acme", COHORT_AGENT_ID: "robin", COHORT_BASE: "https://cohort.example" },
79
- () => withFetch(okFetch(urls), async () => {
80
- const ctx = ctxFor(root);
81
- await identity.prompt(ctx);
82
- // Headless prompt resolves the answers from the (now pulled) config defaults.
83
- assert.equal(ctx.answers.identity.firstName, "Robin");
84
- assert.equal(ctx.answers.identity.email, "robin@example.com");
85
- })
86
- );
87
- assert.ok(urls.some((u) => u.includes("/api/v1/org/members/robin")), "members endpoint hit");
88
- const id = readAgentJson(root);
89
- assert.equal(id.firstName, "Robin", "placeholder overwritten by pull");
90
- assert.equal(id.function, "technical-leader");
91
- });
92
-
93
- test("COHORT_AGENT_ID selects /org/members/<id>; absent selects whoami", async () => {
94
- const root = tmpRoot();
95
- const urls = [];
96
- await withCohortEnv(
97
- { COHORT_API_KEY: "k", COHORT_ORG_ID: "acme", COHORT_BASE: "https://cohort.example" },
98
- () => withFetch(okFetch(urls), async () => {
99
- await identity.prompt(ctxFor(root));
100
- })
101
- );
102
- assert.ok(urls.some((u) => u.includes("/api/v1/org/whoami?orgId=acme")), "whoami endpoint hit when no agent id (org sent as the tenant pin, not a member slug)");
103
- });
104
-
105
- test("a local override is NOT clobbered by the pull (without --force)", async () => {
106
- const root = tmpRoot();
107
- writeAgent(root, { title: "My Custom Title", firstName: "" });
108
- await withCohortEnv(
109
- { COHORT_API_KEY: "k", COHORT_ORG_ID: "acme", COHORT_AGENT_ID: "robin", COHORT_BASE: "https://cohort.example" },
110
- () => withFetch(okFetch(), async () => {
111
- await identity.prompt(ctxFor(root));
112
- })
113
- );
114
- const id = readAgentJson(root);
115
- assert.equal(id.title, "My Custom Title", "operator title preserved");
116
- assert.equal(id.firstName, "Robin", "empty field still filled from org");
117
- });
118
-
119
- test("absent COHORT_* env → no pull (manual path unchanged)", async () => {
120
- const root = tmpRoot();
121
- writeAgent(root, { firstName: "UNCONFIGURED" });
122
- let fetched = false;
123
- await withCohortEnv({}, () => withFetch(async () => { fetched = true; return { ok: true, status: 200, headers: { get: () => undefined }, json: async () => PROFILE }; }, async () => {
124
- await identity.prompt(ctxFor(root));
125
- }));
126
- assert.equal(fetched, false, "no network call without the pull env");
127
- assert.equal(readAgentJson(root).firstName, "UNCONFIGURED", "config unchanged");
128
- });
129
-
130
- test("pull is fail-open: a fetch error leaves config untouched", async () => {
131
- const root = tmpRoot();
132
- writeAgent(root, { firstName: "UNCONFIGURED" });
133
- await withCohortEnv(
134
- { COHORT_API_KEY: "k", COHORT_ORG_ID: "acme", COHORT_AGENT_ID: "robin", COHORT_BASE: "https://cohort.example" },
135
- () => withFetch(async () => { throw new Error("network down"); }, async () => {
136
- await identity.prompt(ctxFor(root)); // must not throw
137
- })
138
- );
139
- assert.equal(readAgentJson(root).firstName, "UNCONFIGURED");
140
- });
141
-
142
- // ---------------------------------------------------------------------------
143
- // ARCHETYPE AXES (the fatal apply() regression).
144
- //
145
- // The wizard used to offer `people-leader` and `compliance-leader`, neither of
146
- // which has an archetype file on disk. Picking either resolved to nothing and
147
- // made apply() throw — and because the whole init pipeline downstream
148
- // (capability pack -> cadences -> plan compiler) keys off this value, a bad axis
149
- // poisons everything after it. These assert the invariant against the real
150
- // filesystem, so adding an archetype without offering it (or offering one that
151
- // does not exist) fails here rather than in a user's setup run.
152
- // ---------------------------------------------------------------------------
153
-
154
- import { FUNCTIONS, ALTITUDES } from "./identity.mjs";
155
- import { listFunctions, listAltitudes, resolveArchetype } from "../../archetype.mjs";
156
- import { FUNCTIONS as ENROLL_FUNCTIONS, ALTITUDES as ENROLL_ALTITUDES, deriveFunction, deriveAltitude } from "../enroll-from-cohort.mjs";
157
- import { loadSections } from "../runner.mjs";
158
-
159
- test("every function the wizard offers has an archetype file on disk", () => {
160
- const onDisk = listFunctions();
161
- for (const f of FUNCTIONS) {
162
- assert.ok(onDisk.includes(f.value), `wizard offers "${f.value}" but archetypes/functions/${f.value}.yaml does not exist`);
163
- }
164
- });
165
-
166
- test("every archetype on disk is offered by the wizard (no orphaned archetype)", () => {
167
- const offered = new Set(FUNCTIONS.map((f) => f.value));
168
- for (const f of listFunctions()) {
169
- assert.ok(offered.has(f), `archetypes/functions/${f}.yaml exists but the wizard never offers it`);
170
- }
171
- });
172
-
173
- test("every altitude the wizard offers has an archetype file, and vice versa", () => {
174
- const onDisk = listAltitudes();
175
- for (const a of ALTITUDES) assert.ok(onDisk.includes(a.value), `wizard offers altitude "${a.value}" with no archetypes/altitudes/${a.value}.yaml`);
176
- const offered = new Set(ALTITUDES.map((a) => a.value));
177
- for (const a of onDisk) assert.ok(offered.has(a), `archetypes/altitudes/${a}.yaml exists but the wizard never offers it`);
178
- });
179
-
180
- test("`founder` is reachable from the wizard (it owns runway + investor cadences)", () => {
181
- assert.ok(ALTITUDES.some((a) => a.value === "founder"), "founder altitude is offered");
182
- });
183
-
184
- test("the pull path can only derive an axis the wizard can render", () => {
185
- // enroll-from-cohort writes function/altitude straight into config/agent.json,
186
- // so a value it can derive but the wizard cannot render is an un-resolvable seat.
187
- const offeredFns = new Set(FUNCTIONS.map((f) => f.value));
188
- for (const f of ENROLL_FUNCTIONS) assert.ok(offeredFns.has(f), `enroll can derive "${f}" which the wizard cannot render`);
189
- const offeredAlts = new Set(ALTITUDES.map((a) => a.value));
190
- for (const a of ENROLL_ALTITUDES) assert.ok(offeredAlts.has(a), `enroll can derive altitude "${a}" which the wizard cannot render`);
191
- });
192
-
193
- test("the retired axes are gone from BOTH lists", () => {
194
- for (const dead of ["people-leader", "compliance-leader"]) {
195
- assert.ok(!FUNCTIONS.some((f) => f.value === dead), `wizard still offers the non-existent "${dead}"`);
196
- assert.ok(!ENROLL_FUNCTIONS.includes(dead), `enroll can still derive the non-existent "${dead}"`);
197
- }
198
- });
199
-
200
- test("the roles that used to derive a dead axis now derive a real one", () => {
201
- assert.equal(deriveFunction({ role: "Head of People", team: "HR" }), "operations-leader");
202
- assert.equal(deriveFunction({ role: "general counsel", team: "Legal" }), "compliance-officer");
203
- assert.equal(deriveFunction({ role: "Head of Product", team: "Product" }), "product-leader");
204
- assert.equal(deriveAltitude({ title: "Co-Founder & CEO" }), "founder");
205
- });
206
-
207
- test("every offered (function, altitude) pair actually resolves to an archetype", async () => {
208
- // The real end-to-end guarantee: no combination the wizard can produce throws.
209
- for (const f of FUNCTIONS) {
210
- for (const a of ALTITUDES) {
211
- const arch = await resolveArchetype({ function: f.value, altitude: a.value });
212
- assert.ok(arch && typeof arch === "object", `resolveArchetype failed for ${f.value}/${a.value}`);
213
- }
214
- }
215
- });
216
-
217
- test("every derivable pull result resolves to an archetype too", async () => {
218
- for (const f of ENROLL_FUNCTIONS) {
219
- for (const a of ENROLL_ALTITUDES) {
220
- const arch = await resolveArchetype({ function: f, altitude: a });
221
- assert.ok(arch && typeof arch === "object", `resolveArchetype failed for pulled ${f}/${a}`);
222
- }
223
- }
224
- });
225
-
226
- test("the identity section is registered by the directory glob at order 10", async () => {
227
- const sections = await loadSections();
228
- const s = sections.find((x) => x.id === "identity");
229
- assert.ok(s, "identity is discovered by loadSections()");
230
- assert.equal(s.order, 10);
231
- assert.equal(s.order, identity.order);
232
- // It must run before the capability inventory, which reads its archetype.
233
- assert.ok(s.order < sections.find((x) => x.id === "inventory").order);
234
- });
@@ -1,198 +0,0 @@
1
- /**
2
- * inventory.test.mjs — the capability-inventory setup section (order 55).
3
- * Run: node --test lib/setup/sections/inventory.test.mjs
4
- *
5
- * Also asserts the REGISTRATION mechanism itself: runner.loadSections() globs
6
- * this directory, so the section must be discoverable and correctly ordered
7
- * without any core edit.
8
- */
9
- "use strict";
10
-
11
- import { test } from "node:test";
12
- import assert from "node:assert/strict";
13
- import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync } from "node:fs";
14
- import { tmpdir } from "node:os";
15
- import { join, dirname } from "node:path";
16
- import { fileURLToPath } from "node:url";
17
-
18
- import inventory, { archetypeOf, declareCapability } from "./inventory.mjs";
19
- import { loadSections } from "../runner.mjs";
20
- import { MANIFEST_REL } from "../../capability/inventory.mjs";
21
- import * as io from "../io.mjs";
22
-
23
- const MAESTRO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
24
-
25
- /**
26
- * A tmp agent repo, a tmp HOME and a tmp MAESTRO_ROOT. The framework root is
27
- * faked deliberately: `repair:true` writes marketplace manifests into the plugin
28
- * dirs it scans, and a test must never mutate the real repo (or the operator's
29
- * ~/.claude/settings.json).
30
- */
31
- function tmpRoot({ archetype = true } = {}) {
32
- const root = mkdtempSync(join(tmpdir(), "maestro-invsec-"));
33
- const home = mkdtempSync(join(tmpdir(), "maestro-invhome-"));
34
- const fakeMaestro = mkdtempSync(join(tmpdir(), "maestro-invfw-"));
35
- mkdirSync(join(root, "config"), { recursive: true });
36
- writeFileSync(join(root, "config", "agent.json"), JSON.stringify(
37
- archetype ? { firstName: "Placeholder", function: "executive-operator", altitude: "c-suite" } : { firstName: "Placeholder" },
38
- ));
39
- mkdirSync(join(root, "plugins", "agent-skills", "skills"), { recursive: true });
40
- writeFileSync(join(root, "plugins", "agent-skills", "skills", "morning-brief.md"), "# morning-brief\n");
41
- writeFileSync(join(root, ".mcp.json"), JSON.stringify({ mcpServers: { cohort: { command: "cohort-mcp" } } }));
42
- return { root, home, fakeMaestro };
43
- }
44
-
45
- function ctxFor(root, home, answers = {}, extra = {}) {
46
- return {
47
- agentRoot: root,
48
- maestroRoot: extra.maestroRoot || MAESTRO_ROOT,
49
- flags: { headless: true },
50
- answers,
51
- io,
52
- capabilityDeps: {
53
- homeDir: home,
54
- now: () => "2026-08-11T09:00:00.000Z",
55
- logImpl: () => {},
56
- orgToolsImpl: async () => [
57
- { name: "board_ready", access: "read", binding: { kind: "rpc" } },
58
- { name: "task_create", access: "write", binding: { kind: "rpc" } },
59
- ],
60
- orgProbeImpl: async () => ({ ok: true, detail: "round-trip ok", mandateFamily: true }),
61
- capabilitySurface: async () => ({ workflows: [{ id: "weekly-operating-review", cadence: "weekly" }] }),
62
- wishlistImpl: async () => [],
63
- callImpl: async () => ({ ok: true, result: {} }),
64
- ...(extra.capabilityDeps || {}),
65
- },
66
- };
67
- }
68
-
69
- test("REGISTRATION: runner.loadSections() discovers `inventory` at order 55, between tools(50) and operating-model(60)", async () => {
70
- const sections = await loadSections();
71
- const ids = sections.map((s) => s.id);
72
- assert.ok(ids.includes("inventory"), "section is auto-discovered by the directory glob — no dispatcher edit");
73
- const idx = ids.indexOf("inventory");
74
- assert.equal(sections[idx].order, 55);
75
- assert.ok(ids.indexOf("tools") < idx, "runs after tools (50)");
76
- assert.ok(ids.indexOf("operating-model") > idx, "runs before operating-model (60)");
77
- });
78
-
79
- test("section shape: id/order/hooks", () => {
80
- assert.equal(inventory.id, "inventory");
81
- assert.equal(inventory.order, 55);
82
- for (const h of ["detect", "prompt", "apply", "verify"]) assert.equal(typeof inventory[h], "function");
83
- });
84
-
85
- test("detect: unconfigured → complete across apply()", async () => {
86
- const { root, home, fakeMaestro } = tmpRoot();
87
- const before = await inventory.detect(ctxFor(root, home, {}, { maestroRoot: fakeMaestro }));
88
- assert.equal(before.status, "unconfigured");
89
- assert.deepEqual(before.missing, [MANIFEST_REL]);
90
-
91
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro }));
92
- const after = await inventory.detect(ctxFor(root, home, {}, { maestroRoot: fakeMaestro }));
93
- assert.equal(after.status, "complete");
94
- assert.match(after.summary, /capabilities/);
95
- assert.ok(existsSync(join(root, MANIFEST_REL)));
96
- });
97
-
98
- test("apply writes a durable, queryable manifest with all four planes", async () => {
99
- const { root, home, fakeMaestro } = tmpRoot();
100
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro }));
101
- const m = JSON.parse(readFileSync(join(root, MANIFEST_REL), "utf8"));
102
- assert.equal(m.schemaVersion, 1);
103
- for (const plane of ["builtin", "skill", "mcp", "org"]) {
104
- assert.ok(m.counts[plane] > 0, `${plane} plane inventoried`);
105
- }
106
- assert.ok(m.entries.some((e) => e.id === "skill:agent-skills:morning-brief"));
107
- assert.ok(m.entries.some((e) => e.id === "workflow:weekly-operating-review"));
108
- assert.ok(m.entries.some((e) => e.id === "mcp:cohort"));
109
- assert.ok(m.entries.some((e) => e.id === "board_ready"));
110
- });
111
-
112
- test("apply is IDEMPOTENT — the checksum is stable across runs", async () => {
113
- const { root, home, fakeMaestro } = tmpRoot();
114
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro }));
115
- const a = JSON.parse(readFileSync(join(root, MANIFEST_REL), "utf8")).checksum;
116
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro }));
117
- const b = JSON.parse(readFileSync(join(root, MANIFEST_REL), "utf8")).checksum;
118
- assert.equal(a, b);
119
- });
120
-
121
- test("apply with repair registers the marketplace so the skills become reachable", async () => {
122
- const { root, home, fakeMaestro } = tmpRoot();
123
- await inventory.apply(ctxFor(root, home, { capabilityRepair: true }, { maestroRoot: fakeMaestro }));
124
- const m = JSON.parse(readFileSync(join(root, MANIFEST_REL), "utf8"));
125
- const skill = m.entries.find((e) => e.id === "skill:agent-skills:morning-brief");
126
- assert.equal(skill.reachable, true);
127
- assert.ok(existsSync(join(root, "plugins", "agent-skills", ".claude-plugin", "marketplace.json")));
128
- });
129
-
130
- test("verify: hard-fails only on a missing/empty manifest; plane emptiness is a SOFT remedy", async () => {
131
- const { root, home, fakeMaestro } = tmpRoot();
132
- const bad = await inventory.verify(ctxFor(root, home, {}, { maestroRoot: fakeMaestro }));
133
- assert.equal(bad.ok, false);
134
-
135
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro }));
136
- const good = await inventory.verify(ctxFor(root, home, {}, { maestroRoot: fakeMaestro }));
137
- assert.equal(good.ok, true, JSON.stringify(good.checks.filter((c) => !c.ok)));
138
- const names = good.checks.map((c) => c.name);
139
- assert.ok(names.some((n) => /every entry carries/.test(n)));
140
- assert.ok(names.some((n) => /skill plane/.test(n)));
141
- // The unregistered-marketplace state is reported (the archetype workflow IS
142
- // reachable, the skill file is NOT), and it never hard-fails setup.
143
- const skillCheck = good.checks.find((c) => /skill plane/.test(c.name));
144
- assert.equal(skillCheck.ok, true);
145
- assert.match(skillCheck.name, /skill plane: 1\/2 reachable/);
146
- const degCheck = good.checks.find((c) => /degradations recorded/.test(c.name));
147
- assert.equal(degCheck.ok, true);
148
- assert.match(degCheck.remedy, /capability-manifest\.json/);
149
- });
150
-
151
- test("verify: a plane with ZERO reachable entries surfaces an explicit remedy (never silent)", async () => {
152
- const { root, home, fakeMaestro } = tmpRoot();
153
- await inventory.apply(ctxFor(root, home, { capabilityRepair: false }, { maestroRoot: fakeMaestro,
154
- capabilityDeps: { orgProbeImpl: async () => ({ ok: false, detail: "org.cohort is not enabled", degraded: "org-not-enrolled", mandateFamily: false }) },
155
- }));
156
- const v = await inventory.verify(ctxFor(root, home, {}, { maestroRoot: fakeMaestro }));
157
- const orgCheck = v.checks.find((c) => /org plane/.test(c.name));
158
- assert.equal(orgCheck.ok, true, "an un-enrolled agent is a legitimate init state");
159
- assert.match(orgCheck.remedy, /nothing on the org plane is reachable/);
160
- assert.equal(v.ok, true);
161
- });
162
-
163
- test("archetypeOf reads the SoT and returns null when unset", () => {
164
- const { root } = tmpRoot();
165
- assert.deepEqual(archetypeOf(root), { function: "executive-operator", altitude: "c-suite" });
166
- const { root: bare } = tmpRoot({ archetype: false });
167
- assert.equal(archetypeOf(bare), null);
168
- });
169
-
170
- test("declareCapability fails OPEN and LOGS when hq rejects or is absent", async () => {
171
- const { root } = tmpRoot();
172
- const logs = [];
173
- const rejected = await declareCapability(root, { schemaVersion: 1, entries: [] }, {
174
- callImpl: async () => ({ ok: false, error: { code: "NOT_FOUND" } }),
175
- logImpl: (m) => logs.push(m),
176
- });
177
- assert.equal(rejected.posted, false);
178
- assert.equal(rejected.reason, "NOT_FOUND");
179
- assert.ok(logs.some((l) => /kept local only/.test(l)), "the degradation is never silent");
180
-
181
- const threw = await declareCapability(root, { schemaVersion: 1, entries: [] }, {
182
- callImpl: async () => { throw new Error("ECONNREFUSED"); },
183
- logImpl: (m) => logs.push(m),
184
- });
185
- assert.equal(threw.posted, false);
186
- assert.ok(logs.some((l) => /ECONNREFUSED/.test(l)));
187
- });
188
-
189
- test("declareCapability sends ids + reachability only — never invocation details", async () => {
190
- const { root } = tmpRoot();
191
- let sent = null;
192
- await declareCapability(root, {
193
- schemaVersion: 1,
194
- entries: [{ id: "board_ready", plane: "org", kind: "method_tool", reachable: true, probedAt: "t", blastRadius: "internal", costHint: "free", invocation: "board_ready", probe: { detail: "secret" } }],
195
- }, { callImpl: async (m, p) => { sent = { m, p }; return { ok: true }; }, logImpl: () => {} });
196
- assert.equal(sent.m, "mandate.declareCapability");
197
- assert.deepEqual(Object.keys(sent.p.body[0]).sort(), ["blastRadius", "costHint", "id", "kind", "plane", "probedAt", "reachable"]);
198
- });
@@ -1,81 +0,0 @@
1
- /**
2
- * learning.test.mjs — WS3 setup section (order 80) tests.
3
- * Run: node --test lib/setup/sections/learning.test.mjs
4
- */
5
- "use strict";
6
-
7
- import { test } from "node:test";
8
- import assert from "node:assert/strict";
9
- import { mkdtempSync, existsSync, readFileSync, mkdirSync, writeFileSync } from "node:fs";
10
- import { tmpdir } from "node:os";
11
- import { join, dirname } from "node:path";
12
- import { fileURLToPath } from "node:url";
13
-
14
- import learning from "./learning.mjs";
15
- import * as io from "../io.mjs";
16
-
17
- const MAESTRO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
18
-
19
- function tmpRoot() {
20
- const root = mkdtempSync(join(tmpdir(), "maestro-learnsec-"));
21
- mkdirSync(join(root, "config"), { recursive: true });
22
- return root;
23
- }
24
- function ctxFor(root, answers = {}) {
25
- return { agentRoot: root, maestroRoot: MAESTRO_ROOT, flags: { headless: true }, answers, io };
26
- }
27
-
28
- test("section shape: id/order/hooks", () => {
29
- assert.equal(learning.id, "learning");
30
- assert.equal(learning.order, 80);
31
- for (const h of ["detect", "prompt", "apply", "verify"]) assert.equal(typeof learning[h], "function");
32
- });
33
-
34
- test("detect: unconfigured before apply, complete after", async () => {
35
- const root = tmpRoot();
36
- const before = await learning.detect(ctxFor(root));
37
- assert.equal(before.status, "unconfigured");
38
-
39
- await learning.apply(ctxFor(root, { learningEnabled: true }));
40
- // config + counters now exist; hook is NOT wired on a CI machine → partial.
41
- const after = await learning.detect(ctxFor(root));
42
- assert.ok(["complete", "partial"].includes(after.status));
43
- assert.ok(existsSync(join(root, "config", "learning.yaml")));
44
- assert.ok(existsSync(join(root, "state", "learning", "counters.json")));
45
- // Counters seeded to zero state.
46
- const c = JSON.parse(readFileSync(join(root, "state", "learning", "counters.json"), "utf8"));
47
- assert.equal(c.tool_uses_since_skill, 0);
48
- });
49
-
50
- test("apply: disabled choice writes enabled:false and skips seeding", async () => {
51
- const root = tmpRoot();
52
- await learning.apply(ctxFor(root, { learningEnabled: false }));
53
- const body = readFileSync(join(root, "config", "learning.yaml"), "utf8");
54
- assert.match(body, /enabled:\s*false/);
55
- assert.ok(!existsSync(join(root, "state", "learning", "counters.json")), "no counters when disabled");
56
- const det = await learning.detect(ctxFor(root));
57
- assert.equal(det.status, "complete");
58
- assert.match(det.summary, /disabled/);
59
- });
60
-
61
- test("verify: config + counters checks; hook is a soft (non-failing) check", async () => {
62
- const root = tmpRoot();
63
- await learning.apply(ctxFor(root, { learningEnabled: true }));
64
- const v = await learning.verify(ctxFor(root));
65
- const names = v.checks.map((c) => c.name);
66
- assert.ok(names.some((n) => /config\/learning\.yaml/.test(n)));
67
- assert.ok(names.some((n) => /counters seeded/.test(n)));
68
- // The hook check never hard-fails verify (so CI / fresh repos stay green).
69
- const hookCheck = v.checks.find((c) => /Stop-hook/.test(c.name));
70
- assert.equal(hookCheck.ok, true);
71
- assert.equal(v.ok, true);
72
- });
73
-
74
- test("apply: idempotent — re-apply does not clobber an existing config", async () => {
75
- const root = tmpRoot();
76
- // Operator hand-customised config.
77
- writeFileSync(join(root, "config", "learning.yaml"), "enabled: true\nminTurns: 9\n# custom\n");
78
- await learning.apply(ctxFor(root, { learningEnabled: true }));
79
- const body = readFileSync(join(root, "config", "learning.yaml"), "utf8");
80
- assert.match(body, /minTurns: 9/, "existing customisation preserved");
81
- });