@clawos-dev/clawd 0.2.594 → 0.2.595

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/cli.cjs CHANGED
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
450
450
  init_errors();
451
451
  init_en();
452
452
  makeIssue = (params) => {
453
- const { data, path: path104, errorMaps, issueData } = params;
454
- const fullPath = [...path104, ...issueData.path || []];
453
+ const { data, path: path106, errorMaps, issueData } = params;
454
+ const fullPath = [...path106, ...issueData.path || []];
455
455
  const fullIssue = {
456
456
  ...issueData,
457
457
  path: fullPath
@@ -762,11 +762,11 @@ var init_types = __esm({
762
762
  init_parseUtil();
763
763
  init_util();
764
764
  ParseInputLazyPath = class {
765
- constructor(parent, value, path104, key) {
765
+ constructor(parent, value, path106, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path104;
769
+ this._path = path106;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -8144,8 +8144,8 @@ var init_schemas = __esm({
8144
8144
  tui: external_exports.boolean(),
8145
8145
  observe: external_exports.boolean(),
8146
8146
  fileSharing: external_exports.boolean(),
8147
- // fork:session:fork 走 forkSession(claude jsonl 专用,派生新 jsonl)。codex 无 claude jsonl
8148
- // → fork 不可用。UI 据此 gate assistant 消息上的 fork 按钮(codex 一轮多条消息会刷出一堆按钮且点了报错)。
8147
+ // fork:Claude 派生 transcript JSONL;本机 Codex 按已完成 turn 调原生 thread/fork。
8148
+ // UI 只在有有效 fork 锚点的回复气泡上显示入口。
8149
8149
  fork: external_exports.boolean()
8150
8150
  });
8151
8151
  CapabilitiesResponseSchema = external_exports.object({
@@ -8489,7 +8489,9 @@ var init_schemas = __esm({
8489
8489
  kind: external_exports.literal("turn_end"),
8490
8490
  // 本轮耗时(ms)。SDK=result.duration_ms;TUI=turn_duration.durationMs;缺失时 reducer 按 turnStartedAt 兜底
8491
8491
  durationMs: external_exports.number().int().nonnegative().optional(),
8492
- reason: external_exports.enum(TURN_END_REASONS).optional()
8492
+ reason: external_exports.enum(TURN_END_REASONS).optional(),
8493
+ /** Codex 完成轮次的原生 id;用于在该轮末条回复上显示 Fork / Quick Ask。 */
8494
+ turnId: external_exports.string().min(1).optional()
8493
8495
  }),
8494
8496
  // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
8495
8497
  // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。
@@ -8707,7 +8709,12 @@ var init_schemas = __esm({
8707
8709
  SessionForkArgs = external_exports.object({
8708
8710
  cwd: external_exports.string().min(1),
8709
8711
  toolSessionId: external_exports.string().min(1),
8710
- messageUuid: external_exports.string().min(1),
8712
+ /** Claude 消息 UUID;Codex 改用 turnId。 */
8713
+ messageUuid: external_exports.string().min(1).optional(),
8714
+ /** Codex 原生已完成 turn ID。 */
8715
+ turnId: external_exports.string().min(1).optional(),
8716
+ /** 源 clawd session ID;Codex 必填,handler 用它校验 thread 归属。 */
8717
+ sourceSessionId: external_exports.string().min(1).optional(),
8711
8718
  /**
8712
8719
  * 派生 jsonl 的落点 cwd(缺省 = 源文件所在目录,保持老行为)。
8713
8720
  *
@@ -8718,7 +8725,7 @@ var init_schemas = __esm({
8718
8725
  * 正确编排:先 sessionCreate 拿到 daemon 定的真实 cwd,再以它作 targetCwd fork。
8719
8726
  */
8720
8727
  targetCwd: external_exports.string().min(1).optional()
8721
- });
8728
+ }).refine((args) => Boolean(args.messageUuid || args.turnId), "messageUuid or turnId required");
8722
8729
  SessionForkResponseSchema = external_exports.object({
8723
8730
  forkedToolSessionId: external_exports.string().min(1),
8724
8731
  forkedFilePath: external_exports.string().min(1)
@@ -9103,8 +9110,11 @@ var init_methods = __esm({
9103
9110
  args: SessionIdArgs
9104
9111
  },
9105
9112
  "session:fork": {
9106
- summary: "\u4ECE\u6307\u5B9A message \u5904 fork \u51FA\u65B0 transcript\uFF08\u622A\u65AD + \u91CD\u5199 sessionId/parentUuid\uFF09\uFF0C\u8FD4\u56DE\u65B0 toolSessionId\uFF1B\u4E0D\u81EA\u52A8\u62C9\u8D77\u8FDB\u7A0B",
9107
- args: SessionForkArgs
9113
+ summary: "\u4ECE Claude \u6D88\u606F\u6216 Codex \u5DF2\u5B8C\u6210 turn \u6D3E\u751F\u65B0\u4F1A\u8BDD\uFF0C\u8FD4\u56DE\u65B0 toolSessionId\uFF1B\u4E0D\u81EA\u52A8\u62C9\u8D77\u4F1A\u8BDD\u8FDB\u7A0B",
9114
+ args: SessionForkArgs,
9115
+ argsConstraints: {
9116
+ anyOf: [{ required: ["messageUuid"] }, { required: ["turnId"] }]
9117
+ }
9108
9118
  },
9109
9119
  "session:new": {
9110
9120
  summary: "\u5728**\u5DF2\u6709**\u4F1A\u8BDD\u4E0A\u6E05\u7A7A\u4E0A\u4E0B\u6587\u5F00\u65B0\u4E00\u8F6E\uFF0C\u76F8\u5F53\u4E8E CC \u7684 /clear\uFF08\u4E0D\u662F\u5EFA\u65B0\u4F1A\u8BDD\u2014\u2014\u5EFA\u65B0\u4F1A\u8BDD\u7528 session:create\uFF09",
@@ -10325,8 +10335,8 @@ var require_req = __commonJS({
10325
10335
  if (req.originalUrl) {
10326
10336
  _req.url = req.originalUrl;
10327
10337
  } else {
10328
- const path104 = req.path;
10329
- _req.url = typeof path104 === "string" ? path104 : req.url ? req.url.path || req.url : void 0;
10338
+ const path106 = req.path;
10339
+ _req.url = typeof path106 === "string" ? path106 : req.url ? req.url.path || req.url : void 0;
10330
10340
  }
10331
10341
  if (req.query) {
10332
10342
  _req.query = req.query;
@@ -10491,14 +10501,14 @@ var require_redact = __commonJS({
10491
10501
  }
10492
10502
  return obj;
10493
10503
  }
10494
- function parsePath(path104) {
10504
+ function parsePath(path106) {
10495
10505
  const parts = [];
10496
10506
  let current = "";
10497
10507
  let inBrackets = false;
10498
10508
  let inQuotes = false;
10499
10509
  let quoteChar = "";
10500
- for (let i2 = 0; i2 < path104.length; i2++) {
10501
- const char = path104[i2];
10510
+ for (let i2 = 0; i2 < path106.length; i2++) {
10511
+ const char = path106[i2];
10502
10512
  if (!inBrackets && char === ".") {
10503
10513
  if (current) {
10504
10514
  parts.push(current);
@@ -10629,10 +10639,10 @@ var require_redact = __commonJS({
10629
10639
  return current;
10630
10640
  }
10631
10641
  function redactPaths(obj, paths, censor, remove = false) {
10632
- for (const path104 of paths) {
10633
- const parts = parsePath(path104);
10642
+ for (const path106 of paths) {
10643
+ const parts = parsePath(path106);
10634
10644
  if (parts.includes("*")) {
10635
- redactWildcardPath(obj, parts, censor, path104, remove);
10645
+ redactWildcardPath(obj, parts, censor, path106, remove);
10636
10646
  } else {
10637
10647
  if (remove) {
10638
10648
  removeKey(obj, parts);
@@ -10717,8 +10727,8 @@ var require_redact = __commonJS({
10717
10727
  }
10718
10728
  } else {
10719
10729
  if (afterWildcard.includes("*")) {
10720
- const wrappedCensor = typeof censor === "function" ? (value, path104) => {
10721
- const fullPath = [...pathArray.slice(0, pathLength), ...path104];
10730
+ const wrappedCensor = typeof censor === "function" ? (value, path106) => {
10731
+ const fullPath = [...pathArray.slice(0, pathLength), ...path106];
10722
10732
  return censor(value, fullPath);
10723
10733
  } : censor;
10724
10734
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10753,8 +10763,8 @@ var require_redact = __commonJS({
10753
10763
  return null;
10754
10764
  }
10755
10765
  const pathStructure = /* @__PURE__ */ new Map();
10756
- for (const path104 of pathsToClone) {
10757
- const parts = parsePath(path104);
10766
+ for (const path106 of pathsToClone) {
10767
+ const parts = parsePath(path106);
10758
10768
  let current = pathStructure;
10759
10769
  for (let i2 = 0; i2 < parts.length; i2++) {
10760
10770
  const part = parts[i2];
@@ -10806,24 +10816,24 @@ var require_redact = __commonJS({
10806
10816
  }
10807
10817
  return cloneSelectively(obj, pathStructure);
10808
10818
  }
10809
- function validatePath(path104) {
10810
- if (typeof path104 !== "string") {
10819
+ function validatePath(path106) {
10820
+ if (typeof path106 !== "string") {
10811
10821
  throw new Error("Paths must be (non-empty) strings");
10812
10822
  }
10813
- if (path104 === "") {
10823
+ if (path106 === "") {
10814
10824
  throw new Error("Invalid redaction path ()");
10815
10825
  }
10816
- if (path104.includes("..")) {
10817
- throw new Error(`Invalid redaction path (${path104})`);
10826
+ if (path106.includes("..")) {
10827
+ throw new Error(`Invalid redaction path (${path106})`);
10818
10828
  }
10819
- if (path104.includes(",")) {
10820
- throw new Error(`Invalid redaction path (${path104})`);
10829
+ if (path106.includes(",")) {
10830
+ throw new Error(`Invalid redaction path (${path106})`);
10821
10831
  }
10822
10832
  let bracketCount = 0;
10823
10833
  let inQuotes = false;
10824
10834
  let quoteChar = "";
10825
- for (let i2 = 0; i2 < path104.length; i2++) {
10826
- const char = path104[i2];
10835
+ for (let i2 = 0; i2 < path106.length; i2++) {
10836
+ const char = path106[i2];
10827
10837
  if ((char === '"' || char === "'") && bracketCount > 0) {
10828
10838
  if (!inQuotes) {
10829
10839
  inQuotes = true;
@@ -10837,20 +10847,20 @@ var require_redact = __commonJS({
10837
10847
  } else if (char === "]" && !inQuotes) {
10838
10848
  bracketCount--;
10839
10849
  if (bracketCount < 0) {
10840
- throw new Error(`Invalid redaction path (${path104})`);
10850
+ throw new Error(`Invalid redaction path (${path106})`);
10841
10851
  }
10842
10852
  }
10843
10853
  }
10844
10854
  if (bracketCount !== 0) {
10845
- throw new Error(`Invalid redaction path (${path104})`);
10855
+ throw new Error(`Invalid redaction path (${path106})`);
10846
10856
  }
10847
10857
  }
10848
10858
  function validatePaths(paths) {
10849
10859
  if (!Array.isArray(paths)) {
10850
10860
  throw new TypeError("paths must be an array");
10851
10861
  }
10852
- for (const path104 of paths) {
10853
- validatePath(path104);
10862
+ for (const path106 of paths) {
10863
+ validatePath(path106);
10854
10864
  }
10855
10865
  }
10856
10866
  function slowRedact(options = {}) {
@@ -11018,8 +11028,8 @@ var require_redaction = __commonJS({
11018
11028
  if (shape[k3] === null) {
11019
11029
  o2[k3] = (value) => topCensor(value, [k3]);
11020
11030
  } else {
11021
- const wrappedCensor = typeof censor === "function" ? (value, path104) => {
11022
- return censor(value, [k3, ...path104]);
11031
+ const wrappedCensor = typeof censor === "function" ? (value, path106) => {
11032
+ return censor(value, [k3, ...path106]);
11023
11033
  } : censor;
11024
11034
  o2[k3] = Redact({
11025
11035
  paths: shape[k3],
@@ -11237,10 +11247,10 @@ var require_atomic_sleep = __commonJS({
11237
11247
  var require_sonic_boom = __commonJS({
11238
11248
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
11239
11249
  "use strict";
11240
- var fs94 = require("fs");
11250
+ var fs95 = require("fs");
11241
11251
  var EventEmitter2 = require("events");
11242
11252
  var inherits = require("util").inherits;
11243
- var path104 = require("path");
11253
+ var path106 = require("path");
11244
11254
  var sleep2 = require_atomic_sleep();
11245
11255
  var assert = require("assert");
11246
11256
  var BUSY_WRITE_TIMEOUT = 100;
@@ -11294,20 +11304,20 @@ var require_sonic_boom = __commonJS({
11294
11304
  const mode = sonic.mode;
11295
11305
  if (sonic.sync) {
11296
11306
  try {
11297
- if (sonic.mkdir) fs94.mkdirSync(path104.dirname(file), { recursive: true });
11298
- const fd = fs94.openSync(file, flags, mode);
11307
+ if (sonic.mkdir) fs95.mkdirSync(path106.dirname(file), { recursive: true });
11308
+ const fd = fs95.openSync(file, flags, mode);
11299
11309
  fileOpened(null, fd);
11300
11310
  } catch (err) {
11301
11311
  fileOpened(err);
11302
11312
  throw err;
11303
11313
  }
11304
11314
  } else if (sonic.mkdir) {
11305
- fs94.mkdir(path104.dirname(file), { recursive: true }, (err) => {
11315
+ fs95.mkdir(path106.dirname(file), { recursive: true }, (err) => {
11306
11316
  if (err) return fileOpened(err);
11307
- fs94.open(file, flags, mode, fileOpened);
11317
+ fs95.open(file, flags, mode, fileOpened);
11308
11318
  });
11309
11319
  } else {
11310
- fs94.open(file, flags, mode, fileOpened);
11320
+ fs95.open(file, flags, mode, fileOpened);
11311
11321
  }
11312
11322
  }
11313
11323
  function SonicBoom(opts) {
@@ -11348,8 +11358,8 @@ var require_sonic_boom = __commonJS({
11348
11358
  this.flush = flushBuffer;
11349
11359
  this.flushSync = flushBufferSync;
11350
11360
  this._actualWrite = actualWriteBuffer;
11351
- fsWriteSync = () => fs94.writeSync(this.fd, this._writingBuf);
11352
- fsWrite = () => fs94.write(this.fd, this._writingBuf, this.release);
11361
+ fsWriteSync = () => fs95.writeSync(this.fd, this._writingBuf);
11362
+ fsWrite = () => fs95.write(this.fd, this._writingBuf, this.release);
11353
11363
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
11354
11364
  this._writingBuf = "";
11355
11365
  this.write = write;
@@ -11358,15 +11368,15 @@ var require_sonic_boom = __commonJS({
11358
11368
  this._actualWrite = actualWrite;
11359
11369
  fsWriteSync = () => {
11360
11370
  if (Buffer.isBuffer(this._writingBuf)) {
11361
- return fs94.writeSync(this.fd, this._writingBuf);
11371
+ return fs95.writeSync(this.fd, this._writingBuf);
11362
11372
  }
11363
- return fs94.writeSync(this.fd, this._writingBuf, "utf8");
11373
+ return fs95.writeSync(this.fd, this._writingBuf, "utf8");
11364
11374
  };
11365
11375
  fsWrite = () => {
11366
11376
  if (Buffer.isBuffer(this._writingBuf)) {
11367
- return fs94.write(this.fd, this._writingBuf, this.release);
11377
+ return fs95.write(this.fd, this._writingBuf, this.release);
11368
11378
  }
11369
- return fs94.write(this.fd, this._writingBuf, "utf8", this.release);
11379
+ return fs95.write(this.fd, this._writingBuf, "utf8", this.release);
11370
11380
  };
11371
11381
  } else {
11372
11382
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -11423,7 +11433,7 @@ var require_sonic_boom = __commonJS({
11423
11433
  }
11424
11434
  }
11425
11435
  if (this._fsync) {
11426
- fs94.fsyncSync(this.fd);
11436
+ fs95.fsyncSync(this.fd);
11427
11437
  }
11428
11438
  const len = this._len;
11429
11439
  if (this._reopening) {
@@ -11537,7 +11547,7 @@ var require_sonic_boom = __commonJS({
11537
11547
  const onDrain = () => {
11538
11548
  if (!this._fsync) {
11539
11549
  try {
11540
- fs94.fsync(this.fd, (err) => {
11550
+ fs95.fsync(this.fd, (err) => {
11541
11551
  this._flushPending = false;
11542
11552
  cb(err);
11543
11553
  });
@@ -11639,7 +11649,7 @@ var require_sonic_boom = __commonJS({
11639
11649
  const fd = this.fd;
11640
11650
  this.once("ready", () => {
11641
11651
  if (fd !== this.fd) {
11642
- fs94.close(fd, (err) => {
11652
+ fs95.close(fd, (err) => {
11643
11653
  if (err) {
11644
11654
  return this.emit("error", err);
11645
11655
  }
@@ -11688,7 +11698,7 @@ var require_sonic_boom = __commonJS({
11688
11698
  buf = this._bufs[0];
11689
11699
  }
11690
11700
  try {
11691
- const n2 = Buffer.isBuffer(buf) ? fs94.writeSync(this.fd, buf) : fs94.writeSync(this.fd, buf, "utf8");
11701
+ const n2 = Buffer.isBuffer(buf) ? fs95.writeSync(this.fd, buf) : fs95.writeSync(this.fd, buf, "utf8");
11692
11702
  const releasedBufObj = releaseWritingBuf(buf, this._len, n2);
11693
11703
  buf = releasedBufObj.writingBuf;
11694
11704
  this._len = releasedBufObj.len;
@@ -11704,7 +11714,7 @@ var require_sonic_boom = __commonJS({
11704
11714
  }
11705
11715
  }
11706
11716
  try {
11707
- fs94.fsyncSync(this.fd);
11717
+ fs95.fsyncSync(this.fd);
11708
11718
  } catch {
11709
11719
  }
11710
11720
  }
@@ -11725,7 +11735,7 @@ var require_sonic_boom = __commonJS({
11725
11735
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11726
11736
  }
11727
11737
  try {
11728
- const n2 = fs94.writeSync(this.fd, buf);
11738
+ const n2 = fs95.writeSync(this.fd, buf);
11729
11739
  buf = buf.subarray(n2);
11730
11740
  this._len = Math.max(this._len - n2, 0);
11731
11741
  if (buf.length <= 0) {
@@ -11753,13 +11763,13 @@ var require_sonic_boom = __commonJS({
11753
11763
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11754
11764
  if (this.sync) {
11755
11765
  try {
11756
- const written = Buffer.isBuffer(this._writingBuf) ? fs94.writeSync(this.fd, this._writingBuf) : fs94.writeSync(this.fd, this._writingBuf, "utf8");
11766
+ const written = Buffer.isBuffer(this._writingBuf) ? fs95.writeSync(this.fd, this._writingBuf) : fs95.writeSync(this.fd, this._writingBuf, "utf8");
11757
11767
  release2(null, written);
11758
11768
  } catch (err) {
11759
11769
  release2(err);
11760
11770
  }
11761
11771
  } else {
11762
- fs94.write(this.fd, this._writingBuf, release2);
11772
+ fs95.write(this.fd, this._writingBuf, release2);
11763
11773
  }
11764
11774
  }
11765
11775
  function actualWriteBuffer() {
@@ -11768,7 +11778,7 @@ var require_sonic_boom = __commonJS({
11768
11778
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11769
11779
  if (this.sync) {
11770
11780
  try {
11771
- const written = fs94.writeSync(this.fd, this._writingBuf);
11781
+ const written = fs95.writeSync(this.fd, this._writingBuf);
11772
11782
  release2(null, written);
11773
11783
  } catch (err) {
11774
11784
  release2(err);
@@ -11777,7 +11787,7 @@ var require_sonic_boom = __commonJS({
11777
11787
  if (kCopyBuffer) {
11778
11788
  this._writingBuf = Buffer.from(this._writingBuf);
11779
11789
  }
11780
- fs94.write(this.fd, this._writingBuf, release2);
11790
+ fs95.write(this.fd, this._writingBuf, release2);
11781
11791
  }
11782
11792
  }
11783
11793
  function actualClose(sonic) {
@@ -11793,12 +11803,12 @@ var require_sonic_boom = __commonJS({
11793
11803
  sonic._lens = [];
11794
11804
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11795
11805
  try {
11796
- fs94.fsync(sonic.fd, closeWrapped);
11806
+ fs95.fsync(sonic.fd, closeWrapped);
11797
11807
  } catch {
11798
11808
  }
11799
11809
  function closeWrapped() {
11800
11810
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11801
- fs94.close(sonic.fd, done);
11811
+ fs95.close(sonic.fd, done);
11802
11812
  } else {
11803
11813
  done();
11804
11814
  }
@@ -14933,11 +14943,11 @@ var init_lib = __esm({
14933
14943
  }
14934
14944
  }
14935
14945
  },
14936
- addToPath: function addToPath(path104, added, removed, oldPosInc, options) {
14937
- var last = path104.lastComponent;
14946
+ addToPath: function addToPath(path106, added, removed, oldPosInc, options) {
14947
+ var last = path106.lastComponent;
14938
14948
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14939
14949
  return {
14940
- oldPos: path104.oldPos + oldPosInc,
14950
+ oldPos: path106.oldPos + oldPosInc,
14941
14951
  lastComponent: {
14942
14952
  count: last.count + 1,
14943
14953
  added,
@@ -14947,7 +14957,7 @@ var init_lib = __esm({
14947
14957
  };
14948
14958
  } else {
14949
14959
  return {
14950
- oldPos: path104.oldPos + oldPosInc,
14960
+ oldPos: path106.oldPos + oldPosInc,
14951
14961
  lastComponent: {
14952
14962
  count: 1,
14953
14963
  added,
@@ -15529,10 +15539,10 @@ function attachmentToHistoryMessage(o2, ts) {
15529
15539
  const memories = raw.map((m3) => {
15530
15540
  if (!m3 || typeof m3 !== "object") return null;
15531
15541
  const rec6 = m3;
15532
- const path104 = typeof rec6.path === "string" ? rec6.path : null;
15542
+ const path106 = typeof rec6.path === "string" ? rec6.path : null;
15533
15543
  const content = typeof rec6.content === "string" ? rec6.content : null;
15534
- if (!path104 || content == null) return null;
15535
- const entry = { path: path104, content };
15544
+ if (!path106 || content == null) return null;
15545
+ const entry = { path: path106, content };
15536
15546
  if (typeof rec6.mtimeMs === "number") entry.mtimeMs = rec6.mtimeMs;
15537
15547
  return entry;
15538
15548
  }).filter((m3) => m3 !== null);
@@ -16398,10 +16408,10 @@ function parseAttachment(obj) {
16398
16408
  const memories = raw.map((m3) => {
16399
16409
  if (!m3 || typeof m3 !== "object") return null;
16400
16410
  const rec6 = m3;
16401
- const path104 = typeof rec6.path === "string" ? rec6.path : null;
16411
+ const path106 = typeof rec6.path === "string" ? rec6.path : null;
16402
16412
  const content = typeof rec6.content === "string" ? rec6.content : null;
16403
- if (!path104 || content == null) return null;
16404
- const out = { path: path104, content };
16413
+ if (!path106 || content == null) return null;
16414
+ const out = { path: path106, content };
16405
16415
  if (typeof rec6.mtimeMs === "number") out.mtimeMs = rec6.mtimeMs;
16406
16416
  return out;
16407
16417
  }).filter((m3) => m3 !== null);
@@ -37375,8 +37385,8 @@ var require_utils = __commonJS({
37375
37385
  var result = transform[inputType][outputType](input);
37376
37386
  return result;
37377
37387
  };
37378
- exports2.resolve = function(path104) {
37379
- var parts = path104.split("/");
37388
+ exports2.resolve = function(path106) {
37389
+ var parts = path106.split("/");
37380
37390
  var result = [];
37381
37391
  for (var index = 0; index < parts.length; index++) {
37382
37392
  var part = parts[index];
@@ -43229,18 +43239,18 @@ var require_object = __commonJS({
43229
43239
  var object = new ZipObject(name, zipObjectContent, o2);
43230
43240
  this.files[name] = object;
43231
43241
  };
43232
- var parentFolder = function(path104) {
43233
- if (path104.slice(-1) === "/") {
43234
- path104 = path104.substring(0, path104.length - 1);
43242
+ var parentFolder = function(path106) {
43243
+ if (path106.slice(-1) === "/") {
43244
+ path106 = path106.substring(0, path106.length - 1);
43235
43245
  }
43236
- var lastSlash = path104.lastIndexOf("/");
43237
- return lastSlash > 0 ? path104.substring(0, lastSlash) : "";
43246
+ var lastSlash = path106.lastIndexOf("/");
43247
+ return lastSlash > 0 ? path106.substring(0, lastSlash) : "";
43238
43248
  };
43239
- var forceTrailingSlash = function(path104) {
43240
- if (path104.slice(-1) !== "/") {
43241
- path104 += "/";
43249
+ var forceTrailingSlash = function(path106) {
43250
+ if (path106.slice(-1) !== "/") {
43251
+ path106 += "/";
43242
43252
  }
43243
- return path104;
43253
+ return path106;
43244
43254
  };
43245
43255
  var folderAdd = function(name, createFolders) {
43246
43256
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -44242,7 +44252,7 @@ var require_lib3 = __commonJS({
44242
44252
  // src/run-case/recorder.ts
44243
44253
  function startRunCaseRecorder(opts) {
44244
44254
  const now = opts.now ?? Date.now;
44245
- const dir = import_node_path83.default.dirname(opts.recordPath);
44255
+ const dir = import_node_path85.default.dirname(opts.recordPath);
44246
44256
  let stream = null;
44247
44257
  let closing = false;
44248
44258
  let closedSettled = false;
@@ -44256,8 +44266,8 @@ function startRunCaseRecorder(opts) {
44256
44266
  });
44257
44267
  const ensureStream = () => {
44258
44268
  if (stream) return stream;
44259
- import_node_fs65.default.mkdirSync(dir, { recursive: true });
44260
- stream = import_node_fs65.default.createWriteStream(opts.recordPath, { flags: "a" });
44269
+ import_node_fs66.default.mkdirSync(dir, { recursive: true });
44270
+ stream = import_node_fs66.default.createWriteStream(opts.recordPath, { flags: "a" });
44261
44271
  stream.on("close", () => closedResolve());
44262
44272
  return stream;
44263
44273
  };
@@ -44282,12 +44292,12 @@ function startRunCaseRecorder(opts) {
44282
44292
  };
44283
44293
  return { tap, close, closed };
44284
44294
  }
44285
- var import_node_fs65, import_node_path83;
44295
+ var import_node_fs66, import_node_path85;
44286
44296
  var init_recorder = __esm({
44287
44297
  "src/run-case/recorder.ts"() {
44288
44298
  "use strict";
44289
- import_node_fs65 = __toESM(require("fs"), 1);
44290
- import_node_path83 = __toESM(require("path"), 1);
44299
+ import_node_fs66 = __toESM(require("fs"), 1);
44300
+ import_node_path85 = __toESM(require("path"), 1);
44291
44301
  }
44292
44302
  });
44293
44303
 
@@ -44330,7 +44340,7 @@ var init_wire = __esm({
44330
44340
  // src/run-case/controller.ts
44331
44341
  async function runController(opts) {
44332
44342
  const now = opts.now ?? Date.now;
44333
- const cwd = opts.cwd ?? (0, import_node_fs66.mkdtempSync)(import_node_path84.default.join(import_node_os32.default.tmpdir(), "clawd-runcase-"));
44343
+ const cwd = opts.cwd ?? (0, import_node_fs67.mkdtempSync)(import_node_path86.default.join(import_node_os32.default.tmpdir(), "clawd-runcase-"));
44334
44344
  const ownsCwd = opts.cwd === void 0;
44335
44345
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
44336
44346
  const spawnCtx = { cwd };
@@ -44491,19 +44501,19 @@ async function runController(opts) {
44491
44501
  if (sigintHandler) process.off("SIGINT", sigintHandler);
44492
44502
  if (ownsCwd) {
44493
44503
  try {
44494
- (0, import_node_fs66.rmSync)(cwd, { recursive: true, force: true });
44504
+ (0, import_node_fs67.rmSync)(cwd, { recursive: true, force: true });
44495
44505
  } catch {
44496
44506
  }
44497
44507
  }
44498
44508
  return exitCode ?? 0;
44499
44509
  }
44500
- var import_node_fs66, import_node_os32, import_node_path84;
44510
+ var import_node_fs67, import_node_os32, import_node_path86;
44501
44511
  var init_controller = __esm({
44502
44512
  "src/run-case/controller.ts"() {
44503
44513
  "use strict";
44504
- import_node_fs66 = require("fs");
44514
+ import_node_fs67 = require("fs");
44505
44515
  import_node_os32 = __toESM(require("os"), 1);
44506
- import_node_path84 = __toESM(require("path"), 1);
44516
+ import_node_path86 = __toESM(require("path"), 1);
44507
44517
  init_claude();
44508
44518
  init_stdout_splitter();
44509
44519
  init_permission_stdio();
@@ -44775,8 +44785,8 @@ Env (advanced):
44775
44785
  `;
44776
44786
 
44777
44787
  // src/index.ts
44778
- var import_node_path82 = __toESM(require("path"), 1);
44779
- var import_node_fs64 = __toESM(require("fs"), 1);
44788
+ var import_node_path84 = __toESM(require("path"), 1);
44789
+ var import_node_fs65 = __toESM(require("fs"), 1);
44780
44790
  var import_node_os31 = __toESM(require("os"), 1);
44781
44791
  var import_node_crypto26 = require("crypto");
44782
44792
  var import_node_url6 = require("url");
@@ -50064,45 +50074,169 @@ var ProjectsStore = class {
50064
50074
 
50065
50075
  // src/tools/codex-home.ts
50066
50076
  var import_node_os6 = __toESM(require("os"), 1);
50067
- var path14 = __toESM(require("path"), 1);
50068
- var norm = (p3) => path14.resolve(p3);
50077
+ var path15 = __toESM(require("path"), 1);
50078
+
50079
+ // src/tools/transcript-search.ts
50080
+ var import_node_fs10 = __toESM(require("fs"), 1);
50081
+ var import_node_path10 = __toESM(require("path"), 1);
50082
+ var SNIPPET_PAD = 60;
50083
+ var INJECTED_ENVELOPE_RE = /^<(system-reminder|command-name|command-message|command-args|local-command-stdout|local-command-stderr|task-notification|user-prompt-submit-hook|environment_context|user_instructions)\b/;
50084
+ var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
50085
+ function asRecord(v3) {
50086
+ return typeof v3 === "object" && v3 !== null ? v3 : null;
50087
+ }
50088
+ function textOfBlocks(content, types) {
50089
+ if (!Array.isArray(content)) return null;
50090
+ const parts = [];
50091
+ for (const block of content) {
50092
+ const b3 = asRecord(block);
50093
+ if (!b3 || typeof b3.type !== "string" || !types.includes(b3.type)) continue;
50094
+ const text = b3.text;
50095
+ if (typeof text === "string" && text !== "") parts.push(text);
50096
+ }
50097
+ return parts.length > 0 ? parts.join("\n") : null;
50098
+ }
50099
+ function lineToSearchableText(raw) {
50100
+ const line = asRecord(raw);
50101
+ if (!line) return null;
50102
+ if (line.type === "response_item") {
50103
+ const payload = asRecord(line.payload);
50104
+ if (!payload || payload.type !== "message") return null;
50105
+ const role = payload.role;
50106
+ if (role !== "user" && role !== "assistant") return null;
50107
+ const text2 = textOfBlocks(payload.content, ["input_text", "output_text"]);
50108
+ if (text2 === null) return null;
50109
+ if (role !== "user") return text2;
50110
+ const stripped = text2.replace(CODEX_WRAPPER_RE, "").trim();
50111
+ if (stripped === "") return null;
50112
+ return INJECTED_ENVELOPE_RE.test(stripped) ? null : stripped;
50113
+ }
50114
+ if (line.type !== "user" && line.type !== "assistant") return null;
50115
+ const message = asRecord(line.message);
50116
+ if (!message) return null;
50117
+ const content = message.content;
50118
+ const text = typeof content === "string" && content !== "" ? content : textOfBlocks(content, ["text"]);
50119
+ if (text === null) return null;
50120
+ if (line.type === "user" && (line.isMeta === true || line.isSynthetic === true)) return null;
50121
+ if (line.type === "user" && INJECTED_ENVELOPE_RE.test(text.trimStart())) return null;
50122
+ return text;
50123
+ }
50124
+ function escapeRegExp(s2) {
50125
+ return s2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
50126
+ }
50127
+ function makeSnippet(text, at3, needleLength) {
50128
+ const from = Math.max(0, at3 - SNIPPET_PAD);
50129
+ const to = Math.min(text.length, at3 + needleLength + SNIPPET_PAD);
50130
+ const body = text.slice(from, to).replace(/\s+/g, " ").trim();
50131
+ return `${from > 0 ? "\u2026 " : ""}${body}${to < text.length ? " \u2026" : ""}`;
50132
+ }
50133
+ function searchTranscriptFile(file, query) {
50134
+ let buf;
50135
+ try {
50136
+ buf = import_node_fs10.default.readFileSync(file);
50137
+ } catch {
50138
+ return null;
50139
+ }
50140
+ const haystack = buf.toString("latin1");
50141
+ const needle = Buffer.from(query, "utf8").toString("latin1");
50142
+ const re2 = new RegExp(escapeRegExp(needle), "gi");
50143
+ let m3;
50144
+ while ((m3 = re2.exec(haystack)) !== null) {
50145
+ const lineStart = haystack.lastIndexOf("\n", m3.index) + 1;
50146
+ let lineEnd = haystack.indexOf("\n", m3.index);
50147
+ if (lineEnd < 0) lineEnd = haystack.length;
50148
+ re2.lastIndex = lineEnd + 1;
50149
+ let parsed;
50150
+ try {
50151
+ parsed = JSON.parse(Buffer.from(haystack.slice(lineStart, lineEnd), "latin1").toString("utf8"));
50152
+ } catch {
50153
+ continue;
50154
+ }
50155
+ const text = lineToSearchableText(parsed);
50156
+ if (text === null) continue;
50157
+ const at3 = text.toLowerCase().indexOf(query.toLowerCase());
50158
+ if (at3 < 0) continue;
50159
+ return makeSnippet(text, at3, query.length);
50160
+ }
50161
+ return null;
50162
+ }
50163
+ var ROLLOUT_NAME_RE = /-([0-9a-fA-F-]{36})\.jsonl$/;
50164
+ function createCodexRolloutLocator(roots) {
50165
+ let index = null;
50166
+ const walk2 = (dir, into) => {
50167
+ let entries;
50168
+ try {
50169
+ entries = import_node_fs10.default.readdirSync(dir, { withFileTypes: true });
50170
+ } catch {
50171
+ return;
50172
+ }
50173
+ for (const entry of entries) {
50174
+ const full = import_node_path10.default.join(dir, entry.name);
50175
+ if (entry.isDirectory()) {
50176
+ walk2(full, into);
50177
+ continue;
50178
+ }
50179
+ const matched = ROLLOUT_NAME_RE.exec(entry.name);
50180
+ if (matched) into.set(matched[1].toLowerCase(), full);
50181
+ }
50182
+ };
50183
+ return (toolSessionId) => {
50184
+ if (index === null) {
50185
+ index = /* @__PURE__ */ new Map();
50186
+ for (const root of roots) walk2(root, index);
50187
+ }
50188
+ return index.get(toolSessionId.toLowerCase()) ?? null;
50189
+ };
50190
+ }
50191
+
50192
+ // src/tools/codex-home.ts
50193
+ var norm = (p3) => path15.resolve(p3);
50069
50194
  function resolveCodexHome(input) {
50070
50195
  const cwd = norm(input.cwd);
50071
- const rel = path14.relative(norm(input.personaRoot), cwd);
50072
- const isPersonaRoot = rel !== "" && !rel.startsWith("..") && !path14.isAbsolute(rel) && !rel.includes(path14.sep);
50196
+ const rel = path15.relative(norm(input.personaRoot), cwd);
50197
+ const isPersonaRoot = rel !== "" && !rel.startsWith("..") && !path15.isAbsolute(rel) && !rel.includes(path15.sep);
50073
50198
  if (isPersonaRoot) return input.sharedHome;
50074
50199
  if (input.projectPaths.some((p3) => norm(p3) === cwd)) return input.sharedHome;
50075
50200
  return input.isolatedHome;
50076
50201
  }
50077
- function codexRolloutRoots(dataDir, sharedHome = path14.join(import_node_os6.default.homedir(), ".codex")) {
50078
- const roots = [path14.join(sharedHome, "sessions")];
50079
- if (dataDir) roots.push(path14.join(dataDir, "codex-home", "sessions"));
50202
+ function codexRolloutRoots(dataDir, sharedHome = path15.join(import_node_os6.default.homedir(), ".codex")) {
50203
+ const roots = [path15.join(sharedHome, "sessions")];
50204
+ if (dataDir) roots.push(path15.join(dataDir, "codex-home", "sessions"));
50080
50205
  return roots;
50081
50206
  }
50207
+ function locateCodexThread(roots, threadId) {
50208
+ const file = createCodexRolloutLocator(roots)(threadId);
50209
+ if (!file) return null;
50210
+ const root = roots.find((candidate) => {
50211
+ const relative5 = path15.relative(candidate, file);
50212
+ return relative5 !== "" && !relative5.startsWith("..") && !path15.isAbsolute(relative5);
50213
+ });
50214
+ return root ? { file, home: path15.dirname(root) } : null;
50215
+ }
50082
50216
 
50083
50217
  // src/persona/store.ts
50084
- var fs12 = __toESM(require("fs"), 1);
50085
- var path15 = __toESM(require("path"), 1);
50218
+ var fs13 = __toESM(require("fs"), 1);
50219
+ var path16 = __toESM(require("path"), 1);
50086
50220
  init_protocol();
50087
50221
  var PersonaStore = class {
50088
50222
  constructor(root) {
50089
50223
  this.root = root;
50090
- fs12.mkdirSync(root, { recursive: true });
50224
+ fs13.mkdirSync(root, { recursive: true });
50091
50225
  }
50092
50226
  root;
50093
50227
  personaDir(personaId2) {
50094
- return path15.join(this.root, safeFileName(personaId2));
50228
+ return path16.join(this.root, safeFileName(personaId2));
50095
50229
  }
50096
50230
  metaPath(personaId2) {
50097
- return path15.join(this.personaDir(personaId2), ".clawd", "persona.json");
50231
+ return path16.join(this.personaDir(personaId2), ".clawd", "persona.json");
50098
50232
  }
50099
50233
  claudeMdPath(personaId2) {
50100
- return path15.join(this.personaDir(personaId2), "CLAUDE.md");
50234
+ return path16.join(this.personaDir(personaId2), "CLAUDE.md");
50101
50235
  }
50102
50236
  // codex 原生读 cwd 的 AGENTS.md。人格双写镜像:claude 读 CLAUDE.md、codex 读 AGENTS.md,
50103
50237
  // 两份内容恒一致,persona 切 tool 零迁移。
50104
50238
  agentsMdPath(personaId2) {
50105
- return path15.join(this.personaDir(personaId2), "AGENTS.md");
50239
+ return path16.join(this.personaDir(personaId2), "AGENTS.md");
50106
50240
  }
50107
50241
  /**
50108
50242
  * persona 级 sandbox base 落盘路径 —— 故意放 `.clawd/` 而非 `.claude/`,让 CC 的 project
@@ -50111,7 +50245,7 @@ var PersonaStore = class {
50111
50245
  * spawn 前 per-guest 动态拼到各自 session 目录的那份(base + 强制底座 + 本 guest userWorkDir carve)。
50112
50246
  */
50113
50247
  sandboxSettingsPath(personaId2) {
50114
- return path15.join(this.personaDir(personaId2), ".clawd", "sandbox-settings.json");
50248
+ return path16.join(this.personaDir(personaId2), ".clawd", "sandbox-settings.json");
50115
50249
  }
50116
50250
  /**
50117
50251
  * 人格补充层落盘路径 —— `<personaDir>/.clawd/personality.local.md`。
@@ -50126,11 +50260,11 @@ var PersonaStore = class {
50126
50260
  * (见 local-personality-prompt.ts),通道唯一,不会被当第二份 CLAUDE.md 重复加载。
50127
50261
  */
50128
50262
  personalityLocalPath(personaId2) {
50129
- return path15.join(this.personaDir(personaId2), ".clawd", "personality.local.md");
50263
+ return path16.join(this.personaDir(personaId2), ".clawd", "personality.local.md");
50130
50264
  }
50131
50265
  write(persona, personality) {
50132
50266
  const dir = this.personaDir(persona.personaId);
50133
- fs12.mkdirSync(path15.join(dir, ".clawd"), { recursive: true });
50267
+ fs13.mkdirSync(path16.join(dir, ".clawd"), { recursive: true });
50134
50268
  this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
50135
50269
  this.atomicWrite(this.agentsMdPath(persona.personaId), personality);
50136
50270
  this.writeSandboxSettings(persona.personaId, buildGuestSettingsV1());
@@ -50143,8 +50277,8 @@ var PersonaStore = class {
50143
50277
  /** 读人格补充层正文;文件不存在返回 null(= 该 persona 没有补充,走内置人格)。 */
50144
50278
  readPersonalityLocal(personaId2) {
50145
50279
  const p3 = this.personalityLocalPath(personaId2);
50146
- if (!fs12.existsSync(p3)) return null;
50147
- return fs12.readFileSync(p3, "utf8");
50280
+ if (!fs13.existsSync(p3)) return null;
50281
+ return fs13.readFileSync(p3, "utf8");
50148
50282
  }
50149
50283
  /**
50150
50284
  * 写人格补充层。**纯空白 = 清空**:删文件而不是留个空文件——「有没有补充」的唯一判据
@@ -50153,10 +50287,10 @@ var PersonaStore = class {
50153
50287
  writePersonalityLocal(personaId2, body) {
50154
50288
  const p3 = this.personalityLocalPath(personaId2);
50155
50289
  if (!body.trim()) {
50156
- fs12.rmSync(p3, { force: true });
50290
+ fs13.rmSync(p3, { force: true });
50157
50291
  return;
50158
50292
  }
50159
- fs12.mkdirSync(path15.dirname(p3), { recursive: true });
50293
+ fs13.mkdirSync(path16.dirname(p3), { recursive: true });
50160
50294
  this.atomicWrite(p3, body);
50161
50295
  }
50162
50296
  /**
@@ -50168,9 +50302,9 @@ var PersonaStore = class {
50168
50302
  ensureAgentsMirror(personaId2) {
50169
50303
  const claudeMd = this.claudeMdPath(personaId2);
50170
50304
  const agentsMd = this.agentsMdPath(personaId2);
50171
- if (!fs12.existsSync(claudeMd)) return false;
50172
- if (fs12.existsSync(agentsMd)) return false;
50173
- this.atomicWrite(agentsMd, fs12.readFileSync(claudeMd, "utf8"));
50305
+ if (!fs13.existsSync(claudeMd)) return false;
50306
+ if (fs13.existsSync(agentsMd)) return false;
50307
+ this.atomicWrite(agentsMd, fs13.readFileSync(claudeMd, "utf8"));
50174
50308
  return true;
50175
50309
  }
50176
50310
  /**
@@ -50220,22 +50354,22 @@ var PersonaStore = class {
50220
50354
  };
50221
50355
  }
50222
50356
  codexSandboxSettingsPath(personaId2) {
50223
- return path15.join(this.personaDir(personaId2), ".clawd", "codex-sandbox.json");
50357
+ return path16.join(this.personaDir(personaId2), ".clawd", "codex-sandbox.json");
50224
50358
  }
50225
50359
  /** 读 codex-sandbox.json;不存在/损坏 → null。 */
50226
50360
  readCodexSandboxSettings(personaId2) {
50227
50361
  const p3 = this.codexSandboxSettingsPath(personaId2);
50228
- if (!fs12.existsSync(p3)) return null;
50362
+ if (!fs13.existsSync(p3)) return null;
50229
50363
  try {
50230
- return CodexSandboxSettingsSchema.parse(JSON.parse(fs12.readFileSync(p3, "utf8")));
50364
+ return CodexSandboxSettingsSchema.parse(JSON.parse(fs13.readFileSync(p3, "utf8")));
50231
50365
  } catch {
50232
50366
  return null;
50233
50367
  }
50234
50368
  }
50235
50369
  /** 覆盖写 codex-sandbox.json(seed/migrate 用)。 */
50236
50370
  writeCodexSandboxSettings(personaId2, settings) {
50237
- const dir = path15.join(this.personaDir(personaId2), ".clawd");
50238
- fs12.mkdirSync(dir, { recursive: true });
50371
+ const dir = path16.join(this.personaDir(personaId2), ".clawd");
50372
+ fs13.mkdirSync(dir, { recursive: true });
50239
50373
  this.atomicWrite(this.codexSandboxSettingsPath(personaId2), JSON.stringify(settings, null, 2));
50240
50374
  }
50241
50375
  writeMeta(persona) {
@@ -50243,8 +50377,8 @@ var PersonaStore = class {
50243
50377
  }
50244
50378
  read(personaId2) {
50245
50379
  const p3 = this.metaPath(personaId2);
50246
- if (!fs12.existsSync(p3)) return null;
50247
- const raw = JSON.parse(fs12.readFileSync(p3, "utf8"));
50380
+ if (!fs13.existsSync(p3)) return null;
50381
+ const raw = JSON.parse(fs13.readFileSync(p3, "utf8"));
50248
50382
  if (raw && typeof raw === "object" && "tokenMap" in raw) {
50249
50383
  delete raw.tokenMap;
50250
50384
  this.atomicWrite(p3, JSON.stringify(raw, null, 2));
@@ -50252,13 +50386,13 @@ var PersonaStore = class {
50252
50386
  return PersonaFileSchema.parse(raw);
50253
50387
  }
50254
50388
  has(personaId2) {
50255
- return fs12.existsSync(this.metaPath(personaId2));
50389
+ return fs13.existsSync(this.metaPath(personaId2));
50256
50390
  }
50257
50391
  readPersonality(personaId2) {
50258
50392
  const claudeMd = this.claudeMdPath(personaId2);
50259
- if (fs12.existsSync(claudeMd)) return fs12.readFileSync(claudeMd, "utf8");
50393
+ if (fs13.existsSync(claudeMd)) return fs13.readFileSync(claudeMd, "utf8");
50260
50394
  const agentsMd = this.agentsMdPath(personaId2);
50261
- if (fs12.existsSync(agentsMd)) return fs12.readFileSync(agentsMd, "utf8");
50395
+ if (fs13.existsSync(agentsMd)) return fs13.readFileSync(agentsMd, "utf8");
50262
50396
  return null;
50263
50397
  }
50264
50398
  /**
@@ -50267,23 +50401,23 @@ var PersonaStore = class {
50267
50401
  */
50268
50402
  readSandboxSettings(personaId2) {
50269
50403
  const p3 = this.sandboxSettingsPath(personaId2);
50270
- if (!fs12.existsSync(p3)) return null;
50404
+ if (!fs13.existsSync(p3)) return null;
50271
50405
  try {
50272
- return JSON.parse(fs12.readFileSync(p3, "utf8"));
50406
+ return JSON.parse(fs13.readFileSync(p3, "utf8"));
50273
50407
  } catch {
50274
50408
  return null;
50275
50409
  }
50276
50410
  }
50277
50411
  /** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
50278
50412
  skillsDir(personaId2) {
50279
- return path15.join(this.personaDir(personaId2), ".claude", "skills");
50413
+ return path16.join(this.personaDir(personaId2), ".claude", "skills");
50280
50414
  }
50281
50415
  /**
50282
50416
  * Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
50283
50417
  * 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
50284
50418
  */
50285
50419
  claudeSettingsPath(personaId2) {
50286
- return path15.join(this.personaDir(personaId2), ".claude", "settings.json");
50420
+ return path16.join(this.personaDir(personaId2), ".claude", "settings.json");
50287
50421
  }
50288
50422
  /**
50289
50423
  * 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
@@ -50298,10 +50432,10 @@ var PersonaStore = class {
50298
50432
  */
50299
50433
  readEnabledPlugins(personaId2) {
50300
50434
  const p3 = this.claudeSettingsPath(personaId2);
50301
- if (!fs12.existsSync(p3)) return [];
50435
+ if (!fs13.existsSync(p3)) return [];
50302
50436
  let raw;
50303
50437
  try {
50304
- raw = JSON.parse(fs12.readFileSync(p3, "utf8"));
50438
+ raw = JSON.parse(fs13.readFileSync(p3, "utf8"));
50305
50439
  } catch {
50306
50440
  return [];
50307
50441
  }
@@ -50315,22 +50449,22 @@ var PersonaStore = class {
50315
50449
  return out;
50316
50450
  }
50317
50451
  list() {
50318
- if (!fs12.existsSync(this.root)) return [];
50319
- return fs12.readdirSync(this.root).filter((name) => {
50320
- return fs12.existsSync(path15.join(this.root, name, ".clawd", "persona.json"));
50452
+ if (!fs13.existsSync(this.root)) return [];
50453
+ return fs13.readdirSync(this.root).filter((name) => {
50454
+ return fs13.existsSync(path16.join(this.root, name, ".clawd", "persona.json"));
50321
50455
  });
50322
50456
  }
50323
50457
  remove(personaId2) {
50324
50458
  const dir = this.personaDir(personaId2);
50325
- if (fs12.existsSync(dir)) fs12.rmSync(dir, { recursive: true, force: true });
50459
+ if (fs13.existsSync(dir)) fs13.rmSync(dir, { recursive: true, force: true });
50326
50460
  }
50327
50461
  personaDirPath(personaId2) {
50328
50462
  return this.personaDir(personaId2);
50329
50463
  }
50330
50464
  atomicWrite(file, content) {
50331
50465
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
50332
- fs12.writeFileSync(tmp, content, { mode: 384 });
50333
- fs12.renameSync(tmp, file);
50466
+ fs13.writeFileSync(tmp, content, { mode: 384 });
50467
+ fs13.renameSync(tmp, file);
50334
50468
  }
50335
50469
  };
50336
50470
 
@@ -50384,8 +50518,8 @@ var PersonaRegistry = class {
50384
50518
  };
50385
50519
 
50386
50520
  // src/persona/seed.ts
50387
- var fs13 = __toESM(require("fs"), 1);
50388
- var path16 = __toESM(require("path"), 1);
50521
+ var fs14 = __toESM(require("fs"), 1);
50522
+ var path17 = __toESM(require("path"), 1);
50389
50523
  var import_node_url = require("url");
50390
50524
  init_protocol();
50391
50525
  var import_meta = {};
@@ -50584,24 +50718,24 @@ function bundleSiblingFromArgv(argv1, sibling) {
50584
50718
  if (!argv1) return null;
50585
50719
  let real = argv1;
50586
50720
  try {
50587
- real = fs13.realpathSync(argv1);
50721
+ real = fs14.realpathSync(argv1);
50588
50722
  } catch {
50589
50723
  }
50590
- return path16.resolve(path16.dirname(real), sibling);
50724
+ return path17.resolve(path17.dirname(real), sibling);
50591
50725
  }
50592
50726
  function findDefaultsRoot(logger) {
50593
50727
  const candidates = [];
50594
50728
  try {
50595
- const here = path16.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
50596
- candidates.push(path16.resolve(here, "defaults"));
50597
- candidates.push(path16.resolve(here, "persona-defaults"));
50729
+ const here = path17.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
50730
+ candidates.push(path17.resolve(here, "defaults"));
50731
+ candidates.push(path17.resolve(here, "persona-defaults"));
50598
50732
  } catch {
50599
50733
  }
50600
50734
  const fromArgv = bundleSiblingFromArgv(process.argv[1], "persona-defaults");
50601
50735
  if (fromArgv) candidates.push(fromArgv);
50602
50736
  for (const c2 of candidates) {
50603
50737
  try {
50604
- if (fs13.statSync(c2).isDirectory()) {
50738
+ if (fs14.statSync(c2).isDirectory()) {
50605
50739
  logger?.info("persona.defaults-root.resolved", { root: c2 });
50606
50740
  return c2;
50607
50741
  }
@@ -50618,8 +50752,8 @@ function seedDefaultPersonas(args) {
50618
50752
  args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
50619
50753
  continue;
50620
50754
  }
50621
- const bundleDir = path16.join(args.defaultsRoot, entry.personaId);
50622
- if (!fs13.existsSync(bundleDir)) {
50755
+ const bundleDir = path17.join(args.defaultsRoot, entry.personaId);
50756
+ if (!fs14.existsSync(bundleDir)) {
50623
50757
  args.logger.warn("persona.seed.skip", {
50624
50758
  personaId: entry.personaId,
50625
50759
  reason: "bundle-missing",
@@ -50627,8 +50761,8 @@ function seedDefaultPersonas(args) {
50627
50761
  });
50628
50762
  continue;
50629
50763
  }
50630
- const claudeMdPath = path16.join(bundleDir, "CLAUDE.md");
50631
- if (!fs13.existsSync(claudeMdPath)) {
50764
+ const claudeMdPath = path17.join(bundleDir, "CLAUDE.md");
50765
+ if (!fs14.existsSync(claudeMdPath)) {
50632
50766
  args.logger.warn("persona.seed.skip", {
50633
50767
  personaId: entry.personaId,
50634
50768
  reason: "no-CLAUDE.md",
@@ -50636,7 +50770,7 @@ function seedDefaultPersonas(args) {
50636
50770
  });
50637
50771
  continue;
50638
50772
  }
50639
- const personality = fs13.readFileSync(claudeMdPath, "utf8");
50773
+ const personality = fs14.readFileSync(claudeMdPath, "utf8");
50640
50774
  const now = Date.now();
50641
50775
  const persona = {
50642
50776
  personaId: entry.personaId,
@@ -50663,51 +50797,51 @@ function seedDefaultPersonas(args) {
50663
50797
  }
50664
50798
  }
50665
50799
  function skipNodeModulesUnder(srcRoot) {
50666
- return (src) => !path16.relative(srcRoot, src).split(path16.sep).includes("node_modules");
50800
+ return (src) => !path17.relative(srcRoot, src).split(path17.sep).includes("node_modules");
50667
50801
  }
50668
50802
  function copyBundleExtras(srcDir, dstDir) {
50669
- for (const entry of fs13.readdirSync(srcDir, { withFileTypes: true })) {
50803
+ for (const entry of fs14.readdirSync(srcDir, { withFileTypes: true })) {
50670
50804
  if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
50671
- const srcPath = path16.join(srcDir, entry.name);
50672
- const dstPath = path16.join(dstDir, entry.name);
50805
+ const srcPath = path17.join(srcDir, entry.name);
50806
+ const dstPath = path17.join(dstDir, entry.name);
50673
50807
  if (entry.isDirectory()) {
50674
- fs13.cpSync(srcPath, dstPath, { recursive: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
50808
+ fs14.cpSync(srcPath, dstPath, { recursive: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
50675
50809
  } else if (entry.isFile()) {
50676
- fs13.copyFileSync(srcPath, dstPath);
50810
+ fs14.copyFileSync(srcPath, dstPath);
50677
50811
  }
50678
50812
  }
50679
50813
  }
50680
50814
  var DAEMON_MANAGED_PATHS = ["extension-kit", "CLAUDE.md", ".mcp.json", ".claude/skills", ".claude/agents", "mcp"];
50681
50815
  function replaceManagedPath(src, dst) {
50682
- if (!fs13.statSync(src).isDirectory()) {
50683
- fs13.mkdirSync(path16.dirname(dst), { recursive: true });
50684
- fs13.rmSync(dst, { recursive: true, force: true });
50685
- fs13.cpSync(src, dst, { dereference: true });
50816
+ if (!fs14.statSync(src).isDirectory()) {
50817
+ fs14.mkdirSync(path17.dirname(dst), { recursive: true });
50818
+ fs14.rmSync(dst, { recursive: true, force: true });
50819
+ fs14.cpSync(src, dst, { dereference: true });
50686
50820
  return;
50687
50821
  }
50688
- fs13.mkdirSync(dst, { recursive: true });
50689
- for (const e of fs13.readdirSync(src, { withFileTypes: true })) {
50822
+ fs14.mkdirSync(dst, { recursive: true });
50823
+ for (const e of fs14.readdirSync(src, { withFileTypes: true })) {
50690
50824
  if (e.name === "node_modules") continue;
50691
- const child = path16.join(dst, e.name);
50692
- fs13.rmSync(child, { recursive: true, force: true });
50693
- fs13.cpSync(path16.join(src, e.name), child, { recursive: true, dereference: true });
50825
+ const child = path17.join(dst, e.name);
50826
+ fs14.rmSync(child, { recursive: true, force: true });
50827
+ fs14.cpSync(path17.join(src, e.name), child, { recursive: true, dereference: true });
50694
50828
  }
50695
50829
  }
50696
50830
  function refreshDaemonManagedDirs(args) {
50697
50831
  const entries = args.entries ?? DEFAULT_PERSONAS;
50698
50832
  for (const entry of entries) {
50699
- const bundleDir = path16.join(args.defaultsRoot, entry.personaId);
50700
- if (!fs13.existsSync(bundleDir)) continue;
50833
+ const bundleDir = path17.join(args.defaultsRoot, entry.personaId);
50834
+ if (!fs14.existsSync(bundleDir)) continue;
50701
50835
  const personaDir = args.store.personaDirPath(entry.personaId);
50702
- if (!fs13.existsSync(personaDir)) continue;
50836
+ if (!fs14.existsSync(personaDir)) continue;
50703
50837
  for (const relPath of DAEMON_MANAGED_PATHS) {
50704
- const srcPath = path16.join(bundleDir, relPath);
50705
- if (!fs13.existsSync(srcPath)) continue;
50706
- const dstPath = path16.join(personaDir, relPath);
50838
+ const srcPath = path17.join(bundleDir, relPath);
50839
+ if (!fs14.existsSync(srcPath)) continue;
50840
+ const dstPath = path17.join(personaDir, relPath);
50707
50841
  try {
50708
50842
  replaceManagedPath(srcPath, dstPath);
50709
50843
  if (relPath === "CLAUDE.md") {
50710
- replaceManagedPath(srcPath, path16.join(personaDir, "AGENTS.md"));
50844
+ replaceManagedPath(srcPath, path17.join(personaDir, "AGENTS.md"));
50711
50845
  }
50712
50846
  args.logger.info("persona.refresh.synced", {
50713
50847
  personaId: entry.personaId,
@@ -50731,12 +50865,12 @@ function migratePersonalityOverlay(args) {
50731
50865
  for (const entry of entries) {
50732
50866
  const personaId2 = entry.personaId;
50733
50867
  try {
50734
- if (fs13.existsSync(args.store.personalityLocalPath(personaId2))) continue;
50735
- const bundleClaudeMd = path16.join(args.defaultsRoot, personaId2, "CLAUDE.md");
50736
- if (!fs13.existsSync(bundleClaudeMd)) continue;
50868
+ if (fs14.existsSync(args.store.personalityLocalPath(personaId2))) continue;
50869
+ const bundleClaudeMd = path17.join(args.defaultsRoot, personaId2, "CLAUDE.md");
50870
+ if (!fs14.existsSync(bundleClaudeMd)) continue;
50737
50871
  const current = args.store.readPersonality(personaId2);
50738
50872
  if (current === null) continue;
50739
- const bundle = fs13.readFileSync(bundleClaudeMd, "utf8");
50873
+ const bundle = fs14.readFileSync(bundleClaudeMd, "utf8");
50740
50874
  if (current === bundle) continue;
50741
50875
  if (!current.startsWith(bundle)) continue;
50742
50876
  const tail2 = current.slice(bundle.length).trim();
@@ -50835,7 +50969,7 @@ function migrateSandboxAllowRead(args) {
50835
50969
  for (const personaId2 of args.store.list()) {
50836
50970
  try {
50837
50971
  const readPath = tildePath(args.store.personaDirPath(personaId2));
50838
- if (!fs13.existsSync(args.store.sandboxSettingsPath(personaId2))) {
50972
+ if (!fs14.existsSync(args.store.sandboxSettingsPath(personaId2))) {
50839
50973
  args.store.writeSandboxSettings(personaId2, buildGuestSettingsV1());
50840
50974
  n2++;
50841
50975
  continue;
@@ -50878,13 +51012,13 @@ var PERSONA_BUILDER_TOMBSTONE = `${PERSONA_BUILDER_TOMBSTONE_MARKER}
50878
51012
  function containsAnyFile(dir) {
50879
51013
  let entries;
50880
51014
  try {
50881
- entries = fs13.readdirSync(dir, { withFileTypes: true });
51015
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
50882
51016
  } catch {
50883
51017
  return false;
50884
51018
  }
50885
51019
  for (const e of entries) {
50886
51020
  if (e.isDirectory()) {
50887
- if (containsAnyFile(path16.join(dir, e.name))) return true;
51021
+ if (containsAnyFile(path17.join(dir, e.name))) return true;
50888
51022
  } else {
50889
51023
  return true;
50890
51024
  }
@@ -50893,9 +51027,9 @@ function containsAnyFile(dir) {
50893
51027
  }
50894
51028
  function retirePersonaBuilder(args) {
50895
51029
  const dir = args.store.personaDirPath(PERSONA_BUILDER_ID);
50896
- if (!fs13.existsSync(dir)) return;
51030
+ if (!fs14.existsSync(dir)) return;
50897
51031
  try {
50898
- const used = containsAnyFile(path16.join(dir, ".clawd", "sessions")) || containsAnyFile(path16.join(dir, ".claude", "skills")) || containsAnyFile(path16.join(dir, "projects"));
51032
+ const used = containsAnyFile(path17.join(dir, ".clawd", "sessions")) || containsAnyFile(path17.join(dir, ".claude", "skills")) || containsAnyFile(path17.join(dir, "projects"));
50899
51033
  if (!used) {
50900
51034
  args.store.remove(PERSONA_BUILDER_ID);
50901
51035
  args.logger.info("persona.retire-builder.removed", { personaId: PERSONA_BUILDER_ID });
@@ -50903,10 +51037,10 @@ function retirePersonaBuilder(args) {
50903
51037
  }
50904
51038
  let wrote = false;
50905
51039
  for (const name of ["CLAUDE.md", "AGENTS.md"]) {
50906
- const p3 = path16.join(dir, name);
50907
- const cur = fs13.existsSync(p3) ? fs13.readFileSync(p3, "utf8") : null;
51040
+ const p3 = path17.join(dir, name);
51041
+ const cur = fs14.existsSync(p3) ? fs14.readFileSync(p3, "utf8") : null;
50908
51042
  if (cur?.startsWith(PERSONA_BUILDER_TOMBSTONE_MARKER)) continue;
50909
- fs13.writeFileSync(p3, PERSONA_BUILDER_TOMBSTONE);
51043
+ fs14.writeFileSync(p3, PERSONA_BUILDER_TOMBSTONE);
50910
51044
  wrote = true;
50911
51045
  }
50912
51046
  if (wrote) args.logger.info("persona.retire-builder.tombstoned", { personaId: PERSONA_BUILDER_ID });
@@ -50919,9 +51053,9 @@ function retirePersonaBuilder(args) {
50919
51053
  }
50920
51054
 
50921
51055
  // src/skills/scanner.ts
50922
- var import_node_fs10 = __toESM(require("fs"), 1);
51056
+ var import_node_fs11 = __toESM(require("fs"), 1);
50923
51057
  var import_node_os7 = __toESM(require("os"), 1);
50924
- var import_node_path10 = __toESM(require("path"), 1);
51058
+ var import_node_path11 = __toESM(require("path"), 1);
50925
51059
 
50926
51060
  // src/skills/frontmatter.ts
50927
51061
  var STRIP_QUOTES = /^["']|["']$/g;
@@ -51030,7 +51164,7 @@ function parseDescription(content) {
51030
51164
  }
51031
51165
  function isDirLikeSync(p3) {
51032
51166
  try {
51033
- return import_node_fs10.default.statSync(p3).isDirectory();
51167
+ return import_node_fs11.default.statSync(p3).isDirectory();
51034
51168
  } catch {
51035
51169
  return false;
51036
51170
  }
@@ -51038,19 +51172,19 @@ function isDirLikeSync(p3) {
51038
51172
  function scanSkillDir(dir, source, seen, out, pluginName) {
51039
51173
  let entries;
51040
51174
  try {
51041
- entries = import_node_fs10.default.readdirSync(dir, { withFileTypes: true });
51175
+ entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
51042
51176
  } catch {
51043
51177
  return;
51044
51178
  }
51045
51179
  for (const ent of entries) {
51046
- const entryPath = import_node_path10.default.join(dir, ent.name);
51180
+ const entryPath = import_node_path11.default.join(dir, ent.name);
51047
51181
  if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
51048
51182
  let content;
51049
51183
  try {
51050
- content = import_node_fs10.default.readFileSync(import_node_path10.default.join(entryPath, "SKILL.md"), "utf8");
51184
+ content = import_node_fs11.default.readFileSync(import_node_path11.default.join(entryPath, "SKILL.md"), "utf8");
51051
51185
  } catch {
51052
51186
  try {
51053
- content = import_node_fs10.default.readFileSync(import_node_path10.default.join(entryPath, "skill.md"), "utf8");
51187
+ content = import_node_fs11.default.readFileSync(import_node_path11.default.join(entryPath, "skill.md"), "utf8");
51054
51188
  } catch {
51055
51189
  continue;
51056
51190
  }
@@ -51074,26 +51208,26 @@ function listSkillsForDir(dir, source) {
51074
51208
  function scanCommandDir(dir, source, seen, out, pluginName) {
51075
51209
  let entries;
51076
51210
  try {
51077
- entries = import_node_fs10.default.readdirSync(dir, { withFileTypes: true });
51211
+ entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
51078
51212
  } catch {
51079
51213
  return;
51080
51214
  }
51081
51215
  for (const ent of entries) {
51082
- const entryPath = import_node_path10.default.join(dir, ent.name);
51216
+ const entryPath = import_node_path11.default.join(dir, ent.name);
51083
51217
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
51084
51218
  const ns = ent.name;
51085
51219
  let subEntries;
51086
51220
  try {
51087
- subEntries = import_node_fs10.default.readdirSync(entryPath, { withFileTypes: true });
51221
+ subEntries = import_node_fs11.default.readdirSync(entryPath, { withFileTypes: true });
51088
51222
  } catch {
51089
51223
  continue;
51090
51224
  }
51091
51225
  for (const se2 of subEntries) {
51092
51226
  if (!se2.name.endsWith(".md")) continue;
51093
- const sePath = import_node_path10.default.join(entryPath, se2.name);
51227
+ const sePath = import_node_path11.default.join(entryPath, se2.name);
51094
51228
  let content;
51095
51229
  try {
51096
- content = import_node_fs10.default.readFileSync(sePath, "utf8");
51230
+ content = import_node_fs11.default.readFileSync(sePath, "utf8");
51097
51231
  } catch {
51098
51232
  continue;
51099
51233
  }
@@ -51110,7 +51244,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
51110
51244
  } else if (ent.name.endsWith(".md")) {
51111
51245
  let content;
51112
51246
  try {
51113
- content = import_node_fs10.default.readFileSync(entryPath, "utf8");
51247
+ content = import_node_fs11.default.readFileSync(entryPath, "utf8");
51114
51248
  } catch {
51115
51249
  continue;
51116
51250
  }
@@ -51126,10 +51260,10 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
51126
51260
  }
51127
51261
  }
51128
51262
  function readInstalledPlugins(home) {
51129
- const file = import_node_path10.default.join(home, ".claude", "plugins", "installed_plugins.json");
51263
+ const file = import_node_path11.default.join(home, ".claude", "plugins", "installed_plugins.json");
51130
51264
  let raw;
51131
51265
  try {
51132
- raw = import_node_fs10.default.readFileSync(file, "utf8");
51266
+ raw = import_node_fs11.default.readFileSync(file, "utf8");
51133
51267
  } catch {
51134
51268
  return [];
51135
51269
  }
@@ -51177,14 +51311,14 @@ var SkillsScanner = class {
51177
51311
  });
51178
51312
  }
51179
51313
  const fsBlock = [];
51180
- scanSkillDir(import_node_path10.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
51181
- scanCommandDir(import_node_path10.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
51182
- scanSkillDir(import_node_path10.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
51183
- scanCommandDir(import_node_path10.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
51314
+ scanSkillDir(import_node_path11.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
51315
+ scanCommandDir(import_node_path11.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
51316
+ scanSkillDir(import_node_path11.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
51317
+ scanCommandDir(import_node_path11.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
51184
51318
  const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
51185
51319
  for (const { name, root } of plugins) {
51186
- scanSkillDir(import_node_path10.default.join(root, "skills"), "plugin", seen, fsBlock, name);
51187
- scanCommandDir(import_node_path10.default.join(root, "commands"), "plugin", seen, fsBlock, name);
51320
+ scanSkillDir(import_node_path11.default.join(root, "skills"), "plugin", seen, fsBlock, name);
51321
+ scanCommandDir(import_node_path11.default.join(root, "commands"), "plugin", seen, fsBlock, name);
51188
51322
  }
51189
51323
  fsBlock.sort((a2, b3) => a2.name < b3.name ? -1 : a2.name > b3.name ? 1 : 0);
51190
51324
  return [...builtinBlock, ...fsBlock];
@@ -51326,12 +51460,12 @@ var PersonaManager = class {
51326
51460
  };
51327
51461
 
51328
51462
  // src/share-md-viewer/load.ts
51329
- var import_node_fs12 = __toESM(require("fs"), 1);
51330
- var import_node_path11 = __toESM(require("path"), 1);
51463
+ var import_node_fs13 = __toESM(require("fs"), 1);
51464
+ var import_node_path12 = __toESM(require("path"), 1);
51331
51465
  var import_node_url2 = require("url");
51332
51466
 
51333
51467
  // src/share-md-viewer/asset-loader.ts
51334
- var import_node_fs11 = __toESM(require("fs"), 1);
51468
+ var import_node_fs12 = __toESM(require("fs"), 1);
51335
51469
  function htmlEscape(s2) {
51336
51470
  return s2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
51337
51471
  }
@@ -51339,12 +51473,12 @@ function createViewerAssetLoader(opts) {
51339
51473
  let viewerTemplate;
51340
51474
  let errorTemplate;
51341
51475
  try {
51342
- viewerTemplate = import_node_fs11.default.readFileSync(opts.viewerHtmlPath, "utf8");
51476
+ viewerTemplate = import_node_fs12.default.readFileSync(opts.viewerHtmlPath, "utf8");
51343
51477
  } catch (err) {
51344
51478
  throw new Error(`viewer asset not found at ${opts.viewerHtmlPath}: ${err.message}`);
51345
51479
  }
51346
51480
  try {
51347
- errorTemplate = import_node_fs11.default.readFileSync(opts.errorHtmlPath, "utf8");
51481
+ errorTemplate = import_node_fs12.default.readFileSync(opts.errorHtmlPath, "utf8");
51348
51482
  } catch (err) {
51349
51483
  throw new Error(`viewer error asset not found at ${opts.errorHtmlPath}: ${err.message}`);
51350
51484
  }
@@ -51363,25 +51497,25 @@ var import_meta2 = {};
51363
51497
  function tryLoadViewerAssets(logger) {
51364
51498
  const candidates = [];
51365
51499
  try {
51366
- const here = import_node_path11.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
51500
+ const here = import_node_path12.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
51367
51501
  candidates.push(here);
51368
- candidates.push(import_node_path11.default.resolve(here, ".."));
51369
- candidates.push(import_node_path11.default.resolve(here, "..", "..", "dist"));
51502
+ candidates.push(import_node_path12.default.resolve(here, ".."));
51503
+ candidates.push(import_node_path12.default.resolve(here, "..", "..", "dist"));
51370
51504
  } catch {
51371
51505
  }
51372
51506
  if (process.argv[1]) {
51373
51507
  let real = process.argv[1];
51374
51508
  try {
51375
- real = import_node_fs12.default.realpathSync(process.argv[1]);
51509
+ real = import_node_fs13.default.realpathSync(process.argv[1]);
51376
51510
  } catch {
51377
51511
  }
51378
- candidates.push(import_node_path11.default.dirname(real));
51512
+ candidates.push(import_node_path12.default.dirname(real));
51379
51513
  }
51380
51514
  for (const root of candidates) {
51381
- const viewerHtmlPath = import_node_path11.default.join(root, "share-md-viewer.html");
51382
- const errorHtmlPath = import_node_path11.default.join(root, "share-md-viewer-error.html");
51515
+ const viewerHtmlPath = import_node_path12.default.join(root, "share-md-viewer.html");
51516
+ const errorHtmlPath = import_node_path12.default.join(root, "share-md-viewer-error.html");
51383
51517
  try {
51384
- if (import_node_fs12.default.statSync(viewerHtmlPath).isFile() && import_node_fs12.default.statSync(errorHtmlPath).isFile()) {
51518
+ if (import_node_fs13.default.statSync(viewerHtmlPath).isFile() && import_node_fs13.default.statSync(errorHtmlPath).isFile()) {
51385
51519
  logger?.info("share-md-viewer.assets-root.resolved", { root });
51386
51520
  return createViewerAssetLoader({ viewerHtmlPath, errorHtmlPath });
51387
51521
  }
@@ -51396,25 +51530,25 @@ function tryLoadViewerAssets(logger) {
51396
51530
  }
51397
51531
 
51398
51532
  // src/dashboard/load.ts
51399
- var import_node_fs13 = __toESM(require("fs"), 1);
51400
- var import_node_path12 = __toESM(require("path"), 1);
51533
+ var import_node_fs14 = __toESM(require("fs"), 1);
51534
+ var import_node_path13 = __toESM(require("path"), 1);
51401
51535
  var import_node_url3 = require("url");
51402
51536
  init_protocol();
51403
51537
  var import_meta3 = {};
51404
51538
  function candidateRoots() {
51405
51539
  const roots = [];
51406
51540
  try {
51407
- const here = import_node_path12.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url));
51408
- roots.push(here, import_node_path12.default.resolve(here, ".."), import_node_path12.default.resolve(here, "..", "..", "dist"));
51541
+ const here = import_node_path13.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url));
51542
+ roots.push(here, import_node_path13.default.resolve(here, ".."), import_node_path13.default.resolve(here, "..", "..", "dist"));
51409
51543
  } catch {
51410
51544
  }
51411
51545
  if (process.argv[1]) {
51412
51546
  let real = process.argv[1];
51413
51547
  try {
51414
- real = import_node_fs13.default.realpathSync(process.argv[1]);
51548
+ real = import_node_fs14.default.realpathSync(process.argv[1]);
51415
51549
  } catch {
51416
51550
  }
51417
- roots.push(import_node_path12.default.dirname(real));
51551
+ roots.push(import_node_path13.default.dirname(real));
51418
51552
  }
51419
51553
  return roots;
51420
51554
  }
@@ -51422,10 +51556,10 @@ function loadDashboardPages(logger, roots = candidateRoots()) {
51422
51556
  const pages = /* @__PURE__ */ new Map();
51423
51557
  for (const page of DASHBOARD_PAGES) {
51424
51558
  for (const root of roots) {
51425
- const file = import_node_path12.default.join(root, `${page}.html`);
51559
+ const file = import_node_path13.default.join(root, `${page}.html`);
51426
51560
  try {
51427
- if (import_node_fs13.default.statSync(file).isFile()) {
51428
- pages.set(page, import_node_fs13.default.readFileSync(file, "utf8"));
51561
+ if (import_node_fs14.default.statSync(file).isFile()) {
51562
+ pages.set(page, import_node_fs14.default.readFileSync(file, "utf8"));
51429
51563
  logger?.info("dashboard.page-asset.resolved", { page, root });
51430
51564
  break;
51431
51565
  }
@@ -51775,7 +51909,8 @@ function parseCodexRollout(text) {
51775
51909
  kind: "turn-end",
51776
51910
  raw: obj,
51777
51911
  ...ts ? { ts } : {},
51778
- ...durationMs !== void 0 ? { durationMs } : {}
51912
+ ...durationMs !== void 0 ? { durationMs } : {},
51913
+ ...p3.type === "task_complete" && turnId ? { turnId } : {}
51779
51914
  });
51780
51915
  break;
51781
51916
  }
@@ -51843,121 +51978,6 @@ function subagentTerminalResult(started, child) {
51843
51978
  // src/tools/codex-history.ts
51844
51979
  var import_node_fs15 = __toESM(require("fs"), 1);
51845
51980
  var import_node_path14 = __toESM(require("path"), 1);
51846
-
51847
- // src/tools/transcript-search.ts
51848
- var import_node_fs14 = __toESM(require("fs"), 1);
51849
- var import_node_path13 = __toESM(require("path"), 1);
51850
- var SNIPPET_PAD = 60;
51851
- var INJECTED_ENVELOPE_RE = /^<(system-reminder|command-name|command-message|command-args|local-command-stdout|local-command-stderr|task-notification|user-prompt-submit-hook|environment_context|user_instructions)\b/;
51852
- var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
51853
- function asRecord(v3) {
51854
- return typeof v3 === "object" && v3 !== null ? v3 : null;
51855
- }
51856
- function textOfBlocks(content, types) {
51857
- if (!Array.isArray(content)) return null;
51858
- const parts = [];
51859
- for (const block of content) {
51860
- const b3 = asRecord(block);
51861
- if (!b3 || typeof b3.type !== "string" || !types.includes(b3.type)) continue;
51862
- const text = b3.text;
51863
- if (typeof text === "string" && text !== "") parts.push(text);
51864
- }
51865
- return parts.length > 0 ? parts.join("\n") : null;
51866
- }
51867
- function lineToSearchableText(raw) {
51868
- const line = asRecord(raw);
51869
- if (!line) return null;
51870
- if (line.type === "response_item") {
51871
- const payload = asRecord(line.payload);
51872
- if (!payload || payload.type !== "message") return null;
51873
- const role = payload.role;
51874
- if (role !== "user" && role !== "assistant") return null;
51875
- const text2 = textOfBlocks(payload.content, ["input_text", "output_text"]);
51876
- if (text2 === null) return null;
51877
- if (role !== "user") return text2;
51878
- const stripped = text2.replace(CODEX_WRAPPER_RE, "").trim();
51879
- if (stripped === "") return null;
51880
- return INJECTED_ENVELOPE_RE.test(stripped) ? null : stripped;
51881
- }
51882
- if (line.type !== "user" && line.type !== "assistant") return null;
51883
- const message = asRecord(line.message);
51884
- if (!message) return null;
51885
- const content = message.content;
51886
- const text = typeof content === "string" && content !== "" ? content : textOfBlocks(content, ["text"]);
51887
- if (text === null) return null;
51888
- if (line.type === "user" && (line.isMeta === true || line.isSynthetic === true)) return null;
51889
- if (line.type === "user" && INJECTED_ENVELOPE_RE.test(text.trimStart())) return null;
51890
- return text;
51891
- }
51892
- function escapeRegExp(s2) {
51893
- return s2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
51894
- }
51895
- function makeSnippet(text, at3, needleLength) {
51896
- const from = Math.max(0, at3 - SNIPPET_PAD);
51897
- const to = Math.min(text.length, at3 + needleLength + SNIPPET_PAD);
51898
- const body = text.slice(from, to).replace(/\s+/g, " ").trim();
51899
- return `${from > 0 ? "\u2026 " : ""}${body}${to < text.length ? " \u2026" : ""}`;
51900
- }
51901
- function searchTranscriptFile(file, query) {
51902
- let buf;
51903
- try {
51904
- buf = import_node_fs14.default.readFileSync(file);
51905
- } catch {
51906
- return null;
51907
- }
51908
- const haystack = buf.toString("latin1");
51909
- const needle = Buffer.from(query, "utf8").toString("latin1");
51910
- const re2 = new RegExp(escapeRegExp(needle), "gi");
51911
- let m3;
51912
- while ((m3 = re2.exec(haystack)) !== null) {
51913
- const lineStart = haystack.lastIndexOf("\n", m3.index) + 1;
51914
- let lineEnd = haystack.indexOf("\n", m3.index);
51915
- if (lineEnd < 0) lineEnd = haystack.length;
51916
- re2.lastIndex = lineEnd + 1;
51917
- let parsed;
51918
- try {
51919
- parsed = JSON.parse(Buffer.from(haystack.slice(lineStart, lineEnd), "latin1").toString("utf8"));
51920
- } catch {
51921
- continue;
51922
- }
51923
- const text = lineToSearchableText(parsed);
51924
- if (text === null) continue;
51925
- const at3 = text.toLowerCase().indexOf(query.toLowerCase());
51926
- if (at3 < 0) continue;
51927
- return makeSnippet(text, at3, query.length);
51928
- }
51929
- return null;
51930
- }
51931
- var ROLLOUT_NAME_RE = /-([0-9a-fA-F-]{36})\.jsonl$/;
51932
- function createCodexRolloutLocator(roots) {
51933
- let index = null;
51934
- const walk2 = (dir, into) => {
51935
- let entries;
51936
- try {
51937
- entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
51938
- } catch {
51939
- return;
51940
- }
51941
- for (const entry of entries) {
51942
- const full = import_node_path13.default.join(dir, entry.name);
51943
- if (entry.isDirectory()) {
51944
- walk2(full, into);
51945
- continue;
51946
- }
51947
- const matched = ROLLOUT_NAME_RE.exec(entry.name);
51948
- if (matched) into.set(matched[1].toLowerCase(), full);
51949
- }
51950
- };
51951
- return (toolSessionId) => {
51952
- if (index === null) {
51953
- index = /* @__PURE__ */ new Map();
51954
- for (const root of roots) walk2(root, index);
51955
- }
51956
- return index.get(toolSessionId.toLowerCase()) ?? null;
51957
- };
51958
- }
51959
-
51960
- // src/tools/codex-history.ts
51961
51981
  var CODEX_LIST_SESSIONS_LIMIT = 100;
51962
51982
  var CODEX_LIST_SESSIONS_SCAN_CAP = 4e3;
51963
51983
  var PEEK_BYTES = 8 * 1024;
@@ -52523,9 +52543,9 @@ var CentralClientError = class extends Error {
52523
52543
  cause;
52524
52544
  status;
52525
52545
  };
52526
- async function centralRequest(opts, path104, init) {
52546
+ async function centralRequest(opts, path106, init) {
52527
52547
  const f2 = opts.fetchImpl ?? globalThis.fetch;
52528
- const url = `${opts.api.replace(/\/+$/, "")}${path104}`;
52548
+ const url = `${opts.api.replace(/\/+$/, "")}${path106}`;
52529
52549
  const ctrl = new AbortController();
52530
52550
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
52531
52551
  let res;
@@ -53234,7 +53254,8 @@ function tokenUsage(usage) {
53234
53254
  }
53235
53255
  function turnCompleted(turn) {
53236
53256
  if (turn?.status === "failed") return [{ kind: "error", message: str3(rec3(turn.error)?.message) ?? "codex turn failed" }, { kind: "turn_end" }];
53237
- return [{ kind: "turn_end" }];
53257
+ const turnId = turn?.status === "completed" ? str3(turn.id) : void 0;
53258
+ return [{ kind: "turn_end", ...turnId ? { turnId } : {} }];
53238
53259
  }
53239
53260
  function rec3(v3) {
53240
53261
  return typeof v3 === "object" && v3 !== null ? v3 : void 0;
@@ -53559,8 +53580,8 @@ function turnStartInput(text, resolveImage) {
53559
53580
  const items = [];
53560
53581
  let leftover = text;
53561
53582
  for (const m3 of text.matchAll(SKILL_RE)) {
53562
- const [marker, name, path104] = m3;
53563
- items.push({ type: "skill", name, path: path104 });
53583
+ const [marker, name, path106] = m3;
53584
+ items.push({ type: "skill", name, path: path106 });
53564
53585
  leftover = leftover.replace(marker, "");
53565
53586
  }
53566
53587
  for (const m3 of text.matchAll(ATTACHMENT_RE2)) {
@@ -54007,7 +54028,7 @@ function createCodexSession(ctx, sink, deps = {}) {
54007
54028
  );
54008
54029
  args.push(...codexAgentsCliArgs(loadCodexAgentsConfig({ cwd: ctx.cwd, logger: deps.logger })));
54009
54030
  args.push(...codexMemoriesCliArgs(ctx));
54010
- const resolvedCodexHome = deps.codexHomeFor?.(ctx.cwd);
54031
+ const resolvedCodexHome = (ctx.toolSessionId ? deps.codexHomeForThread?.(ctx.toolSessionId) : void 0) ?? deps.codexHomeFor?.(ctx.cwd);
54011
54032
  const env = {
54012
54033
  ...process.env,
54013
54034
  ...resolvedCodexHome ? { CODEX_HOME: resolvedCodexHome } : {},
@@ -54294,9 +54315,8 @@ var CODEX_CAPABILITIES_BASE = {
54294
54315
  tool: "codex",
54295
54316
  toolSessionIdLabel: "Codex Thread ID",
54296
54317
  permissionModes: CODEX_APPROVAL_PRESETS,
54297
- // Codex 原生 child thread 已经映射到现有 Agent 卡 + history drawer;其余功能仍不支持
54298
- //(rewind 无 file-snapshot / 无 TUI pty / 无 observe 推送 / 无文件分享 / fork 是 claude jsonl 专用)。
54299
- features: { rewind: false, subagents: true, tui: false, observe: false, fileSharing: false, fork: false },
54318
+ // 本机 Codex 支持原生 child thread、已完成 turn 的 fork;rewind / TUI / observe / 文件分享仍关闭。
54319
+ features: { rewind: false, subagents: true, tui: false, observe: false, fileSharing: false, fork: true },
54300
54320
  configSchema: [
54301
54321
  {
54302
54322
  name: "model",
@@ -54361,6 +54381,7 @@ var CodexAdapter = class {
54361
54381
  fetchImpl;
54362
54382
  /** CODEX_HOME 归属解析(spec 2026-08-18-codex-project-alignment §3.1),由 index.ts 注入 */
54363
54383
  codexHomeFor;
54384
+ codexHomeForThread;
54364
54385
  getSignSecret;
54365
54386
  // capabilities 的进程级 memo。**回落结果同样被缓存**——否则 codex 没装时每次开弹窗都
54366
54387
  // spawn 一次必然失败的子进程。装好 codex / provider 加了模型后不用重启:设置 → 账号「引擎」的
@@ -54374,6 +54395,7 @@ var CodexAdapter = class {
54374
54395
  this.configQueryOverride = opts.configQueryOverride;
54375
54396
  this.fetchImpl = opts.fetchImpl;
54376
54397
  this.codexHomeFor = opts.codexHomeFor;
54398
+ this.codexHomeForThread = opts.codexHomeForThread;
54377
54399
  this.getSignSecret = opts.getSignSecret;
54378
54400
  }
54379
54401
  async probe() {
@@ -54446,6 +54468,7 @@ var CodexAdapter = class {
54446
54468
  return createCodexSession({ ...ctx, model: sanitizeCodexModel(ctx.model) }, sink, {
54447
54469
  logger: this.logger,
54448
54470
  codexHomeFor: this.codexHomeFor,
54471
+ codexHomeForThread: this.codexHomeForThread,
54449
54472
  getSignSecret: this.getSignSecret
54450
54473
  });
54451
54474
  }
@@ -56654,12 +56677,12 @@ var DEFAULT_TIMEOUT_MS2 = 15e3;
56654
56677
  var MAX_BUFFER = 4 * 1024 * 1024;
56655
56678
  function createGhRunner(defaults) {
56656
56679
  const baseTimeoutMs = defaults?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
56657
- const spawn15 = defaults?.execFile ?? import_node_child_process8.execFile;
56680
+ const spawn16 = defaults?.execFile ?? import_node_child_process8.execFile;
56658
56681
  return {
56659
56682
  run(args, opts) {
56660
56683
  const token = defaults?.token?.();
56661
56684
  return new Promise((resolve9, reject) => {
56662
- spawn15(
56685
+ spawn16(
56663
56686
  "gh",
56664
56687
  args,
56665
56688
  {
@@ -60933,10 +60956,10 @@ function createGithubApi(args) {
60933
60956
  const doFetch = args.fetch ?? fetch;
60934
60957
  const seal = args.seal ?? sealWithSodium;
60935
60958
  const timeoutMs = args.timeoutMs ?? TIMEOUT_MS;
60936
- async function request(method, path104, body) {
60959
+ async function request(method, path106, body) {
60937
60960
  let res;
60938
60961
  try {
60939
- res = await doFetch(`${API}${path104}`, {
60962
+ res = await doFetch(`${API}${path106}`, {
60940
60963
  method,
60941
60964
  headers: {
60942
60965
  Authorization: `Bearer ${args.token}`,
@@ -60961,8 +60984,8 @@ function createGithubApi(args) {
60961
60984
  }
60962
60985
  return { status: res.status, json };
60963
60986
  }
60964
- async function must(method, path104, what, body) {
60965
- const r2 = await request(method, path104, body);
60987
+ async function must(method, path106, what, body) {
60988
+ const r2 = await request(method, path106, body);
60966
60989
  if (r2.status < 200 || r2.status >= 300) throw new GithubApiError(r2.status, explain(r2.status, what, r2.json));
60967
60990
  return r2.json;
60968
60991
  }
@@ -61007,9 +61030,9 @@ function createGithubApi(args) {
61007
61030
  return { env: x2.name, ...Number.isFinite(at3) ? { setAt: at3 } : {} };
61008
61031
  });
61009
61032
  },
61010
- async getJson(path104) {
61033
+ async getJson(path106) {
61011
61034
  try {
61012
- const r2 = await request("GET", path104);
61035
+ const r2 = await request("GET", path106);
61013
61036
  return r2.status >= 200 && r2.status < 300 ? r2.json : void 0;
61014
61037
  } catch {
61015
61038
  return void 0;
@@ -62486,8 +62509,8 @@ function refreshPathFromLoginShell() {
62486
62509
  timeout: 3e3,
62487
62510
  stdio: ["ignore", "pipe", "ignore"]
62488
62511
  });
62489
- const path104 = out.trim();
62490
- if (path104) process.env.PATH = path104;
62512
+ const path106 = out.trim();
62513
+ if (path106) process.env.PATH = path106;
62491
62514
  } catch {
62492
62515
  }
62493
62516
  }
@@ -65436,13 +65459,13 @@ function mapSkillsListResponse(res) {
65436
65459
  const r2 = s2 ?? {};
65437
65460
  const name = str4(r2.name);
65438
65461
  if (!name) continue;
65439
- const path104 = str4(r2.path);
65462
+ const path106 = str4(r2.path);
65440
65463
  const description = str4(r2.description);
65441
65464
  const isPlugin = name.includes(":");
65442
65465
  out.push({
65443
65466
  name,
65444
65467
  source: isPlugin ? "plugin" : "project",
65445
- ...path104 ? { path: path104 } : {},
65468
+ ...path106 ? { path: path106 } : {},
65446
65469
  ...description ? { description } : {},
65447
65470
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
65448
65471
  });
@@ -69976,7 +69999,7 @@ var ServerKeyStore = class {
69976
69999
  init_protocol();
69977
70000
 
69978
70001
  // src/handlers/index.ts
69979
- var import_node_path78 = __toESM(require("path"), 1);
70002
+ var import_node_path80 = __toESM(require("path"), 1);
69980
70003
 
69981
70004
  // src/handlers/session.ts
69982
70005
  init_protocol();
@@ -70049,20 +70072,83 @@ function forkSession(input) {
70049
70072
  return { forkedToolSessionId, forkedFilePath };
70050
70073
  }
70051
70074
 
70052
- // src/session/external-scan.ts
70075
+ // src/tools/codex-fork.ts
70076
+ var import_node_child_process17 = require("child_process");
70053
70077
  var import_node_fs59 = __toESM(require("fs"), 1);
70078
+ var import_node_path65 = __toESM(require("path"), 1);
70079
+ function openCodexAppServer(home, cwd) {
70080
+ const proc = (0, import_node_child_process17.spawn)(process.env.CODEX_BIN ?? "codex", ["app-server", "--listen", "stdio://"], {
70081
+ cwd,
70082
+ env: { ...process.env, CODEX_HOME: home },
70083
+ stdio: ["pipe", "pipe", "pipe"]
70084
+ });
70085
+ proc.on("error", () => proc.stdout?.destroy());
70086
+ const stream = stdioLineStream(proc);
70087
+ return {
70088
+ stream,
70089
+ close: () => {
70090
+ stream.close();
70091
+ if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
70092
+ }
70093
+ };
70094
+ }
70095
+ async function forkCodexThread(input, deps = {}) {
70096
+ const source = locateCodexThread(input.roots, input.sourceThreadId);
70097
+ if (!source) throw new Error(`codex fork: source thread not found: ${input.sourceThreadId}`);
70098
+ const rollout = parseCodexRollout(import_node_fs59.default.readFileSync(source.file, "utf8"));
70099
+ if (rollout.meta?.threadId.toLowerCase() !== input.sourceThreadId.toLowerCase()) {
70100
+ throw new Error(`codex fork: source thread metadata does not match ${input.sourceThreadId}`);
70101
+ }
70102
+ if (!rollout.turns.some((turn) => turn.turnId === input.turnId && turn.status === "completed")) {
70103
+ throw new Error(`codex fork: completed turn not found: ${input.turnId}`);
70104
+ }
70105
+ const connection = (deps.open ?? openCodexAppServer)(source.home, input.targetCwd);
70106
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_CODEX_QUERY_TIMEOUT_MS;
70107
+ let timer;
70108
+ const timeout = new Promise((_3, reject) => {
70109
+ timer = setTimeout(() => reject(new Error(`codex app-server thread/fork timed out after ${timeoutMs}ms`)), timeoutMs);
70110
+ });
70111
+ try {
70112
+ const client = new CodexAppServerClient(connection.stream);
70113
+ return await Promise.race([timeout, (async () => {
70114
+ await client.request("initialize", {
70115
+ clientInfo: { name: "clawd", title: "clawd", version: "0" },
70116
+ capabilities: null
70117
+ });
70118
+ client.notify("initialized", {});
70119
+ const result = await client.request("thread/fork", {
70120
+ threadId: input.sourceThreadId,
70121
+ lastTurnId: input.turnId,
70122
+ cwd: input.targetCwd
70123
+ });
70124
+ const forkedToolSessionId = result?.thread?.id;
70125
+ if (typeof forkedToolSessionId !== "string" || !forkedToolSessionId) {
70126
+ throw new Error("codex fork: app-server returned no thread id");
70127
+ }
70128
+ const forked = locateCodexThread([import_node_path65.default.join(source.home, "sessions")], forkedToolSessionId);
70129
+ if (!forked) throw new Error(`codex fork: rollout not found for forked thread ${forkedToolSessionId}`);
70130
+ return { forkedToolSessionId, forkedFilePath: forked.file };
70131
+ })()]);
70132
+ } finally {
70133
+ if (timer) clearTimeout(timer);
70134
+ connection.close();
70135
+ }
70136
+ }
70137
+
70138
+ // src/session/external-scan.ts
70139
+ var import_node_fs60 = __toESM(require("fs"), 1);
70054
70140
  var import_promises11 = __toESM(require("fs/promises"), 1);
70055
70141
  var import_node_os24 = __toESM(require("os"), 1);
70056
- var import_node_path65 = __toESM(require("path"), 1);
70142
+ var import_node_path66 = __toESM(require("path"), 1);
70057
70143
  var import_node_module = require("module");
70058
- var import_node_child_process17 = require("child_process");
70144
+ var import_node_child_process18 = require("child_process");
70059
70145
  var import_meta7 = {};
70060
70146
  function defaultRoots() {
70061
70147
  const home = import_node_os24.default.homedir();
70062
70148
  return {
70063
- claudeProjectsDir: import_node_path65.default.join(home, ".claude", "projects"),
70064
- codexDir: import_node_path65.default.join(home, ".codex"),
70065
- clawdDir: import_node_path65.default.join(home, ".clawd")
70149
+ claudeProjectsDir: import_node_path66.default.join(home, ".claude", "projects"),
70150
+ codexDir: import_node_path66.default.join(home, ".codex"),
70151
+ clawdDir: import_node_path66.default.join(home, ".clawd")
70066
70152
  };
70067
70153
  }
70068
70154
  function width(s2) {
@@ -70113,7 +70199,7 @@ function userText(msg) {
70113
70199
  }
70114
70200
  function isDir2(p3) {
70115
70201
  try {
70116
- return import_node_fs59.default.statSync(p3).isDirectory();
70202
+ return import_node_fs60.default.statSync(p3).isDirectory();
70117
70203
  } catch {
70118
70204
  return false;
70119
70205
  }
@@ -70122,7 +70208,7 @@ async function scanClaude(roots) {
70122
70208
  const out = [];
70123
70209
  let dirs;
70124
70210
  try {
70125
- dirs = import_node_fs59.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
70211
+ dirs = import_node_fs60.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
70126
70212
  } catch {
70127
70213
  return out;
70128
70214
  }
@@ -70130,16 +70216,16 @@ async function scanClaude(roots) {
70130
70216
  if (!d2.isDirectory()) continue;
70131
70217
  let files;
70132
70218
  try {
70133
- files = import_node_fs59.default.readdirSync(import_node_path65.default.join(roots.claudeProjectsDir, d2.name));
70219
+ files = import_node_fs60.default.readdirSync(import_node_path66.default.join(roots.claudeProjectsDir, d2.name));
70134
70220
  } catch {
70135
70221
  continue;
70136
70222
  }
70137
70223
  for (const name of files) {
70138
70224
  if (!name.endsWith(".jsonl")) continue;
70139
- const file = import_node_path65.default.join(roots.claudeProjectsDir, d2.name, name);
70225
+ const file = import_node_path66.default.join(roots.claudeProjectsDir, d2.name, name);
70140
70226
  let st2;
70141
70227
  try {
70142
- st2 = import_node_fs59.default.statSync(file);
70228
+ st2 = import_node_fs60.default.statSync(file);
70143
70229
  } catch {
70144
70230
  continue;
70145
70231
  }
@@ -70192,7 +70278,7 @@ async function scanClaude(roots) {
70192
70278
  return out;
70193
70279
  }
70194
70280
  async function countCodexTurns(rolloutPath) {
70195
- if (!rolloutPath || !import_node_fs59.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
70281
+ if (!rolloutPath || !import_node_fs60.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
70196
70282
  let turns = 0;
70197
70283
  let first = "";
70198
70284
  for await (const rec6 of jsonLines(rolloutPath)) {
@@ -70223,14 +70309,14 @@ function readCodexThreads(db) {
70223
70309
  } catch {
70224
70310
  }
70225
70311
  try {
70226
- const info = (0, import_node_child_process17.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
70312
+ const info = (0, import_node_child_process18.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
70227
70313
  if (info.status !== 0) return null;
70228
70314
  const have = new Set(
70229
70315
  info.stdout.split("\n").map((l2) => l2.split("|")[1]).filter(Boolean)
70230
70316
  );
70231
70317
  if (!["id", "cwd", "updated_at", "thread_source"].every((c2) => have.has(c2))) return null;
70232
70318
  const sel = COLS.map((c2) => have.has(c2) ? c2 : `NULL AS ${c2}`).join(", ");
70233
- const res = (0, import_node_child_process17.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
70319
+ const res = (0, import_node_child_process18.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
70234
70320
  encoding: "utf8",
70235
70321
  maxBuffer: 64 * 1024 * 1024
70236
70322
  });
@@ -70266,7 +70352,7 @@ async function codexFromRows(rows) {
70266
70352
  async function scanCodex(roots) {
70267
70353
  let dbs = [];
70268
70354
  try {
70269
- dbs = import_node_fs59.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path65.default.join(roots.codexDir, n2));
70355
+ dbs = import_node_fs60.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path66.default.join(roots.codexDir, n2));
70270
70356
  } catch {
70271
70357
  }
70272
70358
  if (!dbs.length) return [];
@@ -70275,14 +70361,14 @@ async function scanCodex(roots) {
70275
70361
  }
70276
70362
  async function scanExternalSessions(rootsIn) {
70277
70363
  const roots = { ...defaultRoots(), ...rootsIn };
70278
- const personaRoot = import_node_path65.default.join(roots.clawdDir, "personas");
70364
+ const personaRoot = import_node_path66.default.join(roots.clawdDir, "personas");
70279
70365
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
70280
70366
  const out = [];
70281
70367
  for (const c2 of all) {
70282
70368
  if (c2.skip) continue;
70283
70369
  if (c2.turns < 1) continue;
70284
70370
  if (!c2.cwd || !isDir2(c2.cwd)) continue;
70285
- if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path65.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path65.default.sep)) {
70371
+ if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path66.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path66.default.sep)) {
70286
70372
  continue;
70287
70373
  }
70288
70374
  out.push({
@@ -70299,13 +70385,13 @@ async function scanExternalSessions(rootsIn) {
70299
70385
  }
70300
70386
 
70301
70387
  // src/session/import-ledger.ts
70302
- var import_node_fs60 = __toESM(require("fs"), 1);
70303
- var import_node_path66 = __toESM(require("path"), 1);
70388
+ var import_node_fs61 = __toESM(require("fs"), 1);
70389
+ var import_node_path67 = __toESM(require("path"), 1);
70304
70390
  var LEDGER_FILENAME = "session-import-ledger.json";
70305
70391
  function readImportLedger(dataDir) {
70306
70392
  try {
70307
70393
  const parsed = JSON.parse(
70308
- import_node_fs60.default.readFileSync(import_node_path66.default.join(dataDir, LEDGER_FILENAME), "utf8")
70394
+ import_node_fs61.default.readFileSync(import_node_path67.default.join(dataDir, LEDGER_FILENAME), "utf8")
70309
70395
  );
70310
70396
  return Array.isArray(parsed) ? parsed : [];
70311
70397
  } catch {
@@ -70313,14 +70399,15 @@ function readImportLedger(dataDir) {
70313
70399
  }
70314
70400
  }
70315
70401
  function appendImportLedger(dataDir, entry) {
70316
- const file = import_node_path66.default.join(dataDir, LEDGER_FILENAME);
70402
+ const file = import_node_path67.default.join(dataDir, LEDGER_FILENAME);
70317
70403
  const entries = readImportLedger(dataDir);
70318
70404
  entries.push(entry);
70319
- import_node_fs60.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70405
+ import_node_fs61.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70320
70406
  }
70321
70407
 
70322
70408
  // src/handlers/session.ts
70323
70409
  init_protocol();
70410
+ var import_node_path68 = __toESM(require("path"), 1);
70324
70411
  function canReadSearchHit(ctx, file) {
70325
70412
  if (!ctx || ctx.principal.kind === "owner") return true;
70326
70413
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
@@ -70588,8 +70675,12 @@ ${attribution}` } : args;
70588
70675
  };
70589
70676
  const fork = async (frame, _client, ctx) => {
70590
70677
  const args = SessionForkArgs.parse(frame);
70678
+ const source = args.sourceSessionId ? manager.get({ sessionId: args.sourceSessionId }).response : null;
70679
+ if (source && (source.sessionId !== args.sourceSessionId || source.toolSessionId !== args.toolSessionId)) {
70680
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: source thread does not match source session");
70681
+ }
70591
70682
  if (ctx && ctx.principal.kind === "guest") {
70592
- const src = store.list().find((s2) => s2.toolSessionId === args.toolSessionId);
70683
+ const src = source ?? store.list().find((s2) => s2.toolSessionId === args.toolSessionId);
70593
70684
  const ok = src != null && canAccessPersona(ctx.grants, src.ownerPersonaId, "read") && src.creatorPrincipalId === ctx.principal.id;
70594
70685
  if (!ok) {
70595
70686
  throw new ClawdError(
@@ -70597,8 +70688,33 @@ ${attribution}` } : args;
70597
70688
  `principal guest:${ctx.principal.id} cannot fork tool session ${args.toolSessionId}`
70598
70689
  );
70599
70690
  }
70691
+ if (source?.tool === "codex" && args.targetCwd && import_node_path68.default.resolve(args.targetCwd) !== import_node_path68.default.resolve(source.cwd)) {
70692
+ throw new ClawdError(ERROR_CODES.FORBIDDEN, "fork: guest targetCwd must match source cwd");
70693
+ }
70694
+ }
70695
+ if (source && source.tool !== void 0 && source.tool !== "claude" && source.tool !== "codex") {
70696
+ throw new ClawdError(ERROR_CODES.TOOL_NOT_SUPPORTED, `tool ${source.tool} does not support fork`);
70697
+ }
70698
+ if (args.turnId && source?.tool !== "codex") {
70699
+ throw new ClawdError(ERROR_CODES.TOOL_NOT_SUPPORTED, "fork: turnId requires a local Codex source session");
70700
+ }
70701
+ if (source?.tool === "codex" && (!args.turnId || args.messageUuid || !args.targetCwd)) {
70702
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: Codex requires turnId and targetCwd");
70703
+ }
70704
+ if (source?.tool !== "codex" && !args.messageUuid) {
70705
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: Claude requires messageUuid");
70600
70706
  }
70601
- const result = forkSession(args);
70707
+ const result = source?.tool === "codex" ? await (deps.forkCodexThread ?? forkCodexThread)({
70708
+ roots: codexRolloutRoots(deps.dataDir),
70709
+ sourceThreadId: args.toolSessionId,
70710
+ turnId: args.turnId,
70711
+ targetCwd: args.targetCwd
70712
+ }) : forkSession({
70713
+ cwd: args.cwd,
70714
+ toolSessionId: args.toolSessionId,
70715
+ messageUuid: args.messageUuid,
70716
+ ...args.targetCwd ? { targetCwd: args.targetCwd } : {}
70717
+ });
70602
70718
  deps.logger?.info("session-fork.done", {
70603
70719
  argCwd: args.cwd,
70604
70720
  sourceToolSessionId: args.toolSessionId,
@@ -70849,7 +70965,7 @@ function buildPermissionHandlers(deps) {
70849
70965
  }
70850
70966
 
70851
70967
  // src/handlers/history.ts
70852
- var path81 = __toESM(require("path"), 1);
70968
+ var path83 = __toESM(require("path"), 1);
70853
70969
  init_protocol();
70854
70970
 
70855
70971
  // src/session/recent-dirs.ts
@@ -70867,7 +70983,7 @@ function listRecentDirs(store, limit = 50) {
70867
70983
  }
70868
70984
 
70869
70985
  // src/permission/persona-paths.ts
70870
- var path80 = __toESM(require("path"), 1);
70986
+ var path82 = __toESM(require("path"), 1);
70871
70987
  function getAllowedPersonaIds(grants, action) {
70872
70988
  const ids = /* @__PURE__ */ new Set();
70873
70989
  for (const g3 of grants) {
@@ -70880,42 +70996,42 @@ function getAllowedPersonaIds(grants, action) {
70880
70996
  return ids;
70881
70997
  }
70882
70998
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
70883
- const target = path80.resolve(absPath);
70999
+ const target = path82.resolve(absPath);
70884
71000
  if (userWorkDir) {
70885
- const u2 = path80.resolve(userWorkDir);
70886
- const usep = u2.endsWith(path80.sep) ? "" : path80.sep;
71001
+ const u2 = path82.resolve(userWorkDir);
71002
+ const usep = u2.endsWith(path82.sep) ? "" : path82.sep;
70887
71003
  if (target === u2 || target.startsWith(u2 + usep)) return true;
70888
71004
  }
70889
- const root = path80.resolve(personaRoot);
70890
- const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
71005
+ const root = path82.resolve(personaRoot);
71006
+ const sep4 = root.endsWith(path82.sep) ? "" : path82.sep;
70891
71007
  if (!target.startsWith(root + sep4)) return false;
70892
- const rel = path80.relative(root, target);
71008
+ const rel = path82.relative(root, target);
70893
71009
  if (!rel || rel.startsWith("..")) return false;
70894
- const personaId2 = rel.split(path80.sep)[0];
71010
+ const personaId2 = rel.split(path82.sep)[0];
70895
71011
  if (!personaId2) return false;
70896
71012
  const allowed = getAllowedPersonaIds(grants, action);
70897
71013
  if (allowed === "*") return true;
70898
71014
  return allowed.has(personaId2);
70899
71015
  }
70900
71016
  function personaIdFromPath(absPath, personaRoot) {
70901
- const root = path80.resolve(personaRoot);
70902
- const target = path80.resolve(absPath);
70903
- const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
71017
+ const root = path82.resolve(personaRoot);
71018
+ const target = path82.resolve(absPath);
71019
+ const sep4 = root.endsWith(path82.sep) ? "" : path82.sep;
70904
71020
  if (!target.startsWith(root + sep4)) return null;
70905
- const rel = path80.relative(root, target);
71021
+ const rel = path82.relative(root, target);
70906
71022
  if (!rel || rel.startsWith("..")) return null;
70907
- const id = rel.split(path80.sep)[0];
71023
+ const id = rel.split(path82.sep)[0];
70908
71024
  return id || null;
70909
71025
  }
70910
71026
  function isPathWithin(dir, absPath) {
70911
- const d2 = path80.resolve(dir);
70912
- const t2 = path80.resolve(absPath);
70913
- const sep4 = d2.endsWith(path80.sep) ? "" : path80.sep;
71027
+ const d2 = path82.resolve(dir);
71028
+ const t2 = path82.resolve(absPath);
71029
+ const sep4 = d2.endsWith(path82.sep) ? "" : path82.sep;
70914
71030
  return t2 === d2 || t2.startsWith(d2 + sep4);
70915
71031
  }
70916
71032
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
70917
71033
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
70918
- return personaIdFromPath(path80.resolve(absPath), personaRoot) === personaId2;
71034
+ return personaIdFromPath(path82.resolve(absPath), personaRoot) === personaId2;
70919
71035
  }
70920
71036
 
70921
71037
  // src/handlers/history.ts
@@ -70941,6 +71057,7 @@ function slimHistoryMessages(messages) {
70941
71057
  if (m3.isSidechain !== void 0) out.isSidechain = m3.isSidechain;
70942
71058
  if (m3.askQuestionAnswers !== void 0) out.askQuestionAnswers = m3.askQuestionAnswers;
70943
71059
  if (m3.durationMs !== void 0) out.durationMs = m3.durationMs;
71060
+ if (m3.turnId !== void 0) out.turnId = m3.turnId;
70944
71061
  const isErrorPair = m3.toolUseId !== void 0 && errorToolUseIds.has(m3.toolUseId);
70945
71062
  if (m3.kind === "tool_call" && isErrorPair && m3.input !== void 0) out.input = m3.input;
70946
71063
  if (m3.kind === "tool_result" && m3.error !== void 0 && m3.output !== void 0) out.output = m3.output;
@@ -70968,7 +71085,7 @@ function buildHistoryHandlers(deps) {
70968
71085
  if (!pid) return false;
70969
71086
  return isGuestPathAllowed(
70970
71087
  ctx.grants,
70971
- path81.join(personaRoot, pid),
71088
+ path83.join(personaRoot, pid),
70972
71089
  personaRoot,
70973
71090
  "read",
70974
71091
  userWorkDir
@@ -70980,7 +71097,7 @@ function buildHistoryHandlers(deps) {
70980
71097
  };
70981
71098
  const list = async (frame, _client, ctx) => {
70982
71099
  const args = HistoryListArgs.parse(frame);
70983
- assertGuestPath(ctx, path81.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
71100
+ assertGuestPath(ctx, path83.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
70984
71101
  const sessions = await history.listSessions(args);
70985
71102
  return { response: { type: "history:list", sessions } };
70986
71103
  };
@@ -71028,14 +71145,14 @@ function buildHistoryHandlers(deps) {
71028
71145
  };
71029
71146
  const subagents = async (frame, _client, ctx) => {
71030
71147
  const args = HistorySubagentsArgs.parse(frame);
71031
- assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
71148
+ assertGuestPath(ctx, path83.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
71032
71149
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
71033
71150
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
71034
71151
  return { response: { type: "history:subagents", subagents: subs } };
71035
71152
  };
71036
71153
  const subagentRead = async (frame, _client, ctx) => {
71037
71154
  const args = HistorySubagentReadArgs.parse(frame);
71038
- assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
71155
+ assertGuestPath(ctx, path83.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
71039
71156
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
71040
71157
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
71041
71158
  return { response: { type: "history:subagent-read", ...res } };
@@ -71045,7 +71162,7 @@ function buildHistoryHandlers(deps) {
71045
71162
  if (ctx?.principal.kind === "guest" && personaRoot) {
71046
71163
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
71047
71164
  const filtered = dirs.filter(
71048
- (d2) => isGuestPathAllowed(ctx.grants, path81.resolve(d2.cwd), personaRoot, "read", userWorkDir)
71165
+ (d2) => isGuestPathAllowed(ctx.grants, path83.resolve(d2.cwd), personaRoot, "read", userWorkDir)
71049
71166
  );
71050
71167
  return { response: { type: "history:recentDirs", dirs: filtered } };
71051
71168
  }
@@ -71062,17 +71179,17 @@ function buildHistoryHandlers(deps) {
71062
71179
  }
71063
71180
 
71064
71181
  // src/handlers/projects.ts
71065
- var fs78 = __toESM(require("fs"), 1);
71182
+ var fs79 = __toESM(require("fs"), 1);
71066
71183
  var os26 = __toESM(require("os"), 1);
71067
- var path82 = __toESM(require("path"), 1);
71068
- var import_node_child_process18 = require("child_process");
71184
+ var path84 = __toESM(require("path"), 1);
71185
+ var import_node_child_process19 = require("child_process");
71069
71186
  init_protocol();
71070
- var DEFAULT_PROJECTS_ROOT = path82.join(os26.homedir(), "Documents", "ChatGPT");
71187
+ var DEFAULT_PROJECTS_ROOT = path84.join(os26.homedir(), "Documents", "ChatGPT");
71071
71188
  function allocateDir(root, name) {
71072
- let candidate = path82.join(root, name);
71189
+ let candidate = path84.join(root, name);
71073
71190
  let n2 = 2;
71074
- while (fs78.existsSync(candidate)) {
71075
- candidate = path82.join(root, `${name} ${n2}`);
71191
+ while (fs79.existsSync(candidate)) {
71192
+ candidate = path84.join(root, `${name} ${n2}`);
71076
71193
  n2 += 1;
71077
71194
  }
71078
71195
  return candidate;
@@ -71100,11 +71217,11 @@ function buildProjectHandlers(deps) {
71100
71217
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
71101
71218
  }
71102
71219
  try {
71103
- if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
71220
+ if (!fs79.statSync(args.path).isDirectory()) throw new Error("not dir");
71104
71221
  } catch {
71105
71222
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
71106
71223
  }
71107
- const r2 = (0, import_node_child_process18.spawnSync)("open", ["-R", args.path], { stdio: "ignore" });
71224
+ const r2 = (0, import_node_child_process19.spawnSync)("open", ["-R", args.path], { stdio: "ignore" });
71108
71225
  if (r2.status !== 0) {
71109
71226
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `open -R \u5931\u8D25: exit ${r2.status}`);
71110
71227
  }
@@ -71116,7 +71233,7 @@ function buildProjectHandlers(deps) {
71116
71233
  let target;
71117
71234
  if (args.path) {
71118
71235
  try {
71119
- if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
71236
+ if (!fs79.statSync(args.path).isDirectory()) throw new Error("not dir");
71120
71237
  } catch {
71121
71238
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
71122
71239
  }
@@ -71124,15 +71241,15 @@ function buildProjectHandlers(deps) {
71124
71241
  } else {
71125
71242
  const name = args.name;
71126
71243
  try {
71127
- fs78.mkdirSync(root, { recursive: true });
71244
+ fs79.mkdirSync(root, { recursive: true });
71128
71245
  target = allocateDir(root, name);
71129
- fs78.mkdirSync(target);
71246
+ fs79.mkdirSync(target);
71130
71247
  } catch (err) {
71131
71248
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
71132
71249
  }
71133
- const git2 = (0, import_node_child_process18.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
71250
+ const git2 = (0, import_node_child_process19.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
71134
71251
  if (git2.status !== 0) {
71135
- fs78.rmSync(target, { recursive: true, force: true });
71252
+ fs79.rmSync(target, { recursive: true, force: true });
71136
71253
  throw new ClawdError(
71137
71254
  ERROR_CODES.INVALID_CWD,
71138
71255
  `git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
@@ -71157,7 +71274,7 @@ function buildProjectHandlers(deps) {
71157
71274
  }
71158
71275
 
71159
71276
  // src/handlers/workspace.ts
71160
- var path83 = __toESM(require("path"), 1);
71277
+ var path85 = __toESM(require("path"), 1);
71161
71278
  init_protocol();
71162
71279
  var os27 = __toESM(require("os"), 1);
71163
71280
  init_protocol();
@@ -71200,22 +71317,22 @@ function buildWorkspaceHandlers(deps) {
71200
71317
  const args = WorkspaceListArgs.parse(frame);
71201
71318
  const isGuest = ctx?.principal.kind === "guest";
71202
71319
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os27.homedir();
71203
- const resolvedCwd = path83.resolve(args.cwd ?? fallbackCwd);
71204
- const target = args.path ? path83.resolve(resolvedCwd, args.path) : resolvedCwd;
71320
+ const resolvedCwd = path85.resolve(args.cwd ?? fallbackCwd);
71321
+ const target = args.path ? path85.resolve(resolvedCwd, args.path) : resolvedCwd;
71205
71322
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
71206
71323
  const res = workspace.list({ ...args, cwd: resolvedCwd });
71207
71324
  return { response: { type: "workspace:list", ...res } };
71208
71325
  };
71209
71326
  const read = async (frame, _client, ctx) => {
71210
71327
  const args = WorkspaceReadArgs.parse(frame);
71211
- const target = path83.isAbsolute(args.path) ? path83.resolve(args.path) : path83.resolve(args.cwd, args.path);
71328
+ const target = path85.isAbsolute(args.path) ? path85.resolve(args.path) : path85.resolve(args.cwd, args.path);
71212
71329
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
71213
71330
  const res = workspace.read(args);
71214
71331
  return { response: { type: "workspace:read", ...res } };
71215
71332
  };
71216
71333
  const skillsList = async (frame, _client, ctx) => {
71217
71334
  const args = SkillsListArgs.parse(frame);
71218
- const cwdAbs = path83.resolve(args.cwd);
71335
+ const cwdAbs = path85.resolve(args.cwd);
71219
71336
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
71220
71337
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
71221
71338
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -71227,7 +71344,7 @@ function buildWorkspaceHandlers(deps) {
71227
71344
  };
71228
71345
  const agentsList = async (frame, _client, ctx) => {
71229
71346
  const args = AgentsListArgs.parse(frame);
71230
- const cwdAbs = path83.resolve(args.cwd);
71347
+ const cwdAbs = path85.resolve(args.cwd);
71231
71348
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
71232
71349
  if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
71233
71350
  return { response: { type: "agents:list", agents: [] } };
@@ -71249,20 +71366,20 @@ function buildWorkspaceHandlers(deps) {
71249
71366
  }
71250
71367
 
71251
71368
  // src/handlers/git.ts
71252
- var path85 = __toESM(require("path"), 1);
71369
+ var path87 = __toESM(require("path"), 1);
71253
71370
  init_protocol();
71254
71371
  init_protocol();
71255
71372
 
71256
71373
  // src/workspace/git.ts
71257
- var import_node_child_process19 = require("child_process");
71258
- var import_node_fs61 = __toESM(require("fs"), 1);
71259
- var import_node_path67 = __toESM(require("path"), 1);
71374
+ var import_node_child_process20 = require("child_process");
71375
+ var import_node_fs62 = __toESM(require("fs"), 1);
71376
+ var import_node_path69 = __toESM(require("path"), 1);
71260
71377
  var import_node_util2 = require("util");
71261
- var pexec = (0, import_node_util2.promisify)(import_node_child_process19.execFile);
71378
+ var pexec = (0, import_node_util2.promisify)(import_node_child_process20.execFile);
71262
71379
  function normalizePath(p3) {
71263
- const resolved = import_node_path67.default.resolve(p3);
71380
+ const resolved = import_node_path69.default.resolve(p3);
71264
71381
  try {
71265
- return import_node_fs61.default.realpathSync(resolved);
71382
+ return import_node_fs62.default.realpathSync(resolved);
71266
71383
  } catch {
71267
71384
  return resolved;
71268
71385
  }
@@ -71336,7 +71453,7 @@ async function listGitBranches(cwd) {
71336
71453
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
71337
71454
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
71338
71455
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
71339
- if (!isGuestPathAllowed(ctx.grants, path85.resolve(cwd), personaRoot, "read", userWorkDir)) {
71456
+ if (!isGuestPathAllowed(ctx.grants, path87.resolve(cwd), personaRoot, "read", userWorkDir)) {
71340
71457
  throw new ClawdError(
71341
71458
  ERROR_CODES.UNAUTHORIZED,
71342
71459
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -71388,7 +71505,7 @@ function buildCapabilitiesHandlers(deps) {
71388
71505
  init_protocol();
71389
71506
 
71390
71507
  // src/tools/version-probe.ts
71391
- var import_node_child_process20 = require("child_process");
71508
+ var import_node_child_process21 = require("child_process");
71392
71509
  init_claude();
71393
71510
  init_protocol();
71394
71511
  function parseVersionOutput(out) {
@@ -71396,7 +71513,7 @@ function parseVersionOutput(out) {
71396
71513
  }
71397
71514
  function execVersion(bin) {
71398
71515
  return new Promise((resolve9, reject) => {
71399
- (0, import_node_child_process20.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
71516
+ (0, import_node_child_process21.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
71400
71517
  if (err) reject(err);
71401
71518
  else resolve9(String(stdout));
71402
71519
  });
@@ -71429,7 +71546,7 @@ async function probeToolVersions(opts = {}) {
71429
71546
  }
71430
71547
 
71431
71548
  // src/tools/pool-connect.ts
71432
- var import_node_child_process21 = require("child_process");
71549
+ var import_node_child_process22 = require("child_process");
71433
71550
  init_protocol();
71434
71551
  var POOL_SETUP_SCRIPT_PATH = "/api/setup.sh";
71435
71552
  var POOL_SCRIPT_FETCH_TIMEOUT_MS = 5e3;
@@ -71455,7 +71572,7 @@ async function fetchScript(deps) {
71455
71572
  }
71456
71573
  function runScript(script, apiKey, deps) {
71457
71574
  return new Promise((resolve9, reject) => {
71458
- const proc = (0, import_node_child_process21.spawn)("bash", ["-s"], {
71575
+ const proc = (0, import_node_child_process22.spawn)("bash", ["-s"], {
71459
71576
  env: { ...deps.env ?? process.env, CPA_KEY: apiKey, CPA_MODE: "api" },
71460
71577
  stdio: ["pipe", "pipe", "pipe"]
71461
71578
  });
@@ -71500,7 +71617,7 @@ function runScript(script, apiKey, deps) {
71500
71617
  }
71501
71618
 
71502
71619
  // src/tools/claude-auth-status.ts
71503
- var import_node_child_process22 = require("child_process");
71620
+ var import_node_child_process23 = require("child_process");
71504
71621
  var str5 = (v3) => typeof v3 === "string" && v3 ? v3 : void 0;
71505
71622
  function mapClaudeAuthStatus(raw) {
71506
71623
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
@@ -71523,7 +71640,7 @@ function mapClaudeAuthStatus(raw) {
71523
71640
  };
71524
71641
  }
71525
71642
  async function queryClaudeAuthStatus(deps = {}) {
71526
- const run = deps.execFileImpl ?? import_node_child_process22.execFile;
71643
+ const run = deps.execFileImpl ?? import_node_child_process23.execFile;
71527
71644
  const env = deps.env ?? process.env;
71528
71645
  const bin = env.CLAUDE_BIN ?? "claude";
71529
71646
  const stdout = await new Promise((resolve9, reject) => {
@@ -71593,12 +71710,12 @@ async function queryCodexAccount(deps = {}) {
71593
71710
  }
71594
71711
 
71595
71712
  // src/tools/pi-account.ts
71596
- var import_node_fs62 = __toESM(require("fs"), 1);
71597
- var import_node_path68 = __toESM(require("path"), 1);
71713
+ var import_node_fs63 = __toESM(require("fs"), 1);
71714
+ var import_node_path70 = __toESM(require("path"), 1);
71598
71715
  function readPiCredentials(agentDir) {
71599
71716
  let raw;
71600
71717
  try {
71601
- raw = JSON.parse(import_node_fs62.default.readFileSync(import_node_path68.default.join(agentDir, "auth.json"), "utf8"));
71718
+ raw = JSON.parse(import_node_fs63.default.readFileSync(import_node_path70.default.join(agentDir, "auth.json"), "utf8"));
71602
71719
  } catch {
71603
71720
  return {};
71604
71721
  }
@@ -71682,9 +71799,9 @@ function buildEngineHandlers(deps, overrides = {}) {
71682
71799
  }
71683
71800
 
71684
71801
  // src/tools/subscription-channels-apply.ts
71685
- var import_node_fs63 = __toESM(require("fs"), 1);
71802
+ var import_node_fs64 = __toESM(require("fs"), 1);
71686
71803
  var import_node_os25 = __toESM(require("os"), 1);
71687
- var import_node_path69 = __toESM(require("path"), 1);
71804
+ var import_node_path71 = __toESM(require("path"), 1);
71688
71805
  var TABLE_HEADER = /^\s*\[\[?\s*([A-Za-z0-9_.-]+)\s*\]\]?\s*(?:#.*)?$/;
71689
71806
  var KEY_LINE = /^\s*([A-Za-z0-9_.-]+)\s*=/;
71690
71807
  function stripCodexProvider(text) {
@@ -71712,10 +71829,10 @@ function stripCodexProvider(text) {
71712
71829
  return out.join("\n").trim();
71713
71830
  }
71714
71831
  function applyCodexSubscriptionChannel(opts) {
71715
- const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path69.default.join(import_node_os25.default.homedir(), ".codex");
71716
- import_node_fs63.default.mkdirSync(codexHome, { recursive: true });
71717
- const configFile = import_node_path69.default.join(codexHome, "config.toml");
71718
- const original = import_node_fs63.default.existsSync(configFile) ? import_node_fs63.default.readFileSync(configFile, "utf8") : "";
71832
+ const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path71.default.join(import_node_os25.default.homedir(), ".codex");
71833
+ import_node_fs64.default.mkdirSync(codexHome, { recursive: true });
71834
+ const configFile = import_node_path71.default.join(codexHome, "config.toml");
71835
+ const original = import_node_fs64.default.existsSync(configFile) ? import_node_fs64.default.readFileSync(configFile, "utf8") : "";
71719
71836
  const rest = stripCodexProvider(original);
71720
71837
  let content;
71721
71838
  if (opts.channel) {
@@ -71739,18 +71856,18 @@ function applyCodexSubscriptionChannel(opts) {
71739
71856
  ].join("\n");
71740
71857
  }
71741
71858
  const tmpFile = `${configFile}.tmp.${Date.now()}`;
71742
- import_node_fs63.default.writeFileSync(tmpFile, content, { mode: 384 });
71743
- import_node_fs63.default.renameSync(tmpFile, configFile);
71859
+ import_node_fs64.default.writeFileSync(tmpFile, content, { mode: 384 });
71860
+ import_node_fs64.default.renameSync(tmpFile, configFile);
71744
71861
  }
71745
71862
  function applyPiSubscriptionChannel(opts) {
71746
- const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path69.default.join(import_node_os25.default.homedir(), ".pi", "agent");
71747
- if (!import_node_fs63.default.existsSync(agentDir)) return false;
71748
- const configFile = import_node_path69.default.join(agentDir, "cliproxyapi.json");
71863
+ const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path71.default.join(import_node_os25.default.homedir(), ".pi", "agent");
71864
+ if (!import_node_fs64.default.existsSync(agentDir)) return false;
71865
+ const configFile = import_node_path71.default.join(agentDir, "cliproxyapi.json");
71749
71866
  if (opts.channel) {
71750
71867
  const data = { baseUrl: opts.channel.baseUrl, apiKey: opts.channel.apiKey };
71751
71868
  const tmp = `${configFile}.tmp.${Date.now()}`;
71752
- import_node_fs63.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
71753
- import_node_fs63.default.renameSync(tmp, configFile);
71869
+ import_node_fs64.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
71870
+ import_node_fs64.default.renameSync(tmp, configFile);
71754
71871
  return true;
71755
71872
  }
71756
71873
  return false;
@@ -72758,21 +72875,21 @@ function computeMethodAccess(args) {
72758
72875
  }
72759
72876
 
72760
72877
  // src/version.ts
72761
- var version = "0.2.594".length > 0 ? "0.2.594" : "dev";
72878
+ var version = "0.2.595".length > 0 ? "0.2.595" : "dev";
72762
72879
 
72763
72880
  // src/cli-probe/probe.ts
72764
- var fs82 = __toESM(require("fs"), 1);
72765
- var path88 = __toESM(require("path"), 1);
72881
+ var fs83 = __toESM(require("fs"), 1);
72882
+ var path90 = __toESM(require("path"), 1);
72766
72883
  var PKG_NAME = "@clawos-dev/clawd";
72767
72884
  var BIN_NAME = "clawd";
72768
72885
  var MAX_PARENT_HOPS = 5;
72769
72886
  function probeGlobalCli(pathEnv) {
72770
72887
  if (!pathEnv) return null;
72771
- for (const dir of pathEnv.split(path88.delimiter)) {
72888
+ for (const dir of pathEnv.split(path90.delimiter)) {
72772
72889
  if (!dir) continue;
72773
72890
  let real;
72774
72891
  try {
72775
- real = fs82.realpathSync(path88.join(dir, BIN_NAME));
72892
+ real = fs83.realpathSync(path90.join(dir, BIN_NAME));
72776
72893
  } catch {
72777
72894
  continue;
72778
72895
  }
@@ -72782,15 +72899,15 @@ function probeGlobalCli(pathEnv) {
72782
72899
  return null;
72783
72900
  }
72784
72901
  function readOwnPackageVersion(entryPath) {
72785
- let dir = path88.dirname(entryPath);
72902
+ let dir = path90.dirname(entryPath);
72786
72903
  for (let i2 = 0; i2 < MAX_PARENT_HOPS; i2++) {
72787
72904
  try {
72788
- const raw = fs82.readFileSync(path88.join(dir, "package.json"), "utf8");
72905
+ const raw = fs83.readFileSync(path90.join(dir, "package.json"), "utf8");
72789
72906
  const pkg = JSON.parse(raw);
72790
72907
  if (pkg.name !== PKG_NAME) return null;
72791
72908
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
72792
72909
  } catch {
72793
- const parent = path88.dirname(dir);
72910
+ const parent = path90.dirname(dir);
72794
72911
  if (parent === dir) return null;
72795
72912
  dir = parent;
72796
72913
  }
@@ -72966,7 +73083,7 @@ function buildPersonaHandlers(deps) {
72966
73083
  }
72967
73084
 
72968
73085
  // src/handlers/attachment.ts
72969
- var import_node_path70 = __toESM(require("path"), 1);
73086
+ var import_node_path72 = __toESM(require("path"), 1);
72970
73087
  init_protocol();
72971
73088
  init_protocol();
72972
73089
  function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot) {
@@ -73045,12 +73162,12 @@ function buildAttachmentHandlers(deps) {
73045
73162
  `session ${args.sessionId} scope unresolved`
73046
73163
  );
73047
73164
  }
73048
- const cwdAbs = import_node_path70.default.resolve(sessionFile.cwd);
73049
- const candidateAbs = import_node_path70.default.isAbsolute(args.relPath) ? import_node_path70.default.resolve(args.relPath) : import_node_path70.default.resolve(cwdAbs, args.relPath);
73165
+ const cwdAbs = import_node_path72.default.resolve(sessionFile.cwd);
73166
+ const candidateAbs = import_node_path72.default.isAbsolute(args.relPath) ? import_node_path72.default.resolve(args.relPath) : import_node_path72.default.resolve(cwdAbs, args.relPath);
73050
73167
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
73051
73168
  const entries = deps.groupFileStore.list(scope, args.sessionId);
73052
73169
  const entry = entries.find((e) => {
73053
- const storedAbs = import_node_path70.default.isAbsolute(e.relPath) ? import_node_path70.default.resolve(e.relPath) : import_node_path70.default.resolve(cwdAbs, e.relPath);
73170
+ const storedAbs = import_node_path72.default.isAbsolute(e.relPath) ? import_node_path72.default.resolve(e.relPath) : import_node_path72.default.resolve(cwdAbs, e.relPath);
73054
73171
  return storedAbs === candidateAbs && !e.stale;
73055
73172
  });
73056
73173
  if (!entry) {
@@ -73074,7 +73191,7 @@ function buildAttachmentHandlers(deps) {
73074
73191
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
73075
73192
  const f2 = deps.sessionStore.read(sessionId);
73076
73193
  if (!f2) return;
73077
- assertGuestAttachmentPath(ctx, import_node_path70.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
73194
+ assertGuestAttachmentPath(ctx, import_node_path72.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
73078
73195
  }
73079
73196
  const groupAdd = async (frame, _client, ctx) => {
73080
73197
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -73089,8 +73206,8 @@ function buildAttachmentHandlers(deps) {
73089
73206
  if (!scope) {
73090
73207
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
73091
73208
  }
73092
- const cwdAbs = import_node_path70.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
73093
- const candidateAbs = import_node_path70.default.isAbsolute(args.relPath) ? import_node_path70.default.resolve(args.relPath) : import_node_path70.default.resolve(cwdAbs, args.relPath);
73209
+ const cwdAbs = import_node_path72.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
73210
+ const candidateAbs = import_node_path72.default.isAbsolute(args.relPath) ? import_node_path72.default.resolve(args.relPath) : import_node_path72.default.resolve(cwdAbs, args.relPath);
73094
73211
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
73095
73212
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
73096
73213
  const size = 0;
@@ -73149,19 +73266,19 @@ function buildAttachmentHandlers(deps) {
73149
73266
 
73150
73267
  // src/handlers/extension.ts
73151
73268
  var import_promises15 = __toESM(require("fs/promises"), 1);
73152
- var import_node_path75 = __toESM(require("path"), 1);
73269
+ var import_node_path77 = __toESM(require("path"), 1);
73153
73270
  init_protocol();
73154
73271
 
73155
73272
  // src/extension/bundle-zip.ts
73156
73273
  var import_promises12 = __toESM(require("fs/promises"), 1);
73157
- var import_node_path71 = __toESM(require("path"), 1);
73274
+ var import_node_path73 = __toESM(require("path"), 1);
73158
73275
  var import_node_crypto22 = __toESM(require("crypto"), 1);
73159
73276
  var import_jszip2 = __toESM(require_lib3(), 1);
73160
73277
  async function bundleExtensionDir(dir) {
73161
73278
  const entries = await listFilesSorted(dir);
73162
73279
  const zip = new import_jszip2.default();
73163
73280
  for (const rel of entries) {
73164
- const abs = import_node_path71.default.join(dir, rel);
73281
+ const abs = import_node_path73.default.join(dir, rel);
73165
73282
  const content = await import_promises12.default.readFile(abs);
73166
73283
  zip.file(rel, content, { date: FIXED_DATE });
73167
73284
  }
@@ -73182,7 +73299,7 @@ async function listFilesSorted(rootDir) {
73182
73299
  return out;
73183
73300
  }
73184
73301
  async function walk(absRoot, relPrefix, out) {
73185
- const dirAbs = import_node_path71.default.join(absRoot, relPrefix);
73302
+ const dirAbs = import_node_path73.default.join(absRoot, relPrefix);
73186
73303
  const entries = await import_promises12.default.readdir(dirAbs, { withFileTypes: true });
73187
73304
  for (const e of entries) {
73188
73305
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -73236,25 +73353,25 @@ function computePublishCheck(args) {
73236
73353
 
73237
73354
  // src/extension/install-flow.ts
73238
73355
  var import_promises13 = __toESM(require("fs/promises"), 1);
73239
- var import_node_path73 = __toESM(require("path"), 1);
73356
+ var import_node_path75 = __toESM(require("path"), 1);
73240
73357
  var import_node_os28 = __toESM(require("os"), 1);
73241
73358
  var import_node_crypto23 = __toESM(require("crypto"), 1);
73242
73359
  var import_jszip3 = __toESM(require_lib3(), 1);
73243
73360
 
73244
73361
  // src/extension/paths.ts
73245
73362
  var import_node_os27 = __toESM(require("os"), 1);
73246
- var import_node_path72 = __toESM(require("path"), 1);
73363
+ var import_node_path74 = __toESM(require("path"), 1);
73247
73364
  function clawdHomeRoot(override) {
73248
- return override ?? process.env.CLAWD_HOME ?? import_node_path72.default.join(import_node_os27.default.homedir(), ".clawd");
73365
+ return override ?? process.env.CLAWD_HOME ?? import_node_path74.default.join(import_node_os27.default.homedir(), ".clawd");
73249
73366
  }
73250
73367
  function extensionsRoot(override) {
73251
- return import_node_path72.default.join(clawdHomeRoot(override), "extensions");
73368
+ return import_node_path74.default.join(clawdHomeRoot(override), "extensions");
73252
73369
  }
73253
73370
  function publishedChannelsFile(override) {
73254
- return import_node_path72.default.join(clawdHomeRoot(override), "extensions-published.json");
73371
+ return import_node_path74.default.join(clawdHomeRoot(override), "extensions-published.json");
73255
73372
  }
73256
73373
  function bundleCacheRoot(override) {
73257
- return import_node_path72.default.join(clawdHomeRoot(override), "extension-bundles");
73374
+ return import_node_path74.default.join(clawdHomeRoot(override), "extension-bundles");
73258
73375
  }
73259
73376
 
73260
73377
  // src/extension/install-flow.ts
@@ -73281,7 +73398,7 @@ async function installFromChannel(args, deps) {
73281
73398
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
73282
73399
  }
73283
73400
  for (const name of Object.keys(zip.files)) {
73284
- if (name.includes("..") || name.startsWith("/") || import_node_path73.default.isAbsolute(name)) {
73401
+ if (name.includes("..") || name.startsWith("/") || import_node_path75.default.isAbsolute(name)) {
73285
73402
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
73286
73403
  }
73287
73404
  }
@@ -73313,7 +73430,7 @@ async function installFromChannel(args, deps) {
73313
73430
  );
73314
73431
  }
73315
73432
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
73316
- const destDir = import_node_path73.default.join(deps.extensionsRoot, localExtId);
73433
+ const destDir = import_node_path75.default.join(deps.extensionsRoot, localExtId);
73317
73434
  let destExists = false;
73318
73435
  try {
73319
73436
  await import_promises13.default.access(destDir);
@@ -73327,16 +73444,16 @@ async function installFromChannel(args, deps) {
73327
73444
  );
73328
73445
  }
73329
73446
  const stage = await import_promises13.default.mkdtemp(
73330
- import_node_path73.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
73447
+ import_node_path75.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
73331
73448
  );
73332
73449
  try {
73333
73450
  for (const [name, entry] of Object.entries(zip.files)) {
73334
- const dest = import_node_path73.default.join(stage, name);
73451
+ const dest = import_node_path75.default.join(stage, name);
73335
73452
  if (entry.dir) {
73336
73453
  await import_promises13.default.mkdir(dest, { recursive: true });
73337
73454
  continue;
73338
73455
  }
73339
- await import_promises13.default.mkdir(import_node_path73.default.dirname(dest), { recursive: true });
73456
+ await import_promises13.default.mkdir(import_node_path75.default.dirname(dest), { recursive: true });
73340
73457
  if (name === "manifest.json") {
73341
73458
  const rewritten = { ...parsed.data, id: localExtId };
73342
73459
  await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -73357,7 +73474,7 @@ async function installFromChannel(args, deps) {
73357
73474
 
73358
73475
  // src/extension/update-flow.ts
73359
73476
  var import_promises14 = __toESM(require("fs/promises"), 1);
73360
- var import_node_path74 = __toESM(require("path"), 1);
73477
+ var import_node_path76 = __toESM(require("path"), 1);
73361
73478
  var import_node_os29 = __toESM(require("os"), 1);
73362
73479
  var import_node_crypto24 = __toESM(require("crypto"), 1);
73363
73480
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -73374,11 +73491,11 @@ async function updateFromChannel(args, deps) {
73374
73491
  channelRef.extId,
73375
73492
  channelRef.ownerPrincipalId
73376
73493
  );
73377
- const liveDir = import_node_path74.default.join(deps.extensionsRoot, localExtId);
73494
+ const liveDir = import_node_path76.default.join(deps.extensionsRoot, localExtId);
73378
73495
  const prevDir = `${liveDir}.prev`;
73379
73496
  let existingVersion;
73380
73497
  try {
73381
- const raw = await import_promises14.default.readFile(import_node_path74.default.join(liveDir, "manifest.json"), "utf8");
73498
+ const raw = await import_promises14.default.readFile(import_node_path76.default.join(liveDir, "manifest.json"), "utf8");
73382
73499
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
73383
73500
  if (!parsed2.success) {
73384
73501
  throw new UpdateError(
@@ -73411,7 +73528,7 @@ async function updateFromChannel(args, deps) {
73411
73528
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
73412
73529
  }
73413
73530
  for (const name of Object.keys(zip.files)) {
73414
- if (name.includes("..") || name.startsWith("/") || import_node_path74.default.isAbsolute(name)) {
73531
+ if (name.includes("..") || name.startsWith("/") || import_node_path76.default.isAbsolute(name)) {
73415
73532
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
73416
73533
  }
73417
73534
  }
@@ -73446,16 +73563,16 @@ async function updateFromChannel(args, deps) {
73446
73563
  await import_promises14.default.rm(prevDir, { recursive: true, force: true });
73447
73564
  await import_promises14.default.rename(liveDir, prevDir);
73448
73565
  const stage = await import_promises14.default.mkdtemp(
73449
- import_node_path74.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73566
+ import_node_path76.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73450
73567
  );
73451
73568
  try {
73452
73569
  for (const [name, entry] of Object.entries(zip.files)) {
73453
- const dest = import_node_path74.default.join(stage, name);
73570
+ const dest = import_node_path76.default.join(stage, name);
73454
73571
  if (entry.dir) {
73455
73572
  await import_promises14.default.mkdir(dest, { recursive: true });
73456
73573
  continue;
73457
73574
  }
73458
- await import_promises14.default.mkdir(import_node_path74.default.dirname(dest), { recursive: true });
73575
+ await import_promises14.default.mkdir(import_node_path76.default.dirname(dest), { recursive: true });
73459
73576
  if (name === "manifest.json") {
73460
73577
  const rewritten = { ...parsed.data, id: localExtId };
73461
73578
  await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -73522,7 +73639,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73522
73639
  );
73523
73640
  }
73524
73641
  }
73525
- const manifestPath = import_node_path75.default.join(root, extId, "manifest.json");
73642
+ const manifestPath = import_node_path77.default.join(root, extId, "manifest.json");
73526
73643
  const manifest = await readManifest(root, extId);
73527
73644
  const next = { ...manifest, version: newVersion };
73528
73645
  const tmp = `${manifestPath}.tmp`;
@@ -73530,7 +73647,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73530
73647
  await import_promises15.default.rename(tmp, manifestPath);
73531
73648
  }
73532
73649
  async function readManifest(root, extId) {
73533
- const file = import_node_path75.default.join(root, extId, "manifest.json");
73650
+ const file = import_node_path77.default.join(root, extId, "manifest.json");
73534
73651
  let raw;
73535
73652
  try {
73536
73653
  raw = await import_promises15.default.readFile(file, "utf8");
@@ -73614,7 +73731,7 @@ function buildExtensionHandlers(deps) {
73614
73731
  };
73615
73732
  async function buildSnapshotMeta(extId) {
73616
73733
  const manifest = await readManifest(deps.root, extId);
73617
- const { sha256, buffer } = await bundleExtensionDir(import_node_path75.default.join(deps.root, extId));
73734
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path77.default.join(deps.root, extId));
73618
73735
  return { manifest, contentHash: sha256, buffer };
73619
73736
  }
73620
73737
  const publish = async (frame, _client, ctx) => {
@@ -74442,7 +74559,7 @@ function buildVisitorHandlers(deps) {
74442
74559
 
74443
74560
  // src/extension/registry.ts
74444
74561
  var import_promises17 = __toESM(require("fs/promises"), 1);
74445
- var import_node_path76 = __toESM(require("path"), 1);
74562
+ var import_node_path78 = __toESM(require("path"), 1);
74446
74563
  async function loadAll(root) {
74447
74564
  let entries;
74448
74565
  try {
@@ -74455,13 +74572,13 @@ async function loadAll(root) {
74455
74572
  for (const ent of entries) {
74456
74573
  if (!ent.isDirectory()) continue;
74457
74574
  if (ent.name.startsWith(".")) continue;
74458
- records.push(await loadOne(import_node_path76.default.join(root, ent.name), ent.name));
74575
+ records.push(await loadOne(import_node_path78.default.join(root, ent.name), ent.name));
74459
74576
  }
74460
74577
  records.sort((a2, b3) => a2.extId < b3.extId ? -1 : a2.extId > b3.extId ? 1 : 0);
74461
74578
  return records;
74462
74579
  }
74463
74580
  async function loadOne(dir, dirName) {
74464
- const manifestPath = import_node_path76.default.join(dir, "manifest.json");
74581
+ const manifestPath = import_node_path78.default.join(dir, "manifest.json");
74465
74582
  let raw;
74466
74583
  try {
74467
74584
  raw = await import_promises17.default.readFile(manifestPath, "utf8");
@@ -74506,7 +74623,7 @@ async function loadOne(dir, dirName) {
74506
74623
 
74507
74624
  // src/extension/uninstall.ts
74508
74625
  var import_promises18 = __toESM(require("fs/promises"), 1);
74509
- var import_node_path77 = __toESM(require("path"), 1);
74626
+ var import_node_path79 = __toESM(require("path"), 1);
74510
74627
  var UninstallError = class extends Error {
74511
74628
  constructor(code, message) {
74512
74629
  super(message);
@@ -74515,7 +74632,7 @@ var UninstallError = class extends Error {
74515
74632
  code;
74516
74633
  };
74517
74634
  async function uninstall(deps) {
74518
- const dir = import_node_path77.default.join(deps.root, deps.extId);
74635
+ const dir = import_node_path79.default.join(deps.root, deps.extId);
74519
74636
  try {
74520
74637
  await import_promises18.default.access(dir);
74521
74638
  } catch {
@@ -74532,7 +74649,7 @@ var import_node_crypto25 = require("crypto");
74532
74649
  init_protocol();
74533
74650
 
74534
74651
  // src/peer-ops/run-command.ts
74535
- var import_node_child_process23 = require("child_process");
74652
+ var import_node_child_process24 = require("child_process");
74536
74653
  var import_node_os30 = __toESM(require("os"), 1);
74537
74654
  var DEFAULT_TIMEOUT_MS6 = 3e4;
74538
74655
  var MAX_TIMEOUT_MS = 3e5;
@@ -74540,7 +74657,7 @@ var MAX_OUTPUT_BYTES = 1048576;
74540
74657
  function runCommand2(command, opts = {}) {
74541
74658
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS6, MAX_TIMEOUT_MS);
74542
74659
  return new Promise((resolve9) => {
74543
- const child = (0, import_node_child_process23.spawn)("bash", ["-c", command], { cwd: import_node_os30.default.homedir() });
74660
+ const child = (0, import_node_child_process24.spawn)("bash", ["-c", command], { cwd: import_node_os30.default.homedir() });
74544
74661
  const out = [];
74545
74662
  const err = [];
74546
74663
  let outBytes = 0;
@@ -74733,7 +74850,7 @@ function buildMethodHandlers(deps) {
74733
74850
  broadcast: deps.broadcastToOwners
74734
74851
  }),
74735
74852
  ...buildMasterHandlers({
74736
- authorityTablePath: import_node_path78.default.join(deps.masterDataDir, "master-authority.json")
74853
+ authorityTablePath: import_node_path80.default.join(deps.masterDataDir, "master-authority.json")
74737
74854
  }),
74738
74855
  ...buildTopicHandlers({
74739
74856
  topicStore: deps.topicStore,
@@ -74875,8 +74992,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
74875
74992
  }
74876
74993
 
74877
74994
  // src/extension/runtime.ts
74878
- var import_node_child_process24 = require("child_process");
74879
- var import_node_path79 = __toESM(require("path"), 1);
74995
+ var import_node_child_process25 = require("child_process");
74996
+ var import_node_path81 = __toESM(require("path"), 1);
74880
74997
  var import_promises19 = require("timers/promises");
74881
74998
 
74882
74999
  // src/extension/port-allocator.ts
@@ -74977,13 +75094,13 @@ var Runtime = class {
74977
75094
  /\$CLAWOS_EXT_PORT/g,
74978
75095
  String(port)
74979
75096
  );
74980
- const dir = import_node_path79.default.join(this.root, extId);
75097
+ const dir = import_node_path81.default.join(this.root, extId);
74981
75098
  const env = {
74982
75099
  ...process.env,
74983
75100
  CLAWOS_EXT_PORT: String(port),
74984
75101
  CLAWOS_EXT_ID: extId
74985
75102
  };
74986
- const child = (0, import_node_child_process24.spawn)("sh", ["-c", cmd], {
75103
+ const child = (0, import_node_child_process25.spawn)("sh", ["-c", cmd], {
74987
75104
  cwd: dir,
74988
75105
  env,
74989
75106
  stdio: ["ignore", "pipe", "pipe"],
@@ -75089,7 +75206,7 @@ ${handle.stderrTail}`
75089
75206
 
75090
75207
  // src/extension/published-channels.ts
75091
75208
  var import_promises20 = __toESM(require("fs/promises"), 1);
75092
- var import_node_path80 = __toESM(require("path"), 1);
75209
+ var import_node_path82 = __toESM(require("path"), 1);
75093
75210
  init_zod();
75094
75211
  var PublishedChannelsError = class extends Error {
75095
75212
  constructor(code, message) {
@@ -75188,7 +75305,7 @@ var PublishedChannelStore = class {
75188
75305
  )
75189
75306
  };
75190
75307
  const tmp = `${this.filePath}.tmp`;
75191
- await import_promises20.default.mkdir(import_node_path80.default.dirname(this.filePath), { recursive: true });
75308
+ await import_promises20.default.mkdir(import_node_path82.default.dirname(this.filePath), { recursive: true });
75192
75309
  await import_promises20.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
75193
75310
  await import_promises20.default.rename(tmp, this.filePath);
75194
75311
  }
@@ -75196,7 +75313,7 @@ var PublishedChannelStore = class {
75196
75313
 
75197
75314
  // src/extension/bundle-cache.ts
75198
75315
  var import_promises21 = __toESM(require("fs/promises"), 1);
75199
- var import_node_path81 = __toESM(require("path"), 1);
75316
+ var import_node_path83 = __toESM(require("path"), 1);
75200
75317
  var BundleCache = class {
75201
75318
  constructor(rootDir) {
75202
75319
  this.rootDir = rootDir;
@@ -75205,14 +75322,14 @@ var BundleCache = class {
75205
75322
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
75206
75323
  async write(snapshotHash, buffer) {
75207
75324
  await import_promises21.default.mkdir(this.rootDir, { recursive: true });
75208
- const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
75325
+ const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
75209
75326
  const tmp = `${file}.tmp`;
75210
75327
  await import_promises21.default.writeFile(tmp, buffer, { mode: 384 });
75211
75328
  await import_promises21.default.rename(tmp, file);
75212
75329
  }
75213
75330
  /** Returns the bundle bytes, or null when the file doesn't exist. */
75214
75331
  async read(snapshotHash) {
75215
- const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
75332
+ const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
75216
75333
  try {
75217
75334
  return await import_promises21.default.readFile(file);
75218
75335
  } catch (e) {
@@ -75222,7 +75339,7 @@ var BundleCache = class {
75222
75339
  }
75223
75340
  /** Idempotent — missing file is not an error. */
75224
75341
  async delete(snapshotHash) {
75225
- const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
75342
+ const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
75226
75343
  await import_promises21.default.rm(file, { force: true });
75227
75344
  }
75228
75345
  };
@@ -75245,24 +75362,24 @@ async function startDaemon(config) {
75245
75362
  sampling: logShippingCfg.sampling,
75246
75363
  homeDir: import_node_os31.default.homedir()
75247
75364
  });
75248
- const logDir = import_node_path82.default.join(config.dataDir, "log");
75249
- import_node_fs64.default.mkdirSync(logDir, { recursive: true });
75365
+ const logDir = import_node_path84.default.join(config.dataDir, "log");
75366
+ import_node_fs65.default.mkdirSync(logDir, { recursive: true });
75250
75367
  const logger = createLogger({
75251
75368
  level: config.logLevel,
75252
- file: import_node_path82.default.join(logDir, "clawd.log"),
75369
+ file: import_node_path84.default.join(logDir, "clawd.log"),
75253
75370
  logClient
75254
75371
  });
75255
75372
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
75256
75373
  const screenIdleProbeLogger = createFileOnlyLogger({
75257
- file: import_node_path82.default.join(logDir, "screen-idle-probe.log"),
75374
+ file: import_node_path84.default.join(logDir, "screen-idle-probe.log"),
75258
75375
  level: "debug"
75259
75376
  });
75260
75377
  logger.info("screen-idle probe logger enabled", {
75261
- file: import_node_path82.default.join(logDir, "screen-idle-probe.log")
75378
+ file: import_node_path84.default.join(logDir, "screen-idle-probe.log")
75262
75379
  });
75263
75380
  const CAP_TARGETS = [
75264
- import_node_path82.default.join(logDir, "clawd.log"),
75265
- import_node_path82.default.join(logDir, "screen-idle-probe.log")
75381
+ import_node_path84.default.join(logDir, "clawd.log"),
75382
+ import_node_path84.default.join(logDir, "screen-idle-probe.log")
75266
75383
  ];
75267
75384
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
75268
75385
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -75384,9 +75501,9 @@ async function startDaemon(config) {
75384
75501
  const agents = new AgentsScanner();
75385
75502
  const history = new ClaudeHistoryReader();
75386
75503
  let transport = null;
75387
- const personaStore = new PersonaStore(import_node_path82.default.join(config.dataDir, "personas"));
75504
+ const personaStore = new PersonaStore(import_node_path84.default.join(config.dataDir, "personas"));
75388
75505
  const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
75389
- const usersRoot = import_node_path82.default.join(config.dataDir, "users");
75506
+ const usersRoot = import_node_path84.default.join(config.dataDir, "users");
75390
75507
  const defaultsRoot = findDefaultsRoot(logger);
75391
75508
  if (defaultsRoot) {
75392
75509
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -75403,7 +75520,7 @@ async function startDaemon(config) {
75403
75520
  retirePersonaBuilder({ store: personaStore, logger });
75404
75521
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
75405
75522
  const dispatchStore = createDispatchStore({
75406
- filePath: import_node_path82.default.join(config.dataDir, "dispatch.json"),
75523
+ filePath: import_node_path84.default.join(config.dataDir, "dispatch.json"),
75407
75524
  now: () => Date.now(),
75408
75525
  onFlushError: (err) => logger.error("dispatch store flush failed", {
75409
75526
  reason: err instanceof Error ? err.message : String(err)
@@ -75412,7 +75529,7 @@ async function startDaemon(config) {
75412
75529
  await dispatchStore.load();
75413
75530
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
75414
75531
  const channelStore = createChannelStore({
75415
- filePath: import_node_path82.default.join(config.dataDir, "channels.json"),
75532
+ filePath: import_node_path84.default.join(config.dataDir, "channels.json"),
75416
75533
  now: () => Date.now(),
75417
75534
  genId: () => `ch-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75418
75535
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -75421,7 +75538,7 @@ async function startDaemon(config) {
75421
75538
  });
75422
75539
  await channelStore.load();
75423
75540
  const topicStore = createTopicStore({
75424
- filePath: import_node_path82.default.join(config.dataDir, "topics.json"),
75541
+ filePath: import_node_path84.default.join(config.dataDir, "topics.json"),
75425
75542
  now: () => Date.now(),
75426
75543
  genId: () => `tp-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75427
75544
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -75448,12 +75565,12 @@ async function startDaemon(config) {
75448
75565
  });
75449
75566
  }
75450
75567
  });
75451
- const here = typeof __dirname === "string" ? __dirname : import_node_path82.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75568
+ const here = typeof __dirname === "string" ? __dirname : import_node_path84.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75452
75569
  const mcpConfigs = [];
75453
75570
  const secretsBundleRoot = findSecretsBundleRoot(logger);
75454
- const localSecretsDir = import_node_path82.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75571
+ const localSecretsDir = import_node_path84.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75455
75572
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
75456
- const githubTokenFile = import_node_path82.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75573
+ const githubTokenFile = import_node_path84.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75457
75574
  const githubIdentity = createGithubIdentity({
75458
75575
  resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
75459
75576
  store: (token) => storeGithubAuth({
@@ -75491,22 +75608,22 @@ async function startDaemon(config) {
75491
75608
  void githubIdentity.refresh();
75492
75609
  return renderPersonaMcpSecrets({
75493
75610
  personaId: personaId2,
75494
- personaDir: import_node_path82.default.join(config.dataDir, "personas", personaId2),
75611
+ personaDir: import_node_path84.default.join(config.dataDir, "personas", personaId2),
75495
75612
  secrets,
75496
- outDir: import_node_path82.default.join(config.dataDir, "persona-mcp"),
75613
+ outDir: import_node_path84.default.join(config.dataDir, "persona-mcp"),
75497
75614
  logger
75498
75615
  });
75499
75616
  };
75500
75617
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
75501
75618
  const dispatchServerCandidates = [
75502
- import_node_path82.default.join(here, "dispatch", "mcp-server.cjs"),
75619
+ import_node_path84.default.join(here, "dispatch", "mcp-server.cjs"),
75503
75620
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
75504
- import_node_path82.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75621
+ import_node_path84.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75505
75622
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
75506
75623
  ];
75507
- const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75624
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75508
75625
  if (dispatchServerScriptPath) {
75509
- const dispatchLogPath = import_node_path82.default.join(logDir, "dispatch-mcp-server.log");
75626
+ const dispatchLogPath = import_node_path84.default.join(logDir, "dispatch-mcp-server.log");
75510
75627
  const dispatchCfgPath = writeDispatchMcpConfig({
75511
75628
  dataDir: config.dataDir,
75512
75629
  serverScriptPath: dispatchServerScriptPath,
@@ -75526,12 +75643,12 @@ async function startDaemon(config) {
75526
75643
  });
75527
75644
  }
75528
75645
  const ticketServerCandidates = [
75529
- import_node_path82.default.join(here, "ticket", "mcp-server.cjs"),
75530
- import_node_path82.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
75646
+ import_node_path84.default.join(here, "ticket", "mcp-server.cjs"),
75647
+ import_node_path84.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
75531
75648
  ];
75532
- const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75649
+ const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75533
75650
  if (ticketServerScriptPath) {
75534
- const ticketLogPath = import_node_path82.default.join(logDir, "ticket-mcp-server.log");
75651
+ const ticketLogPath = import_node_path84.default.join(logDir, "ticket-mcp-server.log");
75535
75652
  const ticketCfgPath = writeTicketMcpConfig({
75536
75653
  dataDir: config.dataDir,
75537
75654
  serverScriptPath: ticketServerScriptPath,
@@ -75553,12 +75670,12 @@ async function startDaemon(config) {
75553
75670
  });
75554
75671
  }
75555
75672
  const shiftServerCandidates = [
75556
- import_node_path82.default.join(here, "shift", "mcp-server.cjs"),
75557
- import_node_path82.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
75673
+ import_node_path84.default.join(here, "shift", "mcp-server.cjs"),
75674
+ import_node_path84.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
75558
75675
  ];
75559
- const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75676
+ const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75560
75677
  if (shiftServerScriptPath) {
75561
- const shiftLogPath = import_node_path82.default.join(logDir, "shift-mcp-server.log");
75678
+ const shiftLogPath = import_node_path84.default.join(logDir, "shift-mcp-server.log");
75562
75679
  const shiftCfgPath = await writeShiftMcpConfig({
75563
75680
  dataDir: config.dataDir,
75564
75681
  serverScriptPath: shiftServerScriptPath,
@@ -75579,12 +75696,12 @@ async function startDaemon(config) {
75579
75696
  );
75580
75697
  }
75581
75698
  const inboxServerCandidates = [
75582
- import_node_path82.default.join(here, "inbox", "mcp-server.cjs"),
75583
- import_node_path82.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
75699
+ import_node_path84.default.join(here, "inbox", "mcp-server.cjs"),
75700
+ import_node_path84.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
75584
75701
  ];
75585
- const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75702
+ const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75586
75703
  if (inboxServerScriptPath) {
75587
- const inboxLogPath = import_node_path82.default.join(logDir, "inbox-mcp-server.log");
75704
+ const inboxLogPath = import_node_path84.default.join(logDir, "inbox-mcp-server.log");
75588
75705
  const inboxCfgPath = await writeInboxMcpConfig({
75589
75706
  dataDir: config.dataDir,
75590
75707
  serverScriptPath: inboxServerScriptPath,
@@ -75605,10 +75722,10 @@ async function startDaemon(config) {
75605
75722
  );
75606
75723
  }
75607
75724
  const peerOpsServerCandidates = [
75608
- import_node_path82.default.join(here, "peer-ops", "mcp-server.cjs"),
75609
- import_node_path82.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
75725
+ import_node_path84.default.join(here, "peer-ops", "mcp-server.cjs"),
75726
+ import_node_path84.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
75610
75727
  ];
75611
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75728
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75612
75729
  if (peerOpsServerScriptPath) {
75613
75730
  const peerOpsCfgPath = writePeerOpsMcpConfig({
75614
75731
  dataDir: config.dataDir,
@@ -75628,12 +75745,12 @@ async function startDaemon(config) {
75628
75745
  );
75629
75746
  }
75630
75747
  const rpcToolServerCandidates = [
75631
- import_node_path82.default.join(here, "rpc-tool", "mcp-server.cjs"),
75632
- import_node_path82.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
75748
+ import_node_path84.default.join(here, "rpc-tool", "mcp-server.cjs"),
75749
+ import_node_path84.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
75633
75750
  ];
75634
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75751
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75635
75752
  if (rpcToolServerScriptPath) {
75636
- const rpcToolLogPath = import_node_path82.default.join(logDir, "rpc-tool-mcp-server.log");
75753
+ const rpcToolLogPath = import_node_path84.default.join(logDir, "rpc-tool-mcp-server.log");
75637
75754
  const rpcToolCfgPath = writeRpcToolMcpConfig({
75638
75755
  dataDir: config.dataDir,
75639
75756
  serverScriptPath: rpcToolServerScriptPath,
@@ -75654,7 +75771,7 @@ async function startDaemon(config) {
75654
75771
  );
75655
75772
  }
75656
75773
  const shiftStore = createShiftStore({
75657
- filePath: import_node_path82.default.join(config.dataDir, "shift.json"),
75774
+ filePath: import_node_path84.default.join(config.dataDir, "shift.json"),
75658
75775
  ownerIdProvider: () => ownerPrincipalId,
75659
75776
  now: () => Date.now()
75660
75777
  });
@@ -75676,7 +75793,7 @@ async function startDaemon(config) {
75676
75793
  getAdapter,
75677
75794
  historyReader: history,
75678
75795
  dataDir: config.dataDir,
75679
- personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75796
+ personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
75680
75797
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
75681
75798
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
75682
75799
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -75733,10 +75850,10 @@ async function startDaemon(config) {
75733
75850
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
75734
75851
  attachmentGroup: {
75735
75852
  onFileEdit: (input) => {
75736
- const absPath = import_node_path82.default.isAbsolute(input.relPath) ? input.relPath : import_node_path82.default.join(input.cwd, input.relPath);
75853
+ const absPath = import_node_path84.default.isAbsolute(input.relPath) ? input.relPath : import_node_path84.default.join(input.cwd, input.relPath);
75737
75854
  let size = 0;
75738
75855
  try {
75739
- size = import_node_fs64.default.statSync(absPath).size;
75856
+ size = import_node_fs65.default.statSync(absPath).size;
75740
75857
  } catch (err) {
75741
75858
  logger.warn("attachment.onFileEdit stat failed", {
75742
75859
  sessionId: input.sessionId,
@@ -75777,9 +75894,9 @@ async function startDaemon(config) {
75777
75894
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
75778
75895
  }
75779
75896
  const projectsStore = new ProjectsStore({
75780
- file: import_node_path82.default.join(config.dataDir, "projects.json"),
75897
+ file: import_node_path84.default.join(config.dataDir, "projects.json"),
75781
75898
  clawdDir: config.dataDir,
75782
- codexStateFile: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
75899
+ codexStateFile: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
75783
75900
  logger
75784
75901
  });
75785
75902
  const observer = new SessionObserver({
@@ -75844,13 +75961,13 @@ async function startDaemon(config) {
75844
75961
  logger
75845
75962
  });
75846
75963
  registerAdapter("claude", claudeAdapter);
75847
- const codexIsolatedHome = import_node_path82.default.join(config.dataDir, "codex-home");
75964
+ const codexIsolatedHome = import_node_path84.default.join(config.dataDir, "codex-home");
75848
75965
  try {
75849
- import_node_fs64.default.mkdirSync(codexIsolatedHome, { recursive: true });
75966
+ import_node_fs65.default.mkdirSync(codexIsolatedHome, { recursive: true });
75850
75967
  for (const f2 of ["auth.json", "config.toml"]) {
75851
- const link = import_node_path82.default.join(codexIsolatedHome, f2);
75852
- const target = import_node_path82.default.join(import_node_os31.default.homedir(), ".codex", f2);
75853
- if (!import_node_fs64.default.existsSync(link) && import_node_fs64.default.existsSync(target)) import_node_fs64.default.symlinkSync(target, link);
75968
+ const link = import_node_path84.default.join(codexIsolatedHome, f2);
75969
+ const target = import_node_path84.default.join(import_node_os31.default.homedir(), ".codex", f2);
75970
+ if (!import_node_fs65.default.existsSync(link) && import_node_fs65.default.existsSync(target)) import_node_fs65.default.symlinkSync(target, link);
75854
75971
  }
75855
75972
  } catch (err) {
75856
75973
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -75861,19 +75978,20 @@ async function startDaemon(config) {
75861
75978
  logger,
75862
75979
  historyReader: new CodexHistoryReader({
75863
75980
  roots: codexRolloutRoots(config.dataDir),
75864
- sharedHome: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex"),
75981
+ sharedHome: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex"),
75865
75982
  logger
75866
75983
  }),
75867
75984
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
75868
75985
  codexHomeFor: (cwd) => resolveCodexHome({
75869
75986
  cwd,
75870
- personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75987
+ personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
75871
75988
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
75872
75989
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
75873
75990
  projectPaths: projectsStore.listMerged().map((x2) => x2.path),
75874
- sharedHome: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex"),
75991
+ sharedHome: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex"),
75875
75992
  isolatedHome: codexIsolatedHome
75876
75993
  }),
75994
+ codexHomeForThread: (threadId) => locateCodexThread(codexRolloutRoots(config.dataDir), threadId)?.home,
75877
75995
  // 附件图片验签:与 http-router /files 路由同一把 secret
75878
75996
  getSignSecret: () => authFile.token
75879
75997
  })
@@ -75896,10 +76014,10 @@ async function startDaemon(config) {
75896
76014
  );
75897
76015
  registerAdapter(PI_CLOUD_TOOL_ID, new CloudPiAdapter({ client: cloudGateway, history: cloudHistorySource, logger }));
75898
76016
  const piMcpBridgeCandidates = [
75899
- import_node_path82.default.join(here, "pi-mcp-bridge", "extension.cjs"),
75900
- import_node_path82.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
76017
+ import_node_path84.default.join(here, "pi-mcp-bridge", "extension.cjs"),
76018
+ import_node_path84.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
75901
76019
  ];
75902
- const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
76020
+ const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75903
76021
  if (piMcpBridgePath) {
75904
76022
  logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
75905
76023
  } else {
@@ -76195,11 +76313,11 @@ async function startDaemon(config) {
76195
76313
  // 'persona/<pid>/owner',default 走 'default'。
76196
76314
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
76197
76315
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
76198
- personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
76316
+ personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
76199
76317
  usersRoot
76200
76318
  },
76201
76319
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
76202
- personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
76320
+ personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
76203
76321
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
76204
76322
  usersRoot,
76205
76323
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -76505,7 +76623,7 @@ async function startDaemon(config) {
76505
76623
  });
76506
76624
  shiftScheduler.start();
76507
76625
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
76508
- const larkBotStore = createLarkBotBindingStore(import_node_path82.default.join(config.dataDir, "personas"));
76626
+ const larkBotStore = createLarkBotBindingStore(import_node_path84.default.join(config.dataDir, "personas"));
76509
76627
  const larkBotCloud = createLarkBotCloudClient({
76510
76628
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
76511
76629
  getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
@@ -76517,7 +76635,7 @@ async function startDaemon(config) {
76517
76635
  store: larkBotStore,
76518
76636
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
76519
76637
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
76520
- mediaRootFor: (chatId) => import_node_path82.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
76638
+ mediaRootFor: (chatId) => import_node_path84.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
76521
76639
  isShuttingDown: () => larkDraining,
76522
76640
  logger: {
76523
76641
  warn: (msg) => logger.warn(msg),
@@ -76817,8 +76935,8 @@ async function startDaemon(config) {
76817
76935
  const lines = [
76818
76936
  `Tunnel: ${r2.url}`,
76819
76937
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
76820
- `Frpc config: ${import_node_path82.default.join(config.dataDir, "frpc.toml")}`,
76821
- `Frpc log: ${import_node_path82.default.join(logDir, "frpc.log")}`
76938
+ `Frpc config: ${import_node_path84.default.join(config.dataDir, "frpc.toml")}`,
76939
+ `Frpc log: ${import_node_path84.default.join(logDir, "frpc.log")}`
76822
76940
  ];
76823
76941
  const width2 = Math.max(...lines.map((l2) => l2.length));
76824
76942
  const bar = "\u2550".repeat(width2 + 4);
@@ -76831,8 +76949,8 @@ ${bar}
76831
76949
 
76832
76950
  `);
76833
76951
  try {
76834
- const connectPath = import_node_path82.default.join(config.dataDir, "connect.txt");
76835
- import_node_fs64.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
76952
+ const connectPath = import_node_path84.default.join(config.dataDir, "connect.txt");
76953
+ import_node_fs65.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
76836
76954
  } catch {
76837
76955
  }
76838
76956
  } catch (err) {
@@ -76930,9 +77048,9 @@ ${bar}
76930
77048
  };
76931
77049
  }
76932
77050
  function migrateDropPersonsDir(dataDir) {
76933
- const dir = import_node_path82.default.join(dataDir, "persons");
77051
+ const dir = import_node_path84.default.join(dataDir, "persons");
76934
77052
  try {
76935
- import_node_fs64.default.rmSync(dir, { recursive: true, force: true });
77053
+ import_node_fs65.default.rmSync(dir, { recursive: true, force: true });
76936
77054
  } catch {
76937
77055
  }
76938
77056
  }