@cohortapp/agent-sdk 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/init-agent.md +104 -0
- package/.claude/commands/init-maestro.md +1187 -0
- package/.claude/settings.json +161 -0
- package/.env.example +216 -0
- package/README.md +632 -0
- package/agents/browser-operator/agent.md +52 -0
- package/agents/calendar-ops/agent.md +50 -0
- package/agents/communications/agent.md +96 -0
- package/agents/decision-log/agent.md +65 -0
- package/agents/desktop-operator/agent.md +59 -0
- package/agents/gmail-operator/agent.md +62 -0
- package/agents/inbound-dispatcher/agent.md +66 -0
- package/agents/inbox-processor/agent.md +39 -0
- package/agents/pmo-execution/agent.md +60 -0
- package/agents/session-spawner/agent.md +64 -0
- package/agents/slack-operator/agent.md +60 -0
- package/agents/whatsapp-operator/agent.md +60 -0
- package/agents/workflow-automation/agent.md +61 -0
- package/archetypes/altitudes/c-suite.yaml +58 -0
- package/archetypes/altitudes/founder.yaml +68 -0
- package/archetypes/altitudes/senior-manager.yaml +63 -0
- package/archetypes/altitudes/svp.yaml +60 -0
- package/archetypes/altitudes/vp.yaml +50 -0
- package/archetypes/archetype.schema.json +77 -0
- package/archetypes/base.yaml +47 -0
- package/archetypes/capabilities/commercial-leader.yaml +159 -0
- package/archetypes/capabilities/compliance-officer.yaml +159 -0
- package/archetypes/capabilities/executive-operator.yaml +169 -0
- package/archetypes/capabilities/finance-leader.yaml +162 -0
- package/archetypes/capabilities/operations-leader.yaml +154 -0
- package/archetypes/capabilities/product-leader.yaml +148 -0
- package/archetypes/capabilities/technical-leader.yaml +146 -0
- package/archetypes/functions/commercial-leader.yaml +62 -0
- package/archetypes/functions/compliance-officer.yaml +64 -0
- package/archetypes/functions/executive-operator.yaml +70 -0
- package/archetypes/functions/finance-leader.yaml +70 -0
- package/archetypes/functions/operations-leader.yaml +62 -0
- package/archetypes/functions/product-leader.yaml +61 -0
- package/archetypes/functions/technical-leader.yaml +57 -0
- package/bin/cohort-mcp.mjs +81 -0
- package/bin/maestro.mjs +3516 -0
- package/bin/maestro.test.mjs +1015 -0
- package/desktop-control/README.md +56 -0
- package/desktop-control/app-profiles/gmail.yaml +120 -0
- package/desktop-control/app-profiles/slack.yaml +315 -0
- package/desktop-control/app-profiles/whatsapp.yaml +107 -0
- package/docs/architecture/agent-topology.md +2239 -0
- package/docs/architecture/archetype-agent-factory.md +110 -0
- package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
- package/docs/architecture/continuous-monitoring.md +221 -0
- package/docs/architecture/mcp-capability-map.md +585 -0
- package/docs/architecture/system-architecture.md +1272 -0
- package/docs/company-context/README.md +40 -0
- package/docs/guides/agent-persona-setup.md +600 -0
- package/docs/guides/agents-observe-setup.md +64 -0
- package/docs/guides/billing-console-keys.md +88 -0
- package/docs/guides/ccxray-diagnostics.md +65 -0
- package/docs/guides/channel-bus.md +127 -0
- package/docs/guides/claude-mem-setup.md +79 -0
- package/docs/guides/claude-pace-setup.md +56 -0
- package/docs/guides/claudraband-sessions.md +98 -0
- package/docs/guides/clawteam-swarm.md +116 -0
- package/docs/guides/code-review-graph-setup.md +86 -0
- package/docs/guides/email-setup.md +431 -0
- package/docs/guides/mac-mini.md +119 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/model-routing.md +162 -0
- package/docs/guides/observability-otel.md +265 -0
- package/docs/guides/org-onboarding.md +132 -0
- package/docs/guides/outbound-governance-setup.md +437 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +563 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/self-optimization-pattern.md +82 -0
- package/docs/guides/setup-wizard.md +178 -0
- package/docs/guides/slack-setup.md +350 -0
- package/docs/guides/telegram-setup.md +227 -0
- package/docs/guides/twilio-subaccounts-setup.md +223 -0
- package/docs/guides/verification.md +128 -0
- package/docs/guides/voice-mode.md +188 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/webhook-relay-setup.md +349 -0
- package/docs/guides/whatsapp-setup.md +288 -0
- package/docs/prompts/board-pack-cover-template.md +36 -0
- package/docs/prompts/decision-recommendation-template.md +88 -0
- package/docs/prompts/followup-message-template.md +141 -0
- package/docs/prompts/investor-letter-template.md +52 -0
- package/docs/prompts/morning-brief-template.md +82 -0
- package/docs/prompts/presentation-template.md +58 -0
- package/docs/prompts/weekly-strategic-memo-template.md +104 -0
- package/docs/research/hallucinated-tool-output-investigation.md +151 -0
- package/docs/runbooks/backup-restore.md +205 -0
- package/docs/runbooks/cohort-cutover.md +129 -0
- package/docs/runbooks/fleet-operations.md +200 -0
- package/docs/runbooks/incident-response.md +226 -0
- package/docs/runbooks/mac-mini-bootstrap.md +431 -0
- package/docs/runbooks/perpetual-operations.md +509 -0
- package/docs/runbooks/recovery-and-failover.md +260 -0
- package/framework-features.json +267 -0
- package/ingest/README.md +87 -0
- package/lib/action-executor.js +689 -0
- package/lib/action-executor.test.mjs +871 -0
- package/lib/agent-root.mjs +37 -0
- package/lib/archetype.mjs +236 -0
- package/lib/archetype.test.mjs +132 -0
- package/lib/autonomy.mjs +114 -0
- package/lib/autonomy.test.mjs +66 -0
- package/lib/backlog.mjs +358 -0
- package/lib/backlog.test.mjs +266 -0
- package/lib/budget-guard.mjs +279 -0
- package/lib/budget-guard.test.mjs +291 -0
- package/lib/cadence-bus-schedule.test.mjs +194 -0
- package/lib/cadence-bus.mjs +1120 -0
- package/lib/cadence-bus.test.mjs +720 -0
- package/lib/cadences.mjs +205 -0
- package/lib/cadences.test.mjs +125 -0
- package/lib/capability.mjs +154 -0
- package/lib/capability.test.mjs +78 -0
- package/lib/channels/base-adapter.mjs +719 -0
- package/lib/channels/base-adapter.test.mjs +590 -0
- package/lib/channels/channel.mjs +128 -0
- package/lib/channels/channels.test.mjs +371 -0
- package/lib/channels/contract.mjs +215 -0
- package/lib/channels/contract.test.mjs +137 -0
- package/lib/channels/conversation-resolver.mjs +95 -0
- package/lib/channels/gmail/adapter.mjs +87 -0
- package/lib/channels/inbox-item.mjs +255 -0
- package/lib/channels/inbox-item.test.mjs +335 -0
- package/lib/channels/index.mjs +94 -0
- package/lib/channels/orgmail/adapter.mjs +353 -0
- package/lib/channels/orgmail/adapter.test.mjs +311 -0
- package/lib/channels/pairing.mjs +363 -0
- package/lib/channels/pairing.test.mjs +270 -0
- package/lib/channels/registry.mjs +164 -0
- package/lib/channels/slack/adapter.mjs +317 -0
- package/lib/channels/slack-adapter.test.mjs +212 -0
- package/lib/channels/sms/adapter.mjs +43 -0
- package/lib/channels/telegram/adapter.mjs +432 -0
- package/lib/channels/telegram-adapter.test.mjs +306 -0
- package/lib/channels/voice/adapter.mjs +301 -0
- package/lib/channels/voice/adapter.test.mjs +278 -0
- package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
- package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
- package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
- package/lib/charter.mjs +256 -0
- package/lib/charter.test.mjs +89 -0
- package/lib/claude-bin.mjs +134 -0
- package/lib/claude-bin.test.mjs +75 -0
- package/lib/collective/capture.mjs +185 -0
- package/lib/collective/capture.test.mjs +121 -0
- package/lib/collective/cards.mjs +201 -0
- package/lib/collective/cards.test.mjs +114 -0
- package/lib/collective/config.mjs +186 -0
- package/lib/collective/config.test.mjs +123 -0
- package/lib/collective/global-config.mjs +113 -0
- package/lib/collective/global-config.test.mjs +75 -0
- package/lib/collective/presence.mjs +201 -0
- package/lib/collective/presence.test.mjs +95 -0
- package/lib/collective/recall.mjs +215 -0
- package/lib/collective/recall.test.mjs +116 -0
- package/lib/comms/send-gate.mjs +554 -0
- package/lib/comms/send-gate.test.mjs +577 -0
- package/lib/comms.mjs +67 -0
- package/lib/comms.test.mjs +41 -0
- package/lib/diagnostics/alerts.mjs +424 -0
- package/lib/diagnostics/alerts.test.mjs +318 -0
- package/lib/diagnostics/backup-freshness.mjs +188 -0
- package/lib/diagnostics/backup-freshness.test.mjs +185 -0
- package/lib/diagnostics/counters.mjs +269 -0
- package/lib/diagnostics/counters.test.mjs +206 -0
- package/lib/diagnostics/events.mjs +188 -0
- package/lib/diagnostics/events.test.mjs +290 -0
- package/lib/diagnostics/otel.mjs +237 -0
- package/lib/diagnostics/otel.test.mjs +196 -0
- package/lib/diagnostics/trace.mjs +216 -0
- package/lib/diagnostics/trace.test.mjs +251 -0
- package/lib/env-compat.mjs +74 -0
- package/lib/env-compat.test.mjs +104 -0
- package/lib/feature-init.mjs +331 -0
- package/lib/fs-atomic.mjs +112 -0
- package/lib/fs-atomic.test.mjs +72 -0
- package/lib/fs-ownership.mjs +111 -0
- package/lib/fs-ownership.test.mjs +158 -0
- package/lib/hooks/bus.mjs +347 -0
- package/lib/hooks/bus.test.mjs +387 -0
- package/lib/index.js +16 -0
- package/lib/learning/config.mjs +106 -0
- package/lib/learning/config.test.mjs +75 -0
- package/lib/learning/counters.mjs +156 -0
- package/lib/learning/counters.test.mjs +69 -0
- package/lib/learning/curator-consolidate.test.mjs +238 -0
- package/lib/learning/curator.mjs +453 -0
- package/lib/learning/curator.test.mjs +106 -0
- package/lib/learning/log.mjs +40 -0
- package/lib/learning/reflect.mjs +534 -0
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.mjs +352 -0
- package/lib/learning/session-index.test.mjs +125 -0
- package/lib/learning/skill-writer.mjs +474 -0
- package/lib/learning/skill-writer.test.mjs +210 -0
- package/lib/mcp/server.mjs +328 -0
- package/lib/mcp/server.test.mjs +400 -0
- package/lib/model-router/auth-profiles.mjs +758 -0
- package/lib/model-router/auth-profiles.test.mjs +580 -0
- package/lib/model-router/catalog/anthropic.yaml +153 -0
- package/lib/model-router/catalog/deepseek.yaml +86 -0
- package/lib/model-router/catalog/moonshot.yaml +81 -0
- package/lib/model-router/catalog/qwen.yaml +114 -0
- package/lib/model-router/catalog.mjs +925 -0
- package/lib/model-router/catalog.test.mjs +385 -0
- package/lib/model-router/economics.mjs +564 -0
- package/lib/model-router/economics.test.mjs +344 -0
- package/lib/model-router/failover.mjs +298 -0
- package/lib/model-router/failover.test.mjs +439 -0
- package/lib/model-router/health.mjs +453 -0
- package/lib/model-router/health.test.mjs +338 -0
- package/lib/model-router/integration-coverage.test.mjs +829 -0
- package/lib/model-router/integration.test.mjs +564 -0
- package/lib/model-router/ledger.mjs +402 -0
- package/lib/model-router/ledger.test.mjs +382 -0
- package/lib/model-router/llm-task.mjs +515 -0
- package/lib/model-router/llm-task.test.mjs +392 -0
- package/lib/model-router/org-credentials.mjs +260 -0
- package/lib/model-router/org-credentials.test.mjs +265 -0
- package/lib/model-router/pricing-refresh.mjs +463 -0
- package/lib/model-router/pricing-refresh.test.mjs +286 -0
- package/lib/model-router/reconcile.mjs +429 -0
- package/lib/model-router/reconcile.test.mjs +316 -0
- package/lib/model-router/repair.mjs +471 -0
- package/lib/model-router/repair.test.mjs +180 -0
- package/lib/model-router/resolve.mjs +1206 -0
- package/lib/model-router/spawn.mjs +497 -0
- package/lib/model-router/spawn.test.mjs +425 -0
- package/lib/model-router/taxonomy.mjs +893 -0
- package/lib/model-router/taxonomy.test.mjs +410 -0
- package/lib/model-router.mjs +677 -0
- package/lib/model-router.test.mjs +907 -0
- package/lib/org/activity.mjs +211 -0
- package/lib/org/activity.test.mjs +134 -0
- package/lib/org/approvals.mjs +448 -0
- package/lib/org/approvals.test.mjs +216 -0
- package/lib/org/awareness.mjs +222 -0
- package/lib/org/awareness.test.mjs +159 -0
- package/lib/org/board.mjs +229 -0
- package/lib/org/board.test.mjs +177 -0
- package/lib/org/bootstrap-context.mjs +169 -0
- package/lib/org/bootstrap-context.test.mjs +153 -0
- package/lib/org/client.mjs +1628 -0
- package/lib/org/client.test.mjs +1107 -0
- package/lib/org/cohort-client.mjs +67 -0
- package/lib/org/cohort-client.test.mjs +126 -0
- package/lib/org/cost-sync.mjs +227 -0
- package/lib/org/cost-sync.test.mjs +153 -0
- package/lib/org/doctor.mjs +212 -0
- package/lib/org/doctor.test.mjs +212 -0
- package/lib/org/handoff.mjs +293 -0
- package/lib/org/handoff.test.mjs +269 -0
- package/lib/org/integration-tools.mjs +182 -0
- package/lib/org/integration-tools.test.mjs +160 -0
- package/lib/org/keys.mjs +131 -0
- package/lib/org/keys.test.mjs +92 -0
- package/lib/org/knowledge.mjs +463 -0
- package/lib/org/knowledge.test.mjs +319 -0
- package/lib/org/leases.mjs +335 -0
- package/lib/org/leases.test.mjs +235 -0
- package/lib/org/mesh-integration.test.mjs +127 -0
- package/lib/org/mesh.mjs +459 -0
- package/lib/org/mesh.test.mjs +345 -0
- package/lib/org/messaging.mjs +503 -0
- package/lib/org/messaging.test.mjs +238 -0
- package/lib/org/policy.mjs +345 -0
- package/lib/org/policy.test.mjs +237 -0
- package/lib/org/protocol.checksum +1 -0
- package/lib/org/protocol.checksum.test.mjs +90 -0
- package/lib/org/protocol.mjs +967 -0
- package/lib/org/protocol.test.mjs +264 -0
- package/lib/org/registry.mjs +194 -0
- package/lib/org/registry.test.mjs +100 -0
- package/lib/org/tool-surface-integration.test.mjs +120 -0
- package/lib/org/tool-surface.mjs +2535 -0
- package/lib/org/tool-surface.test.mjs +589 -0
- package/lib/org/ui-parity.mjs +3236 -0
- package/lib/org/ui-parity.test.mjs +348 -0
- package/lib/org/verify.mjs +176 -0
- package/lib/org/verify.test.mjs +194 -0
- package/lib/rag/embed.mjs +188 -0
- package/lib/rag/indexer.mjs +425 -0
- package/lib/rag/rag.test.mjs +505 -0
- package/lib/rag/search.mjs +475 -0
- package/lib/rate-guard.mjs +246 -0
- package/lib/rate-guard.test.mjs +201 -0
- package/lib/render.mjs +112 -0
- package/lib/render.test.mjs +68 -0
- package/lib/resource-governor.mjs +297 -0
- package/lib/resource-governor.test.mjs +262 -0
- package/lib/scheduling/dynamic-jobs.mjs +675 -0
- package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
- package/lib/scheduling/jitter.mjs +0 -0
- package/lib/scheduling/jitter.test.mjs +140 -0
- package/lib/secrets/broker.mjs +315 -0
- package/lib/secrets/broker.test.mjs +280 -0
- package/lib/secrets/providers.mjs +461 -0
- package/lib/secrets/providers.test.mjs +274 -0
- package/lib/security/audit-engine.mjs +684 -0
- package/lib/security/audit-engine.test.mjs +389 -0
- package/lib/security/coerce-args.mjs +552 -0
- package/lib/security/coerce-args.test.mjs +281 -0
- package/lib/security/dangerous-tools.mjs +97 -0
- package/lib/security/dangerous-tools.test.mjs +68 -0
- package/lib/security/external-content.mjs +145 -0
- package/lib/security/external-content.test.mjs +67 -0
- package/lib/security/redact.mjs +592 -0
- package/lib/security/redact.test.mjs +441 -0
- package/lib/security/secret-equal.mjs +73 -0
- package/lib/security/secret-equal.test.mjs +55 -0
- package/lib/session-permissions.mjs +101 -0
- package/lib/session-permissions.test.mjs +100 -0
- package/lib/setup/claude-probe.mjs +74 -0
- package/lib/setup/completeness.mjs +175 -0
- package/lib/setup/completeness.test.mjs +110 -0
- package/lib/setup/context-pack.mjs +173 -0
- package/lib/setup/context-pack.test.mjs +89 -0
- package/lib/setup/enrich.mjs +277 -0
- package/lib/setup/enrich.test.mjs +115 -0
- package/lib/setup/enroll-from-cohort.mjs +441 -0
- package/lib/setup/enroll-from-cohort.test.mjs +233 -0
- package/lib/setup/integration.test.mjs +162 -0
- package/lib/setup/io.mjs +360 -0
- package/lib/setup/io.test.mjs +77 -0
- package/lib/setup/run-generator.mjs +81 -0
- package/lib/setup/runner.mjs +244 -0
- package/lib/setup/runner.test.mjs +132 -0
- package/lib/setup/sections/comms.mjs +173 -0
- package/lib/setup/sections/company.mjs +120 -0
- package/lib/setup/sections/enrich.mjs +138 -0
- package/lib/setup/sections/identity.mjs +182 -0
- package/lib/setup/sections/identity.test.mjs +140 -0
- package/lib/setup/sections/learning.mjs +153 -0
- package/lib/setup/sections/learning.test.mjs +81 -0
- package/lib/setup/sections/messaging.mjs +219 -0
- package/lib/setup/sections/messaging.test.mjs +127 -0
- package/lib/setup/sections/model.mjs +102 -0
- package/lib/setup/sections/operating-model.mjs +78 -0
- package/lib/setup/sections/org.mjs +475 -0
- package/lib/setup/sections/org.test.mjs +313 -0
- package/lib/setup/sections/orgmail.mjs +173 -0
- package/lib/setup/sections/orgmail.test.mjs +118 -0
- package/lib/setup/sections/recovery.mjs +159 -0
- package/lib/setup/sections/recovery.test.mjs +98 -0
- package/lib/setup/sections/tools.mjs +132 -0
- package/lib/setup/sections/verify.mjs +97 -0
- package/lib/setup/sot.mjs +205 -0
- package/lib/setup/sot.test.mjs +81 -0
- package/lib/setup/state.mjs +151 -0
- package/lib/setup/state.test.mjs +92 -0
- package/lib/singleton.js +229 -0
- package/lib/singleton.test.mjs +135 -0
- package/lib/telemetry/alerts.mjs +216 -0
- package/lib/telemetry/alerts.test.mjs +109 -0
- package/lib/telemetry/collect.mjs +512 -0
- package/lib/telemetry/collect.test.mjs +202 -0
- package/lib/tool-definitions-integration.test.mjs +83 -0
- package/lib/tool-definitions.js +738 -0
- package/lib/tool-definitions.test.mjs +437 -0
- package/lib/util/fetch-timeout.mjs +136 -0
- package/lib/util/fetch-timeout.test.mjs +202 -0
- package/lib/util/reconnect.mjs +343 -0
- package/lib/util/reconnect.test.mjs +369 -0
- package/lib/util/unhandled.mjs +205 -0
- package/lib/util/unhandled.test.mjs +216 -0
- package/lib/voice/context-loader.mjs +466 -0
- package/lib/voice/index.mjs +100 -0
- package/lib/voice/openai-realtime.mjs +510 -0
- package/lib/voice/outbound.mjs +542 -0
- package/lib/voice/outbound.test.mjs +69 -0
- package/lib/voice/post-call-brief.mjs +428 -0
- package/lib/voice/provider.mjs +52 -0
- package/lib/voice/session-rotation.mjs +257 -0
- package/lib/voice/stt.mjs +161 -0
- package/lib/voice/stt.test.mjs +226 -0
- package/lib/voice/tool-bridge.mjs +370 -0
- package/lib/voice/tts.mjs +104 -0
- package/lib/voice/twilio-sip-bridge.mjs +288 -0
- package/lib/voice/voice.test.mjs +990 -0
- package/mcp/README.md +80 -0
- package/package.json +151 -0
- package/plugins/maestro-skills/plugin.json +139 -0
- package/plugins/maestro-skills/skills/agents-observe.md +110 -0
- package/plugins/maestro-skills/skills/board-deck.md +68 -0
- package/plugins/maestro-skills/skills/books-close.md +77 -0
- package/plugins/maestro-skills/skills/brand-steward.md +121 -0
- package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
- package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
- package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
- package/plugins/maestro-skills/skills/claude-pace.md +61 -0
- package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
- package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
- package/plugins/maestro-skills/skills/decision-brief.md +89 -0
- package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
- package/plugins/maestro-skills/skills/draft-comms.md +84 -0
- package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
- package/plugins/maestro-skills/skills/files-find.md +65 -0
- package/plugins/maestro-skills/skills/generative-ui.md +228 -0
- package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
- package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
- package/plugins/maestro-skills/skills/mail-triage.md +86 -0
- package/plugins/maestro-skills/skills/morning-brief.md +54 -0
- package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
- package/plugins/maestro-skills/skills/org-board.md +133 -0
- package/plugins/maestro-skills/skills/org-credential.md +68 -0
- package/plugins/maestro-skills/skills/org-recall.md +81 -0
- package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
- package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
- package/plugins/maestro-skills/skills/router-why.md +78 -0
- package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
- package/plugins/maestro-skills/skills/session-search.md +71 -0
- package/plugins/maestro-skills/skills/set-reminder.md +93 -0
- package/plugins/maestro-skills/skills/slack-followup.md +64 -0
- package/plugins/maestro-skills/skills/team-activity.md +86 -0
- package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
- package/policies/action-classification.yaml +114 -0
- package/policies/ai-disclosure.yaml +294 -0
- package/policies/communication-style.md +139 -0
- package/policies/information-barriers.yaml +118 -0
- package/policies/prompt-injection-defence.yaml +138 -0
- package/public/assets/icon-dark.png +0 -0
- package/public/assets/icon-dark.svg +9 -0
- package/public/assets/icon-light.svg +9 -0
- package/public/assets/logo-dark.svg +15 -0
- package/public/assets/logo-light.svg +15 -0
- package/scaffold/.mcp.json +7 -0
- package/scaffold/CLAUDE.md +368 -0
- package/scaffold/config/agent.json +55 -0
- package/scaffold/config/agent.ts +76 -0
- package/scaffold/config/agent.ts.example +89 -0
- package/scaffold/config/alerts.yaml +23 -0
- package/scaffold/config/allowlist.yaml.example +25 -0
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scaffold/config/collective.yaml +49 -0
- package/scaffold/config/company.json +20 -0
- package/scaffold/config/known-agents.json +6 -0
- package/scaffold/config/learning.yaml +55 -0
- package/scaffold/config/model-routing.yaml.example +104 -0
- package/scaffold/config/org.yaml +25 -0
- package/scaffold/config/orgmail.yaml.example +19 -0
- package/scaffold/config/recovery.yaml +72 -0
- package/scaffold/config/secrets.yaml +27 -0
- package/scaffold/config/slack.yaml.example +35 -0
- package/scaffold/config/telegram.yaml.example +38 -0
- package/scaffold/config/voice.yaml.example +89 -0
- package/scaffold/config/whatsapp.yaml.example +39 -0
- package/schedules/README.md +49 -0
- package/schedules/triggers/backlog-executor.md +102 -0
- package/schedules/triggers/brand-steward.md +72 -0
- package/schedules/triggers/daily-evening-wrap.md +159 -0
- package/schedules/triggers/daily-midday-sweep.md +58 -0
- package/schedules/triggers/daily-morning-brief.md +55 -0
- package/schedules/triggers/directory-hygiene.md +81 -0
- package/schedules/triggers/dynamic-jobs.md +40 -0
- package/schedules/triggers/inbox-processor.md +115 -0
- package/schedules/triggers/meeting-action-capture.md +60 -0
- package/schedules/triggers/meeting-prep.md +69 -0
- package/schedules/triggers/messaging-inbound.md +50 -0
- package/schedules/triggers/org-pulse.md +24 -0
- package/schedules/triggers/quarterly-self-assessment.md +54 -0
- package/schedules/triggers/weekly-engineering-health.md +37 -0
- package/schedules/triggers/weekly-execution.md +65 -0
- package/schedules/triggers/weekly-hiring.md +53 -0
- package/schedules/triggers/weekly-priorities.md +38 -0
- package/schedules/triggers/weekly-strategic-memo.md +124 -0
- package/scripts/archive-email.sh +55 -0
- package/scripts/cadence/cadence-status.mjs +36 -0
- package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
- package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
- package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
- package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
- package/scripts/ci/check-docs-accuracy.mjs +493 -0
- package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
- package/scripts/ci/check-exports-exist.mjs +140 -0
- package/scripts/ci/check-files-exist.mjs +107 -0
- package/scripts/ci/check-no-build-artifacts.mjs +111 -0
- package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
- package/scripts/ci/check-no-confidential.mjs +198 -0
- package/scripts/ci/check-no-conflict-markers.mjs +169 -0
- package/scripts/ci/check-no-residual-identity.mjs +163 -0
- package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
- package/scripts/ci/check-tarball-fidelity.mjs +205 -0
- package/scripts/ci/check-unresolved-tokens.mjs +83 -0
- package/scripts/ci/check.mjs +109 -0
- package/scripts/ci/check.test.mjs +194 -0
- package/scripts/ci/run-coverage.mjs +82 -0
- package/scripts/ci/run-tests.mjs +71 -0
- package/scripts/cloud-relay/README.md +59 -0
- package/scripts/cloud-relay/index.mjs +233 -0
- package/scripts/cloud-relay/package.json +15 -0
- package/scripts/cloud-relay/railway.json +13 -0
- package/scripts/cloud-relay/voice/README.md +94 -0
- package/scripts/cloud-relay/voice/package-lock.json +39 -0
- package/scripts/cloud-relay/voice/package.json +16 -0
- package/scripts/cloud-relay/voice/railway.json +13 -0
- package/scripts/cloud-relay/voice/server.mjs +532 -0
- package/scripts/collective/hook-runner.mjs +211 -0
- package/scripts/collective/hook-runner.test.mjs +90 -0
- package/scripts/collective/org-pulse.mjs +72 -0
- package/scripts/collective/org-sync.mjs +61 -0
- package/scripts/collective/recall.mjs +45 -0
- package/scripts/collective/who.mjs +30 -0
- package/scripts/comms-monitor.sh +288 -0
- package/scripts/configure-whatsapp-sandbox.sh +201 -0
- package/scripts/continuous-monitor.sh +91 -0
- package/scripts/cost/fleet-digest.mjs +407 -0
- package/scripts/cost/fleet-digest.test.mjs +207 -0
- package/scripts/cost/track-claude-usage.mjs +169 -0
- package/scripts/daemon/agent-daemon.mjs +989 -0
- package/scripts/daemon/agent-daemon.test.mjs +525 -0
- package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
- package/scripts/daemon/cadence-consumer.mjs +1080 -0
- package/scripts/daemon/cadence-consumer.test.mjs +770 -0
- package/scripts/daemon/cadence-handlers.mjs +1121 -0
- package/scripts/daemon/cadence-handlers.test.mjs +617 -0
- package/scripts/daemon/classifier.mjs +704 -0
- package/scripts/daemon/classifier.test.mjs +238 -0
- package/scripts/daemon/classify-kind.mjs +54 -0
- package/scripts/daemon/classify-kind.test.mjs +40 -0
- package/scripts/daemon/context-compiler.mjs +605 -0
- package/scripts/daemon/context-compiler.test.mjs +300 -0
- package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
- package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
- package/scripts/daemon/dispatcher.mjs +1516 -0
- package/scripts/daemon/health.mjs +72 -0
- package/scripts/daemon/inbox-deferral.mjs +210 -0
- package/scripts/daemon/inbox-deferral.test.mjs +242 -0
- package/scripts/daemon/integration.test.mjs +149 -0
- package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
- package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
- package/scripts/daemon/launchd-wrapper.sh +91 -0
- package/scripts/daemon/lib/session-router.mjs +274 -0
- package/scripts/daemon/lib/session-router.test.mjs +295 -0
- package/scripts/daemon/maestro-daemon.mjs +275 -0
- package/scripts/daemon/prompt-builder.mjs +685 -0
- package/scripts/daemon/prompt-builder.test.mjs +213 -0
- package/scripts/daemon/responder.mjs +854 -0
- package/scripts/daemon/session-lock.mjs +721 -0
- package/scripts/daemon/session-lock.test.mjs +252 -0
- package/scripts/daemon/session-outcomes.mjs +640 -0
- package/scripts/daemon/session-outcomes.test.mjs +533 -0
- package/scripts/daemon/typing-registry.mjs +90 -0
- package/scripts/daemon/typing-registry.test.mjs +77 -0
- package/scripts/daemon/voice-webhook-server.mjs +804 -0
- package/scripts/decisions/capture-decision.mjs +116 -0
- package/scripts/disclosure_assessment.py +873 -0
- package/scripts/disclosure_boundaries.py +562 -0
- package/scripts/email-signature-principal.html +52 -0
- package/scripts/email-signature.html +60 -0
- package/scripts/email_quote_thread.py +167 -0
- package/scripts/email_thread_dedup.py +362 -0
- package/scripts/emergency-stop.sh +81 -0
- package/scripts/healthcheck.sh +116 -0
- package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
- package/scripts/hooks/block-mcp-slack-send.sh +7 -0
- package/scripts/hooks/post-action-log.sh +126 -0
- package/scripts/hooks/pre-send-audit.sh +174 -0
- package/scripts/hooks/pre-send-audit.test.mjs +215 -0
- package/scripts/hooks/session-end-log.sh +27 -0
- package/scripts/hooks/session-start-banner.sh +115 -0
- package/scripts/huddle/audio-bridge.mjs +664 -0
- package/scripts/huddle/boot-slack-cdp.sh +102 -0
- package/scripts/huddle/huddle-controller.mjs +942 -0
- package/scripts/huddle/huddle-server.mjs +1229 -0
- package/scripts/huddle/launch-slack.sh +232 -0
- package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
- package/scripts/huddle/package-lock.json +62 -0
- package/scripts/huddle/package.json +22 -0
- package/scripts/huddle/setup-audio.sh +239 -0
- package/scripts/huddle/start-call.mjs +318 -0
- package/scripts/huddle/test-pipeline.mjs +263 -0
- package/scripts/learning/consolidate-skills.mjs +72 -0
- package/scripts/learning/session-search.mjs +125 -0
- package/scripts/llm_email_dedup.py +442 -0
- package/scripts/local-triggers/generate-plists.sh +432 -0
- package/scripts/local-triggers/generate-plists.test.mjs +413 -0
- package/scripts/local-triggers/install-all.sh +49 -0
- package/scripts/local-triggers/plists/.gitkeep +0 -0
- package/scripts/local-triggers/run-trigger.sh +63 -0
- package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
- package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
- package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
- package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
- package/scripts/maintenance/backup-to-cloud.sh +124 -0
- package/scripts/maintenance/health-check.sh +377 -0
- package/scripts/media-generation/README.md +105 -0
- package/scripts/media-generation/gemini-image-client.mjs +173 -0
- package/scripts/media-generation/generate-assets.mjs +289 -0
- package/scripts/media-generation/veo-video-client.mjs +219 -0
- package/scripts/org/send-orgmail.mjs +227 -0
- package/scripts/outbound-dedup-cleanup.sh +43 -0
- package/scripts/outbound-dedup.sh +477 -0
- package/scripts/outbound_dedup.py +115 -0
- package/scripts/parse-voice-transcript.mjs +481 -0
- package/scripts/pdf-generation/README.md +63 -0
- package/scripts/pdf-generation/build-document.mjs +247 -0
- package/scripts/pdf-generation/templates/board-pack.latex +136 -0
- package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
- package/scripts/pdf-generation/templates/memo.latex +114 -0
- package/scripts/poll-slack-events.sh +35 -0
- package/scripts/poller/calendar-poller.mjs +12 -0
- package/scripts/poller/gmail-poller.mjs +192 -0
- package/scripts/poller/imap-client.mjs +289 -0
- package/scripts/poller/inbox-scan-poller.mjs +156 -0
- package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
- package/scripts/poller/index.mjs +73 -0
- package/scripts/poller/intra-session-check.mjs +285 -0
- package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
- package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
- package/scripts/poller/secondary-gmail-poller.mjs +132 -0
- package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
- package/scripts/poller/slack-poller.mjs +854 -0
- package/scripts/poller/slack-socket-mode.mjs +917 -0
- package/scripts/poller/slack-socket-mode.test.mjs +753 -0
- package/scripts/poller/trigger.mjs +75 -0
- package/scripts/poller/utils.mjs +371 -0
- package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
- package/scripts/poller/voice-poller.mjs +236 -0
- package/scripts/poller-launchd/install.sh +66 -0
- package/scripts/poller-launchd/poller.plist.template +40 -0
- package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
- package/scripts/post-interaction-indexer.py +1598 -0
- package/scripts/pre-draft-context.py +994 -0
- package/scripts/pre_draft_lookup.py +258 -0
- package/scripts/rag/build-index.mjs +47 -0
- package/scripts/rag/ingest.mjs +111 -0
- package/scripts/rag/search.mjs +119 -0
- package/scripts/rag-indexer.py +629 -0
- package/scripts/restore-from-backup.sh +248 -0
- package/scripts/restore-from-backup.test.mjs +178 -0
- package/scripts/resume-operations.sh +80 -0
- package/scripts/search-secondary-inbox.py +181 -0
- package/scripts/secondary-inbox-poller.py +437 -0
- package/scripts/self-optimization/compute-metrics.py +398 -0
- package/scripts/send-email-as-principal.py +369 -0
- package/scripts/send-email-threaded.py +392 -0
- package/scripts/send-email-with-attachment.py +377 -0
- package/scripts/send-email.sh +131 -0
- package/scripts/send-sms.sh +175 -0
- package/scripts/send-whatsapp.sh +292 -0
- package/scripts/session-start.sh +106 -0
- package/scripts/setup/boot-claude-session.sh +94 -0
- package/scripts/setup/configure-macos.sh +674 -0
- package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
- package/scripts/setup/configure-voice-tunnel.mjs +182 -0
- package/scripts/setup/generate-agent-env.mjs +92 -0
- package/scripts/setup/generate-agent-package-json.mjs +222 -0
- package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
- package/scripts/setup/generate-autonomy.mjs +60 -0
- package/scripts/setup/generate-backlog.mjs +101 -0
- package/scripts/setup/generate-cadences.mjs +92 -0
- package/scripts/setup/generate-capability.mjs +162 -0
- package/scripts/setup/generate-charter.mjs +76 -0
- package/scripts/setup/generate-comms.mjs +59 -0
- package/scripts/setup/generate-company.mjs +92 -0
- package/scripts/setup/init-agent.sh +547 -0
- package/scripts/setup/init-agent.test.mjs +151 -0
- package/scripts/setup/init-archetype.mjs +74 -0
- package/scripts/setup/init-backup.mjs +54 -0
- package/scripts/setup/init-cadence-bus.mjs +60 -0
- package/scripts/setup/init-channel-bus.mjs +46 -0
- package/scripts/setup/init-cost-tracking.mjs +45 -0
- package/scripts/setup/init-decision-capture.mjs +66 -0
- package/scripts/setup/init-known-agents.mjs +57 -0
- package/scripts/setup/init-learning.mjs +70 -0
- package/scripts/setup/init-memory-executive.mjs +45 -0
- package/scripts/setup/init-model-router.mjs +124 -0
- package/scripts/setup/init-rag.mjs +174 -0
- package/scripts/setup/init-session-router.mjs +38 -0
- package/scripts/setup/init-slack-socket-mode.mjs +260 -0
- package/scripts/setup/init-telegram.mjs +165 -0
- package/scripts/setup/init-voice-realtime.mjs +204 -0
- package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
- package/scripts/setup/install-dev-tools.sh +150 -0
- package/scripts/setup/lib/install-plist.mjs +95 -0
- package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
- package/scripts/setup/render-environment-yaml.mjs +133 -0
- package/scripts/slack-events-ctl.sh +177 -0
- package/scripts/slack-events-server.mjs +1045 -0
- package/scripts/slack-react.mjs +89 -0
- package/scripts/slack-responded.sh +232 -0
- package/scripts/slack-send.sh +287 -0
- package/scripts/slack-typing.mjs +196 -0
- package/scripts/slack-upload-v2.py +95 -0
- package/scripts/sms-handler.mjs +450 -0
- package/scripts/spawn-session.sh +120 -0
- package/scripts/sync-protocol.mjs +217 -0
- package/scripts/system-verify.sh +184 -0
- package/scripts/test-email-thread-dedup.py +239 -0
- package/scripts/test-information-barriers.py +484 -0
- package/scripts/test-llm-email-dedup.py +251 -0
- package/scripts/test-pre-draft-integration.py +203 -0
- package/scripts/test-rag-phase2.sh +442 -0
- package/scripts/test-rag-search.sh +251 -0
- package/scripts/test-voice-parser.mjs +316 -0
- package/scripts/user-context-search.py +659 -0
- package/scripts/validate_outbound.py +1504 -0
- package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
- package/scripts/watchdog/force-reboot.sh +157 -0
- package/scripts/watchdog/memory-watchdog.sh +473 -0
- package/scripts/whatsapp-handler.mjs +538 -0
- package/teams/desktop-operations.yaml +34 -0
- package/teams/executive-office.yaml +27 -0
- package/teams/legal-and-regulatory.yaml +24 -0
- package/teams/platform-and-engineering.yaml +23 -0
- package/teams/strategy-and-growth.yaml +29 -0
- package/workflows/continuous/backlog-executor.yaml +141 -0
- package/workflows/continuous/inbound-monitor.yaml +168 -0
- package/workflows/daily/applicant-triage.yaml +197 -0
- package/workflows/daily/comms-triage.yaml +80 -0
- package/workflows/daily/evening-wrap.yaml +105 -0
- package/workflows/daily/morning-brief.yaml +164 -0
- package/workflows/daily/slack-followup-sweep.yaml +87 -0
- package/workflows/event-driven/README.md +50 -0
- package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
- package/workflows/event-driven/pr-review.yaml +107 -0
- package/workflows/monthly/board-readiness.yaml +76 -0
- package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
- package/workflows/session-protocol.md +171 -0
- package/workflows/weekly/engineering-health.yaml +154 -0
- package/workflows/weekly/hiring-review.yaml +169 -0
- package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
- package/workflows/weekly/strategic-memo.yaml +79 -0
package/lib/cadences.mjs
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cadences.mjs — resolve an archetype's scheduled-task cadence set.
|
|
3
|
+
*
|
|
4
|
+
* "Which scheduled tasks run, when" is a function of the archetype, not a fixed
|
|
5
|
+
* 13-tick rhythm. The resolved cadence list =
|
|
6
|
+
* STANDARD_CADENCES (every agent: inbox/backlog/meeting sweeps + daily brief/
|
|
7
|
+
* sweep/wrap + quarterly self-assessment)
|
|
8
|
+
* ⊕ the function's recurring workflows (from the capability pack — pr-review is
|
|
9
|
+
* event-driven so excluded; engineering-health/weekly, release-train/weekly,
|
|
10
|
+
* capacity-cost/monthly, … become scheduled cadences)
|
|
11
|
+
* ⊕ altitude cadences (a C-suite/SVP gets a weekly strategic memo + board pack;
|
|
12
|
+
* a founder gets runway + investor-update; a VP/senior-manager gets a
|
|
13
|
+
* priorities/execution review).
|
|
14
|
+
*
|
|
15
|
+
* Schedules for function/altitude cadences are assigned deterministically and
|
|
16
|
+
* staggered (by a stable slot derived from the id) so they don't all fire at
|
|
17
|
+
* once. The init generator writes the resolved set to config/cadences.yaml;
|
|
18
|
+
* generate-plists.sh emits launchd plists from it, and cadence-handlers.mjs
|
|
19
|
+
* consults it (both fall back to the legacy hardcoded set when it's absent).
|
|
20
|
+
*
|
|
21
|
+
* Pure-ish (reads the capability pack). Deterministic (no Date/random). ESM.
|
|
22
|
+
*
|
|
23
|
+
* @module cadences
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
"use strict";
|
|
27
|
+
|
|
28
|
+
import { loadCapabilityPack, listCapabilityFunctions } from "./capability.mjs";
|
|
29
|
+
|
|
30
|
+
/** The standard cadences every maestro agent runs, with explicit schedules. */
|
|
31
|
+
export const STANDARD_CADENCES = [
|
|
32
|
+
{ id: "inbox-processor", scope: "standard", mode: "guarded", interval: 300, prompt: "schedules/triggers/inbox-processor.md" },
|
|
33
|
+
{ id: "backlog-executor", scope: "standard", mode: "guarded", interval: 600, prompt: "schedules/triggers/backlog-executor.md" },
|
|
34
|
+
{ id: "meeting-prep", scope: "standard", mode: "guarded", interval: 900, prompt: "schedules/triggers/meeting-prep.md" },
|
|
35
|
+
{ id: "meeting-action-capture", scope: "standard", mode: "escalate", interval: 1800, prompt: "schedules/triggers/meeting-action-capture.md" },
|
|
36
|
+
{ id: "daily-morning-brief", scope: "standard", mode: "escalate", calendar: { hour: 6, minute: 30 }, prompt: "schedules/triggers/daily-morning-brief.md" },
|
|
37
|
+
{ id: "daily-midday-sweep", scope: "standard", mode: "escalate", calendar: { hour: 12, minute: 0 }, prompt: "schedules/triggers/daily-midday-sweep.md" },
|
|
38
|
+
{ id: "daily-evening-wrap", scope: "standard", mode: "escalate", calendar: { hour: 18, minute: 0 }, prompt: "schedules/triggers/daily-evening-wrap.md" },
|
|
39
|
+
{ id: "quarterly-self-assessment", scope: "standard", mode: "escalate", calendar: { day: 1, hour: 9, minute: 0 }, prompt: "schedules/triggers/quarterly-self-assessment.md" },
|
|
40
|
+
{ id: "org-pulse", scope: "standard", mode: "escalate", calendar: { hour: 7, minute: 30 }, prompt: "schedules/triggers/org-pulse.md" },
|
|
41
|
+
// WS3 self-learning: deterministic skill lifecycle housekeeping. Guarded +
|
|
42
|
+
// inline (no prompt) — the daemon only runs the pure curator transitions when
|
|
43
|
+
// a self-authored skill has crossed a 30/90-day staleness boundary.
|
|
44
|
+
{ id: "skill-curator", scope: "standard", mode: "guarded", calendar: { hour: 4, minute: 0 } },
|
|
45
|
+
// Economics / scheduling cadences (WS-economics). All deterministic, so they
|
|
46
|
+
// run INLINE in the persistent daemon (no LLM, no sub-session) — except
|
|
47
|
+
// dynamic-jobs, which is GUARDED: its guard escalates ONLY when an agent-created
|
|
48
|
+
// job is actually due, so the consumer spawns a session to action it.
|
|
49
|
+
// nightly-cost-reconcile: three-way spend reconcile vs the Admin Cost API
|
|
50
|
+
// (fails open with no fetchImpl); flags drift > 10%. Inline, no prompt.
|
|
51
|
+
{ id: "nightly-cost-reconcile", scope: "standard", mode: "inline", calendar: { hour: 3, minute: 30 } },
|
|
52
|
+
// fleet-cost-digest: build the daily fleet LLM-spend digest. Inline, no prompt.
|
|
53
|
+
{ id: "fleet-cost-digest", scope: "standard", mode: "inline", calendar: { hour: 7, minute: 0 } },
|
|
54
|
+
// org-cost-sync: push today's router ledger rows to Cohort cost.report
|
|
55
|
+
// (no-op / fail-open when org.cohort is disabled). Inline, hourly, no prompt.
|
|
56
|
+
{ id: "org-cost-sync", scope: "standard", mode: "inline", interval: 3600 },
|
|
57
|
+
// monitoring-alerts: evaluate + emit behavioral alerts every 5min. Inline, no prompt.
|
|
58
|
+
{ id: "monitoring-alerts", scope: "standard", mode: "inline", interval: 300 },
|
|
59
|
+
// dynamic-jobs: action agent-created one-off / recurring reminders. Guarded —
|
|
60
|
+
// the guard escalates only when dueJobs() returns work; otherwise inline.
|
|
61
|
+
{ id: "dynamic-jobs", scope: "standard", mode: "guarded", interval: 60, prompt: "schedules/triggers/dynamic-jobs.md" },
|
|
62
|
+
// messaging-inbound (SP10): pull Cohort org messages/@mentions/call-invites
|
|
63
|
+
// directed at this agent into the inbox pipeline. Guarded — routes inline (the
|
|
64
|
+
// reactive daemon owns dispatch); escalate-when-items with
|
|
65
|
+
// MESSAGING_INBOUND_ESCALATE=1. Fail-open / no-op when org messaging disabled.
|
|
66
|
+
{ id: "messaging-inbound", scope: "standard", mode: "guarded", interval: 45, prompt: "schedules/triggers/messaging-inbound.md" },
|
|
67
|
+
// directory-hygiene (2026-07): keep the Directory clean — propose captures
|
|
68
|
+
// from signatures/rosters/bank feeds, enrich channels, re-verify anything
|
|
69
|
+
// unseen for >90d, flag duplicates. Guarded: the cheap pre-check reads the two
|
|
70
|
+
// review queues and escalates only when one has work, so an idle org costs two
|
|
71
|
+
// GETs a day and no LLM. PROPOSE-ONLY — merges, awareness changes and archives
|
|
72
|
+
// are human-gated server-side, so the cadence cannot mutate a record.
|
|
73
|
+
{ id: "directory-hygiene", scope: "standard", mode: "guarded", calendar: { hour: 5, minute: 0 }, prompt: "schedules/triggers/directory-hygiene.md" },
|
|
74
|
+
// brand-steward (2026-07): a brand foundation save is what makes rendered
|
|
75
|
+
// imagery and templates stale, so this is EVENT-driven, not report-driven —
|
|
76
|
+
// the guard tails the org event chain for branding version.saved and escalates
|
|
77
|
+
// only on a real save. 15min keeps the reaction prompt without polling hard.
|
|
78
|
+
{ id: "brand-steward", scope: "standard", mode: "guarded", interval: 900, prompt: "schedules/triggers/brand-steward.md" },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
/** Altitude-specific cadences (reuse existing triggers where one exists). */
|
|
82
|
+
export const ALTITUDE_CADENCES = {
|
|
83
|
+
founder: [
|
|
84
|
+
{ id: "weekly-runway-review", cadence: "weekly", purpose: "Review runway, burn, and capital position" },
|
|
85
|
+
{ id: "monthly-investor-update", cadence: "monthly", purpose: "Draft the monthly investor update" },
|
|
86
|
+
],
|
|
87
|
+
"c-suite": [
|
|
88
|
+
{ id: "weekly-strategic-memo", cadence: "weekly", purpose: "Weekly strategic memo for the principal/board", prompt: "schedules/triggers/weekly-strategic-memo.md" },
|
|
89
|
+
{ id: "monthly-board-readiness", cadence: "monthly", purpose: "Maintain board-readiness materials" },
|
|
90
|
+
],
|
|
91
|
+
svp: [
|
|
92
|
+
{ id: "weekly-strategic-memo", cadence: "weekly", purpose: "Weekly strategic memo", prompt: "schedules/triggers/weekly-strategic-memo.md" },
|
|
93
|
+
],
|
|
94
|
+
vp: [
|
|
95
|
+
{ id: "weekly-priorities", cadence: "weekly", purpose: "Weekly priorities review", prompt: "schedules/triggers/weekly-priorities.md" },
|
|
96
|
+
],
|
|
97
|
+
"senior-manager": [
|
|
98
|
+
{ id: "weekly-execution", cadence: "weekly", purpose: "Weekly execution review", prompt: "schedules/triggers/weekly-execution.md" },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/** Cadence keywords that map to a recurring schedule (event-driven is excluded). */
|
|
103
|
+
export const RECURRING = new Set(["daily", "weekly", "monthly", "quarterly", "continuous"]);
|
|
104
|
+
|
|
105
|
+
/** Stable non-negative slot from a string id (deterministic stagger). */
|
|
106
|
+
function slotOf(id) {
|
|
107
|
+
let h = 0;
|
|
108
|
+
for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0;
|
|
109
|
+
return h;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Deterministic, staggered launchd schedule for a cadence keyword.
|
|
114
|
+
* @param {string} cadence @param {string} id @returns {object} { interval } | { calendar }
|
|
115
|
+
*/
|
|
116
|
+
export function scheduleFor(cadence, id) {
|
|
117
|
+
const s = slotOf(id);
|
|
118
|
+
switch (cadence) {
|
|
119
|
+
case "continuous": return { interval: 600 };
|
|
120
|
+
case "daily": return { calendar: { hour: 8 + (s % 9), minute: (s % 2) * 30 } };
|
|
121
|
+
case "weekly": return { calendar: { weekday: 1 + (s % 5), hour: 9 + (s % 7), minute: (s % 2) * 30 } };
|
|
122
|
+
case "monthly": return { calendar: { day: 1 + (s % 5), hour: 9 + (s % 6), minute: 0 } };
|
|
123
|
+
case "quarterly": return { calendar: { day: 1, hour: 9 + (s % 6), minute: 0 } }; // handler guards to quarter
|
|
124
|
+
default: return { interval: 3600 };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Months (1-12) that open a calendar quarter — Jan, Apr, Jul, Oct. */
|
|
129
|
+
const QUARTER_START_MONTHS = new Set([1, 4, 7, 10]);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Quarter guard for a cadence that fires monthly (Day=1) but is logically
|
|
133
|
+
* quarterly. The `quarterly-self-assessment` plist fires on the 1st of EVERY
|
|
134
|
+
* month; this returns true only in the first month of each quarter so the
|
|
135
|
+
* handler/trigger can no-op the other 8 ticks instead of delivering a
|
|
136
|
+
* "quarterly" report 12×/year. Pure + deterministic (caller supplies the date).
|
|
137
|
+
*
|
|
138
|
+
* @param {Date} [now] @returns {boolean}
|
|
139
|
+
*/
|
|
140
|
+
export function isQuarterStartMonth(now = new Date()) {
|
|
141
|
+
return QUARTER_START_MONTHS.has(now.getMonth() + 1); // getMonth() is 0-based
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Eligibility guard for a cadence tick. For the quarterly self-assessment
|
|
146
|
+
* (which is scheduled monthly so an outage spanning a quarter boundary still
|
|
147
|
+
* fires) a tick is only due in a quarter-start month. All other cadences are
|
|
148
|
+
* always due here (their own guard/handler decides finer-grained eligibility).
|
|
149
|
+
*
|
|
150
|
+
* @param {string} cadenceId @param {Date} [now] @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
export function isCadenceDue(cadenceId, now = new Date()) {
|
|
153
|
+
if (cadenceId === "quarterly-self-assessment") return isQuarterStartMonth(now);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function normalize(entry, scope) {
|
|
158
|
+
const out = { id: entry.id, scope, mode: entry.mode || "escalate", prompt: entry.prompt || `schedules/triggers/${entry.id}.md` };
|
|
159
|
+
if (entry.interval != null) out.interval = entry.interval;
|
|
160
|
+
else if (entry.calendar) out.calendar = entry.calendar;
|
|
161
|
+
else {
|
|
162
|
+
const sch = scheduleFor(entry.cadence, entry.id);
|
|
163
|
+
Object.assign(out, sch);
|
|
164
|
+
}
|
|
165
|
+
if (entry.purpose) out.purpose = entry.purpose;
|
|
166
|
+
if (entry.cadence) out.cadence = entry.cadence;
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Resolve the full cadence set for a { function, altitude }.
|
|
172
|
+
* @param {{function:string, altitude:string}} sel
|
|
173
|
+
* @returns {Promise<object[]>} ordered, de-duplicated cadence entries
|
|
174
|
+
*/
|
|
175
|
+
export async function resolveCadences(sel = {}) {
|
|
176
|
+
const { function: fn, altitude } = sel;
|
|
177
|
+
if (!fn || !altitude) throw new Error("resolveCadences: requires { function, altitude }");
|
|
178
|
+
|
|
179
|
+
const out = [];
|
|
180
|
+
const seen = new Set();
|
|
181
|
+
const add = (entry, scope) => {
|
|
182
|
+
if (!entry || !entry.id || seen.has(entry.id)) return;
|
|
183
|
+
seen.add(entry.id);
|
|
184
|
+
out.push(normalize(entry, scope));
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
for (const c of STANDARD_CADENCES) add(c, "standard");
|
|
188
|
+
|
|
189
|
+
// Function cadences = the capability pack's recurring workflows.
|
|
190
|
+
try {
|
|
191
|
+
const pack = await loadCapabilityPack(fn);
|
|
192
|
+
for (const wf of pack.workflows || []) {
|
|
193
|
+
if (RECURRING.has(wf.cadence)) add(wf, "function");
|
|
194
|
+
}
|
|
195
|
+
} catch { /* no capability pack for this function — standard + altitude only */ }
|
|
196
|
+
|
|
197
|
+
for (const c of ALTITUDE_CADENCES[altitude] || []) add(c, "altitude");
|
|
198
|
+
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** All function ids that can resolve a cadence set. @returns {string[]} */
|
|
203
|
+
export function listCadenceFunctions() {
|
|
204
|
+
return listCapabilityFunctions();
|
|
205
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cadences.test.mjs — tests for the archetype cadence resolver.
|
|
3
|
+
* Run: `node --test lib/cadences.test.mjs`
|
|
4
|
+
* @module cadences.test
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
import { test } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { resolveCadences, scheduleFor, STANDARD_CADENCES, RECURRING, isQuarterStartMonth, isCadenceDue } from "./cadences.mjs";
|
|
12
|
+
|
|
13
|
+
function hasSchedule(c) {
|
|
14
|
+
return typeof c.interval === "number" || (c.calendar && typeof c.calendar === "object");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test("resolveCadences = standard ⊕ function recurring workflows ⊕ altitude cadences", async () => {
|
|
18
|
+
const cads = await resolveCadences({ function: "technical-leader", altitude: "c-suite" });
|
|
19
|
+
const ids = cads.map((c) => c.id);
|
|
20
|
+
// standard present
|
|
21
|
+
assert.ok(ids.includes("inbox-processor") && ids.includes("daily-morning-brief"));
|
|
22
|
+
// a function recurring cadence (from the technical-leader capability workflows)
|
|
23
|
+
assert.ok(ids.includes("engineering-health"), `expected a function cadence; got ${ids.join(",")}`);
|
|
24
|
+
// altitude cadence (c-suite → strategic memo)
|
|
25
|
+
assert.ok(ids.includes("weekly-strategic-memo"));
|
|
26
|
+
// every entry has a concrete schedule + unique ids
|
|
27
|
+
assert.ok(cads.every(hasSchedule), "every cadence has interval or calendar");
|
|
28
|
+
assert.equal(ids.length, new Set(ids).size, "no duplicate cadence ids");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("event-driven workflows are excluded from cadences (pr-review is not scheduled)", async () => {
|
|
32
|
+
const cads = await resolveCadences({ function: "technical-leader", altitude: "vp" });
|
|
33
|
+
assert.ok(!cads.some((c) => c.id === "pr-review"), "event-driven pr-review must not be a scheduled cadence");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("altitude changes the cadence set (c-suite memo vs senior-manager execution review)", async () => {
|
|
37
|
+
const cSuite = (await resolveCadences({ function: "operations-leader", altitude: "c-suite" })).map((c) => c.id);
|
|
38
|
+
const srMgr = (await resolveCadences({ function: "operations-leader", altitude: "senior-manager" })).map((c) => c.id);
|
|
39
|
+
assert.ok(cSuite.includes("weekly-strategic-memo"));
|
|
40
|
+
assert.ok(srMgr.includes("weekly-execution"));
|
|
41
|
+
assert.notDeepEqual(cSuite, srMgr);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("scheduleFor is deterministic and matches the cadence keyword", () => {
|
|
45
|
+
assert.deepEqual(scheduleFor("weekly", "x"), scheduleFor("weekly", "x"));
|
|
46
|
+
assert.ok(scheduleFor("continuous", "x").interval);
|
|
47
|
+
assert.ok(scheduleFor("weekly", "engineering-health").calendar.weekday >= 1);
|
|
48
|
+
assert.ok(RECURRING.has("weekly") && !RECURRING.has("event-driven"));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("resolveCadences requires { function, altitude }", async () => {
|
|
52
|
+
await assert.rejects(() => resolveCadences({}), /requires/);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("quarter guard: quarterly cadence is due in Jan/Apr/Jul/Oct, not other months", () => {
|
|
56
|
+
// The plist fires Day=1 of every month; the guard restricts it to the
|
|
57
|
+
// quarter-start months so the principal gets 4, not 12, reports/year.
|
|
58
|
+
const due = [1, 4, 7, 10];
|
|
59
|
+
for (let month = 1; month <= 12; month++) {
|
|
60
|
+
// Day 1 of each month, midday local to dodge any TZ/DST edge.
|
|
61
|
+
const d = new Date(2026, month - 1, 1, 12, 0, 0);
|
|
62
|
+
const expected = due.includes(month);
|
|
63
|
+
assert.equal(isQuarterStartMonth(d), expected, `month ${month}: isQuarterStartMonth`);
|
|
64
|
+
assert.equal(isCadenceDue("quarterly-self-assessment", d), expected, `month ${month}: quarterly due`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("quarter guard does not constrain non-quarterly cadences", () => {
|
|
69
|
+
// A daily cadence is due every month — the guard is quarterly-only.
|
|
70
|
+
for (let month = 1; month <= 12; month++) {
|
|
71
|
+
const d = new Date(2026, month - 1, 1, 12, 0, 0);
|
|
72
|
+
assert.equal(isCadenceDue("daily-morning-brief", d), true, `month ${month}: daily always due`);
|
|
73
|
+
assert.equal(isCadenceDue("org-pulse", d), true, `month ${month}: org-pulse always due`);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("STANDARD_CADENCES all carry a schedule; escalating ones carry a prompt", () => {
|
|
78
|
+
assert.ok(STANDARD_CADENCES.length >= 8);
|
|
79
|
+
// Every standard cadence is scheduled.
|
|
80
|
+
assert.ok(STANDARD_CADENCES.every((c) => hasSchedule(c)));
|
|
81
|
+
// Cadences that spawn a sub-session must carry a prompt; a guarded-inline
|
|
82
|
+
// cadence (e.g. skill-curator) legitimately has none — the daemon handles it
|
|
83
|
+
// in-process and never escalates.
|
|
84
|
+
assert.ok(STANDARD_CADENCES.filter((c) => c.mode === "escalate").every((c) => c.prompt));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("economics/scheduling cadences are wired into STANDARD_CADENCES with the right mode + schedule", () => {
|
|
88
|
+
const byId = Object.fromEntries(STANDARD_CADENCES.map((c) => [c.id, c]));
|
|
89
|
+
// Deterministic economics cadences run inline (no LLM).
|
|
90
|
+
for (const id of ["nightly-cost-reconcile", "fleet-cost-digest", "org-cost-sync"]) {
|
|
91
|
+
assert.ok(byId[id], `${id} present in STANDARD_CADENCES`);
|
|
92
|
+
assert.equal(byId[id].mode, "inline", `${id} is inline (deterministic)`);
|
|
93
|
+
assert.ok(hasSchedule(byId[id]), `${id} has a schedule`);
|
|
94
|
+
}
|
|
95
|
+
// Calendar-pinned: nightly-cost-reconcile ~3:30am, fleet-cost-digest ~7am.
|
|
96
|
+
assert.deepEqual(byId["nightly-cost-reconcile"].calendar, { hour: 3, minute: 30 });
|
|
97
|
+
assert.deepEqual(byId["fleet-cost-digest"].calendar, { hour: 7, minute: 0 });
|
|
98
|
+
// org-cost-sync is an hourly interval.
|
|
99
|
+
assert.equal(byId["org-cost-sync"].interval, 3600);
|
|
100
|
+
// dynamic-jobs is the only GUARDED economics cadence (escalate-when-due) and a
|
|
101
|
+
// ~60s interval; because it can escalate it must carry a prompt.
|
|
102
|
+
assert.ok(byId["dynamic-jobs"], "dynamic-jobs present");
|
|
103
|
+
assert.equal(byId["dynamic-jobs"].mode, "guarded");
|
|
104
|
+
assert.equal(byId["dynamic-jobs"].interval, 60);
|
|
105
|
+
assert.ok(byId["dynamic-jobs"].prompt, "guarded dynamic-jobs carries an escalate prompt");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("economics/scheduling cadences resolve into every agent's cadence set", async () => {
|
|
109
|
+
const ids = (await resolveCadences({ function: "operations-leader", altitude: "vp" })).map((c) => c.id);
|
|
110
|
+
for (const id of ["nightly-cost-reconcile", "fleet-cost-digest", "org-cost-sync", "dynamic-jobs"]) {
|
|
111
|
+
assert.ok(ids.includes(id), `${id} resolves into the standard cadence set`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("every STANDARD_CADENCES entry that declares a prompt has the file on disk", async () => {
|
|
116
|
+
// A guarded/escalate cadence whose prompt file is missing would DLQ at escalate
|
|
117
|
+
// time (regression guard for the dynamic-jobs.md gap).
|
|
118
|
+
const { existsSync } = await import("node:fs");
|
|
119
|
+
const { resolve, join } = await import("node:path");
|
|
120
|
+
const { fileURLToPath } = await import("node:url");
|
|
121
|
+
const root = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
|
|
122
|
+
for (const c of STANDARD_CADENCES.filter((x) => x.prompt)) {
|
|
123
|
+
assert.ok(existsSync(join(root, c.prompt)), `cadence ${c.id} prompt missing: ${c.prompt}`);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* capability.mjs — resolve an archetype's CAPABILITY SURFACE.
|
|
3
|
+
*
|
|
4
|
+
* The init wizard generates a deep, ready-to-act agent: not just a charter and a
|
|
5
|
+
* backlog, but the agent's whole capability surface — the sub-agent org, the
|
|
6
|
+
* Claude Code skills, the workflows, the MCP servers/plugins, and the
|
|
7
|
+
* event→capability routing. This module resolves that surface from:
|
|
8
|
+
*
|
|
9
|
+
* STANDARD defaults (every agent gets these generic infrastructure sub-agents)
|
|
10
|
+
* ⊕ the function's capability pack (archetypes/capabilities/<function>.yaml:
|
|
11
|
+
* agentTeams, skills, workflows, mcpServers)
|
|
12
|
+
* ⊕ altitude breadth scaling (profile.delegationBreadth):
|
|
13
|
+
* broad → all teams, all tiers (lead+core+support) — the full 40–60 roster
|
|
14
|
+
* moderate → all teams, drop the support tier
|
|
15
|
+
* narrow → core teams only, drop the support tier
|
|
16
|
+
* none → standard defaults only
|
|
17
|
+
*
|
|
18
|
+
* Generators (scripts/setup/generate-capability.mjs) render concrete agent.md /
|
|
19
|
+
* skills / workflows / config/event-routing.yaml from this surface; the wizard
|
|
20
|
+
* LLM-tailors each to the company context.
|
|
21
|
+
*
|
|
22
|
+
* Pure-ish (reads the capability YAML + resolves the profile for breadth). ESM.
|
|
23
|
+
*
|
|
24
|
+
* @module capability
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
"use strict";
|
|
28
|
+
|
|
29
|
+
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { ARCHETYPES_DIR, resolveArchetype } from "./archetype.mjs";
|
|
32
|
+
|
|
33
|
+
/** Directory of per-function capability packs. */
|
|
34
|
+
export const CAPABILITIES_DIR = path.join(ARCHETYPES_DIR, "capabilities");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The generic infrastructure sub-agents EVERY maestro agent gets, regardless of
|
|
38
|
+
* archetype. (Curated from agents/; these are role-agnostic plumbing.)
|
|
39
|
+
* @type {Array<{ id: string, role: string, purpose: string }>}
|
|
40
|
+
*/
|
|
41
|
+
export const STANDARD_DEFAULT_AGENTS = [
|
|
42
|
+
{ id: "inbound-dispatcher", role: "Inbound Dispatcher", purpose: "Classify and route every inbound event to the right handler." },
|
|
43
|
+
{ id: "inbox-processor", role: "Inbox Processor", purpose: "Triage Slack/email/calendar/SMS inbox items into actions and queues." },
|
|
44
|
+
{ id: "session-spawner", role: "Session Spawner", purpose: "Spawn and supervise managed sub-sessions for delegated work." },
|
|
45
|
+
{ id: "workflow-automation", role: "Workflow Automation", purpose: "Run scheduled and event-driven workflows end-to-end." },
|
|
46
|
+
{ id: "communications", role: "Communications", purpose: "Draft and send messages in the agent's voice across channels." },
|
|
47
|
+
{ id: "calendar-ops", role: "Calendar Ops", purpose: "Manage scheduling, meeting prep, and calendar hygiene." },
|
|
48
|
+
{ id: "decision-log", role: "Decision Log", purpose: "Capture decisions with context, options, and rationale." },
|
|
49
|
+
{ id: "pmo-execution", role: "PMO / Execution", purpose: "Drive the backlog: select, dispatch, and close work items." },
|
|
50
|
+
{ id: "slack-operator", role: "Slack Operator", purpose: "Read/send Slack via the agent's own identity." },
|
|
51
|
+
{ id: "gmail-operator", role: "Gmail Operator", purpose: "Read/send email via IMAP/SMTP under the agent's identity." },
|
|
52
|
+
{ id: "whatsapp-operator", role: "WhatsApp Operator", purpose: "Read/send WhatsApp messages." },
|
|
53
|
+
{ id: "browser-operator", role: "Browser Operator", purpose: "Drive web UIs that lack an API, via the browser." },
|
|
54
|
+
{ id: "desktop-operator", role: "Desktop Operator", purpose: "Drive native macOS apps via accessibility/automation." },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/** Valid breadth values (from altitude profile.delegationBreadth). */
|
|
58
|
+
export const BREADTHS = ["broad", "moderate", "narrow", "none"];
|
|
59
|
+
|
|
60
|
+
let _yaml = null;
|
|
61
|
+
async function getYaml() {
|
|
62
|
+
if (_yaml) return _yaml;
|
|
63
|
+
const mod = await import("js-yaml");
|
|
64
|
+
_yaml = mod && mod.default ? mod.default : mod;
|
|
65
|
+
return _yaml;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Functions that have a capability pack on disk. @returns {string[]} */
|
|
69
|
+
export function listCapabilityFunctions() {
|
|
70
|
+
if (!existsSync(CAPABILITIES_DIR)) return [];
|
|
71
|
+
return readdirSync(CAPABILITIES_DIR).filter((f) => f.endsWith(".yaml")).map((f) => f.slice(0, -5)).sort();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Load a function's capability pack. @param {string} fn @returns {Promise<object>} */
|
|
75
|
+
export async function loadCapabilityPack(fn) {
|
|
76
|
+
const file = path.join(CAPABILITIES_DIR, `${fn}.yaml`);
|
|
77
|
+
if (!existsSync(file)) throw new Error(`capability pack not found for function "${fn}" (${file})`);
|
|
78
|
+
const yaml = await getYaml();
|
|
79
|
+
const pack = yaml.load(readFileSync(file, "utf8")) || {};
|
|
80
|
+
return {
|
|
81
|
+
mcpServers: pack.mcpServers || [],
|
|
82
|
+
skills: pack.skills || [],
|
|
83
|
+
workflows: pack.workflows || [],
|
|
84
|
+
agentTeams: pack.agentTeams || [],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Filter the team/agent catalogue by altitude breadth. Pure.
|
|
90
|
+
* @param {object[]} teams @param {string} breadth @returns {object[]}
|
|
91
|
+
*/
|
|
92
|
+
export function filterTeamsByBreadth(teams, breadth) {
|
|
93
|
+
if (breadth === "none") return [];
|
|
94
|
+
const coreOnly = breadth === "narrow";
|
|
95
|
+
const dropSupport = breadth === "narrow" || breadth === "moderate";
|
|
96
|
+
return (teams || [])
|
|
97
|
+
.filter((t) => (coreOnly ? t.core === true : true))
|
|
98
|
+
.map((t) => ({
|
|
99
|
+
...t,
|
|
100
|
+
agents: (t.agents || []).filter((a) => (dropSupport ? a.tier !== "support" : true)),
|
|
101
|
+
}))
|
|
102
|
+
.filter((t) => t.agents.length > 0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the full capability surface for a { function, altitude }.
|
|
107
|
+
* @param {{function:string, altitude:string}} sel
|
|
108
|
+
* @returns {Promise<object>} the capability surface
|
|
109
|
+
*/
|
|
110
|
+
export async function resolveCapabilitySurface(sel = {}) {
|
|
111
|
+
const profile = await resolveArchetype(sel); // validates + gives delegationBreadth
|
|
112
|
+
const breadth = BREADTHS.includes(profile.delegationBreadth) ? profile.delegationBreadth : "moderate";
|
|
113
|
+
const pack = await loadCapabilityPack(sel.function);
|
|
114
|
+
const teams = filterTeamsByBreadth(pack.agentTeams, breadth);
|
|
115
|
+
const roleAgents = teams.flatMap((t) => (t.agents || []).map((a) => ({ ...a, team: t.id })));
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
function: sel.function,
|
|
119
|
+
altitude: sel.altitude,
|
|
120
|
+
breadth,
|
|
121
|
+
standardAgents: STANDARD_DEFAULT_AGENTS,
|
|
122
|
+
teams,
|
|
123
|
+
roleAgents,
|
|
124
|
+
skills: pack.skills,
|
|
125
|
+
workflows: pack.workflows,
|
|
126
|
+
mcpServers: pack.mcpServers,
|
|
127
|
+
counts: {
|
|
128
|
+
standard: STANDARD_DEFAULT_AGENTS.length,
|
|
129
|
+
role: roleAgents.length,
|
|
130
|
+
total: STANDARD_DEFAULT_AGENTS.length + roleAgents.length,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Build a starter event→capability routing table from a resolved surface.
|
|
137
|
+
* The wizard enriches it; this gives sensible defaults so the daemon can route.
|
|
138
|
+
* @param {object} surface @returns {{ routes: Array<{event:string, handler:string, via:string}> }}
|
|
139
|
+
*/
|
|
140
|
+
export function buildEventRouting(surface) {
|
|
141
|
+
const routes = [
|
|
142
|
+
{ event: "inbound.message", handler: "inbound-dispatcher", via: "standard-agent" },
|
|
143
|
+
{ event: "inbound.email", handler: "inbox-processor", via: "standard-agent" },
|
|
144
|
+
{ event: "decision.made", handler: "decision-log", via: "standard-agent" },
|
|
145
|
+
{ event: "backlog.tick", handler: "pmo-execution", via: "standard-agent" },
|
|
146
|
+
];
|
|
147
|
+
for (const w of surface.workflows || []) {
|
|
148
|
+
routes.push({ event: w.cadence === "event-driven" ? `event.${w.id}` : `cadence.${w.cadence}.${w.id}`, handler: w.id, via: "workflow" });
|
|
149
|
+
}
|
|
150
|
+
for (const s of surface.skills || []) {
|
|
151
|
+
routes.push({ event: `request.${s.id}`, handler: s.id, via: "skill" });
|
|
152
|
+
}
|
|
153
|
+
return { routes };
|
|
154
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* capability.test.mjs — tests for the capability-surface resolver.
|
|
3
|
+
* Run: `node --test lib/capability.test.mjs`
|
|
4
|
+
* @module capability.test
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
import { test } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import {
|
|
12
|
+
resolveCapabilitySurface,
|
|
13
|
+
loadCapabilityPack,
|
|
14
|
+
filterTeamsByBreadth,
|
|
15
|
+
buildEventRouting,
|
|
16
|
+
listCapabilityFunctions,
|
|
17
|
+
STANDARD_DEFAULT_AGENTS,
|
|
18
|
+
} from "./capability.mjs";
|
|
19
|
+
|
|
20
|
+
const TEAMS = [
|
|
21
|
+
{ id: "a", core: true, agents: [{ id: "a1", tier: "lead" }, { id: "a2", tier: "core" }, { id: "a3", tier: "support" }] },
|
|
22
|
+
{ id: "b", core: false, agents: [{ id: "b1", tier: "lead" }, { id: "b2", tier: "support" }] },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
test("filterTeamsByBreadth: breadth scales the roster deterministically", () => {
|
|
26
|
+
const count = (b) => filterTeamsByBreadth(TEAMS, b).flatMap((t) => t.agents).length;
|
|
27
|
+
assert.equal(count("broad"), 5); // both teams, all tiers
|
|
28
|
+
assert.equal(count("moderate"), 3); // both teams, drop support (a: lead+core, b: lead)
|
|
29
|
+
assert.equal(count("narrow"), 2); // core team only (a), drop support
|
|
30
|
+
assert.equal(count("none"), 0);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("technical-leader capability pack loads with mcp/skills/workflows/teams", async () => {
|
|
34
|
+
assert.ok(listCapabilityFunctions().includes("technical-leader"));
|
|
35
|
+
const pack = await loadCapabilityPack("technical-leader");
|
|
36
|
+
assert.ok(pack.mcpServers.length >= 1);
|
|
37
|
+
assert.ok(pack.skills.length >= 1);
|
|
38
|
+
assert.ok(pack.workflows.length >= 1);
|
|
39
|
+
assert.ok(pack.agentTeams.length >= 3);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("resolveCapabilitySurface composes standard defaults + altitude-scaled role agents", async () => {
|
|
43
|
+
const s = await resolveCapabilitySurface({ function: "technical-leader", altitude: "c-suite" });
|
|
44
|
+
assert.equal(s.standardAgents.length, STANDARD_DEFAULT_AGENTS.length);
|
|
45
|
+
assert.ok(s.roleAgents.length > 0);
|
|
46
|
+
assert.equal(s.counts.total, s.counts.standard + s.counts.role);
|
|
47
|
+
assert.ok(s.mcpServers.length >= 1);
|
|
48
|
+
assert.ok(s.roleAgents.every((a) => a.id && a.role && a.team), "role agents carry id/role/team");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("altitude scales breadth: c-suite ≥ vp ≥ senior-manager role-agent count", async () => {
|
|
52
|
+
const c = await resolveCapabilitySurface({ function: "technical-leader", altitude: "c-suite" });
|
|
53
|
+
const v = await resolveCapabilitySurface({ function: "technical-leader", altitude: "vp" });
|
|
54
|
+
const m = await resolveCapabilitySurface({ function: "technical-leader", altitude: "senior-manager" });
|
|
55
|
+
assert.ok(c.counts.role >= v.counts.role, `c-suite(${c.counts.role}) ≥ vp(${v.counts.role})`);
|
|
56
|
+
assert.ok(v.counts.role >= m.counts.role, `vp(${v.counts.role}) ≥ senior-manager(${m.counts.role})`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("buildEventRouting maps standard, workflow, and skill handlers", async () => {
|
|
60
|
+
const s = await resolveCapabilitySurface({ function: "technical-leader", altitude: "vp" });
|
|
61
|
+
const { routes } = buildEventRouting(s);
|
|
62
|
+
assert.ok(routes.some((r) => r.via === "standard-agent"));
|
|
63
|
+
assert.ok(routes.some((r) => r.via === "workflow"));
|
|
64
|
+
assert.ok(routes.some((r) => r.via === "skill"));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("every function pack resolves to a 40–60 role roster at broad altitude, with unique ids + mcp/skills/workflows", async () => {
|
|
68
|
+
const fns = listCapabilityFunctions();
|
|
69
|
+
assert.ok(fns.length >= 6, `expected ≥6 capability packs, got ${fns.length}`);
|
|
70
|
+
for (const fn of fns) {
|
|
71
|
+
const pack = await loadCapabilityPack(fn);
|
|
72
|
+
const ids = pack.agentTeams.flatMap((t) => t.agents.map((a) => a.id));
|
|
73
|
+
assert.equal(ids.length, new Set(ids).size, `${fn}: duplicate agent ids`);
|
|
74
|
+
assert.ok(pack.mcpServers.length >= 1 && pack.skills.length >= 1 && pack.workflows.length >= 1, `${fn}: missing mcp/skills/workflows`);
|
|
75
|
+
const broad = await resolveCapabilitySurface({ function: fn, altitude: "founder" }); // founder ⇒ broad
|
|
76
|
+
assert.ok(broad.counts.role >= 40 && broad.counts.role <= 60, `${fn}: broad role count ${broad.counts.role} not in 40–60`);
|
|
77
|
+
}
|
|
78
|
+
});
|