@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,605 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * context-compiler.mjs — Pre-compiles all relevant context for a daemon-spawned session.
4
+ *
5
+ * Single export: compileContext(item, classResult, options)
6
+ *
7
+ * Assembles sender profile, disclosure boundaries, conversation history,
8
+ * active sessions, and sent-message registry into a single context block.
9
+ * Filters history entries by information barrier domains.
10
+ *
11
+ * Adaptive token budget: 12K for critical/high, 8K for normal, 4K for low.
12
+ */
13
+
14
+ import { readFileSync, readdirSync } from "fs";
15
+ import { join } from "path";
16
+ import { isEnabled as orgEnabled, loadOrgConfig } from "../../lib/org/client.mjs";
17
+ import { recall as orgRecall } from "../../lib/org/knowledge.mjs";
18
+
19
+ const AGENT_REPO_DIR = process.env.__TEST_AGENT_DIR || process.env.AGENT_DIR || join(new URL(".", import.meta.url).pathname, "../..");
20
+ const SESSION_DIR = process.env.__TEST_SESSION_DIR || join(AGENT_REPO_DIR, "state", "sessions");
21
+ const CHARS_PER_TOKEN = 4;
22
+
23
+ // ── Org shared-memory (central store via knowledge.* RPC) ───────────
24
+ // The compiled context draws not only from local files but from the org's
25
+ // shared, ACL'd memory plane. Bounded so a large recall can never blow up the
26
+ // prompt: at most this many facts, each truncated. The SERVER enforces ACL —
27
+ // we render exactly what recall() returns.
28
+ const ORG_RECALL_MAX_FACTS = 6;
29
+ const ORG_RECALL_FACT_CHARS = 400;
30
+
31
+ // ── Token budgets by priority ──────────────────────────────────────
32
+
33
+ const TOKEN_BUDGETS = {
34
+ critical: 12000,
35
+ high: 12000,
36
+ normal: 8000,
37
+ low: 4000,
38
+ };
39
+
40
+ // Fixed allocations (in tokens)
41
+ const ALLOC = {
42
+ profile: 500,
43
+ boundaries: 300,
44
+ active_sessions: 300,
45
+ sent_registry: 500,
46
+ org_memory: 600,
47
+ };
48
+
49
+ // History gets 60% of remaining budget
50
+ const HISTORY_SHARE = 0.6;
51
+
52
+ // ── Helpers ────────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * Extract Slack channel ID from item metadata.
56
+ */
57
+ function extractChannelId(item) {
58
+ if (!item) return null;
59
+ if (item.channel_id) return item.channel_id;
60
+ if (item.raw_ref) {
61
+ const match = item.raw_ref.match(/slack:([DC][A-Z0-9]+):/);
62
+ if (match) return match[1];
63
+ }
64
+ if (item.channel && /^[DC][A-Z0-9]{8,}$/.test(item.channel)) return item.channel;
65
+ return null;
66
+ }
67
+
68
+ /**
69
+ * Read a YAML file and truncate to a character budget. Returns null if missing.
70
+ */
71
+ function loadUserProfile(senderSlug, budgetTokens) {
72
+ if (!senderSlug) return null;
73
+ try {
74
+ const filePath = join(AGENT_REPO_DIR, "memory", "profiles", "users", `${senderSlug}.yaml`);
75
+ let raw = readFileSync(filePath, "utf-8");
76
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
77
+ if (raw.length > charBudget) {
78
+ raw = raw.substring(0, charBudget) + "\n...(truncated)";
79
+ }
80
+ return raw;
81
+ } catch {
82
+ return null;
83
+ }
84
+ }
85
+
86
+ // ── Domain / disclosure helpers ────────────────────────────────────
87
+
88
+ /**
89
+ * Parse domain descriptions from information-barriers.yaml using regex.
90
+ * Returns a Map of domain -> description.
91
+ */
92
+ function loadDomainDescriptions() {
93
+ try {
94
+ const filePath = join(AGENT_REPO_DIR, "policies", "information-barriers.yaml");
95
+ const raw = readFileSync(filePath, "utf-8");
96
+ const map = new Map();
97
+ const regex = /^\s{2}([\w-]+):\s*\n\s+description:\s*"(.+?)"/gm;
98
+ let match;
99
+ while ((match = regex.exec(raw)) !== null) {
100
+ map.set(match[1], match[2]);
101
+ }
102
+ return map;
103
+ } catch {
104
+ return new Map();
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Get all domain names except "public".
110
+ */
111
+ function getAllDomains() {
112
+ const descriptions = loadDomainDescriptions();
113
+ return [...descriptions.keys()].filter((d) => d !== "public");
114
+ }
115
+
116
+ // Common words to exclude from keyword matching (4+ chars)
117
+ const COMMON_WORDS = new Set([
118
+ "this", "that", "with", "from", "have", "been", "will", "more", "when",
119
+ "were", "some", "them", "than", "each", "make", "like", "over", "such",
120
+ "take", "only", "come", "into", "also", "back", "after", "would", "what",
121
+ "your", "about", "could", "their", "which", "other", "there", "first",
122
+ "does", "these", "should", "through", "where", "being", "those",
123
+ "between", "before", "under", "still",
124
+ ]);
125
+
126
+ /**
127
+ * Build a map of domain -> keyword array from domain descriptions.
128
+ * Words must be 4+ chars and not in the common-words exclusion list.
129
+ */
130
+ function buildDomainKeywords() {
131
+ const descriptions = loadDomainDescriptions();
132
+ const result = new Map();
133
+ for (const [domain, desc] of descriptions) {
134
+ if (domain === "public") continue;
135
+ const words = desc
136
+ .toLowerCase()
137
+ .replace(/[^a-z0-9\s-]/g, "")
138
+ .split(/\s+/)
139
+ .filter((w) => w.length >= 4 && !COMMON_WORDS.has(w));
140
+ // Deduplicate
141
+ result.set(domain, [...new Set(words)]);
142
+ }
143
+ return result;
144
+ }
145
+
146
+ /**
147
+ * Returns true if the text matches 2+ keywords from any forbidden domain.
148
+ */
149
+ function matchesForbiddenDomain(text, forbiddenDomains, domainKeywords) {
150
+ if (!forbiddenDomains || forbiddenDomains.length === 0) return false;
151
+ if (!text) return false;
152
+ const lower = text.toLowerCase();
153
+ for (const domain of forbiddenDomains) {
154
+ const keywords = domainKeywords.get(domain);
155
+ if (!keywords) continue;
156
+ let hits = 0;
157
+ for (const kw of keywords) {
158
+ if (lower.includes(kw)) {
159
+ hits++;
160
+ if (hits >= 2) return true;
161
+ }
162
+ }
163
+ }
164
+ return false;
165
+ }
166
+
167
+ /**
168
+ * Load disclosure boundaries for a sender.
169
+ * Returns { boundariesSection, forbiddenDomains }.
170
+ */
171
+ function loadDisclosureBoundaries(senderSlug, budgetTokens) {
172
+ // Attempt to load profile
173
+ let privilegeLevel = null;
174
+ let excludedDomains = [];
175
+
176
+ if (senderSlug) {
177
+ try {
178
+ const filePath = join(AGENT_REPO_DIR, "memory", "profiles", "users", `${senderSlug}.yaml`);
179
+ const raw = readFileSync(filePath, "utf-8");
180
+
181
+ // Extract privilege_level via regex
182
+ const privMatch = raw.match(/privilege_level:\s*(\S+)/);
183
+ if (privMatch) privilegeLevel = privMatch[1];
184
+
185
+ // Extract excluded_domains list
186
+ const exclMatch = raw.match(/excluded_domains:\s*\n((?:\s+-\s+\S+\n?)*)/);
187
+ if (exclMatch) {
188
+ excludedDomains = exclMatch[1]
189
+ .split("\n")
190
+ .map((line) => line.replace(/^\s*-\s*/, "").trim())
191
+ .filter(Boolean);
192
+ }
193
+ } catch {
194
+ // No profile — unknown sender
195
+ }
196
+ }
197
+
198
+ // CEO gets no restrictions
199
+ if (privilegeLevel === "ceo") {
200
+ return { boundariesSection: null, forbiddenDomains: [] };
201
+ }
202
+
203
+ // No profile or unknown → restrict to "public" only (forbid all other domains)
204
+ let forbiddenDomains;
205
+ if (!privilegeLevel) {
206
+ forbiddenDomains = getAllDomains();
207
+ } else {
208
+ // Has profile with explicit excluded_domains
209
+ forbiddenDomains = excludedDomains.length > 0 ? excludedDomains : [];
210
+ }
211
+
212
+ if (forbiddenDomains.length === 0) {
213
+ return { boundariesSection: null, forbiddenDomains: [] };
214
+ }
215
+
216
+ // Build human-readable section
217
+ const descriptions = loadDomainDescriptions();
218
+ const lines = ["DO NOT mention or disclose information related to:"];
219
+ for (const domain of forbiddenDomains) {
220
+ const desc = descriptions.get(domain) || domain;
221
+ lines.push(`- ${domain}: ${desc}`);
222
+ }
223
+
224
+ let section = lines.join("\n");
225
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
226
+ if (section.length > charBudget) {
227
+ section = section.substring(0, charBudget) + "\n...(truncated)";
228
+ }
229
+
230
+ return { boundariesSection: section, forbiddenDomains };
231
+ }
232
+
233
+ // ── Conversation history ───────────────────────────────────────────
234
+
235
+ /**
236
+ * Load conversation history from interaction logs, filtered by disclosure boundaries.
237
+ */
238
+ function loadConversationHistory(senderSlug, channelId, budgetTokens, forbiddenDomains) {
239
+ const candidateDirs = [];
240
+ if (channelId) candidateDirs.push(join(AGENT_REPO_DIR, "memory", "interactions", "slack", channelId));
241
+ if (senderSlug) {
242
+ candidateDirs.push(join(AGENT_REPO_DIR, "memory", "interactions", "slack", `dm-${senderSlug}`));
243
+ candidateDirs.push(join(AGENT_REPO_DIR, "memory", "interactions", "slack", senderSlug));
244
+ }
245
+
246
+ const entries = [];
247
+ const seenKeys = new Set();
248
+
249
+ for (const dir of candidateDirs) {
250
+ try {
251
+ const files = readdirSync(dir)
252
+ .filter((f) => f.endsWith(".jsonl"))
253
+ .sort()
254
+ .reverse()
255
+ .slice(0, 3); // Today + yesterday + day before
256
+
257
+ for (const file of files) {
258
+ try {
259
+ const content = readFileSync(join(dir, file), "utf-8").trim();
260
+ if (!content) continue;
261
+ const lines = content.split("\n").filter(Boolean);
262
+ for (const line of lines) {
263
+ try {
264
+ const entry = JSON.parse(line);
265
+ // Deduplicate by ts:from key
266
+ const dedupKey = `${entry.ts || ""}:${entry.from || entry.sender || ""}`;
267
+ if (seenKeys.has(dedupKey)) continue;
268
+ seenKeys.add(dedupKey);
269
+ entries.push(entry);
270
+ } catch { /* skip malformed lines */ }
271
+ }
272
+ } catch { /* skip unreadable files */ }
273
+ }
274
+ } catch { /* dir doesn't exist — try next */ }
275
+ }
276
+
277
+ if (entries.length === 0) return null;
278
+
279
+ // Sort chronologically
280
+ entries.sort((a, b) => {
281
+ const tsA = a.ts || a.received_at || a.timestamp || "";
282
+ const tsB = b.ts || b.received_at || b.timestamp || "";
283
+ return tsA.localeCompare(tsB);
284
+ });
285
+
286
+ // Filter by disclosure boundaries
287
+ const domainKeywords = buildDomainKeywords();
288
+ const filtered = entries.filter((entry) => {
289
+ const text = entry.content || entry.text || "";
290
+ return !matchesForbiddenDomain(text, forbiddenDomains, domainKeywords);
291
+ });
292
+
293
+ if (filtered.length === 0) return null;
294
+
295
+ // Truncate to character budget — most recent messages prioritised (iterate from end)
296
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
297
+ const outputLines = [];
298
+ let totalChars = 0;
299
+
300
+ for (let i = filtered.length - 1; i >= 0; i--) {
301
+ const entry = filtered[i];
302
+ const from = entry.from || entry.sender || entry.user_name || "unknown";
303
+ const text = entry.content || entry.text || "(no text)";
304
+ const ts = entry.received_at || entry.timestamp || entry.processed_at || entry.ts || "";
305
+ const responded = entry.response_sent ? " [Responded]" : "";
306
+ const line = `[${ts}] ${from}: ${text.substring(0, 500)}${responded}`;
307
+
308
+ if (totalChars + line.length > charBudget) break;
309
+ outputLines.unshift(line);
310
+ totalChars += line.length;
311
+ }
312
+
313
+ return outputLines.length > 0 ? outputLines.join("\n") : null;
314
+ }
315
+
316
+ // ── Active sessions ────────────────────────────────────────────────
317
+
318
+ /**
319
+ * Load active sessions and format as bullet list.
320
+ */
321
+ function loadActiveSessions(budgetTokens) {
322
+ try {
323
+ const filePath = join(SESSION_DIR, "active.json");
324
+ const raw = readFileSync(filePath, "utf-8");
325
+ const data = JSON.parse(raw);
326
+
327
+ // data may be an object with session entries or an array
328
+ const sessions = Array.isArray(data) ? data : Object.values(data);
329
+ if (sessions.length === 0) return null;
330
+
331
+ const lines = [];
332
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
333
+ let totalChars = 0;
334
+
335
+ for (const sess of sessions) {
336
+ const id = sess.sessionId || sess.id || "unknown";
337
+ const summary = sess.summary || sess.task || "no summary";
338
+ const model = sess.model || "unknown";
339
+ const sender = sess.sender || sess.owner || "unknown";
340
+ const started = sess.startTime || sess.started_at || "";
341
+ let age = "";
342
+ if (started) {
343
+ const ms = Date.now() - new Date(started).getTime();
344
+ const mins = Math.round(ms / 60000);
345
+ age = `${mins}m ago`;
346
+ }
347
+ const line = `- ${id}: ${summary} (model=${model}, sender=${sender}${age ? ", " + age : ""})`;
348
+ if (totalChars + line.length > charBudget) break;
349
+ lines.push(line);
350
+ totalChars += line.length;
351
+ }
352
+
353
+ return lines.length > 0 ? lines.join("\n") : null;
354
+ } catch {
355
+ return null;
356
+ }
357
+ }
358
+
359
+ // ── Sent registry ──────────────────────────────────────────────────
360
+
361
+ /**
362
+ * Load recent sent-registry entries for the same channel.
363
+ */
364
+ function loadSentRegistry(channelId, budgetTokens) {
365
+ if (!channelId) return null;
366
+ try {
367
+ const filePath = join(SESSION_DIR, "sent-registry.jsonl");
368
+ const raw = readFileSync(filePath, "utf-8").trim();
369
+ if (!raw) return null;
370
+
371
+ const allLines = raw.split("\n").filter(Boolean);
372
+ const matching = [];
373
+ for (const line of allLines) {
374
+ try {
375
+ const entry = JSON.parse(line);
376
+ if (entry.channelId === channelId || entry.channel_id === channelId || entry.channel === channelId) {
377
+ matching.push(entry);
378
+ }
379
+ } catch { /* skip malformed */ }
380
+ }
381
+
382
+ // Take last 20
383
+ const recent = matching.slice(-20);
384
+ if (recent.length === 0) return null;
385
+
386
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
387
+ const lines = [];
388
+ let totalChars = 0;
389
+
390
+ for (const entry of recent) {
391
+ const ts = entry.timestamp || entry.sent_at || "";
392
+ const type = entry.type || entry.action || "message";
393
+ const preview = (entry.preview || entry.content || entry.text || "").substring(0, 100);
394
+ const line = `[${ts}] (${type}) ${preview}`;
395
+ if (totalChars + line.length > charBudget) break;
396
+ lines.push(line);
397
+ totalChars += line.length;
398
+ }
399
+
400
+ return lines.length > 0 ? lines.join("\n") : null;
401
+ } catch {
402
+ return null;
403
+ }
404
+ }
405
+
406
+ // ── Org shared memory ──────────────────────────────────────────────
407
+
408
+ // Cached org config (config/org.yaml) — read once per process. undefined until loaded.
409
+ let cachedOrgCfg;
410
+
411
+ /**
412
+ * Load the org config for the recall binding, cached for the process. Returns {}
413
+ * on any error so callers can null-check uniformly — the org binding must never
414
+ * take down the daemon's main path.
415
+ */
416
+ function loadCachedOrgCfg() {
417
+ if (cachedOrgCfg !== undefined) return cachedOrgCfg;
418
+ try {
419
+ cachedOrgCfg = loadOrgConfig(AGENT_REPO_DIR) || {};
420
+ } catch {
421
+ cachedOrgCfg = {};
422
+ }
423
+ return cachedOrgCfg;
424
+ }
425
+
426
+ /** For tests: reset the cached org config so a fresh config/org.yaml is re-read. */
427
+ export function _resetOrgCfgCache() {
428
+ cachedOrgCfg = undefined;
429
+ }
430
+
431
+ /**
432
+ * Derive a short recall query from the item / classification being processed.
433
+ * Prefers the classifier summary, then subject, then a slice of the body.
434
+ */
435
+ function recallQueryFor(item, classResult, queueItem) {
436
+ const parts = [];
437
+ if (classResult && classResult.summary) parts.push(String(classResult.summary));
438
+ if (item && item.subject) parts.push(String(item.subject));
439
+ if (queueItem && queueItem.title) parts.push(String(queueItem.title));
440
+ if (parts.length === 0 && item && item.content) parts.push(String(item.content).slice(0, 200));
441
+ return parts.join(" — ").trim();
442
+ }
443
+
444
+ /**
445
+ * Read the org's shared memory (central store, `knowledge.search` RPC) for this
446
+ * item's topic and render it as a bounded, clearly-delimited section, or null
447
+ * when disabled / nothing relevant came back. Fail-open: never throws. The
448
+ * SERVER enforces ACL — we render exactly what recall() returns.
449
+ *
450
+ * @param {object} item
451
+ * @param {object} classResult
452
+ * @param {number} budgetTokens
453
+ * @param {object} [opts] - { cfg?, recallImpl?, queueItem? } — injectable for tests
454
+ * @returns {Promise<string|null>}
455
+ */
456
+ async function loadOrgMemory(item, classResult, budgetTokens, opts = {}) {
457
+ try {
458
+ const cfg = opts.cfg !== undefined ? opts.cfg : loadCachedOrgCfg();
459
+ if (!orgEnabled(cfg)) return null;
460
+ const query = recallQueryFor(item, classResult, opts.queueItem);
461
+ if (!query) return null;
462
+
463
+ const recallImpl = opts.recallImpl || orgRecall;
464
+ const facts = await recallImpl(query, { cfg, limit: ORG_RECALL_MAX_FACTS });
465
+ if (!Array.isArray(facts) || facts.length === 0) return null;
466
+
467
+ const charBudget = budgetTokens * CHARS_PER_TOKEN;
468
+ const lines = [
469
+ "Facts the org already knows that may bear on this item (ACL-filtered by the",
470
+ "server; treat as trusted internal context):",
471
+ ];
472
+ let n = 0;
473
+ let totalChars = lines.join("\n").length;
474
+ for (const f of facts) {
475
+ if (n >= ORG_RECALL_MAX_FACTS) break;
476
+ const textRaw = typeof f === "string" ? f : (f && (f.text || f.content || f.body) || "");
477
+ const text = String(textRaw).trim();
478
+ if (!text) continue;
479
+ const clipped = text.length > ORG_RECALL_FACT_CHARS ? `${text.slice(0, ORG_RECALL_FACT_CHARS)}…` : text;
480
+ const id = f && typeof f === "object" && f.id != null ? ` [${String(f.id)}]` : "";
481
+ const line = `- ${clipped}${id}`;
482
+ if (totalChars + line.length > charBudget) break;
483
+ lines.push(line);
484
+ totalChars += line.length;
485
+ n += 1;
486
+ }
487
+ return n > 0 ? lines.join("\n") : null;
488
+ } catch {
489
+ // Fail-open: org recall must never take down the context build.
490
+ return null;
491
+ }
492
+ }
493
+
494
+ // ── Main export ────────────────────────────────────────────────────
495
+
496
+ /**
497
+ * Compile all relevant context for a daemon session.
498
+ *
499
+ * @param {object} item - The inbox item or queue item being processed
500
+ * @param {object} classResult - Classification result with at least .priority
501
+ * @param {object} [options] - Optional overrides
502
+ * @returns {{ contextBlock: string, tokenBudget: number, tokenEstimate: number }}
503
+ */
504
+ export async function compileContext(item, classResult, options = {}) {
505
+ try {
506
+ // Step 1 — Budget
507
+ const priority = classResult?.priority || "normal";
508
+ const tokenBudget = TOKEN_BUDGETS[priority] || TOKEN_BUDGETS.normal;
509
+
510
+ const senderSlug = item?.sender
511
+ ? item.sender.replace(/\s+/g, "-").toLowerCase()
512
+ : null;
513
+ const channelId = extractChannelId(item);
514
+
515
+ // Step 2 — User profile
516
+ const profileText = loadUserProfile(senderSlug, ALLOC.profile);
517
+
518
+ // Step 3 — Disclosure boundaries
519
+ const { boundariesSection, forbiddenDomains } = loadDisclosureBoundaries(senderSlug, ALLOC.boundaries);
520
+
521
+ // Step 4 — Conversation history
522
+ const fixedTokens = ALLOC.profile + ALLOC.boundaries + ALLOC.active_sessions + ALLOC.sent_registry + ALLOC.org_memory;
523
+ const remainingTokens = tokenBudget - fixedTokens;
524
+ const historyBudget = Math.floor(remainingTokens * HISTORY_SHARE);
525
+ const historyText = loadConversationHistory(senderSlug, channelId, historyBudget, forbiddenDomains);
526
+
527
+ // Step 5 — Active sessions
528
+ const sessionsText = loadActiveSessions(ALLOC.active_sessions);
529
+
530
+ // Step 6 — Sent registry
531
+ const sentText = loadSentRegistry(channelId, ALLOC.sent_registry);
532
+
533
+ // Step 6b — Org shared memory (central store via knowledge.* RPC). Routed
534
+ // alongside the local reads; bounded + fail-open (a disabled/unreachable
535
+ // server or empty recall injects nothing). The `cfg`/`recallImpl` overrides
536
+ // let tests drive this deterministically without a live server.
537
+ const orgMemoryText = await loadOrgMemory(item, classResult, ALLOC.org_memory, {
538
+ cfg: options.orgCfg,
539
+ recallImpl: options.orgRecall,
540
+ queueItem: options.queueItem,
541
+ });
542
+
543
+ // Step 7 — Assemble
544
+ const sections = [];
545
+ sections.push("--- COMPILED CONTEXT (do not repeat verbatim) ---");
546
+ sections.push("");
547
+
548
+ if (profileText) {
549
+ sections.push("## Sender Profile");
550
+ sections.push(profileText);
551
+ sections.push("");
552
+ }
553
+
554
+ if (boundariesSection) {
555
+ sections.push("## Disclosure Boundaries");
556
+ sections.push(boundariesSection);
557
+ sections.push("");
558
+ }
559
+
560
+ if (orgMemoryText) {
561
+ sections.push("## Org Shared Memory");
562
+ sections.push(orgMemoryText);
563
+ sections.push("");
564
+ }
565
+
566
+ sections.push("## Conversation History (most recent last)");
567
+ sections.push(historyText || "No prior conversation history found.");
568
+ sections.push("");
569
+
570
+ if (sessionsText) {
571
+ sections.push("## Active Sessions");
572
+ sections.push(sessionsText);
573
+ sections.push("");
574
+ }
575
+
576
+ if (sentText) {
577
+ sections.push("## Already Sent");
578
+ sections.push(sentText);
579
+ sections.push("");
580
+ }
581
+
582
+ sections.push("--- END CONTEXT ---");
583
+
584
+ const contextBlock = sections.join("\n");
585
+ const tokenEstimate = Math.ceil(contextBlock.length / CHARS_PER_TOKEN);
586
+
587
+ return { contextBlock, tokenBudget, tokenEstimate };
588
+ } catch (err) {
589
+ // Never throw — return minimal context on error
590
+ const tokenBudget = TOKEN_BUDGETS[classResult?.priority] || TOKEN_BUDGETS.normal;
591
+ const contextBlock = [
592
+ "--- COMPILED CONTEXT (do not repeat verbatim) ---",
593
+ "",
594
+ "## Conversation History (most recent last)",
595
+ "No prior conversation history found.",
596
+ "",
597
+ "--- END CONTEXT ---",
598
+ ].join("\n");
599
+ return {
600
+ contextBlock,
601
+ tokenBudget,
602
+ tokenEstimate: Math.ceil(contextBlock.length / CHARS_PER_TOKEN),
603
+ };
604
+ }
605
+ }