@dhf-claude/grix 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/daemon.js CHANGED
@@ -1049,11 +1049,11 @@ var hasColors, format, reset, bold, dim, italic, underline, overline, inverse, h
1049
1049
  var init_base = __esm({
1050
1050
  "node_modules/yoctocolors/base.js"() {
1051
1051
  hasColors = tty?.WriteStream?.prototype?.hasColors?.() ?? false;
1052
- format = (open3, close) => {
1052
+ format = (open4, close) => {
1053
1053
  if (!hasColors) {
1054
1054
  return (input) => input;
1055
1055
  }
1056
- const openCode = `\x1B[${open3}m`;
1056
+ const openCode = `\x1B[${open4}m`;
1057
1057
  const closeCode = `\x1B[${close}m`;
1058
1058
  return (input) => {
1059
1059
  const string = input + "";
@@ -1332,7 +1332,7 @@ var require_windows = __commonJS({
1332
1332
  module.exports = isexe;
1333
1333
  isexe.sync = sync;
1334
1334
  var fs = __require("fs");
1335
- function checkPathExt(path24, options) {
1335
+ function checkPathExt(path25, options) {
1336
1336
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
1337
1337
  if (!pathext) {
1338
1338
  return true;
@@ -1343,25 +1343,25 @@ var require_windows = __commonJS({
1343
1343
  }
1344
1344
  for (var i2 = 0; i2 < pathext.length; i2++) {
1345
1345
  var p = pathext[i2].toLowerCase();
1346
- if (p && path24.substr(-p.length).toLowerCase() === p) {
1346
+ if (p && path25.substr(-p.length).toLowerCase() === p) {
1347
1347
  return true;
1348
1348
  }
1349
1349
  }
1350
1350
  return false;
1351
1351
  }
1352
- function checkStat(stat3, path24, options) {
1353
- if (!stat3.isSymbolicLink() && !stat3.isFile()) {
1352
+ function checkStat(stat4, path25, options) {
1353
+ if (!stat4.isSymbolicLink() && !stat4.isFile()) {
1354
1354
  return false;
1355
1355
  }
1356
- return checkPathExt(path24, options);
1356
+ return checkPathExt(path25, options);
1357
1357
  }
1358
- function isexe(path24, options, cb) {
1359
- fs.stat(path24, function(er, stat3) {
1360
- cb(er, er ? false : checkStat(stat3, path24, options));
1358
+ function isexe(path25, options, cb) {
1359
+ fs.stat(path25, function(er, stat4) {
1360
+ cb(er, er ? false : checkStat(stat4, path25, options));
1361
1361
  });
1362
1362
  }
1363
- function sync(path24, options) {
1364
- return checkStat(fs.statSync(path24), path24, options);
1363
+ function sync(path25, options) {
1364
+ return checkStat(fs.statSync(path25), path25, options);
1365
1365
  }
1366
1366
  }
1367
1367
  });
@@ -1372,21 +1372,21 @@ var require_mode = __commonJS({
1372
1372
  module.exports = isexe;
1373
1373
  isexe.sync = sync;
1374
1374
  var fs = __require("fs");
1375
- function isexe(path24, options, cb) {
1376
- fs.stat(path24, function(er, stat3) {
1377
- cb(er, er ? false : checkStat(stat3, options));
1375
+ function isexe(path25, options, cb) {
1376
+ fs.stat(path25, function(er, stat4) {
1377
+ cb(er, er ? false : checkStat(stat4, options));
1378
1378
  });
1379
1379
  }
1380
- function sync(path24, options) {
1381
- return checkStat(fs.statSync(path24), options);
1380
+ function sync(path25, options) {
1381
+ return checkStat(fs.statSync(path25), options);
1382
1382
  }
1383
- function checkStat(stat3, options) {
1384
- return stat3.isFile() && checkMode(stat3, options);
1383
+ function checkStat(stat4, options) {
1384
+ return stat4.isFile() && checkMode(stat4, options);
1385
1385
  }
1386
- function checkMode(stat3, options) {
1387
- var mod = stat3.mode;
1388
- var uid = stat3.uid;
1389
- var gid = stat3.gid;
1386
+ function checkMode(stat4, options) {
1387
+ var mod = stat4.mode;
1388
+ var uid = stat4.uid;
1389
+ var gid = stat4.gid;
1390
1390
  var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
1391
1391
  var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
1392
1392
  var u2 = parseInt("100", 8);
@@ -1411,7 +1411,7 @@ var require_isexe = __commonJS({
1411
1411
  }
1412
1412
  module.exports = isexe;
1413
1413
  isexe.sync = sync;
1414
- function isexe(path24, options, cb) {
1414
+ function isexe(path25, options, cb) {
1415
1415
  if (typeof options === "function") {
1416
1416
  cb = options;
1417
1417
  options = {};
@@ -1421,7 +1421,7 @@ var require_isexe = __commonJS({
1421
1421
  throw new TypeError("callback not provided");
1422
1422
  }
1423
1423
  return new Promise(function(resolve, reject) {
1424
- isexe(path24, options || {}, function(er, is) {
1424
+ isexe(path25, options || {}, function(er, is) {
1425
1425
  if (er) {
1426
1426
  reject(er);
1427
1427
  } else {
@@ -1430,7 +1430,7 @@ var require_isexe = __commonJS({
1430
1430
  });
1431
1431
  });
1432
1432
  }
1433
- core(path24, options || {}, function(er, is) {
1433
+ core(path25, options || {}, function(er, is) {
1434
1434
  if (er) {
1435
1435
  if (er.code === "EACCES" || options && options.ignoreErrors) {
1436
1436
  er = null;
@@ -1440,9 +1440,9 @@ var require_isexe = __commonJS({
1440
1440
  cb(er, is);
1441
1441
  });
1442
1442
  }
1443
- function sync(path24, options) {
1443
+ function sync(path25, options) {
1444
1444
  try {
1445
- return core.sync(path24, options || {});
1445
+ return core.sync(path25, options || {});
1446
1446
  } catch (er) {
1447
1447
  if (options && options.ignoreErrors || er.code === "EACCES") {
1448
1448
  return false;
@@ -1458,7 +1458,7 @@ var require_isexe = __commonJS({
1458
1458
  var require_which = __commonJS({
1459
1459
  "node_modules/which/which.js"(exports, module) {
1460
1460
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
1461
- var path24 = __require("path");
1461
+ var path25 = __require("path");
1462
1462
  var COLON = isWindows ? ";" : ":";
1463
1463
  var isexe = require_isexe();
1464
1464
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -1496,7 +1496,7 @@ var require_which = __commonJS({
1496
1496
  return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
1497
1497
  const ppRaw = pathEnv[i2];
1498
1498
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
1499
- const pCmd = path24.join(pathPart, cmd);
1499
+ const pCmd = path25.join(pathPart, cmd);
1500
1500
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
1501
1501
  resolve(subStep(p, i2, 0));
1502
1502
  });
@@ -1523,7 +1523,7 @@ var require_which = __commonJS({
1523
1523
  for (let i2 = 0; i2 < pathEnv.length; i2++) {
1524
1524
  const ppRaw = pathEnv[i2];
1525
1525
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
1526
- const pCmd = path24.join(pathPart, cmd);
1526
+ const pCmd = path25.join(pathPart, cmd);
1527
1527
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
1528
1528
  for (let j = 0; j < pathExt.length; j++) {
1529
1529
  const cur = p + pathExt[j];
@@ -1571,7 +1571,7 @@ var require_path_key = __commonJS({
1571
1571
  var require_resolveCommand = __commonJS({
1572
1572
  "node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
1573
1573
  "use strict";
1574
- var path24 = __require("path");
1574
+ var path25 = __require("path");
1575
1575
  var which = require_which();
1576
1576
  var getPathKey = require_path_key();
1577
1577
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -1589,7 +1589,7 @@ var require_resolveCommand = __commonJS({
1589
1589
  try {
1590
1590
  resolved = which.sync(parsed.command, {
1591
1591
  path: env[getPathKey({ env })],
1592
- pathExt: withoutPathExt ? path24.delimiter : void 0
1592
+ pathExt: withoutPathExt ? path25.delimiter : void 0
1593
1593
  });
1594
1594
  } catch (e) {
1595
1595
  } finally {
@@ -1598,7 +1598,7 @@ var require_resolveCommand = __commonJS({
1598
1598
  }
1599
1599
  }
1600
1600
  if (resolved) {
1601
- resolved = path24.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
1601
+ resolved = path25.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
1602
1602
  }
1603
1603
  return resolved;
1604
1604
  }
@@ -1652,8 +1652,8 @@ var require_shebang_command = __commonJS({
1652
1652
  if (!match) {
1653
1653
  return null;
1654
1654
  }
1655
- const [path24, argument] = match[0].replace(/#! ?/, "").split(" ");
1656
- const binary = path24.split("/").pop();
1655
+ const [path25, argument] = match[0].replace(/#! ?/, "").split(" ");
1656
+ const binary = path25.split("/").pop();
1657
1657
  if (binary === "env") {
1658
1658
  return argument;
1659
1659
  }
@@ -1688,7 +1688,7 @@ var require_readShebang = __commonJS({
1688
1688
  var require_parse = __commonJS({
1689
1689
  "node_modules/cross-spawn/lib/parse.js"(exports, module) {
1690
1690
  "use strict";
1691
- var path24 = __require("path");
1691
+ var path25 = __require("path");
1692
1692
  var resolveCommand = require_resolveCommand();
1693
1693
  var escape = require_escape();
1694
1694
  var readShebang = require_readShebang();
@@ -1713,7 +1713,7 @@ var require_parse = __commonJS({
1713
1713
  const needsShell = !isExecutableRegExp.test(commandFile);
1714
1714
  if (parsed.options.forceShell || needsShell) {
1715
1715
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
1716
- parsed.command = path24.normalize(parsed.command);
1716
+ parsed.command = path25.normalize(parsed.command);
1717
1717
  parsed.command = escape.command(parsed.command);
1718
1718
  parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
1719
1719
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -1809,7 +1809,7 @@ var require_cross_spawn = __commonJS({
1809
1809
  enoent.hookChildProcess(spawned, parsed);
1810
1810
  return spawned;
1811
1811
  }
1812
- function spawnSync3(command, args, options) {
1812
+ function spawnSync4(command, args, options) {
1813
1813
  const parsed = parse(command, args, options);
1814
1814
  const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
1815
1815
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
@@ -1817,7 +1817,7 @@ var require_cross_spawn = __commonJS({
1817
1817
  }
1818
1818
  module.exports = spawn4;
1819
1819
  module.exports.spawn = spawn4;
1820
- module.exports.sync = spawnSync3;
1820
+ module.exports.sync = spawnSync4;
1821
1821
  module.exports._parse = parse;
1822
1822
  module.exports._enoent = enoent;
1823
1823
  }
@@ -5843,13 +5843,13 @@ var init_output_sync = __esm({
5843
5843
  }
5844
5844
  };
5845
5845
  writeToFiles = (serializedResult, stdioItems, outputFiles) => {
5846
- for (const { path: path24, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
5847
- const pathString = typeof path24 === "string" ? path24 : path24.toString();
5846
+ for (const { path: path25, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
5847
+ const pathString = typeof path25 === "string" ? path25 : path25.toString();
5848
5848
  if (append || outputFiles.has(pathString)) {
5849
- appendFileSync(path24, serializedResult);
5849
+ appendFileSync(path25, serializedResult);
5850
5850
  } else {
5851
5851
  outputFiles.add(pathString);
5852
- writeFileSync(path24, serializedResult);
5852
+ writeFileSync(path25, serializedResult);
5853
5853
  }
5854
5854
  }
5855
5855
  };
@@ -6780,7 +6780,7 @@ var processOk, kExitEmitter, global2, ObjectDefineProperty, Emitter, SignalExitB
6780
6780
  var init_mjs = __esm({
6781
6781
  "node_modules/signal-exit/dist/mjs/index.js"() {
6782
6782
  init_signals2();
6783
- processOk = (process17) => !!process17 && typeof process17 === "object" && typeof process17.removeListener === "function" && typeof process17.emit === "function" && typeof process17.reallyExit === "function" && typeof process17.listeners === "function" && typeof process17.kill === "function" && typeof process17.pid === "number" && typeof process17.on === "function";
6783
+ processOk = (process18) => !!process18 && typeof process18 === "object" && typeof process18.removeListener === "function" && typeof process18.emit === "function" && typeof process18.reallyExit === "function" && typeof process18.listeners === "function" && typeof process18.kill === "function" && typeof process18.pid === "number" && typeof process18.on === "function";
6784
6784
  kExitEmitter = /* @__PURE__ */ Symbol.for("signal-exit emitter");
6785
6785
  global2 = globalThis;
6786
6786
  ObjectDefineProperty = Object.defineProperty.bind(Object);
@@ -6873,15 +6873,15 @@ var init_mjs = __esm({
6873
6873
  #originalProcessReallyExit;
6874
6874
  #sigListeners = {};
6875
6875
  #loaded = false;
6876
- constructor(process17) {
6876
+ constructor(process18) {
6877
6877
  super();
6878
- this.#process = process17;
6878
+ this.#process = process18;
6879
6879
  this.#sigListeners = {};
6880
6880
  for (const sig of signals) {
6881
6881
  this.#sigListeners[sig] = () => {
6882
6882
  const listeners = this.#process.listeners(sig);
6883
6883
  let { count: count2 } = this.#emitter;
6884
- const p = process17;
6884
+ const p = process18;
6885
6885
  if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") {
6886
6886
  count2 += p.__signal_exit_emitter__.count;
6887
6887
  }
@@ -6890,12 +6890,12 @@ var init_mjs = __esm({
6890
6890
  const ret = this.#emitter.emit("exit", null, sig);
6891
6891
  const s = sig === "SIGHUP" ? this.#hupSig : sig;
6892
6892
  if (!ret)
6893
- process17.kill(process17.pid, s);
6893
+ process18.kill(process18.pid, s);
6894
6894
  }
6895
6895
  };
6896
6896
  }
6897
- this.#originalProcessReallyExit = process17.reallyExit;
6898
- this.#originalProcessEmit = process17.emit;
6897
+ this.#originalProcessReallyExit = process18.reallyExit;
6898
+ this.#originalProcessEmit = process18.emit;
6899
6899
  }
6900
6900
  onExit(cb, opts) {
6901
6901
  if (!processOk(this.#process)) {
@@ -8649,7 +8649,7 @@ var require_bin = __commonJS({
8649
8649
  var require_ps = __commonJS({
8650
8650
  "node_modules/pidtree/lib/ps.js"(exports, module) {
8651
8651
  "use strict";
8652
- var os7 = __require("os");
8652
+ var os8 = __require("os");
8653
8653
  var bin = require_bin();
8654
8654
  function ps(callback) {
8655
8655
  var args = ["-A", "-o", "ppid,pid"];
@@ -8659,7 +8659,7 @@ var require_ps = __commonJS({
8659
8659
  return callback(new Error("pidtree ps command exited with code " + code));
8660
8660
  }
8661
8661
  try {
8662
- stdout = stdout.split(os7.EOL);
8662
+ stdout = stdout.split(os8.EOL);
8663
8663
  var list = [];
8664
8664
  for (var i2 = 1; i2 < stdout.length; i2++) {
8665
8665
  stdout[i2] = stdout[i2].trim();
@@ -8683,7 +8683,7 @@ var require_ps = __commonJS({
8683
8683
  var require_wmic = __commonJS({
8684
8684
  "node_modules/pidtree/lib/wmic.js"(exports, module) {
8685
8685
  "use strict";
8686
- var os7 = __require("os");
8686
+ var os8 = __require("os");
8687
8687
  var bin = require_bin();
8688
8688
  function wmic(callback) {
8689
8689
  var args = ["PROCESS", "get", "ParentProcessId,ProcessId"];
@@ -8698,7 +8698,7 @@ var require_wmic = __commonJS({
8698
8698
  return;
8699
8699
  }
8700
8700
  try {
8701
- stdout = stdout.split(os7.EOL);
8701
+ stdout = stdout.split(os8.EOL);
8702
8702
  var list = [];
8703
8703
  for (var i2 = 1; i2 < stdout.length; i2++) {
8704
8704
  stdout[i2] = stdout[i2].trim();
@@ -8722,7 +8722,7 @@ var require_wmic = __commonJS({
8722
8722
  var require_get = __commonJS({
8723
8723
  "node_modules/pidtree/lib/get.js"(exports, module) {
8724
8724
  "use strict";
8725
- var os7 = __require("os");
8725
+ var os8 = __require("os");
8726
8726
  var platformToMethod = {
8727
8727
  darwin: "ps",
8728
8728
  sunos: "ps",
@@ -8736,7 +8736,7 @@ var require_get = __commonJS({
8736
8736
  ps: () => require_ps(),
8737
8737
  wmic: () => require_wmic()
8738
8738
  };
8739
- var platform2 = os7.platform();
8739
+ var platform2 = os8.platform();
8740
8740
  if (platform2.startsWith("win")) {
8741
8741
  platform2 = "win";
8742
8742
  }
@@ -8745,7 +8745,7 @@ var require_get = __commonJS({
8745
8745
  if (method === void 0) {
8746
8746
  callback(
8747
8747
  new Error(
8748
- os7.platform() + " is not supported yet, please open an issue (https://github.com/simonepri/pidtree)"
8748
+ os8.platform() + " is not supported yet, please open an issue (https://github.com/simonepri/pidtree)"
8749
8749
  )
8750
8750
  );
8751
8751
  }
@@ -9429,32 +9429,6 @@ function canDeliverToWorker(binding) {
9429
9429
  const responseState = normalizeWorkerResponseState(binding?.worker_response_state);
9430
9430
  return hasReadyWorkerBridge(binding) && responseState === "healthy";
9431
9431
  }
9432
- function formatWorkerResponseAssessment(binding) {
9433
- const workerStatus = normalizeString10(binding?.worker_status);
9434
- const responseState = normalizeWorkerResponseState(binding?.worker_response_state);
9435
- if (workerStatus === "ready") {
9436
- if (responseState === "healthy") {
9437
- return "\u53EF\u7528\uFF08\u6700\u8FD1\u4E00\u6B21\u771F\u5B9E\u4EA4\u4E92\u5DF2\u9A8C\u8BC1\uFF09";
9438
- }
9439
- if (responseState === "probing") {
9440
- return "\u63A2\u6D4B\u4E2D\uFF08\u6B63\u5728\u7B49\u5F85 ping/pong\uFF09";
9441
- }
9442
- if (responseState === "failed") {
9443
- return "\u5F02\u5E38\uFF08\u6700\u8FD1\u4E00\u6B21\u771F\u5B9E\u4EA4\u4E92\u5931\u8D25\uFF09";
9444
- }
9445
- return "\u5F85\u9A8C\u8BC1\uFF08\u5DF2\u5C31\u7EEA\uFF0C\u4F46\u8FD8\u6CA1\u6709\u771F\u5B9E\u4EA4\u4E92\u8BC1\u660E\uFF09";
9446
- }
9447
- if (workerStatus === "starting" || workerStatus === "connected") {
9448
- return "\u542F\u52A8\u4E2D";
9449
- }
9450
- if (workerStatus === "stopped") {
9451
- return "\u5DF2\u505C\u6B62";
9452
- }
9453
- if (workerStatus === "failed") {
9454
- return "\u5DF2\u5931\u8D25";
9455
- }
9456
- return "\u672A\u77E5";
9457
- }
9458
9432
  var init_worker_state = __esm({
9459
9433
  "server/daemon/worker-state.js"() {
9460
9434
  }
@@ -10380,7 +10354,9 @@ var init_worker_bridge_server = __esm({
10380
10354
  onSendEventResult = null,
10381
10355
  onSendEventStopAck = null,
10382
10356
  onSendEventStopResult = null,
10383
- onSetSessionComposing = null
10357
+ onSetSessionComposing = null,
10358
+ onAgentInvoke = null,
10359
+ onLocalActionResult = null
10384
10360
  } = {}) {
10385
10361
  this.host = host;
10386
10362
  this.port = port;
@@ -10396,6 +10372,8 @@ var init_worker_bridge_server = __esm({
10396
10372
  this.onSendEventStopAck = typeof onSendEventStopAck === "function" ? onSendEventStopAck : null;
10397
10373
  this.onSendEventStopResult = typeof onSendEventStopResult === "function" ? onSendEventStopResult : null;
10398
10374
  this.onSetSessionComposing = typeof onSetSessionComposing === "function" ? onSetSessionComposing : null;
10375
+ this.onAgentInvoke = typeof onAgentInvoke === "function" ? onAgentInvoke : null;
10376
+ this.onLocalActionResult = typeof onLocalActionResult === "function" ? onLocalActionResult : null;
10399
10377
  this.server = null;
10400
10378
  this.address = null;
10401
10379
  }
@@ -10438,6 +10416,8 @@ var init_worker_bridge_server = __esm({
10438
10416
  const server = this.server;
10439
10417
  this.server = null;
10440
10418
  this.address = null;
10419
+ server.closeIdleConnections?.();
10420
+ server.closeAllConnections?.();
10441
10421
  await new Promise((resolve, reject) => {
10442
10422
  server.close((error) => {
10443
10423
  if (error) {
@@ -10576,6 +10556,30 @@ var init_worker_bridge_server = __esm({
10576
10556
  ok(response, result ?? { ok: true });
10577
10557
  return;
10578
10558
  }
10559
+ if (pathname === "/v1/worker/agent-invoke") {
10560
+ this.trace({
10561
+ stage: "worker_agent_invoke_received",
10562
+ worker_id: payload?.worker_id,
10563
+ aibot_session_id: payload?.aibot_session_id,
10564
+ invoke_id: payload?.invoke_id,
10565
+ action: payload?.action
10566
+ });
10567
+ const result = this.onAgentInvoke ? await this.onAgentInvoke(payload) : { code: 4004, msg: "agent invoke handler is not configured" };
10568
+ ok(response, result ?? { code: 4004, msg: "agent invoke handler is not configured" });
10569
+ return;
10570
+ }
10571
+ if (pathname === "/v1/worker/local-action-result") {
10572
+ this.trace({
10573
+ stage: "worker_local_action_result_received",
10574
+ worker_id: payload?.worker_id,
10575
+ aibot_session_id: payload?.aibot_session_id,
10576
+ action_id: payload?.action_id,
10577
+ status: payload?.status
10578
+ });
10579
+ const result = this.onLocalActionResult ? await this.onLocalActionResult(payload) : { ok: true };
10580
+ ok(response, result ?? { ok: true });
10581
+ return;
10582
+ }
10579
10583
  notFound(response);
10580
10584
  }
10581
10585
  };
@@ -10788,7 +10792,7 @@ var init_paths = __esm({
10788
10792
  });
10789
10793
 
10790
10794
  // server/hook-signal-store.js
10791
- import { appendFile, mkdir as mkdir9 } from "node:fs/promises";
10795
+ import { appendFile, mkdir as mkdir9, open as open2, rm as rm5, stat } from "node:fs/promises";
10792
10796
  import path19 from "node:path";
10793
10797
  import { randomUUID as randomUUID3 } from "node:crypto";
10794
10798
  function normalizeString17(value) {
@@ -10805,12 +10809,21 @@ function pickHookEventDetail(input = {}, hookEventName) {
10805
10809
  if (hookEventName === "SessionStart") {
10806
10810
  return normalizeString17(input.source);
10807
10811
  }
10812
+ if (hookEventName === "PermissionRequest") {
10813
+ return normalizeString17(input.tool_name);
10814
+ }
10808
10815
  if (hookEventName === "PostToolUse" || hookEventName === "PostToolUseFailure") {
10809
10816
  return normalizeString17(input.tool_name);
10810
10817
  }
10818
+ if (hookEventName === "PermissionDenied") {
10819
+ return normalizeString17(input.tool_name) || normalizeString17(input.reason);
10820
+ }
10811
10821
  if (hookEventName === "Elicitation") {
10812
10822
  return normalizeString17(input.mode);
10813
10823
  }
10824
+ if (hookEventName === "ElicitationResult") {
10825
+ return normalizeString17(input.action) || normalizeString17(input.mode);
10826
+ }
10814
10827
  if (hookEventName === "Notification") {
10815
10828
  return normalizeString17(input.matcher) || normalizeString17(input.notification_type) || normalizeString17(input.type);
10816
10829
  }
@@ -10829,11 +10842,7 @@ function normalizeHookSignalEvent(input) {
10829
10842
  event_id: eventID,
10830
10843
  hook_event_name: hookEventName,
10831
10844
  event_at: normalizeOptionalTimestamp3(input.event_at),
10832
- detail: normalizeString17(input.detail),
10833
- tool_name: normalizeString17(input.tool_name),
10834
- session_id: normalizeString17(input.session_id),
10835
- cwd: normalizeString17(input.cwd),
10836
- transcript_path: normalizeString17(input.transcript_path)
10845
+ detail: normalizeString17(input.detail)
10837
10846
  };
10838
10847
  }
10839
10848
  function normalizeState4(input) {
@@ -10856,6 +10865,26 @@ function normalizeState4(input) {
10856
10865
  function resolveHookSignalsPath(pluginID) {
10857
10866
  return path19.join(resolvePluginDataDir(pluginID), "hook-signals.json");
10858
10867
  }
10868
+ function resolveHookSignalsLockPathFromDataDir(pluginDataDir, pluginID) {
10869
+ const normalizedDir = normalizeString17(pluginDataDir);
10870
+ if (normalizedDir) {
10871
+ return path19.join(normalizedDir, "hook-signals.lock");
10872
+ }
10873
+ return path19.join(resolvePluginDataDir(pluginID), "hook-signals.lock");
10874
+ }
10875
+ function sleep(delayMs) {
10876
+ return new Promise((resolve) => {
10877
+ setTimeout(resolve, delayMs);
10878
+ });
10879
+ }
10880
+ async function readLockAgeMs(filePath) {
10881
+ try {
10882
+ const details = await stat(filePath);
10883
+ return Date.now() - Number(details.mtimeMs ?? 0);
10884
+ } catch {
10885
+ return 0;
10886
+ }
10887
+ }
10859
10888
  function buildHookSignalEvent(input, { recordedAt = Date.now() } = {}) {
10860
10889
  const hookEventName = normalizeString17(input?.hook_event_name);
10861
10890
  if (!hookEventName) {
@@ -10865,24 +10894,10 @@ function buildHookSignalEvent(input, { recordedAt = Date.now() } = {}) {
10865
10894
  event_id: randomUUID3(),
10866
10895
  hook_event_name: hookEventName,
10867
10896
  event_at: normalizeOptionalTimestamp3(recordedAt) || Date.now(),
10868
- detail: pickHookEventDetail(input, hookEventName),
10869
- tool_name: normalizeString17(input?.tool_name),
10870
- session_id: normalizeString17(input?.session_id),
10871
- cwd: normalizeString17(input?.cwd),
10872
- transcript_path: normalizeString17(input?.transcript_path)
10897
+ detail: pickHookEventDetail(input, hookEventName)
10873
10898
  };
10874
10899
  }
10875
- function summarizeHookSignalEvent(event) {
10876
- const normalized = normalizeHookSignalEvent(event);
10877
- if (!normalized) {
10878
- return "";
10879
- }
10880
- if (normalized.detail) {
10881
- return `${normalized.hook_event_name}:${normalized.detail}`;
10882
- }
10883
- return normalized.hook_event_name;
10884
- }
10885
- var schemaVersion4, defaultRecentEventLimit, HookSignalStore;
10900
+ var schemaVersion4, defaultRecentEventLimit, defaultLockTimeoutMs, defaultLockPollMs, defaultLockStaleMs, HookSignalStore;
10886
10901
  var init_hook_signal_store = __esm({
10887
10902
  "server/hook-signal-store.js"() {
10888
10903
  init_json_file();
@@ -10890,10 +10905,17 @@ var init_hook_signal_store = __esm({
10890
10905
  init_paths();
10891
10906
  schemaVersion4 = 1;
10892
10907
  defaultRecentEventLimit = 20;
10908
+ defaultLockTimeoutMs = 5e3;
10909
+ defaultLockPollMs = 25;
10910
+ defaultLockStaleMs = 3e4;
10893
10911
  HookSignalStore = class {
10894
- constructor(filePath = resolveHookSignalsPath(), { logPath = path19.join(path19.dirname(filePath), "hook-signals.log") } = {}) {
10912
+ constructor(filePath = resolveHookSignalsPath(), {
10913
+ logPath = path19.join(path19.dirname(filePath), "hook-signals.log"),
10914
+ lockPath = resolveHookSignalsLockPathFromDataDir(path19.dirname(filePath))
10915
+ } = {}) {
10895
10916
  this.filePath = filePath;
10896
10917
  this.logPath = logPath;
10918
+ this.lockPath = lockPath;
10897
10919
  }
10898
10920
  async readState() {
10899
10921
  const stored = await readJSONFile(this.filePath, null);
@@ -10903,9 +10925,54 @@ var init_hook_signal_store = __esm({
10903
10925
  await mkdir9(path19.dirname(this.filePath), { recursive: true });
10904
10926
  await writeJSONFileAtomic(this.filePath, normalizeState4(state));
10905
10927
  }
10928
+ async withStateLock(callback, {
10929
+ timeoutMs = defaultLockTimeoutMs,
10930
+ pollMs = defaultLockPollMs,
10931
+ staleMs = defaultLockStaleMs
10932
+ } = {}) {
10933
+ await mkdir9(path19.dirname(this.lockPath), { recursive: true });
10934
+ const deadlineAt = Date.now() + Math.max(1, Number(timeoutMs) || defaultLockTimeoutMs);
10935
+ while (Date.now() < deadlineAt) {
10936
+ let handle = null;
10937
+ try {
10938
+ handle = await open2(this.lockPath, "wx", 384);
10939
+ await handle.writeFile(JSON.stringify({
10940
+ schema_version: schemaVersion4,
10941
+ pid: process.pid,
10942
+ acquired_at: Date.now()
10943
+ }), "utf8");
10944
+ try {
10945
+ return await callback();
10946
+ } finally {
10947
+ await handle.close().catch(() => {
10948
+ });
10949
+ await rm5(this.lockPath, { force: true }).catch(() => {
10950
+ });
10951
+ }
10952
+ } catch (error) {
10953
+ if (!error || typeof error !== "object" || !("code" in error) || error.code !== "EEXIST") {
10954
+ if (handle) {
10955
+ await handle.close().catch(() => {
10956
+ });
10957
+ }
10958
+ throw error;
10959
+ }
10960
+ const lockAgeMs = await readLockAgeMs(this.lockPath);
10961
+ if (lockAgeMs > staleMs) {
10962
+ await rm5(this.lockPath, { force: true }).catch(() => {
10963
+ });
10964
+ continue;
10965
+ }
10966
+ await sleep(Math.min(pollMs, Math.max(1, deadlineAt - Date.now())));
10967
+ }
10968
+ }
10969
+ throw new Error("hook signal store lock timeout");
10970
+ }
10906
10971
  async reset() {
10907
- await this.writeState(normalizeState4(null));
10908
- return this.readState();
10972
+ return this.withStateLock(async () => {
10973
+ await this.writeState(normalizeState4(null));
10974
+ return this.readState();
10975
+ });
10909
10976
  }
10910
10977
  async appendEventLog(event) {
10911
10978
  const normalized = normalizeHookSignalEvent(event);
@@ -10918,11 +10985,7 @@ var init_hook_signal_store = __esm({
10918
10985
  event_id: normalized.event_id,
10919
10986
  hook_event_name: normalized.hook_event_name,
10920
10987
  hook_detail: normalized.detail,
10921
- event_at: normalized.event_at,
10922
- tool_name: normalized.tool_name,
10923
- session_id: normalized.session_id,
10924
- cwd: normalized.cwd,
10925
- transcript_path: normalized.transcript_path
10988
+ event_at: normalized.event_at
10926
10989
  })}
10927
10990
  `, "utf8");
10928
10991
  return true;
@@ -10935,29 +10998,100 @@ var init_hook_signal_store = __esm({
10935
10998
  if (!nextEvent) {
10936
10999
  return this.readState();
10937
11000
  }
10938
- const current = await this.readState();
10939
- const nextState = {
10940
- schema_version: schemaVersion4,
10941
- updated_at: nextEvent.event_at,
10942
- latest_event: nextEvent,
10943
- recent_events: [
11001
+ return this.withStateLock(async () => {
11002
+ const current = await this.readState();
11003
+ const recentEvents = [
10944
11004
  ...current.recent_events,
10945
11005
  nextEvent
10946
- ].slice(-Math.max(1, Number(recentEventLimit) || defaultRecentEventLimit))
10947
- };
10948
- await this.writeState(nextState);
10949
- await this.appendEventLog(nextEvent);
10950
- return normalizeState4(nextState);
11006
+ ].sort((left, right) => left.event_at - right.event_at).slice(-Math.max(1, Number(recentEventLimit) || defaultRecentEventLimit));
11007
+ const latestEvent = !current.latest_event || nextEvent.event_at >= current.updated_at ? nextEvent : current.latest_event;
11008
+ const nextState = {
11009
+ schema_version: schemaVersion4,
11010
+ updated_at: Math.max(current.updated_at, nextEvent.event_at),
11011
+ latest_event: latestEvent,
11012
+ recent_events: recentEvents
11013
+ };
11014
+ await this.writeState(nextState);
11015
+ await this.appendEventLog(nextEvent);
11016
+ return normalizeState4(nextState);
11017
+ });
10951
11018
  }
10952
11019
  };
10953
11020
  }
10954
11021
  });
10955
11022
 
10956
- // server/daemon/worker-process.js
10957
- import { chmod as chmod2, mkdir as mkdir10, open as open2, readdir, readFile as readFile4, stat, writeFile as writeFile3 } from "node:fs/promises";
10958
- import { execSync, spawn as spawn3 } from "node:child_process";
11023
+ // server/claude-command.js
11024
+ import { spawnSync as spawnSync3 } from "node:child_process";
11025
+ import { accessSync, constants as fsConstants } from "node:fs";
11026
+ import os7 from "node:os";
10959
11027
  import path20 from "node:path";
10960
11028
  import process13 from "node:process";
11029
+ function normalizeString18(value) {
11030
+ return String(value ?? "").trim();
11031
+ }
11032
+ function defaultClaudeCommandName(platform2 = process13.platform) {
11033
+ return platform2 === "win32" ? "claude.cmd" : "claude";
11034
+ }
11035
+ function buildClaudeCommandCandidates(env = process13.env) {
11036
+ const candidates = [];
11037
+ const explicit = normalizeString18(env.CLAUDE_BIN);
11038
+ if (explicit) {
11039
+ candidates.push(explicit);
11040
+ }
11041
+ const commandName = defaultClaudeCommandName();
11042
+ candidates.push(commandName);
11043
+ if (process13.platform !== "win32") {
11044
+ const homeDir = normalizeString18(env.HOME || env.USERPROFILE) || os7.homedir();
11045
+ if (homeDir) {
11046
+ candidates.push(path20.join(homeDir, ".local", "bin", "claude"));
11047
+ }
11048
+ candidates.push("/opt/homebrew/bin/claude");
11049
+ candidates.push("/usr/local/bin/claude");
11050
+ }
11051
+ return Array.from(new Set(candidates.filter((value) => normalizeString18(value))));
11052
+ }
11053
+ function claudeCommandExists(command, env = process13.env) {
11054
+ const normalized = normalizeString18(command);
11055
+ if (!normalized) {
11056
+ return false;
11057
+ }
11058
+ if (path20.isAbsolute(normalized) || normalized.includes(path20.sep)) {
11059
+ try {
11060
+ accessSync(normalized, fsConstants.X_OK);
11061
+ return true;
11062
+ } catch {
11063
+ return false;
11064
+ }
11065
+ }
11066
+ const locator = process13.platform === "win32" ? "where" : "which";
11067
+ const located = spawnSync3(locator, [normalized], {
11068
+ stdio: "ignore",
11069
+ env
11070
+ });
11071
+ return located.status === 0;
11072
+ }
11073
+ function resolveClaudeCommand(env = process13.env) {
11074
+ const explicit = normalizeString18(env.CLAUDE_BIN);
11075
+ if (explicit) {
11076
+ return explicit;
11077
+ }
11078
+ for (const candidate of buildClaudeCommandCandidates(env)) {
11079
+ if (claudeCommandExists(candidate, env)) {
11080
+ return candidate;
11081
+ }
11082
+ }
11083
+ return defaultClaudeCommandName();
11084
+ }
11085
+ var init_claude_command = __esm({
11086
+ "server/claude-command.js"() {
11087
+ }
11088
+ });
11089
+
11090
+ // server/daemon/worker-process.js
11091
+ import { chmod as chmod2, mkdir as mkdir10, open as open3, readdir, readFile as readFile4, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
11092
+ import { execSync, spawn as spawn3 } from "node:child_process";
11093
+ import path21 from "node:path";
11094
+ import process14 from "node:process";
10961
11095
  import { randomUUID as randomUUID4 } from "node:crypto";
10962
11096
  function stripTerminalControlSequences(content) {
10963
11097
  return String(content ?? "").replace(/\u001B\][^\u0007]*(?:\u0007|\u001B\\)/gu, " ").replace(/\u001B\[[0-?]*[ -/]*[@-~]/gu, " ").replace(/\r/g, "\n");
@@ -10969,7 +11103,7 @@ function patternMatches(pattern, content) {
10969
11103
  pattern.lastIndex = 0;
10970
11104
  return pattern.test(content);
10971
11105
  }
10972
- function normalizeString18(value) {
11106
+ function normalizeString19(value) {
10973
11107
  return String(value ?? "").trim();
10974
11108
  }
10975
11109
  function normalizeNonNegativeOffset(value) {
@@ -10990,13 +11124,13 @@ async function readLogSlice(filePath, {
10990
11124
  startOffset = 0,
10991
11125
  maxBytes = 0
10992
11126
  } = {}) {
10993
- const normalizedPath = normalizeString18(filePath);
11127
+ const normalizedPath = normalizeString19(filePath);
10994
11128
  if (!normalizedPath) {
10995
11129
  return "";
10996
11130
  }
10997
11131
  let fileSize = 0;
10998
11132
  try {
10999
- const info = await stat(normalizedPath);
11133
+ const info = await stat2(normalizedPath);
11000
11134
  fileSize = normalizeNonNegativeOffset(info?.size);
11001
11135
  } catch {
11002
11136
  return "";
@@ -11013,7 +11147,7 @@ async function readLogSlice(filePath, {
11013
11147
  if (bytesToRead <= 0) {
11014
11148
  return "";
11015
11149
  }
11016
- const handle = await open2(normalizedPath, "r");
11150
+ const handle = await open3(normalizedPath, "r");
11017
11151
  try {
11018
11152
  const buffer = Buffer.alloc(bytesToRead);
11019
11153
  const { bytesRead = 0 } = await handle.read(buffer, 0, bytesToRead, start);
@@ -11023,12 +11157,6 @@ async function readLogSlice(filePath, {
11023
11157
  });
11024
11158
  }
11025
11159
  }
11026
- function resolveClaudeCommand(env = process13.env) {
11027
- if (process13.platform === "win32") {
11028
- return env.CLAUDE_BIN || "claude.cmd";
11029
- }
11030
- return env.CLAUDE_BIN || "claude";
11031
- }
11032
11160
  function shellEscape(value) {
11033
11161
  return `'${String(value ?? "").replace(/'/g, `'\\''`)}'`;
11034
11162
  }
@@ -11063,24 +11191,24 @@ function buildVisibleTerminalCleanupLines() {
11063
11191
  ];
11064
11192
  }
11065
11193
  function buildShellEnvArgs(env) {
11066
- return Object.entries(env).filter(([key, value]) => normalizeString18(key) && !String(key).includes("=") && value !== void 0).map(([key, value]) => shellEscape(`${String(key)}=${String(value ?? "")}`));
11194
+ return Object.entries(env).filter(([key, value]) => normalizeString19(key) && !String(key).includes("=") && value !== void 0).map(([key, value]) => shellEscape(`${String(key)}=${String(value ?? "")}`));
11067
11195
  }
11068
- function shouldShowClaudeWindow(env = process13.env) {
11196
+ function shouldShowClaudeWindow(env = process14.env) {
11069
11197
  return env.GRIX_CLAUDE_SHOW_CLAUDE_WINDOW === "1";
11070
11198
  }
11071
11199
  function buildWorkerSessionName(aibotSessionID) {
11072
- const normalized = normalizeString18(aibotSessionID).replace(/[^a-zA-Z0-9._-]+/g, "-");
11200
+ const normalized = normalizeString19(aibotSessionID).replace(/[^a-zA-Z0-9._-]+/g, "-");
11073
11201
  return normalized ? `grix-${normalized}` : "grix-worker";
11074
11202
  }
11075
11203
  function resolveWorkerLogPaths({ logsDir, workerID }) {
11076
- const normalizedWorkerID = normalizeString18(workerID) || randomUUID4();
11204
+ const normalizedWorkerID = normalizeString19(workerID) || randomUUID4();
11077
11205
  return {
11078
- stdoutLogPath: path20.join(logsDir, `${normalizedWorkerID}.out.log`),
11079
- stderrLogPath: path20.join(logsDir, `${normalizedWorkerID}.err.log`)
11206
+ stdoutLogPath: path21.join(logsDir, `${normalizedWorkerID}.out.log`),
11207
+ stderrLogPath: path21.join(logsDir, `${normalizedWorkerID}.err.log`)
11080
11208
  };
11081
11209
  }
11082
11210
  function buildWorkerEnvironment({
11083
- baseEnv = process13.env,
11211
+ baseEnv = process14.env,
11084
11212
  pluginDataDir,
11085
11213
  aibotSessionID,
11086
11214
  claudeSessionID,
@@ -11091,18 +11219,18 @@ function buildWorkerEnvironment({
11091
11219
  }) {
11092
11220
  const env = {
11093
11221
  ...baseEnv,
11094
- CLAUDE_PLUGIN_DATA: normalizeString18(pluginDataDir),
11095
- GRIX_CLAUDE_AIBOT_SESSION_ID: normalizeString18(aibotSessionID),
11096
- GRIX_CLAUDE_SESSION_ID: normalizeString18(claudeSessionID),
11222
+ CLAUDE_PLUGIN_DATA: normalizeString19(pluginDataDir),
11223
+ GRIX_CLAUDE_AIBOT_SESSION_ID: normalizeString19(aibotSessionID),
11224
+ GRIX_CLAUDE_SESSION_ID: normalizeString19(claudeSessionID),
11097
11225
  GRIX_CLAUDE_DAEMON_MODE: "1",
11098
- GRIX_CLAUDE_WORKER_ID: normalizeString18(workerID),
11099
- GRIX_CLAUDE_DAEMON_BRIDGE_URL: normalizeString18(bridgeURL),
11100
- GRIX_CLAUDE_DAEMON_BRIDGE_TOKEN: normalizeString18(bridgeToken)
11226
+ GRIX_CLAUDE_WORKER_ID: normalizeString19(workerID),
11227
+ GRIX_CLAUDE_DAEMON_BRIDGE_URL: normalizeString19(bridgeURL),
11228
+ GRIX_CLAUDE_DAEMON_BRIDGE_TOKEN: normalizeString19(bridgeToken)
11101
11229
  };
11102
11230
  if (connectionConfig) {
11103
- env.GRIX_CLAUDE_WS_URL = normalizeString18(connectionConfig.wsURL);
11104
- env.GRIX_CLAUDE_AGENT_ID = normalizeString18(connectionConfig.agentID);
11105
- env.GRIX_CLAUDE_API_KEY = normalizeString18(connectionConfig.apiKey);
11231
+ env.GRIX_CLAUDE_WS_URL = normalizeString19(connectionConfig.wsURL);
11232
+ env.GRIX_CLAUDE_AGENT_ID = normalizeString19(connectionConfig.agentID);
11233
+ env.GRIX_CLAUDE_API_KEY = normalizeString19(connectionConfig.apiKey);
11106
11234
  if (Number.isFinite(Number(connectionConfig.outboundTextChunkLimit))) {
11107
11235
  env.GRIX_CLAUDE_OUTBOUND_TEXT_CHUNK_LIMIT = String(
11108
11236
  Math.floor(Number(connectionConfig.outboundTextChunkLimit))
@@ -11117,8 +11245,8 @@ function buildWorkerClaudeArgs({
11117
11245
  claudeSessionID,
11118
11246
  resumeSession = false
11119
11247
  }) {
11120
- const normalizedPackageRoot = normalizeString18(packageRoot);
11121
- const normalizedClaudeSessionID = normalizeString18(claudeSessionID);
11248
+ const normalizedPackageRoot = normalizeString19(packageRoot);
11249
+ const normalizedClaudeSessionID = normalizeString19(claudeSessionID);
11122
11250
  if (!normalizedPackageRoot) {
11123
11251
  throw new Error("packageRoot is required");
11124
11252
  }
@@ -11153,10 +11281,10 @@ async function createVisibleClaudeLaunchScript({
11153
11281
  captureOutputInExpectLog = true
11154
11282
  }) {
11155
11283
  await mkdir10(logsDir, { recursive: true });
11156
- const normalizedWorkerID = normalizeString18(workerID) || randomUUID4();
11157
- const scriptPath = path20.join(logsDir, `${normalizedWorkerID}.launch.command`);
11158
- const expectPath = path20.join(logsDir, `${normalizedWorkerID}.launch.expect`);
11159
- const pidPath = path20.join(logsDir, `${normalizedWorkerID}.pid`);
11284
+ const normalizedWorkerID = normalizeString19(workerID) || randomUUID4();
11285
+ const scriptPath = path21.join(logsDir, `${normalizedWorkerID}.launch.command`);
11286
+ const expectPath = path21.join(logsDir, `${normalizedWorkerID}.launch.expect`);
11287
+ const pidPath = path21.join(logsDir, `${normalizedWorkerID}.pid`);
11160
11288
  const { stdoutLogPath } = resolveWorkerLogPaths({
11161
11289
  logsDir,
11162
11290
  workerID: normalizedWorkerID
@@ -11256,7 +11384,7 @@ async function launchClaudeInVisibleTerminal({
11256
11384
  env,
11257
11385
  spawnImpl
11258
11386
  }) {
11259
- if (process13.platform !== "darwin") {
11387
+ if (process14.platform !== "darwin") {
11260
11388
  throw new Error("show-claude currently only supports macOS Terminal");
11261
11389
  }
11262
11390
  const { scriptPath, pidPath } = await createVisibleClaudeLaunchScript({
@@ -11350,17 +11478,17 @@ async function launchClaudeInHiddenPty({
11350
11478
  };
11351
11479
  }
11352
11480
  function resolveWorkerPIDPath(logsDir, workerID) {
11353
- const normalizedWorkerID = normalizeString18(workerID) || randomUUID4();
11354
- return path20.join(logsDir, `${normalizedWorkerID}.pid`);
11481
+ const normalizedWorkerID = normalizeString19(workerID) || randomUUID4();
11482
+ return path21.join(logsDir, `${normalizedWorkerID}.pid`);
11355
11483
  }
11356
11484
  async function listManagedPIDFiles(logsDir) {
11357
- const normalizedLogsDir = normalizeString18(logsDir);
11485
+ const normalizedLogsDir = normalizeString19(logsDir);
11358
11486
  if (!normalizedLogsDir) {
11359
11487
  return [];
11360
11488
  }
11361
11489
  try {
11362
11490
  const entries = await readdir(normalizedLogsDir, { withFileTypes: true });
11363
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".pid")).map((entry) => path20.join(normalizedLogsDir, entry.name));
11491
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".pid")).map((entry) => path21.join(normalizedLogsDir, entry.name));
11364
11492
  } catch {
11365
11493
  return [];
11366
11494
  }
@@ -11383,6 +11511,7 @@ var init_worker_process = __esm({
11383
11511
  init_mcp();
11384
11512
  init_daemon_paths();
11385
11513
  init_hook_signal_store();
11514
+ init_claude_command();
11386
11515
  init_process_control();
11387
11516
  missingResumeSessionPattern = /No conversation found with session ID:/u;
11388
11517
  authLoginRequiredPatterns = [
@@ -11410,7 +11539,7 @@ var init_worker_process = __esm({
11410
11539
  startupMcpServerFailedMarkerPattern = /\[grix\]\s+startup_mcp_server_failed/u;
11411
11540
  WorkerProcessManager = class {
11412
11541
  constructor({
11413
- env = process13.env,
11542
+ env = process14.env,
11414
11543
  packageRoot = resolvePackageRoot(),
11415
11544
  connectionConfig = null,
11416
11545
  spawnImpl = spawn3,
@@ -11430,14 +11559,14 @@ var init_worker_process = __esm({
11430
11559
  this.spawnQueues = /* @__PURE__ */ new Map();
11431
11560
  }
11432
11561
  getWorkerRuntime(workerID) {
11433
- const runtime = this.runtimes.get(normalizeString18(workerID));
11562
+ const runtime = this.runtimes.get(normalizeString19(workerID));
11434
11563
  return runtime ? { ...runtime } : null;
11435
11564
  }
11436
11565
  markWorkerRuntimeStopped(workerID, {
11437
11566
  exitCode = 0,
11438
11567
  exitSignal = ""
11439
11568
  } = {}) {
11440
- const normalizedWorkerID = normalizeString18(workerID);
11569
+ const normalizedWorkerID = normalizeString19(workerID);
11441
11570
  if (!normalizedWorkerID) {
11442
11571
  return null;
11443
11572
  }
@@ -11449,7 +11578,7 @@ var init_worker_process = __esm({
11449
11578
  ...current,
11450
11579
  status: "stopped",
11451
11580
  exit_code: Number(exitCode ?? 0),
11452
- exit_signal: normalizeString18(exitSignal),
11581
+ exit_signal: normalizeString19(exitSignal),
11453
11582
  stopped_at: Date.now()
11454
11583
  };
11455
11584
  this.runtimes.set(normalizedWorkerID, next);
@@ -11460,7 +11589,7 @@ var init_worker_process = __esm({
11460
11589
  const serverEntryPath = resolveServerEntryPath(this.packageRoot);
11461
11590
  await this.ensureUserMcpServer({
11462
11591
  claudeCommand,
11463
- serverCommand: process13.execPath,
11592
+ serverCommand: process14.execPath,
11464
11593
  serverArgs: [serverEntryPath],
11465
11594
  env
11466
11595
  });
@@ -11471,7 +11600,7 @@ var init_worker_process = __esm({
11471
11600
  }
11472
11601
  async cleanupStaleManagedProcesses(aibotSessionIDs = []) {
11473
11602
  const normalizedSessionIDs = Array.from(new Set(
11474
- (Array.isArray(aibotSessionIDs) ? aibotSessionIDs : []).map((value) => normalizeString18(value)).filter((value) => value)
11603
+ (Array.isArray(aibotSessionIDs) ? aibotSessionIDs : []).map((value) => normalizeString19(value)).filter((value) => value)
11475
11604
  ));
11476
11605
  if (normalizedSessionIDs.length === 0) {
11477
11606
  return [];
@@ -11496,7 +11625,7 @@ var init_worker_process = __esm({
11496
11625
  if (!entry?.pid) {
11497
11626
  continue;
11498
11627
  }
11499
- await this.terminateProcessTree(entry.pid, { platform: process13.platform });
11628
+ await this.terminateProcessTree(entry.pid, { platform: process14.platform });
11500
11629
  terminatedPIDs.push(entry.pid);
11501
11630
  if (entry.pidPath) {
11502
11631
  await writeFile3(entry.pidPath, "", "utf8").catch(() => {
@@ -11511,7 +11640,7 @@ var init_worker_process = __esm({
11511
11640
  );
11512
11641
  const orphanPIDs = output.trim().split("\n").map(Number).filter((n2) => n2 > 0);
11513
11642
  for (const pid of orphanPIDs) {
11514
- await this.terminateProcessTree(pid, { platform: process13.platform });
11643
+ await this.terminateProcessTree(pid, { platform: process14.platform });
11515
11644
  terminatedPIDs.push(pid);
11516
11645
  }
11517
11646
  } catch {
@@ -11520,7 +11649,7 @@ var init_worker_process = __esm({
11520
11649
  return terminatedPIDs;
11521
11650
  }
11522
11651
  enqueueSpawnForSession(aibotSessionID, task) {
11523
- const normalizedSessionID = normalizeString18(aibotSessionID);
11652
+ const normalizedSessionID = normalizeString19(aibotSessionID);
11524
11653
  if (!normalizedSessionID || typeof task !== "function") {
11525
11654
  return Promise.resolve().then(task);
11526
11655
  }
@@ -11546,18 +11675,18 @@ var init_worker_process = __esm({
11546
11675
  bridgeToken = "",
11547
11676
  resumeSession = false
11548
11677
  }) {
11549
- const normalizedWorkerID = normalizeString18(workerID) || randomUUID4();
11550
- const normalizedSessionID = normalizeString18(aibotSessionID);
11551
- const normalizedCwd = normalizeString18(cwd);
11552
- const normalizedPluginDataDir = normalizeString18(pluginDataDir);
11553
- const normalizedClaudeSessionID = normalizeString18(claudeSessionID) || randomUUID4();
11678
+ const normalizedWorkerID = normalizeString19(workerID) || randomUUID4();
11679
+ const normalizedSessionID = normalizeString19(aibotSessionID);
11680
+ const normalizedCwd = normalizeString19(cwd);
11681
+ const normalizedPluginDataDir = normalizeString19(pluginDataDir);
11682
+ const normalizedClaudeSessionID = normalizeString19(claudeSessionID) || randomUUID4();
11554
11683
  if (!normalizedSessionID || !normalizedCwd || !normalizedPluginDataDir) {
11555
11684
  throw new Error("aibotSessionID, cwd, and pluginDataDir are required");
11556
11685
  }
11557
11686
  return this.enqueueSpawnForSession(normalizedSessionID, async () => {
11558
11687
  const logsDir = resolveWorkerLogsDir(normalizedSessionID, this.env);
11559
11688
  await mkdir10(logsDir, { recursive: true });
11560
- await new HookSignalStore(path20.join(normalizedPluginDataDir, "hook-signals.json")).reset();
11689
+ await new HookSignalStore(path21.join(normalizedPluginDataDir, "hook-signals.json")).reset();
11561
11690
  const workerEnv = buildWorkerEnvironment({
11562
11691
  baseEnv: this.env,
11563
11692
  pluginDataDir: normalizedPluginDataDir,
@@ -11584,8 +11713,8 @@ var init_worker_process = __esm({
11584
11713
  logsDir,
11585
11714
  workerID: normalizedWorkerID
11586
11715
  });
11587
- const stdoutHandle = await open2(stdoutLogPath, "w");
11588
- const stderrHandle = await open2(stderrLogPath, "w");
11716
+ const stdoutHandle = await open3(stdoutLogPath, "w");
11717
+ const stderrHandle = await open3(stderrLogPath, "w");
11589
11718
  let deferFDClose = false;
11590
11719
  try {
11591
11720
  await this.cleanupStaleManagedProcesses([normalizedSessionID]);
@@ -11604,8 +11733,8 @@ var init_worker_process = __esm({
11604
11733
  spawnImpl: this.spawnImpl
11605
11734
  });
11606
11735
  pid = Number(visibleTerminal.pid ?? 0);
11607
- pidPath = normalizeString18(visibleTerminal.pidPath);
11608
- } else if (process13.platform === "darwin") {
11736
+ pidPath = normalizeString19(visibleTerminal.pidPath);
11737
+ } else if (process14.platform === "darwin") {
11609
11738
  const hiddenPty = await launchClaudeInHiddenPty({
11610
11739
  logsDir,
11611
11740
  workerID: normalizedWorkerID,
@@ -11618,7 +11747,7 @@ var init_worker_process = __esm({
11618
11747
  stderrFD: stderrHandle.fd
11619
11748
  });
11620
11749
  pid = hiddenPty.pid;
11621
- pidPath = normalizeString18(hiddenPty.pidPath);
11750
+ pidPath = normalizeString19(hiddenPty.pidPath);
11622
11751
  if (hiddenPty.child) {
11623
11752
  child = hiddenPty.child;
11624
11753
  const exitWorkerID = normalizedWorkerID;
@@ -11674,7 +11803,7 @@ var init_worker_process = __esm({
11674
11803
  if (!Number.isFinite(pid) || pid <= 0) {
11675
11804
  throw new Error("failed to determine spawned Claude pid");
11676
11805
  }
11677
- const isHiddenPty = !visibleTerminal && process13.platform === "darwin";
11806
+ const isHiddenPty = !visibleTerminal && process14.platform === "darwin";
11678
11807
  deferFDClose = isHiddenPty;
11679
11808
  const runtime = {
11680
11809
  worker_id: normalizedWorkerID,
@@ -11710,7 +11839,7 @@ var init_worker_process = __esm({
11710
11839
  });
11711
11840
  }
11712
11841
  async stopWorker(workerID) {
11713
- const normalizedWorkerID = normalizeString18(workerID);
11842
+ const normalizedWorkerID = normalizeString19(workerID);
11714
11843
  const runtime = this.runtimes.get(normalizedWorkerID);
11715
11844
  if (!runtime) {
11716
11845
  return false;
@@ -11719,7 +11848,7 @@ var init_worker_process = __esm({
11719
11848
  let exitSignal = "SIGTERM";
11720
11849
  if (pid > 0) {
11721
11850
  const terminated = await this.terminateProcessTree(pid, {
11722
- platform: process13.platform,
11851
+ platform: process14.platform,
11723
11852
  signal: exitSignal
11724
11853
  });
11725
11854
  if (!terminated) {
@@ -11731,7 +11860,7 @@ var init_worker_process = __esm({
11731
11860
  if (!exited) {
11732
11861
  exitSignal = "SIGKILL";
11733
11862
  await this.terminateProcessTree(pid, {
11734
- platform: process13.platform,
11863
+ platform: process14.platform,
11735
11864
  signal: exitSignal
11736
11865
  });
11737
11866
  const forceExited = await this.waitForProcessExit(pid, {
@@ -11762,7 +11891,7 @@ var init_worker_process = __esm({
11762
11891
  logCursor = null,
11763
11892
  maxBytes = 0
11764
11893
  } = {}) {
11765
- const runtime = this.runtimes.get(normalizeString18(workerID));
11894
+ const runtime = this.runtimes.get(normalizeString19(workerID));
11766
11895
  if (!runtime) {
11767
11896
  return false;
11768
11897
  }
@@ -11782,7 +11911,7 @@ var init_worker_process = __esm({
11782
11911
  }
11783
11912
  ];
11784
11913
  for (const target of logTargets) {
11785
- const normalizedFilePath = normalizeString18(target.filePath);
11914
+ const normalizedFilePath = normalizeString19(target.filePath);
11786
11915
  if (!normalizedFilePath) {
11787
11916
  continue;
11788
11917
  }
@@ -11819,19 +11948,19 @@ var init_worker_process = __esm({
11819
11948
  });
11820
11949
  }
11821
11950
  async captureLogCursor(workerID) {
11822
- const runtime = this.runtimes.get(normalizeString18(workerID));
11951
+ const runtime = this.runtimes.get(normalizeString19(workerID));
11823
11952
  if (!runtime) {
11824
11953
  return null;
11825
11954
  }
11826
11955
  let stdoutOffset = 0;
11827
11956
  let stderrOffset = 0;
11828
11957
  try {
11829
- stdoutOffset = normalizeNonNegativeOffset((await stat(runtime.stdout_log_path)).size);
11958
+ stdoutOffset = normalizeNonNegativeOffset((await stat2(runtime.stdout_log_path)).size);
11830
11959
  } catch {
11831
11960
  stdoutOffset = 0;
11832
11961
  }
11833
11962
  try {
11834
- stderrOffset = normalizeNonNegativeOffset((await stat(runtime.stderr_log_path)).size);
11963
+ stderrOffset = normalizeNonNegativeOffset((await stat2(runtime.stderr_log_path)).size);
11835
11964
  } catch {
11836
11965
  stderrOffset = 0;
11837
11966
  }
@@ -15052,7 +15181,7 @@ var require_stream = __commonJS({
15052
15181
  };
15053
15182
  duplex2._final = function(callback) {
15054
15183
  if (ws.readyState === ws.CONNECTING) {
15055
- ws.once("open", function open3() {
15184
+ ws.once("open", function open4() {
15056
15185
  duplex2._final(callback);
15057
15186
  });
15058
15187
  return;
@@ -15073,7 +15202,7 @@ var require_stream = __commonJS({
15073
15202
  };
15074
15203
  duplex2._write = function(chunk, encoding, callback) {
15075
15204
  if (ws.readyState === ws.CONNECTING) {
15076
- ws.once("open", function open3() {
15205
+ ws.once("open", function open4() {
15077
15206
  duplex2._write(chunk, encoding, callback);
15078
15207
  });
15079
15208
  return;
@@ -15539,10 +15668,258 @@ var init_wrapper = __esm({
15539
15668
  }
15540
15669
  });
15541
15670
 
15671
+ // package.json
15672
+ var package_default;
15673
+ var init_package = __esm({
15674
+ "package.json"() {
15675
+ package_default = {
15676
+ name: "@dhf-claude/grix",
15677
+ version: "0.1.9",
15678
+ description: "Claude Code channel plugin for Aibot Grix",
15679
+ type: "module",
15680
+ repository: {
15681
+ type: "git",
15682
+ url: "git+https://github.com/askie/clawpool-claude.git"
15683
+ },
15684
+ bugs: {
15685
+ url: "https://github.com/askie/clawpool-claude/issues"
15686
+ },
15687
+ homepage: "https://github.com/askie/clawpool-claude#readme",
15688
+ publishConfig: {
15689
+ access: "public"
15690
+ },
15691
+ bin: {
15692
+ "grix-claude": "bin/grix-claude.js"
15693
+ },
15694
+ files: [
15695
+ "bin",
15696
+ "cli",
15697
+ "dist",
15698
+ "hooks",
15699
+ "scripts",
15700
+ "skills",
15701
+ ".claude-plugin",
15702
+ "start.sh"
15703
+ ],
15704
+ scripts: {
15705
+ prepublishOnly: "npm run build",
15706
+ clean: `node -e "const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true });"`,
15707
+ "build:worker": "esbuild server/main.js --bundle --platform=node --format=esm --target=node20 --outfile=dist/index.js",
15708
+ "build:daemon": `esbuild bin/grix-claude.js --bundle --platform=node --format=esm --target=node20 --banner:js="import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);" --outfile=dist/daemon.js`,
15709
+ build: "npm run clean && npm run build:worker && npm run build:daemon",
15710
+ dev: "node ./scripts/dev-start.js",
15711
+ "dev:build": "node ./scripts/dev-build.js",
15712
+ daemon: "node ./dist/daemon.js --show-claude",
15713
+ prod: "node ./scripts/prod-start.js",
15714
+ test: "node --test server/*.test.js cli/*.test.js",
15715
+ "test:daemon-sim": "node --test server/daemon-simulated-e2e.scenario.js"
15716
+ },
15717
+ dependencies: {
15718
+ "@modelcontextprotocol/sdk": "^1.18.0",
15719
+ execa: "^9.6.0",
15720
+ pidtree: "^0.6.0",
15721
+ ws: "^8.18.3",
15722
+ zod: "^4.3.6"
15723
+ },
15724
+ devDependencies: {
15725
+ esbuild: "^0.27.0"
15726
+ }
15727
+ };
15728
+ }
15729
+ });
15730
+
15731
+ // server/protocol-contract.js
15732
+ var contractVersion, protocolVersion, adapterHint, declaredCapabilities, localActionTypes, declaredLocalActions, agentInvokeActions, sessionControlVerbs, interactionKinds, interactionResolutionTypes, accessControlVerbs, resultDomains, bindingWorkerStatuses, sessionControlOutcomes, localActionResultStatuses, localActionErrorCodes, sessionControlErrorCodes, interactionReplyOutcomes, interactionReplyErrorCodes, eventResultStatuses, publicProtocolContract;
15733
+ var init_protocol_contract = __esm({
15734
+ "server/protocol-contract.js"() {
15735
+ contractVersion = 1;
15736
+ protocolVersion = "aibot-agent-api-v1";
15737
+ adapterHint = "claude/base";
15738
+ declaredCapabilities = Object.freeze([
15739
+ "session_route",
15740
+ "local_action_v1",
15741
+ "agent_invoke"
15742
+ ]);
15743
+ localActionTypes = Object.freeze({
15744
+ sessionControl: "claude_session_control",
15745
+ interactionReply: "claude_interaction_reply"
15746
+ });
15747
+ declaredLocalActions = Object.freeze([
15748
+ localActionTypes.sessionControl,
15749
+ localActionTypes.interactionReply
15750
+ ]);
15751
+ agentInvokeActions = Object.freeze({
15752
+ interactionRequestCreate: "claude_interaction_request_create",
15753
+ accessControl: "claude_access_control"
15754
+ });
15755
+ sessionControlVerbs = Object.freeze({
15756
+ open: "open",
15757
+ status: "status",
15758
+ where: "where",
15759
+ stop: "stop"
15760
+ });
15761
+ interactionKinds = Object.freeze({
15762
+ permission: "permission",
15763
+ elicitation: "elicitation"
15764
+ });
15765
+ interactionResolutionTypes = Object.freeze({
15766
+ decision: "decision",
15767
+ action: "action",
15768
+ text: "text",
15769
+ map: "map"
15770
+ });
15771
+ accessControlVerbs = Object.freeze({
15772
+ statusRead: "status_read",
15773
+ pairApprove: "pair_approve",
15774
+ pairDeny: "pair_deny",
15775
+ senderAllow: "sender_allow",
15776
+ senderRemove: "sender_remove",
15777
+ policySet: "policy_set"
15778
+ });
15779
+ resultDomains = Object.freeze({
15780
+ sessionControl: "session_control",
15781
+ interactionReply: "interaction_reply"
15782
+ });
15783
+ bindingWorkerStatuses = Object.freeze({
15784
+ starting: "starting",
15785
+ connected: "connected",
15786
+ ready: "ready",
15787
+ stopped: "stopped",
15788
+ failed: "failed"
15789
+ });
15790
+ sessionControlOutcomes = Object.freeze({
15791
+ opened: "opened",
15792
+ alreadyBound: "already_bound",
15793
+ status: "status",
15794
+ where: "where",
15795
+ stopped: "stopped"
15796
+ });
15797
+ localActionResultStatuses = Object.freeze({
15798
+ ok: "ok",
15799
+ failed: "failed"
15800
+ });
15801
+ localActionErrorCodes = Object.freeze({
15802
+ unsupportedLocalAction: "unsupported_local_action",
15803
+ localActionRouteMissing: "local_action_route_missing"
15804
+ });
15805
+ sessionControlErrorCodes = Object.freeze({
15806
+ cwdRequired: "session_cwd_required",
15807
+ invalidCwd: "session_invalid_cwd",
15808
+ bindingMissing: "session_binding_missing",
15809
+ rebindForbidden: "session_rebind_forbidden",
15810
+ verbInvalid: "session_verb_invalid",
15811
+ runtimeError: "session_runtime_error"
15812
+ });
15813
+ interactionReplyOutcomes = Object.freeze({
15814
+ resolved: "resolved"
15815
+ });
15816
+ interactionReplyErrorCodes = Object.freeze({
15817
+ requestIDRequired: "interaction_request_id_required",
15818
+ requestNotFound: "interaction_request_not_found",
15819
+ requestNotPending: "interaction_request_not_pending",
15820
+ resolutionInvalid: "interaction_resolution_invalid",
15821
+ forwardFailed: "interaction_forward_failed"
15822
+ });
15823
+ eventResultStatuses = Object.freeze({
15824
+ responded: "responded",
15825
+ failed: "failed",
15826
+ canceled: "canceled"
15827
+ });
15828
+ publicProtocolContract = Object.freeze({
15829
+ contract_version: contractVersion,
15830
+ protocol_version: protocolVersion,
15831
+ adapter_hint: adapterHint,
15832
+ capabilities: [...declaredCapabilities],
15833
+ local_actions: [...declaredLocalActions],
15834
+ agent_invoke_actions: [
15835
+ agentInvokeActions.interactionRequestCreate,
15836
+ agentInvokeActions.accessControl
15837
+ ],
15838
+ local_action_types: [
15839
+ localActionTypes.sessionControl,
15840
+ localActionTypes.interactionReply
15841
+ ],
15842
+ session_control_verbs: [
15843
+ sessionControlVerbs.open,
15844
+ sessionControlVerbs.status,
15845
+ sessionControlVerbs.where,
15846
+ sessionControlVerbs.stop
15847
+ ],
15848
+ interaction_kinds: [
15849
+ interactionKinds.permission,
15850
+ interactionKinds.elicitation
15851
+ ],
15852
+ interaction_resolution_types: [
15853
+ interactionResolutionTypes.decision,
15854
+ interactionResolutionTypes.action,
15855
+ interactionResolutionTypes.text,
15856
+ interactionResolutionTypes.map
15857
+ ],
15858
+ access_control_verbs: [
15859
+ accessControlVerbs.statusRead,
15860
+ accessControlVerbs.pairApprove,
15861
+ accessControlVerbs.pairDeny,
15862
+ accessControlVerbs.senderAllow,
15863
+ accessControlVerbs.senderRemove,
15864
+ accessControlVerbs.policySet
15865
+ ],
15866
+ result_domains: [
15867
+ resultDomains.sessionControl,
15868
+ resultDomains.interactionReply
15869
+ ],
15870
+ binding_worker_statuses: [
15871
+ bindingWorkerStatuses.starting,
15872
+ bindingWorkerStatuses.connected,
15873
+ bindingWorkerStatuses.ready,
15874
+ bindingWorkerStatuses.stopped,
15875
+ bindingWorkerStatuses.failed
15876
+ ],
15877
+ session_control_outcomes: [
15878
+ sessionControlOutcomes.opened,
15879
+ sessionControlOutcomes.alreadyBound,
15880
+ sessionControlOutcomes.status,
15881
+ sessionControlOutcomes.where,
15882
+ sessionControlOutcomes.stopped
15883
+ ],
15884
+ local_action_result_statuses: [
15885
+ localActionResultStatuses.ok,
15886
+ localActionResultStatuses.failed
15887
+ ],
15888
+ local_action_error_codes: [
15889
+ localActionErrorCodes.unsupportedLocalAction,
15890
+ localActionErrorCodes.localActionRouteMissing
15891
+ ],
15892
+ session_control_error_codes: [
15893
+ sessionControlErrorCodes.cwdRequired,
15894
+ sessionControlErrorCodes.invalidCwd,
15895
+ sessionControlErrorCodes.bindingMissing,
15896
+ sessionControlErrorCodes.rebindForbidden,
15897
+ sessionControlErrorCodes.verbInvalid,
15898
+ sessionControlErrorCodes.runtimeError
15899
+ ],
15900
+ interaction_reply_outcomes: [
15901
+ interactionReplyOutcomes.resolved
15902
+ ],
15903
+ interaction_reply_error_codes: [
15904
+ interactionReplyErrorCodes.requestIDRequired,
15905
+ interactionReplyErrorCodes.requestNotFound,
15906
+ interactionReplyErrorCodes.requestNotPending,
15907
+ interactionReplyErrorCodes.resolutionInvalid,
15908
+ interactionReplyErrorCodes.forwardFailed
15909
+ ],
15910
+ event_result_statuses: [
15911
+ eventResultStatuses.responded,
15912
+ eventResultStatuses.failed,
15913
+ eventResultStatuses.canceled
15914
+ ]
15915
+ });
15916
+ }
15917
+ });
15918
+
15542
15919
  // server/aibot-client.js
15543
15920
  import { randomUUID as randomUUID5 } from "node:crypto";
15544
15921
  import { appendFileSync as appendFileSync3 } from "node:fs";
15545
- function normalizeString19(value) {
15922
+ function normalizeString20(value) {
15546
15923
  return String(value ?? "").trim();
15547
15924
  }
15548
15925
  function logDebug(message) {
@@ -15557,23 +15934,33 @@ function logDebug(message) {
15557
15934
  function buildSendNackError(packet) {
15558
15935
  const payload = packet?.payload ?? {};
15559
15936
  const code = Number(payload.code ?? 5001);
15560
- const msg = normalizeString19(payload.msg) || packet?.cmd || "unknown error";
15937
+ const msg = normalizeString20(payload.msg) || packet?.cmd || "unknown error";
15561
15938
  const error = new Error(`aibot ${packet?.cmd ?? "packet"} error ${code}: ${msg}`);
15562
15939
  error.code = code;
15563
15940
  return error;
15564
15941
  }
15565
15942
  function withOptionalString(target, key, value) {
15566
- const normalized = normalizeString19(value);
15943
+ const normalized = normalizeString20(value);
15567
15944
  if (normalized) {
15568
15945
  target[key] = normalized;
15569
15946
  }
15570
15947
  }
15571
15948
  function buildAuthPayload(config) {
15949
+ const clientVersion = normalizeString20(config?.clientVersion) || pluginVersion;
15950
+ const hostVersion = normalizeString20(config?.hostVersion) || clientVersion;
15572
15951
  return {
15573
15952
  agent_id: config.agentID,
15574
15953
  api_key: config.apiKey,
15575
15954
  client: "claude-grix-claude-channel",
15576
- client_type: "claude"
15955
+ client_type: "claude",
15956
+ contract_version: contractVersion,
15957
+ client_version: clientVersion,
15958
+ host_type: "claude",
15959
+ host_version: hostVersion,
15960
+ protocol_version: protocolVersion,
15961
+ capabilities: [...declaredCapabilities],
15962
+ local_actions: [...declaredLocalActions],
15963
+ adapter_hint: adapterHint
15577
15964
  };
15578
15965
  }
15579
15966
  function buildSessionActivityPayload({
@@ -15585,8 +15972,8 @@ function buildSessionActivityPayload({
15585
15972
  refEventID = ""
15586
15973
  }) {
15587
15974
  const payload = {
15588
- session_id: normalizeString19(sessionID),
15589
- kind: normalizeString19(kind),
15975
+ session_id: normalizeString20(sessionID),
15976
+ kind: normalizeString20(kind),
15590
15977
  active: active === true
15591
15978
  };
15592
15979
  if (Number.isFinite(Number(ttlMs)) && Number(ttlMs) > 0) {
@@ -15596,17 +15983,21 @@ function buildSessionActivityPayload({
15596
15983
  withOptionalString(payload, "ref_event_id", refEventID);
15597
15984
  return payload;
15598
15985
  }
15599
- var verboseDebugEnabled, verboseDebugLogPath, AibotClient;
15986
+ var verboseDebugEnabled, verboseDebugLogPath, pluginVersion, AibotClient;
15600
15987
  var init_aibot_client = __esm({
15601
15988
  "server/aibot-client.js"() {
15602
15989
  init_wrapper();
15990
+ init_package();
15991
+ init_protocol_contract();
15603
15992
  verboseDebugEnabled = process.env.GRIX_CLAUDE_E2E_DEBUG === "1";
15604
- verboseDebugLogPath = normalizeString19(process.env.GRIX_CLAUDE_E2E_DEBUG_LOG);
15993
+ verboseDebugLogPath = normalizeString20(process.env.GRIX_CLAUDE_E2E_DEBUG_LOG);
15994
+ pluginVersion = normalizeString20(package_default?.version) || "0.1.0";
15605
15995
  AibotClient = class {
15606
- constructor({ onEventMessage, onEventStop, onEventRevoke, onStatus } = {}) {
15996
+ constructor({ onEventMessage, onEventStop, onEventRevoke, onLocalAction, onStatus } = {}) {
15607
15997
  this.onEventMessage = onEventMessage;
15608
15998
  this.onEventStop = onEventStop;
15609
15999
  this.onEventRevoke = onEventRevoke;
16000
+ this.onLocalAction = onLocalAction;
15610
16001
  this.onStatus = onStatus;
15611
16002
  this.desired = false;
15612
16003
  this.config = null;
@@ -15736,10 +16127,10 @@ var init_aibot_client = __esm({
15736
16127
  expected: ["auth_ack"],
15737
16128
  timeoutMs: 1e4
15738
16129
  });
15739
- logDebug(`auth response code=${Number(auth?.payload?.code ?? 0)} msg=${normalizeString19(auth?.payload?.msg)}`);
16130
+ logDebug(`auth response code=${Number(auth?.payload?.code ?? 0)} msg=${normalizeString20(auth?.payload?.msg)}`);
15740
16131
  const code = Number(auth?.payload?.code ?? 0);
15741
16132
  if (code !== 0) {
15742
- throw new Error(normalizeString19(auth?.payload?.msg) || `auth failed code=${code}`);
16133
+ throw new Error(normalizeString20(auth?.payload?.msg) || `auth failed code=${code}`);
15743
16134
  }
15744
16135
  this.setStatus({
15745
16136
  connecting: false,
@@ -15847,7 +16238,7 @@ var init_aibot_client = __esm({
15847
16238
  }
15848
16239
  async handleMessage(text) {
15849
16240
  const packet = JSON.parse(text);
15850
- const cmd = normalizeString19(packet.cmd);
16241
+ const cmd = normalizeString20(packet.cmd);
15851
16242
  const seq = Number(packet.seq ?? 0);
15852
16243
  logDebug(`recv cmd=${cmd} seq=${seq}`);
15853
16244
  if (cmd === "ping") {
@@ -15871,6 +16262,10 @@ var init_aibot_client = __esm({
15871
16262
  }
15872
16263
  if (cmd === "event_revoke" && this.onEventRevoke) {
15873
16264
  await this.onEventRevoke(packet.payload ?? {});
16265
+ return;
16266
+ }
16267
+ if (cmd === "local_action" && this.onLocalAction) {
16268
+ await this.onLocalAction(packet.payload ?? {});
15874
16269
  }
15875
16270
  }
15876
16271
  setStatus(patch) {
@@ -15940,7 +16335,7 @@ var init_aibot_client = __esm({
15940
16335
  }
15941
16336
  ackEvent(eventID, { sessionID, msgID, receivedAt = Date.now() } = {}) {
15942
16337
  const payload = {
15943
- event_id: normalizeString19(eventID),
16338
+ event_id: normalizeString20(eventID),
15944
16339
  received_at: Math.floor(receivedAt)
15945
16340
  };
15946
16341
  withOptionalString(payload, "session_id", sessionID);
@@ -15949,8 +16344,8 @@ var init_aibot_client = __esm({
15949
16344
  }
15950
16345
  sendEventResult({ event_id, status, code = "", msg = "", updated_at = Date.now() }) {
15951
16346
  const payload = {
15952
- event_id: normalizeString19(event_id),
15953
- status: normalizeString19(status),
16347
+ event_id: normalizeString20(event_id),
16348
+ status: normalizeString20(status),
15954
16349
  updated_at: Math.floor(updated_at)
15955
16350
  };
15956
16351
  withOptionalString(payload, "code", code);
@@ -15959,7 +16354,7 @@ var init_aibot_client = __esm({
15959
16354
  }
15960
16355
  sendEventStopAck({ event_id, stop_id = "", accepted, updated_at = Date.now() }) {
15961
16356
  const payload = {
15962
- event_id: normalizeString19(event_id),
16357
+ event_id: normalizeString20(event_id),
15963
16358
  accepted: accepted === true,
15964
16359
  updated_at: Math.floor(updated_at)
15965
16360
  };
@@ -15975,8 +16370,8 @@ var init_aibot_client = __esm({
15975
16370
  updated_at = Date.now()
15976
16371
  }) {
15977
16372
  const payload = {
15978
- event_id: normalizeString19(event_id),
15979
- status: normalizeString19(status),
16373
+ event_id: normalizeString20(event_id),
16374
+ status: normalizeString20(status),
15980
16375
  updated_at: Math.floor(updated_at)
15981
16376
  };
15982
16377
  withOptionalString(payload, "stop_id", stop_id);
@@ -16013,8 +16408,8 @@ var init_aibot_client = __esm({
16013
16408
  extra = {}
16014
16409
  }) {
16015
16410
  const payload = {
16016
- session_id: normalizeString19(sessionID),
16017
- client_msg_id: normalizeString19(clientMsgID),
16411
+ session_id: normalizeString20(sessionID),
16412
+ client_msg_id: normalizeString20(clientMsgID),
16018
16413
  msg_type: 1,
16019
16414
  content: String(text ?? ""),
16020
16415
  extra
@@ -16040,11 +16435,11 @@ var init_aibot_client = __esm({
16040
16435
  extra = {}
16041
16436
  }) {
16042
16437
  const payload = {
16043
- session_id: normalizeString19(sessionID),
16044
- client_msg_id: normalizeString19(clientMsgID),
16438
+ session_id: normalizeString20(sessionID),
16439
+ client_msg_id: normalizeString20(clientMsgID),
16045
16440
  msg_type: 2,
16046
- content: normalizeString19(caption) || "[attachment]",
16047
- media_url: normalizeString19(mediaURL),
16441
+ content: normalizeString20(caption) || "[attachment]",
16442
+ media_url: normalizeString20(mediaURL),
16048
16443
  extra
16049
16444
  };
16050
16445
  withOptionalString(payload, "event_id", eventID);
@@ -16058,9 +16453,69 @@ var init_aibot_client = __esm({
16058
16453
  }
16059
16454
  return packet.payload ?? {};
16060
16455
  }
16456
+ async sendAgentInvoke({
16457
+ invokeID = randomUUID5(),
16458
+ action,
16459
+ params = {},
16460
+ timeoutMs = 15e3
16461
+ } = {}) {
16462
+ const normalizedAction = normalizeString20(action);
16463
+ if (!normalizedAction) {
16464
+ throw new Error("sendAgentInvoke requires action");
16465
+ }
16466
+ const normalizedTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 15e3;
16467
+ const packet = await this.request("agent_invoke", {
16468
+ invoke_id: normalizeString20(invokeID) || randomUUID5(),
16469
+ action: normalizedAction,
16470
+ params: params && typeof params === "object" && !Array.isArray(params) ? params : {},
16471
+ timeout_ms: normalizedTimeoutMs
16472
+ }, {
16473
+ expected: ["agent_invoke_result", "error"],
16474
+ timeoutMs: normalizedTimeoutMs + 1e3
16475
+ });
16476
+ if (packet.cmd !== "agent_invoke_result") {
16477
+ throw buildSendNackError(packet);
16478
+ }
16479
+ return packet.payload ?? {};
16480
+ }
16481
+ async sendLocalActionResult({
16482
+ actionID,
16483
+ status,
16484
+ result = void 0,
16485
+ errorCode = "",
16486
+ errorMsg = "",
16487
+ timeoutMs = 15e3
16488
+ } = {}) {
16489
+ const normalizedActionID = normalizeString20(actionID);
16490
+ if (!normalizedActionID) {
16491
+ throw new Error("sendLocalActionResult requires actionID");
16492
+ }
16493
+ const normalizedStatus = normalizeString20(status);
16494
+ if (!normalizedStatus) {
16495
+ throw new Error("sendLocalActionResult requires status");
16496
+ }
16497
+ const normalizedTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 15e3;
16498
+ const payload = {
16499
+ action_id: normalizedActionID,
16500
+ status: normalizedStatus
16501
+ };
16502
+ if (arguments[0] && Object.prototype.hasOwnProperty.call(arguments[0], "result")) {
16503
+ payload.result = result;
16504
+ }
16505
+ withOptionalString(payload, "error_code", errorCode);
16506
+ withOptionalString(payload, "error_msg", errorMsg);
16507
+ const packet = await this.request("local_action_result", payload, {
16508
+ expected: ["local_action_ack", "error"],
16509
+ timeoutMs: normalizedTimeoutMs
16510
+ });
16511
+ if (packet.cmd !== "local_action_ack") {
16512
+ throw buildSendNackError(packet);
16513
+ }
16514
+ return packet.payload ?? {};
16515
+ }
16061
16516
  async deleteMessage(sessionID, messageID, { timeoutMs = 2e4 } = {}) {
16062
- const normalizedSessionID = normalizeString19(sessionID);
16063
- const normalizedMessageID = normalizeString19(messageID);
16517
+ const normalizedSessionID = normalizeString20(sessionID);
16518
+ const normalizedMessageID = normalizeString20(messageID);
16064
16519
  if (!normalizedSessionID) {
16065
16520
  throw new Error("deleteMessage requires sessionID");
16066
16521
  }
@@ -16083,74 +16538,113 @@ var init_aibot_client = __esm({
16083
16538
  }
16084
16539
  });
16085
16540
 
16086
- // server/daemon/control-command.js
16087
- import path21 from "node:path";
16088
- function normalizeString20(value) {
16541
+ // server/grix-card-link.js
16542
+ function normalizeString21(value) {
16089
16543
  return String(value ?? "").trim();
16090
16544
  }
16091
- function normalizeTokens(text) {
16092
- return normalizeString20(text).split(/\s+/).filter(Boolean);
16545
+ function hasComplexPayload(payload) {
16546
+ return Object.values(payload ?? {}).some((value) => Array.isArray(value) || value && typeof value === "object");
16093
16547
  }
16094
- function parseControlCommand(text) {
16095
- const normalizedText = normalizeString20(text);
16096
- if (!normalizedText) {
16097
- return { matched: false, command: "", args: {}, error: "" };
16098
- }
16099
- const tokens = normalizeTokens(normalizedText);
16100
- if (tokens.length === 0) {
16101
- return { matched: false, command: "", args: {}, error: "" };
16548
+ function appendFlatPayload(params, payload) {
16549
+ for (const [rawKey, value] of Object.entries(payload ?? {})) {
16550
+ const key = normalizeString21(rawKey);
16551
+ if (!key || value == null) {
16552
+ continue;
16553
+ }
16554
+ if (typeof value === "string") {
16555
+ if (!value) {
16556
+ continue;
16557
+ }
16558
+ params.set(key, value);
16559
+ continue;
16560
+ }
16561
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
16562
+ params.set(key, String(value));
16563
+ }
16102
16564
  }
16103
- let startIndex = 0;
16104
- if (tokens[0] === "/grix" || tokens[0] === "grix") {
16105
- startIndex = 1;
16565
+ }
16566
+ function buildGrixCardURI(cardType, payload = {}) {
16567
+ const normalizedType = normalizeString21(cardType);
16568
+ if (!normalizedType) {
16569
+ throw new Error("cardType is required");
16106
16570
  }
16107
- const command = normalizeString20(tokens[startIndex]).toLowerCase();
16108
- if (!command) {
16109
- return { matched: false, command: "", args: {}, error: "" };
16571
+ const params = new URLSearchParams();
16572
+ if (hasComplexPayload(payload)) {
16573
+ params.set("d", JSON.stringify(payload));
16574
+ } else {
16575
+ appendFlatPayload(params, payload);
16110
16576
  }
16111
- if (command === "open") {
16112
- const cwd = normalizeString20(tokens.slice(startIndex + 1).join(" "));
16113
- if (!cwd) {
16114
- return { matched: true, ok: false, command, args: {}, error: "open \u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002" };
16115
- }
16116
- return {
16117
- matched: true,
16118
- ok: true,
16119
- command,
16120
- args: {
16121
- cwd: path21.resolve(cwd)
16122
- },
16123
- error: ""
16124
- };
16577
+ const query = params.toString();
16578
+ return `grix://card/${encodeURIComponent(normalizedType)}${query ? `?${query}` : ""}`;
16579
+ }
16580
+ function buildGrixCardLink({
16581
+ fallbackText,
16582
+ cardType,
16583
+ payload = {}
16584
+ }) {
16585
+ const normalizedFallbackText = normalizeString21(fallbackText);
16586
+ if (!normalizedFallbackText) {
16587
+ throw new Error("fallbackText is required");
16125
16588
  }
16126
- if (command === "status" || command === "stop" || command === "where") {
16127
- return {
16128
- matched: true,
16129
- ok: true,
16130
- command,
16131
- args: {},
16132
- error: ""
16133
- };
16589
+ return `[${normalizedFallbackText}](${buildGrixCardURI(cardType, payload)})`;
16590
+ }
16591
+ var init_grix_card_link = __esm({
16592
+ "server/grix-card-link.js"() {
16134
16593
  }
16135
- return { matched: false, command: "", args: {}, error: "" };
16594
+ });
16595
+
16596
+ // server/agent-open-session-card.js
16597
+ function normalizeString22(value) {
16598
+ return String(value ?? "").trim();
16599
+ }
16600
+ function buildAgentOpenSessionCardLink({
16601
+ fallbackText = "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55",
16602
+ summaryText = "",
16603
+ detailText = "",
16604
+ initialCwd = "",
16605
+ submittedPath = ""
16606
+ } = {}) {
16607
+ const payload = {};
16608
+ const normalizedSummaryText = normalizeString22(summaryText);
16609
+ const normalizedDetailText = normalizeString22(detailText);
16610
+ const normalizedInitialCwd = normalizeString22(initialCwd);
16611
+ const normalizedSubmittedPath = normalizeString22(submittedPath);
16612
+ if (normalizedSummaryText) {
16613
+ payload.summary_text = normalizedSummaryText;
16614
+ }
16615
+ if (normalizedDetailText) {
16616
+ payload.detail_text = normalizedDetailText;
16617
+ }
16618
+ if (normalizedInitialCwd) {
16619
+ payload.initial_cwd = normalizedInitialCwd;
16620
+ }
16621
+ if (normalizedSubmittedPath) {
16622
+ payload.submitted_path = normalizedSubmittedPath;
16623
+ }
16624
+ return buildGrixCardLink({
16625
+ fallbackText: normalizeString22(fallbackText) || "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55",
16626
+ cardType: "agent_open_session",
16627
+ payload
16628
+ });
16136
16629
  }
16137
- var init_control_command = __esm({
16138
- "server/daemon/control-command.js"() {
16630
+ var init_agent_open_session_card = __esm({
16631
+ "server/agent-open-session-card.js"() {
16632
+ init_grix_card_link();
16139
16633
  }
16140
16634
  });
16141
16635
 
16142
16636
  // server/inbound-event-meta.js
16143
- function normalizeString21(value) {
16637
+ function normalizeString23(value) {
16144
16638
  return String(value ?? "").trim();
16145
16639
  }
16146
16640
  function normalizeOptionalString(value) {
16147
- return normalizeString21(value) || "";
16641
+ return normalizeString23(value) || "";
16148
16642
  }
16149
16643
  function normalizeStringArray(value) {
16150
16644
  if (!Array.isArray(value)) {
16151
16645
  return [];
16152
16646
  }
16153
- return value.map((item) => normalizeString21(item)).filter((item) => item);
16647
+ return value.map((item) => normalizeString23(item)).filter((item) => item);
16154
16648
  }
16155
16649
  function normalizeJSONObject(value) {
16156
16650
  if (!value) {
@@ -16206,6 +16700,43 @@ function normalizeAttachmentRecord(value) {
16206
16700
  }
16207
16701
  return attachment;
16208
16702
  }
16703
+ function normalizeContextMessageRecord(value) {
16704
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
16705
+ return null;
16706
+ }
16707
+ const normalized = {
16708
+ msg_id: normalizeOptionalString(value.msg_id),
16709
+ sender_id: normalizeOptionalString(value.sender_id),
16710
+ sender_type: Number(value.sender_type ?? 0),
16711
+ msg_type: Number(value.msg_type ?? 0),
16712
+ content: String(value.content ?? ""),
16713
+ quoted_message_id: normalizeOptionalString(value.quoted_message_id),
16714
+ mention_user_ids: normalizeStringArray(value.mention_user_ids),
16715
+ created_at: Number(value.created_at ?? 0)
16716
+ };
16717
+ if (!normalized.msg_id) {
16718
+ return null;
16719
+ }
16720
+ return normalized;
16721
+ }
16722
+ function normalizeContextMessageArray(value) {
16723
+ if (Array.isArray(value)) {
16724
+ return value.map((item) => normalizeContextMessageRecord(item)).filter(Boolean);
16725
+ }
16726
+ if (typeof value === "string") {
16727
+ const trimmed = value.trim();
16728
+ if (!trimmed) {
16729
+ return [];
16730
+ }
16731
+ try {
16732
+ const parsed = JSON.parse(trimmed);
16733
+ return normalizeContextMessageArray(parsed);
16734
+ } catch {
16735
+ return [];
16736
+ }
16737
+ }
16738
+ return [];
16739
+ }
16209
16740
  function deriveAttachments(payload, extra) {
16210
16741
  const explicit = normalizeJSONArray(payload.attachments).map((item) => normalizeAttachmentRecord(item)).filter(Boolean);
16211
16742
  if (explicit.length > 0) {
@@ -16235,19 +16766,25 @@ function stringifyJSON(value) {
16235
16766
  }
16236
16767
  return JSON.stringify(value);
16237
16768
  }
16769
+ function deriveContextMessages(payload) {
16770
+ const currentMsgID = normalizeString23(payload.msg_id);
16771
+ return normalizeContextMessageArray(payload.context_messages).filter((entry) => entry.msg_id !== currentMsgID);
16772
+ }
16238
16773
  function normalizeInboundEventPayload(rawPayload) {
16239
16774
  const extra = normalizeJSONObject(rawPayload.extra);
16240
16775
  const attachments = deriveAttachments(rawPayload, extra);
16241
16776
  const bizCard = normalizeJSONObject(rawPayload.biz_card) ?? normalizeJSONObject(extra?.biz_card);
16242
16777
  const channelData = normalizeJSONObject(rawPayload.channel_data) ?? normalizeJSONObject(extra?.channel_data);
16778
+ const contextMessages = deriveContextMessages(rawPayload);
16243
16779
  return {
16244
- event_id: normalizeString21(rawPayload.event_id),
16245
- event_type: normalizeString21(rawPayload.event_type),
16246
- session_id: normalizeString21(rawPayload.session_id),
16780
+ event_id: normalizeString23(rawPayload.event_id),
16781
+ event_type: normalizeString23(rawPayload.event_type),
16782
+ mirror_mode: normalizeString23(rawPayload.mirror_mode),
16783
+ session_id: normalizeString23(rawPayload.session_id),
16247
16784
  session_type: normalizeOptionalString(rawPayload.session_type),
16248
- msg_id: normalizeString21(rawPayload.msg_id),
16785
+ msg_id: normalizeString23(rawPayload.msg_id),
16249
16786
  quoted_message_id: normalizeOptionalString(rawPayload.quoted_message_id),
16250
- sender_id: normalizeString21(rawPayload.sender_id),
16787
+ sender_id: normalizeString23(rawPayload.sender_id),
16251
16788
  owner_id: normalizeOptionalString(rawPayload.owner_id),
16252
16789
  agent_id: normalizeOptionalString(rawPayload.agent_id),
16253
16790
  msg_type: normalizeOptionalString(rawPayload.msg_type),
@@ -16258,7 +16795,8 @@ function normalizeInboundEventPayload(rawPayload) {
16258
16795
  attachments_json: stringifyJSON(attachments),
16259
16796
  attachment_count: attachments.length > 0 ? String(attachments.length) : "",
16260
16797
  biz_card_json: stringifyJSON(bizCard),
16261
- channel_data_json: stringifyJSON(channelData)
16798
+ channel_data_json: stringifyJSON(channelData),
16799
+ context_messages_json: stringifyJSON(contextMessages)
16262
16800
  };
16263
16801
  }
16264
16802
  var init_inbound_event_meta = __esm({
@@ -16267,7 +16805,7 @@ var init_inbound_event_meta = __esm({
16267
16805
  });
16268
16806
 
16269
16807
  // server/daemon/worker-control-client.js
16270
- function normalizeString22(value) {
16808
+ function normalizeString24(value) {
16271
16809
  return String(value ?? "").trim();
16272
16810
  }
16273
16811
  async function parseJSONResponse(response) {
@@ -16282,8 +16820,8 @@ var init_worker_control_client = __esm({
16282
16820
  "server/daemon/worker-control-client.js"() {
16283
16821
  WorkerControlClient = class {
16284
16822
  constructor({ controlURL, token, fetchImpl = globalThis.fetch, pingTimeoutMs = 5e3, deliverTimeoutMs = 1e4 } = {}) {
16285
- this.controlURL = normalizeString22(controlURL).replace(/\/+$/u, "");
16286
- this.token = normalizeString22(token);
16823
+ this.controlURL = normalizeString24(controlURL).replace(/\/+$/u, "");
16824
+ this.token = normalizeString24(token);
16287
16825
  this.fetchImpl = fetchImpl;
16288
16826
  this.pingTimeoutMs = pingTimeoutMs;
16289
16827
  this.deliverTimeoutMs = deliverTimeoutMs;
@@ -16291,135 +16829,52 @@ var init_worker_control_client = __esm({
16291
16829
  isConfigured() {
16292
16830
  return Boolean(this.controlURL && this.token && typeof this.fetchImpl === "function");
16293
16831
  }
16294
- async deliverEvent(rawPayload) {
16832
+ async post(pathname, payload, timeoutMs) {
16295
16833
  if (!this.isConfigured()) {
16296
16834
  throw new Error("worker control is not configured");
16297
16835
  }
16298
- const response = await this.fetchImpl(`${this.controlURL}/v1/worker/deliver-event`, {
16836
+ const response = await this.fetchImpl(`${this.controlURL}${pathname}`, {
16299
16837
  method: "POST",
16300
16838
  headers: {
16301
16839
  "content-type": "application/json",
16302
16840
  authorization: `Bearer ${this.token}`
16303
16841
  },
16304
- body: JSON.stringify({ payload: rawPayload }),
16305
- signal: AbortSignal.timeout(this.deliverTimeoutMs)
16842
+ body: JSON.stringify(payload),
16843
+ signal: AbortSignal.timeout(timeoutMs)
16306
16844
  });
16307
16845
  const json = await parseJSONResponse(response);
16308
16846
  if (!response.ok) {
16309
- throw new Error(normalizeString22(json.error) || `worker control failed ${response.status}`);
16847
+ throw new Error(normalizeString24(json.error) || `worker control failed ${response.status}`);
16310
16848
  }
16311
16849
  return json;
16312
16850
  }
16851
+ async deliverEvent(rawPayload) {
16852
+ return this.post("/v1/worker/deliver-event", { payload: rawPayload }, this.deliverTimeoutMs);
16853
+ }
16313
16854
  async deliverStop(rawPayload) {
16314
- if (!this.isConfigured()) {
16315
- throw new Error("worker control is not configured");
16316
- }
16317
- const response = await this.fetchImpl(`${this.controlURL}/v1/worker/deliver-stop`, {
16318
- method: "POST",
16319
- headers: {
16320
- "content-type": "application/json",
16321
- authorization: `Bearer ${this.token}`
16322
- },
16323
- body: JSON.stringify({ payload: rawPayload }),
16324
- signal: AbortSignal.timeout(this.deliverTimeoutMs)
16325
- });
16326
- const json = await parseJSONResponse(response);
16327
- if (!response.ok) {
16328
- throw new Error(normalizeString22(json.error) || `worker control failed ${response.status}`);
16329
- }
16330
- return json;
16855
+ return this.post("/v1/worker/deliver-stop", { payload: rawPayload }, this.deliverTimeoutMs);
16331
16856
  }
16332
16857
  async deliverRevoke(rawPayload) {
16333
- if (!this.isConfigured()) {
16334
- throw new Error("worker control is not configured");
16335
- }
16336
- const response = await this.fetchImpl(`${this.controlURL}/v1/worker/deliver-revoke`, {
16337
- method: "POST",
16338
- headers: {
16339
- "content-type": "application/json",
16340
- authorization: `Bearer ${this.token}`
16341
- },
16342
- body: JSON.stringify({ payload: rawPayload }),
16343
- signal: AbortSignal.timeout(this.deliverTimeoutMs)
16344
- });
16345
- const json = await parseJSONResponse(response);
16346
- if (!response.ok) {
16347
- throw new Error(normalizeString22(json.error) || `worker control failed ${response.status}`);
16348
- }
16349
- return json;
16858
+ return this.post("/v1/worker/deliver-revoke", { payload: rawPayload }, this.deliverTimeoutMs);
16859
+ }
16860
+ async deliverLocalAction(rawPayload) {
16861
+ return this.post("/v1/worker/deliver-local-action", { payload: rawPayload }, this.deliverTimeoutMs);
16350
16862
  }
16351
16863
  async ping() {
16352
- if (!this.isConfigured()) {
16353
- throw new Error("worker control is not configured");
16354
- }
16355
- const response = await this.fetchImpl(`${this.controlURL}/v1/worker/ping`, {
16356
- method: "POST",
16357
- headers: {
16358
- "content-type": "application/json",
16359
- authorization: `Bearer ${this.token}`
16360
- },
16361
- body: JSON.stringify({}),
16362
- signal: AbortSignal.timeout(this.pingTimeoutMs)
16363
- });
16364
- const json = await parseJSONResponse(response);
16365
- if (!response.ok) {
16366
- throw new Error(normalizeString22(json.error) || `worker control failed ${response.status}`);
16367
- }
16368
- return json;
16864
+ return this.post("/v1/worker/ping", {}, this.pingTimeoutMs);
16369
16865
  }
16370
16866
  };
16371
16867
  }
16372
16868
  });
16373
16869
 
16374
- // server/message-card-envelope.js
16375
- function buildMessageCardEnvelope(type, payload) {
16376
- return {
16377
- version: currentVersion,
16378
- type,
16379
- payload
16380
- };
16381
- }
16382
- var currentVersion;
16383
- var init_message_card_envelope = __esm({
16384
- "server/message-card-envelope.js"() {
16385
- currentVersion = 1;
16386
- }
16387
- });
16388
-
16389
- // server/daemon/control-card.js
16390
- function normalizeString23(value) {
16391
- return String(value ?? "").trim();
16392
- }
16393
- function buildOpenWorkspaceCard({
16394
- summaryText = "open \u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002",
16395
- detailText = "\u8BF7\u8F93\u5165\u5DE5\u4F5C\u76EE\u5F55\u6765\u542F\u52A8\u6216\u6062\u590D Claude \u4F1A\u8BDD\u3002",
16396
- initialCwd = ""
16397
- } = {}) {
16398
- return buildMessageCardEnvelope("claude_open_session", {
16399
- summary_text: normalizeString23(summaryText),
16400
- detail_text: normalizeString23(detailText),
16401
- command_prefix: openCommandPrefix,
16402
- command_hint: openCommandHint,
16403
- initial_cwd: normalizeString23(initialCwd)
16404
- });
16405
- }
16406
- var openCommandPrefix, openCommandHint;
16407
- var init_control_card = __esm({
16408
- "server/daemon/control-card.js"() {
16409
- init_message_card_envelope();
16410
- openCommandPrefix = "/grix open";
16411
- openCommandHint = "/grix open <working-directory>";
16412
- }
16413
- });
16414
-
16415
16870
  // server/daemon/claude-session-store.js
16416
16871
  import path22 from "node:path";
16417
16872
  import { access } from "node:fs/promises";
16418
- function normalizeString24(value) {
16873
+ function normalizeString25(value) {
16419
16874
  return String(value ?? "").trim();
16420
16875
  }
16421
16876
  function encodeClaudeProjectPath(cwd) {
16422
- const normalized = normalizeString24(cwd);
16877
+ const normalized = normalizeString25(cwd);
16423
16878
  if (!normalized) {
16424
16879
  return "";
16425
16880
  }
@@ -16427,8 +16882,8 @@ function encodeClaudeProjectPath(cwd) {
16427
16882
  }
16428
16883
  function resolveClaudeSessionPath({ cwd, claudeSessionID, env = process.env } = {}) {
16429
16884
  const projectKey = encodeClaudeProjectPath(cwd);
16430
- const sessionID = normalizeString24(claudeSessionID);
16431
- const homeDir = normalizeString24(env?.HOME);
16885
+ const sessionID = normalizeString25(claudeSessionID);
16886
+ const homeDir = normalizeString25(env?.HOME);
16432
16887
  if (!projectKey || !sessionID || !homeDir) {
16433
16888
  return "";
16434
16889
  }
@@ -16451,228 +16906,6 @@ var init_claude_session_store = __esm({
16451
16906
  }
16452
16907
  });
16453
16908
 
16454
- // server/daemon/control-command-handler.js
16455
- import { randomUUID as randomUUID6 } from "node:crypto";
16456
- function normalizeString25(value) {
16457
- return String(value ?? "").trim();
16458
- }
16459
- function defaultFormatBindingSummary(binding) {
16460
- if (!binding) {
16461
- return "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u76EE\u5F55\u3002";
16462
- }
16463
- const lines = [
16464
- `Aibot \u4F1A\u8BDD: ${binding.aibot_session_id}`,
16465
- `Claude \u4F1A\u8BDD: ${binding.claude_session_id}`,
16466
- `\u76EE\u5F55: ${binding.cwd}`,
16467
- `Worker \u72B6\u6001: ${binding.worker_status}`,
16468
- `\u53EF\u7528\u6027\u8BC4\u4F30: ${formatWorkerResponseAssessment(binding)}`
16469
- ];
16470
- if (normalizeString25(binding.worker_response_reason)) {
16471
- lines.push(`\u8BC4\u4F30\u539F\u56E0: ${normalizeString25(binding.worker_response_reason)}`);
16472
- }
16473
- return lines.join("\n");
16474
- }
16475
- function defaultBuildMissingBindingCardOptions() {
16476
- return {
16477
- summaryText: "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u76EE\u5F55\u3002",
16478
- detailText: "\u53D1\u9001 open <\u76EE\u5F55> \u6765\u521B\u5EFA\u4F1A\u8BDD\u3002"
16479
- };
16480
- }
16481
- function defaultFormatRuntimeError(error, fallback = "\u5904\u7406\u5931\u8D25\u3002") {
16482
- const message = normalizeString25(error?.message || error);
16483
- return message || fallback;
16484
- }
16485
- var DaemonControlCommandHandler;
16486
- var init_control_command_handler = __esm({
16487
- "server/daemon/control-command-handler.js"() {
16488
- init_daemon_paths();
16489
- init_worker_state();
16490
- DaemonControlCommandHandler = class {
16491
- constructor({
16492
- env = process.env,
16493
- bindingRegistry,
16494
- workerProcessManager,
16495
- bridgeServer,
16496
- ensureWorker,
16497
- respond,
16498
- respondWithOpenWorkspaceCard,
16499
- ensureDirectoryExists: ensureDirectoryExists2,
16500
- formatBindingSummary: formatBindingSummary2 = defaultFormatBindingSummary,
16501
- buildMissingBindingCardOptions: buildMissingBindingCardOptions2 = defaultBuildMissingBindingCardOptions,
16502
- formatRuntimeError: formatRuntimeError2 = defaultFormatRuntimeError
16503
- } = {}) {
16504
- this.env = env;
16505
- this.bindingRegistry = bindingRegistry;
16506
- this.workerProcessManager = workerProcessManager;
16507
- this.bridgeServer = bridgeServer;
16508
- this.ensureWorker = ensureWorker;
16509
- this.respond = respond;
16510
- this.respondWithOpenWorkspaceCard = respondWithOpenWorkspaceCard;
16511
- this.ensureDirectoryExists = ensureDirectoryExists2;
16512
- this.formatBindingSummary = formatBindingSummary2;
16513
- this.buildMissingBindingCardOptions = buildMissingBindingCardOptions2;
16514
- this.formatRuntimeError = formatRuntimeError2;
16515
- }
16516
- async handleOpenCommand(event, parsed) {
16517
- const cwd = normalizeString25(parsed.args.cwd);
16518
- await this.ensureDirectoryExists(cwd);
16519
- const existing = this.bindingRegistry.getByAibotSessionID(event.session_id);
16520
- if (existing) {
16521
- if (existing.cwd !== cwd) {
16522
- await this.respond(
16523
- event,
16524
- `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u7ECF\u56FA\u5B9A\u7ED1\u5B9A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u6539\u6210\u65B0\u76EE\u5F55\u3002
16525
-
16526
- ${this.formatBindingSummary(existing)}`,
16527
- { reply_source: "daemon_control_open_reject" }
16528
- );
16529
- return;
16530
- }
16531
- await this.ensureWorker(existing, { ignoreAuthCooldown: true });
16532
- await this.respond(
16533
- event,
16534
- `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u7ECF\u7ED1\u5B9A\uFF0C\u5DF2\u6309\u539F\u76EE\u5F55\u6062\u590D\u6216\u4FDD\u6301\u539F\u4F1A\u8BDD\u3002
16535
-
16536
- ${this.formatBindingSummary(existing)}`,
16537
- { reply_source: "daemon_control_open_existing" }
16538
- );
16539
- return;
16540
- }
16541
- const workerID = randomUUID6();
16542
- const claudeSessionID = randomUUID6();
16543
- const pluginDataDir = resolveWorkerPluginDataDir(event.session_id, this.env);
16544
- const created = await this.bindingRegistry.createBinding({
16545
- aibot_session_id: event.session_id,
16546
- claude_session_id: claudeSessionID,
16547
- cwd,
16548
- worker_id: workerID,
16549
- worker_status: "starting",
16550
- plugin_data_dir: pluginDataDir,
16551
- created_at: Date.now(),
16552
- updated_at: Date.now(),
16553
- last_started_at: Date.now(),
16554
- last_stopped_at: 0
16555
- });
16556
- await this.workerProcessManager.spawnWorker({
16557
- aibotSessionID: created.aibot_session_id,
16558
- cwd: created.cwd,
16559
- pluginDataDir: created.plugin_data_dir,
16560
- claudeSessionID: created.claude_session_id,
16561
- workerID: created.worker_id,
16562
- bridgeURL: this.bridgeServer.getURL(),
16563
- bridgeToken: this.bridgeServer.token
16564
- });
16565
- await this.respond(
16566
- event,
16567
- `\u5DF2\u65B0\u5EFA\u76EE\u5F55\u4F1A\u8BDD\u3002
16568
-
16569
- ${this.formatBindingSummary(created)}`,
16570
- { reply_source: "daemon_control_open_created" }
16571
- );
16572
- }
16573
- async handleStatusCommand(event) {
16574
- const binding = this.bindingRegistry.getByAibotSessionID(event.session_id);
16575
- if (!binding) {
16576
- await this.respondWithOpenWorkspaceCard(event, {
16577
- ...this.buildMissingBindingCardOptions(),
16578
- replySource: "daemon_control_status_missing"
16579
- });
16580
- return;
16581
- }
16582
- await this.respond(event, this.formatBindingSummary(binding), {
16583
- reply_source: "daemon_control_status"
16584
- });
16585
- }
16586
- async handleWhereCommand(event) {
16587
- const binding = this.bindingRegistry.getByAibotSessionID(event.session_id);
16588
- if (!binding) {
16589
- await this.respondWithOpenWorkspaceCard(event, {
16590
- ...this.buildMissingBindingCardOptions(),
16591
- replySource: "daemon_control_where_missing"
16592
- });
16593
- return;
16594
- }
16595
- const text = `\u5F53\u524D\u76EE\u5F55: ${binding.cwd}`;
16596
- await this.respond(event, text, {
16597
- reply_source: "daemon_control_where"
16598
- });
16599
- }
16600
- async handleStopCommand(event) {
16601
- const binding = this.bindingRegistry.getByAibotSessionID(event.session_id);
16602
- if (!binding) {
16603
- await this.respondWithOpenWorkspaceCard(event, {
16604
- ...this.buildMissingBindingCardOptions(),
16605
- replySource: "daemon_control_stop_missing"
16606
- });
16607
- return;
16608
- }
16609
- if (binding.worker_id) {
16610
- await this.workerProcessManager.stopWorker(binding.worker_id);
16611
- }
16612
- await this.bindingRegistry.markWorkerStopped(event.session_id, {
16613
- updatedAt: Date.now(),
16614
- lastStoppedAt: Date.now()
16615
- });
16616
- await this.respond(event, `\u5DF2\u505C\u6B62\u5F53\u524D\u4F1A\u8BDD\u5BF9\u5E94\u7684 Claude\u3002
16617
-
16618
- ${this.formatBindingSummary({
16619
- ...binding,
16620
- worker_status: "stopped"
16621
- })}`, {
16622
- reply_source: "daemon_control_stop"
16623
- });
16624
- }
16625
- async handleControlCommand(event, parsed) {
16626
- if (!parsed.ok) {
16627
- if (parsed.command === "open") {
16628
- await this.respondWithOpenWorkspaceCard(event, {
16629
- summaryText: parsed.error,
16630
- replySource: "daemon_control_invalid"
16631
- });
16632
- return true;
16633
- }
16634
- await this.respond(event, parsed.error, {
16635
- reply_source: "daemon_control_invalid"
16636
- });
16637
- return true;
16638
- }
16639
- try {
16640
- switch (parsed.command) {
16641
- case "open":
16642
- await this.handleOpenCommand(event, parsed);
16643
- return true;
16644
- case "status":
16645
- await this.handleStatusCommand(event);
16646
- return true;
16647
- case "where":
16648
- await this.handleWhereCommand(event);
16649
- return true;
16650
- case "stop":
16651
- await this.handleStopCommand(event);
16652
- return true;
16653
- default:
16654
- return false;
16655
- }
16656
- } catch (error) {
16657
- const message = this.formatRuntimeError(error, "\u547D\u4EE4\u6267\u884C\u5931\u8D25\u3002");
16658
- if (parsed.command === "open") {
16659
- await this.respondWithOpenWorkspaceCard(event, {
16660
- summaryText: message,
16661
- detailText: "\u53D1\u9001 open <\u76EE\u5F55> \u6765\u521B\u5EFA\u4F1A\u8BDD\u3002",
16662
- replySource: "daemon_control_open_error"
16663
- });
16664
- return true;
16665
- }
16666
- await this.respond(event, message, {
16667
- reply_source: "daemon_control_error"
16668
- });
16669
- return true;
16670
- }
16671
- }
16672
- };
16673
- }
16674
- });
16675
-
16676
16909
  // server/daemon/worker-health-inspector.js
16677
16910
  function normalizeString26(value) {
16678
16911
  return String(value ?? "").trim();
@@ -16930,7 +17163,7 @@ function resolveRecordInFlightActivityAt(record) {
16930
17163
  const normalizedComposingAt = Number.isFinite(composingAt) && composingAt > 0 ? composingAt : 0;
16931
17164
  return Math.max(normalizedUpdatedAt, normalizedComposingAt);
16932
17165
  }
16933
- function sleep(ms) {
17166
+ function sleep2(ms) {
16934
17167
  return new Promise((resolve) => setTimeout(resolve, ms));
16935
17168
  }
16936
17169
  var PendingEventOrchestrator;
@@ -17077,7 +17310,7 @@ var init_pending_event_orchestrator = __esm({
17077
17310
  error: error instanceof Error ? error.message : String(error)
17078
17311
  }, "error");
17079
17312
  }
17080
- await sleep(this.retryDelayMs);
17313
+ await sleep2(this.retryDelayMs);
17081
17314
  const latestBinding = this.bindingRegistry.getByAibotSessionID(normalizedSessionID);
17082
17315
  if (!canDeliverToWorker(latestBinding)) {
17083
17316
  this.trace({
@@ -17185,8 +17418,473 @@ var init_session_queue = __esm({
17185
17418
  delete(sessionID) {
17186
17419
  this._queues.delete(String(sessionID ?? "").trim());
17187
17420
  }
17188
- clear() {
17189
- this._queues.clear();
17421
+ clear() {
17422
+ this._queues.clear();
17423
+ }
17424
+ };
17425
+ }
17426
+ });
17427
+
17428
+ // server/inbound-interaction-action.js
17429
+ import path23 from "node:path";
17430
+ function normalizeString29(value) {
17431
+ return String(value ?? "").trim();
17432
+ }
17433
+ function buildUnmatchedResult() {
17434
+ return {
17435
+ matched: false,
17436
+ ok: false,
17437
+ source: "",
17438
+ action: null,
17439
+ errorCode: "",
17440
+ errorMsg: ""
17441
+ };
17442
+ }
17443
+ function buildErrorResult({
17444
+ source,
17445
+ errorCode,
17446
+ errorMsg
17447
+ } = {}) {
17448
+ return {
17449
+ matched: true,
17450
+ ok: false,
17451
+ source: normalizeString29(source),
17452
+ action: null,
17453
+ errorCode: normalizeString29(errorCode),
17454
+ errorMsg: normalizeString29(errorMsg)
17455
+ };
17456
+ }
17457
+ function buildSuccessResult({
17458
+ source,
17459
+ actionType,
17460
+ params,
17461
+ timeoutMs = 0
17462
+ } = {}) {
17463
+ return {
17464
+ matched: true,
17465
+ ok: true,
17466
+ source: normalizeString29(source),
17467
+ action: {
17468
+ action_type: normalizeString29(actionType),
17469
+ params: params && typeof params === "object" && !Array.isArray(params) ? params : {},
17470
+ timeout_ms: Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 0
17471
+ },
17472
+ errorCode: "",
17473
+ errorMsg: ""
17474
+ };
17475
+ }
17476
+ function decodeUrlComponentRepeatedly(value) {
17477
+ let current = normalizeString29(value);
17478
+ if (!current) {
17479
+ return "";
17480
+ }
17481
+ for (let index = 0; index < 3; index += 1) {
17482
+ try {
17483
+ const decoded = decodeURIComponent(current);
17484
+ if (decoded === current) {
17485
+ break;
17486
+ }
17487
+ current = decoded;
17488
+ } catch {
17489
+ break;
17490
+ }
17491
+ }
17492
+ return normalizeString29(current);
17493
+ }
17494
+ function extractGrixCardURI(text) {
17495
+ const normalizedText = normalizeString29(text).replace(/&amp;/giu, "&");
17496
+ if (!normalizedText) {
17497
+ return "";
17498
+ }
17499
+ const match = normalizedText.match(/grix:\/\/card\/[^\s)]+/u);
17500
+ return normalizeString29(match?.[0] ?? normalizedText);
17501
+ }
17502
+ function parseGrixCardURI(text) {
17503
+ const rawURI = extractGrixCardURI(text);
17504
+ if (!rawURI) {
17505
+ return null;
17506
+ }
17507
+ let parsed;
17508
+ try {
17509
+ parsed = new URL(rawURI);
17510
+ } catch {
17511
+ return null;
17512
+ }
17513
+ if (parsed.protocol !== "grix:" || normalizeString29(parsed.hostname) !== "card") {
17514
+ return null;
17515
+ }
17516
+ return parsed;
17517
+ }
17518
+ function normalizeResolutionMapEntries(entries) {
17519
+ if (!Array.isArray(entries)) {
17520
+ return [];
17521
+ }
17522
+ return entries.map((entry) => {
17523
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
17524
+ return null;
17525
+ }
17526
+ const key = normalizeString29(entry.key);
17527
+ const value = normalizeString29(entry.value);
17528
+ if (!key || !value) {
17529
+ return null;
17530
+ }
17531
+ return { key, value };
17532
+ }).filter(Boolean);
17533
+ }
17534
+ function parseQuestionReplyPayload(rawPayload) {
17535
+ const decoded = decodeUrlComponentRepeatedly(rawPayload);
17536
+ if (!decoded) {
17537
+ return null;
17538
+ }
17539
+ try {
17540
+ const parsed = JSON.parse(decoded);
17541
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
17542
+ } catch {
17543
+ return null;
17544
+ }
17545
+ }
17546
+ function parseQuestionReplyAction(parsedURI) {
17547
+ const payload = parseQuestionReplyPayload(parsedURI?.searchParams?.get("d"));
17548
+ if (!payload) {
17549
+ return buildErrorResult({
17550
+ source: "grix_card_question_reply",
17551
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17552
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u5185\u5BB9\u683C\u5F0F\u4E0D\u6B63\u786E\u3002"
17553
+ });
17554
+ }
17555
+ const requestID = normalizeString29(payload.request_id);
17556
+ if (!requestID) {
17557
+ return buildErrorResult({
17558
+ source: "grix_card_question_reply",
17559
+ errorCode: interactionReplyErrorCodes.requestIDRequired,
17560
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11 request_id\u3002"
17561
+ });
17562
+ }
17563
+ const action = normalizeString29(payload.action).toLowerCase();
17564
+ if (action) {
17565
+ if (!["accept", "cancel", "decline"].includes(action)) {
17566
+ return buildErrorResult({
17567
+ source: "grix_card_question_reply",
17568
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17569
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u52A8\u4F5C\u65E0\u6548\u3002"
17570
+ });
17571
+ }
17572
+ return buildSuccessResult({
17573
+ source: "grix_card_question_reply",
17574
+ actionType: localActionTypes.interactionReply,
17575
+ timeoutMs: 15e3,
17576
+ params: {
17577
+ kind: interactionKinds.elicitation,
17578
+ request_id: requestID,
17579
+ resolution: {
17580
+ type: interactionResolutionTypes.action,
17581
+ value: action
17582
+ }
17583
+ }
17584
+ });
17585
+ }
17586
+ const response = payload.response;
17587
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
17588
+ return buildErrorResult({
17589
+ source: "grix_card_question_reply",
17590
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17591
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u7B54\u6848\u5185\u5BB9\u3002"
17592
+ });
17593
+ }
17594
+ const responseType = normalizeString29(response.type).toLowerCase();
17595
+ if (responseType === "single") {
17596
+ const value = normalizeString29(response.value);
17597
+ if (!value) {
17598
+ return buildErrorResult({
17599
+ source: "grix_card_question_reply",
17600
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17601
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u7B54\u6848\u5185\u5BB9\u3002"
17602
+ });
17603
+ }
17604
+ return buildSuccessResult({
17605
+ source: "grix_card_question_reply",
17606
+ actionType: localActionTypes.interactionReply,
17607
+ timeoutMs: 15e3,
17608
+ params: {
17609
+ kind: interactionKinds.elicitation,
17610
+ request_id: requestID,
17611
+ resolution: {
17612
+ type: interactionResolutionTypes.text,
17613
+ value
17614
+ }
17615
+ }
17616
+ });
17617
+ }
17618
+ if (responseType === "map") {
17619
+ const entries = normalizeResolutionMapEntries(response.entries);
17620
+ if (entries.length === 0) {
17621
+ return buildErrorResult({
17622
+ source: "grix_card_question_reply",
17623
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17624
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u6709\u6548\u7B54\u6848\u3002"
17625
+ });
17626
+ }
17627
+ return buildSuccessResult({
17628
+ source: "grix_card_question_reply",
17629
+ actionType: localActionTypes.interactionReply,
17630
+ timeoutMs: 15e3,
17631
+ params: {
17632
+ kind: interactionKinds.elicitation,
17633
+ request_id: requestID,
17634
+ resolution: {
17635
+ type: interactionResolutionTypes.map,
17636
+ entries
17637
+ }
17638
+ }
17639
+ });
17640
+ }
17641
+ return buildErrorResult({
17642
+ source: "grix_card_question_reply",
17643
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17644
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7C7B\u578B\u65E0\u6548\u3002"
17645
+ });
17646
+ }
17647
+ function parseOpenSessionAction(parsedURI) {
17648
+ const cwd = decodeUrlComponentRepeatedly(parsedURI?.searchParams?.get("cwd"));
17649
+ if (!cwd) {
17650
+ return buildErrorResult({
17651
+ source: "grix_card_open_session_submit",
17652
+ errorCode: sessionControlErrorCodes.cwdRequired,
17653
+ errorMsg: "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u65F6\u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002"
17654
+ });
17655
+ }
17656
+ return buildSuccessResult({
17657
+ source: "grix_card_open_session_submit",
17658
+ actionType: localActionTypes.sessionControl,
17659
+ params: {
17660
+ verb: "open",
17661
+ cwd: path23.resolve(cwd)
17662
+ }
17663
+ });
17664
+ }
17665
+ function parseInboundInteractionAction(text) {
17666
+ const parsedURI = parseGrixCardURI(text);
17667
+ if (!parsedURI) {
17668
+ return buildUnmatchedResult();
17669
+ }
17670
+ const cardType = normalizeString29(parsedURI.pathname).replace(/^\/+/u, "");
17671
+ if (cardType === "agent_open_session_submit") {
17672
+ return parseOpenSessionAction(parsedURI);
17673
+ }
17674
+ if (cardType === "agent_question_reply") {
17675
+ return parseQuestionReplyAction(parsedURI);
17676
+ }
17677
+ return buildUnmatchedResult();
17678
+ }
17679
+ var init_inbound_interaction_action = __esm({
17680
+ "server/inbound-interaction-action.js"() {
17681
+ init_protocol_contract();
17682
+ }
17683
+ });
17684
+
17685
+ // server/daemon/session-control-action-handler.js
17686
+ import { randomUUID as randomUUID6 } from "node:crypto";
17687
+ function normalizeString30(value) {
17688
+ return String(value ?? "").trim();
17689
+ }
17690
+ function buildBindingResult(binding) {
17691
+ return {
17692
+ aibot_session_id: normalizeString30(binding?.aibot_session_id),
17693
+ claude_session_id: normalizeString30(binding?.claude_session_id),
17694
+ cwd: normalizeString30(binding?.cwd),
17695
+ worker_status: normalizeString30(binding?.worker_status)
17696
+ };
17697
+ }
17698
+ function buildSuccessResult2(verb, outcome, binding) {
17699
+ return {
17700
+ status: localActionResultStatuses.ok,
17701
+ result: {
17702
+ domain: resultDomains.sessionControl,
17703
+ verb,
17704
+ outcome,
17705
+ binding: buildBindingResult(binding)
17706
+ }
17707
+ };
17708
+ }
17709
+ function buildFailure(errorCode, errorMsg) {
17710
+ return {
17711
+ status: localActionResultStatuses.failed,
17712
+ errorCode,
17713
+ errorMsg
17714
+ };
17715
+ }
17716
+ var DaemonSessionControlActionHandler;
17717
+ var init_session_control_action_handler = __esm({
17718
+ "server/daemon/session-control-action-handler.js"() {
17719
+ init_protocol_contract();
17720
+ init_daemon_paths();
17721
+ DaemonSessionControlActionHandler = class {
17722
+ constructor({
17723
+ env = process.env,
17724
+ bindingRegistry,
17725
+ workerProcessManager,
17726
+ bridgeServer,
17727
+ ensureWorker,
17728
+ ensureDirectoryExists: ensureDirectoryExists2
17729
+ } = {}) {
17730
+ this.env = env;
17731
+ this.bindingRegistry = bindingRegistry;
17732
+ this.workerProcessManager = workerProcessManager;
17733
+ this.bridgeServer = bridgeServer;
17734
+ this.ensureWorker = ensureWorker;
17735
+ this.ensureDirectoryExists = ensureDirectoryExists2;
17736
+ }
17737
+ getBinding(sessionID) {
17738
+ return this.bindingRegistry.getByAibotSessionID(sessionID);
17739
+ }
17740
+ async createBinding(sessionID, cwd) {
17741
+ const workerID = randomUUID6();
17742
+ const claudeSessionID = randomUUID6();
17743
+ const pluginDataDir = resolveWorkerPluginDataDir(sessionID, this.env);
17744
+ const now = Date.now();
17745
+ const created = await this.bindingRegistry.createBinding({
17746
+ aibot_session_id: sessionID,
17747
+ claude_session_id: claudeSessionID,
17748
+ cwd,
17749
+ worker_id: workerID,
17750
+ worker_status: bindingWorkerStatuses.starting,
17751
+ plugin_data_dir: pluginDataDir,
17752
+ created_at: now,
17753
+ updated_at: now,
17754
+ last_started_at: now,
17755
+ last_stopped_at: 0
17756
+ });
17757
+ await this.workerProcessManager.spawnWorker({
17758
+ aibotSessionID: created.aibot_session_id,
17759
+ cwd: created.cwd,
17760
+ pluginDataDir: created.plugin_data_dir,
17761
+ claudeSessionID: created.claude_session_id,
17762
+ workerID: created.worker_id,
17763
+ bridgeURL: this.bridgeServer.getURL(),
17764
+ bridgeToken: this.bridgeServer.token
17765
+ });
17766
+ return this.getBinding(sessionID) ?? created;
17767
+ }
17768
+ async handleOpen(sessionID, params) {
17769
+ const cwd = normalizeString30(params?.cwd);
17770
+ if (!cwd) {
17771
+ return buildFailure(sessionControlErrorCodes.cwdRequired, "session control cwd is required");
17772
+ }
17773
+ try {
17774
+ await this.ensureDirectoryExists(cwd);
17775
+ } catch (error) {
17776
+ return buildFailure(
17777
+ sessionControlErrorCodes.invalidCwd,
17778
+ normalizeString30(error?.message || error) || "session control cwd is invalid"
17779
+ );
17780
+ }
17781
+ const existing = this.getBinding(sessionID);
17782
+ if (existing) {
17783
+ if (existing.cwd !== cwd) {
17784
+ return buildFailure(
17785
+ sessionControlErrorCodes.rebindForbidden,
17786
+ "session binding cannot be changed to another working directory"
17787
+ );
17788
+ }
17789
+ try {
17790
+ await this.ensureWorker(existing, { ignoreAuthCooldown: true });
17791
+ } catch (error) {
17792
+ return buildFailure(
17793
+ sessionControlErrorCodes.runtimeError,
17794
+ normalizeString30(error?.message || error) || "session control open failed"
17795
+ );
17796
+ }
17797
+ return buildSuccessResult2(sessionControlVerbs.open, sessionControlOutcomes.alreadyBound, this.getBinding(sessionID) ?? existing);
17798
+ }
17799
+ try {
17800
+ const created = await this.createBinding(sessionID, cwd);
17801
+ return buildSuccessResult2(sessionControlVerbs.open, sessionControlOutcomes.opened, created);
17802
+ } catch (error) {
17803
+ return buildFailure(
17804
+ sessionControlErrorCodes.runtimeError,
17805
+ normalizeString30(error?.message || error) || "session control open failed"
17806
+ );
17807
+ }
17808
+ }
17809
+ handleStatus(sessionID) {
17810
+ const binding = this.getBinding(sessionID);
17811
+ if (!binding) {
17812
+ return buildFailure(sessionControlErrorCodes.bindingMissing, "session binding was not found");
17813
+ }
17814
+ return buildSuccessResult2(sessionControlVerbs.status, sessionControlOutcomes.status, binding);
17815
+ }
17816
+ handleWhere(sessionID) {
17817
+ const binding = this.getBinding(sessionID);
17818
+ if (!binding) {
17819
+ return buildFailure(sessionControlErrorCodes.bindingMissing, "session binding was not found");
17820
+ }
17821
+ return buildSuccessResult2(sessionControlVerbs.where, sessionControlOutcomes.where, binding);
17822
+ }
17823
+ async handleStop(sessionID) {
17824
+ const binding = this.getBinding(sessionID);
17825
+ if (!binding) {
17826
+ return buildFailure(sessionControlErrorCodes.bindingMissing, "session binding was not found");
17827
+ }
17828
+ try {
17829
+ if (binding.worker_id) {
17830
+ await this.workerProcessManager.stopWorker(binding.worker_id);
17831
+ }
17832
+ await this.bindingRegistry.markWorkerStopped(sessionID, {
17833
+ updatedAt: Date.now(),
17834
+ lastStoppedAt: Date.now()
17835
+ });
17836
+ } catch (error) {
17837
+ return buildFailure(
17838
+ sessionControlErrorCodes.runtimeError,
17839
+ normalizeString30(error?.message || error) || "session control stop failed"
17840
+ );
17841
+ }
17842
+ return buildSuccessResult2(sessionControlVerbs.stop, sessionControlOutcomes.stopped, this.getBinding(sessionID) ?? {
17843
+ ...binding,
17844
+ worker_status: bindingWorkerStatuses.stopped
17845
+ });
17846
+ }
17847
+ async handleLocalAction(action) {
17848
+ if (normalizeString30(action?.action_type) !== localActionTypes.sessionControl) {
17849
+ return {
17850
+ handled: false
17851
+ };
17852
+ }
17853
+ const sessionID = normalizeString30(action?.params?.session_id);
17854
+ if (!sessionID) {
17855
+ return {
17856
+ handled: true,
17857
+ response: buildFailure(localActionErrorCodes.localActionRouteMissing, "local action session_id is required")
17858
+ };
17859
+ }
17860
+ const verb = normalizeString30(action?.params?.verb).toLowerCase();
17861
+ switch (verb) {
17862
+ case sessionControlVerbs.open:
17863
+ return {
17864
+ handled: true,
17865
+ response: await this.handleOpen(sessionID, action.params)
17866
+ };
17867
+ case sessionControlVerbs.status:
17868
+ return {
17869
+ handled: true,
17870
+ response: this.handleStatus(sessionID)
17871
+ };
17872
+ case sessionControlVerbs.where:
17873
+ return {
17874
+ handled: true,
17875
+ response: this.handleWhere(sessionID)
17876
+ };
17877
+ case sessionControlVerbs.stop:
17878
+ return {
17879
+ handled: true,
17880
+ response: await this.handleStop(sessionID)
17881
+ };
17882
+ default:
17883
+ return {
17884
+ handled: true,
17885
+ response: buildFailure(sessionControlErrorCodes.verbInvalid, "session control verb is invalid")
17886
+ };
17887
+ }
17190
17888
  }
17191
17889
  };
17192
17890
  }
@@ -17194,7 +17892,7 @@ var init_session_queue = __esm({
17194
17892
 
17195
17893
  // server/worker-probe.js
17196
17894
  import { randomUUID as randomUUID7 } from "node:crypto";
17197
- function normalizeString29(value) {
17895
+ function normalizeString31(value) {
17198
17896
  return String(value ?? "").trim();
17199
17897
  }
17200
17898
  function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID = "" } = {}) {
@@ -17211,7 +17909,7 @@ function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID
17211
17909
  return {
17212
17910
  event_id: `probe_${probeID}`,
17213
17911
  event_type: "user_chat",
17214
- session_id: normalizeString29(sessionID),
17912
+ session_id: normalizeString31(sessionID),
17215
17913
  session_type: "1",
17216
17914
  msg_id: `probe_msg_${probeID}`,
17217
17915
  sender_id: probeSenderID,
@@ -17220,13 +17918,13 @@ function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID
17220
17918
  msg_type: "1",
17221
17919
  content: "ping",
17222
17920
  created_at: Date.now(),
17223
- worker_id: normalizeString29(workerID),
17224
- claude_session_id: normalizeString29(claudeSessionID),
17921
+ worker_id: normalizeString31(workerID),
17922
+ claude_session_id: normalizeString31(claudeSessionID),
17225
17923
  channel_data: channelData
17226
17924
  };
17227
17925
  }
17228
17926
  function isExpectedWorkerProbeReply(text, expectedReply = "pong") {
17229
- return normalizeString29(text).toLowerCase() === normalizeString29(expectedReply).toLowerCase();
17927
+ return normalizeString31(text).toLowerCase() === normalizeString31(expectedReply).toLowerCase();
17230
17928
  }
17231
17929
  var probeChannelNamespace, probeSenderID, probeKind, defaultWorkerPingProbeTimeoutMs;
17232
17930
  var init_worker_probe = __esm({
@@ -17240,19 +17938,22 @@ var init_worker_probe = __esm({
17240
17938
 
17241
17939
  // server/daemon/runtime.js
17242
17940
  import { randomUUID as randomUUID8 } from "node:crypto";
17243
- import { stat as stat2 } from "node:fs/promises";
17244
- function normalizeString30(value) {
17941
+ import { stat as stat3 } from "node:fs/promises";
17942
+ function normalizeString32(value) {
17245
17943
  return String(value ?? "").trim();
17246
17944
  }
17247
- function sleep2(ms) {
17945
+ function isRecordOnlyMirror(event) {
17946
+ return normalizeString32(event?.mirror_mode) === "record_only";
17947
+ }
17948
+ function sleep3(ms) {
17248
17949
  return new Promise((resolve) => setTimeout(resolve, ms));
17249
17950
  }
17250
17951
  async function ensureDirectoryExists(directoryPath) {
17251
17952
  let info;
17252
17953
  try {
17253
- info = await stat2(directoryPath);
17954
+ info = await stat3(directoryPath);
17254
17955
  } catch (error) {
17255
- const code = normalizeString30(error?.code);
17956
+ const code = normalizeString32(error?.code);
17256
17957
  if (code === "ENOENT") {
17257
17958
  throw new Error("\u6307\u5B9A\u8DEF\u5F84\u4E0D\u5B58\u5728\u3002");
17258
17959
  }
@@ -17265,44 +17966,6 @@ async function ensureDirectoryExists(directoryPath) {
17265
17966
  throw new Error("\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\u3002");
17266
17967
  }
17267
17968
  }
17268
- function formatBindingSummary(binding) {
17269
- if (!binding) {
17270
- return "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u76EE\u5F55\u3002";
17271
- }
17272
- const lines = [
17273
- `Aibot \u4F1A\u8BDD: ${binding.aibot_session_id}`,
17274
- `Claude \u4F1A\u8BDD: ${binding.claude_session_id}`,
17275
- `\u76EE\u5F55: ${binding.cwd}`,
17276
- `Worker \u72B6\u6001: ${binding.worker_status}`,
17277
- `\u53EF\u7528\u6027\u8BC4\u4F30: ${formatWorkerResponseAssessment(binding)}`
17278
- ];
17279
- const responseReason = normalizeString30(binding?.worker_response_reason);
17280
- if (responseReason) {
17281
- lines.push(`\u8BC4\u4F30\u539F\u56E0: ${responseReason}`);
17282
- }
17283
- const lastReplyAt = formatStatusTimestamp(binding?.worker_last_reply_at);
17284
- if (lastReplyAt) {
17285
- lines.push(`\u6700\u8FD1\u6210\u529F: ${lastReplyAt}`);
17286
- }
17287
- const lastFailureAt = formatStatusTimestamp(binding?.worker_last_failure_at);
17288
- if (lastFailureAt) {
17289
- const failureCode = normalizeString30(binding?.worker_last_failure_code);
17290
- lines.push(`\u6700\u8FD1\u5931\u8D25: ${lastFailureAt}${failureCode ? ` (${failureCode})` : ""}`);
17291
- }
17292
- const lastHookAt = formatStatusTimestamp(binding?.worker_last_hook_event_at);
17293
- if (lastHookAt) {
17294
- const lastHookSummary = summarizeHookSignalEvent({
17295
- event_id: binding?.worker_last_hook_event_id,
17296
- hook_event_name: binding?.worker_last_hook_event_name,
17297
- event_at: binding?.worker_last_hook_event_at,
17298
- detail: binding?.worker_last_hook_event_detail
17299
- });
17300
- if (lastHookSummary) {
17301
- lines.push(`\u6700\u8FD1 Hook: ${lastHookSummary} @ ${lastHookAt}`);
17302
- }
17303
- }
17304
- return lines.join("\n");
17305
- }
17306
17969
  function buildInterruptedEventNotice() {
17307
17970
  return "Claude \u521A\u521A\u4E2D\u65AD\u4E86\uFF0C\u8FD9\u6761\u6D88\u606F\u6CA1\u6709\u5904\u7406\u5B8C\u6210\u3002\u8BF7\u518D\u53D1\u4E00\u6B21\u3002";
17308
17971
  }
@@ -17312,46 +17975,147 @@ function buildAuthLoginRequiredEventNotice() {
17312
17975
  function buildUsageLimitReachedEventNotice() {
17313
17976
  return "Claude \u5F53\u524D\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6CA1\u6CD5\u7EE7\u7EED\u56DE\u590D\u3002\u8BF7\u5148\u5728 Claude \u91CC\u5904\u7406\u989D\u5EA6\u63D0\u793A\uFF0C\u7136\u540E\u628A\u8FD9\u6761\u6D88\u606F\u518D\u53D1\u4E00\u6B21\u3002";
17314
17977
  }
17978
+ function buildBindingMissingEventNotice() {
17979
+ return buildAgentOpenSessionCardLink({
17980
+ summaryText: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002",
17981
+ detailText: "\u5148\u63D0\u4EA4\u4E00\u4E2A\u5DE5\u4F5C\u76EE\u5F55\uFF0CClaude \u624D\u80FD\u7EE7\u7EED\u5904\u7406\u6D88\u606F\u3002\u63D0\u4EA4\u540E\uFF0C\u628A\u521A\u624D\u90A3\u6761\u6D88\u606F\u518D\u53D1\u4E00\u6B21\u3002"
17982
+ });
17983
+ }
17984
+ function buildSessionControlOpenCardNotice({
17985
+ summaryText = "",
17986
+ detailText = "",
17987
+ initialCwd = ""
17988
+ } = {}) {
17989
+ return buildAgentOpenSessionCardLink({
17990
+ summaryText: normalizeString32(summaryText) || "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002",
17991
+ detailText: normalizeString32(detailText) || "\u5148\u63D0\u4EA4\u4E00\u4E2A\u5DE5\u4F5C\u76EE\u5F55\uFF0CClaude \u624D\u80FD\u7EE7\u7EED\u5904\u7406\u6D88\u606F\u3002",
17992
+ initialCwd
17993
+ });
17994
+ }
17995
+ function formatSessionControlBindingSummary(binding) {
17996
+ const normalizedBinding = binding ?? {};
17997
+ const cwd = normalizeString32(normalizedBinding.cwd);
17998
+ const workerStatus = normalizeString32(normalizedBinding.worker_status);
17999
+ const lines = [];
18000
+ if (cwd) {
18001
+ lines.push(`\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}`);
18002
+ }
18003
+ if (workerStatus) {
18004
+ lines.push(`\u72B6\u6001\uFF1A${workerStatus}`);
18005
+ }
18006
+ return lines.join("\n");
18007
+ }
18008
+ function buildSessionControlSuccessNotice(result) {
18009
+ const verb = normalizeString32(result?.verb);
18010
+ const outcome = normalizeString32(result?.outcome);
18011
+ const binding = result?.binding ?? {};
18012
+ const summary = formatSessionControlBindingSummary(binding);
18013
+ if (verb === sessionControlVerbs.open) {
18014
+ const title = outcome === sessionControlOutcomes.alreadyBound ? "\u5F53\u524D\u5BF9\u8BDD\u5DF2\u7ECF\u6253\u5F00\u8FD9\u4E2A\u5DE5\u4F5C\u76EE\u5F55\u3002" : "\u5DF2\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18015
+ return summary ? `${title}
18016
+
18017
+ ${summary}` : title;
18018
+ }
18019
+ if (verb === sessionControlVerbs.status) {
18020
+ return summary || "\u5F53\u524D\u5BF9\u8BDD\u5DF2\u7ECF\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18021
+ }
18022
+ if (verb === sessionControlVerbs.where) {
18023
+ const cwd = normalizeString32(binding.cwd);
18024
+ return cwd ? `\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}` : "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18025
+ }
18026
+ if (verb === sessionControlVerbs.stop) {
18027
+ return summary ? `\u5DF2\u505C\u6B62\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F1A\u8BDD\u3002
18028
+
18029
+ ${summary}` : "\u5DF2\u505C\u6B62\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F1A\u8BDD\u3002";
18030
+ }
18031
+ return "\u5DE5\u4F5C\u76EE\u5F55\u64CD\u4F5C\u5DF2\u5B8C\u6210\u3002";
18032
+ }
18033
+ function buildSessionControlFailureNotice({
18034
+ errorCode = "",
18035
+ errorMsg = ""
18036
+ } = {}) {
18037
+ const normalizedErrorCode = normalizeString32(errorCode);
18038
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18039
+ if (normalizedErrorCode === sessionControlErrorCodes.rebindForbidden) {
18040
+ return normalizedErrorMsg || "\u5F53\u524D\u5BF9\u8BDD\u5DF2\u7ECF\u56FA\u5B9A\u7ED1\u5B9A\u5230\u53E6\u4E00\u4E2A\u5DE5\u4F5C\u76EE\u5F55\u3002";
18041
+ }
18042
+ if (normalizedErrorCode === sessionControlErrorCodes.verbInvalid) {
18043
+ return normalizedErrorMsg || "\u547D\u4EE4\u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
18044
+ }
18045
+ return normalizedErrorMsg || "\u5DE5\u4F5C\u76EE\u5F55\u64CD\u4F5C\u5931\u8D25\u3002";
18046
+ }
18047
+ function buildSessionControlCardSummary(errorCode, errorMsg) {
18048
+ const normalizedErrorCode = normalizeString32(errorCode);
18049
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18050
+ if (normalizedErrorCode === sessionControlErrorCodes.bindingMissing) {
18051
+ return "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18052
+ }
18053
+ if (normalizedErrorCode === sessionControlErrorCodes.invalidCwd) {
18054
+ return normalizedErrorMsg || "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u53EF\u7528\u3002";
18055
+ }
18056
+ if (normalizedErrorCode === sessionControlErrorCodes.cwdRequired) {
18057
+ return normalizedErrorMsg || "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u65F6\u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002";
18058
+ }
18059
+ return normalizedErrorMsg || "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18060
+ }
18061
+ function buildInteractionReplyFailureNotice({
18062
+ errorCode = "",
18063
+ errorMsg = ""
18064
+ } = {}) {
18065
+ const normalizedErrorCode = normalizeString32(errorCode);
18066
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18067
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestNotPending) {
18068
+ return "\u8FD9\u6761\u4EA4\u4E92\u5DF2\u7ECF\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u3002";
18069
+ }
18070
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestNotFound) {
18071
+ return "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u4EA4\u4E92\u8BF7\u6C42\u3002";
18072
+ }
18073
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestIDRequired || normalizedErrorCode === interactionReplyErrorCodes.resolutionInvalid) {
18074
+ return normalizedErrorMsg || "\u4EA4\u4E92\u56DE\u590D\u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
18075
+ }
18076
+ if (normalizedErrorCode === "local_action_delivery_failed") {
18077
+ return "Claude \u8FD8\u6CA1\u51C6\u5907\u597D\u5904\u7406\u8FD9\u6761\u4EA4\u4E92\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
18078
+ }
18079
+ if (normalizedErrorCode === "local_action_result_timeout") {
18080
+ return "\u4EA4\u4E92\u56DE\u590D\u63D0\u4EA4\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
18081
+ }
18082
+ return normalizedErrorMsg || "\u4EA4\u4E92\u56DE\u590D\u63D0\u4EA4\u5931\u8D25\u3002";
18083
+ }
17315
18084
  function buildWorkerStartupFailedNotice() {
17316
18085
  return "Claude \u542F\u52A8\u672A\u5B8C\u6210\uFF0C\u6D88\u606F\u672A\u53D1\u9001\u3002\u8BF7\u6267\u884C grix-claude restart \u540E\u91CD\u8BD5\u3002";
17317
18086
  }
17318
18087
  function buildUsageLimitFailureOptions() {
17319
18088
  return {
17320
18089
  noticeText: buildUsageLimitReachedEventNotice(),
17321
- replySource: "daemon_worker_usage_limit_reached",
17322
18090
  resultCode: "claude_usage_limit_reached",
17323
18091
  resultMessage: "claude usage limit reached; user action required"
17324
18092
  };
17325
18093
  }
17326
- function buildMissingBindingCardOptions() {
18094
+ function normalizeLocalActionPayload(rawPayload) {
17327
18095
  return {
17328
- summaryText: "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u76EE\u5F55\u3002",
17329
- detailText: "\u53D1\u9001 open <\u76EE\u5F55> \u6765\u521B\u5EFA\u4F1A\u8BDD\u3002"
18096
+ action_id: normalizeString32(rawPayload?.action_id),
18097
+ event_id: normalizeString32(rawPayload?.event_id),
18098
+ action_type: normalizeString32(rawPayload?.action_type),
18099
+ params: rawPayload?.params && typeof rawPayload.params === "object" && !Array.isArray(rawPayload.params) ? rawPayload.params : {},
18100
+ timeout_ms: normalizeNonNegativeInt(rawPayload?.timeout_ms, 0)
17330
18101
  };
17331
18102
  }
17332
18103
  function withWorkerLaunchFailure(binding, code) {
17333
18104
  return {
17334
18105
  ...binding ?? {},
17335
- worker_launch_failure: normalizeString30(code)
18106
+ worker_launch_failure: normalizeString32(code)
17336
18107
  };
17337
18108
  }
17338
18109
  function formatRuntimeError(error, fallback = "\u5904\u7406\u5931\u8D25\u3002") {
17339
- const message = normalizeString30(error?.message || error);
18110
+ const message = normalizeString32(error?.message || error);
17340
18111
  return message || fallback;
17341
18112
  }
17342
- function formatStatusTimestamp(value) {
17343
- const numeric = Number(value);
17344
- if (!Number.isFinite(numeric) || numeric <= 0) {
17345
- return "";
17346
- }
17347
- return new Date(numeric).toISOString();
17348
- }
17349
18113
  function normalizeHookSignalRecord(input) {
17350
18114
  if (!input || typeof input !== "object") {
17351
18115
  return null;
17352
18116
  }
17353
- const eventID = normalizeString30(input.event_id);
17354
- const eventName = normalizeString30(input.hook_event_name);
18117
+ const eventID = normalizeString32(input.event_id);
18118
+ const eventName = normalizeString32(input.hook_event_name);
17355
18119
  const eventAt = Number(input.event_at ?? 0);
17356
18120
  if (!eventID || !eventName || !Number.isFinite(eventAt) || eventAt <= 0) {
17357
18121
  return null;
@@ -17360,7 +18124,7 @@ function normalizeHookSignalRecord(input) {
17360
18124
  event_id: eventID,
17361
18125
  hook_event_name: eventName,
17362
18126
  event_at: Math.floor(eventAt),
17363
- detail: normalizeString30(input.detail)
18127
+ detail: normalizeString32(input.detail)
17364
18128
  };
17365
18129
  }
17366
18130
  function listHookSignalRecords(pingPayload) {
@@ -17386,12 +18150,12 @@ function buildPingActivityTraceFields(pingPayload = {}) {
17386
18150
  reported_mcp_ready: pingPayload?.mcp_ready === true ? true : pingPayload?.mcp_ready === false ? false : "",
17387
18151
  reported_mcp_last_activity_at: normalizeNonNegativeInt(pingPayload?.mcp_last_activity_at, 0),
17388
18152
  reported_hook_last_activity_at: normalizeNonNegativeInt(pingPayload?.hook_last_activity_at, 0),
17389
- reported_hook_event_name: normalizeString30(pingPayload?.hook_latest_event?.hook_event_name)
18153
+ reported_hook_event_name: normalizeString32(pingPayload?.hook_latest_event?.hook_event_name)
17390
18154
  };
17391
18155
  }
17392
18156
  function buildMcpHealthTraceFields(mcpHealth = {}) {
17393
18157
  return {
17394
- mcp_health_reason: normalizeString30(mcpHealth?.reason),
18158
+ mcp_health_reason: normalizeString32(mcpHealth?.reason),
17395
18159
  mcp_health_idle_ms: normalizeNonNegativeInt(mcpHealth?.idleMs, 0),
17396
18160
  inflight_event_count: normalizeNonNegativeInt(mcpHealth?.inFlightCount, 0),
17397
18161
  latest_event_activity_at: normalizeNonNegativeInt(mcpHealth?.latestInteractionAt, 0),
@@ -17400,7 +18164,7 @@ function buildMcpHealthTraceFields(mcpHealth = {}) {
17400
18164
  }
17401
18165
  function buildMcpResultTimeoutTraceFields(details = {}) {
17402
18166
  return {
17403
- delivery_state: normalizeString30(details?.deliveryState),
18167
+ delivery_state: normalizeString32(details?.deliveryState),
17404
18168
  record_updated_at: normalizeNonNegativeInt(details?.updatedAt, 0),
17405
18169
  record_last_composing_at: normalizeNonNegativeInt(details?.lastComposingAt, 0),
17406
18170
  record_interaction_at: normalizeNonNegativeInt(details?.recordInteractionAt, 0),
@@ -17416,6 +18180,9 @@ function normalizeNonNegativeInt(value, fallbackValue) {
17416
18180
  }
17417
18181
  return Math.max(0, Math.floor(numeric));
17418
18182
  }
18183
+ function isSyntheticLocalActionID(actionID) {
18184
+ return normalizeString32(actionID).startsWith(syntheticLocalActionIDPrefix);
18185
+ }
17419
18186
  function resolveExpectedWorkerPid(binding, runtime) {
17420
18187
  const bindingPid = Number(binding?.worker_pid ?? 0);
17421
18188
  if (Number.isFinite(bindingPid) && bindingPid > 0) {
@@ -17435,15 +18202,15 @@ function resolveExpectedIdentityWorkerPid(binding) {
17435
18202
  return 0;
17436
18203
  }
17437
18204
  function buildRevokeDedupKey({ eventID = "", sessionID = "", msgID = "" } = {}) {
17438
- const normalizedSessionID = normalizeString30(sessionID);
17439
- const normalizedMsgID = normalizeString30(msgID);
18205
+ const normalizedSessionID = normalizeString32(sessionID);
18206
+ const normalizedMsgID = normalizeString32(msgID);
17440
18207
  if (normalizedSessionID && normalizedMsgID) {
17441
18208
  return `${normalizedSessionID}:${normalizedMsgID}`;
17442
18209
  }
17443
- return normalizeString30(eventID);
18210
+ return normalizeString32(eventID);
17444
18211
  }
17445
18212
  function classifyWorkerEventResult(payload) {
17446
- const code = normalizeString30(payload?.code);
18213
+ const code = normalizeString32(payload?.code);
17447
18214
  if (workerResponseFailureCodes.has(code)) {
17448
18215
  return {
17449
18216
  state: "failed",
@@ -17453,27 +18220,28 @@ function classifyWorkerEventResult(payload) {
17453
18220
  }
17454
18221
  return {
17455
18222
  state: "healthy",
17456
- reason: code || normalizeString30(payload?.status) || "worker_event_result_observed",
18223
+ reason: code || normalizeString32(payload?.status) || "worker_event_result_observed",
17457
18224
  failureCode: ""
17458
18225
  };
17459
18226
  }
17460
- var defaultDeliveredInFlightMaxAgeMs, defaultWorkerControlProbeFailureThreshold, defaultMcpInteractionIdleMs, defaultMcpResultTimeoutMs, defaultRecentRevokeRetentionMs, defaultAuthFailureCooldownMs, defaultWorkerPingProbeRetentionMs, workerResponseFailureCodes, DaemonRuntime;
18227
+ var defaultDeliveredInFlightMaxAgeMs, defaultWorkerControlProbeFailureThreshold, defaultMcpInteractionIdleMs, defaultMcpResultTimeoutMs, defaultRecentRevokeRetentionMs, defaultAuthFailureCooldownMs, defaultWorkerPingProbeRetentionMs, syntheticLocalActionIDPrefix, workerResponseFailureCodes, DaemonRuntime;
17461
18228
  var init_runtime = __esm({
17462
18229
  "server/daemon/runtime.js"() {
17463
- init_control_command();
18230
+ init_agent_open_session_card();
17464
18231
  init_inbound_event_meta();
17465
18232
  init_message_delivery_store();
17466
18233
  init_worker_control_client();
17467
- init_control_card();
17468
18234
  init_claude_session_store();
17469
- init_control_command_handler();
17470
18235
  init_worker_health_inspector();
17471
18236
  init_pending_event_orchestrator();
17472
18237
  init_session_queue();
17473
18238
  init_process_control();
17474
18239
  init_hook_signal_store();
18240
+ init_inbound_interaction_action();
18241
+ init_session_control_action_handler();
17475
18242
  init_worker_state();
17476
18243
  init_worker_probe();
18244
+ init_protocol_contract();
17477
18245
  defaultDeliveredInFlightMaxAgeMs = 60 * 1e3;
17478
18246
  defaultWorkerControlProbeFailureThreshold = 3;
17479
18247
  defaultMcpInteractionIdleMs = 15 * 60 * 1e3;
@@ -17481,6 +18249,7 @@ var init_runtime = __esm({
17481
18249
  defaultRecentRevokeRetentionMs = 24 * 60 * 60 * 1e3;
17482
18250
  defaultAuthFailureCooldownMs = 60 * 1e3;
17483
18251
  defaultWorkerPingProbeRetentionMs = 60 * 1e3;
18252
+ syntheticLocalActionIDPrefix = "synthetic-local-action:";
17484
18253
  workerResponseFailureCodes = /* @__PURE__ */ new Set([
17485
18254
  "claude_result_timeout",
17486
18255
  "claude_usage_limit_reached",
@@ -17562,6 +18331,7 @@ var init_runtime = __esm({
17562
18331
  this.workerControlProbeFailures = /* @__PURE__ */ new Map();
17563
18332
  this.workerPingProbeRecords = /* @__PURE__ */ new Map();
17564
18333
  this.workerPingProbeInFlight = /* @__PURE__ */ new Map();
18334
+ this.syntheticLocalActionWaiters = /* @__PURE__ */ new Map();
17565
18335
  this.pendingEventWorkerLogCursors = /* @__PURE__ */ new Map();
17566
18336
  this.ensureWorkerInFlight = /* @__PURE__ */ new Map();
17567
18337
  this.resumeAuthRecoveryInFlight = /* @__PURE__ */ new Map();
@@ -17569,18 +18339,13 @@ var init_runtime = __esm({
17569
18339
  this.sessionQueues = new SessionQueueRegistry(
17570
18340
  (fields, level) => this.trace(fields, level)
17571
18341
  );
17572
- this.controlCommandHandler = new DaemonControlCommandHandler({
18342
+ this.sessionControlActionHandler = new DaemonSessionControlActionHandler({
17573
18343
  env: this.env,
17574
18344
  bindingRegistry: this.bindingRegistry,
17575
18345
  workerProcessManager: this.workerProcessManager,
17576
18346
  bridgeServer: this.bridgeServer,
17577
18347
  ensureWorker: async (...args) => this.ensureWorker(...args),
17578
- respond: async (event, text, extra = {}, result = {}) => this.respond(event, text, extra, result),
17579
- respondWithOpenWorkspaceCard: async (event, options = {}, result = {}) => this.respondWithOpenWorkspaceCard(event, options, result),
17580
- ensureDirectoryExists,
17581
- formatBindingSummary,
17582
- buildMissingBindingCardOptions,
17583
- formatRuntimeError
18348
+ ensureDirectoryExists
17584
18349
  });
17585
18350
  this.pendingEventOrchestrator = new PendingEventOrchestrator({
17586
18351
  messageDeliveryStore: this.messageDeliveryStore,
@@ -17612,18 +18377,18 @@ var init_runtime = __esm({
17612
18377
  }, { level });
17613
18378
  }
17614
18379
  async handleWorkerProcessExit({ workerID, aibotSessionID, exitCode, exitSignal }) {
17615
- const sessionID = normalizeString30(aibotSessionID);
18380
+ const sessionID = normalizeString32(aibotSessionID);
17616
18381
  if (!sessionID) return;
17617
18382
  const queue = this.sessionQueues.ensure(sessionID);
17618
18383
  queue.run(async () => {
17619
18384
  const binding = this.bindingRegistry.getByAibotSessionID(sessionID);
17620
- if (!binding || normalizeString30(binding.worker_id) !== normalizeString30(workerID)) {
18385
+ if (!binding || normalizeString32(binding.worker_id) !== normalizeString32(workerID)) {
17621
18386
  return;
17622
18387
  }
17623
18388
  if (binding.worker_status === "stopped" || binding.worker_status === "failed") {
17624
18389
  return;
17625
18390
  }
17626
- let signal = normalizeString30(exitSignal) || "wrapper_exited";
18391
+ let signal = normalizeString32(exitSignal) || "wrapper_exited";
17627
18392
  const hasAuthError = await this.workerProcessManager?.hasAuthLoginRequiredError?.(workerID);
17628
18393
  if (hasAuthError) {
17629
18394
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
@@ -17661,14 +18426,14 @@ var init_runtime = __esm({
17661
18426
  });
17662
18427
  }
17663
18428
  getWorkerPingProbeRecord(eventID) {
17664
- const normalizedEventID = normalizeString30(eventID);
18429
+ const normalizedEventID = normalizeString32(eventID);
17665
18430
  if (!normalizedEventID) {
17666
18431
  return null;
17667
18432
  }
17668
18433
  return this.workerPingProbeRecords.get(normalizedEventID) ?? null;
17669
18434
  }
17670
18435
  clearWorkerPingProbeRecord(eventID) {
17671
- const normalizedEventID = normalizeString30(eventID);
18436
+ const normalizedEventID = normalizeString32(eventID);
17672
18437
  if (!normalizedEventID) {
17673
18438
  return;
17674
18439
  }
@@ -17737,9 +18502,9 @@ var init_runtime = __esm({
17737
18502
  event_id: record.eventID,
17738
18503
  response_state: nextBinding?.worker_response_state,
17739
18504
  response_reason: nextBinding?.worker_response_reason,
17740
- terminal_status: normalizeString30(payload?.status),
17741
- terminal_code: normalizeString30(payload?.code),
17742
- probe_text: normalizeString30(payload?.text)
18505
+ terminal_status: normalizeString32(payload?.status),
18506
+ terminal_code: normalizeString32(payload?.code),
18507
+ probe_text: normalizeString32(payload?.text)
17743
18508
  }, level);
17744
18509
  this.scheduleWorkerPingProbeRecordCleanup(record.eventID);
17745
18510
  record.resolve?.(nextBinding);
@@ -17747,7 +18512,7 @@ var init_runtime = __esm({
17747
18512
  return nextBinding;
17748
18513
  }
17749
18514
  async ensureWorkerPingProbe(binding) {
17750
- const sessionID = normalizeString30(binding?.aibot_session_id);
18515
+ const sessionID = normalizeString32(binding?.aibot_session_id);
17751
18516
  if (!sessionID) {
17752
18517
  return binding;
17753
18518
  }
@@ -17769,7 +18534,7 @@ var init_runtime = __esm({
17769
18534
  }
17770
18535
  }
17771
18536
  async runWorkerPingProbe(binding) {
17772
- const sessionID = normalizeString30(binding?.aibot_session_id);
18537
+ const sessionID = normalizeString32(binding?.aibot_session_id);
17773
18538
  if (!sessionID || !hasReadyWorkerBridge(binding)) {
17774
18539
  return binding;
17775
18540
  }
@@ -17808,8 +18573,8 @@ var init_runtime = __esm({
17808
18573
  const record = {
17809
18574
  eventID: probePayload.event_id,
17810
18575
  sessionID,
17811
- workerID: normalizeString30(probingBinding?.worker_id),
17812
- claudeSessionID: normalizeString30(probingBinding?.claude_session_id),
18576
+ workerID: normalizeString32(probingBinding?.worker_id),
18577
+ claudeSessionID: normalizeString32(probingBinding?.claude_session_id),
17813
18578
  expectedReply: "pong",
17814
18579
  state: "probing",
17815
18580
  settled: false,
@@ -17849,7 +18614,7 @@ var init_runtime = __esm({
17849
18614
  worker_id: record.workerID,
17850
18615
  claude_session_id: record.claudeSessionID,
17851
18616
  event_id: record.eventID,
17852
- fallback_reason: normalizeString30(record.lastControlPingReason) || "control_ping_unavailable"
18617
+ fallback_reason: normalizeString32(record.lastControlPingReason) || "control_ping_unavailable"
17853
18618
  }, "debug");
17854
18619
  try {
17855
18620
  await client.deliverEvent(probePayload);
@@ -17895,10 +18660,10 @@ var init_runtime = __esm({
17895
18660
  }, "debug");
17896
18661
  return null;
17897
18662
  }
17898
- const expectedWorkerID = normalizeString30(record?.workerID);
17899
- const expectedClaudeSessionID = normalizeString30(record?.claudeSessionID);
17900
- const currentWorkerID = normalizeString30(currentBinding?.worker_id);
17901
- const currentClaudeSessionID = normalizeString30(currentBinding?.claude_session_id);
18663
+ const expectedWorkerID = normalizeString32(record?.workerID);
18664
+ const expectedClaudeSessionID = normalizeString32(record?.claudeSessionID);
18665
+ const currentWorkerID = normalizeString32(currentBinding?.worker_id);
18666
+ const currentClaudeSessionID = normalizeString32(currentBinding?.claude_session_id);
17902
18667
  if (expectedWorkerID && currentWorkerID && expectedWorkerID !== currentWorkerID) {
17903
18668
  record.lastControlPingReason = "worker_id_mismatch";
17904
18669
  this.trace({
@@ -17940,26 +18705,26 @@ var init_runtime = __esm({
17940
18705
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(currentWorkerID);
17941
18706
  const identityHealth = this.inspectWorkerIdentityHealth(currentBinding, runtime, pingPayload);
17942
18707
  if (!identityHealth.ok) {
17943
- record.lastControlPingReason = normalizeString30(identityHealth.reason) || "identity_unhealthy";
18708
+ record.lastControlPingReason = normalizeString32(identityHealth.reason) || "identity_unhealthy";
17944
18709
  this.trace({
17945
18710
  stage: "worker_ping_probe_control_ping_unhealthy",
17946
18711
  ...traceContext,
17947
18712
  reason: record.lastControlPingReason,
17948
18713
  expected_pid: normalizeNonNegativeInt(identityHealth.expectedPid, 0),
17949
18714
  reported_pid: normalizeNonNegativeInt(identityHealth.reportedPid, 0),
17950
- expected_worker_id: normalizeString30(identityHealth.expectedWorkerID),
17951
- reported_worker_id: normalizeString30(identityHealth.reportedWorkerID),
17952
- expected_session_id: normalizeString30(identityHealth.expectedSessionID),
17953
- reported_session_id: normalizeString30(identityHealth.reportedSessionID),
17954
- expected_claude_session_id: normalizeString30(identityHealth.expectedClaudeSessionID),
17955
- reported_claude_session_id: normalizeString30(identityHealth.reportedClaudeSessionID),
18715
+ expected_worker_id: normalizeString32(identityHealth.expectedWorkerID),
18716
+ reported_worker_id: normalizeString32(identityHealth.reportedWorkerID),
18717
+ expected_session_id: normalizeString32(identityHealth.expectedSessionID),
18718
+ reported_session_id: normalizeString32(identityHealth.reportedSessionID),
18719
+ expected_claude_session_id: normalizeString32(identityHealth.expectedClaudeSessionID),
18720
+ reported_claude_session_id: normalizeString32(identityHealth.reportedClaudeSessionID),
17956
18721
  ...buildPingActivityTraceFields(pingPayload)
17957
18722
  });
17958
18723
  return null;
17959
18724
  }
17960
18725
  const mcpHealth = this.inspectMcpInteractionHealth(currentBinding, pingPayload);
17961
18726
  if (!mcpHealth.ok) {
17962
- record.lastControlPingReason = normalizeString30(mcpHealth.reason) || "mcp_unhealthy";
18727
+ record.lastControlPingReason = normalizeString32(mcpHealth.reason) || "mcp_unhealthy";
17963
18728
  this.trace({
17964
18729
  stage: "worker_ping_probe_control_ping_unhealthy",
17965
18730
  ...traceContext,
@@ -18020,7 +18785,7 @@ var init_runtime = __esm({
18020
18785
  if (record.settled) {
18021
18786
  return { handled: true, ack: { msg_id: `probe_${record.eventID}` } };
18022
18787
  }
18023
- const replyText = normalizeString30(payload?.text);
18788
+ const replyText = normalizeString32(payload?.text);
18024
18789
  if (isExpectedWorkerProbeReply(replyText, record.expectedReply)) {
18025
18790
  await this.updateWorkerPingProbeOutcome(record, {
18026
18791
  state: "healthy",
@@ -18044,8 +18809,8 @@ var init_runtime = __esm({
18044
18809
  return { handled: false };
18045
18810
  }
18046
18811
  if (!record.settled) {
18047
- const status = normalizeString30(payload?.status);
18048
- const code = normalizeString30(payload?.code);
18812
+ const status = normalizeString32(payload?.status);
18813
+ const code = normalizeString32(payload?.code);
18049
18814
  if (record.timeoutRecovering && status !== "responded" && code === "claude_result_timeout") {
18050
18815
  this.trace({
18051
18816
  stage: "worker_ping_probe_event_result_ignored_timeout_during_recovery",
@@ -18084,6 +18849,9 @@ var init_runtime = __esm({
18084
18849
  this.clearWorkerPingProbeRecord(eventID);
18085
18850
  }
18086
18851
  this.workerPingProbeInFlight.clear();
18852
+ for (const actionID of [...this.syntheticLocalActionWaiters.keys()]) {
18853
+ this.clearSyntheticLocalActionWaiter(actionID);
18854
+ }
18087
18855
  this.ensureWorkerInFlight.clear();
18088
18856
  this.resumeAuthRecoveryInFlight.clear();
18089
18857
  this.lastAuthRecoverySpawnAt.clear();
@@ -18120,8 +18888,8 @@ var init_runtime = __esm({
18120
18888
  event_id: event.event_id,
18121
18889
  status
18122
18890
  };
18123
- const normalizedCode = normalizeString30(code);
18124
- const normalizedMsg = normalizeString30(msg);
18891
+ const normalizedCode = normalizeString32(code);
18892
+ const normalizedMsg = normalizeString32(msg);
18125
18893
  if (normalizedCode) {
18126
18894
  payload.code = normalizedCode;
18127
18895
  }
@@ -18142,26 +18910,278 @@ var init_runtime = __esm({
18142
18910
  this.complete(event, result);
18143
18911
  return response;
18144
18912
  }
18145
- async respondWithOpenWorkspaceCard(event, {
18146
- summaryText,
18147
- detailText,
18148
- initialCwd = "",
18149
- replySource = ""
18150
- } = {}, result = {}) {
18151
- const fallbackText = normalizeString30(summaryText) || "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u7ED1\u5B9A\u76EE\u5F55\u3002";
18152
- return this.respond(
18913
+ createSyntheticLocalActionWaiter(actionID, sessionID, timeoutMs) {
18914
+ const normalizedActionID = normalizeString32(actionID);
18915
+ const normalizedSessionID = normalizeString32(sessionID);
18916
+ const effectiveTimeoutMs = Math.max(1, normalizeNonNegativeInt(timeoutMs, 15e3));
18917
+ let resolvePromise = () => {
18918
+ };
18919
+ const promise = new Promise((resolve) => {
18920
+ resolvePromise = resolve;
18921
+ });
18922
+ const timer = setTimeout(() => {
18923
+ if (!this.syntheticLocalActionWaiters.has(normalizedActionID)) {
18924
+ return;
18925
+ }
18926
+ this.syntheticLocalActionWaiters.delete(normalizedActionID);
18927
+ resolvePromise({
18928
+ status: localActionResultStatuses.failed,
18929
+ result: void 0,
18930
+ errorCode: "local_action_result_timeout",
18931
+ errorMsg: "worker local action result timed out"
18932
+ });
18933
+ }, effectiveTimeoutMs);
18934
+ timer.unref?.();
18935
+ this.syntheticLocalActionWaiters.set(normalizedActionID, {
18936
+ sessionID: normalizedSessionID,
18937
+ resolve: resolvePromise,
18938
+ timer
18939
+ });
18940
+ return promise;
18941
+ }
18942
+ clearSyntheticLocalActionWaiter(actionID) {
18943
+ const normalizedActionID = normalizeString32(actionID);
18944
+ const pending = this.syntheticLocalActionWaiters.get(normalizedActionID);
18945
+ if (!pending) {
18946
+ return null;
18947
+ }
18948
+ clearTimeout(pending.timer);
18949
+ this.syntheticLocalActionWaiters.delete(normalizedActionID);
18950
+ return pending;
18951
+ }
18952
+ resolveSyntheticLocalActionWaiter(actionID, result) {
18953
+ const pending = this.clearSyntheticLocalActionWaiter(actionID);
18954
+ if (!pending) {
18955
+ return false;
18956
+ }
18957
+ pending.resolve(result);
18958
+ return true;
18959
+ }
18960
+ async observeWorkerLocalActionResult(payload) {
18961
+ const actionID = normalizeString32(payload?.action_id);
18962
+ if (!actionID) {
18963
+ return { handled: false };
18964
+ }
18965
+ const pending = this.syntheticLocalActionWaiters.get(actionID);
18966
+ if (!pending) {
18967
+ if (isSyntheticLocalActionID(actionID)) {
18968
+ this.trace({
18969
+ stage: "synthetic_local_action_result_ignored_late",
18970
+ action_id: actionID,
18971
+ session_id: this.resolveObservedSessionID(payload),
18972
+ worker_id: payload?.worker_id,
18973
+ claude_session_id: payload?.claude_session_id
18974
+ });
18975
+ return { handled: true };
18976
+ }
18977
+ return { handled: false };
18978
+ }
18979
+ const binding = this.bindingRegistry.getByAibotSessionID(pending.sessionID);
18980
+ if (binding && this.shouldIgnoreObservedWorker(binding, payload)) {
18981
+ this.trace({
18982
+ stage: "synthetic_local_action_result_ignored",
18983
+ action_id: actionID,
18984
+ session_id: pending.sessionID,
18985
+ worker_id: payload?.worker_id,
18986
+ claude_session_id: payload?.claude_session_id
18987
+ });
18988
+ return { handled: true };
18989
+ }
18990
+ this.trace({
18991
+ stage: "synthetic_local_action_result_observed",
18992
+ action_id: actionID,
18993
+ session_id: pending.sessionID,
18994
+ status: payload?.status,
18995
+ worker_id: payload?.worker_id
18996
+ });
18997
+ this.resolveSyntheticLocalActionWaiter(actionID, {
18998
+ status: normalizeString32(payload?.status) || localActionResultStatuses.failed,
18999
+ result: payload?.result,
19000
+ errorCode: normalizeString32(payload?.error_code),
19001
+ errorMsg: normalizeString32(payload?.error_msg)
19002
+ });
19003
+ return { handled: true };
19004
+ }
19005
+ async runSyntheticWorkerLocalAction(event, action) {
19006
+ const normalizedActionType = normalizeString32(action?.action_type);
19007
+ const params = action?.params && typeof action.params === "object" && !Array.isArray(action.params) ? action.params : {};
19008
+ const sessionID = normalizeString32(params.session_id) || normalizeString32(event?.session_id);
19009
+ if (!sessionID) {
19010
+ return {
19011
+ status: localActionResultStatuses.failed,
19012
+ result: void 0,
19013
+ errorCode: localActionErrorCodes.localActionRouteMissing,
19014
+ errorMsg: "local action session_id is required"
19015
+ };
19016
+ }
19017
+ const timeoutMs = Math.max(1, normalizeNonNegativeInt(action?.timeout_ms, 15e3));
19018
+ const actionID = `${syntheticLocalActionIDPrefix}${event?.event_id || randomUUID8()}:${randomUUID8()}`;
19019
+ const payload = {
19020
+ action_id: actionID,
19021
+ event_id: normalizeString32(event?.event_id),
19022
+ action_type: normalizedActionType,
19023
+ params: {
19024
+ ...params,
19025
+ session_id: sessionID
19026
+ },
19027
+ timeout_ms: timeoutMs
19028
+ };
19029
+ const waitPromise = this.createSyntheticLocalActionWaiter(actionID, sessionID, timeoutMs);
19030
+ try {
19031
+ const routedBinding = await this.deliverWithRecovery(
19032
+ sessionID,
19033
+ payload,
19034
+ this.deliverLocalActionToWorker
19035
+ );
19036
+ if (routedBinding && canDeliverToWorker(routedBinding)) {
19037
+ return waitPromise;
19038
+ }
19039
+ this.resolveSyntheticLocalActionWaiter(actionID, {
19040
+ status: localActionResultStatuses.failed,
19041
+ result: void 0,
19042
+ errorCode: "local_action_delivery_failed",
19043
+ errorMsg: "worker is not ready for local action delivery"
19044
+ });
19045
+ return waitPromise;
19046
+ } catch (error) {
19047
+ this.resolveSyntheticLocalActionWaiter(actionID, {
19048
+ status: localActionResultStatuses.failed,
19049
+ result: void 0,
19050
+ errorCode: "local_action_delivery_failed",
19051
+ errorMsg: normalizeString32(error?.message || error) || "worker local action delivery failed"
19052
+ });
19053
+ return waitPromise;
19054
+ }
19055
+ }
19056
+ async handleSyntheticSessionControlEvent(event, action) {
19057
+ const params = action?.params && typeof action.params === "object" && !Array.isArray(action.params) ? action.params : {};
19058
+ const sessionControlResult = await this.sessionControlActionHandler.handleLocalAction({
19059
+ action_type: localActionTypes.sessionControl,
19060
+ params: {
19061
+ ...params,
19062
+ session_id: event.session_id
19063
+ }
19064
+ });
19065
+ if (!sessionControlResult?.handled) {
19066
+ return false;
19067
+ }
19068
+ const response = sessionControlResult.response ?? {};
19069
+ const result = response.result ?? {};
19070
+ if (response.status === localActionResultStatuses.ok && normalizeString32(result.domain) === resultDomains.sessionControl) {
19071
+ await this.respond(event, buildSessionControlSuccessNotice(result), {}, {
19072
+ status: "responded"
19073
+ });
19074
+ return true;
19075
+ }
19076
+ const errorCode = normalizeString32(response.errorCode);
19077
+ const errorMsg = normalizeString32(response.errorMsg);
19078
+ if (errorCode === sessionControlErrorCodes.cwdRequired || errorCode === sessionControlErrorCodes.invalidCwd || errorCode === sessionControlErrorCodes.bindingMissing) {
19079
+ await this.respond(
19080
+ event,
19081
+ buildSessionControlOpenCardNotice({
19082
+ summaryText: buildSessionControlCardSummary(errorCode, errorMsg),
19083
+ initialCwd: normalizeString32(params.cwd)
19084
+ }),
19085
+ {},
19086
+ {
19087
+ status: "responded",
19088
+ code: errorCode,
19089
+ msg: errorMsg
19090
+ }
19091
+ );
19092
+ return true;
19093
+ }
19094
+ await this.respond(
18153
19095
  event,
18154
- fallbackText,
19096
+ buildSessionControlFailureNotice({
19097
+ errorCode,
19098
+ errorMsg
19099
+ }),
19100
+ {},
18155
19101
  {
18156
- ...replySource ? { reply_source: replySource } : {},
18157
- biz_card: buildOpenWorkspaceCard({
18158
- summaryText,
18159
- detailText,
18160
- initialCwd
18161
- })
18162
- },
18163
- result
19102
+ status: "responded",
19103
+ code: errorCode,
19104
+ msg: errorMsg
19105
+ }
19106
+ );
19107
+ return true;
19108
+ }
19109
+ async handleSyntheticInteractionReplyEvent(event, action) {
19110
+ const actionResult = await this.runSyntheticWorkerLocalAction(event, action);
19111
+ if (normalizeString32(actionResult?.status) === localActionResultStatuses.ok) {
19112
+ this.complete(event, {
19113
+ status: "responded"
19114
+ });
19115
+ return true;
19116
+ }
19117
+ const errorCode = normalizeString32(actionResult?.errorCode);
19118
+ const errorMsg = normalizeString32(actionResult?.errorMsg);
19119
+ await this.respond(
19120
+ event,
19121
+ buildInteractionReplyFailureNotice({
19122
+ errorCode,
19123
+ errorMsg
19124
+ }),
19125
+ {},
19126
+ {
19127
+ status: "responded",
19128
+ code: errorCode,
19129
+ msg: errorMsg
19130
+ }
18164
19131
  );
19132
+ return true;
19133
+ }
19134
+ async handleInteractionActionEvent(event) {
19135
+ const parsed = parseInboundInteractionAction(event.content);
19136
+ if (!parsed.matched) {
19137
+ return false;
19138
+ }
19139
+ this.trace({
19140
+ stage: "interaction_action_received",
19141
+ event_id: event.event_id,
19142
+ session_id: event.session_id,
19143
+ source: parsed.source,
19144
+ action_type: parsed.action?.action_type,
19145
+ ok: parsed.ok === true
19146
+ });
19147
+ if (!parsed.ok) {
19148
+ if (parsed.errorCode === sessionControlErrorCodes.cwdRequired) {
19149
+ await this.respond(
19150
+ event,
19151
+ buildSessionControlOpenCardNotice({
19152
+ summaryText: buildSessionControlCardSummary(parsed.errorCode, parsed.errorMsg)
19153
+ }),
19154
+ {},
19155
+ {
19156
+ status: "responded",
19157
+ code: parsed.errorCode,
19158
+ msg: parsed.errorMsg
19159
+ }
19160
+ );
19161
+ return true;
19162
+ }
19163
+ await this.respond(
19164
+ event,
19165
+ buildInteractionReplyFailureNotice({
19166
+ errorCode: parsed.errorCode,
19167
+ errorMsg: parsed.errorMsg
19168
+ }),
19169
+ {},
19170
+ {
19171
+ status: "responded",
19172
+ code: parsed.errorCode,
19173
+ msg: parsed.errorMsg
19174
+ }
19175
+ );
19176
+ return true;
19177
+ }
19178
+ if (normalizeString32(parsed.action?.action_type) === localActionTypes.sessionControl) {
19179
+ return this.handleSyntheticSessionControlEvent(event, parsed.action);
19180
+ }
19181
+ if (normalizeString32(parsed.action?.action_type) === localActionTypes.interactionReply) {
19182
+ return this.handleSyntheticInteractionReplyEvent(event, parsed.action);
19183
+ }
19184
+ return false;
18165
19185
  }
18166
19186
  ack(event) {
18167
19187
  this.aibotClient.ackEvent(event.event_id, {
@@ -18177,8 +19197,8 @@ var init_runtime = __esm({
18177
19197
  });
18178
19198
  }
18179
19199
  async shouldResumeClaudeSession(binding) {
18180
- const claudeSessionID = normalizeString30(binding?.claude_session_id);
18181
- const cwd = normalizeString30(binding?.cwd);
19200
+ const claudeSessionID = normalizeString32(binding?.claude_session_id);
19201
+ const cwd = normalizeString32(binding?.cwd);
18182
19202
  if (!claudeSessionID || !cwd) {
18183
19203
  return false;
18184
19204
  }
@@ -18198,19 +19218,19 @@ var init_runtime = __esm({
18198
19218
  if (this.authFailureCooldownMs <= 0) {
18199
19219
  return null;
18200
19220
  }
18201
- const normalizedStatus = normalizeString30(binding?.worker_status);
19221
+ const normalizedStatus = normalizeString32(binding?.worker_status);
18202
19222
  if (normalizedStatus !== "stopped" && normalizedStatus !== "failed") {
18203
19223
  return null;
18204
19224
  }
18205
- const workerID = normalizeString30(binding?.worker_id);
19225
+ const workerID = normalizeString32(binding?.worker_id);
18206
19226
  if (!workerID) {
18207
19227
  return null;
18208
19228
  }
18209
19229
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
18210
- if (normalizeString30(runtime?.status) !== "stopped") {
19230
+ if (normalizeString32(runtime?.status) !== "stopped") {
18211
19231
  return null;
18212
19232
  }
18213
- if (normalizeString30(runtime?.exit_signal) !== "auth_login_required") {
19233
+ if (normalizeString32(runtime?.exit_signal) !== "auth_login_required") {
18214
19234
  return null;
18215
19235
  }
18216
19236
  const runtimeStoppedAt = Number(runtime?.stopped_at ?? 0);
@@ -18233,7 +19253,7 @@ var init_runtime = __esm({
18233
19253
  };
18234
19254
  }
18235
19255
  async ensureWorker(binding, { ignoreAuthCooldown = false } = {}) {
18236
- const sessionID = normalizeString30(binding?.aibot_session_id);
19256
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18237
19257
  if (!sessionID) {
18238
19258
  return null;
18239
19259
  }
@@ -18314,7 +19334,7 @@ var init_runtime = __esm({
18314
19334
  };
18315
19335
  }
18316
19336
  const currentReadyFailed = hasReadyWorkerBridge(current) && normalizeWorkerResponseState(current?.worker_response_state) === "failed";
18317
- const workerID2 = normalizeString30(binding.worker_id);
19337
+ const workerID2 = normalizeString32(binding.worker_id);
18318
19338
  if (!currentReadyFailed && workerID2) {
18319
19339
  const existingRuntime = this.workerProcessManager?.getWorkerRuntime?.(workerID2);
18320
19340
  const existingPid = Number(existingRuntime?.pid ?? 0);
@@ -18393,13 +19413,13 @@ var init_runtime = __esm({
18393
19413
  if (current && current.worker_status === "ready" && current.worker_control_url && current.worker_control_token) {
18394
19414
  return current;
18395
19415
  }
18396
- await sleep2(intervalMs);
19416
+ await sleep3(intervalMs);
18397
19417
  }
18398
19418
  return this.bindingRegistry.getByAibotSessionID(aibotSessionID);
18399
19419
  }
18400
19420
  async resolveWorkerLaunchFailure(binding) {
18401
- const workerID = normalizeString30(binding?.worker_id);
18402
- const workerStatus = normalizeString30(binding?.worker_status);
19421
+ const workerID = normalizeString32(binding?.worker_id);
19422
+ const workerStatus = normalizeString32(binding?.worker_status);
18403
19423
  if (!workerID || !["starting", "connected"].includes(workerStatus)) {
18404
19424
  return "";
18405
19425
  }
@@ -18433,27 +19453,27 @@ var init_runtime = __esm({
18433
19453
  if (current2.worker_status === "stopped" || current2.worker_status === "failed") {
18434
19454
  return current2;
18435
19455
  }
18436
- await sleep2(intervalMs);
19456
+ await sleep3(intervalMs);
18437
19457
  }
18438
19458
  const current = this.bindingRegistry.getByAibotSessionID(aibotSessionID);
18439
19459
  const launchFailure = await this.resolveWorkerLaunchFailure(current);
18440
19460
  if (launchFailure) {
18441
19461
  return withWorkerLaunchFailure(current, launchFailure);
18442
19462
  }
18443
- if (["starting", "connected"].includes(normalizeString30(current?.worker_status))) {
19463
+ if (["starting", "connected"].includes(normalizeString32(current?.worker_status))) {
18444
19464
  return withWorkerLaunchFailure(current, "startup_wait_timeout");
18445
19465
  }
18446
19466
  return current;
18447
19467
  }
18448
19468
  clearWorkerControlProbeFailure(workerID) {
18449
- const normalizedWorkerID = normalizeString30(workerID);
19469
+ const normalizedWorkerID = normalizeString32(workerID);
18450
19470
  if (!normalizedWorkerID) {
18451
19471
  return;
18452
19472
  }
18453
19473
  this.workerControlProbeFailures.delete(normalizedWorkerID);
18454
19474
  }
18455
19475
  markWorkerControlProbeFailure(workerID, error, extraFields = {}) {
18456
- const normalizedWorkerID = normalizeString30(workerID);
19476
+ const normalizedWorkerID = normalizeString32(workerID);
18457
19477
  if (!normalizedWorkerID) {
18458
19478
  return 0;
18459
19479
  }
@@ -18492,22 +19512,22 @@ var init_runtime = __esm({
18492
19512
  });
18493
19513
  }
18494
19514
  resolveObservedSessionID(payload = {}) {
18495
- const explicitSessionID = normalizeString30(payload?.session_id);
19515
+ const explicitSessionID = normalizeString32(payload?.session_id);
18496
19516
  if (explicitSessionID) {
18497
19517
  return explicitSessionID;
18498
19518
  }
18499
- return normalizeString30(this.messageDeliveryStore.getRememberedSessionID(payload?.event_id));
19519
+ return normalizeString32(this.messageDeliveryStore.getRememberedSessionID(payload?.event_id));
18500
19520
  }
18501
19521
  shouldIgnoreObservedWorker(binding, payload = {}) {
18502
19522
  if (!binding) {
18503
19523
  return false;
18504
19524
  }
18505
- const observedWorkerID = normalizeString30(payload?.worker_id);
18506
- if (observedWorkerID && normalizeString30(binding?.worker_id) && observedWorkerID !== normalizeString30(binding.worker_id)) {
19525
+ const observedWorkerID = normalizeString32(payload?.worker_id);
19526
+ if (observedWorkerID && normalizeString32(binding?.worker_id) && observedWorkerID !== normalizeString32(binding.worker_id)) {
18507
19527
  return true;
18508
19528
  }
18509
- const observedClaudeSessionID = normalizeString30(payload?.claude_session_id);
18510
- if (observedClaudeSessionID && normalizeString30(binding?.claude_session_id) && observedClaudeSessionID !== normalizeString30(binding.claude_session_id)) {
19529
+ const observedClaudeSessionID = normalizeString32(payload?.claude_session_id);
19530
+ if (observedClaudeSessionID && normalizeString32(binding?.claude_session_id) && observedClaudeSessionID !== normalizeString32(binding.claude_session_id)) {
18511
19531
  return true;
18512
19532
  }
18513
19533
  return false;
@@ -18517,10 +19537,10 @@ var init_runtime = __esm({
18517
19537
  stage,
18518
19538
  event_id: payload?.event_id,
18519
19539
  session_id: this.resolveObservedSessionID(payload),
18520
- worker_id: normalizeString30(payload?.worker_id),
18521
- expected_worker_id: normalizeString30(binding?.worker_id),
18522
- claude_session_id: normalizeString30(payload?.claude_session_id),
18523
- expected_claude_session_id: normalizeString30(binding?.claude_session_id)
19540
+ worker_id: normalizeString32(payload?.worker_id),
19541
+ expected_worker_id: normalizeString32(binding?.worker_id),
19542
+ claude_session_id: normalizeString32(payload?.claude_session_id),
19543
+ expected_claude_session_id: normalizeString32(binding?.claude_session_id)
18524
19544
  }, "error");
18525
19545
  }
18526
19546
  async recordWorkerReplyObserved(payload, { kind = "text" } = {}) {
@@ -18583,19 +19603,19 @@ var init_runtime = __esm({
18583
19603
  response_state: nextBinding?.worker_response_state,
18584
19604
  response_reason: nextBinding?.worker_response_reason,
18585
19605
  event_id: payload?.event_id,
18586
- terminal_status: normalizeString30(payload?.status),
18587
- terminal_code: normalizeString30(payload?.code)
19606
+ terminal_status: normalizeString32(payload?.status),
19607
+ terminal_code: normalizeString32(payload?.code)
18588
19608
  }, classification.state === "failed" ? "error" : "info");
18589
19609
  return nextBinding;
18590
19610
  }
18591
19611
  async recordWorkerHookSignalsObserved(binding, pingPayload) {
18592
- const sessionID = normalizeString30(binding?.aibot_session_id);
19612
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18593
19613
  if (!sessionID) {
18594
19614
  return binding;
18595
19615
  }
18596
19616
  let nextBinding = binding;
18597
19617
  let lastEventAt = Number(binding?.worker_last_hook_event_at ?? 0);
18598
- let lastEventID = normalizeString30(binding?.worker_last_hook_event_id);
19618
+ let lastEventID = normalizeString32(binding?.worker_last_hook_event_id);
18599
19619
  for (const event of listHookSignalRecords(pingPayload)) {
18600
19620
  const isNewer = event.event_at > lastEventAt || event.event_at === lastEventAt && event.event_id !== lastEventID;
18601
19621
  if (!isNewer) {
@@ -18625,16 +19645,16 @@ var init_runtime = __esm({
18625
19645
  if (this.workerControlProbeFailureThreshold <= 0) {
18626
19646
  return { ok: true };
18627
19647
  }
18628
- if (normalizeString30(binding?.worker_status) !== "ready") {
19648
+ if (normalizeString32(binding?.worker_status) !== "ready") {
18629
19649
  return { ok: true };
18630
19650
  }
18631
- const workerID = normalizeString30(binding?.worker_id);
19651
+ const workerID = normalizeString32(binding?.worker_id);
18632
19652
  if (!workerID) {
18633
19653
  return { ok: true };
18634
19654
  }
18635
19655
  const probeTraceFields = {
18636
- session_id: normalizeString30(binding?.aibot_session_id),
18637
- claude_session_id: normalizeString30(binding?.claude_session_id),
19656
+ session_id: normalizeString32(binding?.aibot_session_id),
19657
+ claude_session_id: normalizeString32(binding?.claude_session_id),
18638
19658
  expected_pid: resolveExpectedWorkerPid(binding, runtime)
18639
19659
  };
18640
19660
  let client = null;
@@ -18673,12 +19693,12 @@ var init_runtime = __esm({
18673
19693
  reason: identityHealth.reason,
18674
19694
  expected_pid: normalizeNonNegativeInt(identityHealth.expectedPid, 0),
18675
19695
  reported_pid: normalizeNonNegativeInt(identityHealth.reportedPid, 0),
18676
- expected_worker_id: normalizeString30(identityHealth.expectedWorkerID),
18677
- reported_worker_id: normalizeString30(identityHealth.reportedWorkerID),
18678
- expected_session_id: normalizeString30(identityHealth.expectedSessionID),
18679
- reported_session_id: normalizeString30(identityHealth.reportedSessionID),
18680
- expected_claude_session_id: normalizeString30(identityHealth.expectedClaudeSessionID),
18681
- reported_claude_session_id: normalizeString30(identityHealth.reportedClaudeSessionID),
19696
+ expected_worker_id: normalizeString32(identityHealth.expectedWorkerID),
19697
+ reported_worker_id: normalizeString32(identityHealth.reportedWorkerID),
19698
+ expected_session_id: normalizeString32(identityHealth.expectedSessionID),
19699
+ reported_session_id: normalizeString32(identityHealth.reportedSessionID),
19700
+ expected_claude_session_id: normalizeString32(identityHealth.expectedClaudeSessionID),
19701
+ reported_claude_session_id: normalizeString32(identityHealth.reportedClaudeSessionID),
18682
19702
  ...buildPingActivityTraceFields(pingPayload)
18683
19703
  });
18684
19704
  const failures = this.markWorkerControlProbeFailure(
@@ -18750,6 +19770,13 @@ var init_runtime = __esm({
18750
19770
  }
18751
19771
  return client.deliverRevoke(rawPayload);
18752
19772
  }
19773
+ async deliverLocalActionToWorker(binding, rawPayload) {
19774
+ const client = this.workerControlClientFactory(binding);
19775
+ if (!client?.isConfigured?.()) {
19776
+ throw new Error("worker control client is not configured");
19777
+ }
19778
+ return client.deliverLocalAction(rawPayload);
19779
+ }
18753
19780
  async trackPendingEvent(rawPayload) {
18754
19781
  return this.pendingEventOrchestrator.trackPendingEvent(rawPayload);
18755
19782
  }
@@ -18766,22 +19793,22 @@ var init_runtime = __esm({
18766
19793
  return this.pendingEventOrchestrator.markPendingEventInterrupted(eventID);
18767
19794
  }
18768
19795
  async clearPendingEvent(eventID) {
18769
- const normalizedEventID = normalizeString30(eventID);
19796
+ const normalizedEventID = normalizeString32(eventID);
18770
19797
  if (normalizedEventID) {
18771
19798
  this.pendingEventWorkerLogCursors.delete(normalizedEventID);
18772
19799
  }
18773
19800
  return this.pendingEventOrchestrator.clearPendingEvent(eventID);
18774
19801
  }
18775
19802
  getPendingEventWorkerLogCursor(eventID) {
18776
- const normalizedEventID = normalizeString30(eventID);
19803
+ const normalizedEventID = normalizeString32(eventID);
18777
19804
  if (!normalizedEventID) {
18778
19805
  return null;
18779
19806
  }
18780
19807
  return this.pendingEventWorkerLogCursors.get(normalizedEventID) ?? null;
18781
19808
  }
18782
19809
  async recordPendingEventWorkerLogCursor(eventID, workerID) {
18783
- const normalizedEventID = normalizeString30(eventID);
18784
- const normalizedWorkerID = normalizeString30(workerID);
19810
+ const normalizedEventID = normalizeString32(eventID);
19811
+ const normalizedWorkerID = normalizeString32(workerID);
18785
19812
  if (!normalizedEventID || !normalizedWorkerID) {
18786
19813
  return null;
18787
19814
  }
@@ -18822,19 +19849,19 @@ var init_runtime = __esm({
18822
19849
  return this.pendingEventOrchestrator.touchPendingEventComposing(eventID);
18823
19850
  }
18824
19851
  async handleWorkerSessionComposing(payload = {}) {
18825
- const eventID = normalizeString30(payload.ref_event_id);
19852
+ const eventID = normalizeString32(payload.ref_event_id);
18826
19853
  if (!eventID) {
18827
19854
  return null;
18828
19855
  }
18829
- const workerID = normalizeString30(payload.worker_id);
18830
- const workerSessionID = normalizeString30(payload.session_id || payload.aibot_session_id);
18831
- const claudeSessionID = normalizeString30(payload.claude_session_id);
19856
+ const workerID = normalizeString32(payload.worker_id);
19857
+ const workerSessionID = normalizeString32(payload.session_id || payload.aibot_session_id);
19858
+ const claudeSessionID = normalizeString32(payload.claude_session_id);
18832
19859
  const reportedPid = Number(payload.pid ?? 0);
18833
19860
  const record = this.getPendingEvent(eventID);
18834
19861
  if (!record) {
18835
19862
  return null;
18836
19863
  }
18837
- const deliveryState = normalizeString30(record.delivery_state);
19864
+ const deliveryState = normalizeString32(record.delivery_state);
18838
19865
  if (deliveryState !== "dispatching" && deliveryState !== "delivered") {
18839
19866
  this.trace({
18840
19867
  stage: "pending_event_activity_rejected",
@@ -18845,7 +19872,7 @@ var init_runtime = __esm({
18845
19872
  }, "error");
18846
19873
  return null;
18847
19874
  }
18848
- const sessionID = normalizeString30(record.sessionID);
19875
+ const sessionID = normalizeString32(record.sessionID);
18849
19876
  if (workerSessionID && workerSessionID !== sessionID) {
18850
19877
  this.trace({
18851
19878
  stage: "pending_event_activity_rejected",
@@ -18866,7 +19893,7 @@ var init_runtime = __esm({
18866
19893
  }, "error");
18867
19894
  return null;
18868
19895
  }
18869
- const expectedWorkerID = normalizeString30(binding.worker_id);
19896
+ const expectedWorkerID = normalizeString32(binding.worker_id);
18870
19897
  if (!workerID || !expectedWorkerID || workerID !== expectedWorkerID) {
18871
19898
  this.trace({
18872
19899
  stage: "pending_event_activity_rejected",
@@ -18892,7 +19919,7 @@ var init_runtime = __esm({
18892
19919
  return null;
18893
19920
  }
18894
19921
  }
18895
- const dispatchedWorkerID = normalizeString30(record.last_worker_id);
19922
+ const dispatchedWorkerID = normalizeString32(record.last_worker_id);
18896
19923
  if (dispatchedWorkerID && workerID !== dispatchedWorkerID) {
18897
19924
  this.trace({
18898
19925
  stage: "pending_event_activity_rejected",
@@ -18904,7 +19931,7 @@ var init_runtime = __esm({
18904
19931
  }, "error");
18905
19932
  return null;
18906
19933
  }
18907
- const expectedClaudeSessionID = normalizeString30(binding.claude_session_id);
19934
+ const expectedClaudeSessionID = normalizeString32(binding.claude_session_id);
18908
19935
  if (!claudeSessionID || !expectedClaudeSessionID || claudeSessionID !== expectedClaudeSessionID) {
18909
19936
  this.trace({
18910
19937
  stage: "pending_event_activity_rejected",
@@ -18941,12 +19968,12 @@ var init_runtime = __esm({
18941
19968
  async flushStalePendingEvents() {
18942
19969
  const bindings = this.bindingRegistry?.listBindings?.() ?? [];
18943
19970
  for (const binding of bindings) {
18944
- const sessionID = normalizeString30(binding?.aibot_session_id);
19971
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18945
19972
  if (!sessionID) continue;
18946
19973
  if (!canDeliverToWorker(binding)) continue;
18947
19974
  const pendingEvents = this.listPendingEventsForSession(sessionID);
18948
19975
  const hasPending = pendingEvents.some(
18949
- (r) => normalizeString30(r.delivery_state) === "pending"
19976
+ (r) => normalizeString32(r.delivery_state) === "pending"
18950
19977
  );
18951
19978
  if (!hasPending) continue;
18952
19979
  const queue = this.sessionQueues.ensure(sessionID);
@@ -18966,7 +19993,6 @@ var init_runtime = __esm({
18966
19993
  async failPendingEvent(record, {
18967
19994
  notifyText = true,
18968
19995
  noticeText = buildInterruptedEventNotice(),
18969
- replySource = "daemon_worker_interrupted",
18970
19996
  resultCode = "worker_interrupted",
18971
19997
  resultMessage = "worker interrupted while processing event"
18972
19998
  } = {}) {
@@ -18983,10 +20009,7 @@ var init_runtime = __esm({
18983
20009
  eventID: record.eventID,
18984
20010
  sessionID: record.sessionID,
18985
20011
  text: noticeText,
18986
- quotedMessageID: record.msgID,
18987
- extra: {
18988
- reply_source: replySource
18989
- }
20012
+ quotedMessageID: record.msgID
18990
20013
  });
18991
20014
  } catch {
18992
20015
  }
@@ -19009,7 +20032,7 @@ var init_runtime = __esm({
19009
20032
  }, "error");
19010
20033
  }
19011
20034
  async resolveWorkerFailureEventOptions(workerID) {
19012
- const normalizedWorkerID = normalizeString30(workerID);
20035
+ const normalizedWorkerID = normalizeString32(workerID);
19013
20036
  if (!normalizedWorkerID) {
19014
20037
  return null;
19015
20038
  }
@@ -19027,23 +20050,22 @@ var init_runtime = __esm({
19027
20050
  }
19028
20051
  return {
19029
20052
  noticeText: buildAuthLoginRequiredEventNotice(),
19030
- replySource: "daemon_worker_auth_login_required",
19031
20053
  resultCode: "claude_auth_login_required",
19032
20054
  resultMessage: "claude authentication expired; run claude auth login"
19033
20055
  };
19034
20056
  }
19035
20057
  resolveWorkerIDForEventResult(payload) {
19036
- const explicitWorkerID = normalizeString30(payload?.worker_id);
20058
+ const explicitWorkerID = normalizeString32(payload?.worker_id);
19037
20059
  if (explicitWorkerID) {
19038
20060
  return explicitWorkerID;
19039
20061
  }
19040
20062
  const sessionID = this.resolveObservedSessionID(payload);
19041
20063
  const binding = sessionID ? this.bindingRegistry.getByAibotSessionID(sessionID) : null;
19042
- return normalizeString30(binding?.worker_id);
20064
+ return normalizeString32(binding?.worker_id);
19043
20065
  }
19044
20066
  async resolveWorkerEventResultFailureOptions(payload) {
19045
- const status = normalizeString30(payload?.status);
19046
- const code = normalizeString30(payload?.code);
20067
+ const status = normalizeString32(payload?.status);
20068
+ const code = normalizeString32(payload?.code);
19047
20069
  if (status !== "failed" || code !== "claude_result_timeout") {
19048
20070
  return null;
19049
20071
  }
@@ -19051,7 +20073,7 @@ var init_runtime = __esm({
19051
20073
  if (!workerID) {
19052
20074
  return null;
19053
20075
  }
19054
- const eventID = normalizeString30(payload?.event_id);
20076
+ const eventID = normalizeString32(payload?.event_id);
19055
20077
  const logCursor = this.getPendingEventWorkerLogCursor(eventID);
19056
20078
  const hasExtraUsageLimitPrompt = await this.workerProcessManager?.hasExtraUsageLimitPrompt?.(
19057
20079
  workerID,
@@ -19079,7 +20101,7 @@ var init_runtime = __esm({
19079
20101
  if (!failureOptions?.noticeText) {
19080
20102
  return null;
19081
20103
  }
19082
- const eventID = normalizeString30(payload?.event_id);
20104
+ const eventID = normalizeString32(payload?.event_id);
19083
20105
  const record = this.getPendingEvent(eventID);
19084
20106
  if (!record?.eventID || !record?.sessionID) {
19085
20107
  return null;
@@ -19089,10 +20111,7 @@ var init_runtime = __esm({
19089
20111
  eventID: record.eventID,
19090
20112
  sessionID: record.sessionID,
19091
20113
  text: failureOptions.noticeText,
19092
- quotedMessageID: record.msgID,
19093
- extra: {
19094
- reply_source: failureOptions.replySource
19095
- }
20114
+ quotedMessageID: record.msgID
19096
20115
  });
19097
20116
  } catch {
19098
20117
  return null;
@@ -19108,18 +20127,18 @@ var init_runtime = __esm({
19108
20127
  return nextPayload;
19109
20128
  }
19110
20129
  async requeuePendingEventsForWorker(sessionID, workerID) {
19111
- const normalizedSessionID = normalizeString30(sessionID);
19112
- const normalizedWorkerID = normalizeString30(workerID);
20130
+ const normalizedSessionID = normalizeString32(sessionID);
20131
+ const normalizedWorkerID = normalizeString32(workerID);
19113
20132
  if (!normalizedSessionID || !normalizedWorkerID) {
19114
20133
  return 0;
19115
20134
  }
19116
20135
  let requeuedCount = 0;
19117
20136
  const requeuedEventIDs = [];
19118
20137
  for (const record of this.listPendingEventsForSession(normalizedSessionID)) {
19119
- if (normalizeString30(record.last_worker_id) !== normalizedWorkerID) {
20138
+ if (normalizeString32(record.last_worker_id) !== normalizedWorkerID) {
19120
20139
  continue;
19121
20140
  }
19122
- const deliveryState = normalizeString30(record.delivery_state);
20141
+ const deliveryState = normalizeString32(record.delivery_state);
19123
20142
  if (!["dispatching", "delivered", "interrupted"].includes(deliveryState)) {
19124
20143
  continue;
19125
20144
  }
@@ -19142,8 +20161,8 @@ var init_runtime = __esm({
19142
20161
  return requeuedCount;
19143
20162
  }
19144
20163
  async tryRecoverResumeAuthFailure(previousBinding, nextBinding) {
19145
- const sessionID = normalizeString30(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
19146
- const workerID = normalizeString30(previousBinding?.worker_id || nextBinding?.worker_id);
20164
+ const sessionID = normalizeString32(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
20165
+ const workerID = normalizeString32(previousBinding?.worker_id || nextBinding?.worker_id);
19147
20166
  if (!sessionID || !workerID) {
19148
20167
  return false;
19149
20168
  }
@@ -19195,7 +20214,7 @@ var init_runtime = __esm({
19195
20214
  return false;
19196
20215
  }
19197
20216
  const fallbackBinding = await this.rotateClaudeSession(latestBinding);
19198
- const nextWorkerID = normalizeString30(nextBinding?.worker_id) || workerID || randomUUID8();
20217
+ const nextWorkerID = normalizeString32(nextBinding?.worker_id) || workerID || randomUUID8();
19199
20218
  await this.bindingRegistry.markWorkerStarting(sessionID, {
19200
20219
  workerID: nextWorkerID,
19201
20220
  updatedAt: Date.now(),
@@ -19232,7 +20251,7 @@ var init_runtime = __esm({
19232
20251
  async reconcileWorkerProcesses() {
19233
20252
  const bindings = this.bindingRegistry?.listBindings?.() ?? [];
19234
20253
  for (const binding of bindings) {
19235
- const sessionID = normalizeString30(binding?.aibot_session_id);
20254
+ const sessionID = normalizeString32(binding?.aibot_session_id);
19236
20255
  if (!sessionID) continue;
19237
20256
  const queue = this.sessionQueues.ensure(sessionID);
19238
20257
  queue.run(() => this.reconcileWorkerProcess(binding)).catch((err) => {
@@ -19241,11 +20260,11 @@ var init_runtime = __esm({
19241
20260
  }
19242
20261
  }
19243
20262
  async reconcileWorkerProcess(binding) {
19244
- const sessionID = normalizeString30(binding?.aibot_session_id);
20263
+ const sessionID = normalizeString32(binding?.aibot_session_id);
19245
20264
  if (!sessionID) return false;
19246
20265
  const freshBinding = this.bindingRegistry?.getByAibotSessionID?.(sessionID) ?? binding;
19247
- const workerID = normalizeString30(freshBinding?.worker_id);
19248
- const workerStatus = normalizeString30(freshBinding?.worker_status);
20266
+ const workerID = normalizeString32(freshBinding?.worker_id);
20267
+ const workerStatus = normalizeString32(freshBinding?.worker_status);
19249
20268
  if (!workerID || !["starting", "connected", "ready"].includes(workerStatus)) {
19250
20269
  return false;
19251
20270
  }
@@ -19297,7 +20316,7 @@ var init_runtime = __esm({
19297
20316
  return true;
19298
20317
  }
19299
20318
  const previousBinding = this.bindingRegistry.getByAibotSessionID(sessionID) ?? binding;
19300
- if (normalizeString30(previousBinding?.worker_id) !== workerID || ["stopped", "failed"].includes(normalizeString30(previousBinding?.worker_status))) {
20319
+ if (normalizeString32(previousBinding?.worker_id) !== workerID || ["stopped", "failed"].includes(normalizeString32(previousBinding?.worker_status))) {
19301
20320
  return false;
19302
20321
  }
19303
20322
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
@@ -19306,7 +20325,7 @@ var init_runtime = __esm({
19306
20325
  }
19307
20326
  const pid = resolveExpectedWorkerPid(previousBinding, runtime);
19308
20327
  if (Number.isFinite(pid) && pid > 0 && !this.isProcessRunning(pid)) {
19309
- const exitSignal = normalizeString30(runtime.exit_signal) || "worker_exited";
20328
+ const exitSignal = normalizeString32(runtime.exit_signal) || "worker_exited";
19310
20329
  this.workerProcessManager?.markWorkerRuntimeStopped?.(workerID, {
19311
20330
  exitCode: Number(runtime.exit_code ?? 0),
19312
20331
  exitSignal
@@ -19350,7 +20369,7 @@ var init_runtime = __esm({
19350
20369
  }, "error");
19351
20370
  await this.bindingRegistry.markWorkerResponseFailed(sessionID, {
19352
20371
  observedAt: Date.now(),
19353
- reason: normalizeString30(probe.reason) || "worker_control_unreachable",
20372
+ reason: normalizeString32(probe.reason) || "worker_control_unreachable",
19354
20373
  failureCode: "worker_control_unreachable"
19355
20374
  });
19356
20375
  const nextBinding = await this.bindingRegistry.markWorkerStopped(sessionID, {
@@ -19421,7 +20440,7 @@ var init_runtime = __esm({
19421
20440
  * handling.
19422
20441
  */
19423
20442
  async handleWorkerStatusUpdateQueued(previousBinding, nextBinding) {
19424
- const sessionID = normalizeString30(
20443
+ const sessionID = normalizeString32(
19425
20444
  nextBinding?.aibot_session_id || previousBinding?.aibot_session_id
19426
20445
  );
19427
20446
  if (!sessionID) {
@@ -19433,8 +20452,8 @@ var init_runtime = __esm({
19433
20452
  );
19434
20453
  }
19435
20454
  async handleWorkerStatusUpdate(previousBinding, nextBinding) {
19436
- const sessionID = normalizeString30(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
19437
- const nextStatus = normalizeString30(nextBinding?.worker_status);
20455
+ const sessionID = normalizeString32(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
20456
+ const nextStatus = normalizeString32(nextBinding?.worker_status);
19438
20457
  if (!sessionID || !nextStatus) {
19439
20458
  return;
19440
20459
  }
@@ -19446,8 +20465,8 @@ var init_runtime = __esm({
19446
20465
  claude_session_id: nextBinding?.claude_session_id || previousBinding?.claude_session_id,
19447
20466
  status: nextStatus
19448
20467
  });
19449
- const previousWorkerID = normalizeString30(previousBinding?.worker_id);
19450
- const nextWorkerID = normalizeString30(nextBinding?.worker_id);
20468
+ const previousWorkerID = normalizeString32(previousBinding?.worker_id);
20469
+ const nextWorkerID = normalizeString32(nextBinding?.worker_id);
19451
20470
  if (nextStatus === "ready" || nextStatus === "connected") {
19452
20471
  if (nextWorkerID) {
19453
20472
  this.clearWorkerControlProbeFailure(nextWorkerID);
@@ -19499,11 +20518,11 @@ var init_runtime = __esm({
19499
20518
  }, "error");
19500
20519
  }
19501
20520
  for (const record of this.listPendingEventsForSession(sessionID)) {
19502
- if (previousWorkerID && normalizeString30(record.last_worker_id) !== previousWorkerID) {
19503
- if (normalizeString30(record.last_worker_id)) {
20521
+ if (previousWorkerID && normalizeString32(record.last_worker_id) !== previousWorkerID) {
20522
+ if (normalizeString32(record.last_worker_id)) {
19504
20523
  continue;
19505
20524
  }
19506
- if (!["pending", "dispatching", "interrupted"].includes(normalizeString30(record.delivery_state))) {
20525
+ if (!["pending", "dispatching", "interrupted"].includes(normalizeString32(record.delivery_state))) {
19507
20526
  continue;
19508
20527
  }
19509
20528
  }
@@ -19513,7 +20532,7 @@ var init_runtime = __esm({
19513
20532
  }
19514
20533
  async handleEventCompleted(eventID) {
19515
20534
  const record = this.getPendingEvent(eventID);
19516
- const sessionID = normalizeString30(record?.sessionID || this.messageDeliveryStore.getRememberedSessionID(eventID));
20535
+ const sessionID = normalizeString32(record?.sessionID || this.messageDeliveryStore.getRememberedSessionID(eventID));
19517
20536
  await this.clearPendingEvent(eventID);
19518
20537
  this.trace({
19519
20538
  stage: "event_completed",
@@ -19581,7 +20600,6 @@ var init_runtime = __esm({
19581
20600
  const currentRecord = this.getPendingEvent(record.eventID) ?? record;
19582
20601
  await this.failPendingEvent(currentRecord, {
19583
20602
  notifyText: false,
19584
- replySource: "daemon_recover_failed",
19585
20603
  resultCode: "worker_recover_failed",
19586
20604
  resultMessage: message
19587
20605
  });
@@ -19658,7 +20676,7 @@ var init_runtime = __esm({
19658
20676
  });
19659
20677
  return null;
19660
20678
  }
19661
- if (currentRecord && ["dispatching", "delivered"].includes(normalizeString30(currentRecord.delivery_state)) && normalizeString30(currentRecord.last_worker_id) === normalizeString30(readyBinding?.worker_id)) {
20679
+ if (currentRecord && ["dispatching", "delivered"].includes(normalizeString32(currentRecord.delivery_state)) && normalizeString32(currentRecord.last_worker_id) === normalizeString32(readyBinding?.worker_id)) {
19662
20680
  this.trace({
19663
20681
  stage: "event_dispatch_skipped",
19664
20682
  event_id: rawPayload?.event_id,
@@ -19710,7 +20728,7 @@ var init_runtime = __esm({
19710
20728
  } else {
19711
20729
  readyBinding = this.bindingRegistry.getByAibotSessionID(aibotSessionID) ?? readyBinding;
19712
20730
  }
19713
- if (readyBinding?.worker_launch_failure === "resume_session_missing" && normalizeString30(binding.claude_session_id)) {
20731
+ if (readyBinding?.worker_launch_failure === "resume_session_missing" && normalizeString32(binding.claude_session_id)) {
19714
20732
  this.trace({
19715
20733
  stage: "worker_resume_missing_recovering",
19716
20734
  session_id: binding.aibot_session_id,
@@ -19764,9 +20782,6 @@ var init_runtime = __esm({
19764
20782
  }
19765
20783
  return readyBinding ?? binding;
19766
20784
  }
19767
- async handleControlCommand(event, parsed) {
19768
- return this.controlCommandHandler.handleControlCommand(event, parsed);
19769
- }
19770
20785
  /**
19771
20786
  * Queue-aware wrapper: routes handleEvent through the per-session
19772
20787
  * serial queue to prevent races with reconcile and worker status updates.
@@ -19794,10 +20809,18 @@ var init_runtime = __esm({
19794
20809
  sender_id: event.sender_id
19795
20810
  });
19796
20811
  this.ack(event);
20812
+ if (isRecordOnlyMirror(event)) {
20813
+ this.trace({
20814
+ stage: "event_mirrored_record_only",
20815
+ event_id: event.event_id,
20816
+ session_id: event.session_id,
20817
+ msg_id: event.msg_id,
20818
+ sender_id: event.sender_id
20819
+ });
20820
+ return;
20821
+ }
19797
20822
  try {
19798
- const parsed = parseControlCommand(event.content);
19799
- if (parsed.matched) {
19800
- await this.handleControlCommand(event, parsed);
20823
+ if (await this.handleInteractionActionEvent(event)) {
19801
20824
  return;
19802
20825
  }
19803
20826
  const binding = this.bindingRegistry.getByAibotSessionID(event.session_id);
@@ -19807,9 +20830,10 @@ var init_runtime = __esm({
19807
20830
  event_id: event.event_id,
19808
20831
  session_id: event.session_id
19809
20832
  }, "error");
19810
- await this.respondWithOpenWorkspaceCard(event, {
19811
- ...buildMissingBindingCardOptions(),
19812
- replySource: "daemon_route_missing"
20833
+ await this.respond(event, buildBindingMissingEventNotice(), {}, {
20834
+ status: "responded",
20835
+ code: sessionControlErrorCodes.bindingMissing,
20836
+ msg: "session binding is required before event delivery"
19813
20837
  });
19814
20838
  return;
19815
20839
  }
@@ -19827,9 +20851,7 @@ var init_runtime = __esm({
19827
20851
  await this.respond(
19828
20852
  event,
19829
20853
  buildAuthLoginRequiredEventNotice(),
19830
- {
19831
- reply_source: "daemon_worker_auth_login_required"
19832
- },
20854
+ {},
19833
20855
  {
19834
20856
  status: "failed",
19835
20857
  code: "claude_auth_login_required",
@@ -19881,7 +20903,7 @@ var init_runtime = __esm({
19881
20903
  }
19882
20904
  const readyBinding = routedBinding ?? this.bindingRegistry.getByAibotSessionID(binding.aibot_session_id) ?? binding;
19883
20905
  if (!readyBinding.worker_control_url || !readyBinding.worker_control_token) {
19884
- const launchFailure = normalizeString30(readyBinding?.worker_launch_failure);
20906
+ const launchFailure = normalizeString32(readyBinding?.worker_launch_failure);
19885
20907
  this.trace({
19886
20908
  stage: "event_worker_not_ready",
19887
20909
  event_id: event.event_id,
@@ -19891,7 +20913,7 @@ var init_runtime = __esm({
19891
20913
  worker_launch_failure: launchFailure
19892
20914
  }, "error");
19893
20915
  if (pending && (launchFailure === "startup_mcp_server_failed" || launchFailure === "startup_wait_timeout")) {
19894
- const workerID = normalizeString30(readyBinding?.worker_id);
20916
+ const workerID = normalizeString32(readyBinding?.worker_id);
19895
20917
  if (workerID) {
19896
20918
  try {
19897
20919
  await this.workerProcessManager?.stopWorker?.(workerID);
@@ -19917,7 +20939,6 @@ var init_runtime = __esm({
19917
20939
  await this.markPendingEventInterrupted(pending.eventID);
19918
20940
  await this.failPendingEvent(pending, {
19919
20941
  noticeText: buildWorkerStartupFailedNotice(),
19920
- replySource: "daemon_worker_startup_failed",
19921
20942
  resultCode: launchFailure === "startup_mcp_server_failed" ? "claude_startup_mcp_failed" : "claude_startup_timeout",
19922
20943
  resultMessage: launchFailure === "startup_mcp_server_failed" ? "claude worker startup failed: mcp server not ready" : "claude worker startup timed out"
19923
20944
  });
@@ -19933,9 +20954,7 @@ var init_runtime = __esm({
19933
20954
  error: message
19934
20955
  }, "error");
19935
20956
  try {
19936
- await this.respond(event, `\u5904\u7406\u5931\u8D25\uFF1A${message}`, {
19937
- reply_source: "daemon_event_error"
19938
- }, {
20957
+ await this.respond(event, `\u5904\u7406\u5931\u8D25\uFF1A${message}`, {}, {
19939
20958
  status: "failed",
19940
20959
  code: "daemon_event_handle_failed",
19941
20960
  msg: message
@@ -19950,7 +20969,7 @@ var init_runtime = __esm({
19950
20969
  }
19951
20970
  }
19952
20971
  async handleStopEvent(rawPayload) {
19953
- const eventID = normalizeString30(rawPayload?.event_id);
20972
+ const eventID = normalizeString32(rawPayload?.event_id);
19954
20973
  if (!eventID) {
19955
20974
  return;
19956
20975
  }
@@ -19960,7 +20979,7 @@ var init_runtime = __esm({
19960
20979
  session_id: rawPayload?.session_id,
19961
20980
  stop_id: rawPayload?.stop_id
19962
20981
  });
19963
- const sessionID = normalizeString30(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
20982
+ const sessionID = normalizeString32(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
19964
20983
  if (!sessionID) {
19965
20984
  this.trace({
19966
20985
  stage: "stop_route_missing",
@@ -19978,12 +20997,12 @@ var init_runtime = __esm({
19978
20997
  });
19979
20998
  }
19980
20999
  async handleRevokeEvent(rawPayload) {
19981
- const eventID = normalizeString30(rawPayload?.event_id);
21000
+ const eventID = normalizeString32(rawPayload?.event_id);
19982
21001
  if (!eventID) {
19983
21002
  return;
19984
21003
  }
19985
21004
  const receivedAt = Date.now();
19986
- const resolvedSessionID = normalizeString30(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
21005
+ const resolvedSessionID = normalizeString32(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
19987
21006
  this.aibotClient.ackEvent(eventID, {
19988
21007
  sessionID: resolvedSessionID,
19989
21008
  msgID: rawPayload?.msg_id,
@@ -20028,12 +21047,80 @@ var init_runtime = __esm({
20028
21047
  msg_id: rawPayload?.msg_id
20029
21048
  });
20030
21049
  }
21050
+ async handleLocalAction(rawPayload) {
21051
+ const action = normalizeLocalActionPayload(rawPayload);
21052
+ if (!action.action_id) {
21053
+ this.trace({
21054
+ stage: "local_action_invalid",
21055
+ reason: "missing_action_id",
21056
+ action_type: action.action_type
21057
+ }, "error");
21058
+ return;
21059
+ }
21060
+ const sessionControlResult = await this.sessionControlActionHandler.handleLocalAction(action);
21061
+ if (sessionControlResult?.handled) {
21062
+ await this.aibotClient.sendLocalActionResult({
21063
+ actionID: action.action_id,
21064
+ status: sessionControlResult.response?.status,
21065
+ result: sessionControlResult.response?.result,
21066
+ errorCode: sessionControlResult.response?.errorCode,
21067
+ errorMsg: sessionControlResult.response?.errorMsg,
21068
+ timeoutMs: action.timeout_ms
21069
+ });
21070
+ return;
21071
+ }
21072
+ const sessionID = normalizeString32(action.params?.session_id) || this.messageDeliveryStore.getRememberedSessionID(action.event_id);
21073
+ if (!sessionID) {
21074
+ this.trace({
21075
+ stage: "local_action_route_missing",
21076
+ action_id: action.action_id,
21077
+ action_type: action.action_type,
21078
+ event_id: action.event_id
21079
+ }, "error");
21080
+ await this.aibotClient.sendLocalActionResult({
21081
+ actionID: action.action_id,
21082
+ status: localActionResultStatuses.failed,
21083
+ errorCode: localActionErrorCodes.localActionRouteMissing,
21084
+ errorMsg: "local action session_id is required",
21085
+ timeoutMs: action.timeout_ms
21086
+ });
21087
+ return;
21088
+ }
21089
+ const routedBinding = await this.deliverWithRecovery(
21090
+ sessionID,
21091
+ action,
21092
+ this.deliverLocalActionToWorker
21093
+ );
21094
+ if (routedBinding && canDeliverToWorker(routedBinding)) {
21095
+ this.trace({
21096
+ stage: "local_action_forwarded",
21097
+ action_id: action.action_id,
21098
+ action_type: action.action_type,
21099
+ session_id: sessionID,
21100
+ worker_id: routedBinding?.worker_id
21101
+ });
21102
+ return;
21103
+ }
21104
+ this.trace({
21105
+ stage: "local_action_delivery_failed",
21106
+ action_id: action.action_id,
21107
+ action_type: action.action_type,
21108
+ session_id: sessionID
21109
+ }, "error");
21110
+ await this.aibotClient.sendLocalActionResult({
21111
+ actionID: action.action_id,
21112
+ status: "failed",
21113
+ errorCode: "local_action_delivery_failed",
21114
+ errorMsg: "worker is not ready for local action delivery",
21115
+ timeoutMs: action.timeout_ms
21116
+ });
21117
+ }
20031
21118
  };
20032
21119
  }
20033
21120
  });
20034
21121
 
20035
21122
  // server/session-activity-dispatcher.js
20036
- function normalizeString31(value) {
21123
+ function normalizeString33(value) {
20037
21124
  return String(value ?? "").trim();
20038
21125
  }
20039
21126
  function buildSessionActivityDispatchKey({
@@ -20042,10 +21129,10 @@ function buildSessionActivityDispatchKey({
20042
21129
  refEventID = "",
20043
21130
  refMsgID = ""
20044
21131
  } = {}) {
20045
- const normalizedSessionID = normalizeString31(sessionID);
20046
- const normalizedKind = normalizeString31(kind) || "composing";
20047
- const normalizedRefEventID = normalizeString31(refEventID);
20048
- const normalizedRefMsgID = normalizeString31(refMsgID);
21132
+ const normalizedSessionID = normalizeString33(sessionID);
21133
+ const normalizedKind = normalizeString33(kind) || "composing";
21134
+ const normalizedRefEventID = normalizeString33(refEventID);
21135
+ const normalizedRefMsgID = normalizeString33(refMsgID);
20049
21136
  if (normalizedRefEventID) {
20050
21137
  return `event:${normalizedRefEventID}`;
20051
21138
  }
@@ -20082,19 +21169,19 @@ var init_session_activity_dispatcher = __esm({
20082
21169
 
20083
21170
  // server/daemon/session-log-writer.js
20084
21171
  import { appendFile as appendFile2, mkdir as mkdir11 } from "node:fs/promises";
20085
- import path23 from "node:path";
20086
- function normalizeString32(value) {
21172
+ import path24 from "node:path";
21173
+ function normalizeString34(value) {
20087
21174
  return String(value ?? "").trim();
20088
21175
  }
20089
21176
  function normalizeSessionID(value) {
20090
- return normalizeString32(value).replace(/[^a-zA-Z0-9._-]+/g, "-");
21177
+ return normalizeString34(value).replace(/[^a-zA-Z0-9._-]+/g, "-");
20091
21178
  }
20092
21179
  function resolveSessionID(fields = {}) {
20093
- const explicitSessionID = normalizeString32(fields.session_id);
21180
+ const explicitSessionID = normalizeString34(fields.session_id);
20094
21181
  if (explicitSessionID) {
20095
21182
  return explicitSessionID;
20096
21183
  }
20097
- return normalizeString32(fields.aibot_session_id);
21184
+ return normalizeString34(fields.aibot_session_id);
20098
21185
  }
20099
21186
  var SessionLogWriter;
20100
21187
  var init_session_log_writer = __esm({
@@ -20109,7 +21196,7 @@ var init_session_log_writer = __esm({
20109
21196
  appendFileImpl = appendFile2
20110
21197
  } = {}) {
20111
21198
  this.env = env;
20112
- this.logFileName = normalizeString32(logFileName) || "daemon-session.log";
21199
+ this.logFileName = normalizeString34(logFileName) || "daemon-session.log";
20113
21200
  this.mkdirImpl = typeof mkdirImpl === "function" ? mkdirImpl : mkdir11;
20114
21201
  this.appendFileImpl = typeof appendFileImpl === "function" ? appendFileImpl : appendFile2;
20115
21202
  this.writeQueues = /* @__PURE__ */ new Map();
@@ -20119,7 +21206,7 @@ var init_session_log_writer = __esm({
20119
21206
  if (!normalizedSessionID) {
20120
21207
  return "";
20121
21208
  }
20122
- return path23.join(resolveWorkerLogsDir(normalizedSessionID, this.env), this.logFileName);
21209
+ return path24.join(resolveWorkerLogsDir(normalizedSessionID, this.env), this.logFileName);
20123
21210
  }
20124
21211
  enqueueWrite(aibotSessionID, task) {
20125
21212
  const normalizedSessionID = normalizeSessionID(aibotSessionID);
@@ -20143,7 +21230,7 @@ var init_session_log_writer = __esm({
20143
21230
  return false;
20144
21231
  }
20145
21232
  const line = formatTraceLine({
20146
- level: normalizeString32(level) || "info",
21233
+ level: normalizeString34(level) || "info",
20147
21234
  ...fields
20148
21235
  });
20149
21236
  return this.enqueueWrite(sessionID, async () => {
@@ -20151,7 +21238,7 @@ var init_session_log_writer = __esm({
20151
21238
  if (!logPath) {
20152
21239
  return false;
20153
21240
  }
20154
- await this.mkdirImpl(path23.dirname(logPath), { recursive: true });
21241
+ await this.mkdirImpl(path24.dirname(logPath), { recursive: true });
20155
21242
  await this.appendFileImpl(logPath, `${line}
20156
21243
  `, "utf8");
20157
21244
  return true;
@@ -20171,7 +21258,7 @@ __export(main_exports, {
20171
21258
  shouldIgnoreWorkerStatusUpdate: () => shouldIgnoreWorkerStatusUpdate,
20172
21259
  shouldNotifyWorkerReady: () => shouldNotifyWorkerReady
20173
21260
  });
20174
- import process14 from "node:process";
21261
+ import process15 from "node:process";
20175
21262
  function usage() {
20176
21263
  return `\u7528\u6CD5:
20177
21264
  grix-claude daemon [options]
@@ -20190,7 +21277,7 @@ function usage() {
20190
21277
  `;
20191
21278
  }
20192
21279
  function print(message) {
20193
- process14.stdout.write(`${message}
21280
+ process15.stdout.write(`${message}
20194
21281
  `);
20195
21282
  }
20196
21283
  function parseArgs(argv) {
@@ -20216,7 +21303,7 @@ function readOption(argv, name) {
20216
21303
  }
20217
21304
  return value;
20218
21305
  }
20219
- function normalizeString33(value) {
21306
+ function normalizeString35(value) {
20220
21307
  return String(value ?? "").trim();
20221
21308
  }
20222
21309
  function normalizePid3(value) {
@@ -20239,13 +21326,13 @@ function shouldIgnoreWorkerStatusUpdate(previousBinding, payload) {
20239
21326
  if (!previousBinding) {
20240
21327
  return false;
20241
21328
  }
20242
- const expectedWorkerID = normalizeString33(previousBinding.worker_id);
20243
- const incomingWorkerID = normalizeString33(payload?.worker_id);
21329
+ const expectedWorkerID = normalizeString35(previousBinding.worker_id);
21330
+ const incomingWorkerID = normalizeString35(payload?.worker_id);
20244
21331
  if (expectedWorkerID && incomingWorkerID && expectedWorkerID !== incomingWorkerID) {
20245
21332
  return true;
20246
21333
  }
20247
- const expectedClaudeSessionID = normalizeString33(previousBinding.claude_session_id);
20248
- const incomingClaudeSessionID = normalizeString33(payload?.claude_session_id);
21334
+ const expectedClaudeSessionID = normalizeString35(previousBinding.claude_session_id);
21335
+ const incomingClaudeSessionID = normalizeString35(payload?.claude_session_id);
20249
21336
  if (expectedClaudeSessionID && incomingClaudeSessionID && expectedClaudeSessionID !== incomingClaudeSessionID) {
20250
21337
  return true;
20251
21338
  }
@@ -20260,13 +21347,10 @@ async function notifyWorkerReady(aibotClient, binding) {
20260
21347
  }
20261
21348
  return aibotClient.sendText({
20262
21349
  sessionID: binding.aibot_session_id,
20263
- text: buildWorkerReadyNoticeText(binding),
20264
- extra: {
20265
- reply_source: "daemon_worker_ready"
20266
- }
21350
+ text: buildWorkerReadyNoticeText(binding)
20267
21351
  });
20268
21352
  }
20269
- async function run(argv = [], env = process14.env) {
21353
+ async function run(argv = [], env = process15.env) {
20270
21354
  const options = parseArgs(argv);
20271
21355
  if (options.help) {
20272
21356
  print(usage());
@@ -20514,6 +21598,25 @@ async function run(argv = [], env = process14.env) {
20514
21598
  refEventID: payload.ref_event_id
20515
21599
  });
20516
21600
  return { ok: true };
21601
+ },
21602
+ onAgentInvoke: async (payload) => aibotClient.sendAgentInvoke({
21603
+ invokeID: payload?.invoke_id,
21604
+ action: payload?.action,
21605
+ params: payload?.params,
21606
+ timeoutMs: payload?.timeout_ms
21607
+ }),
21608
+ onLocalActionResult: async (payload) => {
21609
+ const syntheticResult = await runtime?.observeWorkerLocalActionResult?.(payload);
21610
+ if (syntheticResult?.handled) {
21611
+ return { ok: true };
21612
+ }
21613
+ return aibotClient.sendLocalActionResult({
21614
+ actionID: payload?.action_id,
21615
+ status: payload?.status,
21616
+ result: payload?.result,
21617
+ errorCode: payload?.error_code,
21618
+ errorMsg: payload?.error_msg
21619
+ });
20517
21620
  }
20518
21621
  });
20519
21622
  try {
@@ -20538,6 +21641,9 @@ async function run(argv = [], env = process14.env) {
20538
21641
  aibotClient.onEventRevoke = async (payload) => {
20539
21642
  await runtime.handleRevokeEvent(payload);
20540
21643
  };
21644
+ aibotClient.onLocalAction = async (payload) => {
21645
+ await runtime.handleLocalAction(payload);
21646
+ };
20541
21647
  print("grix-claude daemon \u5DF2\u542F\u52A8\u3002");
20542
21648
  print(`\u6570\u636E\u76EE\u5F55: ${dataDir}`);
20543
21649
  print(`Bridge: ${bridgeServer.getURL()}`);
@@ -20577,15 +21683,15 @@ async function run(argv = [], env = process14.env) {
20577
21683
  }
20578
21684
  await new Promise((resolve) => {
20579
21685
  const stop = async () => {
20580
- process14.off("SIGINT", stop);
20581
- process14.off("SIGTERM", stop);
21686
+ process15.off("SIGINT", stop);
21687
+ process15.off("SIGTERM", stop);
20582
21688
  await processState.markStopping("signal");
20583
21689
  await aibotClient.stop();
20584
21690
  await bridgeServer.stop();
20585
21691
  resolve();
20586
21692
  };
20587
- process14.once("SIGINT", stop);
20588
- process14.once("SIGTERM", stop);
21693
+ process15.once("SIGINT", stop);
21694
+ process15.once("SIGTERM", stop);
20589
21695
  });
20590
21696
  await processState.release({
20591
21697
  exitCode: 0,
@@ -20597,8 +21703,8 @@ async function run(argv = [], env = process14.env) {
20597
21703
  throw error;
20598
21704
  }
20599
21705
  }
20600
- async function main(argv = process14.argv.slice(2), env = process14.env) {
20601
- process14.exitCode = await run(argv, env);
21706
+ async function main(argv = process15.argv.slice(2), env = process15.env) {
21707
+ process15.exitCode = await run(argv, env);
20602
21708
  }
20603
21709
  var workerReadySettleDelayMs;
20604
21710
  var init_main2 = __esm({
@@ -20627,7 +21733,7 @@ __export(main_exports2, {
20627
21733
  main: () => main2,
20628
21734
  run: () => run2
20629
21735
  });
20630
- import process15 from "node:process";
21736
+ import process16 from "node:process";
20631
21737
  function usage2() {
20632
21738
  return `\u7528\u6CD5:
20633
21739
  grix-claude worker
@@ -20637,7 +21743,7 @@ function usage2() {
20637
21743
  `;
20638
21744
  }
20639
21745
  function print2(message) {
20640
- process15.stdout.write(`${message}
21746
+ process16.stdout.write(`${message}
20641
21747
  `);
20642
21748
  }
20643
21749
  async function run2(argv = []) {
@@ -20648,8 +21754,8 @@ async function run2(argv = []) {
20648
21754
  print2("\u4E0D\u8981\u624B\u52A8\u8FD0\u884C worker\u3002Claude \u4F1A\u8BDD\u4F1A\u5728 daemon \u8C03\u5EA6\u4E0B\u81EA\u52A8\u52A0\u8F7D\u5B83\u3002");
20649
21755
  return 1;
20650
21756
  }
20651
- async function main2(argv = process15.argv.slice(2)) {
20652
- process15.exitCode = await run2(argv);
21757
+ async function main2(argv = process16.argv.slice(2)) {
21758
+ process16.exitCode = await run2(argv);
20653
21759
  }
20654
21760
  var init_main3 = __esm({
20655
21761
  "server/worker/main.js"() {
@@ -20660,7 +21766,7 @@ var init_main3 = __esm({
20660
21766
  init_config();
20661
21767
  init_config_store();
20662
21768
  init_daemon_paths();
20663
- import process16 from "node:process";
21769
+ import process17 from "node:process";
20664
21770
 
20665
21771
  // server/service/service-manager.js
20666
21772
  init_config();
@@ -21263,7 +22369,7 @@ var ServiceManager = class {
21263
22369
  minUpdatedAt = 0,
21264
22370
  timeoutMs = 5e3
21265
22371
  } = {}) {
21266
- const { setTimeout: sleep3 } = await import("node:timers/promises");
22372
+ const { setTimeout: sleep4 } = await import("node:timers/promises");
21267
22373
  const start = this.now();
21268
22374
  let lastState = null;
21269
22375
  while (this.now() - start < timeoutMs) {
@@ -21273,7 +22379,7 @@ var ServiceManager = class {
21273
22379
  if (state.running && state.pid && restarted) {
21274
22380
  return state;
21275
22381
  }
21276
- await sleep3(100);
22382
+ await sleep4(100);
21277
22383
  }
21278
22384
  throw new Error(
21279
22385
  `daemon start timeout (${timeoutMs}ms), state=${lastState?.state || "unknown"}, pid=${Number(lastState?.pid ?? 0)}`
@@ -21502,11 +22608,11 @@ function parseArgs2(argv) {
21502
22608
  return options;
21503
22609
  }
21504
22610
  function print3(message) {
21505
- process16.stdout.write(`${message}
22611
+ process17.stdout.write(`${message}
21506
22612
  `);
21507
22613
  }
21508
22614
  function printError(message) {
21509
- process16.stderr.write(`${message}
22615
+ process17.stderr.write(`${message}
21510
22616
  `);
21511
22617
  }
21512
22618
  function shellQuoteForDisplay(value) {
@@ -21545,10 +22651,10 @@ function formatRunningCommand(argv) {
21545
22651
  return command.map((item) => shellQuoteForDisplay(item)).join(" ");
21546
22652
  }
21547
22653
  function formatRuntimeEntryCommand(argv) {
21548
- const command = [process16.execPath, resolvePackageBinPath(), ...redactSensitiveArgs(argv)];
22654
+ const command = [process17.execPath, resolvePackageBinPath(), ...redactSensitiveArgs(argv)];
21549
22655
  return command.map((item) => shellQuoteForDisplay(item)).join(" ");
21550
22656
  }
21551
- function createServiceManager(env = process16.env) {
22657
+ function createServiceManager(env = process17.env) {
21552
22658
  return new ServiceManager({ env });
21553
22659
  }
21554
22660
  function buildRuntimeEnv(options, env) {
@@ -21566,7 +22672,7 @@ function buildDaemonStatus(configStore) {
21566
22672
  configPath: configStore.filePath
21567
22673
  };
21568
22674
  }
21569
- async function prepareDaemonConfig(options, env = process16.env, { persistResolvedConfig = false } = {}) {
22675
+ async function prepareDaemonConfig(options, env = process17.env, { persistResolvedConfig = false } = {}) {
21570
22676
  const runtimeEnv = buildRuntimeEnv(options, env);
21571
22677
  const configStore = new ConfigStore(resolveDaemonConfigPath(runtimeEnv), {
21572
22678
  env: runtimeEnv
@@ -21591,7 +22697,7 @@ async function prepareDaemonConfig(options, env = process16.env, { persistResolv
21591
22697
  ...buildDaemonStatus(configStore)
21592
22698
  };
21593
22699
  }
21594
- async function runDefault(argv, env = process16.env) {
22700
+ async function runDefault(argv, env = process17.env) {
21595
22701
  const options = parseArgs2(argv);
21596
22702
  if (options.help) {
21597
22703
  print3(usage3());
@@ -21705,7 +22811,7 @@ async function runSubcommand(name, argv, env, deps = {}) {
21705
22811
  }
21706
22812
  throw new Error(`\u672A\u77E5\u5B50\u547D\u4EE4: ${name}`);
21707
22813
  }
21708
- async function run3(argv, env = process16.env, deps = {}) {
22814
+ async function run3(argv, env = process17.env, deps = {}) {
21709
22815
  const [first = ""] = argv;
21710
22816
  if ([
21711
22817
  "daemon",
@@ -21721,17 +22827,17 @@ async function run3(argv, env = process16.env, deps = {}) {
21721
22827
  }
21722
22828
  return runDefault(argv, env);
21723
22829
  }
21724
- async function main3(argv = process16.argv.slice(2), env = process16.env) {
22830
+ async function main3(argv = process17.argv.slice(2), env = process17.env) {
21725
22831
  try {
21726
22832
  print3(`\u8FD0\u884C\u547D\u4EE4: ${formatRunningCommand(argv)}`);
21727
22833
  print3(`\u5B9E\u9645\u5165\u53E3: ${formatRuntimeEntryCommand(argv)}`);
21728
22834
  const exitCode = await run3(argv, env);
21729
- process16.exitCode = exitCode;
22835
+ process17.exitCode = exitCode;
21730
22836
  } catch (error) {
21731
22837
  printError(error instanceof Error ? error.message : String(error));
21732
22838
  printError("");
21733
22839
  printError(usage3());
21734
- process16.exitCode = 1;
22840
+ process17.exitCode = 1;
21735
22841
  }
21736
22842
  }
21737
22843