@kontextmind/kxm 0.7.5 → 0.7.7
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/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +43485 -42676
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime.js +693 -32
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/context-skills.ts +373 -0
- package/plugins/kxm/src/cli/hub.ts +614 -0
- package/plugins/kxm/src/cli/roles.ts +615 -0
- package/plugins/kxm/src/cli/system.ts +906 -0
- package/plugins/kxm/src/cli/tasks.ts +364 -0
- package/plugins/kxm/src/cli/types.ts +270 -0
- package/plugins/kxm/src/cli/vnext.ts +698 -0
- package/plugins/kxm/src/cli/workflows.ts +699 -0
- package/plugins/kxm/src/cli.ts +206 -4257
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/modes.ts +348 -0
- package/plugins/kxm/src/runtime.ts +2 -0
- package/plugins/kxm/src/ssh-remote.ts +560 -0
- package/schemas/vnext/modes.schema.json +56 -0
|
@@ -2986,7 +2986,7 @@ var require_compile = __commonJS({
|
|
|
2986
2986
|
const schOrFunc = root.refs[ref];
|
|
2987
2987
|
if (schOrFunc)
|
|
2988
2988
|
return schOrFunc;
|
|
2989
|
-
let _sch =
|
|
2989
|
+
let _sch = resolve9.call(this, root, ref);
|
|
2990
2990
|
if (_sch === void 0) {
|
|
2991
2991
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2992
2992
|
const { schemaId } = this.opts;
|
|
@@ -3013,7 +3013,7 @@ var require_compile = __commonJS({
|
|
|
3013
3013
|
function sameSchemaEnv(s1, s2) {
|
|
3014
3014
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3015
3015
|
}
|
|
3016
|
-
function
|
|
3016
|
+
function resolve9(root, ref) {
|
|
3017
3017
|
let sch;
|
|
3018
3018
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3019
3019
|
ref = sch;
|
|
@@ -3834,11 +3834,11 @@ var require_fast_uri = __commonJS({
|
|
|
3834
3834
|
normalizeString(uri, options);
|
|
3835
3835
|
} else if (typeof uri === "object") {
|
|
3836
3836
|
uri = /** @type {T} */
|
|
3837
|
-
|
|
3837
|
+
parse6(serialize(uri, options), options);
|
|
3838
3838
|
}
|
|
3839
3839
|
return uri;
|
|
3840
3840
|
}
|
|
3841
|
-
function
|
|
3841
|
+
function resolve9(baseURI, relativeURI, options) {
|
|
3842
3842
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3843
3843
|
const {
|
|
3844
3844
|
parsed: baseParsed,
|
|
@@ -3874,8 +3874,8 @@ var require_fast_uri = __commonJS({
|
|
|
3874
3874
|
function resolveComponent(base, relative5, options, skipNormalization) {
|
|
3875
3875
|
const target = {};
|
|
3876
3876
|
if (!skipNormalization) {
|
|
3877
|
-
base =
|
|
3878
|
-
relative5 =
|
|
3877
|
+
base = parse6(serialize(base, options), options);
|
|
3878
|
+
relative5 = parse6(serialize(relative5, options), options);
|
|
3879
3879
|
}
|
|
3880
3880
|
options = options || {};
|
|
3881
3881
|
if (!options.tolerant && relative5.scheme) {
|
|
@@ -4167,7 +4167,7 @@ var require_fast_uri = __commonJS({
|
|
|
4167
4167
|
}
|
|
4168
4168
|
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
4169
4169
|
}
|
|
4170
|
-
function
|
|
4170
|
+
function parse6(uri, opts) {
|
|
4171
4171
|
return parseWithStatus(uri, opts).parsed;
|
|
4172
4172
|
}
|
|
4173
4173
|
function normalizeString(uri, opts) {
|
|
@@ -4200,11 +4200,11 @@ var require_fast_uri = __commonJS({
|
|
|
4200
4200
|
var fastUri = {
|
|
4201
4201
|
SCHEMES,
|
|
4202
4202
|
normalize,
|
|
4203
|
-
resolve:
|
|
4203
|
+
resolve: resolve9,
|
|
4204
4204
|
resolveComponent,
|
|
4205
4205
|
equal,
|
|
4206
4206
|
serialize,
|
|
4207
|
-
parse:
|
|
4207
|
+
parse: parse6
|
|
4208
4208
|
};
|
|
4209
4209
|
module.exports = fastUri;
|
|
4210
4210
|
module.exports.default = fastUri;
|
|
@@ -14674,7 +14674,7 @@ var require_public_api = __commonJS({
|
|
|
14674
14674
|
}
|
|
14675
14675
|
return doc;
|
|
14676
14676
|
}
|
|
14677
|
-
function
|
|
14677
|
+
function parse6(src, reviver, options) {
|
|
14678
14678
|
let _reviver = void 0;
|
|
14679
14679
|
if (typeof reviver === "function") {
|
|
14680
14680
|
_reviver = reviver;
|
|
@@ -14715,7 +14715,7 @@ var require_public_api = __commonJS({
|
|
|
14715
14715
|
return value.toString(options);
|
|
14716
14716
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
14717
14717
|
}
|
|
14718
|
-
exports.parse =
|
|
14718
|
+
exports.parse = parse6;
|
|
14719
14719
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14720
14720
|
exports.parseDocument = parseDocument2;
|
|
14721
14721
|
exports.stringify = stringify3;
|
|
@@ -15139,7 +15139,7 @@ function defaultSpawn(command, args, options) {
|
|
|
15139
15139
|
if (options.signal?.aborted) {
|
|
15140
15140
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
15141
15141
|
}
|
|
15142
|
-
return new Promise((
|
|
15142
|
+
return new Promise((resolve9) => {
|
|
15143
15143
|
const stdout = [];
|
|
15144
15144
|
const stderr = [];
|
|
15145
15145
|
let outputBytes = 0;
|
|
@@ -15168,7 +15168,7 @@ function defaultSpawn(command, args, options) {
|
|
|
15168
15168
|
child?.unref();
|
|
15169
15169
|
const started = Boolean(child?.pid);
|
|
15170
15170
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
15171
|
-
|
|
15171
|
+
resolve9({ stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8"), code, signal, started, observedChildExit, terminationRequested: stopping, ...error ? { error } : {} });
|
|
15172
15172
|
};
|
|
15173
15173
|
const kill = (requested) => {
|
|
15174
15174
|
killProcessTree(child, requested);
|
|
@@ -16925,8 +16925,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
16925
16925
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
16926
16926
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
16927
16927
|
}
|
|
16928
|
-
const
|
|
16929
|
-
const minimumPassed =
|
|
16928
|
+
const join17 = objectValue(step.join);
|
|
16929
|
+
const minimumPassed = join17 && typeof join17.minimumPassed === "number" ? join17.minimumPassed : void 0;
|
|
16930
16930
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
16931
16931
|
const distinctBy = names(assignment?.distinctBy);
|
|
16932
16932
|
if (distinctBy.length > 0) {
|
|
@@ -20454,7 +20454,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20454
20454
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
20455
20455
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
20456
20456
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
20457
|
-
const
|
|
20457
|
+
const join17 = compileJoin(step, id, sink);
|
|
20458
20458
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
20459
20459
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
20460
20460
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -20482,7 +20482,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20482
20482
|
transitions: orderedTransitions,
|
|
20483
20483
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
20484
20484
|
assignments,
|
|
20485
|
-
join:
|
|
20485
|
+
join: join17
|
|
20486
20486
|
};
|
|
20487
20487
|
if (kind === "agent" || kind === "moa") {
|
|
20488
20488
|
if (!agent) return void 0;
|
|
@@ -20532,15 +20532,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
20532
20532
|
};
|
|
20533
20533
|
}
|
|
20534
20534
|
function compileJoin(step, stepId, sink) {
|
|
20535
|
-
const
|
|
20536
|
-
if (!
|
|
20537
|
-
const declared = stringValue2(
|
|
20535
|
+
const join17 = objectValue2(step.join);
|
|
20536
|
+
if (!join17) return { strategy: "all" };
|
|
20537
|
+
const declared = stringValue2(join17.strategy);
|
|
20538
20538
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
20539
|
-
const minimumPassed = compileOptionalCount(
|
|
20539
|
+
const minimumPassed = compileOptionalCount(join17.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
20540
20540
|
const compiled = {
|
|
20541
20541
|
strategy,
|
|
20542
20542
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
20543
|
-
...typeof
|
|
20543
|
+
...typeof join17.cancelRemaining === "boolean" ? { cancelRemaining: join17.cancelRemaining } : {}
|
|
20544
20544
|
};
|
|
20545
20545
|
return compiled;
|
|
20546
20546
|
}
|
|
@@ -21835,12 +21835,12 @@ function enqueueVnextScheduledRun(storePath, runId, configRevision, bound, start
|
|
|
21835
21835
|
if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
|
|
21836
21836
|
return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already admitted or queued`));
|
|
21837
21837
|
}
|
|
21838
|
-
return new Promise((
|
|
21838
|
+
return new Promise((resolve9, reject) => {
|
|
21839
21839
|
owner.queue.push({
|
|
21840
21840
|
runId,
|
|
21841
21841
|
configRevision,
|
|
21842
21842
|
bound,
|
|
21843
|
-
start: (token) => start(token).then(
|
|
21843
|
+
start: (token) => start(token).then(resolve9, reject),
|
|
21844
21844
|
fail: (error) => reject(error)
|
|
21845
21845
|
});
|
|
21846
21846
|
pump(storePath, owner);
|
|
@@ -23013,6 +23013,17 @@ var INSECURE_SSH_HOST_KEY_PATTERNS = Object.freeze([
|
|
|
23013
23013
|
/StrictHostKeyChecking=(accept-new|no|off)/i,
|
|
23014
23014
|
/UserKnownHostsFile=\/dev\/null/i
|
|
23015
23015
|
]);
|
|
23016
|
+
function assertPinnedSshHostKeyPolicy(sshArgs) {
|
|
23017
|
+
for (const arg of sshArgs) {
|
|
23018
|
+
for (const pattern of INSECURE_SSH_HOST_KEY_PATTERNS) {
|
|
23019
|
+
if (pattern.test(arg)) {
|
|
23020
|
+
throw new Error(
|
|
23021
|
+
`Insecure SSH host key policy rejected: "${arg}". KXM headless SSH requires pinned host keys with StrictHostKeyChecking=yes and BatchMode=yes.`
|
|
23022
|
+
);
|
|
23023
|
+
}
|
|
23024
|
+
}
|
|
23025
|
+
}
|
|
23026
|
+
}
|
|
23016
23027
|
|
|
23017
23028
|
// plugins/kxm/src/vnext-engine-command.ts
|
|
23018
23029
|
var MAX_DIRECT_TIMER_MS = 2147483647;
|
|
@@ -23100,8 +23111,8 @@ var CommandObserver = class {
|
|
|
23100
23111
|
this.requestStop("error", "lost-close");
|
|
23101
23112
|
}
|
|
23102
23113
|
run() {
|
|
23103
|
-
return new Promise((
|
|
23104
|
-
this.resolveOutcome =
|
|
23114
|
+
return new Promise((resolve9) => {
|
|
23115
|
+
this.resolveOutcome = resolve9;
|
|
23105
23116
|
try {
|
|
23106
23117
|
this.start();
|
|
23107
23118
|
} catch (error) {
|
|
@@ -26532,8 +26543,8 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26532
26543
|
}
|
|
26533
26544
|
let releaseActive = () => {
|
|
26534
26545
|
};
|
|
26535
|
-
const activePromise = new Promise((
|
|
26536
|
-
releaseActive =
|
|
26546
|
+
const activePromise = new Promise((resolve9) => {
|
|
26547
|
+
releaseActive = resolve9;
|
|
26537
26548
|
});
|
|
26538
26549
|
activeDrives.set(runId, activePromise);
|
|
26539
26550
|
const cleanupActive = () => {
|
|
@@ -26989,8 +27000,8 @@ var PiSession = class {
|
|
|
26989
27000
|
}
|
|
26990
27001
|
const id = `cmd_${++this.commandCounter}`;
|
|
26991
27002
|
const payload = { ...command, id };
|
|
26992
|
-
return new Promise((
|
|
26993
|
-
this.pendingCommands.set(id, { resolve:
|
|
27003
|
+
return new Promise((resolve9, reject) => {
|
|
27004
|
+
this.pendingCommands.set(id, { resolve: resolve9, reject });
|
|
26994
27005
|
try {
|
|
26995
27006
|
this.process.stdin.write(JSON.stringify(payload) + "\n");
|
|
26996
27007
|
} catch (err) {
|
|
@@ -27011,7 +27022,7 @@ var PiSession = class {
|
|
|
27011
27022
|
return { outcome, text: "aborted", usage: {} };
|
|
27012
27023
|
}
|
|
27013
27024
|
this.status = "busy";
|
|
27014
|
-
return new Promise((
|
|
27025
|
+
return new Promise((resolve9, reject) => {
|
|
27015
27026
|
let signalCleanup;
|
|
27016
27027
|
if (signal) {
|
|
27017
27028
|
const onAbort = () => {
|
|
@@ -27025,7 +27036,7 @@ var PiSession = class {
|
|
|
27025
27036
|
signalCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
27026
27037
|
}
|
|
27027
27038
|
this.activePrompt = {
|
|
27028
|
-
resolve:
|
|
27039
|
+
resolve: resolve9,
|
|
27029
27040
|
reject,
|
|
27030
27041
|
allowedOutcomes,
|
|
27031
27042
|
text: "",
|
|
@@ -28173,16 +28184,652 @@ Instructions for Operator:
|
|
|
28173
28184
|
return orphaned;
|
|
28174
28185
|
}
|
|
28175
28186
|
};
|
|
28187
|
+
|
|
28188
|
+
// plugins/kxm/src/modes.ts
|
|
28189
|
+
var import_yaml6 = __toESM(require_dist(), 1);
|
|
28190
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
28191
|
+
import { join as join15 } from "node:path";
|
|
28192
|
+
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
28193
|
+
schema: "kxm.modes.v1",
|
|
28194
|
+
majorModes: {
|
|
28195
|
+
coder: {
|
|
28196
|
+
description: "First-pass implementation, bug fixing, and test authoring",
|
|
28197
|
+
baseTools: ["read", "edit", "write", "bash"],
|
|
28198
|
+
contextFiles: ["AGENTS.md"],
|
|
28199
|
+
thinkingLevel: "medium",
|
|
28200
|
+
model: "grok/grok-4.6"
|
|
28201
|
+
},
|
|
28202
|
+
planner: {
|
|
28203
|
+
description: "High-level architectural planning, scoping, and decomposition",
|
|
28204
|
+
baseTools: ["read", "grep", "find"],
|
|
28205
|
+
contextFiles: ["plans/implementation-plan.md"],
|
|
28206
|
+
thinkingLevel: "high",
|
|
28207
|
+
model: "claude/fable"
|
|
28208
|
+
},
|
|
28209
|
+
auditor: {
|
|
28210
|
+
description: "Security, compliance, and code quality verification",
|
|
28211
|
+
baseTools: ["read", "grep"],
|
|
28212
|
+
contextFiles: ["SECURITY.md"],
|
|
28213
|
+
thinkingLevel: "high",
|
|
28214
|
+
model: "codex/gpt-5.6-sol"
|
|
28215
|
+
},
|
|
28216
|
+
browser: {
|
|
28217
|
+
description: "Web application exploration, screenshotting, and UI testing",
|
|
28218
|
+
baseTools: ["read", "bash"],
|
|
28219
|
+
contextFiles: ["docs/browser-automation.md"],
|
|
28220
|
+
thinkingLevel: "medium",
|
|
28221
|
+
model: "grok/grok-4.6"
|
|
28222
|
+
}
|
|
28223
|
+
},
|
|
28224
|
+
domains: {
|
|
28225
|
+
git: {
|
|
28226
|
+
description: "Git version control operations",
|
|
28227
|
+
tools: ["git_status", "git_diff", "git_commit"],
|
|
28228
|
+
promptSnippet: "Follow git branch conventions; never commit directly to main."
|
|
28229
|
+
},
|
|
28230
|
+
k8s: {
|
|
28231
|
+
description: "Kubernetes cluster inspection and deployment",
|
|
28232
|
+
tools: ["kubectl_get", "kubectl_describe"],
|
|
28233
|
+
promptSnippet: "Target local dev cluster; verify namespaces before mutating."
|
|
28234
|
+
},
|
|
28235
|
+
database: {
|
|
28236
|
+
description: "Database queries and schema verification",
|
|
28237
|
+
tools: ["sqlite_query", "sqlite_schema"],
|
|
28238
|
+
promptSnippet: "Database is SQLite at .kxm/state/kxm.db; use read-only queries."
|
|
28239
|
+
},
|
|
28240
|
+
browser: {
|
|
28241
|
+
description: "Remote Steel browser sessions and visual testing",
|
|
28242
|
+
tools: ["steel_session", "steel_scrape", "steel_screenshot"],
|
|
28243
|
+
promptSnippet: "Use Steel on DOKS for browser automation; invoke takeover on MFA."
|
|
28244
|
+
}
|
|
28245
|
+
}
|
|
28246
|
+
});
|
|
28247
|
+
function estimateTokens(charCount) {
|
|
28248
|
+
return Math.ceil(charCount / 3.8);
|
|
28249
|
+
}
|
|
28250
|
+
function loadModesConfig(projectRoot) {
|
|
28251
|
+
if (!projectRoot) {
|
|
28252
|
+
return DEFAULT_MODES_CONFIG;
|
|
28253
|
+
}
|
|
28254
|
+
const modesPath = join15(projectRoot, ".kxm", "modes.yaml");
|
|
28255
|
+
if (!existsSync12(modesPath)) {
|
|
28256
|
+
return DEFAULT_MODES_CONFIG;
|
|
28257
|
+
}
|
|
28258
|
+
try {
|
|
28259
|
+
const raw = readFileSync10(modesPath, "utf8");
|
|
28260
|
+
const parsed = (0, import_yaml6.parse)(raw);
|
|
28261
|
+
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
28262
|
+
return {
|
|
28263
|
+
schema: "kxm.modes.v1",
|
|
28264
|
+
majorModes: { ...DEFAULT_MODES_CONFIG.majorModes, ...parsed.majorModes },
|
|
28265
|
+
domains: { ...DEFAULT_MODES_CONFIG.domains, ...parsed.domains }
|
|
28266
|
+
};
|
|
28267
|
+
}
|
|
28268
|
+
} catch {
|
|
28269
|
+
}
|
|
28270
|
+
return DEFAULT_MODES_CONFIG;
|
|
28271
|
+
}
|
|
28272
|
+
function resolveActiveMode(config, majorModeName = "coder", domainNames = []) {
|
|
28273
|
+
const major = config.majorModes[majorModeName] || config.majorModes["coder"] || DEFAULT_MODES_CONFIG.majorModes["coder"];
|
|
28274
|
+
const tools = new Set(major.baseTools);
|
|
28275
|
+
const contextFiles = new Set(major.contextFiles || []);
|
|
28276
|
+
const promptSnippets = [];
|
|
28277
|
+
const enabledDomains = [];
|
|
28278
|
+
if (config.domains) {
|
|
28279
|
+
for (const dName of domainNames) {
|
|
28280
|
+
const d = config.domains[dName.toLowerCase().trim()];
|
|
28281
|
+
if (d) {
|
|
28282
|
+
enabledDomains.push(dName.toLowerCase().trim());
|
|
28283
|
+
d.tools.forEach((t) => tools.add(t));
|
|
28284
|
+
(d.contextFiles || []).forEach((f) => contextFiles.add(f));
|
|
28285
|
+
if (d.promptSnippet) {
|
|
28286
|
+
promptSnippets.push(d.promptSnippet);
|
|
28287
|
+
}
|
|
28288
|
+
}
|
|
28289
|
+
}
|
|
28290
|
+
}
|
|
28291
|
+
return {
|
|
28292
|
+
majorMode: majorModeName,
|
|
28293
|
+
enabledDomains,
|
|
28294
|
+
tools: Array.from(tools),
|
|
28295
|
+
contextFiles: Array.from(contextFiles),
|
|
28296
|
+
promptSnippets,
|
|
28297
|
+
thinkingLevel: major.thinkingLevel,
|
|
28298
|
+
model: major.model || "grok/grok-4.6"
|
|
28299
|
+
};
|
|
28300
|
+
}
|
|
28301
|
+
function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog) {
|
|
28302
|
+
const breakdown = [];
|
|
28303
|
+
const baseSystemPromptChars = 3200;
|
|
28304
|
+
breakdown.push({
|
|
28305
|
+
name: `Base System Prompt (${resolved.majorMode})`,
|
|
28306
|
+
chars: baseSystemPromptChars,
|
|
28307
|
+
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
28308
|
+
});
|
|
28309
|
+
for (const relPath of resolved.contextFiles) {
|
|
28310
|
+
const fullPath = join15(projectRoot, relPath);
|
|
28311
|
+
let chars = 0;
|
|
28312
|
+
if (existsSync12(fullPath)) {
|
|
28313
|
+
try {
|
|
28314
|
+
chars = readFileSync10(fullPath, "utf8").length;
|
|
28315
|
+
} catch {
|
|
28316
|
+
chars = 0;
|
|
28317
|
+
}
|
|
28318
|
+
}
|
|
28319
|
+
if (chars === 0) {
|
|
28320
|
+
chars = 1500;
|
|
28321
|
+
}
|
|
28322
|
+
breakdown.push({
|
|
28323
|
+
name: `Context File: ${relPath}`,
|
|
28324
|
+
chars,
|
|
28325
|
+
estimatedTokens: estimateTokens(chars)
|
|
28326
|
+
});
|
|
28327
|
+
}
|
|
28328
|
+
if (resolved.promptSnippets.length > 0) {
|
|
28329
|
+
const snippetChars = resolved.promptSnippets.join("\n").length;
|
|
28330
|
+
breakdown.push({
|
|
28331
|
+
name: `Domain Prompts (${resolved.enabledDomains.join(", ")})`,
|
|
28332
|
+
chars: snippetChars,
|
|
28333
|
+
estimatedTokens: estimateTokens(snippetChars)
|
|
28334
|
+
});
|
|
28335
|
+
}
|
|
28336
|
+
const toolSchemaChars = resolved.tools.length * 650;
|
|
28337
|
+
breakdown.push({
|
|
28338
|
+
name: `Tool Schemas (${resolved.tools.length} active tools)`,
|
|
28339
|
+
chars: toolSchemaChars,
|
|
28340
|
+
estimatedTokens: estimateTokens(toolSchemaChars)
|
|
28341
|
+
});
|
|
28342
|
+
const totalChars = breakdown.reduce((sum, item) => sum + item.chars, 0);
|
|
28343
|
+
const totalTokens = breakdown.reduce((sum, item) => sum + item.estimatedTokens, 0);
|
|
28344
|
+
const maxContextWindow = 2e5;
|
|
28345
|
+
const contextWindowRatio = Math.round(totalTokens / maxContextWindow * 1e3) / 10;
|
|
28346
|
+
const cat = catalog || loadPriceCatalog(projectRoot);
|
|
28347
|
+
const rawModel = resolved.model || "grok/grok-4.6";
|
|
28348
|
+
const [prov, mod] = rawModel.includes("/") ? rawModel.split("/", 2) : [void 0, rawModel];
|
|
28349
|
+
const inputCost = cat ? calculateModelCost(cat, {
|
|
28350
|
+
model: mod || rawModel,
|
|
28351
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28352
|
+
tokensIn: totalTokens,
|
|
28353
|
+
tokensOut: 0,
|
|
28354
|
+
cacheReadTokens: 0,
|
|
28355
|
+
cacheWriteTokens: 0
|
|
28356
|
+
}) : void 0;
|
|
28357
|
+
const cacheReadCost = cat ? calculateModelCost(cat, {
|
|
28358
|
+
model: mod || rawModel,
|
|
28359
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28360
|
+
tokensIn: 0,
|
|
28361
|
+
tokensOut: 0,
|
|
28362
|
+
cacheReadTokens: totalTokens,
|
|
28363
|
+
cacheWriteTokens: 0
|
|
28364
|
+
}) : void 0;
|
|
28365
|
+
const outputEstimateCost = cat ? calculateModelCost(cat, {
|
|
28366
|
+
model: mod || rawModel,
|
|
28367
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28368
|
+
tokensIn: 0,
|
|
28369
|
+
tokensOut: 1e3,
|
|
28370
|
+
cacheReadTokens: 0,
|
|
28371
|
+
cacheWriteTokens: 0
|
|
28372
|
+
}) : void 0;
|
|
28373
|
+
return {
|
|
28374
|
+
majorMode: resolved.majorMode,
|
|
28375
|
+
enabledDomains: resolved.enabledDomains,
|
|
28376
|
+
model: resolved.model || "grok/grok-4.6",
|
|
28377
|
+
breakdown,
|
|
28378
|
+
totalChars,
|
|
28379
|
+
totalTokens,
|
|
28380
|
+
contextWindowRatio,
|
|
28381
|
+
projectedCost: {
|
|
28382
|
+
inputCostUsd: inputCost?.costUsd ?? null,
|
|
28383
|
+
cacheReadCostUsd: cacheReadCost?.costUsd ?? null,
|
|
28384
|
+
outputCostEstimateUsd: outputEstimateCost?.costUsd ?? null
|
|
28385
|
+
}
|
|
28386
|
+
};
|
|
28387
|
+
}
|
|
28388
|
+
function formatModesExplainReport(footprint) {
|
|
28389
|
+
const divider = "\u2550".repeat(60);
|
|
28390
|
+
const subDivider = "\u2500".repeat(60);
|
|
28391
|
+
let out = `
|
|
28392
|
+
${divider}
|
|
28393
|
+
`;
|
|
28394
|
+
out += `KXM PRE-FLIGHT CONTEXT EXPLAIN
|
|
28395
|
+
`;
|
|
28396
|
+
out += `${divider}
|
|
28397
|
+
`;
|
|
28398
|
+
out += `Major Mode: ${footprint.majorMode}
|
|
28399
|
+
`;
|
|
28400
|
+
out += `Enabled Domains: ${footprint.enabledDomains.length > 0 ? footprint.enabledDomains.join(", ") : "(none)"}
|
|
28401
|
+
`;
|
|
28402
|
+
out += `Target Model: ${footprint.model}
|
|
28403
|
+
|
|
28404
|
+
`;
|
|
28405
|
+
out += `CONTEXT BREAKDOWN:
|
|
28406
|
+
`;
|
|
28407
|
+
for (const item of footprint.breakdown) {
|
|
28408
|
+
const padName = item.name.padEnd(38, " ");
|
|
28409
|
+
const tokenStr = `${item.estimatedTokens.toLocaleString()} tokens`.padStart(16, " ");
|
|
28410
|
+
out += ` \u2022 ${padName} ${tokenStr}
|
|
28411
|
+
`;
|
|
28412
|
+
}
|
|
28413
|
+
out += `${subDivider}
|
|
28414
|
+
`;
|
|
28415
|
+
const totalPad = `TOTAL PROMPT FOOTPRINT:`.padEnd(38, " ");
|
|
28416
|
+
const totalStr = `${footprint.totalTokens.toLocaleString()} tokens`.padStart(16, " ");
|
|
28417
|
+
out += ` ${totalPad} ${totalStr} (${footprint.contextWindowRatio}% of 200k window)
|
|
28418
|
+
|
|
28419
|
+
`;
|
|
28420
|
+
out += `PROJECTED COSTS (per turn):
|
|
28421
|
+
`;
|
|
28422
|
+
out += ` \u2022 Initial Turn Input Cost: ${footprint.projectedCost.inputCostUsd !== null ? `$${footprint.projectedCost.inputCostUsd.toFixed(4)}` : "unmetered/unknown"}
|
|
28423
|
+
`;
|
|
28424
|
+
out += ` \u2022 Subsequent Cache-Read Cost: ${footprint.projectedCost.cacheReadCostUsd !== null ? `$${footprint.projectedCost.cacheReadCostUsd.toFixed(4)} (approx 90% savings)` : "unmetered/unknown"}
|
|
28425
|
+
`;
|
|
28426
|
+
out += ` \u2022 Output Estimate (1k tokens): ${footprint.projectedCost.outputCostEstimateUsd !== null ? `$${footprint.projectedCost.outputCostEstimateUsd.toFixed(4)}` : "unmetered/unknown"}
|
|
28427
|
+
`;
|
|
28428
|
+
out += `${divider}
|
|
28429
|
+
`;
|
|
28430
|
+
return out;
|
|
28431
|
+
}
|
|
28432
|
+
|
|
28433
|
+
// plugins/kxm/src/ssh-remote.ts
|
|
28434
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
28435
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync5, rmSync as rmSync2, statSync as statSync4 } from "node:fs";
|
|
28436
|
+
import { homedir as homedir2 } from "node:os";
|
|
28437
|
+
import { join as join16, resolve as resolve8 } from "node:path";
|
|
28438
|
+
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
28439
|
+
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
28440
|
+
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
28441
|
+
var DEFAULT_CONTROL_PERSIST = "10m";
|
|
28442
|
+
function truncateSshOutput(raw) {
|
|
28443
|
+
let text = raw;
|
|
28444
|
+
let truncated = false;
|
|
28445
|
+
if (Buffer.byteLength(text, "utf-8") > MAX_SSH_OUTPUT_BYTES) {
|
|
28446
|
+
const buf = Buffer.from(text, "utf-8");
|
|
28447
|
+
text = buf.subarray(0, MAX_SSH_OUTPUT_BYTES).toString("utf-8");
|
|
28448
|
+
truncated = true;
|
|
28449
|
+
}
|
|
28450
|
+
const lines = text.split("\n");
|
|
28451
|
+
if (lines.length > MAX_SSH_OUTPUT_LINES) {
|
|
28452
|
+
text = lines.slice(0, MAX_SSH_OUTPUT_LINES).join("\n");
|
|
28453
|
+
truncated = true;
|
|
28454
|
+
}
|
|
28455
|
+
if (truncated) {
|
|
28456
|
+
text += `
|
|
28457
|
+
|
|
28458
|
+
[kxm: ssh output truncated to ${MAX_SSH_OUTPUT_BYTES / 1024}KB / ${MAX_SSH_OUTPUT_LINES} lines]`;
|
|
28459
|
+
}
|
|
28460
|
+
return { text, truncated };
|
|
28461
|
+
}
|
|
28462
|
+
function parseSshConfig(configPath) {
|
|
28463
|
+
const targetPath = configPath ?? join16(homedir2(), ".ssh", "config");
|
|
28464
|
+
if (!existsSync13(targetPath)) {
|
|
28465
|
+
return [];
|
|
28466
|
+
}
|
|
28467
|
+
try {
|
|
28468
|
+
const content = readFileSync11(targetPath, "utf-8");
|
|
28469
|
+
const lines = content.split("\n");
|
|
28470
|
+
const hosts = [];
|
|
28471
|
+
let currentHosts = [];
|
|
28472
|
+
for (const rawLine of lines) {
|
|
28473
|
+
const line = rawLine.trim();
|
|
28474
|
+
if (!line || line.startsWith("#")) continue;
|
|
28475
|
+
const spaceIdx = line.search(/\s/);
|
|
28476
|
+
if (spaceIdx === -1) continue;
|
|
28477
|
+
const key = line.slice(0, spaceIdx).trim().toLowerCase();
|
|
28478
|
+
const value = line.slice(spaceIdx + 1).trim();
|
|
28479
|
+
if (key === "host") {
|
|
28480
|
+
const aliases = value.split(/\s+/).filter((a) => a !== "*");
|
|
28481
|
+
currentHosts = [];
|
|
28482
|
+
for (const alias of aliases) {
|
|
28483
|
+
const entry = { alias, identityFiles: [] };
|
|
28484
|
+
currentHosts.push(entry);
|
|
28485
|
+
hosts.push(entry);
|
|
28486
|
+
}
|
|
28487
|
+
} else if (currentHosts.length > 0) {
|
|
28488
|
+
for (const currentHost of currentHosts) {
|
|
28489
|
+
if (key === "hostname") {
|
|
28490
|
+
currentHost.hostName = value;
|
|
28491
|
+
} else if (key === "user") {
|
|
28492
|
+
currentHost.user = value;
|
|
28493
|
+
} else if (key === "port") {
|
|
28494
|
+
const p = Number.parseInt(value, 10);
|
|
28495
|
+
if (!Number.isNaN(p)) currentHost.port = p;
|
|
28496
|
+
} else if (key === "proxyjump") {
|
|
28497
|
+
currentHost.proxyJump = value;
|
|
28498
|
+
} else if (key === "identityfile") {
|
|
28499
|
+
currentHost.identityFiles = currentHost.identityFiles ?? [];
|
|
28500
|
+
currentHost.identityFiles.push(value);
|
|
28501
|
+
}
|
|
28502
|
+
}
|
|
28503
|
+
}
|
|
28504
|
+
}
|
|
28505
|
+
return hosts;
|
|
28506
|
+
} catch {
|
|
28507
|
+
return [];
|
|
28508
|
+
}
|
|
28509
|
+
}
|
|
28510
|
+
function resolveSshHostG(host, execFn = spawnSync3) {
|
|
28511
|
+
try {
|
|
28512
|
+
const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
|
|
28513
|
+
if (result.status !== 0 || !result.stdout) {
|
|
28514
|
+
return { alias: host, hostName: host };
|
|
28515
|
+
}
|
|
28516
|
+
const lines = String(result.stdout).split("\n");
|
|
28517
|
+
const info = { alias: host, identityFiles: [] };
|
|
28518
|
+
for (const rawLine of lines) {
|
|
28519
|
+
const line = rawLine.trim();
|
|
28520
|
+
if (!line) continue;
|
|
28521
|
+
const spaceIdx = line.indexOf(" ");
|
|
28522
|
+
if (spaceIdx === -1) continue;
|
|
28523
|
+
const key = line.slice(0, spaceIdx).toLowerCase();
|
|
28524
|
+
const value = line.slice(spaceIdx + 1).trim();
|
|
28525
|
+
if (key === "hostname") {
|
|
28526
|
+
info.hostName = value;
|
|
28527
|
+
} else if (key === "user") {
|
|
28528
|
+
info.user = value;
|
|
28529
|
+
} else if (key === "port") {
|
|
28530
|
+
const p = Number.parseInt(value, 10);
|
|
28531
|
+
if (!Number.isNaN(p)) info.port = p;
|
|
28532
|
+
} else if (key === "proxyjump") {
|
|
28533
|
+
if (value && value !== "none") info.proxyJump = value;
|
|
28534
|
+
} else if (key === "identityfile") {
|
|
28535
|
+
info.identityFiles = info.identityFiles ?? [];
|
|
28536
|
+
info.identityFiles.push(value);
|
|
28537
|
+
}
|
|
28538
|
+
}
|
|
28539
|
+
return info;
|
|
28540
|
+
} catch {
|
|
28541
|
+
return { alias: host, hostName: host };
|
|
28542
|
+
}
|
|
28543
|
+
}
|
|
28544
|
+
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
28545
|
+
const resolved = resolve8(socketDir);
|
|
28546
|
+
if (!existsSync13(resolved)) {
|
|
28547
|
+
mkdirSync7(resolved, { recursive: true, mode: 448 });
|
|
28548
|
+
}
|
|
28549
|
+
return resolved;
|
|
28550
|
+
}
|
|
28551
|
+
function buildSshArgs(options) {
|
|
28552
|
+
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
28553
|
+
const controlPath = join16(socketDir, "%C");
|
|
28554
|
+
const persist2 = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
28555
|
+
const args = [
|
|
28556
|
+
"-o",
|
|
28557
|
+
`ControlMaster=auto`,
|
|
28558
|
+
"-o",
|
|
28559
|
+
`ControlPath=${controlPath}`,
|
|
28560
|
+
"-o",
|
|
28561
|
+
`ControlPersist=${persist2}`
|
|
28562
|
+
];
|
|
28563
|
+
if (options.batchMode !== false) {
|
|
28564
|
+
args.push("-o", "BatchMode=yes");
|
|
28565
|
+
}
|
|
28566
|
+
if (options.strictHostKey !== false) {
|
|
28567
|
+
args.push("-o", "StrictHostKeyChecking=yes");
|
|
28568
|
+
}
|
|
28569
|
+
if (options.extraArgs) {
|
|
28570
|
+
args.push(...options.extraArgs);
|
|
28571
|
+
}
|
|
28572
|
+
assertPinnedSshHostKeyPolicy(args);
|
|
28573
|
+
args.push(options.host);
|
|
28574
|
+
return args;
|
|
28575
|
+
}
|
|
28576
|
+
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync3) {
|
|
28577
|
+
const resolvedDir = ensureSocketDir(socketDir);
|
|
28578
|
+
const controlPath = join16(resolvedDir, "%C");
|
|
28579
|
+
try {
|
|
28580
|
+
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
28581
|
+
encoding: "utf-8"
|
|
28582
|
+
});
|
|
28583
|
+
return result.status === 0;
|
|
28584
|
+
} catch {
|
|
28585
|
+
return false;
|
|
28586
|
+
}
|
|
28587
|
+
}
|
|
28588
|
+
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync3) {
|
|
28589
|
+
const resolvedDir = ensureSocketDir(socketDir);
|
|
28590
|
+
const controlPath = join16(resolvedDir, "%C");
|
|
28591
|
+
try {
|
|
28592
|
+
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
28593
|
+
encoding: "utf-8"
|
|
28594
|
+
});
|
|
28595
|
+
return result.status === 0;
|
|
28596
|
+
} catch {
|
|
28597
|
+
return false;
|
|
28598
|
+
}
|
|
28599
|
+
}
|
|
28600
|
+
function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
28601
|
+
const resolvedDir = ensureSocketDir(socketDir);
|
|
28602
|
+
let removed = 0;
|
|
28603
|
+
try {
|
|
28604
|
+
const entries = readdirSync5(resolvedDir);
|
|
28605
|
+
for (const entry of entries) {
|
|
28606
|
+
const fullPath = join16(resolvedDir, entry);
|
|
28607
|
+
try {
|
|
28608
|
+
const stat = statSync4(fullPath);
|
|
28609
|
+
if (stat.isSocket()) {
|
|
28610
|
+
rmSync2(fullPath, { force: true });
|
|
28611
|
+
removed++;
|
|
28612
|
+
}
|
|
28613
|
+
} catch {
|
|
28614
|
+
}
|
|
28615
|
+
}
|
|
28616
|
+
} catch {
|
|
28617
|
+
}
|
|
28618
|
+
return removed;
|
|
28619
|
+
}
|
|
28620
|
+
function executeSshRun(params) {
|
|
28621
|
+
const startTime = Date.now();
|
|
28622
|
+
const execSyncFn = params.execFn ?? spawnSync3;
|
|
28623
|
+
if (params.action === "info") {
|
|
28624
|
+
if (params.host) {
|
|
28625
|
+
const hostInfo = resolveSshHostG(params.host, execSyncFn);
|
|
28626
|
+
return {
|
|
28627
|
+
ok: true,
|
|
28628
|
+
action: "info",
|
|
28629
|
+
host: params.host,
|
|
28630
|
+
resolvedHost: hostInfo.hostName ?? params.host,
|
|
28631
|
+
user: hostInfo.user,
|
|
28632
|
+
port: hostInfo.port,
|
|
28633
|
+
hosts: [hostInfo],
|
|
28634
|
+
durationMs: Date.now() - startTime
|
|
28635
|
+
};
|
|
28636
|
+
}
|
|
28637
|
+
const discovered = parseSshConfig();
|
|
28638
|
+
return {
|
|
28639
|
+
ok: true,
|
|
28640
|
+
action: "info",
|
|
28641
|
+
hosts: discovered,
|
|
28642
|
+
durationMs: Date.now() - startTime
|
|
28643
|
+
};
|
|
28644
|
+
}
|
|
28645
|
+
if (!params.host) {
|
|
28646
|
+
return {
|
|
28647
|
+
ok: false,
|
|
28648
|
+
action: params.action,
|
|
28649
|
+
error: 'Parameter "host" is required for command and file actions.',
|
|
28650
|
+
durationMs: Date.now() - startTime
|
|
28651
|
+
};
|
|
28652
|
+
}
|
|
28653
|
+
const host = params.host;
|
|
28654
|
+
const socketDir = params.socket_dir ?? DEFAULT_SOCKET_DIR;
|
|
28655
|
+
const wasSocketActive = checkControlSocket(host, socketDir, execSyncFn);
|
|
28656
|
+
if (params.action === "command") {
|
|
28657
|
+
if (!params.command) {
|
|
28658
|
+
return {
|
|
28659
|
+
ok: false,
|
|
28660
|
+
action: "command",
|
|
28661
|
+
host,
|
|
28662
|
+
error: 'Parameter "command" is required for command action.',
|
|
28663
|
+
durationMs: Date.now() - startTime
|
|
28664
|
+
};
|
|
28665
|
+
}
|
|
28666
|
+
try {
|
|
28667
|
+
assertCommandSeatbelt(params.command);
|
|
28668
|
+
} catch (err) {
|
|
28669
|
+
return {
|
|
28670
|
+
ok: false,
|
|
28671
|
+
action: "command",
|
|
28672
|
+
host,
|
|
28673
|
+
error: err.message,
|
|
28674
|
+
durationMs: Date.now() - startTime
|
|
28675
|
+
};
|
|
28676
|
+
}
|
|
28677
|
+
let remoteCommand = params.command;
|
|
28678
|
+
let inputStdin = void 0;
|
|
28679
|
+
if (params.sudo) {
|
|
28680
|
+
const sudoPwd = params.sudo_password ?? params.password;
|
|
28681
|
+
if (sudoPwd) {
|
|
28682
|
+
inputStdin = `${sudoPwd}
|
|
28683
|
+
`;
|
|
28684
|
+
remoteCommand = `sudo -S -p '' -- sh -c ${JSON.stringify(params.command)}`;
|
|
28685
|
+
} else {
|
|
28686
|
+
remoteCommand = `sudo -- sh -c ${JSON.stringify(params.command)}`;
|
|
28687
|
+
}
|
|
28688
|
+
}
|
|
28689
|
+
const useSshPass = Boolean(params.password);
|
|
28690
|
+
const sshArgs = buildSshArgs({
|
|
28691
|
+
host,
|
|
28692
|
+
socketDir,
|
|
28693
|
+
controlPersist: params.control_persist,
|
|
28694
|
+
batchMode: !useSshPass,
|
|
28695
|
+
strictHostKey: params.strict_host_key
|
|
28696
|
+
});
|
|
28697
|
+
sshArgs.push("--", remoteCommand);
|
|
28698
|
+
const spawnEnv = { ...process.env };
|
|
28699
|
+
let binary = "ssh";
|
|
28700
|
+
let finalArgs = sshArgs;
|
|
28701
|
+
if (useSshPass && params.password) {
|
|
28702
|
+
binary = "sshpass";
|
|
28703
|
+
finalArgs = ["-e", "ssh", ...sshArgs];
|
|
28704
|
+
spawnEnv.SSHPASS = params.password;
|
|
28705
|
+
}
|
|
28706
|
+
try {
|
|
28707
|
+
const result = execSyncFn(binary, finalArgs, {
|
|
28708
|
+
encoding: "utf-8",
|
|
28709
|
+
env: spawnEnv,
|
|
28710
|
+
input: inputStdin,
|
|
28711
|
+
timeout: params.timeout_ms ?? 12e4,
|
|
28712
|
+
maxBuffer: 10 * 1024 * 1024
|
|
28713
|
+
});
|
|
28714
|
+
const stdoutRaw = String(result.stdout || "");
|
|
28715
|
+
const stderrRaw = String(result.stderr || "");
|
|
28716
|
+
const sanitizedStderr = stderrRaw.replace(/\[sudo\] password for [^:]+:\s*/gi, "");
|
|
28717
|
+
const stdoutTrunc = truncateSshOutput(stdoutRaw);
|
|
28718
|
+
const stderrTrunc = truncateSshOutput(sanitizedStderr);
|
|
28719
|
+
return {
|
|
28720
|
+
ok: result.status === 0,
|
|
28721
|
+
action: "command",
|
|
28722
|
+
host,
|
|
28723
|
+
exitCode: result.status ?? 1,
|
|
28724
|
+
stdout: stdoutTrunc.text,
|
|
28725
|
+
stderr: stderrTrunc.text,
|
|
28726
|
+
truncated: stdoutTrunc.truncated || stderrTrunc.truncated,
|
|
28727
|
+
socketReused: wasSocketActive,
|
|
28728
|
+
durationMs: Date.now() - startTime,
|
|
28729
|
+
error: result.error ? result.error.message : void 0
|
|
28730
|
+
};
|
|
28731
|
+
} catch (err) {
|
|
28732
|
+
return {
|
|
28733
|
+
ok: false,
|
|
28734
|
+
action: "command",
|
|
28735
|
+
host,
|
|
28736
|
+
error: err.message,
|
|
28737
|
+
durationMs: Date.now() - startTime
|
|
28738
|
+
};
|
|
28739
|
+
}
|
|
28740
|
+
}
|
|
28741
|
+
if (params.action === "file") {
|
|
28742
|
+
if (!params.file_path) {
|
|
28743
|
+
return {
|
|
28744
|
+
ok: false,
|
|
28745
|
+
action: "file",
|
|
28746
|
+
host,
|
|
28747
|
+
error: 'Parameter "file_path" is required for file action.',
|
|
28748
|
+
durationMs: Date.now() - startTime
|
|
28749
|
+
};
|
|
28750
|
+
}
|
|
28751
|
+
const filePath = params.file_path;
|
|
28752
|
+
const op = params.file_op ?? "write";
|
|
28753
|
+
if (op === "read") {
|
|
28754
|
+
const readCmd = params.sudo ? `sudo cat ${JSON.stringify(filePath)}` : `cat ${JSON.stringify(filePath)}`;
|
|
28755
|
+
return executeSshRun({
|
|
28756
|
+
...params,
|
|
28757
|
+
action: "command",
|
|
28758
|
+
command: readCmd
|
|
28759
|
+
});
|
|
28760
|
+
}
|
|
28761
|
+
const content = params.file_content ?? "";
|
|
28762
|
+
const redirectOp = op === "append" ? ">>" : ">";
|
|
28763
|
+
const writeCmd = params.sudo ? `sudo tee ${op === "append" ? "-a " : ""}${JSON.stringify(filePath)} > /dev/null` : `cat ${redirectOp} ${JSON.stringify(filePath)}`;
|
|
28764
|
+
const useSshPass = Boolean(params.password);
|
|
28765
|
+
const sshArgs = buildSshArgs({
|
|
28766
|
+
host,
|
|
28767
|
+
socketDir,
|
|
28768
|
+
controlPersist: params.control_persist,
|
|
28769
|
+
batchMode: !useSshPass,
|
|
28770
|
+
strictHostKey: params.strict_host_key
|
|
28771
|
+
});
|
|
28772
|
+
sshArgs.push("--", writeCmd);
|
|
28773
|
+
const spawnEnv = { ...process.env };
|
|
28774
|
+
let binary = "ssh";
|
|
28775
|
+
let finalArgs = sshArgs;
|
|
28776
|
+
if (useSshPass && params.password) {
|
|
28777
|
+
binary = "sshpass";
|
|
28778
|
+
finalArgs = ["-e", "ssh", ...sshArgs];
|
|
28779
|
+
spawnEnv.SSHPASS = params.password;
|
|
28780
|
+
}
|
|
28781
|
+
try {
|
|
28782
|
+
const result = execSyncFn(binary, finalArgs, {
|
|
28783
|
+
encoding: "utf-8",
|
|
28784
|
+
env: spawnEnv,
|
|
28785
|
+
input: content,
|
|
28786
|
+
timeout: params.timeout_ms ?? 6e4
|
|
28787
|
+
});
|
|
28788
|
+
return {
|
|
28789
|
+
ok: result.status === 0,
|
|
28790
|
+
action: "file",
|
|
28791
|
+
host,
|
|
28792
|
+
exitCode: result.status ?? 1,
|
|
28793
|
+
stdout: String(result.stdout || ""),
|
|
28794
|
+
stderr: String(result.stderr || ""),
|
|
28795
|
+
fileProcessed: filePath,
|
|
28796
|
+
bytesProcessed: Buffer.byteLength(content, "utf-8"),
|
|
28797
|
+
socketReused: wasSocketActive,
|
|
28798
|
+
durationMs: Date.now() - startTime,
|
|
28799
|
+
error: result.error ? result.error.message : void 0
|
|
28800
|
+
};
|
|
28801
|
+
} catch (err) {
|
|
28802
|
+
return {
|
|
28803
|
+
ok: false,
|
|
28804
|
+
action: "file",
|
|
28805
|
+
host,
|
|
28806
|
+
error: err.message,
|
|
28807
|
+
durationMs: Date.now() - startTime
|
|
28808
|
+
};
|
|
28809
|
+
}
|
|
28810
|
+
}
|
|
28811
|
+
return {
|
|
28812
|
+
ok: false,
|
|
28813
|
+
action: params.action,
|
|
28814
|
+
error: `Unknown action: ${params.action}`,
|
|
28815
|
+
durationMs: Date.now() - startTime
|
|
28816
|
+
};
|
|
28817
|
+
}
|
|
28176
28818
|
export {
|
|
28177
28819
|
BUILTIN_HARNESSES,
|
|
28178
28820
|
BUILTIN_HARNESS_IDS,
|
|
28179
28821
|
CANDIDATE_SCHEMA,
|
|
28822
|
+
DEFAULT_CONTROL_PERSIST,
|
|
28180
28823
|
DEFAULT_HARNESS,
|
|
28181
28824
|
DEFAULT_LOG_MAX_BYTES,
|
|
28182
28825
|
DEFAULT_LOG_MAX_FILES,
|
|
28826
|
+
DEFAULT_MODES_CONFIG,
|
|
28827
|
+
DEFAULT_SOCKET_DIR,
|
|
28183
28828
|
IMPROVEMENT_REPORT_SCHEMA,
|
|
28184
28829
|
IMPROVEMENT_REPORT_V1_SCHEMA,
|
|
28185
28830
|
LOG_LEVEL_PRIORITY,
|
|
28831
|
+
MAX_SSH_OUTPUT_BYTES,
|
|
28832
|
+
MAX_SSH_OUTPUT_LINES,
|
|
28186
28833
|
NATIVE_HARNESS_PROVIDERS,
|
|
28187
28834
|
PI_ALLOWED_PROVIDERS,
|
|
28188
28835
|
PI_NATIVE_BRAKE_PROVIDERS,
|
|
@@ -28202,12 +28849,16 @@ export {
|
|
|
28202
28849
|
assertVnextConfigError,
|
|
28203
28850
|
backupDatabaseFile,
|
|
28204
28851
|
buildImprovementReport,
|
|
28852
|
+
buildSshArgs,
|
|
28853
|
+
calculatePromptFootprint,
|
|
28205
28854
|
cancelVnextRun,
|
|
28855
|
+
checkControlSocket,
|
|
28206
28856
|
checkIntegrity,
|
|
28207
28857
|
checkMemoryRevisionDrift,
|
|
28208
28858
|
checkedParent,
|
|
28209
28859
|
checkpointWal,
|
|
28210
28860
|
classifyCandidateKind,
|
|
28861
|
+
closeControlSocket,
|
|
28211
28862
|
closeVnextRuntimeContext,
|
|
28212
28863
|
computeGateEvidenceOutcome,
|
|
28213
28864
|
computeVnextMemoryRevision,
|
|
@@ -28220,9 +28871,12 @@ export {
|
|
|
28220
28871
|
defaultSpawn,
|
|
28221
28872
|
discoverProjectStores,
|
|
28222
28873
|
eligibleHarnesses,
|
|
28874
|
+
ensureSocketDir,
|
|
28223
28875
|
ensureVnextSupervisor,
|
|
28224
28876
|
ensureWalJournalMode,
|
|
28877
|
+
estimateTokens,
|
|
28225
28878
|
evaluatePromotionPolicy,
|
|
28879
|
+
executeSshRun,
|
|
28226
28880
|
fileSha256,
|
|
28227
28881
|
findWinNpmInnerExe,
|
|
28228
28882
|
foldStoredVnextRun,
|
|
@@ -28231,6 +28885,7 @@ export {
|
|
|
28231
28885
|
formatHarnessInventory,
|
|
28232
28886
|
formatHarnessUpdate,
|
|
28233
28887
|
formatImprovementReport,
|
|
28888
|
+
formatModesExplainReport,
|
|
28234
28889
|
formatPiSessionDisplayName,
|
|
28235
28890
|
formatPiSessionKey,
|
|
28236
28891
|
gateRowContentHash,
|
|
@@ -28242,6 +28897,7 @@ export {
|
|
|
28242
28897
|
isKnownHarnessId,
|
|
28243
28898
|
isVnextRuntimeContextClosed,
|
|
28244
28899
|
isWindowsHarnessShim,
|
|
28900
|
+
loadModesConfig,
|
|
28245
28901
|
newVnextAssignmentId,
|
|
28246
28902
|
newVnextAttemptId,
|
|
28247
28903
|
newVnextCommandId,
|
|
@@ -28259,6 +28915,7 @@ export {
|
|
|
28259
28915
|
parseGenericOneShotUsage,
|
|
28260
28916
|
parseGrokOneShotUsage,
|
|
28261
28917
|
parseKimiOneShotUsage,
|
|
28918
|
+
parseSshConfig,
|
|
28262
28919
|
persistVnextRunState,
|
|
28263
28920
|
planHarnessUpdate,
|
|
28264
28921
|
probeHarnessAssignment,
|
|
@@ -28266,13 +28923,16 @@ export {
|
|
|
28266
28923
|
probeHarnesses,
|
|
28267
28924
|
probeHarnessesForModel,
|
|
28268
28925
|
projectRuntimeKey,
|
|
28926
|
+
pruneSocketDir,
|
|
28269
28927
|
readVnextRunStatus,
|
|
28270
28928
|
readVnextSupervisorToken,
|
|
28271
28929
|
rebuildVnextRunProjection,
|
|
28272
28930
|
redactLogValue,
|
|
28273
28931
|
registerVnextRuntimeCloseHook,
|
|
28932
|
+
resolveActiveMode,
|
|
28274
28933
|
resolveDispatchStatus,
|
|
28275
28934
|
resolvePassCliApiKey,
|
|
28935
|
+
resolveSshHostG,
|
|
28276
28936
|
resolveSteelConfig,
|
|
28277
28937
|
resolveViewportDimensions,
|
|
28278
28938
|
restoreBackup,
|
|
@@ -28283,6 +28943,7 @@ export {
|
|
|
28283
28943
|
sanitizeLogOutput,
|
|
28284
28944
|
startVnextRuntimeSupervisor,
|
|
28285
28945
|
tableColumns,
|
|
28946
|
+
truncateSshOutput,
|
|
28286
28947
|
userTables,
|
|
28287
28948
|
validateHarnessModelPair,
|
|
28288
28949
|
verifyExpectedTables,
|