@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,413 @@
1
+ /**
2
+ * generate-plists.test.mjs — Coverage for scripts/local-triggers/generate-plists.sh
3
+ *
4
+ * Builds a fixture agent repo (minimal config/agent.ts + script tree),
5
+ * runs the generator, and asserts every emitted plist matches the
6
+ * cadence-bus architecture marker and never references the legacy
7
+ * run-trigger.sh spawn-per-tick pattern.
8
+ */
9
+
10
+ import { test } from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import { promises as fsp } from "fs";
13
+ import { readFileSync, readdirSync, writeFileSync, mkdirSync, copyFileSync } from "node:fs";
14
+ import { tmpdir } from "os";
15
+ import { join, resolve, dirname } from "path";
16
+ import { fileURLToPath } from "node:url";
17
+ import { spawnSync } from "node:child_process";
18
+
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const MAESTRO_ROOT = resolve(__dirname, "..", "..");
21
+ const GENERATOR = resolve(__dirname, "generate-plists.sh");
22
+
23
+ async function makeAgent(firstName) {
24
+ const root = join(
25
+ tmpdir(),
26
+ `plist-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
27
+ );
28
+ await fsp.mkdir(root, { recursive: true });
29
+
30
+ // Minimal agent identity.
31
+ await fsp.mkdir(join(root, "config"), { recursive: true });
32
+ writeFileSync(
33
+ join(root, "config/agent.ts"),
34
+ `export const AGENT = { firstName: '${firstName}', lastName: 'Tester' };\n`
35
+ );
36
+ writeFileSync(join(root, "package.json"), '{"name":"t"}');
37
+
38
+ // Copy the scripts the generator references.
39
+ await fsp.mkdir(join(root, "scripts/local-triggers"), { recursive: true });
40
+ await fsp.mkdir(join(root, "scripts/daemon"), { recursive: true });
41
+ await fsp.mkdir(join(root, "scripts/cadence"), { recursive: true });
42
+ // The generator now derives the standard cadence set from the canonical
43
+ // STANDARD_CADENCES in lib/cadences.mjs (SoT), so the fixture needs the
44
+ // module + its local import chain (capability → archetype).
45
+ await fsp.mkdir(join(root, "lib"), { recursive: true });
46
+ for (const m of ["lib/cadences.mjs", "lib/capability.mjs", "lib/archetype.mjs"]) {
47
+ copyFileSync(join(MAESTRO_ROOT, m), join(root, m));
48
+ }
49
+ copyFileSync(GENERATOR, join(root, "scripts/local-triggers/generate-plists.sh"));
50
+ copyFileSync(
51
+ join(MAESTRO_ROOT, "scripts/local-triggers/run-trigger.sh"),
52
+ join(root, "scripts/local-triggers/run-trigger.sh"),
53
+ );
54
+ copyFileSync(
55
+ join(MAESTRO_ROOT, "scripts/daemon/launchd-wrapper.sh"),
56
+ join(root, "scripts/daemon/launchd-wrapper.sh"),
57
+ );
58
+ copyFileSync(
59
+ join(MAESTRO_ROOT, "scripts/daemon/launchd-wrapper-generic.sh"),
60
+ join(root, "scripts/daemon/launchd-wrapper-generic.sh"),
61
+ );
62
+ copyFileSync(
63
+ join(MAESTRO_ROOT, "scripts/cadence/launchd-cadence-wrapper.sh"),
64
+ join(root, "scripts/cadence/launchd-cadence-wrapper.sh"),
65
+ );
66
+ copyFileSync(
67
+ join(MAESTRO_ROOT, "scripts/cadence/launchd-socket-mode-wrapper.sh"),
68
+ join(root, "scripts/cadence/launchd-socket-mode-wrapper.sh"),
69
+ );
70
+ copyFileSync(
71
+ join(MAESTRO_ROOT, "scripts/cadence/enqueue-cadence-tick.mjs"),
72
+ join(root, "scripts/cadence/enqueue-cadence-tick.mjs"),
73
+ );
74
+
75
+ // Make scripts executable.
76
+ for (const p of [
77
+ "scripts/local-triggers/generate-plists.sh",
78
+ "scripts/local-triggers/run-trigger.sh",
79
+ "scripts/daemon/launchd-wrapper.sh",
80
+ "scripts/daemon/launchd-wrapper-generic.sh",
81
+ "scripts/cadence/launchd-cadence-wrapper.sh",
82
+ "scripts/cadence/launchd-socket-mode-wrapper.sh",
83
+ ]) {
84
+ await fsp.chmod(join(root, p), 0o755);
85
+ }
86
+ return root;
87
+ }
88
+
89
+ async function rmRoot(path) {
90
+ try { await fsp.rm(path, { recursive: true, force: true }); } catch { /* */ }
91
+ }
92
+
93
+ function runGenerator(agentRoot) {
94
+ return spawnSync("/bin/bash", [join(agentRoot, "scripts/local-triggers/generate-plists.sh")], {
95
+ cwd: agentRoot,
96
+ encoding: "utf-8",
97
+ env: { ...process.env },
98
+ });
99
+ }
100
+
101
+ function listPlists(agentRoot) {
102
+ const dir = join(agentRoot, "scripts/local-triggers/plists");
103
+ return readdirSync(dir).filter((n) => n.endsWith(".plist"));
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // Tests
108
+ // ---------------------------------------------------------------------------
109
+
110
+ test("generator emits 21 standard plists with the agent's first name", async () => {
111
+ // Standard inventory (cadence-bus v1 + slack-socket-mode v1), with NO
112
+ // config/.cadence-plists.tsv present (no archetype cadences):
113
+ // daemon, poll-relay, slack-socket (3 infra), PLUS one trigger plist per
114
+ // STANDARD_CADENCES entry in lib/cadences.mjs (the SoT):
115
+ // inbox-processor, backlog-executor, meeting-prep, meeting-action-capture,
116
+ // daily-morning-brief, daily-midday-sweep, daily-evening-wrap,
117
+ // quarterly-self-assessment, org-pulse, skill-curator (10), PLUS the
118
+ // economics/scheduling cadences nightly-cost-reconcile, fleet-cost-digest,
119
+ // org-cost-sync, monitoring-alerts, dynamic-jobs (5), PLUS the SP10
120
+ // messaging-inbound cadence (1), PLUS the 2026-07 Directory & Design
121
+ // stewards directory-hygiene + brand-steward (2). = 3 infra + 18 trigger
122
+ // = 21 total.
123
+ // org-pulse used to be declared standard but was OMITTED by the old hardcoded
124
+ // list (it never got a plist); deriving from the SoT fixes that drift.
125
+ // The former weekly-* cadences are still ARCHETYPE-DRIVEN (function × altitude),
126
+ // emitted from config/.cadence-plists.tsv (scripts/setup/generate-cadences.mjs).
127
+ const root = await makeAgent("alice");
128
+ try {
129
+ const r = runGenerator(root);
130
+ assert.equal(r.status, 0, r.stderr);
131
+ const plists = listPlists(root);
132
+ assert.equal(plists.length, 21, `expected 21 standard plists; got ${plists.join(",")}`);
133
+ assert.ok(plists.includes("ai.maestro.alice-messaging-inbound.plist"),
134
+ "messaging-inbound (SP10 standard cadence) must get a SoT-derived plist");
135
+ for (const id of ["directory-hygiene", "brand-steward"]) {
136
+ assert.ok(plists.includes(`ai.maestro.alice-${id}.plist`),
137
+ `Directory/Design steward "${id}" must get a SoT-derived plist; got ${plists.join(",")}`);
138
+ }
139
+ assert.ok(plists.includes("ai.maestro.alice-org-pulse.plist"),
140
+ "org-pulse (declared standard) must get a plist now it's SoT-derived");
141
+ // The newly-wired economics/scheduling cadences each get a plist.
142
+ for (const id of ["nightly-cost-reconcile", "fleet-cost-digest", "org-cost-sync", "dynamic-jobs"]) {
143
+ assert.ok(plists.includes(`ai.maestro.alice-${id}.plist`),
144
+ `economics cadence "${id}" must get a SoT-derived plist; got ${plists.join(",")}`);
145
+ }
146
+ for (const p of plists) {
147
+ assert.match(p, /^ai\.maestro\.alice-/);
148
+ }
149
+ } finally { await rmRoot(root); }
150
+ });
151
+
152
+ test("every cadence resolved by resolveCadences() gets a generated plist (incl. org-pulse)", async () => {
153
+ // Single-source-of-truth guarantee: the launchd plist set is derived from the
154
+ // canonical cadence resolution, so a cadence declared in lib/cadences.mjs can
155
+ // never silently lack a job (the org-pulse-never-fires class of bug).
156
+ const root = await makeAgent("hana");
157
+ try {
158
+ // Drive the archetype TSV too, so we cover standard + archetype in one pass.
159
+ const { resolveCadences } = await import(join(MAESTRO_ROOT, "lib/cadences.mjs"));
160
+ const cadences = await resolveCadences({ function: "technical-leader", altitude: "c-suite" });
161
+ // Emit the archetype (non-standard) cadences via the TSV, exactly as
162
+ // generate-cadences.mjs does (id|interval| / id||base64(sched)).
163
+ const tsvLines = [];
164
+ for (const c of cadences) {
165
+ if (c.scope === "standard") continue;
166
+ if (typeof c.interval === "number") tsvLines.push(`${c.id}|${c.interval}|`);
167
+ else if (c.calendar) {
168
+ const cal = c.calendar;
169
+ let x = "";
170
+ if (cal.weekday != null) x += ` <key>Weekday</key>\n <integer>${cal.weekday}</integer>\n`;
171
+ if (cal.day != null) x += ` <key>Day</key>\n <integer>${cal.day}</integer>\n`;
172
+ x += ` <key>Hour</key>\n <integer>${cal.hour ?? 9}</integer>\n <key>Minute</key>\n <integer>${cal.minute ?? 0}</integer>`;
173
+ tsvLines.push(`${c.id}||${Buffer.from(x, "utf-8").toString("base64")}`);
174
+ }
175
+ }
176
+ writeFileSync(join(root, "config/.cadence-plists.tsv"), tsvLines.join("\n") + (tsvLines.length ? "\n" : ""));
177
+
178
+ const r = runGenerator(root);
179
+ assert.equal(r.status, 0, r.stderr);
180
+ const plists = new Set(listPlists(root));
181
+ for (const c of cadences) {
182
+ // skill-curator has a calendar; every resolved cadence here has a
183
+ // schedule, so each must produce exactly one trigger plist.
184
+ const label = `ai.maestro.hana-${c.id}.plist`;
185
+ assert.ok(plists.has(label), `resolved cadence "${c.id}" (${c.scope}) has no plist; got ${[...plists].join(",")}`);
186
+ }
187
+ // Spot-check the specific regression: org-pulse is standard and present.
188
+ assert.ok(plists.has("ai.maestro.hana-org-pulse.plist"), "org-pulse must be present");
189
+ } finally { await rmRoot(root); }
190
+ });
191
+
192
+ test("archetype cadences from config/.cadence-plists.tsv emit extra trigger plists", async () => {
193
+ const root = await makeAgent("erin");
194
+ try {
195
+ const calXml = " <key>Weekday</key>\n <integer>3</integer>\n <key>Hour</key>\n <integer>10</integer>\n <key>Minute</key>\n <integer>0</integer>";
196
+ const tsv =
197
+ `engineering-health||${Buffer.from(calXml, "utf-8").toString("base64")}\n` +
198
+ `quality-pulse|1800|\n`;
199
+ writeFileSync(join(root, "config/.cadence-plists.tsv"), tsv);
200
+ const r = runGenerator(root);
201
+ assert.equal(r.status, 0, r.stderr);
202
+ const plists = listPlists(root);
203
+ assert.equal(plists.length, 23, `expected 21 standard + 2 archetype; got ${plists.join(",")}`);
204
+ const dir = join(root, "scripts/local-triggers/plists");
205
+ const eng = readFileSync(join(dir, "ai.maestro.erin-engineering-health.plist"), "utf-8");
206
+ assert.match(eng, /<key>Weekday<\/key>\s*<integer>3<\/integer>/); // base64 schedule decoded
207
+ assert.match(eng, /enqueue-cadence-tick\.mjs/);
208
+ const qp = readFileSync(join(dir, "ai.maestro.erin-quality-pulse.plist"), "utf-8");
209
+ assert.match(qp, /<integer>1800<\/integer>/); // interval path
210
+ } finally { await rmRoot(root); }
211
+ });
212
+
213
+ test("every trigger plist carries the cadence-bus architecture marker", async () => {
214
+ const root = await makeAgent("bob");
215
+ try {
216
+ runGenerator(root);
217
+ const dir = join(root, "scripts/local-triggers/plists");
218
+ for (const name of listPlists(root)) {
219
+ const body = readFileSync(join(dir, name), "utf-8");
220
+ assert.match(body, /maestro-plist-arch: cadence-bus/, `${name} missing arch marker`);
221
+ }
222
+ } finally { await rmRoot(root); }
223
+ });
224
+
225
+ test("NO trigger plist invokes run-trigger.sh", async () => {
226
+ const root = await makeAgent("carol");
227
+ try {
228
+ runGenerator(root);
229
+ const dir = join(root, "scripts/local-triggers/plists");
230
+ for (const name of listPlists(root)) {
231
+ const body = readFileSync(join(dir, name), "utf-8");
232
+ // Exception: the daemon/poll-relay/slack-socket plists don't run cadence
233
+ // triggers at all (the first two are KeepAlive workers; slack-socket is
234
+ // a KeepAlive WSS listener). The trigger plists must invoke
235
+ // enqueue-cadence-tick.mjs.
236
+ if (name.endsWith("-daemon.plist") || name.endsWith("-poll-relay.plist") ||
237
+ name.endsWith("-slack-socket.plist")) {
238
+ continue;
239
+ }
240
+ assert.ok(!body.includes("run-trigger.sh"),
241
+ `${name} still references run-trigger.sh:\n${body}`);
242
+ assert.ok(body.includes("enqueue-cadence-tick.mjs"),
243
+ `${name} should invoke enqueue script`);
244
+ }
245
+ } finally { await rmRoot(root); }
246
+ });
247
+
248
+ test("trigger plists pass --source=launchd to the enqueue script", async () => {
249
+ const root = await makeAgent("dana");
250
+ try {
251
+ runGenerator(root);
252
+ const dir = join(root, "scripts/local-triggers/plists");
253
+ const triggerPlist = join(dir, "ai.maestro.dana-inbox-processor.plist");
254
+ const body = readFileSync(triggerPlist, "utf-8");
255
+ assert.match(body, /<string>--source=launchd<\/string>/);
256
+ assert.match(body, /<string>inbox-processor<\/string>/);
257
+ // StartInterval 300 (every 5 min).
258
+ assert.match(body, /<integer>300<\/integer>/);
259
+ } finally { await rmRoot(root); }
260
+ });
261
+
262
+ test("interval trigger plists pass --interval=<seconds> for the at-most-once gate (WS4)", async () => {
263
+ const root = await makeAgent("gita");
264
+ try {
265
+ runGenerator(root);
266
+ const dir = join(root, "scripts/local-triggers/plists");
267
+ // StartInterval cadence: --interval mirrors the interval seconds.
268
+ const inbox = readFileSync(join(dir, "ai.maestro.gita-inbox-processor.plist"), "utf-8");
269
+ assert.match(inbox, /<string>--interval=300<\/string>/);
270
+ // Calendar cadence (daily): carries a daily catch-up interval so an outage
271
+ // spanning the trigger time fast-forwards to exactly one catch-up tick.
272
+ const morning = readFileSync(join(dir, "ai.maestro.gita-daily-morning-brief.plist"), "utf-8");
273
+ assert.match(morning, /<string>--interval=86400<\/string>/);
274
+ // Still a StartCalendarInterval-driven plist (wall-clock trigger unchanged).
275
+ assert.match(morning, /<key>StartCalendarInterval<\/key>/);
276
+ } finally { await rmRoot(root); }
277
+ });
278
+
279
+ test("economics/scheduling cadences emit plists with the right schedule + enqueue wiring", async () => {
280
+ const root = await makeAgent("nadia");
281
+ try {
282
+ runGenerator(root);
283
+ const dir = join(root, "scripts/local-triggers/plists");
284
+ // nightly-cost-reconcile: calendar 03:30, daily catch-up, enqueue wiring.
285
+ const reconcile = readFileSync(join(dir, "ai.maestro.nadia-nightly-cost-reconcile.plist"), "utf-8");
286
+ assert.match(reconcile, /<key>StartCalendarInterval<\/key>/);
287
+ assert.match(reconcile, /<key>Hour<\/key>\s*<integer>3<\/integer>/);
288
+ assert.match(reconcile, /<key>Minute<\/key>\s*<integer>30<\/integer>/);
289
+ assert.match(reconcile, /<string>--interval=86400<\/string>/); // daily catch-up
290
+ assert.match(reconcile, /enqueue-cadence-tick\.mjs/);
291
+ assert.match(reconcile, /<string>nightly-cost-reconcile<\/string>/);
292
+ // fleet-cost-digest: calendar 07:00.
293
+ const digest = readFileSync(join(dir, "ai.maestro.nadia-fleet-cost-digest.plist"), "utf-8");
294
+ assert.match(digest, /<key>Hour<\/key>\s*<integer>7<\/integer>/);
295
+ // org-cost-sync: hourly StartInterval.
296
+ const sync = readFileSync(join(dir, "ai.maestro.nadia-org-cost-sync.plist"), "utf-8");
297
+ assert.match(sync, /<key>StartInterval<\/key>\s*<integer>3600<\/integer>/);
298
+ assert.match(sync, /<string>--interval=3600<\/string>/);
299
+ // dynamic-jobs: 60s StartInterval.
300
+ const jobs = readFileSync(join(dir, "ai.maestro.nadia-dynamic-jobs.plist"), "utf-8");
301
+ assert.match(jobs, /<key>StartInterval<\/key>\s*<integer>60<\/integer>/);
302
+ assert.match(jobs, /<string>--interval=60<\/string>/);
303
+ } finally { await rmRoot(root); }
304
+ });
305
+
306
+ test("daemon plist remains a KeepAlive job (not a cadence enqueue)", async () => {
307
+ const root = await makeAgent("erin");
308
+ try {
309
+ runGenerator(root);
310
+ const path = join(root, "scripts/local-triggers/plists/ai.maestro.erin-daemon.plist");
311
+ const body = readFileSync(path, "utf-8");
312
+ // KeepAlive switched 1.9.2 from plain `<true/>` to a dict with
313
+ // SuccessfulExit:false / Crashed:true so emergency-stop doesn't trigger
314
+ // a restart treadmill but real crashes still do.
315
+ assert.match(body, /<key>KeepAlive<\/key>/);
316
+ assert.match(body, /<key>SuccessfulExit<\/key>\s*<false\/>/);
317
+ assert.match(body, /<key>Crashed<\/key>\s*<true\/>/);
318
+ assert.match(body, /launchd-wrapper\.sh/);
319
+ assert.ok(!body.includes("enqueue-cadence-tick.mjs"),
320
+ "daemon plist should not enqueue ticks — it IS the consumer");
321
+ } finally { await rmRoot(root); }
322
+ });
323
+
324
+ test("generator reads firstName from agent.json when agent.ts is type-only (SOT layout)", async () => {
325
+ // Reproduce the SOT layout where agent.ts only declares interfaces
326
+ // (containing `firstName: string;` as a type, not a value) and the
327
+ // actual identity lives in agent.json. The legacy resolver matched the
328
+ // interface line and produced labels like
329
+ // `ai.maestro. firstname: string;-…` — guard against regression.
330
+ const root = join(
331
+ tmpdir(),
332
+ `plist-sot-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
333
+ );
334
+ await fsp.mkdir(root, { recursive: true });
335
+ // Manually wire the same fixture-builder used by other tests, except
336
+ // overwrite agent.ts to look like a type-only TypeScript file and add
337
+ // a real agent.json.
338
+ await fsp.mkdir(join(root, "config"), { recursive: true });
339
+ writeFileSync(
340
+ join(root, "config/agent.ts"),
341
+ `// Type declarations only — value lives in agent.json
342
+ export interface PrincipalConfig { firstName: string; }
343
+ export interface AgentConfig { firstName: string; }
344
+ `,
345
+ );
346
+ writeFileSync(
347
+ join(root, "config/agent.json"),
348
+ JSON.stringify({ firstName: "Sigrid", lastName: "Test" }) + "\n",
349
+ );
350
+ writeFileSync(join(root, "package.json"), '{"name":"t"}');
351
+
352
+ await fsp.mkdir(join(root, "scripts/local-triggers"), { recursive: true });
353
+ await fsp.mkdir(join(root, "scripts/daemon"), { recursive: true });
354
+ await fsp.mkdir(join(root, "scripts/cadence"), { recursive: true });
355
+ // Same set of helper scripts as makeAgent().
356
+ const { copyFileSync } = await import("node:fs");
357
+ copyFileSync(GENERATOR, join(root, "scripts/local-triggers/generate-plists.sh"));
358
+ copyFileSync(
359
+ join(MAESTRO_ROOT, "scripts/local-triggers/run-trigger.sh"),
360
+ join(root, "scripts/local-triggers/run-trigger.sh"),
361
+ );
362
+ copyFileSync(
363
+ join(MAESTRO_ROOT, "scripts/daemon/launchd-wrapper.sh"),
364
+ join(root, "scripts/daemon/launchd-wrapper.sh"),
365
+ );
366
+ copyFileSync(
367
+ join(MAESTRO_ROOT, "scripts/daemon/launchd-wrapper-generic.sh"),
368
+ join(root, "scripts/daemon/launchd-wrapper-generic.sh"),
369
+ );
370
+ copyFileSync(
371
+ join(MAESTRO_ROOT, "scripts/cadence/launchd-cadence-wrapper.sh"),
372
+ join(root, "scripts/cadence/launchd-cadence-wrapper.sh"),
373
+ );
374
+ copyFileSync(
375
+ join(MAESTRO_ROOT, "scripts/cadence/launchd-socket-mode-wrapper.sh"),
376
+ join(root, "scripts/cadence/launchd-socket-mode-wrapper.sh"),
377
+ );
378
+ copyFileSync(
379
+ join(MAESTRO_ROOT, "scripts/cadence/enqueue-cadence-tick.mjs"),
380
+ join(root, "scripts/cadence/enqueue-cadence-tick.mjs"),
381
+ );
382
+ await fsp.chmod(join(root, "scripts/local-triggers/generate-plists.sh"), 0o755);
383
+
384
+ try {
385
+ const r = runGenerator(root);
386
+ assert.equal(r.status, 0, r.stderr);
387
+ const plists = listPlists(root);
388
+ assert.ok(plists.length >= 1);
389
+ for (const p of plists) {
390
+ assert.match(p, /^ai\.maestro\.sigrid-/, `expected "sigrid" label, got: ${p}`);
391
+ assert.ok(!p.includes("string"),
392
+ `label leaked the TypeScript type: ${p}`);
393
+ }
394
+ } finally { await rmRoot(root); }
395
+ });
396
+
397
+ test("regeneration clears stale plists", async () => {
398
+ const root = await makeAgent("frank");
399
+ try {
400
+ // Plant a stale plist for a long-gone agent — intentionally using the legacy
401
+ // ai.adaptic.* namespace to confirm pre-rename plists are also cleared on regen.
402
+ const dir = join(root, "scripts/local-triggers/plists");
403
+ mkdirSync(dir, { recursive: true });
404
+ writeFileSync(join(dir, "ai.adaptic.OLD-AGENT-stale.plist"), "<plist/>");
405
+ runGenerator(root);
406
+ const remaining = listPlists(root);
407
+ assert.ok(!remaining.includes("ai.adaptic.OLD-AGENT-stale.plist"),
408
+ "generator must clear stale plists");
409
+ for (const p of remaining) {
410
+ assert.match(p, /^ai\.maestro\.frank-/);
411
+ }
412
+ } finally { await rmRoot(root); }
413
+ });
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+ # Install all local agent triggers as macOS launchd daemons
3
+ # Usage: ./scripts/local-triggers/install-all.sh
4
+ #
5
+ # This generates plist files from agent config and installs them.
6
+ # The generate-plists.sh script reads config/agent.ts to determine
7
+ # the agent name and generates properly configured plist files.
8
+
9
+ set -e
10
+
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ AGENT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
13
+ PLIST_DIR="$SCRIPT_DIR/plists"
14
+ GENERATOR="$SCRIPT_DIR/generate-plists.sh"
15
+ LAUNCH_AGENTS_DIR="$HOME/Library/LaunchAgents"
16
+
17
+ mkdir -p "$LAUNCH_AGENTS_DIR"
18
+
19
+ # Generate plists from agent config
20
+ if [ -x "$GENERATOR" ]; then
21
+ echo "Generating plist files from agent config..."
22
+ bash "$GENERATOR"
23
+ else
24
+ echo "Warning: generate-plists.sh not found — using existing plists"
25
+ fi
26
+
27
+ echo ""
28
+ echo "Installing local triggers..."
29
+
30
+ for plist in "$PLIST_DIR"/*.plist; do
31
+ [ -f "$plist" ] || continue
32
+ PLIST_NAME=$(basename "$plist")
33
+ LABEL=$(basename "$plist" .plist)
34
+ DST="$LAUNCH_AGENTS_DIR/$PLIST_NAME"
35
+
36
+ # Unload if already loaded
37
+ launchctl unload "$DST" 2>/dev/null || true
38
+
39
+ # Copy and load
40
+ cp "$plist" "$DST"
41
+ launchctl load "$DST"
42
+
43
+ echo " Installed: $LABEL"
44
+ done
45
+
46
+ echo ""
47
+ echo "All local triggers installed."
48
+ echo "Check status: launchctl list | grep -E 'maestro|adaptic'"
49
+ echo "Uninstall all: for f in ~/Library/LaunchAgents/ai.{maestro,adaptic}.*.plist; do launchctl unload \"\$f\" && rm \"\$f\"; done"
File without changes
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # Run a local scheduled trigger via Claude Code CLI (legacy / manual path).
3
+ #
4
+ # Usage: run-trigger.sh <trigger-name>
5
+ #
6
+ # Reads the prompt from schedules/triggers/<trigger-name>.md and runs it as
7
+ # a non-interactive `claude --print` session.
8
+ #
9
+ # ⚠ LEGACY PATH — DO NOT USE FROM LAUNCHD ⚠
10
+ #
11
+ # As of the cadence-bus architecture (maestro 1.8), scheduled cadence ticks
12
+ # go through scripts/cadence/enqueue-cadence-tick.mjs instead of running
13
+ # claude directly. The persistent maestro-daemon.mjs consumes events from
14
+ # state/cadence-bus/ and decides whether to handle them inline or escalate
15
+ # to a managed sub-session.
16
+ #
17
+ # This script remains available for two specific purposes:
18
+ # 1. Manual one-shot invocation by an operator who wants to run a single
19
+ # cadence prompt immediately, without waiting for the daemon.
20
+ # 2. Compatibility with very old launchd plists during migration. Doctor
21
+ # / upgrade will flag plists that still call this script and rewrite
22
+ # them through the cadence bus.
23
+ #
24
+ # Prefer instead:
25
+ # node scripts/cadence/enqueue-cadence-tick.mjs <trigger-name> --source=manual
26
+
27
+ set -e
28
+
29
+ TRIGGER_NAME="${1:?Trigger name required}"
30
+ AGENT_REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
31
+ PROMPT_FILE="$AGENT_REPO_DIR/schedules/triggers/$TRIGGER_NAME.md"
32
+ CLAUDE_BIN="${CLAUDE_BIN:-claude}"
33
+ LOG_DIR="$AGENT_REPO_DIR/logs/workflows"
34
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
35
+ DATE=$(date +%Y-%m-%d)
36
+ LOG_FILE="$LOG_DIR/$DATE-$TRIGGER_NAME.jsonl"
37
+
38
+ # Check emergency stop
39
+ if [ -f "$AGENT_REPO_DIR/.emergency-stop" ]; then
40
+ echo "{\"timestamp\":\"$TIMESTAMP\",\"trigger\":\"$TRIGGER_NAME\",\"status\":\"blocked\",\"reason\":\"emergency-stop\"}" >> "$LOG_FILE"
41
+ exit 0
42
+ fi
43
+
44
+ # Check prompt file exists
45
+ if [ ! -f "$PROMPT_FILE" ]; then
46
+ echo "ERROR: Prompt file not found: $PROMPT_FILE" >&2
47
+ exit 1
48
+ fi
49
+
50
+ # Read the prompt
51
+ PROMPT=$(cat "$PROMPT_FILE")
52
+
53
+ # Log trigger start
54
+ mkdir -p "$LOG_DIR"
55
+ echo "{\"timestamp\":\"$TIMESTAMP\",\"trigger\":\"$TRIGGER_NAME\",\"status\":\"started\"}" >> "$LOG_FILE"
56
+
57
+ # Run Claude Code in non-interactive mode
58
+ cd "$AGENT_REPO_DIR"
59
+ "$CLAUDE_BIN" --print --dangerously-skip-permissions "$PROMPT" >> "$LOG_DIR/$DATE-$TRIGGER_NAME.log" 2>&1
60
+
61
+ EXIT_CODE=$?
62
+ END_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
63
+ echo "{\"timestamp\":\"$END_TIMESTAMP\",\"trigger\":\"$TRIGGER_NAME\",\"status\":\"completed\",\"exit_code\":$EXIT_CODE}" >> "$LOG_FILE"
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- maestro-plist-arch: cadence-bus v1 -->
3
+ <!-- rag-reindex plist template — refresh the FTS5 index every hour so
4
+ newly-written memory / decisions / briefs are searchable promptly. -->
5
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
6
+ <plist version="1.0">
7
+ <dict>
8
+ <key>Label</key>
9
+ <string>ai.maestro.{{FIRSTNAME}}-rag-reindex</string>
10
+
11
+ <key>ProgramArguments</key>
12
+ <array>
13
+ <string>{{NODE_BIN}}</string>
14
+ <string>{{AGENT_ROOT}}/scripts/rag/build-index.mjs</string>
15
+ <string>--quiet</string>
16
+ </array>
17
+
18
+ <key>WorkingDirectory</key>
19
+ <string>{{AGENT_ROOT}}</string>
20
+
21
+ <!-- Every 60 minutes; FTS5 incremental updates are fast (<1s for
22
+ a few hundred files) so the cost is negligible. -->
23
+ <key>StartInterval</key>
24
+ <integer>3600</integer>
25
+
26
+ <key>RunAtLoad</key>
27
+ <true/>
28
+
29
+ <key>EnvironmentVariables</key>
30
+ <dict>
31
+ <key>PATH</key>
32
+ <string>/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
33
+ <key>HOME</key>
34
+ <string>{{HOME}}</string>
35
+ <key>USER</key>
36
+ <string>{{USER}}</string>
37
+ <key>AGENT_ROOT</key>
38
+ <string>{{AGENT_ROOT}}</string>
39
+ </dict>
40
+
41
+ <key>StandardOutPath</key>
42
+ <string>{{AGENT_ROOT}}/logs/rag/reindex-stdout.log</string>
43
+
44
+ <key>StandardErrorPath</key>
45
+ <string>{{AGENT_ROOT}}/logs/rag/reindex-stderr.log</string>
46
+ </dict>
47
+ </plist>
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- maestro-plist-arch: cadence-bus v1 -->
3
+ <!-- voice-relay-poller plist template — long-running daemon that polls
4
+ the Railway-hosted voice cloud-relay for buffered OpenAI
5
+ realtime.call.incoming events and forwards them to the local
6
+ voice-webhook-server on port 3200. -->
7
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
8
+ <plist version="1.0">
9
+ <dict>
10
+ <key>Label</key>
11
+ <string>ai.maestro.{{FIRSTNAME}}-voice-relay-poller</string>
12
+
13
+ <key>ProgramArguments</key>
14
+ <array>
15
+ <string>{{NODE_BIN}}</string>
16
+ <string>{{AGENT_ROOT}}/scripts/poller/voice-cloud-relay-client.mjs</string>
17
+ </array>
18
+
19
+ <key>WorkingDirectory</key>
20
+ <string>{{AGENT_ROOT}}</string>
21
+
22
+ <key>KeepAlive</key>
23
+ <dict>
24
+ <key>SuccessfulExit</key>
25
+ <false/>
26
+ <key>Crashed</key>
27
+ <true/>
28
+ </dict>
29
+
30
+ <key>RunAtLoad</key>
31
+ <true/>
32
+
33
+ <key>ThrottleInterval</key>
34
+ <integer>15</integer>
35
+
36
+ <key>EnvironmentVariables</key>
37
+ <dict>
38
+ <key>PATH</key>
39
+ <string>/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
40
+ <key>HOME</key>
41
+ <string>{{HOME}}</string>
42
+ <key>USER</key>
43
+ <string>{{USER}}</string>
44
+ <key>AGENT_ROOT</key>
45
+ <string>{{AGENT_ROOT}}</string>
46
+ </dict>
47
+
48
+ <key>StandardOutPath</key>
49
+ <string>{{AGENT_ROOT}}/logs/voice/relay-poller-stdout.log</string>
50
+
51
+ <key>StandardErrorPath</key>
52
+ <string>{{AGENT_ROOT}}/logs/voice/relay-poller-stderr.log</string>
53
+ </dict>
54
+ </plist>