@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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/specialists/roster.mjs — lazy specialist catalog for runtime resolution
|
|
3
|
+
* (construct-ymp5).
|
|
4
|
+
*
|
|
5
|
+
* The specialist catalog is resolved at runtime through orchestration_policy rather
|
|
6
|
+
* than inlined into synced orchestrator prompts. Each catalog entry carries id and
|
|
7
|
+
* whenToUse for routing discovery without an always-on prompt block.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const REGISTRY_PATH = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'specialists', 'registry.json');
|
|
14
|
+
|
|
15
|
+
function loadRegistry(rootDir = null) {
|
|
16
|
+
const path = rootDir
|
|
17
|
+
? join(rootDir, 'specialists', 'registry.json')
|
|
18
|
+
: REGISTRY_PATH;
|
|
19
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compact specialist catalog for orchestration_policy responses. Each entry names
|
|
24
|
+
* the cx-prefixed id and the routing hint (when_to_use when present, else description).
|
|
25
|
+
*/
|
|
26
|
+
export function buildSpecialistCatalog({ rootDir = null, includeInternal = true } = {}) {
|
|
27
|
+
const registry = loadRegistry(rootDir);
|
|
28
|
+
const prefix = registry.prefix || 'cx';
|
|
29
|
+
const specialists = Array.isArray(registry.specialists) ? registry.specialists : [];
|
|
30
|
+
return specialists
|
|
31
|
+
.filter((s) => includeInternal || !s.internal)
|
|
32
|
+
.map((s) => ({
|
|
33
|
+
id: `${prefix}-${s.name}`,
|
|
34
|
+
whenToUse: s.when_to_use || s.description || '',
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Legacy text roster shape retained for tests and migration comparisons.
|
|
40
|
+
*/
|
|
41
|
+
export function formatSpecialistRosterText(catalog) {
|
|
42
|
+
return catalog.map((row) => `- ${row.id}: ${row.whenToUse}`).join('\n');
|
|
43
|
+
}
|
|
@@ -51,6 +51,62 @@ export function renderSkeleton({ role, perspective = {}, roleGuidance } = {}) {
|
|
|
51
51
|
return `---\n${yaml.dump(fm).trimEnd()}\n---\n\n${body}`;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function buildFrontmatterFromRegistry(role, { perspective, roleGuidance, roleOverlays, docArtifacts } = {}) {
|
|
55
|
+
if (!perspective || typeof perspective !== 'object') {
|
|
56
|
+
throw new Error(`perspective is required to wrap legacy prompt cx-${role} (frontmatter is the source of truth)`);
|
|
57
|
+
}
|
|
58
|
+
const fm = {
|
|
59
|
+
name: `cx-${role}`,
|
|
60
|
+
role,
|
|
61
|
+
version: 1,
|
|
62
|
+
perspective,
|
|
63
|
+
};
|
|
64
|
+
if (roleGuidance) fm.roleGuidance = roleGuidance;
|
|
65
|
+
if (Array.isArray(roleOverlays) && roleOverlays.length) fm.roleOverlays = roleOverlays;
|
|
66
|
+
if (Array.isArray(docArtifacts) && docArtifacts.length) fm.templates = docArtifacts;
|
|
67
|
+
return fm;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Wrap a legacy prompt body with hybrid frontmatter from the registry entry.
|
|
72
|
+
* The body bytes are preserved (emit-neutral) aside from a trailing newline.
|
|
73
|
+
*/
|
|
74
|
+
export function wrapLegacyPromptWithFrontmatter({ role, perspective, registryEntry = {}, body }) {
|
|
75
|
+
const fm = buildFrontmatterFromRegistry(role, {
|
|
76
|
+
perspective,
|
|
77
|
+
roleGuidance: registryEntry.roleGuidance,
|
|
78
|
+
roleOverlays: registryEntry.roleOverlays,
|
|
79
|
+
docArtifacts: registryEntry.docArtifacts,
|
|
80
|
+
});
|
|
81
|
+
const normalizedBody = String(body ?? '').replace(/^\n+/, '');
|
|
82
|
+
const withNl = normalizedBody.endsWith('\n') ? normalizedBody : `${normalizedBody}\n`;
|
|
83
|
+
return `---\n${yaml.dump(fm).trimEnd()}\n---\n\n${withNl}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Convert one on-disk legacy prompt to hybrid format in place.
|
|
88
|
+
* @returns {{ path: string, relPath: string, converted: boolean }}
|
|
89
|
+
*/
|
|
90
|
+
export function convertLegacyPromptFile({ rootDir = process.cwd(), role, perspective, registryEntry } = {}) {
|
|
91
|
+
const relPath = promptRelPath(role);
|
|
92
|
+
const filePath = path.join(rootDir, relPath);
|
|
93
|
+
if (!fs.existsSync(filePath)) throw new Error(`${relPath} does not exist`);
|
|
94
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
95
|
+
const { frontmatter, body } = splitFrontmatter(raw);
|
|
96
|
+
if (frontmatter) return { path: filePath, relPath, converted: false };
|
|
97
|
+
|
|
98
|
+
const persp = perspective ?? registryEntry?.perspective;
|
|
99
|
+
if (!persp) {
|
|
100
|
+
throw new Error(`perspective required to convert ${relPath} — pass explicitly or supply registryEntry.perspective`);
|
|
101
|
+
}
|
|
102
|
+
const content = wrapLegacyPromptWithFrontmatter({ role, perspective: persp, registryEntry, body });
|
|
103
|
+
const { errors } = validatePromptContent({ content, id: `cx-${role}`, registryEntry });
|
|
104
|
+
if (errors.length) throw new Error(`convert ${relPath} failed:\n ${errors.join('\n ')}`);
|
|
105
|
+
|
|
106
|
+
fs.writeFileSync(filePath, content);
|
|
107
|
+
return { path: filePath, relPath, converted: true };
|
|
108
|
+
}
|
|
109
|
+
|
|
54
110
|
/**
|
|
55
111
|
* Create a specialist prompt draft on disk. Refuses to overwrite. Validates
|
|
56
112
|
* the rendered skeleton before writing.
|
package/lib/storage/backend.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/storage/backend.mjs — shared storage backend helpers.
|
|
3
3
|
*
|
|
4
|
-
* Construct
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Postgres orchestration.
|
|
4
|
+
* Construct uses embedded LanceDB and Git-backed state. createSqlClient and
|
|
5
|
+
* related helpers are stubs that keep existing imports working without
|
|
6
|
+
* orchestrating local Postgres.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
export function createSqlClient(env = process.env) {
|
|
11
|
-
//
|
|
12
|
-
//
|
|
10
|
+
// Stub: local-first operations skip Postgres, so external DATABASE_URL has
|
|
11
|
+
// no effect here.
|
|
12
|
+
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/storage/hybrid-query.mjs — unified search across knowledge and facts.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Stub for the LanceDB-backed search.
|
|
5
5
|
*/
|
|
6
6
|
import { VectorClient } from './vector-client.mjs';
|
|
7
7
|
|
|
8
8
|
export async function buildHybridSearchResultsAsync(rootDir, query, { limit = 10, env = process.env } = {}) {
|
|
9
|
-
//
|
|
9
|
+
// Embed the query
|
|
10
|
+
|
|
10
11
|
const { embedText } = await import('./embeddings-engine.mjs');
|
|
11
12
|
const { embedding } = await embedText(query, { env });
|
|
12
13
|
|
|
13
|
-
//
|
|
14
|
+
// Search LanceDB documents and observations
|
|
15
|
+
|
|
14
16
|
const client = new VectorClient({ env });
|
|
15
17
|
const docs = await client.searchDocuments({ project: 'construct', queryEmbedding: embedding, limit });
|
|
16
18
|
const obs = await client.searchObservations({ project: 'construct', queryEmbedding: embedding, limit });
|
|
17
19
|
|
|
18
|
-
//
|
|
20
|
+
// Merge both result sets and rank by similarity
|
|
21
|
+
|
|
19
22
|
const all = [...docs.map(d => ({ ...d, type: 'document' })), ...obs.map(o => ({ ...o, type: 'observation' }))];
|
|
20
23
|
return all.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
21
24
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, readdirSync, statSync, readFileSync } from 'node:fs';
|
|
6
6
|
import { basename, extname, join, relative } from 'node:path';
|
|
7
|
-
import { EXTRACTABLE_DOCUMENT_EXTS,
|
|
7
|
+
import { EXTRACTABLE_DOCUMENT_EXTS, extractDocumentTextNodeNative } from '../document-extract.mjs';
|
|
8
8
|
|
|
9
9
|
function readJsonIfExists(filePath) {
|
|
10
10
|
if (!existsSync(filePath)) return null;
|
|
@@ -28,7 +28,7 @@ function titleFromPath(filePath) {
|
|
|
28
28
|
return basename(filePath, extname(filePath)).replace(/[-_]+/g, ' ');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function collectTextFiles(rootDir, dirs, { extensions = EXTRACTABLE_DOCUMENT_EXTS } = {}) {
|
|
31
|
+
async function collectTextFiles(rootDir, dirs, { extensions = EXTRACTABLE_DOCUMENT_EXTS } = {}) {
|
|
32
32
|
const files = [];
|
|
33
33
|
for (const dir of dirs) {
|
|
34
34
|
const abs = join(rootDir, dir);
|
|
@@ -47,7 +47,7 @@ function collectTextFiles(rootDir, dirs, { extensions = EXTRACTABLE_DOCUMENT_EXT
|
|
|
47
47
|
try {
|
|
48
48
|
const stat = statSync(full);
|
|
49
49
|
if (stat.size > 5_000_000) continue;
|
|
50
|
-
const body =
|
|
50
|
+
const body = (await extractDocumentTextNodeNative(full, { maxChars: 200_000 })).text;
|
|
51
51
|
files.push({
|
|
52
52
|
path: relative(rootDir, full),
|
|
53
53
|
title: titleFromPath(full),
|
|
@@ -62,12 +62,12 @@ function collectTextFiles(rootDir, dirs, { extensions = EXTRACTABLE_DOCUMENT_EXT
|
|
|
62
62
|
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export function loadStateSnapshot(rootDir) {
|
|
65
|
+
export async function loadStateSnapshot(rootDir) {
|
|
66
66
|
const contextJsonPath = join(rootDir, '.cx', 'context.json');
|
|
67
67
|
const planPath = join(rootDir, 'plan.md');
|
|
68
68
|
const architecturePath = join(rootDir, 'docs', 'architecture.md');
|
|
69
69
|
const docsReadmePath = join(rootDir, 'docs', 'README.md');
|
|
70
|
-
const productIntelDocs = collectTextFiles(rootDir, [
|
|
70
|
+
const productIntelDocs = await collectTextFiles(rootDir, [
|
|
71
71
|
'.cx/knowledge',
|
|
72
72
|
'docs/prd',
|
|
73
73
|
'docs/meta-prd',
|
package/lib/storage/sync.mjs
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* lib/storage/sync.mjs — sync file-state artifacts into local LanceDB indices.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* one, matching the new local-first, Git-backed architecture.
|
|
5
|
+
* Syncs into LanceDB indices, matching the local-first, Git-backed architecture.
|
|
7
6
|
*/
|
|
8
7
|
import crypto from 'node:crypto';
|
|
9
8
|
import { loadStateSnapshot } from './state-source.mjs';
|
|
@@ -87,7 +86,7 @@ function toDocumentRows(rootDir, snapshot, project = 'construct') {
|
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
export async function syncFileStateToSql(rootDir, { env = process.env, project = 'construct' } = {}) {
|
|
90
|
-
const snapshot = loadStateSnapshot(rootDir);
|
|
89
|
+
const snapshot = await loadStateSnapshot(rootDir);
|
|
91
90
|
const rows = toDocumentRows(rootDir, snapshot, project);
|
|
92
91
|
|
|
93
92
|
const modelInfo = await getEmbeddingModelInfo({ env });
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/telemetry/rule-calls.mjs — record when a rule path is referenced at runtime.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors hook-calls telemetry: append-only JSONL at ~/.cx/rule-calls.jsonl.
|
|
5
|
+
* Consumed by `construct rules usage` for consolidation decisions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { appendBounded } from '../logging/rotate.mjs';
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_LOG_PATH = path.join(os.homedir(), '.cx', 'rule-calls.jsonl');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} event
|
|
17
|
+
* @param {string} event.rulePath — e.g. rules/common/no-fabrication.md
|
|
18
|
+
* @param {string} event.source — mcp | hook | prompt-composer | validation | other
|
|
19
|
+
* @param {string} [event.callerContext]
|
|
20
|
+
*/
|
|
21
|
+
export function logRuleCall(event, { logPath = DEFAULT_LOG_PATH, env = process.env } = {}) {
|
|
22
|
+
if (env.CONSTRUCT_RULE_TELEMETRY === 'off') return;
|
|
23
|
+
const entry = {
|
|
24
|
+
ts: new Date().toISOString(),
|
|
25
|
+
rulePath: event.rulePath,
|
|
26
|
+
source: event.source || 'other',
|
|
27
|
+
callerContext: event.callerContext || null,
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
appendBounded('rule-calls', logPath, `${JSON.stringify(entry)}\n`);
|
|
31
|
+
} catch {
|
|
32
|
+
/* non-fatal */
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function summarizeRuleCalls({ logPath = DEFAULT_LOG_PATH, since = '30d' } = {}) {
|
|
37
|
+
if (!fs.existsSync(logPath)) return { rules: {}, total: 0 };
|
|
38
|
+
const ms = since.endsWith('d') ? parseInt(since, 10) * 86400000 : 30 * 86400000;
|
|
39
|
+
const cutoff = Date.now() - ms;
|
|
40
|
+
const rules = {};
|
|
41
|
+
let total = 0;
|
|
42
|
+
for (const line of fs.readFileSync(logPath, 'utf8').split('\n')) {
|
|
43
|
+
if (!line.trim()) continue;
|
|
44
|
+
try {
|
|
45
|
+
const row = JSON.parse(line);
|
|
46
|
+
if (Date.parse(row.ts) < cutoff) continue;
|
|
47
|
+
total += 1;
|
|
48
|
+
rules[row.rulePath] = (rules[row.rulePath] || 0) + 1;
|
|
49
|
+
} catch { /* skip */ }
|
|
50
|
+
}
|
|
51
|
+
return { rules, total, since };
|
|
52
|
+
}
|
|
@@ -20,7 +20,7 @@ export const SPECIALIST_TEMPLATES = {
|
|
|
20
20
|
// Tranche 1 — five new templates authored alongside this map.
|
|
21
21
|
'cx-reviewer': ['code-review-report'],
|
|
22
22
|
'cx-security': ['security-audit-report'],
|
|
23
|
-
'cx-qa': ['qa-report', 'test-plan'],
|
|
23
|
+
'cx-qa': ['qa-report', 'test-plan', 'qa-strategy'],
|
|
24
24
|
'cx-debugger': ['debug-investigation'],
|
|
25
25
|
'cx-devil-advocate': ['verdict'],
|
|
26
26
|
'cx-evaluator': ['verdict'],
|
|
@@ -31,7 +31,7 @@ export const SPECIALIST_TEMPLATES = {
|
|
|
31
31
|
// Already-wired specialists pinned here so the gate guards them against drift.
|
|
32
32
|
'cx-architect': ['adr', 'rfc', 'architecture-review'],
|
|
33
33
|
'cx-researcher': ['research-brief', 'evidence-brief'],
|
|
34
|
-
'cx-sre': ['runbook', 'incident-report'],
|
|
34
|
+
'cx-sre': ['runbook', 'incident-report', 'postmortem'],
|
|
35
35
|
'cx-product-manager': ['prd', 'meta-prd'],
|
|
36
36
|
|
|
37
37
|
// Tranche 2 — three lower-frequency artifacts.
|
|
@@ -1,66 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* lib/templates/visual-requirements.mjs — required visuals per document type.
|
|
2
|
+
* lib/templates/visual-requirements.mjs — required visuals and structure per document type.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* enforces them. The shipped template for each listed type must satisfy its own
|
|
8
|
-
* requirements — pinned by tests/template-visuals.test.mjs — so the templates can
|
|
9
|
-
* never drift out of step with the matrix (beads wvbf.10 / wvbf.11).
|
|
4
|
+
* Loads structure and visual requirements from specialists/artifact-manifest.json
|
|
5
|
+
* (single source of truth) and merges legacy types not yet in the manifest.
|
|
6
|
+
* Paired with docs/concepts/doc-visual-matrix.md; pinned by template tests.
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
import { validateArtifactPostconditions } from '../contracts/validate.mjs';
|
|
10
|
+
import {
|
|
11
|
+
structureRequirementsFromManifest,
|
|
12
|
+
visualRequirementsFromManifest,
|
|
13
|
+
getArtifactEntry,
|
|
14
|
+
} from '../artifact-manifest.mjs';
|
|
15
|
+
|
|
16
|
+
const LEGACY_STRUCTURE = {
|
|
17
|
+
'persona-artifact': ['Goals', 'Frustrations', 'Decision rights', 'Output contract', 'Failure modes', 'Evidence'],
|
|
18
|
+
'skill-artifact': ['What this skill produces', 'When to invoke it', 'Competency rubric', 'Failure modes', 'Worked example'],
|
|
19
|
+
'research-finding': ['SOURCES', 'FINDINGS', 'INFERENCES', 'CONFIDENCE', 'GAPS', 'RECOMMENDATION'],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const STRUCTURE_REQUIREMENTS = {
|
|
23
|
+
...structureRequirementsFromManifest(),
|
|
24
|
+
...LEGACY_STRUCTURE,
|
|
25
|
+
};
|
|
13
26
|
|
|
14
27
|
export const VISUAL_REQUIREMENTS = {
|
|
15
|
-
|
|
16
|
-
{ id: 'runbook-diagnostic-flowchart', check: 'artifact-has-mermaid', diagram: 'flowchart' },
|
|
17
|
-
],
|
|
18
|
-
'incident-report': [
|
|
19
|
-
{ id: 'incident-timeline-table', check: 'artifact-table-has-columns', columns: ['Time (UTC)', 'Event'] },
|
|
20
|
-
],
|
|
21
|
-
rfc: [
|
|
22
|
-
{ id: 'rfc-sequence-diagram', check: 'artifact-has-mermaid', diagram: 'sequenceDiagram' },
|
|
23
|
-
],
|
|
28
|
+
...visualRequirementsFromManifest(),
|
|
24
29
|
};
|
|
25
30
|
|
|
26
31
|
export function visualRequirementTypes() {
|
|
27
32
|
return Object.keys(VISUAL_REQUIREMENTS);
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
// The structural floor of the quality rubric (ADR-0018): the sections a domain
|
|
31
|
-
// expert expects for each doc type. Each shipped template must satisfy its own
|
|
32
|
-
// entry — pinned by tests/structure-requirements.test.mjs — so a template can
|
|
33
|
-
// never quietly drop a required section. Section requirements compose with the
|
|
34
|
-
// VISUAL_REQUIREMENTS above; lintDocStructure runs both.
|
|
35
|
-
|
|
36
|
-
export const STRUCTURE_REQUIREMENTS = {
|
|
37
|
-
adr: ['Problem', 'Decision', 'Rejected alternatives', 'Consequences', 'Reversibility'],
|
|
38
|
-
rfc: ['Summary', 'Motivation', 'Proposed design', 'Risks', 'Verification'],
|
|
39
|
-
prd: ['Problem', 'Goals', 'Success metrics', 'Risks and mitigations'],
|
|
40
|
-
'research-brief': ['Sources', 'Findings', 'Confidence summary', 'Recommendation'],
|
|
41
|
-
'incident-report': ['Summary', 'Severity rationale', 'Impact', 'Timeline', 'Trigger', 'Root cause', 'Contributing factors', 'Action items'],
|
|
42
|
-
runbook: ['Alert trigger', 'Symptoms', 'Impact', 'Severity and response', 'Diagnostic steps', 'Remediation', 'Rollback', 'Escalation'],
|
|
43
|
-
strategy: ['Vision', 'Bets', 'Non-bets', 'North Star Metric', 'Metrics', 'Milestones', 'Risks'],
|
|
44
|
-
'signal-brief': ['Signal', 'Evidence', 'Counter-signal', 'What would make this actionable'],
|
|
45
|
-
prfaq: ['Problem statement', 'Press release', 'External FAQ', 'Internal FAQ', 'Evidence appendix'],
|
|
46
|
-
'customer-profile': ['Snapshot', 'Active pain points', 'Open asks', 'Evidence links'],
|
|
47
|
-
'one-pager': ['Problem', 'Proposal', 'Why now', 'Success measure', 'Cost', 'Asks'],
|
|
48
|
-
'product-intelligence-report': ['Executive readout', 'Evidence base', 'Themes', 'Customer asks', 'Product implications', 'Recommended actions', 'Gaps and risks'],
|
|
49
|
-
'backlog-proposal': ['Source evidence', 'Proposed changes', 'Duplicate and conflict check', 'Approval request'],
|
|
50
|
-
'persona-artifact': ['Goals', 'Frustrations', 'Decision rights', 'Output contract', 'Failure modes', 'Evidence'],
|
|
51
|
-
'skill-artifact': ['What this skill produces', 'When to invoke it', 'Competency rubric', 'Failure modes', 'Worked example'],
|
|
52
|
-
'research-finding': ['SOURCES', 'FINDINGS', 'INFERENCES', 'CONFIDENCE', 'GAPS', 'RECOMMENDATION'],
|
|
53
|
-
};
|
|
54
|
-
|
|
55
35
|
export function structureRequirementTypes() {
|
|
56
36
|
return [...new Set([...Object.keys(STRUCTURE_REQUIREMENTS), ...Object.keys(VISUAL_REQUIREMENTS)])];
|
|
57
37
|
}
|
|
58
38
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
39
|
+
export function resolveTemplatePath(type, rootDir) {
|
|
40
|
+
const entry = getArtifactEntry(type, { rootDir });
|
|
41
|
+
if (entry?.template) return entry.template;
|
|
42
|
+
return `templates/docs/${type}.md`;
|
|
43
|
+
}
|
|
44
|
+
|
|
64
45
|
export function lintDocStructure(filePath, type) {
|
|
65
46
|
const sectionChecks = (STRUCTURE_REQUIREMENTS[type] || []).map((section) => ({
|
|
66
47
|
id: `${type}-section-${section}`,
|
|
@@ -72,11 +53,6 @@ export function lintDocStructure(filePath, type) {
|
|
|
72
53
|
return validateArtifactPostconditions({ contract: { postconditions }, artifactPath: filePath });
|
|
73
54
|
}
|
|
74
55
|
|
|
75
|
-
/**
|
|
76
|
-
* Lint one document against the visual requirements for its type. Returns an
|
|
77
|
-
* array of violation strings (empty when satisfied, or when the type has no
|
|
78
|
-
* declared visual requirements).
|
|
79
|
-
*/
|
|
80
56
|
export function lintDocVisuals(filePath, type) {
|
|
81
57
|
const postconditions = VISUAL_REQUIREMENTS[type];
|
|
82
58
|
if (!postconditions) return [];
|