@geraldmaron/construct 1.1.1 → 1.2.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 +29 -19
- package/bin/construct +311 -81
- 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 +112 -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/audit-skills.mjs +4 -0
- package/lib/audit-specialists.mjs +285 -0
- package/lib/audit-trail.mjs +1 -1
- package/lib/auto-docs.mjs +87 -18
- 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 +245 -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 +129 -15
- package/lib/comment-lint.mjs +6 -4
- package/lib/config/schema.mjs +36 -5
- 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/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 +360 -36
- package/lib/document-extract.mjs +44 -4
- package/lib/document-ingest.mjs +29 -20
- package/lib/embed/cli.mjs +2 -2
- package/lib/embed/daemon.mjs +18 -46
- package/lib/embed/worker.mjs +2 -2
- 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/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 +4 -5
- 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 +27 -97
- 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/daemon.mjs +2 -0
- package/lib/intake/git-queue.mjs +9 -8
- 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 +84 -9
- 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/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 +252 -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 +228 -7
- 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 +480 -0
- package/specialists/artifact-manifest.schema.json +53 -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-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
package/bin/construct
CHANGED
|
@@ -12,10 +12,10 @@ import os from 'node:os';
|
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { spawnSync } from 'node:child_process';
|
|
14
14
|
|
|
15
|
-
import { CLI_COMMANDS,
|
|
15
|
+
import { CLI_COMMANDS, CATEGORY_ORDER, formatCommandHelp } from '../lib/cli-commands.mjs';
|
|
16
16
|
import { buildStatus, formatStatusReport } from '../lib/status.mjs';
|
|
17
17
|
import { validateRegistry } from '../lib/validator.mjs';
|
|
18
|
-
import { readCurrentModels, readOpenRouterApiKeyFromOpenCodeConfig, applyToEnv, resetEnv,
|
|
18
|
+
import { readCurrentModels, readOpenRouterApiKeyFromOpenCodeConfig, applyToEnv, resetEnv, setModelWithTierInference } from '../lib/model-router.mjs';
|
|
19
19
|
import { pollFreeModels, topForTier, selectForTier } from '../lib/model-free-selector.mjs';
|
|
20
20
|
import { cmdMcpList, cmdMcpAdd, cmdMcpRemove, cmdMcpInfo } from '../lib/mcp-manager.mjs';
|
|
21
21
|
import { cmdOllama } from '../lib/ollama-manager.mjs';
|
|
@@ -26,7 +26,8 @@ import { runUpdate } from '../lib/update.mjs';
|
|
|
26
26
|
import { runUpgrade } from '../lib/upgrade.mjs';
|
|
27
27
|
import { runUninstall } from '../lib/uninstall/uninstall.mjs';
|
|
28
28
|
import { maybeFirstInvocationProbe } from '../lib/install/first-invocation.mjs';
|
|
29
|
-
import { loadConstructEnv, getUserEnvPath
|
|
29
|
+
import { loadConstructEnv, getUserEnvPath } from '../lib/env-config.mjs';
|
|
30
|
+
import { ensureConstructCredentials } from '../lib/providers/credential-bootstrap.mjs';
|
|
30
31
|
import {
|
|
31
32
|
loadProjectConfig,
|
|
32
33
|
writeProjectConfig,
|
|
@@ -39,30 +40,30 @@ import {
|
|
|
39
40
|
import { validateProjectConfig } from '../lib/config/schema.mjs';
|
|
40
41
|
import {
|
|
41
42
|
DEPLOYMENT_MODES,
|
|
42
|
-
DEFAULT_DEPLOYMENT_MODE,
|
|
43
43
|
DEPLOYMENT_MODE_ENV_KEY,
|
|
44
44
|
describeDeploymentMode,
|
|
45
|
-
describeResourceLine,
|
|
46
45
|
getDeploymentMode,
|
|
47
|
-
isValidDeploymentMode,
|
|
48
46
|
resolveResourceMode,
|
|
49
47
|
} from '../lib/deployment-mode.mjs';
|
|
50
48
|
import { runDistillCli } from '../lib/distill.mjs';
|
|
51
49
|
import { runIngestCli } from '../lib/document-ingest.mjs';
|
|
52
50
|
import { runInferCli } from '../lib/schema-infer.mjs';
|
|
53
|
-
import {
|
|
51
|
+
import { generateCompletions, getCompletionScript } from '../lib/completions.mjs';
|
|
54
52
|
import { runHeadhunt, listTeamTemplates } from '../lib/headhunt.mjs';
|
|
55
53
|
import {
|
|
56
54
|
getLockStatus,
|
|
57
55
|
cleanupStaleLock,
|
|
58
56
|
cleanupStaleQueue,
|
|
59
57
|
readQueue,
|
|
60
|
-
formatStatus,
|
|
61
58
|
} from '../lib/beads-lock.mjs';
|
|
62
59
|
import { runBd, getHumanStatus, acquireMergeSlot, releaseMergeSlot } from '../lib/beads-client.mjs';
|
|
63
60
|
import { auditSkills, runAuditSkillsCli } from '../lib/audit-skills.mjs';
|
|
61
|
+
import { auditSpecialists, runAuditSpecialistsCli } from '../lib/audit-specialists.mjs';
|
|
62
|
+
import { runCapabilityLedgerAuditCli } from '../lib/capability-ledger.mjs';
|
|
63
|
+
import { runCorpusInventoryAuditCli } from '../lib/test-corpus-inventory.mjs';
|
|
64
|
+
import { runArtifactValidateCli } from '../lib/artifact-release-gate.mjs';
|
|
64
65
|
import { runTeamReviewCli } from '../lib/telemetry/team-rollup.mjs';
|
|
65
|
-
import {
|
|
66
|
+
import { startDashboard, startServices } from '../lib/service-manager.mjs';
|
|
66
67
|
import { readCostLog, summarizeCostData, formatCostReport, clearCostLog } from '../lib/cost.mjs';
|
|
67
68
|
import { readEfficiencyLog, summarizeEfficiencyData, formatEfficiencyReport } from '../lib/efficiency.mjs';
|
|
68
69
|
import { resolveColors } from '../lib/term-format.mjs';
|
|
@@ -74,6 +75,7 @@ import { runPressureRelease } from '../lib/runtime-pressure.mjs';
|
|
|
74
75
|
|
|
75
76
|
const ROOT_DIR = path.resolve(import.meta.dirname, '..');
|
|
76
77
|
const HOME = os.homedir();
|
|
78
|
+
ensureConstructCredentials({ env: process.env, cwd: ROOT_DIR, home: HOME });
|
|
77
79
|
const ENV = loadConstructEnv({ rootDir: ROOT_DIR, homeDir: HOME, env: process.env });
|
|
78
80
|
for (const [key, value] of Object.entries(ENV)) {
|
|
79
81
|
if (!(key in process.env)) process.env[key] = value;
|
|
@@ -170,41 +172,51 @@ function runNodeScript(scriptPath, args = [], extraEnv = {}, { exitOnError = tru
|
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
async function cmdRegistryStatus(args = []) {
|
|
173
|
-
const {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (!existsSync(matrixPath)) {
|
|
178
|
-
errorln('Capability matrix not found. Run "construct sync" or ensure tests/registry/capability-matrix.json exists.');
|
|
179
|
-
process.exit(1);
|
|
180
|
-
}
|
|
175
|
+
const { runRegistryStatus } = await import('../lib/registry/cli.mjs');
|
|
176
|
+
const code = await runRegistryStatus(args, { rootDir: ROOT_DIR, println, errorln });
|
|
177
|
+
if (code) process.exit(code);
|
|
178
|
+
}
|
|
181
179
|
|
|
182
|
-
|
|
183
|
-
const
|
|
180
|
+
async function cmdRegistryValidate(args = []) {
|
|
181
|
+
const { runRegistryValidate } = await import('../lib/registry/cli.mjs');
|
|
182
|
+
const code = await runRegistryValidate(args, { rootDir: ROOT_DIR, println, errorln });
|
|
183
|
+
if (code) process.exit(code);
|
|
184
|
+
}
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
async function cmdRegistryGenerateDocs(args = []) {
|
|
187
|
+
const { runRegistryGenerateDocs } = await import('../lib/registry/cli.mjs');
|
|
188
|
+
const code = await runRegistryGenerateDocs(args, { rootDir: ROOT_DIR, println, errorln });
|
|
189
|
+
if (code) process.exit(code);
|
|
190
|
+
}
|
|
189
191
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
async function cmdRulesUsage(args = []) {
|
|
193
|
+
const { summarizeRuleCalls } = await import('../lib/telemetry/rule-calls.mjs');
|
|
194
|
+
const { summarizeHookCalls } = await import('../lib/telemetry/hook-calls.mjs');
|
|
195
|
+
const sub = args[0] || 'usage';
|
|
196
|
+
const sinceFlag = args.find((a) => a.startsWith('--since='));
|
|
197
|
+
const since = sinceFlag ? sinceFlag.split('=')[1] : '30d';
|
|
193
198
|
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
println(`
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
for (const [
|
|
201
|
-
const icon = status.quality_score === null ? '⚪' : status.quality_score >= 0.9 ? '🟢' : status.quality_score >= 0.7 ? '🟡' : '🔴';
|
|
202
|
-
const score = status.quality_score !== null ? `${(status.quality_score * 100).toFixed(0)}%` : 'N/A';
|
|
203
|
-
const date = status.last_validated ? new Date(status.last_validated).toLocaleDateString() : 'never';
|
|
204
|
-
println(` ${icon} ${name.padEnd(10)} | Score: ${score.padEnd(5)} | Validated: ${date}`);
|
|
205
|
-
}
|
|
199
|
+
if (sub === 'usage') {
|
|
200
|
+
const rules = summarizeRuleCalls({ since });
|
|
201
|
+
const hooks = summarizeHookCalls({ since });
|
|
202
|
+
println(`Rule references — last ${since} (${rules.total} events)\n`);
|
|
203
|
+
const ruleRows = Object.entries(rules.rules).sort((a, b) => b[1] - a[1]);
|
|
204
|
+
if (ruleRows.length === 0) println(' No rule reference events in the window.');
|
|
205
|
+
for (const [path, count] of ruleRows) println(` ${path.padEnd(50)} refs=${count}`);
|
|
206
206
|
println('');
|
|
207
|
+
println(`Hook fires — last ${since} (${hooks.totalEvents ?? 0} events)\n`);
|
|
208
|
+
const hookEntries = Object.entries(hooks.hooks ?? {}).sort((a, b) => b[1].calls - a[1].calls);
|
|
209
|
+
if (!hookEntries.length) {
|
|
210
|
+
println(' No hook events in window.');
|
|
211
|
+
} else {
|
|
212
|
+
for (const [id, s] of hookEntries) {
|
|
213
|
+
println(` ${id.padEnd(40)} calls=${s.calls} blocked=${s.blocked ?? 0} errors=${s.errors ?? 0}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
207
217
|
}
|
|
218
|
+
errorln(`Unknown rules subcommand: ${sub}. Available: usage`);
|
|
219
|
+
process.exit(1);
|
|
208
220
|
}
|
|
209
221
|
|
|
210
222
|
async function cmdStatus() {
|
|
@@ -255,22 +267,6 @@ async function cmdStatus() {
|
|
|
255
267
|
} catch { /* best-effort surface; never block status */ }
|
|
256
268
|
}
|
|
257
269
|
|
|
258
|
-
async function cmdShow() {
|
|
259
|
-
const status = await buildStatus({ rootDir: ROOT_DIR, cwd: process.cwd(), homeDir: HOME, env: process.env });
|
|
260
|
-
const dashboard = readDashboardState(HOME);
|
|
261
|
-
println('');
|
|
262
|
-
println('Construct Services');
|
|
263
|
-
println('══════════════════');
|
|
264
|
-
println('');
|
|
265
|
-
if (dashboard) println(` • Managed dashboard PID ${dashboard.pid} on ${dashboard.url}`);
|
|
266
|
-
for (const service of status.system.services) {
|
|
267
|
-
const icon = service.status === 'healthy' ? '✓' : service.status === 'degraded' ? '⚠' : '✗';
|
|
268
|
-
const note = service.note ? ` (${service.note})` : '';
|
|
269
|
-
println(` ${icon} ${service.name.padEnd(28)} ${service.url}${note}`);
|
|
270
|
-
}
|
|
271
|
-
println('');
|
|
272
|
-
}
|
|
273
|
-
|
|
274
270
|
async function cmdSync(args) {
|
|
275
271
|
const { startOpLog } = await import('../lib/op-log.mjs');
|
|
276
272
|
const opLog = startOpLog('sync', { homeDir: HOME });
|
|
@@ -677,6 +673,14 @@ async function cmdDoctor() {
|
|
|
677
673
|
|
|
678
674
|
add('Node.js 20+ (recommended)', Number.parseInt(process.versions.node.split('.')[0], 10) >= 20);
|
|
679
675
|
add('npm available', true);
|
|
676
|
+
const npmDevdir = process.env.npm_config_devdir ?? process.env.NPM_CONFIG_DEVDIR;
|
|
677
|
+
if (npmDevdir) {
|
|
678
|
+
add(
|
|
679
|
+
'npm env: npm_config_devdir set (Cursor sandbox) — npm 11.2+ warns on every `npm run`. Unset: unset npm_config_devdir NPM_CONFIG_DEVDIR. Or run scripts directly: node scripts/... / construct ...',
|
|
680
|
+
false,
|
|
681
|
+
true,
|
|
682
|
+
);
|
|
683
|
+
}
|
|
680
684
|
const constructOnPath = spawnSync('zsh', ['-lc', 'command -v construct'], { encoding: 'utf8', env: process.env });
|
|
681
685
|
const constructPath = constructOnPath.status === 0 ? constructOnPath.stdout.trim() : '';
|
|
682
686
|
const constructVersion = constructPath
|
|
@@ -854,6 +858,8 @@ async function cmdDoctor() {
|
|
|
854
858
|
add('Headhunt classifier agents exist in registry', classifierOrphans.length === 0);
|
|
855
859
|
const skillAudit = auditSkills({ rootDir: ROOT_DIR, silent: true });
|
|
856
860
|
add('No declared skills missing on disk', skillAudit.pass, false);
|
|
861
|
+
const specialistAudit = auditSpecialists({ rootDir: ROOT_DIR, silent: true });
|
|
862
|
+
add('Specialist/skill audit cross-checks', specialistAudit.pass, false);
|
|
857
863
|
const { lintResearchRepo } = await import('../lib/research-lint.mjs');
|
|
858
864
|
const researchLintResults = lintResearchRepo({ rootDir: process.cwd() });
|
|
859
865
|
add('Research artifacts meet minimum evidence structure', researchLintResults.every((entry) => entry.errors.length === 0), true);
|
|
@@ -916,6 +922,14 @@ async function cmdDoctor() {
|
|
|
916
922
|
add('Cross-surface adapter parity', false);
|
|
917
923
|
}
|
|
918
924
|
|
|
925
|
+
try {
|
|
926
|
+
const { checkProjectAdaptersForDoctor } = await import('../lib/doctor/project-adapters.mjs');
|
|
927
|
+
const projectAdapters = checkProjectAdaptersForDoctor({ rootDir: ROOT_DIR, projectDir: process.cwd() });
|
|
928
|
+
add(projectAdapters.label, projectAdapters.ok, projectAdapters.warning);
|
|
929
|
+
} catch {
|
|
930
|
+
add('Project adapters', false, true);
|
|
931
|
+
}
|
|
932
|
+
|
|
919
933
|
try {
|
|
920
934
|
const { validateSkills } = await import('../lib/validators/skills.mjs');
|
|
921
935
|
const skillsRoot = path.join(ROOT_DIR, 'skills');
|
|
@@ -928,6 +942,28 @@ async function cmdDoctor() {
|
|
|
928
942
|
add('Skill structure', false, true);
|
|
929
943
|
}
|
|
930
944
|
|
|
945
|
+
try {
|
|
946
|
+
const { lintWorkflowSkillVerification } = await import('../lib/registry/skill-verification.mjs');
|
|
947
|
+
const wf = lintWorkflowSkillVerification(path.join(ROOT_DIR, 'skills'));
|
|
948
|
+
const wfLabel = wf.warnings.length
|
|
949
|
+
? `Workflow skill verification (${wf.checked} checked, ${wf.warnings.length} missing bars)`
|
|
950
|
+
: `Workflow skill verification (${wf.checked} checked)`;
|
|
951
|
+
add(wfLabel, wf.valid && wf.warnings.length === 0, true);
|
|
952
|
+
} catch {
|
|
953
|
+
add('Workflow skill verification', false, true);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
try {
|
|
957
|
+
const { validateCapabilityRegistry } = await import('../lib/registry/validate.mjs');
|
|
958
|
+
const reg = validateCapabilityRegistry({ rootDir: ROOT_DIR });
|
|
959
|
+
const regLabel = reg.warnings.length
|
|
960
|
+
? `Capability registry (${reg.count} entries, ${reg.warnings.length} warnings)`
|
|
961
|
+
: `Capability registry (${reg.count} entries)`;
|
|
962
|
+
add(regLabel, reg.valid, reg.errors.length > 0);
|
|
963
|
+
} catch {
|
|
964
|
+
add('Capability registry', false, true);
|
|
965
|
+
}
|
|
966
|
+
|
|
931
967
|
try {
|
|
932
968
|
const { describeBreakers, STATES } = await import('../lib/providers/circuit-breaker.mjs');
|
|
933
969
|
const breakers = describeBreakers();
|
|
@@ -1036,7 +1072,7 @@ async function cmdDoctor() {
|
|
|
1036
1072
|
}
|
|
1037
1073
|
|
|
1038
1074
|
// Agent contracts integrity
|
|
1039
|
-
const { getAllContracts
|
|
1075
|
+
const { getAllContracts } = await import('../lib/specialist-contracts.mjs');
|
|
1040
1076
|
const contracts = getAllContracts();
|
|
1041
1077
|
add('Agent contracts loaded', contracts.length > 0);
|
|
1042
1078
|
if (contracts.length > 0) {
|
|
@@ -1242,7 +1278,7 @@ async function cmdDev(args = []) {
|
|
|
1242
1278
|
opLog.event('selection', { services: selected ? [...selected] : 'all' });
|
|
1243
1279
|
|
|
1244
1280
|
// Auto-magic health check — catch missing prerequisites before starting services
|
|
1245
|
-
const { quickHealthCheck,
|
|
1281
|
+
const { quickHealthCheck, resolveCredentials } = await import('../lib/health-check.mjs');
|
|
1246
1282
|
|
|
1247
1283
|
// Resolve credentials from env, .env files, and 1Password before starting services
|
|
1248
1284
|
const resolvedCreds = await resolveCredentials({ homeDir: HOME });
|
|
@@ -1524,6 +1560,7 @@ async function cmdExport(args) {
|
|
|
1524
1560
|
const toFlag = args.find((a) => a.startsWith('--to='))?.split('=')[1];
|
|
1525
1561
|
const outFlag = args.find((a) => a.startsWith('--output='))?.split('=')[1];
|
|
1526
1562
|
const detectOnly = args.includes('--detect');
|
|
1563
|
+
const figures = !args.includes('--no-figures');
|
|
1527
1564
|
|
|
1528
1565
|
const { detect, exportMarkdown, EXPORT_FORMATS } = await import('../lib/document-export.mjs');
|
|
1529
1566
|
|
|
@@ -1534,7 +1571,7 @@ async function cmdExport(args) {
|
|
|
1534
1571
|
}
|
|
1535
1572
|
|
|
1536
1573
|
if (!inputPath) {
|
|
1537
|
-
errorln('Usage: construct export <markdown-file> --to=<pdf|docx|html> [--output=<path>] [--detect]');
|
|
1574
|
+
errorln('Usage: construct export <markdown-file> --to=<pdf|docx|html> [--output=<path>] [--figures|--no-figures] [--detect]');
|
|
1538
1575
|
process.exit(1);
|
|
1539
1576
|
}
|
|
1540
1577
|
if (!toFlag) {
|
|
@@ -1544,7 +1581,13 @@ async function cmdExport(args) {
|
|
|
1544
1581
|
|
|
1545
1582
|
const resolvedIn = path.resolve(process.cwd(), inputPath);
|
|
1546
1583
|
const resolvedOut = outFlag ? path.resolve(process.cwd(), outFlag) : null;
|
|
1547
|
-
const result = exportMarkdown({
|
|
1584
|
+
const result = exportMarkdown({
|
|
1585
|
+
inputPath: resolvedIn,
|
|
1586
|
+
outputPath: resolvedOut,
|
|
1587
|
+
format: toFlag,
|
|
1588
|
+
figures: toFlag === 'pdf' ? figures : false,
|
|
1589
|
+
repoRoot: ROOT_DIR,
|
|
1590
|
+
});
|
|
1548
1591
|
if (!result.ok) {
|
|
1549
1592
|
errorln(result.message);
|
|
1550
1593
|
process.exit(result.missing?.length ? 2 : 1);
|
|
@@ -1552,6 +1595,36 @@ async function cmdExport(args) {
|
|
|
1552
1595
|
ok(result.message);
|
|
1553
1596
|
}
|
|
1554
1597
|
|
|
1598
|
+
async function cmdPublish(args) {
|
|
1599
|
+
const { runPublishCli } = await import('../lib/publish.mjs');
|
|
1600
|
+
const { exitCode } = await runPublishCli(args, { cwd: process.cwd(), repoRoot: ROOT_DIR });
|
|
1601
|
+
process.exit(exitCode ?? 0);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
async function cmdTools(args) {
|
|
1605
|
+
const [sub, ...rest] = args;
|
|
1606
|
+
if (sub !== 'detect') {
|
|
1607
|
+
errorln('Usage: construct tools detect [--json] [--figures] [--no-figures] [--demo=NAME] [--dashboard-demo=NAME]');
|
|
1608
|
+
process.exit(1);
|
|
1609
|
+
}
|
|
1610
|
+
const { detectPublishPipeline, formatToolsDetectReport } = await import('../lib/publish-tooling.mjs');
|
|
1611
|
+
const json = rest.includes('--json');
|
|
1612
|
+
const figures = !rest.includes('--no-figures');
|
|
1613
|
+
const demos = rest.filter((a) => a.startsWith('--demo=')).map((a) => a.slice(7));
|
|
1614
|
+
const dashboardDemos = rest.filter((a) => a.startsWith('--dashboard-demo=')).map((a) => a.slice(17));
|
|
1615
|
+
const detection = detectPublishPipeline({
|
|
1616
|
+
format: 'pdf',
|
|
1617
|
+
includeFigures: figures,
|
|
1618
|
+
includeTerminalDemo: demos.length > 0,
|
|
1619
|
+
includeDashboardDemo: dashboardDemos.length > 0,
|
|
1620
|
+
cwd: process.cwd(),
|
|
1621
|
+
repoRoot: ROOT_DIR,
|
|
1622
|
+
});
|
|
1623
|
+
if (json) println(formatToolsDetectReport(detection, { json: true }));
|
|
1624
|
+
else println(formatToolsDetectReport(detection));
|
|
1625
|
+
process.exit(detection.present ? 0 : 2);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1555
1628
|
async function cmdInfer(args) {
|
|
1556
1629
|
try {
|
|
1557
1630
|
const result = await runInferCli(args, { cwd: process.cwd() });
|
|
@@ -1667,7 +1740,7 @@ async function cmdPrune(args) {
|
|
|
1667
1740
|
println(`.cx/ now at ${Math.round(after.totalCxBytes / 1024 / 1024)}MB / ${Math.round(after.totalCxCap / 1024 / 1024)}MB cap (${Math.round(after.totalCxUsageRatio * 100)}%).`);
|
|
1668
1741
|
}
|
|
1669
1742
|
|
|
1670
|
-
async function
|
|
1743
|
+
async function _cmdCosts(args) {
|
|
1671
1744
|
const sub = args[0] || 'status';
|
|
1672
1745
|
const {
|
|
1673
1746
|
getDailySpend,
|
|
@@ -1882,7 +1955,7 @@ async function cmdOverrides(args) {
|
|
|
1882
1955
|
process.exit(1);
|
|
1883
1956
|
}
|
|
1884
1957
|
|
|
1885
|
-
async function
|
|
1958
|
+
async function _cmdPricing(args) {
|
|
1886
1959
|
const sub = args[0] || 'status';
|
|
1887
1960
|
const {
|
|
1888
1961
|
describePricingCatalogFreshness,
|
|
@@ -2080,7 +2153,7 @@ async function cmdEmbeddedTriage(args) {
|
|
|
2080
2153
|
input = fs.readFileSync(0, 'utf8');
|
|
2081
2154
|
}
|
|
2082
2155
|
if (!input.trim() && !ingestion?.error) {
|
|
2083
|
-
//
|
|
2156
|
+
// Embedded-contract verb: an embedder that pipes empty/no input
|
|
2084
2157
|
// must still get a parseable, versioned envelope — not a bare exit. Emit a
|
|
2085
2158
|
// typed error envelope on stdout so the contract holds, and exit non-zero so
|
|
2086
2159
|
// shell callers still see failure.
|
|
@@ -3078,7 +3151,7 @@ async function cmdWorkspace(args) {
|
|
|
3078
3151
|
const sub = args[0];
|
|
3079
3152
|
if (!sub || sub === '--help' || sub === '-h') { printWorkspaceHelp(); return; }
|
|
3080
3153
|
|
|
3081
|
-
const { createWorkspace, getWorkspace, listWorkspaces
|
|
3154
|
+
const { createWorkspace, getWorkspace, listWorkspaces } = await import('../lib/embed/workspaces.mjs');
|
|
3082
3155
|
|
|
3083
3156
|
if (sub === 'list') {
|
|
3084
3157
|
const workspaces = listWorkspaces();
|
|
@@ -3192,7 +3265,6 @@ async function cmdRecommendations(args) {
|
|
|
3192
3265
|
const reasonFlag = args.find(a => a.startsWith('--reason='))?.split('=').slice(1).join('=');
|
|
3193
3266
|
const suppressDaysFlag = args.find(a => a.startsWith('--suppress-days='))?.split('=')[1];
|
|
3194
3267
|
try {
|
|
3195
|
-
const { dedupKey: computeKey } = await import('../lib/embed/recommendation-store.mjs');
|
|
3196
3268
|
const key = `${recType}::${recTitle.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 60)}`;
|
|
3197
3269
|
const { dismissRecommendation } = await import('../lib/embed/recommendation-store.mjs');
|
|
3198
3270
|
dismissRecommendation(key, {
|
|
@@ -3602,6 +3674,7 @@ async function cmdModels(args) {
|
|
|
3602
3674
|
return;
|
|
3603
3675
|
}
|
|
3604
3676
|
if (tier && setModel) {
|
|
3677
|
+
const registry = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'specialists', 'registry.json'), 'utf8'));
|
|
3605
3678
|
const preferFree = args.includes('--prefer-free');
|
|
3606
3679
|
const preferFreeSameFamily = args.includes('--prefer-free-same-family');
|
|
3607
3680
|
const inferred = setModelWithTierInference(envPath, tier, setModel, registry.models ?? {}, { preferFree, preferFreeSameFamily });
|
|
@@ -3647,7 +3720,7 @@ async function cmdModels(args) {
|
|
|
3647
3720
|
return;
|
|
3648
3721
|
}
|
|
3649
3722
|
if (args.includes('--cheapest')) {
|
|
3650
|
-
const { selectCheapestProvider,
|
|
3723
|
+
const { selectCheapestProvider, formatCheapestProviderMessage, isCheapestProviderEnabled } =
|
|
3651
3724
|
await import('../lib/model-cheapest-provider.mjs');
|
|
3652
3725
|
const cheapestTier = args.find((arg) => arg.startsWith('--tier='))?.split('=')[1] ?? 'standard';
|
|
3653
3726
|
const verbose = args.includes('--verbose');
|
|
@@ -3659,7 +3732,7 @@ async function cmdModels(args) {
|
|
|
3659
3732
|
return;
|
|
3660
3733
|
}
|
|
3661
3734
|
if (args.includes('--apply-cheapest')) {
|
|
3662
|
-
const {
|
|
3735
|
+
const { setCheapestProviderPreference } =
|
|
3663
3736
|
await import('../lib/model-cheapest-provider.mjs');
|
|
3664
3737
|
const allTiers = args.includes('--all-tiers') || !args.find((arg) => arg.startsWith('--tier='));
|
|
3665
3738
|
const tierArg = args.find((arg) => arg.startsWith('--tier='))?.split('=')[1];
|
|
@@ -3684,6 +3757,22 @@ async function cmdModels(args) {
|
|
|
3684
3757
|
await cmdSync([]);
|
|
3685
3758
|
return;
|
|
3686
3759
|
}
|
|
3760
|
+
if (args.includes('--list') || args[0] === 'list') {
|
|
3761
|
+
const { getProviderModelCatalog } = await import('../lib/model-router.mjs');
|
|
3762
|
+
const { listChatModels } = await import('../apps/chat/engine/models.mjs');
|
|
3763
|
+
const catalog = getProviderModelCatalog({ env: process.env, cwd: process.cwd() });
|
|
3764
|
+
const models = listChatModels({ env: process.env, cwd: process.cwd() });
|
|
3765
|
+
if (args.includes('--json')) {
|
|
3766
|
+
println(JSON.stringify({ catalog, models }, null, 2));
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
println('Visible models (filtered by construct.config.json models.visibility):');
|
|
3770
|
+
for (const model of models) {
|
|
3771
|
+
const flag = model.available ? 'ok' : '—';
|
|
3772
|
+
println(` ${flag} ${model.id}${model.configured ? '' : ' (provider not configured)'}`);
|
|
3773
|
+
}
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3687
3776
|
const registry = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'specialists', 'registry.json'), 'utf8'));
|
|
3688
3777
|
const result = readCurrentModels(envPath, registry.models ?? {});
|
|
3689
3778
|
const nothingSelected = ['reasoning', 'standard', 'fast'].every((t) => !result[t]);
|
|
@@ -3937,10 +4026,21 @@ async function cmdCleanup() {
|
|
|
3937
4026
|
println(` ! ${err.step}: ${err.error}`);
|
|
3938
4027
|
}
|
|
3939
4028
|
}
|
|
4029
|
+
|
|
4030
|
+
// Reclaim orphaned Postgres containers/volumes from deleted home namespaces.
|
|
4031
|
+
const { reclaimOrphanedDockerResources, formatReclaim } = await import('../lib/maintenance/docker-reclaim.mjs');
|
|
4032
|
+
const reclaim = reclaimOrphanedDockerResources({ homeDir: HOME, env: process.env, dryRun });
|
|
4033
|
+
if (!quiet) {
|
|
4034
|
+
const line = formatReclaim(reclaim);
|
|
4035
|
+
if (line) println(` ${line}`);
|
|
4036
|
+
for (const entry of reclaim.errors ?? []) {
|
|
4037
|
+
println(` ! docker reclaim ${entry.name}: ${entry.error}`);
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
3940
4040
|
}
|
|
3941
4041
|
}
|
|
3942
4042
|
|
|
3943
|
-
async function
|
|
4043
|
+
async function _cmdCost(args) {
|
|
3944
4044
|
const jsonOutput = args.includes('--json');
|
|
3945
4045
|
const resetFlag = args.includes('--reset');
|
|
3946
4046
|
const daysArg = args.find((a) => a.startsWith('--days='));
|
|
@@ -4191,8 +4291,21 @@ async function cmdDocsCheck(args) {
|
|
|
4191
4291
|
}
|
|
4192
4292
|
}
|
|
4193
4293
|
|
|
4194
|
-
async function cmdDocsSite() {
|
|
4195
|
-
const
|
|
4294
|
+
async function cmdDocsSite(args = []) {
|
|
4295
|
+
const check = args.includes('--check');
|
|
4296
|
+
const { buildFumadocsReference, checkFumadocsReferenceDrift } = await import('../lib/auto-docs.mjs');
|
|
4297
|
+
if (check) {
|
|
4298
|
+
const { drift } = checkFumadocsReferenceDrift({ rootDir: ROOT_DIR });
|
|
4299
|
+
if (drift.length === 0) {
|
|
4300
|
+
ok('docs/reference/ is up to date.');
|
|
4301
|
+
return;
|
|
4302
|
+
}
|
|
4303
|
+
println('');
|
|
4304
|
+
println('Generated reference docs are out of date. Run `construct docs:site` to regenerate:');
|
|
4305
|
+
for (const f of drift) println(` ✗ ${f}`);
|
|
4306
|
+
process.exitCode = 1;
|
|
4307
|
+
return;
|
|
4308
|
+
}
|
|
4196
4309
|
const { written } = buildFumadocsReference({ rootDir: ROOT_DIR });
|
|
4197
4310
|
if (written.length === 0) {
|
|
4198
4311
|
ok('docs/reference/ already up to date.');
|
|
@@ -4340,7 +4453,6 @@ async function cmdCiPreview(args) {
|
|
|
4340
4453
|
const { readFileSync, existsSync } = await import('node:fs');
|
|
4341
4454
|
const { join } = await import('node:path');
|
|
4342
4455
|
const { spawnSync: spSync } = await import('node:child_process');
|
|
4343
|
-
const YAML = await import('node:fs');
|
|
4344
4456
|
|
|
4345
4457
|
const listOnly = args.includes('--list');
|
|
4346
4458
|
const fullMode = args.includes('--full');
|
|
@@ -4838,7 +4950,7 @@ async function cmdTags(args) {
|
|
|
4838
4950
|
|
|
4839
4951
|
async function cmdScheduler(args) {
|
|
4840
4952
|
const sub = args[0];
|
|
4841
|
-
const {
|
|
4953
|
+
const { runJobOnce, listJobs } = await import('../lib/scheduler/index.mjs');
|
|
4842
4954
|
|
|
4843
4955
|
if (!sub || sub === 'list') {
|
|
4844
4956
|
const jobs = listJobs();
|
|
@@ -4876,18 +4988,30 @@ async function cmdScheduler(args) {
|
|
|
4876
4988
|
|
|
4877
4989
|
async function cmdCreds(args) {
|
|
4878
4990
|
const sub = args[0];
|
|
4879
|
-
const {
|
|
4991
|
+
const { writeCreds, deleteCreds, listCreds, checkCredsFileMode, credsFilePath } =
|
|
4880
4992
|
await import('../lib/providers/creds.mjs');
|
|
4881
4993
|
const { createInterface } = await import('node:readline');
|
|
4882
4994
|
|
|
4883
4995
|
if (!sub || sub === 'list') {
|
|
4884
4996
|
const entries = listCreds();
|
|
4885
|
-
if (entries.length === 0) {
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
println(
|
|
4997
|
+
if (entries.length === 0) {
|
|
4998
|
+
println('No provider credentials stored in the rotation store.');
|
|
4999
|
+
} else {
|
|
5000
|
+
println('Provider credentials\n');
|
|
5001
|
+
println(' PROVIDER ACCOUNT ROTATED_AT NEXT_ROTATION');
|
|
5002
|
+
for (const e of entries) {
|
|
5003
|
+
println(` ${e.provider.padEnd(26)} ${(e.account || '—').padEnd(27)} ${(e.rotatedAt || '—').padEnd(23)} ${e.nextRotationDue || '—'}`);
|
|
5004
|
+
}
|
|
4890
5005
|
}
|
|
5006
|
+
try {
|
|
5007
|
+
const { getProviderModelCatalog } = await import('../lib/model-router.mjs');
|
|
5008
|
+
const { providers } = getProviderModelCatalog({ env: process.env });
|
|
5009
|
+
println('\nLLM provider readiness (op:// references resolve at call time)\n');
|
|
5010
|
+
for (const p of providers) {
|
|
5011
|
+
println(` ${p.configured ? '✓' : '·'} ${p.id}`);
|
|
5012
|
+
}
|
|
5013
|
+
println('\n Set keys as values or op:// refs in ~/.construct/config.env; run `construct creds login copilot` for GitHub Copilot.');
|
|
5014
|
+
} catch { /* readiness view is informational */ }
|
|
4891
5015
|
return;
|
|
4892
5016
|
}
|
|
4893
5017
|
|
|
@@ -4926,7 +5050,68 @@ async function cmdCreds(args) {
|
|
|
4926
5050
|
return;
|
|
4927
5051
|
}
|
|
4928
5052
|
|
|
4929
|
-
|
|
5053
|
+
if (sub === 'login') {
|
|
5054
|
+
const provider = args[1] || 'copilot';
|
|
5055
|
+
if (provider !== 'copilot' && provider !== 'github-copilot') {
|
|
5056
|
+
errorln(`\`creds login\` currently supports only \`copilot\`. For API-key providers use \`construct creds set ${provider}\`.`);
|
|
5057
|
+
process.exit(1);
|
|
5058
|
+
}
|
|
5059
|
+
const copilot = await import('../lib/providers/copilot-auth.mjs');
|
|
5060
|
+
if (copilot.hasStoredCredential() && !args.includes('--force')) {
|
|
5061
|
+
try {
|
|
5062
|
+
await copilot.getCopilotToken();
|
|
5063
|
+
println('GitHub Copilot is already authenticated and the session token exchanged successfully.');
|
|
5064
|
+
println('Re-run with --force to authenticate a different account.');
|
|
5065
|
+
return;
|
|
5066
|
+
} catch {
|
|
5067
|
+
println('A stored Copilot credential exists but the session exchange failed; re-authenticating.');
|
|
5068
|
+
}
|
|
5069
|
+
}
|
|
5070
|
+
let device;
|
|
5071
|
+
try {
|
|
5072
|
+
device = await copilot.requestDeviceCode({});
|
|
5073
|
+
} catch (err) {
|
|
5074
|
+
errorln(err.message);
|
|
5075
|
+
process.exit(1);
|
|
5076
|
+
}
|
|
5077
|
+
println('\nGitHub Copilot sign-in');
|
|
5078
|
+
println(` 1. Open: ${device.verificationUri}`);
|
|
5079
|
+
println(` 2. Enter code: ${device.userCode}`);
|
|
5080
|
+
println('\nWaiting for authorization...');
|
|
5081
|
+
let token;
|
|
5082
|
+
try {
|
|
5083
|
+
token = await copilot.pollForAccessToken({
|
|
5084
|
+
deviceCode: device.deviceCode,
|
|
5085
|
+
interval: device.interval,
|
|
5086
|
+
expiresIn: device.expiresIn,
|
|
5087
|
+
onPending: () => process.stdout.write('.'),
|
|
5088
|
+
});
|
|
5089
|
+
process.stdout.write('\n');
|
|
5090
|
+
} catch (err) {
|
|
5091
|
+
process.stdout.write('\n');
|
|
5092
|
+
errorln(err.message);
|
|
5093
|
+
process.exit(1);
|
|
5094
|
+
}
|
|
5095
|
+
copilot.persistOAuth({ accessToken: token.accessToken, refreshToken: token.refreshToken, expiresAt: token.expiresAt, user: null });
|
|
5096
|
+
try {
|
|
5097
|
+
await copilot.getCopilotToken();
|
|
5098
|
+
println('GitHub Copilot authenticated. The session token exchanged successfully.');
|
|
5099
|
+
println('Credentials stored in ~/.construct/auth/github-copilot.json and ~/.config/github-copilot/apps.json.');
|
|
5100
|
+
try {
|
|
5101
|
+
const models = await copilot.listCopilotModels({});
|
|
5102
|
+
if (models.length) {
|
|
5103
|
+
println('\nModels available to your account (use as github-copilot/<id>):');
|
|
5104
|
+
for (const id of models) println(` - github-copilot/${id}`);
|
|
5105
|
+
}
|
|
5106
|
+
} catch { /* model listing is informational; auth already succeeded */ }
|
|
5107
|
+
} catch (err) {
|
|
5108
|
+
errorln(`Authenticated with GitHub, but the Copilot token exchange failed: ${err.message}`);
|
|
5109
|
+
process.exit(1);
|
|
5110
|
+
}
|
|
5111
|
+
return;
|
|
5112
|
+
}
|
|
5113
|
+
|
|
5114
|
+
errorln(`Unknown creds subcommand: ${sub}. Available: list, login, set, rotate, revoke, test`);
|
|
4930
5115
|
process.exit(1);
|
|
4931
5116
|
}
|
|
4932
5117
|
|
|
@@ -5149,7 +5334,7 @@ async function cmdTelemetryQuery(args) {
|
|
|
5149
5334
|
println(' errors [--agent=<name>] [--since=24h] error span summary');
|
|
5150
5335
|
println(' trace <traceId> full span tree');
|
|
5151
5336
|
println('');
|
|
5152
|
-
println('For Langfuse/Honeycomb/Grafana Tempo/Datadog, see docs/concepts/observability.
|
|
5337
|
+
println('For Langfuse/Honeycomb/Grafana Tempo/Datadog, see docs/concepts/observability.md');
|
|
5153
5338
|
}
|
|
5154
5339
|
|
|
5155
5340
|
async function cmdHook(args) {
|
|
@@ -5233,13 +5418,18 @@ const handlers = new Map([
|
|
|
5233
5418
|
['distill', cmdDistill],
|
|
5234
5419
|
['ingest', cmdIngest],
|
|
5235
5420
|
['export', cmdExport],
|
|
5421
|
+
['publish', cmdPublish],
|
|
5422
|
+
['tools', cmdTools],
|
|
5236
5423
|
['infer', cmdInfer],
|
|
5237
5424
|
['search', cmdSearch],
|
|
5238
5425
|
['storage', cmdStorage],
|
|
5239
5426
|
['registry:status', cmdRegistryStatus],
|
|
5427
|
+
['registry:validate', cmdRegistryValidate],
|
|
5428
|
+
['registry:generate-docs', cmdRegistryGenerateDocs],
|
|
5429
|
+
['rules', cmdRulesUsage],
|
|
5240
5430
|
// Pricing / cost readouts are stubbed out: the ledger writes, model-pricing
|
|
5241
5431
|
// catalog, and per-turn accounting still run, but no CLI surface exposes
|
|
5242
|
-
// them to the user. Handlers (
|
|
5432
|
+
// them to the user. Handlers (_cmdPricing, _cmdCosts, _cmdCost) remain in this
|
|
5243
5433
|
// file so the OTel + dashboard wiring (planned in Workstream J) can rewire
|
|
5244
5434
|
// the surface without re-implementing the logic.
|
|
5245
5435
|
['overrides', cmdOverrides],
|
|
@@ -5262,7 +5452,7 @@ const handlers = new Map([
|
|
|
5262
5452
|
if (sub === 'verify') return cmdDocsVerify(rest);
|
|
5263
5453
|
if (sub === 'update') return cmdDocsUpdate(rest);
|
|
5264
5454
|
if (sub === 'check') return cmdDocsCheck(rest);
|
|
5265
|
-
if (sub === 'site') return cmdDocsSite();
|
|
5455
|
+
if (sub === 'site') return cmdDocsSite(rest);
|
|
5266
5456
|
if (sub === 'reconcile') return cmdDocsReconcile(rest);
|
|
5267
5457
|
errorln(`Unknown docs subcommand: ${sub}. Available: check, verify, update, site, reconcile`);
|
|
5268
5458
|
process.exit(1);
|
|
@@ -5277,6 +5467,10 @@ const handlers = new Map([
|
|
|
5277
5467
|
const { runAcpServer } = await import('../lib/acp/server.mjs');
|
|
5278
5468
|
runAcpServer({ input: process.stdin, output: process.stdout, env: process.env, defaultCwd: process.cwd() });
|
|
5279
5469
|
}],
|
|
5470
|
+
['chat', async (args) => {
|
|
5471
|
+
const { runChat } = await import('../lib/chat/cli.mjs');
|
|
5472
|
+
process.exitCode = await runChat(args, { env: process.env, cwd: process.cwd() });
|
|
5473
|
+
}],
|
|
5280
5474
|
['beads:stats', async (args) => {
|
|
5281
5475
|
const { getContentionStats, getHumanStatus } = await import('../lib/beads-optimistic.mjs');
|
|
5282
5476
|
const jsonOutput = args.includes('--json');
|
|
@@ -5438,11 +5632,23 @@ const handlers = new Map([
|
|
|
5438
5632
|
['audit', async (args) => {
|
|
5439
5633
|
const sub = args[0];
|
|
5440
5634
|
if (sub === 'skills') return runAuditSkillsCli(args.slice(1));
|
|
5635
|
+
if (sub === 'specialists') return runAuditSpecialistsCli(args.slice(1));
|
|
5636
|
+
if (sub === 'tests') {
|
|
5637
|
+
const rest = args.slice(1);
|
|
5638
|
+
if (rest.includes('--corpus')) return runCorpusInventoryAuditCli(rest.filter((arg) => arg !== '--corpus'), { rootDir: ROOT_DIR });
|
|
5639
|
+
return runCapabilityLedgerAuditCli(rest, { rootDir: ROOT_DIR });
|
|
5640
|
+
}
|
|
5441
5641
|
if (sub === 'trail' || !sub) {
|
|
5442
5642
|
const { runAuditTrailCli } = await import('../lib/audit-trail.mjs');
|
|
5443
5643
|
return runAuditTrailCli(args.slice(sub === 'trail' ? 1 : 0));
|
|
5444
5644
|
}
|
|
5445
|
-
errorln(`Unknown audit subcommand: ${sub}. Available: skills, trail`);
|
|
5645
|
+
errorln(`Unknown audit subcommand: ${sub}. Available: skills, specialists, tests, trail`);
|
|
5646
|
+
process.exit(1);
|
|
5647
|
+
}],
|
|
5648
|
+
['artifact', async (args) => {
|
|
5649
|
+
const sub = args[0];
|
|
5650
|
+
if (sub === 'validate') return runArtifactValidateCli(args.slice(1));
|
|
5651
|
+
errorln(`Unknown artifact subcommand: ${sub || '(none)'}. Available: validate`);
|
|
5446
5652
|
process.exit(1);
|
|
5447
5653
|
}],
|
|
5448
5654
|
['doc', async (args) => {
|
|
@@ -5890,6 +6096,30 @@ const handlers = new Map([
|
|
|
5890
6096
|
const { runEmbedCli } = await import('../lib/embed/cli.mjs');
|
|
5891
6097
|
return runEmbedCli(args, { rootDir: new URL('..', import.meta.url).pathname });
|
|
5892
6098
|
}],
|
|
6099
|
+
['oracle', async (args) => {
|
|
6100
|
+
const { runOracleCli } = await import('../lib/oracle/cli.mjs');
|
|
6101
|
+
return runOracleCli(args, { rootDir: ROOT_DIR, projectDir: process.cwd(), homeDir: HOME });
|
|
6102
|
+
}],
|
|
6103
|
+
['certify', async (args) => {
|
|
6104
|
+
const { runCertificationCli } = await import('../lib/certification/cli.mjs');
|
|
6105
|
+
const code = await runCertificationCli(args, { projectDir: process.cwd(), repoRoot: ROOT_DIR });
|
|
6106
|
+
if (typeof code === 'number' && code !== 0) process.exit(code);
|
|
6107
|
+
}],
|
|
6108
|
+
['improvement', async (args) => {
|
|
6109
|
+
const { runImprovementCli } = await import('../lib/improvement/cli.mjs');
|
|
6110
|
+
const code = await runImprovementCli(args, { projectDir: process.cwd() });
|
|
6111
|
+
if (typeof code === 'number' && code !== 0) process.exit(code);
|
|
6112
|
+
}],
|
|
6113
|
+
['matrix', async (args) => {
|
|
6114
|
+
const { runGraphCli } = await import('../lib/graph/cli.mjs');
|
|
6115
|
+
const code = runGraphCli(args, { rootDir: ROOT_DIR, projectDir: process.cwd() });
|
|
6116
|
+
if (typeof code === 'number' && code !== 0) process.exit(code);
|
|
6117
|
+
}],
|
|
6118
|
+
['impact', async (args) => {
|
|
6119
|
+
const { runImpactCli } = await import('../lib/graph/impact-cli.mjs');
|
|
6120
|
+
const code = await runImpactCli(args, { rootDir: ROOT_DIR, projectDir: process.cwd() });
|
|
6121
|
+
if (typeof code === 'number' && code !== 0) process.exit(code);
|
|
6122
|
+
}],
|
|
5893
6123
|
['reflect', async (args) => {
|
|
5894
6124
|
const { runReflectCli } = await import('../lib/reflect.mjs');
|
|
5895
6125
|
return runReflectCli(args);
|