@kontextmind/kxm 0.7.97 → 0.7.98

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.
Files changed (43) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/workflows/default.yaml +2 -0
  3. package/CHANGELOG.md +39 -2
  4. package/docs/concepts/architecture.md +1 -1
  5. package/docs/concepts/data-and-storage.md +1 -1
  6. package/docs/contracts/routing.md +1 -1
  7. package/docs/contributing/test-matrix.md +6 -5
  8. package/docs/operations/backup-and-restore.md +43 -24
  9. package/docs/operations/deploy.md +1 -1
  10. package/docs/reference/cli-reference.md +59 -24
  11. package/docs/reference/config-reference.md +24 -13
  12. package/docs/reference/harness-routing.md +3 -3
  13. package/docs/reference/http-api.md +1 -1
  14. package/docs/start/first-workflow.md +4 -4
  15. package/docs/start/quickstart-claude-code.md +2 -2
  16. package/package.json +1 -1
  17. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  18. package/plugins/kxm/dist/cli.js +393 -154
  19. package/plugins/kxm/dist/core.js +5 -2
  20. package/plugins/kxm/dist/mcp-server.js +1 -1
  21. package/plugins/kxm/dist/runtime-supervisor.js +231 -48
  22. package/plugins/kxm/dist/runtime.js +415 -92
  23. package/plugins/kxm/dist/server.js +7 -0
  24. package/plugins/kxm/package.json +1 -1
  25. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +4 -3
  26. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +3 -2
  27. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +3 -0
  28. package/plugins/kxm/skills/kxm-runs/SKILL.md +8 -7
  29. package/plugins/kxm/src/cli/project.ts +22 -13
  30. package/plugins/kxm/src/cli/system.ts +22 -1
  31. package/plugins/kxm/src/cli.ts +11 -3
  32. package/plugins/kxm/src/database.ts +210 -36
  33. package/plugins/kxm/src/engine.ts +117 -2
  34. package/plugins/kxm/src/harness.ts +29 -0
  35. package/plugins/kxm/src/init-guide-setup.ts +43 -28
  36. package/plugins/kxm/src/mcp-server.ts +1 -1
  37. package/plugins/kxm/src/oneshot-producer.ts +16 -8
  38. package/plugins/kxm/src/prices.ts +33 -2
  39. package/plugins/kxm/src/routing.ts +13 -7
  40. package/plugins/kxm/src/studio-layout.ts +5 -4
  41. package/plugins/kxm/src/template.ts +31 -0
  42. package/plugins/kxm/src/worktree-witness.ts +71 -0
  43. package/schemas/backup-manifest.schema.json +33 -0
@@ -163,10 +163,10 @@ var require_code = __commonJS({
163
163
  function interpolate(x) {
164
164
  return typeof x == "number" || typeof x == "boolean" || x === null ? x : safeStringify(Array.isArray(x) ? x.join(",") : x);
165
165
  }
166
- function stringify4(x) {
166
+ function stringify5(x) {
167
167
  return new _Code(safeStringify(x));
168
168
  }
169
- exports.stringify = stringify4;
169
+ exports.stringify = stringify5;
170
170
  function safeStringify(x) {
171
171
  return JSON.stringify(x).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
172
172
  }
@@ -8917,7 +8917,7 @@ var require_stringify = __commonJS({
8917
8917
  props.push(doc.directives.tagString(tag));
8918
8918
  return props.join(" ");
8919
8919
  }
8920
- function stringify4(item, ctx, onComment, onChompKeep) {
8920
+ function stringify5(item, ctx, onComment, onChompKeep) {
8921
8921
  if (identity.isPair(item))
8922
8922
  return item.toString(ctx, onComment, onChompKeep);
8923
8923
  if (identity.isAlias(item)) {
@@ -8946,7 +8946,7 @@ var require_stringify = __commonJS({
8946
8946
  ${ctx.indent}${str}`;
8947
8947
  }
8948
8948
  exports.createStringifyContext = createStringifyContext;
8949
- exports.stringify = stringify4;
8949
+ exports.stringify = stringify5;
8950
8950
  }
8951
8951
  });
8952
8952
 
@@ -8956,7 +8956,7 @@ var require_stringifyPair = __commonJS({
8956
8956
  "use strict";
8957
8957
  var identity = require_identity();
8958
8958
  var Scalar = require_Scalar();
8959
- var stringify4 = require_stringify();
8959
+ var stringify5 = require_stringify();
8960
8960
  var stringifyComment = require_stringifyComment();
8961
8961
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
8962
8962
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
@@ -8978,7 +8978,7 @@ var require_stringifyPair = __commonJS({
8978
8978
  });
8979
8979
  let keyCommentDone = false;
8980
8980
  let chompKeep = false;
8981
- let str = stringify4.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
8981
+ let str = stringify5.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
8982
8982
  if (!explicitKey && !ctx.inFlow && str.length > 1024) {
8983
8983
  if (simpleKeys)
8984
8984
  throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
@@ -9030,7 +9030,7 @@ ${indent}:`;
9030
9030
  ctx.indent = ctx.indent.substring(2);
9031
9031
  }
9032
9032
  let valueCommentDone = false;
9033
- const valueStr = stringify4.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
9033
+ const valueStr = stringify5.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
9034
9034
  let ws = " ";
9035
9035
  if (keyComment || vsb || vcb) {
9036
9036
  ws = vsb ? "\n" : "";
@@ -9171,7 +9171,7 @@ var require_addPairToJSMap = __commonJS({
9171
9171
  "use strict";
9172
9172
  var log = require_log();
9173
9173
  var merge = require_merge();
9174
- var stringify4 = require_stringify();
9174
+ var stringify5 = require_stringify();
9175
9175
  var identity = require_identity();
9176
9176
  var toJS = require_toJS();
9177
9177
  function addPairToJSMap(ctx, map, { key, value }) {
@@ -9207,7 +9207,7 @@ var require_addPairToJSMap = __commonJS({
9207
9207
  if (typeof jsKey !== "object")
9208
9208
  return String(jsKey);
9209
9209
  if (identity.isNode(key) && ctx?.doc) {
9210
- const strCtx = stringify4.createStringifyContext(ctx.doc, {});
9210
+ const strCtx = stringify5.createStringifyContext(ctx.doc, {});
9211
9211
  strCtx.anchors = /* @__PURE__ */ new Set();
9212
9212
  for (const node of ctx.anchors.keys())
9213
9213
  strCtx.anchors.add(node.anchor);
@@ -9274,12 +9274,12 @@ var require_stringifyCollection = __commonJS({
9274
9274
  "node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
9275
9275
  "use strict";
9276
9276
  var identity = require_identity();
9277
- var stringify4 = require_stringify();
9277
+ var stringify5 = require_stringify();
9278
9278
  var stringifyComment = require_stringifyComment();
9279
9279
  function stringifyCollection(collection, ctx, options) {
9280
9280
  const flow = ctx.inFlow ?? collection.flow;
9281
- const stringify5 = flow ? stringifyFlowCollection : stringifyBlockCollection;
9282
- return stringify5(collection, ctx, options);
9281
+ const stringify6 = flow ? stringifyFlowCollection : stringifyBlockCollection;
9282
+ return stringify6(collection, ctx, options);
9283
9283
  }
9284
9284
  function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
9285
9285
  const { indent, options: { commentString } } = ctx;
@@ -9304,7 +9304,7 @@ var require_stringifyCollection = __commonJS({
9304
9304
  }
9305
9305
  }
9306
9306
  chompKeep = false;
9307
- let str2 = stringify4.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
9307
+ let str2 = stringify5.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
9308
9308
  if (comment2)
9309
9309
  str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
9310
9310
  if (chompKeep && comment2)
@@ -9371,7 +9371,7 @@ ${indent}${line}` : "\n";
9371
9371
  }
9372
9372
  if (comment)
9373
9373
  reqNewline = true;
9374
- let str = stringify4.stringify(item, itemCtx, () => comment = null);
9374
+ let str = stringify5.stringify(item, itemCtx, () => comment = null);
9375
9375
  reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
9376
9376
  if (i < items.length - 1) {
9377
9377
  str += ",";
@@ -10732,7 +10732,7 @@ var require_stringifyDocument = __commonJS({
10732
10732
  "node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
10733
10733
  "use strict";
10734
10734
  var identity = require_identity();
10735
- var stringify4 = require_stringify();
10735
+ var stringify5 = require_stringify();
10736
10736
  var stringifyComment = require_stringifyComment();
10737
10737
  function stringifyDocument(doc, options) {
10738
10738
  const lines = [];
@@ -10747,7 +10747,7 @@ var require_stringifyDocument = __commonJS({
10747
10747
  }
10748
10748
  if (hasDirectives)
10749
10749
  lines.push("---");
10750
- const ctx = stringify4.createStringifyContext(doc, options);
10750
+ const ctx = stringify5.createStringifyContext(doc, options);
10751
10751
  const { commentString } = ctx.options;
10752
10752
  if (doc.commentBefore) {
10753
10753
  if (lines.length !== 1)
@@ -10769,7 +10769,7 @@ var require_stringifyDocument = __commonJS({
10769
10769
  contentComment = doc.contents.comment;
10770
10770
  }
10771
10771
  const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
10772
- let body = stringify4.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
10772
+ let body = stringify5.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
10773
10773
  if (contentComment)
10774
10774
  body += stringifyComment.lineComment(body, "", commentString(contentComment));
10775
10775
  if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
@@ -10777,7 +10777,7 @@ var require_stringifyDocument = __commonJS({
10777
10777
  } else
10778
10778
  lines.push(body);
10779
10779
  } else {
10780
- lines.push(stringify4.stringify(doc.contents, ctx));
10780
+ lines.push(stringify5.stringify(doc.contents, ctx));
10781
10781
  }
10782
10782
  if (doc.directives?.docEnd) {
10783
10783
  if (doc.comment) {
@@ -12913,7 +12913,7 @@ var require_cst_scalar = __commonJS({
12913
12913
  var require_cst_stringify = __commonJS({
12914
12914
  "node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
12915
12915
  "use strict";
12916
- var stringify4 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
12916
+ var stringify5 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
12917
12917
  function stringifyToken(token) {
12918
12918
  switch (token.type) {
12919
12919
  case "block-scalar": {
@@ -12966,7 +12966,7 @@ var require_cst_stringify = __commonJS({
12966
12966
  res += stringifyToken(value);
12967
12967
  return res;
12968
12968
  }
12969
- exports.stringify = stringify4;
12969
+ exports.stringify = stringify5;
12970
12970
  }
12971
12971
  });
12972
12972
 
@@ -14696,7 +14696,7 @@ var require_public_api = __commonJS({
14696
14696
  }
14697
14697
  return doc.toJS(Object.assign({ reviver: _reviver }, options));
14698
14698
  }
14699
- function stringify4(value, replacer, options) {
14699
+ function stringify5(value, replacer, options) {
14700
14700
  let _replacer = null;
14701
14701
  if (typeof replacer === "function" || Array.isArray(replacer)) {
14702
14702
  _replacer = replacer;
@@ -14721,7 +14721,7 @@ var require_public_api = __commonJS({
14721
14721
  exports.parse = parse8;
14722
14722
  exports.parseAllDocuments = parseAllDocuments;
14723
14723
  exports.parseDocument = parseDocument2;
14724
- exports.stringify = stringify4;
14724
+ exports.stringify = stringify5;
14725
14725
  }
14726
14726
  });
14727
14727
 
@@ -15051,6 +15051,35 @@ function coreTemplate(projectId, projectName, variant) {
15051
15051
  }]
15052
15052
  ]);
15053
15053
  if (variant === "v4-registry") {
15054
+ const coordinator = files.get(".kxm/agents/coordinator.yaml");
15055
+ if (coordinator) {
15056
+ files.set(".kxm/agents/coordinator.yaml", {
15057
+ ...coordinator,
15058
+ harness: "claude",
15059
+ model: { provider: "anthropic", model: "fable" }
15060
+ });
15061
+ }
15062
+ const implementer = files.get(".kxm/agents/implementer.yaml");
15063
+ if (implementer) {
15064
+ files.set(".kxm/agents/implementer.yaml", {
15065
+ ...implementer,
15066
+ harness: "grok",
15067
+ model: { provider: "xai", model: "grok-4.6" }
15068
+ });
15069
+ }
15070
+ const workflow = files.get(".kxm/workflows/default.yaml");
15071
+ if (workflow) {
15072
+ const limits = { ...workflow.limits };
15073
+ delete limits.maxAgentTimeMs;
15074
+ files.set(".kxm/workflows/default.yaml", { ...workflow, limits });
15075
+ }
15076
+ files.set(".kxm/routes.yaml", {
15077
+ schema: "kxm.routes.v2",
15078
+ updatedAt: "2026-09-23T00:00:00.000Z",
15079
+ admitted: ["anthropic/fable", "xai/grok-4.6"],
15080
+ disabled: [],
15081
+ roles: { implementer: ["xai/grok-4.6"] }
15082
+ });
15054
15083
  files.set(".kxm/gates.yaml", {
15055
15084
  schema: "kxm.gate-registry.v1",
15056
15085
  gates: { test: { kind: "command", argv: ["npm", "test"], timeoutMs: 36e5 } }
@@ -15601,6 +15630,16 @@ var READ_ONLY_ONESHOT_ARGS = Object.freeze({
15601
15630
  function oneShotReadOnlyArgs(harness) {
15602
15631
  return Object.hasOwn(READ_ONLY_ONESHOT_ARGS, harness) ? READ_ONLY_ONESHOT_ARGS[harness] : void 0;
15603
15632
  }
15633
+ var WRITER_ONESHOT_ARGS = Object.freeze({
15634
+ pi: Object.freeze(["-a", "--no-extensions", "--no-skills", "--no-prompt-templates", "--no-session"]),
15635
+ grok: Object.freeze(["--always-approve", "--no-subagents", "--disable-web-search"])
15636
+ });
15637
+ function oneShotWriterArgs(harness) {
15638
+ return Object.hasOwn(WRITER_ONESHOT_ARGS, harness) ? WRITER_ONESHOT_ARGS[harness] : void 0;
15639
+ }
15640
+ function oneShotPermissionArgs(harness, permission) {
15641
+ return permission === "edit" ? oneShotWriterArgs(harness) : oneShotReadOnlyArgs(harness);
15642
+ }
15604
15643
  var BUILTIN_HARNESSES = Object.freeze([
15605
15644
  {
15606
15645
  id: "pi",
@@ -18374,79 +18413,190 @@ var KXM_BACKUP_CEILINGS = {
18374
18413
  events: 7
18375
18414
  };
18376
18415
  function kxmBackupCeiling(storeId) {
18416
+ if (storeId === "runtime-registry") return KXM_BACKUP_CEILINGS.registry;
18377
18417
  if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
18378
18418
  return KXM_BACKUP_CEILINGS[storeId] ?? KXM_BACKUP_CEILINGS["hub-store"];
18379
18419
  }
18380
- function discoverProjectStores(projectRoot, options = {}) {
18420
+ function pushStore(stores, storeId, sourcePath) {
18421
+ if (stores.some((store) => store.storeId === storeId || store.sourcePath === sourcePath)) return;
18422
+ stores.push({ storeId, sourcePath, maxSupportedVersion: kxmBackupCeiling(storeId) });
18423
+ }
18424
+ function discoverUserRuntime(env, stores, files) {
18425
+ let stateRoot;
18426
+ try {
18427
+ stateRoot = kxmUserStateRoot(env ? { env } : {});
18428
+ } catch {
18429
+ return;
18430
+ }
18431
+ const runtimeDir = join4(stateRoot, "runtime");
18432
+ const registryPath = join4(runtimeDir, "registry.db");
18433
+ if (existsSync4(registryPath)) {
18434
+ const storeId = stores.some((store) => store.storeId === "registry") ? "runtime-registry" : "registry";
18435
+ pushStore(stores, storeId, registryPath);
18436
+ }
18437
+ const projectsDir = join4(runtimeDir, "projects");
18438
+ if (!existsSync4(projectsDir)) return;
18439
+ let entries;
18440
+ try {
18441
+ entries = readdirSync2(projectsDir, { withFileTypes: true });
18442
+ } catch {
18443
+ return;
18444
+ }
18445
+ for (const entry of entries) {
18446
+ if (!entry.isDirectory()) continue;
18447
+ const dbPath = join4(projectsDir, entry.name, "run-events.db");
18448
+ if (!existsSync4(dbPath)) continue;
18449
+ const safe = entry.name.replace(/[^a-zA-Z0-9_.-]/g, "_");
18450
+ let storeId = `events:${safe}`;
18451
+ if (stores.some((store) => store.storeId === storeId)) storeId = `events:runtime:${safe}`;
18452
+ pushStore(stores, storeId, dbPath);
18453
+ const sidecar = `${dbPath}.run-prompts.json`;
18454
+ if (existsSync4(sidecar)) {
18455
+ const id = `${storeId}:run-prompts`;
18456
+ if (!files.some((file) => file.id === id || file.sourcePath === sidecar)) {
18457
+ files.push({ id, sourcePath: sidecar });
18458
+ }
18459
+ }
18460
+ }
18461
+ }
18462
+ function discoverBackupSources(projectRoot, options = {}) {
18381
18463
  const root = resolve3(projectRoot);
18382
18464
  const stores = [];
18465
+ const files = [];
18383
18466
  const hubPath = options.hubDataPath ? resolve3(options.hubDataPath) : join4(root, ".kxm", "state", "kxm.db");
18384
- if (existsSync4(hubPath)) {
18385
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
18386
- }
18467
+ if (existsSync4(hubPath)) pushStore(stores, "hub-store", hubPath);
18387
18468
  const registryPath = join4(root, ".kxm", "runtime", "registry.db");
18388
- if (existsSync4(registryPath)) {
18389
- stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
18390
- }
18469
+ if (existsSync4(registryPath)) pushStore(stores, "registry", registryPath);
18391
18470
  const bindingsPath = join4(root, ".kxm", "runtime", "bindings.db");
18392
- if (existsSync4(bindingsPath)) {
18393
- stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
18394
- }
18471
+ if (existsSync4(bindingsPath)) pushStore(stores, "binding-store", bindingsPath);
18395
18472
  const eventsDir = join4(root, ".kxm", "runtime", "events");
18396
18473
  if (existsSync4(eventsDir)) {
18397
18474
  const entries = readdirSync2(eventsDir, { withFileTypes: true });
18398
18475
  for (const entry of entries) {
18399
18476
  if (entry.isFile() && entry.name.endsWith(".db")) {
18400
- const key = entry.name.replace(/\.db$/, "");
18401
- stores.push({
18402
- storeId: `events:${key}`,
18403
- sourcePath: join4(eventsDir, entry.name),
18404
- maxSupportedVersion: kxmBackupCeiling(`events:${key}`)
18405
- });
18477
+ const key = entry.name.replace(/\.db$/, "").replace(/[^a-zA-Z0-9_.-]/g, "_");
18478
+ pushStore(stores, `events:${key}`, join4(eventsDir, entry.name));
18406
18479
  }
18407
18480
  }
18408
18481
  }
18409
- return stores;
18482
+ discoverUserRuntime(options.env, stores, files);
18483
+ return { stores, files };
18484
+ }
18485
+ function backupPlainFile(sourcePath, targetPath, id) {
18486
+ const resolvedSource = resolve3(sourcePath);
18487
+ const sourceStat = lstatSync2(resolvedSource, { throwIfNoEntry: false });
18488
+ if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
18489
+ throw databaseError("runtime_path_invalid", resolvedSource, `backup file ${resolvedSource} must be a regular file, not a link or directory`);
18490
+ }
18491
+ checkedParent(targetPath, "backup target");
18492
+ if (existsSync4(targetPath)) unlinkSync(targetPath);
18493
+ copyFileSync(resolvedSource, targetPath);
18494
+ try {
18495
+ chmodSync(targetPath, 384);
18496
+ } catch {
18497
+ }
18498
+ return {
18499
+ id,
18500
+ sourcePath: resolvedSource,
18501
+ backupFile: basename2(targetPath),
18502
+ sha256: fileSha256(targetPath),
18503
+ bytes: sourceStat.size
18504
+ };
18505
+ }
18506
+ function backupFilename(sourcePath, id, used) {
18507
+ let filename = basename2(sourcePath);
18508
+ if (used.has(filename)) {
18509
+ filename = `${id.replace(/[^a-zA-Z0-9_.-]/g, "_")}-${filename}`;
18510
+ }
18511
+ used.add(filename);
18512
+ return filename;
18513
+ }
18514
+ function restorePlainFile(backupFilePath, targetPath) {
18515
+ checkedParent(targetPath, "restore target");
18516
+ if (existsSync4(targetPath)) unlinkSync(targetPath);
18517
+ copyFileSync(backupFilePath, targetPath);
18518
+ try {
18519
+ chmodSync(targetPath, 384);
18520
+ } catch {
18521
+ }
18522
+ }
18523
+ function discoverProjectStores(projectRoot, options = {}) {
18524
+ return discoverBackupSources(projectRoot, options).stores;
18525
+ }
18526
+ function backupDiscoverOptions(options) {
18527
+ return {
18528
+ ...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {},
18529
+ ...options.env !== void 0 ? { env: options.env } : {}
18530
+ };
18410
18531
  }
18411
18532
  function planBackup(options = {}) {
18412
18533
  const projectRoot = options.projectRoot ? resolve3(options.projectRoot) : process.cwd();
18413
- const stores = discoverProjectStores(projectRoot, {
18414
- ...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {}
18415
- });
18416
- if (stores.length === 0) {
18534
+ const discovered = discoverBackupSources(projectRoot, backupDiscoverOptions(options));
18535
+ if (discovered.stores.length === 0) {
18417
18536
  throw databaseError("backup_no_stores", projectRoot, "no existing SQLite stores found to backup");
18418
18537
  }
18419
18538
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
18420
18539
  const timestamp = createdAt.replace(/[:.]/g, "-");
18421
18540
  const outDir = options.outDir ? resolve3(options.outDir) : join4(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
18422
18541
  const usedFilenames = /* @__PURE__ */ new Set();
18423
- const planned = stores.map((store) => {
18424
- let filename = basename2(store.sourcePath);
18425
- if (usedFilenames.has(filename)) {
18426
- const sanitizedId = store.storeId.replace(/[^a-zA-Z0-9_.-]/g, "_");
18427
- filename = `${sanitizedId}-${filename}`;
18428
- }
18429
- usedFilenames.add(filename);
18430
- return { storeId: store.storeId, sourcePath: store.sourcePath, backupFile: filename };
18431
- });
18432
- return { projectRoot, outDir, createdAt, stores: planned };
18542
+ const stores = discovered.stores.map((store) => ({
18543
+ storeId: store.storeId,
18544
+ sourcePath: store.sourcePath,
18545
+ backupFile: backupFilename(store.sourcePath, store.storeId, usedFilenames)
18546
+ }));
18547
+ const files = discovered.files.map((file) => ({
18548
+ id: file.id,
18549
+ sourcePath: file.sourcePath,
18550
+ backupFile: backupFilename(file.sourcePath, file.id, usedFilenames)
18551
+ }));
18552
+ return { projectRoot, outDir, createdAt, stores, files };
18433
18553
  }
18434
18554
  function createBackup(options = {}) {
18435
- const { projectRoot, outDir, createdAt, stores } = planBackup(options);
18555
+ const { projectRoot, outDir, createdAt, stores, files } = planBackup(options);
18436
18556
  const backupId = `bk_${randomBytes(8).toString("hex")}`;
18437
18557
  if (!existsSync4(outDir)) {
18438
18558
  mkdirSync(outDir, { recursive: true, mode: 448 });
18439
18559
  }
18440
18560
  const backedUpStores = [];
18561
+ const backedUpFiles = [];
18562
+ const omitted = [];
18441
18563
  for (const store of stores) {
18442
- backedUpStores.push(backupDatabaseFile(store.sourcePath, join4(outDir, store.backupFile), store.storeId));
18564
+ try {
18565
+ backedUpStores.push(backupDatabaseFile(store.sourcePath, join4(outDir, store.backupFile), store.storeId));
18566
+ } catch {
18567
+ omitted.push(store.storeId);
18568
+ }
18569
+ }
18570
+ for (const file of files) {
18571
+ try {
18572
+ backedUpFiles.push(backupPlainFile(file.sourcePath, join4(outDir, file.backupFile), file.id));
18573
+ } catch {
18574
+ omitted.push(file.id);
18575
+ }
18576
+ }
18577
+ if (backedUpStores.length === 0) {
18578
+ throw databaseError("backup_no_stores", projectRoot, "no SQLite store could be copied");
18579
+ }
18580
+ const again = discoverBackupSources(projectRoot, backupDiscoverOptions(options));
18581
+ for (const store of again.stores) {
18582
+ if (!backedUpStores.some((copied) => copied.storeId === store.storeId) && !omitted.includes(store.storeId)) {
18583
+ omitted.push(store.storeId);
18584
+ }
18585
+ }
18586
+ for (const file of again.files) {
18587
+ if (!backedUpFiles.some((copied) => copied.id === file.id) && !omitted.includes(file.id)) {
18588
+ omitted.push(file.id);
18589
+ }
18443
18590
  }
18444
18591
  const manifest = {
18445
18592
  schema: "kxm.backup-manifest.v1",
18446
18593
  backupId,
18447
18594
  createdAt,
18448
18595
  projectRoot,
18449
- stores: backedUpStores
18596
+ stores: backedUpStores,
18597
+ ...backedUpFiles.length > 0 ? { files: backedUpFiles } : {},
18598
+ complete: omitted.length === 0,
18599
+ ...omitted.length > 0 ? { omitted } : {}
18450
18600
  };
18451
18601
  const manifestJson = JSON.stringify(manifest, null, 2) + "\n";
18452
18602
  const manifestSha256 = `sha256:${createHash4("sha256").update(manifestJson, "utf8").digest("hex")}`;
@@ -18479,6 +18629,9 @@ function planRestore(manifestPathOrDir, options = {}) {
18479
18629
  if (manifest.schema !== "kxm.backup-manifest.v1" || !Array.isArray(manifest.stores) || manifest.stores.length === 0) {
18480
18630
  throw databaseError("restore_manifest_invalid", manifestPath, "manifest is not a valid kxm.backup-manifest.v1 document");
18481
18631
  }
18632
+ if (manifest.complete === false) {
18633
+ throw databaseError("restore_incomplete", manifestPath, "backup manifest is incomplete; refusing to restore a partial copy");
18634
+ }
18482
18635
  const stores = [];
18483
18636
  for (const store of manifest.stores) {
18484
18637
  const backupFilePath = join4(manifestDir, store.backupFile);
@@ -18508,7 +18661,28 @@ function planRestore(manifestPathOrDir, options = {}) {
18508
18661
  }
18509
18662
  stores.push({ storeId: store.storeId, backupFilePath, targetPath, schemaVersion: store.schemaVersion, maxSupportedVersion });
18510
18663
  }
18511
- return { manifestPath, backupId: manifest.backupId, stores };
18664
+ const files = [];
18665
+ for (const file of manifest.files ?? []) {
18666
+ const backupFilePath = join4(manifestDir, file.backupFile);
18667
+ if (!existsSync4(backupFilePath)) {
18668
+ throw databaseError("restore_file_missing", backupFilePath, `backup file ${file.backupFile} missing from ${manifestDir}`);
18669
+ }
18670
+ const actualSha256 = fileSha256(backupFilePath);
18671
+ if (actualSha256 !== file.sha256) {
18672
+ throw databaseError(
18673
+ "restore_manifest_digest_mismatch",
18674
+ backupFilePath,
18675
+ `backup file ${file.backupFile} sha256 ${actualSha256} does not match manifest hash ${file.sha256}`
18676
+ );
18677
+ }
18678
+ let targetPath = file.sourcePath;
18679
+ if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
18680
+ const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
18681
+ targetPath = join4(resolve3(options.projectRoot), rel);
18682
+ }
18683
+ files.push({ id: file.id, backupFilePath, targetPath });
18684
+ }
18685
+ return { manifestPath, backupId: manifest.backupId, stores, files };
18512
18686
  }
18513
18687
  function restoreBackup(manifestPathOrDir, options = {}) {
18514
18688
  const plan = planRestore(manifestPathOrDir, options);
@@ -18519,6 +18693,9 @@ function restoreBackup(manifestPathOrDir, options = {}) {
18519
18693
  store.schemaVersion,
18520
18694
  store.maxSupportedVersion
18521
18695
  ));
18696
+ for (const file of plan.files) {
18697
+ restorePlainFile(file.backupFilePath, file.targetPath);
18698
+ }
18522
18699
  return {
18523
18700
  manifestPath: plan.manifestPath,
18524
18701
  backupId: plan.backupId,
@@ -23543,7 +23720,7 @@ function assertKxmConfigError(error) {
23543
23720
  // plugins/kxm/src/runtime-supervisor.ts
23544
23721
  import { spawn as spawn3 } from "node:child_process";
23545
23722
  import { createHash as createHash14, createHmac, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
23546
- import { chmodSync as chmodSync2, existsSync as existsSync15, lstatSync as lstatSync5, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
23723
+ import { chmodSync as chmodSync2, existsSync as existsSync15, lstatSync as lstatSync5, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
23547
23724
  import { createServer } from "node:http";
23548
23725
  import { dirname as dirname11, isAbsolute as isAbsolute6, join as join18 } from "node:path";
23549
23726
 
@@ -23670,7 +23847,7 @@ async function beginOneShotEvidence(root, intent, sensitive) {
23670
23847
  // plugins/kxm/src/prices.ts
23671
23848
  var import_yaml3 = __toESM(require_dist(), 1);
23672
23849
  import { createHash as createHash9 } from "node:crypto";
23673
- import { existsSync as existsSync7, readFileSync as readFileSync5, statSync } from "node:fs";
23850
+ import { existsSync as existsSync7, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync3 } from "node:fs";
23674
23851
  import { join as join8 } from "node:path";
23675
23852
 
23676
23853
  // plugins/kxm/src/price-calc.ts
@@ -23851,7 +24028,7 @@ import { join as join14 } from "node:path";
23851
24028
 
23852
24029
  // plugins/kxm/src/routes.ts
23853
24030
  var import_yaml4 = __toESM(require_dist(), 1);
23854
- import { existsSync as existsSync8, readFileSync as readFileSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
24031
+ import { existsSync as existsSync8, readFileSync as readFileSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync4 } from "node:fs";
23855
24032
  import { join as join9 } from "node:path";
23856
24033
  var RETIRED_POLICY = ".kxm/producers.yaml";
23857
24034
  var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
@@ -23879,6 +24056,55 @@ function isRouteAdmitted(root, modelId) {
23879
24056
  return policy.admitted.includes(modelId) && !policy.disabled.includes(modelId);
23880
24057
  }
23881
24058
 
24059
+ // plugins/kxm/src/worktree-witness.ts
24060
+ import { spawnSync as spawnSync3 } from "node:child_process";
24061
+ function gitText(cwd, args) {
24062
+ const result = spawnSync3("git", ["-C", cwd, ...args], {
24063
+ encoding: "utf8",
24064
+ windowsHide: true,
24065
+ timeout: 15e3
24066
+ });
24067
+ if (result.error || result.status !== 0) return void 0;
24068
+ return result.stdout ?? "";
24069
+ }
24070
+ function captureWorktreeWitness(cwd) {
24071
+ const porcelain = gitText(cwd, ["status", "--porcelain=v1", "-uall"]);
24072
+ const diff = gitText(cwd, ["diff", "--no-ext-diff"]);
24073
+ const staged = gitText(cwd, ["diff", "--cached", "--no-ext-diff"]);
24074
+ if (porcelain === void 0 || diff === void 0 || staged === void 0) {
24075
+ return { unwitnessed: true, fingerprint: "" };
24076
+ }
24077
+ return { unwitnessed: false, fingerprint: `${porcelain}\0${diff}\0${staged}` };
24078
+ }
24079
+ function worktreeChanged(before, after) {
24080
+ if (before.unwitnessed || after.unwitnessed) return false;
24081
+ return before.fingerprint !== after.fingerprint;
24082
+ }
24083
+ function applyAuthoringWitness(result, input) {
24084
+ const changed = worktreeChanged(input.before, input.after);
24085
+ const unwitnessed = input.before.unwitnessed || input.after.unwitnessed;
24086
+ const providerMetadata = { ...result.providerMetadata ?? {} };
24087
+ if (input.writes) {
24088
+ if (unwitnessed || !changed) {
24089
+ providerMetadata.authored = false;
24090
+ providerMetadata.authoringWitness = unwitnessed ? "unwitnessed" : "unchanged";
24091
+ if (result.outcome === "passed") return { ...result, outcome: "failed", providerMetadata };
24092
+ } else {
24093
+ providerMetadata.authored = true;
24094
+ providerMetadata.authoringWitness = "changed";
24095
+ }
24096
+ } else {
24097
+ providerMetadata.authored = false;
24098
+ if (!unwitnessed && changed) {
24099
+ providerMetadata.authoringWitness = "readonly_mutated";
24100
+ if (result.outcome === "passed") return { ...result, outcome: "failed", providerMetadata };
24101
+ } else {
24102
+ providerMetadata.authoringWitness = unwitnessed ? "unwitnessed" : "read-only";
24103
+ }
24104
+ }
24105
+ return { ...result, providerMetadata };
24106
+ }
24107
+
23882
24108
  // plugins/kxm/src/context-packet.ts
23883
24109
  import { randomUUID as randomUUID4 } from "node:crypto";
23884
24110
  var CONTEXT_PACKET_SCHEMA = "kxm.context-packet.v2";
@@ -24146,7 +24372,7 @@ function pruneContextPacket(packet, tokenBudget) {
24146
24372
  }
24147
24373
 
24148
24374
  // plugins/kxm/src/dispatch-context.ts
24149
- import { spawnSync as spawnSync3 } from "node:child_process";
24375
+ import { spawnSync as spawnSync4 } from "node:child_process";
24150
24376
  import { readdirSync as readdirSync7 } from "node:fs";
24151
24377
  import { extname as extname3, join as join12 } from "node:path";
24152
24378
 
@@ -24780,7 +25006,7 @@ function memoryRecordToContextItem(record2, project) {
24780
25006
 
24781
25007
  // plugins/kxm/src/memory.ts
24782
25008
  var import_yaml5 = __toESM(require_dist(), 1);
24783
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
25009
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
24784
25010
  import { extname as extname2, join as join10, resolve as resolve5 } from "node:path";
24785
25011
  var MEMORY_SCHEMA = "kxm.memory.v1";
24786
25012
  var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
@@ -24909,7 +25135,7 @@ function loadAuthoredMemory(repoRoot) {
24909
25135
  // plugins/kxm/src/skills.ts
24910
25136
  var import_yaml6 = __toESM(require_dist(), 1);
24911
25137
  import { createHash as createHash10 } from "node:crypto";
24912
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync6, readFileSync as readFileSync8, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync5 } from "node:fs";
25138
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync6, readFileSync as readFileSync8, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync6 } from "node:fs";
24913
25139
  import { dirname as dirname7, join as join11 } from "node:path";
24914
25140
  var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
24915
25141
  var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
@@ -25013,7 +25239,7 @@ var SkillLifecycle = class {
25013
25239
  return;
25014
25240
  }
25015
25241
  mkdirSync5(dirname7(file), { recursive: true });
25016
- writeFileSync5(file, content);
25242
+ writeFileSync6(file, content);
25017
25243
  }
25018
25244
  dir(state) {
25019
25245
  return join11(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
@@ -25350,7 +25576,7 @@ function gitEnvironment2() {
25350
25576
  return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
25351
25577
  }
25352
25578
  function committedGateGap(projectRoot) {
25353
- const result = spawnSync3("git", [
25579
+ const result = spawnSync4("git", [
25354
25580
  "--no-optional-locks",
25355
25581
  "-C",
25356
25582
  projectRoot,
@@ -27637,6 +27863,14 @@ function prepareDispatch(context, runId, producerId, dispatchSources) {
27637
27863
  return { kind: "return", state, handoff: { ...routeResult.error, stepId } };
27638
27864
  }
27639
27865
  resolvedRoute = routeResult;
27866
+ const writeRefusal = unsupportedLiveWrite(
27867
+ context.projectRoot,
27868
+ step,
27869
+ agentId,
27870
+ resolvedRoute.selector,
27871
+ loadKxmRunPlanEnvelope(context.eventStore, run).projectLimits.maxConcurrentRuns
27872
+ );
27873
+ if (writeRefusal) return { kind: "return", state, handoff: { ...writeRefusal, stepId } };
27640
27874
  }
27641
27875
  const used = state.stepAttempts[stepId] ?? 0;
27642
27876
  if (used >= step.maxAttempts) {
@@ -27845,6 +28079,7 @@ function birthMember(context, input) {
27845
28079
 
27846
28080
  ${generatedPrompt}` : generatedPrompt,
27847
28081
  thinking: input.stepAttempt <= 1 ? "low" : "medium",
28082
+ permission: Object.values(input.step.repositories).some((access) => access === "write") ? "edit" : "read-only",
27848
28083
  contextPacket,
27849
28084
  ...resolvedRoute ? { provider: resolvedRoute.provider, model: resolvedRoute.model } : {}
27850
28085
  },
@@ -27971,7 +28206,18 @@ async function drivePanel(context, panel, producer) {
27971
28206
  if (!executingBound()) return { attemptId: member.attemptId, invoked: false, skipped: true };
27972
28207
  kxmPanelDispatchSeams.beforeInvoke?.(member);
27973
28208
  if (!executingBound()) return { attemptId: member.attemptId, invoked: false, skipped: true };
28209
+ const live = member.producerId !== "driver-simulated";
28210
+ const writes = Object.values(member.step.repositories).some((access) => access === "write");
28211
+ const before = live ? captureWorktreeWitness(context.projectRoot) : void 0;
27974
28212
  const produced = await invokeProducer(producer, member.request);
28213
+ if (live && produced.result && before) {
28214
+ const after = captureWorktreeWitness(context.projectRoot);
28215
+ return {
28216
+ attemptId: member.attemptId,
28217
+ invoked: true,
28218
+ produced: { ...produced, result: applyAuthoringWitness(produced.result, { writes, before, after }) }
28219
+ };
28220
+ }
27975
28221
  return { attemptId: member.attemptId, invoked: true, produced };
27976
28222
  } catch (error) {
27977
28223
  member.controller.abort();
@@ -28609,11 +28855,78 @@ function unsupportedStep(plan, step, producerId) {
28609
28855
  return { reason: "step_unsupported", field: "repositories", detail: `invalid repository access '${access}' on ${repoId}` };
28610
28856
  }
28611
28857
  }
28612
- if (producerId !== "driver-simulated" && Object.values(step.repositories).some((access) => access === "write")) {
28858
+ return void 0;
28859
+ }
28860
+ function readYamlRecord(path) {
28861
+ if (!existsSync11(path)) return void 0;
28862
+ try {
28863
+ const parsed = (0, import_yaml7.parse)(readFileSync9(path, "utf8"));
28864
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
28865
+ } catch {
28866
+ return void 0;
28867
+ }
28868
+ return void 0;
28869
+ }
28870
+ function agentHarness(projectRoot, agentId) {
28871
+ const harness = readYamlRecord(join14(projectRoot, ".kxm", "agents", `${agentId}.yaml`))?.harness;
28872
+ return typeof harness === "string" && harness.length > 0 ? harness : void 0;
28873
+ }
28874
+ function projectDefaultHarness(projectRoot) {
28875
+ const harness = readYamlRecord(join14(projectRoot, ".kxm", "project.yaml"))?.defaultHarness;
28876
+ return typeof harness === "string" && harness.length > 0 ? harness : "pi";
28877
+ }
28878
+ function unsupportedLiveWrite(projectRoot, step, agentId, selector, maxConcurrentRuns) {
28879
+ if (!Object.values(step.repositories).some((access) => access === "write")) return void 0;
28880
+ if (step.assignments.maximum !== 1) {
28881
+ return {
28882
+ reason: "step_unsupported",
28883
+ field: "assignments.maximum",
28884
+ detail: "live write steps run a single assignment; the checkout witness cannot attribute edits between writers"
28885
+ };
28886
+ }
28887
+ if (maxConcurrentRuns !== 1) {
28888
+ return {
28889
+ reason: "step_unsupported",
28890
+ field: "limits.maxConcurrentRuns",
28891
+ detail: "live write steps require limits.maxConcurrentRuns of 1; concurrent runs share one checkout"
28892
+ };
28893
+ }
28894
+ const harness = agentHarness(projectRoot, agentId) ?? projectDefaultHarness(projectRoot);
28895
+ if (!oneShotWriterArgs(harness)) {
28613
28896
  return {
28614
28897
  reason: "step_unsupported",
28615
28898
  field: "repositories",
28616
- detail: "live write steps are unsupported until writer sandboxing witness passes"
28899
+ detail: `live write steps require an audited writer profile; ${harness} has none`
28900
+ };
28901
+ }
28902
+ const rosterPath = join14(projectRoot, ".kxm", "roster.yaml");
28903
+ if (!existsSync11(rosterPath)) return void 0;
28904
+ const roster = readYamlRecord(rosterPath);
28905
+ if (!roster || roster.schema !== "kxm.developer-roster.v1") {
28906
+ return { reason: "step_unsupported", field: "model", detail: "live write steps require a readable kxm.developer-roster.v1" };
28907
+ }
28908
+ const routes = roster.routes;
28909
+ const lineup = roster.lineup;
28910
+ const writerIds = lineup && typeof lineup === "object" && !Array.isArray(lineup) ? lineup.writer : void 0;
28911
+ if (!routes || typeof routes !== "object" || Array.isArray(routes) || !Array.isArray(writerIds)) {
28912
+ return { reason: "step_unsupported", field: "model", detail: "developer roster has no writer lineup" };
28913
+ }
28914
+ const allowed = writerIds.some((id) => {
28915
+ if (typeof id !== "string") return false;
28916
+ const route = routes[id];
28917
+ if (!route || typeof route !== "object" || Array.isArray(route)) return false;
28918
+ const record2 = route;
28919
+ if (record2.harness !== harness || record2.status !== "admitted") return false;
28920
+ if (!Array.isArray(record2.permissions) || !record2.permissions.includes("edit")) return false;
28921
+ const model = typeof record2.model === "string" ? record2.model : "";
28922
+ const vendor = typeof record2.vendor === "string" ? record2.vendor : "";
28923
+ return model === selector || vendor.length > 0 && `${vendor}/${model}` === selector;
28924
+ });
28925
+ if (!allowed) {
28926
+ return {
28927
+ reason: "step_unsupported",
28928
+ field: "model",
28929
+ detail: `live write route ${selector} on ${harness} is not on the developer roster writer lineup`
28617
28930
  };
28618
28931
  }
28619
28932
  return void 0;
@@ -29079,10 +29392,10 @@ function createKxmOneShotProducer(options = {}) {
29079
29392
  if (request.provider) {
29080
29393
  return { provider: request.provider.toLowerCase(), model: request.model, thinking: request.thinking };
29081
29394
  }
29082
- const parsed2 = parseModelString(request.model, harness);
29395
+ const parsed = parseModelString(request.model, harness);
29083
29396
  return {
29084
- provider: request.provider?.toLowerCase() ?? parsed2.provider,
29085
- model: parsed2.model,
29397
+ provider: request.provider?.toLowerCase() ?? parsed.provider,
29398
+ model: parsed.model,
29086
29399
  thinking: request.thinking
29087
29400
  };
29088
29401
  }
@@ -29092,17 +29405,19 @@ function createKxmOneShotProducer(options = {}) {
29092
29405
  if (resolved.provider) {
29093
29406
  return { provider: resolved.provider.toLowerCase(), model: resolved.model, thinking: resolved.thinking };
29094
29407
  }
29095
- const parsed2 = parseModelString(resolved.model, harness);
29408
+ const parsed = parseModelString(resolved.model, harness);
29096
29409
  return {
29097
- provider: resolved.provider?.toLowerCase() ?? parsed2.provider,
29098
- model: parsed2.model,
29410
+ provider: resolved.provider?.toLowerCase() ?? parsed.provider,
29411
+ model: parsed.model,
29099
29412
  thinking: resolved.thinking
29100
29413
  };
29101
29414
  }
29102
29415
  }
29103
- const defaultModel = options.defaultModel ?? (harness === "codex" ? "gpt-5.6-sol" : harness === "kimi" ? "kimi-for-coding" : harness === "agy" ? "gemini-3.8-flash-high" : "claude-3-7-sonnet");
29104
- const parsed = parseModelString(defaultModel, harness);
29105
- return { provider: parsed.provider, model: parsed.model, thinking: request.thinking };
29416
+ if (options.defaultModel) {
29417
+ const parsed = parseModelString(options.defaultModel, harness);
29418
+ return { provider: parsed.provider, model: parsed.model, thinking: request.thinking };
29419
+ }
29420
+ throw new Error("producer_route_not_admitted");
29106
29421
  }
29107
29422
  async function checkAuth(harness, provider, model, env, signal) {
29108
29423
  if (options.inventory) {
@@ -29140,8 +29455,11 @@ function createKxmOneShotProducer(options = {}) {
29140
29455
  if (request.signal.aborted) return cancelled();
29141
29456
  const catalogEntry = (options.catalog ?? BUILTIN_HARNESSES).find((h) => h.id === harness);
29142
29457
  if (!catalogEntry?.oneShot) throw new Error(`oneshot_harness_unsupported: ${harness}`);
29143
- const permissionArgs = oneShotReadOnlyArgs(harness);
29144
- if (!permissionArgs) throw new Error(`oneshot_harness_unsupported: ${harness} permission_profile_unaudited`);
29458
+ const permission = request.permission === "edit" || request.contextPacket?.task.permissionCeiling === "edit" ? "edit" : "read-only";
29459
+ const permissionArgs = oneShotPermissionArgs(harness, permission);
29460
+ if (!permissionArgs) {
29461
+ throw new Error(`oneshot_harness_unsupported: ${harness} ${permission === "edit" ? "writer_profile_unaudited" : "permission_profile_unaudited"}`);
29462
+ }
29145
29463
  const env = { ...options.env ?? process.env };
29146
29464
  let auth;
29147
29465
  try {
@@ -29257,7 +29575,10 @@ Return a final JSON object with an "outcome" field chosen from ${JSON.stringify(
29257
29575
  const outcome = aborted ? "cancelled" : transportFailed || parsed.isError ? "failed" : determineOutcome(parsed.text, request.allowedOutcomes);
29258
29576
  const providerMetadata = {
29259
29577
  processStatus: aborted ? "aborted" : transportFailed ? "failed" : "completed",
29260
- executionEvidenceId: evidence.id
29578
+ executionEvidenceId: evidence.id,
29579
+ permission,
29580
+ permissionProfile: permission === "edit" ? "writer" : "read-only",
29581
+ authored: false
29261
29582
  };
29262
29583
  if (procResult.code !== null && Number.isFinite(procResult.code)) providerMetadata.processExitCode = procResult.code;
29263
29584
  if (procResult.signal) providerMetadata.processSignal = procResult.signal;
@@ -29460,7 +29781,7 @@ var RuntimeHubClient = class {
29460
29781
  };
29461
29782
 
29462
29783
  // plugins/kxm/src/hub-binding.ts
29463
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
29784
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
29464
29785
  import { homedir as homedir2 } from "node:os";
29465
29786
  import { dirname as dirname8, isAbsolute as isAbsolute4, join as join16, resolve as resolve7 } from "node:path";
29466
29787
  var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
@@ -29532,7 +29853,7 @@ function readHubBinding(env = process.env) {
29532
29853
  }
29533
29854
 
29534
29855
  // plugins/kxm/src/hub-env.ts
29535
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
29856
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
29536
29857
  import { homedir as homedir3 } from "node:os";
29537
29858
  import { dirname as dirname9, isAbsolute as isAbsolute5, join as join17, resolve as resolve8 } from "node:path";
29538
29859
  var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
@@ -29762,7 +30083,7 @@ function publishKxmSupervisorToken(paths, token) {
29762
30083
  const file = kxmSupervisorTokenFile(paths);
29763
30084
  mkdirSync9(dirname11(file), { recursive: true, mode: 448 });
29764
30085
  const temp = `${file}.${process.pid}.tmp`;
29765
- writeFileSync8(temp, `${token}
30086
+ writeFileSync9(temp, `${token}
29766
30087
  `, { encoding: "utf8", mode: 384 });
29767
30088
  try {
29768
30089
  chmodSync2(temp, 384);
@@ -29807,7 +30128,7 @@ function clearSupervisorError(paths) {
29807
30128
  function recordSupervisorError(paths, message) {
29808
30129
  try {
29809
30130
  mkdirSync9(paths.runtimeDir, { recursive: true, mode: 448 });
29810
- writeFileSync8(supervisorErrorFile(paths), `${message}
30131
+ writeFileSync9(supervisorErrorFile(paths), `${message}
29811
30132
  `, { encoding: "utf8", mode: 384 });
29812
30133
  } catch {
29813
30134
  }
@@ -31220,7 +31541,7 @@ function createKxmPiProducer(options = {}) {
31220
31541
 
31221
31542
  // plugins/kxm/src/improve.ts
31222
31543
  import { createHash as createHash15 } from "node:crypto";
31223
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "node:fs";
31544
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "node:fs";
31224
31545
  import { join as join20, relative as relative4, resolve as resolve9 } from "node:path";
31225
31546
  var CANDIDATE_SCHEMA = "kxm.candidate.v1";
31226
31547
  var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
@@ -31517,9 +31838,9 @@ function buildImprovementReport(records, options = {}) {
31517
31838
  if (!existsSync16(candidatesDir)) {
31518
31839
  mkdirSync10(candidatesDir, { recursive: true });
31519
31840
  }
31520
- writeFileSync9(diffFilePath, diff, "utf8");
31841
+ writeFileSync10(diffFilePath, diff, "utf8");
31521
31842
  const jsonFilePath = join20(candidatesDir, `${group.candidateId}.json`);
31522
- writeFileSync9(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
31843
+ writeFileSync10(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
31523
31844
  }
31524
31845
  candidates.push(candidate);
31525
31846
  }
@@ -31550,7 +31871,7 @@ function writeImprovementReport(improvementsDir, report, dryRun = false) {
31550
31871
  const path = join20(improvementsDir, `${stamp}.json`);
31551
31872
  if (!dryRun) {
31552
31873
  mkdirSync10(improvementsDir, { recursive: true });
31553
- writeFileSync9(path, `${JSON.stringify(report, null, 2)}
31874
+ writeFileSync10(path, `${JSON.stringify(report, null, 2)}
31554
31875
  `, { encoding: "utf8" });
31555
31876
  }
31556
31877
  return path;
@@ -32340,7 +32661,7 @@ ${divider}
32340
32661
  }
32341
32662
 
32342
32663
  // plugins/kxm/src/ssh-remote.ts
32343
- import { spawnSync as spawnSync4 } from "node:child_process";
32664
+ import { spawnSync as spawnSync5 } from "node:child_process";
32344
32665
  import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync15, readdirSync as readdirSync8, rmSync as rmSync5, statSync as statSync5 } from "node:fs";
32345
32666
  import { homedir as homedir4 } from "node:os";
32346
32667
  import { join as join22, resolve as resolve10 } from "node:path";
@@ -32416,7 +32737,7 @@ function parseSshConfig(configPath) {
32416
32737
  return [];
32417
32738
  }
32418
32739
  }
32419
- function resolveSshHostG(host, execFn = spawnSync4) {
32740
+ function resolveSshHostG(host, execFn = spawnSync5) {
32420
32741
  try {
32421
32742
  const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
32422
32743
  if (result.status !== 0 || !result.stdout) {
@@ -32482,7 +32803,7 @@ function buildSshArgs(options) {
32482
32803
  args.push(options.host);
32483
32804
  return args;
32484
32805
  }
32485
- function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync4) {
32806
+ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync5) {
32486
32807
  const resolvedDir = ensureSocketDir(socketDir);
32487
32808
  const controlPath = join22(resolvedDir, "%C");
32488
32809
  try {
@@ -32494,7 +32815,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
32494
32815
  return false;
32495
32816
  }
32496
32817
  }
32497
- function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync4) {
32818
+ function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync5) {
32498
32819
  const resolvedDir = ensureSocketDir(socketDir);
32499
32820
  const controlPath = join22(resolvedDir, "%C");
32500
32821
  try {
@@ -32528,7 +32849,7 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
32528
32849
  }
32529
32850
  function executeSshRun(params) {
32530
32851
  const startTime = Date.now();
32531
- const execSyncFn = params.execFn ?? spawnSync4;
32852
+ const execSyncFn = params.execFn ?? spawnSync5;
32532
32853
  if (params.action === "info") {
32533
32854
  if (params.host) {
32534
32855
  const hostInfo = resolveSshHostG(params.host, execSyncFn);
@@ -33052,7 +33373,9 @@ export {
33052
33373
  newKxmEvidenceId,
33053
33374
  newKxmObservationId,
33054
33375
  newKxmRunId,
33376
+ oneShotPermissionArgs,
33055
33377
  oneShotReadOnlyArgs,
33378
+ oneShotWriterArgs,
33056
33379
  openDatabase,
33057
33380
  openKxmRuntimeContext,
33058
33381
  parseAgyOneShotUsage,