@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,256 @@
1
+ /**
2
+ * charter.mjs — operating-charter skeleton builder.
3
+ *
4
+ * Renders a complete, enterprise-grade operating charter (Markdown) from a
5
+ * resolved archetype profile (lib/archetype.mjs) + the agent's identity
6
+ * (config/agent.json). The output is deterministic and structurally complete on
7
+ * its own — towers, decision-rights matrix, autonomy bands, escalation, KPI
8
+ * tree, stakeholder map, operating principles, and a 30/60/90 scaffold all flow
9
+ * from the profile. The init wizard then ENRICHES the company-specific slots
10
+ * (concrete purpose, named stakeholders, real KPI targets, a real first-90)
11
+ * from the gathered context pack — but even un-enriched this is a real charter,
12
+ * not a placeholder.
13
+ *
14
+ * Pure (no I/O). The caller stamps any date/identity. ESM.
15
+ *
16
+ * @module charter
17
+ */
18
+
19
+ "use strict";
20
+
21
+ const AUTHORITY_LABEL = {
22
+ owns: "Owns",
23
+ recommends: "Recommends",
24
+ escalates: "Escalates",
25
+ informed: "Informed",
26
+ };
27
+
28
+ function mdEscape(s) {
29
+ return String(s == null ? "" : s).replace(/\|/g, "\\|");
30
+ }
31
+
32
+ function bulletList(items, fallback) {
33
+ const arr = Array.isArray(items) ? items.filter(Boolean) : [];
34
+ if (arr.length === 0) return fallback ? `- ${fallback}` : "- _(to be defined during init enrichment)_";
35
+ return arr.map((x) => `- ${x}`).join("\n");
36
+ }
37
+
38
+ /**
39
+ * Build the operating charter Markdown from a resolved profile + identity.
40
+ *
41
+ * @param {object} profile - resolved archetype profile (lib/archetype.mjs)
42
+ * @param {object} identity - config/agent.json (fullName, title, company, principal, …)
43
+ * @param {object} [opts] @param {string} [opts.date] ISO date string for the header
44
+ * @returns {string} charter Markdown
45
+ */
46
+ export function buildCharterSkeleton(profile, identity, opts = {}) {
47
+ if (!profile || !identity) throw new Error("buildCharterSkeleton: requires (profile, identity)");
48
+ const id = identity;
49
+ const principal = id.principal || {};
50
+ const date = opts.date || "";
51
+ const L = [];
52
+
53
+ L.push(`# Operating Charter — ${id.fullName || "Unconfigured Agent"}`);
54
+ L.push("");
55
+ L.push(`> Generated by Maestro from the \`${profile.function} × ${profile.altitude}\` archetype.${date ? ` ${date}.` : ""}`);
56
+ L.push("> Company-specific sections are enriched at init from the gathered context pack.");
57
+ L.push("");
58
+ L.push(`- **Role:** ${id.title || profile.label}`);
59
+ L.push(`- **Archetype:** ${profile.label} — \`${profile.function}\` × \`${profile.altitude}\``);
60
+ L.push(`- **Operating posture:** ${profile.posture || "—"}`);
61
+ if (principal.fullName) L.push(`- **Principal:** ${principal.fullName}${principal.title ? `, ${principal.title}` : ""}`);
62
+ if (id.company) L.push(`- **Company:** ${id.company}`);
63
+ L.push("");
64
+
65
+ // --- Purpose & Mandate ---
66
+ L.push("## 1. Purpose & Mandate");
67
+ L.push("");
68
+ L.push(`As ${id.title || profile.label}${id.company ? ` at ${id.company}` : ""}, this agent owns **${profile.domain || profile.label}**. ${profile.posture || ""}`.trim());
69
+ L.push("");
70
+ L.push("_Mandate (enrich at init): the specific charge the principal is giving this agent, and the outcomes it is accountable for._");
71
+ L.push("");
72
+
73
+ // --- Control Towers ---
74
+ L.push("## 2. Control Towers");
75
+ L.push("");
76
+ L.push("The standing areas of responsibility this agent monitors and manages.");
77
+ L.push("");
78
+ L.push("| # | Tower | Focus |");
79
+ L.push("| - | ----- | ----- |");
80
+ (profile.towers || []).forEach((t, i) => {
81
+ L.push(`| ${i + 1} | ${mdEscape(t.name)} | ${mdEscape(t.focus || "")} |`);
82
+ });
83
+ L.push("");
84
+
85
+ // --- Decision Rights ---
86
+ L.push("## 3. Decision Rights");
87
+ L.push("");
88
+ L.push(`Authority by scope, calibrated to the **${profile.altitude}** altitude. "Owns" = decides and acts; "Recommends" = proposes, principal decides; "Escalates" = must route up; "Informed" = kept in the loop.`);
89
+ L.push("");
90
+ L.push("| Scope | Authority |");
91
+ L.push("| ----- | --------- |");
92
+ (profile.decisionRights || []).forEach((d) => {
93
+ L.push(`| ${mdEscape(d.scope)} | ${AUTHORITY_LABEL[d.authority] || d.authority} |`);
94
+ });
95
+ L.push("");
96
+
97
+ // --- Autonomy Model ---
98
+ const a = profile.autonomy || {};
99
+ L.push("## 4. Autonomy Model");
100
+ L.push("");
101
+ L.push(`Default posture: **${a.default || "draft"}**.`);
102
+ L.push("");
103
+ L.push("**Green — act autonomously**");
104
+ L.push(bulletList(a.green));
105
+ L.push("");
106
+ L.push("**Amber — approval preferred**");
107
+ L.push(bulletList(a.amber));
108
+ L.push("");
109
+ L.push("**Red — explicit approval required**");
110
+ L.push(bulletList(a.red));
111
+ L.push("");
112
+
113
+ // --- Escalation ---
114
+ const esc = profile.escalation || {};
115
+ L.push("## 5. Escalation Protocol");
116
+ L.push("");
117
+ L.push(`Escalates to: ${(esc.to || []).join(", ") || "the principal"}.`);
118
+ L.push("");
119
+ L.push("Escalation triggers:");
120
+ L.push(bulletList(esc.triggers, "Any binding, irreversible, or beyond-mandate decision"));
121
+ L.push("");
122
+
123
+ // --- KPI Tree ---
124
+ L.push("## 6. KPI Tree");
125
+ L.push("");
126
+ L.push(`KPI altitude: **${profile.kpiAltitude || "operational"}**. Targets are set at init against company baselines.`);
127
+ L.push("");
128
+ (profile.kpiCategories || []).forEach((k) => {
129
+ L.push(`### ${k.name}`);
130
+ L.push(bulletList((k.examples || []).map((e) => `${e} — _target: TBD at init_`)));
131
+ L.push("");
132
+ });
133
+
134
+ // --- Stakeholder Map ---
135
+ L.push("## 7. Stakeholder Map");
136
+ L.push("");
137
+ L.push("| Stakeholder | Typical relationship | Named contact (enrich at init) |");
138
+ L.push("| ----------- | -------------------- | ------------------------------ |");
139
+ (profile.stakeholderSlots || []).forEach((s) => {
140
+ L.push(`| ${mdEscape(s.role)} | ${mdEscape(s.typicalRelationship || "")} | _TBD_ |`);
141
+ });
142
+ L.push("");
143
+
144
+ // --- Operating Principles ---
145
+ L.push("## 8. Operating Principles");
146
+ L.push("");
147
+ L.push(bulletList(profile.operatingPrinciples));
148
+ L.push("");
149
+
150
+ // --- First 90 Days ---
151
+ L.push("## 9. First 90 Days");
152
+ L.push("");
153
+ L.push("_Enriched at init from the seeded backlog (see `state/backlog/wbs.yaml`)._");
154
+ L.push("");
155
+ L.push("### First 30 days — establish");
156
+ L.push("- Stand up the operating cadence and instrument the control towers.");
157
+ L.push("");
158
+ L.push("### Days 31–60 — execute");
159
+ L.push("- Drive the priority streams to their first milestones.");
160
+ L.push("");
161
+ L.push("### Days 61–90 — compound");
162
+ L.push("- Systematise what works; report outcomes against the KPI tree.");
163
+ L.push("");
164
+
165
+ L.push("---");
166
+ L.push("");
167
+ L.push(`_Tone & communication follow \`policies/communication-style.md\`. This charter is generated from the archetype library; regenerate with \`maestro\` after an archetype or identity change._`);
168
+ L.push("");
169
+
170
+ return L.join("\n");
171
+ }
172
+
173
+ /** Title-case a section `kind` token (e.g. "decision_rights" → "Decision Rights"). */
174
+ function titleizeKind(kind) {
175
+ return String(kind || "")
176
+ .replace(/[-_]+/g, " ")
177
+ .replace(/\s+/g, " ")
178
+ .trim()
179
+ .replace(/\b\w/g, (c) => c.toUpperCase());
180
+ }
181
+
182
+ /**
183
+ * Render the operating charter Markdown FROM a Cohort-authored CharterDTO — the
184
+ * org source of truth. When a member's charter exists in Cohort
185
+ * (config/agent.json `charter` = { approvedByLine, gatesText, sections }), this
186
+ * is what `scripts/setup/generate-charter.mjs` writes, IN PLACE OF the archetype
187
+ * skeleton (buildCharterSkeleton). The agent thus operates on the charter its org
188
+ * authored, not a locally-synthesised one.
189
+ *
190
+ * Sections are rendered in `order`. Each section's heading is its `title` (or a
191
+ * title-cased `kind`), followed by its verbatim `body`. The approvedBy line and
192
+ * gates text are appended as their own blocks. Pure (no I/O).
193
+ *
194
+ * @param {object} charter - { approvedByLine?, gatesText?, sections:[{kind,order,title,body}] }
195
+ * @param {object} identity - config/agent.json (fullName, title, company, principal, …)
196
+ * @param {object} [opts] @param {string} [opts.date] ISO date string for the header
197
+ * @returns {string} charter Markdown
198
+ */
199
+ export function renderCohortCharter(charter, identity, opts = {}) {
200
+ if (!charter || typeof charter !== "object") throw new Error("renderCohortCharter: requires a charter");
201
+ const id = identity || {};
202
+ const principal = id.principal || {};
203
+ const date = opts.date || "";
204
+ const L = [];
205
+
206
+ L.push(`# Operating Charter — ${id.fullName || "Unconfigured Agent"}`);
207
+ L.push("");
208
+ L.push(`> Authored in Cohort (org source of truth) and rendered by Maestro.${date ? ` ${date}.` : ""}`);
209
+ L.push("");
210
+ if (id.title) L.push(`- **Role:** ${id.title}`);
211
+ if (principal.fullName) L.push(`- **Principal:** ${principal.fullName}${principal.title ? `, ${principal.title}` : ""}`);
212
+ if (id.company) L.push(`- **Company:** ${id.company}`);
213
+ if (charter.approvedByLine) L.push(`- **Approved by:** ${charter.approvedByLine}`);
214
+ L.push("");
215
+
216
+ const sections = (Array.isArray(charter.sections) ? charter.sections.slice() : [])
217
+ .filter((s) => s && typeof s === "object")
218
+ .sort((a, b) => (Number(a.order) || 0) - (Number(b.order) || 0));
219
+ for (const s of sections) {
220
+ const heading = (s.title && String(s.title).trim()) || titleizeKind(s.kind) || "Section";
221
+ L.push(`## ${heading}`);
222
+ L.push("");
223
+ const body = s.body == null ? "" : String(s.body).trim();
224
+ L.push(body || "_(no content)_");
225
+ L.push("");
226
+ }
227
+
228
+ if (charter.gatesText && String(charter.gatesText).trim()) {
229
+ L.push("## Gates");
230
+ L.push("");
231
+ L.push(String(charter.gatesText).trim());
232
+ L.push("");
233
+ }
234
+
235
+ L.push("---");
236
+ L.push("");
237
+ L.push(`_Source of truth: the member's charter in Cohort. Regenerate with \`maestro\` after the org updates it._`);
238
+ L.push("");
239
+
240
+ return L.join("\n");
241
+ }
242
+
243
+ /**
244
+ * True if a charter body still contains unfilled placeholders that should be
245
+ * enriched before it is considered init-complete (used by the doctor gate).
246
+ *
247
+ * @param {string} body @returns {string[]} the placeholder markers found
248
+ */
249
+ export function findCharterPlaceholders(body) {
250
+ if (typeof body !== "string") return [];
251
+ const markers = [];
252
+ if (/\{\{[^}]+\}\}/.test(body)) markers.push("unresolved {{token}}");
253
+ if (/\bTBD\b/.test(body)) markers.push("TBD");
254
+ if (/_\(to be defined during init enrichment\)_/.test(body)) markers.push("undefined autonomy/escalation band");
255
+ return [...new Set(markers)];
256
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * charter.test.mjs — tests for the operating-charter skeleton builder.
3
+ * Run: `node --test lib/charter.test.mjs`
4
+ * @module charter.test
5
+ */
6
+
7
+ "use strict";
8
+
9
+ import { test } from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { resolveArchetype } from "./archetype.mjs";
12
+ import { buildCharterSkeleton, findCharterPlaceholders, renderCohortCharter } from "./charter.mjs";
13
+
14
+ const IDENTITY = {
15
+ firstName: "Jacob", fullName: "Jacob Chen", title: "VP, Engineering", company: "Acme",
16
+ principal: { fullName: "Dana Reyes", title: "CEO" },
17
+ };
18
+
19
+ test("buildCharterSkeleton renders a complete charter from the profile", async () => {
20
+ const profile = await resolveArchetype({ function: "technical-leader", altitude: "vp" });
21
+ const md = buildCharterSkeleton(profile, IDENTITY, { date: "2026-06-01" });
22
+
23
+ assert.match(md, /# Operating Charter — Jacob Chen/);
24
+ assert.match(md, /\*\*Role:\*\* VP, Engineering/);
25
+ assert.match(md, /Dana Reyes, CEO/);
26
+ // towers from the function overlay
27
+ assert.match(md, /Platform & Architecture/);
28
+ // decision-rights matrix with altitude authorities
29
+ assert.match(md, /## 3\. Decision Rights/);
30
+ assert.match(md, /Escalates/);
31
+ // autonomy bands
32
+ assert.match(md, /Green — act autonomously/);
33
+ assert.match(md, /Red — explicit approval required/);
34
+ // KPI tree + stakeholders + principles + 90-day
35
+ assert.match(md, /## 6\. KPI Tree/);
36
+ assert.match(md, /## 7\. Stakeholder Map/);
37
+ assert.match(md, /Technical rigour over speed/); // a function principle
38
+ assert.match(md, /## 9\. First 90 Days/);
39
+ });
40
+
41
+ test("a C-suite charter differs from a senior-manager charter (altitude shows through)", async () => {
42
+ const cSuite = buildCharterSkeleton(await resolveArchetype({ function: "technical-leader", altitude: "c-suite" }), IDENTITY);
43
+ const srMgr = buildCharterSkeleton(await resolveArchetype({ function: "technical-leader", altitude: "senior-manager" }), IDENTITY);
44
+ assert.notEqual(cSuite, srMgr); // same function, different altitude → different charter
45
+ });
46
+
47
+ test("findCharterPlaceholders flags un-enriched markers (KPI targets are TBD pre-init)", async () => {
48
+ const profile = await resolveArchetype({ function: "commercial-leader", altitude: "svp" });
49
+ const md = buildCharterSkeleton(profile, IDENTITY);
50
+ assert.ok(findCharterPlaceholders(md).includes("TBD"));
51
+ // a fully-enriched body has no markers
52
+ assert.deepEqual(findCharterPlaceholders("# Charter\nAll concrete, no placeholders."), []);
53
+ assert.ok(findCharterPlaceholders("see {{agent.firstName}}").includes("unresolved {{token}}"));
54
+ });
55
+
56
+ test("buildCharterSkeleton requires both arguments", () => {
57
+ assert.throws(() => buildCharterSkeleton(null, IDENTITY), /requires/);
58
+ });
59
+
60
+ // --- charter source-of-truth: render FROM a Cohort-authored CharterDTO -------
61
+
62
+ const ORG_CHARTER = {
63
+ approvedByLine: "Approved by Dana Reyes, CEO — 2026-06-01",
64
+ gatesText: "Irreversible spend > $25k escalates to the principal.",
65
+ sections: [
66
+ { kind: "decision_rights", order: 2, title: null, body: "Owns the deploy cadence; recommends headcount." },
67
+ { kind: "purpose", order: 1, title: "Purpose & Mandate", body: "Own platform reliability and developer velocity." },
68
+ ],
69
+ };
70
+
71
+ test("renderCohortCharter renders sections in order with the authored bodies", () => {
72
+ const md = renderCohortCharter(ORG_CHARTER, IDENTITY, { date: "2026-06-01" });
73
+ assert.match(md, /# Operating Charter — Jacob Chen/);
74
+ assert.match(md, /Authored in Cohort \(org source of truth\)/);
75
+ assert.match(md, /Approved by Dana Reyes, CEO — 2026-06-01/);
76
+ // section 1 (order 1) renders before section 2 (order 2)
77
+ const iPurpose = md.indexOf("Purpose & Mandate");
78
+ const iRights = md.indexOf("Decision Rights"); // title null → title-cased kind
79
+ assert.ok(iPurpose > 0 && iRights > iPurpose, "sections render in `order`");
80
+ assert.match(md, /Own platform reliability and developer velocity\./);
81
+ assert.match(md, /Owns the deploy cadence; recommends headcount\./);
82
+ // gates block
83
+ assert.match(md, /## Gates/);
84
+ assert.match(md, /Irreversible spend > \$25k escalates/);
85
+ });
86
+
87
+ test("renderCohortCharter requires a charter object", () => {
88
+ assert.throws(() => renderCohortCharter(null, IDENTITY), /requires/);
89
+ });
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Maestro — Claude CLI binary resolver.
3
+ *
4
+ * Shared utility for every code path that spawns `claude --print`.
5
+ * launchd's bare environment does NOT include ~/.local/bin or homebrew
6
+ * paths, so a plain `spawn('claude', …)` from a daemon-spawned process
7
+ * fails with ENOENT — even though the operator's interactive shell finds
8
+ * it without trouble.
9
+ *
10
+ * Caller sites:
11
+ * - scripts/daemon/dispatcher.mjs (reactive: replies to Slack/Gmail/etc)
12
+ * - scripts/daemon/responder.mjs (quick replies + holding messages)
13
+ * - scripts/daemon/cadence-consumer.mjs (scheduled cadence ticks)
14
+ * - scripts/poller/intra-session-check.mjs
15
+ * - any other module that spawns claude from a non-interactive context
16
+ */
17
+
18
+ import { existsSync, statSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { homedir } from "node:os";
21
+
22
+ let _resolved = null;
23
+
24
+ /**
25
+ * Is `p` a regular file that is safe to execute as this agent? An attacker who
26
+ * can rewrite the resolved binary — or point $CLAUDE_BIN at one they control —
27
+ * gets code execution as the agent on the next spawn, which on an unattended
28
+ * 24/7 Mac mini is a realistic local-persistence vector. We therefore require
29
+ * the file to exist, be a regular file, not be group/world-writable, and be
30
+ * owned by this user or root. (M2)
31
+ *
32
+ * @param {string} p
33
+ * @returns {boolean}
34
+ */
35
+ export function isSafeExecutable(p) {
36
+ try {
37
+ const st = statSync(p);
38
+ if (!st.isFile()) return false;
39
+ // Reject group- or world-writable binaries (someone other than the owner
40
+ // could swap the executable out from under us).
41
+ if (st.mode & 0o022) return false;
42
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
43
+ if (uid !== null && st.uid !== uid && st.uid !== 0) return false;
44
+ return true;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Return the absolute path to the Claude CLI. Searches, in order:
52
+ * 1. $CLAUDE_BIN env var (if set + executable on disk)
53
+ * 2. ~/.local/bin/claude (default Claude Code install location)
54
+ * 3. /opt/homebrew/bin/claude (Apple Silicon homebrew)
55
+ * 4. /usr/local/bin/claude (Intel homebrew)
56
+ * 5. /usr/bin/claude
57
+ *
58
+ * Falls back to bare "claude" so the spawn's own error stays informative
59
+ * if nothing on the search path exists.
60
+ */
61
+ export function resolveClaudeBin() {
62
+ if (_resolved) return _resolved;
63
+ const envOverride = process.env.CLAUDE_BIN;
64
+ // The env override is the highest-trust candidate, so it gets the full
65
+ // safety check (M2). If it is set but unsafe/missing, we log and fall
66
+ // through to the known-good fixed locations rather than trusting it.
67
+ if (envOverride) {
68
+ if (isSafeExecutable(envOverride)) { _resolved = envOverride; return envOverride; }
69
+ console.error(
70
+ `[claude-bin] Ignoring CLAUDE_BIN=${envOverride}: not a safe, owner-only, ` +
71
+ `non-writable executable. Falling back to default search paths.`
72
+ );
73
+ }
74
+ const candidates = [
75
+ join(homedir(), ".local/bin/claude"),
76
+ "/opt/homebrew/bin/claude",
77
+ "/usr/local/bin/claude",
78
+ "/usr/bin/claude",
79
+ ];
80
+ for (const c of candidates) {
81
+ if (existsSync(c)) { _resolved = c; return c; }
82
+ }
83
+ // Last resort: bare name (lets the OS PATH + spawn error stay informative).
84
+ // Do NOT memoize this — if the CLI gets installed later, a long-lived daemon
85
+ // should pick it up on the next call rather than caching the fallback. (L28)
86
+ return "claude";
87
+ }
88
+
89
+ /**
90
+ * Default args every daemon-spawned `claude --print` should receive on
91
+ * top of the prompt + model selection. Currently:
92
+ *
93
+ * --strict-mcp-config
94
+ * Skip every globally-installed Claude Code MCP plugin (Serena,
95
+ * Playwright, etc). Daemon spawns don't need IDE-grade code
96
+ * intelligence; they need to write a Slack reply / draft an email
97
+ * / classify an item. Loading MCPs wastes 3-5s per spawn AND opens
98
+ * a browser dashboard tab per session (Serena does this).
99
+ *
100
+ * --bare (opt-in via DAEMON_BARE_MODE=1)
101
+ * Skip hooks, LSP, plugin sync, auto-memory, keychain reads. Even
102
+ * more minimal. Use when you specifically want a stateless spawn —
103
+ * but it disables Keychain OAuth, so MAESTRO_PREFER_SUBSCRIPTION_AUTH
104
+ * callers should NOT set this.
105
+ *
106
+ * Operators who want full MCP support on daemon spawns can set
107
+ * DAEMON_LOAD_MCPS=1 in .env; the spawn sites will skip these flags.
108
+ */
109
+ export function daemonClaudeArgs() {
110
+ if (process.env.DAEMON_LOAD_MCPS === "1") return [];
111
+ const args = ["--strict-mcp-config"];
112
+ if (process.env.DAEMON_BARE_MODE === "1") args.unshift("--bare");
113
+ return args;
114
+ }
115
+
116
+ /**
117
+ * Build a PATH suitable for child processes spawned from a daemon.
118
+ * launchd strips PATH down to /usr/bin:/bin; this returns a string that
119
+ * preserves the caller's PATH if set, then appends the locations claude
120
+ * subsessions might need to find node, jq, gh, etc.
121
+ */
122
+ export function augmentedPath() {
123
+ return [
124
+ process.env.PATH || "",
125
+ `${homedir()}/.local/bin`,
126
+ "/opt/homebrew/bin",
127
+ "/opt/homebrew/sbin",
128
+ "/usr/local/bin",
129
+ "/usr/bin",
130
+ "/bin",
131
+ "/usr/sbin",
132
+ "/sbin",
133
+ ].filter(Boolean).join(":");
134
+ }
@@ -0,0 +1,75 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, writeFileSync, chmodSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { isSafeExecutable, augmentedPath, daemonClaudeArgs } from "./claude-bin.mjs";
7
+
8
+ function tmp() {
9
+ return mkdtempSync(join(tmpdir(), "claude-bin-test-"));
10
+ }
11
+
12
+ test("isSafeExecutable accepts an owner-only, non-writable regular file", () => {
13
+ const dir = tmp();
14
+ try {
15
+ const p = join(dir, "claude");
16
+ writeFileSync(p, "#!/bin/sh\n");
17
+ chmodSync(p, 0o755);
18
+ assert.equal(isSafeExecutable(p), true);
19
+ } finally {
20
+ rmSync(dir, { recursive: true, force: true });
21
+ }
22
+ });
23
+
24
+ test("isSafeExecutable rejects a world-writable file (swap vector)", () => {
25
+ const dir = tmp();
26
+ try {
27
+ const p = join(dir, "claude");
28
+ writeFileSync(p, "#!/bin/sh\n");
29
+ chmodSync(p, 0o757); // world-writable
30
+ assert.equal(isSafeExecutable(p), false);
31
+ } finally {
32
+ rmSync(dir, { recursive: true, force: true });
33
+ }
34
+ });
35
+
36
+ test("isSafeExecutable rejects a group-writable file", () => {
37
+ const dir = tmp();
38
+ try {
39
+ const p = join(dir, "claude");
40
+ writeFileSync(p, "#!/bin/sh\n");
41
+ chmodSync(p, 0o775); // group-writable
42
+ assert.equal(isSafeExecutable(p), false);
43
+ } finally {
44
+ rmSync(dir, { recursive: true, force: true });
45
+ }
46
+ });
47
+
48
+ test("isSafeExecutable rejects a nonexistent path without throwing", () => {
49
+ assert.equal(isSafeExecutable("/nope/does/not/exist/claude"), false);
50
+ });
51
+
52
+ test("isSafeExecutable rejects a directory", () => {
53
+ const dir = tmp();
54
+ try {
55
+ assert.equal(isSafeExecutable(dir), false);
56
+ } finally {
57
+ rmSync(dir, { recursive: true, force: true });
58
+ }
59
+ });
60
+
61
+ test("augmentedPath includes common bin locations and preserves existing PATH", () => {
62
+ const p = augmentedPath();
63
+ assert.ok(p.includes("/usr/bin"));
64
+ assert.ok(p.includes("/opt/homebrew/bin"));
65
+ });
66
+
67
+ test("daemonClaudeArgs returns strict-mcp-config by default", () => {
68
+ const prev = process.env.DAEMON_LOAD_MCPS;
69
+ delete process.env.DAEMON_LOAD_MCPS;
70
+ try {
71
+ assert.deepEqual(daemonClaudeArgs(), ["--strict-mcp-config"]);
72
+ } finally {
73
+ if (prev !== undefined) process.env.DAEMON_LOAD_MCPS = prev;
74
+ }
75
+ });