@clawos-dev/clawd 0.2.88 → 0.2.89-beta.165.fab5549

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +250 -602
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -651,8 +651,8 @@ var init_parseUtil = __esm({
651
651
  init_errors2();
652
652
  init_en();
653
653
  makeIssue = (params) => {
654
- const { data, path: path46, errorMaps, issueData } = params;
655
- const fullPath = [...path46, ...issueData.path || []];
654
+ const { data, path: path44, errorMaps, issueData } = params;
655
+ const fullPath = [...path44, ...issueData.path || []];
656
656
  const fullIssue = {
657
657
  ...issueData,
658
658
  path: fullPath
@@ -963,11 +963,11 @@ var init_types = __esm({
963
963
  init_parseUtil();
964
964
  init_util();
965
965
  ParseInputLazyPath = class {
966
- constructor(parent, value, path46, key) {
966
+ constructor(parent, value, path44, key) {
967
967
  this._cachedPath = [];
968
968
  this.parent = parent;
969
969
  this.data = value;
970
- this._path = path46;
970
+ this._path = path44;
971
971
  this._key = key;
972
972
  }
973
973
  get path() {
@@ -4351,13 +4351,13 @@ var init_zod = __esm({
4351
4351
  });
4352
4352
 
4353
4353
  // ../protocol/src/attachment-schemas.ts
4354
- var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema, AttachmentUploadResponseSchema;
4354
+ var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema;
4355
4355
  var init_attachment_schemas = __esm({
4356
4356
  "../protocol/src/attachment-schemas.ts"() {
4357
4357
  "use strict";
4358
4358
  init_zod();
4359
4359
  TOKEN_ROLES = ["owner"];
4360
- GROUP_FILE_SOURCES = ["agent", "owner", "user-upload"];
4360
+ GROUP_FILE_SOURCES = ["agent", "owner"];
4361
4361
  GroupFileEntrySchema = external_exports.object({
4362
4362
  /** daemon 派发的稳定 id(用于 RPC remove / UI key) */
4363
4363
  id: external_exports.string().min(1),
@@ -4412,16 +4412,6 @@ var init_attachment_schemas = __esm({
4412
4412
  AttachmentGroupListResponseSchema = external_exports.object({
4413
4413
  entries: external_exports.array(GroupFileEntrySchema)
4414
4414
  });
4415
- AttachmentUploadResponseSchema = external_exports.object({
4416
- /** sha256(bytes) 前 16 位,前端持有的稳定 ref */
4417
- attachmentId: external_exports.string().min(1),
4418
- /** 完整 tunnel signed URL,前端拼 marker / 直接送 Anthropic 都用它 */
4419
- url: external_exports.string().min(1),
4420
- /** 落在 session 目录下的相对路径(后续 group RPC / drawer 展示用) */
4421
- relPath: external_exports.string().min(1),
4422
- sizeBytes: external_exports.number().int().nonnegative(),
4423
- mimeType: external_exports.string().min(1)
4424
- });
4425
4415
  }
4426
4416
  });
4427
4417
 
@@ -5635,8 +5625,8 @@ var require_req = __commonJS({
5635
5625
  if (req.originalUrl) {
5636
5626
  _req.url = req.originalUrl;
5637
5627
  } else {
5638
- const path46 = req.path;
5639
- _req.url = typeof path46 === "string" ? path46 : req.url ? req.url.path || req.url : void 0;
5628
+ const path44 = req.path;
5629
+ _req.url = typeof path44 === "string" ? path44 : req.url ? req.url.path || req.url : void 0;
5640
5630
  }
5641
5631
  if (req.query) {
5642
5632
  _req.query = req.query;
@@ -5801,14 +5791,14 @@ var require_redact = __commonJS({
5801
5791
  }
5802
5792
  return obj;
5803
5793
  }
5804
- function parsePath(path46) {
5794
+ function parsePath(path44) {
5805
5795
  const parts = [];
5806
5796
  let current = "";
5807
5797
  let inBrackets = false;
5808
5798
  let inQuotes = false;
5809
5799
  let quoteChar = "";
5810
- for (let i = 0; i < path46.length; i++) {
5811
- const char = path46[i];
5800
+ for (let i = 0; i < path44.length; i++) {
5801
+ const char = path44[i];
5812
5802
  if (!inBrackets && char === ".") {
5813
5803
  if (current) {
5814
5804
  parts.push(current);
@@ -5939,10 +5929,10 @@ var require_redact = __commonJS({
5939
5929
  return current;
5940
5930
  }
5941
5931
  function redactPaths(obj, paths, censor, remove = false) {
5942
- for (const path46 of paths) {
5943
- const parts = parsePath(path46);
5932
+ for (const path44 of paths) {
5933
+ const parts = parsePath(path44);
5944
5934
  if (parts.includes("*")) {
5945
- redactWildcardPath(obj, parts, censor, path46, remove);
5935
+ redactWildcardPath(obj, parts, censor, path44, remove);
5946
5936
  } else {
5947
5937
  if (remove) {
5948
5938
  removeKey(obj, parts);
@@ -6027,8 +6017,8 @@ var require_redact = __commonJS({
6027
6017
  }
6028
6018
  } else {
6029
6019
  if (afterWildcard.includes("*")) {
6030
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6031
- const fullPath = [...pathArray.slice(0, pathLength), ...path46];
6020
+ const wrappedCensor = typeof censor === "function" ? (value, path44) => {
6021
+ const fullPath = [...pathArray.slice(0, pathLength), ...path44];
6032
6022
  return censor(value, fullPath);
6033
6023
  } : censor;
6034
6024
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6063,8 +6053,8 @@ var require_redact = __commonJS({
6063
6053
  return null;
6064
6054
  }
6065
6055
  const pathStructure = /* @__PURE__ */ new Map();
6066
- for (const path46 of pathsToClone) {
6067
- const parts = parsePath(path46);
6056
+ for (const path44 of pathsToClone) {
6057
+ const parts = parsePath(path44);
6068
6058
  let current = pathStructure;
6069
6059
  for (let i = 0; i < parts.length; i++) {
6070
6060
  const part = parts[i];
@@ -6116,24 +6106,24 @@ var require_redact = __commonJS({
6116
6106
  }
6117
6107
  return cloneSelectively(obj, pathStructure);
6118
6108
  }
6119
- function validatePath(path46) {
6120
- if (typeof path46 !== "string") {
6109
+ function validatePath(path44) {
6110
+ if (typeof path44 !== "string") {
6121
6111
  throw new Error("Paths must be (non-empty) strings");
6122
6112
  }
6123
- if (path46 === "") {
6113
+ if (path44 === "") {
6124
6114
  throw new Error("Invalid redaction path ()");
6125
6115
  }
6126
- if (path46.includes("..")) {
6127
- throw new Error(`Invalid redaction path (${path46})`);
6116
+ if (path44.includes("..")) {
6117
+ throw new Error(`Invalid redaction path (${path44})`);
6128
6118
  }
6129
- if (path46.includes(",")) {
6130
- throw new Error(`Invalid redaction path (${path46})`);
6119
+ if (path44.includes(",")) {
6120
+ throw new Error(`Invalid redaction path (${path44})`);
6131
6121
  }
6132
6122
  let bracketCount = 0;
6133
6123
  let inQuotes = false;
6134
6124
  let quoteChar = "";
6135
- for (let i = 0; i < path46.length; i++) {
6136
- const char = path46[i];
6125
+ for (let i = 0; i < path44.length; i++) {
6126
+ const char = path44[i];
6137
6127
  if ((char === '"' || char === "'") && bracketCount > 0) {
6138
6128
  if (!inQuotes) {
6139
6129
  inQuotes = true;
@@ -6147,20 +6137,20 @@ var require_redact = __commonJS({
6147
6137
  } else if (char === "]" && !inQuotes) {
6148
6138
  bracketCount--;
6149
6139
  if (bracketCount < 0) {
6150
- throw new Error(`Invalid redaction path (${path46})`);
6140
+ throw new Error(`Invalid redaction path (${path44})`);
6151
6141
  }
6152
6142
  }
6153
6143
  }
6154
6144
  if (bracketCount !== 0) {
6155
- throw new Error(`Invalid redaction path (${path46})`);
6145
+ throw new Error(`Invalid redaction path (${path44})`);
6156
6146
  }
6157
6147
  }
6158
6148
  function validatePaths(paths) {
6159
6149
  if (!Array.isArray(paths)) {
6160
6150
  throw new TypeError("paths must be an array");
6161
6151
  }
6162
- for (const path46 of paths) {
6163
- validatePath(path46);
6152
+ for (const path44 of paths) {
6153
+ validatePath(path44);
6164
6154
  }
6165
6155
  }
6166
6156
  function slowRedact(options = {}) {
@@ -6328,8 +6318,8 @@ var require_redaction = __commonJS({
6328
6318
  if (shape[k2] === null) {
6329
6319
  o[k2] = (value) => topCensor(value, [k2]);
6330
6320
  } else {
6331
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6332
- return censor(value, [k2, ...path46]);
6321
+ const wrappedCensor = typeof censor === "function" ? (value, path44) => {
6322
+ return censor(value, [k2, ...path44]);
6333
6323
  } : censor;
6334
6324
  o[k2] = Redact({
6335
6325
  paths: shape[k2],
@@ -6547,10 +6537,10 @@ var require_atomic_sleep = __commonJS({
6547
6537
  var require_sonic_boom = __commonJS({
6548
6538
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6549
6539
  "use strict";
6550
- var fs37 = require("fs");
6540
+ var fs35 = require("fs");
6551
6541
  var EventEmitter2 = require("events");
6552
6542
  var inherits = require("util").inherits;
6553
- var path46 = require("path");
6543
+ var path44 = require("path");
6554
6544
  var sleep = require_atomic_sleep();
6555
6545
  var assert = require("assert");
6556
6546
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6604,20 +6594,20 @@ var require_sonic_boom = __commonJS({
6604
6594
  const mode = sonic.mode;
6605
6595
  if (sonic.sync) {
6606
6596
  try {
6607
- if (sonic.mkdir) fs37.mkdirSync(path46.dirname(file), { recursive: true });
6608
- const fd = fs37.openSync(file, flags, mode);
6597
+ if (sonic.mkdir) fs35.mkdirSync(path44.dirname(file), { recursive: true });
6598
+ const fd = fs35.openSync(file, flags, mode);
6609
6599
  fileOpened(null, fd);
6610
6600
  } catch (err) {
6611
6601
  fileOpened(err);
6612
6602
  throw err;
6613
6603
  }
6614
6604
  } else if (sonic.mkdir) {
6615
- fs37.mkdir(path46.dirname(file), { recursive: true }, (err) => {
6605
+ fs35.mkdir(path44.dirname(file), { recursive: true }, (err) => {
6616
6606
  if (err) return fileOpened(err);
6617
- fs37.open(file, flags, mode, fileOpened);
6607
+ fs35.open(file, flags, mode, fileOpened);
6618
6608
  });
6619
6609
  } else {
6620
- fs37.open(file, flags, mode, fileOpened);
6610
+ fs35.open(file, flags, mode, fileOpened);
6621
6611
  }
6622
6612
  }
6623
6613
  function SonicBoom(opts) {
@@ -6658,8 +6648,8 @@ var require_sonic_boom = __commonJS({
6658
6648
  this.flush = flushBuffer;
6659
6649
  this.flushSync = flushBufferSync;
6660
6650
  this._actualWrite = actualWriteBuffer;
6661
- fsWriteSync = () => fs37.writeSync(this.fd, this._writingBuf);
6662
- fsWrite = () => fs37.write(this.fd, this._writingBuf, this.release);
6651
+ fsWriteSync = () => fs35.writeSync(this.fd, this._writingBuf);
6652
+ fsWrite = () => fs35.write(this.fd, this._writingBuf, this.release);
6663
6653
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6664
6654
  this._writingBuf = "";
6665
6655
  this.write = write;
@@ -6668,15 +6658,15 @@ var require_sonic_boom = __commonJS({
6668
6658
  this._actualWrite = actualWrite;
6669
6659
  fsWriteSync = () => {
6670
6660
  if (Buffer.isBuffer(this._writingBuf)) {
6671
- return fs37.writeSync(this.fd, this._writingBuf);
6661
+ return fs35.writeSync(this.fd, this._writingBuf);
6672
6662
  }
6673
- return fs37.writeSync(this.fd, this._writingBuf, "utf8");
6663
+ return fs35.writeSync(this.fd, this._writingBuf, "utf8");
6674
6664
  };
6675
6665
  fsWrite = () => {
6676
6666
  if (Buffer.isBuffer(this._writingBuf)) {
6677
- return fs37.write(this.fd, this._writingBuf, this.release);
6667
+ return fs35.write(this.fd, this._writingBuf, this.release);
6678
6668
  }
6679
- return fs37.write(this.fd, this._writingBuf, "utf8", this.release);
6669
+ return fs35.write(this.fd, this._writingBuf, "utf8", this.release);
6680
6670
  };
6681
6671
  } else {
6682
6672
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6733,7 +6723,7 @@ var require_sonic_boom = __commonJS({
6733
6723
  }
6734
6724
  }
6735
6725
  if (this._fsync) {
6736
- fs37.fsyncSync(this.fd);
6726
+ fs35.fsyncSync(this.fd);
6737
6727
  }
6738
6728
  const len = this._len;
6739
6729
  if (this._reopening) {
@@ -6847,7 +6837,7 @@ var require_sonic_boom = __commonJS({
6847
6837
  const onDrain = () => {
6848
6838
  if (!this._fsync) {
6849
6839
  try {
6850
- fs37.fsync(this.fd, (err) => {
6840
+ fs35.fsync(this.fd, (err) => {
6851
6841
  this._flushPending = false;
6852
6842
  cb(err);
6853
6843
  });
@@ -6949,7 +6939,7 @@ var require_sonic_boom = __commonJS({
6949
6939
  const fd = this.fd;
6950
6940
  this.once("ready", () => {
6951
6941
  if (fd !== this.fd) {
6952
- fs37.close(fd, (err) => {
6942
+ fs35.close(fd, (err) => {
6953
6943
  if (err) {
6954
6944
  return this.emit("error", err);
6955
6945
  }
@@ -6998,7 +6988,7 @@ var require_sonic_boom = __commonJS({
6998
6988
  buf = this._bufs[0];
6999
6989
  }
7000
6990
  try {
7001
- const n = Buffer.isBuffer(buf) ? fs37.writeSync(this.fd, buf) : fs37.writeSync(this.fd, buf, "utf8");
6991
+ const n = Buffer.isBuffer(buf) ? fs35.writeSync(this.fd, buf) : fs35.writeSync(this.fd, buf, "utf8");
7002
6992
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7003
6993
  buf = releasedBufObj.writingBuf;
7004
6994
  this._len = releasedBufObj.len;
@@ -7014,7 +7004,7 @@ var require_sonic_boom = __commonJS({
7014
7004
  }
7015
7005
  }
7016
7006
  try {
7017
- fs37.fsyncSync(this.fd);
7007
+ fs35.fsyncSync(this.fd);
7018
7008
  } catch {
7019
7009
  }
7020
7010
  }
@@ -7035,7 +7025,7 @@ var require_sonic_boom = __commonJS({
7035
7025
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7036
7026
  }
7037
7027
  try {
7038
- const n = fs37.writeSync(this.fd, buf);
7028
+ const n = fs35.writeSync(this.fd, buf);
7039
7029
  buf = buf.subarray(n);
7040
7030
  this._len = Math.max(this._len - n, 0);
7041
7031
  if (buf.length <= 0) {
@@ -7063,13 +7053,13 @@ var require_sonic_boom = __commonJS({
7063
7053
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7064
7054
  if (this.sync) {
7065
7055
  try {
7066
- const written = Buffer.isBuffer(this._writingBuf) ? fs37.writeSync(this.fd, this._writingBuf) : fs37.writeSync(this.fd, this._writingBuf, "utf8");
7056
+ const written = Buffer.isBuffer(this._writingBuf) ? fs35.writeSync(this.fd, this._writingBuf) : fs35.writeSync(this.fd, this._writingBuf, "utf8");
7067
7057
  release(null, written);
7068
7058
  } catch (err) {
7069
7059
  release(err);
7070
7060
  }
7071
7061
  } else {
7072
- fs37.write(this.fd, this._writingBuf, release);
7062
+ fs35.write(this.fd, this._writingBuf, release);
7073
7063
  }
7074
7064
  }
7075
7065
  function actualWriteBuffer() {
@@ -7078,7 +7068,7 @@ var require_sonic_boom = __commonJS({
7078
7068
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7079
7069
  if (this.sync) {
7080
7070
  try {
7081
- const written = fs37.writeSync(this.fd, this._writingBuf);
7071
+ const written = fs35.writeSync(this.fd, this._writingBuf);
7082
7072
  release(null, written);
7083
7073
  } catch (err) {
7084
7074
  release(err);
@@ -7087,7 +7077,7 @@ var require_sonic_boom = __commonJS({
7087
7077
  if (kCopyBuffer) {
7088
7078
  this._writingBuf = Buffer.from(this._writingBuf);
7089
7079
  }
7090
- fs37.write(this.fd, this._writingBuf, release);
7080
+ fs35.write(this.fd, this._writingBuf, release);
7091
7081
  }
7092
7082
  }
7093
7083
  function actualClose(sonic) {
@@ -7103,12 +7093,12 @@ var require_sonic_boom = __commonJS({
7103
7093
  sonic._lens = [];
7104
7094
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7105
7095
  try {
7106
- fs37.fsync(sonic.fd, closeWrapped);
7096
+ fs35.fsync(sonic.fd, closeWrapped);
7107
7097
  } catch {
7108
7098
  }
7109
7099
  function closeWrapped() {
7110
7100
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7111
- fs37.close(sonic.fd, done);
7101
+ fs35.close(sonic.fd, done);
7112
7102
  } else {
7113
7103
  done();
7114
7104
  }
@@ -7839,7 +7829,7 @@ var require_transport = __commonJS({
7839
7829
  stream.flushSync();
7840
7830
  }
7841
7831
  function transport(fullOptions) {
7842
- const { pipeline: pipeline3, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions;
7832
+ const { pipeline: pipeline2, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions;
7843
7833
  const options = {
7844
7834
  ...fullOptions.options
7845
7835
  };
@@ -7867,9 +7857,9 @@ var require_transport = __commonJS({
7867
7857
  };
7868
7858
  });
7869
7859
  });
7870
- } else if (pipeline3) {
7860
+ } else if (pipeline2) {
7871
7861
  target = bundlerOverrides["pino-worker"] || join11(__dirname, "worker.js");
7872
- options.pipelines = [pipeline3.map((dest) => {
7862
+ options.pipelines = [pipeline2.map((dest) => {
7873
7863
  return {
7874
7864
  ...dest,
7875
7865
  target: fixTarget(dest.target)
@@ -10243,11 +10233,11 @@ var init_lib = __esm({
10243
10233
  }
10244
10234
  }
10245
10235
  },
10246
- addToPath: function addToPath(path46, added, removed, oldPosInc, options) {
10247
- var last = path46.lastComponent;
10236
+ addToPath: function addToPath(path44, added, removed, oldPosInc, options) {
10237
+ var last = path44.lastComponent;
10248
10238
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10249
10239
  return {
10250
- oldPos: path46.oldPos + oldPosInc,
10240
+ oldPos: path44.oldPos + oldPosInc,
10251
10241
  lastComponent: {
10252
10242
  count: last.count + 1,
10253
10243
  added,
@@ -10257,7 +10247,7 @@ var init_lib = __esm({
10257
10247
  };
10258
10248
  } else {
10259
10249
  return {
10260
- oldPos: path46.oldPos + oldPosInc,
10250
+ oldPos: path44.oldPos + oldPosInc,
10261
10251
  lastComponent: {
10262
10252
  count: 1,
10263
10253
  added,
@@ -10688,10 +10678,10 @@ function attachmentToHistoryMessage(o, ts) {
10688
10678
  const memories = raw.map((m2) => {
10689
10679
  if (!m2 || typeof m2 !== "object") return null;
10690
10680
  const rec = m2;
10691
- const path46 = typeof rec.path === "string" ? rec.path : null;
10681
+ const path44 = typeof rec.path === "string" ? rec.path : null;
10692
10682
  const content = typeof rec.content === "string" ? rec.content : null;
10693
- if (!path46 || content == null) return null;
10694
- const entry = { path: path46, content };
10683
+ if (!path44 || content == null) return null;
10684
+ const entry = { path: path44, content };
10695
10685
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10696
10686
  return entry;
10697
10687
  }).filter((m2) => m2 !== null);
@@ -11517,10 +11507,10 @@ function parseAttachment(obj) {
11517
11507
  const memories = raw.map((m2) => {
11518
11508
  if (!m2 || typeof m2 !== "object") return null;
11519
11509
  const rec = m2;
11520
- const path46 = typeof rec.path === "string" ? rec.path : null;
11510
+ const path44 = typeof rec.path === "string" ? rec.path : null;
11521
11511
  const content = typeof rec.content === "string" ? rec.content : null;
11522
- if (!path46 || content == null) return null;
11523
- const out = { path: path46, content };
11512
+ if (!path44 || content == null) return null;
11513
+ const out = { path: path44, content };
11524
11514
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11525
11515
  return out;
11526
11516
  }).filter((m2) => m2 !== null);
@@ -20435,7 +20425,7 @@ var require_websocket_server = __commonJS({
20435
20425
  // src/run-case/recorder.ts
20436
20426
  function startRunCaseRecorder(opts) {
20437
20427
  const now = opts.now ?? Date.now;
20438
- const dir = import_node_path32.default.dirname(opts.recordPath);
20428
+ const dir = import_node_path30.default.dirname(opts.recordPath);
20439
20429
  let stream = null;
20440
20430
  let closing = false;
20441
20431
  let closedSettled = false;
@@ -20449,8 +20439,8 @@ function startRunCaseRecorder(opts) {
20449
20439
  });
20450
20440
  const ensureStream = () => {
20451
20441
  if (stream) return stream;
20452
- import_node_fs29.default.mkdirSync(dir, { recursive: true });
20453
- stream = import_node_fs29.default.createWriteStream(opts.recordPath, { flags: "a" });
20442
+ import_node_fs27.default.mkdirSync(dir, { recursive: true });
20443
+ stream = import_node_fs27.default.createWriteStream(opts.recordPath, { flags: "a" });
20454
20444
  stream.on("close", () => closedResolve());
20455
20445
  return stream;
20456
20446
  };
@@ -20475,12 +20465,12 @@ function startRunCaseRecorder(opts) {
20475
20465
  };
20476
20466
  return { tap, close, closed };
20477
20467
  }
20478
- var import_node_fs29, import_node_path32;
20468
+ var import_node_fs27, import_node_path30;
20479
20469
  var init_recorder = __esm({
20480
20470
  "src/run-case/recorder.ts"() {
20481
20471
  "use strict";
20482
- import_node_fs29 = __toESM(require("fs"), 1);
20483
- import_node_path32 = __toESM(require("path"), 1);
20472
+ import_node_fs27 = __toESM(require("fs"), 1);
20473
+ import_node_path30 = __toESM(require("path"), 1);
20484
20474
  }
20485
20475
  });
20486
20476
 
@@ -20523,7 +20513,7 @@ var init_wire = __esm({
20523
20513
  // src/run-case/controller.ts
20524
20514
  async function runController(opts) {
20525
20515
  const now = opts.now ?? Date.now;
20526
- const cwd = opts.cwd ?? (0, import_node_fs30.mkdtempSync)(import_node_path33.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
20516
+ const cwd = opts.cwd ?? (0, import_node_fs28.mkdtempSync)(import_node_path31.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
20527
20517
  const ownsCwd = opts.cwd === void 0;
20528
20518
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
20529
20519
  const spawnCtx = { cwd };
@@ -20684,19 +20674,19 @@ async function runController(opts) {
20684
20674
  if (sigintHandler) process.off("SIGINT", sigintHandler);
20685
20675
  if (ownsCwd) {
20686
20676
  try {
20687
- (0, import_node_fs30.rmSync)(cwd, { recursive: true, force: true });
20677
+ (0, import_node_fs28.rmSync)(cwd, { recursive: true, force: true });
20688
20678
  } catch {
20689
20679
  }
20690
20680
  }
20691
20681
  return exitCode ?? 0;
20692
20682
  }
20693
- var import_node_fs30, import_node_os15, import_node_path33;
20683
+ var import_node_fs28, import_node_os15, import_node_path31;
20694
20684
  var init_controller = __esm({
20695
20685
  "src/run-case/controller.ts"() {
20696
20686
  "use strict";
20697
- import_node_fs30 = require("fs");
20687
+ import_node_fs28 = require("fs");
20698
20688
  import_node_os15 = __toESM(require("os"), 1);
20699
- import_node_path33 = __toESM(require("path"), 1);
20689
+ import_node_path31 = __toESM(require("path"), 1);
20700
20690
  init_claude();
20701
20691
  init_stdout_splitter();
20702
20692
  init_permission_stdio();
@@ -20928,8 +20918,8 @@ Env (advanced):
20928
20918
  `;
20929
20919
 
20930
20920
  // src/index.ts
20931
- var import_node_path31 = __toESM(require("path"), 1);
20932
- var import_node_fs28 = __toESM(require("fs"), 1);
20921
+ var import_node_path29 = __toESM(require("path"), 1);
20922
+ var import_node_fs26 = __toESM(require("fs"), 1);
20933
20923
 
20934
20924
  // src/logger.ts
20935
20925
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -22664,18 +22654,6 @@ var SessionManager = class {
22664
22654
  (a, b2) => a.updatedAt > b2.updatedAt ? -1 : a.updatedAt < b2.updatedAt ? 1 : 0
22665
22655
  );
22666
22656
  }
22667
- /**
22668
- * 跨 scope 列出所有 owner 视角的 session(default + persona owner + persona guest),
22669
- * 附带派生的 SessionScope。attachment GC tick 用 —— 需要遍历所有活跃 session 的
22670
- * .attachments 目录 + 群文件清单求 liveSet。
22671
- */
22672
- listOwnedSessionScopes() {
22673
- return this.listAllOwned().map((file) => ({
22674
- scope: this.scopeForFile(file),
22675
- sessionId: file.sessionId,
22676
- cwd: file.cwd
22677
- }));
22678
- }
22679
22657
  // 写回 SessionFile,自动根据 ownerPersonaId / creatorPrincipalId 派生写入 scope.
22680
22658
  // 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由.
22681
22659
  writeOwned(file) {
@@ -22933,20 +22911,27 @@ var SessionManager = class {
22933
22911
  // 非空)持久化到本机 default store。dumb write,**不广播 push 帧**——UI 是写入唯一源,
22934
22912
  // 双写完成后通过 cache.setData 同步 sidebar 本地 state。
22935
22913
  //
22936
- // 强制走 deps.store(即 default scope),不走 scopeForFile:即使 mirror SessionFile
22937
- // 远端 ownerPersonaId(远端 persona session),本机也落 default,不创建本机 persona 目录。
22914
+ // 强制走 deps.store(即 default scope),不走 scopeForFilemirror 物理落 default 即可。
22938
22915
  // 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
22939
22916
  //
22917
+ // strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
22918
+ // 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
22919
+ // (MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
22920
+ //
22940
22921
  // 与 manager.create / manager.update 区别:
22941
22922
  // - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
22942
22923
  // - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
22943
22924
  mirrorUpsert(file) {
22944
- return this.deps.store.write(file);
22945
- }
22946
- // mirror peer sessions:删本机 mirror SessionFile。强制 default store。
22947
- // idempotent:找不到不 throw(UI 反复点删容错)。**不广播 session:deleted**。
22925
+ const { ownerPersonaId: _stripped, ...rest } = file;
22926
+ return this.deps.store.write(rest);
22927
+ }
22928
+ // mirror peer sessions:删本机 mirror SessionFile。**跟 listAllOwned 对称扫所有 scope**
22929
+ // (default + persona/owner + persona/guest)。光删 deps.store 会有 store.delete 返回
22930
+ // false 但 handler 仍 ack `peerSession:remove:ok` 的假象(文件落到 persona scope 时
22931
+ // listAllOwned 还能扫出来 → sidebar 刷新页面 mirror 复活)。deleteOwned 跟 listAllOwned
22932
+ // 一对,对账齐全。idempotent:找不到不 throw。**不广播 session:deleted**。
22948
22933
  mirrorRemove(sessionId) {
22949
- this.deps.store.delete(sessionId);
22934
+ this.deleteOwned(sessionId);
22950
22935
  }
22951
22936
  // observer 上报"jsonl 写入了一条 user 行"时调用:在 buffer 里找到与之对应的、
22952
22937
  // 还没建立映射的最早一条 synth user_text,记下 synth → real 映射。
@@ -27185,8 +27170,8 @@ function rmdirIfEmpty(p2) {
27185
27170
  }
27186
27171
 
27187
27172
  // src/transport/http-router.ts
27188
- var import_node_fs16 = __toESM(require("fs"), 1);
27189
- var import_node_path18 = __toESM(require("path"), 1);
27173
+ var import_node_fs15 = __toESM(require("fs"), 1);
27174
+ var import_node_path17 = __toESM(require("path"), 1);
27190
27175
 
27191
27176
  // src/attachment/mime.ts
27192
27177
  var import_node_path16 = __toESM(require("path"), 1);
@@ -27364,137 +27349,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
27364
27349
  return { ok: true, absPath };
27365
27350
  }
27366
27351
 
27367
- // src/attachment/upload.ts
27368
- var import_node_fs15 = __toESM(require("fs"), 1);
27369
- var import_node_path17 = __toESM(require("path"), 1);
27370
- var import_node_crypto6 = __toESM(require("crypto"), 1);
27371
- var import_promises = require("stream/promises");
27372
- var UploadError = class extends Error {
27373
- constructor(code, message) {
27374
- super(message);
27375
- this.code = code;
27376
- this.name = "UploadError";
27377
- }
27378
- code;
27379
- };
27380
- function assertValidFileName(fileName) {
27381
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path17.default.basename(fileName)) {
27382
- throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
27383
- }
27384
- }
27385
- var HASH_PREFIX_LEN = 16;
27386
- async function writeUploadedAttachment(args) {
27387
- assertValidFileName(args.fileName);
27388
- const attachmentsRoot = import_node_path17.default.join(args.sessionDir, ".attachments");
27389
- try {
27390
- import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
27391
- } catch (err) {
27392
- throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
27393
- }
27394
- const hasher = import_node_crypto6.default.createHash("sha256");
27395
- let actualSize = 0;
27396
- const tmpPath = import_node_path17.default.join(
27397
- attachmentsRoot,
27398
- `.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
27399
- );
27400
- try {
27401
- await (0, import_promises.pipeline)(
27402
- args.body,
27403
- async function* (source) {
27404
- for await (const chunk of source) {
27405
- const buf = chunk;
27406
- actualSize += buf.length;
27407
- hasher.update(buf);
27408
- yield buf;
27409
- }
27410
- },
27411
- import_node_fs15.default.createWriteStream(tmpPath, { mode: 384 })
27412
- );
27413
- } catch (err) {
27414
- try {
27415
- import_node_fs15.default.unlinkSync(tmpPath);
27416
- } catch {
27417
- }
27418
- throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
27419
- }
27420
- if (actualSize !== args.contentLength) {
27421
- try {
27422
- import_node_fs15.default.unlinkSync(tmpPath);
27423
- } catch {
27424
- }
27425
- throw new UploadError(
27426
- "SIZE_MISMATCH",
27427
- `expected ${args.contentLength} bytes, got ${actualSize}`
27428
- );
27429
- }
27430
- const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
27431
- const hashDir = import_node_path17.default.join(attachmentsRoot, attachmentId);
27432
- let finalFileName;
27433
- let hashDirExists = false;
27434
- try {
27435
- hashDirExists = import_node_fs15.default.statSync(hashDir).isDirectory();
27436
- } catch {
27437
- }
27438
- if (hashDirExists) {
27439
- const existing = import_node_fs15.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
27440
- finalFileName = existing[0] ?? args.fileName;
27441
- try {
27442
- import_node_fs15.default.unlinkSync(tmpPath);
27443
- } catch {
27444
- }
27445
- } else {
27446
- try {
27447
- import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
27448
- finalFileName = args.fileName;
27449
- import_node_fs15.default.renameSync(tmpPath, import_node_path17.default.join(hashDir, finalFileName));
27450
- } catch (err) {
27451
- try {
27452
- import_node_fs15.default.unlinkSync(tmpPath);
27453
- } catch {
27454
- }
27455
- throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
27456
- }
27457
- }
27458
- const absPath = import_node_path17.default.join(hashDir, finalFileName);
27459
- const relPath = import_node_path17.default.relative(args.sessionDir, absPath);
27460
- args.groupFileStore.upsert(args.scope, args.sessionId, {
27461
- relPath: absPath,
27462
- // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
27463
- from: "user-upload",
27464
- label: args.fileName,
27465
- size: actualSize,
27466
- mime: args.mimeType
27467
- });
27468
- return { attachmentId, absPath, relPath, sizeBytes: actualSize, mimeType: args.mimeType };
27469
- }
27470
-
27471
27352
  // src/transport/http-router.ts
27472
- var UPLOAD_MIME_ALLOW = /* @__PURE__ */ new Set([
27473
- "image/png",
27474
- "image/jpeg",
27475
- "image/gif",
27476
- "image/webp",
27477
- "application/pdf"
27478
- ]);
27479
- var UPLOAD_MIME_ALLOW_PREFIX = ["text/"];
27480
- var UPLOAD_MAX_BYTES = 25 * 1024 * 1024;
27481
- var UPLOAD_CORS_HEADERS = {
27482
- "Access-Control-Allow-Origin": "*",
27483
- "Access-Control-Allow-Methods": "POST, OPTIONS",
27484
- "Access-Control-Allow-Headers": "Authorization, Content-Type",
27485
- "Access-Control-Max-Age": "86400"
27486
- };
27487
- function isUploadMimeAllowed(mime) {
27488
- if (UPLOAD_MIME_ALLOW.has(mime)) return true;
27489
- return UPLOAD_MIME_ALLOW_PREFIX.some((p2) => mime.startsWith(p2));
27490
- }
27491
- function isValidUploadFileName(fileName) {
27492
- if (fileName.length === 0) return false;
27493
- if (fileName === "." || fileName === "..") return false;
27494
- if (fileName.startsWith(".")) return false;
27495
- if (fileName.includes("/") || fileName.includes("\\")) return false;
27496
- return fileName === import_node_path18.default.basename(fileName);
27497
- }
27498
27353
  function createHttpRouter(deps) {
27499
27354
  return async (req, res) => {
27500
27355
  const url = parseUrl(req.url);
@@ -27508,14 +27363,9 @@ function createHttpRouter(deps) {
27508
27363
  });
27509
27364
  return true;
27510
27365
  }
27511
- if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/") && url.pathname !== "/attachments/upload") {
27366
+ if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
27512
27367
  return false;
27513
27368
  }
27514
- if (url.pathname === "/attachments/upload" && req.method === "OPTIONS") {
27515
- res.writeHead(204, UPLOAD_CORS_HEADERS);
27516
- res.end();
27517
- return true;
27518
- }
27519
27369
  if (url.pathname.startsWith("/files/") && req.method === "GET") {
27520
27370
  const secret = deps.getSignSecret?.();
27521
27371
  if (!secret) {
@@ -27553,107 +27403,6 @@ function createHttpRouter(deps) {
27553
27403
  sendJson(res, 401, { code: "UNAUTHORIZED", message: "missing or invalid bearer token" });
27554
27404
  return true;
27555
27405
  }
27556
- if (url.pathname === "/attachments/upload" && req.method === "POST") {
27557
- const sendUploadJson = (status, body) => sendJson(res, status, body, UPLOAD_CORS_HEADERS);
27558
- if (ctx.role !== "owner") {
27559
- sendUploadJson(403, { code: "FORBIDDEN", message: "owner only" });
27560
- return true;
27561
- }
27562
- const up = deps.attachmentUpload;
27563
- if (!up) {
27564
- sendUploadJson(501, { code: "NOT_IMPLEMENTED", message: "attachment upload not wired" });
27565
- return true;
27566
- }
27567
- const sessionId = url.searchParams.get("sessionId");
27568
- const fileName = url.searchParams.get("fileName");
27569
- const mimeType = url.searchParams.get("mimeType");
27570
- const contentLengthRaw = req.headers["content-length"];
27571
- if (!sessionId || !fileName || !mimeType || !contentLengthRaw) {
27572
- sendUploadJson(400, {
27573
- code: "INVALID_PARAM",
27574
- message: "missing sessionId/fileName/mimeType/Content-Length"
27575
- });
27576
- return true;
27577
- }
27578
- if (!isValidUploadFileName(fileName)) {
27579
- sendUploadJson(400, {
27580
- code: "INVALID_FILENAME",
27581
- message: `fileName must be a plain basename (no path separators, no dotfiles): ${fileName}`
27582
- });
27583
- return true;
27584
- }
27585
- const contentLength = Number.parseInt(contentLengthRaw, 10);
27586
- if (!Number.isFinite(contentLength) || contentLength < 0) {
27587
- sendUploadJson(400, { code: "INVALID_PARAM", message: "malformed Content-Length" });
27588
- return true;
27589
- }
27590
- if (contentLength > UPLOAD_MAX_BYTES) {
27591
- sendUploadJson(413, {
27592
- code: "FILE_TOO_LARGE",
27593
- message: `max ${UPLOAD_MAX_BYTES} bytes`
27594
- });
27595
- return true;
27596
- }
27597
- if (!isUploadMimeAllowed(mimeType)) {
27598
- sendUploadJson(400, {
27599
- code: "UNSUPPORTED_MIME",
27600
- message: `mime ${mimeType} not allowed`
27601
- });
27602
- return true;
27603
- }
27604
- const sessionDir = up.getSessionDir(sessionId);
27605
- const scope = up.getSessionScope(sessionId);
27606
- if (!sessionDir || !scope) {
27607
- sendUploadJson(404, { code: "NOT_FOUND", message: `session ${sessionId} not found` });
27608
- return true;
27609
- }
27610
- const httpBaseUrl = up.getHttpBaseUrl();
27611
- if (!httpBaseUrl) {
27612
- sendUploadJson(503, {
27613
- code: "TUNNEL_NOT_READY",
27614
- message: "httpBaseUrl unavailable"
27615
- });
27616
- return true;
27617
- }
27618
- const secret = deps.getSignSecret?.();
27619
- if (!secret) {
27620
- sendUploadJson(501, {
27621
- code: "NOT_IMPLEMENTED",
27622
- message: "sign secret unavailable (noAuth?)"
27623
- });
27624
- return true;
27625
- }
27626
- try {
27627
- const result = await writeUploadedAttachment({
27628
- sessionDir,
27629
- sessionId,
27630
- scope,
27631
- fileName,
27632
- mimeType,
27633
- contentLength,
27634
- body: req,
27635
- groupFileStore: up.groupFileStore
27636
- });
27637
- const parts = signUrlParts(secret, result.absPath, null);
27638
- const fullUrl = buildSignedFileUrl(httpBaseUrl, parts);
27639
- sendUploadJson(200, {
27640
- attachmentId: result.attachmentId,
27641
- url: fullUrl,
27642
- relPath: result.relPath,
27643
- sizeBytes: result.sizeBytes,
27644
- mimeType: result.mimeType
27645
- });
27646
- } catch (err) {
27647
- if (err instanceof UploadError) {
27648
- const status = err.code === "SIZE_MISMATCH" ? 400 : 500;
27649
- sendUploadJson(status, { code: err.code, message: err.message });
27650
- } else {
27651
- deps.logger?.warn("attachment upload failed", { err: err.message });
27652
- sendUploadJson(500, { code: "STORAGE_ERROR", message: err.message });
27653
- }
27654
- }
27655
- return true;
27656
- }
27657
27406
  const sessionFilesMatch = url.pathname.match(/^\/session\/([^/]+)\/files$/);
27658
27407
  if (sessionFilesMatch && req.method === "GET") {
27659
27408
  const sid = sessionFilesMatch[1];
@@ -27663,7 +27412,7 @@ function createHttpRouter(deps) {
27663
27412
  return true;
27664
27413
  }
27665
27414
  let absPath;
27666
- if (import_node_path18.default.isAbsolute(pathParam)) {
27415
+ if (import_node_path17.default.isAbsolute(pathParam)) {
27667
27416
  absPath = pathParam;
27668
27417
  } else if (deps.sessionStore) {
27669
27418
  const file = deps.sessionStore.read(sid);
@@ -27671,7 +27420,7 @@ function createHttpRouter(deps) {
27671
27420
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
27672
27421
  return true;
27673
27422
  }
27674
- absPath = import_node_path18.default.join(file.cwd, pathParam);
27423
+ absPath = import_node_path17.default.join(file.cwd, pathParam);
27675
27424
  } else {
27676
27425
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
27677
27426
  return true;
@@ -27704,7 +27453,7 @@ function withCtx(ctx, body) {
27704
27453
  function streamFile(res, absPath, logger) {
27705
27454
  let stat;
27706
27455
  try {
27707
- stat = import_node_fs16.default.statSync(absPath);
27456
+ stat = import_node_fs15.default.statSync(absPath);
27708
27457
  } catch (err) {
27709
27458
  const code = err?.code;
27710
27459
  if (code === "ENOENT") {
@@ -27719,7 +27468,7 @@ function streamFile(res, absPath, logger) {
27719
27468
  return;
27720
27469
  }
27721
27470
  const mime = lookupMime(absPath);
27722
- const basename = import_node_path18.default.basename(absPath);
27471
+ const basename = import_node_path17.default.basename(absPath);
27723
27472
  res.writeHead(200, {
27724
27473
  "Content-Type": mime,
27725
27474
  "Content-Length": String(stat.size),
@@ -27727,7 +27476,7 @@ function streamFile(res, absPath, logger) {
27727
27476
  // 防止浏览器把任意 mime 当 html 渲染
27728
27477
  "X-Content-Type-Options": "nosniff"
27729
27478
  });
27730
- const stream = import_node_fs16.default.createReadStream(absPath);
27479
+ const stream = import_node_fs15.default.createReadStream(absPath);
27731
27480
  stream.on("error", (err) => {
27732
27481
  logger?.warn("streamFile read error", { absPath, err: err.message });
27733
27482
  res.destroy();
@@ -27735,78 +27484,10 @@ function streamFile(res, absPath, logger) {
27735
27484
  stream.pipe(res);
27736
27485
  }
27737
27486
 
27738
- // src/attachment/gc.ts
27739
- var import_node_fs17 = __toESM(require("fs"), 1);
27740
- var import_node_path19 = __toESM(require("path"), 1);
27741
- var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
27742
- function runAttachmentGc(args) {
27743
- const now = (args.now ?? Date.now)();
27744
- const ttlMs = args.ttlMs ?? DEFAULT_TTL_MS;
27745
- const liveAbs = /* @__PURE__ */ new Set();
27746
- for (const { scope, sessionId } of args.sessionScopes) {
27747
- for (const entry of args.groupFileStore.list(scope, sessionId)) {
27748
- if (entry.stale) continue;
27749
- if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
27750
- }
27751
- }
27752
- for (const { scope, sessionId } of args.sessionScopes) {
27753
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
27754
- args.dataDir,
27755
- "sessions",
27756
- ...scopeSubPath(scope).map(safeFileName),
27757
- safeFileName(sessionId)
27758
- );
27759
- const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
27760
- let hashDirs;
27761
- try {
27762
- hashDirs = import_node_fs17.default.readdirSync(attRoot);
27763
- } catch (err) {
27764
- if (err.code === "ENOENT") continue;
27765
- args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
27766
- continue;
27767
- }
27768
- for (const hashDir of hashDirs) {
27769
- const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
27770
- let files;
27771
- try {
27772
- files = import_node_fs17.default.readdirSync(hashDirAbs);
27773
- } catch {
27774
- continue;
27775
- }
27776
- for (const name of files) {
27777
- const file = import_node_path19.default.join(hashDirAbs, name);
27778
- let stat;
27779
- try {
27780
- stat = import_node_fs17.default.statSync(file);
27781
- } catch {
27782
- continue;
27783
- }
27784
- if (!stat.isFile()) continue;
27785
- const age = now - stat.mtimeMs;
27786
- if (age < ttlMs) continue;
27787
- if (liveAbs.has(file)) continue;
27788
- try {
27789
- import_node_fs17.default.unlinkSync(file);
27790
- } catch (err) {
27791
- args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
27792
- }
27793
- }
27794
- try {
27795
- if (import_node_fs17.default.readdirSync(hashDirAbs).length === 0) import_node_fs17.default.rmdirSync(hashDirAbs);
27796
- } catch {
27797
- }
27798
- }
27799
- try {
27800
- if (import_node_fs17.default.readdirSync(attRoot).length === 0) import_node_fs17.default.rmdirSync(attRoot);
27801
- } catch {
27802
- }
27803
- }
27804
- }
27805
-
27806
27487
  // src/attachment/group.ts
27807
- var import_node_fs18 = __toESM(require("fs"), 1);
27808
- var import_node_path20 = __toESM(require("path"), 1);
27809
- var import_node_crypto7 = __toESM(require("crypto"), 1);
27488
+ var import_node_fs16 = __toESM(require("fs"), 1);
27489
+ var import_node_path18 = __toESM(require("path"), 1);
27490
+ var import_node_crypto6 = __toESM(require("crypto"), 1);
27810
27491
  init_protocol();
27811
27492
  var GroupFileStore = class {
27812
27493
  dataDir;
@@ -27817,11 +27498,11 @@ var GroupFileStore = class {
27817
27498
  this.logger = opts.logger;
27818
27499
  }
27819
27500
  rootForScope(scope) {
27820
- return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27501
+ return import_node_path18.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27821
27502
  }
27822
27503
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
27823
27504
  filePath(scope, sessionId) {
27824
- return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27505
+ return import_node_path18.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27825
27506
  }
27826
27507
  cacheKey(scope, sessionId) {
27827
27508
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -27830,7 +27511,7 @@ var GroupFileStore = class {
27830
27511
  readFile(scope, sessionId) {
27831
27512
  const file = this.filePath(scope, sessionId);
27832
27513
  try {
27833
- const raw = import_node_fs18.default.readFileSync(file, "utf8");
27514
+ const raw = import_node_fs16.default.readFileSync(file, "utf8");
27834
27515
  const parsed = JSON.parse(raw);
27835
27516
  if (!Array.isArray(parsed)) {
27836
27517
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -27856,10 +27537,10 @@ var GroupFileStore = class {
27856
27537
  }
27857
27538
  writeFile(scope, sessionId, entries) {
27858
27539
  const file = this.filePath(scope, sessionId);
27859
- import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
27540
+ import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
27860
27541
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
27861
- import_node_fs18.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27862
- import_node_fs18.default.renameSync(tmp, file);
27542
+ import_node_fs16.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27543
+ import_node_fs16.default.renameSync(tmp, file);
27863
27544
  }
27864
27545
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
27865
27546
  list(scope, sessionId) {
@@ -27895,7 +27576,7 @@ var GroupFileStore = class {
27895
27576
  entries[idx] = next;
27896
27577
  } else {
27897
27578
  next = {
27898
- id: `gf-${import_node_crypto7.default.randomBytes(6).toString("base64url")}`,
27579
+ id: `gf-${import_node_crypto6.default.randomBytes(6).toString("base64url")}`,
27899
27580
  relPath: input.relPath,
27900
27581
  from: input.from,
27901
27582
  label: input.label,
@@ -27945,10 +27626,10 @@ var GroupFileStore = class {
27945
27626
  };
27946
27627
 
27947
27628
  // src/discovery/state-file.ts
27948
- var import_node_fs19 = __toESM(require("fs"), 1);
27949
- var import_node_path21 = __toESM(require("path"), 1);
27629
+ var import_node_fs17 = __toESM(require("fs"), 1);
27630
+ var import_node_path19 = __toESM(require("path"), 1);
27950
27631
  function defaultStateFilePath(dataDir) {
27951
- return import_node_path21.default.join(dataDir, "state.json");
27632
+ return import_node_path19.default.join(dataDir, "state.json");
27952
27633
  }
27953
27634
  function isPidAlive(pid) {
27954
27635
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -27970,7 +27651,7 @@ var StateFileManager = class {
27970
27651
  }
27971
27652
  read() {
27972
27653
  try {
27973
- const raw = import_node_fs19.default.readFileSync(this.file, "utf8");
27654
+ const raw = import_node_fs17.default.readFileSync(this.file, "utf8");
27974
27655
  const parsed = JSON.parse(raw);
27975
27656
  return parsed;
27976
27657
  } catch {
@@ -27984,34 +27665,34 @@ var StateFileManager = class {
27984
27665
  return { status: "stale", existing };
27985
27666
  }
27986
27667
  write(state) {
27987
- import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
27668
+ import_node_fs17.default.mkdirSync(import_node_path19.default.dirname(this.file), { recursive: true });
27988
27669
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
27989
- import_node_fs19.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
27990
- import_node_fs19.default.renameSync(tmp, this.file);
27670
+ import_node_fs17.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
27671
+ import_node_fs17.default.renameSync(tmp, this.file);
27991
27672
  if (process.platform !== "win32") {
27992
27673
  try {
27993
- import_node_fs19.default.chmodSync(this.file, 384);
27674
+ import_node_fs17.default.chmodSync(this.file, 384);
27994
27675
  } catch {
27995
27676
  }
27996
27677
  }
27997
27678
  }
27998
27679
  delete() {
27999
27680
  try {
28000
- import_node_fs19.default.unlinkSync(this.file);
27681
+ import_node_fs17.default.unlinkSync(this.file);
28001
27682
  } catch {
28002
27683
  }
28003
27684
  }
28004
27685
  };
28005
27686
 
28006
27687
  // src/tunnel/tunnel-manager.ts
28007
- var import_node_fs23 = __toESM(require("fs"), 1);
28008
- var import_node_path25 = __toESM(require("path"), 1);
28009
- var import_node_crypto8 = __toESM(require("crypto"), 1);
27688
+ var import_node_fs21 = __toESM(require("fs"), 1);
27689
+ var import_node_path23 = __toESM(require("path"), 1);
27690
+ var import_node_crypto7 = __toESM(require("crypto"), 1);
28010
27691
  var import_node_child_process5 = require("child_process");
28011
27692
 
28012
27693
  // src/tunnel/tunnel-store.ts
28013
- var import_node_fs20 = __toESM(require("fs"), 1);
28014
- var import_node_path22 = __toESM(require("path"), 1);
27694
+ var import_node_fs18 = __toESM(require("fs"), 1);
27695
+ var import_node_path20 = __toESM(require("path"), 1);
28015
27696
  var TunnelStore = class {
28016
27697
  constructor(filePath) {
28017
27698
  this.filePath = filePath;
@@ -28019,7 +27700,7 @@ var TunnelStore = class {
28019
27700
  filePath;
28020
27701
  async get() {
28021
27702
  try {
28022
- const raw = await import_node_fs20.default.promises.readFile(this.filePath, "utf8");
27703
+ const raw = await import_node_fs18.default.promises.readFile(this.filePath, "utf8");
28023
27704
  const obj = JSON.parse(raw);
28024
27705
  if (!isPersistedTunnel(obj)) return null;
28025
27706
  return obj;
@@ -28030,22 +27711,22 @@ var TunnelStore = class {
28030
27711
  }
28031
27712
  }
28032
27713
  async set(v2) {
28033
- const dir = import_node_path22.default.dirname(this.filePath);
28034
- await import_node_fs20.default.promises.mkdir(dir, { recursive: true });
27714
+ const dir = import_node_path20.default.dirname(this.filePath);
27715
+ await import_node_fs18.default.promises.mkdir(dir, { recursive: true });
28035
27716
  const data = JSON.stringify(v2, null, 2);
28036
27717
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
28037
- await import_node_fs20.default.promises.writeFile(tmp, data, { mode: 384 });
27718
+ await import_node_fs18.default.promises.writeFile(tmp, data, { mode: 384 });
28038
27719
  if (process.platform !== "win32") {
28039
27720
  try {
28040
- await import_node_fs20.default.promises.chmod(tmp, 384);
27721
+ await import_node_fs18.default.promises.chmod(tmp, 384);
28041
27722
  } catch {
28042
27723
  }
28043
27724
  }
28044
- await import_node_fs20.default.promises.rename(tmp, this.filePath);
27725
+ await import_node_fs18.default.promises.rename(tmp, this.filePath);
28045
27726
  }
28046
27727
  async clear() {
28047
27728
  try {
28048
- await import_node_fs20.default.promises.unlink(this.filePath);
27729
+ await import_node_fs18.default.promises.unlink(this.filePath);
28049
27730
  } catch (err) {
28050
27731
  const code = err?.code;
28051
27732
  if (code !== "ENOENT") throw err;
@@ -28140,12 +27821,12 @@ function escape(v2) {
28140
27821
  }
28141
27822
 
28142
27823
  // src/tunnel/frpc-binary.ts
28143
- var import_node_fs21 = __toESM(require("fs"), 1);
27824
+ var import_node_fs19 = __toESM(require("fs"), 1);
28144
27825
  var import_node_os10 = __toESM(require("os"), 1);
28145
- var import_node_path23 = __toESM(require("path"), 1);
27826
+ var import_node_path21 = __toESM(require("path"), 1);
28146
27827
  var import_node_child_process3 = require("child_process");
28147
27828
  var import_node_stream2 = require("stream");
28148
- var import_promises2 = require("stream/promises");
27829
+ var import_promises = require("stream/promises");
28149
27830
  var FRPC_VERSION = "0.68.0";
28150
27831
  var UnsupportedPlatformError = class extends Error {
28151
27832
  constructor(platform, arch) {
@@ -28174,20 +27855,20 @@ function frpcDownloadUrl(version2, p2) {
28174
27855
  }
28175
27856
  async function ensureFrpcBinary(opts) {
28176
27857
  if (opts.override) {
28177
- if (!import_node_fs21.default.existsSync(opts.override)) {
27858
+ if (!import_node_fs19.default.existsSync(opts.override)) {
28178
27859
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
28179
27860
  }
28180
27861
  return opts.override;
28181
27862
  }
28182
27863
  const version2 = opts.version ?? FRPC_VERSION;
28183
27864
  const platform = opts.platform ?? detectPlatform();
28184
- const binDir = import_node_path23.default.join(opts.dataDir, "bin");
28185
- import_node_fs21.default.mkdirSync(binDir, { recursive: true });
27865
+ const binDir = import_node_path21.default.join(opts.dataDir, "bin");
27866
+ import_node_fs19.default.mkdirSync(binDir, { recursive: true });
28186
27867
  cleanupStaleArtifacts(binDir);
28187
- const stableBin = import_node_path23.default.join(binDir, "frpc");
28188
- if (import_node_fs21.default.existsSync(stableBin)) return stableBin;
27868
+ const stableBin = import_node_path21.default.join(binDir, "frpc");
27869
+ if (import_node_fs19.default.existsSync(stableBin)) return stableBin;
28189
27870
  const partialBin = `${stableBin}.partial`;
28190
- const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
27871
+ const tarballPath = import_node_path21.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
28191
27872
  try {
28192
27873
  const url = frpcDownloadUrl(version2, platform);
28193
27874
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -28196,8 +27877,8 @@ async function ensureFrpcBinary(opts) {
28196
27877
  } else {
28197
27878
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
28198
27879
  }
28199
- import_node_fs21.default.chmodSync(partialBin, 493);
28200
- import_node_fs21.default.renameSync(partialBin, stableBin);
27880
+ import_node_fs19.default.chmodSync(partialBin, 493);
27881
+ import_node_fs19.default.renameSync(partialBin, stableBin);
28201
27882
  } finally {
28202
27883
  safeUnlink(tarballPath);
28203
27884
  safeUnlink(partialBin);
@@ -28207,15 +27888,15 @@ async function ensureFrpcBinary(opts) {
28207
27888
  function cleanupStaleArtifacts(binDir) {
28208
27889
  let entries;
28209
27890
  try {
28210
- entries = import_node_fs21.default.readdirSync(binDir);
27891
+ entries = import_node_fs19.default.readdirSync(binDir);
28211
27892
  } catch {
28212
27893
  return;
28213
27894
  }
28214
27895
  for (const name of entries) {
28215
27896
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
28216
- const full = import_node_path23.default.join(binDir, name);
27897
+ const full = import_node_path21.default.join(binDir, name);
28217
27898
  try {
28218
- import_node_fs21.default.rmSync(full, { recursive: true, force: true });
27899
+ import_node_fs19.default.rmSync(full, { recursive: true, force: true });
28219
27900
  } catch {
28220
27901
  }
28221
27902
  }
@@ -28223,7 +27904,7 @@ function cleanupStaleArtifacts(binDir) {
28223
27904
  }
28224
27905
  function safeUnlink(p2) {
28225
27906
  try {
28226
- import_node_fs21.default.unlinkSync(p2);
27907
+ import_node_fs19.default.unlinkSync(p2);
28227
27908
  } catch {
28228
27909
  }
28229
27910
  }
@@ -28234,13 +27915,13 @@ async function downloadToFile(url, dest, fetchImpl) {
28234
27915
  if (!res.ok || !res.body) {
28235
27916
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
28236
27917
  }
28237
- const out = import_node_fs21.default.createWriteStream(dest);
27918
+ const out = import_node_fs19.default.createWriteStream(dest);
28238
27919
  const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
28239
- await (0, import_promises2.pipeline)(nodeStream, out);
27920
+ await (0, import_promises.pipeline)(nodeStream, out);
28240
27921
  }
28241
27922
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
28242
- const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
28243
- import_node_fs21.default.mkdirSync(work, { recursive: true });
27923
+ const work = import_node_path21.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
27924
+ import_node_fs19.default.mkdirSync(work, { recursive: true });
28244
27925
  try {
28245
27926
  await new Promise((resolve6, reject) => {
28246
27927
  const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -28248,32 +27929,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
28248
27929
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
28249
27930
  });
28250
27931
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
28251
- const src = import_node_path23.default.join(work, dirName, "frpc");
28252
- if (!import_node_fs21.default.existsSync(src)) {
27932
+ const src = import_node_path21.default.join(work, dirName, "frpc");
27933
+ if (!import_node_fs19.default.existsSync(src)) {
28253
27934
  throw new Error(`frpc not found inside tarball at ${src}`);
28254
27935
  }
28255
- import_node_fs21.default.copyFileSync(src, destBin);
27936
+ import_node_fs19.default.copyFileSync(src, destBin);
28256
27937
  } finally {
28257
- import_node_fs21.default.rmSync(work, { recursive: true, force: true });
27938
+ import_node_fs19.default.rmSync(work, { recursive: true, force: true });
28258
27939
  }
28259
27940
  }
28260
27941
 
28261
27942
  // src/tunnel/frpc-process.ts
28262
- var import_node_fs22 = __toESM(require("fs"), 1);
28263
- var import_node_path24 = __toESM(require("path"), 1);
27943
+ var import_node_fs20 = __toESM(require("fs"), 1);
27944
+ var import_node_path22 = __toESM(require("path"), 1);
28264
27945
  var import_node_child_process4 = require("child_process");
28265
27946
  function frpcPidFilePath(dataDir) {
28266
- return import_node_path24.default.join(dataDir, "frpc.pid");
27947
+ return import_node_path22.default.join(dataDir, "frpc.pid");
28267
27948
  }
28268
27949
  function writeFrpcPid(dataDir, pid) {
28269
27950
  try {
28270
- import_node_fs22.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
27951
+ import_node_fs20.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
28271
27952
  } catch {
28272
27953
  }
28273
27954
  }
28274
27955
  function clearFrpcPid(dataDir) {
28275
27956
  try {
28276
- import_node_fs22.default.unlinkSync(frpcPidFilePath(dataDir));
27957
+ import_node_fs20.default.unlinkSync(frpcPidFilePath(dataDir));
28277
27958
  } catch {
28278
27959
  }
28279
27960
  }
@@ -28289,7 +27970,7 @@ function defaultIsPidAlive(pid) {
28289
27970
  }
28290
27971
  function defaultReadPidFile(file) {
28291
27972
  try {
28292
- return import_node_fs22.default.readFileSync(file, "utf8");
27973
+ return import_node_fs20.default.readFileSync(file, "utf8");
28293
27974
  } catch {
28294
27975
  return null;
28295
27976
  }
@@ -28305,7 +27986,7 @@ function defaultSleep(ms) {
28305
27986
  }
28306
27987
  async function killStaleFrpc(deps) {
28307
27988
  const pidFile = frpcPidFilePath(deps.dataDir);
28308
- const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
27989
+ const tomlPath = import_node_path22.default.join(deps.dataDir, "frpc.toml");
28309
27990
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
28310
27991
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
28311
27992
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -28329,7 +28010,7 @@ async function killStaleFrpc(deps) {
28329
28010
  }
28330
28011
  if (victims.size === 0) {
28331
28012
  try {
28332
- import_node_fs22.default.unlinkSync(pidFile);
28013
+ import_node_fs20.default.unlinkSync(pidFile);
28333
28014
  } catch {
28334
28015
  }
28335
28016
  return;
@@ -28340,7 +28021,7 @@ async function killStaleFrpc(deps) {
28340
28021
  }
28341
28022
  await sleep(deps.reapWaitMs ?? 300);
28342
28023
  try {
28343
- import_node_fs22.default.unlinkSync(pidFile);
28024
+ import_node_fs20.default.unlinkSync(pidFile);
28344
28025
  } catch {
28345
28026
  }
28346
28027
  }
@@ -28377,7 +28058,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
28377
28058
  var TunnelManager = class {
28378
28059
  constructor(deps) {
28379
28060
  this.deps = deps;
28380
- this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
28061
+ this.store = deps.store ?? new TunnelStore(import_node_path23.default.join(deps.dataDir, "tunnel.json"));
28381
28062
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
28382
28063
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
28383
28064
  }
@@ -28504,8 +28185,8 @@ var TunnelManager = class {
28504
28185
  dataDir: this.deps.dataDir,
28505
28186
  override: this.deps.frpcBinaryOverride ?? void 0
28506
28187
  });
28507
- const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
28508
- const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto8.default.randomBytes(3).toString("hex")}`;
28188
+ const tomlPath = import_node_path23.default.join(this.deps.dataDir, "frpc.toml");
28189
+ const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
28509
28190
  const toml = buildFrpcToml({
28510
28191
  serverAddr: t.frpsHost,
28511
28192
  serverPort: t.frpsPort,
@@ -28515,12 +28196,12 @@ var TunnelManager = class {
28515
28196
  localPort,
28516
28197
  logLevel: "info"
28517
28198
  });
28518
- await import_node_fs23.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28199
+ await import_node_fs21.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28519
28200
  const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
28520
28201
  stdio: ["ignore", "pipe", "pipe"]
28521
28202
  });
28522
- const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
28523
- const logStream = import_node_fs23.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
28203
+ const logFilePath = import_node_path23.default.join(this.deps.dataDir, "frpc.log");
28204
+ const logStream = import_node_fs21.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
28524
28205
  logStream.on("error", () => {
28525
28206
  });
28526
28207
  const tee = (chunk) => {
@@ -28603,22 +28284,22 @@ async function waitForFrpcReady(proc, timeoutMs) {
28603
28284
 
28604
28285
  // src/tunnel/device-key.ts
28605
28286
  var import_node_os11 = __toESM(require("os"), 1);
28606
- var import_node_crypto9 = __toESM(require("crypto"), 1);
28287
+ var import_node_crypto8 = __toESM(require("crypto"), 1);
28607
28288
  var DERIVE_SALT = "clawd-tunnel-device-v1";
28608
28289
  function deriveStableDeviceKey(opts = {}) {
28609
28290
  const hostname = opts.hostname ?? import_node_os11.default.hostname();
28610
28291
  const uid = opts.uid ?? (typeof import_node_os11.default.userInfo === "function" ? import_node_os11.default.userInfo().uid : 0);
28611
28292
  const input = `${hostname}::${uid}`;
28612
- return import_node_crypto9.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
28293
+ return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
28613
28294
  }
28614
28295
 
28615
28296
  // src/auth-store.ts
28616
- var import_node_fs24 = __toESM(require("fs"), 1);
28617
- var import_node_path26 = __toESM(require("path"), 1);
28618
- var import_node_crypto10 = __toESM(require("crypto"), 1);
28297
+ var import_node_fs22 = __toESM(require("fs"), 1);
28298
+ var import_node_path24 = __toESM(require("path"), 1);
28299
+ var import_node_crypto9 = __toESM(require("crypto"), 1);
28619
28300
  var AUTH_FILE_NAME = "auth.json";
28620
28301
  function authFilePath(dataDir) {
28621
- return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
28302
+ return import_node_path24.default.join(dataDir, AUTH_FILE_NAME);
28622
28303
  }
28623
28304
  function loadOrCreateAuthFile(opts) {
28624
28305
  const file = authFilePath(opts.dataDir);
@@ -28643,14 +28324,14 @@ function loadOrCreateAuthFile(opts) {
28643
28324
  return next;
28644
28325
  }
28645
28326
  function defaultGenerateToken2() {
28646
- return import_node_crypto10.default.randomBytes(32).toString("base64url");
28327
+ return import_node_crypto9.default.randomBytes(32).toString("base64url");
28647
28328
  }
28648
28329
  function defaultGenerateOwnerPrincipalId() {
28649
- return `owner-${import_node_crypto10.default.randomUUID()}`;
28330
+ return `owner-${import_node_crypto9.default.randomUUID()}`;
28650
28331
  }
28651
28332
  function readAuthFile(file) {
28652
28333
  try {
28653
- const raw = import_node_fs24.default.readFileSync(file, "utf8");
28334
+ const raw = import_node_fs22.default.readFileSync(file, "utf8");
28654
28335
  const parsed = JSON.parse(raw);
28655
28336
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
28656
28337
  return null;
@@ -28668,25 +28349,25 @@ function readAuthFile(file) {
28668
28349
  }
28669
28350
  }
28670
28351
  function writeAuthFile(file, content) {
28671
- import_node_fs24.default.mkdirSync(import_node_path26.default.dirname(file), { recursive: true });
28672
- import_node_fs24.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28352
+ import_node_fs22.default.mkdirSync(import_node_path24.default.dirname(file), { recursive: true });
28353
+ import_node_fs22.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28673
28354
  try {
28674
- import_node_fs24.default.chmodSync(file, 384);
28355
+ import_node_fs22.default.chmodSync(file, 384);
28675
28356
  } catch {
28676
28357
  }
28677
28358
  }
28678
28359
 
28679
28360
  // src/owner-profile.ts
28680
- var import_node_fs25 = __toESM(require("fs"), 1);
28361
+ var import_node_fs23 = __toESM(require("fs"), 1);
28681
28362
  var import_node_os12 = __toESM(require("os"), 1);
28682
- var import_node_path27 = __toESM(require("path"), 1);
28363
+ var import_node_path25 = __toESM(require("path"), 1);
28683
28364
  var PROFILE_FILENAME = "profile.json";
28684
28365
  function loadOwnerDisplayName(dataDir) {
28685
28366
  const fallback = import_node_os12.default.userInfo().username;
28686
- const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
28367
+ const profilePath = import_node_path25.default.join(dataDir, PROFILE_FILENAME);
28687
28368
  let raw;
28688
28369
  try {
28689
- raw = import_node_fs25.default.readFileSync(profilePath, "utf8");
28370
+ raw = import_node_fs23.default.readFileSync(profilePath, "utf8");
28690
28371
  } catch {
28691
28372
  return fallback;
28692
28373
  }
@@ -28715,12 +28396,12 @@ init_protocol();
28715
28396
  init_protocol();
28716
28397
 
28717
28398
  // src/session/fork.ts
28718
- var import_node_fs26 = __toESM(require("fs"), 1);
28399
+ var import_node_fs24 = __toESM(require("fs"), 1);
28719
28400
  var import_node_os13 = __toESM(require("os"), 1);
28720
- var import_node_path28 = __toESM(require("path"), 1);
28401
+ var import_node_path26 = __toESM(require("path"), 1);
28721
28402
  init_claude_history();
28722
28403
  function readJsonlEntries(file) {
28723
- const raw = import_node_fs26.default.readFileSync(file, "utf8");
28404
+ const raw = import_node_fs24.default.readFileSync(file, "utf8");
28724
28405
  const out = [];
28725
28406
  for (const line of raw.split("\n")) {
28726
28407
  const t = line.trim();
@@ -28733,10 +28414,10 @@ function readJsonlEntries(file) {
28733
28414
  return out;
28734
28415
  }
28735
28416
  function forkSession(input) {
28736
- const baseDir = input.baseDir ?? import_node_path28.default.join(import_node_os13.default.homedir(), ".claude");
28737
- const projectDir = import_node_path28.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28738
- const sourceFile = import_node_path28.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28739
- if (!import_node_fs26.default.existsSync(sourceFile)) {
28417
+ const baseDir = input.baseDir ?? import_node_path26.default.join(import_node_os13.default.homedir(), ".claude");
28418
+ const projectDir = import_node_path26.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28419
+ const sourceFile = import_node_path26.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28420
+ if (!import_node_fs24.default.existsSync(sourceFile)) {
28740
28421
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
28741
28422
  }
28742
28423
  const entries = readJsonlEntries(sourceFile);
@@ -28766,9 +28447,9 @@ function forkSession(input) {
28766
28447
  }
28767
28448
  forkedLines.push(JSON.stringify(forked));
28768
28449
  }
28769
- const forkedFilePath = import_node_path28.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28770
- import_node_fs26.default.mkdirSync(projectDir, { recursive: true });
28771
- import_node_fs26.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28450
+ const forkedFilePath = import_node_path26.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28451
+ import_node_fs24.default.mkdirSync(projectDir, { recursive: true });
28452
+ import_node_fs24.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28772
28453
  return { forkedToolSessionId, forkedFilePath };
28773
28454
  }
28774
28455
 
@@ -29124,7 +28805,7 @@ function buildPermissionHandlers(deps) {
29124
28805
  }
29125
28806
 
29126
28807
  // src/handlers/history.ts
29127
- var path38 = __toESM(require("path"), 1);
28808
+ var path36 = __toESM(require("path"), 1);
29128
28809
  init_protocol();
29129
28810
 
29130
28811
  // src/session/recent-dirs.ts
@@ -29142,7 +28823,7 @@ function listRecentDirs(store, limit = 50) {
29142
28823
  }
29143
28824
 
29144
28825
  // src/permission/persona-paths.ts
29145
- var path37 = __toESM(require("path"), 1);
28826
+ var path35 = __toESM(require("path"), 1);
29146
28827
  function getAllowedPersonaIds(grants, action) {
29147
28828
  const ids = /* @__PURE__ */ new Set();
29148
28829
  for (const g2 of grants) {
@@ -29155,26 +28836,26 @@ function getAllowedPersonaIds(grants, action) {
29155
28836
  return ids;
29156
28837
  }
29157
28838
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
29158
- const root = path37.resolve(personaRoot);
29159
- const target = path37.resolve(absPath);
29160
- const sep3 = root.endsWith(path37.sep) ? "" : path37.sep;
28839
+ const root = path35.resolve(personaRoot);
28840
+ const target = path35.resolve(absPath);
28841
+ const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
29161
28842
  if (!target.startsWith(root + sep3)) return false;
29162
- const rel = path37.relative(root, target);
28843
+ const rel = path35.relative(root, target);
29163
28844
  if (!rel || rel.startsWith("..")) return false;
29164
- const personaId = rel.split(path37.sep)[0];
28845
+ const personaId = rel.split(path35.sep)[0];
29165
28846
  if (!personaId) return false;
29166
28847
  const allowed = getAllowedPersonaIds(grants, action);
29167
28848
  if (allowed === "*") return true;
29168
28849
  return allowed.has(personaId);
29169
28850
  }
29170
28851
  function personaIdFromPath(absPath, personaRoot) {
29171
- const root = path37.resolve(personaRoot);
29172
- const target = path37.resolve(absPath);
29173
- const sep3 = root.endsWith(path37.sep) ? "" : path37.sep;
28852
+ const root = path35.resolve(personaRoot);
28853
+ const target = path35.resolve(absPath);
28854
+ const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
29174
28855
  if (!target.startsWith(root + sep3)) return null;
29175
- const rel = path37.relative(root, target);
28856
+ const rel = path35.relative(root, target);
29176
28857
  if (!rel || rel.startsWith("..")) return null;
29177
- const id = rel.split(path37.sep)[0];
28858
+ const id = rel.split(path35.sep)[0];
29178
28859
  return id || null;
29179
28860
  }
29180
28861
 
@@ -29199,7 +28880,7 @@ function buildHistoryHandlers(deps) {
29199
28880
  if (!pid) return false;
29200
28881
  return isGuestPathAllowed(
29201
28882
  ctx.grants,
29202
- path38.join(personaRoot, pid),
28883
+ path36.join(personaRoot, pid),
29203
28884
  personaRoot,
29204
28885
  "read"
29205
28886
  );
@@ -29210,7 +28891,7 @@ function buildHistoryHandlers(deps) {
29210
28891
  };
29211
28892
  const list = async (frame, _client, ctx) => {
29212
28893
  const args = HistoryListArgs.parse(frame);
29213
- assertGuestPath(ctx, path38.resolve(args.projectPath), personaRoot, "history:list");
28894
+ assertGuestPath(ctx, path36.resolve(args.projectPath), personaRoot, "history:list");
29214
28895
  const sessions = await history.listSessions(args);
29215
28896
  return { response: { type: "history:list", sessions } };
29216
28897
  };
@@ -29242,13 +28923,13 @@ function buildHistoryHandlers(deps) {
29242
28923
  };
29243
28924
  const subagents = async (frame, _client, ctx) => {
29244
28925
  const args = HistorySubagentsArgs.parse(frame);
29245
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagents");
28926
+ assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagents");
29246
28927
  const subs = await history.listSubagents(args);
29247
28928
  return { response: { type: "history:subagents", subagents: subs } };
29248
28929
  };
29249
28930
  const subagentRead = async (frame, _client, ctx) => {
29250
28931
  const args = HistorySubagentReadArgs.parse(frame);
29251
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagent-read");
28932
+ assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagent-read");
29252
28933
  const res = await history.readSubagent(args);
29253
28934
  return { response: { type: "history:subagent-read", ...res } };
29254
28935
  };
@@ -29256,7 +28937,7 @@ function buildHistoryHandlers(deps) {
29256
28937
  const dirs = listRecentDirs(store);
29257
28938
  if (ctx?.principal.kind === "guest" && personaRoot) {
29258
28939
  const filtered = dirs.filter(
29259
- (d) => isGuestPathAllowed(ctx.grants, path38.resolve(d.cwd), personaRoot, "read")
28940
+ (d) => isGuestPathAllowed(ctx.grants, path36.resolve(d.cwd), personaRoot, "read")
29260
28941
  );
29261
28942
  return { response: { type: "history:recentDirs", dirs: filtered } };
29262
28943
  }
@@ -29273,7 +28954,7 @@ function buildHistoryHandlers(deps) {
29273
28954
  }
29274
28955
 
29275
28956
  // src/handlers/workspace.ts
29276
- var path39 = __toESM(require("path"), 1);
28957
+ var path37 = __toESM(require("path"), 1);
29277
28958
  var os14 = __toESM(require("os"), 1);
29278
28959
  init_protocol();
29279
28960
  init_protocol();
@@ -29314,22 +28995,22 @@ function buildWorkspaceHandlers(deps) {
29314
28995
  const args = WorkspaceListArgs.parse(frame);
29315
28996
  const isGuest = ctx?.principal.kind === "guest";
29316
28997
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
29317
- const resolvedCwd = path39.resolve(args.cwd ?? fallbackCwd);
29318
- const target = args.path ? path39.resolve(resolvedCwd, args.path) : resolvedCwd;
28998
+ const resolvedCwd = path37.resolve(args.cwd ?? fallbackCwd);
28999
+ const target = args.path ? path37.resolve(resolvedCwd, args.path) : resolvedCwd;
29319
29000
  assertGuestPath2(ctx, target, personaRoot, "workspace:list");
29320
29001
  const res = workspace.list({ ...args, cwd: resolvedCwd });
29321
29002
  return { response: { type: "workspace:list", ...res } };
29322
29003
  };
29323
29004
  const read = async (frame, _client, ctx) => {
29324
29005
  const args = WorkspaceReadArgs.parse(frame);
29325
- const target = path39.isAbsolute(args.path) ? path39.resolve(args.path) : path39.resolve(args.cwd, args.path);
29006
+ const target = path37.isAbsolute(args.path) ? path37.resolve(args.path) : path37.resolve(args.cwd, args.path);
29326
29007
  assertGuestPath2(ctx, target, personaRoot, "workspace:read");
29327
29008
  const res = workspace.read(args);
29328
29009
  return { response: { type: "workspace:read", ...res } };
29329
29010
  };
29330
29011
  const skillsList = async (frame, _client, ctx) => {
29331
29012
  const args = SkillsListArgs.parse(frame);
29332
- const cwdAbs = path39.resolve(args.cwd);
29013
+ const cwdAbs = path37.resolve(args.cwd);
29333
29014
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
29334
29015
  const list2 = skills.list(args);
29335
29016
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29341,7 +29022,7 @@ function buildWorkspaceHandlers(deps) {
29341
29022
  };
29342
29023
  const agentsList = async (frame, _client, ctx) => {
29343
29024
  const args = AgentsListArgs.parse(frame);
29344
- const cwdAbs = path39.resolve(args.cwd);
29025
+ const cwdAbs = path37.resolve(args.cwd);
29345
29026
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
29346
29027
  const list2 = agents.list(args);
29347
29028
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29360,20 +29041,20 @@ function buildWorkspaceHandlers(deps) {
29360
29041
  }
29361
29042
 
29362
29043
  // src/handlers/git.ts
29363
- var path41 = __toESM(require("path"), 1);
29044
+ var path39 = __toESM(require("path"), 1);
29364
29045
  init_protocol();
29365
29046
  init_protocol();
29366
29047
 
29367
29048
  // src/workspace/git.ts
29368
29049
  var import_node_child_process6 = require("child_process");
29369
- var import_node_fs27 = __toESM(require("fs"), 1);
29370
- var import_node_path29 = __toESM(require("path"), 1);
29050
+ var import_node_fs25 = __toESM(require("fs"), 1);
29051
+ var import_node_path27 = __toESM(require("path"), 1);
29371
29052
  var import_node_util = require("util");
29372
29053
  var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
29373
29054
  function normalizePath(p2) {
29374
- const resolved = import_node_path29.default.resolve(p2);
29055
+ const resolved = import_node_path27.default.resolve(p2);
29375
29056
  try {
29376
- return import_node_fs27.default.realpathSync(resolved);
29057
+ return import_node_fs25.default.realpathSync(resolved);
29377
29058
  } catch {
29378
29059
  return resolved;
29379
29060
  }
@@ -29446,7 +29127,7 @@ async function listGitBranches(cwd) {
29446
29127
  // src/handlers/git.ts
29447
29128
  function assertGuestCwd(ctx, cwd, personaRoot, method) {
29448
29129
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
29449
- if (!isGuestPathAllowed(ctx.grants, path41.resolve(cwd), personaRoot, "read")) {
29130
+ if (!isGuestPathAllowed(ctx.grants, path39.resolve(cwd), personaRoot, "read")) {
29450
29131
  throw new ClawdError(
29451
29132
  ERROR_CODES.UNAUTHORIZED,
29452
29133
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -29933,7 +29614,7 @@ function buildPersonaHandlers(deps) {
29933
29614
  }
29934
29615
 
29935
29616
  // src/handlers/attachment.ts
29936
- var import_node_path30 = __toESM(require("path"), 1);
29617
+ var import_node_path28 = __toESM(require("path"), 1);
29937
29618
  init_protocol();
29938
29619
  init_protocol();
29939
29620
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -29987,12 +29668,12 @@ function buildAttachmentHandlers(deps) {
29987
29668
  `session ${args.sessionId} scope unresolved`
29988
29669
  );
29989
29670
  }
29990
- const cwdAbs = import_node_path30.default.resolve(sessionFile.cwd);
29991
- const candidateAbs = import_node_path30.default.isAbsolute(args.relPath) ? import_node_path30.default.resolve(args.relPath) : import_node_path30.default.resolve(cwdAbs, args.relPath);
29671
+ const cwdAbs = import_node_path28.default.resolve(sessionFile.cwd);
29672
+ const candidateAbs = import_node_path28.default.isAbsolute(args.relPath) ? import_node_path28.default.resolve(args.relPath) : import_node_path28.default.resolve(cwdAbs, args.relPath);
29992
29673
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
29993
29674
  const entries = deps.groupFileStore.list(scope, args.sessionId);
29994
29675
  const entry = entries.find((e) => {
29995
- const storedAbs = import_node_path30.default.isAbsolute(e.relPath) ? import_node_path30.default.resolve(e.relPath) : import_node_path30.default.resolve(cwdAbs, e.relPath);
29676
+ const storedAbs = import_node_path28.default.isAbsolute(e.relPath) ? import_node_path28.default.resolve(e.relPath) : import_node_path28.default.resolve(cwdAbs, e.relPath);
29996
29677
  return storedAbs === candidateAbs && !e.stale;
29997
29678
  });
29998
29679
  if (!entry) {
@@ -30016,7 +29697,7 @@ function buildAttachmentHandlers(deps) {
30016
29697
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
30017
29698
  const f = deps.sessionStore.read(sessionId);
30018
29699
  if (!f) return;
30019
- assertGuestAttachmentPath(ctx, import_node_path30.default.resolve(f.cwd), deps.personaRoot, method);
29700
+ assertGuestAttachmentPath(ctx, import_node_path28.default.resolve(f.cwd), deps.personaRoot, method);
30020
29701
  }
30021
29702
  const groupAdd = async (frame, _client, ctx) => {
30022
29703
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -30057,7 +29738,7 @@ function buildAttachmentHandlers(deps) {
30057
29738
  }
30058
29739
  const entries = deps.groupFileStore.list(scope, parsed.data.sessionId);
30059
29740
  const target = entries.find((e) => e.relPath === parsed.data.relPath);
30060
- if (target?.from === "owner" || target?.from === "user-upload") {
29741
+ if (target?.from === "owner") {
30061
29742
  deps.groupFileStore.remove(scope, parsed.data.sessionId, parsed.data.relPath);
30062
29743
  } else {
30063
29744
  deps.groupFileStore.markStale(scope, parsed.data.sessionId, parsed.data.relPath);
@@ -30258,7 +29939,7 @@ function computeGrantForFrame(method, frame) {
30258
29939
  async function startDaemon(config) {
30259
29940
  const logger = createLogger({
30260
29941
  level: config.logLevel,
30261
- file: import_node_path31.default.join(config.dataDir, "clawd.log")
29942
+ file: import_node_path29.default.join(config.dataDir, "clawd.log")
30262
29943
  });
30263
29944
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
30264
29945
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -30345,7 +30026,7 @@ async function startDaemon(config) {
30345
30026
  const agents = new AgentsScanner();
30346
30027
  const history = new ClaudeHistoryReader();
30347
30028
  let transport = null;
30348
- const personaStore = new PersonaStore(import_node_path31.default.join(config.dataDir, "personas"));
30029
+ const personaStore = new PersonaStore(import_node_path29.default.join(config.dataDir, "personas"));
30349
30030
  const defaultsRoot = findDefaultsRoot();
30350
30031
  if (defaultsRoot) {
30351
30032
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -30362,7 +30043,7 @@ async function startDaemon(config) {
30362
30043
  getAdapter,
30363
30044
  historyReader: history,
30364
30045
  dataDir: config.dataDir,
30365
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30046
+ personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
30366
30047
  personaStore,
30367
30048
  ownerDisplayName,
30368
30049
  ownerPrincipalId,
@@ -30386,10 +30067,10 @@ async function startDaemon(config) {
30386
30067
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
30387
30068
  attachmentGroup: {
30388
30069
  onFileEdit: (input) => {
30389
- const absPath = import_node_path31.default.isAbsolute(input.relPath) ? input.relPath : import_node_path31.default.join(input.cwd, input.relPath);
30070
+ const absPath = import_node_path29.default.isAbsolute(input.relPath) ? input.relPath : import_node_path29.default.join(input.cwd, input.relPath);
30390
30071
  let size = 0;
30391
30072
  try {
30392
- size = import_node_fs28.default.statSync(absPath).size;
30073
+ size = import_node_fs26.default.statSync(absPath).size;
30393
30074
  } catch (err) {
30394
30075
  logger.warn("attachment.onFileEdit stat failed", {
30395
30076
  sessionId: input.sessionId,
@@ -30507,10 +30188,10 @@ async function startDaemon(config) {
30507
30188
  // 'persona/<pid>/owner',default 走 'default'。
30508
30189
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
30509
30190
  // guest path guard:candidate 必须在 personaRoot 子树下
30510
- personaRoot: import_node_path31.default.join(config.dataDir, "personas")
30191
+ personaRoot: import_node_path29.default.join(config.dataDir, "personas")
30511
30192
  },
30512
30193
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
30513
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30194
+ personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
30514
30195
  // capability:list / delete handler 依赖
30515
30196
  capabilityManager,
30516
30197
  // personal-cap:get 返回的 shareBaseUrl 用此 base URL:
@@ -30546,19 +30227,7 @@ async function startDaemon(config) {
30546
30227
  sessionStore: store,
30547
30228
  // /files HMAC verify 用 auth.json 的 signSecret 字段(与 attachment.signUrl 同源)。
30548
30229
  // --auth-token CLI 模式没 signSecret → 路由返 501,sign URL 功能整体禁用。
30549
- getSignSecret: () => authFile?.signSecret ?? null,
30550
- // chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
30551
- // 在 session.cwd 下的 .attachments/ 落盘;signSecret 与 /files HMAC 同源;
30552
- // tunnel 未启时返 503 TUNNEL_NOT_READY 让前端显式提示。
30553
- attachmentUpload: {
30554
- groupFileStore,
30555
- getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
30556
- getSessionDir: (sid) => {
30557
- const f = manager.findOwnedSession(sid);
30558
- return f ? f.cwd : null;
30559
- },
30560
- getHttpBaseUrl: () => currentTunnelUrl ? getHttpBaseUrl() : null
30561
- }
30230
+ getSignSecret: () => authFile?.signSecret ?? null
30562
30231
  });
30563
30232
  wsServer = new LocalWsServer({
30564
30233
  host: config.host,
@@ -30723,8 +30392,8 @@ async function startDaemon(config) {
30723
30392
  const lines = [
30724
30393
  `Tunnel: ${r.url}`,
30725
30394
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
30726
- `Frpc config: ${import_node_path31.default.join(config.dataDir, "frpc.toml")}`,
30727
- `Frpc log: ${import_node_path31.default.join(config.dataDir, "frpc.log")}`
30395
+ `Frpc config: ${import_node_path29.default.join(config.dataDir, "frpc.toml")}`,
30396
+ `Frpc log: ${import_node_path29.default.join(config.dataDir, "frpc.log")}`
30728
30397
  ];
30729
30398
  const width = Math.max(...lines.map((l) => l.length));
30730
30399
  const bar = "\u2550".repeat(width + 4);
@@ -30737,8 +30406,8 @@ ${bar}
30737
30406
 
30738
30407
  `);
30739
30408
  try {
30740
- const connectPath = import_node_path31.default.join(config.dataDir, "connect.txt");
30741
- import_node_fs28.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30409
+ const connectPath = import_node_path29.default.join(config.dataDir, "connect.txt");
30410
+ import_node_fs26.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30742
30411
  } catch {
30743
30412
  }
30744
30413
  } catch (err) {
@@ -30763,29 +30432,8 @@ ${bar}
30763
30432
  logger.warn("tunnel unavailable, degraded to local mode", { reason: tunnelError });
30764
30433
  }
30765
30434
  }
30766
- const tickAttachmentGc = () => {
30767
- try {
30768
- runAttachmentGc({
30769
- dataDir: config.dataDir,
30770
- groupFileStore,
30771
- sessionScopes: manager.listOwnedSessionScopes().map(({ scope, sessionId }) => ({
30772
- scope,
30773
- sessionId
30774
- })),
30775
- // 注入 cwd 让 GC 直接定位 .attachments 目录(与 upload 落盘点一致)
30776
- getSessionCwd: (sid) => manager.findOwnedSession(sid)?.cwd ?? null,
30777
- logger
30778
- });
30779
- } catch (err) {
30780
- logger.warn("attachment gc tick failed", { err: err.message });
30781
- }
30782
- };
30783
- setImmediate(tickAttachmentGc);
30784
- const attachmentGcInterval = setInterval(tickAttachmentGc, 24 * 3600 * 1e3);
30785
- attachmentGcInterval.unref();
30786
30435
  const shutdown = async () => {
30787
30436
  logger.info("stopping clawd");
30788
- clearInterval(attachmentGcInterval);
30789
30437
  observer.stopAll();
30790
30438
  manager.stopAll();
30791
30439
  if (tunnelMgr) {
@@ -30803,9 +30451,9 @@ ${bar}
30803
30451
  };
30804
30452
  }
30805
30453
  function migrateDropPersonsDir(dataDir) {
30806
- const dir = import_node_path31.default.join(dataDir, "persons");
30454
+ const dir = import_node_path29.default.join(dataDir, "persons");
30807
30455
  try {
30808
- import_node_fs28.default.rmSync(dir, { recursive: true, force: true });
30456
+ import_node_fs26.default.rmSync(dir, { recursive: true, force: true });
30809
30457
  } catch {
30810
30458
  }
30811
30459
  }