mu-agent 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +7 -3
  3. package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +6 -0
  4. package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/{chunk-FUXEF6JQ.js → chunk-4O2SCVYF.js} +1 -1
  7. package/dist/bundle/chunks/chunk-AYFRR3OD.js +2 -0
  8. package/dist/bundle/chunks/chunk-FU4XQUSL.js +11 -0
  9. package/dist/bundle/chunks/{chunk-S7SZN6Z3.js → chunk-GNYZK6XN.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-XOBBIK6P.js → chunk-HEMXN7VJ.js} +75 -67
  11. package/dist/bundle/chunks/chunk-MVPXOVOJ.js +2 -0
  12. package/dist/bundle/chunks/chunk-UTB4DTYQ.js +2 -0
  13. package/dist/bundle/chunks/{chunk-WIUZI2CJ.js → chunk-V7IXECST.js} +2 -2
  14. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +2 -0
  15. package/dist/bundle/chunks/github-copilot.js +1 -1
  16. package/dist/bundle/chunks/google-generative-ai-C44KRRZ4.js +2 -0
  17. package/dist/bundle/chunks/google-vertex-25DUXPTJ.js +2 -0
  18. package/dist/bundle/chunks/meta.js +2 -0
  19. package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +5 -0
  20. package/dist/bundle/chunks/{openai-codex-responses-QDSOTBBO.js → openai-codex-responses-3UAYOSSR.js} +2 -2
  21. package/dist/bundle/chunks/{openai-completions-KQPOPEVM.js → openai-completions-FIEQGWAH.js} +3 -3
  22. package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +2 -0
  23. package/dist/bundle/chunks/{openrouter-images-N4XVVFSD.js → openrouter-images-JVEJN44Q.js} +1 -1
  24. package/dist/bundle/chunks/{pi-messages-GFKBWJHZ.js → pi-messages-TM5SOOIW.js} +2 -2
  25. package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +2 -0
  26. package/dist/bundle/chunks/{virtual-modules-MYFARBUK.js → virtual-modules-V7SXVVLP.js} +1 -1
  27. package/dist/bundle/cli-runtime.js +3 -0
  28. package/dist/bundle/cli.js +4 -2
  29. package/dist/bundle/index.js +1 -1
  30. package/dist/bundle/rpc-entry.js +1 -1
  31. package/dist/core/export-html/template.css +10 -0
  32. package/dist/core/export-html/template.js +56 -18
  33. package/dist/modes/interactive/theme/theme-controller.d.ts +6 -0
  34. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  35. package/dist/modes/interactive/theme/theme-controller.js +41 -3
  36. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  37. package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
  38. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
  39. package/dist/modes/interactive/theme/theme-json.js +3 -1
  40. package/dist/modes/interactive/theme/theme-json.js.map +1 -1
  41. package/dist/modes/interactive/theme/theme-schema.json +7 -2
  42. package/dist/modes/interactive/theme/theme.d.ts +40 -7
  43. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  44. package/dist/modes/interactive/theme/theme.js +122 -214
  45. package/dist/modes/interactive/theme/theme.js.map +1 -1
  46. package/docs/cli-integration.md +106 -0
  47. package/docs/cli.md +268 -0
  48. package/docs/compaction.md +45 -26
  49. package/docs/configuration.md +45 -0
  50. package/docs/containerization.md +109 -82
  51. package/docs/custom-provider.md +109 -722
  52. package/docs/docs.json +139 -99
  53. package/docs/environment-variables.md +3 -5
  54. package/docs/extensions.md +137 -2953
  55. package/docs/how-pi-works.md +49 -0
  56. package/docs/images/interactive-mode.png +0 -0
  57. package/docs/index.md +24 -69
  58. package/docs/json.md +193 -65
  59. package/docs/keybindings.md +57 -102
  60. package/docs/llama-cpp.md +3 -3
  61. package/docs/message-types.md +261 -0
  62. package/docs/models.md +64 -546
  63. package/docs/packages.md +67 -166
  64. package/docs/prompt-templates.md +31 -68
  65. package/docs/providers.md +102 -232
  66. package/docs/quickstart.md +61 -106
  67. package/docs/rpc-commands.md +854 -0
  68. package/docs/rpc-extension-ui.md +200 -0
  69. package/docs/rpc.md +129 -1556
  70. package/docs/sdk.md +76 -1160
  71. package/docs/security.md +70 -32
  72. package/docs/session-format.md +25 -216
  73. package/docs/sessions.md +35 -141
  74. package/docs/settings.md +109 -387
  75. package/docs/shell-aliases.md +85 -5
  76. package/docs/skills.md +51 -190
  77. package/docs/slash-commands.md +60 -0
  78. package/docs/terminal-setup.md +105 -78
  79. package/docs/termux.md +74 -83
  80. package/docs/themes.md +71 -279
  81. package/docs/tmux.md +31 -39
  82. package/docs/tui.md +74 -910
  83. package/docs/usage.md +54 -272
  84. package/docs/windows.md +43 -17
  85. package/examples/README.md +13 -2
  86. package/examples/extensions/README.md +1 -0
  87. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  88. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  89. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  90. package/examples/extensions/debug-provider.ts +90 -0
  91. package/examples/extensions/gondolin/package-lock.json +2 -2
  92. package/examples/extensions/gondolin/package.json +1 -1
  93. package/examples/extensions/sandbox/package-lock.json +2 -2
  94. package/examples/extensions/sandbox/package.json +1 -1
  95. package/examples/extensions/with-deps/package-lock.json +2 -2
  96. package/examples/extensions/with-deps/package.json +1 -1
  97. package/examples/plugins/pi-example-plugin/src/session.ts +3 -2
  98. package/examples/rpc-client.ts +35 -0
  99. package/examples/rpc-extension-ui.ts +25 -5
  100. package/examples/sdk/README.md +1 -1
  101. package/judge/dist/auth.js +166 -28
  102. package/judge/dist/chrome.js +12 -1
  103. package/judge/dist/kyrn-judge.js +1424 -589
  104. package/judge/dist/setup.js +2051 -0
  105. package/judge/manifest.json +13 -13
  106. package/judge/skills/mu-browser/SKILL.md +1 -0
  107. package/kyrn/bin/kyrn-doctor +107 -18
  108. package/kyrn/bin/mu.mjs +389 -29
  109. package/package.json +4 -4
  110. package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +0 -6
  111. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +0 -2
  112. package/dist/bundle/chunks/chunk-6R7UI4IY.js +0 -2
  113. package/dist/bundle/chunks/chunk-CK5Z65DM.js +0 -2
  114. package/dist/bundle/chunks/chunk-RCZIEVGO.js +0 -11
  115. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +0 -2
  116. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +0 -2
  117. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +0 -5
  118. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +0 -2
  119. package/docs/development.md +0 -90
@@ -53,7 +53,7 @@ var pi_host_modules_exports = {};
53
53
  __export(pi_host_modules_exports, {
54
54
  VIRTUAL_MODULES: () => VIRTUAL_MODULES
55
55
  });
56
- import { VIRTUAL_MODULES } from "../../dist/bundle/chunks/virtual-modules-MYFARBUK.js";
56
+ import { VIRTUAL_MODULES } from "../../dist/bundle/chunks/virtual-modules-V7SXVVLP.js";
57
57
  var init_pi_host_modules = __esm({
58
58
  "pi-host-modules:pi-host-modules"() {
59
59
  "use strict";
@@ -2730,9 +2730,9 @@ var require_dispatcher_base = __commonJS({
2730
2730
  }
2731
2731
  close(callback) {
2732
2732
  if (callback === void 0) {
2733
- return new Promise((resolve13, reject) => {
2733
+ return new Promise((resolve15, reject) => {
2734
2734
  this.close((err, data) => {
2735
- return err ? reject(err) : resolve13(data);
2735
+ return err ? reject(err) : resolve15(data);
2736
2736
  });
2737
2737
  });
2738
2738
  }
@@ -2770,9 +2770,9 @@ var require_dispatcher_base = __commonJS({
2770
2770
  err = null;
2771
2771
  }
2772
2772
  if (callback === void 0) {
2773
- return new Promise((resolve13, reject) => {
2773
+ return new Promise((resolve15, reject) => {
2774
2774
  this.destroy(err, (err2, data) => {
2775
- return err2 ? reject(err2) : resolve13(data);
2775
+ return err2 ? reject(err2) : resolve15(data);
2776
2776
  });
2777
2777
  });
2778
2778
  }
@@ -6638,7 +6638,7 @@ var require_client_h1 = __commonJS({
6638
6638
  kHTTPContext,
6639
6639
  kClosed
6640
6640
  } = require_symbols();
6641
- var constants3 = require_constants2();
6641
+ var constants4 = require_constants2();
6642
6642
  var EMPTY_BUF = Buffer.alloc(0);
6643
6643
  var FastBuffer = Buffer[Symbol.species];
6644
6644
  var removeAllListeners = util.removeAllListeners;
@@ -6769,7 +6769,7 @@ var require_client_h1 = __commonJS({
6769
6769
  */
6770
6770
  constructor(client, socket, { exports: exports2 }) {
6771
6771
  this.llhttp = exports2;
6772
- this.ptr = this.llhttp.llhttp_alloc(constants3.TYPE.RESPONSE);
6772
+ this.ptr = this.llhttp.llhttp_alloc(constants4.TYPE.RESPONSE);
6773
6773
  this.client = client;
6774
6774
  this.socket = socket;
6775
6775
  this.timeout = null;
@@ -6868,11 +6868,11 @@ var require_client_h1 = __commonJS({
6868
6868
  currentParser = null;
6869
6869
  currentBufferRef = null;
6870
6870
  }
6871
- if (ret !== constants3.ERROR.OK) {
6871
+ if (ret !== constants4.ERROR.OK) {
6872
6872
  const data = chunk.subarray(llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr);
6873
- if (ret === constants3.ERROR.PAUSED_UPGRADE) {
6873
+ if (ret === constants4.ERROR.PAUSED_UPGRADE) {
6874
6874
  this.onUpgrade(data);
6875
- } else if (ret === constants3.ERROR.PAUSED) {
6875
+ } else if (ret === constants4.ERROR.PAUSED) {
6876
6876
  this.paused = true;
6877
6877
  socket.unshift(data);
6878
6878
  } else {
@@ -6907,10 +6907,10 @@ var require_client_h1 = __commonJS({
6907
6907
  } finally {
6908
6908
  currentParser = null;
6909
6909
  }
6910
- if (ret === constants3.ERROR.OK) {
6910
+ if (ret === constants4.ERROR.OK) {
6911
6911
  return null;
6912
6912
  }
6913
- if (ret === constants3.ERROR.PAUSED || ret === constants3.ERROR.PAUSED_UPGRADE) {
6913
+ if (ret === constants4.ERROR.PAUSED || ret === constants4.ERROR.PAUSED_UPGRADE) {
6914
6914
  this.paused = true;
6915
6915
  return null;
6916
6916
  }
@@ -6927,7 +6927,7 @@ var require_client_h1 = __commonJS({
6927
6927
  const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0);
6928
6928
  message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")";
6929
6929
  }
6930
- return new HTTPParserError(message, constants3.ERROR[ret], data);
6930
+ return new HTTPParserError(message, constants4.ERROR[ret], data);
6931
6931
  }
6932
6932
  destroy() {
6933
6933
  assert(currentParser === null);
@@ -7142,7 +7142,7 @@ var require_client_h1 = __commonJS({
7142
7142
  socket[kBlocking] = false;
7143
7143
  client[kResume]();
7144
7144
  }
7145
- return pause ? constants3.ERROR.PAUSED : 0;
7145
+ return pause ? constants4.ERROR.PAUSED : 0;
7146
7146
  }
7147
7147
  /**
7148
7148
  * @param {Buffer} buf
@@ -7168,7 +7168,7 @@ var require_client_h1 = __commonJS({
7168
7168
  }
7169
7169
  this.bytesRead += buf.length;
7170
7170
  if (request.onResponseData(buf) === false) {
7171
- return constants3.ERROR.PAUSED;
7171
+ return constants4.ERROR.PAUSED;
7172
7172
  }
7173
7173
  return 0;
7174
7174
  }
@@ -7208,13 +7208,13 @@ var require_client_h1 = __commonJS({
7208
7208
  if (socket[kWriting]) {
7209
7209
  assert(client[kRunning] === 0);
7210
7210
  util.destroy(socket, new InformationalError("reset"));
7211
- return constants3.ERROR.PAUSED;
7211
+ return constants4.ERROR.PAUSED;
7212
7212
  } else if (!shouldKeepAlive) {
7213
7213
  util.destroy(socket, new InformationalError("reset"));
7214
- return constants3.ERROR.PAUSED;
7214
+ return constants4.ERROR.PAUSED;
7215
7215
  } else if (socket[kReset] && client[kRunning] === 0) {
7216
7216
  util.destroy(socket, new InformationalError("reset"));
7217
- return constants3.ERROR.PAUSED;
7217
+ return constants4.ERROR.PAUSED;
7218
7218
  } else if (client[kPipelining] == null || client[kPipelining] === 1) {
7219
7219
  setImmediate(client[kResume]);
7220
7220
  } else {
@@ -7729,12 +7729,12 @@ upgrade: ${upgrade}\r
7729
7729
  cb();
7730
7730
  }
7731
7731
  }
7732
- const waitForDrain = () => new Promise((resolve13, reject) => {
7732
+ const waitForDrain = () => new Promise((resolve15, reject) => {
7733
7733
  assert(callback === null);
7734
7734
  if (socket[kError]) {
7735
7735
  reject(socket[kError]);
7736
7736
  } else {
7737
- callback = resolve13;
7737
+ callback = resolve15;
7738
7738
  }
7739
7739
  });
7740
7740
  socket.on("close", onDrain).on("drain", onDrain);
@@ -9117,12 +9117,12 @@ var require_client_h2 = __commonJS({
9117
9117
  cb();
9118
9118
  }
9119
9119
  }
9120
- const waitForDrain = () => new Promise((resolve13, reject) => {
9120
+ const waitForDrain = () => new Promise((resolve15, reject) => {
9121
9121
  assert(callback === null);
9122
9122
  if (socket[kError]) {
9123
9123
  reject(socket[kError]);
9124
9124
  } else {
9125
- callback = resolve13;
9125
+ callback = resolve15;
9126
9126
  }
9127
9127
  });
9128
9128
  h2stream.on("close", onDrain).on("drain", onDrain);
@@ -9491,16 +9491,16 @@ var require_client = __commonJS({
9491
9491
  return this[kNeedDrain] < 2;
9492
9492
  }
9493
9493
  [kClose]() {
9494
- return new Promise((resolve13) => {
9494
+ return new Promise((resolve15) => {
9495
9495
  if (this[kSize]) {
9496
- this[kClosedResolve] = resolve13;
9496
+ this[kClosedResolve] = resolve15;
9497
9497
  } else {
9498
- resolve13(null);
9498
+ resolve15(null);
9499
9499
  }
9500
9500
  });
9501
9501
  }
9502
9502
  [kDestroy](err) {
9503
- return new Promise((resolve13) => {
9503
+ return new Promise((resolve15) => {
9504
9504
  const requests = this[kQueue].splice(this[kPendingIdx]);
9505
9505
  for (let i2 = 0; i2 < requests.length; i2++) {
9506
9506
  const request = requests[i2];
@@ -9513,7 +9513,7 @@ var require_client = __commonJS({
9513
9513
  this[kClosedResolve]();
9514
9514
  this[kClosedResolve] = null;
9515
9515
  }
9516
- resolve13(null);
9516
+ resolve15(null);
9517
9517
  };
9518
9518
  if (this[kHTTPContext]) {
9519
9519
  this[kHTTPContext].destroy(err, callback);
@@ -9926,8 +9926,8 @@ var require_pool_base = __commonJS({
9926
9926
  }
9927
9927
  return Promise.all(closeAll);
9928
9928
  } else {
9929
- return new Promise((resolve13) => {
9930
- this[kClosedResolve] = resolve13;
9929
+ return new Promise((resolve15) => {
9930
+ this[kClosedResolve] = resolve15;
9931
9931
  });
9932
9932
  }
9933
9933
  }
@@ -12590,7 +12590,7 @@ var require_readable = __commonJS({
12590
12590
  if (this._readableState.closeEmitted) {
12591
12591
  return Promise.resolve(null);
12592
12592
  }
12593
- return new Promise((resolve13, reject) => {
12593
+ return new Promise((resolve15, reject) => {
12594
12594
  if (this[kContentLength] && this[kContentLength] > limit || this[kBytesRead] > limit) {
12595
12595
  this.destroy(new AbortError2());
12596
12596
  }
@@ -12604,11 +12604,11 @@ var require_readable = __commonJS({
12604
12604
  if (signal.aborted) {
12605
12605
  reject(signal.reason ?? new AbortError2());
12606
12606
  } else {
12607
- resolve13(null);
12607
+ resolve15(null);
12608
12608
  }
12609
12609
  });
12610
12610
  } else {
12611
- this.on("close", resolve13);
12611
+ this.on("close", resolve15);
12612
12612
  }
12613
12613
  this.on("error", noop2).on("data", () => {
12614
12614
  if (this[kBytesRead] > limit) {
@@ -12636,7 +12636,7 @@ var require_readable = __commonJS({
12636
12636
  }
12637
12637
  function consume(stream2, type) {
12638
12638
  assert(!stream2[kConsume]);
12639
- return new Promise((resolve13, reject) => {
12639
+ return new Promise((resolve15, reject) => {
12640
12640
  if (isUnusable(stream2)) {
12641
12641
  const rState = stream2._readableState;
12642
12642
  if (rState.destroyed && rState.closeEmitted === false) {
@@ -12651,7 +12651,7 @@ var require_readable = __commonJS({
12651
12651
  stream2[kConsume] = {
12652
12652
  type,
12653
12653
  stream: stream2,
12654
- resolve: resolve13,
12654
+ resolve: resolve15,
12655
12655
  reject,
12656
12656
  length: 0,
12657
12657
  body: []
@@ -12729,18 +12729,18 @@ var require_readable = __commonJS({
12729
12729
  return buffer;
12730
12730
  }
12731
12731
  function consumeEnd(consume2, encoding) {
12732
- const { type, body, resolve: resolve13, stream: stream2, length } = consume2;
12732
+ const { type, body, resolve: resolve15, stream: stream2, length } = consume2;
12733
12733
  try {
12734
12734
  if (type === "text") {
12735
- resolve13(chunksDecode(body, length, encoding));
12735
+ resolve15(chunksDecode(body, length, encoding));
12736
12736
  } else if (type === "json") {
12737
- resolve13(JSON.parse(chunksDecode(body, length, encoding)));
12737
+ resolve15(JSON.parse(chunksDecode(body, length, encoding)));
12738
12738
  } else if (type === "arrayBuffer") {
12739
- resolve13(chunksConcat(body, length).buffer);
12739
+ resolve15(chunksConcat(body, length).buffer);
12740
12740
  } else if (type === "blob") {
12741
- resolve13(new Blob(body, { type: stream2[kContentType] }));
12741
+ resolve15(new Blob(body, { type: stream2[kContentType] }));
12742
12742
  } else if (type === "bytes") {
12743
- resolve13(chunksConcat(body, length));
12743
+ resolve15(chunksConcat(body, length));
12744
12744
  }
12745
12745
  consumeFinish(consume2);
12746
12746
  } catch (err) {
@@ -12959,9 +12959,9 @@ var require_api_request = __commonJS({
12959
12959
  };
12960
12960
  function request(opts, callback) {
12961
12961
  if (callback === void 0) {
12962
- return new Promise((resolve13, reject) => {
12962
+ return new Promise((resolve15, reject) => {
12963
12963
  request.call(this, opts, (err, data) => {
12964
- return err ? reject(err) : resolve13(data);
12964
+ return err ? reject(err) : resolve15(data);
12965
12965
  });
12966
12966
  });
12967
12967
  }
@@ -13222,9 +13222,9 @@ var require_api_stream = __commonJS({
13222
13222
  };
13223
13223
  function stream2(opts, factory, callback) {
13224
13224
  if (callback === void 0) {
13225
- return new Promise((resolve13, reject) => {
13225
+ return new Promise((resolve15, reject) => {
13226
13226
  stream2.call(this, opts, factory, (err, data) => {
13227
- return err ? reject(err) : resolve13(data);
13227
+ return err ? reject(err) : resolve15(data);
13228
13228
  });
13229
13229
  });
13230
13230
  }
@@ -13524,9 +13524,9 @@ var require_api_upgrade = __commonJS({
13524
13524
  };
13525
13525
  function upgrade(opts, callback) {
13526
13526
  if (callback === void 0) {
13527
- return new Promise((resolve13, reject) => {
13527
+ return new Promise((resolve15, reject) => {
13528
13528
  upgrade.call(this, opts, (err, data) => {
13529
- return err ? reject(err) : resolve13(data);
13529
+ return err ? reject(err) : resolve15(data);
13530
13530
  });
13531
13531
  });
13532
13532
  }
@@ -13620,9 +13620,9 @@ var require_api_connect = __commonJS({
13620
13620
  };
13621
13621
  function connect2(opts, callback) {
13622
13622
  if (callback === void 0) {
13623
- return new Promise((resolve13, reject) => {
13623
+ return new Promise((resolve15, reject) => {
13624
13624
  connect2.call(this, opts, (err, data) => {
13625
- return err ? reject(err) : resolve13(data);
13625
+ return err ? reject(err) : resolve15(data);
13626
13626
  });
13627
13627
  });
13628
13628
  }
@@ -15089,7 +15089,7 @@ var require_snapshot_recorder = __commonJS({
15089
15089
  "node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
15090
15090
  "use strict";
15091
15091
  var { writeFile: writeFile7, readFile: readFile6, mkdir: mkdir2 } = __require("node:fs/promises");
15092
- var { dirname: dirname9, resolve: resolve13 } = __require("node:path");
15092
+ var { dirname: dirname10, resolve: resolve15 } = __require("node:path");
15093
15093
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
15094
15094
  var { InvalidArgumentError, UndiciError } = require_errors();
15095
15095
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -15305,7 +15305,7 @@ var require_snapshot_recorder = __commonJS({
15305
15305
  throw new InvalidArgumentError("Snapshot path is required");
15306
15306
  }
15307
15307
  try {
15308
- const data = await readFile6(resolve13(path), "utf8");
15308
+ const data = await readFile6(resolve15(path), "utf8");
15309
15309
  const parsed = JSON.parse(data);
15310
15310
  if (Array.isArray(parsed)) {
15311
15311
  this.#snapshots.clear();
@@ -15334,8 +15334,8 @@ var require_snapshot_recorder = __commonJS({
15334
15334
  if (!path) {
15335
15335
  throw new InvalidArgumentError("Snapshot path is required");
15336
15336
  }
15337
- const resolvedPath = resolve13(path);
15338
- await mkdir2(dirname9(resolvedPath), { recursive: true });
15337
+ const resolvedPath = resolve15(path);
15338
+ await mkdir2(dirname10(resolvedPath), { recursive: true });
15339
15339
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot2]) => ({
15340
15340
  hash,
15341
15341
  snapshot: snapshot2
@@ -16279,8 +16279,8 @@ var require_dump = __commonJS({
16279
16279
  var require_dns = __commonJS({
16280
16280
  "node_modules/undici/lib/interceptor/dns.js"(exports, module) {
16281
16281
  "use strict";
16282
- var { isIP: isIP3 } = __require("node:net");
16283
- var { lookup } = __require("node:dns");
16282
+ var { isIP: isIP4 } = __require("node:net");
16283
+ var { lookup: lookup2 } = __require("node:dns");
16284
16284
  var DecoratorHandler = require_decorator_handler();
16285
16285
  var { InvalidArgumentError, InformationalError } = require_errors();
16286
16286
  var { kRequestOrigin } = require_symbols();
@@ -16471,7 +16471,7 @@ var require_dns = __commonJS({
16471
16471
  }
16472
16472
  }
16473
16473
  #defaultLookup(origin, opts, cb) {
16474
- lookup(
16474
+ lookup2(
16475
16475
  origin.hostname,
16476
16476
  {
16477
16477
  all: true,
@@ -16690,7 +16690,7 @@ var require_dns = __commonJS({
16690
16690
  return dispatch(origDispatchOpts, handler);
16691
16691
  }
16692
16692
  const origin = origDispatchOpts.origin.constructor === URL ? origDispatchOpts.origin : new URL(origDispatchOpts.origin);
16693
- if (isIP3(origin.hostname) !== 0) {
16693
+ if (isIP4(origin.hostname) !== 0) {
16694
16694
  return dispatch(origDispatchOpts, handler);
16695
16695
  }
16696
16696
  instance.runLookup(origin, origDispatchOpts, (err, newOrigin) => {
@@ -20341,10 +20341,10 @@ var require_headers = __commonJS({
20341
20341
  const lowercaseName = isLowerCase ? name : name.toLowerCase();
20342
20342
  const exists = this.headersMap.get(lowercaseName);
20343
20343
  if (exists) {
20344
- const delimiter = lowercaseName === "cookie" ? "; " : ", ";
20344
+ const delimiter2 = lowercaseName === "cookie" ? "; " : ", ";
20345
20345
  this.headersMap.set(lowercaseName, {
20346
20346
  name: exists.name,
20347
- value: `${exists.value}${delimiter}${value}`
20347
+ value: `${exists.value}${delimiter2}${value}`
20348
20348
  });
20349
20349
  } else {
20350
20350
  this.headersMap.set(lowercaseName, { name, value });
@@ -22998,7 +22998,7 @@ var require_fetch = __commonJS({
22998
22998
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
22999
22999
  return dispatchWithProtocolPreference(body);
23000
23000
  function dispatchWithProtocolPreference(body2, allowH2) {
23001
- return new Promise((resolve13, reject) => agent.dispatch(
23001
+ return new Promise((resolve15, reject) => agent.dispatch(
23002
23002
  {
23003
23003
  path: hasTrailingQuestionMark ? `${path}?` : path,
23004
23004
  origin: url.origin,
@@ -23081,7 +23081,7 @@ var require_fetch = __commonJS({
23081
23081
  }
23082
23082
  }
23083
23083
  const onError = (err) => this.onResponseError(controller, err);
23084
- resolve13({
23084
+ resolve15({
23085
23085
  status,
23086
23086
  statusText,
23087
23087
  headersList,
@@ -23114,7 +23114,7 @@ var require_fetch = __commonJS({
23114
23114
  fetchParams.controller.off("terminated", this.abort);
23115
23115
  }
23116
23116
  if (request.mode === "websocket" && allowH2 !== false && error?.code === "UND_ERR_INFO" && error?.message === "HTTP/2: Extended CONNECT protocol not supported by server") {
23117
- resolve13(dispatchWithProtocolPreference(body2, false));
23117
+ resolve15(dispatchWithProtocolPreference(body2, false));
23118
23118
  return;
23119
23119
  }
23120
23120
  this.body?.destroy(error);
@@ -23131,7 +23131,7 @@ var require_fetch = __commonJS({
23131
23131
  const rawHeaders = controller?.rawHeaders ?? [];
23132
23132
  const headersList = new HeadersList();
23133
23133
  appendHeadersListFromResponseHeaders(headersList, headers, rawHeaders);
23134
- resolve13({
23134
+ resolve15({
23135
23135
  status,
23136
23136
  statusText: STATUS_CODES[status],
23137
23137
  headersList,
@@ -27747,7 +27747,7 @@ var require_p_retry = __commonJS({
27747
27747
  return error;
27748
27748
  };
27749
27749
  var isNetworkError = (errorMessage2) => networkErrorMsgs.includes(errorMessage2);
27750
- var pRetry2 = (input, options) => new Promise((resolve13, reject) => {
27750
+ var pRetry2 = (input, options) => new Promise((resolve15, reject) => {
27751
27751
  options = {
27752
27752
  onFailedAttempt: () => {
27753
27753
  },
@@ -27757,7 +27757,7 @@ var require_p_retry = __commonJS({
27757
27757
  const operation = retry.operation(options);
27758
27758
  operation.attempt(async (attemptNumber) => {
27759
27759
  try {
27760
- resolve13(await input(attemptNumber));
27760
+ resolve15(await input(attemptNumber));
27761
27761
  } catch (error) {
27762
27762
  if (!(error instanceof Error)) {
27763
27763
  reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
@@ -28293,8 +28293,8 @@ var require_retry4 = __commonJS({
28293
28293
  }
28294
28294
  const delay = getNextRetryDelay(config);
28295
28295
  err.config.retryConfig.currentRetryAttempt += 1;
28296
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve13) => {
28297
- setTimeout(resolve13, delay);
28296
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve15) => {
28297
+ setTimeout(resolve15, delay);
28298
28298
  });
28299
28299
  if (config.onRetryAttempt) {
28300
28300
  await config.onRetryAttempt(err);
@@ -28573,8 +28573,8 @@ var require_common2 = __commonJS({
28573
28573
  }
28574
28574
  return debug;
28575
28575
  }
28576
- function extend(namespace, delimiter) {
28577
- const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
28576
+ function extend(namespace, delimiter2) {
28577
+ const newDebug = createDebug(this.namespace + (typeof delimiter2 === "undefined" ? ":" : delimiter2) + namespace);
28578
28578
  newDebug.log = this.log;
28579
28579
  return newDebug;
28580
28580
  }
@@ -29075,8 +29075,8 @@ var require_helpers = __commonJS({
29075
29075
  function req(url, opts = {}) {
29076
29076
  const href = typeof url === "string" ? url : url.href;
29077
29077
  const req2 = (href.startsWith("https:") ? https2 : http3).request(url, opts);
29078
- const promise = new Promise((resolve13, reject) => {
29079
- req2.once("response", resolve13).once("error", reject).end();
29078
+ const promise = new Promise((resolve15, reject) => {
29079
+ req2.once("response", resolve15).once("error", reject).end();
29080
29080
  });
29081
29081
  req2.then = promise.then.bind(promise);
29082
29082
  return req2;
@@ -29253,7 +29253,7 @@ var require_parse_proxy_response = __commonJS({
29253
29253
  var debug_1 = __importDefault(require_src());
29254
29254
  var debug = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
29255
29255
  function parseProxyResponse(socket) {
29256
- return new Promise((resolve13, reject) => {
29256
+ return new Promise((resolve15, reject) => {
29257
29257
  let buffersLength = 0;
29258
29258
  const buffers = [];
29259
29259
  function read() {
@@ -29319,7 +29319,7 @@ var require_parse_proxy_response = __commonJS({
29319
29319
  }
29320
29320
  debug("got proxy server response: %o %o", firstLine4, headers);
29321
29321
  cleanup();
29322
- resolve13({
29322
+ resolve15({
29323
29323
  connect: {
29324
29324
  statusCode,
29325
29325
  statusText,
@@ -29563,7 +29563,7 @@ var require_ponyfill_es2018 = __commonJS({
29563
29563
  return new originalPromise(executor);
29564
29564
  }
29565
29565
  function promiseResolvedWith(value) {
29566
- return newPromise((resolve13) => resolve13(value));
29566
+ return newPromise((resolve15) => resolve15(value));
29567
29567
  }
29568
29568
  function promiseRejectedWith(reason) {
29569
29569
  return originalPromiseReject(reason);
@@ -29733,8 +29733,8 @@ var require_ponyfill_es2018 = __commonJS({
29733
29733
  return new TypeError("Cannot " + name + " a stream using a released reader");
29734
29734
  }
29735
29735
  function defaultReaderClosedPromiseInitialize(reader) {
29736
- reader._closedPromise = newPromise((resolve13, reject) => {
29737
- reader._closedPromise_resolve = resolve13;
29736
+ reader._closedPromise = newPromise((resolve15, reject) => {
29737
+ reader._closedPromise_resolve = resolve15;
29738
29738
  reader._closedPromise_reject = reject;
29739
29739
  });
29740
29740
  }
@@ -29908,8 +29908,8 @@ var require_ponyfill_es2018 = __commonJS({
29908
29908
  }
29909
29909
  let resolvePromise;
29910
29910
  let rejectPromise;
29911
- const promise = newPromise((resolve13, reject) => {
29912
- resolvePromise = resolve13;
29911
+ const promise = newPromise((resolve15, reject) => {
29912
+ resolvePromise = resolve15;
29913
29913
  rejectPromise = reject;
29914
29914
  });
29915
29915
  const readRequest = {
@@ -30014,8 +30014,8 @@ var require_ponyfill_es2018 = __commonJS({
30014
30014
  const reader = this._reader;
30015
30015
  let resolvePromise;
30016
30016
  let rejectPromise;
30017
- const promise = newPromise((resolve13, reject) => {
30018
- resolvePromise = resolve13;
30017
+ const promise = newPromise((resolve15, reject) => {
30018
+ resolvePromise = resolve15;
30019
30019
  rejectPromise = reject;
30020
30020
  });
30021
30021
  const readRequest = {
@@ -31034,8 +31034,8 @@ var require_ponyfill_es2018 = __commonJS({
31034
31034
  }
31035
31035
  let resolvePromise;
31036
31036
  let rejectPromise;
31037
- const promise = newPromise((resolve13, reject) => {
31038
- resolvePromise = resolve13;
31037
+ const promise = newPromise((resolve15, reject) => {
31038
+ resolvePromise = resolve15;
31039
31039
  rejectPromise = reject;
31040
31040
  });
31041
31041
  const readIntoRequest = {
@@ -31347,10 +31347,10 @@ var require_ponyfill_es2018 = __commonJS({
31347
31347
  wasAlreadyErroring = true;
31348
31348
  reason = void 0;
31349
31349
  }
31350
- const promise = newPromise((resolve13, reject) => {
31350
+ const promise = newPromise((resolve15, reject) => {
31351
31351
  stream2._pendingAbortRequest = {
31352
31352
  _promise: void 0,
31353
- _resolve: resolve13,
31353
+ _resolve: resolve15,
31354
31354
  _reject: reject,
31355
31355
  _reason: reason,
31356
31356
  _wasAlreadyErroring: wasAlreadyErroring
@@ -31367,9 +31367,9 @@ var require_ponyfill_es2018 = __commonJS({
31367
31367
  if (state === "closed" || state === "errored") {
31368
31368
  return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
31369
31369
  }
31370
- const promise = newPromise((resolve13, reject) => {
31370
+ const promise = newPromise((resolve15, reject) => {
31371
31371
  const closeRequest = {
31372
- _resolve: resolve13,
31372
+ _resolve: resolve15,
31373
31373
  _reject: reject
31374
31374
  };
31375
31375
  stream2._closeRequest = closeRequest;
@@ -31382,9 +31382,9 @@ var require_ponyfill_es2018 = __commonJS({
31382
31382
  return promise;
31383
31383
  }
31384
31384
  function WritableStreamAddWriteRequest(stream2) {
31385
- const promise = newPromise((resolve13, reject) => {
31385
+ const promise = newPromise((resolve15, reject) => {
31386
31386
  const writeRequest = {
31387
- _resolve: resolve13,
31387
+ _resolve: resolve15,
31388
31388
  _reject: reject
31389
31389
  };
31390
31390
  stream2._writeRequests.push(writeRequest);
@@ -32000,8 +32000,8 @@ var require_ponyfill_es2018 = __commonJS({
32000
32000
  return new TypeError("Cannot " + name + " a stream using a released writer");
32001
32001
  }
32002
32002
  function defaultWriterClosedPromiseInitialize(writer) {
32003
- writer._closedPromise = newPromise((resolve13, reject) => {
32004
- writer._closedPromise_resolve = resolve13;
32003
+ writer._closedPromise = newPromise((resolve15, reject) => {
32004
+ writer._closedPromise_resolve = resolve15;
32005
32005
  writer._closedPromise_reject = reject;
32006
32006
  writer._closedPromiseState = "pending";
32007
32007
  });
@@ -32037,8 +32037,8 @@ var require_ponyfill_es2018 = __commonJS({
32037
32037
  writer._closedPromiseState = "resolved";
32038
32038
  }
32039
32039
  function defaultWriterReadyPromiseInitialize(writer) {
32040
- writer._readyPromise = newPromise((resolve13, reject) => {
32041
- writer._readyPromise_resolve = resolve13;
32040
+ writer._readyPromise = newPromise((resolve15, reject) => {
32041
+ writer._readyPromise_resolve = resolve15;
32042
32042
  writer._readyPromise_reject = reject;
32043
32043
  });
32044
32044
  writer._readyPromiseState = "pending";
@@ -32125,7 +32125,7 @@ var require_ponyfill_es2018 = __commonJS({
32125
32125
  source._disturbed = true;
32126
32126
  let shuttingDown = false;
32127
32127
  let currentWrite = promiseResolvedWith(void 0);
32128
- return newPromise((resolve13, reject) => {
32128
+ return newPromise((resolve15, reject) => {
32129
32129
  let abortAlgorithm;
32130
32130
  if (signal !== void 0) {
32131
32131
  abortAlgorithm = () => {
@@ -32270,7 +32270,7 @@ var require_ponyfill_es2018 = __commonJS({
32270
32270
  if (isError) {
32271
32271
  reject(error);
32272
32272
  } else {
32273
- resolve13(void 0);
32273
+ resolve15(void 0);
32274
32274
  }
32275
32275
  return null;
32276
32276
  }
@@ -32551,8 +32551,8 @@ var require_ponyfill_es2018 = __commonJS({
32551
32551
  let branch1;
32552
32552
  let branch2;
32553
32553
  let resolveCancelPromise;
32554
- const cancelPromise = newPromise((resolve13) => {
32555
- resolveCancelPromise = resolve13;
32554
+ const cancelPromise = newPromise((resolve15) => {
32555
+ resolveCancelPromise = resolve15;
32556
32556
  });
32557
32557
  function pullAlgorithm() {
32558
32558
  if (reading) {
@@ -32643,8 +32643,8 @@ var require_ponyfill_es2018 = __commonJS({
32643
32643
  let branch1;
32644
32644
  let branch2;
32645
32645
  let resolveCancelPromise;
32646
- const cancelPromise = newPromise((resolve13) => {
32647
- resolveCancelPromise = resolve13;
32646
+ const cancelPromise = newPromise((resolve15) => {
32647
+ resolveCancelPromise = resolve15;
32648
32648
  });
32649
32649
  function forwardReaderError(thisReader) {
32650
32650
  uponRejection(thisReader._closedPromise, (r2) => {
@@ -33424,8 +33424,8 @@ var require_ponyfill_es2018 = __commonJS({
33424
33424
  const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1);
33425
33425
  const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy);
33426
33426
  let startPromise_resolve;
33427
- const startPromise = newPromise((resolve13) => {
33428
- startPromise_resolve = resolve13;
33427
+ const startPromise = newPromise((resolve15) => {
33428
+ startPromise_resolve = resolve15;
33429
33429
  });
33430
33430
  InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm);
33431
33431
  SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
@@ -33518,8 +33518,8 @@ var require_ponyfill_es2018 = __commonJS({
33518
33518
  if (stream2._backpressureChangePromise !== void 0) {
33519
33519
  stream2._backpressureChangePromise_resolve();
33520
33520
  }
33521
- stream2._backpressureChangePromise = newPromise((resolve13) => {
33522
- stream2._backpressureChangePromise_resolve = resolve13;
33521
+ stream2._backpressureChangePromise = newPromise((resolve15) => {
33522
+ stream2._backpressureChangePromise_resolve = resolve15;
33523
33523
  });
33524
33524
  stream2._backpressure = backpressure;
33525
33525
  }
@@ -33687,8 +33687,8 @@ var require_ponyfill_es2018 = __commonJS({
33687
33687
  return controller._finishPromise;
33688
33688
  }
33689
33689
  const readable = stream2._readable;
33690
- controller._finishPromise = newPromise((resolve13, reject) => {
33691
- controller._finishPromise_resolve = resolve13;
33690
+ controller._finishPromise = newPromise((resolve15, reject) => {
33691
+ controller._finishPromise_resolve = resolve15;
33692
33692
  controller._finishPromise_reject = reject;
33693
33693
  });
33694
33694
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -33714,8 +33714,8 @@ var require_ponyfill_es2018 = __commonJS({
33714
33714
  return controller._finishPromise;
33715
33715
  }
33716
33716
  const readable = stream2._readable;
33717
- controller._finishPromise = newPromise((resolve13, reject) => {
33718
- controller._finishPromise_resolve = resolve13;
33717
+ controller._finishPromise = newPromise((resolve15, reject) => {
33718
+ controller._finishPromise_resolve = resolve15;
33719
33719
  controller._finishPromise_reject = reject;
33720
33720
  });
33721
33721
  const flushPromise = controller._flushAlgorithm();
@@ -33745,8 +33745,8 @@ var require_ponyfill_es2018 = __commonJS({
33745
33745
  return controller._finishPromise;
33746
33746
  }
33747
33747
  const writable = stream2._writable;
33748
- controller._finishPromise = newPromise((resolve13, reject) => {
33749
- controller._finishPromise_resolve = resolve13;
33748
+ controller._finishPromise = newPromise((resolve15, reject) => {
33749
+ controller._finishPromise_resolve = resolve15;
33750
33750
  controller._finishPromise_reject = reject;
33751
33751
  });
33752
33752
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -34292,7 +34292,7 @@ var require_node_domexception = __commonJS({
34292
34292
  });
34293
34293
 
34294
34294
  // node_modules/fetch-blob/from.js
34295
- import { statSync as statSync4, createReadStream, promises as fs } from "node:fs";
34295
+ import { statSync as statSync5, createReadStream, promises as fs } from "node:fs";
34296
34296
  import { basename as basename4 } from "node:path";
34297
34297
  var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
34298
34298
  var init_from = __esm({
@@ -34302,10 +34302,10 @@ var init_from = __esm({
34302
34302
  init_file();
34303
34303
  init_fetch_blob();
34304
34304
  ({ stat } = fs);
34305
- blobFromSync = (path, type) => fromBlob(statSync4(path), path, type);
34305
+ blobFromSync = (path, type) => fromBlob(statSync5(path), path, type);
34306
34306
  blobFrom = (path, type) => stat(path).then((stat2) => fromBlob(stat2, path, type));
34307
34307
  fileFrom = (path, type) => stat(path).then((stat2) => fromFile(stat2, path, type));
34308
- fileFromSync = (path, type) => fromFile(statSync4(path), path, type);
34308
+ fileFromSync = (path, type) => fromFile(statSync5(path), path, type);
34309
34309
  fromBlob = (stat2, path, type = "") => new fetch_blob_default([new BlobDataItem({
34310
34310
  path,
34311
34311
  size: stat2.size,
@@ -35326,7 +35326,7 @@ var init_get_search = __esm({
35326
35326
  });
35327
35327
 
35328
35328
  // node_modules/node-fetch/src/utils/referrer.js
35329
- import { isIP } from "node:net";
35329
+ import { isIP as isIP3 } from "node:net";
35330
35330
  function stripURLForUseAsAReferrer(url, originOnly = false) {
35331
35331
  if (url == null) {
35332
35332
  return "no-referrer";
@@ -35355,7 +35355,7 @@ function isOriginPotentiallyTrustworthy(url) {
35355
35355
  return true;
35356
35356
  }
35357
35357
  const hostIp = url.host.replace(/(^\[)|(]$)/g, "");
35358
- const hostIPVersion = isIP(hostIp);
35358
+ const hostIPVersion = isIP3(hostIp);
35359
35359
  if (hostIPVersion === 4 && /^127\./.test(hostIp)) {
35360
35360
  return true;
35361
35361
  }
@@ -35715,7 +35715,7 @@ import zlib from "node:zlib";
35715
35715
  import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "node:stream";
35716
35716
  import { Buffer as Buffer3 } from "node:buffer";
35717
35717
  async function fetch3(url, options_) {
35718
- return new Promise((resolve13, reject) => {
35718
+ return new Promise((resolve15, reject) => {
35719
35719
  const request = new Request2(url, options_);
35720
35720
  const { parsedURL, options } = getNodeRequestOptions(request);
35721
35721
  if (!supportedSchemas.has(parsedURL.protocol)) {
@@ -35724,7 +35724,7 @@ async function fetch3(url, options_) {
35724
35724
  if (parsedURL.protocol === "data:") {
35725
35725
  const data = dist_default(request.url);
35726
35726
  const response2 = new Response2(data, { headers: { "Content-Type": data.typeFull } });
35727
- resolve13(response2);
35727
+ resolve15(response2);
35728
35728
  return;
35729
35729
  }
35730
35730
  const send = (parsedURL.protocol === "https:" ? https : http2).request;
@@ -35846,7 +35846,7 @@ async function fetch3(url, options_) {
35846
35846
  if (responseReferrerPolicy) {
35847
35847
  requestOptions.referrerPolicy = responseReferrerPolicy;
35848
35848
  }
35849
- resolve13(fetch3(new Request2(locationURL, requestOptions)));
35849
+ resolve15(fetch3(new Request2(locationURL, requestOptions)));
35850
35850
  finalize();
35851
35851
  return;
35852
35852
  }
@@ -35879,7 +35879,7 @@ async function fetch3(url, options_) {
35879
35879
  const codings = headers.get("Content-Encoding");
35880
35880
  if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
35881
35881
  response = new Response2(body, responseOptions);
35882
- resolve13(response);
35882
+ resolve15(response);
35883
35883
  return;
35884
35884
  }
35885
35885
  const zlibOptions = {
@@ -35893,7 +35893,7 @@ async function fetch3(url, options_) {
35893
35893
  }
35894
35894
  });
35895
35895
  response = new Response2(body, responseOptions);
35896
- resolve13(response);
35896
+ resolve15(response);
35897
35897
  return;
35898
35898
  }
35899
35899
  if (codings === "deflate" || codings === "x-deflate") {
@@ -35917,12 +35917,12 @@ async function fetch3(url, options_) {
35917
35917
  });
35918
35918
  }
35919
35919
  response = new Response2(body, responseOptions);
35920
- resolve13(response);
35920
+ resolve15(response);
35921
35921
  });
35922
35922
  raw.once("end", () => {
35923
35923
  if (!response) {
35924
35924
  response = new Response2(body, responseOptions);
35925
- resolve13(response);
35925
+ resolve15(response);
35926
35926
  }
35927
35927
  });
35928
35928
  return;
@@ -35934,11 +35934,11 @@ async function fetch3(url, options_) {
35934
35934
  }
35935
35935
  });
35936
35936
  response = new Response2(body, responseOptions);
35937
- resolve13(response);
35937
+ resolve15(response);
35938
35938
  return;
35939
35939
  }
35940
35940
  response = new Response2(body, responseOptions);
35941
- resolve13(response);
35941
+ resolve15(response);
35942
35942
  });
35943
35943
  writeToStream(request_, request).catch(reject);
35944
35944
  });
@@ -38965,12 +38965,12 @@ var require_base64_js = __commonJS({
38965
38965
  exports.byteLength = byteLength;
38966
38966
  exports.toByteArray = toByteArray;
38967
38967
  exports.fromByteArray = fromByteArray;
38968
- var lookup = [];
38968
+ var lookup2 = [];
38969
38969
  var revLookup = [];
38970
38970
  var Arr = typeof Uint8Array !== "undefined" ? Uint8Array : Array;
38971
38971
  var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
38972
38972
  for (i2 = 0, len = code.length; i2 < len; ++i2) {
38973
- lookup[i2] = code[i2];
38973
+ lookup2[i2] = code[i2];
38974
38974
  revLookup[code.charCodeAt(i2)] = i2;
38975
38975
  }
38976
38976
  var i2;
@@ -39023,7 +39023,7 @@ var require_base64_js = __commonJS({
39023
39023
  return arr;
39024
39024
  }
39025
39025
  function tripletToBase64(num) {
39026
- return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
39026
+ return lookup2[num >> 18 & 63] + lookup2[num >> 12 & 63] + lookup2[num >> 6 & 63] + lookup2[num & 63];
39027
39027
  }
39028
39028
  function encodeChunk(uint8, start, end) {
39029
39029
  var tmp;
@@ -39046,12 +39046,12 @@ var require_base64_js = __commonJS({
39046
39046
  if (extraBytes === 1) {
39047
39047
  tmp = uint8[len2 - 1];
39048
39048
  parts.push(
39049
- lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "=="
39049
+ lookup2[tmp >> 2] + lookup2[tmp << 4 & 63] + "=="
39050
39050
  );
39051
39051
  } else if (extraBytes === 2) {
39052
39052
  tmp = (uint8[len2 - 2] << 8) + uint8[len2 - 1];
39053
39053
  parts.push(
39054
- lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "="
39054
+ lookup2[tmp >> 10] + lookup2[tmp >> 4 & 63] + lookup2[tmp << 2 & 63] + "="
39055
39055
  );
39056
39056
  }
39057
39057
  return parts.join("");
@@ -42020,7 +42020,7 @@ var require_jwtaccess = __commonJS({
42020
42020
  }
42021
42021
  }
42022
42022
  fromStreamAsync(inputStream) {
42023
- return new Promise((resolve13, reject) => {
42023
+ return new Promise((resolve15, reject) => {
42024
42024
  if (!inputStream) {
42025
42025
  reject(new Error("Must pass in a stream containing the service account auth settings."));
42026
42026
  }
@@ -42029,7 +42029,7 @@ var require_jwtaccess = __commonJS({
42029
42029
  try {
42030
42030
  const data = JSON.parse(s2);
42031
42031
  this.fromJSON(data);
42032
- resolve13();
42032
+ resolve15();
42033
42033
  } catch (err) {
42034
42034
  reject(err);
42035
42035
  }
@@ -42268,7 +42268,7 @@ var require_jwtclient = __commonJS({
42268
42268
  }
42269
42269
  }
42270
42270
  fromStreamAsync(inputStream) {
42271
- return new Promise((resolve13, reject) => {
42271
+ return new Promise((resolve15, reject) => {
42272
42272
  if (!inputStream) {
42273
42273
  throw new Error("Must pass in a stream containing the service account auth settings.");
42274
42274
  }
@@ -42277,7 +42277,7 @@ var require_jwtclient = __commonJS({
42277
42277
  try {
42278
42278
  const data = JSON.parse(s2);
42279
42279
  this.fromJSON(data);
42280
- resolve13();
42280
+ resolve15();
42281
42281
  } catch (e2) {
42282
42282
  reject(e2);
42283
42283
  }
@@ -42410,7 +42410,7 @@ var require_refreshclient = __commonJS({
42410
42410
  }
42411
42411
  }
42412
42412
  async fromStreamAsync(inputStream) {
42413
- return new Promise((resolve13, reject) => {
42413
+ return new Promise((resolve15, reject) => {
42414
42414
  if (!inputStream) {
42415
42415
  return reject(new Error("Must pass in a stream containing the user refresh token."));
42416
42416
  }
@@ -42419,7 +42419,7 @@ var require_refreshclient = __commonJS({
42419
42419
  try {
42420
42420
  const data = JSON.parse(s2);
42421
42421
  this.fromJSON(data);
42422
- return resolve13();
42422
+ return resolve15();
42423
42423
  } catch (err) {
42424
42424
  return reject(err);
42425
42425
  }
@@ -44252,7 +44252,7 @@ var require_pluggable_auth_handler = __commonJS({
44252
44252
  * @return A promise that resolves with the executable response.
44253
44253
  */
44254
44254
  retrieveResponseFromExecutable(envMap) {
44255
- return new Promise((resolve13, reject) => {
44255
+ return new Promise((resolve15, reject) => {
44256
44256
  const child = childProcess.spawn(this.commandComponents[0], this.commandComponents.slice(1), {
44257
44257
  env: { ...process.env, ...Object.fromEntries(envMap) }
44258
44258
  });
@@ -44274,7 +44274,7 @@ var require_pluggable_auth_handler = __commonJS({
44274
44274
  try {
44275
44275
  const responseJson = JSON.parse(output);
44276
44276
  const response = new executable_response_1.ExecutableResponse(responseJson);
44277
- return resolve13(response);
44277
+ return resolve15(response);
44278
44278
  } catch (error) {
44279
44279
  if (error instanceof executable_response_1.ExecutableResponseError) {
44280
44280
  return reject(error);
@@ -45177,7 +45177,7 @@ var require_googleauth = __commonJS({
45177
45177
  }
45178
45178
  }
45179
45179
  fromStreamAsync(inputStream, options) {
45180
- return new Promise((resolve13, reject) => {
45180
+ return new Promise((resolve15, reject) => {
45181
45181
  if (!inputStream) {
45182
45182
  throw new Error("Must pass in a stream containing the Google auth settings.");
45183
45183
  }
@@ -45187,7 +45187,7 @@ var require_googleauth = __commonJS({
45187
45187
  try {
45188
45188
  const data = JSON.parse(chunks.join(""));
45189
45189
  const r2 = this._cacheClientFromJSON(data, options);
45190
- return resolve13(r2);
45190
+ return resolve15(r2);
45191
45191
  } catch (err) {
45192
45192
  if (!this.keyFilename)
45193
45193
  throw err;
@@ -45197,7 +45197,7 @@ var require_googleauth = __commonJS({
45197
45197
  });
45198
45198
  this.cachedCredential = client;
45199
45199
  this.setGapicJWTValues(client);
45200
- return resolve13(client);
45200
+ return resolve15(client);
45201
45201
  }
45202
45202
  } catch (err) {
45203
45203
  return reject(err);
@@ -45233,17 +45233,17 @@ var require_googleauth = __commonJS({
45233
45233
  * Run the Google Cloud SDK command that prints the default project ID
45234
45234
  */
45235
45235
  async getDefaultServiceProjectId() {
45236
- return new Promise((resolve13) => {
45236
+ return new Promise((resolve15) => {
45237
45237
  (0, child_process_1.exec)("gcloud config config-helper --format json", (err, stdout) => {
45238
45238
  if (!err && stdout) {
45239
45239
  try {
45240
45240
  const projectId = JSON.parse(stdout).configuration.properties.core.project;
45241
- resolve13(projectId);
45241
+ resolve15(projectId);
45242
45242
  return;
45243
45243
  } catch (e2) {
45244
45244
  }
45245
45245
  }
45246
- resolve13(null);
45246
+ resolve15(null);
45247
45247
  });
45248
45248
  });
45249
45249
  }
@@ -50266,14 +50266,14 @@ function __asyncValues(o) {
50266
50266
  }, i2);
50267
50267
  function verb(n) {
50268
50268
  i2[n] = o[n] && function(v) {
50269
- return new Promise(function(resolve13, reject) {
50270
- v = o[n](v), settle(resolve13, reject, v.done, v.value);
50269
+ return new Promise(function(resolve15, reject) {
50270
+ v = o[n](v), settle(resolve15, reject, v.done, v.value);
50271
50271
  });
50272
50272
  };
50273
50273
  }
50274
- function settle(resolve13, reject, d, v) {
50274
+ function settle(resolve15, reject, d, v) {
50275
50275
  Promise.resolve(v).then(function(v2) {
50276
- resolve13({ value: v2, done: d });
50276
+ resolve15({ value: v2, done: d });
50277
50277
  }, reject);
50278
50278
  }
50279
50279
  }
@@ -53966,7 +53966,7 @@ function isPlainObject$1(value) {
53966
53966
  return false;
53967
53967
  }
53968
53968
  }
53969
- function formEncoder(sep2) {
53969
+ function formEncoder(sep4) {
53970
53970
  return (key, value, options) => {
53971
53971
  let out = "";
53972
53972
  const pairs = (options === null || options === void 0 ? void 0 : options.explode) ? explode(key, value) : [[key, value]];
@@ -53977,7 +53977,7 @@ function formEncoder(sep2) {
53977
53977
  return (options === null || options === void 0 ? void 0 : options.charEncoding) === "percent" ? encodeURIComponent(v) : v;
53978
53978
  };
53979
53979
  const encodeValue = (v) => encodeString(serializeValue(v));
53980
- const encodedSep = encodeString(sep2);
53980
+ const encodedSep = encodeString(sep4);
53981
53981
  pairs.forEach(([pk, pv]) => {
53982
53982
  var _a2, _b;
53983
53983
  let tmp = "";
@@ -56524,8 +56524,8 @@ var init_event_stream = __esm({
56524
56524
  this.done = false;
56525
56525
  this.isComplete = isComplete;
56526
56526
  this.extractResult = extractResult;
56527
- this.finalResultPromise = new Promise((resolve13) => {
56528
- this.resolveFinalResult = resolve13;
56527
+ this.finalResultPromise = new Promise((resolve15) => {
56528
+ this.resolveFinalResult = resolve15;
56529
56529
  });
56530
56530
  }
56531
56531
  push(event) {
@@ -56558,7 +56558,7 @@ var init_event_stream = __esm({
56558
56558
  } else if (this.done) {
56559
56559
  return;
56560
56560
  } else {
56561
- const result = await new Promise((resolve13) => this.waiting.enqueue(resolve13));
56561
+ const result = await new Promise((resolve15) => this.waiting.enqueue(resolve15));
56562
56562
  if (result.done) return;
56563
56563
  yield result.value;
56564
56564
  }
@@ -57388,6 +57388,7 @@ function buildBaseOptions(model, context, options, apiKey) {
57388
57388
  headers: options?.headers,
57389
57389
  onPayload: options?.onPayload,
57390
57390
  onResponse: options?.onResponse,
57391
+ onProviderStreamEvent: options?.onProviderStreamEvent,
57391
57392
  timeoutMs: options?.timeoutMs,
57392
57393
  websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,
57393
57394
  maxRetries: options?.maxRetries,
@@ -57440,13 +57441,16 @@ function headersToRecord(headers) {
57440
57441
  }
57441
57442
  return result;
57442
57443
  }
57443
- function providerHeadersToRecord(headers) {
57444
- if (!headers) return void 0;
57445
- const result = {};
57446
- for (const [key, value] of Object.entries(headers)) {
57447
- if (value !== null) result[key] = value;
57444
+ function providerHeadersToRecord(...headerSources) {
57445
+ const merged = /* @__PURE__ */ new Map();
57446
+ for (const source of headerSources) {
57447
+ for (const [name, value] of Object.entries(source ?? {})) {
57448
+ const normalizedName = name.toLowerCase();
57449
+ merged.delete(normalizedName);
57450
+ if (value !== null) merged.set(normalizedName, [name, value]);
57451
+ }
57448
57452
  }
57449
- return Object.keys(result).length > 0 ? result : void 0;
57453
+ return merged.size > 0 ? Object.fromEntries(merged.values()) : void 0;
57450
57454
  }
57451
57455
  var init_headers2 = __esm({
57452
57456
  "packages/ai/src/utils/headers.ts"() {
@@ -57497,9 +57501,9 @@ function errorMessage(text6) {
57497
57501
  return text6.slice(0, 500);
57498
57502
  }
57499
57503
  function sleep2(ms, signal) {
57500
- return new Promise((resolve13, reject) => {
57504
+ return new Promise((resolve15, reject) => {
57501
57505
  if (signal?.aborted) return reject(new Error("Request was aborted"));
57502
- const timer = setTimeout(resolve13, ms);
57506
+ const timer = setTimeout(resolve15, ms);
57503
57507
  signal?.addEventListener(
57504
57508
  "abort",
57505
57509
  () => {
@@ -57889,8 +57893,8 @@ var init_cloud_code = __esm({
57889
57893
  });
57890
57894
 
57891
57895
  // packages/kyrn-judge/src/extension/kyrn-judge.ts
57892
- var import_pi_coding_agent12 = __toESM(require_pi_coding_agent(), 1);
57893
- import { homedir as homedir9 } from "node:os";
57896
+ var import_pi_coding_agent13 = __toESM(require_pi_coding_agent(), 1);
57897
+ import { homedir as homedir10 } from "node:os";
57894
57898
 
57895
57899
  // packages/kyrn-judge/src/config.ts
57896
57900
  import { readFileSync } from "node:fs";
@@ -57915,7 +57919,17 @@ function muHome(home = homedir()) {
57915
57919
  var BUILT_IN_JUDGES = {
57916
57920
  jev: { type: "jev" },
57917
57921
  "jev-direct": { type: "typesafe" },
57922
+ // OpenRouter serves Jev over the same System One protocol. The key is Jev's own, not the one for OpenRouter's
57923
+ // chat models, so setting one never changes the other.
57924
+ "jev-openrouter": {
57925
+ type: "typesafe",
57926
+ baseUrl: "https://openrouter.ai/api/v1/systemone",
57927
+ model: "~typesafe/jev-latest",
57928
+ apiKeyEnv: "MU_JUDGE_OPENROUTER_API_KEY"
57929
+ },
57918
57930
  "jev-gateway": { type: "gateway", model: "typesafe-ai/jev" },
57931
+ // CLM-8B on this machine, where `clm-serve` listens by default. Its profile is not measured on mu's questions yet.
57932
+ clm: { type: "clm" },
57919
57933
  // Measured in kyrn/docs/03-local-judge.md: the base checkpoint classifies one text well, says "yes" to
57920
57934
  // nearly every relational question, and cannot use a rubric or judge the request itself.
57921
57935
  laya: { type: "local", profile: { capabilities: { relate: false, rate: false, meta: false } } },
@@ -57959,7 +57973,7 @@ function readJudges(value) {
57959
57973
  if (!isRecord(value)) return judges;
57960
57974
  for (const [name, config] of Object.entries(value)) {
57961
57975
  if (!isRecord(config) || typeof config.type !== "string") continue;
57962
- if (!["jev", "typesafe", "gateway", "local", "http", "llm", "mock"].includes(config.type)) continue;
57976
+ if (!["jev", "typesafe", "clm", "gateway", "local", "http", "llm", "mock"].includes(config.type)) continue;
57963
57977
  judges[name] = config;
57964
57978
  }
57965
57979
  return judges;
@@ -58386,16 +58400,20 @@ function parseBrief(raw) {
58386
58400
  previous: previousTitle && previousReport ? { title: previousTitle, report: previousReport } : void 0
58387
58401
  };
58388
58402
  }
58389
- function briefFor(task, parent) {
58403
+ function briefFor(task, parent, userGoal) {
58390
58404
  const wanted = task.serves?.trim().replace(/^#/, "").toLowerCase();
58391
58405
  const item = wanted ? parent?.acceptance.find((each) => each.id === wanted) : void 0;
58392
58406
  return {
58393
58407
  goal: flat(`${task.title}: ${task.instructions}`, GOAL_CHARS2),
58394
- parentGoal: parent?.goal,
58408
+ parentGoal: parent?.goal ?? text(userGoal, GOAL_CHARS2),
58395
58409
  serves: item ? { id: item.id, text: item.text } : void 0,
58396
58410
  done: (task.done ?? []).map((each) => text(each, ITEM_CHARS2)).filter((each) => each !== void 0).slice(0, MAX_DONE)
58397
58411
  };
58398
58412
  }
58413
+ function subAgentUserGoal(env = process.env) {
58414
+ if (!env.KYRN_SWARM_DEPTH) return void 0;
58415
+ return parseBrief(env[BRIEF_ENV])?.parentGoal ?? "";
58416
+ }
58399
58417
  function briefEnv(brief) {
58400
58418
  const { previous: _previous, lessons: _lessons, ...rest } = brief;
58401
58419
  return JSON.stringify(rest);
@@ -58532,6 +58550,62 @@ function neutralAnswer(question) {
58532
58550
  return { type: "choice", choice: options.find(isEscapeOption) ?? options[0] };
58533
58551
  }
58534
58552
 
58553
+ // packages/kyrn-judge/src/redact.ts
58554
+ var REDACTED = "[redacted]";
58555
+ var SHAPES = [
58556
+ // A private key, the whole block, or to the end when the text was cut inside it.
58557
+ /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY-----|$)/g,
58558
+ // OpenAI, Anthropic, OpenRouter, DeepSeek and the like.
58559
+ /\bsk-[A-Za-z0-9_-]{20,}/g,
58560
+ /\b(?:gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,})/g,
58561
+ /\bglpat-[A-Za-z0-9_-]{20,}/g,
58562
+ /\bxox[abposr]-[A-Za-z0-9-]{10,}/g,
58563
+ /\bAIza[0-9A-Za-z_-]{35}/g,
58564
+ /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
58565
+ /\b[rs]k_(?:live|test)_[0-9A-Za-z]{16,}/g,
58566
+ /\bnpm_[A-Za-z0-9]{36}\b/g,
58567
+ /\bhf_[A-Za-z0-9]{30,}/g,
58568
+ // A JSON web token.
58569
+ /\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g
58570
+ ];
58571
+ var BEARER = /\b(Bearer|Basic)(\s+)(?=[A-Za-z._~+/=-]*[0-9])[A-Za-z0-9._~+/=-]{12,}/g;
58572
+ var URL_PASSWORD = /\b([a-z][a-z0-9+.-]*:\/\/[^\s:@/]+:)[^\s@/]+(@)/gi;
58573
+ var KEY_WORD = "(?:SECRET|TOKEN|PASSWD|PASSWORD|API_?KEY|ACCESS_?KEY|PRIVATE_?KEY)";
58574
+ var ENV_VALUE = new RegExp(`\\b([A-Z0-9_]*${KEY_WORD}[A-Z0-9_]*=)("[^"\\n]{8,}"|'[^'\\n]{8,}'|[^\\s"';&|]{8,})`, "g");
58575
+ var QUOTED_VALUE = new RegExp(
58576
+ `(["']?[A-Za-z0-9_-]*${KEY_WORD.replaceAll("_?", "[_-]?")}[A-Za-z0-9_-]*["']?\\s*[:=]\\s*)(["'])[^"'\\s]{8,}\\2`,
58577
+ "gi"
58578
+ );
58579
+ var LINE_VALUE = new RegExp(
58580
+ `^(\\s*[A-Za-z0-9_.-]*${KEY_WORD.replaceAll("_?", "[_.-]?")}[A-Za-z0-9_.-]*\\s*[:=][ \\t]*)[^\\s#"']{8,}[ \\t]*$`,
58581
+ "gim"
58582
+ );
58583
+ var CREDENTIAL_NAME = /SECRET|TOKEN|PASSWD|PASSWORD|API_?KEY|ACCESS_?KEY|PRIVATE_?KEY|CREDENTIAL/i;
58584
+ function environmentSecrets(env = process.env) {
58585
+ const values = Object.entries(env).flatMap(([name, raw]) => {
58586
+ const value = raw?.trim() ?? "";
58587
+ const secretish = value.length >= 16 || value.length >= 8 && /\d/.test(value);
58588
+ return secretish && CREDENTIAL_NAME.test(name) ? [value] : [];
58589
+ });
58590
+ return [...new Set(values)].sort((a, b) => b.length - a.length);
58591
+ }
58592
+ function redactSecrets(text6, known = []) {
58593
+ let clean2 = text6;
58594
+ for (const secret of known) if (clean2.includes(secret)) clean2 = clean2.split(secret).join(REDACTED);
58595
+ for (const shape of SHAPES) clean2 = clean2.replace(shape, REDACTED);
58596
+ return clean2.replace(BEARER, `$1$2${REDACTED}`).replace(URL_PASSWORD, `$1${REDACTED}$2`).replace(ENV_VALUE, `$1${REDACTED}`).replace(QUOTED_VALUE, `$1$2${REDACTED}$2`).replace(LINE_VALUE, `$1${REDACTED}`);
58597
+ }
58598
+ function redactJson(value, known = []) {
58599
+ if (typeof value === "string") return redactSecrets(value, known);
58600
+ if (Array.isArray(value)) return value.map((item) => redactJson(item, known));
58601
+ if (value && typeof value === "object") {
58602
+ return Object.fromEntries(
58603
+ Object.entries(value).map(([key, item]) => [key, redactJson(item, known)])
58604
+ );
58605
+ }
58606
+ return value;
58607
+ }
58608
+
58535
58609
  // packages/kyrn-judge/src/decision.ts
58536
58610
  var ABSTAIN = /* @__PURE__ */ Symbol("kyrn.judge.abstain");
58537
58611
  var MAX_BATCH_ANSWERS = 8;
@@ -58562,6 +58636,7 @@ var DecisionEngine = class {
58562
58636
  this.modes = new Map(Object.entries(options.modes ?? {}));
58563
58637
  this.recordState = options.recordState ?? false;
58564
58638
  this.origin = options.origin;
58639
+ this.knownSecrets = options.knownSecrets ?? (() => environmentSecrets());
58565
58640
  }
58566
58641
  get providerId() {
58567
58642
  return this.judge.id;
@@ -58620,7 +58695,13 @@ var DecisionEngine = class {
58620
58695
  const capabilities = typeof declared === "string" ? Object.fromEntries(Object.keys(questions).map((id) => [id, declared])) : declared;
58621
58696
  this.stats.calls++;
58622
58697
  try {
58623
- const result = await this.judgeFor(spec.id).evaluate({ state, questions, signal, capabilities });
58698
+ const known = this.knownSecrets();
58699
+ const result = await this.judgeFor(spec.id).evaluate({
58700
+ state: redactJson(state, known),
58701
+ questions: redactJson(questions, known),
58702
+ signal,
58703
+ capabilities
58704
+ });
58624
58705
  this.stats.inputTokens += result.usage.inputTokens ?? 0;
58625
58706
  const evaluation = {
58626
58707
  answers: result.answers,
@@ -59367,7 +59448,7 @@ var CascadeJudge = class {
59367
59448
  const reports = [];
59368
59449
  let requests = 0;
59369
59450
  let modelId;
59370
- let lastError;
59451
+ const errors = [];
59371
59452
  let pending = Object.keys(request.questions);
59372
59453
  const capability = (id) => capabilityOf(request.questions[id], request.capabilities?.[id]);
59373
59454
  for (const [index, tier] of this.tiers.entries()) {
@@ -59382,7 +59463,7 @@ var CascadeJudge = class {
59382
59463
  try {
59383
59464
  result = await tier.judge.evaluate({ state: request.state, questions, signal: request.signal });
59384
59465
  } catch (error) {
59385
- lastError = error;
59466
+ errors.push(error);
59386
59467
  reports.push({
59387
59468
  judgeId: tier.judge.id,
59388
59469
  asked: mine.length,
@@ -59419,8 +59500,10 @@ var CascadeJudge = class {
59419
59500
  const missing = Object.keys(request.questions).filter((id) => !(id in settled));
59420
59501
  if (missing.length > 0) {
59421
59502
  if (reports.every((report3) => report3.error !== void 0)) {
59422
- if (lastError instanceof JudgeError) throw lastError;
59423
- throw new JudgeError("unreachable", "No judge in the cascade answered", { cause: lastError });
59503
+ const lasting = (error) => error instanceof JudgeError && (error.kind === "auth" || error.kind === "payment_required");
59504
+ const telling = [...errors].reverse().find((error) => !lasting(error)) ?? errors.at(-1);
59505
+ if (telling instanceof JudgeError) throw telling;
59506
+ throw new JudgeError("unreachable", "No judge in the cascade answered", { cause: telling });
59424
59507
  }
59425
59508
  for (const id of missing) settled[id] = { ...neutralAnswer(request.questions[id]), judge: "unavailable" };
59426
59509
  }
@@ -59448,7 +59531,8 @@ function messageFromErrorBody(body) {
59448
59531
  if (typeof nestedMessage === "string") return nestedMessage;
59449
59532
  }
59450
59533
  if (typeof nested === "string") return nested;
59451
- return typeof record4.message === "string" ? record4.message : "";
59534
+ if (typeof record4.message === "string") return record4.message;
59535
+ return typeof record4.detail === "string" ? record4.detail : "";
59452
59536
  }
59453
59537
  function readWarnings(value) {
59454
59538
  if (!Array.isArray(value)) return void 0;
@@ -59482,7 +59566,7 @@ var GatewayJudgeProvider = class {
59482
59566
  constructor(options) {
59483
59567
  this.apiKey = options.apiKey;
59484
59568
  this.model = options.model ?? DEFAULT_MODEL;
59485
- this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
59569
+ this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
59486
59570
  this.fetchImpl = options.fetch ?? fetch;
59487
59571
  this.id = `gateway:${this.model}`;
59488
59572
  }
@@ -59634,7 +59718,7 @@ function unitInterval(value) {
59634
59718
  var LocalJudgeProvider = class {
59635
59719
  constructor(options = {}) {
59636
59720
  this.id = options.id ?? "local:laya";
59637
- this.baseUrl = (options.baseUrl ?? DEFAULT_LOCAL_JUDGE_URL).replace(/\/+$/, "");
59721
+ this.baseUrl = (options.baseUrl || DEFAULT_LOCAL_JUDGE_URL).replace(/\/+$/, "");
59638
59722
  this.path = options.path ?? "/evaluate";
59639
59723
  this.headers = options.headers;
59640
59724
  this.fetchImpl = options.fetch ?? fetch;
@@ -59710,6 +59794,15 @@ var MockJudgeProvider = class {
59710
59794
  // packages/kyrn-judge/src/providers/typesafe.ts
59711
59795
  var TYPESAFE_BASE_URL = "https://api.typesafe.ai/v1/systemone";
59712
59796
  var TYPESAFE_DEFAULT_MODEL = "jev-latest";
59797
+ var OPENROUTER_DEFAULT_MODEL = "~typesafe/jev-latest";
59798
+ var CLM_BASE_URL = "http://127.0.0.1:8700";
59799
+ var CLM_DEFAULT_MODEL = "clm-latest";
59800
+ function clmEndpoint(baseUrl) {
59801
+ const url = (baseUrl || CLM_BASE_URL).replace(/\/+$/, "");
59802
+ if (!URL.canParse(url)) return url;
59803
+ const path = new URL(url).pathname;
59804
+ return path === "/" ? `${url}/v1/systemone` : path === "/v1" ? `${url}/systemone` : url;
59805
+ }
59713
59806
  function errorKindForStatus2(status, message) {
59714
59807
  if (status === 401) return "auth";
59715
59808
  if (status === 402) return "payment_required";
@@ -59745,14 +59838,20 @@ function fromWire(question, raw) {
59745
59838
  var TypeSafeJudgeProvider = class {
59746
59839
  constructor(options) {
59747
59840
  this.apiKey = options.apiKey;
59748
- this.model = options.model ?? TYPESAFE_DEFAULT_MODEL;
59749
- this.baseUrl = (options.baseUrl ?? TYPESAFE_BASE_URL).replace(/\/+$/, "");
59841
+ this.keyName = options.keyName ?? "TYPESAFE_API_KEY";
59842
+ this.keyOptional = options.keyOptional ?? false;
59843
+ this.baseUrl = (options.baseUrl || TYPESAFE_BASE_URL).replace(/\/+$/, "");
59750
59844
  this.fetchImpl = options.fetch ?? fetch;
59751
- this.id = `typesafe:${this.model}`;
59845
+ const host2 = URL.canParse(this.baseUrl) ? new URL(this.baseUrl).host : this.baseUrl;
59846
+ const service = host2 === new URL(TYPESAFE_BASE_URL).host ? "TypeSafe" : host2;
59847
+ this.service = options.judgeName ? `${options.judgeName} at ${service}` : service;
59848
+ this.model = options.model || (host2 === "openrouter.ai" ? OPENROUTER_DEFAULT_MODEL : TYPESAFE_DEFAULT_MODEL);
59849
+ this.id = `${service === "TypeSafe" ? "typesafe" : host2}:${this.model}`;
59752
59850
  }
59753
59851
  async evaluate(request) {
59754
59852
  const apiKey = typeof this.apiKey === "string" ? this.apiKey : await this.apiKey();
59755
- if (!apiKey) throw new JudgeError("auth", "No TypeSafe API key is configured (TYPESAFE_API_KEY)");
59853
+ if (!apiKey && !this.keyOptional)
59854
+ throw new JudgeError("auth", `No API key is configured for Jev at ${this.service} (${this.keyName})`);
59756
59855
  const questions = Object.fromEntries(
59757
59856
  Object.entries(request.questions).map(([id, question]) => [id, toWire(question)])
59758
59857
  );
@@ -59760,31 +59859,34 @@ var TypeSafeJudgeProvider = class {
59760
59859
  try {
59761
59860
  response = await this.fetchImpl(this.baseUrl, {
59762
59861
  method: "POST",
59763
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
59862
+ headers: { ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}, "Content-Type": "application/json" },
59764
59863
  body: JSON.stringify({ model: this.model, state: request.state, questions }),
59765
59864
  signal: request.signal
59766
59865
  });
59767
59866
  } catch (error) {
59768
59867
  if (error instanceof Error && error.name === "AbortError") throw error;
59769
- throw new JudgeError("unreachable", "Could not reach TypeSafe", { cause: error });
59868
+ throw new JudgeError("unreachable", `Could not reach ${this.service}`, { cause: error });
59770
59869
  }
59771
59870
  if (!response.ok) {
59772
59871
  const body2 = await response.json().catch(() => void 0);
59773
59872
  const message = messageFromErrorBody(body2).slice(0, MAX_ERROR_MESSAGE_LENGTH);
59873
+ const unkeyed = response.status === 401 && !apiKey && `${this.service} asks for a key (${this.keyName})`;
59774
59874
  throw new JudgeError(
59775
59875
  errorKindForStatus2(response.status, message),
59776
- message || `TypeSafe responded with HTTP ${response.status}`,
59876
+ unkeyed || message || `${this.service} responded with HTTP ${response.status}`,
59777
59877
  { status: response.status }
59778
59878
  );
59779
59879
  }
59780
59880
  const body = await response.json().catch(() => void 0);
59781
59881
  if (!body || typeof body.answers !== "object" || body.answers === null) {
59782
- throw new JudgeError("invalid_response", "TypeSafe response has no answers", { status: response.status });
59882
+ throw new JudgeError("invalid_response", `${this.service} response has no answers`, {
59883
+ status: response.status
59884
+ });
59783
59885
  }
59784
59886
  const answers = {};
59785
59887
  for (const [id, question] of Object.entries(request.questions)) {
59786
59888
  const answer = fromWire(question, body.answers[id]);
59787
- if (!answer) throw new JudgeError("invalid_response", `TypeSafe gave no usable answer for "${id}"`);
59889
+ if (!answer) throw new JudgeError("invalid_response", `${this.service} gave no usable answer for "${id}"`);
59788
59890
  answers[id] = answer;
59789
59891
  }
59790
59892
  return {
@@ -59801,12 +59903,19 @@ var DEFAULT_TIMEOUT_MS2 = {
59801
59903
  // Jev answers in well under a second, but a cold connection over a long route can take several.
59802
59904
  jev: 1e4,
59803
59905
  typesafe: 1e4,
59906
+ // A CLM server embeds every question together with the state: a batch of long ones takes seconds on a small GPU.
59907
+ clm: 8e3,
59804
59908
  gateway: 4e3,
59805
59909
  local: 4e3,
59806
59910
  http: 8e3,
59807
59911
  llm: 3e4,
59808
59912
  mock: 1e3
59809
59913
  };
59914
+ var KEYS_FOR_ELSEWHERE = /* @__PURE__ */ new Set([
59915
+ "MU_JUDGE_OPENROUTER_API_KEY",
59916
+ "MU_JUDGE_CUSTOM_API_KEY",
59917
+ "MU_JUDGE_CLM_API_KEY"
59918
+ ]);
59810
59919
  function resolveJudgeConfig(name, config) {
59811
59920
  if (name.startsWith("llm:")) return { type: "llm", model: name.slice("llm:".length) };
59812
59921
  return config.judges[name] ?? BUILT_IN_JUDGES[name];
@@ -59839,15 +59948,39 @@ function createProvider(name, judge, host2) {
59839
59948
  if (!complete3) throw new TypeError(`Judge "${name}": model "${judge.model}" is not available`);
59840
59949
  return new LlmJudgeProvider({ id: `llm:${judge.model}`, complete: complete3 });
59841
59950
  }
59842
- case "typesafe":
59951
+ case "typesafe": {
59952
+ const keyName = judge.apiKeyEnv ?? "TYPESAFE_API_KEY";
59953
+ if (KEYS_FOR_ELSEWHERE.has(keyName) && !judge.baseUrl) {
59954
+ throw new TypeError(`Judge "${name}" needs a baseUrl: its key ${keyName} is not sent to TypeSafe`);
59955
+ }
59843
59956
  return new TypeSafeJudgeProvider({
59844
- apiKey: () => host2.env?.[judge.apiKeyEnv ?? "TYPESAFE_API_KEY"],
59957
+ apiKey: () => host2.env?.[keyName],
59958
+ keyName,
59845
59959
  model: judge.model,
59846
59960
  baseUrl: judge.baseUrl,
59847
59961
  fetch: host2.fetch
59848
59962
  });
59849
- case "jev":
59850
- return host2.env?.[judge.apiKeyEnv ?? "TYPESAFE_API_KEY"] ? createProvider(name, { ...judge, type: "typesafe" }, host2) : createProvider(name, { ...judge, type: "gateway", model: judge.model ?? "typesafe-ai/jev" }, host2);
59963
+ }
59964
+ case "clm": {
59965
+ const keyName = judge.apiKeyEnv ?? "MU_JUDGE_CLM_API_KEY";
59966
+ return new TypeSafeJudgeProvider({
59967
+ apiKey: () => host2.env?.[keyName],
59968
+ keyName,
59969
+ keyOptional: true,
59970
+ judgeName: "CLM",
59971
+ model: judge.model || CLM_DEFAULT_MODEL,
59972
+ baseUrl: clmEndpoint(judge.baseUrl),
59973
+ fetch: host2.fetch
59974
+ });
59975
+ }
59976
+ case "jev": {
59977
+ if (host2.env?.[judge.apiKeyEnv ?? "TYPESAFE_API_KEY"])
59978
+ return createProvider(name, { ...judge, type: "typesafe" }, host2);
59979
+ const openRouter = BUILT_IN_JUDGES["jev-openrouter"];
59980
+ if (openRouter.apiKeyEnv && host2.env?.[openRouter.apiKeyEnv]) return createProvider(name, openRouter, host2);
59981
+ const model = judge.model?.includes("/") ? judge.model : "typesafe-ai/jev";
59982
+ return createProvider(name, { ...judge, type: "gateway", model }, host2);
59983
+ }
59851
59984
  default:
59852
59985
  return new GatewayJudgeProvider({
59853
59986
  apiKey: judge.apiKeyEnv ? () => host2.env?.[judge.apiKeyEnv] : host2.gatewayApiKey ?? (() => host2.env?.AI_GATEWAY_API_KEY),
@@ -59885,7 +60018,7 @@ var UnavailableJudgeProvider = class {
59885
60018
  this.id = "none";
59886
60019
  }
59887
60020
  async evaluate() {
59888
- throw new JudgeError("unreachable", "No judge is configured");
60021
+ throw new JudgeError("auth", "No judge is configured");
59889
60022
  }
59890
60023
  };
59891
60024
 
@@ -59893,20 +60026,44 @@ var UnavailableJudgeProvider = class {
59893
60026
  var undici = __toESM(require_undici(), 1);
59894
60027
  import { EventEmitter } from "node:events";
59895
60028
  var JUDGE_KEEP_ALIVE_MS = 6e4;
60029
+ var JUDGE_FAILURES_BEFORE_RECONNECT = 2;
60030
+ var unanswered = (error) => error instanceof Error && (error.name === "TimeoutError" || error.name === "TypeError");
59896
60031
  function createJudgeFetch(options = {}) {
59897
60032
  const keepAliveMs = options.keepAliveMs ?? JUDGE_KEEP_ALIVE_MS;
59898
60033
  const http22 = options.http2 ?? muEnv("JUDGE_HTTP2") !== "off";
59899
- const dispatcher = new undici.EnvHttpProxyAgent({
59900
- keepAliveTimeout: keepAliveMs,
59901
- keepAliveMaxTimeout: Math.max(keepAliveMs, 6e5),
59902
- // Judge calls are small and short: a few connections per origin cover what a turn asks at once.
59903
- connections: 4,
59904
- allowH2: http22
59905
- });
59906
- if (dispatcher instanceof EventEmitter) EventEmitter.prototype.on.call(dispatcher, "error", () => {
59907
- });
60034
+ const failuresBeforeReconnect = options.failuresBeforeReconnect ?? JUDGE_FAILURES_BEFORE_RECONNECT;
60035
+ const connect2 = () => {
60036
+ const dispatcher2 = new undici.EnvHttpProxyAgent({
60037
+ keepAliveTimeout: keepAliveMs,
60038
+ keepAliveMaxTimeout: Math.max(keepAliveMs, 6e5),
60039
+ // Judge calls are small and short: a few connections per origin cover what a turn asks at once.
60040
+ connections: 4,
60041
+ allowH2: http22,
60042
+ ...options.h2c ? { useH2c: true } : {}
60043
+ });
60044
+ if (dispatcher2 instanceof EventEmitter) EventEmitter.prototype.on.call(dispatcher2, "error", () => {
60045
+ });
60046
+ return dispatcher2;
60047
+ };
60048
+ let dispatcher = connect2();
60049
+ let failures = 0;
59908
60050
  const withDispatcher = undici.fetch;
59909
- const judgeFetch = (input, init) => withDispatcher(input, { ...init ?? {}, dispatcher });
60051
+ const judgeFetch = async (input, init) => {
60052
+ const used = dispatcher;
60053
+ try {
60054
+ const response = await withDispatcher(input, { ...init ?? {}, dispatcher: used });
60055
+ if (used === dispatcher) failures = 0;
60056
+ return response;
60057
+ } catch (error) {
60058
+ if (used === dispatcher && unanswered(error) && ++failures >= failuresBeforeReconnect) {
60059
+ dispatcher = connect2();
60060
+ failures = 0;
60061
+ void used.destroy().catch(() => {
60062
+ });
60063
+ }
60064
+ throw error;
60065
+ }
60066
+ };
59910
60067
  return { fetch: judgeFetch, http2: http22, close: () => dispatcher.close() };
59911
60068
  }
59912
60069
 
@@ -60156,8 +60313,8 @@ var KyrnRuntime = class {
60156
60313
  let timer;
60157
60314
  return Promise.race([
60158
60315
  work,
60159
- new Promise((resolve13) => {
60160
- timer = setTimeout(() => resolve13(void 0), left);
60316
+ new Promise((resolve15) => {
60317
+ timer = setTimeout(() => resolve15(void 0), left);
60161
60318
  })
60162
60319
  ]).finally(() => {
60163
60320
  if (timer) clearTimeout(timer);
@@ -60268,8 +60425,8 @@ function within(work, waitMs) {
60268
60425
  let timer;
60269
60426
  return Promise.race([
60270
60427
  work,
60271
- new Promise((resolve13) => {
60272
- timer = setTimeout(() => resolve13(void 0), waitMs);
60428
+ new Promise((resolve15) => {
60429
+ timer = setTimeout(() => resolve15(void 0), waitMs);
60273
60430
  })
60274
60431
  ]).finally(() => {
60275
60432
  if (timer) clearTimeout(timer);
@@ -60804,14 +60961,14 @@ var JobManager = class {
60804
60961
  scanFrom = offset;
60805
60962
  return void 0;
60806
60963
  };
60807
- return new Promise((resolve13) => {
60964
+ return new Promise((resolve15) => {
60808
60965
  let timer;
60809
60966
  const settle = (result) => {
60810
60967
  if (timer) clearTimeout(timer);
60811
60968
  job.listeners.delete(check);
60812
60969
  request.signal?.removeEventListener("abort", onAbort);
60813
60970
  job.waiting--;
60814
- resolve13(result);
60971
+ resolve15(result);
60815
60972
  };
60816
60973
  const check = () => {
60817
60974
  const line3 = scan2();
@@ -60849,13 +61006,13 @@ var JobManager = class {
60849
61006
  }
60850
61007
  /** Polls a condition that a job's end may change; resolves to whether it came true in time. */
60851
61008
  until(job, condition, timeoutMs) {
60852
- return new Promise((resolve13) => {
60853
- if (condition()) return resolve13(true);
61009
+ return new Promise((resolve15) => {
61010
+ if (condition()) return resolve15(true);
60854
61011
  const startedAt = Date.now();
60855
61012
  const done = (result) => {
60856
61013
  clearInterval(poll);
60857
61014
  job.listeners.delete(check);
60858
- resolve13(result);
61015
+ resolve15(result);
60859
61016
  };
60860
61017
  const check = () => {
60861
61018
  if (condition()) done(true);
@@ -61428,12 +61585,12 @@ function parseBoardText(reply) {
61428
61585
  const { progress, now, confirm, note: note2 } = parsed;
61429
61586
  if (typeof progress !== "string" || typeof now !== "string" || !now.trim()) return void 0;
61430
61587
  const waiting = Array.isArray(confirm) ? confirm.filter((item) => typeof item === "string" && item.trim() !== "") : [];
61431
- const told = typeof note2 === "string" ? note2.trim() : "";
61588
+ const told2 = typeof note2 === "string" ? note2.trim() : "";
61432
61589
  return {
61433
61590
  progress: clip2(progress.trim(), 400),
61434
61591
  now: clip2(now.trim(), 400),
61435
61592
  confirm: waiting.slice(0, 5).map((item) => clip2(item.trim(), 300)),
61436
- ...told ? { note: clip2(told, 300) } : {}
61593
+ ...told2 ? { note: clip2(told2, 300) } : {}
61437
61594
  };
61438
61595
  }
61439
61596
  var NOW = {
@@ -61641,15 +61798,42 @@ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
61641
61798
  "bg_output"
61642
61799
  ]);
61643
61800
  var SHELL_TRICKS = /[<>;&`\n\r]|\$\(|\$\{/;
61801
+ var POWERSHELL_TRICKS = /[(){}]/;
61644
61802
  var READ_ONLY_PROGRAM = /^(?:ls|pwd|cat|head|tail|wc|which|file|stat|du|df|date|whoami|uname|echo|printf|rg|grep|sort|uniq|cut|nl|tree|git\s+(?:status|log|diff|show|blame|rev-parse|ls-files|describe)|Get-ChildItem|gci|dir|Get-Content|gc|type|Get-Location|Select-String|sls|Get-Item|gi|Get-Date|Write-Output|Write-Host)(?:\s|$)/i;
61645
- function isReadOnlyCommand(command) {
61803
+ var WRITES_OR_RUNS = /* @__PURE__ */ new Map([
61804
+ // ripgrep runs `--pre` on every file it searches, and `--hostname-bin` for its links.
61805
+ ["rg", /(?:^|\s)--(?:pre|hostname-bin)(?:[\s=]|$)/],
61806
+ // `-o FILE`, also in a cluster (`-uo`); `--compress-program` runs on its temporary files.
61807
+ ["sort", /(?:^|\s)-[a-zA-Z]*o|--compress-program/],
61808
+ // `-o FILE`; `-R` writes an index into every folder.
61809
+ ["tree", /(?:^|\s)-[a-zA-Z]*[oR]/],
61810
+ // `-C` compiles a magic file next to the one it is given.
61811
+ ["file", /(?:^|\s)-[a-zA-Z]*C/]
61812
+ ]);
61813
+ function uniqWrites(words2) {
61814
+ let operands = 0;
61815
+ for (let index = 1; index < words2.length; index++) {
61816
+ if (/^-[fsw]$/.test(words2[index])) index++;
61817
+ else if (words2[index] === "-" || !words2[index].startsWith("-")) operands++;
61818
+ }
61819
+ return operands > 1;
61820
+ }
61821
+ function isReadOnlyCommand(command, powershell = false) {
61646
61822
  const text6 = command.trim();
61647
61823
  if (!text6 || SHELL_TRICKS.test(text6) || /--output\b/.test(text6)) return false;
61648
- return text6.split("|").every((part) => READ_ONLY_PROGRAM.test(part.trim()));
61824
+ if (powershell && POWERSHELL_TRICKS.test(text6)) return false;
61825
+ return text6.split("|").every((part) => {
61826
+ const piece = part.trim();
61827
+ if (!READ_ONLY_PROGRAM.test(piece)) return false;
61828
+ const words2 = piece.split(/\s+/);
61829
+ const program = words2[0].toLowerCase();
61830
+ if (program === "uniq") return !uniqWrites(words2);
61831
+ return !WRITES_OR_RUNS.get(program)?.test(piece);
61832
+ });
61649
61833
  }
61650
61834
  function isMutatingCall(toolName, input) {
61651
61835
  if (READ_ONLY_TOOLS.has(toolName)) return false;
61652
- if (isShellTool(toolName)) return !isReadOnlyCommand(String(input.command ?? ""));
61836
+ if (isShellTool(toolName)) return !isReadOnlyCommand(String(input.command ?? ""), toolName === "powershell");
61653
61837
  return true;
61654
61838
  }
61655
61839
  var CHECK_COMMAND = /\b(?:vitest|jest|pytest|mocha|ava|tsc|eslint|biome|ruff|mypy|rspec|phpunit|ctest|tox|nox|gradle|mvn)\b|\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|build|check|lint|typecheck)\b|\b(?:cargo|go|dotnet|swift|make|deno)\s+(?:test|build|check|vet|clippy)\b|\bnode\b[^\n]*--test\b|\btest\.sh\b/;
@@ -61858,6 +62042,13 @@ function flat2(text6, length) {
61858
62042
  const line2 = text6.replace(/\s+/g, " ").trim();
61859
62043
  return line2.length <= length ? line2 : `${line2.slice(0, length - 1)}\u2026`;
61860
62044
  }
62045
+ function opening(text6) {
62046
+ if (text6.length <= MAX_SAID) return text6;
62047
+ const head = text6.slice(0, MAX_SAID - 1);
62048
+ let end = head.length;
62049
+ while (end > MAX_SAID * 0.75 && !/[\s,。;:!?、]/.test(head[end - 1])) end--;
62050
+ return `${(end > MAX_SAID * 0.75 ? head.slice(0, end) : head).trimEnd()}\u2026`;
62051
+ }
61861
62052
  function note(state, at, text6, coded) {
61862
62053
  state.recent.push({
61863
62054
  at,
@@ -61866,6 +62057,11 @@ function note(state, at, text6, coded) {
61866
62057
  });
61867
62058
  if (state.recent.length > MAX_RECENT) state.recent.splice(0, state.recent.length - MAX_RECENT);
61868
62059
  }
62060
+ function told(state, now) {
62061
+ if (state.wrapUp?.heardAt !== void 0) return;
62062
+ if (state.wrapUp) state.wrapUp.heardAt = now;
62063
+ note(state, now, "\u2190 told to wrap up and report", { code: "told_wrap_up" });
62064
+ }
61869
62065
  function textOf2(content) {
61870
62066
  if (typeof content === "string") return content;
61871
62067
  if (!Array.isArray(content)) return "";
@@ -61915,25 +62111,28 @@ function applyEvent(state, event, now) {
61915
62111
  const type = event.message.customType;
61916
62112
  const text6 = type === HIVE_MESSAGE || type === SWARM_MESSAGE ? textOf2(event.message.content) : "";
61917
62113
  const notes = text6.split("\n").filter((line2) => line2.startsWith("- ")).length;
61918
- if (text6.startsWith(NOTES_HEADER))
62114
+ if (text6.startsWith(NOTES_HEADER)) {
61919
62115
  note(state, now, `\u2190 ${notes} note${notes === 1 ? "" : "s"} from the others`, {
61920
62116
  code: "notes_received",
61921
62117
  params: { count: notes }
61922
62118
  });
61923
- else if (text6.startsWith(LAST_CALL))
62119
+ if (text6.endsWith(CHECKPOINT))
62120
+ note(state, now, "\u2190 asked what it has found so far", { code: "asked_findings" });
62121
+ } else if (text6.startsWith(LAST_CALL))
61924
62122
  note(state, now, `\u2190 last call: ${notes} late note${notes === 1 ? "" : "s"}`, {
61925
62123
  code: "late_notes",
61926
62124
  params: { count: notes }
61927
62125
  });
61928
62126
  else if (text6 === CHECKPOINT)
61929
62127
  note(state, now, "\u2190 asked what it has found so far", { code: "asked_findings" });
61930
- else if (text6.startsWith(WRAP_UP))
61931
- note(state, now, "\u2190 told to wrap up and report", { code: "told_wrap_up" });
62128
+ else if (text6.startsWith(WRAP_UP)) told(state, now);
62129
+ } else if (event.message?.role === "toolResult" && textOf2(event.message.content).startsWith(TOOLS_CLOSED)) {
62130
+ told(state, now);
61932
62131
  }
61933
62132
  break;
61934
62133
  case "message_update":
61935
- if (event.assistantMessageEvent?.type === "text_delta" && typeof event.assistantMessageEvent.delta === "string") {
61936
- state.said = `${state.said ?? ""}${event.assistantMessageEvent.delta}`.slice(-MAX_SAID);
62134
+ if (event.assistantMessageEvent?.type === "text_delta" && typeof event.assistantMessageEvent.delta === "string" && (state.said?.length ?? 0) < MAX_SAID) {
62135
+ state.said = `${state.said ?? ""}${event.assistantMessageEvent.delta}`.slice(0, MAX_SAID);
61937
62136
  }
61938
62137
  break;
61939
62138
  case "message_end": {
@@ -61947,7 +62146,7 @@ function applyEvent(state, event, now) {
61947
62146
  state.usage.cost += usage.cost?.total ?? 0;
61948
62147
  }
61949
62148
  const text6 = textOf2(message.content).trim();
61950
- if (text6) state.said = text6.slice(-MAX_SAID);
62149
+ if (text6) state.said = opening(text6);
61951
62150
  if (message.stopReason === "error" || message.stopReason === "aborted") {
61952
62151
  state.error = message.errorMessage ?? `the model request was ${message.stopReason}`;
61953
62152
  state.errorCode = "model_error";
@@ -62025,6 +62224,18 @@ function applyEvent(state, event, now) {
62025
62224
  }
62026
62225
  return false;
62027
62226
  }
62227
+ var MAX_DRAFT = 4e4;
62228
+ function followDraft(draft, event, now) {
62229
+ if (event.type === "message_start" && event.message?.role === "assistant") return { text: "", at: now };
62230
+ if (draft && event.type === "message_update" && event.assistantMessageEvent?.type === "text_delta" && typeof event.assistantMessageEvent.delta === "string" && draft.text.length < MAX_DRAFT) {
62231
+ return { ...draft, text: draft.text + event.assistantMessageEvent.delta };
62232
+ }
62233
+ if (event.type === "message_end" && event.message?.role === "assistant") {
62234
+ const text6 = textOf2(event.message.content).trim();
62235
+ return text6 ? { text: text6.slice(0, MAX_DRAFT), at: draft?.at ?? now } : draft;
62236
+ }
62237
+ return draft;
62238
+ }
62028
62239
  function reportOf(state) {
62029
62240
  const unchanged = new RegExp(`^\\W*${NO_CHANGE}\\W*$`, "i");
62030
62241
  const finals = state.finals.filter((text6) => !unchanged.test(text6));
@@ -62066,6 +62277,8 @@ function activeRuns() {
62066
62277
  var SwarmRun = class {
62067
62278
  constructor(options) {
62068
62279
  this.outcomes = [];
62280
+ /** Per bee, the message it is writing, whole: the report of one cut off halfway is in it. */
62281
+ this.drafts = [];
62069
62282
  /** Slots at work; each one takes the next bee that has not been started until there is none. */
62070
62283
  this.workers = [];
62071
62284
  this.next = 0;
@@ -62192,20 +62405,21 @@ var SwarmRun = class {
62192
62405
  continue;
62193
62406
  }
62194
62407
  if (bee.wrapUp) {
62195
- if (now - bee.wrapUp.at >= this.limits.graceSeconds * 1e3) {
62196
- this.kill(
62197
- bee.name,
62198
- `${bee.wrapUp.reason}; no report within ${this.limits.graceSeconds}s of being asked`,
62199
- "timed-out",
62200
- {
62201
- code: "no_report_in_time",
62202
- // What the wrap-up was for, so "time budget reached; no report in time" can be said whole.
62203
- params: {
62204
- seconds: this.limits.graceSeconds,
62205
- ...bee.wrapUp.code ? { after: bee.wrapUp.code } : {}
62206
- }
62408
+ const grace = this.limits.graceSeconds * 1e3;
62409
+ const deadline = Math.min(
62410
+ (bee.wrapUp.heardAt ?? Number.POSITIVE_INFINITY) + grace,
62411
+ bee.wrapUp.at + 2 * grace
62412
+ );
62413
+ if (now >= deadline) {
62414
+ const seconds3 = Math.round((now - bee.wrapUp.at) / 1e3);
62415
+ this.kill(bee.name, `${bee.wrapUp.reason}; no report within ${seconds3}s of being asked`, "timed-out", {
62416
+ code: "no_report_in_time",
62417
+ // What the wrap-up was for, so "time budget reached; no report in time" can be said whole.
62418
+ params: {
62419
+ seconds: seconds3,
62420
+ ...bee.wrapUp.code ? { after: bee.wrapUp.code } : {}
62207
62421
  }
62208
- );
62422
+ });
62209
62423
  }
62210
62424
  } else if (this.limits.beeMinutes > 0 && now - (bee.startedAt ?? now) >= this.limits.beeMinutes * 6e4) {
62211
62425
  this.wrapUp(bee.name, `time budget of ${this.limits.beeMinutes} min reached`, {
@@ -62239,9 +62453,14 @@ ${body}` : body };
62239
62453
  const spent = `after ${clock((bee.endedAt ?? this.now()) - (bee.startedAt ?? bee.queuedAt))}, ${count(bee.turns, "turn")}, ${count(bee.toolCalls, "tool call")}`;
62240
62454
  const label2 = bee.status === "failed" ? "FAILED" : bee.status === "timed-out" ? "STOPPED BY THE WATCHDOG" : "STOPPED";
62241
62455
  const lines2 = [`${label2}: ${bee.error ?? "unknown reason"} (${spent}).`];
62456
+ const draft = this.drafts[index];
62457
+ const heardAt = bee.wrapUp?.heardAt;
62242
62458
  if (report3) lines2.push(`What it had reported by then:
62243
62459
  ${report3}`);
62244
- else if (bee.said) lines2.push(`The last thing it said: ${bee.said}`);
62460
+ else if (draft?.text.trim() && heardAt !== void 0 && draft.at >= heardAt)
62461
+ lines2.push(`What it had written of its report when it was stopped:
62462
+ ${draft.text.trim()}`);
62463
+ else if (draft?.text.trim() || bee.said) lines2.push(`The last thing it said: ${draft?.text.trim() || bee.said}`);
62245
62464
  return { state: bee, report: lines2.join("\n") };
62246
62465
  }
62247
62466
  async work(runner) {
@@ -62264,6 +62483,7 @@ ${report3}`);
62264
62483
  event: (event) => {
62265
62484
  if (isOver(bee.status)) return;
62266
62485
  applyEvent(bee, event, this.now());
62486
+ this.drafts[index] = followDraft(this.drafts[index], event, this.now());
62267
62487
  if (event.type !== "message_update" && event.type !== "tool_execution_update" && bee.transcript) {
62268
62488
  try {
62269
62489
  appendFileSync(bee.transcript, `${JSON.stringify({ at: this.now(), ...event })}
@@ -62403,7 +62623,7 @@ function registerConstraints(runtime) {
62403
62623
  }
62404
62624
  const decision = await Promise.race([
62405
62625
  runtime.engine.decide(toolConstraint, input, { signal: ctx.signal }),
62406
- new Promise((resolve13) => setTimeout(() => resolve13(void 0), options.waitMs))
62626
+ new Promise((resolve15) => setTimeout(() => resolve15(void 0), options.waitMs))
62407
62627
  ]);
62408
62628
  if (!decision || decision.mode !== "active" || decision.source !== "judge") return void 0;
62409
62629
  const broken = decision.outcome.broken.map((index) => constraints[index]).filter(Boolean);
@@ -62521,8 +62741,8 @@ function describeBoard(board, language, account) {
62521
62741
  if (board.confirm.length > 0) {
62522
62742
  lines2.push(`${zh ? "\u9700\u8981\u4F60\u786E\u8BA4" : "Waiting on you"}:`, ...board.confirm.map((item) => ` - ${item}`));
62523
62743
  }
62524
- const told = (account ?? board.log ?? []).slice(-8);
62525
- if (told.length > 0) lines2.push(`${zh ? "\u5B83\u505A\u4E86\u4EC0\u4E48" : "What it did"}:`, ...told.map((note2) => ` \xB7 ${note2.text}`));
62744
+ const told2 = (account ?? board.log ?? []).slice(-8);
62745
+ if (told2.length > 0) lines2.push(`${zh ? "\u5B83\u505A\u4E86\u4EC0\u4E48" : "What it did"}:`, ...told2.map((note2) => ` \xB7 ${note2.text}`));
62526
62746
  return lines2.join("\n");
62527
62747
  }
62528
62748
  function registerBoard(runtime, roots) {
@@ -62840,7 +63060,8 @@ function registerBoard(runtime, roots) {
62840
63060
  try {
62841
63061
  const reply = await complete3({
62842
63062
  system: narratorSystem(facts.language, writeIn()),
62843
- user: narratorRequest(facts),
63063
+ // The writer tells what the agent did, never the key it did it with.
63064
+ user: redactSecrets(narratorRequest(facts), environmentSecrets()),
62844
63065
  signal: AbortSignal.any([AbortSignal.timeout(options.narrateTimeoutMs), gone])
62845
63066
  });
62846
63067
  text6 = parseBoardText(reply.text);
@@ -63259,6 +63480,197 @@ var browserStep = defineDecision({
63259
63480
  }
63260
63481
  });
63261
63482
 
63483
+ // packages/kyrn-judge/src/browser/bounds.ts
63484
+ import { lookup } from "node:dns/promises";
63485
+ import { isIP as isIP2 } from "node:net";
63486
+
63487
+ // packages/kyrn-judge/src/web/ssrf.ts
63488
+ import { lookup as dnsLookup } from "node:dns";
63489
+ import { isIP } from "node:net";
63490
+ var FetchRefusal = class extends Error {
63491
+ constructor(code, message) {
63492
+ super(message);
63493
+ this.code = code;
63494
+ }
63495
+ };
63496
+ function v4(octets) {
63497
+ const [a, b, c] = octets;
63498
+ if (a === 127) return "loopback";
63499
+ if (a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168) return "private";
63500
+ if (a === 100 && b >= 64 && b <= 127) return "private";
63501
+ if (a === 169 && b === 254) return "link-local";
63502
+ if (a === 0 || a >= 224) return "reserved";
63503
+ if (a === 192 && b === 0 && (c === 0 || c === 2)) return "reserved";
63504
+ if (a === 198 && b === 51 && c === 100 || a === 203 && b === 0 && c === 113) return "reserved";
63505
+ return "public";
63506
+ }
63507
+ function groups(address) {
63508
+ let text6 = address.split("%")[0];
63509
+ const dotted = /^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(text6);
63510
+ if (dotted) {
63511
+ const octets = dotted[2].split(".").map(Number);
63512
+ if (octets.some((octet) => octet > 255)) return void 0;
63513
+ text6 = `${dotted[1]}${(octets[0] << 8 | octets[1]).toString(16)}:${(octets[2] << 8 | octets[3]).toString(16)}`;
63514
+ }
63515
+ const halves = text6.split("::");
63516
+ if (halves.length > 2) return void 0;
63517
+ const head = halves[0] ? halves[0].split(":") : [];
63518
+ const tail = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
63519
+ const fill = halves.length === 2 ? 8 - head.length - tail.length : 0;
63520
+ if (fill < 0 || halves.length === 1 && head.length !== 8) return void 0;
63521
+ const all = [...head, ...Array(fill).fill("0"), ...tail].map((group) => Number.parseInt(group, 16));
63522
+ return all.length === 8 && all.every((group) => group >= 0 && group <= 65535) ? all : void 0;
63523
+ }
63524
+ function classifyAddress(address) {
63525
+ const bare = address.replace(/^\[|\]$/g, "");
63526
+ if (isIP(bare) === 4) return v4(bare.split(".").map(Number));
63527
+ const parts = groups(bare);
63528
+ if (!parts) return "reserved";
63529
+ const embedded = [parts[6] >> 8, parts[6] & 255, parts[7] >> 8, parts[7] & 255];
63530
+ const zeroPrefix = parts.slice(0, 5).every((group) => group === 0);
63531
+ if (zeroPrefix && parts[5] === 65535) return v4(embedded);
63532
+ if (parts[0] === 100 && parts[1] === 65435 && parts.slice(2, 6).every((group) => group === 0)) return v4(embedded);
63533
+ if (zeroPrefix && parts[5] === 0) {
63534
+ if (parts[6] === 0 && parts[7] === 1) return "loopback";
63535
+ return parts[6] === 0 && parts[7] === 0 ? "reserved" : v4(embedded);
63536
+ }
63537
+ if ((parts[0] & 65024) === 64512) return "private";
63538
+ if ((parts[0] & 65472) === 65152) return "link-local";
63539
+ if ((parts[0] & 65280) === 65280) return "reserved";
63540
+ if (parts[0] === 8193 && parts[1] === 3512) return "reserved";
63541
+ return "public";
63542
+ }
63543
+ function allowed(kind, policy) {
63544
+ if (kind === "public") return true;
63545
+ if (kind === "loopback") return policy.allowLoopback;
63546
+ if (kind === "private" || kind === "link-local") return policy.allowPrivate;
63547
+ return false;
63548
+ }
63549
+ function refusal(host2, address, kind) {
63550
+ return new FetchRefusal(
63551
+ "address",
63552
+ `Refused: ${host2} is a ${kind} address (${address}). web_fetch only reads the public web and, when asked directly, this machine's own dev servers.`
63553
+ );
63554
+ }
63555
+ function checkUrl(raw, policy) {
63556
+ let url;
63557
+ try {
63558
+ url = new URL(raw);
63559
+ } catch {
63560
+ throw new FetchRefusal("url", `Not a URL: ${raw.slice(0, 200)}`);
63561
+ }
63562
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
63563
+ throw new FetchRefusal("scheme", `Refused: only http and https can be fetched, not ${url.protocol}`);
63564
+ }
63565
+ if (url.username || url.password) {
63566
+ throw new FetchRefusal("credentials", "Refused: the URL carries credentials. Remove the user:password@ part.");
63567
+ }
63568
+ const host2 = url.hostname.replace(/^\[|\]$/g, "");
63569
+ if (isIP(host2)) {
63570
+ const kind = classifyAddress(host2);
63571
+ if (!allowed(kind, policy)) throw refusal(url.hostname, host2, kind);
63572
+ }
63573
+ return url;
63574
+ }
63575
+ function isLoopbackUrl(url) {
63576
+ const host2 = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
63577
+ if (host2 === "localhost" || host2.endsWith(".localhost")) return true;
63578
+ return isIP(host2) !== 0 && classifyAddress(host2) === "loopback";
63579
+ }
63580
+ function checkedLookup(policy, resolve15 = dnsLookup) {
63581
+ return (hostname, options, callback) => {
63582
+ resolve15(hostname, { ...options, all: true }, (error, answer) => {
63583
+ if (error) return callback(error);
63584
+ const addresses = Array.isArray(answer) ? answer : [];
63585
+ if (addresses.length === 0) return callback(new FetchRefusal("dns", `${hostname} has no address`));
63586
+ for (const entry of addresses) {
63587
+ const kind = classifyAddress(entry.address);
63588
+ if (!allowed(kind, policy)) return callback(refusal(hostname, entry.address, kind));
63589
+ }
63590
+ if (options.all) callback(null, addresses);
63591
+ else callback(null, addresses[0].address, addresses[0].family);
63592
+ });
63593
+ };
63594
+ }
63595
+
63596
+ // packages/kyrn-judge/src/browser/bounds.ts
63597
+ var RESOLVE_MS = 2e3;
63598
+ async function systemResolve(host2) {
63599
+ let timer;
63600
+ try {
63601
+ return await Promise.race([
63602
+ lookup(host2, { all: true }).then((answers) => answers.map((answer) => answer.address)),
63603
+ new Promise((_resolve, reject) => {
63604
+ timer = setTimeout(() => reject(new Error(`${host2} did not resolve in time`)), RESOLVE_MS);
63605
+ })
63606
+ ]);
63607
+ } finally {
63608
+ clearTimeout(timer);
63609
+ }
63610
+ }
63611
+ var NOWHERE = /^(?:about:(?:blank|srcdoc)|chrome-error:\/\/chromewebdata\/)(?:[?#]|$)/i;
63612
+ var WHAT = {
63613
+ loopback: "this computer",
63614
+ private: "the local network",
63615
+ "link-local": "a link-local address, such as a cloud machine's metadata service",
63616
+ reserved: "a reserved address"
63617
+ };
63618
+ var NOT_PUBLIC = ["loopback", "link-local", "private", "reserved"];
63619
+ function refusalReason(refused) {
63620
+ return `a page sent the browser to ${refused.where} (${refused.what}), where it goes only when asked to open it there; nothing of that page was read`;
63621
+ }
63622
+ var Bounds = class {
63623
+ constructor(start, resolve15 = systemResolve) {
63624
+ this.places = /* @__PURE__ */ new Map();
63625
+ this.resolve = resolve15;
63626
+ let parsed;
63627
+ try {
63628
+ parsed = new URL(start);
63629
+ } catch {
63630
+ }
63631
+ this.start = parsed;
63632
+ }
63633
+ /** Why the browser may not be at `url`, or undefined when it may. */
63634
+ async refuse(url) {
63635
+ if (NOWHERE.test(url)) return void 0;
63636
+ let now;
63637
+ try {
63638
+ now = new URL(url);
63639
+ } catch {
63640
+ return { where: "an address that is not a URL", what: "not a web page" };
63641
+ }
63642
+ if (now.protocol === "blob:")
63643
+ return now.origin === "null" ? { where: "blob:", what: "not a web page" } : this.refuse(now.origin);
63644
+ if (now.protocol !== "http:" && now.protocol !== "https:") return { where: now.protocol, what: "not a web page" };
63645
+ if (this.start && now.hostname === this.start.hostname) return void 0;
63646
+ const place = await this.place(now.hostname);
63647
+ if (place === "public") return void 0;
63648
+ const asked = this.start ? await this.place(this.start.hostname) : "public";
63649
+ return place === asked ? void 0 : { where: now.origin, what: WHAT[place] };
63650
+ }
63651
+ place(hostname) {
63652
+ let known = this.places.get(hostname);
63653
+ if (!known) {
63654
+ known = this.classify(hostname);
63655
+ this.places.set(hostname, known);
63656
+ }
63657
+ return known;
63658
+ }
63659
+ async classify(hostname) {
63660
+ const host2 = hostname.replace(/^\[|\]$/g, "").replace(/\.$/, "").toLowerCase();
63661
+ if (host2 === "localhost" || host2.endsWith(".localhost")) return "loopback";
63662
+ if (isIP2(host2)) return classifyAddress(host2);
63663
+ let addresses;
63664
+ try {
63665
+ addresses = await this.resolve(host2);
63666
+ } catch {
63667
+ return "public";
63668
+ }
63669
+ const places = addresses.map(classifyAddress);
63670
+ return NOT_PUBLIC.find((place) => places.includes(place)) ?? "public";
63671
+ }
63672
+ };
63673
+
63262
63674
  // packages/kyrn-judge/src/browser/session.ts
63263
63675
  import { createHash as createHash2 } from "node:crypto";
63264
63676
 
@@ -63403,20 +63815,21 @@ var SNAPSHOT_SCRIPT = String.raw`(() => {
63403
63815
  // packages/kyrn-judge/src/browser/session.ts
63404
63816
  var StalePage = class extends Error {
63405
63817
  };
63406
- var sleep = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
63818
+ var sleep = (ms) => new Promise((resolve15) => setTimeout(resolve15, ms));
63407
63819
  var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
63408
63820
  var BrowserSession = class _BrowserSession {
63409
- constructor(cdp, targetId, sessionId) {
63821
+ constructor(cdp, targetId, sessionId, start) {
63410
63822
  this.cdp = cdp;
63411
63823
  this.targetId = targetId;
63412
63824
  this.sessionId = sessionId;
63825
+ this.start = start;
63413
63826
  }
63414
63827
  static async open(cdp, url) {
63415
63828
  const { targetId } = await cdp.send("Target.createTarget", { url: "about:blank" });
63416
63829
  let session;
63417
63830
  try {
63418
63831
  const { sessionId } = await cdp.send("Target.attachToTarget", { targetId, flatten: true });
63419
- session = new _BrowserSession(cdp, targetId, sessionId);
63832
+ session = new _BrowserSession(cdp, targetId, sessionId, url);
63420
63833
  await session.call("Emulation.setDeviceMetricsOverride", {
63421
63834
  width: 1120,
63422
63835
  height: 780,
@@ -63650,6 +64063,7 @@ async function runBrowserTask(options) {
63650
64063
  const startedAt = performance.now();
63651
64064
  const history = [];
63652
64065
  let decisions = 0;
64066
+ const bounds = new Bounds(session.start, options.resolve);
63653
64067
  let page = await session.observe();
63654
64068
  const finish = (status, code, reason, params) => ({
63655
64069
  status,
@@ -63661,13 +64075,28 @@ async function runBrowserTask(options) {
63661
64075
  decisions,
63662
64076
  elapsedMs: Math.round(performance.now() - startedAt)
63663
64077
  });
64078
+ const within2 = async () => {
64079
+ const refused = await bounds.refuse(page.url);
64080
+ if (refused) page = { ...page, url: refused.where, title: "", text: "", actions: [] };
64081
+ return refused;
64082
+ };
64083
+ const look = async () => {
64084
+ page = await session.observe();
64085
+ return within2();
64086
+ };
64087
+ const offTheWeb = (refused) => finish("blocked", "off_the_web", refusalReason(refused), { where: refused.where });
64088
+ const opened = await within2();
64089
+ if (opened) return offTheWeb(opened);
63664
64090
  while (true) {
63665
64091
  if (options.signal?.aborted) return finish("aborted", "cancelled");
63666
64092
  if (options.beforeStep && !await options.beforeStep())
63667
64093
  return finish("aborted", "stopped_by_user", "stopped by the person watching");
63668
64094
  if (history.length >= maxSteps || decisions >= maxSteps * 2)
63669
64095
  return finish("budget", "max_steps", `stopped after ${maxSteps} actions`, { maxSteps });
63670
- if (!await session.fresh(page)) page = await session.observe();
64096
+ if (!await session.fresh(page)) {
64097
+ const refused = await look();
64098
+ if (refused) return offTheWeb(refused);
64099
+ }
63671
64100
  const space = actionSpace(page.actions);
63672
64101
  const input = {
63673
64102
  goal,
@@ -63724,7 +64153,8 @@ async function runBrowserTask(options) {
63724
64153
  await session.act(action, page, text6);
63725
64154
  } catch (error) {
63726
64155
  if (!(error instanceof StalePage)) throw error;
63727
- page = await session.observe();
64156
+ const refused2 = await look();
64157
+ if (refused2) return offTheWeb(refused2);
63728
64158
  continue;
63729
64159
  }
63730
64160
  const record4 = {
@@ -63736,10 +64166,11 @@ async function runBrowserTask(options) {
63736
64166
  };
63737
64167
  history.push(record4);
63738
64168
  const before = page.fingerprint;
63739
- page = await session.observe();
64169
+ const refused = await look();
63740
64170
  record4.page_changed = page.fingerprint !== before;
63741
64171
  record4.url = page.url;
63742
64172
  options.onStep?.(record4);
64173
+ if (refused) return offTheWeb(refused);
63743
64174
  }
63744
64175
  const lastThree = history.slice(-3);
63745
64176
  if (lastThree.length === 3 && lastThree.every((entry) => entry.page_changed === false && entry.kind !== "wait")) {
@@ -63762,7 +64193,7 @@ var CdpConnection = class _CdpConnection {
63762
64193
  socket.addEventListener("error", () => this.failAll("The browser connection failed"));
63763
64194
  }
63764
64195
  static connect(url, timeoutMs = 5e3) {
63765
- return new Promise((resolve13, reject) => {
64196
+ return new Promise((resolve15, reject) => {
63766
64197
  const socket = new WebSocket(url);
63767
64198
  const timer = setTimeout(() => {
63768
64199
  socket.close();
@@ -63770,7 +64201,7 @@ var CdpConnection = class _CdpConnection {
63770
64201
  }, timeoutMs);
63771
64202
  socket.addEventListener("open", () => {
63772
64203
  clearTimeout(timer);
63773
- resolve13(new _CdpConnection(socket));
64204
+ resolve15(new _CdpConnection(socket));
63774
64205
  });
63775
64206
  socket.addEventListener("error", () => {
63776
64207
  clearTimeout(timer);
@@ -63805,7 +64236,7 @@ var CdpConnection = class _CdpConnection {
63805
64236
  send(method, params = {}, sessionId, timeoutMs = 3e4) {
63806
64237
  if (this.closed) return Promise.reject(new CdpError("The browser connection is closed"));
63807
64238
  const id = this.nextId++;
63808
- return new Promise((resolve13, reject) => {
64239
+ return new Promise((resolve15, reject) => {
63809
64240
  const timer = setTimeout(() => {
63810
64241
  this.pending.delete(id);
63811
64242
  reject(new CdpError(`The browser did not answer ${method} within ${Math.round(timeoutMs / 1e3)}s`));
@@ -63813,7 +64244,7 @@ var CdpConnection = class _CdpConnection {
63813
64244
  this.pending.set(id, {
63814
64245
  resolve: (value) => {
63815
64246
  clearTimeout(timer);
63816
- resolve13(value);
64247
+ resolve15(value);
63817
64248
  },
63818
64249
  reject: (error) => {
63819
64250
  clearTimeout(timer);
@@ -64085,6 +64516,16 @@ async function isAlive(endpoint) {
64085
64516
  return false;
64086
64517
  }
64087
64518
  }
64519
+ function exitOf(child, ms) {
64520
+ if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
64521
+ return new Promise((resolve15) => {
64522
+ const timer = setTimeout(resolve15, ms);
64523
+ child.once("exit", () => {
64524
+ clearTimeout(timer);
64525
+ resolve15();
64526
+ });
64527
+ });
64528
+ }
64088
64529
  async function launchChrome(options = {}) {
64089
64530
  const host2 = options.host ?? thisBrowserHost();
64090
64531
  const browser = options.executable ? { executable: options.executable, side: sideOf(options.executable, host2) } : findBrowser(host2);
@@ -64109,7 +64550,7 @@ async function launchChrome(options = {}) {
64109
64550
  child.on("error", (error) => {
64110
64551
  failure = error;
64111
64552
  });
64112
- const deadline = Date.now() + 15e3;
64553
+ const deadline = Date.now() + (options.portWaitMs ?? 15e3);
64113
64554
  while (Date.now() < deadline) {
64114
64555
  const endpoint = readEndpoint(profileDir);
64115
64556
  if (endpoint && await isAlive(endpoint)) return { endpoint, process: child, profileDir };
@@ -64123,9 +64564,10 @@ async function launchChrome(options = {}) {
64123
64564
  code: "browser_exited_on_start",
64124
64565
  params: { exitCode: child.exitCode }
64125
64566
  });
64126
- await new Promise((resolve13) => setTimeout(resolve13, 100));
64567
+ await new Promise((resolve15) => setTimeout(resolve15, 100));
64127
64568
  }
64128
64569
  child.kill();
64570
+ await exitOf(child, 5e3);
64129
64571
  throw codedError("Chrome did not open its DevTools port in time", { code: "devtools_port_timeout" });
64130
64572
  }
64131
64573
 
@@ -64223,7 +64665,7 @@ var EmbeddedBrowser = class _EmbeddedBrowser {
64223
64665
  const state = await this.control();
64224
64666
  if (state.stop) return false;
64225
64667
  if (!state.paused) return true;
64226
- await new Promise((resolve13) => setTimeout(resolve13, pollMs));
64668
+ await new Promise((resolve15) => setTimeout(resolve15, pollMs));
64227
64669
  }
64228
64670
  }
64229
64671
  };
@@ -64244,7 +64686,9 @@ function registerBrowser(runtime) {
64244
64686
  /** Empty means mu's own ~/.mu/browser-profile. */
64245
64687
  profileDir: "",
64246
64688
  /** Use the desktop app's browser panel when the app offers one. */
64247
- embedded: true
64689
+ embedded: true,
64690
+ /** How long the model may take to say what goes into a field. Past it the run ends: it does not hold the turn. */
64691
+ writeTimeoutMs: 6e4
64248
64692
  });
64249
64693
  if (!options.enabled) return;
64250
64694
  const { pi } = runtime;
@@ -64276,11 +64720,22 @@ function registerBrowser(runtime) {
64276
64720
  cdp = await CdpConnection.connect(chrome.endpoint);
64277
64721
  return cdp;
64278
64722
  };
64279
- const writeText = async (context) => {
64723
+ const writeText = async (context, signal) => {
64280
64724
  const model = runtime.ctx?.model;
64281
64725
  const complete3 = runtime.writer() ?? (model ? runtime.llm(`${model.provider}/${model.id}`, { thinking: "off" }) : void 0);
64282
64726
  if (!complete3) return void 0;
64283
- const reply = await complete3({ system: TEXT_RULES, user: JSON.stringify(context) });
64727
+ const limit = AbortSignal.timeout(options.writeTimeoutMs);
64728
+ let reply;
64729
+ try {
64730
+ reply = await complete3({
64731
+ system: TEXT_RULES,
64732
+ user: JSON.stringify(context),
64733
+ // Stopping the run stops the question too; without either, a stalled model would hold the turn.
64734
+ signal: signal ? AbortSignal.any([signal, limit]) : limit
64735
+ });
64736
+ } catch {
64737
+ return void 0;
64738
+ }
64284
64739
  try {
64285
64740
  const parsed = JSON.parse(reply.text.slice(reply.text.indexOf("{"), reply.text.lastIndexOf("}") + 1));
64286
64741
  return typeof parsed.text === "string" && parsed.text.trim() && parsed.text.length <= 2e3 ? parsed.text : void 0;
@@ -64340,6 +64795,14 @@ function registerBrowser(runtime) {
64340
64795
  try {
64341
64796
  if (!params.goal?.trim()) {
64342
64797
  const page = await session.observe();
64798
+ const refused = await new Bounds(session.start).refuse(page.url);
64799
+ if (refused) {
64800
+ status = "blocked";
64801
+ code = "off_the_web";
64802
+ codeParams = { where: refused.where };
64803
+ reason = refusalReason(refused);
64804
+ return { text: `status: blocked (${reason})`, status, url: refused.where };
64805
+ }
64343
64806
  const text7 = `${page.title}
64344
64807
  ${page.url}
64345
64808
 
@@ -64354,7 +64817,7 @@ ${page.text.slice(0, textChars)}`;
64354
64817
  session,
64355
64818
  engine: runtime.engine,
64356
64819
  goal: params.goal,
64357
- writeText,
64820
+ writeText: (context) => writeText(context, signal),
64358
64821
  // In the app the person watching the page answers, in the app's own dialog.
64359
64822
  confirm: app ? (label2, url) => app.confirm(label2, url) : ctx.hasUI ? (label2) => ctx.ui.confirm("mu browser", `Allow this action?
64360
64823
 
@@ -64702,8 +65165,9 @@ import { homedir as homedir3 } from "node:os";
64702
65165
  import { join as join15 } from "node:path";
64703
65166
 
64704
65167
  // packages/kyrn-judge/src/checkpoint/git.ts
64705
- import { spawn as spawn4 } from "node:child_process";
64706
- import { join as join13 } from "node:path";
65168
+ import { execFile, spawn as spawn4 } from "node:child_process";
65169
+ import { accessSync, constants, existsSync as existsSync4, statSync as statSync3 } from "node:fs";
65170
+ import { delimiter, join as join13 } from "node:path";
64707
65171
  var TIMED_OUT = 124;
64708
65172
  var GitMissing = class extends Error {
64709
65173
  constructor(binary, cause) {
@@ -64711,6 +65175,13 @@ var GitMissing = class extends Error {
64711
65175
  this.name = "GitMissing";
64712
65176
  }
64713
65177
  };
65178
+ var GitUnusable = class extends Error {
65179
+ constructor(reason, message) {
65180
+ super(message);
65181
+ this.name = "GitUnusable";
65182
+ this.reason = reason;
65183
+ }
65184
+ };
64714
65185
  var GitFailed = class extends Error {
64715
65186
  constructor(args, result) {
64716
65187
  super(`git ${args[0]} exited with ${result.code}: ${result.stderr.trim().slice(0, 300)}`);
@@ -64718,8 +65189,58 @@ var GitFailed = class extends Error {
64718
65189
  this.result = result;
64719
65190
  }
64720
65191
  };
64721
- function spawnGit(binary = "git", timeoutMs = 3e4) {
64722
- return (args, env, input, limit) => new Promise((resolve13, reject) => {
65192
+ function findOnPath(binary, path) {
65193
+ const candidates = binary.includes("/") ? [binary] : (path ?? "").split(delimiter).filter(Boolean).map((folder) => join13(folder, binary));
65194
+ return candidates.find((candidate) => {
65195
+ try {
65196
+ accessSync(candidate, constants.X_OK);
65197
+ return statSync3(candidate).isFile();
65198
+ } catch {
65199
+ return false;
65200
+ }
65201
+ });
65202
+ }
65203
+ var hostProbe = {
65204
+ platform: process.platform,
65205
+ find: findOnPath,
65206
+ hasDeveloperTools: () => new Promise((done) => {
65207
+ execFile(
65208
+ "/usr/bin/xcode-select",
65209
+ ["-p"],
65210
+ { timeout: 5e3 },
65211
+ (error, stdout) => done(!error && existsSync4(stdout.trim()))
65212
+ );
65213
+ })
65214
+ };
65215
+ var MAC_STUB = "/usr/bin/git";
65216
+ var XCODE_LICENSE_EXIT = 69;
65217
+ async function stubProblem(binary, path, probe = hostProbe) {
65218
+ if (probe.platform !== "darwin" || probe.find(binary, path) !== MAC_STUB) return void 0;
65219
+ if (await probe.hasDeveloperTools()) return void 0;
65220
+ return new GitUnusable("developer_tools_missing", `${MAC_STUB} needs the developer tools, which are not installed`);
65221
+ }
65222
+ function heldByLicense(code, output) {
65223
+ return code === XCODE_LICENSE_EXIT && /licen[cs]e/i.test(output());
65224
+ }
65225
+ var UNUSABLE_TEXT = {
65226
+ developer_tools_missing: "git cannot run on this Mac: Apple's command line developer tools are not installed. Only the user can install them; do not try",
65227
+ xcode_license: "git cannot run on this Mac until the user accepts the Xcode license. Only they can; do not try"
65228
+ };
65229
+ function spawnGit(binary = "git", timeoutMs = 3e4, probe = hostProbe) {
65230
+ let stub;
65231
+ return async (args, env, input, limit) => {
65232
+ stub ??= stubProblem(binary, env.PATH, probe);
65233
+ const problem = await stub;
65234
+ if (problem) throw problem;
65235
+ const result = await spawnOnce(binary, timeoutMs, args, env, input, limit);
65236
+ if (heldByLicense(result.code, () => `${result.stderr}
65237
+ ${result.stdout}`))
65238
+ throw new GitUnusable("xcode_license", `git ${args[0]} exited with 69: ${result.stderr.trim().slice(0, 300)}`);
65239
+ return result;
65240
+ };
65241
+ }
65242
+ function spawnOnce(binary, timeoutMs, args, env, input, limit) {
65243
+ return new Promise((resolve15, reject) => {
64723
65244
  let child;
64724
65245
  try {
64725
65246
  child = spawn4(binary, [...args], { env: { ...env }, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
@@ -64755,10 +65276,10 @@ function spawnGit(binary = "git", timeoutMs = 3e4) {
64755
65276
  child.on("close", (code) => {
64756
65277
  clearTimeout(timer);
64757
65278
  if (truncated) {
64758
- resolve13({ code: 0, stdout: Buffer.concat(out).toString("utf8"), stderr: "", truncated: true });
65279
+ resolve15({ code: 0, stdout: Buffer.concat(out).toString("utf8"), stderr: "", truncated: true });
64759
65280
  return;
64760
65281
  }
64761
- resolve13({
65282
+ resolve15({
64762
65283
  code: timedOut ? TIMED_OUT : code ?? 1,
64763
65284
  stdout: Buffer.concat(out).toString("utf8"),
64764
65285
  stderr: timedOut ? `timed out after ${timeoutMs} ms` : Buffer.concat(err).toString("utf8")
@@ -64794,10 +65315,11 @@ function shadowEnv(base, gitDir, workTree, indexFile = join13(gitDir, "index"))
64794
65315
  // packages/kyrn-judge/src/checkpoint/store.ts
64795
65316
  import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
64796
65317
  import {
64797
- accessSync,
65318
+ accessSync as accessSync2,
64798
65319
  appendFileSync as appendFileSync2,
64799
- constants,
64800
- existsSync as existsSync4,
65320
+ chmodSync,
65321
+ constants as constants2,
65322
+ existsSync as existsSync5,
64801
65323
  lstatSync,
64802
65324
  mkdirSync as mkdirSync6,
64803
65325
  readdirSync as readdirSync2,
@@ -64805,7 +65327,7 @@ import {
64805
65327
  realpathSync,
64806
65328
  rmdirSync,
64807
65329
  rmSync as rmSync4,
64808
- statSync as statSync3,
65330
+ statSync as statSync4,
64809
65331
  unlinkSync,
64810
65332
  writeFileSync as writeFileSync4
64811
65333
  } from "node:fs";
@@ -64838,7 +65360,22 @@ var BUILT_IN_IGNORES = [
64838
65360
  "DerivedData/",
64839
65361
  ".dart_tool/",
64840
65362
  ".DS_Store",
64841
- "Thumbs.db"
65363
+ "Thumbs.db",
65364
+ "*.env",
65365
+ ".env.*",
65366
+ "!.env.example",
65367
+ "!.env.sample",
65368
+ "!.env.template",
65369
+ ".envrc",
65370
+ ".netrc",
65371
+ "*.pem",
65372
+ "*.key",
65373
+ "*.p12",
65374
+ "*.pfx",
65375
+ "id_rsa",
65376
+ "id_dsa",
65377
+ "id_ecdsa",
65378
+ "id_ed25519"
64842
65379
  ];
64843
65380
  var CONFIG_MARKER = "# mu checkpoint settings";
64844
65381
  var shadowConfig = (gitDir) => `${CONFIG_MARKER}
@@ -64925,12 +65462,16 @@ async function openStore(options) {
64925
65462
  env: shadowEnv(options.env ?? process.env, gitDir, options.root),
64926
65463
  maxFileBytes: options.maxFileBytes ?? 5 * 1024 * 1024
64927
65464
  };
64928
- if (!existsSync4(join14(gitDir, "HEAD"))) {
64929
- mkdirSync6(gitDir, { recursive: true });
65465
+ if (!existsSync5(join14(gitDir, "HEAD"))) {
65466
+ mkdirSync6(gitDir, { recursive: true, mode: 448 });
64930
65467
  const { GIT_WORK_TREE: _tree, GIT_INDEX_FILE: _index, GIT_DIR: _dir, ...bare } = store.env;
64931
65468
  const result = await options.run(["-c", "init.defaultBranch=mu", "init", "--bare", "--quiet", gitDir], bare);
64932
65469
  if (result.code !== 0) throw new GitFailed(["init"], result);
64933
65470
  }
65471
+ try {
65472
+ chmodSync(gitDir, 448);
65473
+ } catch {
65474
+ }
64934
65475
  const config = join14(gitDir, "config");
64935
65476
  if (!readFileSync6(config, "utf8").includes(CONFIG_MARKER)) appendFileSync2(config, `
64936
65477
  ${shadowConfig(gitDir)}`);
@@ -64942,6 +65483,8 @@ ${shadowConfig(gitDir)}`);
64942
65483
  writeFileSync4(join14(gitDir, PROJECT_FILE), `${JSON.stringify({ root: options.root, lastUsed: Date.now() })}
64943
65484
  `);
64944
65485
  releaseLocks(store, STALE_LOCK_MS);
65486
+ const stale = zList(await git(store, ["ls-files", "-z", "--cached", "--ignored", "--exclude-standard"]));
65487
+ if (stale.length > 0) await git(store, ["update-index", "-z", "--force-remove", "--stdin"], `${stale.join("\0")}\0`);
64945
65488
  return store;
64946
65489
  }
64947
65490
  function releaseLocks(store, olderThanMs) {
@@ -64955,7 +65498,7 @@ function releaseLocks(store, olderThanMs) {
64955
65498
  if (!name.endsWith(".lock") && !/^restore-.*\.index$/.test(name)) continue;
64956
65499
  const path = join14(store.gitDir, name);
64957
65500
  try {
64958
- if (Date.now() - statSync3(path).mtimeMs >= olderThanMs) rmSync4(path, { force: true });
65501
+ if (Date.now() - statSync4(path).mtimeMs >= olderThanMs) rmSync4(path, { force: true });
64959
65502
  } catch {
64960
65503
  }
64961
65504
  }
@@ -64973,7 +65516,7 @@ async function scan(store, limits) {
64973
65516
  if (listing.code !== 0) throw new GitFailed(LIST_CHANGES, listing);
64974
65517
  const listed2 = zList(listing.stdout);
64975
65518
  const update = [];
64976
- const drop = [];
65519
+ const drop2 = [];
64977
65520
  const leftOut = [];
64978
65521
  let bytes = 0;
64979
65522
  for (const path of new Set(listed2)) {
@@ -64983,19 +65526,19 @@ async function scan(store, limits) {
64983
65526
  let stats;
64984
65527
  try {
64985
65528
  stats = lstatSync(file);
64986
- if (stats.isFile()) accessSync(file, constants.R_OK);
65529
+ if (stats.isFile()) accessSync2(file, constants2.R_OK);
64987
65530
  } catch (error) {
64988
65531
  if (error.code !== "ENOENT") {
64989
65532
  leftOut.push(path);
64990
- drop.push(path);
65533
+ drop2.push(path);
64991
65534
  continue;
64992
65535
  }
64993
65536
  stats = void 0;
64994
65537
  }
64995
- if (stats && !stats.isFile() && !stats.isSymbolicLink()) drop.push(path);
65538
+ if (stats && !stats.isFile() && !stats.isSymbolicLink()) drop2.push(path);
64996
65539
  else if (stats && stats.size > store.maxFileBytes) {
64997
65540
  leftOut.push(path);
64998
- drop.push(path);
65541
+ drop2.push(path);
64999
65542
  } else {
65000
65543
  update.push(path);
65001
65544
  bytes += stats?.size ?? 0;
@@ -65004,7 +65547,7 @@ async function scan(store, limits) {
65004
65547
  if (limits && bytes > limits.maxBytes) throw new SnapshotTooLarge("bytes", limits);
65005
65548
  if (update.length > 0)
65006
65549
  await git(store, ["update-index", "-z", "--add", "--remove", "--stdin"], `${update.join("\0")}\0`);
65007
- if (drop.length > 0) await git(store, ["update-index", "-z", "--force-remove", "--stdin"], `${drop.join("\0")}\0`);
65550
+ if (drop2.length > 0) await git(store, ["update-index", "-z", "--force-remove", "--stdin"], `${drop2.join("\0")}\0`);
65008
65551
  return { tree: (await git(store, ["write-tree"])).trim(), leftOut };
65009
65552
  }
65010
65553
  async function snapshot(store, name, limits) {
@@ -65247,6 +65790,11 @@ function describePlan(plan2) {
65247
65790
  return lines2.length > 0 ? lines2.join("\n") : "no file differs from the checkpoint";
65248
65791
  }
65249
65792
  var describeResult = (result) => `${result.restored.length} put back, ${result.removed.length} removed, ${result.broughtBack.length} brought back${result.leftAlone.length > 0 ? `, ${result.leftAlone.length} left alone (${listed(result.leftAlone.map((entry) => entry.path))})` : ""}`;
65793
+ var GIT_CANNOT_RUN = /* @__PURE__ */ new Set([
65794
+ "git_missing",
65795
+ "xcode_license",
65796
+ "developer_tools_missing"
65797
+ ]);
65250
65798
  function offNotice(code, limits) {
65251
65799
  const start = { zh: "\u5728\u9879\u76EE\u6587\u4EF6\u5939\u91CC\u542F\u52A8 mu \u5C31\u6709\u68C0\u67E5\u70B9", en: "Start mu in a project folder to get them" };
65252
65800
  const seconds3 = Math.round(limits.timeoutMs / 1e3);
@@ -65259,6 +65807,22 @@ function offNotice(code, limits) {
65259
65807
  }),
65260
65808
  params: {}
65261
65809
  };
65810
+ case "xcode_license":
65811
+ return {
65812
+ line: say({
65813
+ zh: "mu\uFF1A\u68C0\u67E5\u70B9\u5DF2\u5173\u95ED\uFF0C\u56E0\u4E3A\u8FD9\u53F0 Mac \u8FD8\u6CA1\u6709\u540C\u610F Xcode \u8BB8\u53EF\u534F\u8BAE\uFF0Cgit \u65E0\u6CD5\u8FD0\u884C\u3002\u5728\u7EC8\u7AEF\u91CC\u7528 sudo xcodebuild -license \u540C\u610F\u540E\uFF0C\u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5C31\u6709\u68C0\u67E5\u70B9\u3002",
65814
+ en: "mu: checkpoints are off, because git cannot run on this Mac until the Xcode license is accepted. Accept it with sudo xcodebuild -license in Terminal, then start a new session to get them."
65815
+ }),
65816
+ params: {}
65817
+ };
65818
+ case "developer_tools_missing":
65819
+ return {
65820
+ line: say({
65821
+ zh: "mu\uFF1A\u68C0\u67E5\u70B9\u5DF2\u5173\u95ED\uFF0C\u56E0\u4E3A\u8FD9\u53F0 Mac \u6CA1\u6709\u5B89\u88C5 git \u6240\u9700\u7684\u547D\u4EE4\u884C\u5F00\u53D1\u8005\u5DE5\u5177\u3002\u7528 xcode-select --install \u5B89\u88C5\u540E\uFF0C\u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5C31\u6709\u68C0\u67E5\u70B9\u3002",
65822
+ en: "mu: checkpoints are off, because this Mac has no command line developer tools, which git needs. Install them with xcode-select --install, then start a new session to get them."
65823
+ }),
65824
+ params: {}
65825
+ };
65262
65826
  case "home_folder":
65263
65827
  return {
65264
65828
  line: say({
@@ -65364,13 +65928,14 @@ function registerCheckpoint(runtime, roots, deps = {}) {
65364
65928
  runtime.present("checkpoint.off", { code, params: notice.params, message: notice.line });
65365
65929
  };
65366
65930
  const refusal2 = (cwd) => {
65367
- if (off?.code === "git_missing") return off.line;
65931
+ if (off && GIT_CANNOT_RUN.has(off.code)) return off.line;
65368
65932
  const place = placeOff(cwd);
65369
65933
  return place ? offNotice(place, options).line : void 0;
65370
65934
  };
65371
65935
  const giveUp = (ctx, error) => {
65372
65936
  if (off) return;
65373
65937
  if (error instanceof GitMissing) switchOff(ctx, "git_missing");
65938
+ else if (error instanceof GitUnusable) switchOff(ctx, error.reason);
65374
65939
  else if (error instanceof SnapshotTooLarge) {
65375
65940
  const codes = { files: "too_many_files", bytes: "too_many_bytes", slow: "too_slow" };
65376
65941
  switchOff(ctx, codes[error.reason]);
@@ -65531,8 +66096,8 @@ function registerCheckpoint(runtime, roots, deps = {}) {
65531
66096
  let body = `Abandoned because: ${reason}`;
65532
66097
  const writer = runtime.writer();
65533
66098
  if (writer && turn.steps.length > 0) {
65534
- const timeout = new Promise((resolve13) => {
65535
- setTimeout(() => resolve13(void 0), 8e3).unref?.();
66099
+ const timeout = new Promise((resolve15) => {
66100
+ setTimeout(() => resolve15(void 0), 8e3).unref?.();
65536
66101
  });
65537
66102
  const reply = await Promise.race([
65538
66103
  writer({
@@ -65854,7 +66419,7 @@ The agent then starts over from your request with a note about what did not work
65854
66419
  } catch (error) {
65855
66420
  pending = void 0;
65856
66421
  giveUp(ctx, error);
65857
- if (!(error instanceof GitMissing))
66422
+ if (!(error instanceof GitMissing || error instanceof GitUnusable))
65858
66423
  ctx.ui.notify(
65859
66424
  `The rewind stopped: ${clip(error instanceof Error ? error.message : String(error), 300)}`,
65860
66425
  "error"
@@ -65868,8 +66433,8 @@ The agent then starts over from your request with a note about what did not work
65868
66433
  const wasBusy = busy > 0;
65869
66434
  await Promise.race([
65870
66435
  chain,
65871
- new Promise((resolve13) => {
65872
- setTimeout(resolve13, 3e3).unref?.();
66436
+ new Promise((resolve15) => {
66437
+ setTimeout(resolve15, 3e3).unref?.();
65873
66438
  })
65874
66439
  ]);
65875
66440
  if (store) releaseLocks(store, wasBusy && busy > 0 ? 0 : 12e4);
@@ -65880,7 +66445,7 @@ The agent then starts over from your request with a note about what did not work
65880
66445
 
65881
66446
  // packages/kyrn-judge/src/extension/features/commands.ts
65882
66447
  var import_pi_coding_agent4 = __toESM(require_pi_coding_agent(), 1);
65883
- import { existsSync as existsSync6 } from "node:fs";
66448
+ import { existsSync as existsSync7 } from "node:fs";
65884
66449
  import { join as join18 } from "node:path";
65885
66450
  import { fileURLToPath as fileURLToPath3 } from "node:url";
65886
66451
 
@@ -65940,7 +66505,7 @@ function loadAgents(userDir, builtInDir = BUILT_IN_AGENTS_DIR) {
65940
66505
 
65941
66506
  // packages/kyrn-judge/src/extension/localized-prompts.ts
65942
66507
  import { createHash as createHash4 } from "node:crypto";
65943
- import { existsSync as existsSync5, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "node:fs";
66508
+ import { existsSync as existsSync6, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "node:fs";
65944
66509
  import { join as join17 } from "node:path";
65945
66510
  var FORMAT = 1;
65946
66511
  var LANGUAGE_KEY = /^([A-Za-z]+(?:-[A-Za-z]+)*)-(zh|en):/;
@@ -65982,7 +66547,7 @@ function promptsFor(dir, wording, root) {
65982
66547
  const sources = readdirSync4(dir).filter((name) => name.endsWith(".md")).sort().map((name) => [name, readFileSync8(join17(dir, name), "utf8")]);
65983
66548
  const hash = createHash4("sha256").update(JSON.stringify([FORMAT, wording, sources])).digest("hex").slice(0, 12);
65984
66549
  const target = join17(root, `${wording}-${hash}`);
65985
- if (existsSync5(target)) return target;
66550
+ if (existsSync6(target)) return target;
65986
66551
  const temporary = `${target}.${process.pid}.tmp`;
65987
66552
  mkdirSync7(temporary, { recursive: true, mode: 448 });
65988
66553
  for (const [name, text6] of sources) writeFileSync5(join17(temporary, name), localizeTemplate(text6, wording));
@@ -65991,7 +66556,7 @@ function promptsFor(dir, wording, root) {
65991
66556
  } catch {
65992
66557
  rmSync5(temporary, { recursive: true, force: true });
65993
66558
  }
65994
- return existsSync5(target) ? target : dir;
66559
+ return existsSync6(target) ? target : dir;
65995
66560
  } catch {
65996
66561
  return dir;
65997
66562
  }
@@ -66029,19 +66594,24 @@ function readVersions(judgeRoot, fallbackPi = import_pi_coding_agent3.VERSION) {
66029
66594
  };
66030
66595
  }
66031
66596
  var VERSIONS = readVersions(new URL("../../../", new URL("src/extension/features/welcome.ts", new URL("../", import.meta.url)).href));
66597
+ var HEALTH_ERROR = {
66598
+ unreachable: "not reachable",
66599
+ auth: "no usable key (mu setup)",
66600
+ payment_required: "out of credit"
66601
+ };
66032
66602
  function healthText(view, paint) {
66033
66603
  if (view.judge === "off") return paint.fg("muted", "off \xB7 pi's stock behaviour everywhere");
66034
66604
  if (view.health === "checking") return `${view.judge} ${paint.fg("dim", "\xB7 checking\u2026")}`;
66035
66605
  if (view.health.ok) {
66036
66606
  return `${view.judge} ${paint.fg("success", `\xB7 answering in ${view.health.latencyMs} ms`)} ${paint.fg("dim", `\xB7 decisions ${view.mode}`)}`;
66037
66607
  }
66038
- const why = view.health.error === "unreachable" ? "not reachable" : `failing (${view.health.error ?? "error"})`;
66608
+ const why = HEALTH_ERROR[view.health.error ?? ""] ?? `failing (${view.health.error ?? "error"})`;
66039
66609
  return `${view.judge} ${paint.fg("warning", `\xB7 ${why}, falling back to stock behaviour`)}`;
66040
66610
  }
66041
66611
  function renderWelcome(view, width, paint) {
66042
66612
  const home = homedir4();
66043
66613
  const cwd = view.cwd.startsWith(home) ? `~${view.cwd.slice(home.length)}` : view.cwd;
66044
- const model = view.model ? `${view.model}${view.thinking ? paint.fg("dim", ` \xB7 thinking ${view.thinking}`) : ""}` : paint.fg("warning", "none yet \xB7 /login, then /model");
66614
+ const model = view.model ? `${view.model}${view.thinking ? paint.fg("dim", ` \xB7 thinking ${view.thinking}`) : ""}` : paint.fg("warning", "none yet \xB7 /login, or mu setup in a terminal");
66045
66615
  const rows = [
66046
66616
  ["judge", healthText(view, paint)],
66047
66617
  ["model", model],
@@ -66183,7 +66753,7 @@ var helpZh = () => `mu ${VERSIONS.mu} \xB7 \u5148\u5224\u65AD\u518D\u52A8\u624B\
66183
66753
  \u5224\u65AD\u5C42
66184
66754
  \u4F60\u7684\u6BCF\u6761\u6D88\u606F\u90FD\u5148\u4EA4\u7ED9\u5224\u5B9A\u5668\u8BFB\uFF1A\u8BFB\u7684\u65F6\u5019\u6D88\u606F\u505C\u5728\u8F93\u5165\u6846\u4E0A\u65B9\uFF08\u6309 esc \u53EF\u8DF3\u8FC7\u7B49\u5F85\uFF09\uFF0C
66185
66755
  \u5224\u5B9A\u7ED3\u679C\u7559\u5728\u5BF9\u8BDD\u91CC\u8FD9\u6761\u6D88\u606F\u4E0B\u9762\u3002${(0, import_pi_coding_agent4.keyText)("app.tools.expand")} \u53EF\u4EE5\u770B\u6BCF\u4E2A\u5224\u5B9A\u80CC\u540E\u7684\u5168\u90E8\u56DE\u7B54\u3002
66186
- /mu judge <\u5224\u5B9A\u5668>\uFF1A\u7531\u54EA\u4E9B\u6A21\u578B\u6765\u5224\u5B9A\u3001\u6309\u4EC0\u4E48\u987A\u5E8F\uFF0C\u6BD4\u5982 laya | laya,jev | llm:<\u63D0\u4F9B\u5546>/<\u6A21\u578B>
66756
+ /mu judge <\u5224\u5B9A\u5668>\uFF1A\u7531\u54EA\u4E9B\u6A21\u578B\u6765\u5224\u5B9A\u3001\u6309\u4EC0\u4E48\u987A\u5E8F\uFF0C\u6BD4\u5982 laya | laya,jev | clm | llm:<\u63D0\u4F9B\u5546>/<\u6A21\u578B>
66187
66757
  /mu route <\u5224\u5B9A\u70B9> <\u5224\u5B9A\u5668|default>\uFF1A\u8BA9\u67D0\u4E00\u4E2A\u5224\u5B9A\u70B9\u7528\u81EA\u5DF1\u7684\u5224\u5B9A\u5668\uFF0C\u6BD4\u5982 browser.step luna
66188
66758
  /mu mode <\u5224\u5B9A\u70B9|default> <off|shadow|active>\uFF1Aoff \u5173\u95ED\uFF0Cshadow \u5F71\u5B50\uFF08\u53EA\u8BB0\u5F55\uFF0C\u4E0D\u8D77\u4F5C\u7528\uFF09\uFF0Cactive \u751F\u6548
66189
66759
  /frame\uFF1A\u67E5\u770B\u4EFB\u52A1\u5E27\uFF0C\u4E5F\u5C31\u662F mu \u8BB0\u4F4F\u7684\u76EE\u6807\u3001\u4F60\u7684\u786C\u7EA6\u675F\uFF08\u539F\u8BDD\u52A0\u51FA\u5904\uFF09\u548C\u9A8C\u6536\u6761\u4EF6
@@ -66206,6 +66776,8 @@ var helpZh = () => `mu ${VERSIONS.mu} \xB7 \u5148\u5224\u65AD\u518D\u52A8\u624B\
66206
66776
  /implement <\u4EFB\u52A1>\uFF1A\u4FA6\u5BDF\u3001\u8BA1\u5212\u3001\u5B9E\u73B0\uFF0C\u4E09\u4E2A\u5B50\u4EE3\u7406\u63A5\u529B\uFF0C\u6BCF\u4E2A\u6309\u81EA\u5DF1\u7684\u6E05\u5355\u505A
66207
66777
  /scout-and-plan <\u4EFB\u52A1>\uFF1A\u5148\u4FA6\u5BDF\uFF0C\u518D\u8BA1\u5212\uFF1B\u4EC0\u4E48\u90FD\u4E0D\u6539
66208
66778
  /implement-and-review <\u4EFB\u52A1>\uFF1A\u5B9E\u73B0\u3001\u8BC4\u5BA1\u3001\u4FEE\u6B63
66779
+ /hive <\u95EE\u9898>\uFF1A\u8BA9\u51E0\u4E2A\u8C03\u67E5\u5458\u4ECE\u4E0D\u540C\u89D2\u5EA6\u540C\u65F6\u67E5\u4E00\u4E2A\u95EE\u9898\uFF0C\u5224\u5B9A\u5668\u628A\u6BCF\u4E2A\u4EBA\u7684\u53D1\u73B0\u4F20\u7ED9\u7528\u5F97\u4E0A\u7684\u5176\u4ED6\u4EBA\uFF0C
66780
+ \u56DE\u7B54\u7EFC\u5408\u6240\u6709\u4EBA\u7684\u7ED3\u679C
66209
66781
  /swarm\uFF1A\u6BCF\u4E2A\u6B63\u5728\u8FD0\u884C\u7684\u5B50\u4EE3\u7406\u6B64\u523B\u5728\u505A\u4EC0\u4E48\uFF1B/swarm stop [\u540D\u5B57] \u8BA9\u5B83\u73B0\u5728\u4EA4\u62A5\u544A\u5E76\u4FDD\u7559\u53D1\u73B0\uFF0C
66210
66782
  /swarm kill [\u540D\u5B57] \u7ACB\u523B\u7ED3\u675F\u5B83
66211
66783
  /review [\u8981\u5BA1\u7684\u5185\u5BB9]\uFF1A\u4EA4\u7ED9\u8BC4\u5BA1\u5B50\u4EE3\u7406\u5BA1\u67E5\uFF1B\u5224\u5B9A\u5668\u628A\u8BC4\u5BA1\u53D1\u73B0\u6309\u8F7B\u91CD\u6392\u6210 P0 \u5230 P3
@@ -66231,7 +66803,7 @@ Start here
66231
66803
  Judgment layer
66232
66804
  Every message is read by the judge first: it waits above the editor while that happens (esc skips
66233
66805
  the wait), and the verdict stays under it in the chat. ${(0, import_pi_coding_agent4.keyText)("app.tools.expand")} shows every answer behind a verdict.
66234
- /mu judge <tiers> which models judge, in order: laya | laya,jev | llm:<provider>/<model>
66806
+ /mu judge <tiers> which models judge, in order: laya | laya,jev | clm | llm:<provider>/<model>
66235
66807
  /mu route <decision> <tiers|default> one decision on its own judge, e.g. browser.step luna
66236
66808
  /mu mode <decision|default> <off|shadow|active>
66237
66809
  /frame the task as mu holds it: goal, your hard constraints and where you said them, to-do items
@@ -66255,6 +66827,8 @@ Tools the agent can use (and you can ask for)
66255
66827
  /implement <task> scout, plan, implement: a chain of sub-agents, each working to its own checklist
66256
66828
  /scout-and-plan <task> scout, then plan; nothing is changed
66257
66829
  /implement-and-review <task> implement, review, fix
66830
+ /hive <question> several investigators on one question at once, each from its own angle; the judge
66831
+ passes what one finds to the others it matters to, and the answer draws on all of them
66258
66832
  /swarm what every running sub-agent is doing right now; /swarm stop [name] has it report
66259
66833
  now and keeps what it found, /swarm kill [name] ends it at once
66260
66834
  /review [what] hand a review to the reviewer role; the judge sorts its findings P0 to P3
@@ -66433,7 +67007,7 @@ function registerCommands(runtime, roots) {
66433
67007
  pi.on(
66434
67008
  "resources_discover",
66435
67009
  failOpen(
66436
- () => existsSync6(PROMPTS_DIR) ? {
67010
+ () => existsSync7(PROMPTS_DIR) ? {
66437
67011
  promptPaths: [
66438
67012
  // In mu's own folder, which is the user's alone: a template is text the model follows.
66439
67013
  roots ? promptsFor(PROMPTS_DIR, appLanguage()?.wording, join18(roots.agentDir, "mu", "prompts")) : PROMPTS_DIR
@@ -67715,8 +68289,8 @@ function registerFrame(runtime) {
67715
68289
  let timer;
67716
68290
  const late = await Promise.race([
67717
68291
  ask.pending.then(() => false),
67718
- new Promise((resolve13) => {
67719
- timer = setTimeout(() => resolve13(true), Math.max(0, options.waitMs - (Date.now() - ask.startedAt)));
68292
+ new Promise((resolve15) => {
68293
+ timer = setTimeout(() => resolve15(true), Math.max(0, options.waitMs - (Date.now() - ask.startedAt)));
67720
68294
  })
67721
68295
  ]);
67722
68296
  if (timer) clearTimeout(timer);
@@ -68395,15 +68969,28 @@ ${goal.text}`
68395
68969
  var import_pi_ai3 = __toESM(require_pi_ai(), 1);
68396
68970
 
68397
68971
  // packages/ai/src/providers/data/google.json
68398
- var google_default = { "google-generative-ai": { "deep-research-max-preview-04-2026": { id: "deep-research-max-preview-04-2026", name: "Deep Research Max Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "deep-research-preview-04-2026": { id: "deep-research-preview-04-2026", name: "Deep Research Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-2.5-computer-use-preview-10-2025": { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview 10-2025", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-2.5-flash": { id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-2.5-flash-lite": { id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-2.5-pro": { id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3-flash-preview": { id: "gemini-3-flash-preview", name: "Gemini 3 Flash Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-lite": { id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-lite-image": { id: "gemini-3.1-flash-lite-image", name: "Nano Banana 2 Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: null, medium: null, high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 65536 }, "gemini-3.1-flash-lite-preview": { id: "gemini-3.1-flash-lite-preview", name: "Gemini 3.1 Flash Lite Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-live-preview": { id: "gemini-3.1-flash-live-preview", name: "Gemini 3.1 Flash Live Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 4.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-3.1-pro-preview": { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-pro-preview-customtools": { id: "gemini-3.1-pro-preview-customtools", name: "Gemini 3.1 Pro Preview Custom Tools", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.5-flash": { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.5-flash-lite": { id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.6-flash": { id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.7-flash": { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.8-flash": { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-flash-latest": { id: "gemini-flash-latest", name: "Gemini Flash Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-flash-lite-latest": { id: "gemini-flash-lite-latest", name: "Gemini Flash-Lite Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemma-4-26b-a4b-it": { id: "gemma-4-26b-a4b-it", name: "Gemma 4 26B A4B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, "gemma-4-31b-it": { id: "gemma-4-31b-it", name: "Gemma 4 31B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 } } };
68972
+ var google_default = { "google-generative-ai": { "chat:deep-research-max-preview-04-2026": { id: "deep-research-max-preview-04-2026", name: "Deep Research Max Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:deep-research-preview-04-2026": { id: "deep-research-preview-04-2026", name: "Deep Research Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-computer-use-preview-10-2025": { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview 10-2025", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 64e3, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-flash": { id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-flash-lite": { id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-pro": { id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3-flash-preview": { id: "gemini-3-flash-preview", name: "Gemini 3 Flash Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite": { id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite-image": { id: "gemini-3.1-flash-lite-image", name: "Nano Banana 2 Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: null, medium: null, high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 4096, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite-preview": { id: "gemini-3.1-flash-lite-preview", name: "Gemini 3.1 Flash Lite Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-live-preview": { id: "gemini-3.1-flash-live-preview", name: "Gemini 3.1 Flash Live Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 4.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-pro-preview": { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-pro-preview-customtools": { id: "gemini-3.1-pro-preview-customtools", name: "Gemini 3.1 Pro Preview Custom Tools", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.5-flash": { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.5-flash-lite": { id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.6-flash": { id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.7-flash": { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.8-flash": { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-flash-latest": { id: "gemini-flash-latest", name: "Gemini Flash Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-flash-lite-latest": { id: "gemini-flash-lite-latest", name: "Gemini Flash-Lite Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemma-4-26b-a4b-it": { id: "gemma-4-26b-a4b-it", name: "Gemma 4 26B A4B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemma-4-31b-it": { id: "gemma-4-31b-it", name: "Gemma 4 31B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" } } };
68399
68973
 
68400
68974
  // packages/ai/src/model-catalog.ts
68401
- function flattenModelCatalog(_provider, groups2) {
68402
- return Object.assign({}, ...Object.values(groups2));
68975
+ function flattenModelCatalog(groups2, type) {
68976
+ return Object.fromEntries(
68977
+ Object.values(groups2).flatMap((models) => Object.values(models)).filter((model) => model.type === type).map((model) => [model.id, model])
68978
+ );
68979
+ }
68980
+ function flattenChatModelCatalog(_provider, groups2) {
68981
+ return flattenModelCatalog(groups2, "chat");
68982
+ }
68983
+ function flattenImageModelCatalog(_provider, groups2) {
68984
+ return flattenModelCatalog(groups2, "image");
68985
+ }
68986
+ function flattenClassifierModelCatalog(_provider, groups2) {
68987
+ return flattenModelCatalog(groups2, "classifier");
68403
68988
  }
68404
68989
 
68405
68990
  // packages/ai/src/providers/google.models.ts
68406
- var GOOGLE_MODELS = flattenModelCatalog("google", google_default);
68991
+ var GOOGLE_MODELS = flattenChatModelCatalog("google", google_default);
68992
+ var GOOGLE_IMAGE_MODELS = flattenImageModelCatalog("google", google_default);
68993
+ var GOOGLE_CLASSIFIER_MODELS = flattenClassifierModelCatalog("google", google_default);
68407
68994
 
68408
68995
  // packages/kyrn-judge/src/google-login/providers.ts
68409
68996
  init_endpoints();
@@ -68470,7 +69057,7 @@ async function pkce() {
68470
69057
  return { verifier, challenge: base64url(new Uint8Array(digest2)) };
68471
69058
  }
68472
69059
  function listen(config, state) {
68473
- return new Promise((resolve13, reject) => {
69060
+ return new Promise((resolve15, reject) => {
68474
69061
  let settle = () => {
68475
69062
  };
68476
69063
  const wait = new Promise((done) => {
@@ -68517,7 +69104,7 @@ function listen(config, state) {
68517
69104
  server.listen(
68518
69105
  config.callbackPort,
68519
69106
  config.callbackHost,
68520
- () => resolve13({ server, wait, cancel: () => settle(void 0) })
69107
+ () => resolve15({ server, wait, cancel: () => settle(void 0) })
68521
69108
  );
68522
69109
  });
68523
69110
  }
@@ -68610,7 +69197,7 @@ async function geminiProject(config, token, interaction) {
68610
69197
  if (!started.ok) throw new Error(`onboardUser failed (${started.status}): ${(await started.text()).slice(0, 300)}`);
68611
69198
  let operation = await started.json();
68612
69199
  for (let attempt = 0; !operation.done && operation.name && attempt < 60; attempt++) {
68613
- await new Promise((resolve13) => setTimeout(resolve13, attempt === 0 ? 1e3 : 5e3));
69200
+ await new Promise((resolve15) => setTimeout(resolve15, attempt === 0 ? 1e3 : 5e3));
68614
69201
  const polled = await fetch(`${endpoint}/v1internal/${operation.name}`, { headers, signal: interaction.signal });
68615
69202
  if (!polled.ok) throw new Error(`Setting up the project failed (${polled.status})`);
68616
69203
  operation = await polled.json();
@@ -68943,11 +69530,21 @@ var toolRisk = defineDecision({
68943
69530
  // packages/kyrn-judge/src/extension/features/guard.ts
68944
69531
  var RULES = [
68945
69532
  [/\brm\s+(-[a-zA-Z]+\s+)*-[a-zA-Z]*[rf]/, "recursive or forced delete"],
69533
+ // find deletes what it finds with -delete, or with rm run on each.
69534
+ [/\bfind\b[^|;&\n]*\s-(?:delete\b|(?:exec|execdir|ok|okdir)\s+(?:\S*\/)?rm\b)/, "recursive or forced delete"],
68946
69535
  [
68947
69536
  /\bgit\s+(reset\s+--hard|clean\s+-[a-zA-Z]*f|checkout\s+--\s|branch\s+-D|stash\s+(drop|clear))/,
68948
69537
  "discards git work"
68949
69538
  ],
69539
+ // The same deeds spelled otherwise: clean forced by a later option, a checkout of everything or by force, a
69540
+ // restore of the working tree, a branch deleted by force.
69541
+ [
69542
+ /\bgit\s+(?:clean\b[^|;&\n]*\s(?:-[a-zA-Z]*f|--force)\b|checkout\s+(?:\.(?:\s|$)|-f\b|--force\b)|restore\b(?:(?![^|;&\n]*--staged)|(?=[^|;&\n]*(?:--worktree|\s-W\b)))|branch\b[^|;&\n]*(?:--delete\s+--force|--force\s+--delete|\s-(?:D|df|fd)\b))/,
69543
+ "discards git work"
69544
+ ],
68950
69545
  [/\bgit\s+push\b.*(--force|\s-f\b)/, "force push"],
69546
+ // A `+` refspec forces as well; --mirror, --delete and `:branch` remove what is on the remote.
69547
+ [/\bgit\s+push\b[^|;&\n]*\s(?:\+\S|--mirror\b|--delete\b|-d\b|:\S)/, "force push"],
68951
69548
  [/\b(drop|truncate)\s+(table|database|schema)\b/i, "drops database objects"],
68952
69549
  [/\bmkfs\b|\bdd\b.*\bof=\/dev\//, "overwrites a device"],
68953
69550
  [/\bchmod\s+-R\s+0?777\b/, "opens permissions recursively"],
@@ -68962,9 +69559,14 @@ var RULES = [
68962
69559
  ],
68963
69560
  [/\bStart-Process\b[^|;\n]*-Verb\s+RunAs\b|\brunas\b/i, "runs as administrator"],
68964
69561
  [/\bformat\s+[a-z]:|\bFormat-Volume\b|\bClear-Disk\b/i, "overwrites a device"],
68965
- [/\b(curl|wget)\b[^|;&]*\|\s*(sudo\s+)?(ba|z)?sh\b/, "runs a downloaded script"],
68966
- [/\bsudo\b/, "runs as root"]
69562
+ [/\b(curl|wget)\b[^|;&]*\|\s*(sudo\s+)?(?:(?:ba|z|da|k)?sh|python\d*|perl|ruby|node)\b/, "runs a downloaded script"],
69563
+ // Without a pipe: a download read as a file (`bash <(curl …)`) or as the text of `sh -c "$(curl …)"`.
69564
+ [/<\(\s*(?:curl|wget)\b|\b(?:ba|z|da|k)?sh\s+-c\s+["']?\$\(\s*(?:curl|wget)\b/, "runs a downloaded script"],
69565
+ [/\b(?:sudo|doas|pkexec)\b/, "runs as root"]
68967
69566
  ];
69567
+ function unquoted(command) {
69568
+ return command.replace(/\\(?=[A-Za-z])/g, "").replace(/(["'])([^"'\s]*)\1/g, "$2");
69569
+ }
68968
69570
  var FLAG_ZH = {
68969
69571
  "recursive or forced delete": "\u9012\u5F52\u6216\u5F3A\u5236\u5220\u9664",
68970
69572
  "discards git work": "\u4E22\u5F03 git \u91CC\u7684\u6539\u52A8",
@@ -68989,7 +69591,8 @@ var FLAG_CODES = {
68989
69591
  };
68990
69592
  var COMMAND_TOOLS = /* @__PURE__ */ new Set([...SHELL_TOOLS, "bg_start"]);
68991
69593
  function riskFlag(command) {
68992
- return RULES.find(([pattern]) => pattern.test(command))?.[1];
69594
+ const plain2 = unquoted(command);
69595
+ return RULES.find(([pattern]) => pattern.test(command) || pattern.test(plain2))?.[1];
68993
69596
  }
68994
69597
  function registerGuard(runtime) {
68995
69598
  const options = runtime.options("guard", { enabled: true });
@@ -69003,9 +69606,10 @@ function registerGuard(runtime) {
69003
69606
  const command = String(event.input.command ?? "");
69004
69607
  const flag = riskFlag(command);
69005
69608
  if (!flag) return void 0;
69609
+ const asked = subAgentUserGoal() ?? runtime.turn.userMessage;
69006
69610
  const decision = await runtime.engine.decide(
69007
69611
  toolRisk,
69008
- { command: clip(command, 400), userMessage: clip(runtime.turn.userMessage, 400), flag },
69612
+ { command: clip(command, 400), userMessage: clip(asked, 400), flag },
69009
69613
  { signal: ctx.signal }
69010
69614
  );
69011
69615
  if (decision.mode !== "active" || decision.outcome === "allow") return void 0;
@@ -69086,9 +69690,10 @@ var hiveDeliver = defineDecision({
69086
69690
  return { deliver: false, score: 0 };
69087
69691
  }
69088
69692
  });
69693
+ var ACROSS_BEES_SUPERSEDES = 0.9;
69089
69694
  var hiveRelate = defineDecision({
69090
69695
  id: "hive.relate",
69091
- version: 1,
69696
+ version: 2,
69092
69697
  cacheImpact: "none",
69093
69698
  latency: "background",
69094
69699
  capabilities: "classify",
@@ -69115,7 +69720,9 @@ var hiveRelate = defineDecision({
69115
69720
  const choice = pickChoice(answers.relation);
69116
69721
  const score = answers.relation.probabilities?.[answers.relation.choice] ?? 1;
69117
69722
  if (!choice) return { relation: null, score };
69118
- if (choice === "contradicts" && input.earlier.bee === input.later.bee) return { relation: "supersedes", score };
69723
+ const ownNote = input.earlier.bee === input.later.bee;
69724
+ if (choice === "contradicts" && ownNote) return { relation: "supersedes", score };
69725
+ if (choice === "supersedes" && !ownNote && score < ACROSS_BEES_SUPERSEDES) return { relation: null, score };
69119
69726
  return { relation: choice, score };
69120
69727
  },
69121
69728
  fallback() {
@@ -69291,11 +69898,16 @@ function overlapping(text6, notes, options = {}) {
69291
69898
  function foldRelations(notes, relations) {
69292
69899
  const ids = new Set(notes.map((note2) => note2.id));
69293
69900
  const known = relations.filter((row) => ids.has(row.earlier) && ids.has(row.later));
69901
+ const beeOf = new Map(notes.map((note2) => [note2.id, note2.bee]));
69294
69902
  const superseded = /* @__PURE__ */ new Map();
69295
69903
  const supported = /* @__PURE__ */ new Map();
69296
69904
  for (const row of known) {
69297
69905
  if (row.relation === "supersedes") superseded.set(row.earlier, row);
69298
- else if (row.relation === "supports") supported.set(row.earlier, (supported.get(row.earlier) ?? 0) + 1);
69906
+ else if (row.relation === "supports") {
69907
+ const by = beeOf.get(row.later) ?? row.by;
69908
+ const named = supported.get(row.earlier) ?? [];
69909
+ if (by !== beeOf.get(row.earlier) && !named.includes(by)) supported.set(row.earlier, [...named, by]);
69910
+ }
69299
69911
  }
69300
69912
  const contested = /* @__PURE__ */ new Map();
69301
69913
  for (const row of known) {
@@ -69315,12 +69927,34 @@ function isDuplicate(text6, notes, overlap = 0.8) {
69315
69927
  });
69316
69928
  }
69317
69929
 
69930
+ // packages/kyrn-judge/src/hive/request.ts
69931
+ function parseHiveArgs(args) {
69932
+ const text6 = args.trim();
69933
+ if (!text6 || text6 === "status") return { kind: "status" };
69934
+ const [verb, name, ...more] = text6.split(/\s+/);
69935
+ if ((verb === "stop" || verb === "kill") && more.length === 0) {
69936
+ return { kind: "control", verb, ...name ? { name } : {} };
69937
+ }
69938
+ return { kind: "question", question: text6 };
69939
+ }
69940
+ function hiveRequest(question) {
69941
+ return [
69942
+ `Question for a hive: ${question.trim()}`,
69943
+ "",
69944
+ "Call the `hive` tool now, as your first step: do not read anything first, and do not ask me anything.",
69945
+ "- goal: my question as I asked it, and what a complete answer to it must contain.",
69946
+ "- bees: three investigators (two for a narrow question, four for one with four separate parts). Give each a different angle on the same question, chosen so that what one finds can confirm, correct or advance what the others look at: where it is implemented, how it is configured or called, what running it or its tests shows, what the history or the documentation says. Name each after its angle.",
69947
+ "",
69948
+ "When the hive returns, answer my question from the reports and the board: the answer first, then the evidence (file:line, commands and what they printed). Rely most on findings that were confirmed or that corrected another, and say what stayed disputed or unverified. Answer in the language of my question."
69949
+ ].join("\n");
69950
+ }
69951
+
69318
69952
  // packages/kyrn-judge/src/extension/features/swarm.ts
69319
69953
  var import_pi_coding_agent6 = __toESM(require_pi_coding_agent(), 1);
69320
69954
  var import_typebox6 = __toESM(require_typebox(), 1);
69321
69955
  import { spawn as spawn6 } from "node:child_process";
69322
69956
  import { randomUUID as randomUUID5 } from "node:crypto";
69323
- import { existsSync as existsSync8 } from "node:fs";
69957
+ import { existsSync as existsSync9 } from "node:fs";
69324
69958
  import { mkdtemp, readFile as readFile2, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
69325
69959
  import { tmpdir as tmpdir5 } from "node:os";
69326
69960
  import { basename as basename6, join as join24 } from "node:path";
@@ -69333,7 +69967,7 @@ import { join as join22 } from "node:path";
69333
69967
 
69334
69968
  // packages/kyrn-judge/src/swarm/worktree.ts
69335
69969
  import { spawn as spawn5 } from "node:child_process";
69336
- import { existsSync as existsSync7 } from "node:fs";
69970
+ import { existsSync as existsSync8 } from "node:fs";
69337
69971
  import { chmod, copyFile, lstat, mkdir, readdir, readFile, readlink, rm, symlink, writeFile } from "node:fs/promises";
69338
69972
  import { dirname as dirname3, join as join21 } from "node:path";
69339
69973
  function gitArgs(args, platform = process.platform) {
@@ -69349,7 +69983,7 @@ function gitArgs(args, platform = process.platform) {
69349
69983
  ];
69350
69984
  }
69351
69985
  var INHERITED = ["GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR", "GIT_PREFIX"];
69352
- var runGit = (args, options) => new Promise((resolve13) => {
69986
+ var spawnGit2 = (args, options) => new Promise((resolve15) => {
69353
69987
  const env = { ...process.env };
69354
69988
  for (const name of INHERITED) delete env[name];
69355
69989
  Object.assign(env, { LC_ALL: "C", LANGUAGE: "C", GIT_TERMINAL_PROMPT: "0" }, options.env);
@@ -69366,7 +70000,7 @@ var runGit = (args, options) => new Promise((resolve13) => {
69366
70000
  signal: options.signal
69367
70001
  });
69368
70002
  } catch (error) {
69369
- resolve13({ code: -1, stdout: Buffer.alloc(0), stderr: String(error), missing: true });
70003
+ resolve15({ code: -1, stdout: Buffer.alloc(0), stderr: String(error), missing: true });
69370
70004
  return;
69371
70005
  }
69372
70006
  child.stdout?.on("data", (chunk) => out.push(chunk));
@@ -69374,12 +70008,25 @@ var runGit = (args, options) => new Promise((resolve13) => {
69374
70008
  stderr = (stderr + chunk.toString("utf8")).slice(-8e3);
69375
70009
  });
69376
70010
  child.on("error", (error) => {
69377
- resolve13({ code: -1, stdout: Buffer.concat(out), stderr: error.message, missing: error.code === "ENOENT" });
70011
+ resolve15({ code: -1, stdout: Buffer.concat(out), stderr: error.message, missing: error.code === "ENOENT" });
69378
70012
  });
69379
- child.on("close", (code) => resolve13({ code: code ?? -1, stdout: Buffer.concat(out), stderr }));
70013
+ child.on("close", (code) => resolve15({ code: code ?? -1, stdout: Buffer.concat(out), stderr }));
69380
70014
  child.stdin?.on("error", () => void 0);
69381
70015
  child.stdin?.end(options.input);
69382
70016
  });
70017
+ function gitRunner(probe = hostProbe) {
70018
+ let stub;
70019
+ return async (args, options) => {
70020
+ stub ??= stubProblem("git", options.env?.PATH ?? process.env.PATH, probe);
70021
+ const problem = await stub;
70022
+ if (problem)
70023
+ return { code: -1, stdout: Buffer.alloc(0), stderr: problem.message, missing: true, unusable: problem.reason };
70024
+ const result = await spawnGit2(args, options);
70025
+ return heldByLicense(result.code, () => `${result.stderr}
70026
+ ${result.stdout.toString("utf8")}`) ? { ...result, missing: true, unusable: "xcode_license" } : result;
70027
+ };
70028
+ }
70029
+ var runGit = gitRunner();
69383
70030
  var text2 = (result) => result.stdout.toString("utf8");
69384
70031
  var lastLine = (stderr) => stderr.trim().split("\n").pop()?.trim() ?? "";
69385
70032
  var BUSY = [
@@ -69392,6 +70039,7 @@ var BUSY = [
69392
70039
  ];
69393
70040
  async function checkRepo(run2, cwd) {
69394
70041
  const probe = await run2(["rev-parse", "--is-bare-repository", "--is-inside-work-tree"], { cwd });
70042
+ if (probe.unusable) return { ok: false, problem: "no-git", message: UNUSABLE_TEXT[probe.unusable] };
69395
70043
  if (probe.missing) return { ok: false, problem: "no-git", message: "git is not installed or not on PATH" };
69396
70044
  if (probe.code !== 0)
69397
70045
  return { ok: false, problem: "not-a-repo", message: "this directory is not in a git repository" };
@@ -69403,7 +70051,7 @@ async function checkRepo(run2, cwd) {
69403
70051
  if (where2.code !== 0) return { ok: false, problem: "not-a-repo", message: lastLine(where2.stderr) };
69404
70052
  if (head.code !== 0) return { ok: false, problem: "no-commit", message: "the repository has no commit yet" };
69405
70053
  const [root, gitDir, prefix = ""] = text2(where2).replace(/\n$/, "").split("\n");
69406
- const busy = BUSY.find(([name]) => existsSync7(join21(gitDir, name)));
70054
+ const busy = BUSY.find(([name]) => existsSync8(join21(gitDir, name)));
69407
70055
  if (busy) return { ok: false, problem: "busy", message: `${busy[1]} is in progress in this repository` };
69408
70056
  return { ok: true, repo: { root, gitDir, prefix, head: text2(head).trim() } };
69409
70057
  }
@@ -69550,11 +70198,11 @@ async function removeWorktree(run2, worktree) {
69550
70198
  const problems = [];
69551
70199
  const cwd = worktree.repoRoot;
69552
70200
  let removed = await run2(["worktree", "remove", "--force", worktree.dir], { cwd });
69553
- if (removed.code !== 0 || existsSync7(worktree.dir)) {
70201
+ if (removed.code !== 0 || existsSync8(worktree.dir)) {
69554
70202
  await rm(worktree.dir, { recursive: true, force: true, maxRetries: 8, retryDelay: 250 }).catch(() => void 0);
69555
70203
  removed = await run2(["worktree", "remove", "--force", worktree.dir], { cwd });
69556
70204
  if (removed.code !== 0) await run2(["worktree", "prune"], { cwd });
69557
- if (existsSync7(worktree.dir)) problems.push(`could not delete ${worktree.dir}`);
70205
+ if (existsSync8(worktree.dir)) problems.push(`could not delete ${worktree.dir}`);
69558
70206
  }
69559
70207
  const listed2 = await run2(["branch", "--list", worktree.branch], { cwd });
69560
70208
  if (text2(listed2).trim()) {
@@ -69598,9 +70246,9 @@ async function sweepStaleWorktrees(run2, options) {
69598
70246
  if (markerPath(marker.dir) !== path || typeof marker.repoRoot !== "string") continue;
69599
70247
  const stale = marker.released || !alive(marker.pid) || now - marker.createdAt > maxAge;
69600
70248
  if (!stale) continue;
69601
- if (existsSync7(marker.repoRoot)) await removeWorktree(run2, marker);
70249
+ if (existsSync8(marker.repoRoot)) await removeWorktree(run2, marker);
69602
70250
  else await rm(marker.dir, { recursive: true, force: true }).catch(() => void 0);
69603
- if (!existsSync7(marker.dir)) {
70251
+ if (!existsSync8(marker.dir)) {
69604
70252
  await rm(path, { force: true }).catch(() => void 0);
69605
70253
  swept.push(marker);
69606
70254
  }
@@ -69760,6 +70408,7 @@ function readPatch(record4) {
69760
70408
 
69761
70409
  // packages/kyrn-judge/src/swarm/view.ts
69762
70410
  var import_pi_tui2 = __toESM(require_pi_tui(), 1);
70411
+ import { stripVTControlCharacters } from "node:util";
69763
70412
  function clock2(ms) {
69764
70413
  const seconds3 = Math.max(0, Math.round(ms / 1e3));
69765
70414
  return seconds3 < 60 ? `${seconds3}s` : `${Math.floor(seconds3 / 60)}m${String(seconds3 % 60).padStart(2, "0")}s`;
@@ -69827,7 +70476,7 @@ function quote(text6, width, maxLines, paint) {
69827
70476
  const lines2 = (0, import_pi_tui2.wrapTextWithAnsi)(flat3(text6), Math.max(16, width));
69828
70477
  const shown2 = lines2.slice(0, maxLines);
69829
70478
  if (lines2.length > maxLines)
69830
- shown2[maxLines - 1] = `${(0, import_pi_tui2.truncateToWidth)(shown2[maxLines - 1], Math.max(8, width - 2))} \u2026`;
70479
+ shown2[maxLines - 1] = `${(0, import_pi_tui2.truncateToWidth)(shown2[maxLines - 1], Math.max(8, width - 2), "")} \u2026`;
69831
70480
  return shown2.map((line2) => paint.fg("dim", line2));
69832
70481
  }
69833
70482
  function renderSwarm(snapshot2, options, paint) {
@@ -69901,7 +70550,11 @@ function renderSwarm(snapshot2, options, paint) {
69901
70550
  } else if (expanded) {
69902
70551
  lines2.push(paint.fg("dim", `transcripts, board and gate log: ${snapshot2.dir}`));
69903
70552
  }
69904
- return lines2.map((line2) => (0, import_pi_tui2.truncateToWidth)(line2, width));
70553
+ return lines2.map((line2) => (0, import_pi_tui2.truncateToWidth)(line2, width, "\u2026"));
70554
+ }
70555
+ var PLAIN = { fg: (_color, text6) => text6, bold: (text6) => text6 };
70556
+ function swarmText(snapshot2, options) {
70557
+ return stripVTControlCharacters(renderSwarm(snapshot2, options, PLAIN).join("\n"));
69905
70558
  }
69906
70559
 
69907
70560
  // packages/kyrn-judge/src/extension/features/swarm-isolation.ts
@@ -70266,7 +70919,8 @@ The patch is kept.`,
70266
70919
  };
70267
70920
  function rebase(instructions, parent, dir) {
70268
70921
  const prefix = parent.repo.prefix.replace(/[\\/]$/, "");
70269
- const asSpelled = prefix && parent.cwd.endsWith(prefix) ? parent.cwd.slice(0, -prefix.length - 1) : parent.cwd;
70922
+ const nested = prefix && parent.cwd.replaceAll("\\", "/").endsWith(`/${prefix}`);
70923
+ const asSpelled = nested ? parent.cwd.slice(0, -prefix.length - 1) : parent.cwd;
70270
70924
  const roots = [.../* @__PURE__ */ new Set([parent.repo.root, asSpelled])].sort((a, b) => b.length - a.length);
70271
70925
  return roots.reduce((text6, root) => root ? text6.split(root).join(dir) : text6, instructions);
70272
70926
  }
@@ -70300,7 +70954,7 @@ function thinkingForRoute(route) {
70300
70954
  }
70301
70955
  function piInvocation(args) {
70302
70956
  const script = process.argv[1];
70303
- if (script && existsSync8(script)) return { command: process.execPath, args: [...process.execArgv, script, ...args] };
70957
+ if (script && existsSync9(script)) return { command: process.execPath, args: [...process.execArgv, script, ...args] };
70304
70958
  const generic = /^(node|bun)(\.exe)?$/.test(basename6(process.execPath).toLowerCase());
70305
70959
  return generic ? { command: "pi", args } : { command: process.execPath, args };
70306
70960
  }
@@ -70374,7 +71028,7 @@ var spawnRunner = async (task, assignment, signal, env, observer) => {
70374
71028
  await writeFile2(promptPath, assignment.agent.systemPrompt, { encoding: "utf8", mode: 384 });
70375
71029
  }
70376
71030
  try {
70377
- return await new Promise((resolve13, reject) => {
71031
+ return await new Promise((resolve15, reject) => {
70378
71032
  const invocation = piInvocation(childArgs(task, assignment, promptPath));
70379
71033
  const child = spawn6(invocation.command, invocation.args, {
70380
71034
  // An isolated sub-agent works in its own checkout; everyone else where the parent is.
@@ -70411,7 +71065,7 @@ var spawnRunner = async (task, assignment, signal, env, observer) => {
70411
71065
  finished = true;
70412
71066
  signal?.removeEventListener("abort", onAbort);
70413
71067
  if (error) reject(error);
70414
- else resolve13(lastText.trim());
71068
+ else resolve15(lastText.trim());
70415
71069
  };
70416
71070
  const onAbort = () => {
70417
71071
  terminate();
@@ -70489,7 +71143,7 @@ function announceRouting(onUpdate, count3) {
70489
71143
  var SWARM_LIMIT_DEFAULTS = {
70490
71144
  /** Minutes a sub-agent may work before it is told to wrap up and report. 0 means no budget. */
70491
71145
  beeMinutes: 10,
70492
- /** Seconds it then has to hand in its report. */
71146
+ /** Seconds it then has to hand in its report, from when it heard it was to; twice this at most from the asking. */
70493
71147
  graceSeconds: 90,
70494
71148
  /** Seconds without a sign of life before it is stopped: while the model thinks, and while a tool runs. */
70495
71149
  stallSeconds: 300,
@@ -70514,7 +71168,7 @@ function streamUpdates(run2, onUpdate) {
70514
71168
  last = Date.now();
70515
71169
  const snapshot2 = run2.snapshot();
70516
71170
  onUpdate({
70517
- content: [{ type: "text", text: renderSwarm(snapshot2, { expanded: false, width: 120 }, PLAIN).join("\n") }],
71171
+ content: [{ type: "text", text: swarmText(snapshot2, { expanded: false, width: 120 }) }],
70518
71172
  details: { snapshot: snapshot2 }
70519
71173
  });
70520
71174
  };
@@ -70528,7 +71182,6 @@ function streamUpdates(run2, onUpdate) {
70528
71182
  else pending ??= setTimeout(send, wait);
70529
71183
  };
70530
71184
  }
70531
- var PLAIN = { fg: (_color, text6) => text6, bold: (text6) => text6 };
70532
71185
  function renderSwarmResult(result, options, theme) {
70533
71186
  const details = result.details;
70534
71187
  return {
@@ -70621,11 +71274,12 @@ function registerSwarm(runtime, runner = spawnRunner) {
70621
71274
  execute: async (_toolCallId, params, signal, onUpdate, ctx) => {
70622
71275
  runtime.touch(ctx);
70623
71276
  const parent = runtime.frame;
71277
+ const userGoal = userWords(runtime.turn.userMessage);
70624
71278
  const tasks = params.tasks.slice(0, options.maxTasks).map((task) => ({
70625
71279
  title: task.title,
70626
71280
  instructions: task.instructions,
70627
71281
  agent: task.agent,
70628
- brief: briefFor(task, parent)
71282
+ brief: briefFor(task, parent, userGoal)
70629
71283
  }));
70630
71284
  const constraints = (parent?.constraints ?? []).map((constraint) => constraint.text);
70631
71285
  const inheritedConstraints = constraints.length > 0 ? { KYRN_SWARM_CONSTRAINTS: JSON.stringify(constraints.slice(-12)) } : void 0;
@@ -70775,54 +71429,48 @@ ${checklist}` : ""}${isolation.describe(outcomesOfIsolation.get(task))}`;
70775
71429
  });
70776
71430
  }
70777
71431
  var withCommand = /* @__PURE__ */ new WeakSet();
70778
- function registerSwarmCommand(runtime) {
70779
- if (withCommand.has(runtime)) return;
70780
- withCommand.add(runtime);
70781
- const handler = async (args, ctx) => {
70782
- const [verb = "status", ...rest] = args.trim().split(/\s+/).filter(Boolean);
70783
- const name = rest.join(" ") || void 0;
70784
- const runs = activeRuns();
70785
- const patches = patchesOf(runtime).map((record4) => ` ${describeRecord2(record4)}`);
70786
- const patchList = patches.length > 0 ? `patches (apply_patch_from brings one in)
71432
+ function controlSwarm(runtime, args, ctx, idle) {
71433
+ const [verb = "status", ...rest] = args.trim().split(/\s+/).filter(Boolean);
71434
+ const name = rest.join(" ") || void 0;
71435
+ const runs = activeRuns();
71436
+ const patches = patchesOf(runtime).map((record4) => ` ${describeRecord2(record4)}`);
71437
+ const patchList = patches.length > 0 ? `patches (apply_patch_from brings one in)
70787
71438
  ${patches.join("\n")}` : "";
70788
- if (runs.length === 0) {
70789
- ctx.ui.notify(
70790
- patchList || "No sub-agents are running. They start when the agent uses its delegate or hive tool.",
70791
- "info"
70792
- );
70793
- return;
70794
- }
70795
- if (verb === "stop" || verb === "kill") {
70796
- const reached = runs.reduce(
70797
- (sum, run2) => sum + (verb === "stop" ? run2.wrapUp(name, "stopped by the user", { code: "stopped_by_user" }) : run2.kill(name, "ended by the user", "stopped", { code: "ended_by_user" })),
70798
- 0
70799
- );
70800
- ctx.ui.notify(
70801
- reached === 0 ? `Nothing to ${verb}${name ? ` named "${name}"` : ""}. Running: ${runs.flatMap((run2) => run2.bees.map((bee) => bee.name)).join(", ")}` : verb === "stop" ? `Asked ${reached} sub-agent${reached === 1 ? "" : "s"} to stop and report. Anything that has not reported in time is ended.` : `Ended ${reached} sub-agent${reached === 1 ? "" : "s"}. What they had found is kept.`,
70802
- reached === 0 ? "warning" : "info"
70803
- );
70804
- return;
70805
- }
70806
- const theme = PLAIN;
71439
+ if (runs.length === 0) {
70807
71440
  ctx.ui.notify(
70808
- [
70809
- ...runs.map((run2) => renderSwarm(run2.snapshot(), { expanded: true, width: 110 }, theme).join("\n")),
70810
- patchList
70811
- ].filter(Boolean).join("\n\n"),
71441
+ [patchList || "No sub-agents are running. They start when the agent uses its delegate or hive tool.", idle].filter(Boolean).join("\n"),
70812
71442
  "info"
70813
71443
  );
70814
- };
70815
- for (const command of ["swarm", "hive"]) {
70816
- runtime.pi.registerCommand(command, {
70817
- description: command === "swarm" ? say({
70818
- zh: "\u6B63\u5728\u5E72\u6D3B\u7684\u5B50\u4EE3\u7406\uFF1A/swarm \u770B\u6BCF\u4E2A\u5728\u505A\u4EC0\u4E48\uFF0C/swarm stop [\u540D\u5B57] \u8BA9\u5B83\u73B0\u5728\u4EA4\u62A5\u544A\uFF0C/swarm kill [\u540D\u5B57] \u7ACB\u523B\u7ED3\u675F\u5B83",
70819
- en: "Sub-agents at work: /swarm (what each one is doing), /swarm stop [name] (report now), /swarm kill [name]"
70820
- }) : say({ zh: "\u540C /swarm", en: "Same as /swarm" }),
70821
- // No argument completions on purpose: with them the first Enter picks a completion and only the
70822
- // second one runs the command, and "stop" is typed by someone who wants it to happen now.
70823
- handler
70824
- });
71444
+ return;
70825
71445
  }
71446
+ if (verb === "stop" || verb === "kill") {
71447
+ const reached = runs.reduce(
71448
+ (sum, run2) => sum + (verb === "stop" ? run2.wrapUp(name, "stopped by the user", { code: "stopped_by_user" }) : run2.kill(name, "ended by the user", "stopped", { code: "ended_by_user" })),
71449
+ 0
71450
+ );
71451
+ ctx.ui.notify(
71452
+ reached === 0 ? `Nothing to ${verb}${name ? ` named "${name}"` : ""}. Running: ${runs.flatMap((run2) => run2.bees.map((bee) => bee.name)).join(", ")}` : verb === "stop" ? `Asked ${reached} sub-agent${reached === 1 ? "" : "s"} to stop and report. Anything that has not reported in time is ended.` : `Ended ${reached} sub-agent${reached === 1 ? "" : "s"}. What they had found is kept.`,
71453
+ reached === 0 ? "warning" : "info"
71454
+ );
71455
+ return;
71456
+ }
71457
+ ctx.ui.notify(
71458
+ [...runs.map((run2) => swarmText(run2.snapshot(), { expanded: true, width: 110 })), patchList].filter(Boolean).join("\n\n"),
71459
+ "info"
71460
+ );
71461
+ }
71462
+ function registerSwarmCommand(runtime) {
71463
+ if (withCommand.has(runtime)) return;
71464
+ withCommand.add(runtime);
71465
+ runtime.pi.registerCommand("swarm", {
71466
+ description: say({
71467
+ zh: "\u6B63\u5728\u5E72\u6D3B\u7684\u5B50\u4EE3\u7406\uFF1A/swarm \u770B\u6BCF\u4E2A\u5728\u505A\u4EC0\u4E48\uFF0C/swarm stop [\u540D\u5B57] \u8BA9\u5B83\u73B0\u5728\u4EA4\u62A5\u544A\uFF0C/swarm kill [\u540D\u5B57] \u7ACB\u523B\u7ED3\u675F\u5B83",
71468
+ en: "Sub-agents at work: /swarm (what each one is doing), /swarm stop [name] (report now), /swarm kill [name]"
71469
+ }),
71470
+ // No argument completions on purpose: with them the first Enter picks a completion and only the
71471
+ // second one runs the command, and "stop" is typed by someone who wants it to happen now.
71472
+ handler: async (args, ctx) => controlSwarm(runtime, args, ctx)
71473
+ });
70826
71474
  }
70827
71475
 
70828
71476
  // packages/kyrn-judge/src/extension/features/swarm-child.ts
@@ -70987,6 +71635,7 @@ function registerMember(runtime, dir) {
70987
71635
  const verdicts = await runtime.engine.decideMany(hiveRelate, inputs, { signal });
70988
71636
  pairs.forEach(({ note: note2, earlier }, at) => {
70989
71637
  const { relation, score } = verdicts[at].outcome;
71638
+ const answer = verdicts[at].answers?.relation;
70990
71639
  board.log({
70991
71640
  gate: "relate",
70992
71641
  by: me,
@@ -70994,6 +71643,7 @@ function registerMember(runtime, dir) {
70994
71643
  earlier: earlier.id,
70995
71644
  relation,
70996
71645
  score,
71646
+ ...answer?.type === "choice" ? { choice: answer.choice, ...answer.probabilities ? { p: answer.probabilities } : {} } : {},
70997
71647
  reason: verdicts[at].reason
70998
71648
  });
70999
71649
  if (relation)
@@ -71115,21 +71765,23 @@ function registerMember(runtime, dir) {
71115
71765
  queue = queue.then(() => step(candidates, ctx.signal)).catch(() => void 0);
71116
71766
  if (isWrappingUp(runtime)) return void 0;
71117
71767
  if (event.toolResults.length > 0) {
71768
+ const told2 = [];
71118
71769
  if (inbox.length > 0) {
71119
71770
  const lines3 = takeInbox();
71120
- if (lines3.length > 0) tell(`${NOTES_HEADER}
71771
+ if (lines3.length > 0) told2.push(`${NOTES_HEADER}
71121
71772
  ${lines3.join("\n")}`);
71122
71773
  }
71123
71774
  const spoke = candidates.some((candidate) => candidate.source === "said");
71124
71775
  silentCalls = spoke ? 0 : silentCalls + event.toolResults.length;
71125
71776
  if (options.checkpointEvery > 0 && silentCalls >= options.checkpointEvery) {
71126
71777
  silentCalls = 0;
71127
- tell(CHECKPOINT);
71778
+ told2.push(CHECKPOINT);
71128
71779
  }
71780
+ if (told2.length > 0) tell(told2.join("\n\n"));
71129
71781
  return void 0;
71130
71782
  }
71131
71783
  if (lastCalled || !options.lastCall) return void 0;
71132
- await Promise.race([queue, new Promise((resolve13) => setTimeout(resolve13, LAST_CALL_WAIT_MS))]);
71784
+ await Promise.race([queue, new Promise((resolve15) => setTimeout(resolve15, LAST_CALL_WAIT_MS))]);
71133
71785
  if (inbox.length === 0) return void 0;
71134
71786
  const lines2 = takeInbox();
71135
71787
  if (lines2.length === 0) return void 0;
@@ -71141,7 +71793,7 @@ ${lines3.join("\n")}`);
71141
71793
  runtime.pi.on(
71142
71794
  "agent_end",
71143
71795
  failOpen(async () => {
71144
- await Promise.race([queue, new Promise((resolve13) => setTimeout(resolve13, 6e3))]);
71796
+ await Promise.race([queue, new Promise((resolve15) => setTimeout(resolve15, 6e3))]);
71145
71797
  return void 0;
71146
71798
  })
71147
71799
  );
@@ -71241,6 +71893,14 @@ ${others.join("\n")}`,
71241
71893
  thinking: member.assignment.thinking,
71242
71894
  env: {
71243
71895
  ...permissionEnv(runtime),
71896
+ // The angle is the bee's goal; what the user asked for is what its calls are weighed against.
71897
+ [BRIEF_ENV]: briefEnv(
71898
+ briefFor(
71899
+ { title: member.name, instructions: `${member.focus} (part of: ${params.goal})` },
71900
+ runtime.frame,
71901
+ userWords(runtime.turn.userMessage)
71902
+ )
71903
+ ),
71244
71904
  KYRN_HIVE_DIR: dir,
71245
71905
  KYRN_HIVE_BEE: member.name,
71246
71906
  KYRN_HIVE_GOAL: clip(params.goal, 600),
@@ -71323,7 +71983,7 @@ ${others.join("\n")}`,
71323
71983
  const marks = (note2) => {
71324
71984
  const parts = [];
71325
71985
  const confirmed = state.supported.get(note2.id);
71326
- if (confirmed) parts.push(`confirmed by ${confirmed}`);
71986
+ if (confirmed) parts.push(`confirmed by ${confirmed.join(", ")}`);
71327
71987
  if (state.contested.has(note2.id)) parts.push("in dispute");
71328
71988
  return parts.length > 0 ? ` (${parts.join(", ")})` : "";
71329
71989
  };
@@ -71383,6 +72043,80 @@ ${sections.join("\n")}
71383
72043
  renderResult: (result, renderOptions, theme) => renderSwarmResult(result, renderOptions, theme)
71384
72044
  });
71385
72045
  registerSwarmCommand(runtime);
72046
+ registerHiveCommand(runtime);
72047
+ }
72048
+ var TURN_START_MS = 6e4;
72049
+ function registerHiveCommand(runtime) {
72050
+ const { pi } = runtime;
72051
+ let waiting;
72052
+ pi.on(
72053
+ "agent_start",
72054
+ failOpen(() => {
72055
+ if (waiting) waiting.started = true;
72056
+ return void 0;
72057
+ })
72058
+ );
72059
+ pi.on(
72060
+ "agent_settled",
72061
+ failOpen(() => {
72062
+ if (waiting?.started) waiting.over();
72063
+ return void 0;
72064
+ })
72065
+ );
72066
+ const untilTurnEnds = () => new Promise((resolve15) => {
72067
+ let timer;
72068
+ const over = () => {
72069
+ clearTimeout(timer);
72070
+ waiting = void 0;
72071
+ resolve15();
72072
+ };
72073
+ waiting = { started: false, over };
72074
+ timer = setTimeout(() => {
72075
+ if (!waiting?.started) over();
72076
+ }, TURN_START_MS);
72077
+ timer.unref?.();
72078
+ });
72079
+ pi.registerCommand("hive", {
72080
+ description: say({
72081
+ zh: "\u8BA9\u51E0\u4E2A\u8C03\u67E5\u5458\u540C\u65F6\u67E5\u4E00\u4E2A\u95EE\u9898\uFF1A/hive <\u95EE\u9898>\uFF1B\u4E0D\u5E26\u95EE\u9898\u65F6\u540C /swarm\uFF0C\u770B\u6B63\u5728\u5E72\u6D3B\u7684\u5B50\u4EE3\u7406",
72082
+ en: "Put several investigators on one question at once: /hive <question>. Without one, the same as /swarm"
72083
+ }),
72084
+ // No argument completions, like /swarm: "/hive stop" is typed by someone who wants it to happen now.
72085
+ handler: async (args, ctx) => {
72086
+ runtime.touch(ctx);
72087
+ const asked = parseHiveArgs(args);
72088
+ if (asked.kind !== "question") {
72089
+ const control = asked.kind === "control" ? `${asked.verb} ${asked.name ?? ""}` : "";
72090
+ controlSwarm(runtime, control, ctx, "/hive <question> puts several investigators on a question of yours.");
72091
+ return;
72092
+ }
72093
+ const refuse = (message) => {
72094
+ if (!ctx.hasUI) throw new Error(message);
72095
+ ctx.ui.notify(message, "warning");
72096
+ };
72097
+ if (!pi.getActiveTools().includes("hive")) {
72098
+ refuse("The hive tool is not active in this session (--tools leaves it out), so /hive cannot start one.");
72099
+ return;
72100
+ }
72101
+ if (!ctx.model) {
72102
+ refuse("No model is selected: /login, then /model.");
72103
+ return;
72104
+ }
72105
+ const request = hiveRequest(asked.question);
72106
+ if (!ctx.isIdle()) {
72107
+ pi.sendUserMessage(request, { deliverAs: "followUp" });
72108
+ ctx.ui.notify("The hive starts when the current turn is over.", "info");
72109
+ return;
72110
+ }
72111
+ const typed = `/hive ${asked.question}`;
72112
+ runtime.beginTurn(typed);
72113
+ runtime.startTurnWork(typed);
72114
+ const wait = (ctx.mode === "print" || ctx.mode === "json") && ctx.modelRegistry.hasConfiguredAuth(ctx.model);
72115
+ const over = wait ? untilTurnEnds() : void 0;
72116
+ pi.sendUserMessage(request);
72117
+ await over;
72118
+ }
72119
+ });
71386
72120
  }
71387
72121
  function summarizeBoard(board) {
71388
72122
  const notes = board.all();
@@ -71421,12 +72155,12 @@ var import_pi_coding_agent8 = __toESM(require_pi_coding_agent(), 1);
71421
72155
  var import_pi_tui3 = __toESM(require_pi_tui(), 1);
71422
72156
 
71423
72157
  // packages/kyrn-judge/src/import/index.ts
71424
- import { mkdirSync as mkdirSync11, readdirSync as readdirSync6, realpathSync as realpathSync2, statSync as statSync8 } from "node:fs";
72158
+ import { mkdirSync as mkdirSync11, readdirSync as readdirSync6, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
71425
72159
  import { homedir as homedir6 } from "node:os";
71426
72160
  import { join as join27 } from "node:path";
71427
72161
 
71428
72162
  // packages/kyrn-judge/src/import/claude-code.ts
71429
- import { statSync as statSync6 } from "node:fs";
72163
+ import { statSync as statSync7 } from "node:fs";
71430
72164
  import { basename as basename7 } from "node:path";
71431
72165
 
71432
72166
  // packages/kyrn-judge/src/import/jsonl.ts
@@ -71522,7 +72256,7 @@ function list(value) {
71522
72256
 
71523
72257
  // packages/kyrn-judge/src/import/session.ts
71524
72258
  import { randomBytes as randomBytes2, randomUUID as randomUUID7 } from "node:crypto";
71525
- import { closeSync as closeSync3, openSync as openSync3, readdirSync as readdirSync5, statSync as statSync5, writeSync } from "node:fs";
72259
+ import { closeSync as closeSync3, openSync as openSync3, readdirSync as readdirSync5, statSync as statSync6, writeSync } from "node:fs";
71526
72260
  import { homedir as homedir5 } from "node:os";
71527
72261
  import { isAbsolute as isAbsolute3, join as join26, resolve as resolve4 } from "node:path";
71528
72262
  var TOOL_NAMES = { "claude-code": "Claude Code", codex: "Codex" };
@@ -71622,7 +72356,7 @@ function findImports(store) {
71622
72356
  if (name.endsWith(".jsonl")) files.push(path);
71623
72357
  else if (depth > 0) {
71624
72358
  try {
71625
- if (statSync5(path).isDirectory()) scan2(path, depth - 1);
72359
+ if (statSync6(path).isDirectory()) scan2(path, depth - 1);
71626
72360
  } catch {
71627
72361
  }
71628
72362
  }
@@ -72430,7 +73164,7 @@ async function readClaudeCode(path, options = {}) {
72430
73164
  let startedIso = started === void 0 ? void 0 : new Date(started).toISOString();
72431
73165
  if (!startedIso) {
72432
73166
  try {
72433
- startedIso = statSync6(source).mtime.toISOString();
73167
+ startedIso = statSync7(source).mtime.toISOString();
72434
73168
  } catch {
72435
73169
  startedIso = (/* @__PURE__ */ new Date()).toISOString();
72436
73170
  }
@@ -72448,7 +73182,7 @@ async function readClaudeCode(path, options = {}) {
72448
73182
  }
72449
73183
 
72450
73184
  // packages/kyrn-judge/src/import/codex.ts
72451
- import { statSync as statSync7 } from "node:fs";
73185
+ import { statSync as statSync8 } from "node:fs";
72452
73186
  import { basename as basename8 } from "node:path";
72453
73187
  var APP_RECORDS = /* @__PURE__ */ new Set([
72454
73188
  "event_msg",
@@ -72736,7 +73470,7 @@ ${text6}`, at);
72736
73470
  let startedIso = started && !Number.isNaN(Date.parse(started)) ? new Date(Date.parse(started)).toISOString() : void 0;
72737
73471
  if (!startedIso) {
72738
73472
  try {
72739
- startedIso = statSync7(source).mtime.toISOString();
73473
+ startedIso = statSync8(source).mtime.toISOString();
72740
73474
  } catch {
72741
73475
  startedIso = (/* @__PURE__ */ new Date()).toISOString();
72742
73476
  }
@@ -72911,7 +73645,7 @@ function jsonlFiles(dir, depth) {
72911
73645
  if (name.endsWith(".jsonl")) files.push(path);
72912
73646
  else if (depth > 0 && !name.startsWith(".")) {
72913
73647
  try {
72914
- if (statSync8(path).isDirectory()) files.push(...jsonlFiles(path, depth - 1));
73648
+ if (statSync9(path).isDirectory()) files.push(...jsonlFiles(path, depth - 1));
72915
73649
  } catch {
72916
73650
  }
72917
73651
  }
@@ -72943,7 +73677,7 @@ function listConversations(options = {}) {
72943
73677
  let size;
72944
73678
  let modified;
72945
73679
  try {
72946
- const stats = statSync8(path);
73680
+ const stats = statSync9(path);
72947
73681
  size = stats.size;
72948
73682
  modified = stats.mtime.toISOString();
72949
73683
  } catch {
@@ -72966,7 +73700,7 @@ async function importOne(path, options, imports) {
72966
73700
  const source = absolute(path);
72967
73701
  const failed = (error) => ({ status: "failed", source, error });
72968
73702
  try {
72969
- if (!statSync8(source).isFile()) return failed("not a file");
73703
+ if (!statSync9(source).isFile()) return failed("not a file");
72970
73704
  } catch {
72971
73705
  return failed("no such file");
72972
73706
  }
@@ -73184,7 +73918,7 @@ ${theme.fg("dim", detail)}`, 0, 0));
73184
73918
  import { isAbsolute as isAbsolute4, join as join33, resolve as resolve7 } from "node:path";
73185
73919
 
73186
73920
  // packages/kyrn-judge/src/inherit/files.ts
73187
- import { existsSync as existsSync9, readdirSync as readdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync9 } from "node:fs";
73921
+ import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync10 } from "node:fs";
73188
73922
  import { dirname as dirname5, join as join28, resolve as resolve5 } from "node:path";
73189
73923
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
73190
73924
  function projectChain(projectDir, home) {
@@ -73195,7 +73929,7 @@ function projectChain(projectDir, home) {
73195
73929
  for (let depth = 0; depth < 32; depth++) {
73196
73930
  if (current === homeDir) break;
73197
73931
  chain.push(current);
73198
- if (existsSync9(join28(current, ".git"))) return chain;
73932
+ if (existsSync10(join28(current, ".git"))) return chain;
73199
73933
  const parent = dirname5(current);
73200
73934
  if (parent === current) break;
73201
73935
  current = parent;
@@ -73204,7 +73938,7 @@ function projectChain(projectDir, home) {
73204
73938
  }
73205
73939
  function readBytes(path, problems, maxBytes = MAX_FILE_BYTES) {
73206
73940
  try {
73207
- const stats = statSync9(path);
73941
+ const stats = statSync10(path);
73208
73942
  if (!stats.isFile()) return void 0;
73209
73943
  if (stats.size > maxBytes) {
73210
73944
  problems.push({ source: path, message: `skipped: larger than ${maxBytes} bytes` });
@@ -73234,7 +73968,7 @@ function listFiles(dir, extensions, depth = 4) {
73234
73968
  const path = join28(dir, name);
73235
73969
  let stats;
73236
73970
  try {
73237
- stats = statSync9(path);
73971
+ stats = statSync10(path);
73238
73972
  } catch {
73239
73973
  continue;
73240
73974
  }
@@ -74045,7 +74779,7 @@ function expandPlaceholders(value, context) {
74045
74779
 
74046
74780
  // packages/kyrn-judge/src/inherit/skills.ts
74047
74781
  var import_pi_coding_agent9 = __toESM(require_pi_coding_agent(), 1);
74048
- import { readdirSync as readdirSync8, statSync as statSync10 } from "node:fs";
74782
+ import { readdirSync as readdirSync8, statSync as statSync11 } from "node:fs";
74049
74783
  import { basename as basename10, join as join31 } from "node:path";
74050
74784
  function readSkill(dir, problems) {
74051
74785
  const file = join31(dir, "SKILL.md");
@@ -74074,7 +74808,7 @@ function skillsBelow(root, problems, depth = 3) {
74074
74808
  if (name.startsWith(".") || name === "node_modules") continue;
74075
74809
  const dir = join31(root, name);
74076
74810
  try {
74077
- if (!statSync10(dir).isDirectory()) continue;
74811
+ if (!statSync11(dir).isDirectory()) continue;
74078
74812
  } catch {
74079
74813
  continue;
74080
74814
  }
@@ -74437,7 +75171,7 @@ function registerInterjection(runtime) {
74437
75171
  goal,
74438
75172
  currentAction: clip(runtime.lastAssistantText, 300)
74439
75173
  }),
74440
- new Promise((resolve13) => setTimeout(() => resolve13(void 0), options.waitMs))
75174
+ new Promise((resolve15) => setTimeout(() => resolve15(void 0), options.waitMs))
74441
75175
  ]);
74442
75176
  if (!decision || decision.source !== "judge") return void 0;
74443
75177
  if (decision.outcome === "keep" || decision.outcome === event.streamingBehavior) return void 0;
@@ -74449,7 +75183,7 @@ function registerInterjection(runtime) {
74449
75183
 
74450
75184
  // packages/kyrn-judge/src/extension/features/lsp.ts
74451
75185
  var import_pi_coding_agent10 = __toESM(require_pi_coding_agent(), 1);
74452
- import { readFileSync as readFileSync14, statSync as statSync12 } from "node:fs";
75186
+ import { readFileSync as readFileSync14, statSync as statSync13 } from "node:fs";
74453
75187
  import { homedir as homedir7 } from "node:os";
74454
75188
  import { join as join34, relative as relative4, resolve as resolve8 } from "node:path";
74455
75189
 
@@ -74635,7 +75369,7 @@ function formatReport(items, options) {
74635
75369
  }
74636
75370
 
74637
75371
  // packages/kyrn-judge/src/lsp/manager.ts
74638
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync10, statSync as statSync11 } from "node:fs";
75372
+ import { accessSync as accessSync3, constants as constants3, existsSync as existsSync11, statSync as statSync12 } from "node:fs";
74639
75373
 
74640
75374
  // packages/kyrn-judge/src/lsp/client.ts
74641
75375
  import { spawn as spawn7 } from "node:child_process";
@@ -74896,12 +75630,12 @@ var LspClient = class {
74896
75630
  this.state = "stopping";
74897
75631
  this.clearTimers();
74898
75632
  if (child && child.exitCode === null && child.signalCode === null) {
74899
- const gone = new Promise((resolve13) => child.once("exit", () => resolve13()));
75633
+ const gone = new Promise((resolve15) => child.once("exit", () => resolve15()));
74900
75634
  if (wasRunning) {
74901
75635
  await this.request("shutdown", void 0, 2e3).catch(() => void 0);
74902
75636
  this.notify("exit", void 0);
74903
75637
  }
74904
- await Promise.race([gone, new Promise((resolve13) => setTimeout(resolve13, wasRunning ? 1e3 : 0))]);
75638
+ await Promise.race([gone, new Promise((resolve15) => setTimeout(resolve15, wasRunning ? 1e3 : 0))]);
74905
75639
  killTree(child, this.platform);
74906
75640
  }
74907
75641
  this.state = "stopped";
@@ -75006,16 +75740,16 @@ var LspClient = class {
75006
75740
  return true;
75007
75741
  };
75008
75742
  if (settled()) return Promise.resolve(true);
75009
- return new Promise((resolve13) => {
75743
+ return new Promise((resolve15) => {
75010
75744
  const check = () => {
75011
75745
  if (!settled()) return;
75012
75746
  clearTimeout(timer);
75013
75747
  this.waiters.delete(check);
75014
- resolve13(true);
75748
+ resolve15(true);
75015
75749
  };
75016
75750
  const timer = setTimeout(() => {
75017
75751
  this.waiters.delete(check);
75018
- resolve13(false);
75752
+ resolve15(false);
75019
75753
  }, budgetMs);
75020
75754
  this.waiters.add(check);
75021
75755
  });
@@ -75207,7 +75941,7 @@ var LspClient = class {
75207
75941
  }
75208
75942
  request(method, params, timeoutMs) {
75209
75943
  const id = this.nextId++;
75210
- return new Promise((resolve13, reject) => {
75944
+ return new Promise((resolve15, reject) => {
75211
75945
  const timer = setTimeout(
75212
75946
  () => {
75213
75947
  this.pending.delete(id);
@@ -75216,7 +75950,7 @@ var LspClient = class {
75216
75950
  },
75217
75951
  timeoutMs ?? this.options.requestTimeoutMs ?? 1e4
75218
75952
  );
75219
- this.pending.set(id, { resolve: resolve13, reject, timer });
75953
+ this.pending.set(id, { resolve: resolve15, reject, timer });
75220
75954
  this.send({ id, method, params });
75221
75955
  });
75222
75956
  }
@@ -75419,7 +76153,7 @@ function envValue(env, name) {
75419
76153
  return key ? env[key] : void 0;
75420
76154
  }
75421
76155
  var WINDOWS_MOUNT = /^\/mnt\/[a-z]\//i;
75422
- function findOnPath(command, options) {
76156
+ function findOnPath2(command, options) {
75423
76157
  const { env, platform, isExecutable } = options;
75424
76158
  const paths = platform === "win32" ? win322 : posix2;
75425
76159
  const endings = platform === "win32" ? ["", ...(envValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)] : [""];
@@ -75440,12 +76174,12 @@ function findOnPath(command, options) {
75440
76174
  }
75441
76175
  return void 0;
75442
76176
  }
75443
- function detectServers(specs, lookup) {
76177
+ function detectServers(specs, lookup2) {
75444
76178
  const taken = /* @__PURE__ */ new Set();
75445
76179
  const ordered = [...specs].sort((a, b) => Number(a.origin === "built-in") - Number(b.origin === "built-in"));
75446
76180
  const detected = /* @__PURE__ */ new Map();
75447
76181
  for (const spec of ordered) {
75448
- const executable = lookup(spec.command);
76182
+ const executable = lookup2(spec.command);
75449
76183
  const chosen = executable !== void 0 && !(spec.group && taken.has(spec.group));
75450
76184
  if (chosen && spec.group) taken.add(spec.group);
75451
76185
  detected.set(spec.id, { spec, executable, chosen });
@@ -75487,8 +76221,8 @@ function spawnPlan(executable, args, platform, env = {}) {
75487
76221
  var MAX_STARTS = 2;
75488
76222
  function isExecutableFile(path, platform = process.platform) {
75489
76223
  try {
75490
- if (!statSync11(path).isFile()) return false;
75491
- if (platform !== "win32") accessSync2(path, constants2.X_OK);
76224
+ if (!statSync12(path).isFile()) return false;
76225
+ if (platform !== "win32") accessSync3(path, constants3.X_OK);
75492
76226
  return true;
75493
76227
  } catch {
75494
76228
  return false;
@@ -75511,7 +76245,7 @@ var LspManager = class {
75511
76245
  this.specsKey = key;
75512
76246
  this.detected = detectServers(
75513
76247
  specs,
75514
- (command) => findOnPath(command, {
76248
+ (command) => findOnPath2(command, {
75515
76249
  env: this.env,
75516
76250
  platform: this.platform,
75517
76251
  isExecutable: (path) => isExecutableFile(path, this.platform)
@@ -75600,7 +76334,7 @@ var LspManager = class {
75600
76334
  }
75601
76335
  instanceFor(server, file, cwd) {
75602
76336
  if (!server.executable) return void 0;
75603
- const root = findRoot(file, server.spec.rootMarkers, cwd, existsSync10, this.platform);
76337
+ const root = findRoot(file, server.spec.rootMarkers, cwd, existsSync11, this.platform);
75604
76338
  const key = `${server.spec.id}
75605
76339
  ${root}`;
75606
76340
  let instance = this.instances.get(key);
@@ -75837,7 +76571,7 @@ function registerLsp(runtime) {
75837
76571
  };
75838
76572
  const read = (path) => {
75839
76573
  try {
75840
- if (statSync12(path).size > options.maxFileBytes) return false;
76574
+ if (statSync13(path).size > options.maxFileBytes) return false;
75841
76575
  return readFileSync14(path, "utf8");
75842
76576
  } catch {
75843
76577
  return void 0;
@@ -76330,7 +77064,7 @@ var McpClient = class {
76330
77064
  } : params;
76331
77065
  const timeoutMs = options.timeoutMs ?? this.options.requestTimeoutMs;
76332
77066
  const abort = new AbortController();
76333
- return new Promise((resolve13, reject) => {
77067
+ return new Promise((resolve15, reject) => {
76334
77068
  const giveUp = (error) => {
76335
77069
  const entry = this.pending.get(id);
76336
77070
  if (!entry) return;
@@ -76356,7 +77090,7 @@ var McpClient = class {
76356
77090
  const onAbort = () => giveUp(new McpError("aborted", "the call was cancelled"));
76357
77091
  options.signal?.addEventListener("abort", onAbort, { once: true });
76358
77092
  this.pending.set(id, {
76359
- resolve: resolve13,
77093
+ resolve: resolve15,
76360
77094
  reject,
76361
77095
  cleanup: () => {
76362
77096
  clearTimeout(timer);
@@ -76590,7 +77324,7 @@ var StreamableHttpTransport = class {
76590
77324
 
76591
77325
  // packages/kyrn-judge/src/mcp/stdio.ts
76592
77326
  import { spawn as spawn8 } from "node:child_process";
76593
- import { existsSync as existsSync11 } from "node:fs";
77327
+ import { existsSync as existsSync12 } from "node:fs";
76594
77328
 
76595
77329
  // packages/kyrn-judge/src/mcp/spawn.ts
76596
77330
  import { win32 as win323 } from "node:path";
@@ -76702,10 +77436,10 @@ var StdioTransport = class {
76702
77436
  const plan2 = planSpawn2(this.options.command, this.options.args, {
76703
77437
  platform,
76704
77438
  env: parentEnv,
76705
- exists: existsSync11,
77439
+ exists: existsSync12,
76706
77440
  cwd: this.options.cwd
76707
77441
  });
76708
- return new Promise((resolve13, reject) => {
77442
+ return new Promise((resolve15, reject) => {
76709
77443
  let child;
76710
77444
  try {
76711
77445
  child = spawn8(plan2.command, [...plan2.args], {
@@ -76744,7 +77478,7 @@ var StdioTransport = class {
76744
77478
  child.once("spawn", () => {
76745
77479
  if (settled) return;
76746
77480
  settled = true;
76747
- resolve13();
77481
+ resolve15();
76748
77482
  });
76749
77483
  child.stdout?.setEncoding("utf8");
76750
77484
  child.stdout?.on("data", (chunk) => this.readOutput(chunk));
@@ -76790,11 +77524,11 @@ var StdioTransport = class {
76790
77524
  if (!stdin || stdin.destroyed || !stdin.writable) {
76791
77525
  return Promise.reject(new McpError("closed", "the server is not running"));
76792
77526
  }
76793
- return new Promise((resolve13, reject) => {
77527
+ return new Promise((resolve15, reject) => {
76794
77528
  stdin.write(
76795
77529
  `${JSON.stringify(message)}
76796
77530
  `,
76797
- (error) => error ? reject(new McpError("closed", "the server is not running")) : resolve13()
77531
+ (error) => error ? reject(new McpError("closed", "the server is not running")) : resolve15()
76798
77532
  );
76799
77533
  });
76800
77534
  }
@@ -76811,8 +77545,8 @@ var StdioTransport = class {
76811
77545
  }
76812
77546
  exitedWithin(ms) {
76813
77547
  let timer;
76814
- const timeout = new Promise((resolve13) => {
76815
- timer = setTimeout(() => resolve13(false), ms);
77548
+ const timeout = new Promise((resolve15) => {
77549
+ timer = setTimeout(() => resolve15(false), ms);
76816
77550
  });
76817
77551
  return Promise.race([this.exited.then(() => true), timeout]).finally(() => clearTimeout(timer));
76818
77552
  }
@@ -78644,17 +79378,17 @@ function registerNotify(runtime) {
78644
79378
 
78645
79379
  // packages/kyrn-judge/src/packs/exec.ts
78646
79380
  import { spawn as spawn9 } from "node:child_process";
78647
- import { statSync as statSync13 } from "node:fs";
79381
+ import { statSync as statSync14 } from "node:fs";
78648
79382
  import { posix as posix3, win32 as win324 } from "node:path";
78649
79383
  var STDERR_LIMIT = 64 * 1024;
78650
79384
  var KILL_GRACE_MS2 = 2e3;
78651
79385
  var PIPE_GRACE_MS = 500;
78652
- var run = (command, args, options = {}) => new Promise((resolve13) => {
79386
+ var run = (command, args, options = {}) => new Promise((resolve15) => {
78653
79387
  const platform = options.platform ?? process.platform;
78654
79388
  const env = { ...process.env, ...options.env };
78655
79389
  const invocation = invocationFor(command, args, { platform, env });
78656
79390
  if (!invocation) {
78657
- resolve13({ code: 127, stdout: "", stderr: "", missing: true, stopped: false });
79391
+ resolve15({ code: 127, stdout: "", stderr: "", missing: true, stopped: false });
78658
79392
  return;
78659
79393
  }
78660
79394
  const encoding = options.encoding ?? "utf8";
@@ -78700,7 +79434,7 @@ var run = (command, args, options = {}) => new Promise((resolve13) => {
78700
79434
  if (late) clearTimeout(late);
78701
79435
  options.signal?.removeEventListener("abort", stop);
78702
79436
  if (options.onLine && carry && !stopped) options.onLine(carry);
78703
- resolve13({ code, stdout: Buffer.concat(chunks).toString(encoding), stderr, missing, stopped });
79437
+ resolve15({ code, stdout: Buffer.concat(chunks).toString(encoding), stderr, missing, stopped });
78704
79438
  };
78705
79439
  if (options.onLine) {
78706
79440
  child.stdout?.setEncoding(encoding);
@@ -78739,16 +79473,16 @@ var run = (command, args, options = {}) => new Promise((resolve13) => {
78739
79473
  });
78740
79474
  function isFile(path) {
78741
79475
  try {
78742
- return statSync13(path).isFile();
79476
+ return statSync14(path).isFile();
78743
79477
  } catch {
78744
79478
  return false;
78745
79479
  }
78746
79480
  }
78747
- function findOnPath2(name, lookup) {
78748
- const exists = lookup.isFile ?? isFile;
78749
- const windows = lookup.platform === "win32";
79481
+ function findOnPath3(name, lookup2) {
79482
+ const exists = lookup2.isFile ?? isFile;
79483
+ const windows = lookup2.platform === "win32";
78750
79484
  const path = windows ? win324 : posix3;
78751
- const get = (key) => windows ? Object.entries(lookup.env).find(([candidate]) => candidate.toUpperCase() === key)?.[1] : lookup.env[key];
79485
+ const get = (key) => windows ? Object.entries(lookup2.env).find(([candidate]) => candidate.toUpperCase() === key)?.[1] : lookup2.env[key];
78752
79486
  const extensions = windows ? path.extname(name) ? [""] : (get("PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
78753
79487
  const named = name.includes("/") || windows && name.includes("\\");
78754
79488
  const directories = named ? [""] : (get("PATH") ?? "").split(path.delimiter).filter(Boolean);
@@ -78766,13 +79500,13 @@ function quoteForCmd3(argument, twice) {
78766
79500
  const escaped = quoted.replace(CMD_META2, "^$1");
78767
79501
  return twice ? escaped.replace(CMD_META2, "^$1") : escaped;
78768
79502
  }
78769
- function invocationFor(command, args, lookup) {
78770
- if (lookup.platform !== "win32") return { command, args: [...args], verbatim: false };
78771
- const found = findOnPath2(command, lookup);
79503
+ function invocationFor(command, args, lookup2) {
79504
+ if (lookup2.platform !== "win32") return { command, args: [...args], verbatim: false };
79505
+ const found = findOnPath3(command, lookup2);
78772
79506
  if (!found) return void 0;
78773
79507
  if (!/\.(cmd|bat)$/i.test(found)) return { command: found, args: [...args], verbatim: false };
78774
79508
  const line2 = [found.replace(CMD_META2, "^$1"), ...args.map((argument) => quoteForCmd3(argument, true))].join(" ");
78775
- const shell = Object.entries(lookup.env).find(([key]) => key.toUpperCase() === "COMSPEC")?.[1] ?? "cmd.exe";
79509
+ const shell = Object.entries(lookup2.env).find(([key]) => key.toUpperCase() === "COMSPEC")?.[1] ?? "cmd.exe";
78776
79510
  return { command: shell, args: ["/d", "/s", "/c", `"${line2}"`], verbatim: true };
78777
79511
  }
78778
79512
  function installHint(binary, platform) {
@@ -79128,8 +79862,19 @@ import { join as join38 } from "node:path";
79128
79862
 
79129
79863
  // packages/kyrn-judge/src/packs/git.ts
79130
79864
  var INHERITED3 = ["GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR", "GIT_PREFIX"];
79131
- function gitOver(run2, binary = "git") {
79865
+ function gitOver(run2, binary = "git", probe = hostProbe) {
79866
+ let stub;
79132
79867
  return async (args, call) => {
79868
+ stub ??= stubProblem(binary, call.env?.PATH ?? process.env.PATH, probe);
79869
+ const problem = await stub;
79870
+ if (problem)
79871
+ return {
79872
+ code: 127,
79873
+ stdout: Buffer.alloc(0),
79874
+ stderr: problem.message,
79875
+ missing: false,
79876
+ unusable: problem.reason
79877
+ };
79133
79878
  const env = {};
79134
79879
  for (const name of INHERITED3) env[name] = void 0;
79135
79880
  Object.assign(env, { LC_ALL: "C", LANGUAGE: "C", GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat" }, call.env);
@@ -79141,12 +79886,14 @@ function gitOver(run2, binary = "git") {
79141
79886
  timeoutMs: call.timeoutMs ?? 6e4,
79142
79887
  encoding: "latin1"
79143
79888
  });
79144
- return {
79889
+ const output = {
79145
79890
  code: result.code,
79146
79891
  stdout: Buffer.from(result.stdout, "latin1"),
79147
79892
  stderr: result.stderr,
79148
79893
  missing: result.missing
79149
79894
  };
79895
+ return heldByLicense(result.code, () => `${result.stderr}
79896
+ ${result.stdout}`) ? { ...output, unusable: "xcode_license" } : output;
79150
79897
  };
79151
79898
  }
79152
79899
  var text4 = (output) => output.stdout.toString("utf8");
@@ -79161,6 +79908,8 @@ var IN_PROGRESS = [
79161
79908
  async function repoState(git2, cwd) {
79162
79909
  const top = await git2(["rev-parse", "--show-toplevel", "--absolute-git-dir"], { cwd });
79163
79910
  if (top.missing) return { ok: false, reason: "no-git", message: "git could not be started" };
79911
+ if (top.unusable)
79912
+ return { ok: false, reason: "unusable", unusable: top.unusable, message: UNUSABLE_TEXT[top.unusable] };
79164
79913
  if (top.code !== 0)
79165
79914
  return { ok: false, reason: "not-a-repo", message: lastLine3(top.stderr) || "not a git repository" };
79166
79915
  const [root, gitDir] = lines(top).map((line2) => line2.trim());
@@ -79632,6 +80381,16 @@ async function applyPlan(git2, repo, change, plan2, signal) {
79632
80381
 
79633
80382
  // packages/kyrn-judge/src/extension/features/packs/commit.ts
79634
80383
  var TITLE = "mu /commit";
80384
+ var CANNOT_RUN = {
80385
+ developer_tools_missing: {
80386
+ zh: "/commit \u7528\u4E0D\u4E86\uFF1A\u8FD9\u53F0 Mac \u6CA1\u6709\u5B89\u88C5 git \u6240\u9700\u7684\u547D\u4EE4\u884C\u5F00\u53D1\u8005\u5DE5\u5177\u3002\u7528 xcode-select --install \u5B89\u88C5\u540E\u518D\u8BD5\u3002",
80387
+ en: "/commit cannot run: this Mac has no command line developer tools, which git needs. Install them with xcode-select --install, then try again."
80388
+ },
80389
+ xcode_license: {
80390
+ zh: "/commit \u7528\u4E0D\u4E86\uFF1A\u8FD9\u53F0 Mac \u8FD8\u6CA1\u6709\u540C\u610F Xcode \u8BB8\u53EF\u534F\u8BAE\uFF0Cgit \u65E0\u6CD5\u8FD0\u884C\u3002\u5728\u7EC8\u7AEF\u91CC\u7528 sudo xcodebuild -license \u540C\u610F\u540E\u518D\u8BD5\u3002",
80391
+ en: "/commit cannot run: git cannot run on this Mac until the Xcode license is accepted. Accept it with sudo xcodebuild -license in Terminal, then try again."
80392
+ }
80393
+ };
79635
80394
  function registerCommit(shared, options) {
79636
80395
  const { runtime } = shared;
79637
80396
  runtime.pi.registerCommand("commit", {
@@ -79644,7 +80403,10 @@ function registerCommit(shared, options) {
79644
80403
  const git2 = gitOver(shared.run);
79645
80404
  const repo = await repoState(git2, ctx.cwd);
79646
80405
  if (!repo.ok) {
79647
- const why = repo.reason === "no-git" ? installHint("git", shared.platform) : say({ zh: `\u8FD9\u91CC\u4E0D\u662F git \u4ED3\u5E93\uFF1A${repo.message}`, en: `Not a git repository here: ${repo.message}` });
80406
+ const why = repo.reason === "unusable" ? say(CANNOT_RUN[repo.unusable]) : repo.reason === "no-git" ? installHint("git", shared.platform) : say({
80407
+ zh: `\u8FD9\u91CC\u4E0D\u662F git \u4ED3\u5E93\uFF1A${repo.message}`,
80408
+ en: `Not a git repository here: ${repo.message}`
80409
+ });
79648
80410
  ctx.ui.notify(why, "warning");
79649
80411
  return;
79650
80412
  }
@@ -79940,8 +80702,9 @@ function conflictsPack(shared, options) {
79940
80702
  description: "For a merge, rebase or cherry-pick that stopped on conflicts: shows each conflicted file with both sides and their common base, and resolves one file at a time.",
79941
80703
  tools: ["conflicts_list", "conflicts_show", "conflicts_resolve"],
79942
80704
  async start() {
79943
- const probe = await shared.run("git", ["--version"], { cwd: shared.cwd(), timeoutMs: 5e3 });
80705
+ const probe = await git2(["--version"], { cwd: shared.cwd(), timeoutMs: 5e3 });
79944
80706
  if (probe.missing) throw new Error(installHint("git", shared.platform));
80707
+ if (probe.unusable) throw new Error(UNUSABLE_TEXT[probe.unusable]);
79945
80708
  runtime.pi.registerTool({
79946
80709
  name: "conflicts_list",
79947
80710
  label: "Conflicts",
@@ -80212,15 +80975,15 @@ import { spawn as spawn10, spawnSync as spawnSync2 } from "node:child_process";
80212
80975
  import { connect, createServer as createServer2 } from "node:net";
80213
80976
  var DapError = class extends Error {
80214
80977
  };
80215
- var sleep3 = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
80978
+ var sleep3 = (ms) => new Promise((resolve15) => setTimeout(resolve15, ms));
80216
80979
  async function freePort() {
80217
- return new Promise((resolve13, reject) => {
80980
+ return new Promise((resolve15, reject) => {
80218
80981
  const server = createServer2();
80219
80982
  server.once("error", reject);
80220
80983
  server.listen(0, "127.0.0.1", () => {
80221
80984
  const address = server.address();
80222
80985
  const port = typeof address === "object" && address ? address.port : 0;
80223
- server.close(() => resolve13(port));
80986
+ server.close(() => resolve15(port));
80224
80987
  });
80225
80988
  });
80226
80989
  }
@@ -80274,8 +81037,8 @@ var DapClient = class {
80274
81037
  while (true) {
80275
81038
  if (this.ended) throw new DapError(this.why());
80276
81039
  try {
80277
- const socket = await new Promise((resolve13, reject) => {
80278
- const attempt = connect(port, "127.0.0.1", () => resolve13(attempt));
81040
+ const socket = await new Promise((resolve15, reject) => {
81041
+ const attempt = connect(port, "127.0.0.1", () => resolve15(attempt));
80279
81042
  attempt.once("error", reject);
80280
81043
  });
80281
81044
  socket.on("close", () => this.fail("the debug adapter closed the connection"));
@@ -80351,7 +81114,7 @@ var DapClient = class {
80351
81114
  request(command, args = {}, timeoutMs) {
80352
81115
  if (this.ended) return Promise.reject(new DapError(`${command}: ${this.why()}`));
80353
81116
  const seq = this.seq++;
80354
- return new Promise((resolve13, reject) => {
81117
+ return new Promise((resolve15, reject) => {
80355
81118
  const timer = setTimeout(
80356
81119
  () => {
80357
81120
  this.pending.delete(seq);
@@ -80359,7 +81122,7 @@ var DapClient = class {
80359
81122
  },
80360
81123
  timeoutMs ?? this.options.requestTimeoutMs ?? 3e4
80361
81124
  );
80362
- this.pending.set(seq, { command, resolve: resolve13, reject, timer });
81125
+ this.pending.set(seq, { command, resolve: resolve15, reject, timer });
80363
81126
  this.write({ seq, type: "request", command, arguments: args });
80364
81127
  });
80365
81128
  }
@@ -80375,12 +81138,12 @@ var DapClient = class {
80375
81138
  if (names.includes(this.received[at].event)) return this.received[at];
80376
81139
  }
80377
81140
  if (this.ended || signal?.aborted || Date.now() >= deadline) return void 0;
80378
- await new Promise((resolve13) => {
81141
+ await new Promise((resolve15) => {
80379
81142
  const wake = () => {
80380
81143
  this.waiters.delete(wake);
80381
81144
  signal?.removeEventListener("abort", wake);
80382
81145
  clearTimeout(timer);
80383
- resolve13();
81146
+ resolve15();
80384
81147
  };
80385
81148
  const timer = setTimeout(wake, Math.max(1, deadline - Date.now()));
80386
81149
  this.waiters.add(wake);
@@ -80739,7 +81502,7 @@ function debuggerPack(shared, options) {
80739
81502
  );
80740
81503
  const locate = async (spec, cwd) => {
80741
81504
  const own = projectInterpreter(spec, cwd, platform, isExecutable);
80742
- const onPath = findOnPath(spec.command, { env: process.env, platform, isExecutable });
81505
+ const onPath = findOnPath2(spec.command, { env: process.env, platform, isExecutable });
80743
81506
  const elsewhere = onPath ? void 0 : spec.fallbacks?.find((path) => isExecutable(path));
80744
81507
  const candidates = [...new Set([own, onPath, elsewhere].filter((path) => path !== void 0))];
80745
81508
  if (candidates.length === 0) {
@@ -80797,7 +81560,7 @@ function debuggerPack(shared, options) {
80797
81560
  async start() {
80798
81561
  const adapters = adaptersFor(platform, options.adapters);
80799
81562
  const present = adapters.some(
80800
- (spec) => findOnPath(spec.command, { env: process.env, platform, isExecutable }) !== void 0 || spec.fallbacks?.some((path) => isExecutable(path))
81563
+ (spec) => findOnPath2(spec.command, { env: process.env, platform, isExecutable }) !== void 0 || spec.fallbacks?.some((path) => isExecutable(path))
80801
81564
  );
80802
81565
  if (!present) {
80803
81566
  throw new Error(
@@ -80993,7 +81756,7 @@ ${tail}` : "Ended the debugging run."
80993
81756
  }
80994
81757
 
80995
81758
  // packages/kyrn-judge/src/extension/features/packs/github.ts
80996
- import { existsSync as existsSync12 } from "node:fs";
81759
+ import { existsSync as existsSync13 } from "node:fs";
80997
81760
  import { fileURLToPath as fileURLToPath4 } from "node:url";
80998
81761
  var GITHUB_SKILL_PATH = fileURLToPath4(new URL("../../../../skills/mu-github/SKILL.md", new URL("src/extension/features/packs/github.ts", new URL("../", import.meta.url)).href));
80999
81762
  function githubPack(shared, options) {
@@ -81002,7 +81765,7 @@ function githubPack(shared, options) {
81002
81765
  title: "GitHub through gh",
81003
81766
  description: "For work on GitHub: pull requests, issues, CI checks and their logs, reviews, releases, the API. Adds no tools; the mu-github skill says how to use gh.",
81004
81767
  tools: [],
81005
- skills: existsSync12(GITHUB_SKILL_PATH) ? [GITHUB_SKILL_PATH] : [],
81768
+ skills: existsSync13(GITHUB_SKILL_PATH) ? [GITHUB_SKILL_PATH] : [],
81006
81769
  async start() {
81007
81770
  const result = await shared.run(options.command || "gh", ["--version"], {
81008
81771
  cwd: shared.cwd(),
@@ -81299,8 +82062,9 @@ function registerPacks(runtime) {
81299
82062
  }
81300
82063
 
81301
82064
  // packages/kyrn-judge/src/extension/features/permissions.ts
81302
- import { homedir as homedir8 } from "node:os";
81303
- import { join as join42 } from "node:path";
82065
+ var import_pi_coding_agent12 = __toESM(require_pi_coding_agent(), 1);
82066
+ import { homedir as homedir9 } from "node:os";
82067
+ import { join as join42, resolve as resolve13, sep as sep3 } from "node:path";
81304
82068
 
81305
82069
  // packages/kyrn-judge/src/decisions/tool-approval.ts
81306
82070
  var APPROVE_AT = 0.8;
@@ -81340,8 +82104,10 @@ var toolApproval = defineDecision({
81340
82104
  });
81341
82105
 
81342
82106
  // packages/kyrn-judge/src/permissions/modes.ts
81343
- import { mkdirSync as mkdirSync16, readFileSync as readFileSync17, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
81344
- import { isAbsolute as isAbsolute7, join as join41, relative as relative7, resolve as resolve12 } from "node:path";
82107
+ import { lstatSync as lstatSync2, mkdirSync as mkdirSync16, readFileSync as readFileSync17, readlinkSync, realpathSync as realpathSync5, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
82108
+ import { homedir as homedir8 } from "node:os";
82109
+ import { basename as basename14, dirname as dirname9, isAbsolute as isAbsolute7, join as join41, relative as relative7, resolve as resolve12, sep as sep2 } from "node:path";
82110
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
81345
82111
  var PERMISSION_MODES = ["full", "jev", "ask"];
81346
82112
  var MODE_TEXT = {
81347
82113
  full: {
@@ -81398,19 +82164,20 @@ var LOOKING = /* @__PURE__ */ new Set([
81398
82164
  "conflicts_show",
81399
82165
  "sg_search",
81400
82166
  "review_triage",
81401
- "debug_inspect",
81402
82167
  "debug_step",
81403
82168
  "debug_stop"
81404
82169
  ]);
81405
82170
  var EDITING = /* @__PURE__ */ new Set(["edit", "write", "apply_patch_from", "conflicts_resolve", "sg_rewrite"]);
81406
82171
  var TWO_WORD = /^(?:git|npm|pnpm|yarn|bun|npx|cargo|go|docker|kubectl|pip|pip3|uv|poetry|make|dotnet|gh|brew|apt|apt-get)$/;
81407
82172
  var COMPOUND = /[<>;&|`\n\r]|\$\(|\$\{/;
82173
+ var WRAPPER = /^(?:sudo|doas|pkexec|su|runas|env|xargs|eval|exec|command|builtin|nohup|timeout|nice|ionice|time|stdbuf|setsid|chroot|taskset|flock|watch|unbuffer|caffeinate|script|busybox|start|sh|bash|zsh|dash|ksh|fish|pwsh|powershell|cmd)$/i;
82174
+ var FIND_ACTS = /^-(?:exec|execdir|ok|okdir|delete|fprint0?|fprintf|fls)$/;
81408
82175
  function commandPrefix(command) {
81409
82176
  const text6 = command.trim();
81410
82177
  if (!text6 || COMPOUND.test(text6)) return void 0;
81411
82178
  const words2 = text6.split(/\s+/);
81412
- if (/=/.test(words2[0]) || /^(?:sudo|doas|env|xargs|eval|exec|sh|bash|zsh|pwsh|powershell|cmd)$/i.test(words2[0]))
81413
- return void 0;
82179
+ if (/=/.test(words2[0]) || WRAPPER.test(words2[0])) return void 0;
82180
+ if (/^find$/i.test(words2[0]) && words2.some((word) => FIND_ACTS.test(word))) return void 0;
81414
82181
  const [first, second] = words2;
81415
82182
  return TWO_WORD.test(first) && second && !second.startsWith("-") ? `${first} ${second}` : first;
81416
82183
  }
@@ -81418,11 +82185,51 @@ var text5 = (value) => typeof value === "string" ? value : "";
81418
82185
  function pathOf2(input) {
81419
82186
  return text5(input.path) || text5(input.file_path) || text5(input.file);
81420
82187
  }
81421
- function insideProject(cwd, path) {
81422
- if (!path) return true;
81423
- const target = resolve12(cwd, path);
81424
- const rel = relative7(resolve12(cwd), target);
81425
- return rel === "" || !rel.startsWith("..") && !isAbsolute7(rel);
82188
+ function realPath2(path, depth = 0) {
82189
+ try {
82190
+ return realpathSync5.native(path);
82191
+ } catch {
82192
+ if (depth < 40) {
82193
+ try {
82194
+ if (lstatSync2(path).isSymbolicLink())
82195
+ return realPath2(resolve12(dirname9(path), readlinkSync(path)), depth + 1);
82196
+ } catch {
82197
+ }
82198
+ }
82199
+ const parent = dirname9(path);
82200
+ return parent === path ? path : join41(realPath2(parent, depth + 1), basename14(path));
82201
+ }
82202
+ }
82203
+ var UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
82204
+ function windowsDrive(path) {
82205
+ if (!path.startsWith("/") || path.startsWith("//") || path.includes("\\")) return path;
82206
+ const match = /^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/i.exec(path);
82207
+ return match ? `${match[1].toUpperCase()}:\\${match[2]?.replaceAll("/", "\\") ?? ""}` : path;
82208
+ }
82209
+ function toolPath(cwd, raw, home = homedir8()) {
82210
+ let path = raw.replace(UNICODE_SPACES, " ");
82211
+ if (path.startsWith("@")) path = path.slice(1);
82212
+ if (process.platform === "win32") path = windowsDrive(path);
82213
+ if (path === "~") path = home;
82214
+ else if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\"))
82215
+ path = join41(home, path.slice(2));
82216
+ else if (/^file:\/\//.test(path)) {
82217
+ try {
82218
+ path = fileURLToPath5(path);
82219
+ } catch {
82220
+ return void 0;
82221
+ }
82222
+ }
82223
+ return realPath2(isAbsolute7(path) ? resolve12(path) : resolve12(cwd, path));
82224
+ }
82225
+ function inProject(cwd, target) {
82226
+ if (target === void 0) return void 0;
82227
+ const rel = relative7(realPath2(resolve12(cwd)), target);
82228
+ return rel === ".." || rel.startsWith(`..${sep2}`) || isAbsolute7(rel) ? void 0 : rel;
82229
+ }
82230
+ function projectFile(cwd, target) {
82231
+ const rel = inProject(cwd, target);
82232
+ return rel !== void 0 && !rel.split(/[\\/]/).some((part) => part.toLowerCase() === ".git");
81426
82233
  }
81427
82234
  function protectedSpellings(agentDir, home, platform) {
81428
82235
  if (platform !== "win32") {
@@ -81452,7 +82259,8 @@ function permissionNeed(toolName, input, cwd, protectedPaths2 = []) {
81452
82259
  if (LOOKING.has(toolName)) return void 0;
81453
82260
  if (isShellTool(toolName) || toolName === "bg_start") {
81454
82261
  const command = text5(input.command);
81455
- if (isReadOnlyCommand(command)) return void 0;
82262
+ const powershell = toolName === "powershell" || toolName === "bg_start" && process.platform === "win32";
82263
+ if (isReadOnlyCommand(command, powershell)) return void 0;
81456
82264
  const guarded = touches(command);
81457
82265
  const prefix = commandPrefix(command);
81458
82266
  return {
@@ -81464,11 +82272,18 @@ function permissionNeed(toolName, input, cwd, protectedPaths2 = []) {
81464
82272
  if (toolName === "sg_rewrite" && input.apply !== true) return void 0;
81465
82273
  if (EDITING.has(toolName)) {
81466
82274
  const path = pathOf2(input);
81467
- const inProject = insideProject(cwd, path);
81468
- const guarded = path ? touches(resolve12(cwd, path)) : void 0;
81469
- const summary = clip5(`${toolName} ${path || text5(input.id) || text5(input.pattern)}`, 300);
82275
+ const listed2 = Array.isArray(input.paths) ? input.paths.filter((each) => typeof each === "string") : [];
82276
+ const paths = [...path ? [path] : [], ...listed2];
82277
+ const targets = paths.map((each) => ({ said: each, target: toolPath(cwd, each) }));
82278
+ const summary = clip5(`${toolName} ${path || listed2.join(" ") || text5(input.id) || text5(input.pattern)}`, 300);
82279
+ const guarded = targets.flatMap(({ said, target }) => [resolve12(cwd, said), ...target ? [target] : []]).map(touches).find(Boolean);
81470
82280
  if (guarded) return { kind: "edit", summary, protected: guarded };
81471
- return inProject ? { kind: "edit", summary, inProject, grant: { key: "edit", label: "edit" } } : { kind: "outside", summary, grant: { key: `outside:${resolve12(cwd, path)}`, label: path } };
82281
+ const away = targets.find(({ target }) => !projectFile(cwd, target));
82282
+ return away ? {
82283
+ kind: "outside",
82284
+ summary,
82285
+ grant: { key: `outside:${away.target ?? away.said}`, label: away.said }
82286
+ } : { kind: "edit", summary, inProject: true, grant: { key: "edit", label: "edit" } };
81472
82287
  }
81473
82288
  if (toolName === "delegate" || toolName === "hive") {
81474
82289
  const tasks = Array.isArray(input.tasks) ? input.tasks.length : 0;
@@ -81479,6 +82294,15 @@ function permissionNeed(toolName, input, cwd, protectedPaths2 = []) {
81479
82294
  grant: { key: `tool:${toolName}`, label: toolName }
81480
82295
  };
81481
82296
  }
82297
+ if (toolName === "debug_inspect") {
82298
+ const expression = text5(input.expression).trim();
82299
+ if (!expression) return void 0;
82300
+ return {
82301
+ kind: "run",
82302
+ summary: clip5(`${toolName} ${expression}`, 300),
82303
+ grant: { key: "tool:debug_inspect", label: toolName }
82304
+ };
82305
+ }
81482
82306
  if (toolName === "debug_start") {
81483
82307
  return {
81484
82308
  kind: "run",
@@ -81539,7 +82363,12 @@ var REASON_TEXT = {
81539
82363
  protected: {
81540
82364
  zh: "\u8FD9\u4F1A\u52A8\u5230 mu \u81EA\u5DF1\u7684\u8BBE\u7F6E\uFF0C\u53EA\u80FD\u7531\u4F60\u51B3\u5B9A\u3002",
81541
82365
  en: "This touches mu's own settings; only you can allow it."
81542
- }
82366
+ },
82367
+ nojudge: {
82368
+ zh: "\u8FD8\u6CA1\u6709\u53EF\u7528\u7684\u5224\u5B9A\u5668\uFF0C\u6240\u4EE5\u6BCF\u4E00\u6B65\u90FD\u5148\u95EE\u4F60\u3002",
82369
+ en: "No judge is available yet, so mu asks about each step."
82370
+ },
82371
+ judgedown: { zh: "\u5224\u5B9A\u5668\u8FD9\u6B21\u6CA1\u6709\u56DE\u7B54\uFF0C\u6240\u4EE5\u5148\u95EE\u4F60\u3002", en: "The judge did not answer this time, so mu asks you." }
81543
82372
  };
81544
82373
  var ANSWERS = {
81545
82374
  once: { zh: "\u5141\u8BB8\u8FD9\u4E00\u6B21", en: "Allow once" },
@@ -81549,8 +82378,23 @@ var ANSWERS = {
81549
82378
  function modeLabel(mode) {
81550
82379
  return say({ zh: MODE_TEXT[mode].zh, en: MODE_TEXT[mode].en });
81551
82380
  }
82381
+ function unanswered2(decision) {
82382
+ if (decision.reason === "error:auth" || decision.reason === "error:payment_required") return "nojudge";
82383
+ if (decision.reason?.startsWith("error:")) return "judgedown";
82384
+ const judges = Object.values(decision.answers ?? {}).map((answer) => answer.judge);
82385
+ if (judges.length > 0 && judges.every((judge) => judge === "untrusted")) return "nojudge";
82386
+ return judges.includes("unavailable") ? "judgedown" : void 0;
82387
+ }
81552
82388
  function protectedPaths(roots) {
81553
- return roots ? protectedSpellings(roots.agentDir, homedir8(), process.platform) : [];
82389
+ if (!roots) return [];
82390
+ const spelled = protectedSpellings(roots.agentDir, homedir9(), process.platform);
82391
+ const real2 = toolPath(roots.agentDir, roots.agentDir);
82392
+ return real2 && real2 !== roots.agentDir ? [...spelled, real2] : spelled;
82393
+ }
82394
+ function projectSettings(cwd) {
82395
+ const spelled = join42(resolve13(cwd), import_pi_coding_agent12.CONFIG_DIR_NAME);
82396
+ const real2 = toolPath(cwd, import_pi_coding_agent12.CONFIG_DIR_NAME) ?? spelled;
82397
+ return [.../* @__PURE__ */ new Set([spelled, real2])].map((path) => `${path}${sep3}`);
81554
82398
  }
81555
82399
  function registerPermissions(runtime, roots) {
81556
82400
  const options = runtime.options("permissions", {
@@ -81606,12 +82450,19 @@ function registerPermissions(runtime, roots) {
81606
82450
  show(ctx);
81607
82451
  });
81608
82452
  const approvedBy = (event, need, by) => {
81609
- runtime.present("permissions.approved", { tool: event.toolName, kind: need.kind, summary: need.summary, by });
82453
+ runtime.present("permissions.approved", {
82454
+ toolCallId: event.toolCallId,
82455
+ tool: event.toolName,
82456
+ kind: need.kind,
82457
+ summary: need.summary,
82458
+ by
82459
+ });
81610
82460
  return void 0;
81611
82461
  };
81612
82462
  const jevApproves = async (event, need, flag, ctx) => {
81613
82463
  const call = `${event.toolName}: ${clip(describeCall2(event.toolName, event.input), 400)}`;
81614
- const userMessage = clip(runtime.turn.userMessage, 400);
82464
+ const inherited = subAgentUserGoal();
82465
+ const userMessage = clip(inherited ?? runtime.turn.userMessage, 400);
81615
82466
  runtime.progress(
81616
82467
  say({ zh: `Jev \u5728\u5BA1\u6279\uFF1A${clip(need.summary, 60)}`, en: `Jev is reviewing: ${clip(need.summary, 60)}` }),
81617
82468
  "permission_review",
@@ -81623,13 +82474,18 @@ function registerPermissions(runtime, roots) {
81623
82474
  { command: clip(describeCall2(event.toolName, event.input), 400), userMessage, flag },
81624
82475
  { signal: ctx.signal }
81625
82476
  );
81626
- return { approved: (decision2.judged ?? decision2.outcome) === "allow", reason: "flagged" };
82477
+ const requested = decision2.answers?.requested;
82478
+ const asked2 = requested?.type === "boolean" && threeZone(requested) === "yes";
82479
+ return { approved: asked2 && (decision2.judged ?? decision2.outcome) === "allow", reason: "flagged" };
81627
82480
  }
81628
82481
  const frame = runtime.frame;
81629
82482
  const decision = await runtime.engine.decide(
81630
82483
  toolApproval,
81631
82484
  {
81632
- task: clip([frame?.goal, frame?.currentSubgoal].filter(Boolean).join(" / now: ") || userMessage, 600),
82485
+ task: clip(
82486
+ inherited ?? ([frame?.goal, frame?.currentSubgoal].filter(Boolean).join(" / now: ") || userMessage),
82487
+ 600
82488
+ ),
81633
82489
  userMessage,
81634
82490
  call,
81635
82491
  where: need.kind === "outside" ? "outside the project folder" : need.kind === "shell" || need.kind === "run" ? "a program run in the project folder" : need.kind === "delegate" ? "sub-agents working on the project" : "an action outside this computer or program, such as a web page or a connected service"
@@ -81637,7 +82493,8 @@ function registerPermissions(runtime, roots) {
81637
82493
  { signal: ctx.signal }
81638
82494
  );
81639
82495
  const verdict3 = decision.judged ?? decision.outcome;
81640
- return verdict3 === "approve" ? { approved: true, reason: "ask" } : { approved: false, reason: verdict3 };
82496
+ if (verdict3 === "approve") return { approved: true, reason: "ask" };
82497
+ return { approved: false, reason: unanswered2(decision) ?? verdict3 };
81641
82498
  };
81642
82499
  const askUser = async (event, need, reason, flag, ctx) => {
81643
82500
  const why = reason === "flagged" ? say({ zh: `\u5371\u9669\u64CD\u4F5C\uFF1A${FLAG_ZH[flag ?? ""] ?? flag}\u3002`, en: `Risky: ${flag}.` }) : say(REASON_TEXT[reason]);
@@ -81654,6 +82511,9 @@ function registerPermissions(runtime, roots) {
81654
82511
  const deny = say(ANSWERS.deny);
81655
82512
  runtime.present("permissions.request", {
81656
82513
  id,
82514
+ // The call this is about, here and in `permissions.resolved`: a client marks that call's own row by it, in
82515
+ // its own words. The model is still told in English why a refused call did not run.
82516
+ toolCallId: event.toolCallId,
81657
82517
  mode,
81658
82518
  tool: event.toolName,
81659
82519
  kind: need.kind,
@@ -81687,7 +82547,7 @@ function registerPermissions(runtime, roots) {
81687
82547
  ctx.ui.setStatus(PENDING_STATUS, void 0);
81688
82548
  }
81689
82549
  const answer = picked === once2 ? "once" : session && picked === session ? "session" : "deny";
81690
- runtime.present("permissions.resolved", { id, answer });
82550
+ runtime.present("permissions.resolved", { id, toolCallId: event.toolCallId, answer });
81691
82551
  if (answer === "session" && grant) grants.add(grant.key);
81692
82552
  if (answer !== "deny") return void 0;
81693
82553
  return {
@@ -81698,7 +82558,7 @@ function registerPermissions(runtime, roots) {
81698
82558
  const gate = async (event, ctx) => {
81699
82559
  if (mode === "full") return void 0;
81700
82560
  const input = event.input;
81701
- const need = permissionNeed(event.toolName, input, ctx.cwd, guarded);
82561
+ const need = permissionNeed(event.toolName, input, ctx.cwd, [...guarded, ...projectSettings(ctx.cwd)]);
81702
82562
  if (!need) return void 0;
81703
82563
  const command = isShellTool(event.toolName) || event.toolName === "bg_start" ? String(input.command ?? "") : "";
81704
82564
  const flag = command ? riskFlag(command) : void 0;
@@ -82040,10 +82900,10 @@ function renderVerdict(data, expanded, width, paint) {
82040
82900
  const pad = Math.max(...QUESTION_LABELS.map(([, label2]) => label2.length)) + 2;
82041
82901
  for (const [label2, value] of data.answers) lines2.push(` ${paint.fg("muted", label2.padEnd(pad))}${value}`);
82042
82902
  const room = Math.max(16, width - pad - 4);
82043
- const told = (data.hints.length > 0 ? data.hints : ["nothing extra"]).flatMap(
82903
+ const told2 = (data.hints.length > 0 ? data.hints : ["nothing extra"]).flatMap(
82044
82904
  (hint) => (0, import_pi_tui4.wrapTextWithAnsi)(`- ${hint}`, room).map((line2, index) => index === 0 ? line2 : ` ${line2}`)
82045
82905
  );
82046
- told.forEach((line2, index) => {
82906
+ told2.forEach((line2, index) => {
82047
82907
  lines2.push(
82048
82908
  ` ${paint.fg("muted", (index === 0 ? "told the model" : "").padEnd(pad))}${paint.fg("dim", line2)}`
82049
82909
  );
@@ -82285,8 +83145,8 @@ function registerPreflight(runtime) {
82285
83145
  }
82286
83146
  let skip = () => {
82287
83147
  };
82288
- const skipped = new Promise((resolve13) => {
82289
- skip = () => resolve13("skipped");
83148
+ const skipped = new Promise((resolve15) => {
83149
+ skip = () => resolve15("skipped");
82290
83150
  });
82291
83151
  const unsubscribe = panel ? ctx.ui.onTerminalInput((keys) => {
82292
83152
  if (!(0, import_pi_tui5.matchesKey)(keys, "escape")) return void 0;
@@ -82294,8 +83154,8 @@ function registerPreflight(runtime) {
82294
83154
  return { consume: true };
82295
83155
  }) : void 0;
82296
83156
  let timer;
82297
- const timeout = new Promise((resolve13) => {
82298
- timer = setTimeout(() => resolve13("timeout"), options.waitMs);
83157
+ const timeout = new Promise((resolve15) => {
83158
+ timer = setTimeout(() => resolve15("timeout"), options.waitMs);
82299
83159
  });
82300
83160
  try {
82301
83161
  current.waitEndedBy = await Promise.race([pending.then(() => "verdict"), timeout, skipped]);
@@ -82589,6 +83449,19 @@ function registerTools(runtime) {
82589
83449
  const options = runtime.options("locate", { enabled: true, candidates: 40, results: 12 });
82590
83450
  if (!options.enabled) return;
82591
83451
  const { pi } = runtime;
83452
+ let stub;
83453
+ const cannot = (reason) => {
83454
+ const none = [];
83455
+ return {
83456
+ content: [
83457
+ {
83458
+ type: "text",
83459
+ text: `${UNUSABLE_TEXT[reason]}. locate lists files with git; search another way.`
83460
+ }
83461
+ ],
83462
+ details: { ranked: none, judged: false }
83463
+ };
83464
+ };
82592
83465
  pi.registerTool({
82593
83466
  name: "locate",
82594
83467
  label: "Locate",
@@ -82599,10 +83472,15 @@ function registerTools(runtime) {
82599
83472
  }),
82600
83473
  execute: async (_toolCallId, params, signal) => {
82601
83474
  const cwd = runtime.ctx?.cwd ?? process.cwd();
83475
+ stub ??= stubProblem("git", process.env.PATH);
83476
+ const problem = await stub;
83477
+ if (problem) return cannot(problem.reason);
82602
83478
  const listing = await pi.exec("git", ["ls-files", ...params.directory ? [params.directory] : []], {
82603
83479
  cwd,
82604
83480
  signal
82605
83481
  });
83482
+ if (heldByLicense(listing.code, () => `${listing.stderr}
83483
+ ${listing.stdout}`)) return cannot("xcode_license");
82606
83484
  const paths = listing.stdout.split("\n").filter(Boolean);
82607
83485
  if (paths.length === 0) {
82608
83486
  const none = [];
@@ -83180,115 +84058,6 @@ function htmlToText(html, baseUrl) {
83180
84058
  var findElements = find;
83181
84059
  var elementText = (node) => squash(plainText(node));
83182
84060
 
83183
- // packages/kyrn-judge/src/web/ssrf.ts
83184
- import { lookup as dnsLookup } from "node:dns";
83185
- import { isIP as isIP2 } from "node:net";
83186
- var FetchRefusal = class extends Error {
83187
- constructor(code, message) {
83188
- super(message);
83189
- this.code = code;
83190
- }
83191
- };
83192
- function v4(octets) {
83193
- const [a, b, c] = octets;
83194
- if (a === 127) return "loopback";
83195
- if (a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168) return "private";
83196
- if (a === 100 && b >= 64 && b <= 127) return "private";
83197
- if (a === 169 && b === 254) return "link-local";
83198
- if (a === 0 || a >= 224) return "reserved";
83199
- if (a === 192 && b === 0 && (c === 0 || c === 2)) return "reserved";
83200
- if (a === 198 && b === 51 && c === 100 || a === 203 && b === 0 && c === 113) return "reserved";
83201
- return "public";
83202
- }
83203
- function groups(address) {
83204
- let text6 = address.split("%")[0];
83205
- const dotted = /^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(text6);
83206
- if (dotted) {
83207
- const octets = dotted[2].split(".").map(Number);
83208
- if (octets.some((octet) => octet > 255)) return void 0;
83209
- text6 = `${dotted[1]}${(octets[0] << 8 | octets[1]).toString(16)}:${(octets[2] << 8 | octets[3]).toString(16)}`;
83210
- }
83211
- const halves = text6.split("::");
83212
- if (halves.length > 2) return void 0;
83213
- const head = halves[0] ? halves[0].split(":") : [];
83214
- const tail = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
83215
- const fill = halves.length === 2 ? 8 - head.length - tail.length : 0;
83216
- if (fill < 0 || halves.length === 1 && head.length !== 8) return void 0;
83217
- const all = [...head, ...Array(fill).fill("0"), ...tail].map((group) => Number.parseInt(group, 16));
83218
- return all.length === 8 && all.every((group) => group >= 0 && group <= 65535) ? all : void 0;
83219
- }
83220
- function classifyAddress(address) {
83221
- const bare = address.replace(/^\[|\]$/g, "");
83222
- if (isIP2(bare) === 4) return v4(bare.split(".").map(Number));
83223
- const parts = groups(bare);
83224
- if (!parts) return "reserved";
83225
- const embedded = [parts[6] >> 8, parts[6] & 255, parts[7] >> 8, parts[7] & 255];
83226
- const zeroPrefix = parts.slice(0, 5).every((group) => group === 0);
83227
- if (zeroPrefix && parts[5] === 65535) return v4(embedded);
83228
- if (parts[0] === 100 && parts[1] === 65435 && parts.slice(2, 6).every((group) => group === 0)) return v4(embedded);
83229
- if (zeroPrefix && parts[5] === 0) {
83230
- if (parts[6] === 0 && parts[7] === 1) return "loopback";
83231
- return parts[6] === 0 && parts[7] === 0 ? "reserved" : v4(embedded);
83232
- }
83233
- if ((parts[0] & 65024) === 64512) return "private";
83234
- if ((parts[0] & 65472) === 65152) return "link-local";
83235
- if ((parts[0] & 65280) === 65280) return "reserved";
83236
- if (parts[0] === 8193 && parts[1] === 3512) return "reserved";
83237
- return "public";
83238
- }
83239
- function allowed(kind, policy) {
83240
- if (kind === "public") return true;
83241
- if (kind === "loopback") return policy.allowLoopback;
83242
- if (kind === "private" || kind === "link-local") return policy.allowPrivate;
83243
- return false;
83244
- }
83245
- function refusal(host2, address, kind) {
83246
- return new FetchRefusal(
83247
- "address",
83248
- `Refused: ${host2} is a ${kind} address (${address}). web_fetch only reads the public web and, when asked directly, this machine's own dev servers.`
83249
- );
83250
- }
83251
- function checkUrl(raw, policy) {
83252
- let url;
83253
- try {
83254
- url = new URL(raw);
83255
- } catch {
83256
- throw new FetchRefusal("url", `Not a URL: ${raw.slice(0, 200)}`);
83257
- }
83258
- if (url.protocol !== "http:" && url.protocol !== "https:") {
83259
- throw new FetchRefusal("scheme", `Refused: only http and https can be fetched, not ${url.protocol}`);
83260
- }
83261
- if (url.username || url.password) {
83262
- throw new FetchRefusal("credentials", "Refused: the URL carries credentials. Remove the user:password@ part.");
83263
- }
83264
- const host2 = url.hostname.replace(/^\[|\]$/g, "");
83265
- if (isIP2(host2)) {
83266
- const kind = classifyAddress(host2);
83267
- if (!allowed(kind, policy)) throw refusal(url.hostname, host2, kind);
83268
- }
83269
- return url;
83270
- }
83271
- function isLoopbackUrl(url) {
83272
- const host2 = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
83273
- if (host2 === "localhost" || host2.endsWith(".localhost")) return true;
83274
- return isIP2(host2) !== 0 && classifyAddress(host2) === "loopback";
83275
- }
83276
- function checkedLookup(policy, resolve13 = dnsLookup) {
83277
- return (hostname, options, callback) => {
83278
- resolve13(hostname, { ...options, all: true }, (error, answer) => {
83279
- if (error) return callback(error);
83280
- const addresses = Array.isArray(answer) ? answer : [];
83281
- if (addresses.length === 0) return callback(new FetchRefusal("dns", `${hostname} has no address`));
83282
- for (const entry of addresses) {
83283
- const kind = classifyAddress(entry.address);
83284
- if (!allowed(kind, policy)) return callback(refusal(hostname, entry.address, kind));
83285
- }
83286
- if (options.all) callback(null, addresses);
83287
- else callback(null, addresses[0].address, addresses[0].family);
83288
- });
83289
- };
83290
- }
83291
-
83292
84061
  // packages/kyrn-judge/src/web/fetch.ts
83293
84062
  var BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36";
83294
84063
  var REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
@@ -83300,7 +84069,7 @@ function decompressed(response) {
83300
84069
  return response.pipe(through);
83301
84070
  }
83302
84071
  function once(url, limits, policy, signal) {
83303
- return new Promise((resolve13, reject) => {
84072
+ return new Promise((resolve15, reject) => {
83304
84073
  const send = url.protocol === "https:" ? httpsRequest : httpRequest;
83305
84074
  const request = send(
83306
84075
  url,
@@ -83316,7 +84085,7 @@ function once(url, limits, policy, signal) {
83316
84085
  ...limits.headers
83317
84086
  }
83318
84087
  },
83319
- resolve13
84088
+ resolve15
83320
84089
  );
83321
84090
  request.on("error", reject);
83322
84091
  request.end();
@@ -83901,6 +84670,69 @@ ${lines2.join("\n\n")}`
83901
84670
  });
83902
84671
  }
83903
84672
 
84673
+ // packages/kyrn-judge/src/extension/quit.ts
84674
+ import { join as join43 } from "node:path";
84675
+
84676
+ // packages/kyrn-judge/src/auth/exit.ts
84677
+ import { mkdirSync as mkdirSync17, rmdirSync as rmdirSync2 } from "node:fs";
84678
+ import { resolve as resolve14 } from "node:path";
84679
+ import { setTimeout as sleep4 } from "node:timers/promises";
84680
+ async function holdLocksUntilExit(files, {
84681
+ limitMs = 3e3,
84682
+ pollMs = 20,
84683
+ holdMs = 2e3
84684
+ } = {}) {
84685
+ const locks = lockFolders(files);
84686
+ const deadline = Date.now() + limitMs;
84687
+ let taken = takeAll(locks);
84688
+ while (!taken && Date.now() < deadline) {
84689
+ await sleep4(pollMs);
84690
+ taken = takeAll(locks);
84691
+ }
84692
+ if (!taken) return void 0;
84693
+ const held = taken;
84694
+ const release = () => {
84695
+ clearTimeout(timer);
84696
+ process.off("exit", release);
84697
+ for (const lock of held) drop(lock);
84698
+ };
84699
+ const timer = setTimeout(release, holdMs);
84700
+ timer.unref();
84701
+ process.once("exit", release);
84702
+ return release;
84703
+ }
84704
+ function lockFolders(files) {
84705
+ return [...new Set(files.map((file) => `${resolve14(file)}.lock`))];
84706
+ }
84707
+ function takeAll(locks) {
84708
+ const taken = [];
84709
+ for (const lock of locks) {
84710
+ try {
84711
+ mkdirSync17(lock);
84712
+ taken.push(lock);
84713
+ } catch (error) {
84714
+ if (error.code !== "EEXIST") continue;
84715
+ for (const mine of taken) drop(mine);
84716
+ return void 0;
84717
+ }
84718
+ }
84719
+ return taken;
84720
+ }
84721
+ function drop(lock) {
84722
+ try {
84723
+ rmdirSync2(lock);
84724
+ } catch {
84725
+ }
84726
+ }
84727
+
84728
+ // packages/kyrn-judge/src/extension/quit.ts
84729
+ function registerLockSafeQuit(pi, agentDir) {
84730
+ const stores2 = [join43(agentDir, "auth.json"), join43(agentDir, "models-store.json")];
84731
+ pi.on("session_shutdown", async (event) => {
84732
+ if (event.reason === "quit") await holdLocksUntilExit(stores2);
84733
+ });
84734
+ }
84735
+
83904
84736
  // packages/kyrn-judge/src/extension/rejections.ts
83905
84737
  import { inspect } from "node:util";
83906
84738
  var logging = /* @__PURE__ */ new WeakSet();
@@ -83935,7 +84767,7 @@ function kyrnJudgeExtension(pi) {
83935
84767
  function registerKyrn(pi, options) {
83936
84768
  delete process.env.ELECTRON_RUN_AS_NODE;
83937
84769
  registerRejectionLog(pi);
83938
- const loaded = options.config || options.provider ? { config: options.config ?? DEFAULT_CONFIG, disabled: false, problem: void 0 } : loadConfig({ dir: (0, import_pi_coding_agent12.getAgentDir)(), env: process.env });
84770
+ const loaded = options.config || options.provider ? { config: options.config ?? DEFAULT_CONFIG, disabled: false, problem: void 0 } : loadConfig({ dir: (0, import_pi_coding_agent13.getAgentDir)(), env: process.env });
83939
84771
  const config = loaded.disabled ? { ...loaded.config, tiers: ["mock"], modes: { default: "off" } } : options.mode ? { ...loaded.config, modes: { ...loaded.config.modes, default: options.mode } } : loaded.config;
83940
84772
  const runtime = new KyrnRuntime(
83941
84773
  pi,
@@ -83947,10 +84779,12 @@ function registerKyrn(pi, options) {
83947
84779
  runtime.onPresentation = options.onPresentation;
83948
84780
  for (const capability of options.capabilities ?? []) runtime.catalog.register(capability);
83949
84781
  registerWelcome(runtime);
83950
- const roots = options.roots ?? (options.config || options.provider ? void 0 : { home: homedir9(), agentDir: (0, import_pi_coding_agent12.getAgentDir)() });
84782
+ const roots = options.roots ?? (options.config || options.provider ? void 0 : { home: homedir10(), agentDir: (0, import_pi_coding_agent13.getAgentDir)() });
83951
84783
  if (loaded.disabled) {
84784
+ if (!options.only || options.only.includes("permissions")) registerPermissions(runtime, roots);
83952
84785
  registerCommands(runtime, roots);
83953
84786
  registerImport(pi);
84787
+ if (roots) registerLockSafeQuit(pi, roots.agentDir);
83954
84788
  return;
83955
84789
  }
83956
84790
  if (process.env.KYRN_SWARM_CONTROL)
@@ -84000,6 +84834,7 @@ function registerKyrn(pi, options) {
84000
84834
  }
84001
84835
  registerCommands(runtime, roots);
84002
84836
  registerImport(pi);
84837
+ if (roots) registerLockSafeQuit(pi, roots.agentDir);
84003
84838
  }
84004
84839
  export {
84005
84840
  createKyrnJudgeExtension,