@dhf-claude/grix 0.1.8 → 0.1.10

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.10",
15678
+ description: "Claude Code channel plugin for Aibot Grix",
15679
+ type: "module",
15680
+ repository: {
15681
+ type: "git",
15682
+ url: "git+ssh://git@github.com/askie/grix-claude.git"
15683
+ },
15684
+ bugs: {
15685
+ url: "https://github.com/askie/grix-claude/issues"
15686
+ },
15687
+ homepage: "https://github.com/askie/grix-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,40 @@ 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
  }
15948
+ function normalizeSessionActivityKind(value) {
15949
+ const normalized = normalizeString20(value);
15950
+ if (!normalized || normalized === "composing") {
15951
+ return "typing";
15952
+ }
15953
+ return normalized;
15954
+ }
15571
15955
  function buildAuthPayload(config) {
15956
+ const clientVersion = normalizeString20(config?.clientVersion) || pluginVersion;
15957
+ const hostVersion = normalizeString20(config?.hostVersion) || clientVersion;
15572
15958
  return {
15573
15959
  agent_id: config.agentID,
15574
15960
  api_key: config.apiKey,
15575
15961
  client: "claude-grix-claude-channel",
15576
- client_type: "claude"
15962
+ client_type: "claude",
15963
+ contract_version: contractVersion,
15964
+ client_version: clientVersion,
15965
+ host_type: "claude",
15966
+ host_version: hostVersion,
15967
+ protocol_version: protocolVersion,
15968
+ capabilities: [...declaredCapabilities],
15969
+ local_actions: [...declaredLocalActions],
15970
+ adapter_hint: adapterHint
15577
15971
  };
15578
15972
  }
15579
15973
  function buildSessionActivityPayload({
@@ -15585,8 +15979,8 @@ function buildSessionActivityPayload({
15585
15979
  refEventID = ""
15586
15980
  }) {
15587
15981
  const payload = {
15588
- session_id: normalizeString19(sessionID),
15589
- kind: normalizeString19(kind),
15982
+ session_id: normalizeString20(sessionID),
15983
+ kind: normalizeSessionActivityKind(kind),
15590
15984
  active: active === true
15591
15985
  };
15592
15986
  if (Number.isFinite(Number(ttlMs)) && Number(ttlMs) > 0) {
@@ -15596,17 +15990,21 @@ function buildSessionActivityPayload({
15596
15990
  withOptionalString(payload, "ref_event_id", refEventID);
15597
15991
  return payload;
15598
15992
  }
15599
- var verboseDebugEnabled, verboseDebugLogPath, AibotClient;
15993
+ var verboseDebugEnabled, verboseDebugLogPath, pluginVersion, AibotClient;
15600
15994
  var init_aibot_client = __esm({
15601
15995
  "server/aibot-client.js"() {
15602
15996
  init_wrapper();
15997
+ init_package();
15998
+ init_protocol_contract();
15603
15999
  verboseDebugEnabled = process.env.GRIX_CLAUDE_E2E_DEBUG === "1";
15604
- verboseDebugLogPath = normalizeString19(process.env.GRIX_CLAUDE_E2E_DEBUG_LOG);
16000
+ verboseDebugLogPath = normalizeString20(process.env.GRIX_CLAUDE_E2E_DEBUG_LOG);
16001
+ pluginVersion = normalizeString20(package_default?.version) || "0.1.0";
15605
16002
  AibotClient = class {
15606
- constructor({ onEventMessage, onEventStop, onEventRevoke, onStatus } = {}) {
16003
+ constructor({ onEventMessage, onEventStop, onEventRevoke, onLocalAction, onStatus } = {}) {
15607
16004
  this.onEventMessage = onEventMessage;
15608
16005
  this.onEventStop = onEventStop;
15609
16006
  this.onEventRevoke = onEventRevoke;
16007
+ this.onLocalAction = onLocalAction;
15610
16008
  this.onStatus = onStatus;
15611
16009
  this.desired = false;
15612
16010
  this.config = null;
@@ -15736,10 +16134,10 @@ var init_aibot_client = __esm({
15736
16134
  expected: ["auth_ack"],
15737
16135
  timeoutMs: 1e4
15738
16136
  });
15739
- logDebug(`auth response code=${Number(auth?.payload?.code ?? 0)} msg=${normalizeString19(auth?.payload?.msg)}`);
16137
+ logDebug(`auth response code=${Number(auth?.payload?.code ?? 0)} msg=${normalizeString20(auth?.payload?.msg)}`);
15740
16138
  const code = Number(auth?.payload?.code ?? 0);
15741
16139
  if (code !== 0) {
15742
- throw new Error(normalizeString19(auth?.payload?.msg) || `auth failed code=${code}`);
16140
+ throw new Error(normalizeString20(auth?.payload?.msg) || `auth failed code=${code}`);
15743
16141
  }
15744
16142
  this.setStatus({
15745
16143
  connecting: false,
@@ -15847,7 +16245,7 @@ var init_aibot_client = __esm({
15847
16245
  }
15848
16246
  async handleMessage(text) {
15849
16247
  const packet = JSON.parse(text);
15850
- const cmd = normalizeString19(packet.cmd);
16248
+ const cmd = normalizeString20(packet.cmd);
15851
16249
  const seq = Number(packet.seq ?? 0);
15852
16250
  logDebug(`recv cmd=${cmd} seq=${seq}`);
15853
16251
  if (cmd === "ping") {
@@ -15871,6 +16269,10 @@ var init_aibot_client = __esm({
15871
16269
  }
15872
16270
  if (cmd === "event_revoke" && this.onEventRevoke) {
15873
16271
  await this.onEventRevoke(packet.payload ?? {});
16272
+ return;
16273
+ }
16274
+ if (cmd === "local_action" && this.onLocalAction) {
16275
+ await this.onLocalAction(packet.payload ?? {});
15874
16276
  }
15875
16277
  }
15876
16278
  setStatus(patch) {
@@ -15940,7 +16342,7 @@ var init_aibot_client = __esm({
15940
16342
  }
15941
16343
  ackEvent(eventID, { sessionID, msgID, receivedAt = Date.now() } = {}) {
15942
16344
  const payload = {
15943
- event_id: normalizeString19(eventID),
16345
+ event_id: normalizeString20(eventID),
15944
16346
  received_at: Math.floor(receivedAt)
15945
16347
  };
15946
16348
  withOptionalString(payload, "session_id", sessionID);
@@ -15949,8 +16351,8 @@ var init_aibot_client = __esm({
15949
16351
  }
15950
16352
  sendEventResult({ event_id, status, code = "", msg = "", updated_at = Date.now() }) {
15951
16353
  const payload = {
15952
- event_id: normalizeString19(event_id),
15953
- status: normalizeString19(status),
16354
+ event_id: normalizeString20(event_id),
16355
+ status: normalizeString20(status),
15954
16356
  updated_at: Math.floor(updated_at)
15955
16357
  };
15956
16358
  withOptionalString(payload, "code", code);
@@ -15959,7 +16361,7 @@ var init_aibot_client = __esm({
15959
16361
  }
15960
16362
  sendEventStopAck({ event_id, stop_id = "", accepted, updated_at = Date.now() }) {
15961
16363
  const payload = {
15962
- event_id: normalizeString19(event_id),
16364
+ event_id: normalizeString20(event_id),
15963
16365
  accepted: accepted === true,
15964
16366
  updated_at: Math.floor(updated_at)
15965
16367
  };
@@ -15975,8 +16377,8 @@ var init_aibot_client = __esm({
15975
16377
  updated_at = Date.now()
15976
16378
  }) {
15977
16379
  const payload = {
15978
- event_id: normalizeString19(event_id),
15979
- status: normalizeString19(status),
16380
+ event_id: normalizeString20(event_id),
16381
+ status: normalizeString20(status),
15980
16382
  updated_at: Math.floor(updated_at)
15981
16383
  };
15982
16384
  withOptionalString(payload, "stop_id", stop_id);
@@ -16013,8 +16415,8 @@ var init_aibot_client = __esm({
16013
16415
  extra = {}
16014
16416
  }) {
16015
16417
  const payload = {
16016
- session_id: normalizeString19(sessionID),
16017
- client_msg_id: normalizeString19(clientMsgID),
16418
+ session_id: normalizeString20(sessionID),
16419
+ client_msg_id: normalizeString20(clientMsgID),
16018
16420
  msg_type: 1,
16019
16421
  content: String(text ?? ""),
16020
16422
  extra
@@ -16040,11 +16442,11 @@ var init_aibot_client = __esm({
16040
16442
  extra = {}
16041
16443
  }) {
16042
16444
  const payload = {
16043
- session_id: normalizeString19(sessionID),
16044
- client_msg_id: normalizeString19(clientMsgID),
16445
+ session_id: normalizeString20(sessionID),
16446
+ client_msg_id: normalizeString20(clientMsgID),
16045
16447
  msg_type: 2,
16046
- content: normalizeString19(caption) || "[attachment]",
16047
- media_url: normalizeString19(mediaURL),
16448
+ content: normalizeString20(caption) || "[attachment]",
16449
+ media_url: normalizeString20(mediaURL),
16048
16450
  extra
16049
16451
  };
16050
16452
  withOptionalString(payload, "event_id", eventID);
@@ -16058,9 +16460,69 @@ var init_aibot_client = __esm({
16058
16460
  }
16059
16461
  return packet.payload ?? {};
16060
16462
  }
16463
+ async sendAgentInvoke({
16464
+ invokeID = randomUUID5(),
16465
+ action,
16466
+ params = {},
16467
+ timeoutMs = 15e3
16468
+ } = {}) {
16469
+ const normalizedAction = normalizeString20(action);
16470
+ if (!normalizedAction) {
16471
+ throw new Error("sendAgentInvoke requires action");
16472
+ }
16473
+ const normalizedTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 15e3;
16474
+ const packet = await this.request("agent_invoke", {
16475
+ invoke_id: normalizeString20(invokeID) || randomUUID5(),
16476
+ action: normalizedAction,
16477
+ params: params && typeof params === "object" && !Array.isArray(params) ? params : {},
16478
+ timeout_ms: normalizedTimeoutMs
16479
+ }, {
16480
+ expected: ["agent_invoke_result", "error"],
16481
+ timeoutMs: normalizedTimeoutMs + 1e3
16482
+ });
16483
+ if (packet.cmd !== "agent_invoke_result") {
16484
+ throw buildSendNackError(packet);
16485
+ }
16486
+ return packet.payload ?? {};
16487
+ }
16488
+ async sendLocalActionResult({
16489
+ actionID,
16490
+ status,
16491
+ result = void 0,
16492
+ errorCode = "",
16493
+ errorMsg = "",
16494
+ timeoutMs = 15e3
16495
+ } = {}) {
16496
+ const normalizedActionID = normalizeString20(actionID);
16497
+ if (!normalizedActionID) {
16498
+ throw new Error("sendLocalActionResult requires actionID");
16499
+ }
16500
+ const normalizedStatus = normalizeString20(status);
16501
+ if (!normalizedStatus) {
16502
+ throw new Error("sendLocalActionResult requires status");
16503
+ }
16504
+ const normalizedTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 15e3;
16505
+ const payload = {
16506
+ action_id: normalizedActionID,
16507
+ status: normalizedStatus
16508
+ };
16509
+ if (arguments[0] && Object.prototype.hasOwnProperty.call(arguments[0], "result")) {
16510
+ payload.result = result;
16511
+ }
16512
+ withOptionalString(payload, "error_code", errorCode);
16513
+ withOptionalString(payload, "error_msg", errorMsg);
16514
+ const packet = await this.request("local_action_result", payload, {
16515
+ expected: ["local_action_ack", "error"],
16516
+ timeoutMs: normalizedTimeoutMs
16517
+ });
16518
+ if (packet.cmd !== "local_action_ack") {
16519
+ throw buildSendNackError(packet);
16520
+ }
16521
+ return packet.payload ?? {};
16522
+ }
16061
16523
  async deleteMessage(sessionID, messageID, { timeoutMs = 2e4 } = {}) {
16062
- const normalizedSessionID = normalizeString19(sessionID);
16063
- const normalizedMessageID = normalizeString19(messageID);
16524
+ const normalizedSessionID = normalizeString20(sessionID);
16525
+ const normalizedMessageID = normalizeString20(messageID);
16064
16526
  if (!normalizedSessionID) {
16065
16527
  throw new Error("deleteMessage requires sessionID");
16066
16528
  }
@@ -16083,74 +16545,113 @@ var init_aibot_client = __esm({
16083
16545
  }
16084
16546
  });
16085
16547
 
16086
- // server/daemon/control-command.js
16087
- import path21 from "node:path";
16088
- function normalizeString20(value) {
16548
+ // server/grix-card-link.js
16549
+ function normalizeString21(value) {
16089
16550
  return String(value ?? "").trim();
16090
16551
  }
16091
- function normalizeTokens(text) {
16092
- return normalizeString20(text).split(/\s+/).filter(Boolean);
16552
+ function hasComplexPayload(payload) {
16553
+ return Object.values(payload ?? {}).some((value) => Array.isArray(value) || value && typeof value === "object");
16093
16554
  }
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: "" };
16555
+ function appendFlatPayload(params, payload) {
16556
+ for (const [rawKey, value] of Object.entries(payload ?? {})) {
16557
+ const key = normalizeString21(rawKey);
16558
+ if (!key || value == null) {
16559
+ continue;
16560
+ }
16561
+ if (typeof value === "string") {
16562
+ if (!value) {
16563
+ continue;
16564
+ }
16565
+ params.set(key, value);
16566
+ continue;
16567
+ }
16568
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
16569
+ params.set(key, String(value));
16570
+ }
16102
16571
  }
16103
- let startIndex = 0;
16104
- if (tokens[0] === "/grix" || tokens[0] === "grix") {
16105
- startIndex = 1;
16572
+ }
16573
+ function buildGrixCardURI(cardType, payload = {}) {
16574
+ const normalizedType = normalizeString21(cardType);
16575
+ if (!normalizedType) {
16576
+ throw new Error("cardType is required");
16106
16577
  }
16107
- const command = normalizeString20(tokens[startIndex]).toLowerCase();
16108
- if (!command) {
16109
- return { matched: false, command: "", args: {}, error: "" };
16578
+ const params = new URLSearchParams();
16579
+ if (hasComplexPayload(payload)) {
16580
+ params.set("d", JSON.stringify(payload));
16581
+ } else {
16582
+ appendFlatPayload(params, payload);
16110
16583
  }
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
- };
16584
+ const query = params.toString();
16585
+ return `grix://card/${encodeURIComponent(normalizedType)}${query ? `?${query}` : ""}`;
16586
+ }
16587
+ function buildGrixCardLink({
16588
+ fallbackText,
16589
+ cardType,
16590
+ payload = {}
16591
+ }) {
16592
+ const normalizedFallbackText = normalizeString21(fallbackText);
16593
+ if (!normalizedFallbackText) {
16594
+ throw new Error("fallbackText is required");
16125
16595
  }
16126
- if (command === "status" || command === "stop" || command === "where") {
16127
- return {
16128
- matched: true,
16129
- ok: true,
16130
- command,
16131
- args: {},
16132
- error: ""
16133
- };
16596
+ return `[${normalizedFallbackText}](${buildGrixCardURI(cardType, payload)})`;
16597
+ }
16598
+ var init_grix_card_link = __esm({
16599
+ "server/grix-card-link.js"() {
16134
16600
  }
16135
- return { matched: false, command: "", args: {}, error: "" };
16601
+ });
16602
+
16603
+ // server/agent-open-session-card.js
16604
+ function normalizeString22(value) {
16605
+ return String(value ?? "").trim();
16606
+ }
16607
+ function buildAgentOpenSessionCardLink({
16608
+ fallbackText = "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55",
16609
+ summaryText = "",
16610
+ detailText = "",
16611
+ initialCwd = "",
16612
+ submittedPath = ""
16613
+ } = {}) {
16614
+ const payload = {};
16615
+ const normalizedSummaryText = normalizeString22(summaryText);
16616
+ const normalizedDetailText = normalizeString22(detailText);
16617
+ const normalizedInitialCwd = normalizeString22(initialCwd);
16618
+ const normalizedSubmittedPath = normalizeString22(submittedPath);
16619
+ if (normalizedSummaryText) {
16620
+ payload.summary_text = normalizedSummaryText;
16621
+ }
16622
+ if (normalizedDetailText) {
16623
+ payload.detail_text = normalizedDetailText;
16624
+ }
16625
+ if (normalizedInitialCwd) {
16626
+ payload.initial_cwd = normalizedInitialCwd;
16627
+ }
16628
+ if (normalizedSubmittedPath) {
16629
+ payload.submitted_path = normalizedSubmittedPath;
16630
+ }
16631
+ return buildGrixCardLink({
16632
+ fallbackText: normalizeString22(fallbackText) || "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55",
16633
+ cardType: "agent_open_session",
16634
+ payload
16635
+ });
16136
16636
  }
16137
- var init_control_command = __esm({
16138
- "server/daemon/control-command.js"() {
16637
+ var init_agent_open_session_card = __esm({
16638
+ "server/agent-open-session-card.js"() {
16639
+ init_grix_card_link();
16139
16640
  }
16140
16641
  });
16141
16642
 
16142
16643
  // server/inbound-event-meta.js
16143
- function normalizeString21(value) {
16644
+ function normalizeString23(value) {
16144
16645
  return String(value ?? "").trim();
16145
16646
  }
16146
16647
  function normalizeOptionalString(value) {
16147
- return normalizeString21(value) || "";
16648
+ return normalizeString23(value) || "";
16148
16649
  }
16149
16650
  function normalizeStringArray(value) {
16150
16651
  if (!Array.isArray(value)) {
16151
16652
  return [];
16152
16653
  }
16153
- return value.map((item) => normalizeString21(item)).filter((item) => item);
16654
+ return value.map((item) => normalizeString23(item)).filter((item) => item);
16154
16655
  }
16155
16656
  function normalizeJSONObject(value) {
16156
16657
  if (!value) {
@@ -16206,6 +16707,43 @@ function normalizeAttachmentRecord(value) {
16206
16707
  }
16207
16708
  return attachment;
16208
16709
  }
16710
+ function normalizeContextMessageRecord(value) {
16711
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
16712
+ return null;
16713
+ }
16714
+ const normalized = {
16715
+ msg_id: normalizeOptionalString(value.msg_id),
16716
+ sender_id: normalizeOptionalString(value.sender_id),
16717
+ sender_type: Number(value.sender_type ?? 0),
16718
+ msg_type: Number(value.msg_type ?? 0),
16719
+ content: String(value.content ?? ""),
16720
+ quoted_message_id: normalizeOptionalString(value.quoted_message_id),
16721
+ mention_user_ids: normalizeStringArray(value.mention_user_ids),
16722
+ created_at: Number(value.created_at ?? 0)
16723
+ };
16724
+ if (!normalized.msg_id) {
16725
+ return null;
16726
+ }
16727
+ return normalized;
16728
+ }
16729
+ function normalizeContextMessageArray(value) {
16730
+ if (Array.isArray(value)) {
16731
+ return value.map((item) => normalizeContextMessageRecord(item)).filter(Boolean);
16732
+ }
16733
+ if (typeof value === "string") {
16734
+ const trimmed = value.trim();
16735
+ if (!trimmed) {
16736
+ return [];
16737
+ }
16738
+ try {
16739
+ const parsed = JSON.parse(trimmed);
16740
+ return normalizeContextMessageArray(parsed);
16741
+ } catch {
16742
+ return [];
16743
+ }
16744
+ }
16745
+ return [];
16746
+ }
16209
16747
  function deriveAttachments(payload, extra) {
16210
16748
  const explicit = normalizeJSONArray(payload.attachments).map((item) => normalizeAttachmentRecord(item)).filter(Boolean);
16211
16749
  if (explicit.length > 0) {
@@ -16235,19 +16773,25 @@ function stringifyJSON(value) {
16235
16773
  }
16236
16774
  return JSON.stringify(value);
16237
16775
  }
16776
+ function deriveContextMessages(payload) {
16777
+ const currentMsgID = normalizeString23(payload.msg_id);
16778
+ return normalizeContextMessageArray(payload.context_messages).filter((entry) => entry.msg_id !== currentMsgID);
16779
+ }
16238
16780
  function normalizeInboundEventPayload(rawPayload) {
16239
16781
  const extra = normalizeJSONObject(rawPayload.extra);
16240
16782
  const attachments = deriveAttachments(rawPayload, extra);
16241
16783
  const bizCard = normalizeJSONObject(rawPayload.biz_card) ?? normalizeJSONObject(extra?.biz_card);
16242
16784
  const channelData = normalizeJSONObject(rawPayload.channel_data) ?? normalizeJSONObject(extra?.channel_data);
16785
+ const contextMessages = deriveContextMessages(rawPayload);
16243
16786
  return {
16244
- event_id: normalizeString21(rawPayload.event_id),
16245
- event_type: normalizeString21(rawPayload.event_type),
16246
- session_id: normalizeString21(rawPayload.session_id),
16787
+ event_id: normalizeString23(rawPayload.event_id),
16788
+ event_type: normalizeString23(rawPayload.event_type),
16789
+ mirror_mode: normalizeString23(rawPayload.mirror_mode),
16790
+ session_id: normalizeString23(rawPayload.session_id),
16247
16791
  session_type: normalizeOptionalString(rawPayload.session_type),
16248
- msg_id: normalizeString21(rawPayload.msg_id),
16792
+ msg_id: normalizeString23(rawPayload.msg_id),
16249
16793
  quoted_message_id: normalizeOptionalString(rawPayload.quoted_message_id),
16250
- sender_id: normalizeString21(rawPayload.sender_id),
16794
+ sender_id: normalizeString23(rawPayload.sender_id),
16251
16795
  owner_id: normalizeOptionalString(rawPayload.owner_id),
16252
16796
  agent_id: normalizeOptionalString(rawPayload.agent_id),
16253
16797
  msg_type: normalizeOptionalString(rawPayload.msg_type),
@@ -16258,7 +16802,8 @@ function normalizeInboundEventPayload(rawPayload) {
16258
16802
  attachments_json: stringifyJSON(attachments),
16259
16803
  attachment_count: attachments.length > 0 ? String(attachments.length) : "",
16260
16804
  biz_card_json: stringifyJSON(bizCard),
16261
- channel_data_json: stringifyJSON(channelData)
16805
+ channel_data_json: stringifyJSON(channelData),
16806
+ context_messages_json: stringifyJSON(contextMessages)
16262
16807
  };
16263
16808
  }
16264
16809
  var init_inbound_event_meta = __esm({
@@ -16267,7 +16812,7 @@ var init_inbound_event_meta = __esm({
16267
16812
  });
16268
16813
 
16269
16814
  // server/daemon/worker-control-client.js
16270
- function normalizeString22(value) {
16815
+ function normalizeString24(value) {
16271
16816
  return String(value ?? "").trim();
16272
16817
  }
16273
16818
  async function parseJSONResponse(response) {
@@ -16282,8 +16827,8 @@ var init_worker_control_client = __esm({
16282
16827
  "server/daemon/worker-control-client.js"() {
16283
16828
  WorkerControlClient = class {
16284
16829
  constructor({ controlURL, token, fetchImpl = globalThis.fetch, pingTimeoutMs = 5e3, deliverTimeoutMs = 1e4 } = {}) {
16285
- this.controlURL = normalizeString22(controlURL).replace(/\/+$/u, "");
16286
- this.token = normalizeString22(token);
16830
+ this.controlURL = normalizeString24(controlURL).replace(/\/+$/u, "");
16831
+ this.token = normalizeString24(token);
16287
16832
  this.fetchImpl = fetchImpl;
16288
16833
  this.pingTimeoutMs = pingTimeoutMs;
16289
16834
  this.deliverTimeoutMs = deliverTimeoutMs;
@@ -16291,135 +16836,52 @@ var init_worker_control_client = __esm({
16291
16836
  isConfigured() {
16292
16837
  return Boolean(this.controlURL && this.token && typeof this.fetchImpl === "function");
16293
16838
  }
16294
- async deliverEvent(rawPayload) {
16839
+ async post(pathname, payload, timeoutMs) {
16295
16840
  if (!this.isConfigured()) {
16296
16841
  throw new Error("worker control is not configured");
16297
16842
  }
16298
- const response = await this.fetchImpl(`${this.controlURL}/v1/worker/deliver-event`, {
16843
+ const response = await this.fetchImpl(`${this.controlURL}${pathname}`, {
16299
16844
  method: "POST",
16300
16845
  headers: {
16301
16846
  "content-type": "application/json",
16302
16847
  authorization: `Bearer ${this.token}`
16303
16848
  },
16304
- body: JSON.stringify({ payload: rawPayload }),
16305
- signal: AbortSignal.timeout(this.deliverTimeoutMs)
16849
+ body: JSON.stringify(payload),
16850
+ signal: AbortSignal.timeout(timeoutMs)
16306
16851
  });
16307
16852
  const json = await parseJSONResponse(response);
16308
16853
  if (!response.ok) {
16309
- throw new Error(normalizeString22(json.error) || `worker control failed ${response.status}`);
16854
+ throw new Error(normalizeString24(json.error) || `worker control failed ${response.status}`);
16310
16855
  }
16311
16856
  return json;
16312
16857
  }
16858
+ async deliverEvent(rawPayload) {
16859
+ return this.post("/v1/worker/deliver-event", { payload: rawPayload }, this.deliverTimeoutMs);
16860
+ }
16313
16861
  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;
16862
+ return this.post("/v1/worker/deliver-stop", { payload: rawPayload }, this.deliverTimeoutMs);
16331
16863
  }
16332
16864
  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;
16865
+ return this.post("/v1/worker/deliver-revoke", { payload: rawPayload }, this.deliverTimeoutMs);
16866
+ }
16867
+ async deliverLocalAction(rawPayload) {
16868
+ return this.post("/v1/worker/deliver-local-action", { payload: rawPayload }, this.deliverTimeoutMs);
16350
16869
  }
16351
16870
  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;
16871
+ return this.post("/v1/worker/ping", {}, this.pingTimeoutMs);
16369
16872
  }
16370
16873
  };
16371
16874
  }
16372
16875
  });
16373
16876
 
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
16877
  // server/daemon/claude-session-store.js
16416
16878
  import path22 from "node:path";
16417
16879
  import { access } from "node:fs/promises";
16418
- function normalizeString24(value) {
16880
+ function normalizeString25(value) {
16419
16881
  return String(value ?? "").trim();
16420
16882
  }
16421
16883
  function encodeClaudeProjectPath(cwd) {
16422
- const normalized = normalizeString24(cwd);
16884
+ const normalized = normalizeString25(cwd);
16423
16885
  if (!normalized) {
16424
16886
  return "";
16425
16887
  }
@@ -16427,8 +16889,8 @@ function encodeClaudeProjectPath(cwd) {
16427
16889
  }
16428
16890
  function resolveClaudeSessionPath({ cwd, claudeSessionID, env = process.env } = {}) {
16429
16891
  const projectKey = encodeClaudeProjectPath(cwd);
16430
- const sessionID = normalizeString24(claudeSessionID);
16431
- const homeDir = normalizeString24(env?.HOME);
16892
+ const sessionID = normalizeString25(claudeSessionID);
16893
+ const homeDir = normalizeString25(env?.HOME);
16432
16894
  if (!projectKey || !sessionID || !homeDir) {
16433
16895
  return "";
16434
16896
  }
@@ -16451,228 +16913,6 @@ var init_claude_session_store = __esm({
16451
16913
  }
16452
16914
  });
16453
16915
 
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
16916
  // server/daemon/worker-health-inspector.js
16677
16917
  function normalizeString26(value) {
16678
16918
  return String(value ?? "").trim();
@@ -16930,7 +17170,7 @@ function resolveRecordInFlightActivityAt(record) {
16930
17170
  const normalizedComposingAt = Number.isFinite(composingAt) && composingAt > 0 ? composingAt : 0;
16931
17171
  return Math.max(normalizedUpdatedAt, normalizedComposingAt);
16932
17172
  }
16933
- function sleep(ms) {
17173
+ function sleep2(ms) {
16934
17174
  return new Promise((resolve) => setTimeout(resolve, ms));
16935
17175
  }
16936
17176
  var PendingEventOrchestrator;
@@ -17077,7 +17317,7 @@ var init_pending_event_orchestrator = __esm({
17077
17317
  error: error instanceof Error ? error.message : String(error)
17078
17318
  }, "error");
17079
17319
  }
17080
- await sleep(this.retryDelayMs);
17320
+ await sleep2(this.retryDelayMs);
17081
17321
  const latestBinding = this.bindingRegistry.getByAibotSessionID(normalizedSessionID);
17082
17322
  if (!canDeliverToWorker(latestBinding)) {
17083
17323
  this.trace({
@@ -17192,9 +17432,474 @@ var init_session_queue = __esm({
17192
17432
  }
17193
17433
  });
17194
17434
 
17435
+ // server/inbound-interaction-action.js
17436
+ import path23 from "node:path";
17437
+ function normalizeString29(value) {
17438
+ return String(value ?? "").trim();
17439
+ }
17440
+ function buildUnmatchedResult() {
17441
+ return {
17442
+ matched: false,
17443
+ ok: false,
17444
+ source: "",
17445
+ action: null,
17446
+ errorCode: "",
17447
+ errorMsg: ""
17448
+ };
17449
+ }
17450
+ function buildErrorResult({
17451
+ source,
17452
+ errorCode,
17453
+ errorMsg
17454
+ } = {}) {
17455
+ return {
17456
+ matched: true,
17457
+ ok: false,
17458
+ source: normalizeString29(source),
17459
+ action: null,
17460
+ errorCode: normalizeString29(errorCode),
17461
+ errorMsg: normalizeString29(errorMsg)
17462
+ };
17463
+ }
17464
+ function buildSuccessResult({
17465
+ source,
17466
+ actionType,
17467
+ params,
17468
+ timeoutMs = 0
17469
+ } = {}) {
17470
+ return {
17471
+ matched: true,
17472
+ ok: true,
17473
+ source: normalizeString29(source),
17474
+ action: {
17475
+ action_type: normalizeString29(actionType),
17476
+ params: params && typeof params === "object" && !Array.isArray(params) ? params : {},
17477
+ timeout_ms: Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Math.floor(Number(timeoutMs)) : 0
17478
+ },
17479
+ errorCode: "",
17480
+ errorMsg: ""
17481
+ };
17482
+ }
17483
+ function decodeUrlComponentRepeatedly(value) {
17484
+ let current = normalizeString29(value);
17485
+ if (!current) {
17486
+ return "";
17487
+ }
17488
+ for (let index = 0; index < 3; index += 1) {
17489
+ try {
17490
+ const decoded = decodeURIComponent(current);
17491
+ if (decoded === current) {
17492
+ break;
17493
+ }
17494
+ current = decoded;
17495
+ } catch {
17496
+ break;
17497
+ }
17498
+ }
17499
+ return normalizeString29(current);
17500
+ }
17501
+ function extractGrixCardURI(text) {
17502
+ const normalizedText = normalizeString29(text).replace(/&amp;/giu, "&");
17503
+ if (!normalizedText) {
17504
+ return "";
17505
+ }
17506
+ const match = normalizedText.match(/grix:\/\/card\/[^\s)]+/u);
17507
+ return normalizeString29(match?.[0] ?? normalizedText);
17508
+ }
17509
+ function parseGrixCardURI(text) {
17510
+ const rawURI = extractGrixCardURI(text);
17511
+ if (!rawURI) {
17512
+ return null;
17513
+ }
17514
+ let parsed;
17515
+ try {
17516
+ parsed = new URL(rawURI);
17517
+ } catch {
17518
+ return null;
17519
+ }
17520
+ if (parsed.protocol !== "grix:" || normalizeString29(parsed.hostname) !== "card") {
17521
+ return null;
17522
+ }
17523
+ return parsed;
17524
+ }
17525
+ function normalizeResolutionMapEntries(entries) {
17526
+ if (!Array.isArray(entries)) {
17527
+ return [];
17528
+ }
17529
+ return entries.map((entry) => {
17530
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
17531
+ return null;
17532
+ }
17533
+ const key = normalizeString29(entry.key);
17534
+ const value = normalizeString29(entry.value);
17535
+ if (!key || !value) {
17536
+ return null;
17537
+ }
17538
+ return { key, value };
17539
+ }).filter(Boolean);
17540
+ }
17541
+ function parseQuestionReplyPayload(rawPayload) {
17542
+ const decoded = decodeUrlComponentRepeatedly(rawPayload);
17543
+ if (!decoded) {
17544
+ return null;
17545
+ }
17546
+ try {
17547
+ const parsed = JSON.parse(decoded);
17548
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
17549
+ } catch {
17550
+ return null;
17551
+ }
17552
+ }
17553
+ function parseQuestionReplyAction(parsedURI) {
17554
+ const payload = parseQuestionReplyPayload(parsedURI?.searchParams?.get("d"));
17555
+ if (!payload) {
17556
+ return buildErrorResult({
17557
+ source: "grix_card_question_reply",
17558
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17559
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u5185\u5BB9\u683C\u5F0F\u4E0D\u6B63\u786E\u3002"
17560
+ });
17561
+ }
17562
+ const requestID = normalizeString29(payload.request_id);
17563
+ if (!requestID) {
17564
+ return buildErrorResult({
17565
+ source: "grix_card_question_reply",
17566
+ errorCode: interactionReplyErrorCodes.requestIDRequired,
17567
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11 request_id\u3002"
17568
+ });
17569
+ }
17570
+ const action = normalizeString29(payload.action).toLowerCase();
17571
+ if (action) {
17572
+ if (!["accept", "cancel", "decline"].includes(action)) {
17573
+ return buildErrorResult({
17574
+ source: "grix_card_question_reply",
17575
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17576
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u52A8\u4F5C\u65E0\u6548\u3002"
17577
+ });
17578
+ }
17579
+ return buildSuccessResult({
17580
+ source: "grix_card_question_reply",
17581
+ actionType: localActionTypes.interactionReply,
17582
+ timeoutMs: 15e3,
17583
+ params: {
17584
+ kind: interactionKinds.elicitation,
17585
+ request_id: requestID,
17586
+ resolution: {
17587
+ type: interactionResolutionTypes.action,
17588
+ value: action
17589
+ }
17590
+ }
17591
+ });
17592
+ }
17593
+ const response = payload.response;
17594
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
17595
+ return buildErrorResult({
17596
+ source: "grix_card_question_reply",
17597
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17598
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u7B54\u6848\u5185\u5BB9\u3002"
17599
+ });
17600
+ }
17601
+ const responseType = normalizeString29(response.type).toLowerCase();
17602
+ if (responseType === "single") {
17603
+ const value = normalizeString29(response.value);
17604
+ if (!value) {
17605
+ return buildErrorResult({
17606
+ source: "grix_card_question_reply",
17607
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17608
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u7B54\u6848\u5185\u5BB9\u3002"
17609
+ });
17610
+ }
17611
+ return buildSuccessResult({
17612
+ source: "grix_card_question_reply",
17613
+ actionType: localActionTypes.interactionReply,
17614
+ timeoutMs: 15e3,
17615
+ params: {
17616
+ kind: interactionKinds.elicitation,
17617
+ request_id: requestID,
17618
+ resolution: {
17619
+ type: interactionResolutionTypes.text,
17620
+ value
17621
+ }
17622
+ }
17623
+ });
17624
+ }
17625
+ if (responseType === "map") {
17626
+ const entries = normalizeResolutionMapEntries(response.entries);
17627
+ if (entries.length === 0) {
17628
+ return buildErrorResult({
17629
+ source: "grix_card_question_reply",
17630
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17631
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7F3A\u5C11\u6709\u6548\u7B54\u6848\u3002"
17632
+ });
17633
+ }
17634
+ return buildSuccessResult({
17635
+ source: "grix_card_question_reply",
17636
+ actionType: localActionTypes.interactionReply,
17637
+ timeoutMs: 15e3,
17638
+ params: {
17639
+ kind: interactionKinds.elicitation,
17640
+ request_id: requestID,
17641
+ resolution: {
17642
+ type: interactionResolutionTypes.map,
17643
+ entries
17644
+ }
17645
+ }
17646
+ });
17647
+ }
17648
+ return buildErrorResult({
17649
+ source: "grix_card_question_reply",
17650
+ errorCode: interactionReplyErrorCodes.resolutionInvalid,
17651
+ errorMsg: "\u4EA4\u4E92\u56DE\u590D\u7C7B\u578B\u65E0\u6548\u3002"
17652
+ });
17653
+ }
17654
+ function parseOpenSessionAction(parsedURI) {
17655
+ const cwd = decodeUrlComponentRepeatedly(parsedURI?.searchParams?.get("cwd"));
17656
+ if (!cwd) {
17657
+ return buildErrorResult({
17658
+ source: "grix_card_open_session_submit",
17659
+ errorCode: sessionControlErrorCodes.cwdRequired,
17660
+ errorMsg: "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u65F6\u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002"
17661
+ });
17662
+ }
17663
+ return buildSuccessResult({
17664
+ source: "grix_card_open_session_submit",
17665
+ actionType: localActionTypes.sessionControl,
17666
+ params: {
17667
+ verb: "open",
17668
+ cwd: path23.resolve(cwd)
17669
+ }
17670
+ });
17671
+ }
17672
+ function parseInboundInteractionAction(text) {
17673
+ const parsedURI = parseGrixCardURI(text);
17674
+ if (!parsedURI) {
17675
+ return buildUnmatchedResult();
17676
+ }
17677
+ const cardType = normalizeString29(parsedURI.pathname).replace(/^\/+/u, "");
17678
+ if (cardType === "agent_open_session_submit") {
17679
+ return parseOpenSessionAction(parsedURI);
17680
+ }
17681
+ if (cardType === "agent_question_reply") {
17682
+ return parseQuestionReplyAction(parsedURI);
17683
+ }
17684
+ return buildUnmatchedResult();
17685
+ }
17686
+ var init_inbound_interaction_action = __esm({
17687
+ "server/inbound-interaction-action.js"() {
17688
+ init_protocol_contract();
17689
+ }
17690
+ });
17691
+
17692
+ // server/daemon/session-control-action-handler.js
17693
+ import { randomUUID as randomUUID6 } from "node:crypto";
17694
+ function normalizeString30(value) {
17695
+ return String(value ?? "").trim();
17696
+ }
17697
+ function buildBindingResult(binding) {
17698
+ return {
17699
+ aibot_session_id: normalizeString30(binding?.aibot_session_id),
17700
+ claude_session_id: normalizeString30(binding?.claude_session_id),
17701
+ cwd: normalizeString30(binding?.cwd),
17702
+ worker_status: normalizeString30(binding?.worker_status)
17703
+ };
17704
+ }
17705
+ function buildSuccessResult2(verb, outcome, binding) {
17706
+ return {
17707
+ status: localActionResultStatuses.ok,
17708
+ result: {
17709
+ domain: resultDomains.sessionControl,
17710
+ verb,
17711
+ outcome,
17712
+ binding: buildBindingResult(binding)
17713
+ }
17714
+ };
17715
+ }
17716
+ function buildFailure(errorCode, errorMsg) {
17717
+ return {
17718
+ status: localActionResultStatuses.failed,
17719
+ errorCode,
17720
+ errorMsg
17721
+ };
17722
+ }
17723
+ var DaemonSessionControlActionHandler;
17724
+ var init_session_control_action_handler = __esm({
17725
+ "server/daemon/session-control-action-handler.js"() {
17726
+ init_protocol_contract();
17727
+ init_daemon_paths();
17728
+ DaemonSessionControlActionHandler = class {
17729
+ constructor({
17730
+ env = process.env,
17731
+ bindingRegistry,
17732
+ workerProcessManager,
17733
+ bridgeServer,
17734
+ ensureWorker,
17735
+ ensureDirectoryExists: ensureDirectoryExists2
17736
+ } = {}) {
17737
+ this.env = env;
17738
+ this.bindingRegistry = bindingRegistry;
17739
+ this.workerProcessManager = workerProcessManager;
17740
+ this.bridgeServer = bridgeServer;
17741
+ this.ensureWorker = ensureWorker;
17742
+ this.ensureDirectoryExists = ensureDirectoryExists2;
17743
+ }
17744
+ getBinding(sessionID) {
17745
+ return this.bindingRegistry.getByAibotSessionID(sessionID);
17746
+ }
17747
+ async createBinding(sessionID, cwd) {
17748
+ const workerID = randomUUID6();
17749
+ const claudeSessionID = randomUUID6();
17750
+ const pluginDataDir = resolveWorkerPluginDataDir(sessionID, this.env);
17751
+ const now = Date.now();
17752
+ const created = await this.bindingRegistry.createBinding({
17753
+ aibot_session_id: sessionID,
17754
+ claude_session_id: claudeSessionID,
17755
+ cwd,
17756
+ worker_id: workerID,
17757
+ worker_status: bindingWorkerStatuses.starting,
17758
+ plugin_data_dir: pluginDataDir,
17759
+ created_at: now,
17760
+ updated_at: now,
17761
+ last_started_at: now,
17762
+ last_stopped_at: 0
17763
+ });
17764
+ await this.workerProcessManager.spawnWorker({
17765
+ aibotSessionID: created.aibot_session_id,
17766
+ cwd: created.cwd,
17767
+ pluginDataDir: created.plugin_data_dir,
17768
+ claudeSessionID: created.claude_session_id,
17769
+ workerID: created.worker_id,
17770
+ bridgeURL: this.bridgeServer.getURL(),
17771
+ bridgeToken: this.bridgeServer.token
17772
+ });
17773
+ return this.getBinding(sessionID) ?? created;
17774
+ }
17775
+ async handleOpen(sessionID, params) {
17776
+ const cwd = normalizeString30(params?.cwd);
17777
+ if (!cwd) {
17778
+ return buildFailure(sessionControlErrorCodes.cwdRequired, "session control cwd is required");
17779
+ }
17780
+ try {
17781
+ await this.ensureDirectoryExists(cwd);
17782
+ } catch (error) {
17783
+ return buildFailure(
17784
+ sessionControlErrorCodes.invalidCwd,
17785
+ normalizeString30(error?.message || error) || "session control cwd is invalid"
17786
+ );
17787
+ }
17788
+ const existing = this.getBinding(sessionID);
17789
+ if (existing) {
17790
+ if (existing.cwd !== cwd) {
17791
+ return buildFailure(
17792
+ sessionControlErrorCodes.rebindForbidden,
17793
+ "session binding cannot be changed to another working directory"
17794
+ );
17795
+ }
17796
+ try {
17797
+ await this.ensureWorker(existing, { ignoreAuthCooldown: true });
17798
+ } catch (error) {
17799
+ return buildFailure(
17800
+ sessionControlErrorCodes.runtimeError,
17801
+ normalizeString30(error?.message || error) || "session control open failed"
17802
+ );
17803
+ }
17804
+ return buildSuccessResult2(sessionControlVerbs.open, sessionControlOutcomes.alreadyBound, this.getBinding(sessionID) ?? existing);
17805
+ }
17806
+ try {
17807
+ const created = await this.createBinding(sessionID, cwd);
17808
+ return buildSuccessResult2(sessionControlVerbs.open, sessionControlOutcomes.opened, created);
17809
+ } catch (error) {
17810
+ return buildFailure(
17811
+ sessionControlErrorCodes.runtimeError,
17812
+ normalizeString30(error?.message || error) || "session control open failed"
17813
+ );
17814
+ }
17815
+ }
17816
+ handleStatus(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.status, sessionControlOutcomes.status, binding);
17822
+ }
17823
+ handleWhere(sessionID) {
17824
+ const binding = this.getBinding(sessionID);
17825
+ if (!binding) {
17826
+ return buildFailure(sessionControlErrorCodes.bindingMissing, "session binding was not found");
17827
+ }
17828
+ return buildSuccessResult2(sessionControlVerbs.where, sessionControlOutcomes.where, binding);
17829
+ }
17830
+ async handleStop(sessionID) {
17831
+ const binding = this.getBinding(sessionID);
17832
+ if (!binding) {
17833
+ return buildFailure(sessionControlErrorCodes.bindingMissing, "session binding was not found");
17834
+ }
17835
+ try {
17836
+ if (binding.worker_id) {
17837
+ await this.workerProcessManager.stopWorker(binding.worker_id);
17838
+ }
17839
+ await this.bindingRegistry.markWorkerStopped(sessionID, {
17840
+ updatedAt: Date.now(),
17841
+ lastStoppedAt: Date.now()
17842
+ });
17843
+ } catch (error) {
17844
+ return buildFailure(
17845
+ sessionControlErrorCodes.runtimeError,
17846
+ normalizeString30(error?.message || error) || "session control stop failed"
17847
+ );
17848
+ }
17849
+ return buildSuccessResult2(sessionControlVerbs.stop, sessionControlOutcomes.stopped, this.getBinding(sessionID) ?? {
17850
+ ...binding,
17851
+ worker_status: bindingWorkerStatuses.stopped
17852
+ });
17853
+ }
17854
+ async handleLocalAction(action) {
17855
+ if (normalizeString30(action?.action_type) !== localActionTypes.sessionControl) {
17856
+ return {
17857
+ handled: false
17858
+ };
17859
+ }
17860
+ const sessionID = normalizeString30(action?.params?.session_id);
17861
+ if (!sessionID) {
17862
+ return {
17863
+ handled: true,
17864
+ response: buildFailure(localActionErrorCodes.localActionRouteMissing, "local action session_id is required")
17865
+ };
17866
+ }
17867
+ const verb = normalizeString30(action?.params?.verb).toLowerCase();
17868
+ switch (verb) {
17869
+ case sessionControlVerbs.open:
17870
+ return {
17871
+ handled: true,
17872
+ response: await this.handleOpen(sessionID, action.params)
17873
+ };
17874
+ case sessionControlVerbs.status:
17875
+ return {
17876
+ handled: true,
17877
+ response: this.handleStatus(sessionID)
17878
+ };
17879
+ case sessionControlVerbs.where:
17880
+ return {
17881
+ handled: true,
17882
+ response: this.handleWhere(sessionID)
17883
+ };
17884
+ case sessionControlVerbs.stop:
17885
+ return {
17886
+ handled: true,
17887
+ response: await this.handleStop(sessionID)
17888
+ };
17889
+ default:
17890
+ return {
17891
+ handled: true,
17892
+ response: buildFailure(sessionControlErrorCodes.verbInvalid, "session control verb is invalid")
17893
+ };
17894
+ }
17895
+ }
17896
+ };
17897
+ }
17898
+ });
17899
+
17195
17900
  // server/worker-probe.js
17196
17901
  import { randomUUID as randomUUID7 } from "node:crypto";
17197
- function normalizeString29(value) {
17902
+ function normalizeString31(value) {
17198
17903
  return String(value ?? "").trim();
17199
17904
  }
17200
17905
  function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID = "" } = {}) {
@@ -17211,7 +17916,7 @@ function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID
17211
17916
  return {
17212
17917
  event_id: `probe_${probeID}`,
17213
17918
  event_type: "user_chat",
17214
- session_id: normalizeString29(sessionID),
17919
+ session_id: normalizeString31(sessionID),
17215
17920
  session_type: "1",
17216
17921
  msg_id: `probe_msg_${probeID}`,
17217
17922
  sender_id: probeSenderID,
@@ -17220,13 +17925,13 @@ function buildWorkerPingProbePayload({ sessionID, workerID = "", claudeSessionID
17220
17925
  msg_type: "1",
17221
17926
  content: "ping",
17222
17927
  created_at: Date.now(),
17223
- worker_id: normalizeString29(workerID),
17224
- claude_session_id: normalizeString29(claudeSessionID),
17928
+ worker_id: normalizeString31(workerID),
17929
+ claude_session_id: normalizeString31(claudeSessionID),
17225
17930
  channel_data: channelData
17226
17931
  };
17227
17932
  }
17228
17933
  function isExpectedWorkerProbeReply(text, expectedReply = "pong") {
17229
- return normalizeString29(text).toLowerCase() === normalizeString29(expectedReply).toLowerCase();
17934
+ return normalizeString31(text).toLowerCase() === normalizeString31(expectedReply).toLowerCase();
17230
17935
  }
17231
17936
  var probeChannelNamespace, probeSenderID, probeKind, defaultWorkerPingProbeTimeoutMs;
17232
17937
  var init_worker_probe = __esm({
@@ -17240,19 +17945,22 @@ var init_worker_probe = __esm({
17240
17945
 
17241
17946
  // server/daemon/runtime.js
17242
17947
  import { randomUUID as randomUUID8 } from "node:crypto";
17243
- import { stat as stat2 } from "node:fs/promises";
17244
- function normalizeString30(value) {
17948
+ import { stat as stat3 } from "node:fs/promises";
17949
+ function normalizeString32(value) {
17245
17950
  return String(value ?? "").trim();
17246
17951
  }
17247
- function sleep2(ms) {
17952
+ function isRecordOnlyMirror(event) {
17953
+ return normalizeString32(event?.mirror_mode) === "record_only";
17954
+ }
17955
+ function sleep3(ms) {
17248
17956
  return new Promise((resolve) => setTimeout(resolve, ms));
17249
17957
  }
17250
17958
  async function ensureDirectoryExists(directoryPath) {
17251
17959
  let info;
17252
17960
  try {
17253
- info = await stat2(directoryPath);
17961
+ info = await stat3(directoryPath);
17254
17962
  } catch (error) {
17255
- const code = normalizeString30(error?.code);
17963
+ const code = normalizeString32(error?.code);
17256
17964
  if (code === "ENOENT") {
17257
17965
  throw new Error("\u6307\u5B9A\u8DEF\u5F84\u4E0D\u5B58\u5728\u3002");
17258
17966
  }
@@ -17265,44 +17973,6 @@ async function ensureDirectoryExists(directoryPath) {
17265
17973
  throw new Error("\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\u3002");
17266
17974
  }
17267
17975
  }
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
17976
  function buildInterruptedEventNotice() {
17307
17977
  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
17978
  }
@@ -17312,46 +17982,147 @@ function buildAuthLoginRequiredEventNotice() {
17312
17982
  function buildUsageLimitReachedEventNotice() {
17313
17983
  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
17984
  }
17985
+ function buildBindingMissingEventNotice() {
17986
+ return buildAgentOpenSessionCardLink({
17987
+ summaryText: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002",
17988
+ 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"
17989
+ });
17990
+ }
17991
+ function buildSessionControlOpenCardNotice({
17992
+ summaryText = "",
17993
+ detailText = "",
17994
+ initialCwd = ""
17995
+ } = {}) {
17996
+ return buildAgentOpenSessionCardLink({
17997
+ summaryText: normalizeString32(summaryText) || "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002",
17998
+ detailText: normalizeString32(detailText) || "\u5148\u63D0\u4EA4\u4E00\u4E2A\u5DE5\u4F5C\u76EE\u5F55\uFF0CClaude \u624D\u80FD\u7EE7\u7EED\u5904\u7406\u6D88\u606F\u3002",
17999
+ initialCwd
18000
+ });
18001
+ }
18002
+ function formatSessionControlBindingSummary(binding) {
18003
+ const normalizedBinding = binding ?? {};
18004
+ const cwd = normalizeString32(normalizedBinding.cwd);
18005
+ const workerStatus = normalizeString32(normalizedBinding.worker_status);
18006
+ const lines = [];
18007
+ if (cwd) {
18008
+ lines.push(`\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}`);
18009
+ }
18010
+ if (workerStatus) {
18011
+ lines.push(`\u72B6\u6001\uFF1A${workerStatus}`);
18012
+ }
18013
+ return lines.join("\n");
18014
+ }
18015
+ function buildSessionControlSuccessNotice(result) {
18016
+ const verb = normalizeString32(result?.verb);
18017
+ const outcome = normalizeString32(result?.outcome);
18018
+ const binding = result?.binding ?? {};
18019
+ const summary = formatSessionControlBindingSummary(binding);
18020
+ if (verb === sessionControlVerbs.open) {
18021
+ 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";
18022
+ return summary ? `${title}
18023
+
18024
+ ${summary}` : title;
18025
+ }
18026
+ if (verb === sessionControlVerbs.status) {
18027
+ return summary || "\u5F53\u524D\u5BF9\u8BDD\u5DF2\u7ECF\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18028
+ }
18029
+ if (verb === sessionControlVerbs.where) {
18030
+ const cwd = normalizeString32(binding.cwd);
18031
+ return cwd ? `\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}` : "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18032
+ }
18033
+ if (verb === sessionControlVerbs.stop) {
18034
+ return summary ? `\u5DF2\u505C\u6B62\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F1A\u8BDD\u3002
18035
+
18036
+ ${summary}` : "\u5DF2\u505C\u6B62\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F1A\u8BDD\u3002";
18037
+ }
18038
+ return "\u5DE5\u4F5C\u76EE\u5F55\u64CD\u4F5C\u5DF2\u5B8C\u6210\u3002";
18039
+ }
18040
+ function buildSessionControlFailureNotice({
18041
+ errorCode = "",
18042
+ errorMsg = ""
18043
+ } = {}) {
18044
+ const normalizedErrorCode = normalizeString32(errorCode);
18045
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18046
+ if (normalizedErrorCode === sessionControlErrorCodes.rebindForbidden) {
18047
+ return normalizedErrorMsg || "\u5F53\u524D\u5BF9\u8BDD\u5DF2\u7ECF\u56FA\u5B9A\u7ED1\u5B9A\u5230\u53E6\u4E00\u4E2A\u5DE5\u4F5C\u76EE\u5F55\u3002";
18048
+ }
18049
+ if (normalizedErrorCode === sessionControlErrorCodes.verbInvalid) {
18050
+ return normalizedErrorMsg || "\u547D\u4EE4\u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
18051
+ }
18052
+ return normalizedErrorMsg || "\u5DE5\u4F5C\u76EE\u5F55\u64CD\u4F5C\u5931\u8D25\u3002";
18053
+ }
18054
+ function buildSessionControlCardSummary(errorCode, errorMsg) {
18055
+ const normalizedErrorCode = normalizeString32(errorCode);
18056
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18057
+ if (normalizedErrorCode === sessionControlErrorCodes.bindingMissing) {
18058
+ return "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18059
+ }
18060
+ if (normalizedErrorCode === sessionControlErrorCodes.invalidCwd) {
18061
+ return normalizedErrorMsg || "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u53EF\u7528\u3002";
18062
+ }
18063
+ if (normalizedErrorCode === sessionControlErrorCodes.cwdRequired) {
18064
+ return normalizedErrorMsg || "\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u65F6\u7F3A\u5C11\u76EE\u5F55\u8DEF\u5F84\u3002";
18065
+ }
18066
+ return normalizedErrorMsg || "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u6253\u5F00\u5DE5\u4F5C\u76EE\u5F55\u3002";
18067
+ }
18068
+ function buildInteractionReplyFailureNotice({
18069
+ errorCode = "",
18070
+ errorMsg = ""
18071
+ } = {}) {
18072
+ const normalizedErrorCode = normalizeString32(errorCode);
18073
+ const normalizedErrorMsg = normalizeString32(errorMsg);
18074
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestNotPending) {
18075
+ return "\u8FD9\u6761\u4EA4\u4E92\u5DF2\u7ECF\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u3002";
18076
+ }
18077
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestNotFound) {
18078
+ return "\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u4EA4\u4E92\u8BF7\u6C42\u3002";
18079
+ }
18080
+ if (normalizedErrorCode === interactionReplyErrorCodes.requestIDRequired || normalizedErrorCode === interactionReplyErrorCodes.resolutionInvalid) {
18081
+ return normalizedErrorMsg || "\u4EA4\u4E92\u56DE\u590D\u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
18082
+ }
18083
+ if (normalizedErrorCode === "local_action_delivery_failed") {
18084
+ return "Claude \u8FD8\u6CA1\u51C6\u5907\u597D\u5904\u7406\u8FD9\u6761\u4EA4\u4E92\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
18085
+ }
18086
+ if (normalizedErrorCode === "local_action_result_timeout") {
18087
+ return "\u4EA4\u4E92\u56DE\u590D\u63D0\u4EA4\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
18088
+ }
18089
+ return normalizedErrorMsg || "\u4EA4\u4E92\u56DE\u590D\u63D0\u4EA4\u5931\u8D25\u3002";
18090
+ }
17315
18091
  function buildWorkerStartupFailedNotice() {
17316
18092
  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
18093
  }
17318
18094
  function buildUsageLimitFailureOptions() {
17319
18095
  return {
17320
18096
  noticeText: buildUsageLimitReachedEventNotice(),
17321
- replySource: "daemon_worker_usage_limit_reached",
17322
18097
  resultCode: "claude_usage_limit_reached",
17323
18098
  resultMessage: "claude usage limit reached; user action required"
17324
18099
  };
17325
18100
  }
17326
- function buildMissingBindingCardOptions() {
18101
+ function normalizeLocalActionPayload(rawPayload) {
17327
18102
  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"
18103
+ action_id: normalizeString32(rawPayload?.action_id),
18104
+ event_id: normalizeString32(rawPayload?.event_id),
18105
+ action_type: normalizeString32(rawPayload?.action_type),
18106
+ params: rawPayload?.params && typeof rawPayload.params === "object" && !Array.isArray(rawPayload.params) ? rawPayload.params : {},
18107
+ timeout_ms: normalizeNonNegativeInt(rawPayload?.timeout_ms, 0)
17330
18108
  };
17331
18109
  }
17332
18110
  function withWorkerLaunchFailure(binding, code) {
17333
18111
  return {
17334
18112
  ...binding ?? {},
17335
- worker_launch_failure: normalizeString30(code)
18113
+ worker_launch_failure: normalizeString32(code)
17336
18114
  };
17337
18115
  }
17338
18116
  function formatRuntimeError(error, fallback = "\u5904\u7406\u5931\u8D25\u3002") {
17339
- const message = normalizeString30(error?.message || error);
18117
+ const message = normalizeString32(error?.message || error);
17340
18118
  return message || fallback;
17341
18119
  }
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
18120
  function normalizeHookSignalRecord(input) {
17350
18121
  if (!input || typeof input !== "object") {
17351
18122
  return null;
17352
18123
  }
17353
- const eventID = normalizeString30(input.event_id);
17354
- const eventName = normalizeString30(input.hook_event_name);
18124
+ const eventID = normalizeString32(input.event_id);
18125
+ const eventName = normalizeString32(input.hook_event_name);
17355
18126
  const eventAt = Number(input.event_at ?? 0);
17356
18127
  if (!eventID || !eventName || !Number.isFinite(eventAt) || eventAt <= 0) {
17357
18128
  return null;
@@ -17360,7 +18131,7 @@ function normalizeHookSignalRecord(input) {
17360
18131
  event_id: eventID,
17361
18132
  hook_event_name: eventName,
17362
18133
  event_at: Math.floor(eventAt),
17363
- detail: normalizeString30(input.detail)
18134
+ detail: normalizeString32(input.detail)
17364
18135
  };
17365
18136
  }
17366
18137
  function listHookSignalRecords(pingPayload) {
@@ -17386,12 +18157,12 @@ function buildPingActivityTraceFields(pingPayload = {}) {
17386
18157
  reported_mcp_ready: pingPayload?.mcp_ready === true ? true : pingPayload?.mcp_ready === false ? false : "",
17387
18158
  reported_mcp_last_activity_at: normalizeNonNegativeInt(pingPayload?.mcp_last_activity_at, 0),
17388
18159
  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)
18160
+ reported_hook_event_name: normalizeString32(pingPayload?.hook_latest_event?.hook_event_name)
17390
18161
  };
17391
18162
  }
17392
18163
  function buildMcpHealthTraceFields(mcpHealth = {}) {
17393
18164
  return {
17394
- mcp_health_reason: normalizeString30(mcpHealth?.reason),
18165
+ mcp_health_reason: normalizeString32(mcpHealth?.reason),
17395
18166
  mcp_health_idle_ms: normalizeNonNegativeInt(mcpHealth?.idleMs, 0),
17396
18167
  inflight_event_count: normalizeNonNegativeInt(mcpHealth?.inFlightCount, 0),
17397
18168
  latest_event_activity_at: normalizeNonNegativeInt(mcpHealth?.latestInteractionAt, 0),
@@ -17400,7 +18171,7 @@ function buildMcpHealthTraceFields(mcpHealth = {}) {
17400
18171
  }
17401
18172
  function buildMcpResultTimeoutTraceFields(details = {}) {
17402
18173
  return {
17403
- delivery_state: normalizeString30(details?.deliveryState),
18174
+ delivery_state: normalizeString32(details?.deliveryState),
17404
18175
  record_updated_at: normalizeNonNegativeInt(details?.updatedAt, 0),
17405
18176
  record_last_composing_at: normalizeNonNegativeInt(details?.lastComposingAt, 0),
17406
18177
  record_interaction_at: normalizeNonNegativeInt(details?.recordInteractionAt, 0),
@@ -17416,6 +18187,9 @@ function normalizeNonNegativeInt(value, fallbackValue) {
17416
18187
  }
17417
18188
  return Math.max(0, Math.floor(numeric));
17418
18189
  }
18190
+ function isSyntheticLocalActionID(actionID) {
18191
+ return normalizeString32(actionID).startsWith(syntheticLocalActionIDPrefix);
18192
+ }
17419
18193
  function resolveExpectedWorkerPid(binding, runtime) {
17420
18194
  const bindingPid = Number(binding?.worker_pid ?? 0);
17421
18195
  if (Number.isFinite(bindingPid) && bindingPid > 0) {
@@ -17435,15 +18209,15 @@ function resolveExpectedIdentityWorkerPid(binding) {
17435
18209
  return 0;
17436
18210
  }
17437
18211
  function buildRevokeDedupKey({ eventID = "", sessionID = "", msgID = "" } = {}) {
17438
- const normalizedSessionID = normalizeString30(sessionID);
17439
- const normalizedMsgID = normalizeString30(msgID);
18212
+ const normalizedSessionID = normalizeString32(sessionID);
18213
+ const normalizedMsgID = normalizeString32(msgID);
17440
18214
  if (normalizedSessionID && normalizedMsgID) {
17441
18215
  return `${normalizedSessionID}:${normalizedMsgID}`;
17442
18216
  }
17443
- return normalizeString30(eventID);
18217
+ return normalizeString32(eventID);
17444
18218
  }
17445
18219
  function classifyWorkerEventResult(payload) {
17446
- const code = normalizeString30(payload?.code);
18220
+ const code = normalizeString32(payload?.code);
17447
18221
  if (workerResponseFailureCodes.has(code)) {
17448
18222
  return {
17449
18223
  state: "failed",
@@ -17453,27 +18227,28 @@ function classifyWorkerEventResult(payload) {
17453
18227
  }
17454
18228
  return {
17455
18229
  state: "healthy",
17456
- reason: code || normalizeString30(payload?.status) || "worker_event_result_observed",
18230
+ reason: code || normalizeString32(payload?.status) || "worker_event_result_observed",
17457
18231
  failureCode: ""
17458
18232
  };
17459
18233
  }
17460
- var defaultDeliveredInFlightMaxAgeMs, defaultWorkerControlProbeFailureThreshold, defaultMcpInteractionIdleMs, defaultMcpResultTimeoutMs, defaultRecentRevokeRetentionMs, defaultAuthFailureCooldownMs, defaultWorkerPingProbeRetentionMs, workerResponseFailureCodes, DaemonRuntime;
18234
+ var defaultDeliveredInFlightMaxAgeMs, defaultWorkerControlProbeFailureThreshold, defaultMcpInteractionIdleMs, defaultMcpResultTimeoutMs, defaultRecentRevokeRetentionMs, defaultAuthFailureCooldownMs, defaultWorkerPingProbeRetentionMs, syntheticLocalActionIDPrefix, workerResponseFailureCodes, DaemonRuntime;
17461
18235
  var init_runtime = __esm({
17462
18236
  "server/daemon/runtime.js"() {
17463
- init_control_command();
18237
+ init_agent_open_session_card();
17464
18238
  init_inbound_event_meta();
17465
18239
  init_message_delivery_store();
17466
18240
  init_worker_control_client();
17467
- init_control_card();
17468
18241
  init_claude_session_store();
17469
- init_control_command_handler();
17470
18242
  init_worker_health_inspector();
17471
18243
  init_pending_event_orchestrator();
17472
18244
  init_session_queue();
17473
18245
  init_process_control();
17474
18246
  init_hook_signal_store();
18247
+ init_inbound_interaction_action();
18248
+ init_session_control_action_handler();
17475
18249
  init_worker_state();
17476
18250
  init_worker_probe();
18251
+ init_protocol_contract();
17477
18252
  defaultDeliveredInFlightMaxAgeMs = 60 * 1e3;
17478
18253
  defaultWorkerControlProbeFailureThreshold = 3;
17479
18254
  defaultMcpInteractionIdleMs = 15 * 60 * 1e3;
@@ -17481,6 +18256,7 @@ var init_runtime = __esm({
17481
18256
  defaultRecentRevokeRetentionMs = 24 * 60 * 60 * 1e3;
17482
18257
  defaultAuthFailureCooldownMs = 60 * 1e3;
17483
18258
  defaultWorkerPingProbeRetentionMs = 60 * 1e3;
18259
+ syntheticLocalActionIDPrefix = "synthetic-local-action:";
17484
18260
  workerResponseFailureCodes = /* @__PURE__ */ new Set([
17485
18261
  "claude_result_timeout",
17486
18262
  "claude_usage_limit_reached",
@@ -17562,6 +18338,7 @@ var init_runtime = __esm({
17562
18338
  this.workerControlProbeFailures = /* @__PURE__ */ new Map();
17563
18339
  this.workerPingProbeRecords = /* @__PURE__ */ new Map();
17564
18340
  this.workerPingProbeInFlight = /* @__PURE__ */ new Map();
18341
+ this.syntheticLocalActionWaiters = /* @__PURE__ */ new Map();
17565
18342
  this.pendingEventWorkerLogCursors = /* @__PURE__ */ new Map();
17566
18343
  this.ensureWorkerInFlight = /* @__PURE__ */ new Map();
17567
18344
  this.resumeAuthRecoveryInFlight = /* @__PURE__ */ new Map();
@@ -17569,18 +18346,13 @@ var init_runtime = __esm({
17569
18346
  this.sessionQueues = new SessionQueueRegistry(
17570
18347
  (fields, level) => this.trace(fields, level)
17571
18348
  );
17572
- this.controlCommandHandler = new DaemonControlCommandHandler({
18349
+ this.sessionControlActionHandler = new DaemonSessionControlActionHandler({
17573
18350
  env: this.env,
17574
18351
  bindingRegistry: this.bindingRegistry,
17575
18352
  workerProcessManager: this.workerProcessManager,
17576
18353
  bridgeServer: this.bridgeServer,
17577
18354
  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
18355
+ ensureDirectoryExists
17584
18356
  });
17585
18357
  this.pendingEventOrchestrator = new PendingEventOrchestrator({
17586
18358
  messageDeliveryStore: this.messageDeliveryStore,
@@ -17612,18 +18384,18 @@ var init_runtime = __esm({
17612
18384
  }, { level });
17613
18385
  }
17614
18386
  async handleWorkerProcessExit({ workerID, aibotSessionID, exitCode, exitSignal }) {
17615
- const sessionID = normalizeString30(aibotSessionID);
18387
+ const sessionID = normalizeString32(aibotSessionID);
17616
18388
  if (!sessionID) return;
17617
18389
  const queue = this.sessionQueues.ensure(sessionID);
17618
18390
  queue.run(async () => {
17619
18391
  const binding = this.bindingRegistry.getByAibotSessionID(sessionID);
17620
- if (!binding || normalizeString30(binding.worker_id) !== normalizeString30(workerID)) {
18392
+ if (!binding || normalizeString32(binding.worker_id) !== normalizeString32(workerID)) {
17621
18393
  return;
17622
18394
  }
17623
18395
  if (binding.worker_status === "stopped" || binding.worker_status === "failed") {
17624
18396
  return;
17625
18397
  }
17626
- let signal = normalizeString30(exitSignal) || "wrapper_exited";
18398
+ let signal = normalizeString32(exitSignal) || "wrapper_exited";
17627
18399
  const hasAuthError = await this.workerProcessManager?.hasAuthLoginRequiredError?.(workerID);
17628
18400
  if (hasAuthError) {
17629
18401
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
@@ -17661,14 +18433,14 @@ var init_runtime = __esm({
17661
18433
  });
17662
18434
  }
17663
18435
  getWorkerPingProbeRecord(eventID) {
17664
- const normalizedEventID = normalizeString30(eventID);
18436
+ const normalizedEventID = normalizeString32(eventID);
17665
18437
  if (!normalizedEventID) {
17666
18438
  return null;
17667
18439
  }
17668
18440
  return this.workerPingProbeRecords.get(normalizedEventID) ?? null;
17669
18441
  }
17670
18442
  clearWorkerPingProbeRecord(eventID) {
17671
- const normalizedEventID = normalizeString30(eventID);
18443
+ const normalizedEventID = normalizeString32(eventID);
17672
18444
  if (!normalizedEventID) {
17673
18445
  return;
17674
18446
  }
@@ -17737,9 +18509,9 @@ var init_runtime = __esm({
17737
18509
  event_id: record.eventID,
17738
18510
  response_state: nextBinding?.worker_response_state,
17739
18511
  response_reason: nextBinding?.worker_response_reason,
17740
- terminal_status: normalizeString30(payload?.status),
17741
- terminal_code: normalizeString30(payload?.code),
17742
- probe_text: normalizeString30(payload?.text)
18512
+ terminal_status: normalizeString32(payload?.status),
18513
+ terminal_code: normalizeString32(payload?.code),
18514
+ probe_text: normalizeString32(payload?.text)
17743
18515
  }, level);
17744
18516
  this.scheduleWorkerPingProbeRecordCleanup(record.eventID);
17745
18517
  record.resolve?.(nextBinding);
@@ -17747,7 +18519,7 @@ var init_runtime = __esm({
17747
18519
  return nextBinding;
17748
18520
  }
17749
18521
  async ensureWorkerPingProbe(binding) {
17750
- const sessionID = normalizeString30(binding?.aibot_session_id);
18522
+ const sessionID = normalizeString32(binding?.aibot_session_id);
17751
18523
  if (!sessionID) {
17752
18524
  return binding;
17753
18525
  }
@@ -17769,7 +18541,7 @@ var init_runtime = __esm({
17769
18541
  }
17770
18542
  }
17771
18543
  async runWorkerPingProbe(binding) {
17772
- const sessionID = normalizeString30(binding?.aibot_session_id);
18544
+ const sessionID = normalizeString32(binding?.aibot_session_id);
17773
18545
  if (!sessionID || !hasReadyWorkerBridge(binding)) {
17774
18546
  return binding;
17775
18547
  }
@@ -17808,8 +18580,8 @@ var init_runtime = __esm({
17808
18580
  const record = {
17809
18581
  eventID: probePayload.event_id,
17810
18582
  sessionID,
17811
- workerID: normalizeString30(probingBinding?.worker_id),
17812
- claudeSessionID: normalizeString30(probingBinding?.claude_session_id),
18583
+ workerID: normalizeString32(probingBinding?.worker_id),
18584
+ claudeSessionID: normalizeString32(probingBinding?.claude_session_id),
17813
18585
  expectedReply: "pong",
17814
18586
  state: "probing",
17815
18587
  settled: false,
@@ -17849,7 +18621,7 @@ var init_runtime = __esm({
17849
18621
  worker_id: record.workerID,
17850
18622
  claude_session_id: record.claudeSessionID,
17851
18623
  event_id: record.eventID,
17852
- fallback_reason: normalizeString30(record.lastControlPingReason) || "control_ping_unavailable"
18624
+ fallback_reason: normalizeString32(record.lastControlPingReason) || "control_ping_unavailable"
17853
18625
  }, "debug");
17854
18626
  try {
17855
18627
  await client.deliverEvent(probePayload);
@@ -17895,10 +18667,10 @@ var init_runtime = __esm({
17895
18667
  }, "debug");
17896
18668
  return null;
17897
18669
  }
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);
18670
+ const expectedWorkerID = normalizeString32(record?.workerID);
18671
+ const expectedClaudeSessionID = normalizeString32(record?.claudeSessionID);
18672
+ const currentWorkerID = normalizeString32(currentBinding?.worker_id);
18673
+ const currentClaudeSessionID = normalizeString32(currentBinding?.claude_session_id);
17902
18674
  if (expectedWorkerID && currentWorkerID && expectedWorkerID !== currentWorkerID) {
17903
18675
  record.lastControlPingReason = "worker_id_mismatch";
17904
18676
  this.trace({
@@ -17940,26 +18712,26 @@ var init_runtime = __esm({
17940
18712
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(currentWorkerID);
17941
18713
  const identityHealth = this.inspectWorkerIdentityHealth(currentBinding, runtime, pingPayload);
17942
18714
  if (!identityHealth.ok) {
17943
- record.lastControlPingReason = normalizeString30(identityHealth.reason) || "identity_unhealthy";
18715
+ record.lastControlPingReason = normalizeString32(identityHealth.reason) || "identity_unhealthy";
17944
18716
  this.trace({
17945
18717
  stage: "worker_ping_probe_control_ping_unhealthy",
17946
18718
  ...traceContext,
17947
18719
  reason: record.lastControlPingReason,
17948
18720
  expected_pid: normalizeNonNegativeInt(identityHealth.expectedPid, 0),
17949
18721
  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),
18722
+ expected_worker_id: normalizeString32(identityHealth.expectedWorkerID),
18723
+ reported_worker_id: normalizeString32(identityHealth.reportedWorkerID),
18724
+ expected_session_id: normalizeString32(identityHealth.expectedSessionID),
18725
+ reported_session_id: normalizeString32(identityHealth.reportedSessionID),
18726
+ expected_claude_session_id: normalizeString32(identityHealth.expectedClaudeSessionID),
18727
+ reported_claude_session_id: normalizeString32(identityHealth.reportedClaudeSessionID),
17956
18728
  ...buildPingActivityTraceFields(pingPayload)
17957
18729
  });
17958
18730
  return null;
17959
18731
  }
17960
18732
  const mcpHealth = this.inspectMcpInteractionHealth(currentBinding, pingPayload);
17961
18733
  if (!mcpHealth.ok) {
17962
- record.lastControlPingReason = normalizeString30(mcpHealth.reason) || "mcp_unhealthy";
18734
+ record.lastControlPingReason = normalizeString32(mcpHealth.reason) || "mcp_unhealthy";
17963
18735
  this.trace({
17964
18736
  stage: "worker_ping_probe_control_ping_unhealthy",
17965
18737
  ...traceContext,
@@ -18020,7 +18792,7 @@ var init_runtime = __esm({
18020
18792
  if (record.settled) {
18021
18793
  return { handled: true, ack: { msg_id: `probe_${record.eventID}` } };
18022
18794
  }
18023
- const replyText = normalizeString30(payload?.text);
18795
+ const replyText = normalizeString32(payload?.text);
18024
18796
  if (isExpectedWorkerProbeReply(replyText, record.expectedReply)) {
18025
18797
  await this.updateWorkerPingProbeOutcome(record, {
18026
18798
  state: "healthy",
@@ -18044,8 +18816,8 @@ var init_runtime = __esm({
18044
18816
  return { handled: false };
18045
18817
  }
18046
18818
  if (!record.settled) {
18047
- const status = normalizeString30(payload?.status);
18048
- const code = normalizeString30(payload?.code);
18819
+ const status = normalizeString32(payload?.status);
18820
+ const code = normalizeString32(payload?.code);
18049
18821
  if (record.timeoutRecovering && status !== "responded" && code === "claude_result_timeout") {
18050
18822
  this.trace({
18051
18823
  stage: "worker_ping_probe_event_result_ignored_timeout_during_recovery",
@@ -18084,6 +18856,9 @@ var init_runtime = __esm({
18084
18856
  this.clearWorkerPingProbeRecord(eventID);
18085
18857
  }
18086
18858
  this.workerPingProbeInFlight.clear();
18859
+ for (const actionID of [...this.syntheticLocalActionWaiters.keys()]) {
18860
+ this.clearSyntheticLocalActionWaiter(actionID);
18861
+ }
18087
18862
  this.ensureWorkerInFlight.clear();
18088
18863
  this.resumeAuthRecoveryInFlight.clear();
18089
18864
  this.lastAuthRecoverySpawnAt.clear();
@@ -18120,14 +18895,19 @@ var init_runtime = __esm({
18120
18895
  event_id: event.event_id,
18121
18896
  status
18122
18897
  };
18123
- const normalizedCode = normalizeString30(code);
18124
- const normalizedMsg = normalizeString30(msg);
18898
+ const normalizedCode = normalizeString32(code);
18899
+ const normalizedMsg = normalizeString32(msg);
18125
18900
  if (normalizedCode) {
18126
18901
  payload.code = normalizedCode;
18127
18902
  }
18128
18903
  if (normalizedMsg) {
18129
18904
  payload.msg = normalizedMsg;
18130
18905
  }
18906
+ this.stopTypingForEvent({
18907
+ eventID: event.event_id,
18908
+ sessionID: event.session_id,
18909
+ msgID: event.msg_id
18910
+ });
18131
18911
  this.aibotClient.sendEventResult(payload);
18132
18912
  this.trace({
18133
18913
  stage: "event_result_sent",
@@ -18142,26 +18922,278 @@ var init_runtime = __esm({
18142
18922
  this.complete(event, result);
18143
18923
  return response;
18144
18924
  }
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(
18925
+ createSyntheticLocalActionWaiter(actionID, sessionID, timeoutMs) {
18926
+ const normalizedActionID = normalizeString32(actionID);
18927
+ const normalizedSessionID = normalizeString32(sessionID);
18928
+ const effectiveTimeoutMs = Math.max(1, normalizeNonNegativeInt(timeoutMs, 15e3));
18929
+ let resolvePromise = () => {
18930
+ };
18931
+ const promise = new Promise((resolve) => {
18932
+ resolvePromise = resolve;
18933
+ });
18934
+ const timer = setTimeout(() => {
18935
+ if (!this.syntheticLocalActionWaiters.has(normalizedActionID)) {
18936
+ return;
18937
+ }
18938
+ this.syntheticLocalActionWaiters.delete(normalizedActionID);
18939
+ resolvePromise({
18940
+ status: localActionResultStatuses.failed,
18941
+ result: void 0,
18942
+ errorCode: "local_action_result_timeout",
18943
+ errorMsg: "worker local action result timed out"
18944
+ });
18945
+ }, effectiveTimeoutMs);
18946
+ timer.unref?.();
18947
+ this.syntheticLocalActionWaiters.set(normalizedActionID, {
18948
+ sessionID: normalizedSessionID,
18949
+ resolve: resolvePromise,
18950
+ timer
18951
+ });
18952
+ return promise;
18953
+ }
18954
+ clearSyntheticLocalActionWaiter(actionID) {
18955
+ const normalizedActionID = normalizeString32(actionID);
18956
+ const pending = this.syntheticLocalActionWaiters.get(normalizedActionID);
18957
+ if (!pending) {
18958
+ return null;
18959
+ }
18960
+ clearTimeout(pending.timer);
18961
+ this.syntheticLocalActionWaiters.delete(normalizedActionID);
18962
+ return pending;
18963
+ }
18964
+ resolveSyntheticLocalActionWaiter(actionID, result) {
18965
+ const pending = this.clearSyntheticLocalActionWaiter(actionID);
18966
+ if (!pending) {
18967
+ return false;
18968
+ }
18969
+ pending.resolve(result);
18970
+ return true;
18971
+ }
18972
+ async observeWorkerLocalActionResult(payload) {
18973
+ const actionID = normalizeString32(payload?.action_id);
18974
+ if (!actionID) {
18975
+ return { handled: false };
18976
+ }
18977
+ const pending = this.syntheticLocalActionWaiters.get(actionID);
18978
+ if (!pending) {
18979
+ if (isSyntheticLocalActionID(actionID)) {
18980
+ this.trace({
18981
+ stage: "synthetic_local_action_result_ignored_late",
18982
+ action_id: actionID,
18983
+ session_id: this.resolveObservedSessionID(payload),
18984
+ worker_id: payload?.worker_id,
18985
+ claude_session_id: payload?.claude_session_id
18986
+ });
18987
+ return { handled: true };
18988
+ }
18989
+ return { handled: false };
18990
+ }
18991
+ const binding = this.bindingRegistry.getByAibotSessionID(pending.sessionID);
18992
+ if (binding && this.shouldIgnoreObservedWorker(binding, payload)) {
18993
+ this.trace({
18994
+ stage: "synthetic_local_action_result_ignored",
18995
+ action_id: actionID,
18996
+ session_id: pending.sessionID,
18997
+ worker_id: payload?.worker_id,
18998
+ claude_session_id: payload?.claude_session_id
18999
+ });
19000
+ return { handled: true };
19001
+ }
19002
+ this.trace({
19003
+ stage: "synthetic_local_action_result_observed",
19004
+ action_id: actionID,
19005
+ session_id: pending.sessionID,
19006
+ status: payload?.status,
19007
+ worker_id: payload?.worker_id
19008
+ });
19009
+ this.resolveSyntheticLocalActionWaiter(actionID, {
19010
+ status: normalizeString32(payload?.status) || localActionResultStatuses.failed,
19011
+ result: payload?.result,
19012
+ errorCode: normalizeString32(payload?.error_code),
19013
+ errorMsg: normalizeString32(payload?.error_msg)
19014
+ });
19015
+ return { handled: true };
19016
+ }
19017
+ async runSyntheticWorkerLocalAction(event, action) {
19018
+ const normalizedActionType = normalizeString32(action?.action_type);
19019
+ const params = action?.params && typeof action.params === "object" && !Array.isArray(action.params) ? action.params : {};
19020
+ const sessionID = normalizeString32(params.session_id) || normalizeString32(event?.session_id);
19021
+ if (!sessionID) {
19022
+ return {
19023
+ status: localActionResultStatuses.failed,
19024
+ result: void 0,
19025
+ errorCode: localActionErrorCodes.localActionRouteMissing,
19026
+ errorMsg: "local action session_id is required"
19027
+ };
19028
+ }
19029
+ const timeoutMs = Math.max(1, normalizeNonNegativeInt(action?.timeout_ms, 15e3));
19030
+ const actionID = `${syntheticLocalActionIDPrefix}${event?.event_id || randomUUID8()}:${randomUUID8()}`;
19031
+ const payload = {
19032
+ action_id: actionID,
19033
+ event_id: normalizeString32(event?.event_id),
19034
+ action_type: normalizedActionType,
19035
+ params: {
19036
+ ...params,
19037
+ session_id: sessionID
19038
+ },
19039
+ timeout_ms: timeoutMs
19040
+ };
19041
+ const waitPromise = this.createSyntheticLocalActionWaiter(actionID, sessionID, timeoutMs);
19042
+ try {
19043
+ const routedBinding = await this.deliverWithRecovery(
19044
+ sessionID,
19045
+ payload,
19046
+ this.deliverLocalActionToWorker
19047
+ );
19048
+ if (routedBinding && canDeliverToWorker(routedBinding)) {
19049
+ return waitPromise;
19050
+ }
19051
+ this.resolveSyntheticLocalActionWaiter(actionID, {
19052
+ status: localActionResultStatuses.failed,
19053
+ result: void 0,
19054
+ errorCode: "local_action_delivery_failed",
19055
+ errorMsg: "worker is not ready for local action delivery"
19056
+ });
19057
+ return waitPromise;
19058
+ } catch (error) {
19059
+ this.resolveSyntheticLocalActionWaiter(actionID, {
19060
+ status: localActionResultStatuses.failed,
19061
+ result: void 0,
19062
+ errorCode: "local_action_delivery_failed",
19063
+ errorMsg: normalizeString32(error?.message || error) || "worker local action delivery failed"
19064
+ });
19065
+ return waitPromise;
19066
+ }
19067
+ }
19068
+ async handleSyntheticSessionControlEvent(event, action) {
19069
+ const params = action?.params && typeof action.params === "object" && !Array.isArray(action.params) ? action.params : {};
19070
+ const sessionControlResult = await this.sessionControlActionHandler.handleLocalAction({
19071
+ action_type: localActionTypes.sessionControl,
19072
+ params: {
19073
+ ...params,
19074
+ session_id: event.session_id
19075
+ }
19076
+ });
19077
+ if (!sessionControlResult?.handled) {
19078
+ return false;
19079
+ }
19080
+ const response = sessionControlResult.response ?? {};
19081
+ const result = response.result ?? {};
19082
+ if (response.status === localActionResultStatuses.ok && normalizeString32(result.domain) === resultDomains.sessionControl) {
19083
+ await this.respond(event, buildSessionControlSuccessNotice(result), {}, {
19084
+ status: "responded"
19085
+ });
19086
+ return true;
19087
+ }
19088
+ const errorCode = normalizeString32(response.errorCode);
19089
+ const errorMsg = normalizeString32(response.errorMsg);
19090
+ if (errorCode === sessionControlErrorCodes.cwdRequired || errorCode === sessionControlErrorCodes.invalidCwd || errorCode === sessionControlErrorCodes.bindingMissing) {
19091
+ await this.respond(
19092
+ event,
19093
+ buildSessionControlOpenCardNotice({
19094
+ summaryText: buildSessionControlCardSummary(errorCode, errorMsg),
19095
+ initialCwd: normalizeString32(params.cwd)
19096
+ }),
19097
+ {},
19098
+ {
19099
+ status: "responded",
19100
+ code: errorCode,
19101
+ msg: errorMsg
19102
+ }
19103
+ );
19104
+ return true;
19105
+ }
19106
+ await this.respond(
19107
+ event,
19108
+ buildSessionControlFailureNotice({
19109
+ errorCode,
19110
+ errorMsg
19111
+ }),
19112
+ {},
19113
+ {
19114
+ status: "responded",
19115
+ code: errorCode,
19116
+ msg: errorMsg
19117
+ }
19118
+ );
19119
+ return true;
19120
+ }
19121
+ async handleSyntheticInteractionReplyEvent(event, action) {
19122
+ const actionResult = await this.runSyntheticWorkerLocalAction(event, action);
19123
+ if (normalizeString32(actionResult?.status) === localActionResultStatuses.ok) {
19124
+ this.complete(event, {
19125
+ status: "responded"
19126
+ });
19127
+ return true;
19128
+ }
19129
+ const errorCode = normalizeString32(actionResult?.errorCode);
19130
+ const errorMsg = normalizeString32(actionResult?.errorMsg);
19131
+ await this.respond(
18153
19132
  event,
18154
- fallbackText,
19133
+ buildInteractionReplyFailureNotice({
19134
+ errorCode,
19135
+ errorMsg
19136
+ }),
19137
+ {},
18155
19138
  {
18156
- ...replySource ? { reply_source: replySource } : {},
18157
- biz_card: buildOpenWorkspaceCard({
18158
- summaryText,
18159
- detailText,
18160
- initialCwd
18161
- })
18162
- },
18163
- result
19139
+ status: "responded",
19140
+ code: errorCode,
19141
+ msg: errorMsg
19142
+ }
18164
19143
  );
19144
+ return true;
19145
+ }
19146
+ async handleInteractionActionEvent(event) {
19147
+ const parsed = parseInboundInteractionAction(event.content);
19148
+ if (!parsed.matched) {
19149
+ return false;
19150
+ }
19151
+ this.trace({
19152
+ stage: "interaction_action_received",
19153
+ event_id: event.event_id,
19154
+ session_id: event.session_id,
19155
+ source: parsed.source,
19156
+ action_type: parsed.action?.action_type,
19157
+ ok: parsed.ok === true
19158
+ });
19159
+ if (!parsed.ok) {
19160
+ if (parsed.errorCode === sessionControlErrorCodes.cwdRequired) {
19161
+ await this.respond(
19162
+ event,
19163
+ buildSessionControlOpenCardNotice({
19164
+ summaryText: buildSessionControlCardSummary(parsed.errorCode, parsed.errorMsg)
19165
+ }),
19166
+ {},
19167
+ {
19168
+ status: "responded",
19169
+ code: parsed.errorCode,
19170
+ msg: parsed.errorMsg
19171
+ }
19172
+ );
19173
+ return true;
19174
+ }
19175
+ await this.respond(
19176
+ event,
19177
+ buildInteractionReplyFailureNotice({
19178
+ errorCode: parsed.errorCode,
19179
+ errorMsg: parsed.errorMsg
19180
+ }),
19181
+ {},
19182
+ {
19183
+ status: "responded",
19184
+ code: parsed.errorCode,
19185
+ msg: parsed.errorMsg
19186
+ }
19187
+ );
19188
+ return true;
19189
+ }
19190
+ if (normalizeString32(parsed.action?.action_type) === localActionTypes.sessionControl) {
19191
+ return this.handleSyntheticSessionControlEvent(event, parsed.action);
19192
+ }
19193
+ if (normalizeString32(parsed.action?.action_type) === localActionTypes.interactionReply) {
19194
+ return this.handleSyntheticInteractionReplyEvent(event, parsed.action);
19195
+ }
19196
+ return false;
18165
19197
  }
18166
19198
  ack(event) {
18167
19199
  this.aibotClient.ackEvent(event.event_id, {
@@ -18176,9 +19208,36 @@ var init_runtime = __esm({
18176
19208
  msg_id: event.msg_id
18177
19209
  });
18178
19210
  }
19211
+ stopTypingForEvent({
19212
+ eventID,
19213
+ sessionID = "",
19214
+ msgID = ""
19215
+ } = {}) {
19216
+ const normalizedEventID = normalizeString32(eventID);
19217
+ const normalizedSessionID = normalizeString32(sessionID) || this.messageDeliveryStore.getRememberedSessionID(normalizedEventID);
19218
+ if (!normalizedEventID || !normalizedSessionID || typeof this.aibotClient?.setSessionComposing !== "function") {
19219
+ return;
19220
+ }
19221
+ try {
19222
+ this.aibotClient.setSessionComposing({
19223
+ sessionID: normalizedSessionID,
19224
+ kind: "typing",
19225
+ active: false,
19226
+ refMsgID: normalizeString32(msgID),
19227
+ refEventID: normalizedEventID
19228
+ });
19229
+ } catch (error) {
19230
+ this.trace({
19231
+ stage: "event_typing_stop_failed",
19232
+ event_id: normalizedEventID,
19233
+ session_id: normalizedSessionID,
19234
+ error: error instanceof Error ? error.message : String(error)
19235
+ }, "error");
19236
+ }
19237
+ }
18179
19238
  async shouldResumeClaudeSession(binding) {
18180
- const claudeSessionID = normalizeString30(binding?.claude_session_id);
18181
- const cwd = normalizeString30(binding?.cwd);
19239
+ const claudeSessionID = normalizeString32(binding?.claude_session_id);
19240
+ const cwd = normalizeString32(binding?.cwd);
18182
19241
  if (!claudeSessionID || !cwd) {
18183
19242
  return false;
18184
19243
  }
@@ -18198,19 +19257,19 @@ var init_runtime = __esm({
18198
19257
  if (this.authFailureCooldownMs <= 0) {
18199
19258
  return null;
18200
19259
  }
18201
- const normalizedStatus = normalizeString30(binding?.worker_status);
19260
+ const normalizedStatus = normalizeString32(binding?.worker_status);
18202
19261
  if (normalizedStatus !== "stopped" && normalizedStatus !== "failed") {
18203
19262
  return null;
18204
19263
  }
18205
- const workerID = normalizeString30(binding?.worker_id);
19264
+ const workerID = normalizeString32(binding?.worker_id);
18206
19265
  if (!workerID) {
18207
19266
  return null;
18208
19267
  }
18209
19268
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
18210
- if (normalizeString30(runtime?.status) !== "stopped") {
19269
+ if (normalizeString32(runtime?.status) !== "stopped") {
18211
19270
  return null;
18212
19271
  }
18213
- if (normalizeString30(runtime?.exit_signal) !== "auth_login_required") {
19272
+ if (normalizeString32(runtime?.exit_signal) !== "auth_login_required") {
18214
19273
  return null;
18215
19274
  }
18216
19275
  const runtimeStoppedAt = Number(runtime?.stopped_at ?? 0);
@@ -18233,7 +19292,7 @@ var init_runtime = __esm({
18233
19292
  };
18234
19293
  }
18235
19294
  async ensureWorker(binding, { ignoreAuthCooldown = false } = {}) {
18236
- const sessionID = normalizeString30(binding?.aibot_session_id);
19295
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18237
19296
  if (!sessionID) {
18238
19297
  return null;
18239
19298
  }
@@ -18314,7 +19373,7 @@ var init_runtime = __esm({
18314
19373
  };
18315
19374
  }
18316
19375
  const currentReadyFailed = hasReadyWorkerBridge(current) && normalizeWorkerResponseState(current?.worker_response_state) === "failed";
18317
- const workerID2 = normalizeString30(binding.worker_id);
19376
+ const workerID2 = normalizeString32(binding.worker_id);
18318
19377
  if (!currentReadyFailed && workerID2) {
18319
19378
  const existingRuntime = this.workerProcessManager?.getWorkerRuntime?.(workerID2);
18320
19379
  const existingPid = Number(existingRuntime?.pid ?? 0);
@@ -18393,13 +19452,13 @@ var init_runtime = __esm({
18393
19452
  if (current && current.worker_status === "ready" && current.worker_control_url && current.worker_control_token) {
18394
19453
  return current;
18395
19454
  }
18396
- await sleep2(intervalMs);
19455
+ await sleep3(intervalMs);
18397
19456
  }
18398
19457
  return this.bindingRegistry.getByAibotSessionID(aibotSessionID);
18399
19458
  }
18400
19459
  async resolveWorkerLaunchFailure(binding) {
18401
- const workerID = normalizeString30(binding?.worker_id);
18402
- const workerStatus = normalizeString30(binding?.worker_status);
19460
+ const workerID = normalizeString32(binding?.worker_id);
19461
+ const workerStatus = normalizeString32(binding?.worker_status);
18403
19462
  if (!workerID || !["starting", "connected"].includes(workerStatus)) {
18404
19463
  return "";
18405
19464
  }
@@ -18433,27 +19492,27 @@ var init_runtime = __esm({
18433
19492
  if (current2.worker_status === "stopped" || current2.worker_status === "failed") {
18434
19493
  return current2;
18435
19494
  }
18436
- await sleep2(intervalMs);
19495
+ await sleep3(intervalMs);
18437
19496
  }
18438
19497
  const current = this.bindingRegistry.getByAibotSessionID(aibotSessionID);
18439
19498
  const launchFailure = await this.resolveWorkerLaunchFailure(current);
18440
19499
  if (launchFailure) {
18441
19500
  return withWorkerLaunchFailure(current, launchFailure);
18442
19501
  }
18443
- if (["starting", "connected"].includes(normalizeString30(current?.worker_status))) {
19502
+ if (["starting", "connected"].includes(normalizeString32(current?.worker_status))) {
18444
19503
  return withWorkerLaunchFailure(current, "startup_wait_timeout");
18445
19504
  }
18446
19505
  return current;
18447
19506
  }
18448
19507
  clearWorkerControlProbeFailure(workerID) {
18449
- const normalizedWorkerID = normalizeString30(workerID);
19508
+ const normalizedWorkerID = normalizeString32(workerID);
18450
19509
  if (!normalizedWorkerID) {
18451
19510
  return;
18452
19511
  }
18453
19512
  this.workerControlProbeFailures.delete(normalizedWorkerID);
18454
19513
  }
18455
19514
  markWorkerControlProbeFailure(workerID, error, extraFields = {}) {
18456
- const normalizedWorkerID = normalizeString30(workerID);
19515
+ const normalizedWorkerID = normalizeString32(workerID);
18457
19516
  if (!normalizedWorkerID) {
18458
19517
  return 0;
18459
19518
  }
@@ -18492,22 +19551,22 @@ var init_runtime = __esm({
18492
19551
  });
18493
19552
  }
18494
19553
  resolveObservedSessionID(payload = {}) {
18495
- const explicitSessionID = normalizeString30(payload?.session_id);
19554
+ const explicitSessionID = normalizeString32(payload?.session_id);
18496
19555
  if (explicitSessionID) {
18497
19556
  return explicitSessionID;
18498
19557
  }
18499
- return normalizeString30(this.messageDeliveryStore.getRememberedSessionID(payload?.event_id));
19558
+ return normalizeString32(this.messageDeliveryStore.getRememberedSessionID(payload?.event_id));
18500
19559
  }
18501
19560
  shouldIgnoreObservedWorker(binding, payload = {}) {
18502
19561
  if (!binding) {
18503
19562
  return false;
18504
19563
  }
18505
- const observedWorkerID = normalizeString30(payload?.worker_id);
18506
- if (observedWorkerID && normalizeString30(binding?.worker_id) && observedWorkerID !== normalizeString30(binding.worker_id)) {
19564
+ const observedWorkerID = normalizeString32(payload?.worker_id);
19565
+ if (observedWorkerID && normalizeString32(binding?.worker_id) && observedWorkerID !== normalizeString32(binding.worker_id)) {
18507
19566
  return true;
18508
19567
  }
18509
- const observedClaudeSessionID = normalizeString30(payload?.claude_session_id);
18510
- if (observedClaudeSessionID && normalizeString30(binding?.claude_session_id) && observedClaudeSessionID !== normalizeString30(binding.claude_session_id)) {
19568
+ const observedClaudeSessionID = normalizeString32(payload?.claude_session_id);
19569
+ if (observedClaudeSessionID && normalizeString32(binding?.claude_session_id) && observedClaudeSessionID !== normalizeString32(binding.claude_session_id)) {
18511
19570
  return true;
18512
19571
  }
18513
19572
  return false;
@@ -18517,10 +19576,10 @@ var init_runtime = __esm({
18517
19576
  stage,
18518
19577
  event_id: payload?.event_id,
18519
19578
  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)
19579
+ worker_id: normalizeString32(payload?.worker_id),
19580
+ expected_worker_id: normalizeString32(binding?.worker_id),
19581
+ claude_session_id: normalizeString32(payload?.claude_session_id),
19582
+ expected_claude_session_id: normalizeString32(binding?.claude_session_id)
18524
19583
  }, "error");
18525
19584
  }
18526
19585
  async recordWorkerReplyObserved(payload, { kind = "text" } = {}) {
@@ -18583,19 +19642,19 @@ var init_runtime = __esm({
18583
19642
  response_state: nextBinding?.worker_response_state,
18584
19643
  response_reason: nextBinding?.worker_response_reason,
18585
19644
  event_id: payload?.event_id,
18586
- terminal_status: normalizeString30(payload?.status),
18587
- terminal_code: normalizeString30(payload?.code)
19645
+ terminal_status: normalizeString32(payload?.status),
19646
+ terminal_code: normalizeString32(payload?.code)
18588
19647
  }, classification.state === "failed" ? "error" : "info");
18589
19648
  return nextBinding;
18590
19649
  }
18591
19650
  async recordWorkerHookSignalsObserved(binding, pingPayload) {
18592
- const sessionID = normalizeString30(binding?.aibot_session_id);
19651
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18593
19652
  if (!sessionID) {
18594
19653
  return binding;
18595
19654
  }
18596
19655
  let nextBinding = binding;
18597
19656
  let lastEventAt = Number(binding?.worker_last_hook_event_at ?? 0);
18598
- let lastEventID = normalizeString30(binding?.worker_last_hook_event_id);
19657
+ let lastEventID = normalizeString32(binding?.worker_last_hook_event_id);
18599
19658
  for (const event of listHookSignalRecords(pingPayload)) {
18600
19659
  const isNewer = event.event_at > lastEventAt || event.event_at === lastEventAt && event.event_id !== lastEventID;
18601
19660
  if (!isNewer) {
@@ -18625,16 +19684,16 @@ var init_runtime = __esm({
18625
19684
  if (this.workerControlProbeFailureThreshold <= 0) {
18626
19685
  return { ok: true };
18627
19686
  }
18628
- if (normalizeString30(binding?.worker_status) !== "ready") {
19687
+ if (normalizeString32(binding?.worker_status) !== "ready") {
18629
19688
  return { ok: true };
18630
19689
  }
18631
- const workerID = normalizeString30(binding?.worker_id);
19690
+ const workerID = normalizeString32(binding?.worker_id);
18632
19691
  if (!workerID) {
18633
19692
  return { ok: true };
18634
19693
  }
18635
19694
  const probeTraceFields = {
18636
- session_id: normalizeString30(binding?.aibot_session_id),
18637
- claude_session_id: normalizeString30(binding?.claude_session_id),
19695
+ session_id: normalizeString32(binding?.aibot_session_id),
19696
+ claude_session_id: normalizeString32(binding?.claude_session_id),
18638
19697
  expected_pid: resolveExpectedWorkerPid(binding, runtime)
18639
19698
  };
18640
19699
  let client = null;
@@ -18673,12 +19732,12 @@ var init_runtime = __esm({
18673
19732
  reason: identityHealth.reason,
18674
19733
  expected_pid: normalizeNonNegativeInt(identityHealth.expectedPid, 0),
18675
19734
  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),
19735
+ expected_worker_id: normalizeString32(identityHealth.expectedWorkerID),
19736
+ reported_worker_id: normalizeString32(identityHealth.reportedWorkerID),
19737
+ expected_session_id: normalizeString32(identityHealth.expectedSessionID),
19738
+ reported_session_id: normalizeString32(identityHealth.reportedSessionID),
19739
+ expected_claude_session_id: normalizeString32(identityHealth.expectedClaudeSessionID),
19740
+ reported_claude_session_id: normalizeString32(identityHealth.reportedClaudeSessionID),
18682
19741
  ...buildPingActivityTraceFields(pingPayload)
18683
19742
  });
18684
19743
  const failures = this.markWorkerControlProbeFailure(
@@ -18750,6 +19809,13 @@ var init_runtime = __esm({
18750
19809
  }
18751
19810
  return client.deliverRevoke(rawPayload);
18752
19811
  }
19812
+ async deliverLocalActionToWorker(binding, rawPayload) {
19813
+ const client = this.workerControlClientFactory(binding);
19814
+ if (!client?.isConfigured?.()) {
19815
+ throw new Error("worker control client is not configured");
19816
+ }
19817
+ return client.deliverLocalAction(rawPayload);
19818
+ }
18753
19819
  async trackPendingEvent(rawPayload) {
18754
19820
  return this.pendingEventOrchestrator.trackPendingEvent(rawPayload);
18755
19821
  }
@@ -18766,22 +19832,22 @@ var init_runtime = __esm({
18766
19832
  return this.pendingEventOrchestrator.markPendingEventInterrupted(eventID);
18767
19833
  }
18768
19834
  async clearPendingEvent(eventID) {
18769
- const normalizedEventID = normalizeString30(eventID);
19835
+ const normalizedEventID = normalizeString32(eventID);
18770
19836
  if (normalizedEventID) {
18771
19837
  this.pendingEventWorkerLogCursors.delete(normalizedEventID);
18772
19838
  }
18773
19839
  return this.pendingEventOrchestrator.clearPendingEvent(eventID);
18774
19840
  }
18775
19841
  getPendingEventWorkerLogCursor(eventID) {
18776
- const normalizedEventID = normalizeString30(eventID);
19842
+ const normalizedEventID = normalizeString32(eventID);
18777
19843
  if (!normalizedEventID) {
18778
19844
  return null;
18779
19845
  }
18780
19846
  return this.pendingEventWorkerLogCursors.get(normalizedEventID) ?? null;
18781
19847
  }
18782
19848
  async recordPendingEventWorkerLogCursor(eventID, workerID) {
18783
- const normalizedEventID = normalizeString30(eventID);
18784
- const normalizedWorkerID = normalizeString30(workerID);
19849
+ const normalizedEventID = normalizeString32(eventID);
19850
+ const normalizedWorkerID = normalizeString32(workerID);
18785
19851
  if (!normalizedEventID || !normalizedWorkerID) {
18786
19852
  return null;
18787
19853
  }
@@ -18822,19 +19888,19 @@ var init_runtime = __esm({
18822
19888
  return this.pendingEventOrchestrator.touchPendingEventComposing(eventID);
18823
19889
  }
18824
19890
  async handleWorkerSessionComposing(payload = {}) {
18825
- const eventID = normalizeString30(payload.ref_event_id);
19891
+ const eventID = normalizeString32(payload.ref_event_id);
18826
19892
  if (!eventID) {
18827
19893
  return null;
18828
19894
  }
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);
19895
+ const workerID = normalizeString32(payload.worker_id);
19896
+ const workerSessionID = normalizeString32(payload.session_id || payload.aibot_session_id);
19897
+ const claudeSessionID = normalizeString32(payload.claude_session_id);
18832
19898
  const reportedPid = Number(payload.pid ?? 0);
18833
19899
  const record = this.getPendingEvent(eventID);
18834
19900
  if (!record) {
18835
19901
  return null;
18836
19902
  }
18837
- const deliveryState = normalizeString30(record.delivery_state);
19903
+ const deliveryState = normalizeString32(record.delivery_state);
18838
19904
  if (deliveryState !== "dispatching" && deliveryState !== "delivered") {
18839
19905
  this.trace({
18840
19906
  stage: "pending_event_activity_rejected",
@@ -18845,7 +19911,7 @@ var init_runtime = __esm({
18845
19911
  }, "error");
18846
19912
  return null;
18847
19913
  }
18848
- const sessionID = normalizeString30(record.sessionID);
19914
+ const sessionID = normalizeString32(record.sessionID);
18849
19915
  if (workerSessionID && workerSessionID !== sessionID) {
18850
19916
  this.trace({
18851
19917
  stage: "pending_event_activity_rejected",
@@ -18866,7 +19932,7 @@ var init_runtime = __esm({
18866
19932
  }, "error");
18867
19933
  return null;
18868
19934
  }
18869
- const expectedWorkerID = normalizeString30(binding.worker_id);
19935
+ const expectedWorkerID = normalizeString32(binding.worker_id);
18870
19936
  if (!workerID || !expectedWorkerID || workerID !== expectedWorkerID) {
18871
19937
  this.trace({
18872
19938
  stage: "pending_event_activity_rejected",
@@ -18892,7 +19958,7 @@ var init_runtime = __esm({
18892
19958
  return null;
18893
19959
  }
18894
19960
  }
18895
- const dispatchedWorkerID = normalizeString30(record.last_worker_id);
19961
+ const dispatchedWorkerID = normalizeString32(record.last_worker_id);
18896
19962
  if (dispatchedWorkerID && workerID !== dispatchedWorkerID) {
18897
19963
  this.trace({
18898
19964
  stage: "pending_event_activity_rejected",
@@ -18904,7 +19970,7 @@ var init_runtime = __esm({
18904
19970
  }, "error");
18905
19971
  return null;
18906
19972
  }
18907
- const expectedClaudeSessionID = normalizeString30(binding.claude_session_id);
19973
+ const expectedClaudeSessionID = normalizeString32(binding.claude_session_id);
18908
19974
  if (!claudeSessionID || !expectedClaudeSessionID || claudeSessionID !== expectedClaudeSessionID) {
18909
19975
  this.trace({
18910
19976
  stage: "pending_event_activity_rejected",
@@ -18941,12 +20007,12 @@ var init_runtime = __esm({
18941
20007
  async flushStalePendingEvents() {
18942
20008
  const bindings = this.bindingRegistry?.listBindings?.() ?? [];
18943
20009
  for (const binding of bindings) {
18944
- const sessionID = normalizeString30(binding?.aibot_session_id);
20010
+ const sessionID = normalizeString32(binding?.aibot_session_id);
18945
20011
  if (!sessionID) continue;
18946
20012
  if (!canDeliverToWorker(binding)) continue;
18947
20013
  const pendingEvents = this.listPendingEventsForSession(sessionID);
18948
20014
  const hasPending = pendingEvents.some(
18949
- (r) => normalizeString30(r.delivery_state) === "pending"
20015
+ (r) => normalizeString32(r.delivery_state) === "pending"
18950
20016
  );
18951
20017
  if (!hasPending) continue;
18952
20018
  const queue = this.sessionQueues.ensure(sessionID);
@@ -18966,7 +20032,6 @@ var init_runtime = __esm({
18966
20032
  async failPendingEvent(record, {
18967
20033
  notifyText = true,
18968
20034
  noticeText = buildInterruptedEventNotice(),
18969
- replySource = "daemon_worker_interrupted",
18970
20035
  resultCode = "worker_interrupted",
18971
20036
  resultMessage = "worker interrupted while processing event"
18972
20037
  } = {}) {
@@ -18983,10 +20048,7 @@ var init_runtime = __esm({
18983
20048
  eventID: record.eventID,
18984
20049
  sessionID: record.sessionID,
18985
20050
  text: noticeText,
18986
- quotedMessageID: record.msgID,
18987
- extra: {
18988
- reply_source: replySource
18989
- }
20051
+ quotedMessageID: record.msgID
18990
20052
  });
18991
20053
  } catch {
18992
20054
  }
@@ -19009,7 +20071,7 @@ var init_runtime = __esm({
19009
20071
  }, "error");
19010
20072
  }
19011
20073
  async resolveWorkerFailureEventOptions(workerID) {
19012
- const normalizedWorkerID = normalizeString30(workerID);
20074
+ const normalizedWorkerID = normalizeString32(workerID);
19013
20075
  if (!normalizedWorkerID) {
19014
20076
  return null;
19015
20077
  }
@@ -19027,23 +20089,22 @@ var init_runtime = __esm({
19027
20089
  }
19028
20090
  return {
19029
20091
  noticeText: buildAuthLoginRequiredEventNotice(),
19030
- replySource: "daemon_worker_auth_login_required",
19031
20092
  resultCode: "claude_auth_login_required",
19032
20093
  resultMessage: "claude authentication expired; run claude auth login"
19033
20094
  };
19034
20095
  }
19035
20096
  resolveWorkerIDForEventResult(payload) {
19036
- const explicitWorkerID = normalizeString30(payload?.worker_id);
20097
+ const explicitWorkerID = normalizeString32(payload?.worker_id);
19037
20098
  if (explicitWorkerID) {
19038
20099
  return explicitWorkerID;
19039
20100
  }
19040
20101
  const sessionID = this.resolveObservedSessionID(payload);
19041
20102
  const binding = sessionID ? this.bindingRegistry.getByAibotSessionID(sessionID) : null;
19042
- return normalizeString30(binding?.worker_id);
20103
+ return normalizeString32(binding?.worker_id);
19043
20104
  }
19044
20105
  async resolveWorkerEventResultFailureOptions(payload) {
19045
- const status = normalizeString30(payload?.status);
19046
- const code = normalizeString30(payload?.code);
20106
+ const status = normalizeString32(payload?.status);
20107
+ const code = normalizeString32(payload?.code);
19047
20108
  if (status !== "failed" || code !== "claude_result_timeout") {
19048
20109
  return null;
19049
20110
  }
@@ -19051,7 +20112,7 @@ var init_runtime = __esm({
19051
20112
  if (!workerID) {
19052
20113
  return null;
19053
20114
  }
19054
- const eventID = normalizeString30(payload?.event_id);
20115
+ const eventID = normalizeString32(payload?.event_id);
19055
20116
  const logCursor = this.getPendingEventWorkerLogCursor(eventID);
19056
20117
  const hasExtraUsageLimitPrompt = await this.workerProcessManager?.hasExtraUsageLimitPrompt?.(
19057
20118
  workerID,
@@ -19079,7 +20140,7 @@ var init_runtime = __esm({
19079
20140
  if (!failureOptions?.noticeText) {
19080
20141
  return null;
19081
20142
  }
19082
- const eventID = normalizeString30(payload?.event_id);
20143
+ const eventID = normalizeString32(payload?.event_id);
19083
20144
  const record = this.getPendingEvent(eventID);
19084
20145
  if (!record?.eventID || !record?.sessionID) {
19085
20146
  return null;
@@ -19089,10 +20150,7 @@ var init_runtime = __esm({
19089
20150
  eventID: record.eventID,
19090
20151
  sessionID: record.sessionID,
19091
20152
  text: failureOptions.noticeText,
19092
- quotedMessageID: record.msgID,
19093
- extra: {
19094
- reply_source: failureOptions.replySource
19095
- }
20153
+ quotedMessageID: record.msgID
19096
20154
  });
19097
20155
  } catch {
19098
20156
  return null;
@@ -19103,23 +20161,29 @@ var init_runtime = __esm({
19103
20161
  const nextPayload = this.buildForwardedWorkerEventResult(payload, failureOptions);
19104
20162
  await this.recordWorkerEventResultObserved(nextPayload);
19105
20163
  await this.notifyWorkerEventResultFailure(nextPayload, failureOptions);
20164
+ const record = this.getPendingEvent(nextPayload?.event_id);
20165
+ this.stopTypingForEvent({
20166
+ eventID: nextPayload?.event_id,
20167
+ sessionID: nextPayload?.session_id || record?.sessionID,
20168
+ msgID: record?.msgID
20169
+ });
19106
20170
  this.aibotClient.sendEventResult(nextPayload);
19107
20171
  await this.handleEventCompleted(nextPayload?.event_id);
19108
20172
  return nextPayload;
19109
20173
  }
19110
20174
  async requeuePendingEventsForWorker(sessionID, workerID) {
19111
- const normalizedSessionID = normalizeString30(sessionID);
19112
- const normalizedWorkerID = normalizeString30(workerID);
20175
+ const normalizedSessionID = normalizeString32(sessionID);
20176
+ const normalizedWorkerID = normalizeString32(workerID);
19113
20177
  if (!normalizedSessionID || !normalizedWorkerID) {
19114
20178
  return 0;
19115
20179
  }
19116
20180
  let requeuedCount = 0;
19117
20181
  const requeuedEventIDs = [];
19118
20182
  for (const record of this.listPendingEventsForSession(normalizedSessionID)) {
19119
- if (normalizeString30(record.last_worker_id) !== normalizedWorkerID) {
20183
+ if (normalizeString32(record.last_worker_id) !== normalizedWorkerID) {
19120
20184
  continue;
19121
20185
  }
19122
- const deliveryState = normalizeString30(record.delivery_state);
20186
+ const deliveryState = normalizeString32(record.delivery_state);
19123
20187
  if (!["dispatching", "delivered", "interrupted"].includes(deliveryState)) {
19124
20188
  continue;
19125
20189
  }
@@ -19142,8 +20206,8 @@ var init_runtime = __esm({
19142
20206
  return requeuedCount;
19143
20207
  }
19144
20208
  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);
20209
+ const sessionID = normalizeString32(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
20210
+ const workerID = normalizeString32(previousBinding?.worker_id || nextBinding?.worker_id);
19147
20211
  if (!sessionID || !workerID) {
19148
20212
  return false;
19149
20213
  }
@@ -19195,7 +20259,7 @@ var init_runtime = __esm({
19195
20259
  return false;
19196
20260
  }
19197
20261
  const fallbackBinding = await this.rotateClaudeSession(latestBinding);
19198
- const nextWorkerID = normalizeString30(nextBinding?.worker_id) || workerID || randomUUID8();
20262
+ const nextWorkerID = normalizeString32(nextBinding?.worker_id) || workerID || randomUUID8();
19199
20263
  await this.bindingRegistry.markWorkerStarting(sessionID, {
19200
20264
  workerID: nextWorkerID,
19201
20265
  updatedAt: Date.now(),
@@ -19232,7 +20296,7 @@ var init_runtime = __esm({
19232
20296
  async reconcileWorkerProcesses() {
19233
20297
  const bindings = this.bindingRegistry?.listBindings?.() ?? [];
19234
20298
  for (const binding of bindings) {
19235
- const sessionID = normalizeString30(binding?.aibot_session_id);
20299
+ const sessionID = normalizeString32(binding?.aibot_session_id);
19236
20300
  if (!sessionID) continue;
19237
20301
  const queue = this.sessionQueues.ensure(sessionID);
19238
20302
  queue.run(() => this.reconcileWorkerProcess(binding)).catch((err) => {
@@ -19241,11 +20305,11 @@ var init_runtime = __esm({
19241
20305
  }
19242
20306
  }
19243
20307
  async reconcileWorkerProcess(binding) {
19244
- const sessionID = normalizeString30(binding?.aibot_session_id);
20308
+ const sessionID = normalizeString32(binding?.aibot_session_id);
19245
20309
  if (!sessionID) return false;
19246
20310
  const freshBinding = this.bindingRegistry?.getByAibotSessionID?.(sessionID) ?? binding;
19247
- const workerID = normalizeString30(freshBinding?.worker_id);
19248
- const workerStatus = normalizeString30(freshBinding?.worker_status);
20311
+ const workerID = normalizeString32(freshBinding?.worker_id);
20312
+ const workerStatus = normalizeString32(freshBinding?.worker_status);
19249
20313
  if (!workerID || !["starting", "connected", "ready"].includes(workerStatus)) {
19250
20314
  return false;
19251
20315
  }
@@ -19297,7 +20361,7 @@ var init_runtime = __esm({
19297
20361
  return true;
19298
20362
  }
19299
20363
  const previousBinding = this.bindingRegistry.getByAibotSessionID(sessionID) ?? binding;
19300
- if (normalizeString30(previousBinding?.worker_id) !== workerID || ["stopped", "failed"].includes(normalizeString30(previousBinding?.worker_status))) {
20364
+ if (normalizeString32(previousBinding?.worker_id) !== workerID || ["stopped", "failed"].includes(normalizeString32(previousBinding?.worker_status))) {
19301
20365
  return false;
19302
20366
  }
19303
20367
  const runtime = this.workerProcessManager?.getWorkerRuntime?.(workerID);
@@ -19306,7 +20370,7 @@ var init_runtime = __esm({
19306
20370
  }
19307
20371
  const pid = resolveExpectedWorkerPid(previousBinding, runtime);
19308
20372
  if (Number.isFinite(pid) && pid > 0 && !this.isProcessRunning(pid)) {
19309
- const exitSignal = normalizeString30(runtime.exit_signal) || "worker_exited";
20373
+ const exitSignal = normalizeString32(runtime.exit_signal) || "worker_exited";
19310
20374
  this.workerProcessManager?.markWorkerRuntimeStopped?.(workerID, {
19311
20375
  exitCode: Number(runtime.exit_code ?? 0),
19312
20376
  exitSignal
@@ -19350,7 +20414,7 @@ var init_runtime = __esm({
19350
20414
  }, "error");
19351
20415
  await this.bindingRegistry.markWorkerResponseFailed(sessionID, {
19352
20416
  observedAt: Date.now(),
19353
- reason: normalizeString30(probe.reason) || "worker_control_unreachable",
20417
+ reason: normalizeString32(probe.reason) || "worker_control_unreachable",
19354
20418
  failureCode: "worker_control_unreachable"
19355
20419
  });
19356
20420
  const nextBinding = await this.bindingRegistry.markWorkerStopped(sessionID, {
@@ -19421,7 +20485,7 @@ var init_runtime = __esm({
19421
20485
  * handling.
19422
20486
  */
19423
20487
  async handleWorkerStatusUpdateQueued(previousBinding, nextBinding) {
19424
- const sessionID = normalizeString30(
20488
+ const sessionID = normalizeString32(
19425
20489
  nextBinding?.aibot_session_id || previousBinding?.aibot_session_id
19426
20490
  );
19427
20491
  if (!sessionID) {
@@ -19433,8 +20497,8 @@ var init_runtime = __esm({
19433
20497
  );
19434
20498
  }
19435
20499
  async handleWorkerStatusUpdate(previousBinding, nextBinding) {
19436
- const sessionID = normalizeString30(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
19437
- const nextStatus = normalizeString30(nextBinding?.worker_status);
20500
+ const sessionID = normalizeString32(nextBinding?.aibot_session_id || previousBinding?.aibot_session_id);
20501
+ const nextStatus = normalizeString32(nextBinding?.worker_status);
19438
20502
  if (!sessionID || !nextStatus) {
19439
20503
  return;
19440
20504
  }
@@ -19446,8 +20510,8 @@ var init_runtime = __esm({
19446
20510
  claude_session_id: nextBinding?.claude_session_id || previousBinding?.claude_session_id,
19447
20511
  status: nextStatus
19448
20512
  });
19449
- const previousWorkerID = normalizeString30(previousBinding?.worker_id);
19450
- const nextWorkerID = normalizeString30(nextBinding?.worker_id);
20513
+ const previousWorkerID = normalizeString32(previousBinding?.worker_id);
20514
+ const nextWorkerID = normalizeString32(nextBinding?.worker_id);
19451
20515
  if (nextStatus === "ready" || nextStatus === "connected") {
19452
20516
  if (nextWorkerID) {
19453
20517
  this.clearWorkerControlProbeFailure(nextWorkerID);
@@ -19499,11 +20563,11 @@ var init_runtime = __esm({
19499
20563
  }, "error");
19500
20564
  }
19501
20565
  for (const record of this.listPendingEventsForSession(sessionID)) {
19502
- if (previousWorkerID && normalizeString30(record.last_worker_id) !== previousWorkerID) {
19503
- if (normalizeString30(record.last_worker_id)) {
20566
+ if (previousWorkerID && normalizeString32(record.last_worker_id) !== previousWorkerID) {
20567
+ if (normalizeString32(record.last_worker_id)) {
19504
20568
  continue;
19505
20569
  }
19506
- if (!["pending", "dispatching", "interrupted"].includes(normalizeString30(record.delivery_state))) {
20570
+ if (!["pending", "dispatching", "interrupted"].includes(normalizeString32(record.delivery_state))) {
19507
20571
  continue;
19508
20572
  }
19509
20573
  }
@@ -19513,7 +20577,7 @@ var init_runtime = __esm({
19513
20577
  }
19514
20578
  async handleEventCompleted(eventID) {
19515
20579
  const record = this.getPendingEvent(eventID);
19516
- const sessionID = normalizeString30(record?.sessionID || this.messageDeliveryStore.getRememberedSessionID(eventID));
20580
+ const sessionID = normalizeString32(record?.sessionID || this.messageDeliveryStore.getRememberedSessionID(eventID));
19517
20581
  await this.clearPendingEvent(eventID);
19518
20582
  this.trace({
19519
20583
  stage: "event_completed",
@@ -19581,7 +20645,6 @@ var init_runtime = __esm({
19581
20645
  const currentRecord = this.getPendingEvent(record.eventID) ?? record;
19582
20646
  await this.failPendingEvent(currentRecord, {
19583
20647
  notifyText: false,
19584
- replySource: "daemon_recover_failed",
19585
20648
  resultCode: "worker_recover_failed",
19586
20649
  resultMessage: message
19587
20650
  });
@@ -19658,7 +20721,7 @@ var init_runtime = __esm({
19658
20721
  });
19659
20722
  return null;
19660
20723
  }
19661
- if (currentRecord && ["dispatching", "delivered"].includes(normalizeString30(currentRecord.delivery_state)) && normalizeString30(currentRecord.last_worker_id) === normalizeString30(readyBinding?.worker_id)) {
20724
+ if (currentRecord && ["dispatching", "delivered"].includes(normalizeString32(currentRecord.delivery_state)) && normalizeString32(currentRecord.last_worker_id) === normalizeString32(readyBinding?.worker_id)) {
19662
20725
  this.trace({
19663
20726
  stage: "event_dispatch_skipped",
19664
20727
  event_id: rawPayload?.event_id,
@@ -19710,7 +20773,7 @@ var init_runtime = __esm({
19710
20773
  } else {
19711
20774
  readyBinding = this.bindingRegistry.getByAibotSessionID(aibotSessionID) ?? readyBinding;
19712
20775
  }
19713
- if (readyBinding?.worker_launch_failure === "resume_session_missing" && normalizeString30(binding.claude_session_id)) {
20776
+ if (readyBinding?.worker_launch_failure === "resume_session_missing" && normalizeString32(binding.claude_session_id)) {
19714
20777
  this.trace({
19715
20778
  stage: "worker_resume_missing_recovering",
19716
20779
  session_id: binding.aibot_session_id,
@@ -19764,9 +20827,6 @@ var init_runtime = __esm({
19764
20827
  }
19765
20828
  return readyBinding ?? binding;
19766
20829
  }
19767
- async handleControlCommand(event, parsed) {
19768
- return this.controlCommandHandler.handleControlCommand(event, parsed);
19769
- }
19770
20830
  /**
19771
20831
  * Queue-aware wrapper: routes handleEvent through the per-session
19772
20832
  * serial queue to prevent races with reconcile and worker status updates.
@@ -19776,12 +20836,13 @@ var init_runtime = __esm({
19776
20836
  if (!event.event_id || !event.session_id || !event.msg_id) {
19777
20837
  return;
19778
20838
  }
20839
+ this.ack(event);
19779
20840
  const queue = this.sessionQueues.ensure(event.session_id);
19780
- queue.run(() => this.handleEvent(rawPayload)).catch((err) => {
20841
+ queue.run(() => this.handleEvent(rawPayload, { alreadyAcked: true })).catch((err) => {
19781
20842
  this.trace({ stage: "handle_event_error", session_id: event.session_id, event_id: event.event_id, error: String(err?.message ?? err) }, "error");
19782
20843
  });
19783
20844
  }
19784
- async handleEvent(rawPayload) {
20845
+ async handleEvent(rawPayload, { alreadyAcked = false } = {}) {
19785
20846
  const event = normalizeInboundEventPayload(rawPayload);
19786
20847
  if (!event.event_id || !event.session_id || !event.msg_id) {
19787
20848
  return;
@@ -19793,11 +20854,21 @@ var init_runtime = __esm({
19793
20854
  msg_id: event.msg_id,
19794
20855
  sender_id: event.sender_id
19795
20856
  });
19796
- this.ack(event);
20857
+ if (!alreadyAcked) {
20858
+ this.ack(event);
20859
+ }
20860
+ if (isRecordOnlyMirror(event)) {
20861
+ this.trace({
20862
+ stage: "event_mirrored_record_only",
20863
+ event_id: event.event_id,
20864
+ session_id: event.session_id,
20865
+ msg_id: event.msg_id,
20866
+ sender_id: event.sender_id
20867
+ });
20868
+ return;
20869
+ }
19797
20870
  try {
19798
- const parsed = parseControlCommand(event.content);
19799
- if (parsed.matched) {
19800
- await this.handleControlCommand(event, parsed);
20871
+ if (await this.handleInteractionActionEvent(event)) {
19801
20872
  return;
19802
20873
  }
19803
20874
  const binding = this.bindingRegistry.getByAibotSessionID(event.session_id);
@@ -19807,9 +20878,10 @@ var init_runtime = __esm({
19807
20878
  event_id: event.event_id,
19808
20879
  session_id: event.session_id
19809
20880
  }, "error");
19810
- await this.respondWithOpenWorkspaceCard(event, {
19811
- ...buildMissingBindingCardOptions(),
19812
- replySource: "daemon_route_missing"
20881
+ await this.respond(event, buildBindingMissingEventNotice(), {}, {
20882
+ status: "responded",
20883
+ code: sessionControlErrorCodes.bindingMissing,
20884
+ msg: "session binding is required before event delivery"
19813
20885
  });
19814
20886
  return;
19815
20887
  }
@@ -19827,9 +20899,7 @@ var init_runtime = __esm({
19827
20899
  await this.respond(
19828
20900
  event,
19829
20901
  buildAuthLoginRequiredEventNotice(),
19830
- {
19831
- reply_source: "daemon_worker_auth_login_required"
19832
- },
20902
+ {},
19833
20903
  {
19834
20904
  status: "failed",
19835
20905
  code: "claude_auth_login_required",
@@ -19881,7 +20951,7 @@ var init_runtime = __esm({
19881
20951
  }
19882
20952
  const readyBinding = routedBinding ?? this.bindingRegistry.getByAibotSessionID(binding.aibot_session_id) ?? binding;
19883
20953
  if (!readyBinding.worker_control_url || !readyBinding.worker_control_token) {
19884
- const launchFailure = normalizeString30(readyBinding?.worker_launch_failure);
20954
+ const launchFailure = normalizeString32(readyBinding?.worker_launch_failure);
19885
20955
  this.trace({
19886
20956
  stage: "event_worker_not_ready",
19887
20957
  event_id: event.event_id,
@@ -19891,7 +20961,7 @@ var init_runtime = __esm({
19891
20961
  worker_launch_failure: launchFailure
19892
20962
  }, "error");
19893
20963
  if (pending && (launchFailure === "startup_mcp_server_failed" || launchFailure === "startup_wait_timeout")) {
19894
- const workerID = normalizeString30(readyBinding?.worker_id);
20964
+ const workerID = normalizeString32(readyBinding?.worker_id);
19895
20965
  if (workerID) {
19896
20966
  try {
19897
20967
  await this.workerProcessManager?.stopWorker?.(workerID);
@@ -19917,7 +20987,6 @@ var init_runtime = __esm({
19917
20987
  await this.markPendingEventInterrupted(pending.eventID);
19918
20988
  await this.failPendingEvent(pending, {
19919
20989
  noticeText: buildWorkerStartupFailedNotice(),
19920
- replySource: "daemon_worker_startup_failed",
19921
20990
  resultCode: launchFailure === "startup_mcp_server_failed" ? "claude_startup_mcp_failed" : "claude_startup_timeout",
19922
20991
  resultMessage: launchFailure === "startup_mcp_server_failed" ? "claude worker startup failed: mcp server not ready" : "claude worker startup timed out"
19923
20992
  });
@@ -19933,9 +21002,7 @@ var init_runtime = __esm({
19933
21002
  error: message
19934
21003
  }, "error");
19935
21004
  try {
19936
- await this.respond(event, `\u5904\u7406\u5931\u8D25\uFF1A${message}`, {
19937
- reply_source: "daemon_event_error"
19938
- }, {
21005
+ await this.respond(event, `\u5904\u7406\u5931\u8D25\uFF1A${message}`, {}, {
19939
21006
  status: "failed",
19940
21007
  code: "daemon_event_handle_failed",
19941
21008
  msg: message
@@ -19950,7 +21017,7 @@ var init_runtime = __esm({
19950
21017
  }
19951
21018
  }
19952
21019
  async handleStopEvent(rawPayload) {
19953
- const eventID = normalizeString30(rawPayload?.event_id);
21020
+ const eventID = normalizeString32(rawPayload?.event_id);
19954
21021
  if (!eventID) {
19955
21022
  return;
19956
21023
  }
@@ -19960,7 +21027,7 @@ var init_runtime = __esm({
19960
21027
  session_id: rawPayload?.session_id,
19961
21028
  stop_id: rawPayload?.stop_id
19962
21029
  });
19963
- const sessionID = normalizeString30(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
21030
+ const sessionID = normalizeString32(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
19964
21031
  if (!sessionID) {
19965
21032
  this.trace({
19966
21033
  stage: "stop_route_missing",
@@ -19978,12 +21045,12 @@ var init_runtime = __esm({
19978
21045
  });
19979
21046
  }
19980
21047
  async handleRevokeEvent(rawPayload) {
19981
- const eventID = normalizeString30(rawPayload?.event_id);
21048
+ const eventID = normalizeString32(rawPayload?.event_id);
19982
21049
  if (!eventID) {
19983
21050
  return;
19984
21051
  }
19985
21052
  const receivedAt = Date.now();
19986
- const resolvedSessionID = normalizeString30(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
21053
+ const resolvedSessionID = normalizeString32(rawPayload?.session_id) || this.messageDeliveryStore.getRememberedSessionID(eventID);
19987
21054
  this.aibotClient.ackEvent(eventID, {
19988
21055
  sessionID: resolvedSessionID,
19989
21056
  msgID: rawPayload?.msg_id,
@@ -20028,12 +21095,80 @@ var init_runtime = __esm({
20028
21095
  msg_id: rawPayload?.msg_id
20029
21096
  });
20030
21097
  }
21098
+ async handleLocalAction(rawPayload) {
21099
+ const action = normalizeLocalActionPayload(rawPayload);
21100
+ if (!action.action_id) {
21101
+ this.trace({
21102
+ stage: "local_action_invalid",
21103
+ reason: "missing_action_id",
21104
+ action_type: action.action_type
21105
+ }, "error");
21106
+ return;
21107
+ }
21108
+ const sessionControlResult = await this.sessionControlActionHandler.handleLocalAction(action);
21109
+ if (sessionControlResult?.handled) {
21110
+ await this.aibotClient.sendLocalActionResult({
21111
+ actionID: action.action_id,
21112
+ status: sessionControlResult.response?.status,
21113
+ result: sessionControlResult.response?.result,
21114
+ errorCode: sessionControlResult.response?.errorCode,
21115
+ errorMsg: sessionControlResult.response?.errorMsg,
21116
+ timeoutMs: action.timeout_ms
21117
+ });
21118
+ return;
21119
+ }
21120
+ const sessionID = normalizeString32(action.params?.session_id) || this.messageDeliveryStore.getRememberedSessionID(action.event_id);
21121
+ if (!sessionID) {
21122
+ this.trace({
21123
+ stage: "local_action_route_missing",
21124
+ action_id: action.action_id,
21125
+ action_type: action.action_type,
21126
+ event_id: action.event_id
21127
+ }, "error");
21128
+ await this.aibotClient.sendLocalActionResult({
21129
+ actionID: action.action_id,
21130
+ status: localActionResultStatuses.failed,
21131
+ errorCode: localActionErrorCodes.localActionRouteMissing,
21132
+ errorMsg: "local action session_id is required",
21133
+ timeoutMs: action.timeout_ms
21134
+ });
21135
+ return;
21136
+ }
21137
+ const routedBinding = await this.deliverWithRecovery(
21138
+ sessionID,
21139
+ action,
21140
+ this.deliverLocalActionToWorker
21141
+ );
21142
+ if (routedBinding && canDeliverToWorker(routedBinding)) {
21143
+ this.trace({
21144
+ stage: "local_action_forwarded",
21145
+ action_id: action.action_id,
21146
+ action_type: action.action_type,
21147
+ session_id: sessionID,
21148
+ worker_id: routedBinding?.worker_id
21149
+ });
21150
+ return;
21151
+ }
21152
+ this.trace({
21153
+ stage: "local_action_delivery_failed",
21154
+ action_id: action.action_id,
21155
+ action_type: action.action_type,
21156
+ session_id: sessionID
21157
+ }, "error");
21158
+ await this.aibotClient.sendLocalActionResult({
21159
+ actionID: action.action_id,
21160
+ status: "failed",
21161
+ errorCode: "local_action_delivery_failed",
21162
+ errorMsg: "worker is not ready for local action delivery",
21163
+ timeoutMs: action.timeout_ms
21164
+ });
21165
+ }
20031
21166
  };
20032
21167
  }
20033
21168
  });
20034
21169
 
20035
21170
  // server/session-activity-dispatcher.js
20036
- function normalizeString31(value) {
21171
+ function normalizeString33(value) {
20037
21172
  return String(value ?? "").trim();
20038
21173
  }
20039
21174
  function buildSessionActivityDispatchKey({
@@ -20042,10 +21177,10 @@ function buildSessionActivityDispatchKey({
20042
21177
  refEventID = "",
20043
21178
  refMsgID = ""
20044
21179
  } = {}) {
20045
- const normalizedSessionID = normalizeString31(sessionID);
20046
- const normalizedKind = normalizeString31(kind) || "composing";
20047
- const normalizedRefEventID = normalizeString31(refEventID);
20048
- const normalizedRefMsgID = normalizeString31(refMsgID);
21180
+ const normalizedSessionID = normalizeString33(sessionID);
21181
+ const normalizedKind = normalizeString33(kind) || "composing";
21182
+ const normalizedRefEventID = normalizeString33(refEventID);
21183
+ const normalizedRefMsgID = normalizeString33(refMsgID);
20049
21184
  if (normalizedRefEventID) {
20050
21185
  return `event:${normalizedRefEventID}`;
20051
21186
  }
@@ -20082,19 +21217,19 @@ var init_session_activity_dispatcher = __esm({
20082
21217
 
20083
21218
  // server/daemon/session-log-writer.js
20084
21219
  import { appendFile as appendFile2, mkdir as mkdir11 } from "node:fs/promises";
20085
- import path23 from "node:path";
20086
- function normalizeString32(value) {
21220
+ import path24 from "node:path";
21221
+ function normalizeString34(value) {
20087
21222
  return String(value ?? "").trim();
20088
21223
  }
20089
21224
  function normalizeSessionID(value) {
20090
- return normalizeString32(value).replace(/[^a-zA-Z0-9._-]+/g, "-");
21225
+ return normalizeString34(value).replace(/[^a-zA-Z0-9._-]+/g, "-");
20091
21226
  }
20092
21227
  function resolveSessionID(fields = {}) {
20093
- const explicitSessionID = normalizeString32(fields.session_id);
21228
+ const explicitSessionID = normalizeString34(fields.session_id);
20094
21229
  if (explicitSessionID) {
20095
21230
  return explicitSessionID;
20096
21231
  }
20097
- return normalizeString32(fields.aibot_session_id);
21232
+ return normalizeString34(fields.aibot_session_id);
20098
21233
  }
20099
21234
  var SessionLogWriter;
20100
21235
  var init_session_log_writer = __esm({
@@ -20109,7 +21244,7 @@ var init_session_log_writer = __esm({
20109
21244
  appendFileImpl = appendFile2
20110
21245
  } = {}) {
20111
21246
  this.env = env;
20112
- this.logFileName = normalizeString32(logFileName) || "daemon-session.log";
21247
+ this.logFileName = normalizeString34(logFileName) || "daemon-session.log";
20113
21248
  this.mkdirImpl = typeof mkdirImpl === "function" ? mkdirImpl : mkdir11;
20114
21249
  this.appendFileImpl = typeof appendFileImpl === "function" ? appendFileImpl : appendFile2;
20115
21250
  this.writeQueues = /* @__PURE__ */ new Map();
@@ -20119,7 +21254,7 @@ var init_session_log_writer = __esm({
20119
21254
  if (!normalizedSessionID) {
20120
21255
  return "";
20121
21256
  }
20122
- return path23.join(resolveWorkerLogsDir(normalizedSessionID, this.env), this.logFileName);
21257
+ return path24.join(resolveWorkerLogsDir(normalizedSessionID, this.env), this.logFileName);
20123
21258
  }
20124
21259
  enqueueWrite(aibotSessionID, task) {
20125
21260
  const normalizedSessionID = normalizeSessionID(aibotSessionID);
@@ -20143,7 +21278,7 @@ var init_session_log_writer = __esm({
20143
21278
  return false;
20144
21279
  }
20145
21280
  const line = formatTraceLine({
20146
- level: normalizeString32(level) || "info",
21281
+ level: normalizeString34(level) || "info",
20147
21282
  ...fields
20148
21283
  });
20149
21284
  return this.enqueueWrite(sessionID, async () => {
@@ -20151,7 +21286,7 @@ var init_session_log_writer = __esm({
20151
21286
  if (!logPath) {
20152
21287
  return false;
20153
21288
  }
20154
- await this.mkdirImpl(path23.dirname(logPath), { recursive: true });
21289
+ await this.mkdirImpl(path24.dirname(logPath), { recursive: true });
20155
21290
  await this.appendFileImpl(logPath, `${line}
20156
21291
  `, "utf8");
20157
21292
  return true;
@@ -20171,7 +21306,7 @@ __export(main_exports, {
20171
21306
  shouldIgnoreWorkerStatusUpdate: () => shouldIgnoreWorkerStatusUpdate,
20172
21307
  shouldNotifyWorkerReady: () => shouldNotifyWorkerReady
20173
21308
  });
20174
- import process14 from "node:process";
21309
+ import process15 from "node:process";
20175
21310
  function usage() {
20176
21311
  return `\u7528\u6CD5:
20177
21312
  grix-claude daemon [options]
@@ -20190,7 +21325,7 @@ function usage() {
20190
21325
  `;
20191
21326
  }
20192
21327
  function print(message) {
20193
- process14.stdout.write(`${message}
21328
+ process15.stdout.write(`${message}
20194
21329
  `);
20195
21330
  }
20196
21331
  function parseArgs(argv) {
@@ -20216,7 +21351,7 @@ function readOption(argv, name) {
20216
21351
  }
20217
21352
  return value;
20218
21353
  }
20219
- function normalizeString33(value) {
21354
+ function normalizeString35(value) {
20220
21355
  return String(value ?? "").trim();
20221
21356
  }
20222
21357
  function normalizePid3(value) {
@@ -20239,13 +21374,13 @@ function shouldIgnoreWorkerStatusUpdate(previousBinding, payload) {
20239
21374
  if (!previousBinding) {
20240
21375
  return false;
20241
21376
  }
20242
- const expectedWorkerID = normalizeString33(previousBinding.worker_id);
20243
- const incomingWorkerID = normalizeString33(payload?.worker_id);
21377
+ const expectedWorkerID = normalizeString35(previousBinding.worker_id);
21378
+ const incomingWorkerID = normalizeString35(payload?.worker_id);
20244
21379
  if (expectedWorkerID && incomingWorkerID && expectedWorkerID !== incomingWorkerID) {
20245
21380
  return true;
20246
21381
  }
20247
- const expectedClaudeSessionID = normalizeString33(previousBinding.claude_session_id);
20248
- const incomingClaudeSessionID = normalizeString33(payload?.claude_session_id);
21382
+ const expectedClaudeSessionID = normalizeString35(previousBinding.claude_session_id);
21383
+ const incomingClaudeSessionID = normalizeString35(payload?.claude_session_id);
20249
21384
  if (expectedClaudeSessionID && incomingClaudeSessionID && expectedClaudeSessionID !== incomingClaudeSessionID) {
20250
21385
  return true;
20251
21386
  }
@@ -20260,13 +21395,10 @@ async function notifyWorkerReady(aibotClient, binding) {
20260
21395
  }
20261
21396
  return aibotClient.sendText({
20262
21397
  sessionID: binding.aibot_session_id,
20263
- text: buildWorkerReadyNoticeText(binding),
20264
- extra: {
20265
- reply_source: "daemon_worker_ready"
20266
- }
21398
+ text: buildWorkerReadyNoticeText(binding)
20267
21399
  });
20268
21400
  }
20269
- async function run(argv = [], env = process14.env) {
21401
+ async function run(argv = [], env = process15.env) {
20270
21402
  const options = parseArgs(argv);
20271
21403
  if (options.help) {
20272
21404
  print(usage());
@@ -20514,6 +21646,25 @@ async function run(argv = [], env = process14.env) {
20514
21646
  refEventID: payload.ref_event_id
20515
21647
  });
20516
21648
  return { ok: true };
21649
+ },
21650
+ onAgentInvoke: async (payload) => aibotClient.sendAgentInvoke({
21651
+ invokeID: payload?.invoke_id,
21652
+ action: payload?.action,
21653
+ params: payload?.params,
21654
+ timeoutMs: payload?.timeout_ms
21655
+ }),
21656
+ onLocalActionResult: async (payload) => {
21657
+ const syntheticResult = await runtime?.observeWorkerLocalActionResult?.(payload);
21658
+ if (syntheticResult?.handled) {
21659
+ return { ok: true };
21660
+ }
21661
+ return aibotClient.sendLocalActionResult({
21662
+ actionID: payload?.action_id,
21663
+ status: payload?.status,
21664
+ result: payload?.result,
21665
+ errorCode: payload?.error_code,
21666
+ errorMsg: payload?.error_msg
21667
+ });
20517
21668
  }
20518
21669
  });
20519
21670
  try {
@@ -20538,6 +21689,9 @@ async function run(argv = [], env = process14.env) {
20538
21689
  aibotClient.onEventRevoke = async (payload) => {
20539
21690
  await runtime.handleRevokeEvent(payload);
20540
21691
  };
21692
+ aibotClient.onLocalAction = async (payload) => {
21693
+ await runtime.handleLocalAction(payload);
21694
+ };
20541
21695
  print("grix-claude daemon \u5DF2\u542F\u52A8\u3002");
20542
21696
  print(`\u6570\u636E\u76EE\u5F55: ${dataDir}`);
20543
21697
  print(`Bridge: ${bridgeServer.getURL()}`);
@@ -20577,15 +21731,15 @@ async function run(argv = [], env = process14.env) {
20577
21731
  }
20578
21732
  await new Promise((resolve) => {
20579
21733
  const stop = async () => {
20580
- process14.off("SIGINT", stop);
20581
- process14.off("SIGTERM", stop);
21734
+ process15.off("SIGINT", stop);
21735
+ process15.off("SIGTERM", stop);
20582
21736
  await processState.markStopping("signal");
20583
21737
  await aibotClient.stop();
20584
21738
  await bridgeServer.stop();
20585
21739
  resolve();
20586
21740
  };
20587
- process14.once("SIGINT", stop);
20588
- process14.once("SIGTERM", stop);
21741
+ process15.once("SIGINT", stop);
21742
+ process15.once("SIGTERM", stop);
20589
21743
  });
20590
21744
  await processState.release({
20591
21745
  exitCode: 0,
@@ -20597,8 +21751,8 @@ async function run(argv = [], env = process14.env) {
20597
21751
  throw error;
20598
21752
  }
20599
21753
  }
20600
- async function main(argv = process14.argv.slice(2), env = process14.env) {
20601
- process14.exitCode = await run(argv, env);
21754
+ async function main(argv = process15.argv.slice(2), env = process15.env) {
21755
+ process15.exitCode = await run(argv, env);
20602
21756
  }
20603
21757
  var workerReadySettleDelayMs;
20604
21758
  var init_main2 = __esm({
@@ -20627,7 +21781,7 @@ __export(main_exports2, {
20627
21781
  main: () => main2,
20628
21782
  run: () => run2
20629
21783
  });
20630
- import process15 from "node:process";
21784
+ import process16 from "node:process";
20631
21785
  function usage2() {
20632
21786
  return `\u7528\u6CD5:
20633
21787
  grix-claude worker
@@ -20637,7 +21791,7 @@ function usage2() {
20637
21791
  `;
20638
21792
  }
20639
21793
  function print2(message) {
20640
- process15.stdout.write(`${message}
21794
+ process16.stdout.write(`${message}
20641
21795
  `);
20642
21796
  }
20643
21797
  async function run2(argv = []) {
@@ -20648,8 +21802,8 @@ async function run2(argv = []) {
20648
21802
  print2("\u4E0D\u8981\u624B\u52A8\u8FD0\u884C worker\u3002Claude \u4F1A\u8BDD\u4F1A\u5728 daemon \u8C03\u5EA6\u4E0B\u81EA\u52A8\u52A0\u8F7D\u5B83\u3002");
20649
21803
  return 1;
20650
21804
  }
20651
- async function main2(argv = process15.argv.slice(2)) {
20652
- process15.exitCode = await run2(argv);
21805
+ async function main2(argv = process16.argv.slice(2)) {
21806
+ process16.exitCode = await run2(argv);
20653
21807
  }
20654
21808
  var init_main3 = __esm({
20655
21809
  "server/worker/main.js"() {
@@ -20660,7 +21814,7 @@ var init_main3 = __esm({
20660
21814
  init_config();
20661
21815
  init_config_store();
20662
21816
  init_daemon_paths();
20663
- import process16 from "node:process";
21817
+ import process17 from "node:process";
20664
21818
 
20665
21819
  // server/service/service-manager.js
20666
21820
  init_config();
@@ -21263,7 +22417,7 @@ var ServiceManager = class {
21263
22417
  minUpdatedAt = 0,
21264
22418
  timeoutMs = 5e3
21265
22419
  } = {}) {
21266
- const { setTimeout: sleep3 } = await import("node:timers/promises");
22420
+ const { setTimeout: sleep4 } = await import("node:timers/promises");
21267
22421
  const start = this.now();
21268
22422
  let lastState = null;
21269
22423
  while (this.now() - start < timeoutMs) {
@@ -21273,7 +22427,7 @@ var ServiceManager = class {
21273
22427
  if (state.running && state.pid && restarted) {
21274
22428
  return state;
21275
22429
  }
21276
- await sleep3(100);
22430
+ await sleep4(100);
21277
22431
  }
21278
22432
  throw new Error(
21279
22433
  `daemon start timeout (${timeoutMs}ms), state=${lastState?.state || "unknown"}, pid=${Number(lastState?.pid ?? 0)}`
@@ -21502,11 +22656,11 @@ function parseArgs2(argv) {
21502
22656
  return options;
21503
22657
  }
21504
22658
  function print3(message) {
21505
- process16.stdout.write(`${message}
22659
+ process17.stdout.write(`${message}
21506
22660
  `);
21507
22661
  }
21508
22662
  function printError(message) {
21509
- process16.stderr.write(`${message}
22663
+ process17.stderr.write(`${message}
21510
22664
  `);
21511
22665
  }
21512
22666
  function shellQuoteForDisplay(value) {
@@ -21545,10 +22699,10 @@ function formatRunningCommand(argv) {
21545
22699
  return command.map((item) => shellQuoteForDisplay(item)).join(" ");
21546
22700
  }
21547
22701
  function formatRuntimeEntryCommand(argv) {
21548
- const command = [process16.execPath, resolvePackageBinPath(), ...redactSensitiveArgs(argv)];
22702
+ const command = [process17.execPath, resolvePackageBinPath(), ...redactSensitiveArgs(argv)];
21549
22703
  return command.map((item) => shellQuoteForDisplay(item)).join(" ");
21550
22704
  }
21551
- function createServiceManager(env = process16.env) {
22705
+ function createServiceManager(env = process17.env) {
21552
22706
  return new ServiceManager({ env });
21553
22707
  }
21554
22708
  function buildRuntimeEnv(options, env) {
@@ -21566,7 +22720,7 @@ function buildDaemonStatus(configStore) {
21566
22720
  configPath: configStore.filePath
21567
22721
  };
21568
22722
  }
21569
- async function prepareDaemonConfig(options, env = process16.env, { persistResolvedConfig = false } = {}) {
22723
+ async function prepareDaemonConfig(options, env = process17.env, { persistResolvedConfig = false } = {}) {
21570
22724
  const runtimeEnv = buildRuntimeEnv(options, env);
21571
22725
  const configStore = new ConfigStore(resolveDaemonConfigPath(runtimeEnv), {
21572
22726
  env: runtimeEnv
@@ -21591,7 +22745,7 @@ async function prepareDaemonConfig(options, env = process16.env, { persistResolv
21591
22745
  ...buildDaemonStatus(configStore)
21592
22746
  };
21593
22747
  }
21594
- async function runDefault(argv, env = process16.env) {
22748
+ async function runDefault(argv, env = process17.env) {
21595
22749
  const options = parseArgs2(argv);
21596
22750
  if (options.help) {
21597
22751
  print3(usage3());
@@ -21705,7 +22859,7 @@ async function runSubcommand(name, argv, env, deps = {}) {
21705
22859
  }
21706
22860
  throw new Error(`\u672A\u77E5\u5B50\u547D\u4EE4: ${name}`);
21707
22861
  }
21708
- async function run3(argv, env = process16.env, deps = {}) {
22862
+ async function run3(argv, env = process17.env, deps = {}) {
21709
22863
  const [first = ""] = argv;
21710
22864
  if ([
21711
22865
  "daemon",
@@ -21721,17 +22875,17 @@ async function run3(argv, env = process16.env, deps = {}) {
21721
22875
  }
21722
22876
  return runDefault(argv, env);
21723
22877
  }
21724
- async function main3(argv = process16.argv.slice(2), env = process16.env) {
22878
+ async function main3(argv = process17.argv.slice(2), env = process17.env) {
21725
22879
  try {
21726
22880
  print3(`\u8FD0\u884C\u547D\u4EE4: ${formatRunningCommand(argv)}`);
21727
22881
  print3(`\u5B9E\u9645\u5165\u53E3: ${formatRuntimeEntryCommand(argv)}`);
21728
22882
  const exitCode = await run3(argv, env);
21729
- process16.exitCode = exitCode;
22883
+ process17.exitCode = exitCode;
21730
22884
  } catch (error) {
21731
22885
  printError(error instanceof Error ? error.message : String(error));
21732
22886
  printError("");
21733
22887
  printError(usage3());
21734
- process16.exitCode = 1;
22888
+ process17.exitCode = 1;
21735
22889
  }
21736
22890
  }
21737
22891