@geraldmaron/construct 1.2.2 → 1.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/README.md +7 -10
- package/bin/construct +286 -220
- package/bin/construct-postinstall.mjs +0 -21
- package/commands/work/optimize-prompts.md +1 -1
- package/examples/distribution/sources/adr.md +2 -2
- package/examples/seed-observations/decisions.md +1 -1
- package/lib/artifact-loop-core.mjs +412 -0
- package/lib/artifact-manifest.mjs +6 -0
- package/lib/artifact-release-gate.mjs +115 -49
- package/lib/audit-rules.mjs +2 -4
- package/lib/audit-skills.mjs +32 -20
- package/lib/audit-specialists.mjs +44 -26
- package/lib/auto-docs.mjs +6 -5
- package/lib/brand-prose.mjs +3 -3
- package/lib/brand-tokens.mjs +2 -2
- package/lib/certification/artifact-fixtures.mjs +4 -1
- package/lib/certification/demo-parity.mjs +6 -32
- package/lib/certification/real-llm-scenarios.mjs +58 -13
- package/lib/certification/role-cards.mjs +7 -6
- package/lib/certification/role-overlays.mjs +4 -4
- package/lib/certification/runner.mjs +9 -2
- package/lib/certification/skill-inventory.mjs +34 -22
- package/lib/certification/skill-scenarios.mjs +21 -8
- package/lib/certification/specialist-contracts.mjs +4 -3
- package/lib/certification/specialist-scenarios.mjs +7 -6
- package/lib/certification/status.mjs +5 -4
- package/lib/cli-commands.mjs +56 -57
- package/lib/comment-lint.mjs +1 -5
- package/lib/completions.mjs +20 -2
- package/lib/config/legacy-config-migration.mjs +125 -0
- package/lib/config/schema.mjs +5 -5
- package/lib/config/source-targets.mjs +80 -0
- package/lib/contracts/validate.mjs +119 -51
- package/lib/decisions/golden.mjs +3 -2
- package/lib/decisions/registry.mjs +11 -6
- package/lib/demo-project.mjs +188 -0
- package/lib/demo-recording.mjs +9 -34
- package/lib/demo-script.mjs +2 -2
- package/lib/demo-surface.mjs +13 -131
- package/lib/demo-tour-renderer.mjs +92 -0
- package/lib/demo.mjs +69 -54
- package/lib/diagram-export.mjs +63 -14
- package/lib/doctor/source-checkout.mjs +3 -4
- package/lib/doctor/watchers/consistency.mjs +90 -22
- package/lib/doctor/watchers/credential-parity.mjs +97 -0
- package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
- package/lib/doctor/watchers/service-health.mjs +4 -32
- package/lib/document-export.mjs +73 -9
- package/lib/document-extract.mjs +10 -198
- package/lib/embed/artifact.mjs +2 -3
- package/lib/embed/cli.mjs +1 -1
- package/lib/embed/config.mjs +1 -2
- package/lib/embed/customer-profiles.mjs +1 -1
- package/lib/embed/daemon.mjs +5 -6
- package/lib/embed/demand-fetch.mjs +114 -2
- package/lib/embed/docs-lifecycle.mjs +9 -5
- package/lib/embed/intake-metrics.mjs +2 -2
- package/lib/embed/notifications.mjs +2 -3
- package/lib/embed/recommendation-store.mjs +25 -22
- package/lib/embed/role-framing.mjs +4 -9
- package/lib/embedded-contract/capability.mjs +4 -2
- package/lib/embedded-contract/contract-version.mjs +1 -1
- package/lib/env-config.mjs +2 -2
- package/lib/flavors/loader.mjs +21 -19
- package/lib/graph/build-from-registry.mjs +31 -7
- package/lib/graph/staleness.mjs +1 -1
- package/lib/headhunt.mjs +82 -35
- package/lib/hooks/agent-tracker.mjs +2 -2
- package/lib/hooks/config-protection.mjs +1 -1
- package/lib/hooks/registry-sync.mjs +3 -3
- package/lib/host-capabilities.mjs +5 -5
- package/lib/improvement/controller.mjs +2 -2
- package/lib/init-unified.mjs +19 -21
- package/lib/intake/classify.mjs +26 -0
- package/lib/intake/daemon.mjs +2 -3
- package/lib/intake/prepare.mjs +10 -3
- package/lib/intake/session-prelude.mjs +1 -1
- package/lib/intake/tables/creative.mjs +9 -9
- package/lib/intake/tables/operations.mjs +4 -4
- package/lib/intake/tables/research.mjs +2 -2
- package/lib/integrations/intake-integrations.mjs +9 -10
- package/lib/knowledge/research-store.mjs +2 -2
- package/lib/mcp/server.mjs +104 -61
- package/lib/mcp/tool-budget.mjs +1 -46
- package/lib/mcp/tool-recovery.mjs +44 -0
- package/lib/mcp/tools/artifact-author.mjs +36 -0
- package/lib/mcp/tools/find-tool.mjs +86 -0
- package/lib/mcp/tools/orchestration-run.mjs +107 -69
- package/lib/mcp/tools/project.mjs +4 -3
- package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
- package/lib/mcp/tools/skills.mjs +39 -22
- package/lib/mcp/tools/telemetry.mjs +2 -1
- package/lib/mcp/tools/workflow.mjs +1 -1
- package/lib/mcp-platform-config.mjs +7 -5
- package/lib/migrations/index.mjs +4 -2
- package/lib/migrations/v2-unified-registry.mjs +35 -0
- package/lib/model-router.mjs +203 -36
- package/lib/models/catalog.mjs +25 -9
- package/lib/models/execution-capability-profile.mjs +3 -3
- package/lib/models/execution-policy.mjs +7 -6
- package/lib/models/provider-poll.mjs +18 -4
- package/lib/opencode-config.mjs +56 -1
- package/lib/opencode-runtime-plugin.mjs +13 -10
- package/lib/oracle/artifact-gate.mjs +14 -4
- package/lib/oracle/cli.mjs +2 -0
- package/lib/oracle/dispatch.mjs +18 -1
- package/lib/oracle/execute.mjs +39 -7
- package/lib/oracle/index.mjs +1 -1
- package/lib/oracle/org-graph.mjs +10 -5
- package/lib/oracle/policy.mjs +6 -0
- package/lib/oracle/read-model.mjs +103 -6
- package/lib/oracle/reconcile.mjs +31 -4
- package/lib/oracle/remediation-dispatch.mjs +53 -0
- package/lib/oracle/routing.mjs +5 -0
- package/lib/oracle/synthesize.mjs +80 -3
- package/lib/orchestration/routing-tables.mjs +44 -10
- package/lib/orchestration/runtime.mjs +2 -0
- package/lib/orchestration/worker.mjs +1 -1
- package/lib/orchestration-policy.mjs +351 -62
- package/lib/overrides/resolver.mjs +1 -12
- package/lib/parity.mjs +37 -11
- package/lib/policy/engine.mjs +80 -15
- package/lib/prompt-composer.js +51 -15
- package/lib/prompt-metadata.mjs +3 -2
- package/lib/providers/connection-probe.mjs +58 -0
- package/lib/providers/copilot-auth.mjs +1 -1
- package/lib/providers/credential-bootstrap.mjs +1 -1
- package/lib/providers/op-run.mjs +3 -4
- package/lib/providers/secret-resolver.mjs +31 -0
- package/lib/publish-tooling.mjs +3 -11
- package/lib/publish.mjs +12 -29
- package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
- package/lib/reflect.mjs +2 -2
- package/lib/registry/agent-manifest.mjs +190 -0
- package/lib/registry/assemble.mjs +133 -0
- package/lib/registry/catalog.mjs +171 -0
- package/lib/registry/cli.mjs +590 -6
- package/lib/registry/consolidation.mjs +5 -4
- package/lib/registry/docs-sync.mjs +67 -0
- package/lib/registry/loader.mjs +147 -0
- package/lib/registry/org-io.mjs +76 -0
- package/lib/registry/retired-paths.mjs +71 -0
- package/lib/registry/surface-map.mjs +5 -7
- package/lib/registry/validator.mjs +438 -0
- package/lib/research-execution-policy.mjs +173 -0
- package/lib/roles/catalog.mjs +4 -9
- package/lib/roles/fence.mjs +107 -1
- package/lib/roles/flavor-bindings.mjs +68 -0
- package/lib/roles/gateway.mjs +140 -29
- package/lib/roles/manifest.mjs +22 -13
- package/lib/roles/router.mjs +1 -1
- package/lib/runtime-env.mjs +1 -1
- package/lib/scopes/enrich.mjs +67 -0
- package/lib/scopes/hooks.mjs +12 -0
- package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
- package/lib/scopes/loader.mjs +104 -0
- package/lib/scopes/rebrand.mjs +32 -0
- package/lib/scopes/research-profile.mjs +16 -0
- package/lib/scopes/teams.mjs +98 -0
- package/lib/service-manager.mjs +1 -117
- package/lib/setup-prompts.mjs +1 -1
- package/lib/setup.mjs +17 -28
- package/lib/skills/composition-graph.mjs +98 -0
- package/lib/skills/router.mjs +80 -0
- package/lib/specialist-contracts.mjs +17 -18
- package/lib/specialists/postconditions.mjs +2 -2
- package/lib/specialists/prompt-schema.mjs +6 -5
- package/lib/specialists/roster.mjs +7 -12
- package/lib/specialists/schema.mjs +9 -6
- package/lib/status.mjs +25 -90
- package/lib/storage/file-lock.mjs +6 -3
- package/lib/telemetry/skill-calls.mjs +1 -1
- package/lib/templates/doc-presentation.mjs +63 -0
- package/lib/templates/visual-requirements.mjs +35 -2
- package/lib/term-format.mjs +107 -2
- package/lib/test-env-setup.mjs +21 -0
- package/lib/ui/components.mjs +42 -0
- package/lib/ui/glyphs.mjs +58 -0
- package/lib/ui/links.mjs +115 -0
- package/lib/ui/theme.mjs +108 -0
- package/lib/uninstall/uninstall.mjs +2 -1
- package/lib/validator.mjs +45 -8
- package/lib/validators/skill-effectiveness.mjs +174 -0
- package/lib/validators/skills.mjs +1 -1
- package/package.json +12 -7
- package/personas/construct.md +12 -3
- package/platforms/claude/CLAUDE.md +1 -1
- package/rules/common/beads-hygiene.md +52 -0
- package/rules/common/neurodivergent-output.md +4 -7
- package/rules/common/research.md +2 -0
- package/scripts/sync-specialists.mjs +260 -49
- package/skills/ai/prompt-optimizer.md +3 -3
- package/skills/brand/output-vibe.md +48 -0
- package/skills/docs/adr-workflow.md +3 -0
- package/skills/docs/backlog-proposal-workflow.md +3 -0
- package/skills/docs/codebase-research-workflow.md +5 -2
- package/skills/docs/customer-profile-workflow.md +3 -0
- package/skills/docs/document-ingest-workflow.md +3 -0
- package/skills/docs/evidence-ingest-workflow.md +4 -1
- package/skills/docs/init-project.md +1 -1
- package/skills/docs/prd-workflow.md +1 -1
- package/skills/docs/prfaq-workflow.md +3 -0
- package/skills/docs/product-intelligence-workflow.md +4 -1
- package/skills/docs/product-signal-workflow.md +3 -0
- package/skills/docs/research-workflow.md +13 -6
- package/skills/docs/runbook-workflow.md +3 -0
- package/skills/docs/strategy-workflow.md +3 -0
- package/skills/docs/user-research-workflow.md +6 -3
- package/skills/operating/orchestration-reference.md +1 -1
- package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
- package/skills/roles/architect.ai-systems.md +1 -1
- package/skills/roles/architect.data.md +1 -1
- package/skills/roles/architect.enterprise.md +1 -1
- package/skills/roles/architect.integration.md +1 -1
- package/skills/roles/architect.md +1 -1
- package/skills/roles/architect.platform.md +1 -1
- package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
- package/skills/roles/data-analyst.experiment.md +1 -1
- package/skills/roles/data-analyst.md +1 -1
- package/skills/roles/data-analyst.product-intelligence.md +1 -1
- package/skills/roles/data-analyst.product.md +1 -1
- package/skills/roles/data-analyst.telemetry.md +1 -1
- package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
- package/skills/roles/data-engineer.pipeline.md +2 -2
- package/skills/roles/data-engineer.vector-retrieval.md +2 -2
- package/skills/roles/data-engineer.warehouse.md +2 -2
- package/skills/roles/debugger.md +1 -1
- package/skills/roles/designer.accessibility.md +1 -1
- package/skills/roles/designer.md +1 -1
- package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
- package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
- package/skills/roles/engineer.md +3 -7
- package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
- package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
- package/skills/roles/{operator.md → operations.md} +2 -5
- package/skills/roles/orchestrator.md +1 -1
- package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
- package/skills/roles/product-manager.ai-product.md +1 -1
- package/skills/roles/product-manager.enterprise.md +1 -1
- package/skills/roles/product-manager.growth.md +1 -2
- package/skills/roles/product-manager.md +1 -2
- package/skills/roles/product-manager.platform.md +1 -1
- package/skills/roles/product-manager.product.md +1 -1
- package/skills/roles/qa.ai-eval.md +1 -1
- package/skills/roles/qa.api-contract.md +1 -1
- package/skills/roles/qa.data-pipeline.md +1 -1
- package/skills/roles/qa.md +1 -1
- package/skills/roles/qa.web-ui.md +1 -1
- package/skills/roles/{operator.release.md → release-manager.md} +3 -3
- package/skills/roles/researcher.md +1 -1
- package/skills/roles/reviewer.md +1 -1
- package/skills/roles/security.ai.md +1 -1
- package/skills/roles/security.appsec.md +1 -1
- package/skills/roles/security.cloud.md +1 -1
- package/skills/roles/security.legal-compliance.md +1 -1
- package/skills/roles/security.md +1 -1
- package/skills/roles/security.privacy.md +1 -1
- package/skills/roles/security.supply-chain.md +1 -1
- package/skills/roles/{operator.sre.md → sre.md} +3 -3
- package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
- package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
- package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
- package/skills/routing.json +18 -0
- package/skills/routing.md +1 -1
- package/specialists/artifact-manifest.json +2 -1
- package/specialists/audit-enrichments.json +14 -14
- package/specialists/org/contracts/accessibility-to-qa.json +37 -0
- package/specialists/org/contracts/any-to-business-strategist.json +57 -0
- package/specialists/org/contracts/any-to-debugger.json +38 -0
- package/specialists/org/contracts/any-to-designer.json +33 -0
- package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
- package/specialists/org/contracts/any-to-explorer.json +39 -0
- package/specialists/org/contracts/any-to-sre-incident.json +33 -0
- package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
- package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
- package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
- package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
- package/specialists/org/contracts/architect-to-engineer.json +34 -0
- package/specialists/org/contracts/architect-to-evaluator.json +59 -0
- package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
- package/specialists/org/contracts/architect-to-operations.json +45 -0
- package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
- package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
- package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
- package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
- package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
- package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
- package/specialists/org/contracts/designer-to-accessibility.json +36 -0
- package/specialists/org/contracts/engineer-to-qa.json +34 -0
- package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
- package/specialists/org/contracts/explorer-to-engineer.json +38 -0
- package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
- package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
- package/specialists/org/contracts/product-manager-to-architect.json +71 -0
- package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
- package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
- package/specialists/org/contracts/qa-to-release-manager.json +42 -0
- package/specialists/org/contracts/qa-to-test-automation.json +42 -0
- package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
- package/specialists/org/contracts/researcher-to-architect.json +40 -0
- package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
- package/specialists/org/contracts/reviewer-to-security.json +41 -0
- package/specialists/org/contracts/sre-to-release-manager.json +36 -0
- package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
- package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
- package/specialists/org/contracts/user-to-construct.json +30 -0
- package/specialists/org/groups/engineering-group.json +43 -0
- package/specialists/org/groups/governance-group.json +38 -0
- package/specialists/org/groups/operations-group.json +41 -0
- package/specialists/org/groups/product-group.json +46 -0
- package/specialists/org/groups/quality-group.json +42 -0
- package/specialists/org/groups/strategy-group.json +41 -0
- package/specialists/org/policies/action-approval.json +13 -0
- package/specialists/org/policies/agents-routing.json +13 -0
- package/specialists/org/policies/architecture.json +20 -0
- package/specialists/org/policies/bash-safety.json +13 -0
- package/specialists/org/policies/beads-hygiene.json +13 -0
- package/specialists/org/policies/bootstrap-state.json +13 -0
- package/specialists/org/policies/code-review.json +13 -0
- package/specialists/org/policies/coding-style.json +13 -0
- package/specialists/org/policies/comments.json +13 -0
- package/specialists/org/policies/commit-approval.json +13 -0
- package/specialists/org/policies/contract-preconditions.json +13 -0
- package/specialists/org/policies/deployment.json +20 -0
- package/specialists/org/policies/description.json +14 -0
- package/specialists/org/policies/design-approval.json +19 -0
- package/specialists/org/policies/doc-ownership.json +13 -0
- package/specialists/org/policies/file-path-fence.json +13 -0
- package/specialists/org/policies/framing.json +13 -0
- package/specialists/org/policies/git-workflow.json +13 -0
- package/specialists/org/policies/incident-response.json +15 -0
- package/specialists/org/policies/intake-triage.json +15 -0
- package/specialists/org/policies/neurodivergent-output.json +13 -0
- package/specialists/org/policies/no-fabrication.json +13 -0
- package/specialists/org/policies/patterns.json +13 -0
- package/specialists/org/policies/quality-gate-approval.json +17 -0
- package/specialists/org/policies/release-gates.json +13 -0
- package/specialists/org/policies/research-evidence.json +13 -0
- package/specialists/org/policies/review-before-change.json +13 -0
- package/specialists/org/policies/rollback.json +15 -0
- package/specialists/org/policies/scope-change.json +20 -0
- package/specialists/org/policies/secret-scan.json +13 -0
- package/specialists/org/policies/security-approval.json +17 -0
- package/specialists/org/policies/security.json +13 -0
- package/specialists/org/policies/session-efficiency.json +13 -0
- package/specialists/org/policies/skill-routing.json +13 -0
- package/specialists/org/policies/strategic-prioritization.json +17 -0
- package/specialists/org/policies/testing.json +13 -0
- package/specialists/org/policies/tool-invisibility.json +14 -0
- package/specialists/org/scopes/creative.json +54 -0
- package/specialists/org/scopes/operations.json +51 -0
- package/specialists/org/scopes/research.json +60 -0
- package/specialists/org/scopes/rnd.json +81 -0
- package/specialists/org/specialists/cx-accessibility.json +69 -0
- package/specialists/org/specialists/cx-ai-engineer.json +75 -0
- package/specialists/org/specialists/cx-architect.json +89 -0
- package/specialists/org/specialists/cx-business-strategist.json +72 -0
- package/specialists/org/specialists/cx-data-analyst.json +68 -0
- package/specialists/org/specialists/cx-data-engineer.json +71 -0
- package/specialists/org/specialists/cx-debugger.json +75 -0
- package/specialists/org/specialists/cx-designer.json +85 -0
- package/specialists/org/specialists/cx-devil-advocate.json +71 -0
- package/specialists/org/specialists/cx-docs-keeper.json +82 -0
- package/specialists/org/specialists/cx-engineer.json +106 -0
- package/specialists/org/specialists/cx-evaluator.json +69 -0
- package/specialists/org/specialists/cx-explorer.json +69 -0
- package/specialists/org/specialists/cx-legal-compliance.json +74 -0
- package/specialists/org/specialists/cx-operations.json +72 -0
- package/specialists/org/specialists/cx-oracle.json +46 -0
- package/specialists/org/specialists/cx-orchestrator.json +81 -0
- package/specialists/org/specialists/cx-platform-engineer.json +80 -0
- package/specialists/org/specialists/cx-product-manager.json +102 -0
- package/specialists/org/specialists/cx-qa.json +79 -0
- package/specialists/org/specialists/cx-rd-lead.json +73 -0
- package/specialists/org/specialists/cx-release-manager.json +77 -0
- package/specialists/org/specialists/cx-researcher.json +82 -0
- package/specialists/org/specialists/cx-reviewer.json +71 -0
- package/specialists/org/specialists/cx-security.json +91 -0
- package/specialists/org/specialists/cx-sre.json +94 -0
- package/specialists/org/specialists/cx-test-automation.json +69 -0
- package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
- package/specialists/org/specialists/cx-ux-researcher.json +68 -0
- package/specialists/org/teams/accessibility-team.json +39 -0
- package/specialists/org/teams/design-team.json +40 -0
- package/specialists/org/teams/engineering-team.json +50 -0
- package/specialists/org/teams/governance-team.json +41 -0
- package/specialists/org/teams/operations-team.json +46 -0
- package/specialists/org/teams/product-management-team.json +45 -0
- package/specialists/org/teams/quality-team.json +49 -0
- package/specialists/org/teams/research-team.json +39 -0
- package/specialists/org/teams/strategy-team.json +48 -0
- package/specialists/org/teams/ux-research-team.json +39 -0
- package/specialists/prompts/_shared/validation-contract.md +1 -1
- package/specialists/prompts/_team-template.md +10 -0
- package/specialists/prompts/cx-accessibility.md +1 -0
- package/specialists/prompts/cx-ai-engineer.md +1 -1
- package/specialists/prompts/cx-business-strategist.md +1 -1
- package/specialists/prompts/cx-data-engineer.md +1 -1
- package/specialists/prompts/cx-designer.md +1 -0
- package/specialists/prompts/cx-devil-advocate.md +1 -1
- package/specialists/prompts/cx-docs-keeper.md +1 -1
- package/specialists/prompts/cx-evaluator.md +1 -1
- package/specialists/prompts/cx-explorer.md +1 -1
- package/specialists/prompts/cx-operations.md +1 -1
- package/specialists/prompts/cx-oracle.md +7 -3
- package/specialists/prompts/cx-orchestrator.md +17 -1
- package/specialists/prompts/cx-platform-engineer.md +1 -1
- package/specialists/prompts/cx-product-manager.md +2 -0
- package/specialists/prompts/cx-release-manager.md +1 -1
- package/specialists/prompts/cx-researcher.md +7 -4
- package/specialists/prompts/cx-sre.md +1 -1
- package/specialists/prompts/cx-test-automation.md +2 -2
- package/specialists/prompts/cx-trace-reviewer.md +3 -3
- package/specialists/prompts/cx-ux-researcher.md +2 -1
- package/templates/demos/scripts/architecture-review-adr.json +30 -0
- package/templates/demos/scripts/capability-contract.json +25 -0
- package/templates/demos/scripts/intake-triage.json +25 -0
- package/templates/demos/scripts/profile-doctor-health.json +25 -0
- package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
- package/templates/demos/tapes/architecture-review-adr.tape +44 -0
- package/templates/demos/tapes/capability-contract.tape +39 -0
- package/templates/demos/tapes/intake-triage.tape +39 -0
- package/templates/demos/tapes/profile-doctor-health.tape +39 -0
- package/templates/distribution/construct-brand.typ +23 -18
- package/templates/distribution/construct-decision.typ +1 -1
- package/templates/distribution/construct-pdf.typ +1 -1
- package/templates/distribution/construct-prd.typ +1 -1
- package/templates/distribution/construct-research.typ +1 -1
- package/templates/distribution/mermaid-puppeteer.json +8 -0
- package/templates/docs/persona-artifact.md +1 -1
- package/templates/docs/prd.md +6 -0
- package/lib/boundary.mjs +0 -127
- package/lib/certification/dashboard-api.mjs +0 -71
- package/lib/chat/cli.mjs +0 -333
- package/lib/chat/command-suggest.mjs +0 -161
- package/lib/chat/commands.mjs +0 -215
- package/lib/chat/config.mjs +0 -142
- package/lib/chat/context-compactor.mjs +0 -250
- package/lib/chat/context-continuation.mjs +0 -253
- package/lib/chat/continuation-source.mjs +0 -58
- package/lib/chat/demo-guide.mjs +0 -61
- package/lib/chat/design-tokens.mjs +0 -91
- package/lib/chat/desktop-binary.mjs +0 -81
- package/lib/chat/desktop-build.mjs +0 -130
- package/lib/chat/desktop-launcher.mjs +0 -133
- package/lib/chat/evidence.mjs +0 -145
- package/lib/chat/export.mjs +0 -74
- package/lib/chat/harness/driver.mjs +0 -91
- package/lib/chat/list-picker.mjs +0 -112
- package/lib/chat/model-picker.mjs +0 -356
- package/lib/chat/openrouter-fallback.mjs +0 -151
- package/lib/chat/permission-prompt.mjs +0 -33
- package/lib/chat/picker-catalog.mjs +0 -45
- package/lib/chat/policy-telemetry.mjs +0 -34
- package/lib/chat/present.mjs +0 -246
- package/lib/chat/session-context.mjs +0 -39
- package/lib/chat/session-persist.mjs +0 -73
- package/lib/chat/session-restore.mjs +0 -71
- package/lib/chat/session-settings.mjs +0 -53
- package/lib/chat/system-prompt.mjs +0 -52
- package/lib/chat/transparency.mjs +0 -93
- package/lib/chat/tui/color-scheme.mjs +0 -42
- package/lib/chat/tui/markdown.mjs +0 -123
- package/lib/chat/tui/presentation.mjs +0 -100
- package/lib/chat/tui/render.mjs +0 -500
- package/lib/chat/tui/turn-block.mjs +0 -284
- package/lib/chat/tui/turn-present.mjs +0 -18
- package/lib/chat/tui/turn-state.mjs +0 -88
- package/lib/chat/tui/usage.mjs +0 -122
- package/lib/chat/web-commands.mjs +0 -146
- package/lib/chat/web-launcher.mjs +0 -63
- package/lib/chat/web-picker-keys.mjs +0 -46
- package/lib/chat/web-session.mjs +0 -159
- package/lib/config/alias.mjs +0 -57
- package/lib/dashboard-demo.mjs +0 -71
- package/lib/dashboard-static.mjs +0 -175
- package/lib/install/desktop-binary-download.mjs +0 -88
- package/lib/profiles/loader.mjs +0 -123
- package/lib/profiles/rebrand.mjs +0 -46
- package/lib/server/auth.mjs +0 -169
- package/lib/server/chat-loop.mjs +0 -622
- package/lib/server/chat.mjs +0 -336
- package/lib/server/cors.mjs +0 -77
- package/lib/server/csrf.mjs +0 -103
- package/lib/server/demo-preview.mjs +0 -63
- package/lib/server/index.mjs +0 -2641
- package/lib/server/insights.mjs +0 -780
- package/lib/server/langfuse-login.mjs +0 -58
- package/lib/server/rate-limit.mjs +0 -93
- package/lib/server/telemetry-login.mjs +0 -100
- package/lib/server/webhook.mjs +0 -512
- package/specialists/contracts.json +0 -1032
- package/specialists/contracts.schema.json +0 -83
- package/specialists/policy-inventory.json +0 -188
- package/specialists/registry.json +0 -1412
- package/specialists/role-manifests.json +0 -217
- package/specialists/teams.json +0 -94
|
@@ -6,19 +6,24 @@
|
|
|
6
6
|
* 2. framing/research/doc-ownership gates (what must be true before work starts)
|
|
7
7
|
* 3. contract chain (resolveContractChain) (what the typed handoffs are)
|
|
8
8
|
*
|
|
9
|
-
* Agent-to-agent contracts are
|
|
10
|
-
* lib/specialist-contracts.mjs.
|
|
11
|
-
* producer→consumer typed handoffs.
|
|
9
|
+
* Agent-to-agent contracts are declared in specialists/org
|
|
10
|
+
* (registry.contracts) and resolved via lib/specialist-contracts.mjs. The
|
|
11
|
+
* unified registry is the source of truth for producer→consumer typed handoffs.
|
|
12
12
|
*
|
|
13
13
|
* Event ownership, doc-artifact ownership, and watch-condition routing live
|
|
14
|
-
* declaratively on specialist entries in specialists/
|
|
14
|
+
* declaratively on specialist entries in specialists/org and are
|
|
15
15
|
* resolved by lib/orchestration/routing-tables.mjs. Hardcoded maps here
|
|
16
16
|
* would create a second source of truth.
|
|
17
17
|
*/
|
|
18
18
|
import { resolveContractChain } from './specialist-contracts.mjs';
|
|
19
19
|
import { verifyRoute } from './intent-classifier.mjs';
|
|
20
20
|
import { ownerForEvent, ownerForDoc, evaluateWatchConditions, knownDocTypes } from './orchestration/routing-tables.mjs';
|
|
21
|
-
import { getArtifactEntry } from './artifact-manifest.mjs';
|
|
21
|
+
import { getArtifactEntry, resolveArtifactWorkflowContract } from './artifact-manifest.mjs';
|
|
22
|
+
import { loadRegistry } from './registry/loader.mjs';
|
|
23
|
+
import { buildResearchExecutionPolicy } from './research-execution-policy.mjs';
|
|
24
|
+
import { resolveActiveScope } from './scopes/loader.mjs';
|
|
25
|
+
import { scopeTeamsById, resolveIntentTeamForScope, resolveScopeTeamMeta } from './scopes/teams.mjs';
|
|
26
|
+
import { formatOverlayLine } from './roles/flavor-bindings.mjs';
|
|
22
27
|
|
|
23
28
|
export const EXECUTION_TRACKS = {
|
|
24
29
|
immediate: 'immediate',
|
|
@@ -34,6 +39,20 @@ export const INTENT_CLASSES = {
|
|
|
34
39
|
fix: 'fix',
|
|
35
40
|
};
|
|
36
41
|
|
|
42
|
+
// RFC-0004 §2: each intent class maps to the team that naturally owns that work.
|
|
43
|
+
// The primary team drives ownership in teamRouting; specialist selection stays
|
|
44
|
+
// flavor-driven. Domain refinements the RFC notes (investigation/fix can fall to
|
|
45
|
+
// operations-group, research to product-group) layer on as the decision matrix
|
|
46
|
+
// grows — the base mapping is deterministic so routing is testable.
|
|
47
|
+
|
|
48
|
+
export const INTENT_TO_TEAM = Object.freeze({
|
|
49
|
+
research: 'strategy-team',
|
|
50
|
+
implementation: 'engineering-team',
|
|
51
|
+
investigation: 'engineering-team',
|
|
52
|
+
evaluation: 'quality-team',
|
|
53
|
+
fix: 'engineering-team',
|
|
54
|
+
});
|
|
55
|
+
|
|
37
56
|
export const WORK_CATEGORIES = {
|
|
38
57
|
visual: 'visual',
|
|
39
58
|
deep: 'deep',
|
|
@@ -44,7 +63,7 @@ export const WORK_CATEGORIES = {
|
|
|
44
63
|
|
|
45
64
|
export const TERMINAL_STATES = ['DONE', 'BLOCKED', 'NEEDS_MAIN_INPUT'];
|
|
46
65
|
|
|
47
|
-
// Event and doc-artifact ownership are resolved from specialists/
|
|
66
|
+
// Event and doc-artifact ownership are resolved from specialists/org
|
|
48
67
|
// via routing-tables.mjs. Re-exported here so callers that historically
|
|
49
68
|
// imported from this module keep working.
|
|
50
69
|
|
|
@@ -77,7 +96,18 @@ const DOC_AUTHORING_PATTERNS = [
|
|
|
77
96
|
{ pattern: /\bchangelog/i, docType: 'changelog' },
|
|
78
97
|
];
|
|
79
98
|
|
|
80
|
-
const AUTHORING_VERBS = /\b(write|writing|draft|drafting|create|creating|author|authoring|produce|producing|compose|composing|prepare|preparing)\b/i;
|
|
99
|
+
const AUTHORING_VERBS = /\b(write|writing|draft|drafting|create|creating|author|authoring|produce|producing|compose|composing|prepare|preparing|generate|generating)\b/i;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Resolves a document type mentioned in text without requiring an authoring verb.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveDocTypeMention(request = '') {
|
|
105
|
+
const text = String(request);
|
|
106
|
+
for (const { pattern, docType } of DOC_AUTHORING_PATTERNS) {
|
|
107
|
+
if (pattern.test(text)) return docType;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
81
111
|
|
|
82
112
|
/**
|
|
83
113
|
* Detects whether the request is asking for authorship of a typed document
|
|
@@ -205,6 +235,13 @@ const SPECIALIST_MAP = {
|
|
|
205
235
|
research: ['cx-researcher'],
|
|
206
236
|
};
|
|
207
237
|
|
|
238
|
+
const WORKFLOW_SKILL_TO_TYPE = {
|
|
239
|
+
'docs/prd-workflow': 'prd-draft',
|
|
240
|
+
'docs/adr-workflow': 'architecture-review',
|
|
241
|
+
'docs/research-workflow': 'research-synthesis',
|
|
242
|
+
'docs/evidence-ingest-workflow': 'evidence-ingest',
|
|
243
|
+
};
|
|
244
|
+
|
|
208
245
|
function includesAny(text, patterns) {
|
|
209
246
|
return patterns.some((pattern) => pattern.test(text));
|
|
210
247
|
}
|
|
@@ -292,7 +329,7 @@ export function classifyEngineerFlavor(request = '') {
|
|
|
292
329
|
const text = String(request).toLowerCase();
|
|
293
330
|
if (containsAny(text, ['llm', 'agent', 'prompt', 'eval', 'hallucination', 'rag', 'model behavior', 'model routing'])) return 'ai';
|
|
294
331
|
if (containsAny(text, ['vector', 'embedding', 'retrieval', 'warehouse', 'etl', 'elt', 'pipeline', 'streaming', 'data contract'])) return 'data';
|
|
295
|
-
if (containsAny(text, ['ci', 'build', 'deploy', 'docker', 'kubernetes', 'terraform', 'helm', 'release pipeline', 'platform tooling', 'developer experience'])) return 'platform';
|
|
332
|
+
if (containsAny(text, ['ci/cd', ' ci ', 'build pipeline', 'build system', 'deploy', 'docker', 'kubernetes', 'terraform', 'helm', 'release pipeline', 'platform tooling', 'developer experience'])) return 'platform';
|
|
296
333
|
return null;
|
|
297
334
|
}
|
|
298
335
|
|
|
@@ -377,28 +414,32 @@ export function isVisualDeliverableRequest(request = '') {
|
|
|
377
414
|
}
|
|
378
415
|
|
|
379
416
|
export function classifyRoleFlavors(request = '') {
|
|
417
|
+
const engineerFlavor = classifyEngineerFlavor(request);
|
|
418
|
+
const dataEngineerFlavor = classifyDataEngineerFlavor(request);
|
|
380
419
|
return {
|
|
381
|
-
engineer:
|
|
420
|
+
engineer: engineerFlavor && !['ai', 'platform', 'data'].includes(engineerFlavor) ? engineerFlavor : null,
|
|
421
|
+
aiEngineer: engineerFlavor === 'ai' ? 'core' : null,
|
|
422
|
+
platformEngineer: engineerFlavor === 'platform' ? 'core' : null,
|
|
382
423
|
architect: classifyArchitectFlavor(request),
|
|
383
424
|
productManager: isProductIntelligenceRequest(request) ? classifyProductManagerFlavor(request) : null,
|
|
384
425
|
qa: classifyQaFlavor(request),
|
|
385
426
|
security: classifySecurityFlavor(request),
|
|
386
427
|
dataAnalyst: classifyDataAnalystFlavor(request),
|
|
387
|
-
dataEngineer:
|
|
428
|
+
dataEngineer: dataEngineerFlavor,
|
|
429
|
+
businessStrategist: isBusinessStrategyRequest(request) ? 'core' : null,
|
|
388
430
|
};
|
|
389
431
|
}
|
|
390
432
|
|
|
391
433
|
// One line per non-null flavor: "cx-<role>: loaded <role>.<flavor>
|
|
392
|
-
// overlay". Verbose
|
|
434
|
+
// overlay". Verbose host surfaces + cx_trace span attribute; lets a
|
|
393
435
|
// post-hoc reviewer see which overlays drove a given dispatch.
|
|
394
436
|
|
|
395
437
|
export function formatOverlaySelection(roleFlavors) {
|
|
396
438
|
if (!roleFlavors || typeof roleFlavors !== 'object') return [];
|
|
397
439
|
const lines = [];
|
|
398
|
-
for (const [
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
lines.push(`${specialist}: loaded ${role}.${flavor} overlay`);
|
|
440
|
+
for (const [classifierKey, flavor] of Object.entries(roleFlavors)) {
|
|
441
|
+
const line = formatOverlayLine(classifierKey, flavor);
|
|
442
|
+
if (line) lines.push(line);
|
|
402
443
|
}
|
|
403
444
|
return lines;
|
|
404
445
|
}
|
|
@@ -444,8 +485,16 @@ export function determineExecutionTrack({
|
|
|
444
485
|
} = {}) {
|
|
445
486
|
const intent = classifyIntent(request);
|
|
446
487
|
const workCategory = classifyWorkCategory(request, riskFlags);
|
|
488
|
+
const text = String(request).toLowerCase();
|
|
489
|
+
const localWalkthrough = isExplorerRequest(request)
|
|
490
|
+
|| /\b(?:explain|understand|what does|what is)\b[\s\S]{0,60}\b(?:how\b|do\b|does\b|works?\b|flow\b|path\b|layer\b|module\b|implementation\b|code\b|function\b)/i.test(text)
|
|
491
|
+
|| /\bhow\b[\s\S]{0,40}\bworks?\b/i.test(text);
|
|
447
492
|
if (explicitDrive) return EXECUTION_TRACKS.orchestrated;
|
|
448
|
-
if (intent === INTENT_CLASSES.research
|
|
493
|
+
if (intent === INTENT_CLASSES.research) {
|
|
494
|
+
if (localWalkthrough && fileCount <= 1 && moduleCount <= 1) return EXECUTION_TRACKS.immediate;
|
|
495
|
+
if (fileCount <= 1 && moduleCount <= 1) return EXECUTION_TRACKS.focused;
|
|
496
|
+
return EXECUTION_TRACKS.orchestrated;
|
|
497
|
+
}
|
|
449
498
|
if (introducesContract || fileCount >= 3 || moduleCount >= 2) return EXECUTION_TRACKS.orchestrated;
|
|
450
499
|
if (riskFlags.architecture || riskFlags.security || riskFlags.dataIntegrity || riskFlags.ai) return EXECUTION_TRACKS.orchestrated;
|
|
451
500
|
if (workCategory === WORK_CATEGORIES.visual) return EXECUTION_TRACKS.focused;
|
|
@@ -465,6 +514,36 @@ export function determineExecutionTrack({
|
|
|
465
514
|
return EXECUTION_TRACKS.focused;
|
|
466
515
|
}
|
|
467
516
|
|
|
517
|
+
function refineEngineeringSpecialists(specialists, request = '') {
|
|
518
|
+
const engineerFlavor = classifyEngineerFlavor(request);
|
|
519
|
+
if (!engineerFlavor || !['ai', 'platform', 'data'].includes(engineerFlavor)) return specialists;
|
|
520
|
+
const replacement = {
|
|
521
|
+
ai: 'cx-ai-engineer',
|
|
522
|
+
platform: 'cx-platform-engineer',
|
|
523
|
+
data: 'cx-data-engineer',
|
|
524
|
+
}[engineerFlavor];
|
|
525
|
+
const set = new Set(specialists);
|
|
526
|
+
set.delete('cx-engineer');
|
|
527
|
+
set.add(replacement);
|
|
528
|
+
return [...set];
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function suggestWorkflowType({ intent, request = '', docAuthoring } = {}) {
|
|
532
|
+
const text = String(request).toLowerCase();
|
|
533
|
+
const localWalkthrough = isExplorerRequest(request)
|
|
534
|
+
|| /\b(?:explain|understand|what does|what is)\b[\s\S]{0,60}\b(?:how\b|do\b|does\b|works?\b|flow\b|path\b|layer\b|module\b|implementation\b|code\b|function\b)/i.test(text)
|
|
535
|
+
|| /\bhow\b[\s\S]{0,40}\bworks?\b/i.test(text);
|
|
536
|
+
if (intent === INTENT_CLASSES.research && !localWalkthrough) {
|
|
537
|
+
return 'research-synthesis';
|
|
538
|
+
}
|
|
539
|
+
if (docAuthoring?.docType) {
|
|
540
|
+
const contract = resolveArtifactWorkflowContract(docAuthoring.docType);
|
|
541
|
+
const workflowType = WORKFLOW_SKILL_TO_TYPE[contract?.workflowSkill];
|
|
542
|
+
if (workflowType) return workflowType;
|
|
543
|
+
}
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
|
|
468
547
|
export function selectSpecialists({ request = '', intent, track, riskFlags = detectRiskFlags(request), workCategory = classifyWorkCategory(request, riskFlags) } = {}) {
|
|
469
548
|
const text = String(request).toLowerCase();
|
|
470
549
|
const productRequest = isProductIntelligenceRequest(text);
|
|
@@ -474,6 +553,8 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
|
|
|
474
553
|
if (track === EXECUTION_TRACKS.focused) {
|
|
475
554
|
if (workCategory === WORK_CATEGORIES.visual || riskFlags.ui) return ['cx-designer'];
|
|
476
555
|
if (productRequest) return ['cx-product-manager'];
|
|
556
|
+
const docAuthoring = detectDocAuthoringIntent(text);
|
|
557
|
+
if (docAuthoring?.owner) return [docAuthoring.owner];
|
|
477
558
|
if (dataEngineeringRequest) return ['cx-data-engineer'];
|
|
478
559
|
if (dataAnalysisRequest) return ['cx-data-analyst'];
|
|
479
560
|
if (isLegalComplianceRequest(text)) return ['cx-legal-compliance'];
|
|
@@ -482,13 +563,15 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
|
|
|
482
563
|
if (isRdLeadRequest(text)) return ['cx-rd-lead'];
|
|
483
564
|
if (isExplorerRequest(text)) return ['cx-explorer'];
|
|
484
565
|
if (riskFlags.docs) return ['cx-docs-keeper'];
|
|
485
|
-
if (riskFlags.security && intent === INTENT_CLASSES.evaluation) return ['cx-security'];
|
|
486
|
-
return SPECIALIST_MAP[intent] || ['cx-engineer'];
|
|
566
|
+
if (riskFlags.security && intent === INTENT_CLASSES.evaluation) return refineEngineeringSpecialists(['cx-security'], request);
|
|
567
|
+
return refineEngineeringSpecialists(SPECIALIST_MAP[intent] || ['cx-engineer'], request);
|
|
487
568
|
}
|
|
488
569
|
|
|
489
570
|
const specialists = ['cx-architect'];
|
|
490
571
|
if (intent === INTENT_CLASSES.fix || intent === INTENT_CLASSES.investigation) specialists.push('cx-debugger');
|
|
491
572
|
if (intent === INTENT_CLASSES.research) specialists.push('cx-researcher');
|
|
573
|
+
const docAuthoring = detectDocAuthoringIntent(text);
|
|
574
|
+
if (docAuthoring?.owner) specialists.push(docAuthoring.owner);
|
|
492
575
|
if (workCategory === WORK_CATEGORIES.visual || riskFlags.ui) specialists.push('cx-designer');
|
|
493
576
|
if (productRequest) specialists.push('cx-product-manager');
|
|
494
577
|
if (dataAnalysisRequest) specialists.push('cx-data-analyst');
|
|
@@ -496,7 +579,56 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
|
|
|
496
579
|
else if (riskFlags.docs) specialists.push('cx-docs-keeper');
|
|
497
580
|
specialists.push('cx-engineer', 'cx-reviewer', 'cx-qa');
|
|
498
581
|
if (riskFlags.security || riskFlags.dataIntegrity) specialists.push('cx-security');
|
|
499
|
-
return Array.from(new Set(specialists));
|
|
582
|
+
return refineEngineeringSpecialists(Array.from(new Set(specialists)), request);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export function augmentSpecialists(
|
|
586
|
+
specialists = [],
|
|
587
|
+
{
|
|
588
|
+
request = '',
|
|
589
|
+
docAuthoring = null,
|
|
590
|
+
externalResearch = null,
|
|
591
|
+
framingChallenge = null,
|
|
592
|
+
artifactReview = null,
|
|
593
|
+
triggers = [],
|
|
594
|
+
} = {},
|
|
595
|
+
) {
|
|
596
|
+
let list = [...specialists];
|
|
597
|
+
if (docAuthoring?.owner && !list.includes(docAuthoring.owner)) {
|
|
598
|
+
list = [docAuthoring.owner, ...list];
|
|
599
|
+
}
|
|
600
|
+
if (externalResearch?.required && !list.includes('cx-researcher')) {
|
|
601
|
+
list = ['cx-researcher', ...list];
|
|
602
|
+
}
|
|
603
|
+
if (framingChallenge?.required && !list.includes('cx-devil-advocate')) {
|
|
604
|
+
list = ['cx-devil-advocate', ...list];
|
|
605
|
+
}
|
|
606
|
+
for (const reviewer of artifactReview?.requiredReviewers || []) {
|
|
607
|
+
if (!list.includes(reviewer)) list = [...list, reviewer];
|
|
608
|
+
}
|
|
609
|
+
if (isLegalComplianceRequest(request) && !list.includes('cx-legal-compliance')) {
|
|
610
|
+
list = ['cx-legal-compliance', ...list];
|
|
611
|
+
}
|
|
612
|
+
if (isRdLeadRequest(request) && !list.includes('cx-rd-lead')) {
|
|
613
|
+
list = ['cx-rd-lead', ...list];
|
|
614
|
+
}
|
|
615
|
+
if (isBusinessStrategyRequest(request) && !list.includes('cx-business-strategist')) {
|
|
616
|
+
list = ['cx-business-strategist', ...list];
|
|
617
|
+
}
|
|
618
|
+
for (const { specialist } of triggers) {
|
|
619
|
+
if (!list.includes(specialist)) list = [specialist, ...list];
|
|
620
|
+
}
|
|
621
|
+
return Array.from(new Set(list));
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function enrichPolicyForProjectQuestion(request, policySpecialists = []) {
|
|
625
|
+
if (!/\b(what is this (project|repo|codebase)|what('s| is) this (project|repo|codebase)|describe this (project|repo|codebase))\b/i.test(String(request))) {
|
|
626
|
+
return policySpecialists;
|
|
627
|
+
}
|
|
628
|
+
const list = [...policySpecialists];
|
|
629
|
+
if (!list.includes('cx-explorer')) list.unshift('cx-explorer');
|
|
630
|
+
if (!list.includes('cx-researcher')) list.splice(list.indexOf('cx-explorer') + 1, 0, 'cx-researcher');
|
|
631
|
+
return Array.from(new Set(list));
|
|
500
632
|
}
|
|
501
633
|
|
|
502
634
|
/**
|
|
@@ -598,7 +730,7 @@ export function requestSignals(request = '', context = {}) {
|
|
|
598
730
|
// pairs for specialists that should engage PRE-DISPATCH based on signals —
|
|
599
731
|
// separate from the keyword-only paths in selectSpecialists. The watch
|
|
600
732
|
// predicates and their specialist owners are declared in
|
|
601
|
-
// specialists/
|
|
733
|
+
// specialists/org (watchConditions) and evaluated by
|
|
602
734
|
// orchestration/routing-tables.mjs.
|
|
603
735
|
|
|
604
736
|
export function proactiveTriggers(signals) {
|
|
@@ -667,6 +799,159 @@ function resolveArtifactReviewRequirements(docAuthoring) {
|
|
|
667
799
|
};
|
|
668
800
|
}
|
|
669
801
|
|
|
802
|
+
// Map a free-text request to the decision names that gate it. Keyed against the
|
|
803
|
+
// union of every team's forbiddenDecisions so a BLOCKED status fires only when
|
|
804
|
+
// the request actually asks for a decision the primary team cannot make. Ordered
|
|
805
|
+
// most-specific-first (deployment-timing before deployment) so the narrow match
|
|
806
|
+
// wins.
|
|
807
|
+
|
|
808
|
+
const REQUESTED_DECISION_PATTERNS = [
|
|
809
|
+
[/\bsecurity[ -]?override\b|\boverride\s+(the\s+)?security\b/i, 'security-override'],
|
|
810
|
+
[/\bdeployment[ -]?timing\b|\bwhen\s+to\s+deploy\b|\bdeploy\s+(?:immediately|now)\b/i, 'deployment-timing'],
|
|
811
|
+
[/\bdeployment[ -]?readiness\b/i, 'deployment-readiness'],
|
|
812
|
+
[/\bdeploy(?:ment|ing|s)?\b|\brelease\s+to\s+prod/i, 'deployment'],
|
|
813
|
+
[/\binfra(?:structure)?[ -]?change\b|\bchange\s+(?:the\s+)?infra/i, 'infra-change'],
|
|
814
|
+
[/\bscope[ -]?change\b|\bchange\s+(?:the\s+)?scope\b|\bre-?scope\b/i, 'scope-change'],
|
|
815
|
+
[/\bproduct[ -]?scope\b/i, 'product-scope'],
|
|
816
|
+
[/\buser[ -]?research\s+method/i, 'user-research-methods'],
|
|
817
|
+
[/\buser[ -]?research\b/i, 'user-research'],
|
|
818
|
+
[/\bimplementation[ -]?approach\b/i, 'implementation-approach'],
|
|
819
|
+
[/\bimplementation[ -]?detail/i, 'implementation-details'],
|
|
820
|
+
[/\bsecurity[ -]?policy\b/i, 'security-policy'],
|
|
821
|
+
[/\bops[ -]?procedure|operational\s+procedure/i, 'ops-procedures'],
|
|
822
|
+
[/\barchitect/i, 'architecture'],
|
|
823
|
+
];
|
|
824
|
+
|
|
825
|
+
function detectRequestedDecisions(request = '') {
|
|
826
|
+
const text = String(request || '');
|
|
827
|
+
const found = new Set();
|
|
828
|
+
for (const [pattern, decision] of REQUESTED_DECISION_PATTERNS) {
|
|
829
|
+
if (pattern.test(text)) found.add(decision);
|
|
830
|
+
}
|
|
831
|
+
return Array.from(found);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Build team-aware routing metadata (RFC-0004 §2).
|
|
836
|
+
* Returns { primaryTeam, involvedTeams, requiredApprovals, escalationPath, blockedStatus }.
|
|
837
|
+
*
|
|
838
|
+
* The primary team is intent-driven (INTENT_TO_TEAM), falling back to the first
|
|
839
|
+
* specialist's team when the intent has no mapping. involvedTeams unions the
|
|
840
|
+
* primary team with every selected specialist's team. blockedStatus fires when
|
|
841
|
+
* the primary team's forbiddenDecisions intersect the decisions the request asks
|
|
842
|
+
* for; escalation walks the primary team's path first. Team membership and team
|
|
843
|
+
* metadata resolve from specialists/org.
|
|
844
|
+
*/
|
|
845
|
+
export function teamRoutingForSpecialists(specialists = [], { intent = null, request = '', cwd = null, docAuthoring = null } = {}) {
|
|
846
|
+
let registry = null;
|
|
847
|
+
try {
|
|
848
|
+
registry = loadRegistry();
|
|
849
|
+
} catch {
|
|
850
|
+
return {
|
|
851
|
+
primaryTeam: null,
|
|
852
|
+
involvedTeams: [],
|
|
853
|
+
requiredApprovals: [],
|
|
854
|
+
escalationPath: [],
|
|
855
|
+
blockedStatus: null,
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
const profile = cwd ? resolveActiveScope(cwd) : null;
|
|
860
|
+
const profileTeams = scopeTeamsById(profile);
|
|
861
|
+
|
|
862
|
+
const teams = new Map();
|
|
863
|
+
const involvedTeamIds = new Set();
|
|
864
|
+
const addTeam = (teamId) => {
|
|
865
|
+
if (!teamId) return;
|
|
866
|
+
involvedTeamIds.add(teamId);
|
|
867
|
+
if (teams.has(teamId)) return;
|
|
868
|
+
const profileTeam = profileTeams ? resolveScopeTeamMeta(teamId, profile) : null;
|
|
869
|
+
teams.set(teamId, profileTeam || registry.teams?.[teamId] || null);
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
for (const specialistId of specialists) {
|
|
873
|
+
const cxId = specialistId.startsWith('cx-') ? specialistId : `cx-${specialistId}`;
|
|
874
|
+
const specialist = registry.specialists?.[cxId];
|
|
875
|
+
if (specialist?.team) addTeam(specialist.team);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// RFC-0004 §2 step 2: intent selects the primary owning team. It always counts
|
|
879
|
+
// as involved even if no selected specialist sits on it yet.
|
|
880
|
+
const profileIntentTeam = resolveIntentTeamForScope(intent, profile);
|
|
881
|
+
const intentTeam = profileIntentTeam
|
|
882
|
+
?? (intent && INTENT_TO_TEAM[intent] ? INTENT_TO_TEAM[intent] : null);
|
|
883
|
+
addTeam(intentTeam);
|
|
884
|
+
|
|
885
|
+
const involvedTeams = Array.from(involvedTeamIds).sort();
|
|
886
|
+
let primaryTeam = intentTeam || (involvedTeams.length > 0 ? involvedTeams[0] : null);
|
|
887
|
+
|
|
888
|
+
if (docAuthoring?.owner) {
|
|
889
|
+
const cxId = docAuthoring.owner.startsWith('cx-') ? docAuthoring.owner : `cx-${docAuthoring.owner}`;
|
|
890
|
+
const ownerTeam = registry.specialists?.[cxId]?.team;
|
|
891
|
+
if (ownerTeam) {
|
|
892
|
+
addTeam(ownerTeam);
|
|
893
|
+
primaryTeam = ownerTeam;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Collect required approvals from involved teams' decision rights.
|
|
898
|
+
const requiredApprovals = new Set();
|
|
899
|
+
for (const teamId of involvedTeamIds) {
|
|
900
|
+
const team = teams.get(teamId);
|
|
901
|
+
if (team?.decisionRights) {
|
|
902
|
+
for (const decision of team.decisionRights) requiredApprovals.add(decision);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// RFC-0004 §2 step 5: BLOCKED when the primary team forbids a decision the
|
|
907
|
+
// request actually asks for. Escalate via that team's path.
|
|
908
|
+
let blockedStatus = null;
|
|
909
|
+
const primaryTeamObj = primaryTeam ? (teams.get(primaryTeam) || registry.teams?.[primaryTeam]) : null;
|
|
910
|
+
if (Array.isArray(primaryTeamObj?.forbiddenDecisions)) {
|
|
911
|
+
const blocked = detectRequestedDecisions(request)
|
|
912
|
+
.filter((decision) => primaryTeamObj.forbiddenDecisions.includes(decision));
|
|
913
|
+
if (blocked.length > 0) {
|
|
914
|
+
blockedStatus = {
|
|
915
|
+
team: primaryTeam,
|
|
916
|
+
forbiddenDecisions: blocked,
|
|
917
|
+
escalationPath: primaryTeamObj.escalationPath || [],
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// Concatenate escalation paths, primary team first, de-duplicated.
|
|
923
|
+
const escalationPath = [];
|
|
924
|
+
const seen = new Set();
|
|
925
|
+
const orderedTeams = primaryTeam
|
|
926
|
+
? [primaryTeam, ...involvedTeams.filter((t) => t !== primaryTeam)]
|
|
927
|
+
: involvedTeams;
|
|
928
|
+
for (const teamId of orderedTeams) {
|
|
929
|
+
const team = teams.get(teamId) || registry.teams?.[teamId];
|
|
930
|
+
if (Array.isArray(team?.escalationPath)) {
|
|
931
|
+
for (const role of team.escalationPath) {
|
|
932
|
+
if (!seen.has(role)) {
|
|
933
|
+
escalationPath.push(role);
|
|
934
|
+
seen.add(role);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const squadId = primaryTeamObj?.kind === 'squad' ? primaryTeam : null;
|
|
941
|
+
const groupId = primaryTeamObj?.kind === 'group' ? primaryTeam : (primaryTeamObj?.groupId ?? null);
|
|
942
|
+
|
|
943
|
+
return {
|
|
944
|
+
primaryTeam,
|
|
945
|
+
squadId,
|
|
946
|
+
groupId,
|
|
947
|
+
collaborators: primaryTeamObj?.collaborators || [],
|
|
948
|
+
involvedTeams,
|
|
949
|
+
requiredApprovals: Array.from(requiredApprovals).sort(),
|
|
950
|
+
escalationPath,
|
|
951
|
+
blockedStatus,
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
|
|
670
955
|
export function routeRequest(options = {}) {
|
|
671
956
|
const intent = classifyIntent(options.request);
|
|
672
957
|
const riskFlags = detectRiskFlags(options.request);
|
|
@@ -676,67 +961,65 @@ export function routeRequest(options = {}) {
|
|
|
676
961
|
: null;
|
|
677
962
|
const workCategory = classifyWorkCategory(options.request, riskFlags);
|
|
678
963
|
const track = determineExecutionTrack({ ...options, riskFlags });
|
|
679
|
-
let specialists = selectSpecialists({ ...options, intent, track, riskFlags, workCategory });
|
|
680
964
|
const docAuthoring = detectDocAuthoringIntent(options.request);
|
|
681
965
|
const externalResearch = requiresExternalResearch({ request: options.request, workCategory, riskFlags });
|
|
682
966
|
const framingChallenge = requiresFramingChallenge({ request: options.request, workCategory, riskFlags, introducesContract: options.introducesContract });
|
|
683
|
-
|
|
684
|
-
// Doc ownership: the owning specialist authors; orchestrator routes.
|
|
685
|
-
if (docAuthoring?.owner && !specialists.includes(docAuthoring.owner)) {
|
|
686
|
-
specialists = [docAuthoring.owner, ...specialists];
|
|
687
|
-
}
|
|
688
|
-
// External research must precede authoring.
|
|
689
|
-
if (externalResearch.required && !specialists.includes('cx-researcher')) {
|
|
690
|
-
specialists = ['cx-researcher', ...specialists];
|
|
691
|
-
}
|
|
692
|
-
// Framing challenge must precede scaffolding.
|
|
693
|
-
if (framingChallenge.required && !specialists.includes('cx-devil-advocate')) {
|
|
694
|
-
specialists = ['cx-devil-advocate', ...specialists];
|
|
695
|
-
}
|
|
696
|
-
|
|
697
967
|
const artifactReview = resolveArtifactReviewRequirements(docAuthoring);
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
// Order matters: business framing → R&D validation → legal/compliance review,
|
|
703
|
-
// each prepended so it runs earliest in the chain.
|
|
704
|
-
if (isLegalComplianceRequest(options.request) && !specialists.includes('cx-legal-compliance')) {
|
|
705
|
-
specialists = ['cx-legal-compliance', ...specialists];
|
|
706
|
-
}
|
|
707
|
-
if (isRdLeadRequest(options.request) && !specialists.includes('cx-rd-lead')) {
|
|
708
|
-
specialists = ['cx-rd-lead', ...specialists];
|
|
709
|
-
}
|
|
710
|
-
if (isBusinessStrategyRequest(options.request) && !specialists.includes('cx-business-strategist')) {
|
|
711
|
-
specialists = ['cx-business-strategist', ...specialists];
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// Signal-driven proactive triggers — surfaces specialists whose engagement
|
|
715
|
-
// hinges on structured signals rather than literal keyword matches. The
|
|
716
|
-
// routing list is union'd with the keyword paths so neither dimension
|
|
717
|
-
// drops a legitimate dispatch.
|
|
718
|
-
|
|
968
|
+
const suggestedWorkflowType = suggestWorkflowType({ intent, request: options.request, docAuthoring });
|
|
969
|
+
const researchExecutionPolicy = intent === INTENT_CLASSES.research || externalResearch?.required
|
|
970
|
+
? buildResearchExecutionPolicy({ request: options.request })
|
|
971
|
+
: null;
|
|
719
972
|
const signals = requestSignals(options.request, options.context);
|
|
720
973
|
const triggers = proactiveTriggers(signals);
|
|
721
974
|
const reasons = {};
|
|
722
975
|
for (const { specialist, reason } of triggers) {
|
|
723
|
-
if (!specialists.includes(specialist)) specialists = [specialist, ...specialists];
|
|
724
976
|
reasons[specialist] = reason;
|
|
725
977
|
}
|
|
726
|
-
|
|
978
|
+
|
|
979
|
+
const augmentOpts = {
|
|
980
|
+
request: options.request,
|
|
981
|
+
docAuthoring,
|
|
982
|
+
externalResearch,
|
|
983
|
+
framingChallenge,
|
|
984
|
+
artifactReview,
|
|
985
|
+
triggers,
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
let specialists = augmentSpecialists(
|
|
989
|
+
selectSpecialists({ ...options, intent, track, riskFlags, workCategory }),
|
|
990
|
+
augmentOpts,
|
|
991
|
+
);
|
|
992
|
+
|
|
993
|
+
const policyTrack = track === EXECUTION_TRACKS.immediate ? EXECUTION_TRACKS.focused : track;
|
|
994
|
+
let policySpecialists = augmentSpecialists(
|
|
995
|
+
selectSpecialists({ ...options, intent, track: policyTrack, riskFlags, workCategory }),
|
|
996
|
+
augmentOpts,
|
|
997
|
+
);
|
|
998
|
+
policySpecialists = enrichPolicyForProjectQuestion(options.request, policySpecialists);
|
|
999
|
+
|
|
1000
|
+
const displaySpecialists = specialists.length ? specialists : policySpecialists;
|
|
727
1001
|
|
|
728
1002
|
const contractChain = resolveContractChain({
|
|
729
1003
|
intent,
|
|
730
1004
|
workCategory,
|
|
731
1005
|
track,
|
|
732
1006
|
riskFlags,
|
|
733
|
-
specialists,
|
|
1007
|
+
specialists: displaySpecialists,
|
|
734
1008
|
framingChallenge,
|
|
735
1009
|
externalResearch,
|
|
736
1010
|
docAuthoring,
|
|
737
1011
|
artifactReview,
|
|
738
1012
|
});
|
|
739
1013
|
|
|
1014
|
+
// Team-aware routing: analyze specialist-to-team mapping and identify
|
|
1015
|
+
// team involvement, primary owner, required approvals, and escalation paths.
|
|
1016
|
+
const teamRouting = teamRoutingForSpecialists(displaySpecialists, {
|
|
1017
|
+
intent,
|
|
1018
|
+
request: options.request,
|
|
1019
|
+
cwd: options.cwd ?? null,
|
|
1020
|
+
docAuthoring,
|
|
1021
|
+
});
|
|
1022
|
+
|
|
740
1023
|
const route = {
|
|
741
1024
|
intent,
|
|
742
1025
|
workCategory,
|
|
@@ -745,6 +1028,8 @@ export function routeRequest(options = {}) {
|
|
|
745
1028
|
productFlavor,
|
|
746
1029
|
roleFlavors,
|
|
747
1030
|
specialists,
|
|
1031
|
+
policySpecialists,
|
|
1032
|
+
displaySpecialists,
|
|
748
1033
|
signals,
|
|
749
1034
|
triggers,
|
|
750
1035
|
dispatchReasons: reasons,
|
|
@@ -752,9 +1037,12 @@ export function routeRequest(options = {}) {
|
|
|
752
1037
|
externalResearch,
|
|
753
1038
|
framingChallenge,
|
|
754
1039
|
artifactReview,
|
|
1040
|
+
suggestedWorkflowType,
|
|
1041
|
+
researchExecutionPolicy,
|
|
755
1042
|
contractChain,
|
|
756
|
-
|
|
757
|
-
|
|
1043
|
+
teamRouting,
|
|
1044
|
+
dispatchPlan: buildDispatchPlan({ track, intent, specialists: displaySpecialists }),
|
|
1045
|
+
dispatchSummary: buildDispatchSummary({ specialists: displaySpecialists, reasons }),
|
|
758
1046
|
};
|
|
759
1047
|
|
|
760
1048
|
if (process.env.CONSTRUCT_VERBOSE === '1' && triggers.length > 0) {
|
|
@@ -777,7 +1065,7 @@ export function routeRequestVerified(options = {}) {
|
|
|
777
1065
|
}
|
|
778
1066
|
|
|
779
1067
|
/**
|
|
780
|
-
* Build the construct→orchestrator contract packet (specialists/
|
|
1068
|
+
* Build the construct→orchestrator contract packet (specialists/org).
|
|
781
1069
|
* Callers must pass this object to agent_contract — not a bare goal string.
|
|
782
1070
|
*/
|
|
783
1071
|
export function buildConstructToOrchestratorPacket(options = {}) {
|
|
@@ -801,6 +1089,7 @@ export function buildConstructToOrchestratorPacket(options = {}) {
|
|
|
801
1089
|
intent: route.intent,
|
|
802
1090
|
workCategory: route.workCategory,
|
|
803
1091
|
riskFlags: route.riskFlags || {},
|
|
1092
|
+
suggestedWorkflowType: route.suggestedWorkflowType || null,
|
|
804
1093
|
acceptanceCriteria,
|
|
805
1094
|
};
|
|
806
1095
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/overrides/resolver.mjs — single override + backup helper for every
|
|
3
|
-
* user-customizable Construct primitive (personas, skills, rules
|
|
4
|
-
* contracts, role manifests).
|
|
3
|
+
* user-customizable Construct primitive (personas, agents, skills, rules).
|
|
5
4
|
*
|
|
6
5
|
* Convention:
|
|
7
6
|
* - Original lives in the install (`personas/<n>.md`, `skills/.../<n>.md`, …)
|
|
@@ -32,8 +31,6 @@ export const SUPPORTED_CATEGORIES = Object.freeze([
|
|
|
32
31
|
'agents',
|
|
33
32
|
'skills',
|
|
34
33
|
'rules',
|
|
35
|
-
'contracts',
|
|
36
|
-
'role-manifests',
|
|
37
34
|
]);
|
|
38
35
|
|
|
39
36
|
const CATEGORY_RULES = {
|
|
@@ -41,8 +38,6 @@ const CATEGORY_RULES = {
|
|
|
41
38
|
agents: { originalDir: 'specialists/prompts', defaultExt: '.md' },
|
|
42
39
|
skills: { originalDir: 'skills', defaultExt: '.md' },
|
|
43
40
|
rules: { originalDir: 'rules', defaultExt: '.md' },
|
|
44
|
-
contracts: { originalDir: 'specialists', defaultExt: '.json', singleFile: 'contracts.json' },
|
|
45
|
-
'role-manifests': { originalDir: 'specialists', defaultExt: '.json', singleFile: 'role-manifests.json' },
|
|
46
41
|
};
|
|
47
42
|
|
|
48
43
|
function categoryRule(category) {
|
|
@@ -69,18 +64,12 @@ function ensureCxIgnore(projectRoot) {
|
|
|
69
64
|
|
|
70
65
|
function originalPath(projectRoot, category, name) {
|
|
71
66
|
const rule = categoryRule(category);
|
|
72
|
-
if (rule.singleFile) {
|
|
73
|
-
return path.join(projectRoot, rule.originalDir, rule.singleFile);
|
|
74
|
-
}
|
|
75
67
|
const ext = name.includes('.') ? '' : rule.defaultExt;
|
|
76
68
|
return path.join(projectRoot, rule.originalDir, `${name}${ext}`);
|
|
77
69
|
}
|
|
78
70
|
|
|
79
71
|
function overridePath(projectRoot, category, name) {
|
|
80
72
|
const rule = categoryRule(category);
|
|
81
|
-
if (rule.singleFile) {
|
|
82
|
-
return path.join(projectRoot, '.cx', category, rule.singleFile);
|
|
83
|
-
}
|
|
84
73
|
const ext = name.includes('.') ? '' : rule.defaultExt;
|
|
85
74
|
return path.join(projectRoot, '.cx', category, `${name}${ext}`);
|
|
86
75
|
}
|