@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,372 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unit tests for src/loop/worker.ts
|
|
4
|
+
*
|
|
5
|
+
* Uses a mock executeChild hook and mock bootstrap packet to verify:
|
|
6
|
+
* - CompactReturn schema validity on success
|
|
7
|
+
* - current-state.json child completion fields updated
|
|
8
|
+
* - Telemetry JSONL events appended
|
|
9
|
+
* - Worker does not continue to next child
|
|
10
|
+
* - Failure path returns correct CompactReturn
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const vitest_1 = require("vitest");
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
15
|
+
const node_path_1 = require("node:path");
|
|
16
|
+
const node_os_1 = require("node:os");
|
|
17
|
+
const worker_js_1 = require("./worker.js");
|
|
18
|
+
const compact_return_js_1 = require("./compact-return.js");
|
|
19
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
20
|
+
function makeTmpDir() {
|
|
21
|
+
const dir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), `polaris-worker-test-${Date.now()}`);
|
|
22
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
23
|
+
return dir;
|
|
24
|
+
}
|
|
25
|
+
function makeStateFile(dir, childId) {
|
|
26
|
+
const stateFile = (0, node_path_1.join)(dir, "current-state.json");
|
|
27
|
+
const state = {
|
|
28
|
+
schema_version: "1.0",
|
|
29
|
+
run_id: "test-run-001",
|
|
30
|
+
cluster_id: "POL-99",
|
|
31
|
+
skill: "polaris-run",
|
|
32
|
+
artifact_dir: dir,
|
|
33
|
+
branch: "feature/test",
|
|
34
|
+
step_cursor: "dispatching",
|
|
35
|
+
status: "executing",
|
|
36
|
+
session_type: "implementation",
|
|
37
|
+
active_child: childId,
|
|
38
|
+
last_commit: "abc1234",
|
|
39
|
+
next_open_child: childId,
|
|
40
|
+
completed_children: ["POL-68"],
|
|
41
|
+
open_children: [childId, "POL-70"],
|
|
42
|
+
open_children_meta: {},
|
|
43
|
+
context_budget: {
|
|
44
|
+
children_completed: 1,
|
|
45
|
+
files_touched_total: 5,
|
|
46
|
+
max_children_per_session: 3,
|
|
47
|
+
},
|
|
48
|
+
updated_at: new Date().toISOString(),
|
|
49
|
+
};
|
|
50
|
+
(0, node_fs_1.writeFileSync)(stateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
51
|
+
return stateFile;
|
|
52
|
+
}
|
|
53
|
+
function makeTelemetryFile(dir, runId) {
|
|
54
|
+
const telemetryFile = (0, node_path_1.join)(dir, "runs", runId, "telemetry.jsonl");
|
|
55
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, "runs", runId), { recursive: true });
|
|
56
|
+
(0, node_fs_1.writeFileSync)(telemetryFile, "", "utf-8");
|
|
57
|
+
return telemetryFile;
|
|
58
|
+
}
|
|
59
|
+
function makePacket(stateFile, telemetryFile, childId = "POL-69", runId = "test-run-001") {
|
|
60
|
+
return {
|
|
61
|
+
schema_version: "1.0",
|
|
62
|
+
run_id: runId,
|
|
63
|
+
cluster_id: "POL-99",
|
|
64
|
+
active_child: childId,
|
|
65
|
+
state_file: stateFile,
|
|
66
|
+
telemetry_file: telemetryFile,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
70
|
+
(0, vitest_1.describe)("executeOneChild", () => {
|
|
71
|
+
let tmpDir;
|
|
72
|
+
(0, vitest_1.beforeEach)(() => {
|
|
73
|
+
tmpDir = makeTmpDir();
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.afterEach)(() => {
|
|
76
|
+
try {
|
|
77
|
+
(0, node_fs_1.rmSync)(tmpDir, { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// ignore cleanup errors
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)("returns a valid CompactReturn JSON for a successful child", async () => {
|
|
84
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
85
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
86
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
87
|
+
let childExecuted = false;
|
|
88
|
+
const result = await (0, worker_js_1.executeOneChild)(packet, {
|
|
89
|
+
repoRoot: tmpDir,
|
|
90
|
+
executeChild: (childId) => {
|
|
91
|
+
(0, vitest_1.expect)(childId).toBe("POL-69");
|
|
92
|
+
childExecuted = true;
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.expect)(childExecuted).toBe(true);
|
|
96
|
+
// Schema validity
|
|
97
|
+
const errors = (0, compact_return_js_1.validateCompactReturn)(result);
|
|
98
|
+
(0, vitest_1.expect)(errors).toHaveLength(0);
|
|
99
|
+
// Core fields
|
|
100
|
+
(0, vitest_1.expect)(result.child_id).toBe("POL-69");
|
|
101
|
+
(0, vitest_1.expect)(result.status).toBe("done");
|
|
102
|
+
(0, vitest_1.expect)(result.validation).toBe("passed");
|
|
103
|
+
(0, vitest_1.expect)(result.telemetry_updated).toBe(true);
|
|
104
|
+
(0, vitest_1.expect)(result.state_updated).toBe(true);
|
|
105
|
+
(0, vitest_1.expect)(result.next_recommended_action).toBe("continue");
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)("updates current-state.json child completion fields", async () => {
|
|
108
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
109
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
110
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
111
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
112
|
+
repoRoot: tmpDir,
|
|
113
|
+
executeChild: () => { },
|
|
114
|
+
});
|
|
115
|
+
const savedState = JSON.parse((0, node_fs_1.readFileSync)(stateFile, "utf-8"));
|
|
116
|
+
// POL-69 moved from open_children to completed_children
|
|
117
|
+
(0, vitest_1.expect)(savedState["open_children"]).not.toContain("POL-69");
|
|
118
|
+
(0, vitest_1.expect)(savedState["completed_children"]).toContain("POL-69");
|
|
119
|
+
// active_child cleared
|
|
120
|
+
(0, vitest_1.expect)(savedState["active_child"]).toBe("");
|
|
121
|
+
// children_completed incremented
|
|
122
|
+
const budget = savedState["context_budget"];
|
|
123
|
+
(0, vitest_1.expect)(budget["children_completed"]).toBe(2); // was 1, now 2
|
|
124
|
+
// status reflects remaining children
|
|
125
|
+
(0, vitest_1.expect)(savedState["status"]).toBe("running"); // POL-70 still open
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)("does not emit intermediate step-complete telemetry events on success", async () => {
|
|
128
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
129
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
130
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
131
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
132
|
+
repoRoot: tmpDir,
|
|
133
|
+
executeChild: () => { },
|
|
134
|
+
});
|
|
135
|
+
// Worker writes no telemetry on the success path — the parent emits
|
|
136
|
+
// child-complete via polaris loop continue (checkpoint cadence).
|
|
137
|
+
const raw = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
|
|
138
|
+
const lines = raw ? raw.split("\n").filter(Boolean) : [];
|
|
139
|
+
const stepCompleteEvents = lines
|
|
140
|
+
.map((l) => JSON.parse(l))
|
|
141
|
+
.filter((e) => e["event"] === "step-complete");
|
|
142
|
+
(0, vitest_1.expect)(stepCompleteEvents).toHaveLength(0);
|
|
143
|
+
});
|
|
144
|
+
(0, vitest_1.it)("returns status=failed when executeChild throws", async () => {
|
|
145
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
146
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
147
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
148
|
+
const result = await (0, worker_js_1.executeOneChild)(packet, {
|
|
149
|
+
repoRoot: tmpDir,
|
|
150
|
+
executeChild: () => {
|
|
151
|
+
throw new Error("mock child failure");
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
const errors = (0, compact_return_js_1.validateCompactReturn)(result);
|
|
155
|
+
(0, vitest_1.expect)(errors).toHaveLength(0);
|
|
156
|
+
(0, vitest_1.expect)(result.child_id).toBe("POL-69");
|
|
157
|
+
(0, vitest_1.expect)(result.status).toBe("failed");
|
|
158
|
+
(0, vitest_1.expect)(result.validation).toBe("failed");
|
|
159
|
+
(0, vitest_1.expect)(result.state_updated).toBe(false);
|
|
160
|
+
(0, vitest_1.expect)(result.next_recommended_action).toBe("investigate");
|
|
161
|
+
});
|
|
162
|
+
(0, vitest_1.it)("does not continue to the next child (single execution only)", async () => {
|
|
163
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
164
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
165
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
166
|
+
let callCount = 0;
|
|
167
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
168
|
+
repoRoot: tmpDir,
|
|
169
|
+
executeChild: () => {
|
|
170
|
+
callCount += 1;
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
// executeChild must be called exactly once — never for POL-70 or any other child
|
|
174
|
+
(0, vitest_1.expect)(callCount).toBe(1);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
178
|
+
// POL-221: worker-acknowledged event emission tests
|
|
179
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
180
|
+
(0, vitest_1.describe)("executeOneChild — worker-acknowledged event (POL-221)", () => {
|
|
181
|
+
let tmpDir;
|
|
182
|
+
(0, vitest_1.beforeEach)(() => {
|
|
183
|
+
tmpDir = makeTmpDir();
|
|
184
|
+
});
|
|
185
|
+
(0, vitest_1.afterEach)(() => {
|
|
186
|
+
try {
|
|
187
|
+
(0, node_fs_1.rmSync)(tmpDir, { recursive: true, force: true });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// ignore cleanup errors
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
(0, vitest_1.it)("emits worker-acknowledged event with dispatch_id, worker_id, packet_sha", async () => {
|
|
194
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
195
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
196
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
197
|
+
packet.dispatch_id = "dispatch-uuid-001";
|
|
198
|
+
packet.worker_id = "worker-uuid-001";
|
|
199
|
+
// Write the packet to a file so SHA can be computed
|
|
200
|
+
const packetPath = tmpDir + "/packet.json";
|
|
201
|
+
(0, node_fs_1.writeFileSync)(packetPath, JSON.stringify(packet), "utf-8");
|
|
202
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
203
|
+
repoRoot: tmpDir,
|
|
204
|
+
packetPath,
|
|
205
|
+
executeChild: () => { },
|
|
206
|
+
});
|
|
207
|
+
const raw = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
|
|
208
|
+
const events = raw.split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
209
|
+
const ackEvent = events.find((e) => e["event"] === "worker-acknowledged");
|
|
210
|
+
(0, vitest_1.expect)(ackEvent).toBeDefined();
|
|
211
|
+
(0, vitest_1.expect)(ackEvent?.["dispatch_id"]).toBe("dispatch-uuid-001");
|
|
212
|
+
(0, vitest_1.expect)(ackEvent?.["worker_id"]).toBe("worker-uuid-001");
|
|
213
|
+
(0, vitest_1.expect)(typeof ackEvent?.["packet_sha"]).toBe("string");
|
|
214
|
+
(0, vitest_1.expect)((ackEvent?.["packet_sha"]).length).toBe(64); // SHA-256 hex
|
|
215
|
+
});
|
|
216
|
+
(0, vitest_1.it)("emits worker-acknowledged before any other telemetry events", async () => {
|
|
217
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
218
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
219
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
220
|
+
packet.dispatch_id = "dispatch-uuid-002";
|
|
221
|
+
packet.worker_id = "worker-uuid-002";
|
|
222
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
223
|
+
repoRoot: tmpDir,
|
|
224
|
+
executeChild: () => { },
|
|
225
|
+
});
|
|
226
|
+
const raw = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
|
|
227
|
+
const events = raw.split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
228
|
+
(0, vitest_1.expect)(events.length).toBeGreaterThan(0);
|
|
229
|
+
(0, vitest_1.expect)(events[0]?.["event"]).toBe("worker-acknowledged");
|
|
230
|
+
});
|
|
231
|
+
(0, vitest_1.it)("emits worker-acknowledged with empty packet_sha when no packet file or raw JSON provided", async () => {
|
|
232
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
233
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
234
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
235
|
+
packet.dispatch_id = "dispatch-uuid-003";
|
|
236
|
+
packet.worker_id = "worker-uuid-003";
|
|
237
|
+
// No packetPath or packetRawJson — SHA will be empty string
|
|
238
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
239
|
+
repoRoot: tmpDir,
|
|
240
|
+
executeChild: () => { },
|
|
241
|
+
});
|
|
242
|
+
const raw = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
|
|
243
|
+
const events = raw.split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
244
|
+
const ackEvent = events.find((e) => e["event"] === "worker-acknowledged");
|
|
245
|
+
(0, vitest_1.expect)(ackEvent).toBeDefined();
|
|
246
|
+
(0, vitest_1.expect)(ackEvent?.["packet_sha"]).toBe("");
|
|
247
|
+
});
|
|
248
|
+
(0, vitest_1.it)("computes packet_sha from packetRawJson when no file path provided", async () => {
|
|
249
|
+
const stateFile = makeStateFile(tmpDir, "POL-69");
|
|
250
|
+
const telemetryFile = makeTelemetryFile(tmpDir, "test-run-001");
|
|
251
|
+
const packet = makePacket(stateFile, telemetryFile);
|
|
252
|
+
packet.dispatch_id = "dispatch-uuid-004";
|
|
253
|
+
packet.worker_id = "worker-uuid-004";
|
|
254
|
+
const rawJson = JSON.stringify(packet);
|
|
255
|
+
await (0, worker_js_1.executeOneChild)(packet, {
|
|
256
|
+
repoRoot: tmpDir,
|
|
257
|
+
packetRawJson: rawJson,
|
|
258
|
+
executeChild: () => { },
|
|
259
|
+
});
|
|
260
|
+
const raw = (0, node_fs_1.readFileSync)(telemetryFile, "utf-8").trim();
|
|
261
|
+
const events = raw.split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
262
|
+
const ackEvent = events.find((e) => e["event"] === "worker-acknowledged");
|
|
263
|
+
(0, vitest_1.expect)(ackEvent).toBeDefined();
|
|
264
|
+
(0, vitest_1.expect)(typeof ackEvent?.["packet_sha"]).toBe("string");
|
|
265
|
+
(0, vitest_1.expect)((ackEvent?.["packet_sha"]).length).toBe(64);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
(0, vitest_1.describe)("readBootstrapPacket", () => {
|
|
269
|
+
let tmpDir;
|
|
270
|
+
(0, vitest_1.beforeEach)(() => {
|
|
271
|
+
tmpDir = makeTmpDir();
|
|
272
|
+
});
|
|
273
|
+
(0, vitest_1.afterEach)(() => {
|
|
274
|
+
try {
|
|
275
|
+
(0, node_fs_1.rmSync)(tmpDir, { recursive: true, force: true });
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// ignore
|
|
279
|
+
}
|
|
280
|
+
// Restore env vars
|
|
281
|
+
delete process.env["POLARIS_BOOTSTRAP_PACKET"];
|
|
282
|
+
delete process.env["POLARIS_PACKET_FILE"];
|
|
283
|
+
delete process.env["POLARIS_PACKET_JSON"];
|
|
284
|
+
});
|
|
285
|
+
(0, vitest_1.it)("reads packet from --bootstrap CLI argument", () => {
|
|
286
|
+
const packetFile = (0, node_path_1.join)(tmpDir, "packet.json");
|
|
287
|
+
const packet = {
|
|
288
|
+
schema_version: "1.0",
|
|
289
|
+
run_id: "run-1",
|
|
290
|
+
cluster_id: "POL-99",
|
|
291
|
+
active_child: "POL-69",
|
|
292
|
+
state_file: "/tmp/state.json",
|
|
293
|
+
telemetry_file: "/tmp/telemetry.jsonl",
|
|
294
|
+
};
|
|
295
|
+
(0, node_fs_1.writeFileSync)(packetFile, JSON.stringify(packet), "utf-8");
|
|
296
|
+
const result = (0, worker_js_1.readBootstrapPacket)(["node", "worker.js", "--bootstrap", packetFile]);
|
|
297
|
+
(0, vitest_1.expect)(result.active_child).toBe("POL-69");
|
|
298
|
+
(0, vitest_1.expect)(result.run_id).toBe("run-1");
|
|
299
|
+
});
|
|
300
|
+
(0, vitest_1.it)("reads packet from POLARIS_BOOTSTRAP_PACKET env var", () => {
|
|
301
|
+
const packetFile = (0, node_path_1.join)(tmpDir, "packet.json");
|
|
302
|
+
const packet = {
|
|
303
|
+
schema_version: "1.0",
|
|
304
|
+
run_id: "run-2",
|
|
305
|
+
cluster_id: "POL-99",
|
|
306
|
+
active_child: "POL-70",
|
|
307
|
+
state_file: "/tmp/state.json",
|
|
308
|
+
telemetry_file: "/tmp/telemetry.jsonl",
|
|
309
|
+
};
|
|
310
|
+
(0, node_fs_1.writeFileSync)(packetFile, JSON.stringify(packet), "utf-8");
|
|
311
|
+
process.env["POLARIS_BOOTSTRAP_PACKET"] = packetFile;
|
|
312
|
+
const result = (0, worker_js_1.readBootstrapPacket)(["node", "worker.js"]);
|
|
313
|
+
(0, vitest_1.expect)(result.active_child).toBe("POL-70");
|
|
314
|
+
});
|
|
315
|
+
(0, vitest_1.it)("reads packet from POLARIS_PACKET_JSON env var", () => {
|
|
316
|
+
const packet = {
|
|
317
|
+
schema_version: "1.0",
|
|
318
|
+
run_id: "run-3",
|
|
319
|
+
cluster_id: "POL-99",
|
|
320
|
+
active_child: "POL-71",
|
|
321
|
+
state_file: "/tmp/state.json",
|
|
322
|
+
telemetry_file: "/tmp/telemetry.jsonl",
|
|
323
|
+
};
|
|
324
|
+
process.env["POLARIS_PACKET_JSON"] = JSON.stringify(packet);
|
|
325
|
+
const result = (0, worker_js_1.readBootstrapPacket)(["node", "worker.js"]);
|
|
326
|
+
(0, vitest_1.expect)(result.active_child).toBe("POL-71");
|
|
327
|
+
});
|
|
328
|
+
(0, vitest_1.it)("throws when no packet source is available", () => {
|
|
329
|
+
(0, vitest_1.expect)(() => (0, worker_js_1.readBootstrapPacket)(["node", "worker.js"])).toThrow(/No bootstrap packet found/);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
(0, vitest_1.describe)("validateCompactReturn", () => {
|
|
333
|
+
(0, vitest_1.it)("accepts a valid CompactReturn", () => {
|
|
334
|
+
const valid = {
|
|
335
|
+
child_id: "POL-69",
|
|
336
|
+
status: "done",
|
|
337
|
+
commit: "abc1234",
|
|
338
|
+
validation: "passed",
|
|
339
|
+
tracker_updated: false,
|
|
340
|
+
state_updated: true,
|
|
341
|
+
telemetry_updated: true,
|
|
342
|
+
next_recommended_action: "continue",
|
|
343
|
+
};
|
|
344
|
+
(0, vitest_1.expect)((0, compact_return_js_1.validateCompactReturn)(valid)).toHaveLength(0);
|
|
345
|
+
});
|
|
346
|
+
(0, vitest_1.it)("rejects missing child_id", () => {
|
|
347
|
+
const invalid = {
|
|
348
|
+
child_id: "",
|
|
349
|
+
status: "done",
|
|
350
|
+
commit: null,
|
|
351
|
+
validation: "passed",
|
|
352
|
+
tracker_updated: false,
|
|
353
|
+
state_updated: true,
|
|
354
|
+
telemetry_updated: true,
|
|
355
|
+
next_recommended_action: "continue",
|
|
356
|
+
};
|
|
357
|
+
(0, vitest_1.expect)((0, compact_return_js_1.validateCompactReturn)(invalid).length).toBeGreaterThan(0);
|
|
358
|
+
});
|
|
359
|
+
(0, vitest_1.it)("rejects invalid status value", () => {
|
|
360
|
+
const invalid = {
|
|
361
|
+
child_id: "POL-69",
|
|
362
|
+
status: "unknown",
|
|
363
|
+
commit: null,
|
|
364
|
+
validation: "passed",
|
|
365
|
+
tracker_updated: false,
|
|
366
|
+
state_updated: true,
|
|
367
|
+
telemetry_updated: true,
|
|
368
|
+
next_recommended_action: "continue",
|
|
369
|
+
};
|
|
370
|
+
(0, vitest_1.expect)((0, compact_return_js_1.validateCompactReturn)(invalid).length).toBeGreaterThan(0);
|
|
371
|
+
});
|
|
372
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VALID_ROLE_OWNERS = void 0;
|
|
4
|
+
exports.resolveInstructionFile = resolveInstructionFile;
|
|
5
|
+
exports.computeInstructionCoverage = computeInstructionCoverage;
|
|
6
|
+
exports.readFileRoutes = readFileRoutes;
|
|
7
|
+
exports.writeFileRoutes = writeFileRoutes;
|
|
8
|
+
exports.readNeedsReview = readNeedsReview;
|
|
9
|
+
exports.writeNeedsReview = writeNeedsReview;
|
|
10
|
+
exports.readExemptions = readExemptions;
|
|
11
|
+
exports.writeExemptions = writeExemptions;
|
|
12
|
+
exports.writeAtlasIndex = writeAtlasIndex;
|
|
13
|
+
const node_fs_1 = require("node:fs");
|
|
14
|
+
const node_path_1 = require("node:path");
|
|
15
|
+
exports.VALID_ROLE_OWNERS = ["worker", "foreman", "analyst", "librarian", "any"];
|
|
16
|
+
function resolveInstructionFile(filePath, repoRoot) {
|
|
17
|
+
const parts = filePath.split("/");
|
|
18
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
19
|
+
const dir = parts.slice(0, i).join("/");
|
|
20
|
+
const candidate = dir ? `${dir}/POLARIS.md` : "POLARIS.md";
|
|
21
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, candidate))) {
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
function computeInstructionCoverage(entries) {
|
|
28
|
+
const routesTotal = Object.keys(entries).length;
|
|
29
|
+
const routesCovered = Object.values(entries).filter((e) => e.instructionFile !== undefined).length;
|
|
30
|
+
return {
|
|
31
|
+
routesCovered,
|
|
32
|
+
routesTotal,
|
|
33
|
+
coveragePercent: routesTotal > 0 ? Math.round((routesCovered / routesTotal) * 100) : 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function ensureDir(filePath) {
|
|
37
|
+
const dir = (0, node_path_1.dirname)(filePath);
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(dir)) {
|
|
39
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function readJson(filePath, fallback) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse((0, node_fs_1.readFileSync)(filePath, "utf-8"));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function writeJson(filePath, data) {
|
|
54
|
+
ensureDir(filePath);
|
|
55
|
+
(0, node_fs_1.writeFileSync)(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
56
|
+
}
|
|
57
|
+
function readFileRoutes(outputPath) {
|
|
58
|
+
return readJson((0, node_path_1.resolve)(outputPath, "file-routes.json"), {});
|
|
59
|
+
}
|
|
60
|
+
function writeFileRoutes(outputPath, routes) {
|
|
61
|
+
writeJson((0, node_path_1.resolve)(outputPath, "file-routes.json"), routes);
|
|
62
|
+
}
|
|
63
|
+
function readNeedsReview(outputPath) {
|
|
64
|
+
return readJson((0, node_path_1.resolve)(outputPath, "needs-review.json"), {});
|
|
65
|
+
}
|
|
66
|
+
function writeNeedsReview(outputPath, entries) {
|
|
67
|
+
writeJson((0, node_path_1.resolve)(outputPath, "needs-review.json"), entries);
|
|
68
|
+
}
|
|
69
|
+
function readExemptions(outputPath) {
|
|
70
|
+
return readJson((0, node_path_1.resolve)(outputPath, "exemptions.json"), {});
|
|
71
|
+
}
|
|
72
|
+
function writeExemptions(outputPath, entries) {
|
|
73
|
+
writeJson((0, node_path_1.resolve)(outputPath, "exemptions.json"), entries);
|
|
74
|
+
}
|
|
75
|
+
function writeAtlasIndex(outputPath, index) {
|
|
76
|
+
writeJson((0, node_path_1.resolve)(outputPath, "index.json"), index);
|
|
77
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runMapBackfill = runMapBackfill;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const node_child_process_1 = require("node:child_process");
|
|
7
|
+
const loader_js_1 = require("../config/loader.js");
|
|
8
|
+
const parser_js_1 = require("../ignore/parser.js");
|
|
9
|
+
const defaults_js_1 = require("../ignore/defaults.js");
|
|
10
|
+
const inference_js_1 = require("./inference.js");
|
|
11
|
+
const atlas_js_1 = require("./atlas.js");
|
|
12
|
+
const SECRET_REGEXES = defaults_js_1.SECRET_PATTERNS.map((p) => new RegExp("^" + p.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"));
|
|
13
|
+
function isSecretFile(filePath) {
|
|
14
|
+
const parts = filePath.split("/");
|
|
15
|
+
const base = parts[parts.length - 1];
|
|
16
|
+
return SECRET_REGEXES.some((re) => re.test(base) || re.test(filePath));
|
|
17
|
+
}
|
|
18
|
+
function* walkDir(dir, root, ig) {
|
|
19
|
+
if (!(0, node_fs_1.existsSync)(dir))
|
|
20
|
+
return;
|
|
21
|
+
for (const entry of (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })) {
|
|
22
|
+
const full = (0, node_path_1.join)(dir, entry.name);
|
|
23
|
+
const rel = (0, node_path_1.relative)(root, full).replace(/\\/g, "/");
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
if (ig?.ignores(rel + "/"))
|
|
26
|
+
continue;
|
|
27
|
+
yield* walkDir(full, root, ig);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
yield rel;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function loadIgnoreFilter(repoRoot) {
|
|
35
|
+
let userPatterns = [];
|
|
36
|
+
try {
|
|
37
|
+
const raw = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(repoRoot, ".polarisignore"), "utf-8");
|
|
38
|
+
userPatterns = raw.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("#"));
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (typeof err === "object" && err !== null && "code" in err && err.code !== "ENOENT") {
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return (0, parser_js_1.parsePolarisIgnore)(userPatterns);
|
|
46
|
+
}
|
|
47
|
+
function getBranchName(repoRoot) {
|
|
48
|
+
try {
|
|
49
|
+
return (0, node_child_process_1.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
50
|
+
cwd: repoRoot,
|
|
51
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
52
|
+
}).toString().trim();
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function runMapBackfill(repoRoot, dryRun, domainFilter, verbose) {
|
|
59
|
+
const config = (0, loader_js_1.loadConfig)(repoRoot);
|
|
60
|
+
const outputPath = (0, node_path_1.resolve)(repoRoot, config.repo.sidecarOutputPath ?? ".polaris/map");
|
|
61
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.resolve)(outputPath, "file-routes.json"))) {
|
|
62
|
+
console.error("atlas not initialized — run `polaris map index` first");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
const routes = (0, atlas_js_1.readFileRoutes)(outputPath);
|
|
66
|
+
const needsReview = (0, atlas_js_1.readNeedsReview)(outputPath);
|
|
67
|
+
const exemptions = (0, atlas_js_1.readExemptions)(outputPath);
|
|
68
|
+
const ig = loadIgnoreFilter(repoRoot);
|
|
69
|
+
const branchName = getBranchName(repoRoot);
|
|
70
|
+
const autoWriteAbove = config.map.autoWriteAbove ?? 0.85;
|
|
71
|
+
const now = new Date().toISOString();
|
|
72
|
+
const newRoutes = { ...routes };
|
|
73
|
+
const newNeedsReview = { ...needsReview };
|
|
74
|
+
let added = 0;
|
|
75
|
+
let queued = 0;
|
|
76
|
+
let skippedSecret = 0;
|
|
77
|
+
let skippedAlreadyMapped = 0;
|
|
78
|
+
let skippedExempted = 0;
|
|
79
|
+
let skippedIgnored = 0;
|
|
80
|
+
const scanRoots = [
|
|
81
|
+
...(config.repo.sourceRoots ?? ["src"]),
|
|
82
|
+
...(config.repo.docsRoots ?? []),
|
|
83
|
+
];
|
|
84
|
+
const processedFiles = new Set();
|
|
85
|
+
for (const scanRoot of scanRoots) {
|
|
86
|
+
const scanDir = (0, node_path_1.resolve)(repoRoot, scanRoot);
|
|
87
|
+
for (const filePath of walkDir(scanDir, repoRoot, ig)) {
|
|
88
|
+
// Apply --domain filter: only process files under sourceRoot/domain/
|
|
89
|
+
if (domainFilter !== undefined) {
|
|
90
|
+
const domainPrefix = `${scanRoot}/${domainFilter}/`;
|
|
91
|
+
if (!filePath.startsWith(domainPrefix))
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (processedFiles.has(filePath))
|
|
95
|
+
continue;
|
|
96
|
+
processedFiles.add(filePath);
|
|
97
|
+
// Security check — never process secret files
|
|
98
|
+
if (isSecretFile(filePath)) {
|
|
99
|
+
console.log(` [HIGH] secret file skipped: ${filePath}`);
|
|
100
|
+
skippedSecret++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
// Skip if already mapped (never overwrite)
|
|
104
|
+
if (routes[filePath] || needsReview[filePath]) {
|
|
105
|
+
skippedAlreadyMapped++;
|
|
106
|
+
if (verbose)
|
|
107
|
+
console.log(` skip (already mapped): ${filePath}`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Skip if exempted
|
|
111
|
+
if (exemptions[filePath]) {
|
|
112
|
+
skippedExempted++;
|
|
113
|
+
if (verbose)
|
|
114
|
+
console.log(` skip (exempted): ${filePath}`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Skip if ignored
|
|
118
|
+
if (ig.ignores(filePath)) {
|
|
119
|
+
skippedIgnored++;
|
|
120
|
+
if (verbose)
|
|
121
|
+
console.log(` skip (ignored): ${filePath}`);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Run inference on unmapped file
|
|
125
|
+
const inferred = (0, inference_js_1.inferRoute)(filePath, repoRoot, config, routes, branchName);
|
|
126
|
+
const instructionFile = (0, atlas_js_1.resolveInstructionFile)(filePath, repoRoot);
|
|
127
|
+
const entry = {
|
|
128
|
+
domain: inferred.domain,
|
|
129
|
+
route: inferred.route,
|
|
130
|
+
taskchain: inferred.taskchain,
|
|
131
|
+
confidence: inferred.confidence,
|
|
132
|
+
classification: inferred.confidence >= autoWriteAbove ? "indexed" : "needs-review",
|
|
133
|
+
last_updated: now,
|
|
134
|
+
updated_by: "polaris-map-backfill",
|
|
135
|
+
tags: inferred.tags,
|
|
136
|
+
...(instructionFile && { instructionFile }),
|
|
137
|
+
};
|
|
138
|
+
if (inferred.confidence >= autoWriteAbove) {
|
|
139
|
+
newRoutes[filePath] = entry;
|
|
140
|
+
added++;
|
|
141
|
+
if (verbose)
|
|
142
|
+
console.log(` add (${inferred.confidence.toFixed(2)}): ${filePath}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
newNeedsReview[filePath] = entry;
|
|
146
|
+
queued++;
|
|
147
|
+
if (verbose)
|
|
148
|
+
console.log(` queue (${inferred.confidence.toFixed(2)}): ${filePath}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const total = added + queued;
|
|
153
|
+
if (!dryRun && total > 0) {
|
|
154
|
+
(0, atlas_js_1.writeFileRoutes)(outputPath, newRoutes);
|
|
155
|
+
(0, atlas_js_1.writeNeedsReview)(outputPath, newNeedsReview);
|
|
156
|
+
const allEntries = { ...newRoutes, ...newNeedsReview };
|
|
157
|
+
const totalEntries = Object.keys(allEntries).length;
|
|
158
|
+
const indexedCount = Object.values(allEntries).filter((e) => e.classification === "indexed").length;
|
|
159
|
+
(0, atlas_js_1.writeAtlasIndex)(outputPath, {
|
|
160
|
+
scan_date: now,
|
|
161
|
+
file_count: totalEntries,
|
|
162
|
+
coverage_pct: totalEntries > 0 ? Math.round((indexedCount / totalEntries) * 100) : 0,
|
|
163
|
+
instructionCoverage: (0, atlas_js_1.computeInstructionCoverage)(allEntries),
|
|
164
|
+
entries: allEntries,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const skipped = skippedSecret + skippedAlreadyMapped + skippedExempted + skippedIgnored;
|
|
168
|
+
console.log(`Backfilled ${total} files. Added ${added}. Queued ${queued} for review. Skipped ${skipped} (secret: ${skippedSecret}, already mapped: ${skippedAlreadyMapped}, exempted: ${skippedExempted}, ignored: ${skippedIgnored}).`);
|
|
169
|
+
if (dryRun)
|
|
170
|
+
console.log("(dry-run: no files written)");
|
|
171
|
+
}
|