@geraldmaron/construct 1.1.1 → 1.2.1
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 +30 -19
- package/bin/construct +487 -87
- package/bin/construct-postinstall.mjs +30 -2
- package/examples/distribution/README.md +42 -0
- package/examples/distribution/manifest.json +53 -0
- package/examples/distribution/sources/adr.md +84 -0
- package/examples/distribution/sources/deck-one-pager.md +65 -0
- package/examples/distribution/sources/prd-platform.md +161 -0
- package/examples/distribution/sources/research-brief.md +80 -0
- package/examples/distribution/sources/rfc-platform.md +82 -0
- package/examples/distribution/sources/runbook.md +103 -0
- package/examples/distribution/sources/strategy.md +88 -0
- package/lib/adapters-sync.mjs +67 -0
- package/lib/artifact-gate-notice.mjs +38 -0
- package/lib/artifact-manifest.mjs +258 -0
- package/lib/artifact-release-gate.mjs +171 -0
- package/lib/artifact-reviewers.mjs +68 -0
- package/lib/artifact-type-from-path.mjs +79 -0
- package/lib/artifact-workflow.mjs +252 -0
- package/lib/audit-skills.mjs +4 -0
- package/lib/audit-specialists.mjs +285 -0
- package/lib/audit-trail.mjs +1 -1
- package/lib/auto-docs.mjs +90 -19
- package/lib/beads/drift.mjs +27 -6
- package/lib/beads-client.mjs +49 -121
- package/lib/beads-optimistic.mjs +5 -12
- package/lib/brand-fonts.mjs +93 -0
- package/lib/brand-prose.mjs +214 -0
- package/lib/brand-tokens.mjs +92 -0
- package/lib/bridges/copilot-proxy.mjs +13 -26
- package/lib/capability-ledger.mjs +156 -0
- package/lib/certification/artifact-fixtures.mjs +132 -0
- package/lib/certification/artifact-gates.mjs +63 -0
- package/lib/certification/artifact-provenance.mjs +97 -0
- package/lib/certification/canonical-scenarios.mjs +78 -0
- package/lib/certification/cli.mjs +191 -0
- package/lib/certification/dashboard-api.mjs +71 -0
- package/lib/certification/demo-parity.mjs +116 -0
- package/lib/certification/document-io-fixtures.mjs +246 -0
- package/lib/certification/document-workflow.mjs +97 -0
- package/lib/certification/eval-bridge.mjs +77 -0
- package/lib/certification/model-routing.mjs +149 -0
- package/lib/certification/prompt-budget.mjs +119 -0
- package/lib/certification/rc-gate.mjs +206 -0
- package/lib/certification/real-llm-scenarios.mjs +303 -0
- package/lib/certification/role-cards.mjs +113 -0
- package/lib/certification/role-overlays.mjs +117 -0
- package/lib/certification/run.mjs +122 -0
- package/lib/certification/runner.mjs +323 -0
- package/lib/certification/scenarios.mjs +51 -0
- package/lib/certification/skill-inventory.mjs +289 -0
- package/lib/certification/skill-scenarios.mjs +147 -0
- package/lib/certification/specialist-contracts.mjs +85 -0
- package/lib/certification/specialist-scenarios.mjs +175 -0
- package/lib/certification/stale-impact.mjs +146 -0
- package/lib/certification/status.mjs +252 -0
- package/lib/certification/store.mjs +77 -0
- package/lib/chat/cli.mjs +333 -0
- package/lib/chat/command-suggest.mjs +161 -0
- package/lib/chat/commands.mjs +215 -0
- package/lib/chat/config.mjs +142 -0
- package/lib/chat/context-compactor.mjs +250 -0
- package/lib/chat/context-continuation.mjs +253 -0
- package/lib/chat/continuation-source.mjs +58 -0
- package/lib/chat/demo-guide.mjs +61 -0
- package/lib/chat/design-tokens.mjs +91 -0
- package/lib/chat/desktop-binary.mjs +79 -0
- package/lib/chat/desktop-build.mjs +130 -0
- package/lib/chat/desktop-launcher.mjs +133 -0
- package/lib/chat/evidence.mjs +145 -0
- package/lib/chat/export.mjs +74 -0
- package/lib/chat/harness/driver.mjs +91 -0
- package/lib/chat/list-picker.mjs +112 -0
- package/lib/chat/model-picker.mjs +356 -0
- package/lib/chat/openrouter-fallback.mjs +151 -0
- package/lib/chat/permission-prompt.mjs +33 -0
- package/lib/chat/picker-catalog.mjs +45 -0
- package/lib/chat/policy-telemetry.mjs +34 -0
- package/lib/chat/present.mjs +246 -0
- package/lib/chat/session-context.mjs +39 -0
- package/lib/chat/session-persist.mjs +73 -0
- package/lib/chat/session-restore.mjs +71 -0
- package/lib/chat/session-settings.mjs +53 -0
- package/lib/chat/system-prompt.mjs +52 -0
- package/lib/chat/transparency.mjs +93 -0
- package/lib/chat/tui/color-scheme.mjs +42 -0
- package/lib/chat/tui/markdown.mjs +123 -0
- package/lib/chat/tui/presentation.mjs +100 -0
- package/lib/chat/tui/render.mjs +500 -0
- package/lib/chat/tui/turn-block.mjs +284 -0
- package/lib/chat/tui/turn-present.mjs +18 -0
- package/lib/chat/tui/turn-state.mjs +88 -0
- package/lib/chat/tui/usage.mjs +122 -0
- package/lib/chat/web-commands.mjs +146 -0
- package/lib/chat/web-launcher.mjs +63 -0
- package/lib/chat/web-picker-keys.mjs +46 -0
- package/lib/chat/web-session.mjs +159 -0
- package/lib/cli-commands.mjs +146 -15
- package/lib/cli-service-inventory.mjs +42 -0
- package/lib/comment-lint.mjs +6 -4
- package/lib/config/intake-policy.mjs +209 -0
- package/lib/config/project-config.mjs +11 -2
- package/lib/config/schema.mjs +86 -6
- package/lib/config/source-targets.mjs +311 -0
- package/lib/contract-schemas/decision.json +50 -0
- package/lib/contract-schemas/implementation.json +51 -0
- package/lib/contract-schemas/review-report.json +32 -0
- package/lib/contract-schemas/test-report.json +43 -0
- package/lib/contracts/construct-handoff.mjs +60 -0
- package/lib/contracts/validate.mjs +32 -3
- package/lib/contracts/violation-log.mjs +58 -5
- package/lib/dashboard-demo.mjs +71 -0
- package/lib/dashboard-static.mjs +19 -5
- package/lib/decisions/registry.mjs +5 -3
- package/lib/deck-export-pptx.mjs +1152 -0
- package/lib/demo-recording.mjs +142 -0
- package/lib/demo-script.mjs +114 -0
- package/lib/demo-surface.mjs +249 -0
- package/lib/demo.mjs +598 -140
- package/lib/diagram-export.mjs +192 -0
- package/lib/diagram.mjs +13 -11
- package/lib/docs-verify.mjs +25 -7
- package/lib/doctor/index.mjs +3 -1
- package/lib/doctor/project-adapters.mjs +44 -0
- package/lib/doctor/source-checkout.mjs +16 -0
- package/lib/doctor/watchers/cx-budget.mjs +98 -0
- package/lib/doctor/watchers/graph-staleness.mjs +52 -0
- package/lib/doctor/watchers/process-pressure.mjs +4 -3
- package/lib/document-export.mjs +384 -38
- package/lib/document-extract.mjs +44 -4
- package/lib/document-ingest.mjs +29 -20
- package/lib/embed/auto-sources.mjs +44 -0
- package/lib/embed/cli.mjs +4 -3
- package/lib/embed/daemon.mjs +18 -46
- package/lib/embed/demand-fetch.mjs +50 -19
- package/lib/embed/inbox.mjs +6 -10
- package/lib/embed/worker.mjs +4 -3
- package/lib/embedded-contract/index.mjs +11 -0
- package/lib/embedded-contract/model-resolve.mjs +10 -9
- package/lib/env-config.mjs +26 -0
- package/lib/evals/dataset.mjs +137 -0
- package/lib/evals/gates.mjs +175 -0
- package/lib/export-branding.mjs +32 -0
- package/lib/graph/build-co-change.mjs +54 -0
- package/lib/graph/build-from-registry.mjs +136 -0
- package/lib/graph/build-import-graph.mjs +153 -0
- package/lib/graph/cli.mjs +110 -0
- package/lib/graph/impact-cli.mjs +89 -0
- package/lib/graph/impact.mjs +108 -0
- package/lib/graph/staleness.mjs +44 -0
- package/lib/graph/store.mjs +172 -0
- package/lib/health-check.mjs +90 -76
- package/lib/hooks/artifact-release-gate.mjs +43 -0
- package/lib/hooks/brand-prose-lint.mjs +38 -0
- package/lib/hooks/graph-impact-advisory.mjs +62 -0
- package/lib/hooks/session-optimize.mjs +84 -207
- package/lib/hooks/session-start.mjs +18 -16
- package/lib/host-disposition.mjs +7 -0
- package/lib/improvement/cli.mjs +189 -0
- package/lib/improvement/controller.mjs +137 -0
- package/lib/improvement/proposal.mjs +120 -0
- package/lib/improvement/specialist-loop.mjs +192 -0
- package/lib/improvement/store.mjs +89 -0
- package/lib/improvement/surface.mjs +219 -0
- package/lib/ingest-tooling.mjs +97 -0
- package/lib/init/doc-lanes.mjs +165 -0
- package/lib/init-docs.mjs +31 -178
- package/lib/init-unified.mjs +50 -119
- package/lib/init-update-guide.mjs +102 -0
- package/lib/init-update.mjs +32 -1
- package/lib/init.mjs +8 -0
- package/lib/install/desktop-binary-download.mjs +85 -0
- package/lib/install/legacy-global-cleanup.mjs +189 -0
- package/lib/intake/constants.mjs +29 -0
- package/lib/intake/daemon.mjs +2 -0
- package/lib/intake/git-queue.mjs +9 -8
- package/lib/intake/intake-config.mjs +52 -105
- package/lib/intake/legacy-paths.mjs +5 -0
- package/lib/intake/queue.mjs +2 -1
- package/lib/intake/session-prelude.mjs +90 -1
- package/lib/libreoffice-export.mjs +97 -0
- package/lib/logging/rotate.mjs +9 -0
- package/lib/maintenance/docker-reclaim.mjs +206 -0
- package/lib/mcp/external-schema-cost.mjs +74 -0
- package/lib/mcp/server.mjs +103 -10
- package/lib/mcp/stdio-mcp-probe.mjs +188 -0
- package/lib/mcp/tool-budget.mjs +55 -4
- package/lib/mcp/tools/document.mjs +18 -4
- package/lib/mcp/tools/embedded-contract.mjs +14 -0
- package/lib/mcp/tools/skills.mjs +32 -3
- package/lib/mcp/tools/workflow.mjs +13 -1
- package/lib/model-free-selector.mjs +18 -0
- package/lib/model-registry.mjs +13 -229
- package/lib/model-router.mjs +373 -92
- package/lib/models/behavior-matrix.mjs +289 -0
- package/lib/models/catalog.mjs +209 -0
- package/lib/models/execution-capability-profile.mjs +196 -0
- package/lib/models/execution-policy.mjs +307 -0
- package/lib/models/provider-poll.mjs +383 -0
- package/lib/npm-spawn-env.mjs +17 -0
- package/lib/ollama/installed-models.mjs +129 -0
- package/lib/oracle/actions.mjs +187 -0
- package/lib/oracle/artifact-gate.mjs +99 -0
- package/lib/oracle/cli.mjs +204 -0
- package/lib/oracle/daemon-entry.mjs +14 -0
- package/lib/oracle/dispatch.mjs +81 -0
- package/lib/oracle/execute.mjs +143 -0
- package/lib/oracle/gaps.mjs +76 -0
- package/lib/oracle/index.mjs +84 -0
- package/lib/oracle/issues.mjs +164 -0
- package/lib/oracle/org-graph.mjs +170 -0
- package/lib/oracle/policy.mjs +80 -0
- package/lib/oracle/read-model.mjs +398 -0
- package/lib/oracle/reconcile.mjs +191 -0
- package/lib/oracle/routing.mjs +89 -0
- package/lib/oracle/synthesize.mjs +384 -0
- package/lib/oracle/verdicts.mjs +51 -0
- package/lib/orchestration/worker.mjs +88 -27
- package/lib/orchestration-policy.mjs +50 -0
- package/lib/parity.mjs +96 -2
- package/lib/playwright-demo.mjs +254 -0
- package/lib/project-init-shared.mjs +4 -1
- package/lib/prompt-composer.js +7 -3
- package/lib/prompt-validation-contract.mjs +24 -0
- package/lib/provider-capabilities.js +57 -11
- package/lib/providers/contract/adapters/confluence/index.mjs +181 -0
- package/lib/providers/contract/adapters/git/index.mjs +115 -0
- package/lib/providers/contract/adapters/github/index.mjs +166 -0
- package/lib/providers/contract/adapters/jira/index.mjs +187 -0
- package/lib/providers/contract/adapters/slack/index.mjs +175 -0
- package/lib/providers/contract/contract-tests.mjs +57 -0
- package/lib/providers/contract/errors.mjs +48 -0
- package/lib/providers/contract/interface.mjs +50 -0
- package/lib/providers/contract/registry.mjs +102 -0
- package/lib/providers/copilot-auth.mjs +297 -0
- package/lib/providers/credential-bootstrap.mjs +178 -0
- package/lib/providers/credential-catalog.mjs +46 -0
- package/lib/providers/credential-sources.mjs +63 -0
- package/lib/providers/creds.mjs +5 -2
- package/lib/providers/op-run.mjs +59 -0
- package/lib/providers/secret-resolver.mjs +159 -0
- package/lib/publish-template.mjs +163 -0
- package/lib/publish-tooling.mjs +119 -0
- package/lib/publish.mjs +305 -0
- package/lib/registry/cli.mjs +82 -0
- package/lib/registry/consolidation.mjs +147 -0
- package/lib/registry/generate-docs.mjs +75 -0
- package/lib/registry/skill-verification.mjs +57 -0
- package/lib/registry/surface-map.mjs +76 -0
- package/lib/registry/validate.mjs +135 -0
- package/lib/resources/budget.mjs +82 -0
- package/lib/resources/process-budget.mjs +45 -0
- package/lib/rules-delivery.mjs +9 -2
- package/lib/rules-read.mjs +26 -0
- package/lib/runtime-env.mjs +23 -0
- package/lib/runtime-pressure.mjs +51 -7
- package/lib/schema-infer.mjs +13 -2
- package/lib/server/chat-loop.mjs +622 -0
- package/lib/server/demo-preview.mjs +63 -0
- package/lib/server/index.mjs +259 -9
- package/lib/server/rate-limit.mjs +5 -3
- package/lib/server/webhook.mjs +3 -2
- package/lib/service-manager.mjs +60 -8
- package/lib/setup.mjs +70 -7
- package/lib/specialists/prompt-schema.mjs +19 -10
- package/lib/specialists/roster.mjs +43 -0
- package/lib/specialists/scaffold.mjs +56 -0
- package/lib/storage/backend.mjs +6 -6
- package/lib/storage/hybrid-query.mjs +7 -4
- package/lib/storage/state-source.mjs +5 -5
- package/lib/storage/sync.mjs +2 -3
- package/lib/telemetry/rule-calls.mjs +52 -0
- package/lib/template-registry.mjs +2 -2
- package/lib/templates/visual-requirements.mjs +27 -51
- package/lib/test-corpus-inventory.mjs +313 -0
- package/lib/uninstall/uninstall.mjs +19 -7
- package/lib/update.mjs +12 -0
- package/lib/upgrade.mjs +14 -0
- package/lib/wireframe.mjs +20 -14
- package/lib/worker/run.mjs +17 -4
- package/lib/worker/trace.mjs +11 -3
- package/package.json +28 -14
- package/personas/construct.md +2 -2
- package/platforms/claude/settings.template.json +36 -0
- package/rules/common/patterns.md +1 -1
- package/rules/common/release-gates.md +4 -3
- package/scripts/sync-specialists.mjs +41 -28
- package/skills/devops/data-engineering.md +1 -1
- package/skills/docs/adr-workflow.md +1 -0
- package/skills/docs/backlog-proposal-workflow.md +1 -0
- package/skills/docs/codebase-research-workflow.md +40 -0
- package/skills/docs/customer-profile-workflow.md +1 -0
- package/skills/docs/document-ingest-workflow.md +1 -0
- package/skills/docs/evidence-ingest-workflow.md +1 -0
- package/skills/docs/init-docs.md +2 -2
- package/skills/docs/init-project.md +7 -2
- package/skills/docs/prd-workflow.md +24 -1
- package/skills/docs/prfaq-workflow.md +1 -0
- package/skills/docs/product-intelligence-workflow.md +1 -0
- package/skills/docs/product-signal-workflow.md +1 -0
- package/skills/docs/research-workflow.md +54 -37
- package/skills/docs/runbook-workflow.md +1 -0
- package/skills/docs/strategy-workflow.md +1 -0
- package/skills/docs/user-research-workflow.md +40 -0
- package/skills/operating/orchestration-reference.md +1 -1
- package/skills/roles/architect.md +5 -0
- package/skills/roles/operator.docs.md +4 -0
- package/skills/routing.md +4 -2
- package/specialists/artifact-manifest.json +489 -0
- package/specialists/artifact-manifest.schema.json +83 -0
- package/specialists/audit-enrichments.json +454 -0
- package/specialists/contracts.json +37 -25
- package/specialists/prompts/_shared/validation-contract.md +26 -0
- package/specialists/prompts/cx-accessibility.md +21 -2
- package/specialists/prompts/cx-ai-engineer.md +24 -1
- package/specialists/prompts/cx-architect.md +4 -1
- package/specialists/prompts/cx-business-strategist.md +23 -2
- package/specialists/prompts/cx-data-analyst.md +22 -1
- package/specialists/prompts/cx-data-engineer.md +23 -2
- package/specialists/prompts/cx-debugger.md +21 -2
- package/specialists/prompts/cx-designer.md +26 -3
- package/specialists/prompts/cx-devil-advocate.md +19 -2
- package/specialists/prompts/cx-docs-keeper.md +28 -1
- package/specialists/prompts/cx-engineer.md +22 -1
- package/specialists/prompts/cx-evaluator.md +18 -1
- package/specialists/prompts/cx-explorer.md +21 -2
- package/specialists/prompts/cx-legal-compliance.md +21 -2
- package/specialists/prompts/cx-operations.md +21 -2
- package/specialists/prompts/cx-oracle.md +94 -0
- package/specialists/prompts/cx-orchestrator.md +20 -1
- package/specialists/prompts/cx-platform-engineer.md +25 -2
- package/specialists/prompts/cx-product-manager.md +32 -1
- package/specialists/prompts/cx-qa.md +24 -2
- package/specialists/prompts/cx-rd-lead.md +23 -2
- package/specialists/prompts/cx-release-manager.md +23 -2
- package/specialists/prompts/cx-researcher.md +22 -2
- package/specialists/prompts/cx-reviewer.md +18 -1
- package/specialists/prompts/cx-security.md +22 -2
- package/specialists/prompts/cx-sre.md +30 -3
- package/specialists/prompts/cx-test-automation.md +7 -1
- package/specialists/prompts/cx-trace-reviewer.md +22 -3
- package/specialists/prompts/cx-ux-researcher.md +21 -2
- package/specialists/registry.json +52 -173
- package/specialists/tone-profiles.json +42 -0
- package/templates/demos/playwright/demo-recording.config.mjs +47 -0
- package/templates/demos/recordings/agentic-platforms-prd.json +19 -0
- package/templates/demos/scripts/agentic-platforms-prd.json +44 -0
- package/templates/demos/specs/_helpers/scroll-artifact.ts +89 -0
- package/templates/demos/tapes/agentic-platforms-prd.tape +49 -0
- package/templates/demos/tapes/resource-guard-rails.tape +49 -0
- package/templates/demos/vhs/construct-cockpit.json +24 -0
- package/templates/distribution/construct-brand.typ +446 -0
- package/templates/distribution/construct-decision.typ +38 -0
- package/templates/distribution/construct-deck.html +95 -0
- package/templates/distribution/construct-pdf.typ +38 -0
- package/templates/distribution/construct-prd.typ +38 -0
- package/templates/distribution/construct-reference.docx +0 -0
- package/templates/distribution/construct-research.typ +38 -0
- package/templates/distribution/construct-web.html +92 -0
- package/templates/distribution/fonts/Geist-Bold.ttf +0 -0
- package/templates/distribution/fonts/Geist-Medium.ttf +0 -0
- package/templates/distribution/fonts/Geist-Regular.ttf +0 -0
- package/templates/distribution/fonts/Geist-SemiBold.ttf +0 -0
- package/templates/distribution/fonts/GeistMono-Medium.ttf +0 -0
- package/templates/distribution/fonts/GeistMono-Regular.ttf +0 -0
- package/templates/distribution/fonts/GeistMono-SemiBold.ttf +0 -0
- package/templates/distribution/fonts/IBMPlexMono-Regular.otf +0 -0
- package/templates/distribution/fonts/JetBrainsMono-Medium.ttf +0 -0
- package/templates/distribution/fonts/JetBrainsMono-Regular.ttf +0 -0
- package/templates/distribution/fonts/JetBrainsMono-SemiBold.ttf +0 -0
- package/templates/distribution/fonts/PlusJakartaSans-Bold.ttf +0 -0
- package/templates/distribution/fonts/PlusJakartaSans-Medium.ttf +0 -0
- package/templates/distribution/fonts/PlusJakartaSans-Regular.ttf +0 -0
- package/templates/distribution/fonts/PlusJakartaSans-SemiBold.ttf +0 -0
- package/templates/distribution/fonts/README.md +36 -0
- package/templates/distribution/fonts/SpaceGrotesk-Variable.ttf +0 -0
- package/templates/distribution/fonts/handwritten/Caveat.ttf +0 -0
- package/templates/distribution/fonts/legacy/IBMPlexMono-Regular.otf +0 -0
- package/templates/distribution/fonts/legacy/Inter-Medium.otf +0 -0
- package/templates/distribution/fonts/legacy/Inter-Regular.otf +0 -0
- package/templates/distribution/fonts/legacy/Inter-SemiBold.otf +0 -0
- package/templates/distribution/fonts/legacy/InterDisplay-SemiBold.otf +0 -0
- package/templates/distribution/fonts/legacy/SourceSerif4-Regular.otf +0 -0
- package/templates/distribution/fonts/legacy/SourceSerif4-Semibold.otf +0 -0
- package/templates/distribution/icons/activity.svg +15 -0
- package/templates/distribution/icons/alert-triangle.svg +17 -0
- package/templates/distribution/icons/book-open.svg +16 -0
- package/templates/distribution/icons/bot.svg +20 -0
- package/templates/distribution/icons/brain.svg +22 -0
- package/templates/distribution/icons/circle-check.svg +16 -0
- package/templates/distribution/icons/clipboard-check.svg +17 -0
- package/templates/distribution/icons/cpu.svg +28 -0
- package/templates/distribution/icons/database.svg +17 -0
- package/templates/distribution/icons/eye.svg +16 -0
- package/templates/distribution/icons/file-text.svg +19 -0
- package/templates/distribution/icons/gauge.svg +16 -0
- package/templates/distribution/icons/git-branch.svg +17 -0
- package/templates/distribution/icons/key.svg +17 -0
- package/templates/distribution/icons/layers.svg +17 -0
- package/templates/distribution/icons/list-checks.svg +19 -0
- package/templates/distribution/icons/lock.svg +16 -0
- package/templates/distribution/icons/message-square.svg +15 -0
- package/templates/distribution/icons/network.svg +19 -0
- package/templates/distribution/icons/route.svg +17 -0
- package/templates/distribution/icons/scale.svg +19 -0
- package/templates/distribution/icons/search.svg +16 -0
- package/templates/distribution/icons/send.svg +16 -0
- package/templates/distribution/icons/server.svg +18 -0
- package/templates/distribution/icons/shield-check.svg +16 -0
- package/templates/distribution/icons/users.svg +18 -0
- package/templates/distribution/icons/webhook.svg +17 -0
- package/templates/distribution/icons/workflow.svg +17 -0
- package/templates/distribution/icons/wrench.svg +15 -0
- package/templates/distribution/run.mjs +18 -1
- package/templates/docs/adr.md +7 -0
- package/templates/docs/construct_guide.md +8 -8
- package/templates/docs/customer-profile.md +4 -0
- package/templates/docs/one-pager.md +4 -0
- package/templates/docs/postmortem.md +31 -0
- package/templates/docs/prd-platform.md +19 -0
- package/templates/docs/prd.md +15 -0
- package/templates/docs/prfaq.md +7 -0
- package/templates/docs/qa-strategy.md +103 -0
- package/templates/docs/research-brief.md +8 -0
- package/templates/docs/rfc-platform.md +12 -0
- package/templates/docs/test-plan.md +7 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/chat/web-launcher.mjs — start dashboard server and open /chat for construct chat --web.
|
|
3
|
+
*
|
|
4
|
+
* Reuses lib/service-manager.mjs startDashboard so the browser surface shares auth,
|
|
5
|
+
* CSRF, and static hosting with the operations dashboard.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
9
|
+
import { startDashboard, readDashboardState } from '../service-manager.mjs';
|
|
10
|
+
|
|
11
|
+
function openBrowser(url) {
|
|
12
|
+
const platform = process.platform;
|
|
13
|
+
let cmd;
|
|
14
|
+
let args;
|
|
15
|
+
if (platform === 'darwin') {
|
|
16
|
+
cmd = 'open';
|
|
17
|
+
args = [url];
|
|
18
|
+
} else if (platform === 'win32') {
|
|
19
|
+
cmd = 'cmd';
|
|
20
|
+
args = ['/c', 'start', '', url];
|
|
21
|
+
} else {
|
|
22
|
+
cmd = 'xdg-open';
|
|
23
|
+
args = [url];
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
spawn(cmd, args, { detached: true, stdio: 'ignore' }).unref();
|
|
27
|
+
} catch {
|
|
28
|
+
/* browser open is best-effort */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function runWebChat({
|
|
33
|
+
cwd = process.cwd(),
|
|
34
|
+
env = process.env,
|
|
35
|
+
output = process.stdout,
|
|
36
|
+
errorOutput = process.stderr,
|
|
37
|
+
surface = null,
|
|
38
|
+
} = {}) {
|
|
39
|
+
let dash = readDashboardState();
|
|
40
|
+
if (!dash?.port) {
|
|
41
|
+
const result = await startDashboard({ rootDir: cwd, preferredPort: parseInt(env.PORT || env.DASHBOARD_PORT || '4242', 10) });
|
|
42
|
+
if (result.started || result.reused) {
|
|
43
|
+
dash = { port: result.port, url: result.url || `http://127.0.0.1:${result.port}` };
|
|
44
|
+
} else {
|
|
45
|
+
errorOutput.write(`Failed to start dashboard: ${result.reason || 'unknown error'}\n`);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const base = (dash.url || `http://127.0.0.1:${dash.port}`).replace(/\/$/, '');
|
|
51
|
+
const chatUrl = surface === 'desktop'
|
|
52
|
+
? `${base}/chat/?surface=desktop`
|
|
53
|
+
: `${base}/chat/`;
|
|
54
|
+
output.write(`Construct web chat: ${chatUrl}\n`);
|
|
55
|
+
output.write('Press Ctrl-C to stop the dashboard server.\n');
|
|
56
|
+
openBrowser(chatUrl);
|
|
57
|
+
|
|
58
|
+
await new Promise((resolve) => {
|
|
59
|
+
process.once('SIGINT', resolve);
|
|
60
|
+
process.once('SIGTERM', resolve);
|
|
61
|
+
});
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/chat/web-picker-keys.mjs — keyboard routing for the web list picker.
|
|
3
|
+
*
|
|
4
|
+
* Arrow/enter/escape handling shared with Ink via list-picker.mjs; this module
|
|
5
|
+
* adapts DOM KeyboardEvent shapes for tests and the React overlay.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
getPickerSelectedItem,
|
|
10
|
+
getPickerVisibleItems,
|
|
11
|
+
movePickerIndex,
|
|
12
|
+
reducePickerKey,
|
|
13
|
+
} from './list-picker.mjs';
|
|
14
|
+
|
|
15
|
+
export { getPickerSelectedItem, getPickerVisibleItems, movePickerIndex };
|
|
16
|
+
|
|
17
|
+
export function domKeyToPickerKey(event) {
|
|
18
|
+
const key = event?.key || '';
|
|
19
|
+
return {
|
|
20
|
+
char: key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey ? key : undefined,
|
|
21
|
+
key: {
|
|
22
|
+
escape: key === 'Escape',
|
|
23
|
+
return: key === 'Enter',
|
|
24
|
+
upArrow: key === 'ArrowUp',
|
|
25
|
+
downArrow: key === 'ArrowDown',
|
|
26
|
+
backspace: key === 'Backspace',
|
|
27
|
+
delete: key === 'Delete',
|
|
28
|
+
ctrl: event.ctrlKey,
|
|
29
|
+
meta: event.metaKey,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isPickerNavigationKey(key) {
|
|
35
|
+
return key === 'ArrowUp' || key === 'ArrowDown' || key === 'Enter' || key === 'Escape';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function reduceWebPickerKey(state, event) {
|
|
39
|
+
return reducePickerKey(state, domKeyToPickerKey(event));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function commitWebPickerSelection(state) {
|
|
43
|
+
const item = getPickerSelectedItem(state);
|
|
44
|
+
if (!item || item.disabled) return { ok: false, item: null };
|
|
45
|
+
return { ok: true, item };
|
|
46
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/chat/web-session.mjs — owned-loop runtime factory for browser chat.
|
|
3
|
+
*
|
|
4
|
+
* Builds the same driver + session shape as lib/chat/cli.mjs so dashboard SSE
|
|
5
|
+
* and construct chat --web share one configuration path. One runtime instance
|
|
6
|
+
* is kept per conversation id for the lifetime of the server process.
|
|
7
|
+
*/
|
|
8
|
+
import { randomBytes } from 'crypto';
|
|
9
|
+
import { createOwnedLoopDriver } from '../../apps/chat/engine/loop-driver.mjs';
|
|
10
|
+
import { resolveChatModelSelectionAsync, resolveSessionModel } from '../../apps/chat/engine/models.mjs';
|
|
11
|
+
import { loadChatConfig } from './config.mjs';
|
|
12
|
+
import { loadConstructEnv } from '../env-config.mjs';
|
|
13
|
+
import { resolveLayers } from './transparency.mjs';
|
|
14
|
+
import { buildSystemPrompt } from './system-prompt.mjs';
|
|
15
|
+
import { createSessionUsage } from './tui/usage.mjs';
|
|
16
|
+
import { resolveExecutionCapabilityProfile } from '../models/execution-capability-profile.mjs';
|
|
17
|
+
import { compileExecutionPolicy } from '../models/execution-policy.mjs';
|
|
18
|
+
import { resolveDemoGuideForChat } from '../demo-surface.mjs';
|
|
19
|
+
|
|
20
|
+
const runtimes = new Map();
|
|
21
|
+
const pendingPermissions = new Map();
|
|
22
|
+
|
|
23
|
+
function createPermissionHandler({ session, onPermission = null }) {
|
|
24
|
+
return async (req) => {
|
|
25
|
+
const mode = session.permissionMode || 'allow_once';
|
|
26
|
+
if (mode === 'reject') return 'reject';
|
|
27
|
+
if (mode === 'allow_always') return 'allow_always';
|
|
28
|
+
if (mode === 'allow_once') return 'allow';
|
|
29
|
+
if (mode === 'ask') {
|
|
30
|
+
const requestId = req.requestId || `perm-${randomBytes(8).toString('hex')}`;
|
|
31
|
+
onPermission?.({
|
|
32
|
+
type: 'permission',
|
|
33
|
+
requestId,
|
|
34
|
+
toolCall: { title: req.tool || req.toolCall?.title || 'tool', input: req.input ?? null },
|
|
35
|
+
options: ['allow', 'allow_always', 'reject'],
|
|
36
|
+
});
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
pendingPermissions.set(requestId, { resolve, req, convId: session.convId });
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
if (pendingPermissions.has(requestId)) {
|
|
41
|
+
pendingPermissions.delete(requestId);
|
|
42
|
+
resolve('reject');
|
|
43
|
+
}
|
|
44
|
+
}, 120_000);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return 'allow';
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function resolveWebPermission(requestId, decision) {
|
|
52
|
+
const pending = pendingPermissions.get(requestId);
|
|
53
|
+
if (!pending) return false;
|
|
54
|
+
pendingPermissions.delete(requestId);
|
|
55
|
+
pending.resolve(decision);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function listPendingPermissions(convId) {
|
|
60
|
+
return [...pendingPermissions.entries()]
|
|
61
|
+
.filter(([, p]) => p.convId === convId)
|
|
62
|
+
.map(([requestId, p]) => ({
|
|
63
|
+
requestId,
|
|
64
|
+
title: p.req?.toolCall?.title || 'tool',
|
|
65
|
+
options: p.req?.options || ['allow', 'reject'],
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getWebChatRuntime(convId) {
|
|
70
|
+
return runtimes.get(convId) || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function ensureWebChatRuntime({
|
|
74
|
+
convId,
|
|
75
|
+
cwd = process.cwd(),
|
|
76
|
+
env = process.env,
|
|
77
|
+
onPermission = null,
|
|
78
|
+
} = {}) {
|
|
79
|
+
if (runtimes.has(convId)) return runtimes.get(convId);
|
|
80
|
+
|
|
81
|
+
const effectiveEnv = loadConstructEnv({ rootDir: cwd, env, warn: false });
|
|
82
|
+
const { config } = loadChatConfig({ cwd });
|
|
83
|
+
const layers = resolveLayers({ flags: {}, env: effectiveEnv });
|
|
84
|
+
for (const key of Object.keys(config.layers || {})) {
|
|
85
|
+
if (config.layers[key] === false) layers[key] = false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let modelMode = config.modelMode || 'pinned';
|
|
89
|
+
let resolvedModel = config.model || null;
|
|
90
|
+
if (modelMode === 'free-router') {
|
|
91
|
+
const sessionStub = { modelMode: 'free-router', failedModels: new Set() };
|
|
92
|
+
resolvedModel = await resolveSessionModel(sessionStub, { env: effectiveEnv, tier: 'standard' });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const modelResolution = modelMode === 'free-router' && resolvedModel
|
|
96
|
+
? { id: resolvedModel, notice: null }
|
|
97
|
+
: await resolveChatModelSelectionAsync({ env: effectiveEnv, requested: resolvedModel });
|
|
98
|
+
|
|
99
|
+
const demoName = effectiveEnv.CONSTRUCT_DEMO || null;
|
|
100
|
+
const demoPack = demoName ? resolveDemoGuideForChat(demoName, { cwd, repoRoot: cwd }) : null;
|
|
101
|
+
|
|
102
|
+
const session = {
|
|
103
|
+
convId,
|
|
104
|
+
model: modelResolution.id || resolvedModel,
|
|
105
|
+
modelMode,
|
|
106
|
+
permissionMode: config.permissionMode || 'allow_once',
|
|
107
|
+
sandbox: config.sandbox || 'workspace-write',
|
|
108
|
+
layers,
|
|
109
|
+
usage: createSessionUsage(),
|
|
110
|
+
demoGuide: demoPack?.guide || null,
|
|
111
|
+
demoTitle: demoPack?.script?.title || null,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const handlers = {
|
|
115
|
+
getSandbox: () => session.sandbox,
|
|
116
|
+
getPermissionMode: () => session.permissionMode,
|
|
117
|
+
requestPermission: createPermissionHandler({ session, onPermission }),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const { createAiSdkAgent } = await import('../../apps/chat/engine/ai-sdk-agent.mjs');
|
|
121
|
+
const driver = createOwnedLoopDriver({
|
|
122
|
+
env: effectiveEnv,
|
|
123
|
+
cwd,
|
|
124
|
+
model: session.model,
|
|
125
|
+
handlers,
|
|
126
|
+
systemPrompt: buildSystemPrompt({
|
|
127
|
+
capabilityTier: compileExecutionPolicy({
|
|
128
|
+
profile: resolveExecutionCapabilityProfile({ model: session.model }),
|
|
129
|
+
}).prompt.systemPromptTier,
|
|
130
|
+
}),
|
|
131
|
+
createAgent: (opts) => createAiSdkAgent(opts),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const runtime = { convId, driver, session, layers, cwd, env: effectiveEnv, _started: false };
|
|
135
|
+
runtimes.set(convId, runtime);
|
|
136
|
+
|
|
137
|
+
if (!demoPack?.guide) {
|
|
138
|
+
await driver.start();
|
|
139
|
+
runtime._started = true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return runtime;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function ensureDriverStarted(runtime) {
|
|
146
|
+
if (!runtime || runtime._started) return runtime;
|
|
147
|
+
await runtime.driver.start();
|
|
148
|
+
runtime._started = true;
|
|
149
|
+
return runtime;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const createWebChatRuntime = ensureWebChatRuntime;
|
|
153
|
+
|
|
154
|
+
export function dropWebChatRuntime(convId) {
|
|
155
|
+
const runtime = runtimes.get(convId);
|
|
156
|
+
if (!runtime) return;
|
|
157
|
+
try { runtime.driver.stop?.(); } catch { /* already stopped */ }
|
|
158
|
+
runtimes.delete(convId);
|
|
159
|
+
}
|
package/lib/cli-commands.mjs
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { resolveColors } from './term-format.mjs';
|
|
16
|
+
import { surfaceForCommand } from './registry/surface-map.mjs';
|
|
16
17
|
|
|
17
18
|
export const CLI_COMMANDS = [
|
|
18
19
|
// ── Core (shown by default) ───────────────────────────────────────────
|
|
@@ -321,15 +322,63 @@ export const CLI_COMMANDS = [
|
|
|
321
322
|
category: 'Work',
|
|
322
323
|
core: false,
|
|
323
324
|
description: 'Convert documents to indexed markdown',
|
|
324
|
-
usage: 'construct ingest <file> [--strategy=adapter|provider] [--orchestration=prompt-only|orchestrated] [--strict] [--
|
|
325
|
+
usage: 'construct ingest <file> [--strategy=adapter|provider] [--orchestration=prompt-only|orchestrated] [--strict] [--fidelity=fast|high]',
|
|
325
326
|
},
|
|
326
327
|
{
|
|
327
328
|
name: 'export',
|
|
328
329
|
emoji: '📤',
|
|
329
330
|
category: 'Work',
|
|
330
331
|
core: false,
|
|
331
|
-
description: 'Export markdown to PDF
|
|
332
|
-
usage: 'construct export <markdown-file> --to=<pdf|docx|html> [--output=<path>]',
|
|
332
|
+
description: 'Export markdown to PDF, DOCX, HTML, and other Pandoc formats via Pandoc + Typst (optional system binaries; ADR-0024)',
|
|
333
|
+
usage: 'construct export <markdown-file> --to=<pdf|docx|deck|pptx|html|rtf|odt|epub|tex|txt|md|mdx> [--output=<path>] [--figures|--no-figures] [--plain] [--detect]',
|
|
334
|
+
strictFlags: true,
|
|
335
|
+
options: [
|
|
336
|
+
{ flag: '--to=<format>', desc: 'pdf, docx, deck, pptx, html, rtf, odt, epub, tex, txt, md, mdx' },
|
|
337
|
+
{ flag: '--output=<path>', desc: 'Output path' },
|
|
338
|
+
{ flag: '--figures', desc: 'Render d2/mermaid via pandoc-ext/diagram filter' },
|
|
339
|
+
{ flag: '--no-figures', desc: 'Skip diagram rendering' },
|
|
340
|
+
{ flag: '--plain, --no-brand', desc: 'Explicitly opt out of Construct branding for a brand-capable output' },
|
|
341
|
+
{ flag: '--detect', desc: 'Report binary availability (JSON)' },
|
|
342
|
+
],
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: 'publish',
|
|
346
|
+
emoji: '📰',
|
|
347
|
+
category: 'Work',
|
|
348
|
+
core: false,
|
|
349
|
+
description: 'Publish typed artifacts: release gate + export PDF with figures + optional demos',
|
|
350
|
+
usage: 'construct publish <markdown> [--to=pdf] [--type=DOC] [--demo=NAME] [--strict]',
|
|
351
|
+
strictFlags: true,
|
|
352
|
+
options: [
|
|
353
|
+
{ flag: '--to=<format>', desc: 'pdf (default), docx, deck, pptx, html, rtf, odt, epub, tex, txt, md, mdx' },
|
|
354
|
+
{ flag: '--output=<path>', desc: 'Output path (default: .cx/publish/<name>.<format>)' },
|
|
355
|
+
{ flag: '--type=<doc-type>', desc: 'Manifest doc type for release gate (inferred when omitted)' },
|
|
356
|
+
{ flag: '--demo=<name>', desc: 'Terminal VHS tape to record (repeatable)' },
|
|
357
|
+
{ flag: '--dashboard-demo=<name>', desc: 'Playwright demo spec basename (repeatable)' },
|
|
358
|
+
{ flag: '--figures', desc: 'Render d2/mermaid via diagram filter (default on)' },
|
|
359
|
+
{ flag: '--no-figures', desc: 'Skip diagram filter' },
|
|
360
|
+
{ flag: '--no-gate', desc: 'Skip artifact release gate (escape hatch only)' },
|
|
361
|
+
{ flag: '--source-only', desc: 'Write sources only' },
|
|
362
|
+
{ flag: '--strict', desc: 'Exit 2 when toolchain or release gate fails (default)' },
|
|
363
|
+
{ flag: '--no-strict', desc: 'Do not exit 2 on toolchain/gate failure' },
|
|
364
|
+
{ flag: '--detect', desc: 'Print tooling JSON and exit' },
|
|
365
|
+
],
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: 'tools',
|
|
369
|
+
emoji: '🧰',
|
|
370
|
+
category: 'Work',
|
|
371
|
+
core: false,
|
|
372
|
+
description: 'Detect optional publish pipeline binaries (Pandoc, D2, VHS, Playwright)',
|
|
373
|
+
usage: 'construct tools detect [--json] [--figures] [--demo=NAME]',
|
|
374
|
+
strictFlags: true,
|
|
375
|
+
options: [
|
|
376
|
+
{ flag: '--json', desc: 'JSON output' },
|
|
377
|
+
{ flag: '--figures', desc: 'Include figure tooling (default on)' },
|
|
378
|
+
{ flag: '--no-figures', desc: 'Skip figure binaries' },
|
|
379
|
+
{ flag: '--demo=<name>', desc: 'Include terminal demo recorder check' },
|
|
380
|
+
{ flag: '--dashboard-demo=<name>', desc: 'Include dashboard Playwright check' },
|
|
381
|
+
],
|
|
333
382
|
},
|
|
334
383
|
{
|
|
335
384
|
name: 'infer',
|
|
@@ -433,6 +482,14 @@ export const CLI_COMMANDS = [
|
|
|
433
482
|
description: 'Run Construct as an Agent Client Protocol (ACP) server over stdio for Zed/JetBrains/VS Code ACP clients',
|
|
434
483
|
usage: 'construct acp',
|
|
435
484
|
},
|
|
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
|
+
},
|
|
436
493
|
{
|
|
437
494
|
name: 'mcp',
|
|
438
495
|
emoji: '🔌',
|
|
@@ -534,6 +591,15 @@ export const CLI_COMMANDS = [
|
|
|
534
591
|
description: 'Show evaluator catalog for prompt and agent experiments',
|
|
535
592
|
usage: 'construct evals <list|run>',
|
|
536
593
|
},
|
|
594
|
+
{
|
|
595
|
+
name: 'improvement',
|
|
596
|
+
emoji: '🔁',
|
|
597
|
+
category: 'Observability',
|
|
598
|
+
core: false,
|
|
599
|
+
surface: 'dashboard',
|
|
600
|
+
description: 'Governed improvement loop — review, approve, and record apply/rollback for proposals',
|
|
601
|
+
usage: 'construct improvement submit|review|pending|show|approve|apply|rollback|list',
|
|
602
|
+
},
|
|
537
603
|
{
|
|
538
604
|
name: 'cleanup',
|
|
539
605
|
emoji: '🧹',
|
|
@@ -545,7 +611,7 @@ export const CLI_COMMANDS = [
|
|
|
545
611
|
options: [
|
|
546
612
|
{ flag: '--dry-run', desc: 'Show what would be cleaned without changing anything' },
|
|
547
613
|
{ flag: '--quiet', desc: 'Minimal output' },
|
|
548
|
-
{ flag: '--pressure-release', desc: 'Also kill stale dev-agent processes' },
|
|
614
|
+
{ flag: '--pressure-release', desc: 'Also kill stale dev-agent and leaked VHS demo-recorder processes' },
|
|
549
615
|
{ flag: '--pressure-only', desc: 'Pressure release only — skip disk cleanup' },
|
|
550
616
|
{ flag: '--disk-only', desc: 'Disk cleanup only — skip pressure release' },
|
|
551
617
|
],
|
|
@@ -564,7 +630,42 @@ export const CLI_COMMANDS = [
|
|
|
564
630
|
category: 'Diagnostics',
|
|
565
631
|
core: false,
|
|
566
632
|
description: 'Audit Construct internals and review the mutation trail',
|
|
567
|
-
usage: 'construct audit <
|
|
633
|
+
usage: 'construct audit <skills|specialists|tests|trail>',
|
|
634
|
+
subcommands: [
|
|
635
|
+
{ name: 'skills', desc: 'Audit skill corpus coverage and metadata (`--inventory` checks certification skill inventory freshness)' },
|
|
636
|
+
{ name: 'specialists', desc: 'Audit specialist/skill matrix and cross-checks' },
|
|
637
|
+
{ name: 'tests', desc: 'Validate behavior-to-test capability traceability (`--corpus` checks test-file inventory)' },
|
|
638
|
+
{ name: 'trail', desc: 'Review mutation audit trail' },
|
|
639
|
+
],
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: 'certify',
|
|
643
|
+
emoji: '✅',
|
|
644
|
+
category: 'Diagnostics',
|
|
645
|
+
core: false,
|
|
646
|
+
description: 'Inspect and run scenario-based certification under .cx/certification/',
|
|
647
|
+
usage: 'construct certify list|show|scenarios|models|demos|status|gate|run <scenario-id>',
|
|
648
|
+
subcommands: [
|
|
649
|
+
{ name: 'list', desc: 'List recorded certification run ids' },
|
|
650
|
+
{ name: 'show', desc: 'Show one certification run record as JSON' },
|
|
651
|
+
{ name: 'scenarios', desc: 'List available certification scenarios with model tier' },
|
|
652
|
+
{ name: 'models', desc: 'List routable certification models (free by default)' },
|
|
653
|
+
{ name: 'status', desc: 'Roll up certification posture across capabilities and surfaces' },
|
|
654
|
+
{ name: 'gate', desc: 'Release candidate gate — stale or failing release-critical certification evidence blocks' },
|
|
655
|
+
{ name: 'run', desc: 'Execute a scenario (live requires CONSTRUCT_CERTIFY_LIVE=1; paid requires CONSTRUCT_CERTIFY_ALLOW_PAID=1)' },
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: 'artifact',
|
|
660
|
+
emoji: '📋',
|
|
661
|
+
category: 'Work',
|
|
662
|
+
core: false,
|
|
663
|
+
description: 'Plan or locally execute manifest-backed artifact workflows with execution provenance',
|
|
664
|
+
usage: 'construct artifact <validate|workflow> ...',
|
|
665
|
+
subcommands: [
|
|
666
|
+
{ name: 'validate', desc: 'Run manifest structure, citation, and reviewer checks' },
|
|
667
|
+
{ name: 'workflow', desc: 'Return a truthful plan/run report; --apply only runs local validation/export after approval' },
|
|
668
|
+
],
|
|
568
669
|
},
|
|
569
670
|
{
|
|
570
671
|
name: 'doc',
|
|
@@ -635,13 +736,19 @@ export const CLI_COMMANDS = [
|
|
|
635
736
|
emoji: '🎬',
|
|
636
737
|
category: 'Work',
|
|
637
738
|
core: false,
|
|
638
|
-
description: '
|
|
639
|
-
usage: 'construct demo <name> [--format=gif|mp4|webm] [--out=<path>] [--source-only]',
|
|
739
|
+
description: 'Run guided demos via construct chat (default) or record VHS/asciinema tapes',
|
|
740
|
+
usage: 'construct demo <list|init|record|name> [--surface=chat|web|tape|dashboard] [--format=gif|mp4|webm] [--out=<path>] [--source-only]',
|
|
640
741
|
strictFlags: true,
|
|
641
742
|
options: [
|
|
642
|
-
{ flag: '--
|
|
643
|
-
{ flag: '--
|
|
644
|
-
{ flag: '--
|
|
743
|
+
{ flag: '--surface=<s>', desc: 'chat (default) | web | tape | dashboard' },
|
|
744
|
+
{ flag: '--model=<id>', desc: 'Pin model for chat demo' },
|
|
745
|
+
{ flag: '--web', desc: 'Open web chat (/chat/) instead of terminal Ink' },
|
|
746
|
+
{ flag: '--plain', desc: 'Linear chat renderer (accessibility / non-TTY)' },
|
|
747
|
+
{ flag: '--free', desc: 'OpenRouter free-router mode for chat demo' },
|
|
748
|
+
{ flag: '--format=<f>', desc: 'gif (default) | mp4 | webm (tape surface only)' },
|
|
749
|
+
{ flag: '--out=<path>', desc: 'Output path (tape recording)' },
|
|
750
|
+
{ flag: '--from=<t>', desc: 'Template for init: quickstart | diagram' },
|
|
751
|
+
{ flag: '--source-only', desc: 'Tape: write .tape only; skip recording' },
|
|
645
752
|
],
|
|
646
753
|
},
|
|
647
754
|
{
|
|
@@ -668,6 +775,20 @@ export const CLI_COMMANDS = [
|
|
|
668
775
|
description: 'Deployment mode configuration',
|
|
669
776
|
usage: 'construct config <get|set>',
|
|
670
777
|
},
|
|
778
|
+
{
|
|
779
|
+
name: 'sources',
|
|
780
|
+
emoji: '🔗',
|
|
781
|
+
category: 'Advanced',
|
|
782
|
+
core: false,
|
|
783
|
+
description: 'Manage typed integration source targets in construct.config.json',
|
|
784
|
+
usage: 'construct sources list|add|remove|validate',
|
|
785
|
+
subcommands: [
|
|
786
|
+
{ name: 'list', desc: 'Show config targets, legacy env merge, and effective set' },
|
|
787
|
+
{ name: 'add <provider> <id> <selector-json>', desc: 'Add a typed target (github, jira, linear, slack)' },
|
|
788
|
+
{ name: 'remove <id>', desc: 'Remove a config target by id' },
|
|
789
|
+
{ name: 'validate', desc: 'Validate sources.targets in construct.config.json' },
|
|
790
|
+
],
|
|
791
|
+
},
|
|
671
792
|
{
|
|
672
793
|
name: 'uninstall',
|
|
673
794
|
emoji: '🧹',
|
|
@@ -876,8 +997,8 @@ export const CLI_COMMANDS = [
|
|
|
876
997
|
emoji: '🔑',
|
|
877
998
|
category: 'Integrations',
|
|
878
999
|
core: false,
|
|
879
|
-
description: 'Manage provider credentials (set, rotate, revoke, list)',
|
|
880
|
-
usage: 'construct creds <list|set|rotate|revoke|test>',
|
|
1000
|
+
description: 'Manage provider credentials (login, set, rotate, revoke, list, test)',
|
|
1001
|
+
usage: 'construct creds <list|login|set|rotate|revoke|test>',
|
|
881
1002
|
},
|
|
882
1003
|
{
|
|
883
1004
|
name: 'providers',
|
|
@@ -991,8 +1112,8 @@ export const CLI_COMMANDS = [
|
|
|
991
1112
|
emoji: '📄',
|
|
992
1113
|
category: 'Diagnostics',
|
|
993
1114
|
core: false,
|
|
994
|
-
description: '
|
|
995
|
-
usage: 'construct docs:site
|
|
1115
|
+
description: 'Regenerate generated reference pages under docs/reference/',
|
|
1116
|
+
usage: 'construct docs:site [--check]',
|
|
996
1117
|
},
|
|
997
1118
|
{
|
|
998
1119
|
name: 'beads:stats',
|
|
@@ -1023,7 +1144,13 @@ export const CLI_COMMANDS = [
|
|
|
1023
1144
|
{ name: 'lint:templates', category: 'Internal', core: false, internal: true, description: 'Internal lint: shipped templates', usage: 'construct lint:templates' },
|
|
1024
1145
|
{ name: 'lint:prompts', category: 'Internal', core: false, internal: true, description: 'Internal lint: specialist prompt frontmatter + sections', usage: 'construct lint:prompts' },
|
|
1025
1146
|
{ name: 'specialist', category: 'Internal', core: false, internal: true, description: 'Maintainer tool: scaffold, edit, and lint specialist prompts', usage: 'construct specialist <create|edit|lint>' },
|
|
1026
|
-
{ name: 'registry:status', category: 'Internal', core: false, internal: true, description: 'Dev: capability
|
|
1147
|
+
{ 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]' },
|
|
1149
|
+
{ name: 'registry:generate-docs', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Generate docs/reference/capabilities.md from registry', usage: 'construct registry:generate-docs' },
|
|
1150
|
+
{ 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
|
+
{ 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
|
+
{ 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]' },
|
|
1153
|
+
{ name: 'rules', category: 'Diagnostics', core: false, internal: false, surface: 'thin-cli', description: 'Rule and hook reference telemetry rollup', usage: 'construct rules usage [--since=30d]' },
|
|
1027
1154
|
{ name: 'evaluator:rubrics', category: 'Internal', core: false, internal: true, description: 'Internal: list registered evaluator rubrics', usage: 'construct evaluator:rubrics' },
|
|
1028
1155
|
{ name: 'activation:status', category: 'Internal', core: false, internal: true, description: 'Internal: agent activation telemetry', usage: 'construct activation:status' },
|
|
1029
1156
|
{ name: 'prune', category: 'Internal', core: false, internal: true, description: 'Internal: prune ephemeral storage entries', usage: 'construct prune' },
|
|
@@ -1031,6 +1158,10 @@ export const CLI_COMMANDS = [
|
|
|
1031
1158
|
{ name: 'resources', category: 'Internal', core: false, internal: true, description: 'Internal: resource probe', usage: 'construct resources' },
|
|
1032
1159
|
];
|
|
1033
1160
|
|
|
1161
|
+
for (const cmd of CLI_COMMANDS) {
|
|
1162
|
+
if (!cmd.surface) cmd.surface = surfaceForCommand(cmd.name);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1034
1165
|
/** Flat list of all top-level command names (for completions). */
|
|
1035
1166
|
export const COMMAND_NAMES = CLI_COMMANDS.filter((c) => !c.internal).map((c) => c.name);
|
|
1036
1167
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/cli-service-inventory.mjs — auditable public CLI/catalog/docs inventory.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { CLI_COMMANDS } from './cli-commands.mjs';
|
|
8
|
+
|
|
9
|
+
function slugify(category) {
|
|
10
|
+
return category.toLowerCase().replace(/&/g, 'and').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function handlerNames(rootDir) {
|
|
14
|
+
const source = fs.readFileSync(path.join(rootDir, 'bin', 'construct'), 'utf8');
|
|
15
|
+
const names = new Set();
|
|
16
|
+
for (const match of source.matchAll(/\n {2,3}\[\s*'([^']+)'\s*,/g)) names.add(match[1]);
|
|
17
|
+
return names;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The catalog is the public-service source of truth. This projection joins it
|
|
22
|
+
* to runtime dispatch and the generated reference pages so drift is observable
|
|
23
|
+
* without treating internal handlers as public services.
|
|
24
|
+
*/
|
|
25
|
+
export function buildCliServiceInventory({ rootDir = process.cwd() } = {}) {
|
|
26
|
+
const handlers = handlerNames(rootDir);
|
|
27
|
+
return CLI_COMMANDS.filter((spec) => !spec.internal).map((spec) => {
|
|
28
|
+
const page = path.join(rootDir, 'docs', 'reference', 'cli', `${slugify(spec.category)}.md`);
|
|
29
|
+
const pageText = fs.existsSync(page) ? fs.readFileSync(page, 'utf8') : '';
|
|
30
|
+
return {
|
|
31
|
+
name: spec.name,
|
|
32
|
+
category: spec.category,
|
|
33
|
+
runnable: handlers.has(spec.name),
|
|
34
|
+
documented: pageText.includes(`## construct ${spec.name}`),
|
|
35
|
+
usage: spec.usage,
|
|
36
|
+
subcommands: (spec.subcommands ?? []).map((sub) => ({
|
|
37
|
+
name: typeof sub === 'string' ? sub : sub.name,
|
|
38
|
+
documented: typeof sub === 'string' ? true : Boolean(sub.desc || sub.description),
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
package/lib/comment-lint.mjs
CHANGED
|
@@ -94,7 +94,9 @@ function requiresHeader(rel) {
|
|
|
94
94
|
return { required: false, type: null };
|
|
95
95
|
}
|
|
96
96
|
// Exclude test fixture data files — these are project artifacts, not source files.
|
|
97
|
-
if (rel.startsWith('tests/fixtures/projects/')
|
|
97
|
+
if (rel.startsWith('tests/fixtures/projects/')
|
|
98
|
+
|| rel.startsWith('tests/fixtures/artifacts/')
|
|
99
|
+
|| rel.startsWith('tests/fixtures/document-io/')) {
|
|
98
100
|
return { required: false, type: null };
|
|
99
101
|
}
|
|
100
102
|
// Markdown files always get markdown-style headers, even if the directory
|
|
@@ -158,7 +160,7 @@ const BANNED = [
|
|
|
158
160
|
{ pattern: /<!--.*\b(?:added for|added recently|just added|new:)\b.*-->/i, label: 'point-in-time in markdown comment' },
|
|
159
161
|
{ pattern: /<!--.*\b(?:used by|called from|only consumer)\b.*-->/i, label: 'caller reference in markdown comment' },
|
|
160
162
|
// TODO without owner
|
|
161
|
-
{ pattern: new RegExp(`${CMT}\\s*TODO(
|
|
163
|
+
{ pattern: new RegExp(`${CMT}\\s*TODO(?!\\s*\\(\\w+\\)\\s*:)`, 'i'), label: 'TODO without owner — use: TODO(owner): what and why' }, // construct-lint-ignore
|
|
162
164
|
];
|
|
163
165
|
|
|
164
166
|
// Files whose content is authored precisely to demonstrate banned patterns
|
|
@@ -319,7 +321,7 @@ function checkArtifactBanned(content, rel) {
|
|
|
319
321
|
// Internal specialist role ids (cx-business-strategist, cx-product-manager, …) are
|
|
320
322
|
// implementation detail; in a consuming project's deliverable they read as a tool-identity
|
|
321
323
|
// leak. The set is anchored to the real role ids from specialists/registry.json — an
|
|
322
|
-
// open-ended /cx-[a-z-]+/ also matches unrelated npm packages (cx-
|
|
324
|
+
// open-ended /cx-[a-z-]+/ also matches unrelated npm packages (cx-ray, cx-pro, cx-widget)
|
|
323
325
|
// and would fail the release gate on legitimate user content. Drift from the registry is
|
|
324
326
|
// caught by tests/tool-invisibility.test.mjs, not at runtime: this module sits on the hook
|
|
325
327
|
// path and must never throw on a missing or malformed registry file.
|
|
@@ -327,7 +329,7 @@ function checkArtifactBanned(content, rel) {
|
|
|
327
329
|
export const KNOWN_CX_ROLE_IDS = [
|
|
328
330
|
'accessibility', 'ai-engineer', 'architect', 'business-strategist', 'data-analyst',
|
|
329
331
|
'data-engineer', 'debugger', 'designer', 'devil-advocate', 'docs-keeper', 'engineer',
|
|
330
|
-
'evaluator', 'explorer', 'legal-compliance', 'operations', 'orchestrator',
|
|
332
|
+
'evaluator', 'explorer', 'legal-compliance', 'operations', 'oracle', 'orchestrator',
|
|
331
333
|
'platform-engineer', 'product-manager', 'qa', 'rd-lead', 'release-manager', 'researcher',
|
|
332
334
|
'reviewer', 'security', 'sre', 'test-automation', 'trace-reviewer', 'ux-researcher',
|
|
333
335
|
];
|