@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,124 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * init-model-router.mjs — Idempotent init step for the model-router feature.
4
+ *
5
+ * Called by `maestro init` / `maestro upgrade` (via the feature-init
6
+ * tracker). Safe to run repeatedly.
7
+ *
8
+ * What it does (in order):
9
+ * 1. Confirms scaffold/config/model-routing.yaml.example is in the
10
+ * framework install.
11
+ * 2. If the agent already has config/model-routing.yaml, validates that
12
+ * it parses and points at known backends; otherwise copies the
13
+ * example file into place as `config/model-routing.yaml.disabled`
14
+ * (operator renames it once they've added their keys).
15
+ * 3. Patches .env.example with placeholder lines for MOONSHOT_API_KEY
16
+ * and OPENROUTER_API_KEY if they aren't there yet (idempotent).
17
+ * 4. Prints a short summary of detected backends and which env vars
18
+ * need to be filled in.
19
+ *
20
+ * The router itself is opt-in: a disabled file means "the framework is
21
+ * aware of routing, the operator has not yet chosen to switch on
22
+ * non-Anthropic backends". Existing daemon behaviour is preserved
23
+ * verbatim until the operator renames .disabled → .yaml.
24
+ */
25
+
26
+ import { dirname, join, resolve } from "node:path";
27
+ import { fileURLToPath } from "node:url";
28
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from "node:fs";
29
+
30
+ const __dirname = dirname(fileURLToPath(import.meta.url));
31
+ const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
32
+ const MAESTRO_ROOT = process.env.MAESTRO_ROOT || resolve(__dirname, "..", "..");
33
+
34
+ const ok = (m) => process.stdout.write(`[init-model-router] ✓ ${m}\n`);
35
+ const warn = (m) => process.stdout.write(`[init-model-router] ⚠ ${m}\n`);
36
+ const info = (m) => process.stdout.write(`[init-model-router] · ${m}\n`);
37
+
38
+ // ── Resolve scaffold example
39
+ const examplePath = join(MAESTRO_ROOT, "scaffold/config/model-routing.yaml.example");
40
+ const exampleAlt = join(MAESTRO_ROOT, "scaffold", "config", "model-routing.yaml.example");
41
+ const exampleSrc = existsSync(examplePath) ? examplePath : existsSync(exampleAlt) ? exampleAlt : null;
42
+ if (!exampleSrc) {
43
+ warn(`scaffold/config/model-routing.yaml.example not found in framework install at ${MAESTRO_ROOT}`);
44
+ warn("This feature requires maestro >= 1.12.0 — run `npm run upgrade` then retry.");
45
+ process.exit(1);
46
+ }
47
+
48
+ // ── Place the disabled config file (idempotent)
49
+ const cfgDir = join(AGENT_DIR, "config");
50
+ mkdirSync(cfgDir, { recursive: true });
51
+
52
+ const activePath = join(cfgDir, "model-routing.yaml");
53
+ const disabledPath = join(cfgDir, "model-routing.yaml.disabled");
54
+
55
+ if (existsSync(activePath)) {
56
+ // Active config already in place — try to parse + validate.
57
+ try {
58
+ const { loadRoutingConfig, listBackends } = await import(
59
+ pathToFileUrl(join(MAESTRO_ROOT, "lib/model-router.mjs"))
60
+ );
61
+ const cfg = loadRoutingConfig(AGENT_DIR);
62
+ if (!cfg) {
63
+ warn("config/model-routing.yaml exists but loader returned null");
64
+ } else {
65
+ const names = Object.keys(cfg.backends);
66
+ ok(`model-routing.yaml is active with backends: ${names.join(", ")}`);
67
+ reportMissingEnv(cfg);
68
+ }
69
+ } catch (err) {
70
+ warn(`failed to load existing model-routing.yaml: ${err.message}`);
71
+ }
72
+ } else if (existsSync(disabledPath)) {
73
+ info("model-routing.yaml.disabled is present; rename to model-routing.yaml to activate.");
74
+ } else {
75
+ copyFileSync(exampleSrc, disabledPath);
76
+ ok("placed scaffold/model-routing.yaml.example at config/model-routing.yaml.disabled");
77
+ info("Activate by:");
78
+ info(" 1. Edit config/model-routing.yaml.disabled to remove unused backends.");
79
+ info(" 2. Add MOONSHOT_API_KEY / OPENROUTER_API_KEY to .env as needed.");
80
+ info(" 3. Rename → config/model-routing.yaml");
81
+ info(" 4. Restart the daemon: launchctl unload + load the .plist");
82
+ }
83
+
84
+ // ── Patch .env.example with placeholder env var lines (idempotent)
85
+ const envExamplePath = join(AGENT_DIR, ".env.example");
86
+ if (existsSync(envExamplePath)) {
87
+ let envBody = readFileSync(envExamplePath, "utf-8");
88
+ let changed = false;
89
+ for (const [key, comment] of [
90
+ ["MOONSHOT_API_KEY", "Moonshot AI (Kimi K2.6) — https://platform.moonshot.ai/"],
91
+ ["OPENROUTER_API_KEY", "OpenRouter (Qwen3-Coder etc.) — https://openrouter.ai/keys"],
92
+ ]) {
93
+ if (!new RegExp(`^${key}=`, "m").test(envBody)) {
94
+ if (!envBody.endsWith("\n")) envBody += "\n";
95
+ envBody += `\n# ${comment}\n${key}=\n`;
96
+ changed = true;
97
+ }
98
+ }
99
+ if (changed) {
100
+ writeFileSync(envExamplePath, envBody);
101
+ ok("appended MOONSHOT_API_KEY / OPENROUTER_API_KEY placeholders to .env.example");
102
+ } else {
103
+ info(".env.example already has router env-var placeholders");
104
+ }
105
+ }
106
+
107
+ ok("done");
108
+
109
+ // ── Helpers ────────────────────────────────────────────────────────────────
110
+
111
+ function reportMissingEnv(cfg) {
112
+ for (const [name, b] of Object.entries(cfg.backends || {})) {
113
+ if (!b.auth_env) continue;
114
+ if (!process.env[b.auth_env]) {
115
+ warn(`backend "${name}" needs ${b.auth_env} but it's not set in your env`);
116
+ }
117
+ }
118
+ }
119
+
120
+ function pathToFileUrl(p) {
121
+ // Cross-platform absolute-path → file:// URL for dynamic import.
122
+ if (p.startsWith("/")) return "file://" + p;
123
+ return "file:///" + p.replace(/\\/g, "/");
124
+ }
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * init-rag.mjs — Bootstrap the local RAG index.
4
+ *
5
+ * (1) Auto-discovers candidate repos under ~/ and writes them to
6
+ * config/repo-registry.yaml. By default this is *not* auto-run because
7
+ * repo selection needs operator judgement; pass --yes to take all
8
+ * discovered candidates.
9
+ * (2) Installs ai.maestro.<firstname>-rag-reindex.plist so the FTS5 index
10
+ * refreshes hourly.
11
+ * (3) Optionally runs the initial index build (--build).
12
+ */
13
+ import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync, readFileSync } from "node:fs";
14
+ import { join, resolve, dirname } from "node:path";
15
+ import { homedir } from "node:os";
16
+ import { fileURLToPath } from "node:url";
17
+ import { execFileSync } from "node:child_process";
18
+
19
+ import { installPlist, bootInLaunchd } from "./lib/install-plist.mjs";
20
+
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
23
+
24
+ const ok = (m) => process.stdout.write(`[init-rag] ✓ ${m}\n`);
25
+ const warn = (m) => process.stdout.write(`[init-rag] ⚠ ${m}\n`);
26
+ const info = (m) => process.stdout.write(`[init-rag] · ${m}\n`);
27
+
28
+ const args = new Set(process.argv.slice(2));
29
+ const autoYes = args.has("--yes") || args.has("-y");
30
+ const skipPlists = args.has("--skip-plists");
31
+ const skipBoot = args.has("--skip-boot");
32
+ const runBuild = args.has("--build");
33
+
34
+ function loadFirstname() {
35
+ const agentJsonPath = join(AGENT_DIR, "config/agent.json");
36
+ if (existsSync(agentJsonPath)) {
37
+ try {
38
+ const j = JSON.parse(readFileSync(agentJsonPath, "utf-8"));
39
+ const n = j.firstName || j.fullName?.split(/\s+/)[0] || "";
40
+ return n.toLowerCase().replace(/[^a-z0-9]/g, "");
41
+ } catch { /* fall through */ }
42
+ }
43
+ return "agent";
44
+ }
45
+ const firstname = loadFirstname();
46
+
47
+ for (const d of ["state/rag", "state/rag/index", "scripts/rag"]) {
48
+ const full = join(AGENT_DIR, d);
49
+ if (!existsSync(full)) {
50
+ mkdirSync(full, { recursive: true });
51
+ ok(`created ${d}`);
52
+ }
53
+ }
54
+
55
+ // Discover candidate repos under $HOME.
56
+ function discoverRepos() {
57
+ const home = homedir();
58
+ const candidates = [];
59
+ for (const name of readdirSync(home)) {
60
+ if (name.startsWith(".") || name === "ravi-ai" || name === "Library" || name === "Applications") continue;
61
+ const full = join(home, name);
62
+ try {
63
+ const st = statSync(full);
64
+ if (!st.isDirectory()) continue;
65
+ // Heuristic: looks like a code repo (.git or package.json or pyproject.toml).
66
+ const isRepo =
67
+ existsSync(join(full, ".git")) ||
68
+ existsSync(join(full, "package.json")) ||
69
+ existsSync(join(full, "pyproject.toml")) ||
70
+ existsSync(join(full, "go.mod")) ||
71
+ existsSync(join(full, "Cargo.toml"));
72
+ if (isRepo) {
73
+ candidates.push({ name, path: full });
74
+ }
75
+ } catch { /* ignore */ }
76
+ }
77
+ return candidates;
78
+ }
79
+
80
+ const candidates = discoverRepos();
81
+ ok(`discovered ${candidates.length} candidate repo(s) under ${homedir()}`);
82
+
83
+ const registryPath = join(AGENT_DIR, "config/repo-registry.yaml");
84
+ let registry = { repositories: [] };
85
+ if (existsSync(registryPath)) {
86
+ // Crude YAML re-read: just check whether `repositories: []` is empty.
87
+ const body = readFileSync(registryPath, "utf-8");
88
+ if (/repositories:\s*\[\s*\]/.test(body) || /repositories:\s*$/m.test(body)) {
89
+ // empty list — overwrite with discovered set if user opted in.
90
+ } else {
91
+ ok("config/repo-registry.yaml already populated — leaving as-is");
92
+ process.exit(0);
93
+ }
94
+ }
95
+
96
+ if (!autoYes) {
97
+ warn("Not running interactively — to populate, run with --yes:");
98
+ warn(" node scripts/setup/init-rag.mjs --yes");
99
+ warn("Candidates that would be added:");
100
+ for (const c of candidates) warn(` - ${c.name} (${c.path})`);
101
+ process.exit(0);
102
+ }
103
+
104
+ // Build the YAML.
105
+ const lines = [
106
+ "# Source Repository Registry",
107
+ "# Populated by scripts/setup/init-rag.mjs. Add/remove entries as needed.",
108
+ "# Format:",
109
+ "# - name: repo-slug",
110
+ "# path: ~/repo-slug",
111
+ "# purpose: what this repo contains",
112
+ "# index: true | false (indexed by state/rag/)",
113
+ "",
114
+ "repositories:",
115
+ ];
116
+ for (const c of candidates) {
117
+ lines.push(` - name: ${c.name}`);
118
+ lines.push(` path: ${c.path}`);
119
+ lines.push(` purpose: ""`);
120
+ lines.push(` index: true`);
121
+ }
122
+ writeFileSync(registryPath, lines.join("\n") + "\n");
123
+ ok(`wrote ${candidates.length} entries to config/repo-registry.yaml`);
124
+
125
+ // ── Install rag-reindex plist (hourly FTS5 refresh) ────────────────────────
126
+ if (skipPlists) {
127
+ info("--skip-plists set — leaving ~/Library/LaunchAgents/ untouched");
128
+ } else {
129
+ const templatePath = join(AGENT_DIR, "scripts/local-triggers/templates/rag-reindex.plist.template");
130
+ if (!existsSync(templatePath)) {
131
+ warn(`template not found: ${templatePath} — skipping rag-reindex plist`);
132
+ } else {
133
+ try {
134
+ const { installedPath, changed, label } = installPlist({
135
+ templatePath,
136
+ firstname,
137
+ agentRoot: AGENT_DIR,
138
+ label: "rag-reindex",
139
+ });
140
+ ok(`${changed ? "installed" : "no-op (up-to-date)"} ${label} → ${installedPath}`);
141
+ if (!skipBoot && changed) {
142
+ try {
143
+ bootInLaunchd(installedPath);
144
+ ok(`booted ${label}`);
145
+ } catch (err) {
146
+ warn(`bootstrap failed: ${err.message}`);
147
+ }
148
+ }
149
+ } catch (err) {
150
+ warn(`failed to install rag-reindex plist: ${err.message}`);
151
+ }
152
+ }
153
+ }
154
+
155
+ // ── Optional initial index build ───────────────────────────────────────────
156
+ if (runBuild) {
157
+ const indexer = join(AGENT_DIR, "scripts/rag/build-index.mjs");
158
+ if (existsSync(indexer)) {
159
+ info("running initial RAG index build (this may take a minute)…");
160
+ try {
161
+ execFileSync(process.argv[0], [indexer, "--quiet"], { stdio: "inherit" });
162
+ ok("initial RAG index built");
163
+ } catch (err) {
164
+ warn(`initial index build failed: ${err.message}`);
165
+ warn(" retry manually: node scripts/rag/build-index.mjs");
166
+ }
167
+ } else {
168
+ warn(`indexer not present at ${indexer}`);
169
+ }
170
+ }
171
+
172
+ ok("done");
173
+ info("Next: ensure OPENAI_API_KEY is set in .env (used for text-embedding-3-small).");
174
+ info("Manual reindex any time: node scripts/rag/build-index.mjs");
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * init-session-router.mjs — Opt-in session router enablement.
4
+ *
5
+ * Session router enables LRU reuse of long-running Claude sessions for
6
+ * conversational items (Slack threads, Gmail threads). Requires
7
+ * SESSION_ROUTER_ENABLED=1 in .env. This init step appends that line if
8
+ * absent, but is intentionally `auto: false` in the registry so the
9
+ * operator confirms the decision.
10
+ */
11
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
12
+ import { join, resolve, dirname } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
17
+
18
+ const ok = (m) => process.stdout.write(`[init-session-router] ✓ ${m}\n`);
19
+ const warn = (m) => process.stdout.write(`[init-session-router] ⚠ ${m}\n`);
20
+
21
+ const envFile = join(AGENT_DIR, ".env");
22
+ if (!existsSync(envFile)) {
23
+ warn(".env not present — create it first (copy .env.example).");
24
+ process.exit(0);
25
+ }
26
+
27
+ const body = readFileSync(envFile, "utf-8");
28
+ if (/^SESSION_ROUTER_ENABLED=/m.test(body)) {
29
+ ok("SESSION_ROUTER_ENABLED already configured");
30
+ } else {
31
+ const updated = body.replace(/\n*$/, "") + `\n\n# Session router (LRU reuse) — disabled by default. Set to 1 to enable.\nSESSION_ROUTER_ENABLED=1\n`;
32
+ writeFileSync(envFile, updated);
33
+ ok("appended SESSION_ROUTER_ENABLED=1 to .env");
34
+ }
35
+
36
+ // Touch the registry dir.
37
+ mkdirSync(join(AGENT_DIR, "state/sessions"), { recursive: true });
38
+ ok("done");
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * init-slack-socket-mode.mjs — Interactive init for the Slack Socket Mode
4
+ * feature.
5
+ *
6
+ * Called by `maestro init slack-socket-mode --apply`. Walks the operator
7
+ * through enabling Socket Mode on the Slack app, generating an app-level
8
+ * token with the `connections:write` scope, and dropping it into .env.
9
+ * Then ensures the launchd plist exists + loads it.
10
+ *
11
+ * Safe to run repeatedly — every step is idempotent and the script never
12
+ * overwrites an existing token. If the operator already configured the
13
+ * feature, the script confirms each piece is in place and exits 0.
14
+ */
15
+ import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from "node:fs";
16
+ import { join, dirname, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { spawnSync } from "node:child_process";
19
+ import { createInterface } from "node:readline/promises";
20
+
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
23
+
24
+ const ok = (m) => process.stdout.write(`[init-slack-socket-mode] ✓ ${m}\n`);
25
+ const warn = (m) => process.stdout.write(`[init-slack-socket-mode] ⚠ ${m}\n`);
26
+ const info = (m) => process.stdout.write(`[init-slack-socket-mode] ${m}\n`);
27
+ const fail = (m) => process.stderr.write(`[init-slack-socket-mode] ✗ ${m}\n`);
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Step 1 — Print the Slack admin walkthrough
31
+ // ---------------------------------------------------------------------------
32
+
33
+ function printWalkthrough() {
34
+ process.stdout.write(`
35
+ ================================================================================
36
+ Slack Socket Mode Setup — 3 steps in the Slack admin UI
37
+ ================================================================================
38
+
39
+ This feature gives the agent a persistent WebSocket to Slack so DMs and
40
+ @mentions arrive in real time instead of being polled every 60 seconds.
41
+ You need a Slack app with Socket Mode enabled and an app-level token.
42
+
43
+ Step 1 — Create or open the agent's Slack app
44
+ Open https://api.slack.com/apps
45
+ If you already have an app for this agent's bot, click into it.
46
+ Otherwise: "Create New App" → "From scratch" → pick a workspace.
47
+
48
+ Step 2 — Enable Socket Mode + Event Subscriptions
49
+ In the left sidebar:
50
+ a. "Socket Mode" → toggle ON
51
+ When prompted, generate an App-Level Token. Give it a name
52
+ (e.g. "maestro-socket") and add the connections:write scope.
53
+ Copy the token (xapp-1-…) somewhere safe — you'll paste it
54
+ below in step 3.
55
+ b. "Event Subscriptions" → toggle ON
56
+ Subscribe to BOT events:
57
+ - message.channels
58
+ - message.groups
59
+ - message.im
60
+ - message.mpim
61
+ - app_mention
62
+ Reinstall the app to your workspace when prompted.
63
+
64
+ Step 3 — Add the app-level token to .env
65
+ Paste it on the prompt below, or skip and add it manually as:
66
+ SLACK_APP_LEVEL_TOKEN=xapp-1-…
67
+ in ${join(AGENT_DIR, ".env")}.
68
+
69
+ ================================================================================
70
+ `);
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Step 2 — Check .env for SLACK_APP_LEVEL_TOKEN and offer to add it
75
+ // ---------------------------------------------------------------------------
76
+
77
+ /**
78
+ * Parse `.env` into a plain object. Best-effort — no fancy quoting. Used
79
+ * only to detect whether the token line is present.
80
+ */
81
+ function readEnv(envPath) {
82
+ if (!existsSync(envPath)) return {};
83
+ const map = {};
84
+ for (const line of readFileSync(envPath, "utf-8").split("\n")) {
85
+ const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
86
+ if (m) map[m[1]] = m[2].trim().replace(/^["']|["']$/g, "");
87
+ }
88
+ return map;
89
+ }
90
+
91
+ /**
92
+ * Append a single `KEY=VALUE` line to .env. Does NOT rewrite existing keys
93
+ * — the operator should hand-edit if they need to change a value.
94
+ */
95
+ function appendEnvLine(envPath, key, value) {
96
+ if (!existsSync(envPath)) {
97
+ writeFileSync(envPath, `${key}=${value}\n`);
98
+ return;
99
+ }
100
+ const body = readFileSync(envPath, "utf-8");
101
+ const suffix = body.endsWith("\n") ? "" : "\n";
102
+ appendFileSync(envPath, `${suffix}${key}=${value}\n`);
103
+ }
104
+
105
+ async function promptForToken() {
106
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
107
+ try {
108
+ const answer = await rl.question("Paste your SLACK_APP_LEVEL_TOKEN (xapp-1-…), or press ENTER to skip: ");
109
+ return answer.trim();
110
+ } finally {
111
+ rl.close();
112
+ }
113
+ }
114
+
115
+ async function ensureTokenInEnv() {
116
+ const envPath = join(AGENT_DIR, ".env");
117
+ const env = readEnv(envPath);
118
+ const existing = env.SLACK_APP_LEVEL_TOKEN || "";
119
+ if (existing.startsWith("xapp-")) {
120
+ ok("SLACK_APP_LEVEL_TOKEN already set in .env");
121
+ return true;
122
+ }
123
+
124
+ // Skip the prompt when running in a non-interactive environment (CI,
125
+ // upgrade in --apply mode, etc). The operator can re-run interactively
126
+ // later or hand-edit .env.
127
+ if (!process.stdin.isTTY) {
128
+ warn("SLACK_APP_LEVEL_TOKEN missing and stdin is non-interactive — skipping prompt.");
129
+ info(`Add the token manually to ${envPath}:`);
130
+ info(" SLACK_APP_LEVEL_TOKEN=xapp-1-…");
131
+ return false;
132
+ }
133
+
134
+ const token = await promptForToken();
135
+ if (!token) {
136
+ warn("No token provided — skipping. Add it manually before launchd-loading the plist.");
137
+ info(` echo 'SLACK_APP_LEVEL_TOKEN=xapp-1-…' >> ${envPath}`);
138
+ return false;
139
+ }
140
+ if (!token.startsWith("xapp-")) {
141
+ fail(`Token must start with 'xapp-' — got '${token.slice(0, 8)}…'. Skipping.`);
142
+ return false;
143
+ }
144
+ appendEnvLine(envPath, "SLACK_APP_LEVEL_TOKEN", token);
145
+ ok(`SLACK_APP_LEVEL_TOKEN appended to ${envPath}`);
146
+ return true;
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Step 3 — Ensure the launchd plist exists, then load it
151
+ // ---------------------------------------------------------------------------
152
+
153
+ /**
154
+ * Derive the agent's launchd label prefix from config/agent.json or fall
155
+ * back to the directory name. Mirrors the resolution in
156
+ * scripts/local-triggers/generate-plists.sh.
157
+ */
158
+ function resolveAgentFirstName() {
159
+ try {
160
+ const a = JSON.parse(readFileSync(join(AGENT_DIR, "config/agent.json"), "utf-8"));
161
+ if (a.firstName && typeof a.firstName === "string") {
162
+ return a.firstName.toLowerCase();
163
+ }
164
+ } catch { /* try fallback */ }
165
+ return AGENT_DIR.split("/").pop().replace(/-ai$/, "").toLowerCase();
166
+ }
167
+
168
+ function regenPlistsIfNeeded(firstName) {
169
+ const plistDir = join(AGENT_DIR, "scripts/local-triggers/plists");
170
+ const expected = join(plistDir, `ai.maestro.${firstName}-slack-socket.plist`);
171
+ if (existsSync(expected)) {
172
+ ok(`plist already generated: ${expected}`);
173
+ return expected;
174
+ }
175
+ // Run the generator. It's idempotent and lives in the agent repo.
176
+ const generator = join(AGENT_DIR, "scripts/local-triggers/generate-plists.sh");
177
+ if (!existsSync(generator)) {
178
+ warn(`generator missing at ${generator} — cannot create plist`);
179
+ return null;
180
+ }
181
+ info(`generating plists via ${generator}`);
182
+ const r = spawnSync("/bin/bash", [generator], { cwd: AGENT_DIR, encoding: "utf-8" });
183
+ if (r.status !== 0) {
184
+ fail(`generator failed (exit ${r.status}): ${(r.stderr || "").trim()}`);
185
+ return null;
186
+ }
187
+ if (existsSync(expected)) {
188
+ ok(`plist generated: ${expected}`);
189
+ return expected;
190
+ }
191
+ warn(`generator ran but ${expected} not found. Re-check generate-plists.sh.`);
192
+ return null;
193
+ }
194
+
195
+ /**
196
+ * Copy the generated plist into ~/Library/LaunchAgents/ and launchctl-load
197
+ * it. Idempotent: if already loaded, unload-then-load to pick up changes.
198
+ */
199
+ function loadPlist(plistPath, label) {
200
+ const home = process.env.HOME || "";
201
+ if (!home) {
202
+ warn("HOME not set — cannot install plist");
203
+ return false;
204
+ }
205
+ const installedDir = join(home, "Library/LaunchAgents");
206
+ mkdirSync(installedDir, { recursive: true });
207
+ const installed = join(installedDir, `${label}.plist`);
208
+
209
+ // Copy (preserve atomicity by writing-then-renaming).
210
+ try {
211
+ const body = readFileSync(plistPath, "utf-8");
212
+ writeFileSync(installed + ".tmp", body);
213
+ // Use rename to make the install atomic.
214
+ spawnSync("/bin/mv", [installed + ".tmp", installed], { encoding: "utf-8" });
215
+ ok(`copied to ${installed}`);
216
+ } catch (err) {
217
+ fail(`could not install plist: ${err.message}`);
218
+ return false;
219
+ }
220
+
221
+ // Unload any existing instance, then load the fresh one.
222
+ spawnSync("launchctl", ["unload", installed], { encoding: "utf-8" });
223
+ const loadRes = spawnSync("launchctl", ["load", installed], { encoding: "utf-8" });
224
+ if (loadRes.status !== 0) {
225
+ warn(`launchctl load returned ${loadRes.status}: ${(loadRes.stderr || "").trim()}`);
226
+ info("You can retry manually: launchctl load " + installed);
227
+ return false;
228
+ }
229
+ ok(`launchctl loaded ${label}`);
230
+ return true;
231
+ }
232
+
233
+ // ---------------------------------------------------------------------------
234
+ // Main
235
+ // ---------------------------------------------------------------------------
236
+
237
+ async function main() {
238
+ printWalkthrough();
239
+ const tokenOk = await ensureTokenInEnv();
240
+
241
+ const firstName = resolveAgentFirstName();
242
+ const label = `ai.maestro.${firstName}-slack-socket`;
243
+ const plistPath = regenPlistsIfNeeded(firstName);
244
+
245
+ if (plistPath && tokenOk) {
246
+ loadPlist(plistPath, label);
247
+ } else if (plistPath && !tokenOk) {
248
+ info("Skipping launchctl load — add SLACK_APP_LEVEL_TOKEN to .env first, then run:");
249
+ info(` launchctl load ~/Library/LaunchAgents/${label}.plist`);
250
+ }
251
+
252
+ ok("init-slack-socket-mode complete");
253
+ info("Verify with: maestro doctor (checks token + plist + recent connect log)");
254
+ }
255
+
256
+ main().catch((err) => {
257
+ fail(`unexpected error: ${err.message}`);
258
+ process.stderr.write(`${err.stack}\n`);
259
+ process.exit(1);
260
+ });