@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,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for check-docs-accuracy.mjs — docs-accuracy guard (P1-3).
|
|
3
|
+
*
|
|
4
|
+
* Pure-function level: the count-claim extractors, the teams/workflows
|
|
5
|
+
* structural parsers, README link extraction, and the dangling-ref +
|
|
6
|
+
* broken-link finders are exercised against fixtures written to a tmp dir.
|
|
7
|
+
* The fixture-tree tests prove the guard catches a planted bad count, a
|
|
8
|
+
* planted dangling teams ref, and a planted broken README link — and that a
|
|
9
|
+
* clean tree produces zero drift.
|
|
10
|
+
*
|
|
11
|
+
* @module scripts/ci/check-docs-accuracy.test
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, before, after } from "node:test";
|
|
15
|
+
import assert from "node:assert/strict";
|
|
16
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import os from "node:os";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
extractAgentCountClaims,
|
|
22
|
+
extractToolCountClaims,
|
|
23
|
+
parseTeamMembers,
|
|
24
|
+
parseWorkflowAgentRefs,
|
|
25
|
+
extractRelativeLinks,
|
|
26
|
+
countAgentDirs,
|
|
27
|
+
agentIdSet,
|
|
28
|
+
findDanglingAgentRefs,
|
|
29
|
+
findBrokenReadmeLinks,
|
|
30
|
+
analyzeDocsAccuracy,
|
|
31
|
+
run,
|
|
32
|
+
} from "./check-docs-accuracy.mjs";
|
|
33
|
+
|
|
34
|
+
// ── count-claim extraction ──────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
describe("extractAgentCountClaims", () => {
|
|
37
|
+
it("extracts '34 agent definitions'", () => {
|
|
38
|
+
assert.deepEqual(
|
|
39
|
+
extractAgentCountClaims("…and 34 agent definitions with mandates…"),
|
|
40
|
+
[34],
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("extracts the '34 sub-agent definitions' phrasing", () => {
|
|
45
|
+
assert.deepEqual(extractAgentCountClaims("agents/ ← 34 sub-agent definitions"), [34]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("extracts '34 specialist agent definitions' (one adjective)", () => {
|
|
49
|
+
assert.deepEqual(
|
|
50
|
+
extractAgentCountClaims("| 34 specialist agent definitions with mandates |"),
|
|
51
|
+
[34],
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns every claim in order when several appear", () => {
|
|
56
|
+
assert.deepEqual(
|
|
57
|
+
extractAgentCountClaims("13 agent definitions … later 34 agent definitions"),
|
|
58
|
+
[13, 34],
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("does not misread unrelated numbers (40-60 generated range, ports)", () => {
|
|
63
|
+
assert.deepEqual(
|
|
64
|
+
extractAgentCountClaims("generates 40–60 sub-agents on port 8080"),
|
|
65
|
+
[],
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("returns [] for non-string", () => {
|
|
70
|
+
assert.deepEqual(extractAgentCountClaims(null), []);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("extractToolCountClaims", () => {
|
|
75
|
+
it("extracts '30 tools across'", () => {
|
|
76
|
+
assert.deepEqual(extractToolCountClaims("30 tools across 6 categories"), [30]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("ignores per-access-level counts like '29 tools' / '(24 tools)'", () => {
|
|
80
|
+
assert.deepEqual(
|
|
81
|
+
extractToolCountClaims("ceo (29 tools), leadership (24 tools)"),
|
|
82
|
+
[],
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ── teams members parser ────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
describe("parseTeamMembers", () => {
|
|
90
|
+
const yaml = [
|
|
91
|
+
"name: executive-office",
|
|
92
|
+
"lead: chief-of-staff",
|
|
93
|
+
"members:",
|
|
94
|
+
" - chief-of-staff # lead",
|
|
95
|
+
" - ceo-briefing",
|
|
96
|
+
" - communications",
|
|
97
|
+
"responsibilities:",
|
|
98
|
+
" - Morning and evening briefs",
|
|
99
|
+
" - Follow-up management",
|
|
100
|
+
"escalation: principal",
|
|
101
|
+
].join("\n");
|
|
102
|
+
|
|
103
|
+
it("extracts only the members block (not responsibilities)", () => {
|
|
104
|
+
assert.deepEqual(parseTeamMembers(yaml), [
|
|
105
|
+
"chief-of-staff",
|
|
106
|
+
"ceo-briefing",
|
|
107
|
+
"communications",
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("strips trailing comments and whitespace", () => {
|
|
112
|
+
assert.deepEqual(parseTeamMembers("members:\n - alpha # note\n"), ["alpha"]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("ignores prose list items that are not the members block", () => {
|
|
116
|
+
const out = parseTeamMembers(
|
|
117
|
+
"members:\n - alpha\nprinciples:\n - All actions are logged\n",
|
|
118
|
+
);
|
|
119
|
+
assert.deepEqual(out, ["alpha"]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("returns [] when there is no members key", () => {
|
|
123
|
+
assert.deepEqual(parseTeamMembers("name: x\nlead: y\n"), []);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ── workflows agent-ref parser ──────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
describe("parseWorkflowAgentRefs", () => {
|
|
130
|
+
const yaml = [
|
|
131
|
+
"steps:",
|
|
132
|
+
" - id: market-sweep",
|
|
133
|
+
" agent: market-research",
|
|
134
|
+
" action: x",
|
|
135
|
+
" - id: triage",
|
|
136
|
+
" agent: gmail-operator",
|
|
137
|
+
" - id: notify",
|
|
138
|
+
" action: notify",
|
|
139
|
+
"on_failure:",
|
|
140
|
+
" notify: agent-self",
|
|
141
|
+
].join("\n");
|
|
142
|
+
|
|
143
|
+
it("extracts agent: step values", () => {
|
|
144
|
+
assert.deepEqual(parseWorkflowAgentRefs(yaml), [
|
|
145
|
+
"market-research",
|
|
146
|
+
"gmail-operator",
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("excludes the agent-self sentinel", () => {
|
|
151
|
+
assert.deepEqual(parseWorkflowAgentRefs(" - agent: agent-self\n"), []);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("ignores steps with no agent (action-only)", () => {
|
|
155
|
+
assert.deepEqual(parseWorkflowAgentRefs(" - action: notify\n"), []);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ── README link extraction ──────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
describe("extractRelativeLinks", () => {
|
|
162
|
+
it("returns relative links, skipping http/mailto/anchors", () => {
|
|
163
|
+
const md =
|
|
164
|
+
"see [docs](docs/a.md) and [site](https://x.com) and [mail](mailto:a@b.c) and [top](#intro)";
|
|
165
|
+
assert.deepEqual(extractRelativeLinks(md), ["docs/a.md"]);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("strips anchors and query strings from relative links", () => {
|
|
169
|
+
assert.deepEqual(
|
|
170
|
+
extractRelativeLinks("[x](docs/a.md#section) [y](docs/b.md?v=1)"),
|
|
171
|
+
["docs/a.md", "docs/b.md"],
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("drops a markdown link title", () => {
|
|
176
|
+
assert.deepEqual(extractRelativeLinks('[x](docs/a.md "Title")'), ["docs/a.md"]);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("de-dupes repeated links", () => {
|
|
180
|
+
assert.deepEqual(extractRelativeLinks("[a](x.md) [b](x.md)"), ["x.md"]);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ── fixture-tree integration ────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
/** Build a minimal repo fixture under a tmp dir. */
|
|
187
|
+
function makeFixture(opts = {}) {
|
|
188
|
+
const root = mkdtempSync(path.join(os.tmpdir(), "docs-acc-"));
|
|
189
|
+
// agents/ — three agent dirs by default
|
|
190
|
+
for (const a of opts.agents || ["alpha", "beta", "gamma"]) {
|
|
191
|
+
mkdirSync(path.join(root, "agents", a), { recursive: true });
|
|
192
|
+
writeFileSync(path.join(root, "agents", a, "agent.md"), "# agent\n");
|
|
193
|
+
}
|
|
194
|
+
// lib/tool-definitions.js — exports getAllToolsByCategory returning N tools
|
|
195
|
+
mkdirSync(path.join(root, "lib"), { recursive: true });
|
|
196
|
+
const toolCount = opts.tools ?? 2;
|
|
197
|
+
const toolEntries = Array.from({ length: toolCount }, (_, i) => `{name:"t${i}"}`);
|
|
198
|
+
writeFileSync(
|
|
199
|
+
path.join(root, "lib", "tool-definitions.js"),
|
|
200
|
+
`export function getAllToolsByCategory(){return {communication:[${toolEntries.join(",")}]};}\n`,
|
|
201
|
+
);
|
|
202
|
+
// docs
|
|
203
|
+
if (opts.readme != null) writeFileSync(path.join(root, "README.md"), opts.readme);
|
|
204
|
+
if (opts.claude != null) writeFileSync(path.join(root, "CLAUDE.md"), opts.claude);
|
|
205
|
+
// teams + workflows
|
|
206
|
+
for (const [name, body] of Object.entries(opts.teams || {})) {
|
|
207
|
+
mkdirSync(path.join(root, "teams"), { recursive: true });
|
|
208
|
+
writeFileSync(path.join(root, "teams", name), body);
|
|
209
|
+
}
|
|
210
|
+
for (const [rel, body] of Object.entries(opts.workflows || {})) {
|
|
211
|
+
const abs = path.join(root, "workflows", rel);
|
|
212
|
+
mkdirSync(path.dirname(abs), { recursive: true });
|
|
213
|
+
writeFileSync(abs, body);
|
|
214
|
+
}
|
|
215
|
+
// extra real files for link resolution
|
|
216
|
+
for (const [rel, body] of Object.entries(opts.files || {})) {
|
|
217
|
+
const abs = path.join(root, rel);
|
|
218
|
+
mkdirSync(path.dirname(abs), { recursive: true });
|
|
219
|
+
writeFileSync(abs, body);
|
|
220
|
+
}
|
|
221
|
+
return root;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
describe("count helpers on a fixture", () => {
|
|
225
|
+
let root;
|
|
226
|
+
before(() => {
|
|
227
|
+
root = makeFixture({ agents: ["a", "b"], tools: 5 });
|
|
228
|
+
});
|
|
229
|
+
after(() => rmSync(root, { recursive: true, force: true }));
|
|
230
|
+
|
|
231
|
+
it("countAgentDirs counts agent subdirs", () => {
|
|
232
|
+
assert.equal(countAgentDirs(root), 2);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("agentIdSet returns the agent dir names", () => {
|
|
236
|
+
assert.deepEqual([...agentIdSet(root)].sort(), ["a", "b"]);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("analyzeDocsAccuracy reports actual tool count from the module", async () => {
|
|
240
|
+
const r = await analyzeDocsAccuracy({ cwd: root });
|
|
241
|
+
assert.equal(r.counts.toolsActual, 5);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("catches a planted bad count", () => {
|
|
246
|
+
let root;
|
|
247
|
+
before(() => {
|
|
248
|
+
root = makeFixture({
|
|
249
|
+
agents: ["a", "b", "c"], // actual = 3
|
|
250
|
+
tools: 4,
|
|
251
|
+
readme: "Ships with 99 agent definitions and 88 tools across categories.\n",
|
|
252
|
+
claude: "agents/ ← 99 sub-agent definitions\n",
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
after(() => rmSync(root, { recursive: true, force: true }));
|
|
256
|
+
|
|
257
|
+
it("flags the agent-count drift in README and CLAUDE.md", async () => {
|
|
258
|
+
const r = await analyzeDocsAccuracy({ cwd: root });
|
|
259
|
+
assert.equal(r.counts.agentsActual, 3);
|
|
260
|
+
const files = r.counts.agentDrift.map((d) => d.file).sort();
|
|
261
|
+
assert.deepEqual(files, ["CLAUDE.md", "README.md"]);
|
|
262
|
+
for (const d of r.counts.agentDrift) {
|
|
263
|
+
assert.equal(d.claimed, 99);
|
|
264
|
+
assert.equal(d.actual, 3);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("flags the tool-count drift", async () => {
|
|
269
|
+
const r = await analyzeDocsAccuracy({ cwd: root });
|
|
270
|
+
assert.equal(r.counts.toolsActual, 4);
|
|
271
|
+
assert.equal(r.counts.toolDrift.length, 1);
|
|
272
|
+
assert.equal(r.counts.toolDrift[0].claimed, 88);
|
|
273
|
+
assert.equal(r.counts.toolDrift[0].actual, 4);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("reports zero count-drift when claims match reality", async () => {
|
|
277
|
+
const clean = makeFixture({
|
|
278
|
+
agents: ["a", "b", "c"],
|
|
279
|
+
tools: 4,
|
|
280
|
+
readme: "Ships with 3 agent definitions and 4 tools across categories.\n",
|
|
281
|
+
});
|
|
282
|
+
try {
|
|
283
|
+
const r = await analyzeDocsAccuracy({ cwd: clean });
|
|
284
|
+
assert.equal(r.counts.agentDrift.length, 0);
|
|
285
|
+
assert.equal(r.counts.toolDrift.length, 0);
|
|
286
|
+
} finally {
|
|
287
|
+
rmSync(clean, { recursive: true, force: true });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe("catches a dangling teams ref", () => {
|
|
293
|
+
let root;
|
|
294
|
+
before(() => {
|
|
295
|
+
root = makeFixture({
|
|
296
|
+
agents: ["alpha", "beta"], // ghost is missing
|
|
297
|
+
teams: {
|
|
298
|
+
"core.yaml": [
|
|
299
|
+
"name: core",
|
|
300
|
+
"members:",
|
|
301
|
+
" - alpha",
|
|
302
|
+
" - ghost", // dangling
|
|
303
|
+
"responsibilities:",
|
|
304
|
+
" - do things",
|
|
305
|
+
].join("\n"),
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
after(() => rmSync(root, { recursive: true, force: true }));
|
|
310
|
+
|
|
311
|
+
it("flags the missing member but not the resolving one", () => {
|
|
312
|
+
const { teamRefs } = findDanglingAgentRefs({ cwd: root });
|
|
313
|
+
assert.equal(teamRefs.length, 1);
|
|
314
|
+
assert.equal(teamRefs[0].agent, "ghost");
|
|
315
|
+
assert.match(teamRefs[0].file, /core\.yaml$/);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("does not treat responsibilities prose as agent refs", () => {
|
|
319
|
+
const { teamRefs } = findDanglingAgentRefs({ cwd: root });
|
|
320
|
+
assert.ok(!teamRefs.some((t) => t.agent === "do"));
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
describe("workflow refs are de-duped and WARN-classed", () => {
|
|
325
|
+
let root;
|
|
326
|
+
before(() => {
|
|
327
|
+
root = makeFixture({
|
|
328
|
+
agents: ["alpha"],
|
|
329
|
+
workflows: {
|
|
330
|
+
"daily/x.yaml": [
|
|
331
|
+
"steps:",
|
|
332
|
+
" - agent: alpha", // resolves
|
|
333
|
+
" - agent: phantom", // dangling
|
|
334
|
+
" - agent: phantom", // duplicate dangling -> deduped
|
|
335
|
+
].join("\n"),
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
after(() => rmSync(root, { recursive: true, force: true }));
|
|
340
|
+
|
|
341
|
+
it("reports each (file, agent) dangling pair exactly once", () => {
|
|
342
|
+
const { workflowRefs } = findDanglingAgentRefs({ cwd: root });
|
|
343
|
+
assert.equal(workflowRefs.length, 1);
|
|
344
|
+
assert.equal(workflowRefs[0].agent, "phantom");
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
describe("catches a broken README link and ratchets it as FAIL", () => {
|
|
349
|
+
it("findBrokenReadmeLinks flags only the missing target", () => {
|
|
350
|
+
const root = makeFixture({
|
|
351
|
+
readme: "see [real](docs/real.md) and [dead](docs/missing.md)\n",
|
|
352
|
+
files: { "docs/real.md": "# real\n" },
|
|
353
|
+
});
|
|
354
|
+
try {
|
|
355
|
+
const { checked, broken } = findBrokenReadmeLinks({ cwd: root });
|
|
356
|
+
assert.equal(checked, 2);
|
|
357
|
+
assert.deepEqual(broken, ["docs/missing.md"]);
|
|
358
|
+
} finally {
|
|
359
|
+
rmSync(root, { recursive: true, force: true });
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("run() exits 1 when a README link is broken", async () => {
|
|
364
|
+
const root = makeFixture({
|
|
365
|
+
agents: ["a"],
|
|
366
|
+
readme: "[dead](docs/missing.md)\n",
|
|
367
|
+
});
|
|
368
|
+
try {
|
|
369
|
+
const code = await run(root);
|
|
370
|
+
assert.equal(code, 1);
|
|
371
|
+
} finally {
|
|
372
|
+
rmSync(root, { recursive: true, force: true });
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("run() exits 0 when links resolve, even with count/ref WARN drift", async () => {
|
|
377
|
+
const root = makeFixture({
|
|
378
|
+
agents: ["a", "b"],
|
|
379
|
+
readme: "Ships 99 agent definitions. See [ok](docs/ok.md).\n",
|
|
380
|
+
files: { "docs/ok.md": "# ok\n" },
|
|
381
|
+
teams: { "t.yaml": "name: t\nmembers:\n - ghost\n" },
|
|
382
|
+
});
|
|
383
|
+
try {
|
|
384
|
+
const code = await run(root);
|
|
385
|
+
assert.equal(code, 0); // drift is WARN, not FAIL
|
|
386
|
+
} finally {
|
|
387
|
+
rmSync(root, { recursive: true, force: true });
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ── the live repo: link invariant must hold ─────────────────────────────────
|
|
393
|
+
|
|
394
|
+
describe("live repo", () => {
|
|
395
|
+
it("README relative links all resolve (the ratcheted invariant)", async () => {
|
|
396
|
+
const r = await analyzeDocsAccuracy();
|
|
397
|
+
assert.deepEqual(
|
|
398
|
+
r.links.broken,
|
|
399
|
+
[],
|
|
400
|
+
`broken README links: ${r.links.broken.join(", ")}`,
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it("counts the real agent dirs and tools", async () => {
|
|
405
|
+
const r = await analyzeDocsAccuracy();
|
|
406
|
+
assert.ok(r.counts.agentsActual >= 1);
|
|
407
|
+
assert.ok(r.counts.toolsActual >= 1);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-exports-exist.mjs — CI guard that fails if any package.json "exports"
|
|
3
|
+
* subpath points at a file that does not exist on disk.
|
|
4
|
+
*
|
|
5
|
+
* Adapted from OpenClaw's scripts/check.mjs packaging guards. Pure,
|
|
6
|
+
* dependency-light: Node builtins only. ESM module (maestro is "type":"module").
|
|
7
|
+
*
|
|
8
|
+
* This guards the exact class of bug just fixed in maestro, where the "./tts"
|
|
9
|
+
* export pointed at a missing file. The "exports" map is the package's public
|
|
10
|
+
* API surface; a dangling target means `import "@cohortapp/agent-sdk/<subpath>"`
|
|
11
|
+
* throws ERR_MODULE_NOT_FOUND at the consumer, which npm publish does not catch.
|
|
12
|
+
*
|
|
13
|
+
* Handles both string targets (`"./x": "./lib/x.js"`) and conditional-export
|
|
14
|
+
* objects (`"./x": { "import": "./lib/x.mjs", "require": "./lib/x.cjs" }`),
|
|
15
|
+
* recursing into nested condition maps. Only string leaf values that look like
|
|
16
|
+
* relative file paths (start with ".") are checked; the special `null` "block"
|
|
17
|
+
* target and bare condition keys are ignored.
|
|
18
|
+
*
|
|
19
|
+
* Usage (standalone): `node scripts/ci/check-exports-exist.mjs`
|
|
20
|
+
* exit 0 → all targets exist; exit 1 → one or more missing.
|
|
21
|
+
*
|
|
22
|
+
* @module scripts/ci/check-exports-exist
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
"use strict";
|
|
26
|
+
|
|
27
|
+
import { readFile } from "node:fs/promises";
|
|
28
|
+
import { existsSync, statSync } from "node:fs";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
|
|
32
|
+
/** Repo root: two levels up from scripts/ci/. @type {string} */
|
|
33
|
+
const REPO_ROOT = path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..", "..");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Collect every string leaf from an "exports" value, regardless of whether it
|
|
37
|
+
* is a plain string, an array of fallbacks, or a nested condition object.
|
|
38
|
+
*
|
|
39
|
+
* @param {unknown} value - An exports map value (string | object | array | null).
|
|
40
|
+
* @param {string} subpath - The export key this value belongs to (for reporting).
|
|
41
|
+
* @param {Array<{ subpath: string, target: string }>} [out=[]] - Accumulator.
|
|
42
|
+
* @returns {Array<{ subpath: string, target: string }>}
|
|
43
|
+
*/
|
|
44
|
+
export function collectExportTargets(value, subpath, out = []) {
|
|
45
|
+
if (value == null) return out; // null is a deliberate "block this subpath".
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
out.push({ subpath, target: value });
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
for (const item of value) collectExportTargets(item, subpath, out);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
if (typeof value === "object") {
|
|
55
|
+
for (const v of Object.values(value)) collectExportTargets(v, subpath, out);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Flatten a whole "exports" map into a list of (subpath, target) pairs.
|
|
63
|
+
*
|
|
64
|
+
* @param {Record<string, unknown> | string | undefined} exportsField
|
|
65
|
+
* @returns {Array<{ subpath: string, target: string }>}
|
|
66
|
+
*/
|
|
67
|
+
export function flattenExports(exportsField) {
|
|
68
|
+
if (exportsField == null) return [];
|
|
69
|
+
// Sugar form: "exports": "./index.js"
|
|
70
|
+
if (typeof exportsField === "string") {
|
|
71
|
+
return [{ subpath: ".", target: exportsField }];
|
|
72
|
+
}
|
|
73
|
+
const pairs = [];
|
|
74
|
+
for (const [subpath, value] of Object.entries(exportsField)) {
|
|
75
|
+
// A key that is a condition (e.g. "import") rather than a subpath ("./x" or ".")
|
|
76
|
+
// still resolves to the same kind of leaf values, so treat uniformly.
|
|
77
|
+
collectExportTargets(value, subpath, pairs);
|
|
78
|
+
}
|
|
79
|
+
return pairs;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check that every relative-path export target resolves to an existing file.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} [opts]
|
|
86
|
+
* @param {string} [opts.cwd=REPO_ROOT] - Repo root containing package.json.
|
|
87
|
+
* @param {object} [opts.pkg] - Pre-parsed package.json (skips disk read).
|
|
88
|
+
* @returns {Promise<{ ok: boolean, checked: number, missing: Array<{ subpath: string, target: string, resolved: string }> }>}
|
|
89
|
+
*/
|
|
90
|
+
export async function checkExportsExist(opts = {}) {
|
|
91
|
+
const cwd = opts.cwd || REPO_ROOT;
|
|
92
|
+
let pkg = opts.pkg;
|
|
93
|
+
if (!pkg) {
|
|
94
|
+
const raw = await readFile(path.join(cwd, "package.json"), "utf8");
|
|
95
|
+
pkg = JSON.parse(raw);
|
|
96
|
+
}
|
|
97
|
+
const targets = flattenExports(pkg.exports);
|
|
98
|
+
const missing = [];
|
|
99
|
+
let checked = 0;
|
|
100
|
+
for (const { subpath, target } of targets) {
|
|
101
|
+
// Only verify relative file targets. Bare specifiers (rare in "exports")
|
|
102
|
+
// and non-path strings are out of scope for a filesystem existence check.
|
|
103
|
+
if (typeof target !== "string" || !target.startsWith(".")) continue;
|
|
104
|
+
checked++;
|
|
105
|
+
const resolved = path.resolve(cwd, target);
|
|
106
|
+
const present = existsSync(resolved) && statSync(resolved).isFile();
|
|
107
|
+
if (!present) missing.push({ subpath, target, resolved });
|
|
108
|
+
}
|
|
109
|
+
return { ok: missing.length === 0, checked, missing };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Run the check and print a human report.
|
|
114
|
+
*
|
|
115
|
+
* @param {string} [cwd=REPO_ROOT]
|
|
116
|
+
* @returns {Promise<number>} Process exit code (0 = ok, 1 = missing target).
|
|
117
|
+
*/
|
|
118
|
+
export async function run(cwd = REPO_ROOT) {
|
|
119
|
+
const { ok, checked, missing } = await checkExportsExist({ cwd });
|
|
120
|
+
if (ok) {
|
|
121
|
+
console.log(`check-exports-exist: OK (${checked} export target(s) exist)`);
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
console.error("check-exports-exist: FAIL — exports point at missing files:");
|
|
125
|
+
for (const m of missing) {
|
|
126
|
+
console.error(` "${m.subpath}" -> ${m.target} (not found: ${m.resolved})`);
|
|
127
|
+
}
|
|
128
|
+
console.error(`check-exports-exist: ${missing.length} missing of ${checked} checked`);
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Run when invoked directly (not when imported).
|
|
133
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
134
|
+
run()
|
|
135
|
+
.then((code) => process.exit(code))
|
|
136
|
+
.catch((err) => {
|
|
137
|
+
console.error("check-exports-exist: ERROR", err && err.message ? err.message : err);
|
|
138
|
+
process.exit(2);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-files-exist.mjs — CI guard that fails if any entry in package.json
|
|
3
|
+
* "files" does not exist on disk.
|
|
4
|
+
*
|
|
5
|
+
* Adapted from OpenClaw's scripts/check.mjs packaging guards. Pure,
|
|
6
|
+
* dependency-light: Node builtins only. ESM module (maestro is "type":"module").
|
|
7
|
+
*
|
|
8
|
+
* The "files" array is the allowlist npm uses to decide what ends up in the
|
|
9
|
+
* published tarball. An entry that points at a deleted/renamed directory
|
|
10
|
+
* silently ships nothing for that path — consumers then hit missing modules at
|
|
11
|
+
* runtime. This guard asserts every listed path resolves to an existing file
|
|
12
|
+
* or directory in the working tree.
|
|
13
|
+
*
|
|
14
|
+
* Entries are treated as literal paths (the common maestro case: "lib/",
|
|
15
|
+
* "agents/", "README.md"). npm also allows glob patterns in "files"; a bare
|
|
16
|
+
* glob ("*", "?", "[", "{") is reported as "skipped (glob)" rather than failed,
|
|
17
|
+
* since resolving globs here would add a dependency.
|
|
18
|
+
*
|
|
19
|
+
* Usage (standalone): `node scripts/ci/check-files-exist.mjs`
|
|
20
|
+
* exit 0 → all entries exist (or are skipped globs); exit 1 → one missing.
|
|
21
|
+
*
|
|
22
|
+
* @module scripts/ci/check-files-exist
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
"use strict";
|
|
26
|
+
|
|
27
|
+
import { readFile } from "node:fs/promises";
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
|
|
32
|
+
/** Repo root: two levels up from scripts/ci/. @type {string} */
|
|
33
|
+
const REPO_ROOT = path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..", "..");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* True if a "files" entry contains npm/glob metacharacters and so cannot be
|
|
37
|
+
* checked with a plain existence test.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} entry
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
export function isGlob(entry) {
|
|
43
|
+
return /[*?[\]{}!]/.test(entry);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check that every literal entry in the "files" array exists on disk.
|
|
48
|
+
*
|
|
49
|
+
* @param {object} [opts]
|
|
50
|
+
* @param {string} [opts.cwd=REPO_ROOT] - Repo root containing package.json.
|
|
51
|
+
* @param {object} [opts.pkg] - Pre-parsed package.json (skips disk read).
|
|
52
|
+
* @returns {Promise<{ ok: boolean, checked: number, skipped: string[], missing: Array<{ entry: string, resolved: string }> }>}
|
|
53
|
+
*/
|
|
54
|
+
export async function checkFilesExist(opts = {}) {
|
|
55
|
+
const cwd = opts.cwd || REPO_ROOT;
|
|
56
|
+
let pkg = opts.pkg;
|
|
57
|
+
if (!pkg) {
|
|
58
|
+
const raw = await readFile(path.join(cwd, "package.json"), "utf8");
|
|
59
|
+
pkg = JSON.parse(raw);
|
|
60
|
+
}
|
|
61
|
+
const entries = Array.isArray(pkg.files) ? pkg.files : [];
|
|
62
|
+
const missing = [];
|
|
63
|
+
const skipped = [];
|
|
64
|
+
let checked = 0;
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (typeof entry !== "string" || entry.length === 0) continue;
|
|
67
|
+
if (isGlob(entry)) {
|
|
68
|
+
skipped.push(entry);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
checked++;
|
|
72
|
+
const resolved = path.resolve(cwd, entry);
|
|
73
|
+
if (!existsSync(resolved)) missing.push({ entry, resolved });
|
|
74
|
+
}
|
|
75
|
+
return { ok: missing.length === 0, checked, skipped, missing };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Run the check and print a human report.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} [cwd=REPO_ROOT]
|
|
82
|
+
* @returns {Promise<number>} Process exit code (0 = ok, 1 = missing entry).
|
|
83
|
+
*/
|
|
84
|
+
export async function run(cwd = REPO_ROOT) {
|
|
85
|
+
const { ok, checked, skipped, missing } = await checkFilesExist({ cwd });
|
|
86
|
+
const skipNote = skipped.length ? ` (${skipped.length} glob(s) skipped)` : "";
|
|
87
|
+
if (ok) {
|
|
88
|
+
console.log(`check-files-exist: OK (${checked} files entry/entries exist)${skipNote}`);
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
console.error("check-files-exist: FAIL — files[] entries missing on disk:");
|
|
92
|
+
for (const m of missing) {
|
|
93
|
+
console.error(` "${m.entry}" (not found: ${m.resolved})`);
|
|
94
|
+
}
|
|
95
|
+
console.error(`check-files-exist: ${missing.length} missing of ${checked} checked${skipNote}`);
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Run when invoked directly (not when imported).
|
|
100
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
101
|
+
run()
|
|
102
|
+
.then((code) => process.exit(code))
|
|
103
|
+
.catch((err) => {
|
|
104
|
+
console.error("check-files-exist: ERROR", err && err.message ? err.message : err);
|
|
105
|
+
process.exit(2);
|
|
106
|
+
});
|
|
107
|
+
}
|