@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,370 @@
1
+ /**
2
+ * Maestro — Voice tool bridge
3
+ *
4
+ * Converts maestro's existing action handlers (defined in
5
+ * lib/tool-definitions.js + executed via lib/action-executor.js) into
6
+ * the function-tool format OpenAI Realtime expects, and wires the
7
+ * provider's tool.call events back through the same action executor and
8
+ * action-classification policy used by the Slack / Gmail surfaces.
9
+ *
10
+ * Why this matters:
11
+ * - The voice channel must NOT bypass the approval policy that protects
12
+ * the Slack / Gmail surfaces. A user saying "wire fifty thousand to
13
+ * this account" should require the same verbal-confirmation gate that
14
+ * a Slack-typed equivalent would, not silently fire the transfer.
15
+ * - We surface that gate by tagging high-risk actions in the Realtime
16
+ * tool description and (optionally) by inserting a pre-execution
17
+ * verbal-confirm step that asks the model to read back the action
18
+ * before invoking it.
19
+ *
20
+ * Public API:
21
+ * actionsToRealtimeTools(opts) → array of Realtime function tool defs
22
+ * registerToolBridge(provider, opts) → attach handler to provider events
23
+ */
24
+
25
+ import { readFileSync, existsSync } from "node:fs";
26
+ import { createRequire } from "node:module";
27
+ import { redactSensitiveUrl, isSensitiveParamName, REDACTED } from "../security/redact.mjs";
28
+
29
+ // js-yaml is a declared maestro dependency, but action policies are usually
30
+ // authored as JSON, so we keep YAML loading optional. createRequire gives us a
31
+ // working `require` inside this ESM module — a bare `require("js-yaml")` here is
32
+ // a ReferenceError under "type":"module", which previously got swallowed and
33
+ // silently disabled the verbal-confirm gate for YAML policies.
34
+ const require = createRequire(import.meta.url);
35
+ import { join, resolve } from "node:path";
36
+
37
+ // We dynamically import the action-executor only on first invocation
38
+ // to avoid circular import order issues during module load.
39
+ let _toolDefs = null;
40
+ let _executor = null;
41
+
42
+ async function loadMaestroBindings() {
43
+ if (_toolDefs && _executor) return { _toolDefs, _executor };
44
+ try {
45
+ const td = await import("../tool-definitions.js");
46
+ const ae = await import("../action-executor.js");
47
+ _toolDefs = td;
48
+ _executor = ae;
49
+ return { _toolDefs, _executor };
50
+ } catch (err) {
51
+ throw new Error(`tool-bridge: failed to load maestro bindings: ${err.message}`);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Load the action-classification policy (YAML or JSON) so we know which
57
+ * actions are low/medium/high risk and how each should be gated.
58
+ *
59
+ * Returns a normalised map: { actionName: { risk, approval, ... } }
60
+ */
61
+ export function loadActionClassification(agentRoot, opts = {}) {
62
+ const root = resolve(
63
+ agentRoot || opts.agentRoot || process.env.AGENT_ROOT || process.env.AGENT_DIR || process.cwd()
64
+ );
65
+ // Try JSON first (no js-yaml dependency), then YAML.
66
+ const candidates = [
67
+ join(root, "policies/action-classification.json"),
68
+ join(root, "policies/action-classification.yaml"),
69
+ ];
70
+ for (const path of candidates) {
71
+ if (!existsSync(path)) continue;
72
+ const raw = readFileSync(path, "utf-8");
73
+ if (path.endsWith(".json")) return normaliseClassification(JSON.parse(raw));
74
+ // YAML policy file. createRequire makes this resolve correctly when
75
+ // js-yaml is installed; if it genuinely is not, we fall back to {} rather
76
+ // than crashing — but we log it so a misconfigured policy is visible
77
+ // instead of silently disabling the gate.
78
+ try {
79
+ const yaml = require("js-yaml");
80
+ return normaliseClassification(yaml.load(raw));
81
+ } catch (err) {
82
+ console.error(
83
+ `[tool-bridge] Could not load YAML action policy at ${path} ` +
84
+ `(${err.message}); action-classification gate is INACTIVE for this session.`
85
+ );
86
+ return {};
87
+ }
88
+ }
89
+ return {};
90
+ }
91
+
92
+ function normaliseClassification(raw) {
93
+ if (!raw || typeof raw !== "object") return {};
94
+ const out = {};
95
+ // Two shapes we accept:
96
+ // { actions: { send_slack_message: { risk: "high", ... } } }
97
+ // { send_slack_message: { risk: "high", ... } }
98
+ const actions = raw.actions || raw;
99
+ for (const [name, def] of Object.entries(actions)) {
100
+ if (!def || typeof def !== "object") continue;
101
+ out[name] = {
102
+ risk: def.risk || def.level || "low",
103
+ approval: def.approval || def.gate || "none",
104
+ verbal_confirm: def.verbal_confirm ?? (def.risk === "high"),
105
+ notes: def.notes || "",
106
+ };
107
+ }
108
+ return out;
109
+ }
110
+
111
+ /**
112
+ * Build the array of function tools for the Realtime session. By default
113
+ * exposes every "communication"-tier maestro tool (send-slack, send-email,
114
+ * send-whatsapp, etc.) plus the "low-risk" research tools.
115
+ *
116
+ * @param {object} opts
117
+ * @param {string[]} [opts.include] Specific tool names to include
118
+ * @param {string[]} [opts.exclude] Names to exclude
119
+ * @param {string} [opts.accessLevel] "voice" (default), "full"
120
+ * @param {object} [opts.classification] action-classification map
121
+ * @returns {Promise<Array<RealtimeTool>>}
122
+ */
123
+ export async function actionsToRealtimeTools(opts = {}) {
124
+ const { _toolDefs } = await loadMaestroBindings();
125
+ const classification = opts.classification || loadActionClassification(opts.agentRoot);
126
+ const accessLevel = opts.accessLevel || "voice";
127
+ let sourceTools;
128
+ if (typeof _toolDefs.getToolsForAccessLevel === "function") {
129
+ // The framework already exposes this — use it so the voice surface
130
+ // automatically picks up new tools added to the registry.
131
+ sourceTools = _toolDefs.getToolsForAccessLevel(accessLevel);
132
+ } else if (Array.isArray(_toolDefs.ALL_TOOLS)) {
133
+ sourceTools = _toolDefs.ALL_TOOLS;
134
+ } else {
135
+ sourceTools = [];
136
+ }
137
+
138
+ const include = new Set(opts.include || []);
139
+ const exclude = new Set(opts.exclude || []);
140
+
141
+ const out = [];
142
+ for (const t of sourceTools) {
143
+ const name = t.name || t.toolName;
144
+ if (!name) continue;
145
+ if (include.size && !include.has(name)) continue;
146
+ if (exclude.has(name)) continue;
147
+ const risk = classification[name]?.risk || "low";
148
+ const verbalConfirm = classification[name]?.verbal_confirm ?? (risk === "high");
149
+ const baseDesc = t.description || `Maestro action: ${name}`;
150
+ const description = verbalConfirm
151
+ ? `${baseDesc}\n\n⚠ HIGH-RISK action — before calling this tool you MUST verbally read back the parameters (recipient, amount, key fields) and obtain explicit user confirmation in the SAME turn. Do not call this tool on the first turn it is mentioned.`
152
+ : baseDesc;
153
+
154
+ out.push({
155
+ type: "function",
156
+ name,
157
+ description,
158
+ parameters: toolParameters(t),
159
+ });
160
+ }
161
+ return out;
162
+ }
163
+
164
+ function toolParameters(t) {
165
+ // We accept either: t.parameters (already JSON Schema) OR t.input_schema
166
+ // (Anthropic-style). Both pass through unchanged; the OpenAI Realtime
167
+ // function format wants JSON Schema in `parameters`.
168
+ if (t.parameters && typeof t.parameters === "object") return t.parameters;
169
+ if (t.input_schema && typeof t.input_schema === "object") return t.input_schema;
170
+ if (t.inputSchema && typeof t.inputSchema === "object") return t.inputSchema;
171
+ return { type: "object", properties: {}, additionalProperties: true };
172
+ }
173
+
174
+ // ── Audit redaction (L11) ─────────────────────────────────────────────────
175
+ // The audit hook receives raw tool arguments and results, which on the voice
176
+ // surface routinely contain PII and message bodies (recipients, amounts, email
177
+ // text, etc.). Callers that ship audit entries to a shared sink can opt in to
178
+ // redaction so secrets/PII don't leak into logs. Default behaviour is unchanged
179
+ // (no redaction) — you must pass opts.redact, opts.auditAllowlist, or
180
+ // opts.redactAudit to enable any of this.
181
+
182
+ const DEFAULT_TRUNCATE_LEN = 256;
183
+
184
+ /**
185
+ * Deep-redact a JSON-ish value for audit logging:
186
+ * - values of object keys whose NAME looks sensitive (token/secret/password/
187
+ * auth/… per lib/security/redact.mjs) are replaced with REDACTED ("***")
188
+ * - string values are passed through redactSensitiveUrl (strips embedded
189
+ * credentials + masks sensitive query params) and truncated to maxLen
190
+ * - arrays/objects are walked recursively (bounded depth, cycle-safe)
191
+ *
192
+ * Pure; never throws.
193
+ *
194
+ * @param {*} value
195
+ * @param {{ maxLen?: number, allowlist?: Set<string>|null, depth?: number,
196
+ * seen?: WeakSet<object> }} [opts]
197
+ * @returns {*}
198
+ */
199
+ export function redactAuditValue(value, opts = {}) {
200
+ const maxLen = opts.maxLen ?? DEFAULT_TRUNCATE_LEN;
201
+ const allowlist = opts.allowlist || null;
202
+ const depth = opts.depth ?? 0;
203
+ const seen = opts.seen || new WeakSet();
204
+
205
+ if (value == null) return value;
206
+ if (typeof value === "string") {
207
+ let out = redactSensitiveUrl(value);
208
+ if (maxLen > 0 && out.length > maxLen) out = out.slice(0, maxLen) + "…";
209
+ return out;
210
+ }
211
+ if (typeof value === "number" || typeof value === "boolean") return value;
212
+ if (typeof value !== "object") return REDACTED; // function/symbol/bigint → mask
213
+ if (depth >= 6) return REDACTED; // bound recursion
214
+ if (seen.has(value)) return REDACTED; // cycle guard
215
+ seen.add(value);
216
+
217
+ if (Array.isArray(value)) {
218
+ return value.map((v) =>
219
+ redactAuditValue(v, { maxLen, allowlist, depth: depth + 1, seen })
220
+ );
221
+ }
222
+
223
+ const out = {};
224
+ for (const [k, v] of Object.entries(value)) {
225
+ // Field allowlist: if provided, only top-level keys (depth 0) on the list
226
+ // survive; the rest are dropped entirely.
227
+ if (allowlist && depth === 0 && !allowlist.has(k)) continue;
228
+ if (isSensitiveParamName(k)) {
229
+ out[k] = REDACTED;
230
+ continue;
231
+ }
232
+ out[k] = redactAuditValue(v, { maxLen, allowlist, depth: depth + 1, seen });
233
+ }
234
+ return out;
235
+ }
236
+
237
+ /**
238
+ * Build the redactor applied to each audit entry's args/result, from
239
+ * registerToolBridge opts. Returns null when no redaction was requested (so the
240
+ * default no-op path stays allocation-free).
241
+ *
242
+ * @param {object} opts
243
+ * @returns {((entry:object)=>object)|null}
244
+ */
245
+ function buildAuditRedactor(opts) {
246
+ // Fully-custom redactor wins.
247
+ if (typeof opts.redact === "function") return opts.redact;
248
+
249
+ const wantAllowlist = Array.isArray(opts.auditAllowlist);
250
+ const wantRedact = opts.redactAudit === true || wantAllowlist;
251
+ if (!wantRedact) return null;
252
+
253
+ const allowlist = wantAllowlist ? new Set(opts.auditAllowlist) : null;
254
+ const maxLen = typeof opts.auditMaxLen === "number" ? opts.auditMaxLen : DEFAULT_TRUNCATE_LEN;
255
+ return (entry) => {
256
+ const next = { ...entry };
257
+ if ("args" in next) next.args = redactAuditValue(next.args, { allowlist, maxLen });
258
+ if ("result" in next) next.result = redactAuditValue(next.result, { allowlist, maxLen });
259
+ return next;
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Attach a tool-call handler to a voice provider. When the model emits a
265
+ * tool.call event, we look up the action in maestro's executor, run it,
266
+ * and feed the result back into the conversation via
267
+ * provider.sendToolResult().
268
+ *
269
+ * Returns a teardown fn that removes the listeners.
270
+ *
271
+ * @param {VoiceProvider} provider
272
+ * @param {object} opts
273
+ * @param {(name:string,args:object)=>Promise<object>} [opts.executor]
274
+ * Override the default executor (useful for tests).
275
+ * @param {Array<string>} [opts.allow] Allow-list of tool names; others
276
+ * are refused without invocation.
277
+ * @param {object} [opts.classification] action-classification map
278
+ * @param {(entry:object)=>void} [opts.audit] Hook called for each tool
279
+ * call with {name, args, result, error, started_at, finished_at}.
280
+ * @param {(entry:object)=>object} [opts.redact] Optional redactor applied to
281
+ * the audit entry BEFORE it reaches opts.audit. Receives the full entry,
282
+ * returns the (redacted) entry to log. Use this for full control.
283
+ * @param {boolean} [opts.redactAudit] Convenience flag: when true, apply the
284
+ * built-in deep redactor to entry.args/entry.result — masks sensitive
285
+ * field values, strips URL credentials, and truncates long strings.
286
+ * @param {string[]} [opts.auditAllowlist] Convenience: keep only these
287
+ * top-level arg/result fields in the audit entry (implies redactAudit).
288
+ * @param {number} [opts.auditMaxLen] Max length for redacted strings
289
+ * (default 256). Only used by the built-in redactor.
290
+ *
291
+ * Default behaviour is unchanged: with none of the redact options set, raw
292
+ * args/results reach the audit sink exactly as before.
293
+ */
294
+ export function registerToolBridge(provider, opts = {}) {
295
+ const allow = opts.allow ? new Set(opts.allow) : null;
296
+ const classification = opts.classification || {};
297
+ const rawAudit = typeof opts.audit === "function" ? opts.audit : () => {};
298
+ const redactor = buildAuditRedactor(opts);
299
+ // Single choke point so every audit site goes through the redactor (if any).
300
+ // Redaction must never break auditing, so failures fall back to the raw entry.
301
+ const audit = redactor
302
+ ? (entry) => {
303
+ let safe = entry;
304
+ try {
305
+ safe = redactor(entry);
306
+ } catch {
307
+ safe = entry;
308
+ }
309
+ rawAudit(safe);
310
+ }
311
+ : rawAudit;
312
+
313
+ const handler = async (evt) => {
314
+ const { call_id, name, arguments: args } = evt;
315
+ const startedAt = new Date().toISOString();
316
+
317
+ if (!call_id || !name) {
318
+ audit({ name, args, error: "missing_call_id_or_name", started_at: startedAt, finished_at: new Date().toISOString() });
319
+ return;
320
+ }
321
+ if (allow && !allow.has(name)) {
322
+ provider.sendToolResult(call_id, {
323
+ ok: false,
324
+ error: "tool_not_allowed",
325
+ message: `Tool "${name}" is not in the voice-session allow-list. The agent must invoke a different tool or escalate to a human.`,
326
+ });
327
+ audit({ name, args, error: "tool_not_allowed", started_at: startedAt, finished_at: new Date().toISOString() });
328
+ return;
329
+ }
330
+
331
+ let result;
332
+ let error = null;
333
+ try {
334
+ if (opts.executor) {
335
+ result = await opts.executor(name, args || {});
336
+ } else {
337
+ const { _executor } = await loadMaestroBindings();
338
+ const fn = _executor.executeAction || _executor.default;
339
+ if (typeof fn !== "function") {
340
+ throw new Error("maestro action-executor is missing executeAction()");
341
+ }
342
+ result = await fn(name, args || {});
343
+ }
344
+ } catch (err) {
345
+ error = err.message || String(err);
346
+ result = { ok: false, error };
347
+ }
348
+
349
+ provider.sendToolResult(call_id, result);
350
+ audit({
351
+ name,
352
+ args,
353
+ result,
354
+ error,
355
+ risk: classification[name]?.risk || "low",
356
+ started_at: startedAt,
357
+ finished_at: new Date().toISOString(),
358
+ });
359
+ };
360
+
361
+ provider.on("tool.call", handler);
362
+ return () => provider.off("tool.call", handler);
363
+ }
364
+
365
+ export default {
366
+ actionsToRealtimeTools,
367
+ registerToolBridge,
368
+ loadActionClassification,
369
+ redactAuditValue,
370
+ };
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Maestro — Text-to-speech helper for outbound voice messages.
3
+ *
4
+ * Wraps OpenAI's `/v1/audio/speech` endpoint. Used by the voice channel
5
+ * adapter's send() path when an agent wants to deliver a voice note
6
+ * over WhatsApp, Slack, or a one-shot Twilio <Play> phone call.
7
+ *
8
+ * Why a separate helper:
9
+ * - One-shot TTS is much cheaper than spinning up a full Realtime
10
+ * session ($0.015/M chars for gpt-4o-mini-tts vs. $32-$64/M tokens
11
+ * for gpt-realtime-2).
12
+ * - WhatsApp / Slack / SMS can't take live audio anyway — they want
13
+ * a file. TTS is the right primitive for asynchronous delivery.
14
+ * - The Realtime API is reserved for true live conversations.
15
+ *
16
+ * Public API:
17
+ * synthesizeSpeech({ text, voice, format, model }) → Promise<Buffer>
18
+ * ttsCostEstimate(text, model) → number (USD)
19
+ *
20
+ * Voices (May 2026): alloy, ash, ballad, coral, echo, sage, shimmer,
21
+ * verse + the GA-only Realtime voices cedar / marin (only available
22
+ * via gpt-realtime-2; tts-1 / gpt-4o-mini-tts use the original eight).
23
+ *
24
+ * Formats: mp3 (default; ~16 kbps for tts-1), opus (best for WhatsApp
25
+ * PTT), aac, flac, wav, pcm.
26
+ */
27
+
28
+ const OPENAI_TTS_URL = "https://api.openai.com/v1/audio/speech";
29
+
30
+ const DEFAULT_MODEL = "gpt-4o-mini-tts"; // best quality/cost for prose
31
+ const DEFAULT_VOICE = "alloy";
32
+ const DEFAULT_FORMAT = "mp3";
33
+
34
+ /**
35
+ * @param {object} opts
36
+ * @param {string} opts.text The text to synthesize (max ~4096 chars per call).
37
+ * @param {string} [opts.voice] Voice name (default: alloy).
38
+ * @param {string} [opts.format] Audio format (default: mp3). Use "opus" for WhatsApp PTT.
39
+ * @param {string} [opts.model] TTS model id (default: gpt-4o-mini-tts).
40
+ * @param {number} [opts.speed] Playback speed multiplier 0.25–4.0 (default: 1.0).
41
+ * @param {string} [opts.apiKey] Override OPENAI_API_KEY.
42
+ * @returns {Promise<Buffer>} Audio bytes.
43
+ */
44
+ export async function synthesizeSpeech(opts = {}) {
45
+ const text = String(opts.text || "").trim();
46
+ if (!text) throw new Error("synthesizeSpeech: text required");
47
+ if (text.length > 4096) {
48
+ throw new Error(`synthesizeSpeech: text > 4096 chars (got ${text.length}); chunk it first`);
49
+ }
50
+ const apiKey = opts.apiKey || process.env.OPENAI_API_KEY;
51
+ if (!apiKey) throw new Error("OPENAI_API_KEY not set");
52
+
53
+ const body = {
54
+ model: opts.model || DEFAULT_MODEL,
55
+ input: text,
56
+ voice: opts.voice || DEFAULT_VOICE,
57
+ response_format: opts.format || DEFAULT_FORMAT,
58
+ };
59
+ if (typeof opts.speed === "number") body.speed = opts.speed;
60
+
61
+ const r = await fetch(OPENAI_TTS_URL, {
62
+ method: "POST",
63
+ headers: {
64
+ Authorization: `Bearer ${apiKey}`,
65
+ "Content-Type": "application/json",
66
+ },
67
+ body: JSON.stringify(body),
68
+ });
69
+ if (!r.ok) {
70
+ const errText = await r.text();
71
+ throw new Error(`tts failed: HTTP ${r.status} ${errText.slice(0, 300)}`);
72
+ }
73
+ const arr = await r.arrayBuffer();
74
+ return Buffer.from(arr);
75
+ }
76
+
77
+ /**
78
+ * Rough USD cost estimate for a TTS call.
79
+ * gpt-4o-mini-tts: $0.015 / 1k characters
80
+ * tts-1 / tts-1-hd: $0.015 / 1k characters (legacy)
81
+ */
82
+ export function ttsCostEstimate(text, model = DEFAULT_MODEL) {
83
+ const chars = String(text || "").length;
84
+ return Number(((chars / 1000) * 0.015).toFixed(6));
85
+ }
86
+
87
+ /**
88
+ * Choose a sensible default voice for an agent based on its config.
89
+ * Falls back to "alloy" so any agent gets a working default without
90
+ * needing to declare one. Operators can pin a specific voice in
91
+ * config/voice.yaml under `voice:`.
92
+ */
93
+ export function pickDefaultVoice(agentVoiceConfig = {}) {
94
+ const v = (agentVoiceConfig.voice || "").toLowerCase();
95
+ // tts-1 / gpt-4o-mini-tts voices (not the Realtime-only cedar/marin)
96
+ const valid = ["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"];
97
+ if (valid.includes(v)) return v;
98
+ // Realtime-only voices fall back gracefully.
99
+ if (v === "cedar") return "ash";
100
+ if (v === "marin") return "shimmer";
101
+ return "alloy";
102
+ }
103
+
104
+ export default { synthesizeSpeech, ttsCostEstimate, pickDefaultVoice };