@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
|
@@ -7,14 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
|
+
import { loadRegistry } from '../registry/loader.mjs';
|
|
10
11
|
import path from 'node:path';
|
|
11
12
|
import { createHash } from 'node:crypto';
|
|
12
13
|
import { artifactTypes, loadArtifactManifest } from '../artifact-manifest.mjs';
|
|
14
|
+
import { validateSkillEffectiveness } from '../validators/skill-effectiveness.mjs';
|
|
15
|
+
import { collectScopeRoleIds } from '../scopes/enrich.mjs';
|
|
13
16
|
|
|
14
17
|
function findConstructRoot(startPath = process.cwd()) {
|
|
15
18
|
let current = path.resolve(startPath);
|
|
16
19
|
while (true) {
|
|
17
|
-
if (fs.existsSync(path.join(current, 'specialists', '
|
|
20
|
+
if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
|
|
18
21
|
const parent = path.dirname(current);
|
|
19
22
|
if (parent === current) return path.resolve(startPath);
|
|
20
23
|
current = parent;
|
|
@@ -37,22 +40,18 @@ function collectSkillFiles(skillsDir) {
|
|
|
37
40
|
return results.sort();
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
function
|
|
41
|
-
const dir = path.join(root, '
|
|
43
|
+
function collectScopeRoles(root) {
|
|
44
|
+
const dir = path.join(root, 'specialists', 'org', 'scopes');
|
|
42
45
|
const roles = new Set();
|
|
43
|
-
const scan = (node) => {
|
|
44
|
-
if (Array.isArray(node)) { node.forEach(scan); return; }
|
|
45
|
-
if (node && typeof node === 'object') {
|
|
46
|
-
if (Array.isArray(node.roles)) for (const r of node.roles) if (typeof r === 'string') roles.add(r);
|
|
47
|
-
for (const v of Object.values(node)) scan(v);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
46
|
try {
|
|
51
47
|
for (const f of fs.readdirSync(dir)) {
|
|
52
48
|
if (!f.endsWith('.json')) continue;
|
|
53
|
-
try {
|
|
49
|
+
try {
|
|
50
|
+
const raw = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8'));
|
|
51
|
+
for (const r of collectScopeRoleIds(raw, { rootDir: root })) roles.add(r);
|
|
52
|
+
} catch { /* skip malformed */ }
|
|
54
53
|
}
|
|
55
|
-
} catch { /* no
|
|
54
|
+
} catch { /* no scopes dir */ }
|
|
56
55
|
return roles;
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -96,19 +95,20 @@ function verificationHooks(meta, body) {
|
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
function resolveOwners(skillId, { registry, declaredSkills, ownerBases }) {
|
|
98
|
+
if (skillId.startsWith('brand/')) return ['cx-docs-keeper'];
|
|
99
99
|
const owners = new Set();
|
|
100
|
-
for (const agent of registry.specialists ??
|
|
100
|
+
for (const agent of Object.values(registry.specialists ?? {})) {
|
|
101
101
|
if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
|
|
102
102
|
}
|
|
103
103
|
const base = roleBase(skillId);
|
|
104
104
|
if (base && ownerBases.has(base)) {
|
|
105
|
-
for (const agent of registry.specialists ??
|
|
105
|
+
for (const agent of Object.values(registry.specialists ?? {})) {
|
|
106
106
|
if (agent.name === base || agent.name.replace(/^cx-/, '') === base) owners.add(`cx-${agent.name}`);
|
|
107
107
|
}
|
|
108
|
-
if (!owners.size) owners.add(`
|
|
108
|
+
if (!owners.size) owners.add(`scope-role:${base}`);
|
|
109
109
|
}
|
|
110
110
|
if (declaredSkills.has(skillId) && owners.size === 0) {
|
|
111
|
-
for (const agent of registry.specialists ??
|
|
111
|
+
for (const agent of Object.values(registry.specialists ?? {})) {
|
|
112
112
|
if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -138,10 +138,11 @@ function detectConflictingOutputs(skills) {
|
|
|
138
138
|
for (const [artifactType, entries] of byType) {
|
|
139
139
|
if (entries.length < 2) continue;
|
|
140
140
|
const bars = new Set(entries.map((e) => e.verificationHooks.find((h) => h.kind === 'verificationBar')?.value ?? ''));
|
|
141
|
+
if (bars.size <= 1) continue;
|
|
141
142
|
conflicts.push({
|
|
142
143
|
artifactType,
|
|
143
144
|
skillIds: entries.map((e) => e.id),
|
|
144
|
-
reason:
|
|
145
|
+
reason: 'divergent verificationBar across workflow skills',
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
148
|
return conflicts;
|
|
@@ -154,15 +155,15 @@ export function defaultSkillInventoryPath(rootDir = process.cwd()) {
|
|
|
154
155
|
export function buildSkillInventory({ rootDir } = {}) {
|
|
155
156
|
const root = findConstructRoot(rootDir);
|
|
156
157
|
const skillsDir = path.join(root, 'skills');
|
|
157
|
-
const registry =
|
|
158
|
+
const registry = loadRegistry({ rootDir: root });
|
|
158
159
|
const manifest = loadArtifactManifest({ rootDir: root });
|
|
159
160
|
const declaredSkills = new Set();
|
|
160
|
-
for (const agent of registry.specialists ??
|
|
161
|
+
for (const agent of Object.values(registry.specialists ?? {})) {
|
|
161
162
|
for (const skill of agent.skills ?? []) declaredSkills.add(skill);
|
|
162
163
|
}
|
|
163
164
|
const ownerBases = new Set([
|
|
164
|
-
...(registry.specialists ??
|
|
165
|
-
...
|
|
165
|
+
...Object.values(registry.specialists ?? {}).map((a) => a.name.replace(/^cx-/, '')),
|
|
166
|
+
...collectScopeRoles(root),
|
|
166
167
|
]);
|
|
167
168
|
const workflowIds = workflowSkillIds(manifest);
|
|
168
169
|
|
|
@@ -202,6 +203,14 @@ export function buildSkillInventory({ rootDir } = {}) {
|
|
|
202
203
|
});
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
const effectiveness = validateSkillEffectiveness({ rootDir: root });
|
|
207
|
+
const effectivenessFindings = effectiveness.errors.map((message) => ({
|
|
208
|
+
kind: 'effectiveness',
|
|
209
|
+
severity: 'blocking',
|
|
210
|
+
message,
|
|
211
|
+
}));
|
|
212
|
+
blockingFindings.push(...effectivenessFindings);
|
|
213
|
+
|
|
205
214
|
const payload = {
|
|
206
215
|
version: 1,
|
|
207
216
|
generatedAt: new Date().toISOString(),
|
|
@@ -209,6 +218,7 @@ export function buildSkillInventory({ rootDir } = {}) {
|
|
|
209
218
|
skillCount: skills.length,
|
|
210
219
|
skills,
|
|
211
220
|
blockingFindings,
|
|
221
|
+
effectivenessFindings,
|
|
212
222
|
digest: null,
|
|
213
223
|
};
|
|
214
224
|
const canonical = { ...payload, digest: undefined };
|
|
@@ -238,7 +248,9 @@ export function validateSkillInventory({ rootDir, inventory: supplied, checkFres
|
|
|
238
248
|
}
|
|
239
249
|
|
|
240
250
|
for (const finding of inventory.blockingFindings ?? []) {
|
|
241
|
-
if (finding.severity === 'blocking')
|
|
251
|
+
if (finding.severity === 'blocking') {
|
|
252
|
+
errors.push(`blocking finding: ${finding.kind} ${finding.skillId ?? finding.message ?? finding.artifactType ?? ''}`.trim());
|
|
253
|
+
}
|
|
242
254
|
}
|
|
243
255
|
|
|
244
256
|
if (checkFreshness) {
|
|
@@ -8,16 +8,19 @@
|
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
|
|
11
|
+
import { validateSkillEffectiveness } from '../validators/skill-effectiveness.mjs';
|
|
12
|
+
import { auditSkillComposition } from '../skills/composition-graph.mjs';
|
|
11
13
|
import { defaultSkillInventoryPath } from './skill-inventory.mjs';
|
|
12
14
|
import { defaultScenarioCatalogPath } from './scenarios.mjs';
|
|
13
15
|
|
|
14
|
-
const HIGH_RISK_SKILLS =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'
|
|
20
|
-
]);
|
|
16
|
+
const HIGH_RISK_SKILLS = null;
|
|
17
|
+
|
|
18
|
+
function highRiskSkillIds(root) {
|
|
19
|
+
if (HIGH_RISK_SKILLS) return HIGH_RISK_SKILLS;
|
|
20
|
+
const file = defaultSkillInventoryPath(root);
|
|
21
|
+
const inventory = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
22
|
+
return new Set((inventory.skills ?? []).filter((s) => s.workflowSkill).map((s) => s.id));
|
|
23
|
+
}
|
|
21
24
|
|
|
22
25
|
function findConstructRoot(startPath = process.cwd()) {
|
|
23
26
|
let current = path.resolve(startPath);
|
|
@@ -50,6 +53,8 @@ export function buildPositiveScenario(skill) {
|
|
|
50
53
|
verificationSteps: [
|
|
51
54
|
'skill file exists under skills/',
|
|
52
55
|
'inventory lists owners and workflowSkill=true',
|
|
56
|
+
'effectiveness rubric passes (lint:scopes)',
|
|
57
|
+
'get_skill and specialist refs resolve (composition graph)',
|
|
53
58
|
],
|
|
54
59
|
owners: skill.owners ?? [],
|
|
55
60
|
};
|
|
@@ -80,6 +85,14 @@ export function validateSkillScenarioFixture(fixture, { rootDir } = {}) {
|
|
|
80
85
|
if (fixture.mode === 'positive' && !Array.isArray(fixture.verificationSteps)) {
|
|
81
86
|
errors.push('positive fixture requires verificationSteps');
|
|
82
87
|
}
|
|
88
|
+
if (fixture.mode === 'positive' && fixture.verificationSteps?.includes('effectiveness rubric passes (lint:scopes)')) {
|
|
89
|
+
const eff = validateSkillEffectiveness({ rootDir: root });
|
|
90
|
+
if (!eff.valid) errors.push(`effectiveness: ${eff.errors.find((e) => e.startsWith(fixture.skillId)) ?? eff.errors[0]}`);
|
|
91
|
+
}
|
|
92
|
+
if (fixture.mode === 'positive' && fixture.verificationSteps?.includes('get_skill and specialist refs resolve (composition graph)')) {
|
|
93
|
+
const comp = auditSkillComposition({ rootDir: root });
|
|
94
|
+
if (!comp.pass) errors.push(`composition: ${comp.blocking[0] ?? 'blocking'}`);
|
|
95
|
+
}
|
|
83
96
|
if (fixture.mode === 'negative') {
|
|
84
97
|
if (fixture.expected?.silentSuccess !== false) errors.push('negative fixture must forbid silent success');
|
|
85
98
|
if (!fixture.expected?.errorType) errors.push('negative fixture requires expected.errorType');
|
|
@@ -121,7 +134,7 @@ export function writeSkillScenarioFixtures({ rootDir } = {}) {
|
|
|
121
134
|
model: { provider: 'hermetic', requestedId: 'fixture/skill', resolvedId: 'fixture/skill', tier: 'hermetic' },
|
|
122
135
|
});
|
|
123
136
|
lines.push(`- \`${skill.id}\` — positive: \`${relPositive}\``);
|
|
124
|
-
if (
|
|
137
|
+
if (highRiskSkillIds(root).has(skill.id)) {
|
|
125
138
|
const negative = buildNegativeScenario(skill);
|
|
126
139
|
const negativePath = path.join(dir, 'negative.json');
|
|
127
140
|
fs.writeFileSync(negativePath, `${JSON.stringify(negative, null, 2)}\n`);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from 'node:fs';
|
|
9
|
+
import { loadRegistry } from '../registry/loader.mjs';
|
|
9
10
|
import path from 'node:path';
|
|
10
11
|
|
|
11
12
|
import { validatePromptContent } from '../specialists/prompt-schema.mjs';
|
|
@@ -13,7 +14,7 @@ import { validatePromptContent } from '../specialists/prompt-schema.mjs';
|
|
|
13
14
|
function findConstructRoot(startPath = process.cwd()) {
|
|
14
15
|
let current = path.resolve(startPath);
|
|
15
16
|
while (true) {
|
|
16
|
-
if (fs.existsSync(path.join(current, 'specialists', '
|
|
17
|
+
if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
|
|
17
18
|
const parent = path.dirname(current);
|
|
18
19
|
if (parent === current) return path.resolve(startPath);
|
|
19
20
|
current = parent;
|
|
@@ -73,8 +74,8 @@ export function checkSpecialistContract(agent, { rootDir } = {}) {
|
|
|
73
74
|
|
|
74
75
|
export function auditSpecialistContracts({ rootDir } = {}) {
|
|
75
76
|
const root = findConstructRoot(rootDir);
|
|
76
|
-
const registry =
|
|
77
|
-
const results = (registry.specialists ??
|
|
77
|
+
const registry = loadRegistry({ rootDir: root });
|
|
78
|
+
const results = Object.values(registry.specialists ?? {}).map((agent) => checkSpecialistContract(agent, { rootDir: root }));
|
|
78
79
|
const failures = results.filter((r) => !r.pass);
|
|
79
80
|
return {
|
|
80
81
|
pass: failures.length === 0,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
|
+
import { loadRegistry } from '../registry/loader.mjs';
|
|
10
11
|
import path from 'node:path';
|
|
11
12
|
|
|
12
13
|
import { roleCardsDir } from './role-cards.mjs';
|
|
@@ -16,7 +17,7 @@ import { defaultScenarioCatalogPath } from './scenarios.mjs';
|
|
|
16
17
|
function findConstructRoot(startPath = process.cwd()) {
|
|
17
18
|
let current = path.resolve(startPath);
|
|
18
19
|
while (true) {
|
|
19
|
-
if (fs.existsSync(path.join(current, 'specialists', '
|
|
20
|
+
if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
|
|
20
21
|
const parent = path.dirname(current);
|
|
21
22
|
if (parent === current) return path.resolve(startPath);
|
|
22
23
|
current = parent;
|
|
@@ -75,8 +76,8 @@ export function validateSpecialistScenarioFixture(fixture, { rootDir } = {}) {
|
|
|
75
76
|
if (!fixture?.capabilityId) errors.push('capabilityId required');
|
|
76
77
|
if (!['normal', 'adversarial'].includes(fixture.mode)) errors.push('mode must be normal or adversarial');
|
|
77
78
|
|
|
78
|
-
const registry =
|
|
79
|
-
const agent = (registry.specialists ??
|
|
79
|
+
const registry = loadRegistry({ rootDir: root });
|
|
80
|
+
const agent = Object.values(registry.specialists ?? {}).find((entry) => `cx-${entry.name}` === fixture.specialistId);
|
|
80
81
|
if (!agent) errors.push(`unknown specialist: ${fixture.specialistId}`);
|
|
81
82
|
|
|
82
83
|
const cardPath = path.join(roleCardsDir(root), `${fixture.specialistId}.role-card.json`);
|
|
@@ -110,7 +111,7 @@ export function validateSpecialistScenarioFixture(fixture, { rootDir } = {}) {
|
|
|
110
111
|
|
|
111
112
|
export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
|
|
112
113
|
const root = findConstructRoot(rootDir);
|
|
113
|
-
const registry =
|
|
114
|
+
const registry = loadRegistry({ rootDir: root });
|
|
114
115
|
const readme = path.join(root, 'tests', 'certification', 'scenarios', 'specialists', 'README.md');
|
|
115
116
|
fs.mkdirSync(path.dirname(readme), { recursive: true });
|
|
116
117
|
const lines = [
|
|
@@ -127,7 +128,7 @@ export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
|
|
|
127
128
|
];
|
|
128
129
|
const catalogEntries = [];
|
|
129
130
|
|
|
130
|
-
for (const agent of registry.specialists ??
|
|
131
|
+
for (const agent of Object.values(registry.specialists ?? {})) {
|
|
131
132
|
const specialistId = `cx-${agent.name}`;
|
|
132
133
|
const cardPath = path.join(roleCardsDir(root), `${specialistId}.role-card.json`);
|
|
133
134
|
if (!fs.existsSync(cardPath)) continue;
|
|
@@ -171,5 +172,5 @@ export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
|
|
|
171
172
|
&& !String(s.id).startsWith('specialist.adversarial.'));
|
|
172
173
|
catalog.scenarios = [...keep, ...catalogEntries];
|
|
173
174
|
fs.writeFileSync(catalogPath, `${JSON.stringify(catalog, null, 2)}\n`);
|
|
174
|
-
return { specialistCount: (registry.specialists ??
|
|
175
|
+
return { specialistCount: Object.values(registry.specialists ?? {}).length, catalogEntries: catalogEntries.length, readme };
|
|
175
176
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from 'node:fs';
|
|
9
|
+
import { loadRegistry } from '../registry/loader.mjs';
|
|
9
10
|
import path from 'node:path';
|
|
10
11
|
|
|
11
12
|
import { loadCapabilityLedger } from '../capability-ledger.mjs';
|
|
@@ -28,13 +29,13 @@ function findConstructRoot(startPath = process.cwd()) {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
function readRegistry(rootDir) {
|
|
31
|
-
const
|
|
32
|
-
if (!fs.existsSync(
|
|
33
|
-
return
|
|
32
|
+
const dir = path.join(rootDir, 'specialists', 'org');
|
|
33
|
+
if (!fs.existsSync(dir)) return { specialists: [] };
|
|
34
|
+
return loadRegistry({ rootDir });
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
function listSpecialists(registry) {
|
|
37
|
-
return registry.specialists ??
|
|
38
|
+
return Object.values(registry.specialists ?? {});
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function normalizeStatus({ verdict = null, stale = false, neverRun = true }) {
|
package/lib/cli-commands.mjs
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Consumed by:
|
|
5
5
|
* - bin/construct (usage text + emoji output)
|
|
6
6
|
* - lib/completions.mjs (bash + zsh completion generation)
|
|
7
|
-
* - lib/server/index.mjs (/api/status → dashboard)
|
|
8
7
|
*
|
|
9
8
|
* Command Visibility:
|
|
10
9
|
* - core: true → shown in default --help (90% of users)
|
|
@@ -13,6 +12,8 @@
|
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
14
|
import { resolveColors } from './term-format.mjs';
|
|
15
|
+
import { resolveUiColors } from './ui/theme.mjs';
|
|
16
|
+
import { formatPathLink, terminalLinksEnabled } from './ui/links.mjs';
|
|
16
17
|
import { surfaceForCommand } from './registry/surface-map.mjs';
|
|
17
18
|
|
|
18
19
|
export const CLI_COMMANDS = [
|
|
@@ -23,26 +24,14 @@ export const CLI_COMMANDS = [
|
|
|
23
24
|
category: 'Core',
|
|
24
25
|
core: true,
|
|
25
26
|
description: 'Start services for development',
|
|
26
|
-
usage: 'construct dev [--select] [--only=postgres
|
|
27
|
+
usage: 'construct dev [--select] [--only=postgres,...]',
|
|
27
28
|
examples: [
|
|
28
29
|
{ cmd: 'construct dev', desc: 'Start the default service set' },
|
|
29
|
-
{ cmd: 'construct dev --only=
|
|
30
|
+
{ cmd: 'construct dev --only=postgres', desc: 'Start just Postgres' },
|
|
30
31
|
],
|
|
31
32
|
options: [
|
|
32
33
|
{ flag: '--select', desc: 'Pick which services to start from an interactive checklist' },
|
|
33
|
-
{ flag: '--only=<a,b,c>', desc: 'Start only the named services (postgres,
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: 'dashboard',
|
|
38
|
-
emoji: '📊',
|
|
39
|
-
category: 'Core',
|
|
40
|
-
core: true,
|
|
41
|
-
description: 'Start the local dashboard/orchestration daemon (or --token to mint a dashboard token)',
|
|
42
|
-
usage: 'construct dashboard [--token]',
|
|
43
|
-
examples: [
|
|
44
|
-
{ cmd: 'construct dashboard', desc: 'Launch the local dashboard daemon' },
|
|
45
|
-
{ cmd: 'construct dashboard --token', desc: 'Mint a dashboard access token' },
|
|
34
|
+
{ flag: '--only=<a,b,c>', desc: 'Start only the named services (postgres, telemetry, memory, opencode)' },
|
|
46
35
|
],
|
|
47
36
|
},
|
|
48
37
|
{
|
|
@@ -230,24 +219,24 @@ export const CLI_COMMANDS = [
|
|
|
230
219
|
],
|
|
231
220
|
},
|
|
232
221
|
{
|
|
233
|
-
name: '
|
|
222
|
+
name: 'scope',
|
|
234
223
|
emoji: '🧭',
|
|
235
224
|
category: 'Core',
|
|
236
225
|
core: true,
|
|
237
|
-
description: 'Manage the active org
|
|
238
|
-
usage: 'construct
|
|
226
|
+
description: 'Manage the active org scope and its lifecycle (draft, promote, archive, health)',
|
|
227
|
+
usage: 'construct scope show|list|set|create|drafts|archive|health',
|
|
239
228
|
examples: [
|
|
240
|
-
{ cmd: 'construct
|
|
241
|
-
{ cmd: 'construct
|
|
229
|
+
{ cmd: 'construct scope list', desc: 'List curated scopes' },
|
|
230
|
+
{ cmd: 'construct scope set <id>', desc: 'Switch the active scope' },
|
|
242
231
|
],
|
|
243
232
|
subcommands: [
|
|
244
|
-
{ name: 'show', desc: 'Show the active
|
|
245
|
-
{ name: 'list', desc: 'List curated
|
|
246
|
-
{ name: 'set <id>', desc: 'Switch the active
|
|
247
|
-
{ name: 'create <id> [--display=…] [--role=…] [--department=…] [--yes|--dry-run]', desc: 'Scaffold a draft
|
|
248
|
-
{ name: 'drafts', desc: 'List in-progress draft
|
|
249
|
-
{ name: 'archive <id> --reason="..."', desc: 'Move a curated
|
|
250
|
-
{ name: 'health <id> [--days=N]', desc: 'Per-
|
|
233
|
+
{ name: 'show', desc: 'Show the active scope' },
|
|
234
|
+
{ name: 'list', desc: 'List curated scopes' },
|
|
235
|
+
{ name: 'set <id>', desc: 'Switch the active scope (writes construct.config.json)' },
|
|
236
|
+
{ name: 'create <id> [--display=…] [--role=…] [--department=…] [--yes|--dry-run]', desc: 'Scaffold a draft scope; previews and confirms by default, prompts interactively when no flags' },
|
|
237
|
+
{ name: 'drafts', desc: 'List in-progress draft scopes' },
|
|
238
|
+
{ name: 'archive <id> --reason="..."', desc: 'Move a curated scope into archive/scopes/<id>/' },
|
|
239
|
+
{ name: 'health <id> [--days=N]', desc: 'Per-scope observation + outcome rollup' },
|
|
251
240
|
],
|
|
252
241
|
},
|
|
253
242
|
{
|
|
@@ -354,7 +343,7 @@ export const CLI_COMMANDS = [
|
|
|
354
343
|
{ flag: '--output=<path>', desc: 'Output path (default: .cx/publish/<name>.<format>)' },
|
|
355
344
|
{ flag: '--type=<doc-type>', desc: 'Manifest doc type for release gate (inferred when omitted)' },
|
|
356
345
|
{ flag: '--demo=<name>', desc: 'Terminal VHS tape to record (repeatable)' },
|
|
357
|
-
{ flag: '--
|
|
346
|
+
{ flag: '--recording=<name>', desc: 'Playwright recording manifest (repeatable)' },
|
|
358
347
|
{ flag: '--figures', desc: 'Render d2/mermaid via diagram filter (default on)' },
|
|
359
348
|
{ flag: '--no-figures', desc: 'Skip diagram filter' },
|
|
360
349
|
{ flag: '--no-gate', desc: 'Skip artifact release gate (escape hatch only)' },
|
|
@@ -377,7 +366,6 @@ export const CLI_COMMANDS = [
|
|
|
377
366
|
{ flag: '--figures', desc: 'Include figure tooling (default on)' },
|
|
378
367
|
{ flag: '--no-figures', desc: 'Skip figure binaries' },
|
|
379
368
|
{ flag: '--demo=<name>', desc: 'Include terminal demo recorder check' },
|
|
380
|
-
{ flag: '--dashboard-demo=<name>', desc: 'Include dashboard Playwright check' },
|
|
381
369
|
],
|
|
382
370
|
},
|
|
383
371
|
{
|
|
@@ -429,14 +417,12 @@ export const CLI_COMMANDS = [
|
|
|
429
417
|
category: 'Models & Integrations',
|
|
430
418
|
core: false,
|
|
431
419
|
description: 'Show or update model tier assignments',
|
|
432
|
-
usage: 'construct models <list|set|free|reset|
|
|
420
|
+
usage: 'construct models <list|set|free|reset|resolve>',
|
|
433
421
|
subcommands: [
|
|
434
422
|
{ name: 'list', desc: 'Show current tier assignments' },
|
|
435
423
|
{ name: 'set --tier=<reasoning|standard|fast> --model=<model>', desc: 'Set a model for a tier' },
|
|
436
424
|
{ name: 'free', desc: 'List available free models' },
|
|
437
425
|
{ name: 'reset', desc: 'Reset all tier assignments' },
|
|
438
|
-
{ name: 'usage', desc: 'Show token usage per tier' },
|
|
439
|
-
{ name: 'cost', desc: 'Show cost breakdown' },
|
|
440
426
|
{ name: 'resolve --json', desc: 'Resolve the model for an embedded workflow given host context' },
|
|
441
427
|
],
|
|
442
428
|
},
|
|
@@ -482,14 +468,6 @@ export const CLI_COMMANDS = [
|
|
|
482
468
|
description: 'Run Construct as an Agent Client Protocol (ACP) server over stdio for Zed/JetBrains/VS Code ACP clients',
|
|
483
469
|
usage: 'construct acp',
|
|
484
470
|
},
|
|
485
|
-
{
|
|
486
|
-
name: 'chat',
|
|
487
|
-
emoji: '💬',
|
|
488
|
-
category: 'Models & Integrations',
|
|
489
|
-
core: false,
|
|
490
|
-
description: "Interactive terminal chat on Construct's owned agent loop, with a multi-pane transparency surface (live token/cost/context usage, reasoning, tool timeline, and the planned specialist route); switch models, change settings, and see a token/cost breakdown in-session. Use --accessible or --plain for the linear, screen-reader-friendly renderer",
|
|
491
|
-
usage: 'construct chat [--model <id>] [--free] [--web] [--list] [--resume[=file]] [--ascii] [--plain] [--accessible] [--no-thinking] [--no-path] [--no-specialists] [--no-tools] [--no-observability] [--quiet]',
|
|
492
|
-
},
|
|
493
471
|
{
|
|
494
472
|
name: 'mcp',
|
|
495
473
|
emoji: '🔌',
|
|
@@ -596,7 +574,7 @@ export const CLI_COMMANDS = [
|
|
|
596
574
|
emoji: '🔁',
|
|
597
575
|
category: 'Observability',
|
|
598
576
|
core: false,
|
|
599
|
-
surface: '
|
|
577
|
+
surface: 'thin-cli',
|
|
600
578
|
description: 'Governed improvement loop — review, approve, and record apply/rollback for proposals',
|
|
601
579
|
usage: 'construct improvement submit|review|pending|show|approve|apply|rollback|list',
|
|
602
580
|
},
|
|
@@ -621,8 +599,14 @@ export const CLI_COMMANDS = [
|
|
|
621
599
|
emoji: '👥',
|
|
622
600
|
category: 'Work',
|
|
623
601
|
core: false,
|
|
624
|
-
description: 'Team review and template listing',
|
|
625
|
-
usage: 'construct team <list|review>',
|
|
602
|
+
description: 'Team review and template listing (`team:add` / `team:remove` are internal registry editors)',
|
|
603
|
+
usage: 'construct team <list|show|review|templates>',
|
|
604
|
+
subcommands: [
|
|
605
|
+
{ name: 'list', desc: 'List macro groups and squads (--kind group|squad)' },
|
|
606
|
+
{ name: 'show', desc: 'Show one group or squad by id' },
|
|
607
|
+
{ name: 'review', desc: 'Team review workflow' },
|
|
608
|
+
{ name: 'templates', desc: 'List team doc templates' },
|
|
609
|
+
],
|
|
626
610
|
},
|
|
627
611
|
{
|
|
628
612
|
name: 'audit',
|
|
@@ -688,7 +672,7 @@ export const CLI_COMMANDS = [
|
|
|
688
672
|
emoji: '🪞',
|
|
689
673
|
category: 'Work',
|
|
690
674
|
core: false,
|
|
691
|
-
description: 'Capture improvement feedback
|
|
675
|
+
description: 'Capture improvement feedback and update Construct core',
|
|
692
676
|
usage: 'construct reflect',
|
|
693
677
|
},
|
|
694
678
|
{
|
|
@@ -736,18 +720,17 @@ export const CLI_COMMANDS = [
|
|
|
736
720
|
emoji: '🎬',
|
|
737
721
|
category: 'Work',
|
|
738
722
|
core: false,
|
|
739
|
-
description: 'Run guided
|
|
740
|
-
usage: 'construct demo <list|init|record|name> [--surface=
|
|
723
|
+
description: 'Run guided tours or record VHS/asciinema tapes',
|
|
724
|
+
usage: 'construct demo <list|init|record|tour|name> [--surface=tape|playwright] [--format=gif|mp4|webm] [--out=<path>] [--source-only]',
|
|
741
725
|
strictFlags: true,
|
|
742
726
|
options: [
|
|
743
|
-
{ flag: '--surface=<s>', desc: '
|
|
744
|
-
{ flag: '--
|
|
745
|
-
{ flag: '--
|
|
746
|
-
{ flag: '--plain', desc: 'Linear chat renderer (accessibility / non-TTY)' },
|
|
747
|
-
{ flag: '--free', desc: 'OpenRouter free-router mode for chat demo' },
|
|
727
|
+
{ flag: '--surface=<s>', desc: 'tape (default) | playwright' },
|
|
728
|
+
{ flag: '--accessible', desc: 'Screen-reader-friendly linear tour renderer' },
|
|
729
|
+
{ flag: '--skip-input', desc: 'Tour: auto-advance without waiting for Enter (headless/CI)' },
|
|
748
730
|
{ flag: '--format=<f>', desc: 'gif (default) | mp4 | webm (tape surface only)' },
|
|
749
731
|
{ flag: '--out=<path>', desc: 'Output path (tape recording)' },
|
|
750
732
|
{ flag: '--from=<t>', desc: 'Template for init: quickstart | diagram' },
|
|
733
|
+
{ flag: '--from-project', desc: 'init: scaffold a project demo plug-in under .cx/demos/' },
|
|
751
734
|
{ flag: '--source-only', desc: 'Tape: write .tape only; skip recording' },
|
|
752
735
|
],
|
|
753
736
|
},
|
|
@@ -890,7 +873,13 @@ export const CLI_COMMANDS = [
|
|
|
890
873
|
category: 'Advanced',
|
|
891
874
|
core: false,
|
|
892
875
|
description: 'Skill relevance detection',
|
|
893
|
-
usage: 'construct skills scope|apply',
|
|
876
|
+
usage: 'construct skills <scope|apply|suggest|routing>',
|
|
877
|
+
subcommands: [
|
|
878
|
+
{ name: 'scope', desc: 'Show skill scope for the active profile' },
|
|
879
|
+
{ name: 'apply', desc: 'Apply skill profile to host config' },
|
|
880
|
+
{ name: 'suggest', desc: 'Rank skills for an intent string' },
|
|
881
|
+
{ name: 'routing', desc: 'Dump machine-readable routing table' },
|
|
882
|
+
],
|
|
894
883
|
},
|
|
895
884
|
{
|
|
896
885
|
name: 'hooks:health',
|
|
@@ -1135,7 +1124,6 @@ export const CLI_COMMANDS = [
|
|
|
1135
1124
|
{ name: 'hook', category: 'Internal', core: false, internal: true, description: 'Hook dispatch — invoked by the harness, not by users', usage: 'construct hook <event>' },
|
|
1136
1125
|
{ name: 'seed-traces', category: 'Internal', core: false, internal: true, description: 'Dev fixture: seed traces for testing', usage: 'construct seed-traces' },
|
|
1137
1126
|
{ name: 'migrate', category: 'Internal', core: false, internal: true, description: 'Internal: run pending storage migrations', usage: 'construct migrate' },
|
|
1138
|
-
{ name: 'dashboard:sync', category: 'Internal', core: false, internal: true, description: 'Internal: refresh dashboard state from the registry', usage: 'construct dashboard:sync' },
|
|
1139
1127
|
{ name: 'init:update', category: 'Internal', core: false, internal: true, description: 'Internal: re-run init scaffolding for an existing project', usage: 'construct init:update' },
|
|
1140
1128
|
{ name: 'lint:agents', category: 'Internal', core: false, internal: true, description: 'Internal lint: agent definitions', usage: 'construct lint:agents' },
|
|
1141
1129
|
{ name: 'lint:comments', category: 'Internal', core: false, internal: true, description: 'Internal lint: source comments', usage: 'construct lint:comments' },
|
|
@@ -1145,8 +1133,17 @@ export const CLI_COMMANDS = [
|
|
|
1145
1133
|
{ name: 'lint:prompts', category: 'Internal', core: false, internal: true, description: 'Internal lint: specialist prompt frontmatter + sections', usage: 'construct lint:prompts' },
|
|
1146
1134
|
{ name: 'specialist', category: 'Internal', core: false, internal: true, description: 'Maintainer tool: scaffold, edit, and lint specialist prompts', usage: 'construct specialist <create|edit|lint>' },
|
|
1147
1135
|
{ name: 'registry:status', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Dev: capability registry inspector', usage: 'construct registry:status [--json]' },
|
|
1148
|
-
{ name: 'registry:validate', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Validate registry/capabilities.json against repo reality', usage: 'construct registry:validate [--json]'
|
|
1136
|
+
{ name: 'registry:validate', category: 'Internal', core: false, internal: true, surface: 'internal', strictFlags: true, description: 'Validate registry/capabilities.json against repo reality; --unified validates specialists/org (+ .cx overlay) invariants', usage: 'construct registry:validate [--json] [--unified]', options: [
|
|
1137
|
+
{ flag: '--json', desc: 'Emit the validation report as JSON' },
|
|
1138
|
+
{ flag: '--unified', desc: 'Validate the unified registry (specialists/org + optional .cx overlay) against its 13 invariants instead of the capability registry' },
|
|
1139
|
+
] },
|
|
1149
1140
|
{ name: 'registry:generate-docs', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Generate docs/guides/reference/capabilities.md from registry', usage: 'construct registry:generate-docs' },
|
|
1141
|
+
{ name: 'registry:diff', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Show unified registry changes vs. last commit', usage: 'construct registry:diff [--json]' },
|
|
1142
|
+
{ name: 'registry:prune', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'List orphaned specialist prompts and skills', usage: 'construct registry:prune [--json]' },
|
|
1143
|
+
{ name: 'team:add', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Add a new team to the unified registry', usage: 'construct team:add <team-id>' },
|
|
1144
|
+
{ name: 'team:remove', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Remove a team from the unified registry', usage: 'construct team:remove <team-id> [--force]' },
|
|
1145
|
+
{ name: 'specialist:add', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Add a new specialist to a team', usage: 'construct specialist:add <specialist-id> --team <team-id>' },
|
|
1146
|
+
{ name: 'specialist:remove', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Remove a specialist from the unified registry', usage: 'construct specialist:remove <specialist-id> [--force]' },
|
|
1150
1147
|
{ name: 'oracle', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Oracle meta-controller — fleet health review and bounded-auto maintenance', usage: 'construct oracle start|status|review|pending|approve|gaps|reconcile' },
|
|
1151
1148
|
{ name: 'matrix', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Living dependency matrix — build/inspect the typed file↔capability↔workflow↔test graph', usage: 'construct matrix build|stat|query <node-id> [--json]' },
|
|
1152
1149
|
{ name: 'impact', category: 'Diagnostics', core: false, internal: false, surface: 'thin-cli', description: 'Change-impact analysis — map changed files to affected tests, capabilities, and workflows', usage: 'construct impact [files…] [--stdin] [--run] [--json]' },
|
|
@@ -1222,7 +1219,8 @@ export function getCommandSpec(name) {
|
|
|
1222
1219
|
// every command. Internal commands fall back to a minimal block.
|
|
1223
1220
|
|
|
1224
1221
|
export function formatCommandHelp(name, { colors = false } = {}) {
|
|
1225
|
-
const c =
|
|
1222
|
+
const c = resolveUiColors({ enabled: colors });
|
|
1223
|
+
const linksOn = terminalLinksEnabled(process.env);
|
|
1226
1224
|
const spec = getCommandSpec(name);
|
|
1227
1225
|
if (!spec) {
|
|
1228
1226
|
return `Unknown command: ${name}\n\nRun 'construct --help' for available commands.\n`;
|
|
@@ -1271,7 +1269,8 @@ export function formatCommandHelp(name, { colors = false } = {}) {
|
|
|
1271
1269
|
lines.push(`${c.dim}Next:${c.reset} ${next}`);
|
|
1272
1270
|
lines.push('');
|
|
1273
1271
|
}
|
|
1274
|
-
|
|
1272
|
+
const cliDocs = formatPathLink('docs/guides/reference/cli/', c, { enabled: linksOn });
|
|
1273
|
+
lines.push(`${c.dim}See also:${c.reset} run \`construct --help\` for all commands; full reference in ${cliDocs}.`);
|
|
1275
1274
|
lines.push('');
|
|
1276
1275
|
return lines.join('\n');
|
|
1277
1276
|
}
|
package/lib/comment-lint.mjs
CHANGED
|
@@ -93,10 +93,6 @@ function requiresHeader(rel) {
|
|
|
93
93
|
if (['.yaml', '.yml', '.json', '.jsonl', '.toml', '.txt'].includes(ext)) return { required: false, type: null };
|
|
94
94
|
const jsMatch = JS_HEADER_GLOBS.some(r => r.test(rel));
|
|
95
95
|
const mdMatch = MD_HEADER_GLOBS.some(r => r.test(rel));
|
|
96
|
-
// Exclude static assets under lib/server/static from requiring headers
|
|
97
|
-
if (rel.startsWith('lib/server/static/')) {
|
|
98
|
-
return { required: false, type: null };
|
|
99
|
-
}
|
|
100
96
|
// Exclude test fixture data files — these are project artifacts, not source files.
|
|
101
97
|
if (rel.startsWith('tests/fixtures/projects/')
|
|
102
98
|
|| rel.startsWith('tests/fixtures/artifacts/')
|
|
@@ -324,7 +320,7 @@ function checkArtifactBanned(content, rel) {
|
|
|
324
320
|
|
|
325
321
|
// Internal specialist role ids (cx-business-strategist, cx-product-manager, …) are
|
|
326
322
|
// implementation detail; in a consuming project's deliverable they read as a tool-identity
|
|
327
|
-
// leak. The set is anchored to the real role ids from specialists/
|
|
323
|
+
// leak. The set is anchored to the real role ids from specialists/org — an
|
|
328
324
|
// open-ended /cx-[a-z-]+/ also matches unrelated npm packages (cx-ray, cx-pro, cx-widget)
|
|
329
325
|
// and would fail the release gate on legitimate user content. Drift from the registry is
|
|
330
326
|
// caught by tests/tool-invisibility.test.mjs, not at runtime: this module sits on the hook
|
package/lib/completions.mjs
CHANGED
|
@@ -31,6 +31,7 @@ function subcommandDesc(subcommand) {
|
|
|
31
31
|
|
|
32
32
|
function buildBash() {
|
|
33
33
|
const names = CLI_COMMANDS.map(c => c.name).join(' ');
|
|
34
|
+
const globalFlags = '--help -h --all -a --version -V';
|
|
34
35
|
|
|
35
36
|
const subcommandCases = CLI_COMMANDS
|
|
36
37
|
.filter(c => c.subcommands?.length)
|
|
@@ -68,15 +69,28 @@ _construct_completions() {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
local commands="${names}"
|
|
72
|
+
local global_flags="${globalFlags}"
|
|
71
73
|
|
|
72
|
-
# First argument:
|
|
74
|
+
# First argument: subcommand names or global flags
|
|
73
75
|
if [[ $cword -eq 1 ]]; then
|
|
74
|
-
|
|
76
|
+
if [[ "$cur" == -* ]]; then
|
|
77
|
+
COMPREPLY=($(compgen -W "$global_flags" -- "$cur"))
|
|
78
|
+
else
|
|
79
|
+
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
|
80
|
+
fi
|
|
75
81
|
return 0
|
|
76
82
|
fi
|
|
77
83
|
|
|
78
84
|
local cmd="\${words[1]}"
|
|
79
85
|
|
|
86
|
+
# Global flag continuation
|
|
87
|
+
if [[ "$cmd" == -* ]]; then
|
|
88
|
+
if [[ "$cur" == -* ]]; then
|
|
89
|
+
COMPREPLY=($(compgen -W "$global_flags" -- "$cur"))
|
|
90
|
+
return 0
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
80
94
|
# Subcommands
|
|
81
95
|
if [[ $cword -eq 2 ]]; then
|
|
82
96
|
case "$cmd" in
|
|
@@ -100,6 +114,9 @@ complete -F _construct_completions construct
|
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
function buildZsh() {
|
|
117
|
+
const globalFlagDescriptions = ['--help', '-h', '--all', '-a', '--version', '-V']
|
|
118
|
+
.map((f) => ` '${f}:global flag' \\`)
|
|
119
|
+
.join('\n');
|
|
103
120
|
const commandDescriptions = CLI_COMMANDS
|
|
104
121
|
.map(c => ` '${c.name}:${c.emoji || ''} ${(c.description || '').replace(/'/g, "\\'")}' \\`)
|
|
105
122
|
.join('\n');
|
|
@@ -140,6 +157,7 @@ ${subcommandFunctions}
|
|
|
140
157
|
_construct_commands() {
|
|
141
158
|
local commands
|
|
142
159
|
commands=(
|
|
160
|
+
${globalFlagDescriptions}
|
|
143
161
|
${commandDescriptions}
|
|
144
162
|
)
|
|
145
163
|
_describe -t commands 'construct command' commands
|