@clawos-dev/clawd 0.2.590 → 0.2.591

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: path104, errorMaps, issueData } = params;
454
+ const fullPath = [...path104, ...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, path104, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path102;
769
+ this._path = path104;
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 path104 = req.path;
10329
+ _req.url = typeof path104 === "string" ? path104 : 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(path104) {
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 < path104.length; i2++) {
10501
+ const char = path104[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 path104 of paths) {
10633
+ const parts = parsePath(path104);
10546
10634
  if (parts.includes("*")) {
10547
- redactWildcardPath(obj, parts, censor, path102, remove);
10635
+ redactWildcardPath(obj, parts, censor, path104, 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, path104) => {
10721
+ const fullPath = [...pathArray.slice(0, pathLength), ...path104];
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 path104 of pathsToClone) {
10757
+ const parts = parsePath(path104);
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(path104) {
10810
+ if (typeof path104 !== "string") {
10723
10811
  throw new Error("Paths must be (non-empty) strings");
10724
10812
  }
10725
- if (path102 === "") {
10813
+ if (path104 === "") {
10726
10814
  throw new Error("Invalid redaction path ()");
10727
10815
  }
10728
- if (path102.includes("..")) {
10729
- throw new Error(`Invalid redaction path (${path102})`);
10816
+ if (path104.includes("..")) {
10817
+ throw new Error(`Invalid redaction path (${path104})`);
10730
10818
  }
10731
- if (path102.includes(",")) {
10732
- throw new Error(`Invalid redaction path (${path102})`);
10819
+ if (path104.includes(",")) {
10820
+ throw new Error(`Invalid redaction path (${path104})`);
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 < path104.length; i2++) {
10826
+ const char = path104[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 (${path104})`);
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 (${path104})`);
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 path104 of paths) {
10853
+ validatePath(path104);
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, path104) => {
11022
+ return censor(value, [k3, ...path104]);
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 fs94 = require("fs");
11153
11241
  var EventEmitter2 = require("events");
11154
11242
  var inherits = require("util").inherits;
11155
- var path102 = require("path");
11243
+ var path104 = 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) fs94.mkdirSync(path104.dirname(file), { recursive: true });
11298
+ const fd = fs94.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
+ fs94.mkdir(path104.dirname(file), { recursive: true }, (err) => {
11218
11306
  if (err) return fileOpened(err);
11219
- fs92.open(file, flags, mode, fileOpened);
11307
+ fs94.open(file, flags, mode, fileOpened);
11220
11308
  });
11221
11309
  } else {
11222
- fs92.open(file, flags, mode, fileOpened);
11310
+ fs94.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 = () => fs94.writeSync(this.fd, this._writingBuf);
11352
+ fsWrite = () => fs94.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 fs94.writeSync(this.fd, this._writingBuf);
11274
11362
  }
11275
- return fs92.writeSync(this.fd, this._writingBuf, "utf8");
11363
+ return fs94.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 fs94.write(this.fd, this._writingBuf, this.release);
11280
11368
  }
11281
- return fs92.write(this.fd, this._writingBuf, "utf8", this.release);
11369
+ return fs94.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
+ fs94.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
+ fs94.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
+ fs94.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) ? fs94.writeSync(this.fd, buf) : fs94.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
+ fs94.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 = fs94.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) ? fs94.writeSync(this.fd, this._writingBuf) : fs94.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
+ fs94.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 = fs94.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
+ fs94.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
+ fs94.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
+ fs94.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 os36 = 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 = os36.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(path104, added, removed, oldPosInc, options) {
14937
+ var last = path104.lastComponent;
14850
14938
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14851
14939
  return {
14852
- oldPos: path102.oldPos + oldPosInc,
14940
+ oldPos: path104.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: path104.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 path104 = 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 (!path104 || content == null) return null;
15535
+ const entry = { path: path104, 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 path104 = 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 (!path104 || content == null) return null;
16404
+ const out = { path: path104, 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(path104) {
37379
+ var parts = path104.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(path104) {
43233
+ if (path104.slice(-1) === "/") {
43234
+ path104 = path104.substring(0, path104.length - 1);
43147
43235
  }
43148
- var lastSlash = path102.lastIndexOf("/");
43149
- return lastSlash > 0 ? path102.substring(0, lastSlash) : "";
43236
+ var lastSlash = path104.lastIndexOf("/");
43237
+ return lastSlash > 0 ? path104.substring(0, lastSlash) : "";
43150
43238
  };
43151
- var forceTrailingSlash = function(path102) {
43152
- if (path102.slice(-1) !== "/") {
43153
- path102 += "/";
43239
+ var forceTrailingSlash = function(path104) {
43240
+ if (path104.slice(-1) !== "/") {
43241
+ path104 += "/";
43154
43242
  }
43155
- return path102;
43243
+ return path104;
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_path83.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_fs65.default.mkdirSync(dir, { recursive: true });
44260
+ stream = import_node_fs65.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_fs65, import_node_path83;
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_fs65 = __toESM(require("fs"), 1);
44290
+ import_node_path83 = __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_fs66.mkdtempSync)(import_node_path84.default.join(import_node_os32.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_fs66.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_fs66, import_node_os32, import_node_path84;
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_fs66 = require("fs");
44505
+ import_node_os32 = __toESM(require("os"), 1);
44506
+ import_node_path84 = __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_path82 = __toESM(require("path"), 1);
44779
+ var import_node_fs64 = __toESM(require("fs"), 1);
44780
+ var import_node_os31 = __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, path104, init) {
52439
52527
  const f2 = opts.fetchImpl ?? globalThis.fetch;
52440
- const url = `${opts.api.replace(/\/+$/, "")}${path102}`;
52528
+ const url = `${opts.api.replace(/\/+$/, "")}${path104}`;
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, path104] = m3;
53563
+ items.push({ type: "skill", name, path: path104 });
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, path104, body) {
60843
60937
  let res;
60844
60938
  try {
60845
- res = await doFetch(`${API}${path102}`, {
60939
+ res = await doFetch(`${API}${path104}`, {
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, path104, what, body) {
60965
+ const r2 = await request(method, path104, 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(path104) {
60917
61011
  try {
60918
- const r2 = await request("GET", path102);
61012
+ const r2 = await request("GET", path104);
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,168 @@ 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
+ var SubscriptionChannelStore = class {
62275
+ filePath;
62276
+ codexHome;
62277
+ constructor(options) {
62278
+ this.filePath = import_node_path40.default.join(options.dataDir, CHANNELS_FILE_NAME);
62279
+ this.codexHome = options.codexHome || process.env.CODEX_HOME || import_node_path40.default.join(import_node_os12.default.homedir(), ".codex");
62280
+ }
62281
+ /** 获取列表与激活通道 ID(Key 经脱敏掩码) */
62282
+ list() {
62283
+ const data = this.readOrCreate();
62284
+ return {
62285
+ activeChannelId: data.activeChannelId,
62286
+ channels: data.channels.map(toChannelView)
62287
+ };
62288
+ }
62289
+ /** 获取通道原始实体(含明文 Key,供配置应用与部署写入使用) */
62290
+ get(id) {
62291
+ const data = this.readOrCreate();
62292
+ return data.channels.find((c2) => c2.id === id) ?? null;
62293
+ }
62294
+ /** 获取当前激活的通道实体 */
62295
+ getActive() {
62296
+ const data = this.readOrCreate();
62297
+ if (!data.activeChannelId) return null;
62298
+ return data.channels.find((c2) => c2.id === data.activeChannelId) ?? null;
62299
+ }
62300
+ /** 保存(新增或更新)通道 */
62301
+ save(input) {
62302
+ const name = input.name.trim();
62303
+ if (!name) throw new Error("\u901A\u9053\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
62304
+ let baseUrl;
62305
+ try {
62306
+ baseUrl = normalizeEngineBaseUrl(input.baseUrl);
62307
+ } catch (err) {
62308
+ throw new Error(err instanceof Error ? err.message : String(err));
62309
+ }
62310
+ const data = this.readOrCreate();
62311
+ const now = Date.now();
62312
+ if (input.id) {
62313
+ const idx = data.channels.findIndex((c2) => c2.id === input.id);
62314
+ if (idx === -1) throw new Error(`\u672A\u627E\u5230 ID \u4E3A ${input.id} \u7684\u901A\u9053`);
62315
+ const existing = data.channels[idx];
62316
+ const apiKey2 = input.apiKey && input.apiKey.trim() ? input.apiKey.trim() : existing.apiKey;
62317
+ const updated = {
62318
+ ...existing,
62319
+ name,
62320
+ baseUrl,
62321
+ apiKey: apiKey2,
62322
+ ...input.remark !== void 0 ? { remark: input.remark.trim() || void 0 } : {},
62323
+ updatedAt: now
62324
+ };
62325
+ data.channels[idx] = updated;
62326
+ this.write(data);
62327
+ return updated;
62328
+ }
62329
+ const apiKey = input.apiKey?.trim();
62330
+ if (!apiKey) throw new Error("\u65B0\u5EFA\u901A\u9053\u5FC5\u987B\u586B\u5199 API Key");
62331
+ const newId = `chan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
62332
+ const newChannel = {
62333
+ id: newId,
62334
+ name,
62335
+ baseUrl,
62336
+ apiKey,
62337
+ ...input.remark && input.remark.trim() ? { remark: input.remark.trim() } : {},
62338
+ createdAt: now,
62339
+ updatedAt: now
62340
+ };
62341
+ data.channels.push(newChannel);
62342
+ if (data.channels.length === 1 && !data.activeChannelId) {
62343
+ data.activeChannelId = newChannel.id;
62344
+ }
62345
+ this.write(data);
62346
+ return newChannel;
62347
+ }
62348
+ /** 删除通道 */
62349
+ delete(id) {
62350
+ const data = this.readOrCreate();
62351
+ const filtered = data.channels.filter((c2) => c2.id !== id);
62352
+ if (filtered.length === data.channels.length) return;
62353
+ data.channels = filtered;
62354
+ if (data.activeChannelId === id) {
62355
+ data.activeChannelId = data.channels.length > 0 ? data.channels[0].id : null;
62356
+ }
62357
+ this.write(data);
62358
+ }
62359
+ /** 设置当前激活通道(id 为 null 表示停用所有通道) */
62360
+ setActive(id) {
62361
+ const data = this.readOrCreate();
62362
+ if (id === null) {
62363
+ data.activeChannelId = null;
62364
+ this.write(data);
62365
+ return null;
62366
+ }
62367
+ const target = data.channels.find((c2) => c2.id === id);
62368
+ if (!target) throw new Error(`\u901A\u9053 ${id} \u4E0D\u5B58\u5728`);
62369
+ data.activeChannelId = id;
62370
+ this.write(data);
62371
+ return target;
62372
+ }
62373
+ readOrCreate() {
62374
+ if (import_node_fs35.default.existsSync(this.filePath)) {
62375
+ try {
62376
+ const raw = JSON.parse(import_node_fs35.default.readFileSync(this.filePath, "utf8"));
62377
+ if (raw && Array.isArray(raw.channels)) {
62378
+ return {
62379
+ activeChannelId: typeof raw.activeChannelId === "string" ? raw.activeChannelId : null,
62380
+ channels: raw.channels
62381
+ };
62382
+ }
62383
+ } catch {
62384
+ }
62385
+ }
62386
+ const migrated = this.tryMigrateFromCodexConfig();
62387
+ const initial = migrated ?? {
62388
+ activeChannelId: null,
62389
+ channels: []
62390
+ };
62391
+ this.write(initial);
62392
+ return initial;
62393
+ }
62394
+ tryMigrateFromCodexConfig() {
62395
+ try {
62396
+ const configPath = import_node_path40.default.join(this.codexHome, "config.toml");
62397
+ if (!import_node_fs35.default.existsSync(configPath)) return null;
62398
+ const content = import_node_fs35.default.readFileSync(configPath, "utf8");
62399
+ if (!content.includes('model_provider = "cliproxyapi"')) return null;
62400
+ const urlMatch = /base_url\s*=\s*["']([^"']+)["']/.exec(content);
62401
+ const keyMatch = /args\s*=\s*\[\s*["']([^"']+)["']\s*\]/.exec(content) || /experimental_bearer_token\s*=\s*["']([^"']+)["']/.exec(content);
62402
+ if (urlMatch && keyMatch) {
62403
+ const id = "default-pool";
62404
+ const channel = {
62405
+ id,
62406
+ name: "\u9ED8\u8BA4\u56E2\u961F\u53F7\u6C60",
62407
+ baseUrl: normalizeEngineBaseUrl(urlMatch[1]),
62408
+ apiKey: keyMatch[1],
62409
+ remark: "\u4ECE\u672C\u673A\u5DF2\u63A5\u5165\u7684\u53F7\u6C60\u914D\u7F6E\u81EA\u52A8\u8FC1\u79FB",
62410
+ createdAt: Date.now(),
62411
+ updatedAt: Date.now()
62412
+ };
62413
+ return {
62414
+ activeChannelId: id,
62415
+ channels: [channel]
62416
+ };
62417
+ }
62418
+ } catch {
62419
+ }
62420
+ return null;
62421
+ }
62422
+ write(data) {
62423
+ const dir = import_node_path40.default.dirname(this.filePath);
62424
+ import_node_fs35.default.mkdirSync(dir, { recursive: true });
62425
+ const tmp = `${this.filePath}.tmp.${Date.now()}`;
62426
+ import_node_fs35.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
62427
+ import_node_fs35.default.renameSync(tmp, this.filePath);
62428
+ }
62429
+ };
62430
+
62169
62431
  // src/deploy/local-probe.ts
62170
62432
  function pickVersion(s2) {
62171
62433
  return /(\d+)\.(\d+)(?:\.(\d+))?/.exec(s2)?.[0];
@@ -62214,18 +62476,18 @@ async function probeLocalVersion(exec, pkg) {
62214
62476
 
62215
62477
  // src/tools/shell-path.ts
62216
62478
  var import_node_child_process10 = require("child_process");
62217
- var import_node_os12 = __toESM(require("os"), 1);
62479
+ var import_node_os13 = __toESM(require("os"), 1);
62218
62480
  function refreshPathFromLoginShell() {
62219
62481
  if (process.platform === "win32") return;
62220
- const shell = process.env.SHELL ?? import_node_os12.default.userInfo().shell ?? "/bin/zsh";
62482
+ const shell = process.env.SHELL ?? import_node_os13.default.userInfo().shell ?? "/bin/zsh";
62221
62483
  try {
62222
62484
  const out = (0, import_node_child_process10.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
62223
62485
  encoding: "utf8",
62224
62486
  timeout: 3e3,
62225
62487
  stdio: ["ignore", "pipe", "ignore"]
62226
62488
  });
62227
- const path102 = out.trim();
62228
- if (path102) process.env.PATH = path102;
62489
+ const path104 = out.trim();
62490
+ if (path104) process.env.PATH = path104;
62229
62491
  } catch {
62230
62492
  }
62231
62493
  }
@@ -62763,15 +63025,15 @@ async function refreshTunnelUrlOnStartup(deps) {
62763
63025
  }
62764
63026
 
62765
63027
  // 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);
63028
+ var import_node_fs36 = __toESM(require("fs"), 1);
63029
+ var import_node_path41 = __toESM(require("path"), 1);
62768
63030
  function createLarkBotBindingStore(personaRoot) {
62769
- const filePath = (personaId2) => import_node_path40.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
63031
+ const filePath = (personaId2) => import_node_path41.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
62770
63032
  const read = (personaId2) => {
62771
63033
  const file = filePath(personaId2);
62772
- if (!import_node_fs35.default.existsSync(file)) return null;
63034
+ if (!import_node_fs36.default.existsSync(file)) return null;
62773
63035
  try {
62774
- const raw = JSON.parse(import_node_fs35.default.readFileSync(file, "utf8"));
63036
+ const raw = JSON.parse(import_node_fs36.default.readFileSync(file, "utf8"));
62775
63037
  if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
62776
63038
  return raw;
62777
63039
  } catch {
@@ -62780,16 +63042,16 @@ function createLarkBotBindingStore(personaRoot) {
62780
63042
  };
62781
63043
  const write = (personaId2, meta) => {
62782
63044
  const file = filePath(personaId2);
62783
- import_node_fs35.default.mkdirSync(import_node_path40.default.dirname(file), { recursive: true });
63045
+ import_node_fs36.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true });
62784
63046
  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);
63047
+ import_node_fs36.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
63048
+ import_node_fs36.default.renameSync(tmp, file);
62787
63049
  };
62788
63050
  return {
62789
63051
  read,
62790
63052
  write,
62791
63053
  remove(personaId2) {
62792
- import_node_fs35.default.rmSync(filePath(personaId2), { force: true });
63054
+ import_node_fs36.default.rmSync(filePath(personaId2), { force: true });
62793
63055
  },
62794
63056
  addRemovedChat(personaId2, chatId) {
62795
63057
  const meta = read(personaId2);
@@ -62941,8 +63203,8 @@ function createLarkBotCloudClient(opts) {
62941
63203
  }
62942
63204
 
62943
63205
  // 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);
63206
+ var import_node_fs37 = __toESM(require("fs"), 1);
63207
+ var import_node_path42 = __toESM(require("path"), 1);
62946
63208
  init_protocol();
62947
63209
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
62948
63210
  var LOCAL_TURN_RETRIES = 2;
@@ -63020,9 +63282,9 @@ function createLarkChatRouter(deps) {
63020
63282
  continue;
63021
63283
  }
63022
63284
  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);
63285
+ import_node_fs37.default.mkdirSync(dir, { recursive: true });
63286
+ const p3 = import_node_path42.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}.${ext}`);
63287
+ import_node_fs37.default.writeFileSync(p3, r2.data);
63026
63288
  lines.push(`[\u56FE\u7247: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
63027
63289
  } catch (err) {
63028
63290
  deps.logger?.warn(`larkBot image fetch failed ${key}: ${err.message}`);
@@ -63043,9 +63305,9 @@ function createLarkChatRouter(deps) {
63043
63305
  continue;
63044
63306
  }
63045
63307
  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);
63308
+ import_node_fs37.default.mkdirSync(dir, { recursive: true });
63309
+ const p3 = import_node_path42.default.join(dir, `${safeMediaName(ownerMessageId)}-${i2}-${safeAttachmentName(f2.name)}`);
63310
+ import_node_fs37.default.writeFileSync(p3, r2.data);
63049
63311
  lines.push(`[\u6587\u4EF6: ${p3}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
63050
63312
  } catch (err) {
63051
63313
  deps.logger?.warn(`larkBot file fetch failed ${f2.key}: ${err.message}`);
@@ -64241,7 +64503,7 @@ function openHttpLineStream(opts) {
64241
64503
  init_protocol();
64242
64504
 
64243
64505
  // src/tools/codex-cloud-session.ts
64244
- var import_node_fs37 = __toESM(require("fs"), 1);
64506
+ var import_node_fs38 = __toESM(require("fs"), 1);
64245
64507
  function cloudThreadParams(ctx, paths) {
64246
64508
  const { model: _model, ...base } = threadStartParams(ctx);
64247
64509
  const developerInstructions = [ctx.extraSystemPrompt, workDirPrompt(paths.workDir, ctx.personaMode ?? "owner")].filter((x2) => Boolean(x2)).join("\n\n");
@@ -64298,7 +64560,7 @@ function cloudImageInput(deps) {
64298
64560
  const mime = lookupMime(p3);
64299
64561
  if (!mime.startsWith("image/")) return null;
64300
64562
  try {
64301
- const bytes = (deps.readFile ?? import_node_fs37.default.readFileSync)(p3);
64563
+ const bytes = (deps.readFile ?? import_node_fs38.default.readFileSync)(p3);
64302
64564
  return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
64303
64565
  } catch (e) {
64304
64566
  deps.logger?.warn("cloud image attachment unreadable", { path: p3, message: e.message });
@@ -64432,7 +64694,7 @@ init_protocol();
64432
64694
 
64433
64695
  // src/tools/pi.ts
64434
64696
  var import_node_child_process12 = require("child_process");
64435
- var import_node_fs39 = __toESM(require("fs"), 1);
64697
+ var import_node_fs40 = __toESM(require("fs"), 1);
64436
64698
  init_protocol();
64437
64699
 
64438
64700
  // src/tools/pi-rpc-client.ts
@@ -64533,8 +64795,8 @@ var PiRpcClient = class {
64533
64795
  // src/tools/pi-session.ts
64534
64796
  var import_node_child_process11 = require("child_process");
64535
64797
  var import_node_crypto12 = require("crypto");
64536
- var import_node_fs38 = __toESM(require("fs"), 1);
64537
- var import_node_path42 = __toESM(require("path"), 1);
64798
+ var import_node_fs39 = __toESM(require("fs"), 1);
64799
+ var import_node_path43 = __toESM(require("path"), 1);
64538
64800
 
64539
64801
  // src/tools/pi-events.ts
64540
64802
  init_protocol();
@@ -64806,8 +65068,8 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
64806
65068
  function createPiSession(ctx, sink, deps = {}) {
64807
65069
  const cmd = process.env.PI_BIN ?? "pi";
64808
65070
  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));
65071
+ const skillsDir = import_node_path43.default.join(ctx.cwd, ".claude", "skills");
65072
+ const exists = deps.skillsDirExists ?? ((d2) => import_node_fs39.default.existsSync(d2));
64811
65073
  const args = buildPiArgs(ctx, {
64812
65074
  sessionId,
64813
65075
  skillsDir: exists(skillsDir) ? skillsDir : void 0,
@@ -64869,10 +65131,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
64869
65131
  };
64870
65132
  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
65133
  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 };
65134
+ if (env.PI_BIN && import_node_fs40.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
64873
65135
  try {
64874
65136
  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 };
65137
+ if (out && import_node_fs40.default.existsSync(out)) return { available: true, path: out };
64876
65138
  } catch {
64877
65139
  }
64878
65140
  return { available: false };
@@ -65159,7 +65421,7 @@ var CloudPiAdapter = class {
65159
65421
  init_protocol();
65160
65422
 
65161
65423
  // src/tools/codex-skills.ts
65162
- var import_node_path43 = __toESM(require("path"), 1);
65424
+ var import_node_path44 = __toESM(require("path"), 1);
65163
65425
  function str4(v3) {
65164
65426
  return typeof v3 === "string" ? v3 : void 0;
65165
65427
  }
@@ -65174,13 +65436,13 @@ function mapSkillsListResponse(res) {
65174
65436
  const r2 = s2 ?? {};
65175
65437
  const name = str4(r2.name);
65176
65438
  if (!name) continue;
65177
- const path102 = str4(r2.path);
65439
+ const path104 = str4(r2.path);
65178
65440
  const description = str4(r2.description);
65179
65441
  const isPlugin = name.includes(":");
65180
65442
  out.push({
65181
65443
  name,
65182
65444
  source: isPlugin ? "plugin" : "project",
65183
- ...path102 ? { path: path102 } : {},
65445
+ ...path104 ? { path: path104 } : {},
65184
65446
  ...description ? { description } : {},
65185
65447
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
65186
65448
  });
@@ -65196,7 +65458,7 @@ async function listCodexSkills(cwd, deps = {}) {
65196
65458
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
65197
65459
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
65198
65460
  beforeRequest: (client) => {
65199
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path43.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
65461
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path44.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
65200
65462
  }
65201
65463
  });
65202
65464
  return mapSkillsListResponse(res);
@@ -65270,23 +65532,23 @@ function rec4(v3) {
65270
65532
  }
65271
65533
 
65272
65534
  // 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);
65535
+ var import_node_fs41 = __toESM(require("fs"), 1);
65536
+ var import_node_os14 = __toESM(require("os"), 1);
65537
+ var import_node_path45 = __toESM(require("path"), 1);
65276
65538
  init_protocol();
65277
65539
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
65278
65540
  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)) {
65541
+ const absCwd = import_node_path45.default.resolve(cwd);
65542
+ const joined = import_node_path45.default.resolve(absCwd, subpath ?? ".");
65543
+ const rel = import_node_path45.default.relative(absCwd, joined);
65544
+ if (rel.startsWith("..") || import_node_path45.default.isAbsolute(rel)) {
65283
65545
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
65284
65546
  }
65285
65547
  return joined;
65286
65548
  }
65287
65549
  function ensureCwd(cwd) {
65288
65550
  try {
65289
- const stat = import_node_fs40.default.statSync(cwd);
65551
+ const stat = import_node_fs41.default.statSync(cwd);
65290
65552
  if (!stat.isDirectory()) {
65291
65553
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
65292
65554
  }
@@ -65297,10 +65559,10 @@ function ensureCwd(cwd) {
65297
65559
  }
65298
65560
  var WorkspaceBrowser = class {
65299
65561
  list(args) {
65300
- const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os13.default.homedir();
65562
+ const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os14.default.homedir();
65301
65563
  ensureCwd(cwd);
65302
65564
  const full = resolveInsideCwd(cwd, args.path);
65303
- const dirents = import_node_fs40.default.readdirSync(full, { withFileTypes: true });
65565
+ const dirents = import_node_fs41.default.readdirSync(full, { withFileTypes: true });
65304
65566
  const entries = [];
65305
65567
  for (const d2 of dirents) {
65306
65568
  if (!args.showHidden && d2.name.startsWith(".")) continue;
@@ -65310,7 +65572,7 @@ var WorkspaceBrowser = class {
65310
65572
  mtime: ""
65311
65573
  };
65312
65574
  try {
65313
- const st2 = import_node_fs40.default.statSync(import_node_path44.default.join(full, d2.name));
65575
+ const st2 = import_node_fs41.default.statSync(import_node_path45.default.join(full, d2.name));
65314
65576
  entry.mtime = new Date(st2.mtimeMs).toISOString();
65315
65577
  if (d2.isFile()) entry.size = st2.size;
65316
65578
  } catch {
@@ -65326,14 +65588,14 @@ var WorkspaceBrowser = class {
65326
65588
  read(args) {
65327
65589
  ensureCwd(args.cwd);
65328
65590
  const full = resolveInsideCwd(args.cwd, args.path);
65329
- const st2 = import_node_fs40.default.statSync(full);
65591
+ const st2 = import_node_fs41.default.statSync(full);
65330
65592
  if (!st2.isFile()) {
65331
65593
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
65332
65594
  }
65333
65595
  if (st2.size > MAX_FILE_BYTES2) {
65334
65596
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
65335
65597
  }
65336
- const buf = import_node_fs40.default.readFileSync(full);
65598
+ const buf = import_node_fs41.default.readFileSync(full);
65337
65599
  const isBinary = buf.includes(0);
65338
65600
  if (isBinary) {
65339
65601
  return {
@@ -65355,20 +65617,20 @@ var WorkspaceBrowser = class {
65355
65617
  };
65356
65618
 
65357
65619
  // 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);
65620
+ var import_node_fs42 = __toESM(require("fs"), 1);
65621
+ var import_node_os15 = __toESM(require("os"), 1);
65622
+ var import_node_path46 = __toESM(require("path"), 1);
65361
65623
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
65362
65624
  function isDirLikeSync2(p3) {
65363
65625
  try {
65364
- return import_node_fs41.default.statSync(p3).isDirectory();
65626
+ return import_node_fs42.default.statSync(p3).isDirectory();
65365
65627
  } catch {
65366
65628
  return false;
65367
65629
  }
65368
65630
  }
65369
65631
  function fileExistsSync(p3) {
65370
65632
  try {
65371
- return import_node_fs41.default.statSync(p3).isFile();
65633
+ return import_node_fs42.default.statSync(p3).isFile();
65372
65634
  } catch {
65373
65635
  return false;
65374
65636
  }
@@ -65376,7 +65638,7 @@ function fileExistsSync(p3) {
65376
65638
  function parseAgentFile(filePath) {
65377
65639
  let content;
65378
65640
  try {
65379
- content = import_node_fs41.default.readFileSync(filePath, "utf8");
65641
+ content = import_node_fs42.default.readFileSync(filePath, "utf8");
65380
65642
  } catch {
65381
65643
  return {};
65382
65644
  }
@@ -65389,16 +65651,16 @@ function parseAgentFile(filePath) {
65389
65651
  function scanAgentsDir(dir, source, seen, out) {
65390
65652
  let entries;
65391
65653
  try {
65392
- entries = import_node_fs41.default.readdirSync(dir, { withFileTypes: true });
65654
+ entries = import_node_fs42.default.readdirSync(dir, { withFileTypes: true });
65393
65655
  } catch {
65394
65656
  return;
65395
65657
  }
65396
65658
  for (const ent of entries) {
65397
65659
  if (!ent.name.endsWith(".md")) continue;
65398
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path45.default.join(dir, ent.name)))) {
65660
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path46.default.join(dir, ent.name)))) {
65399
65661
  continue;
65400
65662
  }
65401
- const filePath = import_node_path45.default.join(dir, ent.name);
65663
+ const filePath = import_node_path46.default.join(dir, ent.name);
65402
65664
  const baseName = ent.name.replace(/\.md$/, "");
65403
65665
  if (seen.has(baseName)) continue;
65404
65666
  seen.add(baseName);
@@ -65416,12 +65678,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
65416
65678
  function walk2(dir, namespaces) {
65417
65679
  let entries;
65418
65680
  try {
65419
- entries = import_node_fs41.default.readdirSync(dir, { withFileTypes: true });
65681
+ entries = import_node_fs42.default.readdirSync(dir, { withFileTypes: true });
65420
65682
  } catch {
65421
65683
  return;
65422
65684
  }
65423
65685
  for (const ent of entries) {
65424
- const childPath = import_node_path45.default.join(dir, ent.name);
65686
+ const childPath = import_node_path46.default.join(dir, ent.name);
65425
65687
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
65426
65688
  walk2(childPath, [...namespaces, ent.name]);
65427
65689
  continue;
@@ -65446,13 +65708,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
65446
65708
  walk2(root, []);
65447
65709
  }
65448
65710
  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");
65711
+ const pluginsDir = import_node_path46.default.join(home, ".claude", "plugins");
65712
+ const v22 = import_node_path46.default.join(pluginsDir, "installed_plugins_v2.json");
65713
+ const v1 = import_node_path46.default.join(pluginsDir, "installed_plugins.json");
65452
65714
  let raw = null;
65453
65715
  for (const candidate of [v22, v1]) {
65454
65716
  try {
65455
- raw = import_node_fs41.default.readFileSync(candidate, "utf8");
65717
+ raw = import_node_fs42.default.readFileSync(candidate, "utf8");
65456
65718
  break;
65457
65719
  } catch {
65458
65720
  }
@@ -65477,19 +65739,19 @@ function readInstalledPlugins2(home) {
65477
65739
  return out;
65478
65740
  }
65479
65741
  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;
65742
+ let cur = import_node_path46.default.resolve(startCwd);
65743
+ const fsRoot = import_node_path46.default.parse(cur).root;
65482
65744
  while (true) {
65483
- scanAgentsDir(import_node_path45.default.join(cur, ".claude", "agents"), "project", seen, out);
65745
+ scanAgentsDir(import_node_path46.default.join(cur, ".claude", "agents"), "project", seen, out);
65484
65746
  let hasGit = false;
65485
65747
  try {
65486
- hasGit = import_node_fs41.default.existsSync(import_node_path45.default.join(cur, ".git"));
65748
+ hasGit = import_node_fs42.default.existsSync(import_node_path46.default.join(cur, ".git"));
65487
65749
  } catch {
65488
65750
  }
65489
65751
  if (hasGit) return;
65490
65752
  if (cur === home) return;
65491
65753
  if (cur === fsRoot) return;
65492
- const parent = import_node_path45.default.dirname(cur);
65754
+ const parent = import_node_path46.default.dirname(cur);
65493
65755
  if (parent === cur) return;
65494
65756
  cur = parent;
65495
65757
  }
@@ -65499,7 +65761,7 @@ var AgentsScanner = class {
65499
65761
  extraPluginRoots;
65500
65762
  policyDir;
65501
65763
  constructor(opts = {}) {
65502
- this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os14.default.homedir();
65764
+ this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os15.default.homedir();
65503
65765
  this.extraPluginRoots = opts.extraPluginRoots ?? [];
65504
65766
  if (opts.policyDir !== void 0) {
65505
65767
  this.policyDir = opts.policyDir;
@@ -65524,7 +65786,7 @@ var AgentsScanner = class {
65524
65786
  }
65525
65787
  const fsBlock = [];
65526
65788
  scanAgentsDir(
65527
- import_node_path45.default.join(this.home, ".claude", "agents"),
65789
+ import_node_path46.default.join(this.home, ".claude", "agents"),
65528
65790
  "global",
65529
65791
  seen,
65530
65792
  fsBlock
@@ -65538,7 +65800,7 @@ var AgentsScanner = class {
65538
65800
  ...this.extraPluginRoots
65539
65801
  ];
65540
65802
  for (const { name, root } of plugins) {
65541
- const agentsRoot = import_node_path45.default.join(root, "agents");
65803
+ const agentsRoot = import_node_path46.default.join(root, "agents");
65542
65804
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
65543
65805
  }
65544
65806
  return [...builtinBlock, ...fsBlock];
@@ -65546,28 +65808,28 @@ var AgentsScanner = class {
65546
65808
  };
65547
65809
 
65548
65810
  // 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);
65811
+ var import_node_fs44 = __toESM(require("fs"), 1);
65812
+ var import_node_os17 = __toESM(require("os"), 1);
65813
+ var import_node_path48 = __toESM(require("path"), 1);
65552
65814
  init_claude_history();
65553
65815
 
65554
65816
  // 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);
65817
+ var import_node_fs43 = __toESM(require("fs"), 1);
65818
+ var import_node_os16 = __toESM(require("os"), 1);
65819
+ var import_node_path47 = __toESM(require("path"), 1);
65558
65820
  init_claude_history();
65559
65821
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
65560
65822
  var SubagentMetaObserver = class {
65561
65823
  constructor(opts) {
65562
65824
  this.opts = opts;
65563
- this.home = opts.home ?? import_node_os15.default.homedir();
65825
+ this.home = opts.home ?? import_node_os16.default.homedir();
65564
65826
  }
65565
65827
  opts;
65566
65828
  home;
65567
65829
  watches = /* @__PURE__ */ new Map();
65568
65830
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
65569
65831
  resolveSubagentDir(cwd, toolSessionId) {
65570
- return import_node_path46.default.join(
65832
+ return import_node_path47.default.join(
65571
65833
  this.home,
65572
65834
  ".claude",
65573
65835
  "projects",
@@ -65597,7 +65859,7 @@ var SubagentMetaObserver = class {
65597
65859
  attachWatcher(w3) {
65598
65860
  if (w3.watcher) return;
65599
65861
  try {
65600
- w3.watcher = import_node_fs42.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
65862
+ w3.watcher = import_node_fs43.default.watch(w3.dirPath, { persistent: false }, (_evt, name) => {
65601
65863
  if (!name) return;
65602
65864
  const m3 = META_RE.exec(String(name));
65603
65865
  if (!m3) return;
@@ -65609,7 +65871,7 @@ var SubagentMetaObserver = class {
65609
65871
  scan(w3) {
65610
65872
  let entries;
65611
65873
  try {
65612
- entries = import_node_fs42.default.readdirSync(w3.dirPath);
65874
+ entries = import_node_fs43.default.readdirSync(w3.dirPath);
65613
65875
  } catch {
65614
65876
  return;
65615
65877
  }
@@ -65623,10 +65885,10 @@ var SubagentMetaObserver = class {
65623
65885
  if (!m3) return;
65624
65886
  const agentId = m3[1];
65625
65887
  if (w3.emitted.has(agentId)) return;
65626
- const file = import_node_path46.default.join(w3.dirPath, name);
65888
+ const file = import_node_path47.default.join(w3.dirPath, name);
65627
65889
  let raw;
65628
65890
  try {
65629
- raw = import_node_fs42.default.readFileSync(file, "utf8");
65891
+ raw = import_node_fs43.default.readFileSync(file, "utf8");
65630
65892
  } catch {
65631
65893
  return;
65632
65894
  }
@@ -65671,7 +65933,7 @@ var SubagentMetaObserver = class {
65671
65933
  var SessionObserver = class {
65672
65934
  constructor(opts) {
65673
65935
  this.opts = opts;
65674
- this.home = opts.home ?? import_node_os16.default.homedir();
65936
+ this.home = opts.home ?? import_node_os17.default.homedir();
65675
65937
  this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
65676
65938
  }
65677
65939
  opts;
@@ -65683,14 +65945,14 @@ var SessionObserver = class {
65683
65945
  metaObserver;
65684
65946
  resolveJsonlPath(cwd, toolSessionId, override) {
65685
65947
  if (override) return override;
65686
- return import_node_path47.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
65948
+ return import_node_path48.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
65687
65949
  }
65688
65950
  start(args) {
65689
65951
  this.stop(args.sessionId);
65690
65952
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
65691
65953
  let size = 0;
65692
65954
  try {
65693
- size = import_node_fs43.default.statSync(filePath).size;
65955
+ size = import_node_fs44.default.statSync(filePath).size;
65694
65956
  } catch {
65695
65957
  }
65696
65958
  const w3 = {
@@ -65703,16 +65965,16 @@ var SessionObserver = class {
65703
65965
  adapter: args.adapter,
65704
65966
  prevIsRejectSentinel: false,
65705
65967
  toolSessionId: args.toolSessionId,
65706
- sawFile: import_node_fs43.default.existsSync(filePath),
65968
+ sawFile: import_node_fs44.default.existsSync(filePath),
65707
65969
  lastRelocateScanMs: 0,
65708
65970
  pendingCwdDerive: false,
65709
65971
  lastDeriveMs: 0
65710
65972
  };
65711
65973
  try {
65712
- import_node_fs43.default.mkdirSync(import_node_path47.default.dirname(filePath), { recursive: true });
65974
+ import_node_fs44.default.mkdirSync(import_node_path48.default.dirname(filePath), { recursive: true });
65713
65975
  } catch {
65714
65976
  }
65715
- w3.watcher = import_node_fs43.default.watch(import_node_path47.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
65977
+ w3.watcher = import_node_fs44.default.watch(import_node_path48.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
65716
65978
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
65717
65979
  this.poll(w3);
65718
65980
  });
@@ -65735,7 +65997,7 @@ var SessionObserver = class {
65735
65997
  // 异常静默吞,不阻塞 watcher 启动
65736
65998
  hydrateMetaTail(w3, maxLines = 200) {
65737
65999
  try {
65738
- const raw = import_node_fs43.default.readFileSync(w3.filePath, "utf8");
66000
+ const raw = import_node_fs44.default.readFileSync(w3.filePath, "utf8");
65739
66001
  if (!raw) return;
65740
66002
  const allLines = raw.split("\n").filter((l2) => l2.trim().length > 0);
65741
66003
  if (allLines.length === 0) return;
@@ -65759,7 +66021,7 @@ var SessionObserver = class {
65759
66021
  poll(w3) {
65760
66022
  let size = 0;
65761
66023
  try {
65762
- size = import_node_fs43.default.statSync(w3.filePath).size;
66024
+ size = import_node_fs44.default.statSync(w3.filePath).size;
65763
66025
  } catch {
65764
66026
  if (w3.sawFile) this.maybeRelocate(w3);
65765
66027
  return;
@@ -65770,11 +66032,11 @@ var SessionObserver = class {
65770
66032
  w3.buf = "";
65771
66033
  }
65772
66034
  if (size === w3.lastSize) return;
65773
- const fd = import_node_fs43.default.openSync(w3.filePath, "r");
66035
+ const fd = import_node_fs44.default.openSync(w3.filePath, "r");
65774
66036
  try {
65775
66037
  const len = size - w3.lastSize;
65776
66038
  const buf = Buffer.alloc(len);
65777
- import_node_fs43.default.readSync(fd, buf, 0, len, w3.lastSize);
66039
+ import_node_fs44.default.readSync(fd, buf, 0, len, w3.lastSize);
65778
66040
  w3.lastSize = size;
65779
66041
  w3.buf += buf.toString("utf8");
65780
66042
  let newlineIndex;
@@ -65797,7 +66059,7 @@ var SessionObserver = class {
65797
66059
  }
65798
66060
  }
65799
66061
  } finally {
65800
- import_node_fs43.default.closeSync(fd);
66062
+ import_node_fs44.default.closeSync(fd);
65801
66063
  }
65802
66064
  if (w3.pendingCwdDerive) this.maybeDeriveCwd(w3);
65803
66065
  }
@@ -65809,7 +66071,7 @@ var SessionObserver = class {
65809
66071
  const now = Date.now();
65810
66072
  if (now - w3.lastRelocateScanMs < 1e3) return;
65811
66073
  w3.lastRelocateScanMs = now;
65812
- const projectsRoot = import_node_path47.default.join(this.home, ".claude", "projects");
66074
+ const projectsRoot = import_node_path48.default.join(this.home, ".claude", "projects");
65813
66075
  const found = findTranscriptByToolSessionId(projectsRoot, w3.toolSessionId);
65814
66076
  if (!found || found === w3.filePath) return;
65815
66077
  try {
@@ -65818,7 +66080,7 @@ var SessionObserver = class {
65818
66080
  }
65819
66081
  w3.filePath = found;
65820
66082
  try {
65821
- w3.watcher = import_node_fs43.default.watch(import_node_path47.default.dirname(found), { persistent: false }, (_event, changedName) => {
66083
+ w3.watcher = import_node_fs44.default.watch(import_node_path48.default.dirname(found), { persistent: false }, (_event, changedName) => {
65822
66084
  if (!changedName || !w3.filePath.endsWith(changedName)) return;
65823
66085
  this.poll(w3);
65824
66086
  });
@@ -65940,9 +66202,9 @@ function listRegistered() {
65940
66202
  // src/tools/title-generator.ts
65941
66203
  var import_node_child_process13 = require("child_process");
65942
66204
  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);
66205
+ var import_node_fs45 = __toESM(require("fs"), 1);
66206
+ var import_node_os18 = __toESM(require("os"), 1);
66207
+ var import_node_path49 = __toESM(require("path"), 1);
65946
66208
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
65947
66209
  var TITLE_MODEL_BY_TOOL = {
65948
66210
  claude: "haiku",
@@ -66013,21 +66275,21 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
66013
66275
  if (!text) return null;
66014
66276
  let workDir;
66015
66277
  try {
66016
- workDir = import_node_fs44.default.mkdtempSync(import_node_path48.default.join(import_node_os17.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
66278
+ workDir = import_node_fs45.default.mkdtempSync(import_node_path49.default.join(import_node_os18.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
66017
66279
  } catch {
66018
66280
  return null;
66019
66281
  }
66020
66282
  const cleanupWorkDir = () => {
66021
66283
  try {
66022
- import_node_fs44.default.rmSync(workDir, { recursive: true, force: true });
66284
+ import_node_fs45.default.rmSync(workDir, { recursive: true, force: true });
66023
66285
  } catch {
66024
66286
  }
66025
66287
  };
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");
66288
+ const outFile = import_node_path49.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
66289
+ const schemaFile = import_node_path49.default.join(workDir, "title-schema.json");
66028
66290
  if (isCodexFamily(tool)) {
66029
66291
  try {
66030
- import_node_fs44.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
66292
+ import_node_fs45.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
66031
66293
  } catch {
66032
66294
  cleanupWorkDir();
66033
66295
  return null;
@@ -66077,7 +66339,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
66077
66339
  if (tool === "claude") return finish(parseTitleJson(stdout));
66078
66340
  let fileText = "";
66079
66341
  try {
66080
- fileText = import_node_fs44.default.readFileSync(outFile, "utf8");
66342
+ fileText = import_node_fs45.default.readFileSync(outFile, "utf8");
66081
66343
  } catch {
66082
66344
  return finish(null);
66083
66345
  }
@@ -66722,8 +66984,8 @@ async function authenticate(token, deps) {
66722
66984
  }
66723
66985
 
66724
66986
  // src/legacy-cleanup.ts
66725
- var fs55 = __toESM(require("fs/promises"), 1);
66726
- var path56 = __toESM(require("path"), 1);
66987
+ var fs56 = __toESM(require("fs/promises"), 1);
66988
+ var path57 = __toESM(require("path"), 1);
66727
66989
  var LEGACY_FILES = [
66728
66990
  "personal-capability.json",
66729
66991
  "received-capabilities.json",
@@ -66732,9 +66994,9 @@ var LEGACY_FILES = [
66732
66994
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
66733
66995
  const removed = [];
66734
66996
  for (const name of LEGACY_FILES) {
66735
- const p3 = path56.join(dataDir, name);
66997
+ const p3 = path57.join(dataDir, name);
66736
66998
  try {
66737
- await fs55.unlink(p3);
66999
+ await fs56.unlink(p3);
66738
67000
  removed.push(name);
66739
67001
  logger.debug("legacy capability file removed", { file: name });
66740
67002
  } catch (err) {
@@ -66746,13 +67008,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
66746
67008
  }
66747
67009
 
66748
67010
  // src/inbox/inbox-store.ts
66749
- var fs56 = __toESM(require("fs"), 1);
66750
- var path57 = __toESM(require("path"), 1);
67011
+ var fs57 = __toESM(require("fs"), 1);
67012
+ var path58 = __toESM(require("path"), 1);
66751
67013
  var INBOX_SUBDIR = "inbox";
66752
67014
  var InboxStore = class {
66753
67015
  constructor(dataDir) {
66754
67016
  this.dataDir = dataDir;
66755
- fs56.mkdirSync(this.dirPath(), { recursive: true });
67017
+ fs57.mkdirSync(this.dirPath(), { recursive: true });
66756
67018
  }
66757
67019
  dataDir;
66758
67020
  /**
@@ -66764,7 +67026,7 @@ var InboxStore = class {
66764
67026
  const file = this.filePath(peerDeviceId);
66765
67027
  let raw;
66766
67028
  try {
66767
- raw = fs56.readFileSync(file, "utf8");
67029
+ raw = fs57.readFileSync(file, "utf8");
66768
67030
  } catch (err) {
66769
67031
  if (err?.code === "ENOENT") return [];
66770
67032
  return [];
@@ -66780,7 +67042,7 @@ var InboxStore = class {
66780
67042
  const dir = this.dirPath();
66781
67043
  let entries;
66782
67044
  try {
66783
- entries = fs56.readdirSync(dir);
67045
+ entries = fs57.readdirSync(dir);
66784
67046
  } catch (err) {
66785
67047
  if (err?.code === "ENOENT") return [];
66786
67048
  return [];
@@ -66796,9 +67058,9 @@ var InboxStore = class {
66796
67058
  if (existing.some((m3) => m3.id === message.id)) return;
66797
67059
  const file = this.filePath(message.peerDeviceId);
66798
67060
  const line = JSON.stringify(message) + "\n";
66799
- fs56.appendFileSync(file, line, { mode: 384 });
67061
+ fs57.appendFileSync(file, line, { mode: 384 });
66800
67062
  try {
66801
- fs56.chmodSync(file, 384);
67063
+ fs57.chmodSync(file, 384);
66802
67064
  } catch {
66803
67065
  }
66804
67066
  }
@@ -66828,7 +67090,7 @@ var InboxStore = class {
66828
67090
  removeByPeerDeviceId(peerDeviceId) {
66829
67091
  const file = this.filePath(peerDeviceId);
66830
67092
  try {
66831
- fs56.unlinkSync(file);
67093
+ fs57.unlinkSync(file);
66832
67094
  } catch (err) {
66833
67095
  if (err?.code === "ENOENT") return;
66834
67096
  }
@@ -66837,18 +67099,18 @@ var InboxStore = class {
66837
67099
  const file = this.filePath(peerDeviceId);
66838
67100
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
66839
67101
  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);
67102
+ fs57.writeFileSync(tmp, content, { mode: 384 });
67103
+ fs57.renameSync(tmp, file);
66842
67104
  try {
66843
- fs56.chmodSync(file, 384);
67105
+ fs57.chmodSync(file, 384);
66844
67106
  } catch {
66845
67107
  }
66846
67108
  }
66847
67109
  dirPath() {
66848
- return path57.join(this.dataDir, INBOX_SUBDIR);
67110
+ return path58.join(this.dataDir, INBOX_SUBDIR);
66849
67111
  }
66850
67112
  filePath(peerDeviceId) {
66851
- return path57.join(this.dirPath(), `${peerDeviceId}.jsonl`);
67113
+ return path58.join(this.dirPath(), `${peerDeviceId}.jsonl`);
66852
67114
  }
66853
67115
  };
66854
67116
  function parseAllLines(raw) {
@@ -66936,8 +67198,8 @@ var InboxManager = class {
66936
67198
  };
66937
67199
 
66938
67200
  // src/state/contact-store.ts
66939
- var fs57 = __toESM(require("fs"), 1);
66940
- var path58 = __toESM(require("path"), 1);
67201
+ var fs58 = __toESM(require("fs"), 1);
67202
+ var path59 = __toESM(require("path"), 1);
66941
67203
  var FILE_NAME = "contacts.json";
66942
67204
  var ContactStore = class {
66943
67205
  constructor(dataDir) {
@@ -66947,10 +67209,10 @@ var ContactStore = class {
66947
67209
  contacts = /* @__PURE__ */ new Map();
66948
67210
  load() {
66949
67211
  this.contacts.clear();
66950
- const file = path58.join(this.dataDir, FILE_NAME);
67212
+ const file = path59.join(this.dataDir, FILE_NAME);
66951
67213
  let raw;
66952
67214
  try {
66953
- raw = fs57.readFileSync(file, "utf8");
67215
+ raw = fs58.readFileSync(file, "utf8");
66954
67216
  } catch (err) {
66955
67217
  if (err?.code !== "ENOENT") this.renameBak(file);
66956
67218
  return;
@@ -67031,20 +67293,20 @@ var ContactStore = class {
67031
67293
  return true;
67032
67294
  }
67033
67295
  flush() {
67034
- const file = path58.join(this.dataDir, FILE_NAME);
67296
+ const file = path59.join(this.dataDir, FILE_NAME);
67035
67297
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
67036
67298
  const content = JSON.stringify(
67037
67299
  { contacts: Array.from(this.contacts.values()) },
67038
67300
  null,
67039
67301
  2
67040
67302
  );
67041
- fs57.mkdirSync(this.dataDir, { recursive: true });
67042
- fs57.writeFileSync(tmp, content, { mode: 384 });
67043
- fs57.renameSync(tmp, file);
67303
+ fs58.mkdirSync(this.dataDir, { recursive: true });
67304
+ fs58.writeFileSync(tmp, content, { mode: 384 });
67305
+ fs58.renameSync(tmp, file);
67044
67306
  }
67045
67307
  renameBak(file) {
67046
67308
  try {
67047
- fs57.renameSync(file, `${file}.bak`);
67309
+ fs58.renameSync(file, `${file}.bak`);
67048
67310
  } catch {
67049
67311
  }
67050
67312
  }
@@ -67152,61 +67414,61 @@ async function connectRemote(args) {
67152
67414
  }
67153
67415
 
67154
67416
  // src/migrations/2026-05-20-flatten-sessions.ts
67155
- var fs58 = __toESM(require("fs"), 1);
67156
- var path59 = __toESM(require("path"), 1);
67417
+ var fs59 = __toESM(require("fs"), 1);
67418
+ var path60 = __toESM(require("path"), 1);
67157
67419
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
67158
67420
  function migrateFlattenSessions(opts) {
67159
67421
  const dataDir = opts.dataDir;
67160
67422
  const now = opts.now ?? Date.now;
67161
- const sessionsDir = path59.join(dataDir, "sessions");
67162
- const flagPath = path59.join(sessionsDir, MIGRATION_FLAG_NAME);
67423
+ const sessionsDir = path60.join(dataDir, "sessions");
67424
+ const flagPath = path60.join(sessionsDir, MIGRATION_FLAG_NAME);
67163
67425
  if (existsSync3(flagPath)) {
67164
67426
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
67165
67427
  }
67166
67428
  let movedBare = 0;
67167
67429
  let movedVmOwner = 0;
67168
67430
  let archivedListener = 0;
67169
- const defaultDir = path59.join(sessionsDir, "default");
67431
+ const defaultDir = path60.join(sessionsDir, "default");
67170
67432
  if (existsSync3(defaultDir)) {
67171
67433
  for (const entry of readdirSafe(defaultDir)) {
67172
67434
  if (!entry.endsWith(".json")) continue;
67173
- const src = path59.join(defaultDir, entry);
67174
- const dst = path59.join(sessionsDir, entry);
67175
- fs58.renameSync(src, dst);
67435
+ const src = path60.join(defaultDir, entry);
67436
+ const dst = path60.join(sessionsDir, entry);
67437
+ fs59.renameSync(src, dst);
67176
67438
  movedBare += 1;
67177
67439
  }
67178
67440
  rmdirIfEmpty(defaultDir);
67179
67441
  }
67180
67442
  for (const pid of readdirSafe(sessionsDir)) {
67181
- const personaDir = path59.join(sessionsDir, pid);
67443
+ const personaDir = path60.join(sessionsDir, pid);
67182
67444
  if (!isDir(personaDir)) continue;
67183
67445
  if (pid === "default") continue;
67184
- const ownerSrc = path59.join(personaDir, "owner");
67446
+ const ownerSrc = path60.join(personaDir, "owner");
67185
67447
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
67186
- const ownerDst = path59.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
67187
- fs58.mkdirSync(ownerDst, { recursive: true });
67448
+ const ownerDst = path60.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
67449
+ fs59.mkdirSync(ownerDst, { recursive: true });
67188
67450
  for (const file of readdirSafe(ownerSrc)) {
67189
67451
  if (!file.endsWith(".json")) continue;
67190
- fs58.renameSync(path59.join(ownerSrc, file), path59.join(ownerDst, file));
67452
+ fs59.renameSync(path60.join(ownerSrc, file), path60.join(ownerDst, file));
67191
67453
  movedVmOwner += 1;
67192
67454
  }
67193
67455
  rmdirIfEmpty(ownerSrc);
67194
67456
  }
67195
- const listenerSrc = path59.join(personaDir, "listener");
67457
+ const listenerSrc = path60.join(personaDir, "listener");
67196
67458
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
67197
- const archiveDst = path59.join(dataDir, ".legacy", `listener-${pid}`);
67198
- fs58.mkdirSync(archiveDst, { recursive: true });
67459
+ const archiveDst = path60.join(dataDir, ".legacy", `listener-${pid}`);
67460
+ fs59.mkdirSync(archiveDst, { recursive: true });
67199
67461
  for (const file of readdirSafe(listenerSrc)) {
67200
67462
  if (!file.endsWith(".json")) continue;
67201
- fs58.renameSync(path59.join(listenerSrc, file), path59.join(archiveDst, file));
67463
+ fs59.renameSync(path60.join(listenerSrc, file), path60.join(archiveDst, file));
67202
67464
  archivedListener += 1;
67203
67465
  }
67204
67466
  rmdirIfEmpty(listenerSrc);
67205
67467
  }
67206
67468
  rmdirIfEmpty(personaDir);
67207
67469
  }
67208
- fs58.mkdirSync(sessionsDir, { recursive: true });
67209
- fs58.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
67470
+ fs59.mkdirSync(sessionsDir, { recursive: true });
67471
+ fs59.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
67210
67472
  return {
67211
67473
  skipped: false,
67212
67474
  flagWritten: true,
@@ -67217,7 +67479,7 @@ function migrateFlattenSessions(opts) {
67217
67479
  }
67218
67480
  function existsSync3(p3) {
67219
67481
  try {
67220
- fs58.statSync(p3);
67482
+ fs59.statSync(p3);
67221
67483
  return true;
67222
67484
  } catch {
67223
67485
  return false;
@@ -67225,62 +67487,62 @@ function existsSync3(p3) {
67225
67487
  }
67226
67488
  function isDir(p3) {
67227
67489
  try {
67228
- return fs58.statSync(p3).isDirectory();
67490
+ return fs59.statSync(p3).isDirectory();
67229
67491
  } catch {
67230
67492
  return false;
67231
67493
  }
67232
67494
  }
67233
67495
  function readdirSafe(p3) {
67234
67496
  try {
67235
- return fs58.readdirSync(p3);
67497
+ return fs59.readdirSync(p3);
67236
67498
  } catch {
67237
67499
  return [];
67238
67500
  }
67239
67501
  }
67240
67502
  function rmdirIfEmpty(p3) {
67241
67503
  try {
67242
- fs58.rmdirSync(p3);
67504
+ fs59.rmdirSync(p3);
67243
67505
  } catch {
67244
67506
  }
67245
67507
  }
67246
67508
 
67247
67509
  // src/migrations/2026-08-18-drop-seeded-projects.ts
67248
- var fs59 = __toESM(require("fs"), 1);
67249
- var path60 = __toESM(require("path"), 1);
67510
+ var fs60 = __toESM(require("fs"), 1);
67511
+ var path61 = __toESM(require("path"), 1);
67250
67512
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
67251
67513
  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");
67514
+ fs60.mkdirSync(opts.dataDir, { recursive: true });
67515
+ const flag = path61.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
67516
+ if (fs60.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
67517
+ const file = path61.join(opts.dataDir, "projects.json");
67256
67518
  let raw = null;
67257
67519
  let dropped = 0;
67258
67520
  try {
67259
- raw = fs59.readFileSync(file, "utf8");
67521
+ raw = fs60.readFileSync(file, "utf8");
67260
67522
  dropped = JSON.parse(raw).projects?.length ?? 0;
67261
67523
  } catch {
67262
67524
  }
67263
67525
  let backup = null;
67264
67526
  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);
67527
+ const dir = path61.join(opts.dataDir, "backups");
67528
+ fs60.mkdirSync(dir, { recursive: true });
67529
+ backup = path61.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
67530
+ fs60.writeFileSync(backup, raw);
67269
67531
  }
67270
67532
  if (raw != null || dropped > 0) {
67271
- fs59.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
67533
+ fs60.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
67272
67534
  }
67273
- fs59.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
67535
+ fs60.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
67274
67536
  return { skipped: false, dropped, backup };
67275
67537
  }
67276
67538
 
67277
67539
  // src/transport/http-router.ts
67278
- var import_node_fs46 = __toESM(require("fs"), 1);
67279
- var import_node_path51 = __toESM(require("path"), 1);
67540
+ var import_node_fs47 = __toESM(require("fs"), 1);
67541
+ var import_node_path52 = __toESM(require("path"), 1);
67280
67542
 
67281
67543
  // src/attachment/upload.ts
67282
- var import_node_fs45 = __toESM(require("fs"), 1);
67283
- var import_node_path49 = __toESM(require("path"), 1);
67544
+ var import_node_fs46 = __toESM(require("fs"), 1);
67545
+ var import_node_path50 = __toESM(require("path"), 1);
67284
67546
  var import_node_crypto15 = __toESM(require("crypto"), 1);
67285
67547
  var import_promises8 = require("stream/promises");
67286
67548
  var UploadError = class extends Error {
@@ -67292,22 +67554,22 @@ var UploadError = class extends Error {
67292
67554
  code;
67293
67555
  };
67294
67556
  function assertValidFileName(fileName) {
67295
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path49.default.basename(fileName)) {
67557
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path50.default.basename(fileName)) {
67296
67558
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
67297
67559
  }
67298
67560
  }
67299
67561
  var HASH_PREFIX_LEN = 16;
67300
67562
  async function writeUploadedAttachment(args) {
67301
67563
  assertValidFileName(args.fileName);
67302
- const attachmentsRoot = import_node_path49.default.join(args.baseDir, ".attachments");
67564
+ const attachmentsRoot = import_node_path50.default.join(args.baseDir, ".attachments");
67303
67565
  try {
67304
- import_node_fs45.default.mkdirSync(attachmentsRoot, { recursive: true });
67566
+ import_node_fs46.default.mkdirSync(attachmentsRoot, { recursive: true });
67305
67567
  } catch (err) {
67306
67568
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
67307
67569
  }
67308
67570
  const hasher = import_node_crypto15.default.createHash("sha256");
67309
67571
  let actualSize = 0;
67310
- const tmpPath = import_node_path49.default.join(
67572
+ const tmpPath = import_node_path50.default.join(
67311
67573
  attachmentsRoot,
67312
67574
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto15.default.randomBytes(4).toString("hex")}`
67313
67575
  );
@@ -67322,18 +67584,18 @@ async function writeUploadedAttachment(args) {
67322
67584
  yield buf;
67323
67585
  }
67324
67586
  },
67325
- import_node_fs45.default.createWriteStream(tmpPath, { mode: 384 })
67587
+ import_node_fs46.default.createWriteStream(tmpPath, { mode: 384 })
67326
67588
  );
67327
67589
  } catch (err) {
67328
67590
  try {
67329
- import_node_fs45.default.unlinkSync(tmpPath);
67591
+ import_node_fs46.default.unlinkSync(tmpPath);
67330
67592
  } catch {
67331
67593
  }
67332
67594
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
67333
67595
  }
67334
67596
  if (actualSize !== args.contentLength) {
67335
67597
  try {
67336
- import_node_fs45.default.unlinkSync(tmpPath);
67598
+ import_node_fs46.default.unlinkSync(tmpPath);
67337
67599
  } catch {
67338
67600
  }
67339
67601
  throw new UploadError(
@@ -67342,34 +67604,34 @@ async function writeUploadedAttachment(args) {
67342
67604
  );
67343
67605
  }
67344
67606
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
67345
- const hashDir = import_node_path49.default.join(attachmentsRoot, attachmentId);
67607
+ const hashDir = import_node_path50.default.join(attachmentsRoot, attachmentId);
67346
67608
  let finalFileName;
67347
67609
  let hashDirExists = false;
67348
67610
  try {
67349
- hashDirExists = import_node_fs45.default.statSync(hashDir).isDirectory();
67611
+ hashDirExists = import_node_fs46.default.statSync(hashDir).isDirectory();
67350
67612
  } catch {
67351
67613
  }
67352
67614
  if (hashDirExists) {
67353
- const existing = import_node_fs45.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
67615
+ const existing = import_node_fs46.default.readdirSync(hashDir).filter((n2) => !n2.startsWith("."));
67354
67616
  finalFileName = existing[0] ?? args.fileName;
67355
67617
  try {
67356
- import_node_fs45.default.unlinkSync(tmpPath);
67618
+ import_node_fs46.default.unlinkSync(tmpPath);
67357
67619
  } catch {
67358
67620
  }
67359
67621
  } else {
67360
67622
  try {
67361
- import_node_fs45.default.mkdirSync(hashDir, { recursive: true });
67623
+ import_node_fs46.default.mkdirSync(hashDir, { recursive: true });
67362
67624
  finalFileName = args.fileName;
67363
- import_node_fs45.default.renameSync(tmpPath, import_node_path49.default.join(hashDir, finalFileName));
67625
+ import_node_fs46.default.renameSync(tmpPath, import_node_path50.default.join(hashDir, finalFileName));
67364
67626
  } catch (err) {
67365
67627
  try {
67366
- import_node_fs45.default.unlinkSync(tmpPath);
67628
+ import_node_fs46.default.unlinkSync(tmpPath);
67367
67629
  } catch {
67368
67630
  }
67369
67631
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
67370
67632
  }
67371
67633
  }
67372
- const absPath = import_node_path49.default.join(hashDir, finalFileName);
67634
+ const absPath = import_node_path50.default.join(hashDir, finalFileName);
67373
67635
  const relPath = absPath;
67374
67636
  args.groupFileStore.upsert(args.scope, args.sessionId, {
67375
67637
  relPath: absPath,
@@ -67384,8 +67646,8 @@ async function writeUploadedAttachment(args) {
67384
67646
 
67385
67647
  // src/extension/import.ts
67386
67648
  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);
67649
+ var import_node_path51 = __toESM(require("path"), 1);
67650
+ var import_node_os19 = __toESM(require("os"), 1);
67389
67651
  var import_jszip = __toESM(require_lib3(), 1);
67390
67652
  var ImportError = class extends Error {
67391
67653
  constructor(code, message) {
@@ -67402,7 +67664,7 @@ async function importZip(buf, root) {
67402
67664
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
67403
67665
  }
67404
67666
  for (const name of Object.keys(zip.files)) {
67405
- if (name.includes("..") || name.startsWith("/") || import_node_path50.default.isAbsolute(name)) {
67667
+ if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
67406
67668
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
67407
67669
  }
67408
67670
  }
@@ -67435,7 +67697,7 @@ async function importZip(buf, root) {
67435
67697
  );
67436
67698
  }
67437
67699
  }
67438
- const destDir = import_node_path50.default.join(root, manifest.id);
67700
+ const destDir = import_node_path51.default.join(root, manifest.id);
67439
67701
  let destExists = false;
67440
67702
  try {
67441
67703
  await import_promises9.default.access(destDir);
@@ -67445,15 +67707,15 @@ async function importZip(buf, root) {
67445
67707
  if (destExists) {
67446
67708
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
67447
67709
  }
67448
- const stage = await import_promises9.default.mkdtemp(import_node_path50.default.join(import_node_os18.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
67710
+ const stage = await import_promises9.default.mkdtemp(import_node_path51.default.join(import_node_os19.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
67449
67711
  try {
67450
67712
  for (const [name, entry] of Object.entries(zip.files)) {
67451
- const dest = import_node_path50.default.join(stage, name);
67713
+ const dest = import_node_path51.default.join(stage, name);
67452
67714
  if (entry.dir) {
67453
67715
  await import_promises9.default.mkdir(dest, { recursive: true });
67454
67716
  continue;
67455
67717
  }
67456
- await import_promises9.default.mkdir(import_node_path50.default.dirname(dest), { recursive: true });
67718
+ await import_promises9.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
67457
67719
  const content = await entry.async("nodebuffer");
67458
67720
  await import_promises9.default.writeFile(dest, content);
67459
67721
  }
@@ -67507,7 +67769,7 @@ var SHARE_UI_ASSET_MIME = {
67507
67769
  ".wasm": "application/wasm"
67508
67770
  };
67509
67771
  function shareUiAssetMime(filePath) {
67510
- const ext = import_node_path51.default.extname(filePath).toLowerCase();
67772
+ const ext = import_node_path52.default.extname(filePath).toLowerCase();
67511
67773
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
67512
67774
  }
67513
67775
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -67606,7 +67868,7 @@ function isValidUploadFileName(fileName) {
67606
67868
  if (fileName === "." || fileName === "..") return false;
67607
67869
  if (fileName.startsWith(".")) return false;
67608
67870
  if (fileName.includes("/") || fileName.includes("\\")) return false;
67609
- return fileName === import_node_path51.default.basename(fileName);
67871
+ return fileName === import_node_path52.default.basename(fileName);
67610
67872
  }
67611
67873
  function createHttpRouter(deps) {
67612
67874
  return async (req, res) => {
@@ -67690,7 +67952,7 @@ function createHttpRouter(deps) {
67690
67952
  }
67691
67953
  let buf;
67692
67954
  try {
67693
- buf = await import_node_fs46.default.promises.readFile(abs);
67955
+ buf = await import_node_fs47.default.promises.readFile(abs);
67694
67956
  } catch {
67695
67957
  sendJson2(res, 404, { code: "NOT_FOUND", message: "asset not found" });
67696
67958
  return true;
@@ -67836,7 +68098,7 @@ function createHttpRouter(deps) {
67836
68098
  sendHtml(res, statusByCode[r2.code], loader.renderErrorHtml(r2.code, msgByCode[r2.code]));
67837
68099
  return true;
67838
68100
  }
67839
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path51.default.basename(r2.absPath)));
68101
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path52.default.basename(r2.absPath)));
67840
68102
  return true;
67841
68103
  }
67842
68104
  const ctx = deps.authResolver.resolveFromHeader(
@@ -67957,7 +68219,7 @@ function createHttpRouter(deps) {
67957
68219
  return true;
67958
68220
  }
67959
68221
  let absPath;
67960
- if (import_node_path51.default.isAbsolute(pathParam)) {
68222
+ if (import_node_path52.default.isAbsolute(pathParam)) {
67961
68223
  absPath = pathParam;
67962
68224
  } else if (deps.sessionStore) {
67963
68225
  const file = deps.sessionStore.read(sid);
@@ -67965,7 +68227,7 @@ function createHttpRouter(deps) {
67965
68227
  sendJson2(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
67966
68228
  return true;
67967
68229
  }
67968
- absPath = import_node_path51.default.join(file.cwd, pathParam);
68230
+ absPath = import_node_path52.default.join(file.cwd, pathParam);
67969
68231
  } else {
67970
68232
  sendJson2(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
67971
68233
  return true;
@@ -68049,7 +68311,7 @@ function withCtx(ctx, body) {
68049
68311
  function streamFile(res, absPath, logger) {
68050
68312
  let stat;
68051
68313
  try {
68052
- stat = import_node_fs46.default.statSync(absPath);
68314
+ stat = import_node_fs47.default.statSync(absPath);
68053
68315
  } catch (err) {
68054
68316
  const code = err?.code;
68055
68317
  if (code === "ENOENT") {
@@ -68064,7 +68326,7 @@ function streamFile(res, absPath, logger) {
68064
68326
  return;
68065
68327
  }
68066
68328
  const mime = lookupMime(absPath);
68067
- const basename2 = import_node_path51.default.basename(absPath);
68329
+ const basename2 = import_node_path52.default.basename(absPath);
68068
68330
  res.writeHead(200, {
68069
68331
  "Content-Type": mime,
68070
68332
  "Content-Length": String(stat.size),
@@ -68072,7 +68334,7 @@ function streamFile(res, absPath, logger) {
68072
68334
  // 防止浏览器把任意 mime 当 html 渲染
68073
68335
  "X-Content-Type-Options": "nosniff"
68074
68336
  });
68075
- const stream = import_node_fs46.default.createReadStream(absPath);
68337
+ const stream = import_node_fs47.default.createReadStream(absPath);
68076
68338
  stream.on("error", (err) => {
68077
68339
  logger?.warn("streamFile read error", { absPath, err: err.message });
68078
68340
  res.destroy();
@@ -68081,8 +68343,8 @@ function streamFile(res, absPath, logger) {
68081
68343
  }
68082
68344
 
68083
68345
  // src/attachment/gc.ts
68084
- var import_node_fs47 = __toESM(require("fs"), 1);
68085
- var import_node_path52 = __toESM(require("path"), 1);
68346
+ var import_node_fs48 = __toESM(require("fs"), 1);
68347
+ var import_node_path53 = __toESM(require("path"), 1);
68086
68348
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
68087
68349
  function runAttachmentGc(args) {
68088
68350
  const now = (args.now ?? Date.now)();
@@ -68091,12 +68353,12 @@ function runAttachmentGc(args) {
68091
68353
  for (const { scope, sessionId } of args.sessionScopes) {
68092
68354
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
68093
68355
  if (entry.stale) continue;
68094
- if (import_node_path52.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
68356
+ if (import_node_path53.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
68095
68357
  }
68096
68358
  }
68097
68359
  const visited = /* @__PURE__ */ new Set();
68098
68360
  for (const { scope, sessionId } of args.sessionScopes) {
68099
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path52.default.join(
68361
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path53.default.join(
68100
68362
  args.dataDir,
68101
68363
  "sessions",
68102
68364
  ...scopeSubPath(scope).map(safeFileName),
@@ -68109,28 +68371,28 @@ function runAttachmentGc(args) {
68109
68371
  return true;
68110
68372
  });
68111
68373
  for (const rootDir of roots) {
68112
- const attRoot = import_node_path52.default.join(rootDir, ".attachments");
68374
+ const attRoot = import_node_path53.default.join(rootDir, ".attachments");
68113
68375
  let hashDirs;
68114
68376
  try {
68115
- hashDirs = import_node_fs47.default.readdirSync(attRoot);
68377
+ hashDirs = import_node_fs48.default.readdirSync(attRoot);
68116
68378
  } catch (err) {
68117
68379
  if (err.code === "ENOENT") continue;
68118
68380
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
68119
68381
  continue;
68120
68382
  }
68121
68383
  for (const hashDir of hashDirs) {
68122
- const hashDirAbs = import_node_path52.default.join(attRoot, hashDir);
68384
+ const hashDirAbs = import_node_path53.default.join(attRoot, hashDir);
68123
68385
  let files;
68124
68386
  try {
68125
- files = import_node_fs47.default.readdirSync(hashDirAbs);
68387
+ files = import_node_fs48.default.readdirSync(hashDirAbs);
68126
68388
  } catch {
68127
68389
  continue;
68128
68390
  }
68129
68391
  for (const name of files) {
68130
- const file = import_node_path52.default.join(hashDirAbs, name);
68392
+ const file = import_node_path53.default.join(hashDirAbs, name);
68131
68393
  let stat;
68132
68394
  try {
68133
- stat = import_node_fs47.default.statSync(file);
68395
+ stat = import_node_fs48.default.statSync(file);
68134
68396
  } catch {
68135
68397
  continue;
68136
68398
  }
@@ -68139,18 +68401,18 @@ function runAttachmentGc(args) {
68139
68401
  if (age < ttlMs) continue;
68140
68402
  if (liveAbs.has(file)) continue;
68141
68403
  try {
68142
- import_node_fs47.default.unlinkSync(file);
68404
+ import_node_fs48.default.unlinkSync(file);
68143
68405
  } catch (err) {
68144
68406
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
68145
68407
  }
68146
68408
  }
68147
68409
  try {
68148
- if (import_node_fs47.default.readdirSync(hashDirAbs).length === 0) import_node_fs47.default.rmdirSync(hashDirAbs);
68410
+ if (import_node_fs48.default.readdirSync(hashDirAbs).length === 0) import_node_fs48.default.rmdirSync(hashDirAbs);
68149
68411
  } catch {
68150
68412
  }
68151
68413
  }
68152
68414
  try {
68153
- if (import_node_fs47.default.readdirSync(attRoot).length === 0) import_node_fs47.default.rmdirSync(attRoot);
68415
+ if (import_node_fs48.default.readdirSync(attRoot).length === 0) import_node_fs48.default.rmdirSync(attRoot);
68154
68416
  } catch {
68155
68417
  }
68156
68418
  }
@@ -68158,8 +68420,8 @@ function runAttachmentGc(args) {
68158
68420
  }
68159
68421
 
68160
68422
  // src/attachment/group.ts
68161
- var import_node_fs48 = __toESM(require("fs"), 1);
68162
- var import_node_path53 = __toESM(require("path"), 1);
68423
+ var import_node_fs49 = __toESM(require("fs"), 1);
68424
+ var import_node_path54 = __toESM(require("path"), 1);
68163
68425
  var import_node_crypto16 = __toESM(require("crypto"), 1);
68164
68426
  init_protocol();
68165
68427
  var GroupFileStore = class {
@@ -68171,11 +68433,11 @@ var GroupFileStore = class {
68171
68433
  this.logger = opts.logger;
68172
68434
  }
68173
68435
  rootForScope(scope) {
68174
- return import_node_path53.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
68436
+ return import_node_path54.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
68175
68437
  }
68176
68438
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
68177
68439
  filePath(scope, sessionId) {
68178
- return import_node_path53.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
68440
+ return import_node_path54.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
68179
68441
  }
68180
68442
  cacheKey(scope, sessionId) {
68181
68443
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -68184,7 +68446,7 @@ var GroupFileStore = class {
68184
68446
  readFile(scope, sessionId) {
68185
68447
  const file = this.filePath(scope, sessionId);
68186
68448
  try {
68187
- const raw = import_node_fs48.default.readFileSync(file, "utf8");
68449
+ const raw = import_node_fs49.default.readFileSync(file, "utf8");
68188
68450
  const parsed = JSON.parse(raw);
68189
68451
  if (!Array.isArray(parsed)) {
68190
68452
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -68210,10 +68472,10 @@ var GroupFileStore = class {
68210
68472
  }
68211
68473
  writeFile(scope, sessionId, entries) {
68212
68474
  const file = this.filePath(scope, sessionId);
68213
- import_node_fs48.default.mkdirSync(import_node_path53.default.dirname(file), { recursive: true });
68475
+ import_node_fs49.default.mkdirSync(import_node_path54.default.dirname(file), { recursive: true });
68214
68476
  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);
68477
+ import_node_fs49.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
68478
+ import_node_fs49.default.renameSync(tmp, file);
68217
68479
  }
68218
68480
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
68219
68481
  list(scope, sessionId) {
@@ -68305,7 +68567,7 @@ var GroupFileStore = class {
68305
68567
  */
68306
68568
  deleteSession(scope, sessionId) {
68307
68569
  try {
68308
- import_node_fs48.default.unlinkSync(this.filePath(scope, sessionId));
68570
+ import_node_fs49.default.unlinkSync(this.filePath(scope, sessionId));
68309
68571
  } catch (err) {
68310
68572
  if (err?.code !== "ENOENT") throw err;
68311
68573
  }
@@ -68318,7 +68580,7 @@ var GroupFileStore = class {
68318
68580
  * 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
68319
68581
  */
68320
68582
  deletePersona(personaId2) {
68321
- import_node_fs48.default.rmSync(import_node_path53.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
68583
+ import_node_fs49.default.rmSync(import_node_path54.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
68322
68584
  const prefix = `persona:${personaId2}:`;
68323
68585
  for (const key of this.cache.keys()) {
68324
68586
  if (key.startsWith(prefix)) this.cache.delete(key);
@@ -68327,10 +68589,10 @@ var GroupFileStore = class {
68327
68589
  };
68328
68590
 
68329
68591
  // src/discovery/state-file.ts
68330
- var import_node_fs49 = __toESM(require("fs"), 1);
68331
- var import_node_path54 = __toESM(require("path"), 1);
68592
+ var import_node_fs50 = __toESM(require("fs"), 1);
68593
+ var import_node_path55 = __toESM(require("path"), 1);
68332
68594
  function defaultStateFilePath(dataDir) {
68333
- return import_node_path54.default.join(dataDir, "state.json");
68595
+ return import_node_path55.default.join(dataDir, "state.json");
68334
68596
  }
68335
68597
  function isPidAlive(pid) {
68336
68598
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -68352,7 +68614,7 @@ var StateFileManager = class {
68352
68614
  }
68353
68615
  read() {
68354
68616
  try {
68355
- const raw = import_node_fs49.default.readFileSync(this.file, "utf8");
68617
+ const raw = import_node_fs50.default.readFileSync(this.file, "utf8");
68356
68618
  const parsed = JSON.parse(raw);
68357
68619
  return parsed;
68358
68620
  } catch {
@@ -68366,20 +68628,20 @@ var StateFileManager = class {
68366
68628
  return { status: "stale", existing };
68367
68629
  }
68368
68630
  write(state) {
68369
- import_node_fs49.default.mkdirSync(import_node_path54.default.dirname(this.file), { recursive: true });
68631
+ import_node_fs50.default.mkdirSync(import_node_path55.default.dirname(this.file), { recursive: true });
68370
68632
  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);
68633
+ import_node_fs50.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
68634
+ import_node_fs50.default.renameSync(tmp, this.file);
68373
68635
  if (process.platform !== "win32") {
68374
68636
  try {
68375
- import_node_fs49.default.chmodSync(this.file, 384);
68637
+ import_node_fs50.default.chmodSync(this.file, 384);
68376
68638
  } catch {
68377
68639
  }
68378
68640
  }
68379
68641
  }
68380
68642
  delete() {
68381
68643
  try {
68382
- import_node_fs49.default.unlinkSync(this.file);
68644
+ import_node_fs50.default.unlinkSync(this.file);
68383
68645
  } catch {
68384
68646
  }
68385
68647
  }
@@ -68393,14 +68655,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
68393
68655
  }
68394
68656
 
68395
68657
  // src/tunnel/tunnel-manager.ts
68396
- var import_node_fs53 = __toESM(require("fs"), 1);
68397
- var import_node_path58 = __toESM(require("path"), 1);
68658
+ var import_node_fs54 = __toESM(require("fs"), 1);
68659
+ var import_node_path59 = __toESM(require("path"), 1);
68398
68660
  var import_node_crypto17 = __toESM(require("crypto"), 1);
68399
68661
  var import_node_child_process16 = require("child_process");
68400
68662
 
68401
68663
  // src/tunnel/tunnel-store.ts
68402
- var import_node_fs50 = __toESM(require("fs"), 1);
68403
- var import_node_path55 = __toESM(require("path"), 1);
68664
+ var import_node_fs51 = __toESM(require("fs"), 1);
68665
+ var import_node_path56 = __toESM(require("path"), 1);
68404
68666
  var TunnelStore = class {
68405
68667
  constructor(filePath) {
68406
68668
  this.filePath = filePath;
@@ -68408,7 +68670,7 @@ var TunnelStore = class {
68408
68670
  filePath;
68409
68671
  async get() {
68410
68672
  try {
68411
- const raw = await import_node_fs50.default.promises.readFile(this.filePath, "utf8");
68673
+ const raw = await import_node_fs51.default.promises.readFile(this.filePath, "utf8");
68412
68674
  const obj = JSON.parse(raw);
68413
68675
  if (!isPersistedTunnel(obj)) return null;
68414
68676
  return obj;
@@ -68419,22 +68681,22 @@ var TunnelStore = class {
68419
68681
  }
68420
68682
  }
68421
68683
  async set(v3) {
68422
- const dir = import_node_path55.default.dirname(this.filePath);
68423
- await import_node_fs50.default.promises.mkdir(dir, { recursive: true });
68684
+ const dir = import_node_path56.default.dirname(this.filePath);
68685
+ await import_node_fs51.default.promises.mkdir(dir, { recursive: true });
68424
68686
  const data = JSON.stringify(v3, null, 2);
68425
68687
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
68426
- await import_node_fs50.default.promises.writeFile(tmp, data, { mode: 384 });
68688
+ await import_node_fs51.default.promises.writeFile(tmp, data, { mode: 384 });
68427
68689
  if (process.platform !== "win32") {
68428
68690
  try {
68429
- await import_node_fs50.default.promises.chmod(tmp, 384);
68691
+ await import_node_fs51.default.promises.chmod(tmp, 384);
68430
68692
  } catch {
68431
68693
  }
68432
68694
  }
68433
- await import_node_fs50.default.promises.rename(tmp, this.filePath);
68695
+ await import_node_fs51.default.promises.rename(tmp, this.filePath);
68434
68696
  }
68435
68697
  async clear() {
68436
68698
  try {
68437
- await import_node_fs50.default.promises.unlink(this.filePath);
68699
+ await import_node_fs51.default.promises.unlink(this.filePath);
68438
68700
  } catch (err) {
68439
68701
  const code = err?.code;
68440
68702
  if (code !== "ENOENT") throw err;
@@ -68529,9 +68791,9 @@ function escape2(v3) {
68529
68791
  }
68530
68792
 
68531
68793
  // 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);
68794
+ var import_node_fs52 = __toESM(require("fs"), 1);
68795
+ var import_node_os20 = __toESM(require("os"), 1);
68796
+ var import_node_path57 = __toESM(require("path"), 1);
68535
68797
  var import_node_child_process14 = require("child_process");
68536
68798
  var import_node_stream4 = require("stream");
68537
68799
  var import_promises10 = require("stream/promises");
@@ -68563,20 +68825,20 @@ function frpcDownloadUrl(version2, p3) {
68563
68825
  }
68564
68826
  async function ensureFrpcBinary(opts) {
68565
68827
  if (opts.override) {
68566
- if (!import_node_fs51.default.existsSync(opts.override)) {
68828
+ if (!import_node_fs52.default.existsSync(opts.override)) {
68567
68829
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
68568
68830
  }
68569
68831
  return opts.override;
68570
68832
  }
68571
68833
  const version2 = opts.version ?? FRPC_VERSION;
68572
68834
  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 });
68835
+ const binDir = import_node_path57.default.join(opts.dataDir, "bin");
68836
+ import_node_fs52.default.mkdirSync(binDir, { recursive: true });
68575
68837
  cleanupStaleArtifacts(binDir);
68576
- const stableBin = import_node_path56.default.join(binDir, "frpc");
68577
- if (import_node_fs51.default.existsSync(stableBin)) return stableBin;
68838
+ const stableBin = import_node_path57.default.join(binDir, "frpc");
68839
+ if (import_node_fs52.default.existsSync(stableBin)) return stableBin;
68578
68840
  const partialBin = `${stableBin}.partial`;
68579
- const tarballPath = import_node_path56.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
68841
+ const tarballPath = import_node_path57.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
68580
68842
  try {
68581
68843
  const url = frpcDownloadUrl(version2, platform);
68582
68844
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -68585,8 +68847,8 @@ async function ensureFrpcBinary(opts) {
68585
68847
  } else {
68586
68848
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
68587
68849
  }
68588
- import_node_fs51.default.chmodSync(partialBin, 493);
68589
- import_node_fs51.default.renameSync(partialBin, stableBin);
68850
+ import_node_fs52.default.chmodSync(partialBin, 493);
68851
+ import_node_fs52.default.renameSync(partialBin, stableBin);
68590
68852
  } finally {
68591
68853
  safeUnlink(tarballPath);
68592
68854
  safeUnlink(partialBin);
@@ -68596,15 +68858,15 @@ async function ensureFrpcBinary(opts) {
68596
68858
  function cleanupStaleArtifacts(binDir) {
68597
68859
  let entries;
68598
68860
  try {
68599
- entries = import_node_fs51.default.readdirSync(binDir);
68861
+ entries = import_node_fs52.default.readdirSync(binDir);
68600
68862
  } catch {
68601
68863
  return;
68602
68864
  }
68603
68865
  for (const name of entries) {
68604
68866
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
68605
- const full = import_node_path56.default.join(binDir, name);
68867
+ const full = import_node_path57.default.join(binDir, name);
68606
68868
  try {
68607
- import_node_fs51.default.rmSync(full, { recursive: true, force: true });
68869
+ import_node_fs52.default.rmSync(full, { recursive: true, force: true });
68608
68870
  } catch {
68609
68871
  }
68610
68872
  }
@@ -68612,7 +68874,7 @@ function cleanupStaleArtifacts(binDir) {
68612
68874
  }
68613
68875
  function safeUnlink(p3) {
68614
68876
  try {
68615
- import_node_fs51.default.unlinkSync(p3);
68877
+ import_node_fs52.default.unlinkSync(p3);
68616
68878
  } catch {
68617
68879
  }
68618
68880
  }
@@ -68623,13 +68885,13 @@ async function downloadToFile(url, dest, fetchImpl) {
68623
68885
  if (!res.ok || !res.body) {
68624
68886
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
68625
68887
  }
68626
- const out = import_node_fs51.default.createWriteStream(dest);
68888
+ const out = import_node_fs52.default.createWriteStream(dest);
68627
68889
  const nodeStream = import_node_stream4.Readable.fromWeb(res.body);
68628
68890
  await (0, import_promises10.pipeline)(nodeStream, out);
68629
68891
  }
68630
68892
  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 });
68893
+ const work = import_node_path57.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
68894
+ import_node_fs52.default.mkdirSync(work, { recursive: true });
68633
68895
  try {
68634
68896
  await new Promise((resolve9, reject) => {
68635
68897
  const proc = (0, import_node_child_process14.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -68637,32 +68899,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
68637
68899
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
68638
68900
  });
68639
68901
  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)) {
68902
+ const src = import_node_path57.default.join(work, dirName, "frpc");
68903
+ if (!import_node_fs52.default.existsSync(src)) {
68642
68904
  throw new Error(`frpc not found inside tarball at ${src}`);
68643
68905
  }
68644
- import_node_fs51.default.copyFileSync(src, destBin);
68906
+ import_node_fs52.default.copyFileSync(src, destBin);
68645
68907
  } finally {
68646
- import_node_fs51.default.rmSync(work, { recursive: true, force: true });
68908
+ import_node_fs52.default.rmSync(work, { recursive: true, force: true });
68647
68909
  }
68648
68910
  }
68649
68911
 
68650
68912
  // src/tunnel/frpc-process.ts
68651
- var import_node_fs52 = __toESM(require("fs"), 1);
68652
- var import_node_path57 = __toESM(require("path"), 1);
68913
+ var import_node_fs53 = __toESM(require("fs"), 1);
68914
+ var import_node_path58 = __toESM(require("path"), 1);
68653
68915
  var import_node_child_process15 = require("child_process");
68654
68916
  function frpcPidFilePath(dataDir) {
68655
- return import_node_path57.default.join(dataDir, "frpc.pid");
68917
+ return import_node_path58.default.join(dataDir, "frpc.pid");
68656
68918
  }
68657
68919
  function writeFrpcPid(dataDir, pid) {
68658
68920
  try {
68659
- import_node_fs52.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
68921
+ import_node_fs53.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
68660
68922
  } catch {
68661
68923
  }
68662
68924
  }
68663
68925
  function clearFrpcPid(dataDir) {
68664
68926
  try {
68665
- import_node_fs52.default.unlinkSync(frpcPidFilePath(dataDir));
68927
+ import_node_fs53.default.unlinkSync(frpcPidFilePath(dataDir));
68666
68928
  } catch {
68667
68929
  }
68668
68930
  }
@@ -68678,7 +68940,7 @@ function defaultIsPidAlive(pid) {
68678
68940
  }
68679
68941
  function defaultReadPidFile(file) {
68680
68942
  try {
68681
- return import_node_fs52.default.readFileSync(file, "utf8");
68943
+ return import_node_fs53.default.readFileSync(file, "utf8");
68682
68944
  } catch {
68683
68945
  return null;
68684
68946
  }
@@ -68694,7 +68956,7 @@ function defaultSleep2(ms) {
68694
68956
  }
68695
68957
  async function killStaleFrpc(deps) {
68696
68958
  const pidFile = frpcPidFilePath(deps.dataDir);
68697
- const tomlPath = import_node_path57.default.join(deps.dataDir, "frpc.toml");
68959
+ const tomlPath = import_node_path58.default.join(deps.dataDir, "frpc.toml");
68698
68960
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
68699
68961
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
68700
68962
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -68718,7 +68980,7 @@ async function killStaleFrpc(deps) {
68718
68980
  }
68719
68981
  if (victims.size === 0) {
68720
68982
  try {
68721
- import_node_fs52.default.unlinkSync(pidFile);
68983
+ import_node_fs53.default.unlinkSync(pidFile);
68722
68984
  } catch {
68723
68985
  }
68724
68986
  return;
@@ -68729,7 +68991,7 @@ async function killStaleFrpc(deps) {
68729
68991
  }
68730
68992
  await sleep2(deps.reapWaitMs ?? 300);
68731
68993
  try {
68732
- import_node_fs52.default.unlinkSync(pidFile);
68994
+ import_node_fs53.default.unlinkSync(pidFile);
68733
68995
  } catch {
68734
68996
  }
68735
68997
  }
@@ -68766,7 +69028,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
68766
69028
  var TunnelManager = class {
68767
69029
  constructor(deps) {
68768
69030
  this.deps = deps;
68769
- this.store = deps.store ?? new TunnelStore(import_node_path58.default.join(deps.dataDir, "tunnel.json"));
69031
+ this.store = deps.store ?? new TunnelStore(import_node_path59.default.join(deps.dataDir, "tunnel.json"));
68770
69032
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
68771
69033
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
68772
69034
  }
@@ -68893,7 +69155,7 @@ var TunnelManager = class {
68893
69155
  dataDir: this.deps.dataDir,
68894
69156
  override: this.deps.frpcBinaryOverride ?? void 0
68895
69157
  });
68896
- const tomlPath = import_node_path58.default.join(this.deps.dataDir, "frpc.toml");
69158
+ const tomlPath = import_node_path59.default.join(this.deps.dataDir, "frpc.toml");
68897
69159
  const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto17.default.randomBytes(3).toString("hex")}`;
68898
69160
  const toml = buildFrpcToml({
68899
69161
  serverAddr: t2.frpsHost,
@@ -68904,14 +69166,14 @@ var TunnelManager = class {
68904
69166
  localPort,
68905
69167
  logLevel: "info"
68906
69168
  });
68907
- await import_node_fs53.default.promises.writeFile(tomlPath, toml, { mode: 384 });
69169
+ await import_node_fs54.default.promises.writeFile(tomlPath, toml, { mode: 384 });
68908
69170
  const proc = (this.deps.spawnImpl ?? import_node_child_process16.spawn)(frpcBin, ["-c", tomlPath], {
68909
69171
  stdio: ["ignore", "pipe", "pipe"]
68910
69172
  });
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 });
69173
+ const logDir = import_node_path59.default.join(this.deps.dataDir, "log");
69174
+ import_node_fs54.default.mkdirSync(logDir, { recursive: true });
69175
+ const logFilePath = import_node_path59.default.join(logDir, "frpc.log");
69176
+ const logStream = import_node_fs54.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
68915
69177
  logStream.on("error", () => {
68916
69178
  });
68917
69179
  const tee = (chunk) => {
@@ -68993,28 +69255,28 @@ async function waitForFrpcReady(proc, timeoutMs) {
68993
69255
  }
68994
69256
 
68995
69257
  // src/tunnel/device-key.ts
68996
- var import_node_os20 = __toESM(require("os"), 1);
68997
- var import_node_path59 = __toESM(require("path"), 1);
69258
+ var import_node_os21 = __toESM(require("os"), 1);
69259
+ var import_node_path60 = __toESM(require("path"), 1);
68998
69260
  var import_node_crypto18 = __toESM(require("crypto"), 1);
68999
69261
  var DERIVE_SALT = "clawd-tunnel-device-v1";
69000
69262
  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;
69263
+ const hostname = opts.hostname ?? import_node_os21.default.hostname();
69264
+ const uid = opts.uid ?? (typeof import_node_os21.default.userInfo === "function" ? import_node_os21.default.userInfo().uid : 0);
69265
+ const home = opts.home ?? import_node_os21.default.homedir();
69266
+ const defaultDataDir = import_node_path60.default.resolve(import_node_path60.default.join(home, ".clawd"));
69267
+ const normalizedDataDir = opts.dataDir ? import_node_path60.default.resolve(opts.dataDir) : null;
69006
69268
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
69007
69269
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
69008
69270
  return import_node_crypto18.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
69009
69271
  }
69010
69272
 
69011
69273
  // src/auth-store.ts
69012
- var import_node_fs54 = __toESM(require("fs"), 1);
69013
- var import_node_path60 = __toESM(require("path"), 1);
69274
+ var import_node_fs55 = __toESM(require("fs"), 1);
69275
+ var import_node_path61 = __toESM(require("path"), 1);
69014
69276
  var import_node_crypto19 = __toESM(require("crypto"), 1);
69015
69277
  var AUTH_FILE_NAME = "auth.json";
69016
69278
  function authFilePath(dataDir) {
69017
- return import_node_path60.default.join(dataDir, AUTH_FILE_NAME);
69279
+ return import_node_path61.default.join(dataDir, AUTH_FILE_NAME);
69018
69280
  }
69019
69281
  function loadOrCreateAuthFile(opts) {
69020
69282
  const file = authFilePath(opts.dataDir);
@@ -69055,7 +69317,7 @@ function defaultGenerateOwnerPrincipalId() {
69055
69317
  }
69056
69318
  function readAuthFile(file) {
69057
69319
  try {
69058
- const raw = import_node_fs54.default.readFileSync(file, "utf8");
69320
+ const raw = import_node_fs55.default.readFileSync(file, "utf8");
69059
69321
  const parsed = JSON.parse(raw);
69060
69322
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
69061
69323
  return null;
@@ -69076,26 +69338,26 @@ function readAuthFile(file) {
69076
69338
  }
69077
69339
  }
69078
69340
  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 });
69341
+ import_node_fs55.default.mkdirSync(import_node_path61.default.dirname(file), { recursive: true });
69342
+ import_node_fs55.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
69081
69343
  try {
69082
- import_node_fs54.default.chmodSync(file, 384);
69344
+ import_node_fs55.default.chmodSync(file, 384);
69083
69345
  } catch {
69084
69346
  }
69085
69347
  }
69086
69348
 
69087
69349
  // 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);
69350
+ var import_node_fs56 = __toESM(require("fs"), 1);
69351
+ var import_node_os22 = __toESM(require("os"), 1);
69352
+ var import_node_path62 = __toESM(require("path"), 1);
69091
69353
  var PROFILE_FILENAME = "profile.json";
69092
69354
  function profilePath(dataDir) {
69093
- return import_node_path61.default.join(dataDir, PROFILE_FILENAME);
69355
+ return import_node_path62.default.join(dataDir, PROFILE_FILENAME);
69094
69356
  }
69095
69357
  function loadOwnerProfile(dataDir) {
69096
69358
  let raw;
69097
69359
  try {
69098
- raw = import_node_fs55.default.readFileSync(profilePath(dataDir), "utf8");
69360
+ raw = import_node_fs56.default.readFileSync(profilePath(dataDir), "utf8");
69099
69361
  } catch {
69100
69362
  return {};
69101
69363
  }
@@ -69111,11 +69373,11 @@ function loadOwnerProfile(dataDir) {
69111
69373
  }
69112
69374
  function patchOwnerProfile(dataDir, patch) {
69113
69375
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
69114
- import_node_fs55.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
69376
+ import_node_fs56.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
69115
69377
  return merged;
69116
69378
  }
69117
69379
  function loadOwnerDisplayName(dataDir) {
69118
- const fallback = import_node_os21.default.userInfo().username;
69380
+ const fallback = import_node_os22.default.userInfo().username;
69119
69381
  const displayName = loadOwnerProfile(dataDir).displayName;
69120
69382
  if (typeof displayName !== "string" || displayName.length === 0) {
69121
69383
  if (displayName !== void 0) {
@@ -69127,18 +69389,18 @@ function loadOwnerDisplayName(dataDir) {
69127
69389
  }
69128
69390
 
69129
69391
  // 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);
69392
+ var import_node_fs57 = __toESM(require("fs"), 1);
69393
+ var import_node_path63 = __toESM(require("path"), 1);
69132
69394
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
69133
69395
  var OwnerIdentityStore = class {
69134
69396
  file;
69135
69397
  constructor(dataDir) {
69136
- this.file = import_node_path62.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
69398
+ this.file = import_node_path63.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
69137
69399
  }
69138
69400
  read() {
69139
69401
  let raw;
69140
69402
  try {
69141
- raw = import_node_fs56.default.readFileSync(this.file, "utf8");
69403
+ raw = import_node_fs57.default.readFileSync(this.file, "utf8");
69142
69404
  } catch {
69143
69405
  return null;
69144
69406
  }
@@ -69165,16 +69427,16 @@ var OwnerIdentityStore = class {
69165
69427
  };
69166
69428
  }
69167
69429
  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 });
69430
+ import_node_fs57.default.mkdirSync(import_node_path63.default.dirname(this.file), { recursive: true });
69431
+ import_node_fs57.default.writeFileSync(this.file, JSON.stringify(record4, null, 2), { mode: 384 });
69170
69432
  try {
69171
- import_node_fs56.default.chmodSync(this.file, 384);
69433
+ import_node_fs57.default.chmodSync(this.file, 384);
69172
69434
  } catch {
69173
69435
  }
69174
69436
  }
69175
69437
  clear() {
69176
69438
  try {
69177
- import_node_fs56.default.unlinkSync(this.file);
69439
+ import_node_fs57.default.unlinkSync(this.file);
69178
69440
  } catch (err) {
69179
69441
  const code = err?.code;
69180
69442
  if (code !== "ENOENT") throw err;
@@ -69670,8 +69932,8 @@ function verifyConnectToken(args) {
69670
69932
  }
69671
69933
 
69672
69934
  // src/feishu-auth/server-key.ts
69673
- var fs73 = __toESM(require("fs"), 1);
69674
- var path75 = __toESM(require("path"), 1);
69935
+ var fs74 = __toESM(require("fs"), 1);
69936
+ var path76 = __toESM(require("path"), 1);
69675
69937
  var FILE_NAME2 = "server-signing-key.json";
69676
69938
  var ServerKeyStore = class {
69677
69939
  constructor(dataDir) {
@@ -69679,12 +69941,12 @@ var ServerKeyStore = class {
69679
69941
  }
69680
69942
  dataDir;
69681
69943
  filePath() {
69682
- return path75.join(this.dataDir, FILE_NAME2);
69944
+ return path76.join(this.dataDir, FILE_NAME2);
69683
69945
  }
69684
69946
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
69685
69947
  read() {
69686
69948
  try {
69687
- const raw = fs73.readFileSync(this.filePath(), "utf8");
69949
+ const raw = fs74.readFileSync(this.filePath(), "utf8");
69688
69950
  const parsed = JSON.parse(raw);
69689
69951
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
69690
69952
  return parsed.publicKeyPem;
@@ -69699,12 +69961,12 @@ var ServerKeyStore = class {
69699
69961
  publicKeyPem,
69700
69962
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
69701
69963
  };
69702
- fs73.mkdirSync(this.dataDir, { recursive: true });
69703
- fs73.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
69964
+ fs74.mkdirSync(this.dataDir, { recursive: true });
69965
+ fs74.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
69704
69966
  }
69705
69967
  clear() {
69706
69968
  try {
69707
- fs73.unlinkSync(this.filePath());
69969
+ fs74.unlinkSync(this.filePath());
69708
69970
  } catch {
69709
69971
  }
69710
69972
  }
@@ -69714,19 +69976,19 @@ var ServerKeyStore = class {
69714
69976
  init_protocol();
69715
69977
 
69716
69978
  // src/handlers/index.ts
69717
- var import_node_path76 = __toESM(require("path"), 1);
69979
+ var import_node_path78 = __toESM(require("path"), 1);
69718
69980
 
69719
69981
  // src/handlers/session.ts
69720
69982
  init_protocol();
69721
69983
 
69722
69984
  // 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);
69985
+ var import_node_fs58 = __toESM(require("fs"), 1);
69986
+ var import_node_os23 = __toESM(require("os"), 1);
69987
+ var import_node_path64 = __toESM(require("path"), 1);
69726
69988
  var import_node_crypto21 = require("crypto");
69727
69989
  init_claude_history();
69728
69990
  function readJsonlEntries(file) {
69729
- const raw = import_node_fs57.default.readFileSync(file, "utf8");
69991
+ const raw = import_node_fs58.default.readFileSync(file, "utf8");
69730
69992
  const out = [];
69731
69993
  for (const line of raw.split("\n")) {
69732
69994
  const t2 = line.trim();
@@ -69739,19 +70001,19 @@ function readJsonlEntries(file) {
69739
70001
  return out;
69740
70002
  }
69741
70003
  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)) {
70004
+ const baseDir = input.baseDir ?? import_node_path64.default.join(import_node_os23.default.homedir(), ".claude");
70005
+ let projectDir = import_node_path64.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
70006
+ let sourceFile = import_node_path64.default.join(projectDir, `${input.toolSessionId}.jsonl`);
70007
+ if (!import_node_fs58.default.existsSync(sourceFile)) {
69746
70008
  const found = findTranscriptByToolSessionId(
69747
- import_node_path63.default.join(baseDir, "projects"),
70009
+ import_node_path64.default.join(baseDir, "projects"),
69748
70010
  input.toolSessionId
69749
70011
  );
69750
70012
  if (!found) {
69751
70013
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
69752
70014
  }
69753
70015
  sourceFile = found;
69754
- projectDir = import_node_path63.default.dirname(found);
70016
+ projectDir = import_node_path64.default.dirname(found);
69755
70017
  }
69756
70018
  const entries = readJsonlEntries(sourceFile);
69757
70019
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -69780,27 +70042,27 @@ function forkSession(input) {
69780
70042
  }
69781
70043
  forkedLines.push(JSON.stringify(forked));
69782
70044
  }
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 });
70045
+ const outDir = input.targetCwd ? import_node_path64.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
70046
+ const forkedFilePath = import_node_path64.default.join(outDir, `${forkedToolSessionId}.jsonl`);
70047
+ import_node_fs58.default.mkdirSync(outDir, { recursive: true });
70048
+ import_node_fs58.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
69787
70049
  return { forkedToolSessionId, forkedFilePath };
69788
70050
  }
69789
70051
 
69790
70052
  // src/session/external-scan.ts
69791
- var import_node_fs58 = __toESM(require("fs"), 1);
70053
+ var import_node_fs59 = __toESM(require("fs"), 1);
69792
70054
  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);
70055
+ var import_node_os24 = __toESM(require("os"), 1);
70056
+ var import_node_path65 = __toESM(require("path"), 1);
69795
70057
  var import_node_module = require("module");
69796
70058
  var import_node_child_process17 = require("child_process");
69797
70059
  var import_meta7 = {};
69798
70060
  function defaultRoots() {
69799
- const home = import_node_os23.default.homedir();
70061
+ const home = import_node_os24.default.homedir();
69800
70062
  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")
70063
+ claudeProjectsDir: import_node_path65.default.join(home, ".claude", "projects"),
70064
+ codexDir: import_node_path65.default.join(home, ".codex"),
70065
+ clawdDir: import_node_path65.default.join(home, ".clawd")
69804
70066
  };
69805
70067
  }
69806
70068
  function width(s2) {
@@ -69851,7 +70113,7 @@ function userText(msg) {
69851
70113
  }
69852
70114
  function isDir2(p3) {
69853
70115
  try {
69854
- return import_node_fs58.default.statSync(p3).isDirectory();
70116
+ return import_node_fs59.default.statSync(p3).isDirectory();
69855
70117
  } catch {
69856
70118
  return false;
69857
70119
  }
@@ -69860,7 +70122,7 @@ async function scanClaude(roots) {
69860
70122
  const out = [];
69861
70123
  let dirs;
69862
70124
  try {
69863
- dirs = import_node_fs58.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
70125
+ dirs = import_node_fs59.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
69864
70126
  } catch {
69865
70127
  return out;
69866
70128
  }
@@ -69868,16 +70130,16 @@ async function scanClaude(roots) {
69868
70130
  if (!d2.isDirectory()) continue;
69869
70131
  let files;
69870
70132
  try {
69871
- files = import_node_fs58.default.readdirSync(import_node_path64.default.join(roots.claudeProjectsDir, d2.name));
70133
+ files = import_node_fs59.default.readdirSync(import_node_path65.default.join(roots.claudeProjectsDir, d2.name));
69872
70134
  } catch {
69873
70135
  continue;
69874
70136
  }
69875
70137
  for (const name of files) {
69876
70138
  if (!name.endsWith(".jsonl")) continue;
69877
- const file = import_node_path64.default.join(roots.claudeProjectsDir, d2.name, name);
70139
+ const file = import_node_path65.default.join(roots.claudeProjectsDir, d2.name, name);
69878
70140
  let st2;
69879
70141
  try {
69880
- st2 = import_node_fs58.default.statSync(file);
70142
+ st2 = import_node_fs59.default.statSync(file);
69881
70143
  } catch {
69882
70144
  continue;
69883
70145
  }
@@ -69930,7 +70192,7 @@ async function scanClaude(roots) {
69930
70192
  return out;
69931
70193
  }
69932
70194
  async function countCodexTurns(rolloutPath) {
69933
- if (!rolloutPath || !import_node_fs58.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
70195
+ if (!rolloutPath || !import_node_fs59.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
69934
70196
  let turns = 0;
69935
70197
  let first = "";
69936
70198
  for await (const rec6 of jsonLines(rolloutPath)) {
@@ -70004,7 +70266,7 @@ async function codexFromRows(rows) {
70004
70266
  async function scanCodex(roots) {
70005
70267
  let dbs = [];
70006
70268
  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));
70269
+ dbs = import_node_fs59.default.readdirSync(roots.codexDir).filter((n2) => /^state_.*\.sqlite$/.test(n2)).sort().map((n2) => import_node_path65.default.join(roots.codexDir, n2));
70008
70270
  } catch {
70009
70271
  }
70010
70272
  if (!dbs.length) return [];
@@ -70013,14 +70275,14 @@ async function scanCodex(roots) {
70013
70275
  }
70014
70276
  async function scanExternalSessions(rootsIn) {
70015
70277
  const roots = { ...defaultRoots(), ...rootsIn };
70016
- const personaRoot = import_node_path64.default.join(roots.clawdDir, "personas");
70278
+ const personaRoot = import_node_path65.default.join(roots.clawdDir, "personas");
70017
70279
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
70018
70280
  const out = [];
70019
70281
  for (const c2 of all) {
70020
70282
  if (c2.skip) continue;
70021
70283
  if (c2.turns < 1) continue;
70022
70284
  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)) {
70285
+ if (c2.cwd === roots.clawdDir || c2.cwd === personaRoot || c2.cwd.startsWith(personaRoot + import_node_path65.default.sep) || c2.cwd.startsWith(roots.clawdDir + import_node_path65.default.sep)) {
70024
70286
  continue;
70025
70287
  }
70026
70288
  out.push({
@@ -70037,13 +70299,13 @@ async function scanExternalSessions(rootsIn) {
70037
70299
  }
70038
70300
 
70039
70301
  // src/session/import-ledger.ts
70040
- var import_node_fs59 = __toESM(require("fs"), 1);
70041
- var import_node_path65 = __toESM(require("path"), 1);
70302
+ var import_node_fs60 = __toESM(require("fs"), 1);
70303
+ var import_node_path66 = __toESM(require("path"), 1);
70042
70304
  var LEDGER_FILENAME = "session-import-ledger.json";
70043
70305
  function readImportLedger(dataDir) {
70044
70306
  try {
70045
70307
  const parsed = JSON.parse(
70046
- import_node_fs59.default.readFileSync(import_node_path65.default.join(dataDir, LEDGER_FILENAME), "utf8")
70308
+ import_node_fs60.default.readFileSync(import_node_path66.default.join(dataDir, LEDGER_FILENAME), "utf8")
70047
70309
  );
70048
70310
  return Array.isArray(parsed) ? parsed : [];
70049
70311
  } catch {
@@ -70051,10 +70313,10 @@ function readImportLedger(dataDir) {
70051
70313
  }
70052
70314
  }
70053
70315
  function appendImportLedger(dataDir, entry) {
70054
- const file = import_node_path65.default.join(dataDir, LEDGER_FILENAME);
70316
+ const file = import_node_path66.default.join(dataDir, LEDGER_FILENAME);
70055
70317
  const entries = readImportLedger(dataDir);
70056
70318
  entries.push(entry);
70057
- import_node_fs59.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70319
+ import_node_fs60.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
70058
70320
  }
70059
70321
 
70060
70322
  // src/handlers/session.ts
@@ -70587,7 +70849,7 @@ function buildPermissionHandlers(deps) {
70587
70849
  }
70588
70850
 
70589
70851
  // src/handlers/history.ts
70590
- var path80 = __toESM(require("path"), 1);
70852
+ var path81 = __toESM(require("path"), 1);
70591
70853
  init_protocol();
70592
70854
 
70593
70855
  // src/session/recent-dirs.ts
@@ -70605,7 +70867,7 @@ function listRecentDirs(store, limit = 50) {
70605
70867
  }
70606
70868
 
70607
70869
  // src/permission/persona-paths.ts
70608
- var path79 = __toESM(require("path"), 1);
70870
+ var path80 = __toESM(require("path"), 1);
70609
70871
  function getAllowedPersonaIds(grants, action) {
70610
70872
  const ids = /* @__PURE__ */ new Set();
70611
70873
  for (const g3 of grants) {
@@ -70618,42 +70880,42 @@ function getAllowedPersonaIds(grants, action) {
70618
70880
  return ids;
70619
70881
  }
70620
70882
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
70621
- const target = path79.resolve(absPath);
70883
+ const target = path80.resolve(absPath);
70622
70884
  if (userWorkDir) {
70623
- const u2 = path79.resolve(userWorkDir);
70624
- const usep = u2.endsWith(path79.sep) ? "" : path79.sep;
70885
+ const u2 = path80.resolve(userWorkDir);
70886
+ const usep = u2.endsWith(path80.sep) ? "" : path80.sep;
70625
70887
  if (target === u2 || target.startsWith(u2 + usep)) return true;
70626
70888
  }
70627
- const root = path79.resolve(personaRoot);
70628
- const sep4 = root.endsWith(path79.sep) ? "" : path79.sep;
70889
+ const root = path80.resolve(personaRoot);
70890
+ const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
70629
70891
  if (!target.startsWith(root + sep4)) return false;
70630
- const rel = path79.relative(root, target);
70892
+ const rel = path80.relative(root, target);
70631
70893
  if (!rel || rel.startsWith("..")) return false;
70632
- const personaId2 = rel.split(path79.sep)[0];
70894
+ const personaId2 = rel.split(path80.sep)[0];
70633
70895
  if (!personaId2) return false;
70634
70896
  const allowed = getAllowedPersonaIds(grants, action);
70635
70897
  if (allowed === "*") return true;
70636
70898
  return allowed.has(personaId2);
70637
70899
  }
70638
70900
  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;
70901
+ const root = path80.resolve(personaRoot);
70902
+ const target = path80.resolve(absPath);
70903
+ const sep4 = root.endsWith(path80.sep) ? "" : path80.sep;
70642
70904
  if (!target.startsWith(root + sep4)) return null;
70643
- const rel = path79.relative(root, target);
70905
+ const rel = path80.relative(root, target);
70644
70906
  if (!rel || rel.startsWith("..")) return null;
70645
- const id = rel.split(path79.sep)[0];
70907
+ const id = rel.split(path80.sep)[0];
70646
70908
  return id || null;
70647
70909
  }
70648
70910
  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;
70911
+ const d2 = path80.resolve(dir);
70912
+ const t2 = path80.resolve(absPath);
70913
+ const sep4 = d2.endsWith(path80.sep) ? "" : path80.sep;
70652
70914
  return t2 === d2 || t2.startsWith(d2 + sep4);
70653
70915
  }
70654
70916
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
70655
70917
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
70656
- return personaIdFromPath(path79.resolve(absPath), personaRoot) === personaId2;
70918
+ return personaIdFromPath(path80.resolve(absPath), personaRoot) === personaId2;
70657
70919
  }
70658
70920
 
70659
70921
  // src/handlers/history.ts
@@ -70706,7 +70968,7 @@ function buildHistoryHandlers(deps) {
70706
70968
  if (!pid) return false;
70707
70969
  return isGuestPathAllowed(
70708
70970
  ctx.grants,
70709
- path80.join(personaRoot, pid),
70971
+ path81.join(personaRoot, pid),
70710
70972
  personaRoot,
70711
70973
  "read",
70712
70974
  userWorkDir
@@ -70718,7 +70980,7 @@ function buildHistoryHandlers(deps) {
70718
70980
  };
70719
70981
  const list = async (frame, _client, ctx) => {
70720
70982
  const args = HistoryListArgs.parse(frame);
70721
- assertGuestPath(ctx, path80.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
70983
+ assertGuestPath(ctx, path81.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
70722
70984
  const sessions = await history.listSessions(args);
70723
70985
  return { response: { type: "history:list", sessions } };
70724
70986
  };
@@ -70766,14 +71028,14 @@ function buildHistoryHandlers(deps) {
70766
71028
  };
70767
71029
  const subagents = async (frame, _client, ctx) => {
70768
71030
  const args = HistorySubagentsArgs.parse(frame);
70769
- assertGuestPath(ctx, path80.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
71031
+ assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
70770
71032
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
70771
71033
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
70772
71034
  return { response: { type: "history:subagents", subagents: subs } };
70773
71035
  };
70774
71036
  const subagentRead = async (frame, _client, ctx) => {
70775
71037
  const args = HistorySubagentReadArgs.parse(frame);
70776
- assertGuestPath(ctx, path80.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
71038
+ assertGuestPath(ctx, path81.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
70777
71039
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
70778
71040
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
70779
71041
  return { response: { type: "history:subagent-read", ...res } };
@@ -70783,7 +71045,7 @@ function buildHistoryHandlers(deps) {
70783
71045
  if (ctx?.principal.kind === "guest" && personaRoot) {
70784
71046
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
70785
71047
  const filtered = dirs.filter(
70786
- (d2) => isGuestPathAllowed(ctx.grants, path80.resolve(d2.cwd), personaRoot, "read", userWorkDir)
71048
+ (d2) => isGuestPathAllowed(ctx.grants, path81.resolve(d2.cwd), personaRoot, "read", userWorkDir)
70787
71049
  );
70788
71050
  return { response: { type: "history:recentDirs", dirs: filtered } };
70789
71051
  }
@@ -70800,17 +71062,17 @@ function buildHistoryHandlers(deps) {
70800
71062
  }
70801
71063
 
70802
71064
  // 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);
71065
+ var fs78 = __toESM(require("fs"), 1);
71066
+ var os26 = __toESM(require("os"), 1);
71067
+ var path82 = __toESM(require("path"), 1);
70806
71068
  var import_node_child_process18 = require("child_process");
70807
71069
  init_protocol();
70808
- var DEFAULT_PROJECTS_ROOT = path81.join(os25.homedir(), "Documents", "ChatGPT");
71070
+ var DEFAULT_PROJECTS_ROOT = path82.join(os26.homedir(), "Documents", "ChatGPT");
70809
71071
  function allocateDir(root, name) {
70810
- let candidate = path81.join(root, name);
71072
+ let candidate = path82.join(root, name);
70811
71073
  let n2 = 2;
70812
- while (fs77.existsSync(candidate)) {
70813
- candidate = path81.join(root, `${name} ${n2}`);
71074
+ while (fs78.existsSync(candidate)) {
71075
+ candidate = path82.join(root, `${name} ${n2}`);
70814
71076
  n2 += 1;
70815
71077
  }
70816
71078
  return candidate;
@@ -70838,7 +71100,7 @@ function buildProjectHandlers(deps) {
70838
71100
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
70839
71101
  }
70840
71102
  try {
70841
- if (!fs77.statSync(args.path).isDirectory()) throw new Error("not dir");
71103
+ if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
70842
71104
  } catch {
70843
71105
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
70844
71106
  }
@@ -70854,7 +71116,7 @@ function buildProjectHandlers(deps) {
70854
71116
  let target;
70855
71117
  if (args.path) {
70856
71118
  try {
70857
- if (!fs77.statSync(args.path).isDirectory()) throw new Error("not dir");
71119
+ if (!fs78.statSync(args.path).isDirectory()) throw new Error("not dir");
70858
71120
  } catch {
70859
71121
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
70860
71122
  }
@@ -70862,15 +71124,15 @@ function buildProjectHandlers(deps) {
70862
71124
  } else {
70863
71125
  const name = args.name;
70864
71126
  try {
70865
- fs77.mkdirSync(root, { recursive: true });
71127
+ fs78.mkdirSync(root, { recursive: true });
70866
71128
  target = allocateDir(root, name);
70867
- fs77.mkdirSync(target);
71129
+ fs78.mkdirSync(target);
70868
71130
  } catch (err) {
70869
71131
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
70870
71132
  }
70871
71133
  const git2 = (0, import_node_child_process18.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
70872
71134
  if (git2.status !== 0) {
70873
- fs77.rmSync(target, { recursive: true, force: true });
71135
+ fs78.rmSync(target, { recursive: true, force: true });
70874
71136
  throw new ClawdError(
70875
71137
  ERROR_CODES.INVALID_CWD,
70876
71138
  `git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
@@ -70895,9 +71157,9 @@ function buildProjectHandlers(deps) {
70895
71157
  }
70896
71158
 
70897
71159
  // src/handlers/workspace.ts
70898
- var path82 = __toESM(require("path"), 1);
71160
+ var path83 = __toESM(require("path"), 1);
70899
71161
  init_protocol();
70900
- var os26 = __toESM(require("os"), 1);
71162
+ var os27 = __toESM(require("os"), 1);
70901
71163
  init_protocol();
70902
71164
  init_protocol();
70903
71165
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -70937,23 +71199,23 @@ function buildWorkspaceHandlers(deps) {
70937
71199
  const list = async (frame, _client, ctx) => {
70938
71200
  const args = WorkspaceListArgs.parse(frame);
70939
71201
  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;
71202
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os27.homedir();
71203
+ const resolvedCwd = path83.resolve(args.cwd ?? fallbackCwd);
71204
+ const target = args.path ? path83.resolve(resolvedCwd, args.path) : resolvedCwd;
70943
71205
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
70944
71206
  const res = workspace.list({ ...args, cwd: resolvedCwd });
70945
71207
  return { response: { type: "workspace:list", ...res } };
70946
71208
  };
70947
71209
  const read = async (frame, _client, ctx) => {
70948
71210
  const args = WorkspaceReadArgs.parse(frame);
70949
- const target = path82.isAbsolute(args.path) ? path82.resolve(args.path) : path82.resolve(args.cwd, args.path);
71211
+ const target = path83.isAbsolute(args.path) ? path83.resolve(args.path) : path83.resolve(args.cwd, args.path);
70950
71212
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
70951
71213
  const res = workspace.read(args);
70952
71214
  return { response: { type: "workspace:read", ...res } };
70953
71215
  };
70954
71216
  const skillsList = async (frame, _client, ctx) => {
70955
71217
  const args = SkillsListArgs.parse(frame);
70956
- const cwdAbs = path82.resolve(args.cwd);
71218
+ const cwdAbs = path83.resolve(args.cwd);
70957
71219
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
70958
71220
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
70959
71221
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -70965,7 +71227,7 @@ function buildWorkspaceHandlers(deps) {
70965
71227
  };
70966
71228
  const agentsList = async (frame, _client, ctx) => {
70967
71229
  const args = AgentsListArgs.parse(frame);
70968
- const cwdAbs = path82.resolve(args.cwd);
71230
+ const cwdAbs = path83.resolve(args.cwd);
70969
71231
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
70970
71232
  if (isCodexFamily(args.tool) || isPiFamily(args.tool)) {
70971
71233
  return { response: { type: "agents:list", agents: [] } };
@@ -70987,20 +71249,20 @@ function buildWorkspaceHandlers(deps) {
70987
71249
  }
70988
71250
 
70989
71251
  // src/handlers/git.ts
70990
- var path84 = __toESM(require("path"), 1);
71252
+ var path85 = __toESM(require("path"), 1);
70991
71253
  init_protocol();
70992
71254
  init_protocol();
70993
71255
 
70994
71256
  // src/workspace/git.ts
70995
71257
  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);
71258
+ var import_node_fs61 = __toESM(require("fs"), 1);
71259
+ var import_node_path67 = __toESM(require("path"), 1);
70998
71260
  var import_node_util2 = require("util");
70999
71261
  var pexec = (0, import_node_util2.promisify)(import_node_child_process19.execFile);
71000
71262
  function normalizePath(p3) {
71001
- const resolved = import_node_path66.default.resolve(p3);
71263
+ const resolved = import_node_path67.default.resolve(p3);
71002
71264
  try {
71003
- return import_node_fs60.default.realpathSync(resolved);
71265
+ return import_node_fs61.default.realpathSync(resolved);
71004
71266
  } catch {
71005
71267
  return resolved;
71006
71268
  }
@@ -71074,7 +71336,7 @@ async function listGitBranches(cwd) {
71074
71336
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
71075
71337
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
71076
71338
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
71077
- if (!isGuestPathAllowed(ctx.grants, path84.resolve(cwd), personaRoot, "read", userWorkDir)) {
71339
+ if (!isGuestPathAllowed(ctx.grants, path85.resolve(cwd), personaRoot, "read", userWorkDir)) {
71078
71340
  throw new ClawdError(
71079
71341
  ERROR_CODES.UNAUTHORIZED,
71080
71342
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -71331,12 +71593,12 @@ async function queryCodexAccount(deps = {}) {
71331
71593
  }
71332
71594
 
71333
71595
  // src/tools/pi-account.ts
71334
- var import_node_fs61 = __toESM(require("fs"), 1);
71335
- var import_node_path67 = __toESM(require("path"), 1);
71596
+ var import_node_fs62 = __toESM(require("fs"), 1);
71597
+ var import_node_path68 = __toESM(require("path"), 1);
71336
71598
  function readPiCredentials(agentDir) {
71337
71599
  let raw;
71338
71600
  try {
71339
- raw = JSON.parse(import_node_fs61.default.readFileSync(import_node_path67.default.join(agentDir, "auth.json"), "utf8"));
71601
+ raw = JSON.parse(import_node_fs62.default.readFileSync(import_node_path68.default.join(agentDir, "auth.json"), "utf8"));
71340
71602
  } catch {
71341
71603
  return {};
71342
71604
  }
@@ -71419,6 +71681,129 @@ function buildEngineHandlers(deps, overrides = {}) {
71419
71681
  return { "engine:status": status, "engine:connectPool": connectPool };
71420
71682
  }
71421
71683
 
71684
+ // src/tools/subscription-channels-apply.ts
71685
+ var import_node_fs63 = __toESM(require("fs"), 1);
71686
+ var import_node_os25 = __toESM(require("os"), 1);
71687
+ var import_node_path69 = __toESM(require("path"), 1);
71688
+ var TABLE_HEADER = /^\s*\[\[?\s*([A-Za-z0-9_.-]+)\s*\]\]?\s*(?:#.*)?$/;
71689
+ var KEY_LINE = /^\s*([A-Za-z0-9_.-]+)\s*=/;
71690
+ function stripCodexProvider(text) {
71691
+ const out = [];
71692
+ let inProviderSection = false;
71693
+ for (const line of text.split("\n")) {
71694
+ const headerMatch = TABLE_HEADER.exec(line);
71695
+ if (headerMatch) {
71696
+ const section = headerMatch[1].trim();
71697
+ inProviderSection = section === "model_providers" || section.startsWith("model_providers.");
71698
+ if (inProviderSection) continue;
71699
+ out.push(line);
71700
+ continue;
71701
+ }
71702
+ if (inProviderSection) continue;
71703
+ const keyMatch = KEY_LINE.exec(line);
71704
+ if (keyMatch) {
71705
+ const key = keyMatch[1].trim();
71706
+ if (key === "model_provider" || key.startsWith("model_providers.")) {
71707
+ continue;
71708
+ }
71709
+ }
71710
+ out.push(line);
71711
+ }
71712
+ return out.join("\n").trim();
71713
+ }
71714
+ function applyCodexSubscriptionChannel(opts) {
71715
+ const codexHome = opts.codexHome || process.env.CODEX_HOME || import_node_path69.default.join(import_node_os25.default.homedir(), ".codex");
71716
+ import_node_fs63.default.mkdirSync(codexHome, { recursive: true });
71717
+ const configFile = import_node_path69.default.join(codexHome, "config.toml");
71718
+ const original = import_node_fs63.default.existsSync(configFile) ? import_node_fs63.default.readFileSync(configFile, "utf8") : "";
71719
+ const rest = stripCodexProvider(original);
71720
+ let content;
71721
+ if (opts.channel) {
71722
+ const ch = opts.channel;
71723
+ content = [
71724
+ 'model_provider = "cliproxyapi"',
71725
+ ...rest ? ["", rest] : [],
71726
+ "",
71727
+ "[model_providers.cliproxyapi]",
71728
+ 'name = "cliproxyapi"',
71729
+ `base_url = ${JSON.stringify(ch.baseUrl)}`,
71730
+ 'wire_api = "responses"',
71731
+ `auth = { command = "echo", args = [${JSON.stringify(ch.apiKey)}] }`,
71732
+ ""
71733
+ ].join("\n");
71734
+ } else {
71735
+ content = [
71736
+ 'model_provider = "openai"',
71737
+ ...rest ? ["", rest] : [],
71738
+ ""
71739
+ ].join("\n");
71740
+ }
71741
+ const tmpFile = `${configFile}.tmp.${Date.now()}`;
71742
+ import_node_fs63.default.writeFileSync(tmpFile, content, { mode: 384 });
71743
+ import_node_fs63.default.renameSync(tmpFile, configFile);
71744
+ }
71745
+ function applyPiSubscriptionChannel(opts) {
71746
+ const agentDir = opts.agentDir || process.env.PI_CODING_AGENT_DIR || import_node_path69.default.join(import_node_os25.default.homedir(), ".pi", "agent");
71747
+ if (!import_node_fs63.default.existsSync(agentDir)) return false;
71748
+ const configFile = import_node_path69.default.join(agentDir, "cliproxyapi.json");
71749
+ if (opts.channel) {
71750
+ const data = { baseUrl: opts.channel.baseUrl, apiKey: opts.channel.apiKey };
71751
+ const tmp = `${configFile}.tmp.${Date.now()}`;
71752
+ import_node_fs63.default.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
71753
+ import_node_fs63.default.renameSync(tmp, configFile);
71754
+ return true;
71755
+ }
71756
+ return false;
71757
+ }
71758
+
71759
+ // src/handlers/channels.ts
71760
+ function buildChannelsHandlers(deps) {
71761
+ const get = async () => {
71762
+ return { response: deps.store.list() };
71763
+ };
71764
+ const save = async (frame) => {
71765
+ const args = parseArgs2(SubscriptionChannelSaveArgsSchema, frame, "subscriptionChannel:save");
71766
+ const channel = deps.store.save(args);
71767
+ const state = deps.store.list();
71768
+ if (state.activeChannelId === channel.id) {
71769
+ applyCodexSubscriptionChannel({ codexHome: deps.codexHome, channel });
71770
+ applyPiSubscriptionChannel({ agentDir: deps.agentDir, channel });
71771
+ await deps.manager.getCapabilities("codex", { refresh: true });
71772
+ }
71773
+ return { response: deps.store.list() };
71774
+ };
71775
+ const del = async (frame) => {
71776
+ const args = parseArgs2(SubscriptionChannelDeleteArgsSchema, frame, "subscriptionChannel:delete");
71777
+ const wasActive = deps.store.list().activeChannelId === args.id;
71778
+ deps.store.delete(args.id);
71779
+ if (wasActive) {
71780
+ const newActive = deps.store.getActive();
71781
+ applyCodexSubscriptionChannel({ codexHome: deps.codexHome, channel: newActive });
71782
+ applyPiSubscriptionChannel({ agentDir: deps.agentDir, channel: newActive });
71783
+ if (newActive) {
71784
+ await deps.manager.getCapabilities("codex", { refresh: true });
71785
+ }
71786
+ }
71787
+ return { response: { ok: true } };
71788
+ };
71789
+ const activate = async (frame) => {
71790
+ const args = parseArgs2(SubscriptionChannelActivateArgsSchema, frame, "subscriptionChannel:activate");
71791
+ const channel = deps.store.setActive(args.id);
71792
+ applyCodexSubscriptionChannel({ codexHome: deps.codexHome, channel });
71793
+ applyPiSubscriptionChannel({ agentDir: deps.agentDir, channel });
71794
+ if (channel) {
71795
+ await deps.manager.getCapabilities("codex", { refresh: true });
71796
+ }
71797
+ return { response: { ok: true } };
71798
+ };
71799
+ return {
71800
+ "subscriptionChannel:get": get,
71801
+ "subscriptionChannel:save": save,
71802
+ "subscriptionChannel:delete": del,
71803
+ "subscriptionChannel:activate": activate
71804
+ };
71805
+ }
71806
+
71422
71807
  // src/handlers/inbox.ts
71423
71808
  init_protocol();
71424
71809
  function resolvePeerDeviceId(ctx, argsPeerDeviceId) {
@@ -72053,7 +72438,7 @@ function buildDashboardHandlers(deps) {
72053
72438
  }
72054
72439
 
72055
72440
  // src/handlers/meta.ts
72056
- var import_node_os24 = __toESM(require("os"), 1);
72441
+ var import_node_os26 = __toESM(require("os"), 1);
72057
72442
  init_protocol();
72058
72443
 
72059
72444
  // src/handlers/method-grants.ts
@@ -72252,6 +72637,10 @@ var METHOD_GRANT_MAP = {
72252
72637
  "engine:status": ADMIN_ANY,
72253
72638
  // engine:connectPool(接入号池,spec 2026-09-17-onboarding-pool-key):改本机 ~/.codex/config.toml,owner-only
72254
72639
  "engine:connectPool": ADMIN_ANY,
72640
+ "subscriptionChannel:get": ADMIN_ANY,
72641
+ "subscriptionChannel:save": ADMIN_ANY,
72642
+ "subscriptionChannel:delete": ADMIN_ANY,
72643
+ "subscriptionChannel:activate": ADMIN_ANY,
72255
72644
  "persona:create": ADMIN_ANY,
72256
72645
  // persona:list / persona:get 下沉到 CAPABILITY_SCOPED:guest 调用合法
72257
72646
  // (list 用于 People 面板展开对方分享的 personas;get 用于 guest 视角下
@@ -72369,21 +72758,21 @@ function computeMethodAccess(args) {
72369
72758
  }
72370
72759
 
72371
72760
  // src/version.ts
72372
- var version = "0.2.590".length > 0 ? "0.2.590" : "dev";
72761
+ var version = "0.2.591".length > 0 ? "0.2.591" : "dev";
72373
72762
 
72374
72763
  // src/cli-probe/probe.ts
72375
- var fs80 = __toESM(require("fs"), 1);
72376
- var path86 = __toESM(require("path"), 1);
72764
+ var fs82 = __toESM(require("fs"), 1);
72765
+ var path88 = __toESM(require("path"), 1);
72377
72766
  var PKG_NAME = "@clawos-dev/clawd";
72378
72767
  var BIN_NAME = "clawd";
72379
72768
  var MAX_PARENT_HOPS = 5;
72380
72769
  function probeGlobalCli(pathEnv) {
72381
72770
  if (!pathEnv) return null;
72382
- for (const dir of pathEnv.split(path86.delimiter)) {
72771
+ for (const dir of pathEnv.split(path88.delimiter)) {
72383
72772
  if (!dir) continue;
72384
72773
  let real;
72385
72774
  try {
72386
- real = fs80.realpathSync(path86.join(dir, BIN_NAME));
72775
+ real = fs82.realpathSync(path88.join(dir, BIN_NAME));
72387
72776
  } catch {
72388
72777
  continue;
72389
72778
  }
@@ -72393,15 +72782,15 @@ function probeGlobalCli(pathEnv) {
72393
72782
  return null;
72394
72783
  }
72395
72784
  function readOwnPackageVersion(entryPath) {
72396
- let dir = path86.dirname(entryPath);
72785
+ let dir = path88.dirname(entryPath);
72397
72786
  for (let i2 = 0; i2 < MAX_PARENT_HOPS; i2++) {
72398
72787
  try {
72399
- const raw = fs80.readFileSync(path86.join(dir, "package.json"), "utf8");
72788
+ const raw = fs82.readFileSync(path88.join(dir, "package.json"), "utf8");
72400
72789
  const pkg = JSON.parse(raw);
72401
72790
  if (pkg.name !== PKG_NAME) return null;
72402
72791
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
72403
72792
  } catch {
72404
- const parent = path86.dirname(dir);
72793
+ const parent = path88.dirname(dir);
72405
72794
  if (parent === dir) return null;
72406
72795
  dir = parent;
72407
72796
  }
@@ -72437,7 +72826,7 @@ function buildReadyFrame(deps, client) {
72437
72826
  return {
72438
72827
  version,
72439
72828
  protocolVersion: PROTOCOL_VERSION,
72440
- hostname: import_node_os24.default.hostname(),
72829
+ hostname: import_node_os26.default.hostname(),
72441
72830
  os: process.platform,
72442
72831
  tools,
72443
72832
  runningSessions: info.runningSessions,
@@ -72577,7 +72966,7 @@ function buildPersonaHandlers(deps) {
72577
72966
  }
72578
72967
 
72579
72968
  // src/handlers/attachment.ts
72580
- var import_node_path68 = __toESM(require("path"), 1);
72969
+ var import_node_path70 = __toESM(require("path"), 1);
72581
72970
  init_protocol();
72582
72971
  init_protocol();
72583
72972
  function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot) {
@@ -72656,12 +73045,12 @@ function buildAttachmentHandlers(deps) {
72656
73045
  `session ${args.sessionId} scope unresolved`
72657
73046
  );
72658
73047
  }
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);
73048
+ const cwdAbs = import_node_path70.default.resolve(sessionFile.cwd);
73049
+ const candidateAbs = import_node_path70.default.isAbsolute(args.relPath) ? import_node_path70.default.resolve(args.relPath) : import_node_path70.default.resolve(cwdAbs, args.relPath);
72661
73050
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
72662
73051
  const entries = deps.groupFileStore.list(scope, args.sessionId);
72663
73052
  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);
73053
+ const storedAbs = import_node_path70.default.isAbsolute(e.relPath) ? import_node_path70.default.resolve(e.relPath) : import_node_path70.default.resolve(cwdAbs, e.relPath);
72665
73054
  return storedAbs === candidateAbs && !e.stale;
72666
73055
  });
72667
73056
  if (!entry) {
@@ -72685,7 +73074,7 @@ function buildAttachmentHandlers(deps) {
72685
73074
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
72686
73075
  const f2 = deps.sessionStore.read(sessionId);
72687
73076
  if (!f2) return;
72688
- assertGuestAttachmentPath(ctx, import_node_path68.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
73077
+ assertGuestAttachmentPath(ctx, import_node_path70.default.resolve(f2.cwd), deps.personaRoot, method, deps.usersRoot);
72689
73078
  }
72690
73079
  const groupAdd = async (frame, _client, ctx) => {
72691
73080
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -72700,8 +73089,8 @@ function buildAttachmentHandlers(deps) {
72700
73089
  if (!scope) {
72701
73090
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
72702
73091
  }
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);
73092
+ const cwdAbs = import_node_path70.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
73093
+ const candidateAbs = import_node_path70.default.isAbsolute(args.relPath) ? import_node_path70.default.resolve(args.relPath) : import_node_path70.default.resolve(cwdAbs, args.relPath);
72705
73094
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
72706
73095
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
72707
73096
  const size = 0;
@@ -72760,19 +73149,19 @@ function buildAttachmentHandlers(deps) {
72760
73149
 
72761
73150
  // src/handlers/extension.ts
72762
73151
  var import_promises15 = __toESM(require("fs/promises"), 1);
72763
- var import_node_path73 = __toESM(require("path"), 1);
73152
+ var import_node_path75 = __toESM(require("path"), 1);
72764
73153
  init_protocol();
72765
73154
 
72766
73155
  // src/extension/bundle-zip.ts
72767
73156
  var import_promises12 = __toESM(require("fs/promises"), 1);
72768
- var import_node_path69 = __toESM(require("path"), 1);
73157
+ var import_node_path71 = __toESM(require("path"), 1);
72769
73158
  var import_node_crypto22 = __toESM(require("crypto"), 1);
72770
73159
  var import_jszip2 = __toESM(require_lib3(), 1);
72771
73160
  async function bundleExtensionDir(dir) {
72772
73161
  const entries = await listFilesSorted(dir);
72773
73162
  const zip = new import_jszip2.default();
72774
73163
  for (const rel of entries) {
72775
- const abs = import_node_path69.default.join(dir, rel);
73164
+ const abs = import_node_path71.default.join(dir, rel);
72776
73165
  const content = await import_promises12.default.readFile(abs);
72777
73166
  zip.file(rel, content, { date: FIXED_DATE });
72778
73167
  }
@@ -72793,7 +73182,7 @@ async function listFilesSorted(rootDir) {
72793
73182
  return out;
72794
73183
  }
72795
73184
  async function walk(absRoot, relPrefix, out) {
72796
- const dirAbs = import_node_path69.default.join(absRoot, relPrefix);
73185
+ const dirAbs = import_node_path71.default.join(absRoot, relPrefix);
72797
73186
  const entries = await import_promises12.default.readdir(dirAbs, { withFileTypes: true });
72798
73187
  for (const e of entries) {
72799
73188
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -72847,25 +73236,25 @@ function computePublishCheck(args) {
72847
73236
 
72848
73237
  // src/extension/install-flow.ts
72849
73238
  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);
73239
+ var import_node_path73 = __toESM(require("path"), 1);
73240
+ var import_node_os28 = __toESM(require("os"), 1);
72852
73241
  var import_node_crypto23 = __toESM(require("crypto"), 1);
72853
73242
  var import_jszip3 = __toESM(require_lib3(), 1);
72854
73243
 
72855
73244
  // src/extension/paths.ts
72856
- var import_node_os25 = __toESM(require("os"), 1);
72857
- var import_node_path70 = __toESM(require("path"), 1);
73245
+ var import_node_os27 = __toESM(require("os"), 1);
73246
+ var import_node_path72 = __toESM(require("path"), 1);
72858
73247
  function clawdHomeRoot(override) {
72859
- return override ?? process.env.CLAWD_HOME ?? import_node_path70.default.join(import_node_os25.default.homedir(), ".clawd");
73248
+ return override ?? process.env.CLAWD_HOME ?? import_node_path72.default.join(import_node_os27.default.homedir(), ".clawd");
72860
73249
  }
72861
73250
  function extensionsRoot(override) {
72862
- return import_node_path70.default.join(clawdHomeRoot(override), "extensions");
73251
+ return import_node_path72.default.join(clawdHomeRoot(override), "extensions");
72863
73252
  }
72864
73253
  function publishedChannelsFile(override) {
72865
- return import_node_path70.default.join(clawdHomeRoot(override), "extensions-published.json");
73254
+ return import_node_path72.default.join(clawdHomeRoot(override), "extensions-published.json");
72866
73255
  }
72867
73256
  function bundleCacheRoot(override) {
72868
- return import_node_path70.default.join(clawdHomeRoot(override), "extension-bundles");
73257
+ return import_node_path72.default.join(clawdHomeRoot(override), "extension-bundles");
72869
73258
  }
72870
73259
 
72871
73260
  // src/extension/install-flow.ts
@@ -72892,7 +73281,7 @@ async function installFromChannel(args, deps) {
72892
73281
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
72893
73282
  }
72894
73283
  for (const name of Object.keys(zip.files)) {
72895
- if (name.includes("..") || name.startsWith("/") || import_node_path71.default.isAbsolute(name)) {
73284
+ if (name.includes("..") || name.startsWith("/") || import_node_path73.default.isAbsolute(name)) {
72896
73285
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
72897
73286
  }
72898
73287
  }
@@ -72924,7 +73313,7 @@ async function installFromChannel(args, deps) {
72924
73313
  );
72925
73314
  }
72926
73315
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
72927
- const destDir = import_node_path71.default.join(deps.extensionsRoot, localExtId);
73316
+ const destDir = import_node_path73.default.join(deps.extensionsRoot, localExtId);
72928
73317
  let destExists = false;
72929
73318
  try {
72930
73319
  await import_promises13.default.access(destDir);
@@ -72938,16 +73327,16 @@ async function installFromChannel(args, deps) {
72938
73327
  );
72939
73328
  }
72940
73329
  const stage = await import_promises13.default.mkdtemp(
72941
- import_node_path71.default.join(import_node_os26.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
73330
+ import_node_path73.default.join(import_node_os28.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
72942
73331
  );
72943
73332
  try {
72944
73333
  for (const [name, entry] of Object.entries(zip.files)) {
72945
- const dest = import_node_path71.default.join(stage, name);
73334
+ const dest = import_node_path73.default.join(stage, name);
72946
73335
  if (entry.dir) {
72947
73336
  await import_promises13.default.mkdir(dest, { recursive: true });
72948
73337
  continue;
72949
73338
  }
72950
- await import_promises13.default.mkdir(import_node_path71.default.dirname(dest), { recursive: true });
73339
+ await import_promises13.default.mkdir(import_node_path73.default.dirname(dest), { recursive: true });
72951
73340
  if (name === "manifest.json") {
72952
73341
  const rewritten = { ...parsed.data, id: localExtId };
72953
73342
  await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -72968,8 +73357,8 @@ async function installFromChannel(args, deps) {
72968
73357
 
72969
73358
  // src/extension/update-flow.ts
72970
73359
  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);
73360
+ var import_node_path74 = __toESM(require("path"), 1);
73361
+ var import_node_os29 = __toESM(require("os"), 1);
72973
73362
  var import_node_crypto24 = __toESM(require("crypto"), 1);
72974
73363
  var import_jszip4 = __toESM(require_lib3(), 1);
72975
73364
  var UpdateError = class extends Error {
@@ -72985,11 +73374,11 @@ async function updateFromChannel(args, deps) {
72985
73374
  channelRef.extId,
72986
73375
  channelRef.ownerPrincipalId
72987
73376
  );
72988
- const liveDir = import_node_path72.default.join(deps.extensionsRoot, localExtId);
73377
+ const liveDir = import_node_path74.default.join(deps.extensionsRoot, localExtId);
72989
73378
  const prevDir = `${liveDir}.prev`;
72990
73379
  let existingVersion;
72991
73380
  try {
72992
- const raw = await import_promises14.default.readFile(import_node_path72.default.join(liveDir, "manifest.json"), "utf8");
73381
+ const raw = await import_promises14.default.readFile(import_node_path74.default.join(liveDir, "manifest.json"), "utf8");
72993
73382
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
72994
73383
  if (!parsed2.success) {
72995
73384
  throw new UpdateError(
@@ -73022,7 +73411,7 @@ async function updateFromChannel(args, deps) {
73022
73411
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
73023
73412
  }
73024
73413
  for (const name of Object.keys(zip.files)) {
73025
- if (name.includes("..") || name.startsWith("/") || import_node_path72.default.isAbsolute(name)) {
73414
+ if (name.includes("..") || name.startsWith("/") || import_node_path74.default.isAbsolute(name)) {
73026
73415
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
73027
73416
  }
73028
73417
  }
@@ -73057,16 +73446,16 @@ async function updateFromChannel(args, deps) {
73057
73446
  await import_promises14.default.rm(prevDir, { recursive: true, force: true });
73058
73447
  await import_promises14.default.rename(liveDir, prevDir);
73059
73448
  const stage = await import_promises14.default.mkdtemp(
73060
- import_node_path72.default.join(import_node_os27.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73449
+ import_node_path74.default.join(import_node_os29.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
73061
73450
  );
73062
73451
  try {
73063
73452
  for (const [name, entry] of Object.entries(zip.files)) {
73064
- const dest = import_node_path72.default.join(stage, name);
73453
+ const dest = import_node_path74.default.join(stage, name);
73065
73454
  if (entry.dir) {
73066
73455
  await import_promises14.default.mkdir(dest, { recursive: true });
73067
73456
  continue;
73068
73457
  }
73069
- await import_promises14.default.mkdir(import_node_path72.default.dirname(dest), { recursive: true });
73458
+ await import_promises14.default.mkdir(import_node_path74.default.dirname(dest), { recursive: true });
73070
73459
  if (name === "manifest.json") {
73071
73460
  const rewritten = { ...parsed.data, id: localExtId };
73072
73461
  await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -73133,7 +73522,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73133
73522
  );
73134
73523
  }
73135
73524
  }
73136
- const manifestPath = import_node_path73.default.join(root, extId, "manifest.json");
73525
+ const manifestPath = import_node_path75.default.join(root, extId, "manifest.json");
73137
73526
  const manifest = await readManifest(root, extId);
73138
73527
  const next = { ...manifest, version: newVersion };
73139
73528
  const tmp = `${manifestPath}.tmp`;
@@ -73141,7 +73530,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
73141
73530
  await import_promises15.default.rename(tmp, manifestPath);
73142
73531
  }
73143
73532
  async function readManifest(root, extId) {
73144
- const file = import_node_path73.default.join(root, extId, "manifest.json");
73533
+ const file = import_node_path75.default.join(root, extId, "manifest.json");
73145
73534
  let raw;
73146
73535
  try {
73147
73536
  raw = await import_promises15.default.readFile(file, "utf8");
@@ -73225,7 +73614,7 @@ function buildExtensionHandlers(deps) {
73225
73614
  };
73226
73615
  async function buildSnapshotMeta(extId) {
73227
73616
  const manifest = await readManifest(deps.root, extId);
73228
- const { sha256, buffer } = await bundleExtensionDir(import_node_path73.default.join(deps.root, extId));
73617
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path75.default.join(deps.root, extId));
73229
73618
  return { manifest, contentHash: sha256, buffer };
73230
73619
  }
73231
73620
  const publish = async (frame, _client, ctx) => {
@@ -74053,7 +74442,7 @@ function buildVisitorHandlers(deps) {
74053
74442
 
74054
74443
  // src/extension/registry.ts
74055
74444
  var import_promises17 = __toESM(require("fs/promises"), 1);
74056
- var import_node_path74 = __toESM(require("path"), 1);
74445
+ var import_node_path76 = __toESM(require("path"), 1);
74057
74446
  async function loadAll(root) {
74058
74447
  let entries;
74059
74448
  try {
@@ -74066,13 +74455,13 @@ async function loadAll(root) {
74066
74455
  for (const ent of entries) {
74067
74456
  if (!ent.isDirectory()) continue;
74068
74457
  if (ent.name.startsWith(".")) continue;
74069
- records.push(await loadOne(import_node_path74.default.join(root, ent.name), ent.name));
74458
+ records.push(await loadOne(import_node_path76.default.join(root, ent.name), ent.name));
74070
74459
  }
74071
74460
  records.sort((a2, b3) => a2.extId < b3.extId ? -1 : a2.extId > b3.extId ? 1 : 0);
74072
74461
  return records;
74073
74462
  }
74074
74463
  async function loadOne(dir, dirName) {
74075
- const manifestPath = import_node_path74.default.join(dir, "manifest.json");
74464
+ const manifestPath = import_node_path76.default.join(dir, "manifest.json");
74076
74465
  let raw;
74077
74466
  try {
74078
74467
  raw = await import_promises17.default.readFile(manifestPath, "utf8");
@@ -74117,7 +74506,7 @@ async function loadOne(dir, dirName) {
74117
74506
 
74118
74507
  // src/extension/uninstall.ts
74119
74508
  var import_promises18 = __toESM(require("fs/promises"), 1);
74120
- var import_node_path75 = __toESM(require("path"), 1);
74509
+ var import_node_path77 = __toESM(require("path"), 1);
74121
74510
  var UninstallError = class extends Error {
74122
74511
  constructor(code, message) {
74123
74512
  super(message);
@@ -74126,7 +74515,7 @@ var UninstallError = class extends Error {
74126
74515
  code;
74127
74516
  };
74128
74517
  async function uninstall(deps) {
74129
- const dir = import_node_path75.default.join(deps.root, deps.extId);
74518
+ const dir = import_node_path77.default.join(deps.root, deps.extId);
74130
74519
  try {
74131
74520
  await import_promises18.default.access(dir);
74132
74521
  } catch {
@@ -74144,14 +74533,14 @@ init_protocol();
74144
74533
 
74145
74534
  // src/peer-ops/run-command.ts
74146
74535
  var import_node_child_process23 = require("child_process");
74147
- var import_node_os28 = __toESM(require("os"), 1);
74536
+ var import_node_os30 = __toESM(require("os"), 1);
74148
74537
  var DEFAULT_TIMEOUT_MS6 = 3e4;
74149
74538
  var MAX_TIMEOUT_MS = 3e5;
74150
74539
  var MAX_OUTPUT_BYTES = 1048576;
74151
74540
  function runCommand2(command, opts = {}) {
74152
74541
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS6, MAX_TIMEOUT_MS);
74153
74542
  return new Promise((resolve9) => {
74154
- const child = (0, import_node_child_process23.spawn)("bash", ["-c", command], { cwd: import_node_os28.default.homedir() });
74543
+ const child = (0, import_node_child_process23.spawn)("bash", ["-c", command], { cwd: import_node_os30.default.homedir() });
74155
74544
  const out = [];
74156
74545
  const err = [];
74157
74546
  let outBytes = 0;
@@ -74264,7 +74653,9 @@ function ensureGuest(ctx) {
74264
74653
 
74265
74654
  // src/handlers/index.ts
74266
74655
  function buildMethodHandlers(deps) {
74656
+ const channelStore = deps.subscriptionChannelStore ?? new SubscriptionChannelStore({ dataDir: deps.dataDir ?? deps.masterDataDir });
74267
74657
  const handlers = {
74658
+ ...buildChannelsHandlers({ store: channelStore, manager: deps.manager }),
74268
74659
  ...buildSessionHandlers({
74269
74660
  ...deps,
74270
74661
  getTunnelUrl: deps.getTunnelUrl,
@@ -74342,7 +74733,7 @@ function buildMethodHandlers(deps) {
74342
74733
  broadcast: deps.broadcastToOwners
74343
74734
  }),
74344
74735
  ...buildMasterHandlers({
74345
- authorityTablePath: import_node_path76.default.join(deps.masterDataDir, "master-authority.json")
74736
+ authorityTablePath: import_node_path78.default.join(deps.masterDataDir, "master-authority.json")
74346
74737
  }),
74347
74738
  ...buildTopicHandlers({
74348
74739
  topicStore: deps.topicStore,
@@ -74485,7 +74876,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
74485
74876
 
74486
74877
  // src/extension/runtime.ts
74487
74878
  var import_node_child_process24 = require("child_process");
74488
- var import_node_path77 = __toESM(require("path"), 1);
74879
+ var import_node_path79 = __toESM(require("path"), 1);
74489
74880
  var import_promises19 = require("timers/promises");
74490
74881
 
74491
74882
  // src/extension/port-allocator.ts
@@ -74586,7 +74977,7 @@ var Runtime = class {
74586
74977
  /\$CLAWOS_EXT_PORT/g,
74587
74978
  String(port)
74588
74979
  );
74589
- const dir = import_node_path77.default.join(this.root, extId);
74980
+ const dir = import_node_path79.default.join(this.root, extId);
74590
74981
  const env = {
74591
74982
  ...process.env,
74592
74983
  CLAWOS_EXT_PORT: String(port),
@@ -74698,7 +75089,7 @@ ${handle.stderrTail}`
74698
75089
 
74699
75090
  // src/extension/published-channels.ts
74700
75091
  var import_promises20 = __toESM(require("fs/promises"), 1);
74701
- var import_node_path78 = __toESM(require("path"), 1);
75092
+ var import_node_path80 = __toESM(require("path"), 1);
74702
75093
  init_zod();
74703
75094
  var PublishedChannelsError = class extends Error {
74704
75095
  constructor(code, message) {
@@ -74797,7 +75188,7 @@ var PublishedChannelStore = class {
74797
75188
  )
74798
75189
  };
74799
75190
  const tmp = `${this.filePath}.tmp`;
74800
- await import_promises20.default.mkdir(import_node_path78.default.dirname(this.filePath), { recursive: true });
75191
+ await import_promises20.default.mkdir(import_node_path80.default.dirname(this.filePath), { recursive: true });
74801
75192
  await import_promises20.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
74802
75193
  await import_promises20.default.rename(tmp, this.filePath);
74803
75194
  }
@@ -74805,7 +75196,7 @@ var PublishedChannelStore = class {
74805
75196
 
74806
75197
  // src/extension/bundle-cache.ts
74807
75198
  var import_promises21 = __toESM(require("fs/promises"), 1);
74808
- var import_node_path79 = __toESM(require("path"), 1);
75199
+ var import_node_path81 = __toESM(require("path"), 1);
74809
75200
  var BundleCache = class {
74810
75201
  constructor(rootDir) {
74811
75202
  this.rootDir = rootDir;
@@ -74814,14 +75205,14 @@ var BundleCache = class {
74814
75205
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
74815
75206
  async write(snapshotHash, buffer) {
74816
75207
  await import_promises21.default.mkdir(this.rootDir, { recursive: true });
74817
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75208
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
74818
75209
  const tmp = `${file}.tmp`;
74819
75210
  await import_promises21.default.writeFile(tmp, buffer, { mode: 384 });
74820
75211
  await import_promises21.default.rename(tmp, file);
74821
75212
  }
74822
75213
  /** Returns the bundle bytes, or null when the file doesn't exist. */
74823
75214
  async read(snapshotHash) {
74824
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75215
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
74825
75216
  try {
74826
75217
  return await import_promises21.default.readFile(file);
74827
75218
  } catch (e) {
@@ -74831,7 +75222,7 @@ var BundleCache = class {
74831
75222
  }
74832
75223
  /** Idempotent — missing file is not an error. */
74833
75224
  async delete(snapshotHash) {
74834
- const file = import_node_path79.default.join(this.rootDir, `${snapshotHash}.zip`);
75225
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
74835
75226
  await import_promises21.default.rm(file, { force: true });
74836
75227
  }
74837
75228
  };
@@ -74852,26 +75243,26 @@ async function startDaemon(config) {
74852
75243
  },
74853
75244
  source: "daemon",
74854
75245
  sampling: logShippingCfg.sampling,
74855
- homeDir: import_node_os29.default.homedir()
75246
+ homeDir: import_node_os31.default.homedir()
74856
75247
  });
74857
- const logDir = import_node_path80.default.join(config.dataDir, "log");
74858
- import_node_fs62.default.mkdirSync(logDir, { recursive: true });
75248
+ const logDir = import_node_path82.default.join(config.dataDir, "log");
75249
+ import_node_fs64.default.mkdirSync(logDir, { recursive: true });
74859
75250
  const logger = createLogger({
74860
75251
  level: config.logLevel,
74861
- file: import_node_path80.default.join(logDir, "clawd.log"),
75252
+ file: import_node_path82.default.join(logDir, "clawd.log"),
74862
75253
  logClient
74863
75254
  });
74864
75255
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
74865
75256
  const screenIdleProbeLogger = createFileOnlyLogger({
74866
- file: import_node_path80.default.join(logDir, "screen-idle-probe.log"),
75257
+ file: import_node_path82.default.join(logDir, "screen-idle-probe.log"),
74867
75258
  level: "debug"
74868
75259
  });
74869
75260
  logger.info("screen-idle probe logger enabled", {
74870
- file: import_node_path80.default.join(logDir, "screen-idle-probe.log")
75261
+ file: import_node_path82.default.join(logDir, "screen-idle-probe.log")
74871
75262
  });
74872
75263
  const CAP_TARGETS = [
74873
- import_node_path80.default.join(logDir, "clawd.log"),
74874
- import_node_path80.default.join(logDir, "screen-idle-probe.log")
75264
+ import_node_path82.default.join(logDir, "clawd.log"),
75265
+ import_node_path82.default.join(logDir, "screen-idle-probe.log")
74875
75266
  ];
74876
75267
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
74877
75268
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -74993,8 +75384,9 @@ async function startDaemon(config) {
74993
75384
  const agents = new AgentsScanner();
74994
75385
  const history = new ClaudeHistoryReader();
74995
75386
  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");
75387
+ const personaStore = new PersonaStore(import_node_path82.default.join(config.dataDir, "personas"));
75388
+ const subscriptionChannelStore = new SubscriptionChannelStore({ dataDir: config.dataDir });
75389
+ const usersRoot = import_node_path82.default.join(config.dataDir, "users");
74998
75390
  const defaultsRoot = findDefaultsRoot(logger);
74999
75391
  if (defaultsRoot) {
75000
75392
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -75011,7 +75403,7 @@ async function startDaemon(config) {
75011
75403
  retirePersonaBuilder({ store: personaStore, logger });
75012
75404
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
75013
75405
  const dispatchStore = createDispatchStore({
75014
- filePath: import_node_path80.default.join(config.dataDir, "dispatch.json"),
75406
+ filePath: import_node_path82.default.join(config.dataDir, "dispatch.json"),
75015
75407
  now: () => Date.now(),
75016
75408
  onFlushError: (err) => logger.error("dispatch store flush failed", {
75017
75409
  reason: err instanceof Error ? err.message : String(err)
@@ -75020,7 +75412,7 @@ async function startDaemon(config) {
75020
75412
  await dispatchStore.load();
75021
75413
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
75022
75414
  const channelStore = createChannelStore({
75023
- filePath: import_node_path80.default.join(config.dataDir, "channels.json"),
75415
+ filePath: import_node_path82.default.join(config.dataDir, "channels.json"),
75024
75416
  now: () => Date.now(),
75025
75417
  genId: () => `ch-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75026
75418
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -75029,7 +75421,7 @@ async function startDaemon(config) {
75029
75421
  });
75030
75422
  await channelStore.load();
75031
75423
  const topicStore = createTopicStore({
75032
- filePath: import_node_path80.default.join(config.dataDir, "topics.json"),
75424
+ filePath: import_node_path82.default.join(config.dataDir, "topics.json"),
75033
75425
  now: () => Date.now(),
75034
75426
  genId: () => `tp-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`,
75035
75427
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -75056,12 +75448,12 @@ async function startDaemon(config) {
75056
75448
  });
75057
75449
  }
75058
75450
  });
75059
- const here = typeof __dirname === "string" ? __dirname : import_node_path80.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75451
+ const here = typeof __dirname === "string" ? __dirname : import_node_path82.default.dirname((0, import_node_url6.fileURLToPath)(import_meta10.url));
75060
75452
  const mcpConfigs = [];
75061
75453
  const secretsBundleRoot = findSecretsBundleRoot(logger);
75062
- const localSecretsDir = import_node_path80.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75454
+ const localSecretsDir = import_node_path82.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
75063
75455
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
75064
- const githubTokenFile = import_node_path80.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75456
+ const githubTokenFile = import_node_path82.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
75065
75457
  const githubIdentity = createGithubIdentity({
75066
75458
  resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
75067
75459
  store: (token) => storeGithubAuth({
@@ -75099,22 +75491,22 @@ async function startDaemon(config) {
75099
75491
  void githubIdentity.refresh();
75100
75492
  return renderPersonaMcpSecrets({
75101
75493
  personaId: personaId2,
75102
- personaDir: import_node_path80.default.join(config.dataDir, "personas", personaId2),
75494
+ personaDir: import_node_path82.default.join(config.dataDir, "personas", personaId2),
75103
75495
  secrets,
75104
- outDir: import_node_path80.default.join(config.dataDir, "persona-mcp"),
75496
+ outDir: import_node_path82.default.join(config.dataDir, "persona-mcp"),
75105
75497
  logger
75106
75498
  });
75107
75499
  };
75108
75500
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
75109
75501
  const dispatchServerCandidates = [
75110
- import_node_path80.default.join(here, "dispatch", "mcp-server.cjs"),
75502
+ import_node_path82.default.join(here, "dispatch", "mcp-server.cjs"),
75111
75503
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
75112
- import_node_path80.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75504
+ import_node_path82.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
75113
75505
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
75114
75506
  ];
75115
- const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75507
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75116
75508
  if (dispatchServerScriptPath) {
75117
- const dispatchLogPath = import_node_path80.default.join(logDir, "dispatch-mcp-server.log");
75509
+ const dispatchLogPath = import_node_path82.default.join(logDir, "dispatch-mcp-server.log");
75118
75510
  const dispatchCfgPath = writeDispatchMcpConfig({
75119
75511
  dataDir: config.dataDir,
75120
75512
  serverScriptPath: dispatchServerScriptPath,
@@ -75134,12 +75526,12 @@ async function startDaemon(config) {
75134
75526
  });
75135
75527
  }
75136
75528
  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")
75529
+ import_node_path82.default.join(here, "ticket", "mcp-server.cjs"),
75530
+ import_node_path82.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
75139
75531
  ];
75140
- const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75532
+ const ticketServerScriptPath = ticketServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75141
75533
  if (ticketServerScriptPath) {
75142
- const ticketLogPath = import_node_path80.default.join(logDir, "ticket-mcp-server.log");
75534
+ const ticketLogPath = import_node_path82.default.join(logDir, "ticket-mcp-server.log");
75143
75535
  const ticketCfgPath = writeTicketMcpConfig({
75144
75536
  dataDir: config.dataDir,
75145
75537
  serverScriptPath: ticketServerScriptPath,
@@ -75161,12 +75553,12 @@ async function startDaemon(config) {
75161
75553
  });
75162
75554
  }
75163
75555
  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")
75556
+ import_node_path82.default.join(here, "shift", "mcp-server.cjs"),
75557
+ import_node_path82.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
75166
75558
  ];
75167
- const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75559
+ const shiftServerScriptPath = shiftServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75168
75560
  if (shiftServerScriptPath) {
75169
- const shiftLogPath = import_node_path80.default.join(logDir, "shift-mcp-server.log");
75561
+ const shiftLogPath = import_node_path82.default.join(logDir, "shift-mcp-server.log");
75170
75562
  const shiftCfgPath = await writeShiftMcpConfig({
75171
75563
  dataDir: config.dataDir,
75172
75564
  serverScriptPath: shiftServerScriptPath,
@@ -75187,12 +75579,12 @@ async function startDaemon(config) {
75187
75579
  );
75188
75580
  }
75189
75581
  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")
75582
+ import_node_path82.default.join(here, "inbox", "mcp-server.cjs"),
75583
+ import_node_path82.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
75192
75584
  ];
75193
- const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75585
+ const inboxServerScriptPath = inboxServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75194
75586
  if (inboxServerScriptPath) {
75195
- const inboxLogPath = import_node_path80.default.join(logDir, "inbox-mcp-server.log");
75587
+ const inboxLogPath = import_node_path82.default.join(logDir, "inbox-mcp-server.log");
75196
75588
  const inboxCfgPath = await writeInboxMcpConfig({
75197
75589
  dataDir: config.dataDir,
75198
75590
  serverScriptPath: inboxServerScriptPath,
@@ -75213,10 +75605,10 @@ async function startDaemon(config) {
75213
75605
  );
75214
75606
  }
75215
75607
  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")
75608
+ import_node_path82.default.join(here, "peer-ops", "mcp-server.cjs"),
75609
+ import_node_path82.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
75218
75610
  ];
75219
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75611
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75220
75612
  if (peerOpsServerScriptPath) {
75221
75613
  const peerOpsCfgPath = writePeerOpsMcpConfig({
75222
75614
  dataDir: config.dataDir,
@@ -75236,12 +75628,12 @@ async function startDaemon(config) {
75236
75628
  );
75237
75629
  }
75238
75630
  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")
75631
+ import_node_path82.default.join(here, "rpc-tool", "mcp-server.cjs"),
75632
+ import_node_path82.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
75241
75633
  ];
75242
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75634
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75243
75635
  if (rpcToolServerScriptPath) {
75244
- const rpcToolLogPath = import_node_path80.default.join(logDir, "rpc-tool-mcp-server.log");
75636
+ const rpcToolLogPath = import_node_path82.default.join(logDir, "rpc-tool-mcp-server.log");
75245
75637
  const rpcToolCfgPath = writeRpcToolMcpConfig({
75246
75638
  dataDir: config.dataDir,
75247
75639
  serverScriptPath: rpcToolServerScriptPath,
@@ -75262,7 +75654,7 @@ async function startDaemon(config) {
75262
75654
  );
75263
75655
  }
75264
75656
  const shiftStore = createShiftStore({
75265
- filePath: import_node_path80.default.join(config.dataDir, "shift.json"),
75657
+ filePath: import_node_path82.default.join(config.dataDir, "shift.json"),
75266
75658
  ownerIdProvider: () => ownerPrincipalId,
75267
75659
  now: () => Date.now()
75268
75660
  });
@@ -75284,7 +75676,7 @@ async function startDaemon(config) {
75284
75676
  getAdapter,
75285
75677
  historyReader: history,
75286
75678
  dataDir: config.dataDir,
75287
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
75679
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75288
75680
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
75289
75681
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
75290
75682
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -75341,10 +75733,10 @@ async function startDaemon(config) {
75341
75733
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
75342
75734
  attachmentGroup: {
75343
75735
  onFileEdit: (input) => {
75344
- const absPath = import_node_path80.default.isAbsolute(input.relPath) ? input.relPath : import_node_path80.default.join(input.cwd, input.relPath);
75736
+ const absPath = import_node_path82.default.isAbsolute(input.relPath) ? input.relPath : import_node_path82.default.join(input.cwd, input.relPath);
75345
75737
  let size = 0;
75346
75738
  try {
75347
- size = import_node_fs62.default.statSync(absPath).size;
75739
+ size = import_node_fs64.default.statSync(absPath).size;
75348
75740
  } catch (err) {
75349
75741
  logger.warn("attachment.onFileEdit stat failed", {
75350
75742
  sessionId: input.sessionId,
@@ -75385,9 +75777,9 @@ async function startDaemon(config) {
75385
75777
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
75386
75778
  }
75387
75779
  const projectsStore = new ProjectsStore({
75388
- file: import_node_path80.default.join(config.dataDir, "projects.json"),
75780
+ file: import_node_path82.default.join(config.dataDir, "projects.json"),
75389
75781
  clawdDir: config.dataDir,
75390
- codexStateFile: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex", ".codex-global-state.json"),
75782
+ codexStateFile: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex", ".codex-global-state.json"),
75391
75783
  logger
75392
75784
  });
75393
75785
  const observer = new SessionObserver({
@@ -75452,13 +75844,13 @@ async function startDaemon(config) {
75452
75844
  logger
75453
75845
  });
75454
75846
  registerAdapter("claude", claudeAdapter);
75455
- const codexIsolatedHome = import_node_path80.default.join(config.dataDir, "codex-home");
75847
+ const codexIsolatedHome = import_node_path82.default.join(config.dataDir, "codex-home");
75456
75848
  try {
75457
- import_node_fs62.default.mkdirSync(codexIsolatedHome, { recursive: true });
75849
+ import_node_fs64.default.mkdirSync(codexIsolatedHome, { recursive: true });
75458
75850
  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);
75851
+ const link = import_node_path82.default.join(codexIsolatedHome, f2);
75852
+ const target = import_node_path82.default.join(import_node_os31.default.homedir(), ".codex", f2);
75853
+ if (!import_node_fs64.default.existsSync(link) && import_node_fs64.default.existsSync(target)) import_node_fs64.default.symlinkSync(target, link);
75462
75854
  }
75463
75855
  } catch (err) {
75464
75856
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -75469,17 +75861,17 @@ async function startDaemon(config) {
75469
75861
  logger,
75470
75862
  historyReader: new CodexHistoryReader({
75471
75863
  roots: codexRolloutRoots(config.dataDir),
75472
- sharedHome: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex"),
75864
+ sharedHome: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex"),
75473
75865
  logger
75474
75866
  }),
75475
75867
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
75476
75868
  codexHomeFor: (cwd) => resolveCodexHome({
75477
75869
  cwd,
75478
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
75870
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75479
75871
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
75480
75872
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
75481
75873
  projectPaths: projectsStore.listMerged().map((x2) => x2.path),
75482
- sharedHome: import_node_path80.default.join(import_node_os29.default.homedir(), ".codex"),
75874
+ sharedHome: import_node_path82.default.join(import_node_os31.default.homedir(), ".codex"),
75483
75875
  isolatedHome: codexIsolatedHome
75484
75876
  }),
75485
75877
  // 附件图片验签:与 http-router /files 路由同一把 secret
@@ -75504,10 +75896,10 @@ async function startDaemon(config) {
75504
75896
  );
75505
75897
  registerAdapter(PI_CLOUD_TOOL_ID, new CloudPiAdapter({ client: cloudGateway, history: cloudHistorySource, logger }));
75506
75898
  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")
75899
+ import_node_path82.default.join(here, "pi-mcp-bridge", "extension.cjs"),
75900
+ import_node_path82.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
75509
75901
  ];
75510
- const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs62.default.existsSync(p3));
75902
+ const piMcpBridgePath = piMcpBridgeCandidates.find((p3) => import_node_fs64.default.existsSync(p3));
75511
75903
  if (piMcpBridgePath) {
75512
75904
  logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
75513
75905
  } else {
@@ -75724,6 +76116,7 @@ async function startDaemon(config) {
75724
76116
  topicStore,
75725
76117
  dispatchStore,
75726
76118
  masterDataDir: config.dataDir,
76119
+ subscriptionChannelStore,
75727
76120
  // 建话题即起该话题的 Master session(1:1)。走与 session:create 同一条 manager.create
75728
76121
  // 链路,不复制会话创建逻辑;creatorPrincipalId 用本机 deviceId(owner ctx 的 principal.id)。
75729
76122
  createMasterSession: ({ label }) => {
@@ -75802,11 +76195,11 @@ async function startDaemon(config) {
75802
76195
  // 'persona/<pid>/owner',default 走 'default'。
75803
76196
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
75804
76197
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
75805
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
76198
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75806
76199
  usersRoot
75807
76200
  },
75808
76201
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
75809
- personaRoot: import_node_path80.default.join(config.dataDir, "personas"),
76202
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
75810
76203
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
75811
76204
  usersRoot,
75812
76205
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -75952,7 +76345,7 @@ async function startDaemon(config) {
75952
76345
  sourceSessionId: args.sourceSessionId
75953
76346
  });
75954
76347
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
75955
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os29.default.homedir());
76348
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os31.default.homedir());
75956
76349
  logger.info("dispatch.spawnB.source-resolved", {
75957
76350
  dispatchId: args.dispatchId,
75958
76351
  sourceJsonlPath,
@@ -76027,6 +76420,7 @@ async function startDaemon(config) {
76027
76420
  }
76028
76421
  let lastPathRefresh = 0;
76029
76422
  const deployHandlers = buildDeployHandlers({
76423
+ channelStore: subscriptionChannelStore,
76030
76424
  hasPersona: (personaId2) => personaStore.has(personaId2),
76031
76425
  personaDir: (personaId2) => personaStore.personaDirPath(personaId2),
76032
76426
  // 发布前落闸要看它现在配的引擎和模型(云上只跑 codex / pi,且模型跟着这次发布走)
@@ -76111,7 +76505,7 @@ async function startDaemon(config) {
76111
76505
  });
76112
76506
  shiftScheduler.start();
76113
76507
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
76114
- const larkBotStore = createLarkBotBindingStore(import_node_path80.default.join(config.dataDir, "personas"));
76508
+ const larkBotStore = createLarkBotBindingStore(import_node_path82.default.join(config.dataDir, "personas"));
76115
76509
  const larkBotCloud = createLarkBotCloudClient({
76116
76510
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
76117
76511
  getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
@@ -76123,7 +76517,7 @@ async function startDaemon(config) {
76123
76517
  store: larkBotStore,
76124
76518
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
76125
76519
  // 图片落 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"),
76520
+ mediaRootFor: (chatId) => import_node_path82.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
76127
76521
  isShuttingDown: () => larkDraining,
76128
76522
  logger: {
76129
76523
  warn: (msg) => logger.warn(msg),
@@ -76423,8 +76817,8 @@ async function startDaemon(config) {
76423
76817
  const lines = [
76424
76818
  `Tunnel: ${r2.url}`,
76425
76819
  ...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")}`
76820
+ `Frpc config: ${import_node_path82.default.join(config.dataDir, "frpc.toml")}`,
76821
+ `Frpc log: ${import_node_path82.default.join(logDir, "frpc.log")}`
76428
76822
  ];
76429
76823
  const width2 = Math.max(...lines.map((l2) => l2.length));
76430
76824
  const bar = "\u2550".repeat(width2 + 4);
@@ -76437,8 +76831,8 @@ ${bar}
76437
76831
 
76438
76832
  `);
76439
76833
  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 });
76834
+ const connectPath = import_node_path82.default.join(config.dataDir, "connect.txt");
76835
+ import_node_fs64.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
76442
76836
  } catch {
76443
76837
  }
76444
76838
  } catch (err) {
@@ -76536,9 +76930,9 @@ ${bar}
76536
76930
  };
76537
76931
  }
76538
76932
  function migrateDropPersonsDir(dataDir) {
76539
- const dir = import_node_path80.default.join(dataDir, "persons");
76933
+ const dir = import_node_path82.default.join(dataDir, "persons");
76540
76934
  try {
76541
- import_node_fs62.default.rmSync(dir, { recursive: true, force: true });
76935
+ import_node_fs64.default.rmSync(dir, { recursive: true, force: true });
76542
76936
  } catch {
76543
76937
  }
76544
76938
  }