@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/lib/init-docs.mjs
CHANGED
|
@@ -27,6 +27,16 @@ import { suggestDocsLaneForFile } from './docs-routing.mjs';
|
|
|
27
27
|
import { stampFrontmatter } from "./doc-stamp.mjs";
|
|
28
28
|
import { multiSelect, selectOption } from './tty-prompts.mjs';
|
|
29
29
|
import readline from "node:readline";
|
|
30
|
+
import {
|
|
31
|
+
DOC_LANES,
|
|
32
|
+
DOC_PRESETS,
|
|
33
|
+
DEFAULT_LANES,
|
|
34
|
+
LANE_ORDER,
|
|
35
|
+
normalizeCustomLaneName,
|
|
36
|
+
normalizeLaneKey,
|
|
37
|
+
parseCsvList,
|
|
38
|
+
parseSelectableLanes,
|
|
39
|
+
} from './init/doc-lanes.mjs';
|
|
30
40
|
|
|
31
41
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
32
42
|
const ROOT_DIR = path.join(__dirname, "..");
|
|
@@ -52,170 +62,40 @@ const docsDir = path.join(target, docsRootRelative);
|
|
|
52
62
|
const created = [];
|
|
53
63
|
const skipped = [];
|
|
54
64
|
|
|
55
|
-
const DOC_LANES = {
|
|
56
|
-
adrs: {
|
|
57
|
-
title: "ADRs",
|
|
58
|
-
dir: "adr",
|
|
59
|
-
description: "Architecture decision records for decisions that have already been made.",
|
|
60
|
-
templates: ["adr.md"],
|
|
61
|
-
},
|
|
62
|
-
briefs: {
|
|
63
|
-
title: "Briefs",
|
|
64
|
-
dir: "briefs",
|
|
65
|
-
description: "Research, evidence, signal, and one-pager style documents.",
|
|
66
|
-
templates: [
|
|
67
|
-
"research-brief.md",
|
|
68
|
-
"evidence-brief.md",
|
|
69
|
-
"signal-brief.md",
|
|
70
|
-
"one-pager.md",
|
|
71
|
-
"customer-profile.md",
|
|
72
|
-
"product-intelligence-report.md",
|
|
73
|
-
"backlog-proposal.md",
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
changelogs: {
|
|
77
|
-
title: "Changelogs",
|
|
78
|
-
dir: "changelogs",
|
|
79
|
-
description: "User-facing release notes and version history entries.",
|
|
80
|
-
templates: ["changelog-entry.md"],
|
|
81
|
-
},
|
|
82
|
-
intake: {
|
|
83
|
-
title: "Intake",
|
|
84
|
-
dir: "intake",
|
|
85
|
-
description: "Intake batch records that explain what arrived, why it matters, and how it should be ingested.",
|
|
86
|
-
templates: ["__intake-template__"],
|
|
87
|
-
},
|
|
88
|
-
memos: {
|
|
89
|
-
title: "Memos",
|
|
90
|
-
dir: "memos",
|
|
91
|
-
description: "Decision memos and internal arguments for alignment and approval.",
|
|
92
|
-
templates: ["memo.md"],
|
|
93
|
-
},
|
|
94
|
-
meetings: {
|
|
95
|
-
title: 'Meetings',
|
|
96
|
-
dir: 'meetings',
|
|
97
|
-
description: 'Meeting notes, minutes, retros, standups, planning sessions, and agendas.',
|
|
98
|
-
templates: ['__meeting-notes-template__'],
|
|
99
|
-
},
|
|
100
|
-
notes: {
|
|
101
|
-
title: "Notes",
|
|
102
|
-
dir: "notes",
|
|
103
|
-
description: "Working notes and lightweight durable context outside formal docs or meetings.",
|
|
104
|
-
templates: ["__notes-template__"],
|
|
105
|
-
},
|
|
106
|
-
onboarding: {
|
|
107
|
-
title: "Onboarding",
|
|
108
|
-
dir: "onboarding",
|
|
109
|
-
description: "Runnable setup guides and first-day workflows for engineers, product, or ops.",
|
|
110
|
-
templates: ["onboarding.md"],
|
|
111
|
-
},
|
|
112
|
-
postmortems: {
|
|
113
|
-
title: "Postmortems",
|
|
114
|
-
dir: "postmortems",
|
|
115
|
-
description: "Blameless incident reports: timeline, root cause, contributing factors, and corrective actions.",
|
|
116
|
-
templates: ["incident-report.md"],
|
|
117
|
-
},
|
|
118
|
-
prds: {
|
|
119
|
-
title: "PRDs",
|
|
120
|
-
dir: "prds",
|
|
121
|
-
description: "Product and capability requirement documents.",
|
|
122
|
-
templates: ["prd.md", "meta-prd.md", "prd-business.md", "prd-platform.md", "prfaq.md"],
|
|
123
|
-
},
|
|
124
|
-
rfcs: {
|
|
125
|
-
title: "RFCs",
|
|
126
|
-
dir: "rfcs",
|
|
127
|
-
description: "Architecture and implementation proposals that need review before a decision.",
|
|
128
|
-
templates: ["rfc.md", "rfc-platform.md"],
|
|
129
|
-
},
|
|
130
|
-
runbooks: {
|
|
131
|
-
title: "Runbooks",
|
|
132
|
-
dir: "runbooks",
|
|
133
|
-
description: "Operational procedures, diagnostics, remediation, and escalation paths.",
|
|
134
|
-
templates: ["runbook.md"],
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const DOC_PRESETS = {
|
|
139
|
-
lean: ["adrs", "intake", "memos", "meetings", "notes", "prds"],
|
|
140
|
-
product: ["adrs", "intake", "memos", "meetings", "notes", "prds", "rfcs"],
|
|
141
|
-
full: ["adrs", "briefs", "changelogs", "intake", "memos", "meetings", "notes", "onboarding", "postmortems", "prds", "rfcs", "runbooks"],
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const DEFAULT_LANES = DOC_PRESETS.lean;
|
|
145
|
-
const LANE_ORDER = ["adrs", "briefs", "changelogs", "intake", "memos", "meetings", "notes", "onboarding", "postmortems", "prds", "rfcs", "runbooks"];
|
|
146
|
-
const LANE_ALIASES = {
|
|
147
|
-
adr: "adrs",
|
|
148
|
-
adrs: "adrs",
|
|
149
|
-
brief: "briefs",
|
|
150
|
-
briefs: "briefs",
|
|
151
|
-
changelog: "changelogs",
|
|
152
|
-
changelogs: "changelogs",
|
|
153
|
-
releases: "changelogs",
|
|
154
|
-
release: "changelogs",
|
|
155
|
-
intake: "intake",
|
|
156
|
-
memo: "memos",
|
|
157
|
-
memos: "memos",
|
|
158
|
-
meeting: 'meetings',
|
|
159
|
-
meetings: 'meetings',
|
|
160
|
-
minutes: 'meetings',
|
|
161
|
-
retro: 'meetings',
|
|
162
|
-
note: "notes",
|
|
163
|
-
notes: "notes",
|
|
164
|
-
onboard: "onboarding",
|
|
165
|
-
onboarding: "onboarding",
|
|
166
|
-
postmortem: "postmortems",
|
|
167
|
-
postmortems: "postmortems",
|
|
168
|
-
incident: "postmortems",
|
|
169
|
-
incidents: "postmortems",
|
|
170
|
-
prd: "prds",
|
|
171
|
-
prds: "prds",
|
|
172
|
-
rfc: "rfcs",
|
|
173
|
-
rfcs: "rfcs",
|
|
174
|
-
runbook: "runbooks",
|
|
175
|
-
runbooks: "runbooks",
|
|
176
|
-
};
|
|
177
|
-
|
|
178
65
|
function inferProjectName(targetPath) {
|
|
179
|
-
const packageJsonPath = path.join(targetPath,
|
|
66
|
+
const packageJsonPath = path.join(targetPath, 'package.json');
|
|
180
67
|
if (fs.existsSync(packageJsonPath)) {
|
|
181
68
|
try {
|
|
182
|
-
const pkg = JSON.parse(fs.readFileSync(packageJsonPath,
|
|
69
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
183
70
|
return pkg.name || path.basename(targetPath);
|
|
184
|
-
} catch {}
|
|
71
|
+
} catch { /* ignore */ }
|
|
185
72
|
}
|
|
186
73
|
return path.basename(targetPath);
|
|
187
74
|
}
|
|
188
75
|
|
|
189
|
-
function parseCsvList(value) {
|
|
190
|
-
return value
|
|
191
|
-
.split(",")
|
|
192
|
-
.map((entry) => entry.trim())
|
|
193
|
-
.filter(Boolean);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
76
|
const NO_ANSWER_PATTERNS = new Set([
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
77
|
+
'',
|
|
78
|
+
'n',
|
|
79
|
+
'no',
|
|
80
|
+
'none',
|
|
81
|
+
'nope',
|
|
82
|
+
'nah',
|
|
83
|
+
'nothing',
|
|
84
|
+
'blank',
|
|
85
|
+
'skip',
|
|
86
|
+
'no thanks',
|
|
207
87
|
]);
|
|
208
88
|
|
|
209
89
|
const ALL_ANSWER_PATTERNS = new Set([
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
90
|
+
'all',
|
|
91
|
+
'all of them',
|
|
92
|
+
'everything',
|
|
93
|
+
'default',
|
|
94
|
+
'defaults',
|
|
215
95
|
]);
|
|
216
96
|
|
|
217
97
|
function normalizeAnswer(value) {
|
|
218
|
-
return value.trim().toLowerCase().replace(/\s+/g,
|
|
98
|
+
return value.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
219
99
|
}
|
|
220
100
|
|
|
221
101
|
function isNegativeAnswer(value) {
|
|
@@ -241,41 +121,14 @@ function parseExtraLaneSelection(value) {
|
|
|
241
121
|
.filter(Boolean);
|
|
242
122
|
}
|
|
243
123
|
|
|
244
|
-
function parseSelectableLanes(value) {
|
|
245
|
-
return value
|
|
246
|
-
.split(/[,\n]/)
|
|
247
|
-
.map((entry) => entry.trim())
|
|
248
|
-
.filter(Boolean)
|
|
249
|
-
.map((entry) => {
|
|
250
|
-
if (/^\d+$/.test(entry)) {
|
|
251
|
-
const lane = LANE_ORDER[Number(entry) - 1];
|
|
252
|
-
return lane ?? "";
|
|
253
|
-
}
|
|
254
|
-
return normalizeLaneKey(entry);
|
|
255
|
-
})
|
|
256
|
-
.filter((lane) => lane in DOC_LANES);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
124
|
function parseBooleanAnswer(value, defaultValue = false) {
|
|
260
125
|
if (!value.trim()) return defaultValue;
|
|
261
126
|
const normalized = normalizeAnswer(value);
|
|
262
|
-
if ([
|
|
263
|
-
if ([
|
|
127
|
+
if (['y', 'yes', 'true'].includes(normalized)) return true;
|
|
128
|
+
if (['n', 'no', 'false', 'nope', 'nah'].includes(normalized)) return false;
|
|
264
129
|
return defaultValue;
|
|
265
130
|
}
|
|
266
131
|
|
|
267
|
-
function normalizeCustomLaneName(name) {
|
|
268
|
-
return name
|
|
269
|
-
.trim()
|
|
270
|
-
.toLowerCase()
|
|
271
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
272
|
-
.replace(/^-+|-+$/g, "");
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function normalizeLaneKey(name) {
|
|
276
|
-
return LANE_ALIASES[name.trim().toLowerCase()] ?? name.trim().toLowerCase();
|
|
277
|
-
}
|
|
278
|
-
|
|
279
132
|
function repoHasAny(targetDir, candidates) {
|
|
280
133
|
return candidates.some((candidate) => fs.existsSync(path.join(targetDir, candidate)));
|
|
281
134
|
}
|
package/lib/init-unified.mjs
CHANGED
|
@@ -24,6 +24,8 @@ import { execSync, spawnSync } from 'node:child_process';
|
|
|
24
24
|
import { stageProjectAdapters } from './install/stage-project.mjs';
|
|
25
25
|
import { missingIgnorePatterns, isConstructPackageRepo } from './host-disposition.mjs';
|
|
26
26
|
import { HOST_KEYS, displayNameToKey } from './platforms/capabilities.mjs';
|
|
27
|
+
import { DOC_LANES, LANE_ORDER, DOC_PRESETS } from './init/doc-lanes.mjs';
|
|
28
|
+
import { initWorkflow } from './workflow-state.mjs';
|
|
27
29
|
|
|
28
30
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
29
31
|
const ROOT_DIR = path.join(__dirname, "..");
|
|
@@ -133,92 +135,9 @@ async function checkPrerequisites() {
|
|
|
133
135
|
return result.ok;
|
|
134
136
|
}
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
title: "ADRs",
|
|
140
|
-
dir: "adr",
|
|
141
|
-
description: "Architecture decision records for decisions that have already been made.",
|
|
142
|
-
templates: ["adr.md"],
|
|
143
|
-
},
|
|
144
|
-
briefs: {
|
|
145
|
-
title: "Briefs",
|
|
146
|
-
dir: "briefs",
|
|
147
|
-
description: "Research, evidence, signal, and one-pager style documents.",
|
|
148
|
-
templates: [
|
|
149
|
-
"research-brief.md",
|
|
150
|
-
"evidence-brief.md",
|
|
151
|
-
"signal-brief.md",
|
|
152
|
-
"one-pager.md",
|
|
153
|
-
"customer-profile.md",
|
|
154
|
-
"product-intelligence-report.md",
|
|
155
|
-
"backlog-proposal.md",
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
changelogs: {
|
|
159
|
-
title: "Changelogs",
|
|
160
|
-
dir: "changelogs",
|
|
161
|
-
description: "User-facing release notes and version history entries.",
|
|
162
|
-
templates: ["changelog-entry.md"],
|
|
163
|
-
},
|
|
164
|
-
intake: {
|
|
165
|
-
title: "Intake",
|
|
166
|
-
dir: "intake",
|
|
167
|
-
description: "Intake batch records that explain what arrived, why it matters, and how it should be ingested.",
|
|
168
|
-
templates: ["__intake-template__"],
|
|
169
|
-
},
|
|
170
|
-
memos: {
|
|
171
|
-
title: "Memos",
|
|
172
|
-
dir: "memos",
|
|
173
|
-
description: "Decision memos and internal arguments for alignment and approval.",
|
|
174
|
-
templates: ["memo.md"],
|
|
175
|
-
},
|
|
176
|
-
meetings: {
|
|
177
|
-
title: 'Meetings',
|
|
178
|
-
dir: 'meetings',
|
|
179
|
-
description: 'Meeting notes, minutes, retros, standups, planning sessions, and agendas.',
|
|
180
|
-
templates: ['__meeting-notes-template__'],
|
|
181
|
-
},
|
|
182
|
-
notes: {
|
|
183
|
-
title: "Notes",
|
|
184
|
-
dir: "notes",
|
|
185
|
-
description: "Working notes and lightweight durable context outside formal docs or meetings.",
|
|
186
|
-
templates: ["__notes-template__"],
|
|
187
|
-
},
|
|
188
|
-
onboarding: {
|
|
189
|
-
title: "Onboarding",
|
|
190
|
-
dir: "onboarding",
|
|
191
|
-
description: "Runnable setup guides and first-day workflows for engineers, product, or ops.",
|
|
192
|
-
templates: ["onboarding.md"],
|
|
193
|
-
},
|
|
194
|
-
postmortems: {
|
|
195
|
-
title: "Postmortems",
|
|
196
|
-
dir: "postmortems",
|
|
197
|
-
description: "Blameless incident reports: timeline, root cause, contributing factors, and corrective actions.",
|
|
198
|
-
templates: ["incident-report.md"],
|
|
199
|
-
},
|
|
200
|
-
prds: {
|
|
201
|
-
title: "PRDs",
|
|
202
|
-
dir: "prds",
|
|
203
|
-
description: "Product and capability requirement documents.",
|
|
204
|
-
templates: ["prd.md", "meta-prd.md", "prd-business.md", "prd-platform.md", "prfaq.md"],
|
|
205
|
-
},
|
|
206
|
-
rfcs: {
|
|
207
|
-
title: "RFCs",
|
|
208
|
-
dir: "rfcs",
|
|
209
|
-
description: "Architecture and implementation proposals that need review before a decision.",
|
|
210
|
-
templates: ["rfc.md", "rfc-platform.md"],
|
|
211
|
-
},
|
|
212
|
-
runbooks: {
|
|
213
|
-
title: "Runbooks",
|
|
214
|
-
dir: "runbooks",
|
|
215
|
-
description: "Operational procedures, diagnostics, remediation, and escalation paths.",
|
|
216
|
-
templates: ["runbook.md"],
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
// Lane order for display (alphabetical by title)
|
|
221
|
-
const LANE_ORDER = ["adrs", "briefs", "changelogs", "intake", "meetings", "memos", "notes", "onboarding", "postmortems", "prds", "rfcs", "runbooks"];
|
|
138
|
+
const docsPresetArg = args.find((arg) => arg.startsWith('--docs-preset='));
|
|
139
|
+
const docsLanesArg = args.find((arg) => arg.startsWith('--docs-lanes='));
|
|
140
|
+
const docsPresetName = docsPresetArg ? docsPresetArg.split('=')[1].toLowerCase() : 'lean';
|
|
222
141
|
|
|
223
142
|
// Project type detection
|
|
224
143
|
function detectProjectType(targetPath) {
|
|
@@ -515,27 +434,32 @@ function copyLaneTemplates(laneKey) {
|
|
|
515
434
|
}
|
|
516
435
|
|
|
517
436
|
async function askDocumentationQuestions() {
|
|
518
|
-
// Non-interactive mode: use flags or defaults
|
|
437
|
+
// Non-interactive mode: use flags or defaults (lean preset by default)
|
|
519
438
|
if (skipInteractive) {
|
|
520
439
|
let lanes = [];
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
440
|
+
|
|
441
|
+
if (docsLanesArg) {
|
|
442
|
+
lanes = parseWithDocs(docsLanesArg.split('=')[1]);
|
|
443
|
+
} else if (withAllDocsFlag) {
|
|
524
444
|
lanes = LANE_ORDER;
|
|
525
445
|
} else if (withDocsFlag) {
|
|
526
|
-
lanes = parseWithDocs(withDocsFlag.split(
|
|
446
|
+
lanes = parseWithDocs(withDocsFlag.split('=')[1]);
|
|
527
447
|
} else {
|
|
528
|
-
// Check individual flags
|
|
529
448
|
if (withAdrsFlag) lanes.push('adrs');
|
|
530
449
|
if (withRfcsFlag) lanes.push('rfcs');
|
|
531
450
|
if (withRunbooksFlag) lanes.push('runbooks');
|
|
532
451
|
if (withPostmortemsFlag) lanes.push('postmortems');
|
|
533
452
|
}
|
|
534
|
-
|
|
453
|
+
|
|
454
|
+
if (lanes.length === 0) {
|
|
455
|
+
lanes = DOC_PRESETS[docsPresetName] ?? DOC_PRESETS.lean;
|
|
456
|
+
}
|
|
457
|
+
|
|
535
458
|
return {
|
|
536
|
-
lanes: [...new Set(lanes)],
|
|
459
|
+
lanes: [...new Set(lanes)],
|
|
537
460
|
withArchitecture: withArchitectureFlag,
|
|
538
461
|
withReadme: withReadmeFlag || !fs.existsSync(path.join(target, "README.md")),
|
|
462
|
+
docsPreset: docsPresetName,
|
|
539
463
|
};
|
|
540
464
|
}
|
|
541
465
|
|
|
@@ -559,13 +483,16 @@ async function askDocumentationQuestions() {
|
|
|
559
483
|
}
|
|
560
484
|
|
|
561
485
|
// Build options for multi-select with suggestions pre-checked
|
|
562
|
-
const suggestedLaneNames = new Set(
|
|
486
|
+
const suggestedLaneNames = new Set([
|
|
487
|
+
...(DOC_PRESETS[docsPresetName] ?? DOC_PRESETS.lean),
|
|
488
|
+
...suggestions.filter((s) => s.recommended).map((s) => s.lane),
|
|
489
|
+
]);
|
|
563
490
|
const laneOptions = LANE_ORDER.map(lane => {
|
|
564
491
|
const suggestion = suggestions.find(s => s.lane === lane);
|
|
565
492
|
return {
|
|
566
493
|
label: DOC_LANES[lane].title,
|
|
567
494
|
value: lane,
|
|
568
|
-
checked: suggestion?.recommended ??
|
|
495
|
+
checked: suggestion?.recommended ?? suggestedLaneNames.has(lane),
|
|
569
496
|
description: DOC_LANES[lane].description,
|
|
570
497
|
suggestion: suggestion?.reason,
|
|
571
498
|
};
|
|
@@ -592,7 +519,7 @@ async function askDocumentationQuestions() {
|
|
|
592
519
|
withArchitecture = archResponse;
|
|
593
520
|
}
|
|
594
521
|
|
|
595
|
-
return { lanes: selectedLanes, withArchitecture, withReadme };
|
|
522
|
+
return { lanes: selectedLanes, withArchitecture, withReadme, docsPreset: docsPresetName };
|
|
596
523
|
}
|
|
597
524
|
|
|
598
525
|
// Intake collection — suggest directories to watch for context
|
|
@@ -930,6 +857,9 @@ async function main() {
|
|
|
930
857
|
generator: "construct/init",
|
|
931
858
|
attribution,
|
|
932
859
|
});
|
|
860
|
+
|
|
861
|
+
const { created: workflowCreated } = initWorkflow(target, projectName || "Project workflow");
|
|
862
|
+
if (workflowCreated) created.push(".cx/workflow.json");
|
|
933
863
|
|
|
934
864
|
// `.cx/` already exists from the context writes above and is gitignored in full
|
|
935
865
|
// (ADR-0027), so a keep file there could never be tracked. No dead keep file is written.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/init-update-guide.mjs — detect and migrate stale .cx/construct_guide.md copies.
|
|
3
|
+
*
|
|
4
|
+
* Older inits wrote R&D-specific language, fixed port URLs, or root-level guides.
|
|
5
|
+
* init:update proposes or applies the current templates/docs/construct_guide.md.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import crypto from 'node:crypto';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { constructDir } from './paths.mjs';
|
|
13
|
+
|
|
14
|
+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
15
|
+
|
|
16
|
+
const STALE_GUIDE_MARKERS = [
|
|
17
|
+
/R&D\s+(intake|classification)/i,
|
|
18
|
+
/review-queue/i,
|
|
19
|
+
/localhost:54330\b/,
|
|
20
|
+
/54329-54339/,
|
|
21
|
+
/construct init.*per.?machine/i,
|
|
22
|
+
/construct init.*machine setup/i,
|
|
23
|
+
/Welcome to Construct[\s\S]{0,400}repo root/i,
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export function locateConstructGuide(targetDir) {
|
|
27
|
+
const cxGuide = path.join(targetDir, '.cx', 'construct_guide.md');
|
|
28
|
+
if (fs.existsSync(cxGuide)) return { path: cxGuide, location: '.cx' };
|
|
29
|
+
const rootGuide = path.join(targetDir, 'construct_guide.md');
|
|
30
|
+
if (fs.existsSync(rootGuide)) return { path: rootGuide, location: 'root' };
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function shippedConstructGuidePath() {
|
|
35
|
+
const fromInstall = path.join(constructDir(), 'templates', 'docs', 'construct_guide.md');
|
|
36
|
+
if (fs.existsSync(fromInstall)) return fromInstall;
|
|
37
|
+
return path.join(REPO_ROOT, 'templates', 'docs', 'construct_guide.md');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function sha256(content) {
|
|
41
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isStaleConstructGuide(content) {
|
|
45
|
+
if (!content || !content.trim()) return false;
|
|
46
|
+
if (!content.includes('construct intake --help')) return true;
|
|
47
|
+
return STALE_GUIDE_MARKERS.some((re) => re.test(content));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function needsConstructGuideUpdate(targetDir) {
|
|
51
|
+
const located = locateConstructGuide(targetDir);
|
|
52
|
+
if (!located) return { needed: false };
|
|
53
|
+
const content = fs.readFileSync(located.path, 'utf8');
|
|
54
|
+
const shippedPath = shippedConstructGuidePath();
|
|
55
|
+
if (!fs.existsSync(shippedPath)) return { needed: false };
|
|
56
|
+
const shipped = fs.readFileSync(shippedPath, 'utf8');
|
|
57
|
+
if (sha256(content) === sha256(shipped)) return { needed: false };
|
|
58
|
+
if (!isStaleConstructGuide(content)) return { needed: false };
|
|
59
|
+
return { needed: true, located, content, shipped };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function writeConstructGuideProposal(targetDir, { located, shipped }) {
|
|
63
|
+
const proposalDir = path.join(targetDir, '.cx', 'proposals');
|
|
64
|
+
fs.mkdirSync(proposalDir, { recursive: true });
|
|
65
|
+
const proposalPath = path.join(proposalDir, 'construct_guide.construct-update.md');
|
|
66
|
+
const body = [
|
|
67
|
+
'# Proposed construct_guide.md update',
|
|
68
|
+
'',
|
|
69
|
+
'Your orientation guide predates current Construct branding and intake terminology.',
|
|
70
|
+
'Merge the sections you still need from your copy, then replace `.cx/construct_guide.md`',
|
|
71
|
+
'with the shipped template below (or run `construct init:update --apply-guide`).',
|
|
72
|
+
'',
|
|
73
|
+
located.location === 'root'
|
|
74
|
+
? '**Note:** the guide still lives at repo root; relocate to `.cx/construct_guide.md` (gitignored).'
|
|
75
|
+
: '',
|
|
76
|
+
'',
|
|
77
|
+
'## Shipped template (current standard)',
|
|
78
|
+
'',
|
|
79
|
+
shipped.trimEnd(),
|
|
80
|
+
'',
|
|
81
|
+
].filter(Boolean).join('\n');
|
|
82
|
+
fs.writeFileSync(proposalPath, body, 'utf8');
|
|
83
|
+
return proposalPath;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function applyConstructGuideUpdate(targetDir, shippedContent) {
|
|
87
|
+
const cxDir = path.join(targetDir, '.cx');
|
|
88
|
+
fs.mkdirSync(cxDir, { recursive: true });
|
|
89
|
+
const dest = path.join(cxDir, 'construct_guide.md');
|
|
90
|
+
const rootLegacy = path.join(targetDir, 'construct_guide.md');
|
|
91
|
+
|
|
92
|
+
if (fs.existsSync(dest)) {
|
|
93
|
+
fs.copyFileSync(dest, `${dest}.bak`);
|
|
94
|
+
}
|
|
95
|
+
fs.writeFileSync(dest, shippedContent, 'utf8');
|
|
96
|
+
|
|
97
|
+
if (fs.existsSync(rootLegacy)) {
|
|
98
|
+
fs.rmSync(rootLegacy);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return dest;
|
|
102
|
+
}
|
package/lib/init-update.mjs
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* `construct init:update` helps projects adopt current Construct standards without replacing
|
|
6
6
|
* user-managed instruction files. Proposed updates are written under .cx/proposals/ for
|
|
7
|
-
* manual review and merge.
|
|
7
|
+
* manual review and merge. Stale `.cx/construct_guide.md` copies can be refreshed via
|
|
8
|
+
* `--apply-guide`.
|
|
8
9
|
*
|
|
9
10
|
* checkTemplateConflicts(targetDir) compares project templates against the construct install's
|
|
10
11
|
* templates/docs/ directory. resolveTemplateConflict(conflict, resolution, targetDir) applies
|
|
@@ -15,9 +16,15 @@ import fs from "node:fs";
|
|
|
15
16
|
import path from "node:path";
|
|
16
17
|
import crypto from "node:crypto";
|
|
17
18
|
import { constructDir } from "./paths.mjs";
|
|
19
|
+
import {
|
|
20
|
+
applyConstructGuideUpdate,
|
|
21
|
+
needsConstructGuideUpdate,
|
|
22
|
+
writeConstructGuideProposal,
|
|
23
|
+
} from "./init-update-guide.mjs";
|
|
18
24
|
|
|
19
25
|
const args = process.argv.slice(2);
|
|
20
26
|
const dryRun = args.includes("--dry-run");
|
|
27
|
+
const applyGuide = args.includes("--apply-guide");
|
|
21
28
|
const cwdArg = args.find((arg) => arg.startsWith("--cwd="));
|
|
22
29
|
const cwd = cwdArg ? path.resolve(cwdArg.split("=")[1]) : process.cwd();
|
|
23
30
|
|
|
@@ -168,6 +175,18 @@ async function main() {
|
|
|
168
175
|
}
|
|
169
176
|
}
|
|
170
177
|
|
|
178
|
+
const guideState = needsConstructGuideUpdate(cwd);
|
|
179
|
+
if (guideState.needed) {
|
|
180
|
+
planned.push({
|
|
181
|
+
label: "construct_guide.md refresh (profile-neutral intake language)",
|
|
182
|
+
write() {
|
|
183
|
+
return writeConstructGuideProposal(cwd, guideState);
|
|
184
|
+
},
|
|
185
|
+
relativePath: path.join(".cx", "proposals", "construct_guide.construct-update.md"),
|
|
186
|
+
applyGuide: () => applyConstructGuideUpdate(cwd, guideState.shipped),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
171
190
|
if (planned.length === 0) {
|
|
172
191
|
console.log("No proposals needed. The project already satisfies the current update checks.");
|
|
173
192
|
return;
|
|
@@ -187,12 +206,24 @@ async function main() {
|
|
|
187
206
|
|
|
188
207
|
console.log("");
|
|
189
208
|
for (const item of planned) {
|
|
209
|
+
if (applyGuide && item.applyGuide) {
|
|
210
|
+
const dest = item.applyGuide();
|
|
211
|
+
console.log(`Applied construct_guide.md refresh: ${dest} (backup: ${dest}.bak when prior .cx copy existed)`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
190
214
|
const proposalPath = item.write();
|
|
191
215
|
console.log(`Wrote proposal: ${proposalPath}`);
|
|
192
216
|
}
|
|
193
217
|
|
|
218
|
+
if (applyGuide) {
|
|
219
|
+
console.log("");
|
|
220
|
+
console.log("Guide refresh applied. Review .cx/construct_guide.md and restore any team-specific notes from .bak if needed.");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
194
224
|
console.log("");
|
|
195
225
|
console.log("Review the proposal files under .cx/proposals/ and merge the needed changes manually.");
|
|
226
|
+
console.log("To replace .cx/construct_guide.md with the shipped template: construct init:update --apply-guide");
|
|
196
227
|
}
|
|
197
228
|
|
|
198
229
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
package/lib/init.mjs
CHANGED
|
@@ -69,6 +69,14 @@ function main() {
|
|
|
69
69
|
content: buildContextMarkdown(),
|
|
70
70
|
generator: "construct/init",
|
|
71
71
|
});
|
|
72
|
+
writeStampedIfMissing({
|
|
73
|
+
targetRoot: target,
|
|
74
|
+
created,
|
|
75
|
+
skipped,
|
|
76
|
+
filePath: path.join(target, ".cx", "brand-voice.json"),
|
|
77
|
+
content: `${JSON.stringify({ version: 1, formality: 3, toneOverride: {}, audienceLexicon: { prefer: [], avoid: [] } }, null, 2)}\n`,
|
|
78
|
+
generator: "construct/init",
|
|
79
|
+
});
|
|
72
80
|
// `.cx/` already exists from the context writes above and is gitignored in full
|
|
73
81
|
// (ADR-0027), so a keep file there could never be tracked; `.cx/inbox/` is the local
|
|
74
82
|
// intake drop zone the watcher polls. Create the directories; write no dead keep file.
|