@clawos-dev/clawd 0.2.590 → 0.2.592

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: path102, errorMaps, issueData } = params;
454
- const fullPath = [...path102, ...issueData.path || []];
453
+ const { data, path: path105, errorMaps, issueData } = params;
454
+ const fullPath = [...path105, ...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, path102, key) {
765
+ constructor(parent, value, path105, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path102;
769
+ this._path = path105;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -5769,6 +5769,70 @@ var init_esm = __esm({
5769
5769
  }
5770
5770
  });
5771
5771
 
5772
+ // ../protocol/src/subscription-channel.ts
5773
+ function maskApiKey(key) {
5774
+ const trimmed = key.trim();
5775
+ if (!trimmed) return "";
5776
+ if (trimmed.length <= 8) return "****";
5777
+ return `${trimmed.slice(0, 3)}****${trimmed.slice(-4)}`;
5778
+ }
5779
+ function toChannelView(channel) {
5780
+ return {
5781
+ id: channel.id,
5782
+ name: channel.name,
5783
+ baseUrl: channel.baseUrl,
5784
+ ...channel.remark ? { remark: channel.remark } : {},
5785
+ keyMasked: maskApiKey(channel.apiKey),
5786
+ hasKey: Boolean(channel.apiKey.trim()),
5787
+ createdAt: channel.createdAt,
5788
+ updatedAt: channel.updatedAt
5789
+ };
5790
+ }
5791
+ var SubscriptionChannelSchema, SubscriptionChannelViewSchema, SubscriptionChannelsStateSchema, SubscriptionChannelGetArgsSchema, SubscriptionChannelSaveArgsSchema, SubscriptionChannelDeleteArgsSchema, SubscriptionChannelActivateArgsSchema;
5792
+ var init_subscription_channel = __esm({
5793
+ "../protocol/src/subscription-channel.ts"() {
5794
+ "use strict";
5795
+ init_zod();
5796
+ SubscriptionChannelSchema = external_exports.object({
5797
+ id: external_exports.string().min(1),
5798
+ name: external_exports.string().min(1),
5799
+ baseUrl: external_exports.string().min(1),
5800
+ apiKey: external_exports.string().min(1),
5801
+ remark: external_exports.string().optional(),
5802
+ createdAt: external_exports.number(),
5803
+ updatedAt: external_exports.number()
5804
+ }).strict();
5805
+ SubscriptionChannelViewSchema = external_exports.object({
5806
+ id: external_exports.string().min(1),
5807
+ name: external_exports.string().min(1),
5808
+ baseUrl: external_exports.string().min(1),
5809
+ remark: external_exports.string().optional(),
5810
+ keyMasked: external_exports.string(),
5811
+ hasKey: external_exports.boolean(),
5812
+ createdAt: external_exports.number(),
5813
+ updatedAt: external_exports.number()
5814
+ }).strict();
5815
+ SubscriptionChannelsStateSchema = external_exports.object({
5816
+ activeChannelId: external_exports.string().nullable(),
5817
+ channels: external_exports.array(SubscriptionChannelViewSchema)
5818
+ }).strict();
5819
+ SubscriptionChannelGetArgsSchema = external_exports.object({}).strict();
5820
+ SubscriptionChannelSaveArgsSchema = external_exports.object({
5821
+ id: external_exports.string().min(1).optional(),
5822
+ name: external_exports.string().min(1),
5823
+ baseUrl: external_exports.string().min(1),
5824
+ apiKey: external_exports.string().optional(),
5825
+ remark: external_exports.string().optional()
5826
+ }).strict();
5827
+ SubscriptionChannelDeleteArgsSchema = external_exports.object({
5828
+ id: external_exports.string().min(1)
5829
+ }).strict();
5830
+ SubscriptionChannelActivateArgsSchema = external_exports.object({
5831
+ id: external_exports.string().min(1).nullable()
5832
+ }).strict();
5833
+ }
5834
+ });
5835
+
5772
5836
  // ../protocol/src/attachment-schemas.ts
5773
5837
  var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema, AttachmentUploadResponseSchema;
5774
5838
  var init_attachment_schemas = __esm({
@@ -6386,8 +6450,11 @@ var init_deploy_schemas = __esm({
6386
6450
  }).strict();
6387
6451
  DeploySetEngineAuthArgsSchema = external_exports.object({
6388
6452
  personaId: external_exports.string().min(1),
6389
- auth: external_exports.object({ baseUrl: external_exports.string(), apiKey: external_exports.string() }).strict().nullable()
6390
- }).strict();
6453
+ channelId: external_exports.string().min(1).optional(),
6454
+ auth: external_exports.object({ baseUrl: external_exports.string(), apiKey: external_exports.string() }).strict().nullable().optional()
6455
+ }).strict().refine((data) => data.channelId !== void 0 || data.auth !== void 0, {
6456
+ message: "Either channelId or auth must be provided"
6457
+ });
6391
6458
  DeployRerunJobArgsSchema = external_exports.object({
6392
6459
  personaId: external_exports.string().min(1),
6393
6460
  /** GitHub 的 job databaseId。**是数字**——字符串会在拼命令时静默出错 */
@@ -8943,6 +9010,7 @@ var init_methods = __esm({
8943
9010
  "use strict";
8944
9011
  init_zod();
8945
9012
  init_esm();
9013
+ init_subscription_channel();
8946
9014
  init_attachment_schemas();
8947
9015
  init_contact_handshake();
8948
9016
  init_deploy_schemas();
@@ -9172,7 +9240,10 @@ var init_methods = __esm({
9172
9240
  },
9173
9241
  "deploy:setEngineAuth": {
9174
9242
  summary: "\u6A21\u578B\u8BA2\u9605\uFF08\u4E91\u4E0A\u8DD1\u8FD9\u4E2A persona \u82B1\u8C01\u7684\u6A21\u578B\u989D\u5EA6\uFF09\uFF1Aauth = { baseUrl, apiKey } \u5199\u8FDB\u4ED3\u5E93 GitHub Secrets \u7684 CLAWD_ENGINE_BASE_URL / CLAWD_ENGINE_API_KEY\uFF08\u5730\u5740\u89C4\u8303\u6210 \u2026/v1\uFF09\uFF0Cnull = \u5220\u8FD9\u4E24\u6761\u3001\u6539\u56DE\u5E73\u53F0\u9ED8\u8BA4\u3002\u4E0B\u6B21\u53D1\u5E03\u751F\u6548\u3002\u540C putSecret \u7684\u7EAA\u5F8B\uFF1A\u5165\u53C2\u4E0D\u8FDB\u65E5\u5FD7\u3001\u54CD\u5E94\u4E0D\u56DE\u663E\u503C\u3001\u672C\u673A\u4E0D\u843D\u76D8\uFF1B\u56DE deploy:get \u540C\u5F62\u7684\u72B6\u6001\uFF1Bowner-only\u3001human-only",
9175
- args: DeploySetEngineAuthArgsSchema
9243
+ args: DeploySetEngineAuthArgsSchema,
9244
+ argsConstraints: {
9245
+ anyOf: [{ required: ["channelId"] }, { required: ["auth"] }]
9246
+ }
9176
9247
  },
9177
9248
  "deploy:reportFinding": {
9178
9249
  summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08cli / secret / asset\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u9875\u9762\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002owner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
@@ -9417,6 +9488,22 @@ var init_methods = __esm({
9417
9488
  summary: "\u67D0\u4E2A\u5F15\u64CE\uFF08claude / codex / pi\uFF09\u7684\u5B89\u88C5\u72B6\u6001 + \u8BA2\u9605 / \u767B\u5F55\u60C5\u51B5\uFF08claude auth status\u3001codex account/read + rateLimits\u3001pi auth.json \u51ED\u636E\u7C7B\u578B\uFF09+ \u6A21\u578B\u8868\u52A0\u8F7D\u65F6\u95F4\u3002\u4E00\u5F8B\u4E0D\u5E26 key / token \u503C\u3002owner-only",
9418
9489
  args: EngineStatusArgs
9419
9490
  },
9491
+ "subscriptionChannel:get": {
9492
+ summary: "\u83B7\u53D6\u672C\u5730\u4FDD\u5B58\u7684\u6240\u6709\u6A21\u578B\u8BA2\u9605\u901A\u9053\u53CA\u5F53\u524D\u6FC0\u6D3B\u901A\u9053\u3002owner-only",
9493
+ args: SubscriptionChannelGetArgsSchema
9494
+ },
9495
+ "subscriptionChannel:save": {
9496
+ summary: "\u521B\u5EFA\u6216\u7F16\u8F91\u6A21\u578B\u8BA2\u9605\u901A\u9053\uFF08\u540D\u79F0\u3001URL\u3001Key\u3001\u5907\u6CE8\uFF09\u3002owner-only",
9497
+ args: SubscriptionChannelSaveArgsSchema
9498
+ },
9499
+ "subscriptionChannel:delete": {
9500
+ summary: "\u5220\u9664\u6307\u5B9A\u7684\u6A21\u578B\u8BA2\u9605\u901A\u9053\u3002owner-only",
9501
+ args: SubscriptionChannelDeleteArgsSchema
9502
+ },
9503
+ "subscriptionChannel:activate": {
9504
+ summary: "\u5207\u6362\u5F53\u524D\u6FC0\u6D3B\u7684\u6A21\u578B\u8BA2\u9605\u901A\u9053\uFF08\u5199 config.toml \u5E76\u5237\u65B0\u6A21\u578B\u8868\uFF09\u3002owner-only",
9505
+ args: SubscriptionChannelActivateArgsSchema
9506
+ },
9420
9507
  "engine:connectPool": {
9421
9508
  summary: "\u63A5\u5165\u53F7\u6C60\uFF1A\u62FF\u81EA\u52A9\u53F0\u53D1\u7684\u4E2A\u4EBA key\uFF0C\u62C9\u53F7\u6C60 setup.sh \u8DD1\u4E00\u904D\uFF08\u5199 ~/.codex/config.toml \u6307\u5411 CLIProxyAPI \u4EE3\u7406\uFF09\uFF0C\u518D\u5237 codex \u6A21\u578B\u8868\u9A8C\u8BC1\u3002\u6210\u529F\u56DE { ok:true }\uFF1B\u62FF\u4E0D\u5230\u811A\u672C / \u811A\u672C\u62A5\u9519 / \u8D85\u65F6 / 401 \u4E00\u5F8B reject \u5E26\u4EBA\u8BDD\u3002\u53EA\u7BA1 codex\uFF1B\u672C\u673A\u6CA1\u88C5 codex \u62A5 INVALID_PARAM\u3002owner-only",
9422
9509
  args: EngineConnectPoolArgs
@@ -9963,6 +10050,7 @@ var init_runtime = __esm({
9963
10050
  init_onboarding_schemas();
9964
10051
  init_engine_schemas();
9965
10052
  init_tool_family();
10053
+ init_subscription_channel();
9966
10054
  }
9967
10055
  });
9968
10056
 
@@ -10237,8 +10325,8 @@ var require_req = __commonJS({
10237
10325
  if (req.originalUrl) {
10238
10326
  _req.url = req.originalUrl;
10239
10327
  } else {
10240
- const path102 = req.path;
10241
- _req.url = typeof path102 === "string" ? path102 : req.url ? req.url.path || req.url : void 0;
10328
+ const path105 = req.path;
10329
+ _req.url = typeof path105 === "string" ? path105 : req.url ? req.url.path || req.url : void 0;
10242
10330
  }
10243
10331
  if (req.query) {
10244
10332
  _req.query = req.query;
@@ -10403,14 +10491,14 @@ var require_redact = __commonJS({
10403
10491
  }
10404
10492
  return obj;
10405
10493
  }
10406
- function parsePath(path102) {
10494
+ function parsePath(path105) {
10407
10495
  const parts = [];
10408
10496
  let current = "";
10409
10497
  let inBrackets = false;
10410
10498
  let inQuotes = false;
10411
10499
  let quoteChar = "";
10412
- for (let i2 = 0; i2 < path102.length; i2++) {
10413
- const char = path102[i2];
10500
+ for (let i2 = 0; i2 < path105.length; i2++) {
10501
+ const char = path105[i2];
10414
10502
  if (!inBrackets && char === ".") {
10415
10503
  if (current) {
10416
10504
  parts.push(current);
@@ -10541,10 +10629,10 @@ var require_redact = __commonJS({
10541
10629
  return current;
10542
10630
  }
10543
10631
  function redactPaths(obj, paths, censor, remove = false) {
10544
- for (const path102 of paths) {
10545
- const parts = parsePath(path102);
10632
+ for (const path105 of paths) {
10633
+ const parts = parsePath(path105);
10546
10634
  if (parts.includes("*")) {
10547
- redactWildcardPath(obj, parts, censor, path102, remove);
10635
+ redactWildcardPath(obj, parts, censor, path105, remove);
10548
10636
  } else {
10549
10637
  if (remove) {
10550
10638
  removeKey(obj, parts);
@@ -10629,8 +10717,8 @@ var require_redact = __commonJS({
10629
10717
  }
10630
10718
  } else {
10631
10719
  if (afterWildcard.includes("*")) {
10632
- const wrappedCensor = typeof censor === "function" ? (value, path102) => {
10633
- const fullPath = [...pathArray.slice(0, pathLength), ...path102];
10720
+ const wrappedCensor = typeof censor === "function" ? (value, path105) => {
10721
+ const fullPath = [...pathArray.slice(0, pathLength), ...path105];
10634
10722
  return censor(value, fullPath);
10635
10723
  } : censor;
10636
10724
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10665,8 +10753,8 @@ var require_redact = __commonJS({
10665
10753
  return null;
10666
10754
  }
10667
10755
  const pathStructure = /* @__PURE__ */ new Map();
10668
- for (const path102 of pathsToClone) {
10669
- const parts = parsePath(path102);
10756
+ for (const path105 of pathsToClone) {
10757
+ const parts = parsePath(path105);
10670
10758
  let current = pathStructure;
10671
10759
  for (let i2 = 0; i2 < parts.length; i2++) {
10672
10760
  const part = parts[i2];
@@ -10718,24 +10806,24 @@ var require_redact = __commonJS({
10718
10806
  }
10719
10807
  return cloneSelectively(obj, pathStructure);
10720
10808
  }
10721
- function validatePath(path102) {
10722
- if (typeof path102 !== "string") {
10809
+ function validatePath(path105) {
10810
+ if (typeof path105 !== "string") {
10723
10811
  throw new Error("Paths must be (non-empty) strings");
10724
10812
  }
10725
- if (path102 === "") {
10813
+ if (path105 === "") {
10726
10814
  throw new Error("Invalid redaction path ()");
10727
10815
  }
10728
- if (path102.includes("..")) {
10729
- throw new Error(`Invalid redaction path (${path102})`);
10816
+ if (path105.includes("..")) {
10817
+ throw new Error(`Invalid redaction path (${path105})`);
10730
10818
  }
10731
- if (path102.includes(",")) {
10732
- throw new Error(`Invalid redaction path (${path102})`);
10819
+ if (path105.includes(",")) {
10820
+ throw new Error(`Invalid redaction path (${path105})`);
10733
10821
  }
10734
10822
  let bracketCount = 0;
10735
10823
  let inQuotes = false;
10736
10824
  let quoteChar = "";
10737
- for (let i2 = 0; i2 < path102.length; i2++) {
10738
- const char = path102[i2];
10825
+ for (let i2 = 0; i2 < path105.length; i2++) {
10826
+ const char = path105[i2];
10739
10827
  if ((char === '"' || char === "'") && bracketCount > 0) {
10740
10828
  if (!inQuotes) {
10741
10829
  inQuotes = true;
@@ -10749,20 +10837,20 @@ var require_redact = __commonJS({
10749
10837
  } else if (char === "]" && !inQuotes) {
10750
10838
  bracketCount--;
10751
10839
  if (bracketCount < 0) {
10752
- throw new Error(`Invalid redaction path (${path102})`);
10840
+ throw new Error(`Invalid redaction path (${path105})`);
10753
10841
  }
10754
10842
  }
10755
10843
  }
10756
10844
  if (bracketCount !== 0) {
10757
- throw new Error(`Invalid redaction path (${path102})`);
10845
+ throw new Error(`Invalid redaction path (${path105})`);
10758
10846
  }
10759
10847
  }
10760
10848
  function validatePaths(paths) {
10761
10849
  if (!Array.isArray(paths)) {
10762
10850
  throw new TypeError("paths must be an array");
10763
10851
  }
10764
- for (const path102 of paths) {
10765
- validatePath(path102);
10852
+ for (const path105 of paths) {
10853
+ validatePath(path105);
10766
10854
  }
10767
10855
  }
10768
10856
  function slowRedact(options = {}) {
@@ -10930,8 +11018,8 @@ var require_redaction = __commonJS({
10930
11018
  if (shape[k3] === null) {
10931
11019
  o2[k3] = (value) => topCensor(value, [k3]);
10932
11020
  } else {
10933
- const wrappedCensor = typeof censor === "function" ? (value, path102) => {
10934
- return censor(value, [k3, ...path102]);
11021
+ const wrappedCensor = typeof censor === "function" ? (value, path105) => {
11022
+ return censor(value, [k3, ...path105]);
10935
11023
  } : censor;
10936
11024
  o2[k3] = Redact({
10937
11025
  paths: shape[k3],
@@ -11149,10 +11237,10 @@ var require_atomic_sleep = __commonJS({
11149
11237
  var require_sonic_boom = __commonJS({
11150
11238
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
11151
11239
  "use strict";
11152
- var fs92 = require("fs");
11240
+ var fs95 = require("fs");
11153
11241
  var EventEmitter2 = require("events");
11154
11242
  var inherits = require("util").inherits;
11155
- var path102 = require("path");
11243
+ var path105 = require("path");
11156
11244
  var sleep2 = require_atomic_sleep();
11157
11245
  var assert = require("assert");
11158
11246
  var BUSY_WRITE_TIMEOUT = 100;
@@ -11206,20 +11294,20 @@ var require_sonic_boom = __commonJS({
11206
11294
  const mode = sonic.mode;
11207
11295
  if (sonic.sync) {
11208
11296
  try {
11209
- if (sonic.mkdir) fs92.mkdirSync(path102.dirname(file), { recursive: true });
11210
- const fd = fs92.openSync(file, flags, mode);
11297
+ if (sonic.mkdir) fs95.mkdirSync(path105.dirname(file), { recursive: true });
11298
+ const fd = fs95.openSync(file, flags, mode);
11211
11299
  fileOpened(null, fd);
11212
11300
  } catch (err) {
11213
11301
  fileOpened(err);
11214
11302
  throw err;
11215
11303
  }
11216
11304
  } else if (sonic.mkdir) {
11217
- fs92.mkdir(path102.dirname(file), { recursive: true }, (err) => {
11305
+ fs95.mkdir(path105.dirname(file), { recursive: true }, (err) => {
11218
11306
  if (err) return fileOpened(err);
11219
- fs92.open(file, flags, mode, fileOpened);
11307
+ fs95.open(file, flags, mode, fileOpened);
11220
11308
  });
11221
11309
  } else {
11222
- fs92.open(file, flags, mode, fileOpened);
11310
+ fs95.open(file, flags, mode, fileOpened);
11223
11311
  }
11224
11312
  }
11225
11313
  function SonicBoom(opts) {
@@ -11260,8 +11348,8 @@ var require_sonic_boom = __commonJS({
11260
11348
  this.flush = flushBuffer;
11261
11349
  this.flushSync = flushBufferSync;
11262
11350
  this._actualWrite = actualWriteBuffer;
11263
- fsWriteSync = () => fs92.writeSync(this.fd, this._writingBuf);
11264
- fsWrite = () => fs92.write(this.fd, this._writingBuf, this.release);
11351
+ fsWriteSync = () => fs95.writeSync(this.fd, this._writingBuf);
11352
+ fsWrite = () => fs95.write(this.fd, this._writingBuf, this.release);
11265
11353
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
11266
11354
  this._writingBuf = "";
11267
11355
  this.write = write;
@@ -11270,15 +11358,15 @@ var require_sonic_boom = __commonJS({
11270
11358
  this._actualWrite = actualWrite;
11271
11359
  fsWriteSync = () => {
11272
11360
  if (Buffer.isBuffer(this._writingBuf)) {
11273
- return fs92.writeSync(this.fd, this._writingBuf);
11361
+ return fs95.writeSync(this.fd, this._writingBuf);
11274
11362
  }
11275
- return fs92.writeSync(this.fd, this._writingBuf, "utf8");
11363
+ return fs95.writeSync(this.fd, this._writingBuf, "utf8");
11276
11364
  };
11277
11365
  fsWrite = () => {
11278
11366
  if (Buffer.isBuffer(this._writingBuf)) {
11279
- return fs92.write(this.fd, this._writingBuf, this.release);
11367
+ return fs95.write(this.fd, this._writingBuf, this.release);
11280
11368
  }
11281
- return fs92.write(this.fd, this._writingBuf, "utf8", this.release);
11369
+ return fs95.write(this.fd, this._writingBuf, "utf8", this.release);
11282
11370
  };
11283
11371
  } else {
11284
11372
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -11335,7 +11423,7 @@ var require_sonic_boom = __commonJS({
11335
11423
  }
11336
11424
  }
11337
11425
  if (this._fsync) {
11338
- fs92.fsyncSync(this.fd);
11426
+ fs95.fsyncSync(this.fd);
11339
11427
  }
11340
11428
  const len = this._len;
11341
11429
  if (this._reopening) {
@@ -11449,7 +11537,7 @@ var require_sonic_boom = __commonJS({
11449
11537
  const onDrain = () => {
11450
11538
  if (!this._fsync) {
11451
11539
  try {
11452
- fs92.fsync(this.fd, (err) => {
11540
+ fs95.fsync(this.fd, (err) => {
11453
11541
  this._flushPending = false;
11454
11542
  cb(err);
11455
11543
  });
@@ -11551,7 +11639,7 @@ var require_sonic_boom = __commonJS({
11551
11639
  const fd = this.fd;
11552
11640
  this.once("ready", () => {
11553
11641
  if (fd !== this.fd) {
11554
- fs92.close(fd, (err) => {
11642
+ fs95.close(fd, (err) => {
11555
11643
  if (err) {
11556
11644
  return this.emit("error", err);
11557
11645
  }
@@ -11600,7 +11688,7 @@ var require_sonic_boom = __commonJS({
11600
11688
  buf = this._bufs[0];
11601
11689
  }
11602
11690
  try {
11603
- const n2 = Buffer.isBuffer(buf) ? fs92.writeSync(this.fd, buf) : fs92.writeSync(this.fd, buf, "utf8");
11691
+ const n2 = Buffer.isBuffer(buf) ? fs95.writeSync(this.fd, buf) : fs95.writeSync(this.fd, buf, "utf8");
11604
11692
  const releasedBufObj = releaseWritingBuf(buf, this._len, n2);
11605
11693
  buf = releasedBufObj.writingBuf;
11606
11694
  this._len = releasedBufObj.len;
@@ -11616,7 +11704,7 @@ var require_sonic_boom = __commonJS({
11616
11704
  }
11617
11705
  }
11618
11706
  try {
11619
- fs92.fsyncSync(this.fd);
11707
+ fs95.fsyncSync(this.fd);
11620
11708
  } catch {
11621
11709
  }
11622
11710
  }
@@ -11637,7 +11725,7 @@ var require_sonic_boom = __commonJS({
11637
11725
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11638
11726
  }
11639
11727
  try {
11640
- const n2 = fs92.writeSync(this.fd, buf);
11728
+ const n2 = fs95.writeSync(this.fd, buf);
11641
11729
  buf = buf.subarray(n2);
11642
11730
  this._len = Math.max(this._len - n2, 0);
11643
11731
  if (buf.length <= 0) {
@@ -11665,13 +11753,13 @@ var require_sonic_boom = __commonJS({
11665
11753
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11666
11754
  if (this.sync) {
11667
11755
  try {
11668
- const written = Buffer.isBuffer(this._writingBuf) ? fs92.writeSync(this.fd, this._writingBuf) : fs92.writeSync(this.fd, this._writingBuf, "utf8");
11756
+ const written = Buffer.isBuffer(this._writingBuf) ? fs95.writeSync(this.fd, this._writingBuf) : fs95.writeSync(this.fd, this._writingBuf, "utf8");
11669
11757
  release2(null, written);
11670
11758
  } catch (err) {
11671
11759
  release2(err);
11672
11760
  }
11673
11761
  } else {
11674
- fs92.write(this.fd, this._writingBuf, release2);
11762
+ fs95.write(this.fd, this._writingBuf, release2);
11675
11763
  }
11676
11764
  }
11677
11765
  function actualWriteBuffer() {
@@ -11680,7 +11768,7 @@ var require_sonic_boom = __commonJS({
11680
11768
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11681
11769
  if (this.sync) {
11682
11770
  try {
11683
- const written = fs92.writeSync(this.fd, this._writingBuf);
11771
+ const written = fs95.writeSync(this.fd, this._writingBuf);
11684
11772
  release2(null, written);
11685
11773
  } catch (err) {
11686
11774
  release2(err);
@@ -11689,7 +11777,7 @@ var require_sonic_boom = __commonJS({
11689
11777
  if (kCopyBuffer) {
11690
11778
  this._writingBuf = Buffer.from(this._writingBuf);
11691
11779
  }
11692
- fs92.write(this.fd, this._writingBuf, release2);
11780
+ fs95.write(this.fd, this._writingBuf, release2);
11693
11781
  }
11694
11782
  }
11695
11783
  function actualClose(sonic) {
@@ -11705,12 +11793,12 @@ var require_sonic_boom = __commonJS({
11705
11793
  sonic._lens = [];
11706
11794
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11707
11795
  try {
11708
- fs92.fsync(sonic.fd, closeWrapped);
11796
+ fs95.fsync(sonic.fd, closeWrapped);
11709
11797
  } catch {
11710
11798
  }
11711
11799
  function closeWrapped() {
11712
11800
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11713
- fs92.close(sonic.fd, done);
11801
+ fs95.close(sonic.fd, done);
11714
11802
  } else {
11715
11803
  done();
11716
11804
  }
@@ -14074,7 +14162,7 @@ var require_multistream = __commonJS({
14074
14162
  var require_pino = __commonJS({
14075
14163
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
14076
14164
  "use strict";
14077
- var os34 = require("os");
14165
+ var os37 = require("os");
14078
14166
  var stdSerializers = require_pino_std_serializers();
14079
14167
  var caller = require_caller();
14080
14168
  var redaction = require_redaction();
@@ -14121,7 +14209,7 @@ var require_pino = __commonJS({
14121
14209
  } = symbols;
14122
14210
  var { epochTime, nullTime } = time;
14123
14211
  var { pid } = process;
14124
- var hostname = os34.hostname();
14212
+ var hostname = os37.hostname();
14125
14213
  var defaultErrorSerializer = stdSerializers.err;
14126
14214
  var defaultOptions2 = {
14127
14215
  level: "info",
@@ -14845,11 +14933,11 @@ var init_lib = __esm({
14845
14933
  }
14846
14934
  }
14847
14935
  },
14848
- addToPath: function addToPath(path102, added, removed, oldPosInc, options) {
14849
- var last = path102.lastComponent;
14936
+ addToPath: function addToPath(path105, added, removed, oldPosInc, options) {
14937
+ var last = path105.lastComponent;
14850
14938
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14851
14939
  return {
14852
- oldPos: path102.oldPos + oldPosInc,
14940
+ oldPos: path105.oldPos + oldPosInc,
14853
14941
  lastComponent: {
14854
14942
  count: last.count + 1,
14855
14943
  added,
@@ -14859,7 +14947,7 @@ var init_lib = __esm({
14859
14947
  };
14860
14948
  } else {
14861
14949
  return {
14862
- oldPos: path102.oldPos + oldPosInc,
14950
+ oldPos: path105.oldPos + oldPosInc,
14863
14951
  lastComponent: {
14864
14952
  count: 1,
14865
14953
  added,
@@ -15441,10 +15529,10 @@ function attachmentToHistoryMessage(o2, ts) {
15441
15529
  const memories = raw.map((m3) => {
15442
15530
  if (!m3 || typeof m3 !== "object") return null;
15443
15531
  const rec6 = m3;
15444
- const path102 = typeof rec6.path === "string" ? rec6.path : null;
15532
+ const path105 = typeof rec6.path === "string" ? rec6.path : null;
15445
15533
  const content = typeof rec6.content === "string" ? rec6.content : null;
15446
- if (!path102 || content == null) return null;
15447
- const entry = { path: path102, content };
15534
+ if (!path105 || content == null) return null;
15535
+ const entry = { path: path105, content };
15448
15536
  if (typeof rec6.mtimeMs === "number") entry.mtimeMs = rec6.mtimeMs;
15449
15537
  return entry;
15450
15538
  }).filter((m3) => m3 !== null);
@@ -16310,10 +16398,10 @@ function parseAttachment(obj) {
16310
16398
  const memories = raw.map((m3) => {
16311
16399
  if (!m3 || typeof m3 !== "object") return null;
16312
16400
  const rec6 = m3;
16313
- const path102 = typeof rec6.path === "string" ? rec6.path : null;
16401
+ const path105 = typeof rec6.path === "string" ? rec6.path : null;
16314
16402
  const content = typeof rec6.content === "string" ? rec6.content : null;
16315
- if (!path102 || content == null) return null;
16316
- const out = { path: path102, content };
16403
+ if (!path105 || content == null) return null;
16404
+ const out = { path: path105, content };
16317
16405
  if (typeof rec6.mtimeMs === "number") out.mtimeMs = rec6.mtimeMs;
16318
16406
  return out;
16319
16407
  }).filter((m3) => m3 !== null);
@@ -37287,8 +37375,8 @@ var require_utils = __commonJS({
37287
37375
  var result = transform[inputType][outputType](input);
37288
37376
  return result;
37289
37377
  };
37290
- exports2.resolve = function(path102) {
37291
- var parts = path102.split("/");
37378
+ exports2.resolve = function(path105) {
37379
+ var parts = path105.split("/");
37292
37380
  var result = [];
37293
37381
  for (var index = 0; index < parts.length; index++) {
37294
37382
  var part = parts[index];
@@ -43141,18 +43229,18 @@ var require_object = __commonJS({
43141
43229
  var object = new ZipObject(name, zipObjectContent, o2);
43142
43230
  this.files[name] = object;
43143
43231
  };
43144
- var parentFolder = function(path102) {
43145
- if (path102.slice(-1) === "/") {
43146
- path102 = path102.substring(0, path102.length - 1);
43232
+ var parentFolder = function(path105) {
43233
+ if (path105.slice(-1) === "/") {
43234
+ path105 = path105.substring(0, path105.length - 1);
43147
43235
  }
43148
- var lastSlash = path102.lastIndexOf("/");
43149
- return lastSlash > 0 ? path102.substring(0, lastSlash) : "";
43236
+ var lastSlash = path105.lastIndexOf("/");
43237
+ return lastSlash > 0 ? path105.substring(0, lastSlash) : "";
43150
43238
  };
43151
- var forceTrailingSlash = function(path102) {
43152
- if (path102.slice(-1) !== "/") {
43153
- path102 += "/";
43239
+ var forceTrailingSlash = function(path105) {
43240
+ if (path105.slice(-1) !== "/") {
43241
+ path105 += "/";
43154
43242
  }
43155
- return path102;
43243
+ return path105;
43156
43244
  };
43157
43245
  var folderAdd = function(name, createFolders) {
43158
43246
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -44154,7 +44242,7 @@ var require_lib3 = __commonJS({
44154
44242
  // src/run-case/recorder.ts
44155
44243
  function startRunCaseRecorder(opts) {
44156
44244
  const now = opts.now ?? Date.now;
44157
- const dir = import_node_path81.default.dirname(opts.recordPath);
44245
+ const dir = import_node_path84.default.dirname(opts.recordPath);
44158
44246
  let stream = null;
44159
44247
  let closing = false;
44160
44248
  let closedSettled = false;
@@ -44168,8 +44256,8 @@ function startRunCaseRecorder(opts) {
44168
44256
  });
44169
44257
  const ensureStream = () => {
44170
44258
  if (stream) return stream;
44171
- import_node_fs63.default.mkdirSync(dir, { recursive: true });
44172
- stream = import_node_fs63.default.createWriteStream(opts.recordPath, { flags: "a" });
44259
+ import_node_fs66.default.mkdirSync(dir, { recursive: true });
44260
+ stream = import_node_fs66.default.createWriteStream(opts.recordPath, { flags: "a" });
44173
44261
  stream.on("close", () => closedResolve());
44174
44262
  return stream;
44175
44263
  };
@@ -44194,12 +44282,12 @@ function startRunCaseRecorder(opts) {
44194
44282
  };
44195
44283
  return { tap, close, closed };
44196
44284
  }
44197
- var import_node_fs63, import_node_path81;
44285
+ var import_node_fs66, import_node_path84;
44198
44286
  var init_recorder = __esm({
44199
44287
  "src/run-case/recorder.ts"() {
44200
44288
  "use strict";
44201
- import_node_fs63 = __toESM(require("fs"), 1);
44202
- import_node_path81 = __toESM(require("path"), 1);
44289
+ import_node_fs66 = __toESM(require("fs"), 1);
44290
+ import_node_path84 = __toESM(require("path"), 1);
44203
44291
  }
44204
44292
  });
44205
44293
 
@@ -44242,7 +44330,7 @@ var init_wire = __esm({
44242
44330
  // src/run-case/controller.ts
44243
44331
  async function runController(opts) {
44244
44332
  const now = opts.now ?? Date.now;
44245
- const cwd = opts.cwd ?? (0, import_node_fs64.mkdtempSync)(import_node_path82.default.join(import_node_os30.default.tmpdir(), "clawd-runcase-"));
44333
+ const cwd = opts.cwd ?? (0, import_node_fs67.mkdtempSync)(import_node_path85.default.join(import_node_os33.default.tmpdir(), "clawd-runcase-"));
44246
44334
  const ownsCwd = opts.cwd === void 0;
44247
44335
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
44248
44336
  const spawnCtx = { cwd };
@@ -44403,19 +44491,19 @@ async function runController(opts) {
44403
44491
  if (sigintHandler) process.off("SIGINT", sigintHandler);
44404
44492
  if (ownsCwd) {
44405
44493
  try {
44406
- (0, import_node_fs64.rmSync)(cwd, { recursive: true, force: true });
44494
+ (0, import_node_fs67.rmSync)(cwd, { recursive: true, force: true });
44407
44495
  } catch {
44408
44496
  }
44409
44497
  }
44410
44498
  return exitCode ?? 0;
44411
44499
  }
44412
- var import_node_fs64, import_node_os30, import_node_path82;
44500
+ var import_node_fs67, import_node_os33, import_node_path85;
44413
44501
  var init_controller = __esm({
44414
44502
  "src/run-case/controller.ts"() {
44415
44503
  "use strict";
44416
- import_node_fs64 = require("fs");
44417
- import_node_os30 = __toESM(require("os"), 1);
44418
- import_node_path82 = __toESM(require("path"), 1);
44504
+ import_node_fs67 = require("fs");
44505
+ import_node_os33 = __toESM(require("os"), 1);
44506
+ import_node_path85 = __toESM(require("path"), 1);
44419
44507
  init_claude();
44420
44508
  init_stdout_splitter();
44421
44509
  init_permission_stdio();
@@ -44687,9 +44775,9 @@ Env (advanced):
44687
44775
  `;
44688
44776
 
44689
44777
  // src/index.ts
44690
- var import_node_path80 = __toESM(require("path"), 1);
44691
- var import_node_fs62 = __toESM(require("fs"), 1);
44692
- var import_node_os29 = __toESM(require("os"), 1);
44778
+ var import_node_path83 = __toESM(require("path"), 1);
44779
+ var import_node_fs65 = __toESM(require("fs"), 1);
44780
+ var import_node_os32 = __toESM(require("os"), 1);
44693
44781
  var import_node_crypto26 = require("crypto");
44694
44782
  var import_node_url6 = require("url");
44695
44783
 
@@ -52435,9 +52523,9 @@ var CentralClientError = class extends Error {
52435
52523
  cause;
52436
52524
  status;
52437
52525
  };
52438
- async function centralRequest(opts, path102, init) {
52526
+ async function centralRequest(opts, path105, init) {
52439
52527
  const f2 = opts.fetchImpl ?? globalThis.fetch;
52440
- const url = `${opts.api.replace(/\/+$/, "")}${path102}`;
52528
+ const url = `${opts.api.replace(/\/+$/, "")}${path105}`;
52441
52529
  const ctrl = new AbortController();
52442
52530
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
52443
52531
  let res;
@@ -53471,8 +53559,8 @@ function turnStartInput(text, resolveImage) {
53471
53559
  const items = [];
53472
53560
  let leftover = text;
53473
53561
  for (const m3 of text.matchAll(SKILL_RE)) {
53474
- const [marker, name, path102] = m3;
53475
- items.push({ type: "skill", name, path: path102 });
53562
+ const [marker, name, path105] = m3;
53563
+ items.push({ type: "skill", name, path: path105 });
53476
53564
  leftover = leftover.replace(marker, "");
53477
53565
  }
53478
53566
  for (const m3 of text.matchAll(ATTACHMENT_RE2)) {
@@ -56775,9 +56863,15 @@ function createShiftSpawnFn(deps) {
56775
56863
  }
56776
56864
 
56777
56865
  // src/handlers/types.ts
56866
+ init_zod();
56778
56867
  init_protocol();
56779
56868
  function parseArgs2(schema, frame, what, code = ERROR_CODES.VALIDATION_ERROR) {
56780
- const effective = typeof schema.strip === "function" ? schema.strip() : schema;
56869
+ let effective = schema;
56870
+ if (typeof schema.strip === "function") {
56871
+ effective = schema.strip();
56872
+ } else if (schema instanceof external_exports.ZodEffects && typeof schema._def?.schema?.strip === "function") {
56873
+ effective = new external_exports.ZodEffects({ ...schema._def, schema: schema._def.schema.strip() });
56874
+ }
56781
56875
  const r2 = effective.safeParse(frame);
56782
56876
  if (!r2.success) throw new ClawdError(code, `${what}: ${r2.error.message}`);
56783
56877
  return r2.data;
@@ -60839,10 +60933,10 @@ function createGithubApi(args) {
60839
60933
  const doFetch = args.fetch ?? fetch;
60840
60934
  const seal = args.seal ?? sealWithSodium;
60841
60935
  const timeoutMs = args.timeoutMs ?? TIMEOUT_MS;
60842
- async function request(method, path102, body) {
60936
+ async function request(method, path105, body) {
60843
60937
  let res;
60844
60938
  try {
60845
- res = await doFetch(`${API}${path102}`, {
60939
+ res = await doFetch(`${API}${path105}`, {
60846
60940
  method,
60847
60941
  headers: {
60848
60942
  Authorization: `Bearer ${args.token}`,
@@ -60867,8 +60961,8 @@ function createGithubApi(args) {
60867
60961
  }
60868
60962
  return { status: res.status, json };
60869
60963
  }
60870
- async function must(method, path102, what, body) {
60871
- const r2 = await request(method, path102, body);
60964
+ async function must(method, path105, what, body) {
60965
+ const r2 = await request(method, path105, body);
60872
60966
  if (r2.status < 200 || r2.status >= 300) throw new GithubApiError(r2.status, explain(r2.status, what, r2.json));
60873
60967
  return r2.json;
60874
60968
  }
@@ -60913,9 +61007,9 @@ function createGithubApi(args) {
60913
61007
  return { env: x2.name, ...Number.isFinite(at3) ? { setAt: at3 } : {} };
60914
61008
  });
60915
61009
  },
60916
- async getJson(path102) {
61010
+ async getJson(path105) {
60917
61011
  try {
60918
- const r2 = await request("GET", path102);
61012
+ const r2 = await request("GET", path105);
60919
61013
  return r2.status >= 200 && r2.status < 300 ? r2.json : void 0;
60920
61014
  } catch {
60921
61015
  return void 0;
@@ -61903,15 +61997,21 @@ function buildDeployHandlers(deps) {
61903
61997
  ensureOwner(ctx);
61904
61998
  const args = parseArgs2(DeploySetEngineAuthArgsSchema, frame, "deploy:setEngineAuth");
61905
61999
  const dir = mustPersona(args.personaId);
62000
+ let auth = args.auth;
62001
+ if (args.channelId) {
62002
+ const channel = deps.channelStore?.get(args.channelId);
62003
+ if (!channel) throw invalid(`\u672A\u627E\u5230 ID \u4E3A ${args.channelId} \u7684\u8BA2\u9605\u901A\u9053`);
62004
+ auth = { baseUrl: channel.baseUrl, apiKey: channel.apiKey };
62005
+ }
61906
62006
  let writes;
61907
- if (args.auth) {
62007
+ if (auth) {
61908
62008
  let baseUrl;
61909
62009
  try {
61910
- baseUrl = normalizeEngineBaseUrl(args.auth.baseUrl);
62010
+ baseUrl = normalizeEngineBaseUrl(auth.baseUrl);
61911
62011
  } catch (err) {
61912
62012
  throw invalid(err instanceof Error ? err.message : String(err));
61913
62013
  }
61914
- const apiKey = args.auth.apiKey.trim();
62014
+ const apiKey = auth.apiKey.trim();
61915
62015
  if (!apiKey) throw invalid("key \u4E0D\u80FD\u662F\u7A7A\u7684");
61916
62016
  if (/[\s\p{Cc}]/u.test(apiKey)) throw invalid("key \u91CC\u4E0D\u80FD\u6709\u7A7A\u767D\u6216\u63A7\u5236\u5B57\u7B26\uFF08\u591A\u534A\u662F\u7C98\u8D34\u65F6\u5E26\u8FDB\u4E86\u6362\u884C\u6216\u7A7A\u683C\uFF09");
61917
62017
  writes = [[ENGINE_AUTH_SECRETS.apiKey, apiKey], [ENGINE_AUTH_SECRETS.baseUrl, baseUrl]];
@@ -62166,6 +62266,188 @@ function buildDeployHandlers(deps) {
62166
62266
  };
62167
62267
  }
62168
62268
 
62269
+ // src/tools/subscription-channels-store.ts
62270
+ var import_node_fs35 = __toESM(require("fs"), 1);
62271
+ var import_node_os12 = __toESM(require("os"), 1);
62272
+ var import_node_path40 = __toESM(require("path"), 1);
62273
+ var CHANNELS_FILE_NAME = "subscription-channels.json";
62274
+ function providerSection(content) {
62275
+ const header = /^\[model_providers\.cliproxyapi\][^\n]*(?:\n|$)/m.exec(content);
62276
+ if (!header) return null;
62277
+ const body = content.slice(header.index + header[0].length);
62278
+ const nextHeader = body.search(/^\[/m);
62279
+ return nextHeader < 0 ? body : body.slice(0, nextHeader);
62280
+ }
62281
+ function readAuthKey2(codexHome) {
62282
+ try {
62283
+ const key = JSON.parse(import_node_fs35.default.readFileSync(import_node_path40.default.join(codexHome, "auth.json"), "utf8")).OPENAI_API_KEY;
62284
+ return typeof key === "string" && key ? key : null;
62285
+ } catch {
62286
+ return null;
62287
+ }
62288
+ }
62289
+ var SubscriptionChannelStore = class {
62290
+ filePath;
62291
+ codexHome;
62292
+ constructor(options) {
62293
+ this.filePath = import_node_path40.default.join(options.dataDir, CHANNELS_FILE_NAME);
62294
+ this.codexHome = options.codexHome || process.env.CODEX_HOME || import_node_path40.default.join(import_node_os12.default.homedir(), ".codex");
62295
+ }
62296
+ /** 获取列表与激活通道 ID(Key 经脱敏掩码) */
62297
+ list() {
62298
+ const data = this.readOrCreate();
62299
+ return {
62300
+ activeChannelId: data.activeChannelId,
62301
+ channels: data.channels.map(toChannelView)
62302
+ };
62303
+ }
62304
+ /** 获取通道原始实体(含明文 Key,供配置应用与部署写入使用) */
62305
+ get(id) {
62306
+ const data = this.readOrCreate();
62307
+ return data.channels.find((c2) => c2.id === id) ?? null;
62308
+ }
62309
+ /** 获取当前激活的通道实体 */
62310
+ getActive() {
62311
+ const data = this.readOrCreate();
62312
+ if (!data.activeChannelId) return null;
62313
+ return data.channels.find((c2) => c2.id === data.activeChannelId) ?? null;
62314
+ }
62315
+ /** 保存(新增或更新)通道 */
62316
+ save(input) {
62317
+ const name = input.name.trim();
62318
+ if (!name) throw new Error("\u901A\u9053\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
62319
+ let baseUrl;
62320
+ try {
62321
+ baseUrl = normalizeEngineBaseUrl(input.baseUrl);
62322
+ } catch (err) {
62323
+ throw new Error(err instanceof Error ? err.message : String(err));
62324
+ }
62325
+ const data = this.readOrCreate();
62326
+ const now = Date.now();
62327
+ if (input.id) {
62328
+ const idx = data.channels.findIndex((c2) => c2.id === input.id);
62329
+ if (idx === -1) throw new Error(`\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u901A\u9053`);
62330
+ const existing = data.channels[idx];
62331
+ const apiKey2 = input.apiKey && input.apiKey.trim() ? input.apiKey.trim() : existing.apiKey;
62332
+ const updated = {
62333
+ ...existing,
62334
+ name,
62335
+ baseUrl,
62336
+ apiKey: apiKey2,
62337
+ ...input.remark !== void 0 ? { remark: input.remark.trim() || void 0 } : {},
62338
+ updatedAt: now
62339
+ };
62340
+ data.channels[idx] = updated;
62341
+ this.write(data);
62342
+ return updated;
62343
+ }
62344
+ const apiKey = input.apiKey?.trim();
62345
+ if (!apiKey) throw new Error("\u65B0\u5EFA\u901A\u9053\u5FC5\u987B\u586B\u5199 API Key");
62346
+ const newId = `chan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
62347
+ const newChannel = {
62348
+ id: newId,
62349
+ name,
62350
+ baseUrl,
62351
+ apiKey,
62352
+ ...input.remark && input.remark.trim() ? { remark: input.remark.trim() } : {},
62353
+ createdAt: now,
62354
+ updatedAt: now
62355
+ };
62356
+ data.channels.push(newChannel);
62357
+ if (data.channels.length === 1 && !data.activeChannelId) {
62358
+ data.activeChannelId = newChannel.id;
62359
+ }
62360
+ this.write(data);
62361
+ return newChannel;
62362
+ }
62363
+ /** 删除通道 */
62364
+ delete(id) {
62365
+ const data = this.readOrCreate();
62366
+ const filtered = data.channels.filter((c2) => c2.id !== id);
62367
+ if (filtered.length === data.channels.length) return;
62368
+ data.channels = filtered;
62369
+ if (data.activeChannelId === id) {
62370
+ data.activeChannelId = data.channels.length > 0 ? data.channels[0].id : null;
62371
+ }
62372
+ this.write(data);
62373
+ }
62374
+ /** 设置当前激活通道(id 为 null 表示停用所有通道) */
62375
+ setActive(id) {
62376
+ const data = this.readOrCreate();
62377
+ if (id === null) {
62378
+ data.activeChannelId = null;
62379
+ this.write(data);
62380
+ return null;
62381
+ }
62382
+ const target = data.channels.find((c2) => c2.id === id);
62383
+ if (!target) throw new Error(`\u901A\u9053 ${id} \u4E0D\u5B58\u5728`);
62384
+ data.activeChannelId = id;
62385
+ this.write(data);
62386
+ return target;
62387
+ }
62388
+ readOrCreate() {
62389
+ if (import_node_fs35.default.existsSync(this.filePath)) {
62390
+ try {
62391
+ const raw = JSON.parse(import_node_fs35.default.readFileSync(this.filePath, "utf8"));
62392
+ if (raw && Array.isArray(raw.channels)) {
62393
+ return {
62394
+ activeChannelId: typeof raw.activeChannelId === "string" ? raw.activeChannelId : null,
62395
+ channels: raw.channels
62396
+ };
62397
+ }
62398
+ } catch {
62399
+ }
62400
+ }
62401
+ const migrated = this.tryMigrateFromCodexConfig();
62402
+ const initial = migrated ?? {
62403
+ activeChannelId: null,
62404
+ channels: []
62405
+ };
62406
+ this.write(initial);
62407
+ return initial;
62408
+ }
62409
+ tryMigrateFromCodexConfig() {
62410
+ try {
62411
+ const configPath = import_node_path40.default.join(this.codexHome, "config.toml");
62412
+ if (!import_node_fs35.default.existsSync(configPath)) return null;
62413
+ const content = import_node_fs35.default.readFileSync(configPath, "utf8");
62414
+ if (!content.includes('model_provider = "cliproxyapi"')) return null;
62415
+ const section = providerSection(content);
62416
+ if (!section) return null;
62417
+ const urlMatch = /^\s*base_url\s*=\s*["']([^"']+)["']/m.exec(section);
62418
+ const echoKey = /^\s*auth\s*=\s*\{\s*command\s*=\s*["']echo["']\s*,\s*args\s*=\s*\[\s*["']([^"']+)["']\s*\]/m.exec(section)?.[1];
62419
+ const inlineKey = /^\s*experimental_bearer_token\s*=\s*["']([^"']+)["']/m.exec(section)?.[1];
62420
+ const envKey = /^\s*env_key\s*=\s*["']([^"']+)["']/m.exec(section)?.[1];
62421
+ const key = echoKey ?? inlineKey ?? (envKey ? process.env[envKey] : !/^\s*auth\s*=/m.test(section) ? readAuthKey2(this.codexHome) : null);
62422
+ if (urlMatch && key) {
62423
+ const id = "default-pool";
62424
+ const channel = {
62425
+ id,
62426
+ name: "\u9ED8\u8BA4\u56E2\u961F\u53F7\u6C60",
62427
+ baseUrl: normalizeEngineBaseUrl(urlMatch[1]),
62428
+ apiKey: key,
62429
+ remark: "\u4ECE\u672C\u673A\u5DF2\u63A5\u5165\u7684\u53F7\u6C60\u914D\u7F6E\u81EA\u52A8\u8FC1\u79FB",
62430
+ createdAt: Date.now(),
62431
+ updatedAt: Date.now()
62432
+ };
62433
+ return {
62434
+ activeChannelId: id,
62435
+ channels: [channel]
62436
+ };
62437
+ }
62438
+ } catch {
62439
+ }
62440
+ return null;
62441
+ }
62442
+ write(data) {
62443
+ const dir = import_node_path40.default.dirname(this.filePath);
62444
+ import_node_fs35.default.mkdirSync(dir, { recursive: true });
62445
+ const tmp = `${this.filePath}.tmp.${Date.now()}`;
62446
+ import_node_fs35.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
62447
+ import_node_fs35.default.renameSync(tmp, this.filePath);
62448
+ }
62449
+ };
62450
+
62169
62451
  // src/deploy/local-probe.ts
62170
62452
  function pickVersion(s2) {
62171
62453
  return /(\d+)\.(\d+)(?:\.(\d+))?/.exec(s2)?.[0];
@@ -62214,18 +62496,18 @@ async function probeLocalVersion(exec, pkg) {
62214
62496
 
62215
62497
  // src/tools/shell-path.ts
62216
62498
  var import_node_child_process10 = require("child_process");
62217
- var import_node_os12 = __toESM(require("os"), 1);
62499
+ var import_node_os13 = __toESM(require("os"), 1);
62218
62500
  function refreshPathFromLoginShell() {
62219
62501
  if (process.platform === "win32") return;
62220
- const shell = process.env.SHELL ?? import_node_os12.default.userInfo().shell ?? "/bin/zsh";
62502
+ const shell = process.env.SHELL ?? import_node_os13.default.userInfo().shell ?? "/bin/zsh";
62221
62503
  try {
62222
62504
  const out = (0, import_node_child_process10.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
62223
62505
  encoding: "utf8",
62224
62506
  timeout: 3e3,
62225
62507
  stdio: ["ignore", "pipe", "ignore"]
62226
62508
  });
62227
- const path102 = out.trim();
62228
- if (path102) process.env.PATH = path102;
62509
+ const path105 = out.trim();
62510
+ if (path105) process.env.PATH = path105;
62229
62511
  } catch {
62230
62512
  }
62231
62513
  }
@@ -62763,15 +63045,15 @@ async function refreshTunnelUrlOnStartup(deps) {
62763
63045
  }
62764
63046
 
62765
63047
  // src/lark-bot-connector/binding-store.ts
62766
- var import_node_fs35 = __toESM(require("fs"), 1);
62767
- var import_node_path40 = __toESM(require("path"), 1);
63048
+ var import_node_fs36 = __toESM(require("fs"), 1);
63049
+ var import_node_path41 = __toESM(require("path"), 1);
62768
63050
  function createLarkBotBindingStore(personaRoot) {
62769
- const filePath = (personaId2) => import_node_path40.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
63051
+ const filePath = (personaId2) => import_node_path41.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
62770
63052
  const read = (personaId2) => {
62771
63053
  const file = filePath(personaId2);
62772
- if (!import_node_fs35.default.existsSync(file)) return null;
63054
+ if (!import_node_fs36.default.existsSync(file)) return null;
62773
63055
  try {
62774
- const raw = JSON.parse(import_node_fs35.default.readFileSync(file, "utf8"));
63056
+ const raw = JSON.parse(import_node_fs36.default.readFileSync(file, "utf8"));
62775
63057
  if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
62776
63058
  return raw;
62777
63059
  } catch {
@@ -62780,16 +63062,16 @@ function createLarkBotBindingStore(personaRoot) {
62780
63062
  };
62781
63063
  const write = (personaId2, meta) => {
62782
63064
  const file = filePath(personaId2);
62783
- import_node_fs35.default.mkdirSync(import_node_path40.default.dirname(file), { recursive: true });
63065
+ import_node_fs36.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true });
62784
63066
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
62785
- import_node_fs35.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
62786
- import_node_fs35.default.renameSync(tmp, file);
63067
+ import_node_fs36.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
63068
+ import_node_fs36.default.renameSync(tmp, file);
62787
63069
  };
62788
63070
  return {
62789
63071
  read,
62790
63072
  write,
62791
63073
  remove(personaId2) {
62792
- import_node_fs35.default.rmSync(filePath(personaId2), { force: true });
63074
+ import_node_fs36.default.rmSync(filePath(personaId2), { force: true });
62793
63075
  },
62794
63076
  addRemovedChat(personaId2, chatId) {
62795
63077
  const meta = read(personaId2);
@@ -62941,8 +63223,8 @@ function createLarkBotCloudClient(opts) {
62941
63223
  }
62942
63224
 
62943
63225
  // src/lark-bot-connector/chat-router.ts
62944
- var import_node_fs36 = __toESM(require("fs"), 1);
62945
- var import_node_path41 = __toESM(require("path"), 1);
63226
+ var import_node_fs37 = __toESM(require("fs"), 1);
63227
+ var import_node_path42 = __toESM(require("path"), 1);
62946
63228
  init_protocol();
62947
63229
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
62948
63230
  var LOCAL_TURN_RETRIES = 2;
@@ -63020,9 +63302,9 @@ function createLarkChatRouter(deps) {
63020
63302
  continue;
63021
63303
  }
63022
63304
  const dir = deps.mediaRootFor(env.chatId);
63023
- import_node_fs36.default.mkdirSync(dir, { recursive: true });
63024
- const p3 = import_node_path41.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}.${ext}`);
63025
- import_node_fs36.default.writeFileSync(p3, r2.data);
63305
+ import_node_fs37.default.mkdirSync(dir, { recursive: true });
63306
+ const p3 = import_node_path42.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}.${ext}`);
63307
+ import_node_fs37.default.writeFileSync(p3, r2.data);
63026
63308
  lines.push(`[\u56FE\u7247: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
63027
63309
  } catch (err) {
63028
63310
  deps.logger?.warn(`larkBot image fetch failed ${key}: ${err.message}`);
@@ -63043,9 +63325,9 @@ function createLarkChatRouter(deps) {
63043
63325
  continue;
63044
63326
  }
63045
63327
  const dir = deps.mediaRootFor(env.chatId);
63046
- import_node_fs36.default.mkdirSync(dir, { recursive: true });
63047
- const p3 = import_node_path41.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}-${safeAttachmentName(f2.name)}`);
63048
- import_node_fs36.default.writeFileSync(p3, r2.data);
63328
+ import_node_fs37.default.mkdirSync(dir, { recursive: true });
63329
+ const p3 = import_node_path42.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}-${safeAttachmentName(f2.name)}`);
63330
+ import_node_fs37.default.writeFileSync(p3, r2.data);
63049
63331
  lines.push(`[\u6587\u4EF6: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
63050
63332
  } catch (err) {
63051
63333
  deps.logger?.warn(`larkBot file fetch failed ${f2.key}: ${err.message}`);
@@ -64241,7 +64523,7 @@ function openHttpLineStream(opts) {
64241
64523
  init_protocol();
64242
64524
 
64243
64525
  // src/tools/codex-cloud-session.ts
64244
- var import_node_fs37 = __toESM(require("fs"), 1);
64526
+ var import_node_fs38 = __toESM(require("fs"), 1);
64245
64527
  function cloudThreadParams(ctx, paths) {
64246
64528
  const { model: _model, ...base } = threadStartParams(ctx);
64247
64529
  const developerInstructions = [ctx.extraSystemPrompt, workDirPrompt(paths.workDir, ctx.personaMode ?? "owner")].filter((x2) => Boolean(x2)).join("\n\n");
@@ -64298,7 +64580,7 @@ function cloudImageInput(deps) {
64298
64580
  const mime = lookupMime(p3);
64299
64581
  if (!mime.startsWith("image/")) return null;
64300
64582
  try {
64301
- const bytes = (deps.readFile ?? import_node_fs37.default.readFileSync)(p3);
64583
+ const bytes = (deps.readFile ?? import_node_fs38.default.readFileSync)(p3);
64302
64584
  return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
64303
64585
  } catch (e) {
64304
64586
  deps.logger?.warn("cloud image attachment unreadable", { path: p3, message: e.message });
@@ -64432,7 +64714,7 @@ init_protocol();
64432
64714
 
64433
64715
  // src/tools/pi.ts
64434
64716
  var import_node_child_process12 = require("child_process");
64435
- var import_node_fs39 = __toESM(require("fs"), 1);
64717
+ var import_node_fs40 = __toESM(require("fs"), 1);
64436
64718
  init_protocol();
64437
64719
 
64438
64720
  // src/tools/pi-rpc-client.ts
@@ -64533,8 +64815,8 @@ var PiRpcClient = class {
64533
64815
  // src/tools/pi-session.ts
64534
64816
  var import_node_child_process11 = require("child_process");
64535
64817
  var import_node_crypto12 = require("crypto");
64536
- var import_node_fs38 = __toESM(require("fs"), 1);
64537
- var import_node_path42 = __toESM(require("path"), 1);
64818
+ var import_node_fs39 = __toESM(require("fs"), 1);
64819
+ var import_node_path43 = __toESM(require("path"), 1);
64538
64820
 
64539
64821
  // src/tools/pi-events.ts
64540
64822
  init_protocol();
@@ -64806,8 +65088,8 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
64806
65088
  function createPiSession(ctx, sink, deps = {}) {
64807
65089
  const cmd = process.env.PI_BIN ?? "pi";
64808
65090
  const sessionId = ctx.toolSessionId ?? (0, import_node_crypto12.randomUUID)();
64809
- const skillsDir = import_node_path42.default.join(ctx.cwd, ".claude", "skills");
64810
- const exists = deps.skillsDirExists ?? ((d2) => import_node_fs38.default.existsSync(d2));
65091
+ const skillsDir = import_node_path43.default.join(ctx.cwd, ".claude", "skills");
65092
+ const exists = deps.skillsDirExists ?? ((d2) => import_node_fs39.default.existsSync(d2));
64811
65093
  const args = buildPiArgs(ctx, {
64812
65094
  sessionId,
64813
65095
  skillsDir: exists(skillsDir) ? skillsDir : void 0,
@@ -64869,10 +65151,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
64869
65151
  };
64870
65152
  var PI_FULL_ACCESS = { id: "never", label: "Full Access", description: "pi \u65E0\u5BA1\u6279\uFF1A\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" };
64871
65153
  async function probePi(env = process.env) {
64872
- if (env.PI_BIN && import_node_fs39.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
65154
+ if (env.PI_BIN && import_node_fs40.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
64873
65155
  try {
64874
65156
  const out = (0, import_node_child_process12.execFileSync)("which", ["pi"], { encoding: "utf8" }).trim();
64875
- if (out && import_node_fs39.default.existsSync(out)) return { available: true, path: out };
65157
+ if (out && import_node_fs40.default.existsSync(out)) return { available: true, path: out };
64876
65158
  } catch {
64877
65159
  }
64878
65160
  return { available: false };
@@ -65159,7 +65441,7 @@ var CloudPiAdapter = class {
65159
65441
  init_protocol();
65160
65442
 
65161
65443
  // src/tools/codex-skills.ts
65162
- var import_node_path43 = __toESM(require("path"), 1);
65444
+ var import_node_path44 = __toESM(require("path"), 1);
65163
65445
  function str4(v3) {
65164
65446
  return typeof v3 === "string" ? v3 : void 0;
65165
65447
  }
@@ -65174,13 +65456,13 @@ function mapSkillsListResponse(res) {
65174
65456
  const r2 = s2 ?? {};
65175
65457
  const name = str4(r2.name);
65176
65458
  if (!name) continue;
65177
- const path102 = str4(r2.path);
65459
+ const path105 = str4(r2.path);
65178
65460
  const description = str4(r2.description);
65179
65461
  const isPlugin = name.includes(":");
65180
65462
  out.push({
65181
65463
  name,
65182
65464
  source: isPlugin ? "plugin" : "project",
65183
- ...path102 ? { path: path102 } : {},
65465
+ ...path105 ? { path: path105 } : {},
65184
65466
  ...description ? { description } : {},
65185
65467
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
65186
65468
  });
@@ -65196,7 +65478,7 @@ async function listCodexSkills(cwd, deps = {}) {
65196
65478
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
65197
65479
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
65198
65480
  beforeRequest: (client) => {
65199
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path43.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
65481
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path44.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
65200
65482
  }
65201
65483
  });
65202
65484
  return mapSkillsListResponse(res);
@@ -65270,23 +65552,23 @@ function rec4(v3) {
65270
65552
  }
65271
65553
 
65272
65554
  // src/workspace/browser.ts
65273
- var import_node_fs40 = __toESM(require("fs"), 1);
65274
- var import_node_os13 = __toESM(require("os"), 1);
65275
- var import_node_path44 = __toESM(require("path"), 1);
65555
+ var import_node_fs41 = __toESM(require("fs"), 1);
65556
+ var import_node_os14 = __toESM(require("os"), 1);
65557
+ var import_node_path45 = __toESM(require("path"), 1);
65276
65558
  init_protocol();
65277
65559
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
65278
65560
  function resolveInsideCwd(cwd, subpath) {
65279
- const absCwd = import_node_path44.default.resolve(cwd);
65280
- const joined = import_node_path44.default.resolve(absCwd, subpath ?? ".");
65281
- const rel = import_node_path44.default.relative(absCwd, joined);
65282
- if (rel.startsWith("..") || import_node_path44.default.isAbsolute(rel)) {
65561
+ const absCwd = import_node_path45.default.resolve(cwd);
65562
+ const joined = import_node_path45.default.resolve(absCwd, subpath ?? ".");
65563
+ const rel = import_node_path45.default.relative(absCwd, joined);
65564
+ if (rel.startsWith("..") || import_node_path45.default.isAbsolute(rel)) {
65283
65565
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
65284
65566
  }
65285
65567
  return joined;
65286
65568
  }
65287
65569
  function ensureCwd(cwd) {
65288
65570
  try {
65289
- const stat = import_node_fs40.default.statSync(cwd);
65571
+ const stat = import_node_fs41.default.statSync(cwd);
65290
65572
  if (!stat.isDirectory()) {
65291
65573
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
65292
65574
  }
@@ -65297,10 +65579,10 @@ function ensureCwd(cwd) {
65297
65579
  }
65298
65580
  var WorkspaceBrowser = class {
65299
65581
  list(args) {
65300
- const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os13.default.homedir();
65582
+ const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os14.default.homedir();
65301
65583
  ensureCwd(cwd);
65302
65584
  const full = resolveInsideCwd(cwd, args.path);
65303
- const dirents = import_node_fs40.default.readdirSync(full, { withFileTypes: true });
65585
+ const dirents = import_node_fs41.default.readdirSync(full, { withFileTypes: true });
65304
65586
  const entries = [];
65305
65587
  for (const d2 of dirents) {
65306
65588
  if (!args.showHidden && d2.name.startsWith(".")) continue;
@@ -65310,7 +65592,7 @@ var WorkspaceBrowser = class {
65310
65592
  mtime: ""
65311
65593
  };
65312
65594
  try {
65313
- const st2 = import_node_fs40.default.statSync(import_node_path44.default.join(full, d2.name));
65595
+ const st2 = import_node_fs41.default.statSync(import_node_path45.default.join(full, d2.name));
65314
65596
  entry.mtime = new Date(st2.mtimeMs).toISOString();
65315
65597
  if (d2.isFile()) entry.size = st2.size;
65316
65598
  } catch {
@@ -65326,14 +65608,14 @@ var WorkspaceBrowser = class {
65326
65608
  read(args) {
65327
65609
  ensureCwd(args.cwd);
65328
65610
  const full = resolveInsideCwd(args.cwd, args.path);
65329
- const st2 = import_node_fs40.default.statSync(full);
65611
+ const st2 = import_node_fs41.default.statSync(full);
65330
65612
  if (!st2.isFile()) {
65331
65613
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
65332
65614
  }
65333
65615
  if (st2.size > MAX_FILE_BYTES2) {
65334
65616
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
65335
65617
  }
65336
- const buf = import_node_fs40.default.readFileSync(full);
65618
+ const buf = import_node_fs41.default.readFileSync(full);
65337
65619
  const isBinary = buf.includes(0);
65338
65620
  if (isBinary) {
65339
65621
  return {
@@ -65355,20 +65637,20 @@ var WorkspaceBrowser = class {
65355
65637
  };
65356
65638
 
65357
65639
  // src/skills/agents-scanner.ts
65358
- var import_node_fs41 = __toESM(require("fs"), 1);
65359
- var import_node_os14 = __toESM(require("os"), 1);
65360
- var import_node_path45 = __toESM(require("path"), 1);
65640
+ var import_node_fs42 = __toESM(require("fs"), 1);
65641
+ var import_node_os15 = __toESM(require("os"), 1);
65642
+ var import_node_path46 = __toESM(require("path"), 1);
65361
65643
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
65362
65644
  function isDirLikeSync2(p3) {
65363
65645
  try {
65364
- return import_node_fs41.default.statSync(p3).isDirectory();
65646
+ return import_node_fs42.default.statSync(p3).isDirectory();
65365
65647
  } catch {
65366
65648
  return false;
65367
65649
  }
65368
65650
  }
65369
65651
  function fileExistsSync(p3) {
65370
65652
  try {
65371
- return import_node_fs41.default.statSync(p3).isFile();
65653
+ return import_node_fs42.default.statSync(p3).isFile();
65372
65654
  } catch {
65373
65655
  return false;
65374
65656
  }
@@ -65376,7 +65658,7 @@ function fileExistsSync(p3) {
65376
65658
  function parseAgentFile(filePath) {
65377
65659
  let content;
65378
65660
  try {
65379
- content = import_node_fs41.default.readFileSync(filePath, "utf8");
65661
+ content = import_node_fs42.default.readFileSync(filePath, "utf8");
65380
65662
  } catch {
65381
65663
  return {};
65382
65664
  }
@@ -65389,16 +65671,16 @@ function parseAgentFile(filePath) {
65389
65671
  function scanAgentsDir(dir, source, seen, out) {
65390
65672
  let entries;
65391
65673
  try {
65392
- entries = import_node_fs41.default.readdirSync(dir, { withFileTypes: true });
65674
+ entries = import_node_fs42.default.readdirSync(dir, { withFileTypes: true });
65393
65675
  } catch {
65394
65676
  return;
65395
65677
  }
65396
65678
  for (const ent of entries) {
65397
65679
  if (!ent.name.endsWith(".md")) continue;
65398
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path45.default.join(dir, ent.name)))) {
65680
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path46.default.join(dir, ent.name)))) {
65399
65681
  continue;
65400
65682
  }
65401
- const filePath = import_node_path45.default.join(dir, ent.name);
65683
+ const filePath = import_node_path46.default.join(dir, ent.name);
65402
65684
  const baseName = ent.name.replace(/\.md$/, "");
65403
65685
  if (seen.has(baseName)) continue;
65404
65686
  seen.add(baseName);
@@ -65416,12 +65698,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
65416
65698
  function walk2(dir, namespaces) {
65417
65699
  let entries;
65418
65700
  try {
65419
- entries = import_node_fs41.default.readdirSync(dir, { withFileTypes: true });
65701
+ entries = import_node_fs42.default.readdirSync(dir, { withFileTypes: true });
65420
65702
  } catch {
65421
65703
  return;
65422
65704
  }
65423
65705
  for (const ent of entries) {
65424
- const childPath = import_node_path45.default.join(dir, ent.name);
65706
+ const childPath = import_node_path46.default.join(dir, ent.name);
65425
65707
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
65426
65708
  walk2(childPath, [...namespaces, ent.name]);
65427
65709
  continue;
@@ -65446,13 +65728,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
65446
65728
  walk2(root, []);
65447
65729
  }
65448
65730
  function readInstalledPlugins2(home) {
65449
- const pluginsDir = import_node_path45.default.join(home, ".claude", "plugins");
65450
- const v22 = import_node_path45.default.join(pluginsDir, "installed_plugins_v2.json");
65451
- const v1 = import_node_path45.default.join(pluginsDir, "installed_plugins.json");
65731
+ const pluginsDir = import_node_path46.default.join(home, ".claude", "plugins");
65732
+ const v22 = import_node_path46.default.join(pluginsDir, "installed_plugins_v2.json");
65733
+ const v1 = import_node_path46.default.join(pluginsDir, "installed_plugins.json");
65452
65734
  let raw = null;
65453
65735
  for (const candidate of [v22, v1]) {
65454
65736
  try {
65455
- raw = import_node_fs41.default.readFileSync(candidate, "utf8");
65737
+ raw = import_node_fs42.default.readFileSync(candidate, "utf8");
65456
65738
  break;
65457
65739
  } catch {
65458
65740
  }
@@ -65477,19 +65759,19 @@ function readInstalledPlugins2(home) {
65477
65759
  return out;
65478
65760
  }
65479
65761
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
65480
- let cur = import_node_path45.default.resolve(startCwd);
65481
- const fsRoot = import_node_path45.default.parse(cur).root;
65762
+ let cur = import_node_path46.default.resolve(startCwd);
65763
+ const fsRoot = import_node_path46.default.parse(cur).root;
65482
65764
  while (true) {
65483
- scanAgentsDir(import_node_path45.default.join(cur, ".claude", "agents"), "project", seen, out);
65765
+ scanAgentsDir(import_node_path46.default.join(cur, ".claude", "agents"), "project", seen, out);
65484
65766
  let hasGit = false;
65485
65767
  try {
65486
- hasGit = import_node_fs41.default.existsSync(import_node_path45.default.join(cur, ".git"));
65768
+ hasGit = import_node_fs42.default.existsSync(import_node_path46.default.join(cur, ".git"));
65487
65769
  } catch {
65488
65770
  }
65489
65771
  if (hasGit) return;
65490
65772
  if (cur === home) return;
65491
65773
  if (cur === fsRoot) return;
65492
- const parent = import_node_path45.default.dirname(cur);
65774
+ const parent = import_node_path46.default.dirname(cur);
65493
65775
  if (parent === cur) return;
65494
65776
  cur = parent;
65495
65777
  }
@@ -65499,7 +65781,7 @@ var AgentsScanner = class {
65499
65781
  extraPluginRoots;
65500
65782
  policyDir;
65501
65783
  constructor(opts = {}) {
65502
- this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os14.default.homedir();
65784
+ this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os15.default.homedir();
65503
65785
  this.extraPluginRoots = opts.extraPluginRoots ?? [];
65504
65786
  if (opts.policyDir !== void 0) {
65505
65787
  this.policyDir = opts.policyDir;
@@ -65524,7 +65806,7 @@ var AgentsScanner = class {
65524
65806
  }
65525
65807
  const fsBlock = [];
65526
65808
  scanAgentsDir(
65527
- import_node_path45.default.join(this.home, ".claude", "agents"),
65809
+ import_node_path46.default.join(this.home, ".claude", "agents"),
65528
65810
  "global",
65529
65811
  seen,
65530
65812
  fsBlock
@@ -65538,7 +65820,7 @@ var AgentsScanner = class {
65538
65820
  ...this.extraPluginRoots
65539
65821
  ];
65540
65822
  for (const { name, root } of plugins) {
65541
- const agentsRoot = import_node_path45.default.join(root, "agents");
65823
+ const agentsRoot = import_node_path46.default.join(root, "agents");
65542
65824
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
65543
65825
  }
65544
65826
  return [...builtinBlock, ...fsBlock];
@@ -65546,28 +65828,28 @@ var AgentsScanner = class {
65546
65828
  };
65547
65829
 
65548
65830
  // src/observer/session-observer.ts
65549
- var import_node_fs43 = __toESM(require("fs"), 1);
65550
- var import_node_os16 = __toESM(require("os"), 1);
65551
- var import_node_path47 = __toESM(require("path"), 1);
65831
+ var import_node_fs44 = __toESM(require("fs"), 1);
65832
+ var import_node_os17 = __toESM(require("os"), 1);
65833
+ var import_node_path48 = __toESM(require("path"), 1);
65552
65834
  init_claude_history();
65553
65835
 
65554
65836
  // src/observer/subagent-meta-observer.ts
65555
- var import_node_fs42 = __toESM(require("fs"), 1);
65556
- var import_node_os15 = __toESM(require("os"), 1);
65557
- var import_node_path46 = __toESM(require("path"), 1);
65837
+ var import_node_fs43 = __toESM(require("fs"), 1);
65838
+ var import_node_os16 = __toESM(require("os"), 1);
65839
+ var import_node_path47 = __toESM(require("path"), 1);
65558
65840
  init_claude_history();
65559
65841
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
65560
65842
  var SubagentMetaObserver = class {
65561
65843
  constructor(opts) {
65562
65844
  this.opts = opts;
65563
- this.home = opts.home ?? import_node_os15.default.homedir();
65845
+ this.home = opts.home ?? import_node_os16.default.homedir();
65564
65846
  }
65565
65847
  opts;
65566
65848
  home;
65567
65849
  watches = /* @__PURE__ */ new Map();
65568
65850
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
65569
65851
  resolveSubagentDir(cwd, toolSessionId) {
65570
- return import_node_path46.default.join(
65852
+ return import_node_path47.default.join(
65571
65853
  this.home,
65572
65854
  ".claude",
65573
65855
  "projects",
@@ -65597,7 +65879,7 @@ var SubagentMetaObserver = class {
65597
65879
  attachWatcher(w3) {
65598
65880
  if (w3.watcher) return;
65599
65881
  try {
65600
- w3.watcher = import_node_fs42.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
65882
+ w3.watcher = import_node_fs43.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
65601
65883
  if (!name) return;
65602
65884
  const m3 = META_RE.exec(String(name));
65603
65885
  if (!m3) return;
@@ -65609,7 +65891,7 @@ var SubagentMetaObserver = class {
65609
65891
  scan(w3) {
65610
65892
  let entries;
65611
65893
  try {
65612
- entries = import_node_fs42.default.readdirSync(w3.dirPath);
65894
+ entries = import_node_fs43.default.readdirSync(w3.dirPath);
65613
65895
  } catch {
65614
65896
  return;
65615
65897
  }
@@ -65623,10 +65905,10 @@ var SubagentMetaObserver = class {
65623
65905
  if (!m3) return;
65624
65906
  const agentId = m3[1];
65625
65907
  if (w3.emitted.has(agentId)) return;
65626
- const file = import_node_path46.default.join(w3.dirPath, name);
65908
+ const file = import_node_path47.default.join(w3.dirPath, name);
65627
65909
  let raw;
65628
65910
  try {
65629
- raw = import_node_fs42.default.readFileSync(file, "utf8");
65911
+ raw = import_node_fs43.default.readFileSync(file, "utf8");
65630
65912
  } catch {
65631
65913
  return;
65632
65914
  }
@@ -65671,7 +65953,7 @@ var SubagentMetaObserver = class {
65671
65953
  var SessionObserver = class {
65672
65954
  constructor(opts) {
65673
65955
  this.opts = opts;
65674
- this.home = opts.home ?? import_node_os16.default.homedir();
65956
+ this.home = opts.home ?? import_node_os17.default.homedir();
65675
65957
  this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
65676
65958
  }
65677
65959
  opts;
@@ -65683,14 +65965,14 @@ var SessionObserver = class {
65683
65965
  metaObserver;
65684
65966
  resolveJsonlPath(cwd, toolSessionId, override) {
65685
65967
  if (override) return override;
65686
- return import_node_path47.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
65968
+ return import_node_path48.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
65687
65969
  }
65688
65970
  start(args) {
65689
65971
  this.stop(args.sessionId);
65690
65972
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
65691
65973
  let size = 0;
65692
65974
  try {
65693
- size = import_node_fs43.default.statSync(filePath).size;
65975
+ size = import_node_fs44.default.statSync(filePath).size;
65694
65976
  } catch {
65695
65977
  }
65696
65978
  const w3 = {
@@ -65703,16 +65985,16 @@ var SessionObserver = class {
65703
65985
  adapter: args.adapter,
65704
65986
  prevIsRejectSentinel: false,
65705
65987
  toolSessionId: args.toolSessionId,
65706
- sawFile: import_node_fs43.default.existsSync(filePath),
65988
+ sawFile: import_node_fs44.default.existsSync(filePath),
65707
65989
  lastRelocateScanMs: 0,
65708
65990
  pendingCwdDerive: false,
65709
65991
  lastDeriveMs: 0
65710
65992
  };
65711
65993
  try {
65712
- import_node_fs43.default.mkdirSync(import_node_path47.default.dirname(filePath), { recursive: true });
65994
+ import_node_fs44.default.mkdirSync(import_node_path48.default.dirname(filePath), { recursive: true });
65713
65995
  } catch {
65714
65996
  }
65715
- w3.watcher = import_node_fs43.default.watch(import_node_path47.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
65997
+ w3.watcher = import_node_fs44.default.watch(import_node_path48.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
65716
65998
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
65717
65999
  this.poll(w3);
65718
66000
  });
@@ -65735,7 +66017,7 @@ var SessionObserver = class {
65735
66017
  // 异常静默吞,不阻塞 watcher 启动
65736
66018
  hydrateMetaTail(w3, maxLines = 200) {
65737
66019
  try {
65738
- const raw = import_node_fs43.default.readFileSync(w3.filePath, "utf8");
66020
+ const raw = import_node_fs44.default.readFileSync(w3.filePath, "utf8");
65739
66021
  if (!raw) return;
65740
66022
  const allLines = raw.split("\n").filter((l2) => l2.trim().length > 0);
65741
66023
  if (allLines.length === 0) return;
@@ -65759,7 +66041,7 @@ var SessionObserver = class {
65759
66041
  poll(w3) {
65760
66042
  let size = 0;
65761
66043
  try {
65762
- size = import_node_fs43.default.statSync(w3.filePath).size;
66044
+ size = import_node_fs44.default.statSync(w3.filePath).size;
65763
66045
  } catch {
65764
66046
  if (w3.sawFile) this.maybeRelocate(w3);
65765
66047
  return;
@@ -65770,11 +66052,11 @@ var SessionObserver = class {
65770
66052
  w3.buf = "";
65771
66053
  }
65772
66054
  if (size === w3.lastSize) return;
65773
- const fd = import_node_fs43.default.openSync(w3.filePath, "r");
66055
+ const fd = import_node_fs44.default.openSync(w3.filePath, "r");
65774
66056
  try {
65775
66057
  const len = size - w3.lastSize;
65776
66058
  const buf = Buffer.alloc(len);
65777
- import_node_fs43.default.readSync(fd, buf, 0, len, w3.lastSize);
66059
+ import_node_fs44.default.readSync(fd, buf, 0, len, w3.lastSize);
65778
66060
  w3.lastSize = size;
65779
66061
  w3.buf += buf.toString("utf8");
65780
66062
  let newlineIndex;
@@ -65797,7 +66079,7 @@ var SessionObserver = class {
65797
66079
  }
65798
66080
  }
65799
66081
  } finally {
65800
- import_node_fs43.default.closeSync(fd);
66082
+ import_node_fs44.default.closeSync(fd);
65801
66083
  }
65802
66084
  if (w3.pendingCwdDerive) this.maybeDeriveCwd(w3);
65803
66085
  }
@@ -65809,7 +66091,7 @@ var SessionObserver = class {
65809
66091
  const now = Date.now();
65810
66092
  if (now - w3.lastRelocateScanMs < 1e3) return;
65811
66093
  w3.lastRelocateScanMs = now;
65812
- const projectsRoot = import_node_path47.default.join(this.home, ".claude", "projects");
66094
+ const projectsRoot = import_node_path48.default.join(this.home, ".claude", "projects");
65813
66095
  const found = findTranscriptByToolSessionId(projectsRoot, w3.toolSessionId);
65814
66096
  if (!found || found === w3.filePath) return;
65815
66097
  try {
@@ -65818,7 +66100,7 @@ var SessionObserver = class {
65818
66100
  }
65819
66101
  w3.filePath = found;
65820
66102
  try {
65821
- w3.watcher = import_node_fs43.default.watch(import_node_path47.default.dirname(found), { persistent: false }, (_event, changedName) => {
66103
+ w3.watcher = import_node_fs44.default.watch(import_node_path48.default.dirname(found), { persistent: false }, (_event, changedName) => {
65822
66104
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
65823
66105
  this.poll(w3);
65824
66106
  });
@@ -65940,9 +66222,9 @@ function listRegistered() {
65940
66222
  // src/tools/title-generator.ts
65941
66223
  var import_node_child_process13 = require("child_process");
65942
66224
  init_protocol();
65943
- var import_node_fs44 = __toESM(require("fs"), 1);
65944
- var import_node_os17 = __toESM(require("os"), 1);
65945
- var import_node_path48 = __toESM(require("path"), 1);
66225
+ var import_node_fs45 = __toESM(require("fs"), 1);
66226
+ var import_node_os18 = __toESM(require("os"), 1);
66227
+ var import_node_path49 = __toESM(require("path"), 1);
65946
66228
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
65947
66229
  var TITLE_MODEL_BY_TOOL = {
65948
66230
  claude: "haiku",
@@ -66013,21 +66295,21 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
66013
66295
  if (!text) return null;
66014
66296
  let workDir;
66015
66297
  try {
66016
- workDir = import_node_fs44.default.mkdtempSync(import_node_path48.default.join(import_node_os17.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
66298
+ workDir = import_node_fs45.default.mkdtempSync(import_node_path49.default.join(import_node_os18.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
66017
66299
  } catch {
66018
66300
  return null;
66019
66301
  }
66020
66302
  const cleanupWorkDir = () => {
66021
66303
  try {
66022
- import_node_fs44.default.rmSync(workDir, { recursive: true, force: true });
66304
+ import_node_fs45.default.rmSync(workDir, { recursive: true, force: true });
66023
66305
  } catch {
66024
66306
  }
66025
66307
  };
66026
- const outFile = import_node_path48.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
66027
- const schemaFile = import_node_path48.default.join(workDir, "title-schema.json");
66308
+ const outFile = import_node_path49.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
66309
+ const schemaFile = import_node_path49.default.join(workDir, "title-schema.json");
66028
66310
  if (isCodexFamily(tool)) {
66029
66311
  try {
66030
- import_node_fs44.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
66312
+ import_node_fs45.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
66031
66313
  } catch {
66032
66314
  cleanupWorkDir();
66033
66315
  return null;
@@ -66077,7 +66359,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
66077
66359
  if (tool === "claude") return finish(parseTitleJson(stdout));
66078
66360
  let fileText = "";
66079
66361
  try {
66080
- fileText = import_node_fs44.default.readFileSync(outFile, "utf8");
66362
+ fileText = import_node_fs45.default.readFileSync(outFile, "utf8");
66081
66363
  } catch {
66082
66364
  return finish(null);
66083
66365
  }
@@ -66722,8 +67004,8 @@ async function authenticate(token, deps) {
66722
67004
  }
66723
67005
 
66724
67006
  // src/legacy-cleanup.ts
66725
- var fs55 = __toESM(require("fs/promises"), 1);
66726
- var path56 = __toESM(require("path"), 1);
67007
+ var fs56 = __toESM(require("fs/promises"), 1);
67008
+ var path57 = __toESM(require("path"), 1);
66727
67009
  var LEGACY_FILES = [
66728
67010
  "personal-capability.json",
66729
67011
  "received-capabilities.json",
@@ -66732,9 +67014,9 @@ var LEGACY_FILES = [
66732
67014
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
66733
67015
  const removed = [];
66734
67016
  for (const name of LEGACY_FILES) {
66735
- const p3 = path56.join(dataDir, name);
67017
+ const p3 = path57.join(dataDir, name);
66736
67018
  try {
66737
- await fs55.unlink(p3);
67019
+ await fs56.unlink(p3);
66738
67020
  removed.push(name);
66739
67021
  logger.debug("legacy capability file removed", { file: name });
66740
67022
  } catch (err) {
@@ -66746,13 +67028,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
66746
67028
  }
66747
67029
 
66748
67030
  // src/inbox/inbox-store.ts
66749
- var fs56 = __toESM(require("fs"), 1);
66750
- var path57 = __toESM(require("path"), 1);
67031
+ var fs57 = __toESM(require("fs"), 1);
67032
+ var path58 = __toESM(require("path"), 1);
66751
67033
  var INBOX_SUBDIR = "inbox";
66752
67034
  var InboxStore = class {
66753
67035
  constructor(dataDir) {
66754
67036
  this.dataDir = dataDir;
66755
- fs56.mkdirSync(this.dirPath(), { recursive: true });
67037
+ fs57.mkdirSync(this.dirPath(), { recursive: true });
66756
67038
  }
66757
67039
  dataDir;
66758
67040
  /**
@@ -66764,7 +67046,7 @@ var InboxStore = class {
66764
67046
  const file = this.filePath(peerDeviceId);
66765
67047
  let raw;
66766
67048
  try {
66767
- raw = fs56.readFileSync(file, "utf8");
67049
+ raw = fs57.readFileSync(file, "utf8");
66768
67050
  } catch (err) {
66769
67051
  if (err?.code === "ENOENT") return [];
66770
67052
  return [];
@@ -66780,7 +67062,7 @@ var InboxStore = class {
66780
67062
  const dir = this.dirPath();
66781
67063
  let entries;
66782
67064
  try {
66783
- entries = fs56.readdirSync(dir);
67065
+ entries = fs57.readdirSync(dir);
66784
67066
  } catch (err) {
66785
67067
  if (err?.code === "ENOENT") return [];
66786
67068
  return [];
@@ -66796,9 +67078,9 @@ var InboxStore = class {
66796
67078
  if (existing.some((m3) => m3.id === message.id)) return;
66797
67079
  const file = this.filePath(message.peerDeviceId);
66798
67080
  const line = JSON.stringify(message) + "\n";
66799
- fs56.appendFileSync(file, line, { mode: 384 });
67081
+ fs57.appendFileSync(file, line, { mode: 384 });
66800
67082
  try {
66801
- fs56.chmodSync(file, 384);
67083
+ fs57.chmodSync(file, 384);
66802
67084
  } catch {
66803
67085
  }
66804
67086
  }
@@ -66828,7 +67110,7 @@ var InboxStore = class {
66828
67110
  removeByPeerDeviceId(peerDeviceId) {
66829
67111
  const file = this.filePath(peerDeviceId);
66830
67112
  try {
66831
- fs56.unlinkSync(file);
67113
+ fs57.unlinkSync(file);
66832
67114
  } catch (err) {
66833
67115
  if (err?.code === "ENOENT") return;
66834
67116
  }
@@ -66837,18 +67119,18 @@ var InboxStore = class {
66837
67119
  const file = this.filePath(peerDeviceId);
66838
67120
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
66839
67121
  const content = messages.map((m3) => JSON.stringify(m3)).join("\n") + (messages.length > 0 ? "\n" : "");
66840
- fs56.writeFileSync(tmp, content, { mode: 384 });
66841
- fs56.renameSync(tmp, file);
67122
+ fs57.writeFileSync(tmp, content, { mode: 384 });
67123
+ fs57.renameSync(tmp, file);
66842
67124
  try {
66843
- fs56.chmodSync(file, 384);
67125
+ fs57.chmodSync(file, 384);
66844
67126
  } catch {
66845
67127
  }
66846
67128
  }
66847
67129
  dirPath() {
66848
- return path57.join(this.dataDir, INBOX_SUBDIR);
67130
+ return path58.join(this.dataDir, INBOX_SUBDIR);
66849
67131
  }
66850
67132
  filePath(peerDeviceId) {
66851
- return path57.join(this.dirPath(), `${peerDeviceId}.jsonl`);
67133
+ return path58.join(this.dirPath(), `${peerDeviceId}.jsonl`);
66852
67134
  }
66853
67135
  };
66854
67136
  function parseAllLines(raw) {
@@ -66936,8 +67218,8 @@ var InboxManager = class {
66936
67218
  };
66937
67219
 
66938
67220
  // src/state/contact-store.ts
66939
- var fs57 = __toESM(require("fs"), 1);
66940
- var path58 = __toESM(require("path"), 1);
67221
+ var fs58 = __toESM(require("fs"), 1);
67222
+ var path59 = __toESM(require("path"), 1);
66941
67223
  var FILE_NAME = "contacts.json";
66942
67224
  var ContactStore = class {
66943
67225
  constructor(dataDir) {
@@ -66947,10 +67229,10 @@ var ContactStore = class {
66947
67229
  contacts = /* @__PURE__ */ new Map();
66948
67230
  load() {
66949
67231
  this.contacts.clear();
66950
- const file = path58.join(this.dataDir, FILE_NAME);
67232
+ const file = path59.join(this.dataDir, FILE_NAME);
66951
67233
  let raw;
66952
67234
  try {
66953
- raw = fs57.readFileSync(file, "utf8");
67235
+ raw = fs58.readFileSync(file, "utf8");
66954
67236
  } catch (err) {
66955
67237
  if (err?.code !== "ENOENT") this.renameBak(file);
66956
67238
  return;
@@ -67031,20 +67313,20 @@ var ContactStore = class {
67031
67313
  return true;
67032
67314
  }
67033
67315
  flush() {
67034
- const file = path58.join(this.dataDir, FILE_NAME);
67316
+ const file = path59.join(this.dataDir, FILE_NAME);
67035
67317
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
67036
67318
  const content = JSON.stringify(
67037
67319
  { contacts: Array.from(this.contacts.values()) },
67038
67320
  null,
67039
67321
  2
67040
67322
  );
67041
- fs57.mkdirSync(this.dataDir, { recursive: true });
67042
- fs57.writeFileSync(tmp, content, { mode: 384 });
67043
- fs57.renameSync(tmp, file);
67323
+ fs58.mkdirSync(this.dataDir, { recursive: true });
67324
+ fs58.writeFileSync(tmp, content, { mode: 384 });
67325
+ fs58.renameSync(tmp, file);
67044
67326
  }
67045
67327
  renameBak(file) {
67046
67328
  try {
67047
- fs57.renameSync(file, `${file}.bak`);
67329
+ fs58.renameSync(file, `${file}.bak`);
67048
67330
  } catch {
67049
67331
  }
67050
67332
  }
@@ -67152,61 +67434,61 @@ async function connectRemote(args) {
67152
67434
  }
67153
67435
 
67154
67436
  // src/migrations/2026-05-20-flatten-sessions.ts
67155
- var fs58 = __toESM(require("fs"), 1);
67156
- var path59 = __toESM(require("path"), 1);
67437
+ var fs59 = __toESM(require("fs"), 1);
67438
+ var path60 = __toESM(require("path"), 1);
67157
67439
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
67158
67440
  function migrateFlattenSessions(opts) {
67159
67441
  const dataDir = opts.dataDir;
67160
67442
  const now = opts.now ?? Date.now;
67161
- const sessionsDir = path59.join(dataDir, "sessions");
67162
- const flagPath = path59.join(sessionsDir, MIGRATION_FLAG_NAME);
67443
+ const sessionsDir = path60.join(dataDir, "sessions");
67444
+ const flagPath = path60.join(sessionsDir, MIGRATION_FLAG_NAME);
67163
67445
  if (existsSync3(flagPath)) {
67164
67446
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
67165
67447
  }
67166
67448
  let movedBare = 0;
67167
67449
  let movedVmOwner = 0;
67168
67450
  let archivedListener = 0;
67169
- const defaultDir = path59.join(sessionsDir, "default");
67451
+ const defaultDir = path60.join(sessionsDir, "default");
67170
67452
  if (existsSync3(defaultDir)) {
67171
67453
  for (const entry of readdirSafe(defaultDir)) {
67172
67454
  if (!entry.endsWith(".json")) continue;
67173
- const src = path59.join(defaultDir, entry);
67174
- const dst = path59.join(sessionsDir, entry);
67175
- fs58.renameSync(src, dst);
67455
+ const src = path60.join(defaultDir, entry);
67456
+ const dst = path60.join(sessionsDir, entry);
67457
+ fs59.renameSync(src, dst);
67176
67458
  movedBare += 1;
67177
67459
  }
67178
67460
  rmdirIfEmpty(defaultDir);
67179
67461
  }
67180
67462
  for (const pid of readdirSafe(sessionsDir)) {
67181
- const personaDir = path59.join(sessionsDir, pid);
67463
+ const personaDir = path60.join(sessionsDir, pid);
67182
67464
  if (!isDir(personaDir)) continue;
67183
67465
  if (pid === "default") continue;
67184
- const ownerSrc = path59.join(personaDir, "owner");
67466
+ const ownerSrc = path60.join(personaDir, "owner");
67185
67467
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
67186
- const ownerDst = path59.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
67187
- fs58.mkdirSync(ownerDst, { recursive: true });
67468
+ const ownerDst = path60.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
67469
+ fs59.mkdirSync(ownerDst, { recursive: true });
67188
67470
  for (const file of readdirSafe(ownerSrc)) {
67189
67471
  if (!file.endsWith(".json")) continue;
67190
- fs58.renameSync(path59.join(ownerSrc, file), path59.join(ownerDst, file));
67472
+ fs59.renameSync(path60.join(ownerSrc, file), path60.join(ownerDst, file));
67191
67473
  movedVmOwner += 1;
67192
67474
  }
67193
67475
  rmdirIfEmpty(ownerSrc);
67194
67476
  }
67195
- const listenerSrc = path59.join(personaDir, "listener");
67477
+ const listenerSrc = path60.join(personaDir, "listener");
67196
67478
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
67197
- const archiveDst = path59.join(dataDir, ".legacy", `listener-${pid}`);
67198
- fs58.mkdirSync(archiveDst, { recursive: true });
67479
+ const archiveDst = path60.join(dataDir, ".legacy", `listener-${pid}`);
67480
+ fs59.mkdirSync(archiveDst, { recursive: true });
67199
67481
  for (const file of readdirSafe(listenerSrc)) {
67200
67482
  if (!file.endsWith(".json")) continue;
67201
- fs58.renameSync(path59.join(listenerSrc, file), path59.join(archiveDst, file));
67483
+ fs59.renameSync(path60.join(listenerSrc, file), path60.join(archiveDst, file));
67202
67484
  archivedListener += 1;
67203
67485
  }
67204
67486
  rmdirIfEmpty(listenerSrc);
67205
67487
  }
67206
67488
  rmdirIfEmpty(personaDir);
67207
67489
  }
67208
- fs58.mkdirSync(sessionsDir, { recursive: true });
67209
- fs58.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
67490
+ fs59.mkdirSync(sessionsDir, { recursive: true });
67491
+ fs59.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
67210
67492
  return {
67211
67493
  skipped: false,
67212
67494
  flagWritten: true,
@@ -67217,7 +67499,7 @@ function migrateFlattenSessions(opts) {
67217
67499
  }
67218
67500
  function existsSync3(p3) {
67219
67501
  try {
67220
- fs58.statSync(p3);
67502
+ fs59.statSync(p3);
67221
67503
  return true;
67222
67504
  } catch {
67223
67505
  return false;
@@ -67225,62 +67507,62 @@ function existsSync3(p3) {
67225
67507
  }
67226
67508
  function isDir(p3) {
67227
67509
  try {
67228
- return fs58.statSync(p3).isDirectory();
67510
+ return fs59.statSync(p3).isDirectory();
67229
67511
  } catch {
67230
67512
  return false;
67231
67513
  }
67232
67514
  }
67233
67515
  function readdirSafe(p3) {
67234
67516
  try {
67235
- return fs58.readdirSync(p3);
67517
+ return fs59.readdirSync(p3);
67236
67518
  } catch {
67237
67519
  return [];
67238
67520
  }
67239
67521
  }
67240
67522
  function rmdirIfEmpty(p3) {
67241
67523
  try {
67242
- fs58.rmdirSync(p3);
67524
+ fs59.rmdirSync(p3);
67243
67525
  } catch {
67244
67526
  }
67245
67527
  }
67246
67528
 
67247
67529
  // src/migrations/2026-08-18-drop-seeded-projects.ts
67248
- var fs59 = __toESM(require("fs"), 1);
67249
- var path60 = __toESM(require("path"), 1);
67530
+ var fs60 = __toESM(require("fs"), 1);
67531
+ var path61 = __toESM(require("path"), 1);
67250
67532
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
67251
67533
  function dropSeededProjects(opts) {
67252
- fs59.mkdirSync(opts.dataDir, { recursive: true });
67253
- const flag = path60.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
67254
- if (fs59.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
67255
- const file = path60.join(opts.dataDir, "projects.json");
67534
+ fs60.mkdirSync(opts.dataDir, { recursive: true });
67535
+ const flag = path61.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
67536
+ if (fs60.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
67537
+ const file = path61.join(opts.dataDir, "projects.json");
67256
67538
  let raw = null;
67257
67539
  let dropped = 0;
67258
67540
  try {
67259
- raw = fs59.readFileSync(file, "utf8");
67541
+ raw = fs60.readFileSync(file, "utf8");
67260
67542
  dropped = JSON.parse(raw).projects?.length ?? 0;
67261
67543
  } catch {
67262
67544
  }
67263
67545
  let backup = null;
67264
67546
  if (raw != null && dropped > 0) {
67265
- const dir = path60.join(opts.dataDir, "backups");
67266
- fs59.mkdirSync(dir, { recursive: true });
67267
- backup = path60.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
67268
- fs59.writeFileSync(backup, raw);
67547
+ const dir = path61.join(opts.dataDir, "backups");
67548
+ fs60.mkdirSync(dir, { recursive: true });
67549
+ backup = path61.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
67550
+ fs60.writeFileSync(backup, raw);
67269
67551
  }
67270
67552
  if (raw != null || dropped > 0) {
67271
- fs59.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
67553
+ fs60.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
67272
67554
  }
67273
- fs59.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
67555
+ fs60.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
67274
67556
  return { skipped: false, dropped, backup };
67275
67557
  }
67276
67558
 
67277
67559
  // src/transport/http-router.ts
67278
- var import_node_fs46 = __toESM(require("fs"), 1);
67279
- var import_node_path51 = __toESM(require("path"), 1);
67560
+ var import_node_fs47 = __toESM(require("fs"), 1);
67561
+ var import_node_path52 = __toESM(require("path"), 1);
67280
67562
 
67281
67563
  // src/attachment/upload.ts
67282
- var import_node_fs45 = __toESM(require("fs"), 1);
67283
- var import_node_path49 = __toESM(require("path"), 1);
67564
+ var import_node_fs46 = __toESM(require("fs"), 1);
67565
+ var import_node_path50 = __toESM(require("path"), 1);
67284
67566
  var import_node_crypto15 = __toESM(require("crypto"), 1);
67285
67567
  var import_promises8 = require("stream/promises");
67286
67568
  var UploadError = class extends Error {
@@ -67292,22 +67574,22 @@ var UploadError = class extends Error {
67292
67574
  code;
67293
67575
  };
67294
67576
  function assertValidFileName(fileName) {
67295
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path49.default.basename(fileName)) {
67577
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path50.default.basename(fileName)) {
67296
67578
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
67297
67579
  }
67298
67580
  }
67299
67581
  var HASH_PREFIX_LEN = 16;
67300
67582
  async function writeUploadedAttachment(args) {
67301
67583
  assertValidFileName(args.fileName);
67302
- const attachmentsRoot = import_node_path49.default.join(args.baseDir, ".attachments");
67584
+ const attachmentsRoot = import_node_path50.default.join(args.baseDir, ".attachments");
67303
67585
  try {
67304
- import_node_fs45.default.mkdirSync(attachmentsRoot, { recursive: true });
67586
+ import_node_fs46.default.mkdirSync(attachmentsRoot, { recursive: true });
67305
67587
  } catch (err) {
67306
67588
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
67307
67589
  }
67308
67590
  const hasher = import_node_crypto15.default.createHash("sha256");
67309
67591
  let actualSize = 0;
67310
- const tmpPath = import_node_path49.default.join(
67592
+ const tmpPath = import_node_path50.default.join(
67311
67593
  attachmentsRoot,
67312
67594
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto15.default.randomBytes(4).toString("hex")}`
67313
67595
  );
@@ -67322,18 +67604,18 @@ async function writeUploadedAttachment(args) {
67322
67604
  yield buf;
67323
67605
  }
67324
67606
  },
67325
- import_node_fs45.default.createWriteStream(tmpPath, { mode: 384 })
67607
+ import_node_fs46.default.createWriteStream(tmpPath, { mode: 384 })
67326
67608
  );
67327
67609
  } catch (err) {
67328
67610
  try {
67329
- import_node_fs45.default.unlinkSync(tmpPath);
67611
+ import_node_fs46.default.unlinkSync(tmpPath);
67330
67612
  } catch {
67331
67613
  }
67332
67614
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
67333
67615
  }
67334
67616
  if (actualSize !== args.contentLength) {
67335
67617
  try {
67336
- import_node_fs45.default.unlinkSync(tmpPath);
67618
+ import_node_fs46.default.unlinkSync(tmpPath);
67337
67619
  } catch {
67338
67620
  }
67339
67621
  throw new UploadError(
@@ -67342,34 +67624,34 @@ async function writeUploadedAttachment(args) {
67342
67624
  );
67343
67625
  }
67344
67626
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
67345
- const hashDir = import_node_path49.default.join(attachmentsRoot, attachmentId);
67627
+ const hashDir = import_node_path50.default.join(attachmentsRoot, attachmentId);
67346
67628
  let finalFileName;
67347
67629
  let hashDirExists = false;
67348
67630
  try {
67349
- hashDirExists = import_node_fs45.default.statSync(hashDir).isDirectory();
67631
+ hashDirExists = import_node_fs46.default.statSync(hashDir).isDirectory();
67350
67632
  } catch {
67351
67633
  }
67352
67634
  if (hashDirExists) {
67353
- const existing = import_node_fs45.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
67635
+ const existing = import_node_fs46.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
67354
67636
  finalFileName = existing[0] ?? args.fileName;
67355
67637
  try {
67356
- import_node_fs45.default.unlinkSync(tmpPath);
67638
+ import_node_fs46.default.unlinkSync(tmpPath);
67357
67639
  } catch {
67358
67640
  }
67359
67641
  } else {
67360
67642
  try {
67361
- import_node_fs45.default.mkdirSync(hashDir, { recursive: true });
67643
+ import_node_fs46.default.mkdirSync(hashDir, { recursive: true });
67362
67644
  finalFileName = args.fileName;
67363
- import_node_fs45.default.renameSync(tmpPath, import_node_path49.default.join(hashDir, finalFileName));
67645
+ import_node_fs46.default.renameSync(tmpPath, import_node_path50.default.join(hashDir, finalFileName));
67364
67646
  } catch (err) {
67365
67647
  try {
67366
- import_node_fs45.default.unlinkSync(tmpPath);
67648
+ import_node_fs46.default.unlinkSync(tmpPath);
67367
67649
  } catch {
67368
67650
  }
67369
67651
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
67370
67652
  }
67371
67653
  }
67372
- const absPath = import_node_path49.default.join(hashDir, finalFileName);
67654
+ const absPath = import_node_path50.default.join(hashDir, finalFileName);
67373
67655
  const relPath = absPath;
67374
67656
  args.groupFileStore.upsert(args.scope, args.sessionId, {
67375
67657
  relPath: absPath,
@@ -67384,8 +67666,8 @@ async function writeUploadedAttachment(args) {
67384
67666
 
67385
67667
  // src/extension/import.ts
67386
67668
  var import_promises9 = __toESM(require("fs/promises"), 1);
67387
- var import_node_path50 = __toESM(require("path"), 1);
67388
- var import_node_os18 = __toESM(require("os"), 1);
67669
+ var import_node_path51 = __toESM(require("path"), 1);
67670
+ var import_node_os19 = __toESM(require("os"), 1);
67389
67671
  var import_jszip = __toESM(require_lib3(), 1);
67390
67672
  var ImportError = class extends Error {
67391
67673
  constructor(code, message) {
@@ -67402,7 +67684,7 @@ async function importZip(buf, root) {
67402
67684
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
67403
67685
  }
67404
67686
  for (const name of Object.keys(zip.files)) {
67405
- if (name.includes("..") || name.startsWith("/") || import_node_path50.default.isAbsolute(name)) {
67687
+ if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
67406
67688
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
67407
67689
  }
67408
67690
  }
@@ -67435,7 +67717,7 @@ async function importZip(buf, root) {
67435
67717
  );
67436
67718
  }
67437
67719
  }
67438
- const destDir = import_node_path50.default.join(root, manifest.id);
67720
+ const destDir = import_node_path51.default.join(root, manifest.id);
67439
67721
  let destExists = false;
67440
67722
  try {
67441
67723
  await import_promises9.default.access(destDir);
@@ -67445,15 +67727,15 @@ async function importZip(buf, root) {
67445
67727
  if (destExists) {
67446
67728
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
67447
67729
  }
67448
- const stage = await import_promises9.default.mkdtemp(import_node_path50.default.join(import_node_os18.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
67730
+ const stage = await import_promises9.default.mkdtemp(import_node_path51.default.join(import_node_os19.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
67449
67731
  try {
67450
67732
  for (const [name, entry] of Object.entries(zip.files)) {
67451
- const dest = import_node_path50.default.join(stage, name);
67733
+ const dest = import_node_path51.default.join(stage, name);
67452
67734
  if (entry.dir) {
67453
67735
  await import_promises9.default.mkdir(dest, { recursive: true });
67454
67736
  continue;
67455
67737
  }
67456
- await import_promises9.default.mkdir(import_node_path50.default.dirname(dest), { recursive: true });
67738
+ await import_promises9.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
67457
67739
  const content = await entry.async("nodebuffer");
67458
67740
  await import_promises9.default.writeFile(dest, content);
67459
67741
  }
@@ -67507,7 +67789,7 @@ var SHARE_UI_ASSET_MIME = {
67507
67789
  ".wasm": "application/wasm"
67508
67790
  };
67509
67791
  function shareUiAssetMime(filePath) {
67510
- const ext = import_node_path51.default.extname(filePath).toLowerCase();
67792
+ const ext = import_node_path52.default.extname(filePath).toLowerCase();
67511
67793
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
67512
67794
  }
67513
67795
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -67606,7 +67888,7 @@ function isValidUploadFileName(fileName) {
67606
67888
  if (fileName === "." || fileName === "..") return false;
67607
67889
  if (fileName.startsWith(".")) return false;
67608
67890
  if (fileName.includes("/") || fileName.includes("\\")) return false;
67609
- return fileName === import_node_path51.default.basename(fileName);
67891
+ return fileName === import_node_path52.default.basename(fileName);
67610
67892
  }
67611
67893
  function createHttpRouter(deps) {
67612
67894
  return async (req, res) => {
@@ -67690,7 +67972,7 @@ function createHttpRouter(deps) {
67690
67972
  }
67691
67973
  let buf;
67692
67974
  try {
67693
- buf = await import_node_fs46.default.promises.readFile(abs);
67975
+ buf = await import_node_fs47.default.promises.readFile(abs);
67694
67976
  } catch {
67695
67977
  sendJson2(res, 404, { code: "NOT_FOUND", message: "asset not found" });
67696
67978
  return true;
@@ -67836,7 +68118,7 @@ function createHttpRouter(deps) {
67836
68118
  sendHtml(res, statusByCode[r2.code], loader.renderErrorHtml(r2.code, msgByCode[r2.code]));
67837
68119
  return true;
67838
68120
  }
67839
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path51.default.basename(r2.absPath)));
68121
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path52.default.basename(r2.absPath)));
67840
68122
  return true;
67841
68123
  }
67842
68124
  const ctx = deps.authResolver.resolveFromHeader(
@@ -67957,7 +68239,7 @@ function createHttpRouter(deps) {
67957
68239
  return true;
67958
68240
  }
67959
68241
  let absPath;
67960
- if (import_node_path51.default.isAbsolute(pathParam)) {
68242
+ if (import_node_path52.default.isAbsolute(pathParam)) {
67961
68243
  absPath = pathParam;
67962
68244
  } else if (deps.sessionStore) {
67963
68245
  const file = deps.sessionStore.read(sid);
@@ -67965,7 +68247,7 @@ function createHttpRouter(deps) {
67965
68247
  sendJson2(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
67966
68248
  return true;
67967
68249
  }
67968
- absPath = import_node_path51.default.join(file.cwd, pathParam);
68250
+ absPath = import_node_path52.default.join(file.cwd, pathParam);
67969
68251
  } else {
67970
68252
  sendJson2(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
67971
68253
  return true;
@@ -68049,7 +68331,7 @@ function withCtx(ctx, body) {
68049
68331
  function streamFile(res, absPath, logger) {
68050
68332
  let stat;
68051
68333
  try {
68052
- stat = import_node_fs46.default.statSync(absPath);
68334
+ stat = import_node_fs47.default.statSync(absPath);
68053
68335
  } catch (err) {
68054
68336
  const code = err?.code;
68055
68337
  if (code === "ENOENT") {
@@ -68064,7 +68346,7 @@ function streamFile(res, absPath, logger) {
68064
68346
  return;
68065
68347
  }
68066
68348
  const mime = lookupMime(absPath);
68067
- const basename2 = import_node_path51.default.basename(absPath);
68349
+ const basename2 = import_node_path52.default.basename(absPath);
68068
68350
  res.writeHead(200, {
68069
68351
  "Content-Type": mime,
68070
68352
  "Content-Length": String(stat.size),
@@ -68072,7 +68354,7 @@ function streamFile(res, absPath, logger) {
68072
68354
  // 防止浏览器把任意 mime 当 html 渲染
68073
68355
  "X-Content-Type-Options": "nosniff"
68074
68356
  });
68075
- const stream = import_node_fs46.default.createReadStream(absPath);
68357
+ const stream = import_node_fs47.default.createReadStream(absPath);
68076
68358
  stream.on("error", (err) => {
68077
68359
  logger?.warn("streamFile read error", { absPath, err: err.message });
68078
68360
  res.destroy();
@@ -68081,8 +68363,8 @@ function streamFile(res, absPath, logger) {
68081
68363
  }
68082
68364
 
68083
68365
  // src/attachment/gc.ts
68084
- var import_node_fs47 = __toESM(require("fs"), 1);
68085
- var import_node_path52 = __toESM(require("path"), 1);
68366
+ var import_node_fs48 = __toESM(require("fs"), 1);
68367
+ var import_node_path53 = __toESM(require("path"), 1);
68086
68368
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
68087
68369
  function runAttachmentGc(args) {
68088
68370
  const now = (args.now ?? Date.now)();
@@ -68091,12 +68373,12 @@ function runAttachmentGc(args) {
68091
68373
  for (const { scope, sessionId } of args.sessionScopes) {
68092
68374
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
68093
68375
  if (entry.stale) continue;
68094
- if (import_node_path52.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
68376
+ if (import_node_path53.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
68095
68377
  }
68096
68378
  }
68097
68379
  const visited = /* @__PURE__ */ new Set();
68098
68380
  for (const { scope, sessionId } of args.sessionScopes) {
68099
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path52.default.join(
68381
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path53.default.join(
68100
68382
  args.dataDir,
68101
68383
  "sessions",
68102
68384
  ...scopeSubPath(scope).map(safeFileName),
@@ -68109,28 +68391,28 @@ function runAttachmentGc(args) {
68109
68391
  return true;
68110
68392
  });
68111
68393
  for (const rootDir of roots) {
68112
- const attRoot = import_node_path52.default.join(rootDir, ".attachments");
68394
+ const attRoot = import_node_path53.default.join(rootDir, ".attachments");
68113
68395
  let hashDirs;
68114
68396
  try {
68115
- hashDirs = import_node_fs47.default.readdirSync(attRoot);
68397
+ hashDirs = import_node_fs48.default.readdirSync(attRoot);
68116
68398
  } catch (err) {
68117
68399
  if (err.code === "ENOENT") continue;
68118
68400
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
68119
68401
  continue;
68120
68402
  }
68121
68403
  for (const hashDir of hashDirs) {
68122
- const hashDirAbs = import_node_path52.default.join(attRoot, hashDir);
68404
+ const hashDirAbs = import_node_path53.default.join(attRoot, hashDir);
68123
68405
  let files;
68124
68406
  try {
68125
- files = import_node_fs47.default.readdirSync(hashDirAbs);
68407
+ files = import_node_fs48.default.readdirSync(hashDirAbs);
68126
68408
  } catch {
68127
68409
  continue;
68128
68410
  }
68129
68411
  for (const name of files) {
68130
- const file = import_node_path52.default.join(hashDirAbs, name);
68412
+ const file = import_node_path53.default.join(hashDirAbs, name);
68131
68413
  let stat;
68132
68414
  try {
68133
- stat = import_node_fs47.default.statSync(file);
68415
+ stat = import_node_fs48.default.statSync(file);
68134
68416
  } catch {
68135
68417
  continue;
68136
68418
  }
@@ -68139,18 +68421,18 @@ function runAttachmentGc(args) {
68139
68421
  if (age < ttlMs) continue;
68140
68422
  if (liveAbs.has(file)) continue;
68141
68423
  try {
68142
- import_node_fs47.default.unlinkSync(file);
68424
+ import_node_fs48.default.unlinkSync(file);
68143
68425
  } catch (err) {
68144
68426
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
68145
68427
  }
68146
68428
  }
68147
68429
  try {
68148
- if (import_node_fs47.default.readdirSync(hashDirAbs).length === 0) import_node_fs47.default.rmdirSync(hashDirAbs);
68430
+ if (import_node_fs48.default.readdirSync(hashDirAbs).length === 0) import_node_fs48.default.rmdirSync(hashDirAbs);
68149
68431
  } catch {
68150
68432
  }
68151
68433
  }
68152
68434
  try {
68153
- if (import_node_fs47.default.readdirSync(attRoot).length === 0) import_node_fs47.default.rmdirSync(attRoot);
68435
+ if (import_node_fs48.default.readdirSync(attRoot).length === 0) import_node_fs48.default.rmdirSync(attRoot);
68154
68436
  } catch {
68155
68437
  }
68156
68438
  }
@@ -68158,8 +68440,8 @@ function runAttachmentGc(args) {
68158
68440
  }
68159
68441
 
68160
68442
  // src/attachment/group.ts
68161
- var import_node_fs48 = __toESM(require("fs"), 1);
68162
- var import_node_path53 = __toESM(require("path"), 1);
68443
+ var import_node_fs49 = __toESM(require("fs"), 1);
68444
+ var import_node_path54 = __toESM(require("path"), 1);
68163
68445
  var import_node_crypto16 = __toESM(require("crypto"), 1);
68164
68446
  init_protocol();
68165
68447
  var GroupFileStore = class {
@@ -68171,11 +68453,11 @@ var GroupFileStore = class {
68171
68453
  this.logger = opts.logger;
68172
68454
  }
68173
68455
  rootForScope(scope) {
68174
- return import_node_path53.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
68456
+ return import_node_path54.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
68175
68457
  }
68176
68458
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
68177
68459
  filePath(scope, sessionId) {
68178
- return import_node_path53.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
68460
+ return import_node_path54.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
68179
68461
  }
68180
68462
  cacheKey(scope, sessionId) {
68181
68463
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -68184,7 +68466,7 @@ var GroupFileStore = class {
68184
68466
  readFile(scope, sessionId) {
68185
68467
  const file = this.filePath(scope, sessionId);
68186
68468
  try {
68187
- const raw = import_node_fs48.default.readFileSync(file, "utf8");
68469
+ const raw = import_node_fs49.default.readFileSync(file, "utf8");
68188
68470
  const parsed = JSON.parse(raw);
68189
68471
  if (!Array.isArray(parsed)) {
68190
68472
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -68210,10 +68492,10 @@ var GroupFileStore = class {
68210
68492
  }
68211
68493
  writeFile(scope, sessionId, entries) {
68212
68494
  const file = this.filePath(scope, sessionId);
68213
- import_node_fs48.default.mkdirSync(import_node_path53.default.dirname(file), { recursive: true });
68495
+ import_node_fs49.default.mkdirSync(import_node_path54.default.dirname(file), { recursive: true });
68214
68496
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
68215
- import_node_fs48.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
68216
- import_node_fs48.default.renameSync(tmp, file);
68497
+ import_node_fs49.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
68498
+ import_node_fs49.default.renameSync(tmp, file);
68217
68499
  }
68218
68500
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
68219
68501
  list(scope, sessionId) {
@@ -68305,7 +68587,7 @@ var GroupFileStore = class {
68305
68587
  */
68306
68588
  deleteSession(scope, sessionId) {
68307
68589
  try {
68308
- import_node_fs48.default.unlinkSync(this.filePath(scope, sessionId));
68590
+ import_node_fs49.default.unlinkSync(this.filePath(scope, sessionId));
68309
68591
  } catch (err) {
68310
68592
  if (err?.code !== "ENOENT") throw err;
68311
68593
  }
@@ -68318,7 +68600,7 @@ var GroupFileStore = class {
68318
68600
  * 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
68319
68601
  */
68320
68602
  deletePersona(personaId2) {
68321
- import_node_fs48.default.rmSync(import_node_path53.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
68603
+ import_node_fs49.default.rmSync(import_node_path54.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
68322
68604
  const prefix = `persona:${personaId2}:`;
68323
68605
  for (const key of this.cache.keys()) {
68324
68606
  if (key.startsWith(prefix)) this.cache.delete(key);
@@ -68327,10 +68609,10 @@ var GroupFileStore = class {
68327
68609
  };
68328
68610
 
68329
68611
  // src/discovery/state-file.ts
68330
- var import_node_fs49 = __toESM(require("fs"), 1);
68331
- var import_node_path54 = __toESM(require("path"), 1);
68612
+ var import_node_fs50 = __toESM(require("fs"), 1);
68613
+ var import_node_path55 = __toESM(require("path"), 1);
68332
68614
  function defaultStateFilePath(dataDir) {
68333
- return import_node_path54.default.join(dataDir, "state.json");
68615
+ return import_node_path55.default.join(dataDir, "state.json");
68334
68616
  }
68335
68617
  function isPidAlive(pid) {
68336
68618
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -68352,7 +68634,7 @@ var StateFileManager = class {
68352
68634
  }
68353
68635
  read() {
68354
68636
  try {
68355
- const raw = import_node_fs49.default.readFileSync(this.file, "utf8");
68637
+ const raw = import_node_fs50.default.readFileSync(this.file, "utf8");
68356
68638
  const parsed = JSON.parse(raw);
68357
68639
  return parsed;
68358
68640
  } catch {
@@ -68366,20 +68648,20 @@ var StateFileManager = class {
68366
68648
  return { status: "stale", existing };
68367
68649
  }
68368
68650
  write(state) {
68369
- import_node_fs49.default.mkdirSync(import_node_path54.default.dirname(this.file), { recursive: true });
68651
+ import_node_fs50.default.mkdirSync(import_node_path55.default.dirname(this.file), { recursive: true });
68370
68652
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
68371
- import_node_fs49.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
68372
- import_node_fs49.default.renameSync(tmp, this.file);
68653
+ import_node_fs50.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
68654
+ import_node_fs50.default.renameSync(tmp, this.file);
68373
68655
  if (process.platform !== "win32") {
68374
68656
  try {
68375
- import_node_fs49.default.chmodSync(this.file, 384);
68657
+ import_node_fs50.default.chmodSync(this.file, 384);
68376
68658
  } catch {
68377
68659
  }
68378
68660
  }
68379
68661
  }
68380
68662
  delete() {
68381
68663
  try {
68382
- import_node_fs49.default.unlinkSync(this.file);
68664
+ import_node_fs50.default.unlinkSync(this.file);
68383
68665
  } catch {
68384
68666
  }
68385
68667
  }
@@ -68393,14 +68675,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
68393
68675
  }
68394
68676
 
68395
68677
  // src/tunnel/tunnel-manager.ts
68396
- var import_node_fs53 = __toESM(require("fs"), 1);
68397
- var import_node_path58 = __toESM(require("path"), 1);
68678
+ var import_node_fs54 = __toESM(require("fs"), 1);
68679
+ var import_node_path59 = __toESM(require("path"), 1);
68398
68680
  var import_node_crypto17 = __toESM(require("crypto"), 1);
68399
68681
  var import_node_child_process16 = require("child_process");
68400
68682
 
68401
68683
  // src/tunnel/tunnel-store.ts
68402
- var import_node_fs50 = __toESM(require("fs"), 1);
68403
- var import_node_path55 = __toESM(require("path"), 1);
68684
+ var import_node_fs51 = __toESM(require("fs"), 1);
68685
+ var import_node_path56 = __toESM(require("path"), 1);
68404
68686
  var TunnelStore = class {
68405
68687
  constructor(filePath) {
68406
68688
  this.filePath = filePath;
@@ -68408,7 +68690,7 @@ var TunnelStore = class {
68408
68690
  filePath;
68409
68691
  async get() {
68410
68692
  try {
68411
- const raw = await import_node_fs50.default.promises.readFile(this.filePath, "utf8");
68693
+ const raw = await import_node_fs51.default.promises.readFile(this.filePath, "utf8");
68412
68694
  const obj = JSON.parse(raw);
68413
68695
  if (!isPersistedTunnel(obj)) return null;
68414
68696
  return obj;
@@ -68419,22 +68701,22 @@ var TunnelStore = class {
68419
68701
  }
68420
68702
  }
68421
68703
  async set(v3) {
68422
- const dir = import_node_path55.default.dirname(this.filePath);
68423
- await import_node_fs50.default.promises.mkdir(dir, { recursive: true });
68704
+ const dir = import_node_path56.default.dirname(this.filePath);
68705
+ await import_node_fs51.default.promises.mkdir(dir, { recursive: true });
68424
68706
  const data = JSON.stringify(v3, null, 2);
68425
68707
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
68426
- await import_node_fs50.default.promises.writeFile(tmp, data, { mode: 384 });
68708
+ await import_node_fs51.default.promises.writeFile(tmp, data, { mode: 384 });
68427
68709
  if (process.platform !== "win32") {
68428
68710
  try {
68429
- await import_node_fs50.default.promises.chmod(tmp, 384);
68711
+ await import_node_fs51.default.promises.chmod(tmp, 384);
68430
68712
  } catch {
68431
68713
  }
68432
68714
  }
68433
- await import_node_fs50.default.promises.rename(tmp, this.filePath);
68715
+ await import_node_fs51.default.promises.rename(tmp, this.filePath);
68434
68716
  }
68435
68717
  async clear() {
68436
68718
  try {
68437
- await import_node_fs50.default.promises.unlink(this.filePath);
68719
+ await import_node_fs51.default.promises.unlink(this.filePath);
68438
68720
  } catch (err) {
68439
68721
  const code = err?.code;
68440
68722
  if (code !== "ENOENT") throw err;
@@ -68529,9 +68811,9 @@ function escape2(v3) {
68529
68811
  }
68530
68812
 
68531
68813
  // src/tunnel/frpc-binary.ts
68532
- var import_node_fs51 = __toESM(require("fs"), 1);
68533
- var import_node_os19 = __toESM(require("os"), 1);
68534
- var import_node_path56 = __toESM(require("path"), 1);
68814
+ var import_node_fs52 = __toESM(require("fs"), 1);
68815
+ var import_node_os20 = __toESM(require("os"), 1);
68816
+ var import_node_path57 = __toESM(require("path"), 1);
68535
68817
  var import_node_child_process14 = require("child_process");
68536
68818
  var import_node_stream4 = require("stream");
68537
68819
  var import_promises10 = require("stream/promises");
@@ -68563,20 +68845,20 @@ function frpcDownloadUrl(version2, p3) {
68563
68845
  }
68564
68846
  async function ensureFrpcBinary(opts) {
68565
68847
  if (opts.override) {
68566
- if (!import_node_fs51.default.existsSync(opts.override)) {
68848
+ if (!import_node_fs52.default.existsSync(opts.override)) {
68567
68849
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
68568
68850
  }
68569
68851
  return opts.override;
68570
68852
  }
68571
68853
  const version2 = opts.version ?? FRPC_VERSION;
68572
68854
  const platform = opts.platform ?? detectPlatform();
68573
- const binDir = import_node_path56.default.join(opts.dataDir, "bin");
68574
- import_node_fs51.default.mkdirSync(binDir, { recursive: true });
68855
+ const binDir = import_node_path57.default.join(opts.dataDir, "bin");
68856
+ import_node_fs52.default.mkdirSync(binDir, { recursive: true });
68575
68857
  cleanupStaleArtifacts(binDir);
68576
- const stableBin = import_node_path56.default.join(binDir, "frpc");
68577
- if (import_node_fs51.default.existsSync(stableBin)) return stableBin;
68858
+ const stableBin = import_node_path57.default.join(binDir, "frpc");
68859
+ if (import_node_fs52.default.existsSync(stableBin)) return stableBin;
68578
68860
  const partialBin = `${stableBin}.partial`;
68579
- const tarballPath = import_node_path56.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
68861
+ const tarballPath = import_node_path57.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
68580
68862
  try {
68581
68863
  const url = frpcDownloadUrl(version2, platform);
68582
68864
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -68585,8 +68867,8 @@ async function ensureFrpcBinary(opts) {
68585
68867
  } else {
68586
68868
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
68587
68869
  }
68588
- import_node_fs51.default.chmodSync(partialBin, 493);
68589
- import_node_fs51.default.renameSync(partialBin, stableBin);
68870
+ import_node_fs52.default.chmodSync(partialBin, 493);
68871
+ import_node_fs52.default.renameSync(partialBin, stableBin);
68590
68872
  } finally {
68591
68873
  safeUnlink(tarballPath);
68592
68874
  safeUnlink(partialBin);
@@ -68596,15 +68878,15 @@ async function ensureFrpcBinary(opts) {
68596
68878
  function cleanupStaleArtifacts(binDir) {
68597
68879
  let entries;
68598
68880
  try {
68599
- entries = import_node_fs51.default.readdirSync(binDir);
68881
+ entries = import_node_fs52.default.readdirSync(binDir);
68600
68882
  } catch {
68601
68883
  return;
68602
68884
  }
68603
68885
  for (const name of entries) {
68604
68886
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
68605
- const full = import_node_path56.default.join(binDir, name);
68887
+ const full = import_node_path57.default.join(binDir, name);
68606
68888
  try {
68607
- import_node_fs51.default.rmSync(full, { recursive: true, force: true });
68889
+ import_node_fs52.default.rmSync(full, { recursive: true, force: true });
68608
68890
  } catch {
68609
68891
  }
68610
68892
  }
@@ -68612,7 +68894,7 @@ function cleanupStaleArtifacts(binDir) {
68612
68894
  }
68613
68895
  function safeUnlink(p3) {
68614
68896
  try {
68615
- import_node_fs51.default.unlinkSync(p3);
68897
+ import_node_fs52.default.unlinkSync(p3);
68616
68898
  } catch {
68617
68899
  }
68618
68900
  }
@@ -68623,13 +68905,13 @@ async function downloadToFile(url, dest, fetchImpl) {
68623
68905
  if (!res.ok || !res.body) {
68624
68906
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
68625
68907
  }
68626
- const out = import_node_fs51.default.createWriteStream(dest);
68908
+ const out = import_node_fs52.default.createWriteStream(dest);
68627
68909
  const nodeStream = import_node_stream4.Readable.fromWeb(res.body);
68628
68910
  await (0, import_promises10.pipeline)(nodeStream, out);
68629
68911
  }
68630
68912
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
68631
- const work = import_node_path56.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
68632
- import_node_fs51.default.mkdirSync(work, { recursive: true });
68913
+ const work = import_node_path57.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
68914
+ import_node_fs52.default.mkdirSync(work, { recursive: true });
68633
68915
  try {
68634
68916
  await new Promise((resolve9, reject) => {
68635
68917
  const proc = (0, import_node_child_process14.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -68637,32 +68919,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
68637
68919
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
68638
68920
  });
68639
68921
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
68640
- const src = import_node_path56.default.join(work, dirName, "frpc");
68641
- if (!import_node_fs51.default.existsSync(src)) {
68922
+ const src = import_node_path57.default.join(work, dirName, "frpc");
68923
+ if (!import_node_fs52.default.existsSync(src)) {
68642
68924
  throw new Error(`frpc not found inside tarball at ${src}`);
68643
68925
  }
68644
- import_node_fs51.default.copyFileSync(src, destBin);
68926
+ import_node_fs52.default.copyFileSync(src, destBin);
68645
68927
  } finally {
68646
- import_node_fs51.default.rmSync(work, { recursive: true, force: true });
68928
+ import_node_fs52.default.rmSync(work, { recursive: true, force: true });
68647
68929
  }
68648
68930
  }
68649
68931
 
68650
68932
  // src/tunnel/frpc-process.ts
68651
- var import_node_fs52 = __toESM(require("fs"), 1);
68652
- var import_node_path57 = __toESM(require("path"), 1);
68933
+ var import_node_fs53 = __toESM(require("fs"), 1);
68934
+ var import_node_path58 = __toESM(require("path"), 1);
68653
68935
  var import_node_child_process15 = require("child_process");
68654
68936
  function frpcPidFilePath(dataDir) {
68655
- return import_node_path57.default.join(dataDir, "frpc.pid");
68937
+ return import_node_path58.default.join(dataDir, "frpc.pid");
68656
68938
  }
68657
68939
  function writeFrpcPid(dataDir, pid) {
68658
68940
  try {
68659
- import_node_fs52.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
68941
+ import_node_fs53.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
68660
68942
  } catch {
68661
68943
  }
68662
68944
  }
68663
68945
  function clearFrpcPid(dataDir) {
68664
68946
  try {
68665
- import_node_fs52.default.unlinkSync(frpcPidFilePath(dataDir));
68947
+ import_node_fs53.default.unlinkSync(frpcPidFilePath(dataDir));
68666
68948
  } catch {
68667
68949
  }
68668
68950
  }
@@ -68678,7 +68960,7 @@ function defaultIsPidAlive(pid) {
68678
68960
  }
68679
68961
  function defaultReadPidFile(file) {
68680
68962
  try {
68681
- return import_node_fs52.default.readFileSync(file, "utf8");
68963
+ return import_node_fs53.default.readFileSync(file, "utf8");
68682
68964
  } catch {
68683
68965
  return null;
68684
68966
  }
@@ -68694,7 +68976,7 @@ function defaultSleep2(ms) {
68694
68976
  }
68695
68977
  async function killStaleFrpc(deps) {
68696
68978
  const pidFile = frpcPidFilePath(deps.dataDir);
68697
- const tomlPath = import_node_path57.default.join(deps.dataDir, "frpc.toml");
68979
+ const tomlPath = import_node_path58.default.join(deps.dataDir, "frpc.toml");
68698
68980
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
68699
68981
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
68700
68982
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -68718,7 +69000,7 @@ async function killStaleFrpc(deps) {
68718
69000
  }
68719
69001
  if (victims.size === 0) {
68720
69002
  try {
68721
- import_node_fs52.default.unlinkSync(pidFile);
69003
+ import_node_fs53.default.unlinkSync(pidFile);
68722
69004
  } catch {
68723
69005
  }
68724
69006
  return;
@@ -68729,7 +69011,7 @@ async function killStaleFrpc(deps) {
68729
69011
  }
68730
69012
  await sleep2(deps.reapWaitMs ?? 300);
68731
69013
  try {
68732
- import_node_fs52.default.unlinkSync(pidFile);
69014
+ import_node_fs53.default.unlinkSync(pidFile);
68733
69015
  } catch {
68734
69016
  }
68735
69017
  }
@@ -68766,7 +69048,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
68766
69048
  var TunnelManager = class {
68767
69049
  constructor(deps) {
68768
69050
  this.deps = deps;
68769
- this.store = deps.store ?? new TunnelStore(import_node_path58.default.join(deps.dataDir, "tunnel.json"));
69051
+ this.store = deps.store ?? new TunnelStore(import_node_path59.default.join(deps.dataDir, "tunnel.json"));
68770
69052
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
68771
69053
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
68772
69054
  }
@@ -68893,7 +69175,7 @@ var TunnelManager = class {
68893
69175
  dataDir: this.deps.dataDir,
68894
69176
  override: this.deps.frpcBinaryOverride ?? void 0
68895
69177
  });
68896
- const tomlPath = import_node_path58.default.join(this.deps.dataDir, "frpc.toml");
69178
+ const tomlPath = import_node_path59.default.join(this.deps.dataDir, "frpc.toml");
68897
69179
  const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto17.default.randomBytes(3).toString("hex")}`;
68898
69180
  const toml = buildFrpcToml({
68899
69181
  serverAddr: t2.frpsHost,
@@ -68904,14 +69186,14 @@ var TunnelManager = class {
68904
69186
  localPort,
68905
69187
  logLevel: "info"
68906
69188
  });
68907
- await import_node_fs53.default.promises.writeFile(tomlPath, toml, { mode: 384 });
69189
+ await import_node_fs54.default.promises.writeFile(tomlPath, toml, { mode: 384 });
68908
69190
  const proc = (this.deps.spawnImpl ?? import_node_child_process16.spawn)(frpcBin, ["-c", tomlPath], {
68909
69191
  stdio: ["ignore", "pipe", "pipe"]
68910
69192
  });
68911
- const logDir = import_node_path58.default.join(this.deps.dataDir, "log");
68912
- import_node_fs53.default.mkdirSync(logDir, { recursive: true });
68913
- const logFilePath = import_node_path58.default.join(logDir, "frpc.log");
68914
- const logStream = import_node_fs53.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
69193
+ const logDir = import_node_path59.default.join(this.deps.dataDir, "log");
69194
+ import_node_fs54.default.mkdirSync(logDir, { recursive: true });
69195
+ const logFilePath = import_node_path59.default.join(logDir, "frpc.log");
69196
+ const logStream = import_node_fs54.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
68915
69197
  logStream.on("error", () => {
68916
69198
  });
68917
69199
  const tee = (chunk) => {
@@ -68993,28 +69275,28 @@ async function waitForFrpcReady(proc, timeoutMs) {
68993
69275
  }
68994
69276
 
68995
69277
  // src/tunnel/device-key.ts
68996
- var import_node_os20 = __toESM(require("os"), 1);
68997
- var import_node_path59 = __toESM(require("path"), 1);
69278
+ var import_node_os21 = __toESM(require("os"), 1);
69279
+ var import_node_path60 = __toESM(require("path"), 1);
68998
69280
  var import_node_crypto18 = __toESM(require("crypto"), 1);
68999
69281
  var DERIVE_SALT = "clawd-tunnel-device-v1";
69000
69282
  function deriveStableDeviceKey(opts = {}) {
69001
- const hostname = opts.hostname ?? import_node_os20.default.hostname();
69002
- const uid = opts.uid ?? (typeof import_node_os20.default.userInfo === "function" ? import_node_os20.default.userInfo().uid : 0);
69003
- const home = opts.home ?? import_node_os20.default.homedir();
69004
- const defaultDataDir = import_node_path59.default.resolve(import_node_path59.default.join(home, ".clawd"));
69005
- const normalizedDataDir = opts.dataDir ? import_node_path59.default.resolve(opts.dataDir) : null;
69283
+ const hostname = opts.hostname ?? import_node_os21.default.hostname();
69284
+ const uid = opts.uid ?? (typeof import_node_os21.default.userInfo === "function" ? import_node_os21.default.userInfo().uid : 0);
69285
+ const home = opts.home ?? import_node_os21.default.homedir();
69286
+ const defaultDataDir = import_node_path60.default.resolve(import_node_path60.default.join(home, ".clawd"));
69287
+ const normalizedDataDir = opts.dataDir ? import_node_path60.default.resolve(opts.dataDir) : null;
69006
69288
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
69007
69289
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
69008
69290
  return import_node_crypto18.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
69009
69291
  }
69010
69292
 
69011
69293
  // src/auth-store.ts
69012
- var import_node_fs54 = __toESM(require("fs"), 1);
69013
- var import_node_path60 = __toESM(require("path"), 1);
69294
+ var import_node_fs55 = __toESM(require("fs"), 1);
69295
+ var import_node_path61 = __toESM(require("path"), 1);
69014
69296
  var import_node_crypto19 = __toESM(require("crypto"), 1);
69015
69297
  var AUTH_FILE_NAME = "auth.json";
69016
69298
  function authFilePath(dataDir) {
69017
- return import_node_path60.default.join(dataDir, AUTH_FILE_NAME);
69299
+ return import_node_path61.default.join(dataDir, AUTH_FILE_NAME);
69018
69300
  }
69019
69301
  function loadOrCreateAuthFile(opts) {
69020
69302
  const file = authFilePath(opts.dataDir);
@@ -69055,7 +69337,7 @@ function defaultGenerateOwnerPrincipalId() {
69055
69337
  }
69056
69338
  function readAuthFile(file) {
69057
69339
  try {
69058
- const raw = import_node_fs54.default.readFileSync(file, "utf8");
69340
+ const raw = import_node_fs55.default.readFileSync(file, "utf8");
69059
69341
  const parsed = JSON.parse(raw);
69060
69342
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
69061
69343
  return null;
@@ -69076,26 +69358,26 @@ function readAuthFile(file) {
69076
69358
  }
69077
69359
  }
69078
69360
  function writeAuthFile(file, content) {
69079
- import_node_fs54.default.mkdirSync(import_node_path60.default.dirname(file), { recursive: true });
69080
- import_node_fs54.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
69361
+ import_node_fs55.default.mkdirSync(import_node_path61.default.dirname(file), { recursive: true });
69362
+ import_node_fs55.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
69081
69363
  try {
69082
- import_node_fs54.default.chmodSync(file, 384);
69364
+ import_node_fs55.default.chmodSync(file, 384);
69083
69365
  } catch {
69084
69366
  }
69085
69367
  }
69086
69368
 
69087
69369
  // src/owner-profile.ts
69088
- var import_node_fs55 = __toESM(require("fs"), 1);
69089
- var import_node_os21 = __toESM(require("os"), 1);
69090
- var import_node_path61 = __toESM(require("path"), 1);
69370
+ var import_node_fs56 = __toESM(require("fs"), 1);
69371
+ var import_node_os22 = __toESM(require("os"), 1);
69372
+ var import_node_path62 = __toESM(require("path"), 1);
69091
69373
  var PROFILE_FILENAME = "profile.json";
69092
69374
  function profilePath(dataDir) {
69093
- return import_node_path61.default.join(dataDir, PROFILE_FILENAME);
69375
+ return import_node_path62.default.join(dataDir, PROFILE_FILENAME);
69094
69376
  }
69095
69377
  function loadOwnerProfile(dataDir) {
69096
69378
  let raw;
69097
69379
  try {
69098
- raw = import_node_fs55.default.readFileSync(profilePath(dataDir), "utf8");
69380
+ raw = import_node_fs56.default.readFileSync(profilePath(dataDir), "utf8");
69099
69381
  } catch {
69100
69382
  return {};
69101
69383
  }
@@ -69111,11 +69393,11 @@ function loadOwnerProfile(dataDir) {
69111
69393
  }
69112
69394
  function patchOwnerProfile(dataDir, patch) {
69113
69395
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
69114
- import_node_fs55.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
69396
+ import_node_fs56.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
69115
69397
  return merged;
69116
69398
  }
69117
69399
  function loadOwnerDisplayName(dataDir) {
69118
- const fallback = import_node_os21.default.userInfo().username;
69400
+ const fallback = import_node_os22.default.userInfo().username;
69119
69401
  const displayName = loadOwnerProfile(dataDir).displayName;
69120
69402
  if (typeof displayName !== "string" || displayName.length === 0) {
69121
69403
  if (displayName !== void 0) {
@@ -69127,18 +69409,18 @@ function loadOwnerDisplayName(dataDir) {
69127
69409
  }
69128
69410
 
69129
69411
  // src/feishu-auth/owner-identity-store.ts
69130
- var import_node_fs56 = __toESM(require("fs"), 1);
69131
- var import_node_path62 = __toESM(require("path"), 1);
69412
+ var import_node_fs57 = __toESM(require("fs"), 1);
69413
+ var import_node_path63 = __toESM(require("path"), 1);
69132
69414
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
69133
69415
  var OwnerIdentityStore = class {
69134
69416
  file;
69135
69417
  constructor(dataDir) {
69136
- this.file = import_node_path62.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
69418
+ this.file = import_node_path63.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
69137
69419
  }
69138
69420
  read() {
69139
69421
  let raw;
69140
69422
  try {
69141
- raw = import_node_fs56.default.readFileSync(this.file, "utf8");
69423
+ raw = import_node_fs57.default.readFileSync(this.file, "utf8");
69142
69424
  } catch {
69143
69425
  return null;
69144
69426
  }
@@ -69165,16 +69447,16 @@ var OwnerIdentityStore = class {
69165
69447
  };
69166
69448
  }
69167
69449
  write(record4) {
69168
- import_node_fs56.default.mkdirSync(import_node_path62.default.dirname(this.file), { recursive: true });
69169
- import_node_fs56.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
69450
+ import_node_fs57.default.mkdirSync(import_node_path63.default.dirname(this.file), { recursive: true });
69451
+ import_node_fs57.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
69170
69452
  try {
69171
- import_node_fs56.default.chmodSync(this.file, 384);
69453
+ import_node_fs57.default.chmodSync(this.file, 384);
69172
69454
  } catch {
69173
69455
  }
69174
69456
  }
69175
69457
  clear() {
69176
69458
  try {
69177
- import_node_fs56.default.unlinkSync(this.file);
69459
+ import_node_fs57.default.unlinkSync(this.file);
69178
69460
  } catch (err) {
69179
69461
  const code = err?.code;
69180
69462
  if (code !== "ENOENT") throw err;
@@ -69670,8 +69952,8 @@ function verifyConnectToken(args) {
69670
69952
  }
69671
69953
 
69672
69954
  // src/feishu-auth/server-key.ts
69673
- var fs73 = __toESM(require("fs"), 1);
69674
- var path75 = __toESM(require("path"), 1);
69955
+ var fs74 = __toESM(require("fs"), 1);
69956
+ var path76 = __toESM(require("path"), 1);
69675
69957
  var FILE_NAME2 = "server-signing-key.json";
69676
69958
  var ServerKeyStore = class {
69677
69959
  constructor(dataDir) {
@@ -69679,12 +69961,12 @@ var ServerKeyStore = class {
69679
69961
  }
69680
69962
  dataDir;
69681
69963
  filePath() {
69682
- return path75.join(this.dataDir, FILE_NAME2);
69964
+ return path76.join(this.dataDir, FILE_NAME2);
69683
69965
  }
69684
69966
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
69685
69967
  read() {
69686
69968
  try {
69687
- const raw = fs73.readFileSync(this.filePath(), "utf8");
69969
+ const raw = fs74.readFileSync(this.filePath(), "utf8");
69688
69970
  const parsed = JSON.parse(raw);
69689
69971
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
69690
69972
  return parsed.publicKeyPem;
@@ -69699,12 +69981,12 @@ var ServerKeyStore = class {
69699
69981
  publicKeyPem,
69700
69982
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
69701
69983
  };
69702
- fs73.mkdirSync(this.dataDir, { recursive: true });
69703
- fs73.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
69984
+ fs74.mkdirSync(this.dataDir, { recursive: true });
69985
+ fs74.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
69704
69986
  }
69705
69987
  clear() {
69706
69988
  try {
69707
- fs73.unlinkSync(this.filePath());
69989
+ fs74.unlinkSync(this.filePath());
69708
69990
  } catch {
69709
69991
  }
69710
69992
  }
@@ -69714,19 +69996,19 @@ var ServerKeyStore = class {
69714
69996
  init_protocol();
69715
69997
 
69716
69998
  // src/handlers/index.ts
69717
- var import_node_path76 = __toESM(require("path"), 1);
69999
+ var import_node_path79 = __toESM(require("path"), 1);
69718
70000
 
69719
70001
  // src/handlers/session.ts
69720
70002
  init_protocol();
69721
70003
 
69722
70004
  // src/session/fork.ts
69723
- var import_node_fs57 = __toESM(require("fs"), 1);
69724
- var import_node_os22 = __toESM(require("os"), 1);
69725
- var import_node_path63 = __toESM(require("path"), 1);
70005
+ var import_node_fs58 = __toESM(require("fs"), 1);
70006
+ var import_node_os23 = __toESM(require("os"), 1);
70007
+ var import_node_path64 = __toESM(require("path"), 1);
69726
70008
  var import_node_crypto21 = require("crypto");
69727
70009
  init_claude_history();
69728
70010
  function readJsonlEntries(file) {
69729
- const raw = import_node_fs57.default.readFileSync(file, "utf8");
70011
+ const raw = import_node_fs58.default.readFileSync(file, "utf8");
69730
70012
  const out = [];
69731
70013
  for (const line of raw.split("\n")) {
69732
70014
  const t2 = line.trim();
@@ -69739,19 +70021,19 @@ function readJsonlEntries(file) {
69739
70021
  return out;
69740
70022
  }
69741
70023
  function forkSession(input) {
69742
- const baseDir = input.baseDir ?? import_node_path63.default.join(import_node_os22.default.homedir(), ".claude");
69743
- let projectDir = import_node_path63.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
69744
- let sourceFile = import_node_path63.default.join(projectDir, `${input.toolSessionId}.jsonl`);
69745
- if (!import_node_fs57.default.existsSync(sourceFile)) {
70024
+ const baseDir = input.baseDir ?? import_node_path64.default.join(import_node_os23.default.homedir(), ".claude");
70025
+ let projectDir = import_node_path64.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
70026
+ let sourceFile = import_node_path64.default.join(projectDir, `${input.toolSessionId}.jsonl`);
70027
+ if (!import_node_fs58.default.existsSync(sourceFile)) {
69746
70028
  const found = findTranscriptByToolSessionId(
69747
- import_node_path63.default.join(baseDir, "projects"),
70029
+ import_node_path64.default.join(baseDir, "projects"),
69748
70030
  input.toolSessionId
69749
70031
  );
69750
70032
  if (!found) {
69751
70033
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
69752
70034
  }
69753
70035
  sourceFile = found;
69754
- projectDir = import_node_path63.default.dirname(found);
70036
+ projectDir = import_node_path64.default.dirname(found);
69755
70037
  }
69756
70038
  const entries = readJsonlEntries(sourceFile);
69757
70039
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -69780,27 +70062,27 @@ function forkSession(input) {
69780
70062
  }
69781
70063
  forkedLines.push(JSON.stringify(forked));
69782
70064
  }
69783
- const outDir = input.targetCwd ? import_node_path63.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
69784
- const forkedFilePath = import_node_path63.default.join(outDir, `${forkedToolSessionId}.jsonl`);
69785
- import_node_fs57.default.mkdirSync(outDir, { recursive: true });
69786
- import_node_fs57.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
70065
+ const outDir = input.targetCwd ? import_node_path64.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
70066
+ const forkedFilePath = import_node_path64.default.join(outDir, `${forkedToolSessionId}.jsonl`);
70067
+ import_node_fs58.default.mkdirSync(outDir, { recursive: true });
70068
+ import_node_fs58.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
69787
70069
  return { forkedToolSessionId, forkedFilePath };
69788
70070
  }
69789
70071
 
69790
70072
  // src/session/external-scan.ts
69791
- var import_node_fs58 = __toESM(require("fs"), 1);
70073
+ var import_node_fs59 = __toESM(require("fs"), 1);
69792
70074
  var import_promises11 = __toESM(require("fs/promises"), 1);
69793
- var import_node_os23 = __toESM(require("os"), 1);
69794
- var import_node_path64 = __toESM(require("path"), 1);
70075
+ var import_node_os24 = __toESM(require("os"), 1);
70076
+ var import_node_path65 = __toESM(require("path"), 1);
69795
70077
  var import_node_module = require("module");
69796
70078
  var import_node_child_process17 = require("child_process");
69797
70079
  var import_meta7 = {};
69798
70080
  function defaultRoots() {
69799
- const home = import_node_os23.default.homedir();
70081
+ const home = import_node_os24.default.homedir();
69800
70082
  return {
69801
- claudeProjectsDir: import_node_path64.default.join(home, ".claude", "projects"),
69802
- codexDir: import_node_path64.default.join(home, ".codex"),
69803
- clawdDir: import_node_path64.default.join(home, ".clawd")
70083
+ claudeProjectsDir: import_node_path65.default.join(home, ".claude", "projects"),
70084
+ codexDir: import_node_path65.default.join(home, ".codex"),
70085
+ clawdDir: import_node_path65.default.join(home, ".clawd")
69804
70086
  };
69805
70087
  }
69806
70088
  function width(s2) {
@@ -69851,7 +70133,7 @@ function userText(msg) {
69851
70133
  }
69852
70134
  function isDir2(p3) {
69853
70135
  try {
69854
- return import_node_fs58.default.statSync(p3).isDirectory();
70136
+ return import_node_fs59.default.statSync(p3).isDirectory();
69855
70137
  } catch {
69856
70138
  return false;
69857
70139
  }
@@ -69860,7 +70142,7 @@ async function scanClaude(roots) {
69860
70142
  const out = [];
69861
70143
  let dirs;
69862
70144
  try {
69863
- dirs = import_node_fs58.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
70145
+ dirs = import_node_fs59.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
69864
70146
  } catch {
69865
70147
  return out;
69866
70148
  }
@@ -69868,16 +70150,16 @@ async function scanClaude(roots) {
69868
70150
  if (!d2.isDirectory()) continue;
69869
70151
  let files;
69870
70152
  try {
69871
- files = import_node_fs58.default.readdirSync(import_node_path64.default.join(roots.claudeProjectsDir, d2.name));
70153
+ files = import_node_fs59.default.readdirSync(import_node_path65.default.join(roots.claudeProjectsDir, d2.name));
69872
70154
  } catch {
69873
70155
  continue;
69874
70156
  }
69875
70157
  for (const name of files) {
69876
70158
  if (!name.endsWith(".jsonl")) continue;
69877
- const file = import_node_path64.default.join(roots.claudeProjectsDir, d2.name, name);
70159
+ const file = import_node_path65.default.join(roots.claudeProjectsDir, d2.name, name);
69878
70160
  let st2;
69879
70161
  try {
69880
- st2 = import_node_fs58.default.statSync(file);
70162
+ st2 = import_node_fs59.default.statSync(file);
69881
70163
  } catch {
69882
70164
  continue;
69883
70165
  }
@@ -69930,7 +70212,7 @@ async function scanClaude(roots) {
69930
70212
  return out;
69931
70213
  }
69932
70214
  async function countCodexTurns(rolloutPath) {
69933
- if (!rolloutPath || !import_node_fs58.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
70215
+ if (!rolloutPath || !import_node_fs59.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
69934
70216
  let turns = 0;
69935
70217
  let first = "";
69936
70218
  for await (const rec6 of jsonLines(rolloutPath)) {
@@ -70004,7 +70286,7 @@ async function codexFromRows(rows) {
70004
70286
  async function scanCodex(roots) {
70005
70287
  let dbs = [];
70006
70288
  try {
70007
- dbs = import_node_fs58.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path64.default.join(roots.codexDir, n2));
70289
+ dbs = import_node_fs59.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path65.default.join(roots.codexDir, n2));
70008
70290
  } catch {
70009
70291
  }
70010
70292
  if (!dbs.length) return [];
@@ -70013,14 +70295,14 @@ async function scanCodex(roots) {
70013
70295
  }
70014
70296
  async function scanExternalSessions(rootsIn) {
70015
70297
  const roots = { ...defaultRoots(), ...rootsIn };
70016
- const personaRoot = import_node_path64.default.join(roots.clawdDir, "personas");
70298
+ const personaRoot = import_node_path65.default.join(roots.clawdDir, "personas");
70017
70299
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
70018
70300
  const out = [];
70019
70301
  for (const c2 of all) {
70020
70302
  if (c2.skip) continue;
70021
70303
  if (c2.turns < 1) continue;
70022
70304
  if (!c2.cwd || !isDir2(c2.cwd)) continue;
70023
- if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path64.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path64.default.sep)) {
70305
+ if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path65.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path65.default.sep)) {
70024
70306
  continue;
70025
70307
  }
70026
70308
  out.push({
@@ -70037,13 +70319,13 @@ async function scanExternalSessions(rootsIn) {
70037
70319
  }
70038
70320
 
70039
70321
  // src/session/import-ledger.ts
70040
- var import_node_fs59 = __toESM(require("fs"), 1);
70041
- var import_node_path65 = __toESM(require("path"), 1);
70322
+ var import_node_fs60 = __toESM(require("fs"), 1);
70323
+ var import_node_path66 = __toESM(require("path"), 1);
70042
70324
  var LEDGER_FILENAME = "session-import-ledger.json";
70043
70325
  function readImportLedger(dataDir) {
70044
70326
  try {
70045
70327
  const parsed = JSON.parse(
70046
- import_node_fs59.default.readFileSync(import_node_path65.default.join(dataDir, LEDGER_FILENAME), "utf8")
70328
+ import_node_fs60.default.readFileSync(import_node_path66.default.join(dataDir, LEDGER_FILENAME), "utf8")
70047
70329
  );
70048
70330
  return Array.isArray(parsed) ? parsed : [];
70049
70331
  } catch {
@@ -70051,10 +70333,10 @@ function readImportLedger(dataDir) {
70051
70333
  }
70052
70334
  }
70053
70335
  function appendImportLedger(dataDir, entry) {
70054
- const file = import_node_path65.default.join(dataDir, LEDGER_FILENAME);
70336
+ const file = import_node_path66.default.join(dataDir, LEDGER_FILENAME);
70055
70337
  const entries = readImportLedger(dataDir);
70056
70338
  entries.push(entry);
70057
- import_node_fs59.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70339
+ import_node_fs60.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70058
70340
  }
70059
70341
 
70060
70342
  // src/handlers/session.ts
@@ -70587,7 +70869,7 @@ function buildPermissionHandlers(deps) {
70587
70869
  }
70588
70870
 
70589
70871
  // src/handlers/history.ts
70590
- var path80 = __toESM(require("path"), 1);
70872
+ var path81 = __toESM(require("path"), 1);
70591
70873
  init_protocol();
70592
70874
 
70593
70875
  // src/session/recent-dirs.ts
@@ -70605,7 +70887,7 @@ function listRecentDirs(store, limit = 50) {
70605
70887
  }
70606
70888
 
70607
70889
  // src/permission/persona-paths.ts
70608
- var path79 = __toESM(require("path"), 1);
70890
+ var path80 = __toESM(require("path"), 1);
70609
70891
  function getAllowedPersonaIds(grants, action) {
70610
70892
  const ids = /* @__PURE__ */ new Set();
70611
70893
  for (const g3 of grants) {
@@ -70618,42 +70900,42 @@ function getAllowedPersonaIds(grants, action) {
70618
70900
  return ids;
70619
70901
  }
70620
70902
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
70621
- const target = path79.resolve(absPath);
70903
+ const target = path80.resolve(absPath);
70622
70904
  if (userWorkDir) {
70623
- const u2 = path79.resolve(userWorkDir);
70624
- const usep = u2.endsWith(path79.sep) ? "" : path79.sep;
70905
+ const u2 = path80.resolve(userWorkDir);
70906
+ const usep = u2.endsWith(path80.sep) ? "" : path80.sep;
70625
70907
  if (target === u2 || target.startsWith(u2 + usep)) return true;
70626
70908
  }
70627
- const root = path79.resolve(personaRoot);
70628
- const sep4 = root.endsWith(path79.sep) ? "" : path79.sep;
70909
+ const root = path80.resolve(personaRoot);
70910
+ const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
70629
70911
  if (!target.startsWith(root + sep4)) return false;
70630
- const rel = path79.relative(root, target);
70912
+ const rel = path80.relative(root, target);
70631
70913
  if (!rel || rel.startsWith("..")) return false;
70632
- const personaId2 = rel.split(path79.sep)[0];
70914
+ const personaId2 = rel.split(path80.sep)[0];
70633
70915
  if (!personaId2) return false;
70634
70916
  const allowed = getAllowedPersonaIds(grants, action);
70635
70917
  if (allowed === "*") return true;
70636
70918
  return allowed.has(personaId2);
70637
70919
  }
70638
70920
  function personaIdFromPath(absPath, personaRoot) {
70639
- const root = path79.resolve(personaRoot);
70640
- const target = path79.resolve(absPath);
70641
- const sep4 = root.endsWith(path79.sep) ? "" : path79.sep;
70921
+ const root = path80.resolve(personaRoot);
70922
+ const target = path80.resolve(absPath);
70923
+ const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
70642
70924
  if (!target.startsWith(root + sep4)) return null;
70643
- const rel = path79.relative(root, target);
70925
+ const rel = path80.relative(root, target);
70644
70926
  if (!rel || rel.startsWith("..")) return null;
70645
- const id = rel.split(path79.sep)[0];
70927
+ const id = rel.split(path80.sep)[0];
70646
70928
  return id || null;
70647
70929
  }
70648
70930
  function isPathWithin(dir, absPath) {
70649
- const d2 = path79.resolve(dir);
70650
- const t2 = path79.resolve(absPath);
70651
- const sep4 = d2.endsWith(path79.sep) ? "" : path79.sep;
70931
+ const d2 = path80.resolve(dir);
70932
+ const t2 = path80.resolve(absPath);
70933
+ const sep4 = d2.endsWith(path80.sep) ? "" : path80.sep;
70652
70934
  return t2 === d2 || t2.startsWith(d2 + sep4);
70653
70935
  }
70654
70936
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
70655
70937
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
70656
- return personaIdFromPath(path79.resolve(absPath), personaRoot) === personaId2;
70938
+ return personaIdFromPath(path80.resolve(absPath), personaRoot) === personaId2;
70657
70939
  }
70658
70940
 
70659
70941
  // src/handlers/history.ts
@@ -70706,7 +70988,7 @@ function buildHistoryHandlers(deps) {
70706
70988
  if (!pid) return false;
70707
70989
  return isGuestPathAllowed(
70708
70990
  ctx.grants,
70709
- path80.join(personaRoot, pid),
70991
+ path81.join(personaRoot, pid),
70710
70992
  personaRoot,
70711
70993
  "read",
70712
70994
  userWorkDir
@@ -70718,7 +71000,7 @@ function buildHistoryHandlers(deps) {
70718
71000
  };
70719
71001
  const list = async (frame, _client, ctx) => {
70720
71002
  const args = HistoryListArgs.parse(frame);
70721
- assertGuestPath(ctx, path80.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
71003
+ assertGuestPath(ctx, path81.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
70722
71004
  const sessions = await history.listSessions(args);
70723
71005
  return { response: { type: "history:list", sessions } };
70724
71006
  };
@@ -70766,14 +71048,14 @@ function buildHistoryHandlers(deps) {
70766
71048
  };
70767
71049
  const subagents = async (frame, _client, ctx) => {
70768
71050
  const args = HistorySubagentsArgs.parse(frame);
70769
- assertGuestPath(ctx, path80.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
71051
+ assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
70770
71052
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
70771
71053
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
70772
71054
  return { response: { type: "history:subagents", subagents: subs } };
70773
71055
  };
70774
71056
  const subagentRead = async (frame, _client, ctx) => {
70775
71057
  const args = HistorySubagentReadArgs.parse(frame);
70776
- assertGuestPath(ctx, path80.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
71058
+ assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
70777
71059
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
70778
71060
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
70779
71061
  return { response: { type: "history:subagent-read", ...res } };
@@ -70783,7 +71065,7 @@ function buildHistoryHandlers(deps) {
70783
71065
  if (ctx?.principal.kind === "guest" && personaRoot) {
70784
71066
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
70785
71067
  const filtered = dirs.filter(
70786
- (d2) => isGuestPathAllowed(ctx.grants, path80.resolve(d2.cwd), personaRoot, "read", userWorkDir)
71068
+ (d2) => isGuestPathAllowed(ctx.grants, path81.resolve(d2.cwd), personaRoot, "read", userWorkDir)
70787
71069
  );
70788
71070
  return { response: { type: "history:recentDirs", dirs: filtered } };
70789
71071
  }
@@ -70800,17 +71082,17 @@ function buildHistoryHandlers(deps) {
70800
71082
  }
70801
71083
 
70802
71084
  // src/handlers/projects.ts
70803
- var fs77 = __toESM(require("fs"), 1);
70804
- var os25 = __toESM(require("os"), 1);
70805
- var path81 = __toESM(require("path"), 1);
71085
+ var fs78 = __toESM(require("fs"), 1);
71086
+ var os26 = __toESM(require("os"), 1);
71087
+ var path82 = __toESM(require("path"), 1);
70806
71088
  var import_node_child_process18 = require("child_process");
70807
71089
  init_protocol();
70808
- var DEFAULT_PROJECTS_ROOT = path81.join(os25.homedir(), "Documents", "ChatGPT");
71090
+ var DEFAULT_PROJECTS_ROOT = path82.join(os26.homedir(), "Documents", "ChatGPT");
70809
71091
  function allocateDir(root, name) {
70810
- let candidate = path81.join(root, name);
71092
+ let candidate = path82.join(root, name);
70811
71093
  let n2 = 2;
70812
- while (fs77.existsSync(candidate)) {
70813
- candidate = path81.join(root, `${name} ${n2}`);
71094
+ while (fs78.existsSync(candidate)) {
71095
+ candidate = path82.join(root, `${name} ${n2}`);
70814
71096
  n2 += 1;
70815
71097
  }
70816
71098
  return candidate;
@@ -70838,7 +71120,7 @@ function buildProjectHandlers(deps) {
70838
71120
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
70839
71121
  }
70840
71122
  try {
70841
- if (!fs77.statSync(args.path).isDirectory()) throw new Error("not dir");
71123
+ if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
70842
71124
  } catch {
70843
71125
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
70844
71126
  }
@@ -70854,7 +71136,7 @@ function buildProjectHandlers(deps) {
70854
71136
  let target;
70855
71137
  if (args.path) {
70856
71138
  try {
70857
- if (!fs77.statSync(args.path).isDirectory()) throw new Error("not dir");
71139
+ if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
70858
71140
  } catch {
70859
71141
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
70860
71142
  }
@@ -70862,15 +71144,15 @@ function buildProjectHandlers(deps) {
70862
71144
  } else {
70863
71145
  const name = args.name;
70864
71146
  try {
70865
- fs77.mkdirSync(root, { recursive: true });
71147
+ fs78.mkdirSync(root, { recursive: true });
70866
71148
  target = allocateDir(root, name);
70867
- fs77.mkdirSync(target);
71149
+ fs78.mkdirSync(target);
70868
71150
  } catch (err) {
70869
71151
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
70870
71152
  }
70871
71153
  const git2 = (0, import_node_child_process18.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
70872
71154
  if (git2.status !== 0) {
70873
- fs77.rmSync(target, { recursive: true, force: true });
71155
+ fs78.rmSync(target, { recursive: true, force: true });
70874
71156
  throw new ClawdError(
70875
71157
  ERROR_CODES.INVALID_CWD,
70876
71158
  `git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
@@ -70895,9 +71177,9 @@ function buildProjectHandlers(deps) {
70895
71177
  }
70896
71178
 
70897
71179
  // src/handlers/workspace.ts
70898
- var path82 = __toESM(require("path"), 1);
71180
+ var path83 = __toESM(require("path"), 1);
70899
71181
  init_protocol();
70900
- var os26 = __toESM(require("os"), 1);
71182
+ var os27 = __toESM(require("os"), 1);
70901
71183
  init_protocol();
70902
71184
  init_protocol();
70903
71185
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -70937,23 +71219,23 @@ function buildWorkspaceHandlers(deps) {
70937
71219
  const list = async (frame, _client, ctx) => {
70938
71220
  const args = WorkspaceListArgs.parse(frame);
70939
71221
  const isGuest = ctx?.principal.kind === "guest";
70940
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os26.homedir();
70941
- const resolvedCwd = path82.resolve(args.cwd ?? fallbackCwd);
70942
- const target = args.path ? path82.resolve(resolvedCwd, args.path) : resolvedCwd;
71222
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os27.homedir();
71223
+ const resolvedCwd = path83.resolve(args.cwd ?? fallbackCwd);
71224
+ const target = args.path ? path83.resolve(resolvedCwd, args.path) : resolvedCwd;
70943
71225
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
70944
71226
  const res = workspace.list({ ...args, cwd: resolvedCwd });
70945
71227
  return { response: { type: "workspace:list", ...res } };
70946
71228
  };
70947
71229
  const read = async (frame, _client, ctx) => {
70948
71230
  const args = WorkspaceReadArgs.parse(frame);
70949
- const target = path82.isAbsolute(args.path) ? path82.resolve(args.path) : path82.resolve(args.cwd, args.path);
71231
+ const target = path83.isAbsolute(args.path) ? path83.resolve(args.path) : path83.resolve(args.cwd, args.path);
70950
71232
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
70951
71233
  const res = workspace.read(args);
70952
71234
  return { response: { type: "workspace:read", ...res } };
70953
71235
  };
70954
71236
  const skillsList = async (frame, _client, ctx) => {
70955
71237
  const args = SkillsListArgs.parse(frame);
70956
- const cwdAbs = path82.resolve(args.cwd);
71238
+ const cwdAbs = path83.resolve(args.cwd);
70957
71239
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
70958
71240
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
70959
71241
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -70965,7 +71247,7 @@ function buildWorkspaceHandlers(deps) {
70965
71247
  };
70966
71248
  const agentsList = async (frame, _client, ctx) => {
70967
71249
  const args = AgentsListArgs.parse(frame);
70968
- const cwdAbs = path82.resolve(args.cwd);
71250
+ const cwdAbs = path83.resolve(args.cwd);
70969
71251
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
70970
71252
  if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
70971
71253
  return { response: { type: "agents:list", agents: [] } };
@@ -70987,20 +71269,20 @@ function buildWorkspaceHandlers(deps) {
70987
71269
  }
70988
71270
 
70989
71271
  // src/handlers/git.ts
70990
- var path84 = __toESM(require("path"), 1);
71272
+ var path85 = __toESM(require("path"), 1);
70991
71273
  init_protocol();
70992
71274
  init_protocol();
70993
71275
 
70994
71276
  // src/workspace/git.ts
70995
71277
  var import_node_child_process19 = require("child_process");
70996
- var import_node_fs60 = __toESM(require("fs"), 1);
70997
- var import_node_path66 = __toESM(require("path"), 1);
71278
+ var import_node_fs61 = __toESM(require("fs"), 1);
71279
+ var import_node_path67 = __toESM(require("path"), 1);
70998
71280
  var import_node_util2 = require("util");
70999
71281
  var pexec = (0, import_node_util2.promisify)(import_node_child_process19.execFile);
71000
71282
  function normalizePath(p3) {
71001
- const resolved = import_node_path66.default.resolve(p3);
71283
+ const resolved = import_node_path67.default.resolve(p3);
71002
71284
  try {
71003
- return import_node_fs60.default.realpathSync(resolved);
71285
+ return import_node_fs61.default.realpathSync(resolved);
71004
71286
  } catch {
71005
71287
  return resolved;
71006
71288
  }
@@ -71074,7 +71356,7 @@ async function listGitBranches(cwd) {
71074
71356
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
71075
71357
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
71076
71358
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
71077
- if (!isGuestPathAllowed(ctx.grants, path84.resolve(cwd), personaRoot, "read", userWorkDir)) {
71359
+ if (!isGuestPathAllowed(ctx.grants, path85.resolve(cwd), personaRoot, "read", userWorkDir)) {
71078
71360
  throw new ClawdError(
71079
71361
  ERROR_CODES.UNAUTHORIZED,
71080
71362
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -71331,12 +71613,12 @@ async function queryCodexAccount(deps = {}) {
71331
71613
  }
71332
71614
 
71333
71615
  // src/tools/pi-account.ts
71334
- var import_node_fs61 = __toESM(require("fs"), 1);
71335
- var import_node_path67 = __toESM(require("path"), 1);
71616
+ var import_node_fs62 = __toESM(require("fs"), 1);
71617
+ var import_node_path68 = __toESM(require("path"), 1);
71336
71618
  function readPiCredentials(agentDir) {
71337
71619
  let raw;
71338
71620
  try {
71339
- raw = JSON.parse(import_node_fs61.default.readFileSync(import_node_path67.default.join(agentDir, "auth.json"), "utf8"));
71621
+ raw = JSON.parse(import_node_fs62.default.readFileSync(import_node_path68.default.join(agentDir, "auth.json"), "utf8"));
71340
71622
  } catch {
71341
71623
  return {};
71342
71624
  }
@@ -71419,6 +71701,171 @@ function buildEngineHandlers(deps, overrides = {}) {
71419
71701
  return { "engine:status": status, "engine:connectPool": connectPool };
71420
71702
  }
71421
71703
 
71704
+ // src/handlers/channels.ts
71705
+ var import_node_fs64 = __toESM(require("fs"), 1);
71706
+ var import_node_os26 = __toESM(require("os"), 1);
71707
+ var import_node_path70 = __toESM(require("path"), 1);
71708
+
71709
+ // src/tools/subscription-channels-apply.ts
71710
+ var import_node_fs63 = __toESM(require("fs"), 1);
71711
+ var import_node_os25 = __toESM(require("os"), 1);
71712
+ var import_node_path69 = __toESM(require("path"), 1);
71713
+ var TABLE_HEADER = /^\s*\[\[?\s*([A-Za-z0-9_.-]+)\s*\]\]?\s*(?:#.*)?$/;
71714
+ var KEY_LINE = /^\s*([A-Za-z0-9_.-]+)\s*=/;
71715
+ function stripCodexProvider(text) {
71716
+ const out = [];
71717
+ let inProviderSection = false;
71718
+ for (const line of text.split("\n")) {
71719
+ const headerMatch = TABLE_HEADER.exec(line);
71720
+ if (headerMatch) {
71721
+ const section = headerMatch[1].trim();
71722
+ inProviderSection = section === "model_providers" || section.startsWith("model_providers.");
71723
+ if (inProviderSection) continue;
71724
+ out.push(line);
71725
+ continue;
71726
+ }
71727
+ if (inProviderSection) continue;
71728
+ const keyMatch = KEY_LINE.exec(line);
71729
+ if (keyMatch) {
71730
+ const key = keyMatch[1].trim();
71731
+ if (key === "model_provider" || key.startsWith("model_providers.")) {
71732
+ continue;
71733
+ }
71734
+ }
71735
+ out.push(line);
71736
+ }
71737
+ return out.join("\n").trim();
71738
+ }
71739
+ function applyCodexSubscriptionChannel(opts) {
71740
+ const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path69.default.join(import_node_os25.default.homedir(), ".codex");
71741
+ import_node_fs63.default.mkdirSync(codexHome, { recursive: true });
71742
+ const configFile = import_node_path69.default.join(codexHome, "config.toml");
71743
+ const original = import_node_fs63.default.existsSync(configFile) ? import_node_fs63.default.readFileSync(configFile, "utf8") : "";
71744
+ const rest = stripCodexProvider(original);
71745
+ let content;
71746
+ if (opts.channel) {
71747
+ const ch = opts.channel;
71748
+ content = [
71749
+ 'model_provider = "cliproxyapi"',
71750
+ ...rest ? ["", rest] : [],
71751
+ "",
71752
+ "[model_providers.cliproxyapi]",
71753
+ 'name = "cliproxyapi"',
71754
+ `base_url = ${JSON.stringify(ch.baseUrl)}`,
71755
+ 'wire_api = "responses"',
71756
+ `auth = { command = "echo", args = [${JSON.stringify(ch.apiKey)}] }`,
71757
+ ""
71758
+ ].join("\n");
71759
+ } else {
71760
+ content = [
71761
+ 'model_provider = "openai"',
71762
+ ...rest ? ["", rest] : [],
71763
+ ""
71764
+ ].join("\n");
71765
+ }
71766
+ const tmpFile = `${configFile}.tmp.${Date.now()}`;
71767
+ import_node_fs63.default.writeFileSync(tmpFile, content, { mode: 384 });
71768
+ import_node_fs63.default.renameSync(tmpFile, configFile);
71769
+ }
71770
+ function applyPiSubscriptionChannel(opts) {
71771
+ const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path69.default.join(import_node_os25.default.homedir(), ".pi", "agent");
71772
+ if (!import_node_fs63.default.existsSync(agentDir)) return false;
71773
+ const configFile = import_node_path69.default.join(agentDir, "cliproxyapi.json");
71774
+ if (opts.channel) {
71775
+ const data = { baseUrl: opts.channel.baseUrl, apiKey: opts.channel.apiKey };
71776
+ const tmp = `${configFile}.tmp.${Date.now()}`;
71777
+ import_node_fs63.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
71778
+ import_node_fs63.default.renameSync(tmp, configFile);
71779
+ return true;
71780
+ }
71781
+ return false;
71782
+ }
71783
+
71784
+ // src/handlers/channels.ts
71785
+ function snapshotFile(file) {
71786
+ const original = import_node_fs64.default.existsSync(file) ? import_node_fs64.default.readFileSync(file) : null;
71787
+ return () => {
71788
+ if (original === null) {
71789
+ import_node_fs64.default.rmSync(file, { force: true });
71790
+ } else {
71791
+ const tmp = `${file}.tmp.${Date.now()}`;
71792
+ import_node_fs64.default.writeFileSync(tmp, original, { mode: 384 });
71793
+ import_node_fs64.default.renameSync(tmp, file);
71794
+ }
71795
+ };
71796
+ }
71797
+ function buildChannelsHandlers(deps) {
71798
+ let activationQueue = Promise.resolve();
71799
+ const get = async () => {
71800
+ return { response: deps.store.list() };
71801
+ };
71802
+ const save = async (frame) => {
71803
+ const args = parseArgs2(SubscriptionChannelSaveArgsSchema, frame, "subscriptionChannel:save");
71804
+ const channel = deps.store.save(args);
71805
+ const state = deps.store.list();
71806
+ if (state.activeChannelId === channel.id) {
71807
+ applyCodexSubscriptionChannel({ codexHome: deps.codexHome, channel });
71808
+ applyPiSubscriptionChannel({ agentDir: deps.agentDir, channel });
71809
+ await deps.manager.getCapabilities("codex", { refresh: true });
71810
+ }
71811
+ return { response: deps.store.list() };
71812
+ };
71813
+ const del = async (frame) => {
71814
+ const args = parseArgs2(SubscriptionChannelDeleteArgsSchema, frame, "subscriptionChannel:delete");
71815
+ const wasActive = deps.store.list().activeChannelId === args.id;
71816
+ deps.store.delete(args.id);
71817
+ if (wasActive) {
71818
+ const newActive = deps.store.getActive();
71819
+ applyCodexSubscriptionChannel({ codexHome: deps.codexHome, channel: newActive });
71820
+ applyPiSubscriptionChannel({ agentDir: deps.agentDir, channel: newActive });
71821
+ if (newActive) {
71822
+ await deps.manager.getCapabilities("codex", { refresh: true });
71823
+ }
71824
+ }
71825
+ return { response: { ok: true } };
71826
+ };
71827
+ const activate = async (frame, context) => {
71828
+ const run = activationQueue.then(() => activateChannel(frame, context));
71829
+ activationQueue = run.then(() => {
71830
+ }, () => {
71831
+ });
71832
+ return run;
71833
+ };
71834
+ const activateChannel = async (frame) => {
71835
+ const args = parseArgs2(SubscriptionChannelActivateArgsSchema, frame, "subscriptionChannel:activate");
71836
+ const channel = args.id === null ? null : deps.store.get(args.id);
71837
+ if (args.id !== null && !channel) throw new Error(`\u901A\u9053 ${args.id} \u4E0D\u5B58\u5728`);
71838
+ const codexHome = deps.codexHome || process.env.CODEX_HOME || import_node_path70.default.join(import_node_os26.default.homedir(), ".codex");
71839
+ const agentDir = deps.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path70.default.join(import_node_os26.default.homedir(), ".pi", "agent");
71840
+ const restoreCodex = snapshotFile(import_node_path70.default.join(codexHome, "config.toml"));
71841
+ const restorePi = import_node_fs64.default.existsSync(agentDir) ? snapshotFile(import_node_path70.default.join(agentDir, "cliproxyapi.json")) : null;
71842
+ let refreshed = false;
71843
+ try {
71844
+ applyCodexSubscriptionChannel({ codexHome, channel });
71845
+ if (channel) await deps.manager.getCapabilities("codex", { refresh: true });
71846
+ refreshed = Boolean(channel);
71847
+ applyPiSubscriptionChannel({ agentDir, channel });
71848
+ deps.store.setActive(args.id);
71849
+ } catch (err) {
71850
+ restoreCodex();
71851
+ restorePi?.();
71852
+ if (refreshed) await deps.manager.getCapabilities("codex", { refresh: true }).catch(() => {
71853
+ });
71854
+ if (channel?.id === "default-pool" && err instanceof Error && /HTTP 401/.test(err.message)) {
71855
+ throw new Error("\u9ED8\u8BA4\u53F7\u6C60\u8BA4\u8BC1\u5931\u8D25\uFF08HTTP 401\uFF09\uFF1A\u8BF7\u7F16\u8F91\u300C\u9ED8\u8BA4\u56E2\u961F\u53F7\u6C60\u300D\u5E76\u91CD\u65B0\u586B\u5199\u53F7\u6C60 API Key\uFF0C\u518D\u8BBE\u4E3A\u5F53\u524D\u3002");
71856
+ }
71857
+ throw err;
71858
+ }
71859
+ return { response: { ok: true } };
71860
+ };
71861
+ return {
71862
+ "subscriptionChannel:get": get,
71863
+ "subscriptionChannel:save": save,
71864
+ "subscriptionChannel:delete": del,
71865
+ "subscriptionChannel:activate": activate
71866
+ };
71867
+ }
71868
+
71422
71869
  // src/handlers/inbox.ts
71423
71870
  init_protocol();
71424
71871
  function resolvePeerDeviceId(ctx, argsPeerDeviceId) {
@@ -72053,7 +72500,7 @@ function buildDashboardHandlers(deps) {
72053
72500
  }
72054
72501
 
72055
72502
  // src/handlers/meta.ts
72056
- var import_node_os24 = __toESM(require("os"), 1);
72503
+ var import_node_os27 = __toESM(require("os"), 1);
72057
72504
  init_protocol();
72058
72505
 
72059
72506
  // src/handlers/method-grants.ts
@@ -72252,6 +72699,10 @@ var METHOD_GRANT_MAP = {
72252
72699
  "engine:status": ADMIN_ANY,
72253
72700
  // engine:connectPool(接入号池,spec 2026-09-17-onboarding-pool-key):改本机 ~/.codex/config.toml,owner-only
72254
72701
  "engine:connectPool": ADMIN_ANY,
72702
+ "subscriptionChannel:get": ADMIN_ANY,
72703
+ "subscriptionChannel:save": ADMIN_ANY,
72704
+ "subscriptionChannel:delete": ADMIN_ANY,
72705
+ "subscriptionChannel:activate": ADMIN_ANY,
72255
72706
  "persona:create": ADMIN_ANY,
72256
72707
  // persona:list / persona:get 下沉到 CAPABILITY_SCOPED:guest 调用合法
72257
72708
  // (list 用于 People 面板展开对方分享的 personas;get 用于 guest 视角下
@@ -72369,21 +72820,21 @@ function computeMethodAccess(args) {
72369
72820
  }
72370
72821
 
72371
72822
  // src/version.ts
72372
- var version = "0.2.590".length > 0 ? "0.2.590" : "dev";
72823
+ var version = "0.2.592".length > 0 ? "0.2.592" : "dev";
72373
72824
 
72374
72825
  // src/cli-probe/probe.ts
72375
- var fs80 = __toESM(require("fs"), 1);
72376
- var path86 = __toESM(require("path"), 1);
72826
+ var fs83 = __toESM(require("fs"), 1);
72827
+ var path89 = __toESM(require("path"), 1);
72377
72828
  var PKG_NAME = "@clawos-dev/clawd";
72378
72829
  var BIN_NAME = "clawd";
72379
72830
  var MAX_PARENT_HOPS = 5;
72380
72831
  function probeGlobalCli(pathEnv) {
72381
72832
  if (!pathEnv) return null;
72382
- for (const dir of pathEnv.split(path86.delimiter)) {
72833
+ for (const dir of pathEnv.split(path89.delimiter)) {
72383
72834
  if (!dir) continue;
72384
72835
  let real;
72385
72836
  try {
72386
- real = fs80.realpathSync(path86.join(dir, BIN_NAME));
72837
+ real = fs83.realpathSync(path89.join(dir, BIN_NAME));
72387
72838
  } catch {
72388
72839
  continue;
72389
72840
  }
@@ -72393,15 +72844,15 @@ function probeGlobalCli(pathEnv) {
72393
72844
  return null;
72394
72845
  }
72395
72846
  function readOwnPackageVersion(entryPath) {
72396
- let dir = path86.dirname(entryPath);
72847
+ let dir = path89.dirname(entryPath);
72397
72848
  for (let i2 = 0; i2 < MAX_PARENT_HOPS; i2++) {
72398
72849
  try {
72399
- const raw = fs80.readFileSync(path86.join(dir, "package.json"), "utf8");
72850
+ const raw = fs83.readFileSync(path89.join(dir, "package.json"), "utf8");
72400
72851
  const pkg = JSON.parse(raw);
72401
72852
  if (pkg.name !== PKG_NAME) return null;
72402
72853
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
72403
72854
  } catch {
72404
- const parent = path86.dirname(dir);
72855
+ const parent = path89.dirname(dir);
72405
72856
  if (parent === dir) return null;
72406
72857
  dir = parent;
72407
72858
  }
@@ -72437,7 +72888,7 @@ function buildReadyFrame(deps, client) {
72437
72888
  return {
72438
72889
  version,
72439
72890
  protocolVersion: PROTOCOL_VERSION,
72440
- hostname: import_node_os24.default.hostname(),
72891
+ hostname: import_node_os27.default.hostname(),
72441
72892
  os: process.platform,
72442
72893
  tools,
72443
72894
  runningSessions: info.runningSessions,
@@ -72577,7 +73028,7 @@ function buildPersonaHandlers(deps) {
72577
73028
  }
72578
73029
 
72579
73030
  // src/handlers/attachment.ts
72580
- var import_node_path68 = __toESM(require("path"), 1);
73031
+ var import_node_path71 = __toESM(require("path"), 1);
72581
73032
  init_protocol();
72582
73033
  init_protocol();
72583
73034
  function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot) {
@@ -72656,12 +73107,12 @@ function buildAttachmentHandlers(deps) {
72656
73107
  `session ${args.sessionId} scope unresolved`
72657
73108
  );
72658
73109
  }
72659
- const cwdAbs = import_node_path68.default.resolve(sessionFile.cwd);
72660
- const candidateAbs = import_node_path68.default.isAbsolute(args.relPath) ? import_node_path68.default.resolve(args.relPath) : import_node_path68.default.resolve(cwdAbs, args.relPath);
73110
+ const cwdAbs = import_node_path71.default.resolve(sessionFile.cwd);
73111
+ const candidateAbs = import_node_path71.default.isAbsolute(args.relPath) ? import_node_path71.default.resolve(args.relPath) : import_node_path71.default.resolve(cwdAbs, args.relPath);
72661
73112
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
72662
73113
  const entries = deps.groupFileStore.list(scope, args.sessionId);
72663
73114
  const entry = entries.find((e) => {
72664
- const storedAbs = import_node_path68.default.isAbsolute(e.relPath) ? import_node_path68.default.resolve(e.relPath) : import_node_path68.default.resolve(cwdAbs, e.relPath);
73115
+ const storedAbs = import_node_path71.default.isAbsolute(e.relPath) ? import_node_path71.default.resolve(e.relPath) : import_node_path71.default.resolve(cwdAbs, e.relPath);
72665
73116
  return storedAbs === candidateAbs && !e.stale;
72666
73117
  });
72667
73118
  if (!entry) {
@@ -72685,7 +73136,7 @@ function buildAttachmentHandlers(deps) {
72685
73136
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
72686
73137
  const f2 = deps.sessionStore.read(sessionId);
72687
73138
  if (!f2) return;
72688
- assertGuestAttachmentPath(ctx, import_node_path68.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
73139
+ assertGuestAttachmentPath(ctx, import_node_path71.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
72689
73140
  }
72690
73141
  const groupAdd = async (frame, _client, ctx) => {
72691
73142
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -72700,8 +73151,8 @@ function buildAttachmentHandlers(deps) {
72700
73151
  if (!scope) {
72701
73152
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
72702
73153
  }
72703
- const cwdAbs = import_node_path68.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
72704
- const candidateAbs = import_node_path68.default.isAbsolute(args.relPath) ? import_node_path68.default.resolve(args.relPath) : import_node_path68.default.resolve(cwdAbs, args.relPath);
73154
+ const cwdAbs = import_node_path71.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
73155
+ const candidateAbs = import_node_path71.default.isAbsolute(args.relPath) ? import_node_path71.default.resolve(args.relPath) : import_node_path71.default.resolve(cwdAbs, args.relPath);
72705
73156
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
72706
73157
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
72707
73158
  const size = 0;
@@ -72760,19 +73211,19 @@ function buildAttachmentHandlers(deps) {
72760
73211
 
72761
73212
  // src/handlers/extension.ts
72762
73213
  var import_promises15 = __toESM(require("fs/promises"), 1);
72763
- var import_node_path73 = __toESM(require("path"), 1);
73214
+ var import_node_path76 = __toESM(require("path"), 1);
72764
73215
  init_protocol();
72765
73216
 
72766
73217
  // src/extension/bundle-zip.ts
72767
73218
  var import_promises12 = __toESM(require("fs/promises"), 1);
72768
- var import_node_path69 = __toESM(require("path"), 1);
73219
+ var import_node_path72 = __toESM(require("path"), 1);
72769
73220
  var import_node_crypto22 = __toESM(require("crypto"), 1);
72770
73221
  var import_jszip2 = __toESM(require_lib3(), 1);
72771
73222
  async function bundleExtensionDir(dir) {
72772
73223
  const entries = await listFilesSorted(dir);
72773
73224
  const zip = new import_jszip2.default();
72774
73225
  for (const rel of entries) {
72775
- const abs = import_node_path69.default.join(dir, rel);
73226
+ const abs = import_node_path72.default.join(dir, rel);
72776
73227
  const content = await import_promises12.default.readFile(abs);
72777
73228
  zip.file(rel, content, { date: FIXED_DATE });
72778
73229
  }
@@ -72793,7 +73244,7 @@ async function listFilesSorted(rootDir) {
72793
73244
  return out;
72794
73245
  }
72795
73246
  async function walk(absRoot, relPrefix, out) {
72796
- const dirAbs = import_node_path69.default.join(absRoot, relPrefix);
73247
+ const dirAbs = import_node_path72.default.join(absRoot, relPrefix);
72797
73248
  const entries = await import_promises12.default.readdir(dirAbs, { withFileTypes: true });
72798
73249
  for (const e of entries) {
72799
73250
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -72847,25 +73298,25 @@ function computePublishCheck(args) {
72847
73298
 
72848
73299
  // src/extension/install-flow.ts
72849
73300
  var import_promises13 = __toESM(require("fs/promises"), 1);
72850
- var import_node_path71 = __toESM(require("path"), 1);
72851
- var import_node_os26 = __toESM(require("os"), 1);
73301
+ var import_node_path74 = __toESM(require("path"), 1);
73302
+ var import_node_os29 = __toESM(require("os"), 1);
72852
73303
  var import_node_crypto23 = __toESM(require("crypto"), 1);
72853
73304
  var import_jszip3 = __toESM(require_lib3(), 1);
72854
73305
 
72855
73306
  // src/extension/paths.ts
72856
- var import_node_os25 = __toESM(require("os"), 1);
72857
- var import_node_path70 = __toESM(require("path"), 1);
73307
+ var import_node_os28 = __toESM(require("os"), 1);
73308
+ var import_node_path73 = __toESM(require("path"), 1);
72858
73309
  function clawdHomeRoot(override) {
72859
- return override ?? process.env.CLAWD_HOME ?? import_node_path70.default.join(import_node_os25.default.homedir(), ".clawd");
73310
+ return override ?? process.env.CLAWD_HOME ?? import_node_path73.default.join(import_node_os28.default.homedir(), ".clawd");
72860
73311
  }
72861
73312
  function extensionsRoot(override) {
72862
- return import_node_path70.default.join(clawdHomeRoot(override), "extensions");
73313
+ return import_node_path73.default.join(clawdHomeRoot(override), "extensions");
72863
73314
  }
72864
73315
  function publishedChannelsFile(override) {
72865
- return import_node_path70.default.join(clawdHomeRoot(override), "extensions-published.json");
73316
+ return import_node_path73.default.join(clawdHomeRoot(override), "extensions-published.json");
72866
73317
  }
72867
73318
  function bundleCacheRoot(override) {
72868
- return import_node_path70.default.join(clawdHomeRoot(override), "extension-bundles");
73319
+ return import_node_path73.default.join(clawdHomeRoot(override), "extension-bundles");
72869
73320
  }
72870
73321
 
72871
73322
  // src/extension/install-flow.ts
@@ -72892,7 +73343,7 @@ async function installFromChannel(args, deps) {
72892
73343
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
72893
73344
  }
72894
73345
  for (const name of Object.keys(zip.files)) {
72895
- if (name.includes("..") || name.startsWith("/") || import_node_path71.default.isAbsolute(name)) {
73346
+ if (name.includes("..") || name.startsWith("/") || import_node_path74.default.isAbsolute(name)) {
72896
73347
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
72897
73348
  }
72898
73349
  }
@@ -72924,7 +73375,7 @@ async function installFromChannel(args, deps) {
72924
73375
  );
72925
73376
  }
72926
73377
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
72927
- const destDir = import_node_path71.default.join(deps.extensionsRoot, localExtId);
73378
+ const destDir = import_node_path74.default.join(deps.extensionsRoot, localExtId);
72928
73379
  let destExists = false;
72929
73380
  try {
72930
73381
  await import_promises13.default.access(destDir);
@@ -72938,16 +73389,16 @@ async function installFromChannel(args, deps) {
72938
73389
  );
72939
73390
  }
72940
73391
  const stage = await import_promises13.default.mkdtemp(
72941
- import_node_path71.default.join(import_node_os26.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
73392
+ import_node_path74.default.join(import_node_os29.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
72942
73393
  );
72943
73394
  try {
72944
73395
  for (const [name, entry] of Object.entries(zip.files)) {
72945
- const dest = import_node_path71.default.join(stage, name);
73396
+ const dest = import_node_path74.default.join(stage, name);
72946
73397
  if (entry.dir) {
72947
73398
  await import_promises13.default.mkdir(dest, { recursive: true });
72948
73399
  continue;
72949
73400
  }
72950
- await import_promises13.default.mkdir(import_node_path71.default.dirname(dest), { recursive: true });
73401
+ await import_promises13.default.mkdir(import_node_path74.default.dirname(dest), { recursive: true });
72951
73402
  if (name === "manifest.json") {
72952
73403
  const rewritten = { ...parsed.data, id: localExtId };
72953
73404
  await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -72968,8 +73419,8 @@ async function installFromChannel(args, deps) {
72968
73419
 
72969
73420
  // src/extension/update-flow.ts
72970
73421
  var import_promises14 = __toESM(require("fs/promises"), 1);
72971
- var import_node_path72 = __toESM(require("path"), 1);
72972
- var import_node_os27 = __toESM(require("os"), 1);
73422
+ var import_node_path75 = __toESM(require("path"), 1);
73423
+ var import_node_os30 = __toESM(require("os"), 1);
72973
73424
  var import_node_crypto24 = __toESM(require("crypto"), 1);
72974
73425
  var import_jszip4 = __toESM(require_lib3(), 1);
72975
73426
  var UpdateError = class extends Error {
@@ -72985,11 +73436,11 @@ async function updateFromChannel(args, deps) {
72985
73436
  channelRef.extId,
72986
73437
  channelRef.ownerPrincipalId
72987
73438
  );
72988
- const liveDir = import_node_path72.default.join(deps.extensionsRoot, localExtId);
73439
+ const liveDir = import_node_path75.default.join(deps.extensionsRoot, localExtId);
72989
73440
  const prevDir = `${liveDir}.prev`;
72990
73441
  let existingVersion;
72991
73442
  try {
72992
- const raw = await import_promises14.default.readFile(import_node_path72.default.join(liveDir, "manifest.json"), "utf8");
73443
+ const raw = await import_promises14.default.readFile(import_node_path75.default.join(liveDir, "manifest.json"), "utf8");
72993
73444
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
72994
73445
  if (!parsed2.success) {
72995
73446
  throw new UpdateError(
@@ -73022,7 +73473,7 @@ async function updateFromChannel(args, deps) {
73022
73473
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
73023
73474
  }
73024
73475
  for (const name of Object.keys(zip.files)) {
73025
- if (name.includes("..") || name.startsWith("/") || import_node_path72.default.isAbsolute(name)) {
73476
+ if (name.includes("..") || name.startsWith("/") || import_node_path75.default.isAbsolute(name)) {
73026
73477
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
73027
73478
  }
73028
73479
  }
@@ -73057,16 +73508,16 @@ async function updateFromChannel(args, deps) {
73057
73508
  await import_promises14.default.rm(prevDir, { recursive: true, force: true });
73058
73509
  await import_promises14.default.rename(liveDir, prevDir);
73059
73510
  const stage = await import_promises14.default.mkdtemp(
73060
- import_node_path72.default.join(import_node_os27.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73511
+ import_node_path75.default.join(import_node_os30.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73061
73512
  );
73062
73513
  try {
73063
73514
  for (const [name, entry] of Object.entries(zip.files)) {
73064
- const dest = import_node_path72.default.join(stage, name);
73515
+ const dest = import_node_path75.default.join(stage, name);
73065
73516
  if (entry.dir) {
73066
73517
  await import_promises14.default.mkdir(dest, { recursive: true });
73067
73518
  continue;
73068
73519
  }
73069
- await import_promises14.default.mkdir(import_node_path72.default.dirname(dest), { recursive: true });
73520
+ await import_promises14.default.mkdir(import_node_path75.default.dirname(dest), { recursive: true });
73070
73521
  if (name === "manifest.json") {
73071
73522
  const rewritten = { ...parsed.data, id: localExtId };
73072
73523
  await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -73133,7 +73584,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73133
73584
  );
73134
73585
  }
73135
73586
  }
73136
- const manifestPath = import_node_path73.default.join(root, extId, "manifest.json");
73587
+ const manifestPath = import_node_path76.default.join(root, extId, "manifest.json");
73137
73588
  const manifest = await readManifest(root, extId);
73138
73589
  const next = { ...manifest, version: newVersion };
73139
73590
  const tmp = `${manifestPath}.tmp`;
@@ -73141,7 +73592,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73141
73592
  await import_promises15.default.rename(tmp, manifestPath);
73142
73593
  }
73143
73594
  async function readManifest(root, extId) {
73144
- const file = import_node_path73.default.join(root, extId, "manifest.json");
73595
+ const file = import_node_path76.default.join(root, extId, "manifest.json");
73145
73596
  let raw;
73146
73597
  try {
73147
73598
  raw = await import_promises15.default.readFile(file, "utf8");
@@ -73225,7 +73676,7 @@ function buildExtensionHandlers(deps) {
73225
73676
  };
73226
73677
  async function buildSnapshotMeta(extId) {
73227
73678
  const manifest = await readManifest(deps.root, extId);
73228
- const { sha256, buffer } = await bundleExtensionDir(import_node_path73.default.join(deps.root, extId));
73679
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path76.default.join(deps.root, extId));
73229
73680
  return { manifest, contentHash: sha256, buffer };
73230
73681
  }
73231
73682
  const publish = async (frame, _client, ctx) => {
@@ -74053,7 +74504,7 @@ function buildVisitorHandlers(deps) {
74053
74504
 
74054
74505
  // src/extension/registry.ts
74055
74506
  var import_promises17 = __toESM(require("fs/promises"), 1);
74056
- var import_node_path74 = __toESM(require("path"), 1);
74507
+ var import_node_path77 = __toESM(require("path"), 1);
74057
74508
  async function loadAll(root) {
74058
74509
  let entries;
74059
74510
  try {
@@ -74066,13 +74517,13 @@ async function loadAll(root) {
74066
74517
  for (const ent of entries) {
74067
74518
  if (!ent.isDirectory()) continue;
74068
74519
  if (ent.name.startsWith(".")) continue;
74069
- records.push(await loadOne(import_node_path74.default.join(root, ent.name), ent.name));
74520
+ records.push(await loadOne(import_node_path77.default.join(root, ent.name), ent.name));
74070
74521
  }
74071
74522
  records.sort((a2, b3) => a2.extId < b3.extId ? -1 : a2.extId > b3.extId ? 1 : 0);
74072
74523
  return records;
74073
74524
  }
74074
74525
  async function loadOne(dir, dirName) {
74075
- const manifestPath = import_node_path74.default.join(dir, "manifest.json");
74526
+ const manifestPath = import_node_path77.default.join(dir, "manifest.json");
74076
74527
  let raw;
74077
74528
  try {
74078
74529
  raw = await import_promises17.default.readFile(manifestPath, "utf8");
@@ -74117,7 +74568,7 @@ async function loadOne(dir, dirName) {
74117
74568
 
74118
74569
  // src/extension/uninstall.ts
74119
74570
  var import_promises18 = __toESM(require("fs/promises"), 1);
74120
- var import_node_path75 = __toESM(require("path"), 1);
74571
+ var import_node_path78 = __toESM(require("path"), 1);
74121
74572
  var UninstallError = class extends Error {
74122
74573
  constructor(code, message) {
74123
74574
  super(message);
@@ -74126,7 +74577,7 @@ var UninstallError = class extends Error {
74126
74577
  code;
74127
74578
  };
74128
74579
  async function uninstall(deps) {
74129
- const dir = import_node_path75.default.join(deps.root, deps.extId);
74580
+ const dir = import_node_path78.default.join(deps.root, deps.extId);
74130
74581
  try {
74131
74582
  await import_promises18.default.access(dir);
74132
74583
  } catch {
@@ -74144,14 +74595,14 @@ init_protocol();
74144
74595
 
74145
74596
  // src/peer-ops/run-command.ts
74146
74597
  var import_node_child_process23 = require("child_process");
74147
- var import_node_os28 = __toESM(require("os"), 1);
74598
+ var import_node_os31 = __toESM(require("os"), 1);
74148
74599
  var DEFAULT_TIMEOUT_MS6 = 3e4;
74149
74600
  var MAX_TIMEOUT_MS = 3e5;
74150
74601
  var MAX_OUTPUT_BYTES = 1048576;
74151
74602
  function runCommand2(command, opts = {}) {
74152
74603
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS6, MAX_TIMEOUT_MS);
74153
74604
  return new Promise((resolve9) => {
74154
- const child = (0, import_node_child_process23.spawn)("bash", ["-c", command], { cwd: import_node_os28.default.homedir() });
74605
+ const child = (0, import_node_child_process23.spawn)("bash", ["-c", command], { cwd: import_node_os31.default.homedir() });
74155
74606
  const out = [];
74156
74607
  const err = [];
74157
74608
  let outBytes = 0;
@@ -74264,7 +74715,9 @@ function ensureGuest(ctx) {
74264
74715
 
74265
74716
  // src/handlers/index.ts
74266
74717
  function buildMethodHandlers(deps) {
74718
+ const channelStore = deps.subscriptionChannelStore ?? new SubscriptionChannelStore({ dataDir: deps.dataDir ?? deps.masterDataDir });
74267
74719
  const handlers = {
74720
+ ...buildChannelsHandlers({ store: channelStore, manager: deps.manager }),
74268
74721
  ...buildSessionHandlers({
74269
74722
  ...deps,
74270
74723
  getTunnelUrl: deps.getTunnelUrl,
@@ -74342,7 +74795,7 @@ function buildMethodHandlers(deps) {
74342
74795
  broadcast: deps.broadcastToOwners
74343
74796
  }),
74344
74797
  ...buildMasterHandlers({
74345
- authorityTablePath: import_node_path76.default.join(deps.masterDataDir, "master-authority.json")
74798
+ authorityTablePath: import_node_path79.default.join(deps.masterDataDir, "master-authority.json")
74346
74799
  }),
74347
74800
  ...buildTopicHandlers({
74348
74801
  topicStore: deps.topicStore,
@@ -74485,7 +74938,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
74485
74938
 
74486
74939
  // src/extension/runtime.ts
74487
74940
  var import_node_child_process24 = require("child_process");
74488
- var import_node_path77 = __toESM(require("path"), 1);
74941
+ var import_node_path80 = __toESM(require("path"), 1);
74489
74942
  var import_promises19 = require("timers/promises");
74490
74943
 
74491
74944
  // src/extension/port-allocator.ts
@@ -74586,7 +75039,7 @@ var Runtime = class {
74586
75039
  /\$CLAWOS_EXT_PORT/g,
74587
75040
  String(port)
74588
75041
  );
74589
- const dir = import_node_path77.default.join(this.root, extId);
75042
+ const dir = import_node_path80.default.join(this.root, extId);
74590
75043
  const env = {
74591
75044
  ...process.env,
74592
75045
  CLAWOS_EXT_PORT: String(port),
@@ -74698,7 +75151,7 @@ ${handle.stderrTail}`
74698
75151
 
74699
75152
  // src/extension/published-channels.ts
74700
75153
  var import_promises20 = __toESM(require("fs/promises"), 1);
74701
- var import_node_path78 = __toESM(require("path"), 1);
75154
+ var import_node_path81 = __toESM(require("path"), 1);
74702
75155
  init_zod();
74703
75156
  var PublishedChannelsError = class extends Error {
74704
75157
  constructor(code, message) {
@@ -74797,7 +75250,7 @@ var PublishedChannelStore = class {
74797
75250
  )
74798
75251
  };
74799
75252
  const tmp = `${this.filePath}.tmp`;
74800
- await import_promises20.default.mkdir(import_node_path78.default.dirname(this.filePath), { recursive: true });
75253
+ await import_promises20.default.mkdir(import_node_path81.default.dirname(this.filePath), { recursive: true });
74801
75254
  await import_promises20.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
74802
75255
  await import_promises20.default.rename(tmp, this.filePath);
74803
75256
  }
@@ -74805,7 +75258,7 @@ var PublishedChannelStore = class {
74805
75258
 
74806
75259
  // src/extension/bundle-cache.ts
74807
75260
  var import_promises21 = __toESM(require("fs/promises"), 1);
74808
- var import_node_path79 = __toESM(require("path"), 1);
75261
+ var import_node_path82 = __toESM(require("path"), 1);
74809
75262
  var BundleCache = class {
74810
75263
  constructor(rootDir) {
74811
75264
  this.rootDir = rootDir;
@@ -74814,14 +75267,14 @@ var BundleCache = class {
74814
75267
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
74815
75268
  async write(snapshotHash, buffer) {
74816
75269
  await import_promises21.default.mkdir(this.rootDir, { recursive: true });
74817
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75270
+ const file = import_node_path82.default.join(this.rootDir, `${snapshotHash}.zip`);
74818
75271
  const tmp = `${file}.tmp`;
74819
75272
  await import_promises21.default.writeFile(tmp, buffer, { mode: 384 });
74820
75273
  await import_promises21.default.rename(tmp, file);
74821
75274
  }
74822
75275
  /** Returns the bundle bytes, or null when the file doesn't exist. */
74823
75276
  async read(snapshotHash) {
74824
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75277
+ const file = import_node_path82.default.join(this.rootDir, `${snapshotHash}.zip`);
74825
75278
  try {
74826
75279
  return await import_promises21.default.readFile(file);
74827
75280
  } catch (e) {
@@ -74831,7 +75284,7 @@ var BundleCache = class {
74831
75284
  }
74832
75285
  /** Idempotent — missing file is not an error. */
74833
75286
  async delete(snapshotHash) {
74834
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75287
+ const file = import_node_path82.default.join(this.rootDir, `${snapshotHash}.zip`);
74835
75288
  await import_promises21.default.rm(file, { force: true });
74836
75289
  }
74837
75290
  };
@@ -74852,26 +75305,26 @@ async function startDaemon(config) {
74852
75305
  },
74853
75306
  source: "daemon",
74854
75307
  sampling: logShippingCfg.sampling,
74855
- homeDir: import_node_os29.default.homedir()
75308
+ homeDir: import_node_os32.default.homedir()
74856
75309
  });
74857
- const logDir = import_node_path80.default.join(config.dataDir, "log");
74858
- import_node_fs62.default.mkdirSync(logDir, { recursive: true });
75310
+ const logDir = import_node_path83.default.join(config.dataDir, "log");
75311
+ import_node_fs65.default.mkdirSync(logDir, { recursive: true });
74859
75312
  const logger = createLogger({
74860
75313
  level: config.logLevel,
74861
- file: import_node_path80.default.join(logDir, "clawd.log"),
75314
+ file: import_node_path83.default.join(logDir, "clawd.log"),
74862
75315
  logClient
74863
75316
  });
74864
75317
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
74865
75318
  const screenIdleProbeLogger = createFileOnlyLogger({
74866
- file: import_node_path80.default.join(logDir, "screen-idle-probe.log"),
75319
+ file: import_node_path83.default.join(logDir, "screen-idle-probe.log"),
74867
75320
  level: "debug"
74868
75321
  });
74869
75322
  logger.info("screen-idle probe logger enabled", {
74870
- file: import_node_path80.default.join(logDir, "screen-idle-probe.log")
75323
+ file: import_node_path83.default.join(logDir, "screen-idle-probe.log")
74871
75324
  });
74872
75325
  const CAP_TARGETS = [
74873
- import_node_path80.default.join(logDir, "clawd.log"),
74874
- import_node_path80.default.join(logDir, "screen-idle-probe.log")
75326
+ import_node_path83.default.join(logDir, "clawd.log"),
75327
+ import_node_path83.default.join(logDir, "screen-idle-probe.log")
74875
75328
  ];
74876
75329
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
74877
75330
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -74993,8 +75446,9 @@ async function startDaemon(config) {
74993
75446
  const agents = new AgentsScanner();
74994
75447
  const history = new ClaudeHistoryReader();
74995
75448
  let transport = null;
74996
- const personaStore = new PersonaStore(import_node_path80.default.join(config.dataDir, "personas"));
74997
- const usersRoot = import_node_path80.default.join(config.dataDir, "users");
75449
+ const personaStore = new PersonaStore(import_node_path83.default.join(config.dataDir, "personas"));
75450
+ const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
75451
+ const usersRoot = import_node_path83.default.join(config.dataDir, "users");
74998
75452
  const defaultsRoot = findDefaultsRoot(logger);
74999
75453
  if (defaultsRoot) {
75000
75454
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -75011,7 +75465,7 @@ async function startDaemon(config) {
75011
75465
  retirePersonaBuilder({ store: personaStore, logger });
75012
75466
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
75013
75467
  const dispatchStore = createDispatchStore({
75014
- filePath: import_node_path80.default.join(config.dataDir, "dispatch.json"),
75468
+ filePath: import_node_path83.default.join(config.dataDir, "dispatch.json"),
75015
75469
  now: () => Date.now(),
75016
75470
  onFlushError: (err) => logger.error("dispatch store flush failed", {
75017
75471
  reason: err instanceof Error ? err.message : String(err)
@@ -75020,7 +75474,7 @@ async function startDaemon(config) {
75020
75474
  await dispatchStore.load();
75021
75475
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
75022
75476
  const channelStore = createChannelStore({
75023
- filePath: import_node_path80.default.join(config.dataDir, "channels.json"),
75477
+ filePath: import_node_path83.default.join(config.dataDir, "channels.json"),
75024
75478
  now: () => Date.now(),
75025
75479
  genId: () => `ch-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75026
75480
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -75029,7 +75483,7 @@ async function startDaemon(config) {
75029
75483
  });
75030
75484
  await channelStore.load();
75031
75485
  const topicStore = createTopicStore({
75032
- filePath: import_node_path80.default.join(config.dataDir, "topics.json"),
75486
+ filePath: import_node_path83.default.join(config.dataDir, "topics.json"),
75033
75487
  now: () => Date.now(),
75034
75488
  genId: () => `tp-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75035
75489
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -75056,12 +75510,12 @@ async function startDaemon(config) {
75056
75510
  });
75057
75511
  }
75058
75512
  });
75059
- const here = typeof __dirname === "string" ? __dirname : import_node_path80.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75513
+ const here = typeof __dirname === "string" ? __dirname : import_node_path83.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75060
75514
  const mcpConfigs = [];
75061
75515
  const secretsBundleRoot = findSecretsBundleRoot(logger);
75062
- const localSecretsDir = import_node_path80.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75516
+ const localSecretsDir = import_node_path83.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75063
75517
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
75064
- const githubTokenFile = import_node_path80.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75518
+ const githubTokenFile = import_node_path83.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75065
75519
  const githubIdentity = createGithubIdentity({
75066
75520
  resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
75067
75521
  store: (token) => storeGithubAuth({
@@ -75099,22 +75553,22 @@ async function startDaemon(config) {
75099
75553
  void githubIdentity.refresh();
75100
75554
  return renderPersonaMcpSecrets({
75101
75555
  personaId: personaId2,
75102
- personaDir: import_node_path80.default.join(config.dataDir, "personas", personaId2),
75556
+ personaDir: import_node_path83.default.join(config.dataDir, "personas", personaId2),
75103
75557
  secrets,
75104
- outDir: import_node_path80.default.join(config.dataDir, "persona-mcp"),
75558
+ outDir: import_node_path83.default.join(config.dataDir, "persona-mcp"),
75105
75559
  logger
75106
75560
  });
75107
75561
  };
75108
75562
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
75109
75563
  const dispatchServerCandidates = [
75110
- import_node_path80.default.join(here, "dispatch", "mcp-server.cjs"),
75564
+ import_node_path83.default.join(here, "dispatch", "mcp-server.cjs"),
75111
75565
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
75112
- import_node_path80.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75566
+ import_node_path83.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75113
75567
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
75114
75568
  ];
75115
- const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75569
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75116
75570
  if (dispatchServerScriptPath) {
75117
- const dispatchLogPath = import_node_path80.default.join(logDir, "dispatch-mcp-server.log");
75571
+ const dispatchLogPath = import_node_path83.default.join(logDir, "dispatch-mcp-server.log");
75118
75572
  const dispatchCfgPath = writeDispatchMcpConfig({
75119
75573
  dataDir: config.dataDir,
75120
75574
  serverScriptPath: dispatchServerScriptPath,
@@ -75134,12 +75588,12 @@ async function startDaemon(config) {
75134
75588
  });
75135
75589
  }
75136
75590
  const ticketServerCandidates = [
75137
- import_node_path80.default.join(here, "ticket", "mcp-server.cjs"),
75138
- import_node_path80.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
75591
+ import_node_path83.default.join(here, "ticket", "mcp-server.cjs"),
75592
+ import_node_path83.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
75139
75593
  ];
75140
- const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75594
+ const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75141
75595
  if (ticketServerScriptPath) {
75142
- const ticketLogPath = import_node_path80.default.join(logDir, "ticket-mcp-server.log");
75596
+ const ticketLogPath = import_node_path83.default.join(logDir, "ticket-mcp-server.log");
75143
75597
  const ticketCfgPath = writeTicketMcpConfig({
75144
75598
  dataDir: config.dataDir,
75145
75599
  serverScriptPath: ticketServerScriptPath,
@@ -75161,12 +75615,12 @@ async function startDaemon(config) {
75161
75615
  });
75162
75616
  }
75163
75617
  const shiftServerCandidates = [
75164
- import_node_path80.default.join(here, "shift", "mcp-server.cjs"),
75165
- import_node_path80.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
75618
+ import_node_path83.default.join(here, "shift", "mcp-server.cjs"),
75619
+ import_node_path83.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
75166
75620
  ];
75167
- const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75621
+ const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75168
75622
  if (shiftServerScriptPath) {
75169
- const shiftLogPath = import_node_path80.default.join(logDir, "shift-mcp-server.log");
75623
+ const shiftLogPath = import_node_path83.default.join(logDir, "shift-mcp-server.log");
75170
75624
  const shiftCfgPath = await writeShiftMcpConfig({
75171
75625
  dataDir: config.dataDir,
75172
75626
  serverScriptPath: shiftServerScriptPath,
@@ -75187,12 +75641,12 @@ async function startDaemon(config) {
75187
75641
  );
75188
75642
  }
75189
75643
  const inboxServerCandidates = [
75190
- import_node_path80.default.join(here, "inbox", "mcp-server.cjs"),
75191
- import_node_path80.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
75644
+ import_node_path83.default.join(here, "inbox", "mcp-server.cjs"),
75645
+ import_node_path83.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
75192
75646
  ];
75193
- const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75647
+ const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75194
75648
  if (inboxServerScriptPath) {
75195
- const inboxLogPath = import_node_path80.default.join(logDir, "inbox-mcp-server.log");
75649
+ const inboxLogPath = import_node_path83.default.join(logDir, "inbox-mcp-server.log");
75196
75650
  const inboxCfgPath = await writeInboxMcpConfig({
75197
75651
  dataDir: config.dataDir,
75198
75652
  serverScriptPath: inboxServerScriptPath,
@@ -75213,10 +75667,10 @@ async function startDaemon(config) {
75213
75667
  );
75214
75668
  }
75215
75669
  const peerOpsServerCandidates = [
75216
- import_node_path80.default.join(here, "peer-ops", "mcp-server.cjs"),
75217
- import_node_path80.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
75670
+ import_node_path83.default.join(here, "peer-ops", "mcp-server.cjs"),
75671
+ import_node_path83.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
75218
75672
  ];
75219
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75673
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75220
75674
  if (peerOpsServerScriptPath) {
75221
75675
  const peerOpsCfgPath = writePeerOpsMcpConfig({
75222
75676
  dataDir: config.dataDir,
@@ -75236,12 +75690,12 @@ async function startDaemon(config) {
75236
75690
  );
75237
75691
  }
75238
75692
  const rpcToolServerCandidates = [
75239
- import_node_path80.default.join(here, "rpc-tool", "mcp-server.cjs"),
75240
- import_node_path80.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
75693
+ import_node_path83.default.join(here, "rpc-tool", "mcp-server.cjs"),
75694
+ import_node_path83.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
75241
75695
  ];
75242
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75696
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75243
75697
  if (rpcToolServerScriptPath) {
75244
- const rpcToolLogPath = import_node_path80.default.join(logDir, "rpc-tool-mcp-server.log");
75698
+ const rpcToolLogPath = import_node_path83.default.join(logDir, "rpc-tool-mcp-server.log");
75245
75699
  const rpcToolCfgPath = writeRpcToolMcpConfig({
75246
75700
  dataDir: config.dataDir,
75247
75701
  serverScriptPath: rpcToolServerScriptPath,
@@ -75262,7 +75716,7 @@ async function startDaemon(config) {
75262
75716
  );
75263
75717
  }
75264
75718
  const shiftStore = createShiftStore({
75265
- filePath: import_node_path80.default.join(config.dataDir, "shift.json"),
75719
+ filePath: import_node_path83.default.join(config.dataDir, "shift.json"),
75266
75720
  ownerIdProvider: () => ownerPrincipalId,
75267
75721
  now: () => Date.now()
75268
75722
  });
@@ -75284,7 +75738,7 @@ async function startDaemon(config) {
75284
75738
  getAdapter,
75285
75739
  historyReader: history,
75286
75740
  dataDir: config.dataDir,
75287
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
75741
+ personaRoot: import_node_path83.default.join(config.dataDir, "personas"),
75288
75742
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
75289
75743
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
75290
75744
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -75341,10 +75795,10 @@ async function startDaemon(config) {
75341
75795
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
75342
75796
  attachmentGroup: {
75343
75797
  onFileEdit: (input) => {
75344
- const absPath = import_node_path80.default.isAbsolute(input.relPath) ? input.relPath : import_node_path80.default.join(input.cwd, input.relPath);
75798
+ const absPath = import_node_path83.default.isAbsolute(input.relPath) ? input.relPath : import_node_path83.default.join(input.cwd, input.relPath);
75345
75799
  let size = 0;
75346
75800
  try {
75347
- size = import_node_fs62.default.statSync(absPath).size;
75801
+ size = import_node_fs65.default.statSync(absPath).size;
75348
75802
  } catch (err) {
75349
75803
  logger.warn("attachment.onFileEdit stat failed", {
75350
75804
  sessionId: input.sessionId,
@@ -75385,9 +75839,9 @@ async function startDaemon(config) {
75385
75839
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
75386
75840
  }
75387
75841
  const projectsStore = new ProjectsStore({
75388
- file: import_node_path80.default.join(config.dataDir, "projects.json"),
75842
+ file: import_node_path83.default.join(config.dataDir, "projects.json"),
75389
75843
  clawdDir: config.dataDir,
75390
- codexStateFile: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex", ".codex-global-state.json"),
75844
+ codexStateFile: import_node_path83.default.join(import_node_os32.default.homedir(), ".codex", ".codex-global-state.json"),
75391
75845
  logger
75392
75846
  });
75393
75847
  const observer = new SessionObserver({
@@ -75452,13 +75906,13 @@ async function startDaemon(config) {
75452
75906
  logger
75453
75907
  });
75454
75908
  registerAdapter("claude", claudeAdapter);
75455
- const codexIsolatedHome = import_node_path80.default.join(config.dataDir, "codex-home");
75909
+ const codexIsolatedHome = import_node_path83.default.join(config.dataDir, "codex-home");
75456
75910
  try {
75457
- import_node_fs62.default.mkdirSync(codexIsolatedHome, { recursive: true });
75911
+ import_node_fs65.default.mkdirSync(codexIsolatedHome, { recursive: true });
75458
75912
  for (const f2 of ["auth.json", "config.toml"]) {
75459
- const link = import_node_path80.default.join(codexIsolatedHome, f2);
75460
- const target = import_node_path80.default.join(import_node_os29.default.homedir(), ".codex", f2);
75461
- if (!import_node_fs62.default.existsSync(link) && import_node_fs62.default.existsSync(target)) import_node_fs62.default.symlinkSync(target, link);
75913
+ const link = import_node_path83.default.join(codexIsolatedHome, f2);
75914
+ const target = import_node_path83.default.join(import_node_os32.default.homedir(), ".codex", f2);
75915
+ if (!import_node_fs65.default.existsSync(link) && import_node_fs65.default.existsSync(target)) import_node_fs65.default.symlinkSync(target, link);
75462
75916
  }
75463
75917
  } catch (err) {
75464
75918
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -75469,17 +75923,17 @@ async function startDaemon(config) {
75469
75923
  logger,
75470
75924
  historyReader: new CodexHistoryReader({
75471
75925
  roots: codexRolloutRoots(config.dataDir),
75472
- sharedHome: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex"),
75926
+ sharedHome: import_node_path83.default.join(import_node_os32.default.homedir(), ".codex"),
75473
75927
  logger
75474
75928
  }),
75475
75929
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
75476
75930
  codexHomeFor: (cwd) => resolveCodexHome({
75477
75931
  cwd,
75478
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
75932
+ personaRoot: import_node_path83.default.join(config.dataDir, "personas"),
75479
75933
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
75480
75934
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
75481
75935
  projectPaths: projectsStore.listMerged().map((x2) => x2.path),
75482
- sharedHome: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex"),
75936
+ sharedHome: import_node_path83.default.join(import_node_os32.default.homedir(), ".codex"),
75483
75937
  isolatedHome: codexIsolatedHome
75484
75938
  }),
75485
75939
  // 附件图片验签:与 http-router /files 路由同一把 secret
@@ -75504,10 +75958,10 @@ async function startDaemon(config) {
75504
75958
  );
75505
75959
  registerAdapter(PI_CLOUD_TOOL_ID, new CloudPiAdapter({ client: cloudGateway, history: cloudHistorySource, logger }));
75506
75960
  const piMcpBridgeCandidates = [
75507
- import_node_path80.default.join(here, "pi-mcp-bridge", "extension.cjs"),
75508
- import_node_path80.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
75961
+ import_node_path83.default.join(here, "pi-mcp-bridge", "extension.cjs"),
75962
+ import_node_path83.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
75509
75963
  ];
75510
- const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75964
+ const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs65.default.existsSync(p3));
75511
75965
  if (piMcpBridgePath) {
75512
75966
  logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
75513
75967
  } else {
@@ -75724,6 +76178,7 @@ async function startDaemon(config) {
75724
76178
  topicStore,
75725
76179
  dispatchStore,
75726
76180
  masterDataDir: config.dataDir,
76181
+ subscriptionChannelStore,
75727
76182
  // 建话题即起该话题的 Master session(1:1)。走与 session:create 同一条 manager.create
75728
76183
  // 链路,不复制会话创建逻辑;creatorPrincipalId 用本机 deviceId(owner ctx 的 principal.id)。
75729
76184
  createMasterSession: ({ label }) => {
@@ -75802,11 +76257,11 @@ async function startDaemon(config) {
75802
76257
  // 'persona/<pid>/owner',default 走 'default'。
75803
76258
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
75804
76259
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
75805
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
76260
+ personaRoot: import_node_path83.default.join(config.dataDir, "personas"),
75806
76261
  usersRoot
75807
76262
  },
75808
76263
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
75809
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
76264
+ personaRoot: import_node_path83.default.join(config.dataDir, "personas"),
75810
76265
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
75811
76266
  usersRoot,
75812
76267
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -75952,7 +76407,7 @@ async function startDaemon(config) {
75952
76407
  sourceSessionId: args.sourceSessionId
75953
76408
  });
75954
76409
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
75955
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os29.default.homedir());
76410
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os32.default.homedir());
75956
76411
  logger.info("dispatch.spawnB.source-resolved", {
75957
76412
  dispatchId: args.dispatchId,
75958
76413
  sourceJsonlPath,
@@ -76027,6 +76482,7 @@ async function startDaemon(config) {
76027
76482
  }
76028
76483
  let lastPathRefresh = 0;
76029
76484
  const deployHandlers = buildDeployHandlers({
76485
+ channelStore: subscriptionChannelStore,
76030
76486
  hasPersona: (personaId2) => personaStore.has(personaId2),
76031
76487
  personaDir: (personaId2) => personaStore.personaDirPath(personaId2),
76032
76488
  // 发布前落闸要看它现在配的引擎和模型(云上只跑 codex / pi,且模型跟着这次发布走)
@@ -76111,7 +76567,7 @@ async function startDaemon(config) {
76111
76567
  });
76112
76568
  shiftScheduler.start();
76113
76569
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
76114
- const larkBotStore = createLarkBotBindingStore(import_node_path80.default.join(config.dataDir, "personas"));
76570
+ const larkBotStore = createLarkBotBindingStore(import_node_path83.default.join(config.dataDir, "personas"));
76115
76571
  const larkBotCloud = createLarkBotCloudClient({
76116
76572
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
76117
76573
  getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
@@ -76123,7 +76579,7 @@ async function startDaemon(config) {
76123
76579
  store: larkBotStore,
76124
76580
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
76125
76581
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
76126
- mediaRootFor: (chatId) => import_node_path80.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
76582
+ mediaRootFor: (chatId) => import_node_path83.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
76127
76583
  isShuttingDown: () => larkDraining,
76128
76584
  logger: {
76129
76585
  warn: (msg) => logger.warn(msg),
@@ -76423,8 +76879,8 @@ async function startDaemon(config) {
76423
76879
  const lines = [
76424
76880
  `Tunnel: ${r2.url}`,
76425
76881
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
76426
- `Frpc config: ${import_node_path80.default.join(config.dataDir, "frpc.toml")}`,
76427
- `Frpc log: ${import_node_path80.default.join(logDir, "frpc.log")}`
76882
+ `Frpc config: ${import_node_path83.default.join(config.dataDir, "frpc.toml")}`,
76883
+ `Frpc log: ${import_node_path83.default.join(logDir, "frpc.log")}`
76428
76884
  ];
76429
76885
  const width2 = Math.max(...lines.map((l2) => l2.length));
76430
76886
  const bar = "\u2550".repeat(width2 + 4);
@@ -76437,8 +76893,8 @@ ${bar}
76437
76893
 
76438
76894
  `);
76439
76895
  try {
76440
- const connectPath = import_node_path80.default.join(config.dataDir, "connect.txt");
76441
- import_node_fs62.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
76896
+ const connectPath = import_node_path83.default.join(config.dataDir, "connect.txt");
76897
+ import_node_fs65.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
76442
76898
  } catch {
76443
76899
  }
76444
76900
  } catch (err) {
@@ -76536,9 +76992,9 @@ ${bar}
76536
76992
  };
76537
76993
  }
76538
76994
  function migrateDropPersonsDir(dataDir) {
76539
- const dir = import_node_path80.default.join(dataDir, "persons");
76995
+ const dir = import_node_path83.default.join(dataDir, "persons");
76540
76996
  try {
76541
- import_node_fs62.default.rmSync(dir, { recursive: true, force: true });
76997
+ import_node_fs65.default.rmSync(dir, { recursive: true, force: true });
76542
76998
  } catch {
76543
76999
  }
76544
77000
  }