@cohortapp/agent-sdk 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (731) hide show
  1. package/.claude/commands/init-agent.md +104 -0
  2. package/.claude/commands/init-maestro.md +1187 -0
  3. package/.claude/settings.json +161 -0
  4. package/.env.example +216 -0
  5. package/README.md +632 -0
  6. package/agents/browser-operator/agent.md +52 -0
  7. package/agents/calendar-ops/agent.md +50 -0
  8. package/agents/communications/agent.md +96 -0
  9. package/agents/decision-log/agent.md +65 -0
  10. package/agents/desktop-operator/agent.md +59 -0
  11. package/agents/gmail-operator/agent.md +62 -0
  12. package/agents/inbound-dispatcher/agent.md +66 -0
  13. package/agents/inbox-processor/agent.md +39 -0
  14. package/agents/pmo-execution/agent.md +60 -0
  15. package/agents/session-spawner/agent.md +64 -0
  16. package/agents/slack-operator/agent.md +60 -0
  17. package/agents/whatsapp-operator/agent.md +60 -0
  18. package/agents/workflow-automation/agent.md +61 -0
  19. package/archetypes/altitudes/c-suite.yaml +58 -0
  20. package/archetypes/altitudes/founder.yaml +68 -0
  21. package/archetypes/altitudes/senior-manager.yaml +63 -0
  22. package/archetypes/altitudes/svp.yaml +60 -0
  23. package/archetypes/altitudes/vp.yaml +50 -0
  24. package/archetypes/archetype.schema.json +77 -0
  25. package/archetypes/base.yaml +47 -0
  26. package/archetypes/capabilities/commercial-leader.yaml +159 -0
  27. package/archetypes/capabilities/compliance-officer.yaml +159 -0
  28. package/archetypes/capabilities/executive-operator.yaml +169 -0
  29. package/archetypes/capabilities/finance-leader.yaml +162 -0
  30. package/archetypes/capabilities/operations-leader.yaml +154 -0
  31. package/archetypes/capabilities/product-leader.yaml +148 -0
  32. package/archetypes/capabilities/technical-leader.yaml +146 -0
  33. package/archetypes/functions/commercial-leader.yaml +62 -0
  34. package/archetypes/functions/compliance-officer.yaml +64 -0
  35. package/archetypes/functions/executive-operator.yaml +70 -0
  36. package/archetypes/functions/finance-leader.yaml +70 -0
  37. package/archetypes/functions/operations-leader.yaml +62 -0
  38. package/archetypes/functions/product-leader.yaml +61 -0
  39. package/archetypes/functions/technical-leader.yaml +57 -0
  40. package/bin/cohort-mcp.mjs +81 -0
  41. package/bin/maestro.mjs +3516 -0
  42. package/bin/maestro.test.mjs +1015 -0
  43. package/desktop-control/README.md +56 -0
  44. package/desktop-control/app-profiles/gmail.yaml +120 -0
  45. package/desktop-control/app-profiles/slack.yaml +315 -0
  46. package/desktop-control/app-profiles/whatsapp.yaml +107 -0
  47. package/docs/architecture/agent-topology.md +2239 -0
  48. package/docs/architecture/archetype-agent-factory.md +110 -0
  49. package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
  50. package/docs/architecture/continuous-monitoring.md +221 -0
  51. package/docs/architecture/mcp-capability-map.md +585 -0
  52. package/docs/architecture/system-architecture.md +1272 -0
  53. package/docs/company-context/README.md +40 -0
  54. package/docs/guides/agent-persona-setup.md +600 -0
  55. package/docs/guides/agents-observe-setup.md +64 -0
  56. package/docs/guides/billing-console-keys.md +88 -0
  57. package/docs/guides/ccxray-diagnostics.md +65 -0
  58. package/docs/guides/channel-bus.md +127 -0
  59. package/docs/guides/claude-mem-setup.md +79 -0
  60. package/docs/guides/claude-pace-setup.md +56 -0
  61. package/docs/guides/claudraband-sessions.md +98 -0
  62. package/docs/guides/clawteam-swarm.md +116 -0
  63. package/docs/guides/code-review-graph-setup.md +86 -0
  64. package/docs/guides/email-setup.md +431 -0
  65. package/docs/guides/mac-mini.md +119 -0
  66. package/docs/guides/media-generation-setup.md +349 -0
  67. package/docs/guides/model-routing.md +162 -0
  68. package/docs/guides/observability-otel.md +265 -0
  69. package/docs/guides/org-onboarding.md +132 -0
  70. package/docs/guides/outbound-governance-setup.md +437 -0
  71. package/docs/guides/pdf-generation-setup.md +315 -0
  72. package/docs/guides/poller-daemon-setup.md +563 -0
  73. package/docs/guides/rag-context-setup.md +459 -0
  74. package/docs/guides/self-optimization-pattern.md +82 -0
  75. package/docs/guides/setup-wizard.md +178 -0
  76. package/docs/guides/slack-setup.md +350 -0
  77. package/docs/guides/telegram-setup.md +227 -0
  78. package/docs/guides/twilio-subaccounts-setup.md +223 -0
  79. package/docs/guides/verification.md +128 -0
  80. package/docs/guides/voice-mode.md +188 -0
  81. package/docs/guides/voice-sms-setup.md +698 -0
  82. package/docs/guides/webhook-relay-setup.md +349 -0
  83. package/docs/guides/whatsapp-setup.md +288 -0
  84. package/docs/prompts/board-pack-cover-template.md +36 -0
  85. package/docs/prompts/decision-recommendation-template.md +88 -0
  86. package/docs/prompts/followup-message-template.md +141 -0
  87. package/docs/prompts/investor-letter-template.md +52 -0
  88. package/docs/prompts/morning-brief-template.md +82 -0
  89. package/docs/prompts/presentation-template.md +58 -0
  90. package/docs/prompts/weekly-strategic-memo-template.md +104 -0
  91. package/docs/research/hallucinated-tool-output-investigation.md +151 -0
  92. package/docs/runbooks/backup-restore.md +205 -0
  93. package/docs/runbooks/cohort-cutover.md +129 -0
  94. package/docs/runbooks/fleet-operations.md +200 -0
  95. package/docs/runbooks/incident-response.md +226 -0
  96. package/docs/runbooks/mac-mini-bootstrap.md +431 -0
  97. package/docs/runbooks/perpetual-operations.md +509 -0
  98. package/docs/runbooks/recovery-and-failover.md +260 -0
  99. package/framework-features.json +267 -0
  100. package/ingest/README.md +87 -0
  101. package/lib/action-executor.js +689 -0
  102. package/lib/action-executor.test.mjs +871 -0
  103. package/lib/agent-root.mjs +37 -0
  104. package/lib/archetype.mjs +236 -0
  105. package/lib/archetype.test.mjs +132 -0
  106. package/lib/autonomy.mjs +114 -0
  107. package/lib/autonomy.test.mjs +66 -0
  108. package/lib/backlog.mjs +358 -0
  109. package/lib/backlog.test.mjs +266 -0
  110. package/lib/budget-guard.mjs +279 -0
  111. package/lib/budget-guard.test.mjs +291 -0
  112. package/lib/cadence-bus-schedule.test.mjs +194 -0
  113. package/lib/cadence-bus.mjs +1120 -0
  114. package/lib/cadence-bus.test.mjs +720 -0
  115. package/lib/cadences.mjs +205 -0
  116. package/lib/cadences.test.mjs +125 -0
  117. package/lib/capability.mjs +154 -0
  118. package/lib/capability.test.mjs +78 -0
  119. package/lib/channels/base-adapter.mjs +719 -0
  120. package/lib/channels/base-adapter.test.mjs +590 -0
  121. package/lib/channels/channel.mjs +128 -0
  122. package/lib/channels/channels.test.mjs +371 -0
  123. package/lib/channels/contract.mjs +215 -0
  124. package/lib/channels/contract.test.mjs +137 -0
  125. package/lib/channels/conversation-resolver.mjs +95 -0
  126. package/lib/channels/gmail/adapter.mjs +87 -0
  127. package/lib/channels/inbox-item.mjs +255 -0
  128. package/lib/channels/inbox-item.test.mjs +335 -0
  129. package/lib/channels/index.mjs +94 -0
  130. package/lib/channels/orgmail/adapter.mjs +353 -0
  131. package/lib/channels/orgmail/adapter.test.mjs +311 -0
  132. package/lib/channels/pairing.mjs +363 -0
  133. package/lib/channels/pairing.test.mjs +270 -0
  134. package/lib/channels/registry.mjs +164 -0
  135. package/lib/channels/slack/adapter.mjs +317 -0
  136. package/lib/channels/slack-adapter.test.mjs +212 -0
  137. package/lib/channels/sms/adapter.mjs +43 -0
  138. package/lib/channels/telegram/adapter.mjs +432 -0
  139. package/lib/channels/telegram-adapter.test.mjs +306 -0
  140. package/lib/channels/voice/adapter.mjs +301 -0
  141. package/lib/channels/voice/adapter.test.mjs +278 -0
  142. package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
  143. package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
  144. package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
  145. package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
  146. package/lib/charter.mjs +256 -0
  147. package/lib/charter.test.mjs +89 -0
  148. package/lib/claude-bin.mjs +134 -0
  149. package/lib/claude-bin.test.mjs +75 -0
  150. package/lib/collective/capture.mjs +185 -0
  151. package/lib/collective/capture.test.mjs +121 -0
  152. package/lib/collective/cards.mjs +201 -0
  153. package/lib/collective/cards.test.mjs +114 -0
  154. package/lib/collective/config.mjs +186 -0
  155. package/lib/collective/config.test.mjs +123 -0
  156. package/lib/collective/global-config.mjs +113 -0
  157. package/lib/collective/global-config.test.mjs +75 -0
  158. package/lib/collective/presence.mjs +201 -0
  159. package/lib/collective/presence.test.mjs +95 -0
  160. package/lib/collective/recall.mjs +215 -0
  161. package/lib/collective/recall.test.mjs +116 -0
  162. package/lib/comms/send-gate.mjs +554 -0
  163. package/lib/comms/send-gate.test.mjs +577 -0
  164. package/lib/comms.mjs +67 -0
  165. package/lib/comms.test.mjs +41 -0
  166. package/lib/diagnostics/alerts.mjs +424 -0
  167. package/lib/diagnostics/alerts.test.mjs +318 -0
  168. package/lib/diagnostics/backup-freshness.mjs +188 -0
  169. package/lib/diagnostics/backup-freshness.test.mjs +185 -0
  170. package/lib/diagnostics/counters.mjs +269 -0
  171. package/lib/diagnostics/counters.test.mjs +206 -0
  172. package/lib/diagnostics/events.mjs +188 -0
  173. package/lib/diagnostics/events.test.mjs +290 -0
  174. package/lib/diagnostics/otel.mjs +237 -0
  175. package/lib/diagnostics/otel.test.mjs +196 -0
  176. package/lib/diagnostics/trace.mjs +216 -0
  177. package/lib/diagnostics/trace.test.mjs +251 -0
  178. package/lib/env-compat.mjs +74 -0
  179. package/lib/env-compat.test.mjs +104 -0
  180. package/lib/feature-init.mjs +331 -0
  181. package/lib/fs-atomic.mjs +112 -0
  182. package/lib/fs-atomic.test.mjs +72 -0
  183. package/lib/fs-ownership.mjs +111 -0
  184. package/lib/fs-ownership.test.mjs +158 -0
  185. package/lib/hooks/bus.mjs +347 -0
  186. package/lib/hooks/bus.test.mjs +387 -0
  187. package/lib/index.js +16 -0
  188. package/lib/learning/config.mjs +106 -0
  189. package/lib/learning/config.test.mjs +75 -0
  190. package/lib/learning/counters.mjs +156 -0
  191. package/lib/learning/counters.test.mjs +69 -0
  192. package/lib/learning/curator-consolidate.test.mjs +238 -0
  193. package/lib/learning/curator.mjs +453 -0
  194. package/lib/learning/curator.test.mjs +106 -0
  195. package/lib/learning/log.mjs +40 -0
  196. package/lib/learning/reflect.mjs +534 -0
  197. package/lib/learning/reflect.test.mjs +0 -0
  198. package/lib/learning/session-index.mjs +352 -0
  199. package/lib/learning/session-index.test.mjs +125 -0
  200. package/lib/learning/skill-writer.mjs +474 -0
  201. package/lib/learning/skill-writer.test.mjs +210 -0
  202. package/lib/mcp/server.mjs +328 -0
  203. package/lib/mcp/server.test.mjs +400 -0
  204. package/lib/model-router/auth-profiles.mjs +758 -0
  205. package/lib/model-router/auth-profiles.test.mjs +580 -0
  206. package/lib/model-router/catalog/anthropic.yaml +153 -0
  207. package/lib/model-router/catalog/deepseek.yaml +86 -0
  208. package/lib/model-router/catalog/moonshot.yaml +81 -0
  209. package/lib/model-router/catalog/qwen.yaml +114 -0
  210. package/lib/model-router/catalog.mjs +925 -0
  211. package/lib/model-router/catalog.test.mjs +385 -0
  212. package/lib/model-router/economics.mjs +564 -0
  213. package/lib/model-router/economics.test.mjs +344 -0
  214. package/lib/model-router/failover.mjs +298 -0
  215. package/lib/model-router/failover.test.mjs +439 -0
  216. package/lib/model-router/health.mjs +453 -0
  217. package/lib/model-router/health.test.mjs +338 -0
  218. package/lib/model-router/integration-coverage.test.mjs +829 -0
  219. package/lib/model-router/integration.test.mjs +564 -0
  220. package/lib/model-router/ledger.mjs +402 -0
  221. package/lib/model-router/ledger.test.mjs +382 -0
  222. package/lib/model-router/llm-task.mjs +515 -0
  223. package/lib/model-router/llm-task.test.mjs +392 -0
  224. package/lib/model-router/org-credentials.mjs +260 -0
  225. package/lib/model-router/org-credentials.test.mjs +265 -0
  226. package/lib/model-router/pricing-refresh.mjs +463 -0
  227. package/lib/model-router/pricing-refresh.test.mjs +286 -0
  228. package/lib/model-router/reconcile.mjs +429 -0
  229. package/lib/model-router/reconcile.test.mjs +316 -0
  230. package/lib/model-router/repair.mjs +471 -0
  231. package/lib/model-router/repair.test.mjs +180 -0
  232. package/lib/model-router/resolve.mjs +1206 -0
  233. package/lib/model-router/spawn.mjs +497 -0
  234. package/lib/model-router/spawn.test.mjs +425 -0
  235. package/lib/model-router/taxonomy.mjs +893 -0
  236. package/lib/model-router/taxonomy.test.mjs +410 -0
  237. package/lib/model-router.mjs +677 -0
  238. package/lib/model-router.test.mjs +907 -0
  239. package/lib/org/activity.mjs +211 -0
  240. package/lib/org/activity.test.mjs +134 -0
  241. package/lib/org/approvals.mjs +448 -0
  242. package/lib/org/approvals.test.mjs +216 -0
  243. package/lib/org/awareness.mjs +222 -0
  244. package/lib/org/awareness.test.mjs +159 -0
  245. package/lib/org/board.mjs +229 -0
  246. package/lib/org/board.test.mjs +177 -0
  247. package/lib/org/bootstrap-context.mjs +169 -0
  248. package/lib/org/bootstrap-context.test.mjs +153 -0
  249. package/lib/org/client.mjs +1628 -0
  250. package/lib/org/client.test.mjs +1107 -0
  251. package/lib/org/cohort-client.mjs +67 -0
  252. package/lib/org/cohort-client.test.mjs +126 -0
  253. package/lib/org/cost-sync.mjs +227 -0
  254. package/lib/org/cost-sync.test.mjs +153 -0
  255. package/lib/org/doctor.mjs +212 -0
  256. package/lib/org/doctor.test.mjs +212 -0
  257. package/lib/org/handoff.mjs +293 -0
  258. package/lib/org/handoff.test.mjs +269 -0
  259. package/lib/org/integration-tools.mjs +182 -0
  260. package/lib/org/integration-tools.test.mjs +160 -0
  261. package/lib/org/keys.mjs +131 -0
  262. package/lib/org/keys.test.mjs +92 -0
  263. package/lib/org/knowledge.mjs +463 -0
  264. package/lib/org/knowledge.test.mjs +319 -0
  265. package/lib/org/leases.mjs +335 -0
  266. package/lib/org/leases.test.mjs +235 -0
  267. package/lib/org/mesh-integration.test.mjs +127 -0
  268. package/lib/org/mesh.mjs +459 -0
  269. package/lib/org/mesh.test.mjs +345 -0
  270. package/lib/org/messaging.mjs +503 -0
  271. package/lib/org/messaging.test.mjs +238 -0
  272. package/lib/org/policy.mjs +345 -0
  273. package/lib/org/policy.test.mjs +237 -0
  274. package/lib/org/protocol.checksum +1 -0
  275. package/lib/org/protocol.checksum.test.mjs +90 -0
  276. package/lib/org/protocol.mjs +967 -0
  277. package/lib/org/protocol.test.mjs +264 -0
  278. package/lib/org/registry.mjs +194 -0
  279. package/lib/org/registry.test.mjs +100 -0
  280. package/lib/org/tool-surface-integration.test.mjs +120 -0
  281. package/lib/org/tool-surface.mjs +2535 -0
  282. package/lib/org/tool-surface.test.mjs +589 -0
  283. package/lib/org/ui-parity.mjs +3236 -0
  284. package/lib/org/ui-parity.test.mjs +348 -0
  285. package/lib/org/verify.mjs +176 -0
  286. package/lib/org/verify.test.mjs +194 -0
  287. package/lib/rag/embed.mjs +188 -0
  288. package/lib/rag/indexer.mjs +425 -0
  289. package/lib/rag/rag.test.mjs +505 -0
  290. package/lib/rag/search.mjs +475 -0
  291. package/lib/rate-guard.mjs +246 -0
  292. package/lib/rate-guard.test.mjs +201 -0
  293. package/lib/render.mjs +112 -0
  294. package/lib/render.test.mjs +68 -0
  295. package/lib/resource-governor.mjs +297 -0
  296. package/lib/resource-governor.test.mjs +262 -0
  297. package/lib/scheduling/dynamic-jobs.mjs +675 -0
  298. package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
  299. package/lib/scheduling/jitter.mjs +0 -0
  300. package/lib/scheduling/jitter.test.mjs +140 -0
  301. package/lib/secrets/broker.mjs +315 -0
  302. package/lib/secrets/broker.test.mjs +280 -0
  303. package/lib/secrets/providers.mjs +461 -0
  304. package/lib/secrets/providers.test.mjs +274 -0
  305. package/lib/security/audit-engine.mjs +684 -0
  306. package/lib/security/audit-engine.test.mjs +389 -0
  307. package/lib/security/coerce-args.mjs +552 -0
  308. package/lib/security/coerce-args.test.mjs +281 -0
  309. package/lib/security/dangerous-tools.mjs +97 -0
  310. package/lib/security/dangerous-tools.test.mjs +68 -0
  311. package/lib/security/external-content.mjs +145 -0
  312. package/lib/security/external-content.test.mjs +67 -0
  313. package/lib/security/redact.mjs +592 -0
  314. package/lib/security/redact.test.mjs +441 -0
  315. package/lib/security/secret-equal.mjs +73 -0
  316. package/lib/security/secret-equal.test.mjs +55 -0
  317. package/lib/session-permissions.mjs +101 -0
  318. package/lib/session-permissions.test.mjs +100 -0
  319. package/lib/setup/claude-probe.mjs +74 -0
  320. package/lib/setup/completeness.mjs +175 -0
  321. package/lib/setup/completeness.test.mjs +110 -0
  322. package/lib/setup/context-pack.mjs +173 -0
  323. package/lib/setup/context-pack.test.mjs +89 -0
  324. package/lib/setup/enrich.mjs +277 -0
  325. package/lib/setup/enrich.test.mjs +115 -0
  326. package/lib/setup/enroll-from-cohort.mjs +441 -0
  327. package/lib/setup/enroll-from-cohort.test.mjs +233 -0
  328. package/lib/setup/integration.test.mjs +162 -0
  329. package/lib/setup/io.mjs +360 -0
  330. package/lib/setup/io.test.mjs +77 -0
  331. package/lib/setup/run-generator.mjs +81 -0
  332. package/lib/setup/runner.mjs +244 -0
  333. package/lib/setup/runner.test.mjs +132 -0
  334. package/lib/setup/sections/comms.mjs +173 -0
  335. package/lib/setup/sections/company.mjs +120 -0
  336. package/lib/setup/sections/enrich.mjs +138 -0
  337. package/lib/setup/sections/identity.mjs +182 -0
  338. package/lib/setup/sections/identity.test.mjs +140 -0
  339. package/lib/setup/sections/learning.mjs +153 -0
  340. package/lib/setup/sections/learning.test.mjs +81 -0
  341. package/lib/setup/sections/messaging.mjs +219 -0
  342. package/lib/setup/sections/messaging.test.mjs +127 -0
  343. package/lib/setup/sections/model.mjs +102 -0
  344. package/lib/setup/sections/operating-model.mjs +78 -0
  345. package/lib/setup/sections/org.mjs +475 -0
  346. package/lib/setup/sections/org.test.mjs +313 -0
  347. package/lib/setup/sections/orgmail.mjs +173 -0
  348. package/lib/setup/sections/orgmail.test.mjs +118 -0
  349. package/lib/setup/sections/recovery.mjs +159 -0
  350. package/lib/setup/sections/recovery.test.mjs +98 -0
  351. package/lib/setup/sections/tools.mjs +132 -0
  352. package/lib/setup/sections/verify.mjs +97 -0
  353. package/lib/setup/sot.mjs +205 -0
  354. package/lib/setup/sot.test.mjs +81 -0
  355. package/lib/setup/state.mjs +151 -0
  356. package/lib/setup/state.test.mjs +92 -0
  357. package/lib/singleton.js +229 -0
  358. package/lib/singleton.test.mjs +135 -0
  359. package/lib/telemetry/alerts.mjs +216 -0
  360. package/lib/telemetry/alerts.test.mjs +109 -0
  361. package/lib/telemetry/collect.mjs +512 -0
  362. package/lib/telemetry/collect.test.mjs +202 -0
  363. package/lib/tool-definitions-integration.test.mjs +83 -0
  364. package/lib/tool-definitions.js +738 -0
  365. package/lib/tool-definitions.test.mjs +437 -0
  366. package/lib/util/fetch-timeout.mjs +136 -0
  367. package/lib/util/fetch-timeout.test.mjs +202 -0
  368. package/lib/util/reconnect.mjs +343 -0
  369. package/lib/util/reconnect.test.mjs +369 -0
  370. package/lib/util/unhandled.mjs +205 -0
  371. package/lib/util/unhandled.test.mjs +216 -0
  372. package/lib/voice/context-loader.mjs +466 -0
  373. package/lib/voice/index.mjs +100 -0
  374. package/lib/voice/openai-realtime.mjs +510 -0
  375. package/lib/voice/outbound.mjs +542 -0
  376. package/lib/voice/outbound.test.mjs +69 -0
  377. package/lib/voice/post-call-brief.mjs +428 -0
  378. package/lib/voice/provider.mjs +52 -0
  379. package/lib/voice/session-rotation.mjs +257 -0
  380. package/lib/voice/stt.mjs +161 -0
  381. package/lib/voice/stt.test.mjs +226 -0
  382. package/lib/voice/tool-bridge.mjs +370 -0
  383. package/lib/voice/tts.mjs +104 -0
  384. package/lib/voice/twilio-sip-bridge.mjs +288 -0
  385. package/lib/voice/voice.test.mjs +990 -0
  386. package/mcp/README.md +80 -0
  387. package/package.json +151 -0
  388. package/plugins/maestro-skills/plugin.json +139 -0
  389. package/plugins/maestro-skills/skills/agents-observe.md +110 -0
  390. package/plugins/maestro-skills/skills/board-deck.md +68 -0
  391. package/plugins/maestro-skills/skills/books-close.md +77 -0
  392. package/plugins/maestro-skills/skills/brand-steward.md +121 -0
  393. package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
  394. package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
  395. package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
  396. package/plugins/maestro-skills/skills/claude-pace.md +61 -0
  397. package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
  398. package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
  399. package/plugins/maestro-skills/skills/decision-brief.md +89 -0
  400. package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
  401. package/plugins/maestro-skills/skills/draft-comms.md +84 -0
  402. package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
  403. package/plugins/maestro-skills/skills/files-find.md +65 -0
  404. package/plugins/maestro-skills/skills/generative-ui.md +228 -0
  405. package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
  406. package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
  407. package/plugins/maestro-skills/skills/mail-triage.md +86 -0
  408. package/plugins/maestro-skills/skills/morning-brief.md +54 -0
  409. package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
  410. package/plugins/maestro-skills/skills/org-board.md +133 -0
  411. package/plugins/maestro-skills/skills/org-credential.md +68 -0
  412. package/plugins/maestro-skills/skills/org-recall.md +81 -0
  413. package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
  414. package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
  415. package/plugins/maestro-skills/skills/router-why.md +78 -0
  416. package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
  417. package/plugins/maestro-skills/skills/session-search.md +71 -0
  418. package/plugins/maestro-skills/skills/set-reminder.md +93 -0
  419. package/plugins/maestro-skills/skills/slack-followup.md +64 -0
  420. package/plugins/maestro-skills/skills/team-activity.md +86 -0
  421. package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
  422. package/policies/action-classification.yaml +114 -0
  423. package/policies/ai-disclosure.yaml +294 -0
  424. package/policies/communication-style.md +139 -0
  425. package/policies/information-barriers.yaml +118 -0
  426. package/policies/prompt-injection-defence.yaml +138 -0
  427. package/public/assets/icon-dark.png +0 -0
  428. package/public/assets/icon-dark.svg +9 -0
  429. package/public/assets/icon-light.svg +9 -0
  430. package/public/assets/logo-dark.svg +15 -0
  431. package/public/assets/logo-light.svg +15 -0
  432. package/scaffold/.mcp.json +7 -0
  433. package/scaffold/CLAUDE.md +368 -0
  434. package/scaffold/config/agent.json +55 -0
  435. package/scaffold/config/agent.ts +76 -0
  436. package/scaffold/config/agent.ts.example +89 -0
  437. package/scaffold/config/alerts.yaml +23 -0
  438. package/scaffold/config/allowlist.yaml.example +25 -0
  439. package/scaffold/config/caller-id-map.yaml +46 -0
  440. package/scaffold/config/collective.yaml +49 -0
  441. package/scaffold/config/company.json +20 -0
  442. package/scaffold/config/known-agents.json +6 -0
  443. package/scaffold/config/learning.yaml +55 -0
  444. package/scaffold/config/model-routing.yaml.example +104 -0
  445. package/scaffold/config/org.yaml +25 -0
  446. package/scaffold/config/orgmail.yaml.example +19 -0
  447. package/scaffold/config/recovery.yaml +72 -0
  448. package/scaffold/config/secrets.yaml +27 -0
  449. package/scaffold/config/slack.yaml.example +35 -0
  450. package/scaffold/config/telegram.yaml.example +38 -0
  451. package/scaffold/config/voice.yaml.example +89 -0
  452. package/scaffold/config/whatsapp.yaml.example +39 -0
  453. package/schedules/README.md +49 -0
  454. package/schedules/triggers/backlog-executor.md +102 -0
  455. package/schedules/triggers/brand-steward.md +72 -0
  456. package/schedules/triggers/daily-evening-wrap.md +159 -0
  457. package/schedules/triggers/daily-midday-sweep.md +58 -0
  458. package/schedules/triggers/daily-morning-brief.md +55 -0
  459. package/schedules/triggers/directory-hygiene.md +81 -0
  460. package/schedules/triggers/dynamic-jobs.md +40 -0
  461. package/schedules/triggers/inbox-processor.md +115 -0
  462. package/schedules/triggers/meeting-action-capture.md +60 -0
  463. package/schedules/triggers/meeting-prep.md +69 -0
  464. package/schedules/triggers/messaging-inbound.md +50 -0
  465. package/schedules/triggers/org-pulse.md +24 -0
  466. package/schedules/triggers/quarterly-self-assessment.md +54 -0
  467. package/schedules/triggers/weekly-engineering-health.md +37 -0
  468. package/schedules/triggers/weekly-execution.md +65 -0
  469. package/schedules/triggers/weekly-hiring.md +53 -0
  470. package/schedules/triggers/weekly-priorities.md +38 -0
  471. package/schedules/triggers/weekly-strategic-memo.md +124 -0
  472. package/scripts/archive-email.sh +55 -0
  473. package/scripts/cadence/cadence-status.mjs +36 -0
  474. package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
  475. package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
  476. package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
  477. package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
  478. package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
  479. package/scripts/ci/check-docs-accuracy.mjs +493 -0
  480. package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
  481. package/scripts/ci/check-exports-exist.mjs +140 -0
  482. package/scripts/ci/check-files-exist.mjs +107 -0
  483. package/scripts/ci/check-no-build-artifacts.mjs +111 -0
  484. package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
  485. package/scripts/ci/check-no-confidential.mjs +198 -0
  486. package/scripts/ci/check-no-conflict-markers.mjs +169 -0
  487. package/scripts/ci/check-no-residual-identity.mjs +163 -0
  488. package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
  489. package/scripts/ci/check-tarball-fidelity.mjs +205 -0
  490. package/scripts/ci/check-unresolved-tokens.mjs +83 -0
  491. package/scripts/ci/check.mjs +109 -0
  492. package/scripts/ci/check.test.mjs +194 -0
  493. package/scripts/ci/run-coverage.mjs +82 -0
  494. package/scripts/ci/run-tests.mjs +71 -0
  495. package/scripts/cloud-relay/README.md +59 -0
  496. package/scripts/cloud-relay/index.mjs +233 -0
  497. package/scripts/cloud-relay/package.json +15 -0
  498. package/scripts/cloud-relay/railway.json +13 -0
  499. package/scripts/cloud-relay/voice/README.md +94 -0
  500. package/scripts/cloud-relay/voice/package-lock.json +39 -0
  501. package/scripts/cloud-relay/voice/package.json +16 -0
  502. package/scripts/cloud-relay/voice/railway.json +13 -0
  503. package/scripts/cloud-relay/voice/server.mjs +532 -0
  504. package/scripts/collective/hook-runner.mjs +211 -0
  505. package/scripts/collective/hook-runner.test.mjs +90 -0
  506. package/scripts/collective/org-pulse.mjs +72 -0
  507. package/scripts/collective/org-sync.mjs +61 -0
  508. package/scripts/collective/recall.mjs +45 -0
  509. package/scripts/collective/who.mjs +30 -0
  510. package/scripts/comms-monitor.sh +288 -0
  511. package/scripts/configure-whatsapp-sandbox.sh +201 -0
  512. package/scripts/continuous-monitor.sh +91 -0
  513. package/scripts/cost/fleet-digest.mjs +407 -0
  514. package/scripts/cost/fleet-digest.test.mjs +207 -0
  515. package/scripts/cost/track-claude-usage.mjs +169 -0
  516. package/scripts/daemon/agent-daemon.mjs +989 -0
  517. package/scripts/daemon/agent-daemon.test.mjs +525 -0
  518. package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
  519. package/scripts/daemon/cadence-consumer.mjs +1080 -0
  520. package/scripts/daemon/cadence-consumer.test.mjs +770 -0
  521. package/scripts/daemon/cadence-handlers.mjs +1121 -0
  522. package/scripts/daemon/cadence-handlers.test.mjs +617 -0
  523. package/scripts/daemon/classifier.mjs +704 -0
  524. package/scripts/daemon/classifier.test.mjs +238 -0
  525. package/scripts/daemon/classify-kind.mjs +54 -0
  526. package/scripts/daemon/classify-kind.test.mjs +40 -0
  527. package/scripts/daemon/context-compiler.mjs +605 -0
  528. package/scripts/daemon/context-compiler.test.mjs +300 -0
  529. package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
  530. package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
  531. package/scripts/daemon/dispatcher.mjs +1516 -0
  532. package/scripts/daemon/health.mjs +72 -0
  533. package/scripts/daemon/inbox-deferral.mjs +210 -0
  534. package/scripts/daemon/inbox-deferral.test.mjs +242 -0
  535. package/scripts/daemon/integration.test.mjs +149 -0
  536. package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
  537. package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
  538. package/scripts/daemon/launchd-wrapper.sh +91 -0
  539. package/scripts/daemon/lib/session-router.mjs +274 -0
  540. package/scripts/daemon/lib/session-router.test.mjs +295 -0
  541. package/scripts/daemon/maestro-daemon.mjs +275 -0
  542. package/scripts/daemon/prompt-builder.mjs +685 -0
  543. package/scripts/daemon/prompt-builder.test.mjs +213 -0
  544. package/scripts/daemon/responder.mjs +854 -0
  545. package/scripts/daemon/session-lock.mjs +721 -0
  546. package/scripts/daemon/session-lock.test.mjs +252 -0
  547. package/scripts/daemon/session-outcomes.mjs +640 -0
  548. package/scripts/daemon/session-outcomes.test.mjs +533 -0
  549. package/scripts/daemon/typing-registry.mjs +90 -0
  550. package/scripts/daemon/typing-registry.test.mjs +77 -0
  551. package/scripts/daemon/voice-webhook-server.mjs +804 -0
  552. package/scripts/decisions/capture-decision.mjs +116 -0
  553. package/scripts/disclosure_assessment.py +873 -0
  554. package/scripts/disclosure_boundaries.py +562 -0
  555. package/scripts/email-signature-principal.html +52 -0
  556. package/scripts/email-signature.html +60 -0
  557. package/scripts/email_quote_thread.py +167 -0
  558. package/scripts/email_thread_dedup.py +362 -0
  559. package/scripts/emergency-stop.sh +81 -0
  560. package/scripts/healthcheck.sh +116 -0
  561. package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
  562. package/scripts/hooks/block-mcp-slack-send.sh +7 -0
  563. package/scripts/hooks/post-action-log.sh +126 -0
  564. package/scripts/hooks/pre-send-audit.sh +174 -0
  565. package/scripts/hooks/pre-send-audit.test.mjs +215 -0
  566. package/scripts/hooks/session-end-log.sh +27 -0
  567. package/scripts/hooks/session-start-banner.sh +115 -0
  568. package/scripts/huddle/audio-bridge.mjs +664 -0
  569. package/scripts/huddle/boot-slack-cdp.sh +102 -0
  570. package/scripts/huddle/huddle-controller.mjs +942 -0
  571. package/scripts/huddle/huddle-server.mjs +1229 -0
  572. package/scripts/huddle/launch-slack.sh +232 -0
  573. package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
  574. package/scripts/huddle/package-lock.json +62 -0
  575. package/scripts/huddle/package.json +22 -0
  576. package/scripts/huddle/setup-audio.sh +239 -0
  577. package/scripts/huddle/start-call.mjs +318 -0
  578. package/scripts/huddle/test-pipeline.mjs +263 -0
  579. package/scripts/learning/consolidate-skills.mjs +72 -0
  580. package/scripts/learning/session-search.mjs +125 -0
  581. package/scripts/llm_email_dedup.py +442 -0
  582. package/scripts/local-triggers/generate-plists.sh +432 -0
  583. package/scripts/local-triggers/generate-plists.test.mjs +413 -0
  584. package/scripts/local-triggers/install-all.sh +49 -0
  585. package/scripts/local-triggers/plists/.gitkeep +0 -0
  586. package/scripts/local-triggers/run-trigger.sh +63 -0
  587. package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
  588. package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
  589. package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
  590. package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
  591. package/scripts/maintenance/backup-to-cloud.sh +124 -0
  592. package/scripts/maintenance/health-check.sh +377 -0
  593. package/scripts/media-generation/README.md +105 -0
  594. package/scripts/media-generation/gemini-image-client.mjs +173 -0
  595. package/scripts/media-generation/generate-assets.mjs +289 -0
  596. package/scripts/media-generation/veo-video-client.mjs +219 -0
  597. package/scripts/org/send-orgmail.mjs +227 -0
  598. package/scripts/outbound-dedup-cleanup.sh +43 -0
  599. package/scripts/outbound-dedup.sh +477 -0
  600. package/scripts/outbound_dedup.py +115 -0
  601. package/scripts/parse-voice-transcript.mjs +481 -0
  602. package/scripts/pdf-generation/README.md +63 -0
  603. package/scripts/pdf-generation/build-document.mjs +247 -0
  604. package/scripts/pdf-generation/templates/board-pack.latex +136 -0
  605. package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
  606. package/scripts/pdf-generation/templates/memo.latex +114 -0
  607. package/scripts/poll-slack-events.sh +35 -0
  608. package/scripts/poller/calendar-poller.mjs +12 -0
  609. package/scripts/poller/gmail-poller.mjs +192 -0
  610. package/scripts/poller/imap-client.mjs +289 -0
  611. package/scripts/poller/inbox-scan-poller.mjs +156 -0
  612. package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
  613. package/scripts/poller/index.mjs +73 -0
  614. package/scripts/poller/intra-session-check.mjs +285 -0
  615. package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
  616. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
  617. package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
  618. package/scripts/poller/secondary-gmail-poller.mjs +132 -0
  619. package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
  620. package/scripts/poller/slack-poller.mjs +854 -0
  621. package/scripts/poller/slack-socket-mode.mjs +917 -0
  622. package/scripts/poller/slack-socket-mode.test.mjs +753 -0
  623. package/scripts/poller/trigger.mjs +75 -0
  624. package/scripts/poller/utils.mjs +371 -0
  625. package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
  626. package/scripts/poller/voice-poller.mjs +236 -0
  627. package/scripts/poller-launchd/install.sh +66 -0
  628. package/scripts/poller-launchd/poller.plist.template +40 -0
  629. package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
  630. package/scripts/post-interaction-indexer.py +1598 -0
  631. package/scripts/pre-draft-context.py +994 -0
  632. package/scripts/pre_draft_lookup.py +258 -0
  633. package/scripts/rag/build-index.mjs +47 -0
  634. package/scripts/rag/ingest.mjs +111 -0
  635. package/scripts/rag/search.mjs +119 -0
  636. package/scripts/rag-indexer.py +629 -0
  637. package/scripts/restore-from-backup.sh +248 -0
  638. package/scripts/restore-from-backup.test.mjs +178 -0
  639. package/scripts/resume-operations.sh +80 -0
  640. package/scripts/search-secondary-inbox.py +181 -0
  641. package/scripts/secondary-inbox-poller.py +437 -0
  642. package/scripts/self-optimization/compute-metrics.py +398 -0
  643. package/scripts/send-email-as-principal.py +369 -0
  644. package/scripts/send-email-threaded.py +392 -0
  645. package/scripts/send-email-with-attachment.py +377 -0
  646. package/scripts/send-email.sh +131 -0
  647. package/scripts/send-sms.sh +175 -0
  648. package/scripts/send-whatsapp.sh +292 -0
  649. package/scripts/session-start.sh +106 -0
  650. package/scripts/setup/boot-claude-session.sh +94 -0
  651. package/scripts/setup/configure-macos.sh +674 -0
  652. package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
  653. package/scripts/setup/configure-voice-tunnel.mjs +182 -0
  654. package/scripts/setup/generate-agent-env.mjs +92 -0
  655. package/scripts/setup/generate-agent-package-json.mjs +222 -0
  656. package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
  657. package/scripts/setup/generate-autonomy.mjs +60 -0
  658. package/scripts/setup/generate-backlog.mjs +101 -0
  659. package/scripts/setup/generate-cadences.mjs +92 -0
  660. package/scripts/setup/generate-capability.mjs +162 -0
  661. package/scripts/setup/generate-charter.mjs +76 -0
  662. package/scripts/setup/generate-comms.mjs +59 -0
  663. package/scripts/setup/generate-company.mjs +92 -0
  664. package/scripts/setup/init-agent.sh +547 -0
  665. package/scripts/setup/init-agent.test.mjs +151 -0
  666. package/scripts/setup/init-archetype.mjs +74 -0
  667. package/scripts/setup/init-backup.mjs +54 -0
  668. package/scripts/setup/init-cadence-bus.mjs +60 -0
  669. package/scripts/setup/init-channel-bus.mjs +46 -0
  670. package/scripts/setup/init-cost-tracking.mjs +45 -0
  671. package/scripts/setup/init-decision-capture.mjs +66 -0
  672. package/scripts/setup/init-known-agents.mjs +57 -0
  673. package/scripts/setup/init-learning.mjs +70 -0
  674. package/scripts/setup/init-memory-executive.mjs +45 -0
  675. package/scripts/setup/init-model-router.mjs +124 -0
  676. package/scripts/setup/init-rag.mjs +174 -0
  677. package/scripts/setup/init-session-router.mjs +38 -0
  678. package/scripts/setup/init-slack-socket-mode.mjs +260 -0
  679. package/scripts/setup/init-telegram.mjs +165 -0
  680. package/scripts/setup/init-voice-realtime.mjs +204 -0
  681. package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
  682. package/scripts/setup/install-dev-tools.sh +150 -0
  683. package/scripts/setup/lib/install-plist.mjs +95 -0
  684. package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
  685. package/scripts/setup/render-environment-yaml.mjs +133 -0
  686. package/scripts/slack-events-ctl.sh +177 -0
  687. package/scripts/slack-events-server.mjs +1045 -0
  688. package/scripts/slack-react.mjs +89 -0
  689. package/scripts/slack-responded.sh +232 -0
  690. package/scripts/slack-send.sh +287 -0
  691. package/scripts/slack-typing.mjs +196 -0
  692. package/scripts/slack-upload-v2.py +95 -0
  693. package/scripts/sms-handler.mjs +450 -0
  694. package/scripts/spawn-session.sh +120 -0
  695. package/scripts/sync-protocol.mjs +217 -0
  696. package/scripts/system-verify.sh +184 -0
  697. package/scripts/test-email-thread-dedup.py +239 -0
  698. package/scripts/test-information-barriers.py +484 -0
  699. package/scripts/test-llm-email-dedup.py +251 -0
  700. package/scripts/test-pre-draft-integration.py +203 -0
  701. package/scripts/test-rag-phase2.sh +442 -0
  702. package/scripts/test-rag-search.sh +251 -0
  703. package/scripts/test-voice-parser.mjs +316 -0
  704. package/scripts/user-context-search.py +659 -0
  705. package/scripts/validate_outbound.py +1504 -0
  706. package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
  707. package/scripts/watchdog/force-reboot.sh +157 -0
  708. package/scripts/watchdog/memory-watchdog.sh +473 -0
  709. package/scripts/whatsapp-handler.mjs +538 -0
  710. package/teams/desktop-operations.yaml +34 -0
  711. package/teams/executive-office.yaml +27 -0
  712. package/teams/legal-and-regulatory.yaml +24 -0
  713. package/teams/platform-and-engineering.yaml +23 -0
  714. package/teams/strategy-and-growth.yaml +29 -0
  715. package/workflows/continuous/backlog-executor.yaml +141 -0
  716. package/workflows/continuous/inbound-monitor.yaml +168 -0
  717. package/workflows/daily/applicant-triage.yaml +197 -0
  718. package/workflows/daily/comms-triage.yaml +80 -0
  719. package/workflows/daily/evening-wrap.yaml +105 -0
  720. package/workflows/daily/morning-brief.yaml +164 -0
  721. package/workflows/daily/slack-followup-sweep.yaml +87 -0
  722. package/workflows/event-driven/README.md +50 -0
  723. package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
  724. package/workflows/event-driven/pr-review.yaml +107 -0
  725. package/workflows/monthly/board-readiness.yaml +76 -0
  726. package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
  727. package/workflows/session-protocol.md +171 -0
  728. package/workflows/weekly/engineering-health.yaml +154 -0
  729. package/workflows/weekly/hiring-review.yaml +169 -0
  730. package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
  731. package/workflows/weekly/strategic-memo.yaml +79 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * session-permissions.test.mjs — node:test coverage for the H1 permission
3
+ * scoping helper. Pure-function tests: no real claude spawn, no filesystem.
4
+ *
5
+ * Each test that mutates MAESTRO_SCOPED_PERMISSIONS saves + restores it in a
6
+ * try/finally so the env change can't leak into other tests in the same node
7
+ * --test process.
8
+ */
9
+
10
+ import { test } from "node:test";
11
+ import assert from "node:assert/strict";
12
+
13
+ import {
14
+ sessionPermissionArgs,
15
+ CONSERVATIVE_DEFAULT_ALLOWLIST,
16
+ } from "./session-permissions.mjs";
17
+ import { getCadenceDef } from "../scripts/daemon/cadence-handlers.mjs";
18
+
19
+ /**
20
+ * Run `fn` with MAESTRO_SCOPED_PERMISSIONS set to `value` (or deleted when
21
+ * value is undefined), restoring the prior value afterwards.
22
+ */
23
+ function withScopedEnv(value, fn) {
24
+ const prev = process.env.MAESTRO_SCOPED_PERMISSIONS;
25
+ try {
26
+ if (value === undefined) delete process.env.MAESTRO_SCOPED_PERMISSIONS;
27
+ else process.env.MAESTRO_SCOPED_PERMISSIONS = value;
28
+ return fn();
29
+ } finally {
30
+ if (prev === undefined) delete process.env.MAESTRO_SCOPED_PERMISSIONS;
31
+ else process.env.MAESTRO_SCOPED_PERMISSIONS = prev;
32
+ }
33
+ }
34
+
35
+ test("default (env unset) returns the skip-permissions arg — UNCHANGED behaviour", () => {
36
+ withScopedEnv(undefined, () => {
37
+ assert.deepEqual(
38
+ sessionPermissionArgs({ cadence: "daily-morning-brief", mode: "escalate" }),
39
+ ["--dangerously-skip-permissions"],
40
+ );
41
+ // Also unchanged when called with no args at all.
42
+ assert.deepEqual(sessionPermissionArgs(), ["--dangerously-skip-permissions"]);
43
+ });
44
+ });
45
+
46
+ test("non-'1' values do NOT enable scoped mode (only the exact opt-in '1' counts)", () => {
47
+ for (const v of ["0", "true", "yes", "", "01"]) {
48
+ withScopedEnv(v, () => {
49
+ assert.deepEqual(
50
+ sessionPermissionArgs({ cadence: "daily-morning-brief" }),
51
+ ["--dangerously-skip-permissions"],
52
+ `value ${JSON.stringify(v)} must not enable scoped mode`,
53
+ );
54
+ });
55
+ }
56
+ });
57
+
58
+ test("scoped mode emits --allowedTools from the cadence registry allowlist", () => {
59
+ // Pick a cadence that carries an explicit allowedTools fixture in the
60
+ // registry. meeting-prep is read-leaning so it's a natural scoped fixture.
61
+ const cadence = "meeting-prep";
62
+ const def = getCadenceDef(cadence);
63
+ assert.ok(Array.isArray(def?.allowedTools) && def.allowedTools.length > 0,
64
+ `test fixture expects ${cadence} to declare a non-empty allowedTools array in the registry`);
65
+ withScopedEnv("1", () => {
66
+ const args = sessionPermissionArgs({ cadence, mode: def.mode });
67
+ assert.equal(args.length, 2);
68
+ assert.equal(args[0], "--allowedTools");
69
+ assert.equal(args[1], def.allowedTools.join(","));
70
+ });
71
+ });
72
+
73
+ test("scoped mode falls back to the conservative default for an unknown cadence", () => {
74
+ withScopedEnv("1", () => {
75
+ const args = sessionPermissionArgs({ cadence: "totally-unknown-cadence-xyz" });
76
+ assert.deepEqual(args, ["--allowedTools", CONSERVATIVE_DEFAULT_ALLOWLIST.join(",")]);
77
+ });
78
+ });
79
+
80
+ test("scoped mode falls back to the conservative default when cadence is omitted", () => {
81
+ withScopedEnv("1", () => {
82
+ const args = sessionPermissionArgs({});
83
+ assert.deepEqual(args, ["--allowedTools", CONSERVATIVE_DEFAULT_ALLOWLIST.join(",")]);
84
+ });
85
+ });
86
+
87
+ test("conservative default allowlist is read-only / search-only (no write, shell, send, or control-plane tools)", () => {
88
+ const banned = [
89
+ "Bash", "Write", "Edit", "exec", "spawn", "shell", "run",
90
+ "send_slack", "send_email", "cron", "schedule", "gateway",
91
+ ];
92
+ for (const tool of CONSERVATIVE_DEFAULT_ALLOWLIST) {
93
+ assert.ok(
94
+ !banned.includes(tool),
95
+ `conservative default must not include the dangerous tool ${tool}`,
96
+ );
97
+ }
98
+ // And it must be non-empty so scoped mode never emits an empty allowlist.
99
+ assert.ok(CONSERVATIVE_DEFAULT_ALLOWLIST.length > 0);
100
+ });
@@ -0,0 +1,74 @@
1
+ /**
2
+ * lib/setup/claude-probe.mjs — reachability probe for the Claude API.
3
+ *
4
+ * Mirrors the curl check in bin/maestro.mjs (doctor, ~:1566): POST a 5-token
5
+ * ping to api.anthropic.com with the .env key. Returns a structured result with
6
+ * a remedy line so the wizard's capability table and doctor can share the logic.
7
+ *
8
+ * Honors MAESTRO_PREFER_SUBSCRIPTION_AUTH (subscription/keychain OAuth wins → the
9
+ * probe reports `ok` without an API key).
10
+ *
11
+ * @module lib/setup/claude-probe
12
+ */
13
+
14
+ "use strict";
15
+
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { spawnSync } from "node:child_process";
19
+
20
+ /** Parse a single KEY from a .env file body. */
21
+ function envValue(body, key) {
22
+ const m = body.match(new RegExp(`^${key}=(.+)$`, "m"));
23
+ return m ? m[1].trim().replace(/^["']|["']$/g, "") : "";
24
+ }
25
+
26
+ /**
27
+ * Probe Claude API reachability for an agent repo.
28
+ * @param {string} agentRoot
29
+ * @param {object} [opts]
30
+ * @param {(args:string[])=>{stdout?:string}} [opts.curl] injectable curl (for tests)
31
+ * @returns {{ok:boolean, mode:'subscription'|'api-key'|'none', code?:string, name:string, remedy?:string}}
32
+ */
33
+ export function probeClaude(agentRoot, opts = {}) {
34
+ const envPath = join(agentRoot, ".env");
35
+ const body = existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
36
+ const preferSubs = /^(1|true|yes)$/i.test(envValue(body, "MAESTRO_PREFER_SUBSCRIPTION_AUTH"));
37
+ if (preferSubs) {
38
+ return { ok: true, mode: "subscription", name: "Claude API (subscription auth)" };
39
+ }
40
+ const key = envValue(body, "ANTHROPIC_API_KEY");
41
+ if (!key) {
42
+ return {
43
+ ok: false, mode: "none", name: "Claude API reachable",
44
+ remedy: "set ANTHROPIC_API_KEY in .env, or MAESTRO_PREFER_SUBSCRIPTION_AUTH=1 to use Claude Code subscription",
45
+ };
46
+ }
47
+ const run = opts.curl || ((args) => spawnSync("curl", args, { encoding: "utf-8" }));
48
+ let code = "";
49
+ try {
50
+ const res = run([
51
+ "-s", "-o", "/dev/null", "-w", "%{http_code}",
52
+ "-X", "POST",
53
+ "-H", `x-api-key: ${key}`,
54
+ "-H", "anthropic-version: 2023-06-01",
55
+ "-H", "content-type: application/json",
56
+ "--max-time", "8",
57
+ "https://api.anthropic.com/v1/messages",
58
+ "-d", JSON.stringify({ model: "claude-haiku-4-5", max_tokens: 5, messages: [{ role: "user", content: "ping" }] }),
59
+ ]);
60
+ code = (res && res.stdout ? res.stdout : "").trim();
61
+ } catch { code = ""; }
62
+
63
+ if (code === "200") return { ok: true, mode: "api-key", code, name: "Claude API reachable" };
64
+ if (code === "401") {
65
+ return {
66
+ ok: false, mode: "api-key", code, name: "Claude API reachable",
67
+ remedy: "ANTHROPIC_API_KEY is INVALID (HTTP 401) — replace it, or set MAESTRO_PREFER_SUBSCRIPTION_AUTH=1",
68
+ };
69
+ }
70
+ if (!code) {
71
+ return { ok: false, mode: "api-key", code, name: "Claude API reachable", remedy: "no network / curl missing — could not verify the key" };
72
+ }
73
+ return { ok: false, mode: "api-key", code, name: "Claude API reachable", remedy: `unexpected HTTP ${code} (expected 200)` };
74
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * lib/setup/completeness.mjs — the operating-model completeness gate.
3
+ *
4
+ * Single source of truth for "is this agent fully set up?", shared by both the
5
+ * `maestro setup` wizard (verify section) and `maestro doctor`. Extracted from
6
+ * the inline doctor gate so the two never drift.
7
+ *
8
+ * `assertComplete(agentRoot)` → { ok, missing: [{ artifact, reason }] }
9
+ *
10
+ * Passes iff:
11
+ * - identity is populated (non-placeholder firstName/lastName/title/email +
12
+ * function/altitude that RESOLVES via resolveArchetype)
13
+ * - all six operating-model artifacts are present & placeholder-free:
14
+ * config/operating-charter.md (findCharterPlaceholders → none)
15
+ * config/priorities.yaml (≥1 priority)
16
+ * state/queues/backlog.yaml (≥5 open items)
17
+ * config/agent-roster.yaml
18
+ * config/cadences.yaml
19
+ * policies/communication-profile.yaml
20
+ * policies/action-classification.yaml
21
+ *
22
+ * Pure-ish: reads files, no writes, no spawns. yaml is loaded lazily (maestro
23
+ * dep) but the gate degrades to a regex count if it is unavailable.
24
+ *
25
+ * @module lib/setup/completeness
26
+ */
27
+
28
+ "use strict";
29
+
30
+ import { existsSync, readFileSync } from "node:fs";
31
+ import { join, dirname } from "node:path";
32
+ import { fileURLToPath, pathToFileURL } from "node:url";
33
+
34
+ const HERE = dirname(fileURLToPath(import.meta.url));
35
+ const MAESTRO_ROOT = join(HERE, "..", "..");
36
+
37
+ /** Placeholder identity values shipped by the scaffold. */
38
+ const PLACEHOLDER_VALUES = new Set(["", "UNCONFIGURED", "AGENT", "Unconfigured Agent", "Unconfigured Role"]);
39
+
40
+ function isPlaceholder(v) {
41
+ if (v === undefined || v === null) return true;
42
+ const s = String(v).trim();
43
+ if (s === "") return true;
44
+ if (PLACEHOLDER_VALUES.has(s)) return true;
45
+ if (/\{\{[^}]+\}\}/.test(s)) return true; // unresolved token
46
+ return false;
47
+ }
48
+
49
+ async function loadCharterLib() {
50
+ return import(pathToFileURL(join(MAESTRO_ROOT, "lib", "charter.mjs")).href);
51
+ }
52
+ async function loadArchetypeLib() {
53
+ return import(pathToFileURL(join(MAESTRO_ROOT, "lib", "archetype.mjs")).href);
54
+ }
55
+ let _yaml = null;
56
+ async function getYaml() {
57
+ if (_yaml) return _yaml;
58
+ try { const m = await import("js-yaml"); _yaml = m && m.default ? m.default : m; }
59
+ catch { _yaml = null; }
60
+ return _yaml;
61
+ }
62
+
63
+ /** Count list items in a yaml file under `key` (falls back to a regex). */
64
+ async function countYamlList(path, key) {
65
+ if (!existsSync(path)) return 0;
66
+ const body = readFileSync(path, "utf-8");
67
+ const yaml = await getYaml();
68
+ if (yaml) {
69
+ try {
70
+ const doc = yaml.load(body);
71
+ const arr = doc && doc[key];
72
+ if (Array.isArray(arr)) return arr.length;
73
+ } catch { /* fall through to regex */ }
74
+ }
75
+ return (body.match(/(^|\n)\s*-\s+\S/g) || []).length;
76
+ }
77
+
78
+ /** Count `status: open` occurrences across state/queues backlog. */
79
+ function countOpenBacklog(agentRoot) {
80
+ const f = join(agentRoot, "state", "queues", "backlog.yaml");
81
+ if (!existsSync(f)) return 0;
82
+ try { return (readFileSync(f, "utf-8").match(/status:\s*open/g) || []).length; }
83
+ catch { return 0; }
84
+ }
85
+
86
+ /**
87
+ * Evaluate identity completeness. Returns the list of missing artifacts (empty
88
+ * = complete) plus the resolved archetype selector (or null).
89
+ * @param {object|null} identity config/agent.json contents
90
+ * @param {object} archetypeLib
91
+ */
92
+ async function checkIdentity(identity, archetypeLib) {
93
+ const missing = [];
94
+ if (!identity) {
95
+ missing.push({ artifact: "config/agent.json", reason: "missing — run `maestro setup`" });
96
+ return { missing, sel: null };
97
+ }
98
+ for (const field of ["firstName", "lastName", "title", "email"]) {
99
+ if (isPlaceholder(identity[field])) {
100
+ missing.push({ artifact: `identity.${field}`, reason: "unset or placeholder" });
101
+ }
102
+ }
103
+ // archetype must resolve
104
+ const { resolveArchetype, migrateLegacyArchetype } = archetypeLib;
105
+ let sel = identity.function && identity.altitude
106
+ ? { function: identity.function, altitude: identity.altitude }
107
+ : migrateLegacyArchetype(identity.archetype);
108
+ if (!sel) {
109
+ missing.push({ artifact: "identity.archetype", reason: "no { function, altitude } and no legacy archetype" });
110
+ } else {
111
+ try { await resolveArchetype(sel); }
112
+ catch (e) {
113
+ missing.push({ artifact: "identity.archetype", reason: `unresolvable: ${e && e.message ? e.message : e}` });
114
+ sel = null;
115
+ }
116
+ }
117
+ return { missing, sel };
118
+ }
119
+
120
+ /**
121
+ * The completeness gate. Never throws — failures are reported as `missing`.
122
+ * @param {string} agentRoot
123
+ * @returns {Promise<{ok:boolean, missing:Array<{artifact:string, reason:string}>, identityOk:boolean, archetypeOk:boolean}>}
124
+ */
125
+ export async function assertComplete(agentRoot) {
126
+ const missing = [];
127
+ let identity = null;
128
+ try { const raw = join(agentRoot, "config", "agent.json"); if (existsSync(raw)) identity = JSON.parse(readFileSync(raw, "utf-8")); }
129
+ catch (e) { missing.push({ artifact: "config/agent.json", reason: `malformed JSON: ${e && e.message ? e.message : e}` }); }
130
+
131
+ const archetypeLib = await loadArchetypeLib();
132
+ const id = await checkIdentity(identity, archetypeLib);
133
+ for (const m of id.missing) missing.push(m);
134
+ const identityOk = id.missing.every((m) => !m.artifact.startsWith("identity") && m.artifact !== "config/agent.json")
135
+ ? true
136
+ : id.missing.length === 0;
137
+ const archetypeOk = !!id.sel;
138
+
139
+ // 1. operating charter (present + placeholder-free)
140
+ const charterPath = join(agentRoot, "config", "operating-charter.md");
141
+ if (!existsSync(charterPath)) {
142
+ missing.push({ artifact: "config/operating-charter.md", reason: "missing — run generate-charter.mjs" });
143
+ } else {
144
+ try {
145
+ const { findCharterPlaceholders } = await loadCharterLib();
146
+ const marks = findCharterPlaceholders(readFileSync(charterPath, "utf-8"));
147
+ if (marks.length) missing.push({ artifact: "config/operating-charter.md", reason: `un-enriched placeholders: ${marks.join(", ")}` });
148
+ } catch (e) {
149
+ missing.push({ artifact: "config/operating-charter.md", reason: `unreadable: ${e && e.message ? e.message : e}` });
150
+ }
151
+ }
152
+
153
+ // 2. priorities ≥1
154
+ const prioCount = await countYamlList(join(agentRoot, "config", "priorities.yaml"), "priorities");
155
+ if (prioCount < 1) missing.push({ artifact: "config/priorities.yaml", reason: "empty or missing — run generate-backlog.mjs" });
156
+
157
+ // 3. backlog ≥5 open
158
+ const openItems = countOpenBacklog(agentRoot);
159
+ if (openItems < 5) missing.push({ artifact: "state/queues/backlog.yaml", reason: `${openItems} open item(s) (<5) — run generate-backlog.mjs` });
160
+
161
+ // 4-7. presence of the remaining four artifacts
162
+ const required = [
163
+ ["config/agent-roster.yaml", "generate-capability.mjs"],
164
+ ["config/cadences.yaml", "generate-cadences.mjs"],
165
+ ["policies/communication-profile.yaml", "generate-comms.mjs"],
166
+ ["policies/action-classification.yaml", "generate-autonomy.mjs"],
167
+ ];
168
+ for (const [rel, gen] of required) {
169
+ if (!existsSync(join(agentRoot, rel))) missing.push({ artifact: rel, reason: `missing — run ${gen}` });
170
+ }
171
+
172
+ return { ok: missing.length === 0, missing, identityOk, archetypeOk };
173
+ }
174
+
175
+ export { isPlaceholder };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * completeness.test.mjs — the shared operating-model gate (lib/setup/completeness.mjs).
3
+ * Detects placeholders / missing artifacts; passes on a fully generated repo.
4
+ * Run: `node --test lib/setup/completeness.test.mjs`
5
+ * @module lib/setup/completeness.test
6
+ */
7
+
8
+ "use strict";
9
+
10
+ import { test } from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join, dirname, resolve } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ import { execFileSync } from "node:child_process";
17
+ import { assertComplete } from "./completeness.mjs";
18
+
19
+ const HERE = dirname(fileURLToPath(import.meta.url));
20
+ const MAESTRO_ROOT = resolve(HERE, "..", "..");
21
+
22
+ function tmpRoot() {
23
+ const r = mkdtempSync(join(tmpdir(), "maestro-complete-"));
24
+ mkdirSync(join(r, "config"), { recursive: true });
25
+ return r;
26
+ }
27
+
28
+ const POPULATED_IDENTITY = {
29
+ firstName: "Jacob", lastName: "Chen", fullName: "Jacob Chen",
30
+ title: "VP, Engineering", email: "jacob@acme.com",
31
+ function: "technical-leader", altitude: "vp", archetype: "technical-leader",
32
+ company: "Acme", companyDomain: "acme.com",
33
+ principal: { firstName: "Dana", lastName: "Reyes", fullName: "Dana Reyes", title: "CEO", email: "dana@acme.com" },
34
+ schedule: { morningBrief: "08:00", commsTriage: ["09:00"], eveningWrap: "18:00", overnightMonitoring: "22:00" },
35
+ communication: { defaultTone: "warm-professional", externalTone: "formal", voiceModes: [] },
36
+ responsibilities: [], operatingPrinciples: [],
37
+ };
38
+
39
+ function runGen(script, root) {
40
+ execFileSync(process.execPath, [join(MAESTRO_ROOT, "scripts", "setup", script)], {
41
+ cwd: root,
42
+ env: { ...process.env, MAESTRO_ROOT, AGENT_ROOT: root },
43
+ encoding: "utf-8",
44
+ });
45
+ }
46
+
47
+ test("assertComplete reports identity placeholders on a fresh scaffold-like repo", async () => {
48
+ const root = tmpRoot();
49
+ writeFileSync(join(root, "config/agent.json"), JSON.stringify({
50
+ firstName: "UNCONFIGURED", lastName: "AGENT", title: "Unconfigured Role", email: "",
51
+ function: "executive-operator", altitude: "c-suite",
52
+ }, null, 2));
53
+ const res = await assertComplete(root);
54
+ assert.equal(res.ok, false);
55
+ const arts = res.missing.map((m) => m.artifact);
56
+ assert.ok(arts.includes("identity.firstName"));
57
+ assert.ok(arts.includes("identity.email"));
58
+ // operating-model artifacts also missing
59
+ assert.ok(arts.includes("config/operating-charter.md"));
60
+ });
61
+
62
+ test("assertComplete is green after running the real generators on a populated identity", async () => {
63
+ const root = tmpRoot();
64
+ writeFileSync(join(root, "config/agent.json"), JSON.stringify(POPULATED_IDENTITY, null, 2) + "\n");
65
+ // company.json so generate-company can run (not gated by completeness but harmless)
66
+ writeFileSync(join(root, "config/company.json"), JSON.stringify({ name: "Acme", website: "https://acme.com" }, null, 2));
67
+
68
+ runGen("generate-charter.mjs", root);
69
+ runGen("generate-backlog.mjs", root);
70
+ runGen("generate-capability.mjs", root);
71
+ runGen("generate-comms.mjs", root);
72
+ runGen("generate-autonomy.mjs", root);
73
+ runGen("generate-cadences.mjs", root);
74
+
75
+ // The deterministic charter skeleton intentionally leaves "TBD" company slots
76
+ // (KPI targets, named stakeholders) that the enrich section fills. Simulate
77
+ // that enrichment so we can assert the green path of the gate itself.
78
+ const charterPath = join(root, "config/operating-charter.md");
79
+ const enriched = readFileSync(charterPath, "utf-8")
80
+ .replace(/\bTBD\b/g, "Q4 target")
81
+ .replace(/_\(to be defined during init enrichment\)_/g, "defined");
82
+ writeFileSync(charterPath, enriched);
83
+
84
+ const res = await assertComplete(root);
85
+ assert.equal(res.ok, true, "expected green gate, missing: " + JSON.stringify(res.missing));
86
+ assert.equal(res.identityOk, true);
87
+ assert.equal(res.archetypeOk, true);
88
+ });
89
+
90
+ test("assertComplete flags a charter that still has placeholders", async () => {
91
+ const root = tmpRoot();
92
+ writeFileSync(join(root, "config/agent.json"), JSON.stringify(POPULATED_IDENTITY, null, 2) + "\n");
93
+ mkdirSync(join(root, "config"), { recursive: true });
94
+ writeFileSync(join(root, "config/operating-charter.md"), "# Charter\nMandate: {{agent.firstName}} TBD\n");
95
+ const res = await assertComplete(root);
96
+ const charter = res.missing.find((m) => m.artifact === "config/operating-charter.md");
97
+ assert.ok(charter, "charter placeholder must be flagged");
98
+ assert.match(charter.reason, /placeholder/);
99
+ });
100
+
101
+ test("assertComplete flags a too-small backlog (<5 open)", async () => {
102
+ const root = tmpRoot();
103
+ writeFileSync(join(root, "config/agent.json"), JSON.stringify(POPULATED_IDENTITY, null, 2) + "\n");
104
+ mkdirSync(join(root, "state/queues"), { recursive: true });
105
+ writeFileSync(join(root, "state/queues/backlog.yaml"), "items:\n - id: 1\n status: open\n - id: 2\n status: open\n");
106
+ const res = await assertComplete(root);
107
+ const backlog = res.missing.find((m) => m.artifact === "state/queues/backlog.yaml");
108
+ assert.ok(backlog);
109
+ assert.match(backlog.reason, /<5/);
110
+ });
@@ -0,0 +1,173 @@
1
+ /**
2
+ * lib/setup/context-pack.mjs — deterministic context gathering for enrichment.
3
+ *
4
+ * Builds `state/setup/context-pack.json` from on-disk, non-LLM sources so the
5
+ * `enrich` section has a bounded, reproducible grounding bundle:
6
+ * - the agent identity (config/agent.json)
7
+ * - the company brief (config/company.json)
8
+ * - any operator-supplied company context docs (docs/company-context/*.md|txt)
9
+ * - the repo README (first N chars)
10
+ *
11
+ * NO model calls happen here — that is the whole point (the spine is
12
+ * deterministic; the LLM is a bounded function called later).
13
+ *
14
+ * @module lib/setup/context-pack
15
+ */
16
+
17
+ "use strict";
18
+
19
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
20
+ import { join, dirname, extname } from "node:path";
21
+
22
+ export const CONTEXT_PACK_REL = "state/setup/context-pack.json";
23
+
24
+ /** Max bytes pulled from any single doc / README so the pack stays bounded. */
25
+ const MAX_DOC_BYTES = 8000;
26
+ const MAX_DOCS = 20;
27
+
28
+ function readSafe(path, max = MAX_DOC_BYTES) {
29
+ try { return readFileSync(path, "utf-8").slice(0, max); }
30
+ catch { return ""; }
31
+ }
32
+
33
+ function readJsonSafe(path) {
34
+ try { return existsSync(path) ? JSON.parse(readFileSync(path, "utf-8")) : null; }
35
+ catch { return null; }
36
+ }
37
+
38
+ /** Collect company-context docs (markdown/text) under docs/company-context/. */
39
+ function gatherContextDocs(agentRoot) {
40
+ const dir = join(agentRoot, "docs", "company-context");
41
+ if (!existsSync(dir)) return [];
42
+ const out = [];
43
+ let names;
44
+ try { names = readdirSync(dir).sort(); } catch { return []; }
45
+ for (const name of names) {
46
+ if (out.length >= MAX_DOCS) break;
47
+ const ext = extname(name).toLowerCase();
48
+ if (![".md", ".txt", ".markdown"].includes(ext)) continue;
49
+ const p = join(dir, name);
50
+ try { if (!statSync(p).isFile()) continue; } catch { continue; }
51
+ const body = readSafe(p);
52
+ if (body.trim()) out.push({ name, excerpt: body });
53
+ }
54
+ return out;
55
+ }
56
+
57
+ /** Max items pulled from any single org-context list so the excerpt stays bounded. */
58
+ const MAX_ORG_ITEMS = 8;
59
+
60
+ /**
61
+ * Distil `config/org-context.json` (written by the Cohort bootstrap) into a
62
+ * bounded, LLM-groundable excerpt: the agent's authoritative org SoT — strategy
63
+ * north star + levers + streams, escalation path, reports, adopted decisions, and
64
+ * the ready board frontier. Returns null when there is no cached context so a
65
+ * standalone (un-enrolled) agent's pack stays exactly as before.
66
+ * @param {string} agentRoot
67
+ * @returns {object|null}
68
+ */
69
+ function gatherOrgContextExcerpt(agentRoot) {
70
+ const ctx = readJsonSafe(join(agentRoot, "config", "org-context.json"));
71
+ if (!ctx || typeof ctx !== "object") return null;
72
+ const profile = ctx.profile && typeof ctx.profile === "object" ? ctx.profile : {};
73
+ const strategy = ctx.strategy && typeof ctx.strategy === "object" ? ctx.strategy : {};
74
+ const rel = ctx.relationships && typeof ctx.relationships === "object" ? ctx.relationships : {};
75
+ const decisions = Array.isArray(ctx.decisions) ? ctx.decisions : [];
76
+ const board = Array.isArray(ctx.board) ? ctx.board : [];
77
+ const streams = Array.isArray(strategy.streams) ? strategy.streams : [];
78
+ const levers = Array.isArray(strategy.levers) ? strategy.levers : [];
79
+
80
+ const excerpt = {
81
+ fetchedAt: ctx.fetchedAt || null,
82
+ self: {
83
+ slug: profile.slug || "",
84
+ title: profile.title || "",
85
+ escalationPath: profile.escalationPath || "",
86
+ autonomyLevel: profile.autonomyLevel || "",
87
+ },
88
+ strategy: {
89
+ northStar: strategy.northStar || strategy.northstar || "",
90
+ levers: levers.slice(0, MAX_ORG_ITEMS).map((l) => (l && (l.label || l.name)) || String(l || "")).filter(Boolean),
91
+ streams: streams.slice(0, MAX_ORG_ITEMS).map((s) => ({
92
+ code: (s && s.code) || "",
93
+ name: (s && s.name) || "",
94
+ mission: (s && s.mission) || "",
95
+ })).filter((s) => s.code || s.name),
96
+ },
97
+ reports: (Array.isArray(profile.reports) ? profile.reports : (Array.isArray(rel.reports) ? rel.reports : []))
98
+ .slice(0, MAX_ORG_ITEMS)
99
+ .map((r) => (r && r.member && (r.member.displayName || r.member.slug)) || (r && (r.displayName || r.slug)) || "")
100
+ .filter(Boolean),
101
+ adoptedDecisions: decisions.slice(0, MAX_ORG_ITEMS).map((d) => (d && (d.title || d.summary)) || "").filter(Boolean),
102
+ readyBoard: board.slice(0, MAX_ORG_ITEMS).map((b) => (b && (b.title || b.name)) || "").filter(Boolean),
103
+ };
104
+ return excerpt;
105
+ }
106
+
107
+ /**
108
+ * Gather the deterministic context pack object (does not write).
109
+ * @param {string} agentRoot
110
+ * @returns {object}
111
+ */
112
+ export function buildContextPack(agentRoot) {
113
+ const identity = readJsonSafe(join(agentRoot, "config", "agent.json")) || {};
114
+ const company = readJsonSafe(join(agentRoot, "config", "company.json")) || {};
115
+ const docs = gatherContextDocs(agentRoot);
116
+ const readme = readSafe(join(agentRoot, "README.md"));
117
+ const orgContext = gatherOrgContextExcerpt(agentRoot);
118
+
119
+ return {
120
+ generatedAt: new Date().toISOString(),
121
+ identity: {
122
+ firstName: identity.firstName || "",
123
+ lastName: identity.lastName || "",
124
+ fullName: identity.fullName || "",
125
+ title: identity.title || "",
126
+ function: identity.function || "",
127
+ altitude: identity.altitude || "",
128
+ archetype: identity.archetype || "",
129
+ company: identity.company || company.name || "",
130
+ companyDomain: identity.companyDomain || company.domain || "",
131
+ principal: identity.principal || {},
132
+ },
133
+ company: {
134
+ name: company.name || identity.company || "",
135
+ legalName: company.legalName || "",
136
+ website: company.website || "",
137
+ domain: company.domain || "",
138
+ industry: company.industry || "",
139
+ stage: company.stage || "",
140
+ tagline: company.tagline || "",
141
+ description: company.description || "",
142
+ products: Array.isArray(company.products) ? company.products : [],
143
+ strategicPriorities: Array.isArray(company.strategicPriorities) ? company.strategicPriorities : [],
144
+ keyPeople: Array.isArray(company.keyPeople) ? company.keyPeople : [],
145
+ competitors: Array.isArray(company.competitors) ? company.competitors : [],
146
+ },
147
+ contextDocs: docs,
148
+ readmeExcerpt: readme,
149
+ // The org's authoritative view of this agent (from Cohort), when enrolled.
150
+ // Omitted entirely for a standalone agent so the pack shape is unchanged there.
151
+ ...(orgContext ? { orgContext } : {}),
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Build and persist the context pack to state/setup/context-pack.json (atomic).
157
+ * @param {string} agentRoot
158
+ * @returns {object} the pack written
159
+ */
160
+ export function gatherContextPack(agentRoot) {
161
+ const pack = buildContextPack(agentRoot);
162
+ const out = join(agentRoot, CONTEXT_PACK_REL);
163
+ mkdirSync(dirname(out), { recursive: true });
164
+ const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
165
+ writeFileSync(tmp, JSON.stringify(pack, null, 2) + "\n", "utf-8");
166
+ renameSync(tmp, out);
167
+ return pack;
168
+ }
169
+
170
+ /** Read a previously written context pack (or null). */
171
+ export function readContextPack(agentRoot) {
172
+ return readJsonSafe(join(agentRoot, CONTEXT_PACK_REL));
173
+ }