@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,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const query_js_1 = require("./query.js");
|
|
7
|
+
const TMP = (0, node_path_1.join)(process.cwd(), ".test-query-tmp");
|
|
8
|
+
const POLARIS_MD_CONTENT = "# Map subsystem instructions\n\nHandle atlas data.";
|
|
9
|
+
const ROUTES = {
|
|
10
|
+
"src/cli/index.ts": {
|
|
11
|
+
domain: "cli",
|
|
12
|
+
route: "src/cli",
|
|
13
|
+
taskchain: "polaris-cli",
|
|
14
|
+
confidence: 0.95,
|
|
15
|
+
classification: "indexed",
|
|
16
|
+
last_updated: "2026-05-22T20:00:00Z",
|
|
17
|
+
updated_by: "polaris-map-index",
|
|
18
|
+
tags: ["cli", "entry-point"],
|
|
19
|
+
},
|
|
20
|
+
"src/map/atlas.ts": {
|
|
21
|
+
domain: "map",
|
|
22
|
+
route: "src/map",
|
|
23
|
+
taskchain: "polaris-core",
|
|
24
|
+
confidence: 0.92,
|
|
25
|
+
classification: "indexed",
|
|
26
|
+
last_updated: "2026-05-22T20:00:00Z",
|
|
27
|
+
updated_by: "polaris-map-index",
|
|
28
|
+
tags: ["map"],
|
|
29
|
+
instructionFile: "src/map/POLARIS.md",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const NEEDS_REVIEW = {
|
|
33
|
+
"src/map/query.ts": {
|
|
34
|
+
domain: "map",
|
|
35
|
+
route: "src/map",
|
|
36
|
+
taskchain: "polaris-core",
|
|
37
|
+
confidence: 0.6,
|
|
38
|
+
classification: "needs-review",
|
|
39
|
+
last_updated: "2026-05-22T20:00:00Z",
|
|
40
|
+
updated_by: "polaris-map-index",
|
|
41
|
+
tags: ["map"],
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const EXEMPTIONS = {
|
|
45
|
+
"dist/cli/index.js": { classification: "tracked-not-indexed", reason: "generatedRoots" },
|
|
46
|
+
};
|
|
47
|
+
const POLARIS_CONFIG = {
|
|
48
|
+
repo: { sidecarOutputPath: ".polaris/map" },
|
|
49
|
+
map: { autoWriteAbove: 0.85, confidenceThreshold: 0.75 },
|
|
50
|
+
};
|
|
51
|
+
function setup() {
|
|
52
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, ".polaris/map"), { recursive: true });
|
|
53
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/cli"), { recursive: true });
|
|
54
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/map"), { recursive: true });
|
|
55
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "dist/cli"), { recursive: true });
|
|
56
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/cli/index.ts"), "");
|
|
57
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/atlas.ts"), "");
|
|
58
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), POLARIS_MD_CONTENT);
|
|
59
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), JSON.stringify(ROUTES));
|
|
60
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/needs-review.json"), JSON.stringify(NEEDS_REVIEW));
|
|
61
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/exemptions.json"), JSON.stringify(EXEMPTIONS));
|
|
62
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/index.json"), JSON.stringify({ scan_date: "", file_count: 0, coverage_pct: 0, entries: {} }));
|
|
63
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "polaris.config.json"), JSON.stringify(POLARIS_CONFIG));
|
|
64
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polarisignore"), ".env\n*.log\n");
|
|
65
|
+
}
|
|
66
|
+
function teardown() {
|
|
67
|
+
(0, node_fs_1.rmSync)(TMP, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
function captureOutput(fn) {
|
|
70
|
+
const stdoutLines = [];
|
|
71
|
+
const stderrLines = [];
|
|
72
|
+
const origStdout = process.stdout.write.bind(process.stdout);
|
|
73
|
+
const origStderr = process.stderr.write.bind(process.stderr);
|
|
74
|
+
const origLog = console.log.bind(console);
|
|
75
|
+
const origError = console.error.bind(console);
|
|
76
|
+
console.log = (...args) => { stdoutLines.push(args.map(String).join(" ")); };
|
|
77
|
+
console.error = (...args) => { stderrLines.push(args.map(String).join(" ")); };
|
|
78
|
+
process.stdout.write = (chunk) => { stdoutLines.push(String(chunk)); return true; };
|
|
79
|
+
process.stderr.write = (chunk) => { stderrLines.push(String(chunk)); return true; };
|
|
80
|
+
try {
|
|
81
|
+
fn();
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
console.log = origLog;
|
|
85
|
+
console.error = origError;
|
|
86
|
+
process.stdout.write = origStdout;
|
|
87
|
+
process.stderr.write = origStderr;
|
|
88
|
+
}
|
|
89
|
+
return { stdout: stdoutLines.join(""), stderr: stderrLines.join("") };
|
|
90
|
+
}
|
|
91
|
+
(0, vitest_1.describe)("runMapQuery", () => {
|
|
92
|
+
(0, vitest_1.beforeEach)(setup);
|
|
93
|
+
(0, vitest_1.afterEach)(teardown);
|
|
94
|
+
(0, vitest_1.it)("returns indexed metadata for an exact file lookup", () => {
|
|
95
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/cli/index.ts", undefined, undefined, false));
|
|
96
|
+
const result = JSON.parse(stdout);
|
|
97
|
+
(0, vitest_1.expect)(result["src/cli/index.ts"].classification).toBe("indexed");
|
|
98
|
+
(0, vitest_1.expect)(result["src/cli/index.ts"].domain).toBe("cli");
|
|
99
|
+
(0, vitest_1.expect)(result["src/cli/index.ts"].taskchain).toBe("polaris-cli");
|
|
100
|
+
});
|
|
101
|
+
(0, vitest_1.it)("returns ignored classification for a .polarisignore-matched file", () => {
|
|
102
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, ".env", undefined, undefined, false));
|
|
103
|
+
const result = JSON.parse(stdout);
|
|
104
|
+
(0, vitest_1.expect)(result[".env"].classification).toBe("ignored");
|
|
105
|
+
});
|
|
106
|
+
(0, vitest_1.it)("returns unmapped for a file not in the atlas", () => {
|
|
107
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/cli/unknown.ts", undefined, undefined, false));
|
|
108
|
+
const result = JSON.parse(stdout);
|
|
109
|
+
(0, vitest_1.expect)(result["src/cli/unknown.ts"].classification).toBe("unmapped");
|
|
110
|
+
});
|
|
111
|
+
(0, vitest_1.it)("returns tracked-not-indexed for an exempted file", () => {
|
|
112
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "dist/cli/index.js", undefined, undefined, false));
|
|
113
|
+
const result = JSON.parse(stdout);
|
|
114
|
+
(0, vitest_1.expect)(result["dist/cli/index.js"].classification).toBe("tracked-not-indexed");
|
|
115
|
+
});
|
|
116
|
+
(0, vitest_1.it)("matches all .ts files in src/ with a glob", () => {
|
|
117
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/**/*.ts", undefined, undefined, false));
|
|
118
|
+
const result = JSON.parse(stdout);
|
|
119
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/cli/index.ts");
|
|
120
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/atlas.ts");
|
|
121
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/query.ts");
|
|
122
|
+
});
|
|
123
|
+
(0, vitest_1.it)("filters by domain", () => {
|
|
124
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, undefined, "cli", undefined, false));
|
|
125
|
+
const result = JSON.parse(stdout);
|
|
126
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/cli/index.ts");
|
|
127
|
+
(0, vitest_1.expect)(Object.keys(result)).not.toContain("src/map/atlas.ts");
|
|
128
|
+
});
|
|
129
|
+
(0, vitest_1.it)("filters by taskchain", () => {
|
|
130
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, undefined, undefined, "polaris-core", false));
|
|
131
|
+
const result = JSON.parse(stdout);
|
|
132
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/atlas.ts");
|
|
133
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/query.ts");
|
|
134
|
+
(0, vitest_1.expect)(Object.keys(result)).not.toContain("src/cli/index.ts");
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.it)("returns all files in a directory with trailing slash", () => {
|
|
137
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/map/", undefined, undefined, false));
|
|
138
|
+
const result = JSON.parse(stdout);
|
|
139
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/atlas.ts");
|
|
140
|
+
(0, vitest_1.expect)(Object.keys(result)).toContain("src/map/query.ts");
|
|
141
|
+
(0, vitest_1.expect)(Object.keys(result)).not.toContain("src/cli/index.ts");
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)("emits --text output with classification and metadata", () => {
|
|
144
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/cli/index.ts", undefined, undefined, true));
|
|
145
|
+
(0, vitest_1.expect)(stdout).toContain("src/cli/index.ts");
|
|
146
|
+
(0, vitest_1.expect)(stdout).toContain("indexed");
|
|
147
|
+
(0, vitest_1.expect)(stdout).toContain("domain:cli");
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.it)("warns when file does not exist in repo", () => {
|
|
150
|
+
const { stderr } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "does/not/exist.ts", undefined, undefined, false));
|
|
151
|
+
(0, vitest_1.expect)(stderr).toContain("warn: file does not exist in repo");
|
|
152
|
+
});
|
|
153
|
+
(0, vitest_1.it)("includes instructionFile path in output when entry has one", () => {
|
|
154
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/map/atlas.ts", undefined, undefined, false, true));
|
|
155
|
+
const result = JSON.parse(stdout);
|
|
156
|
+
(0, vitest_1.expect)(result["src/map/atlas.ts"].instructionFile).toBe("src/map/POLARIS.md");
|
|
157
|
+
});
|
|
158
|
+
(0, vitest_1.it)("--include-instructions adds instructionContent to output", () => {
|
|
159
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/map/atlas.ts", undefined, undefined, false, true));
|
|
160
|
+
const result = JSON.parse(stdout);
|
|
161
|
+
(0, vitest_1.expect)(result["src/map/atlas.ts"].instructionFile).toBe("src/map/POLARIS.md");
|
|
162
|
+
(0, vitest_1.expect)(result["src/map/atlas.ts"].instructionContent).toBe(POLARIS_MD_CONTENT);
|
|
163
|
+
});
|
|
164
|
+
(0, vitest_1.it)("--include-instructions includes instructionFile in --text output", () => {
|
|
165
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/map/atlas.ts", undefined, undefined, true, true));
|
|
166
|
+
(0, vitest_1.expect)(stdout).toContain("instructions:src/map/POLARIS.md");
|
|
167
|
+
});
|
|
168
|
+
(0, vitest_1.it)("entry without instructionFile omits field even with --include-instructions", () => {
|
|
169
|
+
const { stdout } = captureOutput(() => (0, query_js_1.runMapQuery)(TMP, "src/cli/index.ts", undefined, undefined, false, true));
|
|
170
|
+
const result = JSON.parse(stdout);
|
|
171
|
+
(0, vitest_1.expect)(result["src/cli/index.ts"].instructionFile).toBeUndefined();
|
|
172
|
+
(0, vitest_1.expect)(result["src/cli/index.ts"].instructionContent).toBeUndefined();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectMissingCognitionSurfaces = detectMissingCognitionSurfaces;
|
|
4
|
+
exports.seedCognitionDrafts = seedCognitionDrafts;
|
|
5
|
+
exports.runMapUpdate = runMapUpdate;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const loader_js_1 = require("../config/loader.js");
|
|
10
|
+
const parser_js_1 = require("../ignore/parser.js");
|
|
11
|
+
const defaults_js_1 = require("../ignore/defaults.js");
|
|
12
|
+
const inference_js_1 = require("./inference.js");
|
|
13
|
+
const index_js_1 = require("../cognition/index.js");
|
|
14
|
+
const atlas_js_1 = require("./atlas.js");
|
|
15
|
+
const SECRET_REGEXES = defaults_js_1.SECRET_PATTERNS.map((p) => new RegExp("^" + p.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"));
|
|
16
|
+
function isSecretFile(filePath) {
|
|
17
|
+
const parts = filePath.split("/");
|
|
18
|
+
const base = parts[parts.length - 1];
|
|
19
|
+
return SECRET_REGEXES.some((re) => re.test(base) || re.test(filePath));
|
|
20
|
+
}
|
|
21
|
+
function getChangedFiles(repoRoot, fromCommit, toCommit) {
|
|
22
|
+
const from = fromCommit ?? "HEAD~1";
|
|
23
|
+
const to = toCommit ?? "HEAD";
|
|
24
|
+
try {
|
|
25
|
+
const output = (0, node_child_process_1.execFileSync)("git", ["diff", "--name-only", `${from}..${to}`], {
|
|
26
|
+
cwd: repoRoot,
|
|
27
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
28
|
+
}).toString().trim();
|
|
29
|
+
if (!output)
|
|
30
|
+
return [];
|
|
31
|
+
return output.split("\n").map((f) => f.trim()).filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Fall back to unstaged changes if no commits
|
|
35
|
+
try {
|
|
36
|
+
const output = (0, node_child_process_1.execFileSync)("git", ["diff", "--name-only"], {
|
|
37
|
+
cwd: repoRoot,
|
|
38
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
39
|
+
}).toString().trim();
|
|
40
|
+
if (!output)
|
|
41
|
+
return [];
|
|
42
|
+
return output.split("\n").map((f) => f.trim()).filter(Boolean);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function loadIgnoreFilter(repoRoot) {
|
|
50
|
+
let userPatterns = [];
|
|
51
|
+
try {
|
|
52
|
+
const raw = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(repoRoot, ".polarisignore"), "utf-8");
|
|
53
|
+
userPatterns = raw.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("#"));
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
if (typeof err === "object" && err !== null && "code" in err && err.code !== "ENOENT") {
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return (0, parser_js_1.parsePolarisIgnore)(userPatterns);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Draft POLARIS.md content for a newly discovered eligible folder.
|
|
64
|
+
*/
|
|
65
|
+
function draftPolarismd(folderRel) {
|
|
66
|
+
return [
|
|
67
|
+
`# ${folderRel}`,
|
|
68
|
+
"",
|
|
69
|
+
"<!-- DRAFT: Generated by polaris map update --seed-cognition -->",
|
|
70
|
+
"<!-- Fill in all sections before committing. Do not leave TODOs in production. -->",
|
|
71
|
+
"",
|
|
72
|
+
"## Purpose",
|
|
73
|
+
"",
|
|
74
|
+
"<!-- TODO -->",
|
|
75
|
+
"",
|
|
76
|
+
"## What belongs here",
|
|
77
|
+
"",
|
|
78
|
+
"<!-- TODO -->",
|
|
79
|
+
"",
|
|
80
|
+
"## What does not belong here",
|
|
81
|
+
"",
|
|
82
|
+
"<!-- TODO -->",
|
|
83
|
+
"",
|
|
84
|
+
"## Editing rules",
|
|
85
|
+
"",
|
|
86
|
+
"<!-- TODO -->",
|
|
87
|
+
"",
|
|
88
|
+
"## Related routes",
|
|
89
|
+
"",
|
|
90
|
+
"<!-- TODO -->",
|
|
91
|
+
"",
|
|
92
|
+
].join("\n");
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Draft SUMMARY.md content for a newly discovered eligible folder.
|
|
96
|
+
*/
|
|
97
|
+
function draftSummarymd(folderRel) {
|
|
98
|
+
return [
|
|
99
|
+
`# ${folderRel} — Summary`,
|
|
100
|
+
"",
|
|
101
|
+
"<!-- DRAFT: Generated by polaris map update --seed-cognition -->",
|
|
102
|
+
"<!-- TODO: Short informational summary of this route. Keep under 4 KB. -->",
|
|
103
|
+
"<!-- Informational only. Do not add operational doctrine here. -->",
|
|
104
|
+
"",
|
|
105
|
+
].join("\n");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Detect folders touched by changed files that are missing POLARIS.md or
|
|
109
|
+
* SUMMARY.md. Only eligible non-skipped folders are reported.
|
|
110
|
+
* Root is skipped unless includeRoot=true.
|
|
111
|
+
*/
|
|
112
|
+
function detectMissingCognitionSurfaces(changedFiles, repoRoot, includeRoot) {
|
|
113
|
+
const missingPolaris = new Set();
|
|
114
|
+
const missingSummary = new Set();
|
|
115
|
+
const tierOneFolders = new Set([".polaris", "src", "smartdocs/specs/active"]);
|
|
116
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, "smartdocs", "doctrine", "active"))) {
|
|
117
|
+
tierOneFolders.add("smartdocs/doctrine/active");
|
|
118
|
+
}
|
|
119
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, "src"))) {
|
|
120
|
+
for (const entry of (0, node_fs_1.readdirSync)((0, node_path_1.resolve)(repoRoot, "src"), { withFileTypes: true })) {
|
|
121
|
+
if (!entry.isDirectory())
|
|
122
|
+
continue;
|
|
123
|
+
tierOneFolders.add(`src/${entry.name}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const hasNonTestNonGeneratedSource = (filePath) => {
|
|
127
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
128
|
+
const fileName = normalized.split("/").pop() ?? normalized;
|
|
129
|
+
if (normalized.startsWith(".") ||
|
|
130
|
+
/(^|\/)(dist|build|out|coverage|generated|__generated__)\//.test(normalized) ||
|
|
131
|
+
/(^|\/)\.(?!well-known)/.test(normalized))
|
|
132
|
+
return false;
|
|
133
|
+
if (/\.test\./.test(fileName) ||
|
|
134
|
+
/\.spec\./.test(fileName) ||
|
|
135
|
+
/\.generated\./.test(fileName) ||
|
|
136
|
+
fileName.endsWith(".d.ts"))
|
|
137
|
+
return false;
|
|
138
|
+
return /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|rb|php|cs|c|cc|cpp|h|hpp|sh)$/.test(fileName);
|
|
139
|
+
};
|
|
140
|
+
const detectFolderForFile = (filePath) => {
|
|
141
|
+
const parts = filePath.split("/");
|
|
142
|
+
for (let i = parts.length - 1; i >= 1; i--) {
|
|
143
|
+
const dir = parts.slice(0, i).join("/");
|
|
144
|
+
if (!dir || (0, index_js_1.isCognitionSkippedFolder)(dir, repoRoot))
|
|
145
|
+
continue;
|
|
146
|
+
if ((0, index_js_1.isPolarisOwnedFolder)(dir))
|
|
147
|
+
return dir;
|
|
148
|
+
const folderTouchedFiles = changedFiles.filter((changed) => changed.startsWith(`${dir}/`));
|
|
149
|
+
const sourceTouchedFiles = folderTouchedFiles.filter(hasNonTestNonGeneratedSource);
|
|
150
|
+
if (sourceTouchedFiles.length === 0)
|
|
151
|
+
continue;
|
|
152
|
+
if ((0, index_js_1.detectOperationalReasons)(sourceTouchedFiles).length === 0)
|
|
153
|
+
continue;
|
|
154
|
+
return dir;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
};
|
|
158
|
+
for (const tierOne of tierOneFolders) {
|
|
159
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, tierOne)))
|
|
160
|
+
continue;
|
|
161
|
+
if ((0, index_js_1.isCognitionSkippedFolder)(tierOne, repoRoot))
|
|
162
|
+
continue;
|
|
163
|
+
const hasPolarismd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, tierOne, "POLARIS.md"));
|
|
164
|
+
const hasSummarymd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, tierOne, "SUMMARY.md"));
|
|
165
|
+
if (!hasPolarismd)
|
|
166
|
+
missingPolaris.add(tierOne);
|
|
167
|
+
if (hasPolarismd && !hasSummarymd)
|
|
168
|
+
missingSummary.add(tierOne);
|
|
169
|
+
}
|
|
170
|
+
for (const file of changedFiles) {
|
|
171
|
+
const folder = detectFolderForFile(file);
|
|
172
|
+
const foundAncestor = Boolean(folder);
|
|
173
|
+
if (folder) {
|
|
174
|
+
const hasPolarismd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, folder, "POLARIS.md"));
|
|
175
|
+
const hasSummarymd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, folder, "SUMMARY.md"));
|
|
176
|
+
if (!hasPolarismd)
|
|
177
|
+
missingPolaris.add(folder);
|
|
178
|
+
if (hasPolarismd && !hasSummarymd)
|
|
179
|
+
missingSummary.add(folder);
|
|
180
|
+
}
|
|
181
|
+
// Check root only when explicitly opted in and no non-root ancestor was found
|
|
182
|
+
if (includeRoot && !foundAncestor) {
|
|
183
|
+
const hasPolarismd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, "POLARIS.md"));
|
|
184
|
+
const hasSummarymd = (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, "SUMMARY.md"));
|
|
185
|
+
if (!hasPolarismd)
|
|
186
|
+
missingPolaris.add("");
|
|
187
|
+
if (hasPolarismd && !hasSummarymd)
|
|
188
|
+
missingSummary.add("");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
missingPolaris: Array.from(missingPolaris),
|
|
193
|
+
missingSummary: Array.from(missingSummary),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Seed draft POLARIS.md and/or SUMMARY.md files for newly eligible folders.
|
|
198
|
+
* Only called when --seed-cognition flag is explicitly set.
|
|
199
|
+
* Root is skipped unless includeRoot=true. Already-existing files are never overwritten.
|
|
200
|
+
*
|
|
201
|
+
* Returns the list of folders that were actually seeded.
|
|
202
|
+
*/
|
|
203
|
+
function seedCognitionDrafts(folders, repoRoot, includeRoot) {
|
|
204
|
+
const seeded = [];
|
|
205
|
+
for (const dir of folders.polaris) {
|
|
206
|
+
// Root (empty string) is only seeded when explicitly opted in
|
|
207
|
+
if (!includeRoot && !dir)
|
|
208
|
+
continue;
|
|
209
|
+
if (dir && (0, index_js_1.isCognitionSkippedFolder)(dir, repoRoot))
|
|
210
|
+
continue;
|
|
211
|
+
const target = dir ? (0, node_path_1.resolve)(repoRoot, dir, "POLARIS.md") : (0, node_path_1.resolve)(repoRoot, "POLARIS.md");
|
|
212
|
+
if (!(0, node_fs_1.existsSync)(target)) {
|
|
213
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(target), { recursive: true });
|
|
214
|
+
(0, node_fs_1.writeFileSync)(target, draftPolarismd(dir || "."), "utf-8");
|
|
215
|
+
seeded.push(dir ? `${dir}/POLARIS.md` : "POLARIS.md");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const dir of folders.summary) {
|
|
219
|
+
if (!includeRoot && !dir)
|
|
220
|
+
continue;
|
|
221
|
+
if (dir && (0, index_js_1.isCognitionSkippedFolder)(dir, repoRoot))
|
|
222
|
+
continue;
|
|
223
|
+
const target = dir ? (0, node_path_1.resolve)(repoRoot, dir, "SUMMARY.md") : (0, node_path_1.resolve)(repoRoot, "SUMMARY.md");
|
|
224
|
+
if (!(0, node_fs_1.existsSync)(target)) {
|
|
225
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(target), { recursive: true });
|
|
226
|
+
(0, node_fs_1.writeFileSync)(target, draftSummarymd(dir || "."), "utf-8");
|
|
227
|
+
seeded.push(dir ? `${dir}/SUMMARY.md` : "SUMMARY.md");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return seeded;
|
|
231
|
+
}
|
|
232
|
+
function runMapUpdate(repoRoot, explicitFiles, fromCommit, toCommit, seedCognition, includeRoot) {
|
|
233
|
+
const config = (0, loader_js_1.loadConfig)(repoRoot);
|
|
234
|
+
const outputPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
|
|
235
|
+
const ig = loadIgnoreFilter(repoRoot);
|
|
236
|
+
const changedFiles = explicitFiles.length > 0
|
|
237
|
+
? explicitFiles
|
|
238
|
+
: getChangedFiles(repoRoot, fromCommit, toCommit);
|
|
239
|
+
const routes = (0, atlas_js_1.readFileRoutes)(outputPath);
|
|
240
|
+
const needsReview = (0, atlas_js_1.readNeedsReview)(outputPath);
|
|
241
|
+
const exemptions = (0, atlas_js_1.readExemptions)(outputPath);
|
|
242
|
+
let branchName = "";
|
|
243
|
+
try {
|
|
244
|
+
branchName = (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
245
|
+
cwd: repoRoot,
|
|
246
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
247
|
+
}).toString().trim();
|
|
248
|
+
}
|
|
249
|
+
catch { /* ignore */ }
|
|
250
|
+
const summary = { mapped: 0, validated: 0, inferred: 0, needs_review: 0, ignored: 0 };
|
|
251
|
+
const now = new Date().toISOString();
|
|
252
|
+
for (const filePath of changedFiles) {
|
|
253
|
+
// Security check
|
|
254
|
+
if (isSecretFile(filePath)) {
|
|
255
|
+
console.error(`[HIGH] Secret file pattern matched, skipping: ${filePath}`);
|
|
256
|
+
summary.ignored++;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
// 1. .polarisignore
|
|
260
|
+
if (ig.ignores(filePath)) {
|
|
261
|
+
summary.ignored++;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
// 2. File doesn't exist on disk (deleted) → remove from both indexes, skip
|
|
265
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, filePath))) {
|
|
266
|
+
delete needsReview[filePath];
|
|
267
|
+
delete routes[filePath];
|
|
268
|
+
summary.ignored++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
// 3. Existing entry in file-routes.json → validate and update timestamp
|
|
272
|
+
if (routes[filePath]) {
|
|
273
|
+
routes[filePath].last_updated = now;
|
|
274
|
+
routes[filePath].updated_by = "polaris-map-update";
|
|
275
|
+
routes[filePath].instructionFile = (0, atlas_js_1.resolveInstructionFile)(filePath, repoRoot);
|
|
276
|
+
summary.validated++;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
// 4. Tracked-not-indexed → skip
|
|
280
|
+
if (exemptions[filePath]) {
|
|
281
|
+
summary.ignored++;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// 5. Run inference for new file
|
|
285
|
+
const inferred = (0, inference_js_1.inferRoute)(filePath, repoRoot, config, routes, branchName);
|
|
286
|
+
const autoWriteAbove = config.map.autoWriteAbove ?? 0.85;
|
|
287
|
+
const confidenceThreshold = config.map.confidenceThreshold ?? 0.75;
|
|
288
|
+
const entry = {
|
|
289
|
+
domain: inferred.domain,
|
|
290
|
+
route: inferred.route,
|
|
291
|
+
taskchain: inferred.taskchain,
|
|
292
|
+
confidence: inferred.confidence,
|
|
293
|
+
classification: inferred.confidence >= autoWriteAbove ? "indexed" : "needs-review",
|
|
294
|
+
last_updated: now,
|
|
295
|
+
updated_by: "polaris-map-update",
|
|
296
|
+
tags: inferred.tags,
|
|
297
|
+
instructionFile: (0, atlas_js_1.resolveInstructionFile)(filePath, repoRoot),
|
|
298
|
+
};
|
|
299
|
+
if (inferred.confidence >= autoWriteAbove) {
|
|
300
|
+
routes[filePath] = entry;
|
|
301
|
+
delete needsReview[filePath];
|
|
302
|
+
summary.inferred++;
|
|
303
|
+
summary.mapped++;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
needsReview[filePath] = entry;
|
|
307
|
+
delete routes[filePath];
|
|
308
|
+
summary.needs_review++;
|
|
309
|
+
if (inferred.confidence >= confidenceThreshold) {
|
|
310
|
+
// Between thresholds: also track in needs-review but don't fail by default
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const onLow = config.map.onLowConfidence ?? "warn";
|
|
314
|
+
if (onLow === "warn") {
|
|
315
|
+
console.error(`[WARN] Low confidence (${inferred.confidence.toFixed(2)}) for ${filePath} — added to needs-review`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
(0, atlas_js_1.writeFileRoutes)(outputPath, routes);
|
|
321
|
+
(0, atlas_js_1.writeNeedsReview)(outputPath, needsReview);
|
|
322
|
+
const allEntries = { ...routes, ...needsReview };
|
|
323
|
+
const totalFiles = Object.keys(allEntries).length;
|
|
324
|
+
const indexedCount = Object.values(allEntries).filter((e) => e.classification === "indexed").length;
|
|
325
|
+
(0, atlas_js_1.writeAtlasIndex)(outputPath, {
|
|
326
|
+
scan_date: now,
|
|
327
|
+
file_count: totalFiles,
|
|
328
|
+
coverage_pct: totalFiles > 0 ? Math.round((indexedCount / totalFiles) * 100) : 0,
|
|
329
|
+
instructionCoverage: (0, atlas_js_1.computeInstructionCoverage)(allEntries),
|
|
330
|
+
entries: allEntries,
|
|
331
|
+
});
|
|
332
|
+
// ── Cognition surface detection ─────────────────────────────────────────
|
|
333
|
+
// Detect newly eligible folders missing POLARIS.md or SUMMARY.md.
|
|
334
|
+
// Default: report only. With seedCognition=true: create draft files.
|
|
335
|
+
// Root is skipped by default; opt in with includeRoot=true.
|
|
336
|
+
// Agent/generated/runtime folders are always skipped.
|
|
337
|
+
const { missingPolaris, missingSummary } = detectMissingCognitionSurfaces(changedFiles, repoRoot, includeRoot);
|
|
338
|
+
summary.missing_polaris = missingPolaris;
|
|
339
|
+
summary.missing_summary = missingSummary;
|
|
340
|
+
if (missingPolaris.length > 0) {
|
|
341
|
+
console.error(`[INFO] Folders missing POLARIS.md (${missingPolaris.length}): ${missingPolaris.join(", ")}`);
|
|
342
|
+
}
|
|
343
|
+
if (missingSummary.length > 0) {
|
|
344
|
+
console.error(`[INFO] Folders eligible for SUMMARY.md (${missingSummary.length}): ${missingSummary.join(", ")}`);
|
|
345
|
+
}
|
|
346
|
+
if (seedCognition) {
|
|
347
|
+
const seeded = seedCognitionDrafts({ polaris: missingPolaris, summary: missingSummary }, repoRoot, includeRoot);
|
|
348
|
+
summary.seeded = seeded;
|
|
349
|
+
if (seeded.length > 0) {
|
|
350
|
+
console.error(`[INFO] Seeded draft cognition files (${seeded.length}): ${seeded.join(", ")}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
console.log(JSON.stringify(summary));
|
|
354
|
+
return { summary, hasNeedsReview: summary.needs_review > 0 };
|
|
355
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const atlas_js_1 = require("./atlas.js");
|
|
7
|
+
const TMP = (0, node_path_1.join)(process.cwd(), ".test-update-tmp");
|
|
8
|
+
function setup() {
|
|
9
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/map"), { recursive: true });
|
|
10
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/cli"), { recursive: true });
|
|
11
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/deep/nested/dir"), { recursive: true });
|
|
12
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/POLARIS.md"), "# Map instructions");
|
|
13
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "POLARIS.md"), "# Root instructions");
|
|
14
|
+
}
|
|
15
|
+
function teardown() {
|
|
16
|
+
(0, node_fs_1.rmSync)(TMP, { recursive: true, force: true });
|
|
17
|
+
}
|
|
18
|
+
(0, vitest_1.describe)("resolveInstructionFile", () => {
|
|
19
|
+
(0, vitest_1.beforeEach)(setup);
|
|
20
|
+
(0, vitest_1.afterEach)(teardown);
|
|
21
|
+
(0, vitest_1.it)("finds POLARIS.md in the same directory as the file", () => {
|
|
22
|
+
const result = (0, atlas_js_1.resolveInstructionFile)("src/map/atlas.ts", TMP);
|
|
23
|
+
(0, vitest_1.expect)(result).toBe("src/map/POLARIS.md");
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)("finds root POLARIS.md for a file in a directory without one", () => {
|
|
26
|
+
const result = (0, atlas_js_1.resolveInstructionFile)("src/cli/index.ts", TMP);
|
|
27
|
+
(0, vitest_1.expect)(result).toBe("POLARIS.md");
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)("finds nearest ancestor POLARIS.md for deeply nested file", () => {
|
|
30
|
+
const result = (0, atlas_js_1.resolveInstructionFile)("src/deep/nested/dir/file.ts", TMP);
|
|
31
|
+
(0, vitest_1.expect)(result).toBe("POLARIS.md");
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)("returns undefined when no POLARIS.md exists anywhere", () => {
|
|
34
|
+
(0, node_fs_1.rmSync)((0, node_path_1.join)(TMP, "POLARIS.md"));
|
|
35
|
+
const result = (0, atlas_js_1.resolveInstructionFile)("src/cli/index.ts", TMP);
|
|
36
|
+
(0, vitest_1.expect)(result).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.it)("prefers the closest ancestor over a more distant one", () => {
|
|
39
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/deep/POLARIS.md"), "# Deep src instructions");
|
|
40
|
+
const result = (0, atlas_js_1.resolveInstructionFile)("src/deep/nested/dir/file.ts", TMP);
|
|
41
|
+
(0, vitest_1.expect)(result).toBe("src/deep/POLARIS.md");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.describe)("computeInstructionCoverage", () => {
|
|
45
|
+
(0, vitest_1.it)("returns zero coverage for empty entries", () => {
|
|
46
|
+
const result = (0, atlas_js_1.computeInstructionCoverage)({});
|
|
47
|
+
(0, vitest_1.expect)(result).toEqual({ routesCovered: 0, routesTotal: 0, coveragePercent: 0 });
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)("counts covered and total correctly", () => {
|
|
50
|
+
const entries = {
|
|
51
|
+
"src/a.ts": { domain: "x", route: "x", taskchain: "x", confidence: 1, classification: "indexed", last_updated: "", updated_by: "", tags: [], instructionFile: "POLARIS.md" },
|
|
52
|
+
"src/b.ts": { domain: "x", route: "x", taskchain: "x", confidence: 1, classification: "indexed", last_updated: "", updated_by: "", tags: [] },
|
|
53
|
+
};
|
|
54
|
+
const result = (0, atlas_js_1.computeInstructionCoverage)(entries);
|
|
55
|
+
(0, vitest_1.expect)(result.routesCovered).toBe(1);
|
|
56
|
+
(0, vitest_1.expect)(result.routesTotal).toBe(2);
|
|
57
|
+
(0, vitest_1.expect)(result.coveragePercent).toBe(50);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)("returns 100% when all entries have instructionFile", () => {
|
|
60
|
+
const entries = {
|
|
61
|
+
"src/a.ts": { domain: "x", route: "x", taskchain: "x", confidence: 1, classification: "indexed", last_updated: "", updated_by: "", tags: [], instructionFile: "POLARIS.md" },
|
|
62
|
+
"src/b.ts": { domain: "x", route: "x", taskchain: "x", confidence: 1, classification: "indexed", last_updated: "", updated_by: "", tags: [], instructionFile: "src/POLARIS.md" },
|
|
63
|
+
};
|
|
64
|
+
const result = (0, atlas_js_1.computeInstructionCoverage)(entries);
|
|
65
|
+
(0, vitest_1.expect)(result.coveragePercent).toBe(100);
|
|
66
|
+
});
|
|
67
|
+
});
|