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