@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.
- package/.claude/commands/init-agent.md +104 -0
- package/.claude/commands/init-maestro.md +1187 -0
- package/.claude/settings.json +161 -0
- package/.env.example +216 -0
- package/README.md +632 -0
- package/agents/browser-operator/agent.md +52 -0
- package/agents/calendar-ops/agent.md +50 -0
- package/agents/communications/agent.md +96 -0
- package/agents/decision-log/agent.md +65 -0
- package/agents/desktop-operator/agent.md +59 -0
- package/agents/gmail-operator/agent.md +62 -0
- package/agents/inbound-dispatcher/agent.md +66 -0
- package/agents/inbox-processor/agent.md +39 -0
- package/agents/pmo-execution/agent.md +60 -0
- package/agents/session-spawner/agent.md +64 -0
- package/agents/slack-operator/agent.md +60 -0
- package/agents/whatsapp-operator/agent.md +60 -0
- package/agents/workflow-automation/agent.md +61 -0
- package/archetypes/altitudes/c-suite.yaml +58 -0
- package/archetypes/altitudes/founder.yaml +68 -0
- package/archetypes/altitudes/senior-manager.yaml +63 -0
- package/archetypes/altitudes/svp.yaml +60 -0
- package/archetypes/altitudes/vp.yaml +50 -0
- package/archetypes/archetype.schema.json +77 -0
- package/archetypes/base.yaml +47 -0
- package/archetypes/capabilities/commercial-leader.yaml +159 -0
- package/archetypes/capabilities/compliance-officer.yaml +159 -0
- package/archetypes/capabilities/executive-operator.yaml +169 -0
- package/archetypes/capabilities/finance-leader.yaml +162 -0
- package/archetypes/capabilities/operations-leader.yaml +154 -0
- package/archetypes/capabilities/product-leader.yaml +148 -0
- package/archetypes/capabilities/technical-leader.yaml +146 -0
- package/archetypes/functions/commercial-leader.yaml +62 -0
- package/archetypes/functions/compliance-officer.yaml +64 -0
- package/archetypes/functions/executive-operator.yaml +70 -0
- package/archetypes/functions/finance-leader.yaml +70 -0
- package/archetypes/functions/operations-leader.yaml +62 -0
- package/archetypes/functions/product-leader.yaml +61 -0
- package/archetypes/functions/technical-leader.yaml +57 -0
- package/bin/cohort-mcp.mjs +81 -0
- package/bin/maestro.mjs +3516 -0
- package/bin/maestro.test.mjs +1015 -0
- package/desktop-control/README.md +56 -0
- package/desktop-control/app-profiles/gmail.yaml +120 -0
- package/desktop-control/app-profiles/slack.yaml +315 -0
- package/desktop-control/app-profiles/whatsapp.yaml +107 -0
- package/docs/architecture/agent-topology.md +2239 -0
- package/docs/architecture/archetype-agent-factory.md +110 -0
- package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
- package/docs/architecture/continuous-monitoring.md +221 -0
- package/docs/architecture/mcp-capability-map.md +585 -0
- package/docs/architecture/system-architecture.md +1272 -0
- package/docs/company-context/README.md +40 -0
- package/docs/guides/agent-persona-setup.md +600 -0
- package/docs/guides/agents-observe-setup.md +64 -0
- package/docs/guides/billing-console-keys.md +88 -0
- package/docs/guides/ccxray-diagnostics.md +65 -0
- package/docs/guides/channel-bus.md +127 -0
- package/docs/guides/claude-mem-setup.md +79 -0
- package/docs/guides/claude-pace-setup.md +56 -0
- package/docs/guides/claudraband-sessions.md +98 -0
- package/docs/guides/clawteam-swarm.md +116 -0
- package/docs/guides/code-review-graph-setup.md +86 -0
- package/docs/guides/email-setup.md +431 -0
- package/docs/guides/mac-mini.md +119 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/model-routing.md +162 -0
- package/docs/guides/observability-otel.md +265 -0
- package/docs/guides/org-onboarding.md +132 -0
- package/docs/guides/outbound-governance-setup.md +437 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +563 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/self-optimization-pattern.md +82 -0
- package/docs/guides/setup-wizard.md +178 -0
- package/docs/guides/slack-setup.md +350 -0
- package/docs/guides/telegram-setup.md +227 -0
- package/docs/guides/twilio-subaccounts-setup.md +223 -0
- package/docs/guides/verification.md +128 -0
- package/docs/guides/voice-mode.md +188 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/webhook-relay-setup.md +349 -0
- package/docs/guides/whatsapp-setup.md +288 -0
- package/docs/prompts/board-pack-cover-template.md +36 -0
- package/docs/prompts/decision-recommendation-template.md +88 -0
- package/docs/prompts/followup-message-template.md +141 -0
- package/docs/prompts/investor-letter-template.md +52 -0
- package/docs/prompts/morning-brief-template.md +82 -0
- package/docs/prompts/presentation-template.md +58 -0
- package/docs/prompts/weekly-strategic-memo-template.md +104 -0
- package/docs/research/hallucinated-tool-output-investigation.md +151 -0
- package/docs/runbooks/backup-restore.md +205 -0
- package/docs/runbooks/cohort-cutover.md +129 -0
- package/docs/runbooks/fleet-operations.md +200 -0
- package/docs/runbooks/incident-response.md +226 -0
- package/docs/runbooks/mac-mini-bootstrap.md +431 -0
- package/docs/runbooks/perpetual-operations.md +509 -0
- package/docs/runbooks/recovery-and-failover.md +260 -0
- package/framework-features.json +267 -0
- package/ingest/README.md +87 -0
- package/lib/action-executor.js +689 -0
- package/lib/action-executor.test.mjs +871 -0
- package/lib/agent-root.mjs +37 -0
- package/lib/archetype.mjs +236 -0
- package/lib/archetype.test.mjs +132 -0
- package/lib/autonomy.mjs +114 -0
- package/lib/autonomy.test.mjs +66 -0
- package/lib/backlog.mjs +358 -0
- package/lib/backlog.test.mjs +266 -0
- package/lib/budget-guard.mjs +279 -0
- package/lib/budget-guard.test.mjs +291 -0
- package/lib/cadence-bus-schedule.test.mjs +194 -0
- package/lib/cadence-bus.mjs +1120 -0
- package/lib/cadence-bus.test.mjs +720 -0
- package/lib/cadences.mjs +205 -0
- package/lib/cadences.test.mjs +125 -0
- package/lib/capability.mjs +154 -0
- package/lib/capability.test.mjs +78 -0
- package/lib/channels/base-adapter.mjs +719 -0
- package/lib/channels/base-adapter.test.mjs +590 -0
- package/lib/channels/channel.mjs +128 -0
- package/lib/channels/channels.test.mjs +371 -0
- package/lib/channels/contract.mjs +215 -0
- package/lib/channels/contract.test.mjs +137 -0
- package/lib/channels/conversation-resolver.mjs +95 -0
- package/lib/channels/gmail/adapter.mjs +87 -0
- package/lib/channels/inbox-item.mjs +255 -0
- package/lib/channels/inbox-item.test.mjs +335 -0
- package/lib/channels/index.mjs +94 -0
- package/lib/channels/orgmail/adapter.mjs +353 -0
- package/lib/channels/orgmail/adapter.test.mjs +311 -0
- package/lib/channels/pairing.mjs +363 -0
- package/lib/channels/pairing.test.mjs +270 -0
- package/lib/channels/registry.mjs +164 -0
- package/lib/channels/slack/adapter.mjs +317 -0
- package/lib/channels/slack-adapter.test.mjs +212 -0
- package/lib/channels/sms/adapter.mjs +43 -0
- package/lib/channels/telegram/adapter.mjs +432 -0
- package/lib/channels/telegram-adapter.test.mjs +306 -0
- package/lib/channels/voice/adapter.mjs +301 -0
- package/lib/channels/voice/adapter.test.mjs +278 -0
- package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
- package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
- package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
- package/lib/charter.mjs +256 -0
- package/lib/charter.test.mjs +89 -0
- package/lib/claude-bin.mjs +134 -0
- package/lib/claude-bin.test.mjs +75 -0
- package/lib/collective/capture.mjs +185 -0
- package/lib/collective/capture.test.mjs +121 -0
- package/lib/collective/cards.mjs +201 -0
- package/lib/collective/cards.test.mjs +114 -0
- package/lib/collective/config.mjs +186 -0
- package/lib/collective/config.test.mjs +123 -0
- package/lib/collective/global-config.mjs +113 -0
- package/lib/collective/global-config.test.mjs +75 -0
- package/lib/collective/presence.mjs +201 -0
- package/lib/collective/presence.test.mjs +95 -0
- package/lib/collective/recall.mjs +215 -0
- package/lib/collective/recall.test.mjs +116 -0
- package/lib/comms/send-gate.mjs +554 -0
- package/lib/comms/send-gate.test.mjs +577 -0
- package/lib/comms.mjs +67 -0
- package/lib/comms.test.mjs +41 -0
- package/lib/diagnostics/alerts.mjs +424 -0
- package/lib/diagnostics/alerts.test.mjs +318 -0
- package/lib/diagnostics/backup-freshness.mjs +188 -0
- package/lib/diagnostics/backup-freshness.test.mjs +185 -0
- package/lib/diagnostics/counters.mjs +269 -0
- package/lib/diagnostics/counters.test.mjs +206 -0
- package/lib/diagnostics/events.mjs +188 -0
- package/lib/diagnostics/events.test.mjs +290 -0
- package/lib/diagnostics/otel.mjs +237 -0
- package/lib/diagnostics/otel.test.mjs +196 -0
- package/lib/diagnostics/trace.mjs +216 -0
- package/lib/diagnostics/trace.test.mjs +251 -0
- package/lib/env-compat.mjs +74 -0
- package/lib/env-compat.test.mjs +104 -0
- package/lib/feature-init.mjs +331 -0
- package/lib/fs-atomic.mjs +112 -0
- package/lib/fs-atomic.test.mjs +72 -0
- package/lib/fs-ownership.mjs +111 -0
- package/lib/fs-ownership.test.mjs +158 -0
- package/lib/hooks/bus.mjs +347 -0
- package/lib/hooks/bus.test.mjs +387 -0
- package/lib/index.js +16 -0
- package/lib/learning/config.mjs +106 -0
- package/lib/learning/config.test.mjs +75 -0
- package/lib/learning/counters.mjs +156 -0
- package/lib/learning/counters.test.mjs +69 -0
- package/lib/learning/curator-consolidate.test.mjs +238 -0
- package/lib/learning/curator.mjs +453 -0
- package/lib/learning/curator.test.mjs +106 -0
- package/lib/learning/log.mjs +40 -0
- package/lib/learning/reflect.mjs +534 -0
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.mjs +352 -0
- package/lib/learning/session-index.test.mjs +125 -0
- package/lib/learning/skill-writer.mjs +474 -0
- package/lib/learning/skill-writer.test.mjs +210 -0
- package/lib/mcp/server.mjs +328 -0
- package/lib/mcp/server.test.mjs +400 -0
- package/lib/model-router/auth-profiles.mjs +758 -0
- package/lib/model-router/auth-profiles.test.mjs +580 -0
- package/lib/model-router/catalog/anthropic.yaml +153 -0
- package/lib/model-router/catalog/deepseek.yaml +86 -0
- package/lib/model-router/catalog/moonshot.yaml +81 -0
- package/lib/model-router/catalog/qwen.yaml +114 -0
- package/lib/model-router/catalog.mjs +925 -0
- package/lib/model-router/catalog.test.mjs +385 -0
- package/lib/model-router/economics.mjs +564 -0
- package/lib/model-router/economics.test.mjs +344 -0
- package/lib/model-router/failover.mjs +298 -0
- package/lib/model-router/failover.test.mjs +439 -0
- package/lib/model-router/health.mjs +453 -0
- package/lib/model-router/health.test.mjs +338 -0
- package/lib/model-router/integration-coverage.test.mjs +829 -0
- package/lib/model-router/integration.test.mjs +564 -0
- package/lib/model-router/ledger.mjs +402 -0
- package/lib/model-router/ledger.test.mjs +382 -0
- package/lib/model-router/llm-task.mjs +515 -0
- package/lib/model-router/llm-task.test.mjs +392 -0
- package/lib/model-router/org-credentials.mjs +260 -0
- package/lib/model-router/org-credentials.test.mjs +265 -0
- package/lib/model-router/pricing-refresh.mjs +463 -0
- package/lib/model-router/pricing-refresh.test.mjs +286 -0
- package/lib/model-router/reconcile.mjs +429 -0
- package/lib/model-router/reconcile.test.mjs +316 -0
- package/lib/model-router/repair.mjs +471 -0
- package/lib/model-router/repair.test.mjs +180 -0
- package/lib/model-router/resolve.mjs +1206 -0
- package/lib/model-router/spawn.mjs +497 -0
- package/lib/model-router/spawn.test.mjs +425 -0
- package/lib/model-router/taxonomy.mjs +893 -0
- package/lib/model-router/taxonomy.test.mjs +410 -0
- package/lib/model-router.mjs +677 -0
- package/lib/model-router.test.mjs +907 -0
- package/lib/org/activity.mjs +211 -0
- package/lib/org/activity.test.mjs +134 -0
- package/lib/org/approvals.mjs +448 -0
- package/lib/org/approvals.test.mjs +216 -0
- package/lib/org/awareness.mjs +222 -0
- package/lib/org/awareness.test.mjs +159 -0
- package/lib/org/board.mjs +229 -0
- package/lib/org/board.test.mjs +177 -0
- package/lib/org/bootstrap-context.mjs +169 -0
- package/lib/org/bootstrap-context.test.mjs +153 -0
- package/lib/org/client.mjs +1628 -0
- package/lib/org/client.test.mjs +1107 -0
- package/lib/org/cohort-client.mjs +67 -0
- package/lib/org/cohort-client.test.mjs +126 -0
- package/lib/org/cost-sync.mjs +227 -0
- package/lib/org/cost-sync.test.mjs +153 -0
- package/lib/org/doctor.mjs +212 -0
- package/lib/org/doctor.test.mjs +212 -0
- package/lib/org/handoff.mjs +293 -0
- package/lib/org/handoff.test.mjs +269 -0
- package/lib/org/integration-tools.mjs +182 -0
- package/lib/org/integration-tools.test.mjs +160 -0
- package/lib/org/keys.mjs +131 -0
- package/lib/org/keys.test.mjs +92 -0
- package/lib/org/knowledge.mjs +463 -0
- package/lib/org/knowledge.test.mjs +319 -0
- package/lib/org/leases.mjs +335 -0
- package/lib/org/leases.test.mjs +235 -0
- package/lib/org/mesh-integration.test.mjs +127 -0
- package/lib/org/mesh.mjs +459 -0
- package/lib/org/mesh.test.mjs +345 -0
- package/lib/org/messaging.mjs +503 -0
- package/lib/org/messaging.test.mjs +238 -0
- package/lib/org/policy.mjs +345 -0
- package/lib/org/policy.test.mjs +237 -0
- package/lib/org/protocol.checksum +1 -0
- package/lib/org/protocol.checksum.test.mjs +90 -0
- package/lib/org/protocol.mjs +967 -0
- package/lib/org/protocol.test.mjs +264 -0
- package/lib/org/registry.mjs +194 -0
- package/lib/org/registry.test.mjs +100 -0
- package/lib/org/tool-surface-integration.test.mjs +120 -0
- package/lib/org/tool-surface.mjs +2535 -0
- package/lib/org/tool-surface.test.mjs +589 -0
- package/lib/org/ui-parity.mjs +3236 -0
- package/lib/org/ui-parity.test.mjs +348 -0
- package/lib/org/verify.mjs +176 -0
- package/lib/org/verify.test.mjs +194 -0
- package/lib/rag/embed.mjs +188 -0
- package/lib/rag/indexer.mjs +425 -0
- package/lib/rag/rag.test.mjs +505 -0
- package/lib/rag/search.mjs +475 -0
- package/lib/rate-guard.mjs +246 -0
- package/lib/rate-guard.test.mjs +201 -0
- package/lib/render.mjs +112 -0
- package/lib/render.test.mjs +68 -0
- package/lib/resource-governor.mjs +297 -0
- package/lib/resource-governor.test.mjs +262 -0
- package/lib/scheduling/dynamic-jobs.mjs +675 -0
- package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
- package/lib/scheduling/jitter.mjs +0 -0
- package/lib/scheduling/jitter.test.mjs +140 -0
- package/lib/secrets/broker.mjs +315 -0
- package/lib/secrets/broker.test.mjs +280 -0
- package/lib/secrets/providers.mjs +461 -0
- package/lib/secrets/providers.test.mjs +274 -0
- package/lib/security/audit-engine.mjs +684 -0
- package/lib/security/audit-engine.test.mjs +389 -0
- package/lib/security/coerce-args.mjs +552 -0
- package/lib/security/coerce-args.test.mjs +281 -0
- package/lib/security/dangerous-tools.mjs +97 -0
- package/lib/security/dangerous-tools.test.mjs +68 -0
- package/lib/security/external-content.mjs +145 -0
- package/lib/security/external-content.test.mjs +67 -0
- package/lib/security/redact.mjs +592 -0
- package/lib/security/redact.test.mjs +441 -0
- package/lib/security/secret-equal.mjs +73 -0
- package/lib/security/secret-equal.test.mjs +55 -0
- package/lib/session-permissions.mjs +101 -0
- package/lib/session-permissions.test.mjs +100 -0
- package/lib/setup/claude-probe.mjs +74 -0
- package/lib/setup/completeness.mjs +175 -0
- package/lib/setup/completeness.test.mjs +110 -0
- package/lib/setup/context-pack.mjs +173 -0
- package/lib/setup/context-pack.test.mjs +89 -0
- package/lib/setup/enrich.mjs +277 -0
- package/lib/setup/enrich.test.mjs +115 -0
- package/lib/setup/enroll-from-cohort.mjs +441 -0
- package/lib/setup/enroll-from-cohort.test.mjs +233 -0
- package/lib/setup/integration.test.mjs +162 -0
- package/lib/setup/io.mjs +360 -0
- package/lib/setup/io.test.mjs +77 -0
- package/lib/setup/run-generator.mjs +81 -0
- package/lib/setup/runner.mjs +244 -0
- package/lib/setup/runner.test.mjs +132 -0
- package/lib/setup/sections/comms.mjs +173 -0
- package/lib/setup/sections/company.mjs +120 -0
- package/lib/setup/sections/enrich.mjs +138 -0
- package/lib/setup/sections/identity.mjs +182 -0
- package/lib/setup/sections/identity.test.mjs +140 -0
- package/lib/setup/sections/learning.mjs +153 -0
- package/lib/setup/sections/learning.test.mjs +81 -0
- package/lib/setup/sections/messaging.mjs +219 -0
- package/lib/setup/sections/messaging.test.mjs +127 -0
- package/lib/setup/sections/model.mjs +102 -0
- package/lib/setup/sections/operating-model.mjs +78 -0
- package/lib/setup/sections/org.mjs +475 -0
- package/lib/setup/sections/org.test.mjs +313 -0
- package/lib/setup/sections/orgmail.mjs +173 -0
- package/lib/setup/sections/orgmail.test.mjs +118 -0
- package/lib/setup/sections/recovery.mjs +159 -0
- package/lib/setup/sections/recovery.test.mjs +98 -0
- package/lib/setup/sections/tools.mjs +132 -0
- package/lib/setup/sections/verify.mjs +97 -0
- package/lib/setup/sot.mjs +205 -0
- package/lib/setup/sot.test.mjs +81 -0
- package/lib/setup/state.mjs +151 -0
- package/lib/setup/state.test.mjs +92 -0
- package/lib/singleton.js +229 -0
- package/lib/singleton.test.mjs +135 -0
- package/lib/telemetry/alerts.mjs +216 -0
- package/lib/telemetry/alerts.test.mjs +109 -0
- package/lib/telemetry/collect.mjs +512 -0
- package/lib/telemetry/collect.test.mjs +202 -0
- package/lib/tool-definitions-integration.test.mjs +83 -0
- package/lib/tool-definitions.js +738 -0
- package/lib/tool-definitions.test.mjs +437 -0
- package/lib/util/fetch-timeout.mjs +136 -0
- package/lib/util/fetch-timeout.test.mjs +202 -0
- package/lib/util/reconnect.mjs +343 -0
- package/lib/util/reconnect.test.mjs +369 -0
- package/lib/util/unhandled.mjs +205 -0
- package/lib/util/unhandled.test.mjs +216 -0
- package/lib/voice/context-loader.mjs +466 -0
- package/lib/voice/index.mjs +100 -0
- package/lib/voice/openai-realtime.mjs +510 -0
- package/lib/voice/outbound.mjs +542 -0
- package/lib/voice/outbound.test.mjs +69 -0
- package/lib/voice/post-call-brief.mjs +428 -0
- package/lib/voice/provider.mjs +52 -0
- package/lib/voice/session-rotation.mjs +257 -0
- package/lib/voice/stt.mjs +161 -0
- package/lib/voice/stt.test.mjs +226 -0
- package/lib/voice/tool-bridge.mjs +370 -0
- package/lib/voice/tts.mjs +104 -0
- package/lib/voice/twilio-sip-bridge.mjs +288 -0
- package/lib/voice/voice.test.mjs +990 -0
- package/mcp/README.md +80 -0
- package/package.json +151 -0
- package/plugins/maestro-skills/plugin.json +139 -0
- package/plugins/maestro-skills/skills/agents-observe.md +110 -0
- package/plugins/maestro-skills/skills/board-deck.md +68 -0
- package/plugins/maestro-skills/skills/books-close.md +77 -0
- package/plugins/maestro-skills/skills/brand-steward.md +121 -0
- package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
- package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
- package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
- package/plugins/maestro-skills/skills/claude-pace.md +61 -0
- package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
- package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
- package/plugins/maestro-skills/skills/decision-brief.md +89 -0
- package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
- package/plugins/maestro-skills/skills/draft-comms.md +84 -0
- package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
- package/plugins/maestro-skills/skills/files-find.md +65 -0
- package/plugins/maestro-skills/skills/generative-ui.md +228 -0
- package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
- package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
- package/plugins/maestro-skills/skills/mail-triage.md +86 -0
- package/plugins/maestro-skills/skills/morning-brief.md +54 -0
- package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
- package/plugins/maestro-skills/skills/org-board.md +133 -0
- package/plugins/maestro-skills/skills/org-credential.md +68 -0
- package/plugins/maestro-skills/skills/org-recall.md +81 -0
- package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
- package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
- package/plugins/maestro-skills/skills/router-why.md +78 -0
- package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
- package/plugins/maestro-skills/skills/session-search.md +71 -0
- package/plugins/maestro-skills/skills/set-reminder.md +93 -0
- package/plugins/maestro-skills/skills/slack-followup.md +64 -0
- package/plugins/maestro-skills/skills/team-activity.md +86 -0
- package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
- package/policies/action-classification.yaml +114 -0
- package/policies/ai-disclosure.yaml +294 -0
- package/policies/communication-style.md +139 -0
- package/policies/information-barriers.yaml +118 -0
- package/policies/prompt-injection-defence.yaml +138 -0
- package/public/assets/icon-dark.png +0 -0
- package/public/assets/icon-dark.svg +9 -0
- package/public/assets/icon-light.svg +9 -0
- package/public/assets/logo-dark.svg +15 -0
- package/public/assets/logo-light.svg +15 -0
- package/scaffold/.mcp.json +7 -0
- package/scaffold/CLAUDE.md +368 -0
- package/scaffold/config/agent.json +55 -0
- package/scaffold/config/agent.ts +76 -0
- package/scaffold/config/agent.ts.example +89 -0
- package/scaffold/config/alerts.yaml +23 -0
- package/scaffold/config/allowlist.yaml.example +25 -0
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scaffold/config/collective.yaml +49 -0
- package/scaffold/config/company.json +20 -0
- package/scaffold/config/known-agents.json +6 -0
- package/scaffold/config/learning.yaml +55 -0
- package/scaffold/config/model-routing.yaml.example +104 -0
- package/scaffold/config/org.yaml +25 -0
- package/scaffold/config/orgmail.yaml.example +19 -0
- package/scaffold/config/recovery.yaml +72 -0
- package/scaffold/config/secrets.yaml +27 -0
- package/scaffold/config/slack.yaml.example +35 -0
- package/scaffold/config/telegram.yaml.example +38 -0
- package/scaffold/config/voice.yaml.example +89 -0
- package/scaffold/config/whatsapp.yaml.example +39 -0
- package/schedules/README.md +49 -0
- package/schedules/triggers/backlog-executor.md +102 -0
- package/schedules/triggers/brand-steward.md +72 -0
- package/schedules/triggers/daily-evening-wrap.md +159 -0
- package/schedules/triggers/daily-midday-sweep.md +58 -0
- package/schedules/triggers/daily-morning-brief.md +55 -0
- package/schedules/triggers/directory-hygiene.md +81 -0
- package/schedules/triggers/dynamic-jobs.md +40 -0
- package/schedules/triggers/inbox-processor.md +115 -0
- package/schedules/triggers/meeting-action-capture.md +60 -0
- package/schedules/triggers/meeting-prep.md +69 -0
- package/schedules/triggers/messaging-inbound.md +50 -0
- package/schedules/triggers/org-pulse.md +24 -0
- package/schedules/triggers/quarterly-self-assessment.md +54 -0
- package/schedules/triggers/weekly-engineering-health.md +37 -0
- package/schedules/triggers/weekly-execution.md +65 -0
- package/schedules/triggers/weekly-hiring.md +53 -0
- package/schedules/triggers/weekly-priorities.md +38 -0
- package/schedules/triggers/weekly-strategic-memo.md +124 -0
- package/scripts/archive-email.sh +55 -0
- package/scripts/cadence/cadence-status.mjs +36 -0
- package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
- package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
- package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
- package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
- package/scripts/ci/check-docs-accuracy.mjs +493 -0
- package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
- package/scripts/ci/check-exports-exist.mjs +140 -0
- package/scripts/ci/check-files-exist.mjs +107 -0
- package/scripts/ci/check-no-build-artifacts.mjs +111 -0
- package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
- package/scripts/ci/check-no-confidential.mjs +198 -0
- package/scripts/ci/check-no-conflict-markers.mjs +169 -0
- package/scripts/ci/check-no-residual-identity.mjs +163 -0
- package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
- package/scripts/ci/check-tarball-fidelity.mjs +205 -0
- package/scripts/ci/check-unresolved-tokens.mjs +83 -0
- package/scripts/ci/check.mjs +109 -0
- package/scripts/ci/check.test.mjs +194 -0
- package/scripts/ci/run-coverage.mjs +82 -0
- package/scripts/ci/run-tests.mjs +71 -0
- package/scripts/cloud-relay/README.md +59 -0
- package/scripts/cloud-relay/index.mjs +233 -0
- package/scripts/cloud-relay/package.json +15 -0
- package/scripts/cloud-relay/railway.json +13 -0
- package/scripts/cloud-relay/voice/README.md +94 -0
- package/scripts/cloud-relay/voice/package-lock.json +39 -0
- package/scripts/cloud-relay/voice/package.json +16 -0
- package/scripts/cloud-relay/voice/railway.json +13 -0
- package/scripts/cloud-relay/voice/server.mjs +532 -0
- package/scripts/collective/hook-runner.mjs +211 -0
- package/scripts/collective/hook-runner.test.mjs +90 -0
- package/scripts/collective/org-pulse.mjs +72 -0
- package/scripts/collective/org-sync.mjs +61 -0
- package/scripts/collective/recall.mjs +45 -0
- package/scripts/collective/who.mjs +30 -0
- package/scripts/comms-monitor.sh +288 -0
- package/scripts/configure-whatsapp-sandbox.sh +201 -0
- package/scripts/continuous-monitor.sh +91 -0
- package/scripts/cost/fleet-digest.mjs +407 -0
- package/scripts/cost/fleet-digest.test.mjs +207 -0
- package/scripts/cost/track-claude-usage.mjs +169 -0
- package/scripts/daemon/agent-daemon.mjs +989 -0
- package/scripts/daemon/agent-daemon.test.mjs +525 -0
- package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
- package/scripts/daemon/cadence-consumer.mjs +1080 -0
- package/scripts/daemon/cadence-consumer.test.mjs +770 -0
- package/scripts/daemon/cadence-handlers.mjs +1121 -0
- package/scripts/daemon/cadence-handlers.test.mjs +617 -0
- package/scripts/daemon/classifier.mjs +704 -0
- package/scripts/daemon/classifier.test.mjs +238 -0
- package/scripts/daemon/classify-kind.mjs +54 -0
- package/scripts/daemon/classify-kind.test.mjs +40 -0
- package/scripts/daemon/context-compiler.mjs +605 -0
- package/scripts/daemon/context-compiler.test.mjs +300 -0
- package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
- package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
- package/scripts/daemon/dispatcher.mjs +1516 -0
- package/scripts/daemon/health.mjs +72 -0
- package/scripts/daemon/inbox-deferral.mjs +210 -0
- package/scripts/daemon/inbox-deferral.test.mjs +242 -0
- package/scripts/daemon/integration.test.mjs +149 -0
- package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
- package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
- package/scripts/daemon/launchd-wrapper.sh +91 -0
- package/scripts/daemon/lib/session-router.mjs +274 -0
- package/scripts/daemon/lib/session-router.test.mjs +295 -0
- package/scripts/daemon/maestro-daemon.mjs +275 -0
- package/scripts/daemon/prompt-builder.mjs +685 -0
- package/scripts/daemon/prompt-builder.test.mjs +213 -0
- package/scripts/daemon/responder.mjs +854 -0
- package/scripts/daemon/session-lock.mjs +721 -0
- package/scripts/daemon/session-lock.test.mjs +252 -0
- package/scripts/daemon/session-outcomes.mjs +640 -0
- package/scripts/daemon/session-outcomes.test.mjs +533 -0
- package/scripts/daemon/typing-registry.mjs +90 -0
- package/scripts/daemon/typing-registry.test.mjs +77 -0
- package/scripts/daemon/voice-webhook-server.mjs +804 -0
- package/scripts/decisions/capture-decision.mjs +116 -0
- package/scripts/disclosure_assessment.py +873 -0
- package/scripts/disclosure_boundaries.py +562 -0
- package/scripts/email-signature-principal.html +52 -0
- package/scripts/email-signature.html +60 -0
- package/scripts/email_quote_thread.py +167 -0
- package/scripts/email_thread_dedup.py +362 -0
- package/scripts/emergency-stop.sh +81 -0
- package/scripts/healthcheck.sh +116 -0
- package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
- package/scripts/hooks/block-mcp-slack-send.sh +7 -0
- package/scripts/hooks/post-action-log.sh +126 -0
- package/scripts/hooks/pre-send-audit.sh +174 -0
- package/scripts/hooks/pre-send-audit.test.mjs +215 -0
- package/scripts/hooks/session-end-log.sh +27 -0
- package/scripts/hooks/session-start-banner.sh +115 -0
- package/scripts/huddle/audio-bridge.mjs +664 -0
- package/scripts/huddle/boot-slack-cdp.sh +102 -0
- package/scripts/huddle/huddle-controller.mjs +942 -0
- package/scripts/huddle/huddle-server.mjs +1229 -0
- package/scripts/huddle/launch-slack.sh +232 -0
- package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
- package/scripts/huddle/package-lock.json +62 -0
- package/scripts/huddle/package.json +22 -0
- package/scripts/huddle/setup-audio.sh +239 -0
- package/scripts/huddle/start-call.mjs +318 -0
- package/scripts/huddle/test-pipeline.mjs +263 -0
- package/scripts/learning/consolidate-skills.mjs +72 -0
- package/scripts/learning/session-search.mjs +125 -0
- package/scripts/llm_email_dedup.py +442 -0
- package/scripts/local-triggers/generate-plists.sh +432 -0
- package/scripts/local-triggers/generate-plists.test.mjs +413 -0
- package/scripts/local-triggers/install-all.sh +49 -0
- package/scripts/local-triggers/plists/.gitkeep +0 -0
- package/scripts/local-triggers/run-trigger.sh +63 -0
- package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
- package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
- package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
- package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
- package/scripts/maintenance/backup-to-cloud.sh +124 -0
- package/scripts/maintenance/health-check.sh +377 -0
- package/scripts/media-generation/README.md +105 -0
- package/scripts/media-generation/gemini-image-client.mjs +173 -0
- package/scripts/media-generation/generate-assets.mjs +289 -0
- package/scripts/media-generation/veo-video-client.mjs +219 -0
- package/scripts/org/send-orgmail.mjs +227 -0
- package/scripts/outbound-dedup-cleanup.sh +43 -0
- package/scripts/outbound-dedup.sh +477 -0
- package/scripts/outbound_dedup.py +115 -0
- package/scripts/parse-voice-transcript.mjs +481 -0
- package/scripts/pdf-generation/README.md +63 -0
- package/scripts/pdf-generation/build-document.mjs +247 -0
- package/scripts/pdf-generation/templates/board-pack.latex +136 -0
- package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
- package/scripts/pdf-generation/templates/memo.latex +114 -0
- package/scripts/poll-slack-events.sh +35 -0
- package/scripts/poller/calendar-poller.mjs +12 -0
- package/scripts/poller/gmail-poller.mjs +192 -0
- package/scripts/poller/imap-client.mjs +289 -0
- package/scripts/poller/inbox-scan-poller.mjs +156 -0
- package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
- package/scripts/poller/index.mjs +73 -0
- package/scripts/poller/intra-session-check.mjs +285 -0
- package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
- package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
- package/scripts/poller/secondary-gmail-poller.mjs +132 -0
- package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
- package/scripts/poller/slack-poller.mjs +854 -0
- package/scripts/poller/slack-socket-mode.mjs +917 -0
- package/scripts/poller/slack-socket-mode.test.mjs +753 -0
- package/scripts/poller/trigger.mjs +75 -0
- package/scripts/poller/utils.mjs +371 -0
- package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
- package/scripts/poller/voice-poller.mjs +236 -0
- package/scripts/poller-launchd/install.sh +66 -0
- package/scripts/poller-launchd/poller.plist.template +40 -0
- package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
- package/scripts/post-interaction-indexer.py +1598 -0
- package/scripts/pre-draft-context.py +994 -0
- package/scripts/pre_draft_lookup.py +258 -0
- package/scripts/rag/build-index.mjs +47 -0
- package/scripts/rag/ingest.mjs +111 -0
- package/scripts/rag/search.mjs +119 -0
- package/scripts/rag-indexer.py +629 -0
- package/scripts/restore-from-backup.sh +248 -0
- package/scripts/restore-from-backup.test.mjs +178 -0
- package/scripts/resume-operations.sh +80 -0
- package/scripts/search-secondary-inbox.py +181 -0
- package/scripts/secondary-inbox-poller.py +437 -0
- package/scripts/self-optimization/compute-metrics.py +398 -0
- package/scripts/send-email-as-principal.py +369 -0
- package/scripts/send-email-threaded.py +392 -0
- package/scripts/send-email-with-attachment.py +377 -0
- package/scripts/send-email.sh +131 -0
- package/scripts/send-sms.sh +175 -0
- package/scripts/send-whatsapp.sh +292 -0
- package/scripts/session-start.sh +106 -0
- package/scripts/setup/boot-claude-session.sh +94 -0
- package/scripts/setup/configure-macos.sh +674 -0
- package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
- package/scripts/setup/configure-voice-tunnel.mjs +182 -0
- package/scripts/setup/generate-agent-env.mjs +92 -0
- package/scripts/setup/generate-agent-package-json.mjs +222 -0
- package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
- package/scripts/setup/generate-autonomy.mjs +60 -0
- package/scripts/setup/generate-backlog.mjs +101 -0
- package/scripts/setup/generate-cadences.mjs +92 -0
- package/scripts/setup/generate-capability.mjs +162 -0
- package/scripts/setup/generate-charter.mjs +76 -0
- package/scripts/setup/generate-comms.mjs +59 -0
- package/scripts/setup/generate-company.mjs +92 -0
- package/scripts/setup/init-agent.sh +547 -0
- package/scripts/setup/init-agent.test.mjs +151 -0
- package/scripts/setup/init-archetype.mjs +74 -0
- package/scripts/setup/init-backup.mjs +54 -0
- package/scripts/setup/init-cadence-bus.mjs +60 -0
- package/scripts/setup/init-channel-bus.mjs +46 -0
- package/scripts/setup/init-cost-tracking.mjs +45 -0
- package/scripts/setup/init-decision-capture.mjs +66 -0
- package/scripts/setup/init-known-agents.mjs +57 -0
- package/scripts/setup/init-learning.mjs +70 -0
- package/scripts/setup/init-memory-executive.mjs +45 -0
- package/scripts/setup/init-model-router.mjs +124 -0
- package/scripts/setup/init-rag.mjs +174 -0
- package/scripts/setup/init-session-router.mjs +38 -0
- package/scripts/setup/init-slack-socket-mode.mjs +260 -0
- package/scripts/setup/init-telegram.mjs +165 -0
- package/scripts/setup/init-voice-realtime.mjs +204 -0
- package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
- package/scripts/setup/install-dev-tools.sh +150 -0
- package/scripts/setup/lib/install-plist.mjs +95 -0
- package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
- package/scripts/setup/render-environment-yaml.mjs +133 -0
- package/scripts/slack-events-ctl.sh +177 -0
- package/scripts/slack-events-server.mjs +1045 -0
- package/scripts/slack-react.mjs +89 -0
- package/scripts/slack-responded.sh +232 -0
- package/scripts/slack-send.sh +287 -0
- package/scripts/slack-typing.mjs +196 -0
- package/scripts/slack-upload-v2.py +95 -0
- package/scripts/sms-handler.mjs +450 -0
- package/scripts/spawn-session.sh +120 -0
- package/scripts/sync-protocol.mjs +217 -0
- package/scripts/system-verify.sh +184 -0
- package/scripts/test-email-thread-dedup.py +239 -0
- package/scripts/test-information-barriers.py +484 -0
- package/scripts/test-llm-email-dedup.py +251 -0
- package/scripts/test-pre-draft-integration.py +203 -0
- package/scripts/test-rag-phase2.sh +442 -0
- package/scripts/test-rag-search.sh +251 -0
- package/scripts/test-voice-parser.mjs +316 -0
- package/scripts/user-context-search.py +659 -0
- package/scripts/validate_outbound.py +1504 -0
- package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
- package/scripts/watchdog/force-reboot.sh +157 -0
- package/scripts/watchdog/memory-watchdog.sh +473 -0
- package/scripts/whatsapp-handler.mjs +538 -0
- package/teams/desktop-operations.yaml +34 -0
- package/teams/executive-office.yaml +27 -0
- package/teams/legal-and-regulatory.yaml +24 -0
- package/teams/platform-and-engineering.yaml +23 -0
- package/teams/strategy-and-growth.yaml +29 -0
- package/workflows/continuous/backlog-executor.yaml +141 -0
- package/workflows/continuous/inbound-monitor.yaml +168 -0
- package/workflows/daily/applicant-triage.yaml +197 -0
- package/workflows/daily/comms-triage.yaml +80 -0
- package/workflows/daily/evening-wrap.yaml +105 -0
- package/workflows/daily/morning-brief.yaml +164 -0
- package/workflows/daily/slack-followup-sweep.yaml +87 -0
- package/workflows/event-driven/README.md +50 -0
- package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
- package/workflows/event-driven/pr-review.yaml +107 -0
- package/workflows/monthly/board-readiness.yaml +76 -0
- package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
- package/workflows/session-protocol.md +171 -0
- package/workflows/weekly/engineering-health.yaml +154 -0
- package/workflows/weekly/hiring-review.yaml +169 -0
- package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
- package/workflows/weekly/strategic-memo.yaml +79 -0
package/lib/org/mesh.mjs
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/org/mesh.mjs — the agent's RUNTIME membership of the Cohort org mesh.
|
|
3
|
+
*
|
|
4
|
+
* THE GAP this closes: the Cohort server exists and lib/org/client.mjs can talk
|
|
5
|
+
* to it, but nothing made an agent actually JOIN the mesh at runtime — it never
|
|
6
|
+
* registered itself, never presence-beat, and never acted on the server's
|
|
7
|
+
* directives (the kill switch, policy-stale nudges, resync). connectOrgMesh wires
|
|
8
|
+
* that in at daemon boot:
|
|
9
|
+
*
|
|
10
|
+
* 1. register() — publish this agent's directory entry at boot (idempotent).
|
|
11
|
+
* 2. presence-beat loop (~30s) — collect the SHARED STATUS SNAPSHOT
|
|
12
|
+
* (lib/telemetry/collect.collectStatus) and ride it on the beat as
|
|
13
|
+
* `params.status` (fail-open: a collector error beats WITHOUT status, never
|
|
14
|
+
* breaks the beat); a critical alert in that snapshot also escalates locally
|
|
15
|
+
* (notify the operator). Then call presence.beat and ACT on the returned
|
|
16
|
+
* directives[] (and on an error-frame `directive`, e.g. when a deactivated
|
|
17
|
+
* token is rejected at auth):
|
|
18
|
+
* - "halt" → trip the local kill switch: write .emergency-stop and
|
|
19
|
+
* signal the daemon to stop (requestStop()).
|
|
20
|
+
* - "rotate_token" → log + drop a re-pair flag (state/org/repair-needed).
|
|
21
|
+
* - "policy_stale" → re-fetch + re-verify the signed policy bundle
|
|
22
|
+
* (lib/org/policy.fetchAndApply against the PINNED root).
|
|
23
|
+
* - "resync" → re-fetch the directory (client.fetchDirectory) into the
|
|
24
|
+
* local peers cache (state/org/peers/<id>.json).
|
|
25
|
+
* 3. stop() — clears the interval so the daemon can shut the mesh down cleanly.
|
|
26
|
+
*
|
|
27
|
+
* FAIL-OPEN by design (mirrors lib/org/client): if the org is disabled
|
|
28
|
+
* connectOrgMesh is a no-op; if the org is unreachable every step swallows the
|
|
29
|
+
* failure and the daemon keeps running standalone. Nothing here ever throws past
|
|
30
|
+
* the boundary — a mesh problem must never take the agent down.
|
|
31
|
+
*
|
|
32
|
+
* G16 (zero-LLM-in-the-coordination-loop): pure HTTP + signature verify + file
|
|
33
|
+
* I/O. ZERO LLM calls.
|
|
34
|
+
*
|
|
35
|
+
* Node builtins only. The clock (`now`), interval scheduler (`setInterval`),
|
|
36
|
+
* `fetchImpl`, and the org `client` are all injectable for deterministic tests.
|
|
37
|
+
*
|
|
38
|
+
* @module lib/org/mesh
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
"use strict";
|
|
42
|
+
|
|
43
|
+
import { join, resolve } from "node:path";
|
|
44
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
45
|
+
|
|
46
|
+
import * as defaultClient from "./client.mjs";
|
|
47
|
+
import * as policy from "./policy.mjs";
|
|
48
|
+
import { assembleSelfEntry } from "./registry.mjs";
|
|
49
|
+
import {
|
|
50
|
+
maybeRefresh,
|
|
51
|
+
currentToolsetVersion,
|
|
52
|
+
writeIntegrationToolsToDisk,
|
|
53
|
+
} from "./integration-tools.mjs";
|
|
54
|
+
import { collectStatus as defaultCollectStatus } from "../telemetry/collect.mjs";
|
|
55
|
+
import { hasCritical } from "../telemetry/alerts.mjs";
|
|
56
|
+
|
|
57
|
+
/** How often to presence-beat (ms). Matches the server's liveness expectation. */
|
|
58
|
+
export const DEFAULT_BEAT_MS = 30_000;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A directive we recognise → its handler. Anything else is ignored (forward-
|
|
62
|
+
* compatible). `toolset_changed` (SP5) forces an immediate integration-tool
|
|
63
|
+
* refresh ahead of the 30s poll; hq MAY later surface it as a presence.beat
|
|
64
|
+
* directive — until then the per-beat poll (refreshIntegrationTools, below)
|
|
65
|
+
* covers it, and this entry means the moment hq emits the frame it Just Works.
|
|
66
|
+
*/
|
|
67
|
+
const KNOWN_DIRECTIVES = new Set([
|
|
68
|
+
"halt",
|
|
69
|
+
"rotate_token",
|
|
70
|
+
"policy_stale",
|
|
71
|
+
"resync",
|
|
72
|
+
"toolset_changed",
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
function logInfo(msg) { try { console.log(`[org-mesh] ${msg}`); } catch { /* never throw from logging */ } }
|
|
76
|
+
function logWarn(msg) { try { console.warn(`[org-mesh] ${msg}`); } catch { /* never throw from logging */ } }
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default stop signal: drop the daemon out of its run loop. The daemon's own
|
|
80
|
+
* SIGTERM handler clears the cadence consumer + this mesh handle. We send to
|
|
81
|
+
* ourselves (process group leader); fail-open if signalling isn't permitted.
|
|
82
|
+
*/
|
|
83
|
+
function defaultRequestStop() {
|
|
84
|
+
try { process.kill(process.pid, "SIGTERM"); } catch { /* fail-open */ }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Trip the local kill switch in response to a "halt" directive.
|
|
89
|
+
* 1. Write `.emergency-stop` (the same flag emergency-stop.sh drops) so a
|
|
90
|
+
* launchd restart is refused at the boot gate — the halt is durable across
|
|
91
|
+
* a crash/restart, not just this process.
|
|
92
|
+
* 2. requestStop() — signal the daemon to exit cleanly NOW.
|
|
93
|
+
* Idempotent + fail-open. Never throws.
|
|
94
|
+
*/
|
|
95
|
+
function tripKillSwitch(agentRoot, requestStop, now) {
|
|
96
|
+
const at = new Date((typeof now === "function" ? now() : Date.now())).toISOString();
|
|
97
|
+
try {
|
|
98
|
+
writeFileSync(join(agentRoot, ".emergency-stop"), `${at}\n`);
|
|
99
|
+
logWarn(`HALT directive received — wrote .emergency-stop (${at}) and stopping`);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
logWarn(`HALT directive received — failed to write .emergency-stop (${err && err.message}); stopping anyway`);
|
|
102
|
+
}
|
|
103
|
+
try { requestStop(); } catch { /* fail-open */ }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Re-pair flag in response to a "rotate_token" directive: the agent's token is
|
|
108
|
+
* expired/rotated and a human must re-pair it. We don't auto-pair (that needs a
|
|
109
|
+
* human-issued code); we drop a durable flag + log so the operator/doctor sees it.
|
|
110
|
+
* Fail-open.
|
|
111
|
+
*/
|
|
112
|
+
function flagRepairNeeded(agentRoot, now) {
|
|
113
|
+
const at = new Date((typeof now === "function" ? now() : Date.now())).toISOString();
|
|
114
|
+
try {
|
|
115
|
+
mkdirSync(join(agentRoot, "state", "org"), { recursive: true });
|
|
116
|
+
writeFileSync(
|
|
117
|
+
join(agentRoot, "state", "org", "repair-needed.json"),
|
|
118
|
+
JSON.stringify({ reason: "rotate_token", at }, null, 2),
|
|
119
|
+
);
|
|
120
|
+
logWarn(`rotate_token directive — token rotation required; flagged state/org/repair-needed.json (${at})`);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
logWarn(`rotate_token directive — failed to flag re-pair (${err && err.message})`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Locally escalate a critical telemetry alert to the operator: log it loudly and
|
|
128
|
+
* drop a durable flag (state/org/alert-critical.json) the operator/doctor can see,
|
|
129
|
+
* mirroring flagRepairNeeded. Idempotent overwrite + fail-open; never throws. This
|
|
130
|
+
* is the local half of "a critical alert escalates" — the snapshot also rides the
|
|
131
|
+
* beat so the server/directory sees it.
|
|
132
|
+
*/
|
|
133
|
+
function escalateCriticalAlerts(agentRoot, alerts, now) {
|
|
134
|
+
const at = new Date((typeof now === "function" ? now() : Date.now())).toISOString();
|
|
135
|
+
const crit = (Array.isArray(alerts) ? alerts : []).filter((a) => a && a.severity === "critical");
|
|
136
|
+
if (crit.length === 0) return;
|
|
137
|
+
for (const a of crit) {
|
|
138
|
+
logWarn(`CRITICAL telemetry alert [${a.id || a.kind || "?"}]: ${a.detail || ""}`);
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
mkdirSync(join(agentRoot, "state", "org"), { recursive: true });
|
|
142
|
+
writeFileSync(
|
|
143
|
+
join(agentRoot, "state", "org", "alert-critical.json"),
|
|
144
|
+
JSON.stringify({ at, alerts: crit }, null, 2),
|
|
145
|
+
);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
logWarn(`failed to persist critical alert flag (${err && err.message})`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Collect the SHARED STATUS SNAPSHOT for this beat, fully fail-open: any collector
|
|
153
|
+
* error yields `undefined` so the beat goes out WITHOUT a status (never broken).
|
|
154
|
+
* Returns the snapshot or undefined.
|
|
155
|
+
*/
|
|
156
|
+
async function collectBeatStatus(ctx) {
|
|
157
|
+
try {
|
|
158
|
+
const fn = typeof ctx.collectStatus === "function" ? ctx.collectStatus : defaultCollectStatus;
|
|
159
|
+
const status = await fn({ agentRoot: ctx.agentRoot, now: ctx.now });
|
|
160
|
+
return status && typeof status === "object" ? status : undefined;
|
|
161
|
+
} catch (err) {
|
|
162
|
+
logWarn(`status collection failed (${err && err.message}) — beating without status`);
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Re-fetch the org directory and persist each peer into the local peers cache
|
|
169
|
+
* (state/org/peers/<id>.json), which registry.readDirectory merges. In response
|
|
170
|
+
* to a "resync" directive. Returns the count written. Fail-open.
|
|
171
|
+
*/
|
|
172
|
+
async function resyncDirectory(o) {
|
|
173
|
+
const { agentRoot, client, cfg, fetchImpl } = o;
|
|
174
|
+
let peers = [];
|
|
175
|
+
try {
|
|
176
|
+
peers = await client.fetchDirectory({ cfg, fetchImpl });
|
|
177
|
+
} catch { peers = []; }
|
|
178
|
+
if (!Array.isArray(peers) || peers.length === 0) {
|
|
179
|
+
logInfo("resync directive — directory empty/unreachable, peers cache left as-is");
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
const peersDir = join(agentRoot, "state", "org", "peers");
|
|
183
|
+
let written = 0;
|
|
184
|
+
try { mkdirSync(peersDir, { recursive: true }); } catch { /* fail-open */ }
|
|
185
|
+
for (const p of peers) {
|
|
186
|
+
if (!p || !p.id) continue;
|
|
187
|
+
const id = String(p.id).toLowerCase().replace(/[^a-z0-9._-]/gi, "_");
|
|
188
|
+
if (!id) continue;
|
|
189
|
+
try {
|
|
190
|
+
writeFileSync(join(peersDir, `${id}.json`), JSON.stringify({ ...p, source: "synced" }, null, 2));
|
|
191
|
+
written += 1;
|
|
192
|
+
} catch { /* skip this peer, keep going */ }
|
|
193
|
+
}
|
|
194
|
+
logInfo(`resync directive — refreshed ${written} peer(s) into the local cache`);
|
|
195
|
+
return written;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Refetch + re-verify the signed policy bundle(s) against the PINNED trust root,
|
|
200
|
+
* in response to a "policy_stale" directive. Quarantines an unverifiable bundle
|
|
201
|
+
* (policy.fetchAndApply's contract); leaves the last-good cache in place. We use
|
|
202
|
+
* handlePolicyStale so all currently-cached kinds converge; it delegates to
|
|
203
|
+
* fetchAndApply per kind. Fail-open.
|
|
204
|
+
*/
|
|
205
|
+
async function refreshPolicy(o) {
|
|
206
|
+
const { agentRoot, cfg, fetchImpl, now } = o;
|
|
207
|
+
try {
|
|
208
|
+
const r = await policy.handlePolicyStale({ cfg, agentRoot, fetchImpl, now });
|
|
209
|
+
logInfo(`policy_stale directive — refreshed ${r.refreshed} bundle(s)`);
|
|
210
|
+
return r;
|
|
211
|
+
} catch (err) {
|
|
212
|
+
logWarn(`policy_stale directive — refresh failed (${err && err.message})`);
|
|
213
|
+
return { refreshed: 0, results: [] };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Refresh the workspace's GRANTED integration tools (SP5) and, when the version
|
|
219
|
+
* changed, persist them to state/org/toolset.json so per-session cohort-mcp
|
|
220
|
+
* subprocesses + the native tool snapshot pick up the new set WITHOUT a daemon
|
|
221
|
+
* restart. Cheap: one `integration.toolsetVersion` poll, refetching the manifest
|
|
222
|
+
* only on a version change. Fully fail-open — a refresh hiccup must never break
|
|
223
|
+
* the beat that calls it. Returns the cache (or null on a caught failure).
|
|
224
|
+
* @param {object} ctx the shared loop context
|
|
225
|
+
*/
|
|
226
|
+
async function refreshIntegrationTools(ctx) {
|
|
227
|
+
try {
|
|
228
|
+
const prev = currentToolsetVersion();
|
|
229
|
+
const call = (method, params) =>
|
|
230
|
+
ctx.client.call(method, params, {
|
|
231
|
+
base: ctx.base,
|
|
232
|
+
token: ctx.token,
|
|
233
|
+
orgId: ctx.orgId,
|
|
234
|
+
fetchImpl: ctx.fetchImpl,
|
|
235
|
+
});
|
|
236
|
+
const cache = await maybeRefresh({
|
|
237
|
+
call,
|
|
238
|
+
agentMemberId: ctx.agentMemberId,
|
|
239
|
+
now: ctx.now,
|
|
240
|
+
});
|
|
241
|
+
if (cache.version !== prev) {
|
|
242
|
+
writeIntegrationToolsToDisk(ctx.agentRoot, {
|
|
243
|
+
version: cache.version,
|
|
244
|
+
tools: cache.tools,
|
|
245
|
+
});
|
|
246
|
+
logInfo(
|
|
247
|
+
`integration tools refreshed → v${cache.version} (${cache.tools.length} tool(s)) — wrote state/org/toolset.json`,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return cache;
|
|
251
|
+
} catch (err) {
|
|
252
|
+
logWarn(`integration refresh failed (${err && err.message}) — keeping last-good tools`);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Act on one directive. Pure dispatch; each handler is independently fail-open.
|
|
259
|
+
* @param {string} directive one of KNOWN_DIRECTIVES
|
|
260
|
+
* @param {object} ctx the shared loop context
|
|
261
|
+
*/
|
|
262
|
+
async function handleDirective(directive, ctx) {
|
|
263
|
+
switch (directive) {
|
|
264
|
+
case "halt":
|
|
265
|
+
tripKillSwitch(ctx.agentRoot, ctx.requestStop, ctx.now);
|
|
266
|
+
// Once halted, stop beating: the daemon is going down.
|
|
267
|
+
ctx.stop();
|
|
268
|
+
return;
|
|
269
|
+
case "rotate_token":
|
|
270
|
+
flagRepairNeeded(ctx.agentRoot, ctx.now);
|
|
271
|
+
return;
|
|
272
|
+
case "policy_stale":
|
|
273
|
+
await refreshPolicy(ctx);
|
|
274
|
+
return;
|
|
275
|
+
case "resync":
|
|
276
|
+
await resyncDirectory(ctx);
|
|
277
|
+
return;
|
|
278
|
+
case "toolset_changed":
|
|
279
|
+
// Force an immediate refresh + disk write, ahead of the 30s poll.
|
|
280
|
+
await refreshIntegrationTools(ctx);
|
|
281
|
+
return;
|
|
282
|
+
default:
|
|
283
|
+
return; // forward-compatible: ignore unknown directives
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Extract the directive list from a presence.beat outcome. Handles both shapes:
|
|
289
|
+
* - success res frame: { ok:true, result:{ directives:[...] } }
|
|
290
|
+
* - error res frame (e.g. a deactivated token rejected at auth):
|
|
291
|
+
* { ok:false, error:{ directive:"halt", ... } }
|
|
292
|
+
* Returns a de-duped array limited to KNOWN_DIRECTIVES. Never throws.
|
|
293
|
+
*/
|
|
294
|
+
function extractDirectives(frame) {
|
|
295
|
+
const out = new Set();
|
|
296
|
+
try {
|
|
297
|
+
if (frame && frame.ok && frame.result && Array.isArray(frame.result.directives)) {
|
|
298
|
+
for (const d of frame.result.directives) if (KNOWN_DIRECTIVES.has(d)) out.add(d);
|
|
299
|
+
}
|
|
300
|
+
if (frame && frame.ok === false && frame.error && KNOWN_DIRECTIVES.has(frame.error.directive)) {
|
|
301
|
+
out.add(frame.error.directive);
|
|
302
|
+
}
|
|
303
|
+
} catch { /* fail-open */ }
|
|
304
|
+
return [...out];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Run a single presence-beat: call presence.beat, read the directives, and act.
|
|
309
|
+
* Exported (via _internals) for direct testing without the interval timing.
|
|
310
|
+
* Fully fail-open. Never throws.
|
|
311
|
+
* @param {object} ctx the shared loop context
|
|
312
|
+
*/
|
|
313
|
+
async function beatOnce(ctx) {
|
|
314
|
+
// Collect the status snapshot first (fail-open: undefined => beat without it).
|
|
315
|
+
const status = await collectBeatStatus(ctx);
|
|
316
|
+
// A critical alert escalates locally too (notify the operator), independent of
|
|
317
|
+
// whether the org is reachable.
|
|
318
|
+
if (status && hasCritical(status.alerts)) {
|
|
319
|
+
try { escalateCriticalAlerts(ctx.agentRoot, status.alerts, ctx.now); } catch { /* fail-open */ }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let frame;
|
|
323
|
+
try {
|
|
324
|
+
const params = { focus: ctx.beatFocus || undefined };
|
|
325
|
+
if (status) params.status = status; // rides presence.beat params (no protocol change)
|
|
326
|
+
frame = await ctx.client.presenceBeat(
|
|
327
|
+
params,
|
|
328
|
+
{ base: ctx.base, token: ctx.token, idempotencyKey: undefined, fetchImpl: ctx.fetchImpl },
|
|
329
|
+
);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
logWarn(`presence beat failed (${err && err.message}) — org may be down, continuing standalone`);
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
334
|
+
const directives = extractDirectives(frame);
|
|
335
|
+
for (const d of directives) {
|
|
336
|
+
try { await handleDirective(d, ctx); } catch { /* each directive is independently fail-open */ }
|
|
337
|
+
if (ctx.stopped) break; // a halt stopped us mid-list
|
|
338
|
+
}
|
|
339
|
+
// Poll the granted integration tools once per beat (SP5): cheap version check,
|
|
340
|
+
// refetch + disk-write only on a change. Skipped once halted. Fail-open — the
|
|
341
|
+
// refresh never affects the beat's returned directives. A `toolset_changed`
|
|
342
|
+
// directive above already forced this ahead of the poll when hq pushes one.
|
|
343
|
+
if (!ctx.stopped) await refreshIntegrationTools(ctx);
|
|
344
|
+
return directives;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Join the org mesh at runtime. Idempotent registration at boot + a presence-beat
|
|
349
|
+
* loop that acts on server directives. Returns a handle with stop().
|
|
350
|
+
*
|
|
351
|
+
* No-op (returns an inert handle) when the org integration is disabled. Never
|
|
352
|
+
* throws — every failure path is swallowed so a mesh problem can't take the
|
|
353
|
+
* daemon down.
|
|
354
|
+
*
|
|
355
|
+
* @param {object} o
|
|
356
|
+
* @param {string} o.agentRoot the agent repo root
|
|
357
|
+
* @param {object} o.cfg the collective/agent config
|
|
358
|
+
* @param {Function} [o.fetchImpl] injected fetch (tests/back-compat)
|
|
359
|
+
* @param {Function} [o.now] injected clock () => ms
|
|
360
|
+
* @param {Function} [o.setInterval] injected interval scheduler
|
|
361
|
+
* @param {Function} [o.clearInterval] injected interval clearer
|
|
362
|
+
* @param {object} [o.client] injected org client (defaults to lib/org/client)
|
|
363
|
+
* @param {Function}[o.requestStop] injected stop signal (defaults to SIGTERM self)
|
|
364
|
+
* @param {number} [o.beatMs] beat interval (defaults to DEFAULT_BEAT_MS)
|
|
365
|
+
* @param {Function}[o.collectStatus] injected status collector (defaults to lib/telemetry/collect)
|
|
366
|
+
* @returns {Promise<{stop:Function, isEnabled:boolean}>}
|
|
367
|
+
*/
|
|
368
|
+
export async function connectOrgMesh(o = {}) {
|
|
369
|
+
const client = o.client || defaultClient;
|
|
370
|
+
const cfg = o.cfg || {};
|
|
371
|
+
|
|
372
|
+
// No-op when the org is disabled. Returns an inert handle so the caller's
|
|
373
|
+
// shutdown path (handle.stop()) is always safe to call.
|
|
374
|
+
if (!client.isEnabled(cfg)) {
|
|
375
|
+
return { stop() {}, isEnabled: false };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const agentRoot = resolve(o.agentRoot || process.env.AGENT_ROOT || process.env.AGENT_DIR || process.cwd());
|
|
379
|
+
const now = typeof o.now === "function" ? o.now : Date.now;
|
|
380
|
+
const setIntervalFn = typeof o.setInterval === "function" ? o.setInterval : setInterval;
|
|
381
|
+
const clearIntervalFn = typeof o.clearInterval === "function" ? o.clearInterval : clearInterval;
|
|
382
|
+
const beatMs = Number.isFinite(o.beatMs) && o.beatMs > 0 ? o.beatMs : DEFAULT_BEAT_MS;
|
|
383
|
+
const requestStop = typeof o.requestStop === "function" ? o.requestStop : defaultRequestStop;
|
|
384
|
+
|
|
385
|
+
let conn = {};
|
|
386
|
+
try { conn = client.configFromAgent(cfg) || {}; } catch { conn = {}; }
|
|
387
|
+
|
|
388
|
+
const ctx = {
|
|
389
|
+
agentRoot,
|
|
390
|
+
cfg,
|
|
391
|
+
client,
|
|
392
|
+
fetchImpl: o.fetchImpl,
|
|
393
|
+
now,
|
|
394
|
+
requestStop,
|
|
395
|
+
base: conn.base,
|
|
396
|
+
token: conn.token,
|
|
397
|
+
orgId: conn.orgId,
|
|
398
|
+
// The seat whose GRANTED tools we fetch (SP5). Set from the registration
|
|
399
|
+
// entry id below; absent → the workspace-wide granted set (hq's fallback).
|
|
400
|
+
agentMemberId: null,
|
|
401
|
+
beatFocus: o.beatFocus || null,
|
|
402
|
+
collectStatus: typeof o.collectStatus === "function" ? o.collectStatus : defaultCollectStatus,
|
|
403
|
+
timer: null,
|
|
404
|
+
stopped: false,
|
|
405
|
+
stop: null, // set below
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
ctx.stop = function stop() {
|
|
409
|
+
if (ctx.stopped) return;
|
|
410
|
+
ctx.stopped = true;
|
|
411
|
+
if (ctx.timer != null) {
|
|
412
|
+
try { clearIntervalFn(ctx.timer); } catch { /* fail-open */ }
|
|
413
|
+
ctx.timer = null;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// 1. Register at boot (idempotent). Best-effort: a failure just means we're not
|
|
418
|
+
// in the directory yet; the next presence-beat / org-sync cadence retries.
|
|
419
|
+
try {
|
|
420
|
+
const entry = await assembleSelfEntry(agentRoot, {});
|
|
421
|
+
if (entry && entry.id) {
|
|
422
|
+
// Fetch THIS seat's granted tools (SP5); falls back to workspace-wide when absent.
|
|
423
|
+
ctx.agentMemberId = entry.id;
|
|
424
|
+
await client.register(entry, {
|
|
425
|
+
base: conn.base,
|
|
426
|
+
token: conn.token,
|
|
427
|
+
idempotencyKey: `registry.register:${entry.id}`,
|
|
428
|
+
fetchImpl: o.fetchImpl,
|
|
429
|
+
});
|
|
430
|
+
logInfo(`registered ${entry.id} with the org mesh`);
|
|
431
|
+
}
|
|
432
|
+
} catch (err) {
|
|
433
|
+
logWarn(`registration failed (${err && err.message}) — continuing; presence-beat will retry`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// 2. Presence-beat loop. The first beat fires on the interval (not immediately)
|
|
437
|
+
// so boot isn't blocked on a second round-trip; tests drive it explicitly.
|
|
438
|
+
ctx.timer = setIntervalFn(() => { void beatOnce(ctx); }, beatMs);
|
|
439
|
+
// Don't let the beat timer keep the process alive on its own (Node only).
|
|
440
|
+
try { if (ctx.timer && typeof ctx.timer.unref === "function") ctx.timer.unref(); } catch { /* */ }
|
|
441
|
+
|
|
442
|
+
return { stop: ctx.stop, isEnabled: true, _ctx: ctx };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export const _internals = {
|
|
446
|
+
beatOnce,
|
|
447
|
+
extractDirectives,
|
|
448
|
+
handleDirective,
|
|
449
|
+
tripKillSwitch,
|
|
450
|
+
flagRepairNeeded,
|
|
451
|
+
resyncDirectory,
|
|
452
|
+
refreshPolicy,
|
|
453
|
+
refreshIntegrationTools,
|
|
454
|
+
collectBeatStatus,
|
|
455
|
+
escalateCriticalAlerts,
|
|
456
|
+
KNOWN_DIRECTIVES,
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
export default { connectOrgMesh, DEFAULT_BEAT_MS, _internals };
|