@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,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SpecAdapter = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const local_graph_js_1 = require("../../local-graph.js");
|
|
7
|
+
const schema_js_1 = require("../../schema.js");
|
|
8
|
+
const SECTION_HEADERS = {
|
|
9
|
+
objective: new Set(["objective"]),
|
|
10
|
+
scope: new Set(["scope", "expected code areas", "code areas", "files to change", "files"]),
|
|
11
|
+
validation: new Set(["validation", "validation commands", "test commands", "verify"]),
|
|
12
|
+
children: new Set(["children"]),
|
|
13
|
+
};
|
|
14
|
+
function slugifySegment(value) {
|
|
15
|
+
return value
|
|
16
|
+
.trim()
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
19
|
+
.replace(/^-+|-+$/g, "");
|
|
20
|
+
}
|
|
21
|
+
function parseSections(markdown) {
|
|
22
|
+
const sections = new Map();
|
|
23
|
+
const parts = markdown.split(/^##\s+/m);
|
|
24
|
+
for (const part of parts) {
|
|
25
|
+
const lineBreak = part.indexOf("\n");
|
|
26
|
+
if (lineBreak === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const header = part.slice(0, lineBreak).trim().toLowerCase();
|
|
29
|
+
const content = part.slice(lineBreak + 1);
|
|
30
|
+
sections.set(header, content);
|
|
31
|
+
}
|
|
32
|
+
return sections;
|
|
33
|
+
}
|
|
34
|
+
function parseList(content) {
|
|
35
|
+
return content
|
|
36
|
+
.split("\n")
|
|
37
|
+
.filter((line) => /^\s*[-*]\s+/.test(line))
|
|
38
|
+
.map((line) => line.replace(/^\s*[-*]\s+/, "").trim())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
function readSectionText(sections, headers) {
|
|
42
|
+
for (const [header, content] of sections) {
|
|
43
|
+
if (headers.has(header)) {
|
|
44
|
+
return content.trim();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
function readSectionList(sections, headers) {
|
|
50
|
+
for (const [header, content] of sections) {
|
|
51
|
+
if (headers.has(header)) {
|
|
52
|
+
return parseList(content);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
function toChildId(index) {
|
|
58
|
+
return `spec-child-${String(index).padStart(2, "0")}`;
|
|
59
|
+
}
|
|
60
|
+
function createChildBody(title, scope, validation) {
|
|
61
|
+
const lines = [
|
|
62
|
+
"## Objective",
|
|
63
|
+
title,
|
|
64
|
+
"",
|
|
65
|
+
];
|
|
66
|
+
if (scope.length > 0) {
|
|
67
|
+
lines.push("## Scope");
|
|
68
|
+
for (const scopeEntry of scope) {
|
|
69
|
+
lines.push(`- ${scopeEntry}`);
|
|
70
|
+
}
|
|
71
|
+
lines.push("");
|
|
72
|
+
}
|
|
73
|
+
if (validation.length > 0) {
|
|
74
|
+
lines.push("## Validation");
|
|
75
|
+
for (const command of validation) {
|
|
76
|
+
lines.push(`- ${command}`);
|
|
77
|
+
}
|
|
78
|
+
lines.push("");
|
|
79
|
+
}
|
|
80
|
+
return lines.join("\n").trim();
|
|
81
|
+
}
|
|
82
|
+
class SpecAdapter {
|
|
83
|
+
async syncIn(specPath) {
|
|
84
|
+
const raw = await (0, promises_1.readFile)(specPath, "utf-8");
|
|
85
|
+
const sections = parseSections(raw);
|
|
86
|
+
const objective = readSectionText(sections, SECTION_HEADERS.objective);
|
|
87
|
+
const scope = readSectionList(sections, SECTION_HEADERS.scope);
|
|
88
|
+
const validation = readSectionList(sections, SECTION_HEADERS.validation);
|
|
89
|
+
const childTitles = readSectionList(sections, SECTION_HEADERS.children);
|
|
90
|
+
if (!objective) {
|
|
91
|
+
throw new Error("Spec file is missing required section: ## Objective");
|
|
92
|
+
}
|
|
93
|
+
if (childTitles.length === 0) {
|
|
94
|
+
throw new Error("Spec file is missing required section content: ## Children");
|
|
95
|
+
}
|
|
96
|
+
const baseName = (0, node_path_1.basename)(specPath, (0, node_path_1.extname)(specPath));
|
|
97
|
+
const clusterSlug = slugifySegment(baseName) || "cluster";
|
|
98
|
+
const clusterId = `spec-${clusterSlug}`;
|
|
99
|
+
const rootNodeId = clusterId;
|
|
100
|
+
const nodes = {};
|
|
101
|
+
const dependencies = {};
|
|
102
|
+
const children = [];
|
|
103
|
+
nodes[rootNodeId] = {
|
|
104
|
+
id: rootNodeId,
|
|
105
|
+
title: objective,
|
|
106
|
+
status: "Todo",
|
|
107
|
+
body: raw.trim(),
|
|
108
|
+
};
|
|
109
|
+
for (const [index, childTitle] of childTitles.entries()) {
|
|
110
|
+
const childId = toChildId(index + 1);
|
|
111
|
+
children.push(childId);
|
|
112
|
+
nodes[childId] = {
|
|
113
|
+
id: childId,
|
|
114
|
+
title: childTitle,
|
|
115
|
+
status: "Todo",
|
|
116
|
+
sessionType: "implement",
|
|
117
|
+
body: createChildBody(childTitle, scope, validation),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const cluster = {
|
|
121
|
+
id: clusterId,
|
|
122
|
+
title: objective,
|
|
123
|
+
cluster_root: rootNodeId,
|
|
124
|
+
children,
|
|
125
|
+
};
|
|
126
|
+
const graph = schema_js_1.executionGraphV2Schema.parse({
|
|
127
|
+
schemaVersion: "v2",
|
|
128
|
+
source: {
|
|
129
|
+
id: specPath,
|
|
130
|
+
type: "spec",
|
|
131
|
+
analysis: {
|
|
132
|
+
id: "spec-sync",
|
|
133
|
+
doc: objective,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
nodes,
|
|
137
|
+
dependencies,
|
|
138
|
+
clusters: {
|
|
139
|
+
[clusterId]: cluster,
|
|
140
|
+
},
|
|
141
|
+
activeCluster: clusterId,
|
|
142
|
+
});
|
|
143
|
+
return local_graph_js_1.LocalGraph.fromGraph(graph);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.SpecAdapter = SpecAdapter;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalFileAdapter = exports.LinearAdapter = exports.validateLifecyclePolicy = exports.getDefaultLifecyclePolicy = exports.resolveLifecycleTransition = void 0;
|
|
4
|
+
exports.loadTrackerGraph = loadTrackerGraph;
|
|
5
|
+
exports.loadTrackerAdapter = loadTrackerAdapter;
|
|
6
|
+
const local_graph_js_1 = require("./local-graph.js");
|
|
7
|
+
const index_js_1 = require("./adapters/linear/index.js");
|
|
8
|
+
Object.defineProperty(exports, "LinearAdapter", { enumerable: true, get: function () { return index_js_1.LinearAdapter; } });
|
|
9
|
+
const index_js_2 = require("./adapters/local-file/index.js");
|
|
10
|
+
Object.defineProperty(exports, "LocalFileAdapter", { enumerable: true, get: function () { return index_js_2.LocalFileAdapter; } });
|
|
11
|
+
var lifecycle_policy_js_1 = require("./lifecycle-policy.js");
|
|
12
|
+
Object.defineProperty(exports, "resolveLifecycleTransition", { enumerable: true, get: function () { return lifecycle_policy_js_1.resolveLifecycleTransition; } });
|
|
13
|
+
Object.defineProperty(exports, "getDefaultLifecyclePolicy", { enumerable: true, get: function () { return lifecycle_policy_js_1.getDefaultLifecyclePolicy; } });
|
|
14
|
+
Object.defineProperty(exports, "validateLifecyclePolicy", { enumerable: true, get: function () { return lifecycle_policy_js_1.validateLifecyclePolicy; } });
|
|
15
|
+
/**
|
|
16
|
+
* Loads the execution graph from the configured tracker.
|
|
17
|
+
*
|
|
18
|
+
* @param config The Polaris configuration.
|
|
19
|
+
* @param clusterId The ID of the cluster to load.
|
|
20
|
+
* @returns A promise that resolves to a graph instance, or null if no tracker is enabled.
|
|
21
|
+
*/
|
|
22
|
+
async function loadTrackerGraph(config, clusterId) {
|
|
23
|
+
if (config.tracker?.["local-file"]?.enabled) {
|
|
24
|
+
return local_graph_js_1.LocalGraph.load(clusterId);
|
|
25
|
+
}
|
|
26
|
+
if (config.tracker?.linear?.enabled) {
|
|
27
|
+
const linearAdapter = new index_js_1.LinearAdapter(config);
|
|
28
|
+
return linearAdapter.syncIn(clusterId);
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Loads a tracker adapter instance based on the configuration.
|
|
34
|
+
*
|
|
35
|
+
* @param config The Polaris configuration.
|
|
36
|
+
* @returns A capable tracker adapter instance, or null if no tracker is configured.
|
|
37
|
+
*/
|
|
38
|
+
function loadTrackerAdapter(config) {
|
|
39
|
+
const adapterType = config.tracker?.adapter;
|
|
40
|
+
if (adapterType === "linear" && config.tracker?.linear?.enabled) {
|
|
41
|
+
return new index_js_1.LinearAdapter(config);
|
|
42
|
+
}
|
|
43
|
+
if (adapterType === "local" && config.tracker?.["local-file"]?.enabled) {
|
|
44
|
+
return new index_js_2.LocalFileAdapter();
|
|
45
|
+
}
|
|
46
|
+
// For "mcp-bridge" or other adapters, return null for now
|
|
47
|
+
// They can be added when their CapableTrackerAdapter implementations are ready
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveLifecycleTransition = resolveLifecycleTransition;
|
|
4
|
+
exports.getDefaultLifecyclePolicy = getDefaultLifecyclePolicy;
|
|
5
|
+
exports.validateLifecyclePolicy = validateLifecyclePolicy;
|
|
6
|
+
/**
|
|
7
|
+
* Resolves lifecycle transitions based on policy configuration.
|
|
8
|
+
*
|
|
9
|
+
* This resolver provides tracker-agnostic lifecycle semantics by mapping
|
|
10
|
+
* Polaris execution events to normalized lifecycle states defined in config.
|
|
11
|
+
* Individual tracker adapters then map these normalized states to their
|
|
12
|
+
* native status names or return unsupported-transition results.
|
|
13
|
+
*
|
|
14
|
+
* @param event - The lifecycle transition event to resolve.
|
|
15
|
+
* @param policy - The tracker lifecycle policy from config.
|
|
16
|
+
* @returns A transition result with target state, skip behavior, and evidence requirements.
|
|
17
|
+
*/
|
|
18
|
+
function resolveLifecycleTransition(event, policy) {
|
|
19
|
+
const effectivePolicy = policy || getDefaultLifecyclePolicy();
|
|
20
|
+
switch (event) {
|
|
21
|
+
case "child-dispatch":
|
|
22
|
+
return {
|
|
23
|
+
targetState: effectivePolicy.childOnDispatch || "in_progress",
|
|
24
|
+
skip: false,
|
|
25
|
+
evidenceRequirements: [],
|
|
26
|
+
};
|
|
27
|
+
case "child-validation-passed":
|
|
28
|
+
return {
|
|
29
|
+
targetState: effectivePolicy.childOnValidationPassed || "in_review",
|
|
30
|
+
skip: false,
|
|
31
|
+
evidenceRequirements: ["validation_results", "worker_commit"],
|
|
32
|
+
};
|
|
33
|
+
case "child-merged":
|
|
34
|
+
return {
|
|
35
|
+
targetState: effectivePolicy.childOnMerged || "done",
|
|
36
|
+
skip: false,
|
|
37
|
+
evidenceRequirements: ["merge_commit_hash"],
|
|
38
|
+
};
|
|
39
|
+
case "parent-all-children-complete":
|
|
40
|
+
return {
|
|
41
|
+
targetState: effectivePolicy.parentOnAllChildrenComplete || "in_review",
|
|
42
|
+
skip: false,
|
|
43
|
+
evidenceRequirements: ["completed_children_summary"],
|
|
44
|
+
};
|
|
45
|
+
case "parent-delivery-merged":
|
|
46
|
+
return {
|
|
47
|
+
targetState: effectivePolicy.parentOnDeliveryMerged || "done",
|
|
48
|
+
skip: false,
|
|
49
|
+
evidenceRequirements: ["delivery_merge_commit_hash"],
|
|
50
|
+
};
|
|
51
|
+
case "child-triage-required":
|
|
52
|
+
return {
|
|
53
|
+
targetState: effectivePolicy.childOnTriageRequired || "blocked",
|
|
54
|
+
skip: false,
|
|
55
|
+
evidenceRequirements: ["triage_reason", "failure_details"],
|
|
56
|
+
};
|
|
57
|
+
case "provider-failure-before-work":
|
|
58
|
+
return {
|
|
59
|
+
targetState: effectivePolicy.providerFailureBeforeWork || "no_status_change",
|
|
60
|
+
skip: effectivePolicy.providerFailureBeforeWork === "no_status_change",
|
|
61
|
+
skipReason: effectivePolicy.providerFailureBeforeWork === "no_status_change"
|
|
62
|
+
? "Provider failure before repo work does not change implementation status"
|
|
63
|
+
: undefined,
|
|
64
|
+
evidenceRequirements: ["failure_error", "provider_context"],
|
|
65
|
+
};
|
|
66
|
+
default:
|
|
67
|
+
// Unknown event - treat as no-op
|
|
68
|
+
return {
|
|
69
|
+
targetState: "no_status_change",
|
|
70
|
+
skip: true,
|
|
71
|
+
skipReason: `Unknown lifecycle event: ${event}`,
|
|
72
|
+
evidenceRequirements: [],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the default lifecycle policy with review-gated behavior.
|
|
78
|
+
*
|
|
79
|
+
* Defaults preserve current behavior:
|
|
80
|
+
* - Validation-passed transitions to in_review (review-gated)
|
|
81
|
+
* - Parent completion transitions to in_review (review-gated)
|
|
82
|
+
* - Provider failures before work do not change status (avoid false failures)
|
|
83
|
+
*/
|
|
84
|
+
function getDefaultLifecyclePolicy() {
|
|
85
|
+
return {
|
|
86
|
+
childOnDispatch: "in_progress",
|
|
87
|
+
childOnValidationPassed: "in_review",
|
|
88
|
+
childOnMerged: "done",
|
|
89
|
+
parentOnAllChildrenComplete: "in_review",
|
|
90
|
+
parentOnDeliveryMerged: "done",
|
|
91
|
+
childOnTriageRequired: "blocked",
|
|
92
|
+
providerFailureBeforeWork: "no_status_change",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validates a lifecycle policy value.
|
|
97
|
+
*
|
|
98
|
+
* @param policy - The policy to validate.
|
|
99
|
+
* @returns Validation result with errors if invalid.
|
|
100
|
+
*/
|
|
101
|
+
function validateLifecyclePolicy(policy) {
|
|
102
|
+
const errors = [];
|
|
103
|
+
if (!policy || typeof policy !== "object") {
|
|
104
|
+
return { valid: false, errors: ["Lifecycle policy must be an object"] };
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(policy)) {
|
|
107
|
+
return { valid: false, errors: ["Lifecycle policy must be a plain object"] };
|
|
108
|
+
}
|
|
109
|
+
if (Object.getPrototypeOf(policy) !== Object.prototype) {
|
|
110
|
+
return { valid: false, errors: ["Lifecycle policy must be a plain object"] };
|
|
111
|
+
}
|
|
112
|
+
const validStates = [
|
|
113
|
+
"backlog",
|
|
114
|
+
"in_progress",
|
|
115
|
+
"in_review",
|
|
116
|
+
"done",
|
|
117
|
+
"blocked",
|
|
118
|
+
"cancelled",
|
|
119
|
+
"no_status_change",
|
|
120
|
+
];
|
|
121
|
+
const policyObj = policy;
|
|
122
|
+
const validateField = (fieldName, value) => {
|
|
123
|
+
if (value !== undefined && typeof value !== "string") {
|
|
124
|
+
errors.push(`tracker.lifecyclePolicy.${fieldName} must be a string`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (value !== undefined && !validStates.includes(value)) {
|
|
128
|
+
errors.push(`tracker.lifecyclePolicy.${fieldName} must be one of: ${validStates.join(", ")}`);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
validateField("childOnDispatch", policyObj.childOnDispatch);
|
|
132
|
+
validateField("childOnValidationPassed", policyObj.childOnValidationPassed);
|
|
133
|
+
validateField("childOnMerged", policyObj.childOnMerged);
|
|
134
|
+
validateField("parentOnAllChildrenComplete", policyObj.parentOnAllChildrenComplete);
|
|
135
|
+
validateField("parentOnDeliveryMerged", policyObj.parentOnDeliveryMerged);
|
|
136
|
+
validateField("childOnTriageRequired", policyObj.childOnTriageRequired);
|
|
137
|
+
validateField("providerFailureBeforeWork", policyObj.providerFailureBeforeWork);
|
|
138
|
+
return { valid: errors.length === 0, errors };
|
|
139
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LifecycleTransitionService = void 0;
|
|
4
|
+
const lifecycle_policy_js_1 = require("./lifecycle-policy.js");
|
|
5
|
+
/**
|
|
6
|
+
* Service for applying tracker lifecycle transitions with policy and capability awareness.
|
|
7
|
+
*
|
|
8
|
+
* This service integrates the lifecycle policy resolver with tracker adapter capabilities
|
|
9
|
+
* to ensure transitions are:
|
|
10
|
+
* - Policy-backed: transitions follow the configured lifecycle policy
|
|
11
|
+
* - Idempotent: skipped if the target state is already reached or unsupported
|
|
12
|
+
* - Evidence-backed: requires evidence for validation-passed and merged transitions
|
|
13
|
+
* - Safe: provider/runtime failures before work do not mark implementation failures by default
|
|
14
|
+
*/
|
|
15
|
+
class LifecycleTransitionService {
|
|
16
|
+
/**
|
|
17
|
+
* Applies a lifecycle transition using the provided adapter and policy.
|
|
18
|
+
*
|
|
19
|
+
* @param options - The transition options.
|
|
20
|
+
* @returns A transition attempt result.
|
|
21
|
+
*/
|
|
22
|
+
async applyTransition(options) {
|
|
23
|
+
const { adapter, policy, taskId, event, evidence, timestamp } = options;
|
|
24
|
+
const effectiveTimestamp = timestamp ?? new Date().toISOString();
|
|
25
|
+
// Resolve the transition from policy
|
|
26
|
+
const policyResult = (0, lifecycle_policy_js_1.resolveLifecycleTransition)(event, policy);
|
|
27
|
+
// If policy says skip, return immediately
|
|
28
|
+
if (policyResult.skip) {
|
|
29
|
+
return {
|
|
30
|
+
event,
|
|
31
|
+
targetState: policyResult.targetState,
|
|
32
|
+
applied: false,
|
|
33
|
+
skipped: true,
|
|
34
|
+
skipReason: policyResult.skipReason,
|
|
35
|
+
evidence,
|
|
36
|
+
timestamp: effectiveTimestamp,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// If no adapter is configured, skip with reason
|
|
40
|
+
if (!adapter) {
|
|
41
|
+
return {
|
|
42
|
+
event,
|
|
43
|
+
targetState: policyResult.targetState,
|
|
44
|
+
applied: false,
|
|
45
|
+
skipped: true,
|
|
46
|
+
skipReason: "No tracker adapter configured",
|
|
47
|
+
evidence,
|
|
48
|
+
timestamp: effectiveTimestamp,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Check if adapter supports lifecycle mapping
|
|
52
|
+
const capabilities = adapter.getCapabilities();
|
|
53
|
+
if (!capabilities.supportsLifecycleMapping) {
|
|
54
|
+
return {
|
|
55
|
+
event,
|
|
56
|
+
targetState: policyResult.targetState,
|
|
57
|
+
applied: false,
|
|
58
|
+
skipped: true,
|
|
59
|
+
skipReason: "Tracker adapter does not support lifecycle mapping",
|
|
60
|
+
evidence,
|
|
61
|
+
timestamp: effectiveTimestamp,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Check if target state is no_status_change
|
|
65
|
+
if (policyResult.targetState === "no_status_change") {
|
|
66
|
+
return {
|
|
67
|
+
event,
|
|
68
|
+
targetState: policyResult.targetState,
|
|
69
|
+
applied: false,
|
|
70
|
+
skipped: true,
|
|
71
|
+
skipReason: "Policy specifies no status change for this event",
|
|
72
|
+
evidence,
|
|
73
|
+
timestamp: effectiveTimestamp,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Build evidence record for the adapter
|
|
77
|
+
const adapterEvidence = {};
|
|
78
|
+
if (evidence?.commit)
|
|
79
|
+
adapterEvidence.commit = evidence.commit;
|
|
80
|
+
if (evidence?.resultFile)
|
|
81
|
+
adapterEvidence.resultFile = evidence.resultFile;
|
|
82
|
+
if (evidence?.packetFile)
|
|
83
|
+
adapterEvidence.packetFile = evidence.packetFile;
|
|
84
|
+
if (evidence?.validationResults)
|
|
85
|
+
adapterEvidence.validationResults = evidence.validationResults;
|
|
86
|
+
if (evidence?.error)
|
|
87
|
+
adapterEvidence.error = evidence.error;
|
|
88
|
+
if (evidence?.providerContext)
|
|
89
|
+
adapterEvidence.providerContext = evidence.providerContext;
|
|
90
|
+
// Attempt the transition through the adapter
|
|
91
|
+
try {
|
|
92
|
+
const adapterResult = await adapter.transitionLifecycleState(taskId, policyResult.targetState, adapterEvidence);
|
|
93
|
+
if (adapterResult.skipped) {
|
|
94
|
+
return {
|
|
95
|
+
event,
|
|
96
|
+
targetState: policyResult.targetState,
|
|
97
|
+
applied: false,
|
|
98
|
+
skipped: true,
|
|
99
|
+
skipReason: adapterResult.skipReason ?? "Adapter skipped the transition",
|
|
100
|
+
evidence,
|
|
101
|
+
timestamp: effectiveTimestamp,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (adapterResult.error) {
|
|
105
|
+
return {
|
|
106
|
+
event,
|
|
107
|
+
targetState: policyResult.targetState,
|
|
108
|
+
applied: false,
|
|
109
|
+
skipped: false,
|
|
110
|
+
error: adapterResult.error,
|
|
111
|
+
evidence,
|
|
112
|
+
timestamp: effectiveTimestamp,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
event,
|
|
117
|
+
targetState: policyResult.targetState,
|
|
118
|
+
applied: adapterResult.applied,
|
|
119
|
+
skipped: false,
|
|
120
|
+
evidence,
|
|
121
|
+
timestamp: effectiveTimestamp,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
126
|
+
return {
|
|
127
|
+
event,
|
|
128
|
+
targetState: policyResult.targetState,
|
|
129
|
+
applied: false,
|
|
130
|
+
skipped: false,
|
|
131
|
+
error: `Adapter threw exception: ${errorMessage}`,
|
|
132
|
+
evidence,
|
|
133
|
+
timestamp: effectiveTimestamp,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Applies a lifecycle transition with a fallback to no-op if the adapter is not capable.
|
|
139
|
+
*
|
|
140
|
+
* This is a convenience method for cases where you want to attempt a transition
|
|
141
|
+
* but not fail if the adapter doesn't support it.
|
|
142
|
+
*
|
|
143
|
+
* @param options - The transition options.
|
|
144
|
+
* @returns A transition attempt result (never throws).
|
|
145
|
+
*/
|
|
146
|
+
async applyTransitionSafe(options) {
|
|
147
|
+
try {
|
|
148
|
+
return await this.applyTransition(options);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
152
|
+
return {
|
|
153
|
+
event: options.event,
|
|
154
|
+
targetState: "no_status_change",
|
|
155
|
+
applied: false,
|
|
156
|
+
skipped: false,
|
|
157
|
+
error: `Transition service threw exception: ${errorMessage}`,
|
|
158
|
+
evidence: options.evidence,
|
|
159
|
+
timestamp: options.timestamp ?? new Date().toISOString(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.LifecycleTransitionService = LifecycleTransitionService;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LocalGraph = void 0;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const schema_js_1 = require("./schema.js");
|
|
10
|
+
const types_js_1 = require("./types.js");
|
|
11
|
+
const migration_js_1 = require("./migration.js");
|
|
12
|
+
/**
|
|
13
|
+
* Represents the local execution graph, loaded from a `clusters.json` file.
|
|
14
|
+
* It handles both v1 and v2 formats, migrating v1 to v2 in memory.
|
|
15
|
+
*/
|
|
16
|
+
class LocalGraph {
|
|
17
|
+
graph;
|
|
18
|
+
constructor(graph) {
|
|
19
|
+
this.graph = graph;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Loads an execution graph from the specified `clusters.json` file.
|
|
23
|
+
* It automatically detects the schema version and migrates v1 graphs to v2.
|
|
24
|
+
*
|
|
25
|
+
* @param clusterId The ID of the cluster to load (e.g., "POL-105").
|
|
26
|
+
* @param repoRoot The root directory of the repository.
|
|
27
|
+
* @returns A promise that resolves to a new `LocalGraph` instance.
|
|
28
|
+
*/
|
|
29
|
+
static async load(clusterId, repoRoot = process.cwd()) {
|
|
30
|
+
const filePath = node_path_1.default.join(repoRoot, ".polaris", "clusters", clusterId, "clusters.json");
|
|
31
|
+
const fileContent = await (0, promises_1.readFile)(filePath, "utf-8");
|
|
32
|
+
const rawGraph = JSON.parse(fileContent);
|
|
33
|
+
let v2Graph;
|
|
34
|
+
if ((0, types_js_1.isV2Graph)(rawGraph)) {
|
|
35
|
+
v2Graph = schema_js_1.executionGraphV2Schema.parse(rawGraph);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const v1Graph = schema_js_1.executionGraphV1Schema.parse(rawGraph);
|
|
39
|
+
v2Graph = (0, migration_js_1.migrateV1toV2)(v1Graph);
|
|
40
|
+
// We can also validate the migrated graph to be safe
|
|
41
|
+
v2Graph = schema_js_1.executionGraphV2Schema.parse(v2Graph);
|
|
42
|
+
}
|
|
43
|
+
return new LocalGraph(v2Graph);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a LocalGraph instance directly from an already-validated v2 graph.
|
|
47
|
+
* Use this when the graph has been built in memory (e.g., by a tracker adapter).
|
|
48
|
+
*
|
|
49
|
+
* @param graph A validated ExecutionGraphV2 object.
|
|
50
|
+
* @returns A new LocalGraph instance.
|
|
51
|
+
*/
|
|
52
|
+
static fromGraph(graph) {
|
|
53
|
+
return new LocalGraph(graph);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Persists the graph to `.polaris/clusters/{clusterId}/clusters.json`.
|
|
57
|
+
* Creates the directory if it does not exist.
|
|
58
|
+
*
|
|
59
|
+
* @param clusterId The cluster ID to use as the directory name (e.g., "POL-198").
|
|
60
|
+
* @param repoRoot The root directory of the repository.
|
|
61
|
+
* @returns The absolute path of the written file.
|
|
62
|
+
*/
|
|
63
|
+
async save(clusterId, repoRoot = process.cwd()) {
|
|
64
|
+
const dir = node_path_1.default.join(repoRoot, ".polaris", "clusters", clusterId);
|
|
65
|
+
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
66
|
+
const filePath = node_path_1.default.join(dir, "clusters.json");
|
|
67
|
+
await (0, promises_1.writeFile)(filePath, JSON.stringify(this.graph, null, 2), "utf-8");
|
|
68
|
+
return filePath;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns the full v2 execution graph.
|
|
72
|
+
*/
|
|
73
|
+
get fullGraph() {
|
|
74
|
+
return this.graph;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the active cluster.
|
|
78
|
+
*/
|
|
79
|
+
getActiveCluster() {
|
|
80
|
+
return this.graph.clusters[this.graph.activeCluster];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns a node by its ID.
|
|
84
|
+
* @param id The ID of the node to retrieve.
|
|
85
|
+
*/
|
|
86
|
+
getNode(id) {
|
|
87
|
+
return this.graph.nodes[id];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns the dependencies for a given node.
|
|
91
|
+
* @param id The ID of the node to get dependencies for.
|
|
92
|
+
* @returns An array of node IDs that the given node is blocked by.
|
|
93
|
+
*/
|
|
94
|
+
getDependencies(id) {
|
|
95
|
+
return this.graph.dependencies[id] ?? [];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.LocalGraph = LocalGraph;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrateV1toV2 = migrateV1toV2;
|
|
4
|
+
/**
|
|
5
|
+
* Migrates a v1 execution graph to a v2 execution graph.
|
|
6
|
+
*
|
|
7
|
+
* @param v1Graph The v1 execution graph to migrate.
|
|
8
|
+
* @returns The migrated v2 execution graph.
|
|
9
|
+
*/
|
|
10
|
+
function migrateV1toV2(v1Graph) {
|
|
11
|
+
if (!v1Graph.clusters || v1Graph.clusters.length === 0) {
|
|
12
|
+
throw new Error("Cannot migrate v1 execution graph: clusters array is empty or missing.");
|
|
13
|
+
}
|
|
14
|
+
const v2Graph = {
|
|
15
|
+
schemaVersion: "v2",
|
|
16
|
+
source: {
|
|
17
|
+
id: v1Graph.source_id,
|
|
18
|
+
type: v1Graph.source_type,
|
|
19
|
+
},
|
|
20
|
+
nodes: {},
|
|
21
|
+
dependencies: {},
|
|
22
|
+
clusters: {},
|
|
23
|
+
activeCluster: v1Graph.clusters[0]?.cluster_id ?? "default-cluster",
|
|
24
|
+
};
|
|
25
|
+
if (v1Graph.analyze_source_id) {
|
|
26
|
+
v2Graph.source.analysis = {
|
|
27
|
+
id: v1Graph.analyze_source_id,
|
|
28
|
+
doc: v1Graph.analysis_doc,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
for (const v1Cluster of v1Graph.clusters) {
|
|
32
|
+
const childNodeIds = [];
|
|
33
|
+
for (const child of v1Cluster.children) {
|
|
34
|
+
childNodeIds.push(child.id);
|
|
35
|
+
// Add node to the normalized map
|
|
36
|
+
if (!v2Graph.nodes[child.id]) {
|
|
37
|
+
v2Graph.nodes[child.id] = {
|
|
38
|
+
id: child.id,
|
|
39
|
+
title: child.title,
|
|
40
|
+
status: "Todo", // V1 doesn't have status, so default to Todo
|
|
41
|
+
sessionType: child.session_type,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Add dependencies
|
|
45
|
+
if (child.blockedBy.length > 0) {
|
|
46
|
+
v2Graph.dependencies[child.id] = child.blockedBy;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
v2Graph.clusters[v1Cluster.cluster_id] = {
|
|
50
|
+
id: v1Cluster.cluster_id,
|
|
51
|
+
title: v1Cluster.description,
|
|
52
|
+
children: childNodeIds,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return v2Graph;
|
|
56
|
+
}
|