@kontextmind/kxm 0.7.149 → 0.7.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +14 -0
- package/docs/architecture/agent-path.md +5 -0
- package/docs/operations/troubleshooting.md +1 -0
- package/docs/reference/cli-reference.md +4 -4
- package/docs/reference/config-reference.md +17 -4
- package/docs/reference/harness-routing.md +7 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +153 -60
- package/plugins/kxm/dist/core.js +22 -3
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +676 -130
- package/plugins/kxm/dist/runtime.js +720 -164
- package/plugins/kxm/dist/server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/system.ts +4 -1
- package/plugins/kxm/src/engine-fold.ts +1 -0
- package/plugins/kxm/src/engine.ts +264 -22
- package/plugins/kxm/src/improve-sources.ts +17 -3
- package/plugins/kxm/src/improve.ts +14 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/policy-draft.mjs +2 -2
- package/plugins/kxm/src/role.ts +1 -1
- package/plugins/kxm/src/route-fallback.ts +504 -0
- package/plugins/kxm/src/route-switch.ts +49 -0
- package/plugins/kxm/src/routing.ts +24 -1
- package/schemas/common.schema.json +2 -1
- package/schemas/role.schema.json +1 -1
- package/schemas/run-event.schema.json +20 -1
- package/scripts/ci-unit-shard.mjs +1 -1
|
@@ -3834,7 +3834,7 @@ var require_fast_uri = __commonJS({
|
|
|
3834
3834
|
normalizeString(uri, options);
|
|
3835
3835
|
} else if (typeof uri === "object") {
|
|
3836
3836
|
uri = /** @type {T} */
|
|
3837
|
-
|
|
3837
|
+
parse11(serialize(uri, options), options);
|
|
3838
3838
|
}
|
|
3839
3839
|
return uri;
|
|
3840
3840
|
}
|
|
@@ -3874,8 +3874,8 @@ var require_fast_uri = __commonJS({
|
|
|
3874
3874
|
function resolveComponent(base, relative6, options, skipNormalization) {
|
|
3875
3875
|
const target = {};
|
|
3876
3876
|
if (!skipNormalization) {
|
|
3877
|
-
base =
|
|
3878
|
-
relative6 =
|
|
3877
|
+
base = parse11(serialize(base, options), options);
|
|
3878
|
+
relative6 = parse11(serialize(relative6, options), options);
|
|
3879
3879
|
}
|
|
3880
3880
|
options = options || {};
|
|
3881
3881
|
if (!options.tolerant && relative6.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 parse11(uri, opts) {
|
|
4171
4171
|
return parseWithStatus(uri, opts).parsed;
|
|
4172
4172
|
}
|
|
4173
4173
|
function normalizeString(uri, opts) {
|
|
@@ -4204,7 +4204,7 @@ var require_fast_uri = __commonJS({
|
|
|
4204
4204
|
resolveComponent,
|
|
4205
4205
|
equal,
|
|
4206
4206
|
serialize,
|
|
4207
|
-
parse:
|
|
4207
|
+
parse: parse11
|
|
4208
4208
|
};
|
|
4209
4209
|
module.exports = fastUri;
|
|
4210
4210
|
module.exports.default = fastUri;
|
|
@@ -14677,7 +14677,7 @@ var require_public_api = __commonJS({
|
|
|
14677
14677
|
}
|
|
14678
14678
|
return doc;
|
|
14679
14679
|
}
|
|
14680
|
-
function
|
|
14680
|
+
function parse11(src, reviver, options) {
|
|
14681
14681
|
let _reviver = void 0;
|
|
14682
14682
|
if (typeof reviver === "function") {
|
|
14683
14683
|
_reviver = reviver;
|
|
@@ -14718,7 +14718,7 @@ var require_public_api = __commonJS({
|
|
|
14718
14718
|
return value.toString(options);
|
|
14719
14719
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
14720
14720
|
}
|
|
14721
|
-
exports.parse =
|
|
14721
|
+
exports.parse = parse11;
|
|
14722
14722
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14723
14723
|
exports.parseDocument = parseDocument3;
|
|
14724
14724
|
exports.stringify = stringify7;
|
|
@@ -14973,7 +14973,7 @@ var TOOL_KEYS = Object.freeze(["preset", "allow", "deny"]);
|
|
|
14973
14973
|
var TEMPLATE_KEYS = Object.freeze(["template", "schema"]);
|
|
14974
14974
|
var POLICY_KEYS = Object.freeze(["vendorIndependenceRequired", "maxTransitions", "requiresGateVerification", "fallback"]);
|
|
14975
14975
|
var FALLBACK_KEYS = Object.freeze(["onError", "maxSwitches", "revert"]);
|
|
14976
|
-
var FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable"]);
|
|
14976
|
+
var FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable", "context_overflow"]);
|
|
14977
14977
|
var FALLBACK_REVERT = Object.freeze(["next_run", "never"]);
|
|
14978
14978
|
var ROSTER_ENTRY_KEYS = Object.freeze(["route", "effort", "mode"]);
|
|
14979
14979
|
var CRITIC_PURPOSES = Object.freeze(["reviewer-arch", "reviewer-cli"]);
|
|
@@ -15302,7 +15302,7 @@ function validateRoleShape(document, id, label, issues) {
|
|
|
15302
15302
|
if (!closedObject(fallback, FALLBACK_KEYS, path, issues)) return;
|
|
15303
15303
|
if (fallback.onError !== void 0) {
|
|
15304
15304
|
if (!Array.isArray(fallback.onError) || new Set(fallback.onError).size !== fallback.onError.length || fallback.onError.some((item) => !FALLBACK_ERRORS.includes(item))) {
|
|
15305
|
-
issues.push(issue2("schema", "schema_enum", path, "onError must be unique rate_limit, transport, or
|
|
15305
|
+
issues.push(issue2("schema", "schema_enum", path, "onError must be unique rate_limit, transport, provider_unavailable, or context_overflow values"));
|
|
15306
15306
|
}
|
|
15307
15307
|
}
|
|
15308
15308
|
if (fallback.maxSwitches !== void 0 && (!Number.isInteger(fallback.maxSwitches) || fallback.maxSwitches < 0)) {
|
|
@@ -16982,9 +16982,9 @@ async function probeHarnessesAsync(options = {}) {
|
|
|
16982
16982
|
);
|
|
16983
16983
|
}
|
|
16984
16984
|
function eligibleHarnesses(inventory) {
|
|
16985
|
-
const
|
|
16986
|
-
if (
|
|
16987
|
-
return
|
|
16985
|
+
const eligible2 = inventory.harnesses.filter((entry) => entry !== void 0 && entry.detected && entry.authenticated === true).map((entry) => entry.id);
|
|
16986
|
+
if (eligible2.length === 0) throw new Error("no_authenticated_harness");
|
|
16987
|
+
return eligible2;
|
|
16988
16988
|
}
|
|
16989
16989
|
function validateHarnessModelPair(harnessId, modelSpec) {
|
|
16990
16990
|
if (!isKnownHarnessId(harnessId)) {
|
|
@@ -18139,8 +18139,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
18139
18139
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
18140
18140
|
if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
18141
18141
|
}
|
|
18142
|
-
const
|
|
18143
|
-
const minimumPassed =
|
|
18142
|
+
const join25 = objectValue(step.join);
|
|
18143
|
+
const minimumPassed = join25 && typeof join25.minimumPassed === "number" ? join25.minimumPassed : void 0;
|
|
18144
18144
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
18145
18145
|
const distinctBy = names(assignment?.distinctBy);
|
|
18146
18146
|
if (distinctBy.length > 0) {
|
|
@@ -18161,10 +18161,10 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
18161
18161
|
}
|
|
18162
18162
|
const policy = objectValue(requirement.producerPolicy);
|
|
18163
18163
|
if (!policy) continue;
|
|
18164
|
-
const
|
|
18164
|
+
const eligible2 = names(policy.eligibleAgents);
|
|
18165
18165
|
const producerMinimum = numberValue(policy.minimumProducers, 1);
|
|
18166
|
-
if (producerMinimum > target || producerMinimum >
|
|
18167
|
-
for (const agentId of
|
|
18166
|
+
if (producerMinimum > target || producerMinimum > eligible2.length) issues.push(issue3("semantic", "producer_minimum_impossible", file, `${stepId}.${String(key)} producer minimum exceeds its eligible or target pool`));
|
|
18167
|
+
for (const agentId of eligible2) {
|
|
18168
18168
|
if (!lookupKxmResource(agents.values(), agentId, "agent")) issues.push(issue3("reference", "producer_agent_unknown", file, `${stepId}.${String(key)} references unknown producer ${agentId}`));
|
|
18169
18169
|
if (allowedAgents.length > 0 && !allowedAgents.includes(agentId)) issues.push(issue3("semantic", "producer_agent_ineligible", file, `${stepId}.${String(key)} producer ${agentId} is outside allowedAgents`));
|
|
18170
18170
|
}
|
|
@@ -22191,6 +22191,7 @@ function foldKxmRunState(run, plan, events, options = {}) {
|
|
|
22191
22191
|
foldEffectUncertain(state, plan, event);
|
|
22192
22192
|
break;
|
|
22193
22193
|
case "routing.attempt.recorded":
|
|
22194
|
+
case "routing.route_switched":
|
|
22194
22195
|
break;
|
|
22195
22196
|
default:
|
|
22196
22197
|
throw runtimeError("run_events_illegal", run.runId, `event type ${event.eventType} is not legal in this engine slice`);
|
|
@@ -23210,7 +23211,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
23210
23211
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
23211
23212
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
23212
23213
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
23213
|
-
const
|
|
23214
|
+
const join25 = compileJoin(step, id, sink);
|
|
23214
23215
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
23215
23216
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
23216
23217
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
|
|
@@ -23238,7 +23239,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
23238
23239
|
transitions: orderedTransitions,
|
|
23239
23240
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
23240
23241
|
assignments,
|
|
23241
|
-
join:
|
|
23242
|
+
join: join25
|
|
23242
23243
|
};
|
|
23243
23244
|
if (kind === "agent" || kind === "moa") {
|
|
23244
23245
|
if (!agent) return void 0;
|
|
@@ -23288,15 +23289,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
23288
23289
|
};
|
|
23289
23290
|
}
|
|
23290
23291
|
function compileJoin(step, stepId, sink) {
|
|
23291
|
-
const
|
|
23292
|
-
if (!
|
|
23293
|
-
const declared = stringValue2(
|
|
23292
|
+
const join25 = objectValue2(step.join);
|
|
23293
|
+
if (!join25) return { strategy: "all" };
|
|
23294
|
+
const declared = stringValue2(join25.strategy);
|
|
23294
23295
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
23295
|
-
const minimumPassed = compileOptionalCount(
|
|
23296
|
+
const minimumPassed = compileOptionalCount(join25.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
23296
23297
|
const compiled = {
|
|
23297
23298
|
strategy,
|
|
23298
23299
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
23299
|
-
...typeof
|
|
23300
|
+
...typeof join25.cancelRemaining === "boolean" ? { cancelRemaining: join25.cancelRemaining } : {}
|
|
23300
23301
|
};
|
|
23301
23302
|
return compiled;
|
|
23302
23303
|
}
|
|
@@ -25180,9 +25181,9 @@ function assertKxmConfigError(error) {
|
|
|
25180
25181
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
25181
25182
|
import { spawn as spawn3 } from "node:child_process";
|
|
25182
25183
|
import { createHash as createHash16, createHmac, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
25183
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
25184
|
+
import { chmodSync as chmodSync2, existsSync as existsSync18, lstatSync as lstatSync6, mkdirSync as mkdirSync9, readFileSync as readFileSync15, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25184
25185
|
import { createServer } from "node:http";
|
|
25185
|
-
import { dirname as dirname11, isAbsolute as isAbsolute8, join as
|
|
25186
|
+
import { dirname as dirname11, isAbsolute as isAbsolute8, join as join20 } from "node:path";
|
|
25186
25187
|
|
|
25187
25188
|
// plugins/kxm/src/oneshot-evidence.ts
|
|
25188
25189
|
import { createHash as createHash10, randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -25511,10 +25512,10 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
25511
25512
|
}
|
|
25512
25513
|
|
|
25513
25514
|
// plugins/kxm/src/engine.ts
|
|
25514
|
-
var
|
|
25515
|
+
var import_yaml11 = __toESM(require_dist(), 1);
|
|
25515
25516
|
import { createHash as createHash15, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
|
|
25516
|
-
import { existsSync as
|
|
25517
|
-
import { join as
|
|
25517
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
|
|
25518
|
+
import { join as join17 } from "node:path";
|
|
25518
25519
|
|
|
25519
25520
|
// plugins/kxm/src/routes.ts
|
|
25520
25521
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
@@ -25550,6 +25551,363 @@ function listRoleBindings(root) {
|
|
|
25550
25551
|
return result;
|
|
25551
25552
|
}
|
|
25552
25553
|
|
|
25554
|
+
// plugins/kxm/src/route-fallback.ts
|
|
25555
|
+
var import_yaml8 = __toESM(require_dist(), 1);
|
|
25556
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync9 } from "node:fs";
|
|
25557
|
+
import { join as join12 } from "node:path";
|
|
25558
|
+
|
|
25559
|
+
// plugins/kxm/src/route-switch.ts
|
|
25560
|
+
var WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
|
|
25561
|
+
var EFFORTS2 = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
25562
|
+
|
|
25563
|
+
// plugins/kxm/src/route-fallback.ts
|
|
25564
|
+
var CARRY_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool"]);
|
|
25565
|
+
var MAX_CARRY_MESSAGES = 8;
|
|
25566
|
+
var MAX_CARRY_TEXT = 2e3;
|
|
25567
|
+
var MAX_CARRY_TOTAL = 8e3;
|
|
25568
|
+
var DEFAULT_MAX_SWITCHES = 1;
|
|
25569
|
+
function classifyRouteFailure(input) {
|
|
25570
|
+
const code = (input.code ?? "").toLowerCase();
|
|
25571
|
+
const text = `${code} ${input.text ?? ""}`.toLowerCase();
|
|
25572
|
+
const name = (input.name ?? "").toLowerCase();
|
|
25573
|
+
const status = input.httpStatus;
|
|
25574
|
+
const result = (failureClass) => ({
|
|
25575
|
+
class: failureClass,
|
|
25576
|
+
walkable: WALKABLE_CLASSES.includes(failureClass)
|
|
25577
|
+
});
|
|
25578
|
+
if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted" || text.includes("abort")) {
|
|
25579
|
+
return result("cancelled");
|
|
25580
|
+
}
|
|
25581
|
+
if (/policy_refusal|content_policy|tool_policy|usage policy|safety/.test(text) || text.includes("policy refusal")) {
|
|
25582
|
+
return result("policy_refusal");
|
|
25583
|
+
}
|
|
25584
|
+
if (code.includes("not_authenticated") || /unauthori[sz]ed|authentication|invalid api key|auth_failed|\bauth\b/.test(text) || status === 401 || status === 403) {
|
|
25585
|
+
return result("auth");
|
|
25586
|
+
}
|
|
25587
|
+
if (/permission_profile_unaudited|writer_profile_unaudited|tool_policy/.test(text)) {
|
|
25588
|
+
return result("tool_policy");
|
|
25589
|
+
}
|
|
25590
|
+
if (/harness_unhosted_model|unhosted|does not host/.test(text)) {
|
|
25591
|
+
return result("unhosted_model");
|
|
25592
|
+
}
|
|
25593
|
+
if (code.startsWith("gate_") || text.includes("gate_unsupported") || text.includes("gate_failed")) {
|
|
25594
|
+
return result("gate");
|
|
25595
|
+
}
|
|
25596
|
+
if (code === "producer_route_not_admitted" || text.includes("not_admitted") || text.includes("not admitted")) {
|
|
25597
|
+
return result("admission");
|
|
25598
|
+
}
|
|
25599
|
+
if (status === 413 || /context_overflow|context length|context window|maximum context|token limit|prompt too long|context overflow/.test(text)) {
|
|
25600
|
+
return result("context_overflow");
|
|
25601
|
+
}
|
|
25602
|
+
if (status === 429 || /rate_limit|rate limit|ratelimit|too many requests/.test(text)) {
|
|
25603
|
+
return result("rate_limit");
|
|
25604
|
+
}
|
|
25605
|
+
if (status === 408 || status === 502 || status === 504 || code === "process_timeout" || /etimedout|econnreset|econnrefused|enotfound|eai_again|socket hang up|\btimeout\b|timed out|\btransport\b/.test(text)) {
|
|
25606
|
+
return result("transport");
|
|
25607
|
+
}
|
|
25608
|
+
if (status === 500 || status === 503 || /provider_unavailable|model unavailable|service unavailable|overloaded|model_not_found|no available model/.test(text)) {
|
|
25609
|
+
return result("provider_unavailable");
|
|
25610
|
+
}
|
|
25611
|
+
return result("unknown");
|
|
25612
|
+
}
|
|
25613
|
+
function parseFallbackPolicy(value) {
|
|
25614
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
25615
|
+
const record2 = value;
|
|
25616
|
+
const onErrorRaw = record2.onError;
|
|
25617
|
+
if (!Array.isArray(onErrorRaw) || onErrorRaw.length === 0) return void 0;
|
|
25618
|
+
if (new Set(onErrorRaw).size !== onErrorRaw.length) return void 0;
|
|
25619
|
+
const onError = [];
|
|
25620
|
+
for (const item of onErrorRaw) {
|
|
25621
|
+
if (typeof item !== "string" || !WALKABLE_CLASSES.includes(item)) return void 0;
|
|
25622
|
+
onError.push(item);
|
|
25623
|
+
}
|
|
25624
|
+
let maxSwitches = DEFAULT_MAX_SWITCHES;
|
|
25625
|
+
if (record2.maxSwitches !== void 0) {
|
|
25626
|
+
if (!Number.isInteger(record2.maxSwitches) || record2.maxSwitches < 0) return void 0;
|
|
25627
|
+
maxSwitches = record2.maxSwitches;
|
|
25628
|
+
}
|
|
25629
|
+
let revert = "next_run";
|
|
25630
|
+
if (record2.revert !== void 0) {
|
|
25631
|
+
if (record2.revert !== "next_run" && record2.revert !== "never") return void 0;
|
|
25632
|
+
revert = record2.revert;
|
|
25633
|
+
}
|
|
25634
|
+
return { onError, maxSwitches, revert };
|
|
25635
|
+
}
|
|
25636
|
+
function admittedSelector(model, admitted, disabled) {
|
|
25637
|
+
const candidates = [model.model, `${model.vendor}/${model.model}`, `${model.harness}/${model.model}`];
|
|
25638
|
+
const selector = candidates.find((candidate) => admitted.has(candidate));
|
|
25639
|
+
if (!selector || disabled.has(selector)) return void 0;
|
|
25640
|
+
return selector;
|
|
25641
|
+
}
|
|
25642
|
+
function splitSelector(selector) {
|
|
25643
|
+
const slash = selector.indexOf("/");
|
|
25644
|
+
if (slash <= 0 || slash === selector.length - 1) return void 0;
|
|
25645
|
+
return { provider: selector.slice(0, slash), model: selector.slice(slash + 1) };
|
|
25646
|
+
}
|
|
25647
|
+
function eligible(model, admitted, disabled, liveWrite) {
|
|
25648
|
+
if (model.status !== "admitted" || !model.hosted) return void 0;
|
|
25649
|
+
if (liveWrite && (!model.permissions.includes("edit") || !model.writerReady || !model.onWriterRoster)) return void 0;
|
|
25650
|
+
const selector = admittedSelector(model, admitted, disabled);
|
|
25651
|
+
if (!selector) return void 0;
|
|
25652
|
+
const parts = splitSelector(selector);
|
|
25653
|
+
if (!parts) return void 0;
|
|
25654
|
+
return {
|
|
25655
|
+
routeId: model.routeId,
|
|
25656
|
+
harness: model.harness,
|
|
25657
|
+
provider: parts.provider,
|
|
25658
|
+
model: parts.model,
|
|
25659
|
+
selector,
|
|
25660
|
+
vendor: model.vendor,
|
|
25661
|
+
permissions: model.permissions,
|
|
25662
|
+
priority: model.priority
|
|
25663
|
+
};
|
|
25664
|
+
}
|
|
25665
|
+
function selectorsFor2(fallback, models) {
|
|
25666
|
+
if (fallback.profile) {
|
|
25667
|
+
const model = models.find((item) => item.routeId === fallback.profile);
|
|
25668
|
+
return model ? [model] : [];
|
|
25669
|
+
}
|
|
25670
|
+
if (fallback.tag) {
|
|
25671
|
+
const required2 = new Set(fallback.capabilities ?? []);
|
|
25672
|
+
return models.filter((item) => item.tags.includes(fallback.tag) && [...required2].every((capability) => item.capabilities.includes(capability))).slice().sort((left, right) => right.priority - left.priority || left.routeId.localeCompare(right.routeId));
|
|
25673
|
+
}
|
|
25674
|
+
if (fallback.provider && fallback.model) {
|
|
25675
|
+
return models.filter((item) => item.vendor === fallback.provider && item.model === fallback.model);
|
|
25676
|
+
}
|
|
25677
|
+
return [];
|
|
25678
|
+
}
|
|
25679
|
+
function buildFallbackChain(input) {
|
|
25680
|
+
const admitted = new Set(input.admitted);
|
|
25681
|
+
const disabled = new Set(input.disabled);
|
|
25682
|
+
const critics = new Set(input.criticVendors ?? []);
|
|
25683
|
+
const byId = new Map(input.models.map((model) => [model.routeId, model]));
|
|
25684
|
+
const chain = [];
|
|
25685
|
+
const seen = /* @__PURE__ */ new Set();
|
|
25686
|
+
const entries = [...input.roster, ...input.extendsRoster ?? []];
|
|
25687
|
+
const push2 = (model, effort) => {
|
|
25688
|
+
if (!model || seen.has(model.routeId)) return;
|
|
25689
|
+
const candidate = eligible(model, admitted, disabled, input.liveWrite);
|
|
25690
|
+
if (!candidate) return;
|
|
25691
|
+
if (input.vendorIndependenceRequired && chain.length > 0 && critics.has(candidate.vendor)) return;
|
|
25692
|
+
seen.add(model.routeId);
|
|
25693
|
+
const resolvedEffort = effort && EFFORTS2.has(effort) ? effort : void 0;
|
|
25694
|
+
chain.push(resolvedEffort ? { ...candidate, effort: resolvedEffort } : candidate);
|
|
25695
|
+
};
|
|
25696
|
+
for (const entry of entries) {
|
|
25697
|
+
const model = byId.get(entry.route);
|
|
25698
|
+
push2(model, entry.effort);
|
|
25699
|
+
if (!model) continue;
|
|
25700
|
+
for (const fallback of model.fallbacks) {
|
|
25701
|
+
for (const resolved of selectorsFor2(fallback, input.models)) push2(resolved, entry.effort);
|
|
25702
|
+
}
|
|
25703
|
+
}
|
|
25704
|
+
return chain;
|
|
25705
|
+
}
|
|
25706
|
+
function decideRouteSwitch(input) {
|
|
25707
|
+
if (!input.policy || input.policy.onError.length === 0) return { action: "continue", cause: "disabled" };
|
|
25708
|
+
if (!input.failure.walkable) return { action: "continue", cause: "not_walkable" };
|
|
25709
|
+
if (!input.policy.onError.includes(input.failure.class)) {
|
|
25710
|
+
return { action: "continue", cause: "class_not_opted_in" };
|
|
25711
|
+
}
|
|
25712
|
+
if (input.switchesUsed >= input.policy.maxSwitches) return { action: "continue", cause: "budget" };
|
|
25713
|
+
const index = input.chain.findIndex((candidate) => candidate.routeId === input.currentRouteId);
|
|
25714
|
+
const next = index >= 0 ? input.chain[index + 1] : void 0;
|
|
25715
|
+
if (!next) return { action: "continue", cause: "no_candidate" };
|
|
25716
|
+
const effort = next.effort ?? (input.currentEffort && EFFORTS2.has(input.currentEffort) ? input.currentEffort : void 0);
|
|
25717
|
+
return {
|
|
25718
|
+
action: "switch",
|
|
25719
|
+
to: next,
|
|
25720
|
+
reason: input.failure.class,
|
|
25721
|
+
...effort ? { effort } : {}
|
|
25722
|
+
};
|
|
25723
|
+
}
|
|
25724
|
+
function parseSessionCarry(value) {
|
|
25725
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
25726
|
+
const transcript = value.transcript;
|
|
25727
|
+
if (!Array.isArray(transcript) || transcript.length === 0) return void 0;
|
|
25728
|
+
const messages = [];
|
|
25729
|
+
let total = 0;
|
|
25730
|
+
for (const item of transcript) {
|
|
25731
|
+
if (messages.length >= MAX_CARRY_MESSAGES) break;
|
|
25732
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
25733
|
+
const role = item.role;
|
|
25734
|
+
const text = item.text;
|
|
25735
|
+
if (typeof role !== "string" || !CARRY_ROLES.has(role) || typeof text !== "string" || text.length === 0) continue;
|
|
25736
|
+
const clipped = text.slice(0, MAX_CARRY_TEXT);
|
|
25737
|
+
if (total + clipped.length > MAX_CARRY_TOTAL) break;
|
|
25738
|
+
total += clipped.length;
|
|
25739
|
+
messages.push({ role, text: clipped });
|
|
25740
|
+
}
|
|
25741
|
+
return messages.length > 0 ? { transcript: messages } : void 0;
|
|
25742
|
+
}
|
|
25743
|
+
function mergeSessionCarry(left, right) {
|
|
25744
|
+
return parseSessionCarry({ transcript: [...left?.transcript ?? [], ...right?.transcript ?? []] });
|
|
25745
|
+
}
|
|
25746
|
+
function carryForwardPrompt(prompt, carry) {
|
|
25747
|
+
if (!carry || carry.transcript.length === 0) return prompt;
|
|
25748
|
+
const lines = carry.transcript.map((message) => `${message.role}: ${message.text}`);
|
|
25749
|
+
const block = `Prior attempt transcript:
|
|
25750
|
+
${lines.join("\n")}`;
|
|
25751
|
+
if (!prompt || prompt.length === 0) return block;
|
|
25752
|
+
return `${prompt}
|
|
25753
|
+
|
|
25754
|
+
${block}`;
|
|
25755
|
+
}
|
|
25756
|
+
function readYaml(file) {
|
|
25757
|
+
if (!existsSync11(file)) return void 0;
|
|
25758
|
+
try {
|
|
25759
|
+
const parsed = (0, import_yaml8.parse)(readFileSync9(file, "utf8"));
|
|
25760
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
25761
|
+
return parsed;
|
|
25762
|
+
} catch {
|
|
25763
|
+
return void 0;
|
|
25764
|
+
}
|
|
25765
|
+
}
|
|
25766
|
+
function stringList(value) {
|
|
25767
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
25768
|
+
}
|
|
25769
|
+
function readSelectors(projectRoot, value) {
|
|
25770
|
+
if (!Array.isArray(value)) return [];
|
|
25771
|
+
const modelsDir = join12(projectRoot, ".kxm", "models");
|
|
25772
|
+
const selectors = [];
|
|
25773
|
+
for (const item of value) {
|
|
25774
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
25775
|
+
const record2 = item;
|
|
25776
|
+
if (typeof record2.profile === "string") {
|
|
25777
|
+
selectors.push({ profile: findYamlBasename(modelsDir, record2.profile, "route") ?? record2.profile });
|
|
25778
|
+
} else if (typeof record2.tag === "string") {
|
|
25779
|
+
selectors.push({
|
|
25780
|
+
tag: record2.tag,
|
|
25781
|
+
...Array.isArray(record2.capabilities) ? { capabilities: stringList(record2.capabilities) } : {}
|
|
25782
|
+
});
|
|
25783
|
+
} else if (typeof record2.provider === "string" && typeof record2.model === "string") {
|
|
25784
|
+
selectors.push({ provider: record2.provider, model: record2.model });
|
|
25785
|
+
}
|
|
25786
|
+
}
|
|
25787
|
+
return selectors;
|
|
25788
|
+
}
|
|
25789
|
+
function loadChainModel(projectRoot, routeId2, writerIds) {
|
|
25790
|
+
const modelsDir = join12(projectRoot, ".kxm", "models");
|
|
25791
|
+
const fileId = findYamlBasename(modelsDir, routeId2, "route") ?? routeId2;
|
|
25792
|
+
const doc = readYaml(join12(modelsDir, `${fileId}.yaml`));
|
|
25793
|
+
if (!doc || doc.schema !== "kxm.model.v2") return void 0;
|
|
25794
|
+
const harness = typeof doc.harness === "string" ? doc.harness : "";
|
|
25795
|
+
const model = typeof doc.model === "string" ? doc.model : "";
|
|
25796
|
+
const vendor = typeof doc.vendor === "string" ? doc.vendor : "";
|
|
25797
|
+
if (!harness || !model || !vendor) return void 0;
|
|
25798
|
+
const permissions = stringList(doc.permissions);
|
|
25799
|
+
const selector = [model, `${vendor}/${model}`, `${harness}/${model}`].find((candidate) => candidate.includes("/")) ?? `${vendor}/${model}`;
|
|
25800
|
+
const parts = splitSelector(selector);
|
|
25801
|
+
const hosted = parts ? validateHarnessModelPair(harness, { provider: parts.provider, model: parts.model }).valid : false;
|
|
25802
|
+
return {
|
|
25803
|
+
routeId: fileId,
|
|
25804
|
+
harness,
|
|
25805
|
+
model,
|
|
25806
|
+
vendor,
|
|
25807
|
+
status: typeof doc.status === "string" ? doc.status : "",
|
|
25808
|
+
permissions,
|
|
25809
|
+
tags: stringList(doc.tags),
|
|
25810
|
+
capabilities: stringList(doc.capabilities),
|
|
25811
|
+
priority: typeof doc.priority === "number" ? doc.priority : 0,
|
|
25812
|
+
fallbacks: readSelectors(projectRoot, doc.fallbacks),
|
|
25813
|
+
hosted,
|
|
25814
|
+
writerReady: oneShotWriterArgs(harness) !== void 0,
|
|
25815
|
+
onWriterRoster: writerIds.has(fileId) || writerIds.has(routeId2)
|
|
25816
|
+
};
|
|
25817
|
+
}
|
|
25818
|
+
function canonicalRoster(projectRoot, entries) {
|
|
25819
|
+
const modelsDir = join12(projectRoot, ".kxm", "models");
|
|
25820
|
+
return entries.map((entry) => {
|
|
25821
|
+
const route = findYamlBasename(modelsDir, entry.route, "route") ?? entry.route;
|
|
25822
|
+
return entry.effort ? { route, effort: entry.effort } : { route };
|
|
25823
|
+
});
|
|
25824
|
+
}
|
|
25825
|
+
function rosterEntries(doc) {
|
|
25826
|
+
if (!Array.isArray(doc?.roster)) return [];
|
|
25827
|
+
const entries = [];
|
|
25828
|
+
for (const item of doc.roster) {
|
|
25829
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
25830
|
+
const route = item.route;
|
|
25831
|
+
const effort = item.effort;
|
|
25832
|
+
if (typeof route !== "string" || route.length === 0) continue;
|
|
25833
|
+
entries.push(typeof effort === "string" ? { route, effort } : { route });
|
|
25834
|
+
}
|
|
25835
|
+
return entries;
|
|
25836
|
+
}
|
|
25837
|
+
function loadModelsFor(projectRoot, roster, writerIds) {
|
|
25838
|
+
const modelsDir = join12(projectRoot, ".kxm", "models");
|
|
25839
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
25840
|
+
for (const entry of roster) wanted.add(entry.route);
|
|
25841
|
+
if (existsSync11(modelsDir)) {
|
|
25842
|
+
for (const name of readdirSync7(modelsDir)) {
|
|
25843
|
+
if (!name.endsWith(".yaml") || name === "inventory.yaml") continue;
|
|
25844
|
+
wanted.add(name.slice(0, -5));
|
|
25845
|
+
}
|
|
25846
|
+
}
|
|
25847
|
+
const models = [];
|
|
25848
|
+
const seen = /* @__PURE__ */ new Set();
|
|
25849
|
+
for (const routeId2 of wanted) {
|
|
25850
|
+
const model = loadChainModel(projectRoot, routeId2, writerIds);
|
|
25851
|
+
if (!model || seen.has(model.routeId)) continue;
|
|
25852
|
+
seen.add(model.routeId);
|
|
25853
|
+
models.push(model);
|
|
25854
|
+
}
|
|
25855
|
+
return models;
|
|
25856
|
+
}
|
|
25857
|
+
function criticVendors(projectRoot, writerIds) {
|
|
25858
|
+
const dir = join12(projectRoot, ".kxm", "roles");
|
|
25859
|
+
if (!existsSync11(dir)) return [];
|
|
25860
|
+
const vendors = [];
|
|
25861
|
+
for (const name of readdirSync7(dir)) {
|
|
25862
|
+
if (!name.endsWith(".yaml")) continue;
|
|
25863
|
+
const doc = readYaml(join12(dir, name));
|
|
25864
|
+
const purpose = doc?.purpose;
|
|
25865
|
+
if (purpose !== "reviewer-arch" && purpose !== "reviewer-cli") continue;
|
|
25866
|
+
const first = rosterEntries(doc)[0];
|
|
25867
|
+
if (!first) continue;
|
|
25868
|
+
const model = loadChainModel(projectRoot, first.route, writerIds);
|
|
25869
|
+
if (model?.status === "admitted") vendors.push(model.vendor);
|
|
25870
|
+
}
|
|
25871
|
+
return vendors;
|
|
25872
|
+
}
|
|
25873
|
+
function loadAgentFallback(projectRoot, agentId, options) {
|
|
25874
|
+
const agentsDir = join12(projectRoot, ".kxm", "agents");
|
|
25875
|
+
const agentFile = findYamlBasename(agentsDir, agentId, "agent") ?? agentId;
|
|
25876
|
+
const agent = readYaml(join12(agentsDir, `${agentFile}.yaml`));
|
|
25877
|
+
const roleId = typeof agent?.role === "string" ? agent.role : "";
|
|
25878
|
+
if (!roleId) return void 0;
|
|
25879
|
+
const role = readYaml(join12(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
|
|
25880
|
+
if (!role) return void 0;
|
|
25881
|
+
const policyRecord = role.policy && typeof role.policy === "object" ? role.policy.fallback : void 0;
|
|
25882
|
+
const policy = parseFallbackPolicy(policyRecord);
|
|
25883
|
+
if (!policy) return void 0;
|
|
25884
|
+
const own2 = canonicalRoster(projectRoot, rosterEntries(role));
|
|
25885
|
+
const seenRoles = /* @__PURE__ */ new Set([roleId]);
|
|
25886
|
+
let extendsRoster = [];
|
|
25887
|
+
let cursor = typeof role.extends === "string" ? role.extends : "";
|
|
25888
|
+
while (cursor && !seenRoles.has(cursor)) {
|
|
25889
|
+
seenRoles.add(cursor);
|
|
25890
|
+
const parent = readYaml(join12(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
|
|
25891
|
+
extendsRoster = extendsRoster.concat(canonicalRoster(projectRoot, rosterEntries(parent)));
|
|
25892
|
+
cursor = typeof parent?.extends === "string" ? parent.extends : "";
|
|
25893
|
+
}
|
|
25894
|
+
const writerIds = new Set(listRoleBindings(projectRoot).writer ?? []);
|
|
25895
|
+
const models = loadModelsFor(projectRoot, [...own2, ...extendsRoster], writerIds);
|
|
25896
|
+
const routePolicy = loadRoutePolicy(projectRoot);
|
|
25897
|
+
const independence = Boolean(role.policy && typeof role.policy === "object" && role.policy.vendorIndependenceRequired);
|
|
25898
|
+
const chain = buildFallbackChain({
|
|
25899
|
+
roster: own2,
|
|
25900
|
+
extendsRoster,
|
|
25901
|
+
models,
|
|
25902
|
+
admitted: routePolicy.admitted,
|
|
25903
|
+
disabled: routePolicy.disabled,
|
|
25904
|
+
liveWrite: options.liveWrite,
|
|
25905
|
+
criticVendors: independence ? criticVendors(projectRoot, writerIds) : [],
|
|
25906
|
+
vendorIndependenceRequired: independence
|
|
25907
|
+
});
|
|
25908
|
+
return { policy, chain, roleId };
|
|
25909
|
+
}
|
|
25910
|
+
|
|
25553
25911
|
// plugins/kxm/src/worktree-witness.ts
|
|
25554
25912
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
25555
25913
|
function gitText(cwd, args) {
|
|
@@ -25876,8 +26234,8 @@ function pruneContextPacket(packet, tokenBudget) {
|
|
|
25876
26234
|
|
|
25877
26235
|
// plugins/kxm/src/dispatch-context.ts
|
|
25878
26236
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
25879
|
-
import { readdirSync as
|
|
25880
|
-
import { extname as extname3, join as
|
|
26237
|
+
import { readdirSync as readdirSync10 } from "node:fs";
|
|
26238
|
+
import { extname as extname3, join as join15 } from "node:path";
|
|
25881
26239
|
|
|
25882
26240
|
// plugins/kxm/src/protocol.ts
|
|
25883
26241
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
@@ -26409,16 +26767,16 @@ function arbitrate(requestInput, pool, options = {}) {
|
|
|
26409
26767
|
};
|
|
26410
26768
|
const allowedKinds = new Set(requestedKinds);
|
|
26411
26769
|
const inertProposal = (item) => item.kind === "state" && item.status !== void 0 && item.status !== "current" || item.kind === "skill" && item.status === "proposed";
|
|
26412
|
-
const
|
|
26413
|
-
const scoreList = scoreRelevance(request.task,
|
|
26770
|
+
const eligible2 = candidates.filter((item) => contradictions.has(item.id) || allowedKinds.has(item.kind) && !inertProposal(item));
|
|
26771
|
+
const scoreList = scoreRelevance(request.task, eligible2.map(contextItemRelevanceText));
|
|
26414
26772
|
const scores = /* @__PURE__ */ new Map();
|
|
26415
|
-
|
|
26773
|
+
eligible2.forEach((item, index) => scores.set(item, scoreList[index] ?? 0));
|
|
26416
26774
|
const scoreOf = (item) => scores.get(item) ?? 0;
|
|
26417
26775
|
const when = (item) => {
|
|
26418
26776
|
const parsed = Date.parse(item.observedAt ?? item.validFrom ?? "");
|
|
26419
26777
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
26420
26778
|
};
|
|
26421
|
-
const ordered = [...
|
|
26779
|
+
const ordered = [...eligible2].sort(
|
|
26422
26780
|
(left, right) => (contradictions.has(right.id) ? 1 : 0) - (contradictions.has(left.id) ? 1 : 0) || (left.project === request.project ? 0 : 1) - (right.project === request.project ? 0 : 1) || (scoreOf(right) > 0 ? 1 : 0) - (scoreOf(left) > 0 ? 1 : 0) || kindPreference(left) - kindPreference(right) || scoreOf(right) - scoreOf(left) || CONFIDENCE_RANK[right.confidence] - CONFIDENCE_RANK[left.confidence] || AUTHORITY_WEIGHT[right.authority] - AUTHORITY_WEIGHT[left.authority] || when(right) - when(left) || compareCodeUnitIds(left.id, right.id)
|
|
26423
26781
|
);
|
|
26424
26782
|
const selected = [];
|
|
@@ -26508,9 +26866,9 @@ function memoryRecordToContextItem(record2, project) {
|
|
|
26508
26866
|
}
|
|
26509
26867
|
|
|
26510
26868
|
// plugins/kxm/src/memory.ts
|
|
26511
|
-
var
|
|
26512
|
-
import { existsSync as
|
|
26513
|
-
import { extname as extname2, join as
|
|
26869
|
+
var import_yaml9 = __toESM(require_dist(), 1);
|
|
26870
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4, readdirSync as readdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
|
|
26871
|
+
import { extname as extname2, join as join13, resolve as resolve7 } from "node:path";
|
|
26514
26872
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
26515
26873
|
var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
|
|
26516
26874
|
var VALID_AUTHORITIES = /* @__PURE__ */ new Set(["instruction", "evidence", "promoted"]);
|
|
@@ -26540,7 +26898,7 @@ function parseFrontmatter(content) {
|
|
|
26540
26898
|
}
|
|
26541
26899
|
function parseMemoryRecord(raw, filename = "memory.md") {
|
|
26542
26900
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
26543
|
-
const data = (0,
|
|
26901
|
+
const data = (0, import_yaml9.parse)(frontmatter);
|
|
26544
26902
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
26545
26903
|
throw new Error(`invalid YAML frontmatter in ${filename}`);
|
|
26546
26904
|
}
|
|
@@ -26609,20 +26967,20 @@ function parseMemoryRecord(raw, filename = "memory.md") {
|
|
|
26609
26967
|
}
|
|
26610
26968
|
function memoryDirectories(repoRoot) {
|
|
26611
26969
|
const root = resolve7(repoRoot);
|
|
26612
|
-
const memoryDir =
|
|
26613
|
-
const candidatesDir =
|
|
26970
|
+
const memoryDir = join13(root, ".kxm", "memory");
|
|
26971
|
+
const candidatesDir = join13(memoryDir, "candidates");
|
|
26614
26972
|
return { memoryDir, candidatesDir };
|
|
26615
26973
|
}
|
|
26616
26974
|
function loadAuthoredMemory(repoRoot) {
|
|
26617
26975
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
26618
|
-
if (!
|
|
26976
|
+
if (!existsSync12(memoryDir)) return [];
|
|
26619
26977
|
const records = [];
|
|
26620
|
-
const entries =
|
|
26978
|
+
const entries = readdirSync8(memoryDir, { withFileTypes: true });
|
|
26621
26979
|
for (const entry of entries) {
|
|
26622
26980
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
26623
|
-
const fullPath =
|
|
26981
|
+
const fullPath = join13(memoryDir, entry.name);
|
|
26624
26982
|
try {
|
|
26625
|
-
const text =
|
|
26983
|
+
const text = readFileSync10(fullPath, "utf8");
|
|
26626
26984
|
const record2 = parseMemoryRecord(text, entry.name);
|
|
26627
26985
|
if (record2.lifecycle === "active") {
|
|
26628
26986
|
records.push(record2);
|
|
@@ -26636,10 +26994,10 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
26636
26994
|
}
|
|
26637
26995
|
|
|
26638
26996
|
// plugins/kxm/src/skills.ts
|
|
26639
|
-
var
|
|
26997
|
+
var import_yaml10 = __toESM(require_dist(), 1);
|
|
26640
26998
|
import { createHash as createHash12 } from "node:crypto";
|
|
26641
|
-
import { existsSync as
|
|
26642
|
-
import { dirname as dirname7, join as
|
|
26999
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync11, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
27000
|
+
import { dirname as dirname7, join as join14 } from "node:path";
|
|
26643
27001
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
26644
27002
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
26645
27003
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -26680,7 +27038,7 @@ function parseSkillFrontmatter(content) {
|
|
|
26680
27038
|
return { frontmatter: null, body: content };
|
|
26681
27039
|
}
|
|
26682
27040
|
try {
|
|
26683
|
-
const parsed = (0,
|
|
27041
|
+
const parsed = (0, import_yaml10.parse)(rawFm);
|
|
26684
27042
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
26685
27043
|
return { frontmatter: parsed, body: rawBody };
|
|
26686
27044
|
}
|
|
@@ -26745,20 +27103,20 @@ var SkillLifecycle = class {
|
|
|
26745
27103
|
writeFileSync6(file, content);
|
|
26746
27104
|
}
|
|
26747
27105
|
dir(state) {
|
|
26748
|
-
return
|
|
27106
|
+
return join14(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
26749
27107
|
}
|
|
26750
27108
|
historyFile(id) {
|
|
26751
|
-
return
|
|
27109
|
+
return join14(this.root, "history", `${id}.jsonl`);
|
|
26752
27110
|
}
|
|
26753
27111
|
paths(state, id) {
|
|
26754
|
-
const dir =
|
|
26755
|
-
return { dir, metadata:
|
|
27112
|
+
const dir = join14(this.dir(state), id);
|
|
27113
|
+
return { dir, metadata: join14(dir, "metadata.json"), skill: join14(dir, "SKILL.md") };
|
|
26756
27114
|
}
|
|
26757
27115
|
appendHistory(id, record2) {
|
|
26758
27116
|
const line = `${JSON.stringify(record2)}
|
|
26759
27117
|
`;
|
|
26760
|
-
if (
|
|
26761
|
-
const existing =
|
|
27118
|
+
if (existsSync13(this.historyFile(id))) {
|
|
27119
|
+
const existing = readFileSync11(this.historyFile(id), "utf8");
|
|
26762
27120
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
26763
27121
|
this.write(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
26764
27122
|
} else {
|
|
@@ -26767,20 +27125,20 @@ var SkillLifecycle = class {
|
|
|
26767
27125
|
}
|
|
26768
27126
|
history(id) {
|
|
26769
27127
|
const file = this.historyFile(id);
|
|
26770
|
-
if (!
|
|
26771
|
-
return
|
|
27128
|
+
if (!existsSync13(file)) return [];
|
|
27129
|
+
return readFileSync11(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
26772
27130
|
}
|
|
26773
27131
|
readMetadata(state, id) {
|
|
26774
27132
|
const { metadata } = this.paths(state, id);
|
|
26775
|
-
if (!
|
|
27133
|
+
if (!existsSync13(metadata)) {
|
|
26776
27134
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
26777
27135
|
}
|
|
26778
|
-
return JSON.parse(
|
|
27136
|
+
return JSON.parse(readFileSync11(metadata, "utf8"));
|
|
26779
27137
|
}
|
|
26780
27138
|
move(from, to, id) {
|
|
26781
|
-
const fromDir =
|
|
26782
|
-
const toDir =
|
|
26783
|
-
if (!
|
|
27139
|
+
const fromDir = join14(this.dir(from), id);
|
|
27140
|
+
const toDir = join14(this.dir(to), id);
|
|
27141
|
+
if (!existsSync13(fromDir)) {
|
|
26784
27142
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
26785
27143
|
}
|
|
26786
27144
|
if (this.dryRun) {
|
|
@@ -26788,7 +27146,7 @@ var SkillLifecycle = class {
|
|
|
26788
27146
|
return;
|
|
26789
27147
|
}
|
|
26790
27148
|
mkdirSync5(this.dir(to), { recursive: true });
|
|
26791
|
-
if (
|
|
27149
|
+
if (existsSync13(toDir)) rmSync(toDir, { recursive: true, force: true });
|
|
26792
27150
|
renameSync(fromDir, toDir);
|
|
26793
27151
|
}
|
|
26794
27152
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
@@ -26831,7 +27189,7 @@ var SkillLifecycle = class {
|
|
|
26831
27189
|
const contentSha256 = skillContentSha256(content);
|
|
26832
27190
|
const id = skillIdFor(name, contentSha256);
|
|
26833
27191
|
const { metadata, skill } = this.paths("candidate", id);
|
|
26834
|
-
if (
|
|
27192
|
+
if (existsSync13(metadata)) {
|
|
26835
27193
|
throw new SkillLifecycleError(
|
|
26836
27194
|
"skill_candidate_exists",
|
|
26837
27195
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -26940,11 +27298,11 @@ var SkillLifecycle = class {
|
|
|
26940
27298
|
};
|
|
26941
27299
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
26942
27300
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
26943
|
-
const skillContent =
|
|
26944
|
-
const metadataContent =
|
|
27301
|
+
const skillContent = readFileSync11(candidatePaths.skill, "utf8");
|
|
27302
|
+
const metadataContent = readFileSync11(candidatePaths.metadata, "utf8");
|
|
26945
27303
|
this.write(promotedPaths.skill, skillContent);
|
|
26946
27304
|
this.write(promotedPaths.metadata, metadataContent);
|
|
26947
|
-
const patchPath =
|
|
27305
|
+
const patchPath = join14(this.root, "patches", `${candidateId}.patch`);
|
|
26948
27306
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
26949
27307
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
26950
27308
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -26972,7 +27330,7 @@ var SkillLifecycle = class {
|
|
|
26972
27330
|
verify(state, id) {
|
|
26973
27331
|
const metadata = this.readMetadata(state, id);
|
|
26974
27332
|
const { skill } = this.paths(state, id);
|
|
26975
|
-
const content =
|
|
27333
|
+
const content = readFileSync11(skill, "utf8");
|
|
26976
27334
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
26977
27335
|
throw new SkillLifecycleError(
|
|
26978
27336
|
"skill_integrity_violation",
|
|
@@ -26990,7 +27348,7 @@ var SkillLifecycle = class {
|
|
|
26990
27348
|
}
|
|
26991
27349
|
list(state) {
|
|
26992
27350
|
const dir = this.dir(state);
|
|
26993
|
-
if (!
|
|
27351
|
+
if (!existsSync13(dir)) return [];
|
|
26994
27352
|
const ids = readdirSorted(dir);
|
|
26995
27353
|
return ids.map((id) => {
|
|
26996
27354
|
try {
|
|
@@ -27003,7 +27361,7 @@ var SkillLifecycle = class {
|
|
|
27003
27361
|
read(state, id) {
|
|
27004
27362
|
const metadata = this.readMetadata(state, id);
|
|
27005
27363
|
const { skill } = this.paths(state, id);
|
|
27006
|
-
return { metadata, content:
|
|
27364
|
+
return { metadata, content: readFileSync11(skill, "utf8") };
|
|
27007
27365
|
}
|
|
27008
27366
|
};
|
|
27009
27367
|
function boundedList(value, field) {
|
|
@@ -27018,7 +27376,7 @@ function boundedList(value, field) {
|
|
|
27018
27376
|
return [...new Set(refs)];
|
|
27019
27377
|
}
|
|
27020
27378
|
function readdirSorted(dir) {
|
|
27021
|
-
return
|
|
27379
|
+
return readdirSync9(dir).filter((entry) => statSync3(join14(dir, entry)).isDirectory()).sort();
|
|
27022
27380
|
}
|
|
27023
27381
|
|
|
27024
27382
|
// plugins/kxm/src/dispatch-context.ts
|
|
@@ -27059,18 +27417,18 @@ function contextRoleForAgent(agentId) {
|
|
|
27059
27417
|
return agentId;
|
|
27060
27418
|
}
|
|
27061
27419
|
function dispatchContextPresent(projectRoot) {
|
|
27062
|
-
return hasTopLevelMarkdown(
|
|
27420
|
+
return hasTopLevelMarkdown(join15(projectRoot, ".kxm", "memory")) || hasAnyEntry(join15(projectRoot, ".kxm", "skills", "promoted"));
|
|
27063
27421
|
}
|
|
27064
27422
|
function hasTopLevelMarkdown(dir) {
|
|
27065
27423
|
try {
|
|
27066
|
-
return
|
|
27424
|
+
return readdirSync10(dir, { withFileTypes: true }).some((entry) => entry.isFile() && extname3(entry.name) === ".md");
|
|
27067
27425
|
} catch {
|
|
27068
27426
|
return false;
|
|
27069
27427
|
}
|
|
27070
27428
|
}
|
|
27071
27429
|
function hasAnyEntry(dir) {
|
|
27072
27430
|
try {
|
|
27073
|
-
return
|
|
27431
|
+
return readdirSync10(dir).length > 0;
|
|
27074
27432
|
} catch {
|
|
27075
27433
|
return false;
|
|
27076
27434
|
}
|
|
@@ -27135,7 +27493,7 @@ function loadDispatchContextSources(input) {
|
|
|
27135
27493
|
}
|
|
27136
27494
|
const promoted = [];
|
|
27137
27495
|
try {
|
|
27138
|
-
const lifecycle = new SkillLifecycle(
|
|
27496
|
+
const lifecycle = new SkillLifecycle(join15(projectRoot, ".kxm", "skills"));
|
|
27139
27497
|
for (const metadata of lifecycle.list("promoted")) {
|
|
27140
27498
|
try {
|
|
27141
27499
|
promoted.push(lifecycle.verify("promoted", metadata.id));
|
|
@@ -27218,7 +27576,7 @@ function assembleDispatchContext(sources, input) {
|
|
|
27218
27576
|
}
|
|
27219
27577
|
|
|
27220
27578
|
// plugins/kxm/src/engine-artifacts.ts
|
|
27221
|
-
import { join as
|
|
27579
|
+
import { join as join16 } from "node:path";
|
|
27222
27580
|
|
|
27223
27581
|
// plugins/kxm/src/artifacts-exist.ts
|
|
27224
27582
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
|
|
@@ -27265,14 +27623,14 @@ function verifyArtifactExists(rootInput, pathInput) {
|
|
|
27265
27623
|
// plugins/kxm/src/engine-artifacts.ts
|
|
27266
27624
|
var kxmArtifactsGateSeams = {};
|
|
27267
27625
|
function evaluateArtifactsGate(context, definition) {
|
|
27268
|
-
const root =
|
|
27626
|
+
const root = join16(context.projectRoot, ".kxm", "assets");
|
|
27269
27627
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
27270
27628
|
const startTime = process.hrtime.bigint();
|
|
27271
27629
|
let checkedCount = 0;
|
|
27272
27630
|
let failedCount = 0;
|
|
27273
27631
|
for (const [index, path] of definition.paths.entries()) {
|
|
27274
27632
|
checkedCount += 1;
|
|
27275
|
-
const result = verifyArtifactExists(root,
|
|
27633
|
+
const result = verifyArtifactExists(root, join16(root, path));
|
|
27276
27634
|
if (!result.ok) failedCount += 1;
|
|
27277
27635
|
kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
|
|
27278
27636
|
}
|
|
@@ -28851,32 +29209,185 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
28851
29209
|
});
|
|
28852
29210
|
}
|
|
28853
29211
|
};
|
|
29212
|
+
var attemptFallback = /* @__PURE__ */ new Map();
|
|
29213
|
+
var runStickyRoute = /* @__PURE__ */ new Map();
|
|
29214
|
+
function observeProducerFailure(error, capability) {
|
|
29215
|
+
try {
|
|
29216
|
+
const raw = error instanceof Error ? error.message : error;
|
|
29217
|
+
const message = typeof raw === "string" ? raw : "";
|
|
29218
|
+
let text = message;
|
|
29219
|
+
if (capability) text = text.split(capability).join("[redacted]");
|
|
29220
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
29221
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
29222
|
+
const extracted = match?.[0] ?? "";
|
|
29223
|
+
const code = extracted.length > 0 && extracted.length <= 64 ? extracted : "producer_error";
|
|
29224
|
+
const record2 = error && typeof error === "object" ? error : void 0;
|
|
29225
|
+
const statusValue = record2?.statusCode ?? record2?.status ?? record2?.httpStatus;
|
|
29226
|
+
const httpStatus = typeof statusValue === "number" && Number.isInteger(statusValue) ? statusValue : void 0;
|
|
29227
|
+
const name = error instanceof Error ? error.name : void 0;
|
|
29228
|
+
const sessionCarry = parseSessionCarry(record2?.sessionCarry);
|
|
29229
|
+
return {
|
|
29230
|
+
code,
|
|
29231
|
+
failure: {
|
|
29232
|
+
classified: classifyRouteFailure({ code, text: text.slice(0, 500), httpStatus, name }),
|
|
29233
|
+
...sessionCarry ? { sessionCarry } : {}
|
|
29234
|
+
}
|
|
29235
|
+
};
|
|
29236
|
+
} catch {
|
|
29237
|
+
return { code: "producer_error", failure: { classified: classifyRouteFailure({ code: "producer_error" }) } };
|
|
29238
|
+
}
|
|
29239
|
+
}
|
|
28854
29240
|
function invokeProducer(producer, request) {
|
|
28855
|
-
const reason = (error) => {
|
|
28856
|
-
try {
|
|
28857
|
-
const raw = error instanceof Error ? error.message : error;
|
|
28858
|
-
const message = typeof raw === "string" ? raw : "";
|
|
28859
|
-
let text = message;
|
|
28860
|
-
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
28861
|
-
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
28862
|
-
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
28863
|
-
const code = match?.[0] ?? "";
|
|
28864
|
-
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
28865
|
-
} catch {
|
|
28866
|
-
return "producer_error";
|
|
28867
|
-
}
|
|
28868
|
-
};
|
|
28869
29241
|
let pending;
|
|
28870
29242
|
try {
|
|
28871
29243
|
pending = Promise.resolve(producer.produce(request));
|
|
28872
29244
|
} catch (error) {
|
|
28873
|
-
|
|
29245
|
+
const observed = observeProducerFailure(error, request.capability);
|
|
29246
|
+
return Promise.resolve({ error: true, errorCode: observed.code, failure: observed.failure });
|
|
28874
29247
|
}
|
|
28875
29248
|
return pending.then(
|
|
28876
29249
|
(result) => ({ result, error: false }),
|
|
28877
|
-
(error) =>
|
|
29250
|
+
(error) => {
|
|
29251
|
+
const observed = observeProducerFailure(error, request.capability);
|
|
29252
|
+
return { error: true, errorCode: observed.code, failure: observed.failure };
|
|
29253
|
+
}
|
|
28878
29254
|
);
|
|
28879
29255
|
}
|
|
29256
|
+
function stickyRouteFromEvents(context, runId) {
|
|
29257
|
+
const remembered = runStickyRoute.get(runId);
|
|
29258
|
+
if (remembered) return remembered;
|
|
29259
|
+
let found;
|
|
29260
|
+
for (const event of context.eventStore.events(runId, 0, 1e5)) {
|
|
29261
|
+
if (event.eventType !== "routing.attempt.recorded") continue;
|
|
29262
|
+
const routing = event.payload.routing;
|
|
29263
|
+
const route = routing?.providerMetadata?.fallbackRoute;
|
|
29264
|
+
if (typeof route === "string" && route.length > 0) found = route;
|
|
29265
|
+
}
|
|
29266
|
+
return found;
|
|
29267
|
+
}
|
|
29268
|
+
function stickyWalkRoute(context, step, agentId, runId, liveWrite) {
|
|
29269
|
+
const loaded = loadAgentFallback(context.projectRoot, agentId, { liveWrite });
|
|
29270
|
+
if (!loaded || loaded.policy.revert !== "never") return void 0;
|
|
29271
|
+
const sticky = stickyRouteFromEvents(context, runId);
|
|
29272
|
+
if (!sticky) return void 0;
|
|
29273
|
+
const candidate = loaded.chain.find((item) => item.routeId === sticky);
|
|
29274
|
+
if (!candidate) return void 0;
|
|
29275
|
+
return candidateToRoute(candidate, loaded.roleId);
|
|
29276
|
+
}
|
|
29277
|
+
function candidateToRoute(candidate, role) {
|
|
29278
|
+
return {
|
|
29279
|
+
provider: candidate.provider,
|
|
29280
|
+
model: candidate.model,
|
|
29281
|
+
selector: candidate.selector,
|
|
29282
|
+
harness: candidate.harness,
|
|
29283
|
+
routeId: candidate.routeId,
|
|
29284
|
+
role,
|
|
29285
|
+
permissions: [...candidate.permissions],
|
|
29286
|
+
...candidate.effort ? { effort: candidate.effort } : {}
|
|
29287
|
+
};
|
|
29288
|
+
}
|
|
29289
|
+
function rememberAttemptFallback(attemptId, loaded, index, basePrompt) {
|
|
29290
|
+
if (loaded.chain.length < 2 || loaded.policy.onError.length === 0 || loaded.policy.maxSwitches <= 0) return;
|
|
29291
|
+
if (index < 0 || index >= loaded.chain.length) return;
|
|
29292
|
+
attemptFallback.set(attemptId, {
|
|
29293
|
+
policy: loaded.policy,
|
|
29294
|
+
chain: loaded.chain,
|
|
29295
|
+
index,
|
|
29296
|
+
switches: 0,
|
|
29297
|
+
basePrompt
|
|
29298
|
+
});
|
|
29299
|
+
}
|
|
29300
|
+
function appendRouteSwitch(context, member, routeSwitch) {
|
|
29301
|
+
const run = requireRun(context, member.run.runId);
|
|
29302
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
29303
|
+
const sequence = context.eventStore.nextSequence(run.runId);
|
|
29304
|
+
const event = {
|
|
29305
|
+
...kxmEventBase(context, run, now, kxmMonotonicNs()),
|
|
29306
|
+
eventId: newKxmEventId(),
|
|
29307
|
+
eventType: "routing.route_switched",
|
|
29308
|
+
sequence,
|
|
29309
|
+
payload: {
|
|
29310
|
+
attemptId: member.attemptId,
|
|
29311
|
+
stepId: member.stepId,
|
|
29312
|
+
routeSwitch: {
|
|
29313
|
+
from: routeSwitch.from,
|
|
29314
|
+
to: routeSwitch.to,
|
|
29315
|
+
reason: routeSwitch.reason,
|
|
29316
|
+
...routeSwitch.effort ? { effort: routeSwitch.effort } : {}
|
|
29317
|
+
}
|
|
29318
|
+
}
|
|
29319
|
+
};
|
|
29320
|
+
context.eventStore.appendEvent(event);
|
|
29321
|
+
const next = foldStoredKxmRun(context, run);
|
|
29322
|
+
persistKxmRunState(context, run.runId, next, sequence);
|
|
29323
|
+
try {
|
|
29324
|
+
context.logger?.({
|
|
29325
|
+
event: "route_switch",
|
|
29326
|
+
runId: run.runId,
|
|
29327
|
+
attemptId: member.attemptId,
|
|
29328
|
+
stepId: member.stepId,
|
|
29329
|
+
from: routeSwitch.from,
|
|
29330
|
+
to: routeSwitch.to,
|
|
29331
|
+
reason: routeSwitch.reason,
|
|
29332
|
+
...routeSwitch.effort ? { effort: routeSwitch.effort } : {}
|
|
29333
|
+
});
|
|
29334
|
+
} catch {
|
|
29335
|
+
}
|
|
29336
|
+
}
|
|
29337
|
+
async function produceWithRouteFallback(context, member, producer) {
|
|
29338
|
+
const session = attemptFallback.get(member.attemptId);
|
|
29339
|
+
let request = member.request;
|
|
29340
|
+
let produced = await invokeProducer(producer, request);
|
|
29341
|
+
if (!session) return producerOutcome(produced);
|
|
29342
|
+
let carry;
|
|
29343
|
+
while (produced.error) {
|
|
29344
|
+
const current = session.chain[session.index];
|
|
29345
|
+
if (!current) break;
|
|
29346
|
+
const failure = produced.failure?.classified ?? classifyRouteFailure({ code: produced.errorCode, text: produced.errorCode });
|
|
29347
|
+
const decision = decideRouteSwitch({
|
|
29348
|
+
policy: session.policy,
|
|
29349
|
+
chain: session.chain,
|
|
29350
|
+
currentRouteId: current.routeId,
|
|
29351
|
+
switchesUsed: session.switches,
|
|
29352
|
+
failure,
|
|
29353
|
+
...current.effort || member.request.thinking ? { currentEffort: current.effort ?? member.request.thinking } : {}
|
|
29354
|
+
});
|
|
29355
|
+
if (decision.action !== "switch") break;
|
|
29356
|
+
appendRouteSwitch(context, member, {
|
|
29357
|
+
from: current.routeId,
|
|
29358
|
+
to: decision.to.routeId,
|
|
29359
|
+
reason: decision.reason,
|
|
29360
|
+
...decision.effort ? { effort: decision.effort } : {}
|
|
29361
|
+
});
|
|
29362
|
+
session.switches += 1;
|
|
29363
|
+
session.index = session.chain.findIndex((candidate) => candidate.routeId === decision.to.routeId);
|
|
29364
|
+
carry = mergeSessionCarry(carry, produced.failure?.sessionCarry);
|
|
29365
|
+
request = {
|
|
29366
|
+
...member.request,
|
|
29367
|
+
prompt: carryForwardPrompt(session.basePrompt, carry),
|
|
29368
|
+
model: decision.to.model,
|
|
29369
|
+
provider: decision.to.provider,
|
|
29370
|
+
harness: decision.to.harness,
|
|
29371
|
+
...decision.effort ? { thinking: decision.effort } : {}
|
|
29372
|
+
};
|
|
29373
|
+
produced = await invokeProducer(producer, request);
|
|
29374
|
+
}
|
|
29375
|
+
if (!produced.error && session.switches > 0 && session.policy.revert === "never") {
|
|
29376
|
+
const route = session.chain[session.index];
|
|
29377
|
+
if (route) {
|
|
29378
|
+
session.stickyRouteId = route.routeId;
|
|
29379
|
+
runStickyRoute.set(member.run.runId, route.routeId);
|
|
29380
|
+
}
|
|
29381
|
+
}
|
|
29382
|
+
return producerOutcome(produced);
|
|
29383
|
+
}
|
|
29384
|
+
function producerOutcome(produced) {
|
|
29385
|
+
return {
|
|
29386
|
+
error: produced.error,
|
|
29387
|
+
...produced.result !== void 0 ? { result: produced.result } : {},
|
|
29388
|
+
...produced.errorCode !== void 0 ? { errorCode: produced.errorCode } : {}
|
|
29389
|
+
};
|
|
29390
|
+
}
|
|
28880
29391
|
var kxmGateDispatchSeams = {};
|
|
28881
29392
|
function peekDispatchContextSources(context, runId) {
|
|
28882
29393
|
if (!dispatchContextPresent(context.projectRoot)) return EMPTY_DISPATCH_SOURCES;
|
|
@@ -29150,9 +29661,9 @@ function readYamlFile(file) {
|
|
|
29150
29661
|
return readModelDocument(file);
|
|
29151
29662
|
}
|
|
29152
29663
|
function readModelDocument(file) {
|
|
29153
|
-
if (!
|
|
29664
|
+
if (!existsSync14(file)) return void 0;
|
|
29154
29665
|
try {
|
|
29155
|
-
const parsed = (0,
|
|
29666
|
+
const parsed = (0, import_yaml11.parse)(readFileSync12(file, "utf8"));
|
|
29156
29667
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
29157
29668
|
return parsed;
|
|
29158
29669
|
} catch {
|
|
@@ -29183,8 +29694,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29183
29694
|
}
|
|
29184
29695
|
};
|
|
29185
29696
|
}
|
|
29186
|
-
const agentFile = findYamlBasename(
|
|
29187
|
-
const agent = readYamlFile(
|
|
29697
|
+
const agentFile = findYamlBasename(join17(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
|
|
29698
|
+
const agent = readYamlFile(join17(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
|
|
29188
29699
|
const role = typeof agent?.role === "string" ? agent.role : "";
|
|
29189
29700
|
if (!role) {
|
|
29190
29701
|
return {
|
|
@@ -29195,7 +29706,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29195
29706
|
}
|
|
29196
29707
|
};
|
|
29197
29708
|
}
|
|
29198
|
-
const roleDoc = readYamlFile(
|
|
29709
|
+
const roleDoc = readYamlFile(join17(projectRoot, ".kxm", "roles", `${role}.yaml`));
|
|
29199
29710
|
const roster = Array.isArray(roleDoc?.roster) ? roleDoc.roster : void 0;
|
|
29200
29711
|
if (!roster) {
|
|
29201
29712
|
return {
|
|
@@ -29211,8 +29722,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29211
29722
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
29212
29723
|
const record2 = entry;
|
|
29213
29724
|
if (typeof record2.route !== "string" || record2.route.length === 0) continue;
|
|
29214
|
-
const routeFile = findYamlBasename(
|
|
29215
|
-
const modelPath =
|
|
29725
|
+
const routeFile = findYamlBasename(join17(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
|
|
29726
|
+
const modelPath = join17(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
|
|
29216
29727
|
const doc = readModelDocument(modelPath);
|
|
29217
29728
|
if (!doc) {
|
|
29218
29729
|
return {
|
|
@@ -29229,9 +29740,9 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29229
29740
|
const harness = typeof doc.harness === "string" ? doc.harness : "";
|
|
29230
29741
|
if (!modelName || !vendor || !harness) continue;
|
|
29231
29742
|
const candidates = [modelName, `${vendor}/${modelName}`, `${harness}/${modelName}`];
|
|
29232
|
-
const
|
|
29743
|
+
const admittedSelector2 = candidates.find((candidate) => policy.admitted.includes(candidate));
|
|
29233
29744
|
const disabledSelector = candidates.find((candidate) => policy.disabled.includes(candidate));
|
|
29234
|
-
if (!
|
|
29745
|
+
if (!admittedSelector2 && disabledSelector) {
|
|
29235
29746
|
return {
|
|
29236
29747
|
error: {
|
|
29237
29748
|
reason: "step_unsupported",
|
|
@@ -29240,7 +29751,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29240
29751
|
}
|
|
29241
29752
|
};
|
|
29242
29753
|
}
|
|
29243
|
-
const selector =
|
|
29754
|
+
const selector = admittedSelector2 ?? (modelName.includes("/") ? modelName : `${vendor}/${modelName}`);
|
|
29244
29755
|
if (policy.disabled.includes(selector)) {
|
|
29245
29756
|
return {
|
|
29246
29757
|
error: {
|
|
@@ -29502,6 +30013,14 @@ function prepareDispatch(context, runId, producerId, dispatchSources) {
|
|
|
29502
30013
|
return { kind: "return", state, handoff: { ...routeResult.error, stepId } };
|
|
29503
30014
|
}
|
|
29504
30015
|
resolvedRoute = routeResult;
|
|
30016
|
+
const stickyRoute = stickyWalkRoute(
|
|
30017
|
+
context,
|
|
30018
|
+
step,
|
|
30019
|
+
agentId,
|
|
30020
|
+
run.runId,
|
|
30021
|
+
Object.values(step.repositories).some((access) => access === "write")
|
|
30022
|
+
);
|
|
30023
|
+
if (stickyRoute && stickyRoute.routeId !== resolvedRoute.routeId) resolvedRoute = stickyRoute;
|
|
29505
30024
|
const writeRefusal = unsupportedLiveWrite(
|
|
29506
30025
|
context.projectRoot,
|
|
29507
30026
|
step,
|
|
@@ -29616,6 +30135,27 @@ function birthMember(context, input) {
|
|
|
29616
30135
|
}
|
|
29617
30136
|
resolvedRoute = routeResult;
|
|
29618
30137
|
}
|
|
30138
|
+
const liveProducer = Boolean(input.producerId && input.producerId !== "driver-simulated");
|
|
30139
|
+
const liveWrite = liveProducer && Object.values(input.step.repositories).some((access) => access === "write");
|
|
30140
|
+
const loadedFallback = loadAgentFallback(context.projectRoot, agentId, { liveWrite });
|
|
30141
|
+
let fallbackIndex = -1;
|
|
30142
|
+
if (loadedFallback && loadedFallback.chain.length > 1 && loadedFallback.policy.maxSwitches > 0) {
|
|
30143
|
+
const sticky = loadedFallback.policy.revert === "never" ? stickyRouteFromEvents(context, run.runId) : void 0;
|
|
30144
|
+
const stickyIndex = sticky ? loadedFallback.chain.findIndex((candidate) => candidate.routeId === sticky) : -1;
|
|
30145
|
+
if (!resolvedRoute) {
|
|
30146
|
+
fallbackIndex = stickyIndex > 0 ? stickyIndex : 0;
|
|
30147
|
+
const start = loadedFallback.chain[fallbackIndex];
|
|
30148
|
+
if (start) resolvedRoute = candidateToRoute(start, loadedFallback.roleId);
|
|
30149
|
+
} else if (stickyIndex > 0 && resolvedRoute.routeId !== loadedFallback.chain[stickyIndex]?.routeId) {
|
|
30150
|
+
const start = loadedFallback.chain[stickyIndex];
|
|
30151
|
+
if (start) {
|
|
30152
|
+
resolvedRoute = candidateToRoute(start, loadedFallback.roleId);
|
|
30153
|
+
fallbackIndex = stickyIndex;
|
|
30154
|
+
}
|
|
30155
|
+
} else {
|
|
30156
|
+
fallbackIndex = loadedFallback.chain.findIndex((candidate) => candidate.routeId === resolvedRoute?.routeId);
|
|
30157
|
+
}
|
|
30158
|
+
}
|
|
29619
30159
|
const dispatchContext = assembleDispatchContext(input.dispatchSources, {
|
|
29620
30160
|
projectId: run.projectId,
|
|
29621
30161
|
runId: run.runId,
|
|
@@ -29750,6 +30290,9 @@ ${generatedPrompt}` : generatedPrompt,
|
|
|
29750
30290
|
} catch {
|
|
29751
30291
|
}
|
|
29752
30292
|
}
|
|
30293
|
+
if (loadedFallback && fallbackIndex >= 0) {
|
|
30294
|
+
rememberAttemptFallback(attemptId, loadedFallback, fallbackIndex, member.request.prompt ?? "");
|
|
30295
|
+
}
|
|
29753
30296
|
kxmPanelDispatchSeams.afterBirth?.(member);
|
|
29754
30297
|
return member;
|
|
29755
30298
|
}
|
|
@@ -29853,7 +30396,7 @@ async function drivePanel(context, panel, producer) {
|
|
|
29853
30396
|
const live = member.producerId !== "driver-simulated";
|
|
29854
30397
|
const writes = Object.values(member.step.repositories).some((access) => access === "write");
|
|
29855
30398
|
const before = live ? captureWorktreeWitness(context.projectRoot) : void 0;
|
|
29856
|
-
const produced = await
|
|
30399
|
+
const produced = await produceWithRouteFallback(context, member, producer);
|
|
29857
30400
|
if (live && produced.result && before) {
|
|
29858
30401
|
const after = captureWorktreeWitness(context.projectRoot);
|
|
29859
30402
|
return {
|
|
@@ -30048,6 +30591,8 @@ function engineRoutingMetadata(dispatch, producer) {
|
|
|
30048
30591
|
metadata.askSha256 = kxmStepAskSha256(dispatch.plan, dispatch.stepId, dispatch.agentId);
|
|
30049
30592
|
metadata.objectiveSha256 = dispatch.run.promptSha256;
|
|
30050
30593
|
metadata.stepWrites = Object.values(dispatch.step.repositories).some((access) => access === "write");
|
|
30594
|
+
const stickyRouteId = attemptFallback.get(dispatch.attemptId)?.stickyRouteId;
|
|
30595
|
+
if (stickyRouteId && Object.keys(metadata).length < MAX_PROVIDER_METADATA_FIELDS) metadata.fallbackRoute = stickyRouteId;
|
|
30051
30596
|
return metadata;
|
|
30052
30597
|
}
|
|
30053
30598
|
function producerRoutingRecord(context, dispatch, result, now, finalOutcome) {
|
|
@@ -30206,6 +30751,7 @@ function settleMember(context, dispatch, result, produceError, produceErrorCode)
|
|
|
30206
30751
|
}
|
|
30207
30752
|
}
|
|
30208
30753
|
context.eventStore.settleCapability(dispatch.attemptId, "settled");
|
|
30754
|
+
attemptFallback.delete(dispatch.attemptId);
|
|
30209
30755
|
for (const event of events) context.eventStore.appendEvent(event);
|
|
30210
30756
|
const next = foldStoredKxmRun(context, run);
|
|
30211
30757
|
persistKxmRunState(context, run.runId, next, events[events.length - 1].sequence);
|
|
@@ -31466,9 +32012,9 @@ var RuntimeHubClient = class {
|
|
|
31466
32012
|
};
|
|
31467
32013
|
|
|
31468
32014
|
// plugins/kxm/src/hub-binding.ts
|
|
31469
|
-
import { existsSync as
|
|
32015
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync13, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
31470
32016
|
import { homedir as homedir2 } from "node:os";
|
|
31471
|
-
import { dirname as dirname8, isAbsolute as isAbsolute6, join as
|
|
32017
|
+
import { dirname as dirname8, isAbsolute as isAbsolute6, join as join18, resolve as resolve9 } from "node:path";
|
|
31472
32018
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
31473
32019
|
var HubBindingError = class extends Error {
|
|
31474
32020
|
constructor(message) {
|
|
@@ -31484,16 +32030,16 @@ function resolveUserStateRoot(env) {
|
|
|
31484
32030
|
}
|
|
31485
32031
|
if (process.platform === "win32") {
|
|
31486
32032
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
31487
|
-
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData :
|
|
32033
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join18(homedir2(), "AppData", "Local");
|
|
31488
32034
|
return resolve9(base2, "KXM");
|
|
31489
32035
|
}
|
|
31490
32036
|
if (process.platform === "darwin") return resolve9(homedir2(), "Library", "Application Support", "KXM");
|
|
31491
32037
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
31492
|
-
const base = xdgState && isAbsolute6(xdgState) ? xdgState :
|
|
32038
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join18(homedir2(), ".local", "state");
|
|
31493
32039
|
return resolve9(base, "kxm");
|
|
31494
32040
|
}
|
|
31495
32041
|
function hubBindingFile(env = process.env) {
|
|
31496
|
-
return
|
|
32042
|
+
return join18(resolveUserStateRoot(env), "hub-binding.json");
|
|
31497
32043
|
}
|
|
31498
32044
|
function validateHubUrl(raw) {
|
|
31499
32045
|
let parsed;
|
|
@@ -31513,10 +32059,10 @@ function isIsoTimestamp(value) {
|
|
|
31513
32059
|
}
|
|
31514
32060
|
function readHubBinding(env = process.env) {
|
|
31515
32061
|
const file = hubBindingFile(env);
|
|
31516
|
-
if (!
|
|
32062
|
+
if (!existsSync15(file)) return void 0;
|
|
31517
32063
|
let parsed;
|
|
31518
32064
|
try {
|
|
31519
|
-
parsed = JSON.parse(
|
|
32065
|
+
parsed = JSON.parse(readFileSync13(file, "utf8"));
|
|
31520
32066
|
} catch {
|
|
31521
32067
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31522
32068
|
}
|
|
@@ -31538,9 +32084,9 @@ function readHubBinding(env = process.env) {
|
|
|
31538
32084
|
}
|
|
31539
32085
|
|
|
31540
32086
|
// plugins/kxm/src/hub-env.ts
|
|
31541
|
-
import { existsSync as
|
|
32087
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
31542
32088
|
import { homedir as homedir3 } from "node:os";
|
|
31543
|
-
import { dirname as dirname9, isAbsolute as isAbsolute7, join as
|
|
32089
|
+
import { dirname as dirname9, isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
|
|
31544
32090
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
31545
32091
|
var HubEnvError = class extends Error {
|
|
31546
32092
|
constructor(message) {
|
|
@@ -31556,23 +32102,23 @@ function resolveUserStateRoot2(env) {
|
|
|
31556
32102
|
}
|
|
31557
32103
|
if (process.platform === "win32") {
|
|
31558
32104
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
31559
|
-
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
32105
|
+
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
|
|
31560
32106
|
return resolve10(base2, "KXM");
|
|
31561
32107
|
}
|
|
31562
32108
|
if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
|
|
31563
32109
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
31564
|
-
const base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
32110
|
+
const base = xdgState && isAbsolute7(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
|
|
31565
32111
|
return resolve10(base, "kxm");
|
|
31566
32112
|
}
|
|
31567
32113
|
function hubEnvFile(env = process.env) {
|
|
31568
|
-
return
|
|
32114
|
+
return join19(resolveUserStateRoot2(env), "hub-env.json");
|
|
31569
32115
|
}
|
|
31570
32116
|
function readHubEnvRecord(env = process.env) {
|
|
31571
32117
|
const file = hubEnvFile(env);
|
|
31572
|
-
if (!
|
|
32118
|
+
if (!existsSync16(file)) return void 0;
|
|
31573
32119
|
let parsed;
|
|
31574
32120
|
try {
|
|
31575
|
-
parsed = JSON.parse(
|
|
32121
|
+
parsed = JSON.parse(readFileSync14(file, "utf8"));
|
|
31576
32122
|
} catch (error) {
|
|
31577
32123
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
31578
32124
|
}
|
|
@@ -31612,7 +32158,7 @@ function resolveClientHubAuthToken(env, project) {
|
|
|
31612
32158
|
}
|
|
31613
32159
|
|
|
31614
32160
|
// plugins/kxm/src/logger.ts
|
|
31615
|
-
import { appendFileSync, existsSync as
|
|
32161
|
+
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync8, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
31616
32162
|
import { dirname as dirname10 } from "node:path";
|
|
31617
32163
|
var LOG_LEVEL_PRIORITY = {
|
|
31618
32164
|
debug: 10,
|
|
@@ -31650,7 +32196,7 @@ function redactLogValue(val, key) {
|
|
|
31650
32196
|
function rotateLogFiles(filePath, maxFiles) {
|
|
31651
32197
|
for (let i = maxFiles; i >= 1; i--) {
|
|
31652
32198
|
const current = `${filePath}.${i}`;
|
|
31653
|
-
if (
|
|
32199
|
+
if (existsSync17(current)) {
|
|
31654
32200
|
if (i >= maxFiles) {
|
|
31655
32201
|
try {
|
|
31656
32202
|
unlinkSync2(current);
|
|
@@ -31664,7 +32210,7 @@ function rotateLogFiles(filePath, maxFiles) {
|
|
|
31664
32210
|
}
|
|
31665
32211
|
}
|
|
31666
32212
|
}
|
|
31667
|
-
if (
|
|
32213
|
+
if (existsSync17(filePath)) {
|
|
31668
32214
|
try {
|
|
31669
32215
|
renameSync4(filePath, `${filePath}.1`);
|
|
31670
32216
|
} catch {
|
|
@@ -31681,7 +32227,7 @@ function createLogger(options) {
|
|
|
31681
32227
|
const shouldStdout = options.stdout ?? !isDaemon;
|
|
31682
32228
|
const correlationDefaults = options.correlation ?? {};
|
|
31683
32229
|
let currentSize = 0;
|
|
31684
|
-
if (filePath &&
|
|
32230
|
+
if (filePath && existsSync17(filePath)) {
|
|
31685
32231
|
try {
|
|
31686
32232
|
currentSize = statSync5(filePath).size;
|
|
31687
32233
|
} catch {
|
|
@@ -31762,7 +32308,7 @@ function createLogger(options) {
|
|
|
31762
32308
|
|
|
31763
32309
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
31764
32310
|
function kxmSupervisorTokenFile(paths) {
|
|
31765
|
-
return
|
|
32311
|
+
return join20(paths.runtimeDir, "supervisor.token");
|
|
31766
32312
|
}
|
|
31767
32313
|
function publishKxmSupervisorToken(paths, token) {
|
|
31768
32314
|
const file = kxmSupervisorTokenFile(paths);
|
|
@@ -31790,7 +32336,7 @@ function readKxmSupervisorToken(paths) {
|
|
|
31790
32336
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31791
32337
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
31792
32338
|
}
|
|
31793
|
-
const token =
|
|
32339
|
+
const token = readFileSync15(file, "utf8").trim();
|
|
31794
32340
|
return token.length >= 32 ? token : void 0;
|
|
31795
32341
|
}
|
|
31796
32342
|
function processAlive(pid) {
|
|
@@ -31804,11 +32350,11 @@ function processAlive(pid) {
|
|
|
31804
32350
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
31805
32351
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
31806
32352
|
function supervisorErrorFile(paths) {
|
|
31807
|
-
return
|
|
32353
|
+
return join20(paths.runtimeDir, "supervisor.error");
|
|
31808
32354
|
}
|
|
31809
32355
|
function clearSupervisorError(paths) {
|
|
31810
32356
|
const file = supervisorErrorFile(paths);
|
|
31811
|
-
if (
|
|
32357
|
+
if (existsSync18(file)) rmSync4(file, { force: true });
|
|
31812
32358
|
}
|
|
31813
32359
|
function recordSupervisorError(paths, message) {
|
|
31814
32360
|
try {
|
|
@@ -31825,7 +32371,7 @@ function readRecentSupervisorError(paths) {
|
|
|
31825
32371
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
31826
32372
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
31827
32373
|
try {
|
|
31828
|
-
return
|
|
32374
|
+
return readFileSync15(file, "utf8").trim();
|
|
31829
32375
|
} catch {
|
|
31830
32376
|
return void 0;
|
|
31831
32377
|
}
|
|
@@ -31864,7 +32410,7 @@ function supervisorStatusOf(record2) {
|
|
|
31864
32410
|
};
|
|
31865
32411
|
}
|
|
31866
32412
|
function kxmSupervisorStatus(paths, options = {}) {
|
|
31867
|
-
if (!
|
|
32413
|
+
if (!existsSync18(paths.registryDb)) return { running: false };
|
|
31868
32414
|
if (options.readOnly) {
|
|
31869
32415
|
const database = openReadOnlyDatabase(paths.registryDb);
|
|
31870
32416
|
try {
|
|
@@ -31930,7 +32476,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
31930
32476
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
31931
32477
|
}
|
|
31932
32478
|
clearSupervisorError(paths);
|
|
31933
|
-
const scriptPath =
|
|
32479
|
+
const scriptPath = join20(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
31934
32480
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
31935
32481
|
const child = spawn3(process.execPath, [script], {
|
|
31936
32482
|
detached: true,
|
|
@@ -32153,7 +32699,7 @@ function syncFailureText(error) {
|
|
|
32153
32699
|
return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
|
|
32154
32700
|
}
|
|
32155
32701
|
function runtimeSupervisorLogFile(paths) {
|
|
32156
|
-
return
|
|
32702
|
+
return join20(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
|
|
32157
32703
|
}
|
|
32158
32704
|
async function startKxmRuntimeSupervisor(options = {}) {
|
|
32159
32705
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -32278,8 +32824,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
32278
32824
|
openRunIds = unsettledRunIds(existing2);
|
|
32279
32825
|
} else {
|
|
32280
32826
|
const registration = registry.projectByRoot(projectRoot);
|
|
32281
|
-
const eventsPath =
|
|
32282
|
-
if (registration &&
|
|
32827
|
+
const eventsPath = join20(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
|
|
32828
|
+
if (registration && existsSync18(eventsPath)) {
|
|
32283
32829
|
const store = new KxmRunEventStore(eventsPath);
|
|
32284
32830
|
try {
|
|
32285
32831
|
openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);
|
|
@@ -32795,7 +33341,7 @@ function handoffSuffix(handoff) {
|
|
|
32795
33341
|
|
|
32796
33342
|
// plugins/kxm/src/pi-producer.ts
|
|
32797
33343
|
import { spawn as spawn4 } from "node:child_process";
|
|
32798
|
-
import { join as
|
|
33344
|
+
import { join as join21 } from "node:path";
|
|
32799
33345
|
import { StringDecoder } from "node:string_decoder";
|
|
32800
33346
|
function formatPiSessionKey(params) {
|
|
32801
33347
|
if (params.agentId === "coordinator") {
|
|
@@ -33169,7 +33715,7 @@ function createKxmPiProducer(options = {}) {
|
|
|
33169
33715
|
const args = ["--mode", "rpc", "--name", displayName];
|
|
33170
33716
|
if (options.sessionDir) {
|
|
33171
33717
|
const safeDirName = key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
33172
|
-
args.push("--session-dir",
|
|
33718
|
+
args.push("--session-dir", join21(options.sessionDir, request.runId, safeDirName));
|
|
33173
33719
|
}
|
|
33174
33720
|
if (model) {
|
|
33175
33721
|
args.push("--model", model);
|
|
@@ -33298,8 +33844,8 @@ function createKxmPiProducer(options = {}) {
|
|
|
33298
33844
|
|
|
33299
33845
|
// plugins/kxm/src/improve.ts
|
|
33300
33846
|
import { createHash as createHash17 } from "node:crypto";
|
|
33301
|
-
import { existsSync as
|
|
33302
|
-
import { join as
|
|
33847
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
33848
|
+
import { join as join22, relative as relative5, resolve as resolve11 } from "node:path";
|
|
33303
33849
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
33304
33850
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
33305
33851
|
var IMPROVEMENT_REPORT_V1_SCHEMA = "kxm.improvement-report.v1";
|
|
@@ -33556,7 +34102,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
33556
34102
|
}
|
|
33557
34103
|
function buildImprovementReport(records, options = {}) {
|
|
33558
34104
|
const projectRoot = options.projectRoot ? resolve11(options.projectRoot) : process.cwd();
|
|
33559
|
-
const candidatesDir = options.candidatesDir ? resolve11(options.candidatesDir) :
|
|
34105
|
+
const candidatesDir = options.candidatesDir ? resolve11(options.candidatesDir) : join22(projectRoot, ".kxm", "candidates");
|
|
33560
34106
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
33561
34107
|
const groups = groupRoutingRecords(records, options);
|
|
33562
34108
|
const candidates = [];
|
|
@@ -33570,7 +34116,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
33570
34116
|
group.workflowId
|
|
33571
34117
|
);
|
|
33572
34118
|
const diffFileName = `${group.candidateId}.diff`;
|
|
33573
|
-
const diffFilePath =
|
|
34119
|
+
const diffFilePath = join22(candidatesDir, diffFileName);
|
|
33574
34120
|
const relDiffPath = relative5(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
33575
34121
|
const candidate = {
|
|
33576
34122
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -33592,11 +34138,11 @@ function buildImprovementReport(records, options = {}) {
|
|
|
33592
34138
|
createdAt: nowIso()
|
|
33593
34139
|
};
|
|
33594
34140
|
if (!options.dryRun) {
|
|
33595
|
-
if (!
|
|
34141
|
+
if (!existsSync19(candidatesDir)) {
|
|
33596
34142
|
mkdirSync10(candidatesDir, { recursive: true });
|
|
33597
34143
|
}
|
|
33598
34144
|
writeFileSync10(diffFilePath, diff, "utf8");
|
|
33599
|
-
const jsonFilePath =
|
|
34145
|
+
const jsonFilePath = join22(candidatesDir, `${group.candidateId}.json`);
|
|
33600
34146
|
writeFileSync10(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
33601
34147
|
}
|
|
33602
34148
|
candidates.push(candidate);
|
|
@@ -33612,6 +34158,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
33612
34158
|
})
|
|
33613
34159
|
});
|
|
33614
34160
|
}
|
|
34161
|
+
const routeSwitches = options.routeSwitches?.filter((item) => item.from && item.to) ?? [];
|
|
33615
34162
|
return {
|
|
33616
34163
|
schema: IMPROVEMENT_REPORT_SCHEMA,
|
|
33617
34164
|
createdAt: nowIso(),
|
|
@@ -33620,12 +34167,13 @@ function buildImprovementReport(records, options = {}) {
|
|
|
33620
34167
|
groups,
|
|
33621
34168
|
candidates,
|
|
33622
34169
|
promotionPolicy,
|
|
33623
|
-
promotion
|
|
34170
|
+
promotion,
|
|
34171
|
+
...routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}
|
|
33624
34172
|
};
|
|
33625
34173
|
}
|
|
33626
34174
|
function writeImprovementReport(improvementsDir, report, dryRun = false) {
|
|
33627
34175
|
const stamp = report.createdAt.replace(/[:.]/g, "-");
|
|
33628
|
-
const path =
|
|
34176
|
+
const path = join22(improvementsDir, `${stamp}.json`);
|
|
33629
34177
|
if (!dryRun) {
|
|
33630
34178
|
mkdirSync10(improvementsDir, { recursive: true });
|
|
33631
34179
|
writeFileSync10(path, `${JSON.stringify(report, null, 2)}
|
|
@@ -33656,6 +34204,14 @@ function formatImprovementReport(report) {
|
|
|
33656
34204
|
const cand = g.isCandidate ? `yes (${g.candidateKind})` : g.excludedReason !== void 0 ? `no (${g.excludedReason})` : "no";
|
|
33657
34205
|
lines.push(`${wf} ${step} ${role} ${prompt} ${rec} ${runs} ${asks} ${weighted} ${cost} ${lat} ${accepted} ${rework} ${cand}`);
|
|
33658
34206
|
}
|
|
34207
|
+
if (report.routeSwitches && report.routeSwitches.length > 0) {
|
|
34208
|
+
lines.push("");
|
|
34209
|
+
lines.push(`Route switches (${report.routeSwitches.length}):`);
|
|
34210
|
+
for (const item of report.routeSwitches) {
|
|
34211
|
+
const effort = item.effort ? ` effort ${item.effort}` : "";
|
|
34212
|
+
lines.push(` - ${item.from} -> ${item.to} (${item.reason}${effort}) on ${item.stepId}`);
|
|
34213
|
+
}
|
|
34214
|
+
}
|
|
33659
34215
|
if (report.candidates.length > 0) {
|
|
33660
34216
|
const readiness = new Map(report.promotion.map((entry) => [entry.candidateId, entry]));
|
|
33661
34217
|
lines.push("");
|
|
@@ -34286,9 +34842,9 @@ Instructions for Operator:
|
|
|
34286
34842
|
};
|
|
34287
34843
|
|
|
34288
34844
|
// plugins/kxm/src/modes.ts
|
|
34289
|
-
var
|
|
34290
|
-
import { existsSync as
|
|
34291
|
-
import { join as
|
|
34845
|
+
var import_yaml12 = __toESM(require_dist(), 1);
|
|
34846
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
|
|
34847
|
+
import { join as join23 } from "node:path";
|
|
34292
34848
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
34293
34849
|
schema: "kxm.modes.v1",
|
|
34294
34850
|
majorModes: {
|
|
@@ -34351,13 +34907,13 @@ function loadModesConfig(projectRoot) {
|
|
|
34351
34907
|
if (!projectRoot) {
|
|
34352
34908
|
return DEFAULT_MODES_CONFIG;
|
|
34353
34909
|
}
|
|
34354
|
-
const modesPath =
|
|
34355
|
-
if (!
|
|
34910
|
+
const modesPath = join23(projectRoot, ".kxm", "modes.yaml");
|
|
34911
|
+
if (!existsSync20(modesPath)) {
|
|
34356
34912
|
return DEFAULT_MODES_CONFIG;
|
|
34357
34913
|
}
|
|
34358
34914
|
try {
|
|
34359
|
-
const raw =
|
|
34360
|
-
const parsed = (0,
|
|
34915
|
+
const raw = readFileSync17(modesPath, "utf8");
|
|
34916
|
+
const parsed = (0, import_yaml12.parse)(raw);
|
|
34361
34917
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
34362
34918
|
return {
|
|
34363
34919
|
schema: "kxm.modes.v1",
|
|
@@ -34442,11 +34998,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
34442
34998
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
34443
34999
|
});
|
|
34444
35000
|
for (const relPath of resolved.contextFiles) {
|
|
34445
|
-
const fullPath =
|
|
35001
|
+
const fullPath = join23(projectRoot, relPath);
|
|
34446
35002
|
let chars = 0;
|
|
34447
|
-
if (
|
|
35003
|
+
if (existsSync20(fullPath)) {
|
|
34448
35004
|
try {
|
|
34449
|
-
chars =
|
|
35005
|
+
chars = readFileSync17(fullPath, "utf8").length;
|
|
34450
35006
|
} catch {
|
|
34451
35007
|
chars = 0;
|
|
34452
35008
|
}
|
|
@@ -34578,9 +35134,9 @@ ${divider}
|
|
|
34578
35134
|
|
|
34579
35135
|
// plugins/kxm/src/ssh-remote.ts
|
|
34580
35136
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
34581
|
-
import { existsSync as
|
|
35137
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync18, readdirSync as readdirSync11, rmSync as rmSync5, statSync as statSync6 } from "node:fs";
|
|
34582
35138
|
import { homedir as homedir4 } from "node:os";
|
|
34583
|
-
import { join as
|
|
35139
|
+
import { join as join24, resolve as resolve12 } from "node:path";
|
|
34584
35140
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
34585
35141
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
34586
35142
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -34606,12 +35162,12 @@ function truncateSshOutput(raw) {
|
|
|
34606
35162
|
return { text, truncated };
|
|
34607
35163
|
}
|
|
34608
35164
|
function parseSshConfig(configPath) {
|
|
34609
|
-
const targetPath = configPath ??
|
|
34610
|
-
if (!
|
|
35165
|
+
const targetPath = configPath ?? join24(homedir4(), ".ssh", "config");
|
|
35166
|
+
if (!existsSync21(targetPath)) {
|
|
34611
35167
|
return [];
|
|
34612
35168
|
}
|
|
34613
35169
|
try {
|
|
34614
|
-
const content =
|
|
35170
|
+
const content = readFileSync18(targetPath, "utf-8");
|
|
34615
35171
|
const lines = content.split("\n");
|
|
34616
35172
|
const hosts = [];
|
|
34617
35173
|
let currentHosts = [];
|
|
@@ -34689,14 +35245,14 @@ function resolveSshHostG(host, execFn = spawnSync6) {
|
|
|
34689
35245
|
}
|
|
34690
35246
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
34691
35247
|
const resolved = resolve12(socketDir);
|
|
34692
|
-
if (!
|
|
35248
|
+
if (!existsSync21(resolved)) {
|
|
34693
35249
|
mkdirSync11(resolved, { recursive: true, mode: 448 });
|
|
34694
35250
|
}
|
|
34695
35251
|
return resolved;
|
|
34696
35252
|
}
|
|
34697
35253
|
function buildSshArgs(options) {
|
|
34698
35254
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
34699
|
-
const controlPath =
|
|
35255
|
+
const controlPath = join24(socketDir, "%C");
|
|
34700
35256
|
const persist2 = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
34701
35257
|
const args = [
|
|
34702
35258
|
"-o",
|
|
@@ -34721,7 +35277,7 @@ function buildSshArgs(options) {
|
|
|
34721
35277
|
}
|
|
34722
35278
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync6) {
|
|
34723
35279
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
34724
|
-
const controlPath =
|
|
35280
|
+
const controlPath = join24(resolvedDir, "%C");
|
|
34725
35281
|
try {
|
|
34726
35282
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
34727
35283
|
encoding: "utf-8"
|
|
@@ -34733,7 +35289,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
34733
35289
|
}
|
|
34734
35290
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync6) {
|
|
34735
35291
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
34736
|
-
const controlPath =
|
|
35292
|
+
const controlPath = join24(resolvedDir, "%C");
|
|
34737
35293
|
try {
|
|
34738
35294
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
34739
35295
|
encoding: "utf-8"
|
|
@@ -34747,9 +35303,9 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
34747
35303
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
34748
35304
|
let removed = 0;
|
|
34749
35305
|
try {
|
|
34750
|
-
const entries =
|
|
35306
|
+
const entries = readdirSync11(resolvedDir);
|
|
34751
35307
|
for (const entry of entries) {
|
|
34752
|
-
const fullPath =
|
|
35308
|
+
const fullPath = join24(resolvedDir, entry);
|
|
34753
35309
|
try {
|
|
34754
35310
|
const stat = statSync6(fullPath);
|
|
34755
35311
|
if (stat.isSocket()) {
|