@kontextmind/kxm 0.7.120 → 0.7.122
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/.kxm/gates.yaml +24 -0
- package/.kxm/workflows/land.yaml +95 -0
- package/CHANGELOG.md +16 -0
- package/docs/contributing/assignment-runner.md +56 -22
- package/docs/guides/agent-skills.md +1 -1
- package/docs/reference/cli-reference.md +130 -1
- package/docs/reference/workflow-catalog.md +7 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +370 -169
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm/SKILL.md +2 -1
- package/plugins/kxm/skills/kxm-runs/SKILL.md +25 -1
- package/plugins/kxm/src/cli/assign.ts +144 -0
- package/plugins/kxm/src/cli/land.ts +48 -0
- package/plugins/kxm/src/cli.ts +86 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/scripts/pr-land.d.mts +2 -0
- package/scripts/pr-land.mjs +971 -0
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -18560,8 +18560,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
18560
18560
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
18561
18561
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
18562
18562
|
}
|
|
18563
|
-
const
|
|
18564
|
-
const minimumPassed =
|
|
18563
|
+
const join55 = objectValue(step.join);
|
|
18564
|
+
const minimumPassed = join55 && typeof join55.minimumPassed === "number" ? join55.minimumPassed : void 0;
|
|
18565
18565
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
18566
18566
|
const distinctBy = names(assignment?.distinctBy);
|
|
18567
18567
|
if (distinctBy.length > 0) {
|
|
@@ -20863,7 +20863,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20863
20863
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
20864
20864
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
20865
20865
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
20866
|
-
const
|
|
20866
|
+
const join55 = compileJoin(step, id, sink);
|
|
20867
20867
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
20868
20868
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
20869
20869
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -20891,7 +20891,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20891
20891
|
transitions: orderedTransitions,
|
|
20892
20892
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
20893
20893
|
assignments,
|
|
20894
|
-
join:
|
|
20894
|
+
join: join55
|
|
20895
20895
|
};
|
|
20896
20896
|
if (kind === "agent" || kind === "moa") {
|
|
20897
20897
|
if (!agent) return void 0;
|
|
@@ -20941,15 +20941,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
20941
20941
|
};
|
|
20942
20942
|
}
|
|
20943
20943
|
function compileJoin(step, stepId, sink) {
|
|
20944
|
-
const
|
|
20945
|
-
if (!
|
|
20946
|
-
const declared = stringValue2(
|
|
20944
|
+
const join55 = objectValue2(step.join);
|
|
20945
|
+
if (!join55) return { strategy: "all" };
|
|
20946
|
+
const declared = stringValue2(join55.strategy);
|
|
20947
20947
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
20948
|
-
const minimumPassed = compileOptionalCount(
|
|
20948
|
+
const minimumPassed = compileOptionalCount(join55.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
20949
20949
|
const compiled = {
|
|
20950
20950
|
strategy,
|
|
20951
20951
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
20952
|
-
...typeof
|
|
20952
|
+
...typeof join55.cancelRemaining === "boolean" ? { cancelRemaining: join55.cancelRemaining } : {}
|
|
20953
20953
|
};
|
|
20954
20954
|
return compiled;
|
|
20955
20955
|
}
|
|
@@ -30324,10 +30324,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
30324
30324
|
* @param {string} flag
|
|
30325
30325
|
* @private
|
|
30326
30326
|
*/
|
|
30327
|
-
unknownOption(
|
|
30327
|
+
unknownOption(flag2) {
|
|
30328
30328
|
if (this._allowUnknownOption) return;
|
|
30329
30329
|
let suggestion = "";
|
|
30330
|
-
if (
|
|
30330
|
+
if (flag2.startsWith("--") && this._showSuggestionAfterError) {
|
|
30331
30331
|
let candidateFlags = [];
|
|
30332
30332
|
let command = this;
|
|
30333
30333
|
do {
|
|
@@ -30335,9 +30335,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
30335
30335
|
candidateFlags = candidateFlags.concat(moreFlags);
|
|
30336
30336
|
command = command.parent;
|
|
30337
30337
|
} while (command && !command._enablePositionalOptions);
|
|
30338
|
-
suggestion = suggestSimilar(
|
|
30338
|
+
suggestion = suggestSimilar(flag2, candidateFlags);
|
|
30339
30339
|
}
|
|
30340
|
-
const message = `error: unknown option '${
|
|
30340
|
+
const message = `error: unknown option '${flag2}'${suggestion}`;
|
|
30341
30341
|
this.error(message, { code: "commander.unknownOption" });
|
|
30342
30342
|
}
|
|
30343
30343
|
/**
|
|
@@ -34136,7 +34136,7 @@ async function cmdWorkflowDefinitions(runtime, options) {
|
|
|
34136
34136
|
}
|
|
34137
34137
|
async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
34138
34138
|
const scope = options.scope ?? "local";
|
|
34139
|
-
const
|
|
34139
|
+
const refuse4 = (error, message, code = 2) => {
|
|
34140
34140
|
print(runtime.io, runtime.json, { ok: false, command: "workflow add", error, message }, `workflow add failed: ${message}`);
|
|
34141
34141
|
return code;
|
|
34142
34142
|
};
|
|
@@ -34144,12 +34144,12 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
34144
34144
|
let content;
|
|
34145
34145
|
if (options.template !== void 0) {
|
|
34146
34146
|
if (options.file !== void 0 || options.pick !== void 0) {
|
|
34147
|
-
return
|
|
34147
|
+
return refuse4("workflow_add_conflict", "--template cannot be combined with --file or --pick");
|
|
34148
34148
|
}
|
|
34149
|
-
if (!workflowId) return
|
|
34149
|
+
if (!workflowId) return refuse4("workflow_id_required", "usage: kxm workflow add <workflowId> --template <name>");
|
|
34150
34150
|
const template = Object.hasOwn(WORKFLOW_TEMPLATES, options.template) ? WORKFLOW_TEMPLATES[options.template] : void 0;
|
|
34151
34151
|
if (!template) {
|
|
34152
|
-
return
|
|
34152
|
+
return refuse4("workflow_template_unknown", `unknown template ${options.template}; choose ${Object.keys(WORKFLOW_TEMPLATES).join(", ")}`);
|
|
34153
34153
|
}
|
|
34154
34154
|
content = { ...template, ...options.description !== void 0 ? { description: options.description } : {} };
|
|
34155
34155
|
} else if (!workflowId || options.pick) {
|
|
@@ -34169,7 +34169,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
34169
34169
|
}
|
|
34170
34170
|
const picked = await resolvePickItem(runtime.io, `Select a workflow template to add (${scope})`, candidates, options.pick, runtime.env);
|
|
34171
34171
|
if (!picked) {
|
|
34172
|
-
return
|
|
34172
|
+
return refuse4("workflow_id_required", "provide a workflowId or select an available workflow with --pick <id>", 1);
|
|
34173
34173
|
}
|
|
34174
34174
|
workflowId ??= picked.id;
|
|
34175
34175
|
if (options.file === void 0) {
|
|
@@ -34191,7 +34191,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
34191
34191
|
if (scope === "local") {
|
|
34192
34192
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
34193
34193
|
if (!projectRoot) {
|
|
34194
|
-
return
|
|
34194
|
+
return refuse4("project_not_found", "local workflows belong to a KXM project; run kxm init at the repository root, or pass --scope global");
|
|
34195
34195
|
}
|
|
34196
34196
|
const issues = kxmWorkflowWriteIssues(projectRoot, workflowId, document);
|
|
34197
34197
|
if (issues.length > 0) {
|
|
@@ -34226,7 +34226,7 @@ ${issues.map((entry) => ` ${entry.file}: ${entry.code}: ${entry.message}`).join
|
|
|
34226
34226
|
);
|
|
34227
34227
|
return 0;
|
|
34228
34228
|
} catch (err) {
|
|
34229
|
-
return
|
|
34229
|
+
return refuse4("workflow_add_failed", err instanceof Error ? err.message : String(err), 1);
|
|
34230
34230
|
}
|
|
34231
34231
|
}
|
|
34232
34232
|
async function cmdWorkflowRemove(runtime, workflowId, options) {
|
|
@@ -37067,11 +37067,156 @@ async function cmdLaneRun(runtime, unit, options) {
|
|
|
37067
37067
|
});
|
|
37068
37068
|
}
|
|
37069
37069
|
|
|
37070
|
+
// plugins/kxm/src/cli/land.ts
|
|
37071
|
+
init_project_config();
|
|
37072
|
+
init_repo_root();
|
|
37073
|
+
init_types();
|
|
37074
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
37075
|
+
import { join as join36 } from "node:path";
|
|
37076
|
+
function childEnv() {
|
|
37077
|
+
const env = {};
|
|
37078
|
+
for (const [name, value] of Object.entries(process.env)) {
|
|
37079
|
+
if (value === void 0) continue;
|
|
37080
|
+
if (name.toUpperCase().startsWith("GIT_")) continue;
|
|
37081
|
+
env[name] = value;
|
|
37082
|
+
}
|
|
37083
|
+
return env;
|
|
37084
|
+
}
|
|
37085
|
+
function refuse2(runtime, error, text) {
|
|
37086
|
+
print(runtime.io, runtime.json, { ok: false, command: "land", error }, text);
|
|
37087
|
+
return 1;
|
|
37088
|
+
}
|
|
37089
|
+
function cmdLand(runtime, options = {}) {
|
|
37090
|
+
const root = discoverKxmProjectRoot(runtime.cwd);
|
|
37091
|
+
if (!root) {
|
|
37092
|
+
return Promise.resolve(refuse2(runtime, "project_required", "land requires a KXM project (run kxm init first)"));
|
|
37093
|
+
}
|
|
37094
|
+
const script = join36(findKxmRepoRoot(import.meta.url), "scripts", "pr-land.mjs");
|
|
37095
|
+
const args = [script];
|
|
37096
|
+
if (options.pr) args.push("--pr", options.pr);
|
|
37097
|
+
if (options.stage) args.push("--stage", options.stage);
|
|
37098
|
+
if (options.bodyFile) args.push("--body-file", options.bodyFile);
|
|
37099
|
+
if (runtime.json) args.push("--json");
|
|
37100
|
+
if (runtime.dryRun) args.push("--dry-run");
|
|
37101
|
+
return new Promise((resolveExit) => {
|
|
37102
|
+
const child = spawn4(process.execPath, args, { cwd: root, env: childEnv(), windowsHide: true });
|
|
37103
|
+
child.stdout.on("data", (chunk) => runtime.io.stdout(chunk.toString("utf8")));
|
|
37104
|
+
child.stderr.on("data", (chunk) => runtime.io.stderr(chunk.toString("utf8")));
|
|
37105
|
+
child.once("error", () => resolveExit(1));
|
|
37106
|
+
child.once("close", (code) => resolveExit(code ?? 1));
|
|
37107
|
+
});
|
|
37108
|
+
}
|
|
37109
|
+
|
|
37110
|
+
// plugins/kxm/src/cli/assign.ts
|
|
37111
|
+
init_project_config();
|
|
37112
|
+
init_types();
|
|
37113
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
37114
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
37115
|
+
import { join as join37 } from "node:path";
|
|
37116
|
+
var kxmAssignCliSeams = {};
|
|
37117
|
+
var RUNNER_REL = "scripts/assignment-run.mjs";
|
|
37118
|
+
function refuse3(runtime, command, error, text) {
|
|
37119
|
+
print(runtime.io, runtime.json, { ok: false, command, error }, text);
|
|
37120
|
+
return 1;
|
|
37121
|
+
}
|
|
37122
|
+
function flag(value) {
|
|
37123
|
+
if (value === void 0) throw new Error("assign invocation missing a parsed flag");
|
|
37124
|
+
return value;
|
|
37125
|
+
}
|
|
37126
|
+
function runnerArgv(subcommand, args) {
|
|
37127
|
+
switch (subcommand) {
|
|
37128
|
+
case "run":
|
|
37129
|
+
return ["run", "--manifest", flag(args.manifest)];
|
|
37130
|
+
case "witness":
|
|
37131
|
+
return ["witness", "--record-dir", flag(args.recordDir)];
|
|
37132
|
+
case "plan-current":
|
|
37133
|
+
return [
|
|
37134
|
+
"plan-current",
|
|
37135
|
+
"--task-dir",
|
|
37136
|
+
flag(args.taskDir),
|
|
37137
|
+
"--plan",
|
|
37138
|
+
flag(args.plan),
|
|
37139
|
+
"--sha256",
|
|
37140
|
+
flag(args.sha256),
|
|
37141
|
+
"--base-commit",
|
|
37142
|
+
flag(args.baseCommit),
|
|
37143
|
+
"--expected-generation",
|
|
37144
|
+
flag(args.expectedGeneration)
|
|
37145
|
+
];
|
|
37146
|
+
case "attribute":
|
|
37147
|
+
return [
|
|
37148
|
+
"attribute",
|
|
37149
|
+
"--task-dir",
|
|
37150
|
+
flag(args.taskDir),
|
|
37151
|
+
"--record-dir",
|
|
37152
|
+
flag(args.recordDir),
|
|
37153
|
+
"--class",
|
|
37154
|
+
flag(args.classification),
|
|
37155
|
+
"--explanation-file",
|
|
37156
|
+
flag(args.explanationFile)
|
|
37157
|
+
];
|
|
37158
|
+
case "observe-cost":
|
|
37159
|
+
return ["observe-cost", "--task-dir", flag(args.taskDir), "--input", flag(args.input)];
|
|
37160
|
+
case "accept": {
|
|
37161
|
+
const argv = [
|
|
37162
|
+
"accept",
|
|
37163
|
+
"--task-dir",
|
|
37164
|
+
flag(args.taskDir),
|
|
37165
|
+
"--commit",
|
|
37166
|
+
flag(args.commit),
|
|
37167
|
+
"--record-dir",
|
|
37168
|
+
flag(args.recordDir)
|
|
37169
|
+
];
|
|
37170
|
+
for (const critic of args.critics ?? []) argv.push("--critic", critic);
|
|
37171
|
+
if (args.observedPr !== void 0) argv.push("--observed-pr", args.observedPr);
|
|
37172
|
+
if (args.observedCi !== void 0) argv.push("--observed-ci", args.observedCi);
|
|
37173
|
+
return argv;
|
|
37174
|
+
}
|
|
37175
|
+
case "change-report":
|
|
37176
|
+
return ["change-report", "--task-dir", flag(args.taskDir)];
|
|
37177
|
+
default: {
|
|
37178
|
+
const unreachable = subcommand;
|
|
37179
|
+
throw new Error(`unknown assign verb ${String(unreachable)}`);
|
|
37180
|
+
}
|
|
37181
|
+
}
|
|
37182
|
+
}
|
|
37183
|
+
async function cmdAssign(runtime, subcommand, args) {
|
|
37184
|
+
const command = `assign ${subcommand}`;
|
|
37185
|
+
const root = discoverKxmProjectRoot(runtime.cwd);
|
|
37186
|
+
if (!root) return refuse3(runtime, command, "project_required", `${command} requires a KXM project (run kxm init first)`);
|
|
37187
|
+
if (!existsSync30(join37(root, "scripts", "assignment-run.mjs"))) {
|
|
37188
|
+
return refuse3(runtime, command, "assign_runner_missing", `${command} requires scripts/assignment-run.mjs in the project root`);
|
|
37189
|
+
}
|
|
37190
|
+
const argv = ["node", RUNNER_REL, ...runnerArgv(subcommand, args)];
|
|
37191
|
+
if (runtime.dryRun) {
|
|
37192
|
+
const payload = { schema: CLI_RESULT_SCHEMA, ok: true, command, dryRun: true, argv };
|
|
37193
|
+
runtime.io.stdout(runtime.json ? `${JSON.stringify(payload)}
|
|
37194
|
+
` : `${argv.join(" ")}
|
|
37195
|
+
`);
|
|
37196
|
+
return 0;
|
|
37197
|
+
}
|
|
37198
|
+
const spawn5 = kxmAssignCliSeams.spawn ?? ((commandName, commandArgs, options) => {
|
|
37199
|
+
const result2 = spawnSync7(commandName, commandArgs, {
|
|
37200
|
+
cwd: options.cwd,
|
|
37201
|
+
stdio: options.stdio,
|
|
37202
|
+
env: options.env,
|
|
37203
|
+
windowsHide: true
|
|
37204
|
+
});
|
|
37205
|
+
return { status: result2.status, ...result2.error ? { error: result2.error } : {} };
|
|
37206
|
+
});
|
|
37207
|
+
const result = spawn5("node", argv.slice(1), { cwd: root, stdio: "inherit", env: runtime.env });
|
|
37208
|
+
if (result.status === null) {
|
|
37209
|
+
const detail = result.error?.message ?? "the assignment runner could not be started";
|
|
37210
|
+
return refuse3(runtime, command, "assign_spawn_failed", detail);
|
|
37211
|
+
}
|
|
37212
|
+
return result.status;
|
|
37213
|
+
}
|
|
37214
|
+
|
|
37070
37215
|
// plugins/kxm/src/cli/hub.ts
|
|
37071
37216
|
init_redact();
|
|
37072
37217
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
37073
|
-
import { existsSync as
|
|
37074
|
-
import { join as
|
|
37218
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync28, readFileSync as readFileSync35, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync25 } from "node:fs";
|
|
37219
|
+
import { join as join47, resolve as resolve28 } from "node:path";
|
|
37075
37220
|
init_hub_env();
|
|
37076
37221
|
init_envelope();
|
|
37077
37222
|
|
|
@@ -42769,7 +42914,7 @@ import * as path2 from "node:path";
|
|
|
42769
42914
|
|
|
42770
42915
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
42771
42916
|
import { createRequire as createRequire2 } from "node:module";
|
|
42772
|
-
import { dirname as dirname19, join as
|
|
42917
|
+
import { dirname as dirname19, join as join38 } from "node:path";
|
|
42773
42918
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
42774
42919
|
var moduleRequire = createRequire2(import.meta.url);
|
|
42775
42920
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
@@ -42778,10 +42923,10 @@ function getNativeModuleCandidates(nativePath, options = {}) {
|
|
|
42778
42923
|
const candidates = [];
|
|
42779
42924
|
try {
|
|
42780
42925
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
42781
|
-
candidates.push(
|
|
42926
|
+
candidates.push(join38(dirname19(packageEntry), "..", nativePath));
|
|
42782
42927
|
} catch {
|
|
42783
42928
|
}
|
|
42784
|
-
candidates.push(
|
|
42929
|
+
candidates.push(join38(moduleDir, "..", nativePath), join38(moduleDir, nativePath), join38(dirname19(options.execPath ?? process.execPath), nativePath));
|
|
42785
42930
|
return Array.from(new Set(candidates));
|
|
42786
42931
|
}
|
|
42787
42932
|
|
|
@@ -45512,8 +45657,8 @@ var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
|
45512
45657
|
|
|
45513
45658
|
// plugins/kxm/src/tui.ts
|
|
45514
45659
|
import { mkdirSync as mkdirSync25 } from "node:fs";
|
|
45515
|
-
import { join as
|
|
45516
|
-
import { spawnSync as
|
|
45660
|
+
import { join as join42, resolve as resolve27, dirname as dirname20 } from "node:path";
|
|
45661
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45517
45662
|
|
|
45518
45663
|
// packages/core/tui/src/types/surface.ts
|
|
45519
45664
|
var KXM_TUI_LIMITS = Object.freeze({
|
|
@@ -45656,9 +45801,9 @@ var SHARED_EFFECT_KINDS = Object.freeze([
|
|
|
45656
45801
|
// plugins/kxm/src/local-snapshot.ts
|
|
45657
45802
|
init_sqlite();
|
|
45658
45803
|
init_telemetry();
|
|
45659
|
-
import { existsSync as
|
|
45804
|
+
import { existsSync as existsSync31, readdirSync as readdirSync11, readFileSync as readFileSync30 } from "node:fs";
|
|
45660
45805
|
import { homedir as homedir6 } from "node:os";
|
|
45661
|
-
import { isAbsolute as isAbsolute9, join as
|
|
45806
|
+
import { isAbsolute as isAbsolute9, join as join41, resolve as resolve26 } from "node:path";
|
|
45662
45807
|
var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
|
|
45663
45808
|
var RUNTIME_PROJECT_KEY = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
|
|
45664
45809
|
function processExists2(pid) {
|
|
@@ -45783,36 +45928,36 @@ function readOpenMessageMetadata(database, where = OPEN_MESSAGE_WHERE, params =
|
|
|
45783
45928
|
return messages;
|
|
45784
45929
|
}
|
|
45785
45930
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
45786
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
45931
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join41(cwd, ".kxm", "state");
|
|
45787
45932
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
45788
|
-
const dataPath = configured ? resolve26(cwd, configured) :
|
|
45933
|
+
const dataPath = configured ? resolve26(cwd, configured) : join41(stateDir, "kxm.db");
|
|
45789
45934
|
return { dataPath, stateDir };
|
|
45790
45935
|
}
|
|
45791
45936
|
function resolveKxmStateRoot(stateDir, options) {
|
|
45792
|
-
if (options?.kxmStateRoot &&
|
|
45937
|
+
if (options?.kxmStateRoot && existsSync31(options.kxmStateRoot)) {
|
|
45793
45938
|
return resolve26(options.kxmStateRoot);
|
|
45794
45939
|
}
|
|
45795
|
-
if (
|
|
45940
|
+
if (existsSync31(join41(stateDir, "runtime", "registry.db")) || existsSync31(join41(stateDir, "runtime", "projects"))) {
|
|
45796
45941
|
return stateDir;
|
|
45797
45942
|
}
|
|
45798
45943
|
const env = options?.env ?? process.env;
|
|
45799
45944
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
45800
|
-
if (explicit && isAbsolute9(explicit) &&
|
|
45945
|
+
if (explicit && isAbsolute9(explicit) && existsSync31(resolve26(explicit))) {
|
|
45801
45946
|
return resolve26(explicit);
|
|
45802
45947
|
}
|
|
45803
45948
|
let base;
|
|
45804
45949
|
if (process.platform === "win32") {
|
|
45805
45950
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
45806
|
-
base = localAppData && isAbsolute9(localAppData) ? localAppData :
|
|
45951
|
+
base = localAppData && isAbsolute9(localAppData) ? localAppData : join41(homedir6(), "AppData", "Local");
|
|
45807
45952
|
base = resolve26(base, "KXM");
|
|
45808
45953
|
} else if (process.platform === "darwin") {
|
|
45809
45954
|
base = resolve26(homedir6(), "Library", "Application Support", "KXM");
|
|
45810
45955
|
} else {
|
|
45811
45956
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
45812
|
-
base = xdgState && isAbsolute9(xdgState) ? xdgState :
|
|
45957
|
+
base = xdgState && isAbsolute9(xdgState) ? xdgState : join41(homedir6(), ".local", "state");
|
|
45813
45958
|
base = resolve26(base, "kxm");
|
|
45814
45959
|
}
|
|
45815
|
-
if (
|
|
45960
|
+
if (existsSync31(base)) return base;
|
|
45816
45961
|
return void 0;
|
|
45817
45962
|
}
|
|
45818
45963
|
function readRuntimeRuns(eventDb, projectId) {
|
|
@@ -45845,7 +45990,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45845
45990
|
let legacyRuns = [];
|
|
45846
45991
|
let legacyRunTotal = 0;
|
|
45847
45992
|
let plans = [];
|
|
45848
|
-
if (
|
|
45993
|
+
if (existsSync31(dataPath)) {
|
|
45849
45994
|
hasLegacy = true;
|
|
45850
45995
|
const database = openReadOnlyDatabase(dataPath);
|
|
45851
45996
|
try {
|
|
@@ -45876,11 +46021,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45876
46021
|
let kxmRunTotal = 0;
|
|
45877
46022
|
const kxmStateRoot = scope && !scope.runtimeProjectId ? void 0 : resolveKxmStateRoot(stateDir, options);
|
|
45878
46023
|
if (kxmStateRoot) {
|
|
45879
|
-
const runtimeDir =
|
|
45880
|
-
const registryDbPath =
|
|
45881
|
-
const projectsDir =
|
|
46024
|
+
const runtimeDir = join41(kxmStateRoot, "runtime");
|
|
46025
|
+
const registryDbPath = join41(runtimeDir, "registry.db");
|
|
46026
|
+
const projectsDir = join41(runtimeDir, "projects");
|
|
45882
46027
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
45883
|
-
if (
|
|
46028
|
+
if (existsSync31(registryDbPath)) {
|
|
45884
46029
|
hasKxm = true;
|
|
45885
46030
|
try {
|
|
45886
46031
|
const regDb = openReadOnlyDatabase(registryDbPath);
|
|
@@ -45896,7 +46041,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45896
46041
|
} catch {
|
|
45897
46042
|
}
|
|
45898
46043
|
}
|
|
45899
|
-
if (!scope &&
|
|
46044
|
+
if (!scope && existsSync31(projectsDir)) {
|
|
45900
46045
|
try {
|
|
45901
46046
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
45902
46047
|
if (entry.isDirectory()) {
|
|
@@ -45908,8 +46053,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45908
46053
|
}
|
|
45909
46054
|
for (const key of projectKeys) {
|
|
45910
46055
|
if (scope && !RUNTIME_PROJECT_KEY.test(key)) continue;
|
|
45911
|
-
const eventDbPath =
|
|
45912
|
-
if (
|
|
46056
|
+
const eventDbPath = join41(projectsDir, key, "run-events.db");
|
|
46057
|
+
if (existsSync31(eventDbPath)) {
|
|
45913
46058
|
hasKxm = true;
|
|
45914
46059
|
try {
|
|
45915
46060
|
const eventDb = openReadOnlyDatabase(eventDbPath);
|
|
@@ -45927,10 +46072,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45927
46072
|
}
|
|
45928
46073
|
}
|
|
45929
46074
|
const pids = [];
|
|
45930
|
-
if (
|
|
46075
|
+
if (existsSync31(stateDir)) {
|
|
45931
46076
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
45932
46077
|
try {
|
|
45933
|
-
const record = JSON.parse(readFileSync30(
|
|
46078
|
+
const record = JSON.parse(readFileSync30(join41(stateDir, file), "utf8"));
|
|
45934
46079
|
pids.push({
|
|
45935
46080
|
file,
|
|
45936
46081
|
...record.role ? { role: record.role } : {},
|
|
@@ -45969,8 +46114,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
45969
46114
|
} else {
|
|
45970
46115
|
source = "legacy";
|
|
45971
46116
|
}
|
|
45972
|
-
const telemetryFile =
|
|
45973
|
-
const spend =
|
|
46117
|
+
const telemetryFile = join41(stateDir, "telemetry.jsonl");
|
|
46118
|
+
const spend = existsSync31(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
45974
46119
|
return {
|
|
45975
46120
|
source,
|
|
45976
46121
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -46070,16 +46215,16 @@ function applyMeshTuiKey(view, key, itemCount = 0) {
|
|
|
46070
46215
|
function copyToClipboard(text) {
|
|
46071
46216
|
try {
|
|
46072
46217
|
if (process.platform === "darwin") {
|
|
46073
|
-
const proc =
|
|
46218
|
+
const proc = spawnSync8("pbcopy", { input: text, encoding: "utf8", windowsHide: true });
|
|
46074
46219
|
return proc.status === 0;
|
|
46075
46220
|
}
|
|
46076
46221
|
if (process.platform === "win32") {
|
|
46077
|
-
const proc =
|
|
46222
|
+
const proc = spawnSync8("clip", { input: text, encoding: "utf8", windowsHide: true });
|
|
46078
46223
|
return proc.status === 0;
|
|
46079
46224
|
}
|
|
46080
|
-
const wl =
|
|
46225
|
+
const wl = spawnSync8("wl-copy", [text], { encoding: "utf8", windowsHide: true });
|
|
46081
46226
|
if (wl.status === 0) return true;
|
|
46082
|
-
const xclip =
|
|
46227
|
+
const xclip = spawnSync8("xclip", ["-selection", "clipboard"], { input: text, encoding: "utf8", windowsHide: true });
|
|
46083
46228
|
return xclip.status === 0;
|
|
46084
46229
|
} catch {
|
|
46085
46230
|
return false;
|
|
@@ -46087,7 +46232,7 @@ function copyToClipboard(text) {
|
|
|
46087
46232
|
}
|
|
46088
46233
|
function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
46089
46234
|
const runner = options?.execFn ?? ((cmd, args) => {
|
|
46090
|
-
const res =
|
|
46235
|
+
const res = spawnSync8(cmd, args, {
|
|
46091
46236
|
cwd: repoRoot,
|
|
46092
46237
|
encoding: "utf8",
|
|
46093
46238
|
windowsHide: true,
|
|
@@ -46104,7 +46249,7 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
46104
46249
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
46105
46250
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
46106
46251
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
46107
|
-
const relativeWtPath =
|
|
46252
|
+
const relativeWtPath = join42(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
46108
46253
|
const absoluteWtPath = resolve27(repoRoot, relativeWtPath);
|
|
46109
46254
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
46110
46255
|
try {
|
|
@@ -46871,10 +47016,10 @@ async function runMeshTui(input) {
|
|
|
46871
47016
|
}
|
|
46872
47017
|
|
|
46873
47018
|
// plugins/kxm/src/session-work.ts
|
|
46874
|
-
import { spawnSync as
|
|
47019
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
46875
47020
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
46876
|
-
import { existsSync as
|
|
46877
|
-
import { join as
|
|
47021
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync31, renameSync as renameSync8, writeFileSync as writeFileSync23 } from "node:fs";
|
|
47022
|
+
import { join as join43 } from "node:path";
|
|
46878
47023
|
init_hub_binding();
|
|
46879
47024
|
init_telemetry();
|
|
46880
47025
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
@@ -46932,10 +47077,10 @@ function formatShipLine(ship) {
|
|
|
46932
47077
|
}
|
|
46933
47078
|
function readGitShip(cwd) {
|
|
46934
47079
|
try {
|
|
46935
|
-
const dirty =
|
|
47080
|
+
const dirty = spawnSync9("git", ["-C", cwd, "status", "--porcelain"], { encoding: "utf8", windowsHide: true });
|
|
46936
47081
|
if (dirty.status !== 0) return void 0;
|
|
46937
47082
|
const isDirty = dirty.stdout.trim().length > 0;
|
|
46938
|
-
const upstream =
|
|
47083
|
+
const upstream = spawnSync9("git", ["-C", cwd, "rev-list", "--count", "@{u}..HEAD"], { encoding: "utf8", windowsHide: true });
|
|
46939
47084
|
if (upstream.status === 0) {
|
|
46940
47085
|
return {
|
|
46941
47086
|
dirty: isDirty,
|
|
@@ -46943,9 +47088,9 @@ function readGitShip(cwd) {
|
|
|
46943
47088
|
};
|
|
46944
47089
|
}
|
|
46945
47090
|
for (const baseRef of ["origin/HEAD", "main", "origin/main", "master", "origin/master"]) {
|
|
46946
|
-
const mb =
|
|
47091
|
+
const mb = spawnSync9("git", ["-C", cwd, "merge-base", baseRef, "HEAD"], { encoding: "utf8", windowsHide: true });
|
|
46947
47092
|
if (mb.status === 0 && mb.stdout.trim()) {
|
|
46948
|
-
const count =
|
|
47093
|
+
const count = spawnSync9("git", ["-C", cwd, "rev-list", "--count", `${mb.stdout.trim()}..HEAD`], { encoding: "utf8", windowsHide: true });
|
|
46949
47094
|
if (count.status === 0) {
|
|
46950
47095
|
return {
|
|
46951
47096
|
dirty: isDirty,
|
|
@@ -47033,9 +47178,9 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
47033
47178
|
};
|
|
47034
47179
|
}
|
|
47035
47180
|
function readCachedSessionBrief(stateDir) {
|
|
47036
|
-
const file =
|
|
47181
|
+
const file = join43(stateDir, "session-brief.json");
|
|
47037
47182
|
try {
|
|
47038
|
-
if (!
|
|
47183
|
+
if (!existsSync32(file)) return void 0;
|
|
47039
47184
|
const raw = readFileSync31(file, "utf8");
|
|
47040
47185
|
const parsed = JSON.parse(raw);
|
|
47041
47186
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
@@ -47052,7 +47197,7 @@ function readCachedSessionBrief(stateDir) {
|
|
|
47052
47197
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
47053
47198
|
try {
|
|
47054
47199
|
mkdirSync26(stateDir, { recursive: true, mode: 448 });
|
|
47055
|
-
const file =
|
|
47200
|
+
const file = join43(stateDir, "session-brief.json");
|
|
47056
47201
|
const tmp = `${file}.tmp.${randomUUID12().slice(0, 8)}`;
|
|
47057
47202
|
writeFileSync23(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
47058
47203
|
renameSync8(tmp, file);
|
|
@@ -47061,8 +47206,8 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
47061
47206
|
}
|
|
47062
47207
|
function estimateSessionCost(stateDir) {
|
|
47063
47208
|
try {
|
|
47064
|
-
const telemetryFile =
|
|
47065
|
-
if (!
|
|
47209
|
+
const telemetryFile = join43(stateDir, "telemetry.jsonl");
|
|
47210
|
+
if (!existsSync32(telemetryFile)) return void 0;
|
|
47066
47211
|
const records = readRoutingRecords(telemetryFile);
|
|
47067
47212
|
if (records.length === 0) return void 0;
|
|
47068
47213
|
let totalCost = 0;
|
|
@@ -47234,11 +47379,11 @@ init_hub_binding();
|
|
|
47234
47379
|
|
|
47235
47380
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
47236
47381
|
init_bindings();
|
|
47237
|
-
import { existsSync as
|
|
47238
|
-
import { dirname as dirname21, join as
|
|
47382
|
+
import { existsSync as existsSync33, readFileSync as readFileSync32 } from "node:fs";
|
|
47383
|
+
import { dirname as dirname21, join as join44 } from "node:path";
|
|
47239
47384
|
function packageIsKxm(root) {
|
|
47240
47385
|
try {
|
|
47241
|
-
const pkg = JSON.parse(readFileSync32(
|
|
47386
|
+
const pkg = JSON.parse(readFileSync32(join44(root, "package.json"), "utf8"));
|
|
47242
47387
|
return pkg.name === "@kontextmind/kxm";
|
|
47243
47388
|
} catch {
|
|
47244
47389
|
return false;
|
|
@@ -47287,12 +47432,12 @@ function report(kind, root) {
|
|
|
47287
47432
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
47288
47433
|
}
|
|
47289
47434
|
function classifyInstallRoot(probe) {
|
|
47290
|
-
const piGitRoot =
|
|
47435
|
+
const piGitRoot = join44(probe.homeDir, ".pi", "agent", "git");
|
|
47291
47436
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
47292
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
47293
|
-
const pluginsRoot =
|
|
47437
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join44(probe.homeDir, ".claude");
|
|
47438
|
+
const pluginsRoot = join44(claudeHome, "plugins");
|
|
47294
47439
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
47295
|
-
const hasGit =
|
|
47440
|
+
const hasGit = existsSync33(join44(probe.repoRoot, ".git"));
|
|
47296
47441
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
47297
47442
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
47298
47443
|
return report("npm-package", probe.repoRoot);
|
|
@@ -47316,12 +47461,12 @@ init_bindings();
|
|
|
47316
47461
|
|
|
47317
47462
|
// plugins/kxm/src/kxm-update-config.ts
|
|
47318
47463
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
47319
|
-
import { existsSync as
|
|
47320
|
-
import { join as
|
|
47464
|
+
import { existsSync as existsSync34, readFileSync as readFileSync33 } from "node:fs";
|
|
47465
|
+
import { join as join45 } from "node:path";
|
|
47321
47466
|
init_bindings();
|
|
47322
47467
|
function loadKxmUpdateConfig(env = process.env) {
|
|
47323
|
-
const path4 =
|
|
47324
|
-
if (!
|
|
47468
|
+
const path4 = join45(kxmUserStateRoot({ env }), "update.yaml");
|
|
47469
|
+
if (!existsSync34(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
47325
47470
|
let parsed;
|
|
47326
47471
|
try {
|
|
47327
47472
|
parsed = (0, import_yaml16.parse)(readFileSync33(path4, "utf8"));
|
|
@@ -47352,8 +47497,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
47352
47497
|
// plugins/kxm/src/session.ts
|
|
47353
47498
|
init_protocol();
|
|
47354
47499
|
init_envelope();
|
|
47355
|
-
import { existsSync as
|
|
47356
|
-
import { join as
|
|
47500
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync27, readFileSync as readFileSync34, writeFileSync as writeFileSync24 } from "node:fs";
|
|
47501
|
+
import { join as join46 } from "node:path";
|
|
47357
47502
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
47358
47503
|
var SessionConfigError = class extends Error {
|
|
47359
47504
|
code = "session_config_invalid";
|
|
@@ -47363,12 +47508,12 @@ var SessionConfigError = class extends Error {
|
|
|
47363
47508
|
}
|
|
47364
47509
|
};
|
|
47365
47510
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
47366
|
-
const root =
|
|
47367
|
-
return [root,
|
|
47511
|
+
const root = join46(assetsDir, "workflows", workflowId);
|
|
47512
|
+
return [root, join46(root, "inputs"), join46(root, "outputs"), join46(root, "generated")];
|
|
47368
47513
|
}
|
|
47369
47514
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
47370
|
-
const root =
|
|
47371
|
-
return [root,
|
|
47515
|
+
const root = join46(assetsDir, "sessions", sessionId);
|
|
47516
|
+
return [root, join46(root, "inputs"), join46(root, "outputs")];
|
|
47372
47517
|
}
|
|
47373
47518
|
function rosterNames(configDir) {
|
|
47374
47519
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -47418,7 +47563,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
47418
47563
|
function loadRosterMap(configDir) {
|
|
47419
47564
|
const byName = /* @__PURE__ */ new Map();
|
|
47420
47565
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
47421
|
-
const path4 =
|
|
47566
|
+
const path4 = join46(configDir, file);
|
|
47422
47567
|
for (const row of loadRoster(path4, key)) {
|
|
47423
47568
|
const name = String(row.name).trim();
|
|
47424
47569
|
const lowered = name.toLowerCase();
|
|
@@ -47432,7 +47577,7 @@ function loadRosterMap(configDir) {
|
|
|
47432
47577
|
return byName;
|
|
47433
47578
|
}
|
|
47434
47579
|
function loadRoster(path4, key) {
|
|
47435
|
-
if (!
|
|
47580
|
+
if (!existsSync35(path4)) return [];
|
|
47436
47581
|
let parsed;
|
|
47437
47582
|
try {
|
|
47438
47583
|
parsed = JSON.parse(readFileSync34(path4, "utf8"));
|
|
@@ -47460,7 +47605,7 @@ function loadRoster(path4, key) {
|
|
|
47460
47605
|
});
|
|
47461
47606
|
}
|
|
47462
47607
|
function createSession(input) {
|
|
47463
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
47608
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join46("assets", "workflows", input.workflowId) : join46("assets", "sessions", input.id);
|
|
47464
47609
|
return {
|
|
47465
47610
|
schema: SESSION_SCHEMA,
|
|
47466
47611
|
id: input.id,
|
|
@@ -47473,8 +47618,8 @@ function createSession(input) {
|
|
|
47473
47618
|
};
|
|
47474
47619
|
}
|
|
47475
47620
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
47476
|
-
const dir =
|
|
47477
|
-
const path4 =
|
|
47621
|
+
const dir = join46(assetsDir, "sessions", session.id);
|
|
47622
|
+
const path4 = join46(dir, "session.json");
|
|
47478
47623
|
if (!dryRun) {
|
|
47479
47624
|
mkdirSync27(dir, { recursive: true });
|
|
47480
47625
|
writeFileSync24(path4, `${JSON.stringify(session, null, 2)}
|
|
@@ -47530,9 +47675,9 @@ function moduleInstallRoot() {
|
|
|
47530
47675
|
}
|
|
47531
47676
|
}
|
|
47532
47677
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
47533
|
-
const projectFile =
|
|
47534
|
-
if (!
|
|
47535
|
-
const userFile =
|
|
47678
|
+
const projectFile = join47(runtime.dirs.workspace, "update.yaml");
|
|
47679
|
+
if (!existsSync36(projectFile)) return;
|
|
47680
|
+
const userFile = join47(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
47536
47681
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
47537
47682
|
`);
|
|
47538
47683
|
}
|
|
@@ -47580,7 +47725,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
47580
47725
|
return 2;
|
|
47581
47726
|
}
|
|
47582
47727
|
const screen = requested;
|
|
47583
|
-
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
47728
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join47(runtime.dirs.state, "kxm.db"));
|
|
47584
47729
|
if (runtime.dryRun) {
|
|
47585
47730
|
print(runtime.io, runtime.json, {
|
|
47586
47731
|
ok: true,
|
|
@@ -47626,7 +47771,7 @@ async function cmdHub(runtime) {
|
|
|
47626
47771
|
config = loadKxmUpdateConfig(runtime.env);
|
|
47627
47772
|
} catch (error) {
|
|
47628
47773
|
if (error instanceof KxmUpdateConfigError) {
|
|
47629
|
-
const yamlPath =
|
|
47774
|
+
const yamlPath = join47(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
47630
47775
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
47631
47776
|
`);
|
|
47632
47777
|
} else {
|
|
@@ -47813,7 +47958,7 @@ async function cmdWorker(runtime, options) {
|
|
|
47813
47958
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
47814
47959
|
}
|
|
47815
47960
|
async function cmdStop(runtime, waitMsFlag) {
|
|
47816
|
-
const pids =
|
|
47961
|
+
const pids = existsSync36(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
47817
47962
|
if (runtime.dryRun) {
|
|
47818
47963
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
47819
47964
|
return 0;
|
|
@@ -47828,7 +47973,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47828
47973
|
const orphans = [];
|
|
47829
47974
|
for (const file of pids) {
|
|
47830
47975
|
try {
|
|
47831
|
-
const record = JSON.parse(readFileSync35(
|
|
47976
|
+
const record = JSON.parse(readFileSync35(join47(runtime.dirs.state, file), "utf8"));
|
|
47832
47977
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
47833
47978
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
47834
47979
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -47848,7 +47993,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47848
47993
|
ignored.push(file);
|
|
47849
47994
|
continue;
|
|
47850
47995
|
}
|
|
47851
|
-
writeFileSync25(
|
|
47996
|
+
writeFileSync25(join47(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
47852
47997
|
`, { encoding: "utf8", mode: 384 });
|
|
47853
47998
|
requested.push(file);
|
|
47854
47999
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -47866,7 +48011,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47866
48011
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
47867
48012
|
for (const [file, record] of records) {
|
|
47868
48013
|
try {
|
|
47869
|
-
const current = JSON.parse(readFileSync35(
|
|
48014
|
+
const current = JSON.parse(readFileSync35(join47(runtime.dirs.state, file), "utf8"));
|
|
47870
48015
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
47871
48016
|
} catch {
|
|
47872
48017
|
stopped.add(file);
|
|
@@ -47879,7 +48024,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47879
48024
|
for (const file of orphans) {
|
|
47880
48025
|
while (Date.now() <= deadlineOrphans) {
|
|
47881
48026
|
try {
|
|
47882
|
-
const current = JSON.parse(readFileSync35(
|
|
48027
|
+
const current = JSON.parse(readFileSync35(join47(runtime.dirs.state, file), "utf8"));
|
|
47883
48028
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
47884
48029
|
} catch {
|
|
47885
48030
|
break;
|
|
@@ -47887,14 +48032,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47887
48032
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
47888
48033
|
}
|
|
47889
48034
|
try {
|
|
47890
|
-
const current = JSON.parse(readFileSync35(
|
|
48035
|
+
const current = JSON.parse(readFileSync35(join47(runtime.dirs.state, file), "utf8"));
|
|
47891
48036
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
47892
48037
|
try {
|
|
47893
48038
|
process.kill(current.serverPid, "SIGKILL");
|
|
47894
48039
|
} catch {
|
|
47895
48040
|
}
|
|
47896
48041
|
}
|
|
47897
|
-
rmSync11(
|
|
48042
|
+
rmSync11(join47(runtime.dirs.state, file), { force: true });
|
|
47898
48043
|
} catch {
|
|
47899
48044
|
}
|
|
47900
48045
|
stopped.add(file);
|
|
@@ -47905,11 +48050,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
47905
48050
|
}
|
|
47906
48051
|
async function cmdSessionStatus(runtime) {
|
|
47907
48052
|
const stateDir = runtime.dirs.state;
|
|
47908
|
-
const names3 =
|
|
48053
|
+
const names3 = existsSync36(stateDir) ? readdirSync12(stateDir) : [];
|
|
47909
48054
|
const claims = [];
|
|
47910
48055
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
47911
48056
|
try {
|
|
47912
|
-
const record = JSON.parse(readFileSync35(
|
|
48057
|
+
const record = JSON.parse(readFileSync35(join47(stateDir, file), "utf8"));
|
|
47913
48058
|
claims.push({
|
|
47914
48059
|
file,
|
|
47915
48060
|
role: record.role,
|
|
@@ -47924,7 +48069,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
47924
48069
|
const recoveries = [];
|
|
47925
48070
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
47926
48071
|
try {
|
|
47927
|
-
const envelope = JSON.parse(readFileSync35(
|
|
48072
|
+
const envelope = JSON.parse(readFileSync35(join47(stateDir, file), "utf8"));
|
|
47928
48073
|
recoveries.push({
|
|
47929
48074
|
file,
|
|
47930
48075
|
reason: envelope.reason,
|
|
@@ -47950,7 +48095,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
47950
48095
|
async function cmdAuthToken(runtime, options = {}) {
|
|
47951
48096
|
const tokenFile = sessionTokenPath(runtime.env.KXM_USER_CONFIG_DIR);
|
|
47952
48097
|
if (options.clear && runtime.dryRun) {
|
|
47953
|
-
const present =
|
|
48098
|
+
const present = existsSync36(tokenFile);
|
|
47954
48099
|
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");
|
|
47955
48100
|
return 0;
|
|
47956
48101
|
}
|
|
@@ -48039,7 +48184,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
48039
48184
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
48040
48185
|
return 0;
|
|
48041
48186
|
}
|
|
48042
|
-
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
48187
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join47(runtime.dirs.state, "kxm.db"));
|
|
48043
48188
|
const env = {
|
|
48044
48189
|
...runtime.env,
|
|
48045
48190
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -48065,7 +48210,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
48065
48210
|
writeCache: !runtime.dryRun
|
|
48066
48211
|
});
|
|
48067
48212
|
if (runtime.dryRun) {
|
|
48068
|
-
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target:
|
|
48213
|
+
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target: join47(runtime.dirs.state, "session-brief.json") });
|
|
48069
48214
|
print(runtime.io, runtime.json, { ...brief, dryRun: true, planned }, [
|
|
48070
48215
|
options.status ? brief.statusLine : formatSessionBriefText(brief),
|
|
48071
48216
|
...planned.map((change) => `dry run: would ${change.action} ${change.target}`)
|
|
@@ -48147,11 +48292,11 @@ init_redact();
|
|
|
48147
48292
|
init_telemetry();
|
|
48148
48293
|
init_routing();
|
|
48149
48294
|
init_prices();
|
|
48150
|
-
import { spawnSync as
|
|
48295
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
48151
48296
|
import { createHash as createHash17 } from "node:crypto";
|
|
48152
|
-
import { existsSync as
|
|
48297
|
+
import { existsSync as existsSync43, mkdtempSync as mkdtempSync3, readFileSync as readFileSync40, rmSync as rmSync13 } from "node:fs";
|
|
48153
48298
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
48154
|
-
import { basename as basename11, extname as extname3, join as
|
|
48299
|
+
import { basename as basename11, extname as extname3, join as join53, resolve as resolve33 } from "node:path";
|
|
48155
48300
|
import { createInterface as createInterface3 } from "node:readline";
|
|
48156
48301
|
|
|
48157
48302
|
// plugins/kxm/src/improve.ts
|
|
@@ -48159,8 +48304,8 @@ init_routing();
|
|
|
48159
48304
|
init_protocol();
|
|
48160
48305
|
init_relevance();
|
|
48161
48306
|
import { createHash as createHash16 } from "node:crypto";
|
|
48162
|
-
import { existsSync as
|
|
48163
|
-
import { join as
|
|
48307
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
48308
|
+
import { join as join48, relative as relative7, resolve as resolve29 } from "node:path";
|
|
48164
48309
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
48165
48310
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
48166
48311
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -48416,7 +48561,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
48416
48561
|
}
|
|
48417
48562
|
function buildImprovementReport(records, options = {}) {
|
|
48418
48563
|
const projectRoot = options.projectRoot ? resolve29(options.projectRoot) : process.cwd();
|
|
48419
|
-
const candidatesDir = options.candidatesDir ? resolve29(options.candidatesDir) :
|
|
48564
|
+
const candidatesDir = options.candidatesDir ? resolve29(options.candidatesDir) : join48(projectRoot, ".kxm", "candidates");
|
|
48420
48565
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
48421
48566
|
const groups = groupRoutingRecords(records, options);
|
|
48422
48567
|
const candidates = [];
|
|
@@ -48430,7 +48575,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
48430
48575
|
group.workflowId
|
|
48431
48576
|
);
|
|
48432
48577
|
const diffFileName = `${group.candidateId}.diff`;
|
|
48433
|
-
const diffFilePath =
|
|
48578
|
+
const diffFilePath = join48(candidatesDir, diffFileName);
|
|
48434
48579
|
const relDiffPath = relative7(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
48435
48580
|
const candidate = {
|
|
48436
48581
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -48452,11 +48597,11 @@ function buildImprovementReport(records, options = {}) {
|
|
|
48452
48597
|
createdAt: nowIso()
|
|
48453
48598
|
};
|
|
48454
48599
|
if (!options.dryRun) {
|
|
48455
|
-
if (!
|
|
48600
|
+
if (!existsSync37(candidatesDir)) {
|
|
48456
48601
|
mkdirSync29(candidatesDir, { recursive: true });
|
|
48457
48602
|
}
|
|
48458
48603
|
writeFileSync26(diffFilePath, diff, "utf8");
|
|
48459
|
-
const jsonFilePath =
|
|
48604
|
+
const jsonFilePath = join48(candidatesDir, `${group.candidateId}.json`);
|
|
48460
48605
|
writeFileSync26(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
48461
48606
|
}
|
|
48462
48607
|
candidates.push(candidate);
|
|
@@ -48485,7 +48630,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
48485
48630
|
}
|
|
48486
48631
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
48487
48632
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
48488
|
-
const path4 =
|
|
48633
|
+
const path4 = join48(improvementsDir, `${stamp}.json`);
|
|
48489
48634
|
if (!dryRun) {
|
|
48490
48635
|
mkdirSync29(improvementsDir, { recursive: true });
|
|
48491
48636
|
writeFileSync26(path4, `${JSON.stringify(report2, null, 2)}
|
|
@@ -48569,7 +48714,7 @@ init_project_config();
|
|
|
48569
48714
|
init_runtime_store();
|
|
48570
48715
|
init_routing();
|
|
48571
48716
|
init_telemetry();
|
|
48572
|
-
import { existsSync as
|
|
48717
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
48573
48718
|
import { resolve as resolve30 } from "node:path";
|
|
48574
48719
|
var ENGINE_EVENTS_SQL = "SELECT run_id, sequence, event_type, payload FROM events WHERE event_type IN ('routing.attempt.recorded','step.entered','run.status_changed') ORDER BY run_id, sequence";
|
|
48575
48720
|
var SIMULATED_HARNESS = "driver-simulated";
|
|
@@ -48592,7 +48737,7 @@ function readEngineRoutingRecords(path4) {
|
|
|
48592
48737
|
undecided: 0,
|
|
48593
48738
|
duplicatesDropped: 0
|
|
48594
48739
|
};
|
|
48595
|
-
if (!
|
|
48740
|
+
if (!existsSync38(path4)) return { records: [], source };
|
|
48596
48741
|
source.exists = true;
|
|
48597
48742
|
let rows;
|
|
48598
48743
|
let database;
|
|
@@ -48668,7 +48813,7 @@ function readEngineRoutingRecords(path4) {
|
|
|
48668
48813
|
};
|
|
48669
48814
|
}
|
|
48670
48815
|
function readJsonlSource(kind, path4) {
|
|
48671
|
-
const exists =
|
|
48816
|
+
const exists = existsSync38(path4);
|
|
48672
48817
|
const records = exists ? readRoutingRecords(path4).map((entry) => entry.routing) : [];
|
|
48673
48818
|
return { records, source: { kind, path: path4, exists, records: records.length, duplicatesDropped: 0 } };
|
|
48674
48819
|
}
|
|
@@ -48713,8 +48858,8 @@ function loadRoutingSources(options) {
|
|
|
48713
48858
|
// plugins/kxm/src/modes.ts
|
|
48714
48859
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
48715
48860
|
init_prices();
|
|
48716
|
-
import { existsSync as
|
|
48717
|
-
import { join as
|
|
48861
|
+
import { existsSync as existsSync39, readFileSync as readFileSync37 } from "node:fs";
|
|
48862
|
+
import { join as join49 } from "node:path";
|
|
48718
48863
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
48719
48864
|
schema: "kxm.modes.v1",
|
|
48720
48865
|
majorModes: {
|
|
@@ -48777,8 +48922,8 @@ function loadModesConfig(projectRoot) {
|
|
|
48777
48922
|
if (!projectRoot) {
|
|
48778
48923
|
return DEFAULT_MODES_CONFIG;
|
|
48779
48924
|
}
|
|
48780
|
-
const modesPath =
|
|
48781
|
-
if (!
|
|
48925
|
+
const modesPath = join49(projectRoot, ".kxm", "modes.yaml");
|
|
48926
|
+
if (!existsSync39(modesPath)) {
|
|
48782
48927
|
return DEFAULT_MODES_CONFIG;
|
|
48783
48928
|
}
|
|
48784
48929
|
try {
|
|
@@ -48868,9 +49013,9 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
48868
49013
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
48869
49014
|
});
|
|
48870
49015
|
for (const relPath of resolved.contextFiles) {
|
|
48871
|
-
const fullPath =
|
|
49016
|
+
const fullPath = join49(projectRoot, relPath);
|
|
48872
49017
|
let chars = 0;
|
|
48873
|
-
if (
|
|
49018
|
+
if (existsSync39(fullPath)) {
|
|
48874
49019
|
try {
|
|
48875
49020
|
chars = readFileSync37(fullPath, "utf8").length;
|
|
48876
49021
|
} catch {
|
|
@@ -49004,10 +49149,10 @@ ${divider}
|
|
|
49004
49149
|
|
|
49005
49150
|
// plugins/kxm/src/ssh-remote.ts
|
|
49006
49151
|
init_safety_integrity();
|
|
49007
|
-
import { spawnSync as
|
|
49008
|
-
import { existsSync as
|
|
49152
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
49153
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync30, readFileSync as readFileSync38, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
|
|
49009
49154
|
import { homedir as homedir8 } from "node:os";
|
|
49010
|
-
import { join as
|
|
49155
|
+
import { join as join50, resolve as resolve31 } from "node:path";
|
|
49011
49156
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
49012
49157
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
49013
49158
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -49033,8 +49178,8 @@ function truncateSshOutput(raw) {
|
|
|
49033
49178
|
return { text, truncated };
|
|
49034
49179
|
}
|
|
49035
49180
|
function parseSshConfig(configPath) {
|
|
49036
|
-
const targetPath = configPath ??
|
|
49037
|
-
if (!
|
|
49181
|
+
const targetPath = configPath ?? join50(homedir8(), ".ssh", "config");
|
|
49182
|
+
if (!existsSync40(targetPath)) {
|
|
49038
49183
|
return [];
|
|
49039
49184
|
}
|
|
49040
49185
|
try {
|
|
@@ -49080,7 +49225,7 @@ function parseSshConfig(configPath) {
|
|
|
49080
49225
|
return [];
|
|
49081
49226
|
}
|
|
49082
49227
|
}
|
|
49083
|
-
function resolveSshHostG(host, execFn =
|
|
49228
|
+
function resolveSshHostG(host, execFn = spawnSync10) {
|
|
49084
49229
|
try {
|
|
49085
49230
|
const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
|
|
49086
49231
|
if (result.status !== 0 || !result.stdout) {
|
|
@@ -49116,14 +49261,14 @@ function resolveSshHostG(host, execFn = spawnSync9) {
|
|
|
49116
49261
|
}
|
|
49117
49262
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
49118
49263
|
const resolved = resolve31(socketDir);
|
|
49119
|
-
if (!
|
|
49264
|
+
if (!existsSync40(resolved)) {
|
|
49120
49265
|
mkdirSync30(resolved, { recursive: true, mode: 448 });
|
|
49121
49266
|
}
|
|
49122
49267
|
return resolved;
|
|
49123
49268
|
}
|
|
49124
49269
|
function buildSshArgs(options) {
|
|
49125
49270
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
49126
|
-
const controlPath =
|
|
49271
|
+
const controlPath = join50(socketDir, "%C");
|
|
49127
49272
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
49128
49273
|
const args = [
|
|
49129
49274
|
"-o",
|
|
@@ -49146,9 +49291,9 @@ function buildSshArgs(options) {
|
|
|
49146
49291
|
args.push(options.host);
|
|
49147
49292
|
return args;
|
|
49148
49293
|
}
|
|
49149
|
-
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
49294
|
+
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync10) {
|
|
49150
49295
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
49151
|
-
const controlPath =
|
|
49296
|
+
const controlPath = join50(resolvedDir, "%C");
|
|
49152
49297
|
try {
|
|
49153
49298
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
49154
49299
|
encoding: "utf-8"
|
|
@@ -49158,9 +49303,9 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
49158
49303
|
return false;
|
|
49159
49304
|
}
|
|
49160
49305
|
}
|
|
49161
|
-
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
49306
|
+
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync10) {
|
|
49162
49307
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
49163
|
-
const controlPath =
|
|
49308
|
+
const controlPath = join50(resolvedDir, "%C");
|
|
49164
49309
|
try {
|
|
49165
49310
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
49166
49311
|
encoding: "utf-8"
|
|
@@ -49172,7 +49317,7 @@ function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
49172
49317
|
}
|
|
49173
49318
|
function executeSshRun(params) {
|
|
49174
49319
|
const startTime = Date.now();
|
|
49175
|
-
const execSyncFn = params.execFn ??
|
|
49320
|
+
const execSyncFn = params.execFn ?? spawnSync10;
|
|
49176
49321
|
if (params.action === "info") {
|
|
49177
49322
|
if (params.host) {
|
|
49178
49323
|
const hostInfo = resolveSshHostG(params.host, execSyncFn);
|
|
@@ -49608,9 +49753,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
49608
49753
|
}
|
|
49609
49754
|
|
|
49610
49755
|
// plugins/kxm/src/completion-install.ts
|
|
49611
|
-
import { existsSync as
|
|
49756
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync31, readFileSync as readFileSync39, writeFileSync as writeFileSync27 } from "node:fs";
|
|
49612
49757
|
import { homedir as homedir9 } from "node:os";
|
|
49613
|
-
import { basename as basename10, delimiter, dirname as dirname24, isAbsolute as isAbsolute10, join as
|
|
49758
|
+
import { basename as basename10, delimiter, dirname as dirname24, isAbsolute as isAbsolute10, join as join51, resolve as resolve32 } from "node:path";
|
|
49614
49759
|
var COMPLETION_MARKER = "# kxm completion";
|
|
49615
49760
|
var PATH_MARKER = "# kxm path";
|
|
49616
49761
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -49632,25 +49777,25 @@ function completionScriptPath(shell, options = {}) {
|
|
|
49632
49777
|
const env = options.env ?? process.env;
|
|
49633
49778
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
49634
49779
|
const base = explicit && explicit.length > 0 ? resolve32(explicit) : resolve32(effectiveHome(options), ".config", "kxm");
|
|
49635
|
-
return
|
|
49780
|
+
return join51(base, "completions", `kxm.${shell}`);
|
|
49636
49781
|
}
|
|
49637
49782
|
function bashRcCandidate(options) {
|
|
49638
49783
|
const home = effectiveHome(options);
|
|
49639
|
-
const candidates = [
|
|
49640
|
-
const existing = candidates.find((candidate) =>
|
|
49784
|
+
const candidates = [join51(home, ".bashrc"), join51(home, ".bash_profile")];
|
|
49785
|
+
const existing = candidates.find((candidate) => existsSync41(candidate));
|
|
49641
49786
|
return existing ?? candidates[0];
|
|
49642
49787
|
}
|
|
49643
49788
|
function zshRcCandidate(options) {
|
|
49644
49789
|
const env = options.env ?? process.env;
|
|
49645
49790
|
const home = effectiveHome(options);
|
|
49646
|
-
if (env.ZDOTDIR?.trim()) return
|
|
49647
|
-
return
|
|
49791
|
+
if (env.ZDOTDIR?.trim()) return join51(resolve32(env.ZDOTDIR.trim()), ".zshrc");
|
|
49792
|
+
return join51(home, ".zshrc");
|
|
49648
49793
|
}
|
|
49649
49794
|
function fishCompletionTarget(shell, options) {
|
|
49650
49795
|
const env = options.env ?? process.env;
|
|
49651
49796
|
const home = effectiveHome(options);
|
|
49652
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
49653
|
-
return
|
|
49797
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join51(resolve32(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
49798
|
+
return join51(home, ".config", "fish", "completions", "kxm.fish");
|
|
49654
49799
|
}
|
|
49655
49800
|
function completionRcTarget(shell, options = {}) {
|
|
49656
49801
|
if (shell === "fish") {
|
|
@@ -49682,13 +49827,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
49682
49827
|
const scriptPath = completionScriptPath(shell, options);
|
|
49683
49828
|
const { rcFile } = completionRcTarget(shell, options);
|
|
49684
49829
|
const script = generateShellCompletion(shell);
|
|
49685
|
-
const existingScript =
|
|
49830
|
+
const existingScript = existsSync41(scriptPath);
|
|
49686
49831
|
const existingScriptMatches = existingScript && readFileSync39(scriptPath, "utf8") === script;
|
|
49687
49832
|
let rcModified = false;
|
|
49688
49833
|
let alreadyInstalled = false;
|
|
49689
49834
|
if (shell === "fish") {
|
|
49690
49835
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
49691
|
-
const fishInstalled =
|
|
49836
|
+
const fishInstalled = existsSync41(fishTarget) && readFileSync39(fishTarget, "utf8") === script;
|
|
49692
49837
|
alreadyInstalled = fishInstalled;
|
|
49693
49838
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
49694
49839
|
mkdirSync31(resolve32(fishTarget, ".."), { recursive: true });
|
|
@@ -49705,7 +49850,7 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
49705
49850
|
}
|
|
49706
49851
|
if (rcFile) {
|
|
49707
49852
|
const line = sourceLine(shell, scriptPath);
|
|
49708
|
-
const rcContent =
|
|
49853
|
+
const rcContent = existsSync41(rcFile) ? readFileSync39(rcFile, "utf8") : "";
|
|
49709
49854
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
49710
49855
|
}
|
|
49711
49856
|
if (!options.dryRun) {
|
|
@@ -49721,7 +49866,7 @@ ${marker}
|
|
|
49721
49866
|
${line}
|
|
49722
49867
|
`;
|
|
49723
49868
|
mkdirSync31(resolve32(rcFile, ".."), { recursive: true });
|
|
49724
|
-
writeFileSync27(rcFile, (
|
|
49869
|
+
writeFileSync27(rcFile, (existsSync41(rcFile) ? readFileSync39(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
49725
49870
|
rcModified = true;
|
|
49726
49871
|
}
|
|
49727
49872
|
}
|
|
@@ -49738,13 +49883,13 @@ function kxmBinDir(env = process.env) {
|
|
|
49738
49883
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
49739
49884
|
if (argv1 && isAbsolute10(argv1)) {
|
|
49740
49885
|
const dir = dirname24(argv1);
|
|
49741
|
-
if (
|
|
49886
|
+
if (existsSync41(join51(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
49742
49887
|
}
|
|
49743
49888
|
const pathEnv = env.PATH ?? "";
|
|
49744
49889
|
for (const part of pathEnv.split(delimiter)) {
|
|
49745
49890
|
if (!part) continue;
|
|
49746
49891
|
const candidate = resolve32(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
49747
|
-
if (
|
|
49892
|
+
if (existsSync41(candidate)) return resolve32(part);
|
|
49748
49893
|
}
|
|
49749
49894
|
return void 0;
|
|
49750
49895
|
}
|
|
@@ -49762,7 +49907,7 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
49762
49907
|
}
|
|
49763
49908
|
const { rcFile } = completionRcTarget(shell, options);
|
|
49764
49909
|
const line = pathLine(binDir);
|
|
49765
|
-
const rcContent =
|
|
49910
|
+
const rcContent = existsSync41(rcFile ?? "") ? readFileSync39(rcFile, "utf8") : "";
|
|
49766
49911
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
49767
49912
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
49768
49913
|
mkdirSync31(dirname24(rcFile), { recursive: true });
|
|
@@ -49777,8 +49922,8 @@ ${line}
|
|
|
49777
49922
|
// plugins/kxm/src/init-guide-setup.ts
|
|
49778
49923
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
49779
49924
|
init_routes();
|
|
49780
|
-
import { existsSync as
|
|
49781
|
-
import { dirname as dirname25, join as
|
|
49925
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync32, writeFileSync as writeFileSync28 } from "node:fs";
|
|
49926
|
+
import { dirname as dirname25, join as join52 } from "node:path";
|
|
49782
49927
|
var ADMITTED_GUIDE_BINDINGS = Object.freeze({
|
|
49783
49928
|
"anthropic/claude-fable-5.1": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
49784
49929
|
"anthropic/fable": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
@@ -50169,13 +50314,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
50169
50314
|
const stage = roleStages.get(role);
|
|
50170
50315
|
if (!stage) continue;
|
|
50171
50316
|
files.push({
|
|
50172
|
-
path:
|
|
50317
|
+
path: join52(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
50173
50318
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
50174
50319
|
});
|
|
50175
50320
|
}
|
|
50176
50321
|
for (const workflow of plan.workflows) {
|
|
50177
50322
|
files.push({
|
|
50178
|
-
path:
|
|
50323
|
+
path: join52(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
50179
50324
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
50180
50325
|
});
|
|
50181
50326
|
}
|
|
@@ -50192,7 +50337,7 @@ function mergeGuideRouteAdmission(projectRoot, plan) {
|
|
|
50192
50337
|
}
|
|
50193
50338
|
if (added.length === 0) return added;
|
|
50194
50339
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
50195
|
-
const path4 =
|
|
50340
|
+
const path4 = join52(projectRoot, ".kxm", "routes.yaml");
|
|
50196
50341
|
mkdirSync32(dirname25(path4), { recursive: true });
|
|
50197
50342
|
writeFileSync28(path4, (0, import_yaml18.stringify)(policy), "utf8");
|
|
50198
50343
|
return added;
|
|
@@ -50201,7 +50346,7 @@ function writeGuideSetupFiles(files) {
|
|
|
50201
50346
|
const written = [];
|
|
50202
50347
|
const existed = [];
|
|
50203
50348
|
for (const file of files) {
|
|
50204
|
-
if (
|
|
50349
|
+
if (existsSync42(file.path)) {
|
|
50205
50350
|
existed.push(file.path);
|
|
50206
50351
|
continue;
|
|
50207
50352
|
}
|
|
@@ -50234,7 +50379,7 @@ init_types();
|
|
|
50234
50379
|
init_repo_root();
|
|
50235
50380
|
function cliSpawn(runtime, command, args, extra) {
|
|
50236
50381
|
if (runtime.io.spawnSync) return runtime.io.spawnSync(command, args);
|
|
50237
|
-
const result =
|
|
50382
|
+
const result = spawnSync11(command, [...args], {
|
|
50238
50383
|
encoding: "utf8",
|
|
50239
50384
|
windowsHide: true,
|
|
50240
50385
|
shell: process.platform === "win32",
|
|
@@ -50272,7 +50417,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
50272
50417
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
50273
50418
|
};
|
|
50274
50419
|
}
|
|
50275
|
-
const releaseDir = mkdtempSync3(
|
|
50420
|
+
const releaseDir = mkdtempSync3(join53(tmpdir2(), "kxm-pkg-update-"));
|
|
50276
50421
|
try {
|
|
50277
50422
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
50278
50423
|
if (runtime.dryRun) {
|
|
@@ -50281,7 +50426,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
50281
50426
|
for (const step of planned) {
|
|
50282
50427
|
if (step.kind === "verify") {
|
|
50283
50428
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
50284
|
-
const actual =
|
|
50429
|
+
const actual = existsSync43(step.path) ? createHash17("sha256").update(readFileSync40(step.path)).digest("hex") : "missing";
|
|
50285
50430
|
return {
|
|
50286
50431
|
ok: false,
|
|
50287
50432
|
error: "release_digest_mismatch",
|
|
@@ -50559,7 +50704,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
50559
50704
|
}
|
|
50560
50705
|
const selectedFile = explicitFile || configuredFile;
|
|
50561
50706
|
const file = selectedFile ? resolve33(runtime.cwd, selectedFile) : void 0;
|
|
50562
|
-
if (file && !
|
|
50707
|
+
if (file && !existsSync43(file)) {
|
|
50563
50708
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
50564
50709
|
return 1;
|
|
50565
50710
|
}
|
|
@@ -50659,7 +50804,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
50659
50804
|
print(runtime.io, runtime.json, { ok: false, command: "improve", error: "config_invalid", detail: message }, `config_invalid: ${message}`);
|
|
50660
50805
|
return 1;
|
|
50661
50806
|
}
|
|
50662
|
-
const candidatesDir = options.outDir ? resolve33(runtime.cwd, options.outDir) :
|
|
50807
|
+
const candidatesDir = options.outDir ? resolve33(runtime.cwd, options.outDir) : join53(root, ".kxm", "candidates");
|
|
50663
50808
|
const report2 = buildImprovementReport(loaded.records, {
|
|
50664
50809
|
candidatesDir,
|
|
50665
50810
|
projectRoot: root,
|
|
@@ -50668,7 +50813,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
50668
50813
|
autoThreshold: config.improvement.autoThreshold,
|
|
50669
50814
|
halfLifeDays: config.improvement.telemetryHalfLifeDays
|
|
50670
50815
|
});
|
|
50671
|
-
const reportDir =
|
|
50816
|
+
const reportDir = join53(runtime.dirs.assets, "improvements");
|
|
50672
50817
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
50673
50818
|
const text = [
|
|
50674
50819
|
"Sources:",
|
|
@@ -50812,7 +50957,7 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
50812
50957
|
if (!pathNeeded) {
|
|
50813
50958
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
50814
50959
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
50815
|
-
if (rcFile &&
|
|
50960
|
+
if (rcFile && existsSync43(rcFile)) {
|
|
50816
50961
|
try {
|
|
50817
50962
|
if (readFileSync40(rcFile, "utf8").includes(scriptPath)) return;
|
|
50818
50963
|
} catch {
|
|
@@ -50977,7 +51122,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
50977
51122
|
let catalog;
|
|
50978
51123
|
if (includeEquivalentListCost) {
|
|
50979
51124
|
try {
|
|
50980
|
-
const pricesPath = options.prices ? resolve33(runtime.cwd, options.prices) :
|
|
51125
|
+
const pricesPath = options.prices ? resolve33(runtime.cwd, options.prices) : join53(runtime.dirs.workspace, "prices.yaml");
|
|
50981
51126
|
catalog = loadPriceCatalog(pricesPath);
|
|
50982
51127
|
} catch {
|
|
50983
51128
|
}
|
|
@@ -51090,6 +51235,14 @@ var DRY_RUN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
51090
51235
|
"lane status",
|
|
51091
51236
|
"lane drop",
|
|
51092
51237
|
"lane run",
|
|
51238
|
+
"land",
|
|
51239
|
+
"assign run",
|
|
51240
|
+
"assign witness",
|
|
51241
|
+
"assign plan-current",
|
|
51242
|
+
"assign attribute",
|
|
51243
|
+
"assign observe-cost",
|
|
51244
|
+
"assign accept",
|
|
51245
|
+
"assign change-report",
|
|
51093
51246
|
"plugin install",
|
|
51094
51247
|
"plugin",
|
|
51095
51248
|
"runs status",
|
|
@@ -51391,6 +51544,54 @@ function createProgram(ctx, result) {
|
|
|
51391
51544
|
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
51392
51545
|
});
|
|
51393
51546
|
});
|
|
51547
|
+
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("--body-file <path>", "Pull request body file used when creating a pull request").action(async function landAction(options) {
|
|
51548
|
+
result.code = await cmdLand(runtimeFrom(ctx, this), {
|
|
51549
|
+
...options.pr !== void 0 ? { pr: options.pr } : {},
|
|
51550
|
+
...options.stage !== void 0 ? { stage: options.stage } : {},
|
|
51551
|
+
...options.bodyFile !== void 0 ? { bodyFile: options.bodyFile } : {}
|
|
51552
|
+
});
|
|
51553
|
+
});
|
|
51554
|
+
const assignCmd = addGlobalOptions(program2.command("assign").description("Run this repository's developer assignment runner"));
|
|
51555
|
+
assignCmd.helpCommand("help", "Show assign help");
|
|
51556
|
+
addGlobalOptions(assignCmd.command("run").description("Dispatch a bound assignment manifest")).requiredOption("--manifest <path>", "Absolute path to the assignment manifest").action(async function assignRunAction(options) {
|
|
51557
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "run", { manifest: options.manifest });
|
|
51558
|
+
});
|
|
51559
|
+
addGlobalOptions(assignCmd.command("witness").description("Run the fixed verification witness for an existing assignment")).requiredOption("--record-dir <path>", "Absolute path to the assignment record directory").action(async function assignWitnessAction(options) {
|
|
51560
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "witness", { recordDir: options.recordDir });
|
|
51561
|
+
});
|
|
51562
|
+
addGlobalOptions(assignCmd.command("plan-current").description("Stamp or advance the current-plan pointer")).requiredOption("--task-dir <path>", "Absolute path to the task directory").requiredOption("--plan <path>", "Absolute path to the plan file").requiredOption("--sha256 <hex>", "SHA-256 of the plan file").requiredOption("--base-commit <sha>", "Base commit the pointer records").requiredOption("--expected-generation <n>", "Generation the pointer must currently have").action(async function assignPlanCurrentAction(options) {
|
|
51563
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "plan-current", {
|
|
51564
|
+
taskDir: options.taskDir,
|
|
51565
|
+
plan: options.plan,
|
|
51566
|
+
sha256: options.sha256,
|
|
51567
|
+
baseCommit: options.baseCommit,
|
|
51568
|
+
expectedGeneration: options.expectedGeneration
|
|
51569
|
+
});
|
|
51570
|
+
});
|
|
51571
|
+
addGlobalOptions(assignCmd.command("attribute").description("Attach a private attribution note")).requiredOption("--task-dir <path>", "Absolute path to the task directory").requiredOption("--record-dir <path>", "Absolute path to the assignment record directory").requiredOption("--class <class>", "orchestration, model, environment, or unclassified").requiredOption("--explanation-file <path>", "Absolute path to the note file").action(async function assignAttributeAction(options) {
|
|
51572
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "attribute", {
|
|
51573
|
+
taskDir: options.taskDir,
|
|
51574
|
+
recordDir: options.recordDir,
|
|
51575
|
+
classification: options.class,
|
|
51576
|
+
explanationFile: options.explanationFile
|
|
51577
|
+
});
|
|
51578
|
+
});
|
|
51579
|
+
addGlobalOptions(assignCmd.command("observe-cost").description("Import one historical cost observation as cost-only")).requiredOption("--task-dir <path>", "Absolute path to the task directory").requiredOption("--input <path>", "Absolute path to the observation file").action(async function assignObserveCostAction(options) {
|
|
51580
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "observe-cost", { taskDir: options.taskDir, input: options.input });
|
|
51581
|
+
});
|
|
51582
|
+
addGlobalOptions(assignCmd.command("accept").description("Bind an exact witnessed commit and two critic PASS records")).requiredOption("--task-dir <path>", "Absolute path to the task directory").requiredOption("--commit <sha>", "Commit to accept").requiredOption("--record-dir <path>", "Absolute path to the writer record directory").requiredOption("--critic <path>", "Absolute path to a critic record directory; pass twice", (value, previous) => previous.concat(value), []).option("--observed-pr <id>", "Observed pull request id").option("--observed-ci <id>", "Observed CI run id").action(async function assignAcceptAction(options) {
|
|
51583
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "accept", {
|
|
51584
|
+
taskDir: options.taskDir,
|
|
51585
|
+
commit: options.commit,
|
|
51586
|
+
recordDir: options.recordDir,
|
|
51587
|
+
critics: options.critic,
|
|
51588
|
+
...options.observedPr !== void 0 ? { observedPr: options.observedPr } : {},
|
|
51589
|
+
...options.observedCi !== void 0 ? { observedCi: options.observedCi } : {}
|
|
51590
|
+
});
|
|
51591
|
+
});
|
|
51592
|
+
addGlobalOptions(assignCmd.command("change-report").description("Report attempts, rework, costs, and retained verification history")).requiredOption("--task-dir <path>", "Absolute path to the task directory").action(async function assignChangeReportAction(options) {
|
|
51593
|
+
result.code = await cmdAssign(runtimeFrom(ctx, this), "change-report", { taskDir: options.taskDir });
|
|
51594
|
+
});
|
|
51394
51595
|
addGlobalOptions(program2.command("run").description("Create a KXM run without executing steps; follow its prerequisites, then kxm runs drive <runId> --wait").argument("[workflow]", "Workflow id to run").argument("[prompt...]", "Run prompt (events keep its hash; the full text is kept in a local 0600 sidecar file)").option("--brief <file>", "Read the run prompt from a file instead of the positional prompt").option("--lane <unit>", "Discover the project from this lane's worktree").action(async function runAction(workflow2, promptParts, options) {
|
|
51395
51596
|
result.code = await cmdKxmRunCli(runtimeFrom(ctx, this), workflow2, promptParts, options);
|
|
51396
51597
|
}));
|