@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,120 @@
|
|
|
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 backfill_js_1 = require("./backfill.js");
|
|
7
|
+
const TMP = (0, node_path_1.join)(process.cwd(), ".test-backfill-tmp");
|
|
8
|
+
const EXISTING_ROUTES = {
|
|
9
|
+
"src/cli/index.ts": {
|
|
10
|
+
domain: "cli",
|
|
11
|
+
route: "src/cli",
|
|
12
|
+
taskchain: "polaris-cli",
|
|
13
|
+
confidence: 0.95,
|
|
14
|
+
classification: "indexed",
|
|
15
|
+
last_updated: "2026-05-22T20:00:00Z",
|
|
16
|
+
updated_by: "polaris-map-index",
|
|
17
|
+
tags: ["cli", "entry-point"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
const POLARIS_CONFIG = {
|
|
21
|
+
repo: { sourceRoots: ["src"], docsRoots: [], sidecarOutputPath: ".polaris/map" },
|
|
22
|
+
map: { autoWriteAbove: 0.85, confidenceThreshold: 0.75 },
|
|
23
|
+
};
|
|
24
|
+
function setup() {
|
|
25
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, ".polaris/map"), { recursive: true });
|
|
26
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/cli"), { recursive: true });
|
|
27
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(TMP, "src/map"), { recursive: true });
|
|
28
|
+
// Pre-existing file already in atlas
|
|
29
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/cli/index.ts"), "");
|
|
30
|
+
// New unmapped file — should be backfilled
|
|
31
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/cli/version.ts"), "");
|
|
32
|
+
// New file in a different domain
|
|
33
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "src/map/backfill.ts"), "");
|
|
34
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), JSON.stringify(EXISTING_ROUTES));
|
|
35
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/needs-review.json"), JSON.stringify({}));
|
|
36
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polaris/map/exemptions.json"), JSON.stringify({}));
|
|
37
|
+
(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: {} }));
|
|
38
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, "polaris.config.json"), JSON.stringify(POLARIS_CONFIG));
|
|
39
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(TMP, ".polarisignore"), "*.log\n");
|
|
40
|
+
}
|
|
41
|
+
function teardown() {
|
|
42
|
+
(0, node_fs_1.rmSync)(TMP, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
function captureOutput(fn) {
|
|
45
|
+
const stdoutLines = [];
|
|
46
|
+
const stderrLines = [];
|
|
47
|
+
const origLog = console.log.bind(console);
|
|
48
|
+
const origError = console.error.bind(console);
|
|
49
|
+
const origStdout = process.stdout.write.bind(process.stdout);
|
|
50
|
+
const origStderr = process.stderr.write.bind(process.stderr);
|
|
51
|
+
console.log = (...args) => { stdoutLines.push(args.map(String).join(" ")); };
|
|
52
|
+
console.error = (...args) => { stderrLines.push(args.map(String).join(" ")); };
|
|
53
|
+
process.stdout.write = (chunk) => { stdoutLines.push(String(chunk)); return true; };
|
|
54
|
+
process.stderr.write = (chunk) => { stderrLines.push(String(chunk)); return true; };
|
|
55
|
+
try {
|
|
56
|
+
fn();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
console.log = origLog;
|
|
60
|
+
console.error = origError;
|
|
61
|
+
process.stdout.write = origStdout;
|
|
62
|
+
process.stderr.write = origStderr;
|
|
63
|
+
}
|
|
64
|
+
return { stdout: stdoutLines.join(""), stderr: stderrLines.join("") };
|
|
65
|
+
}
|
|
66
|
+
(0, vitest_1.describe)("runMapBackfill", () => {
|
|
67
|
+
(0, vitest_1.beforeEach)(setup);
|
|
68
|
+
(0, vitest_1.afterEach)(teardown);
|
|
69
|
+
(0, vitest_1.it)("adds unmapped files to file-routes.json without touching existing entries", () => {
|
|
70
|
+
captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, undefined, false));
|
|
71
|
+
const routes = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8"));
|
|
72
|
+
// Existing entry preserved
|
|
73
|
+
(0, vitest_1.expect)(routes["src/cli/index.ts"].confidence).toBe(0.95);
|
|
74
|
+
(0, vitest_1.expect)(routes["src/cli/index.ts"].updated_by).toBe("polaris-map-index");
|
|
75
|
+
// New entry added
|
|
76
|
+
(0, vitest_1.expect)(routes["src/cli/version.ts"] || routes["src/map/backfill.ts"]).toBeTruthy();
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)("reports correct summary counts", () => {
|
|
79
|
+
const { stdout } = captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, undefined, false));
|
|
80
|
+
(0, vitest_1.expect)(stdout).toMatch(/Backfilled \d+ files\. Added \d+\. Queued \d+ for review\. Skipped \d+/);
|
|
81
|
+
// src/cli/index.ts should be counted as skipped
|
|
82
|
+
(0, vitest_1.expect)(stdout).toContain("Skipped 1");
|
|
83
|
+
});
|
|
84
|
+
(0, vitest_1.it)("does not write files when --dry-run is set", () => {
|
|
85
|
+
const beforeRoutes = (0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8");
|
|
86
|
+
const { stdout } = captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, true, undefined, false));
|
|
87
|
+
const afterRoutes = (0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8");
|
|
88
|
+
(0, vitest_1.expect)(afterRoutes).toBe(beforeRoutes);
|
|
89
|
+
(0, vitest_1.expect)(stdout).toContain("dry-run");
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)("limits backfill to --domain when specified", () => {
|
|
92
|
+
captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, "cli", false));
|
|
93
|
+
const routes = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8"));
|
|
94
|
+
// cli domain file added
|
|
95
|
+
(0, vitest_1.expect)(routes["src/cli/version.ts"]).toBeTruthy();
|
|
96
|
+
// map domain file NOT added (filtered out)
|
|
97
|
+
(0, vitest_1.expect)(routes["src/map/backfill.ts"]).toBeUndefined();
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)("never overwrites an existing entry in a second run", () => {
|
|
100
|
+
captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, undefined, false));
|
|
101
|
+
const routesAfterFirst = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8"));
|
|
102
|
+
const versionEntry = routesAfterFirst["src/cli/version.ts"];
|
|
103
|
+
captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, undefined, false));
|
|
104
|
+
const routesAfterSecond = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"), "utf-8"));
|
|
105
|
+
(0, vitest_1.expect)(routesAfterSecond["src/cli/version.ts"]).toEqual(versionEntry);
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)("errors if atlas is not initialized", () => {
|
|
108
|
+
(0, node_fs_1.rmSync)((0, node_path_1.join)(TMP, ".polaris/map/file-routes.json"));
|
|
109
|
+
let exited = false;
|
|
110
|
+
const origExit = process.exit.bind(process);
|
|
111
|
+
process.exit = (() => { exited = true; });
|
|
112
|
+
try {
|
|
113
|
+
captureOutput(() => (0, backfill_js_1.runMapBackfill)(TMP, false, undefined, false));
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
process.exit = origExit;
|
|
117
|
+
}
|
|
118
|
+
(0, vitest_1.expect)(exited).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runMapIndex = runMapIndex;
|
|
4
|
+
exports.createMapCommand = createMapCommand;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const loader_js_1 = require("../config/loader.js");
|
|
10
|
+
const update_js_1 = require("./update.js");
|
|
11
|
+
const validate_js_1 = require("./validate.js");
|
|
12
|
+
const query_js_1 = require("./query.js");
|
|
13
|
+
const backfill_js_1 = require("./backfill.js");
|
|
14
|
+
const welfare_js_1 = require("./welfare.js");
|
|
15
|
+
const parser_js_1 = require("../ignore/parser.js");
|
|
16
|
+
const defaults_js_1 = require("../ignore/defaults.js");
|
|
17
|
+
const inference_js_1 = require("./inference.js");
|
|
18
|
+
const atlas_js_1 = require("./atlas.js");
|
|
19
|
+
const SECRET_REGEXES = defaults_js_1.SECRET_PATTERNS.map((p) => new RegExp("^" + p.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"));
|
|
20
|
+
function isSecretFile(filePath) {
|
|
21
|
+
const parts = filePath.split("/");
|
|
22
|
+
const base = parts[parts.length - 1];
|
|
23
|
+
return SECRET_REGEXES.some((re) => re.test(base) || re.test(filePath));
|
|
24
|
+
}
|
|
25
|
+
function* walkDir(dir, root, ig) {
|
|
26
|
+
for (const entry of (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })) {
|
|
27
|
+
const full = (0, node_path_1.join)(dir, entry.name);
|
|
28
|
+
const rel = (0, node_path_1.relative)(root, full).replace(/\\/g, "/");
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
if (ig?.ignores(rel + "/"))
|
|
31
|
+
continue;
|
|
32
|
+
yield* walkDir(full, root, ig);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
yield rel;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getBranchName(repoRoot) {
|
|
40
|
+
try {
|
|
41
|
+
return (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
42
|
+
cwd: repoRoot,
|
|
43
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
44
|
+
})
|
|
45
|
+
.toString()
|
|
46
|
+
.trim();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function loadIgnoreFilter(repoRoot) {
|
|
53
|
+
let userPatterns = [];
|
|
54
|
+
try {
|
|
55
|
+
const raw = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(repoRoot, ".polarisignore"), "utf-8");
|
|
56
|
+
userPatterns = raw.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("#"));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (typeof err === "object" && err !== null && "code" in err && err.code !== "ENOENT") {
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return (0, parser_js_1.parsePolarisIgnore)(userPatterns);
|
|
64
|
+
}
|
|
65
|
+
function runMapIndex(repoRoot, dryRun, verbose, _options = {}) {
|
|
66
|
+
if (!(0, node_fs_1.existsSync)(repoRoot)) {
|
|
67
|
+
console.error(`Repo root not found: ${repoRoot}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const config = (0, loader_js_1.loadConfig)(repoRoot);
|
|
71
|
+
const outputPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
|
|
72
|
+
const branchName = getBranchName(repoRoot);
|
|
73
|
+
const ig = loadIgnoreFilter(repoRoot);
|
|
74
|
+
const existingRoutes = (0, atlas_js_1.readFileRoutes)(outputPath);
|
|
75
|
+
const existingExemptions = (0, atlas_js_1.readExemptions)(outputPath);
|
|
76
|
+
const newRoutes = {};
|
|
77
|
+
const newNeedsReview = {};
|
|
78
|
+
const newExemptions = { ...existingExemptions };
|
|
79
|
+
let scanned = 0;
|
|
80
|
+
let mapped = 0;
|
|
81
|
+
let trackedNotIndexed = 0;
|
|
82
|
+
let needsReview = 0;
|
|
83
|
+
let ignored = 0;
|
|
84
|
+
const now = new Date().toISOString();
|
|
85
|
+
for (const filePath of walkDir(repoRoot, repoRoot, ig)) {
|
|
86
|
+
scanned++;
|
|
87
|
+
// Security check — never process secret files
|
|
88
|
+
if (isSecretFile(filePath)) {
|
|
89
|
+
console.error(`[HIGH] Secret file pattern matched, skipping: ${filePath}`);
|
|
90
|
+
ignored++;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// 1. .polarisignore
|
|
94
|
+
if (ig.ignores(filePath)) {
|
|
95
|
+
ignored++;
|
|
96
|
+
if (verbose)
|
|
97
|
+
console.log(` ignored: ${filePath}`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// 2. exemptions.json
|
|
101
|
+
if (existingExemptions[filePath]) {
|
|
102
|
+
trackedNotIndexed++;
|
|
103
|
+
if (verbose)
|
|
104
|
+
console.log(` tracked-not-indexed (exemption): ${filePath}`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// 3. generatedRoots
|
|
108
|
+
const isGenerated = (config.repo.generatedRoots ?? []).some((root) => {
|
|
109
|
+
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
110
|
+
return filePath.startsWith(prefix);
|
|
111
|
+
});
|
|
112
|
+
if (isGenerated) {
|
|
113
|
+
newExemptions[filePath] = { classification: "tracked-not-indexed", reason: "generatedRoots" };
|
|
114
|
+
trackedNotIndexed++;
|
|
115
|
+
if (verbose)
|
|
116
|
+
console.log(` tracked-not-indexed (generated): ${filePath}`);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// 4. Route inference
|
|
120
|
+
const inferred = (0, inference_js_1.inferRoute)(filePath, repoRoot, config, existingRoutes, branchName);
|
|
121
|
+
const entry = {
|
|
122
|
+
domain: inferred.domain,
|
|
123
|
+
route: inferred.route,
|
|
124
|
+
taskchain: inferred.taskchain,
|
|
125
|
+
confidence: inferred.confidence,
|
|
126
|
+
classification: inferred.confidence >= (config.map.autoWriteAbove ?? 0.85) ? "indexed" : "needs-review",
|
|
127
|
+
last_updated: now,
|
|
128
|
+
updated_by: "polaris-map-index",
|
|
129
|
+
tags: inferred.tags,
|
|
130
|
+
instructionFile: (0, atlas_js_1.resolveInstructionFile)(filePath, repoRoot),
|
|
131
|
+
};
|
|
132
|
+
if (inferred.confidence >= (config.map.autoWriteAbove ?? 0.85)) {
|
|
133
|
+
newRoutes[filePath] = entry;
|
|
134
|
+
mapped++;
|
|
135
|
+
if (verbose)
|
|
136
|
+
console.log(` indexed (${inferred.confidence.toFixed(2)}): ${filePath}`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
newNeedsReview[filePath] = entry;
|
|
140
|
+
needsReview++;
|
|
141
|
+
if (verbose)
|
|
142
|
+
console.log(` needs-review (${inferred.confidence.toFixed(2)}): ${filePath}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const coveragePct = scanned > 0 ? Math.round((mapped / scanned) * 100) : 0;
|
|
146
|
+
if (!dryRun) {
|
|
147
|
+
(0, atlas_js_1.writeFileRoutes)(outputPath, newRoutes);
|
|
148
|
+
(0, atlas_js_1.writeNeedsReview)(outputPath, newNeedsReview);
|
|
149
|
+
(0, atlas_js_1.writeExemptions)(outputPath, newExemptions);
|
|
150
|
+
const allEntries = { ...newRoutes, ...newNeedsReview };
|
|
151
|
+
(0, atlas_js_1.writeAtlasIndex)(outputPath, {
|
|
152
|
+
scan_date: now,
|
|
153
|
+
file_count: scanned,
|
|
154
|
+
coverage_pct: coveragePct,
|
|
155
|
+
instructionCoverage: (0, atlas_js_1.computeInstructionCoverage)(allEntries),
|
|
156
|
+
entries: allEntries,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
console.log(`Scanned ${scanned} files. Mapped ${mapped}. Tracked-not-indexed ${trackedNotIndexed}. Needs-review ${needsReview}. Ignored ${ignored}.`);
|
|
160
|
+
if (dryRun)
|
|
161
|
+
console.log("(dry-run: no files written)");
|
|
162
|
+
}
|
|
163
|
+
function failMissingSubcommand(command, commandName) {
|
|
164
|
+
const unknownSubcommand = command.args[0];
|
|
165
|
+
const message = unknownSubcommand
|
|
166
|
+
? `error: unknown command '${unknownSubcommand}' for '${commandName}'. Run '${commandName} --help'.`
|
|
167
|
+
: `error: missing command for '${commandName}'. Run '${commandName} --help'.`;
|
|
168
|
+
command.error(message, {
|
|
169
|
+
code: "commander.missingCommand",
|
|
170
|
+
exitCode: 1,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function createMapCommand(handlers = {}) {
|
|
174
|
+
const indexHandler = handlers.runMapIndex ?? runMapIndex;
|
|
175
|
+
const updateHandler = handlers.runMapUpdate ?? update_js_1.runMapUpdate;
|
|
176
|
+
const validateHandler = handlers.runMapValidate ?? validate_js_1.runMapValidate;
|
|
177
|
+
const backfillHandler = handlers.runMapBackfill ?? backfill_js_1.runMapBackfill;
|
|
178
|
+
const queryHandler = handlers.runMapQuery ?? query_js_1.runMapQuery;
|
|
179
|
+
const repoRootDefault = handlers.repoRoot ?? process.cwd();
|
|
180
|
+
const map = new commander_1.Command("map")
|
|
181
|
+
.description("Polaris atlas map commands: --dry-run is a non-mutating preview")
|
|
182
|
+
.showHelpAfterError()
|
|
183
|
+
.showSuggestionAfterError();
|
|
184
|
+
map.action(() => failMissingSubcommand(map, "polaris map"));
|
|
185
|
+
map
|
|
186
|
+
.command("index")
|
|
187
|
+
.description("mutating: full first-pass atlas generation")
|
|
188
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
189
|
+
.option("--dry-run", "non-mutating preview: print results without writing files")
|
|
190
|
+
.option("-v, --verbose", "Show per-file classification")
|
|
191
|
+
.action((options) => {
|
|
192
|
+
indexHandler(options.repoRoot, options.dryRun ?? false, options.verbose ?? false);
|
|
193
|
+
});
|
|
194
|
+
map
|
|
195
|
+
.command("update")
|
|
196
|
+
.description("mutating: incremental changed-file mapping")
|
|
197
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
198
|
+
.option("--changed [files...]", "Changed files (omit to detect from git diff)")
|
|
199
|
+
.option("--from-commit <sha>", "Start commit for diff (default: HEAD~1)")
|
|
200
|
+
.option("--to-commit <sha>", "End commit for diff (default: HEAD)")
|
|
201
|
+
.option("--seed-cognition", "Create draft POLARIS.md and SUMMARY.md for newly eligible folders (default: report only)")
|
|
202
|
+
.option("--include-root", "Include root folder in cognition surface detection/seeding (skipped by default)")
|
|
203
|
+
.action((options) => {
|
|
204
|
+
const files = Array.isArray(options.changed) ? options.changed : [];
|
|
205
|
+
const { hasNeedsReview } = updateHandler(options.repoRoot, files, options.fromCommit, options.toCommit, options.seedCognition, options.includeRoot);
|
|
206
|
+
const onLowConfidence = (0, loader_js_1.loadConfig)(options.repoRoot).map.onLowConfidence ?? "warn";
|
|
207
|
+
if (hasNeedsReview && onLowConfidence === "fail")
|
|
208
|
+
process.exit(1);
|
|
209
|
+
});
|
|
210
|
+
map
|
|
211
|
+
.command("validate")
|
|
212
|
+
.description("safe/read-only by default: atlas integrity check and needs-review reporting")
|
|
213
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
214
|
+
.option("--stale-threshold <days>", "Days before an entry is considered stale", "30")
|
|
215
|
+
.option("--fix <path>", "Show and optionally fix entry for a specific file")
|
|
216
|
+
.action((options) => {
|
|
217
|
+
const { hasError } = validateHandler(options.repoRoot, parseInt(options.staleThreshold, 10), options.fix);
|
|
218
|
+
if (hasError)
|
|
219
|
+
process.exit(1);
|
|
220
|
+
});
|
|
221
|
+
map
|
|
222
|
+
.command("backfill")
|
|
223
|
+
.description("mutating unless --dry-run: incremental gap-fill for an already-indexed repo")
|
|
224
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
225
|
+
.option("--dry-run", "non-mutating preview: print results without writing files")
|
|
226
|
+
.option("--domain <domain>", "Limit backfill to a specific domain")
|
|
227
|
+
.option("-v, --verbose", "Show per-file classification")
|
|
228
|
+
.action((options) => {
|
|
229
|
+
backfillHandler(options.repoRoot, options.dryRun ?? false, options.domain, options.verbose ?? false);
|
|
230
|
+
});
|
|
231
|
+
map
|
|
232
|
+
.command("query [path]")
|
|
233
|
+
.description("safe/read-only: sidecar metadata lookup by path, glob, or filter")
|
|
234
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
235
|
+
.option("--domain <domain>", "All files in a domain")
|
|
236
|
+
.option("--taskchain <taskchain>", "All files in a taskchain")
|
|
237
|
+
.option("--text", "Human-readable output instead of JSON")
|
|
238
|
+
.option("--include-instructions", "Include POLARIS.md instruction file path and content in output")
|
|
239
|
+
.action((pathArg, options) => {
|
|
240
|
+
queryHandler(options.repoRoot, pathArg, options.domain, options.taskchain, options.text ?? false, options.includeInstructions ?? false);
|
|
241
|
+
});
|
|
242
|
+
map
|
|
243
|
+
.command("welfare-check")
|
|
244
|
+
.description("safe/read-only: run route welfare checks and report per-route health")
|
|
245
|
+
.option("-r, --repo-root <path>", "Repository root", repoRootDefault)
|
|
246
|
+
.option("--route <path>", "Scope to a single route domain")
|
|
247
|
+
.action((options) => {
|
|
248
|
+
const report = (0, welfare_js_1.runWelfareCheck)(options.repoRoot, options.route);
|
|
249
|
+
(0, welfare_js_1.printWelfareCheckReport)(report);
|
|
250
|
+
if (report.needsReview > 0) {
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
return map;
|
|
255
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferRoute = inferRoute;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
function inferRoute(filePath, repoRoot, config, knownRoutes, branchName) {
|
|
7
|
+
let confidence = 0;
|
|
8
|
+
let domain = "";
|
|
9
|
+
let route = "";
|
|
10
|
+
let taskchain = "";
|
|
11
|
+
const tags = [];
|
|
12
|
+
// Signal 1: file path prefix matching sourceRoots
|
|
13
|
+
for (const sourceRoot of (config.repo.sourceRoots ?? [])) {
|
|
14
|
+
const prefix = sourceRoot.endsWith("/") ? sourceRoot : `${sourceRoot}/`;
|
|
15
|
+
if (filePath.startsWith(prefix)) {
|
|
16
|
+
const rest = filePath.slice(prefix.length);
|
|
17
|
+
const subdir = rest.split("/")[0];
|
|
18
|
+
if (subdir && rest.includes("/")) {
|
|
19
|
+
domain = subdir;
|
|
20
|
+
route = `${sourceRoot}/${subdir}`;
|
|
21
|
+
taskchain = `polaris-${subdir}`;
|
|
22
|
+
confidence += 0.85;
|
|
23
|
+
tags.push(subdir);
|
|
24
|
+
}
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Signal 2: nearby mapped files in same directory (corroborating)
|
|
29
|
+
if (domain) {
|
|
30
|
+
const dir = (0, node_path_1.dirname)(filePath);
|
|
31
|
+
const nearbyAgreement = Object.entries(knownRoutes).some(([p, e]) => (0, node_path_1.dirname)(p) === dir && e.domain === domain);
|
|
32
|
+
if (nearbyAgreement) {
|
|
33
|
+
confidence = Math.min(confidence + 0.05, 0.99);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Signal 3: branch name contains domain slug (corroborating)
|
|
37
|
+
if (domain && branchName) {
|
|
38
|
+
const slugParts = branchName.toLowerCase().split(/[-/]/);
|
|
39
|
+
if (slugParts.includes(domain.toLowerCase())) {
|
|
40
|
+
confidence = Math.min(confidence + 0.05, 0.99);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Signal 4: file imports from paths in the same domain (corroborating)
|
|
44
|
+
if (domain) {
|
|
45
|
+
try {
|
|
46
|
+
const fullPath = (0, node_path_1.resolve)(repoRoot, filePath);
|
|
47
|
+
if ((0, node_fs_1.existsSync)(fullPath)) {
|
|
48
|
+
const content = (0, node_fs_1.readFileSync)(fullPath, "utf-8");
|
|
49
|
+
const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
50
|
+
const sameDomainImport = new RegExp(`from\\s+['"](?:\\.\\.?/)*${escapedDomain}/`);
|
|
51
|
+
if (sameDomainImport.test(content)) {
|
|
52
|
+
confidence = Math.min(confidence + 0.05, 0.99);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// ignore read errors
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Tags: entry-point and test detection
|
|
61
|
+
const file = (0, node_path_1.basename)(filePath);
|
|
62
|
+
if (file === "index.ts" || file === "index.js")
|
|
63
|
+
tags.push("entry-point");
|
|
64
|
+
if (file.includes(".test.") || file.includes(".spec."))
|
|
65
|
+
tags.push("test");
|
|
66
|
+
return {
|
|
67
|
+
domain: domain || "unknown",
|
|
68
|
+
route: route || filePath,
|
|
69
|
+
taskchain: taskchain || "polaris-core",
|
|
70
|
+
confidence,
|
|
71
|
+
tags,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const inference_js_1 = require("./inference.js");
|
|
5
|
+
const defaults_js_1 = require("../config/defaults.js");
|
|
6
|
+
const config = defaults_js_1.DEFAULT_CONFIG;
|
|
7
|
+
(0, vitest_1.describe)("inferRoute", () => {
|
|
8
|
+
(0, vitest_1.it)("classifies a file under a sourceRoot subdirectory", () => {
|
|
9
|
+
const result = (0, inference_js_1.inferRoute)("src/cli/index.ts", "/repo", config, {}, "");
|
|
10
|
+
(0, vitest_1.expect)(result.domain).toBe("cli");
|
|
11
|
+
(0, vitest_1.expect)(result.route).toBe("src/cli");
|
|
12
|
+
(0, vitest_1.expect)(result.taskchain).toBe("polaris-cli");
|
|
13
|
+
(0, vitest_1.expect)(result.confidence).toBeGreaterThanOrEqual(0.85);
|
|
14
|
+
(0, vitest_1.expect)(result.tags).toContain("cli");
|
|
15
|
+
(0, vitest_1.expect)(result.tags).toContain("entry-point");
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)("classifies a map domain file", () => {
|
|
18
|
+
const result = (0, inference_js_1.inferRoute)("src/map/atlas.ts", "/repo", config, {}, "");
|
|
19
|
+
(0, vitest_1.expect)(result.domain).toBe("map");
|
|
20
|
+
(0, vitest_1.expect)(result.confidence).toBeGreaterThanOrEqual(0.85);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)("returns low confidence for files outside sourceRoots", () => {
|
|
23
|
+
const result = (0, inference_js_1.inferRoute)("package.json", "/repo", config, {}, "");
|
|
24
|
+
(0, vitest_1.expect)(result.confidence).toBeLessThan(0.85);
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.it)("tags test files", () => {
|
|
27
|
+
const result = (0, inference_js_1.inferRoute)("src/cli/version.test.ts", "/repo", config, {}, "");
|
|
28
|
+
(0, vitest_1.expect)(result.tags).toContain("test");
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)("boosts confidence from branch name", () => {
|
|
31
|
+
const base = (0, inference_js_1.inferRoute)("src/map/index.ts", "/repo", config, {}, "");
|
|
32
|
+
const withBranch = (0, inference_js_1.inferRoute)("src/map/index.ts", "/repo", config, {}, "philmeaux/pol-4-cluster-3-polaris-map");
|
|
33
|
+
(0, vitest_1.expect)(withBranch.confidence).toBeGreaterThanOrEqual(base.confidence);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runMapQuery = runMapQuery;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const loader_js_1 = require("../config/loader.js");
|
|
7
|
+
const parser_js_1 = require("../ignore/parser.js");
|
|
8
|
+
const atlas_js_1 = require("./atlas.js");
|
|
9
|
+
function globToRegex(pattern) {
|
|
10
|
+
let regStr = "";
|
|
11
|
+
let i = 0;
|
|
12
|
+
while (i < pattern.length) {
|
|
13
|
+
const c = pattern[i];
|
|
14
|
+
if (c === "*" && pattern[i + 1] === "*") {
|
|
15
|
+
regStr += ".*";
|
|
16
|
+
i += 2;
|
|
17
|
+
if (pattern[i] === "/")
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
else if (c === "*") {
|
|
21
|
+
regStr += "[^/]*";
|
|
22
|
+
i++;
|
|
23
|
+
}
|
|
24
|
+
else if (c === "?") {
|
|
25
|
+
regStr += "[^/]";
|
|
26
|
+
i++;
|
|
27
|
+
}
|
|
28
|
+
else if (".+^${}[]|()\\".includes(c)) {
|
|
29
|
+
regStr += "\\" + c;
|
|
30
|
+
i++;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
regStr += c;
|
|
34
|
+
i++;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return new RegExp("^" + regStr + "$");
|
|
38
|
+
}
|
|
39
|
+
function loadIgnoreFilter(repoRoot) {
|
|
40
|
+
let userPatterns = [];
|
|
41
|
+
try {
|
|
42
|
+
const raw = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(repoRoot, ".polarisignore"), "utf-8");
|
|
43
|
+
userPatterns = raw.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("#"));
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (typeof err === "object" && err !== null && "code" in err && err.code !== "ENOENT") {
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return (0, parser_js_1.parsePolarisIgnore)(userPatterns);
|
|
51
|
+
}
|
|
52
|
+
function toQueryEntry(entry, repoRoot, includeInstructions) {
|
|
53
|
+
const base = {
|
|
54
|
+
domain: entry.domain,
|
|
55
|
+
route: entry.route,
|
|
56
|
+
taskchain: entry.taskchain,
|
|
57
|
+
confidence: entry.confidence,
|
|
58
|
+
classification: entry.classification === "needs-review" ? "needs-review" : "indexed",
|
|
59
|
+
last_updated: entry.last_updated,
|
|
60
|
+
tags: entry.tags,
|
|
61
|
+
};
|
|
62
|
+
if (entry.instructionFile !== undefined) {
|
|
63
|
+
base.instructionFile = entry.instructionFile;
|
|
64
|
+
if (includeInstructions && repoRoot !== undefined) {
|
|
65
|
+
try {
|
|
66
|
+
base.instructionContent = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(repoRoot, entry.instructionFile), "utf-8");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// file missing — omit content silently
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return base;
|
|
74
|
+
}
|
|
75
|
+
function resolveEntry(filePath, routes, needsReview, exemptions, ig, repoRoot, includeInstructions) {
|
|
76
|
+
if (routes[filePath])
|
|
77
|
+
return toQueryEntry(routes[filePath], repoRoot, includeInstructions);
|
|
78
|
+
if (needsReview[filePath])
|
|
79
|
+
return toQueryEntry(needsReview[filePath], repoRoot, includeInstructions);
|
|
80
|
+
if (exemptions[filePath])
|
|
81
|
+
return { classification: exemptions[filePath].classification };
|
|
82
|
+
if (ig.ignores(filePath))
|
|
83
|
+
return { classification: "ignored" };
|
|
84
|
+
return { classification: "unmapped" };
|
|
85
|
+
}
|
|
86
|
+
function printText(result) {
|
|
87
|
+
for (const [filePath, entry] of Object.entries(result)) {
|
|
88
|
+
const parts = [filePath, entry.classification];
|
|
89
|
+
if ("domain" in entry) {
|
|
90
|
+
parts.push(`domain:${entry.domain}`, `route:${entry.route}`, `taskchain:${entry.taskchain}`, `conf:${entry.confidence.toFixed(2)}`);
|
|
91
|
+
if (entry.instructionFile !== undefined)
|
|
92
|
+
parts.push(`instructions:${entry.instructionFile}`);
|
|
93
|
+
}
|
|
94
|
+
console.log(parts.join(" "));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function runMapQuery(repoRoot, pathArg, domain, taskchain, textMode, includeInstructions = false) {
|
|
98
|
+
const config = (0, loader_js_1.loadConfig)(repoRoot);
|
|
99
|
+
const outputPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
|
|
100
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.resolve)(outputPath, "file-routes.json"))) {
|
|
101
|
+
console.error("atlas not initialized — run `polaris map index` first");
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
const routes = (0, atlas_js_1.readFileRoutes)(outputPath);
|
|
105
|
+
const needsReview = (0, atlas_js_1.readNeedsReview)(outputPath);
|
|
106
|
+
const exemptions = (0, atlas_js_1.readExemptions)(outputPath);
|
|
107
|
+
const ig = loadIgnoreFilter(repoRoot);
|
|
108
|
+
const result = {};
|
|
109
|
+
if (domain !== undefined) {
|
|
110
|
+
for (const [filePath, entry] of [...Object.entries(routes), ...Object.entries(needsReview)]) {
|
|
111
|
+
if (entry.domain === domain)
|
|
112
|
+
result[filePath] = toQueryEntry(entry, repoRoot, includeInstructions);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (taskchain !== undefined) {
|
|
116
|
+
for (const [filePath, entry] of [...Object.entries(routes), ...Object.entries(needsReview)]) {
|
|
117
|
+
if (entry.taskchain === taskchain)
|
|
118
|
+
result[filePath] = toQueryEntry(entry, repoRoot, includeInstructions);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (pathArg !== undefined) {
|
|
122
|
+
const isGlobPattern = pathArg.includes("*") || pathArg.includes("?");
|
|
123
|
+
const isDir = !isGlobPattern && pathArg.endsWith("/");
|
|
124
|
+
if (isGlobPattern) {
|
|
125
|
+
const re = globToRegex(pathArg);
|
|
126
|
+
const allPaths = new Set([...Object.keys(routes), ...Object.keys(needsReview), ...Object.keys(exemptions)]);
|
|
127
|
+
for (const filePath of allPaths) {
|
|
128
|
+
if (re.test(filePath))
|
|
129
|
+
result[filePath] = resolveEntry(filePath, routes, needsReview, exemptions, ig, repoRoot, includeInstructions);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (isDir) {
|
|
133
|
+
const prefix = pathArg;
|
|
134
|
+
const allPaths = new Set([...Object.keys(routes), ...Object.keys(needsReview), ...Object.keys(exemptions)]);
|
|
135
|
+
for (const filePath of allPaths) {
|
|
136
|
+
if (filePath.startsWith(prefix))
|
|
137
|
+
result[filePath] = resolveEntry(filePath, routes, needsReview, exemptions, ig, repoRoot, includeInstructions);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, pathArg))) {
|
|
142
|
+
process.stderr.write(`warn: file does not exist in repo: ${pathArg}\n`);
|
|
143
|
+
}
|
|
144
|
+
result[pathArg] = resolveEntry(pathArg, routes, needsReview, exemptions, ig, repoRoot, includeInstructions);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.error("polaris map query: specify a path, glob, or --domain/--taskchain filter");
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
if (textMode) {
|
|
152
|
+
printText(result);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(JSON.stringify(result, null, 2));
|
|
156
|
+
}
|
|
157
|
+
}
|