@clawos-dev/clawd 0.2.612 → 0.2.613

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: path106, errorMaps, issueData } = params;
454
- const fullPath = [...path106, ...issueData.path || []];
453
+ const { data, path: path107, errorMaps, issueData } = params;
454
+ const fullPath = [...path107, ...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, path106, key) {
765
+ constructor(parent, value, path107, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path106;
769
+ this._path = path107;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -7968,11 +7968,12 @@ var init_persona_schemas = __esm({
7968
7968
  });
7969
7969
 
7970
7970
  // ../protocol/src/events.ts
7971
- var DAEMON_MODE_VALUES, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
7971
+ var DAEMON_MODE_VALUES, CLOUD_HISTORY_REFRESH_KIND, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
7972
7972
  var init_events = __esm({
7973
7973
  "../protocol/src/events.ts"() {
7974
7974
  "use strict";
7975
7975
  DAEMON_MODE_VALUES = ["sdk", "tui"];
7976
+ CLOUD_HISTORY_REFRESH_KIND = "cloud_history_refresh";
7976
7977
  SESSION_STATUS_VALUES = [
7977
7978
  "idle",
7978
7979
  "running",
@@ -8165,6 +8166,12 @@ var init_schemas = __esm({
8165
8166
  });
8166
8167
  SessionFileSchema = external_exports.object({
8167
8168
  sessionId: external_exports.string().min(1),
8169
+ /** New gateway execution identity after session:new; defaults to sessionId for the first execution. */
8170
+ cloudExecutionId: external_exports.string().min(1).optional(),
8171
+ /** Owner gateway session observed in ready; proves the remote Pod was opened. */
8172
+ cloudGatewaySessionId: external_exports.string().min(1).optional(),
8173
+ /** Persisted before sending so daemon restart can retry the same gateway command ID. */
8174
+ cloudPendingCommand: external_exports.object({ id: external_exports.string().min(1), text: external_exports.string(), prepared: external_exports.boolean().optional() }).optional(),
8168
8175
  cwd: external_exports.string().min(1),
8169
8176
  tool: external_exports.literal("claude").or(external_exports.string().min(1)).default("claude"),
8170
8177
  // 归一化 tool 侧 session id(CC = claude session uuid,Codex = codex 自己的 id)
@@ -10345,8 +10352,8 @@ var require_req = __commonJS({
10345
10352
  if (req.originalUrl) {
10346
10353
  _req.url = req.originalUrl;
10347
10354
  } else {
10348
- const path106 = req.path;
10349
- _req.url = typeof path106 === "string" ? path106 : req.url ? req.url.path || req.url : void 0;
10355
+ const path107 = req.path;
10356
+ _req.url = typeof path107 === "string" ? path107 : req.url ? req.url.path || req.url : void 0;
10350
10357
  }
10351
10358
  if (req.query) {
10352
10359
  _req.query = req.query;
@@ -10511,14 +10518,14 @@ var require_redact = __commonJS({
10511
10518
  }
10512
10519
  return obj;
10513
10520
  }
10514
- function parsePath(path106) {
10521
+ function parsePath(path107) {
10515
10522
  const parts = [];
10516
10523
  let current = "";
10517
10524
  let inBrackets = false;
10518
10525
  let inQuotes = false;
10519
10526
  let quoteChar = "";
10520
- for (let i2 = 0; i2 < path106.length; i2++) {
10521
- const char = path106[i2];
10527
+ for (let i2 = 0; i2 < path107.length; i2++) {
10528
+ const char = path107[i2];
10522
10529
  if (!inBrackets && char === ".") {
10523
10530
  if (current) {
10524
10531
  parts.push(current);
@@ -10649,10 +10656,10 @@ var require_redact = __commonJS({
10649
10656
  return current;
10650
10657
  }
10651
10658
  function redactPaths(obj, paths, censor, remove = false) {
10652
- for (const path106 of paths) {
10653
- const parts = parsePath(path106);
10659
+ for (const path107 of paths) {
10660
+ const parts = parsePath(path107);
10654
10661
  if (parts.includes("*")) {
10655
- redactWildcardPath(obj, parts, censor, path106, remove);
10662
+ redactWildcardPath(obj, parts, censor, path107, remove);
10656
10663
  } else {
10657
10664
  if (remove) {
10658
10665
  removeKey(obj, parts);
@@ -10737,8 +10744,8 @@ var require_redact = __commonJS({
10737
10744
  }
10738
10745
  } else {
10739
10746
  if (afterWildcard.includes("*")) {
10740
- const wrappedCensor = typeof censor === "function" ? (value, path106) => {
10741
- const fullPath = [...pathArray.slice(0, pathLength), ...path106];
10747
+ const wrappedCensor = typeof censor === "function" ? (value, path107) => {
10748
+ const fullPath = [...pathArray.slice(0, pathLength), ...path107];
10742
10749
  return censor(value, fullPath);
10743
10750
  } : censor;
10744
10751
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10773,8 +10780,8 @@ var require_redact = __commonJS({
10773
10780
  return null;
10774
10781
  }
10775
10782
  const pathStructure = /* @__PURE__ */ new Map();
10776
- for (const path106 of pathsToClone) {
10777
- const parts = parsePath(path106);
10783
+ for (const path107 of pathsToClone) {
10784
+ const parts = parsePath(path107);
10778
10785
  let current = pathStructure;
10779
10786
  for (let i2 = 0; i2 < parts.length; i2++) {
10780
10787
  const part = parts[i2];
@@ -10826,24 +10833,24 @@ var require_redact = __commonJS({
10826
10833
  }
10827
10834
  return cloneSelectively(obj, pathStructure);
10828
10835
  }
10829
- function validatePath(path106) {
10830
- if (typeof path106 !== "string") {
10836
+ function validatePath(path107) {
10837
+ if (typeof path107 !== "string") {
10831
10838
  throw new Error("Paths must be (non-empty) strings");
10832
10839
  }
10833
- if (path106 === "") {
10840
+ if (path107 === "") {
10834
10841
  throw new Error("Invalid redaction path ()");
10835
10842
  }
10836
- if (path106.includes("..")) {
10837
- throw new Error(`Invalid redaction path (${path106})`);
10843
+ if (path107.includes("..")) {
10844
+ throw new Error(`Invalid redaction path (${path107})`);
10838
10845
  }
10839
- if (path106.includes(",")) {
10840
- throw new Error(`Invalid redaction path (${path106})`);
10846
+ if (path107.includes(",")) {
10847
+ throw new Error(`Invalid redaction path (${path107})`);
10841
10848
  }
10842
10849
  let bracketCount = 0;
10843
10850
  let inQuotes = false;
10844
10851
  let quoteChar = "";
10845
- for (let i2 = 0; i2 < path106.length; i2++) {
10846
- const char = path106[i2];
10852
+ for (let i2 = 0; i2 < path107.length; i2++) {
10853
+ const char = path107[i2];
10847
10854
  if ((char === '"' || char === "'") && bracketCount > 0) {
10848
10855
  if (!inQuotes) {
10849
10856
  inQuotes = true;
@@ -10857,20 +10864,20 @@ var require_redact = __commonJS({
10857
10864
  } else if (char === "]" && !inQuotes) {
10858
10865
  bracketCount--;
10859
10866
  if (bracketCount < 0) {
10860
- throw new Error(`Invalid redaction path (${path106})`);
10867
+ throw new Error(`Invalid redaction path (${path107})`);
10861
10868
  }
10862
10869
  }
10863
10870
  }
10864
10871
  if (bracketCount !== 0) {
10865
- throw new Error(`Invalid redaction path (${path106})`);
10872
+ throw new Error(`Invalid redaction path (${path107})`);
10866
10873
  }
10867
10874
  }
10868
10875
  function validatePaths(paths) {
10869
10876
  if (!Array.isArray(paths)) {
10870
10877
  throw new TypeError("paths must be an array");
10871
10878
  }
10872
- for (const path106 of paths) {
10873
- validatePath(path106);
10879
+ for (const path107 of paths) {
10880
+ validatePath(path107);
10874
10881
  }
10875
10882
  }
10876
10883
  function slowRedact(options = {}) {
@@ -11038,8 +11045,8 @@ var require_redaction = __commonJS({
11038
11045
  if (shape[k3] === null) {
11039
11046
  o2[k3] = (value) => topCensor(value, [k3]);
11040
11047
  } else {
11041
- const wrappedCensor = typeof censor === "function" ? (value, path106) => {
11042
- return censor(value, [k3, ...path106]);
11048
+ const wrappedCensor = typeof censor === "function" ? (value, path107) => {
11049
+ return censor(value, [k3, ...path107]);
11043
11050
  } : censor;
11044
11051
  o2[k3] = Redact({
11045
11052
  paths: shape[k3],
@@ -11257,10 +11264,10 @@ var require_atomic_sleep = __commonJS({
11257
11264
  var require_sonic_boom = __commonJS({
11258
11265
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
11259
11266
  "use strict";
11260
- var fs95 = require("fs");
11267
+ var fs96 = require("fs");
11261
11268
  var EventEmitter2 = require("events");
11262
11269
  var inherits = require("util").inherits;
11263
- var path106 = require("path");
11270
+ var path107 = require("path");
11264
11271
  var sleep2 = require_atomic_sleep();
11265
11272
  var assert = require("assert");
11266
11273
  var BUSY_WRITE_TIMEOUT = 100;
@@ -11314,20 +11321,20 @@ var require_sonic_boom = __commonJS({
11314
11321
  const mode = sonic.mode;
11315
11322
  if (sonic.sync) {
11316
11323
  try {
11317
- if (sonic.mkdir) fs95.mkdirSync(path106.dirname(file), { recursive: true });
11318
- const fd = fs95.openSync(file, flags, mode);
11324
+ if (sonic.mkdir) fs96.mkdirSync(path107.dirname(file), { recursive: true });
11325
+ const fd = fs96.openSync(file, flags, mode);
11319
11326
  fileOpened(null, fd);
11320
11327
  } catch (err) {
11321
11328
  fileOpened(err);
11322
11329
  throw err;
11323
11330
  }
11324
11331
  } else if (sonic.mkdir) {
11325
- fs95.mkdir(path106.dirname(file), { recursive: true }, (err) => {
11332
+ fs96.mkdir(path107.dirname(file), { recursive: true }, (err) => {
11326
11333
  if (err) return fileOpened(err);
11327
- fs95.open(file, flags, mode, fileOpened);
11334
+ fs96.open(file, flags, mode, fileOpened);
11328
11335
  });
11329
11336
  } else {
11330
- fs95.open(file, flags, mode, fileOpened);
11337
+ fs96.open(file, flags, mode, fileOpened);
11331
11338
  }
11332
11339
  }
11333
11340
  function SonicBoom(opts) {
@@ -11368,8 +11375,8 @@ var require_sonic_boom = __commonJS({
11368
11375
  this.flush = flushBuffer;
11369
11376
  this.flushSync = flushBufferSync;
11370
11377
  this._actualWrite = actualWriteBuffer;
11371
- fsWriteSync = () => fs95.writeSync(this.fd, this._writingBuf);
11372
- fsWrite = () => fs95.write(this.fd, this._writingBuf, this.release);
11378
+ fsWriteSync = () => fs96.writeSync(this.fd, this._writingBuf);
11379
+ fsWrite = () => fs96.write(this.fd, this._writingBuf, this.release);
11373
11380
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
11374
11381
  this._writingBuf = "";
11375
11382
  this.write = write;
@@ -11378,15 +11385,15 @@ var require_sonic_boom = __commonJS({
11378
11385
  this._actualWrite = actualWrite;
11379
11386
  fsWriteSync = () => {
11380
11387
  if (Buffer.isBuffer(this._writingBuf)) {
11381
- return fs95.writeSync(this.fd, this._writingBuf);
11388
+ return fs96.writeSync(this.fd, this._writingBuf);
11382
11389
  }
11383
- return fs95.writeSync(this.fd, this._writingBuf, "utf8");
11390
+ return fs96.writeSync(this.fd, this._writingBuf, "utf8");
11384
11391
  };
11385
11392
  fsWrite = () => {
11386
11393
  if (Buffer.isBuffer(this._writingBuf)) {
11387
- return fs95.write(this.fd, this._writingBuf, this.release);
11394
+ return fs96.write(this.fd, this._writingBuf, this.release);
11388
11395
  }
11389
- return fs95.write(this.fd, this._writingBuf, "utf8", this.release);
11396
+ return fs96.write(this.fd, this._writingBuf, "utf8", this.release);
11390
11397
  };
11391
11398
  } else {
11392
11399
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -11443,7 +11450,7 @@ var require_sonic_boom = __commonJS({
11443
11450
  }
11444
11451
  }
11445
11452
  if (this._fsync) {
11446
- fs95.fsyncSync(this.fd);
11453
+ fs96.fsyncSync(this.fd);
11447
11454
  }
11448
11455
  const len = this._len;
11449
11456
  if (this._reopening) {
@@ -11557,7 +11564,7 @@ var require_sonic_boom = __commonJS({
11557
11564
  const onDrain = () => {
11558
11565
  if (!this._fsync) {
11559
11566
  try {
11560
- fs95.fsync(this.fd, (err) => {
11567
+ fs96.fsync(this.fd, (err) => {
11561
11568
  this._flushPending = false;
11562
11569
  cb(err);
11563
11570
  });
@@ -11659,7 +11666,7 @@ var require_sonic_boom = __commonJS({
11659
11666
  const fd = this.fd;
11660
11667
  this.once("ready", () => {
11661
11668
  if (fd !== this.fd) {
11662
- fs95.close(fd, (err) => {
11669
+ fs96.close(fd, (err) => {
11663
11670
  if (err) {
11664
11671
  return this.emit("error", err);
11665
11672
  }
@@ -11708,7 +11715,7 @@ var require_sonic_boom = __commonJS({
11708
11715
  buf = this._bufs[0];
11709
11716
  }
11710
11717
  try {
11711
- const n2 = Buffer.isBuffer(buf) ? fs95.writeSync(this.fd, buf) : fs95.writeSync(this.fd, buf, "utf8");
11718
+ const n2 = Buffer.isBuffer(buf) ? fs96.writeSync(this.fd, buf) : fs96.writeSync(this.fd, buf, "utf8");
11712
11719
  const releasedBufObj = releaseWritingBuf(buf, this._len, n2);
11713
11720
  buf = releasedBufObj.writingBuf;
11714
11721
  this._len = releasedBufObj.len;
@@ -11724,7 +11731,7 @@ var require_sonic_boom = __commonJS({
11724
11731
  }
11725
11732
  }
11726
11733
  try {
11727
- fs95.fsyncSync(this.fd);
11734
+ fs96.fsyncSync(this.fd);
11728
11735
  } catch {
11729
11736
  }
11730
11737
  }
@@ -11745,7 +11752,7 @@ var require_sonic_boom = __commonJS({
11745
11752
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11746
11753
  }
11747
11754
  try {
11748
- const n2 = fs95.writeSync(this.fd, buf);
11755
+ const n2 = fs96.writeSync(this.fd, buf);
11749
11756
  buf = buf.subarray(n2);
11750
11757
  this._len = Math.max(this._len - n2, 0);
11751
11758
  if (buf.length <= 0) {
@@ -11773,13 +11780,13 @@ var require_sonic_boom = __commonJS({
11773
11780
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11774
11781
  if (this.sync) {
11775
11782
  try {
11776
- const written = Buffer.isBuffer(this._writingBuf) ? fs95.writeSync(this.fd, this._writingBuf) : fs95.writeSync(this.fd, this._writingBuf, "utf8");
11783
+ const written = Buffer.isBuffer(this._writingBuf) ? fs96.writeSync(this.fd, this._writingBuf) : fs96.writeSync(this.fd, this._writingBuf, "utf8");
11777
11784
  release2(null, written);
11778
11785
  } catch (err) {
11779
11786
  release2(err);
11780
11787
  }
11781
11788
  } else {
11782
- fs95.write(this.fd, this._writingBuf, release2);
11789
+ fs96.write(this.fd, this._writingBuf, release2);
11783
11790
  }
11784
11791
  }
11785
11792
  function actualWriteBuffer() {
@@ -11788,7 +11795,7 @@ var require_sonic_boom = __commonJS({
11788
11795
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11789
11796
  if (this.sync) {
11790
11797
  try {
11791
- const written = fs95.writeSync(this.fd, this._writingBuf);
11798
+ const written = fs96.writeSync(this.fd, this._writingBuf);
11792
11799
  release2(null, written);
11793
11800
  } catch (err) {
11794
11801
  release2(err);
@@ -11797,7 +11804,7 @@ var require_sonic_boom = __commonJS({
11797
11804
  if (kCopyBuffer) {
11798
11805
  this._writingBuf = Buffer.from(this._writingBuf);
11799
11806
  }
11800
- fs95.write(this.fd, this._writingBuf, release2);
11807
+ fs96.write(this.fd, this._writingBuf, release2);
11801
11808
  }
11802
11809
  }
11803
11810
  function actualClose(sonic) {
@@ -11813,12 +11820,12 @@ var require_sonic_boom = __commonJS({
11813
11820
  sonic._lens = [];
11814
11821
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11815
11822
  try {
11816
- fs95.fsync(sonic.fd, closeWrapped);
11823
+ fs96.fsync(sonic.fd, closeWrapped);
11817
11824
  } catch {
11818
11825
  }
11819
11826
  function closeWrapped() {
11820
11827
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11821
- fs95.close(sonic.fd, done);
11828
+ fs96.close(sonic.fd, done);
11822
11829
  } else {
11823
11830
  done();
11824
11831
  }
@@ -14953,11 +14960,11 @@ var init_lib = __esm({
14953
14960
  }
14954
14961
  }
14955
14962
  },
14956
- addToPath: function addToPath(path106, added, removed, oldPosInc, options) {
14957
- var last = path106.lastComponent;
14963
+ addToPath: function addToPath(path107, added, removed, oldPosInc, options) {
14964
+ var last = path107.lastComponent;
14958
14965
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14959
14966
  return {
14960
- oldPos: path106.oldPos + oldPosInc,
14967
+ oldPos: path107.oldPos + oldPosInc,
14961
14968
  lastComponent: {
14962
14969
  count: last.count + 1,
14963
14970
  added,
@@ -14967,7 +14974,7 @@ var init_lib = __esm({
14967
14974
  };
14968
14975
  } else {
14969
14976
  return {
14970
- oldPos: path106.oldPos + oldPosInc,
14977
+ oldPos: path107.oldPos + oldPosInc,
14971
14978
  lastComponent: {
14972
14979
  count: 1,
14973
14980
  added,
@@ -15549,10 +15556,10 @@ function attachmentToHistoryMessage(o2, ts) {
15549
15556
  const memories = raw.map((m3) => {
15550
15557
  if (!m3 || typeof m3 !== "object") return null;
15551
15558
  const rec6 = m3;
15552
- const path106 = typeof rec6.path === "string" ? rec6.path : null;
15559
+ const path107 = typeof rec6.path === "string" ? rec6.path : null;
15553
15560
  const content = typeof rec6.content === "string" ? rec6.content : null;
15554
- if (!path106 || content == null) return null;
15555
- const entry = { path: path106, content };
15561
+ if (!path107 || content == null) return null;
15562
+ const entry = { path: path107, content };
15556
15563
  if (typeof rec6.mtimeMs === "number") entry.mtimeMs = rec6.mtimeMs;
15557
15564
  return entry;
15558
15565
  }).filter((m3) => m3 !== null);
@@ -16418,10 +16425,10 @@ function parseAttachment(obj) {
16418
16425
  const memories = raw.map((m3) => {
16419
16426
  if (!m3 || typeof m3 !== "object") return null;
16420
16427
  const rec6 = m3;
16421
- const path106 = typeof rec6.path === "string" ? rec6.path : null;
16428
+ const path107 = typeof rec6.path === "string" ? rec6.path : null;
16422
16429
  const content = typeof rec6.content === "string" ? rec6.content : null;
16423
- if (!path106 || content == null) return null;
16424
- const out = { path: path106, content };
16430
+ if (!path107 || content == null) return null;
16431
+ const out = { path: path107, content };
16425
16432
  if (typeof rec6.mtimeMs === "number") out.mtimeMs = rec6.mtimeMs;
16426
16433
  return out;
16427
16434
  }).filter((m3) => m3 !== null);
@@ -37395,8 +37402,8 @@ var require_utils = __commonJS({
37395
37402
  var result = transform[inputType][outputType](input);
37396
37403
  return result;
37397
37404
  };
37398
- exports2.resolve = function(path106) {
37399
- var parts = path106.split("/");
37405
+ exports2.resolve = function(path107) {
37406
+ var parts = path107.split("/");
37400
37407
  var result = [];
37401
37408
  for (var index = 0; index < parts.length; index++) {
37402
37409
  var part = parts[index];
@@ -43249,18 +43256,18 @@ var require_object = __commonJS({
43249
43256
  var object = new ZipObject(name, zipObjectContent, o2);
43250
43257
  this.files[name] = object;
43251
43258
  };
43252
- var parentFolder = function(path106) {
43253
- if (path106.slice(-1) === "/") {
43254
- path106 = path106.substring(0, path106.length - 1);
43259
+ var parentFolder = function(path107) {
43260
+ if (path107.slice(-1) === "/") {
43261
+ path107 = path107.substring(0, path107.length - 1);
43255
43262
  }
43256
- var lastSlash = path106.lastIndexOf("/");
43257
- return lastSlash > 0 ? path106.substring(0, lastSlash) : "";
43263
+ var lastSlash = path107.lastIndexOf("/");
43264
+ return lastSlash > 0 ? path107.substring(0, lastSlash) : "";
43258
43265
  };
43259
- var forceTrailingSlash = function(path106) {
43260
- if (path106.slice(-1) !== "/") {
43261
- path106 += "/";
43266
+ var forceTrailingSlash = function(path107) {
43267
+ if (path107.slice(-1) !== "/") {
43268
+ path107 += "/";
43262
43269
  }
43263
- return path106;
43270
+ return path107;
43264
43271
  };
43265
43272
  var folderAdd = function(name, createFolders) {
43266
43273
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -44262,7 +44269,7 @@ var require_lib3 = __commonJS({
44262
44269
  // src/run-case/recorder.ts
44263
44270
  function startRunCaseRecorder(opts) {
44264
44271
  const now = opts.now ?? Date.now;
44265
- const dir = import_node_path85.default.dirname(opts.recordPath);
44272
+ const dir = import_node_path86.default.dirname(opts.recordPath);
44266
44273
  let stream = null;
44267
44274
  let closing = false;
44268
44275
  let closedSettled = false;
@@ -44276,8 +44283,8 @@ function startRunCaseRecorder(opts) {
44276
44283
  });
44277
44284
  const ensureStream = () => {
44278
44285
  if (stream) return stream;
44279
- import_node_fs66.default.mkdirSync(dir, { recursive: true });
44280
- stream = import_node_fs66.default.createWriteStream(opts.recordPath, { flags: "a" });
44286
+ import_node_fs67.default.mkdirSync(dir, { recursive: true });
44287
+ stream = import_node_fs67.default.createWriteStream(opts.recordPath, { flags: "a" });
44281
44288
  stream.on("close", () => closedResolve());
44282
44289
  return stream;
44283
44290
  };
@@ -44302,12 +44309,12 @@ function startRunCaseRecorder(opts) {
44302
44309
  };
44303
44310
  return { tap, close, closed };
44304
44311
  }
44305
- var import_node_fs66, import_node_path85;
44312
+ var import_node_fs67, import_node_path86;
44306
44313
  var init_recorder = __esm({
44307
44314
  "src/run-case/recorder.ts"() {
44308
44315
  "use strict";
44309
- import_node_fs66 = __toESM(require("fs"), 1);
44310
- import_node_path85 = __toESM(require("path"), 1);
44316
+ import_node_fs67 = __toESM(require("fs"), 1);
44317
+ import_node_path86 = __toESM(require("path"), 1);
44311
44318
  }
44312
44319
  });
44313
44320
 
@@ -44350,7 +44357,7 @@ var init_wire = __esm({
44350
44357
  // src/run-case/controller.ts
44351
44358
  async function runController(opts) {
44352
44359
  const now = opts.now ?? Date.now;
44353
- const cwd = opts.cwd ?? (0, import_node_fs67.mkdtempSync)(import_node_path86.default.join(import_node_os32.default.tmpdir(), "clawd-runcase-"));
44360
+ const cwd = opts.cwd ?? (0, import_node_fs68.mkdtempSync)(import_node_path87.default.join(import_node_os32.default.tmpdir(), "clawd-runcase-"));
44354
44361
  const ownsCwd = opts.cwd === void 0;
44355
44362
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
44356
44363
  const spawnCtx = { cwd };
@@ -44511,19 +44518,19 @@ async function runController(opts) {
44511
44518
  if (sigintHandler) process.off("SIGINT", sigintHandler);
44512
44519
  if (ownsCwd) {
44513
44520
  try {
44514
- (0, import_node_fs67.rmSync)(cwd, { recursive: true, force: true });
44521
+ (0, import_node_fs68.rmSync)(cwd, { recursive: true, force: true });
44515
44522
  } catch {
44516
44523
  }
44517
44524
  }
44518
44525
  return exitCode ?? 0;
44519
44526
  }
44520
- var import_node_fs67, import_node_os32, import_node_path86;
44527
+ var import_node_fs68, import_node_os32, import_node_path87;
44521
44528
  var init_controller = __esm({
44522
44529
  "src/run-case/controller.ts"() {
44523
44530
  "use strict";
44524
- import_node_fs67 = require("fs");
44531
+ import_node_fs68 = require("fs");
44525
44532
  import_node_os32 = __toESM(require("os"), 1);
44526
- import_node_path86 = __toESM(require("path"), 1);
44533
+ import_node_path87 = __toESM(require("path"), 1);
44527
44534
  init_claude();
44528
44535
  init_stdout_splitter();
44529
44536
  init_permission_stdio();
@@ -44795,10 +44802,10 @@ Env (advanced):
44795
44802
  `;
44796
44803
 
44797
44804
  // src/index.ts
44798
- var import_node_path84 = __toESM(require("path"), 1);
44799
- var import_node_fs65 = __toESM(require("fs"), 1);
44805
+ var import_node_path85 = __toESM(require("path"), 1);
44806
+ var import_node_fs66 = __toESM(require("fs"), 1);
44800
44807
  var import_node_os31 = __toESM(require("os"), 1);
44801
- var import_node_crypto27 = require("crypto");
44808
+ var import_node_crypto28 = require("crypto");
44802
44809
  var import_node_url6 = require("url");
44803
44810
 
44804
44811
  // src/logger.ts
@@ -45951,9 +45958,8 @@ function cloneState(s2) {
45951
45958
  currentTurnSender: s2.currentTurnSender
45952
45959
  };
45953
45960
  }
45954
- var CLOUD_IDLE_KILL_DELAY_MS = 5 * 6e4;
45955
45961
  function idleKillDelayOf(state) {
45956
- if (isCloudTool(state.file.tool)) return CLOUD_IDLE_KILL_DELAY_MS;
45962
+ if (isCloudTool(state.file.tool)) return void 0;
45957
45963
  const ms = state.subSessionMeta?.idleKillDelayMs;
45958
45964
  return ms !== void 0 && ms > 0 ? ms : void 0;
45959
45965
  }
@@ -46113,6 +46119,8 @@ function buildSpawnContext(state, deps) {
46113
46119
  const mcpConfigs = deps.getMcpConfigs?.() ?? [];
46114
46120
  const ctx = {
46115
46121
  cwd: file.cwd,
46122
+ cloudExecutionId: file.cloudExecutionId,
46123
+ cloudGatewaySessionId: file.cloudGatewaySessionId,
46116
46124
  toolSessionId: file.toolSessionId,
46117
46125
  model: file.model,
46118
46126
  permissionMode: file.permissionMode,
@@ -46367,7 +46375,11 @@ function pushEventToBufferInPlace(next, event, deps) {
46367
46375
  }
46368
46376
  }
46369
46377
  if (isUserText || isTurnEnd) {
46370
- next.file = { ...next.file, updatedAt: nowIso(deps) };
46378
+ next.file = {
46379
+ ...next.file,
46380
+ updatedAt: nowIso(deps),
46381
+ ...isCloudTool(next.file.tool) && next.status !== "error" && !(withSeq.kind === "turn_end" && withSeq.reason === "interrupted") ? { cloudPendingCommand: withSeq.kind === "user_text" ? { id: withSeq.uuid ?? `${next.file.sessionId}-${seq}`, text: withSeq.text } : void 0 } : {}
46382
+ };
46371
46383
  effects.push({ kind: "persist-file", file: next.file });
46372
46384
  effects.push(sessionInfoFrame(next.file));
46373
46385
  }
@@ -46483,6 +46495,10 @@ function applyCommand(state, command, deps) {
46483
46495
  return { state: next, effects };
46484
46496
  }
46485
46497
  case "stop": {
46498
+ if (isCloudTool(next.file.tool) && next.file.cloudPendingCommand) {
46499
+ next.file = { ...next.file, cloudPendingCommand: void 0 };
46500
+ effects.push({ kind: "persist-file", file: next.file }, sessionInfoFrame(next.file));
46501
+ }
46486
46502
  for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
46487
46503
  effects.push({
46488
46504
  kind: "emit-frame",
@@ -46616,6 +46632,8 @@ function applyCommand(state, command, deps) {
46616
46632
  case "new": {
46617
46633
  const {
46618
46634
  toolSessionId: _drop,
46635
+ cloudPendingCommand: _cloudPendingCommand,
46636
+ cloudGatewaySessionId: _cloudGatewaySessionId,
46619
46637
  contextUsage: _ctx,
46620
46638
  contextWindowSize: _win,
46621
46639
  gitBranch: _branch,
@@ -46626,6 +46644,8 @@ function applyCommand(state, command, deps) {
46626
46644
  ...rest
46627
46645
  } = next.file;
46628
46646
  void _drop;
46647
+ void _cloudPendingCommand;
46648
+ void _cloudGatewaySessionId;
46629
46649
  void _ctx;
46630
46650
  void _win;
46631
46651
  void _branch;
@@ -46634,6 +46654,7 @@ function applyCommand(state, command, deps) {
46634
46654
  void _titleGeneratedAt;
46635
46655
  const nextFile = {
46636
46656
  ...rest,
46657
+ ...command.nextCloudExecutionId ? { cloudExecutionId: command.nextCloudExecutionId } : {},
46637
46658
  ...command.nextToolSessionId ? { toolSessionId: command.nextToolSessionId } : {},
46638
46659
  updatedAt: nowIso(deps)
46639
46660
  };
@@ -46696,9 +46717,31 @@ function reduceSessionInner(state, input, deps) {
46696
46717
  case "inject-events": {
46697
46718
  return applyEventBatch(state, input.events, deps);
46698
46719
  }
46720
+ case "cloud-recovery-absent": {
46721
+ if (!state.file.cloudPendingCommand) return { state, effects: [] };
46722
+ const next = cloneState(state);
46723
+ next.file = { ...next.file, cloudPendingCommand: void 0, cloudGatewaySessionId: void 0 };
46724
+ return { state: next, effects: [{ kind: "persist-file", file: next.file }, sessionInfoFrame(next.file)] };
46725
+ }
46726
+ case "cloud-gateway-ready": {
46727
+ if (state.file.cloudGatewaySessionId === input.gatewaySessionId) return { state, effects: [] };
46728
+ const next = cloneState(state);
46729
+ next.file = { ...next.file, cloudGatewaySessionId: input.gatewaySessionId };
46730
+ return { state: next, effects: [{ kind: "persist-file", file: next.file }] };
46731
+ }
46732
+ case "cloud-command-prepared": {
46733
+ const pending = state.file.cloudPendingCommand;
46734
+ if (!pending || pending.id !== input.commandId) return { state, effects: [] };
46735
+ const next = cloneState(state);
46736
+ next.file = { ...next.file, cloudPendingCommand: { id: pending.id, text: input.text, prepared: true } };
46737
+ return { state: next, effects: [{ kind: "persist-file", file: next.file }] };
46738
+ }
46699
46739
  case "proc-exit": {
46700
46740
  const next = cloneState(state);
46701
46741
  next.procAlive = false;
46742
+ if (isCloudTool(next.file.tool) && !next.file.cloudPendingCommand && next.file.cloudGatewaySessionId) {
46743
+ next.file = { ...next.file, cloudGatewaySessionId: void 0 };
46744
+ }
46702
46745
  next.status = "stopped";
46703
46746
  next.stdinClosed = false;
46704
46747
  next.pendingBgTasks = [];
@@ -46721,6 +46764,7 @@ function reduceSessionInner(state, input, deps) {
46721
46764
  return {
46722
46765
  state: next,
46723
46766
  effects: [
46767
+ ...isCloudTool(state.file.tool) && state.file.cloudGatewaySessionId && !next.file.cloudGatewaySessionId ? [{ kind: "persist-file", file: next.file }] : [],
46724
46768
  ...interruptEffects,
46725
46769
  {
46726
46770
  kind: "emit-frame",
@@ -46867,6 +46911,7 @@ function reduceSessionInner(state, input, deps) {
46867
46911
  };
46868
46912
  }
46869
46913
  case "idle-kill-fired": {
46914
+ if (isCloudTool(state.file.tool)) return { state, effects: [] };
46870
46915
  if (state.status !== "running-idle") {
46871
46916
  return { state, effects: [] };
46872
46917
  }
@@ -46939,6 +46984,7 @@ function reduceSessionInner(state, input, deps) {
46939
46984
  // src/session/runner.ts
46940
46985
  init_stdout_splitter();
46941
46986
  init_permission_stdio();
46987
+ init_protocol();
46942
46988
  init_claude_history();
46943
46989
 
46944
46990
  // src/tools/spawn-error.ts
@@ -47116,6 +47162,7 @@ var SessionRunner = class {
47116
47162
  this.state = initial;
47117
47163
  }
47118
47164
  hooks;
47165
+ recoveringCloud = false;
47119
47166
  state;
47120
47167
  proc = null;
47121
47168
  // JSON-RPC 类 agent(codex app-server) 的 per-session 驱动器;非 null 时 runner 不用 spawn()/ChildProcess,
@@ -47189,6 +47236,17 @@ var SessionRunner = class {
47189
47236
  for (const w3 of waiters) w3();
47190
47237
  }
47191
47238
  }
47239
+ recoverCloud() {
47240
+ if (this.state.procAlive) return;
47241
+ this.recoveringCloud = true;
47242
+ try {
47243
+ this.input({ kind: "command", command: { kind: "spawn-if-needed" } });
47244
+ const pending = this.state.file.cloudPendingCommand;
47245
+ if (pending) this.session?.startTurn(pending.text, pending.id, pending.prepared === true);
47246
+ } finally {
47247
+ this.recoveringCloud = false;
47248
+ }
47249
+ }
47192
47250
  // 等子进程退出(procAlive=false)。manager.stop 在发完 SIGTERM 后调它确保
47193
47251
  // 真停下来再 ack 给前端,从而避免"删 worktree 时 CC 还活着持有文件锁"的 race。
47194
47252
  // 已经停止则立即 resolve;超时(默认 3000ms)抛错由上层透传成 RPC error
@@ -47239,6 +47297,15 @@ var SessionRunner = class {
47239
47297
  }
47240
47298
  await this.sendControlRequest("interrupt");
47241
47299
  }
47300
+ /** Daemon shutdown releases only the local cloud subscription. */
47301
+ detachCloud() {
47302
+ this.session?.detach?.();
47303
+ }
47304
+ /** Explicit cancellation has been acknowledged; close the local runner state. */
47305
+ confirmCloudCancelled() {
47306
+ this.detachCloud();
47307
+ if (this.state.procAlive) this.input({ kind: "proc-exit", code: null });
47308
+ }
47242
47309
  /**
47243
47310
  * file-sharing tool_use ↔ tool_result 配对(spec §6 PR 3)。
47244
47311
  *
@@ -47359,7 +47426,7 @@ var SessionRunner = class {
47359
47426
  applyEffect(effect) {
47360
47427
  switch (effect.kind) {
47361
47428
  case "spawn":
47362
- this.doSpawn(effect.ctx);
47429
+ this.doSpawn(this.recoveringCloud && effect.ctx.cloudGatewaySessionId ? { ...effect.ctx, cloudAttachOnly: true } : effect.ctx);
47363
47430
  break;
47364
47431
  case "kill":
47365
47432
  if (this.session) {
@@ -47373,7 +47440,7 @@ var SessionRunner = class {
47373
47440
  break;
47374
47441
  case "write-stdin":
47375
47442
  if (this.session) {
47376
- this.session.startTurn(effect.payload);
47443
+ this.session.startTurn(effect.payload, this.state.file.cloudPendingCommand?.id);
47377
47444
  break;
47378
47445
  }
47379
47446
  this.hooks.logger?.debug("[RG] write-stdin", {
@@ -47501,7 +47568,31 @@ var SessionRunner = class {
47501
47568
  this.clearIdleKillTimers();
47502
47569
  this.input({ kind: "proc-exit", code });
47503
47570
  },
47504
- onError: (message) => this.input({ kind: "proc-error", message })
47571
+ onError: (message) => this.input({ kind: "proc-error", message }),
47572
+ onHistoryGap: (synchronized) => this.hooks.broadcastFrame({
47573
+ type: "session:control",
47574
+ sessionId: this.state.file.sessionId,
47575
+ kind: CLOUD_HISTORY_REFRESH_KIND,
47576
+ synchronized
47577
+ }, "broadcast"),
47578
+ onRecoveryAbsent: () => {
47579
+ this.input({ kind: "cloud-recovery-absent" });
47580
+ this.hooks.broadcastFrame({ type: "session:control", sessionId: this.state.file.sessionId, kind: CLOUD_HISTORY_REFRESH_KIND, synchronized: true }, "broadcast");
47581
+ },
47582
+ onGatewayReady: (gatewaySessionId) => {
47583
+ if (this.state.file.cloudGatewaySessionId === gatewaySessionId) return;
47584
+ this.hooks.store.write({ ...this.state.file, cloudGatewaySessionId: gatewaySessionId });
47585
+ this.input({ kind: "cloud-gateway-ready", gatewaySessionId });
47586
+ },
47587
+ onCommandPrepared: (commandId, text, prepared) => {
47588
+ const pending = this.state.file.cloudPendingCommand;
47589
+ if (!pending || pending.id !== commandId || prepared && pending.text !== text) return false;
47590
+ if (!prepared) {
47591
+ this.hooks.store.write({ ...this.state.file, cloudPendingCommand: { id: commandId, text, prepared: true } });
47592
+ this.input({ kind: "cloud-command-prepared", commandId, text });
47593
+ }
47594
+ return true;
47595
+ }
47505
47596
  });
47506
47597
  return;
47507
47598
  }
@@ -47695,6 +47786,10 @@ var SessionManager = class {
47695
47786
  this.deps = deps;
47696
47787
  }
47697
47788
  deps;
47789
+ cloudCancel = null;
47790
+ setCloudCanceller(cancel) {
47791
+ this.cloudCancel = cancel;
47792
+ }
47698
47793
  // sessionId → SessionRunner;在 send / ensureSession 时按需创建
47699
47794
  runners = /* @__PURE__ */ new Map();
47700
47795
  // 标题生成 in-flight 防重(进程内);跨重启防重靠 SessionFile.aiLabelGeneratedAt
@@ -48562,6 +48657,19 @@ var SessionManager = class {
48562
48657
  ]
48563
48658
  };
48564
48659
  }
48660
+ async deleteWithCloudCancel(args) {
48661
+ const file = this.findOwnedSession(args.sessionId);
48662
+ if (!file) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
48663
+ const runner = this.runners.get(args.sessionId) ?? null;
48664
+ if (isCloudTool(file.tool)) {
48665
+ if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
48666
+ else if (file.cloudPendingCommand || runner?.getState().procAlive) {
48667
+ if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
48668
+ await this.cloudCancel(file, runner);
48669
+ }
48670
+ }
48671
+ return this.delete(args);
48672
+ }
48565
48673
  send(args, senderPrincipal) {
48566
48674
  const existing = this.getFile(args.sessionId);
48567
48675
  let runner = this.runners.get(args.sessionId);
@@ -48725,8 +48833,19 @@ var SessionManager = class {
48725
48833
  // 极端 OS 异常时才会用上。这样修掉了"前端 sessionStop 还没等 CC 退就去删 worktree
48726
48834
  // 撞文件锁"的 race,同时也覆盖 CC streaming hang / 幽灵进程这类 SIGTERM 杀不动的 case
48727
48835
  async stop(args) {
48836
+ const file = this.findOwnedSession(args.sessionId);
48728
48837
  const runner = this.runners.get(args.sessionId);
48729
- if (!runner) return { response: { ok: true }, broadcast: [] };
48838
+ if (file && isCloudTool(file.tool)) {
48839
+ if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
48840
+ else if (file.cloudPendingCommand || runner?.getState().procAlive) {
48841
+ if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
48842
+ await this.cloudCancel(file, runner ?? null);
48843
+ }
48844
+ }
48845
+ if (!runner) {
48846
+ if (file && isCloudTool(file.tool) && file.cloudPendingCommand) this.writeOwned({ ...file, cloudPendingCommand: void 0 });
48847
+ return { response: { ok: true }, broadcast: [] };
48848
+ }
48730
48849
  this.clearPendingTurnEnd(args.sessionId);
48731
48850
  const { broadcast } = this.withCollector(() => {
48732
48851
  runner.input({ kind: "command", command: { kind: "stop" } });
@@ -48868,7 +48987,7 @@ var SessionManager = class {
48868
48987
  }
48869
48988
  return { response: normalized, broadcast };
48870
48989
  }
48871
- newSession(args) {
48990
+ newSession(args, nextCloudExecutionId) {
48872
48991
  const existingFile = this.getFile(args.sessionId);
48873
48992
  this.titleGenPending.get(args.sessionId)?.abort();
48874
48993
  this.titleGenPending.delete(args.sessionId);
@@ -48879,7 +48998,7 @@ var SessionManager = class {
48879
48998
  const { value, broadcast } = this.withCollector(() => {
48880
48999
  runner.input({
48881
49000
  kind: "command",
48882
- command: { kind: "new", ...nextToolSessionId ? { nextToolSessionId } : {} }
49001
+ command: { kind: "new", ...nextToolSessionId ? { nextToolSessionId } : {}, ...nextCloudExecutionId ? { nextCloudExecutionId } : {} }
48883
49002
  });
48884
49003
  return runner.getState().file;
48885
49004
  });
@@ -48888,6 +49007,8 @@ var SessionManager = class {
48888
49007
  const existing = this.findOwnedSession(args.sessionId);
48889
49008
  const {
48890
49009
  toolSessionId: _drop,
49010
+ cloudPendingCommand: _cloudPendingCommand,
49011
+ cloudGatewaySessionId: _cloudGatewaySessionId,
48891
49012
  contextUsage: _ctx,
48892
49013
  contextWindowSize: _win,
48893
49014
  gitBranch: _branch,
@@ -48897,6 +49018,8 @@ var SessionManager = class {
48897
49018
  ...rest
48898
49019
  } = existing;
48899
49020
  void _drop;
49021
+ void _cloudPendingCommand;
49022
+ void _cloudGatewaySessionId;
48900
49023
  void _ctx;
48901
49024
  void _win;
48902
49025
  void _branch;
@@ -48905,11 +49028,25 @@ var SessionManager = class {
48905
49028
  void _titleGeneratedAt;
48906
49029
  const updated = {
48907
49030
  ...rest,
49031
+ ...nextCloudExecutionId ? { cloudExecutionId: nextCloudExecutionId } : {},
48908
49032
  ...nextToolSessionId ? { toolSessionId: nextToolSessionId } : {},
48909
49033
  updatedAt: nowIso2(this.deps)
48910
49034
  };
48911
49035
  return { response: this.writeOwned(updated), broadcast: [] };
48912
49036
  }
49037
+ async newSessionWithCloudCancel(args) {
49038
+ const file = this.getFile(args.sessionId);
49039
+ if (isCloudTool(file.tool)) {
49040
+ const runner = this.runners.get(args.sessionId) ?? null;
49041
+ if (!file.cloudGatewaySessionId) runner?.confirmCloudCancelled();
49042
+ else if (file.cloudPendingCommand || runner?.getState().procAlive) {
49043
+ if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
49044
+ await this.cloudCancel(file, runner);
49045
+ }
49046
+ return this.newSession(args, (0, import_node_crypto3.randomUUID)());
49047
+ }
49048
+ return this.newSession(args);
49049
+ }
48913
49050
  resume(args) {
48914
49051
  this.getFile(args.sessionId);
48915
49052
  const runner = this.runners.get(args.sessionId);
@@ -48974,11 +49111,20 @@ var SessionManager = class {
48974
49111
  }
48975
49112
  return { runningSessions: running };
48976
49113
  }
49114
+ /** Reattach only to executions whose last turn lacks a durable end marker. */
49115
+ recoverCloudSessions() {
49116
+ for (const file of this.listAllOwned()) {
49117
+ if (!isCloudTool(file.tool) || !file.cloudPendingCommand) continue;
49118
+ const runner = this.ensureSession(file);
49119
+ runner.recoverCloud();
49120
+ }
49121
+ }
48977
49122
  stopAll() {
48978
49123
  for (const controller of this.titleGenPending.values()) controller.abort();
48979
49124
  this.titleGenPending.clear();
48980
49125
  for (const r2 of this.runners.values()) {
48981
- r2.input({ kind: "command", command: { kind: "stop" } });
49126
+ if (isCloudTool(r2.getState().file.tool)) r2.detachCloud();
49127
+ else r2.input({ kind: "command", command: { kind: "stop" } });
48982
49128
  }
48983
49129
  this.pendingTurnDurationSignals.clear();
48984
49130
  }
@@ -52752,9 +52898,9 @@ var CentralClientError = class extends Error {
52752
52898
  cause;
52753
52899
  status;
52754
52900
  };
52755
- async function centralRequest(opts, path106, init) {
52901
+ async function centralRequest(opts, path107, init) {
52756
52902
  const f2 = opts.fetchImpl ?? globalThis.fetch;
52757
- const url = `${opts.api.replace(/\/+$/, "")}${path106}`;
52903
+ const url = `${opts.api.replace(/\/+$/, "")}${path107}`;
52758
52904
  const ctrl = new AbortController();
52759
52905
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
52760
52906
  let res;
@@ -53790,8 +53936,8 @@ function turnStartInput(text, resolveImage) {
53790
53936
  const items = [];
53791
53937
  let leftover = text;
53792
53938
  for (const m3 of text.matchAll(SKILL_RE)) {
53793
- const [marker, name, path106] = m3;
53794
- items.push({ type: "skill", name, path: path106 });
53939
+ const [marker, name, path107] = m3;
53940
+ items.push({ type: "skill", name, path: path107 });
53795
53941
  leftover = leftover.replace(marker, "");
53796
53942
  }
53797
53943
  for (const m3 of text.matchAll(ATTACHMENT_RE2)) {
@@ -61166,10 +61312,10 @@ function createGithubApi(args) {
61166
61312
  const doFetch = args.fetch ?? fetch;
61167
61313
  const seal = args.seal ?? sealWithSodium;
61168
61314
  const timeoutMs = args.timeoutMs ?? TIMEOUT_MS;
61169
- async function request(method, path106, body) {
61315
+ async function request(method, path107, body) {
61170
61316
  let res;
61171
61317
  try {
61172
- res = await doFetch(`${API}${path106}`, {
61318
+ res = await doFetch(`${API}${path107}`, {
61173
61319
  method,
61174
61320
  headers: {
61175
61321
  Authorization: `Bearer ${args.token}`,
@@ -61194,8 +61340,8 @@ function createGithubApi(args) {
61194
61340
  }
61195
61341
  return { status: res.status, json };
61196
61342
  }
61197
- async function must(method, path106, what, body) {
61198
- const r2 = await request(method, path106, body);
61343
+ async function must(method, path107, what, body) {
61344
+ const r2 = await request(method, path107, body);
61199
61345
  if (r2.status < 200 || r2.status >= 300) throw new GithubApiError(r2.status, explain(r2.status, what, r2.json));
61200
61346
  return r2.json;
61201
61347
  }
@@ -61240,9 +61386,9 @@ function createGithubApi(args) {
61240
61386
  return { env: x2.name, ...Number.isFinite(at3) ? { setAt: at3 } : {} };
61241
61387
  });
61242
61388
  },
61243
- async getJson(path106) {
61389
+ async getJson(path107) {
61244
61390
  try {
61245
- const r2 = await request("GET", path106);
61391
+ const r2 = await request("GET", path107);
61246
61392
  return r2.status >= 200 && r2.status < 300 ? r2.json : void 0;
61247
61393
  } catch {
61248
61394
  return void 0;
@@ -62794,8 +62940,8 @@ function refreshPathFromLoginShell() {
62794
62940
  timeout: 3e3,
62795
62941
  stdio: ["ignore", "pipe", "ignore"]
62796
62942
  });
62797
- const path106 = out.trim();
62798
- if (path106) process.env.PATH = path106;
62943
+ const path107 = out.trim();
62944
+ if (path107) process.env.PATH = path107;
62799
62945
  } catch {
62800
62946
  }
62801
62947
  }
@@ -63597,10 +63743,10 @@ function createCloudPersonaBotClient(opts) {
63597
63743
  const f2 = opts.fetchImpl ?? fetch;
63598
63744
  const base = opts.api.replace(/\/+$/, "");
63599
63745
  const route = (personaId2) => `/api/lark-bot/cloud/${encodeURIComponent(personaId2)}`;
63600
- async function request(method, path106, body) {
63746
+ async function request(method, path107, body) {
63601
63747
  const pass = opts.getLoginPass();
63602
63748
  if (!pass) throw new LarkBotCloudError("\u98DE\u4E66\u767B\u5F55\u540E\u624D\u80FD\u7BA1\u7406\u4E91 Persona \u7684 Bot", 401);
63603
- const response = await f2(base + path106, {
63749
+ const response = await f2(base + path107, {
63604
63750
  method,
63605
63751
  headers: { authorization: `Bearer ${pass}`, "content-type": "application/json" },
63606
63752
  ...body ? { body: JSON.stringify(body) } : {},
@@ -63609,7 +63755,7 @@ function createCloudPersonaBotClient(opts) {
63609
63755
  const json = await response.json().catch(() => ({}));
63610
63756
  if (!response.ok) {
63611
63757
  const detail = typeof json.message === "string" ? json.message : `HTTP ${response.status}`;
63612
- throw new LarkBotCloudError(`cloud bot ${method} ${path106}: ${detail}`, response.status);
63758
+ throw new LarkBotCloudError(`cloud bot ${method} ${path107}: ${detail}`, response.status);
63613
63759
  }
63614
63760
  return json;
63615
63761
  }
@@ -64603,6 +64749,7 @@ var GATEWAY_ROUTES = {
64603
64749
  sessionSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}`,
64604
64750
  sessionMirror: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}/mirror`,
64605
64751
  eventSession: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events`,
64752
+ eventCancel: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events:cancel`,
64606
64753
  eventSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/events/${encodeURIComponent(sessionId)}`,
64607
64754
  // 调用方自己那块盘的用量(design 2026-09-19-cloud-volume-usage §3.3):同样按人、不挂 persona
64608
64755
  volume: () => "/me/volume",
@@ -64726,20 +64873,42 @@ var CloudGatewayClient = class {
64726
64873
  }
64727
64874
  async openEventSession(personaId2, opts) {
64728
64875
  const { apiKey, gatewayUrl } = await this.credentials();
64876
+ const health = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.healthz());
64877
+ if (!health.ok || (await health.json()).sessionProtocolVersion !== 2) throw new Error("\u4E91 gateway \u7684\u4F1A\u8BDD\u534F\u8BAE\u7248\u672C\u4E0D\u5339\u914D\uFF0C\u8BF7\u5148\u5347\u7EA7 gateway");
64729
64878
  return openHttpEventSession({
64730
64879
  fetchImpl: this.fetchImpl,
64731
64880
  gatewayUrl,
64732
64881
  apiKey,
64733
64882
  personaId: personaId2,
64883
+ clientSessionId: opts.clientSessionId,
64884
+ gatewaySessionId: opts.gatewaySessionId,
64734
64885
  engineSessionId: opts.toolSessionId,
64735
64886
  instructions: opts.instructions,
64736
64887
  purpose: opts.purpose,
64737
64888
  expectedEngine: opts.expectedEngine,
64738
64889
  effort: opts.effort,
64739
64890
  personaMode: opts.personaMode,
64891
+ attachOnly: opts.attachOnly,
64740
64892
  logger: this.deps.logger
64741
64893
  });
64742
64894
  }
64895
+ async cancelEventSession(personaId2, clientSessionId, gatewaySessionId) {
64896
+ const { apiKey, gatewayUrl } = await this.credentials();
64897
+ const res = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventCancel(personaId2), {
64898
+ method: "POST",
64899
+ headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
64900
+ body: JSON.stringify({ protocolVersion: 2, clientSessionId, gatewaySessionId })
64901
+ });
64902
+ if (!res.ok) {
64903
+ let message = `gateway \u56DE ${res.status}`;
64904
+ try {
64905
+ const body = await res.json();
64906
+ if (typeof body.message === "string") message = body.message;
64907
+ } catch {
64908
+ }
64909
+ throw new Error(message);
64910
+ }
64911
+ }
64743
64912
  /**
64744
64913
  * 看板数据(design 2026-09-23-cloud-persona-metrics §3.8):GET /metrics/<persona>?window&entry,**原样回**状态码与 body——
64745
64914
  * 形状真源在 gateway 的 cloud-persona-metrics,daemon 只是替浏览器拿本机 api key 转一跳。拿不到 key / 连不上 / 超时 → 抛(路由折成 502)。
@@ -64796,9 +64965,9 @@ var CloudGatewayClient = class {
64796
64965
  }
64797
64966
  };
64798
64967
  function openHttpEventSession(opts) {
64799
- const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, engineSessionId, instructions, purpose, effort, personaMode, expectedEngine, logger } = opts;
64968
+ const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, clientSessionId, gatewaySessionId, engineSessionId, instructions, purpose, effort, personaMode, attachOnly, expectedEngine, logger } = opts;
64800
64969
  const headers = { authorization: `Bearer ${apiKey}`, "content-type": "application/json" };
64801
- const abort = new AbortController();
64970
+ let abort = new AbortController();
64802
64971
  const eventCbs = [];
64803
64972
  const controlCbs = [];
64804
64973
  const closeCbs = [];
@@ -64807,7 +64976,11 @@ function openHttpEventSession(opts) {
64807
64976
  let closed = false;
64808
64977
  let readyControl = null;
64809
64978
  let errorControl = null;
64810
- let sessionId = null;
64979
+ let sessionId = gatewaySessionId ?? null;
64980
+ let lastSeq = 0;
64981
+ let everReady = false;
64982
+ let connected = false;
64983
+ const attachWaiters = [];
64811
64984
  let resolveReady;
64812
64985
  let rejectReady;
64813
64986
  const ready = new Promise((resolve9, reject) => {
@@ -64829,87 +65002,146 @@ function openHttpEventSession(opts) {
64829
65002
  closed = true;
64830
65003
  rejectReady(new Error(message ?? "event session closed"));
64831
65004
  abort.abort();
65005
+ for (const resolve9 of attachWaiters.splice(0)) resolve9();
64832
65006
  for (const cb of closeCbs) cb();
64833
65007
  };
65008
+ const waitForAttach = () => connected ? Promise.resolve() : new Promise((resolve9) => {
65009
+ attachWaiters.push(resolve9);
65010
+ });
65011
+ const retryWait = () => new Promise((resolve9) => {
65012
+ const timer = setTimeout(resolve9, 250);
65013
+ timer.unref?.();
65014
+ abort.signal.addEventListener("abort", () => {
65015
+ clearTimeout(timer);
65016
+ resolve9();
65017
+ }, { once: true });
65018
+ });
64834
65019
  void (async () => {
64835
- try {
64836
- const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSession(personaId2), {
64837
- method: "POST",
64838
- headers,
64839
- body: JSON.stringify({ expectedEngine, ...engineSessionId ? { engineSessionId } : {}, ...instructions ? { instructions } : {}, ...purpose ? { purpose } : {}, ...effort ? { effort } : {}, ...personaMode ? { personaMode } : {} }),
64840
- signal: abort.signal
64841
- });
64842
- if (!res.ok || !res.body) {
64843
- let message = `gateway \u56DE ${res.status}`;
64844
- try {
64845
- const body = await res.json();
64846
- if (typeof body.message === "string") message = body.message;
64847
- if (body.error === "SESSION_VERSION_EXPIRED" && !message.includes("SESSION_VERSION_EXPIRED")) message = `SESSION_VERSION_EXPIRED: ${message}`;
64848
- } catch {
64849
- }
64850
- finish(message);
64851
- return;
64852
- }
64853
- const reader = res.body.getReader();
64854
- const decoder = new TextDecoder();
64855
- let pending = "";
64856
- for (; ; ) {
64857
- const { value, done } = await reader.read();
64858
- if (done) break;
64859
- pending += decoder.decode(value, { stream: true });
64860
- const lines = pending.split("\n");
64861
- pending = lines.pop() ?? "";
64862
- for (const line of lines) {
64863
- if (!line.trim()) continue;
64864
- const data = JSON.parse(line);
64865
- if (data.clawd === "events") {
64866
- const events = ParsedEventSchema.array().parse(data.events);
64867
- if (!eventCbs.length) earlyEvents.push(events);
64868
- for (const cb of eventCbs) cb(events);
64869
- continue;
65020
+ while (!closed) {
65021
+ abort = new AbortController();
65022
+ let fatal = false;
65023
+ try {
65024
+ const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSession(personaId2), {
65025
+ method: "POST",
65026
+ headers,
65027
+ body: JSON.stringify({ protocolVersion: 2, clientSessionId, afterSeq: lastSeq, ...sessionId ? { gatewaySessionId: sessionId } : {}, expectedEngine, ...engineSessionId ? { engineSessionId } : {}, ...instructions ? { instructions } : {}, ...purpose ? { purpose } : {}, ...effort ? { effort } : {}, ...personaMode ? { personaMode } : {}, ...attachOnly ? { attachOnly: true } : {} }),
65028
+ signal: abort.signal
65029
+ });
65030
+ if (!res.ok || !res.body) {
65031
+ let message = `gateway \u56DE ${res.status}`;
65032
+ let code;
65033
+ try {
65034
+ const body = await res.json();
65035
+ if (typeof body.message === "string") message = body.message;
65036
+ code = body.error;
65037
+ if (body.error === "SESSION_VERSION_EXPIRED" && !message.includes("SESSION_VERSION_EXPIRED")) message = `SESSION_VERSION_EXPIRED: ${message}`;
65038
+ } catch {
64870
65039
  }
64871
- const control = parseControlLine(line);
64872
- if (!control) throw new Error("gateway event stream contains an unknown line");
64873
- if (control.kind === "ready") {
64874
- if (!control.session) throw new Error("gateway ready line has no session id");
64875
- if (control.engine !== expectedEngine) {
64876
- finish(control.engine ? `SESSION_VERSION_EXPIRED: \u5F53\u524D Pod \u662F ${control.engine}\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u9700\u8981 ${expectedEngine}` : "gateway \u7684 ready \u63A7\u5236\u884C\u6CA1\u5E26 engine\uFF0Cgateway \u592A\u8001\uFF0C\u5148\u5347 gateway");
65040
+ if ((attachOnly || sessionId) && res.status === 404 && code === "SESSION_NOT_FOUND") {
65041
+ emitControl({ kind: "closed", reason: "not-found" });
65042
+ finish();
65043
+ return;
65044
+ }
65045
+ if (res.status === 426 || res.status === 400 || res.status === 401 || res.status === 403 || res.status === 409 || res.status === 410 || code === "CLIENT_UPGRADE_REQUIRED") {
65046
+ fatal = true;
65047
+ finish(message);
65048
+ return;
65049
+ }
65050
+ throw new Error(message);
65051
+ }
65052
+ connected = true;
65053
+ for (const resolve9 of attachWaiters.splice(0)) resolve9();
65054
+ const reader = res.body.getReader();
65055
+ const decoder = new TextDecoder();
65056
+ let pending = "";
65057
+ for (; ; ) {
65058
+ const { value, done } = await reader.read();
65059
+ if (done) break;
65060
+ pending += decoder.decode(value, { stream: true });
65061
+ const lines = pending.split("\n");
65062
+ pending = lines.pop() ?? "";
65063
+ for (const line of lines) {
65064
+ if (!line.trim()) continue;
65065
+ const data = JSON.parse(line);
65066
+ if (data.clawd === "events") {
65067
+ if (typeof data.seq === "number") {
65068
+ if (data.seq <= lastSeq) continue;
65069
+ lastSeq = data.seq;
65070
+ }
65071
+ const events = ParsedEventSchema.array().parse(data.events);
65072
+ if (!eventCbs.length) earlyEvents.push(events);
65073
+ for (const cb of eventCbs) cb(events);
65074
+ continue;
65075
+ }
65076
+ const control = parseControlLine(line);
65077
+ if (!control) throw new Error("gateway event stream contains an unknown line");
65078
+ if (control.kind === "ready") {
65079
+ if (!control.session) throw new Error("gateway ready line has no session id");
65080
+ if (control.engine !== expectedEngine) {
65081
+ finish(control.engine ? `SESSION_VERSION_EXPIRED: \u5F53\u524D Pod \u662F ${control.engine}\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u9700\u8981 ${expectedEngine}` : "gateway \u7684 ready \u63A7\u5236\u884C\u6CA1\u5E26 engine\uFF0Cgateway \u592A\u8001\uFF0C\u5148\u5347 gateway");
65082
+ return;
65083
+ }
65084
+ sessionId = control.session;
65085
+ everReady = true;
65086
+ resolveReady();
65087
+ }
65088
+ emitControl(control);
65089
+ if (control.kind === "error") {
65090
+ finish();
65091
+ return;
65092
+ }
65093
+ if (control.kind === "closed") {
65094
+ finish();
64877
65095
  return;
64878
65096
  }
64879
- sessionId = control.session;
64880
- resolveReady();
64881
65097
  }
64882
- emitControl(control);
64883
- if (control.kind === "error") {
64884
- finish();
65098
+ }
65099
+ connected = false;
65100
+ } catch (e) {
65101
+ if (!closed) {
65102
+ if (e instanceof SyntaxError || e.name === "ZodError") {
65103
+ finish("gateway event stream contains invalid data");
64885
65104
  return;
64886
65105
  }
65106
+ connected = false;
65107
+ logger?.warn("cloud event stream failed; reconnecting", { code: e.code, name: e.name, ready: everReady });
64887
65108
  }
64888
65109
  }
64889
- finish();
64890
- } catch (e) {
64891
- if (!closed) {
64892
- logger?.warn("cloud event stream failed", { message: e.message });
64893
- finish(`\u4E91\u4E0A\u4E8B\u4EF6\u901A\u9053\u51FA\u9519\uFF1A${e.message}`);
64894
- }
65110
+ if (!closed && !fatal) await retryWait();
64895
65111
  }
64896
65112
  })();
64897
65113
  return {
64898
65114
  send(command) {
64899
65115
  const next = sendChain.then(async () => {
64900
65116
  await ready;
64901
- if (closed || !sessionId) throw new Error("event session closed");
64902
- const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSend(personaId2, sessionId), { method: "POST", headers, body: JSON.stringify(command) });
64903
- if (!res.ok) {
65117
+ while (!closed) {
65118
+ await waitForAttach();
65119
+ if (!sessionId) continue;
65120
+ let res;
65121
+ try {
65122
+ res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSend(personaId2, sessionId), { method: "POST", headers, body: JSON.stringify(command) });
65123
+ } catch {
65124
+ connected = false;
65125
+ abort.abort();
65126
+ await retryWait();
65127
+ continue;
65128
+ }
65129
+ if (res.ok) return;
65130
+ if (res.status === 404 || res.status >= 500) {
65131
+ connected = false;
65132
+ abort.abort();
65133
+ await retryWait();
65134
+ continue;
65135
+ }
64904
65136
  let message = `gateway \u56DE ${res.status}`;
64905
65137
  try {
64906
65138
  const body = await res.json();
64907
65139
  if (typeof body.message === "string") message = body.message;
64908
65140
  } catch {
64909
65141
  }
64910
- finish(message);
64911
65142
  throw new Error(message);
64912
65143
  }
65144
+ throw new Error("event session closed");
64913
65145
  });
64914
65146
  sendChain = next.catch(() => {
64915
65147
  });
@@ -64957,10 +65189,17 @@ function parseControlLine(line) {
64957
65189
  personaDir: typeof r2.personaDir === "string" ? r2.personaDir : "",
64958
65190
  workDir: typeof r2.workDir === "string" ? r2.workDir : "",
64959
65191
  ...typeof r2.model === "string" ? { model: r2.model } : {},
64960
- ...typeof r2.engine === "string" ? { engine: r2.engine } : {}
65192
+ ...typeof r2.engine === "string" ? { engine: r2.engine } : {},
65193
+ ...typeof r2.replayGap === "boolean" ? { replayGap: r2.replayGap } : {},
65194
+ ...typeof r2.historySynchronized === "boolean" ? { historySynchronized: r2.historySynchronized } : {},
65195
+ ...typeof r2.activeTurn === "boolean" ? { activeTurn: r2.activeTurn } : {}
64961
65196
  };
64962
65197
  case "error":
64963
65198
  return { kind: "error", message: typeof r2.message === "string" ? r2.message : "gateway error" };
65199
+ case "closed":
65200
+ return { kind: "closed", reason: typeof r2.reason === "string" ? r2.reason : "unknown" };
65201
+ case "history":
65202
+ return { kind: "history", synchronized: r2.synchronized === true };
64964
65203
  default:
64965
65204
  return { kind: "ping" };
64966
65205
  }
@@ -65153,11 +65392,97 @@ function openHttpLineStream(opts) {
65153
65392
  };
65154
65393
  }
65155
65394
 
65395
+ // src/cloud/cancel-outbox.ts
65396
+ var import_node_fs39 = __toESM(require("fs"), 1);
65397
+ var import_node_path44 = __toESM(require("path"), 1);
65398
+ var CloudCancelOutbox = class {
65399
+ constructor(dir, send2, logger) {
65400
+ this.dir = dir;
65401
+ this.send = send2;
65402
+ this.logger = logger;
65403
+ }
65404
+ dir;
65405
+ send;
65406
+ logger;
65407
+ timer = null;
65408
+ inFlight = /* @__PURE__ */ new Set();
65409
+ record(clientSessionId, personaId2, gatewaySessionId) {
65410
+ if (!clientSessionId || !personaId2 || !gatewaySessionId) throw new Error("cloud cancel requires client, gateway and persona IDs");
65411
+ import_node_fs39.default.mkdirSync(this.dir, { recursive: true, mode: 448 });
65412
+ const target = this.pathFor(clientSessionId);
65413
+ const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
65414
+ import_node_fs39.default.writeFileSync(temporary, JSON.stringify({ clientSessionId, personaId: personaId2, gatewaySessionId }), { mode: 384 });
65415
+ import_node_fs39.default.renameSync(temporary, target);
65416
+ this.inFlight.add(clientSessionId);
65417
+ }
65418
+ confirm(clientSessionId) {
65419
+ import_node_fs39.default.rmSync(this.pathFor(clientSessionId), { force: true });
65420
+ this.inFlight.delete(clientSessionId);
65421
+ }
65422
+ release(clientSessionId) {
65423
+ this.inFlight.delete(clientSessionId);
65424
+ }
65425
+ async request(clientSessionId, personaId2, gatewaySessionId) {
65426
+ this.record(clientSessionId, personaId2, gatewaySessionId);
65427
+ try {
65428
+ await this.send(personaId2, clientSessionId, gatewaySessionId);
65429
+ this.confirm(clientSessionId);
65430
+ } catch (e) {
65431
+ this.release(clientSessionId);
65432
+ throw e;
65433
+ }
65434
+ }
65435
+ async flush() {
65436
+ let names;
65437
+ try {
65438
+ names = import_node_fs39.default.readdirSync(this.dir).filter((name) => name.endsWith(".json"));
65439
+ } catch (e) {
65440
+ if (e.code === "ENOENT") return;
65441
+ throw e;
65442
+ }
65443
+ for (const name of names) {
65444
+ const target = import_node_path44.default.join(this.dir, name);
65445
+ let pending;
65446
+ try {
65447
+ pending = JSON.parse(import_node_fs39.default.readFileSync(target, "utf8"));
65448
+ } catch {
65449
+ continue;
65450
+ }
65451
+ if (!pending.clientSessionId || !pending.personaId || !pending.gatewaySessionId || this.pathFor(pending.clientSessionId) !== target) continue;
65452
+ if (this.inFlight.has(pending.clientSessionId)) continue;
65453
+ this.inFlight.add(pending.clientSessionId);
65454
+ try {
65455
+ await this.send(pending.personaId, pending.clientSessionId, pending.gatewaySessionId);
65456
+ import_node_fs39.default.rmSync(target, { force: true });
65457
+ } catch (e) {
65458
+ this.logger?.warn("cloud cancel pending", { sessionId: pending.clientSessionId, error: e.message });
65459
+ } finally {
65460
+ this.inFlight.delete(pending.clientSessionId);
65461
+ }
65462
+ }
65463
+ }
65464
+ start() {
65465
+ if (this.timer) return;
65466
+ const retry = () => void this.flush().catch((e) => this.logger?.warn("cloud cancel outbox flush failed", { error: e.message }));
65467
+ retry();
65468
+ this.timer = setInterval(retry, 3e4);
65469
+ this.timer.unref?.();
65470
+ }
65471
+ stop() {
65472
+ if (this.timer) clearInterval(this.timer);
65473
+ this.timer = null;
65474
+ }
65475
+ pathFor(clientSessionId) {
65476
+ return import_node_path44.default.join(this.dir, `${safeFileName(clientSessionId)}.json`);
65477
+ }
65478
+ };
65479
+
65156
65480
  // src/tools/codex-cloud.ts
65157
65481
  init_protocol();
65158
65482
 
65159
65483
  // src/tools/codex-cloud-session.ts
65160
- var import_node_fs39 = __toESM(require("fs"), 1);
65484
+ var import_node_fs40 = __toESM(require("fs"), 1);
65485
+ var import_node_crypto13 = require("crypto");
65161
65486
 
65162
65487
  // src/tools/cloud-portable-input.ts
65163
65488
  async function portableCloudInput(text, resolvers) {
@@ -65186,7 +65511,7 @@ function cloudImageInput(deps) {
65186
65511
  const mime = lookupMime(p3);
65187
65512
  if (!mime.startsWith("image/")) return null;
65188
65513
  try {
65189
- const bytes = (deps.readFile ?? import_node_fs39.default.readFileSync)(p3);
65514
+ const bytes = (deps.readFile ?? import_node_fs40.default.readFileSync)(p3);
65190
65515
  return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
65191
65516
  } catch (e) {
65192
65517
  deps.logger?.warn("cloud image attachment unreadable", { path: p3, message: e.message });
@@ -65196,18 +65521,22 @@ function cloudImageInput(deps) {
65196
65521
  }
65197
65522
  function createCloudCodexSession(ctx, sink, deps) {
65198
65523
  const personaId2 = personaIdFromCloudCwd(ctx.cwd);
65524
+ const clientSessionId = ctx.titleOnly ? (0, import_node_crypto13.randomUUID)() : ctx.cloudExecutionId ?? ctx.env?.CLAWD_SESSION_ID;
65199
65525
  let channel = null;
65200
65526
  let closed = false;
65527
+ let detached = false;
65528
+ let stopping = null;
65201
65529
  let exited = false;
65530
+ let ready = false;
65202
65531
  const exit = () => {
65203
65532
  if (!exited) {
65204
65533
  exited = true;
65205
65534
  sink.onExit(null);
65206
65535
  }
65207
65536
  };
65208
- if (!personaId2) {
65537
+ if (!personaId2 || !clientSessionId) {
65209
65538
  queueMicrotask(() => {
65210
- sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
65539
+ sink.onError(`cloud session is missing ${personaId2 ? "CLAWD_SESSION_ID" : "persona id"}`);
65211
65540
  exit();
65212
65541
  });
65213
65542
  return { startTurn() {
@@ -65218,23 +65547,36 @@ function createCloudCodexSession(ctx, sink, deps) {
65218
65547
  }
65219
65548
  const opened = deps.client.openEventSession(personaId2, {
65220
65549
  expectedEngine: "codex",
65550
+ clientSessionId,
65551
+ ...ctx.cloudGatewaySessionId ? { gatewaySessionId: ctx.cloudGatewaySessionId } : {},
65221
65552
  ...ctx.toolSessionId ? { toolSessionId: ctx.toolSessionId } : {},
65222
65553
  ...ctx.extraSystemPrompt ? { instructions: ctx.extraSystemPrompt } : {},
65223
65554
  ...ctx.effort ? { effort: ctx.effort } : {},
65224
65555
  ...ctx.personaMode ? { personaMode: ctx.personaMode } : {},
65225
- ...ctx.titleOnly ? { purpose: "title" } : {}
65556
+ ...ctx.titleOnly ? { purpose: "title" } : {},
65557
+ ...ctx.cloudAttachOnly ? { attachOnly: true } : {}
65226
65558
  }).then(
65227
65559
  (opened2) => {
65228
65560
  channel = opened2;
65229
65561
  channel.onEvents((events) => sink.pushEvents(events));
65230
65562
  channel.onControl((c2) => {
65231
- if (c2.kind === "queued") {
65563
+ if (c2.kind === "ready") {
65564
+ ready = true;
65565
+ sink.onGatewayReady?.(c2.session);
65566
+ if (c2.replayGap || c2.historySynchronized === false) sink.onHistoryGap?.(c2.historySynchronized === true);
65567
+ } else if (c2.kind === "queued") {
65232
65568
  sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
65569
+ } else if (c2.kind === "history") {
65570
+ sink.onHistoryGap?.(c2.synchronized);
65233
65571
  } else if (c2.kind === "error") {
65234
- sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
65572
+ sink.onError(`${ready ? "\u4E91\u4E0A\u6267\u884C\u5931\u8D25" : "\u4E91\u4E0A persona \u8D77\u4E0D\u6765"}\uFF1A${c2.message}`);
65573
+ } else if (c2.kind === "closed" && c2.reason === "not-found") {
65574
+ sink.onRecoveryAbsent?.();
65235
65575
  }
65236
65576
  });
65237
- channel.onClose(exit);
65577
+ channel.onClose(() => {
65578
+ if (!detached) exit();
65579
+ });
65238
65580
  if (closed) channel.close();
65239
65581
  return channel;
65240
65582
  },
@@ -65253,12 +65595,13 @@ function createCloudCodexSession(ctx, sink, deps) {
65253
65595
  });
65254
65596
  };
65255
65597
  return {
65256
- startTurn(text) {
65598
+ startTurn(text, commandId = (0, import_node_crypto13.randomUUID)(), prepared = false) {
65257
65599
  send2(async () => {
65258
65600
  const ch = await opened;
65259
65601
  if (closed) return;
65260
- const portable = await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
65261
- await ch.send({ command: "turn", text: portable });
65602
+ const portable = prepared ? text : await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
65603
+ if (sink.onCommandPrepared?.(commandId, portable, prepared) === false) return;
65604
+ await ch.send({ command: "turn", text: portable, commandId });
65262
65605
  });
65263
65606
  },
65264
65607
  respondPermission(requestId, allow) {
@@ -65267,11 +65610,23 @@ function createCloudCodexSession(ctx, sink, deps) {
65267
65610
  interrupt() {
65268
65611
  send2(async () => (await opened).send({ command: "interrupt" }));
65269
65612
  },
65270
- async stop() {
65613
+ detach() {
65614
+ detached = true;
65271
65615
  closed = true;
65272
- const ch = await opened.catch(() => null);
65273
- ch?.close();
65274
- exit();
65616
+ channel?.close();
65617
+ },
65618
+ stop() {
65619
+ if (stopping) return stopping;
65620
+ closed = true;
65621
+ stopping = (async () => {
65622
+ const ch = await opened.catch(() => null);
65623
+ if (ch) {
65624
+ await ch.send({ command: "cancel" });
65625
+ ch.close();
65626
+ }
65627
+ exit();
65628
+ })();
65629
+ return stopping;
65275
65630
  }
65276
65631
  };
65277
65632
  }
@@ -65344,7 +65699,7 @@ init_protocol();
65344
65699
 
65345
65700
  // src/tools/pi.ts
65346
65701
  var import_node_child_process12 = require("child_process");
65347
- var import_node_fs41 = __toESM(require("fs"), 1);
65702
+ var import_node_fs42 = __toESM(require("fs"), 1);
65348
65703
  init_protocol();
65349
65704
 
65350
65705
  // src/tools/pi-rpc-client.ts
@@ -65444,9 +65799,9 @@ var PiRpcClient = class {
65444
65799
 
65445
65800
  // src/tools/pi-session.ts
65446
65801
  var import_node_child_process11 = require("child_process");
65447
- var import_node_crypto13 = require("crypto");
65448
- var import_node_fs40 = __toESM(require("fs"), 1);
65449
- var import_node_path44 = __toESM(require("path"), 1);
65802
+ var import_node_crypto14 = require("crypto");
65803
+ var import_node_fs41 = __toESM(require("fs"), 1);
65804
+ var import_node_path45 = __toESM(require("path"), 1);
65450
65805
 
65451
65806
  // src/tools/pi-events.ts
65452
65807
  init_protocol();
@@ -65717,9 +66072,9 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
65717
66072
  }
65718
66073
  function createPiSession(ctx, sink, deps = {}) {
65719
66074
  const cmd = process.env.PI_BIN ?? "pi";
65720
- const sessionId = ctx.toolSessionId ?? (0, import_node_crypto13.randomUUID)();
65721
- const skillsDir = import_node_path44.default.join(ctx.cwd, ".claude", "skills");
65722
- const exists = deps.skillsDirExists ?? ((d2) => import_node_fs40.default.existsSync(d2));
66075
+ const sessionId = ctx.toolSessionId ?? (0, import_node_crypto14.randomUUID)();
66076
+ const skillsDir = import_node_path45.default.join(ctx.cwd, ".claude", "skills");
66077
+ const exists = deps.skillsDirExists ?? ((d2) => import_node_fs41.default.existsSync(d2));
65723
66078
  const args = buildPiArgs(ctx, {
65724
66079
  sessionId,
65725
66080
  skillsDir: exists(skillsDir) ? skillsDir : void 0,
@@ -65781,10 +66136,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
65781
66136
  };
65782
66137
  var PI_FULL_ACCESS = { id: "never", label: "Full Access", description: "pi \u65E0\u5BA1\u6279\uFF1A\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" };
65783
66138
  async function probePi(env = process.env) {
65784
- if (env.PI_BIN && import_node_fs41.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
66139
+ if (env.PI_BIN && import_node_fs42.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
65785
66140
  try {
65786
66141
  const out = (0, import_node_child_process12.execFileSync)("which", ["pi"], { encoding: "utf8" }).trim();
65787
- if (out && import_node_fs41.default.existsSync(out)) return { available: true, path: out };
66142
+ if (out && import_node_fs42.default.existsSync(out)) return { available: true, path: out };
65788
66143
  } catch {
65789
66144
  }
65790
66145
  return { available: false };
@@ -65954,25 +66309,29 @@ var PiAdapter = class {
65954
66309
  };
65955
66310
 
65956
66311
  // src/tools/pi-cloud-session.ts
65957
- var import_node_crypto14 = require("crypto");
66312
+ var import_node_crypto15 = require("crypto");
65958
66313
  function cloudPiInstructions(ctx) {
65959
66314
  return [ctx.extraSystemPrompt, workDirPrompt(CLOUD_WORKSPACE_SLOT, ctx.personaMode ?? "owner")].filter((x2) => Boolean(x2)).join("\n\n");
65960
66315
  }
65961
66316
  function createCloudPiSession(ctx, sink, deps) {
65962
66317
  const personaId2 = personaIdFromCloudCwd(ctx.cwd);
65963
- const sessionId = ctx.toolSessionId ?? (0, import_node_crypto14.randomUUID)();
66318
+ const clientSessionId = ctx.titleOnly ? (0, import_node_crypto15.randomUUID)() : ctx.cloudExecutionId ?? ctx.env?.CLAWD_SESSION_ID;
66319
+ const sessionId = ctx.toolSessionId ?? (0, import_node_crypto15.randomUUID)();
65964
66320
  let channel = null;
65965
66321
  let closed = false;
66322
+ let detached = false;
66323
+ let stopping = null;
65966
66324
  let exited = false;
66325
+ let ready = false;
65967
66326
  const exit = () => {
65968
66327
  if (!exited) {
65969
66328
  exited = true;
65970
66329
  sink.onExit(null);
65971
66330
  }
65972
66331
  };
65973
- if (!personaId2) {
66332
+ if (!personaId2 || !clientSessionId) {
65974
66333
  queueMicrotask(() => {
65975
- sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
66334
+ sink.onError(`cloud session is missing ${personaId2 ? "CLAWD_SESSION_ID" : "persona id"}`);
65976
66335
  exit();
65977
66336
  });
65978
66337
  return { startTurn() {
@@ -65981,18 +66340,28 @@ function createCloudPiSession(ctx, sink, deps) {
65981
66340
  }, async stop() {
65982
66341
  } };
65983
66342
  }
65984
- const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {} }).then(
66343
+ const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", clientSessionId, ...ctx.cloudGatewaySessionId ? { gatewaySessionId: ctx.cloudGatewaySessionId } : {}, toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {}, ...ctx.cloudAttachOnly ? { attachOnly: true } : {} }).then(
65985
66344
  (opened2) => {
65986
66345
  channel = opened2;
65987
66346
  channel.onEvents((events) => sink.pushEvents(events));
65988
66347
  channel.onControl((c2) => {
65989
- if (c2.kind === "queued") {
66348
+ if (c2.kind === "ready") {
66349
+ ready = true;
66350
+ sink.onGatewayReady?.(c2.session);
66351
+ if (c2.replayGap || c2.historySynchronized === false) sink.onHistoryGap?.(c2.historySynchronized === true);
66352
+ } else if (c2.kind === "queued") {
65990
66353
  sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
66354
+ } else if (c2.kind === "history") {
66355
+ sink.onHistoryGap?.(c2.synchronized);
65991
66356
  } else if (c2.kind === "error") {
65992
- sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
66357
+ sink.onError(`${ready ? "\u4E91\u4E0A\u6267\u884C\u5931\u8D25" : "\u4E91\u4E0A persona \u8D77\u4E0D\u6765"}\uFF1A${c2.message}`);
66358
+ } else if (c2.kind === "closed" && c2.reason === "not-found") {
66359
+ sink.onRecoveryAbsent?.();
65993
66360
  }
65994
66361
  });
65995
- channel.onClose(exit);
66362
+ channel.onClose(() => {
66363
+ if (!detached) exit();
66364
+ });
65996
66365
  if (closed) channel.close();
65997
66366
  return channel;
65998
66367
  },
@@ -66011,12 +66380,13 @@ function createCloudPiSession(ctx, sink, deps) {
66011
66380
  });
66012
66381
  };
66013
66382
  return {
66014
- startTurn(text) {
66383
+ startTurn(text, commandId = (0, import_node_crypto15.randomUUID)(), prepared = false) {
66015
66384
  send2(async () => {
66016
66385
  const ch = await opened;
66017
66386
  if (closed) return;
66018
- const portable = await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
66019
- await ch.send({ command: "turn", text: portable });
66387
+ const portable = prepared ? text : await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
66388
+ if (sink.onCommandPrepared?.(commandId, portable, prepared) === false) return;
66389
+ await ch.send({ command: "turn", text: portable, commandId });
66020
66390
  });
66021
66391
  },
66022
66392
  respondPermission(requestId, allow) {
@@ -66025,11 +66395,23 @@ function createCloudPiSession(ctx, sink, deps) {
66025
66395
  interrupt() {
66026
66396
  send2(async () => (await opened).send({ command: "interrupt" }));
66027
66397
  },
66028
- async stop() {
66398
+ detach() {
66399
+ detached = true;
66029
66400
  closed = true;
66030
- const ch = await opened.catch(() => null);
66031
- ch?.close();
66032
- exit();
66401
+ channel?.close();
66402
+ },
66403
+ stop() {
66404
+ if (stopping) return stopping;
66405
+ closed = true;
66406
+ stopping = (async () => {
66407
+ const ch = await opened.catch(() => null);
66408
+ if (ch) {
66409
+ await ch.send({ command: "cancel" });
66410
+ ch.close();
66411
+ }
66412
+ exit();
66413
+ })();
66414
+ return stopping;
66033
66415
  }
66034
66416
  };
66035
66417
  }
@@ -66101,7 +66483,7 @@ var CloudPiAdapter = class {
66101
66483
  init_protocol();
66102
66484
 
66103
66485
  // src/tools/codex-skills.ts
66104
- var import_node_path45 = __toESM(require("path"), 1);
66486
+ var import_node_path46 = __toESM(require("path"), 1);
66105
66487
  function str4(v3) {
66106
66488
  return typeof v3 === "string" ? v3 : void 0;
66107
66489
  }
@@ -66116,13 +66498,13 @@ function mapSkillsListResponse(res) {
66116
66498
  const r2 = s2 ?? {};
66117
66499
  const name = str4(r2.name);
66118
66500
  if (!name) continue;
66119
- const path106 = str4(r2.path);
66501
+ const path107 = str4(r2.path);
66120
66502
  const description = str4(r2.description);
66121
66503
  const isPlugin = name.includes(":");
66122
66504
  out.push({
66123
66505
  name,
66124
66506
  source: isPlugin ? "plugin" : "project",
66125
- ...path106 ? { path: path106 } : {},
66507
+ ...path107 ? { path: path107 } : {},
66126
66508
  ...description ? { description } : {},
66127
66509
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
66128
66510
  });
@@ -66138,7 +66520,7 @@ async function listCodexSkills(cwd, deps = {}) {
66138
66520
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
66139
66521
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
66140
66522
  beforeRequest: (client) => {
66141
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path45.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
66523
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path46.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
66142
66524
  }
66143
66525
  });
66144
66526
  return mapSkillsListResponse(res);
@@ -66212,23 +66594,23 @@ function rec4(v3) {
66212
66594
  }
66213
66595
 
66214
66596
  // src/workspace/browser.ts
66215
- var import_node_fs42 = __toESM(require("fs"), 1);
66597
+ var import_node_fs43 = __toESM(require("fs"), 1);
66216
66598
  var import_node_os15 = __toESM(require("os"), 1);
66217
- var import_node_path46 = __toESM(require("path"), 1);
66599
+ var import_node_path47 = __toESM(require("path"), 1);
66218
66600
  init_protocol();
66219
66601
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
66220
66602
  function resolveInsideCwd(cwd, subpath) {
66221
- const absCwd = import_node_path46.default.resolve(cwd);
66222
- const joined = import_node_path46.default.resolve(absCwd, subpath ?? ".");
66223
- const rel = import_node_path46.default.relative(absCwd, joined);
66224
- if (rel.startsWith("..") || import_node_path46.default.isAbsolute(rel)) {
66603
+ const absCwd = import_node_path47.default.resolve(cwd);
66604
+ const joined = import_node_path47.default.resolve(absCwd, subpath ?? ".");
66605
+ const rel = import_node_path47.default.relative(absCwd, joined);
66606
+ if (rel.startsWith("..") || import_node_path47.default.isAbsolute(rel)) {
66225
66607
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
66226
66608
  }
66227
66609
  return joined;
66228
66610
  }
66229
66611
  function ensureCwd(cwd) {
66230
66612
  try {
66231
- const stat = import_node_fs42.default.statSync(cwd);
66613
+ const stat = import_node_fs43.default.statSync(cwd);
66232
66614
  if (!stat.isDirectory()) {
66233
66615
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
66234
66616
  }
@@ -66242,7 +66624,7 @@ var WorkspaceBrowser = class {
66242
66624
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os15.default.homedir();
66243
66625
  ensureCwd(cwd);
66244
66626
  const full = resolveInsideCwd(cwd, args.path);
66245
- const dirents = import_node_fs42.default.readdirSync(full, { withFileTypes: true });
66627
+ const dirents = import_node_fs43.default.readdirSync(full, { withFileTypes: true });
66246
66628
  const entries = [];
66247
66629
  for (const d2 of dirents) {
66248
66630
  if (!args.showHidden && d2.name.startsWith(".")) continue;
@@ -66252,7 +66634,7 @@ var WorkspaceBrowser = class {
66252
66634
  mtime: ""
66253
66635
  };
66254
66636
  try {
66255
- const st2 = import_node_fs42.default.statSync(import_node_path46.default.join(full, d2.name));
66637
+ const st2 = import_node_fs43.default.statSync(import_node_path47.default.join(full, d2.name));
66256
66638
  entry.mtime = new Date(st2.mtimeMs).toISOString();
66257
66639
  if (d2.isFile()) entry.size = st2.size;
66258
66640
  } catch {
@@ -66268,14 +66650,14 @@ var WorkspaceBrowser = class {
66268
66650
  read(args) {
66269
66651
  ensureCwd(args.cwd);
66270
66652
  const full = resolveInsideCwd(args.cwd, args.path);
66271
- const st2 = import_node_fs42.default.statSync(full);
66653
+ const st2 = import_node_fs43.default.statSync(full);
66272
66654
  if (!st2.isFile()) {
66273
66655
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
66274
66656
  }
66275
66657
  if (st2.size > MAX_FILE_BYTES2) {
66276
66658
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
66277
66659
  }
66278
- const buf = import_node_fs42.default.readFileSync(full);
66660
+ const buf = import_node_fs43.default.readFileSync(full);
66279
66661
  const isBinary = buf.includes(0);
66280
66662
  if (isBinary) {
66281
66663
  return {
@@ -66297,20 +66679,20 @@ var WorkspaceBrowser = class {
66297
66679
  };
66298
66680
 
66299
66681
  // src/skills/agents-scanner.ts
66300
- var import_node_fs43 = __toESM(require("fs"), 1);
66682
+ var import_node_fs44 = __toESM(require("fs"), 1);
66301
66683
  var import_node_os16 = __toESM(require("os"), 1);
66302
- var import_node_path47 = __toESM(require("path"), 1);
66684
+ var import_node_path48 = __toESM(require("path"), 1);
66303
66685
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
66304
66686
  function isDirLikeSync2(p3) {
66305
66687
  try {
66306
- return import_node_fs43.default.statSync(p3).isDirectory();
66688
+ return import_node_fs44.default.statSync(p3).isDirectory();
66307
66689
  } catch {
66308
66690
  return false;
66309
66691
  }
66310
66692
  }
66311
66693
  function fileExistsSync(p3) {
66312
66694
  try {
66313
- return import_node_fs43.default.statSync(p3).isFile();
66695
+ return import_node_fs44.default.statSync(p3).isFile();
66314
66696
  } catch {
66315
66697
  return false;
66316
66698
  }
@@ -66318,7 +66700,7 @@ function fileExistsSync(p3) {
66318
66700
  function parseAgentFile(filePath) {
66319
66701
  let content;
66320
66702
  try {
66321
- content = import_node_fs43.default.readFileSync(filePath, "utf8");
66703
+ content = import_node_fs44.default.readFileSync(filePath, "utf8");
66322
66704
  } catch {
66323
66705
  return {};
66324
66706
  }
@@ -66331,16 +66713,16 @@ function parseAgentFile(filePath) {
66331
66713
  function scanAgentsDir(dir, source, seen, out) {
66332
66714
  let entries;
66333
66715
  try {
66334
- entries = import_node_fs43.default.readdirSync(dir, { withFileTypes: true });
66716
+ entries = import_node_fs44.default.readdirSync(dir, { withFileTypes: true });
66335
66717
  } catch {
66336
66718
  return;
66337
66719
  }
66338
66720
  for (const ent of entries) {
66339
66721
  if (!ent.name.endsWith(".md")) continue;
66340
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path47.default.join(dir, ent.name)))) {
66722
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path48.default.join(dir, ent.name)))) {
66341
66723
  continue;
66342
66724
  }
66343
- const filePath = import_node_path47.default.join(dir, ent.name);
66725
+ const filePath = import_node_path48.default.join(dir, ent.name);
66344
66726
  const baseName = ent.name.replace(/\.md$/, "");
66345
66727
  if (seen.has(baseName)) continue;
66346
66728
  seen.add(baseName);
@@ -66358,12 +66740,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
66358
66740
  function walk2(dir, namespaces) {
66359
66741
  let entries;
66360
66742
  try {
66361
- entries = import_node_fs43.default.readdirSync(dir, { withFileTypes: true });
66743
+ entries = import_node_fs44.default.readdirSync(dir, { withFileTypes: true });
66362
66744
  } catch {
66363
66745
  return;
66364
66746
  }
66365
66747
  for (const ent of entries) {
66366
- const childPath = import_node_path47.default.join(dir, ent.name);
66748
+ const childPath = import_node_path48.default.join(dir, ent.name);
66367
66749
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
66368
66750
  walk2(childPath, [...namespaces, ent.name]);
66369
66751
  continue;
@@ -66388,13 +66770,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
66388
66770
  walk2(root, []);
66389
66771
  }
66390
66772
  function readInstalledPlugins2(home) {
66391
- const pluginsDir = import_node_path47.default.join(home, ".claude", "plugins");
66392
- const v22 = import_node_path47.default.join(pluginsDir, "installed_plugins_v2.json");
66393
- const v1 = import_node_path47.default.join(pluginsDir, "installed_plugins.json");
66773
+ const pluginsDir = import_node_path48.default.join(home, ".claude", "plugins");
66774
+ const v22 = import_node_path48.default.join(pluginsDir, "installed_plugins_v2.json");
66775
+ const v1 = import_node_path48.default.join(pluginsDir, "installed_plugins.json");
66394
66776
  let raw = null;
66395
66777
  for (const candidate of [v22, v1]) {
66396
66778
  try {
66397
- raw = import_node_fs43.default.readFileSync(candidate, "utf8");
66779
+ raw = import_node_fs44.default.readFileSync(candidate, "utf8");
66398
66780
  break;
66399
66781
  } catch {
66400
66782
  }
@@ -66419,19 +66801,19 @@ function readInstalledPlugins2(home) {
66419
66801
  return out;
66420
66802
  }
66421
66803
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
66422
- let cur = import_node_path47.default.resolve(startCwd);
66423
- const fsRoot = import_node_path47.default.parse(cur).root;
66804
+ let cur = import_node_path48.default.resolve(startCwd);
66805
+ const fsRoot = import_node_path48.default.parse(cur).root;
66424
66806
  while (true) {
66425
- scanAgentsDir(import_node_path47.default.join(cur, ".claude", "agents"), "project", seen, out);
66807
+ scanAgentsDir(import_node_path48.default.join(cur, ".claude", "agents"), "project", seen, out);
66426
66808
  let hasGit = false;
66427
66809
  try {
66428
- hasGit = import_node_fs43.default.existsSync(import_node_path47.default.join(cur, ".git"));
66810
+ hasGit = import_node_fs44.default.existsSync(import_node_path48.default.join(cur, ".git"));
66429
66811
  } catch {
66430
66812
  }
66431
66813
  if (hasGit) return;
66432
66814
  if (cur === home) return;
66433
66815
  if (cur === fsRoot) return;
66434
- const parent = import_node_path47.default.dirname(cur);
66816
+ const parent = import_node_path48.default.dirname(cur);
66435
66817
  if (parent === cur) return;
66436
66818
  cur = parent;
66437
66819
  }
@@ -66466,7 +66848,7 @@ var AgentsScanner = class {
66466
66848
  }
66467
66849
  const fsBlock = [];
66468
66850
  scanAgentsDir(
66469
- import_node_path47.default.join(this.home, ".claude", "agents"),
66851
+ import_node_path48.default.join(this.home, ".claude", "agents"),
66470
66852
  "global",
66471
66853
  seen,
66472
66854
  fsBlock
@@ -66480,7 +66862,7 @@ var AgentsScanner = class {
66480
66862
  ...this.extraPluginRoots
66481
66863
  ];
66482
66864
  for (const { name, root } of plugins) {
66483
- const agentsRoot = import_node_path47.default.join(root, "agents");
66865
+ const agentsRoot = import_node_path48.default.join(root, "agents");
66484
66866
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
66485
66867
  }
66486
66868
  return [...builtinBlock, ...fsBlock];
@@ -66488,15 +66870,15 @@ var AgentsScanner = class {
66488
66870
  };
66489
66871
 
66490
66872
  // src/observer/session-observer.ts
66491
- var import_node_fs45 = __toESM(require("fs"), 1);
66873
+ var import_node_fs46 = __toESM(require("fs"), 1);
66492
66874
  var import_node_os18 = __toESM(require("os"), 1);
66493
- var import_node_path49 = __toESM(require("path"), 1);
66875
+ var import_node_path50 = __toESM(require("path"), 1);
66494
66876
  init_claude_history();
66495
66877
 
66496
66878
  // src/observer/subagent-meta-observer.ts
66497
- var import_node_fs44 = __toESM(require("fs"), 1);
66879
+ var import_node_fs45 = __toESM(require("fs"), 1);
66498
66880
  var import_node_os17 = __toESM(require("os"), 1);
66499
- var import_node_path48 = __toESM(require("path"), 1);
66881
+ var import_node_path49 = __toESM(require("path"), 1);
66500
66882
  init_claude_history();
66501
66883
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
66502
66884
  var SubagentMetaObserver = class {
@@ -66509,7 +66891,7 @@ var SubagentMetaObserver = class {
66509
66891
  watches = /* @__PURE__ */ new Map();
66510
66892
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
66511
66893
  resolveSubagentDir(cwd, toolSessionId) {
66512
- return import_node_path48.default.join(
66894
+ return import_node_path49.default.join(
66513
66895
  this.home,
66514
66896
  ".claude",
66515
66897
  "projects",
@@ -66539,7 +66921,7 @@ var SubagentMetaObserver = class {
66539
66921
  attachWatcher(w3) {
66540
66922
  if (w3.watcher) return;
66541
66923
  try {
66542
- w3.watcher = import_node_fs44.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
66924
+ w3.watcher = import_node_fs45.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
66543
66925
  if (!name) return;
66544
66926
  const m3 = META_RE.exec(String(name));
66545
66927
  if (!m3) return;
@@ -66551,7 +66933,7 @@ var SubagentMetaObserver = class {
66551
66933
  scan(w3) {
66552
66934
  let entries;
66553
66935
  try {
66554
- entries = import_node_fs44.default.readdirSync(w3.dirPath);
66936
+ entries = import_node_fs45.default.readdirSync(w3.dirPath);
66555
66937
  } catch {
66556
66938
  return;
66557
66939
  }
@@ -66565,10 +66947,10 @@ var SubagentMetaObserver = class {
66565
66947
  if (!m3) return;
66566
66948
  const agentId = m3[1];
66567
66949
  if (w3.emitted.has(agentId)) return;
66568
- const file = import_node_path48.default.join(w3.dirPath, name);
66950
+ const file = import_node_path49.default.join(w3.dirPath, name);
66569
66951
  let raw;
66570
66952
  try {
66571
- raw = import_node_fs44.default.readFileSync(file, "utf8");
66953
+ raw = import_node_fs45.default.readFileSync(file, "utf8");
66572
66954
  } catch {
66573
66955
  return;
66574
66956
  }
@@ -66625,14 +67007,14 @@ var SessionObserver = class {
66625
67007
  metaObserver;
66626
67008
  resolveJsonlPath(cwd, toolSessionId, override) {
66627
67009
  if (override) return override;
66628
- return import_node_path49.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
67010
+ return import_node_path50.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
66629
67011
  }
66630
67012
  start(args) {
66631
67013
  this.stop(args.sessionId);
66632
67014
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
66633
67015
  let size = 0;
66634
67016
  try {
66635
- size = import_node_fs45.default.statSync(filePath).size;
67017
+ size = import_node_fs46.default.statSync(filePath).size;
66636
67018
  } catch {
66637
67019
  }
66638
67020
  const w3 = {
@@ -66645,16 +67027,16 @@ var SessionObserver = class {
66645
67027
  adapter: args.adapter,
66646
67028
  prevIsRejectSentinel: false,
66647
67029
  toolSessionId: args.toolSessionId,
66648
- sawFile: import_node_fs45.default.existsSync(filePath),
67030
+ sawFile: import_node_fs46.default.existsSync(filePath),
66649
67031
  lastRelocateScanMs: 0,
66650
67032
  pendingCwdDerive: false,
66651
67033
  lastDeriveMs: 0
66652
67034
  };
66653
67035
  try {
66654
- import_node_fs45.default.mkdirSync(import_node_path49.default.dirname(filePath), { recursive: true });
67036
+ import_node_fs46.default.mkdirSync(import_node_path50.default.dirname(filePath), { recursive: true });
66655
67037
  } catch {
66656
67038
  }
66657
- w3.watcher = import_node_fs45.default.watch(import_node_path49.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
67039
+ w3.watcher = import_node_fs46.default.watch(import_node_path50.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
66658
67040
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
66659
67041
  this.poll(w3);
66660
67042
  });
@@ -66677,7 +67059,7 @@ var SessionObserver = class {
66677
67059
  // 异常静默吞,不阻塞 watcher 启动
66678
67060
  hydrateMetaTail(w3, maxLines = 200) {
66679
67061
  try {
66680
- const raw = import_node_fs45.default.readFileSync(w3.filePath, "utf8");
67062
+ const raw = import_node_fs46.default.readFileSync(w3.filePath, "utf8");
66681
67063
  if (!raw) return;
66682
67064
  const allLines = raw.split("\n").filter((l2) => l2.trim().length > 0);
66683
67065
  if (allLines.length === 0) return;
@@ -66701,7 +67083,7 @@ var SessionObserver = class {
66701
67083
  poll(w3) {
66702
67084
  let size = 0;
66703
67085
  try {
66704
- size = import_node_fs45.default.statSync(w3.filePath).size;
67086
+ size = import_node_fs46.default.statSync(w3.filePath).size;
66705
67087
  } catch {
66706
67088
  if (w3.sawFile) this.maybeRelocate(w3);
66707
67089
  return;
@@ -66712,11 +67094,11 @@ var SessionObserver = class {
66712
67094
  w3.buf = "";
66713
67095
  }
66714
67096
  if (size === w3.lastSize) return;
66715
- const fd = import_node_fs45.default.openSync(w3.filePath, "r");
67097
+ const fd = import_node_fs46.default.openSync(w3.filePath, "r");
66716
67098
  try {
66717
67099
  const len = size - w3.lastSize;
66718
67100
  const buf = Buffer.alloc(len);
66719
- import_node_fs45.default.readSync(fd, buf, 0, len, w3.lastSize);
67101
+ import_node_fs46.default.readSync(fd, buf, 0, len, w3.lastSize);
66720
67102
  w3.lastSize = size;
66721
67103
  w3.buf += buf.toString("utf8");
66722
67104
  let newlineIndex;
@@ -66739,7 +67121,7 @@ var SessionObserver = class {
66739
67121
  }
66740
67122
  }
66741
67123
  } finally {
66742
- import_node_fs45.default.closeSync(fd);
67124
+ import_node_fs46.default.closeSync(fd);
66743
67125
  }
66744
67126
  if (w3.pendingCwdDerive) this.maybeDeriveCwd(w3);
66745
67127
  }
@@ -66751,7 +67133,7 @@ var SessionObserver = class {
66751
67133
  const now = Date.now();
66752
67134
  if (now - w3.lastRelocateScanMs < 1e3) return;
66753
67135
  w3.lastRelocateScanMs = now;
66754
- const projectsRoot = import_node_path49.default.join(this.home, ".claude", "projects");
67136
+ const projectsRoot = import_node_path50.default.join(this.home, ".claude", "projects");
66755
67137
  const found = findTranscriptByToolSessionId(projectsRoot, w3.toolSessionId);
66756
67138
  if (!found || found === w3.filePath) return;
66757
67139
  try {
@@ -66760,7 +67142,7 @@ var SessionObserver = class {
66760
67142
  }
66761
67143
  w3.filePath = found;
66762
67144
  try {
66763
- w3.watcher = import_node_fs45.default.watch(import_node_path49.default.dirname(found), { persistent: false }, (_event, changedName) => {
67145
+ w3.watcher = import_node_fs46.default.watch(import_node_path50.default.dirname(found), { persistent: false }, (_event, changedName) => {
66764
67146
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
66765
67147
  this.poll(w3);
66766
67148
  });
@@ -66882,9 +67264,9 @@ function listRegistered() {
66882
67264
  // src/tools/title-generator.ts
66883
67265
  var import_node_child_process13 = require("child_process");
66884
67266
  init_protocol();
66885
- var import_node_fs46 = __toESM(require("fs"), 1);
67267
+ var import_node_fs47 = __toESM(require("fs"), 1);
66886
67268
  var import_node_os19 = __toESM(require("os"), 1);
66887
- var import_node_path50 = __toESM(require("path"), 1);
67269
+ var import_node_path51 = __toESM(require("path"), 1);
66888
67270
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
66889
67271
  var TITLE_INPUT_MAX_CHARS = 400;
66890
67272
  var DEFAULT_TITLE_GEN_TIMEOUT_MS = 45e3;
@@ -66975,21 +67357,21 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
66975
67357
  }
66976
67358
  let workDir;
66977
67359
  try {
66978
- workDir = import_node_fs46.default.mkdtempSync(import_node_path50.default.join(import_node_os19.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
67360
+ workDir = import_node_fs47.default.mkdtempSync(import_node_path51.default.join(import_node_os19.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
66979
67361
  } catch {
66980
67362
  return null;
66981
67363
  }
66982
67364
  const cleanupWorkDir = () => {
66983
67365
  try {
66984
- import_node_fs46.default.rmSync(workDir, { recursive: true, force: true });
67366
+ import_node_fs47.default.rmSync(workDir, { recursive: true, force: true });
66985
67367
  } catch {
66986
67368
  }
66987
67369
  };
66988
- const outFile = import_node_path50.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
66989
- const schemaFile = import_node_path50.default.join(workDir, "title-schema.json");
67370
+ const outFile = import_node_path51.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
67371
+ const schemaFile = import_node_path51.default.join(workDir, "title-schema.json");
66990
67372
  if (tool === "codex") {
66991
67373
  try {
66992
- import_node_fs46.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
67374
+ import_node_fs47.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
66993
67375
  } catch {
66994
67376
  cleanupWorkDir();
66995
67377
  return null;
@@ -67044,7 +67426,7 @@ async function generateSessionTitle(file, firstMessage, deps = {}) {
67044
67426
  if (tool === "claude" || tool === "pi") return finish(parseTitleJson(stdout));
67045
67427
  let fileText = "";
67046
67428
  try {
67047
- fileText = import_node_fs46.default.readFileSync(outFile, "utf8");
67429
+ fileText = import_node_fs47.default.readFileSync(outFile, "utf8");
67048
67430
  } catch {
67049
67431
  return finish(null);
67050
67432
  }
@@ -67117,7 +67499,7 @@ var wrapper_default = import_websocket.default;
67117
67499
 
67118
67500
  // src/transport/local-ws-server.ts
67119
67501
  var import_node_http = __toESM(require("http"), 1);
67120
- var import_node_crypto15 = require("crypto");
67502
+ var import_node_crypto16 = require("crypto");
67121
67503
  var LocalWsServer = class {
67122
67504
  constructor(opts) {
67123
67505
  this.opts = opts;
@@ -67334,7 +67716,7 @@ var LocalWsServer = class {
67334
67716
  }
67335
67717
  }
67336
67718
  onConnection(socket, remoteAddress) {
67337
- const id = (0, import_node_crypto15.randomUUID)();
67719
+ const id = (0, import_node_crypto16.randomUUID)();
67338
67720
  const subscribedSessions = /* @__PURE__ */ new Map();
67339
67721
  const handle = {
67340
67722
  id,
@@ -67740,8 +68122,8 @@ async function authenticate(token, deps) {
67740
68122
  }
67741
68123
 
67742
68124
  // src/legacy-cleanup.ts
67743
- var fs57 = __toESM(require("fs/promises"), 1);
67744
- var path58 = __toESM(require("path"), 1);
68125
+ var fs58 = __toESM(require("fs/promises"), 1);
68126
+ var path59 = __toESM(require("path"), 1);
67745
68127
  var LEGACY_FILES = [
67746
68128
  "personal-capability.json",
67747
68129
  "received-capabilities.json",
@@ -67750,9 +68132,9 @@ var LEGACY_FILES = [
67750
68132
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
67751
68133
  const removed = [];
67752
68134
  for (const name of LEGACY_FILES) {
67753
- const p3 = path58.join(dataDir, name);
68135
+ const p3 = path59.join(dataDir, name);
67754
68136
  try {
67755
- await fs57.unlink(p3);
68137
+ await fs58.unlink(p3);
67756
68138
  removed.push(name);
67757
68139
  logger.debug("legacy capability file removed", { file: name });
67758
68140
  } catch (err) {
@@ -67764,13 +68146,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
67764
68146
  }
67765
68147
 
67766
68148
  // src/inbox/inbox-store.ts
67767
- var fs58 = __toESM(require("fs"), 1);
67768
- var path59 = __toESM(require("path"), 1);
68149
+ var fs59 = __toESM(require("fs"), 1);
68150
+ var path60 = __toESM(require("path"), 1);
67769
68151
  var INBOX_SUBDIR = "inbox";
67770
68152
  var InboxStore = class {
67771
68153
  constructor(dataDir) {
67772
68154
  this.dataDir = dataDir;
67773
- fs58.mkdirSync(this.dirPath(), { recursive: true });
68155
+ fs59.mkdirSync(this.dirPath(), { recursive: true });
67774
68156
  }
67775
68157
  dataDir;
67776
68158
  /**
@@ -67782,7 +68164,7 @@ var InboxStore = class {
67782
68164
  const file = this.filePath(peerDeviceId);
67783
68165
  let raw;
67784
68166
  try {
67785
- raw = fs58.readFileSync(file, "utf8");
68167
+ raw = fs59.readFileSync(file, "utf8");
67786
68168
  } catch (err) {
67787
68169
  if (err?.code === "ENOENT") return [];
67788
68170
  return [];
@@ -67798,7 +68180,7 @@ var InboxStore = class {
67798
68180
  const dir = this.dirPath();
67799
68181
  let entries;
67800
68182
  try {
67801
- entries = fs58.readdirSync(dir);
68183
+ entries = fs59.readdirSync(dir);
67802
68184
  } catch (err) {
67803
68185
  if (err?.code === "ENOENT") return [];
67804
68186
  return [];
@@ -67814,9 +68196,9 @@ var InboxStore = class {
67814
68196
  if (existing.some((m3) => m3.id === message.id)) return;
67815
68197
  const file = this.filePath(message.peerDeviceId);
67816
68198
  const line = JSON.stringify(message) + "\n";
67817
- fs58.appendFileSync(file, line, { mode: 384 });
68199
+ fs59.appendFileSync(file, line, { mode: 384 });
67818
68200
  try {
67819
- fs58.chmodSync(file, 384);
68201
+ fs59.chmodSync(file, 384);
67820
68202
  } catch {
67821
68203
  }
67822
68204
  }
@@ -67846,7 +68228,7 @@ var InboxStore = class {
67846
68228
  removeByPeerDeviceId(peerDeviceId) {
67847
68229
  const file = this.filePath(peerDeviceId);
67848
68230
  try {
67849
- fs58.unlinkSync(file);
68231
+ fs59.unlinkSync(file);
67850
68232
  } catch (err) {
67851
68233
  if (err?.code === "ENOENT") return;
67852
68234
  }
@@ -67855,18 +68237,18 @@ var InboxStore = class {
67855
68237
  const file = this.filePath(peerDeviceId);
67856
68238
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
67857
68239
  const content = messages.map((m3) => JSON.stringify(m3)).join("\n") + (messages.length > 0 ? "\n" : "");
67858
- fs58.writeFileSync(tmp, content, { mode: 384 });
67859
- fs58.renameSync(tmp, file);
68240
+ fs59.writeFileSync(tmp, content, { mode: 384 });
68241
+ fs59.renameSync(tmp, file);
67860
68242
  try {
67861
- fs58.chmodSync(file, 384);
68243
+ fs59.chmodSync(file, 384);
67862
68244
  } catch {
67863
68245
  }
67864
68246
  }
67865
68247
  dirPath() {
67866
- return path59.join(this.dataDir, INBOX_SUBDIR);
68248
+ return path60.join(this.dataDir, INBOX_SUBDIR);
67867
68249
  }
67868
68250
  filePath(peerDeviceId) {
67869
- return path59.join(this.dirPath(), `${peerDeviceId}.jsonl`);
68251
+ return path60.join(this.dirPath(), `${peerDeviceId}.jsonl`);
67870
68252
  }
67871
68253
  };
67872
68254
  function parseAllLines(raw) {
@@ -67954,8 +68336,8 @@ var InboxManager = class {
67954
68336
  };
67955
68337
 
67956
68338
  // src/state/contact-store.ts
67957
- var fs59 = __toESM(require("fs"), 1);
67958
- var path60 = __toESM(require("path"), 1);
68339
+ var fs60 = __toESM(require("fs"), 1);
68340
+ var path61 = __toESM(require("path"), 1);
67959
68341
  var FILE_NAME = "contacts.json";
67960
68342
  var ContactStore = class {
67961
68343
  constructor(dataDir) {
@@ -67965,10 +68347,10 @@ var ContactStore = class {
67965
68347
  contacts = /* @__PURE__ */ new Map();
67966
68348
  load() {
67967
68349
  this.contacts.clear();
67968
- const file = path60.join(this.dataDir, FILE_NAME);
68350
+ const file = path61.join(this.dataDir, FILE_NAME);
67969
68351
  let raw;
67970
68352
  try {
67971
- raw = fs59.readFileSync(file, "utf8");
68353
+ raw = fs60.readFileSync(file, "utf8");
67972
68354
  } catch (err) {
67973
68355
  if (err?.code !== "ENOENT") this.renameBak(file);
67974
68356
  return;
@@ -68049,20 +68431,20 @@ var ContactStore = class {
68049
68431
  return true;
68050
68432
  }
68051
68433
  flush() {
68052
- const file = path60.join(this.dataDir, FILE_NAME);
68434
+ const file = path61.join(this.dataDir, FILE_NAME);
68053
68435
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
68054
68436
  const content = JSON.stringify(
68055
68437
  { contacts: Array.from(this.contacts.values()) },
68056
68438
  null,
68057
68439
  2
68058
68440
  );
68059
- fs59.mkdirSync(this.dataDir, { recursive: true });
68060
- fs59.writeFileSync(tmp, content, { mode: 384 });
68061
- fs59.renameSync(tmp, file);
68441
+ fs60.mkdirSync(this.dataDir, { recursive: true });
68442
+ fs60.writeFileSync(tmp, content, { mode: 384 });
68443
+ fs60.renameSync(tmp, file);
68062
68444
  }
68063
68445
  renameBak(file) {
68064
68446
  try {
68065
- fs59.renameSync(file, `${file}.bak`);
68447
+ fs60.renameSync(file, `${file}.bak`);
68066
68448
  } catch {
68067
68449
  }
68068
68450
  }
@@ -68170,61 +68552,61 @@ async function connectRemote(args) {
68170
68552
  }
68171
68553
 
68172
68554
  // src/migrations/2026-05-20-flatten-sessions.ts
68173
- var fs60 = __toESM(require("fs"), 1);
68174
- var path61 = __toESM(require("path"), 1);
68555
+ var fs61 = __toESM(require("fs"), 1);
68556
+ var path62 = __toESM(require("path"), 1);
68175
68557
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
68176
68558
  function migrateFlattenSessions(opts) {
68177
68559
  const dataDir = opts.dataDir;
68178
68560
  const now = opts.now ?? Date.now;
68179
- const sessionsDir = path61.join(dataDir, "sessions");
68180
- const flagPath = path61.join(sessionsDir, MIGRATION_FLAG_NAME);
68561
+ const sessionsDir = path62.join(dataDir, "sessions");
68562
+ const flagPath = path62.join(sessionsDir, MIGRATION_FLAG_NAME);
68181
68563
  if (existsSync3(flagPath)) {
68182
68564
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
68183
68565
  }
68184
68566
  let movedBare = 0;
68185
68567
  let movedVmOwner = 0;
68186
68568
  let archivedListener = 0;
68187
- const defaultDir = path61.join(sessionsDir, "default");
68569
+ const defaultDir = path62.join(sessionsDir, "default");
68188
68570
  if (existsSync3(defaultDir)) {
68189
68571
  for (const entry of readdirSafe(defaultDir)) {
68190
68572
  if (!entry.endsWith(".json")) continue;
68191
- const src = path61.join(defaultDir, entry);
68192
- const dst = path61.join(sessionsDir, entry);
68193
- fs60.renameSync(src, dst);
68573
+ const src = path62.join(defaultDir, entry);
68574
+ const dst = path62.join(sessionsDir, entry);
68575
+ fs61.renameSync(src, dst);
68194
68576
  movedBare += 1;
68195
68577
  }
68196
68578
  rmdirIfEmpty(defaultDir);
68197
68579
  }
68198
68580
  for (const pid of readdirSafe(sessionsDir)) {
68199
- const personaDir = path61.join(sessionsDir, pid);
68581
+ const personaDir = path62.join(sessionsDir, pid);
68200
68582
  if (!isDir(personaDir)) continue;
68201
68583
  if (pid === "default") continue;
68202
- const ownerSrc = path61.join(personaDir, "owner");
68584
+ const ownerSrc = path62.join(personaDir, "owner");
68203
68585
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
68204
- const ownerDst = path61.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
68205
- fs60.mkdirSync(ownerDst, { recursive: true });
68586
+ const ownerDst = path62.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
68587
+ fs61.mkdirSync(ownerDst, { recursive: true });
68206
68588
  for (const file of readdirSafe(ownerSrc)) {
68207
68589
  if (!file.endsWith(".json")) continue;
68208
- fs60.renameSync(path61.join(ownerSrc, file), path61.join(ownerDst, file));
68590
+ fs61.renameSync(path62.join(ownerSrc, file), path62.join(ownerDst, file));
68209
68591
  movedVmOwner += 1;
68210
68592
  }
68211
68593
  rmdirIfEmpty(ownerSrc);
68212
68594
  }
68213
- const listenerSrc = path61.join(personaDir, "listener");
68595
+ const listenerSrc = path62.join(personaDir, "listener");
68214
68596
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
68215
- const archiveDst = path61.join(dataDir, ".legacy", `listener-${pid}`);
68216
- fs60.mkdirSync(archiveDst, { recursive: true });
68597
+ const archiveDst = path62.join(dataDir, ".legacy", `listener-${pid}`);
68598
+ fs61.mkdirSync(archiveDst, { recursive: true });
68217
68599
  for (const file of readdirSafe(listenerSrc)) {
68218
68600
  if (!file.endsWith(".json")) continue;
68219
- fs60.renameSync(path61.join(listenerSrc, file), path61.join(archiveDst, file));
68601
+ fs61.renameSync(path62.join(listenerSrc, file), path62.join(archiveDst, file));
68220
68602
  archivedListener += 1;
68221
68603
  }
68222
68604
  rmdirIfEmpty(listenerSrc);
68223
68605
  }
68224
68606
  rmdirIfEmpty(personaDir);
68225
68607
  }
68226
- fs60.mkdirSync(sessionsDir, { recursive: true });
68227
- fs60.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
68608
+ fs61.mkdirSync(sessionsDir, { recursive: true });
68609
+ fs61.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
68228
68610
  return {
68229
68611
  skipped: false,
68230
68612
  flagWritten: true,
@@ -68235,7 +68617,7 @@ function migrateFlattenSessions(opts) {
68235
68617
  }
68236
68618
  function existsSync3(p3) {
68237
68619
  try {
68238
- fs60.statSync(p3);
68620
+ fs61.statSync(p3);
68239
68621
  return true;
68240
68622
  } catch {
68241
68623
  return false;
@@ -68243,63 +68625,63 @@ function existsSync3(p3) {
68243
68625
  }
68244
68626
  function isDir(p3) {
68245
68627
  try {
68246
- return fs60.statSync(p3).isDirectory();
68628
+ return fs61.statSync(p3).isDirectory();
68247
68629
  } catch {
68248
68630
  return false;
68249
68631
  }
68250
68632
  }
68251
68633
  function readdirSafe(p3) {
68252
68634
  try {
68253
- return fs60.readdirSync(p3);
68635
+ return fs61.readdirSync(p3);
68254
68636
  } catch {
68255
68637
  return [];
68256
68638
  }
68257
68639
  }
68258
68640
  function rmdirIfEmpty(p3) {
68259
68641
  try {
68260
- fs60.rmdirSync(p3);
68642
+ fs61.rmdirSync(p3);
68261
68643
  } catch {
68262
68644
  }
68263
68645
  }
68264
68646
 
68265
68647
  // src/migrations/2026-08-18-drop-seeded-projects.ts
68266
- var fs61 = __toESM(require("fs"), 1);
68267
- var path62 = __toESM(require("path"), 1);
68648
+ var fs62 = __toESM(require("fs"), 1);
68649
+ var path63 = __toESM(require("path"), 1);
68268
68650
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
68269
68651
  function dropSeededProjects(opts) {
68270
- fs61.mkdirSync(opts.dataDir, { recursive: true });
68271
- const flag = path62.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
68272
- if (fs61.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
68273
- const file = path62.join(opts.dataDir, "projects.json");
68652
+ fs62.mkdirSync(opts.dataDir, { recursive: true });
68653
+ const flag = path63.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
68654
+ if (fs62.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
68655
+ const file = path63.join(opts.dataDir, "projects.json");
68274
68656
  let raw = null;
68275
68657
  let dropped = 0;
68276
68658
  try {
68277
- raw = fs61.readFileSync(file, "utf8");
68659
+ raw = fs62.readFileSync(file, "utf8");
68278
68660
  dropped = JSON.parse(raw).projects?.length ?? 0;
68279
68661
  } catch {
68280
68662
  }
68281
68663
  let backup = null;
68282
68664
  if (raw != null && dropped > 0) {
68283
- const dir = path62.join(opts.dataDir, "backups");
68284
- fs61.mkdirSync(dir, { recursive: true });
68285
- backup = path62.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
68286
- fs61.writeFileSync(backup, raw);
68665
+ const dir = path63.join(opts.dataDir, "backups");
68666
+ fs62.mkdirSync(dir, { recursive: true });
68667
+ backup = path63.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
68668
+ fs62.writeFileSync(backup, raw);
68287
68669
  }
68288
68670
  if (raw != null || dropped > 0) {
68289
- fs61.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
68671
+ fs62.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
68290
68672
  }
68291
- fs61.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
68673
+ fs62.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
68292
68674
  return { skipped: false, dropped, backup };
68293
68675
  }
68294
68676
 
68295
68677
  // src/transport/http-router.ts
68296
- var import_node_fs48 = __toESM(require("fs"), 1);
68297
- var import_node_path53 = __toESM(require("path"), 1);
68678
+ var import_node_fs49 = __toESM(require("fs"), 1);
68679
+ var import_node_path54 = __toESM(require("path"), 1);
68298
68680
 
68299
68681
  // src/attachment/upload.ts
68300
- var import_node_fs47 = __toESM(require("fs"), 1);
68301
- var import_node_path51 = __toESM(require("path"), 1);
68302
- var import_node_crypto16 = __toESM(require("crypto"), 1);
68682
+ var import_node_fs48 = __toESM(require("fs"), 1);
68683
+ var import_node_path52 = __toESM(require("path"), 1);
68684
+ var import_node_crypto17 = __toESM(require("crypto"), 1);
68303
68685
  var import_promises8 = require("stream/promises");
68304
68686
  var UploadError = class extends Error {
68305
68687
  constructor(code, message) {
@@ -68310,24 +68692,24 @@ var UploadError = class extends Error {
68310
68692
  code;
68311
68693
  };
68312
68694
  function assertValidFileName(fileName) {
68313
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path51.default.basename(fileName)) {
68695
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path52.default.basename(fileName)) {
68314
68696
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
68315
68697
  }
68316
68698
  }
68317
68699
  var HASH_PREFIX_LEN = 16;
68318
68700
  async function writeUploadedAttachment(args) {
68319
68701
  assertValidFileName(args.fileName);
68320
- const attachmentsRoot = import_node_path51.default.join(args.baseDir, ".attachments");
68702
+ const attachmentsRoot = import_node_path52.default.join(args.baseDir, ".attachments");
68321
68703
  try {
68322
- import_node_fs47.default.mkdirSync(attachmentsRoot, { recursive: true });
68704
+ import_node_fs48.default.mkdirSync(attachmentsRoot, { recursive: true });
68323
68705
  } catch (err) {
68324
68706
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
68325
68707
  }
68326
- const hasher = import_node_crypto16.default.createHash("sha256");
68708
+ const hasher = import_node_crypto17.default.createHash("sha256");
68327
68709
  let actualSize = 0;
68328
- const tmpPath = import_node_path51.default.join(
68710
+ const tmpPath = import_node_path52.default.join(
68329
68711
  attachmentsRoot,
68330
- `.upload-${process.pid}-${Date.now()}-${import_node_crypto16.default.randomBytes(4).toString("hex")}`
68712
+ `.upload-${process.pid}-${Date.now()}-${import_node_crypto17.default.randomBytes(4).toString("hex")}`
68331
68713
  );
68332
68714
  try {
68333
68715
  await (0, import_promises8.pipeline)(
@@ -68340,18 +68722,18 @@ async function writeUploadedAttachment(args) {
68340
68722
  yield buf;
68341
68723
  }
68342
68724
  },
68343
- import_node_fs47.default.createWriteStream(tmpPath, { mode: 384 })
68725
+ import_node_fs48.default.createWriteStream(tmpPath, { mode: 384 })
68344
68726
  );
68345
68727
  } catch (err) {
68346
68728
  try {
68347
- import_node_fs47.default.unlinkSync(tmpPath);
68729
+ import_node_fs48.default.unlinkSync(tmpPath);
68348
68730
  } catch {
68349
68731
  }
68350
68732
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
68351
68733
  }
68352
68734
  if (actualSize !== args.contentLength) {
68353
68735
  try {
68354
- import_node_fs47.default.unlinkSync(tmpPath);
68736
+ import_node_fs48.default.unlinkSync(tmpPath);
68355
68737
  } catch {
68356
68738
  }
68357
68739
  throw new UploadError(
@@ -68360,34 +68742,34 @@ async function writeUploadedAttachment(args) {
68360
68742
  );
68361
68743
  }
68362
68744
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
68363
- const hashDir = import_node_path51.default.join(attachmentsRoot, attachmentId);
68745
+ const hashDir = import_node_path52.default.join(attachmentsRoot, attachmentId);
68364
68746
  let finalFileName;
68365
68747
  let hashDirExists = false;
68366
68748
  try {
68367
- hashDirExists = import_node_fs47.default.statSync(hashDir).isDirectory();
68749
+ hashDirExists = import_node_fs48.default.statSync(hashDir).isDirectory();
68368
68750
  } catch {
68369
68751
  }
68370
68752
  if (hashDirExists) {
68371
- const existing = import_node_fs47.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
68753
+ const existing = import_node_fs48.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
68372
68754
  finalFileName = existing[0] ?? args.fileName;
68373
68755
  try {
68374
- import_node_fs47.default.unlinkSync(tmpPath);
68756
+ import_node_fs48.default.unlinkSync(tmpPath);
68375
68757
  } catch {
68376
68758
  }
68377
68759
  } else {
68378
68760
  try {
68379
- import_node_fs47.default.mkdirSync(hashDir, { recursive: true });
68761
+ import_node_fs48.default.mkdirSync(hashDir, { recursive: true });
68380
68762
  finalFileName = args.fileName;
68381
- import_node_fs47.default.renameSync(tmpPath, import_node_path51.default.join(hashDir, finalFileName));
68763
+ import_node_fs48.default.renameSync(tmpPath, import_node_path52.default.join(hashDir, finalFileName));
68382
68764
  } catch (err) {
68383
68765
  try {
68384
- import_node_fs47.default.unlinkSync(tmpPath);
68766
+ import_node_fs48.default.unlinkSync(tmpPath);
68385
68767
  } catch {
68386
68768
  }
68387
68769
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
68388
68770
  }
68389
68771
  }
68390
- const absPath = import_node_path51.default.join(hashDir, finalFileName);
68772
+ const absPath = import_node_path52.default.join(hashDir, finalFileName);
68391
68773
  const relPath = absPath;
68392
68774
  args.groupFileStore.upsert(args.scope, args.sessionId, {
68393
68775
  relPath: absPath,
@@ -68402,7 +68784,7 @@ async function writeUploadedAttachment(args) {
68402
68784
 
68403
68785
  // src/extension/import.ts
68404
68786
  var import_promises9 = __toESM(require("fs/promises"), 1);
68405
- var import_node_path52 = __toESM(require("path"), 1);
68787
+ var import_node_path53 = __toESM(require("path"), 1);
68406
68788
  var import_node_os20 = __toESM(require("os"), 1);
68407
68789
  var import_jszip = __toESM(require_lib3(), 1);
68408
68790
  var ImportError = class extends Error {
@@ -68420,7 +68802,7 @@ async function importZip(buf, root) {
68420
68802
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
68421
68803
  }
68422
68804
  for (const name of Object.keys(zip.files)) {
68423
- if (name.includes("..") || name.startsWith("/") || import_node_path52.default.isAbsolute(name)) {
68805
+ if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
68424
68806
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
68425
68807
  }
68426
68808
  }
@@ -68453,7 +68835,7 @@ async function importZip(buf, root) {
68453
68835
  );
68454
68836
  }
68455
68837
  }
68456
- const destDir = import_node_path52.default.join(root, manifest.id);
68838
+ const destDir = import_node_path53.default.join(root, manifest.id);
68457
68839
  let destExists = false;
68458
68840
  try {
68459
68841
  await import_promises9.default.access(destDir);
@@ -68463,15 +68845,15 @@ async function importZip(buf, root) {
68463
68845
  if (destExists) {
68464
68846
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
68465
68847
  }
68466
- const stage = await import_promises9.default.mkdtemp(import_node_path52.default.join(import_node_os20.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
68848
+ const stage = await import_promises9.default.mkdtemp(import_node_path53.default.join(import_node_os20.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
68467
68849
  try {
68468
68850
  for (const [name, entry] of Object.entries(zip.files)) {
68469
- const dest = import_node_path52.default.join(stage, name);
68851
+ const dest = import_node_path53.default.join(stage, name);
68470
68852
  if (entry.dir) {
68471
68853
  await import_promises9.default.mkdir(dest, { recursive: true });
68472
68854
  continue;
68473
68855
  }
68474
- await import_promises9.default.mkdir(import_node_path52.default.dirname(dest), { recursive: true });
68856
+ await import_promises9.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
68475
68857
  const content = await entry.async("nodebuffer");
68476
68858
  await import_promises9.default.writeFile(dest, content);
68477
68859
  }
@@ -68525,7 +68907,7 @@ var SHARE_UI_ASSET_MIME = {
68525
68907
  ".wasm": "application/wasm"
68526
68908
  };
68527
68909
  function shareUiAssetMime(filePath) {
68528
- const ext = import_node_path53.default.extname(filePath).toLowerCase();
68910
+ const ext = import_node_path54.default.extname(filePath).toLowerCase();
68529
68911
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
68530
68912
  }
68531
68913
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -68624,7 +69006,7 @@ function isValidUploadFileName(fileName) {
68624
69006
  if (fileName === "." || fileName === "..") return false;
68625
69007
  if (fileName.startsWith(".")) return false;
68626
69008
  if (fileName.includes("/") || fileName.includes("\\")) return false;
68627
- return fileName === import_node_path53.default.basename(fileName);
69009
+ return fileName === import_node_path54.default.basename(fileName);
68628
69010
  }
68629
69011
  function createHttpRouter(deps) {
68630
69012
  return async (req, res) => {
@@ -68708,7 +69090,7 @@ function createHttpRouter(deps) {
68708
69090
  }
68709
69091
  let buf;
68710
69092
  try {
68711
- buf = await import_node_fs48.default.promises.readFile(abs);
69093
+ buf = await import_node_fs49.default.promises.readFile(abs);
68712
69094
  } catch {
68713
69095
  sendJson2(res, 404, { code: "NOT_FOUND", message: "asset not found" });
68714
69096
  return true;
@@ -68854,7 +69236,7 @@ function createHttpRouter(deps) {
68854
69236
  sendHtml(res, statusByCode[r2.code], loader.renderErrorHtml(r2.code, msgByCode[r2.code]));
68855
69237
  return true;
68856
69238
  }
68857
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path53.default.basename(r2.absPath)));
69239
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path54.default.basename(r2.absPath)));
68858
69240
  return true;
68859
69241
  }
68860
69242
  const ctx = deps.authResolver.resolveFromHeader(
@@ -68975,7 +69357,7 @@ function createHttpRouter(deps) {
68975
69357
  return true;
68976
69358
  }
68977
69359
  let absPath;
68978
- if (import_node_path53.default.isAbsolute(pathParam)) {
69360
+ if (import_node_path54.default.isAbsolute(pathParam)) {
68979
69361
  absPath = pathParam;
68980
69362
  } else if (deps.sessionStore) {
68981
69363
  const file = deps.sessionStore.read(sid);
@@ -68983,7 +69365,7 @@ function createHttpRouter(deps) {
68983
69365
  sendJson2(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
68984
69366
  return true;
68985
69367
  }
68986
- absPath = import_node_path53.default.join(file.cwd, pathParam);
69368
+ absPath = import_node_path54.default.join(file.cwd, pathParam);
68987
69369
  } else {
68988
69370
  sendJson2(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
68989
69371
  return true;
@@ -69067,7 +69449,7 @@ function withCtx(ctx, body) {
69067
69449
  function streamFile(res, absPath, logger) {
69068
69450
  let stat;
69069
69451
  try {
69070
- stat = import_node_fs48.default.statSync(absPath);
69452
+ stat = import_node_fs49.default.statSync(absPath);
69071
69453
  } catch (err) {
69072
69454
  const code = err?.code;
69073
69455
  if (code === "ENOENT") {
@@ -69082,7 +69464,7 @@ function streamFile(res, absPath, logger) {
69082
69464
  return;
69083
69465
  }
69084
69466
  const mime = lookupMime(absPath);
69085
- const basename2 = import_node_path53.default.basename(absPath);
69467
+ const basename2 = import_node_path54.default.basename(absPath);
69086
69468
  res.writeHead(200, {
69087
69469
  "Content-Type": mime,
69088
69470
  "Content-Length": String(stat.size),
@@ -69090,7 +69472,7 @@ function streamFile(res, absPath, logger) {
69090
69472
  // 防止浏览器把任意 mime 当 html 渲染
69091
69473
  "X-Content-Type-Options": "nosniff"
69092
69474
  });
69093
- const stream = import_node_fs48.default.createReadStream(absPath);
69475
+ const stream = import_node_fs49.default.createReadStream(absPath);
69094
69476
  stream.on("error", (err) => {
69095
69477
  logger?.warn("streamFile read error", { absPath, err: err.message });
69096
69478
  res.destroy();
@@ -69099,8 +69481,8 @@ function streamFile(res, absPath, logger) {
69099
69481
  }
69100
69482
 
69101
69483
  // src/attachment/gc.ts
69102
- var import_node_fs49 = __toESM(require("fs"), 1);
69103
- var import_node_path54 = __toESM(require("path"), 1);
69484
+ var import_node_fs50 = __toESM(require("fs"), 1);
69485
+ var import_node_path55 = __toESM(require("path"), 1);
69104
69486
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
69105
69487
  function runAttachmentGc(args) {
69106
69488
  const now = (args.now ?? Date.now)();
@@ -69109,12 +69491,12 @@ function runAttachmentGc(args) {
69109
69491
  for (const { scope, sessionId } of args.sessionScopes) {
69110
69492
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
69111
69493
  if (entry.stale) continue;
69112
- if (import_node_path54.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
69494
+ if (import_node_path55.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
69113
69495
  }
69114
69496
  }
69115
69497
  const visited = /* @__PURE__ */ new Set();
69116
69498
  for (const { scope, sessionId } of args.sessionScopes) {
69117
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path54.default.join(
69499
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path55.default.join(
69118
69500
  args.dataDir,
69119
69501
  "sessions",
69120
69502
  ...scopeSubPath(scope).map(safeFileName),
@@ -69127,28 +69509,28 @@ function runAttachmentGc(args) {
69127
69509
  return true;
69128
69510
  });
69129
69511
  for (const rootDir of roots) {
69130
- const attRoot = import_node_path54.default.join(rootDir, ".attachments");
69512
+ const attRoot = import_node_path55.default.join(rootDir, ".attachments");
69131
69513
  let hashDirs;
69132
69514
  try {
69133
- hashDirs = import_node_fs49.default.readdirSync(attRoot);
69515
+ hashDirs = import_node_fs50.default.readdirSync(attRoot);
69134
69516
  } catch (err) {
69135
69517
  if (err.code === "ENOENT") continue;
69136
69518
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
69137
69519
  continue;
69138
69520
  }
69139
69521
  for (const hashDir of hashDirs) {
69140
- const hashDirAbs = import_node_path54.default.join(attRoot, hashDir);
69522
+ const hashDirAbs = import_node_path55.default.join(attRoot, hashDir);
69141
69523
  let files;
69142
69524
  try {
69143
- files = import_node_fs49.default.readdirSync(hashDirAbs);
69525
+ files = import_node_fs50.default.readdirSync(hashDirAbs);
69144
69526
  } catch {
69145
69527
  continue;
69146
69528
  }
69147
69529
  for (const name of files) {
69148
- const file = import_node_path54.default.join(hashDirAbs, name);
69530
+ const file = import_node_path55.default.join(hashDirAbs, name);
69149
69531
  let stat;
69150
69532
  try {
69151
- stat = import_node_fs49.default.statSync(file);
69533
+ stat = import_node_fs50.default.statSync(file);
69152
69534
  } catch {
69153
69535
  continue;
69154
69536
  }
@@ -69157,18 +69539,18 @@ function runAttachmentGc(args) {
69157
69539
  if (age < ttlMs) continue;
69158
69540
  if (liveAbs.has(file)) continue;
69159
69541
  try {
69160
- import_node_fs49.default.unlinkSync(file);
69542
+ import_node_fs50.default.unlinkSync(file);
69161
69543
  } catch (err) {
69162
69544
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
69163
69545
  }
69164
69546
  }
69165
69547
  try {
69166
- if (import_node_fs49.default.readdirSync(hashDirAbs).length === 0) import_node_fs49.default.rmdirSync(hashDirAbs);
69548
+ if (import_node_fs50.default.readdirSync(hashDirAbs).length === 0) import_node_fs50.default.rmdirSync(hashDirAbs);
69167
69549
  } catch {
69168
69550
  }
69169
69551
  }
69170
69552
  try {
69171
- if (import_node_fs49.default.readdirSync(attRoot).length === 0) import_node_fs49.default.rmdirSync(attRoot);
69553
+ if (import_node_fs50.default.readdirSync(attRoot).length === 0) import_node_fs50.default.rmdirSync(attRoot);
69172
69554
  } catch {
69173
69555
  }
69174
69556
  }
@@ -69176,9 +69558,9 @@ function runAttachmentGc(args) {
69176
69558
  }
69177
69559
 
69178
69560
  // src/attachment/group.ts
69179
- var import_node_fs50 = __toESM(require("fs"), 1);
69180
- var import_node_path55 = __toESM(require("path"), 1);
69181
- var import_node_crypto17 = __toESM(require("crypto"), 1);
69561
+ var import_node_fs51 = __toESM(require("fs"), 1);
69562
+ var import_node_path56 = __toESM(require("path"), 1);
69563
+ var import_node_crypto18 = __toESM(require("crypto"), 1);
69182
69564
  init_protocol();
69183
69565
  var GroupFileStore = class {
69184
69566
  dataDir;
@@ -69189,11 +69571,11 @@ var GroupFileStore = class {
69189
69571
  this.logger = opts.logger;
69190
69572
  }
69191
69573
  rootForScope(scope) {
69192
- return import_node_path55.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
69574
+ return import_node_path56.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
69193
69575
  }
69194
69576
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
69195
69577
  filePath(scope, sessionId) {
69196
- return import_node_path55.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
69578
+ return import_node_path56.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
69197
69579
  }
69198
69580
  cacheKey(scope, sessionId) {
69199
69581
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -69202,7 +69584,7 @@ var GroupFileStore = class {
69202
69584
  readFile(scope, sessionId) {
69203
69585
  const file = this.filePath(scope, sessionId);
69204
69586
  try {
69205
- const raw = import_node_fs50.default.readFileSync(file, "utf8");
69587
+ const raw = import_node_fs51.default.readFileSync(file, "utf8");
69206
69588
  const parsed = JSON.parse(raw);
69207
69589
  if (!Array.isArray(parsed)) {
69208
69590
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -69228,10 +69610,10 @@ var GroupFileStore = class {
69228
69610
  }
69229
69611
  writeFile(scope, sessionId, entries) {
69230
69612
  const file = this.filePath(scope, sessionId);
69231
- import_node_fs50.default.mkdirSync(import_node_path55.default.dirname(file), { recursive: true });
69613
+ import_node_fs51.default.mkdirSync(import_node_path56.default.dirname(file), { recursive: true });
69232
69614
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
69233
- import_node_fs50.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
69234
- import_node_fs50.default.renameSync(tmp, file);
69615
+ import_node_fs51.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
69616
+ import_node_fs51.default.renameSync(tmp, file);
69235
69617
  }
69236
69618
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
69237
69619
  list(scope, sessionId) {
@@ -69267,7 +69649,7 @@ var GroupFileStore = class {
69267
69649
  entries[idx] = next;
69268
69650
  } else {
69269
69651
  next = {
69270
- id: `gf-${import_node_crypto17.default.randomBytes(6).toString("base64url")}`,
69652
+ id: `gf-${import_node_crypto18.default.randomBytes(6).toString("base64url")}`,
69271
69653
  relPath: input.relPath,
69272
69654
  from: input.from,
69273
69655
  label: input.label,
@@ -69323,7 +69705,7 @@ var GroupFileStore = class {
69323
69705
  */
69324
69706
  deleteSession(scope, sessionId) {
69325
69707
  try {
69326
- import_node_fs50.default.unlinkSync(this.filePath(scope, sessionId));
69708
+ import_node_fs51.default.unlinkSync(this.filePath(scope, sessionId));
69327
69709
  } catch (err) {
69328
69710
  if (err?.code !== "ENOENT") throw err;
69329
69711
  }
@@ -69336,7 +69718,7 @@ var GroupFileStore = class {
69336
69718
  * 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
69337
69719
  */
69338
69720
  deletePersona(personaId2) {
69339
- import_node_fs50.default.rmSync(import_node_path55.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
69721
+ import_node_fs51.default.rmSync(import_node_path56.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
69340
69722
  const prefix = `persona:${personaId2}:`;
69341
69723
  for (const key of this.cache.keys()) {
69342
69724
  if (key.startsWith(prefix)) this.cache.delete(key);
@@ -69345,10 +69727,10 @@ var GroupFileStore = class {
69345
69727
  };
69346
69728
 
69347
69729
  // src/discovery/state-file.ts
69348
- var import_node_fs51 = __toESM(require("fs"), 1);
69349
- var import_node_path56 = __toESM(require("path"), 1);
69730
+ var import_node_fs52 = __toESM(require("fs"), 1);
69731
+ var import_node_path57 = __toESM(require("path"), 1);
69350
69732
  function defaultStateFilePath(dataDir) {
69351
- return import_node_path56.default.join(dataDir, "state.json");
69733
+ return import_node_path57.default.join(dataDir, "state.json");
69352
69734
  }
69353
69735
  function isPidAlive(pid) {
69354
69736
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -69370,7 +69752,7 @@ var StateFileManager = class {
69370
69752
  }
69371
69753
  read() {
69372
69754
  try {
69373
- const raw = import_node_fs51.default.readFileSync(this.file, "utf8");
69755
+ const raw = import_node_fs52.default.readFileSync(this.file, "utf8");
69374
69756
  const parsed = JSON.parse(raw);
69375
69757
  return parsed;
69376
69758
  } catch {
@@ -69384,20 +69766,20 @@ var StateFileManager = class {
69384
69766
  return { status: "stale", existing };
69385
69767
  }
69386
69768
  write(state) {
69387
- import_node_fs51.default.mkdirSync(import_node_path56.default.dirname(this.file), { recursive: true });
69769
+ import_node_fs52.default.mkdirSync(import_node_path57.default.dirname(this.file), { recursive: true });
69388
69770
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
69389
- import_node_fs51.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
69390
- import_node_fs51.default.renameSync(tmp, this.file);
69771
+ import_node_fs52.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
69772
+ import_node_fs52.default.renameSync(tmp, this.file);
69391
69773
  if (process.platform !== "win32") {
69392
69774
  try {
69393
- import_node_fs51.default.chmodSync(this.file, 384);
69775
+ import_node_fs52.default.chmodSync(this.file, 384);
69394
69776
  } catch {
69395
69777
  }
69396
69778
  }
69397
69779
  }
69398
69780
  delete() {
69399
69781
  try {
69400
- import_node_fs51.default.unlinkSync(this.file);
69782
+ import_node_fs52.default.unlinkSync(this.file);
69401
69783
  } catch {
69402
69784
  }
69403
69785
  }
@@ -69411,14 +69793,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
69411
69793
  }
69412
69794
 
69413
69795
  // src/tunnel/tunnel-manager.ts
69414
- var import_node_fs55 = __toESM(require("fs"), 1);
69415
- var import_node_path60 = __toESM(require("path"), 1);
69416
- var import_node_crypto18 = __toESM(require("crypto"), 1);
69796
+ var import_node_fs56 = __toESM(require("fs"), 1);
69797
+ var import_node_path61 = __toESM(require("path"), 1);
69798
+ var import_node_crypto19 = __toESM(require("crypto"), 1);
69417
69799
  var import_node_child_process16 = require("child_process");
69418
69800
 
69419
69801
  // src/tunnel/tunnel-store.ts
69420
- var import_node_fs52 = __toESM(require("fs"), 1);
69421
- var import_node_path57 = __toESM(require("path"), 1);
69802
+ var import_node_fs53 = __toESM(require("fs"), 1);
69803
+ var import_node_path58 = __toESM(require("path"), 1);
69422
69804
  var TunnelStore = class {
69423
69805
  constructor(filePath) {
69424
69806
  this.filePath = filePath;
@@ -69426,7 +69808,7 @@ var TunnelStore = class {
69426
69808
  filePath;
69427
69809
  async get() {
69428
69810
  try {
69429
- const raw = await import_node_fs52.default.promises.readFile(this.filePath, "utf8");
69811
+ const raw = await import_node_fs53.default.promises.readFile(this.filePath, "utf8");
69430
69812
  const obj = JSON.parse(raw);
69431
69813
  if (!isPersistedTunnel(obj)) return null;
69432
69814
  return obj;
@@ -69437,22 +69819,22 @@ var TunnelStore = class {
69437
69819
  }
69438
69820
  }
69439
69821
  async set(v3) {
69440
- const dir = import_node_path57.default.dirname(this.filePath);
69441
- await import_node_fs52.default.promises.mkdir(dir, { recursive: true });
69822
+ const dir = import_node_path58.default.dirname(this.filePath);
69823
+ await import_node_fs53.default.promises.mkdir(dir, { recursive: true });
69442
69824
  const data = JSON.stringify(v3, null, 2);
69443
69825
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
69444
- await import_node_fs52.default.promises.writeFile(tmp, data, { mode: 384 });
69826
+ await import_node_fs53.default.promises.writeFile(tmp, data, { mode: 384 });
69445
69827
  if (process.platform !== "win32") {
69446
69828
  try {
69447
- await import_node_fs52.default.promises.chmod(tmp, 384);
69829
+ await import_node_fs53.default.promises.chmod(tmp, 384);
69448
69830
  } catch {
69449
69831
  }
69450
69832
  }
69451
- await import_node_fs52.default.promises.rename(tmp, this.filePath);
69833
+ await import_node_fs53.default.promises.rename(tmp, this.filePath);
69452
69834
  }
69453
69835
  async clear() {
69454
69836
  try {
69455
- await import_node_fs52.default.promises.unlink(this.filePath);
69837
+ await import_node_fs53.default.promises.unlink(this.filePath);
69456
69838
  } catch (err) {
69457
69839
  const code = err?.code;
69458
69840
  if (code !== "ENOENT") throw err;
@@ -69547,9 +69929,9 @@ function escape2(v3) {
69547
69929
  }
69548
69930
 
69549
69931
  // src/tunnel/frpc-binary.ts
69550
- var import_node_fs53 = __toESM(require("fs"), 1);
69932
+ var import_node_fs54 = __toESM(require("fs"), 1);
69551
69933
  var import_node_os21 = __toESM(require("os"), 1);
69552
- var import_node_path58 = __toESM(require("path"), 1);
69934
+ var import_node_path59 = __toESM(require("path"), 1);
69553
69935
  var import_node_child_process14 = require("child_process");
69554
69936
  var import_node_stream4 = require("stream");
69555
69937
  var import_promises10 = require("stream/promises");
@@ -69581,20 +69963,20 @@ function frpcDownloadUrl(version2, p3) {
69581
69963
  }
69582
69964
  async function ensureFrpcBinary(opts) {
69583
69965
  if (opts.override) {
69584
- if (!import_node_fs53.default.existsSync(opts.override)) {
69966
+ if (!import_node_fs54.default.existsSync(opts.override)) {
69585
69967
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
69586
69968
  }
69587
69969
  return opts.override;
69588
69970
  }
69589
69971
  const version2 = opts.version ?? FRPC_VERSION;
69590
69972
  const platform = opts.platform ?? detectPlatform();
69591
- const binDir = import_node_path58.default.join(opts.dataDir, "bin");
69592
- import_node_fs53.default.mkdirSync(binDir, { recursive: true });
69973
+ const binDir = import_node_path59.default.join(opts.dataDir, "bin");
69974
+ import_node_fs54.default.mkdirSync(binDir, { recursive: true });
69593
69975
  cleanupStaleArtifacts(binDir);
69594
- const stableBin = import_node_path58.default.join(binDir, "frpc");
69595
- if (import_node_fs53.default.existsSync(stableBin)) return stableBin;
69976
+ const stableBin = import_node_path59.default.join(binDir, "frpc");
69977
+ if (import_node_fs54.default.existsSync(stableBin)) return stableBin;
69596
69978
  const partialBin = `${stableBin}.partial`;
69597
- const tarballPath = import_node_path58.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
69979
+ const tarballPath = import_node_path59.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
69598
69980
  try {
69599
69981
  const url = frpcDownloadUrl(version2, platform);
69600
69982
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -69603,8 +69985,8 @@ async function ensureFrpcBinary(opts) {
69603
69985
  } else {
69604
69986
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
69605
69987
  }
69606
- import_node_fs53.default.chmodSync(partialBin, 493);
69607
- import_node_fs53.default.renameSync(partialBin, stableBin);
69988
+ import_node_fs54.default.chmodSync(partialBin, 493);
69989
+ import_node_fs54.default.renameSync(partialBin, stableBin);
69608
69990
  } finally {
69609
69991
  safeUnlink(tarballPath);
69610
69992
  safeUnlink(partialBin);
@@ -69614,15 +69996,15 @@ async function ensureFrpcBinary(opts) {
69614
69996
  function cleanupStaleArtifacts(binDir) {
69615
69997
  let entries;
69616
69998
  try {
69617
- entries = import_node_fs53.default.readdirSync(binDir);
69999
+ entries = import_node_fs54.default.readdirSync(binDir);
69618
70000
  } catch {
69619
70001
  return;
69620
70002
  }
69621
70003
  for (const name of entries) {
69622
70004
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
69623
- const full = import_node_path58.default.join(binDir, name);
70005
+ const full = import_node_path59.default.join(binDir, name);
69624
70006
  try {
69625
- import_node_fs53.default.rmSync(full, { recursive: true, force: true });
70007
+ import_node_fs54.default.rmSync(full, { recursive: true, force: true });
69626
70008
  } catch {
69627
70009
  }
69628
70010
  }
@@ -69630,7 +70012,7 @@ function cleanupStaleArtifacts(binDir) {
69630
70012
  }
69631
70013
  function safeUnlink(p3) {
69632
70014
  try {
69633
- import_node_fs53.default.unlinkSync(p3);
70015
+ import_node_fs54.default.unlinkSync(p3);
69634
70016
  } catch {
69635
70017
  }
69636
70018
  }
@@ -69641,13 +70023,13 @@ async function downloadToFile(url, dest, fetchImpl) {
69641
70023
  if (!res.ok || !res.body) {
69642
70024
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
69643
70025
  }
69644
- const out = import_node_fs53.default.createWriteStream(dest);
70026
+ const out = import_node_fs54.default.createWriteStream(dest);
69645
70027
  const nodeStream = import_node_stream4.Readable.fromWeb(res.body);
69646
70028
  await (0, import_promises10.pipeline)(nodeStream, out);
69647
70029
  }
69648
70030
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
69649
- const work = import_node_path58.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
69650
- import_node_fs53.default.mkdirSync(work, { recursive: true });
70031
+ const work = import_node_path59.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
70032
+ import_node_fs54.default.mkdirSync(work, { recursive: true });
69651
70033
  try {
69652
70034
  await new Promise((resolve9, reject) => {
69653
70035
  const proc = (0, import_node_child_process14.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -69655,32 +70037,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
69655
70037
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
69656
70038
  });
69657
70039
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
69658
- const src = import_node_path58.default.join(work, dirName, "frpc");
69659
- if (!import_node_fs53.default.existsSync(src)) {
70040
+ const src = import_node_path59.default.join(work, dirName, "frpc");
70041
+ if (!import_node_fs54.default.existsSync(src)) {
69660
70042
  throw new Error(`frpc not found inside tarball at ${src}`);
69661
70043
  }
69662
- import_node_fs53.default.copyFileSync(src, destBin);
70044
+ import_node_fs54.default.copyFileSync(src, destBin);
69663
70045
  } finally {
69664
- import_node_fs53.default.rmSync(work, { recursive: true, force: true });
70046
+ import_node_fs54.default.rmSync(work, { recursive: true, force: true });
69665
70047
  }
69666
70048
  }
69667
70049
 
69668
70050
  // src/tunnel/frpc-process.ts
69669
- var import_node_fs54 = __toESM(require("fs"), 1);
69670
- var import_node_path59 = __toESM(require("path"), 1);
70051
+ var import_node_fs55 = __toESM(require("fs"), 1);
70052
+ var import_node_path60 = __toESM(require("path"), 1);
69671
70053
  var import_node_child_process15 = require("child_process");
69672
70054
  function frpcPidFilePath(dataDir) {
69673
- return import_node_path59.default.join(dataDir, "frpc.pid");
70055
+ return import_node_path60.default.join(dataDir, "frpc.pid");
69674
70056
  }
69675
70057
  function writeFrpcPid(dataDir, pid) {
69676
70058
  try {
69677
- import_node_fs54.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
70059
+ import_node_fs55.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
69678
70060
  } catch {
69679
70061
  }
69680
70062
  }
69681
70063
  function clearFrpcPid(dataDir) {
69682
70064
  try {
69683
- import_node_fs54.default.unlinkSync(frpcPidFilePath(dataDir));
70065
+ import_node_fs55.default.unlinkSync(frpcPidFilePath(dataDir));
69684
70066
  } catch {
69685
70067
  }
69686
70068
  }
@@ -69696,7 +70078,7 @@ function defaultIsPidAlive(pid) {
69696
70078
  }
69697
70079
  function defaultReadPidFile(file) {
69698
70080
  try {
69699
- return import_node_fs54.default.readFileSync(file, "utf8");
70081
+ return import_node_fs55.default.readFileSync(file, "utf8");
69700
70082
  } catch {
69701
70083
  return null;
69702
70084
  }
@@ -69712,7 +70094,7 @@ function defaultSleep2(ms) {
69712
70094
  }
69713
70095
  async function killStaleFrpc(deps) {
69714
70096
  const pidFile = frpcPidFilePath(deps.dataDir);
69715
- const tomlPath = import_node_path59.default.join(deps.dataDir, "frpc.toml");
70097
+ const tomlPath = import_node_path60.default.join(deps.dataDir, "frpc.toml");
69716
70098
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
69717
70099
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
69718
70100
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -69736,7 +70118,7 @@ async function killStaleFrpc(deps) {
69736
70118
  }
69737
70119
  if (victims.size === 0) {
69738
70120
  try {
69739
- import_node_fs54.default.unlinkSync(pidFile);
70121
+ import_node_fs55.default.unlinkSync(pidFile);
69740
70122
  } catch {
69741
70123
  }
69742
70124
  return;
@@ -69747,7 +70129,7 @@ async function killStaleFrpc(deps) {
69747
70129
  }
69748
70130
  await sleep2(deps.reapWaitMs ?? 300);
69749
70131
  try {
69750
- import_node_fs54.default.unlinkSync(pidFile);
70132
+ import_node_fs55.default.unlinkSync(pidFile);
69751
70133
  } catch {
69752
70134
  }
69753
70135
  }
@@ -69784,7 +70166,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
69784
70166
  var TunnelManager = class {
69785
70167
  constructor(deps) {
69786
70168
  this.deps = deps;
69787
- this.store = deps.store ?? new TunnelStore(import_node_path60.default.join(deps.dataDir, "tunnel.json"));
70169
+ this.store = deps.store ?? new TunnelStore(import_node_path61.default.join(deps.dataDir, "tunnel.json"));
69788
70170
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
69789
70171
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
69790
70172
  }
@@ -69911,8 +70293,8 @@ var TunnelManager = class {
69911
70293
  dataDir: this.deps.dataDir,
69912
70294
  override: this.deps.frpcBinaryOverride ?? void 0
69913
70295
  });
69914
- const tomlPath = import_node_path60.default.join(this.deps.dataDir, "frpc.toml");
69915
- const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto18.default.randomBytes(3).toString("hex")}`;
70296
+ const tomlPath = import_node_path61.default.join(this.deps.dataDir, "frpc.toml");
70297
+ const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto19.default.randomBytes(3).toString("hex")}`;
69916
70298
  const toml = buildFrpcToml({
69917
70299
  serverAddr: t2.frpsHost,
69918
70300
  serverPort: t2.frpsPort,
@@ -69922,14 +70304,14 @@ var TunnelManager = class {
69922
70304
  localPort,
69923
70305
  logLevel: "info"
69924
70306
  });
69925
- await import_node_fs55.default.promises.writeFile(tomlPath, toml, { mode: 384 });
70307
+ await import_node_fs56.default.promises.writeFile(tomlPath, toml, { mode: 384 });
69926
70308
  const proc = (this.deps.spawnImpl ?? import_node_child_process16.spawn)(frpcBin, ["-c", tomlPath], {
69927
70309
  stdio: ["ignore", "pipe", "pipe"]
69928
70310
  });
69929
- const logDir = import_node_path60.default.join(this.deps.dataDir, "log");
69930
- import_node_fs55.default.mkdirSync(logDir, { recursive: true });
69931
- const logFilePath = import_node_path60.default.join(logDir, "frpc.log");
69932
- const logStream = import_node_fs55.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
70311
+ const logDir = import_node_path61.default.join(this.deps.dataDir, "log");
70312
+ import_node_fs56.default.mkdirSync(logDir, { recursive: true });
70313
+ const logFilePath = import_node_path61.default.join(logDir, "frpc.log");
70314
+ const logStream = import_node_fs56.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
69933
70315
  logStream.on("error", () => {
69934
70316
  });
69935
70317
  const tee = (chunk) => {
@@ -70012,27 +70394,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
70012
70394
 
70013
70395
  // src/tunnel/device-key.ts
70014
70396
  var import_node_os22 = __toESM(require("os"), 1);
70015
- var import_node_path61 = __toESM(require("path"), 1);
70016
- var import_node_crypto19 = __toESM(require("crypto"), 1);
70397
+ var import_node_path62 = __toESM(require("path"), 1);
70398
+ var import_node_crypto20 = __toESM(require("crypto"), 1);
70017
70399
  var DERIVE_SALT = "clawd-tunnel-device-v1";
70018
70400
  function deriveStableDeviceKey(opts = {}) {
70019
70401
  const hostname = opts.hostname ?? import_node_os22.default.hostname();
70020
70402
  const uid = opts.uid ?? (typeof import_node_os22.default.userInfo === "function" ? import_node_os22.default.userInfo().uid : 0);
70021
70403
  const home = opts.home ?? import_node_os22.default.homedir();
70022
- const defaultDataDir = import_node_path61.default.resolve(import_node_path61.default.join(home, ".clawd"));
70023
- const normalizedDataDir = opts.dataDir ? import_node_path61.default.resolve(opts.dataDir) : null;
70404
+ const defaultDataDir = import_node_path62.default.resolve(import_node_path62.default.join(home, ".clawd"));
70405
+ const normalizedDataDir = opts.dataDir ? import_node_path62.default.resolve(opts.dataDir) : null;
70024
70406
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
70025
70407
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
70026
- return import_node_crypto19.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
70408
+ return import_node_crypto20.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
70027
70409
  }
70028
70410
 
70029
70411
  // src/auth-store.ts
70030
- var import_node_fs56 = __toESM(require("fs"), 1);
70031
- var import_node_path62 = __toESM(require("path"), 1);
70032
- var import_node_crypto20 = __toESM(require("crypto"), 1);
70412
+ var import_node_fs57 = __toESM(require("fs"), 1);
70413
+ var import_node_path63 = __toESM(require("path"), 1);
70414
+ var import_node_crypto21 = __toESM(require("crypto"), 1);
70033
70415
  var AUTH_FILE_NAME = "auth.json";
70034
70416
  function authFilePath(dataDir) {
70035
- return import_node_path62.default.join(dataDir, AUTH_FILE_NAME);
70417
+ return import_node_path63.default.join(dataDir, AUTH_FILE_NAME);
70036
70418
  }
70037
70419
  function loadOrCreateAuthFile(opts) {
70038
70420
  const file = authFilePath(opts.dataDir);
@@ -70066,14 +70448,14 @@ function loadOrCreateTunnelDeviceKey(opts) {
70066
70448
  return tunnelDeviceKey;
70067
70449
  }
70068
70450
  function defaultGenerateToken() {
70069
- return import_node_crypto20.default.randomBytes(32).toString("base64url");
70451
+ return import_node_crypto21.default.randomBytes(32).toString("base64url");
70070
70452
  }
70071
70453
  function defaultGenerateOwnerPrincipalId() {
70072
- return `owner-${import_node_crypto20.default.randomUUID()}`;
70454
+ return `owner-${import_node_crypto21.default.randomUUID()}`;
70073
70455
  }
70074
70456
  function readAuthFile(file) {
70075
70457
  try {
70076
- const raw = import_node_fs56.default.readFileSync(file, "utf8");
70458
+ const raw = import_node_fs57.default.readFileSync(file, "utf8");
70077
70459
  const parsed = JSON.parse(raw);
70078
70460
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
70079
70461
  return null;
@@ -70094,26 +70476,26 @@ function readAuthFile(file) {
70094
70476
  }
70095
70477
  }
70096
70478
  function writeAuthFile(file, content) {
70097
- import_node_fs56.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true });
70098
- import_node_fs56.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
70479
+ import_node_fs57.default.mkdirSync(import_node_path63.default.dirname(file), { recursive: true });
70480
+ import_node_fs57.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
70099
70481
  try {
70100
- import_node_fs56.default.chmodSync(file, 384);
70482
+ import_node_fs57.default.chmodSync(file, 384);
70101
70483
  } catch {
70102
70484
  }
70103
70485
  }
70104
70486
 
70105
70487
  // src/owner-profile.ts
70106
- var import_node_fs57 = __toESM(require("fs"), 1);
70488
+ var import_node_fs58 = __toESM(require("fs"), 1);
70107
70489
  var import_node_os23 = __toESM(require("os"), 1);
70108
- var import_node_path63 = __toESM(require("path"), 1);
70490
+ var import_node_path64 = __toESM(require("path"), 1);
70109
70491
  var PROFILE_FILENAME = "profile.json";
70110
70492
  function profilePath(dataDir) {
70111
- return import_node_path63.default.join(dataDir, PROFILE_FILENAME);
70493
+ return import_node_path64.default.join(dataDir, PROFILE_FILENAME);
70112
70494
  }
70113
70495
  function loadOwnerProfile(dataDir) {
70114
70496
  let raw;
70115
70497
  try {
70116
- raw = import_node_fs57.default.readFileSync(profilePath(dataDir), "utf8");
70498
+ raw = import_node_fs58.default.readFileSync(profilePath(dataDir), "utf8");
70117
70499
  } catch {
70118
70500
  return {};
70119
70501
  }
@@ -70129,7 +70511,7 @@ function loadOwnerProfile(dataDir) {
70129
70511
  }
70130
70512
  function patchOwnerProfile(dataDir, patch) {
70131
70513
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
70132
- import_node_fs57.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
70514
+ import_node_fs58.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
70133
70515
  return merged;
70134
70516
  }
70135
70517
  function loadOwnerDisplayName(dataDir) {
@@ -70145,18 +70527,18 @@ function loadOwnerDisplayName(dataDir) {
70145
70527
  }
70146
70528
 
70147
70529
  // src/feishu-auth/owner-identity-store.ts
70148
- var import_node_fs58 = __toESM(require("fs"), 1);
70149
- var import_node_path64 = __toESM(require("path"), 1);
70530
+ var import_node_fs59 = __toESM(require("fs"), 1);
70531
+ var import_node_path65 = __toESM(require("path"), 1);
70150
70532
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
70151
70533
  var OwnerIdentityStore = class {
70152
70534
  file;
70153
70535
  constructor(dataDir) {
70154
- this.file = import_node_path64.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
70536
+ this.file = import_node_path65.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
70155
70537
  }
70156
70538
  read() {
70157
70539
  let raw;
70158
70540
  try {
70159
- raw = import_node_fs58.default.readFileSync(this.file, "utf8");
70541
+ raw = import_node_fs59.default.readFileSync(this.file, "utf8");
70160
70542
  } catch {
70161
70543
  return null;
70162
70544
  }
@@ -70183,16 +70565,16 @@ var OwnerIdentityStore = class {
70183
70565
  };
70184
70566
  }
70185
70567
  write(record4) {
70186
- import_node_fs58.default.mkdirSync(import_node_path64.default.dirname(this.file), { recursive: true });
70187
- import_node_fs58.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
70568
+ import_node_fs59.default.mkdirSync(import_node_path65.default.dirname(this.file), { recursive: true });
70569
+ import_node_fs59.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
70188
70570
  try {
70189
- import_node_fs58.default.chmodSync(this.file, 384);
70571
+ import_node_fs59.default.chmodSync(this.file, 384);
70190
70572
  } catch {
70191
70573
  }
70192
70574
  }
70193
70575
  clear() {
70194
70576
  try {
70195
- import_node_fs58.default.unlinkSync(this.file);
70577
+ import_node_fs59.default.unlinkSync(this.file);
70196
70578
  } catch (err) {
70197
70579
  const code = err?.code;
70198
70580
  if (code !== "ENOENT") throw err;
@@ -70201,7 +70583,7 @@ var OwnerIdentityStore = class {
70201
70583
  };
70202
70584
 
70203
70585
  // src/feishu-auth/login-flow.ts
70204
- var import_node_crypto21 = __toESM(require("crypto"), 1);
70586
+ var import_node_crypto22 = __toESM(require("crypto"), 1);
70205
70587
  var STATE_TTL_MS = 5 * 60 * 1e3;
70206
70588
  var LoginFlow = class {
70207
70589
  constructor(deps) {
@@ -70210,7 +70592,7 @@ var LoginFlow = class {
70210
70592
  deps;
70211
70593
  pendingStates = /* @__PURE__ */ new Map();
70212
70594
  start() {
70213
- const state = import_node_crypto21.default.randomBytes(16).toString("base64url");
70595
+ const state = import_node_crypto22.default.randomBytes(16).toString("base64url");
70214
70596
  const now = (this.deps.now ?? Date.now)();
70215
70597
  this.pendingStates.set(state, now);
70216
70598
  this.gcExpired(now);
@@ -70688,8 +71070,8 @@ function verifyConnectToken(args) {
70688
71070
  }
70689
71071
 
70690
71072
  // src/feishu-auth/server-key.ts
70691
- var fs75 = __toESM(require("fs"), 1);
70692
- var path77 = __toESM(require("path"), 1);
71073
+ var fs76 = __toESM(require("fs"), 1);
71074
+ var path78 = __toESM(require("path"), 1);
70693
71075
  var FILE_NAME2 = "server-signing-key.json";
70694
71076
  var ServerKeyStore = class {
70695
71077
  constructor(dataDir) {
@@ -70697,12 +71079,12 @@ var ServerKeyStore = class {
70697
71079
  }
70698
71080
  dataDir;
70699
71081
  filePath() {
70700
- return path77.join(this.dataDir, FILE_NAME2);
71082
+ return path78.join(this.dataDir, FILE_NAME2);
70701
71083
  }
70702
71084
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
70703
71085
  read() {
70704
71086
  try {
70705
- const raw = fs75.readFileSync(this.filePath(), "utf8");
71087
+ const raw = fs76.readFileSync(this.filePath(), "utf8");
70706
71088
  const parsed = JSON.parse(raw);
70707
71089
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
70708
71090
  return parsed.publicKeyPem;
@@ -70717,12 +71099,12 @@ var ServerKeyStore = class {
70717
71099
  publicKeyPem,
70718
71100
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
70719
71101
  };
70720
- fs75.mkdirSync(this.dataDir, { recursive: true });
70721
- fs75.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
71102
+ fs76.mkdirSync(this.dataDir, { recursive: true });
71103
+ fs76.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
70722
71104
  }
70723
71105
  clear() {
70724
71106
  try {
70725
- fs75.unlinkSync(this.filePath());
71107
+ fs76.unlinkSync(this.filePath());
70726
71108
  } catch {
70727
71109
  }
70728
71110
  }
@@ -70732,19 +71114,19 @@ var ServerKeyStore = class {
70732
71114
  init_protocol();
70733
71115
 
70734
71116
  // src/handlers/index.ts
70735
- var import_node_path80 = __toESM(require("path"), 1);
71117
+ var import_node_path81 = __toESM(require("path"), 1);
70736
71118
 
70737
71119
  // src/handlers/session.ts
70738
71120
  init_protocol();
70739
71121
 
70740
71122
  // src/session/fork.ts
70741
- var import_node_fs59 = __toESM(require("fs"), 1);
71123
+ var import_node_fs60 = __toESM(require("fs"), 1);
70742
71124
  var import_node_os24 = __toESM(require("os"), 1);
70743
- var import_node_path65 = __toESM(require("path"), 1);
70744
- var import_node_crypto22 = require("crypto");
71125
+ var import_node_path66 = __toESM(require("path"), 1);
71126
+ var import_node_crypto23 = require("crypto");
70745
71127
  init_claude_history();
70746
71128
  function readJsonlEntries(file) {
70747
- const raw = import_node_fs59.default.readFileSync(file, "utf8");
71129
+ const raw = import_node_fs60.default.readFileSync(file, "utf8");
70748
71130
  const out = [];
70749
71131
  for (const line of raw.split("\n")) {
70750
71132
  const t2 = line.trim();
@@ -70757,19 +71139,19 @@ function readJsonlEntries(file) {
70757
71139
  return out;
70758
71140
  }
70759
71141
  function forkSession(input) {
70760
- const baseDir = input.baseDir ?? import_node_path65.default.join(import_node_os24.default.homedir(), ".claude");
70761
- let projectDir = import_node_path65.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
70762
- let sourceFile = import_node_path65.default.join(projectDir, `${input.toolSessionId}.jsonl`);
70763
- if (!import_node_fs59.default.existsSync(sourceFile)) {
71142
+ const baseDir = input.baseDir ?? import_node_path66.default.join(import_node_os24.default.homedir(), ".claude");
71143
+ let projectDir = import_node_path66.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
71144
+ let sourceFile = import_node_path66.default.join(projectDir, `${input.toolSessionId}.jsonl`);
71145
+ if (!import_node_fs60.default.existsSync(sourceFile)) {
70764
71146
  const found = findTranscriptByToolSessionId(
70765
- import_node_path65.default.join(baseDir, "projects"),
71147
+ import_node_path66.default.join(baseDir, "projects"),
70766
71148
  input.toolSessionId
70767
71149
  );
70768
71150
  if (!found) {
70769
71151
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
70770
71152
  }
70771
71153
  sourceFile = found;
70772
- projectDir = import_node_path65.default.dirname(found);
71154
+ projectDir = import_node_path66.default.dirname(found);
70773
71155
  }
70774
71156
  const entries = readJsonlEntries(sourceFile);
70775
71157
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -70778,7 +71160,7 @@ function forkSession(input) {
70778
71160
  throw new Error(`fork: messageUuid not found in transcript: ${input.messageUuid}`);
70779
71161
  }
70780
71162
  const sliced = mainEntries.slice(0, targetIdx + 1);
70781
- const forkedToolSessionId = (0, import_node_crypto22.randomUUID)();
71163
+ const forkedToolSessionId = (0, import_node_crypto23.randomUUID)();
70782
71164
  let parentUuid = null;
70783
71165
  const forkedLines = [];
70784
71166
  for (const entry of sliced) {
@@ -70798,17 +71180,17 @@ function forkSession(input) {
70798
71180
  }
70799
71181
  forkedLines.push(JSON.stringify(forked));
70800
71182
  }
70801
- const outDir = input.targetCwd ? import_node_path65.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
70802
- const forkedFilePath = import_node_path65.default.join(outDir, `${forkedToolSessionId}.jsonl`);
70803
- import_node_fs59.default.mkdirSync(outDir, { recursive: true });
70804
- import_node_fs59.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
71183
+ const outDir = input.targetCwd ? import_node_path66.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
71184
+ const forkedFilePath = import_node_path66.default.join(outDir, `${forkedToolSessionId}.jsonl`);
71185
+ import_node_fs60.default.mkdirSync(outDir, { recursive: true });
71186
+ import_node_fs60.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
70805
71187
  return { forkedToolSessionId, forkedFilePath };
70806
71188
  }
70807
71189
 
70808
71190
  // src/tools/codex-fork.ts
70809
71191
  var import_node_child_process17 = require("child_process");
70810
- var import_node_fs60 = __toESM(require("fs"), 1);
70811
- var import_node_path66 = __toESM(require("path"), 1);
71192
+ var import_node_fs61 = __toESM(require("fs"), 1);
71193
+ var import_node_path67 = __toESM(require("path"), 1);
70812
71194
  function openCodexAppServer(home, cwd) {
70813
71195
  const proc = (0, import_node_child_process17.spawn)(process.env.CODEX_BIN ?? "codex", ["app-server", "--listen", "stdio://"], {
70814
71196
  cwd,
@@ -70828,7 +71210,7 @@ function openCodexAppServer(home, cwd) {
70828
71210
  async function forkCodexThread(input, deps = {}) {
70829
71211
  const source = locateCodexThread(input.roots, input.sourceThreadId);
70830
71212
  if (!source) throw new Error(`codex fork: source thread not found: ${input.sourceThreadId}`);
70831
- const rollout = parseCodexRollout(import_node_fs60.default.readFileSync(source.file, "utf8"));
71213
+ const rollout = parseCodexRollout(import_node_fs61.default.readFileSync(source.file, "utf8"));
70832
71214
  if (rollout.meta?.threadId.toLowerCase() !== input.sourceThreadId.toLowerCase()) {
70833
71215
  throw new Error(`codex fork: source thread metadata does not match ${input.sourceThreadId}`);
70834
71216
  }
@@ -70858,7 +71240,7 @@ async function forkCodexThread(input, deps = {}) {
70858
71240
  if (typeof forkedToolSessionId !== "string" || !forkedToolSessionId) {
70859
71241
  throw new Error("codex fork: app-server returned no thread id");
70860
71242
  }
70861
- const forked = locateCodexThread([import_node_path66.default.join(source.home, "sessions")], forkedToolSessionId);
71243
+ const forked = locateCodexThread([import_node_path67.default.join(source.home, "sessions")], forkedToolSessionId);
70862
71244
  if (!forked) throw new Error(`codex fork: rollout not found for forked thread ${forkedToolSessionId}`);
70863
71245
  return { forkedToolSessionId, forkedFilePath: forked.file };
70864
71246
  })()]);
@@ -70869,19 +71251,19 @@ async function forkCodexThread(input, deps = {}) {
70869
71251
  }
70870
71252
 
70871
71253
  // src/session/external-scan.ts
70872
- var import_node_fs61 = __toESM(require("fs"), 1);
71254
+ var import_node_fs62 = __toESM(require("fs"), 1);
70873
71255
  var import_promises11 = __toESM(require("fs/promises"), 1);
70874
71256
  var import_node_os25 = __toESM(require("os"), 1);
70875
- var import_node_path67 = __toESM(require("path"), 1);
71257
+ var import_node_path68 = __toESM(require("path"), 1);
70876
71258
  var import_node_module = require("module");
70877
71259
  var import_node_child_process18 = require("child_process");
70878
71260
  var import_meta7 = {};
70879
71261
  function defaultRoots() {
70880
71262
  const home = import_node_os25.default.homedir();
70881
71263
  return {
70882
- claudeProjectsDir: import_node_path67.default.join(home, ".claude", "projects"),
70883
- codexDir: import_node_path67.default.join(home, ".codex"),
70884
- clawdDir: import_node_path67.default.join(home, ".clawd")
71264
+ claudeProjectsDir: import_node_path68.default.join(home, ".claude", "projects"),
71265
+ codexDir: import_node_path68.default.join(home, ".codex"),
71266
+ clawdDir: import_node_path68.default.join(home, ".clawd")
70885
71267
  };
70886
71268
  }
70887
71269
  function width(s2) {
@@ -70932,7 +71314,7 @@ function userText(msg) {
70932
71314
  }
70933
71315
  function isDir2(p3) {
70934
71316
  try {
70935
- return import_node_fs61.default.statSync(p3).isDirectory();
71317
+ return import_node_fs62.default.statSync(p3).isDirectory();
70936
71318
  } catch {
70937
71319
  return false;
70938
71320
  }
@@ -70941,7 +71323,7 @@ async function scanClaude(roots) {
70941
71323
  const out = [];
70942
71324
  let dirs;
70943
71325
  try {
70944
- dirs = import_node_fs61.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
71326
+ dirs = import_node_fs62.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
70945
71327
  } catch {
70946
71328
  return out;
70947
71329
  }
@@ -70949,16 +71331,16 @@ async function scanClaude(roots) {
70949
71331
  if (!d2.isDirectory()) continue;
70950
71332
  let files;
70951
71333
  try {
70952
- files = import_node_fs61.default.readdirSync(import_node_path67.default.join(roots.claudeProjectsDir, d2.name));
71334
+ files = import_node_fs62.default.readdirSync(import_node_path68.default.join(roots.claudeProjectsDir, d2.name));
70953
71335
  } catch {
70954
71336
  continue;
70955
71337
  }
70956
71338
  for (const name of files) {
70957
71339
  if (!name.endsWith(".jsonl")) continue;
70958
- const file = import_node_path67.default.join(roots.claudeProjectsDir, d2.name, name);
71340
+ const file = import_node_path68.default.join(roots.claudeProjectsDir, d2.name, name);
70959
71341
  let st2;
70960
71342
  try {
70961
- st2 = import_node_fs61.default.statSync(file);
71343
+ st2 = import_node_fs62.default.statSync(file);
70962
71344
  } catch {
70963
71345
  continue;
70964
71346
  }
@@ -71011,7 +71393,7 @@ async function scanClaude(roots) {
71011
71393
  return out;
71012
71394
  }
71013
71395
  async function countCodexTurns(rolloutPath) {
71014
- if (!rolloutPath || !import_node_fs61.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
71396
+ if (!rolloutPath || !import_node_fs62.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
71015
71397
  let turns = 0;
71016
71398
  let first = "";
71017
71399
  for await (const rec6 of jsonLines(rolloutPath)) {
@@ -71085,7 +71467,7 @@ async function codexFromRows(rows) {
71085
71467
  async function scanCodex(roots) {
71086
71468
  let dbs = [];
71087
71469
  try {
71088
- dbs = import_node_fs61.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path67.default.join(roots.codexDir, n2));
71470
+ dbs = import_node_fs62.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path68.default.join(roots.codexDir, n2));
71089
71471
  } catch {
71090
71472
  }
71091
71473
  if (!dbs.length) return [];
@@ -71094,14 +71476,14 @@ async function scanCodex(roots) {
71094
71476
  }
71095
71477
  async function scanExternalSessions(rootsIn) {
71096
71478
  const roots = { ...defaultRoots(), ...rootsIn };
71097
- const personaRoot = import_node_path67.default.join(roots.clawdDir, "personas");
71479
+ const personaRoot = import_node_path68.default.join(roots.clawdDir, "personas");
71098
71480
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
71099
71481
  const out = [];
71100
71482
  for (const c2 of all) {
71101
71483
  if (c2.skip) continue;
71102
71484
  if (c2.turns < 1) continue;
71103
71485
  if (!c2.cwd || !isDir2(c2.cwd)) continue;
71104
- if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path67.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path67.default.sep)) {
71486
+ if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path68.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path68.default.sep)) {
71105
71487
  continue;
71106
71488
  }
71107
71489
  out.push({
@@ -71118,13 +71500,13 @@ async function scanExternalSessions(rootsIn) {
71118
71500
  }
71119
71501
 
71120
71502
  // src/session/import-ledger.ts
71121
- var import_node_fs62 = __toESM(require("fs"), 1);
71122
- var import_node_path68 = __toESM(require("path"), 1);
71503
+ var import_node_fs63 = __toESM(require("fs"), 1);
71504
+ var import_node_path69 = __toESM(require("path"), 1);
71123
71505
  var LEDGER_FILENAME = "session-import-ledger.json";
71124
71506
  function readImportLedger(dataDir) {
71125
71507
  try {
71126
71508
  const parsed = JSON.parse(
71127
- import_node_fs62.default.readFileSync(import_node_path68.default.join(dataDir, LEDGER_FILENAME), "utf8")
71509
+ import_node_fs63.default.readFileSync(import_node_path69.default.join(dataDir, LEDGER_FILENAME), "utf8")
71128
71510
  );
71129
71511
  return Array.isArray(parsed) ? parsed : [];
71130
71512
  } catch {
@@ -71132,15 +71514,15 @@ function readImportLedger(dataDir) {
71132
71514
  }
71133
71515
  }
71134
71516
  function appendImportLedger(dataDir, entry) {
71135
- const file = import_node_path68.default.join(dataDir, LEDGER_FILENAME);
71517
+ const file = import_node_path69.default.join(dataDir, LEDGER_FILENAME);
71136
71518
  const entries = readImportLedger(dataDir);
71137
71519
  entries.push(entry);
71138
- import_node_fs62.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
71520
+ import_node_fs63.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
71139
71521
  }
71140
71522
 
71141
71523
  // src/handlers/session.ts
71142
71524
  init_protocol();
71143
- var import_node_path69 = __toESM(require("path"), 1);
71525
+ var import_node_path70 = __toESM(require("path"), 1);
71144
71526
  function canReadSearchHit(ctx, file) {
71145
71527
  if (!ctx || ctx.principal.kind === "owner") return true;
71146
71528
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
@@ -71316,7 +71698,7 @@ function buildSessionHandlers(deps) {
71316
71698
  const del = async (frame, _client, ctx) => {
71317
71699
  const args = SessionIdArgs.parse(frame);
71318
71700
  ensureSessionAccess(ctx, args.sessionId, "send");
71319
- const { broadcast } = manager.delete(args);
71701
+ const { broadcast } = await manager.deleteWithCloudCancel(args);
71320
71702
  return {
71321
71703
  response: { type: "session:deleted", sessionId: args.sessionId },
71322
71704
  broadcast
@@ -71421,7 +71803,7 @@ ${attribution}` } : args;
71421
71803
  `principal guest:${ctx.principal.id} cannot fork tool session ${args.toolSessionId}`
71422
71804
  );
71423
71805
  }
71424
- if (source?.tool === "codex" && args.targetCwd && import_node_path69.default.resolve(args.targetCwd) !== import_node_path69.default.resolve(source.cwd)) {
71806
+ if (source?.tool === "codex" && args.targetCwd && import_node_path70.default.resolve(args.targetCwd) !== import_node_path70.default.resolve(source.cwd)) {
71425
71807
  throw new ClawdError(ERROR_CODES.FORBIDDEN, "fork: guest targetCwd must match source cwd");
71426
71808
  }
71427
71809
  }
@@ -71460,7 +71842,7 @@ ${attribution}` } : args;
71460
71842
  const args = SessionIdArgs.parse(frame);
71461
71843
  ensureSessionAccess(ctx, args.sessionId, "send");
71462
71844
  observer.stop(args.sessionId);
71463
- const { response, broadcast } = manager.newSession(args);
71845
+ const { response, broadcast } = await manager.newSessionWithCloudCancel(args);
71464
71846
  return { response: { type: "session:info", ...response }, broadcast };
71465
71847
  };
71466
71848
  const resume = async (frame, _client, ctx) => {
@@ -71698,7 +72080,7 @@ function buildPermissionHandlers(deps) {
71698
72080
  }
71699
72081
 
71700
72082
  // src/handlers/history.ts
71701
- var path84 = __toESM(require("path"), 1);
72083
+ var path85 = __toESM(require("path"), 1);
71702
72084
  init_protocol();
71703
72085
 
71704
72086
  // src/session/recent-dirs.ts
@@ -71716,7 +72098,7 @@ function listRecentDirs(store, limit = 50) {
71716
72098
  }
71717
72099
 
71718
72100
  // src/permission/persona-paths.ts
71719
- var path83 = __toESM(require("path"), 1);
72101
+ var path84 = __toESM(require("path"), 1);
71720
72102
  function getAllowedPersonaIds(grants, action) {
71721
72103
  const ids = /* @__PURE__ */ new Set();
71722
72104
  for (const g3 of grants) {
@@ -71729,42 +72111,42 @@ function getAllowedPersonaIds(grants, action) {
71729
72111
  return ids;
71730
72112
  }
71731
72113
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
71732
- const target = path83.resolve(absPath);
72114
+ const target = path84.resolve(absPath);
71733
72115
  if (userWorkDir) {
71734
- const u2 = path83.resolve(userWorkDir);
71735
- const usep = u2.endsWith(path83.sep) ? "" : path83.sep;
72116
+ const u2 = path84.resolve(userWorkDir);
72117
+ const usep = u2.endsWith(path84.sep) ? "" : path84.sep;
71736
72118
  if (target === u2 || target.startsWith(u2 + usep)) return true;
71737
72119
  }
71738
- const root = path83.resolve(personaRoot);
71739
- const sep4 = root.endsWith(path83.sep) ? "" : path83.sep;
72120
+ const root = path84.resolve(personaRoot);
72121
+ const sep4 = root.endsWith(path84.sep) ? "" : path84.sep;
71740
72122
  if (!target.startsWith(root + sep4)) return false;
71741
- const rel = path83.relative(root, target);
72123
+ const rel = path84.relative(root, target);
71742
72124
  if (!rel || rel.startsWith("..")) return false;
71743
- const personaId2 = rel.split(path83.sep)[0];
72125
+ const personaId2 = rel.split(path84.sep)[0];
71744
72126
  if (!personaId2) return false;
71745
72127
  const allowed = getAllowedPersonaIds(grants, action);
71746
72128
  if (allowed === "*") return true;
71747
72129
  return allowed.has(personaId2);
71748
72130
  }
71749
72131
  function personaIdFromPath(absPath, personaRoot) {
71750
- const root = path83.resolve(personaRoot);
71751
- const target = path83.resolve(absPath);
71752
- const sep4 = root.endsWith(path83.sep) ? "" : path83.sep;
72132
+ const root = path84.resolve(personaRoot);
72133
+ const target = path84.resolve(absPath);
72134
+ const sep4 = root.endsWith(path84.sep) ? "" : path84.sep;
71753
72135
  if (!target.startsWith(root + sep4)) return null;
71754
- const rel = path83.relative(root, target);
72136
+ const rel = path84.relative(root, target);
71755
72137
  if (!rel || rel.startsWith("..")) return null;
71756
- const id = rel.split(path83.sep)[0];
72138
+ const id = rel.split(path84.sep)[0];
71757
72139
  return id || null;
71758
72140
  }
71759
72141
  function isPathWithin(dir, absPath) {
71760
- const d2 = path83.resolve(dir);
71761
- const t2 = path83.resolve(absPath);
71762
- const sep4 = d2.endsWith(path83.sep) ? "" : path83.sep;
72142
+ const d2 = path84.resolve(dir);
72143
+ const t2 = path84.resolve(absPath);
72144
+ const sep4 = d2.endsWith(path84.sep) ? "" : path84.sep;
71763
72145
  return t2 === d2 || t2.startsWith(d2 + sep4);
71764
72146
  }
71765
72147
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
71766
72148
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
71767
- return personaIdFromPath(path83.resolve(absPath), personaRoot) === personaId2;
72149
+ return personaIdFromPath(path84.resolve(absPath), personaRoot) === personaId2;
71768
72150
  }
71769
72151
 
71770
72152
  // src/handlers/history.ts
@@ -71818,7 +72200,7 @@ function buildHistoryHandlers(deps) {
71818
72200
  if (!pid) return false;
71819
72201
  return isGuestPathAllowed(
71820
72202
  ctx.grants,
71821
- path84.join(personaRoot, pid),
72203
+ path85.join(personaRoot, pid),
71822
72204
  personaRoot,
71823
72205
  "read",
71824
72206
  userWorkDir
@@ -71830,7 +72212,7 @@ function buildHistoryHandlers(deps) {
71830
72212
  };
71831
72213
  const list = async (frame, _client, ctx) => {
71832
72214
  const args = HistoryListArgs.parse(frame);
71833
- assertGuestPath(ctx, path84.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
72215
+ assertGuestPath(ctx, path85.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
71834
72216
  const sessions = await history.listSessions(args);
71835
72217
  return { response: { type: "history:list", sessions } };
71836
72218
  };
@@ -71905,14 +72287,14 @@ function buildHistoryHandlers(deps) {
71905
72287
  };
71906
72288
  const subagents = async (frame, _client, ctx) => {
71907
72289
  const args = HistorySubagentsArgs.parse(frame);
71908
- assertGuestPath(ctx, path84.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
72290
+ assertGuestPath(ctx, path85.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
71909
72291
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
71910
72292
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
71911
72293
  return { response: { type: "history:subagents", subagents: subs } };
71912
72294
  };
71913
72295
  const subagentRead = async (frame, _client, ctx) => {
71914
72296
  const args = HistorySubagentReadArgs.parse(frame);
71915
- assertGuestPath(ctx, path84.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
72297
+ assertGuestPath(ctx, path85.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
71916
72298
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
71917
72299
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
71918
72300
  return { response: { type: "history:subagent-read", ...res } };
@@ -71922,7 +72304,7 @@ function buildHistoryHandlers(deps) {
71922
72304
  if (ctx?.principal.kind === "guest" && personaRoot) {
71923
72305
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
71924
72306
  const filtered = dirs.filter(
71925
- (d2) => isGuestPathAllowed(ctx.grants, path84.resolve(d2.cwd), personaRoot, "read", userWorkDir)
72307
+ (d2) => isGuestPathAllowed(ctx.grants, path85.resolve(d2.cwd), personaRoot, "read", userWorkDir)
71926
72308
  );
71927
72309
  return { response: { type: "history:recentDirs", dirs: filtered } };
71928
72310
  }
@@ -71939,17 +72321,17 @@ function buildHistoryHandlers(deps) {
71939
72321
  }
71940
72322
 
71941
72323
  // src/handlers/projects.ts
71942
- var fs80 = __toESM(require("fs"), 1);
72324
+ var fs81 = __toESM(require("fs"), 1);
71943
72325
  var os27 = __toESM(require("os"), 1);
71944
- var path85 = __toESM(require("path"), 1);
72326
+ var path86 = __toESM(require("path"), 1);
71945
72327
  var import_node_child_process19 = require("child_process");
71946
72328
  init_protocol();
71947
- var DEFAULT_PROJECTS_ROOT = path85.join(os27.homedir(), "Documents", "ChatGPT");
72329
+ var DEFAULT_PROJECTS_ROOT = path86.join(os27.homedir(), "Documents", "ChatGPT");
71948
72330
  function allocateDir(root, name) {
71949
- let candidate = path85.join(root, name);
72331
+ let candidate = path86.join(root, name);
71950
72332
  let n2 = 2;
71951
- while (fs80.existsSync(candidate)) {
71952
- candidate = path85.join(root, `${name} ${n2}`);
72333
+ while (fs81.existsSync(candidate)) {
72334
+ candidate = path86.join(root, `${name} ${n2}`);
71953
72335
  n2 += 1;
71954
72336
  }
71955
72337
  return candidate;
@@ -71977,7 +72359,7 @@ function buildProjectHandlers(deps) {
71977
72359
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
71978
72360
  }
71979
72361
  try {
71980
- if (!fs80.statSync(args.path).isDirectory()) throw new Error("not dir");
72362
+ if (!fs81.statSync(args.path).isDirectory()) throw new Error("not dir");
71981
72363
  } catch {
71982
72364
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
71983
72365
  }
@@ -71993,7 +72375,7 @@ function buildProjectHandlers(deps) {
71993
72375
  let target;
71994
72376
  if (args.path) {
71995
72377
  try {
71996
- if (!fs80.statSync(args.path).isDirectory()) throw new Error("not dir");
72378
+ if (!fs81.statSync(args.path).isDirectory()) throw new Error("not dir");
71997
72379
  } catch {
71998
72380
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
71999
72381
  }
@@ -72001,15 +72383,15 @@ function buildProjectHandlers(deps) {
72001
72383
  } else {
72002
72384
  const name = args.name;
72003
72385
  try {
72004
- fs80.mkdirSync(root, { recursive: true });
72386
+ fs81.mkdirSync(root, { recursive: true });
72005
72387
  target = allocateDir(root, name);
72006
- fs80.mkdirSync(target);
72388
+ fs81.mkdirSync(target);
72007
72389
  } catch (err) {
72008
72390
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
72009
72391
  }
72010
72392
  const git2 = (0, import_node_child_process19.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
72011
72393
  if (git2.status !== 0) {
72012
- fs80.rmSync(target, { recursive: true, force: true });
72394
+ fs81.rmSync(target, { recursive: true, force: true });
72013
72395
  throw new ClawdError(
72014
72396
  ERROR_CODES.INVALID_CWD,
72015
72397
  `git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
@@ -72034,7 +72416,7 @@ function buildProjectHandlers(deps) {
72034
72416
  }
72035
72417
 
72036
72418
  // src/handlers/workspace.ts
72037
- var path86 = __toESM(require("path"), 1);
72419
+ var path87 = __toESM(require("path"), 1);
72038
72420
  init_protocol();
72039
72421
  var os28 = __toESM(require("os"), 1);
72040
72422
  init_protocol();
@@ -72077,22 +72459,22 @@ function buildWorkspaceHandlers(deps) {
72077
72459
  const args = WorkspaceListArgs.parse(frame);
72078
72460
  const isGuest = ctx?.principal.kind === "guest";
72079
72461
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os28.homedir();
72080
- const resolvedCwd = path86.resolve(args.cwd ?? fallbackCwd);
72081
- const target = args.path ? path86.resolve(resolvedCwd, args.path) : resolvedCwd;
72462
+ const resolvedCwd = path87.resolve(args.cwd ?? fallbackCwd);
72463
+ const target = args.path ? path87.resolve(resolvedCwd, args.path) : resolvedCwd;
72082
72464
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
72083
72465
  const res = workspace.list({ ...args, cwd: resolvedCwd });
72084
72466
  return { response: { type: "workspace:list", ...res } };
72085
72467
  };
72086
72468
  const read = async (frame, _client, ctx) => {
72087
72469
  const args = WorkspaceReadArgs.parse(frame);
72088
- const target = path86.isAbsolute(args.path) ? path86.resolve(args.path) : path86.resolve(args.cwd, args.path);
72470
+ const target = path87.isAbsolute(args.path) ? path87.resolve(args.path) : path87.resolve(args.cwd, args.path);
72089
72471
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
72090
72472
  const res = workspace.read(args);
72091
72473
  return { response: { type: "workspace:read", ...res } };
72092
72474
  };
72093
72475
  const skillsList = async (frame, _client, ctx) => {
72094
72476
  const args = SkillsListArgs.parse(frame);
72095
- const cwdAbs = path86.resolve(args.cwd);
72477
+ const cwdAbs = path87.resolve(args.cwd);
72096
72478
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
72097
72479
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
72098
72480
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -72104,7 +72486,7 @@ function buildWorkspaceHandlers(deps) {
72104
72486
  };
72105
72487
  const agentsList = async (frame, _client, ctx) => {
72106
72488
  const args = AgentsListArgs.parse(frame);
72107
- const cwdAbs = path86.resolve(args.cwd);
72489
+ const cwdAbs = path87.resolve(args.cwd);
72108
72490
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
72109
72491
  if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
72110
72492
  return { response: { type: "agents:list", agents: [] } };
@@ -72126,20 +72508,20 @@ function buildWorkspaceHandlers(deps) {
72126
72508
  }
72127
72509
 
72128
72510
  // src/handlers/git.ts
72129
- var path88 = __toESM(require("path"), 1);
72511
+ var path89 = __toESM(require("path"), 1);
72130
72512
  init_protocol();
72131
72513
  init_protocol();
72132
72514
 
72133
72515
  // src/workspace/git.ts
72134
72516
  var import_node_child_process20 = require("child_process");
72135
- var import_node_fs63 = __toESM(require("fs"), 1);
72136
- var import_node_path70 = __toESM(require("path"), 1);
72517
+ var import_node_fs64 = __toESM(require("fs"), 1);
72518
+ var import_node_path71 = __toESM(require("path"), 1);
72137
72519
  var import_node_util2 = require("util");
72138
72520
  var pexec = (0, import_node_util2.promisify)(import_node_child_process20.execFile);
72139
72521
  function normalizePath(p3) {
72140
- const resolved = import_node_path70.default.resolve(p3);
72522
+ const resolved = import_node_path71.default.resolve(p3);
72141
72523
  try {
72142
- return import_node_fs63.default.realpathSync(resolved);
72524
+ return import_node_fs64.default.realpathSync(resolved);
72143
72525
  } catch {
72144
72526
  return resolved;
72145
72527
  }
@@ -72213,7 +72595,7 @@ async function listGitBranches(cwd) {
72213
72595
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
72214
72596
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
72215
72597
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
72216
- if (!isGuestPathAllowed(ctx.grants, path88.resolve(cwd), personaRoot, "read", userWorkDir)) {
72598
+ if (!isGuestPathAllowed(ctx.grants, path89.resolve(cwd), personaRoot, "read", userWorkDir)) {
72217
72599
  throw new ClawdError(
72218
72600
  ERROR_CODES.UNAUTHORIZED,
72219
72601
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -72470,12 +72852,12 @@ async function queryCodexAccount(deps = {}) {
72470
72852
  }
72471
72853
 
72472
72854
  // src/tools/pi-account.ts
72473
- var import_node_fs64 = __toESM(require("fs"), 1);
72474
- var import_node_path71 = __toESM(require("path"), 1);
72855
+ var import_node_fs65 = __toESM(require("fs"), 1);
72856
+ var import_node_path72 = __toESM(require("path"), 1);
72475
72857
  function readPiCredentials(agentDir) {
72476
72858
  let raw;
72477
72859
  try {
72478
- raw = JSON.parse(import_node_fs64.default.readFileSync(import_node_path71.default.join(agentDir, "auth.json"), "utf8"));
72860
+ raw = JSON.parse(import_node_fs65.default.readFileSync(import_node_path72.default.join(agentDir, "auth.json"), "utf8"));
72479
72861
  } catch {
72480
72862
  return {};
72481
72863
  }
@@ -73566,21 +73948,21 @@ function computeMethodAccess(args) {
73566
73948
  }
73567
73949
 
73568
73950
  // src/version.ts
73569
- var version = "0.2.612".length > 0 ? "0.2.612" : "dev";
73951
+ var version = "0.2.613".length > 0 ? "0.2.613" : "dev";
73570
73952
 
73571
73953
  // src/cli-probe/probe.ts
73572
- var fs83 = __toESM(require("fs"), 1);
73573
- var path90 = __toESM(require("path"), 1);
73954
+ var fs84 = __toESM(require("fs"), 1);
73955
+ var path91 = __toESM(require("path"), 1);
73574
73956
  var PKG_NAME = "@clawos-dev/clawd";
73575
73957
  var BIN_NAME = "clawd";
73576
73958
  var MAX_PARENT_HOPS = 5;
73577
73959
  function probeGlobalCli(pathEnv) {
73578
73960
  if (!pathEnv) return null;
73579
- for (const dir of pathEnv.split(path90.delimiter)) {
73961
+ for (const dir of pathEnv.split(path91.delimiter)) {
73580
73962
  if (!dir) continue;
73581
73963
  let real;
73582
73964
  try {
73583
- real = fs83.realpathSync(path90.join(dir, BIN_NAME));
73965
+ real = fs84.realpathSync(path91.join(dir, BIN_NAME));
73584
73966
  } catch {
73585
73967
  continue;
73586
73968
  }
@@ -73590,15 +73972,15 @@ function probeGlobalCli(pathEnv) {
73590
73972
  return null;
73591
73973
  }
73592
73974
  function readOwnPackageVersion(entryPath) {
73593
- let dir = path90.dirname(entryPath);
73975
+ let dir = path91.dirname(entryPath);
73594
73976
  for (let i2 = 0; i2 < MAX_PARENT_HOPS; i2++) {
73595
73977
  try {
73596
- const raw = fs83.readFileSync(path90.join(dir, "package.json"), "utf8");
73978
+ const raw = fs84.readFileSync(path91.join(dir, "package.json"), "utf8");
73597
73979
  const pkg = JSON.parse(raw);
73598
73980
  if (pkg.name !== PKG_NAME) return null;
73599
73981
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
73600
73982
  } catch {
73601
- const parent = path90.dirname(dir);
73983
+ const parent = path91.dirname(dir);
73602
73984
  if (parent === dir) return null;
73603
73985
  dir = parent;
73604
73986
  }
@@ -73774,7 +74156,7 @@ function buildPersonaHandlers(deps) {
73774
74156
  }
73775
74157
 
73776
74158
  // src/handlers/attachment.ts
73777
- var import_node_path72 = __toESM(require("path"), 1);
74159
+ var import_node_path73 = __toESM(require("path"), 1);
73778
74160
  init_protocol();
73779
74161
  init_protocol();
73780
74162
  function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot) {
@@ -73853,12 +74235,12 @@ function buildAttachmentHandlers(deps) {
73853
74235
  `session ${args.sessionId} scope unresolved`
73854
74236
  );
73855
74237
  }
73856
- const cwdAbs = import_node_path72.default.resolve(sessionFile.cwd);
73857
- const candidateAbs = import_node_path72.default.isAbsolute(args.relPath) ? import_node_path72.default.resolve(args.relPath) : import_node_path72.default.resolve(cwdAbs, args.relPath);
74238
+ const cwdAbs = import_node_path73.default.resolve(sessionFile.cwd);
74239
+ const candidateAbs = import_node_path73.default.isAbsolute(args.relPath) ? import_node_path73.default.resolve(args.relPath) : import_node_path73.default.resolve(cwdAbs, args.relPath);
73858
74240
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
73859
74241
  const entries = deps.groupFileStore.list(scope, args.sessionId);
73860
74242
  const entry = entries.find((e) => {
73861
- const storedAbs = import_node_path72.default.isAbsolute(e.relPath) ? import_node_path72.default.resolve(e.relPath) : import_node_path72.default.resolve(cwdAbs, e.relPath);
74243
+ const storedAbs = import_node_path73.default.isAbsolute(e.relPath) ? import_node_path73.default.resolve(e.relPath) : import_node_path73.default.resolve(cwdAbs, e.relPath);
73862
74244
  return storedAbs === candidateAbs && !e.stale;
73863
74245
  });
73864
74246
  if (!entry) {
@@ -73882,7 +74264,7 @@ function buildAttachmentHandlers(deps) {
73882
74264
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
73883
74265
  const f2 = deps.sessionStore.read(sessionId);
73884
74266
  if (!f2) return;
73885
- assertGuestAttachmentPath(ctx, import_node_path72.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
74267
+ assertGuestAttachmentPath(ctx, import_node_path73.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
73886
74268
  }
73887
74269
  const groupAdd = async (frame, _client, ctx) => {
73888
74270
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -73897,8 +74279,8 @@ function buildAttachmentHandlers(deps) {
73897
74279
  if (!scope) {
73898
74280
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
73899
74281
  }
73900
- const cwdAbs = import_node_path72.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
73901
- const candidateAbs = import_node_path72.default.isAbsolute(args.relPath) ? import_node_path72.default.resolve(args.relPath) : import_node_path72.default.resolve(cwdAbs, args.relPath);
74282
+ const cwdAbs = import_node_path73.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
74283
+ const candidateAbs = import_node_path73.default.isAbsolute(args.relPath) ? import_node_path73.default.resolve(args.relPath) : import_node_path73.default.resolve(cwdAbs, args.relPath);
73902
74284
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
73903
74285
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
73904
74286
  const size = 0;
@@ -73957,19 +74339,19 @@ function buildAttachmentHandlers(deps) {
73957
74339
 
73958
74340
  // src/handlers/extension.ts
73959
74341
  var import_promises15 = __toESM(require("fs/promises"), 1);
73960
- var import_node_path77 = __toESM(require("path"), 1);
74342
+ var import_node_path78 = __toESM(require("path"), 1);
73961
74343
  init_protocol();
73962
74344
 
73963
74345
  // src/extension/bundle-zip.ts
73964
74346
  var import_promises12 = __toESM(require("fs/promises"), 1);
73965
- var import_node_path73 = __toESM(require("path"), 1);
73966
- var import_node_crypto23 = __toESM(require("crypto"), 1);
74347
+ var import_node_path74 = __toESM(require("path"), 1);
74348
+ var import_node_crypto24 = __toESM(require("crypto"), 1);
73967
74349
  var import_jszip2 = __toESM(require_lib3(), 1);
73968
74350
  async function bundleExtensionDir(dir) {
73969
74351
  const entries = await listFilesSorted(dir);
73970
74352
  const zip = new import_jszip2.default();
73971
74353
  for (const rel of entries) {
73972
- const abs = import_node_path73.default.join(dir, rel);
74354
+ const abs = import_node_path74.default.join(dir, rel);
73973
74355
  const content = await import_promises12.default.readFile(abs);
73974
74356
  zip.file(rel, content, { date: FIXED_DATE });
73975
74357
  }
@@ -73978,7 +74360,7 @@ async function bundleExtensionDir(dir) {
73978
74360
  compression: "DEFLATE",
73979
74361
  compressionOptions: { level: 6 }
73980
74362
  });
73981
- const sha256 = import_node_crypto23.default.createHash("sha256").update(buffer).digest("hex");
74363
+ const sha256 = import_node_crypto24.default.createHash("sha256").update(buffer).digest("hex");
73982
74364
  return { buffer, sha256 };
73983
74365
  }
73984
74366
  var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
@@ -73990,7 +74372,7 @@ async function listFilesSorted(rootDir) {
73990
74372
  return out;
73991
74373
  }
73992
74374
  async function walk(absRoot, relPrefix, out) {
73993
- const dirAbs = import_node_path73.default.join(absRoot, relPrefix);
74375
+ const dirAbs = import_node_path74.default.join(absRoot, relPrefix);
73994
74376
  const entries = await import_promises12.default.readdir(dirAbs, { withFileTypes: true });
73995
74377
  for (const e of entries) {
73996
74378
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -74044,25 +74426,25 @@ function computePublishCheck(args) {
74044
74426
 
74045
74427
  // src/extension/install-flow.ts
74046
74428
  var import_promises13 = __toESM(require("fs/promises"), 1);
74047
- var import_node_path75 = __toESM(require("path"), 1);
74429
+ var import_node_path76 = __toESM(require("path"), 1);
74048
74430
  var import_node_os28 = __toESM(require("os"), 1);
74049
- var import_node_crypto24 = __toESM(require("crypto"), 1);
74431
+ var import_node_crypto25 = __toESM(require("crypto"), 1);
74050
74432
  var import_jszip3 = __toESM(require_lib3(), 1);
74051
74433
 
74052
74434
  // src/extension/paths.ts
74053
74435
  var import_node_os27 = __toESM(require("os"), 1);
74054
- var import_node_path74 = __toESM(require("path"), 1);
74436
+ var import_node_path75 = __toESM(require("path"), 1);
74055
74437
  function clawdHomeRoot(override) {
74056
- return override ?? process.env.CLAWD_HOME ?? import_node_path74.default.join(import_node_os27.default.homedir(), ".clawd");
74438
+ return override ?? process.env.CLAWD_HOME ?? import_node_path75.default.join(import_node_os27.default.homedir(), ".clawd");
74057
74439
  }
74058
74440
  function extensionsRoot(override) {
74059
- return import_node_path74.default.join(clawdHomeRoot(override), "extensions");
74441
+ return import_node_path75.default.join(clawdHomeRoot(override), "extensions");
74060
74442
  }
74061
74443
  function publishedChannelsFile(override) {
74062
- return import_node_path74.default.join(clawdHomeRoot(override), "extensions-published.json");
74444
+ return import_node_path75.default.join(clawdHomeRoot(override), "extensions-published.json");
74063
74445
  }
74064
74446
  function bundleCacheRoot(override) {
74065
- return import_node_path74.default.join(clawdHomeRoot(override), "extension-bundles");
74447
+ return import_node_path75.default.join(clawdHomeRoot(override), "extension-bundles");
74066
74448
  }
74067
74449
 
74068
74450
  // src/extension/install-flow.ts
@@ -74075,7 +74457,7 @@ var InstallError = class extends Error {
74075
74457
  };
74076
74458
  async function installFromChannel(args, deps) {
74077
74459
  const { channelRef, snapshotHash, bundleZip } = args;
74078
- const computed = import_node_crypto24.default.createHash("sha256").update(bundleZip).digest("hex");
74460
+ const computed = import_node_crypto25.default.createHash("sha256").update(bundleZip).digest("hex");
74079
74461
  if (computed !== snapshotHash) {
74080
74462
  throw new InstallError(
74081
74463
  "HASH_MISMATCH",
@@ -74089,7 +74471,7 @@ async function installFromChannel(args, deps) {
74089
74471
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
74090
74472
  }
74091
74473
  for (const name of Object.keys(zip.files)) {
74092
- if (name.includes("..") || name.startsWith("/") || import_node_path75.default.isAbsolute(name)) {
74474
+ if (name.includes("..") || name.startsWith("/") || import_node_path76.default.isAbsolute(name)) {
74093
74475
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
74094
74476
  }
74095
74477
  }
@@ -74121,7 +74503,7 @@ async function installFromChannel(args, deps) {
74121
74503
  );
74122
74504
  }
74123
74505
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
74124
- const destDir = import_node_path75.default.join(deps.extensionsRoot, localExtId);
74506
+ const destDir = import_node_path76.default.join(deps.extensionsRoot, localExtId);
74125
74507
  let destExists = false;
74126
74508
  try {
74127
74509
  await import_promises13.default.access(destDir);
@@ -74135,16 +74517,16 @@ async function installFromChannel(args, deps) {
74135
74517
  );
74136
74518
  }
74137
74519
  const stage = await import_promises13.default.mkdtemp(
74138
- import_node_path75.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
74520
+ import_node_path76.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
74139
74521
  );
74140
74522
  try {
74141
74523
  for (const [name, entry] of Object.entries(zip.files)) {
74142
- const dest = import_node_path75.default.join(stage, name);
74524
+ const dest = import_node_path76.default.join(stage, name);
74143
74525
  if (entry.dir) {
74144
74526
  await import_promises13.default.mkdir(dest, { recursive: true });
74145
74527
  continue;
74146
74528
  }
74147
- await import_promises13.default.mkdir(import_node_path75.default.dirname(dest), { recursive: true });
74529
+ await import_promises13.default.mkdir(import_node_path76.default.dirname(dest), { recursive: true });
74148
74530
  if (name === "manifest.json") {
74149
74531
  const rewritten = { ...parsed.data, id: localExtId };
74150
74532
  await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -74165,9 +74547,9 @@ async function installFromChannel(args, deps) {
74165
74547
 
74166
74548
  // src/extension/update-flow.ts
74167
74549
  var import_promises14 = __toESM(require("fs/promises"), 1);
74168
- var import_node_path76 = __toESM(require("path"), 1);
74550
+ var import_node_path77 = __toESM(require("path"), 1);
74169
74551
  var import_node_os29 = __toESM(require("os"), 1);
74170
- var import_node_crypto25 = __toESM(require("crypto"), 1);
74552
+ var import_node_crypto26 = __toESM(require("crypto"), 1);
74171
74553
  var import_jszip4 = __toESM(require_lib3(), 1);
74172
74554
  var UpdateError = class extends Error {
74173
74555
  constructor(code, message) {
@@ -74182,11 +74564,11 @@ async function updateFromChannel(args, deps) {
74182
74564
  channelRef.extId,
74183
74565
  channelRef.ownerPrincipalId
74184
74566
  );
74185
- const liveDir = import_node_path76.default.join(deps.extensionsRoot, localExtId);
74567
+ const liveDir = import_node_path77.default.join(deps.extensionsRoot, localExtId);
74186
74568
  const prevDir = `${liveDir}.prev`;
74187
74569
  let existingVersion;
74188
74570
  try {
74189
- const raw = await import_promises14.default.readFile(import_node_path76.default.join(liveDir, "manifest.json"), "utf8");
74571
+ const raw = await import_promises14.default.readFile(import_node_path77.default.join(liveDir, "manifest.json"), "utf8");
74190
74572
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
74191
74573
  if (!parsed2.success) {
74192
74574
  throw new UpdateError(
@@ -74205,7 +74587,7 @@ async function updateFromChannel(args, deps) {
74205
74587
  if (e instanceof UpdateError) throw e;
74206
74588
  throw e;
74207
74589
  }
74208
- const computed = import_node_crypto25.default.createHash("sha256").update(bundleZip).digest("hex");
74590
+ const computed = import_node_crypto26.default.createHash("sha256").update(bundleZip).digest("hex");
74209
74591
  if (computed !== snapshotHash) {
74210
74592
  throw new UpdateError(
74211
74593
  "HASH_MISMATCH",
@@ -74219,7 +74601,7 @@ async function updateFromChannel(args, deps) {
74219
74601
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
74220
74602
  }
74221
74603
  for (const name of Object.keys(zip.files)) {
74222
- if (name.includes("..") || name.startsWith("/") || import_node_path76.default.isAbsolute(name)) {
74604
+ if (name.includes("..") || name.startsWith("/") || import_node_path77.default.isAbsolute(name)) {
74223
74605
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
74224
74606
  }
74225
74607
  }
@@ -74254,16 +74636,16 @@ async function updateFromChannel(args, deps) {
74254
74636
  await import_promises14.default.rm(prevDir, { recursive: true, force: true });
74255
74637
  await import_promises14.default.rename(liveDir, prevDir);
74256
74638
  const stage = await import_promises14.default.mkdtemp(
74257
- import_node_path76.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
74639
+ import_node_path77.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
74258
74640
  );
74259
74641
  try {
74260
74642
  for (const [name, entry] of Object.entries(zip.files)) {
74261
- const dest = import_node_path76.default.join(stage, name);
74643
+ const dest = import_node_path77.default.join(stage, name);
74262
74644
  if (entry.dir) {
74263
74645
  await import_promises14.default.mkdir(dest, { recursive: true });
74264
74646
  continue;
74265
74647
  }
74266
- await import_promises14.default.mkdir(import_node_path76.default.dirname(dest), { recursive: true });
74648
+ await import_promises14.default.mkdir(import_node_path77.default.dirname(dest), { recursive: true });
74267
74649
  if (name === "manifest.json") {
74268
74650
  const rewritten = { ...parsed.data, id: localExtId };
74269
74651
  await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -74330,7 +74712,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
74330
74712
  );
74331
74713
  }
74332
74714
  }
74333
- const manifestPath = import_node_path77.default.join(root, extId, "manifest.json");
74715
+ const manifestPath = import_node_path78.default.join(root, extId, "manifest.json");
74334
74716
  const manifest = await readManifest(root, extId);
74335
74717
  const next = { ...manifest, version: newVersion };
74336
74718
  const tmp = `${manifestPath}.tmp`;
@@ -74338,7 +74720,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
74338
74720
  await import_promises15.default.rename(tmp, manifestPath);
74339
74721
  }
74340
74722
  async function readManifest(root, extId) {
74341
- const file = import_node_path77.default.join(root, extId, "manifest.json");
74723
+ const file = import_node_path78.default.join(root, extId, "manifest.json");
74342
74724
  let raw;
74343
74725
  try {
74344
74726
  raw = await import_promises15.default.readFile(file, "utf8");
@@ -74422,7 +74804,7 @@ function buildExtensionHandlers(deps) {
74422
74804
  };
74423
74805
  async function buildSnapshotMeta(extId) {
74424
74806
  const manifest = await readManifest(deps.root, extId);
74425
- const { sha256, buffer } = await bundleExtensionDir(import_node_path77.default.join(deps.root, extId));
74807
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path78.default.join(deps.root, extId));
74426
74808
  return { manifest, contentHash: sha256, buffer };
74427
74809
  }
74428
74810
  const publish = async (frame, _client, ctx) => {
@@ -74893,12 +75275,12 @@ function buildTopicHandlers(deps) {
74893
75275
  "topic:delete": async (frame) => {
74894
75276
  const { topicId } = TopicDeleteArgsSchema.parse(frame);
74895
75277
  const topic = mustGet(topicId);
74896
- const { removed, broadcast } = deps.deleteSession(topic.masterSessionId);
75278
+ const { removed, broadcast } = await deps.deleteSession(topic.masterSessionId);
74897
75279
  const removedWorkerSessionIds = [];
74898
75280
  const allBroadcast = [...broadcast];
74899
75281
  for (const sessionId of workerSessionIdsOf(topic.masterSessionId)) {
74900
75282
  try {
74901
- const w3 = deps.deleteSession(sessionId);
75283
+ const w3 = await deps.deleteSession(sessionId);
74902
75284
  allBroadcast.push(...w3.broadcast);
74903
75285
  if (w3.removed) removedWorkerSessionIds.push(sessionId);
74904
75286
  } catch (err) {
@@ -75250,7 +75632,7 @@ function buildVisitorHandlers(deps) {
75250
75632
 
75251
75633
  // src/extension/registry.ts
75252
75634
  var import_promises17 = __toESM(require("fs/promises"), 1);
75253
- var import_node_path78 = __toESM(require("path"), 1);
75635
+ var import_node_path79 = __toESM(require("path"), 1);
75254
75636
  async function loadAll(root) {
75255
75637
  let entries;
75256
75638
  try {
@@ -75263,13 +75645,13 @@ async function loadAll(root) {
75263
75645
  for (const ent of entries) {
75264
75646
  if (!ent.isDirectory()) continue;
75265
75647
  if (ent.name.startsWith(".")) continue;
75266
- records.push(await loadOne(import_node_path78.default.join(root, ent.name), ent.name));
75648
+ records.push(await loadOne(import_node_path79.default.join(root, ent.name), ent.name));
75267
75649
  }
75268
75650
  records.sort((a2, b3) => a2.extId < b3.extId ? -1 : a2.extId > b3.extId ? 1 : 0);
75269
75651
  return records;
75270
75652
  }
75271
75653
  async function loadOne(dir, dirName) {
75272
- const manifestPath = import_node_path78.default.join(dir, "manifest.json");
75654
+ const manifestPath = import_node_path79.default.join(dir, "manifest.json");
75273
75655
  let raw;
75274
75656
  try {
75275
75657
  raw = await import_promises17.default.readFile(manifestPath, "utf8");
@@ -75314,7 +75696,7 @@ async function loadOne(dir, dirName) {
75314
75696
 
75315
75697
  // src/extension/uninstall.ts
75316
75698
  var import_promises18 = __toESM(require("fs/promises"), 1);
75317
- var import_node_path79 = __toESM(require("path"), 1);
75699
+ var import_node_path80 = __toESM(require("path"), 1);
75318
75700
  var UninstallError = class extends Error {
75319
75701
  constructor(code, message) {
75320
75702
  super(message);
@@ -75323,7 +75705,7 @@ var UninstallError = class extends Error {
75323
75705
  code;
75324
75706
  };
75325
75707
  async function uninstall(deps) {
75326
- const dir = import_node_path79.default.join(deps.root, deps.extId);
75708
+ const dir = import_node_path80.default.join(deps.root, deps.extId);
75327
75709
  try {
75328
75710
  await import_promises18.default.access(dir);
75329
75711
  } catch {
@@ -75334,7 +75716,7 @@ async function uninstall(deps) {
75334
75716
  }
75335
75717
 
75336
75718
  // src/handlers/index.ts
75337
- var import_node_crypto26 = require("crypto");
75719
+ var import_node_crypto27 = require("crypto");
75338
75720
 
75339
75721
  // src/handlers/peer-exec.ts
75340
75722
  init_protocol();
@@ -75491,7 +75873,7 @@ function buildMethodHandlers(deps) {
75491
75873
  const c2 = deps.contactStore.get(deviceId);
75492
75874
  return c2 ? { deviceId: c2.deviceId, remoteUrl: c2.remoteUrl, connectToken: c2.connectToken } : null;
75493
75875
  },
75494
- genId: () => (0, import_node_crypto26.randomUUID)(),
75876
+ genId: () => (0, import_node_crypto27.randomUUID)(),
75495
75877
  now: () => Date.now(),
75496
75878
  forwardInboxPostToPeer,
75497
75879
  logger: deps.logger
@@ -75541,7 +75923,7 @@ function buildMethodHandlers(deps) {
75541
75923
  broadcast: deps.broadcastToOwners
75542
75924
  }),
75543
75925
  ...buildMasterHandlers({
75544
- authorityTablePath: import_node_path80.default.join(deps.masterDataDir, "master-authority.json")
75926
+ authorityTablePath: import_node_path81.default.join(deps.masterDataDir, "master-authority.json")
75545
75927
  }),
75546
75928
  ...buildTopicHandlers({
75547
75929
  topicStore: deps.topicStore,
@@ -75684,7 +76066,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
75684
76066
 
75685
76067
  // src/extension/runtime.ts
75686
76068
  var import_node_child_process25 = require("child_process");
75687
- var import_node_path81 = __toESM(require("path"), 1);
76069
+ var import_node_path82 = __toESM(require("path"), 1);
75688
76070
  var import_promises19 = require("timers/promises");
75689
76071
 
75690
76072
  // src/extension/port-allocator.ts
@@ -75785,7 +76167,7 @@ var Runtime = class {
75785
76167
  /\$CLAWOS_EXT_PORT/g,
75786
76168
  String(port)
75787
76169
  );
75788
- const dir = import_node_path81.default.join(this.root, extId);
76170
+ const dir = import_node_path82.default.join(this.root, extId);
75789
76171
  const env = {
75790
76172
  ...process.env,
75791
76173
  CLAWOS_EXT_PORT: String(port),
@@ -75897,7 +76279,7 @@ ${handle.stderrTail}`
75897
76279
 
75898
76280
  // src/extension/published-channels.ts
75899
76281
  var import_promises20 = __toESM(require("fs/promises"), 1);
75900
- var import_node_path82 = __toESM(require("path"), 1);
76282
+ var import_node_path83 = __toESM(require("path"), 1);
75901
76283
  init_zod();
75902
76284
  var PublishedChannelsError = class extends Error {
75903
76285
  constructor(code, message) {
@@ -75996,7 +76378,7 @@ var PublishedChannelStore = class {
75996
76378
  )
75997
76379
  };
75998
76380
  const tmp = `${this.filePath}.tmp`;
75999
- await import_promises20.default.mkdir(import_node_path82.default.dirname(this.filePath), { recursive: true });
76381
+ await import_promises20.default.mkdir(import_node_path83.default.dirname(this.filePath), { recursive: true });
76000
76382
  await import_promises20.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
76001
76383
  await import_promises20.default.rename(tmp, this.filePath);
76002
76384
  }
@@ -76004,7 +76386,7 @@ var PublishedChannelStore = class {
76004
76386
 
76005
76387
  // src/extension/bundle-cache.ts
76006
76388
  var import_promises21 = __toESM(require("fs/promises"), 1);
76007
- var import_node_path83 = __toESM(require("path"), 1);
76389
+ var import_node_path84 = __toESM(require("path"), 1);
76008
76390
  var BundleCache = class {
76009
76391
  constructor(rootDir) {
76010
76392
  this.rootDir = rootDir;
@@ -76013,14 +76395,14 @@ var BundleCache = class {
76013
76395
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
76014
76396
  async write(snapshotHash, buffer) {
76015
76397
  await import_promises21.default.mkdir(this.rootDir, { recursive: true });
76016
- const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
76398
+ const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
76017
76399
  const tmp = `${file}.tmp`;
76018
76400
  await import_promises21.default.writeFile(tmp, buffer, { mode: 384 });
76019
76401
  await import_promises21.default.rename(tmp, file);
76020
76402
  }
76021
76403
  /** Returns the bundle bytes, or null when the file doesn't exist. */
76022
76404
  async read(snapshotHash) {
76023
- const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
76405
+ const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
76024
76406
  try {
76025
76407
  return await import_promises21.default.readFile(file);
76026
76408
  } catch (e) {
@@ -76030,7 +76412,7 @@ var BundleCache = class {
76030
76412
  }
76031
76413
  /** Idempotent — missing file is not an error. */
76032
76414
  async delete(snapshotHash) {
76033
- const file = import_node_path83.default.join(this.rootDir, `${snapshotHash}.zip`);
76415
+ const file = import_node_path84.default.join(this.rootDir, `${snapshotHash}.zip`);
76034
76416
  await import_promises21.default.rm(file, { force: true });
76035
76417
  }
76036
76418
  };
@@ -76053,24 +76435,24 @@ async function startDaemon(config) {
76053
76435
  sampling: logShippingCfg.sampling,
76054
76436
  homeDir: import_node_os31.default.homedir()
76055
76437
  });
76056
- const logDir = import_node_path84.default.join(config.dataDir, "log");
76057
- import_node_fs65.default.mkdirSync(logDir, { recursive: true });
76438
+ const logDir = import_node_path85.default.join(config.dataDir, "log");
76439
+ import_node_fs66.default.mkdirSync(logDir, { recursive: true });
76058
76440
  const logger = createLogger({
76059
76441
  level: config.logLevel,
76060
- file: import_node_path84.default.join(logDir, "clawd.log"),
76442
+ file: import_node_path85.default.join(logDir, "clawd.log"),
76061
76443
  logClient
76062
76444
  });
76063
76445
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
76064
76446
  const screenIdleProbeLogger = createFileOnlyLogger({
76065
- file: import_node_path84.default.join(logDir, "screen-idle-probe.log"),
76447
+ file: import_node_path85.default.join(logDir, "screen-idle-probe.log"),
76066
76448
  level: "debug"
76067
76449
  });
76068
76450
  logger.info("screen-idle probe logger enabled", {
76069
- file: import_node_path84.default.join(logDir, "screen-idle-probe.log")
76451
+ file: import_node_path85.default.join(logDir, "screen-idle-probe.log")
76070
76452
  });
76071
76453
  const CAP_TARGETS = [
76072
- import_node_path84.default.join(logDir, "clawd.log"),
76073
- import_node_path84.default.join(logDir, "screen-idle-probe.log")
76454
+ import_node_path85.default.join(logDir, "clawd.log"),
76455
+ import_node_path85.default.join(logDir, "screen-idle-probe.log")
76074
76456
  ];
76075
76457
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
76076
76458
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -76192,11 +76574,11 @@ async function startDaemon(config) {
76192
76574
  const agents = new AgentsScanner();
76193
76575
  const history = new ClaudeHistoryReader();
76194
76576
  let transport = null;
76195
- const personaStore = new PersonaStore(import_node_path84.default.join(config.dataDir, "personas"));
76577
+ const personaStore = new PersonaStore(import_node_path85.default.join(config.dataDir, "personas"));
76196
76578
  const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
76197
76579
  const activeSubscriptionChannel = subscriptionChannelStore.getActive();
76198
76580
  if (activeSubscriptionChannel) applyPiSubscriptionChannel({ channel: activeSubscriptionChannel });
76199
- const usersRoot = import_node_path84.default.join(config.dataDir, "users");
76581
+ const usersRoot = import_node_path85.default.join(config.dataDir, "users");
76200
76582
  const defaultsRoot = findDefaultsRoot(logger);
76201
76583
  if (defaultsRoot) {
76202
76584
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -76213,7 +76595,7 @@ async function startDaemon(config) {
76213
76595
  retirePersonaBuilder({ store: personaStore, logger });
76214
76596
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
76215
76597
  const dispatchStore = createDispatchStore({
76216
- filePath: import_node_path84.default.join(config.dataDir, "dispatch.json"),
76598
+ filePath: import_node_path85.default.join(config.dataDir, "dispatch.json"),
76217
76599
  now: () => Date.now(),
76218
76600
  onFlushError: (err) => logger.error("dispatch store flush failed", {
76219
76601
  reason: err instanceof Error ? err.message : String(err)
@@ -76222,18 +76604,18 @@ async function startDaemon(config) {
76222
76604
  await dispatchStore.load();
76223
76605
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
76224
76606
  const channelStore = createChannelStore({
76225
- filePath: import_node_path84.default.join(config.dataDir, "channels.json"),
76607
+ filePath: import_node_path85.default.join(config.dataDir, "channels.json"),
76226
76608
  now: () => Date.now(),
76227
- genId: () => `ch-${(0, import_node_crypto27.randomUUID)().slice(0, 8)}`,
76609
+ genId: () => `ch-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`,
76228
76610
  onFlushError: (err) => logger.error("channel store flush failed", {
76229
76611
  reason: err instanceof Error ? err.message : String(err)
76230
76612
  })
76231
76613
  });
76232
76614
  await channelStore.load();
76233
76615
  const topicStore = createTopicStore({
76234
- filePath: import_node_path84.default.join(config.dataDir, "topics.json"),
76616
+ filePath: import_node_path85.default.join(config.dataDir, "topics.json"),
76235
76617
  now: () => Date.now(),
76236
- genId: () => `tp-${(0, import_node_crypto27.randomUUID)().slice(0, 8)}`,
76618
+ genId: () => `tp-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`,
76237
76619
  onFlushError: (err) => logger.error("topic store flush failed", {
76238
76620
  reason: err instanceof Error ? err.message : String(err)
76239
76621
  })
@@ -76241,7 +76623,7 @@ async function startDaemon(config) {
76241
76623
  await topicStore.load();
76242
76624
  let deliverPendingRef;
76243
76625
  const personaDispatchManager = new PersonaDispatchManager({
76244
- genId: () => (0, import_node_crypto27.randomUUID)(),
76626
+ genId: () => (0, import_node_crypto28.randomUUID)(),
76245
76627
  store: dispatchStore,
76246
76628
  now: () => Date.now(),
76247
76629
  onCompleted: (sid) => deliverPendingRef?.(sid),
@@ -76258,12 +76640,12 @@ async function startDaemon(config) {
76258
76640
  });
76259
76641
  }
76260
76642
  });
76261
- const here = typeof __dirname === "string" ? __dirname : import_node_path84.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
76643
+ const here = typeof __dirname === "string" ? __dirname : import_node_path85.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
76262
76644
  const mcpConfigs = [];
76263
76645
  const secretsBundleRoot = findSecretsBundleRoot(logger);
76264
- const localSecretsDir = import_node_path84.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
76646
+ const localSecretsDir = import_node_path85.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
76265
76647
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
76266
- const githubTokenFile = import_node_path84.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
76648
+ const githubTokenFile = import_node_path85.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
76267
76649
  const githubIdentity = createGithubIdentity({
76268
76650
  resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
76269
76651
  store: (token) => storeGithubAuth({
@@ -76301,22 +76683,22 @@ async function startDaemon(config) {
76301
76683
  void githubIdentity.refresh();
76302
76684
  return renderPersonaMcpSecrets({
76303
76685
  personaId: personaId2,
76304
- personaDir: import_node_path84.default.join(config.dataDir, "personas", personaId2),
76686
+ personaDir: import_node_path85.default.join(config.dataDir, "personas", personaId2),
76305
76687
  secrets,
76306
- outDir: import_node_path84.default.join(config.dataDir, "persona-mcp"),
76688
+ outDir: import_node_path85.default.join(config.dataDir, "persona-mcp"),
76307
76689
  logger
76308
76690
  });
76309
76691
  };
76310
76692
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
76311
76693
  const dispatchServerCandidates = [
76312
- import_node_path84.default.join(here, "dispatch", "mcp-server.cjs"),
76694
+ import_node_path85.default.join(here, "dispatch", "mcp-server.cjs"),
76313
76695
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
76314
- import_node_path84.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
76696
+ import_node_path85.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
76315
76697
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
76316
76698
  ];
76317
- const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76699
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76318
76700
  if (dispatchServerScriptPath) {
76319
- const dispatchLogPath = import_node_path84.default.join(logDir, "dispatch-mcp-server.log");
76701
+ const dispatchLogPath = import_node_path85.default.join(logDir, "dispatch-mcp-server.log");
76320
76702
  const dispatchCfgPath = writeDispatchMcpConfig({
76321
76703
  dataDir: config.dataDir,
76322
76704
  serverScriptPath: dispatchServerScriptPath,
@@ -76336,12 +76718,12 @@ async function startDaemon(config) {
76336
76718
  });
76337
76719
  }
76338
76720
  const ticketServerCandidates = [
76339
- import_node_path84.default.join(here, "ticket", "mcp-server.cjs"),
76340
- import_node_path84.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
76721
+ import_node_path85.default.join(here, "ticket", "mcp-server.cjs"),
76722
+ import_node_path85.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
76341
76723
  ];
76342
- const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76724
+ const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76343
76725
  if (ticketServerScriptPath) {
76344
- const ticketLogPath = import_node_path84.default.join(logDir, "ticket-mcp-server.log");
76726
+ const ticketLogPath = import_node_path85.default.join(logDir, "ticket-mcp-server.log");
76345
76727
  const ticketCfgPath = writeTicketMcpConfig({
76346
76728
  dataDir: config.dataDir,
76347
76729
  serverScriptPath: ticketServerScriptPath,
@@ -76363,12 +76745,12 @@ async function startDaemon(config) {
76363
76745
  });
76364
76746
  }
76365
76747
  const shiftServerCandidates = [
76366
- import_node_path84.default.join(here, "shift", "mcp-server.cjs"),
76367
- import_node_path84.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
76748
+ import_node_path85.default.join(here, "shift", "mcp-server.cjs"),
76749
+ import_node_path85.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
76368
76750
  ];
76369
- const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76751
+ const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76370
76752
  if (shiftServerScriptPath) {
76371
- const shiftLogPath = import_node_path84.default.join(logDir, "shift-mcp-server.log");
76753
+ const shiftLogPath = import_node_path85.default.join(logDir, "shift-mcp-server.log");
76372
76754
  const shiftCfgPath = await writeShiftMcpConfig({
76373
76755
  dataDir: config.dataDir,
76374
76756
  serverScriptPath: shiftServerScriptPath,
@@ -76389,12 +76771,12 @@ async function startDaemon(config) {
76389
76771
  );
76390
76772
  }
76391
76773
  const inboxServerCandidates = [
76392
- import_node_path84.default.join(here, "inbox", "mcp-server.cjs"),
76393
- import_node_path84.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
76774
+ import_node_path85.default.join(here, "inbox", "mcp-server.cjs"),
76775
+ import_node_path85.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
76394
76776
  ];
76395
- const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76777
+ const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76396
76778
  if (inboxServerScriptPath) {
76397
- const inboxLogPath = import_node_path84.default.join(logDir, "inbox-mcp-server.log");
76779
+ const inboxLogPath = import_node_path85.default.join(logDir, "inbox-mcp-server.log");
76398
76780
  const inboxCfgPath = await writeInboxMcpConfig({
76399
76781
  dataDir: config.dataDir,
76400
76782
  serverScriptPath: inboxServerScriptPath,
@@ -76415,10 +76797,10 @@ async function startDaemon(config) {
76415
76797
  );
76416
76798
  }
76417
76799
  const peerOpsServerCandidates = [
76418
- import_node_path84.default.join(here, "peer-ops", "mcp-server.cjs"),
76419
- import_node_path84.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
76800
+ import_node_path85.default.join(here, "peer-ops", "mcp-server.cjs"),
76801
+ import_node_path85.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
76420
76802
  ];
76421
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76803
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76422
76804
  if (peerOpsServerScriptPath) {
76423
76805
  const peerOpsCfgPath = writePeerOpsMcpConfig({
76424
76806
  dataDir: config.dataDir,
@@ -76438,12 +76820,12 @@ async function startDaemon(config) {
76438
76820
  );
76439
76821
  }
76440
76822
  const rpcToolServerCandidates = [
76441
- import_node_path84.default.join(here, "rpc-tool", "mcp-server.cjs"),
76442
- import_node_path84.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
76823
+ import_node_path85.default.join(here, "rpc-tool", "mcp-server.cjs"),
76824
+ import_node_path85.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
76443
76825
  ];
76444
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
76826
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76445
76827
  if (rpcToolServerScriptPath) {
76446
- const rpcToolLogPath = import_node_path84.default.join(logDir, "rpc-tool-mcp-server.log");
76828
+ const rpcToolLogPath = import_node_path85.default.join(logDir, "rpc-tool-mcp-server.log");
76447
76829
  const rpcToolCfgPath = writeRpcToolMcpConfig({
76448
76830
  dataDir: config.dataDir,
76449
76831
  serverScriptPath: rpcToolServerScriptPath,
@@ -76464,7 +76846,7 @@ async function startDaemon(config) {
76464
76846
  );
76465
76847
  }
76466
76848
  const shiftStore = createShiftStore({
76467
- filePath: import_node_path84.default.join(config.dataDir, "shift.json"),
76849
+ filePath: import_node_path85.default.join(config.dataDir, "shift.json"),
76468
76850
  ownerIdProvider: () => ownerPrincipalId,
76469
76851
  now: () => Date.now()
76470
76852
  });
@@ -76486,7 +76868,7 @@ async function startDaemon(config) {
76486
76868
  getAdapter,
76487
76869
  historyReader: history,
76488
76870
  dataDir: config.dataDir,
76489
- personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
76871
+ personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
76490
76872
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
76491
76873
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
76492
76874
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -76547,10 +76929,10 @@ async function startDaemon(config) {
76547
76929
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
76548
76930
  attachmentGroup: {
76549
76931
  onFileEdit: (input) => {
76550
- const absPath = import_node_path84.default.isAbsolute(input.relPath) ? input.relPath : import_node_path84.default.join(input.cwd, input.relPath);
76932
+ const absPath = import_node_path85.default.isAbsolute(input.relPath) ? input.relPath : import_node_path85.default.join(input.cwd, input.relPath);
76551
76933
  let size = 0;
76552
76934
  try {
76553
- size = import_node_fs65.default.statSync(absPath).size;
76935
+ size = import_node_fs66.default.statSync(absPath).size;
76554
76936
  } catch (err) {
76555
76937
  logger.warn("attachment.onFileEdit stat failed", {
76556
76938
  sessionId: input.sessionId,
@@ -76591,9 +76973,9 @@ async function startDaemon(config) {
76591
76973
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
76592
76974
  }
76593
76975
  const projectsStore = new ProjectsStore({
76594
- file: import_node_path84.default.join(config.dataDir, "projects.json"),
76976
+ file: import_node_path85.default.join(config.dataDir, "projects.json"),
76595
76977
  clawdDir: config.dataDir,
76596
- codexStateFile: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
76978
+ codexStateFile: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
76597
76979
  logger
76598
76980
  });
76599
76981
  const observer = new SessionObserver({
@@ -76657,14 +77039,35 @@ async function startDaemon(config) {
76657
77039
  centralApi: config.clawosApi ?? DEFAULT_CLAWOS_API,
76658
77040
  logger
76659
77041
  });
77042
+ const cloudCancelOutbox = new CloudCancelOutbox(
77043
+ import_node_path85.default.join(config.dataDir, "cloud-cancel-outbox"),
77044
+ (personaId2, clientSessionId, gatewaySessionId) => cloudGateway.cancelEventSession(personaId2, clientSessionId, gatewaySessionId),
77045
+ logger
77046
+ );
77047
+ manager.setCloudCanceller(async (file, runner) => {
77048
+ const personaId2 = personaIdFromCloudCwd(file.cwd);
77049
+ if (!personaId2) throw new Error(`\u4E91\u4F1A\u8BDD ${file.sessionId} \u7F3A\u5C11 gateway persona ID`);
77050
+ const executionId = file.cloudExecutionId ?? file.sessionId;
77051
+ if (!file.cloudGatewaySessionId) throw new Error(`\u4E91\u4F1A\u8BDD ${file.sessionId} \u5C1A\u672A\u6536\u5230 gateway ready`);
77052
+ cloudCancelOutbox.record(executionId, personaId2, file.cloudGatewaySessionId);
77053
+ try {
77054
+ await cloudGateway.cancelEventSession(personaId2, executionId, file.cloudGatewaySessionId);
77055
+ cloudCancelOutbox.confirm(executionId);
77056
+ runner?.confirmCloudCancelled();
77057
+ } catch (e) {
77058
+ cloudCancelOutbox.release(executionId);
77059
+ throw e;
77060
+ }
77061
+ });
77062
+ cloudCancelOutbox.start();
76660
77063
  registerAdapter("claude", claudeAdapter);
76661
- const codexIsolatedHome = import_node_path84.default.join(config.dataDir, "codex-home");
77064
+ const codexIsolatedHome = import_node_path85.default.join(config.dataDir, "codex-home");
76662
77065
  try {
76663
- import_node_fs65.default.mkdirSync(codexIsolatedHome, { recursive: true });
77066
+ import_node_fs66.default.mkdirSync(codexIsolatedHome, { recursive: true });
76664
77067
  for (const f2 of ["auth.json", "config.toml"]) {
76665
- const link = import_node_path84.default.join(codexIsolatedHome, f2);
76666
- const target = import_node_path84.default.join(import_node_os31.default.homedir(), ".codex", f2);
76667
- if (!import_node_fs65.default.existsSync(link) && import_node_fs65.default.existsSync(target)) import_node_fs65.default.symlinkSync(target, link);
77068
+ const link = import_node_path85.default.join(codexIsolatedHome, f2);
77069
+ const target = import_node_path85.default.join(import_node_os31.default.homedir(), ".codex", f2);
77070
+ if (!import_node_fs66.default.existsSync(link) && import_node_fs66.default.existsSync(target)) import_node_fs66.default.symlinkSync(target, link);
76668
77071
  }
76669
77072
  } catch (err) {
76670
77073
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -76675,17 +77078,17 @@ async function startDaemon(config) {
76675
77078
  logger,
76676
77079
  historyReader: new CodexHistoryReader({
76677
77080
  roots: codexRolloutRoots(config.dataDir),
76678
- sharedHome: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex"),
77081
+ sharedHome: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex"),
76679
77082
  logger
76680
77083
  }),
76681
77084
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
76682
77085
  codexHomeFor: (cwd) => resolveCodexHome({
76683
77086
  cwd,
76684
- personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
77087
+ personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
76685
77088
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
76686
77089
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
76687
77090
  projectPaths: projectsStore.listMerged().map((x2) => x2.path),
76688
- sharedHome: import_node_path84.default.join(import_node_os31.default.homedir(), ".codex"),
77091
+ sharedHome: import_node_path85.default.join(import_node_os31.default.homedir(), ".codex"),
76689
77092
  isolatedHome: codexIsolatedHome
76690
77093
  }),
76691
77094
  codexHomeForThread: (threadId) => locateCodexThread(codexRolloutRoots(config.dataDir), threadId)?.home,
@@ -76711,10 +77114,10 @@ async function startDaemon(config) {
76711
77114
  );
76712
77115
  registerAdapter(PI_CLOUD_TOOL_ID, new CloudPiAdapter({ client: cloudGateway, history: cloudHistorySource, logger }));
76713
77116
  const piMcpBridgeCandidates = [
76714
- import_node_path84.default.join(here, "pi-mcp-bridge", "extension.cjs"),
76715
- import_node_path84.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
77117
+ import_node_path85.default.join(here, "pi-mcp-bridge", "extension.cjs"),
77118
+ import_node_path85.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
76716
77119
  ];
76717
- const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
77120
+ const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs66.default.existsSync(p3));
76718
77121
  if (piMcpBridgePath) {
76719
77122
  logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
76720
77123
  } else {
@@ -76959,9 +77362,9 @@ async function startDaemon(config) {
76959
77362
  // 删话题连带删这个话题名下的全部会话(Master + 它派出去的 worker),逐条走这里。
76960
77363
  // 会话已经不在本机了不算失败——话题仍要删得掉,所以 SESSION_NOT_FOUND 吞掉并回
76961
77364
  // removed:false,其余错误照抛(别把真故障说成成功)。
76962
- deleteSession: (sessionId) => {
77365
+ deleteSession: async (sessionId) => {
76963
77366
  try {
76964
- const { broadcast } = manager.delete({ sessionId });
77367
+ const { broadcast } = await manager.deleteWithCloudCancel({ sessionId });
76965
77368
  return { removed: true, broadcast };
76966
77369
  } catch (err) {
76967
77370
  if (err instanceof ClawdError && err.code === ERROR_CODES.SESSION_NOT_FOUND) {
@@ -77020,11 +77423,11 @@ async function startDaemon(config) {
77020
77423
  // 'persona/<pid>/owner',default 走 'default'。
77021
77424
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
77022
77425
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
77023
- personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
77426
+ personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
77024
77427
  usersRoot
77025
77428
  },
77026
77429
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
77027
- personaRoot: import_node_path84.default.join(config.dataDir, "personas"),
77430
+ personaRoot: import_node_path85.default.join(config.dataDir, "personas"),
77028
77431
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
77029
77432
  usersRoot,
77030
77433
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -77330,7 +77733,7 @@ async function startDaemon(config) {
77330
77733
  });
77331
77734
  shiftScheduler.start();
77332
77735
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
77333
- const larkBotStore = createLarkBotBindingStore(import_node_path84.default.join(config.dataDir, "personas"));
77736
+ const larkBotStore = createLarkBotBindingStore(import_node_path85.default.join(config.dataDir, "personas"));
77334
77737
  const larkBotCloud = createLarkBotCloudClient({
77335
77738
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
77336
77739
  getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
@@ -77342,7 +77745,7 @@ async function startDaemon(config) {
77342
77745
  store: larkBotStore,
77343
77746
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
77344
77747
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
77345
- mediaRootFor: (chatId) => import_node_path84.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
77748
+ mediaRootFor: (chatId) => import_node_path85.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
77346
77749
  isShuttingDown: () => larkDraining,
77347
77750
  logger: {
77348
77751
  warn: (msg) => logger.warn(msg),
@@ -77599,6 +78002,9 @@ async function startDaemon(config) {
77599
78002
  fanOutBroadcast(result.broadcast);
77600
78003
  });
77601
78004
  manager.sweepEphemeralOnStartup();
78005
+ manager.recoverCloudSessions();
78006
+ const cloudRecoveryInterval = setInterval(() => manager.recoverCloudSessions(), 3e4);
78007
+ cloudRecoveryInterval.unref();
77602
78008
  await wss.start();
77603
78009
  const url = `ws://${config.host}:${config.port}`;
77604
78010
  let stateSnapshot = {
@@ -77652,8 +78058,8 @@ async function startDaemon(config) {
77652
78058
  const lines = [
77653
78059
  `Tunnel: ${r2.url}`,
77654
78060
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
77655
- `Frpc config: ${import_node_path84.default.join(config.dataDir, "frpc.toml")}`,
77656
- `Frpc log: ${import_node_path84.default.join(logDir, "frpc.log")}`
78061
+ `Frpc config: ${import_node_path85.default.join(config.dataDir, "frpc.toml")}`,
78062
+ `Frpc log: ${import_node_path85.default.join(logDir, "frpc.log")}`
77657
78063
  ];
77658
78064
  const width2 = Math.max(...lines.map((l2) => l2.length));
77659
78065
  const bar = "\u2550".repeat(width2 + 4);
@@ -77666,8 +78072,8 @@ ${bar}
77666
78072
 
77667
78073
  `);
77668
78074
  try {
77669
- const connectPath = import_node_path84.default.join(config.dataDir, "connect.txt");
77670
- import_node_fs65.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
78075
+ const connectPath = import_node_path85.default.join(config.dataDir, "connect.txt");
78076
+ import_node_fs66.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
77671
78077
  } catch {
77672
78078
  }
77673
78079
  } catch (err) {
@@ -77735,6 +78141,8 @@ ${bar}
77735
78141
  logger.info("stopping clawd");
77736
78142
  larkDraining = true;
77737
78143
  clearInterval(attachmentGcInterval);
78144
+ clearInterval(cloudRecoveryInterval);
78145
+ cloudCancelOutbox.stop();
77738
78146
  observer.stopAll();
77739
78147
  manager.stopAll();
77740
78148
  await extensionRuntime.stopAll();
@@ -77765,9 +78173,9 @@ ${bar}
77765
78173
  };
77766
78174
  }
77767
78175
  function migrateDropPersonsDir(dataDir) {
77768
- const dir = import_node_path84.default.join(dataDir, "persons");
78176
+ const dir = import_node_path85.default.join(dataDir, "persons");
77769
78177
  try {
77770
- import_node_fs65.default.rmSync(dir, { recursive: true, force: true });
78178
+ import_node_fs66.default.rmSync(dir, { recursive: true, force: true });
77771
78179
  } catch {
77772
78180
  }
77773
78181
  }