@lsctech/polaris 0.1.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 +87 -0
- package/dist/__mocks__/tool-server-linear.js +34 -0
- package/dist/cli/adopt-approve.js +60 -0
- package/dist/cli/adopt-cognition.js +199 -0
- package/dist/cli/adopt-instructions.js +143 -0
- package/dist/cli/adopt-rules.js +169 -0
- package/dist/cli/adopt-scan.js +25 -0
- package/dist/cli/adopt-smartdocs.js +192 -0
- package/dist/cli/adoption-inventory.js +350 -0
- package/dist/cli/adoption-plan.js +222 -0
- package/dist/cli/args.js +28 -0
- package/dist/cli/args.test.js +30 -0
- package/dist/cli/branding.js +41 -0
- package/dist/cli/graph.js +358 -0
- package/dist/cli/index.js +127 -0
- package/dist/cli/index.test.js +162 -0
- package/dist/cli/init-detect.js +61 -0
- package/dist/cli/init.js +492 -0
- package/dist/cli/init.test.js +259 -0
- package/dist/cli/librarian.js +32 -0
- package/dist/cli/medic.js +96 -0
- package/dist/cli/startup.test.js +23 -0
- package/dist/cli/tracker.js +130 -0
- package/dist/cli/tracker.test.js +126 -0
- package/dist/cli/version.js +10 -0
- package/dist/cli/version.test.js +11 -0
- package/dist/cli/worker.js +287 -0
- package/dist/cluster-state/fixtures/test-clusters.json +19 -0
- package/dist/cluster-state/store.js +302 -0
- package/dist/cluster-state/store.test.js +145 -0
- package/dist/cluster-state/types.js +2 -0
- package/dist/cognition/archive.js +158 -0
- package/dist/cognition/closeout-librarian-types.js +161 -0
- package/dist/cognition/cognition.test.js +623 -0
- package/dist/cognition/index.js +41 -0
- package/dist/cognition/librarian-dispatch.js +391 -0
- package/dist/cognition/librarian-dispatch.test.js +247 -0
- package/dist/cognition/librarian-packet.js +313 -0
- package/dist/cognition/librarian-types.js +57 -0
- package/dist/cognition/route-cognition-delta.js +350 -0
- package/dist/cognition/summary-delta.js +279 -0
- package/dist/cognition/validate.js +162 -0
- package/dist/config/defaults.js +98 -0
- package/dist/config/doctor.js +273 -0
- package/dist/config/index.js +14 -0
- package/dist/config/loader.js +58 -0
- package/dist/config/provider-detect.js +60 -0
- package/dist/config/provider-detect.test.js +119 -0
- package/dist/config/schema.js +2 -0
- package/dist/config/show.js +44 -0
- package/dist/config/show.test.js +42 -0
- package/dist/config/validator.js +675 -0
- package/dist/config/validator.test.js +77 -0
- package/dist/docs/canon-check.js +334 -0
- package/dist/docs/canon-check.test.js +207 -0
- package/dist/docs/doctrine.js +133 -0
- package/dist/docs/doctrine.test.js +139 -0
- package/dist/docs/index.js +168 -0
- package/dist/docs/index.test.js +83 -0
- package/dist/docs/ingest.js +295 -0
- package/dist/docs/ingest.test.js +71 -0
- package/dist/docs/migrate.js +165 -0
- package/dist/docs/migrate.test.js +136 -0
- package/dist/docs/seed-instructions.js +147 -0
- package/dist/docs/seed-instructions.test.js +137 -0
- package/dist/docs/validate-instructions.js +267 -0
- package/dist/docs/validate-instructions.test.js +238 -0
- package/dist/finalize/artifact-policy.js +214 -0
- package/dist/finalize/artifact-policy.test.js +84 -0
- package/dist/finalize/delivery-integrity.js +141 -0
- package/dist/finalize/finalize.test.js +210 -0
- package/dist/finalize/github.js +41 -0
- package/dist/finalize/index.js +474 -0
- package/dist/finalize/linear.js +213 -0
- package/dist/finalize/run-report.js +47 -0
- package/dist/finalize/steps/01-map-update.js +11 -0
- package/dist/finalize/steps/02-map-validate.js +11 -0
- package/dist/finalize/steps/03-schema-validate.js +11 -0
- package/dist/finalize/steps/04-run-checks.js +118 -0
- package/dist/finalize/steps/05-generate-report.js +14 -0
- package/dist/finalize/steps/06-commit.js +39 -0
- package/dist/finalize/steps/07-push.js +10 -0
- package/dist/finalize/steps/08-create-pr.js +9 -0
- package/dist/finalize/steps/09-update-state.js +9 -0
- package/dist/finalize/steps/10-append-jsonl.js +23 -0
- package/dist/finalize/steps/11-update-linear.js +22 -0
- package/dist/finalize/steps/12-archive.js +21 -0
- package/dist/graph/adapter/c/adapter.js +45 -0
- package/dist/graph/adapter/c/extract.js +135 -0
- package/dist/graph/adapter/c/index.js +10 -0
- package/dist/graph/adapter/c/runtime.js +67 -0
- package/dist/graph/adapter/cpp/adapter.js +45 -0
- package/dist/graph/adapter/cpp/extract.js +159 -0
- package/dist/graph/adapter/cpp/index.js +10 -0
- package/dist/graph/adapter/cpp/runtime.js +61 -0
- package/dist/graph/adapter/csharp/adapter.js +45 -0
- package/dist/graph/adapter/csharp/extract.js +127 -0
- package/dist/graph/adapter/csharp/index.js +10 -0
- package/dist/graph/adapter/csharp/runtime.js +61 -0
- package/dist/graph/adapter/dart/adapter.js +56 -0
- package/dist/graph/adapter/dart/extract.js +130 -0
- package/dist/graph/adapter/dart/index.js +10 -0
- package/dist/graph/adapter/dart/runtime.js +61 -0
- package/dist/graph/adapter/go/adapter.js +45 -0
- package/dist/graph/adapter/go/extract.js +112 -0
- package/dist/graph/adapter/go/index.js +10 -0
- package/dist/graph/adapter/go/runtime.js +58 -0
- package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
- package/dist/graph/adapter/kotlin-java/index.js +15 -0
- package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
- package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
- package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
- package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
- package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
- package/dist/graph/adapter/python/adapter.js +45 -0
- package/dist/graph/adapter/python/extract.js +121 -0
- package/dist/graph/adapter/python/index.js +10 -0
- package/dist/graph/adapter/python/runtime.js +70 -0
- package/dist/graph/adapter/registry.js +82 -0
- package/dist/graph/adapter/rust/adapter.js +45 -0
- package/dist/graph/adapter/rust/extract.js +110 -0
- package/dist/graph/adapter/rust/index.js +10 -0
- package/dist/graph/adapter/rust/runtime.js +74 -0
- package/dist/graph/adapter/shell/adapter.js +34 -0
- package/dist/graph/adapter/shell/extract.js +98 -0
- package/dist/graph/adapter/shell/index.js +8 -0
- package/dist/graph/adapter/svelte/adapter.js +91 -0
- package/dist/graph/adapter/svelte/extract.js +41 -0
- package/dist/graph/adapter/svelte/index.js +8 -0
- package/dist/graph/adapter/swift/adapter.js +45 -0
- package/dist/graph/adapter/swift/extract.js +120 -0
- package/dist/graph/adapter/swift/index.js +10 -0
- package/dist/graph/adapter/swift/runtime.js +70 -0
- package/dist/graph/adapter/types.js +2 -0
- package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
- package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
- package/dist/graph/adapter/typescript-javascript/index.js +10 -0
- package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
- package/dist/graph/capability/index.js +105 -0
- package/dist/graph/governance.js +104 -0
- package/dist/graph/parser/extract.js +5 -0
- package/dist/graph/parser/loader.js +2 -0
- package/dist/graph/parser/pipeline.js +194 -0
- package/dist/graph/query/index.js +277 -0
- package/dist/graph/query/types.js +5 -0
- package/dist/graph/resolver/build-edges.js +211 -0
- package/dist/graph/resolver/index.js +23 -0
- package/dist/graph/resolver/resolve-imports.js +168 -0
- package/dist/graph/store/adapter.js +132 -0
- package/dist/graph/store/queries.js +124 -0
- package/dist/graph/store/types.js +4 -0
- package/dist/ignore/defaults.js +41 -0
- package/dist/ignore/parser.js +39 -0
- package/dist/lint/map-reference-validator.js +72 -0
- package/dist/loop/abort.js +188 -0
- package/dist/loop/abort.test.js +151 -0
- package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
- package/dist/loop/adapters/agent-subtask.js +137 -0
- package/dist/loop/adapters/agent-subtask.test.js +151 -0
- package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
- package/dist/loop/adapters/index.js +9 -0
- package/dist/loop/adapters/registry.js +17 -0
- package/dist/loop/adapters/terminal-cli.js +403 -0
- package/dist/loop/adapters/types.js +2 -0
- package/dist/loop/adapters/worker-instructions.js +85 -0
- package/dist/loop/body-parser.js +226 -0
- package/dist/loop/bootstrap-packet.js +97 -0
- package/dist/loop/bootstrap-packet.test.js +171 -0
- package/dist/loop/branch-governance.js +54 -0
- package/dist/loop/budget.js +63 -0
- package/dist/loop/budget.test.js +163 -0
- package/dist/loop/checkpoint.js +325 -0
- package/dist/loop/compact-return.js +59 -0
- package/dist/loop/continue.js +645 -0
- package/dist/loop/continue.test.js +337 -0
- package/dist/loop/dispatch-boundary.js +335 -0
- package/dist/loop/dispatch-state.js +223 -0
- package/dist/loop/dispatch-state.test.js +186 -0
- package/dist/loop/dispatch.js +1236 -0
- package/dist/loop/dispatch.test.js +499 -0
- package/dist/loop/ephemeral-smoke.test.js +160 -0
- package/dist/loop/evidence-backfill.js +216 -0
- package/dist/loop/execution-adapter.js +141 -0
- package/dist/loop/execution-adapter.test.js +66 -0
- package/dist/loop/finalize-evidence.js +169 -0
- package/dist/loop/git-custody.js +250 -0
- package/dist/loop/impl-packet-input.js +38 -0
- package/dist/loop/index.js +270 -0
- package/dist/loop/ledger.js +49 -0
- package/dist/loop/ledger.test.js +127 -0
- package/dist/loop/lifecycle-dispatch.js +348 -0
- package/dist/loop/lifecycle-dispatch.test.js +318 -0
- package/dist/loop/lifecycle.js +93 -0
- package/dist/loop/lifecycle.test.js +150 -0
- package/dist/loop/orphan-recovery.js +276 -0
- package/dist/loop/orphan-recovery.test.js +236 -0
- package/dist/loop/parent.js +1566 -0
- package/dist/loop/parent.test.js +738 -0
- package/dist/loop/provider-sealed-packet.test.js +164 -0
- package/dist/loop/resume.js +295 -0
- package/dist/loop/resume.test.js +172 -0
- package/dist/loop/run-bootstrap.js +234 -0
- package/dist/loop/run-preflight.js +203 -0
- package/dist/loop/status.js +665 -0
- package/dist/loop/status.test.js +235 -0
- package/dist/loop/wait.js +86 -0
- package/dist/loop/worker-packet.js +406 -0
- package/dist/loop/worker-packet.test.js +243 -0
- package/dist/loop/worker-prompt.js +260 -0
- package/dist/loop/worker-prompt.test.js +247 -0
- package/dist/loop/worker.js +498 -0
- package/dist/loop/worker.test.js +372 -0
- package/dist/map/atlas.js +77 -0
- package/dist/map/backfill.js +171 -0
- package/dist/map/backfill.test.js +120 -0
- package/dist/map/index.js +255 -0
- package/dist/map/inference.js +73 -0
- package/dist/map/inference.test.js +35 -0
- package/dist/map/query.js +157 -0
- package/dist/map/query.test.js +174 -0
- package/dist/map/update.js +355 -0
- package/dist/map/update.test.js +67 -0
- package/dist/map/validate.js +153 -0
- package/dist/map/validate.test.js +90 -0
- package/dist/map/welfare.js +86 -0
- package/dist/mcp/lib/invoke.js +35 -0
- package/dist/mcp/lib/redact.js +24 -0
- package/dist/mcp/lib/redact.test.js +112 -0
- package/dist/mcp/lib/root.js +41 -0
- package/dist/mcp/lib/root.test.js +114 -0
- package/dist/mcp/server.js +15 -0
- package/dist/mcp/tools/claim-child.js +119 -0
- package/dist/mcp/tools/claim-child.test.js +69 -0
- package/dist/mcp/tools/current-state.js +73 -0
- package/dist/mcp/tools/current-state.test.js +114 -0
- package/dist/mcp/tools/dispatch-result.js +186 -0
- package/dist/mcp/tools/dispatch-result.test.js +109 -0
- package/dist/mcp/tools/index.js +222 -0
- package/dist/mcp/tools/index.test.js +172 -0
- package/dist/mcp/tools/linear.js +74 -0
- package/dist/mcp/tools/loop-continue.js +159 -0
- package/dist/mcp/tools/loop-continue.test.js +186 -0
- package/dist/mcp/tools/loop-dry-run.js +15 -0
- package/dist/mcp/tools/status.js +65 -0
- package/dist/medic/chart-id.js +75 -0
- package/dist/medic/chart-schema.js +139 -0
- package/dist/runs/index.js +119 -0
- package/dist/runs/index.test.js +184 -0
- package/dist/runs/ledger-tail.js +15 -0
- package/dist/runs/list.js +29 -0
- package/dist/runs/reconcile.js +74 -0
- package/dist/runs/show.js +10 -0
- package/dist/runtime/audit/logger.js +15 -0
- package/dist/runtime/audit/reader.js +42 -0
- package/dist/runtime/checkpoint.js +89 -0
- package/dist/runtime/continuation/confirmed.js +225 -0
- package/dist/runtime/continuation/confirmed.test.js +421 -0
- package/dist/runtime/continuation/dry-run.js +74 -0
- package/dist/runtime/execution-window.js +106 -0
- package/dist/runtime/scheduling/child-selector.js +16 -0
- package/dist/runtime/state.js +43 -0
- package/dist/runtime/status.js +46 -0
- package/dist/runtime/verification/envelope.js +80 -0
- package/dist/runtime/verification/fingerprint.js +26 -0
- package/dist/skill-packet/cli.test.js +105 -0
- package/dist/skill-packet/generator.js +225 -0
- package/dist/skill-packet/generator.test.js +159 -0
- package/dist/skill-packet/index.js +49 -0
- package/dist/skill-packet/types.js +2 -0
- package/dist/smartdocs-engine/audit.js +194 -0
- package/dist/smartdocs-engine/audit.test.js +122 -0
- package/dist/smartdocs-engine/canon-check.js +340 -0
- package/dist/smartdocs-engine/canon-check.test.js +234 -0
- package/dist/smartdocs-engine/doctrine.js +633 -0
- package/dist/smartdocs-engine/doctrine.test.js +374 -0
- package/dist/smartdocs-engine/index.js +456 -0
- package/dist/smartdocs-engine/index.test.js +82 -0
- package/dist/smartdocs-engine/ingest.js +495 -0
- package/dist/smartdocs-engine/ingest.test.js +163 -0
- package/dist/smartdocs-engine/migrate.js +217 -0
- package/dist/smartdocs-engine/migrate.test.js +200 -0
- package/dist/smartdocs-engine/seed-instructions.js +335 -0
- package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
- package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
- package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
- package/dist/smartdocs-engine/validate-instructions.js +366 -0
- package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
- package/dist/tracker/adapters/github/index.js +305 -0
- package/dist/tracker/adapters/jira/index.js +293 -0
- package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
- package/dist/tracker/adapters/linear/index.js +621 -0
- package/dist/tracker/adapters/linear/index.test.js +238 -0
- package/dist/tracker/adapters/linear.js +50 -0
- package/dist/tracker/adapters/local/index.js +10 -0
- package/dist/tracker/adapters/local-file/index.js +159 -0
- package/dist/tracker/adapters/mcp-bridge.js +158 -0
- package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
- package/dist/tracker/adapters/spec/index.js +146 -0
- package/dist/tracker/capabilities.js +2 -0
- package/dist/tracker/index.js +49 -0
- package/dist/tracker/lifecycle-policy.js +139 -0
- package/dist/tracker/lifecycle-transition.js +164 -0
- package/dist/tracker/local-graph.js +98 -0
- package/dist/tracker/migration.js +56 -0
- package/dist/tracker/schema.js +86 -0
- package/dist/tracker/sync/index.js +404 -0
- package/dist/tracker/sync/queue-store.js +95 -0
- package/dist/tracker/sync/queue-store.test.js +104 -0
- package/dist/tracker/types.js +11 -0
- package/dist/types/linear.js +3 -0
- package/dist/types/result-packet.js +12 -0
- package/dist/types/runtime-state.js +2 -0
- package/dist/types/work-contract.js +2 -0
- package/dist/utils/monotonic-timestamp.js +13 -0
- package/dist/utils/monotonic-timestamp.test.js +19 -0
- package/package.json +64 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CANDIDATE_MARKER = void 0;
|
|
4
|
+
exports.doctrineDraft = doctrineDraft;
|
|
5
|
+
exports.doctrinePromote = doctrinePromote;
|
|
6
|
+
exports.doctrineDeprecate = doctrineDeprecate;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
exports.CANDIDATE_MARKER = "<!-- polaris:doctrine-candidate -->";
|
|
10
|
+
function generateRunId() {
|
|
11
|
+
return `polaris-doctrine-${new Date().toISOString().slice(0, 10)}-001`;
|
|
12
|
+
}
|
|
13
|
+
function lifecycleFilePath(repoRoot, runId) {
|
|
14
|
+
return (0, node_path_1.join)(repoRoot, ".taskchain_artifacts", "polaris-doctrine", runId, "lifecycle.jsonl");
|
|
15
|
+
}
|
|
16
|
+
function appendLifecycle(lifecyclePath, event) {
|
|
17
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(lifecyclePath), { recursive: true });
|
|
18
|
+
(0, node_fs_1.appendFileSync)(lifecyclePath, JSON.stringify(event) + "\n", "utf-8");
|
|
19
|
+
}
|
|
20
|
+
function resolvePath(path, repoRoot) {
|
|
21
|
+
if (path.startsWith("/"))
|
|
22
|
+
return path;
|
|
23
|
+
return (0, node_path_1.join)((0, node_path_1.resolve)(repoRoot), path);
|
|
24
|
+
}
|
|
25
|
+
/** Move a doc from docs/raw/ or docs/doctrine/raw/ to docs/doctrine/candidate/ */
|
|
26
|
+
function doctrineDraft(path, options) {
|
|
27
|
+
const repoRoot = (0, node_path_1.resolve)(options.repoRoot);
|
|
28
|
+
const runId = options.runId ?? generateRunId();
|
|
29
|
+
const source = resolvePath(path, repoRoot);
|
|
30
|
+
if (!(0, node_fs_1.existsSync)(source)) {
|
|
31
|
+
throw new Error(`Source file not found: ${source}`);
|
|
32
|
+
}
|
|
33
|
+
const rawDir = (0, node_path_1.resolve)(repoRoot, "docs", "raw");
|
|
34
|
+
const doctrineRawDir = (0, node_path_1.resolve)(repoRoot, "docs", "doctrine", "raw");
|
|
35
|
+
const relToRaw = (0, node_path_1.relative)(rawDir, source);
|
|
36
|
+
const relToDoctrineRaw = (0, node_path_1.relative)(doctrineRawDir, source);
|
|
37
|
+
const isInRaw = !relToRaw.startsWith("..") && !relToRaw.startsWith("/");
|
|
38
|
+
const isInDoctrineRaw = !relToDoctrineRaw.startsWith("..") && !relToDoctrineRaw.startsWith("/");
|
|
39
|
+
if (!isInRaw && !isInDoctrineRaw) {
|
|
40
|
+
throw new Error(`doctrineDraft source must be in docs/raw/ or docs/doctrine/raw/ — got: ${source}`);
|
|
41
|
+
}
|
|
42
|
+
const candidateDir = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate");
|
|
43
|
+
(0, node_fs_1.mkdirSync)(candidateDir, { recursive: true });
|
|
44
|
+
const destination = (0, node_path_1.join)(candidateDir, (0, node_path_1.basename)(source));
|
|
45
|
+
if ((0, node_fs_1.existsSync)(destination)) {
|
|
46
|
+
throw new Error(`Destination already exists: ${destination}`);
|
|
47
|
+
}
|
|
48
|
+
const content = (0, node_fs_1.readFileSync)(source, "utf-8");
|
|
49
|
+
(0, node_fs_1.writeFileSync)(destination, `${exports.CANDIDATE_MARKER}\n${content}`, "utf-8");
|
|
50
|
+
(0, node_fs_1.unlinkSync)(source);
|
|
51
|
+
const lifecyclePath = lifecycleFilePath(repoRoot, runId);
|
|
52
|
+
appendLifecycle(lifecyclePath, {
|
|
53
|
+
event: "doctrine-draft",
|
|
54
|
+
run_id: runId,
|
|
55
|
+
source,
|
|
56
|
+
destination,
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
});
|
|
59
|
+
return { source, destination, runId, lifecyclePath };
|
|
60
|
+
}
|
|
61
|
+
/** Move a doc from docs/doctrine/candidate/ to docs/doctrine/active/ */
|
|
62
|
+
function doctrinePromote(path, options) {
|
|
63
|
+
const repoRoot = (0, node_path_1.resolve)(options.repoRoot);
|
|
64
|
+
const runId = options.runId ?? generateRunId();
|
|
65
|
+
const source = resolvePath(path, repoRoot);
|
|
66
|
+
if (!(0, node_fs_1.existsSync)(source)) {
|
|
67
|
+
throw new Error(`Source file not found: ${source}`);
|
|
68
|
+
}
|
|
69
|
+
const candidateDir = (0, node_path_1.resolve)(repoRoot, "docs", "doctrine", "candidate");
|
|
70
|
+
const relToCandidate = (0, node_path_1.relative)(candidateDir, source);
|
|
71
|
+
const isInCandidate = !relToCandidate.startsWith("..") && !relToCandidate.startsWith("/");
|
|
72
|
+
if (!isInCandidate) {
|
|
73
|
+
throw new Error(`doctrinePromote source must be in docs/doctrine/candidate/ — got: ${source}`);
|
|
74
|
+
}
|
|
75
|
+
const content = (0, node_fs_1.readFileSync)(source, "utf-8");
|
|
76
|
+
if (!content.includes(exports.CANDIDATE_MARKER)) {
|
|
77
|
+
throw new Error(`File is not in candidate state (missing ${exports.CANDIDATE_MARKER}): ${source}`);
|
|
78
|
+
}
|
|
79
|
+
const activeDir = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "active");
|
|
80
|
+
(0, node_fs_1.mkdirSync)(activeDir, { recursive: true });
|
|
81
|
+
const destination = (0, node_path_1.join)(activeDir, (0, node_path_1.basename)(source));
|
|
82
|
+
if ((0, node_fs_1.existsSync)(destination)) {
|
|
83
|
+
throw new Error(`Destination already exists: ${destination}`);
|
|
84
|
+
}
|
|
85
|
+
const activeContent = content.replace(`${exports.CANDIDATE_MARKER}\n`, "").replace(exports.CANDIDATE_MARKER, "");
|
|
86
|
+
(0, node_fs_1.writeFileSync)(destination, activeContent, "utf-8");
|
|
87
|
+
(0, node_fs_1.unlinkSync)(source);
|
|
88
|
+
const lifecyclePath = lifecycleFilePath(repoRoot, runId);
|
|
89
|
+
appendLifecycle(lifecyclePath, {
|
|
90
|
+
event: "doctrine-promote",
|
|
91
|
+
run_id: runId,
|
|
92
|
+
source,
|
|
93
|
+
destination,
|
|
94
|
+
timestamp: new Date().toISOString(),
|
|
95
|
+
});
|
|
96
|
+
return { source, destination, runId, lifecyclePath };
|
|
97
|
+
}
|
|
98
|
+
/** Move a doc from docs/doctrine/active/ to docs/doctrine/deprecated/ */
|
|
99
|
+
function doctrineDeprecate(path, options) {
|
|
100
|
+
const repoRoot = (0, node_path_1.resolve)(options.repoRoot);
|
|
101
|
+
const runId = options.runId ?? generateRunId();
|
|
102
|
+
const source = resolvePath(path, repoRoot);
|
|
103
|
+
if (!(0, node_fs_1.existsSync)(source)) {
|
|
104
|
+
throw new Error(`Source file not found: ${source}`);
|
|
105
|
+
}
|
|
106
|
+
const activeDir = (0, node_path_1.resolve)(repoRoot, "docs", "doctrine", "active");
|
|
107
|
+
const relToActive = (0, node_path_1.relative)(activeDir, source);
|
|
108
|
+
const isInActive = !relToActive.startsWith("..") && !relToActive.startsWith("/");
|
|
109
|
+
if (!isInActive) {
|
|
110
|
+
throw new Error(`doctrineDeprecate source must be in docs/doctrine/active/ — got: ${source}`);
|
|
111
|
+
}
|
|
112
|
+
const deprecatedDir = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "deprecated");
|
|
113
|
+
(0, node_fs_1.mkdirSync)(deprecatedDir, { recursive: true });
|
|
114
|
+
const destination = (0, node_path_1.join)(deprecatedDir, (0, node_path_1.basename)(source));
|
|
115
|
+
if ((0, node_fs_1.existsSync)(destination)) {
|
|
116
|
+
throw new Error(`Destination already exists: ${destination}`);
|
|
117
|
+
}
|
|
118
|
+
const content = (0, node_fs_1.readFileSync)(source, "utf-8");
|
|
119
|
+
const deprecatedAt = new Date().toISOString();
|
|
120
|
+
const deprecatedContent = `<!-- polaris:doctrine-deprecated deprecatedAt="${deprecatedAt}" runId="${runId}" -->\n${content}`;
|
|
121
|
+
(0, node_fs_1.writeFileSync)(destination, deprecatedContent, "utf-8");
|
|
122
|
+
(0, node_fs_1.unlinkSync)(source);
|
|
123
|
+
const lifecyclePath = lifecycleFilePath(repoRoot, runId);
|
|
124
|
+
appendLifecycle(lifecyclePath, {
|
|
125
|
+
event: "doctrine-deprecate",
|
|
126
|
+
run_id: runId,
|
|
127
|
+
source,
|
|
128
|
+
destination,
|
|
129
|
+
deprecated_at: deprecatedAt,
|
|
130
|
+
timestamp: deprecatedAt,
|
|
131
|
+
});
|
|
132
|
+
return { source, destination, runId, lifecyclePath };
|
|
133
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_fs_1 = require("node:fs");
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
const node_fs_2 = require("node:fs");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
|
+
const vitest_1 = require("vitest");
|
|
8
|
+
const doctrine_js_1 = require("./doctrine.js");
|
|
9
|
+
function makeTempDir() {
|
|
10
|
+
const root = (0, node_fs_2.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "polaris-doctrine-"));
|
|
11
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "docs", "raw"), { recursive: true });
|
|
12
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "docs", "doctrine", "raw"), { recursive: true });
|
|
13
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "docs", "doctrine", "candidate"), { recursive: true });
|
|
14
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "docs", "doctrine", "active"), { recursive: true });
|
|
15
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "docs", "doctrine", "deprecated"), { recursive: true });
|
|
16
|
+
return root;
|
|
17
|
+
}
|
|
18
|
+
(0, vitest_1.describe)("doctrineDraft", () => {
|
|
19
|
+
let repoRoot;
|
|
20
|
+
(0, vitest_1.beforeEach)(() => {
|
|
21
|
+
repoRoot = makeTempDir();
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.it)("moves a file from docs/raw/ to docs/doctrine/candidate/ with candidate marker", () => {
|
|
24
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "raw", "some-doc.md");
|
|
25
|
+
(0, node_fs_1.writeFileSync)(source, "# Some Doc\n\nContent here.");
|
|
26
|
+
const result = (0, doctrine_js_1.doctrineDraft)(source, { repoRoot, runId: "test-run-001" });
|
|
27
|
+
(0, vitest_1.expect)(result.destination).toBe((0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "some-doc.md"));
|
|
28
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(result.destination)).toBe(true);
|
|
29
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(source)).toBe(false);
|
|
30
|
+
const content = (0, node_fs_1.readFileSync)(result.destination, "utf-8");
|
|
31
|
+
(0, vitest_1.expect)(content.startsWith(doctrine_js_1.CANDIDATE_MARKER)).toBe(true);
|
|
32
|
+
(0, vitest_1.expect)(content).toContain("# Some Doc");
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)("moves a file from docs/doctrine/raw/ to docs/doctrine/candidate/", () => {
|
|
35
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "raw", "draft-doc.md");
|
|
36
|
+
(0, node_fs_1.writeFileSync)(source, "# Draft");
|
|
37
|
+
const result = (0, doctrine_js_1.doctrineDraft)(source, { repoRoot, runId: "test-run-001" });
|
|
38
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(result.destination)).toBe(true);
|
|
39
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(source)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)("emits a doctrine-draft event to lifecycle.jsonl", () => {
|
|
42
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "raw", "event-doc.md");
|
|
43
|
+
(0, node_fs_1.writeFileSync)(source, "# Event Doc");
|
|
44
|
+
const result = (0, doctrine_js_1.doctrineDraft)(source, { repoRoot, runId: "test-run-001" });
|
|
45
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(result.lifecyclePath)).toBe(true);
|
|
46
|
+
const event = JSON.parse((0, node_fs_1.readFileSync)(result.lifecyclePath, "utf-8").trim().split("\n")[0]);
|
|
47
|
+
(0, vitest_1.expect)(event.event).toBe("doctrine-draft");
|
|
48
|
+
(0, vitest_1.expect)(event.run_id).toBe("test-run-001");
|
|
49
|
+
(0, vitest_1.expect)(event.source).toBe(source);
|
|
50
|
+
(0, vitest_1.expect)(event.destination).toBe(result.destination);
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)("throws if source does not exist", () => {
|
|
53
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrineDraft)((0, node_path_1.join)(repoRoot, "docs", "raw", "nonexistent.md"), { repoRoot })).toThrow("Source file not found");
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)("throws if source is not in docs/raw/ or docs/doctrine/raw/", () => {
|
|
56
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "active", "wrong.md");
|
|
57
|
+
(0, node_fs_1.writeFileSync)(source, "# Wrong location");
|
|
58
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrineDraft)(source, { repoRoot })).toThrow("doctrineDraft source must be in docs/raw/ or docs/doctrine/raw/");
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.it)("throws if destination already exists", () => {
|
|
61
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "raw", "dupe.md");
|
|
62
|
+
(0, node_fs_1.writeFileSync)(source, "# Dupe");
|
|
63
|
+
const dest = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "dupe.md");
|
|
64
|
+
(0, node_fs_1.writeFileSync)(dest, "# Already there");
|
|
65
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrineDraft)(source, { repoRoot })).toThrow("Destination already exists");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.describe)("doctrinePromote", () => {
|
|
69
|
+
let repoRoot;
|
|
70
|
+
(0, vitest_1.beforeEach)(() => {
|
|
71
|
+
repoRoot = makeTempDir();
|
|
72
|
+
});
|
|
73
|
+
(0, vitest_1.it)("moves a file from candidate/ to active/ and strips the candidate marker", () => {
|
|
74
|
+
const candidatePath = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "my-doctrine.md");
|
|
75
|
+
(0, node_fs_1.writeFileSync)(candidatePath, `${doctrine_js_1.CANDIDATE_MARKER}\n# My Doctrine\n\nContent.`);
|
|
76
|
+
const result = (0, doctrine_js_1.doctrinePromote)(candidatePath, { repoRoot, runId: "test-run-002" });
|
|
77
|
+
(0, vitest_1.expect)(result.destination).toBe((0, node_path_1.join)(repoRoot, "docs", "doctrine", "active", "my-doctrine.md"));
|
|
78
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(result.destination)).toBe(true);
|
|
79
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(candidatePath)).toBe(false);
|
|
80
|
+
const content = (0, node_fs_1.readFileSync)(result.destination, "utf-8");
|
|
81
|
+
(0, vitest_1.expect)(content).not.toContain(doctrine_js_1.CANDIDATE_MARKER);
|
|
82
|
+
(0, vitest_1.expect)(content).toContain("# My Doctrine");
|
|
83
|
+
});
|
|
84
|
+
(0, vitest_1.it)("emits a doctrine-promote event to lifecycle.jsonl", () => {
|
|
85
|
+
const candidatePath = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "promoted.md");
|
|
86
|
+
(0, node_fs_1.writeFileSync)(candidatePath, `${doctrine_js_1.CANDIDATE_MARKER}\n# Promoted`);
|
|
87
|
+
const result = (0, doctrine_js_1.doctrinePromote)(candidatePath, { repoRoot, runId: "test-run-002" });
|
|
88
|
+
const event = JSON.parse((0, node_fs_1.readFileSync)(result.lifecyclePath, "utf-8").trim().split("\n")[0]);
|
|
89
|
+
(0, vitest_1.expect)(event.event).toBe("doctrine-promote");
|
|
90
|
+
(0, vitest_1.expect)(event.run_id).toBe("test-run-002");
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)("throws if source is not in docs/doctrine/candidate/", () => {
|
|
93
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "raw", "wrong.md");
|
|
94
|
+
(0, node_fs_1.writeFileSync)(source, `${doctrine_js_1.CANDIDATE_MARKER}\n# Wrong`);
|
|
95
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrinePromote)(source, { repoRoot })).toThrow("doctrinePromote source must be in docs/doctrine/candidate/");
|
|
96
|
+
});
|
|
97
|
+
(0, vitest_1.it)("throws if file is missing the candidate marker", () => {
|
|
98
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "unmarked.md");
|
|
99
|
+
(0, node_fs_1.writeFileSync)(source, "# No marker");
|
|
100
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrinePromote)(source, { repoRoot })).toThrow("not in candidate state");
|
|
101
|
+
});
|
|
102
|
+
(0, vitest_1.it)("throws if source does not exist", () => {
|
|
103
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrinePromote)((0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "ghost.md"), { repoRoot })).toThrow("Source file not found");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
(0, vitest_1.describe)("doctrineDeprecate", () => {
|
|
107
|
+
let repoRoot;
|
|
108
|
+
(0, vitest_1.beforeEach)(() => {
|
|
109
|
+
repoRoot = makeTempDir();
|
|
110
|
+
});
|
|
111
|
+
(0, vitest_1.it)("moves a file from active/ to deprecated/ with deprecation provenance header", () => {
|
|
112
|
+
const activePath = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "active", "old-doctrine.md");
|
|
113
|
+
(0, node_fs_1.writeFileSync)(activePath, "# Old Doctrine\n\nOriginal content.");
|
|
114
|
+
const result = (0, doctrine_js_1.doctrineDeprecate)(activePath, { repoRoot, runId: "test-run-003" });
|
|
115
|
+
(0, vitest_1.expect)(result.destination).toBe((0, node_path_1.join)(repoRoot, "docs", "doctrine", "deprecated", "old-doctrine.md"));
|
|
116
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(result.destination)).toBe(true);
|
|
117
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)(activePath)).toBe(false);
|
|
118
|
+
const content = (0, node_fs_1.readFileSync)(result.destination, "utf-8");
|
|
119
|
+
(0, vitest_1.expect)(content).toContain("polaris:doctrine-deprecated");
|
|
120
|
+
(0, vitest_1.expect)(content).toContain("# Old Doctrine");
|
|
121
|
+
});
|
|
122
|
+
(0, vitest_1.it)("emits a doctrine-deprecate event to lifecycle.jsonl", () => {
|
|
123
|
+
const activePath = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "active", "deprecated.md");
|
|
124
|
+
(0, node_fs_1.writeFileSync)(activePath, "# Deprecated");
|
|
125
|
+
const result = (0, doctrine_js_1.doctrineDeprecate)(activePath, { repoRoot, runId: "test-run-003" });
|
|
126
|
+
const event = JSON.parse((0, node_fs_1.readFileSync)(result.lifecyclePath, "utf-8").trim().split("\n")[0]);
|
|
127
|
+
(0, vitest_1.expect)(event.event).toBe("doctrine-deprecate");
|
|
128
|
+
(0, vitest_1.expect)(event.run_id).toBe("test-run-003");
|
|
129
|
+
(0, vitest_1.expect)(event.deprecated_at).toBeDefined();
|
|
130
|
+
});
|
|
131
|
+
(0, vitest_1.it)("throws if source is not in docs/doctrine/active/", () => {
|
|
132
|
+
const source = (0, node_path_1.join)(repoRoot, "docs", "doctrine", "candidate", "wrong.md");
|
|
133
|
+
(0, node_fs_1.writeFileSync)(source, `${doctrine_js_1.CANDIDATE_MARKER}\n# Wrong`);
|
|
134
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrineDeprecate)(source, { repoRoot })).toThrow("doctrineDeprecate source must be in docs/doctrine/active/");
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.it)("throws if source does not exist", () => {
|
|
137
|
+
(0, vitest_1.expect)(() => (0, doctrine_js_1.doctrineDeprecate)((0, node_path_1.join)(repoRoot, "docs", "doctrine", "active", "ghost.md"), { repoRoot })).toThrow("Source file not found");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDocsCommand = createDocsCommand;
|
|
4
|
+
exports.createDoctrineCommand = createDoctrineCommand;
|
|
5
|
+
const commander_1 = require("commander");
|
|
6
|
+
const ingest_js_1 = require("./ingest.js");
|
|
7
|
+
const migrate_js_1 = require("./migrate.js");
|
|
8
|
+
const seed_instructions_js_1 = require("./seed-instructions.js");
|
|
9
|
+
const validate_instructions_js_1 = require("./validate-instructions.js");
|
|
10
|
+
const doctrine_js_1 = require("./doctrine.js");
|
|
11
|
+
function createDocsCommand() {
|
|
12
|
+
const docs = new commander_1.Command("docs").description("Polaris docs lifecycle commands");
|
|
13
|
+
docs
|
|
14
|
+
.command("ingest [path]")
|
|
15
|
+
.description("Classify and place docs into the Polaris docs authority structure")
|
|
16
|
+
.option("--file <path>", "Single file to ingest")
|
|
17
|
+
.option("--cluster <id>", "Cluster ID for bounded batch provenance")
|
|
18
|
+
.option("--files <paths...>", "Bounded batch file list")
|
|
19
|
+
.option("--dry-run", "Classify and report without moving files")
|
|
20
|
+
.option("--approve-authority", "Allow placement in high-authority docs areas")
|
|
21
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
22
|
+
.action((pathArg, options) => {
|
|
23
|
+
const files = options.files ?? (options.file ? [options.file] : pathArg ? [pathArg] : []);
|
|
24
|
+
try {
|
|
25
|
+
const results = (0, ingest_js_1.ingestDocs)(files, {
|
|
26
|
+
repoRoot: options.repoRoot,
|
|
27
|
+
dryRun: options.dryRun,
|
|
28
|
+
clusterId: options.cluster,
|
|
29
|
+
approveAuthority: options.approveAuthority,
|
|
30
|
+
});
|
|
31
|
+
(0, ingest_js_1.printIngestResults)(results);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
docs
|
|
39
|
+
.command("migrate")
|
|
40
|
+
.description("Find scattered markdown files, move them to docs/raw/, and produce an ingest cluster list")
|
|
41
|
+
.option("--dry-run", "Show plan without moving files")
|
|
42
|
+
.option("--migration-run-id <id>", "Override the generated migration run ID")
|
|
43
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
44
|
+
.action((options) => {
|
|
45
|
+
try {
|
|
46
|
+
const result = (0, migrate_js_1.migrateDocs)({
|
|
47
|
+
repoRoot: options.repoRoot,
|
|
48
|
+
dryRun: options.dryRun,
|
|
49
|
+
migrationRunId: options.migrationRunId,
|
|
50
|
+
});
|
|
51
|
+
(0, migrate_js_1.printMigrateResults)(result);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
docs
|
|
59
|
+
.command("seed-instructions [path]")
|
|
60
|
+
.description("Generate a draft POLARIS.md for a directory using atlas signals")
|
|
61
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
62
|
+
.option("--all", "Generate drafts for all directories lacking a POLARIS.md")
|
|
63
|
+
.option("--dry-run", "Print what would be written without writing files")
|
|
64
|
+
.action((pathArg, options) => {
|
|
65
|
+
if (options.all) {
|
|
66
|
+
const { written, skippedExists, skippedDraft } = (0, seed_instructions_js_1.seedInstructionsAll)(options.repoRoot, { dryRun: options.dryRun });
|
|
67
|
+
for (const dir of written) {
|
|
68
|
+
console.log(`${options.dryRun ? "[dry-run] would write" : "written"}: ${dir}/POLARIS.md`);
|
|
69
|
+
}
|
|
70
|
+
for (const dir of skippedExists) {
|
|
71
|
+
console.log(`skipped (human-edited): ${dir}/POLARIS.md`);
|
|
72
|
+
}
|
|
73
|
+
for (const dir of skippedDraft) {
|
|
74
|
+
console.log(`skipped (draft exists): ${dir}/POLARIS.md`);
|
|
75
|
+
}
|
|
76
|
+
console.log(`\nDone. ${written.length} written, ${skippedExists.length} skipped (exists), ${skippedDraft.length} skipped (draft).`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!pathArg) {
|
|
80
|
+
console.error("Error: provide a <path> argument or use --all");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
const result = (0, seed_instructions_js_1.seedInstructions)(pathArg, options.repoRoot, { dryRun: options.dryRun });
|
|
84
|
+
if (result === "written") {
|
|
85
|
+
const label = options.dryRun ? "[dry-run] would write" : "written";
|
|
86
|
+
console.log(`${label}: ${pathArg}/POLARIS.md`);
|
|
87
|
+
}
|
|
88
|
+
else if (result === "skipped-exists") {
|
|
89
|
+
console.warn(`warning: ${pathArg}/POLARIS.md already exists (no draft marker) — skipped`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(`skipped (draft exists): ${pathArg}/POLARIS.md`);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
docs
|
|
96
|
+
.command("validate-instructions")
|
|
97
|
+
.description("Check all POLARIS.md files for staleness, broken links, and missing coverage")
|
|
98
|
+
.option("--path <dir>", "Validate only the given directory")
|
|
99
|
+
.option("--fix", "Write POLARIS.draft.md for stale or missing files")
|
|
100
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
101
|
+
.action((options) => {
|
|
102
|
+
const report = (0, validate_instructions_js_1.validateInstructions)({
|
|
103
|
+
path: options.path,
|
|
104
|
+
fix: options.fix,
|
|
105
|
+
repoRoot: options.repoRoot,
|
|
106
|
+
});
|
|
107
|
+
(0, validate_instructions_js_1.printReport)(report);
|
|
108
|
+
if (report.hasErrors) {
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return docs;
|
|
113
|
+
}
|
|
114
|
+
function createDoctrineCommand() {
|
|
115
|
+
const doctrine = new commander_1.Command("doctrine").description("Polaris doctrine lifecycle commands");
|
|
116
|
+
doctrine
|
|
117
|
+
.command("draft <path>")
|
|
118
|
+
.description("Move a doc from docs/raw/ or docs/doctrine/raw/ to docs/doctrine/candidate/")
|
|
119
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
120
|
+
.option("--run-id <id>", "Override the generated doctrine run ID")
|
|
121
|
+
.action((path, options) => {
|
|
122
|
+
try {
|
|
123
|
+
const result = (0, doctrine_js_1.doctrineDraft)(path, { repoRoot: options.repoRoot, runId: options.runId });
|
|
124
|
+
console.log(`drafted: ${result.destination}`);
|
|
125
|
+
console.log(`provenance: ${result.lifecyclePath}`);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
doctrine
|
|
133
|
+
.command("promote <path>")
|
|
134
|
+
.description("Move a doc from docs/doctrine/candidate/ to docs/doctrine/active/")
|
|
135
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
136
|
+
.option("--run-id <id>", "Override the generated doctrine run ID")
|
|
137
|
+
.action((path, options) => {
|
|
138
|
+
try {
|
|
139
|
+
const result = (0, doctrine_js_1.doctrinePromote)(path, { repoRoot: options.repoRoot, runId: options.runId });
|
|
140
|
+
console.log(`promoted: ${result.destination}`);
|
|
141
|
+
console.log(`provenance: ${result.lifecyclePath}`);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
doctrine
|
|
149
|
+
.command("deprecate <path>")
|
|
150
|
+
.description("Move a doc from docs/doctrine/active/ to docs/doctrine/deprecated/")
|
|
151
|
+
.option("-r, --repo-root <path>", "Repository root", process.cwd())
|
|
152
|
+
.option("--run-id <id>", "Override the generated doctrine run ID")
|
|
153
|
+
.action((path, options) => {
|
|
154
|
+
try {
|
|
155
|
+
const result = (0, doctrine_js_1.doctrineDeprecate)(path, {
|
|
156
|
+
repoRoot: options.repoRoot,
|
|
157
|
+
runId: options.runId,
|
|
158
|
+
});
|
|
159
|
+
console.log(`deprecated: ${result.destination}`);
|
|
160
|
+
console.log(`provenance: ${result.lifecyclePath}`);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return doctrine;
|
|
168
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_fs_1 = require("node:fs");
|
|
4
|
+
const node_fs_2 = require("node:fs");
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const vitest_1 = require("vitest");
|
|
8
|
+
const ingest_js_1 = require("./ingest.js");
|
|
9
|
+
const index_js_1 = require("./index.js");
|
|
10
|
+
function makeRepo() {
|
|
11
|
+
const repoRoot = (0, node_fs_2.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "polaris-docs-init-"));
|
|
12
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, ".polaris", "map"), { recursive: true });
|
|
13
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, "docs", "raw"), { recursive: true });
|
|
14
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, "polaris.config.json"), JSON.stringify({ repo: { sidecarOutputPath: ".polaris/map" } }), "utf-8");
|
|
15
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, ".polaris", "map", "file-routes.json"), "{}\n", "utf-8");
|
|
16
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, ".polaris", "map", "needs-review.json"), "{}\n", "utf-8");
|
|
17
|
+
return repoRoot;
|
|
18
|
+
}
|
|
19
|
+
function configureForTest(command, output) {
|
|
20
|
+
command.exitOverride();
|
|
21
|
+
command.configureOutput({
|
|
22
|
+
writeOut: (value) => {
|
|
23
|
+
output.stdout += value;
|
|
24
|
+
},
|
|
25
|
+
writeErr: (value) => {
|
|
26
|
+
output.stderr += value;
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
for (const subcommand of command.commands) {
|
|
30
|
+
configureForTest(subcommand, output);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function runDocsCommand(repoRoot, argv) {
|
|
34
|
+
const output = { stdout: "", stderr: "" };
|
|
35
|
+
const command = (0, index_js_1.createDocsCommand)({ repoRoot });
|
|
36
|
+
configureForTest(command, output);
|
|
37
|
+
const log = vitest_1.vi.spyOn(console, "log").mockImplementation((value = "") => {
|
|
38
|
+
output.stdout += `${String(value)}\n`;
|
|
39
|
+
});
|
|
40
|
+
const warn = vitest_1.vi.spyOn(console, "warn").mockImplementation((value = "") => {
|
|
41
|
+
output.stderr += `${String(value)}\n`;
|
|
42
|
+
});
|
|
43
|
+
const error = vitest_1.vi.spyOn(console, "error").mockImplementation((value = "") => {
|
|
44
|
+
output.stderr += `${String(value)}\n`;
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
await command.parseAsync(["node", "polaris", ...argv], { from: "node" });
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
log.mockRestore();
|
|
51
|
+
warn.mockRestore();
|
|
52
|
+
error.mockRestore();
|
|
53
|
+
}
|
|
54
|
+
return output;
|
|
55
|
+
}
|
|
56
|
+
(0, vitest_1.describe)("docs init command", () => {
|
|
57
|
+
(0, vitest_1.it)("dry-runs the Smart Docs scaffold without creating directories", async () => {
|
|
58
|
+
const repoRoot = makeRepo();
|
|
59
|
+
const output = await runDocsCommand(repoRoot, ["init", "--dry-run"]);
|
|
60
|
+
(0, vitest_1.expect)(output.stdout).toContain("[dry-run] would create");
|
|
61
|
+
(0, vitest_1.expect)(output.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/specs/raw`);
|
|
62
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET))).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.it)("creates the Smart Docs scaffold and is idempotent", async () => {
|
|
65
|
+
const repoRoot = makeRepo();
|
|
66
|
+
const first = await runDocsCommand(repoRoot, ["init"]);
|
|
67
|
+
const second = await runDocsCommand(repoRoot, ["init"]);
|
|
68
|
+
(0, vitest_1.expect)(first.stdout).toContain("created");
|
|
69
|
+
(0, vitest_1.expect)(first.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/doctrine/active`);
|
|
70
|
+
(0, vitest_1.expect)(second.stdout).toContain("already exists");
|
|
71
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "runtime", "summaries"))).toBe(true);
|
|
72
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "specs", "raw"))).toBe(true);
|
|
73
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "doctrine", "active"))).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)("unblocks docs ingest after initialization", async () => {
|
|
76
|
+
const repoRoot = makeRepo();
|
|
77
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(repoRoot, "docs", "raw", "smart-docs.md"), "# Smart Docs Spec\n\nAcceptance Criteria\n", "utf-8");
|
|
78
|
+
await runDocsCommand(repoRoot, ["init"]);
|
|
79
|
+
const output = await runDocsCommand(repoRoot, ["ingest", "--file", "docs/raw/smart-docs.md"]);
|
|
80
|
+
(0, vitest_1.expect)(output.stdout).toContain(`${ingest_js_1.CANONICAL_TARGET}/specs/raw/smart-docs.md`);
|
|
81
|
+
(0, vitest_1.expect)((0, node_fs_1.existsSync)((0, node_path_1.join)(repoRoot, ingest_js_1.CANONICAL_TARGET, "specs", "raw", "smart-docs.md"))).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
});
|