@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
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* configure-twilio-sip-trunk.mjs — Provision a Twilio Elastic SIP Trunk
|
|
4
|
+
* that bridges PSTN voice traffic to OpenAI's native SIP connector,
|
|
5
|
+
* enabling live conversational outbound calls (placeOutboundCall) and
|
|
6
|
+
* inbound calls (when a phone rings → Twilio routes → OpenAI →
|
|
7
|
+
* realtime.call.incoming webhook fires on our voice-webhook-server).
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/setup/configure-twilio-sip-trunk.mjs --openai-project=proj_xxxxxxxxxxxxxxxxx
|
|
11
|
+
*
|
|
12
|
+
* What it does:
|
|
13
|
+
* 1. Verifies TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN are set.
|
|
14
|
+
* 2. Creates a new Twilio Elastic SIP Trunk via POST /Trunks.
|
|
15
|
+
* 3. Sets the Origination URI to OpenAI's SIP endpoint:
|
|
16
|
+
* sip:<project-id>@sip.api.openai.com;transport=tls
|
|
17
|
+
* 4. Writes TWILIO_SIP_TRUNK_SID + TWILIO_SIP_TRUNK_DOMAIN to .env.
|
|
18
|
+
* 5. Prints the OpenAI-dashboard steps the operator must complete to
|
|
19
|
+
* whitelist the Twilio trunk on the OpenAI side.
|
|
20
|
+
*
|
|
21
|
+
* Idempotency: if a trunk with the same `friendly_name` already exists,
|
|
22
|
+
* we reuse it rather than creating a duplicate.
|
|
23
|
+
*
|
|
24
|
+
* Cost: Twilio Elastic SIP Trunking is metered (per-minute, varies by
|
|
25
|
+
* country). For US: ~$0.0085/min PSTN → SIP outbound.
|
|
26
|
+
*
|
|
27
|
+
* What this does NOT do (operator must complete in OpenAI dashboard):
|
|
28
|
+
* - Whitelist Twilio's SIP origination URI in your OpenAI project's
|
|
29
|
+
* SIP settings (platform.openai.com → project → Voice / SIP).
|
|
30
|
+
* - Configure the inbound webhook URL (realtime.call.incoming) to
|
|
31
|
+
* point at $VOICE_PUBLIC_BASE_URL/voice/sip/incoming.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { fileURLToPath } from "node:url";
|
|
35
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
36
|
+
import { dirname, join, resolve } from "node:path";
|
|
37
|
+
|
|
38
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
39
|
+
const __dirname = dirname(__filename);
|
|
40
|
+
const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
|
|
41
|
+
|
|
42
|
+
const args = Object.fromEntries(
|
|
43
|
+
process.argv.slice(2)
|
|
44
|
+
.map((a) => a.replace(/^--/, "").split("="))
|
|
45
|
+
.filter((p) => p.length === 2)
|
|
46
|
+
);
|
|
47
|
+
const projectId = args["openai-project"] || process.env.OPENAI_PROJECT_ID;
|
|
48
|
+
const friendlyName = args["name"] || "maestro-openai-realtime";
|
|
49
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
50
|
+
|
|
51
|
+
const ok = (m) => process.stdout.write(`[twilio-sip] ✓ ${m}\n`);
|
|
52
|
+
const warn = (m) => process.stdout.write(`[twilio-sip] ⚠ ${m}\n`);
|
|
53
|
+
const info = (m) => process.stdout.write(`[twilio-sip] · ${m}\n`);
|
|
54
|
+
|
|
55
|
+
// ── Validate inputs ────────────────────────────────────────────────────
|
|
56
|
+
function loadEnv(p) {
|
|
57
|
+
if (!existsSync(p)) return;
|
|
58
|
+
for (const ln of readFileSync(p, "utf-8").split("\n")) {
|
|
59
|
+
const t = ln.trim();
|
|
60
|
+
if (!t || t.startsWith("#")) continue;
|
|
61
|
+
const eq = t.indexOf("=");
|
|
62
|
+
if (eq <= 0) continue;
|
|
63
|
+
const k = t.slice(0, eq).trim();
|
|
64
|
+
let v = t.slice(eq + 1).trim();
|
|
65
|
+
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
|
|
66
|
+
if (!process.env[k]) process.env[k] = v;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
loadEnv(join(AGENT_DIR, ".env"));
|
|
70
|
+
|
|
71
|
+
const sid = process.env.TWILIO_ACCOUNT_SID;
|
|
72
|
+
const token = process.env.TWILIO_AUTH_TOKEN;
|
|
73
|
+
if (!sid || !token) {
|
|
74
|
+
warn("TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN required in .env");
|
|
75
|
+
process.exit(64);
|
|
76
|
+
}
|
|
77
|
+
if (!projectId) {
|
|
78
|
+
warn("Missing --openai-project=proj_xxxxxxxxxxxxxxxxx");
|
|
79
|
+
warn("Find it at: https://platform.openai.com/settings/organization/projects");
|
|
80
|
+
process.exit(64);
|
|
81
|
+
}
|
|
82
|
+
if (!/^proj_[A-Za-z0-9]{16,}$/.test(projectId)) {
|
|
83
|
+
warn(`OpenAI project id looks malformed: ${projectId}`);
|
|
84
|
+
warn("Expected format: proj_XXXXXXXXXXXXXXXX");
|
|
85
|
+
process.exit(64);
|
|
86
|
+
}
|
|
87
|
+
ok(`Twilio account: ${sid}`);
|
|
88
|
+
ok(`OpenAI project: ${projectId}`);
|
|
89
|
+
|
|
90
|
+
const sipUri = `sip:${projectId}@sip.api.openai.com;transport=tls`;
|
|
91
|
+
ok(`SIP target: ${sipUri}`);
|
|
92
|
+
|
|
93
|
+
if (dryRun) {
|
|
94
|
+
info("--dry-run set; not creating trunk.");
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── Twilio API helper ──────────────────────────────────────────────────
|
|
99
|
+
const TRUNK_API = "https://trunking.twilio.com/v1";
|
|
100
|
+
const auth = "Basic " + Buffer.from(`${sid}:${token}`).toString("base64");
|
|
101
|
+
|
|
102
|
+
async function twilio(path, init = {}) {
|
|
103
|
+
const r = await fetch(`${TRUNK_API}${path}`, {
|
|
104
|
+
...init,
|
|
105
|
+
headers: {
|
|
106
|
+
Authorization: auth,
|
|
107
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
108
|
+
...(init.headers || {}),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const text = await r.text();
|
|
112
|
+
let data;
|
|
113
|
+
try { data = JSON.parse(text); } catch { data = { _raw: text }; }
|
|
114
|
+
if (!r.ok) {
|
|
115
|
+
throw new Error(`Twilio API ${path} → HTTP ${r.status}: ${data.message || text.slice(0, 300)}`);
|
|
116
|
+
}
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── 1. Find or create the trunk ────────────────────────────────────────
|
|
121
|
+
info("listing existing trunks for idempotency…");
|
|
122
|
+
const list = await twilio(`/Trunks?PageSize=100`);
|
|
123
|
+
let trunk = (list.trunks || []).find((t) => t.friendly_name === friendlyName);
|
|
124
|
+
|
|
125
|
+
if (trunk) {
|
|
126
|
+
ok(`reusing existing trunk: ${trunk.sid} (${trunk.domain_name || "no domain set"})`);
|
|
127
|
+
} else {
|
|
128
|
+
info(`creating new trunk "${friendlyName}"…`);
|
|
129
|
+
const params = new URLSearchParams({
|
|
130
|
+
FriendlyName: friendlyName,
|
|
131
|
+
CnamLookupEnabled: "false",
|
|
132
|
+
Transfer: "disable-all",
|
|
133
|
+
});
|
|
134
|
+
trunk = await twilio("/Trunks", { method: "POST", body: params.toString() });
|
|
135
|
+
ok(`created trunk: ${trunk.sid}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Always ensure the trunk has a meaningful domain_name. Twilio creates
|
|
139
|
+
// trunks with domain_name=null by default — only set explicitly via PUT.
|
|
140
|
+
// Without this, our placeOutboundCall() dial-target gets "null.pstn.twilio.com".
|
|
141
|
+
if (!trunk.domain_name) {
|
|
142
|
+
const safe = friendlyName.replace(/[^a-z0-9-]/gi, "-").toLowerCase().slice(0, 30);
|
|
143
|
+
const desired = `${safe}.pstn.twilio.com`;
|
|
144
|
+
info(`setting trunk domain_name=${desired}…`);
|
|
145
|
+
const params = new URLSearchParams({ DomainName: desired });
|
|
146
|
+
trunk = await twilio(`/Trunks/${trunk.sid}`, { method: "POST", body: params.toString() });
|
|
147
|
+
ok(`trunk domain set: ${trunk.domain_name}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── 2. Configure origination URL pointing at OpenAI SIP endpoint ───────
|
|
151
|
+
info("configuring origination URL → OpenAI SIP endpoint…");
|
|
152
|
+
const origList = await twilio(`/Trunks/${trunk.sid}/OriginationUrls?PageSize=10`);
|
|
153
|
+
const desiredUri = sipUri;
|
|
154
|
+
let originationUrl = (origList.origination_urls || []).find((u) => u.sip_url === desiredUri);
|
|
155
|
+
|
|
156
|
+
if (originationUrl) {
|
|
157
|
+
ok(`origination URL already pointing at OpenAI (${originationUrl.sid})`);
|
|
158
|
+
} else {
|
|
159
|
+
const params = new URLSearchParams({
|
|
160
|
+
FriendlyName: `openai-realtime-${projectId.slice(-8)}`,
|
|
161
|
+
SipUrl: desiredUri,
|
|
162
|
+
Weight: "1",
|
|
163
|
+
Priority: "1",
|
|
164
|
+
Enabled: "true",
|
|
165
|
+
});
|
|
166
|
+
originationUrl = await twilio(`/Trunks/${trunk.sid}/OriginationUrls`, {
|
|
167
|
+
method: "POST",
|
|
168
|
+
body: params.toString(),
|
|
169
|
+
});
|
|
170
|
+
ok(`created origination URL: ${originationUrl.sid}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── 3. Persist to .env ─────────────────────────────────────────────────
|
|
174
|
+
const envPath = join(AGENT_DIR, ".env");
|
|
175
|
+
let body = readFileSync(envPath, "utf-8");
|
|
176
|
+
const updates = {
|
|
177
|
+
TWILIO_SIP_TRUNK_SID: trunk.sid,
|
|
178
|
+
TWILIO_SIP_TRUNK_DOMAIN: `${trunk.domain_name}.pstn.twilio.com`,
|
|
179
|
+
OPENAI_SIP_URI: sipUri,
|
|
180
|
+
OPENAI_PROJECT_ID: projectId,
|
|
181
|
+
};
|
|
182
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
183
|
+
const re = new RegExp(`^${k}=.*$`, "m");
|
|
184
|
+
if (re.test(body)) body = body.replace(re, `${k}=${v}`);
|
|
185
|
+
else body += (body.endsWith("\n") ? "" : "\n") + `${k}=${v}\n`;
|
|
186
|
+
}
|
|
187
|
+
writeFileSync(envPath, body);
|
|
188
|
+
ok("wrote TWILIO_SIP_TRUNK_SID / DOMAIN / OPENAI_SIP_URI / PROJECT_ID to .env");
|
|
189
|
+
|
|
190
|
+
// ── 4. Print operator checklist for OpenAI side ────────────────────────
|
|
191
|
+
console.log();
|
|
192
|
+
info("=".repeat(60));
|
|
193
|
+
info("OpenAI dashboard steps to complete:");
|
|
194
|
+
info("=".repeat(60));
|
|
195
|
+
info(` 1. Open https://platform.openai.com/settings/organization/projects/${projectId}`);
|
|
196
|
+
info(` 2. Navigate to: Voice (or Real-time) → SIP settings`);
|
|
197
|
+
info(` 3. Add the Twilio trunk's termination IPs to your allow-list.`);
|
|
198
|
+
info(` Twilio public IPs vary by region; see:`);
|
|
199
|
+
info(` https://www.twilio.com/docs/sip-trunking/ip-addresses`);
|
|
200
|
+
info(` 4. Configure the inbound webhook ('realtime.call.incoming') to POST to:`);
|
|
201
|
+
const publicBase = process.env.VOICE_PUBLIC_BASE_URL || "(set VOICE_PUBLIC_BASE_URL first)";
|
|
202
|
+
info(` ${publicBase}/voice/sip/incoming`);
|
|
203
|
+
info(` 5. Save. OpenAI will fire that webhook on inbound calls; outbound`);
|
|
204
|
+
info(` calls via placeOutboundCall() will use the same SIP URI as the dial target.`);
|
|
205
|
+
console.log();
|
|
206
|
+
ok(`Trunk fully provisioned. Domain: ${trunk.domain_name}.pstn.twilio.com`);
|
|
207
|
+
info("Test outbound: agent calls place_voice_call({ to: \"+447...\", brief: \"...\" })");
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* configure-voice-tunnel.mjs — Install + run a cloudflared tunnel that
|
|
4
|
+
* exposes the local voice-webhook-server (port 3200) on a public HTTPS
|
|
5
|
+
* URL so Twilio webhooks and OpenAI's SIP webhook can reach it.
|
|
6
|
+
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
* 1. **ephemeral** (default, no args): uses cloudflared's
|
|
9
|
+
* `trycloudflare.com` quick-tunnel feature — no account required,
|
|
10
|
+
* no DNS to configure. URL changes whenever cloudflared restarts,
|
|
11
|
+
* so this is only suitable for dev/testing.
|
|
12
|
+
* 2. **named**: `--named --domain voice.northwind.ai` — uses an
|
|
13
|
+
* authenticated named tunnel routed to a custom hostname. Stable
|
|
14
|
+
* URL across restarts. Requires `cloudflared tunnel login` to
|
|
15
|
+
* have run + a domain on Cloudflare. Recommended for production.
|
|
16
|
+
*
|
|
17
|
+
* This script:
|
|
18
|
+
* 1. Verifies cloudflared is installed.
|
|
19
|
+
* 2. Generates the launchd plist from the template.
|
|
20
|
+
* 3. Loads the plist so launchd starts cloudflared.
|
|
21
|
+
* 4. Polls the cloudflared log for the public URL (ephemeral mode).
|
|
22
|
+
* 5. Writes VOICE_PUBLIC_BASE_URL to .env.
|
|
23
|
+
* 6. Restarts the voice-webhook-server so it picks up the new env var.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { dirname, join, resolve } from "node:path";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
29
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
30
|
+
|
|
31
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
const AGENT_DIR = process.env.AGENT_ROOT || process.env.AGENT_DIR || resolve(__dirname, "..", "..");
|
|
33
|
+
const MAESTRO_ROOT = process.env.MAESTRO_ROOT || resolve(__dirname, "..", "..");
|
|
34
|
+
|
|
35
|
+
const args = new Set(process.argv.slice(2));
|
|
36
|
+
const named = args.has("--named");
|
|
37
|
+
const restart = !args.has("--no-restart");
|
|
38
|
+
const domainArg = process.argv.find((a) => a.startsWith("--domain="));
|
|
39
|
+
const domain = domainArg ? domainArg.split("=")[1] : null;
|
|
40
|
+
|
|
41
|
+
const ok = (m) => process.stdout.write(`[voice-tunnel] ✓ ${m}\n`);
|
|
42
|
+
const warn = (m) => process.stdout.write(`[voice-tunnel] ⚠ ${m}\n`);
|
|
43
|
+
const info = (m) => process.stdout.write(`[voice-tunnel] · ${m}\n`);
|
|
44
|
+
|
|
45
|
+
if (named && !domain) {
|
|
46
|
+
warn("--named requires --domain=<hostname>");
|
|
47
|
+
process.exit(64);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ── 1. cloudflared installed? ──────────────────────────────────────────
|
|
51
|
+
const cfPath = ["/opt/homebrew/bin/cloudflared", "/usr/local/bin/cloudflared"]
|
|
52
|
+
.find((p) => existsSync(p));
|
|
53
|
+
if (!cfPath) {
|
|
54
|
+
warn("cloudflared not installed. Install: brew install cloudflare/cloudflare/cloudflared");
|
|
55
|
+
process.exit(127);
|
|
56
|
+
}
|
|
57
|
+
ok(`cloudflared: ${cfPath}`);
|
|
58
|
+
|
|
59
|
+
// Pull firstname for the launchd label so multi-agent hosts don't collide.
|
|
60
|
+
let firstname = "agent";
|
|
61
|
+
try {
|
|
62
|
+
const aj = JSON.parse(readFileSync(join(AGENT_DIR, "config/agent.json"), "utf-8"));
|
|
63
|
+
firstname = (aj.firstName || "agent").toLowerCase();
|
|
64
|
+
} catch { /* fall through */ }
|
|
65
|
+
|
|
66
|
+
const label = `ai.maestro.${firstname}-voice-tunnel`;
|
|
67
|
+
const plistInstalled = join(process.env.HOME || "/", "Library/LaunchAgents", `${label}.plist`);
|
|
68
|
+
|
|
69
|
+
// ── 2. Generate plist from template ────────────────────────────────────
|
|
70
|
+
const templatePath = join(MAESTRO_ROOT, "scripts/local-triggers/templates/voice-tunnel.plist.template");
|
|
71
|
+
if (!existsSync(templatePath)) {
|
|
72
|
+
warn(`template missing at ${templatePath}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
let template = readFileSync(templatePath, "utf-8");
|
|
76
|
+
const nodeBin = process.execPath; // not used here, but kept for consistency
|
|
77
|
+
const substitutions = {
|
|
78
|
+
"{{FIRSTNAME}}": firstname,
|
|
79
|
+
"{{AGENT_ROOT}}": AGENT_DIR,
|
|
80
|
+
"{{HOME}}": process.env.HOME || `/Users/${firstname}`,
|
|
81
|
+
"{{USER}}": process.env.USER || firstname,
|
|
82
|
+
};
|
|
83
|
+
for (const [k, v] of Object.entries(substitutions)) {
|
|
84
|
+
template = template.split(k).join(v);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// In named mode we override ProgramArguments to use `cloudflared tunnel
|
|
88
|
+
// run` with the named-tunnel UUID. For now the ephemeral path is the
|
|
89
|
+
// default; named requires the operator to set up the tunnel & DNS first.
|
|
90
|
+
if (named) {
|
|
91
|
+
template = template.replace(
|
|
92
|
+
/<array>[\s\S]*?<\/array>/,
|
|
93
|
+
`<array>
|
|
94
|
+
<string>${cfPath}</string>
|
|
95
|
+
<string>tunnel</string>
|
|
96
|
+
<string>run</string>
|
|
97
|
+
<string>--hostname</string>
|
|
98
|
+
<string>${domain}</string>
|
|
99
|
+
<string>${firstname}-voice</string>
|
|
100
|
+
</array>`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
mkdirSync(dirname(plistInstalled), { recursive: true });
|
|
105
|
+
mkdirSync(join(AGENT_DIR, "logs/voice"), { recursive: true });
|
|
106
|
+
writeFileSync(plistInstalled, template);
|
|
107
|
+
ok(`wrote ${plistInstalled}`);
|
|
108
|
+
|
|
109
|
+
// ── 3. Load via launchctl ──────────────────────────────────────────────
|
|
110
|
+
try { execFileSync("launchctl", ["unload", plistInstalled], { stdio: "pipe" }); } catch { /* */ }
|
|
111
|
+
execFileSync("launchctl", ["load", plistInstalled], { stdio: "inherit" });
|
|
112
|
+
ok(`loaded ${label}`);
|
|
113
|
+
|
|
114
|
+
// ── 4. Wait for public URL ──────────────────────────────────────────────
|
|
115
|
+
const stdoutLog = join(AGENT_DIR, "logs/voice/cloudflared-stdout.log");
|
|
116
|
+
const stderrLog = join(AGENT_DIR, "logs/voice/cloudflared-stderr.log");
|
|
117
|
+
|
|
118
|
+
let publicUrl = null;
|
|
119
|
+
if (named) {
|
|
120
|
+
publicUrl = `https://${domain}`;
|
|
121
|
+
info(`named tunnel — public URL: ${publicUrl}`);
|
|
122
|
+
} else {
|
|
123
|
+
info("polling cloudflared log for ephemeral URL (up to 30s)...");
|
|
124
|
+
for (let i = 0; i < 60 && !publicUrl; i++) {
|
|
125
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
126
|
+
for (const path of [stdoutLog, stderrLog]) {
|
|
127
|
+
if (!existsSync(path)) continue;
|
|
128
|
+
const body = readFileSync(path, "utf-8");
|
|
129
|
+
const m = body.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
|
|
130
|
+
if (m) { publicUrl = m[0]; break; }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!publicUrl) {
|
|
134
|
+
warn("ephemeral URL not detected after 30s; check logs/voice/cloudflared-stderr.log");
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
ok(`ephemeral URL: ${publicUrl}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── 5. Update .env ──────────────────────────────────────────────────────
|
|
141
|
+
const envPath = join(AGENT_DIR, ".env");
|
|
142
|
+
if (!existsSync(envPath)) {
|
|
143
|
+
warn(".env not found — cannot persist VOICE_PUBLIC_BASE_URL");
|
|
144
|
+
} else {
|
|
145
|
+
let body = readFileSync(envPath, "utf-8");
|
|
146
|
+
if (/^VOICE_PUBLIC_BASE_URL=/m.test(body)) {
|
|
147
|
+
body = body.replace(/^VOICE_PUBLIC_BASE_URL=.*$/m, `VOICE_PUBLIC_BASE_URL=${publicUrl}`);
|
|
148
|
+
} else {
|
|
149
|
+
if (!body.endsWith("\n")) body += "\n";
|
|
150
|
+
body += `\n# Public base URL for voice webhooks (set by configure-voice-tunnel.mjs)\nVOICE_PUBLIC_BASE_URL=${publicUrl}\n`;
|
|
151
|
+
}
|
|
152
|
+
writeFileSync(envPath, body);
|
|
153
|
+
ok("wrote VOICE_PUBLIC_BASE_URL to .env");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── 6. Restart voice-webhook so it picks up the env change ─────────────
|
|
157
|
+
if (restart) {
|
|
158
|
+
const webhookLabel = `ai.maestro.${firstname}-voice-webhook`;
|
|
159
|
+
const webhookPlist = join(process.env.HOME || "/", "Library/LaunchAgents", `${webhookLabel}.plist`);
|
|
160
|
+
if (existsSync(webhookPlist)) {
|
|
161
|
+
try { execFileSync("launchctl", ["unload", webhookPlist], { stdio: "pipe" }); } catch { /* */ }
|
|
162
|
+
execFileSync("launchctl", ["load", webhookPlist], { stdio: "inherit" });
|
|
163
|
+
ok(`restarted ${webhookLabel}`);
|
|
164
|
+
} else {
|
|
165
|
+
info(`voice-webhook plist not installed (${webhookPlist}); run init-voice-realtime first`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log();
|
|
170
|
+
ok("done");
|
|
171
|
+
info("Verify it works:");
|
|
172
|
+
info(` curl -s ${publicUrl}/health | jq`);
|
|
173
|
+
info(` open ${publicUrl}/voice/test`);
|
|
174
|
+
console.log();
|
|
175
|
+
if (!named) {
|
|
176
|
+
warn("This is an EPHEMERAL URL — it changes on every cloudflared restart.");
|
|
177
|
+
warn("For production, set up a named tunnel:");
|
|
178
|
+
warn(" cloudflared tunnel login # auth Cloudflare account");
|
|
179
|
+
warn(" cloudflared tunnel create <name> # creates UUID + creds");
|
|
180
|
+
warn(" cloudflared tunnel route dns <name> voice.your-domain.com");
|
|
181
|
+
warn(" node scripts/setup/configure-voice-tunnel.mjs --named --domain=voice.your-domain.com");
|
|
182
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* generate-agent-env.mjs — Generate config/agent.env from config/agent.json
|
|
4
|
+
*
|
|
5
|
+
* Shell scripts can't import TypeScript or parse JSON cheaply, so we
|
|
6
|
+
* pre-derive a flat env file that any bash script can source:
|
|
7
|
+
*
|
|
8
|
+
* source "$AGENT_DIR/config/agent.env"
|
|
9
|
+
* echo "Hello, $AGENT_FIRST_NAME"
|
|
10
|
+
*
|
|
11
|
+
* The generator is invoked:
|
|
12
|
+
* - During `npm run init-agent` (initial setup)
|
|
13
|
+
* - At the end of every `maestro upgrade` run
|
|
14
|
+
* - On demand: `node scripts/setup/generate-agent-env.mjs`
|
|
15
|
+
*
|
|
16
|
+
* No TypeScript runtime required — we read agent.json directly.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
20
|
+
import { resolve, dirname } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const AGENT_DIR = process.env.AGENT_DIR || resolve(__dirname, "../..");
|
|
25
|
+
const JSON_PATH = resolve(AGENT_DIR, "config/agent.json");
|
|
26
|
+
const ENV_PATH = resolve(AGENT_DIR, "config/agent.env");
|
|
27
|
+
|
|
28
|
+
if (!existsSync(JSON_PATH)) {
|
|
29
|
+
console.error(`[generate-agent-env] config/agent.json not found at ${JSON_PATH}`);
|
|
30
|
+
console.error("[generate-agent-env] Run /init-maestro to configure identity, or migrate from config/agent.ts");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const agent = JSON.parse(readFileSync(JSON_PATH, "utf-8"));
|
|
35
|
+
|
|
36
|
+
// Shell-quote: wrap in single quotes; replace ' with '\'' (close, escape, reopen).
|
|
37
|
+
const q = (v) => {
|
|
38
|
+
const s = v === null || v === undefined ? "" : String(v);
|
|
39
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const repoDir = `$HOME/${agent.repoSlug}`;
|
|
43
|
+
const firstUpper = (agent.firstName || "").toUpperCase();
|
|
44
|
+
const firstLower = (agent.firstName || "").toLowerCase();
|
|
45
|
+
const signature = `${agent.fullName} | ${agent.title} | ${agent.company}`;
|
|
46
|
+
|
|
47
|
+
const lines = [
|
|
48
|
+
`# Auto-generated from config/agent.json by @cohortapp/agent-sdk.`,
|
|
49
|
+
`# DO NOT EDIT — regenerate with: node scripts/setup/generate-agent-env.mjs`,
|
|
50
|
+
`# Sourced by every shell script that needs agent identity.`,
|
|
51
|
+
``,
|
|
52
|
+
`# ── Agent identity ─────────────────────────────────────────────────`,
|
|
53
|
+
`export AGENT_FIRST_NAME=${q(agent.firstName)}`,
|
|
54
|
+
`export AGENT_LAST_NAME=${q(agent.lastName)}`,
|
|
55
|
+
`export AGENT_FULL_NAME=${q(agent.fullName)}`,
|
|
56
|
+
`export AGENT_TITLE=${q(agent.title)}`,
|
|
57
|
+
`export AGENT_ARCHETYPE=${q(agent.archetype)}`,
|
|
58
|
+
`export AGENT_EMAIL=${q(agent.email)}`,
|
|
59
|
+
`export AGENT_PHONE=${q(agent.phone)}`,
|
|
60
|
+
`export AGENT_SLACK_USER_ID=${q(agent.slackMemberId)}`,
|
|
61
|
+
`export AGENT_REPO_SLUG=${q(agent.repoSlug)}`,
|
|
62
|
+
`export AGENT_REPO_DIR="${repoDir}"`,
|
|
63
|
+
`export AGENT_MACHINE_NAME=${q(agent.machineName)}`,
|
|
64
|
+
`export AGENT_LAUNCHD_PREFIX=${q(agent.launchdLabelPrefix)}`,
|
|
65
|
+
`export AGENT_TIMEZONE=${q(agent.timezone)}`,
|
|
66
|
+
`export AGENT_LOCALE=${q(agent.locale)}`,
|
|
67
|
+
`export AGENT_UPPER=${q(firstUpper)}`,
|
|
68
|
+
`export AGENT_LOWER=${q(firstLower)}`,
|
|
69
|
+
`export AGENT_EMAIL_SIGNATURE=${q(signature)}`,
|
|
70
|
+
``,
|
|
71
|
+
`# ── Principal ──────────────────────────────────────────────────────`,
|
|
72
|
+
`export PRINCIPAL_FIRST_NAME=${q(agent.principal?.firstName)}`,
|
|
73
|
+
`export PRINCIPAL_LAST_NAME=${q(agent.principal?.lastName)}`,
|
|
74
|
+
`export PRINCIPAL_FULL_NAME=${q(agent.principal?.fullName)}`,
|
|
75
|
+
`export PRINCIPAL_TITLE=${q(agent.principal?.title)}`,
|
|
76
|
+
`export PRINCIPAL_EMAIL=${q(agent.principal?.email)}`,
|
|
77
|
+
`export PRINCIPAL_SLACK_USER_ID=${q(agent.principal?.slackMemberId)}`,
|
|
78
|
+
``,
|
|
79
|
+
`# ── Company ────────────────────────────────────────────────────────`,
|
|
80
|
+
`export COMPANY_NAME=${q(agent.company)}`,
|
|
81
|
+
`export COMPANY_DOMAIN=${q(agent.companyDomain)}`,
|
|
82
|
+
`export COMPANY_DESCRIPTION=${q(agent.companyDescription)}`,
|
|
83
|
+
``,
|
|
84
|
+
`# ── Schedule ───────────────────────────────────────────────────────`,
|
|
85
|
+
`export SCHEDULE_MORNING_BRIEF=${q(agent.schedule?.morningBrief)}`,
|
|
86
|
+
`export SCHEDULE_EVENING_WRAP=${q(agent.schedule?.eveningWrap)}`,
|
|
87
|
+
`export SCHEDULE_OVERNIGHT_MONITORING=${q(agent.schedule?.overnightMonitoring)}`,
|
|
88
|
+
``,
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
writeFileSync(ENV_PATH, lines.join("\n"));
|
|
92
|
+
console.log(`[generate-agent-env] wrote ${ENV_PATH}`);
|