@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,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-no-residual-identity.mjs — de-identification ratchet.
|
|
3
|
+
*
|
|
4
|
+
* The framework is white-label: it must carry NO trace of its first instance's
|
|
5
|
+
* real identity (the Sophie / Mehran / Adaptic deployment). Once a path has been
|
|
6
|
+
* de-identified (tokenised with {{agent.*}}/{{company.*}} or rewritten
|
|
7
|
+
* persona-agnostic), it must STAY clean. This guard scans a curated list of
|
|
8
|
+
* already-de-identified paths for the original instance identity and fails on any
|
|
9
|
+
* regression. EXPAND `DE_IDENTIFIED_PATHS` as each increment de-identifies more of
|
|
10
|
+
* the corpus (triggers → agents → lib → templates → docs).
|
|
11
|
+
*
|
|
12
|
+
* These markers are the ORIGINAL client identity (NOT confidential data — that is
|
|
13
|
+
* the job of check-no-confidential.mjs), so they are safe to hardcode here. The
|
|
14
|
+
* generic placeholders the framework now ships (Northwind / Alex / Jordan etc.)
|
|
15
|
+
* are intentional examples and are NOT flagged.
|
|
16
|
+
*
|
|
17
|
+
* Pure, dependency-light: Node builtins only. ESM.
|
|
18
|
+
*
|
|
19
|
+
* Usage: `node scripts/ci/check-no-residual-identity.mjs` (exit 0 ok / 1 found)
|
|
20
|
+
* @module scripts/ci/check-no-residual-identity
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
"use strict";
|
|
24
|
+
|
|
25
|
+
import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
|
+
|
|
29
|
+
const REPO_ROOT = path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..", "..");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Paths confirmed de-identified that must remain free of the original instance
|
|
33
|
+
* identity. Grow this list as increments land. 2.0 grew it with bin/, scripts/,
|
|
34
|
+
* scaffold/, and services/ (the §4.5 rebrand sweep cleaned their offenders).
|
|
35
|
+
* @type {string[]}
|
|
36
|
+
*/
|
|
37
|
+
export const DE_IDENTIFIED_PATHS = [
|
|
38
|
+
"schedules/triggers",
|
|
39
|
+
"agents",
|
|
40
|
+
"lib",
|
|
41
|
+
"teams",
|
|
42
|
+
"bin",
|
|
43
|
+
"scripts",
|
|
44
|
+
"scaffold",
|
|
45
|
+
"services",
|
|
46
|
+
];
|
|
47
|
+
/** @deprecated retained for back-compat with callers/tests referencing the old name. */
|
|
48
|
+
export const DE_SOPHIED_PATHS = DE_IDENTIFIED_PATHS;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* SELF-EXEMPTION (the guard-of-the-guard). These two files carry identity
|
|
52
|
+
* tokens BY DESIGN — this guard's own IDENTITY_PATTERNS literals/labels/header
|
|
53
|
+
* doctrine, and check-no-confidential.mjs's scope-note naming what this guard
|
|
54
|
+
* covers — so scanning them can never come clean. They are skipped by exact
|
|
55
|
+
* repo-relative path. The policy assert below keeps this list from ever
|
|
56
|
+
* growing into a general escape hatch: every entry MUST be a scripts/ci/
|
|
57
|
+
* check-no-* guard, or the module throws at import.
|
|
58
|
+
* @type {string[]}
|
|
59
|
+
*/
|
|
60
|
+
export const EXEMPT_FILES = [
|
|
61
|
+
"scripts/ci/check-no-residual-identity.mjs",
|
|
62
|
+
"scripts/ci/check-no-residual-identity.test.mjs", // seeds/asserts the markers by design
|
|
63
|
+
"scripts/ci/check-no-confidential.mjs",
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Enforce the exemption policy. Exported so the test can drive the throwing
|
|
68
|
+
* branch directly; invoked at module load over the real EXEMPT_FILES.
|
|
69
|
+
* @param {string[]} files
|
|
70
|
+
*/
|
|
71
|
+
export function assertExemptPolicy(files) {
|
|
72
|
+
for (const f of files) {
|
|
73
|
+
if (!String(f).startsWith("scripts/ci/check-no-")) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`check-no-residual-identity: EXEMPT_FILES entry "${f}" is out of policy — ` +
|
|
76
|
+
"only scripts/ci/check-no-* guards may self-exempt (the list is not a general escape hatch)",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
assertExemptPolicy(EXEMPT_FILES);
|
|
82
|
+
|
|
83
|
+
/** Original-instance identity markers the framework must not reintroduce. @type {Array<{label:string, re:RegExp}>} */
|
|
84
|
+
export const IDENTITY_PATTERNS = [
|
|
85
|
+
{ label: "agent name (Sophie)", re: /\bSophie\b/i },
|
|
86
|
+
{ label: "principal name (Mehran)", re: /\bMehran\b/i },
|
|
87
|
+
{ label: "company (Adaptic)", re: /\bAdaptic\b/ },
|
|
88
|
+
{ label: "surname (Granfar)", re: /\bGranfar\b/i },
|
|
89
|
+
{ label: "surname (Nguyen)", re: /\bNguyen\b/i },
|
|
90
|
+
{ label: "principal first name (Hootan)", re: /\bHootan\b/i },
|
|
91
|
+
{ label: "colleague (Nima)", re: /\bNima\b/ },
|
|
92
|
+
{ label: "instance regulator (DFSA)", re: /\bDFSA\b/ },
|
|
93
|
+
{ label: "instance email (@adaptic.ai)", re: /@adaptic\.ai/i },
|
|
94
|
+
{ label: "instance repo slug (sophie-ai)", re: /\bsophie-ai\b/i },
|
|
95
|
+
{ label: "instance home path (/Users/sophie)", re: /\/Users\/sophie/i },
|
|
96
|
+
{ label: "old package scope (@adaptic/)", re: /@adaptic\// },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/** Scan a text blob for identity markers. Pure. @returns {Array<{label:string, match:string}>} */
|
|
100
|
+
export function scanIdentity(text) {
|
|
101
|
+
if (typeof text !== "string" || text.length === 0) return [];
|
|
102
|
+
const hits = [];
|
|
103
|
+
for (const p of IDENTITY_PATTERNS) {
|
|
104
|
+
const m = text.match(p.re);
|
|
105
|
+
if (m) hits.push({ label: p.label, match: m[0] });
|
|
106
|
+
}
|
|
107
|
+
return hits;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function walkFiles(dir) {
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const name of readdirSync(dir)) {
|
|
113
|
+
if (name === "node_modules" || name === ".git") continue;
|
|
114
|
+
const p = path.join(dir, name);
|
|
115
|
+
let st;
|
|
116
|
+
try { st = statSync(p); } catch { continue; }
|
|
117
|
+
if (st.isDirectory()) out.push(...walkFiles(p));
|
|
118
|
+
else out.push(p);
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {object} [opts] @param {string} [opts.cwd=REPO_ROOT] @param {string[]} [opts.dirs=DE_IDENTIFIED_PATHS]
|
|
125
|
+
* @returns {Array<{ file: string, hits: Array<{label:string, match:string}> }>}
|
|
126
|
+
*/
|
|
127
|
+
export function findResidualIdentity(opts = {}) {
|
|
128
|
+
const cwd = opts.cwd || REPO_ROOT;
|
|
129
|
+
const dirs = opts.dirs || DE_IDENTIFIED_PATHS;
|
|
130
|
+
const exempt = new Set(opts.exemptFiles || EXEMPT_FILES);
|
|
131
|
+
const offenders = [];
|
|
132
|
+
for (const d of dirs) {
|
|
133
|
+
const abs = path.join(cwd, d);
|
|
134
|
+
if (!existsSync(abs)) continue;
|
|
135
|
+
for (const file of walkFiles(abs)) {
|
|
136
|
+
const rel = path.relative(cwd, file);
|
|
137
|
+
if (exempt.has(rel)) continue; // self-exemption (policy-asserted above)
|
|
138
|
+
let body;
|
|
139
|
+
try { body = readFileSync(file, "utf8"); } catch { continue; }
|
|
140
|
+
const hits = scanIdentity(body);
|
|
141
|
+
if (hits.length) offenders.push({ file: rel, hits });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return offenders;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @param {string} [cwd=REPO_ROOT] @returns {Promise<number>} */
|
|
148
|
+
export async function run(cwd = REPO_ROOT) {
|
|
149
|
+
const offenders = findResidualIdentity({ cwd });
|
|
150
|
+
if (offenders.length === 0) {
|
|
151
|
+
console.log(`check-no-residual-identity: OK (${DE_IDENTIFIED_PATHS.length} de-identified path(s) clean)`);
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
console.error("check-no-residual-identity: FAIL — original instance identity reintroduced into de-identified paths:");
|
|
155
|
+
for (const o of offenders) {
|
|
156
|
+
for (const h of o.hits) console.error(` ${o.file} :: ${h.label} ("${h.match}")`);
|
|
157
|
+
}
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
162
|
+
run().then((c) => process.exit(c)).catch((e) => { console.error("check-no-residual-identity: ERROR", e && e.message ? e.message : e); process.exit(2); });
|
|
163
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-no-residual-identity.test.mjs — the de-identification ratchet's own
|
|
3
|
+
* guard-of-the-guard (2.0 §4.5(8)):
|
|
4
|
+
* (i) exempt files are skipped by the scan,
|
|
5
|
+
* (ii) an out-of-policy exemption entry throws (the list can never grow
|
|
6
|
+
* into a general escape hatch),
|
|
7
|
+
* (iii) a seeded marker in a tmp corpus still fails — the exemption did not
|
|
8
|
+
* blunt the ratchet.
|
|
9
|
+
* Run: node --test scripts/ci/check-no-residual-identity.test.mjs
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
import { test } from "node:test";
|
|
15
|
+
import assert from "node:assert/strict";
|
|
16
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
DE_IDENTIFIED_PATHS,
|
|
22
|
+
EXEMPT_FILES,
|
|
23
|
+
IDENTITY_PATTERNS,
|
|
24
|
+
assertExemptPolicy,
|
|
25
|
+
findResidualIdentity,
|
|
26
|
+
scanIdentity,
|
|
27
|
+
run,
|
|
28
|
+
} from "./check-no-residual-identity.mjs";
|
|
29
|
+
|
|
30
|
+
test("ratchet coverage: 2.0 grew the de-identified paths with bin/scripts/scaffold/services", () => {
|
|
31
|
+
for (const d of ["bin", "scripts", "scaffold", "services", "lib"]) {
|
|
32
|
+
assert.ok(DE_IDENTIFIED_PATHS.includes(d), `${d} ratcheted`);
|
|
33
|
+
}
|
|
34
|
+
assert.ok(
|
|
35
|
+
IDENTITY_PATTERNS.some((p) => p.label.includes("@adaptic/")),
|
|
36
|
+
"old package scope pattern present",
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("(i) exempt files are skipped: a marker inside an exempt path never offends", () => {
|
|
41
|
+
const cwd = mkdtempSync(join(tmpdir(), "ratchet-"));
|
|
42
|
+
mkdirSync(join(cwd, "scripts", "ci"), { recursive: true });
|
|
43
|
+
// The exempt guard file carries identity tokens BY DESIGN.
|
|
44
|
+
writeFileSync(join(cwd, "scripts", "ci", "check-no-residual-identity.mjs"), "// patterns: Sophie Mehran Adaptic\n");
|
|
45
|
+
writeFileSync(join(cwd, "scripts", "ci", "check-no-confidential.mjs"), "// scope note naming Sophie\n");
|
|
46
|
+
const offenders = findResidualIdentity({ cwd });
|
|
47
|
+
assert.deepEqual(offenders, [], "both exempt files skipped");
|
|
48
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("(ii) an out-of-policy exemption entry throws at policy assert", () => {
|
|
52
|
+
assert.doesNotThrow(() => assertExemptPolicy(EXEMPT_FILES), "the real list is in policy");
|
|
53
|
+
assert.throws(
|
|
54
|
+
() => assertExemptPolicy(["lib/org/client.mjs"]),
|
|
55
|
+
/out of policy/,
|
|
56
|
+
"a non-guard path can never self-exempt",
|
|
57
|
+
);
|
|
58
|
+
assert.throws(() => assertExemptPolicy(["scripts/ci/run-tests.mjs"]), /out of policy/, "even scripts/ci files must be check-no-* guards");
|
|
59
|
+
for (const f of EXEMPT_FILES) {
|
|
60
|
+
assert.match(f, /^scripts\/ci\/check-no-/, `${f} matches the policy prefix`);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("(iii) a seeded marker in a NON-exempt file still fails the ratchet", async () => {
|
|
65
|
+
const cwd = mkdtempSync(join(tmpdir(), "ratchet-"));
|
|
66
|
+
mkdirSync(join(cwd, "scripts", "daemon"), { recursive: true });
|
|
67
|
+
mkdirSync(join(cwd, "services", "x"), { recursive: true });
|
|
68
|
+
writeFileSync(join(cwd, "scripts", "daemon", "sneaky.mjs"), 'const who = "Sophie";\n');
|
|
69
|
+
writeFileSync(join(cwd, "services", "x", "pkg.json"), '{"name": "@adaptic/oops"}\n');
|
|
70
|
+
const offenders = findResidualIdentity({ cwd });
|
|
71
|
+
assert.equal(offenders.length, 2, "both seeded markers caught");
|
|
72
|
+
const labels = offenders.flatMap((o) => o.hits.map((h) => h.label)).join("|");
|
|
73
|
+
assert.match(labels, /Sophie/);
|
|
74
|
+
assert.match(labels, /@adaptic\//);
|
|
75
|
+
const code = await run(cwd);
|
|
76
|
+
assert.equal(code, 1, "run() exits non-zero on offenders");
|
|
77
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("scanIdentity flags every 2.0 pattern incl. the package scope; placeholders stay clean", () => {
|
|
81
|
+
assert.ok(scanIdentity("npm i @adaptic/maestro").some((h) => /@adaptic\//.test(h.match)));
|
|
82
|
+
assert.equal(scanIdentity("Northwind's Alex and Jordan shipped it").length, 0, "generic placeholders are intentional");
|
|
83
|
+
assert.equal(scanIdentity("").length, 0);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("the LIVE repo is clean under the expanded ratchet (the commit that lands it is green)", async () => {
|
|
87
|
+
const code = await run();
|
|
88
|
+
assert.equal(code, 0, "expanded ratchet must be green in-tree");
|
|
89
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* check-tarball-fidelity.mjs — packaging fidelity guard (Phase 0 item 0.13c).
|
|
4
|
+
*
|
|
5
|
+
* `npm publish` ships whatever `npm pack` produces. The cheaper static guard
|
|
6
|
+
* `check-no-build-artifacts.mjs` inspects the git index; this one inspects the
|
|
7
|
+
* *actual tarball* — the bytes that reach the fleet via `npm update`. It runs a
|
|
8
|
+
* real `npm pack` into a tmp dir, extracts it, and asserts:
|
|
9
|
+
*
|
|
10
|
+
* 1. Completeness — every package.json `files[]` entry is represented in the
|
|
11
|
+
* tarball (a missing entry means agents install a broken tree, e.g. the
|
|
12
|
+
* relative `../../lib/...` imports the daemon depends on would 404).
|
|
13
|
+
* 2. Hygiene — the extracted tree contains no `node_modules/`, no Python
|
|
14
|
+
* bytecode (`*.pyc`/`*.pyo`/`__pycache__/`), and no symlinks (a tracked
|
|
15
|
+
* symlink resolves only on the author's machine and cannot survive
|
|
16
|
+
* pack/install; cf. the broken `validate_outbound.py` cross-tenant link).
|
|
17
|
+
* 3. Requireability — the package main (exports["."], default lib/index.js)
|
|
18
|
+
* is present in the extracted tree, so a consumer's `import` resolves.
|
|
19
|
+
*
|
|
20
|
+
* This is a SLOW check (it shells out to `npm pack` and `tar`), so it is wired
|
|
21
|
+
* as its own opt-in npm script (`npm run test:pack`) and is NOT part of the
|
|
22
|
+
* default fast `check`/`test` path. CI runs it best-effort.
|
|
23
|
+
*
|
|
24
|
+
* Node builtins + child_process only (maestro is "type":"module", near-zero-dep).
|
|
25
|
+
*
|
|
26
|
+
* Usage: `node scripts/ci/check-tarball-fidelity.mjs` (exit 0 ok / 1 found / 2 error)
|
|
27
|
+
* @module scripts/ci/check-tarball-fidelity
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
"use strict";
|
|
31
|
+
|
|
32
|
+
import { execFileSync } from "node:child_process";
|
|
33
|
+
import {
|
|
34
|
+
mkdtempSync,
|
|
35
|
+
rmSync,
|
|
36
|
+
readFileSync,
|
|
37
|
+
readdirSync,
|
|
38
|
+
lstatSync,
|
|
39
|
+
existsSync,
|
|
40
|
+
} from "node:fs";
|
|
41
|
+
import { tmpdir } from "node:os";
|
|
42
|
+
import path from "node:path";
|
|
43
|
+
import { fileURLToPath } from "node:url";
|
|
44
|
+
|
|
45
|
+
const REPO_ROOT = path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..", "..");
|
|
46
|
+
|
|
47
|
+
/** Patterns that must never appear in the packaged tree. @type {Array<{label:string, re:RegExp}>} */
|
|
48
|
+
export const FORBIDDEN_PATTERNS = [
|
|
49
|
+
{ label: "bundled node_modules", re: /(^|\/)node_modules(\/|$)/ },
|
|
50
|
+
{ label: "python bytecode (*.pyc)", re: /\.pyc$/ },
|
|
51
|
+
{ label: "python bytecode (*.pyo)", re: /\.pyo$/ },
|
|
52
|
+
{ label: "bytecode cache dir (__pycache__)", re: /(^|\/)__pycache__(\/|$)/ },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The "main" file a consumer's bare `import "@cohortapp/agent-sdk"` resolves to.
|
|
57
|
+
* Falls back to lib/index.js (the documented default) when exports["."] is odd.
|
|
58
|
+
* @param {object} pkg
|
|
59
|
+
* @returns {string|null} repo-relative path or null
|
|
60
|
+
*/
|
|
61
|
+
export function resolveMainEntry(pkg) {
|
|
62
|
+
const dot = pkg && pkg.exports && pkg.exports["."];
|
|
63
|
+
let rel = null;
|
|
64
|
+
if (typeof dot === "string") rel = dot;
|
|
65
|
+
else if (dot && typeof dot === "object") rel = dot.default || dot.import || dot.require || null;
|
|
66
|
+
rel = rel || pkg.main || "lib/index.js";
|
|
67
|
+
return rel.replace(/^\.\//, "");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Recursively walk `dir`, returning every entry as
|
|
72
|
+
* { rel, isSymlink, isDir } with rel relative to `dir` (posix-style).
|
|
73
|
+
* Symlinks are reported but NOT followed.
|
|
74
|
+
* @param {string} dir
|
|
75
|
+
* @returns {Array<{ rel: string, isSymlink: boolean, isDir: boolean }>}
|
|
76
|
+
*/
|
|
77
|
+
export function walkTree(dir) {
|
|
78
|
+
const out = [];
|
|
79
|
+
const stack = [dir];
|
|
80
|
+
while (stack.length) {
|
|
81
|
+
const cur = stack.pop();
|
|
82
|
+
let entries;
|
|
83
|
+
try { entries = readdirSync(cur, { withFileTypes: true }); } catch { continue; }
|
|
84
|
+
for (const e of entries) {
|
|
85
|
+
const full = path.join(cur, e.name);
|
|
86
|
+
const rel = path.relative(dir, full).split(path.sep).join("/");
|
|
87
|
+
// Use lstat so we classify the link itself, never its target.
|
|
88
|
+
let st;
|
|
89
|
+
try { st = lstatSync(full); } catch { continue; }
|
|
90
|
+
const isSymlink = st.isSymbolicLink();
|
|
91
|
+
const isDir = !isSymlink && st.isDirectory();
|
|
92
|
+
out.push({ rel, isSymlink, isDir });
|
|
93
|
+
if (isDir) stack.push(full);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Run npm pack + extraction and assess the tarball. Pure-ish: takes no globals
|
|
101
|
+
* beyond REPO_ROOT and the filesystem, cleans up its own tmp dir.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} [opts] @param {string} [opts.cwd=REPO_ROOT]
|
|
104
|
+
* @returns {{ ok: boolean, offenders: Array<{file:string,reason:string}>, missing: string[], tarballFiles: number, mainEntry: string }}
|
|
105
|
+
*/
|
|
106
|
+
export function checkTarball(opts = {}) {
|
|
107
|
+
const cwd = opts.cwd || REPO_ROOT;
|
|
108
|
+
const pkg = JSON.parse(readFileSync(path.join(cwd, "package.json"), "utf8"));
|
|
109
|
+
const filesAllowlist = Array.isArray(pkg.files) ? pkg.files : [];
|
|
110
|
+
const mainEntry = resolveMainEntry(pkg);
|
|
111
|
+
|
|
112
|
+
const work = mkdtempSync(path.join(tmpdir(), "maestro-pack-"));
|
|
113
|
+
try {
|
|
114
|
+
// 1) Real pack into the tmp dir. --json gives the manifest; the .tgz lands
|
|
115
|
+
// in --pack-destination. Suppress npm's own stdout noise via --silent.
|
|
116
|
+
const raw = execFileSync(
|
|
117
|
+
"npm",
|
|
118
|
+
["pack", "--json", "--silent", "--pack-destination", work],
|
|
119
|
+
{ cwd, encoding: "utf8", maxBuffer: 64 * 1024 * 1024 },
|
|
120
|
+
);
|
|
121
|
+
const manifest = JSON.parse(raw);
|
|
122
|
+
const entry = Array.isArray(manifest) ? manifest[0] : manifest;
|
|
123
|
+
const tarballPath = path.join(work, entry.filename);
|
|
124
|
+
|
|
125
|
+
// 2) Extract the tarball (npm tarballs root everything under "package/").
|
|
126
|
+
execFileSync("tar", ["-xzf", tarballPath, "-C", work]);
|
|
127
|
+
const pkgRoot = path.join(work, "package");
|
|
128
|
+
if (!existsSync(pkgRoot)) {
|
|
129
|
+
throw new Error(`extracted tarball has no package/ root (${tarballPath})`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const tree = walkTree(pkgRoot);
|
|
133
|
+
const filePaths = tree.filter((t) => !t.isDir).map((t) => t.rel);
|
|
134
|
+
|
|
135
|
+
// 3) Hygiene — forbidden artifacts + symlinks in the EXTRACTED tree.
|
|
136
|
+
const offenders = [];
|
|
137
|
+
for (const t of tree) {
|
|
138
|
+
if (t.isSymlink) {
|
|
139
|
+
offenders.push({ file: t.rel, reason: "symlink in tarball (does not survive install; may point cross-tenant)" });
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
for (const p of FORBIDDEN_PATTERNS) {
|
|
143
|
+
if (p.re.test(t.rel)) { offenders.push({ file: t.rel, reason: p.label }); break; }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 4) Completeness — every files[] entry must be represented. A directory
|
|
148
|
+
// entry (e.g. "lib/") is satisfied by any packaged path beneath it; a
|
|
149
|
+
// file entry must appear verbatim.
|
|
150
|
+
const missing = [];
|
|
151
|
+
for (const decl of filesAllowlist) {
|
|
152
|
+
const norm = decl.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
153
|
+
const asDirPrefix = norm + "/";
|
|
154
|
+
const present = filePaths.some(
|
|
155
|
+
(f) => f === norm || f.startsWith(asDirPrefix),
|
|
156
|
+
);
|
|
157
|
+
if (!present) missing.push(decl);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 5) Requireability — the package main must be in the tree.
|
|
161
|
+
if (!filePaths.includes(mainEntry)) {
|
|
162
|
+
missing.push(`${mainEntry} (package main / exports["."])`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
ok: offenders.length === 0 && missing.length === 0,
|
|
167
|
+
offenders,
|
|
168
|
+
missing,
|
|
169
|
+
tarballFiles: filePaths.length,
|
|
170
|
+
mainEntry,
|
|
171
|
+
};
|
|
172
|
+
} finally {
|
|
173
|
+
try { rmSync(work, { recursive: true, force: true }); } catch { /* */ }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** @param {string} [cwd=REPO_ROOT] @returns {Promise<number>} */
|
|
178
|
+
export async function run(cwd = REPO_ROOT) {
|
|
179
|
+
let res;
|
|
180
|
+
try {
|
|
181
|
+
res = checkTarball({ cwd });
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.error(`check-tarball-fidelity: ERROR — ${err && err.message ? err.message : err}`);
|
|
184
|
+
return 2;
|
|
185
|
+
}
|
|
186
|
+
if (res.ok) {
|
|
187
|
+
console.log(`check-tarball-fidelity: OK (${res.tarballFiles} files; main "${res.mainEntry}" present; no node_modules/.pyc/symlinks)`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
if (res.missing.length) {
|
|
191
|
+
console.error("check-tarball-fidelity: FAIL — declared files[] / main missing from the tarball:");
|
|
192
|
+
for (const m of res.missing) console.error(` ${m}`);
|
|
193
|
+
}
|
|
194
|
+
if (res.offenders.length) {
|
|
195
|
+
console.error("check-tarball-fidelity: FAIL — forbidden artifacts in the tarball:");
|
|
196
|
+
for (const o of res.offenders) console.error(` ${o.file} :: ${o.reason}`);
|
|
197
|
+
}
|
|
198
|
+
return 1;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
202
|
+
run()
|
|
203
|
+
.then((c) => process.exit(c))
|
|
204
|
+
.catch((e) => { console.error("check-tarball-fidelity: ERROR", e && e.message ? e.message : e); process.exit(2); });
|
|
205
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-unresolved-tokens.mjs — CI guard that fails if a framework prompt file
|
|
3
|
+
* contains a `{{token}}` outside the known render vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* Framework operational prompts (triggers, agent definitions, skills, prompt
|
|
6
|
+
* templates) carry {{agent.*}} identity tokens that lib/render.mjs resolves at
|
|
7
|
+
* load time. A typo ({{agent.firstname}}) or stray braces would render to
|
|
8
|
+
* nothing and ship a broken prompt to a model. This guard scans those files and
|
|
9
|
+
* fails on any token not in lib/render.mjs KNOWN_TOKENS.
|
|
10
|
+
*
|
|
11
|
+
* Pure, dependency-light: Node builtins + lib/render.mjs. ESM.
|
|
12
|
+
*
|
|
13
|
+
* Usage: `node scripts/ci/check-unresolved-tokens.mjs` (exit 0 ok / 1 found)
|
|
14
|
+
* @module scripts/ci/check-unresolved-tokens
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
"use strict";
|
|
18
|
+
|
|
19
|
+
import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { unknownTokens } from "../../lib/render.mjs";
|
|
23
|
+
|
|
24
|
+
const REPO_ROOT = path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..", "..");
|
|
25
|
+
|
|
26
|
+
/** Directories whose .md prompt files carry render tokens. @type {string[]} */
|
|
27
|
+
export const SCAN_DIRS = [
|
|
28
|
+
"schedules/triggers",
|
|
29
|
+
"agents",
|
|
30
|
+
"plugins/maestro-skills/skills",
|
|
31
|
+
"docs/prompts",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/** Recursively collect *.md files under a directory. */
|
|
35
|
+
function walkMd(dir) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const name of readdirSync(dir)) {
|
|
38
|
+
const p = path.join(dir, name);
|
|
39
|
+
let st;
|
|
40
|
+
try { st = statSync(p); } catch { continue; }
|
|
41
|
+
if (st.isDirectory()) out.push(...walkMd(p));
|
|
42
|
+
else if (name.endsWith(".md")) out.push(p);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Find prompt files containing unknown tokens.
|
|
49
|
+
* @param {object} [opts] @param {string} [opts.cwd=REPO_ROOT] @param {string[]} [opts.dirs=SCAN_DIRS]
|
|
50
|
+
* @returns {Array<{ file: string, tokens: string[] }>}
|
|
51
|
+
*/
|
|
52
|
+
export function findUnresolvedTokens(opts = {}) {
|
|
53
|
+
const cwd = opts.cwd || REPO_ROOT;
|
|
54
|
+
const dirs = opts.dirs || SCAN_DIRS;
|
|
55
|
+
const offenders = [];
|
|
56
|
+
for (const d of dirs) {
|
|
57
|
+
const abs = path.join(cwd, d);
|
|
58
|
+
if (!existsSync(abs)) continue;
|
|
59
|
+
for (const file of walkMd(abs)) {
|
|
60
|
+
let body;
|
|
61
|
+
try { body = readFileSync(file, "utf8"); } catch { continue; }
|
|
62
|
+
const bad = unknownTokens(body);
|
|
63
|
+
if (bad.length) offenders.push({ file: path.relative(cwd, file), tokens: bad });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return offenders;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @param {string} [cwd=REPO_ROOT] @returns {Promise<number>} */
|
|
70
|
+
export async function run(cwd = REPO_ROOT) {
|
|
71
|
+
const offenders = findUnresolvedTokens({ cwd });
|
|
72
|
+
if (offenders.length === 0) {
|
|
73
|
+
console.log("check-unresolved-tokens: OK (no unknown {{tokens}} in prompt files)");
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
console.error("check-unresolved-tokens: FAIL — unknown/typo tokens that will not render:");
|
|
77
|
+
for (const o of offenders) console.error(` ${o.file}: ${o.tokens.map((t) => `{{${t}}}`).join(", ")}`);
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
82
|
+
run().then((c) => process.exit(c)).catch((e) => { console.error("check-unresolved-tokens: ERROR", e && e.message ? e.message : e); process.exit(2); });
|
|
83
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check.mjs — CI guard aggregator. Runs every individual maestro CI guard and
|
|
3
|
+
* exits non-zero if any of them fail, printing a one-line-per-check summary.
|
|
4
|
+
*
|
|
5
|
+
* Adapted from OpenClaw's scripts/check.mjs runner. Pure, dependency-light:
|
|
6
|
+
* Node builtins only. ESM module (maestro is "type":"module").
|
|
7
|
+
*
|
|
8
|
+
* Each guard is imported as a module and its `run()` is awaited, so a single
|
|
9
|
+
* Node process executes the whole suite (no per-check subprocess spawn). A
|
|
10
|
+
* guard that throws is treated as a failure rather than crashing the suite, so
|
|
11
|
+
* the summary still lists every check's outcome.
|
|
12
|
+
*
|
|
13
|
+
* Currently aggregates:
|
|
14
|
+
* - check-no-conflict-markers : no git conflict markers in tracked files
|
|
15
|
+
* - check-exports-exist : every package.json exports[] target exists
|
|
16
|
+
* - check-files-exist : every package.json files[] entry exists
|
|
17
|
+
* - check-no-confidential : no confidential instance data in the tarball
|
|
18
|
+
* - check-unresolved-tokens : no unknown {{tokens}} in framework prompt files
|
|
19
|
+
* - check-no-residual-identity: de-Robin'd paths stay persona-agnostic
|
|
20
|
+
* - check-no-build-artifacts : no tracked .pyc/symlinks reach the tarball
|
|
21
|
+
* - check-docs-accuracy : README links resolve; counts/agent-refs WARN
|
|
22
|
+
*
|
|
23
|
+
* Usage: `node scripts/ci/check.mjs`
|
|
24
|
+
* exit 0 → all checks passed; exit 1 → one or more failed.
|
|
25
|
+
*
|
|
26
|
+
* @module scripts/ci/check
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
"use strict";
|
|
30
|
+
|
|
31
|
+
import { run as runConflictMarkers } from "./check-no-conflict-markers.mjs";
|
|
32
|
+
import { run as runExportsExist } from "./check-exports-exist.mjs";
|
|
33
|
+
import { run as runFilesExist } from "./check-files-exist.mjs";
|
|
34
|
+
import { run as runNoConfidential } from "./check-no-confidential.mjs";
|
|
35
|
+
import { run as runUnresolvedTokens } from "./check-unresolved-tokens.mjs";
|
|
36
|
+
import { run as runNoResidualIdentity } from "./check-no-residual-identity.mjs";
|
|
37
|
+
import { run as runNoBuildArtifacts } from "./check-no-build-artifacts.mjs";
|
|
38
|
+
import { run as runDocsAccuracy } from "./check-docs-accuracy.mjs";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The ordered list of guards this aggregator runs.
|
|
42
|
+
* Each entry's `run` returns a Promise<number> exit code (0 = pass).
|
|
43
|
+
* @type {Array<{ name: string, run: () => Promise<number> }>}
|
|
44
|
+
*/
|
|
45
|
+
export const CHECKS = [
|
|
46
|
+
{ name: "check-no-conflict-markers", run: runConflictMarkers },
|
|
47
|
+
{ name: "check-exports-exist", run: runExportsExist },
|
|
48
|
+
{ name: "check-files-exist", run: runFilesExist },
|
|
49
|
+
{ name: "check-no-confidential", run: runNoConfidential },
|
|
50
|
+
{ name: "check-unresolved-tokens", run: runUnresolvedTokens },
|
|
51
|
+
{ name: "check-no-residual-identity", run: runNoResidualIdentity },
|
|
52
|
+
{ name: "check-no-build-artifacts", run: runNoBuildArtifacts },
|
|
53
|
+
{ name: "check-docs-accuracy", run: runDocsAccuracy },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Run every guard in {@link CHECKS}, capturing pass/fail without letting one
|
|
58
|
+
* throw abort the rest.
|
|
59
|
+
*
|
|
60
|
+
* @param {Array<{ name: string, run: () => Promise<number> }>} [checks=CHECKS]
|
|
61
|
+
* @returns {Promise<{ ok: boolean, results: Array<{ name: string, passed: boolean, code: number, error?: string }> }>}
|
|
62
|
+
*/
|
|
63
|
+
export async function runAll(checks = CHECKS) {
|
|
64
|
+
const results = [];
|
|
65
|
+
for (const check of checks) {
|
|
66
|
+
try {
|
|
67
|
+
const code = await check.run();
|
|
68
|
+
results.push({ name: check.name, passed: code === 0, code });
|
|
69
|
+
} catch (err) {
|
|
70
|
+
results.push({
|
|
71
|
+
name: check.name,
|
|
72
|
+
passed: false,
|
|
73
|
+
code: 2,
|
|
74
|
+
error: err && err.message ? err.message : String(err),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const ok = results.every((r) => r.passed);
|
|
79
|
+
return { ok, results };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run all checks and print a summary block.
|
|
84
|
+
*
|
|
85
|
+
* @returns {Promise<number>} Process exit code (0 = all passed, 1 = any failed).
|
|
86
|
+
*/
|
|
87
|
+
export async function run() {
|
|
88
|
+
const { ok, results } = await runAll();
|
|
89
|
+
console.log("");
|
|
90
|
+
console.log("=== maestro CI guards summary ===");
|
|
91
|
+
for (const r of results) {
|
|
92
|
+
const mark = r.passed ? "PASS" : "FAIL";
|
|
93
|
+
const extra = r.error ? ` (error: ${r.error})` : "";
|
|
94
|
+
console.log(` [${mark}] ${r.name}${extra}`);
|
|
95
|
+
}
|
|
96
|
+
const passedCount = results.filter((r) => r.passed).length;
|
|
97
|
+
console.log(`=== ${passedCount}/${results.length} checks passed ===`);
|
|
98
|
+
return ok ? 0 : 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Run when invoked directly (not when imported).
|
|
102
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
103
|
+
run()
|
|
104
|
+
.then((code) => process.exit(code))
|
|
105
|
+
.catch((err) => {
|
|
106
|
+
console.error("check (aggregator): ERROR", err && err.message ? err.message : err);
|
|
107
|
+
process.exit(2);
|
|
108
|
+
});
|
|
109
|
+
}
|