@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,205 @@
1
+ /**
2
+ * cadences.mjs — resolve an archetype's scheduled-task cadence set.
3
+ *
4
+ * "Which scheduled tasks run, when" is a function of the archetype, not a fixed
5
+ * 13-tick rhythm. The resolved cadence list =
6
+ * STANDARD_CADENCES (every agent: inbox/backlog/meeting sweeps + daily brief/
7
+ * sweep/wrap + quarterly self-assessment)
8
+ * ⊕ the function's recurring workflows (from the capability pack — pr-review is
9
+ * event-driven so excluded; engineering-health/weekly, release-train/weekly,
10
+ * capacity-cost/monthly, … become scheduled cadences)
11
+ * ⊕ altitude cadences (a C-suite/SVP gets a weekly strategic memo + board pack;
12
+ * a founder gets runway + investor-update; a VP/senior-manager gets a
13
+ * priorities/execution review).
14
+ *
15
+ * Schedules for function/altitude cadences are assigned deterministically and
16
+ * staggered (by a stable slot derived from the id) so they don't all fire at
17
+ * once. The init generator writes the resolved set to config/cadences.yaml;
18
+ * generate-plists.sh emits launchd plists from it, and cadence-handlers.mjs
19
+ * consults it (both fall back to the legacy hardcoded set when it's absent).
20
+ *
21
+ * Pure-ish (reads the capability pack). Deterministic (no Date/random). ESM.
22
+ *
23
+ * @module cadences
24
+ */
25
+
26
+ "use strict";
27
+
28
+ import { loadCapabilityPack, listCapabilityFunctions } from "./capability.mjs";
29
+
30
+ /** The standard cadences every maestro agent runs, with explicit schedules. */
31
+ export const STANDARD_CADENCES = [
32
+ { id: "inbox-processor", scope: "standard", mode: "guarded", interval: 300, prompt: "schedules/triggers/inbox-processor.md" },
33
+ { id: "backlog-executor", scope: "standard", mode: "guarded", interval: 600, prompt: "schedules/triggers/backlog-executor.md" },
34
+ { id: "meeting-prep", scope: "standard", mode: "guarded", interval: 900, prompt: "schedules/triggers/meeting-prep.md" },
35
+ { id: "meeting-action-capture", scope: "standard", mode: "escalate", interval: 1800, prompt: "schedules/triggers/meeting-action-capture.md" },
36
+ { id: "daily-morning-brief", scope: "standard", mode: "escalate", calendar: { hour: 6, minute: 30 }, prompt: "schedules/triggers/daily-morning-brief.md" },
37
+ { id: "daily-midday-sweep", scope: "standard", mode: "escalate", calendar: { hour: 12, minute: 0 }, prompt: "schedules/triggers/daily-midday-sweep.md" },
38
+ { id: "daily-evening-wrap", scope: "standard", mode: "escalate", calendar: { hour: 18, minute: 0 }, prompt: "schedules/triggers/daily-evening-wrap.md" },
39
+ { id: "quarterly-self-assessment", scope: "standard", mode: "escalate", calendar: { day: 1, hour: 9, minute: 0 }, prompt: "schedules/triggers/quarterly-self-assessment.md" },
40
+ { id: "org-pulse", scope: "standard", mode: "escalate", calendar: { hour: 7, minute: 30 }, prompt: "schedules/triggers/org-pulse.md" },
41
+ // WS3 self-learning: deterministic skill lifecycle housekeeping. Guarded +
42
+ // inline (no prompt) — the daemon only runs the pure curator transitions when
43
+ // a self-authored skill has crossed a 30/90-day staleness boundary.
44
+ { id: "skill-curator", scope: "standard", mode: "guarded", calendar: { hour: 4, minute: 0 } },
45
+ // Economics / scheduling cadences (WS-economics). All deterministic, so they
46
+ // run INLINE in the persistent daemon (no LLM, no sub-session) — except
47
+ // dynamic-jobs, which is GUARDED: its guard escalates ONLY when an agent-created
48
+ // job is actually due, so the consumer spawns a session to action it.
49
+ // nightly-cost-reconcile: three-way spend reconcile vs the Admin Cost API
50
+ // (fails open with no fetchImpl); flags drift > 10%. Inline, no prompt.
51
+ { id: "nightly-cost-reconcile", scope: "standard", mode: "inline", calendar: { hour: 3, minute: 30 } },
52
+ // fleet-cost-digest: build the daily fleet LLM-spend digest. Inline, no prompt.
53
+ { id: "fleet-cost-digest", scope: "standard", mode: "inline", calendar: { hour: 7, minute: 0 } },
54
+ // org-cost-sync: push today's router ledger rows to Cohort cost.report
55
+ // (no-op / fail-open when org.cohort is disabled). Inline, hourly, no prompt.
56
+ { id: "org-cost-sync", scope: "standard", mode: "inline", interval: 3600 },
57
+ // monitoring-alerts: evaluate + emit behavioral alerts every 5min. Inline, no prompt.
58
+ { id: "monitoring-alerts", scope: "standard", mode: "inline", interval: 300 },
59
+ // dynamic-jobs: action agent-created one-off / recurring reminders. Guarded —
60
+ // the guard escalates only when dueJobs() returns work; otherwise inline.
61
+ { id: "dynamic-jobs", scope: "standard", mode: "guarded", interval: 60, prompt: "schedules/triggers/dynamic-jobs.md" },
62
+ // messaging-inbound (SP10): pull Cohort org messages/@mentions/call-invites
63
+ // directed at this agent into the inbox pipeline. Guarded — routes inline (the
64
+ // reactive daemon owns dispatch); escalate-when-items with
65
+ // MESSAGING_INBOUND_ESCALATE=1. Fail-open / no-op when org messaging disabled.
66
+ { id: "messaging-inbound", scope: "standard", mode: "guarded", interval: 45, prompt: "schedules/triggers/messaging-inbound.md" },
67
+ // directory-hygiene (2026-07): keep the Directory clean — propose captures
68
+ // from signatures/rosters/bank feeds, enrich channels, re-verify anything
69
+ // unseen for >90d, flag duplicates. Guarded: the cheap pre-check reads the two
70
+ // review queues and escalates only when one has work, so an idle org costs two
71
+ // GETs a day and no LLM. PROPOSE-ONLY — merges, awareness changes and archives
72
+ // are human-gated server-side, so the cadence cannot mutate a record.
73
+ { id: "directory-hygiene", scope: "standard", mode: "guarded", calendar: { hour: 5, minute: 0 }, prompt: "schedules/triggers/directory-hygiene.md" },
74
+ // brand-steward (2026-07): a brand foundation save is what makes rendered
75
+ // imagery and templates stale, so this is EVENT-driven, not report-driven —
76
+ // the guard tails the org event chain for branding version.saved and escalates
77
+ // only on a real save. 15min keeps the reaction prompt without polling hard.
78
+ { id: "brand-steward", scope: "standard", mode: "guarded", interval: 900, prompt: "schedules/triggers/brand-steward.md" },
79
+ ];
80
+
81
+ /** Altitude-specific cadences (reuse existing triggers where one exists). */
82
+ export const ALTITUDE_CADENCES = {
83
+ founder: [
84
+ { id: "weekly-runway-review", cadence: "weekly", purpose: "Review runway, burn, and capital position" },
85
+ { id: "monthly-investor-update", cadence: "monthly", purpose: "Draft the monthly investor update" },
86
+ ],
87
+ "c-suite": [
88
+ { id: "weekly-strategic-memo", cadence: "weekly", purpose: "Weekly strategic memo for the principal/board", prompt: "schedules/triggers/weekly-strategic-memo.md" },
89
+ { id: "monthly-board-readiness", cadence: "monthly", purpose: "Maintain board-readiness materials" },
90
+ ],
91
+ svp: [
92
+ { id: "weekly-strategic-memo", cadence: "weekly", purpose: "Weekly strategic memo", prompt: "schedules/triggers/weekly-strategic-memo.md" },
93
+ ],
94
+ vp: [
95
+ { id: "weekly-priorities", cadence: "weekly", purpose: "Weekly priorities review", prompt: "schedules/triggers/weekly-priorities.md" },
96
+ ],
97
+ "senior-manager": [
98
+ { id: "weekly-execution", cadence: "weekly", purpose: "Weekly execution review", prompt: "schedules/triggers/weekly-execution.md" },
99
+ ],
100
+ };
101
+
102
+ /** Cadence keywords that map to a recurring schedule (event-driven is excluded). */
103
+ export const RECURRING = new Set(["daily", "weekly", "monthly", "quarterly", "continuous"]);
104
+
105
+ /** Stable non-negative slot from a string id (deterministic stagger). */
106
+ function slotOf(id) {
107
+ let h = 0;
108
+ for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0;
109
+ return h;
110
+ }
111
+
112
+ /**
113
+ * Deterministic, staggered launchd schedule for a cadence keyword.
114
+ * @param {string} cadence @param {string} id @returns {object} { interval } | { calendar }
115
+ */
116
+ export function scheduleFor(cadence, id) {
117
+ const s = slotOf(id);
118
+ switch (cadence) {
119
+ case "continuous": return { interval: 600 };
120
+ case "daily": return { calendar: { hour: 8 + (s % 9), minute: (s % 2) * 30 } };
121
+ case "weekly": return { calendar: { weekday: 1 + (s % 5), hour: 9 + (s % 7), minute: (s % 2) * 30 } };
122
+ case "monthly": return { calendar: { day: 1 + (s % 5), hour: 9 + (s % 6), minute: 0 } };
123
+ case "quarterly": return { calendar: { day: 1, hour: 9 + (s % 6), minute: 0 } }; // handler guards to quarter
124
+ default: return { interval: 3600 };
125
+ }
126
+ }
127
+
128
+ /** Months (1-12) that open a calendar quarter — Jan, Apr, Jul, Oct. */
129
+ const QUARTER_START_MONTHS = new Set([1, 4, 7, 10]);
130
+
131
+ /**
132
+ * Quarter guard for a cadence that fires monthly (Day=1) but is logically
133
+ * quarterly. The `quarterly-self-assessment` plist fires on the 1st of EVERY
134
+ * month; this returns true only in the first month of each quarter so the
135
+ * handler/trigger can no-op the other 8 ticks instead of delivering a
136
+ * "quarterly" report 12×/year. Pure + deterministic (caller supplies the date).
137
+ *
138
+ * @param {Date} [now] @returns {boolean}
139
+ */
140
+ export function isQuarterStartMonth(now = new Date()) {
141
+ return QUARTER_START_MONTHS.has(now.getMonth() + 1); // getMonth() is 0-based
142
+ }
143
+
144
+ /**
145
+ * Eligibility guard for a cadence tick. For the quarterly self-assessment
146
+ * (which is scheduled monthly so an outage spanning a quarter boundary still
147
+ * fires) a tick is only due in a quarter-start month. All other cadences are
148
+ * always due here (their own guard/handler decides finer-grained eligibility).
149
+ *
150
+ * @param {string} cadenceId @param {Date} [now] @returns {boolean}
151
+ */
152
+ export function isCadenceDue(cadenceId, now = new Date()) {
153
+ if (cadenceId === "quarterly-self-assessment") return isQuarterStartMonth(now);
154
+ return true;
155
+ }
156
+
157
+ function normalize(entry, scope) {
158
+ const out = { id: entry.id, scope, mode: entry.mode || "escalate", prompt: entry.prompt || `schedules/triggers/${entry.id}.md` };
159
+ if (entry.interval != null) out.interval = entry.interval;
160
+ else if (entry.calendar) out.calendar = entry.calendar;
161
+ else {
162
+ const sch = scheduleFor(entry.cadence, entry.id);
163
+ Object.assign(out, sch);
164
+ }
165
+ if (entry.purpose) out.purpose = entry.purpose;
166
+ if (entry.cadence) out.cadence = entry.cadence;
167
+ return out;
168
+ }
169
+
170
+ /**
171
+ * Resolve the full cadence set for a { function, altitude }.
172
+ * @param {{function:string, altitude:string}} sel
173
+ * @returns {Promise<object[]>} ordered, de-duplicated cadence entries
174
+ */
175
+ export async function resolveCadences(sel = {}) {
176
+ const { function: fn, altitude } = sel;
177
+ if (!fn || !altitude) throw new Error("resolveCadences: requires { function, altitude }");
178
+
179
+ const out = [];
180
+ const seen = new Set();
181
+ const add = (entry, scope) => {
182
+ if (!entry || !entry.id || seen.has(entry.id)) return;
183
+ seen.add(entry.id);
184
+ out.push(normalize(entry, scope));
185
+ };
186
+
187
+ for (const c of STANDARD_CADENCES) add(c, "standard");
188
+
189
+ // Function cadences = the capability pack's recurring workflows.
190
+ try {
191
+ const pack = await loadCapabilityPack(fn);
192
+ for (const wf of pack.workflows || []) {
193
+ if (RECURRING.has(wf.cadence)) add(wf, "function");
194
+ }
195
+ } catch { /* no capability pack for this function — standard + altitude only */ }
196
+
197
+ for (const c of ALTITUDE_CADENCES[altitude] || []) add(c, "altitude");
198
+
199
+ return out;
200
+ }
201
+
202
+ /** All function ids that can resolve a cadence set. @returns {string[]} */
203
+ export function listCadenceFunctions() {
204
+ return listCapabilityFunctions();
205
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * cadences.test.mjs — tests for the archetype cadence resolver.
3
+ * Run: `node --test lib/cadences.test.mjs`
4
+ * @module cadences.test
5
+ */
6
+
7
+ "use strict";
8
+
9
+ import { test } from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { resolveCadences, scheduleFor, STANDARD_CADENCES, RECURRING, isQuarterStartMonth, isCadenceDue } from "./cadences.mjs";
12
+
13
+ function hasSchedule(c) {
14
+ return typeof c.interval === "number" || (c.calendar && typeof c.calendar === "object");
15
+ }
16
+
17
+ test("resolveCadences = standard ⊕ function recurring workflows ⊕ altitude cadences", async () => {
18
+ const cads = await resolveCadences({ function: "technical-leader", altitude: "c-suite" });
19
+ const ids = cads.map((c) => c.id);
20
+ // standard present
21
+ assert.ok(ids.includes("inbox-processor") && ids.includes("daily-morning-brief"));
22
+ // a function recurring cadence (from the technical-leader capability workflows)
23
+ assert.ok(ids.includes("engineering-health"), `expected a function cadence; got ${ids.join(",")}`);
24
+ // altitude cadence (c-suite → strategic memo)
25
+ assert.ok(ids.includes("weekly-strategic-memo"));
26
+ // every entry has a concrete schedule + unique ids
27
+ assert.ok(cads.every(hasSchedule), "every cadence has interval or calendar");
28
+ assert.equal(ids.length, new Set(ids).size, "no duplicate cadence ids");
29
+ });
30
+
31
+ test("event-driven workflows are excluded from cadences (pr-review is not scheduled)", async () => {
32
+ const cads = await resolveCadences({ function: "technical-leader", altitude: "vp" });
33
+ assert.ok(!cads.some((c) => c.id === "pr-review"), "event-driven pr-review must not be a scheduled cadence");
34
+ });
35
+
36
+ test("altitude changes the cadence set (c-suite memo vs senior-manager execution review)", async () => {
37
+ const cSuite = (await resolveCadences({ function: "operations-leader", altitude: "c-suite" })).map((c) => c.id);
38
+ const srMgr = (await resolveCadences({ function: "operations-leader", altitude: "senior-manager" })).map((c) => c.id);
39
+ assert.ok(cSuite.includes("weekly-strategic-memo"));
40
+ assert.ok(srMgr.includes("weekly-execution"));
41
+ assert.notDeepEqual(cSuite, srMgr);
42
+ });
43
+
44
+ test("scheduleFor is deterministic and matches the cadence keyword", () => {
45
+ assert.deepEqual(scheduleFor("weekly", "x"), scheduleFor("weekly", "x"));
46
+ assert.ok(scheduleFor("continuous", "x").interval);
47
+ assert.ok(scheduleFor("weekly", "engineering-health").calendar.weekday >= 1);
48
+ assert.ok(RECURRING.has("weekly") && !RECURRING.has("event-driven"));
49
+ });
50
+
51
+ test("resolveCadences requires { function, altitude }", async () => {
52
+ await assert.rejects(() => resolveCadences({}), /requires/);
53
+ });
54
+
55
+ test("quarter guard: quarterly cadence is due in Jan/Apr/Jul/Oct, not other months", () => {
56
+ // The plist fires Day=1 of every month; the guard restricts it to the
57
+ // quarter-start months so the principal gets 4, not 12, reports/year.
58
+ const due = [1, 4, 7, 10];
59
+ for (let month = 1; month <= 12; month++) {
60
+ // Day 1 of each month, midday local to dodge any TZ/DST edge.
61
+ const d = new Date(2026, month - 1, 1, 12, 0, 0);
62
+ const expected = due.includes(month);
63
+ assert.equal(isQuarterStartMonth(d), expected, `month ${month}: isQuarterStartMonth`);
64
+ assert.equal(isCadenceDue("quarterly-self-assessment", d), expected, `month ${month}: quarterly due`);
65
+ }
66
+ });
67
+
68
+ test("quarter guard does not constrain non-quarterly cadences", () => {
69
+ // A daily cadence is due every month — the guard is quarterly-only.
70
+ for (let month = 1; month <= 12; month++) {
71
+ const d = new Date(2026, month - 1, 1, 12, 0, 0);
72
+ assert.equal(isCadenceDue("daily-morning-brief", d), true, `month ${month}: daily always due`);
73
+ assert.equal(isCadenceDue("org-pulse", d), true, `month ${month}: org-pulse always due`);
74
+ }
75
+ });
76
+
77
+ test("STANDARD_CADENCES all carry a schedule; escalating ones carry a prompt", () => {
78
+ assert.ok(STANDARD_CADENCES.length >= 8);
79
+ // Every standard cadence is scheduled.
80
+ assert.ok(STANDARD_CADENCES.every((c) => hasSchedule(c)));
81
+ // Cadences that spawn a sub-session must carry a prompt; a guarded-inline
82
+ // cadence (e.g. skill-curator) legitimately has none — the daemon handles it
83
+ // in-process and never escalates.
84
+ assert.ok(STANDARD_CADENCES.filter((c) => c.mode === "escalate").every((c) => c.prompt));
85
+ });
86
+
87
+ test("economics/scheduling cadences are wired into STANDARD_CADENCES with the right mode + schedule", () => {
88
+ const byId = Object.fromEntries(STANDARD_CADENCES.map((c) => [c.id, c]));
89
+ // Deterministic economics cadences run inline (no LLM).
90
+ for (const id of ["nightly-cost-reconcile", "fleet-cost-digest", "org-cost-sync"]) {
91
+ assert.ok(byId[id], `${id} present in STANDARD_CADENCES`);
92
+ assert.equal(byId[id].mode, "inline", `${id} is inline (deterministic)`);
93
+ assert.ok(hasSchedule(byId[id]), `${id} has a schedule`);
94
+ }
95
+ // Calendar-pinned: nightly-cost-reconcile ~3:30am, fleet-cost-digest ~7am.
96
+ assert.deepEqual(byId["nightly-cost-reconcile"].calendar, { hour: 3, minute: 30 });
97
+ assert.deepEqual(byId["fleet-cost-digest"].calendar, { hour: 7, minute: 0 });
98
+ // org-cost-sync is an hourly interval.
99
+ assert.equal(byId["org-cost-sync"].interval, 3600);
100
+ // dynamic-jobs is the only GUARDED economics cadence (escalate-when-due) and a
101
+ // ~60s interval; because it can escalate it must carry a prompt.
102
+ assert.ok(byId["dynamic-jobs"], "dynamic-jobs present");
103
+ assert.equal(byId["dynamic-jobs"].mode, "guarded");
104
+ assert.equal(byId["dynamic-jobs"].interval, 60);
105
+ assert.ok(byId["dynamic-jobs"].prompt, "guarded dynamic-jobs carries an escalate prompt");
106
+ });
107
+
108
+ test("economics/scheduling cadences resolve into every agent's cadence set", async () => {
109
+ const ids = (await resolveCadences({ function: "operations-leader", altitude: "vp" })).map((c) => c.id);
110
+ for (const id of ["nightly-cost-reconcile", "fleet-cost-digest", "org-cost-sync", "dynamic-jobs"]) {
111
+ assert.ok(ids.includes(id), `${id} resolves into the standard cadence set`);
112
+ }
113
+ });
114
+
115
+ test("every STANDARD_CADENCES entry that declares a prompt has the file on disk", async () => {
116
+ // A guarded/escalate cadence whose prompt file is missing would DLQ at escalate
117
+ // time (regression guard for the dynamic-jobs.md gap).
118
+ const { existsSync } = await import("node:fs");
119
+ const { resolve, join } = await import("node:path");
120
+ const { fileURLToPath } = await import("node:url");
121
+ const root = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
122
+ for (const c of STANDARD_CADENCES.filter((x) => x.prompt)) {
123
+ assert.ok(existsSync(join(root, c.prompt)), `cadence ${c.id} prompt missing: ${c.prompt}`);
124
+ }
125
+ });
@@ -0,0 +1,154 @@
1
+ /**
2
+ * capability.mjs — resolve an archetype's CAPABILITY SURFACE.
3
+ *
4
+ * The init wizard generates a deep, ready-to-act agent: not just a charter and a
5
+ * backlog, but the agent's whole capability surface — the sub-agent org, the
6
+ * Claude Code skills, the workflows, the MCP servers/plugins, and the
7
+ * event→capability routing. This module resolves that surface from:
8
+ *
9
+ * STANDARD defaults (every agent gets these generic infrastructure sub-agents)
10
+ * ⊕ the function's capability pack (archetypes/capabilities/<function>.yaml:
11
+ * agentTeams, skills, workflows, mcpServers)
12
+ * ⊕ altitude breadth scaling (profile.delegationBreadth):
13
+ * broad → all teams, all tiers (lead+core+support) — the full 40–60 roster
14
+ * moderate → all teams, drop the support tier
15
+ * narrow → core teams only, drop the support tier
16
+ * none → standard defaults only
17
+ *
18
+ * Generators (scripts/setup/generate-capability.mjs) render concrete agent.md /
19
+ * skills / workflows / config/event-routing.yaml from this surface; the wizard
20
+ * LLM-tailors each to the company context.
21
+ *
22
+ * Pure-ish (reads the capability YAML + resolves the profile for breadth). ESM.
23
+ *
24
+ * @module capability
25
+ */
26
+
27
+ "use strict";
28
+
29
+ import { readFileSync, existsSync, readdirSync } from "node:fs";
30
+ import path from "node:path";
31
+ import { ARCHETYPES_DIR, resolveArchetype } from "./archetype.mjs";
32
+
33
+ /** Directory of per-function capability packs. */
34
+ export const CAPABILITIES_DIR = path.join(ARCHETYPES_DIR, "capabilities");
35
+
36
+ /**
37
+ * The generic infrastructure sub-agents EVERY maestro agent gets, regardless of
38
+ * archetype. (Curated from agents/; these are role-agnostic plumbing.)
39
+ * @type {Array<{ id: string, role: string, purpose: string }>}
40
+ */
41
+ export const STANDARD_DEFAULT_AGENTS = [
42
+ { id: "inbound-dispatcher", role: "Inbound Dispatcher", purpose: "Classify and route every inbound event to the right handler." },
43
+ { id: "inbox-processor", role: "Inbox Processor", purpose: "Triage Slack/email/calendar/SMS inbox items into actions and queues." },
44
+ { id: "session-spawner", role: "Session Spawner", purpose: "Spawn and supervise managed sub-sessions for delegated work." },
45
+ { id: "workflow-automation", role: "Workflow Automation", purpose: "Run scheduled and event-driven workflows end-to-end." },
46
+ { id: "communications", role: "Communications", purpose: "Draft and send messages in the agent's voice across channels." },
47
+ { id: "calendar-ops", role: "Calendar Ops", purpose: "Manage scheduling, meeting prep, and calendar hygiene." },
48
+ { id: "decision-log", role: "Decision Log", purpose: "Capture decisions with context, options, and rationale." },
49
+ { id: "pmo-execution", role: "PMO / Execution", purpose: "Drive the backlog: select, dispatch, and close work items." },
50
+ { id: "slack-operator", role: "Slack Operator", purpose: "Read/send Slack via the agent's own identity." },
51
+ { id: "gmail-operator", role: "Gmail Operator", purpose: "Read/send email via IMAP/SMTP under the agent's identity." },
52
+ { id: "whatsapp-operator", role: "WhatsApp Operator", purpose: "Read/send WhatsApp messages." },
53
+ { id: "browser-operator", role: "Browser Operator", purpose: "Drive web UIs that lack an API, via the browser." },
54
+ { id: "desktop-operator", role: "Desktop Operator", purpose: "Drive native macOS apps via accessibility/automation." },
55
+ ];
56
+
57
+ /** Valid breadth values (from altitude profile.delegationBreadth). */
58
+ export const BREADTHS = ["broad", "moderate", "narrow", "none"];
59
+
60
+ let _yaml = null;
61
+ async function getYaml() {
62
+ if (_yaml) return _yaml;
63
+ const mod = await import("js-yaml");
64
+ _yaml = mod && mod.default ? mod.default : mod;
65
+ return _yaml;
66
+ }
67
+
68
+ /** Functions that have a capability pack on disk. @returns {string[]} */
69
+ export function listCapabilityFunctions() {
70
+ if (!existsSync(CAPABILITIES_DIR)) return [];
71
+ return readdirSync(CAPABILITIES_DIR).filter((f) => f.endsWith(".yaml")).map((f) => f.slice(0, -5)).sort();
72
+ }
73
+
74
+ /** Load a function's capability pack. @param {string} fn @returns {Promise<object>} */
75
+ export async function loadCapabilityPack(fn) {
76
+ const file = path.join(CAPABILITIES_DIR, `${fn}.yaml`);
77
+ if (!existsSync(file)) throw new Error(`capability pack not found for function "${fn}" (${file})`);
78
+ const yaml = await getYaml();
79
+ const pack = yaml.load(readFileSync(file, "utf8")) || {};
80
+ return {
81
+ mcpServers: pack.mcpServers || [],
82
+ skills: pack.skills || [],
83
+ workflows: pack.workflows || [],
84
+ agentTeams: pack.agentTeams || [],
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Filter the team/agent catalogue by altitude breadth. Pure.
90
+ * @param {object[]} teams @param {string} breadth @returns {object[]}
91
+ */
92
+ export function filterTeamsByBreadth(teams, breadth) {
93
+ if (breadth === "none") return [];
94
+ const coreOnly = breadth === "narrow";
95
+ const dropSupport = breadth === "narrow" || breadth === "moderate";
96
+ return (teams || [])
97
+ .filter((t) => (coreOnly ? t.core === true : true))
98
+ .map((t) => ({
99
+ ...t,
100
+ agents: (t.agents || []).filter((a) => (dropSupport ? a.tier !== "support" : true)),
101
+ }))
102
+ .filter((t) => t.agents.length > 0);
103
+ }
104
+
105
+ /**
106
+ * Resolve the full capability surface for a { function, altitude }.
107
+ * @param {{function:string, altitude:string}} sel
108
+ * @returns {Promise<object>} the capability surface
109
+ */
110
+ export async function resolveCapabilitySurface(sel = {}) {
111
+ const profile = await resolveArchetype(sel); // validates + gives delegationBreadth
112
+ const breadth = BREADTHS.includes(profile.delegationBreadth) ? profile.delegationBreadth : "moderate";
113
+ const pack = await loadCapabilityPack(sel.function);
114
+ const teams = filterTeamsByBreadth(pack.agentTeams, breadth);
115
+ const roleAgents = teams.flatMap((t) => (t.agents || []).map((a) => ({ ...a, team: t.id })));
116
+
117
+ return {
118
+ function: sel.function,
119
+ altitude: sel.altitude,
120
+ breadth,
121
+ standardAgents: STANDARD_DEFAULT_AGENTS,
122
+ teams,
123
+ roleAgents,
124
+ skills: pack.skills,
125
+ workflows: pack.workflows,
126
+ mcpServers: pack.mcpServers,
127
+ counts: {
128
+ standard: STANDARD_DEFAULT_AGENTS.length,
129
+ role: roleAgents.length,
130
+ total: STANDARD_DEFAULT_AGENTS.length + roleAgents.length,
131
+ },
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Build a starter event→capability routing table from a resolved surface.
137
+ * The wizard enriches it; this gives sensible defaults so the daemon can route.
138
+ * @param {object} surface @returns {{ routes: Array<{event:string, handler:string, via:string}> }}
139
+ */
140
+ export function buildEventRouting(surface) {
141
+ const routes = [
142
+ { event: "inbound.message", handler: "inbound-dispatcher", via: "standard-agent" },
143
+ { event: "inbound.email", handler: "inbox-processor", via: "standard-agent" },
144
+ { event: "decision.made", handler: "decision-log", via: "standard-agent" },
145
+ { event: "backlog.tick", handler: "pmo-execution", via: "standard-agent" },
146
+ ];
147
+ for (const w of surface.workflows || []) {
148
+ routes.push({ event: w.cadence === "event-driven" ? `event.${w.id}` : `cadence.${w.cadence}.${w.id}`, handler: w.id, via: "workflow" });
149
+ }
150
+ for (const s of surface.skills || []) {
151
+ routes.push({ event: `request.${s.id}`, handler: s.id, via: "skill" });
152
+ }
153
+ return { routes };
154
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * capability.test.mjs — tests for the capability-surface resolver.
3
+ * Run: `node --test lib/capability.test.mjs`
4
+ * @module capability.test
5
+ */
6
+
7
+ "use strict";
8
+
9
+ import { test } from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import {
12
+ resolveCapabilitySurface,
13
+ loadCapabilityPack,
14
+ filterTeamsByBreadth,
15
+ buildEventRouting,
16
+ listCapabilityFunctions,
17
+ STANDARD_DEFAULT_AGENTS,
18
+ } from "./capability.mjs";
19
+
20
+ const TEAMS = [
21
+ { id: "a", core: true, agents: [{ id: "a1", tier: "lead" }, { id: "a2", tier: "core" }, { id: "a3", tier: "support" }] },
22
+ { id: "b", core: false, agents: [{ id: "b1", tier: "lead" }, { id: "b2", tier: "support" }] },
23
+ ];
24
+
25
+ test("filterTeamsByBreadth: breadth scales the roster deterministically", () => {
26
+ const count = (b) => filterTeamsByBreadth(TEAMS, b).flatMap((t) => t.agents).length;
27
+ assert.equal(count("broad"), 5); // both teams, all tiers
28
+ assert.equal(count("moderate"), 3); // both teams, drop support (a: lead+core, b: lead)
29
+ assert.equal(count("narrow"), 2); // core team only (a), drop support
30
+ assert.equal(count("none"), 0);
31
+ });
32
+
33
+ test("technical-leader capability pack loads with mcp/skills/workflows/teams", async () => {
34
+ assert.ok(listCapabilityFunctions().includes("technical-leader"));
35
+ const pack = await loadCapabilityPack("technical-leader");
36
+ assert.ok(pack.mcpServers.length >= 1);
37
+ assert.ok(pack.skills.length >= 1);
38
+ assert.ok(pack.workflows.length >= 1);
39
+ assert.ok(pack.agentTeams.length >= 3);
40
+ });
41
+
42
+ test("resolveCapabilitySurface composes standard defaults + altitude-scaled role agents", async () => {
43
+ const s = await resolveCapabilitySurface({ function: "technical-leader", altitude: "c-suite" });
44
+ assert.equal(s.standardAgents.length, STANDARD_DEFAULT_AGENTS.length);
45
+ assert.ok(s.roleAgents.length > 0);
46
+ assert.equal(s.counts.total, s.counts.standard + s.counts.role);
47
+ assert.ok(s.mcpServers.length >= 1);
48
+ assert.ok(s.roleAgents.every((a) => a.id && a.role && a.team), "role agents carry id/role/team");
49
+ });
50
+
51
+ test("altitude scales breadth: c-suite ≥ vp ≥ senior-manager role-agent count", async () => {
52
+ const c = await resolveCapabilitySurface({ function: "technical-leader", altitude: "c-suite" });
53
+ const v = await resolveCapabilitySurface({ function: "technical-leader", altitude: "vp" });
54
+ const m = await resolveCapabilitySurface({ function: "technical-leader", altitude: "senior-manager" });
55
+ assert.ok(c.counts.role >= v.counts.role, `c-suite(${c.counts.role}) ≥ vp(${v.counts.role})`);
56
+ assert.ok(v.counts.role >= m.counts.role, `vp(${v.counts.role}) ≥ senior-manager(${m.counts.role})`);
57
+ });
58
+
59
+ test("buildEventRouting maps standard, workflow, and skill handlers", async () => {
60
+ const s = await resolveCapabilitySurface({ function: "technical-leader", altitude: "vp" });
61
+ const { routes } = buildEventRouting(s);
62
+ assert.ok(routes.some((r) => r.via === "standard-agent"));
63
+ assert.ok(routes.some((r) => r.via === "workflow"));
64
+ assert.ok(routes.some((r) => r.via === "skill"));
65
+ });
66
+
67
+ test("every function pack resolves to a 40–60 role roster at broad altitude, with unique ids + mcp/skills/workflows", async () => {
68
+ const fns = listCapabilityFunctions();
69
+ assert.ok(fns.length >= 6, `expected ≥6 capability packs, got ${fns.length}`);
70
+ for (const fn of fns) {
71
+ const pack = await loadCapabilityPack(fn);
72
+ const ids = pack.agentTeams.flatMap((t) => t.agents.map((a) => a.id));
73
+ assert.equal(ids.length, new Set(ids).size, `${fn}: duplicate agent ids`);
74
+ assert.ok(pack.mcpServers.length >= 1 && pack.skills.length >= 1 && pack.workflows.length >= 1, `${fn}: missing mcp/skills/workflows`);
75
+ const broad = await resolveCapabilitySurface({ function: fn, altitude: "founder" }); // founder ⇒ broad
76
+ assert.ok(broad.counts.role >= 40 && broad.counts.role <= 60, `${fn}: broad role count ${broad.counts.role} not in 40–60`);
77
+ }
78
+ });