@kontextmind/kxm 0.7.169 → 0.7.171
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +18 -0
- package/docs/adr/ADR-0005-obscura-default-playwright.md +2 -2
- package/docs/architecture/hosted-direction.md +7 -7
- package/docs/contributing/assignment-runner.md +6 -5
- package/docs/contributing/decisions.md +1 -1
- package/docs/contributing/learnings.md +9 -4
- package/docs/reference/cli-reference.md +27 -4
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +596 -269
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-runs/SKILL.md +10 -0
- package/plugins/kxm/src/cli/supervise.ts +167 -0
- package/plugins/kxm/src/cli.ts +32 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/supervise-state.ts +232 -0
- package/scripts/pr-land.mjs +115 -17
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -20742,8 +20742,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
20742
20742
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
20743
20743
|
if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
20744
20744
|
}
|
|
20745
|
-
const
|
|
20746
|
-
const minimumPassed =
|
|
20745
|
+
const join59 = objectValue(step.join);
|
|
20746
|
+
const minimumPassed = join59 && typeof join59.minimumPassed === "number" ? join59.minimumPassed : void 0;
|
|
20747
20747
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
20748
20748
|
const distinctBy = names(assignment?.distinctBy);
|
|
20749
20749
|
if (distinctBy.length > 0) {
|
|
@@ -21034,26 +21034,26 @@ function originHashIssues(projectRoot, models) {
|
|
|
21034
21034
|
}
|
|
21035
21035
|
function developerCeilings() {
|
|
21036
21036
|
const script = join9(findKxmRepoRoot(import.meta.url), "scripts", "harness-run.mjs");
|
|
21037
|
-
let
|
|
21037
|
+
let loaded2;
|
|
21038
21038
|
try {
|
|
21039
|
-
|
|
21039
|
+
loaded2 = spawnSync5(process.execPath, ["--input-type=module", "-e", `const m = await import(${JSON.stringify(pathToFileURL(script).href)}); process.stdout.write(JSON.stringify({ROUTES:m.ROUTES,NATIVE_PI_BRAKE_PROVIDERS:m.NATIVE_PI_BRAKE_PROVIDERS,PI_ALLOWED_PROVIDERS:m.PI_ALLOWED_PROVIDERS,PI_NATIVE_VENDOR_PROVIDERS:m.PI_NATIVE_VENDOR_PROVIDERS}))`], {
|
|
21040
21040
|
encoding: "utf8",
|
|
21041
21041
|
timeout: 15e3
|
|
21042
21042
|
});
|
|
21043
21043
|
} catch (error) {
|
|
21044
21044
|
return { ok: false, detail: error instanceof Error ? error.message : String(error) };
|
|
21045
21045
|
}
|
|
21046
|
-
if (
|
|
21047
|
-
const code =
|
|
21048
|
-
const detail = code === "ETIMEDOUT" ||
|
|
21046
|
+
if (loaded2.error) {
|
|
21047
|
+
const code = loaded2.error.code;
|
|
21048
|
+
const detail = code === "ETIMEDOUT" || loaded2.signal ? `timed out after 15s (${loaded2.error.message})` : loaded2.error.message;
|
|
21049
21049
|
return { ok: false, detail };
|
|
21050
21050
|
}
|
|
21051
|
-
if (
|
|
21052
|
-
const stderr = (
|
|
21053
|
-
return { ok: false, detail: stderr || `scripts/harness-run.mjs exited ${
|
|
21051
|
+
if (loaded2.status !== 0 || !loaded2.stdout) {
|
|
21052
|
+
const stderr = (loaded2.stderr ?? "").trim();
|
|
21053
|
+
return { ok: false, detail: stderr || `scripts/harness-run.mjs exited ${loaded2.status}` };
|
|
21054
21054
|
}
|
|
21055
21055
|
try {
|
|
21056
|
-
return { ok: true, ...JSON.parse(
|
|
21056
|
+
return { ok: true, ...JSON.parse(loaded2.stdout) };
|
|
21057
21057
|
} catch (error) {
|
|
21058
21058
|
return { ok: false, detail: `ceilings JSON parse failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
21059
21059
|
}
|
|
@@ -25083,7 +25083,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
25083
25083
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
25084
25084
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
25085
25085
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
25086
|
-
const
|
|
25086
|
+
const join59 = compileJoin(step, id, sink);
|
|
25087
25087
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
25088
25088
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
25089
25089
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
|
|
@@ -25111,7 +25111,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
25111
25111
|
transitions: orderedTransitions,
|
|
25112
25112
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
25113
25113
|
assignments,
|
|
25114
|
-
join:
|
|
25114
|
+
join: join59
|
|
25115
25115
|
};
|
|
25116
25116
|
if (kind === "agent" || kind === "moa") {
|
|
25117
25117
|
if (!agent) return void 0;
|
|
@@ -25161,15 +25161,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
25161
25161
|
};
|
|
25162
25162
|
}
|
|
25163
25163
|
function compileJoin(step, stepId, sink) {
|
|
25164
|
-
const
|
|
25165
|
-
if (!
|
|
25166
|
-
const declared = stringValue2(
|
|
25164
|
+
const join59 = objectValue2(step.join);
|
|
25165
|
+
if (!join59) return { strategy: "all" };
|
|
25166
|
+
const declared = stringValue2(join59.strategy);
|
|
25167
25167
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
25168
|
-
const minimumPassed = compileOptionalCount(
|
|
25168
|
+
const minimumPassed = compileOptionalCount(join59.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
25169
25169
|
const compiled = {
|
|
25170
25170
|
strategy,
|
|
25171
25171
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
25172
|
-
...typeof
|
|
25172
|
+
...typeof join59.cancelRemaining === "boolean" ? { cancelRemaining: join59.cancelRemaining } : {}
|
|
25173
25173
|
};
|
|
25174
25174
|
return compiled;
|
|
25175
25175
|
}
|
|
@@ -25812,14 +25812,14 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
25812
25812
|
}
|
|
25813
25813
|
function acknowledgePriceCatalog(projectRoot, now = /* @__PURE__ */ new Date()) {
|
|
25814
25814
|
const path4 = join14(projectRoot, ".kxm", "prices.yaml");
|
|
25815
|
-
const
|
|
25816
|
-
if (!
|
|
25815
|
+
const loaded2 = loadPriceCatalog(projectRoot);
|
|
25816
|
+
if (!loaded2) throw new Error("price catalog missing");
|
|
25817
25817
|
const date = now.toISOString().slice(0, 10);
|
|
25818
25818
|
const body = {
|
|
25819
|
-
schema:
|
|
25819
|
+
schema: loaded2.schema,
|
|
25820
25820
|
date,
|
|
25821
|
-
currency:
|
|
25822
|
-
models:
|
|
25821
|
+
currency: loaded2.currency ?? "USD",
|
|
25822
|
+
models: loaded2.models
|
|
25823
25823
|
};
|
|
25824
25824
|
const stamped = { ...body, sha256: hashPriceCatalog(body) };
|
|
25825
25825
|
writeFileSync9(path4, (0, import_yaml6.stringify)({
|
|
@@ -28657,10 +28657,10 @@ function runtimeFrom(ctx, command) {
|
|
|
28657
28657
|
const envServerUrl = ctx.env.KXM_SERVER_URL?.trim();
|
|
28658
28658
|
let boundHubUrl;
|
|
28659
28659
|
try {
|
|
28660
|
-
const
|
|
28661
|
-
if (
|
|
28660
|
+
const loaded2 = loadHubBinding(ctx.env);
|
|
28661
|
+
if (loaded2.warning) ctx.io.stderr(`kxm: ${loaded2.warning}
|
|
28662
28662
|
`);
|
|
28663
|
-
boundHubUrl =
|
|
28663
|
+
boundHubUrl = loaded2.record?.url;
|
|
28664
28664
|
} catch (error) {
|
|
28665
28665
|
if (error instanceof HubBindingError) {
|
|
28666
28666
|
ctx.io.stderr(`kxm: ignoring malformed hub binding at ${hubBindingFile(ctx.env)}; falling back to the local hub. Run kxm hub bind <url> again
|
|
@@ -38004,7 +38004,7 @@ async function cmdWorkflowDefinitions(runtime, options) {
|
|
|
38004
38004
|
}
|
|
38005
38005
|
async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
38006
38006
|
const scope = options.scope ?? "local";
|
|
38007
|
-
const
|
|
38007
|
+
const refuse5 = (error, message, code = 2) => {
|
|
38008
38008
|
print(runtime.io, runtime.json, { ok: false, command: "workflow add", error, message }, `workflow add failed: ${message}`);
|
|
38009
38009
|
return code;
|
|
38010
38010
|
};
|
|
@@ -38012,12 +38012,12 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
38012
38012
|
let content;
|
|
38013
38013
|
if (options.template !== void 0) {
|
|
38014
38014
|
if (options.file !== void 0 || options.pick !== void 0) {
|
|
38015
|
-
return
|
|
38015
|
+
return refuse5("workflow_add_conflict", "--template cannot be combined with --file or --pick");
|
|
38016
38016
|
}
|
|
38017
|
-
if (!workflowId) return
|
|
38017
|
+
if (!workflowId) return refuse5("workflow_id_required", "usage: kxm workflow add <workflowId> --template <name>");
|
|
38018
38018
|
const template = Object.hasOwn(WORKFLOW_TEMPLATES, options.template) ? WORKFLOW_TEMPLATES[options.template] : void 0;
|
|
38019
38019
|
if (!template) {
|
|
38020
|
-
return
|
|
38020
|
+
return refuse5("workflow_template_unknown", `unknown template ${options.template}; choose ${Object.keys(WORKFLOW_TEMPLATES).join(", ")}`);
|
|
38021
38021
|
}
|
|
38022
38022
|
content = { ...template, ...options.description !== void 0 ? { description: options.description } : {} };
|
|
38023
38023
|
} else if (!workflowId || options.pick) {
|
|
@@ -38037,7 +38037,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
38037
38037
|
}
|
|
38038
38038
|
const picked = await resolvePickItem(runtime.io, `Select a workflow template to add (${scope})`, candidates, options.pick, runtime.env);
|
|
38039
38039
|
if (!picked) {
|
|
38040
|
-
return
|
|
38040
|
+
return refuse5("workflow_id_required", "provide a workflowId or select an available workflow with --pick <id>", 1);
|
|
38041
38041
|
}
|
|
38042
38042
|
workflowId ??= picked.id;
|
|
38043
38043
|
if (options.file === void 0) {
|
|
@@ -38059,7 +38059,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
38059
38059
|
if (scope === "local") {
|
|
38060
38060
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
38061
38061
|
if (!projectRoot) {
|
|
38062
|
-
return
|
|
38062
|
+
return refuse5("project_not_found", "local workflows belong to a KXM project; run kxm init at the repository root, or pass --scope global");
|
|
38063
38063
|
}
|
|
38064
38064
|
const issues = kxmWorkflowWriteIssues(projectRoot, workflowId, document);
|
|
38065
38065
|
if (issues.length > 0) {
|
|
@@ -38094,7 +38094,7 @@ ${issues.map((entry) => ` ${entry.file}: ${entry.code}: ${entry.message}`).join
|
|
|
38094
38094
|
);
|
|
38095
38095
|
return 0;
|
|
38096
38096
|
} catch (err) {
|
|
38097
|
-
return
|
|
38097
|
+
return refuse5("workflow_add_failed", err instanceof Error ? err.message : String(err), 1);
|
|
38098
38098
|
}
|
|
38099
38099
|
}
|
|
38100
38100
|
async function cmdWorkflowRemove(runtime, workflowId, options) {
|
|
@@ -40728,9 +40728,9 @@ function resolveBase(projectRoot, base) {
|
|
|
40728
40728
|
function withLaneCwd(runtime, unit, command = "lane") {
|
|
40729
40729
|
const invalid = refuseUnit(runtime, command, unit);
|
|
40730
40730
|
if (invalid !== void 0) return invalid;
|
|
40731
|
-
const
|
|
40732
|
-
if (typeof
|
|
40733
|
-
const lane =
|
|
40731
|
+
const loaded2 = loadLanes(runtime, command);
|
|
40732
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
40733
|
+
const lane = loaded2.lanes[unit];
|
|
40734
40734
|
if (!lane || !existsSync33(lane.path)) {
|
|
40735
40735
|
return refuse(runtime, command, "lane_missing", `lane ${unit} is not recorded or its worktree is absent`, { unit });
|
|
40736
40736
|
}
|
|
@@ -40888,9 +40888,9 @@ async function laneStoreRuns(runtime, lanePath) {
|
|
|
40888
40888
|
}
|
|
40889
40889
|
}
|
|
40890
40890
|
async function refuseIfLaneStoreRunsOpen(runtime, unit, command) {
|
|
40891
|
-
const
|
|
40892
|
-
if (typeof
|
|
40893
|
-
const lane =
|
|
40891
|
+
const loaded2 = loadLanes(runtime, command);
|
|
40892
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
40893
|
+
const lane = loaded2.lanes[unit];
|
|
40894
40894
|
if (!lane) return void 0;
|
|
40895
40895
|
let runs;
|
|
40896
40896
|
try {
|
|
@@ -40911,9 +40911,9 @@ async function refuseIfLaneStoreRunsOpen(runtime, unit, command) {
|
|
|
40911
40911
|
);
|
|
40912
40912
|
}
|
|
40913
40913
|
async function refuseIfLaneRunOpen(runtime, unit, command) {
|
|
40914
|
-
const
|
|
40915
|
-
if (typeof
|
|
40916
|
-
const lane =
|
|
40914
|
+
const loaded2 = loadLanes(runtime, command);
|
|
40915
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
40916
|
+
const lane = loaded2.lanes[unit];
|
|
40917
40917
|
if (!lane?.lastRunId) return void 0;
|
|
40918
40918
|
const runStatus = await projectedRunStatus(runtime, lane.path, lane.lastRunId, true);
|
|
40919
40919
|
if (isSettled(runStatus)) return void 0;
|
|
@@ -40926,13 +40926,13 @@ async function refuseIfLaneRunOpen(runtime, unit, command) {
|
|
|
40926
40926
|
);
|
|
40927
40927
|
}
|
|
40928
40928
|
function recordLaneRun(runtime, unit, runId, command) {
|
|
40929
|
-
const
|
|
40930
|
-
if (typeof
|
|
40931
|
-
const lane =
|
|
40929
|
+
const loaded2 = loadLanes(runtime, command);
|
|
40930
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
40931
|
+
const lane = loaded2.lanes[unit];
|
|
40932
40932
|
if (!lane) return refuse(runtime, command, "lane_missing", `lane ${unit} is not recorded or its worktree is absent`, { unit });
|
|
40933
40933
|
lane.lastRunId = runId;
|
|
40934
40934
|
try {
|
|
40935
|
-
writeLanes(runtime,
|
|
40935
|
+
writeLanes(runtime, loaded2);
|
|
40936
40936
|
} catch {
|
|
40937
40937
|
return refuse(runtime, command, "lanes_unreadable", `lane record ${lanesFile(runtime)} could not be written`);
|
|
40938
40938
|
}
|
|
@@ -40945,10 +40945,10 @@ async function cmdLaneCreate(runtime, unit, options = {}) {
|
|
|
40945
40945
|
const root = controlRoot(runtime, command);
|
|
40946
40946
|
if (typeof root === "number") return root;
|
|
40947
40947
|
const base = options.base?.trim() || "origin/main";
|
|
40948
|
-
const
|
|
40949
|
-
if (typeof
|
|
40948
|
+
const loaded2 = loadLanes(runtime, command);
|
|
40949
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
40950
40950
|
const path4 = laneWorktreePath(root, unit);
|
|
40951
|
-
if (
|
|
40951
|
+
if (loaded2.lanes[unit] || existsSync33(path4) || branchExists(root, unit)) {
|
|
40952
40952
|
return refuse(runtime, command, "lane_exists", `lane ${unit} already exists`, { unit });
|
|
40953
40953
|
}
|
|
40954
40954
|
const baseSha = resolveBase(root, base);
|
|
@@ -40984,9 +40984,9 @@ async function cmdLaneCreate(runtime, unit, options = {}) {
|
|
|
40984
40984
|
baseSha,
|
|
40985
40985
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
40986
40986
|
};
|
|
40987
|
-
|
|
40987
|
+
loaded2.lanes[unit] = lane;
|
|
40988
40988
|
try {
|
|
40989
|
-
writeLanes(runtime,
|
|
40989
|
+
writeLanes(runtime, loaded2);
|
|
40990
40990
|
} catch {
|
|
40991
40991
|
git2(root, ["worktree", "remove", "--force", path4]);
|
|
40992
40992
|
return refuse(runtime, command, "lanes_unreadable", `lane record ${lanesFile(runtime)} could not be written`, { unit });
|
|
@@ -40996,9 +40996,9 @@ async function cmdLaneCreate(runtime, unit, options = {}) {
|
|
|
40996
40996
|
}
|
|
40997
40997
|
async function cmdLaneList(runtime) {
|
|
40998
40998
|
const command = "lane list";
|
|
40999
|
-
const
|
|
41000
|
-
if (typeof
|
|
41001
|
-
const lanes = Object.keys(
|
|
40999
|
+
const loaded2 = loadLanes(runtime, command);
|
|
41000
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
41001
|
+
const lanes = Object.keys(loaded2.lanes).sort().map((unit) => laneView(unit, loaded2.lanes[unit]));
|
|
41002
41002
|
print(
|
|
41003
41003
|
runtime.io,
|
|
41004
41004
|
runtime.json,
|
|
@@ -41011,9 +41011,9 @@ async function cmdLaneStatus(runtime, unit) {
|
|
|
41011
41011
|
const command = "lane status";
|
|
41012
41012
|
const invalid = refuseUnit(runtime, command, unit);
|
|
41013
41013
|
if (invalid !== void 0) return invalid;
|
|
41014
|
-
const
|
|
41015
|
-
if (typeof
|
|
41016
|
-
const record =
|
|
41014
|
+
const loaded2 = loadLanes(runtime, command);
|
|
41015
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
41016
|
+
const record = loaded2.lanes[unit];
|
|
41017
41017
|
if (!record) return refuse(runtime, command, "lane_missing", `lane ${unit} is not recorded`, { unit });
|
|
41018
41018
|
const view = laneView(unit, record);
|
|
41019
41019
|
const runStatus = record.lastRunId ? await projectedRunStatus(runtime, record.path, record.lastRunId, false) : "unknown";
|
|
@@ -41063,9 +41063,9 @@ async function cmdLaneDrop(runtime, unit, options = {}) {
|
|
|
41063
41063
|
if (invalid !== void 0) return invalid;
|
|
41064
41064
|
const root = controlRoot(runtime, command);
|
|
41065
41065
|
if (typeof root === "number") return root;
|
|
41066
|
-
const
|
|
41067
|
-
if (typeof
|
|
41068
|
-
const record =
|
|
41066
|
+
const loaded2 = loadLanes(runtime, command);
|
|
41067
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
41068
|
+
const record = loaded2.lanes[unit];
|
|
41069
41069
|
if (!record) return refuse(runtime, command, "lane_missing", `lane ${unit} is not recorded`, { unit });
|
|
41070
41070
|
const force = options.force === true;
|
|
41071
41071
|
if (!force) {
|
|
@@ -41101,9 +41101,9 @@ async function cmdLaneDrop(runtime, unit, options = {}) {
|
|
|
41101
41101
|
return refuse(runtime, command, "lane_git_failed", `git worktree remove failed: ${removed.stderr.trim().slice(0, 300)}`, { unit });
|
|
41102
41102
|
}
|
|
41103
41103
|
}
|
|
41104
|
-
delete
|
|
41104
|
+
delete loaded2.lanes[unit];
|
|
41105
41105
|
try {
|
|
41106
|
-
writeLanes(runtime,
|
|
41106
|
+
writeLanes(runtime, loaded2);
|
|
41107
41107
|
} catch {
|
|
41108
41108
|
return refuse(runtime, command, "lanes_unreadable", `lane record ${lanesFile(runtime)} could not be written`, { unit });
|
|
41109
41109
|
}
|
|
@@ -41122,9 +41122,9 @@ async function cmdLaneRun(runtime, unit, options) {
|
|
|
41122
41122
|
if (!options.brief) return refuse(runtime, command, "brief_unreadable", "lane run requires --brief <file>");
|
|
41123
41123
|
const brief = readRunBrief(runtime, options.brief, command);
|
|
41124
41124
|
if (typeof brief === "number") return brief;
|
|
41125
|
-
const
|
|
41126
|
-
if (typeof
|
|
41127
|
-
const existed = Boolean(
|
|
41125
|
+
const loaded2 = loadLanes(runtime, command);
|
|
41126
|
+
if (typeof loaded2 === "number") return loaded2;
|
|
41127
|
+
const existed = Boolean(loaded2.lanes[unit]);
|
|
41128
41128
|
if (!existed) {
|
|
41129
41129
|
const created = await cmdLaneCreate(runtime, unit, options.base !== void 0 ? { base: options.base } : {});
|
|
41130
41130
|
if (created !== 0) return created;
|
|
@@ -41135,7 +41135,7 @@ async function cmdLaneRun(runtime, unit, options) {
|
|
|
41135
41135
|
if (open2 !== void 0) return open2;
|
|
41136
41136
|
}
|
|
41137
41137
|
const root = controlRoot(runtime, command);
|
|
41138
|
-
const path4 = existed ?
|
|
41138
|
+
const path4 = existed ? loaded2.lanes[unit].path : typeof root === "number" ? unit : laneWorktreePath(root, unit);
|
|
41139
41139
|
printPlan(runtime, { command, unit, brief: options.brief }, [
|
|
41140
41140
|
{ action: "request", target: `POST /v1/runs projectRoot=${path4}` },
|
|
41141
41141
|
{ action: "request", target: `POST /v1/runs/<new>/drive projectRoot=${path4}` }
|
|
@@ -41202,15 +41202,320 @@ function cmdLand(runtime, options = {}) {
|
|
|
41202
41202
|
});
|
|
41203
41203
|
}
|
|
41204
41204
|
|
|
41205
|
+
// plugins/kxm/src/cli/supervise.ts
|
|
41206
|
+
init_project_config();
|
|
41207
|
+
import { appendFileSync as appendFileSync2, chmodSync as chmodSync8, mkdirSync as mkdirSync26 } from "node:fs";
|
|
41208
|
+
import { join as join40 } from "node:path";
|
|
41209
|
+
|
|
41210
|
+
// plugins/kxm/src/supervise-state.ts
|
|
41211
|
+
init_project_config();
|
|
41212
|
+
import { chmodSync as chmodSync7, existsSync as existsSync34, mkdirSync as mkdirSync25, readFileSync as readFileSync31, renameSync as renameSync8, writeFileSync as writeFileSync23 } from "node:fs";
|
|
41213
|
+
import { join as join39 } from "node:path";
|
|
41214
|
+
var SUPERVISOR_SCHEMA = "kxm.supervisor.v1";
|
|
41215
|
+
var TIMESTAMP_RE2 = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]{1,9})?Z$/;
|
|
41216
|
+
var MERGE_STATE_RE = /^[A-Z][A-Z0-9_]{0,31}$/;
|
|
41217
|
+
var CI_TOKEN_RE = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
41218
|
+
var MAX_BACKOFF_MS = 24 * 60 * 60 * 1e3;
|
|
41219
|
+
function supervisorStatePath(stateDir) {
|
|
41220
|
+
return join39(stateDir, "supervisor.json");
|
|
41221
|
+
}
|
|
41222
|
+
function emptySupervisorState(now) {
|
|
41223
|
+
return { schema: SUPERVISOR_SCHEMA, updatedAt: now, lanes: {} };
|
|
41224
|
+
}
|
|
41225
|
+
function isSupervisorTimestamp(value) {
|
|
41226
|
+
return TIMESTAMP_RE2.test(value) && Number.isFinite(Date.parse(value));
|
|
41227
|
+
}
|
|
41228
|
+
function resolveSupervisorNow(override, fallback) {
|
|
41229
|
+
if (override === void 0 || override.trim() === "") return fallback.toISOString();
|
|
41230
|
+
const text = override.trim();
|
|
41231
|
+
return isSupervisorTimestamp(text) ? text : "supervisor_clock_invalid";
|
|
41232
|
+
}
|
|
41233
|
+
function isPullRequest(value) {
|
|
41234
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
41235
|
+
const record = value;
|
|
41236
|
+
if (Object.keys(record).some((key) => key !== "number" && key !== "mergeState" && key !== "seenAt")) return false;
|
|
41237
|
+
return Number.isInteger(record.number) && record.number > 0 && typeof record.mergeState === "string" && MERGE_STATE_RE.test(record.mergeState) && typeof record.seenAt === "string" && isSupervisorTimestamp(record.seenAt);
|
|
41238
|
+
}
|
|
41239
|
+
function isCi(value) {
|
|
41240
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
41241
|
+
const record = value;
|
|
41242
|
+
if (Object.keys(record).some((key) => key !== "status" && key !== "conclusion" && key !== "seenAt")) return false;
|
|
41243
|
+
return typeof record.status === "string" && CI_TOKEN_RE.test(record.status) && typeof record.conclusion === "string" && CI_TOKEN_RE.test(record.conclusion) && typeof record.seenAt === "string" && isSupervisorTimestamp(record.seenAt);
|
|
41244
|
+
}
|
|
41245
|
+
function isLane(value) {
|
|
41246
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
41247
|
+
const record = value;
|
|
41248
|
+
if (Object.keys(record).some((key) => key !== "inFlight" && key !== "pr" && key !== "ci" && key !== "backoffUntil")) return false;
|
|
41249
|
+
if (typeof record.inFlight !== "boolean") return false;
|
|
41250
|
+
if (record.pr !== void 0 && !isPullRequest(record.pr)) return false;
|
|
41251
|
+
if (record.ci !== void 0 && !isCi(record.ci)) return false;
|
|
41252
|
+
if (record.backoffUntil !== void 0 && (typeof record.backoffUntil !== "string" || !isSupervisorTimestamp(record.backoffUntil))) return false;
|
|
41253
|
+
return true;
|
|
41254
|
+
}
|
|
41255
|
+
function isState(value) {
|
|
41256
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
41257
|
+
const record = value;
|
|
41258
|
+
if (Object.keys(record).some((key) => key !== "schema" && key !== "updatedAt" && key !== "lanes")) return false;
|
|
41259
|
+
if (record.schema !== SUPERVISOR_SCHEMA) return false;
|
|
41260
|
+
if (typeof record.updatedAt !== "string" || !isSupervisorTimestamp(record.updatedAt)) return false;
|
|
41261
|
+
if (!record.lanes || typeof record.lanes !== "object" || Array.isArray(record.lanes)) return false;
|
|
41262
|
+
for (const [unit, lane] of Object.entries(record.lanes)) {
|
|
41263
|
+
if (!kxmResourceIdentifier(unit) || !isLane(lane)) return false;
|
|
41264
|
+
}
|
|
41265
|
+
return true;
|
|
41266
|
+
}
|
|
41267
|
+
function loadSupervisorState(stateDir, now) {
|
|
41268
|
+
const path4 = supervisorStatePath(stateDir);
|
|
41269
|
+
if (!existsSync34(path4)) return emptySupervisorState(now);
|
|
41270
|
+
let parsed;
|
|
41271
|
+
try {
|
|
41272
|
+
parsed = JSON.parse(readFileSync31(path4, "utf8"));
|
|
41273
|
+
} catch {
|
|
41274
|
+
return "supervisor_unreadable";
|
|
41275
|
+
}
|
|
41276
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "supervisor_unreadable";
|
|
41277
|
+
const schema = parsed.schema;
|
|
41278
|
+
if (schema !== SUPERVISOR_SCHEMA) return "supervisor_schema_unsupported";
|
|
41279
|
+
if (!isState(parsed)) return "supervisor_unreadable";
|
|
41280
|
+
return parsed;
|
|
41281
|
+
}
|
|
41282
|
+
function saveSupervisorState(stateDir, state) {
|
|
41283
|
+
const lanes = {};
|
|
41284
|
+
for (const unit of Object.keys(state.lanes).sort()) {
|
|
41285
|
+
const lane = state.lanes[unit];
|
|
41286
|
+
if (!lane) continue;
|
|
41287
|
+
const next = { inFlight: lane.inFlight };
|
|
41288
|
+
if (lane.pr) next.pr = { number: lane.pr.number, mergeState: lane.pr.mergeState, seenAt: lane.pr.seenAt };
|
|
41289
|
+
if (lane.ci) next.ci = { status: lane.ci.status, conclusion: lane.ci.conclusion, seenAt: lane.ci.seenAt };
|
|
41290
|
+
if (lane.backoffUntil) next.backoffUntil = lane.backoffUntil;
|
|
41291
|
+
lanes[unit] = next;
|
|
41292
|
+
}
|
|
41293
|
+
const body = `${JSON.stringify({ schema: SUPERVISOR_SCHEMA, updatedAt: state.updatedAt, lanes }, null, 2)}
|
|
41294
|
+
`;
|
|
41295
|
+
mkdirSync25(stateDir, { recursive: true });
|
|
41296
|
+
const path4 = supervisorStatePath(stateDir);
|
|
41297
|
+
const temporary = `${path4}.tmp`;
|
|
41298
|
+
writeFileSync23(temporary, body, { encoding: "utf8", mode: 384 });
|
|
41299
|
+
renameSync8(temporary, path4);
|
|
41300
|
+
try {
|
|
41301
|
+
chmodSync7(path4, 384);
|
|
41302
|
+
} catch {
|
|
41303
|
+
}
|
|
41304
|
+
}
|
|
41305
|
+
function applyObservation(state, observation, now) {
|
|
41306
|
+
if (!kxmResourceIdentifier(observation.unit)) return "lane_unit_invalid";
|
|
41307
|
+
if (!isSupervisorTimestamp(now)) return "supervisor_backoff_invalid";
|
|
41308
|
+
if (observation.pr) {
|
|
41309
|
+
if (!Number.isInteger(observation.pr.number) || observation.pr.number <= 0 || !MERGE_STATE_RE.test(observation.pr.mergeState)) {
|
|
41310
|
+
return "supervisor_pr_invalid";
|
|
41311
|
+
}
|
|
41312
|
+
}
|
|
41313
|
+
if (observation.ci) {
|
|
41314
|
+
if (!CI_TOKEN_RE.test(observation.ci.status) || !CI_TOKEN_RE.test(observation.ci.conclusion)) return "supervisor_ci_invalid";
|
|
41315
|
+
}
|
|
41316
|
+
if (observation.backoffMs !== void 0) {
|
|
41317
|
+
if (!Number.isInteger(observation.backoffMs) || observation.backoffMs < 0 || observation.backoffMs > MAX_BACKOFF_MS) {
|
|
41318
|
+
return "supervisor_backoff_invalid";
|
|
41319
|
+
}
|
|
41320
|
+
}
|
|
41321
|
+
const prior = state.lanes[observation.unit];
|
|
41322
|
+
const next = { inFlight: observation.inFlight };
|
|
41323
|
+
if (observation.pr) next.pr = { number: observation.pr.number, mergeState: observation.pr.mergeState, seenAt: now };
|
|
41324
|
+
else if (prior?.pr) next.pr = { ...prior.pr };
|
|
41325
|
+
if (observation.ci) next.ci = { status: observation.ci.status, conclusion: observation.ci.conclusion, seenAt: now };
|
|
41326
|
+
else if (prior?.ci) next.ci = { ...prior.ci };
|
|
41327
|
+
if (observation.backoffMs === void 0) {
|
|
41328
|
+
if (prior?.backoffUntil) next.backoffUntil = prior.backoffUntil;
|
|
41329
|
+
} else if (observation.backoffMs > 0) {
|
|
41330
|
+
next.backoffUntil = new Date(Date.parse(now) + observation.backoffMs).toISOString();
|
|
41331
|
+
}
|
|
41332
|
+
return {
|
|
41333
|
+
schema: SUPERVISOR_SCHEMA,
|
|
41334
|
+
updatedAt: now,
|
|
41335
|
+
lanes: { ...state.lanes, [observation.unit]: next }
|
|
41336
|
+
};
|
|
41337
|
+
}
|
|
41338
|
+
function resumeTick(state, now) {
|
|
41339
|
+
const nowMs = Date.parse(now);
|
|
41340
|
+
const lanes = {};
|
|
41341
|
+
const resumed = [];
|
|
41342
|
+
const waiting = [];
|
|
41343
|
+
for (const unit of Object.keys(state.lanes).sort()) {
|
|
41344
|
+
const lane = state.lanes[unit];
|
|
41345
|
+
if (!lane) continue;
|
|
41346
|
+
const until = lane.backoffUntil === void 0 ? void 0 : Date.parse(lane.backoffUntil);
|
|
41347
|
+
const next = { inFlight: lane.inFlight };
|
|
41348
|
+
if (lane.pr) next.pr = { ...lane.pr };
|
|
41349
|
+
if (lane.ci) next.ci = { ...lane.ci };
|
|
41350
|
+
if (until !== void 0 && until > nowMs && lane.backoffUntil !== void 0) {
|
|
41351
|
+
next.backoffUntil = lane.backoffUntil;
|
|
41352
|
+
waiting.push(unit);
|
|
41353
|
+
} else if (until !== void 0) {
|
|
41354
|
+
resumed.push(unit);
|
|
41355
|
+
}
|
|
41356
|
+
lanes[unit] = next;
|
|
41357
|
+
}
|
|
41358
|
+
return {
|
|
41359
|
+
state: { schema: SUPERVISOR_SCHEMA, updatedAt: now, lanes },
|
|
41360
|
+
resumed,
|
|
41361
|
+
waiting
|
|
41362
|
+
};
|
|
41363
|
+
}
|
|
41364
|
+
function formatTickLine(now, resumed, waiting) {
|
|
41365
|
+
const clock = now.slice(11, 16);
|
|
41366
|
+
if (resumed.length === 0 && waiting.length === 0) {
|
|
41367
|
+
return `[supervisor]: no change. No action. - (${clock})`;
|
|
41368
|
+
}
|
|
41369
|
+
const parts = [];
|
|
41370
|
+
if (resumed.length > 0) parts.push(`resumed ${resumed.join(", ")}`);
|
|
41371
|
+
if (waiting.length > 0) parts.push(`waiting ${waiting.join(", ")}`);
|
|
41372
|
+
const acted = resumed.length > 0 ? `Acted: resume ${resumed.join(", ")}` : "No action";
|
|
41373
|
+
return `[supervisor]: ${parts.join("; ")}. ${acted}. - (${clock})`;
|
|
41374
|
+
}
|
|
41375
|
+
|
|
41376
|
+
// plugins/kxm/src/cli/supervise.ts
|
|
41377
|
+
init_types();
|
|
41378
|
+
function refuse3(runtime, error, text) {
|
|
41379
|
+
print(runtime.io, runtime.json, { ok: false, command: "supervise", error }, text);
|
|
41380
|
+
return 1;
|
|
41381
|
+
}
|
|
41382
|
+
function requireProject2(runtime) {
|
|
41383
|
+
if (!discoverKxmProjectRoot(runtime.cwd)) {
|
|
41384
|
+
return refuse3(runtime, "project_required", "supervise requires a KXM project (run kxm init first)");
|
|
41385
|
+
}
|
|
41386
|
+
return void 0;
|
|
41387
|
+
}
|
|
41388
|
+
function nowOf(runtime) {
|
|
41389
|
+
const now = resolveSupervisorNow(runtime.env.KXM_SUPERVISE_NOW, /* @__PURE__ */ new Date());
|
|
41390
|
+
if (now === "supervisor_clock_invalid") {
|
|
41391
|
+
return refuse3(runtime, "supervisor_clock_invalid", "KXM_SUPERVISE_NOW must be an ISO-8601 UTC timestamp");
|
|
41392
|
+
}
|
|
41393
|
+
return now;
|
|
41394
|
+
}
|
|
41395
|
+
function loaded(runtime, now) {
|
|
41396
|
+
const state = loadSupervisorState(runtime.dirs.state, now);
|
|
41397
|
+
if (state === "supervisor_unreadable") {
|
|
41398
|
+
return refuse3(runtime, "supervisor_unreadable", "supervisor state is unreadable and was left unchanged");
|
|
41399
|
+
}
|
|
41400
|
+
if (state === "supervisor_schema_unsupported") {
|
|
41401
|
+
return refuse3(runtime, "supervisor_schema_unsupported", "supervisor state schema is not kxm.supervisor.v1 and was left unchanged");
|
|
41402
|
+
}
|
|
41403
|
+
return state;
|
|
41404
|
+
}
|
|
41405
|
+
function laneText(state) {
|
|
41406
|
+
const units = Object.keys(state.lanes).sort();
|
|
41407
|
+
if (units.length === 0) return "supervisor: no lanes";
|
|
41408
|
+
const lines = [`supervisor: ${units.length} lane${units.length === 1 ? "" : "s"}`];
|
|
41409
|
+
for (const unit of units) {
|
|
41410
|
+
const lane = state.lanes[unit];
|
|
41411
|
+
if (!lane) continue;
|
|
41412
|
+
const flight = lane.inFlight ? "in-flight" : "settled";
|
|
41413
|
+
const pr = lane.pr ? ` pr ${lane.pr.number} ${lane.pr.mergeState}` : "";
|
|
41414
|
+
const ci = lane.ci ? ` ci ${lane.ci.status}/${lane.ci.conclusion}` : "";
|
|
41415
|
+
const backoff = lane.backoffUntil ? ` backoff ${lane.backoffUntil}` : "";
|
|
41416
|
+
lines.push(`${unit} ${flight}${pr}${ci}${backoff}`);
|
|
41417
|
+
}
|
|
41418
|
+
return lines.join("\n");
|
|
41419
|
+
}
|
|
41420
|
+
function show(runtime, state, extra = {}) {
|
|
41421
|
+
print(runtime.io, runtime.json, { ok: true, command: "supervise", ...extra, state }, laneText(state));
|
|
41422
|
+
return 0;
|
|
41423
|
+
}
|
|
41424
|
+
function cmdSuperviseStatus(runtime) {
|
|
41425
|
+
const missing = requireProject2(runtime);
|
|
41426
|
+
if (missing !== void 0) return missing;
|
|
41427
|
+
const now = nowOf(runtime);
|
|
41428
|
+
if (typeof now === "number") return now;
|
|
41429
|
+
const state = loaded(runtime, now);
|
|
41430
|
+
if (typeof state === "number") return state;
|
|
41431
|
+
return show(runtime, state);
|
|
41432
|
+
}
|
|
41433
|
+
function appendTick(runtime, line) {
|
|
41434
|
+
mkdirSync26(runtime.dirs.logs, { recursive: true });
|
|
41435
|
+
const path4 = join40(runtime.dirs.logs, "supervisor.log");
|
|
41436
|
+
appendFileSync2(path4, `${line}
|
|
41437
|
+
`, { encoding: "utf8", mode: 384 });
|
|
41438
|
+
try {
|
|
41439
|
+
chmodSync8(path4, 384);
|
|
41440
|
+
} catch {
|
|
41441
|
+
}
|
|
41442
|
+
}
|
|
41443
|
+
function cmdSuperviseTick(runtime) {
|
|
41444
|
+
const missing = requireProject2(runtime);
|
|
41445
|
+
if (missing !== void 0) return missing;
|
|
41446
|
+
const now = nowOf(runtime);
|
|
41447
|
+
if (typeof now === "number") return now;
|
|
41448
|
+
const state = loaded(runtime, now);
|
|
41449
|
+
if (typeof state === "number") return state;
|
|
41450
|
+
const tick = resumeTick(state, now);
|
|
41451
|
+
const line = formatTickLine(now, tick.resumed, tick.waiting);
|
|
41452
|
+
if (runtime.dryRun) {
|
|
41453
|
+
printPlan(runtime, { command: "supervise", resumed: tick.resumed, waiting: tick.waiting, log: line, state: tick.state }, [
|
|
41454
|
+
{ action: "write", target: join40(runtime.dirs.state, "supervisor.json") },
|
|
41455
|
+
{ action: "write", target: join40(runtime.dirs.logs, "supervisor.log") }
|
|
41456
|
+
], "resume lanes whose backoff has elapsed");
|
|
41457
|
+
return 0;
|
|
41458
|
+
}
|
|
41459
|
+
saveSupervisorState(runtime.dirs.state, tick.state);
|
|
41460
|
+
appendTick(runtime, line);
|
|
41461
|
+
return show(runtime, tick.state, { resumed: tick.resumed, waiting: tick.waiting, log: line });
|
|
41462
|
+
}
|
|
41463
|
+
function parseBackoff(value) {
|
|
41464
|
+
if (value === void 0) return void 0;
|
|
41465
|
+
if (!/^[0-9]+$/.test(value)) return "supervisor_backoff_invalid";
|
|
41466
|
+
const parsed = Number(value);
|
|
41467
|
+
if (!Number.isSafeInteger(parsed)) return "supervisor_backoff_invalid";
|
|
41468
|
+
return parsed;
|
|
41469
|
+
}
|
|
41470
|
+
function cmdSuperviseRecord(runtime, options) {
|
|
41471
|
+
const missing = requireProject2(runtime);
|
|
41472
|
+
if (missing !== void 0) return missing;
|
|
41473
|
+
const now = nowOf(runtime);
|
|
41474
|
+
if (typeof now === "number") return now;
|
|
41475
|
+
const state = loaded(runtime, now);
|
|
41476
|
+
if (typeof state === "number") return state;
|
|
41477
|
+
const hasPr = options.pr !== void 0 || options.mergeState !== void 0;
|
|
41478
|
+
if (hasPr && (options.pr === void 0 || options.mergeState === void 0 || !/^[0-9]+$/.test(options.pr))) {
|
|
41479
|
+
return refuse3(runtime, "supervisor_pr_invalid", "record a pull request with both --pr and --merge-state");
|
|
41480
|
+
}
|
|
41481
|
+
const hasCi = options.ciStatus !== void 0 || options.ciConclusion !== void 0;
|
|
41482
|
+
if (hasCi && (options.ciStatus === void 0 || options.ciConclusion === void 0)) {
|
|
41483
|
+
return refuse3(runtime, "supervisor_ci_invalid", "record CI with both --ci-status and --ci-conclusion");
|
|
41484
|
+
}
|
|
41485
|
+
const backoffMs = parseBackoff(options.backoffMs);
|
|
41486
|
+
if (backoffMs === "supervisor_backoff_invalid") {
|
|
41487
|
+
return refuse3(runtime, "supervisor_backoff_invalid", "--backoff-ms must be a whole number of milliseconds from 0 through 86400000");
|
|
41488
|
+
}
|
|
41489
|
+
const next = applyObservation(state, {
|
|
41490
|
+
unit: options.lane,
|
|
41491
|
+
inFlight: options.settled !== true,
|
|
41492
|
+
...hasPr ? { pr: { number: Number(options.pr), mergeState: String(options.mergeState).trim().toUpperCase() } } : {},
|
|
41493
|
+
...hasCi ? { ci: { status: String(options.ciStatus).trim().toLowerCase(), conclusion: String(options.ciConclusion).trim().toLowerCase() } } : {},
|
|
41494
|
+
...backoffMs !== void 0 ? { backoffMs } : {}
|
|
41495
|
+
}, now);
|
|
41496
|
+
if (typeof next === "string") {
|
|
41497
|
+
const text = next === "lane_unit_invalid" ? `lane unit ${options.lane} must match the KXM identifier pattern` : next === "supervisor_pr_invalid" ? "pull request number and merge state are not valid" : next === "supervisor_ci_invalid" ? "CI status and conclusion are not valid" : "--backoff-ms must be a whole number of milliseconds from 0 through 86400000";
|
|
41498
|
+
return refuse3(runtime, next, text);
|
|
41499
|
+
}
|
|
41500
|
+
if (runtime.dryRun) {
|
|
41501
|
+
printPlan(runtime, { command: "supervise", state: next }, [
|
|
41502
|
+
{ action: "write", target: join40(runtime.dirs.state, "supervisor.json") }
|
|
41503
|
+
], `record lane ${options.lane}`);
|
|
41504
|
+
return 0;
|
|
41505
|
+
}
|
|
41506
|
+
saveSupervisorState(runtime.dirs.state, next);
|
|
41507
|
+
return show(runtime, next);
|
|
41508
|
+
}
|
|
41509
|
+
|
|
41205
41510
|
// plugins/kxm/src/cli/assign.ts
|
|
41206
41511
|
init_project_config();
|
|
41207
41512
|
init_types();
|
|
41208
41513
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
41209
|
-
import { existsSync as
|
|
41210
|
-
import { join as
|
|
41514
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
41515
|
+
import { join as join41 } from "node:path";
|
|
41211
41516
|
var kxmAssignCliSeams = {};
|
|
41212
41517
|
var RUNNER_REL = "scripts/assignment-run.mjs";
|
|
41213
|
-
function
|
|
41518
|
+
function refuse4(runtime, command, error, text) {
|
|
41214
41519
|
print(runtime.io, runtime.json, { ok: false, command, error }, text);
|
|
41215
41520
|
return 1;
|
|
41216
41521
|
}
|
|
@@ -41278,9 +41583,9 @@ function runnerArgv(subcommand, args) {
|
|
|
41278
41583
|
async function cmdAssign(runtime, subcommand, args) {
|
|
41279
41584
|
const command = `assign ${subcommand}`;
|
|
41280
41585
|
const root = discoverKxmProjectRoot(runtime.cwd);
|
|
41281
|
-
if (!root) return
|
|
41282
|
-
if (!
|
|
41283
|
-
return
|
|
41586
|
+
if (!root) return refuse4(runtime, command, "project_required", `${command} requires a KXM project (run kxm init first)`);
|
|
41587
|
+
if (!existsSync35(join41(root, "scripts", "assignment-run.mjs"))) {
|
|
41588
|
+
return refuse4(runtime, command, "assign_runner_missing", `${command} requires scripts/assignment-run.mjs in the project root`);
|
|
41284
41589
|
}
|
|
41285
41590
|
const argv = ["node", RUNNER_REL, ...runnerArgv(subcommand, args)];
|
|
41286
41591
|
if (runtime.dryRun) {
|
|
@@ -41302,7 +41607,7 @@ async function cmdAssign(runtime, subcommand, args) {
|
|
|
41302
41607
|
const result = spawn6("node", argv.slice(1), { cwd: root, stdio: "inherit", env: runtime.env });
|
|
41303
41608
|
if (result.status === null) {
|
|
41304
41609
|
const detail = result.error?.message ?? "the assignment runner could not be started";
|
|
41305
|
-
return
|
|
41610
|
+
return refuse4(runtime, command, "assign_spawn_failed", detail);
|
|
41306
41611
|
}
|
|
41307
41612
|
return result.status;
|
|
41308
41613
|
}
|
|
@@ -41315,8 +41620,8 @@ init_config();
|
|
|
41315
41620
|
init_hub_identity();
|
|
41316
41621
|
init_envelope();
|
|
41317
41622
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
41318
|
-
import { existsSync as
|
|
41319
|
-
import { join as
|
|
41623
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync30, readFileSync as readFileSync37, readdirSync as readdirSync13, rmSync as rmSync11, writeFileSync as writeFileSync26 } from "node:fs";
|
|
41624
|
+
import { join as join51, resolve as resolve28 } from "node:path";
|
|
41320
41625
|
|
|
41321
41626
|
// node_modules/marked/lib/marked.esm.js
|
|
41322
41627
|
function A() {
|
|
@@ -47012,7 +47317,7 @@ import * as path2 from "node:path";
|
|
|
47012
47317
|
|
|
47013
47318
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
47014
47319
|
import { createRequire as createRequire2 } from "node:module";
|
|
47015
|
-
import { dirname as dirname19, join as
|
|
47320
|
+
import { dirname as dirname19, join as join42 } from "node:path";
|
|
47016
47321
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
47017
47322
|
var moduleRequire = createRequire2(import.meta.url);
|
|
47018
47323
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
@@ -47021,10 +47326,10 @@ function getNativeModuleCandidates(nativePath, options = {}) {
|
|
|
47021
47326
|
const candidates = [];
|
|
47022
47327
|
try {
|
|
47023
47328
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
47024
|
-
candidates.push(
|
|
47329
|
+
candidates.push(join42(dirname19(packageEntry), "..", nativePath));
|
|
47025
47330
|
} catch {
|
|
47026
47331
|
}
|
|
47027
|
-
candidates.push(
|
|
47332
|
+
candidates.push(join42(moduleDir, "..", nativePath), join42(moduleDir, nativePath), join42(dirname19(options.execPath ?? process.execPath), nativePath));
|
|
47028
47333
|
return Array.from(new Set(candidates));
|
|
47029
47334
|
}
|
|
47030
47335
|
|
|
@@ -49754,8 +50059,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
49754
50059
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
49755
50060
|
|
|
49756
50061
|
// plugins/kxm/src/tui.ts
|
|
49757
|
-
import { mkdirSync as
|
|
49758
|
-
import { join as
|
|
50062
|
+
import { mkdirSync as mkdirSync27 } from "node:fs";
|
|
50063
|
+
import { join as join46, resolve as resolve27, dirname as dirname20 } from "node:path";
|
|
49759
50064
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
49760
50065
|
|
|
49761
50066
|
// packages/core/tui/src/types/surface.ts
|
|
@@ -49899,9 +50204,9 @@ var SHARED_EFFECT_KINDS = Object.freeze([
|
|
|
49899
50204
|
// plugins/kxm/src/local-snapshot.ts
|
|
49900
50205
|
init_sqlite();
|
|
49901
50206
|
init_telemetry();
|
|
49902
|
-
import { existsSync as
|
|
50207
|
+
import { existsSync as existsSync36, readdirSync as readdirSync12, readFileSync as readFileSync32 } from "node:fs";
|
|
49903
50208
|
import { homedir as homedir6 } from "node:os";
|
|
49904
|
-
import { isAbsolute as isAbsolute10, join as
|
|
50209
|
+
import { isAbsolute as isAbsolute10, join as join45, resolve as resolve26 } from "node:path";
|
|
49905
50210
|
var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
|
|
49906
50211
|
var RUNTIME_PROJECT_KEY = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
|
|
49907
50212
|
function processExists2(pid) {
|
|
@@ -50026,36 +50331,36 @@ function readOpenMessageMetadata(database, where = OPEN_MESSAGE_WHERE, params =
|
|
|
50026
50331
|
return messages;
|
|
50027
50332
|
}
|
|
50028
50333
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
50029
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
50334
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join45(cwd, ".kxm", "state");
|
|
50030
50335
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
50031
|
-
const dataPath = configured ? resolve26(cwd, configured) :
|
|
50336
|
+
const dataPath = configured ? resolve26(cwd, configured) : join45(stateDir, "kxm.db");
|
|
50032
50337
|
return { dataPath, stateDir };
|
|
50033
50338
|
}
|
|
50034
50339
|
function resolveKxmStateRoot(stateDir, options) {
|
|
50035
|
-
if (options?.kxmStateRoot &&
|
|
50340
|
+
if (options?.kxmStateRoot && existsSync36(options.kxmStateRoot)) {
|
|
50036
50341
|
return resolve26(options.kxmStateRoot);
|
|
50037
50342
|
}
|
|
50038
|
-
if (
|
|
50343
|
+
if (existsSync36(join45(stateDir, "runtime", "registry.db")) || existsSync36(join45(stateDir, "runtime", "projects"))) {
|
|
50039
50344
|
return stateDir;
|
|
50040
50345
|
}
|
|
50041
50346
|
const env = options?.env ?? process.env;
|
|
50042
50347
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
50043
|
-
if (explicit && isAbsolute10(explicit) &&
|
|
50348
|
+
if (explicit && isAbsolute10(explicit) && existsSync36(resolve26(explicit))) {
|
|
50044
50349
|
return resolve26(explicit);
|
|
50045
50350
|
}
|
|
50046
50351
|
let base;
|
|
50047
50352
|
if (process.platform === "win32") {
|
|
50048
50353
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
50049
|
-
base = localAppData && isAbsolute10(localAppData) ? localAppData :
|
|
50354
|
+
base = localAppData && isAbsolute10(localAppData) ? localAppData : join45(homedir6(), "AppData", "Local");
|
|
50050
50355
|
base = resolve26(base, "KXM");
|
|
50051
50356
|
} else if (process.platform === "darwin") {
|
|
50052
50357
|
base = resolve26(homedir6(), "Library", "Application Support", "KXM");
|
|
50053
50358
|
} else {
|
|
50054
50359
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
50055
|
-
base = xdgState && isAbsolute10(xdgState) ? xdgState :
|
|
50360
|
+
base = xdgState && isAbsolute10(xdgState) ? xdgState : join45(homedir6(), ".local", "state");
|
|
50056
50361
|
base = resolve26(base, "kxm");
|
|
50057
50362
|
}
|
|
50058
|
-
if (
|
|
50363
|
+
if (existsSync36(base)) return base;
|
|
50059
50364
|
return void 0;
|
|
50060
50365
|
}
|
|
50061
50366
|
function readRuntimeRuns(eventDb, projectId) {
|
|
@@ -50088,7 +50393,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50088
50393
|
let legacyRuns = [];
|
|
50089
50394
|
let legacyRunTotal = 0;
|
|
50090
50395
|
let plans = [];
|
|
50091
|
-
if (
|
|
50396
|
+
if (existsSync36(dataPath)) {
|
|
50092
50397
|
hasLegacy = true;
|
|
50093
50398
|
const database = openReadOnlyDatabase(dataPath);
|
|
50094
50399
|
try {
|
|
@@ -50119,11 +50424,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50119
50424
|
let kxmRunTotal = 0;
|
|
50120
50425
|
const kxmStateRoot = scope && !scope.runtimeProjectId ? void 0 : resolveKxmStateRoot(stateDir, options);
|
|
50121
50426
|
if (kxmStateRoot) {
|
|
50122
|
-
const runtimeDir =
|
|
50123
|
-
const registryDbPath =
|
|
50124
|
-
const projectsDir =
|
|
50427
|
+
const runtimeDir = join45(kxmStateRoot, "runtime");
|
|
50428
|
+
const registryDbPath = join45(runtimeDir, "registry.db");
|
|
50429
|
+
const projectsDir = join45(runtimeDir, "projects");
|
|
50125
50430
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
50126
|
-
if (
|
|
50431
|
+
if (existsSync36(registryDbPath)) {
|
|
50127
50432
|
hasKxm = true;
|
|
50128
50433
|
try {
|
|
50129
50434
|
const regDb = openReadOnlyDatabase(registryDbPath);
|
|
@@ -50139,7 +50444,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50139
50444
|
} catch {
|
|
50140
50445
|
}
|
|
50141
50446
|
}
|
|
50142
|
-
if (!scope &&
|
|
50447
|
+
if (!scope && existsSync36(projectsDir)) {
|
|
50143
50448
|
try {
|
|
50144
50449
|
for (const entry of readdirSync12(projectsDir, { withFileTypes: true })) {
|
|
50145
50450
|
if (entry.isDirectory()) {
|
|
@@ -50151,8 +50456,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50151
50456
|
}
|
|
50152
50457
|
for (const key of projectKeys) {
|
|
50153
50458
|
if (scope && !RUNTIME_PROJECT_KEY.test(key)) continue;
|
|
50154
|
-
const eventDbPath =
|
|
50155
|
-
if (
|
|
50459
|
+
const eventDbPath = join45(projectsDir, key, "run-events.db");
|
|
50460
|
+
if (existsSync36(eventDbPath)) {
|
|
50156
50461
|
hasKxm = true;
|
|
50157
50462
|
try {
|
|
50158
50463
|
const eventDb = openReadOnlyDatabase(eventDbPath);
|
|
@@ -50170,10 +50475,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50170
50475
|
}
|
|
50171
50476
|
}
|
|
50172
50477
|
const pids = [];
|
|
50173
|
-
if (
|
|
50478
|
+
if (existsSync36(stateDir)) {
|
|
50174
50479
|
for (const file of readdirSync12(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
50175
50480
|
try {
|
|
50176
|
-
const record = JSON.parse(
|
|
50481
|
+
const record = JSON.parse(readFileSync32(join45(stateDir, file), "utf8"));
|
|
50177
50482
|
pids.push({
|
|
50178
50483
|
file,
|
|
50179
50484
|
...record.role ? { role: record.role } : {},
|
|
@@ -50212,8 +50517,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
50212
50517
|
} else {
|
|
50213
50518
|
source = "legacy";
|
|
50214
50519
|
}
|
|
50215
|
-
const telemetryFile =
|
|
50216
|
-
const spend =
|
|
50520
|
+
const telemetryFile = join45(stateDir, "telemetry.jsonl");
|
|
50521
|
+
const spend = existsSync36(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
50217
50522
|
return {
|
|
50218
50523
|
source,
|
|
50219
50524
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -50347,11 +50652,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
50347
50652
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
50348
50653
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
50349
50654
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
50350
|
-
const relativeWtPath =
|
|
50655
|
+
const relativeWtPath = join46(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
50351
50656
|
const absoluteWtPath = resolve27(repoRoot, relativeWtPath);
|
|
50352
50657
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
50353
50658
|
try {
|
|
50354
|
-
|
|
50659
|
+
mkdirSync27(dirname20(absoluteWtPath), { recursive: true });
|
|
50355
50660
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
50356
50661
|
let wtRes;
|
|
50357
50662
|
if (branchCheck.status === 0) {
|
|
@@ -51116,8 +51421,8 @@ async function runMeshTui(input) {
|
|
|
51116
51421
|
// plugins/kxm/src/session-work.ts
|
|
51117
51422
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
51118
51423
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
51119
|
-
import { existsSync as
|
|
51120
|
-
import { join as
|
|
51424
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync28, readFileSync as readFileSync33, renameSync as renameSync9, writeFileSync as writeFileSync24 } from "node:fs";
|
|
51425
|
+
import { join as join47 } from "node:path";
|
|
51121
51426
|
init_hub_binding();
|
|
51122
51427
|
init_telemetry();
|
|
51123
51428
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
@@ -51276,10 +51581,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
51276
51581
|
};
|
|
51277
51582
|
}
|
|
51278
51583
|
function readCachedSessionBrief(stateDir) {
|
|
51279
|
-
const file =
|
|
51584
|
+
const file = join47(stateDir, "session-brief.json");
|
|
51280
51585
|
try {
|
|
51281
|
-
if (!
|
|
51282
|
-
const raw =
|
|
51586
|
+
if (!existsSync37(file)) return void 0;
|
|
51587
|
+
const raw = readFileSync33(file, "utf8");
|
|
51283
51588
|
const parsed = JSON.parse(raw);
|
|
51284
51589
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
51285
51590
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -51294,18 +51599,18 @@ function readCachedSessionBrief(stateDir) {
|
|
|
51294
51599
|
}
|
|
51295
51600
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
51296
51601
|
try {
|
|
51297
|
-
|
|
51298
|
-
const file =
|
|
51602
|
+
mkdirSync28(stateDir, { recursive: true, mode: 448 });
|
|
51603
|
+
const file = join47(stateDir, "session-brief.json");
|
|
51299
51604
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
51300
|
-
|
|
51301
|
-
|
|
51605
|
+
writeFileSync24(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
51606
|
+
renameSync9(tmp, file);
|
|
51302
51607
|
} catch {
|
|
51303
51608
|
}
|
|
51304
51609
|
}
|
|
51305
51610
|
function estimateSessionCost(stateDir) {
|
|
51306
51611
|
try {
|
|
51307
|
-
const telemetryFile =
|
|
51308
|
-
if (!
|
|
51612
|
+
const telemetryFile = join47(stateDir, "telemetry.jsonl");
|
|
51613
|
+
if (!existsSync37(telemetryFile)) return void 0;
|
|
51309
51614
|
const records = readRoutingRecords(telemetryFile);
|
|
51310
51615
|
if (records.length === 0) return void 0;
|
|
51311
51616
|
let totalCost = 0;
|
|
@@ -51477,11 +51782,11 @@ init_hub_binding();
|
|
|
51477
51782
|
|
|
51478
51783
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
51479
51784
|
init_bindings();
|
|
51480
|
-
import { existsSync as
|
|
51481
|
-
import { dirname as dirname21, join as
|
|
51785
|
+
import { existsSync as existsSync38, readFileSync as readFileSync34 } from "node:fs";
|
|
51786
|
+
import { dirname as dirname21, join as join48 } from "node:path";
|
|
51482
51787
|
function packageIsKxm(root) {
|
|
51483
51788
|
try {
|
|
51484
|
-
const pkg = JSON.parse(
|
|
51789
|
+
const pkg = JSON.parse(readFileSync34(join48(root, "package.json"), "utf8"));
|
|
51485
51790
|
return pkg.name === "@kontextmind/kxm";
|
|
51486
51791
|
} catch {
|
|
51487
51792
|
return false;
|
|
@@ -51530,12 +51835,12 @@ function report(kind, root) {
|
|
|
51530
51835
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
51531
51836
|
}
|
|
51532
51837
|
function classifyInstallRoot(probe) {
|
|
51533
|
-
const piGitRoot =
|
|
51838
|
+
const piGitRoot = join48(probe.homeDir, ".pi", "agent", "git");
|
|
51534
51839
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
51535
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
51536
|
-
const pluginsRoot =
|
|
51840
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join48(probe.homeDir, ".claude");
|
|
51841
|
+
const pluginsRoot = join48(claudeHome, "plugins");
|
|
51537
51842
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
51538
|
-
const hasGit =
|
|
51843
|
+
const hasGit = existsSync38(join48(probe.repoRoot, ".git"));
|
|
51539
51844
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
51540
51845
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
51541
51846
|
return report("npm-package", probe.repoRoot);
|
|
@@ -51559,15 +51864,15 @@ init_bindings();
|
|
|
51559
51864
|
|
|
51560
51865
|
// plugins/kxm/src/kxm-update-config.ts
|
|
51561
51866
|
var import_yaml19 = __toESM(require_dist(), 1);
|
|
51562
|
-
import { existsSync as
|
|
51563
|
-
import { join as
|
|
51867
|
+
import { existsSync as existsSync39, readFileSync as readFileSync35 } from "node:fs";
|
|
51868
|
+
import { join as join49 } from "node:path";
|
|
51564
51869
|
init_bindings();
|
|
51565
51870
|
function loadKxmUpdateConfig(env = process.env) {
|
|
51566
|
-
const path4 =
|
|
51567
|
-
if (!
|
|
51871
|
+
const path4 = join49(kxmUserStateRoot({ env }), "update.yaml");
|
|
51872
|
+
if (!existsSync39(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
51568
51873
|
let parsed;
|
|
51569
51874
|
try {
|
|
51570
|
-
parsed = (0, import_yaml19.parse)(
|
|
51875
|
+
parsed = (0, import_yaml19.parse)(readFileSync35(path4, "utf8"));
|
|
51571
51876
|
} catch {
|
|
51572
51877
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
51573
51878
|
}
|
|
@@ -51595,8 +51900,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
51595
51900
|
// plugins/kxm/src/session.ts
|
|
51596
51901
|
init_protocol();
|
|
51597
51902
|
init_envelope();
|
|
51598
|
-
import { existsSync as
|
|
51599
|
-
import { join as
|
|
51903
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync25 } from "node:fs";
|
|
51904
|
+
import { join as join50 } from "node:path";
|
|
51600
51905
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
51601
51906
|
var SessionConfigError = class extends Error {
|
|
51602
51907
|
code = "session_config_invalid";
|
|
@@ -51606,12 +51911,12 @@ var SessionConfigError = class extends Error {
|
|
|
51606
51911
|
}
|
|
51607
51912
|
};
|
|
51608
51913
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
51609
|
-
const root =
|
|
51610
|
-
return [root,
|
|
51914
|
+
const root = join50(assetsDir, "workflows", workflowId);
|
|
51915
|
+
return [root, join50(root, "inputs"), join50(root, "outputs"), join50(root, "generated")];
|
|
51611
51916
|
}
|
|
51612
51917
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
51613
|
-
const root =
|
|
51614
|
-
return [root,
|
|
51918
|
+
const root = join50(assetsDir, "sessions", sessionId);
|
|
51919
|
+
return [root, join50(root, "inputs"), join50(root, "outputs")];
|
|
51615
51920
|
}
|
|
51616
51921
|
function rosterNames(configDir) {
|
|
51617
51922
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -51661,7 +51966,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
51661
51966
|
function loadRosterMap(configDir) {
|
|
51662
51967
|
const byName = /* @__PURE__ */ new Map();
|
|
51663
51968
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
51664
|
-
const path4 =
|
|
51969
|
+
const path4 = join50(configDir, file);
|
|
51665
51970
|
for (const row of loadRoster(path4, key)) {
|
|
51666
51971
|
const name = String(row.name).trim();
|
|
51667
51972
|
const lowered = name.toLowerCase();
|
|
@@ -51675,10 +51980,10 @@ function loadRosterMap(configDir) {
|
|
|
51675
51980
|
return byName;
|
|
51676
51981
|
}
|
|
51677
51982
|
function loadRoster(path4, key) {
|
|
51678
|
-
if (!
|
|
51983
|
+
if (!existsSync40(path4)) return [];
|
|
51679
51984
|
let parsed;
|
|
51680
51985
|
try {
|
|
51681
|
-
parsed = JSON.parse(
|
|
51986
|
+
parsed = JSON.parse(readFileSync36(path4, "utf8"));
|
|
51682
51987
|
} catch (error) {
|
|
51683
51988
|
throw new SessionConfigError(
|
|
51684
51989
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -51703,7 +52008,7 @@ function loadRoster(path4, key) {
|
|
|
51703
52008
|
});
|
|
51704
52009
|
}
|
|
51705
52010
|
function createSession(input) {
|
|
51706
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
52011
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join50("assets", "workflows", input.workflowId) : join50("assets", "sessions", input.id);
|
|
51707
52012
|
return {
|
|
51708
52013
|
schema: SESSION_SCHEMA,
|
|
51709
52014
|
id: input.id,
|
|
@@ -51716,11 +52021,11 @@ function createSession(input) {
|
|
|
51716
52021
|
};
|
|
51717
52022
|
}
|
|
51718
52023
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
51719
|
-
const dir =
|
|
51720
|
-
const path4 =
|
|
52024
|
+
const dir = join50(assetsDir, "sessions", session.id);
|
|
52025
|
+
const path4 = join50(dir, "session.json");
|
|
51721
52026
|
if (!dryRun) {
|
|
51722
|
-
|
|
51723
|
-
|
|
52027
|
+
mkdirSync29(dir, { recursive: true });
|
|
52028
|
+
writeFileSync25(path4, `${JSON.stringify(session, null, 2)}
|
|
51724
52029
|
`, { encoding: "utf8" });
|
|
51725
52030
|
}
|
|
51726
52031
|
return path4;
|
|
@@ -51759,9 +52064,9 @@ function moduleInstallRoot() {
|
|
|
51759
52064
|
}
|
|
51760
52065
|
}
|
|
51761
52066
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
51762
|
-
const projectFile =
|
|
51763
|
-
if (!
|
|
51764
|
-
const userFile =
|
|
52067
|
+
const projectFile = join51(runtime.dirs.workspace, "update.yaml");
|
|
52068
|
+
if (!existsSync41(projectFile)) return;
|
|
52069
|
+
const userFile = join51(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
51765
52070
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
51766
52071
|
`);
|
|
51767
52072
|
}
|
|
@@ -51845,7 +52150,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
51845
52150
|
return 2;
|
|
51846
52151
|
}
|
|
51847
52152
|
const screen = requested;
|
|
51848
|
-
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
52153
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join51(runtime.dirs.state, "kxm.db"));
|
|
51849
52154
|
if (runtime.dryRun) {
|
|
51850
52155
|
print(runtime.io, runtime.json, {
|
|
51851
52156
|
ok: true,
|
|
@@ -51900,7 +52205,7 @@ async function cmdHub(runtime) {
|
|
|
51900
52205
|
config = loadKxmUpdateConfig(runtime.env);
|
|
51901
52206
|
} catch (error) {
|
|
51902
52207
|
if (error instanceof KxmUpdateConfigError) {
|
|
51903
|
-
const yamlPath =
|
|
52208
|
+
const yamlPath = join51(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
51904
52209
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
51905
52210
|
`);
|
|
51906
52211
|
} else {
|
|
@@ -52055,7 +52360,7 @@ async function cmdHubBind(runtime, rawUrl, options = {}) {
|
|
|
52055
52360
|
...cloudFields
|
|
52056
52361
|
};
|
|
52057
52362
|
const identity = resolveProjectIdentity(runtime.dirs.workdir, runtime.env);
|
|
52058
|
-
const configFile =
|
|
52363
|
+
const configFile = join51(findConfigRoot(runtime.dirs.workdir), ".kxm", "config.yaml");
|
|
52059
52364
|
const key = {
|
|
52060
52365
|
...keyOp ? { op: keyOp } : {},
|
|
52061
52366
|
...tokenEnv ? { env: tokenEnv } : {}
|
|
@@ -52215,7 +52520,7 @@ async function cmdWorker(runtime, options) {
|
|
|
52215
52520
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
52216
52521
|
}
|
|
52217
52522
|
async function cmdStop(runtime, waitMsFlag) {
|
|
52218
|
-
const pids =
|
|
52523
|
+
const pids = existsSync41(runtime.dirs.state) ? readdirSync13(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
52219
52524
|
if (runtime.dryRun) {
|
|
52220
52525
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
52221
52526
|
return 0;
|
|
@@ -52230,7 +52535,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52230
52535
|
const orphans = [];
|
|
52231
52536
|
for (const file of pids) {
|
|
52232
52537
|
try {
|
|
52233
|
-
const record = JSON.parse(
|
|
52538
|
+
const record = JSON.parse(readFileSync37(join51(runtime.dirs.state, file), "utf8"));
|
|
52234
52539
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
52235
52540
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
52236
52541
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -52250,7 +52555,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52250
52555
|
ignored.push(file);
|
|
52251
52556
|
continue;
|
|
52252
52557
|
}
|
|
52253
|
-
|
|
52558
|
+
writeFileSync26(join51(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
52254
52559
|
`, { encoding: "utf8", mode: 384 });
|
|
52255
52560
|
requested.push(file);
|
|
52256
52561
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -52268,7 +52573,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52268
52573
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
52269
52574
|
for (const [file, record] of records) {
|
|
52270
52575
|
try {
|
|
52271
|
-
const current = JSON.parse(
|
|
52576
|
+
const current = JSON.parse(readFileSync37(join51(runtime.dirs.state, file), "utf8"));
|
|
52272
52577
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
52273
52578
|
} catch {
|
|
52274
52579
|
stopped.add(file);
|
|
@@ -52281,7 +52586,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52281
52586
|
for (const file of orphans) {
|
|
52282
52587
|
while (Date.now() <= deadlineOrphans) {
|
|
52283
52588
|
try {
|
|
52284
|
-
const current = JSON.parse(
|
|
52589
|
+
const current = JSON.parse(readFileSync37(join51(runtime.dirs.state, file), "utf8"));
|
|
52285
52590
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
52286
52591
|
} catch {
|
|
52287
52592
|
break;
|
|
@@ -52289,14 +52594,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52289
52594
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
52290
52595
|
}
|
|
52291
52596
|
try {
|
|
52292
|
-
const current = JSON.parse(
|
|
52597
|
+
const current = JSON.parse(readFileSync37(join51(runtime.dirs.state, file), "utf8"));
|
|
52293
52598
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
52294
52599
|
try {
|
|
52295
52600
|
process.kill(current.serverPid, "SIGKILL");
|
|
52296
52601
|
} catch {
|
|
52297
52602
|
}
|
|
52298
52603
|
}
|
|
52299
|
-
rmSync11(
|
|
52604
|
+
rmSync11(join51(runtime.dirs.state, file), { force: true });
|
|
52300
52605
|
} catch {
|
|
52301
52606
|
}
|
|
52302
52607
|
stopped.add(file);
|
|
@@ -52307,11 +52612,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
52307
52612
|
}
|
|
52308
52613
|
async function cmdSessionStatus(runtime) {
|
|
52309
52614
|
const stateDir = runtime.dirs.state;
|
|
52310
|
-
const names3 =
|
|
52615
|
+
const names3 = existsSync41(stateDir) ? readdirSync13(stateDir) : [];
|
|
52311
52616
|
const claims = [];
|
|
52312
52617
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
52313
52618
|
try {
|
|
52314
|
-
const record = JSON.parse(
|
|
52619
|
+
const record = JSON.parse(readFileSync37(join51(stateDir, file), "utf8"));
|
|
52315
52620
|
claims.push({
|
|
52316
52621
|
file,
|
|
52317
52622
|
role: record.role,
|
|
@@ -52326,7 +52631,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
52326
52631
|
const recoveries = [];
|
|
52327
52632
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
52328
52633
|
try {
|
|
52329
|
-
const envelope2 = JSON.parse(
|
|
52634
|
+
const envelope2 = JSON.parse(readFileSync37(join51(stateDir, file), "utf8"));
|
|
52330
52635
|
recoveries.push({
|
|
52331
52636
|
file,
|
|
52332
52637
|
reason: envelope2.reason,
|
|
@@ -52352,7 +52657,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
52352
52657
|
async function cmdAuthToken(runtime, options = {}) {
|
|
52353
52658
|
const tokenFile = sessionTokenPath(runtime.env.KXM_USER_CONFIG_DIR);
|
|
52354
52659
|
if (options.clear && runtime.dryRun) {
|
|
52355
|
-
const present =
|
|
52660
|
+
const present = existsSync41(tokenFile);
|
|
52356
52661
|
printPlan(runtime, { command: "auth token", cleared: present }, present ? [{ action: "delete", target: tokenFile }] : [], present ? "clear the session token from disk" : "no session token file to clear");
|
|
52357
52662
|
return 0;
|
|
52358
52663
|
}
|
|
@@ -52441,7 +52746,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
52441
52746
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
52442
52747
|
return 0;
|
|
52443
52748
|
}
|
|
52444
|
-
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
52749
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join51(runtime.dirs.state, "kxm.db"));
|
|
52445
52750
|
const env = {
|
|
52446
52751
|
...runtime.env,
|
|
52447
52752
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -52467,7 +52772,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
52467
52772
|
writeCache: !runtime.dryRun
|
|
52468
52773
|
});
|
|
52469
52774
|
if (runtime.dryRun) {
|
|
52470
|
-
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target:
|
|
52775
|
+
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target: join51(runtime.dirs.state, "session-brief.json") });
|
|
52471
52776
|
print(runtime.io, runtime.json, { ...brief, dryRun: true, planned }, [
|
|
52472
52777
|
options.status ? brief.statusLine : formatSessionBriefText(brief),
|
|
52473
52778
|
...planned.map((change) => `dry run: would ${change.action} ${change.target}`)
|
|
@@ -52527,7 +52832,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
52527
52832
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
52528
52833
|
];
|
|
52529
52834
|
if (!runtime.dryRun) {
|
|
52530
|
-
for (const directory of created)
|
|
52835
|
+
for (const directory of created) mkdirSync30(directory, { recursive: true });
|
|
52531
52836
|
writeSession(runtime.dirs.assets, session);
|
|
52532
52837
|
}
|
|
52533
52838
|
print(runtime.io, runtime.json, {
|
|
@@ -52551,9 +52856,9 @@ init_routing();
|
|
|
52551
52856
|
init_prices();
|
|
52552
52857
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
52553
52858
|
import { createHash as createHash19 } from "node:crypto";
|
|
52554
|
-
import { existsSync as
|
|
52859
|
+
import { existsSync as existsSync48, mkdtempSync as mkdtempSync3, readFileSync as readFileSync42, rmSync as rmSync13 } from "node:fs";
|
|
52555
52860
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
52556
|
-
import { basename as basename11, extname as extname3, join as
|
|
52861
|
+
import { basename as basename11, extname as extname3, join as join57, resolve as resolve33 } from "node:path";
|
|
52557
52862
|
import { createInterface as createInterface3 } from "node:readline";
|
|
52558
52863
|
|
|
52559
52864
|
// plugins/kxm/src/improve.ts
|
|
@@ -52561,8 +52866,8 @@ init_routing();
|
|
|
52561
52866
|
init_protocol();
|
|
52562
52867
|
init_relevance();
|
|
52563
52868
|
import { createHash as createHash18 } from "node:crypto";
|
|
52564
|
-
import { existsSync as
|
|
52565
|
-
import { join as
|
|
52869
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync31, writeFileSync as writeFileSync27 } from "node:fs";
|
|
52870
|
+
import { join as join52, relative as relative7, resolve as resolve29 } from "node:path";
|
|
52566
52871
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
52567
52872
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
52568
52873
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -52818,7 +53123,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
52818
53123
|
}
|
|
52819
53124
|
function buildImprovementReport(records, options = {}) {
|
|
52820
53125
|
const projectRoot = options.projectRoot ? resolve29(options.projectRoot) : process.cwd();
|
|
52821
|
-
const candidatesDir = options.candidatesDir ? resolve29(options.candidatesDir) :
|
|
53126
|
+
const candidatesDir = options.candidatesDir ? resolve29(options.candidatesDir) : join52(projectRoot, ".kxm", "candidates");
|
|
52822
53127
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
52823
53128
|
const groups = groupRoutingRecords(records, options);
|
|
52824
53129
|
const candidates = [];
|
|
@@ -52832,7 +53137,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
52832
53137
|
group.workflowId
|
|
52833
53138
|
);
|
|
52834
53139
|
const diffFileName = `${group.candidateId}.diff`;
|
|
52835
|
-
const diffFilePath =
|
|
53140
|
+
const diffFilePath = join52(candidatesDir, diffFileName);
|
|
52836
53141
|
const relDiffPath = relative7(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
52837
53142
|
const candidate = {
|
|
52838
53143
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -52854,12 +53159,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
52854
53159
|
createdAt: nowIso()
|
|
52855
53160
|
};
|
|
52856
53161
|
if (!options.dryRun) {
|
|
52857
|
-
if (!
|
|
52858
|
-
|
|
53162
|
+
if (!existsSync42(candidatesDir)) {
|
|
53163
|
+
mkdirSync31(candidatesDir, { recursive: true });
|
|
52859
53164
|
}
|
|
52860
|
-
|
|
52861
|
-
const jsonFilePath =
|
|
52862
|
-
|
|
53165
|
+
writeFileSync27(diffFilePath, diff, "utf8");
|
|
53166
|
+
const jsonFilePath = join52(candidatesDir, `${group.candidateId}.json`);
|
|
53167
|
+
writeFileSync27(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
52863
53168
|
}
|
|
52864
53169
|
candidates.push(candidate);
|
|
52865
53170
|
}
|
|
@@ -52889,10 +53194,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
52889
53194
|
}
|
|
52890
53195
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
52891
53196
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
52892
|
-
const path4 =
|
|
53197
|
+
const path4 = join52(improvementsDir, `${stamp}.json`);
|
|
52893
53198
|
if (!dryRun) {
|
|
52894
|
-
|
|
52895
|
-
|
|
53199
|
+
mkdirSync31(improvementsDir, { recursive: true });
|
|
53200
|
+
writeFileSync27(path4, `${JSON.stringify(report2, null, 2)}
|
|
52896
53201
|
`, { encoding: "utf8" });
|
|
52897
53202
|
}
|
|
52898
53203
|
return path4;
|
|
@@ -52982,7 +53287,7 @@ init_runtime_store();
|
|
|
52982
53287
|
init_route_switch();
|
|
52983
53288
|
init_routing();
|
|
52984
53289
|
init_telemetry();
|
|
52985
|
-
import { existsSync as
|
|
53290
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
52986
53291
|
import { resolve as resolve30 } from "node:path";
|
|
52987
53292
|
var ENGINE_EVENTS_SQL = "SELECT run_id, sequence, event_type, payload FROM events WHERE event_type IN ('routing.attempt.recorded','routing.route_switched','step.entered','run.status_changed') ORDER BY run_id, sequence";
|
|
52988
53293
|
var SIMULATED_HARNESS = "driver-simulated";
|
|
@@ -53005,7 +53310,7 @@ function readEngineRoutingRecords(path4) {
|
|
|
53005
53310
|
undecided: 0,
|
|
53006
53311
|
duplicatesDropped: 0
|
|
53007
53312
|
};
|
|
53008
|
-
if (!
|
|
53313
|
+
if (!existsSync43(path4)) return { records: [], source, routeSwitches: [] };
|
|
53009
53314
|
source.exists = true;
|
|
53010
53315
|
let rows;
|
|
53011
53316
|
let database;
|
|
@@ -53091,7 +53396,7 @@ function readEngineRoutingRecords(path4) {
|
|
|
53091
53396
|
};
|
|
53092
53397
|
}
|
|
53093
53398
|
function readJsonlSource(kind, path4) {
|
|
53094
|
-
const exists =
|
|
53399
|
+
const exists = existsSync43(path4);
|
|
53095
53400
|
const records = exists ? readRoutingRecords(path4).map((entry) => entry.routing) : [];
|
|
53096
53401
|
return { records, source: { kind, path: path4, exists, records: records.length, duplicatesDropped: 0 } };
|
|
53097
53402
|
}
|
|
@@ -53137,8 +53442,8 @@ function loadRoutingSources(options) {
|
|
|
53137
53442
|
// plugins/kxm/src/modes.ts
|
|
53138
53443
|
var import_yaml20 = __toESM(require_dist(), 1);
|
|
53139
53444
|
init_prices();
|
|
53140
|
-
import { existsSync as
|
|
53141
|
-
import { join as
|
|
53445
|
+
import { existsSync as existsSync44, readFileSync as readFileSync39 } from "node:fs";
|
|
53446
|
+
import { join as join53 } from "node:path";
|
|
53142
53447
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
53143
53448
|
schema: "kxm.modes.v1",
|
|
53144
53449
|
majorModes: {
|
|
@@ -53201,12 +53506,12 @@ function loadModesConfig(projectRoot) {
|
|
|
53201
53506
|
if (!projectRoot) {
|
|
53202
53507
|
return DEFAULT_MODES_CONFIG;
|
|
53203
53508
|
}
|
|
53204
|
-
const modesPath =
|
|
53205
|
-
if (!
|
|
53509
|
+
const modesPath = join53(projectRoot, ".kxm", "modes.yaml");
|
|
53510
|
+
if (!existsSync44(modesPath)) {
|
|
53206
53511
|
return DEFAULT_MODES_CONFIG;
|
|
53207
53512
|
}
|
|
53208
53513
|
try {
|
|
53209
|
-
const raw =
|
|
53514
|
+
const raw = readFileSync39(modesPath, "utf8");
|
|
53210
53515
|
const parsed = (0, import_yaml20.parse)(raw);
|
|
53211
53516
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
53212
53517
|
return {
|
|
@@ -53252,29 +53557,29 @@ var CATALOG_DATE_RE = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
|
|
|
53252
53557
|
function boundedCatalogDate(value) {
|
|
53253
53558
|
return typeof value === "string" && CATALOG_DATE_RE.test(value) ? value : void 0;
|
|
53254
53559
|
}
|
|
53255
|
-
function catalogDateForStatus(
|
|
53256
|
-
const fromLoaded = boundedCatalogDate(
|
|
53560
|
+
function catalogDateForStatus(loaded2, injected, projectRoot) {
|
|
53561
|
+
const fromLoaded = boundedCatalogDate(loaded2.catalog?.date);
|
|
53257
53562
|
if (fromLoaded) return fromLoaded;
|
|
53258
53563
|
const fromInjected = boundedCatalogDate(injected?.date);
|
|
53259
53564
|
if (fromInjected) return fromInjected;
|
|
53260
|
-
if (!
|
|
53565
|
+
if (!loaded2.stale) return void 0;
|
|
53261
53566
|
try {
|
|
53262
53567
|
return boundedCatalogDate(loadPriceCatalog(projectRoot)?.date);
|
|
53263
53568
|
} catch {
|
|
53264
53569
|
return void 0;
|
|
53265
53570
|
}
|
|
53266
53571
|
}
|
|
53267
|
-
function describePriceCatalogStatus(
|
|
53268
|
-
if (
|
|
53572
|
+
function describePriceCatalogStatus(loaded2, catalogDate) {
|
|
53573
|
+
if (loaded2.stale) {
|
|
53269
53574
|
return {
|
|
53270
53575
|
catalogStatus: "stale",
|
|
53271
53576
|
catalogReason: catalogDate ? `price catalog stale (dated ${catalogDate})` : "price catalog stale"
|
|
53272
53577
|
};
|
|
53273
53578
|
}
|
|
53274
|
-
if (
|
|
53579
|
+
if (loaded2.unavailable) {
|
|
53275
53580
|
return { catalogStatus: "corrupt", catalogReason: "price catalog corrupt" };
|
|
53276
53581
|
}
|
|
53277
|
-
if (!
|
|
53582
|
+
if (!loaded2.catalog) {
|
|
53278
53583
|
return { catalogStatus: "missing", catalogReason: "price catalog missing" };
|
|
53279
53584
|
}
|
|
53280
53585
|
return { catalogStatus: "verified", catalogReason: "price catalog verified" };
|
|
@@ -53292,11 +53597,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
53292
53597
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
53293
53598
|
});
|
|
53294
53599
|
for (const relPath of resolved.contextFiles) {
|
|
53295
|
-
const fullPath =
|
|
53600
|
+
const fullPath = join53(projectRoot, relPath);
|
|
53296
53601
|
let chars = 0;
|
|
53297
|
-
if (
|
|
53602
|
+
if (existsSync44(fullPath)) {
|
|
53298
53603
|
try {
|
|
53299
|
-
chars =
|
|
53604
|
+
chars = readFileSync39(fullPath, "utf8").length;
|
|
53300
53605
|
} catch {
|
|
53301
53606
|
chars = 0;
|
|
53302
53607
|
}
|
|
@@ -53328,14 +53633,14 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
53328
53633
|
const totalTokens = breakdown.reduce((sum, item) => sum + item.estimatedTokens, 0);
|
|
53329
53634
|
const maxContextWindow = 2e5;
|
|
53330
53635
|
const contextWindowRatio = Math.round(totalTokens / maxContextWindow * 1e3) / 10;
|
|
53331
|
-
const
|
|
53636
|
+
const loaded2 = loadPriceCatalogForEstimate(
|
|
53332
53637
|
catalog ? { priceCatalog: catalog } : { projectRoot }
|
|
53333
53638
|
);
|
|
53334
53639
|
const catalogInfo = describePriceCatalogStatus(
|
|
53335
|
-
|
|
53336
|
-
catalogDateForStatus(
|
|
53640
|
+
loaded2,
|
|
53641
|
+
catalogDateForStatus(loaded2, catalog, projectRoot)
|
|
53337
53642
|
);
|
|
53338
|
-
const cat =
|
|
53643
|
+
const cat = loaded2.catalog;
|
|
53339
53644
|
const rawModel = resolved.model || "grok/grok-4.6";
|
|
53340
53645
|
const [prov, mod] = rawModel.includes("/") ? rawModel.split("/", 2) : [void 0, rawModel];
|
|
53341
53646
|
const inputCost = cat ? calculateModelCost(cat, {
|
|
@@ -53429,9 +53734,9 @@ ${divider}
|
|
|
53429
53734
|
// plugins/kxm/src/ssh-remote.ts
|
|
53430
53735
|
init_safety_integrity();
|
|
53431
53736
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
53432
|
-
import { existsSync as
|
|
53737
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync32, readFileSync as readFileSync40, readdirSync as readdirSync14, rmSync as rmSync12, statSync as statSync7 } from "node:fs";
|
|
53433
53738
|
import { homedir as homedir8 } from "node:os";
|
|
53434
|
-
import { join as
|
|
53739
|
+
import { join as join54, resolve as resolve31 } from "node:path";
|
|
53435
53740
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
53436
53741
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
53437
53742
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -53457,12 +53762,12 @@ function truncateSshOutput(raw) {
|
|
|
53457
53762
|
return { text, truncated };
|
|
53458
53763
|
}
|
|
53459
53764
|
function parseSshConfig(configPath) {
|
|
53460
|
-
const targetPath = configPath ??
|
|
53461
|
-
if (!
|
|
53765
|
+
const targetPath = configPath ?? join54(homedir8(), ".ssh", "config");
|
|
53766
|
+
if (!existsSync45(targetPath)) {
|
|
53462
53767
|
return [];
|
|
53463
53768
|
}
|
|
53464
53769
|
try {
|
|
53465
|
-
const content =
|
|
53770
|
+
const content = readFileSync40(targetPath, "utf-8");
|
|
53466
53771
|
const lines = content.split("\n");
|
|
53467
53772
|
const hosts = [];
|
|
53468
53773
|
let currentHosts = [];
|
|
@@ -53540,14 +53845,14 @@ function resolveSshHostG(host, execFn = spawnSync14) {
|
|
|
53540
53845
|
}
|
|
53541
53846
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
53542
53847
|
const resolved = resolve31(socketDir);
|
|
53543
|
-
if (!
|
|
53544
|
-
|
|
53848
|
+
if (!existsSync45(resolved)) {
|
|
53849
|
+
mkdirSync32(resolved, { recursive: true, mode: 448 });
|
|
53545
53850
|
}
|
|
53546
53851
|
return resolved;
|
|
53547
53852
|
}
|
|
53548
53853
|
function buildSshArgs(options) {
|
|
53549
53854
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
53550
|
-
const controlPath =
|
|
53855
|
+
const controlPath = join54(socketDir, "%C");
|
|
53551
53856
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
53552
53857
|
const args = [
|
|
53553
53858
|
"-o",
|
|
@@ -53572,7 +53877,7 @@ function buildSshArgs(options) {
|
|
|
53572
53877
|
}
|
|
53573
53878
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync14) {
|
|
53574
53879
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
53575
|
-
const controlPath =
|
|
53880
|
+
const controlPath = join54(resolvedDir, "%C");
|
|
53576
53881
|
try {
|
|
53577
53882
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
53578
53883
|
encoding: "utf-8"
|
|
@@ -53584,7 +53889,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
53584
53889
|
}
|
|
53585
53890
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync14) {
|
|
53586
53891
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
53587
|
-
const controlPath =
|
|
53892
|
+
const controlPath = join54(resolvedDir, "%C");
|
|
53588
53893
|
try {
|
|
53589
53894
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
53590
53895
|
encoding: "utf-8"
|
|
@@ -54035,9 +54340,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
54035
54340
|
}
|
|
54036
54341
|
|
|
54037
54342
|
// plugins/kxm/src/completion-install.ts
|
|
54038
|
-
import { existsSync as
|
|
54343
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync33, readFileSync as readFileSync41, writeFileSync as writeFileSync28 } from "node:fs";
|
|
54039
54344
|
import { homedir as homedir9 } from "node:os";
|
|
54040
|
-
import { basename as basename10, delimiter, dirname as dirname24, isAbsolute as isAbsolute11, join as
|
|
54345
|
+
import { basename as basename10, delimiter, dirname as dirname24, isAbsolute as isAbsolute11, join as join55, resolve as resolve32 } from "node:path";
|
|
54041
54346
|
var COMPLETION_MARKER = "# kxm completion";
|
|
54042
54347
|
var PATH_MARKER = "# kxm path";
|
|
54043
54348
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -54059,25 +54364,25 @@ function completionScriptPath(shell, options = {}) {
|
|
|
54059
54364
|
const env = options.env ?? process.env;
|
|
54060
54365
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
54061
54366
|
const base = explicit && explicit.length > 0 ? resolve32(explicit) : resolve32(effectiveHome(options), ".config", "kxm");
|
|
54062
|
-
return
|
|
54367
|
+
return join55(base, "completions", `kxm.${shell}`);
|
|
54063
54368
|
}
|
|
54064
54369
|
function bashRcCandidate(options) {
|
|
54065
54370
|
const home = effectiveHome(options);
|
|
54066
|
-
const candidates = [
|
|
54067
|
-
const existing = candidates.find((candidate) =>
|
|
54371
|
+
const candidates = [join55(home, ".bashrc"), join55(home, ".bash_profile")];
|
|
54372
|
+
const existing = candidates.find((candidate) => existsSync46(candidate));
|
|
54068
54373
|
return existing ?? candidates[0];
|
|
54069
54374
|
}
|
|
54070
54375
|
function zshRcCandidate(options) {
|
|
54071
54376
|
const env = options.env ?? process.env;
|
|
54072
54377
|
const home = effectiveHome(options);
|
|
54073
|
-
if (env.ZDOTDIR?.trim()) return
|
|
54074
|
-
return
|
|
54378
|
+
if (env.ZDOTDIR?.trim()) return join55(resolve32(env.ZDOTDIR.trim()), ".zshrc");
|
|
54379
|
+
return join55(home, ".zshrc");
|
|
54075
54380
|
}
|
|
54076
54381
|
function fishCompletionTarget(shell, options) {
|
|
54077
54382
|
const env = options.env ?? process.env;
|
|
54078
54383
|
const home = effectiveHome(options);
|
|
54079
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
54080
|
-
return
|
|
54384
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join55(resolve32(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
54385
|
+
return join55(home, ".config", "fish", "completions", "kxm.fish");
|
|
54081
54386
|
}
|
|
54082
54387
|
function completionRcTarget(shell, options = {}) {
|
|
54083
54388
|
if (shell === "fish") {
|
|
@@ -54109,17 +54414,17 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
54109
54414
|
const scriptPath = completionScriptPath(shell, options);
|
|
54110
54415
|
const { rcFile } = completionRcTarget(shell, options);
|
|
54111
54416
|
const script = generateShellCompletion(shell);
|
|
54112
|
-
const existingScript =
|
|
54113
|
-
const existingScriptMatches = existingScript &&
|
|
54417
|
+
const existingScript = existsSync46(scriptPath);
|
|
54418
|
+
const existingScriptMatches = existingScript && readFileSync41(scriptPath, "utf8") === script;
|
|
54114
54419
|
let rcModified = false;
|
|
54115
54420
|
let alreadyInstalled = false;
|
|
54116
54421
|
if (shell === "fish") {
|
|
54117
54422
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
54118
|
-
const fishInstalled =
|
|
54423
|
+
const fishInstalled = existsSync46(fishTarget) && readFileSync41(fishTarget, "utf8") === script;
|
|
54119
54424
|
alreadyInstalled = fishInstalled;
|
|
54120
54425
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
54121
|
-
|
|
54122
|
-
|
|
54426
|
+
mkdirSync33(resolve32(fishTarget, ".."), { recursive: true });
|
|
54427
|
+
writeFileSync28(fishTarget, script, { encoding: "utf8" });
|
|
54123
54428
|
}
|
|
54124
54429
|
return {
|
|
54125
54430
|
ok: true,
|
|
@@ -54132,13 +54437,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
54132
54437
|
}
|
|
54133
54438
|
if (rcFile) {
|
|
54134
54439
|
const line = sourceLine(shell, scriptPath);
|
|
54135
|
-
const rcContent =
|
|
54440
|
+
const rcContent = existsSync46(rcFile) ? readFileSync41(rcFile, "utf8") : "";
|
|
54136
54441
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
54137
54442
|
}
|
|
54138
54443
|
if (!options.dryRun) {
|
|
54139
54444
|
if (!existingScriptMatches || options.overwrite) {
|
|
54140
|
-
|
|
54141
|
-
|
|
54445
|
+
mkdirSync33(resolve32(scriptPath, ".."), { recursive: true });
|
|
54446
|
+
writeFileSync28(scriptPath, script, { encoding: "utf8" });
|
|
54142
54447
|
}
|
|
54143
54448
|
if (rcFile && !alreadyInstalled) {
|
|
54144
54449
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -54147,8 +54452,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
54147
54452
|
${marker}
|
|
54148
54453
|
${line}
|
|
54149
54454
|
`;
|
|
54150
|
-
|
|
54151
|
-
|
|
54455
|
+
mkdirSync33(resolve32(rcFile, ".."), { recursive: true });
|
|
54456
|
+
writeFileSync28(rcFile, (existsSync46(rcFile) ? readFileSync41(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
54152
54457
|
rcModified = true;
|
|
54153
54458
|
}
|
|
54154
54459
|
}
|
|
@@ -54165,13 +54470,13 @@ function kxmBinDir(env = process.env) {
|
|
|
54165
54470
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
54166
54471
|
if (argv1 && isAbsolute11(argv1)) {
|
|
54167
54472
|
const dir = dirname24(argv1);
|
|
54168
|
-
if (
|
|
54473
|
+
if (existsSync46(join55(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
54169
54474
|
}
|
|
54170
54475
|
const pathEnv = env.PATH ?? "";
|
|
54171
54476
|
for (const part of pathEnv.split(delimiter)) {
|
|
54172
54477
|
if (!part) continue;
|
|
54173
54478
|
const candidate = resolve32(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
54174
|
-
if (
|
|
54479
|
+
if (existsSync46(candidate)) return resolve32(part);
|
|
54175
54480
|
}
|
|
54176
54481
|
return void 0;
|
|
54177
54482
|
}
|
|
@@ -54189,11 +54494,11 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
54189
54494
|
}
|
|
54190
54495
|
const { rcFile } = completionRcTarget(shell, options);
|
|
54191
54496
|
const line = pathLine(binDir);
|
|
54192
|
-
const rcContent =
|
|
54497
|
+
const rcContent = existsSync46(rcFile ?? "") ? readFileSync41(rcFile, "utf8") : "";
|
|
54193
54498
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
54194
54499
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
54195
|
-
|
|
54196
|
-
|
|
54500
|
+
mkdirSync33(dirname24(rcFile), { recursive: true });
|
|
54501
|
+
writeFileSync28(rcFile, rcContent + `
|
|
54197
54502
|
${PATH_MARKER}
|
|
54198
54503
|
${line}
|
|
54199
54504
|
`, { encoding: "utf8" });
|
|
@@ -54204,8 +54509,8 @@ ${line}
|
|
|
54204
54509
|
// plugins/kxm/src/init-guide-setup.ts
|
|
54205
54510
|
var import_yaml21 = __toESM(require_dist(), 1);
|
|
54206
54511
|
init_routes();
|
|
54207
|
-
import { existsSync as
|
|
54208
|
-
import { dirname as dirname25, join as
|
|
54512
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync34, writeFileSync as writeFileSync29 } from "node:fs";
|
|
54513
|
+
import { dirname as dirname25, join as join56 } from "node:path";
|
|
54209
54514
|
var ADMITTED_GUIDE_BINDINGS = Object.freeze({
|
|
54210
54515
|
"anthropic/claude-fable-5.1": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
54211
54516
|
"anthropic/fable": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
@@ -54636,7 +54941,7 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
54636
54941
|
const piMatch = binding.harness === "pi" && guidePiNoteMatches(binding);
|
|
54637
54942
|
if (binding.harness === "pi" && !piMatch) {
|
|
54638
54943
|
files.push({
|
|
54639
|
-
path:
|
|
54944
|
+
path: join56(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
54640
54945
|
content: (0, import_yaml21.stringify)(agentDocument(role, stage))
|
|
54641
54946
|
});
|
|
54642
54947
|
continue;
|
|
@@ -54654,22 +54959,22 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
54654
54959
|
modelDocument.origin = { source: GUIDE_PI_EVIDENCE_SOURCE, sha256: GUIDE_PI_EVIDENCE_SHA256 };
|
|
54655
54960
|
if (!evidenceQueued) {
|
|
54656
54961
|
files.push({
|
|
54657
|
-
path:
|
|
54962
|
+
path: join56(projectRoot, GUIDE_PI_EVIDENCE_SOURCE),
|
|
54658
54963
|
content: GUIDE_PI_EVIDENCE_NOTE
|
|
54659
54964
|
});
|
|
54660
54965
|
evidenceQueued = true;
|
|
54661
54966
|
}
|
|
54662
54967
|
}
|
|
54663
54968
|
files.push({
|
|
54664
|
-
path:
|
|
54969
|
+
path: join56(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
54665
54970
|
content: (0, import_yaml21.stringify)(agentDocument(role, stage))
|
|
54666
54971
|
});
|
|
54667
54972
|
files.push({
|
|
54668
|
-
path:
|
|
54973
|
+
path: join56(projectRoot, ".kxm", "models", `${routeId2}.yaml`),
|
|
54669
54974
|
content: (0, import_yaml21.stringify)(modelDocument)
|
|
54670
54975
|
});
|
|
54671
54976
|
files.push({
|
|
54672
|
-
path:
|
|
54977
|
+
path: join56(projectRoot, ".kxm", "roles", `${role}.yaml`),
|
|
54673
54978
|
content: (0, import_yaml21.stringify)({
|
|
54674
54979
|
schema: "kxm.role.v2",
|
|
54675
54980
|
id: role,
|
|
@@ -54682,7 +54987,7 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
54682
54987
|
}
|
|
54683
54988
|
for (const workflow of plan.workflows) {
|
|
54684
54989
|
files.push({
|
|
54685
|
-
path:
|
|
54990
|
+
path: join56(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
54686
54991
|
content: (0, import_yaml21.stringify)(workflowDocument(workflow))
|
|
54687
54992
|
});
|
|
54688
54993
|
}
|
|
@@ -54699,21 +55004,21 @@ function mergeGuideRouteAdmission(projectRoot, plan) {
|
|
|
54699
55004
|
}
|
|
54700
55005
|
if (added.length === 0) return added;
|
|
54701
55006
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
54702
|
-
const path4 =
|
|
54703
|
-
|
|
54704
|
-
|
|
55007
|
+
const path4 = join56(projectRoot, ".kxm", "routes.yaml");
|
|
55008
|
+
mkdirSync34(dirname25(path4), { recursive: true });
|
|
55009
|
+
writeFileSync29(path4, (0, import_yaml21.stringify)(policy), "utf8");
|
|
54705
55010
|
return added;
|
|
54706
55011
|
}
|
|
54707
55012
|
function writeGuideSetupFiles(files) {
|
|
54708
55013
|
const written = [];
|
|
54709
55014
|
const existed = [];
|
|
54710
55015
|
for (const file of files) {
|
|
54711
|
-
if (
|
|
55016
|
+
if (existsSync47(file.path)) {
|
|
54712
55017
|
existed.push(file.path);
|
|
54713
55018
|
continue;
|
|
54714
55019
|
}
|
|
54715
|
-
|
|
54716
|
-
|
|
55020
|
+
mkdirSync34(dirname25(file.path), { recursive: true });
|
|
55021
|
+
writeFileSync29(file.path, file.content, "utf8");
|
|
54717
55022
|
written.push(file.path);
|
|
54718
55023
|
}
|
|
54719
55024
|
return { written, existed };
|
|
@@ -54779,7 +55084,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
54779
55084
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
54780
55085
|
};
|
|
54781
55086
|
}
|
|
54782
|
-
const releaseDir = mkdtempSync3(
|
|
55087
|
+
const releaseDir = mkdtempSync3(join57(tmpdir3(), "kxm-pkg-update-"));
|
|
54783
55088
|
try {
|
|
54784
55089
|
const downloader = notice.source === "github" && !ghReleaseDownloadAvailable(runtime.env) ? "curl" : "gh";
|
|
54785
55090
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset, downloader);
|
|
@@ -54789,7 +55094,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
54789
55094
|
for (const step of planned) {
|
|
54790
55095
|
if (step.kind === "verify") {
|
|
54791
55096
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
54792
|
-
const actual =
|
|
55097
|
+
const actual = existsSync48(step.path) ? createHash19("sha256").update(readFileSync42(step.path)).digest("hex") : "missing";
|
|
54793
55098
|
return {
|
|
54794
55099
|
ok: false,
|
|
54795
55100
|
error: "release_digest_mismatch",
|
|
@@ -55067,12 +55372,12 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
55067
55372
|
}
|
|
55068
55373
|
const selectedFile = explicitFile || configuredFile;
|
|
55069
55374
|
const file = selectedFile ? resolve33(runtime.cwd, selectedFile) : void 0;
|
|
55070
|
-
if (file && !
|
|
55375
|
+
if (file && !existsSync48(file)) {
|
|
55071
55376
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
55072
55377
|
return 1;
|
|
55073
55378
|
}
|
|
55074
55379
|
try {
|
|
55075
|
-
const raw = file ?
|
|
55380
|
+
const raw = file ? readFileSync42(file, "utf8") : inline;
|
|
55076
55381
|
if (explicitFile && file && !raw.trimStart().startsWith("[")) {
|
|
55077
55382
|
const value = parseRestrictedYaml2(raw, file);
|
|
55078
55383
|
const issues = new KxmSchemaRegistry().validate("workflow", value, file);
|
|
@@ -55155,9 +55460,9 @@ function formatRoutingSource(source) {
|
|
|
55155
55460
|
return ` ${source.kind.padEnd(9)} ${source.path} (exists=${source.exists}, ${counts.join(", ")})`;
|
|
55156
55461
|
}
|
|
55157
55462
|
async function cmdImprove(runtime, options = {}) {
|
|
55158
|
-
const
|
|
55159
|
-
if (!
|
|
55160
|
-
const root =
|
|
55463
|
+
const loaded2 = loadRoutingSourcesOrReport(runtime, "improve", options.file);
|
|
55464
|
+
if (!loaded2) return 1;
|
|
55465
|
+
const root = loaded2.projectRoot ?? runtime.cwd;
|
|
55161
55466
|
let config;
|
|
55162
55467
|
try {
|
|
55163
55468
|
const userConfigDir = runtime.env.KXM_USER_CONFIG_DIR?.trim();
|
|
@@ -55167,22 +55472,22 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
55167
55472
|
print(runtime.io, runtime.json, { ok: false, command: "improve", error: "config_invalid", detail: message }, `config_invalid: ${message}`);
|
|
55168
55473
|
return 1;
|
|
55169
55474
|
}
|
|
55170
|
-
const candidatesDir = options.outDir ? resolve33(runtime.cwd, options.outDir) :
|
|
55171
|
-
const report2 = buildImprovementReport(
|
|
55475
|
+
const candidatesDir = options.outDir ? resolve33(runtime.cwd, options.outDir) : join57(root, ".kxm", "candidates");
|
|
55476
|
+
const report2 = buildImprovementReport(loaded2.records, {
|
|
55172
55477
|
candidatesDir,
|
|
55173
55478
|
projectRoot: root,
|
|
55174
55479
|
dryRun: runtime.dryRun,
|
|
55175
55480
|
promotionPolicy: config.improvement.promotionPolicy,
|
|
55176
55481
|
autoThreshold: config.improvement.autoThreshold,
|
|
55177
55482
|
halfLifeDays: config.improvement.telemetryHalfLifeDays,
|
|
55178
|
-
routeSwitches:
|
|
55483
|
+
routeSwitches: loaded2.routeSwitches
|
|
55179
55484
|
});
|
|
55180
|
-
const reportDir =
|
|
55485
|
+
const reportDir = join57(runtime.dirs.assets, "improvements");
|
|
55181
55486
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
55182
55487
|
const text = [
|
|
55183
55488
|
"Sources:",
|
|
55184
|
-
...
|
|
55185
|
-
|
|
55489
|
+
...loaded2.sources.map(formatRoutingSource),
|
|
55490
|
+
loaded2.projectRoot !== void 0 ? `Project root: ${loaded2.projectRoot}` : `Runtime store not read: no KXM project at ${runtime.cwd}`,
|
|
55186
55491
|
"",
|
|
55187
55492
|
formatImprovementReport(report2)
|
|
55188
55493
|
].join("\n");
|
|
@@ -55197,8 +55502,8 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
55197
55502
|
candidatesCount: report2.candidates.length,
|
|
55198
55503
|
candidates: report2.candidates,
|
|
55199
55504
|
report: report2,
|
|
55200
|
-
sources:
|
|
55201
|
-
projectRoot:
|
|
55505
|
+
sources: loaded2.sources,
|
|
55506
|
+
projectRoot: loaded2.projectRoot ?? null
|
|
55202
55507
|
}, text);
|
|
55203
55508
|
return 0;
|
|
55204
55509
|
}
|
|
@@ -55321,9 +55626,9 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
55321
55626
|
if (!pathNeeded) {
|
|
55322
55627
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
55323
55628
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
55324
|
-
if (rcFile &&
|
|
55629
|
+
if (rcFile && existsSync48(rcFile)) {
|
|
55325
55630
|
try {
|
|
55326
|
-
if (
|
|
55631
|
+
if (readFileSync42(rcFile, "utf8").includes(scriptPath)) return;
|
|
55327
55632
|
} catch {
|
|
55328
55633
|
}
|
|
55329
55634
|
}
|
|
@@ -55477,18 +55782,18 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
55477
55782
|
file = options.file;
|
|
55478
55783
|
records = readRoutingRecords(file).map((entry) => entry.routing);
|
|
55479
55784
|
} else {
|
|
55480
|
-
const
|
|
55481
|
-
if (!
|
|
55785
|
+
const loaded2 = loadRoutingSourcesOrReport(runtime, "routing report");
|
|
55786
|
+
if (!loaded2) return 1;
|
|
55482
55787
|
file = telemetryPath(runtime.dirs.logs);
|
|
55483
|
-
records =
|
|
55484
|
-
sources =
|
|
55485
|
-
routeSwitches =
|
|
55788
|
+
records = loaded2.records;
|
|
55789
|
+
sources = loaded2.sources;
|
|
55790
|
+
routeSwitches = loaded2.routeSwitches;
|
|
55486
55791
|
}
|
|
55487
55792
|
const includeEquivalentListCost = Boolean(options.equivalentListCost || options.listPrices);
|
|
55488
55793
|
let catalog;
|
|
55489
55794
|
if (includeEquivalentListCost) {
|
|
55490
55795
|
try {
|
|
55491
|
-
const pricesPath = options.prices ? resolve33(runtime.cwd, options.prices) :
|
|
55796
|
+
const pricesPath = options.prices ? resolve33(runtime.cwd, options.prices) : join57(runtime.dirs.workspace, "prices.yaml");
|
|
55492
55797
|
catalog = loadPriceCatalog(pricesPath);
|
|
55493
55798
|
} catch {
|
|
55494
55799
|
}
|
|
@@ -55709,7 +56014,10 @@ var DRY_RUN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
55709
56014
|
"studio layout",
|
|
55710
56015
|
"studio serve",
|
|
55711
56016
|
"docs build",
|
|
55712
|
-
"docs serve"
|
|
56017
|
+
"docs serve",
|
|
56018
|
+
"supervise status",
|
|
56019
|
+
"supervise tick",
|
|
56020
|
+
"supervise record"
|
|
55713
56021
|
]);
|
|
55714
56022
|
var DryRunRefused = class extends Error {
|
|
55715
56023
|
code;
|
|
@@ -55953,6 +56261,25 @@ function createProgram(ctx, result, argv) {
|
|
|
55953
56261
|
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
55954
56262
|
});
|
|
55955
56263
|
});
|
|
56264
|
+
const superviseCmd = addGlobalOptions(program2.command("supervise").description("Persist roadmap supervisor state across restarts"));
|
|
56265
|
+
superviseCmd.helpCommand("help", "Show supervise help");
|
|
56266
|
+
addGlobalOptions(superviseCmd.command("status").description("Show persisted in-flight lanes, pull request and CI state, and backoff timers")).action(async function superviseStatusAction() {
|
|
56267
|
+
result.code = cmdSuperviseStatus(runtimeFrom(ctx, this));
|
|
56268
|
+
});
|
|
56269
|
+
addGlobalOptions(superviseCmd.command("tick").description("Resume lanes whose backoff has elapsed and append a supervisor log line")).action(async function superviseTickAction() {
|
|
56270
|
+
result.code = cmdSuperviseTick(runtimeFrom(ctx, this));
|
|
56271
|
+
});
|
|
56272
|
+
addGlobalOptions(superviseCmd.command("record").description("Record one lane observation in the supervisor state")).requiredOption("--lane <unit>", "Lane unit").option("--pr <n>", "Last-seen pull request number").option("--merge-state <status>", "Last-seen mergeStateStatus").option("--ci-status <status>", "Last-seen CI status").option("--ci-conclusion <conclusion>", "Last-seen CI conclusion").option("--backoff-ms <n>", "Backoff from now, in milliseconds; 0 clears it").option("--settled", "Mark the lane not in flight").action(async function superviseRecordAction(options) {
|
|
56273
|
+
result.code = cmdSuperviseRecord(runtimeFrom(ctx, this), {
|
|
56274
|
+
lane: options.lane,
|
|
56275
|
+
...options.pr !== void 0 ? { pr: options.pr } : {},
|
|
56276
|
+
...options.mergeState !== void 0 ? { mergeState: options.mergeState } : {},
|
|
56277
|
+
...options.ciStatus !== void 0 ? { ciStatus: options.ciStatus } : {},
|
|
56278
|
+
...options.ciConclusion !== void 0 ? { ciConclusion: options.ciConclusion } : {},
|
|
56279
|
+
...options.backoffMs !== void 0 ? { backoffMs: options.backoffMs } : {},
|
|
56280
|
+
settled: options.settled === true
|
|
56281
|
+
});
|
|
56282
|
+
});
|
|
55956
56283
|
addGlobalOptions(program2.command("land").description("Land the current branch: verify, regenerate docs, push, pull request, rebase, unblock, squash-merge, release, and milestone")).option("--pr <n>", "Existing pull request number").option("--stage <name>", "Run one stage: verify, docs, push, pr, rebase, unblock, merge, release, or milestone").option("--title <text>", "Pull request title. Default is the subject of the first commit on the branch").option("--body-file <path>", "Pull request body file used when creating a pull request").action(async function landAction(options) {
|
|
55957
56284
|
result.code = await cmdLand(runtimeFrom(ctx, this), {
|
|
55958
56285
|
...options.pr !== void 0 ? { pr: options.pr } : {},
|