@kontextmind/kxm 0.7.52 → 0.7.54

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.
@@ -164,10 +164,10 @@ var require_code = __commonJS({
164
164
  function interpolate(x2) {
165
165
  return typeof x2 == "number" || typeof x2 == "boolean" || x2 === null ? x2 : safeStringify(Array.isArray(x2) ? x2.join(",") : x2);
166
166
  }
167
- function stringify11(x2) {
167
+ function stringify10(x2) {
168
168
  return new _Code(safeStringify(x2));
169
169
  }
170
- exports.stringify = stringify11;
170
+ exports.stringify = stringify10;
171
171
  function safeStringify(x2) {
172
172
  return JSON.stringify(x2).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
173
173
  }
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
2987
2987
  const schOrFunc = root.refs[ref];
2988
2988
  if (schOrFunc)
2989
2989
  return schOrFunc;
2990
- let _sch = resolve31.call(this, root, ref);
2990
+ let _sch = resolve30.call(this, root, ref);
2991
2991
  if (_sch === void 0) {
2992
2992
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
2993
2993
  const { schemaId } = this.opts;
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
3014
3014
  function sameSchemaEnv(s1, s2) {
3015
3015
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3016
3016
  }
3017
- function resolve31(root, ref) {
3017
+ function resolve30(root, ref) {
3018
3018
  let sch;
3019
3019
  while (typeof (sch = this.refs[ref]) == "string")
3020
3020
  ref = sch;
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
3839
3839
  }
3840
3840
  return uri;
3841
3841
  }
3842
- function resolve31(baseURI, relativeURI, options) {
3842
+ function resolve30(baseURI, relativeURI, options) {
3843
3843
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3844
3844
  const {
3845
3845
  parsed: baseParsed,
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
4201
4201
  var fastUri = {
4202
4202
  SCHEMES,
4203
4203
  normalize,
4204
- resolve: resolve31,
4204
+ resolve: resolve30,
4205
4205
  resolveComponent,
4206
4206
  equal,
4207
4207
  serialize,
@@ -8918,7 +8918,7 @@ var require_stringify = __commonJS({
8918
8918
  props.push(doc.directives.tagString(tag));
8919
8919
  return props.join(" ");
8920
8920
  }
8921
- function stringify11(item, ctx, onComment, onChompKeep) {
8921
+ function stringify10(item, ctx, onComment, onChompKeep) {
8922
8922
  if (identity.isPair(item))
8923
8923
  return item.toString(ctx, onComment, onChompKeep);
8924
8924
  if (identity.isAlias(item)) {
@@ -8947,7 +8947,7 @@ var require_stringify = __commonJS({
8947
8947
  ${ctx.indent}${str}`;
8948
8948
  }
8949
8949
  exports.createStringifyContext = createStringifyContext;
8950
- exports.stringify = stringify11;
8950
+ exports.stringify = stringify10;
8951
8951
  }
8952
8952
  });
8953
8953
 
@@ -8957,7 +8957,7 @@ var require_stringifyPair = __commonJS({
8957
8957
  "use strict";
8958
8958
  var identity = require_identity();
8959
8959
  var Scalar = require_Scalar();
8960
- var stringify11 = require_stringify();
8960
+ var stringify10 = require_stringify();
8961
8961
  var stringifyComment = require_stringifyComment();
8962
8962
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
8963
8963
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
@@ -8979,7 +8979,7 @@ var require_stringifyPair = __commonJS({
8979
8979
  });
8980
8980
  let keyCommentDone = false;
8981
8981
  let chompKeep = false;
8982
- let str = stringify11.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
8982
+ let str = stringify10.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
8983
8983
  if (!explicitKey && !ctx.inFlow && str.length > 1024) {
8984
8984
  if (simpleKeys)
8985
8985
  throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
@@ -9031,7 +9031,7 @@ ${indent}:`;
9031
9031
  ctx.indent = ctx.indent.substring(2);
9032
9032
  }
9033
9033
  let valueCommentDone = false;
9034
- const valueStr = stringify11.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
9034
+ const valueStr = stringify10.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
9035
9035
  let ws = " ";
9036
9036
  if (keyComment || vsb || vcb) {
9037
9037
  ws = vsb ? "\n" : "";
@@ -9172,7 +9172,7 @@ var require_addPairToJSMap = __commonJS({
9172
9172
  "use strict";
9173
9173
  var log = require_log();
9174
9174
  var merge = require_merge();
9175
- var stringify11 = require_stringify();
9175
+ var stringify10 = require_stringify();
9176
9176
  var identity = require_identity();
9177
9177
  var toJS = require_toJS();
9178
9178
  function addPairToJSMap(ctx, map, { key, value }) {
@@ -9208,7 +9208,7 @@ var require_addPairToJSMap = __commonJS({
9208
9208
  if (typeof jsKey !== "object")
9209
9209
  return String(jsKey);
9210
9210
  if (identity.isNode(key) && ctx?.doc) {
9211
- const strCtx = stringify11.createStringifyContext(ctx.doc, {});
9211
+ const strCtx = stringify10.createStringifyContext(ctx.doc, {});
9212
9212
  strCtx.anchors = /* @__PURE__ */ new Set();
9213
9213
  for (const node of ctx.anchors.keys())
9214
9214
  strCtx.anchors.add(node.anchor);
@@ -9275,12 +9275,12 @@ var require_stringifyCollection = __commonJS({
9275
9275
  "node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
9276
9276
  "use strict";
9277
9277
  var identity = require_identity();
9278
- var stringify11 = require_stringify();
9278
+ var stringify10 = require_stringify();
9279
9279
  var stringifyComment = require_stringifyComment();
9280
9280
  function stringifyCollection(collection, ctx, options) {
9281
9281
  const flow = ctx.inFlow ?? collection.flow;
9282
- const stringify12 = flow ? stringifyFlowCollection : stringifyBlockCollection;
9283
- return stringify12(collection, ctx, options);
9282
+ const stringify11 = flow ? stringifyFlowCollection : stringifyBlockCollection;
9283
+ return stringify11(collection, ctx, options);
9284
9284
  }
9285
9285
  function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
9286
9286
  const { indent, options: { commentString } } = ctx;
@@ -9305,7 +9305,7 @@ var require_stringifyCollection = __commonJS({
9305
9305
  }
9306
9306
  }
9307
9307
  chompKeep = false;
9308
- let str2 = stringify11.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
9308
+ let str2 = stringify10.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
9309
9309
  if (comment2)
9310
9310
  str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
9311
9311
  if (chompKeep && comment2)
@@ -9372,7 +9372,7 @@ ${indent}${line}` : "\n";
9372
9372
  }
9373
9373
  if (comment)
9374
9374
  reqNewline = true;
9375
- let str = stringify11.stringify(item, itemCtx, () => comment = null);
9375
+ let str = stringify10.stringify(item, itemCtx, () => comment = null);
9376
9376
  reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
9377
9377
  if (i < items.length - 1) {
9378
9378
  str += ",";
@@ -10733,7 +10733,7 @@ var require_stringifyDocument = __commonJS({
10733
10733
  "node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
10734
10734
  "use strict";
10735
10735
  var identity = require_identity();
10736
- var stringify11 = require_stringify();
10736
+ var stringify10 = require_stringify();
10737
10737
  var stringifyComment = require_stringifyComment();
10738
10738
  function stringifyDocument(doc, options) {
10739
10739
  const lines = [];
@@ -10748,7 +10748,7 @@ var require_stringifyDocument = __commonJS({
10748
10748
  }
10749
10749
  if (hasDirectives)
10750
10750
  lines.push("---");
10751
- const ctx = stringify11.createStringifyContext(doc, options);
10751
+ const ctx = stringify10.createStringifyContext(doc, options);
10752
10752
  const { commentString } = ctx.options;
10753
10753
  if (doc.commentBefore) {
10754
10754
  if (lines.length !== 1)
@@ -10770,7 +10770,7 @@ var require_stringifyDocument = __commonJS({
10770
10770
  contentComment = doc.contents.comment;
10771
10771
  }
10772
10772
  const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
10773
- let body = stringify11.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
10773
+ let body = stringify10.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
10774
10774
  if (contentComment)
10775
10775
  body += stringifyComment.lineComment(body, "", commentString(contentComment));
10776
10776
  if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
@@ -10778,7 +10778,7 @@ var require_stringifyDocument = __commonJS({
10778
10778
  } else
10779
10779
  lines.push(body);
10780
10780
  } else {
10781
- lines.push(stringify11.stringify(doc.contents, ctx));
10781
+ lines.push(stringify10.stringify(doc.contents, ctx));
10782
10782
  }
10783
10783
  if (doc.directives?.docEnd) {
10784
10784
  if (doc.comment) {
@@ -12914,7 +12914,7 @@ var require_cst_scalar = __commonJS({
12914
12914
  var require_cst_stringify = __commonJS({
12915
12915
  "node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
12916
12916
  "use strict";
12917
- var stringify11 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
12917
+ var stringify10 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
12918
12918
  function stringifyToken(token) {
12919
12919
  switch (token.type) {
12920
12920
  case "block-scalar": {
@@ -12967,7 +12967,7 @@ var require_cst_stringify = __commonJS({
12967
12967
  res += stringifyToken(value);
12968
12968
  return res;
12969
12969
  }
12970
- exports.stringify = stringify11;
12970
+ exports.stringify = stringify10;
12971
12971
  }
12972
12972
  });
12973
12973
 
@@ -14697,7 +14697,7 @@ var require_public_api = __commonJS({
14697
14697
  }
14698
14698
  return doc.toJS(Object.assign({ reviver: _reviver }, options));
14699
14699
  }
14700
- function stringify11(value, replacer, options) {
14700
+ function stringify10(value, replacer, options) {
14701
14701
  let _replacer = null;
14702
14702
  if (typeof replacer === "function" || Array.isArray(replacer)) {
14703
14703
  _replacer = replacer;
@@ -14722,7 +14722,7 @@ var require_public_api = __commonJS({
14722
14722
  exports.parse = parse12;
14723
14723
  exports.parseAllDocuments = parseAllDocuments;
14724
14724
  exports.parseDocument = parseDocument2;
14725
- exports.stringify = stringify11;
14725
+ exports.stringify = stringify10;
14726
14726
  }
14727
14727
  });
14728
14728
 
@@ -14779,7 +14779,7 @@ var require_dist = __commonJS({
14779
14779
  });
14780
14780
 
14781
14781
  // plugins/kxm/src/cli.ts
14782
- import { resolve as resolve30 } from "node:path";
14782
+ import { resolve as resolve29 } from "node:path";
14783
14783
  import { fileURLToPath as fileURLToPath4 } from "node:url";
14784
14784
 
14785
14785
  // node_modules/commander/lib/error.js
@@ -19446,7 +19446,7 @@ var HubClient = class {
19446
19446
  if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
19447
19447
  const message = await this.getMessage(messageId);
19448
19448
  if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
19449
- await new Promise((resolve31, reject) => {
19449
+ await new Promise((resolve30, reject) => {
19450
19450
  const onAbort = () => {
19451
19451
  signal?.removeEventListener("abort", onAbort);
19452
19452
  clearTimeout(timer);
@@ -19454,7 +19454,7 @@ var HubClient = class {
19454
19454
  };
19455
19455
  const timer = setTimeout(() => {
19456
19456
  signal?.removeEventListener("abort", onAbort);
19457
- resolve31();
19457
+ resolve30();
19458
19458
  }, Math.min(500, Math.max(1, deadline - Date.now())));
19459
19459
  signal?.addEventListener("abort", onAbort, { once: true });
19460
19460
  if (signal?.aborted) onAbort();
@@ -19509,7 +19509,7 @@ var HubClient = class {
19509
19509
  } catch (error) {
19510
19510
  if (this.stopped || error instanceof Error && error.name === "AbortError") return;
19511
19511
  }
19512
- if (!this.stopped) await new Promise((resolve31) => setTimeout(resolve31, this.options.reconnectMs));
19512
+ if (!this.stopped) await new Promise((resolve30) => setTimeout(resolve30, this.options.reconnectMs));
19513
19513
  }
19514
19514
  }
19515
19515
  headers(includeIdentity = true) {
@@ -20960,7 +20960,7 @@ function defaultSpawn(command, args, options) {
20960
20960
  if (options.signal?.aborted) {
20961
20961
  return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
20962
20962
  }
20963
- return new Promise((resolve31) => {
20963
+ return new Promise((resolve30) => {
20964
20964
  const stdout = [];
20965
20965
  const stderr = [];
20966
20966
  let outputBytes = 0;
@@ -20991,7 +20991,7 @@ function defaultSpawn(command, args, options) {
20991
20991
  const started = Boolean(child?.pid);
20992
20992
  if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
20993
20993
  const unverifiedDescendants = stopping || started && !observedChildExit;
20994
- resolve31({
20994
+ resolve30({
20995
20995
  stdout: Buffer.concat(stdout).toString("utf8"),
20996
20996
  stderr: Buffer.concat(stderr).toString("utf8"),
20997
20997
  code,
@@ -22060,9 +22060,6 @@ var KxmSchemaRegistry = class {
22060
22060
  localBindingsValidator;
22061
22061
  templateProvenanceValidator;
22062
22062
  initOperationValidator;
22063
- migrationPlanValidator;
22064
- migrationDecisionValidator;
22065
- migrationReceiptValidator;
22066
22063
  permissionDiffValidator;
22067
22064
  runEventValidator;
22068
22065
  driveReceiptValidator;
@@ -22079,9 +22076,6 @@ var KxmSchemaRegistry = class {
22079
22076
  const localBindingsFile = "local-repository-bindings.schema.json";
22080
22077
  const templateProvenanceFile = "template-provenance.schema.json";
22081
22078
  const initOperationFile = "init-operation.schema.json";
22082
- const migrationPlanFile = "migration-plan.schema.json";
22083
- const migrationDecisionFile = "migration-decision.schema.json";
22084
- const migrationReceiptFile = "migration-receipt.schema.json";
22085
22079
  const permissionDiffFile = "permission-diff.schema.json";
22086
22080
  const runEventFile = "run-event.schema.json";
22087
22081
  const driveReceiptFile = "drive-receipt.schema.json";
@@ -22090,9 +22084,6 @@ var KxmSchemaRegistry = class {
22090
22084
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
22091
22085
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
22092
22086
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
22093
- this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationPlanFile)));
22094
- this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationDecisionFile)));
22095
- this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationReceiptFile)));
22096
22087
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, permissionDiffFile)));
22097
22088
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, runEventFile)));
22098
22089
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, driveReceiptFile)));
@@ -22106,9 +22097,6 @@ var KxmSchemaRegistry = class {
22106
22097
  const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${localBindingsFile}`);
22107
22098
  const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${templateProvenanceFile}`);
22108
22099
  const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${initOperationFile}`);
22109
- const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationPlanFile}`);
22110
- const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationDecisionFile}`);
22111
- const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationReceiptFile}`);
22112
22100
  const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${permissionDiffFile}`);
22113
22101
  const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${runEventFile}`);
22114
22102
  const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
@@ -22117,9 +22105,6 @@ var KxmSchemaRegistry = class {
22117
22105
  if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
22118
22106
  if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
22119
22107
  if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
22120
- if (!migrationPlanValidator) throw new Error(`schema did not compile: ${migrationPlanFile}`);
22121
- if (!migrationDecisionValidator) throw new Error(`schema did not compile: ${migrationDecisionFile}`);
22122
- if (!migrationReceiptValidator) throw new Error(`schema did not compile: ${migrationReceiptFile}`);
22123
22108
  if (!permissionDiffValidator) throw new Error(`schema did not compile: ${permissionDiffFile}`);
22124
22109
  if (!runEventValidator) throw new Error(`schema did not compile: ${runEventFile}`);
22125
22110
  if (!driveReceiptValidator) throw new Error(`schema did not compile: ${driveReceiptFile}`);
@@ -22128,9 +22113,6 @@ var KxmSchemaRegistry = class {
22128
22113
  this.localBindingsValidator = localBindingsValidator;
22129
22114
  this.templateProvenanceValidator = templateProvenanceValidator;
22130
22115
  this.initOperationValidator = initOperationValidator;
22131
- this.migrationPlanValidator = migrationPlanValidator;
22132
- this.migrationDecisionValidator = migrationDecisionValidator;
22133
- this.migrationReceiptValidator = migrationReceiptValidator;
22134
22116
  this.permissionDiffValidator = permissionDiffValidator;
22135
22117
  this.runEventValidator = runEventValidator;
22136
22118
  this.driveReceiptValidator = driveReceiptValidator;
@@ -22156,15 +22138,6 @@ var KxmSchemaRegistry = class {
22156
22138
  validateInitOperation(value, file) {
22157
22139
  return this.validateAuxiliary(value, file, "kxm.init-operation.v1", this.initOperationValidator);
22158
22140
  }
22159
- validateMigrationPlan(value, file) {
22160
- return this.validateAuxiliary(value, file, "kxm.migration-plan.v1", this.migrationPlanValidator);
22161
- }
22162
- validateMigrationDecision(value, file) {
22163
- return this.validateAuxiliary(value, file, "kxm.migration-decision.v1", this.migrationDecisionValidator);
22164
- }
22165
- validateMigrationReceipt(value, file) {
22166
- return this.validateAuxiliary(value, file, "kxm.migration-receipt.v1", this.migrationReceiptValidator);
22167
- }
22168
22141
  validatePermissionDiff(value, file) {
22169
22142
  return this.validateAuxiliary(value, file, "kxm.permission-diff.v1", this.permissionDiffValidator);
22170
22143
  }
@@ -22516,35 +22489,6 @@ function validateToolPolicy(resource, policy, label, issues) {
22516
22489
  if (allowed.has(tool)) issues.push(issue2("semantic", "tool_policy_contradiction", resource.logicalPath, `${label} both allows and denies ${tool}`));
22517
22490
  }
22518
22491
  }
22519
- function validateKxmResources(resources, options = {}) {
22520
- const make = (logicalPath, kind, id, value) => ({
22521
- kind,
22522
- ...id === void 0 ? {} : { id },
22523
- file: logicalPath,
22524
- logicalPath,
22525
- value
22526
- });
22527
- assertNoRegisteredGates(options);
22528
- let gateRegistry;
22529
- let project;
22530
- const repositories = /* @__PURE__ */ new Map();
22531
- const agents = /* @__PURE__ */ new Map();
22532
- const models = /* @__PURE__ */ new Map();
22533
- const workflows = /* @__PURE__ */ new Map();
22534
- const environments = [];
22535
- for (const [logicalPath, resource] of resources) {
22536
- const made = make(logicalPath, resource.kind, resource.id, resource.value);
22537
- if (resource.kind === "project") project = made;
22538
- else if (resource.kind === "repository" && resource.id) repositories.set(resource.id, made);
22539
- else if (resource.kind === "agent" && resource.id) agents.set(resource.id, made);
22540
- else if (resource.kind === "model" && resource.id) models.set(resource.id, made);
22541
- else if (resource.kind === "workflow" && resource.id) workflows.set(resource.id, made);
22542
- else if (resource.kind === "environment") environments.push(made);
22543
- else if (resource.kind === "gate-registry") gateRegistry = made;
22544
- }
22545
- if (!project) return [issue2("discovery", "project_definition_missing", ".kxm/project.yaml", "resource set has no project definition")];
22546
- return validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry);
22547
- }
22548
22492
  function validateAgentScope(agent, step, repositories, file, stepId, issues) {
22549
22493
  validateToolScope(agent, step, file, stepId, issues);
22550
22494
  const agentRepositories = objectValue(agent.value.repositories) ?? {};
@@ -22667,8 +22611,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
22667
22611
  const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
22668
22612
  if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
22669
22613
  }
22670
- const join50 = objectValue(step.join);
22671
- const minimumPassed = join50 && typeof join50.minimumPassed === "number" ? join50.minimumPassed : void 0;
22614
+ const join49 = objectValue(step.join);
22615
+ const minimumPassed = join49 && typeof join49.minimumPassed === "number" ? join49.minimumPassed : void 0;
22672
22616
  if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
22673
22617
  const distinctBy = names(assignment?.distinctBy);
22674
22618
  if (distinctBy.length > 0) {
@@ -22956,11 +22900,14 @@ function assertNoRegisteredGates(options) {
22956
22900
  function loadKxmProject(projectRoot, options = {}) {
22957
22901
  assertNoRegisteredGates(options);
22958
22902
  const root = resolve3(projectRoot);
22959
- let migrationReceipt;
22960
- if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
22961
- const receiptCheck = readKxmMigrationReceipt(root, options);
22962
- if (receiptCheck.issues.length > 0) throw new KxmConfigError(receiptCheck.issues);
22963
- migrationReceipt = receiptCheck.receipt;
22903
+ const legacyPresent = legacyConfigFilesAt(root);
22904
+ if (legacyPresent.length > 0) {
22905
+ throw new KxmConfigError(legacyPresent.map((file) => issue2(
22906
+ "semantic",
22907
+ "legacy_state_unsupported",
22908
+ file,
22909
+ "legacy JSON configuration is present and this build does not migrate it: delete these files once their YAML replacements exist in .kxm/, or initialise a fresh project"
22910
+ )));
22964
22911
  }
22965
22912
  const registry = new KxmSchemaRegistry(options.schemasDir);
22966
22913
  const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
@@ -22973,9 +22920,6 @@ function loadKxmProject(projectRoot, options = {}) {
22973
22920
  earlyIssues.push(issue2("semantic", "template_provenance_project_mismatch", ".kxm/template-provenance.yaml", "template provenance belongs to a different project identity"));
22974
22921
  }
22975
22922
  }
22976
- if (migrationReceipt && stringValue(migrationReceipt.projectId) !== stringValue(project.value.id)) {
22977
- earlyIssues.push(issue2("semantic", "migration_project_mismatch", KXM_MIGRATION_RECEIPT_PATH, "migration receipt belongs to a different project identity"));
22978
- }
22979
22923
  const declaredRepositoryIds = new Set(valuesOf(project.value, "repositories").map((candidate) => stringValue(objectValue(candidate)?.id)).filter((candidate) => candidate !== void 0));
22980
22924
  for (const repositoryId of Object.keys(options.repositoryBindings ?? {}).sort(compareCodeUnits3)) {
22981
22925
  if (!resourceIdentifier(repositoryId)) {
@@ -23052,6 +22996,15 @@ function loadKxmProject(projectRoot, options = {}) {
23052
22996
  continue;
23053
22997
  }
23054
22998
  }
22999
+ const memberLegacy = binding === root ? [] : legacyConfigFilesAt(binding);
23000
+ if (memberLegacy.length > 0) {
23001
+ throw new KxmConfigError(memberLegacy.map((file) => issue2(
23002
+ "semantic",
23003
+ "legacy_state_unsupported",
23004
+ `${repositoryId}/${file}`,
23005
+ `repository ${repositoryId} holds legacy JSON configuration and this build does not migrate it: delete those files once their YAML replacements exist, or bind a clean worktree`
23006
+ )));
23007
+ }
23055
23008
  const foldedBinding = canonicalHostPath(binding).toLocaleLowerCase("en-US");
23056
23009
  const priorBinding = seenBindings.get(foldedBinding);
23057
23010
  if (priorBinding && priorBinding !== repositoryId) {
@@ -23105,50 +23058,10 @@ function loadKxmProject(projectRoot, options = {}) {
23105
23058
  environments,
23106
23059
  ...gateRegistry ? { gateRegistry } : {},
23107
23060
  ...templateProvenance === void 0 ? {} : { templateProvenance },
23108
- ...migrationReceipt === void 0 ? {} : { migrationReceipt },
23109
23061
  resources,
23110
23062
  configRevision: bundleRevision(resources)
23111
23063
  };
23112
23064
  }
23113
- function verifyKxmMigrationReceiptTarget(root, receipt, resources, configRevision) {
23114
- const issues = [];
23115
- if (receipt.configRevision !== configRevision) {
23116
- issues.push(issue2("semantic", "migration_target_changed", KXM_MIGRATION_RECEIPT_PATH, "target configuration revision no longer matches the migration receipt"));
23117
- }
23118
- const declared = /* @__PURE__ */ new Map();
23119
- for (const candidate of Array.isArray(receipt.resources) ? receipt.resources : []) {
23120
- if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
23121
- const record = candidate;
23122
- if (typeof record.path === "string") declared.set(record.path, record);
23123
- }
23124
- }
23125
- const installedPaths = /* @__PURE__ */ new Set();
23126
- for (const resource of resources) {
23127
- const relative7 = resource.file.startsWith(root) ? relativePortable(root, resource.file) : void 0;
23128
- if (!relative7) continue;
23129
- installedPaths.add(relative7);
23130
- const record = declared.get(relative7);
23131
- if (!record) {
23132
- issues.push(issue2("semantic", "migration_target_unreceipted", relative7, "installed resource is not covered by the migration receipt"));
23133
- continue;
23134
- }
23135
- const current = hashFileRecord(root, relative7);
23136
- if (!current || current.sha256 !== record.sha256 || current.bytes !== record.bytes) {
23137
- issues.push(issue2("semantic", "migration_target_modified", relative7, "installed resource bytes differ from the migration receipt"));
23138
- }
23139
- }
23140
- for (const path4 of declared.keys()) {
23141
- if (!installedPaths.has(path4)) {
23142
- issues.push(issue2("semantic", "migration_target_missing", path4, "receipt-covered resource is not part of the validated configuration"));
23143
- }
23144
- }
23145
- return sortIssues2(issues);
23146
- }
23147
- function relativePortable(root, absolute) {
23148
- const rel = relative(root, absolute);
23149
- if (!rel || isAbsolute2(rel) || rel === ".." || rel.startsWith(`..${sep}`)) return void 0;
23150
- return rel.split(sep).join("/");
23151
- }
23152
23065
  function legacyInputsAt(root) {
23153
23066
  const candidates = [
23154
23067
  ".kxm/config/agents.json",
@@ -23158,7 +23071,6 @@ function legacyInputsAt(root) {
23158
23071
  ];
23159
23072
  return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
23160
23073
  }
23161
- var KXM_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
23162
23074
  var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
23163
23075
  function legacyConfigFilesAt(root) {
23164
23076
  const files = [];
@@ -23184,66 +23096,6 @@ function legacyConfigFilesAt(root) {
23184
23096
  }
23185
23097
  return files;
23186
23098
  }
23187
- function hashFileRecord(root, relativePath) {
23188
- const absolute = join6(root, ...relativePath.split("/"));
23189
- if (!existsSync6(absolute)) return void 0;
23190
- const bytes = readFileSync5(absolute);
23191
- return {
23192
- path: relativePath,
23193
- sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
23194
- bytes: bytes.byteLength
23195
- };
23196
- }
23197
- function migrationReceiptSelfHash(receipt) {
23198
- const { receiptSha256: _ignored, ...unsigned } = receipt;
23199
- return `sha256:${createHash6("sha256").update(kxmCanonicalJson(unsigned), "utf8").digest("hex")}`;
23200
- }
23201
- function readKxmMigrationReceipt(root, options = {}) {
23202
- const receiptPath = join6(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
23203
- const legacyFiles = legacyConfigFilesAt(root);
23204
- if (!existsSync6(receiptPath)) {
23205
- return {
23206
- issues: legacyFiles.map((file) => issue2("semantic", "legacy_kxm_conflict", file, "legacy and KXM configuration cannot coexist before an accepted migration receipt"))
23207
- };
23208
- }
23209
- const receiptStat = lstatSync(receiptPath);
23210
- if (receiptStat.isSymbolicLink() || !receiptStat.isFile()) {
23211
- return { issues: [issue2("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")] };
23212
- }
23213
- let receipt;
23214
- try {
23215
- receipt = parseRestrictedYaml2(readFileSync5(receiptPath), KXM_MIGRATION_RECEIPT_PATH);
23216
- } catch (error) {
23217
- if (error instanceof KxmConfigError) return { issues: [...error.issues] };
23218
- throw error;
23219
- }
23220
- const registry = new KxmSchemaRegistry(options.schemasDir);
23221
- const schemaIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
23222
- if (schemaIssues.length > 0) return { issues: schemaIssues };
23223
- if (receipt.receiptSha256 !== migrationReceiptSelfHash(receipt)) {
23224
- return { issues: [issue2("semantic", "migration_receipt_hash_mismatch", KXM_MIGRATION_RECEIPT_PATH, "receipt self-hash does not match its content")] };
23225
- }
23226
- const sources = (Array.isArray(receipt.sources) ? receipt.sources : []).map((candidate) => candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate.path : void 0).filter((candidate) => typeof candidate === "string").sort(compareCodeUnits3);
23227
- const issues = [];
23228
- const declared = new Set(sources);
23229
- for (const file of legacyFiles) {
23230
- if (!declared.has(file)) {
23231
- issues.push(issue2("semantic", "migration_source_unmigrated", file, "legacy configuration file is not covered by the migration receipt"));
23232
- continue;
23233
- }
23234
- const record = (Array.isArray(receipt.sources) ? receipt.sources : []).map((candidate) => candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : void 0).find((candidate) => candidate?.path === file);
23235
- const current = hashFileRecord(root, file);
23236
- if (!current || current.sha256 !== record?.sha256 || current.bytes !== record?.bytes) {
23237
- issues.push(issue2("semantic", "migration_source_changed", file, "legacy configuration changed after the migration receipt was issued"));
23238
- }
23239
- }
23240
- for (const file of sources) {
23241
- if (!legacyFiles.includes(file)) {
23242
- issues.push(issue2("semantic", "migration_source_missing", file, "receipt covers a legacy configuration file that no longer exists"));
23243
- }
23244
- }
23245
- return issues.length > 0 ? { issues } : { receipt, issues: [] };
23246
- }
23247
23099
  function discoverLegacyRoot(start) {
23248
23100
  let initial = resolve3(start);
23249
23101
  if (existsSync6(initial) && !lstatSync(initial).isDirectory()) initial = dirname4(initial);
@@ -23260,16 +23112,32 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
23260
23112
  return { mode: "ready", inspectedFrom, projectRoot, changesRequired: false, issues: [], legacyInputs: [], configRevision: bundle.configRevision };
23261
23113
  } catch (error) {
23262
23114
  if (!(error instanceof KxmConfigError)) throw error;
23115
+ const legacyIssues = error.issues.filter((candidate) => candidate.code === "legacy_state_unsupported");
23263
23116
  const legacyInputs = legacyInputsAt(projectRoot);
23264
- if (legacyInputs.length > 0) {
23265
- return { mode: "migrate", inspectedFrom, projectRoot, legacyRoot: projectRoot, changesRequired: true, issues: error.issues, legacyInputs };
23117
+ if (legacyInputs.length > 0 || legacyIssues.length > 0) {
23118
+ return {
23119
+ mode: "legacy",
23120
+ inspectedFrom,
23121
+ projectRoot,
23122
+ legacyRoot: projectRoot,
23123
+ changesRequired: true,
23124
+ issues: [...error.issues, ...legacyInputs.length > 0 ? [issue2("discovery", "legacy_state_unsupported", ".kxm", "legacy configuration is present and this build does not migrate it: initialise a fresh project directory and carry over the YAML definitions you want to keep")] : []],
23125
+ legacyInputs: [.../* @__PURE__ */ new Set([...legacyInputs, ...legacyIssues.map((candidate) => candidate.file)])]
23126
+ };
23266
23127
  }
23267
23128
  return { mode: "repair", inspectedFrom, projectRoot, changesRequired: true, issues: error.issues, legacyInputs: [] };
23268
23129
  }
23269
23130
  }
23270
23131
  const legacy = discoverLegacyRoot(inspectedFrom);
23271
23132
  if (legacy) {
23272
- return { mode: "migrate", inspectedFrom, legacyRoot: legacy.root, changesRequired: true, issues: [], legacyInputs: legacy.inputs };
23133
+ return {
23134
+ mode: "legacy",
23135
+ inspectedFrom,
23136
+ legacyRoot: legacy.root,
23137
+ changesRequired: true,
23138
+ issues: [issue2("discovery", "legacy_state_unsupported", legacy.root, "legacy KXM/Mesh configuration discovered; this build does not migrate it \u2014 initialise a fresh project directory and copy the YAML definitions you want to keep")],
23139
+ legacyInputs: legacy.inputs
23140
+ };
23273
23141
  }
23274
23142
  const gitRoot = discoverGitRoot(inspectedFrom);
23275
23143
  const candidateRoot = gitRoot ?? inspectedFrom;
@@ -23767,20 +23635,11 @@ function openDatabase(file, description, spec) {
23767
23635
  database.exec(spec.schema);
23768
23636
  database.exec(`PRAGMA user_version = ${spec.version}`);
23769
23637
  } else if (version < spec.version) {
23770
- let currentVersion = version;
23771
- while (currentVersion < spec.version) {
23772
- const step = spec.migrations?.find((m2) => m2.fromVersion === currentVersion);
23773
- if (!step) {
23774
- throw databaseError(
23775
- "runtime_schema_outdated",
23776
- file,
23777
- `${description} schema version ${version} is older than ${spec.version}; no migration lane, backup and restore remain E6`
23778
- );
23779
- }
23780
- step.migrate(database);
23781
- currentVersion = step.toVersion;
23782
- database.exec(`PRAGMA user_version = ${currentVersion}`);
23783
- }
23638
+ throw databaseError(
23639
+ "runtime_schema_outdated",
23640
+ file,
23641
+ `${description} is schema version ${version}; this build requires ${spec.version}. Delete the state file to start fresh and let its owning process recreate it (\`kxm hub start\` for hub state, the Runtime for registry/event stores); \`kxm init\` is project-only and rebuilds no database \u2014 upgrading old state in place is deliberately unsupported`
23642
+ );
23784
23643
  }
23785
23644
  if (spec.tables) {
23786
23645
  verifyExpectedTables(database, file, description, spec.tables);
@@ -24541,7 +24400,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
24541
24400
  const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
24542
24401
  const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
24543
24402
  const assignments = compileAssignments(step, id, agent, sink);
24544
- const join50 = compileJoin(step, id, sink);
24403
+ const join49 = compileJoin(step, id, sink);
24545
24404
  const requiredEvidence = compileEvidence(step, id, sink);
24546
24405
  const transitions = compileTransitions(step, id, index, stepIndex, sink);
24547
24406
  const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
@@ -24569,7 +24428,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
24569
24428
  transitions: orderedTransitions,
24570
24429
  requiresPlanHash: requirePlanHash.includes(id),
24571
24430
  assignments,
24572
- join: join50
24431
+ join: join49
24573
24432
  };
24574
24433
  if (kind === "agent" || kind === "moa") {
24575
24434
  if (!agent) return void 0;
@@ -24619,15 +24478,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
24619
24478
  };
24620
24479
  }
24621
24480
  function compileJoin(step, stepId, sink) {
24622
- const join50 = objectValue2(step.join);
24623
- if (!join50) return { strategy: "all" };
24624
- const declared = stringValue2(join50.strategy);
24481
+ const join49 = objectValue2(step.join);
24482
+ if (!join49) return { strategy: "all" };
24483
+ const declared = stringValue2(join49.strategy);
24625
24484
  const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
24626
- const minimumPassed = compileOptionalCount(join50.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
24485
+ const minimumPassed = compileOptionalCount(join49.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
24627
24486
  const compiled = {
24628
24487
  strategy,
24629
24488
  ...minimumPassed !== void 0 ? { minimumPassed } : {},
24630
- ...typeof join50.cancelRemaining === "boolean" ? { cancelRemaining: join50.cancelRemaining } : {}
24489
+ ...typeof join49.cancelRemaining === "boolean" ? { cancelRemaining: join49.cancelRemaining } : {}
24631
24490
  };
24632
24491
  return compiled;
24633
24492
  }
@@ -27856,7 +27715,7 @@ async function watchGithubChecks(input) {
27856
27715
  }
27857
27716
  const fetchImpl = input.fetchImpl ?? fetch;
27858
27717
  const now = input.now ?? Date.now;
27859
- const sleep = input.sleep ?? ((ms) => new Promise((resolve31) => setTimeout(resolve31, ms)));
27718
+ const sleep = input.sleep ?? ((ms) => new Promise((resolve30) => setTimeout(resolve30, ms)));
27860
27719
  const deadline = now() + input.timeoutMs;
27861
27720
  const headers = {
27862
27721
  authorization: `Bearer ${token}`,
@@ -28851,9 +28710,9 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
28851
28710
  }
28852
28711
 
28853
28712
  // plugins/kxm/src/cli/tasks.ts
28854
- var import_yaml13 = __toESM(require_dist(), 1);
28855
- import { existsSync as existsSync24, readFileSync as readFileSync23, readdirSync as readdirSync8 } from "node:fs";
28856
- import { basename as basename6, join as join28, resolve as resolve21 } from "node:path";
28713
+ var import_yaml12 = __toESM(require_dist(), 1);
28714
+ import { existsSync as existsSync23, readFileSync as readFileSync22, readdirSync as readdirSync8 } from "node:fs";
28715
+ import { basename as basename6, join as join27, resolve as resolve20 } from "node:path";
28857
28716
 
28858
28717
  // plugins/kxm/src/suggest.ts
28859
28718
  var WORKFLOW_PATTERNS = [
@@ -29863,7 +29722,7 @@ function createStudioServer(options = {}) {
29863
29722
  }
29864
29723
 
29865
29724
  // plugins/kxm/src/cli/project.ts
29866
- import { join as join27, resolve as resolve20 } from "node:path";
29725
+ import { join as join26, resolve as resolve19 } from "node:path";
29867
29726
  import { createInterface as createInterface2 } from "node:readline";
29868
29727
 
29869
29728
  // plugins/kxm/src/model-inventory.ts
@@ -31692,17 +31551,20 @@ function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
31692
31551
  ]);
31693
31552
  const loaderOptions2 = configOptions(options, repositoryBindings);
31694
31553
  const transactionOptions = repairOptions(options, repositoryBindings);
31554
+ const plan = planKxmInitialization(start, loaderOptions2);
31555
+ if (plan.mode === "legacy") {
31556
+ return { action: "planned", plan, ...plan.projectRoot ? { projectRoot: plan.projectRoot } : {}, files: [] };
31557
+ }
31695
31558
  if (hasKxmInitTransaction(gitRoot)) {
31696
31559
  const operation = inspectKxmInitTransaction(gitRoot, options.schemasDir);
31697
- const plan2 = planKxmInitialization(start, loaderOptions2);
31698
31560
  if (!operation) {
31699
- if (options.dryRun) return { action: "planned", plan: plan2, projectRoot: gitRoot, resumePending: true, files: [] };
31561
+ if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, resumePending: true, files: [] };
31700
31562
  if (!mutationLock) throw new Error("project mutation lock is required to clean an empty transaction");
31701
31563
  resumeKxmInitTransaction(gitRoot, transactionOptions);
31702
31564
  } else if (options.dryRun) {
31703
31565
  return {
31704
31566
  action: "planned",
31705
- plan: plan2,
31567
+ plan,
31706
31568
  projectRoot: gitRoot,
31707
31569
  resumePending: true,
31708
31570
  transactionKind: operation.kind,
@@ -31751,10 +31613,6 @@ function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
31751
31613
  };
31752
31614
  }
31753
31615
  }
31754
- const plan = planKxmInitialization(start, loaderOptions2);
31755
- if (plan.mode === "migrate") {
31756
- return { action: "planned", plan, ...plan.projectRoot ? { projectRoot: plan.projectRoot } : {}, files: [] };
31757
- }
31758
31616
  if (plan.mode === "repair") {
31759
31617
  const projectRoot = plan.projectRoot ?? gitRoot;
31760
31618
  let templateRepair;
@@ -31903,1486 +31761,6 @@ function initializeKxmProject(start = process.cwd(), options = {}) {
31903
31761
  return withKxmLocalBindingLock(gitRoot, storeOptions, (lock) => initializeKxmProjectAtGitRoot(start, gitRoot, options, lock));
31904
31762
  }
31905
31763
 
31906
- // plugins/kxm/src/migrate.ts
31907
- var import_yaml12 = __toESM(require_dist(), 1);
31908
- import { createHash as createHash13 } from "node:crypto";
31909
- import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync23, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync19, openSync as openSync3, readFileSync as readFileSync22, renameSync as renameSync7, rmSync as rmSync9, writeFileSync as writeFileSync18 } from "node:fs";
31910
- import { join as join26 } from "node:path";
31911
- var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
31912
- var MAX_LEGACY_JSON_DEPTH = 32;
31913
- var MAX_LEGACY_JSON_NODES = 32768;
31914
- var MAX_LEGACY_SOURCES = 64;
31915
- function migrateIssue(phase, code, file, message) {
31916
- return { phase, code, file, message };
31917
- }
31918
- function migrateFail(code, file, message) {
31919
- throw new KxmConfigError([migrateIssue("parse", code, file, message)]);
31920
- }
31921
- function parseLegacyJson(text, label) {
31922
- const bytes = Buffer.byteLength(text, "utf8");
31923
- if (bytes > MAX_LEGACY_JSON_BYTES) migrateFail("document_too_large", label, `document exceeds ${MAX_LEGACY_JSON_BYTES} bytes`);
31924
- const state = { nodes: 0 };
31925
- const parseNode = (value, path4, depth) => {
31926
- state.nodes += 1;
31927
- if (state.nodes > MAX_LEGACY_JSON_NODES) migrateFail("node_limit", label, `document exceeds ${MAX_LEGACY_JSON_NODES} nodes`);
31928
- if (depth > MAX_LEGACY_JSON_DEPTH) migrateFail("depth_limit", label, `document exceeds nesting depth ${MAX_LEGACY_JSON_DEPTH}`);
31929
- if (value === null || typeof value === "boolean" || typeof value === "string") return value;
31930
- if (typeof value === "number") {
31931
- if (!Number.isFinite(value)) migrateFail("non_json_number", label, `${path4} is not a finite number`);
31932
- return value;
31933
- }
31934
- if (Array.isArray(value)) {
31935
- return value.map((entry, index) => parseNode(entry, `${path4}[${index}]`, depth + 1));
31936
- }
31937
- if (value && typeof value === "object") {
31938
- const record = {};
31939
- for (const [key, entry] of Object.entries(value)) record[key] = parseNode(entry, `${path4}.${key}`, depth + 1);
31940
- return record;
31941
- }
31942
- migrateFail("non_json_value", label, `${path4} is not JSON-compatible`);
31943
- };
31944
- let raw;
31945
- try {
31946
- raw = JSON.parse(text);
31947
- } catch (error) {
31948
- migrateFail("invalid_json", label, error instanceof Error ? error.message : String(error));
31949
- }
31950
- detectDuplicateKeys(text, label);
31951
- return parseNode(raw, "$", 0);
31952
- }
31953
- function detectDuplicateKeys(text, label) {
31954
- const stack = [];
31955
- let index = 0;
31956
- const length = text.length;
31957
- const skipWhitespace = () => {
31958
- while (index < length && /[\s]/.test(text[index])) index += 1;
31959
- };
31960
- const parseString = () => {
31961
- let result = "";
31962
- index += 1;
31963
- while (index < length) {
31964
- const char = text[index];
31965
- if (char === '"') {
31966
- index += 1;
31967
- return result;
31968
- }
31969
- if (char === "\\") {
31970
- const escape2 = text[index + 1];
31971
- if (escape2 === "u") {
31972
- result += String.fromCharCode(Number.parseInt(text.slice(index + 2, index + 6), 16));
31973
- index += 6;
31974
- } else {
31975
- const escapes = { '"': '"', "\\": "\\", "/": "/", b: "\b", f: "\f", n: "\n", r: "\r", t: " " };
31976
- result += escapes[escape2] ?? escape2;
31977
- index += 2;
31978
- }
31979
- } else {
31980
- result += char;
31981
- index += 1;
31982
- }
31983
- }
31984
- migrateFail("invalid_json", label, "unterminated string");
31985
- };
31986
- const skipValue = () => {
31987
- skipWhitespace();
31988
- const char = text[index];
31989
- if (char === '"') {
31990
- parseString();
31991
- return;
31992
- }
31993
- if (char === "{" || char === "[") {
31994
- parseContainer();
31995
- return;
31996
- }
31997
- while (index < length && !/[\s,\]}]/.test(text[index])) index += 1;
31998
- };
31999
- const parseContainer = () => {
32000
- const char = text[index];
32001
- if (stack.length > MAX_LEGACY_JSON_DEPTH) migrateFail("depth_limit", label, `document exceeds nesting depth ${MAX_LEGACY_JSON_DEPTH}`);
32002
- if (char === "{") {
32003
- const keys = /* @__PURE__ */ new Set();
32004
- stack.push(keys);
32005
- index += 1;
32006
- skipWhitespace();
32007
- if (text[index] === "}") {
32008
- index += 1;
32009
- stack.pop();
32010
- return;
32011
- }
32012
- for (; ; ) {
32013
- skipWhitespace();
32014
- if (text[index] !== '"') migrateFail("invalid_json", label, `expected object key at byte ${index}`);
32015
- const key = parseString();
32016
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
32017
- migrateFail("forbidden_key", label, `key ${JSON.stringify(key)} is forbidden`);
32018
- }
32019
- const frame = stack[stack.length - 1];
32020
- if (frame instanceof Set) {
32021
- if (frame.has(key)) migrateFail("duplicate_key", label, `duplicate key ${JSON.stringify(key)}`);
32022
- frame.add(key);
32023
- }
32024
- skipWhitespace();
32025
- if (text[index] !== ":") migrateFail("invalid_json", label, `expected ':' at byte ${index}`);
32026
- index += 1;
32027
- skipValue();
32028
- skipWhitespace();
32029
- if (text[index] === ",") {
32030
- index += 1;
32031
- continue;
32032
- }
32033
- if (text[index] === "}") {
32034
- index += 1;
32035
- stack.pop();
32036
- return;
32037
- }
32038
- migrateFail("invalid_json", label, `expected ',' or '}' at byte ${index}`);
32039
- }
32040
- }
32041
- if (char === "[") {
32042
- stack.push("array");
32043
- index += 1;
32044
- skipWhitespace();
32045
- if (text[index] === "]") {
32046
- index += 1;
32047
- stack.pop();
32048
- return;
32049
- }
32050
- for (; ; ) {
32051
- skipValue();
32052
- skipWhitespace();
32053
- if (text[index] === ",") {
32054
- index += 1;
32055
- continue;
32056
- }
32057
- if (text[index] === "]") {
32058
- index += 1;
32059
- stack.pop();
32060
- return;
32061
- }
32062
- migrateFail("invalid_json", label, `expected ',' or ']' at byte ${index}`);
32063
- }
32064
- }
32065
- };
32066
- skipValue();
32067
- skipWhitespace();
32068
- if (index !== length) migrateFail("invalid_json", label, `trailing content at byte ${index}`);
32069
- }
32070
- function sha256Of(input) {
32071
- return `sha256:${createHash13("sha256").update(input).digest("hex")}`;
32072
- }
32073
- function readKxmLegacySources(root) {
32074
- const files = legacyConfigFilesAt(root);
32075
- if (files.length > MAX_LEGACY_SOURCES) {
32076
- throw new KxmConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
32077
- }
32078
- return files.map((path4) => {
32079
- const absolute = join26(root, ...path4.split("/"));
32080
- const stat = lstatSync8(absolute);
32081
- if (stat.isSymbolicLink() || !stat.isFile()) {
32082
- throw new KxmConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
32083
- }
32084
- const buffer = readFileSync22(absolute);
32085
- let text;
32086
- try {
32087
- text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
32088
- } catch {
32089
- throw new KxmConfigError([migrateIssue("parse", "invalid_utf8", path4, "document is not valid UTF-8")]);
32090
- }
32091
- return {
32092
- path: path4,
32093
- sha256: sha256Of(buffer),
32094
- bytes: buffer.byteLength,
32095
- value: parseLegacyJson(text, path4)
32096
- };
32097
- });
32098
- }
32099
- function legacySourceDigest(sources) {
32100
- return sha256Of(kxmCanonicalJson(sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes }))));
32101
- }
32102
- var IDENTIFIER2 = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
32103
- var KNOWN_AGENT_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "driver", "model", "thinking", "purpose"]);
32104
- var KNOWN_GATE_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "driver", "purpose"]);
32105
- var KNOWN_WORKFLOW_FIELDS = /* @__PURE__ */ new Set([
32106
- "id",
32107
- "source",
32108
- "project",
32109
- "target",
32110
- "secret",
32111
- "secretEnv",
32112
- "signalSecret",
32113
- "signalSecretEnv",
32114
- "event",
32115
- "filter",
32116
- "delivery",
32117
- "ttlMs",
32118
- "promptTemplate",
32119
- "stages",
32120
- "maxTransitions",
32121
- "reproOracle",
32122
- "planHash",
32123
- "requirePlanHash"
32124
- ]);
32125
- var KNOWN_STAGE_FIELDS = /* @__PURE__ */ new Set(["id", "label", "instructions", "requiredEvidence", "maxAttempts", "area", "evidencePolicies", "on", "maxTransitions"]);
32126
- var KNOWN_POLICY_FIELDS = /* @__PURE__ */ new Set(["kind", "minProducers", "eligibleAgents", "acceptedStatuses", "degradation"]);
32127
- var KNOWN_TRANSITION_FIELDS = /* @__PURE__ */ new Set(["target", "maxTransitions"]);
32128
- function compareCodeUnits6(left, right) {
32129
- return left < right ? -1 : left > right ? 1 : 0;
32130
- }
32131
- function asObject2(value) {
32132
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
32133
- }
32134
- function asString(value) {
32135
- return typeof value === "string" ? value : void 0;
32136
- }
32137
- function normalizeIdentifier(raw) {
32138
- return raw.toLocaleLowerCase("en-US").replace(/[^a-z0-9_-]+/g, "-").replace(/[-_]{2,}/g, "-").replace(/^[-_]+/, "").replace(/[-_]+$/, "").replace(/^(?=[0-9])/, "id-");
32139
- }
32140
- function pointerEscape2(segment) {
32141
- const escaped = segment.replace(/~/g, "~0").replace(/\//g, "~1");
32142
- if (escaped.length <= 200) return escaped;
32143
- const digest = createHash13("sha256").update(segment, "utf8").digest("hex").slice(0, 8);
32144
- return `${escaped.slice(0, 180)}~digest-${digest}`;
32145
- }
32146
- function elide(raw, max = 120) {
32147
- return raw.length <= max ? raw : `${raw.slice(0, max - 15)}\u2026[${raw.length}]`;
32148
- }
32149
- function keyFragment(raw) {
32150
- const full = normalizeIdentifier(raw) || "unnamed";
32151
- const normalized = full.length > 96 ? `${full.slice(0, 96)}-${full.length}` : full;
32152
- const digest = createHash13("sha256").update(raw, "utf8").digest("hex").slice(0, 8);
32153
- return `${normalized}-${digest}`;
32154
- }
32155
- function recordUnmapped(plan, sourcePath, pointer, value, sensitive) {
32156
- const digestInput = sensitive ? { redacted: true, bytes: Buffer.byteLength(kxmCanonicalJson(value === void 0 ? null : value), "utf8") } : value === void 0 ? null : value;
32157
- plan.unmapped.push({
32158
- sourcePath,
32159
- jsonPointer: pointer,
32160
- valueSha256: sha256Of(kxmCanonicalJson(digestInput)),
32161
- sensitive
32162
- });
32163
- }
32164
- function recordUnknownFields(plan, sourcePath, pointer, record, known) {
32165
- for (const key of Object.keys(record).sort(compareCodeUnits6)) {
32166
- if (!known.has(key)) recordUnmapped(plan, sourcePath, `${pointer}/${pointerEscape2(key)}`, record[key], false);
32167
- }
32168
- }
32169
- function mapIdentity(plan, sourcePath, raw, kind, taken, decisions, dropPointer, dropValue) {
32170
- const normalized = normalizeIdentifier(raw);
32171
- const usable = (candidate) => IDENTIFIER2.test(candidate) && candidate.length <= 64;
32172
- const adopt = (candidate) => {
32173
- const foldedCandidate = candidate.toLocaleLowerCase("en-US");
32174
- const priorCandidate = taken.get(foldedCandidate);
32175
- if (priorCandidate !== void 0 && priorCandidate !== raw) return { outcome: "taken" };
32176
- if (priorCandidate === raw) return { outcome: "duplicate" };
32177
- taken.set(foldedCandidate, raw);
32178
- plan.renames.push({ from: elide(raw), to: candidate, kind });
32179
- return { outcome: "adopted", id: candidate };
32180
- };
32181
- const reportDuplicate = () => {
32182
- const decided = resolveDecision(
32183
- plan,
32184
- `identity-duplicate:${kind}:${keyFragment(raw)}`,
32185
- "unsupported",
32186
- sourcePath,
32187
- `${kind} name ${JSON.stringify(elide(raw, 200))} is declared more than once; confirm the duplicate definition is dropped`,
32188
- ["drop"],
32189
- decisions
32190
- );
32191
- recordUnmapped(plan, sourcePath, dropPointer ?? `/duplicates/${pointerEscape2(raw)}`, dropValue ?? raw, false);
32192
- return decided === "drop" ? { status: "dropped" } : { status: "pending" };
32193
- };
32194
- if (!normalized || !usable(normalized)) {
32195
- const supplied = resolveDecision(
32196
- plan,
32197
- `identity:${kind}:${keyFragment(raw)}`,
32198
- "identity",
32199
- sourcePath,
32200
- `${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a KXM identifier; supply a decision with the target identifier`,
32201
- ["<identifier>"],
32202
- decisions
32203
- );
32204
- if (typeof supplied === "string" && usable(supplied)) {
32205
- const adopted = adopt(supplied);
32206
- if (adopted.outcome === "adopted") return { status: "adopted", id: adopted.id };
32207
- if (adopted.outcome === "duplicate") return reportDuplicate();
32208
- plan.ambiguities.push({
32209
- key: `identity:${kind}:${keyFragment(raw)}`,
32210
- category: "identity",
32211
- sourcePath,
32212
- message: `decision-supplied identifier ${JSON.stringify(elide(supplied, 200))} for ${kind} ${JSON.stringify(elide(raw, 200))} collides with another migrated identity`,
32213
- allowedValues: ["<identifier>"]
32214
- });
32215
- }
32216
- return { status: "pending" };
32217
- }
32218
- const folded = normalized.toLocaleLowerCase("en-US");
32219
- const prior = taken.get(folded);
32220
- if (prior && prior !== raw) {
32221
- const supplied = resolveDecision(
32222
- plan,
32223
- `identity-collision:${kind}:${folded}-${keyFragment(raw)}`,
32224
- "identity",
32225
- sourcePath,
32226
- `${kind} names ${JSON.stringify(elide(prior, 200))} and ${JSON.stringify(elide(raw, 200))} collide after normalization; supply a distinct identifier for ${JSON.stringify(elide(raw, 200))}`,
32227
- ["<identifier>"],
32228
- decisions
32229
- );
32230
- if (typeof supplied === "string" && usable(supplied)) {
32231
- const adopted = adopt(supplied);
32232
- if (adopted.outcome === "adopted") return { status: "adopted", id: adopted.id };
32233
- if (adopted.outcome === "duplicate") return reportDuplicate();
32234
- plan.ambiguities.push({
32235
- key: `identity-collision:${kind}:${folded}-${keyFragment(raw)}`,
32236
- category: "identity",
32237
- sourcePath,
32238
- message: `decision-supplied identifier ${JSON.stringify(elide(supplied, 200))} for ${kind} ${JSON.stringify(elide(raw, 200))} collides with another migrated identity`,
32239
- allowedValues: ["<identifier>"]
32240
- });
32241
- }
32242
- return { status: "pending" };
32243
- }
32244
- if (prior === raw) return reportDuplicate();
32245
- taken.set(folded, raw);
32246
- if (normalized !== raw && !plan.renames.some((rename) => rename.kind === kind && rename.from === raw)) {
32247
- plan.renames.push({ from: elide(raw), to: normalized, kind });
32248
- }
32249
- return { status: "adopted", id: normalized };
32250
- }
32251
- function decisionValueAllowed(key, value, allowed) {
32252
- if (value === void 0) return false;
32253
- if (allowed.some((candidate) => candidate === "<identifier>")) {
32254
- return typeof value === "string" && IDENTIFIER2.test(value) && value.length <= 64;
32255
- }
32256
- if (allowed.some((candidate) => candidate === "<provider/model>")) {
32257
- if (typeof value !== "string") return false;
32258
- const separator = value.indexOf("/");
32259
- const provider = separator > 0 ? normalizeIdentifier(value.slice(0, separator)) : "";
32260
- const modelId2 = separator > 0 ? value.slice(separator + 1) : "";
32261
- return IDENTIFIER2.test(provider) && provider.length <= 64 && modelId2.length >= 1 && modelId2.length <= 200;
32262
- }
32263
- if (key.startsWith("backedge:")) {
32264
- return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 100;
32265
- }
32266
- if (key.startsWith("budget:")) {
32267
- return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 1e3;
32268
- }
32269
- if (key.startsWith("coordinator:") || key.startsWith("producer:")) {
32270
- if (allowed.some((candidate) => candidate === value)) return true;
32271
- return allowed.length >= 64 && typeof value === "string" && IDENTIFIER2.test(value) && value.length <= 64;
32272
- }
32273
- return allowed.some((candidate) => candidate === value);
32274
- }
32275
- function resolveDecision(plan, key, category, sourcePath, message, allowedValues, decisions) {
32276
- plan.decisionKeys.add(key);
32277
- plan.decisionAllowedValues.set(key, allowedValues);
32278
- if (Object.hasOwn(decisions, key)) {
32279
- const value = decisions[key];
32280
- if (decisionValueAllowed(key, value, allowedValues)) return value;
32281
- if (!plan.invalidDecisions.includes(key)) plan.invalidDecisions.push(key);
32282
- }
32283
- if (!plan.ambiguities.some((ambiguity) => ambiguity.key === key)) {
32284
- plan.ambiguities.push({ key, category, sourcePath, message, allowedValues });
32285
- }
32286
- return void 0;
32287
- }
32288
- function convertAgentsRoster(plan, source, decisions, agentNames) {
32289
- const agents = /* @__PURE__ */ new Map();
32290
- const models = /* @__PURE__ */ new Map();
32291
- const rawNames = /* @__PURE__ */ new Map();
32292
- const pendingRawNames = /* @__PURE__ */ new Set();
32293
- const modelNames = /* @__PURE__ */ new Map();
32294
- let identityPending = false;
32295
- const root = asObject2(source.value);
32296
- if (!root) {
32297
- resolveDecision(
32298
- plan,
32299
- `unsupported:${source.path}:/`,
32300
- "unsupported",
32301
- source.path,
32302
- "agents.json must be a JSON object with an agents array; confirm it is dropped from conversion",
32303
- ["drop"],
32304
- decisions
32305
- );
32306
- return { agents, models, rawNames, pendingRawNames, identityPending };
32307
- }
32308
- recordUnknownFields(plan, source.path, "", root, /* @__PURE__ */ new Set(["schema", "project", "host", "agents", "ownership"]));
32309
- if (root.ownership !== void 0) recordUnmapped(plan, source.path, "/ownership", root.ownership, false);
32310
- if (root.host !== void 0) recordUnmapped(plan, source.path, "/host", root.host, false);
32311
- if (root.project !== void 0) recordUnmapped(plan, source.path, "/project", root.project, false);
32312
- if (root.schema !== void 0 && root.schema !== "kxm.agents.v1") recordUnmapped(plan, source.path, "/schema", root.schema, false);
32313
- const list = Array.isArray(root.agents) ? root.agents : [];
32314
- for (const [index, entry] of list.entries()) {
32315
- const pointer = `/agents/${index}`;
32316
- const record = asObject2(entry);
32317
- if (!record) {
32318
- recordUnmapped(plan, source.path, pointer, entry, false);
32319
- continue;
32320
- }
32321
- recordUnknownFields(plan, source.path, pointer, record, KNOWN_AGENT_FIELDS);
32322
- const name = asString(record.name);
32323
- const kind = asString(record.kind) ?? "agent";
32324
- const driver = asString(record.driver) ?? "ai";
32325
- if (!name || kind !== "agent" || driver !== "ai") {
32326
- resolveDecision(
32327
- plan,
32328
- `unsupported:${source.path}:${pointer}`,
32329
- "unsupported",
32330
- source.path,
32331
- `roster entry ${index} (${name === void 0 ? "unnamed" : elide(name, 200)}) has kind ${elide(kind, 64)}/driver ${elide(driver, 64)}; only agent/ai entries convert losslessly \u2014 confirm the entry is dropped`,
32332
- ["drop"],
32333
- decisions
32334
- );
32335
- recordUnmapped(plan, source.path, pointer, record, false);
32336
- continue;
32337
- }
32338
- resolveDecision(
32339
- plan,
32340
- `permission:${keyFragment(name)}`,
32341
- "permission",
32342
- source.path,
32343
- `approve the narrowed tool/repository/network ceiling for agent ${elide(name, 200)}`,
32344
- ["approve"],
32345
- decisions
32346
- );
32347
- const agentIdentity = mapIdentity(plan, source.path, name, "agent", agentNames, decisions, pointer, record);
32348
- if (agentIdentity.status === "pending") {
32349
- identityPending = true;
32350
- pendingRawNames.add(name);
32351
- }
32352
- if (agentIdentity.status !== "adopted") continue;
32353
- const id = agentIdentity.id;
32354
- const agent = {
32355
- schema: "kxm.agent.v1",
32356
- purpose: asString(record.purpose) ?? `Migrated legacy agent ${elide(name, 200)}.`
32357
- };
32358
- const model = asString(record.model);
32359
- if (model) {
32360
- const applyModel = (candidate) => {
32361
- const separator = candidate.indexOf("/");
32362
- if (separator <= 0) return false;
32363
- const provider = normalizeIdentifier(candidate.slice(0, separator));
32364
- const modelId2 = candidate.slice(separator + 1);
32365
- if (IDENTIFIER2.test(provider) && provider.length <= 64 && modelId2.length >= 1 && modelId2.length <= 200) {
32366
- agent.model = { provider, model: modelId2 };
32367
- return true;
32368
- }
32369
- return false;
32370
- };
32371
- if (!applyModel(model)) {
32372
- const supplied = resolveDecision(
32373
- plan,
32374
- `model:${keyFragment(name)}`,
32375
- "identity",
32376
- source.path,
32377
- `agent ${elide(name, 200)} model ${JSON.stringify(elide(model, 200))} does not map to a provider identifier + model id pair; supply <provider>/<model>`,
32378
- ["<provider/model>"],
32379
- decisions
32380
- );
32381
- if (typeof supplied === "string" && supplied !== model) {
32382
- applyModel(supplied);
32383
- } else if (typeof supplied !== "string") {
32384
- recordUnmapped(plan, source.path, `${pointer}/model`, model, false);
32385
- }
32386
- }
32387
- }
32388
- const thinking = asString(record.thinking);
32389
- if (thinking) {
32390
- const selector = asObject2(agent.model);
32391
- if (selector && typeof selector.profile !== "string") {
32392
- const profileIdentity = mapIdentity(plan, source.path, `${id}-primary`, "model", modelNames, decisions);
32393
- const profileId = profileIdentity.status === "adopted" ? profileIdentity.id : void 0;
32394
- if (profileId) {
32395
- const profile = {
32396
- schema: "kxm.model.v1",
32397
- provider: selector.provider,
32398
- model: selector.model,
32399
- thinking
32400
- };
32401
- models.set(profileId, profile);
32402
- agent.model = { profile: profileId };
32403
- }
32404
- } else {
32405
- recordUnmapped(plan, source.path, `${pointer}/thinking`, thinking, false);
32406
- }
32407
- }
32408
- agent.tools = { preset: "workspace-writer" };
32409
- agent.defaultRepositoryAccess = "none";
32410
- agent.network = "provider-only";
32411
- plan.permissionChanges.push({
32412
- sourcePath: source.path,
32413
- targetPath: `.kxm/agents/${id}.yaml`,
32414
- direction: "unknown",
32415
- summary: `agent ${elide(name, 200)}: legacy workers used launch-time tool flags the converter cannot observe; migrated ceiling is workspace-writer tools, no repository access, provider-only network`,
32416
- decisionKey: `permission:${keyFragment(name)}`
32417
- });
32418
- agents.set(id, agent);
32419
- if (!rawNames.has(name)) rawNames.set(name, id);
32420
- }
32421
- return { agents, models, rawNames, pendingRawNames, identityPending };
32422
- }
32423
- var IMPLEMENTED_GATES = /* @__PURE__ */ new Set(["test", "scm-delivery"]);
32424
- function convertGatesRoster(plan, source, decisions) {
32425
- const root = asObject2(source.value);
32426
- if (!root) {
32427
- resolveDecision(
32428
- plan,
32429
- `unsupported:${source.path}:/`,
32430
- "unsupported",
32431
- source.path,
32432
- "gates.json must be a JSON object with a gates array; confirm it is dropped from conversion",
32433
- ["drop"],
32434
- decisions
32435
- );
32436
- return;
32437
- }
32438
- recordUnknownFields(plan, source.path, "", root, /* @__PURE__ */ new Set(["schema", "gates"]));
32439
- if (root.schema !== void 0 && root.schema !== "kxm.gates.v1") recordUnmapped(plan, source.path, "/schema", root.schema, false);
32440
- const list = Array.isArray(root.gates) ? root.gates : [];
32441
- for (const [index, entry] of list.entries()) {
32442
- const pointer = `/gates/${index}`;
32443
- const record = asObject2(entry);
32444
- if (!record) {
32445
- recordUnmapped(plan, source.path, pointer, entry, false);
32446
- continue;
32447
- }
32448
- recordUnknownFields(plan, source.path, pointer, record, KNOWN_GATE_FIELDS);
32449
- const name = asString(record.name) ?? `gate-${index}`;
32450
- if (!IMPLEMENTED_GATES.has(name)) {
32451
- resolveDecision(
32452
- plan,
32453
- `gate:${keyFragment(name)}`,
32454
- "unsupported",
32455
- source.path,
32456
- `gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in KXM; it is preserved in the migration report only`,
32457
- ["report-only"],
32458
- decisions
32459
- );
32460
- recordUnmapped(plan, source.path, pointer, entry, false);
32461
- }
32462
- }
32463
- }
32464
- function mapStageRef(context, raw) {
32465
- return context.renamesByKind.get(raw) ?? normalizeIdentifier(raw);
32466
- }
32467
- function convertTransition(plan, source, context, stageId, stageKey, outcome, rawOutcome, rawValue, decisions, stagePointer) {
32468
- const pointer = `${stagePointer}/on/${pointerEscape2(rawOutcome)}`;
32469
- const rule = typeof rawValue === "string" ? { target: rawValue } : asObject2(rawValue);
32470
- if (!rule) {
32471
- recordUnmapped(plan, source.path, pointer, rawValue, false);
32472
- return void 0;
32473
- }
32474
- if (typeof rawValue !== "string") recordUnknownFields(plan, source.path, pointer, rule, KNOWN_TRANSITION_FIELDS);
32475
- const target = asString(rule.target);
32476
- if (!target) {
32477
- recordUnmapped(plan, source.path, pointer, rawValue, false);
32478
- return void 0;
32479
- }
32480
- const sourceIndex = context.stageIds.indexOf(stageId);
32481
- if (target === "$terminal") {
32482
- const chosen = resolveDecision(
32483
- plan,
32484
- `terminal:${context.workflowKey}:${stageKey}:${outcome}`,
32485
- "terminal-status",
32486
- source.path,
32487
- `legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the KXM terminal status (legacy semantics completed the run even on failure outcomes)`,
32488
- outcome === "passed" ? ["completed"] : ["completed", "failed", "cancelled"],
32489
- decisions
32490
- );
32491
- const status = typeof chosen === "string" && ["completed", "failed", "cancelled"].includes(chosen) ? chosen : "completed";
32492
- const objectRule2 = asObject2(rawValue);
32493
- const result = { target: "$terminal", terminalStatus: status };
32494
- if (typeof objectRule2?.maxTransitions === "number") {
32495
- if (Number.isInteger(objectRule2.maxTransitions) && objectRule2.maxTransitions >= 1 && objectRule2.maxTransitions <= 100) {
32496
- result.maxTransitions = objectRule2.maxTransitions;
32497
- } else {
32498
- recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, objectRule2.maxTransitions, false);
32499
- }
32500
- }
32501
- return result;
32502
- }
32503
- const targetId = mapStageRef(context, target);
32504
- const targetIndex = context.stageIds.indexOf(targetId);
32505
- if (targetIndex < 0) {
32506
- resolveDecision(
32507
- plan,
32508
- `transition-target:${context.workflowKey}:${stageKey}:${outcome}`,
32509
- "identity",
32510
- source.path,
32511
- `transition target ${JSON.stringify(elide(target, 200))} is not a stage of workflow ${context.workflowId}; confirm the edge is dropped`,
32512
- ["drop"],
32513
- decisions
32514
- );
32515
- recordUnmapped(plan, source.path, pointer, rawValue, false);
32516
- return void 0;
32517
- }
32518
- const objectRule = asObject2(rawValue);
32519
- let explicitBudget;
32520
- if (typeof objectRule?.maxTransitions === "number") {
32521
- if (Number.isInteger(objectRule.maxTransitions) && objectRule.maxTransitions >= 1 && objectRule.maxTransitions <= 100) {
32522
- explicitBudget = objectRule.maxTransitions;
32523
- } else {
32524
- recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, objectRule.maxTransitions, false);
32525
- }
32526
- }
32527
- const isBackEdge = targetIndex <= sourceIndex;
32528
- if (isBackEdge && explicitBudget === void 0) {
32529
- const chosen = resolveDecision(
32530
- plan,
32531
- `backedge:${context.workflowKey}:${stageKey}:${outcome}`,
32532
- "transition-budget",
32533
- source.path,
32534
- `back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy; KXM requires maxTransitions (1-100)`,
32535
- [2, 3, 4, 5],
32536
- decisions
32537
- );
32538
- const budget = typeof chosen === "number" && Number.isInteger(chosen) && chosen >= 1 && chosen <= 100 ? chosen : 2;
32539
- return { target: targetId, maxTransitions: budget };
32540
- }
32541
- if (explicitBudget !== void 0) return { target: targetId, maxTransitions: explicitBudget };
32542
- return targetId;
32543
- }
32544
- function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, pendingAgentRawNames, rosterIdentityPending, workflowNames) {
32545
- const workflows = /* @__PURE__ */ new Map();
32546
- const list = Array.isArray(source.value) ? source.value : [source.value];
32547
- for (const [definitionIndex, entry] of list.entries()) {
32548
- const definition = asObject2(entry);
32549
- const basePointer = Array.isArray(source.value) ? `/${definitionIndex}` : "";
32550
- if (!definition) {
32551
- recordUnmapped(plan, source.path, basePointer || "/", entry, false);
32552
- continue;
32553
- }
32554
- recordUnknownFields(plan, source.path, basePointer, definition, KNOWN_WORKFLOW_FIELDS);
32555
- const fileStem = source.path.slice(source.path.lastIndexOf("/") + 1).replace(/\.json$/u, "");
32556
- const rawId = asString(definition.id) ?? `${fileStem}-${definitionIndex}`;
32557
- const workflowIdentity = mapIdentity(plan, source.path, rawId, "workflow", workflowNames, decisions, basePointer || "/", definition);
32558
- if (workflowIdentity.status === "dropped") continue;
32559
- const workflowId = workflowIdentity.status === "adopted" ? workflowIdentity.id : `preview-${(normalizeIdentifier(rawId) || "unnamed").slice(0, 46).replace(/[-_]+$/u, "")}-${createHash13("sha256").update(`${rawId}#${source.path}#${definitionIndex}`, "utf8").digest("hex").slice(0, 8)}`;
32560
- const workflowKey = keyFragment(rawId);
32561
- for (const field of ["source", "project", "event", "filter", "delivery", "ttlMs", "promptTemplate"]) {
32562
- if (definition[field] !== void 0) recordUnmapped(plan, source.path, `${basePointer}/${field}`, definition[field], false);
32563
- }
32564
- for (const field of ["secret", "signalSecret", "secretEnv", "signalSecretEnv"]) {
32565
- if (definition[field] !== void 0) {
32566
- recordUnmapped(plan, source.path, `${basePointer}/${field}`, definition[field], true);
32567
- resolveDecision(
32568
- plan,
32569
- `secret:${workflowKey}:${field}`,
32570
- "secret-reference",
32571
- source.path,
32572
- `workflow ${workflowId} field ${field} configures a webhook secret; KXM workflows never embed secrets \u2014 confirm the field is dropped and re-granted through scoped secret references when the trigger surface lands`,
32573
- ["drop"],
32574
- decisions
32575
- );
32576
- }
32577
- }
32578
- const rawTarget = asString(definition.target);
32579
- const normalizedTarget = rawTarget ? normalizeIdentifier(rawTarget) : void 0;
32580
- let stepAgent = rawTarget !== void 0 ? agentRawNames.get(rawTarget) : void 0;
32581
- if (!stepAgent && rawTarget !== void 0 && pendingAgentRawNames.has(rawTarget)) {
32582
- stepAgent = void 0;
32583
- } else if (!stepAgent && rawTarget !== void 0) {
32584
- const foldedTarget = rawTarget.toLocaleLowerCase("en-US");
32585
- for (const [rawName, id] of agentRawNames) {
32586
- if (rawName.toLocaleLowerCase("en-US") === foldedTarget) {
32587
- stepAgent = id;
32588
- break;
32589
- }
32590
- }
32591
- }
32592
- if (!stepAgent && agentRawNames.size === 0 && normalizedTarget && agentIds.has(normalizedTarget)) {
32593
- stepAgent = normalizedTarget;
32594
- }
32595
- const targetIsPendingAgent = rawTarget !== void 0 && [...pendingAgentRawNames].some((pending) => pending === rawTarget || pending.toLocaleLowerCase("en-US") === rawTarget.toLocaleLowerCase("en-US"));
32596
- if (!stepAgent && targetIsPendingAgent) {
32597
- stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
32598
- }
32599
- if (!stepAgent) {
32600
- if (agentIds.size === 0 && rosterIdentityPending) {
32601
- stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
32602
- } else if (agentIds.size === 0) {
32603
- const dropped = resolveDecision(
32604
- plan,
32605
- `coordinator:${workflowKey}`,
32606
- "identity",
32607
- source.path,
32608
- `workflow ${workflowId} target ${JSON.stringify(rawTarget === void 0 ? "" : elide(rawTarget, 200))} matches no migrated agent and the roster is empty; confirm the workflow is dropped`,
32609
- ["drop"],
32610
- decisions
32611
- );
32612
- if (dropped === "drop") continue;
32613
- stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
32614
- } else {
32615
- const chosen = resolveDecision(
32616
- plan,
32617
- `coordinator:${workflowKey}`,
32618
- "identity",
32619
- source.path,
32620
- `workflow ${workflowId} target ${JSON.stringify(rawTarget === void 0 ? "" : elide(rawTarget, 200))} is not a migrated agent; choose the roster agent that executes its steps`,
32621
- [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64),
32622
- decisions
32623
- );
32624
- if (typeof chosen === "string" && agentIds.has(chosen)) {
32625
- stepAgent = chosen;
32626
- if (rawTarget) plan.renames.push({ from: elide(rawTarget), to: chosen, kind: "agent" });
32627
- } else {
32628
- if (chosen !== void 0 && !plan.invalidDecisions.includes(`coordinator:${workflowKey}`)) {
32629
- plan.invalidDecisions.push(`coordinator:${workflowKey}`);
32630
- }
32631
- if (chosen !== void 0 && !plan.ambiguities.some((ambiguity) => ambiguity.key === `coordinator:${workflowKey}`)) {
32632
- plan.ambiguities.push({
32633
- key: `coordinator:${workflowKey}`,
32634
- category: "identity",
32635
- sourcePath: source.path,
32636
- message: `decision value ${JSON.stringify(typeof chosen === "string" ? elide(chosen, 200) : chosen)} for workflow ${workflowId} is not a migrated agent`,
32637
- allowedValues: [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64)
32638
- });
32639
- }
32640
- stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
32641
- }
32642
- }
32643
- }
32644
- const rawStages = Array.isArray(definition.stages) ? definition.stages : [];
32645
- const stageIds = [];
32646
- const stageRename = /* @__PURE__ */ new Map();
32647
- const stepIdByIndex = /* @__PURE__ */ new Map();
32648
- const stageKeyByRaw = /* @__PURE__ */ new Map();
32649
- const droppedStageIndexes = /* @__PURE__ */ new Set();
32650
- const takenSteps = /* @__PURE__ */ new Map();
32651
- for (const [stageIndex, stageEntry] of rawStages.entries()) {
32652
- const stage = asObject2(stageEntry);
32653
- if (!stage) {
32654
- recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stageEntry, false);
32655
- droppedStageIndexes.add(stageIndex);
32656
- continue;
32657
- }
32658
- const rawStageId = asString(stage.id);
32659
- if (!rawStageId) {
32660
- recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stage, false);
32661
- droppedStageIndexes.add(stageIndex);
32662
- continue;
32663
- }
32664
- const stepIdentity = mapIdentity(plan, source.path, rawStageId, "step", takenSteps, decisions, `${basePointer}/stages/${stageIndex}`, stage);
32665
- if (stepIdentity.status === "dropped") {
32666
- droppedStageIndexes.add(stageIndex);
32667
- continue;
32668
- }
32669
- const stepId = stepIdentity.status === "adopted" ? stepIdentity.id : `preview-${(normalizeIdentifier(rawStageId) || "unnamed").slice(0, 46).replace(/[-_]+$/u, "")}-${createHash13("sha256").update(`${rawStageId}#${stageIndex}`, "utf8").digest("hex").slice(0, 8)}`;
32670
- const stepKey = keyFragment(rawStageId);
32671
- stageKeyByRaw.set(rawStageId, stepKey);
32672
- if (!asString(stage.instructions)) {
32673
- resolveDecision(
32674
- plan,
32675
- `instructions:${workflowKey}:${stepKey}`,
32676
- "unsupported",
32677
- source.path,
32678
- `stage ${stepId} has no instructions; KXM agent steps require executable instructions \u2014 confirm the stage is dropped`,
32679
- ["drop"],
32680
- decisions
32681
- );
32682
- recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stage, false);
32683
- droppedStageIndexes.add(stageIndex);
32684
- continue;
32685
- }
32686
- if (!stageRename.has(rawStageId)) stageRename.set(rawStageId, stepId);
32687
- stepIdByIndex.set(stageIndex, stepId);
32688
- stageIds.push(stepId);
32689
- }
32690
- const context = { workflowId, workflowKey, stageIds, renamesByKind: stageRename };
32691
- const steps = [];
32692
- for (const [stageIndex, stageEntry] of rawStages.entries()) {
32693
- if (droppedStageIndexes.has(stageIndex)) continue;
32694
- const stage = asObject2(stageEntry);
32695
- if (!stage) continue;
32696
- const rawStageId = asString(stage.id);
32697
- if (!rawStageId) continue;
32698
- const stepId = stepIdByIndex.get(stageIndex);
32699
- if (!stepId) continue;
32700
- const stepKey = stageKeyByRaw.get(rawStageId) ?? keyFragment(rawStageId);
32701
- const pointer = `${basePointer}/stages/${stageIndex}`;
32702
- recordUnknownFields(plan, source.path, pointer, stage, KNOWN_STAGE_FIELDS);
32703
- const label = asString(stage.label);
32704
- const instructions = asString(stage.instructions);
32705
- if (!instructions) continue;
32706
- const step = {
32707
- id: stepId,
32708
- kind: "agent",
32709
- agent: stepAgent
32710
- };
32711
- if (label) step.description = label;
32712
- let maxAttempts = 3;
32713
- if (typeof stage.maxAttempts === "number" && Number.isInteger(stage.maxAttempts) && stage.maxAttempts >= 1 && stage.maxAttempts <= 20) {
32714
- maxAttempts = stage.maxAttempts;
32715
- } else if (stage.maxAttempts !== void 0) {
32716
- recordUnmapped(plan, source.path, `${pointer}/maxAttempts`, stage.maxAttempts, false);
32717
- }
32718
- step.maxAttempts = maxAttempts;
32719
- step.instructions = instructions;
32720
- const requiredEvidence = [];
32721
- const policyProducers = /* @__PURE__ */ new Set();
32722
- let policyProducerMinimum = 0;
32723
- const rawEvidence = Array.isArray(stage.requiredEvidence) ? stage.requiredEvidence : [];
32724
- const seenKeys = /* @__PURE__ */ new Set();
32725
- for (const [evidenceIndex, evidenceEntry] of rawEvidence.entries()) {
32726
- const rawKey = asString(evidenceEntry);
32727
- if (!rawKey) {
32728
- recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
32729
- continue;
32730
- }
32731
- const key = normalizeIdentifier(rawKey);
32732
- if (!IDENTIFIER2.test(key) || key.length > 64) {
32733
- recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
32734
- continue;
32735
- }
32736
- if (seenKeys.has(key)) {
32737
- recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
32738
- continue;
32739
- }
32740
- if (key !== rawKey) plan.renames.push({ from: elide(rawKey), to: key, kind: "evidence" });
32741
- seenKeys.add(key);
32742
- requiredEvidence.push({ key, kind: "assignment-result" });
32743
- }
32744
- const policies = asObject2(stage.evidencePolicies);
32745
- if (policies) {
32746
- const seenPolicies = /* @__PURE__ */ new Set();
32747
- for (const [rawPolicyKey, policyEntry] of Object.entries(policies).sort(([left], [right]) => compareCodeUnits6(left, right))) {
32748
- const policy = asObject2(policyEntry);
32749
- const policyKey = normalizeIdentifier(rawPolicyKey);
32750
- if (seenPolicies.has(policyKey)) {
32751
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
32752
- continue;
32753
- }
32754
- seenPolicies.add(policyKey);
32755
- const requirement = requiredEvidence.find((candidate) => candidate.key === policyKey);
32756
- if (!policy || !requirement) {
32757
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
32758
- continue;
32759
- }
32760
- recordUnknownFields(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policy, KNOWN_POLICY_FIELDS);
32761
- let minProducers = 1;
32762
- if (typeof policy.minProducers === "number" && Number.isInteger(policy.minProducers) && policy.minProducers >= 1 && policy.minProducers <= 16) {
32763
- minProducers = policy.minProducers;
32764
- } else if (policy.minProducers !== void 0) {
32765
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/minProducers`, policy.minProducers, false);
32766
- }
32767
- if (policy.eligibleAgents !== void 0 && !Array.isArray(policy.eligibleAgents)) {
32768
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents`, policy.eligibleAgents, false);
32769
- }
32770
- const eligible = Array.isArray(policy.eligibleAgents) ? policy.eligibleAgents : [];
32771
- const eligibleIds = [];
32772
- for (const [eligibleIndex, candidate] of eligible.entries()) {
32773
- const rawName = asString(candidate);
32774
- if (!rawName) {
32775
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents/${eligibleIndex}`, candidate, false);
32776
- continue;
32777
- }
32778
- const rawBound = pendingAgentRawNames.has(rawName) ? void 0 : agentRawNames.get(rawName) ?? [...agentRawNames].find(([candidateName]) => candidateName.toLocaleLowerCase("en-US") === rawName.toLocaleLowerCase("en-US"))?.[1];
32779
- if (rawBound) {
32780
- if (!eligibleIds.includes(rawBound)) eligibleIds.push(rawBound);
32781
- continue;
32782
- }
32783
- if ([...pendingAgentRawNames].some((pending) => pending === rawName || pending.toLocaleLowerCase("en-US") === rawName.toLocaleLowerCase("en-US"))) {
32784
- const previewId = normalizeIdentifier(rawName);
32785
- if (IDENTIFIER2.test(previewId) && previewId.length <= 64 && !eligibleIds.includes(previewId)) {
32786
- eligibleIds.push(previewId);
32787
- }
32788
- continue;
32789
- }
32790
- const normalized = normalizeIdentifier(rawName);
32791
- if (agentRawNames.size === 0 && agentIds.has(normalized)) {
32792
- if (!eligibleIds.includes(normalized)) eligibleIds.push(normalized);
32793
- continue;
32794
- }
32795
- if (agentIds.size === 0) {
32796
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents/${eligibleIndex}`, candidate, false);
32797
- continue;
32798
- }
32799
- const mapped = resolveDecision(
32800
- plan,
32801
- `producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`,
32802
- "evidence-policy",
32803
- source.path,
32804
- `evidence policy on ${stepId}.${policyKey} names producer ${JSON.stringify(elide(rawName, 200))} which is not a migrated agent; choose the roster agent that takes this producer role`,
32805
- [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64),
32806
- decisions
32807
- );
32808
- if (typeof mapped === "string" && agentIds.has(mapped)) {
32809
- plan.renames.push({ from: elide(rawName), to: mapped, kind: "agent" });
32810
- if (!eligibleIds.includes(mapped)) eligibleIds.push(mapped);
32811
- } else if (mapped !== void 0) {
32812
- if (!plan.invalidDecisions.includes(`producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`)) {
32813
- plan.invalidDecisions.push(`producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`);
32814
- }
32815
- if (!plan.ambiguities.some((ambiguity) => ambiguity.key === `producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`)) {
32816
- plan.ambiguities.push({
32817
- key: `producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`,
32818
- category: "evidence-policy",
32819
- sourcePath: source.path,
32820
- message: `decision value ${JSON.stringify(typeof mapped === "string" ? elide(mapped, 200) : mapped)} for producer ${JSON.stringify(elide(rawName, 200))} is not a migrated agent`,
32821
- allowedValues: [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64)
32822
- });
32823
- }
32824
- }
32825
- }
32826
- const acceptedStatusesMalformed = policy.acceptedStatuses !== void 0 && !Array.isArray(policy.acceptedStatuses);
32827
- if (acceptedStatusesMalformed) {
32828
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/acceptedStatuses`, policy.acceptedStatuses, false);
32829
- }
32830
- const accepted = acceptedStatusesMalformed ? [] : Array.isArray(policy.acceptedStatuses) ? policy.acceptedStatuses : ["replied"];
32831
- if (Array.isArray(policy.acceptedStatuses) && policy.acceptedStatuses.length === 0) {
32832
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/acceptedStatuses`, policy.acceptedStatuses, false);
32833
- }
32834
- let acceptedStatuses = accepted.length > 0 && accepted.every((status) => status === "replied") ? ["passed"] : void 0;
32835
- if (!acceptedStatuses) {
32836
- const chosen = resolveDecision(
32837
- plan,
32838
- `statuses:${workflowKey}:${stepKey}:${policyKey}`,
32839
- "evidence-policy",
32840
- source.path,
32841
- acceptedStatusesMalformed ? `evidence policy ${policyKey} acceptedStatuses is malformed (not an array) and was preserved in the report; confirm mapping the policy to KXM 'passed'` : `evidence policy ${policyKey} accepted statuses ${JSON.stringify(elide(accepted.map((candidate) => String(candidate)).join(","), 200))} cannot map losslessly; confirm mapping to KXM 'passed'`,
32842
- ["passed"],
32843
- decisions
32844
- );
32845
- if (chosen === "passed") acceptedStatuses = ["passed"];
32846
- }
32847
- if (acceptedStatuses) {
32848
- plan.permissionChanges.push({
32849
- sourcePath: source.path,
32850
- targetPath: `.kxm/workflows/${workflowId}.yaml`,
32851
- direction: "narrowing",
32852
- summary: `evidence ${policyKey} on ${stepId}: legacy peer-reply policy (status 'replied') migrates to assignment-result producer policy requiring 'passed'`,
32853
- decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`
32854
- });
32855
- plan.permissionChanges.push({
32856
- sourcePath: source.path,
32857
- targetPath: `.kxm/workflows/${workflowId}.yaml`,
32858
- direction: "expansion",
32859
- summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so KXM producer evidence stays in scope`,
32860
- decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`
32861
- });
32862
- resolveDecision(
32863
- plan,
32864
- `evidence:${workflowKey}:${stepKey}:${policyKey}`,
32865
- "evidence-policy",
32866
- source.path,
32867
- `approve strengthening ${stepId}.${policyKey} from 'peer replied' to 'peer assignment passed' and widening the step assignment pool to include the producers`,
32868
- ["approve"],
32869
- decisions
32870
- );
32871
- }
32872
- if (eligibleIds.length > 0 && acceptedStatuses) {
32873
- requirement.kind = "assignment-result";
32874
- requirement.producerPolicy = {
32875
- minimumProducers: minProducers,
32876
- eligibleAgents: eligibleIds,
32877
- acceptedStatuses
32878
- };
32879
- for (const producer of eligibleIds) policyProducers.add(producer);
32880
- policyProducerMinimum = Math.max(policyProducerMinimum, minProducers);
32881
- const degradation = asObject2(policy.degradation);
32882
- if (degradation && degradation.minProducers !== void 0) {
32883
- if (typeof degradation.minProducers === "number" && Number.isInteger(degradation.minProducers) && degradation.minProducers >= 1 && degradation.minProducers <= 15 && degradation.minProducers < minProducers) {
32884
- requirement.producerPolicy.degradation = { minimumProducers: degradation.minProducers };
32885
- } else {
32886
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/degradation`, policy.degradation, false);
32887
- }
32888
- }
32889
- } else {
32890
- recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
32891
- }
32892
- }
32893
- }
32894
- if (requiredEvidence.length > 0) step.requiredEvidence = requiredEvidence;
32895
- if (policyProducers.size > 0) {
32896
- const pool = [stepAgent, ...[...policyProducers].filter((candidate) => candidate !== stepAgent).sort(compareCodeUnits6)];
32897
- step.assignments = {
32898
- allowedAgents: pool,
32899
- minimum: 1,
32900
- target: Math.max(1, policyProducerMinimum),
32901
- maximum: pool.length,
32902
- maxParallel: pool.length
32903
- };
32904
- }
32905
- const on = asObject2(stage.on);
32906
- const transitions = {};
32907
- if (on) {
32908
- const seenOutcomes = /* @__PURE__ */ new Set();
32909
- for (const [rawOutcome, rawTransition] of Object.entries(on).sort(([left], [right]) => compareCodeUnits6(left, right))) {
32910
- const outcome = normalizeIdentifier(rawOutcome);
32911
- if (!IDENTIFIER2.test(outcome) || outcome.length > 64) {
32912
- recordUnmapped(plan, source.path, `${pointer}/on/${pointerEscape2(rawOutcome)}`, rawTransition, false);
32913
- continue;
32914
- }
32915
- if (seenOutcomes.has(outcome)) {
32916
- recordUnmapped(plan, source.path, `${pointer}/on/${pointerEscape2(rawOutcome)}`, rawTransition, false);
32917
- continue;
32918
- }
32919
- seenOutcomes.add(outcome);
32920
- if (outcome !== rawOutcome) plan.renames.push({ from: elide(rawOutcome), to: outcome, kind: "outcome" });
32921
- const converted = convertTransition(plan, source, context, stepId, stepKey, outcome, rawOutcome, rawTransition, decisions, pointer);
32922
- if (converted !== void 0) transitions[outcome] = converted;
32923
- }
32924
- if (transitions.passed === void 0) {
32925
- const nextId = stageIds[stageIds.indexOf(stepId) + 1];
32926
- transitions.passed = nextId ?? { target: "$terminal", terminalStatus: "completed" };
32927
- }
32928
- } else {
32929
- const nextId = stageIds[stageIds.indexOf(stepId) + 1];
32930
- transitions.passed = nextId ?? { target: "$terminal", terminalStatus: "completed" };
32931
- }
32932
- step.on = transitions;
32933
- if (typeof stage.maxTransitions === "number") {
32934
- recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, stage.maxTransitions, false);
32935
- }
32936
- if (stage.area !== void 0) recordUnmapped(plan, source.path, `${pointer}/area`, stage.area, false);
32937
- steps.push(step);
32938
- }
32939
- if (steps.length === 0) {
32940
- resolveDecision(
32941
- plan,
32942
- `stages:${workflowKey}`,
32943
- "unsupported",
32944
- source.path,
32945
- `workflow ${workflowId} produced no convertible steps; confirm it is dropped`,
32946
- ["drop"],
32947
- decisions
32948
- );
32949
- continue;
32950
- }
32951
- const workflow = {
32952
- schema: "kxm.workflow.v1",
32953
- coordinator: stepAgent,
32954
- steps
32955
- };
32956
- if (typeof definition.maxTransitions === "number" && Number.isInteger(definition.maxTransitions) && definition.maxTransitions >= 1 && definition.maxTransitions <= 1e3) {
32957
- workflow.limits = { maxTransitions: definition.maxTransitions };
32958
- } else if (definition.maxTransitions !== void 0) {
32959
- recordUnmapped(plan, source.path, `${basePointer}/maxTransitions`, definition.maxTransitions, false);
32960
- }
32961
- if (workflow.limits === void 0) {
32962
- const hasBackEdge = steps.some((step) => Object.values(asObject2(step.on) ?? {}).some((rule) => {
32963
- const target = typeof rule === "string" ? rule : asObject2(rule)?.target;
32964
- return typeof target === "string" && target !== "$terminal" && stageIds.indexOf(target) <= stageIds.indexOf(String(step.id));
32965
- }));
32966
- if (hasBackEdge) {
32967
- const chosen = resolveDecision(
32968
- plan,
32969
- `budget:${workflowKey}`,
32970
- "transition-budget",
32971
- source.path,
32972
- `workflow ${workflowId} has back-edges but no legacy global maxTransitions; KXM requires limits.maxTransitions (1-1000)`,
32973
- [28],
32974
- decisions
32975
- );
32976
- workflow.limits = { maxTransitions: typeof chosen === "number" && Number.isInteger(chosen) && chosen >= 1 && chosen <= 1e3 ? chosen : 28 };
32977
- }
32978
- }
32979
- for (const oracleField of ["reproOracle", "planHash"]) {
32980
- const oracle = asObject2(definition[oracleField]);
32981
- if (!oracle) continue;
32982
- const oracleStage = asString(oracle.stageId);
32983
- const oracleEvidence = asString(oracle.evidenceKey);
32984
- if (!oracleStage || !oracleEvidence) {
32985
- recordUnmapped(plan, source.path, `${basePointer}/${oracleField}`, definition[oracleField], false);
32986
- continue;
32987
- }
32988
- const mappedStage = context.renamesByKind.get(oracleStage);
32989
- if (!mappedStage) {
32990
- if (!context.stageIds.includes(normalizeIdentifier(oracleStage))) {
32991
- recordUnmapped(plan, source.path, `${basePointer}/${oracleField}`, definition[oracleField], false);
32992
- continue;
32993
- }
32994
- }
32995
- workflow[oracleField] = {
32996
- stageId: mappedStage ?? normalizeIdentifier(oracleStage),
32997
- evidenceKey: normalizeIdentifier(oracleEvidence)
32998
- };
32999
- }
33000
- if (Array.isArray(definition.requirePlanHash)) {
33001
- const mapped = [];
33002
- for (const [requireIndex, candidate] of definition.requirePlanHash.entries()) {
33003
- const rawStage = asString(candidate);
33004
- if (!rawStage) {
33005
- recordUnmapped(plan, source.path, `${basePointer}/requirePlanHash/${requireIndex}`, candidate, false);
33006
- continue;
33007
- }
33008
- const mappedStage = context.renamesByKind.get(rawStage);
33009
- if (!mappedStage && !context.stageIds.includes(normalizeIdentifier(rawStage))) {
33010
- recordUnmapped(plan, source.path, `${basePointer}/requirePlanHash/${requireIndex}`, candidate, false);
33011
- continue;
33012
- }
33013
- mapped.push(mappedStage ?? normalizeIdentifier(rawStage));
33014
- }
33015
- if (mapped.length > 0) workflow.requirePlanHash = [...new Set(mapped)].sort(compareCodeUnits6);
33016
- }
33017
- workflows.set(workflowId, workflow);
33018
- }
33019
- return workflows;
33020
- }
33021
- var PROJECT_ID2 = /^prj_[A-Za-z0-9][A-Za-z0-9_-]{5,127}$/;
33022
- function sortedRecord(map, prefix) {
33023
- return new Map([...map.entries()].sort(([left], [right]) => compareCodeUnits6(left, right)).map(([key, value]) => [`${prefix}${key}.yaml`, value]));
33024
- }
33025
- function migrationGitRoot(start) {
33026
- const root = discoverGitRoot(start);
33027
- if (!root) {
33028
- throw new KxmConfigError([migrateIssue("discovery", "git_root_required", ".", "kxm migrate must run inside the authoritative Git worktree")]);
33029
- }
33030
- return root;
33031
- }
33032
- function planKxmMigration(projectRoot, options = {}) {
33033
- const root = migrationGitRoot(projectRoot);
33034
- const registry = new KxmSchemaRegistry(options.schemasDir);
33035
- const sources = readKxmLegacySources(root);
33036
- if (sources.length === 0) {
33037
- throw new KxmConfigError([migrateIssue("discovery", "legacy_sources_missing", ".kxm/config", "no legacy configuration files found to migrate")]);
33038
- }
33039
- const decisions = options.decisions ?? {};
33040
- const plan = { ambiguities: [], invalidDecisions: [], decisionKeys: /* @__PURE__ */ new Set(), decisionAllowedValues: /* @__PURE__ */ new Map(), unmapped: [], renames: [], permissionChanges: [] };
33041
- const agentNames = /* @__PURE__ */ new Map();
33042
- const workflowNames = /* @__PURE__ */ new Map();
33043
- const agentsSource = sources.find((source) => source.path === ".kxm/config/agents.json");
33044
- const gatesSource = sources.find((source) => source.path === ".kxm/config/gates.json");
33045
- const converted = agentsSource ? convertAgentsRoster(plan, agentsSource, decisions, agentNames) : { agents: /* @__PURE__ */ new Map(), models: /* @__PURE__ */ new Map(), rawNames: /* @__PURE__ */ new Map(), pendingRawNames: /* @__PURE__ */ new Set(), identityPending: false };
33046
- if (!agentsSource) {
33047
- resolveDecision(
33048
- plan,
33049
- "agents-missing",
33050
- "unsupported",
33051
- ".kxm/config/agents.json",
33052
- "no agents.json roster; workflows convert against an empty agent set \u2014 confirm conversion continues",
33053
- ["continue"],
33054
- decisions
33055
- );
33056
- }
33057
- if (gatesSource) convertGatesRoster(plan, gatesSource, decisions);
33058
- const workflows = /* @__PURE__ */ new Map();
33059
- for (const source of sources) {
33060
- if (!source.path.startsWith(".kxm/config/workflows/")) continue;
33061
- const convertedWorkflows = convertWorkflowFile(
33062
- plan,
33063
- source,
33064
- decisions,
33065
- converted.agents,
33066
- converted.rawNames,
33067
- converted.pendingRawNames,
33068
- converted.identityPending,
33069
- workflowNames
33070
- );
33071
- for (const [id, workflow] of convertedWorkflows) workflows.set(id, workflow);
33072
- }
33073
- const projectId = options.projectId ?? `prj_mig${sha256Of(legacySourceDigest(sources)).slice(7, 39)}`;
33074
- if (!PROJECT_ID2.test(projectId)) {
33075
- throw new KxmConfigError([migrateIssue("semantic", "project_id_invalid", ".kxm/project.yaml", "project ID must satisfy the kxm.project.v1 opaque ID grammar and use the prj_ prefix")]);
33076
- }
33077
- const projectName = options.projectName ?? "Migrated legacy project";
33078
- if (projectName.length < 1 || projectName.length > 120 || /[\u0000\r\n]/.test(projectName)) {
33079
- throw new KxmConfigError([migrateIssue("semantic", "project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
33080
- }
33081
- const resources = /* @__PURE__ */ new Map();
33082
- resources.set(".kxm/project.yaml", {
33083
- schema: "kxm.project.v1",
33084
- id: projectId,
33085
- name: projectName,
33086
- ...workflows.size > 0 ? { defaultWorkflow: [...workflows.keys()].sort(compareCodeUnits6)[0] } : {},
33087
- defaultExecutor: "local",
33088
- repositories: [{ id: "control", role: "control", required: true, pathHint: "." }],
33089
- workspace: {
33090
- dirtySnapshot: {
33091
- untracked: "ask",
33092
- dirtySubmodules: "fail"
33093
- }
33094
- }
33095
- });
33096
- resources.set(".kxm/repo/repo.yaml", {
33097
- schema: "kxm.repository.v1",
33098
- projectId,
33099
- repositoryId: "control",
33100
- description: "Authoritative project configuration and repository content.",
33101
- defaultAccess: "write"
33102
- });
33103
- for (const [path4, value] of sortedRecord(converted.agents, ".kxm/agents/")) resources.set(path4, value);
33104
- for (const [path4, value] of sortedRecord(converted.models, ".kxm/models/")) resources.set(path4, value);
33105
- for (const [path4, value] of sortedRecord(workflows, ".kxm/workflows/")) resources.set(path4, value);
33106
- const schemaIssues = [];
33107
- const kindOf = (path4) => path4 === ".kxm/project.yaml" ? "project" : path4.endsWith("repo.yaml") ? "repository" : path4.startsWith(".kxm/agents/") ? "agent" : path4.startsWith(".kxm/models/") ? "model" : "workflow";
33108
- const idOf = (path4) => path4 === ".kxm/project.yaml" || path4.endsWith("repo.yaml") ? void 0 : path4.slice(path4.lastIndexOf("/") + 1, -".yaml".length);
33109
- const semanticResources = /* @__PURE__ */ new Map();
33110
- for (const [path4, value] of [...resources.entries()].sort(([left], [right]) => compareCodeUnits6(left, right))) {
33111
- const kind = kindOf(path4);
33112
- schemaIssues.push(...registry.validate(kind, value, path4));
33113
- const id = idOf(path4);
33114
- semanticResources.set(path4, kind === "repository" ? { kind, id: "control", value } : { kind, ...id === void 0 ? {} : { id }, value });
33115
- }
33116
- if (schemaIssues.length > 0) throw new KxmConfigError(schemaIssues);
33117
- if (plan.ambiguities.length === 0) {
33118
- const semanticIssues = validateKxmResources(semanticResources, options);
33119
- if (semanticIssues.length > 0) throw new KxmConfigError(semanticIssues);
33120
- }
33121
- const planRecord = {
33122
- schema: "kxm.migration-plan.v1",
33123
- projectId,
33124
- projectName,
33125
- sourceDigest: legacySourceDigest(sources),
33126
- sources: sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes })),
33127
- resources: [...resources.keys()].sort(compareCodeUnits6).map((path4) => {
33128
- const bytes = Buffer.from((0, import_yaml12.stringify)(resources.get(path4), { lineWidth: 0 }), "utf8");
33129
- return { path: path4, sha256: sha256Of(bytes), bytes: bytes.byteLength };
33130
- }),
33131
- ambiguities: [...plan.ambiguities].sort((left, right) => compareCodeUnits6(left.key, right.key)).map((ambiguity) => ({
33132
- key: ambiguity.key,
33133
- category: ambiguity.category,
33134
- sourcePath: ambiguity.sourcePath,
33135
- message: ambiguity.message,
33136
- allowedValues: [...ambiguity.allowedValues]
33137
- })),
33138
- unmapped: [...plan.unmapped].sort((left, right) => compareCodeUnits6(left.sourcePath, right.sourcePath) || compareCodeUnits6(left.jsonPointer, right.jsonPointer)).map((entry) => ({ ...entry })),
33139
- renames: [...new Map(plan.renames.map((rename) => [JSON.stringify([rename.kind, rename.from, rename.to]), rename])).values()].sort((left, right) => compareCodeUnits6(left.kind, right.kind) || compareCodeUnits6(left.from, right.from)).map((entry) => ({ ...entry })),
33140
- permissionChanges: [...plan.permissionChanges].sort((left, right) => compareCodeUnits6(left.decisionKey, right.decisionKey)).map((entry) => ({ ...entry })),
33141
- canApply: plan.ambiguities.length === 0
33142
- };
33143
- const planIssues = registry.validateMigrationPlan(planRecord, "kxm.migration-plan.v1");
33144
- if (planIssues.length > 0) throw new KxmConfigError(planIssues);
33145
- return {
33146
- plan: planRecord,
33147
- resources,
33148
- ambiguities: plan.ambiguities,
33149
- decisionKeys: plan.decisionKeys,
33150
- decisionAllowedValues: plan.decisionAllowedValues,
33151
- invalidDecisions: plan.invalidDecisions,
33152
- decisions,
33153
- sources
33154
- };
33155
- }
33156
- function readKxmMigrationDecisions(path4, schemasDir) {
33157
- if (!existsSync23(path4)) {
33158
- throw new KxmConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
33159
- }
33160
- const registry = new KxmSchemaRegistry(schemasDir);
33161
- const value = parseRestrictedYaml2(readFileSync22(path4), path4);
33162
- const issues = registry.validateMigrationDecision(value, path4);
33163
- if (issues.length > 0) throw new KxmConfigError(issues);
33164
- return value;
33165
- }
33166
- function resolutionsOf(decisions) {
33167
- const resolutions = decisions.resolutions;
33168
- if (!resolutions || typeof resolutions !== "object" || Array.isArray(resolutions)) return {};
33169
- return { ...resolutions };
33170
- }
33171
- function syncDirectory3(path4) {
33172
- let descriptor;
33173
- try {
33174
- descriptor = openSync3(path4, "r");
33175
- fsyncSync3(descriptor);
33176
- } catch (error) {
33177
- const code = error.code;
33178
- if (process.platform !== "win32" && code !== "EINVAL" && code !== "ENOTSUP" && code !== "EISDIR") throw error;
33179
- } finally {
33180
- if (descriptor !== void 0) closeSync3(descriptor);
33181
- }
33182
- }
33183
- function writeDurable2(path4, content) {
33184
- const temp = `${path4}.kxm-migration-tmp-${process.pid}-${createHash13("sha256").update(`${path4}${Date.now()}${Math.random()}`, "utf8").digest("hex").slice(0, 12)}`;
33185
- let created = false;
33186
- try {
33187
- const descriptor = openSync3(temp, "wx", 384);
33188
- created = true;
33189
- try {
33190
- writeFileSync18(descriptor, content);
33191
- fsyncSync3(descriptor);
33192
- } finally {
33193
- closeSync3(descriptor);
33194
- }
33195
- renameSync7(temp, path4);
33196
- try {
33197
- chmodSync6(path4, 384);
33198
- } catch {
33199
- }
33200
- syncDirectory3(join26(path4, ".."));
33201
- } finally {
33202
- if (created && existsSync23(temp)) rmSync9(temp, { force: true });
33203
- }
33204
- }
33205
- function applyKxmMigration(projectRoot, options = {}) {
33206
- const root = migrationGitRoot(projectRoot);
33207
- const storeOptions = {
33208
- ...options.localStateRoot === void 0 ? {} : { stateRoot: options.localStateRoot },
33209
- ...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
33210
- };
33211
- const execute = (lock) => {
33212
- const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
33213
- if (existsSync23(receiptAbsolute)) {
33214
- const stat = lstatSync8(receiptAbsolute);
33215
- if (stat.isSymbolicLink() || !stat.isFile()) {
33216
- throw new KxmConfigError([migrateIssue("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
33217
- }
33218
- const existing = loadKxmProject(root, options);
33219
- return {
33220
- action: "already-migrated",
33221
- projectRoot: root,
33222
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33223
- configRevision: existing.configRevision,
33224
- files: []
33225
- };
33226
- }
33227
- const decisionsRecord = options.decisionsFile ? readKxmMigrationDecisions(options.decisionsFile, options.schemasDir) : void 0;
33228
- const decisions = decisionsRecord ? resolutionsOf(decisionsRecord) : options.decisions ?? {};
33229
- const first = planKxmMigration(root, { ...options, decisions });
33230
- if (decisionsRecord) {
33231
- if (decisionsRecord.projectId !== first.plan.projectId) {
33232
- throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectId does not match the recomputed plan")]);
33233
- }
33234
- if (decisionsRecord.projectName !== first.plan.projectName) {
33235
- throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectName does not match the recomputed plan")]);
33236
- }
33237
- if (decisionsRecord.sourceDigest !== first.plan.sourceDigest) {
33238
- throw new KxmConfigError([migrateIssue("semantic", "decision_source_changed", options.decisionsFile ?? "<decisions>", "legacy sources changed after the decisions file was reviewed")]);
33239
- }
33240
- }
33241
- if (Object.keys(decisions).length > 0) {
33242
- const universe = planKxmMigration(root, { ...options, decisions: {} });
33243
- const unknown = [];
33244
- const invalid = [];
33245
- for (const [key, value] of Object.entries(decisions)) {
33246
- if (first.decisionKeys.has(key)) continue;
33247
- const universeAllowed = universe.decisionAllowedValues.get(key);
33248
- if (!universeAllowed) {
33249
- unknown.push(key);
33250
- } else if (!decisionValueAllowed(key, value, universeAllowed)) {
33251
- invalid.push(key);
33252
- }
33253
- }
33254
- if (unknown.length > 0) {
33255
- throw new KxmConfigError(unknown.sort(compareCodeUnits6).map((key) => migrateIssue("semantic", "decision_unknown", key, "decision key does not match any current ambiguity")));
33256
- }
33257
- const allInvalid = [.../* @__PURE__ */ new Set([...invalid, ...first.invalidDecisions])].sort(compareCodeUnits6);
33258
- if (allInvalid.length > 0) {
33259
- throw new KxmConfigError(allInvalid.map((key) => migrateIssue("semantic", "decision_value_invalid", key, "decision value is not one of the plan's allowed values")));
33260
- }
33261
- }
33262
- if (first.ambiguities.length > 0) {
33263
- return { action: "planned", projectRoot: root, files: [], plan: first.plan };
33264
- }
33265
- const files = [...first.resources.entries()].sort(([left], [right]) => compareCodeUnits6(left, right)).map(([path4, value]) => ({ path: path4, bytes: Buffer.from((0, import_yaml12.stringify)(value, { lineWidth: 0 }), "utf8") }));
33266
- const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
33267
- if (collisions.length > 0) {
33268
- throw new KxmConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
33269
- }
33270
- const parentIssues = [];
33271
- for (const file of files) {
33272
- const segments = file.path.split("/");
33273
- let current = root;
33274
- for (const segment of segments.slice(0, -1)) {
33275
- current = join26(current, segment);
33276
- if (!existsSync23(current)) continue;
33277
- const stat = lstatSync8(current);
33278
- if (stat.isSymbolicLink() || !stat.isDirectory()) {
33279
- parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
33280
- break;
33281
- }
33282
- }
33283
- }
33284
- if (parentIssues.length > 0) throw new KxmConfigError(parentIssues);
33285
- if (options.dryRun) {
33286
- return { action: "planned", projectRoot: root, files: files.map((file) => file.path), plan: first.plan };
33287
- }
33288
- if (!lock) throw new Error("project mutation lock is required to apply a migration");
33289
- const written = [];
33290
- try {
33291
- for (const file of files) {
33292
- const absolute = join26(root, ...file.path.split("/"));
33293
- mkdirSync19(join26(absolute, ".."), { recursive: true });
33294
- written.push(absolute);
33295
- writeDurable2(absolute, file.bytes);
33296
- }
33297
- const bundle = loadKxmProject(root, { ...options, allowUnreceiptedLegacyConfig: true });
33298
- const receipt = {
33299
- schema: "kxm.migration-receipt.v1",
33300
- migrationId: `mig_${sha256Of(`${first.plan.sourceDigest}
33301
- ${bundle.configRevision}`).slice(7, 39)}`,
33302
- projectId: String(first.plan.projectId),
33303
- sourceDigest: String(first.plan.sourceDigest),
33304
- decisionDigest: sha256Of(kxmCanonicalJson(decisionsRecord ?? { schema: "kxm.migration-decision.v1", projectId: first.plan.projectId, projectName: first.plan.projectName, sourceDigest: first.plan.sourceDigest, resolutions: decisions })),
33305
- configRevision: bundle.configRevision,
33306
- sources: first.plan.sources,
33307
- resources: files.map((file) => ({ path: file.path, sha256: sha256Of(file.bytes), bytes: file.bytes.byteLength }))
33308
- };
33309
- receipt.receiptSha256 = migrationReceiptSelfHash(receipt);
33310
- const registry = new KxmSchemaRegistry(options.schemasDir);
33311
- const receiptIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
33312
- if (receiptIssues.length > 0) throw new KxmConfigError(receiptIssues);
33313
- written.push(receiptAbsolute);
33314
- writeDurable2(receiptAbsolute, Buffer.from((0, import_yaml12.stringify)(receipt, { lineWidth: 0 }), "utf8"));
33315
- const verified = loadKxmProject(root, options);
33316
- return {
33317
- action: "applied",
33318
- projectRoot: root,
33319
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33320
- configRevision: verified.configRevision,
33321
- files: files.map((file) => file.path),
33322
- plan: first.plan
33323
- };
33324
- } catch (error) {
33325
- for (const absolute of written.reverse()) {
33326
- try {
33327
- rmSync9(absolute, { force: true });
33328
- } catch {
33329
- }
33330
- }
33331
- throw error;
33332
- }
33333
- };
33334
- if (options.dryRun) return execute(void 0);
33335
- return withKxmLocalBindingLock(root, storeOptions, (lock) => execute(lock));
33336
- }
33337
- function verifyKxmMigration(projectRoot, options = {}) {
33338
- const root = migrationGitRoot(projectRoot);
33339
- const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
33340
- if (!existsSync23(receiptAbsolute)) {
33341
- return {
33342
- ok: false,
33343
- projectRoot: root,
33344
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33345
- issues: [migrateIssue("discovery", "migration_receipt_missing", KXM_MIGRATION_RECEIPT_PATH, "no migration receipt exists")]
33346
- };
33347
- }
33348
- try {
33349
- const bundle = loadKxmProject(root, options);
33350
- const receipt = bundle.migrationReceipt;
33351
- if (!receipt) {
33352
- if (legacyConfigFilesAt(root).length === 0) {
33353
- const direct = readKxmMigrationReceipt(root, options);
33354
- return {
33355
- ok: false,
33356
- projectRoot: root,
33357
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33358
- configRevision: bundle.configRevision,
33359
- issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate")]
33360
- };
33361
- }
33362
- return {
33363
- ok: false,
33364
- projectRoot: root,
33365
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33366
- configRevision: bundle.configRevision,
33367
- issues: [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate during project load")]
33368
- };
33369
- }
33370
- const targetIssues = verifyKxmMigrationReceiptTarget(root, receipt, bundle.resources, bundle.configRevision);
33371
- return {
33372
- ok: targetIssues.length === 0,
33373
- projectRoot: root,
33374
- receiptPath: KXM_MIGRATION_RECEIPT_PATH,
33375
- configRevision: bundle.configRevision,
33376
- issues: targetIssues
33377
- };
33378
- } catch (error) {
33379
- if (error instanceof KxmConfigError) {
33380
- return { ok: false, projectRoot: root, receiptPath: KXM_MIGRATION_RECEIPT_PATH, issues: error.issues };
33381
- }
33382
- throw error;
33383
- }
33384
- }
33385
-
33386
31764
  // plugins/kxm/src/cli/project.ts
33387
31765
  var kxmDriveCliSeams = {};
33388
31766
  function initPlanPayload(plan) {
@@ -33480,7 +31858,7 @@ async function cmdKxmInit(runtime, options, postHooks) {
33480
31858
  if (runtime.dryRun) {
33481
31859
  return finishInit(0, `init plan: ${initialized.plan.mode}`);
33482
31860
  }
33483
- const next = initialized.plan.mode === "migrate" ? "legacy state requires reviewed migration; conversion is not available in this implementation slice" : initialized.repairPlan?.issues.length ? "managed-template repair is blocked by conflicts or authority changes; local files were preserved" : "partial or provenance-free KXM state requires explicit repair; no files were overwritten";
31861
+ const next = initialized.plan.mode === "legacy" ? "legacy state is not migrated by this build: initialise a fresh project directory and copy the YAML definitions you want to keep" : initialized.repairPlan?.issues.length ? "managed-template repair is blocked by conflicts or authority changes; local files were preserved" : "partial or provenance-free KXM state requires explicit repair; no files were overwritten";
33484
31862
  return finishInit(1, next);
33485
31863
  } catch (error) {
33486
31864
  if (error instanceof KxmConfigError) {
@@ -33500,141 +31878,11 @@ async function cmdKxmInit(runtime, options, postHooks) {
33500
31878
  return 1;
33501
31879
  }
33502
31880
  }
33503
- async function cmdKxmMigratePlan(runtime) {
33504
- if (runtime.workspaceFlag !== void 0) {
33505
- print(runtime.io, runtime.json, {
33506
- ok: false,
33507
- command: "migrate plan",
33508
- error: "workspace_option_unsupported"
33509
- }, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
33510
- return 2;
33511
- }
33512
- try {
33513
- const result = planKxmMigration(runtime.cwd, {});
33514
- const ambiguities = result.plan.ambiguities ?? [];
33515
- const unmapped = result.plan.unmapped ?? [];
33516
- const payload = {
33517
- ok: result.plan.canApply === true,
33518
- command: "migrate plan",
33519
- plan: result.plan,
33520
- plannedOnly: result.plan.canApply !== true
33521
- };
33522
- if (result.plan.canApply === true) {
33523
- print(runtime.io, runtime.json, payload, `migration plan: ${ambiguities.length} ambiguities, ${unmapped.length} preserved fields; ready to apply`);
33524
- return 0;
33525
- }
33526
- print(
33527
- runtime.io,
33528
- runtime.json,
33529
- payload,
33530
- `migration plan requires ${ambiguities.length} reviewed decision(s):
33531
- ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).join("\n")}`
33532
- );
33533
- return 1;
33534
- } catch (error) {
33535
- if (error instanceof KxmConfigError) {
33536
- print(runtime.io, runtime.json, { ok: false, command: "migrate plan", error: "migration_plan_failed", issues: error.issues }, `migration plan failed: ${error.message}`);
33537
- return 1;
33538
- }
33539
- print(runtime.io, runtime.json, { ok: false, command: "migrate plan", error: "migration_plan_io_failed" }, "migration plan failed because a local filesystem operation did not complete");
33540
- return 1;
33541
- }
33542
- }
33543
- async function cmdKxmMigrateApply(runtime, options) {
33544
- if (runtime.workspaceFlag !== void 0) {
33545
- print(runtime.io, runtime.json, {
33546
- ok: false,
33547
- command: "migrate apply",
33548
- error: "workspace_option_unsupported"
33549
- }, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
33550
- return 2;
33551
- }
33552
- try {
33553
- const result = applyKxmMigration(runtime.cwd, {
33554
- ...options.decisions?.trim() ? { decisionsFile: options.decisions.trim() } : {},
33555
- ...options.projectId?.trim() ? { projectId: options.projectId.trim() } : {},
33556
- ...options.name?.trim() ? { projectName: options.name.trim() } : {},
33557
- localStateRoot: kxmUserStateRoot({ env: runtime.env }),
33558
- dryRun: runtime.dryRun
33559
- });
33560
- const payload = {
33561
- ok: result.action !== "planned" || runtime.dryRun === true && result.plan?.canApply === true,
33562
- command: "migrate apply",
33563
- action: result.action,
33564
- files: result.files,
33565
- ...result.configRevision ? { configRevision: result.configRevision } : {},
33566
- ...result.receiptPath ? { receiptPath: result.receiptPath } : {},
33567
- plannedOnly: result.action === "planned"
33568
- };
33569
- if (result.action === "applied") {
33570
- print(runtime.io, runtime.json, payload, `migration applied: ${result.files.length} resources installed, receipt at ${result.receiptPath ?? ""}`);
33571
- return 0;
33572
- }
33573
- if (result.action === "already-migrated") {
33574
- print(runtime.io, runtime.json, payload, "migration receipt already exists; nothing to apply");
33575
- return 0;
33576
- }
33577
- if (runtime.dryRun && result.plan?.canApply === true) {
33578
- print(runtime.io, runtime.json, payload, `migration dry run: ${result.files.length} resources would be installed`);
33579
- return 0;
33580
- }
33581
- const ambiguities = result.plan?.ambiguities ?? [];
33582
- print(
33583
- runtime.io,
33584
- runtime.json,
33585
- { ...payload, plan: result.plan },
33586
- `migration blocked by ${ambiguities.length} unresolved decision(s); review 'kxm migrate plan' and pass --decisions:
33587
- ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).join("\n")}`
33588
- );
33589
- return 1;
33590
- } catch (error) {
33591
- if (error instanceof KxmConfigError) {
33592
- print(runtime.io, runtime.json, { ok: false, command: "migrate apply", error: "migration_apply_failed", issues: error.issues }, `migration apply failed: ${error.message}`);
33593
- return 1;
33594
- }
33595
- print(runtime.io, runtime.json, { ok: false, command: "migrate apply", error: "migration_apply_io_failed" }, "migration apply failed because a local filesystem operation did not complete");
33596
- return 1;
33597
- }
33598
- }
33599
- async function cmdKxmMigrateVerify(runtime) {
33600
- if (runtime.workspaceFlag !== void 0) {
33601
- print(runtime.io, runtime.json, {
33602
- ok: false,
33603
- command: "migrate verify",
33604
- error: "workspace_option_unsupported"
33605
- }, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
33606
- return 2;
33607
- }
33608
- let result;
33609
- try {
33610
- result = verifyKxmMigration(runtime.cwd, {});
33611
- } catch (error) {
33612
- if (error instanceof KxmConfigError) {
33613
- print(runtime.io, runtime.json, { ok: false, command: "migrate verify", error: "migration_verify_failed", issues: error.issues }, `migration verification failed: ${error.message}`);
33614
- return 1;
33615
- }
33616
- print(runtime.io, runtime.json, { ok: false, command: "migrate verify", error: "migration_verify_io_failed" }, "migration verification failed because a local filesystem operation did not complete");
33617
- return 1;
33618
- }
33619
- const payload = {
33620
- ok: result.ok,
33621
- command: "migrate verify",
33622
- ...result.configRevision ? { configRevision: result.configRevision } : {},
33623
- issues: result.issues
33624
- };
33625
- if (result.ok) {
33626
- print(runtime.io, runtime.json, payload, `migration receipt verified: legacy sources unchanged, target bundle matches ${result.configRevision ?? ""}`);
33627
- return 0;
33628
- }
33629
- print(runtime.io, runtime.json, payload, `migration verification failed:
33630
- ${result.issues.map((issue3) => ` - ${issue3.file}: ${issue3.code}: ${issue3.message}`).join("\n")}`);
33631
- return 1;
33632
- }
33633
31881
  async function cmdBackup(runtime, options) {
33634
31882
  try {
33635
31883
  const { manifest, outDir } = createBackup({
33636
31884
  projectRoot: runtime.cwd,
33637
- ...options.out ? { outDir: resolve20(runtime.cwd, options.out) } : {}
31885
+ ...options.out ? { outDir: resolve19(runtime.cwd, options.out) } : {}
33638
31886
  });
33639
31887
  const payload = {
33640
31888
  ok: true,
@@ -33646,7 +31894,7 @@ async function cmdBackup(runtime, options) {
33646
31894
  const summary = [
33647
31895
  `Created SQLite backup with ${manifest.stores.length} store(s):`,
33648
31896
  ...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
33649
- `Manifest: ${join27(outDir, "manifest.json")}`
31897
+ `Manifest: ${join26(outDir, "manifest.json")}`
33650
31898
  ].join("\n");
33651
31899
  print(runtime.io, runtime.json, payload, summary);
33652
31900
  return 0;
@@ -33661,7 +31909,7 @@ async function cmdBackup(runtime, options) {
33661
31909
  }
33662
31910
  async function cmdRestore(runtime, manifestArg) {
33663
31911
  try {
33664
- const result = restoreBackup(resolve20(runtime.cwd, manifestArg), {
31912
+ const result = restoreBackup(resolve19(runtime.cwd, manifestArg), {
33665
31913
  projectRoot: runtime.cwd
33666
31914
  });
33667
31915
  const payload = {
@@ -33866,7 +32114,7 @@ function parseDriveWaitTimeoutMs(raw) {
33866
32114
  return value;
33867
32115
  }
33868
32116
  function sleepMs(ms) {
33869
- return new Promise((resolve31) => setTimeout(resolve31, ms));
32117
+ return new Promise((resolve30) => setTimeout(resolve30, ms));
33870
32118
  }
33871
32119
  function driveWaitCompleted(drive) {
33872
32120
  return drive?.verified === true && drive.receipt?.settlement?.kind === "terminal" && drive.receipt.settlement.status === "completed";
@@ -34011,7 +32259,7 @@ async function selectInventoryModel(runtime, requested) {
34011
32259
  if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
34012
32260
  runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
34013
32261
  const rl = createInterface2({ input: process.stdin, output: process.stderr });
34014
- const answer = await new Promise((resolve31) => rl.once("line", resolve31));
32262
+ const answer = await new Promise((resolve30) => rl.once("line", resolve30));
34015
32263
  rl.close();
34016
32264
  const index = Number.parseInt(answer.trim(), 10) - 1;
34017
32265
  return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
@@ -34037,7 +32285,7 @@ async function cmdModelsScreen(runtime) {
34037
32285
  return 2;
34038
32286
  }
34039
32287
  const rl = createInterface2({ input: process.stdin, output: process.stderr });
34040
- const ask = (q2) => new Promise((resolve31) => rl.question(q2, resolve31));
32288
+ const ask = (q2) => new Promise((resolve30) => rl.question(q2, resolve30));
34041
32289
  try {
34042
32290
  while (true) {
34043
32291
  const policy = loadRoutePolicy(runtime.dirs.workdir);
@@ -34345,12 +32593,12 @@ async function cmdStudioLayout(runtime, workflowPath) {
34345
32593
  const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
34346
32594
  let filePath = workflowPath;
34347
32595
  if (!filePath) {
34348
- filePath = resolve21(projectRoot, ".kxm", "workflows", "default.yaml");
32596
+ filePath = resolve20(projectRoot, ".kxm", "workflows", "default.yaml");
34349
32597
  }
34350
32598
  let yamlContent;
34351
32599
  let workflowId = "default";
34352
- if (existsSync24(filePath)) {
34353
- yamlContent = readFileSync23(filePath, "utf8");
32600
+ if (existsSync23(filePath)) {
32601
+ yamlContent = readFileSync22(filePath, "utf8");
34354
32602
  } else {
34355
32603
  yamlContent = `schema: kxm.workflow.v1
34356
32604
  description: Feature implementation workflow
@@ -34390,7 +32638,7 @@ steps:
34390
32638
  maxTransitions: 2
34391
32639
  `;
34392
32640
  }
34393
- const parsedYaml = (0, import_yaml13.parse)(yamlContent);
32641
+ const parsedYaml = (0, import_yaml12.parse)(yamlContent);
34394
32642
  const plan = compileKxmWorkflow({ id: workflowId, value: parsedYaml });
34395
32643
  const layout = generateStudioLayout(plan);
34396
32644
  print(runtime.io, runtime.json, { ok: true, command: "studio layout", layout }, JSON.stringify(layout, null, 2));
@@ -34423,16 +32671,16 @@ async function cmdStudioServe(runtime, options) {
34423
32671
  sessionToken,
34424
32672
  planProvider: () => {
34425
32673
  try {
34426
- const wfDir = join28(runtime.cwd, ".kxm", "workflows");
34427
- const defaultPath = join28(wfDir, "default.yaml");
34428
- let targetPath = existsSync24(defaultPath) ? defaultPath : void 0;
34429
- if (!targetPath && existsSync24(wfDir)) {
32674
+ const wfDir = join27(runtime.cwd, ".kxm", "workflows");
32675
+ const defaultPath = join27(wfDir, "default.yaml");
32676
+ let targetPath = existsSync23(defaultPath) ? defaultPath : void 0;
32677
+ if (!targetPath && existsSync23(wfDir)) {
34430
32678
  const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
34431
- if (yml) targetPath = join28(wfDir, yml);
32679
+ if (yml) targetPath = join27(wfDir, yml);
34432
32680
  }
34433
- if (targetPath && existsSync24(targetPath)) {
34434
- const raw = readFileSync23(targetPath, "utf8");
34435
- const parsed = (0, import_yaml13.parse)(raw);
32681
+ if (targetPath && existsSync23(targetPath)) {
32682
+ const raw = readFileSync22(targetPath, "utf8");
32683
+ const parsed = (0, import_yaml12.parse)(raw);
34436
32684
  const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
34437
32685
  return compileKxmWorkflow({ id: wfId, value: parsed });
34438
32686
  }
@@ -34481,14 +32729,14 @@ Press Ctrl+C to stop.
34481
32729
  }
34482
32730
 
34483
32731
  // plugins/kxm/src/cli/context-skills.ts
34484
- import { readFileSync as readFileSync26 } from "node:fs";
34485
- import { join as join32, relative as relative5 } from "node:path";
32732
+ import { readFileSync as readFileSync25 } from "node:fs";
32733
+ import { join as join31, relative as relative5 } from "node:path";
34486
32734
 
34487
32735
  // plugins/kxm/src/memory.ts
34488
- var import_yaml14 = __toESM(require_dist(), 1);
32736
+ var import_yaml13 = __toESM(require_dist(), 1);
34489
32737
  import { randomUUID as randomUUID12 } from "node:crypto";
34490
- import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync9, readFileSync as readFileSync24, writeFileSync as writeFileSync19 } from "node:fs";
34491
- import { extname as extname2, join as join29, resolve as resolve22 } from "node:path";
32738
+ import { existsSync as existsSync24, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync18 } from "node:fs";
32739
+ import { extname as extname2, join as join28, resolve as resolve21 } from "node:path";
34492
32740
  var MEMORY_SCHEMA = "kxm.memory.v1";
34493
32741
  var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
34494
32742
  var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
@@ -34521,7 +32769,7 @@ function parseFrontmatter(content) {
34521
32769
  }
34522
32770
  function parseMemoryRecord(raw, filename = "memory.md") {
34523
32771
  const { frontmatter, body } = parseFrontmatter(raw);
34524
- const data = (0, import_yaml14.parse)(frontmatter);
32772
+ const data = (0, import_yaml13.parse)(frontmatter);
34525
32773
  if (!data || typeof data !== "object" || Array.isArray(data)) {
34526
32774
  throw new Error(`invalid YAML frontmatter in ${filename}`);
34527
32775
  }
@@ -34601,7 +32849,7 @@ function formatMemoryRecord(record) {
34601
32849
  lifecycle: record.lifecycle,
34602
32850
  evidenceRefs: record.evidenceRefs
34603
32851
  };
34604
- const yamlText = (0, import_yaml14.stringify)(frontmatter).trim();
32852
+ const yamlText = (0, import_yaml13.stringify)(frontmatter).trim();
34605
32853
  const bodyText = record.body?.trim() ?? "";
34606
32854
  return bodyText ? `---
34607
32855
  ${yamlText}
@@ -34614,21 +32862,21 @@ ${yamlText}
34614
32862
  `;
34615
32863
  }
34616
32864
  function memoryDirectories(repoRoot) {
34617
- const root = resolve22(repoRoot);
34618
- const memoryDir = join29(root, ".kxm", "memory");
34619
- const candidatesDir = join29(memoryDir, "candidates");
32865
+ const root = resolve21(repoRoot);
32866
+ const memoryDir = join28(root, ".kxm", "memory");
32867
+ const candidatesDir = join28(memoryDir, "candidates");
34620
32868
  return { memoryDir, candidatesDir };
34621
32869
  }
34622
32870
  function loadAuthoredMemory(repoRoot) {
34623
32871
  const { memoryDir } = memoryDirectories(repoRoot);
34624
- if (!existsSync25(memoryDir)) return [];
32872
+ if (!existsSync24(memoryDir)) return [];
34625
32873
  const records = [];
34626
32874
  const entries = readdirSync9(memoryDir, { withFileTypes: true });
34627
32875
  for (const entry of entries) {
34628
32876
  if (entry.isFile() && extname2(entry.name) === ".md") {
34629
- const fullPath = join29(memoryDir, entry.name);
32877
+ const fullPath = join28(memoryDir, entry.name);
34630
32878
  try {
34631
- const text = readFileSync24(fullPath, "utf8");
32879
+ const text = readFileSync23(fullPath, "utf8");
34632
32880
  const record = parseMemoryRecord(text, entry.name);
34633
32881
  if (record.lifecycle === "active") {
34634
32882
  records.push(record);
@@ -34642,7 +32890,7 @@ function loadAuthoredMemory(repoRoot) {
34642
32890
  }
34643
32891
  function createMemoryNote(repoRoot, summary, options = {}) {
34644
32892
  const { candidatesDir } = memoryDirectories(repoRoot);
34645
- mkdirSync20(candidatesDir, { recursive: true });
32893
+ mkdirSync19(candidatesDir, { recursive: true });
34646
32894
  const scope = options.scope ?? "project";
34647
32895
  if (!VALID_SCOPES.has(scope)) {
34648
32896
  throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
@@ -34667,8 +32915,8 @@ function createMemoryNote(repoRoot, summary, options = {}) {
34667
32915
  evidenceRefs: [],
34668
32916
  ...options.body ? { body: options.body.trim() } : {}
34669
32917
  };
34670
- const targetPath = join29(candidatesDir, `${id}.md`);
34671
- writeFileSync19(targetPath, formatMemoryRecord(record), "utf8");
32918
+ const targetPath = join28(candidatesDir, `${id}.md`);
32919
+ writeFileSync18(targetPath, formatMemoryRecord(record), "utf8");
34672
32920
  return { record, path: targetPath };
34673
32921
  }
34674
32922
  function generateMemoryBrief(repoRoot) {
@@ -34704,8 +32952,8 @@ function formatHarnessMemoryBlock(records) {
34704
32952
  }
34705
32953
  function updateHarnessDocument(filePath, block, defaultHeader) {
34706
32954
  let original = "";
34707
- if (existsSync25(filePath)) {
34708
- original = readFileSync24(filePath, "utf8");
32955
+ if (existsSync24(filePath)) {
32956
+ original = readFileSync23(filePath, "utf8");
34709
32957
  }
34710
32958
  let updated = "";
34711
32959
  if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
@@ -34733,25 +32981,25 @@ ${block}
34733
32981
  `;
34734
32982
  }
34735
32983
  if (updated !== original) {
34736
- writeFileSync19(filePath, updated, "utf8");
32984
+ writeFileSync18(filePath, updated, "utf8");
34737
32985
  return true;
34738
32986
  }
34739
32987
  return false;
34740
32988
  }
34741
32989
  function syncHarnessMemory(repoRoot) {
34742
- const root = resolve22(repoRoot);
32990
+ const root = resolve21(repoRoot);
34743
32991
  const records = loadAuthoredMemory(root);
34744
32992
  const block = formatHarnessMemoryBlock(records);
34745
32993
  const updated = [];
34746
32994
  const created = [];
34747
- const agentsPath = join29(root, "AGENTS.md");
32995
+ const agentsPath = join28(root, "AGENTS.md");
34748
32996
  const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
34749
- const agentsExisted = existsSync25(agentsPath);
32997
+ const agentsExisted = existsSync24(agentsPath);
34750
32998
  if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
34751
32999
  if (agentsExisted) updated.push("AGENTS.md");
34752
33000
  else created.push("AGENTS.md");
34753
33001
  }
34754
- const claudePath = join29(root, "CLAUDE.md");
33002
+ const claudePath = join28(root, "CLAUDE.md");
34755
33003
  const claudeHeader = `# KXM (Claude)
34756
33004
 
34757
33005
  Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
@@ -34763,12 +33011,12 @@ rotation, not a sole writer. If \`grok\` is logged out, never bill Grok through
34763
33011
  use a relief route Tracking **admits**, or stop and name the limits hit. Your reviews are
34764
33012
  artifacts, not hub \`peer-reply\` evidence.
34765
33013
  `;
34766
- const claudeExisted = existsSync25(claudePath);
33014
+ const claudeExisted = existsSync24(claudePath);
34767
33015
  if (updateHarnessDocument(claudePath, block, claudeHeader)) {
34768
33016
  if (claudeExisted) updated.push("CLAUDE.md");
34769
33017
  else created.push("CLAUDE.md");
34770
33018
  }
34771
- const geminiPath = join29(root, "GEMINI.md");
33019
+ const geminiPath = join28(root, "GEMINI.md");
34772
33020
  const geminiHeader = `# KXM (Gemini / Antigravity)
34773
33021
 
34774
33022
  Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
@@ -34779,7 +33027,7 @@ Google goes through the \`antigravity\` **Pi provider** (Tracking \u2192 Decided
34779
33027
  Current admissions come from Tracking and \`kxm harness list\`. Starting rotation
34780
33028
  remains Grok.
34781
33029
  `;
34782
- const geminiExisted = existsSync25(geminiPath);
33030
+ const geminiExisted = existsSync24(geminiPath);
34783
33031
  if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
34784
33032
  if (geminiExisted) updated.push("GEMINI.md");
34785
33033
  else created.push("GEMINI.md");
@@ -34788,10 +33036,10 @@ remains Grok.
34788
33036
  }
34789
33037
 
34790
33038
  // plugins/kxm/src/skills.ts
34791
- var import_yaml15 = __toESM(require_dist(), 1);
34792
- import { createHash as createHash14 } from "node:crypto";
34793
- import { existsSync as existsSync26, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync25, renameSync as renameSync8, rmSync as rmSync10, statSync as statSync3, writeFileSync as writeFileSync20 } from "node:fs";
34794
- import { join as join30 } from "node:path";
33039
+ var import_yaml14 = __toESM(require_dist(), 1);
33040
+ import { createHash as createHash13 } from "node:crypto";
33041
+ import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync7, rmSync as rmSync9, statSync as statSync3, writeFileSync as writeFileSync19 } from "node:fs";
33042
+ import { join as join29 } from "node:path";
34795
33043
  var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
34796
33044
  var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
34797
33045
  var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
@@ -34814,7 +33062,7 @@ var SkillLifecycleError = class extends Error {
34814
33062
  }
34815
33063
  };
34816
33064
  function skillContentSha256(content) {
34817
- return createHash14("sha256").update(content, "utf8").digest("hex");
33065
+ return createHash13("sha256").update(content, "utf8").digest("hex");
34818
33066
  }
34819
33067
  function skillIdFor(name, contentSha256) {
34820
33068
  const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
@@ -34832,7 +33080,7 @@ function parseSkillFrontmatter(content) {
34832
33080
  return { frontmatter: null, body: content };
34833
33081
  }
34834
33082
  try {
34835
- const parsed = (0, import_yaml15.parse)(rawFm);
33083
+ const parsed = (0, import_yaml14.parse)(rawFm);
34836
33084
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
34837
33085
  return { frontmatter: parsed, body: rawBody };
34838
33086
  }
@@ -34885,48 +33133,48 @@ var SkillLifecycle = class {
34885
33133
  this.allowOptimizationEvals = options.allowOptimizationEvals === true;
34886
33134
  }
34887
33135
  dir(state) {
34888
- return join30(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
33136
+ return join29(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
34889
33137
  }
34890
33138
  historyFile(id) {
34891
- return join30(this.root, "history", `${id}.jsonl`);
33139
+ return join29(this.root, "history", `${id}.jsonl`);
34892
33140
  }
34893
33141
  paths(state, id) {
34894
- const dir = join30(this.dir(state), id);
34895
- return { dir, metadata: join30(dir, "metadata.json"), skill: join30(dir, "SKILL.md") };
33142
+ const dir = join29(this.dir(state), id);
33143
+ return { dir, metadata: join29(dir, "metadata.json"), skill: join29(dir, "SKILL.md") };
34896
33144
  }
34897
33145
  appendHistory(id, record) {
34898
- mkdirSync21(join30(this.root, "history"), { recursive: true });
33146
+ mkdirSync20(join29(this.root, "history"), { recursive: true });
34899
33147
  const line = `${JSON.stringify(record)}
34900
33148
  `;
34901
- if (existsSync26(this.historyFile(id))) {
34902
- const existing = readFileSync25(this.historyFile(id), "utf8");
33149
+ if (existsSync25(this.historyFile(id))) {
33150
+ const existing = readFileSync24(this.historyFile(id), "utf8");
34903
33151
  const lines = existing.split("\n").filter((entry) => entry.trim());
34904
- writeFileSync20(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
33152
+ writeFileSync19(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
34905
33153
  } else {
34906
- writeFileSync20(this.historyFile(id), line);
33154
+ writeFileSync19(this.historyFile(id), line);
34907
33155
  }
34908
33156
  }
34909
33157
  history(id) {
34910
33158
  const file = this.historyFile(id);
34911
- if (!existsSync26(file)) return [];
34912
- return readFileSync25(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
33159
+ if (!existsSync25(file)) return [];
33160
+ return readFileSync24(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
34913
33161
  }
34914
33162
  readMetadata(state, id) {
34915
33163
  const { metadata } = this.paths(state, id);
34916
- if (!existsSync26(metadata)) {
33164
+ if (!existsSync25(metadata)) {
34917
33165
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
34918
33166
  }
34919
- return JSON.parse(readFileSync25(metadata, "utf8"));
33167
+ return JSON.parse(readFileSync24(metadata, "utf8"));
34920
33168
  }
34921
33169
  move(from, to, id) {
34922
- const fromDir = join30(this.dir(from), id);
34923
- const toDir = join30(this.dir(to), id);
34924
- if (!existsSync26(fromDir)) {
33170
+ const fromDir = join29(this.dir(from), id);
33171
+ const toDir = join29(this.dir(to), id);
33172
+ if (!existsSync25(fromDir)) {
34925
33173
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
34926
33174
  }
34927
- mkdirSync21(this.dir(to), { recursive: true });
34928
- if (existsSync26(toDir)) rmSync10(toDir, { recursive: true, force: true });
34929
- renameSync8(fromDir, toDir);
33175
+ mkdirSync20(this.dir(to), { recursive: true });
33176
+ if (existsSync25(toDir)) rmSync9(toDir, { recursive: true, force: true });
33177
+ renameSync7(fromDir, toDir);
34930
33178
  }
34931
33179
  /** Submit a new skill candidate. Content is redacted of secret material at
34932
33180
  * creation; the ID is derived from name + content hash. */
@@ -34968,7 +33216,7 @@ var SkillLifecycle = class {
34968
33216
  const contentSha256 = skillContentSha256(content);
34969
33217
  const id = skillIdFor(name, contentSha256);
34970
33218
  const { dir, metadata, skill } = this.paths("candidate", id);
34971
- if (existsSync26(metadata)) {
33219
+ if (existsSync25(metadata)) {
34972
33220
  throw new SkillLifecycleError(
34973
33221
  "skill_candidate_exists",
34974
33222
  `identical candidate ${id} already exists; changed behavior requires changed content`
@@ -34987,9 +33235,9 @@ var SkillLifecycle = class {
34987
33235
  createdAt: this.now(),
34988
33236
  ...input.supersedes ? { supersedes: input.supersedes } : {}
34989
33237
  };
34990
- mkdirSync21(dir, { recursive: true });
34991
- writeFileSync20(skill, content);
34992
- writeFileSync20(metadata, `${JSON.stringify(record, null, 2)}
33238
+ mkdirSync20(dir, { recursive: true });
33239
+ writeFileSync19(skill, content);
33240
+ writeFileSync19(metadata, `${JSON.stringify(record, null, 2)}
34993
33241
  `);
34994
33242
  this.appendHistory(id, { schema: "kxm.skill-history-event.v1", event: "candidate_created", by: createdBy, supersedes: input.supersedes, at: record.createdAt });
34995
33243
  return record;
@@ -35078,18 +33326,18 @@ var SkillLifecycle = class {
35078
33326
  };
35079
33327
  const candidatePaths = this.paths("candidate", candidateId);
35080
33328
  const promotedPaths = this.paths("promoted", candidateId);
35081
- mkdirSync21(promotedPaths.dir, { recursive: true });
35082
- const skillContent = readFileSync25(candidatePaths.skill, "utf8");
35083
- const metadataContent = readFileSync25(candidatePaths.metadata, "utf8");
35084
- writeFileSync20(promotedPaths.skill, skillContent);
35085
- writeFileSync20(promotedPaths.metadata, metadataContent);
35086
- const patchesDir = join30(this.root, "patches");
35087
- mkdirSync21(patchesDir, { recursive: true });
35088
- const patchPath = join30(patchesDir, `${candidateId}.patch`);
33329
+ mkdirSync20(promotedPaths.dir, { recursive: true });
33330
+ const skillContent = readFileSync24(candidatePaths.skill, "utf8");
33331
+ const metadataContent = readFileSync24(candidatePaths.metadata, "utf8");
33332
+ writeFileSync19(promotedPaths.skill, skillContent);
33333
+ writeFileSync19(promotedPaths.metadata, metadataContent);
33334
+ const patchesDir = join29(this.root, "patches");
33335
+ mkdirSync20(patchesDir, { recursive: true });
33336
+ const patchPath = join29(patchesDir, `${candidateId}.patch`);
35089
33337
  const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
35090
33338
  const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
35091
33339
  const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
35092
- writeFileSync20(patchPath, patch, "utf8");
33340
+ writeFileSync19(patchPath, patch, "utf8");
35093
33341
  this.appendHistory(candidateId, record);
35094
33342
  return { ...metadata, patch, patchPath };
35095
33343
  }
@@ -35113,7 +33361,7 @@ var SkillLifecycle = class {
35113
33361
  verify(state, id) {
35114
33362
  const metadata = this.readMetadata(state, id);
35115
33363
  const { skill } = this.paths(state, id);
35116
- const content = readFileSync25(skill, "utf8");
33364
+ const content = readFileSync24(skill, "utf8");
35117
33365
  if (skillContentSha256(content) !== metadata.contentSha256) {
35118
33366
  throw new SkillLifecycleError(
35119
33367
  "skill_integrity_violation",
@@ -35131,7 +33379,7 @@ var SkillLifecycle = class {
35131
33379
  }
35132
33380
  list(state) {
35133
33381
  const dir = this.dir(state);
35134
- if (!existsSync26(dir)) return [];
33382
+ if (!existsSync25(dir)) return [];
35135
33383
  const ids = readdirSorted(dir);
35136
33384
  return ids.map((id) => {
35137
33385
  try {
@@ -35144,7 +33392,7 @@ var SkillLifecycle = class {
35144
33392
  read(state, id) {
35145
33393
  const metadata = this.readMetadata(state, id);
35146
33394
  const { skill } = this.paths(state, id);
35147
- return { metadata, content: readFileSync25(skill, "utf8") };
33395
+ return { metadata, content: readFileSync24(skill, "utf8") };
35148
33396
  }
35149
33397
  };
35150
33398
  function boundedList(value, field) {
@@ -35159,18 +33407,18 @@ function boundedList(value, field) {
35159
33407
  return [...new Set(refs)];
35160
33408
  }
35161
33409
  function readdirSorted(dir) {
35162
- return readdirSync10(dir).filter((entry) => statSync3(join30(dir, entry)).isDirectory()).sort();
33410
+ return readdirSync10(dir).filter((entry) => statSync3(join29(dir, entry)).isDirectory()).sort();
35163
33411
  }
35164
33412
 
35165
33413
  // plugins/kxm/src/wiki.ts
35166
- import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync21 } from "node:fs";
35167
- import { join as join31 } from "node:path";
33414
+ import { mkdirSync as mkdirSync21, writeFileSync as writeFileSync20 } from "node:fs";
33415
+ import { join as join30 } from "node:path";
35168
33416
  function writeCompiledWiki(root, wiki) {
35169
33417
  const written = [];
35170
33418
  for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
35171
- const absolute = join31(root, relativePath);
35172
- mkdirSync22(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
35173
- writeFileSync21(absolute, content);
33419
+ const absolute = join30(root, relativePath);
33420
+ mkdirSync21(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
33421
+ writeFileSync20(absolute, content);
35174
33422
  written.push(relativePath);
35175
33423
  }
35176
33424
  return written;
@@ -35336,7 +33584,7 @@ function skillStateFromFlag(value) {
35336
33584
  throw new Error(`invalid skill state ${value}`);
35337
33585
  }
35338
33586
  function skillsRoot(runtime) {
35339
- return join32(runtime.dirs.workdir, ".kxm", "skills");
33587
+ return join31(runtime.dirs.workdir, ".kxm", "skills");
35340
33588
  }
35341
33589
  function csv(value) {
35342
33590
  if (!value) return void 0;
@@ -35353,7 +33601,7 @@ async function cmdSkillsCreate(runtime, options) {
35353
33601
  const metadata = lifecycle.create({
35354
33602
  name: options.name,
35355
33603
  description: options.description ?? "",
35356
- content: readFileSync26(options.file, "utf8"),
33604
+ content: readFileSync25(options.file, "utf8"),
35357
33605
  createdBy: options.createdBy,
35358
33606
  sources: {
35359
33607
  runIds: csv(options.run) ?? [],
@@ -35511,8 +33759,8 @@ async function cmdMemorySync(runtime) {
35511
33759
 
35512
33760
  // plugins/kxm/src/cli/hub.ts
35513
33761
  import { randomUUID as randomUUID14 } from "node:crypto";
35514
- import { existsSync as existsSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync32, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
35515
- import { join as join42, resolve as resolve25 } from "node:path";
33762
+ import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, readdirSync as readdirSync12, rmSync as rmSync10, writeFileSync as writeFileSync23 } from "node:fs";
33763
+ import { join as join41, resolve as resolve24 } from "node:path";
35516
33764
 
35517
33765
  // node_modules/marked/lib/marked.esm.js
35518
33766
  function M() {
@@ -39674,10 +37922,10 @@ var TuiBase = class _TuiBase extends Container {
39674
37922
  * @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
39675
37923
  */
39676
37924
  queryTerminalBackgroundColor({ timeoutMs }) {
39677
- return new Promise((resolve31) => {
37925
+ return new Promise((resolve30) => {
39678
37926
  const query = {
39679
37927
  settled: false,
39680
- resolve: resolve31,
37928
+ resolve: resolve30,
39681
37929
  timer: void 0
39682
37930
  };
39683
37931
  query.timer = setTimeout(() => {
@@ -39700,7 +37948,7 @@ var TuiBase = class _TuiBase extends Container {
39700
37948
  * `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
39701
37949
  */
39702
37950
  queryTerminalColorScheme({ timeoutMs }) {
39703
- return new Promise((resolve31) => {
37951
+ return new Promise((resolve30) => {
39704
37952
  let settled = false;
39705
37953
  let timer;
39706
37954
  let unsubscribe = () => {
@@ -39714,7 +37962,7 @@ var TuiBase = class _TuiBase extends Container {
39714
37962
  timer = void 0;
39715
37963
  }
39716
37964
  unsubscribe();
39717
- resolve31(scheme);
37965
+ resolve30(scheme);
39718
37966
  };
39719
37967
  unsubscribe = this.onTerminalColorSchemeChange(settle);
39720
37968
  timer = setTimeout(() => settle(void 0), timeoutMs);
@@ -41445,7 +39693,7 @@ import * as path2 from "node:path";
41445
39693
 
41446
39694
  // node_modules/@earendil-works/pi-tui/dist/native-module-path.js
41447
39695
  import { createRequire as createRequire2 } from "node:module";
41448
- import { dirname as dirname17, join as join33 } from "node:path";
39696
+ import { dirname as dirname17, join as join32 } from "node:path";
41449
39697
  import { fileURLToPath as fileURLToPath2 } from "node:url";
41450
39698
  var moduleRequire = createRequire2(import.meta.url);
41451
39699
  var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
@@ -41454,10 +39702,10 @@ function getNativeModuleCandidates(nativePath, options = {}) {
41454
39702
  const candidates = [];
41455
39703
  try {
41456
39704
  const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
41457
- candidates.push(join33(dirname17(packageEntry), "..", nativePath));
39705
+ candidates.push(join32(dirname17(packageEntry), "..", nativePath));
41458
39706
  } catch {
41459
39707
  }
41460
- candidates.push(join33(moduleDir, "..", nativePath), join33(moduleDir, nativePath), join33(dirname17(options.execPath ?? process.execPath), nativePath));
39708
+ candidates.push(join32(moduleDir, "..", nativePath), join32(moduleDir, nativePath), join32(dirname17(options.execPath ?? process.execPath), nativePath));
41461
39709
  return Array.from(new Set(candidates));
41462
39710
  }
41463
39711
 
@@ -41798,7 +40046,7 @@ var ProcessTerminal = class {
41798
40046
  break;
41799
40047
  if (now - lastDataTime >= idleMs)
41800
40048
  break;
41801
- await new Promise((resolve31) => setTimeout(resolve31, Math.min(idleMs, timeLeft)));
40049
+ await new Promise((resolve30) => setTimeout(resolve30, Math.min(idleMs, timeLeft)));
41802
40050
  }
41803
40051
  } finally {
41804
40052
  process.stdin.removeListener("data", onData);
@@ -43913,8 +42161,8 @@ var TuiAltScreen = class extends TuiBase {
43913
42161
  var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
43914
42162
 
43915
42163
  // plugins/kxm/src/tui.ts
43916
- import { mkdirSync as mkdirSync23 } from "node:fs";
43917
- import { join as join37, resolve as resolve24, dirname as dirname18 } from "node:path";
42164
+ import { mkdirSync as mkdirSync22 } from "node:fs";
42165
+ import { join as join36, resolve as resolve23, dirname as dirname18 } from "node:path";
43918
42166
  import { spawnSync as spawnSync5 } from "node:child_process";
43919
42167
 
43920
42168
  // packages/core/tui/src/types/surface.ts
@@ -44049,9 +42297,9 @@ function slugifyBranchPart(text, maxLength = 40) {
44049
42297
  }
44050
42298
 
44051
42299
  // plugins/kxm/src/local-snapshot.ts
44052
- import { existsSync as existsSync27, readdirSync as readdirSync11, readFileSync as readFileSync27 } from "node:fs";
42300
+ import { existsSync as existsSync26, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "node:fs";
44053
42301
  import { homedir as homedir6 } from "node:os";
44054
- import { isAbsolute as isAbsolute8, join as join36, resolve as resolve23 } from "node:path";
42302
+ import { isAbsolute as isAbsolute8, join as join35, resolve as resolve22 } from "node:path";
44055
42303
  function processExists2(pid) {
44056
42304
  try {
44057
42305
  process.kill(pid, 0);
@@ -44171,36 +42419,36 @@ function readOpenMessageMetadata(database) {
44171
42419
  return messages;
44172
42420
  }
44173
42421
  function resolveKxmSnapshotPaths(cwd, env = process.env) {
44174
- const stateDir = env.KXM_STATE_DIR?.trim() || join36(cwd, ".kxm", "state");
42422
+ const stateDir = env.KXM_STATE_DIR?.trim() || join35(cwd, ".kxm", "state");
44175
42423
  const configured = env.KXM_DATA_PATH?.trim();
44176
- const dataPath = configured ? resolve23(cwd, configured) : join36(stateDir, "kxm.db");
42424
+ const dataPath = configured ? resolve22(cwd, configured) : join35(stateDir, "kxm.db");
44177
42425
  return { dataPath, stateDir };
44178
42426
  }
44179
42427
  function resolveKxmStateRoot(stateDir, options) {
44180
- if (options?.kxmStateRoot && existsSync27(options.kxmStateRoot)) {
44181
- return resolve23(options.kxmStateRoot);
42428
+ if (options?.kxmStateRoot && existsSync26(options.kxmStateRoot)) {
42429
+ return resolve22(options.kxmStateRoot);
44182
42430
  }
44183
- if (existsSync27(join36(stateDir, "runtime", "registry.db")) || existsSync27(join36(stateDir, "runtime", "projects"))) {
42431
+ if (existsSync26(join35(stateDir, "runtime", "registry.db")) || existsSync26(join35(stateDir, "runtime", "projects"))) {
44184
42432
  return stateDir;
44185
42433
  }
44186
42434
  const env = options?.env ?? process.env;
44187
42435
  const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
44188
- if (explicit && isAbsolute8(explicit) && existsSync27(resolve23(explicit))) {
44189
- return resolve23(explicit);
42436
+ if (explicit && isAbsolute8(explicit) && existsSync26(resolve22(explicit))) {
42437
+ return resolve22(explicit);
44190
42438
  }
44191
42439
  let base;
44192
42440
  if (process.platform === "win32") {
44193
42441
  const localAppData = env.LOCALAPPDATA?.trim();
44194
- base = localAppData && isAbsolute8(localAppData) ? localAppData : join36(homedir6(), "AppData", "Local");
44195
- base = resolve23(base, "KXM");
42442
+ base = localAppData && isAbsolute8(localAppData) ? localAppData : join35(homedir6(), "AppData", "Local");
42443
+ base = resolve22(base, "KXM");
44196
42444
  } else if (process.platform === "darwin") {
44197
- base = resolve23(homedir6(), "Library", "Application Support", "KXM");
42445
+ base = resolve22(homedir6(), "Library", "Application Support", "KXM");
44198
42446
  } else {
44199
42447
  const xdgState = env.XDG_STATE_HOME?.trim();
44200
- base = xdgState && isAbsolute8(xdgState) ? xdgState : join36(homedir6(), ".local", "state");
44201
- base = resolve23(base, "kxm");
42448
+ base = xdgState && isAbsolute8(xdgState) ? xdgState : join35(homedir6(), ".local", "state");
42449
+ base = resolve22(base, "kxm");
44202
42450
  }
44203
- if (existsSync27(base)) return base;
42451
+ if (existsSync26(base)) return base;
44204
42452
  return void 0;
44205
42453
  }
44206
42454
  function loadLocalMeshSnapshot(dataPath, stateDir, options) {
@@ -44211,7 +42459,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44211
42459
  let legacyRuns = [];
44212
42460
  let legacyRunTotal = 0;
44213
42461
  let plans = [];
44214
- if (existsSync27(dataPath)) {
42462
+ if (existsSync26(dataPath)) {
44215
42463
  hasLegacy = true;
44216
42464
  const database = new DatabaseSync(dataPath, { readOnly: true });
44217
42465
  try {
@@ -44231,11 +42479,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44231
42479
  let kxmRunTotal = 0;
44232
42480
  const kxmStateRoot = resolveKxmStateRoot(stateDir, options);
44233
42481
  if (kxmStateRoot) {
44234
- const runtimeDir = join36(kxmStateRoot, "runtime");
44235
- const registryDbPath = join36(runtimeDir, "registry.db");
44236
- const projectsDir = join36(runtimeDir, "projects");
42482
+ const runtimeDir = join35(kxmStateRoot, "runtime");
42483
+ const registryDbPath = join35(runtimeDir, "registry.db");
42484
+ const projectsDir = join35(runtimeDir, "projects");
44237
42485
  const projectKeys = /* @__PURE__ */ new Set();
44238
- if (existsSync27(registryDbPath)) {
42486
+ if (existsSync26(registryDbPath)) {
44239
42487
  hasKxm = true;
44240
42488
  try {
44241
42489
  const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
@@ -44251,7 +42499,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44251
42499
  } catch {
44252
42500
  }
44253
42501
  }
44254
- if (existsSync27(projectsDir)) {
42502
+ if (existsSync26(projectsDir)) {
44255
42503
  try {
44256
42504
  for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
44257
42505
  if (entry.isDirectory()) {
@@ -44262,8 +42510,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44262
42510
  }
44263
42511
  }
44264
42512
  for (const key of projectKeys) {
44265
- const eventDbPath = join36(projectsDir, key, "run-events.db");
44266
- if (existsSync27(eventDbPath)) {
42513
+ const eventDbPath = join35(projectsDir, key, "run-events.db");
42514
+ if (existsSync26(eventDbPath)) {
44267
42515
  hasKxm = true;
44268
42516
  try {
44269
42517
  const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
@@ -44293,10 +42541,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44293
42541
  }
44294
42542
  }
44295
42543
  const pids = [];
44296
- if (existsSync27(stateDir)) {
42544
+ if (existsSync26(stateDir)) {
44297
42545
  for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
44298
42546
  try {
44299
- const record = JSON.parse(readFileSync27(join36(stateDir, file), "utf8"));
42547
+ const record = JSON.parse(readFileSync26(join35(stateDir, file), "utf8"));
44300
42548
  pids.push({
44301
42549
  file,
44302
42550
  ...record.role ? { role: record.role } : {},
@@ -44335,8 +42583,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
44335
42583
  } else {
44336
42584
  source = "legacy";
44337
42585
  }
44338
- const telemetryFile = join36(stateDir, "telemetry.jsonl");
44339
- const spend = existsSync27(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
42586
+ const telemetryFile = join35(stateDir, "telemetry.jsonl");
42587
+ const spend = existsSync26(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
44340
42588
  return {
44341
42589
  source,
44342
42590
  agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
@@ -44470,11 +42718,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
44470
42718
  const cleanRunId = runId.replace(/^run_/, "");
44471
42719
  const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
44472
42720
  const branchName = `kxm/run-${cleanRunId}-${desc}`;
44473
- const relativeWtPath = join37(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
44474
- const absoluteWtPath = resolve24(repoRoot, relativeWtPath);
42721
+ const relativeWtPath = join36(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
42722
+ const absoluteWtPath = resolve23(repoRoot, relativeWtPath);
44475
42723
  const jumpCommand = `cd "${absoluteWtPath}"`;
44476
42724
  try {
44477
- mkdirSync23(dirname18(absoluteWtPath), { recursive: true });
42725
+ mkdirSync22(dirname18(absoluteWtPath), { recursive: true });
44478
42726
  const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
44479
42727
  let wtRes;
44480
42728
  if (branchCheck.status === 0) {
@@ -44864,11 +43112,11 @@ async function readJson(response) {
44864
43112
  }
44865
43113
  async function waitForReconnect(signal, milliseconds = 1e3) {
44866
43114
  if (signal.aborted) return;
44867
- await new Promise((resolve31) => {
43115
+ await new Promise((resolve30) => {
44868
43116
  const done = () => {
44869
43117
  clearTimeout(timer);
44870
43118
  signal.removeEventListener("abort", done);
44871
- resolve31();
43119
+ resolve30();
44872
43120
  };
44873
43121
  const timer = setTimeout(done, milliseconds);
44874
43122
  timer.unref();
@@ -45231,8 +43479,8 @@ async function runMeshTui(input) {
45231
43479
  // plugins/kxm/src/session-work.ts
45232
43480
  import { spawnSync as spawnSync6 } from "node:child_process";
45233
43481
  import { randomUUID as randomUUID13 } from "node:crypto";
45234
- import { existsSync as existsSync28, mkdirSync as mkdirSync24, readFileSync as readFileSync28, renameSync as renameSync9, writeFileSync as writeFileSync22 } from "node:fs";
45235
- import { join as join38 } from "node:path";
43482
+ import { existsSync as existsSync27, mkdirSync as mkdirSync23, readFileSync as readFileSync27, renameSync as renameSync8, writeFileSync as writeFileSync21 } from "node:fs";
43483
+ import { join as join37 } from "node:path";
45236
43484
  var MAX_SESSION_BRIEF_TASKS = 5;
45237
43485
  var MAX_SESSION_BRIEF_PLANS = 5;
45238
43486
  var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
@@ -45389,10 +43637,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
45389
43637
  };
45390
43638
  }
45391
43639
  function readCachedSessionBrief(stateDir) {
45392
- const file = join38(stateDir, "session-brief.json");
43640
+ const file = join37(stateDir, "session-brief.json");
45393
43641
  try {
45394
- if (!existsSync28(file)) return void 0;
45395
- const raw = readFileSync28(file, "utf8");
43642
+ if (!existsSync27(file)) return void 0;
43643
+ const raw = readFileSync27(file, "utf8");
45396
43644
  const parsed = JSON.parse(raw);
45397
43645
  if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
45398
43646
  const ageMs = Date.now() - Date.parse(parsed.generatedAt);
@@ -45407,18 +43655,18 @@ function readCachedSessionBrief(stateDir) {
45407
43655
  }
45408
43656
  function writeCachedSessionBrief(stateDir, brief) {
45409
43657
  try {
45410
- mkdirSync24(stateDir, { recursive: true, mode: 448 });
45411
- const file = join38(stateDir, "session-brief.json");
43658
+ mkdirSync23(stateDir, { recursive: true, mode: 448 });
43659
+ const file = join37(stateDir, "session-brief.json");
45412
43660
  const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
45413
- writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
45414
- renameSync9(tmp, file);
43661
+ writeFileSync21(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
43662
+ renameSync8(tmp, file);
45415
43663
  } catch {
45416
43664
  }
45417
43665
  }
45418
43666
  function estimateSessionCost(stateDir) {
45419
43667
  try {
45420
- const telemetryFile = join38(stateDir, "telemetry.jsonl");
45421
- if (!existsSync28(telemetryFile)) return void 0;
43668
+ const telemetryFile = join37(stateDir, "telemetry.jsonl");
43669
+ if (!existsSync27(telemetryFile)) return void 0;
45422
43670
  const records = readRoutingRecords(telemetryFile);
45423
43671
  if (records.length === 0) return void 0;
45424
43672
  let totalCost = 0;
@@ -45586,11 +43834,11 @@ function formatSessionBriefText(brief) {
45586
43834
  }
45587
43835
 
45588
43836
  // plugins/kxm/src/kxm-install-kind.ts
45589
- import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
45590
- import { dirname as dirname19, join as join39 } from "node:path";
43837
+ import { existsSync as existsSync28, readFileSync as readFileSync28 } from "node:fs";
43838
+ import { dirname as dirname19, join as join38 } from "node:path";
45591
43839
  function packageIsKxm(root) {
45592
43840
  try {
45593
- const pkg = JSON.parse(readFileSync29(join39(root, "package.json"), "utf8"));
43841
+ const pkg = JSON.parse(readFileSync28(join38(root, "package.json"), "utf8"));
45594
43842
  return pkg.name === "@kontextmind/kxm";
45595
43843
  } catch {
45596
43844
  return false;
@@ -45639,12 +43887,12 @@ function report(kind, root) {
45639
43887
  return { kind, root, instruction: installKindInstruction(kind, root) };
45640
43888
  }
45641
43889
  function classifyInstallRoot(probe) {
45642
- const piGitRoot = join39(probe.homeDir, ".pi", "agent", "git");
43890
+ const piGitRoot = join38(probe.homeDir, ".pi", "agent", "git");
45643
43891
  if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
45644
- const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join39(probe.homeDir, ".claude");
45645
- const pluginsRoot = join39(claudeHome, "plugins");
43892
+ const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join38(probe.homeDir, ".claude");
43893
+ const pluginsRoot = join38(claudeHome, "plugins");
45646
43894
  if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
45647
- const hasGit = existsSync29(join39(probe.repoRoot, ".git"));
43895
+ const hasGit = existsSync28(join38(probe.repoRoot, ".git"));
45648
43896
  if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
45649
43897
  if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
45650
43898
  return report("npm-package", probe.repoRoot);
@@ -45664,15 +43912,15 @@ function resolveInstallKind(probe, npmGlobalRoot) {
45664
43912
  }
45665
43913
 
45666
43914
  // plugins/kxm/src/kxm-update-config.ts
45667
- var import_yaml16 = __toESM(require_dist(), 1);
45668
- import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
45669
- import { join as join40 } from "node:path";
43915
+ var import_yaml15 = __toESM(require_dist(), 1);
43916
+ import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
43917
+ import { join as join39 } from "node:path";
45670
43918
  function loadKxmUpdateConfig(env = process.env) {
45671
- const path4 = join40(kxmUserStateRoot({ env }), "update.yaml");
45672
- if (!existsSync30(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
43919
+ const path4 = join39(kxmUserStateRoot({ env }), "update.yaml");
43920
+ if (!existsSync29(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
45673
43921
  let parsed;
45674
43922
  try {
45675
- parsed = (0, import_yaml16.parse)(readFileSync30(path4, "utf8"));
43923
+ parsed = (0, import_yaml15.parse)(readFileSync29(path4, "utf8"));
45676
43924
  } catch {
45677
43925
  throw new KxmUpdateConfigError("update.yaml is not valid YAML");
45678
43926
  }
@@ -45698,8 +43946,8 @@ function loadKxmUpdateConfig(env = process.env) {
45698
43946
  }
45699
43947
 
45700
43948
  // plugins/kxm/src/session.ts
45701
- import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync23 } from "node:fs";
45702
- import { join as join41 } from "node:path";
43949
+ import { existsSync as existsSync30, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
43950
+ import { join as join40 } from "node:path";
45703
43951
  var SESSION_SCHEMA = "kxm.session.v1";
45704
43952
  var SessionConfigError = class extends Error {
45705
43953
  code = "session_config_invalid";
@@ -45709,12 +43957,12 @@ var SessionConfigError = class extends Error {
45709
43957
  }
45710
43958
  };
45711
43959
  function workflowAssetDirs(assetsDir, workflowId) {
45712
- const root = join41(assetsDir, "workflows", workflowId);
45713
- return [root, join41(root, "inputs"), join41(root, "outputs"), join41(root, "generated")];
43960
+ const root = join40(assetsDir, "workflows", workflowId);
43961
+ return [root, join40(root, "inputs"), join40(root, "outputs"), join40(root, "generated")];
45714
43962
  }
45715
43963
  function sessionAssetDirs(assetsDir, sessionId) {
45716
- const root = join41(assetsDir, "sessions", sessionId);
45717
- return [root, join41(root, "inputs"), join41(root, "outputs")];
43964
+ const root = join40(assetsDir, "sessions", sessionId);
43965
+ return [root, join40(root, "inputs"), join40(root, "outputs")];
45718
43966
  }
45719
43967
  function rosterNames(configDir) {
45720
43968
  return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
@@ -45764,7 +44012,7 @@ function workerFromRosterRow(name, row, project) {
45764
44012
  function loadRosterMap(configDir) {
45765
44013
  const byName = /* @__PURE__ */ new Map();
45766
44014
  for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
45767
- const path4 = join41(configDir, file);
44015
+ const path4 = join40(configDir, file);
45768
44016
  for (const row of loadRoster(path4, key)) {
45769
44017
  const name = String(row.name).trim();
45770
44018
  const lowered = name.toLowerCase();
@@ -45778,10 +44026,10 @@ function loadRosterMap(configDir) {
45778
44026
  return byName;
45779
44027
  }
45780
44028
  function loadRoster(path4, key) {
45781
- if (!existsSync31(path4)) return [];
44029
+ if (!existsSync30(path4)) return [];
45782
44030
  let parsed;
45783
44031
  try {
45784
- parsed = JSON.parse(readFileSync31(path4, "utf8"));
44032
+ parsed = JSON.parse(readFileSync30(path4, "utf8"));
45785
44033
  } catch (error) {
45786
44034
  throw new SessionConfigError(
45787
44035
  `${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
@@ -45806,7 +44054,7 @@ function loadRoster(path4, key) {
45806
44054
  });
45807
44055
  }
45808
44056
  function createSession(input) {
45809
- const assetDir = input.mode === "workflow" && input.workflowId ? join41("assets", "workflows", input.workflowId) : join41("assets", "sessions", input.id);
44057
+ const assetDir = input.mode === "workflow" && input.workflowId ? join40("assets", "workflows", input.workflowId) : join40("assets", "sessions", input.id);
45810
44058
  return {
45811
44059
  schema: SESSION_SCHEMA,
45812
44060
  id: input.id,
@@ -45819,11 +44067,11 @@ function createSession(input) {
45819
44067
  };
45820
44068
  }
45821
44069
  function writeSession(assetsDir, session, dryRun = false) {
45822
- const dir = join41(assetsDir, "sessions", session.id);
45823
- const path4 = join41(dir, "session.json");
44070
+ const dir = join40(assetsDir, "sessions", session.id);
44071
+ const path4 = join40(dir, "session.json");
45824
44072
  if (!dryRun) {
45825
- mkdirSync25(dir, { recursive: true });
45826
- writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
44073
+ mkdirSync24(dir, { recursive: true });
44074
+ writeFileSync22(path4, `${JSON.stringify(session, null, 2)}
45827
44075
  `, { encoding: "utf8" });
45828
44076
  }
45829
44077
  return path4;
@@ -45851,22 +44099,22 @@ function installProbeFrom(runtime) {
45851
44099
  const partial = runtime.io.installProbe ?? {};
45852
44100
  return {
45853
44101
  moduleDir: partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url)),
45854
- repoRoot: partial.repoRoot ?? resolve25("."),
44102
+ repoRoot: partial.repoRoot ?? resolve24("."),
45855
44103
  homeDir: partial.homeDir ?? homedir7(),
45856
44104
  platform: partial.platform ?? process.platform,
45857
44105
  env: partial.env ?? runtime.env
45858
44106
  };
45859
44107
  }
45860
44108
  function warnIgnoredProjectUpdateYaml(runtime) {
45861
- const projectFile = join42(runtime.dirs.workspace, "update.yaml");
45862
- if (!existsSync32(projectFile)) return;
45863
- const userFile = join42(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
44109
+ const projectFile = join41(runtime.dirs.workspace, "update.yaml");
44110
+ if (!existsSync31(projectFile)) return;
44111
+ const userFile = join41(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
45864
44112
  runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
45865
44113
  `);
45866
44114
  }
45867
44115
  async function refreshKxmUpdateNotice(runtime, config) {
45868
44116
  const resolved = config ?? loadKxmUpdateConfig(runtime.env);
45869
- const current = readInstalledKxmVersion(resolve25("."));
44117
+ const current = readInstalledKxmVersion(resolve24("."));
45870
44118
  const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
45871
44119
  const notice = noticeFromVersions(current, fetched.latest, resolved, fetched.error, fetched.asset);
45872
44120
  writeUpdateCache(runtime.dirs.state, notice);
@@ -45899,7 +44147,7 @@ async function cmdDash(runtime, options = {}) {
45899
44147
  return 2;
45900
44148
  }
45901
44149
  const screen = requested;
45902
- const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
44150
+ const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
45903
44151
  if (runtime.dryRun) {
45904
44152
  print(runtime.io, runtime.json, {
45905
44153
  ok: true,
@@ -45945,7 +44193,7 @@ async function cmdHub(runtime) {
45945
44193
  config = loadKxmUpdateConfig(runtime.env);
45946
44194
  } catch (error) {
45947
44195
  if (error instanceof KxmUpdateConfigError) {
45948
- const yamlPath = join42(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
44196
+ const yamlPath = join41(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
45949
44197
  runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
45950
44198
  `);
45951
44199
  } else {
@@ -46132,7 +44380,7 @@ async function cmdWorker(runtime, options) {
46132
44380
  return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
46133
44381
  }
46134
44382
  async function cmdStop(runtime, waitMsFlag) {
46135
- const pids = existsSync32(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
44383
+ const pids = existsSync31(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
46136
44384
  if (runtime.dryRun) {
46137
44385
  print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
46138
44386
  return 0;
@@ -46147,7 +44395,7 @@ async function cmdStop(runtime, waitMsFlag) {
46147
44395
  const orphans = [];
46148
44396
  for (const file of pids) {
46149
44397
  try {
46150
- const record = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
44398
+ const record = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
46151
44399
  const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
46152
44400
  const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
46153
44401
  if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
@@ -46167,7 +44415,7 @@ async function cmdStop(runtime, waitMsFlag) {
46167
44415
  ignored.push(file);
46168
44416
  continue;
46169
44417
  }
46170
- writeFileSync24(join42(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
44418
+ writeFileSync23(join41(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
46171
44419
  `, { encoding: "utf8", mode: 384 });
46172
44420
  requested.push(file);
46173
44421
  records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
@@ -46185,7 +44433,7 @@ async function cmdStop(runtime, waitMsFlag) {
46185
44433
  while (Date.now() <= deadline && stopped.size < requested.length) {
46186
44434
  for (const [file, record] of records) {
46187
44435
  try {
46188
- const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
44436
+ const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
46189
44437
  if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
46190
44438
  } catch {
46191
44439
  stopped.add(file);
@@ -46198,7 +44446,7 @@ async function cmdStop(runtime, waitMsFlag) {
46198
44446
  for (const file of orphans) {
46199
44447
  while (Date.now() <= deadlineOrphans) {
46200
44448
  try {
46201
- const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
44449
+ const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
46202
44450
  if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
46203
44451
  } catch {
46204
44452
  break;
@@ -46206,14 +44454,14 @@ async function cmdStop(runtime, waitMsFlag) {
46206
44454
  await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
46207
44455
  }
46208
44456
  try {
46209
- const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
44457
+ const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
46210
44458
  if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
46211
44459
  try {
46212
44460
  process.kill(current.serverPid, "SIGKILL");
46213
44461
  } catch {
46214
44462
  }
46215
44463
  }
46216
- rmSync11(join42(runtime.dirs.state, file), { force: true });
44464
+ rmSync10(join41(runtime.dirs.state, file), { force: true });
46217
44465
  } catch {
46218
44466
  }
46219
44467
  stopped.add(file);
@@ -46224,11 +44472,11 @@ async function cmdStop(runtime, waitMsFlag) {
46224
44472
  }
46225
44473
  async function cmdSessionStatus(runtime) {
46226
44474
  const stateDir = runtime.dirs.state;
46227
- const names3 = existsSync32(stateDir) ? readdirSync12(stateDir) : [];
44475
+ const names3 = existsSync31(stateDir) ? readdirSync12(stateDir) : [];
46228
44476
  const claims = [];
46229
44477
  for (const file of names3.filter((name) => name.endsWith(".pid"))) {
46230
44478
  try {
46231
- const record = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
44479
+ const record = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
46232
44480
  claims.push({
46233
44481
  file,
46234
44482
  role: record.role,
@@ -46243,7 +44491,7 @@ async function cmdSessionStatus(runtime) {
46243
44491
  const recoveries = [];
46244
44492
  for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
46245
44493
  try {
46246
- const envelope = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
44494
+ const envelope = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
46247
44495
  recoveries.push({
46248
44496
  file,
46249
44497
  reason: envelope.reason,
@@ -46348,7 +44596,7 @@ async function cmdSessionBrief(runtime, options = {}) {
46348
44596
  print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
46349
44597
  return 0;
46350
44598
  }
46351
- const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
44599
+ const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
46352
44600
  const env = {
46353
44601
  ...runtime.env,
46354
44602
  KXM_STATE_DIR: runtime.dirs.state,
@@ -46425,7 +44673,7 @@ async function cmdSessionStart(runtime, options) {
46425
44673
  ...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
46426
44674
  ];
46427
44675
  if (!runtime.dryRun) {
46428
- for (const directory of created) mkdirSync26(directory, { recursive: true });
44676
+ for (const directory of created) mkdirSync25(directory, { recursive: true });
46429
44677
  writeSession(runtime.dirs.assets, session);
46430
44678
  }
46431
44679
  print(runtime.io, runtime.json, {
@@ -46440,16 +44688,16 @@ async function cmdSessionStart(runtime, options) {
46440
44688
 
46441
44689
  // plugins/kxm/src/cli/system.ts
46442
44690
  import { spawnSync as spawnSync8 } from "node:child_process";
46443
- import { createHash as createHash16 } from "node:crypto";
46444
- import { existsSync as existsSync38, mkdtempSync as mkdtempSync2, readFileSync as readFileSync37, rmSync as rmSync13 } from "node:fs";
44691
+ import { createHash as createHash15 } from "node:crypto";
44692
+ import { existsSync as existsSync37, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
46445
44693
  import { tmpdir as tmpdir2 } from "node:os";
46446
- import { join as join48, resolve as resolve29 } from "node:path";
44694
+ import { join as join47, resolve as resolve28 } from "node:path";
46447
44695
  import { createInterface as createInterface3 } from "node:readline";
46448
44696
 
46449
44697
  // plugins/kxm/src/improve.ts
46450
- import { createHash as createHash15 } from "node:crypto";
46451
- import { existsSync as existsSync33, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25 } from "node:fs";
46452
- import { join as join43, relative as relative6, resolve as resolve26 } from "node:path";
44698
+ import { createHash as createHash14 } from "node:crypto";
44699
+ import { existsSync as existsSync32, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
44700
+ import { join as join42, relative as relative6, resolve as resolve25 } from "node:path";
46453
44701
  var CANDIDATE_SCHEMA = "kxm.candidate.v1";
46454
44702
  var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
46455
44703
  function classifyCandidateKind(stepId, agentRole) {
@@ -46595,7 +44843,7 @@ function groupRoutingRecords(records, options = {}) {
46595
44843
  const isCandidate = recurrence >= minRecurrence && verifyPassRate >= minPassRate;
46596
44844
  const candidateKind = isCandidate ? classifyCandidateKind(group.stepId, group.agentRole) : void 0;
46597
44845
  const safeSlug = group.stepId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 16) || "step";
46598
- const keyHash = createHash15("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
44846
+ const keyHash = createHash14("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
46599
44847
  const candidateId = isCandidate && candidateKind ? `cand_${candidateKind.replace(/-/g, "_")}_${safeSlug}_${keyHash}` : void 0;
46600
44848
  rows.push({
46601
44849
  workflowHash: group.workflowHash,
@@ -46620,8 +44868,8 @@ function groupRoutingRecords(records, options = {}) {
46620
44868
  });
46621
44869
  }
46622
44870
  function buildImprovementReport(records, options = {}) {
46623
- const projectRoot = options.projectRoot ? resolve26(options.projectRoot) : process.cwd();
46624
- const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) : join43(projectRoot, ".kxm", "candidates");
44871
+ const projectRoot = options.projectRoot ? resolve25(options.projectRoot) : process.cwd();
44872
+ const candidatesDir = options.candidatesDir ? resolve25(options.candidatesDir) : join42(projectRoot, ".kxm", "candidates");
46625
44873
  const groups = groupRoutingRecords(records, options);
46626
44874
  const candidates = [];
46627
44875
  for (const group of groups) {
@@ -46633,7 +44881,7 @@ function buildImprovementReport(records, options = {}) {
46633
44881
  group.workflowHash
46634
44882
  );
46635
44883
  const diffFileName = `${group.candidateId}.diff`;
46636
- const diffFilePath = join43(candidatesDir, diffFileName);
44884
+ const diffFilePath = join42(candidatesDir, diffFileName);
46637
44885
  const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
46638
44886
  const candidate = {
46639
44887
  schema: CANDIDATE_SCHEMA,
@@ -46655,12 +44903,12 @@ function buildImprovementReport(records, options = {}) {
46655
44903
  createdAt: nowIso()
46656
44904
  };
46657
44905
  if (!options.dryRun) {
46658
- if (!existsSync33(candidatesDir)) {
46659
- mkdirSync27(candidatesDir, { recursive: true });
44906
+ if (!existsSync32(candidatesDir)) {
44907
+ mkdirSync26(candidatesDir, { recursive: true });
46660
44908
  }
46661
- writeFileSync25(diffFilePath, diff, "utf8");
46662
- const jsonFilePath = join43(candidatesDir, `${group.candidateId}.json`);
46663
- writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
44909
+ writeFileSync24(diffFilePath, diff, "utf8");
44910
+ const jsonFilePath = join42(candidatesDir, `${group.candidateId}.json`);
44911
+ writeFileSync24(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
46664
44912
  }
46665
44913
  candidates.push(candidate);
46666
44914
  }
@@ -46675,10 +44923,10 @@ function buildImprovementReport(records, options = {}) {
46675
44923
  }
46676
44924
  function writeImprovementReport(improvementsDir, report2, dryRun = false) {
46677
44925
  const stamp = report2.createdAt.replace(/[:.]/g, "-");
46678
- const path4 = join43(improvementsDir, `${stamp}.json`);
44926
+ const path4 = join42(improvementsDir, `${stamp}.json`);
46679
44927
  if (!dryRun) {
46680
- mkdirSync27(improvementsDir, { recursive: true });
46681
- writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
44928
+ mkdirSync26(improvementsDir, { recursive: true });
44929
+ writeFileSync24(path4, `${JSON.stringify(report2, null, 2)}
46682
44930
  `, { encoding: "utf8" });
46683
44931
  }
46684
44932
  return path4;
@@ -46717,9 +44965,9 @@ function formatImprovementReport(report2) {
46717
44965
  }
46718
44966
 
46719
44967
  // plugins/kxm/src/modes.ts
46720
- var import_yaml17 = __toESM(require_dist(), 1);
46721
- import { existsSync as existsSync34, readFileSync as readFileSync34 } from "node:fs";
46722
- import { join as join44 } from "node:path";
44968
+ var import_yaml16 = __toESM(require_dist(), 1);
44969
+ import { existsSync as existsSync33, readFileSync as readFileSync33 } from "node:fs";
44970
+ import { join as join43 } from "node:path";
46723
44971
  var DEFAULT_MODES_CONFIG = Object.freeze({
46724
44972
  schema: "kxm.modes.v1",
46725
44973
  majorModes: {
@@ -46782,13 +45030,13 @@ function loadModesConfig(projectRoot) {
46782
45030
  if (!projectRoot) {
46783
45031
  return DEFAULT_MODES_CONFIG;
46784
45032
  }
46785
- const modesPath = join44(projectRoot, ".kxm", "modes.yaml");
46786
- if (!existsSync34(modesPath)) {
45033
+ const modesPath = join43(projectRoot, ".kxm", "modes.yaml");
45034
+ if (!existsSync33(modesPath)) {
46787
45035
  return DEFAULT_MODES_CONFIG;
46788
45036
  }
46789
45037
  try {
46790
- const raw = readFileSync34(modesPath, "utf8");
46791
- const parsed = (0, import_yaml17.parse)(raw);
45038
+ const raw = readFileSync33(modesPath, "utf8");
45039
+ const parsed = (0, import_yaml16.parse)(raw);
46792
45040
  if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
46793
45041
  return {
46794
45042
  schema: "kxm.modes.v1",
@@ -46873,11 +45121,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
46873
45121
  estimatedTokens: estimateTokens(baseSystemPromptChars)
46874
45122
  });
46875
45123
  for (const relPath of resolved.contextFiles) {
46876
- const fullPath = join44(projectRoot, relPath);
45124
+ const fullPath = join43(projectRoot, relPath);
46877
45125
  let chars = 0;
46878
- if (existsSync34(fullPath)) {
45126
+ if (existsSync33(fullPath)) {
46879
45127
  try {
46880
- chars = readFileSync34(fullPath, "utf8").length;
45128
+ chars = readFileSync33(fullPath, "utf8").length;
46881
45129
  } catch {
46882
45130
  chars = 0;
46883
45131
  }
@@ -47009,9 +45257,9 @@ ${divider}
47009
45257
 
47010
45258
  // plugins/kxm/src/ssh-remote.ts
47011
45259
  import { spawnSync as spawnSync7 } from "node:child_process";
47012
- import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
45260
+ import { existsSync as existsSync34, mkdirSync as mkdirSync27, readFileSync as readFileSync34, readdirSync as readdirSync13, rmSync as rmSync11, statSync as statSync5 } from "node:fs";
47013
45261
  import { homedir as homedir8 } from "node:os";
47014
- import { join as join45, resolve as resolve27 } from "node:path";
45262
+ import { join as join44, resolve as resolve26 } from "node:path";
47015
45263
  var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
47016
45264
  var MAX_SSH_OUTPUT_LINES = 2e3;
47017
45265
  var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
@@ -47037,12 +45285,12 @@ function truncateSshOutput(raw) {
47037
45285
  return { text, truncated };
47038
45286
  }
47039
45287
  function parseSshConfig(configPath) {
47040
- const targetPath = configPath ?? join45(homedir8(), ".ssh", "config");
47041
- if (!existsSync35(targetPath)) {
45288
+ const targetPath = configPath ?? join44(homedir8(), ".ssh", "config");
45289
+ if (!existsSync34(targetPath)) {
47042
45290
  return [];
47043
45291
  }
47044
45292
  try {
47045
- const content = readFileSync35(targetPath, "utf-8");
45293
+ const content = readFileSync34(targetPath, "utf-8");
47046
45294
  const lines = content.split("\n");
47047
45295
  const hosts = [];
47048
45296
  let currentHosts = [];
@@ -47119,15 +45367,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
47119
45367
  }
47120
45368
  }
47121
45369
  function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
47122
- const resolved = resolve27(socketDir);
47123
- if (!existsSync35(resolved)) {
47124
- mkdirSync28(resolved, { recursive: true, mode: 448 });
45370
+ const resolved = resolve26(socketDir);
45371
+ if (!existsSync34(resolved)) {
45372
+ mkdirSync27(resolved, { recursive: true, mode: 448 });
47125
45373
  }
47126
45374
  return resolved;
47127
45375
  }
47128
45376
  function buildSshArgs(options) {
47129
45377
  const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
47130
- const controlPath = join45(socketDir, "%C");
45378
+ const controlPath = join44(socketDir, "%C");
47131
45379
  const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
47132
45380
  const args = [
47133
45381
  "-o",
@@ -47152,7 +45400,7 @@ function buildSshArgs(options) {
47152
45400
  }
47153
45401
  function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
47154
45402
  const resolvedDir = ensureSocketDir(socketDir);
47155
- const controlPath = join45(resolvedDir, "%C");
45403
+ const controlPath = join44(resolvedDir, "%C");
47156
45404
  try {
47157
45405
  const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
47158
45406
  encoding: "utf-8"
@@ -47164,7 +45412,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
47164
45412
  }
47165
45413
  function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
47166
45414
  const resolvedDir = ensureSocketDir(socketDir);
47167
- const controlPath = join45(resolvedDir, "%C");
45415
+ const controlPath = join44(resolvedDir, "%C");
47168
45416
  try {
47169
45417
  const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
47170
45418
  encoding: "utf-8"
@@ -47376,7 +45624,6 @@ function executeSshRun(params) {
47376
45624
  // plugins/kxm/src/autocomplete.ts
47377
45625
  var TOP_LEVEL_COMMANDS = [
47378
45626
  "init",
47379
- "migrate",
47380
45627
  "backup",
47381
45628
  "restore",
47382
45629
  "run",
@@ -47409,7 +45656,6 @@ var TOP_LEVEL_COMMANDS = [
47409
45656
  ];
47410
45657
  var SUBCOMMANDS = {
47411
45658
  runs: ["status", "cancel", "list"],
47412
- migrate: ["plan", "apply", "verify"],
47413
45659
  harness: ["list"],
47414
45660
  runtime: ["start", "status", "stop"],
47415
45661
  trust: ["diff", "check"],
@@ -47501,7 +45747,6 @@ _kxm() {
47501
45747
  local -a commands
47502
45748
  commands=(
47503
45749
  'init:Create or validate a KXM project'
47504
- 'migrate:Plan, apply, and verify legacy configuration migration'
47505
45750
  'backup:Create a verified SQLite backup manifest'
47506
45751
  'restore:Restore SQLite stores from a backup manifest'
47507
45752
  'run:Create a KXM workflow run'
@@ -47610,9 +45855,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
47610
45855
  }
47611
45856
 
47612
45857
  // plugins/kxm/src/completion-install.ts
47613
- import { existsSync as existsSync36, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync26 } from "node:fs";
45858
+ import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, writeFileSync as writeFileSync25 } from "node:fs";
47614
45859
  import { homedir as homedir9 } from "node:os";
47615
- import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as join46, resolve as resolve28 } from "node:path";
45860
+ import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as join45, resolve as resolve27 } from "node:path";
47616
45861
  var COMPLETION_MARKER = "# kxm completion";
47617
45862
  var PATH_MARKER = "# kxm path";
47618
45863
  function detectShell(env = process.env, platform = process.platform) {
@@ -47628,31 +45873,31 @@ function effectiveHome(options) {
47628
45873
  const env = options.env ?? process.env;
47629
45874
  if (options.homeDir) return options.homeDir;
47630
45875
  const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
47631
- return envHome && envHome.length > 0 ? resolve28(envHome) : homedir9();
45876
+ return envHome && envHome.length > 0 ? resolve27(envHome) : homedir9();
47632
45877
  }
47633
45878
  function completionScriptPath(shell, options = {}) {
47634
45879
  const env = options.env ?? process.env;
47635
45880
  const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
47636
- const base = explicit && explicit.length > 0 ? resolve28(explicit) : resolve28(effectiveHome(options), ".config", "kxm");
47637
- return join46(base, "completions", `kxm.${shell}`);
45881
+ const base = explicit && explicit.length > 0 ? resolve27(explicit) : resolve27(effectiveHome(options), ".config", "kxm");
45882
+ return join45(base, "completions", `kxm.${shell}`);
47638
45883
  }
47639
45884
  function bashRcCandidate(options) {
47640
45885
  const home = effectiveHome(options);
47641
- const candidates = [join46(home, ".bashrc"), join46(home, ".bash_profile")];
47642
- const existing = candidates.find((candidate) => existsSync36(candidate));
45886
+ const candidates = [join45(home, ".bashrc"), join45(home, ".bash_profile")];
45887
+ const existing = candidates.find((candidate) => existsSync35(candidate));
47643
45888
  return existing ?? candidates[0];
47644
45889
  }
47645
45890
  function zshRcCandidate(options) {
47646
45891
  const env = options.env ?? process.env;
47647
45892
  const home = effectiveHome(options);
47648
- if (env.ZDOTDIR?.trim()) return join46(resolve28(env.ZDOTDIR.trim()), ".zshrc");
47649
- return join46(home, ".zshrc");
45893
+ if (env.ZDOTDIR?.trim()) return join45(resolve27(env.ZDOTDIR.trim()), ".zshrc");
45894
+ return join45(home, ".zshrc");
47650
45895
  }
47651
45896
  function fishCompletionTarget(shell, options) {
47652
45897
  const env = options.env ?? process.env;
47653
45898
  const home = effectiveHome(options);
47654
- if (env.XDG_CONFIG_HOME?.trim()) return join46(resolve28(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
47655
- return join46(home, ".config", "fish", "completions", "kxm.fish");
45899
+ if (env.XDG_CONFIG_HOME?.trim()) return join45(resolve27(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
45900
+ return join45(home, ".config", "fish", "completions", "kxm.fish");
47656
45901
  }
47657
45902
  function completionRcTarget(shell, options = {}) {
47658
45903
  if (shell === "fish") {
@@ -47684,17 +45929,17 @@ function installShellCompletion(shellInput, options = {}) {
47684
45929
  const scriptPath = completionScriptPath(shell, options);
47685
45930
  const { rcFile } = completionRcTarget(shell, options);
47686
45931
  const script = generateShellCompletion(shell);
47687
- const existingScript = existsSync36(scriptPath);
47688
- const existingScriptMatches = existingScript && readFileSync36(scriptPath, "utf8") === script;
45932
+ const existingScript = existsSync35(scriptPath);
45933
+ const existingScriptMatches = existingScript && readFileSync35(scriptPath, "utf8") === script;
47689
45934
  let rcModified = false;
47690
45935
  let alreadyInstalled = false;
47691
45936
  if (shell === "fish") {
47692
45937
  const fishTarget = fishCompletionTarget(shell, options);
47693
- const fishInstalled = existsSync36(fishTarget) && readFileSync36(fishTarget, "utf8") === script;
45938
+ const fishInstalled = existsSync35(fishTarget) && readFileSync35(fishTarget, "utf8") === script;
47694
45939
  alreadyInstalled = fishInstalled;
47695
45940
  if (!options.dryRun && (!fishInstalled || options.overwrite)) {
47696
- mkdirSync29(resolve28(fishTarget, ".."), { recursive: true });
47697
- writeFileSync26(fishTarget, script, { encoding: "utf8" });
45941
+ mkdirSync28(resolve27(fishTarget, ".."), { recursive: true });
45942
+ writeFileSync25(fishTarget, script, { encoding: "utf8" });
47698
45943
  }
47699
45944
  return {
47700
45945
  ok: true,
@@ -47707,13 +45952,13 @@ function installShellCompletion(shellInput, options = {}) {
47707
45952
  }
47708
45953
  if (rcFile) {
47709
45954
  const line = sourceLine(shell, scriptPath);
47710
- const rcContent = existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "";
45955
+ const rcContent = existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "";
47711
45956
  alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
47712
45957
  }
47713
45958
  if (!options.dryRun) {
47714
45959
  if (!existingScriptMatches || options.overwrite) {
47715
- mkdirSync29(resolve28(scriptPath, ".."), { recursive: true });
47716
- writeFileSync26(scriptPath, script, { encoding: "utf8" });
45960
+ mkdirSync28(resolve27(scriptPath, ".."), { recursive: true });
45961
+ writeFileSync25(scriptPath, script, { encoding: "utf8" });
47717
45962
  }
47718
45963
  if (rcFile && !alreadyInstalled) {
47719
45964
  const line = sourceLine(shell, scriptPath);
@@ -47722,8 +45967,8 @@ function installShellCompletion(shellInput, options = {}) {
47722
45967
  ${marker}
47723
45968
  ${line}
47724
45969
  `;
47725
- mkdirSync29(resolve28(rcFile, ".."), { recursive: true });
47726
- writeFileSync26(rcFile, (existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
45970
+ mkdirSync28(resolve27(rcFile, ".."), { recursive: true });
45971
+ writeFileSync25(rcFile, (existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
47727
45972
  rcModified = true;
47728
45973
  }
47729
45974
  }
@@ -47740,13 +45985,13 @@ function kxmBinDir(env = process.env) {
47740
45985
  const argv1 = env.KXM_ENTRY ?? process.argv[1];
47741
45986
  if (argv1 && isAbsolute9(argv1)) {
47742
45987
  const dir = dirname22(argv1);
47743
- if (existsSync36(join46(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
45988
+ if (existsSync35(join45(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
47744
45989
  }
47745
45990
  const pathEnv = env.PATH ?? "";
47746
45991
  for (const part of pathEnv.split(delimiter)) {
47747
45992
  if (!part) continue;
47748
- const candidate = resolve28(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
47749
- if (existsSync36(candidate)) return resolve28(part);
45993
+ const candidate = resolve27(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
45994
+ if (existsSync35(candidate)) return resolve27(part);
47750
45995
  }
47751
45996
  return void 0;
47752
45997
  }
@@ -47764,11 +46009,11 @@ function installPathEntry(shellInput, options = {}) {
47764
46009
  }
47765
46010
  const { rcFile } = completionRcTarget(shell, options);
47766
46011
  const line = pathLine(binDir);
47767
- const rcContent = existsSync36(rcFile ?? "") ? readFileSync36(rcFile, "utf8") : "";
46012
+ const rcContent = existsSync35(rcFile ?? "") ? readFileSync35(rcFile, "utf8") : "";
47768
46013
  const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
47769
46014
  if (!options.dryRun && rcFile && !alreadyInstalled) {
47770
- mkdirSync29(dirname22(rcFile), { recursive: true });
47771
- writeFileSync26(rcFile, rcContent + `
46015
+ mkdirSync28(dirname22(rcFile), { recursive: true });
46016
+ writeFileSync25(rcFile, rcContent + `
47772
46017
  ${PATH_MARKER}
47773
46018
  ${line}
47774
46019
  `, { encoding: "utf8" });
@@ -47777,9 +46022,9 @@ ${line}
47777
46022
  }
47778
46023
 
47779
46024
  // plugins/kxm/src/init-guide-setup.ts
47780
- var import_yaml18 = __toESM(require_dist(), 1);
47781
- import { existsSync as existsSync37, mkdirSync as mkdirSync30, writeFileSync as writeFileSync27 } from "node:fs";
47782
- import { dirname as dirname23, join as join47 } from "node:path";
46025
+ var import_yaml17 = __toESM(require_dist(), 1);
46026
+ import { existsSync as existsSync36, mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
46027
+ import { dirname as dirname23, join as join46 } from "node:path";
47783
46028
  var NATIVE_VENDOR_HARNESS = Object.freeze({
47784
46029
  anthropic: "claude",
47785
46030
  openai: "codex",
@@ -48178,14 +46423,14 @@ function renderGuideSetupFiles(projectRoot, plan) {
48178
46423
  const stage = roleStages.get(role);
48179
46424
  if (!stage) continue;
48180
46425
  files.push({
48181
- path: join47(projectRoot, ".kxm", "agents", `${role}.yaml`),
48182
- content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
46426
+ path: join46(projectRoot, ".kxm", "agents", `${role}.yaml`),
46427
+ content: (0, import_yaml17.stringify)(agentDocument(role, stage, binding))
48183
46428
  });
48184
46429
  }
48185
46430
  for (const workflow of plan.workflows) {
48186
46431
  files.push({
48187
- path: join47(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
48188
- content: (0, import_yaml18.stringify)(workflowDocument(workflow))
46432
+ path: join46(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
46433
+ content: (0, import_yaml17.stringify)(workflowDocument(workflow))
48189
46434
  });
48190
46435
  }
48191
46436
  return files;
@@ -48194,12 +46439,12 @@ function writeGuideSetupFiles(files) {
48194
46439
  const written = [];
48195
46440
  const existed = [];
48196
46441
  for (const file of files) {
48197
- if (existsSync37(file.path)) {
46442
+ if (existsSync36(file.path)) {
48198
46443
  existed.push(file.path);
48199
46444
  continue;
48200
46445
  }
48201
- mkdirSync30(dirname23(file.path), { recursive: true });
48202
- writeFileSync27(file.path, file.content, "utf8");
46446
+ mkdirSync29(dirname23(file.path), { recursive: true });
46447
+ writeFileSync26(file.path, file.content, "utf8");
48203
46448
  written.push(file.path);
48204
46449
  }
48205
46450
  return { written, existed };
@@ -48262,7 +46507,7 @@ function applyKxmPackageUpdate(runtime, notice) {
48262
46507
  detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
48263
46508
  };
48264
46509
  }
48265
- const releaseDir = mkdtempSync2(join48(tmpdir2(), "kxm-pkg-update-"));
46510
+ const releaseDir = mkdtempSync2(join47(tmpdir2(), "kxm-pkg-update-"));
48266
46511
  try {
48267
46512
  const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
48268
46513
  if (runtime.dryRun) {
@@ -48271,7 +46516,7 @@ function applyKxmPackageUpdate(runtime, notice) {
48271
46516
  for (const step of planned) {
48272
46517
  if (step.kind === "verify") {
48273
46518
  if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
48274
- const actual = existsSync38(step.path) ? createHash16("sha256").update(readFileSync37(step.path)).digest("hex") : "missing";
46519
+ const actual = existsSync37(step.path) ? createHash15("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
48275
46520
  return {
48276
46521
  ok: false,
48277
46522
  error: "release_digest_mismatch",
@@ -48288,7 +46533,7 @@ function applyKxmPackageUpdate(runtime, notice) {
48288
46533
  }
48289
46534
  return { ok: true, detail: `installed ${notice.latest} from ${notice.source}` };
48290
46535
  } finally {
48291
- rmSync13(releaseDir, { recursive: true, force: true });
46536
+ rmSync12(releaseDir, { recursive: true, force: true });
48292
46537
  }
48293
46538
  }
48294
46539
  async function cmdExplain(runtime, options) {
@@ -48536,13 +46781,13 @@ async function cmdValidate(runtime, fileFlag) {
48536
46781
  return 2;
48537
46782
  }
48538
46783
  const selectedFile = explicitFile || configuredFile;
48539
- const file = selectedFile ? resolve29(runtime.cwd, selectedFile) : void 0;
48540
- if (file && !existsSync38(file)) {
46784
+ const file = selectedFile ? resolve28(runtime.cwd, selectedFile) : void 0;
46785
+ if (file && !existsSync37(file)) {
48541
46786
  printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
48542
46787
  return 1;
48543
46788
  }
48544
46789
  try {
48545
- const raw = file ? readFileSync37(file, "utf8") : inline;
46790
+ const raw = file ? readFileSync36(file, "utf8") : inline;
48546
46791
  const warnings = [];
48547
46792
  const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
48548
46793
  const secretEnvs = definitions.map((definition) => ({
@@ -48567,7 +46812,7 @@ async function cmdValidate(runtime, fileFlag) {
48567
46812
  }
48568
46813
  async function cmdArtifactsExist(runtime, pathFlag) {
48569
46814
  const worker = gateOf(runtime, "artifacts-exist");
48570
- const checked = verifyArtifactExists(runtime.dirs.assets, resolve29(runtime.cwd, pathFlag));
46815
+ const checked = verifyArtifactExists(runtime.dirs.assets, resolve28(runtime.cwd, pathFlag));
48571
46816
  if (!checked.ok) {
48572
46817
  printWorker(
48573
46818
  runtime,
@@ -48586,15 +46831,15 @@ async function cmdArtifactsExist(runtime, pathFlag) {
48586
46831
  return 0;
48587
46832
  }
48588
46833
  async function cmdImprove(runtime, options = {}) {
48589
- const file = options.file ? resolve29(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
48590
- const routingRecords = existsSync38(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
48591
- const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) : join48(runtime.cwd, ".kxm", "candidates");
46834
+ const file = options.file ? resolve28(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
46835
+ const routingRecords = existsSync37(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
46836
+ const candidatesDir = options.outDir ? resolve28(runtime.cwd, options.outDir) : join47(runtime.cwd, ".kxm", "candidates");
48592
46837
  const report2 = buildImprovementReport(routingRecords, {
48593
46838
  candidatesDir,
48594
46839
  projectRoot: runtime.cwd,
48595
46840
  dryRun: runtime.dryRun
48596
46841
  });
48597
- const reportDir = join48(runtime.dirs.assets, "improvements");
46842
+ const reportDir = join47(runtime.dirs.assets, "improvements");
48598
46843
  const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
48599
46844
  const text = formatImprovementReport(report2);
48600
46845
  print(runtime.io, runtime.json, {
@@ -48726,9 +46971,9 @@ async function maybeOfferCompletionInstall(runtime) {
48726
46971
  if (!pathNeeded) {
48727
46972
  const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
48728
46973
  const { rcFile } = completionRcTarget(shell, { env: runtime.env });
48729
- if (rcFile && existsSync38(rcFile)) {
46974
+ if (rcFile && existsSync37(rcFile)) {
48730
46975
  try {
48731
- if (readFileSync37(rcFile, "utf8").includes(scriptPath)) return;
46976
+ if (readFileSync36(rcFile, "utf8").includes(scriptPath)) return;
48732
46977
  } catch {
48733
46978
  }
48734
46979
  }
@@ -48860,7 +47105,7 @@ async function cmdRoutingReport(runtime, options) {
48860
47105
  let catalog;
48861
47106
  if (includeEquivalentListCost) {
48862
47107
  try {
48863
- const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) : join48(runtime.dirs.workspace, "prices.yaml");
47108
+ const pricesPath = options.prices ? resolve28(runtime.cwd, options.prices) : join47(runtime.dirs.workspace, "prices.yaml");
48864
47109
  catalog = loadPriceCatalog(pricesPath);
48865
47110
  } catch {
48866
47111
  }
@@ -49092,23 +47337,12 @@ function createProgram(ctx, result) {
49092
47337
  writeErr: (text) => ctx.io.stderr(text)
49093
47338
  }).helpCommand("help", "Show help");
49094
47339
  addGlobalOptions(program2);
49095
- program2.command("init").description("Create, validate, or plan migration of a KXM project").option("--json", "Print machine-readable JSON").option("--dry-run", "Plan without making changes").option("--name <name>", "Project display name for a new project").option("--project-id <id>", "Stable project ID for controlled provisioning").option("--repository <id=absolute-path>", "Bind a member repository outside Git configuration", (value, previous) => [...previous, value], []).action(async function initAction(options) {
47340
+ program2.command("init").description("Create, validate, repair, or join a KXM project").option("--json", "Print machine-readable JSON").option("--dry-run", "Plan without making changes").option("--name <name>", "Project display name for a new project").option("--project-id <id>", "Stable project ID for controlled provisioning").option("--repository <id=absolute-path>", "Bind a member repository outside Git configuration", (value, previous) => [...previous, value], []).action(async function initAction(options) {
49096
47341
  result.code = await cmdKxmInit(runtimeFrom(ctx, this), options, {
49097
47342
  maybeOfferCompletionInstall,
49098
47343
  maybeOfferGuideSetup
49099
47344
  });
49100
47345
  });
49101
- const migrate = addGlobalOptions(program2.command("migrate").description("Plan, apply, and verify legacy JSON configuration migration"));
49102
- migrate.helpCommand("help", "Show migrate help");
49103
- addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-KXM migration plan without writes")).action(async function migratePlanAction() {
49104
- result.code = await cmdKxmMigratePlan(runtimeFrom(ctx, this));
49105
- });
49106
- addGlobalOptions(migrate.command("apply").description("Install a reviewed migration with a hash-linked receipt")).option("--decisions <file>", "Reviewed kxm.migration-decision.v1 YAML file").option("--project-id <id>", "Stable project ID for controlled provisioning").option("--name <name>", "Project display name").action(async function migrateApplyAction(options) {
49107
- result.code = await cmdKxmMigrateApply(runtimeFrom(ctx, this), options);
49108
- });
49109
- addGlobalOptions(migrate.command("verify").description("Verify a migration receipt against current sources and target bundle")).action(async function migrateVerifyAction() {
49110
- result.code = await cmdKxmMigrateVerify(runtimeFrom(ctx, this));
49111
- });
49112
47346
  addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of all stores with a hashed manifest")).option("--out <dir>", "Directory to write backup and manifest").action(async function backupAction(options) {
49113
47347
  result.code = await cmdBackup(runtimeFrom(ctx, this), options);
49114
47348
  });
@@ -49565,7 +47799,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
49565
47799
  throw error;
49566
47800
  }
49567
47801
  }
49568
- if (process.argv[1] && resolve30(process.argv[1]) === fileURLToPath4(import.meta.url)) {
47802
+ if (process.argv[1] && resolve29(process.argv[1]) === fileURLToPath4(import.meta.url)) {
49569
47803
  const code = await runCli(process.argv.slice(2));
49570
47804
  process.exitCode = code;
49571
47805
  }