@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
|
+
You are {{agent.fullName}}, {{agent.title}} to {{agent.principal.fullName}}, {{agent.principal.title}} of {{agent.company}}.
|
|
2
|
+
|
|
3
|
+
## Workflow: Weekly Strategic Memo
|
|
4
|
+
|
|
5
|
+
## Cadence: Friday 14:00 GST
|
|
6
|
+
|
|
7
|
+
## Working Directory: the agent repo root (your current working directory)
|
|
8
|
+
|
|
9
|
+
### Instructions
|
|
10
|
+
|
|
11
|
+
1. Read `state/dashboards/executive-summary.yaml`
|
|
12
|
+
2. Read `config/priorities.yaml`
|
|
13
|
+
3. Read `knowledge/syntheses/strategic-synthesis.yaml`
|
|
14
|
+
4. Review this week's interactions from `memory/interactions/` — key themes and signals
|
|
15
|
+
5. Review this week's decisions from `knowledge/decisions/`
|
|
16
|
+
6. Check `state/queues/narrative-opportunities.yaml` for content opportunities
|
|
17
|
+
|
|
18
|
+
7. **Strategic coherence check:**
|
|
19
|
+
- Read `config/priorities.yaml` for the 5 strategic priorities
|
|
20
|
+
- Scan all queue items across all 15 queues in `state/queues/` — map each to a priority using context
|
|
21
|
+
- Flag and include in the memo:
|
|
22
|
+
- Priorities with zero active queue items (stalled — nobody working on it)
|
|
23
|
+
- Queue items not mappable to any priority (unlinked work — effort without strategic purpose)
|
|
24
|
+
- Priorities where all items are blocked (stuck — needs intervention)
|
|
25
|
+
- Any apparent conflicts between initiatives
|
|
26
|
+
|
|
27
|
+
8. **Cadence quality audit:**
|
|
28
|
+
- Read `memory/interactions/meetings/` for all meetings this week
|
|
29
|
+
- For each meeting, check:
|
|
30
|
+
- Were actions captured? (meeting record exists with non-empty actions list)
|
|
31
|
+
- Were actions assigned owners and deadlines?
|
|
32
|
+
- Were previous meeting's actions closed?
|
|
33
|
+
- Calculate and include in memo:
|
|
34
|
+
- Meetings this week: total count
|
|
35
|
+
- Action capture rate: % of meetings with captured actions
|
|
36
|
+
- Action closure rate: % of last week's meeting actions now closed
|
|
37
|
+
- Flag: meetings with consistently zero outputs (suggest cancellation)
|
|
38
|
+
- Flag: meetings where actions captured but never closed (accountability gap)
|
|
39
|
+
|
|
40
|
+
9. **Update living strategy state:**
|
|
41
|
+
- Read `knowledge/syntheses/strategy-state.yaml`
|
|
42
|
+
- Update based on this week's developments:
|
|
43
|
+
- Refresh `strategic_position` if anything material changed
|
|
44
|
+
- Update `key_assumptions` status based on new evidence
|
|
45
|
+
- Add any `emerging_signals` observed this week
|
|
46
|
+
- Update `strategic_risks` severity/likelihood based on new information
|
|
47
|
+
- Add this week's decisions to `recent_decisions`
|
|
48
|
+
- Refresh `next_quarter_focus` if priorities shifted
|
|
49
|
+
- Write updated file back
|
|
50
|
+
|
|
51
|
+
10. **Leadership effectiveness scorecard:**
|
|
52
|
+
- Read `state/dashboards/leadership-accountability.yaml`
|
|
53
|
+
- For each leader: summarise commitments met/missed, response quality, trend
|
|
54
|
+
- Flag patterns: consistently missing deadlines, going silent, declining accountability
|
|
55
|
+
- Include {{agent.firstName}}'s candid assessment and specific recommendations
|
|
56
|
+
- NOTE: This section is sensitive — send via DM to {{agent.principal.firstName}}, not in any channel
|
|
57
|
+
|
|
58
|
+
11. **Relationship pipeline update:**
|
|
59
|
+
- Read `state/dashboards/relationship-pipeline.yaml`
|
|
60
|
+
- Review `memory/interactions/` for all external interactions this week
|
|
61
|
+
- Update relationship stages and warmth based on interaction recency
|
|
62
|
+
- Flag cooling relationships (no interaction >2 weeks for active relationships)
|
|
63
|
+
- Flag overdue next-actions on relationships
|
|
64
|
+
- Write updated pipeline to `state/dashboards/relationship-pipeline.yaml`
|
|
65
|
+
|
|
66
|
+
12. **Commercial position assessment:**
|
|
67
|
+
- Read market signals from `memory/precedents/market-signals/`
|
|
68
|
+
- Assess: ICP clarity, pipeline warmth, partner engagement, competitive positioning
|
|
69
|
+
- Synthesise into "Commercial Position" section in the memo
|
|
70
|
+
|
|
71
|
+
13. **Founder dependency flag:**
|
|
72
|
+
- Read `state/dashboards/org-health.yaml` founder_dependency section
|
|
73
|
+
- If threshold_breached (>60%), include prominent flag in memo with delegation recommendations
|
|
74
|
+
|
|
75
|
+
14. **Advisor utilisation review:**
|
|
76
|
+
- Read `state/dashboards/relationship-pipeline.yaml` advisors section
|
|
77
|
+
- For each advisor: when was last interaction? Was value extracted?
|
|
78
|
+
- Flag advisors not contacted in >30 days
|
|
79
|
+
- Recommend specific re-engagement actions for underutilised advisors
|
|
80
|
+
|
|
81
|
+
15. **Risk register review:**
|
|
82
|
+
- Read `state/dashboards/risk-register.yaml`
|
|
83
|
+
- For each risk: is the review date approaching or past?
|
|
84
|
+
- Have any risk conditions changed based on this week's developments?
|
|
85
|
+
- Update risk severity/likelihood if warranted
|
|
86
|
+
- Flag any new risks identified this week
|
|
87
|
+
- Write updated risk register back
|
|
88
|
+
|
|
89
|
+
16. **Capital position update:**
|
|
90
|
+
- Read `state/dashboards/capital-readiness.yaml`
|
|
91
|
+
- Update fundraising readiness components based on this week's progress
|
|
92
|
+
- Update investor and corp dev pipeline counts
|
|
93
|
+
- Note any approaching capital-related milestones
|
|
94
|
+
- Write updated dashboard back
|
|
95
|
+
|
|
96
|
+
17. Synthesise a weekly strategic memo covering:
|
|
97
|
+
- Week in review: key accomplishments and setbacks
|
|
98
|
+
- Strategic position: how did we advance this week?
|
|
99
|
+
- Strategy scorecard: per-priority status from `state/dashboards/strategy-scorecard.yaml`
|
|
100
|
+
- **Coherence check findings** (stalled priorities, unlinked work, conflicts)
|
|
101
|
+
- Emerging signals: what changed in the environment?
|
|
102
|
+
- **Cadence health** (meeting → action capture rate, closure rate, flagged meetings)
|
|
103
|
+
- **Leadership effectiveness scorecard** ({{agent.principal.firstName}} DM only)
|
|
104
|
+
- **Engineering health** from `state/dashboards/engineering-health.yaml`
|
|
105
|
+
- **Relationship pipeline health** (warming/cooling/overdue)
|
|
106
|
+
- **Commercial position** (ICP, pipeline, competitive)
|
|
107
|
+
- **Founder dependency alert** (if >60%)
|
|
108
|
+
- **Advisor utilisation** (who's engaged, who's dormant, re-engagement recs)
|
|
109
|
+
- **Risk register update** (new risks, changed severity, overdue reviews)
|
|
110
|
+
- **Capital position** (runway, readiness score, pipeline, approaching milestones)
|
|
111
|
+
- Next week preview: what matters most?
|
|
112
|
+
- Recommendations: 2-3 things {{agent.firstName}} recommends the {{agent.principal.title}} focus on
|
|
113
|
+
18. Write memo to `outputs/memos/{date}-strategic-memo.md`
|
|
114
|
+
19. Send to {{agent.principal.firstName}} via Slack or email (executive-quality document)
|
|
115
|
+
20. Update `knowledge/syntheses/strategic-synthesis.yaml` with any new insights
|
|
116
|
+
21. Prepare week-ahead items: update Monday's priorities queue
|
|
117
|
+
22. Log to `logs/workflows/{date}-weekly-strategic-memo.jsonl`
|
|
118
|
+
|
|
119
|
+
### Operating Rules
|
|
120
|
+
|
|
121
|
+
- This is the most important written output of the week — quality matters
|
|
122
|
+
- Be analytical and forward-looking, not just retrospective
|
|
123
|
+
- Include {{agent.firstName}}'s own strategic observations and recommendations
|
|
124
|
+
- If using PDF generation, use: `npm run pdf:memo -- --input outputs/memos/{date}-strategic-memo.md`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# archive-email.sh — Archive non-actionable Gmail messages via IMAP
|
|
3
|
+
# Usage: ./scripts/archive-email.sh
|
|
4
|
+
# Requires GMAIL_APP_PASSWORD environment variable
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
AGENT_REPO_DIR="${AGENT_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
9
|
+
|
|
10
|
+
# Pull AGENT_EMAIL + GMAIL_APP_PASSWORD from agent.env + .env
|
|
11
|
+
[ -f "$AGENT_REPO_DIR/config/agent.env" ] && source "$AGENT_REPO_DIR/config/agent.env"
|
|
12
|
+
[ -f "$AGENT_REPO_DIR/.env" ] && source "$AGENT_REPO_DIR/.env"
|
|
13
|
+
|
|
14
|
+
if [ -z "${GMAIL_APP_PASSWORD:-}" ]; then
|
|
15
|
+
echo "ERROR: GMAIL_APP_PASSWORD not set" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
export AGENT_EMAIL
|
|
19
|
+
export GMAIL_APP_PASSWORD
|
|
20
|
+
|
|
21
|
+
python3 << 'PYEOF'
|
|
22
|
+
import imaplib
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
user = os.environ.get("AGENT_EMAIL", "")
|
|
26
|
+
password = os.environ["GMAIL_APP_PASSWORD"]
|
|
27
|
+
if not user:
|
|
28
|
+
raise SystemExit("AGENT_EMAIL not set — check config/agent.env")
|
|
29
|
+
|
|
30
|
+
mail = imaplib.IMAP4_SSL("imap.gmail.com")
|
|
31
|
+
mail.login(user, password)
|
|
32
|
+
mail.select("INBOX")
|
|
33
|
+
|
|
34
|
+
# Non-actionable sender domains to auto-archive
|
|
35
|
+
junk_domains = [
|
|
36
|
+
"greptile.com", "gamma.app", "linear.app", "netlify.com",
|
|
37
|
+
"consensus.app", "zapier.com", "calendly.com", "jam.dev",
|
|
38
|
+
"send.zapier.com", "mail.consensus.app", "send.calendly.com",
|
|
39
|
+
"noreply@netlify.com", "hello@greptile.com", "hello@gamma.app",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
archived = 0
|
|
43
|
+
for domain in junk_domains:
|
|
44
|
+
status, messages = mail.search(None, f'(UNSEEN FROM "{domain}")')
|
|
45
|
+
if status == "OK" and messages[0]:
|
|
46
|
+
for num in messages[0].split():
|
|
47
|
+
mail.store(num, '+FLAGS', '\\Seen')
|
|
48
|
+
mail.copy(num, '"[Gmail]/All Mail"')
|
|
49
|
+
mail.store(num, '+FLAGS', '\\Deleted')
|
|
50
|
+
archived += 1
|
|
51
|
+
|
|
52
|
+
mail.expunge()
|
|
53
|
+
mail.logout()
|
|
54
|
+
print(f"Archived {archived} non-actionable emails")
|
|
55
|
+
PYEOF
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* cadence-status.mjs — Print the current cadence-bus depth + heartbeat.
|
|
4
|
+
*
|
|
5
|
+
* Used by `npm run cadence:status` and by `maestro doctor` for a quick
|
|
6
|
+
* snapshot. Reads files only; never mutates state.
|
|
7
|
+
*
|
|
8
|
+
* Output (JSON):
|
|
9
|
+
* {
|
|
10
|
+
* "depth": { "inbox": N, "claimed": N, "dlq": N, "failed": N },
|
|
11
|
+
* "health": { ... } | null,
|
|
12
|
+
* "heartbeat_age_ms": N | null
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Exit code is always 0 — health interpretation is the caller's job.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { resolve, dirname } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
|
|
21
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const { busDepth, readHealth, getBusPaths } = await import(
|
|
23
|
+
resolve(__dirname, "..", "..", "lib", "cadence-bus.mjs")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const paths = getBusPaths();
|
|
27
|
+
const depth = busDepth();
|
|
28
|
+
const health = readHealth();
|
|
29
|
+
const heartbeatAgeMs = health?.ts ? Date.now() - new Date(health.ts).getTime() : null;
|
|
30
|
+
|
|
31
|
+
process.stdout.write(JSON.stringify({
|
|
32
|
+
agent_root: paths.agentRoot,
|
|
33
|
+
depth,
|
|
34
|
+
health,
|
|
35
|
+
heartbeat_age_ms: heartbeatAgeMs,
|
|
36
|
+
}, null, 2) + "\n");
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Maestro — enqueue-cadence-tick.mjs
|
|
4
|
+
*
|
|
5
|
+
* Lightweight cadence-bus enqueue CLI. Designed to be invoked from launchd
|
|
6
|
+
* plists (or manual scripting) in place of `claude --print` per tick. The
|
|
7
|
+
* heavy lifting — running the cadence, deciding whether to spawn a sub-
|
|
8
|
+
* session, etc. — is owned by the persistent Maestro daemon, which consumes
|
|
9
|
+
* events from the bus.
|
|
10
|
+
*
|
|
11
|
+
* Design constraints:
|
|
12
|
+
* • Must finish in well under a second so launchd never piles up.
|
|
13
|
+
* • Must never spawn Claude Code itself.
|
|
14
|
+
* • Must be safe to call when the daemon is down (event still lands on
|
|
15
|
+
* disk and is processed on next consumer startup).
|
|
16
|
+
* • Must honour .emergency-stop (no event lands in inbox/; suppressed
|
|
17
|
+
* event is still recorded in queue.jsonl for audit).
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* node scripts/cadence/enqueue-cadence-tick.mjs <cadence-name> [options]
|
|
21
|
+
*
|
|
22
|
+
* Options:
|
|
23
|
+
* --source=<label> launchd | manual | daemon | init-maestro | upgrade (default: manual)
|
|
24
|
+
* --workflow=<path> e.g. continuous/inbox-processor
|
|
25
|
+
* --priority=<high|normal|low>
|
|
26
|
+
* --correlation-id=<id>
|
|
27
|
+
* --interval=<seconds> Cadence interval in seconds (WS4). When present,
|
|
28
|
+
* the bus enforces at-most-once delivery per
|
|
29
|
+
* interval (grace window + stale fast-forward after
|
|
30
|
+
* an outage). Passed by generate-plists.sh from the
|
|
31
|
+
* plist's StartInterval/StartCalendarInterval. Absent
|
|
32
|
+
* → legacy behaviour (every fire enqueues).
|
|
33
|
+
* --metadata=<key=value> May be repeated. Comma-separated pairs also accepted.
|
|
34
|
+
* --quiet Suppress stdout JSON line.
|
|
35
|
+
* --help Show this help.
|
|
36
|
+
*
|
|
37
|
+
* Exit codes:
|
|
38
|
+
* 0 — enqueued (or suppressed by emergency-stop, which is still success)
|
|
39
|
+
* 2 — invalid usage / missing required arg
|
|
40
|
+
* 3 — internal failure (disk full, permissions, etc.) — caller should retry
|
|
41
|
+
*
|
|
42
|
+
* Examples:
|
|
43
|
+
* # Launchd plist invokes this every 10 minutes:
|
|
44
|
+
* node scripts/cadence/enqueue-cadence-tick.mjs backlog-executor --source=launchd
|
|
45
|
+
*
|
|
46
|
+
* # Manual smoke-test:
|
|
47
|
+
* node scripts/cadence/enqueue-cadence-tick.mjs inbox-processor --source=manual --metadata=note=smoke
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import { resolve, dirname } from "node:path";
|
|
51
|
+
import { fileURLToPath } from "node:url";
|
|
52
|
+
|
|
53
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
54
|
+
|
|
55
|
+
// Resolve cadence-bus relative to this script so the same enqueue works
|
|
56
|
+
// whether invoked from the framework repo (~/maestro/scripts/cadence/...)
|
|
57
|
+
// or from a generated agent repo (~/<agent>/scripts/cadence/...).
|
|
58
|
+
const { enqueueTick, BUS_VERSION } = await import(
|
|
59
|
+
resolve(__dirname, "..", "..", "lib", "cadence-bus.mjs")
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
function printHelp() {
|
|
63
|
+
process.stdout.write(`enqueue-cadence-tick — Maestro cadence bus producer
|
|
64
|
+
|
|
65
|
+
Usage:
|
|
66
|
+
node scripts/cadence/enqueue-cadence-tick.mjs <cadence-name> [options]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--source=<label> launchd | manual | daemon | init-maestro | upgrade
|
|
70
|
+
--workflow=<path> e.g. continuous/inbox-processor
|
|
71
|
+
--priority=<high|normal|low>
|
|
72
|
+
--correlation-id=<id>
|
|
73
|
+
--metadata=<key=value> repeatable, or comma-separated pairs
|
|
74
|
+
--quiet suppress JSON output to stdout
|
|
75
|
+
--version print bus version and exit
|
|
76
|
+
--help, -h show this help
|
|
77
|
+
|
|
78
|
+
Exits 0 on success (including emergency-stop suppression).
|
|
79
|
+
`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function parseMetadata(raw) {
|
|
83
|
+
// Accept --metadata=key=value, repeated, or --metadata=k1=v1,k2=v2.
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const item of raw) {
|
|
86
|
+
if (!item) continue;
|
|
87
|
+
for (const pair of String(item).split(",")) {
|
|
88
|
+
const idx = pair.indexOf("=");
|
|
89
|
+
if (idx === -1) continue;
|
|
90
|
+
const k = pair.slice(0, idx).trim();
|
|
91
|
+
const v = pair.slice(idx + 1).trim();
|
|
92
|
+
if (k) out[k] = v;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function parseArgs(argv) {
|
|
99
|
+
const args = { cadence: null, source: "manual", metadata: [], quiet: false };
|
|
100
|
+
for (const arg of argv) {
|
|
101
|
+
if (arg === "--help" || arg === "-h") return { help: true };
|
|
102
|
+
if (arg === "--version") return { version: true };
|
|
103
|
+
if (arg === "--quiet") { args.quiet = true; continue; }
|
|
104
|
+
if (arg.startsWith("--source=")) { args.source = arg.slice("--source=".length); continue; }
|
|
105
|
+
if (arg.startsWith("--workflow=")) { args.workflow = arg.slice("--workflow=".length); continue; }
|
|
106
|
+
if (arg.startsWith("--priority=")) { args.priority = arg.slice("--priority=".length); continue; }
|
|
107
|
+
if (arg.startsWith("--correlation-id=")) { args.correlation_id = arg.slice("--correlation-id=".length); continue; }
|
|
108
|
+
if (arg.startsWith("--interval=")) { args.interval = arg.slice("--interval=".length); continue; }
|
|
109
|
+
if (arg.startsWith("--metadata=")) { args.metadata.push(arg.slice("--metadata=".length)); continue; }
|
|
110
|
+
if (arg.startsWith("--")) {
|
|
111
|
+
process.stderr.write(`enqueue-cadence-tick: unknown flag: ${arg}\n`);
|
|
112
|
+
return { invalid: true };
|
|
113
|
+
}
|
|
114
|
+
if (!args.cadence) { args.cadence = arg; continue; }
|
|
115
|
+
process.stderr.write(`enqueue-cadence-tick: unexpected positional arg: ${arg}\n`);
|
|
116
|
+
return { invalid: true };
|
|
117
|
+
}
|
|
118
|
+
return args;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const argv = process.argv.slice(2);
|
|
122
|
+
const parsed = parseArgs(argv);
|
|
123
|
+
|
|
124
|
+
if (parsed.help) {
|
|
125
|
+
printHelp();
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
if (parsed.version) {
|
|
129
|
+
process.stdout.write(`${BUS_VERSION}\n`);
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
if (parsed.invalid) {
|
|
133
|
+
printHelp();
|
|
134
|
+
process.exit(2);
|
|
135
|
+
}
|
|
136
|
+
if (!parsed.cadence) {
|
|
137
|
+
process.stderr.write("enqueue-cadence-tick: <cadence-name> required\n");
|
|
138
|
+
printHelp();
|
|
139
|
+
process.exit(2);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Convert --interval=<seconds> to milliseconds for the bus. Non-numeric or
|
|
143
|
+
// non-positive values are ignored (falls back to legacy every-fire behaviour).
|
|
144
|
+
let intervalMs;
|
|
145
|
+
if (parsed.interval !== undefined) {
|
|
146
|
+
const secs = Number(parsed.interval);
|
|
147
|
+
if (Number.isFinite(secs) && secs > 0) intervalMs = Math.round(secs * 1000);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const result = enqueueTick({
|
|
152
|
+
cadence: parsed.cadence,
|
|
153
|
+
source: parsed.source,
|
|
154
|
+
workflow: parsed.workflow,
|
|
155
|
+
priority: parsed.priority,
|
|
156
|
+
correlation_id: parsed.correlation_id,
|
|
157
|
+
intervalMs,
|
|
158
|
+
metadata: parseMetadata(parsed.metadata),
|
|
159
|
+
});
|
|
160
|
+
if (!parsed.quiet) {
|
|
161
|
+
process.stdout.write(JSON.stringify({
|
|
162
|
+
ok: true,
|
|
163
|
+
id: result.id,
|
|
164
|
+
cadence: parsed.cadence,
|
|
165
|
+
path: result.path,
|
|
166
|
+
fallback_only: result.fallbackOnly,
|
|
167
|
+
skipped: result.skipped || null,
|
|
168
|
+
}) + "\n");
|
|
169
|
+
}
|
|
170
|
+
process.exit(0);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
process.stderr.write(`enqueue-cadence-tick: ${err.message}\n`);
|
|
173
|
+
process.exit(3);
|
|
174
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* enqueue-cadence-tick.test.mjs — node:test coverage for the CLI enqueue
|
|
3
|
+
* script (the entry point used by launchd plists).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { test } from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { promises as fsp } from "fs";
|
|
9
|
+
import { writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
10
|
+
import { tmpdir } from "os";
|
|
11
|
+
import { join, resolve, dirname } from "path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const ENQUEUE_SCRIPT = resolve(__dirname, "enqueue-cadence-tick.mjs");
|
|
17
|
+
|
|
18
|
+
async function makeAgentRoot() {
|
|
19
|
+
const path = join(
|
|
20
|
+
tmpdir(),
|
|
21
|
+
`enqueue-cli-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
22
|
+
);
|
|
23
|
+
await fsp.mkdir(path, { recursive: true });
|
|
24
|
+
return path;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function rmRoot(path) {
|
|
28
|
+
try { await fsp.rm(path, { recursive: true, force: true }); } catch { /* */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function run(cwd, args, env = {}) {
|
|
32
|
+
return spawnSync(process.execPath, [ENQUEUE_SCRIPT, ...args], {
|
|
33
|
+
cwd,
|
|
34
|
+
env: { ...process.env, AGENT_ROOT: cwd, ...env },
|
|
35
|
+
encoding: "utf-8",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Happy path
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
test("CLI enqueues a tick and writes inbox JSON", async () => {
|
|
44
|
+
const root = await makeAgentRoot();
|
|
45
|
+
try {
|
|
46
|
+
const r = run(root, ["inbox-processor", "--source=launchd"]);
|
|
47
|
+
assert.equal(r.status, 0, r.stderr);
|
|
48
|
+
const out = JSON.parse(r.stdout.trim());
|
|
49
|
+
assert.equal(out.ok, true);
|
|
50
|
+
assert.equal(out.cadence, "inbox-processor");
|
|
51
|
+
assert.equal(out.fallback_only, false);
|
|
52
|
+
assert.ok(out.path);
|
|
53
|
+
assert.ok(existsSync(out.path));
|
|
54
|
+
const event = JSON.parse(readFileSync(out.path, "utf-8"));
|
|
55
|
+
assert.equal(event.source, "launchd");
|
|
56
|
+
assert.equal(event.cadence, "inbox-processor");
|
|
57
|
+
} finally { await rmRoot(root); }
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("CLI accepts metadata pairs (repeated and comma-separated)", async () => {
|
|
61
|
+
const root = await makeAgentRoot();
|
|
62
|
+
try {
|
|
63
|
+
const r = run(root, [
|
|
64
|
+
"weekly-strategic-memo",
|
|
65
|
+
"--source=manual",
|
|
66
|
+
"--metadata=note=launch",
|
|
67
|
+
"--metadata=k1=v1,k2=v2",
|
|
68
|
+
]);
|
|
69
|
+
assert.equal(r.status, 0);
|
|
70
|
+
const out = JSON.parse(r.stdout.trim());
|
|
71
|
+
const event = JSON.parse(readFileSync(out.path, "utf-8"));
|
|
72
|
+
assert.equal(event.metadata.note, "launch");
|
|
73
|
+
assert.equal(event.metadata.k1, "v1");
|
|
74
|
+
assert.equal(event.metadata.k2, "v2");
|
|
75
|
+
} finally { await rmRoot(root); }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("CLI --interval enables the at-most-once gate (duplicate fire suppressed)", async () => {
|
|
79
|
+
const root = await makeAgentRoot();
|
|
80
|
+
try {
|
|
81
|
+
// First fire admits.
|
|
82
|
+
const r1 = run(root, ["inbox-processor", "--source=launchd", "--interval=300"]);
|
|
83
|
+
assert.equal(r1.status, 0, r1.stderr);
|
|
84
|
+
const out1 = JSON.parse(r1.stdout.trim());
|
|
85
|
+
assert.ok(out1.path, "first interval-bearing tick admits");
|
|
86
|
+
// Immediate second fire (well within the grace window) is suppressed.
|
|
87
|
+
const r2 = run(root, ["inbox-processor", "--source=launchd", "--interval=300"]);
|
|
88
|
+
assert.equal(r2.status, 0, r2.stderr);
|
|
89
|
+
const out2 = JSON.parse(r2.stdout.trim());
|
|
90
|
+
assert.equal(out2.path, null);
|
|
91
|
+
assert.equal(out2.skipped, "before-grace-window");
|
|
92
|
+
// schedule.json was created.
|
|
93
|
+
assert.ok(existsSync(join(root, "state/cadence-bus/schedule.json")));
|
|
94
|
+
} finally { await rmRoot(root); }
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("CLI --interval=0 / non-numeric falls back to legacy every-fire behaviour", async () => {
|
|
98
|
+
const root = await makeAgentRoot();
|
|
99
|
+
try {
|
|
100
|
+
const a = run(root, ["inbox-processor", "--source=launchd", "--interval=0"]);
|
|
101
|
+
const b = run(root, ["inbox-processor", "--source=launchd", "--interval=oops"]);
|
|
102
|
+
assert.equal(a.status, 0);
|
|
103
|
+
assert.equal(b.status, 0);
|
|
104
|
+
assert.ok(JSON.parse(a.stdout.trim()).path);
|
|
105
|
+
assert.ok(JSON.parse(b.stdout.trim()).path);
|
|
106
|
+
// No schedule.json created when the gate is inactive.
|
|
107
|
+
assert.equal(existsSync(join(root, "state/cadence-bus/schedule.json")), false);
|
|
108
|
+
} finally { await rmRoot(root); }
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("CLI --quiet suppresses stdout JSON", async () => {
|
|
112
|
+
const root = await makeAgentRoot();
|
|
113
|
+
try {
|
|
114
|
+
const r = run(root, ["inbox-processor", "--source=launchd", "--quiet"]);
|
|
115
|
+
assert.equal(r.status, 0);
|
|
116
|
+
assert.equal(r.stdout.trim(), "");
|
|
117
|
+
} finally { await rmRoot(root); }
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("CLI --version prints bus schema version", async () => {
|
|
121
|
+
const r = spawnSync(process.execPath, [ENQUEUE_SCRIPT, "--version"], { encoding: "utf-8" });
|
|
122
|
+
assert.equal(r.status, 0);
|
|
123
|
+
assert.match(r.stdout, /^\d+$/m);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("CLI --help prints usage and exits 0", async () => {
|
|
127
|
+
const r = spawnSync(process.execPath, [ENQUEUE_SCRIPT, "--help"], { encoding: "utf-8" });
|
|
128
|
+
assert.equal(r.status, 0);
|
|
129
|
+
assert.match(r.stdout, /enqueue-cadence-tick/);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Error paths
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
test("CLI exits 2 with no cadence", async () => {
|
|
137
|
+
const root = await makeAgentRoot();
|
|
138
|
+
try {
|
|
139
|
+
const r = run(root, []);
|
|
140
|
+
assert.equal(r.status, 2);
|
|
141
|
+
assert.match(r.stderr, /required/);
|
|
142
|
+
} finally { await rmRoot(root); }
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("CLI exits 2 on unknown flag", async () => {
|
|
146
|
+
const root = await makeAgentRoot();
|
|
147
|
+
try {
|
|
148
|
+
const r = run(root, ["x", "--what-is-this"]);
|
|
149
|
+
assert.equal(r.status, 2);
|
|
150
|
+
assert.match(r.stderr, /unknown flag/);
|
|
151
|
+
} finally { await rmRoot(root); }
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Emergency stop
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
test("CLI returns 0 with skipped=emergency-stop when stop flag exists", async () => {
|
|
159
|
+
const root = await makeAgentRoot();
|
|
160
|
+
try {
|
|
161
|
+
writeFileSync(join(root, ".emergency-stop"), "now");
|
|
162
|
+
const r = run(root, ["weekly-strategic-memo", "--source=launchd"]);
|
|
163
|
+
assert.equal(r.status, 0);
|
|
164
|
+
const out = JSON.parse(r.stdout.trim());
|
|
165
|
+
assert.equal(out.skipped, "emergency-stop");
|
|
166
|
+
assert.equal(out.fallback_only, true);
|
|
167
|
+
assert.equal(out.path, null);
|
|
168
|
+
// No file landed in inbox/.
|
|
169
|
+
assert.ok(!existsSync(join(root, "state/cadence-bus/inbox", `${out.id}.json`)));
|
|
170
|
+
} finally { await rmRoot(root); }
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Bus-handoff sanity — the CLI must finish in well under a second so launchd
|
|
175
|
+
// never piles up; we don't pin a number, just a generous ceiling.
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
test("CLI completes in well under 2 seconds", async () => {
|
|
179
|
+
const root = await makeAgentRoot();
|
|
180
|
+
try {
|
|
181
|
+
const t0 = Date.now();
|
|
182
|
+
const r = run(root, ["inbox-processor", "--source=launchd", "--quiet"]);
|
|
183
|
+
const dt = Date.now() - t0;
|
|
184
|
+
assert.equal(r.status, 0);
|
|
185
|
+
assert.ok(dt < 2000, `enqueue took ${dt}ms`);
|
|
186
|
+
} finally { await rmRoot(root); }
|
|
187
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# launchd-cadence-wrapper.sh — Bootstraps env and execs the Node cadence
|
|
3
|
+
# enqueue script under launchd.
|
|
4
|
+
#
|
|
5
|
+
# Usage in a plist:
|
|
6
|
+
# <key>ProgramArguments</key>
|
|
7
|
+
# <array>
|
|
8
|
+
# <string>/path/to/scripts/cadence/launchd-cadence-wrapper.sh</string>
|
|
9
|
+
# <string>/path/to/scripts/cadence/enqueue-cadence-tick.mjs</string>
|
|
10
|
+
# <string>cadence-name</string>
|
|
11
|
+
# <string>--source=launchd</string>
|
|
12
|
+
# </array>
|
|
13
|
+
#
|
|
14
|
+
# What it does:
|
|
15
|
+
# 1. Sets HOME, PATH, USER, AGENT_ROOT (launchd's bare env doesn't include them).
|
|
16
|
+
# 2. Picks a node binary (nvm, homebrew, system fallback).
|
|
17
|
+
# 3. Redirects stdout/stderr to logs/cadence-bus/launchd-YYYY-MM-DD.log.
|
|
18
|
+
# 4. Exec's `node <enqueue-script> "$@"`.
|
|
19
|
+
#
|
|
20
|
+
# This is a *pure enqueue* wrapper — it must NOT spawn Claude Code. The
|
|
21
|
+
# heavyweight cadence work happens inside the persistent daemon's cadence
|
|
22
|
+
# consumer, not here.
|
|
23
|
+
|
|
24
|
+
set -e
|
|
25
|
+
|
|
26
|
+
if [ $# -lt 1 ]; then
|
|
27
|
+
echo "[cadence-wrapper] FATAL: enqueue script path required" >&2
|
|
28
|
+
exit 64
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
ENQUEUE_SCRIPT="$1"
|
|
32
|
+
shift
|
|
33
|
+
|
|
34
|
+
# Walk up from the enqueue script to find the agent root. AGENT_ROOT is the
|
|
35
|
+
# nearest ancestor with both package.json and config/.
|
|
36
|
+
TARGET_DIR="$(cd "$(dirname "$ENQUEUE_SCRIPT")" && pwd -P)"
|
|
37
|
+
CANDIDATE="$TARGET_DIR"
|
|
38
|
+
AGENT_ROOT=""
|
|
39
|
+
while [ "$CANDIDATE" != "/" ]; do
|
|
40
|
+
if [ -f "$CANDIDATE/package.json" ] && [ -d "$CANDIDATE/config" ]; then
|
|
41
|
+
AGENT_ROOT="$CANDIDATE"
|
|
42
|
+
break
|
|
43
|
+
fi
|
|
44
|
+
CANDIDATE="$(dirname "$CANDIDATE")"
|
|
45
|
+
done
|
|
46
|
+
AGENT_ROOT="${AGENT_ROOT:-$TARGET_DIR}"
|
|
47
|
+
|
|
48
|
+
export AGENT_ROOT
|
|
49
|
+
export AGENT_DIR="$AGENT_ROOT"
|
|
50
|
+
export HOME="${HOME:-/Users/$(whoami)}"
|
|
51
|
+
export USER="${USER:-$(whoami)}"
|
|
52
|
+
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
|
|
53
|
+
|
|
54
|
+
cd "$AGENT_ROOT"
|
|
55
|
+
|
|
56
|
+
# Resolve node binary — prefer nvm, fall back to homebrew, then system.
|
|
57
|
+
NODE_BIN=""
|
|
58
|
+
for candidate in \
|
|
59
|
+
"$HOME/.nvm/versions/node/v24.11.1/bin/node" \
|
|
60
|
+
"$HOME/.nvm/versions/node/v24/bin/node" \
|
|
61
|
+
"$HOME/.nvm/versions/node/v22/bin/node" \
|
|
62
|
+
"$HOME/.nvm/versions/node/v20/bin/node" \
|
|
63
|
+
/opt/homebrew/bin/node \
|
|
64
|
+
/usr/local/bin/node \
|
|
65
|
+
/usr/bin/node; do
|
|
66
|
+
if [ -x "$candidate" ]; then
|
|
67
|
+
NODE_BIN="$candidate"
|
|
68
|
+
break
|
|
69
|
+
fi
|
|
70
|
+
done
|
|
71
|
+
if [ -z "$NODE_BIN" ] && [ -d "$HOME/.nvm/versions/node" ]; then
|
|
72
|
+
NODE_BIN=$(ls -1d "$HOME/.nvm/versions/node"/v*/bin/node 2>/dev/null | sort -V | tail -1)
|
|
73
|
+
fi
|
|
74
|
+
if [ -z "$NODE_BIN" ] || [ ! -x "$NODE_BIN" ]; then
|
|
75
|
+
echo "[cadence-wrapper] FATAL: could not find node binary" >&2
|
|
76
|
+
exit 127
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
LOG_DATE="$(date +%Y-%m-%d)"
|
|
80
|
+
LOG_DIR="$AGENT_ROOT/logs/cadence-bus"
|
|
81
|
+
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
|
82
|
+
LOG_FILE="$LOG_DIR/launchd-${LOG_DATE}.log"
|
|
83
|
+
|
|
84
|
+
# Exec the enqueue script. stdin is closed; stdout/stderr go to the log.
|
|
85
|
+
exec "$NODE_BIN" "$ENQUEUE_SCRIPT" "$@" >> "$LOG_FILE" 2>&1
|