@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
|
@@ -67,3 +67,55 @@ There is no authorized bypass. Beads hygiene is a release gate. If the tooling i
|
|
|
67
67
|
## Automation
|
|
68
68
|
|
|
69
69
|
Project-level automation is tracked in the beads queue: auto-close on merge, pre-push `bd preflight` gate, weekly drift report, memory-contradiction detection. Until that ships, hygiene is a per-session discipline.
|
|
70
|
+
|
|
71
|
+
## Execution protocol (construct-m7k2 / feature/team-redesign)
|
|
72
|
+
|
|
73
|
+
Every child bead under epic `construct-m7k2` uses **double validation** before close. Definitions are normative for agents on any model tier (including smaller models).
|
|
74
|
+
|
|
75
|
+
### Pass A — implementer
|
|
76
|
+
|
|
77
|
+
The agent that claimed the bead and wrote the code:
|
|
78
|
+
|
|
79
|
+
1. Run scoped tests cited in the bead acceptance criteria (`npm test` or `node --test tests/...`).
|
|
80
|
+
2. Run bead-specific grep or CLI assertions listed in the bead body.
|
|
81
|
+
3. Record command output in `bd note <id>` or the close reason (exit codes, failure counts).
|
|
82
|
+
|
|
83
|
+
Pass A is not done if tests were not executed in this environment.
|
|
84
|
+
|
|
85
|
+
### Pass B — reviewer (different model or fresh session)
|
|
86
|
+
|
|
87
|
+
A different agent, or the same agent in a new session with no assumed memory of Pass A:
|
|
88
|
+
|
|
89
|
+
1. Re-run every Pass A command independently (do not trust prior transcripts).
|
|
90
|
+
2. Run `npm run release:check`.
|
|
91
|
+
3. Run `construct doctor` — no new team/auth/MCP warnings attributable to the change.
|
|
92
|
+
4. Confirm no `CONSTRUCT_SKIP_*` / `CONSTRUCT_ALLOW_*` env vars were introduced.
|
|
93
|
+
|
|
94
|
+
Pass B is not done if `release:check` was not run.
|
|
95
|
+
|
|
96
|
+
### Parallel runs — verify the committed branch, never a stray worktree
|
|
97
|
+
|
|
98
|
+
When beads are implemented by parallel subagents in isolated git worktrees, the verify loop must check the **implementer's committed work**, not a fresh tree branched from the base:
|
|
99
|
+
|
|
100
|
+
1. **Implementers commit to a named branch before review.** No uncommitted worktree state may gate a close — uncommitted work is invisible to a fresh reviewer and is lost when the worktree is pruned.
|
|
101
|
+
2. **Reviewers check out and verify that exact branch** (or the integration branch after merge). A reviewer that branches from the base commit is verifying the *wrong tree*.
|
|
102
|
+
3. **Integration merges the reviewed branch**, then re-runs the close evidence on the merged result.
|
|
103
|
+
4. **Close evidence is reproduced on the merged branch** — e.g. grep the new symbol on the branch, not in a worktree. A symbol that exists only in a worktree is not landed.
|
|
104
|
+
|
|
105
|
+
Failure mode this prevents (observed 2026-06-25): a bead was closed with a reason naming files that were never committed — the work was stranded uncommitted in a worktree, the reviewer branched from base and "passed" the pre-existing tests, and pruning the worktree discarded the work. A close reason must name only what is reproducible on the branch.
|
|
106
|
+
|
|
107
|
+
### Baseline-diff close gate
|
|
108
|
+
|
|
109
|
+
When the suite is not green (pre-existing unrelated failures), "all tests pass" is unsatisfiable and invites premature closes. Use a baseline-diff instead:
|
|
110
|
+
|
|
111
|
+
1. Capture the failing-test set once at the start (e.g. `.cx/artifacts/baseline-fails.json`).
|
|
112
|
+
2. A bead may close only if its scoped tests pass **and** the full suite introduces **zero new failures** vs the baseline. Newly-passing tests are a bonus, not a requirement.
|
|
113
|
+
3. A test that fails on genuinely out-of-scope incomplete logic is marked `node:test` `todo` with a tracking bead id — flagged, not hidden — never silently skipped.
|
|
114
|
+
|
|
115
|
+
### Bead body template
|
|
116
|
+
|
|
117
|
+
Child beads must include sections: Goal, Read first, Out of scope, Steps, Acceptance criteria, Pass A checklist, Pass B checklist, Do not touch. See `construct-m7k2.9` for the gate bead that introduced this contract.
|
|
118
|
+
|
|
119
|
+
### Gate bead
|
|
120
|
+
|
|
121
|
+
Claim `construct-m7k2.9` first on the epic branch to land this section, then proceed to `construct-m7k2-fix-tests` and downstream work per the dependency graph.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: every human-facing Construct output is formatted for neurodivergent readers — without reshaping machine-readable output.
|
|
3
|
-
enforced_by: (persona prompt), tests/term-format.test.mjs
|
|
3
|
+
enforced_by: (persona prompt), tests/term-format.test.mjs
|
|
4
4
|
precedence_tier: style
|
|
5
5
|
---
|
|
6
6
|
# Neurodivergent-Friendly Output
|
|
7
7
|
|
|
8
|
-
Construct's output is read under load — in a terminal, mid-task, often by people who process text differently. Dense walls of prose, buried conclusions, inconsistent structure, and meaning carried only by color cost every reader attention, and cost neurodivergent readers more. This rule applies to **every human-facing output** Construct produces: terminal output, agent prose to the user, reports, error messages
|
|
8
|
+
Construct's output is read under load — in a terminal, mid-task, often by people who process text differently. Dense walls of prose, buried conclusions, inconsistent structure, and meaning carried only by color cost every reader attention, and cost neurodivergent readers more. This rule applies to **every human-facing output** Construct produces: terminal output, agent prose to the user, reports, and error messages.
|
|
9
9
|
|
|
10
10
|
It is a `style` rule by design. The precedence resolver (`rules/common/precedence.md`) guarantees a style rule never overrides a higher tier — so when accessible formatting would conflict with correct machine output, correctness wins automatically. Section 0 states that boundary explicitly.
|
|
11
11
|
|
|
@@ -13,8 +13,8 @@ It is a `style` rule by design. The precedence resolver (`rules/common/precedenc
|
|
|
13
13
|
|
|
14
14
|
Two layers, treated differently:
|
|
15
15
|
|
|
16
|
-
- **Presentation layer (human-facing)** — section titles, prose, help text, report narratives, guidance notes, error wording
|
|
17
|
-
- **Data layer (machine-readable)** — never reshape it for readability. Off-limits: any `--json` / `--plain` output; `specialists/
|
|
16
|
+
- **Presentation layer (human-facing)** — section titles, prose, help text, report narratives, guidance notes, error wording. This is what the rest of this rule shapes.
|
|
17
|
+
- **Data layer (machine-readable)** — never reshape it for readability. Off-limits: any `--json` / `--plain` output; `specialists/org`, `contracts.json`, `role-manifests.json`; the parsed tokens hooks emit (for example the session-start `## Working branch: **<name>**` line, the efficiency status enum `degraded` / `configured` / `healthy`, commit hashes, counts); auxiliary state JSON; any text one component parses out of another.
|
|
18
18
|
|
|
19
19
|
When a format choice would change a value, key, ordering, or token that something downstream parses, do not make it. Accessibility is presentation; it never edits the contract.
|
|
20
20
|
|
|
@@ -47,19 +47,16 @@ End human-facing output with the current state and the next action in plain word
|
|
|
47
47
|
- Meaning carried by color must also be carried by text, shape, or label. A red number is also labelled `error`; a green check is also the word `passed`.
|
|
48
48
|
- Honor `NO_COLOR`, non-TTY, and `TERM=dumb`: degrade to plain text, never to nothing.
|
|
49
49
|
- Respect terminal width — wrap rather than overflow.
|
|
50
|
-
- On the dashboard, honor `prefers-reduced-motion` and `prefers-color-scheme`; motion is never required to understand state, and animation can be fully disabled.
|
|
51
50
|
|
|
52
51
|
## Applies to
|
|
53
52
|
|
|
54
53
|
- **Terminal / CLI** — help text, status, reports, hook display. Routed through the shared formatter (`lib/term-format.mjs`); color and width handled there, never per-call.
|
|
55
54
|
- **Agent prose** — every response Construct and its specialists return to the user.
|
|
56
|
-
- **Dashboard** — `apps/dashboard/` source (semantic landmarks, labels, focus, contrast, reduced-motion), rebuilt into `lib/server/static/`.
|
|
57
55
|
|
|
58
56
|
## Enforcement
|
|
59
57
|
|
|
60
58
|
- Persona prompt: `personas/construct.md` carries the output-style directive; specialists inherit the standard through the front-door agent.
|
|
61
59
|
- `tests/term-format.test.mjs` asserts the terminal formatter honors `NO_COLOR` / non-TTY and that machine-readable `--json` output is unchanged by presentation changes.
|
|
62
|
-
- `construct dashboard:sync --check` keeps the built dashboard in step with the accessible source.
|
|
63
60
|
|
|
64
61
|
## Bypass
|
|
65
62
|
|
package/rules/common/research.md
CHANGED
|
@@ -58,6 +58,8 @@ Start with the narrowest authoritative source that can answer the question:
|
|
|
58
58
|
4. **Tertiary sources last**
|
|
59
59
|
- blogs, forums, Q&A, analyst summaries, AI-generated summaries
|
|
60
60
|
|
|
61
|
+
When the research is specifically about a library/framework/API/cloud-docs surface, a docs MCP such as Context7 is an acceptable way to reach the official documentation. It is a retrieval path, not the evidence standard. If that MCP is unavailable or incomplete, fall back to direct web search and fetch against the official docs, changelog, and release notes. Do not block research on the presence of a single docs integration.
|
|
62
|
+
|
|
61
63
|
## 4. Required metadata for every source
|
|
62
64
|
|
|
63
65
|
Record:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* sync-specialists.mjs — regenerate agent adapters for all platforms from specialists/
|
|
3
|
+
* sync-specialists.mjs — regenerate agent adapters for all platforms from specialists/org.
|
|
4
4
|
*
|
|
5
5
|
* Two scopes, modelled on every host's own convention (global = personal default,
|
|
6
6
|
* project = team-shared):
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import fs from "node:fs";
|
|
32
32
|
import path from "node:path";
|
|
33
33
|
import os from "node:os";
|
|
34
|
+
import { fileURLToPath } from "node:url";
|
|
34
35
|
import { generateCompletions } from "../lib/completions.mjs";
|
|
35
36
|
import {
|
|
36
37
|
buildCodexMcpEntry,
|
|
@@ -43,7 +44,7 @@ import {
|
|
|
43
44
|
tomlString,
|
|
44
45
|
writeCodexConfig,
|
|
45
46
|
} from "../lib/codex-config.mjs";
|
|
46
|
-
import { findOpenCodeConfigPath, readOpenCodeConfig, writeOpenCodeConfig } from "../lib/opencode-config.mjs";
|
|
47
|
+
import { findOpenCodeConfigPath, readOpenCodeConfig, writeOpenCodeConfig, ensureOpenRouterProviderAuth } from "../lib/opencode-config.mjs";
|
|
47
48
|
import { HEAVY_EXTERNAL_MCP_IDS, LOCAL_SURFACE_MODES, decideTrim, isLocalModel } from "../lib/mcp/tool-budget.mjs";
|
|
48
49
|
import { emitCursorRules } from "../lib/rules-delivery.mjs";
|
|
49
50
|
import { resolvePromptContract, readPromptBody } from "../lib/prompt-composer.js";
|
|
@@ -59,21 +60,67 @@ import { configDir } from "../lib/config/xdg.mjs";
|
|
|
59
60
|
import { inlineRoleAntiPatterns, PROMPT_WORD_CAP } from "../lib/role-preload.mjs";
|
|
60
61
|
import { inlineValidationContract } from "../lib/prompt-validation-contract.mjs";
|
|
61
62
|
import { loadManifest } from "../lib/roles/manifest.mjs";
|
|
62
|
-
import {
|
|
63
|
+
import { resolveActiveScope } from "../lib/scopes/loader.mjs";
|
|
63
64
|
import { resolveTiersForPrimary, resolveCapabilityTier, selectLocalEditorModel } from "../lib/model-router.mjs";
|
|
64
65
|
import { stampFrontmatter } from "../lib/doc-stamp.mjs";
|
|
65
66
|
import { buildSkillFrontmatter, stripLeadingFrontmatter } from "../lib/sync/skill-frontmatter.mjs";
|
|
67
|
+
import { loadRegistry, clearCache } from "../lib/registry/loader.mjs";
|
|
68
|
+
import { loadPluginRegistry } from "../lib/plugin-registry.mjs";
|
|
66
69
|
|
|
67
70
|
const home = os.homedir();
|
|
68
71
|
const root = path.resolve(import.meta.dirname, "..");
|
|
72
|
+
const isMain = process.argv[1] ? path.resolve(process.argv[1]) === fileURLToPath(import.meta.url) : false;
|
|
69
73
|
|
|
70
74
|
const mergedEnv = loadConstructEnv({ rootDir: root, homeDir: home, env: process.env });
|
|
71
75
|
for (const [key, value] of Object.entries(mergedEnv)) {
|
|
72
76
|
if (!(key in process.env)) process.env[key] = value;
|
|
73
77
|
}
|
|
74
78
|
if (!process.env.CX_TOOLKIT_DIR) process.env.CX_TOOLKIT_DIR = root;
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
|
|
80
|
+
function unifiedToLegacyRegistry(unified) {
|
|
81
|
+
const orchestrator = Object.values(unified.specialists || {}).find(s => s.role === 'orchestrator') || {};
|
|
82
|
+
const specialists = Object.values(unified.specialists || {}).filter(s => s.role !== 'orchestrator');
|
|
83
|
+
return {
|
|
84
|
+
version: 1,
|
|
85
|
+
system: 'construct',
|
|
86
|
+
prefix: 'cx',
|
|
87
|
+
orchestrator: {
|
|
88
|
+
name: 'construct',
|
|
89
|
+
displayName: orchestrator.displayName || orchestrator.description?.split('—')[0].trim() || 'Construct',
|
|
90
|
+
description: orchestrator.description || '',
|
|
91
|
+
promptFile: orchestrator.promptFile || 'specialists/prompts/cx-orchestrator.md',
|
|
92
|
+
modelTier: orchestrator.modelTier || 'standard',
|
|
93
|
+
skills: orchestrator.skills || [],
|
|
94
|
+
injectAgentRoster: orchestrator.injectAgentRoster ?? false,
|
|
95
|
+
},
|
|
96
|
+
specialists: specialists.map(s => ({
|
|
97
|
+
name: s.name,
|
|
98
|
+
displayName: s.displayName || s.description?.split('—')[0].trim() || s.name,
|
|
99
|
+
description: s.description || '',
|
|
100
|
+
promptFile: s.promptFile,
|
|
101
|
+
modelTier: s.modelTier || 'standard',
|
|
102
|
+
claudeTools: s.claudeTools || 'Read,Grep,Glob,LS',
|
|
103
|
+
internal: s.internal,
|
|
104
|
+
wordCapOverride: s.wordCapOverride,
|
|
105
|
+
skills: s.skills || [],
|
|
106
|
+
team: s.team,
|
|
107
|
+
role: s.role,
|
|
108
|
+
docArtifacts: s.docArtifacts || [],
|
|
109
|
+
subscriptions: s.events || [],
|
|
110
|
+
watchConditions: s.watchConditions || [],
|
|
111
|
+
fence: s.fence || {},
|
|
112
|
+
})),
|
|
113
|
+
sharedGuidance: unified.sharedGuidance || [],
|
|
114
|
+
models: unified.models || { reasoning: { primary: null }, standard: { primary: null }, fast: { primary: null } },
|
|
115
|
+
providers: unified.providers || {},
|
|
116
|
+
mcpServers: unified.mcpServers || {},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
clearCache();
|
|
121
|
+
clearCache();
|
|
122
|
+
const unified = loadRegistry({ rootDir: root });
|
|
123
|
+
const registry = unifiedToLegacyRegistry(unified);
|
|
77
124
|
|
|
78
125
|
function validateRegistry(registry) {
|
|
79
126
|
const errors = [];
|
|
@@ -378,15 +425,15 @@ const sharedGuidance = registry.sharedGuidance ?? [];
|
|
|
378
425
|
const platformGuidance = registry.platformGuidance ?? {};
|
|
379
426
|
const globalModelGuidance = registry.modelGuidance ?? {};
|
|
380
427
|
|
|
381
|
-
const generatedHeader = `# Generated by ${systemName}/sync-specialists.mjs. Edit specialists/
|
|
428
|
+
const generatedHeader = `# Generated by ${systemName}/sync-specialists.mjs. Edit specialists/org instead.`;
|
|
382
429
|
const generatedMarkdownNote = [
|
|
383
430
|
'<!--',
|
|
384
|
-
`Generated by construct sync from specialists/
|
|
431
|
+
`Generated by construct sync from specialists/org.`,
|
|
385
432
|
'Do not edit this file directly — changes will be overwritten on next sync.',
|
|
386
433
|
'Regenerate: construct sync',
|
|
387
434
|
'-->',
|
|
388
435
|
'',
|
|
389
|
-
'> Generated from `specialists/
|
|
436
|
+
'> Generated from `specialists/org`. Edit the registry, then run `construct sync`.',
|
|
390
437
|
].join('\n');
|
|
391
438
|
|
|
392
439
|
const standardConstructTools = [
|
|
@@ -432,6 +479,96 @@ function resolveArgs(args) {
|
|
|
432
479
|
: a));
|
|
433
480
|
}
|
|
434
481
|
|
|
482
|
+
function resolveTemplateStrings(value) {
|
|
483
|
+
if (typeof value === "string") {
|
|
484
|
+
return value.replace(/__([A-Z0-9_]+)__/g, (_, name) => {
|
|
485
|
+
if (process.env[name] !== undefined && process.env[name] !== "") return process.env[name];
|
|
486
|
+
if (name === "CX_TOOLKIT_DIR") return root;
|
|
487
|
+
if (name === "MEMORY_PORT") return process.env.MEMORY_PORT || "8765";
|
|
488
|
+
if (name === "CONSTRUCT_MEMORY_BRIDGE_URL") {
|
|
489
|
+
return process.env.CONSTRUCT_MEMORY_BRIDGE_URL || "http://127.0.0.1:8765/";
|
|
490
|
+
}
|
|
491
|
+
if (name === "GITHUB_TOKEN" && process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
|
|
492
|
+
return process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
493
|
+
}
|
|
494
|
+
if (/(?:TOKEN|SECRET|API_KEY|PUBLIC_KEY|PRIVATE_KEY)$/.test(name)) {
|
|
495
|
+
return `{env:${name}}`;
|
|
496
|
+
}
|
|
497
|
+
return `__${name}__`;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
if (Array.isArray(value)) return value.map((item) => resolveTemplateStrings(item));
|
|
501
|
+
if (value && typeof value === "object") {
|
|
502
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, resolveTemplateStrings(item)]));
|
|
503
|
+
}
|
|
504
|
+
return value;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function constructMcpDefinition() {
|
|
508
|
+
return {
|
|
509
|
+
id: "construct-mcp",
|
|
510
|
+
name: "Construct MCP",
|
|
511
|
+
category: "core",
|
|
512
|
+
description: "Construct stdio MCP server for orchestration, skills, templates, and project context.",
|
|
513
|
+
command: "node",
|
|
514
|
+
args: ["__CX_TOOLKIT_DIR__/lib/mcp/server.mjs"],
|
|
515
|
+
env: {
|
|
516
|
+
CONSTRUCT_TRACE_BACKEND: "__CONSTRUCT_TRACE_BACKEND__",
|
|
517
|
+
CONSTRUCT_TELEMETRY_URL: "__CONSTRUCT_TELEMETRY_URL__",
|
|
518
|
+
CONSTRUCT_TELEMETRY_PUBLIC_KEY: "__CONSTRUCT_TELEMETRY_PUBLIC_KEY__",
|
|
519
|
+
CONSTRUCT_TELEMETRY_SECRET_KEY: "__CONSTRUCT_TELEMETRY_SECRET_KEY__",
|
|
520
|
+
},
|
|
521
|
+
requiredEnv: [],
|
|
522
|
+
setupModes: ["auto"],
|
|
523
|
+
hostSupport: {
|
|
524
|
+
claude: { mode: "managed" },
|
|
525
|
+
opencode: { mode: "managed" },
|
|
526
|
+
codex: { mode: "managed" },
|
|
527
|
+
},
|
|
528
|
+
usedBy: ["construct"],
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function managedMcpDefs() {
|
|
533
|
+
const pluginRegistry = loadPluginRegistry({ cwd: root, homeDir: home, rootDir: root, env: process.env });
|
|
534
|
+
const defs = Object.fromEntries(
|
|
535
|
+
(pluginRegistry.mcps ?? []).map((mcp) => [mcp.id, {
|
|
536
|
+
type: mcp.type,
|
|
537
|
+
url: mcp.url,
|
|
538
|
+
command: mcp.command,
|
|
539
|
+
args: mcp.args,
|
|
540
|
+
env: mcp.env,
|
|
541
|
+
headers: mcp.headers,
|
|
542
|
+
hostSupport: mcp.hostSupport,
|
|
543
|
+
category: mcp.category,
|
|
544
|
+
}]),
|
|
545
|
+
);
|
|
546
|
+
defs["construct-mcp"] = constructMcpDefinition();
|
|
547
|
+
return { ...defs, ...(registry.mcpServers ?? {}) };
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function scopedManagedMcpDefs({ projectScope = false } = {}) {
|
|
551
|
+
const defs = managedMcpDefs();
|
|
552
|
+
if (!projectScope) return defs;
|
|
553
|
+
return Object.fromEntries(
|
|
554
|
+
Object.entries(defs).filter(([id]) => PROJECT_DEFAULT_MCP_IDS.has(id)),
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function mergeMissingObjectDefaults(current, defaults) {
|
|
559
|
+
if (Array.isArray(defaults)) {
|
|
560
|
+
return current === undefined ? [...defaults] : current;
|
|
561
|
+
}
|
|
562
|
+
if (!defaults || typeof defaults !== "object") {
|
|
563
|
+
return current === undefined ? defaults : current;
|
|
564
|
+
}
|
|
565
|
+
const next = current && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
|
|
566
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
567
|
+
next[key] = mergeMissingObjectDefaults(next[key], value);
|
|
568
|
+
}
|
|
569
|
+
return next;
|
|
570
|
+
}
|
|
571
|
+
|
|
435
572
|
function extractFallbackChain(tierDef) {
|
|
436
573
|
if (typeof tierDef === "string") return [tierDef];
|
|
437
574
|
if (tierDef && typeof tierDef === "object") {
|
|
@@ -554,7 +691,7 @@ function buildRoleFooter(entry) {
|
|
|
554
691
|
return `\n\n${lines.join("\n")}`;
|
|
555
692
|
}
|
|
556
693
|
|
|
557
|
-
// Fence + handoff data is the source of truth in specialists/
|
|
694
|
+
// Fence + handoff data is the source of truth in specialists/org
|
|
558
695
|
// (events, fence.allowedPaths, fence.allowedBdLabels, fence.approvalRequired,
|
|
559
696
|
// handoffCandidates, outputs.docTypes). Restating that JSON inside each
|
|
560
697
|
// specialist prompt would invite drift across 28 files; the renderer below
|
|
@@ -599,7 +736,7 @@ export function renderRoleFrameworkSection(entry) {
|
|
|
599
736
|
"",
|
|
600
737
|
`Construct may dispatch you in response to ${eventList} events. A bd issue with the event payload exists when dispatched: read it first via \`bd show <id>\`.`,
|
|
601
738
|
"",
|
|
602
|
-
`**Fence** (source of truth: \`specialists/
|
|
739
|
+
`**Fence** (source of truth: \`specialists/org\` → \`${personaName}\`):`,
|
|
603
740
|
`- Allowed paths: ${pathList}`,
|
|
604
741
|
`- Allowed bd labels: ${labelList}`,
|
|
605
742
|
`- Approval required: ${approvalList}`,
|
|
@@ -616,11 +753,21 @@ export function renderRoleFrameworkSection(entry) {
|
|
|
616
753
|
// small local models' tool-use reliability sharply (bead construct-c16l). Shared by the
|
|
617
754
|
// full path and the capability-tiered local path so both stay in sync.
|
|
618
755
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
756
|
+
function orchestrationToolName(platform, toolName) {
|
|
757
|
+
if (platform === "opencode") return `construct-mcp_${toolName}`;
|
|
758
|
+
return toolName;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function orchestrationMicroPrompt(platform) {
|
|
762
|
+
const policyTool = orchestrationToolName(platform, "orchestration_policy");
|
|
763
|
+
const runTool = orchestrationToolName(platform, "orchestration_run");
|
|
764
|
+
return (
|
|
765
|
+
`You are the primary orchestrator. Before any non-trivial answer, call \`${policyTool}\` with the user's \`request\`. Do not guess agent names or workflow types.\n\n` +
|
|
766
|
+
`Example — the user says "add rate limiting to the API". Your first action is a tool call, not prose:\n` +
|
|
767
|
+
` call ${policyTool} { "request": "add rate limiting to the API" }\n` +
|
|
768
|
+
`If the route is focused/orchestrated specialist work, call \`${runTool}\` with the same request. If the route suggests a workflow such as \`research-synthesis\`, pass it as \`workflow_type\`. Do not narrate completed research unless \`${runTool}\` or evidence tools actually ran.`
|
|
769
|
+
);
|
|
770
|
+
}
|
|
624
771
|
|
|
625
772
|
// Directive for the local editor agent (construct-local). It executes bounded work on
|
|
626
773
|
// the cheap local model and hands planning/reasoning back to the construct architect —
|
|
@@ -661,7 +808,7 @@ function enforcePromptWordCap(prompt, entry) {
|
|
|
661
808
|
console.error(
|
|
662
809
|
`[sync] Hard cap exceeded. Options:\n` +
|
|
663
810
|
` - trim the prompt body or move detail to a skill (preferred)\n` +
|
|
664
|
-
` - set "wordCapOverride": <N> on this entry in specialists/
|
|
811
|
+
` - set "wordCapOverride": <N> on this entry in specialists/org with a written reason\n` +
|
|
665
812
|
` - re-run with --force or CONSTRUCT_SYNC_FORCE=1 as a temporary escape hatch\n` +
|
|
666
813
|
`Prompt budget is a hard contract because every over-cap agent degrades every session that dispatches it.`,
|
|
667
814
|
);
|
|
@@ -684,7 +831,7 @@ function buildPrompt(entry, allEntries, platform, { capabilityTier = 'full' } =
|
|
|
684
831
|
if (capabilityTier && capabilityTier !== 'full' && entry.promptFile) {
|
|
685
832
|
let slim = renderPersonaForTier(readPromptBody(entry.promptFile, root), capabilityTier);
|
|
686
833
|
if (entry.injectAgentRoster) {
|
|
687
|
-
slim = `${
|
|
834
|
+
slim = `${orchestrationMicroPrompt(platform)}\n\n${slim}`;
|
|
688
835
|
}
|
|
689
836
|
return enforcePromptWordCap(slim, entry);
|
|
690
837
|
}
|
|
@@ -707,7 +854,7 @@ function buildPrompt(entry, allEntries, platform, { capabilityTier = 'full' } =
|
|
|
707
854
|
// orchestration_policy / orchestration_run — never inject the static roster.
|
|
708
855
|
|
|
709
856
|
if (entry.injectAgentRoster) {
|
|
710
|
-
prompt = `${
|
|
857
|
+
prompt = `${orchestrationMicroPrompt(platform)}\n\n${prompt}`;
|
|
711
858
|
}
|
|
712
859
|
|
|
713
860
|
prompt += buildRoleFooter(entry);
|
|
@@ -811,7 +958,7 @@ function buildEntries() {
|
|
|
811
958
|
// so behavior is unchanged for the default; non-RND profiles emit only the
|
|
812
959
|
// specialists they declare. Profiles whose role list is empty (legacy/test)
|
|
813
960
|
// fall through to no filter so callers don't get a silent empty registry.
|
|
814
|
-
const activeProfile =
|
|
961
|
+
const activeProfile = resolveActiveScope(process.cwd());
|
|
815
962
|
const profileRoles = Array.isArray(activeProfile?.roles) && activeProfile.roles.length > 0
|
|
816
963
|
? new Set(activeProfile.roles)
|
|
817
964
|
: null;
|
|
@@ -920,12 +1067,6 @@ function filterGlobalClaudeHooks(hooksJson) {
|
|
|
920
1067
|
|
|
921
1068
|
function syncGlobalClaudeMcpServers(settings, registryMcp) {
|
|
922
1069
|
settings.mcpServers ??= {};
|
|
923
|
-
for (const id of Object.keys(settings.mcpServers)) {
|
|
924
|
-
if (id in registryMcp && !GLOBAL_CLAUDE_MCP_IDS.has(id)) {
|
|
925
|
-
delete settings.mcpServers[id];
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
1070
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
930
1071
|
if (!GLOBAL_CLAUDE_MCP_IDS.has(id)) continue;
|
|
931
1072
|
const existingEntry = settings.mcpServers[id];
|
|
@@ -979,7 +1120,7 @@ function writeProjectClaudeSettings(targetDir) {
|
|
|
979
1120
|
// Claude Code as the only selected tool without the construct config. Merge the
|
|
980
1121
|
// registry on top of the template seed; existing entries win so user edits stick,
|
|
981
1122
|
// and buildClaudeMcpEntry resolves each server's path/env.
|
|
982
|
-
const registryMcp =
|
|
1123
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: true });
|
|
983
1124
|
existing.mcpServers ??= {};
|
|
984
1125
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
985
1126
|
if (existing.mcpServers[id]) continue;
|
|
@@ -1057,7 +1198,7 @@ ${personaList}
|
|
|
1057
1198
|
settings.hooks = JSON.parse(hookStr);
|
|
1058
1199
|
}
|
|
1059
1200
|
}
|
|
1060
|
-
const registryMcp =
|
|
1201
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: false });
|
|
1061
1202
|
syncGlobalClaudeMcpServers(settings, registryMcp);
|
|
1062
1203
|
if (!DRY_RUN) fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1063
1204
|
}
|
|
@@ -1135,7 +1276,7 @@ function syncCodex(entries, targetDir = null, wants = true) {
|
|
|
1135
1276
|
: getCodexConfigPath(home);
|
|
1136
1277
|
const existing = removeDanglingConstructMcpMarkers(removeDanglingConstructMcpTimeouts(readCodexConfig(configPath)));
|
|
1137
1278
|
const entryNames = writeEntries.map(adapterName);
|
|
1138
|
-
const registryMcp =
|
|
1279
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1139
1280
|
// Seed every supported MCP server (parity with Claude/OpenCode/VS Code/Cursor),
|
|
1140
1281
|
// not just tables already present — otherwise Codex never receives `construct-mcp`
|
|
1141
1282
|
// and the orchestration tool is unreachable there. existingMcpIds still drives
|
|
@@ -1285,7 +1426,7 @@ function getVSCodeUserMcpPaths() {
|
|
|
1285
1426
|
}
|
|
1286
1427
|
|
|
1287
1428
|
function syncVSCode(targetDir = null, wants = true) {
|
|
1288
|
-
const registryMcp =
|
|
1429
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1289
1430
|
if (Object.keys(registryMcp).length === 0) return false;
|
|
1290
1431
|
|
|
1291
1432
|
// Project scope writes a dedicated `.vscode/mcp.json` (VS Code's documented
|
|
@@ -1369,7 +1510,7 @@ function syncVSCode(targetDir = null, wants = true) {
|
|
|
1369
1510
|
// --- Cursor adapter ---
|
|
1370
1511
|
|
|
1371
1512
|
function syncCursor(targetDir = null, wants = true) {
|
|
1372
|
-
const registryMcp =
|
|
1513
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1373
1514
|
if (Object.keys(registryMcp).length === 0) return false;
|
|
1374
1515
|
|
|
1375
1516
|
const cursorDir = targetDir
|
|
@@ -1567,16 +1708,72 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1567
1708
|
|
|
1568
1709
|
const writeEntries = globalEntries(entries);
|
|
1569
1710
|
|
|
1711
|
+
const hadExistingConfig = fs.existsSync(configPath);
|
|
1570
1712
|
const { config } = targetDir
|
|
1571
|
-
? { config:
|
|
1713
|
+
? { config: hadExistingConfig ? JSON.parse(fs.readFileSync(configPath, "utf8")) : {} }
|
|
1572
1714
|
: readOpenCodeConfig();
|
|
1715
|
+
const opencodeTemplatePath = path.join(root, "platforms", "opencode", "config.template.json");
|
|
1716
|
+
const opencodeTemplate = fs.existsSync(opencodeTemplatePath)
|
|
1717
|
+
? JSON.parse(fs.readFileSync(opencodeTemplatePath, "utf8"))
|
|
1718
|
+
: {};
|
|
1573
1719
|
if (!config.agent) config.agent = {};
|
|
1720
|
+
if (!config.mcp) config.mcp = {};
|
|
1574
1721
|
if (!Array.isArray(config.plugin)) config.plugin = [];
|
|
1575
1722
|
config.plugin = config.plugin.filter((entry) => {
|
|
1576
1723
|
if (typeof entry !== "string") return true;
|
|
1577
1724
|
return entry !== managedPluginPath && entry !== toolkitPluginPath;
|
|
1578
1725
|
});
|
|
1579
1726
|
|
|
1727
|
+
if (opencodeTemplate.$schema && !config.$schema) config.$schema = opencodeTemplate.$schema;
|
|
1728
|
+
if (opencodeTemplate.model && !config.model && !config.defaultModel && !hadExistingConfig) {
|
|
1729
|
+
config.model = opencodeTemplate.model;
|
|
1730
|
+
}
|
|
1731
|
+
if (Array.isArray(opencodeTemplate.enabled_providers) && !Array.isArray(config.enabled_providers)) {
|
|
1732
|
+
config.enabled_providers = [...opencodeTemplate.enabled_providers];
|
|
1733
|
+
}
|
|
1734
|
+
if (opencodeTemplate.provider && typeof opencodeTemplate.provider === "object") {
|
|
1735
|
+
config.provider ??= {};
|
|
1736
|
+
for (const [id, providerDef] of Object.entries(opencodeTemplate.provider)) {
|
|
1737
|
+
config.provider[id] = mergeMissingObjectDefaults(config.provider[id], resolveTemplateStrings(providerDef));
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
if (config.provider?.ollama?.options?.headers?.Authorization === "Bearer ollama") {
|
|
1741
|
+
delete config.provider.ollama.options.headers.Authorization;
|
|
1742
|
+
if (Object.keys(config.provider.ollama.options.headers).length === 0) {
|
|
1743
|
+
delete config.provider.ollama.options.headers;
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
const templateMcp = opencodeTemplate.mcp && typeof opencodeTemplate.mcp === "object"
|
|
1748
|
+
? resolveTemplateStrings(opencodeTemplate.mcp)
|
|
1749
|
+
: {};
|
|
1750
|
+
for (const [id, entry] of Object.entries(templateMcp)) {
|
|
1751
|
+
if (!PROJECT_DEFAULT_MCP_IDS.has(id)) continue;
|
|
1752
|
+
if (!config.mcp[id]) config.mcp[id] = entry;
|
|
1753
|
+
}
|
|
1754
|
+
if (config.mcp["construct-mcp"]) {
|
|
1755
|
+
config.mcp["construct-mcp"] = templateMcp["construct-mcp"] ?? config.mcp["construct-mcp"];
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
const memoryBridgeEntry = buildOpenCodeMcpEntry("memory", {
|
|
1759
|
+
command: "node",
|
|
1760
|
+
args: ["__CX_TOOLKIT_DIR__/lib/mcp/memory-bridge.mjs"],
|
|
1761
|
+
env: { CONSTRUCT_MEMORY_BRIDGE_URL: "__CONSTRUCT_MEMORY_BRIDGE_URL__" },
|
|
1762
|
+
}, {
|
|
1763
|
+
...process.env,
|
|
1764
|
+
CONSTRUCT_MEMORY_BRIDGE_URL:
|
|
1765
|
+
config.mcp.memory?.url
|
|
1766
|
+
|| config.mcp.cass?.url
|
|
1767
|
+
|| process.env.CONSTRUCT_MEMORY_BRIDGE_URL
|
|
1768
|
+
|| "http://127.0.0.1:8765/",
|
|
1769
|
+
}).entry;
|
|
1770
|
+
const staleMemoryRemote = config.mcp.memory && (config.mcp.memory.type === "remote" || config.mcp.memory.type === "http");
|
|
1771
|
+
const staleCassRemote = config.mcp.cass && (config.mcp.cass.type === "remote" || config.mcp.cass.type === "http");
|
|
1772
|
+
if (staleMemoryRemote || staleCassRemote) {
|
|
1773
|
+
config.mcp.memory = memoryBridgeEntry;
|
|
1774
|
+
delete config.mcp.cass;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1580
1777
|
// Sync providers
|
|
1581
1778
|
const registryProviders = registry.providers ?? {};
|
|
1582
1779
|
if (Object.keys(registryProviders).length > 0) {
|
|
@@ -1589,8 +1786,10 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1589
1786
|
...providerDef,
|
|
1590
1787
|
options: {
|
|
1591
1788
|
...providerDef.options,
|
|
1789
|
+
...existing.options,
|
|
1592
1790
|
headers: {
|
|
1593
1791
|
...providerDef.options?.headers,
|
|
1792
|
+
...existing.options?.headers,
|
|
1594
1793
|
...(existingAuth ? { Authorization: existingAuth } : {}),
|
|
1595
1794
|
},
|
|
1596
1795
|
},
|
|
@@ -1602,6 +1801,8 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1602
1801
|
}
|
|
1603
1802
|
}
|
|
1604
1803
|
|
|
1804
|
+
ensureOpenRouterProviderAuth(config);
|
|
1805
|
+
|
|
1605
1806
|
// Derive anthropic models from registry tier definitions
|
|
1606
1807
|
const tierModels = Object.values(registry.models ?? {}).flatMap((t) =>
|
|
1607
1808
|
[t.primary, ...(t.fallback ?? [])].filter((m) => m?.startsWith('anthropic/'))
|
|
@@ -1627,7 +1828,7 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1627
1828
|
}
|
|
1628
1829
|
|
|
1629
1830
|
// Sync MCP servers
|
|
1630
|
-
const registryMcp =
|
|
1831
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1631
1832
|
if (Object.keys(registryMcp).length > 0) {
|
|
1632
1833
|
if (!config.mcp) config.mcp = {};
|
|
1633
1834
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
@@ -1656,7 +1857,7 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1656
1857
|
// into EVERY agent's request — github ~30k alone (fixtures 2026-06-22) —
|
|
1657
1858
|
// agent's request — including the built-in Build/Plan agents the per-agent
|
|
1658
1859
|
// permission prune cannot reach. OpenCode 1.15.4 has no per-session tool
|
|
1659
|
-
// filter (chat.params carries no tool list), so disabling the whole server in
|
|
1860
|
+
// filter (OpenCode chat.params carries no tool list), so disabling the whole server in
|
|
1660
1861
|
// opencode.json is the only lever. The decision is INTENT-driven: trim only
|
|
1661
1862
|
// when this config's own default model is local (or a local Ollama provider is
|
|
1662
1863
|
// registered in it), so a cloud session on a machine that merely also has
|
|
@@ -1689,7 +1890,8 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1689
1890
|
for (const key of Object.keys(config.agent)) {
|
|
1690
1891
|
const isManaged = prefixes.some((p) => key.startsWith(p));
|
|
1691
1892
|
const isOrchestrator = registry.orchestrator?.name === key;
|
|
1692
|
-
|
|
1893
|
+
const isStaleOrchestratorAlias = key === 'orchestrator' && registry.orchestrator?.name === 'construct';
|
|
1894
|
+
if ((isManaged || isOrchestrator || isStaleOrchestratorAlias) && !writeEntries.find((e) => adapterName(e) === key)) {
|
|
1693
1895
|
delete config.agent[key];
|
|
1694
1896
|
}
|
|
1695
1897
|
}
|
|
@@ -1780,21 +1982,28 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1780
1982
|
config.construct = config.construct || {};
|
|
1781
1983
|
config.construct.models = { ...resolvedModels };
|
|
1782
1984
|
|
|
1783
|
-
//
|
|
1784
|
-
//
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
//
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1985
|
+
// OpenCode's primary `model` is user-owned. Remove the legacy Construct seed
|
|
1986
|
+
// when we find it so the app can fall back to its own remembered selection
|
|
1987
|
+
// instead of a stale pin. New syncs never write this key back.
|
|
1988
|
+
const legacyPinnedModels = new Set([
|
|
1989
|
+
opencodeTemplate.model,
|
|
1990
|
+
hardDefaults.standard,
|
|
1991
|
+
].filter(Boolean));
|
|
1992
|
+
if (!targetDir && legacyPinnedModels.has(config.model)) {
|
|
1993
|
+
delete config.model;
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// OpenCode's built-in helper agents drive session naming, summaries, and
|
|
1997
|
+
// compaction. Keep them on a stronger auxiliary model so those surfaces do not
|
|
1998
|
+
// inherit the main chat model's selection history or a low-end coder default.
|
|
1999
|
+
const auxiliaryModel = resolvedModels.reasoning || resolvedModels.standard || resolvedModels.fast;
|
|
2000
|
+
if (auxiliaryModel) {
|
|
2001
|
+
for (const key of ["title", "summary", "compaction"]) {
|
|
2002
|
+
config.agent[key] = {
|
|
2003
|
+
...(config.agent[key] && typeof config.agent[key] === "object" ? config.agent[key] : {}),
|
|
2004
|
+
model: auxiliaryModel,
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
1798
2007
|
}
|
|
1799
2008
|
|
|
1800
2009
|
writeOpenCodeConfig(config, configPath);
|
|
@@ -1943,6 +2152,7 @@ function syncSkills(targetDir = null) {
|
|
|
1943
2152
|
|
|
1944
2153
|
// --- Main ---
|
|
1945
2154
|
|
|
2155
|
+
if (isMain) {
|
|
1946
2156
|
const entries = buildEntries();
|
|
1947
2157
|
|
|
1948
2158
|
if (COMPRESS_PERSONAS) {
|
|
@@ -2035,3 +2245,4 @@ try {
|
|
|
2035
2245
|
} finally {
|
|
2036
2246
|
releaseLock();
|
|
2037
2247
|
}
|
|
2248
|
+
}
|