@clawos-dev/clawd 0.2.284 → 0.2.286

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: path77, errorMaps, issueData } = params;
454
- const fullPath = [...path77, ...issueData.path || []];
453
+ const { data, path: path78, errorMaps, issueData } = params;
454
+ const fullPath = [...path78, ...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, path77, key) {
765
+ constructor(parent, value, path78, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path77;
769
+ this._path = path78;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -6584,6 +6584,46 @@ var init_shift_internal = __esm({
6584
6584
  }
6585
6585
  });
6586
6586
 
6587
+ // ../protocol/src/lark-bot-schemas.ts
6588
+ var LarkBotProvisionArgs, LarkBotProvisionCancelArgs, LarkBotUnbindArgs, LarkBotStatusArgs, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
6589
+ var init_lark_bot_schemas = __esm({
6590
+ "../protocol/src/lark-bot-schemas.ts"() {
6591
+ "use strict";
6592
+ init_zod();
6593
+ LarkBotProvisionArgs = external_exports.object({ personaId: external_exports.string().min(1) });
6594
+ LarkBotProvisionCancelArgs = LarkBotProvisionArgs;
6595
+ LarkBotUnbindArgs = LarkBotProvisionArgs;
6596
+ LarkBotStatusArgs = LarkBotProvisionArgs;
6597
+ LarkBotBindManualArgs = external_exports.object({
6598
+ personaId: external_exports.string().min(1),
6599
+ appId: external_exports.string().min(1),
6600
+ appSecret: external_exports.string().min(1),
6601
+ botName: external_exports.string().min(1).optional()
6602
+ });
6603
+ LarkBotGroupSchema = external_exports.object({
6604
+ chatId: external_exports.string().min(1),
6605
+ chatName: external_exports.string().optional(),
6606
+ /** epoch ms,该群 session 最近一次活跃时间 */
6607
+ lastActiveAt: external_exports.number().int().optional()
6608
+ });
6609
+ LarkBotStatusResultSchema = external_exports.object({
6610
+ state: external_exports.enum(["unbound", "provisioning", "bound", "broken"]),
6611
+ appId: external_exports.string().optional(),
6612
+ botName: external_exports.string().optional(),
6613
+ /** state='provisioning' 时的当前步骤与待用户打开的授权 URL */
6614
+ provisioning: external_exports.object({
6615
+ step: external_exports.enum(["register", "authorize"]),
6616
+ verificationUrl: external_exports.string().optional()
6617
+ }).optional(),
6618
+ brokenReason: external_exports.string().optional(),
6619
+ groups: external_exports.array(LarkBotGroupSchema)
6620
+ });
6621
+ LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
6622
+ personaId: external_exports.string().min(1)
6623
+ });
6624
+ }
6625
+ });
6626
+
6587
6627
  // ../protocol/src/persona-schemas.ts
6588
6628
  var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
6589
6629
  var init_persona_schemas = __esm({
@@ -6994,6 +7034,14 @@ var init_schemas = __esm({
6994
7034
  * mirror,留 strip 防御)。
6995
7035
  */
6996
7036
  shiftFiredFromSessionId: external_exports.string().min(1).optional(),
7037
+ /**
7038
+ * LarkBotConnector(spec 2026-08-05):该 session 是某飞书群的专属会话。
7039
+ * larkChatId = 飞书群 chat_id(oc_ 前缀),与 persona-guest scope 的 capId `lark-<chat_id>` 对应;
7040
+ * 由 daemon lark-bot-connector 模块写入,UI 只读(sidebar 按此字段隐藏,Drawer 群清单按此聚合)。
7041
+ */
7042
+ larkChatId: external_exports.string().min(1).optional(),
7043
+ /** 飞书群名快照(展示用,随事件里的群名更新,可能滞后于飞书侧改名) */
7044
+ larkChatName: external_exports.string().min(1).optional(),
6997
7045
  createdAt: external_exports.string().min(1),
6998
7046
  updatedAt: external_exports.string().min(1)
6999
7047
  });
@@ -7801,6 +7849,7 @@ var init_methods = __esm({
7801
7849
  init_inbox();
7802
7850
  init_peer_exec();
7803
7851
  init_shift_internal();
7852
+ init_lark_bot_schemas();
7804
7853
  init_persona_schemas();
7805
7854
  init_schemas();
7806
7855
  NO_ARGS = external_exports.object({});
@@ -7979,6 +8028,26 @@ var init_methods = __esm({
7979
8028
  summary: "\u67E5 shift \u7684\u6267\u884C\u5386\u53F2\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09",
7980
8029
  args: ShiftInternalHistoryArgs
7981
8030
  },
8031
+ "larkBot:provision": {
8032
+ summary: "\u53D1\u8D77 persona \u7684\u98DE\u4E66 bot \u4E00\u952E\u88C5\u914D\uFF08\u5EFA app + \u6388 scope\uFF09\uFF0C\u8FDB\u5EA6\u4E0E\u6388\u6743 URL \u8D70 larkBot:state \u5E27\uFF1Bowner-only",
8033
+ args: LarkBotProvisionArgs
8034
+ },
8035
+ "larkBot:provisionCancel": {
8036
+ summary: "\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u98DE\u4E66 bot \u88C5\u914D\u6D41\u7A0B\uFF1Bowner-only",
8037
+ args: LarkBotProvisionCancelArgs
8038
+ },
8039
+ "larkBot:bindManual": {
8040
+ summary: "\u624B\u586B app_id/app_secret \u76F4\u63A5\u7ED1\u5B9A\u98DE\u4E66 bot\uFF08\u88C5\u914D\u9003\u751F\u8231\uFF09\uFF1Bowner-only",
8041
+ args: LarkBotBindManualArgs
8042
+ },
8043
+ "larkBot:unbind": {
8044
+ summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
8045
+ args: LarkBotUnbindArgs
8046
+ },
8047
+ "larkBot:status": {
8048
+ summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/provisioning/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
8049
+ args: LarkBotStatusArgs
8050
+ },
7982
8051
  "skills:list": {
7983
8052
  summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
7984
8053
  args: SkillsListArgs
@@ -8418,6 +8487,7 @@ var init_runtime = __esm({
8418
8487
  init_log();
8419
8488
  init_visitor_schemas();
8420
8489
  init_shift_internal();
8490
+ init_lark_bot_schemas();
8421
8491
  }
8422
8492
  });
8423
8493
 
@@ -8692,8 +8762,8 @@ var require_req = __commonJS({
8692
8762
  if (req.originalUrl) {
8693
8763
  _req.url = req.originalUrl;
8694
8764
  } else {
8695
- const path77 = req.path;
8696
- _req.url = typeof path77 === "string" ? path77 : req.url ? req.url.path || req.url : void 0;
8765
+ const path78 = req.path;
8766
+ _req.url = typeof path78 === "string" ? path78 : req.url ? req.url.path || req.url : void 0;
8697
8767
  }
8698
8768
  if (req.query) {
8699
8769
  _req.query = req.query;
@@ -8858,14 +8928,14 @@ var require_redact = __commonJS({
8858
8928
  }
8859
8929
  return obj;
8860
8930
  }
8861
- function parsePath(path77) {
8931
+ function parsePath(path78) {
8862
8932
  const parts = [];
8863
8933
  let current = "";
8864
8934
  let inBrackets = false;
8865
8935
  let inQuotes = false;
8866
8936
  let quoteChar = "";
8867
- for (let i = 0; i < path77.length; i++) {
8868
- const char = path77[i];
8937
+ for (let i = 0; i < path78.length; i++) {
8938
+ const char = path78[i];
8869
8939
  if (!inBrackets && char === ".") {
8870
8940
  if (current) {
8871
8941
  parts.push(current);
@@ -8996,10 +9066,10 @@ var require_redact = __commonJS({
8996
9066
  return current;
8997
9067
  }
8998
9068
  function redactPaths(obj, paths, censor, remove = false) {
8999
- for (const path77 of paths) {
9000
- const parts = parsePath(path77);
9069
+ for (const path78 of paths) {
9070
+ const parts = parsePath(path78);
9001
9071
  if (parts.includes("*")) {
9002
- redactWildcardPath(obj, parts, censor, path77, remove);
9072
+ redactWildcardPath(obj, parts, censor, path78, remove);
9003
9073
  } else {
9004
9074
  if (remove) {
9005
9075
  removeKey(obj, parts);
@@ -9084,8 +9154,8 @@ var require_redact = __commonJS({
9084
9154
  }
9085
9155
  } else {
9086
9156
  if (afterWildcard.includes("*")) {
9087
- const wrappedCensor = typeof censor === "function" ? (value, path77) => {
9088
- const fullPath = [...pathArray.slice(0, pathLength), ...path77];
9157
+ const wrappedCensor = typeof censor === "function" ? (value, path78) => {
9158
+ const fullPath = [...pathArray.slice(0, pathLength), ...path78];
9089
9159
  return censor(value, fullPath);
9090
9160
  } : censor;
9091
9161
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -9120,8 +9190,8 @@ var require_redact = __commonJS({
9120
9190
  return null;
9121
9191
  }
9122
9192
  const pathStructure = /* @__PURE__ */ new Map();
9123
- for (const path77 of pathsToClone) {
9124
- const parts = parsePath(path77);
9193
+ for (const path78 of pathsToClone) {
9194
+ const parts = parsePath(path78);
9125
9195
  let current = pathStructure;
9126
9196
  for (let i = 0; i < parts.length; i++) {
9127
9197
  const part = parts[i];
@@ -9173,24 +9243,24 @@ var require_redact = __commonJS({
9173
9243
  }
9174
9244
  return cloneSelectively(obj, pathStructure);
9175
9245
  }
9176
- function validatePath(path77) {
9177
- if (typeof path77 !== "string") {
9246
+ function validatePath(path78) {
9247
+ if (typeof path78 !== "string") {
9178
9248
  throw new Error("Paths must be (non-empty) strings");
9179
9249
  }
9180
- if (path77 === "") {
9250
+ if (path78 === "") {
9181
9251
  throw new Error("Invalid redaction path ()");
9182
9252
  }
9183
- if (path77.includes("..")) {
9184
- throw new Error(`Invalid redaction path (${path77})`);
9253
+ if (path78.includes("..")) {
9254
+ throw new Error(`Invalid redaction path (${path78})`);
9185
9255
  }
9186
- if (path77.includes(",")) {
9187
- throw new Error(`Invalid redaction path (${path77})`);
9256
+ if (path78.includes(",")) {
9257
+ throw new Error(`Invalid redaction path (${path78})`);
9188
9258
  }
9189
9259
  let bracketCount = 0;
9190
9260
  let inQuotes = false;
9191
9261
  let quoteChar = "";
9192
- for (let i = 0; i < path77.length; i++) {
9193
- const char = path77[i];
9262
+ for (let i = 0; i < path78.length; i++) {
9263
+ const char = path78[i];
9194
9264
  if ((char === '"' || char === "'") && bracketCount > 0) {
9195
9265
  if (!inQuotes) {
9196
9266
  inQuotes = true;
@@ -9204,20 +9274,20 @@ var require_redact = __commonJS({
9204
9274
  } else if (char === "]" && !inQuotes) {
9205
9275
  bracketCount--;
9206
9276
  if (bracketCount < 0) {
9207
- throw new Error(`Invalid redaction path (${path77})`);
9277
+ throw new Error(`Invalid redaction path (${path78})`);
9208
9278
  }
9209
9279
  }
9210
9280
  }
9211
9281
  if (bracketCount !== 0) {
9212
- throw new Error(`Invalid redaction path (${path77})`);
9282
+ throw new Error(`Invalid redaction path (${path78})`);
9213
9283
  }
9214
9284
  }
9215
9285
  function validatePaths(paths) {
9216
9286
  if (!Array.isArray(paths)) {
9217
9287
  throw new TypeError("paths must be an array");
9218
9288
  }
9219
- for (const path77 of paths) {
9220
- validatePath(path77);
9289
+ for (const path78 of paths) {
9290
+ validatePath(path78);
9221
9291
  }
9222
9292
  }
9223
9293
  function slowRedact(options = {}) {
@@ -9385,8 +9455,8 @@ var require_redaction = __commonJS({
9385
9455
  if (shape[k2] === null) {
9386
9456
  o[k2] = (value) => topCensor(value, [k2]);
9387
9457
  } else {
9388
- const wrappedCensor = typeof censor === "function" ? (value, path77) => {
9389
- return censor(value, [k2, ...path77]);
9458
+ const wrappedCensor = typeof censor === "function" ? (value, path78) => {
9459
+ return censor(value, [k2, ...path78]);
9390
9460
  } : censor;
9391
9461
  o[k2] = Redact({
9392
9462
  paths: shape[k2],
@@ -9604,10 +9674,10 @@ var require_atomic_sleep = __commonJS({
9604
9674
  var require_sonic_boom = __commonJS({
9605
9675
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
9606
9676
  "use strict";
9607
- var fs67 = require("fs");
9677
+ var fs68 = require("fs");
9608
9678
  var EventEmitter3 = require("events");
9609
9679
  var inherits = require("util").inherits;
9610
- var path77 = require("path");
9680
+ var path78 = require("path");
9611
9681
  var sleep2 = require_atomic_sleep();
9612
9682
  var assert = require("assert");
9613
9683
  var BUSY_WRITE_TIMEOUT = 100;
@@ -9661,20 +9731,20 @@ var require_sonic_boom = __commonJS({
9661
9731
  const mode = sonic.mode;
9662
9732
  if (sonic.sync) {
9663
9733
  try {
9664
- if (sonic.mkdir) fs67.mkdirSync(path77.dirname(file), { recursive: true });
9665
- const fd = fs67.openSync(file, flags, mode);
9734
+ if (sonic.mkdir) fs68.mkdirSync(path78.dirname(file), { recursive: true });
9735
+ const fd = fs68.openSync(file, flags, mode);
9666
9736
  fileOpened(null, fd);
9667
9737
  } catch (err) {
9668
9738
  fileOpened(err);
9669
9739
  throw err;
9670
9740
  }
9671
9741
  } else if (sonic.mkdir) {
9672
- fs67.mkdir(path77.dirname(file), { recursive: true }, (err) => {
9742
+ fs68.mkdir(path78.dirname(file), { recursive: true }, (err) => {
9673
9743
  if (err) return fileOpened(err);
9674
- fs67.open(file, flags, mode, fileOpened);
9744
+ fs68.open(file, flags, mode, fileOpened);
9675
9745
  });
9676
9746
  } else {
9677
- fs67.open(file, flags, mode, fileOpened);
9747
+ fs68.open(file, flags, mode, fileOpened);
9678
9748
  }
9679
9749
  }
9680
9750
  function SonicBoom(opts) {
@@ -9715,8 +9785,8 @@ var require_sonic_boom = __commonJS({
9715
9785
  this.flush = flushBuffer;
9716
9786
  this.flushSync = flushBufferSync;
9717
9787
  this._actualWrite = actualWriteBuffer;
9718
- fsWriteSync = () => fs67.writeSync(this.fd, this._writingBuf);
9719
- fsWrite = () => fs67.write(this.fd, this._writingBuf, this.release);
9788
+ fsWriteSync = () => fs68.writeSync(this.fd, this._writingBuf);
9789
+ fsWrite = () => fs68.write(this.fd, this._writingBuf, this.release);
9720
9790
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
9721
9791
  this._writingBuf = "";
9722
9792
  this.write = write;
@@ -9725,15 +9795,15 @@ var require_sonic_boom = __commonJS({
9725
9795
  this._actualWrite = actualWrite;
9726
9796
  fsWriteSync = () => {
9727
9797
  if (Buffer.isBuffer(this._writingBuf)) {
9728
- return fs67.writeSync(this.fd, this._writingBuf);
9798
+ return fs68.writeSync(this.fd, this._writingBuf);
9729
9799
  }
9730
- return fs67.writeSync(this.fd, this._writingBuf, "utf8");
9800
+ return fs68.writeSync(this.fd, this._writingBuf, "utf8");
9731
9801
  };
9732
9802
  fsWrite = () => {
9733
9803
  if (Buffer.isBuffer(this._writingBuf)) {
9734
- return fs67.write(this.fd, this._writingBuf, this.release);
9804
+ return fs68.write(this.fd, this._writingBuf, this.release);
9735
9805
  }
9736
- return fs67.write(this.fd, this._writingBuf, "utf8", this.release);
9806
+ return fs68.write(this.fd, this._writingBuf, "utf8", this.release);
9737
9807
  };
9738
9808
  } else {
9739
9809
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -9790,7 +9860,7 @@ var require_sonic_boom = __commonJS({
9790
9860
  }
9791
9861
  }
9792
9862
  if (this._fsync) {
9793
- fs67.fsyncSync(this.fd);
9863
+ fs68.fsyncSync(this.fd);
9794
9864
  }
9795
9865
  const len = this._len;
9796
9866
  if (this._reopening) {
@@ -9904,7 +9974,7 @@ var require_sonic_boom = __commonJS({
9904
9974
  const onDrain = () => {
9905
9975
  if (!this._fsync) {
9906
9976
  try {
9907
- fs67.fsync(this.fd, (err) => {
9977
+ fs68.fsync(this.fd, (err) => {
9908
9978
  this._flushPending = false;
9909
9979
  cb(err);
9910
9980
  });
@@ -10006,7 +10076,7 @@ var require_sonic_boom = __commonJS({
10006
10076
  const fd = this.fd;
10007
10077
  this.once("ready", () => {
10008
10078
  if (fd !== this.fd) {
10009
- fs67.close(fd, (err) => {
10079
+ fs68.close(fd, (err) => {
10010
10080
  if (err) {
10011
10081
  return this.emit("error", err);
10012
10082
  }
@@ -10055,7 +10125,7 @@ var require_sonic_boom = __commonJS({
10055
10125
  buf = this._bufs[0];
10056
10126
  }
10057
10127
  try {
10058
- const n = Buffer.isBuffer(buf) ? fs67.writeSync(this.fd, buf) : fs67.writeSync(this.fd, buf, "utf8");
10128
+ const n = Buffer.isBuffer(buf) ? fs68.writeSync(this.fd, buf) : fs68.writeSync(this.fd, buf, "utf8");
10059
10129
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10060
10130
  buf = releasedBufObj.writingBuf;
10061
10131
  this._len = releasedBufObj.len;
@@ -10071,7 +10141,7 @@ var require_sonic_boom = __commonJS({
10071
10141
  }
10072
10142
  }
10073
10143
  try {
10074
- fs67.fsyncSync(this.fd);
10144
+ fs68.fsyncSync(this.fd);
10075
10145
  } catch {
10076
10146
  }
10077
10147
  }
@@ -10092,7 +10162,7 @@ var require_sonic_boom = __commonJS({
10092
10162
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10093
10163
  }
10094
10164
  try {
10095
- const n = fs67.writeSync(this.fd, buf);
10165
+ const n = fs68.writeSync(this.fd, buf);
10096
10166
  buf = buf.subarray(n);
10097
10167
  this._len = Math.max(this._len - n, 0);
10098
10168
  if (buf.length <= 0) {
@@ -10120,13 +10190,13 @@ var require_sonic_boom = __commonJS({
10120
10190
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
10121
10191
  if (this.sync) {
10122
10192
  try {
10123
- const written = Buffer.isBuffer(this._writingBuf) ? fs67.writeSync(this.fd, this._writingBuf) : fs67.writeSync(this.fd, this._writingBuf, "utf8");
10193
+ const written = Buffer.isBuffer(this._writingBuf) ? fs68.writeSync(this.fd, this._writingBuf) : fs68.writeSync(this.fd, this._writingBuf, "utf8");
10124
10194
  release(null, written);
10125
10195
  } catch (err) {
10126
10196
  release(err);
10127
10197
  }
10128
10198
  } else {
10129
- fs67.write(this.fd, this._writingBuf, release);
10199
+ fs68.write(this.fd, this._writingBuf, release);
10130
10200
  }
10131
10201
  }
10132
10202
  function actualWriteBuffer() {
@@ -10135,7 +10205,7 @@ var require_sonic_boom = __commonJS({
10135
10205
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
10136
10206
  if (this.sync) {
10137
10207
  try {
10138
- const written = fs67.writeSync(this.fd, this._writingBuf);
10208
+ const written = fs68.writeSync(this.fd, this._writingBuf);
10139
10209
  release(null, written);
10140
10210
  } catch (err) {
10141
10211
  release(err);
@@ -10144,7 +10214,7 @@ var require_sonic_boom = __commonJS({
10144
10214
  if (kCopyBuffer) {
10145
10215
  this._writingBuf = Buffer.from(this._writingBuf);
10146
10216
  }
10147
- fs67.write(this.fd, this._writingBuf, release);
10217
+ fs68.write(this.fd, this._writingBuf, release);
10148
10218
  }
10149
10219
  }
10150
10220
  function actualClose(sonic) {
@@ -10160,12 +10230,12 @@ var require_sonic_boom = __commonJS({
10160
10230
  sonic._lens = [];
10161
10231
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
10162
10232
  try {
10163
- fs67.fsync(sonic.fd, closeWrapped);
10233
+ fs68.fsync(sonic.fd, closeWrapped);
10164
10234
  } catch {
10165
10235
  }
10166
10236
  function closeWrapped() {
10167
10237
  if (sonic.fd !== 1 && sonic.fd !== 2) {
10168
- fs67.close(sonic.fd, done);
10238
+ fs68.close(sonic.fd, done);
10169
10239
  } else {
10170
10240
  done();
10171
10241
  }
@@ -13300,11 +13370,11 @@ var init_lib = __esm({
13300
13370
  }
13301
13371
  }
13302
13372
  },
13303
- addToPath: function addToPath(path77, added, removed, oldPosInc, options) {
13304
- var last = path77.lastComponent;
13373
+ addToPath: function addToPath(path78, added, removed, oldPosInc, options) {
13374
+ var last = path78.lastComponent;
13305
13375
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
13306
13376
  return {
13307
- oldPos: path77.oldPos + oldPosInc,
13377
+ oldPos: path78.oldPos + oldPosInc,
13308
13378
  lastComponent: {
13309
13379
  count: last.count + 1,
13310
13380
  added,
@@ -13314,7 +13384,7 @@ var init_lib = __esm({
13314
13384
  };
13315
13385
  } else {
13316
13386
  return {
13317
- oldPos: path77.oldPos + oldPosInc,
13387
+ oldPos: path78.oldPos + oldPosInc,
13318
13388
  lastComponent: {
13319
13389
  count: 1,
13320
13390
  added,
@@ -13823,10 +13893,10 @@ function attachmentToHistoryMessage(o, ts) {
13823
13893
  const memories = raw.map((m2) => {
13824
13894
  if (!m2 || typeof m2 !== "object") return null;
13825
13895
  const rec3 = m2;
13826
- const path77 = typeof rec3.path === "string" ? rec3.path : null;
13896
+ const path78 = typeof rec3.path === "string" ? rec3.path : null;
13827
13897
  const content = typeof rec3.content === "string" ? rec3.content : null;
13828
- if (!path77 || content == null) return null;
13829
- const entry = { path: path77, content };
13898
+ if (!path78 || content == null) return null;
13899
+ const entry = { path: path78, content };
13830
13900
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
13831
13901
  return entry;
13832
13902
  }).filter((m2) => m2 !== null);
@@ -14629,10 +14699,10 @@ function parseAttachment(obj) {
14629
14699
  const memories = raw.map((m2) => {
14630
14700
  if (!m2 || typeof m2 !== "object") return null;
14631
14701
  const rec3 = m2;
14632
- const path77 = typeof rec3.path === "string" ? rec3.path : null;
14702
+ const path78 = typeof rec3.path === "string" ? rec3.path : null;
14633
14703
  const content = typeof rec3.content === "string" ? rec3.content : null;
14634
- if (!path77 || content == null) return null;
14635
- const out = { path: path77, content };
14704
+ if (!path78 || content == null) return null;
14705
+ const out = { path: path78, content };
14636
14706
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
14637
14707
  return out;
14638
14708
  }).filter((m2) => m2 !== null);
@@ -35601,8 +35671,8 @@ var require_utils = __commonJS({
35601
35671
  var result = transform[inputType][outputType](input);
35602
35672
  return result;
35603
35673
  };
35604
- exports2.resolve = function(path77) {
35605
- var parts = path77.split("/");
35674
+ exports2.resolve = function(path78) {
35675
+ var parts = path78.split("/");
35606
35676
  var result = [];
35607
35677
  for (var index = 0; index < parts.length; index++) {
35608
35678
  var part = parts[index];
@@ -41455,18 +41525,18 @@ var require_object = __commonJS({
41455
41525
  var object = new ZipObject(name, zipObjectContent, o);
41456
41526
  this.files[name] = object;
41457
41527
  };
41458
- var parentFolder = function(path77) {
41459
- if (path77.slice(-1) === "/") {
41460
- path77 = path77.substring(0, path77.length - 1);
41528
+ var parentFolder = function(path78) {
41529
+ if (path78.slice(-1) === "/") {
41530
+ path78 = path78.substring(0, path78.length - 1);
41461
41531
  }
41462
- var lastSlash = path77.lastIndexOf("/");
41463
- return lastSlash > 0 ? path77.substring(0, lastSlash) : "";
41532
+ var lastSlash = path78.lastIndexOf("/");
41533
+ return lastSlash > 0 ? path78.substring(0, lastSlash) : "";
41464
41534
  };
41465
- var forceTrailingSlash = function(path77) {
41466
- if (path77.slice(-1) !== "/") {
41467
- path77 += "/";
41535
+ var forceTrailingSlash = function(path78) {
41536
+ if (path78.slice(-1) !== "/") {
41537
+ path78 += "/";
41468
41538
  }
41469
- return path77;
41539
+ return path78;
41470
41540
  };
41471
41541
  var folderAdd = function(name, createFolders) {
41472
41542
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -42468,7 +42538,7 @@ var require_lib3 = __commonJS({
42468
42538
  // src/run-case/recorder.ts
42469
42539
  function startRunCaseRecorder(opts) {
42470
42540
  const now = opts.now ?? Date.now;
42471
- const dir = import_node_path64.default.dirname(opts.recordPath);
42541
+ const dir = import_node_path65.default.dirname(opts.recordPath);
42472
42542
  let stream = null;
42473
42543
  let closing = false;
42474
42544
  let closedSettled = false;
@@ -42482,8 +42552,8 @@ function startRunCaseRecorder(opts) {
42482
42552
  });
42483
42553
  const ensureStream = () => {
42484
42554
  if (stream) return stream;
42485
- import_node_fs48.default.mkdirSync(dir, { recursive: true });
42486
- stream = import_node_fs48.default.createWriteStream(opts.recordPath, { flags: "a" });
42555
+ import_node_fs49.default.mkdirSync(dir, { recursive: true });
42556
+ stream = import_node_fs49.default.createWriteStream(opts.recordPath, { flags: "a" });
42487
42557
  stream.on("close", () => closedResolve());
42488
42558
  return stream;
42489
42559
  };
@@ -42508,12 +42578,12 @@ function startRunCaseRecorder(opts) {
42508
42578
  };
42509
42579
  return { tap, close, closed };
42510
42580
  }
42511
- var import_node_fs48, import_node_path64;
42581
+ var import_node_fs49, import_node_path65;
42512
42582
  var init_recorder = __esm({
42513
42583
  "src/run-case/recorder.ts"() {
42514
42584
  "use strict";
42515
- import_node_fs48 = __toESM(require("fs"), 1);
42516
- import_node_path64 = __toESM(require("path"), 1);
42585
+ import_node_fs49 = __toESM(require("fs"), 1);
42586
+ import_node_path65 = __toESM(require("path"), 1);
42517
42587
  }
42518
42588
  });
42519
42589
 
@@ -42556,7 +42626,7 @@ var init_wire = __esm({
42556
42626
  // src/run-case/controller.ts
42557
42627
  async function runController(opts) {
42558
42628
  const now = opts.now ?? Date.now;
42559
- const cwd = opts.cwd ?? (0, import_node_fs49.mkdtempSync)(import_node_path65.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
42629
+ const cwd = opts.cwd ?? (0, import_node_fs50.mkdtempSync)(import_node_path66.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
42560
42630
  const ownsCwd = opts.cwd === void 0;
42561
42631
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
42562
42632
  const spawnCtx = { cwd };
@@ -42717,19 +42787,19 @@ async function runController(opts) {
42717
42787
  if (sigintHandler) process.off("SIGINT", sigintHandler);
42718
42788
  if (ownsCwd) {
42719
42789
  try {
42720
- (0, import_node_fs49.rmSync)(cwd, { recursive: true, force: true });
42790
+ (0, import_node_fs50.rmSync)(cwd, { recursive: true, force: true });
42721
42791
  } catch {
42722
42792
  }
42723
42793
  }
42724
42794
  return exitCode ?? 0;
42725
42795
  }
42726
- var import_node_fs49, import_node_os23, import_node_path65;
42796
+ var import_node_fs50, import_node_os23, import_node_path66;
42727
42797
  var init_controller = __esm({
42728
42798
  "src/run-case/controller.ts"() {
42729
42799
  "use strict";
42730
- import_node_fs49 = require("fs");
42800
+ import_node_fs50 = require("fs");
42731
42801
  import_node_os23 = __toESM(require("os"), 1);
42732
- import_node_path65 = __toESM(require("path"), 1);
42802
+ import_node_path66 = __toESM(require("path"), 1);
42733
42803
  init_claude();
42734
42804
  init_stdout_splitter();
42735
42805
  init_permission_stdio();
@@ -43004,8 +43074,8 @@ Env (advanced):
43004
43074
  `;
43005
43075
 
43006
43076
  // src/index.ts
43007
- var import_node_path63 = __toESM(require("path"), 1);
43008
- var import_node_fs47 = __toESM(require("fs"), 1);
43077
+ var import_node_path64 = __toESM(require("path"), 1);
43078
+ var import_node_fs48 = __toESM(require("fs"), 1);
43009
43079
  var import_node_os22 = __toESM(require("os"), 1);
43010
43080
 
43011
43081
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
@@ -43893,6 +43963,28 @@ ${r.outcome.text}${files}`;
43893
43963
  return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
43894
43964
  }
43895
43965
 
43966
+ // src/session/lark-reply.ts
43967
+ function extractLarkReplyText(events) {
43968
+ let lastUserIdx = -1;
43969
+ for (let i = events.length - 1; i >= 0; i--) {
43970
+ if (events[i].kind === "user_text") {
43971
+ lastUserIdx = i;
43972
+ break;
43973
+ }
43974
+ }
43975
+ const tail = events.slice(lastUserIdx + 1);
43976
+ const order = [];
43977
+ const latest = /* @__PURE__ */ new Map();
43978
+ let anon = 0;
43979
+ for (const ev of tail) {
43980
+ if (ev.kind !== "text") continue;
43981
+ const key = ev.partialId ?? `__snapshot_${anon++}`;
43982
+ if (!latest.has(key)) order.push(key);
43983
+ latest.set(key, ev.text);
43984
+ }
43985
+ return order.map((k2) => latest.get(k2) ?? "").filter((t) => t.length > 0).join("\n").trim();
43986
+ }
43987
+
43896
43988
  // src/session/runner.ts
43897
43989
  var import_node_os4 = __toESM(require("os"), 1);
43898
43990
  var import_node_path7 = __toESM(require("path"), 1);
@@ -47021,6 +47113,110 @@ var SessionManager = class {
47021
47113
  });
47022
47114
  return { sessionId, ended, kill: killImpl };
47023
47115
  }
47116
+ /**
47117
+ * LarkBotConnector(spec 2026-08-05 §5.3):把一条飞书群 @ 消息作为一个 turn 驱动
47118
+ * 该群的专属 guest session,turn-idle 后从 reducer buffer 提取回复文本。
47119
+ *
47120
+ * 跟 createShiftSession 的差异:
47121
+ * - **find-or-create**:按 capId `lark-<chatId>` 找现存 session(一群一条,D3),
47122
+ * 没有才建;daemon `create` 的无 dedupe 语义不变——dedupe 是本方法私有实现
47123
+ * - guest scope + 沙箱:群成员 query 不带 owner 权限;10min guest idle-kill + resume
47124
+ * - turn-idle 后**不 kill**(session 常驻,记忆即价值);延迟 settleDelayMs 等尾随
47125
+ * text 落盘(schemas.ts turn_end 注释:CC 写 turn_end 早于尾段正文)再读 buffer
47126
+ * - 回复提取:extractLarkReplyText(最后一条 user_text 之后的 text 事件拼接)
47127
+ */
47128
+ runLarkChatTurn(args) {
47129
+ if (!this.deps.personaRoot) {
47130
+ throw new Error("runLarkChatTurn: personaRoot missing in ManagerDeps");
47131
+ }
47132
+ const capId = `lark-${args.chatId}`;
47133
+ const scope = {
47134
+ kind: "persona",
47135
+ personaId: args.personaId,
47136
+ mode: "guest",
47137
+ capId
47138
+ };
47139
+ const store = this.storeFor(scope);
47140
+ let file = store.list().find((f) => f.larkChatId === args.chatId);
47141
+ if (!file) {
47142
+ const now = (/* @__PURE__ */ new Date()).toISOString();
47143
+ file = {
47144
+ sessionId: newSessionId(),
47145
+ cwd: import_node_path9.default.join(this.deps.personaRoot, safeFileName(args.personaId)),
47146
+ tool: this.deps.getPersonaTool?.(args.personaId) ?? "claude",
47147
+ ownerPersonaId: args.personaId,
47148
+ // guest 三件套:creatorPrincipalId=capId(scopeForFile 回落防线)、
47149
+ // creatorDisplayName(reducer guest 分支硬性要求,缺则 spawn 抛)
47150
+ creatorPrincipalId: capId,
47151
+ creatorDisplayName: `\u98DE\u4E66\u7FA4\xB7${args.chatName ?? args.chatId}`,
47152
+ larkChatId: args.chatId,
47153
+ ...args.chatName ? { larkChatName: args.chatName } : {},
47154
+ createdAt: now,
47155
+ updatedAt: now
47156
+ };
47157
+ store.write(file);
47158
+ this.deps.logger?.info("larkBot.runLarkChatTurn.session-created", {
47159
+ sessionId: file.sessionId,
47160
+ personaId: args.personaId,
47161
+ chatId: args.chatId
47162
+ });
47163
+ } else if (args.chatName && file.larkChatName !== args.chatName) {
47164
+ file = { ...file, larkChatName: args.chatName, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
47165
+ store.write(file);
47166
+ }
47167
+ const sessionId = file.sessionId;
47168
+ let resolveEnded = () => {
47169
+ };
47170
+ const ended = new Promise((r) => {
47171
+ resolveEnded = r;
47172
+ });
47173
+ let unsubscribe = () => {
47174
+ };
47175
+ let settled = false;
47176
+ const settle = (info) => {
47177
+ if (settled) return;
47178
+ settled = true;
47179
+ unsubscribe();
47180
+ resolveEnded(info);
47181
+ };
47182
+ const killImpl = () => {
47183
+ const r = this.runners.get(sessionId);
47184
+ if (!r) return;
47185
+ r.input({ kind: "command", command: { kind: "stop" } });
47186
+ };
47187
+ const settleDelayMs = args.settleDelayMs ?? 500;
47188
+ unsubscribe = this.subscribe(
47189
+ sessionId,
47190
+ scope,
47191
+ makeEndFrameHandler(sessionId, (info) => {
47192
+ if (info.kind === "idle") {
47193
+ setTimeout(() => {
47194
+ try {
47195
+ const events = this.readHistoryEventsForScope(sessionId, scope);
47196
+ const replyText = extractLarkReplyText(events);
47197
+ settle(replyText ? { ok: true, replyText } : { error: "empty reply" });
47198
+ } catch (err) {
47199
+ settle({ error: err.message });
47200
+ }
47201
+ }, settleDelayMs);
47202
+ } else if (info.kind === "stopped") {
47203
+ settle({ error: "session stopped before reply" });
47204
+ } else {
47205
+ settle({ error: info.message || "session error" });
47206
+ }
47207
+ })
47208
+ );
47209
+ const runner = this.ensureRunnerForScope(file, scope);
47210
+ runner.input({
47211
+ kind: "command",
47212
+ command: {
47213
+ kind: "send",
47214
+ text: args.text,
47215
+ senderPrincipal: makeGuestSender(capId, args.senderName)
47216
+ }
47217
+ });
47218
+ return { sessionId, ended, kill: killImpl };
47219
+ }
47024
47220
  /**
47025
47221
  * 老板插话:把 'inject-owner-text' input 喂给对应 runner,
47026
47222
  * runner 不存在时按 scope 懒创建。
@@ -49024,8 +49220,8 @@ function turnStartInput(text) {
49024
49220
  const items = [];
49025
49221
  let leftover = text;
49026
49222
  for (const m2 of text.matchAll(SKILL_RE)) {
49027
- const [marker, name, path77] = m2;
49028
- items.push({ type: "skill", name, path: path77 });
49223
+ const [marker, name, path78] = m2;
49224
+ items.push({ type: "skill", name, path: path78 });
49029
49225
  leftover = leftover.replace(marker, "");
49030
49226
  }
49031
49227
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -51526,6 +51722,610 @@ function buildShiftInternalHandlers(deps) {
51526
51722
  };
51527
51723
  }
51528
51724
 
51725
+ // src/lark-bot-connector/provisioner.ts
51726
+ var LARK_BOT_V1_SCOPES = [
51727
+ "offline_access",
51728
+ "im:chat:readonly",
51729
+ "im:resource",
51730
+ "contact:user.base:readonly"
51731
+ ];
51732
+ var REGISTRATION_URL = "https://accounts.feishu.cn/oauth/v1/app/registration";
51733
+ var DEVICE_AUTHORIZE_URL = "https://accounts.feishu.cn/oauth/v1/device/authorize";
51734
+ var DEVICE_TOKEN_URL = "https://open.feishu.cn/open-apis/authen/v2/oauth/token";
51735
+ var DEFAULT_POLL_INTERVAL_MS = 6e3;
51736
+ var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
51737
+ var SLOW_DOWN_STEP_MS = 5e3;
51738
+ var FlowCtx = class {
51739
+ fetchImpl;
51740
+ sleep;
51741
+ now;
51742
+ timeoutMs;
51743
+ intervalMs;
51744
+ cancelled = false;
51745
+ constructor(opts) {
51746
+ const f = opts.fetchImpl ?? globalThis.fetch;
51747
+ if (!f) throw new Error("fetch is not available (Node >= 18 required)");
51748
+ this.fetchImpl = f;
51749
+ this.sleep = opts.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
51750
+ this.now = opts.nowImpl ?? Date.now;
51751
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
51752
+ this.intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
51753
+ }
51754
+ /**
51755
+ * RFC 8628 轮询循环:pollOnce 返回 null 表示 pending 继续;'slow_down' 加间隔;
51756
+ * 非 null 结果即完成。超时 / cancel reject。
51757
+ */
51758
+ async poll(pollOnce) {
51759
+ const start = this.now();
51760
+ for (; ; ) {
51761
+ if (this.cancelled) throw new Error("flow cancelled");
51762
+ if (this.now() - start >= this.timeoutMs) throw new Error("flow timeout");
51763
+ const r = await pollOnce();
51764
+ if (r === "slow_down") {
51765
+ this.intervalMs += SLOW_DOWN_STEP_MS;
51766
+ } else if (r !== "pending") {
51767
+ return r;
51768
+ }
51769
+ await this.sleep(this.intervalMs);
51770
+ }
51771
+ }
51772
+ };
51773
+ var POST_TIMEOUT_MS = 15e3;
51774
+ async function postJson(ctx, url, body) {
51775
+ const ac = new AbortController();
51776
+ const timer = setTimeout(() => ac.abort(), POST_TIMEOUT_MS);
51777
+ let res;
51778
+ try {
51779
+ res = await ctx.fetchImpl(url, {
51780
+ method: "POST",
51781
+ headers: { "content-type": "application/json" },
51782
+ body: JSON.stringify(body),
51783
+ signal: ac.signal
51784
+ });
51785
+ } finally {
51786
+ clearTimeout(timer);
51787
+ }
51788
+ let parsed = {};
51789
+ try {
51790
+ parsed = await res.json();
51791
+ } catch {
51792
+ parsed = {};
51793
+ }
51794
+ return { status: res.status, json: parsed };
51795
+ }
51796
+ var TERMINAL_OAUTH_ERRORS = /* @__PURE__ */ new Set(["access_denied", "expired_token", "invalid_grant"]);
51797
+ function pollSignal(status, json, what) {
51798
+ if (status >= 200 && status < 300) return "done";
51799
+ const err = String(json.error ?? "");
51800
+ if (TERMINAL_OAUTH_ERRORS.has(err)) {
51801
+ throw new Error(`${what} rejected: ${err}`);
51802
+ }
51803
+ if (err === "authorization_pending" || status === 400) {
51804
+ if (err === "slow_down") return "slow_down";
51805
+ if (err === "authorization_pending") return "pending";
51806
+ return "pending";
51807
+ }
51808
+ if (status === 429) return "slow_down";
51809
+ throw new Error(`${what} failed: HTTP ${status} ${JSON.stringify(json).slice(0, 200)}`);
51810
+ }
51811
+ async function startAppRegistration(opts = {}) {
51812
+ const ctx = new FlowCtx(opts);
51813
+ const init = await postJson(ctx, REGISTRATION_URL, { action: "start", brand: "feishu" });
51814
+ const verificationUrl = String(init.json.verification_url ?? init.json.verification_uri ?? "");
51815
+ const flowId = String(init.json.flow_id ?? "");
51816
+ if (init.status < 200 || init.status >= 300 || !verificationUrl || !flowId) {
51817
+ throw new Error(
51818
+ `app registration start failed: HTTP ${init.status} ${JSON.stringify(init.json).slice(0, 200)}`
51819
+ );
51820
+ }
51821
+ return {
51822
+ verificationUrl,
51823
+ cancel: () => {
51824
+ ctx.cancelled = true;
51825
+ },
51826
+ complete: () => ctx.poll(async () => {
51827
+ const r = await postJson(ctx, REGISTRATION_URL, {
51828
+ action: "poll",
51829
+ brand: "feishu",
51830
+ flow_id: flowId
51831
+ });
51832
+ const sig = pollSignal(r.status, r.json, "app registration");
51833
+ if (sig !== "done") return sig;
51834
+ const appId = String(r.json.client_id ?? "");
51835
+ const appSecret = String(r.json.client_secret ?? "");
51836
+ if (!appId || !appSecret) {
51837
+ throw new Error("app registration succeeded but missing client_id or client_secret");
51838
+ }
51839
+ return { appId, appSecret };
51840
+ })
51841
+ };
51842
+ }
51843
+ async function startScopeAuthorization(args) {
51844
+ const ctx = new FlowCtx(args);
51845
+ const init = await postJson(ctx, DEVICE_AUTHORIZE_URL, {
51846
+ client_id: args.appId,
51847
+ scope: args.scopes.join(" ")
51848
+ });
51849
+ const verificationUrl = String(init.json.verification_url ?? init.json.verification_uri ?? "");
51850
+ const deviceCode = String(init.json.device_code ?? "");
51851
+ if (init.status < 200 || init.status >= 300 || !verificationUrl || !deviceCode) {
51852
+ throw new Error(
51853
+ `scope authorization start failed: HTTP ${init.status} ${JSON.stringify(init.json).slice(0, 200)}`
51854
+ );
51855
+ }
51856
+ return {
51857
+ verificationUrl,
51858
+ cancel: () => {
51859
+ ctx.cancelled = true;
51860
+ },
51861
+ complete: () => ctx.poll(async () => {
51862
+ const r = await postJson(ctx, DEVICE_TOKEN_URL, {
51863
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
51864
+ client_id: args.appId,
51865
+ device_code: deviceCode
51866
+ });
51867
+ const sig = pollSignal(r.status, r.json, "scope authorization");
51868
+ if (sig !== "done") return sig;
51869
+ const grantedSet = new Set(
51870
+ String(r.json.scope ?? "").split(/\s+/).filter(Boolean)
51871
+ );
51872
+ const granted = args.scopes.filter((s) => grantedSet.has(s));
51873
+ const denied = args.scopes.filter((s) => !grantedSet.has(s));
51874
+ if (granted.length === 0) {
51875
+ throw new Error(`scope authorization: no scopes granted (requested: ${args.scopes.join(" ")})`);
51876
+ }
51877
+ return { granted: [...granted], denied: [...denied] };
51878
+ })
51879
+ };
51880
+ }
51881
+
51882
+ // src/handlers/lark-bot.ts
51883
+ init_protocol();
51884
+ function statusFrame(personaId2, status) {
51885
+ return { type: "larkBot:state", personaId: personaId2, ...status };
51886
+ }
51887
+ function buildLarkBotHandlers(deps) {
51888
+ const now = deps.now ?? Date.now;
51889
+ const inFlight = /* @__PURE__ */ new Map();
51890
+ const groupsOf = (personaId2) => {
51891
+ const removed = new Set(deps.store.read(personaId2)?.removedChatIds ?? []);
51892
+ return deps.listLarkSessions(personaId2).filter((g2) => !removed.has(g2.chatId));
51893
+ };
51894
+ const emit = (personaId2, status2) => {
51895
+ deps.broadcast(statusFrame(personaId2, status2));
51896
+ };
51897
+ const runProvision = async (personaId2, flight) => {
51898
+ const finish = () => {
51899
+ if (inFlight.get(personaId2) === flight) inFlight.delete(personaId2);
51900
+ };
51901
+ const tunnelUrl = deps.getTunnelUrl();
51902
+ const ownerId = deps.getOwnerId();
51903
+ if (!tunnelUrl || !ownerId) {
51904
+ finish();
51905
+ emit(personaId2, { state: "unbound", brokenReason: "tunnel or owner identity unavailable", groups: [] });
51906
+ return;
51907
+ }
51908
+ try {
51909
+ const reg = await deps.provisioner.startAppRegistration();
51910
+ if (flight.cancelled) return finish();
51911
+ flight.cancelFn = reg.cancel;
51912
+ emit(personaId2, {
51913
+ state: "provisioning",
51914
+ provisioning: { step: "register", verificationUrl: reg.verificationUrl },
51915
+ groups: []
51916
+ });
51917
+ const { appId, appSecret } = await reg.complete();
51918
+ if (flight.cancelled) return finish();
51919
+ const auth = await deps.provisioner.startScopeAuthorization({
51920
+ appId,
51921
+ scopes: LARK_BOT_V1_SCOPES
51922
+ });
51923
+ if (flight.cancelled) return finish();
51924
+ flight.cancelFn = auth.cancel;
51925
+ emit(personaId2, {
51926
+ state: "provisioning",
51927
+ provisioning: { step: "authorize", verificationUrl: auth.verificationUrl },
51928
+ groups: []
51929
+ });
51930
+ const { denied } = await auth.complete();
51931
+ if (flight.cancelled) return finish();
51932
+ if (denied.length > 0) {
51933
+ deps.logger?.warn(`larkBot provision ${personaId2}: scopes denied (accepted): ${denied.join(" ")}`);
51934
+ }
51935
+ const botName = deps.getPersonaName(personaId2) ?? personaId2;
51936
+ await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName, tunnelUrl, ownerId });
51937
+ deps.store.write(personaId2, { appId, botName, boundAt: now() });
51938
+ finish();
51939
+ emit(personaId2, { state: "bound", appId, botName, groups: groupsOf(personaId2) });
51940
+ } catch (err) {
51941
+ finish();
51942
+ if (flight.cancelled) return;
51943
+ emit(personaId2, {
51944
+ state: "unbound",
51945
+ brokenReason: err.message,
51946
+ groups: []
51947
+ });
51948
+ }
51949
+ };
51950
+ const provision = async (frame) => {
51951
+ const { personaId: personaId2 } = parseArgs2(LarkBotProvisionArgs, frame, "larkBot:provision");
51952
+ if (deps.store.read(personaId2)) throw new Error(`larkBot already bound: ${personaId2}`);
51953
+ if (inFlight.has(personaId2)) throw new Error(`larkBot provision already in progress: ${personaId2}`);
51954
+ if (!deps.getTunnelUrl()) throw new Error("larkBot provision requires tunnel to be up");
51955
+ if (!deps.getOwnerId()) throw new Error("larkBot provision requires feishu login (owner identity)");
51956
+ const flight = { cancelled: false, cancelFn: () => {
51957
+ } };
51958
+ inFlight.set(personaId2, flight);
51959
+ void runProvision(personaId2, flight);
51960
+ return { response: { type: "larkBot:provision:ok" } };
51961
+ };
51962
+ const provisionCancel = async (frame) => {
51963
+ const { personaId: personaId2 } = parseArgs2(LarkBotProvisionCancelArgs, frame, "larkBot:provisionCancel");
51964
+ const flight = inFlight.get(personaId2);
51965
+ if (flight) {
51966
+ flight.cancelled = true;
51967
+ inFlight.delete(personaId2);
51968
+ flight.cancelFn();
51969
+ }
51970
+ emit(personaId2, { state: "unbound", groups: [] });
51971
+ return { response: { type: "larkBot:provisionCancel:ok" } };
51972
+ };
51973
+ const bindManual = async (frame) => {
51974
+ const { personaId: personaId2, appId, appSecret, botName } = parseArgs2(
51975
+ LarkBotBindManualArgs,
51976
+ frame,
51977
+ "larkBot:bindManual"
51978
+ );
51979
+ const tunnelUrl = deps.getTunnelUrl();
51980
+ if (!tunnelUrl) throw new Error("larkBot bind requires tunnel to be up");
51981
+ const ownerId = deps.getOwnerId();
51982
+ if (!ownerId) throw new Error("larkBot bind requires feishu login (owner identity)");
51983
+ const name = botName ?? deps.getPersonaName(personaId2) ?? personaId2;
51984
+ await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName: name, tunnelUrl, ownerId });
51985
+ deps.store.write(personaId2, { appId, botName: name, boundAt: now() });
51986
+ emit(personaId2, { state: "bound", appId, botName: name, groups: groupsOf(personaId2) });
51987
+ return { response: { type: "larkBot:bindManual:ok" } };
51988
+ };
51989
+ const unbind = async (frame) => {
51990
+ const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "larkBot:unbind");
51991
+ const meta = deps.store.read(personaId2);
51992
+ if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
51993
+ try {
51994
+ await deps.cloud.unbind(meta.appId);
51995
+ } catch (err) {
51996
+ if (err.status !== 404) throw err;
51997
+ deps.logger?.warn(`larkBot unbind: cloud binding already gone: ${meta.appId}`);
51998
+ }
51999
+ deps.store.remove(personaId2);
52000
+ emit(personaId2, { state: "unbound", groups: [] });
52001
+ return { response: { type: "larkBot:unbind:ok" } };
52002
+ };
52003
+ const status = async (frame) => {
52004
+ const { personaId: personaId2 } = parseArgs2(LarkBotStatusArgs, frame, "larkBot:status");
52005
+ const meta = deps.store.read(personaId2);
52006
+ if (!meta) {
52007
+ return {
52008
+ response: { type: "larkBot:status:ok", state: "unbound", groups: [] }
52009
+ };
52010
+ }
52011
+ let cloudBinding;
52012
+ try {
52013
+ cloudBinding = (await deps.cloud.listBindings()).find((b2) => b2.personaId === personaId2);
52014
+ } catch (err) {
52015
+ deps.logger?.warn(`larkBot status: cloud unreachable: ${err.message}`);
52016
+ }
52017
+ const broken = cloudBinding?.status === "broken";
52018
+ const result = {
52019
+ state: broken ? "broken" : "bound",
52020
+ appId: meta.appId,
52021
+ botName: meta.botName,
52022
+ ...broken ? { brokenReason: cloudBinding?.brokenReason ?? "unknown" } : {},
52023
+ groups: groupsOf(personaId2)
52024
+ };
52025
+ return { response: { type: "larkBot:status:ok", ...result } };
52026
+ };
52027
+ return {
52028
+ "larkBot:provision": provision,
52029
+ "larkBot:provisionCancel": provisionCancel,
52030
+ "larkBot:bindManual": bindManual,
52031
+ "larkBot:unbind": unbind,
52032
+ "larkBot:status": status
52033
+ };
52034
+ }
52035
+ async function refreshTunnelUrlOnStartup(deps) {
52036
+ if (deps.listBoundPersonaIds().length === 0) return;
52037
+ const tunnelUrl = deps.getTunnelUrl();
52038
+ if (!tunnelUrl) return;
52039
+ try {
52040
+ await deps.cloud.updateTunnelUrl(tunnelUrl);
52041
+ } catch (err) {
52042
+ deps.logger?.warn(`larkBot tunnel refresh failed: ${err.message}`);
52043
+ }
52044
+ }
52045
+
52046
+ // src/lark-bot-connector/binding-store.ts
52047
+ var import_node_fs26 = __toESM(require("fs"), 1);
52048
+ var import_node_path27 = __toESM(require("path"), 1);
52049
+ function createLarkBotBindingStore(personaRoot) {
52050
+ const filePath = (personaId2) => import_node_path27.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
52051
+ const read = (personaId2) => {
52052
+ const file = filePath(personaId2);
52053
+ if (!import_node_fs26.default.existsSync(file)) return null;
52054
+ try {
52055
+ const raw = JSON.parse(import_node_fs26.default.readFileSync(file, "utf8"));
52056
+ if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
52057
+ return raw;
52058
+ } catch {
52059
+ return null;
52060
+ }
52061
+ };
52062
+ const write = (personaId2, meta) => {
52063
+ const file = filePath(personaId2);
52064
+ import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
52065
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
52066
+ import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
52067
+ import_node_fs26.default.renameSync(tmp, file);
52068
+ };
52069
+ return {
52070
+ read,
52071
+ write,
52072
+ remove(personaId2) {
52073
+ import_node_fs26.default.rmSync(filePath(personaId2), { force: true });
52074
+ },
52075
+ addRemovedChat(personaId2, chatId) {
52076
+ const meta = read(personaId2);
52077
+ if (!meta) return;
52078
+ const set = new Set(meta.removedChatIds ?? []);
52079
+ set.add(chatId);
52080
+ write(personaId2, { ...meta, removedChatIds: [...set] });
52081
+ }
52082
+ };
52083
+ }
52084
+
52085
+ // src/lark-bot-connector/cloud-client.ts
52086
+ var LarkBotCloudError = class extends Error {
52087
+ constructor(message, status) {
52088
+ super(message);
52089
+ this.status = status;
52090
+ this.name = "LarkBotCloudError";
52091
+ }
52092
+ status;
52093
+ };
52094
+ function createLarkBotCloudClient(opts) {
52095
+ const f = opts.fetchImpl ?? globalThis.fetch;
52096
+ if (!f) throw new Error("fetch is not available (Node >= 18 required)");
52097
+ const base = opts.api.replace(/\/+$/, "");
52098
+ async function request(method, pathname, body) {
52099
+ const ac = new AbortController();
52100
+ const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? 15e3);
52101
+ let res;
52102
+ try {
52103
+ res = await f(`${base}${pathname}`, {
52104
+ method,
52105
+ signal: ac.signal,
52106
+ headers: {
52107
+ authorization: `Bearer ${opts.apiKey}`,
52108
+ "x-did": encodeURIComponent(opts.deviceId),
52109
+ "x-name": encodeURIComponent(opts.displayName),
52110
+ "x-scene": "daemon",
52111
+ "content-type": "application/json"
52112
+ },
52113
+ body: body ? JSON.stringify(body) : void 0
52114
+ });
52115
+ } catch (err) {
52116
+ throw new LarkBotCloudError(`lark-bot cloud request failed: ${err.message}`);
52117
+ } finally {
52118
+ clearTimeout(timer);
52119
+ }
52120
+ let json = {};
52121
+ try {
52122
+ json = await res.json();
52123
+ } catch {
52124
+ json = {};
52125
+ }
52126
+ if (!res.ok) {
52127
+ throw new LarkBotCloudError(
52128
+ `lark-bot cloud ${method} ${pathname}: HTTP ${res.status} ${JSON.stringify(json).slice(0, 200)}`,
52129
+ res.status
52130
+ );
52131
+ }
52132
+ return json;
52133
+ }
52134
+ return {
52135
+ async bind(args) {
52136
+ await request("PUT", "/api/lark-bot/bind", { ...args });
52137
+ },
52138
+ async unbind(appId) {
52139
+ await request("DELETE", `/api/lark-bot/bind/${encodeURIComponent(appId)}`);
52140
+ },
52141
+ async listBindings() {
52142
+ const json = await request("GET", "/api/lark-bot/bindings");
52143
+ return json.items ?? [];
52144
+ },
52145
+ async updateTunnelUrl(tunnelUrl) {
52146
+ await request("PATCH", "/api/lark-bot/tunnel", { tunnelUrl });
52147
+ },
52148
+ async reply(args) {
52149
+ await request("POST", "/api/lark-bot/reply", { ...args });
52150
+ },
52151
+ async claimEvents() {
52152
+ const json = await request("POST", "/api/lark-bot/events/claim");
52153
+ return json.items ?? [];
52154
+ }
52155
+ };
52156
+ }
52157
+
52158
+ // src/lark-bot-connector/chat-router.ts
52159
+ var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
52160
+ var DEFAULT_TURN_TIMEOUT_MS = 10 * 60 * 1e3;
52161
+ function createLarkChatRouter(deps) {
52162
+ const timeoutMs = deps.turnTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS;
52163
+ const replyDelays = deps.replyRetryDelaysMs ?? [2e3, 8e3, 3e4];
52164
+ const sleep2 = deps.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
52165
+ const queues = /* @__PURE__ */ new Map();
52166
+ const activity = /* @__PURE__ */ new Map();
52167
+ const runOne = async (env) => {
52168
+ if (!env.messageId) {
52169
+ deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${env.eventId}`);
52170
+ return;
52171
+ }
52172
+ const chatLabel = env.chatName ?? env.chatId;
52173
+ const text = `[\u98DE\u4E66\u7FA4\xB7${chatLabel}] ${env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458"}: ${env.text ?? ""}`;
52174
+ const turn = deps.manager.runLarkChatTurn({
52175
+ personaId: env.personaId,
52176
+ chatId: env.chatId,
52177
+ chatName: env.chatName,
52178
+ senderOpenId: env.senderOpenId ?? "",
52179
+ senderName: env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
52180
+ text
52181
+ });
52182
+ activity.set(env.chatId, {
52183
+ chatId: env.chatId,
52184
+ chatName: env.chatName,
52185
+ lastActiveAt: Date.now(),
52186
+ personaId: env.personaId
52187
+ });
52188
+ let timedOut = false;
52189
+ let timer;
52190
+ const timeout = new Promise((resolve6) => {
52191
+ timer = setTimeout(() => {
52192
+ timedOut = true;
52193
+ turn.kill();
52194
+ resolve6({ error: "turn timeout" });
52195
+ }, timeoutMs);
52196
+ });
52197
+ let result;
52198
+ try {
52199
+ result = await Promise.race([turn.ended, timeout]);
52200
+ } finally {
52201
+ clearTimeout(timer);
52202
+ }
52203
+ const replyText = "ok" in result && result.ok ? result.replyText : ERROR_REPLY_TEXT;
52204
+ if (!("ok" in result)) {
52205
+ deps.logger?.warn(
52206
+ `larkBot turn ${timedOut ? "timeout" : "error"} (${env.chatId}): ${result.error}`
52207
+ );
52208
+ }
52209
+ for (let attempt = 0; attempt <= replyDelays.length; attempt++) {
52210
+ if (attempt > 0) await sleep2(replyDelays[attempt - 1]);
52211
+ try {
52212
+ await deps.cloud.reply({
52213
+ appId: env.appId,
52214
+ chatId: env.chatId,
52215
+ replyToMessageId: env.messageId,
52216
+ text: replyText,
52217
+ eventId: env.eventId
52218
+ });
52219
+ return;
52220
+ } catch (err) {
52221
+ deps.logger?.warn(
52222
+ `larkBot reply attempt ${attempt + 1} failed (${env.chatId}): ${err.message}`
52223
+ );
52224
+ }
52225
+ }
52226
+ };
52227
+ return {
52228
+ handleEnvelope(env) {
52229
+ if (env.type === "bot_removed") {
52230
+ deps.store.addRemovedChat(env.personaId, env.chatId);
52231
+ activity.delete(env.chatId);
52232
+ queues.delete(env.chatId);
52233
+ deps.logger?.info(`larkBot removed from chat ${env.chatId} (persona ${env.personaId})`);
52234
+ return;
52235
+ }
52236
+ const prev = queues.get(env.chatId) ?? Promise.resolve();
52237
+ const next = prev.then(
52238
+ () => runOne(env).catch(
52239
+ (err) => deps.logger?.warn(`larkBot chat-router runOne failed: ${err.message}`)
52240
+ )
52241
+ );
52242
+ queues.set(env.chatId, next);
52243
+ void next.finally(() => {
52244
+ if (queues.get(env.chatId) === next) queues.delete(env.chatId);
52245
+ });
52246
+ },
52247
+ listLarkSessions(personaId2) {
52248
+ return [...activity.values()].filter((a) => a.personaId === personaId2).map((a) => ({ chatId: a.chatId, chatName: a.chatName, lastActiveAt: a.lastActiveAt }));
52249
+ }
52250
+ };
52251
+ }
52252
+
52253
+ // src/lark-bot-connector/envelope.ts
52254
+ var import_node_crypto6 = require("crypto");
52255
+ var LARK_ENVELOPE_PREFIX = "clawdlbe1";
52256
+ function verifyLarkEventEnvelope(args) {
52257
+ const { token, publicKeyPem } = args;
52258
+ const now = args.nowSeconds ?? Math.floor(Date.now() / 1e3);
52259
+ const parts = token.split(".");
52260
+ if (parts.length !== 3 || parts[0] !== LARK_ENVELOPE_PREFIX) {
52261
+ return { ok: false, reason: "BAD_FORMAT" };
52262
+ }
52263
+ const [prefix, payloadB64, sigB64] = parts;
52264
+ let envelope;
52265
+ try {
52266
+ envelope = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
52267
+ } catch {
52268
+ return { ok: false, reason: "BAD_FORMAT" };
52269
+ }
52270
+ const data = Buffer.from(`${prefix}.${payloadB64}`, "utf8");
52271
+ let sigOk = false;
52272
+ try {
52273
+ sigOk = (0, import_node_crypto6.verify)(null, data, publicKeyPem, Buffer.from(sigB64, "base64url"));
52274
+ } catch {
52275
+ sigOk = false;
52276
+ }
52277
+ if (!sigOk) return { ok: false, reason: "BAD_SIGNATURE" };
52278
+ if (typeof envelope.exp !== "number" || envelope.exp <= now) {
52279
+ return { ok: false, reason: "EXPIRED" };
52280
+ }
52281
+ return { ok: true, envelope };
52282
+ }
52283
+
52284
+ // src/lark-bot-connector/event-endpoint.ts
52285
+ var DEFAULT_DEDUPE_CAPACITY = 1024;
52286
+ function createLarkEventDedupe(capacity = DEFAULT_DEDUPE_CAPACITY) {
52287
+ const seen = /* @__PURE__ */ new Map();
52288
+ return {
52289
+ has: (id) => seen.has(id),
52290
+ add: (id) => {
52291
+ if (seen.has(id)) return;
52292
+ seen.set(id, true);
52293
+ if (seen.size > capacity) {
52294
+ const oldest = seen.keys().next().value;
52295
+ if (oldest !== void 0) seen.delete(oldest);
52296
+ }
52297
+ }
52298
+ };
52299
+ }
52300
+ function createLarkBotEventEndpoint(deps) {
52301
+ const seen = deps.dedupe ?? createLarkEventDedupe(deps.dedupeCapacity ?? DEFAULT_DEDUPE_CAPACITY);
52302
+ return (rawBody) => {
52303
+ const publicKeyPem = deps.getPublicKey();
52304
+ if (!publicKeyPem) {
52305
+ return { status: 503, body: { code: "SERVER_KEY_UNAVAILABLE", message: "server public key not cached yet" } };
52306
+ }
52307
+ const r = verifyLarkEventEnvelope({
52308
+ token: rawBody.trim(),
52309
+ publicKeyPem,
52310
+ nowSeconds: deps.nowSeconds?.()
52311
+ });
52312
+ if (!r.ok) {
52313
+ return { status: 401, body: { code: r.reason, message: `lark event envelope rejected: ${r.reason}` } };
52314
+ }
52315
+ const { envelope } = r;
52316
+ if (seen.has(envelope.eventId)) {
52317
+ return { status: 202, body: { ok: true, deduped: true } };
52318
+ }
52319
+ seen.add(envelope.eventId);
52320
+ try {
52321
+ deps.route(envelope);
52322
+ } catch (err) {
52323
+ deps.logger?.warn(`larkBot event route failed: ${err.message}`);
52324
+ }
52325
+ return { status: 202, body: { ok: true } };
52326
+ };
52327
+ }
52328
+
51529
52329
  // src/ticket/constants.ts
51530
52330
  var DEFAULT_CLAWD_TICKETS_API_KEY = "cf057f047674896978ddcc813adbc4a186551a6fcf59ad9d";
51531
52331
  function resolveClawdTicketsApiKey() {
@@ -52137,7 +52937,7 @@ var CodexHistoryReader = class {
52137
52937
  };
52138
52938
 
52139
52939
  // src/tools/codex-skills.ts
52140
- var import_node_path27 = __toESM(require("path"), 1);
52940
+ var import_node_path28 = __toESM(require("path"), 1);
52141
52941
  function str3(v2) {
52142
52942
  return typeof v2 === "string" ? v2 : void 0;
52143
52943
  }
@@ -52152,13 +52952,13 @@ function mapSkillsListResponse(res) {
52152
52952
  const r = s ?? {};
52153
52953
  const name = str3(r.name);
52154
52954
  if (!name) continue;
52155
- const path77 = str3(r.path);
52955
+ const path78 = str3(r.path);
52156
52956
  const description = str3(r.description);
52157
52957
  const isPlugin = name.includes(":");
52158
52958
  out.push({
52159
52959
  name,
52160
52960
  source: isPlugin ? "plugin" : "project",
52161
- ...path77 ? { path: path77 } : {},
52961
+ ...path78 ? { path: path78 } : {},
52162
52962
  ...description ? { description } : {},
52163
52963
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
52164
52964
  });
@@ -52174,30 +52974,30 @@ async function listCodexSkills(cwd, deps = {}) {
52174
52974
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
52175
52975
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
52176
52976
  beforeRequest: (client) => {
52177
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path27.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
52977
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path28.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
52178
52978
  }
52179
52979
  });
52180
52980
  return mapSkillsListResponse(res);
52181
52981
  }
52182
52982
 
52183
52983
  // src/workspace/browser.ts
52184
- var import_node_fs26 = __toESM(require("fs"), 1);
52984
+ var import_node_fs27 = __toESM(require("fs"), 1);
52185
52985
  var import_node_os8 = __toESM(require("os"), 1);
52186
- var import_node_path28 = __toESM(require("path"), 1);
52986
+ var import_node_path29 = __toESM(require("path"), 1);
52187
52987
  init_protocol();
52188
52988
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
52189
52989
  function resolveInsideCwd(cwd, subpath) {
52190
- const absCwd = import_node_path28.default.resolve(cwd);
52191
- const joined = import_node_path28.default.resolve(absCwd, subpath ?? ".");
52192
- const rel = import_node_path28.default.relative(absCwd, joined);
52193
- if (rel.startsWith("..") || import_node_path28.default.isAbsolute(rel)) {
52990
+ const absCwd = import_node_path29.default.resolve(cwd);
52991
+ const joined = import_node_path29.default.resolve(absCwd, subpath ?? ".");
52992
+ const rel = import_node_path29.default.relative(absCwd, joined);
52993
+ if (rel.startsWith("..") || import_node_path29.default.isAbsolute(rel)) {
52194
52994
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
52195
52995
  }
52196
52996
  return joined;
52197
52997
  }
52198
52998
  function ensureCwd(cwd) {
52199
52999
  try {
52200
- const stat = import_node_fs26.default.statSync(cwd);
53000
+ const stat = import_node_fs27.default.statSync(cwd);
52201
53001
  if (!stat.isDirectory()) {
52202
53002
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
52203
53003
  }
@@ -52211,7 +53011,7 @@ var WorkspaceBrowser = class {
52211
53011
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
52212
53012
  ensureCwd(cwd);
52213
53013
  const full = resolveInsideCwd(cwd, args.path);
52214
- const dirents = import_node_fs26.default.readdirSync(full, { withFileTypes: true });
53014
+ const dirents = import_node_fs27.default.readdirSync(full, { withFileTypes: true });
52215
53015
  const entries = [];
52216
53016
  for (const d of dirents) {
52217
53017
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -52221,7 +53021,7 @@ var WorkspaceBrowser = class {
52221
53021
  mtime: ""
52222
53022
  };
52223
53023
  try {
52224
- const st = import_node_fs26.default.statSync(import_node_path28.default.join(full, d.name));
53024
+ const st = import_node_fs27.default.statSync(import_node_path29.default.join(full, d.name));
52225
53025
  entry.mtime = new Date(st.mtimeMs).toISOString();
52226
53026
  if (d.isFile()) entry.size = st.size;
52227
53027
  } catch {
@@ -52237,14 +53037,14 @@ var WorkspaceBrowser = class {
52237
53037
  read(args) {
52238
53038
  ensureCwd(args.cwd);
52239
53039
  const full = resolveInsideCwd(args.cwd, args.path);
52240
- const st = import_node_fs26.default.statSync(full);
53040
+ const st = import_node_fs27.default.statSync(full);
52241
53041
  if (!st.isFile()) {
52242
53042
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
52243
53043
  }
52244
53044
  if (st.size > MAX_FILE_BYTES) {
52245
53045
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
52246
53046
  }
52247
- const buf = import_node_fs26.default.readFileSync(full);
53047
+ const buf = import_node_fs27.default.readFileSync(full);
52248
53048
  const isBinary = buf.includes(0);
52249
53049
  if (isBinary) {
52250
53050
  return {
@@ -52266,20 +53066,20 @@ var WorkspaceBrowser = class {
52266
53066
  };
52267
53067
 
52268
53068
  // src/skills/agents-scanner.ts
52269
- var import_node_fs27 = __toESM(require("fs"), 1);
53069
+ var import_node_fs28 = __toESM(require("fs"), 1);
52270
53070
  var import_node_os9 = __toESM(require("os"), 1);
52271
- var import_node_path29 = __toESM(require("path"), 1);
53071
+ var import_node_path30 = __toESM(require("path"), 1);
52272
53072
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
52273
53073
  function isDirLikeSync2(p2) {
52274
53074
  try {
52275
- return import_node_fs27.default.statSync(p2).isDirectory();
53075
+ return import_node_fs28.default.statSync(p2).isDirectory();
52276
53076
  } catch {
52277
53077
  return false;
52278
53078
  }
52279
53079
  }
52280
53080
  function fileExistsSync(p2) {
52281
53081
  try {
52282
- return import_node_fs27.default.statSync(p2).isFile();
53082
+ return import_node_fs28.default.statSync(p2).isFile();
52283
53083
  } catch {
52284
53084
  return false;
52285
53085
  }
@@ -52287,7 +53087,7 @@ function fileExistsSync(p2) {
52287
53087
  function parseAgentFile(filePath) {
52288
53088
  let content;
52289
53089
  try {
52290
- content = import_node_fs27.default.readFileSync(filePath, "utf8");
53090
+ content = import_node_fs28.default.readFileSync(filePath, "utf8");
52291
53091
  } catch {
52292
53092
  return {};
52293
53093
  }
@@ -52300,16 +53100,16 @@ function parseAgentFile(filePath) {
52300
53100
  function scanAgentsDir(dir, source, seen, out) {
52301
53101
  let entries;
52302
53102
  try {
52303
- entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
53103
+ entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
52304
53104
  } catch {
52305
53105
  return;
52306
53106
  }
52307
53107
  for (const ent of entries) {
52308
53108
  if (!ent.name.endsWith(".md")) continue;
52309
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path29.default.join(dir, ent.name)))) {
53109
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path30.default.join(dir, ent.name)))) {
52310
53110
  continue;
52311
53111
  }
52312
- const filePath = import_node_path29.default.join(dir, ent.name);
53112
+ const filePath = import_node_path30.default.join(dir, ent.name);
52313
53113
  const baseName = ent.name.replace(/\.md$/, "");
52314
53114
  if (seen.has(baseName)) continue;
52315
53115
  seen.add(baseName);
@@ -52327,12 +53127,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
52327
53127
  function walk2(dir, namespaces) {
52328
53128
  let entries;
52329
53129
  try {
52330
- entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
53130
+ entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
52331
53131
  } catch {
52332
53132
  return;
52333
53133
  }
52334
53134
  for (const ent of entries) {
52335
- const childPath = import_node_path29.default.join(dir, ent.name);
53135
+ const childPath = import_node_path30.default.join(dir, ent.name);
52336
53136
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
52337
53137
  walk2(childPath, [...namespaces, ent.name]);
52338
53138
  continue;
@@ -52357,13 +53157,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
52357
53157
  walk2(root, []);
52358
53158
  }
52359
53159
  function readInstalledPlugins2(home) {
52360
- const pluginsDir = import_node_path29.default.join(home, ".claude", "plugins");
52361
- const v2 = import_node_path29.default.join(pluginsDir, "installed_plugins_v2.json");
52362
- const v1 = import_node_path29.default.join(pluginsDir, "installed_plugins.json");
53160
+ const pluginsDir = import_node_path30.default.join(home, ".claude", "plugins");
53161
+ const v2 = import_node_path30.default.join(pluginsDir, "installed_plugins_v2.json");
53162
+ const v1 = import_node_path30.default.join(pluginsDir, "installed_plugins.json");
52363
53163
  let raw = null;
52364
53164
  for (const candidate of [v2, v1]) {
52365
53165
  try {
52366
- raw = import_node_fs27.default.readFileSync(candidate, "utf8");
53166
+ raw = import_node_fs28.default.readFileSync(candidate, "utf8");
52367
53167
  break;
52368
53168
  } catch {
52369
53169
  }
@@ -52388,19 +53188,19 @@ function readInstalledPlugins2(home) {
52388
53188
  return out;
52389
53189
  }
52390
53190
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
52391
- let cur = import_node_path29.default.resolve(startCwd);
52392
- const fsRoot = import_node_path29.default.parse(cur).root;
53191
+ let cur = import_node_path30.default.resolve(startCwd);
53192
+ const fsRoot = import_node_path30.default.parse(cur).root;
52393
53193
  while (true) {
52394
- scanAgentsDir(import_node_path29.default.join(cur, ".claude", "agents"), "project", seen, out);
53194
+ scanAgentsDir(import_node_path30.default.join(cur, ".claude", "agents"), "project", seen, out);
52395
53195
  let hasGit = false;
52396
53196
  try {
52397
- hasGit = import_node_fs27.default.existsSync(import_node_path29.default.join(cur, ".git"));
53197
+ hasGit = import_node_fs28.default.existsSync(import_node_path30.default.join(cur, ".git"));
52398
53198
  } catch {
52399
53199
  }
52400
53200
  if (hasGit) return;
52401
53201
  if (cur === home) return;
52402
53202
  if (cur === fsRoot) return;
52403
- const parent = import_node_path29.default.dirname(cur);
53203
+ const parent = import_node_path30.default.dirname(cur);
52404
53204
  if (parent === cur) return;
52405
53205
  cur = parent;
52406
53206
  }
@@ -52435,7 +53235,7 @@ var AgentsScanner = class {
52435
53235
  }
52436
53236
  const fsBlock = [];
52437
53237
  scanAgentsDir(
52438
- import_node_path29.default.join(this.home, ".claude", "agents"),
53238
+ import_node_path30.default.join(this.home, ".claude", "agents"),
52439
53239
  "global",
52440
53240
  seen,
52441
53241
  fsBlock
@@ -52449,7 +53249,7 @@ var AgentsScanner = class {
52449
53249
  ...this.extraPluginRoots
52450
53250
  ];
52451
53251
  for (const { name, root } of plugins) {
52452
- const agentsRoot = import_node_path29.default.join(root, "agents");
53252
+ const agentsRoot = import_node_path30.default.join(root, "agents");
52453
53253
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
52454
53254
  }
52455
53255
  return [...builtinBlock, ...fsBlock];
@@ -52457,15 +53257,15 @@ var AgentsScanner = class {
52457
53257
  };
52458
53258
 
52459
53259
  // src/observer/session-observer.ts
52460
- var import_node_fs29 = __toESM(require("fs"), 1);
53260
+ var import_node_fs30 = __toESM(require("fs"), 1);
52461
53261
  var import_node_os11 = __toESM(require("os"), 1);
52462
- var import_node_path31 = __toESM(require("path"), 1);
53262
+ var import_node_path32 = __toESM(require("path"), 1);
52463
53263
  init_claude_history();
52464
53264
 
52465
53265
  // src/observer/subagent-meta-observer.ts
52466
- var import_node_fs28 = __toESM(require("fs"), 1);
53266
+ var import_node_fs29 = __toESM(require("fs"), 1);
52467
53267
  var import_node_os10 = __toESM(require("os"), 1);
52468
- var import_node_path30 = __toESM(require("path"), 1);
53268
+ var import_node_path31 = __toESM(require("path"), 1);
52469
53269
  init_claude_history();
52470
53270
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
52471
53271
  var SubagentMetaObserver = class {
@@ -52478,7 +53278,7 @@ var SubagentMetaObserver = class {
52478
53278
  watches = /* @__PURE__ */ new Map();
52479
53279
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
52480
53280
  resolveSubagentDir(cwd, toolSessionId) {
52481
- return import_node_path30.default.join(
53281
+ return import_node_path31.default.join(
52482
53282
  this.home,
52483
53283
  ".claude",
52484
53284
  "projects",
@@ -52508,7 +53308,7 @@ var SubagentMetaObserver = class {
52508
53308
  attachWatcher(w2) {
52509
53309
  if (w2.watcher) return;
52510
53310
  try {
52511
- w2.watcher = import_node_fs28.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
53311
+ w2.watcher = import_node_fs29.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
52512
53312
  if (!name) return;
52513
53313
  const m2 = META_RE.exec(String(name));
52514
53314
  if (!m2) return;
@@ -52520,7 +53320,7 @@ var SubagentMetaObserver = class {
52520
53320
  scan(w2) {
52521
53321
  let entries;
52522
53322
  try {
52523
- entries = import_node_fs28.default.readdirSync(w2.dirPath);
53323
+ entries = import_node_fs29.default.readdirSync(w2.dirPath);
52524
53324
  } catch {
52525
53325
  return;
52526
53326
  }
@@ -52534,10 +53334,10 @@ var SubagentMetaObserver = class {
52534
53334
  if (!m2) return;
52535
53335
  const agentId = m2[1];
52536
53336
  if (w2.emitted.has(agentId)) return;
52537
- const file = import_node_path30.default.join(w2.dirPath, name);
53337
+ const file = import_node_path31.default.join(w2.dirPath, name);
52538
53338
  let raw;
52539
53339
  try {
52540
- raw = import_node_fs28.default.readFileSync(file, "utf8");
53340
+ raw = import_node_fs29.default.readFileSync(file, "utf8");
52541
53341
  } catch {
52542
53342
  return;
52543
53343
  }
@@ -52594,14 +53394,14 @@ var SessionObserver = class {
52594
53394
  metaObserver;
52595
53395
  resolveJsonlPath(cwd, toolSessionId, override) {
52596
53396
  if (override) return override;
52597
- return import_node_path31.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
53397
+ return import_node_path32.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
52598
53398
  }
52599
53399
  start(args) {
52600
53400
  this.stop(args.sessionId);
52601
53401
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
52602
53402
  let size = 0;
52603
53403
  try {
52604
- size = import_node_fs29.default.statSync(filePath).size;
53404
+ size = import_node_fs30.default.statSync(filePath).size;
52605
53405
  } catch {
52606
53406
  }
52607
53407
  const w2 = {
@@ -52614,16 +53414,16 @@ var SessionObserver = class {
52614
53414
  adapter: args.adapter,
52615
53415
  prevIsRejectSentinel: false,
52616
53416
  toolSessionId: args.toolSessionId,
52617
- sawFile: import_node_fs29.default.existsSync(filePath),
53417
+ sawFile: import_node_fs30.default.existsSync(filePath),
52618
53418
  lastRelocateScanMs: 0,
52619
53419
  pendingCwdDerive: false,
52620
53420
  lastDeriveMs: 0
52621
53421
  };
52622
53422
  try {
52623
- import_node_fs29.default.mkdirSync(import_node_path31.default.dirname(filePath), { recursive: true });
53423
+ import_node_fs30.default.mkdirSync(import_node_path32.default.dirname(filePath), { recursive: true });
52624
53424
  } catch {
52625
53425
  }
52626
- w2.watcher = import_node_fs29.default.watch(import_node_path31.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
53426
+ w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
52627
53427
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
52628
53428
  this.poll(w2);
52629
53429
  });
@@ -52646,7 +53446,7 @@ var SessionObserver = class {
52646
53446
  // 异常静默吞,不阻塞 watcher 启动
52647
53447
  hydrateMetaTail(w2, maxLines = 200) {
52648
53448
  try {
52649
- const raw = import_node_fs29.default.readFileSync(w2.filePath, "utf8");
53449
+ const raw = import_node_fs30.default.readFileSync(w2.filePath, "utf8");
52650
53450
  if (!raw) return;
52651
53451
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
52652
53452
  if (allLines.length === 0) return;
@@ -52670,7 +53470,7 @@ var SessionObserver = class {
52670
53470
  poll(w2) {
52671
53471
  let size = 0;
52672
53472
  try {
52673
- size = import_node_fs29.default.statSync(w2.filePath).size;
53473
+ size = import_node_fs30.default.statSync(w2.filePath).size;
52674
53474
  } catch {
52675
53475
  if (w2.sawFile) this.maybeRelocate(w2);
52676
53476
  return;
@@ -52681,11 +53481,11 @@ var SessionObserver = class {
52681
53481
  w2.buf = "";
52682
53482
  }
52683
53483
  if (size === w2.lastSize) return;
52684
- const fd = import_node_fs29.default.openSync(w2.filePath, "r");
53484
+ const fd = import_node_fs30.default.openSync(w2.filePath, "r");
52685
53485
  try {
52686
53486
  const len = size - w2.lastSize;
52687
53487
  const buf = Buffer.alloc(len);
52688
- import_node_fs29.default.readSync(fd, buf, 0, len, w2.lastSize);
53488
+ import_node_fs30.default.readSync(fd, buf, 0, len, w2.lastSize);
52689
53489
  w2.lastSize = size;
52690
53490
  w2.buf += buf.toString("utf8");
52691
53491
  let newlineIndex;
@@ -52708,7 +53508,7 @@ var SessionObserver = class {
52708
53508
  }
52709
53509
  }
52710
53510
  } finally {
52711
- import_node_fs29.default.closeSync(fd);
53511
+ import_node_fs30.default.closeSync(fd);
52712
53512
  }
52713
53513
  if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
52714
53514
  }
@@ -52720,7 +53520,7 @@ var SessionObserver = class {
52720
53520
  const now = Date.now();
52721
53521
  if (now - w2.lastRelocateScanMs < 1e3) return;
52722
53522
  w2.lastRelocateScanMs = now;
52723
- const projectsRoot = import_node_path31.default.join(this.home, ".claude", "projects");
53523
+ const projectsRoot = import_node_path32.default.join(this.home, ".claude", "projects");
52724
53524
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
52725
53525
  if (!found || found === w2.filePath) return;
52726
53526
  try {
@@ -52729,7 +53529,7 @@ var SessionObserver = class {
52729
53529
  }
52730
53530
  w2.filePath = found;
52731
53531
  try {
52732
- w2.watcher = import_node_fs29.default.watch(import_node_path31.default.dirname(found), { persistent: false }, (_event, changedName) => {
53532
+ w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(found), { persistent: false }, (_event, changedName) => {
52733
53533
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
52734
53534
  this.poll(w2);
52735
53535
  });
@@ -53524,8 +54324,8 @@ async function authenticate(token, deps) {
53524
54324
  }
53525
54325
 
53526
54326
  // src/legacy-cleanup.ts
53527
- var fs34 = __toESM(require("fs/promises"), 1);
53528
- var path36 = __toESM(require("path"), 1);
54327
+ var fs35 = __toESM(require("fs/promises"), 1);
54328
+ var path37 = __toESM(require("path"), 1);
53529
54329
  var LEGACY_FILES = [
53530
54330
  "personal-capability.json",
53531
54331
  "received-capabilities.json",
@@ -53534,9 +54334,9 @@ var LEGACY_FILES = [
53534
54334
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
53535
54335
  const removed = [];
53536
54336
  for (const name of LEGACY_FILES) {
53537
- const p2 = path36.join(dataDir, name);
54337
+ const p2 = path37.join(dataDir, name);
53538
54338
  try {
53539
- await fs34.unlink(p2);
54339
+ await fs35.unlink(p2);
53540
54340
  removed.push(name);
53541
54341
  logger.debug("legacy capability file removed", { file: name });
53542
54342
  } catch (err) {
@@ -53548,13 +54348,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
53548
54348
  }
53549
54349
 
53550
54350
  // src/inbox/inbox-store.ts
53551
- var fs35 = __toESM(require("fs"), 1);
53552
- var path37 = __toESM(require("path"), 1);
54351
+ var fs36 = __toESM(require("fs"), 1);
54352
+ var path38 = __toESM(require("path"), 1);
53553
54353
  var INBOX_SUBDIR = "inbox";
53554
54354
  var InboxStore = class {
53555
54355
  constructor(dataDir) {
53556
54356
  this.dataDir = dataDir;
53557
- fs35.mkdirSync(this.dirPath(), { recursive: true });
54357
+ fs36.mkdirSync(this.dirPath(), { recursive: true });
53558
54358
  }
53559
54359
  dataDir;
53560
54360
  /**
@@ -53566,7 +54366,7 @@ var InboxStore = class {
53566
54366
  const file = this.filePath(peerDeviceId);
53567
54367
  let raw;
53568
54368
  try {
53569
- raw = fs35.readFileSync(file, "utf8");
54369
+ raw = fs36.readFileSync(file, "utf8");
53570
54370
  } catch (err) {
53571
54371
  if (err?.code === "ENOENT") return [];
53572
54372
  return [];
@@ -53582,7 +54382,7 @@ var InboxStore = class {
53582
54382
  const dir = this.dirPath();
53583
54383
  let entries;
53584
54384
  try {
53585
- entries = fs35.readdirSync(dir);
54385
+ entries = fs36.readdirSync(dir);
53586
54386
  } catch (err) {
53587
54387
  if (err?.code === "ENOENT") return [];
53588
54388
  return [];
@@ -53598,9 +54398,9 @@ var InboxStore = class {
53598
54398
  if (existing.some((m2) => m2.id === message.id)) return;
53599
54399
  const file = this.filePath(message.peerDeviceId);
53600
54400
  const line = JSON.stringify(message) + "\n";
53601
- fs35.appendFileSync(file, line, { mode: 384 });
54401
+ fs36.appendFileSync(file, line, { mode: 384 });
53602
54402
  try {
53603
- fs35.chmodSync(file, 384);
54403
+ fs36.chmodSync(file, 384);
53604
54404
  } catch {
53605
54405
  }
53606
54406
  }
@@ -53630,7 +54430,7 @@ var InboxStore = class {
53630
54430
  removeByPeerDeviceId(peerDeviceId) {
53631
54431
  const file = this.filePath(peerDeviceId);
53632
54432
  try {
53633
- fs35.unlinkSync(file);
54433
+ fs36.unlinkSync(file);
53634
54434
  } catch (err) {
53635
54435
  if (err?.code === "ENOENT") return;
53636
54436
  }
@@ -53639,18 +54439,18 @@ var InboxStore = class {
53639
54439
  const file = this.filePath(peerDeviceId);
53640
54440
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
53641
54441
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
53642
- fs35.writeFileSync(tmp, content, { mode: 384 });
53643
- fs35.renameSync(tmp, file);
54442
+ fs36.writeFileSync(tmp, content, { mode: 384 });
54443
+ fs36.renameSync(tmp, file);
53644
54444
  try {
53645
- fs35.chmodSync(file, 384);
54445
+ fs36.chmodSync(file, 384);
53646
54446
  } catch {
53647
54447
  }
53648
54448
  }
53649
54449
  dirPath() {
53650
- return path37.join(this.dataDir, INBOX_SUBDIR);
54450
+ return path38.join(this.dataDir, INBOX_SUBDIR);
53651
54451
  }
53652
54452
  filePath(peerDeviceId) {
53653
- return path37.join(this.dirPath(), `${peerDeviceId}.jsonl`);
54453
+ return path38.join(this.dirPath(), `${peerDeviceId}.jsonl`);
53654
54454
  }
53655
54455
  };
53656
54456
  function parseAllLines(raw) {
@@ -53738,8 +54538,8 @@ var InboxManager = class {
53738
54538
  };
53739
54539
 
53740
54540
  // src/state/contact-store.ts
53741
- var fs36 = __toESM(require("fs"), 1);
53742
- var path38 = __toESM(require("path"), 1);
54541
+ var fs37 = __toESM(require("fs"), 1);
54542
+ var path39 = __toESM(require("path"), 1);
53743
54543
  var FILE_NAME = "contacts.json";
53744
54544
  var ContactStore = class {
53745
54545
  constructor(dataDir) {
@@ -53749,10 +54549,10 @@ var ContactStore = class {
53749
54549
  contacts = /* @__PURE__ */ new Map();
53750
54550
  load() {
53751
54551
  this.contacts.clear();
53752
- const file = path38.join(this.dataDir, FILE_NAME);
54552
+ const file = path39.join(this.dataDir, FILE_NAME);
53753
54553
  let raw;
53754
54554
  try {
53755
- raw = fs36.readFileSync(file, "utf8");
54555
+ raw = fs37.readFileSync(file, "utf8");
53756
54556
  } catch (err) {
53757
54557
  if (err?.code !== "ENOENT") this.renameBak(file);
53758
54558
  return;
@@ -53821,20 +54621,20 @@ var ContactStore = class {
53821
54621
  return true;
53822
54622
  }
53823
54623
  flush() {
53824
- const file = path38.join(this.dataDir, FILE_NAME);
54624
+ const file = path39.join(this.dataDir, FILE_NAME);
53825
54625
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
53826
54626
  const content = JSON.stringify(
53827
54627
  { contacts: Array.from(this.contacts.values()) },
53828
54628
  null,
53829
54629
  2
53830
54630
  );
53831
- fs36.mkdirSync(this.dataDir, { recursive: true });
53832
- fs36.writeFileSync(tmp, content, { mode: 384 });
53833
- fs36.renameSync(tmp, file);
54631
+ fs37.mkdirSync(this.dataDir, { recursive: true });
54632
+ fs37.writeFileSync(tmp, content, { mode: 384 });
54633
+ fs37.renameSync(tmp, file);
53834
54634
  }
53835
54635
  renameBak(file) {
53836
54636
  try {
53837
- fs36.renameSync(file, `${file}.bak`);
54637
+ fs37.renameSync(file, `${file}.bak`);
53838
54638
  } catch {
53839
54639
  }
53840
54640
  }
@@ -53942,61 +54742,61 @@ async function connectRemote(args) {
53942
54742
  }
53943
54743
 
53944
54744
  // src/migrations/2026-05-20-flatten-sessions.ts
53945
- var fs37 = __toESM(require("fs"), 1);
53946
- var path39 = __toESM(require("path"), 1);
54745
+ var fs38 = __toESM(require("fs"), 1);
54746
+ var path40 = __toESM(require("path"), 1);
53947
54747
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
53948
54748
  function migrateFlattenSessions(opts) {
53949
54749
  const dataDir = opts.dataDir;
53950
54750
  const now = opts.now ?? Date.now;
53951
- const sessionsDir = path39.join(dataDir, "sessions");
53952
- const flagPath = path39.join(sessionsDir, MIGRATION_FLAG_NAME);
54751
+ const sessionsDir = path40.join(dataDir, "sessions");
54752
+ const flagPath = path40.join(sessionsDir, MIGRATION_FLAG_NAME);
53953
54753
  if (existsSync3(flagPath)) {
53954
54754
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
53955
54755
  }
53956
54756
  let movedBare = 0;
53957
54757
  let movedVmOwner = 0;
53958
54758
  let archivedListener = 0;
53959
- const defaultDir = path39.join(sessionsDir, "default");
54759
+ const defaultDir = path40.join(sessionsDir, "default");
53960
54760
  if (existsSync3(defaultDir)) {
53961
54761
  for (const entry of readdirSafe(defaultDir)) {
53962
54762
  if (!entry.endsWith(".json")) continue;
53963
- const src = path39.join(defaultDir, entry);
53964
- const dst = path39.join(sessionsDir, entry);
53965
- fs37.renameSync(src, dst);
54763
+ const src = path40.join(defaultDir, entry);
54764
+ const dst = path40.join(sessionsDir, entry);
54765
+ fs38.renameSync(src, dst);
53966
54766
  movedBare += 1;
53967
54767
  }
53968
54768
  rmdirIfEmpty(defaultDir);
53969
54769
  }
53970
54770
  for (const pid of readdirSafe(sessionsDir)) {
53971
- const personaDir = path39.join(sessionsDir, pid);
54771
+ const personaDir = path40.join(sessionsDir, pid);
53972
54772
  if (!isDir(personaDir)) continue;
53973
54773
  if (pid === "default") continue;
53974
- const ownerSrc = path39.join(personaDir, "owner");
54774
+ const ownerSrc = path40.join(personaDir, "owner");
53975
54775
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
53976
- const ownerDst = path39.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
53977
- fs37.mkdirSync(ownerDst, { recursive: true });
54776
+ const ownerDst = path40.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
54777
+ fs38.mkdirSync(ownerDst, { recursive: true });
53978
54778
  for (const file of readdirSafe(ownerSrc)) {
53979
54779
  if (!file.endsWith(".json")) continue;
53980
- fs37.renameSync(path39.join(ownerSrc, file), path39.join(ownerDst, file));
54780
+ fs38.renameSync(path40.join(ownerSrc, file), path40.join(ownerDst, file));
53981
54781
  movedVmOwner += 1;
53982
54782
  }
53983
54783
  rmdirIfEmpty(ownerSrc);
53984
54784
  }
53985
- const listenerSrc = path39.join(personaDir, "listener");
54785
+ const listenerSrc = path40.join(personaDir, "listener");
53986
54786
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
53987
- const archiveDst = path39.join(dataDir, ".legacy", `listener-${pid}`);
53988
- fs37.mkdirSync(archiveDst, { recursive: true });
54787
+ const archiveDst = path40.join(dataDir, ".legacy", `listener-${pid}`);
54788
+ fs38.mkdirSync(archiveDst, { recursive: true });
53989
54789
  for (const file of readdirSafe(listenerSrc)) {
53990
54790
  if (!file.endsWith(".json")) continue;
53991
- fs37.renameSync(path39.join(listenerSrc, file), path39.join(archiveDst, file));
54791
+ fs38.renameSync(path40.join(listenerSrc, file), path40.join(archiveDst, file));
53992
54792
  archivedListener += 1;
53993
54793
  }
53994
54794
  rmdirIfEmpty(listenerSrc);
53995
54795
  }
53996
54796
  rmdirIfEmpty(personaDir);
53997
54797
  }
53998
- fs37.mkdirSync(sessionsDir, { recursive: true });
53999
- fs37.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
54798
+ fs38.mkdirSync(sessionsDir, { recursive: true });
54799
+ fs38.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
54000
54800
  return {
54001
54801
  skipped: false,
54002
54802
  flagWritten: true,
@@ -54007,7 +54807,7 @@ function migrateFlattenSessions(opts) {
54007
54807
  }
54008
54808
  function existsSync3(p2) {
54009
54809
  try {
54010
- fs37.statSync(p2);
54810
+ fs38.statSync(p2);
54011
54811
  return true;
54012
54812
  } catch {
54013
54813
  return false;
@@ -54015,31 +54815,31 @@ function existsSync3(p2) {
54015
54815
  }
54016
54816
  function isDir(p2) {
54017
54817
  try {
54018
- return fs37.statSync(p2).isDirectory();
54818
+ return fs38.statSync(p2).isDirectory();
54019
54819
  } catch {
54020
54820
  return false;
54021
54821
  }
54022
54822
  }
54023
54823
  function readdirSafe(p2) {
54024
54824
  try {
54025
- return fs37.readdirSync(p2);
54825
+ return fs38.readdirSync(p2);
54026
54826
  } catch {
54027
54827
  return [];
54028
54828
  }
54029
54829
  }
54030
54830
  function rmdirIfEmpty(p2) {
54031
54831
  try {
54032
- fs37.rmdirSync(p2);
54832
+ fs38.rmdirSync(p2);
54033
54833
  } catch {
54034
54834
  }
54035
54835
  }
54036
54836
 
54037
54837
  // src/transport/http-router.ts
54038
- var import_node_fs31 = __toESM(require("fs"), 1);
54039
- var import_node_path35 = __toESM(require("path"), 1);
54838
+ var import_node_fs32 = __toESM(require("fs"), 1);
54839
+ var import_node_path36 = __toESM(require("path"), 1);
54040
54840
 
54041
54841
  // src/attachment/mime.ts
54042
- var import_node_path32 = __toESM(require("path"), 1);
54842
+ var import_node_path33 = __toESM(require("path"), 1);
54043
54843
  var TEXT_PLAIN = "text/plain; charset=utf-8";
54044
54844
  var EXT_TO_NATIVE_MIME = {
54045
54845
  // 图片
@@ -54146,14 +54946,14 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
54146
54946
  ".mk"
54147
54947
  ]);
54148
54948
  function lookupMime(filePathOrName) {
54149
- const ext = import_node_path32.default.extname(filePathOrName).toLowerCase();
54949
+ const ext = import_node_path33.default.extname(filePathOrName).toLowerCase();
54150
54950
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
54151
54951
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
54152
54952
  return "application/octet-stream";
54153
54953
  }
54154
54954
 
54155
54955
  // src/attachment/sign-url.ts
54156
- var import_node_crypto6 = __toESM(require("crypto"), 1);
54956
+ var import_node_crypto7 = __toESM(require("crypto"), 1);
54157
54957
  var HMAC_ALGO = "sha256";
54158
54958
  function base64urlEncode(buf) {
54159
54959
  const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
@@ -54171,7 +54971,7 @@ function decodeAbsPathFromUrl(encoded) {
54171
54971
  var DOMAIN_PREFIX2 = "clawd-attach-v1|";
54172
54972
  function computeSig(secret, absPath, e) {
54173
54973
  const msg = e === null ? `${DOMAIN_PREFIX2}${absPath}` : `${DOMAIN_PREFIX2}${absPath}|${e}`;
54174
- return import_node_crypto6.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
54974
+ return import_node_crypto7.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
54175
54975
  }
54176
54976
  function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
54177
54977
  const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
@@ -54206,7 +55006,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
54206
55006
  if (provided.length !== expected.length) {
54207
55007
  return { ok: false, code: "BAD_SIG" };
54208
55008
  }
54209
- if (!import_node_crypto6.default.timingSafeEqual(provided, expected)) {
55009
+ if (!import_node_crypto7.default.timingSafeEqual(provided, expected)) {
54210
55010
  return { ok: false, code: "BAD_SIG" };
54211
55011
  }
54212
55012
  if (e !== null && now() / 1e3 > e) {
@@ -54216,9 +55016,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
54216
55016
  }
54217
55017
 
54218
55018
  // src/attachment/upload.ts
54219
- var import_node_fs30 = __toESM(require("fs"), 1);
54220
- var import_node_path33 = __toESM(require("path"), 1);
54221
- var import_node_crypto7 = __toESM(require("crypto"), 1);
55019
+ var import_node_fs31 = __toESM(require("fs"), 1);
55020
+ var import_node_path34 = __toESM(require("path"), 1);
55021
+ var import_node_crypto8 = __toESM(require("crypto"), 1);
54222
55022
  var import_promises3 = require("stream/promises");
54223
55023
  var UploadError = class extends Error {
54224
55024
  constructor(code, message) {
@@ -54229,24 +55029,24 @@ var UploadError = class extends Error {
54229
55029
  code;
54230
55030
  };
54231
55031
  function assertValidFileName(fileName) {
54232
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path33.default.basename(fileName)) {
55032
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path34.default.basename(fileName)) {
54233
55033
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
54234
55034
  }
54235
55035
  }
54236
55036
  var HASH_PREFIX_LEN = 16;
54237
55037
  async function writeUploadedAttachment(args) {
54238
55038
  assertValidFileName(args.fileName);
54239
- const attachmentsRoot = import_node_path33.default.join(args.sessionDir, ".attachments");
55039
+ const attachmentsRoot = import_node_path34.default.join(args.sessionDir, ".attachments");
54240
55040
  try {
54241
- import_node_fs30.default.mkdirSync(attachmentsRoot, { recursive: true });
55041
+ import_node_fs31.default.mkdirSync(attachmentsRoot, { recursive: true });
54242
55042
  } catch (err) {
54243
55043
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
54244
55044
  }
54245
- const hasher = import_node_crypto7.default.createHash("sha256");
55045
+ const hasher = import_node_crypto8.default.createHash("sha256");
54246
55046
  let actualSize = 0;
54247
- const tmpPath = import_node_path33.default.join(
55047
+ const tmpPath = import_node_path34.default.join(
54248
55048
  attachmentsRoot,
54249
- `.upload-${process.pid}-${Date.now()}-${import_node_crypto7.default.randomBytes(4).toString("hex")}`
55049
+ `.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
54250
55050
  );
54251
55051
  try {
54252
55052
  await (0, import_promises3.pipeline)(
@@ -54259,18 +55059,18 @@ async function writeUploadedAttachment(args) {
54259
55059
  yield buf;
54260
55060
  }
54261
55061
  },
54262
- import_node_fs30.default.createWriteStream(tmpPath, { mode: 384 })
55062
+ import_node_fs31.default.createWriteStream(tmpPath, { mode: 384 })
54263
55063
  );
54264
55064
  } catch (err) {
54265
55065
  try {
54266
- import_node_fs30.default.unlinkSync(tmpPath);
55066
+ import_node_fs31.default.unlinkSync(tmpPath);
54267
55067
  } catch {
54268
55068
  }
54269
55069
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
54270
55070
  }
54271
55071
  if (actualSize !== args.contentLength) {
54272
55072
  try {
54273
- import_node_fs30.default.unlinkSync(tmpPath);
55073
+ import_node_fs31.default.unlinkSync(tmpPath);
54274
55074
  } catch {
54275
55075
  }
54276
55076
  throw new UploadError(
@@ -54279,35 +55079,35 @@ async function writeUploadedAttachment(args) {
54279
55079
  );
54280
55080
  }
54281
55081
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
54282
- const hashDir = import_node_path33.default.join(attachmentsRoot, attachmentId);
55082
+ const hashDir = import_node_path34.default.join(attachmentsRoot, attachmentId);
54283
55083
  let finalFileName;
54284
55084
  let hashDirExists = false;
54285
55085
  try {
54286
- hashDirExists = import_node_fs30.default.statSync(hashDir).isDirectory();
55086
+ hashDirExists = import_node_fs31.default.statSync(hashDir).isDirectory();
54287
55087
  } catch {
54288
55088
  }
54289
55089
  if (hashDirExists) {
54290
- const existing = import_node_fs30.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
55090
+ const existing = import_node_fs31.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
54291
55091
  finalFileName = existing[0] ?? args.fileName;
54292
55092
  try {
54293
- import_node_fs30.default.unlinkSync(tmpPath);
55093
+ import_node_fs31.default.unlinkSync(tmpPath);
54294
55094
  } catch {
54295
55095
  }
54296
55096
  } else {
54297
55097
  try {
54298
- import_node_fs30.default.mkdirSync(hashDir, { recursive: true });
55098
+ import_node_fs31.default.mkdirSync(hashDir, { recursive: true });
54299
55099
  finalFileName = args.fileName;
54300
- import_node_fs30.default.renameSync(tmpPath, import_node_path33.default.join(hashDir, finalFileName));
55100
+ import_node_fs31.default.renameSync(tmpPath, import_node_path34.default.join(hashDir, finalFileName));
54301
55101
  } catch (err) {
54302
55102
  try {
54303
- import_node_fs30.default.unlinkSync(tmpPath);
55103
+ import_node_fs31.default.unlinkSync(tmpPath);
54304
55104
  } catch {
54305
55105
  }
54306
55106
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
54307
55107
  }
54308
55108
  }
54309
- const absPath = import_node_path33.default.join(hashDir, finalFileName);
54310
- const relPath = import_node_path33.default.relative(args.sessionDir, absPath);
55109
+ const absPath = import_node_path34.default.join(hashDir, finalFileName);
55110
+ const relPath = import_node_path34.default.relative(args.sessionDir, absPath);
54311
55111
  args.groupFileStore.upsert(args.scope, args.sessionId, {
54312
55112
  relPath: absPath,
54313
55113
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -54321,7 +55121,7 @@ async function writeUploadedAttachment(args) {
54321
55121
 
54322
55122
  // src/extension/import.ts
54323
55123
  var import_promises4 = __toESM(require("fs/promises"), 1);
54324
- var import_node_path34 = __toESM(require("path"), 1);
55124
+ var import_node_path35 = __toESM(require("path"), 1);
54325
55125
  var import_node_os12 = __toESM(require("os"), 1);
54326
55126
  var import_jszip = __toESM(require_lib3(), 1);
54327
55127
  var ImportError = class extends Error {
@@ -54339,7 +55139,7 @@ async function importZip(buf, root) {
54339
55139
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
54340
55140
  }
54341
55141
  for (const name of Object.keys(zip.files)) {
54342
- if (name.includes("..") || name.startsWith("/") || import_node_path34.default.isAbsolute(name)) {
55142
+ if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
54343
55143
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
54344
55144
  }
54345
55145
  }
@@ -54372,7 +55172,7 @@ async function importZip(buf, root) {
54372
55172
  );
54373
55173
  }
54374
55174
  }
54375
- const destDir = import_node_path34.default.join(root, manifest.id);
55175
+ const destDir = import_node_path35.default.join(root, manifest.id);
54376
55176
  let destExists = false;
54377
55177
  try {
54378
55178
  await import_promises4.default.access(destDir);
@@ -54382,15 +55182,15 @@ async function importZip(buf, root) {
54382
55182
  if (destExists) {
54383
55183
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
54384
55184
  }
54385
- const stage = await import_promises4.default.mkdtemp(import_node_path34.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
55185
+ const stage = await import_promises4.default.mkdtemp(import_node_path35.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
54386
55186
  try {
54387
55187
  for (const [name, entry] of Object.entries(zip.files)) {
54388
- const dest = import_node_path34.default.join(stage, name);
55188
+ const dest = import_node_path35.default.join(stage, name);
54389
55189
  if (entry.dir) {
54390
55190
  await import_promises4.default.mkdir(dest, { recursive: true });
54391
55191
  continue;
54392
55192
  }
54393
- await import_promises4.default.mkdir(import_node_path34.default.dirname(dest), { recursive: true });
55193
+ await import_promises4.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
54394
55194
  const content = await entry.async("nodebuffer");
54395
55195
  await import_promises4.default.writeFile(dest, content);
54396
55196
  }
@@ -54420,7 +55220,7 @@ var SHARE_UI_ASSET_MIME = {
54420
55220
  ".wasm": "application/wasm"
54421
55221
  };
54422
55222
  function shareUiAssetMime(filePath) {
54423
- const ext = import_node_path35.default.extname(filePath).toLowerCase();
55223
+ const ext = import_node_path36.default.extname(filePath).toLowerCase();
54424
55224
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
54425
55225
  }
54426
55226
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -54445,6 +55245,24 @@ function authedRpcErrorStatus(code) {
54445
55245
  return 400;
54446
55246
  }
54447
55247
  }
55248
+ var LARK_BOT_EVENT_MAX_BYTES = 64 * 1024;
55249
+ async function readRawBody(req, max) {
55250
+ return await new Promise((resolve6, reject) => {
55251
+ let size = 0;
55252
+ const chunks = [];
55253
+ req.on("data", (c) => {
55254
+ size += c.length;
55255
+ if (size > max) {
55256
+ reject(new Error(`body too large (> ${max} bytes)`));
55257
+ req.destroy();
55258
+ return;
55259
+ }
55260
+ chunks.push(c);
55261
+ });
55262
+ req.on("end", () => resolve6(Buffer.concat(chunks).toString("utf8")));
55263
+ req.on("error", reject);
55264
+ });
55265
+ }
54448
55266
  async function readJsonBody(req, max) {
54449
55267
  return await new Promise((resolve6, reject) => {
54450
55268
  let size = 0;
@@ -54501,7 +55319,7 @@ function isValidUploadFileName(fileName) {
54501
55319
  if (fileName === "." || fileName === "..") return false;
54502
55320
  if (fileName.startsWith(".")) return false;
54503
55321
  if (fileName.includes("/") || fileName.includes("\\")) return false;
54504
- return fileName === import_node_path35.default.basename(fileName);
55322
+ return fileName === import_node_path36.default.basename(fileName);
54505
55323
  }
54506
55324
  function createHttpRouter(deps) {
54507
55325
  return async (req, res) => {
@@ -54557,6 +55375,22 @@ function createHttpRouter(deps) {
54557
55375
  else sendJson(res, 403, { code: r.reason }, AUTHED_RPC_CORS_HEADERS);
54558
55376
  return true;
54559
55377
  }
55378
+ if (url.pathname === "/lark-bot-connector/event" && req.method === "POST") {
55379
+ if (!deps.larkBotEvent) {
55380
+ sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "lark bot event not wired" });
55381
+ return true;
55382
+ }
55383
+ let raw;
55384
+ try {
55385
+ raw = await readRawBody(req, LARK_BOT_EVENT_MAX_BYTES);
55386
+ } catch (err) {
55387
+ sendJson(res, 400, { code: "INVALID_BODY", message: err instanceof Error ? err.message : String(err) });
55388
+ return true;
55389
+ }
55390
+ const r = deps.larkBotEvent(raw);
55391
+ sendJson(res, r.status, r.body);
55392
+ return true;
55393
+ }
54560
55394
  if ((url.pathname === "/s" || url.pathname.startsWith("/s/")) && req.method === "GET") {
54561
55395
  if (!deps.shareUiAssetLoader) {
54562
55396
  sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "share-ui assets not loaded" });
@@ -54573,7 +55407,7 @@ function createHttpRouter(deps) {
54573
55407
  }
54574
55408
  let buf;
54575
55409
  try {
54576
- buf = await import_node_fs31.default.promises.readFile(abs);
55410
+ buf = await import_node_fs32.default.promises.readFile(abs);
54577
55411
  } catch {
54578
55412
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
54579
55413
  return true;
@@ -54721,7 +55555,7 @@ function createHttpRouter(deps) {
54721
55555
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
54722
55556
  return true;
54723
55557
  }
54724
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path35.default.basename(r.absPath)));
55558
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path36.default.basename(r.absPath)));
54725
55559
  return true;
54726
55560
  }
54727
55561
  const ctx = deps.authResolver.resolveFromHeader(
@@ -54842,7 +55676,7 @@ function createHttpRouter(deps) {
54842
55676
  return true;
54843
55677
  }
54844
55678
  let absPath;
54845
- if (import_node_path35.default.isAbsolute(pathParam)) {
55679
+ if (import_node_path36.default.isAbsolute(pathParam)) {
54846
55680
  absPath = pathParam;
54847
55681
  } else if (deps.sessionStore) {
54848
55682
  const file = deps.sessionStore.read(sid);
@@ -54850,7 +55684,7 @@ function createHttpRouter(deps) {
54850
55684
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
54851
55685
  return true;
54852
55686
  }
54853
- absPath = import_node_path35.default.join(file.cwd, pathParam);
55687
+ absPath = import_node_path36.default.join(file.cwd, pathParam);
54854
55688
  } else {
54855
55689
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
54856
55690
  return true;
@@ -54937,7 +55771,7 @@ function withCtx(ctx, body) {
54937
55771
  function streamFile(res, absPath, logger) {
54938
55772
  let stat;
54939
55773
  try {
54940
- stat = import_node_fs31.default.statSync(absPath);
55774
+ stat = import_node_fs32.default.statSync(absPath);
54941
55775
  } catch (err) {
54942
55776
  const code = err?.code;
54943
55777
  if (code === "ENOENT") {
@@ -54952,7 +55786,7 @@ function streamFile(res, absPath, logger) {
54952
55786
  return;
54953
55787
  }
54954
55788
  const mime = lookupMime(absPath);
54955
- const basename = import_node_path35.default.basename(absPath);
55789
+ const basename = import_node_path36.default.basename(absPath);
54956
55790
  res.writeHead(200, {
54957
55791
  "Content-Type": mime,
54958
55792
  "Content-Length": String(stat.size),
@@ -54960,7 +55794,7 @@ function streamFile(res, absPath, logger) {
54960
55794
  // 防止浏览器把任意 mime 当 html 渲染
54961
55795
  "X-Content-Type-Options": "nosniff"
54962
55796
  });
54963
- const stream = import_node_fs31.default.createReadStream(absPath);
55797
+ const stream = import_node_fs32.default.createReadStream(absPath);
54964
55798
  stream.on("error", (err) => {
54965
55799
  logger?.warn("streamFile read error", { absPath, err: err.message });
54966
55800
  res.destroy();
@@ -54969,8 +55803,8 @@ function streamFile(res, absPath, logger) {
54969
55803
  }
54970
55804
 
54971
55805
  // src/attachment/gc.ts
54972
- var import_node_fs32 = __toESM(require("fs"), 1);
54973
- var import_node_path36 = __toESM(require("path"), 1);
55806
+ var import_node_fs33 = __toESM(require("fs"), 1);
55807
+ var import_node_path37 = __toESM(require("path"), 1);
54974
55808
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
54975
55809
  function runAttachmentGc(args) {
54976
55810
  const now = (args.now ?? Date.now)();
@@ -54979,38 +55813,38 @@ function runAttachmentGc(args) {
54979
55813
  for (const { scope, sessionId } of args.sessionScopes) {
54980
55814
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
54981
55815
  if (entry.stale) continue;
54982
- if (import_node_path36.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
55816
+ if (import_node_path37.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
54983
55817
  }
54984
55818
  }
54985
55819
  for (const { scope, sessionId } of args.sessionScopes) {
54986
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path36.default.join(
55820
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path37.default.join(
54987
55821
  args.dataDir,
54988
55822
  "sessions",
54989
55823
  ...scopeSubPath(scope).map(safeFileName),
54990
55824
  safeFileName(sessionId)
54991
55825
  );
54992
- const attRoot = import_node_path36.default.join(sessionDir, ".attachments");
55826
+ const attRoot = import_node_path37.default.join(sessionDir, ".attachments");
54993
55827
  let hashDirs;
54994
55828
  try {
54995
- hashDirs = import_node_fs32.default.readdirSync(attRoot);
55829
+ hashDirs = import_node_fs33.default.readdirSync(attRoot);
54996
55830
  } catch (err) {
54997
55831
  if (err.code === "ENOENT") continue;
54998
55832
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
54999
55833
  continue;
55000
55834
  }
55001
55835
  for (const hashDir of hashDirs) {
55002
- const hashDirAbs = import_node_path36.default.join(attRoot, hashDir);
55836
+ const hashDirAbs = import_node_path37.default.join(attRoot, hashDir);
55003
55837
  let files;
55004
55838
  try {
55005
- files = import_node_fs32.default.readdirSync(hashDirAbs);
55839
+ files = import_node_fs33.default.readdirSync(hashDirAbs);
55006
55840
  } catch {
55007
55841
  continue;
55008
55842
  }
55009
55843
  for (const name of files) {
55010
- const file = import_node_path36.default.join(hashDirAbs, name);
55844
+ const file = import_node_path37.default.join(hashDirAbs, name);
55011
55845
  let stat;
55012
55846
  try {
55013
- stat = import_node_fs32.default.statSync(file);
55847
+ stat = import_node_fs33.default.statSync(file);
55014
55848
  } catch {
55015
55849
  continue;
55016
55850
  }
@@ -55019,27 +55853,27 @@ function runAttachmentGc(args) {
55019
55853
  if (age < ttlMs) continue;
55020
55854
  if (liveAbs.has(file)) continue;
55021
55855
  try {
55022
- import_node_fs32.default.unlinkSync(file);
55856
+ import_node_fs33.default.unlinkSync(file);
55023
55857
  } catch (err) {
55024
55858
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
55025
55859
  }
55026
55860
  }
55027
55861
  try {
55028
- if (import_node_fs32.default.readdirSync(hashDirAbs).length === 0) import_node_fs32.default.rmdirSync(hashDirAbs);
55862
+ if (import_node_fs33.default.readdirSync(hashDirAbs).length === 0) import_node_fs33.default.rmdirSync(hashDirAbs);
55029
55863
  } catch {
55030
55864
  }
55031
55865
  }
55032
55866
  try {
55033
- if (import_node_fs32.default.readdirSync(attRoot).length === 0) import_node_fs32.default.rmdirSync(attRoot);
55867
+ if (import_node_fs33.default.readdirSync(attRoot).length === 0) import_node_fs33.default.rmdirSync(attRoot);
55034
55868
  } catch {
55035
55869
  }
55036
55870
  }
55037
55871
  }
55038
55872
 
55039
55873
  // src/attachment/group.ts
55040
- var import_node_fs33 = __toESM(require("fs"), 1);
55041
- var import_node_path37 = __toESM(require("path"), 1);
55042
- var import_node_crypto8 = __toESM(require("crypto"), 1);
55874
+ var import_node_fs34 = __toESM(require("fs"), 1);
55875
+ var import_node_path38 = __toESM(require("path"), 1);
55876
+ var import_node_crypto9 = __toESM(require("crypto"), 1);
55043
55877
  init_protocol();
55044
55878
  var GroupFileStore = class {
55045
55879
  dataDir;
@@ -55050,11 +55884,11 @@ var GroupFileStore = class {
55050
55884
  this.logger = opts.logger;
55051
55885
  }
55052
55886
  rootForScope(scope) {
55053
- return import_node_path37.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
55887
+ return import_node_path38.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
55054
55888
  }
55055
55889
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
55056
55890
  filePath(scope, sessionId) {
55057
- return import_node_path37.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
55891
+ return import_node_path38.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
55058
55892
  }
55059
55893
  cacheKey(scope, sessionId) {
55060
55894
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -55063,7 +55897,7 @@ var GroupFileStore = class {
55063
55897
  readFile(scope, sessionId) {
55064
55898
  const file = this.filePath(scope, sessionId);
55065
55899
  try {
55066
- const raw = import_node_fs33.default.readFileSync(file, "utf8");
55900
+ const raw = import_node_fs34.default.readFileSync(file, "utf8");
55067
55901
  const parsed = JSON.parse(raw);
55068
55902
  if (!Array.isArray(parsed)) {
55069
55903
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -55089,10 +55923,10 @@ var GroupFileStore = class {
55089
55923
  }
55090
55924
  writeFile(scope, sessionId, entries) {
55091
55925
  const file = this.filePath(scope, sessionId);
55092
- import_node_fs33.default.mkdirSync(import_node_path37.default.dirname(file), { recursive: true });
55926
+ import_node_fs34.default.mkdirSync(import_node_path38.default.dirname(file), { recursive: true });
55093
55927
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
55094
- import_node_fs33.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
55095
- import_node_fs33.default.renameSync(tmp, file);
55928
+ import_node_fs34.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
55929
+ import_node_fs34.default.renameSync(tmp, file);
55096
55930
  }
55097
55931
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
55098
55932
  list(scope, sessionId) {
@@ -55128,7 +55962,7 @@ var GroupFileStore = class {
55128
55962
  entries[idx] = next;
55129
55963
  } else {
55130
55964
  next = {
55131
- id: `gf-${import_node_crypto8.default.randomBytes(6).toString("base64url")}`,
55965
+ id: `gf-${import_node_crypto9.default.randomBytes(6).toString("base64url")}`,
55132
55966
  relPath: input.relPath,
55133
55967
  from: input.from,
55134
55968
  label: input.label,
@@ -55178,10 +56012,10 @@ var GroupFileStore = class {
55178
56012
  };
55179
56013
 
55180
56014
  // src/discovery/state-file.ts
55181
- var import_node_fs34 = __toESM(require("fs"), 1);
55182
- var import_node_path38 = __toESM(require("path"), 1);
56015
+ var import_node_fs35 = __toESM(require("fs"), 1);
56016
+ var import_node_path39 = __toESM(require("path"), 1);
55183
56017
  function defaultStateFilePath(dataDir) {
55184
- return import_node_path38.default.join(dataDir, "state.json");
56018
+ return import_node_path39.default.join(dataDir, "state.json");
55185
56019
  }
55186
56020
  function isPidAlive(pid) {
55187
56021
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -55203,7 +56037,7 @@ var StateFileManager = class {
55203
56037
  }
55204
56038
  read() {
55205
56039
  try {
55206
- const raw = import_node_fs34.default.readFileSync(this.file, "utf8");
56040
+ const raw = import_node_fs35.default.readFileSync(this.file, "utf8");
55207
56041
  const parsed = JSON.parse(raw);
55208
56042
  return parsed;
55209
56043
  } catch {
@@ -55217,20 +56051,20 @@ var StateFileManager = class {
55217
56051
  return { status: "stale", existing };
55218
56052
  }
55219
56053
  write(state) {
55220
- import_node_fs34.default.mkdirSync(import_node_path38.default.dirname(this.file), { recursive: true });
56054
+ import_node_fs35.default.mkdirSync(import_node_path39.default.dirname(this.file), { recursive: true });
55221
56055
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
55222
- import_node_fs34.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
55223
- import_node_fs34.default.renameSync(tmp, this.file);
56056
+ import_node_fs35.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
56057
+ import_node_fs35.default.renameSync(tmp, this.file);
55224
56058
  if (process.platform !== "win32") {
55225
56059
  try {
55226
- import_node_fs34.default.chmodSync(this.file, 384);
56060
+ import_node_fs35.default.chmodSync(this.file, 384);
55227
56061
  } catch {
55228
56062
  }
55229
56063
  }
55230
56064
  }
55231
56065
  delete() {
55232
56066
  try {
55233
- import_node_fs34.default.unlinkSync(this.file);
56067
+ import_node_fs35.default.unlinkSync(this.file);
55234
56068
  } catch {
55235
56069
  }
55236
56070
  }
@@ -55244,14 +56078,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
55244
56078
  }
55245
56079
 
55246
56080
  // src/tunnel/tunnel-manager.ts
55247
- var import_node_fs38 = __toESM(require("fs"), 1);
55248
- var import_node_path42 = __toESM(require("path"), 1);
55249
- var import_node_crypto9 = __toESM(require("crypto"), 1);
56081
+ var import_node_fs39 = __toESM(require("fs"), 1);
56082
+ var import_node_path43 = __toESM(require("path"), 1);
56083
+ var import_node_crypto10 = __toESM(require("crypto"), 1);
55250
56084
  var import_node_child_process9 = require("child_process");
55251
56085
 
55252
56086
  // src/tunnel/tunnel-store.ts
55253
- var import_node_fs35 = __toESM(require("fs"), 1);
55254
- var import_node_path39 = __toESM(require("path"), 1);
56087
+ var import_node_fs36 = __toESM(require("fs"), 1);
56088
+ var import_node_path40 = __toESM(require("path"), 1);
55255
56089
  var TunnelStore = class {
55256
56090
  constructor(filePath) {
55257
56091
  this.filePath = filePath;
@@ -55259,7 +56093,7 @@ var TunnelStore = class {
55259
56093
  filePath;
55260
56094
  async get() {
55261
56095
  try {
55262
- const raw = await import_node_fs35.default.promises.readFile(this.filePath, "utf8");
56096
+ const raw = await import_node_fs36.default.promises.readFile(this.filePath, "utf8");
55263
56097
  const obj = JSON.parse(raw);
55264
56098
  if (!isPersistedTunnel(obj)) return null;
55265
56099
  return obj;
@@ -55270,22 +56104,22 @@ var TunnelStore = class {
55270
56104
  }
55271
56105
  }
55272
56106
  async set(v2) {
55273
- const dir = import_node_path39.default.dirname(this.filePath);
55274
- await import_node_fs35.default.promises.mkdir(dir, { recursive: true });
56107
+ const dir = import_node_path40.default.dirname(this.filePath);
56108
+ await import_node_fs36.default.promises.mkdir(dir, { recursive: true });
55275
56109
  const data = JSON.stringify(v2, null, 2);
55276
56110
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
55277
- await import_node_fs35.default.promises.writeFile(tmp, data, { mode: 384 });
56111
+ await import_node_fs36.default.promises.writeFile(tmp, data, { mode: 384 });
55278
56112
  if (process.platform !== "win32") {
55279
56113
  try {
55280
- await import_node_fs35.default.promises.chmod(tmp, 384);
56114
+ await import_node_fs36.default.promises.chmod(tmp, 384);
55281
56115
  } catch {
55282
56116
  }
55283
56117
  }
55284
- await import_node_fs35.default.promises.rename(tmp, this.filePath);
56118
+ await import_node_fs36.default.promises.rename(tmp, this.filePath);
55285
56119
  }
55286
56120
  async clear() {
55287
56121
  try {
55288
- await import_node_fs35.default.promises.unlink(this.filePath);
56122
+ await import_node_fs36.default.promises.unlink(this.filePath);
55289
56123
  } catch (err) {
55290
56124
  const code = err?.code;
55291
56125
  if (code !== "ENOENT") throw err;
@@ -55380,9 +56214,9 @@ function escape(v2) {
55380
56214
  }
55381
56215
 
55382
56216
  // src/tunnel/frpc-binary.ts
55383
- var import_node_fs36 = __toESM(require("fs"), 1);
56217
+ var import_node_fs37 = __toESM(require("fs"), 1);
55384
56218
  var import_node_os13 = __toESM(require("os"), 1);
55385
- var import_node_path40 = __toESM(require("path"), 1);
56219
+ var import_node_path41 = __toESM(require("path"), 1);
55386
56220
  var import_node_child_process7 = require("child_process");
55387
56221
  var import_node_stream3 = require("stream");
55388
56222
  var import_promises5 = require("stream/promises");
@@ -55414,20 +56248,20 @@ function frpcDownloadUrl(version2, p2) {
55414
56248
  }
55415
56249
  async function ensureFrpcBinary(opts) {
55416
56250
  if (opts.override) {
55417
- if (!import_node_fs36.default.existsSync(opts.override)) {
56251
+ if (!import_node_fs37.default.existsSync(opts.override)) {
55418
56252
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
55419
56253
  }
55420
56254
  return opts.override;
55421
56255
  }
55422
56256
  const version2 = opts.version ?? FRPC_VERSION;
55423
56257
  const platform = opts.platform ?? detectPlatform();
55424
- const binDir = import_node_path40.default.join(opts.dataDir, "bin");
55425
- import_node_fs36.default.mkdirSync(binDir, { recursive: true });
56258
+ const binDir = import_node_path41.default.join(opts.dataDir, "bin");
56259
+ import_node_fs37.default.mkdirSync(binDir, { recursive: true });
55426
56260
  cleanupStaleArtifacts(binDir);
55427
- const stableBin = import_node_path40.default.join(binDir, "frpc");
55428
- if (import_node_fs36.default.existsSync(stableBin)) return stableBin;
56261
+ const stableBin = import_node_path41.default.join(binDir, "frpc");
56262
+ if (import_node_fs37.default.existsSync(stableBin)) return stableBin;
55429
56263
  const partialBin = `${stableBin}.partial`;
55430
- const tarballPath = import_node_path40.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
56264
+ const tarballPath = import_node_path41.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
55431
56265
  try {
55432
56266
  const url = frpcDownloadUrl(version2, platform);
55433
56267
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -55436,8 +56270,8 @@ async function ensureFrpcBinary(opts) {
55436
56270
  } else {
55437
56271
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
55438
56272
  }
55439
- import_node_fs36.default.chmodSync(partialBin, 493);
55440
- import_node_fs36.default.renameSync(partialBin, stableBin);
56273
+ import_node_fs37.default.chmodSync(partialBin, 493);
56274
+ import_node_fs37.default.renameSync(partialBin, stableBin);
55441
56275
  } finally {
55442
56276
  safeUnlink(tarballPath);
55443
56277
  safeUnlink(partialBin);
@@ -55447,15 +56281,15 @@ async function ensureFrpcBinary(opts) {
55447
56281
  function cleanupStaleArtifacts(binDir) {
55448
56282
  let entries;
55449
56283
  try {
55450
- entries = import_node_fs36.default.readdirSync(binDir);
56284
+ entries = import_node_fs37.default.readdirSync(binDir);
55451
56285
  } catch {
55452
56286
  return;
55453
56287
  }
55454
56288
  for (const name of entries) {
55455
56289
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
55456
- const full = import_node_path40.default.join(binDir, name);
56290
+ const full = import_node_path41.default.join(binDir, name);
55457
56291
  try {
55458
- import_node_fs36.default.rmSync(full, { recursive: true, force: true });
56292
+ import_node_fs37.default.rmSync(full, { recursive: true, force: true });
55459
56293
  } catch {
55460
56294
  }
55461
56295
  }
@@ -55463,7 +56297,7 @@ function cleanupStaleArtifacts(binDir) {
55463
56297
  }
55464
56298
  function safeUnlink(p2) {
55465
56299
  try {
55466
- import_node_fs36.default.unlinkSync(p2);
56300
+ import_node_fs37.default.unlinkSync(p2);
55467
56301
  } catch {
55468
56302
  }
55469
56303
  }
@@ -55474,13 +56308,13 @@ async function downloadToFile(url, dest, fetchImpl) {
55474
56308
  if (!res.ok || !res.body) {
55475
56309
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
55476
56310
  }
55477
- const out = import_node_fs36.default.createWriteStream(dest);
56311
+ const out = import_node_fs37.default.createWriteStream(dest);
55478
56312
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
55479
56313
  await (0, import_promises5.pipeline)(nodeStream, out);
55480
56314
  }
55481
56315
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
55482
- const work = import_node_path40.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
55483
- import_node_fs36.default.mkdirSync(work, { recursive: true });
56316
+ const work = import_node_path41.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
56317
+ import_node_fs37.default.mkdirSync(work, { recursive: true });
55484
56318
  try {
55485
56319
  await new Promise((resolve6, reject) => {
55486
56320
  const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -55488,32 +56322,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
55488
56322
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
55489
56323
  });
55490
56324
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
55491
- const src = import_node_path40.default.join(work, dirName, "frpc");
55492
- if (!import_node_fs36.default.existsSync(src)) {
56325
+ const src = import_node_path41.default.join(work, dirName, "frpc");
56326
+ if (!import_node_fs37.default.existsSync(src)) {
55493
56327
  throw new Error(`frpc not found inside tarball at ${src}`);
55494
56328
  }
55495
- import_node_fs36.default.copyFileSync(src, destBin);
56329
+ import_node_fs37.default.copyFileSync(src, destBin);
55496
56330
  } finally {
55497
- import_node_fs36.default.rmSync(work, { recursive: true, force: true });
56331
+ import_node_fs37.default.rmSync(work, { recursive: true, force: true });
55498
56332
  }
55499
56333
  }
55500
56334
 
55501
56335
  // src/tunnel/frpc-process.ts
55502
- var import_node_fs37 = __toESM(require("fs"), 1);
55503
- var import_node_path41 = __toESM(require("path"), 1);
56336
+ var import_node_fs38 = __toESM(require("fs"), 1);
56337
+ var import_node_path42 = __toESM(require("path"), 1);
55504
56338
  var import_node_child_process8 = require("child_process");
55505
56339
  function frpcPidFilePath(dataDir) {
55506
- return import_node_path41.default.join(dataDir, "frpc.pid");
56340
+ return import_node_path42.default.join(dataDir, "frpc.pid");
55507
56341
  }
55508
56342
  function writeFrpcPid(dataDir, pid) {
55509
56343
  try {
55510
- import_node_fs37.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
56344
+ import_node_fs38.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
55511
56345
  } catch {
55512
56346
  }
55513
56347
  }
55514
56348
  function clearFrpcPid(dataDir) {
55515
56349
  try {
55516
- import_node_fs37.default.unlinkSync(frpcPidFilePath(dataDir));
56350
+ import_node_fs38.default.unlinkSync(frpcPidFilePath(dataDir));
55517
56351
  } catch {
55518
56352
  }
55519
56353
  }
@@ -55529,7 +56363,7 @@ function defaultIsPidAlive(pid) {
55529
56363
  }
55530
56364
  function defaultReadPidFile(file) {
55531
56365
  try {
55532
- return import_node_fs37.default.readFileSync(file, "utf8");
56366
+ return import_node_fs38.default.readFileSync(file, "utf8");
55533
56367
  } catch {
55534
56368
  return null;
55535
56369
  }
@@ -55545,7 +56379,7 @@ function defaultSleep2(ms) {
55545
56379
  }
55546
56380
  async function killStaleFrpc(deps) {
55547
56381
  const pidFile = frpcPidFilePath(deps.dataDir);
55548
- const tomlPath = import_node_path41.default.join(deps.dataDir, "frpc.toml");
56382
+ const tomlPath = import_node_path42.default.join(deps.dataDir, "frpc.toml");
55549
56383
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
55550
56384
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
55551
56385
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -55569,7 +56403,7 @@ async function killStaleFrpc(deps) {
55569
56403
  }
55570
56404
  if (victims.size === 0) {
55571
56405
  try {
55572
- import_node_fs37.default.unlinkSync(pidFile);
56406
+ import_node_fs38.default.unlinkSync(pidFile);
55573
56407
  } catch {
55574
56408
  }
55575
56409
  return;
@@ -55580,7 +56414,7 @@ async function killStaleFrpc(deps) {
55580
56414
  }
55581
56415
  await sleep2(deps.reapWaitMs ?? 300);
55582
56416
  try {
55583
- import_node_fs37.default.unlinkSync(pidFile);
56417
+ import_node_fs38.default.unlinkSync(pidFile);
55584
56418
  } catch {
55585
56419
  }
55586
56420
  }
@@ -55617,7 +56451,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
55617
56451
  var TunnelManager = class {
55618
56452
  constructor(deps) {
55619
56453
  this.deps = deps;
55620
- this.store = deps.store ?? new TunnelStore(import_node_path42.default.join(deps.dataDir, "tunnel.json"));
56454
+ this.store = deps.store ?? new TunnelStore(import_node_path43.default.join(deps.dataDir, "tunnel.json"));
55621
56455
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
55622
56456
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
55623
56457
  }
@@ -55744,8 +56578,8 @@ var TunnelManager = class {
55744
56578
  dataDir: this.deps.dataDir,
55745
56579
  override: this.deps.frpcBinaryOverride ?? void 0
55746
56580
  });
55747
- const tomlPath = import_node_path42.default.join(this.deps.dataDir, "frpc.toml");
55748
- const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto9.default.randomBytes(3).toString("hex")}`;
56581
+ const tomlPath = import_node_path43.default.join(this.deps.dataDir, "frpc.toml");
56582
+ const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
55749
56583
  const toml = buildFrpcToml({
55750
56584
  serverAddr: t.frpsHost,
55751
56585
  serverPort: t.frpsPort,
@@ -55755,14 +56589,14 @@ var TunnelManager = class {
55755
56589
  localPort,
55756
56590
  logLevel: "info"
55757
56591
  });
55758
- await import_node_fs38.default.promises.writeFile(tomlPath, toml, { mode: 384 });
56592
+ await import_node_fs39.default.promises.writeFile(tomlPath, toml, { mode: 384 });
55759
56593
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
55760
56594
  stdio: ["ignore", "pipe", "pipe"]
55761
56595
  });
55762
- const logDir = import_node_path42.default.join(this.deps.dataDir, "log");
55763
- import_node_fs38.default.mkdirSync(logDir, { recursive: true });
55764
- const logFilePath = import_node_path42.default.join(logDir, "frpc.log");
55765
- const logStream = import_node_fs38.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
56596
+ const logDir = import_node_path43.default.join(this.deps.dataDir, "log");
56597
+ import_node_fs39.default.mkdirSync(logDir, { recursive: true });
56598
+ const logFilePath = import_node_path43.default.join(logDir, "frpc.log");
56599
+ const logStream = import_node_fs39.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
55766
56600
  logStream.on("error", () => {
55767
56601
  });
55768
56602
  const tee = (chunk) => {
@@ -55845,27 +56679,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
55845
56679
 
55846
56680
  // src/tunnel/device-key.ts
55847
56681
  var import_node_os14 = __toESM(require("os"), 1);
55848
- var import_node_path43 = __toESM(require("path"), 1);
55849
- var import_node_crypto10 = __toESM(require("crypto"), 1);
56682
+ var import_node_path44 = __toESM(require("path"), 1);
56683
+ var import_node_crypto11 = __toESM(require("crypto"), 1);
55850
56684
  var DERIVE_SALT = "clawd-tunnel-device-v1";
55851
56685
  function deriveStableDeviceKey(opts = {}) {
55852
56686
  const hostname = opts.hostname ?? import_node_os14.default.hostname();
55853
56687
  const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
55854
56688
  const home = opts.home ?? import_node_os14.default.homedir();
55855
- const defaultDataDir = import_node_path43.default.resolve(import_node_path43.default.join(home, ".clawd"));
55856
- const normalizedDataDir = opts.dataDir ? import_node_path43.default.resolve(opts.dataDir) : null;
56689
+ const defaultDataDir = import_node_path44.default.resolve(import_node_path44.default.join(home, ".clawd"));
56690
+ const normalizedDataDir = opts.dataDir ? import_node_path44.default.resolve(opts.dataDir) : null;
55857
56691
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
55858
56692
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
55859
- return import_node_crypto10.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
56693
+ return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
55860
56694
  }
55861
56695
 
55862
56696
  // src/auth-store.ts
55863
- var import_node_fs39 = __toESM(require("fs"), 1);
55864
- var import_node_path44 = __toESM(require("path"), 1);
55865
- var import_node_crypto11 = __toESM(require("crypto"), 1);
56697
+ var import_node_fs40 = __toESM(require("fs"), 1);
56698
+ var import_node_path45 = __toESM(require("path"), 1);
56699
+ var import_node_crypto12 = __toESM(require("crypto"), 1);
55866
56700
  var AUTH_FILE_NAME = "auth.json";
55867
56701
  function authFilePath(dataDir) {
55868
- return import_node_path44.default.join(dataDir, AUTH_FILE_NAME);
56702
+ return import_node_path45.default.join(dataDir, AUTH_FILE_NAME);
55869
56703
  }
55870
56704
  function loadOrCreateAuthFile(opts) {
55871
56705
  const file = authFilePath(opts.dataDir);
@@ -55890,14 +56724,14 @@ function loadOrCreateAuthFile(opts) {
55890
56724
  return next;
55891
56725
  }
55892
56726
  function defaultGenerateToken() {
55893
- return import_node_crypto11.default.randomBytes(32).toString("base64url");
56727
+ return import_node_crypto12.default.randomBytes(32).toString("base64url");
55894
56728
  }
55895
56729
  function defaultGenerateOwnerPrincipalId() {
55896
- return `owner-${import_node_crypto11.default.randomUUID()}`;
56730
+ return `owner-${import_node_crypto12.default.randomUUID()}`;
55897
56731
  }
55898
56732
  function readAuthFile(file) {
55899
56733
  try {
55900
- const raw = import_node_fs39.default.readFileSync(file, "utf8");
56734
+ const raw = import_node_fs40.default.readFileSync(file, "utf8");
55901
56735
  const parsed = JSON.parse(raw);
55902
56736
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
55903
56737
  return null;
@@ -55917,25 +56751,25 @@ function readAuthFile(file) {
55917
56751
  }
55918
56752
  }
55919
56753
  function writeAuthFile(file, content) {
55920
- import_node_fs39.default.mkdirSync(import_node_path44.default.dirname(file), { recursive: true });
55921
- import_node_fs39.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
56754
+ import_node_fs40.default.mkdirSync(import_node_path45.default.dirname(file), { recursive: true });
56755
+ import_node_fs40.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
55922
56756
  try {
55923
- import_node_fs39.default.chmodSync(file, 384);
56757
+ import_node_fs40.default.chmodSync(file, 384);
55924
56758
  } catch {
55925
56759
  }
55926
56760
  }
55927
56761
 
55928
56762
  // src/owner-profile.ts
55929
- var import_node_fs40 = __toESM(require("fs"), 1);
56763
+ var import_node_fs41 = __toESM(require("fs"), 1);
55930
56764
  var import_node_os15 = __toESM(require("os"), 1);
55931
- var import_node_path45 = __toESM(require("path"), 1);
56765
+ var import_node_path46 = __toESM(require("path"), 1);
55932
56766
  var PROFILE_FILENAME = "profile.json";
55933
56767
  function loadOwnerDisplayName(dataDir) {
55934
56768
  const fallback = import_node_os15.default.userInfo().username;
55935
- const profilePath = import_node_path45.default.join(dataDir, PROFILE_FILENAME);
56769
+ const profilePath = import_node_path46.default.join(dataDir, PROFILE_FILENAME);
55936
56770
  let raw;
55937
56771
  try {
55938
- raw = import_node_fs40.default.readFileSync(profilePath, "utf8");
56772
+ raw = import_node_fs41.default.readFileSync(profilePath, "utf8");
55939
56773
  } catch {
55940
56774
  return fallback;
55941
56775
  }
@@ -55958,18 +56792,18 @@ function loadOwnerDisplayName(dataDir) {
55958
56792
  }
55959
56793
 
55960
56794
  // src/feishu-auth/owner-identity-store.ts
55961
- var import_node_fs41 = __toESM(require("fs"), 1);
55962
- var import_node_path46 = __toESM(require("path"), 1);
56795
+ var import_node_fs42 = __toESM(require("fs"), 1);
56796
+ var import_node_path47 = __toESM(require("path"), 1);
55963
56797
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
55964
56798
  var OwnerIdentityStore = class {
55965
56799
  file;
55966
56800
  constructor(dataDir) {
55967
- this.file = import_node_path46.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
56801
+ this.file = import_node_path47.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
55968
56802
  }
55969
56803
  read() {
55970
56804
  let raw;
55971
56805
  try {
55972
- raw = import_node_fs41.default.readFileSync(this.file, "utf8");
56806
+ raw = import_node_fs42.default.readFileSync(this.file, "utf8");
55973
56807
  } catch {
55974
56808
  return null;
55975
56809
  }
@@ -55997,16 +56831,16 @@ var OwnerIdentityStore = class {
55997
56831
  };
55998
56832
  }
55999
56833
  write(record) {
56000
- import_node_fs41.default.mkdirSync(import_node_path46.default.dirname(this.file), { recursive: true });
56001
- import_node_fs41.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
56834
+ import_node_fs42.default.mkdirSync(import_node_path47.default.dirname(this.file), { recursive: true });
56835
+ import_node_fs42.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
56002
56836
  try {
56003
- import_node_fs41.default.chmodSync(this.file, 384);
56837
+ import_node_fs42.default.chmodSync(this.file, 384);
56004
56838
  } catch {
56005
56839
  }
56006
56840
  }
56007
56841
  clear() {
56008
56842
  try {
56009
- import_node_fs41.default.unlinkSync(this.file);
56843
+ import_node_fs42.default.unlinkSync(this.file);
56010
56844
  } catch (err) {
56011
56845
  const code = err?.code;
56012
56846
  if (code !== "ENOENT") throw err;
@@ -56015,7 +56849,7 @@ var OwnerIdentityStore = class {
56015
56849
  };
56016
56850
 
56017
56851
  // src/feishu-auth/login-flow.ts
56018
- var import_node_crypto12 = __toESM(require("crypto"), 1);
56852
+ var import_node_crypto13 = __toESM(require("crypto"), 1);
56019
56853
  var STATE_TTL_MS = 5 * 60 * 1e3;
56020
56854
  var LoginFlow = class {
56021
56855
  constructor(deps) {
@@ -56024,7 +56858,7 @@ var LoginFlow = class {
56024
56858
  deps;
56025
56859
  pendingStates = /* @__PURE__ */ new Map();
56026
56860
  start() {
56027
- const state = import_node_crypto12.default.randomBytes(16).toString("base64url");
56861
+ const state = import_node_crypto13.default.randomBytes(16).toString("base64url");
56028
56862
  const now = (this.deps.now ?? Date.now)();
56029
56863
  this.pendingStates.set(state, now);
56030
56864
  this.gcExpired(now);
@@ -56143,9 +56977,9 @@ var CentralClientError = class extends Error {
56143
56977
  code;
56144
56978
  cause;
56145
56979
  };
56146
- async function centralRequest(opts, path77, init) {
56980
+ async function centralRequest(opts, path78, init) {
56147
56981
  const f = opts.fetchImpl ?? globalThis.fetch;
56148
- const url = `${opts.api.replace(/\/+$/, "")}${path77}`;
56982
+ const url = `${opts.api.replace(/\/+$/, "")}${path78}`;
56149
56983
  const ctrl = new AbortController();
56150
56984
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
56151
56985
  let res;
@@ -56248,11 +57082,11 @@ var DeviceBindingClientError = class extends Error {
56248
57082
  code;
56249
57083
  cause;
56250
57084
  };
56251
- var DEFAULT_TIMEOUT_MS2 = 8e3;
57085
+ var DEFAULT_TIMEOUT_MS3 = 8e3;
56252
57086
  async function upsertDeviceBinding(opts) {
56253
57087
  const doFetch = opts.fetchImpl ?? fetch;
56254
57088
  const ac = new AbortController();
56255
- const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2);
57089
+ const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3);
56256
57090
  const body = { unionId: opts.unionId };
56257
57091
  if (opts.avatarUrl != null) body.avatarUrl = opts.avatarUrl;
56258
57092
  let res;
@@ -56339,8 +57173,8 @@ function verifyConnectToken(args) {
56339
57173
  }
56340
57174
 
56341
57175
  // src/feishu-auth/server-key.ts
56342
- var fs51 = __toESM(require("fs"), 1);
56343
- var path55 = __toESM(require("path"), 1);
57176
+ var fs52 = __toESM(require("fs"), 1);
57177
+ var path56 = __toESM(require("path"), 1);
56344
57178
  var FILE_NAME2 = "server-signing-key.json";
56345
57179
  var ServerKeyStore = class {
56346
57180
  constructor(dataDir) {
@@ -56348,12 +57182,12 @@ var ServerKeyStore = class {
56348
57182
  }
56349
57183
  dataDir;
56350
57184
  filePath() {
56351
- return path55.join(this.dataDir, FILE_NAME2);
57185
+ return path56.join(this.dataDir, FILE_NAME2);
56352
57186
  }
56353
57187
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
56354
57188
  read() {
56355
57189
  try {
56356
- const raw = fs51.readFileSync(this.filePath(), "utf8");
57190
+ const raw = fs52.readFileSync(this.filePath(), "utf8");
56357
57191
  const parsed = JSON.parse(raw);
56358
57192
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
56359
57193
  return parsed.publicKeyPem;
@@ -56368,12 +57202,12 @@ var ServerKeyStore = class {
56368
57202
  publicKeyPem,
56369
57203
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
56370
57204
  };
56371
- fs51.mkdirSync(this.dataDir, { recursive: true });
56372
- fs51.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
57205
+ fs52.mkdirSync(this.dataDir, { recursive: true });
57206
+ fs52.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
56373
57207
  }
56374
57208
  clear() {
56375
57209
  try {
56376
- fs51.unlinkSync(this.filePath());
57210
+ fs52.unlinkSync(this.filePath());
56377
57211
  } catch {
56378
57212
  }
56379
57213
  }
@@ -56386,12 +57220,12 @@ init_protocol();
56386
57220
  init_protocol();
56387
57221
 
56388
57222
  // src/session/fork.ts
56389
- var import_node_fs42 = __toESM(require("fs"), 1);
57223
+ var import_node_fs43 = __toESM(require("fs"), 1);
56390
57224
  var import_node_os16 = __toESM(require("os"), 1);
56391
- var import_node_path47 = __toESM(require("path"), 1);
57225
+ var import_node_path48 = __toESM(require("path"), 1);
56392
57226
  init_claude_history();
56393
57227
  function readJsonlEntries(file) {
56394
- const raw = import_node_fs42.default.readFileSync(file, "utf8");
57228
+ const raw = import_node_fs43.default.readFileSync(file, "utf8");
56395
57229
  const out = [];
56396
57230
  for (const line of raw.split("\n")) {
56397
57231
  const t = line.trim();
@@ -56404,19 +57238,19 @@ function readJsonlEntries(file) {
56404
57238
  return out;
56405
57239
  }
56406
57240
  function forkSession(input) {
56407
- const baseDir = input.baseDir ?? import_node_path47.default.join(import_node_os16.default.homedir(), ".claude");
56408
- let projectDir = import_node_path47.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
56409
- let sourceFile = import_node_path47.default.join(projectDir, `${input.toolSessionId}.jsonl`);
56410
- if (!import_node_fs42.default.existsSync(sourceFile)) {
57241
+ const baseDir = input.baseDir ?? import_node_path48.default.join(import_node_os16.default.homedir(), ".claude");
57242
+ let projectDir = import_node_path48.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
57243
+ let sourceFile = import_node_path48.default.join(projectDir, `${input.toolSessionId}.jsonl`);
57244
+ if (!import_node_fs43.default.existsSync(sourceFile)) {
56411
57245
  const found = findTranscriptByToolSessionId(
56412
- import_node_path47.default.join(baseDir, "projects"),
57246
+ import_node_path48.default.join(baseDir, "projects"),
56413
57247
  input.toolSessionId
56414
57248
  );
56415
57249
  if (!found) {
56416
57250
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
56417
57251
  }
56418
57252
  sourceFile = found;
56419
- projectDir = import_node_path47.default.dirname(found);
57253
+ projectDir = import_node_path48.default.dirname(found);
56420
57254
  }
56421
57255
  const entries = readJsonlEntries(sourceFile);
56422
57256
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -56445,9 +57279,9 @@ function forkSession(input) {
56445
57279
  }
56446
57280
  forkedLines.push(JSON.stringify(forked));
56447
57281
  }
56448
- const forkedFilePath = import_node_path47.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
56449
- import_node_fs42.default.mkdirSync(projectDir, { recursive: true });
56450
- import_node_fs42.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
57282
+ const forkedFilePath = import_node_path48.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
57283
+ import_node_fs43.default.mkdirSync(projectDir, { recursive: true });
57284
+ import_node_fs43.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
56451
57285
  return { forkedToolSessionId, forkedFilePath };
56452
57286
  }
56453
57287
 
@@ -56890,7 +57724,7 @@ function buildPermissionHandlers(deps) {
56890
57724
  }
56891
57725
 
56892
57726
  // src/handlers/history.ts
56893
- var path58 = __toESM(require("path"), 1);
57727
+ var path59 = __toESM(require("path"), 1);
56894
57728
  init_protocol();
56895
57729
 
56896
57730
  // src/session/recent-dirs.ts
@@ -56908,7 +57742,7 @@ function listRecentDirs(store, limit = 50) {
56908
57742
  }
56909
57743
 
56910
57744
  // src/permission/persona-paths.ts
56911
- var path57 = __toESM(require("path"), 1);
57745
+ var path58 = __toESM(require("path"), 1);
56912
57746
  function getAllowedPersonaIds(grants, action) {
56913
57747
  const ids = /* @__PURE__ */ new Set();
56914
57748
  for (const g2 of grants) {
@@ -56921,42 +57755,42 @@ function getAllowedPersonaIds(grants, action) {
56921
57755
  return ids;
56922
57756
  }
56923
57757
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
56924
- const target = path57.resolve(absPath);
57758
+ const target = path58.resolve(absPath);
56925
57759
  if (userWorkDir) {
56926
- const u = path57.resolve(userWorkDir);
56927
- const usep = u.endsWith(path57.sep) ? "" : path57.sep;
57760
+ const u = path58.resolve(userWorkDir);
57761
+ const usep = u.endsWith(path58.sep) ? "" : path58.sep;
56928
57762
  if (target === u || target.startsWith(u + usep)) return true;
56929
57763
  }
56930
- const root = path57.resolve(personaRoot);
56931
- const sep3 = root.endsWith(path57.sep) ? "" : path57.sep;
57764
+ const root = path58.resolve(personaRoot);
57765
+ const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
56932
57766
  if (!target.startsWith(root + sep3)) return false;
56933
- const rel = path57.relative(root, target);
57767
+ const rel = path58.relative(root, target);
56934
57768
  if (!rel || rel.startsWith("..")) return false;
56935
- const personaId2 = rel.split(path57.sep)[0];
57769
+ const personaId2 = rel.split(path58.sep)[0];
56936
57770
  if (!personaId2) return false;
56937
57771
  const allowed = getAllowedPersonaIds(grants, action);
56938
57772
  if (allowed === "*") return true;
56939
57773
  return allowed.has(personaId2);
56940
57774
  }
56941
57775
  function personaIdFromPath(absPath, personaRoot) {
56942
- const root = path57.resolve(personaRoot);
56943
- const target = path57.resolve(absPath);
56944
- const sep3 = root.endsWith(path57.sep) ? "" : path57.sep;
57776
+ const root = path58.resolve(personaRoot);
57777
+ const target = path58.resolve(absPath);
57778
+ const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
56945
57779
  if (!target.startsWith(root + sep3)) return null;
56946
- const rel = path57.relative(root, target);
57780
+ const rel = path58.relative(root, target);
56947
57781
  if (!rel || rel.startsWith("..")) return null;
56948
- const id = rel.split(path57.sep)[0];
57782
+ const id = rel.split(path58.sep)[0];
56949
57783
  return id || null;
56950
57784
  }
56951
57785
  function isPathWithin(dir, absPath) {
56952
- const d = path57.resolve(dir);
56953
- const t = path57.resolve(absPath);
56954
- const sep3 = d.endsWith(path57.sep) ? "" : path57.sep;
57786
+ const d = path58.resolve(dir);
57787
+ const t = path58.resolve(absPath);
57788
+ const sep3 = d.endsWith(path58.sep) ? "" : path58.sep;
56955
57789
  return t === d || t.startsWith(d + sep3);
56956
57790
  }
56957
57791
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
56958
57792
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
56959
- return personaIdFromPath(path57.resolve(absPath), personaRoot) === personaId2;
57793
+ return personaIdFromPath(path58.resolve(absPath), personaRoot) === personaId2;
56960
57794
  }
56961
57795
 
56962
57796
  // src/handlers/history.ts
@@ -57008,7 +57842,7 @@ function buildHistoryHandlers(deps) {
57008
57842
  if (!pid) return false;
57009
57843
  return isGuestPathAllowed(
57010
57844
  ctx.grants,
57011
- path58.join(personaRoot, pid),
57845
+ path59.join(personaRoot, pid),
57012
57846
  personaRoot,
57013
57847
  "read",
57014
57848
  userWorkDir
@@ -57020,7 +57854,7 @@ function buildHistoryHandlers(deps) {
57020
57854
  };
57021
57855
  const list = async (frame, _client, ctx) => {
57022
57856
  const args = HistoryListArgs.parse(frame);
57023
- assertGuestPath(ctx, path58.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
57857
+ assertGuestPath(ctx, path59.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
57024
57858
  const sessions = await history.listSessions(args);
57025
57859
  return { response: { type: "history:list", sessions } };
57026
57860
  };
@@ -57053,13 +57887,13 @@ function buildHistoryHandlers(deps) {
57053
57887
  };
57054
57888
  const subagents = async (frame, _client, ctx) => {
57055
57889
  const args = HistorySubagentsArgs.parse(frame);
57056
- assertGuestPath(ctx, path58.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
57890
+ assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
57057
57891
  const subs = await history.listSubagents(args);
57058
57892
  return { response: { type: "history:subagents", subagents: subs } };
57059
57893
  };
57060
57894
  const subagentRead = async (frame, _client, ctx) => {
57061
57895
  const args = HistorySubagentReadArgs.parse(frame);
57062
- assertGuestPath(ctx, path58.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
57896
+ assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
57063
57897
  const res = await history.readSubagent(args);
57064
57898
  return { response: { type: "history:subagent-read", ...res } };
57065
57899
  };
@@ -57068,7 +57902,7 @@ function buildHistoryHandlers(deps) {
57068
57902
  if (ctx?.principal.kind === "guest" && personaRoot) {
57069
57903
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
57070
57904
  const filtered = dirs.filter(
57071
- (d) => isGuestPathAllowed(ctx.grants, path58.resolve(d.cwd), personaRoot, "read", userWorkDir)
57905
+ (d) => isGuestPathAllowed(ctx.grants, path59.resolve(d.cwd), personaRoot, "read", userWorkDir)
57072
57906
  );
57073
57907
  return { response: { type: "history:recentDirs", dirs: filtered } };
57074
57908
  }
@@ -57085,7 +57919,7 @@ function buildHistoryHandlers(deps) {
57085
57919
  }
57086
57920
 
57087
57921
  // src/handlers/workspace.ts
57088
- var path59 = __toESM(require("path"), 1);
57922
+ var path60 = __toESM(require("path"), 1);
57089
57923
  var os16 = __toESM(require("os"), 1);
57090
57924
  init_protocol();
57091
57925
  init_protocol();
@@ -57127,22 +57961,22 @@ function buildWorkspaceHandlers(deps) {
57127
57961
  const args = WorkspaceListArgs.parse(frame);
57128
57962
  const isGuest = ctx?.principal.kind === "guest";
57129
57963
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
57130
- const resolvedCwd = path59.resolve(args.cwd ?? fallbackCwd);
57131
- const target = args.path ? path59.resolve(resolvedCwd, args.path) : resolvedCwd;
57964
+ const resolvedCwd = path60.resolve(args.cwd ?? fallbackCwd);
57965
+ const target = args.path ? path60.resolve(resolvedCwd, args.path) : resolvedCwd;
57132
57966
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
57133
57967
  const res = workspace.list({ ...args, cwd: resolvedCwd });
57134
57968
  return { response: { type: "workspace:list", ...res } };
57135
57969
  };
57136
57970
  const read = async (frame, _client, ctx) => {
57137
57971
  const args = WorkspaceReadArgs.parse(frame);
57138
- const target = path59.isAbsolute(args.path) ? path59.resolve(args.path) : path59.resolve(args.cwd, args.path);
57972
+ const target = path60.isAbsolute(args.path) ? path60.resolve(args.path) : path60.resolve(args.cwd, args.path);
57139
57973
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
57140
57974
  const res = workspace.read(args);
57141
57975
  return { response: { type: "workspace:read", ...res } };
57142
57976
  };
57143
57977
  const skillsList = async (frame, _client, ctx) => {
57144
57978
  const args = SkillsListArgs.parse(frame);
57145
- const cwdAbs = path59.resolve(args.cwd);
57979
+ const cwdAbs = path60.resolve(args.cwd);
57146
57980
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
57147
57981
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
57148
57982
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -57154,7 +57988,7 @@ function buildWorkspaceHandlers(deps) {
57154
57988
  };
57155
57989
  const agentsList = async (frame, _client, ctx) => {
57156
57990
  const args = AgentsListArgs.parse(frame);
57157
- const cwdAbs = path59.resolve(args.cwd);
57991
+ const cwdAbs = path60.resolve(args.cwd);
57158
57992
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
57159
57993
  if (args.tool === "codex") {
57160
57994
  return { response: { type: "agents:list", agents: [] } };
@@ -57176,20 +58010,20 @@ function buildWorkspaceHandlers(deps) {
57176
58010
  }
57177
58011
 
57178
58012
  // src/handlers/git.ts
57179
- var path61 = __toESM(require("path"), 1);
58013
+ var path62 = __toESM(require("path"), 1);
57180
58014
  init_protocol();
57181
58015
  init_protocol();
57182
58016
 
57183
58017
  // src/workspace/git.ts
57184
58018
  var import_node_child_process10 = require("child_process");
57185
- var import_node_fs43 = __toESM(require("fs"), 1);
57186
- var import_node_path48 = __toESM(require("path"), 1);
58019
+ var import_node_fs44 = __toESM(require("fs"), 1);
58020
+ var import_node_path49 = __toESM(require("path"), 1);
57187
58021
  var import_node_util = require("util");
57188
58022
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
57189
58023
  function normalizePath(p2) {
57190
- const resolved = import_node_path48.default.resolve(p2);
58024
+ const resolved = import_node_path49.default.resolve(p2);
57191
58025
  try {
57192
- return import_node_fs43.default.realpathSync(resolved);
58026
+ return import_node_fs44.default.realpathSync(resolved);
57193
58027
  } catch {
57194
58028
  return resolved;
57195
58029
  }
@@ -57263,7 +58097,7 @@ async function listGitBranches(cwd) {
57263
58097
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
57264
58098
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
57265
58099
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
57266
- if (!isGuestPathAllowed(ctx.grants, path61.resolve(cwd), personaRoot, "read", userWorkDir)) {
58100
+ if (!isGuestPathAllowed(ctx.grants, path62.resolve(cwd), personaRoot, "read", userWorkDir)) {
57267
58101
  throw new ClawdError(
57268
58102
  ERROR_CODES.UNAUTHORIZED,
57269
58103
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -57993,6 +58827,12 @@ var METHOD_GRANT_MAP = {
57993
58827
  "shift-internal:cancel": ADMIN_ANY,
57994
58828
  "shift-internal:update": ADMIN_ANY,
57995
58829
  "shift-internal:history": ADMIN_ANY,
58830
+ // ---- larkBot:* (LarkBotConnector 装配/状态,owner-only) ----
58831
+ "larkBot:provision": ADMIN_ANY,
58832
+ "larkBot:provisionCancel": ADMIN_ANY,
58833
+ "larkBot:bindManual": ADMIN_ANY,
58834
+ "larkBot:unbind": ADMIN_ANY,
58835
+ "larkBot:status": ADMIN_ANY,
57996
58836
  "inbox:sendDm": ADMIN_ANY,
57997
58837
  "personaDispatch:complete": ADMIN_ANY,
57998
58838
  "personaDispatch:list": ADMIN_ANY,
@@ -58124,21 +58964,21 @@ function computeMethodAccess(args) {
58124
58964
  }
58125
58965
 
58126
58966
  // src/version.ts
58127
- var version = "0.2.284".length > 0 ? "0.2.284" : "dev";
58967
+ var version = "0.2.286".length > 0 ? "0.2.286" : "dev";
58128
58968
 
58129
58969
  // src/cli-probe/probe.ts
58130
- var fs54 = __toESM(require("fs"), 1);
58131
- var path62 = __toESM(require("path"), 1);
58970
+ var fs55 = __toESM(require("fs"), 1);
58971
+ var path63 = __toESM(require("path"), 1);
58132
58972
  var PKG_NAME = "@clawos-dev/clawd";
58133
58973
  var BIN_NAME = "clawd";
58134
58974
  var MAX_PARENT_HOPS = 5;
58135
58975
  function probeGlobalCli(pathEnv) {
58136
58976
  if (!pathEnv) return null;
58137
- for (const dir of pathEnv.split(path62.delimiter)) {
58977
+ for (const dir of pathEnv.split(path63.delimiter)) {
58138
58978
  if (!dir) continue;
58139
58979
  let real;
58140
58980
  try {
58141
- real = fs54.realpathSync(path62.join(dir, BIN_NAME));
58981
+ real = fs55.realpathSync(path63.join(dir, BIN_NAME));
58142
58982
  } catch {
58143
58983
  continue;
58144
58984
  }
@@ -58148,15 +58988,15 @@ function probeGlobalCli(pathEnv) {
58148
58988
  return null;
58149
58989
  }
58150
58990
  function readOwnPackageVersion(entryPath) {
58151
- let dir = path62.dirname(entryPath);
58991
+ let dir = path63.dirname(entryPath);
58152
58992
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
58153
58993
  try {
58154
- const raw = fs54.readFileSync(path62.join(dir, "package.json"), "utf8");
58994
+ const raw = fs55.readFileSync(path63.join(dir, "package.json"), "utf8");
58155
58995
  const pkg = JSON.parse(raw);
58156
58996
  if (pkg.name !== PKG_NAME) return null;
58157
58997
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
58158
58998
  } catch {
58159
- const parent = path62.dirname(dir);
58999
+ const parent = path63.dirname(dir);
58160
59000
  if (parent === dir) return null;
58161
59001
  dir = parent;
58162
59002
  }
@@ -58314,7 +59154,7 @@ function buildPersonaHandlers(deps) {
58314
59154
  }
58315
59155
 
58316
59156
  // src/handlers/attachment.ts
58317
- var import_node_path49 = __toESM(require("path"), 1);
59157
+ var import_node_path50 = __toESM(require("path"), 1);
58318
59158
  init_protocol();
58319
59159
  init_protocol();
58320
59160
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -58394,12 +59234,12 @@ function buildAttachmentHandlers(deps) {
58394
59234
  `session ${args.sessionId} scope unresolved`
58395
59235
  );
58396
59236
  }
58397
- const cwdAbs = import_node_path49.default.resolve(sessionFile.cwd);
58398
- const candidateAbs = import_node_path49.default.isAbsolute(args.relPath) ? import_node_path49.default.resolve(args.relPath) : import_node_path49.default.resolve(cwdAbs, args.relPath);
59237
+ const cwdAbs = import_node_path50.default.resolve(sessionFile.cwd);
59238
+ const candidateAbs = import_node_path50.default.isAbsolute(args.relPath) ? import_node_path50.default.resolve(args.relPath) : import_node_path50.default.resolve(cwdAbs, args.relPath);
58399
59239
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
58400
59240
  const entries = deps.groupFileStore.list(scope, args.sessionId);
58401
59241
  const entry = entries.find((e) => {
58402
- const storedAbs = import_node_path49.default.isAbsolute(e.relPath) ? import_node_path49.default.resolve(e.relPath) : import_node_path49.default.resolve(cwdAbs, e.relPath);
59242
+ const storedAbs = import_node_path50.default.isAbsolute(e.relPath) ? import_node_path50.default.resolve(e.relPath) : import_node_path50.default.resolve(cwdAbs, e.relPath);
58403
59243
  return storedAbs === candidateAbs && !e.stale;
58404
59244
  });
58405
59245
  if (!entry) {
@@ -58424,7 +59264,7 @@ function buildAttachmentHandlers(deps) {
58424
59264
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
58425
59265
  const f = deps.sessionStore.read(sessionId);
58426
59266
  if (!f) return;
58427
- assertGuestAttachmentPath(ctx, import_node_path49.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
59267
+ assertGuestAttachmentPath(ctx, import_node_path50.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
58428
59268
  }
58429
59269
  const groupAdd = async (frame, _client, ctx) => {
58430
59270
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -58439,8 +59279,8 @@ function buildAttachmentHandlers(deps) {
58439
59279
  if (!scope) {
58440
59280
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
58441
59281
  }
58442
- const cwdAbs = import_node_path49.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
58443
- const candidateAbs = import_node_path49.default.isAbsolute(args.relPath) ? import_node_path49.default.resolve(args.relPath) : import_node_path49.default.resolve(cwdAbs, args.relPath);
59282
+ const cwdAbs = import_node_path50.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
59283
+ const candidateAbs = import_node_path50.default.isAbsolute(args.relPath) ? import_node_path50.default.resolve(args.relPath) : import_node_path50.default.resolve(cwdAbs, args.relPath);
58444
59284
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
58445
59285
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
58446
59286
  const size = 0;
@@ -58499,19 +59339,19 @@ function buildAttachmentHandlers(deps) {
58499
59339
 
58500
59340
  // src/handlers/extension.ts
58501
59341
  var import_promises9 = __toESM(require("fs/promises"), 1);
58502
- var import_node_path54 = __toESM(require("path"), 1);
59342
+ var import_node_path55 = __toESM(require("path"), 1);
58503
59343
  init_protocol();
58504
59344
 
58505
59345
  // src/extension/bundle-zip.ts
58506
59346
  var import_promises6 = __toESM(require("fs/promises"), 1);
58507
- var import_node_path50 = __toESM(require("path"), 1);
58508
- var import_node_crypto13 = __toESM(require("crypto"), 1);
59347
+ var import_node_path51 = __toESM(require("path"), 1);
59348
+ var import_node_crypto14 = __toESM(require("crypto"), 1);
58509
59349
  var import_jszip2 = __toESM(require_lib3(), 1);
58510
59350
  async function bundleExtensionDir(dir) {
58511
59351
  const entries = await listFilesSorted(dir);
58512
59352
  const zip = new import_jszip2.default();
58513
59353
  for (const rel of entries) {
58514
- const abs = import_node_path50.default.join(dir, rel);
59354
+ const abs = import_node_path51.default.join(dir, rel);
58515
59355
  const content = await import_promises6.default.readFile(abs);
58516
59356
  zip.file(rel, content, { date: FIXED_DATE });
58517
59357
  }
@@ -58520,7 +59360,7 @@ async function bundleExtensionDir(dir) {
58520
59360
  compression: "DEFLATE",
58521
59361
  compressionOptions: { level: 6 }
58522
59362
  });
58523
- const sha256 = import_node_crypto13.default.createHash("sha256").update(buffer).digest("hex");
59363
+ const sha256 = import_node_crypto14.default.createHash("sha256").update(buffer).digest("hex");
58524
59364
  return { buffer, sha256 };
58525
59365
  }
58526
59366
  var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
@@ -58532,7 +59372,7 @@ async function listFilesSorted(rootDir) {
58532
59372
  return out;
58533
59373
  }
58534
59374
  async function walk(absRoot, relPrefix, out) {
58535
- const dirAbs = import_node_path50.default.join(absRoot, relPrefix);
59375
+ const dirAbs = import_node_path51.default.join(absRoot, relPrefix);
58536
59376
  const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
58537
59377
  for (const e of entries) {
58538
59378
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -58586,25 +59426,25 @@ function computePublishCheck(args) {
58586
59426
 
58587
59427
  // src/extension/install-flow.ts
58588
59428
  var import_promises7 = __toESM(require("fs/promises"), 1);
58589
- var import_node_path52 = __toESM(require("path"), 1);
59429
+ var import_node_path53 = __toESM(require("path"), 1);
58590
59430
  var import_node_os19 = __toESM(require("os"), 1);
58591
- var import_node_crypto14 = __toESM(require("crypto"), 1);
59431
+ var import_node_crypto15 = __toESM(require("crypto"), 1);
58592
59432
  var import_jszip3 = __toESM(require_lib3(), 1);
58593
59433
 
58594
59434
  // src/extension/paths.ts
58595
59435
  var import_node_os18 = __toESM(require("os"), 1);
58596
- var import_node_path51 = __toESM(require("path"), 1);
59436
+ var import_node_path52 = __toESM(require("path"), 1);
58597
59437
  function clawdHomeRoot(override) {
58598
- return override ?? process.env.CLAWD_HOME ?? import_node_path51.default.join(import_node_os18.default.homedir(), ".clawd");
59438
+ return override ?? process.env.CLAWD_HOME ?? import_node_path52.default.join(import_node_os18.default.homedir(), ".clawd");
58599
59439
  }
58600
59440
  function extensionsRoot(override) {
58601
- return import_node_path51.default.join(clawdHomeRoot(override), "extensions");
59441
+ return import_node_path52.default.join(clawdHomeRoot(override), "extensions");
58602
59442
  }
58603
59443
  function publishedChannelsFile(override) {
58604
- return import_node_path51.default.join(clawdHomeRoot(override), "extensions-published.json");
59444
+ return import_node_path52.default.join(clawdHomeRoot(override), "extensions-published.json");
58605
59445
  }
58606
59446
  function bundleCacheRoot(override) {
58607
- return import_node_path51.default.join(clawdHomeRoot(override), "extension-bundles");
59447
+ return import_node_path52.default.join(clawdHomeRoot(override), "extension-bundles");
58608
59448
  }
58609
59449
 
58610
59450
  // src/extension/install-flow.ts
@@ -58617,7 +59457,7 @@ var InstallError = class extends Error {
58617
59457
  };
58618
59458
  async function installFromChannel(args, deps) {
58619
59459
  const { channelRef, snapshotHash, bundleZip } = args;
58620
- const computed = import_node_crypto14.default.createHash("sha256").update(bundleZip).digest("hex");
59460
+ const computed = import_node_crypto15.default.createHash("sha256").update(bundleZip).digest("hex");
58621
59461
  if (computed !== snapshotHash) {
58622
59462
  throw new InstallError(
58623
59463
  "HASH_MISMATCH",
@@ -58631,7 +59471,7 @@ async function installFromChannel(args, deps) {
58631
59471
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
58632
59472
  }
58633
59473
  for (const name of Object.keys(zip.files)) {
58634
- if (name.includes("..") || name.startsWith("/") || import_node_path52.default.isAbsolute(name)) {
59474
+ if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
58635
59475
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
58636
59476
  }
58637
59477
  }
@@ -58663,7 +59503,7 @@ async function installFromChannel(args, deps) {
58663
59503
  );
58664
59504
  }
58665
59505
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
58666
- const destDir = import_node_path52.default.join(deps.extensionsRoot, localExtId);
59506
+ const destDir = import_node_path53.default.join(deps.extensionsRoot, localExtId);
58667
59507
  let destExists = false;
58668
59508
  try {
58669
59509
  await import_promises7.default.access(destDir);
@@ -58677,16 +59517,16 @@ async function installFromChannel(args, deps) {
58677
59517
  );
58678
59518
  }
58679
59519
  const stage = await import_promises7.default.mkdtemp(
58680
- import_node_path52.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
59520
+ import_node_path53.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
58681
59521
  );
58682
59522
  try {
58683
59523
  for (const [name, entry] of Object.entries(zip.files)) {
58684
- const dest = import_node_path52.default.join(stage, name);
59524
+ const dest = import_node_path53.default.join(stage, name);
58685
59525
  if (entry.dir) {
58686
59526
  await import_promises7.default.mkdir(dest, { recursive: true });
58687
59527
  continue;
58688
59528
  }
58689
- await import_promises7.default.mkdir(import_node_path52.default.dirname(dest), { recursive: true });
59529
+ await import_promises7.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
58690
59530
  if (name === "manifest.json") {
58691
59531
  const rewritten = { ...parsed.data, id: localExtId };
58692
59532
  await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -58707,9 +59547,9 @@ async function installFromChannel(args, deps) {
58707
59547
 
58708
59548
  // src/extension/update-flow.ts
58709
59549
  var import_promises8 = __toESM(require("fs/promises"), 1);
58710
- var import_node_path53 = __toESM(require("path"), 1);
59550
+ var import_node_path54 = __toESM(require("path"), 1);
58711
59551
  var import_node_os20 = __toESM(require("os"), 1);
58712
- var import_node_crypto15 = __toESM(require("crypto"), 1);
59552
+ var import_node_crypto16 = __toESM(require("crypto"), 1);
58713
59553
  var import_jszip4 = __toESM(require_lib3(), 1);
58714
59554
  var UpdateError = class extends Error {
58715
59555
  constructor(code, message) {
@@ -58724,11 +59564,11 @@ async function updateFromChannel(args, deps) {
58724
59564
  channelRef.extId,
58725
59565
  channelRef.ownerPrincipalId
58726
59566
  );
58727
- const liveDir = import_node_path53.default.join(deps.extensionsRoot, localExtId);
59567
+ const liveDir = import_node_path54.default.join(deps.extensionsRoot, localExtId);
58728
59568
  const prevDir = `${liveDir}.prev`;
58729
59569
  let existingVersion;
58730
59570
  try {
58731
- const raw = await import_promises8.default.readFile(import_node_path53.default.join(liveDir, "manifest.json"), "utf8");
59571
+ const raw = await import_promises8.default.readFile(import_node_path54.default.join(liveDir, "manifest.json"), "utf8");
58732
59572
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
58733
59573
  if (!parsed2.success) {
58734
59574
  throw new UpdateError(
@@ -58747,7 +59587,7 @@ async function updateFromChannel(args, deps) {
58747
59587
  if (e instanceof UpdateError) throw e;
58748
59588
  throw e;
58749
59589
  }
58750
- const computed = import_node_crypto15.default.createHash("sha256").update(bundleZip).digest("hex");
59590
+ const computed = import_node_crypto16.default.createHash("sha256").update(bundleZip).digest("hex");
58751
59591
  if (computed !== snapshotHash) {
58752
59592
  throw new UpdateError(
58753
59593
  "HASH_MISMATCH",
@@ -58761,7 +59601,7 @@ async function updateFromChannel(args, deps) {
58761
59601
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
58762
59602
  }
58763
59603
  for (const name of Object.keys(zip.files)) {
58764
- if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
59604
+ if (name.includes("..") || name.startsWith("/") || import_node_path54.default.isAbsolute(name)) {
58765
59605
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
58766
59606
  }
58767
59607
  }
@@ -58796,16 +59636,16 @@ async function updateFromChannel(args, deps) {
58796
59636
  await import_promises8.default.rm(prevDir, { recursive: true, force: true });
58797
59637
  await import_promises8.default.rename(liveDir, prevDir);
58798
59638
  const stage = await import_promises8.default.mkdtemp(
58799
- import_node_path53.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
59639
+ import_node_path54.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
58800
59640
  );
58801
59641
  try {
58802
59642
  for (const [name, entry] of Object.entries(zip.files)) {
58803
- const dest = import_node_path53.default.join(stage, name);
59643
+ const dest = import_node_path54.default.join(stage, name);
58804
59644
  if (entry.dir) {
58805
59645
  await import_promises8.default.mkdir(dest, { recursive: true });
58806
59646
  continue;
58807
59647
  }
58808
- await import_promises8.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
59648
+ await import_promises8.default.mkdir(import_node_path54.default.dirname(dest), { recursive: true });
58809
59649
  if (name === "manifest.json") {
58810
59650
  const rewritten = { ...parsed.data, id: localExtId };
58811
59651
  await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -58872,7 +59712,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
58872
59712
  );
58873
59713
  }
58874
59714
  }
58875
- const manifestPath = import_node_path54.default.join(root, extId, "manifest.json");
59715
+ const manifestPath = import_node_path55.default.join(root, extId, "manifest.json");
58876
59716
  const manifest = await readManifest(root, extId);
58877
59717
  const next = { ...manifest, version: newVersion };
58878
59718
  const tmp = `${manifestPath}.tmp`;
@@ -58880,7 +59720,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
58880
59720
  await import_promises9.default.rename(tmp, manifestPath);
58881
59721
  }
58882
59722
  async function readManifest(root, extId) {
58883
- const file = import_node_path54.default.join(root, extId, "manifest.json");
59723
+ const file = import_node_path55.default.join(root, extId, "manifest.json");
58884
59724
  let raw;
58885
59725
  try {
58886
59726
  raw = await import_promises9.default.readFile(file, "utf8");
@@ -58964,7 +59804,7 @@ function buildExtensionHandlers(deps) {
58964
59804
  };
58965
59805
  async function buildSnapshotMeta(extId) {
58966
59806
  const manifest = await readManifest(deps.root, extId);
58967
- const { sha256, buffer } = await bundleExtensionDir(import_node_path54.default.join(deps.root, extId));
59807
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path55.default.join(deps.root, extId));
58968
59808
  return { manifest, contentHash: sha256, buffer };
58969
59809
  }
58970
59810
  const publish = async (frame, _client, ctx) => {
@@ -59139,9 +59979,9 @@ function buildExtensionHandlers(deps) {
59139
59979
  }
59140
59980
 
59141
59981
  // src/app-builder/project-store.ts
59142
- var import_node_fs44 = require("fs");
59982
+ var import_node_fs45 = require("fs");
59143
59983
  var import_node_child_process11 = require("child_process");
59144
- var import_node_path55 = require("path");
59984
+ var import_node_path56 = require("path");
59145
59985
  init_protocol();
59146
59986
  var PROJECTS_DIR = "projects";
59147
59987
  var META_FILE = ".clawd-project.json";
@@ -59155,19 +59995,19 @@ var ProjectStore = class {
59155
59995
  root;
59156
59996
  /** projects/<name>/.clawd-project.json 路径 */
59157
59997
  metaPath(name) {
59158
- return (0, import_node_path55.join)(this.projectsRoot(), name, META_FILE);
59998
+ return (0, import_node_path56.join)(this.projectsRoot(), name, META_FILE);
59159
59999
  }
59160
60000
  /** projects/<name>/ 目录路径(cwd 用) */
59161
60001
  projectDir(name) {
59162
- return (0, import_node_path55.join)(this.projectsRoot(), name);
60002
+ return (0, import_node_path56.join)(this.projectsRoot(), name);
59163
60003
  }
59164
60004
  projectsRoot() {
59165
- return (0, import_node_path55.join)(this.root, PROJECTS_DIR);
60005
+ return (0, import_node_path56.join)(this.root, PROJECTS_DIR);
59166
60006
  }
59167
60007
  async list() {
59168
60008
  let entries;
59169
60009
  try {
59170
- entries = await import_node_fs44.promises.readdir(this.projectsRoot());
60010
+ entries = await import_node_fs45.promises.readdir(this.projectsRoot());
59171
60011
  } catch (err) {
59172
60012
  if (err.code === "ENOENT") return [];
59173
60013
  throw err;
@@ -59175,7 +60015,7 @@ var ProjectStore = class {
59175
60015
  const out = [];
59176
60016
  for (const name of entries) {
59177
60017
  try {
59178
- const raw = await import_node_fs44.promises.readFile(this.metaPath(name), "utf8");
60018
+ const raw = await import_node_fs45.promises.readFile(this.metaPath(name), "utf8");
59179
60019
  const json = JSON.parse(raw);
59180
60020
  let migrated = false;
59181
60021
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -59186,7 +60026,7 @@ var ProjectStore = class {
59186
60026
  if (parsed.success) {
59187
60027
  out.push(parsed.data);
59188
60028
  if (migrated) {
59189
- void import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
60029
+ void import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
59190
60030
  });
59191
60031
  }
59192
60032
  }
@@ -59230,8 +60070,8 @@ var ProjectStore = class {
59230
60070
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
59231
60071
  }
59232
60072
  const dir = this.projectDir(name);
59233
- await import_node_fs44.promises.mkdir(dir, { recursive: true });
59234
- await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
60073
+ await import_node_fs45.promises.mkdir(dir, { recursive: true });
60074
+ await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
59235
60075
  return meta;
59236
60076
  }
59237
60077
  /**
@@ -59274,7 +60114,7 @@ var ProjectStore = class {
59274
60114
  }
59275
60115
  async delete(name) {
59276
60116
  const dir = this.projectDir(name);
59277
- await import_node_fs44.promises.rm(dir, { recursive: true, force: true });
60117
+ await import_node_fs45.promises.rm(dir, { recursive: true, force: true });
59278
60118
  }
59279
60119
  async updatePort(name, newPort) {
59280
60120
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -59290,7 +60130,7 @@ var ProjectStore = class {
59290
60130
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
59291
60131
  }
59292
60132
  const updated = { ...target, port: newPort };
59293
- await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
60133
+ await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
59294
60134
  return updated;
59295
60135
  }
59296
60136
  /**
@@ -59307,7 +60147,7 @@ var ProjectStore = class {
59307
60147
  if (!validated.success) {
59308
60148
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
59309
60149
  }
59310
- await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60150
+ await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
59311
60151
  return validated.data;
59312
60152
  }
59313
60153
  /**
@@ -59328,7 +60168,7 @@ var ProjectStore = class {
59328
60168
  if (!validated.success) {
59329
60169
  throw new Error(`invalid publishJob: ${validated.error.message}`);
59330
60170
  }
59331
- await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60171
+ await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
59332
60172
  return validated.data;
59333
60173
  }
59334
60174
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -59343,7 +60183,7 @@ var ProjectStore = class {
59343
60183
  if (!validated.success) {
59344
60184
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
59345
60185
  }
59346
- await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
60186
+ await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
59347
60187
  return validated.data;
59348
60188
  }
59349
60189
  };
@@ -59413,7 +60253,7 @@ function listPidsOnPort(port) {
59413
60253
  }
59414
60254
 
59415
60255
  // src/app-builder/publish-registry.ts
59416
- var import_node_crypto16 = require("crypto");
60256
+ var import_node_crypto17 = require("crypto");
59417
60257
  var PublishJobRegistry = class {
59418
60258
  jobs = /* @__PURE__ */ new Map();
59419
60259
  has(name) {
@@ -59430,7 +60270,7 @@ var PublishJobRegistry = class {
59430
60270
  if (this.jobs.has(args.name)) {
59431
60271
  throw new Error(`already publishing: ${args.name}`);
59432
60272
  }
59433
- const jobId = args.jobId ?? `job-${(0, import_node_crypto16.randomUUID)()}`;
60273
+ const jobId = args.jobId ?? `job-${(0, import_node_crypto17.randomUUID)()}`;
59434
60274
  this.jobs.set(args.name, {
59435
60275
  jobId,
59436
60276
  name: args.name,
@@ -59464,8 +60304,8 @@ var PublishJobRegistry = class {
59464
60304
 
59465
60305
  // src/app-builder/publish-job-runner.ts
59466
60306
  var import_node_child_process13 = require("child_process");
59467
- var import_node_fs45 = require("fs");
59468
- var import_node_path56 = require("path");
60307
+ var import_node_fs46 = require("fs");
60308
+ var import_node_path57 = require("path");
59469
60309
 
59470
60310
  // src/app-builder/publish-stage-parser.ts
59471
60311
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -59497,10 +60337,10 @@ async function startPublishJob(deps, args) {
59497
60337
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
59498
60338
  }
59499
60339
  const projDir = projectDir(args.name);
59500
- const logPath = (0, import_node_path56.join)(projDir, ".publish.log");
60340
+ const logPath = (0, import_node_path57.join)(projDir, ".publish.log");
59501
60341
  let logStream = null;
59502
60342
  try {
59503
- logStream = (0, import_node_fs45.createWriteStream)(logPath, { flags: "w" });
60343
+ logStream = (0, import_node_fs46.createWriteStream)(logPath, { flags: "w" });
59504
60344
  } catch {
59505
60345
  logStream = null;
59506
60346
  }
@@ -59757,8 +60597,8 @@ async function recoverInterruptedJobs(deps) {
59757
60597
 
59758
60598
  // src/handlers/app-builder.ts
59759
60599
  init_protocol();
59760
- var import_node_path57 = require("path");
59761
- var import_node_fs46 = require("fs");
60600
+ var import_node_path58 = require("path");
60601
+ var import_node_fs47 = require("fs");
59762
60602
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
59763
60603
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
59764
60604
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -59839,7 +60679,7 @@ function buildAppBuilderHandlers(deps) {
59839
60679
  async function listAllUsersProjects() {
59840
60680
  if (!deps.usersRoot || !deps.getStore) return [];
59841
60681
  const getStore = deps.getStore;
59842
- const userIds = await import_node_fs46.promises.readdir(deps.usersRoot).catch(() => []);
60682
+ const userIds = await import_node_fs47.promises.readdir(deps.usersRoot).catch(() => []);
59843
60683
  const perUser = await Promise.all(
59844
60684
  userIds.map((uid) => getStore(uid).list().catch(() => []))
59845
60685
  );
@@ -59908,8 +60748,8 @@ function buildAppBuilderHandlers(deps) {
59908
60748
  const project = await userStore.create(f.name, reservedPorts);
59909
60749
  try {
59910
60750
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
59911
- const templateSrcDir = (0, import_node_path57.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
59912
- const scaffoldScript = (0, import_node_path57.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
60751
+ const templateSrcDir = (0, import_node_path58.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
60752
+ const scaffoldScript = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
59913
60753
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
59914
60754
  deps.logger?.info("app-builder.scaffold.done", {
59915
60755
  name: project.name,
@@ -60113,7 +60953,7 @@ function buildAppBuilderHandlers(deps) {
60113
60953
  await userStore.clearPublishJob(args.name);
60114
60954
  }
60115
60955
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
60116
- const scriptPath = (0, import_node_path57.join)(deps.deployKitRoot, "scripts", "publish.sh");
60956
+ const scriptPath = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "publish.sh");
60117
60957
  deps.logger?.info("app-builder.publish.start", {
60118
60958
  name: args.name,
60119
60959
  sessionId: boundSession.sessionId,
@@ -60289,7 +61129,7 @@ function buildVisitorHandlers(deps) {
60289
61129
 
60290
61130
  // src/extension/registry.ts
60291
61131
  var import_promises10 = __toESM(require("fs/promises"), 1);
60292
- var import_node_path58 = __toESM(require("path"), 1);
61132
+ var import_node_path59 = __toESM(require("path"), 1);
60293
61133
  async function loadAll(root) {
60294
61134
  let entries;
60295
61135
  try {
@@ -60302,13 +61142,13 @@ async function loadAll(root) {
60302
61142
  for (const ent of entries) {
60303
61143
  if (!ent.isDirectory()) continue;
60304
61144
  if (ent.name.startsWith(".")) continue;
60305
- records.push(await loadOne(import_node_path58.default.join(root, ent.name), ent.name));
61145
+ records.push(await loadOne(import_node_path59.default.join(root, ent.name), ent.name));
60306
61146
  }
60307
61147
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
60308
61148
  return records;
60309
61149
  }
60310
61150
  async function loadOne(dir, dirName) {
60311
- const manifestPath = import_node_path58.default.join(dir, "manifest.json");
61151
+ const manifestPath = import_node_path59.default.join(dir, "manifest.json");
60312
61152
  let raw;
60313
61153
  try {
60314
61154
  raw = await import_promises10.default.readFile(manifestPath, "utf8");
@@ -60353,7 +61193,7 @@ async function loadOne(dir, dirName) {
60353
61193
 
60354
61194
  // src/extension/uninstall.ts
60355
61195
  var import_promises11 = __toESM(require("fs/promises"), 1);
60356
- var import_node_path59 = __toESM(require("path"), 1);
61196
+ var import_node_path60 = __toESM(require("path"), 1);
60357
61197
  var UninstallError = class extends Error {
60358
61198
  constructor(code, message) {
60359
61199
  super(message);
@@ -60362,7 +61202,7 @@ var UninstallError = class extends Error {
60362
61202
  code;
60363
61203
  };
60364
61204
  async function uninstall(deps) {
60365
- const dir = import_node_path59.default.join(deps.root, deps.extId);
61205
+ const dir = import_node_path60.default.join(deps.root, deps.extId);
60366
61206
  try {
60367
61207
  await import_promises11.default.access(dir);
60368
61208
  } catch {
@@ -60373,7 +61213,7 @@ async function uninstall(deps) {
60373
61213
  }
60374
61214
 
60375
61215
  // src/handlers/index.ts
60376
- var import_node_crypto17 = require("crypto");
61216
+ var import_node_crypto18 = require("crypto");
60377
61217
 
60378
61218
  // src/handlers/peer-exec.ts
60379
61219
  init_protocol();
@@ -60381,11 +61221,11 @@ init_protocol();
60381
61221
  // src/peer-ops/run-command.ts
60382
61222
  var import_node_child_process14 = require("child_process");
60383
61223
  var import_node_os21 = __toESM(require("os"), 1);
60384
- var DEFAULT_TIMEOUT_MS3 = 3e4;
61224
+ var DEFAULT_TIMEOUT_MS4 = 3e4;
60385
61225
  var MAX_TIMEOUT_MS = 3e5;
60386
61226
  var MAX_OUTPUT_BYTES = 1048576;
60387
61227
  function runCommand(command, opts = {}) {
60388
- const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3, MAX_TIMEOUT_MS);
61228
+ const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4, MAX_TIMEOUT_MS);
60389
61229
  return new Promise((resolve6) => {
60390
61230
  const child = (0, import_node_child_process14.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
60391
61231
  const out = [];
@@ -60528,7 +61368,7 @@ function buildMethodHandlers(deps) {
60528
61368
  const c = deps.contactStore.get(deviceId);
60529
61369
  return c ? { deviceId: c.deviceId, remoteUrl: c.remoteUrl, connectToken: c.connectToken } : null;
60530
61370
  },
60531
- genId: () => (0, import_node_crypto17.randomUUID)(),
61371
+ genId: () => (0, import_node_crypto18.randomUUID)(),
60532
61372
  now: () => Date.now(),
60533
61373
  forwardInboxPostToPeer,
60534
61374
  logger: deps.logger
@@ -60892,7 +61732,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
60892
61732
 
60893
61733
  // src/extension/runtime.ts
60894
61734
  var import_node_child_process16 = require("child_process");
60895
- var import_node_path60 = __toESM(require("path"), 1);
61735
+ var import_node_path61 = __toESM(require("path"), 1);
60896
61736
  var import_promises12 = require("timers/promises");
60897
61737
 
60898
61738
  // src/extension/port-allocator.ts
@@ -60993,7 +61833,7 @@ var Runtime = class {
60993
61833
  /\$CLAWOS_EXT_PORT/g,
60994
61834
  String(port)
60995
61835
  );
60996
- const dir = import_node_path60.default.join(this.root, extId);
61836
+ const dir = import_node_path61.default.join(this.root, extId);
60997
61837
  const env = {
60998
61838
  ...process.env,
60999
61839
  CLAWOS_EXT_PORT: String(port),
@@ -61105,7 +61945,7 @@ ${handle.stderrTail}`
61105
61945
 
61106
61946
  // src/extension/published-channels.ts
61107
61947
  var import_promises13 = __toESM(require("fs/promises"), 1);
61108
- var import_node_path61 = __toESM(require("path"), 1);
61948
+ var import_node_path62 = __toESM(require("path"), 1);
61109
61949
  init_zod();
61110
61950
  var PublishedChannelsError = class extends Error {
61111
61951
  constructor(code, message) {
@@ -61204,7 +62044,7 @@ var PublishedChannelStore = class {
61204
62044
  )
61205
62045
  };
61206
62046
  const tmp = `${this.filePath}.tmp`;
61207
- await import_promises13.default.mkdir(import_node_path61.default.dirname(this.filePath), { recursive: true });
62047
+ await import_promises13.default.mkdir(import_node_path62.default.dirname(this.filePath), { recursive: true });
61208
62048
  await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
61209
62049
  await import_promises13.default.rename(tmp, this.filePath);
61210
62050
  }
@@ -61212,7 +62052,7 @@ var PublishedChannelStore = class {
61212
62052
 
61213
62053
  // src/extension/bundle-cache.ts
61214
62054
  var import_promises14 = __toESM(require("fs/promises"), 1);
61215
- var import_node_path62 = __toESM(require("path"), 1);
62055
+ var import_node_path63 = __toESM(require("path"), 1);
61216
62056
  var BundleCache = class {
61217
62057
  constructor(rootDir) {
61218
62058
  this.rootDir = rootDir;
@@ -61221,14 +62061,14 @@ var BundleCache = class {
61221
62061
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
61222
62062
  async write(snapshotHash, buffer) {
61223
62063
  await import_promises14.default.mkdir(this.rootDir, { recursive: true });
61224
- const file = import_node_path62.default.join(this.rootDir, `${snapshotHash}.zip`);
62064
+ const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
61225
62065
  const tmp = `${file}.tmp`;
61226
62066
  await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
61227
62067
  await import_promises14.default.rename(tmp, file);
61228
62068
  }
61229
62069
  /** Returns the bundle bytes, or null when the file doesn't exist. */
61230
62070
  async read(snapshotHash) {
61231
- const file = import_node_path62.default.join(this.rootDir, `${snapshotHash}.zip`);
62071
+ const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
61232
62072
  try {
61233
62073
  return await import_promises14.default.readFile(file);
61234
62074
  } catch (e) {
@@ -61238,7 +62078,7 @@ var BundleCache = class {
61238
62078
  }
61239
62079
  /** Idempotent — missing file is not an error. */
61240
62080
  async delete(snapshotHash) {
61241
- const file = import_node_path62.default.join(this.rootDir, `${snapshotHash}.zip`);
62081
+ const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
61242
62082
  await import_promises14.default.rm(file, { force: true });
61243
62083
  }
61244
62084
  };
@@ -61261,24 +62101,24 @@ async function startDaemon(config) {
61261
62101
  sampling: logShippingCfg.sampling,
61262
62102
  homeDir: import_node_os22.default.homedir()
61263
62103
  });
61264
- const logDir = import_node_path63.default.join(config.dataDir, "log");
61265
- import_node_fs47.default.mkdirSync(logDir, { recursive: true });
62104
+ const logDir = import_node_path64.default.join(config.dataDir, "log");
62105
+ import_node_fs48.default.mkdirSync(logDir, { recursive: true });
61266
62106
  const logger = createLogger({
61267
62107
  level: config.logLevel,
61268
- file: import_node_path63.default.join(logDir, "clawd.log"),
62108
+ file: import_node_path64.default.join(logDir, "clawd.log"),
61269
62109
  logClient
61270
62110
  });
61271
62111
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
61272
62112
  const screenIdleProbeLogger = createFileOnlyLogger({
61273
- file: import_node_path63.default.join(logDir, "screen-idle-probe.log"),
62113
+ file: import_node_path64.default.join(logDir, "screen-idle-probe.log"),
61274
62114
  level: "debug"
61275
62115
  });
61276
62116
  logger.info("screen-idle probe logger enabled", {
61277
- file: import_node_path63.default.join(logDir, "screen-idle-probe.log")
62117
+ file: import_node_path64.default.join(logDir, "screen-idle-probe.log")
61278
62118
  });
61279
62119
  const CAP_TARGETS = [
61280
- import_node_path63.default.join(logDir, "clawd.log"),
61281
- import_node_path63.default.join(logDir, "screen-idle-probe.log")
62120
+ import_node_path64.default.join(logDir, "clawd.log"),
62121
+ import_node_path64.default.join(logDir, "screen-idle-probe.log")
61282
62122
  ];
61283
62123
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
61284
62124
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -61374,8 +62214,8 @@ async function startDaemon(config) {
61374
62214
  const agents = new AgentsScanner();
61375
62215
  const history = new ClaudeHistoryReader();
61376
62216
  let transport = null;
61377
- const personaStore = new PersonaStore(import_node_path63.default.join(config.dataDir, "personas"));
61378
- const usersRoot = import_node_path63.default.join(config.dataDir, "users");
62217
+ const personaStore = new PersonaStore(import_node_path64.default.join(config.dataDir, "personas"));
62218
+ const usersRoot = import_node_path64.default.join(config.dataDir, "users");
61379
62219
  const defaultsRoot = findDefaultsRoot(logger);
61380
62220
  if (defaultsRoot) {
61381
62221
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -61396,7 +62236,7 @@ async function startDaemon(config) {
61396
62236
  retirePersonaBuilder({ store: personaStore, logger });
61397
62237
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
61398
62238
  const dispatchStore = createDispatchStore({
61399
- filePath: import_node_path63.default.join(config.dataDir, "dispatch.json"),
62239
+ filePath: import_node_path64.default.join(config.dataDir, "dispatch.json"),
61400
62240
  now: () => Date.now(),
61401
62241
  onFlushError: (err) => logger.error("dispatch store flush failed", {
61402
62242
  reason: err instanceof Error ? err.message : String(err)
@@ -61411,18 +62251,18 @@ async function startDaemon(config) {
61411
62251
  now: () => Date.now(),
61412
62252
  onCompleted: (sid) => deliverPendingRef?.(sid)
61413
62253
  });
61414
- const here = typeof __dirname === "string" ? __dirname : import_node_path63.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
62254
+ const here = typeof __dirname === "string" ? __dirname : import_node_path64.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
61415
62255
  const mcpConfigs = [];
61416
62256
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
61417
62257
  const dispatchServerCandidates = [
61418
- import_node_path63.default.join(here, "dispatch", "mcp-server.cjs"),
62258
+ import_node_path64.default.join(here, "dispatch", "mcp-server.cjs"),
61419
62259
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
61420
- import_node_path63.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
62260
+ import_node_path64.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
61421
62261
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
61422
62262
  ];
61423
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62263
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61424
62264
  if (dispatchServerScriptPath) {
61425
- const dispatchLogPath = import_node_path63.default.join(logDir, "dispatch-mcp-server.log");
62265
+ const dispatchLogPath = import_node_path64.default.join(logDir, "dispatch-mcp-server.log");
61426
62266
  const dispatchCfgPath = writeDispatchMcpConfig({
61427
62267
  dataDir: config.dataDir,
61428
62268
  serverScriptPath: dispatchServerScriptPath,
@@ -61442,12 +62282,12 @@ async function startDaemon(config) {
61442
62282
  });
61443
62283
  }
61444
62284
  const ticketServerCandidates = [
61445
- import_node_path63.default.join(here, "ticket", "mcp-server.cjs"),
61446
- import_node_path63.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
62285
+ import_node_path64.default.join(here, "ticket", "mcp-server.cjs"),
62286
+ import_node_path64.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
61447
62287
  ];
61448
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62288
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61449
62289
  if (ticketServerScriptPath) {
61450
- const ticketLogPath = import_node_path63.default.join(logDir, "ticket-mcp-server.log");
62290
+ const ticketLogPath = import_node_path64.default.join(logDir, "ticket-mcp-server.log");
61451
62291
  const ticketCfgPath = writeTicketMcpConfig({
61452
62292
  dataDir: config.dataDir,
61453
62293
  serverScriptPath: ticketServerScriptPath,
@@ -61469,12 +62309,12 @@ async function startDaemon(config) {
61469
62309
  });
61470
62310
  }
61471
62311
  const shiftServerCandidates = [
61472
- import_node_path63.default.join(here, "shift", "mcp-server.cjs"),
61473
- import_node_path63.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
62312
+ import_node_path64.default.join(here, "shift", "mcp-server.cjs"),
62313
+ import_node_path64.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
61474
62314
  ];
61475
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62315
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61476
62316
  if (shiftServerScriptPath) {
61477
- const shiftLogPath = import_node_path63.default.join(logDir, "shift-mcp-server.log");
62317
+ const shiftLogPath = import_node_path64.default.join(logDir, "shift-mcp-server.log");
61478
62318
  const shiftCfgPath = await writeShiftMcpConfig({
61479
62319
  dataDir: config.dataDir,
61480
62320
  serverScriptPath: shiftServerScriptPath,
@@ -61495,12 +62335,12 @@ async function startDaemon(config) {
61495
62335
  );
61496
62336
  }
61497
62337
  const inboxServerCandidates = [
61498
- import_node_path63.default.join(here, "inbox", "mcp-server.cjs"),
61499
- import_node_path63.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
62338
+ import_node_path64.default.join(here, "inbox", "mcp-server.cjs"),
62339
+ import_node_path64.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
61500
62340
  ];
61501
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62341
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61502
62342
  if (inboxServerScriptPath) {
61503
- const inboxLogPath = import_node_path63.default.join(logDir, "inbox-mcp-server.log");
62343
+ const inboxLogPath = import_node_path64.default.join(logDir, "inbox-mcp-server.log");
61504
62344
  const inboxCfgPath = await writeInboxMcpConfig({
61505
62345
  dataDir: config.dataDir,
61506
62346
  serverScriptPath: inboxServerScriptPath,
@@ -61521,10 +62361,10 @@ async function startDaemon(config) {
61521
62361
  );
61522
62362
  }
61523
62363
  const peerOpsServerCandidates = [
61524
- import_node_path63.default.join(here, "peer-ops", "mcp-server.cjs"),
61525
- import_node_path63.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
62364
+ import_node_path64.default.join(here, "peer-ops", "mcp-server.cjs"),
62365
+ import_node_path64.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
61526
62366
  ];
61527
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62367
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61528
62368
  if (peerOpsServerScriptPath) {
61529
62369
  const peerOpsCfgPath = writePeerOpsMcpConfig({
61530
62370
  dataDir: config.dataDir,
@@ -61544,12 +62384,12 @@ async function startDaemon(config) {
61544
62384
  );
61545
62385
  }
61546
62386
  const rpcToolServerCandidates = [
61547
- import_node_path63.default.join(here, "rpc-tool", "mcp-server.cjs"),
61548
- import_node_path63.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
62387
+ import_node_path64.default.join(here, "rpc-tool", "mcp-server.cjs"),
62388
+ import_node_path64.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
61549
62389
  ];
61550
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
62390
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
61551
62391
  if (rpcToolServerScriptPath) {
61552
- const rpcToolLogPath = import_node_path63.default.join(logDir, "rpc-tool-mcp-server.log");
62392
+ const rpcToolLogPath = import_node_path64.default.join(logDir, "rpc-tool-mcp-server.log");
61553
62393
  const rpcToolCfgPath = writeRpcToolMcpConfig({
61554
62394
  dataDir: config.dataDir,
61555
62395
  serverScriptPath: rpcToolServerScriptPath,
@@ -61570,7 +62410,7 @@ async function startDaemon(config) {
61570
62410
  );
61571
62411
  }
61572
62412
  const shiftStore = createShiftStore({
61573
- filePath: import_node_path63.default.join(config.dataDir, "shift.json"),
62413
+ filePath: import_node_path64.default.join(config.dataDir, "shift.json"),
61574
62414
  ownerIdProvider: () => ownerPrincipalId,
61575
62415
  now: () => Date.now()
61576
62416
  });
@@ -61592,7 +62432,7 @@ async function startDaemon(config) {
61592
62432
  getAdapter,
61593
62433
  historyReader: history,
61594
62434
  dataDir: config.dataDir,
61595
- personaRoot: import_node_path63.default.join(config.dataDir, "personas"),
62435
+ personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
61596
62436
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
61597
62437
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
61598
62438
  getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
@@ -61643,10 +62483,10 @@ async function startDaemon(config) {
61643
62483
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
61644
62484
  attachmentGroup: {
61645
62485
  onFileEdit: (input) => {
61646
- const absPath = import_node_path63.default.isAbsolute(input.relPath) ? input.relPath : import_node_path63.default.join(input.cwd, input.relPath);
62486
+ const absPath = import_node_path64.default.isAbsolute(input.relPath) ? input.relPath : import_node_path64.default.join(input.cwd, input.relPath);
61647
62487
  let size = 0;
61648
62488
  try {
61649
- size = import_node_fs47.default.statSync(absPath).size;
62489
+ size = import_node_fs48.default.statSync(absPath).size;
61650
62490
  } catch (err) {
61651
62491
  logger.warn("attachment.onFileEdit stat failed", {
61652
62492
  sessionId: input.sessionId,
@@ -61887,11 +62727,11 @@ async function startDaemon(config) {
61887
62727
  // 'persona/<pid>/owner',default 走 'default'。
61888
62728
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
61889
62729
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
61890
- personaRoot: import_node_path63.default.join(config.dataDir, "personas"),
62730
+ personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
61891
62731
  usersRoot
61892
62732
  },
61893
62733
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
61894
- personaRoot: import_node_path63.default.join(config.dataDir, "personas"),
62734
+ personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
61895
62735
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
61896
62736
  usersRoot,
61897
62737
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -62017,11 +62857,11 @@ async function startDaemon(config) {
62017
62857
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
62018
62858
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
62019
62859
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
62020
- appBuilderPersonaRoot: import_node_path63.default.join(config.dataDir, "personas", "persona-app-builder"),
62860
+ appBuilderPersonaRoot: import_node_path64.default.join(config.dataDir, "personas", "persona-app-builder"),
62021
62861
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
62022
- deployKitRoot: import_node_path63.default.join(config.dataDir, "deploy-kit"),
62862
+ deployKitRoot: import_node_path64.default.join(config.dataDir, "deploy-kit"),
62023
62863
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
62024
- resolvePersonaRoot: (personaId2) => import_node_path63.default.join(config.dataDir, "personas", personaId2),
62864
+ resolvePersonaRoot: (personaId2) => import_node_path64.default.join(config.dataDir, "personas", personaId2),
62025
62865
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
62026
62866
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
62027
62867
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -62124,6 +62964,42 @@ async function startDaemon(config) {
62124
62964
  });
62125
62965
  shiftScheduler.start();
62126
62966
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
62967
+ const larkBotStore = createLarkBotBindingStore(import_node_path64.default.join(config.dataDir, "personas"));
62968
+ const larkBotCloud = createLarkBotCloudClient({
62969
+ api: config.clawosApi ?? DEFAULT_CLAWOS_API,
62970
+ apiKey: resolveClawdTicketsApiKey(),
62971
+ deviceId: authFile.deviceId,
62972
+ displayName: ownerDisplayName
62973
+ });
62974
+ const larkChatRouter = createLarkChatRouter({
62975
+ manager,
62976
+ cloud: larkBotCloud,
62977
+ store: larkBotStore,
62978
+ logger: {
62979
+ warn: (msg) => logger.warn(msg),
62980
+ info: (msg) => logger.info(msg)
62981
+ }
62982
+ });
62983
+ const larkEventDedupe = createLarkEventDedupe();
62984
+ const larkBotEventEndpoint = createLarkBotEventEndpoint({
62985
+ getPublicKey: () => serverKeyStore.read(),
62986
+ route: larkChatRouter.handleEnvelope,
62987
+ dedupe: larkEventDedupe,
62988
+ logger: { warn: (msg) => logger.warn(msg) }
62989
+ });
62990
+ const larkBotDeps = {
62991
+ provisioner: { startAppRegistration, startScopeAuthorization },
62992
+ cloud: larkBotCloud,
62993
+ store: larkBotStore,
62994
+ broadcast: (frame) => wsServer?.broadcastToOwners(frame),
62995
+ getTunnelUrl: () => currentTunnelUrl,
62996
+ getOwnerId: () => ownerIdentityStore.read()?.identity.ownerId ?? null,
62997
+ getPersonaName: (personaId2) => personaRegistry.get(personaId2)?.label ?? null,
62998
+ listLarkSessions: larkChatRouter.listLarkSessions,
62999
+ listBoundPersonaIds: () => personaStore.list().filter((pid) => larkBotStore.read(pid) != null),
63000
+ logger: { warn: (msg) => logger.warn(msg) }
63001
+ };
63002
+ Object.assign(handlers, buildLarkBotHandlers(larkBotDeps));
62127
63003
  const authResolver = new AuthContextResolver({
62128
63004
  ownerToken: resolvedAuthToken
62129
63005
  });
@@ -62175,6 +63051,8 @@ async function startDaemon(config) {
62175
63051
  // persona web 分享:访客换 token(POST /share/exchange)+ guest SPA serve(GET /s)
62176
63052
  visitorExchange: exchangeVisitorToken,
62177
63053
  ...shareUiAssetLoader ? { shareUiAssetLoader } : {},
63054
+ // LarkBotConnector 事件入口(云端签名即凭证,无 Bearer)
63055
+ larkBotEvent: larkBotEventEndpoint,
62178
63056
  // /files HMAC verify 用 auth.json token(与 attachment.signUrl 同源)。
62179
63057
  getSignSecret: () => authFile.token,
62180
63058
  // chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
@@ -62359,12 +63237,27 @@ async function startDaemon(config) {
62359
63237
  stateMgr.write(stateSnapshot);
62360
63238
  currentTunnelUrl = r.url;
62361
63239
  wss.broadcastAll({ type: "tunnel:ready", url: r.url, subdomain: r.subdomain });
63240
+ void refreshTunnelUrlOnStartup(larkBotDeps);
63241
+ void (async () => {
63242
+ if (larkBotDeps.listBoundPersonaIds().length === 0) return;
63243
+ try {
63244
+ const items = await larkBotCloud.claimEvents();
63245
+ const nowSec = Math.floor(Date.now() / 1e3);
63246
+ for (const it of items) {
63247
+ larkEventDedupe.add(it.eventId);
63248
+ larkChatRouter.handleEnvelope({ ...it, iat: nowSec, exp: nowSec + 300 });
63249
+ }
63250
+ if (items.length > 0) logger.info("larkBot pending events claimed", { count: items.length });
63251
+ } catch (err) {
63252
+ logger.warn("larkBot pending events claim failed", { err: err.message });
63253
+ }
63254
+ })();
62362
63255
  const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
62363
63256
  const lines = [
62364
63257
  `Tunnel: ${r.url}`,
62365
63258
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
62366
- `Frpc config: ${import_node_path63.default.join(config.dataDir, "frpc.toml")}`,
62367
- `Frpc log: ${import_node_path63.default.join(logDir, "frpc.log")}`
63259
+ `Frpc config: ${import_node_path64.default.join(config.dataDir, "frpc.toml")}`,
63260
+ `Frpc log: ${import_node_path64.default.join(logDir, "frpc.log")}`
62368
63261
  ];
62369
63262
  const width = Math.max(...lines.map((l) => l.length));
62370
63263
  const bar = "\u2550".repeat(width + 4);
@@ -62377,8 +63270,8 @@ ${bar}
62377
63270
 
62378
63271
  `);
62379
63272
  try {
62380
- const connectPath = import_node_path63.default.join(config.dataDir, "connect.txt");
62381
- import_node_fs47.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
63273
+ const connectPath = import_node_path64.default.join(config.dataDir, "connect.txt");
63274
+ import_node_fs48.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
62382
63275
  } catch {
62383
63276
  }
62384
63277
  } catch (err) {
@@ -62450,9 +63343,9 @@ ${bar}
62450
63343
  };
62451
63344
  }
62452
63345
  function migrateDropPersonsDir(dataDir) {
62453
- const dir = import_node_path63.default.join(dataDir, "persons");
63346
+ const dir = import_node_path64.default.join(dataDir, "persons");
62454
63347
  try {
62455
- import_node_fs47.default.rmSync(dir, { recursive: true, force: true });
63348
+ import_node_fs48.default.rmSync(dir, { recursive: true, force: true });
62456
63349
  } catch {
62457
63350
  }
62458
63351
  }