@clawos-dev/clawd 0.2.502 → 0.2.504

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: path100, errorMaps, issueData } = params;
454
- const fullPath = [...path100, ...issueData.path || []];
453
+ const { data, path: path101, errorMaps, issueData } = params;
454
+ const fullPath = [...path101, ...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, path100, key) {
765
+ constructor(parent, value, path101, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path100;
769
+ this._path = path101;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -5951,7 +5951,24 @@ var init_contact_handshake = __esm({
5951
5951
  });
5952
5952
 
5953
5953
  // ../protocol/src/environment-schemas.ts
5954
- var EnvCliSchema, EnvSecretSchema, EnvAssetSchema, ConnectorNameSchema, EnvConnectorSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
5954
+ function connectorBlockers(c) {
5955
+ if (!c.credentialSource) return [`\u8FDE\u63A5\u5668 ${c.name} \u8FD8\u6CA1\u5B9A\u51ED\u636E\u6765\u6E90\uFF08\u65E0 / \u5171\u4EAB / \u4E2A\u4EBA\uFF09`];
5956
+ const out = [];
5957
+ if (c.credentialSource === "personal") {
5958
+ if (!c.auth) out.push(`\u8FDE\u63A5\u5668 ${c.name} \u8FD8\u6CA1\u9009\u5173\u8054\u8FD8\u662F\u586B\u5199`);
5959
+ else if (c.auth === "oauth" && c.kind === "env") out.push(`\u8FDE\u63A5\u5668 ${c.name} \u662F\u8FDB\u7A0B\u578B\uFF08stdio MCP / CLI\uFF09\uFF0C\u53EA\u80FD\u586B\u5199\u4E0D\u80FD\u5173\u8054`);
5960
+ else if (c.auth === "fields" && c.fields.length === 0) out.push(`\u8FDE\u63A5\u5668 ${c.name} \u8981\u586B\u7684\u683C\u8FD8\u6CA1\u5217`);
5961
+ }
5962
+ if (c.credentialSource === "shared" && c.fields.length === 0) out.push(`\u8FDE\u63A5\u5668 ${c.name} \u9009\u4E86\u5171\u4EAB\uFF0C\u4F46\u8981\u586B\u7684\u683C\u8FD8\u6CA1\u5217`);
5963
+ return out;
5964
+ }
5965
+ function sharedConnectorSecrets(m2) {
5966
+ return m2.connectors.filter((c) => c.credentialSource === "shared" && c.fields.length > 0).map((c) => ({ name: c.name, env: [...c.fields] }));
5967
+ }
5968
+ function requiredSecretEnvNames(m2) {
5969
+ return [.../* @__PURE__ */ new Set([...m2.secrets.flatMap((s) => s.env), ...sharedConnectorSecrets(m2).flatMap((s) => s.env)])];
5970
+ }
5971
+ var EnvCliSchema, EnvSecretSchema, EnvAssetSchema, ConnectorNameSchema, CONNECTOR_KINDS, CONNECTOR_RUNNERS, CONNECTOR_PROTOCOLS, CREDENTIAL_SOURCES, CONNECTOR_AUTHS, ConnectorFieldSchema, EnvConnectorSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
5955
5972
  var init_environment_schemas = __esm({
5956
5973
  "../protocol/src/environment-schemas.ts"() {
5957
5974
  "use strict";
@@ -5994,21 +6011,36 @@ var init_environment_schemas = __esm({
5994
6011
  name: external_exports.string().min(1)
5995
6012
  });
5996
6013
  ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
5997
- EnvConnectorSchema = external_exports.object({ name: ConnectorNameSchema });
6014
+ CONNECTOR_KINDS = ["proxy", "env"];
6015
+ CONNECTOR_RUNNERS = ["mcp", "cli"];
6016
+ CONNECTOR_PROTOCOLS = ["bearer", "lark-sidecar"];
6017
+ CREDENTIAL_SOURCES = ["none", "shared", "personal"];
6018
+ CONNECTOR_AUTHS = ["oauth", "fields"];
6019
+ ConnectorFieldSchema = external_exports.string().regex(/^[A-Z][A-Z0-9_]*$/, "\u8981\u586B\u7684\u683C\u7684\u540D\u5B57\u53EA\u80FD\u662F\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF\uFF0C\u4E14\u4EE5\u5B57\u6BCD\u5F00\u5934");
6020
+ EnvConnectorSchema = external_exports.object({
6021
+ name: ConnectorNameSchema,
6022
+ kind: external_exports.enum(CONNECTOR_KINDS),
6023
+ runner: external_exports.enum(CONNECTOR_RUNNERS),
6024
+ protocol: external_exports.enum(CONNECTOR_PROTOCOLS).optional(),
6025
+ id: external_exports.string().min(1),
6026
+ credentialSource: external_exports.enum(CREDENTIAL_SOURCES).optional(),
6027
+ auth: external_exports.enum(CONNECTOR_AUTHS).optional(),
6028
+ fields: external_exports.array(ConnectorFieldSchema).default([]),
6029
+ http: external_exports.object({ url: external_exports.string().min(1), headers: external_exports.record(external_exports.string(), external_exports.string()) }).optional()
6030
+ });
5998
6031
  MANIFEST_BODY = {
5999
6032
  clis: external_exports.array(EnvCliSchema),
6000
6033
  secrets: external_exports.array(EnvSecretSchema),
6001
6034
  assets: external_exports.array(EnvAssetSchema),
6002
6035
  /**
6003
- * 装了哪些连接器(design 2026-09-09-cloud-connector-credentials §7.1)。**字符串数组**,
6004
- * 是四段里唯一不是 `{name}` 对象数组的一段:连接器没有任何附加属性,包一层对象只是多一层壳。
6036
+ * 装了哪些连接器(design 2026-09-11-mcp-connector §3.1)。一条一个对象,形状见 `EnvConnectorSchema`。
6005
6037
  *
6006
- * 不复用 secrets:那段说的是「需要一份值,由部署者填」,这里没有值要填;
6007
- * 不从 clis 推断:lark-cli 在底座里,每个 persona 都有它,推不出任何东西。
6038
+ * 不复用 secrets:那段说的是「需要一份值,由部署者填」;连接器的凭据谁出是单据上点出来的,
6039
+ * 三种来源里只有「共享」才落到 Secrets,而且靠 `sharedConnectorSecrets` 在消费处并入,不写进那段。
6008
6040
  *
6009
- * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装,扫描器照样会报。
6041
+ * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装。
6010
6042
  */
6011
- connectors: external_exports.array(ConnectorNameSchema).default([])
6043
+ connectors: external_exports.array(EnvConnectorSchema).default([])
6012
6044
  };
6013
6045
  EnvManifestBodySchema = external_exports.object(MANIFEST_BODY);
6014
6046
  EnvironmentManifestSchema = external_exports.object({
@@ -6198,7 +6230,8 @@ var init_deploy_schemas = __esm({
6198
6230
  personaId: external_exports.string().min(1),
6199
6231
  kind: external_exports.enum(["cli", "secret", "asset", "connector"]),
6200
6232
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
6201
- // connector 的 item 只有 name,落进清单时只留名字(manifest.connectors 是字符串数组)
6233
+ // connector 的 item 是 butler 报的 CLI 连接器({ name, fields? }),daemon 补齐 kind / runner / id 后落进清单;
6234
+ // MCP 连接器不经这里——由 daemon 从 .mcp.json 机械列出(design 2026-09-11-mcp-connector §3.2)
6202
6235
  item: external_exports.record(external_exports.string(), external_exports.unknown()),
6203
6236
  // 这条发现的来历(一句人话 + 原文出处),形状同 EnvEvidence,target 由 handler 从 kind+name 派生
6204
6237
  evidence: external_exports.object({
@@ -6238,6 +6271,43 @@ var init_contact_remote_access = __esm({
6238
6271
  }
6239
6272
  });
6240
6273
 
6274
+ // ../protocol/src/cloud-connector-schemas.ts
6275
+ var CloudConnectorsListArgsSchema, CLOUD_CONNECTOR_STATUSES, CLOUD_CONNECTOR_ACTIONS, CloudConnectorStatusSchema, CloudConnectorsListResultSchema, CloudConnectorFillArgsSchema;
6276
+ var init_cloud_connector_schemas = __esm({
6277
+ "../protocol/src/cloud-connector-schemas.ts"() {
6278
+ "use strict";
6279
+ init_zod();
6280
+ init_environment_schemas();
6281
+ CloudConnectorsListArgsSchema = external_exports.object({
6282
+ /** 本机 registry 里的键(`<gateway 名>-cloud`);daemon 从它的 `cloud.personaId` 找 gateway 登记行 */
6283
+ personaId: external_exports.string().min(1)
6284
+ }).strict();
6285
+ CLOUD_CONNECTOR_STATUSES = ["connected", "missing", "reauth"];
6286
+ CLOUD_CONNECTOR_ACTIONS = ["link", "fill"];
6287
+ CloudConnectorStatusSchema = external_exports.object({
6288
+ name: ConnectorNameSchema,
6289
+ id: external_exports.string().min(1),
6290
+ kind: external_exports.enum(CONNECTOR_KINDS),
6291
+ runner: external_exports.enum(CONNECTOR_RUNNERS),
6292
+ auth: external_exports.enum(CONNECTOR_AUTHS),
6293
+ status: external_exports.enum(CLOUD_CONNECTOR_STATUSES),
6294
+ action: external_exports.enum(CLOUD_CONNECTOR_ACTIONS),
6295
+ /** 只有 `action: link` 且没连上(或要重新关联)时有;它不是凭证,几分钟过期 */
6296
+ authUrl: external_exports.string().optional(),
6297
+ fields: external_exports.array(ConnectorFieldSchema)
6298
+ }).strict();
6299
+ CloudConnectorsListResultSchema = external_exports.object({
6300
+ connectors: external_exports.array(CloudConnectorStatusSchema)
6301
+ }).strict();
6302
+ CloudConnectorFillArgsSchema = external_exports.object({
6303
+ personaId: external_exports.string().min(1),
6304
+ name: ConnectorNameSchema,
6305
+ /** 格名 → 值。格名必须是该连接器声明过的 `fields` 之一,中心校验 */
6306
+ values: external_exports.record(ConnectorFieldSchema, external_exports.string().min(1))
6307
+ }).strict();
6308
+ }
6309
+ });
6310
+
6241
6311
  // ../protocol/src/contact.ts
6242
6312
  var ContactSchema, ContactWireSchema, ContactRemoveArgsSchema, ContactRemoveOkSchema, ContactListOkSchema, ContactAddedFrameSchema, ContactRemovedFrameSchema, ContactPinArgsSchema, ContactSetNoteArgsSchema, ContactSetNoteOkSchema, ContactPinOkSchema, ContactPinnedFrameSchema;
6243
6313
  var init_contact = __esm({
@@ -8781,6 +8851,7 @@ var init_methods = __esm({
8781
8851
  init_contact_handshake();
8782
8852
  init_deploy_schemas();
8783
8853
  init_contact_remote_access();
8854
+ init_cloud_connector_schemas();
8784
8855
  init_contact();
8785
8856
  init_feishu_auth();
8786
8857
  init_dispatch();
@@ -9016,6 +9087,15 @@ var init_methods = __esm({
9016
9087
  summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08gh run rerun --job\uFF09\u3002**\u540C\u4E00\u4E2A commit\u3001\u540C\u4E00\u4EFD\u8F93\u5165**\uFF0C\u4E0D\u4EA7\u751F\u65B0\u63D0\u4EA4\u2014\u2014\u6539\u4E86 persona \u5185\u5BB9\u6216\u51ED\u636E\u8981\u8D70 deploy:release\u3002jobId \u5FC5\u987B\u5C5E\u4E8E\u6700\u65B0\u90A3\u6761 run\uFF1Bowner-only",
9017
9088
  args: DeployRerunJobArgsSchema
9018
9089
  },
9090
+ // ---- cloud:connectors:*(云 persona 卡片上的连接器;design 2026-09-11-mcp-connector §3.8)----
9091
+ "cloud:connectors:list": {
9092
+ summary: "\u4E91\u4E0A persona \u5361\u7247\u4E0A\u7684\u8FDE\u63A5\u5668\u533A\uFF1A\u8FD9\u4E2A persona \u58F0\u660E\u7684\u3001**\u8981\u4F7F\u7528\u8005\u672C\u4EBA\u6388\u6743\u7684**\u8FDE\u63A5\u5668\u5404\u81EA\u8FDE\u6CA1\u8FDE\u4E0A\uFF08connected / missing / reauth\uFF09\u3001\u6309\u94AE\u662F\u5173\u8054\uFF08\u5E26\u73B0\u7B97\u7684 authUrl\uFF09\u8FD8\u662F\u586B\u5199\uFF08\u5E26\u8981\u586B\u7684\u683C\uFF09\u3002daemon \u62FF gateway \u767B\u8BB0\u884C + \u672C\u673A\u767B\u5F55\u51ED\u8BC1\u5411\u4E2D\u5FC3\u4EE3\u67E5\uFF0C\u51ED\u8BC1\u4E0D\u51FA ws\uFF1Bowner-only",
9093
+ args: CloudConnectorsListArgsSchema
9094
+ },
9095
+ "cloud:connectors:fill": {
9096
+ summary: "\u586B\u5199\u578B\u8FDE\u63A5\u5668\uFF1A\u628A\u4F7F\u7528\u8005\u672C\u4EBA\u7684\u51ED\u636E\u503C\u4EA4\u7ED9\u4E2D\u5FC3\u52A0\u5BC6\u5165\u5E93\uFF08\u4E00\u6B21\u586B\u5199\u5168\u5C40\u5171\u7528\uFF09\u3002**\u8FD9\u662F\u503C\u552F\u4E00\u7684\u5165\u53E3**\uFF1A\u5165\u53C2\u4E0D\u8FDB\u65E5\u5FD7\u3001\u54CD\u5E94\u4E0D\u56DE\u663E\u3001\u672C\u673A\u4E0D\u843D\u76D8\uFF1B\u683C\u540D\u5FC5\u987B\u662F\u8BE5\u8FDE\u63A5\u5668\u58F0\u660E\u8FC7\u7684\uFF1Bowner-only",
9097
+ args: CloudConnectorFillArgsSchema
9098
+ },
9019
9099
  "shift:list": {
9020
9100
  summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
9021
9101
  args: NO_ARGS
@@ -9728,6 +9808,7 @@ var init_runtime = __esm({
9728
9808
  init_schemas();
9729
9809
  init_frames();
9730
9810
  init_environment_schemas();
9811
+ init_cloud_connector_schemas();
9731
9812
  init_deploy_schemas();
9732
9813
  init_persona_schemas();
9733
9814
  init_persona_mode();
@@ -10028,8 +10109,8 @@ var require_req = __commonJS({
10028
10109
  if (req.originalUrl) {
10029
10110
  _req.url = req.originalUrl;
10030
10111
  } else {
10031
- const path100 = req.path;
10032
- _req.url = typeof path100 === "string" ? path100 : req.url ? req.url.path || req.url : void 0;
10112
+ const path101 = req.path;
10113
+ _req.url = typeof path101 === "string" ? path101 : req.url ? req.url.path || req.url : void 0;
10033
10114
  }
10034
10115
  if (req.query) {
10035
10116
  _req.query = req.query;
@@ -10194,14 +10275,14 @@ var require_redact = __commonJS({
10194
10275
  }
10195
10276
  return obj;
10196
10277
  }
10197
- function parsePath(path100) {
10278
+ function parsePath(path101) {
10198
10279
  const parts = [];
10199
10280
  let current = "";
10200
10281
  let inBrackets = false;
10201
10282
  let inQuotes = false;
10202
10283
  let quoteChar = "";
10203
- for (let i = 0; i < path100.length; i++) {
10204
- const char = path100[i];
10284
+ for (let i = 0; i < path101.length; i++) {
10285
+ const char = path101[i];
10205
10286
  if (!inBrackets && char === ".") {
10206
10287
  if (current) {
10207
10288
  parts.push(current);
@@ -10332,10 +10413,10 @@ var require_redact = __commonJS({
10332
10413
  return current;
10333
10414
  }
10334
10415
  function redactPaths(obj, paths, censor, remove = false) {
10335
- for (const path100 of paths) {
10336
- const parts = parsePath(path100);
10416
+ for (const path101 of paths) {
10417
+ const parts = parsePath(path101);
10337
10418
  if (parts.includes("*")) {
10338
- redactWildcardPath(obj, parts, censor, path100, remove);
10419
+ redactWildcardPath(obj, parts, censor, path101, remove);
10339
10420
  } else {
10340
10421
  if (remove) {
10341
10422
  removeKey(obj, parts);
@@ -10420,8 +10501,8 @@ var require_redact = __commonJS({
10420
10501
  }
10421
10502
  } else {
10422
10503
  if (afterWildcard.includes("*")) {
10423
- const wrappedCensor = typeof censor === "function" ? (value, path100) => {
10424
- const fullPath = [...pathArray.slice(0, pathLength), ...path100];
10504
+ const wrappedCensor = typeof censor === "function" ? (value, path101) => {
10505
+ const fullPath = [...pathArray.slice(0, pathLength), ...path101];
10425
10506
  return censor(value, fullPath);
10426
10507
  } : censor;
10427
10508
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10456,8 +10537,8 @@ var require_redact = __commonJS({
10456
10537
  return null;
10457
10538
  }
10458
10539
  const pathStructure = /* @__PURE__ */ new Map();
10459
- for (const path100 of pathsToClone) {
10460
- const parts = parsePath(path100);
10540
+ for (const path101 of pathsToClone) {
10541
+ const parts = parsePath(path101);
10461
10542
  let current = pathStructure;
10462
10543
  for (let i = 0; i < parts.length; i++) {
10463
10544
  const part = parts[i];
@@ -10509,24 +10590,24 @@ var require_redact = __commonJS({
10509
10590
  }
10510
10591
  return cloneSelectively(obj, pathStructure);
10511
10592
  }
10512
- function validatePath(path100) {
10513
- if (typeof path100 !== "string") {
10593
+ function validatePath(path101) {
10594
+ if (typeof path101 !== "string") {
10514
10595
  throw new Error("Paths must be (non-empty) strings");
10515
10596
  }
10516
- if (path100 === "") {
10597
+ if (path101 === "") {
10517
10598
  throw new Error("Invalid redaction path ()");
10518
10599
  }
10519
- if (path100.includes("..")) {
10520
- throw new Error(`Invalid redaction path (${path100})`);
10600
+ if (path101.includes("..")) {
10601
+ throw new Error(`Invalid redaction path (${path101})`);
10521
10602
  }
10522
- if (path100.includes(",")) {
10523
- throw new Error(`Invalid redaction path (${path100})`);
10603
+ if (path101.includes(",")) {
10604
+ throw new Error(`Invalid redaction path (${path101})`);
10524
10605
  }
10525
10606
  let bracketCount = 0;
10526
10607
  let inQuotes = false;
10527
10608
  let quoteChar = "";
10528
- for (let i = 0; i < path100.length; i++) {
10529
- const char = path100[i];
10609
+ for (let i = 0; i < path101.length; i++) {
10610
+ const char = path101[i];
10530
10611
  if ((char === '"' || char === "'") && bracketCount > 0) {
10531
10612
  if (!inQuotes) {
10532
10613
  inQuotes = true;
@@ -10540,20 +10621,20 @@ var require_redact = __commonJS({
10540
10621
  } else if (char === "]" && !inQuotes) {
10541
10622
  bracketCount--;
10542
10623
  if (bracketCount < 0) {
10543
- throw new Error(`Invalid redaction path (${path100})`);
10624
+ throw new Error(`Invalid redaction path (${path101})`);
10544
10625
  }
10545
10626
  }
10546
10627
  }
10547
10628
  if (bracketCount !== 0) {
10548
- throw new Error(`Invalid redaction path (${path100})`);
10629
+ throw new Error(`Invalid redaction path (${path101})`);
10549
10630
  }
10550
10631
  }
10551
10632
  function validatePaths(paths) {
10552
10633
  if (!Array.isArray(paths)) {
10553
10634
  throw new TypeError("paths must be an array");
10554
10635
  }
10555
- for (const path100 of paths) {
10556
- validatePath(path100);
10636
+ for (const path101 of paths) {
10637
+ validatePath(path101);
10557
10638
  }
10558
10639
  }
10559
10640
  function slowRedact(options = {}) {
@@ -10721,8 +10802,8 @@ var require_redaction = __commonJS({
10721
10802
  if (shape[k2] === null) {
10722
10803
  o[k2] = (value) => topCensor(value, [k2]);
10723
10804
  } else {
10724
- const wrappedCensor = typeof censor === "function" ? (value, path100) => {
10725
- return censor(value, [k2, ...path100]);
10805
+ const wrappedCensor = typeof censor === "function" ? (value, path101) => {
10806
+ return censor(value, [k2, ...path101]);
10726
10807
  } : censor;
10727
10808
  o[k2] = Redact({
10728
10809
  paths: shape[k2],
@@ -10940,10 +11021,10 @@ var require_atomic_sleep = __commonJS({
10940
11021
  var require_sonic_boom = __commonJS({
10941
11022
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10942
11023
  "use strict";
10943
- var fs91 = require("fs");
11024
+ var fs92 = require("fs");
10944
11025
  var EventEmitter3 = require("events");
10945
11026
  var inherits = require("util").inherits;
10946
- var path100 = require("path");
11027
+ var path101 = require("path");
10947
11028
  var sleep2 = require_atomic_sleep();
10948
11029
  var assert = require("assert");
10949
11030
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10997,20 +11078,20 @@ var require_sonic_boom = __commonJS({
10997
11078
  const mode = sonic.mode;
10998
11079
  if (sonic.sync) {
10999
11080
  try {
11000
- if (sonic.mkdir) fs91.mkdirSync(path100.dirname(file), { recursive: true });
11001
- const fd = fs91.openSync(file, flags, mode);
11081
+ if (sonic.mkdir) fs92.mkdirSync(path101.dirname(file), { recursive: true });
11082
+ const fd = fs92.openSync(file, flags, mode);
11002
11083
  fileOpened(null, fd);
11003
11084
  } catch (err) {
11004
11085
  fileOpened(err);
11005
11086
  throw err;
11006
11087
  }
11007
11088
  } else if (sonic.mkdir) {
11008
- fs91.mkdir(path100.dirname(file), { recursive: true }, (err) => {
11089
+ fs92.mkdir(path101.dirname(file), { recursive: true }, (err) => {
11009
11090
  if (err) return fileOpened(err);
11010
- fs91.open(file, flags, mode, fileOpened);
11091
+ fs92.open(file, flags, mode, fileOpened);
11011
11092
  });
11012
11093
  } else {
11013
- fs91.open(file, flags, mode, fileOpened);
11094
+ fs92.open(file, flags, mode, fileOpened);
11014
11095
  }
11015
11096
  }
11016
11097
  function SonicBoom(opts) {
@@ -11051,8 +11132,8 @@ var require_sonic_boom = __commonJS({
11051
11132
  this.flush = flushBuffer;
11052
11133
  this.flushSync = flushBufferSync;
11053
11134
  this._actualWrite = actualWriteBuffer;
11054
- fsWriteSync = () => fs91.writeSync(this.fd, this._writingBuf);
11055
- fsWrite = () => fs91.write(this.fd, this._writingBuf, this.release);
11135
+ fsWriteSync = () => fs92.writeSync(this.fd, this._writingBuf);
11136
+ fsWrite = () => fs92.write(this.fd, this._writingBuf, this.release);
11056
11137
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
11057
11138
  this._writingBuf = "";
11058
11139
  this.write = write;
@@ -11061,15 +11142,15 @@ var require_sonic_boom = __commonJS({
11061
11142
  this._actualWrite = actualWrite;
11062
11143
  fsWriteSync = () => {
11063
11144
  if (Buffer.isBuffer(this._writingBuf)) {
11064
- return fs91.writeSync(this.fd, this._writingBuf);
11145
+ return fs92.writeSync(this.fd, this._writingBuf);
11065
11146
  }
11066
- return fs91.writeSync(this.fd, this._writingBuf, "utf8");
11147
+ return fs92.writeSync(this.fd, this._writingBuf, "utf8");
11067
11148
  };
11068
11149
  fsWrite = () => {
11069
11150
  if (Buffer.isBuffer(this._writingBuf)) {
11070
- return fs91.write(this.fd, this._writingBuf, this.release);
11151
+ return fs92.write(this.fd, this._writingBuf, this.release);
11071
11152
  }
11072
- return fs91.write(this.fd, this._writingBuf, "utf8", this.release);
11153
+ return fs92.write(this.fd, this._writingBuf, "utf8", this.release);
11073
11154
  };
11074
11155
  } else {
11075
11156
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -11126,7 +11207,7 @@ var require_sonic_boom = __commonJS({
11126
11207
  }
11127
11208
  }
11128
11209
  if (this._fsync) {
11129
- fs91.fsyncSync(this.fd);
11210
+ fs92.fsyncSync(this.fd);
11130
11211
  }
11131
11212
  const len = this._len;
11132
11213
  if (this._reopening) {
@@ -11240,7 +11321,7 @@ var require_sonic_boom = __commonJS({
11240
11321
  const onDrain = () => {
11241
11322
  if (!this._fsync) {
11242
11323
  try {
11243
- fs91.fsync(this.fd, (err) => {
11324
+ fs92.fsync(this.fd, (err) => {
11244
11325
  this._flushPending = false;
11245
11326
  cb(err);
11246
11327
  });
@@ -11342,7 +11423,7 @@ var require_sonic_boom = __commonJS({
11342
11423
  const fd = this.fd;
11343
11424
  this.once("ready", () => {
11344
11425
  if (fd !== this.fd) {
11345
- fs91.close(fd, (err) => {
11426
+ fs92.close(fd, (err) => {
11346
11427
  if (err) {
11347
11428
  return this.emit("error", err);
11348
11429
  }
@@ -11391,7 +11472,7 @@ var require_sonic_boom = __commonJS({
11391
11472
  buf = this._bufs[0];
11392
11473
  }
11393
11474
  try {
11394
- const n = Buffer.isBuffer(buf) ? fs91.writeSync(this.fd, buf) : fs91.writeSync(this.fd, buf, "utf8");
11475
+ const n = Buffer.isBuffer(buf) ? fs92.writeSync(this.fd, buf) : fs92.writeSync(this.fd, buf, "utf8");
11395
11476
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
11396
11477
  buf = releasedBufObj.writingBuf;
11397
11478
  this._len = releasedBufObj.len;
@@ -11407,7 +11488,7 @@ var require_sonic_boom = __commonJS({
11407
11488
  }
11408
11489
  }
11409
11490
  try {
11410
- fs91.fsyncSync(this.fd);
11491
+ fs92.fsyncSync(this.fd);
11411
11492
  } catch {
11412
11493
  }
11413
11494
  }
@@ -11428,7 +11509,7 @@ var require_sonic_boom = __commonJS({
11428
11509
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11429
11510
  }
11430
11511
  try {
11431
- const n = fs91.writeSync(this.fd, buf);
11512
+ const n = fs92.writeSync(this.fd, buf);
11432
11513
  buf = buf.subarray(n);
11433
11514
  this._len = Math.max(this._len - n, 0);
11434
11515
  if (buf.length <= 0) {
@@ -11456,13 +11537,13 @@ var require_sonic_boom = __commonJS({
11456
11537
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11457
11538
  if (this.sync) {
11458
11539
  try {
11459
- const written = Buffer.isBuffer(this._writingBuf) ? fs91.writeSync(this.fd, this._writingBuf) : fs91.writeSync(this.fd, this._writingBuf, "utf8");
11540
+ const written = Buffer.isBuffer(this._writingBuf) ? fs92.writeSync(this.fd, this._writingBuf) : fs92.writeSync(this.fd, this._writingBuf, "utf8");
11460
11541
  release2(null, written);
11461
11542
  } catch (err) {
11462
11543
  release2(err);
11463
11544
  }
11464
11545
  } else {
11465
- fs91.write(this.fd, this._writingBuf, release2);
11546
+ fs92.write(this.fd, this._writingBuf, release2);
11466
11547
  }
11467
11548
  }
11468
11549
  function actualWriteBuffer() {
@@ -11471,7 +11552,7 @@ var require_sonic_boom = __commonJS({
11471
11552
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11472
11553
  if (this.sync) {
11473
11554
  try {
11474
- const written = fs91.writeSync(this.fd, this._writingBuf);
11555
+ const written = fs92.writeSync(this.fd, this._writingBuf);
11475
11556
  release2(null, written);
11476
11557
  } catch (err) {
11477
11558
  release2(err);
@@ -11480,7 +11561,7 @@ var require_sonic_boom = __commonJS({
11480
11561
  if (kCopyBuffer) {
11481
11562
  this._writingBuf = Buffer.from(this._writingBuf);
11482
11563
  }
11483
- fs91.write(this.fd, this._writingBuf, release2);
11564
+ fs92.write(this.fd, this._writingBuf, release2);
11484
11565
  }
11485
11566
  }
11486
11567
  function actualClose(sonic) {
@@ -11496,12 +11577,12 @@ var require_sonic_boom = __commonJS({
11496
11577
  sonic._lens = [];
11497
11578
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11498
11579
  try {
11499
- fs91.fsync(sonic.fd, closeWrapped);
11580
+ fs92.fsync(sonic.fd, closeWrapped);
11500
11581
  } catch {
11501
11582
  }
11502
11583
  function closeWrapped() {
11503
11584
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11504
- fs91.close(sonic.fd, done);
11585
+ fs92.close(sonic.fd, done);
11505
11586
  } else {
11506
11587
  done();
11507
11588
  }
@@ -14636,11 +14717,11 @@ var init_lib = __esm({
14636
14717
  }
14637
14718
  }
14638
14719
  },
14639
- addToPath: function addToPath(path100, added, removed, oldPosInc, options) {
14640
- var last = path100.lastComponent;
14720
+ addToPath: function addToPath(path101, added, removed, oldPosInc, options) {
14721
+ var last = path101.lastComponent;
14641
14722
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14642
14723
  return {
14643
- oldPos: path100.oldPos + oldPosInc,
14724
+ oldPos: path101.oldPos + oldPosInc,
14644
14725
  lastComponent: {
14645
14726
  count: last.count + 1,
14646
14727
  added,
@@ -14650,7 +14731,7 @@ var init_lib = __esm({
14650
14731
  };
14651
14732
  } else {
14652
14733
  return {
14653
- oldPos: path100.oldPos + oldPosInc,
14734
+ oldPos: path101.oldPos + oldPosInc,
14654
14735
  lastComponent: {
14655
14736
  count: 1,
14656
14737
  added,
@@ -15232,10 +15313,10 @@ function attachmentToHistoryMessage(o, ts) {
15232
15313
  const memories = raw.map((m2) => {
15233
15314
  if (!m2 || typeof m2 !== "object") return null;
15234
15315
  const rec5 = m2;
15235
- const path100 = typeof rec5.path === "string" ? rec5.path : null;
15316
+ const path101 = typeof rec5.path === "string" ? rec5.path : null;
15236
15317
  const content = typeof rec5.content === "string" ? rec5.content : null;
15237
- if (!path100 || content == null) return null;
15238
- const entry = { path: path100, content };
15318
+ if (!path101 || content == null) return null;
15319
+ const entry = { path: path101, content };
15239
15320
  if (typeof rec5.mtimeMs === "number") entry.mtimeMs = rec5.mtimeMs;
15240
15321
  return entry;
15241
15322
  }).filter((m2) => m2 !== null);
@@ -16101,10 +16182,10 @@ function parseAttachment(obj) {
16101
16182
  const memories = raw.map((m2) => {
16102
16183
  if (!m2 || typeof m2 !== "object") return null;
16103
16184
  const rec5 = m2;
16104
- const path100 = typeof rec5.path === "string" ? rec5.path : null;
16185
+ const path101 = typeof rec5.path === "string" ? rec5.path : null;
16105
16186
  const content = typeof rec5.content === "string" ? rec5.content : null;
16106
- if (!path100 || content == null) return null;
16107
- const out = { path: path100, content };
16187
+ if (!path101 || content == null) return null;
16188
+ const out = { path: path101, content };
16108
16189
  if (typeof rec5.mtimeMs === "number") out.mtimeMs = rec5.mtimeMs;
16109
16190
  return out;
16110
16191
  }).filter((m2) => m2 !== null);
@@ -24576,12 +24657,12 @@ var require_luxon = __commonJS({
24576
24657
  if (!reason) {
24577
24658
  throw new InvalidArgumentError("need to specify a reason the Duration is invalid");
24578
24659
  }
24579
- const invalid2 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
24660
+ const invalid3 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
24580
24661
  if (Settings.throwOnInvalid) {
24581
- throw new InvalidDurationError(invalid2);
24662
+ throw new InvalidDurationError(invalid3);
24582
24663
  } else {
24583
24664
  return new _Duration({
24584
- invalid: invalid2
24665
+ invalid: invalid3
24585
24666
  });
24586
24667
  }
24587
24668
  }
@@ -25173,12 +25254,12 @@ var require_luxon = __commonJS({
25173
25254
  if (!reason) {
25174
25255
  throw new InvalidArgumentError("need to specify a reason the Interval is invalid");
25175
25256
  }
25176
- const invalid2 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
25257
+ const invalid3 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
25177
25258
  if (Settings.throwOnInvalid) {
25178
- throw new InvalidIntervalError(invalid2);
25259
+ throw new InvalidIntervalError(invalid3);
25179
25260
  } else {
25180
25261
  return new _Interval({
25181
- invalid: invalid2
25262
+ invalid: invalid3
25182
25263
  });
25183
25264
  }
25184
25265
  }
@@ -26680,9 +26761,9 @@ var require_luxon = __commonJS({
26680
26761
  obj[u] = defaultUnitValues[u];
26681
26762
  }
26682
26763
  }
26683
- const invalid2 = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj);
26684
- if (invalid2) {
26685
- return DateTime.invalid(invalid2);
26764
+ const invalid3 = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj);
26765
+ if (invalid3) {
26766
+ return DateTime.invalid(invalid3);
26686
26767
  }
26687
26768
  const offsetProvis = guessOffsetForZone(zone);
26688
26769
  [ts, o] = objToTS(obj, offsetProvis, zone);
@@ -26739,24 +26820,24 @@ var require_luxon = __commonJS({
26739
26820
  */
26740
26821
  constructor(config) {
26741
26822
  const zone = config.zone || Settings.defaultZone;
26742
- let invalid2 = config.invalid || (Number.isNaN(config.ts) ? new Invalid("invalid input") : null) || (!zone.isValid ? unsupportedZone(zone) : null);
26823
+ let invalid3 = config.invalid || (Number.isNaN(config.ts) ? new Invalid("invalid input") : null) || (!zone.isValid ? unsupportedZone(zone) : null);
26743
26824
  this.ts = isUndefined(config.ts) ? Settings.now() : config.ts;
26744
26825
  let c = null, o = null;
26745
- if (!invalid2) {
26826
+ if (!invalid3) {
26746
26827
  const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone);
26747
26828
  if (unchanged) {
26748
26829
  [c, o] = [config.old.c, config.old.o];
26749
26830
  } else {
26750
26831
  const ot = isNumber(config.o) && !config.old ? config.o : zone.offset(this.ts);
26751
26832
  c = tsToObj(this.ts, ot);
26752
- invalid2 = Number.isNaN(c.year) ? new Invalid("invalid input") : null;
26753
- c = invalid2 ? null : c;
26754
- o = invalid2 ? null : ot;
26833
+ invalid3 = Number.isNaN(c.year) ? new Invalid("invalid input") : null;
26834
+ c = invalid3 ? null : c;
26835
+ o = invalid3 ? null : ot;
26755
26836
  }
26756
26837
  }
26757
26838
  this._zone = zone;
26758
26839
  this.loc = config.loc || Locale.create();
26759
- this.invalid = invalid2;
26840
+ this.invalid = invalid3;
26760
26841
  this.weekData = null;
26761
26842
  this.localWeekData = null;
26762
26843
  this.c = c;
@@ -26990,9 +27071,9 @@ var require_luxon = __commonJS({
26990
27071
  normalized[u] = objNow[u];
26991
27072
  }
26992
27073
  }
26993
- const higherOrderInvalid = useWeekData ? hasInvalidWeekData(normalized, minDaysInFirstWeek, startOfWeek) : containsOrdinal ? hasInvalidOrdinalData(normalized) : hasInvalidGregorianData(normalized), invalid2 = higherOrderInvalid || hasInvalidTimeData(normalized);
26994
- if (invalid2) {
26995
- return _DateTime.invalid(invalid2);
27074
+ const higherOrderInvalid = useWeekData ? hasInvalidWeekData(normalized, minDaysInFirstWeek, startOfWeek) : containsOrdinal ? hasInvalidOrdinalData(normalized) : hasInvalidGregorianData(normalized), invalid3 = higherOrderInvalid || hasInvalidTimeData(normalized);
27075
+ if (invalid3) {
27076
+ return _DateTime.invalid(invalid3);
26996
27077
  }
26997
27078
  const gregorian = useWeekData ? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek) : containsOrdinal ? ordinalToGregorian(normalized) : normalized, [tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse), inst = new _DateTime({
26998
27079
  ts: tsFinal,
@@ -27093,9 +27174,9 @@ var require_luxon = __commonJS({
27093
27174
  locale,
27094
27175
  numberingSystem,
27095
27176
  defaultToEN: true
27096
- }), [vals, parsedZone, specificOffset, invalid2] = parseFromTokens(localeToUse, text, fmt);
27097
- if (invalid2) {
27098
- return _DateTime.invalid(invalid2);
27177
+ }), [vals, parsedZone, specificOffset, invalid3] = parseFromTokens(localeToUse, text, fmt);
27178
+ if (invalid3) {
27179
+ return _DateTime.invalid(invalid3);
27099
27180
  } else {
27100
27181
  return parseDataToDateTime(vals, parsedZone, opts, `format ${fmt}`, text, specificOffset);
27101
27182
  }
@@ -27141,12 +27222,12 @@ var require_luxon = __commonJS({
27141
27222
  if (!reason) {
27142
27223
  throw new InvalidArgumentError("need to specify a reason the DateTime is invalid");
27143
27224
  }
27144
- const invalid2 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
27225
+ const invalid3 = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
27145
27226
  if (Settings.throwOnInvalid) {
27146
- throw new InvalidDateTimeError(invalid2);
27227
+ throw new InvalidDateTimeError(invalid3);
27147
27228
  } else {
27148
27229
  return new _DateTime({
27149
- invalid: invalid2
27230
+ invalid: invalid3
27150
27231
  });
27151
27232
  }
27152
27233
  }
@@ -37078,8 +37159,8 @@ var require_utils = __commonJS({
37078
37159
  var result = transform[inputType][outputType](input);
37079
37160
  return result;
37080
37161
  };
37081
- exports2.resolve = function(path100) {
37082
- var parts = path100.split("/");
37162
+ exports2.resolve = function(path101) {
37163
+ var parts = path101.split("/");
37083
37164
  var result = [];
37084
37165
  for (var index = 0; index < parts.length; index++) {
37085
37166
  var part = parts[index];
@@ -42932,18 +43013,18 @@ var require_object = __commonJS({
42932
43013
  var object = new ZipObject(name, zipObjectContent, o);
42933
43014
  this.files[name] = object;
42934
43015
  };
42935
- var parentFolder = function(path100) {
42936
- if (path100.slice(-1) === "/") {
42937
- path100 = path100.substring(0, path100.length - 1);
43016
+ var parentFolder = function(path101) {
43017
+ if (path101.slice(-1) === "/") {
43018
+ path101 = path101.substring(0, path101.length - 1);
42938
43019
  }
42939
- var lastSlash = path100.lastIndexOf("/");
42940
- return lastSlash > 0 ? path100.substring(0, lastSlash) : "";
43020
+ var lastSlash = path101.lastIndexOf("/");
43021
+ return lastSlash > 0 ? path101.substring(0, lastSlash) : "";
42941
43022
  };
42942
- var forceTrailingSlash = function(path100) {
42943
- if (path100.slice(-1) !== "/") {
42944
- path100 += "/";
43023
+ var forceTrailingSlash = function(path101) {
43024
+ if (path101.slice(-1) !== "/") {
43025
+ path101 += "/";
42945
43026
  }
42946
- return path100;
43027
+ return path101;
42947
43028
  };
42948
43029
  var folderAdd = function(name, createFolders) {
42949
43030
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43945,7 +44026,7 @@ var require_lib3 = __commonJS({
43945
44026
  // src/run-case/recorder.ts
43946
44027
  function startRunCaseRecorder(opts) {
43947
44028
  const now = opts.now ?? Date.now;
43948
- const dir = import_node_path82.default.dirname(opts.recordPath);
44029
+ const dir = import_node_path83.default.dirname(opts.recordPath);
43949
44030
  let stream = null;
43950
44031
  let closing = false;
43951
44032
  let closedSettled = false;
@@ -43959,8 +44040,8 @@ function startRunCaseRecorder(opts) {
43959
44040
  });
43960
44041
  const ensureStream = () => {
43961
44042
  if (stream) return stream;
43962
- import_node_fs63.default.mkdirSync(dir, { recursive: true });
43963
- stream = import_node_fs63.default.createWriteStream(opts.recordPath, { flags: "a" });
44043
+ import_node_fs64.default.mkdirSync(dir, { recursive: true });
44044
+ stream = import_node_fs64.default.createWriteStream(opts.recordPath, { flags: "a" });
43964
44045
  stream.on("close", () => closedResolve());
43965
44046
  return stream;
43966
44047
  };
@@ -43985,12 +44066,12 @@ function startRunCaseRecorder(opts) {
43985
44066
  };
43986
44067
  return { tap, close, closed };
43987
44068
  }
43988
- var import_node_fs63, import_node_path82;
44069
+ var import_node_fs64, import_node_path83;
43989
44070
  var init_recorder = __esm({
43990
44071
  "src/run-case/recorder.ts"() {
43991
44072
  "use strict";
43992
- import_node_fs63 = __toESM(require("fs"), 1);
43993
- import_node_path82 = __toESM(require("path"), 1);
44073
+ import_node_fs64 = __toESM(require("fs"), 1);
44074
+ import_node_path83 = __toESM(require("path"), 1);
43994
44075
  }
43995
44076
  });
43996
44077
 
@@ -44033,7 +44114,7 @@ var init_wire = __esm({
44033
44114
  // src/run-case/controller.ts
44034
44115
  async function runController(opts) {
44035
44116
  const now = opts.now ?? Date.now;
44036
- const cwd = opts.cwd ?? (0, import_node_fs64.mkdtempSync)(import_node_path83.default.join(import_node_os29.default.tmpdir(), "clawd-runcase-"));
44117
+ const cwd = opts.cwd ?? (0, import_node_fs65.mkdtempSync)(import_node_path84.default.join(import_node_os29.default.tmpdir(), "clawd-runcase-"));
44037
44118
  const ownsCwd = opts.cwd === void 0;
44038
44119
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
44039
44120
  const spawnCtx = { cwd };
@@ -44194,19 +44275,19 @@ async function runController(opts) {
44194
44275
  if (sigintHandler) process.off("SIGINT", sigintHandler);
44195
44276
  if (ownsCwd) {
44196
44277
  try {
44197
- (0, import_node_fs64.rmSync)(cwd, { recursive: true, force: true });
44278
+ (0, import_node_fs65.rmSync)(cwd, { recursive: true, force: true });
44198
44279
  } catch {
44199
44280
  }
44200
44281
  }
44201
44282
  return exitCode ?? 0;
44202
44283
  }
44203
- var import_node_fs64, import_node_os29, import_node_path83;
44284
+ var import_node_fs65, import_node_os29, import_node_path84;
44204
44285
  var init_controller = __esm({
44205
44286
  "src/run-case/controller.ts"() {
44206
44287
  "use strict";
44207
- import_node_fs64 = require("fs");
44288
+ import_node_fs65 = require("fs");
44208
44289
  import_node_os29 = __toESM(require("os"), 1);
44209
- import_node_path83 = __toESM(require("path"), 1);
44290
+ import_node_path84 = __toESM(require("path"), 1);
44210
44291
  init_claude();
44211
44292
  init_stdout_splitter();
44212
44293
  init_permission_stdio();
@@ -44481,8 +44562,8 @@ Env (advanced):
44481
44562
  `;
44482
44563
 
44483
44564
  // src/index.ts
44484
- var import_node_path81 = __toESM(require("path"), 1);
44485
- var import_node_fs62 = __toESM(require("fs"), 1);
44565
+ var import_node_path82 = __toESM(require("path"), 1);
44566
+ var import_node_fs63 = __toESM(require("fs"), 1);
44486
44567
  var import_node_os28 = __toESM(require("os"), 1);
44487
44568
  var import_node_crypto23 = require("crypto");
44488
44569
  var import_node_url5 = require("url");
@@ -46656,17 +46737,23 @@ function renderPersonaMcpSecrets(args) {
46656
46737
  if (Array.isArray(def.args) && def.args.some(hasPlaceholder)) {
46657
46738
  args.logger?.warn("persona.mcp-secret.placeholder-in-args", { persona: args.personaId, server: name });
46658
46739
  }
46659
- if (!env || !Object.values(env).some(hasPlaceholder)) continue;
46660
- const renderedEnv = {};
46661
- for (const [k2, v2] of Object.entries(env)) {
46662
- if (typeof v2 !== "string") continue;
46663
- renderedEnv[k2] = v2.replace(PLACEHOLDER, (_m, varName) => {
46664
- const hit = args.secrets[varName];
46665
- if (hit === void 0) missing.add(varName);
46666
- return hit ?? "";
46667
- });
46668
- }
46669
- rendered[name] = { ...def, env: renderedEnv };
46740
+ const headers = def.headers && typeof def.headers === "object" ? def.headers : void 0;
46741
+ const envHas = !!env && Object.values(env).some(hasPlaceholder);
46742
+ const headersHas = !!headers && Object.values(headers).some(hasPlaceholder);
46743
+ if (!envHas && !headersHas) continue;
46744
+ const renderTable = (table) => {
46745
+ const out = {};
46746
+ for (const [k2, v2] of Object.entries(table)) {
46747
+ if (typeof v2 !== "string") continue;
46748
+ out[k2] = v2.replace(PLACEHOLDER, (_m, varName) => {
46749
+ const hit = args.secrets[varName];
46750
+ if (hit === void 0) missing.add(varName);
46751
+ return hit ?? "";
46752
+ });
46753
+ }
46754
+ return out;
46755
+ };
46756
+ rendered[name] = { ...def, ...envHas ? { env: renderTable(env) } : {}, ...headersHas ? { headers: renderTable(headers) } : {} };
46670
46757
  }
46671
46758
  if (Object.keys(rendered).length === 0) return void 0;
46672
46759
  if (missing.size > 0) {
@@ -51770,7 +51857,7 @@ function codexGuestCliArgs(cs, opts = {}) {
51770
51857
  function codexMcpCliArgs(defs) {
51771
51858
  const out = [];
51772
51859
  for (const d of defs) {
51773
- const cfg = {
51860
+ const cfg = "url" in d ? { url: d.url, ...d.httpHeaders && Object.keys(d.httpHeaders).length > 0 ? { http_headers: d.httpHeaders } : {} } : {
51774
51861
  command: d.command,
51775
51862
  ...d.args && d.args.length > 0 ? { args: d.args } : {},
51776
51863
  ...d.env && Object.keys(d.env).length > 0 ? { env: d.env } : {}
@@ -51816,8 +51903,8 @@ function turnStartInput(text, resolveImage) {
51816
51903
  const items = [];
51817
51904
  let leftover = text;
51818
51905
  for (const m2 of text.matchAll(SKILL_RE)) {
51819
- const [marker, name, path100] = m2;
51820
- items.push({ type: "skill", name, path: path100 });
51906
+ const [marker, name, path101] = m2;
51907
+ items.push({ type: "skill", name, path: path101 });
51821
51908
  leftover = leftover.replace(marker, "");
51822
51909
  }
51823
51910
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -51963,6 +52050,7 @@ function stringValue2(value) {
51963
52050
  // src/tools/codex-mcp-config.ts
51964
52051
  var import_node_fs17 = __toESM(require("fs"), 1);
51965
52052
  var import_node_path15 = __toESM(require("path"), 1);
52053
+ var HTTP_TYPES = /* @__PURE__ */ new Set(["http", "sse", "streamable_http", "streamable-http"]);
51966
52054
  function loadCodexMcpServerDefs(args) {
51967
52055
  const out = [];
51968
52056
  const seen = /* @__PURE__ */ new Set();
@@ -51982,7 +52070,21 @@ function loadCodexMcpServerDefs(args) {
51982
52070
  if (!servers || typeof servers !== "object") continue;
51983
52071
  for (const [name, raw] of Object.entries(servers)) {
51984
52072
  const def = raw ?? {};
51985
- const type = typeof def.type === "string" ? def.type : "stdio";
52073
+ const type = typeof def.type === "string" ? def.type.toLowerCase() : typeof def.url === "string" ? "http" : "stdio";
52074
+ if (HTTP_TYPES.has(type)) {
52075
+ if (typeof def.url !== "string" || !def.url) {
52076
+ args.logger?.warn("codex mcp server http without url, skipped", { file, name });
52077
+ continue;
52078
+ }
52079
+ if (seen.has(name)) {
52080
+ args.logger?.warn("codex mcp server name collision, first-wins", { file, name });
52081
+ continue;
52082
+ }
52083
+ seen.add(name);
52084
+ const headers = def.headers && typeof def.headers === "object" ? Object.fromEntries(Object.entries(def.headers).filter((kv) => typeof kv[1] === "string")) : {};
52085
+ out.push({ name, url: def.url, ...Object.keys(headers).length > 0 ? { httpHeaders: headers } : {} });
52086
+ continue;
52087
+ }
51986
52088
  if (type !== "stdio") {
51987
52089
  args.logger?.warn("codex mcp server type unsupported, skipped", { file, name, type });
51988
52090
  continue;
@@ -55259,10 +55361,160 @@ function redactEvidence(evidence) {
55259
55361
 
55260
55362
  // src/deploy/deploy-file.ts
55261
55363
  var import_promises4 = __toESM(require("fs/promises"), 1);
55364
+ var import_node_path33 = __toESM(require("path"), 1);
55365
+ init_protocol();
55366
+
55367
+ // src/deploy/connectors.ts
55368
+ var import_node_fs29 = __toESM(require("fs"), 1);
55262
55369
  var import_node_path32 = __toESM(require("path"), 1);
55370
+ init_zod();
55263
55371
  init_protocol();
55264
- var DEPLOY_FILE = import_node_path32.default.join(".clawd", "deploy.json");
55265
- var SCAN_FILE = import_node_path32.default.join(".clawd", "deploy-scan.json");
55372
+ var PLACEHOLDER2 = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
55373
+ var MCP_SCAN_NOTE_PREFIX = "\u3010.mcp.json\u3011";
55374
+ var LARK_SIDECAR_CONNECTOR = "feishu";
55375
+ var CliConnectorFindingSchema = external_exports.object({
55376
+ name: ConnectorNameSchema,
55377
+ fields: external_exports.array(ConnectorFieldSchema).default([])
55378
+ });
55379
+ function canonicalConnectorUrl(raw) {
55380
+ const u = new URL(raw);
55381
+ return `${u.origin}${u.pathname.replace(/\/+$/, "")}${u.search}`;
55382
+ }
55383
+ function placeholdersIn(value) {
55384
+ if (typeof value !== "string") return [];
55385
+ return [...value.matchAll(new RegExp(PLACEHOLDER2))].map((m2) => m2[1]);
55386
+ }
55387
+ var uniq = (xs) => [...new Set(xs)];
55388
+ function fieldsOf(name, where, placeholders, warnings) {
55389
+ const ok = [];
55390
+ for (const p2 of uniq(placeholders)) {
55391
+ if (ConnectorFieldSchema.safeParse(p2).success) ok.push(p2);
55392
+ else warnings.push(`MCP server\u300C${name}\u300D\u7684 ${where} \u91CC\u6709\u5360\u4F4D \${${p2}}\uFF0C\u53D8\u91CF\u540D\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\uFF0C\u5B57\u6BCD\u5F00\u5934\uFF09\uFF0C\u6CA1\u7B97\u8FDB\u8981\u586B\u7684\u683C\uFF1B\u6539\u540D\u540E\u91CD\u65B0\u626B\u63CF`);
55393
+ }
55394
+ return ok;
55395
+ }
55396
+ function sanitizeForQuote(def) {
55397
+ const strip2 = (obj) => {
55398
+ if (!obj || typeof obj !== "object") return obj;
55399
+ return Object.fromEntries(
55400
+ Object.entries(obj).map(([k2, v2]) => [
55401
+ k2,
55402
+ // 用一份新正则做 test:全局正则的 lastIndex 会串进后面的 matchAll(mcp-secret-render.ts 同款写法)
55403
+ typeof v2 === "string" && v2.length > 0 && !new RegExp(PLACEHOLDER2).test(v2) ? REDACTED : v2
55404
+ ])
55405
+ );
55406
+ };
55407
+ const out = {};
55408
+ for (const [k2, v2] of Object.entries(def)) {
55409
+ out[k2] = k2 === "env" || k2 === "headers" ? strip2(v2) : v2;
55410
+ }
55411
+ return out;
55412
+ }
55413
+ var stringRecord = (v2) => v2 && typeof v2 === "object" ? Object.fromEntries(Object.entries(v2).filter((kv) => typeof kv[1] === "string")) : {};
55414
+ var HTTP_TYPES2 = /* @__PURE__ */ new Set(["http", "sse", "streamable_http", "streamable-http"]);
55415
+ var PACKAGE_RUNNERS = /* @__PURE__ */ new Set(["npx", "uvx", "pnpx", "bunx"]);
55416
+ function scanMcpConnectors(personaDir) {
55417
+ const file = import_node_path32.default.join(personaDir, ".mcp.json");
55418
+ const out = { readable: true, connectors: [], evidence: [], warnings: [] };
55419
+ let parsed;
55420
+ try {
55421
+ parsed = JSON.parse(import_node_fs29.default.readFileSync(file, "utf8"));
55422
+ } catch (e) {
55423
+ if (e.code === "ENOENT") return out;
55424
+ out.readable = false;
55425
+ out.warnings.push(`.mcp.json \u8BFB\u4E0D\u51FA\u6765\uFF08${e.message.split("\n")[0]}\uFF09\uFF0C\u91CC\u9762\u7684 MCP server \u8FD9\u6B21\u6CA1\u91CD\u65B0\u5217\uFF1B\u6E05\u5355\u91CC\u539F\u6709\u7684\u7167\u65E7`);
55426
+ return out;
55427
+ }
55428
+ const servers = parsed?.mcpServers;
55429
+ if (!servers || typeof servers !== "object") return out;
55430
+ for (const [name, raw] of Object.entries(servers)) {
55431
+ const def = raw && typeof raw === "object" ? raw : {};
55432
+ if (!ConnectorNameSchema.safeParse(name).success) {
55433
+ out.warnings.push(`MCP server\u300C${name}\u300D\u7684\u540D\u5B57\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u77ED\u6A2A\u7EBF\uFF09\uFF0C\u6CA1\u5217\u8FDB\u6E05\u5355\uFF1B\u6539\u540D\u540E\u91CD\u65B0\u626B\u63CF`);
55434
+ continue;
55435
+ }
55436
+ const type = typeof def.type === "string" ? def.type.toLowerCase() : typeof def.url === "string" ? "http" : "stdio";
55437
+ const quote = JSON.stringify({ [name]: sanitizeForQuote(def) }, null, 2);
55438
+ if (HTTP_TYPES2.has(type)) {
55439
+ const url = typeof def.url === "string" ? def.url : "";
55440
+ let id2;
55441
+ try {
55442
+ id2 = canonicalConnectorUrl(url);
55443
+ } catch {
55444
+ out.warnings.push(`MCP server\u300C${name}\u300D\u662F http \u578B\u4F46 url \u4E0D\u5408\u6CD5\uFF08${url || "\u7A7A"}\uFF09\uFF0C\u6CA1\u5217\u8FDB\u6E05\u5355`);
55445
+ continue;
55446
+ }
55447
+ const headers = stringRecord(def.headers);
55448
+ if (placeholdersIn(url).length > 0) {
55449
+ out.warnings.push(`MCP server\u300C${name}\u300D\u7684 url \u91CC\u6709 \${VAR} \u5360\u4F4D\u2014\u2014url \u4E0D\u4F1A\u88AB\u6E32\uFF0C\u51ED\u636E\u8BF7\u6539\u5230 headers \u91CC`);
55450
+ }
55451
+ const fields2 = fieldsOf(name, "headers", Object.values(headers).flatMap(placeholdersIn), out.warnings);
55452
+ out.connectors.push({ name, kind: "proxy", runner: "mcp", id: id2, fields: fields2, http: { url, headers } });
55453
+ out.evidence.push({
55454
+ target: `connector:${name}`,
55455
+ reason: `.mcp.json \u91CC\u6302\u4E86 http \u578B MCP server\u300C${name}\u300D\uFF08${id2}\uFF09\u3002` + (fields2.length > 0 ? `\u8BF7\u6C42\u5934\u91CC\u8981\u586B ${fields2.join(" / ")}\u3002` : "\u6CA1\u6709\u5360\u4F4D\uFF1A\u51ED\u636E\u7531\u4F7F\u7528\u8005\u5173\u8054\uFF0C\u6216\u90E8\u7F72\u8005\u5B9A\u4E00\u79CD\u3002") + "\u8C01\u51FA\u51ED\u636E\u5728\u5355\u636E\u4E0A\u70B9\u3002",
55456
+ file: ".mcp.json",
55457
+ quote
55458
+ });
55459
+ continue;
55460
+ }
55461
+ const command = typeof def.command === "string" ? def.command : "";
55462
+ if (!command) {
55463
+ out.warnings.push(`MCP server\u300C${name}\u300D\u65E2\u6CA1\u6709 url \u4E5F\u6CA1\u6709 command\uFF0C\u6CA1\u5217\u8FDB\u6E05\u5355`);
55464
+ continue;
55465
+ }
55466
+ const args = Array.isArray(def.args) ? def.args.map(String) : [];
55467
+ const pkg = PACKAGE_RUNNERS.has(command) ? args.find((a) => !a.startsWith("-")) : void 0;
55468
+ const id = pkg ?? command;
55469
+ const fields = fieldsOf(name, "env", Object.values(stringRecord(def.env)).flatMap(placeholdersIn), out.warnings);
55470
+ if (args.some((a) => placeholdersIn(a).length > 0)) {
55471
+ out.warnings.push(`MCP server\u300C${name}\u300D\u7684 args \u91CC\u6709 \${VAR} \u5360\u4F4D\u2014\u2014args \u4F1A\u8FDB ps\uFF0C\u4E91\u4E0A\u548C\u672C\u673A\u90FD\u53EA\u6E32 env\uFF0C\u8FD9\u4E9B\u5360\u4F4D\u4E0D\u4F1A\u88AB\u586B\uFF1B\u628A\u51ED\u636E\u6539\u5230 env \u91CC`);
55472
+ }
55473
+ out.connectors.push({ name, kind: "env", runner: "mcp", id, fields });
55474
+ out.evidence.push({
55475
+ target: `connector:${name}`,
55476
+ reason: `.mcp.json \u91CC\u6302\u4E86 stdio \u578B MCP server\u300C${name}\u300D\uFF08${id}\uFF09\u3002` + (fields.length > 0 ? `\u5B83\u4ECE\u73AF\u5883\u53D8\u91CF\u8BFB ${fields.join(" / ")}\u3002` : "\u6CA1\u6709\u8981\u586B\u7684\u73AF\u5883\u53D8\u91CF\u3002") + "\u8C01\u51FA\u51ED\u636E\u5728\u5355\u636E\u4E0A\u70B9\uFF1A\u5171\u4EAB = \u90E8\u7F72\u8005\u586B\u8FDB\u4ED3\u5E93 Secrets\uFF0C\u4E2A\u4EBA = \u6BCF\u4E2A\u4F7F\u7528\u8005\u5728\u5361\u7247\u4E0A\u586B\u3002",
55477
+ file: ".mcp.json",
55478
+ quote
55479
+ });
55480
+ }
55481
+ return out;
55482
+ }
55483
+ function cliConnectorFromFinding(item) {
55484
+ if (item.name === LARK_SIDECAR_CONNECTOR) {
55485
+ return {
55486
+ name: item.name,
55487
+ kind: "proxy",
55488
+ runner: "cli",
55489
+ protocol: "lark-sidecar",
55490
+ id: item.name,
55491
+ credentialSource: "personal",
55492
+ auth: "oauth",
55493
+ fields: []
55494
+ };
55495
+ }
55496
+ return { name: item.name, kind: "env", runner: "cli", id: item.name, fields: item.fields };
55497
+ }
55498
+ function mergeConnector(existing, incoming) {
55499
+ if (!existing) return incoming;
55500
+ const reviewed = existing.credentialSource !== void 0;
55501
+ return {
55502
+ ...incoming,
55503
+ ...existing.credentialSource ? { credentialSource: existing.credentialSource } : {},
55504
+ ...existing.auth ? { auth: existing.auth } : {},
55505
+ fields: reviewed ? existing.fields : incoming.fields
55506
+ };
55507
+ }
55508
+ function mergeScannedConnectors(existing, scanned) {
55509
+ const byName = new Map(existing.map((c) => [c.name, c]));
55510
+ const mcp = scanned.map((c) => mergeConnector(byName.get(c.name), c));
55511
+ const cli = existing.filter((c) => c.runner === "cli" && !scanned.some((s) => s.name === c.name));
55512
+ return [...mcp, ...cli];
55513
+ }
55514
+
55515
+ // src/deploy/deploy-file.ts
55516
+ var DEPLOY_FILE = import_node_path33.default.join(".clawd", "deploy.json");
55517
+ var SCAN_FILE = import_node_path33.default.join(".clawd", "deploy-scan.json");
55266
55518
  async function readJson(file) {
55267
55519
  let raw;
55268
55520
  try {
@@ -55278,14 +55530,14 @@ async function readJson(file) {
55278
55530
  }
55279
55531
  }
55280
55532
  async function writeJson(file, value) {
55281
- await import_promises4.default.mkdir(import_node_path32.default.dirname(file), { recursive: true });
55533
+ await import_promises4.default.mkdir(import_node_path33.default.dirname(file), { recursive: true });
55282
55534
  const tmp = `${file}.tmp-${process.pid}`;
55283
55535
  await import_promises4.default.writeFile(tmp, `${JSON.stringify(value, null, 2)}
55284
55536
  `);
55285
55537
  await import_promises4.default.rename(tmp, file);
55286
55538
  }
55287
55539
  async function readDeployFile(dir) {
55288
- const raw = await readJson(import_node_path32.default.join(dir, DEPLOY_FILE));
55540
+ const raw = await readJson(import_node_path33.default.join(dir, DEPLOY_FILE));
55289
55541
  if (raw === void 0) return void 0;
55290
55542
  const parsed = DeployFileSchema.safeParse(raw);
55291
55543
  if (!parsed.success) {
@@ -55295,10 +55547,10 @@ async function readDeployFile(dir) {
55295
55547
  return parsed.data;
55296
55548
  }
55297
55549
  async function writeDeployFile(dir, file) {
55298
- await writeJson(import_node_path32.default.join(dir, DEPLOY_FILE), DeployFileSchema.parse(file));
55550
+ await writeJson(import_node_path33.default.join(dir, DEPLOY_FILE), DeployFileSchema.parse(file));
55299
55551
  }
55300
55552
  async function readScan(dir) {
55301
- const raw = await readJson(import_node_path32.default.join(dir, SCAN_FILE));
55553
+ const raw = await readJson(import_node_path33.default.join(dir, SCAN_FILE));
55302
55554
  if (raw === void 0) return void 0;
55303
55555
  const parsed = DeployScanSchema.safeParse(raw);
55304
55556
  if (!parsed.success) {
@@ -55308,7 +55560,7 @@ async function readScan(dir) {
55308
55560
  return parsed.data;
55309
55561
  }
55310
55562
  async function writeScan(dir, scan) {
55311
- await writeJson(import_node_path32.default.join(dir, SCAN_FILE), DeployScanSchema.parse(scan));
55563
+ await writeJson(import_node_path33.default.join(dir, SCAN_FILE), DeployScanSchema.parse(scan));
55312
55564
  }
55313
55565
  function emptyDeployFile() {
55314
55566
  return { version: 1, manifest: { version: 1, clis: [], secrets: [], assets: [], connectors: [] } };
@@ -55317,7 +55569,9 @@ var FINDING_SCHEMAS = {
55317
55569
  cli: EnvCliSchema,
55318
55570
  secret: EnvSecretSchema,
55319
55571
  asset: EnvAssetSchema,
55320
- connector: EnvConnectorSchema
55572
+ // butler 报的是 CLI 连接器的「名字 + 它读的环境变量名」,kind / runner / id 由 daemon 补
55573
+ //(handlers/deploy.ts 的 cliConnectorFromFinding)。MCP 连接器不经上报口,由 scanMcpConnectors 机械列出。
55574
+ connector: CliConnectorFindingSchema
55321
55575
  };
55322
55576
  function parseFinding(kind, item) {
55323
55577
  const parsed = FINDING_SCHEMAS[kind].safeParse(item);
@@ -55329,8 +55583,12 @@ function parseFinding(kind, item) {
55329
55583
  }
55330
55584
  function upsertFinding(file, kind, item) {
55331
55585
  if (kind === "connector") {
55586
+ const incoming = item;
55332
55587
  const have = file.manifest.connectors;
55333
- const connectors = have.includes(item.name) ? have : [...have, item.name];
55588
+ const idx2 = have.findIndex((c) => c.name === incoming.name);
55589
+ if (idx2 !== -1 && have[idx2].runner === "mcp" && incoming.runner === "cli") return file;
55590
+ const merged = mergeConnector(idx2 === -1 ? void 0 : have[idx2], incoming);
55591
+ const connectors = idx2 === -1 ? [...have, merged] : have.map((c, i) => i === idx2 ? merged : c);
55334
55592
  return { ...file, manifest: { ...file.manifest, connectors } };
55335
55593
  }
55336
55594
  const key = kind === "cli" ? "clis" : kind === "secret" ? "secrets" : "assets";
@@ -55342,13 +55600,13 @@ function upsertFinding(file, kind, item) {
55342
55600
  }
55343
55601
  function requiredEnvNames(file) {
55344
55602
  if (!file) return [];
55345
- return [...new Set(file.manifest.secrets.flatMap((s) => s.env))];
55603
+ return requiredSecretEnvNames(file.manifest);
55346
55604
  }
55347
55605
 
55348
55606
  // src/deploy/repo.ts
55349
55607
  var import_node_child_process8 = require("child_process");
55350
55608
  var import_promises5 = __toESM(require("fs/promises"), 1);
55351
- var import_node_path33 = __toESM(require("path"), 1);
55609
+ var import_node_path34 = __toESM(require("path"), 1);
55352
55610
  init_protocol();
55353
55611
 
55354
55612
  // src/deploy/templates.ts
@@ -55582,7 +55840,7 @@ var L = [
55582
55840
  var WORKFLOW_TEMPLATE = L.join("\n");
55583
55841
 
55584
55842
  // src/deploy/repo.ts
55585
- var DEPLOY_FILE_REL = DEPLOY_FILE.split(import_node_path33.default.sep).join("/");
55843
+ var DEPLOY_FILE_REL = DEPLOY_FILE.split(import_node_path34.default.sep).join("/");
55586
55844
  var DEFAULT_TIMEOUT_MS3 = 6e4;
55587
55845
  var runCommand = (cmd, args, opts = {}) => new Promise((resolve9) => {
55588
55846
  const child = (0, import_node_child_process8.spawn)(cmd, args, {
@@ -55649,7 +55907,7 @@ async function samePath(a, b2) {
55649
55907
  try {
55650
55908
  return await import_promises5.default.realpath(x);
55651
55909
  } catch {
55652
- return import_node_path33.default.resolve(x);
55910
+ return import_node_path34.default.resolve(x);
55653
55911
  }
55654
55912
  };
55655
55913
  return await real(a) === await real(b2);
@@ -55675,7 +55933,7 @@ async function identityArgs(exec, dir) {
55675
55933
  return ["-c", "user.name=clawd", "-c", "user.email=clawd@clawos.local"];
55676
55934
  }
55677
55935
  async function writeTemplates(dir) {
55678
- const gi = import_node_path33.default.join(dir, ".gitignore");
55936
+ const gi = import_node_path34.default.join(dir, ".gitignore");
55679
55937
  let existing;
55680
55938
  try {
55681
55939
  existing = await import_promises5.default.readFile(gi, "utf8");
@@ -55683,8 +55941,8 @@ async function writeTemplates(dir) {
55683
55941
  existing = void 0;
55684
55942
  }
55685
55943
  await import_promises5.default.writeFile(gi, mergeGitignore(existing));
55686
- const wf = import_node_path33.default.join(dir, WORKFLOW_PATH);
55687
- await import_promises5.default.mkdir(import_node_path33.default.dirname(wf), { recursive: true });
55944
+ const wf = import_node_path34.default.join(dir, WORKFLOW_PATH);
55945
+ await import_promises5.default.mkdir(import_node_path34.default.dirname(wf), { recursive: true });
55688
55946
  await import_promises5.default.writeFile(wf, WORKFLOW_TEMPLATE);
55689
55947
  }
55690
55948
  async function ensureRepo(exec, args) {
@@ -55813,8 +56071,8 @@ function runStatusOf(status) {
55813
56071
  if (status === "queued" || status === "waiting" || status === "requested" || status === "pending") return "queued";
55814
56072
  return "running";
55815
56073
  }
55816
- async function ghJson(exec, path100) {
55817
- const r = await exec("gh", ["api", path100], { timeoutMs: TIMEOUT_MS });
56074
+ async function ghJson(exec, path101) {
56075
+ const r = await exec("gh", ["api", path101], { timeoutMs: TIMEOUT_MS });
55818
56076
  if (r.spawnError || r.code !== 0) return void 0;
55819
56077
  try {
55820
56078
  return JSON.parse(r.stdout);
@@ -55874,12 +56132,12 @@ async function rerunJob(exec, slug, runId, jobId) {
55874
56132
  }
55875
56133
 
55876
56134
  // src/deploy/scan-task.ts
55877
- var import_node_path34 = __toESM(require("path"), 1);
56135
+ var import_node_path35 = __toESM(require("path"), 1);
55878
56136
  var BUTLER_PERSONA_ID = "persona-clawd-butler";
55879
56137
  var SCANNABLE_ASSETS = [
55880
56138
  {
55881
56139
  name: "deploy-kit",
55882
- path: (dataDir) => import_node_path34.default.join(dataDir, "deploy-kit"),
56140
+ path: (dataDir) => import_node_path35.default.join(dataDir, "deploy-kit"),
55883
56141
  what: "FC \u90E8\u7F72\u80FD\u529B\uFF08publish.sh / new-extension.sh / \u5DE5\u5177\u94FE / \u51ED\u8BC1\u76EE\u5F55\uFF09\u3002persona \u7528\u7EDD\u5BF9\u8DEF\u5F84\u53BB\u8C03\u8FD9\u91CC\u7684\u811A\u672C\u65F6\uFF0C\u5C31\u8BE5\u62A5\u4E00\u6761 asset\u3002"
55884
56142
  },
55885
56143
  {
@@ -56042,7 +56300,7 @@ function buildDeployHandlers(deps) {
56042
56300
  const startedAt = deps.now();
56043
56301
  const base = {
56044
56302
  evidence: scanBase.kind === "hard" ? [] : current?.evidence ?? [],
56045
- // notes 反过来不沿用:它是「这次扫描要老板判断的事」,沿用会把上次的存疑项一直复读
56303
+ // notes 反过来不沿用:它是「这次扫描要老板处理的事」,沿用会把上次的事项一直复读
56046
56304
  notes: [],
56047
56305
  scannedAssets: [],
56048
56306
  startedAt,
@@ -56059,13 +56317,27 @@ function buildDeployHandlers(deps) {
56059
56317
  };
56060
56318
  await writeScan(dir, { status: "scanning", ...base });
56061
56319
  if (scanBase.kind === "hard") await writeDeployFile(dir, emptyDeployFile());
56320
+ const mcp = scanMcpConnectors(dir);
56321
+ const current0 = await readDeployFile(dir) ?? emptyDeployFile();
56322
+ const carried = scanBase.kind === "hard" ? (prevManifest?.manifest.connectors ?? []).filter((c) => c.runner === "mcp") : current0.manifest.connectors;
56323
+ await writeDeployFile(dir, {
56324
+ ...current0,
56325
+ // 文件读不出来(坏 JSON)时保持原样:当成「零个 MCP」会把清单里的连接器清光,而发布闸对零连接器是放行的
56326
+ manifest: { ...current0.manifest, connectors: mcp.readable ? mergeScannedConnectors(carried, mcp.connectors) : carried }
56327
+ });
56328
+ const mcpTargets = new Set(mcp.evidence.map((e) => e.target));
56329
+ const withMcp = {
56330
+ ...base,
56331
+ evidence: [...base.evidence.filter((e) => !mcpTargets.has(e.target)), ...mcp.evidence.map(redactEvidence)],
56332
+ notes: mcp.warnings.map((w2) => `${MCP_SCAN_NOTE_PREFIX}${w2}`)
56333
+ };
56062
56334
  const started = deps.startScan(personaId2, scanBase);
56063
56335
  if ("sessionId" in started) {
56064
- await writeScan(dir, { status: "scanning", scanSessionId: started.sessionId, ...base });
56336
+ await writeScan(dir, { status: "scanning", scanSessionId: started.sessionId, ...withMcp });
56065
56337
  } else {
56066
56338
  await writeScan(dir, {
56067
56339
  status: "failed",
56068
- ...base,
56340
+ ...withMcp,
56069
56341
  finishedAt: deps.now(),
56070
56342
  error: `\u8D77\u626B\u63CF\u4F1A\u8BDD\u5931\u8D25\uFF1A${started.error}`
56071
56343
  });
@@ -56095,7 +56367,7 @@ function buildDeployHandlers(deps) {
56095
56367
  const args = parseArgs2(DeployPutSecretArgsSchema, frame, "deploy:putSecret");
56096
56368
  const dir = mustPersona(args.personaId);
56097
56369
  const file = await readDeployFile(dir);
56098
- const declared = file?.manifest.secrets.find((s) => s.name === args.name);
56370
+ const declared = file ? [...file.manifest.secrets, ...sharedConnectorSecrets(file.manifest)].find((s) => s.name === args.name) : void 0;
56099
56371
  if (!declared) throw invalid(`\u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u51ED\u636E`);
56100
56372
  const allowed = new Set(declared.env);
56101
56373
  for (const key of Object.keys(args.values)) {
@@ -56122,6 +56394,7 @@ function buildDeployHandlers(deps) {
56122
56394
  } catch (err) {
56123
56395
  throw invalid(err instanceof Error ? err.message : String(err));
56124
56396
  }
56397
+ if (args.kind === "connector") item = cliConnectorFromFinding(item);
56125
56398
  const file = await readDeployFile(dir) ?? emptyDeployFile();
56126
56399
  await writeDeployFile(dir, upsertFinding(file, args.kind, item));
56127
56400
  const target = `${args.kind}:${item.name}`;
@@ -56140,8 +56413,9 @@ function buildDeployHandlers(deps) {
56140
56413
  ...scan,
56141
56414
  status: "done",
56142
56415
  finishedAt: deps.now(),
56143
- // 存疑项也是 agent 的自由文本,跟证据同一道涂抹
56144
- notes: args.notes.map(redactSecretValues),
56416
+ // 存疑项也是 agent 的自由文本,跟证据同一道涂抹。daemon 自己扫 .mcp.json 时发现的问题
56417
+ //(带 MCP_SCAN_NOTE_PREFIX)留着——butler 不知道那些,它的那份不该把它们冲掉
56418
+ notes: [...scan.notes.filter((n) => n.startsWith(MCP_SCAN_NOTE_PREFIX)), ...args.notes.map(redactSecretValues)],
56145
56419
  // 记下这次扫描**被告知有哪些共享资产**。以后资产表长出新条目时,只有扫的时候还不知道
56146
56420
  // 它的那些记录会被提示一次(见 staleScannerAssets)
56147
56421
  scannedAssets: SCANNABLE_ASSETS.map((a) => a.name),
@@ -56175,6 +56449,7 @@ function buildDeployHandlers(deps) {
56175
56449
  }
56176
56450
  const missing = requiredEnvNames(file).filter((e) => !present.has(e));
56177
56451
  if (missing.length > 0) blockers.push(`${missing.join(" / ")} \u8FD8\u6CA1\u586B`);
56452
+ for (const c of file.manifest.connectors) blockers.push(...connectorBlockers(c));
56178
56453
  const engine = deps.personaEngine(personaId2);
56179
56454
  const wrongTool = wrongEngine(engine?.tool);
56180
56455
  if (wrongTool) {
@@ -56612,15 +56887,15 @@ async function refreshTunnelUrlOnStartup(deps) {
56612
56887
  }
56613
56888
 
56614
56889
  // src/lark-bot-connector/binding-store.ts
56615
- var import_node_fs29 = __toESM(require("fs"), 1);
56616
- var import_node_path35 = __toESM(require("path"), 1);
56890
+ var import_node_fs30 = __toESM(require("fs"), 1);
56891
+ var import_node_path36 = __toESM(require("path"), 1);
56617
56892
  function createLarkBotBindingStore(personaRoot) {
56618
- const filePath = (personaId2) => import_node_path35.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
56893
+ const filePath = (personaId2) => import_node_path36.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
56619
56894
  const read = (personaId2) => {
56620
56895
  const file = filePath(personaId2);
56621
- if (!import_node_fs29.default.existsSync(file)) return null;
56896
+ if (!import_node_fs30.default.existsSync(file)) return null;
56622
56897
  try {
56623
- const raw = JSON.parse(import_node_fs29.default.readFileSync(file, "utf8"));
56898
+ const raw = JSON.parse(import_node_fs30.default.readFileSync(file, "utf8"));
56624
56899
  if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
56625
56900
  return raw;
56626
56901
  } catch {
@@ -56629,16 +56904,16 @@ function createLarkBotBindingStore(personaRoot) {
56629
56904
  };
56630
56905
  const write = (personaId2, meta) => {
56631
56906
  const file = filePath(personaId2);
56632
- import_node_fs29.default.mkdirSync(import_node_path35.default.dirname(file), { recursive: true });
56907
+ import_node_fs30.default.mkdirSync(import_node_path36.default.dirname(file), { recursive: true });
56633
56908
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
56634
- import_node_fs29.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
56635
- import_node_fs29.default.renameSync(tmp, file);
56909
+ import_node_fs30.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
56910
+ import_node_fs30.default.renameSync(tmp, file);
56636
56911
  };
56637
56912
  return {
56638
56913
  read,
56639
56914
  write,
56640
56915
  remove(personaId2) {
56641
- import_node_fs29.default.rmSync(filePath(personaId2), { force: true });
56916
+ import_node_fs30.default.rmSync(filePath(personaId2), { force: true });
56642
56917
  },
56643
56918
  addRemovedChat(personaId2, chatId) {
56644
56919
  const meta = read(personaId2);
@@ -56796,8 +57071,8 @@ function createLarkBotCloudClient(opts) {
56796
57071
  }
56797
57072
 
56798
57073
  // src/lark-bot-connector/chat-router.ts
56799
- var import_node_fs30 = __toESM(require("fs"), 1);
56800
- var import_node_path36 = __toESM(require("path"), 1);
57074
+ var import_node_fs31 = __toESM(require("fs"), 1);
57075
+ var import_node_path37 = __toESM(require("path"), 1);
56801
57076
  init_protocol();
56802
57077
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
56803
57078
  var LOCAL_TURN_RETRIES = 2;
@@ -56875,9 +57150,9 @@ function createLarkChatRouter(deps) {
56875
57150
  continue;
56876
57151
  }
56877
57152
  const dir = deps.mediaRootFor(env.chatId);
56878
- import_node_fs30.default.mkdirSync(dir, { recursive: true });
56879
- const p2 = import_node_path36.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
56880
- import_node_fs30.default.writeFileSync(p2, r.data);
57153
+ import_node_fs31.default.mkdirSync(dir, { recursive: true });
57154
+ const p2 = import_node_path37.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
57155
+ import_node_fs31.default.writeFileSync(p2, r.data);
56881
57156
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
56882
57157
  } catch (err) {
56883
57158
  deps.logger?.warn(`larkBot image fetch failed ${key}: ${err.message}`);
@@ -56898,9 +57173,9 @@ function createLarkChatRouter(deps) {
56898
57173
  continue;
56899
57174
  }
56900
57175
  const dir = deps.mediaRootFor(env.chatId);
56901
- import_node_fs30.default.mkdirSync(dir, { recursive: true });
56902
- const p2 = import_node_path36.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
56903
- import_node_fs30.default.writeFileSync(p2, r.data);
57176
+ import_node_fs31.default.mkdirSync(dir, { recursive: true });
57177
+ const p2 = import_node_path37.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
57178
+ import_node_fs31.default.writeFileSync(p2, r.data);
56904
57179
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
56905
57180
  } catch (err) {
56906
57181
  deps.logger?.warn(`larkBot file fetch failed ${f.key}: ${err.message}`);
@@ -57724,12 +57999,12 @@ async function forwardPeerExecToPeer(args) {
57724
57999
  }
57725
58000
 
57726
58001
  // src/tools/codex-history.ts
57727
- var import_node_fs32 = __toESM(require("fs"), 1);
57728
- var import_node_path38 = __toESM(require("path"), 1);
58002
+ var import_node_fs33 = __toESM(require("fs"), 1);
58003
+ var import_node_path39 = __toESM(require("path"), 1);
57729
58004
 
57730
58005
  // src/tools/transcript-search.ts
57731
- var import_node_fs31 = __toESM(require("fs"), 1);
57732
- var import_node_path37 = __toESM(require("path"), 1);
58006
+ var import_node_fs32 = __toESM(require("fs"), 1);
58007
+ var import_node_path38 = __toESM(require("path"), 1);
57733
58008
  var SNIPPET_PAD = 60;
57734
58009
  var INJECTED_ENVELOPE_RE = /^<(system-reminder|command-name|command-message|command-args|local-command-stdout|local-command-stderr|task-notification|user-prompt-submit-hook|environment_context|user_instructions)\b/;
57735
58010
  var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
@@ -57784,7 +58059,7 @@ function makeSnippet(text, at2, needleLength) {
57784
58059
  function searchTranscriptFile(file, query) {
57785
58060
  let buf;
57786
58061
  try {
57787
- buf = import_node_fs31.default.readFileSync(file);
58062
+ buf = import_node_fs32.default.readFileSync(file);
57788
58063
  } catch {
57789
58064
  return null;
57790
58065
  }
@@ -57817,12 +58092,12 @@ function createCodexRolloutLocator(roots) {
57817
58092
  const walk2 = (dir, into) => {
57818
58093
  let entries;
57819
58094
  try {
57820
- entries = import_node_fs31.default.readdirSync(dir, { withFileTypes: true });
58095
+ entries = import_node_fs32.default.readdirSync(dir, { withFileTypes: true });
57821
58096
  } catch {
57822
58097
  return;
57823
58098
  }
57824
58099
  for (const entry of entries) {
57825
- const full = import_node_path37.default.join(dir, entry.name);
58100
+ const full = import_node_path38.default.join(dir, entry.name);
57826
58101
  if (entry.isDirectory()) {
57827
58102
  walk2(full, into);
57828
58103
  continue;
@@ -58044,18 +58319,18 @@ var TITLE_BYTES = 256 * 1024;
58044
58319
  function readHead(file, bytes) {
58045
58320
  let fd;
58046
58321
  try {
58047
- fd = import_node_fs32.default.openSync(file, "r");
58322
+ fd = import_node_fs33.default.openSync(file, "r");
58048
58323
  } catch {
58049
58324
  return null;
58050
58325
  }
58051
58326
  try {
58052
58327
  const buf = Buffer.alloc(bytes);
58053
- const n = import_node_fs32.default.readSync(fd, buf, 0, bytes, 0);
58328
+ const n = import_node_fs33.default.readSync(fd, buf, 0, bytes, 0);
58054
58329
  return buf.subarray(0, n).toString("utf8");
58055
58330
  } catch {
58056
58331
  return null;
58057
58332
  } finally {
58058
- import_node_fs32.default.closeSync(fd);
58333
+ import_node_fs33.default.closeSync(fd);
58059
58334
  }
58060
58335
  }
58061
58336
  function peekSessionCwd(head) {
@@ -58071,7 +58346,7 @@ function peekSessionCwd(head) {
58071
58346
  function readFirstLine(file, max = 512 * 1024) {
58072
58347
  let fd;
58073
58348
  try {
58074
- fd = import_node_fs32.default.openSync(file, "r");
58349
+ fd = import_node_fs33.default.openSync(file, "r");
58075
58350
  } catch {
58076
58351
  return null;
58077
58352
  }
@@ -58080,7 +58355,7 @@ function readFirstLine(file, max = 512 * 1024) {
58080
58355
  const parts = [];
58081
58356
  let total = 0;
58082
58357
  while (total < max) {
58083
- const n = import_node_fs32.default.readSync(fd, chunk, 0, chunk.length, total);
58358
+ const n = import_node_fs33.default.readSync(fd, chunk, 0, chunk.length, total);
58084
58359
  if (n <= 0) break;
58085
58360
  const nl = chunk.subarray(0, n).indexOf(10);
58086
58361
  if (nl >= 0) {
@@ -58094,7 +58369,7 @@ function readFirstLine(file, max = 512 * 1024) {
58094
58369
  } catch {
58095
58370
  return null;
58096
58371
  } finally {
58097
- import_node_fs32.default.closeSync(fd);
58372
+ import_node_fs33.default.closeSync(fd);
58098
58373
  }
58099
58374
  }
58100
58375
  function readThreadNames(sharedHome) {
@@ -58102,7 +58377,7 @@ function readThreadNames(sharedHome) {
58102
58377
  if (!sharedHome) return names;
58103
58378
  let raw;
58104
58379
  try {
58105
- raw = import_node_fs32.default.readFileSync(import_node_path38.default.join(sharedHome, "session_index.jsonl"), "utf8");
58380
+ raw = import_node_fs33.default.readFileSync(import_node_path39.default.join(sharedHome, "session_index.jsonl"), "utf8");
58106
58381
  } catch {
58107
58382
  return names;
58108
58383
  }
@@ -58121,13 +58396,13 @@ function readThreadNames(sharedHome) {
58121
58396
  function walkRollouts(dir, visit) {
58122
58397
  let entries;
58123
58398
  try {
58124
- entries = import_node_fs32.default.readdirSync(dir, { withFileTypes: true });
58399
+ entries = import_node_fs33.default.readdirSync(dir, { withFileTypes: true });
58125
58400
  } catch {
58126
58401
  return true;
58127
58402
  }
58128
58403
  entries.sort((a, b2) => a.name < b2.name ? 1 : a.name > b2.name ? -1 : 0);
58129
58404
  for (const entry of entries) {
58130
- const full = import_node_path38.default.join(dir, entry.name);
58405
+ const full = import_node_path39.default.join(dir, entry.name);
58131
58406
  if (entry.isDirectory()) {
58132
58407
  if (!walkRollouts(full, visit)) return false;
58133
58408
  } else if (ROLLOUT_NAME_RE.test(entry.name)) {
@@ -58195,7 +58470,7 @@ var CodexHistoryReader = class {
58195
58470
  return [];
58196
58471
  }
58197
58472
  async listSessions(args) {
58198
- const want = import_node_path38.default.resolve(args.projectPath);
58473
+ const want = import_node_path39.default.resolve(args.projectPath);
58199
58474
  const names = readThreadNames(this.deps.sharedHome);
58200
58475
  const found = [];
58201
58476
  let scanned = 0;
@@ -58204,13 +58479,13 @@ var CodexHistoryReader = class {
58204
58479
  if (++scanned > CODEX_LIST_SESSIONS_SCAN_CAP) return false;
58205
58480
  const head = readHead(file, PEEK_BYTES);
58206
58481
  const cwd = head === null ? null : peekSessionCwd(head);
58207
- if (!cwd || import_node_path38.default.resolve(cwd) !== want) return;
58482
+ if (!cwd || import_node_path39.default.resolve(cwd) !== want) return;
58208
58483
  const first = readFirstLine(file);
58209
58484
  const meta = first === null ? null : parseCodexRolloutMeta(first);
58210
58485
  if (!meta) return;
58211
58486
  let mtimeMs;
58212
58487
  try {
58213
- mtimeMs = import_node_fs32.default.statSync(file).mtimeMs;
58488
+ mtimeMs = import_node_fs33.default.statSync(file).mtimeMs;
58214
58489
  } catch {
58215
58490
  return;
58216
58491
  }
@@ -58242,7 +58517,7 @@ var CodexHistoryReader = class {
58242
58517
  args.toolSessionId,
58243
58518
  async (agentId) => {
58244
58519
  const file = locate(agentId);
58245
- return file ? import_node_fs32.default.readFileSync(file, "utf8") : null;
58520
+ return file ? import_node_fs33.default.readFileSync(file, "utf8") : null;
58246
58521
  },
58247
58522
  this.deps.logger
58248
58523
  );
@@ -58269,7 +58544,7 @@ var CodexHistoryReader = class {
58269
58544
  parseThread(locate, threadId) {
58270
58545
  const file = locate(threadId);
58271
58546
  if (!file) throw new Error(`Codex rollout not found for thread ${threadId}`);
58272
- return parseCodexRollout(import_node_fs32.default.readFileSync(file, "utf8"));
58547
+ return parseCodexRollout(import_node_fs33.default.readFileSync(file, "utf8"));
58273
58548
  }
58274
58549
  };
58275
58550
 
@@ -58288,9 +58563,9 @@ var CentralClientError = class extends Error {
58288
58563
  code;
58289
58564
  cause;
58290
58565
  };
58291
- async function centralRequest(opts, path100, init) {
58566
+ async function centralRequest(opts, path101, init) {
58292
58567
  const f = opts.fetchImpl ?? globalThis.fetch;
58293
- const url = `${opts.api.replace(/\/+$/, "")}${path100}`;
58568
+ const url = `${opts.api.replace(/\/+$/, "")}${path101}`;
58294
58569
  const ctrl = new AbortController();
58295
58570
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
58296
58571
  let res;
@@ -58313,7 +58588,13 @@ async function centralRequest(opts, path100, init) {
58313
58588
  throw new CentralClientError("UNAUTHORIZED", "TTC JWT invalid or expired");
58314
58589
  }
58315
58590
  if (!res.ok) {
58316
- throw new CentralClientError("API_ERROR", `central server HTTP ${res.status}`);
58591
+ let detail = "";
58592
+ try {
58593
+ const body = await res.json();
58594
+ if (typeof body?.message === "string" && body.message) detail = `: ${body.message}`;
58595
+ } catch {
58596
+ }
58597
+ throw new CentralClientError("API_ERROR", `central server HTTP ${res.status}${detail}`);
58317
58598
  }
58318
58599
  try {
58319
58600
  return await res.json();
@@ -58425,6 +58706,23 @@ async function centralListDevices(opts) {
58425
58706
  }
58426
58707
  return out;
58427
58708
  }
58709
+ async function centralConnectorsMine(opts) {
58710
+ const body = await centralRequest(opts, "/api/persona-cloud/connectors/mine", {
58711
+ method: "POST",
58712
+ bearer: opts.ttcJwt,
58713
+ body: { provider: opts.provider, personaId: opts.personaId, connectors: opts.connectors }
58714
+ });
58715
+ if (!Array.isArray(body.connectors)) throw new CentralClientError("BAD_RESPONSE", "connectors/mine: missing connectors array");
58716
+ return { connectors: body.connectors };
58717
+ }
58718
+ async function centralConnectorFill(opts) {
58719
+ const body = await centralRequest(opts, "/api/persona-cloud/connectors/fields", {
58720
+ method: "PUT",
58721
+ bearer: opts.ttcJwt,
58722
+ body: { provider: opts.provider, connector: opts.connector, values: opts.values }
58723
+ });
58724
+ if (body.ok !== true) throw new CentralClientError("BAD_RESPONSE", "connectors/fields: server did not ack ok");
58725
+ }
58428
58726
 
58429
58727
  // src/cloud/gateway-client.ts
58430
58728
  var GATEWAY_ROUTES = {
@@ -58483,11 +58781,18 @@ var CloudGatewayClient = class {
58483
58781
  ...typeof d.image === "string" ? { image: d.image } : {},
58484
58782
  ...typeof d.model === "string" && d.model ? { model: d.model } : {},
58485
58783
  ...typeof d.effort === "string" && d.effort ? { effort: d.effort } : {},
58486
- ...typeof d.registeredAt === "number" ? { registeredAt: d.registeredAt } : {}
58784
+ ...typeof d.registeredAt === "number" ? { registeredAt: d.registeredAt } : {},
58785
+ // 形状不对的条目丢掉不抛:老 gateway 的登记行是名字数组,那种就是「没有连接器」
58786
+ ...Array.isArray(d.connectors) ? { connectors: d.connectors.map((c) => EnvConnectorSchema.safeParse(c)).flatMap((p2) => p2.success ? [p2.data] : []) } : {}
58487
58787
  });
58488
58788
  }
58489
58789
  return out;
58490
58790
  }
58791
+ /** gateway 登记行上这个 persona(gateway 名)装了哪些连接器;没这行 = 空 */
58792
+ async personaConnectors(gatewayPersonaId) {
58793
+ const list = await this.listPersonas();
58794
+ return list.find((p2) => p2.personaId === gatewayPersonaId)?.connectors ?? [];
58795
+ }
58491
58796
  /**
58492
58797
  * 会话通道。返回的行流在 Pod 就绪前就能 write:写入先攒着,收到 `ready` 控制行后按序 POST 出去——
58493
58798
  * 编排那头一构造就发 initialize,不用知道 Pod 还在起。
@@ -58682,7 +58987,7 @@ function openHttpLineStream(opts) {
58682
58987
  init_protocol();
58683
58988
 
58684
58989
  // src/tools/codex-cloud-session.ts
58685
- var import_node_fs33 = __toESM(require("fs"), 1);
58990
+ var import_node_fs34 = __toESM(require("fs"), 1);
58686
58991
 
58687
58992
  // src/tools/codex-cloud-history.ts
58688
58993
  function personaIdFromCloudCwd(cwd) {
@@ -58806,7 +59111,7 @@ function cloudImageInput(deps) {
58806
59111
  const mime = lookupMime(p2);
58807
59112
  if (!mime.startsWith("image/")) return null;
58808
59113
  try {
58809
- const bytes = (deps.readFile ?? import_node_fs33.default.readFileSync)(p2);
59114
+ const bytes = (deps.readFile ?? import_node_fs34.default.readFileSync)(p2);
58810
59115
  return { type: "image", url: `data:${mime};base64,${bytes.toString("base64")}` };
58811
59116
  } catch (e) {
58812
59117
  deps.logger?.warn("cloud image attachment unreadable", { path: p2, message: e.message });
@@ -58919,7 +59224,7 @@ var CloudCodexAdapter = class {
58919
59224
 
58920
59225
  // src/tools/pi.ts
58921
59226
  var import_node_child_process10 = require("child_process");
58922
- var import_node_fs36 = __toESM(require("fs"), 1);
59227
+ var import_node_fs37 = __toESM(require("fs"), 1);
58923
59228
  init_protocol();
58924
59229
 
58925
59230
  // src/tools/pi-rpc-client.ts
@@ -58998,8 +59303,8 @@ var PiRpcClient = class {
58998
59303
  // src/tools/pi-session.ts
58999
59304
  var import_node_child_process9 = require("child_process");
59000
59305
  var import_node_crypto9 = require("crypto");
59001
- var import_node_fs34 = __toESM(require("fs"), 1);
59002
- var import_node_path39 = __toESM(require("path"), 1);
59306
+ var import_node_fs35 = __toESM(require("fs"), 1);
59307
+ var import_node_path40 = __toESM(require("path"), 1);
59003
59308
 
59004
59309
  // src/tools/pi-events.ts
59005
59310
  init_protocol();
@@ -59176,8 +59481,8 @@ ${dirs.map((d) => `- ${d}`).join("\n")}`;
59176
59481
  function createPiSession(ctx, sink, deps = {}) {
59177
59482
  const cmd = process.env.PI_BIN ?? "pi";
59178
59483
  const sessionId = ctx.toolSessionId ?? (0, import_node_crypto9.randomUUID)();
59179
- const skillsDir = import_node_path39.default.join(ctx.cwd, ".claude", "skills");
59180
- const exists = deps.skillsDirExists ?? ((d) => import_node_fs34.default.existsSync(d));
59484
+ const skillsDir = import_node_path40.default.join(ctx.cwd, ".claude", "skills");
59485
+ const exists = deps.skillsDirExists ?? ((d) => import_node_fs35.default.existsSync(d));
59181
59486
  const args = buildPiArgs(ctx, {
59182
59487
  sessionId,
59183
59488
  skillsDir: exists(skillsDir) ? skillsDir : void 0,
@@ -59293,45 +59598,45 @@ function createPiSession(ctx, sink, deps = {}) {
59293
59598
  }
59294
59599
 
59295
59600
  // src/tools/pi-history.ts
59296
- var import_node_fs35 = __toESM(require("fs"), 1);
59601
+ var import_node_fs36 = __toESM(require("fs"), 1);
59297
59602
  var import_node_os10 = __toESM(require("os"), 1);
59298
- var import_node_path40 = __toESM(require("path"), 1);
59603
+ var import_node_path41 = __toESM(require("path"), 1);
59299
59604
  var PI_LIST_SESSIONS_LIMIT = 100;
59300
59605
  var PI_LIST_SESSIONS_SCAN_CAP = 4e3;
59301
59606
  function piAgentDir(env = process.env) {
59302
- return env.PI_CODING_AGENT_DIR || import_node_path40.default.join(import_node_os10.default.homedir(), ".pi", "agent");
59607
+ return env.PI_CODING_AGENT_DIR || import_node_path41.default.join(import_node_os10.default.homedir(), ".pi", "agent");
59303
59608
  }
59304
59609
  function piSessionsRoot(env = process.env) {
59305
- return import_node_path40.default.join(piAgentDir(env), "sessions");
59610
+ return import_node_path41.default.join(piAgentDir(env), "sessions");
59306
59611
  }
59307
59612
  function encodePiCwd(cwd) {
59308
59613
  return `--${cwd.replace(/^[\\/]+/, "").replace(/[\\/:]/g, "-")}--`;
59309
59614
  }
59310
59615
  function piProjectSessionDir(sessionsRoot, cwd) {
59311
- return import_node_path40.default.join(sessionsRoot, encodePiCwd(cwd));
59616
+ return import_node_path41.default.join(sessionsRoot, encodePiCwd(cwd));
59312
59617
  }
59313
59618
  function findInDir(dir, toolSessionId) {
59314
59619
  let names;
59315
59620
  try {
59316
- names = import_node_fs35.default.readdirSync(dir);
59621
+ names = import_node_fs36.default.readdirSync(dir);
59317
59622
  } catch {
59318
59623
  return null;
59319
59624
  }
59320
59625
  const suffix = `_${toolSessionId}.jsonl`;
59321
59626
  const hit = names.filter((n) => n.endsWith(suffix)).sort().at(-1);
59322
- return hit ? import_node_path40.default.join(dir, hit) : null;
59627
+ return hit ? import_node_path41.default.join(dir, hit) : null;
59323
59628
  }
59324
59629
  function locatePiSessionFile(sessionsRoot, cwd, toolSessionId) {
59325
59630
  const direct = findInDir(piProjectSessionDir(sessionsRoot, cwd), toolSessionId);
59326
59631
  if (direct) return direct;
59327
59632
  let dirs;
59328
59633
  try {
59329
- dirs = import_node_fs35.default.readdirSync(sessionsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
59634
+ dirs = import_node_fs36.default.readdirSync(sessionsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
59330
59635
  } catch {
59331
59636
  return null;
59332
59637
  }
59333
59638
  for (const d of dirs) {
59334
- const hit = findInDir(import_node_path40.default.join(sessionsRoot, d), toolSessionId);
59639
+ const hit = findInDir(import_node_path41.default.join(sessionsRoot, d), toolSessionId);
59335
59640
  if (hit) return hit;
59336
59641
  }
59337
59642
  return null;
@@ -59430,11 +59735,11 @@ var PiHistoryReader = class {
59430
59735
  return [];
59431
59736
  }
59432
59737
  async listSessions(args) {
59433
- const want = import_node_path40.default.resolve(args.projectPath);
59738
+ const want = import_node_path41.default.resolve(args.projectPath);
59434
59739
  const dir = piProjectSessionDir(this.deps.sessionsRoot, want);
59435
59740
  let names;
59436
59741
  try {
59437
- names = import_node_fs35.default.readdirSync(dir).filter((n) => n.endsWith(".jsonl"));
59742
+ names = import_node_fs36.default.readdirSync(dir).filter((n) => n.endsWith(".jsonl"));
59438
59743
  } catch {
59439
59744
  return [];
59440
59745
  }
@@ -59442,15 +59747,15 @@ var PiHistoryReader = class {
59442
59747
  let scanned = 0;
59443
59748
  for (const n of names) {
59444
59749
  if (++scanned > PI_LIST_SESSIONS_SCAN_CAP) break;
59445
- const file = import_node_path40.default.join(dir, n);
59750
+ const file = import_node_path41.default.join(dir, n);
59446
59751
  const head = parseLine2(readFirstLine(file) ?? "");
59447
59752
  if (!head || head.type !== "session") continue;
59448
59753
  const cwd = str3(head.cwd);
59449
59754
  const id = str3(head.id);
59450
- if (!cwd || !id || import_node_path40.default.resolve(cwd) !== want) continue;
59755
+ if (!cwd || !id || import_node_path41.default.resolve(cwd) !== want) continue;
59451
59756
  let mtimeMs;
59452
59757
  try {
59453
- mtimeMs = import_node_fs35.default.statSync(file).mtimeMs;
59758
+ mtimeMs = import_node_fs36.default.statSync(file).mtimeMs;
59454
59759
  } catch {
59455
59760
  continue;
59456
59761
  }
@@ -59458,7 +59763,7 @@ var PiHistoryReader = class {
59458
59763
  }
59459
59764
  found.sort((a, b2) => b2.mtimeMs - a.mtimeMs);
59460
59765
  return found.slice(0, PI_LIST_SESSIONS_LIMIT).map((f) => {
59461
- const parsed = parsePiSession(import_node_fs35.default.readFileSync(f.file, "utf8"));
59766
+ const parsed = parsePiSession(import_node_fs36.default.readFileSync(f.file, "utf8"));
59462
59767
  const firstUser = parsed.messages.find((m2) => m2.kind === "user-text");
59463
59768
  return {
59464
59769
  toolSessionId: f.id,
@@ -59471,7 +59776,7 @@ var PiHistoryReader = class {
59471
59776
  async read(args) {
59472
59777
  const file = locatePiSessionFile(this.deps.sessionsRoot, args.cwd, args.toolSessionId);
59473
59778
  if (!file) throw new Error(`pi session not found for ${args.toolSessionId}`);
59474
- return pageMessages(parsePiSession(import_node_fs35.default.readFileSync(file, "utf8")).messages, args);
59779
+ return pageMessages(parsePiSession(import_node_fs36.default.readFileSync(file, "utf8")).messages, args);
59475
59780
  }
59476
59781
  async listSubagents(_args) {
59477
59782
  return [];
@@ -59506,10 +59811,10 @@ var PI_DEFAULT_MODEL_ENTRY = {
59506
59811
  };
59507
59812
  var PI_FULL_ACCESS = { id: "never", label: "Full Access", description: "pi \u65E0\u5BA1\u6279\uFF1A\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" };
59508
59813
  async function probePi(env = process.env) {
59509
- if (env.PI_BIN && import_node_fs36.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
59814
+ if (env.PI_BIN && import_node_fs37.default.existsSync(env.PI_BIN)) return { available: true, path: env.PI_BIN };
59510
59815
  try {
59511
59816
  const out = (0, import_node_child_process10.execFileSync)("which", ["pi"], { encoding: "utf8" }).trim();
59512
- if (out && import_node_fs36.default.existsSync(out)) return { available: true, path: out };
59817
+ if (out && import_node_fs37.default.existsSync(out)) return { available: true, path: out };
59513
59818
  } catch {
59514
59819
  }
59515
59820
  return { available: false };
@@ -59676,7 +59981,7 @@ var PiAdapter = class {
59676
59981
  init_protocol();
59677
59982
 
59678
59983
  // src/tools/codex-skills.ts
59679
- var import_node_path41 = __toESM(require("path"), 1);
59984
+ var import_node_path42 = __toESM(require("path"), 1);
59680
59985
  function str4(v2) {
59681
59986
  return typeof v2 === "string" ? v2 : void 0;
59682
59987
  }
@@ -59691,13 +59996,13 @@ function mapSkillsListResponse(res) {
59691
59996
  const r = s ?? {};
59692
59997
  const name = str4(r.name);
59693
59998
  if (!name) continue;
59694
- const path100 = str4(r.path);
59999
+ const path101 = str4(r.path);
59695
60000
  const description = str4(r.description);
59696
60001
  const isPlugin = name.includes(":");
59697
60002
  out.push({
59698
60003
  name,
59699
60004
  source: isPlugin ? "plugin" : "project",
59700
- ...path100 ? { path: path100 } : {},
60005
+ ...path101 ? { path: path101 } : {},
59701
60006
  ...description ? { description } : {},
59702
60007
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
59703
60008
  });
@@ -59713,7 +60018,7 @@ async function listCodexSkills(cwd, deps = {}) {
59713
60018
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
59714
60019
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
59715
60020
  beforeRequest: (client) => {
59716
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path41.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
60021
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path42.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
59717
60022
  }
59718
60023
  });
59719
60024
  return mapSkillsListResponse(res);
@@ -59787,23 +60092,23 @@ function rec4(v2) {
59787
60092
  }
59788
60093
 
59789
60094
  // src/workspace/browser.ts
59790
- var import_node_fs37 = __toESM(require("fs"), 1);
60095
+ var import_node_fs38 = __toESM(require("fs"), 1);
59791
60096
  var import_node_os11 = __toESM(require("os"), 1);
59792
- var import_node_path42 = __toESM(require("path"), 1);
60097
+ var import_node_path43 = __toESM(require("path"), 1);
59793
60098
  init_protocol();
59794
60099
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
59795
60100
  function resolveInsideCwd(cwd, subpath) {
59796
- const absCwd = import_node_path42.default.resolve(cwd);
59797
- const joined = import_node_path42.default.resolve(absCwd, subpath ?? ".");
59798
- const rel = import_node_path42.default.relative(absCwd, joined);
59799
- if (rel.startsWith("..") || import_node_path42.default.isAbsolute(rel)) {
60101
+ const absCwd = import_node_path43.default.resolve(cwd);
60102
+ const joined = import_node_path43.default.resolve(absCwd, subpath ?? ".");
60103
+ const rel = import_node_path43.default.relative(absCwd, joined);
60104
+ if (rel.startsWith("..") || import_node_path43.default.isAbsolute(rel)) {
59800
60105
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
59801
60106
  }
59802
60107
  return joined;
59803
60108
  }
59804
60109
  function ensureCwd(cwd) {
59805
60110
  try {
59806
- const stat = import_node_fs37.default.statSync(cwd);
60111
+ const stat = import_node_fs38.default.statSync(cwd);
59807
60112
  if (!stat.isDirectory()) {
59808
60113
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
59809
60114
  }
@@ -59817,7 +60122,7 @@ var WorkspaceBrowser = class {
59817
60122
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os11.default.homedir();
59818
60123
  ensureCwd(cwd);
59819
60124
  const full = resolveInsideCwd(cwd, args.path);
59820
- const dirents = import_node_fs37.default.readdirSync(full, { withFileTypes: true });
60125
+ const dirents = import_node_fs38.default.readdirSync(full, { withFileTypes: true });
59821
60126
  const entries = [];
59822
60127
  for (const d of dirents) {
59823
60128
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -59827,7 +60132,7 @@ var WorkspaceBrowser = class {
59827
60132
  mtime: ""
59828
60133
  };
59829
60134
  try {
59830
- const st = import_node_fs37.default.statSync(import_node_path42.default.join(full, d.name));
60135
+ const st = import_node_fs38.default.statSync(import_node_path43.default.join(full, d.name));
59831
60136
  entry.mtime = new Date(st.mtimeMs).toISOString();
59832
60137
  if (d.isFile()) entry.size = st.size;
59833
60138
  } catch {
@@ -59843,14 +60148,14 @@ var WorkspaceBrowser = class {
59843
60148
  read(args) {
59844
60149
  ensureCwd(args.cwd);
59845
60150
  const full = resolveInsideCwd(args.cwd, args.path);
59846
- const st = import_node_fs37.default.statSync(full);
60151
+ const st = import_node_fs38.default.statSync(full);
59847
60152
  if (!st.isFile()) {
59848
60153
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
59849
60154
  }
59850
60155
  if (st.size > MAX_FILE_BYTES2) {
59851
60156
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
59852
60157
  }
59853
- const buf = import_node_fs37.default.readFileSync(full);
60158
+ const buf = import_node_fs38.default.readFileSync(full);
59854
60159
  const isBinary = buf.includes(0);
59855
60160
  if (isBinary) {
59856
60161
  return {
@@ -59872,20 +60177,20 @@ var WorkspaceBrowser = class {
59872
60177
  };
59873
60178
 
59874
60179
  // src/skills/agents-scanner.ts
59875
- var import_node_fs38 = __toESM(require("fs"), 1);
60180
+ var import_node_fs39 = __toESM(require("fs"), 1);
59876
60181
  var import_node_os12 = __toESM(require("os"), 1);
59877
- var import_node_path43 = __toESM(require("path"), 1);
60182
+ var import_node_path44 = __toESM(require("path"), 1);
59878
60183
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
59879
60184
  function isDirLikeSync2(p2) {
59880
60185
  try {
59881
- return import_node_fs38.default.statSync(p2).isDirectory();
60186
+ return import_node_fs39.default.statSync(p2).isDirectory();
59882
60187
  } catch {
59883
60188
  return false;
59884
60189
  }
59885
60190
  }
59886
60191
  function fileExistsSync(p2) {
59887
60192
  try {
59888
- return import_node_fs38.default.statSync(p2).isFile();
60193
+ return import_node_fs39.default.statSync(p2).isFile();
59889
60194
  } catch {
59890
60195
  return false;
59891
60196
  }
@@ -59893,7 +60198,7 @@ function fileExistsSync(p2) {
59893
60198
  function parseAgentFile(filePath) {
59894
60199
  let content;
59895
60200
  try {
59896
- content = import_node_fs38.default.readFileSync(filePath, "utf8");
60201
+ content = import_node_fs39.default.readFileSync(filePath, "utf8");
59897
60202
  } catch {
59898
60203
  return {};
59899
60204
  }
@@ -59906,16 +60211,16 @@ function parseAgentFile(filePath) {
59906
60211
  function scanAgentsDir(dir, source, seen, out) {
59907
60212
  let entries;
59908
60213
  try {
59909
- entries = import_node_fs38.default.readdirSync(dir, { withFileTypes: true });
60214
+ entries = import_node_fs39.default.readdirSync(dir, { withFileTypes: true });
59910
60215
  } catch {
59911
60216
  return;
59912
60217
  }
59913
60218
  for (const ent of entries) {
59914
60219
  if (!ent.name.endsWith(".md")) continue;
59915
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path43.default.join(dir, ent.name)))) {
60220
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path44.default.join(dir, ent.name)))) {
59916
60221
  continue;
59917
60222
  }
59918
- const filePath = import_node_path43.default.join(dir, ent.name);
60223
+ const filePath = import_node_path44.default.join(dir, ent.name);
59919
60224
  const baseName = ent.name.replace(/\.md$/, "");
59920
60225
  if (seen.has(baseName)) continue;
59921
60226
  seen.add(baseName);
@@ -59933,12 +60238,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
59933
60238
  function walk2(dir, namespaces) {
59934
60239
  let entries;
59935
60240
  try {
59936
- entries = import_node_fs38.default.readdirSync(dir, { withFileTypes: true });
60241
+ entries = import_node_fs39.default.readdirSync(dir, { withFileTypes: true });
59937
60242
  } catch {
59938
60243
  return;
59939
60244
  }
59940
60245
  for (const ent of entries) {
59941
- const childPath = import_node_path43.default.join(dir, ent.name);
60246
+ const childPath = import_node_path44.default.join(dir, ent.name);
59942
60247
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
59943
60248
  walk2(childPath, [...namespaces, ent.name]);
59944
60249
  continue;
@@ -59963,13 +60268,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
59963
60268
  walk2(root, []);
59964
60269
  }
59965
60270
  function readInstalledPlugins2(home) {
59966
- const pluginsDir = import_node_path43.default.join(home, ".claude", "plugins");
59967
- const v2 = import_node_path43.default.join(pluginsDir, "installed_plugins_v2.json");
59968
- const v1 = import_node_path43.default.join(pluginsDir, "installed_plugins.json");
60271
+ const pluginsDir = import_node_path44.default.join(home, ".claude", "plugins");
60272
+ const v2 = import_node_path44.default.join(pluginsDir, "installed_plugins_v2.json");
60273
+ const v1 = import_node_path44.default.join(pluginsDir, "installed_plugins.json");
59969
60274
  let raw = null;
59970
60275
  for (const candidate of [v2, v1]) {
59971
60276
  try {
59972
- raw = import_node_fs38.default.readFileSync(candidate, "utf8");
60277
+ raw = import_node_fs39.default.readFileSync(candidate, "utf8");
59973
60278
  break;
59974
60279
  } catch {
59975
60280
  }
@@ -59994,19 +60299,19 @@ function readInstalledPlugins2(home) {
59994
60299
  return out;
59995
60300
  }
59996
60301
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
59997
- let cur = import_node_path43.default.resolve(startCwd);
59998
- const fsRoot = import_node_path43.default.parse(cur).root;
60302
+ let cur = import_node_path44.default.resolve(startCwd);
60303
+ const fsRoot = import_node_path44.default.parse(cur).root;
59999
60304
  while (true) {
60000
- scanAgentsDir(import_node_path43.default.join(cur, ".claude", "agents"), "project", seen, out);
60305
+ scanAgentsDir(import_node_path44.default.join(cur, ".claude", "agents"), "project", seen, out);
60001
60306
  let hasGit = false;
60002
60307
  try {
60003
- hasGit = import_node_fs38.default.existsSync(import_node_path43.default.join(cur, ".git"));
60308
+ hasGit = import_node_fs39.default.existsSync(import_node_path44.default.join(cur, ".git"));
60004
60309
  } catch {
60005
60310
  }
60006
60311
  if (hasGit) return;
60007
60312
  if (cur === home) return;
60008
60313
  if (cur === fsRoot) return;
60009
- const parent = import_node_path43.default.dirname(cur);
60314
+ const parent = import_node_path44.default.dirname(cur);
60010
60315
  if (parent === cur) return;
60011
60316
  cur = parent;
60012
60317
  }
@@ -60041,7 +60346,7 @@ var AgentsScanner = class {
60041
60346
  }
60042
60347
  const fsBlock = [];
60043
60348
  scanAgentsDir(
60044
- import_node_path43.default.join(this.home, ".claude", "agents"),
60349
+ import_node_path44.default.join(this.home, ".claude", "agents"),
60045
60350
  "global",
60046
60351
  seen,
60047
60352
  fsBlock
@@ -60055,7 +60360,7 @@ var AgentsScanner = class {
60055
60360
  ...this.extraPluginRoots
60056
60361
  ];
60057
60362
  for (const { name, root } of plugins) {
60058
- const agentsRoot = import_node_path43.default.join(root, "agents");
60363
+ const agentsRoot = import_node_path44.default.join(root, "agents");
60059
60364
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
60060
60365
  }
60061
60366
  return [...builtinBlock, ...fsBlock];
@@ -60063,15 +60368,15 @@ var AgentsScanner = class {
60063
60368
  };
60064
60369
 
60065
60370
  // src/observer/session-observer.ts
60066
- var import_node_fs40 = __toESM(require("fs"), 1);
60371
+ var import_node_fs41 = __toESM(require("fs"), 1);
60067
60372
  var import_node_os14 = __toESM(require("os"), 1);
60068
- var import_node_path45 = __toESM(require("path"), 1);
60373
+ var import_node_path46 = __toESM(require("path"), 1);
60069
60374
  init_claude_history();
60070
60375
 
60071
60376
  // src/observer/subagent-meta-observer.ts
60072
- var import_node_fs39 = __toESM(require("fs"), 1);
60377
+ var import_node_fs40 = __toESM(require("fs"), 1);
60073
60378
  var import_node_os13 = __toESM(require("os"), 1);
60074
- var import_node_path44 = __toESM(require("path"), 1);
60379
+ var import_node_path45 = __toESM(require("path"), 1);
60075
60380
  init_claude_history();
60076
60381
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
60077
60382
  var SubagentMetaObserver = class {
@@ -60084,7 +60389,7 @@ var SubagentMetaObserver = class {
60084
60389
  watches = /* @__PURE__ */ new Map();
60085
60390
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
60086
60391
  resolveSubagentDir(cwd, toolSessionId) {
60087
- return import_node_path44.default.join(
60392
+ return import_node_path45.default.join(
60088
60393
  this.home,
60089
60394
  ".claude",
60090
60395
  "projects",
@@ -60114,7 +60419,7 @@ var SubagentMetaObserver = class {
60114
60419
  attachWatcher(w2) {
60115
60420
  if (w2.watcher) return;
60116
60421
  try {
60117
- w2.watcher = import_node_fs39.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
60422
+ w2.watcher = import_node_fs40.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
60118
60423
  if (!name) return;
60119
60424
  const m2 = META_RE.exec(String(name));
60120
60425
  if (!m2) return;
@@ -60126,7 +60431,7 @@ var SubagentMetaObserver = class {
60126
60431
  scan(w2) {
60127
60432
  let entries;
60128
60433
  try {
60129
- entries = import_node_fs39.default.readdirSync(w2.dirPath);
60434
+ entries = import_node_fs40.default.readdirSync(w2.dirPath);
60130
60435
  } catch {
60131
60436
  return;
60132
60437
  }
@@ -60140,10 +60445,10 @@ var SubagentMetaObserver = class {
60140
60445
  if (!m2) return;
60141
60446
  const agentId = m2[1];
60142
60447
  if (w2.emitted.has(agentId)) return;
60143
- const file = import_node_path44.default.join(w2.dirPath, name);
60448
+ const file = import_node_path45.default.join(w2.dirPath, name);
60144
60449
  let raw;
60145
60450
  try {
60146
- raw = import_node_fs39.default.readFileSync(file, "utf8");
60451
+ raw = import_node_fs40.default.readFileSync(file, "utf8");
60147
60452
  } catch {
60148
60453
  return;
60149
60454
  }
@@ -60200,14 +60505,14 @@ var SessionObserver = class {
60200
60505
  metaObserver;
60201
60506
  resolveJsonlPath(cwd, toolSessionId, override) {
60202
60507
  if (override) return override;
60203
- return import_node_path45.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
60508
+ return import_node_path46.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
60204
60509
  }
60205
60510
  start(args) {
60206
60511
  this.stop(args.sessionId);
60207
60512
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
60208
60513
  let size = 0;
60209
60514
  try {
60210
- size = import_node_fs40.default.statSync(filePath).size;
60515
+ size = import_node_fs41.default.statSync(filePath).size;
60211
60516
  } catch {
60212
60517
  }
60213
60518
  const w2 = {
@@ -60220,16 +60525,16 @@ var SessionObserver = class {
60220
60525
  adapter: args.adapter,
60221
60526
  prevIsRejectSentinel: false,
60222
60527
  toolSessionId: args.toolSessionId,
60223
- sawFile: import_node_fs40.default.existsSync(filePath),
60528
+ sawFile: import_node_fs41.default.existsSync(filePath),
60224
60529
  lastRelocateScanMs: 0,
60225
60530
  pendingCwdDerive: false,
60226
60531
  lastDeriveMs: 0
60227
60532
  };
60228
60533
  try {
60229
- import_node_fs40.default.mkdirSync(import_node_path45.default.dirname(filePath), { recursive: true });
60534
+ import_node_fs41.default.mkdirSync(import_node_path46.default.dirname(filePath), { recursive: true });
60230
60535
  } catch {
60231
60536
  }
60232
- w2.watcher = import_node_fs40.default.watch(import_node_path45.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
60537
+ w2.watcher = import_node_fs41.default.watch(import_node_path46.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
60233
60538
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
60234
60539
  this.poll(w2);
60235
60540
  });
@@ -60252,7 +60557,7 @@ var SessionObserver = class {
60252
60557
  // 异常静默吞,不阻塞 watcher 启动
60253
60558
  hydrateMetaTail(w2, maxLines = 200) {
60254
60559
  try {
60255
- const raw = import_node_fs40.default.readFileSync(w2.filePath, "utf8");
60560
+ const raw = import_node_fs41.default.readFileSync(w2.filePath, "utf8");
60256
60561
  if (!raw) return;
60257
60562
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
60258
60563
  if (allLines.length === 0) return;
@@ -60276,7 +60581,7 @@ var SessionObserver = class {
60276
60581
  poll(w2) {
60277
60582
  let size = 0;
60278
60583
  try {
60279
- size = import_node_fs40.default.statSync(w2.filePath).size;
60584
+ size = import_node_fs41.default.statSync(w2.filePath).size;
60280
60585
  } catch {
60281
60586
  if (w2.sawFile) this.maybeRelocate(w2);
60282
60587
  return;
@@ -60287,11 +60592,11 @@ var SessionObserver = class {
60287
60592
  w2.buf = "";
60288
60593
  }
60289
60594
  if (size === w2.lastSize) return;
60290
- const fd = import_node_fs40.default.openSync(w2.filePath, "r");
60595
+ const fd = import_node_fs41.default.openSync(w2.filePath, "r");
60291
60596
  try {
60292
60597
  const len = size - w2.lastSize;
60293
60598
  const buf = Buffer.alloc(len);
60294
- import_node_fs40.default.readSync(fd, buf, 0, len, w2.lastSize);
60599
+ import_node_fs41.default.readSync(fd, buf, 0, len, w2.lastSize);
60295
60600
  w2.lastSize = size;
60296
60601
  w2.buf += buf.toString("utf8");
60297
60602
  let newlineIndex;
@@ -60314,7 +60619,7 @@ var SessionObserver = class {
60314
60619
  }
60315
60620
  }
60316
60621
  } finally {
60317
- import_node_fs40.default.closeSync(fd);
60622
+ import_node_fs41.default.closeSync(fd);
60318
60623
  }
60319
60624
  if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
60320
60625
  }
@@ -60326,7 +60631,7 @@ var SessionObserver = class {
60326
60631
  const now = Date.now();
60327
60632
  if (now - w2.lastRelocateScanMs < 1e3) return;
60328
60633
  w2.lastRelocateScanMs = now;
60329
- const projectsRoot = import_node_path45.default.join(this.home, ".claude", "projects");
60634
+ const projectsRoot = import_node_path46.default.join(this.home, ".claude", "projects");
60330
60635
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
60331
60636
  if (!found || found === w2.filePath) return;
60332
60637
  try {
@@ -60335,7 +60640,7 @@ var SessionObserver = class {
60335
60640
  }
60336
60641
  w2.filePath = found;
60337
60642
  try {
60338
- w2.watcher = import_node_fs40.default.watch(import_node_path45.default.dirname(found), { persistent: false }, (_event, changedName) => {
60643
+ w2.watcher = import_node_fs41.default.watch(import_node_path46.default.dirname(found), { persistent: false }, (_event, changedName) => {
60339
60644
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
60340
60645
  this.poll(w2);
60341
60646
  });
@@ -60457,9 +60762,9 @@ function listRegistered() {
60457
60762
  // src/tools/title-generator.ts
60458
60763
  var import_node_child_process11 = require("child_process");
60459
60764
  init_protocol();
60460
- var import_node_fs41 = __toESM(require("fs"), 1);
60765
+ var import_node_fs42 = __toESM(require("fs"), 1);
60461
60766
  var import_node_os15 = __toESM(require("os"), 1);
60462
- var import_node_path46 = __toESM(require("path"), 1);
60767
+ var import_node_path47 = __toESM(require("path"), 1);
60463
60768
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
60464
60769
  var TITLE_MODEL_BY_TOOL = {
60465
60770
  claude: "haiku",
@@ -60530,21 +60835,21 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
60530
60835
  if (!text) return null;
60531
60836
  let workDir;
60532
60837
  try {
60533
- workDir = import_node_fs41.default.mkdtempSync(import_node_path46.default.join(import_node_os15.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
60838
+ workDir = import_node_fs42.default.mkdtempSync(import_node_path47.default.join(import_node_os15.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
60534
60839
  } catch {
60535
60840
  return null;
60536
60841
  }
60537
60842
  const cleanupWorkDir = () => {
60538
60843
  try {
60539
- import_node_fs41.default.rmSync(workDir, { recursive: true, force: true });
60844
+ import_node_fs42.default.rmSync(workDir, { recursive: true, force: true });
60540
60845
  } catch {
60541
60846
  }
60542
60847
  };
60543
- const outFile = import_node_path46.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
60544
- const schemaFile = import_node_path46.default.join(workDir, "title-schema.json");
60848
+ const outFile = import_node_path47.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
60849
+ const schemaFile = import_node_path47.default.join(workDir, "title-schema.json");
60545
60850
  if (isCodexFamily(tool)) {
60546
60851
  try {
60547
- import_node_fs41.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
60852
+ import_node_fs42.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
60548
60853
  } catch {
60549
60854
  cleanupWorkDir();
60550
60855
  return null;
@@ -60594,7 +60899,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
60594
60899
  if (tool === "claude") return finish(parseTitleJson(stdout));
60595
60900
  let fileText = "";
60596
60901
  try {
60597
- fileText = import_node_fs41.default.readFileSync(outFile, "utf8");
60902
+ fileText = import_node_fs42.default.readFileSync(outFile, "utf8");
60598
60903
  } catch {
60599
60904
  return finish(null);
60600
60905
  }
@@ -61306,8 +61611,8 @@ async function authenticate(token, deps) {
61306
61611
  }
61307
61612
 
61308
61613
  // src/legacy-cleanup.ts
61309
- var fs52 = __toESM(require("fs/promises"), 1);
61310
- var path54 = __toESM(require("path"), 1);
61614
+ var fs53 = __toESM(require("fs/promises"), 1);
61615
+ var path55 = __toESM(require("path"), 1);
61311
61616
  var LEGACY_FILES = [
61312
61617
  "personal-capability.json",
61313
61618
  "received-capabilities.json",
@@ -61316,9 +61621,9 @@ var LEGACY_FILES = [
61316
61621
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
61317
61622
  const removed = [];
61318
61623
  for (const name of LEGACY_FILES) {
61319
- const p2 = path54.join(dataDir, name);
61624
+ const p2 = path55.join(dataDir, name);
61320
61625
  try {
61321
- await fs52.unlink(p2);
61626
+ await fs53.unlink(p2);
61322
61627
  removed.push(name);
61323
61628
  logger.debug("legacy capability file removed", { file: name });
61324
61629
  } catch (err) {
@@ -61330,13 +61635,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
61330
61635
  }
61331
61636
 
61332
61637
  // src/inbox/inbox-store.ts
61333
- var fs53 = __toESM(require("fs"), 1);
61334
- var path55 = __toESM(require("path"), 1);
61638
+ var fs54 = __toESM(require("fs"), 1);
61639
+ var path56 = __toESM(require("path"), 1);
61335
61640
  var INBOX_SUBDIR = "inbox";
61336
61641
  var InboxStore = class {
61337
61642
  constructor(dataDir) {
61338
61643
  this.dataDir = dataDir;
61339
- fs53.mkdirSync(this.dirPath(), { recursive: true });
61644
+ fs54.mkdirSync(this.dirPath(), { recursive: true });
61340
61645
  }
61341
61646
  dataDir;
61342
61647
  /**
@@ -61348,7 +61653,7 @@ var InboxStore = class {
61348
61653
  const file = this.filePath(peerDeviceId);
61349
61654
  let raw;
61350
61655
  try {
61351
- raw = fs53.readFileSync(file, "utf8");
61656
+ raw = fs54.readFileSync(file, "utf8");
61352
61657
  } catch (err) {
61353
61658
  if (err?.code === "ENOENT") return [];
61354
61659
  return [];
@@ -61364,7 +61669,7 @@ var InboxStore = class {
61364
61669
  const dir = this.dirPath();
61365
61670
  let entries;
61366
61671
  try {
61367
- entries = fs53.readdirSync(dir);
61672
+ entries = fs54.readdirSync(dir);
61368
61673
  } catch (err) {
61369
61674
  if (err?.code === "ENOENT") return [];
61370
61675
  return [];
@@ -61380,9 +61685,9 @@ var InboxStore = class {
61380
61685
  if (existing.some((m2) => m2.id === message.id)) return;
61381
61686
  const file = this.filePath(message.peerDeviceId);
61382
61687
  const line = JSON.stringify(message) + "\n";
61383
- fs53.appendFileSync(file, line, { mode: 384 });
61688
+ fs54.appendFileSync(file, line, { mode: 384 });
61384
61689
  try {
61385
- fs53.chmodSync(file, 384);
61690
+ fs54.chmodSync(file, 384);
61386
61691
  } catch {
61387
61692
  }
61388
61693
  }
@@ -61412,7 +61717,7 @@ var InboxStore = class {
61412
61717
  removeByPeerDeviceId(peerDeviceId) {
61413
61718
  const file = this.filePath(peerDeviceId);
61414
61719
  try {
61415
- fs53.unlinkSync(file);
61720
+ fs54.unlinkSync(file);
61416
61721
  } catch (err) {
61417
61722
  if (err?.code === "ENOENT") return;
61418
61723
  }
@@ -61421,18 +61726,18 @@ var InboxStore = class {
61421
61726
  const file = this.filePath(peerDeviceId);
61422
61727
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
61423
61728
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
61424
- fs53.writeFileSync(tmp, content, { mode: 384 });
61425
- fs53.renameSync(tmp, file);
61729
+ fs54.writeFileSync(tmp, content, { mode: 384 });
61730
+ fs54.renameSync(tmp, file);
61426
61731
  try {
61427
- fs53.chmodSync(file, 384);
61732
+ fs54.chmodSync(file, 384);
61428
61733
  } catch {
61429
61734
  }
61430
61735
  }
61431
61736
  dirPath() {
61432
- return path55.join(this.dataDir, INBOX_SUBDIR);
61737
+ return path56.join(this.dataDir, INBOX_SUBDIR);
61433
61738
  }
61434
61739
  filePath(peerDeviceId) {
61435
- return path55.join(this.dirPath(), `${peerDeviceId}.jsonl`);
61740
+ return path56.join(this.dirPath(), `${peerDeviceId}.jsonl`);
61436
61741
  }
61437
61742
  };
61438
61743
  function parseAllLines(raw) {
@@ -61520,8 +61825,8 @@ var InboxManager = class {
61520
61825
  };
61521
61826
 
61522
61827
  // src/state/contact-store.ts
61523
- var fs54 = __toESM(require("fs"), 1);
61524
- var path56 = __toESM(require("path"), 1);
61828
+ var fs55 = __toESM(require("fs"), 1);
61829
+ var path57 = __toESM(require("path"), 1);
61525
61830
  var FILE_NAME = "contacts.json";
61526
61831
  var ContactStore = class {
61527
61832
  constructor(dataDir) {
@@ -61531,10 +61836,10 @@ var ContactStore = class {
61531
61836
  contacts = /* @__PURE__ */ new Map();
61532
61837
  load() {
61533
61838
  this.contacts.clear();
61534
- const file = path56.join(this.dataDir, FILE_NAME);
61839
+ const file = path57.join(this.dataDir, FILE_NAME);
61535
61840
  let raw;
61536
61841
  try {
61537
- raw = fs54.readFileSync(file, "utf8");
61842
+ raw = fs55.readFileSync(file, "utf8");
61538
61843
  } catch (err) {
61539
61844
  if (err?.code !== "ENOENT") this.renameBak(file);
61540
61845
  return;
@@ -61615,20 +61920,20 @@ var ContactStore = class {
61615
61920
  return true;
61616
61921
  }
61617
61922
  flush() {
61618
- const file = path56.join(this.dataDir, FILE_NAME);
61923
+ const file = path57.join(this.dataDir, FILE_NAME);
61619
61924
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
61620
61925
  const content = JSON.stringify(
61621
61926
  { contacts: Array.from(this.contacts.values()) },
61622
61927
  null,
61623
61928
  2
61624
61929
  );
61625
- fs54.mkdirSync(this.dataDir, { recursive: true });
61626
- fs54.writeFileSync(tmp, content, { mode: 384 });
61627
- fs54.renameSync(tmp, file);
61930
+ fs55.mkdirSync(this.dataDir, { recursive: true });
61931
+ fs55.writeFileSync(tmp, content, { mode: 384 });
61932
+ fs55.renameSync(tmp, file);
61628
61933
  }
61629
61934
  renameBak(file) {
61630
61935
  try {
61631
- fs54.renameSync(file, `${file}.bak`);
61936
+ fs55.renameSync(file, `${file}.bak`);
61632
61937
  } catch {
61633
61938
  }
61634
61939
  }
@@ -61736,61 +62041,61 @@ async function connectRemote(args) {
61736
62041
  }
61737
62042
 
61738
62043
  // src/migrations/2026-05-20-flatten-sessions.ts
61739
- var fs55 = __toESM(require("fs"), 1);
61740
- var path57 = __toESM(require("path"), 1);
62044
+ var fs56 = __toESM(require("fs"), 1);
62045
+ var path58 = __toESM(require("path"), 1);
61741
62046
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
61742
62047
  function migrateFlattenSessions(opts) {
61743
62048
  const dataDir = opts.dataDir;
61744
62049
  const now = opts.now ?? Date.now;
61745
- const sessionsDir = path57.join(dataDir, "sessions");
61746
- const flagPath = path57.join(sessionsDir, MIGRATION_FLAG_NAME);
62050
+ const sessionsDir = path58.join(dataDir, "sessions");
62051
+ const flagPath = path58.join(sessionsDir, MIGRATION_FLAG_NAME);
61747
62052
  if (existsSync3(flagPath)) {
61748
62053
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
61749
62054
  }
61750
62055
  let movedBare = 0;
61751
62056
  let movedVmOwner = 0;
61752
62057
  let archivedListener = 0;
61753
- const defaultDir = path57.join(sessionsDir, "default");
62058
+ const defaultDir = path58.join(sessionsDir, "default");
61754
62059
  if (existsSync3(defaultDir)) {
61755
62060
  for (const entry of readdirSafe(defaultDir)) {
61756
62061
  if (!entry.endsWith(".json")) continue;
61757
- const src = path57.join(defaultDir, entry);
61758
- const dst = path57.join(sessionsDir, entry);
61759
- fs55.renameSync(src, dst);
62062
+ const src = path58.join(defaultDir, entry);
62063
+ const dst = path58.join(sessionsDir, entry);
62064
+ fs56.renameSync(src, dst);
61760
62065
  movedBare += 1;
61761
62066
  }
61762
62067
  rmdirIfEmpty(defaultDir);
61763
62068
  }
61764
62069
  for (const pid of readdirSafe(sessionsDir)) {
61765
- const personaDir = path57.join(sessionsDir, pid);
62070
+ const personaDir = path58.join(sessionsDir, pid);
61766
62071
  if (!isDir(personaDir)) continue;
61767
62072
  if (pid === "default") continue;
61768
- const ownerSrc = path57.join(personaDir, "owner");
62073
+ const ownerSrc = path58.join(personaDir, "owner");
61769
62074
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
61770
- const ownerDst = path57.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
61771
- fs55.mkdirSync(ownerDst, { recursive: true });
62075
+ const ownerDst = path58.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
62076
+ fs56.mkdirSync(ownerDst, { recursive: true });
61772
62077
  for (const file of readdirSafe(ownerSrc)) {
61773
62078
  if (!file.endsWith(".json")) continue;
61774
- fs55.renameSync(path57.join(ownerSrc, file), path57.join(ownerDst, file));
62079
+ fs56.renameSync(path58.join(ownerSrc, file), path58.join(ownerDst, file));
61775
62080
  movedVmOwner += 1;
61776
62081
  }
61777
62082
  rmdirIfEmpty(ownerSrc);
61778
62083
  }
61779
- const listenerSrc = path57.join(personaDir, "listener");
62084
+ const listenerSrc = path58.join(personaDir, "listener");
61780
62085
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
61781
- const archiveDst = path57.join(dataDir, ".legacy", `listener-${pid}`);
61782
- fs55.mkdirSync(archiveDst, { recursive: true });
62086
+ const archiveDst = path58.join(dataDir, ".legacy", `listener-${pid}`);
62087
+ fs56.mkdirSync(archiveDst, { recursive: true });
61783
62088
  for (const file of readdirSafe(listenerSrc)) {
61784
62089
  if (!file.endsWith(".json")) continue;
61785
- fs55.renameSync(path57.join(listenerSrc, file), path57.join(archiveDst, file));
62090
+ fs56.renameSync(path58.join(listenerSrc, file), path58.join(archiveDst, file));
61786
62091
  archivedListener += 1;
61787
62092
  }
61788
62093
  rmdirIfEmpty(listenerSrc);
61789
62094
  }
61790
62095
  rmdirIfEmpty(personaDir);
61791
62096
  }
61792
- fs55.mkdirSync(sessionsDir, { recursive: true });
61793
- fs55.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
62097
+ fs56.mkdirSync(sessionsDir, { recursive: true });
62098
+ fs56.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
61794
62099
  return {
61795
62100
  skipped: false,
61796
62101
  flagWritten: true,
@@ -61801,7 +62106,7 @@ function migrateFlattenSessions(opts) {
61801
62106
  }
61802
62107
  function existsSync3(p2) {
61803
62108
  try {
61804
- fs55.statSync(p2);
62109
+ fs56.statSync(p2);
61805
62110
  return true;
61806
62111
  } catch {
61807
62112
  return false;
@@ -61809,62 +62114,62 @@ function existsSync3(p2) {
61809
62114
  }
61810
62115
  function isDir(p2) {
61811
62116
  try {
61812
- return fs55.statSync(p2).isDirectory();
62117
+ return fs56.statSync(p2).isDirectory();
61813
62118
  } catch {
61814
62119
  return false;
61815
62120
  }
61816
62121
  }
61817
62122
  function readdirSafe(p2) {
61818
62123
  try {
61819
- return fs55.readdirSync(p2);
62124
+ return fs56.readdirSync(p2);
61820
62125
  } catch {
61821
62126
  return [];
61822
62127
  }
61823
62128
  }
61824
62129
  function rmdirIfEmpty(p2) {
61825
62130
  try {
61826
- fs55.rmdirSync(p2);
62131
+ fs56.rmdirSync(p2);
61827
62132
  } catch {
61828
62133
  }
61829
62134
  }
61830
62135
 
61831
62136
  // src/migrations/2026-08-18-drop-seeded-projects.ts
61832
- var fs56 = __toESM(require("fs"), 1);
61833
- var path58 = __toESM(require("path"), 1);
62137
+ var fs57 = __toESM(require("fs"), 1);
62138
+ var path59 = __toESM(require("path"), 1);
61834
62139
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
61835
62140
  function dropSeededProjects(opts) {
61836
- fs56.mkdirSync(opts.dataDir, { recursive: true });
61837
- const flag = path58.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
61838
- if (fs56.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
61839
- const file = path58.join(opts.dataDir, "projects.json");
62141
+ fs57.mkdirSync(opts.dataDir, { recursive: true });
62142
+ const flag = path59.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
62143
+ if (fs57.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
62144
+ const file = path59.join(opts.dataDir, "projects.json");
61840
62145
  let raw = null;
61841
62146
  let dropped = 0;
61842
62147
  try {
61843
- raw = fs56.readFileSync(file, "utf8");
62148
+ raw = fs57.readFileSync(file, "utf8");
61844
62149
  dropped = JSON.parse(raw).projects?.length ?? 0;
61845
62150
  } catch {
61846
62151
  }
61847
62152
  let backup = null;
61848
62153
  if (raw != null && dropped > 0) {
61849
- const dir = path58.join(opts.dataDir, "backups");
61850
- fs56.mkdirSync(dir, { recursive: true });
61851
- backup = path58.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
61852
- fs56.writeFileSync(backup, raw);
62154
+ const dir = path59.join(opts.dataDir, "backups");
62155
+ fs57.mkdirSync(dir, { recursive: true });
62156
+ backup = path59.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
62157
+ fs57.writeFileSync(backup, raw);
61853
62158
  }
61854
62159
  if (raw != null || dropped > 0) {
61855
- fs56.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
62160
+ fs57.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
61856
62161
  }
61857
- fs56.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
62162
+ fs57.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
61858
62163
  return { skipped: false, dropped, backup };
61859
62164
  }
61860
62165
 
61861
62166
  // src/transport/http-router.ts
61862
- var import_node_fs43 = __toESM(require("fs"), 1);
61863
- var import_node_path49 = __toESM(require("path"), 1);
62167
+ var import_node_fs44 = __toESM(require("fs"), 1);
62168
+ var import_node_path50 = __toESM(require("path"), 1);
61864
62169
 
61865
62170
  // src/attachment/upload.ts
61866
- var import_node_fs42 = __toESM(require("fs"), 1);
61867
- var import_node_path47 = __toESM(require("path"), 1);
62171
+ var import_node_fs43 = __toESM(require("fs"), 1);
62172
+ var import_node_path48 = __toESM(require("path"), 1);
61868
62173
  var import_node_crypto11 = __toESM(require("crypto"), 1);
61869
62174
  var import_promises7 = require("stream/promises");
61870
62175
  var UploadError = class extends Error {
@@ -61876,22 +62181,22 @@ var UploadError = class extends Error {
61876
62181
  code;
61877
62182
  };
61878
62183
  function assertValidFileName(fileName) {
61879
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path47.default.basename(fileName)) {
62184
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path48.default.basename(fileName)) {
61880
62185
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
61881
62186
  }
61882
62187
  }
61883
62188
  var HASH_PREFIX_LEN = 16;
61884
62189
  async function writeUploadedAttachment(args) {
61885
62190
  assertValidFileName(args.fileName);
61886
- const attachmentsRoot = import_node_path47.default.join(args.baseDir, ".attachments");
62191
+ const attachmentsRoot = import_node_path48.default.join(args.baseDir, ".attachments");
61887
62192
  try {
61888
- import_node_fs42.default.mkdirSync(attachmentsRoot, { recursive: true });
62193
+ import_node_fs43.default.mkdirSync(attachmentsRoot, { recursive: true });
61889
62194
  } catch (err) {
61890
62195
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
61891
62196
  }
61892
62197
  const hasher = import_node_crypto11.default.createHash("sha256");
61893
62198
  let actualSize = 0;
61894
- const tmpPath = import_node_path47.default.join(
62199
+ const tmpPath = import_node_path48.default.join(
61895
62200
  attachmentsRoot,
61896
62201
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto11.default.randomBytes(4).toString("hex")}`
61897
62202
  );
@@ -61906,18 +62211,18 @@ async function writeUploadedAttachment(args) {
61906
62211
  yield buf;
61907
62212
  }
61908
62213
  },
61909
- import_node_fs42.default.createWriteStream(tmpPath, { mode: 384 })
62214
+ import_node_fs43.default.createWriteStream(tmpPath, { mode: 384 })
61910
62215
  );
61911
62216
  } catch (err) {
61912
62217
  try {
61913
- import_node_fs42.default.unlinkSync(tmpPath);
62218
+ import_node_fs43.default.unlinkSync(tmpPath);
61914
62219
  } catch {
61915
62220
  }
61916
62221
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
61917
62222
  }
61918
62223
  if (actualSize !== args.contentLength) {
61919
62224
  try {
61920
- import_node_fs42.default.unlinkSync(tmpPath);
62225
+ import_node_fs43.default.unlinkSync(tmpPath);
61921
62226
  } catch {
61922
62227
  }
61923
62228
  throw new UploadError(
@@ -61926,34 +62231,34 @@ async function writeUploadedAttachment(args) {
61926
62231
  );
61927
62232
  }
61928
62233
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
61929
- const hashDir = import_node_path47.default.join(attachmentsRoot, attachmentId);
62234
+ const hashDir = import_node_path48.default.join(attachmentsRoot, attachmentId);
61930
62235
  let finalFileName;
61931
62236
  let hashDirExists = false;
61932
62237
  try {
61933
- hashDirExists = import_node_fs42.default.statSync(hashDir).isDirectory();
62238
+ hashDirExists = import_node_fs43.default.statSync(hashDir).isDirectory();
61934
62239
  } catch {
61935
62240
  }
61936
62241
  if (hashDirExists) {
61937
- const existing = import_node_fs42.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
62242
+ const existing = import_node_fs43.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
61938
62243
  finalFileName = existing[0] ?? args.fileName;
61939
62244
  try {
61940
- import_node_fs42.default.unlinkSync(tmpPath);
62245
+ import_node_fs43.default.unlinkSync(tmpPath);
61941
62246
  } catch {
61942
62247
  }
61943
62248
  } else {
61944
62249
  try {
61945
- import_node_fs42.default.mkdirSync(hashDir, { recursive: true });
62250
+ import_node_fs43.default.mkdirSync(hashDir, { recursive: true });
61946
62251
  finalFileName = args.fileName;
61947
- import_node_fs42.default.renameSync(tmpPath, import_node_path47.default.join(hashDir, finalFileName));
62252
+ import_node_fs43.default.renameSync(tmpPath, import_node_path48.default.join(hashDir, finalFileName));
61948
62253
  } catch (err) {
61949
62254
  try {
61950
- import_node_fs42.default.unlinkSync(tmpPath);
62255
+ import_node_fs43.default.unlinkSync(tmpPath);
61951
62256
  } catch {
61952
62257
  }
61953
62258
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
61954
62259
  }
61955
62260
  }
61956
- const absPath = import_node_path47.default.join(hashDir, finalFileName);
62261
+ const absPath = import_node_path48.default.join(hashDir, finalFileName);
61957
62262
  const relPath = absPath;
61958
62263
  args.groupFileStore.upsert(args.scope, args.sessionId, {
61959
62264
  relPath: absPath,
@@ -61968,7 +62273,7 @@ async function writeUploadedAttachment(args) {
61968
62273
 
61969
62274
  // src/extension/import.ts
61970
62275
  var import_promises8 = __toESM(require("fs/promises"), 1);
61971
- var import_node_path48 = __toESM(require("path"), 1);
62276
+ var import_node_path49 = __toESM(require("path"), 1);
61972
62277
  var import_node_os16 = __toESM(require("os"), 1);
61973
62278
  var import_jszip = __toESM(require_lib3(), 1);
61974
62279
  var ImportError = class extends Error {
@@ -61986,7 +62291,7 @@ async function importZip(buf, root) {
61986
62291
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
61987
62292
  }
61988
62293
  for (const name of Object.keys(zip.files)) {
61989
- if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
62294
+ if (name.includes("..") || name.startsWith("/") || import_node_path49.default.isAbsolute(name)) {
61990
62295
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
61991
62296
  }
61992
62297
  }
@@ -62019,7 +62324,7 @@ async function importZip(buf, root) {
62019
62324
  );
62020
62325
  }
62021
62326
  }
62022
- const destDir = import_node_path48.default.join(root, manifest.id);
62327
+ const destDir = import_node_path49.default.join(root, manifest.id);
62023
62328
  let destExists = false;
62024
62329
  try {
62025
62330
  await import_promises8.default.access(destDir);
@@ -62029,15 +62334,15 @@ async function importZip(buf, root) {
62029
62334
  if (destExists) {
62030
62335
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
62031
62336
  }
62032
- const stage = await import_promises8.default.mkdtemp(import_node_path48.default.join(import_node_os16.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
62337
+ const stage = await import_promises8.default.mkdtemp(import_node_path49.default.join(import_node_os16.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
62033
62338
  try {
62034
62339
  for (const [name, entry] of Object.entries(zip.files)) {
62035
- const dest = import_node_path48.default.join(stage, name);
62340
+ const dest = import_node_path49.default.join(stage, name);
62036
62341
  if (entry.dir) {
62037
62342
  await import_promises8.default.mkdir(dest, { recursive: true });
62038
62343
  continue;
62039
62344
  }
62040
- await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
62345
+ await import_promises8.default.mkdir(import_node_path49.default.dirname(dest), { recursive: true });
62041
62346
  const content = await entry.async("nodebuffer");
62042
62347
  await import_promises8.default.writeFile(dest, content);
62043
62348
  }
@@ -62067,7 +62372,7 @@ var SHARE_UI_ASSET_MIME = {
62067
62372
  ".wasm": "application/wasm"
62068
62373
  };
62069
62374
  function shareUiAssetMime(filePath) {
62070
- const ext = import_node_path49.default.extname(filePath).toLowerCase();
62375
+ const ext = import_node_path50.default.extname(filePath).toLowerCase();
62071
62376
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
62072
62377
  }
62073
62378
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -62166,7 +62471,7 @@ function isValidUploadFileName(fileName) {
62166
62471
  if (fileName === "." || fileName === "..") return false;
62167
62472
  if (fileName.startsWith(".")) return false;
62168
62473
  if (fileName.includes("/") || fileName.includes("\\")) return false;
62169
- return fileName === import_node_path49.default.basename(fileName);
62474
+ return fileName === import_node_path50.default.basename(fileName);
62170
62475
  }
62171
62476
  function createHttpRouter(deps) {
62172
62477
  return async (req, res) => {
@@ -62254,7 +62559,7 @@ function createHttpRouter(deps) {
62254
62559
  }
62255
62560
  let buf;
62256
62561
  try {
62257
- buf = await import_node_fs43.default.promises.readFile(abs);
62562
+ buf = await import_node_fs44.default.promises.readFile(abs);
62258
62563
  } catch {
62259
62564
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
62260
62565
  return true;
@@ -62402,7 +62707,7 @@ function createHttpRouter(deps) {
62402
62707
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
62403
62708
  return true;
62404
62709
  }
62405
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path49.default.basename(r.absPath)));
62710
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path50.default.basename(r.absPath)));
62406
62711
  return true;
62407
62712
  }
62408
62713
  const ctx = deps.authResolver.resolveFromHeader(
@@ -62523,7 +62828,7 @@ function createHttpRouter(deps) {
62523
62828
  return true;
62524
62829
  }
62525
62830
  let absPath;
62526
- if (import_node_path49.default.isAbsolute(pathParam)) {
62831
+ if (import_node_path50.default.isAbsolute(pathParam)) {
62527
62832
  absPath = pathParam;
62528
62833
  } else if (deps.sessionStore) {
62529
62834
  const file = deps.sessionStore.read(sid);
@@ -62531,7 +62836,7 @@ function createHttpRouter(deps) {
62531
62836
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
62532
62837
  return true;
62533
62838
  }
62534
- absPath = import_node_path49.default.join(file.cwd, pathParam);
62839
+ absPath = import_node_path50.default.join(file.cwd, pathParam);
62535
62840
  } else {
62536
62841
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
62537
62842
  return true;
@@ -62618,7 +62923,7 @@ function withCtx(ctx, body) {
62618
62923
  function streamFile(res, absPath, logger) {
62619
62924
  let stat;
62620
62925
  try {
62621
- stat = import_node_fs43.default.statSync(absPath);
62926
+ stat = import_node_fs44.default.statSync(absPath);
62622
62927
  } catch (err) {
62623
62928
  const code = err?.code;
62624
62929
  if (code === "ENOENT") {
@@ -62633,7 +62938,7 @@ function streamFile(res, absPath, logger) {
62633
62938
  return;
62634
62939
  }
62635
62940
  const mime = lookupMime(absPath);
62636
- const basename2 = import_node_path49.default.basename(absPath);
62941
+ const basename2 = import_node_path50.default.basename(absPath);
62637
62942
  res.writeHead(200, {
62638
62943
  "Content-Type": mime,
62639
62944
  "Content-Length": String(stat.size),
@@ -62641,7 +62946,7 @@ function streamFile(res, absPath, logger) {
62641
62946
  // 防止浏览器把任意 mime 当 html 渲染
62642
62947
  "X-Content-Type-Options": "nosniff"
62643
62948
  });
62644
- const stream = import_node_fs43.default.createReadStream(absPath);
62949
+ const stream = import_node_fs44.default.createReadStream(absPath);
62645
62950
  stream.on("error", (err) => {
62646
62951
  logger?.warn("streamFile read error", { absPath, err: err.message });
62647
62952
  res.destroy();
@@ -62650,8 +62955,8 @@ function streamFile(res, absPath, logger) {
62650
62955
  }
62651
62956
 
62652
62957
  // src/attachment/gc.ts
62653
- var import_node_fs44 = __toESM(require("fs"), 1);
62654
- var import_node_path50 = __toESM(require("path"), 1);
62958
+ var import_node_fs45 = __toESM(require("fs"), 1);
62959
+ var import_node_path51 = __toESM(require("path"), 1);
62655
62960
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
62656
62961
  function runAttachmentGc(args) {
62657
62962
  const now = (args.now ?? Date.now)();
@@ -62660,12 +62965,12 @@ function runAttachmentGc(args) {
62660
62965
  for (const { scope, sessionId } of args.sessionScopes) {
62661
62966
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
62662
62967
  if (entry.stale) continue;
62663
- if (import_node_path50.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
62968
+ if (import_node_path51.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
62664
62969
  }
62665
62970
  }
62666
62971
  const visited = /* @__PURE__ */ new Set();
62667
62972
  for (const { scope, sessionId } of args.sessionScopes) {
62668
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path50.default.join(
62973
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path51.default.join(
62669
62974
  args.dataDir,
62670
62975
  "sessions",
62671
62976
  ...scopeSubPath(scope).map(safeFileName),
@@ -62678,28 +62983,28 @@ function runAttachmentGc(args) {
62678
62983
  return true;
62679
62984
  });
62680
62985
  for (const rootDir of roots) {
62681
- const attRoot = import_node_path50.default.join(rootDir, ".attachments");
62986
+ const attRoot = import_node_path51.default.join(rootDir, ".attachments");
62682
62987
  let hashDirs;
62683
62988
  try {
62684
- hashDirs = import_node_fs44.default.readdirSync(attRoot);
62989
+ hashDirs = import_node_fs45.default.readdirSync(attRoot);
62685
62990
  } catch (err) {
62686
62991
  if (err.code === "ENOENT") continue;
62687
62992
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
62688
62993
  continue;
62689
62994
  }
62690
62995
  for (const hashDir of hashDirs) {
62691
- const hashDirAbs = import_node_path50.default.join(attRoot, hashDir);
62996
+ const hashDirAbs = import_node_path51.default.join(attRoot, hashDir);
62692
62997
  let files;
62693
62998
  try {
62694
- files = import_node_fs44.default.readdirSync(hashDirAbs);
62999
+ files = import_node_fs45.default.readdirSync(hashDirAbs);
62695
63000
  } catch {
62696
63001
  continue;
62697
63002
  }
62698
63003
  for (const name of files) {
62699
- const file = import_node_path50.default.join(hashDirAbs, name);
63004
+ const file = import_node_path51.default.join(hashDirAbs, name);
62700
63005
  let stat;
62701
63006
  try {
62702
- stat = import_node_fs44.default.statSync(file);
63007
+ stat = import_node_fs45.default.statSync(file);
62703
63008
  } catch {
62704
63009
  continue;
62705
63010
  }
@@ -62708,18 +63013,18 @@ function runAttachmentGc(args) {
62708
63013
  if (age < ttlMs) continue;
62709
63014
  if (liveAbs.has(file)) continue;
62710
63015
  try {
62711
- import_node_fs44.default.unlinkSync(file);
63016
+ import_node_fs45.default.unlinkSync(file);
62712
63017
  } catch (err) {
62713
63018
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
62714
63019
  }
62715
63020
  }
62716
63021
  try {
62717
- if (import_node_fs44.default.readdirSync(hashDirAbs).length === 0) import_node_fs44.default.rmdirSync(hashDirAbs);
63022
+ if (import_node_fs45.default.readdirSync(hashDirAbs).length === 0) import_node_fs45.default.rmdirSync(hashDirAbs);
62718
63023
  } catch {
62719
63024
  }
62720
63025
  }
62721
63026
  try {
62722
- if (import_node_fs44.default.readdirSync(attRoot).length === 0) import_node_fs44.default.rmdirSync(attRoot);
63027
+ if (import_node_fs45.default.readdirSync(attRoot).length === 0) import_node_fs45.default.rmdirSync(attRoot);
62723
63028
  } catch {
62724
63029
  }
62725
63030
  }
@@ -62727,8 +63032,8 @@ function runAttachmentGc(args) {
62727
63032
  }
62728
63033
 
62729
63034
  // src/attachment/group.ts
62730
- var import_node_fs45 = __toESM(require("fs"), 1);
62731
- var import_node_path51 = __toESM(require("path"), 1);
63035
+ var import_node_fs46 = __toESM(require("fs"), 1);
63036
+ var import_node_path52 = __toESM(require("path"), 1);
62732
63037
  var import_node_crypto12 = __toESM(require("crypto"), 1);
62733
63038
  init_protocol();
62734
63039
  var GroupFileStore = class {
@@ -62740,11 +63045,11 @@ var GroupFileStore = class {
62740
63045
  this.logger = opts.logger;
62741
63046
  }
62742
63047
  rootForScope(scope) {
62743
- return import_node_path51.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
63048
+ return import_node_path52.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
62744
63049
  }
62745
63050
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
62746
63051
  filePath(scope, sessionId) {
62747
- return import_node_path51.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
63052
+ return import_node_path52.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
62748
63053
  }
62749
63054
  cacheKey(scope, sessionId) {
62750
63055
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -62753,7 +63058,7 @@ var GroupFileStore = class {
62753
63058
  readFile(scope, sessionId) {
62754
63059
  const file = this.filePath(scope, sessionId);
62755
63060
  try {
62756
- const raw = import_node_fs45.default.readFileSync(file, "utf8");
63061
+ const raw = import_node_fs46.default.readFileSync(file, "utf8");
62757
63062
  const parsed = JSON.parse(raw);
62758
63063
  if (!Array.isArray(parsed)) {
62759
63064
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -62779,10 +63084,10 @@ var GroupFileStore = class {
62779
63084
  }
62780
63085
  writeFile(scope, sessionId, entries) {
62781
63086
  const file = this.filePath(scope, sessionId);
62782
- import_node_fs45.default.mkdirSync(import_node_path51.default.dirname(file), { recursive: true });
63087
+ import_node_fs46.default.mkdirSync(import_node_path52.default.dirname(file), { recursive: true });
62783
63088
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
62784
- import_node_fs45.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
62785
- import_node_fs45.default.renameSync(tmp, file);
63089
+ import_node_fs46.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
63090
+ import_node_fs46.default.renameSync(tmp, file);
62786
63091
  }
62787
63092
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
62788
63093
  list(scope, sessionId) {
@@ -62874,7 +63179,7 @@ var GroupFileStore = class {
62874
63179
  */
62875
63180
  deleteSession(scope, sessionId) {
62876
63181
  try {
62877
- import_node_fs45.default.unlinkSync(this.filePath(scope, sessionId));
63182
+ import_node_fs46.default.unlinkSync(this.filePath(scope, sessionId));
62878
63183
  } catch (err) {
62879
63184
  if (err?.code !== "ENOENT") throw err;
62880
63185
  }
@@ -62887,7 +63192,7 @@ var GroupFileStore = class {
62887
63192
  * 不在 persona 目录里(见文件头的路径约定)。没树的 persona 是 noop。
62888
63193
  */
62889
63194
  deletePersona(personaId2) {
62890
- import_node_fs45.default.rmSync(import_node_path51.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
63195
+ import_node_fs46.default.rmSync(import_node_path52.default.join(this.dataDir, "sessions", safeFileName(personaId2)), { recursive: true, force: true });
62891
63196
  const prefix = `persona:${personaId2}:`;
62892
63197
  for (const key of this.cache.keys()) {
62893
63198
  if (key.startsWith(prefix)) this.cache.delete(key);
@@ -62896,10 +63201,10 @@ var GroupFileStore = class {
62896
63201
  };
62897
63202
 
62898
63203
  // src/discovery/state-file.ts
62899
- var import_node_fs46 = __toESM(require("fs"), 1);
62900
- var import_node_path52 = __toESM(require("path"), 1);
63204
+ var import_node_fs47 = __toESM(require("fs"), 1);
63205
+ var import_node_path53 = __toESM(require("path"), 1);
62901
63206
  function defaultStateFilePath(dataDir) {
62902
- return import_node_path52.default.join(dataDir, "state.json");
63207
+ return import_node_path53.default.join(dataDir, "state.json");
62903
63208
  }
62904
63209
  function isPidAlive(pid) {
62905
63210
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -62921,7 +63226,7 @@ var StateFileManager = class {
62921
63226
  }
62922
63227
  read() {
62923
63228
  try {
62924
- const raw = import_node_fs46.default.readFileSync(this.file, "utf8");
63229
+ const raw = import_node_fs47.default.readFileSync(this.file, "utf8");
62925
63230
  const parsed = JSON.parse(raw);
62926
63231
  return parsed;
62927
63232
  } catch {
@@ -62935,20 +63240,20 @@ var StateFileManager = class {
62935
63240
  return { status: "stale", existing };
62936
63241
  }
62937
63242
  write(state) {
62938
- import_node_fs46.default.mkdirSync(import_node_path52.default.dirname(this.file), { recursive: true });
63243
+ import_node_fs47.default.mkdirSync(import_node_path53.default.dirname(this.file), { recursive: true });
62939
63244
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
62940
- import_node_fs46.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
62941
- import_node_fs46.default.renameSync(tmp, this.file);
63245
+ import_node_fs47.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
63246
+ import_node_fs47.default.renameSync(tmp, this.file);
62942
63247
  if (process.platform !== "win32") {
62943
63248
  try {
62944
- import_node_fs46.default.chmodSync(this.file, 384);
63249
+ import_node_fs47.default.chmodSync(this.file, 384);
62945
63250
  } catch {
62946
63251
  }
62947
63252
  }
62948
63253
  }
62949
63254
  delete() {
62950
63255
  try {
62951
- import_node_fs46.default.unlinkSync(this.file);
63256
+ import_node_fs47.default.unlinkSync(this.file);
62952
63257
  } catch {
62953
63258
  }
62954
63259
  }
@@ -62962,14 +63267,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
62962
63267
  }
62963
63268
 
62964
63269
  // src/tunnel/tunnel-manager.ts
62965
- var import_node_fs50 = __toESM(require("fs"), 1);
62966
- var import_node_path56 = __toESM(require("path"), 1);
63270
+ var import_node_fs51 = __toESM(require("fs"), 1);
63271
+ var import_node_path57 = __toESM(require("path"), 1);
62967
63272
  var import_node_crypto13 = __toESM(require("crypto"), 1);
62968
63273
  var import_node_child_process14 = require("child_process");
62969
63274
 
62970
63275
  // src/tunnel/tunnel-store.ts
62971
- var import_node_fs47 = __toESM(require("fs"), 1);
62972
- var import_node_path53 = __toESM(require("path"), 1);
63276
+ var import_node_fs48 = __toESM(require("fs"), 1);
63277
+ var import_node_path54 = __toESM(require("path"), 1);
62973
63278
  var TunnelStore = class {
62974
63279
  constructor(filePath) {
62975
63280
  this.filePath = filePath;
@@ -62977,7 +63282,7 @@ var TunnelStore = class {
62977
63282
  filePath;
62978
63283
  async get() {
62979
63284
  try {
62980
- const raw = await import_node_fs47.default.promises.readFile(this.filePath, "utf8");
63285
+ const raw = await import_node_fs48.default.promises.readFile(this.filePath, "utf8");
62981
63286
  const obj = JSON.parse(raw);
62982
63287
  if (!isPersistedTunnel(obj)) return null;
62983
63288
  return obj;
@@ -62988,22 +63293,22 @@ var TunnelStore = class {
62988
63293
  }
62989
63294
  }
62990
63295
  async set(v2) {
62991
- const dir = import_node_path53.default.dirname(this.filePath);
62992
- await import_node_fs47.default.promises.mkdir(dir, { recursive: true });
63296
+ const dir = import_node_path54.default.dirname(this.filePath);
63297
+ await import_node_fs48.default.promises.mkdir(dir, { recursive: true });
62993
63298
  const data = JSON.stringify(v2, null, 2);
62994
63299
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
62995
- await import_node_fs47.default.promises.writeFile(tmp, data, { mode: 384 });
63300
+ await import_node_fs48.default.promises.writeFile(tmp, data, { mode: 384 });
62996
63301
  if (process.platform !== "win32") {
62997
63302
  try {
62998
- await import_node_fs47.default.promises.chmod(tmp, 384);
63303
+ await import_node_fs48.default.promises.chmod(tmp, 384);
62999
63304
  } catch {
63000
63305
  }
63001
63306
  }
63002
- await import_node_fs47.default.promises.rename(tmp, this.filePath);
63307
+ await import_node_fs48.default.promises.rename(tmp, this.filePath);
63003
63308
  }
63004
63309
  async clear() {
63005
63310
  try {
63006
- await import_node_fs47.default.promises.unlink(this.filePath);
63311
+ await import_node_fs48.default.promises.unlink(this.filePath);
63007
63312
  } catch (err) {
63008
63313
  const code = err?.code;
63009
63314
  if (code !== "ENOENT") throw err;
@@ -63098,9 +63403,9 @@ function escape(v2) {
63098
63403
  }
63099
63404
 
63100
63405
  // src/tunnel/frpc-binary.ts
63101
- var import_node_fs48 = __toESM(require("fs"), 1);
63406
+ var import_node_fs49 = __toESM(require("fs"), 1);
63102
63407
  var import_node_os17 = __toESM(require("os"), 1);
63103
- var import_node_path54 = __toESM(require("path"), 1);
63408
+ var import_node_path55 = __toESM(require("path"), 1);
63104
63409
  var import_node_child_process12 = require("child_process");
63105
63410
  var import_node_stream3 = require("stream");
63106
63411
  var import_promises9 = require("stream/promises");
@@ -63132,20 +63437,20 @@ function frpcDownloadUrl(version2, p2) {
63132
63437
  }
63133
63438
  async function ensureFrpcBinary(opts) {
63134
63439
  if (opts.override) {
63135
- if (!import_node_fs48.default.existsSync(opts.override)) {
63440
+ if (!import_node_fs49.default.existsSync(opts.override)) {
63136
63441
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
63137
63442
  }
63138
63443
  return opts.override;
63139
63444
  }
63140
63445
  const version2 = opts.version ?? FRPC_VERSION;
63141
63446
  const platform = opts.platform ?? detectPlatform();
63142
- const binDir = import_node_path54.default.join(opts.dataDir, "bin");
63143
- import_node_fs48.default.mkdirSync(binDir, { recursive: true });
63447
+ const binDir = import_node_path55.default.join(opts.dataDir, "bin");
63448
+ import_node_fs49.default.mkdirSync(binDir, { recursive: true });
63144
63449
  cleanupStaleArtifacts(binDir);
63145
- const stableBin = import_node_path54.default.join(binDir, "frpc");
63146
- if (import_node_fs48.default.existsSync(stableBin)) return stableBin;
63450
+ const stableBin = import_node_path55.default.join(binDir, "frpc");
63451
+ if (import_node_fs49.default.existsSync(stableBin)) return stableBin;
63147
63452
  const partialBin = `${stableBin}.partial`;
63148
- const tarballPath = import_node_path54.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
63453
+ const tarballPath = import_node_path55.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
63149
63454
  try {
63150
63455
  const url = frpcDownloadUrl(version2, platform);
63151
63456
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -63154,8 +63459,8 @@ async function ensureFrpcBinary(opts) {
63154
63459
  } else {
63155
63460
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
63156
63461
  }
63157
- import_node_fs48.default.chmodSync(partialBin, 493);
63158
- import_node_fs48.default.renameSync(partialBin, stableBin);
63462
+ import_node_fs49.default.chmodSync(partialBin, 493);
63463
+ import_node_fs49.default.renameSync(partialBin, stableBin);
63159
63464
  } finally {
63160
63465
  safeUnlink(tarballPath);
63161
63466
  safeUnlink(partialBin);
@@ -63165,15 +63470,15 @@ async function ensureFrpcBinary(opts) {
63165
63470
  function cleanupStaleArtifacts(binDir) {
63166
63471
  let entries;
63167
63472
  try {
63168
- entries = import_node_fs48.default.readdirSync(binDir);
63473
+ entries = import_node_fs49.default.readdirSync(binDir);
63169
63474
  } catch {
63170
63475
  return;
63171
63476
  }
63172
63477
  for (const name of entries) {
63173
63478
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
63174
- const full = import_node_path54.default.join(binDir, name);
63479
+ const full = import_node_path55.default.join(binDir, name);
63175
63480
  try {
63176
- import_node_fs48.default.rmSync(full, { recursive: true, force: true });
63481
+ import_node_fs49.default.rmSync(full, { recursive: true, force: true });
63177
63482
  } catch {
63178
63483
  }
63179
63484
  }
@@ -63181,7 +63486,7 @@ function cleanupStaleArtifacts(binDir) {
63181
63486
  }
63182
63487
  function safeUnlink(p2) {
63183
63488
  try {
63184
- import_node_fs48.default.unlinkSync(p2);
63489
+ import_node_fs49.default.unlinkSync(p2);
63185
63490
  } catch {
63186
63491
  }
63187
63492
  }
@@ -63192,13 +63497,13 @@ async function downloadToFile(url, dest, fetchImpl) {
63192
63497
  if (!res.ok || !res.body) {
63193
63498
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
63194
63499
  }
63195
- const out = import_node_fs48.default.createWriteStream(dest);
63500
+ const out = import_node_fs49.default.createWriteStream(dest);
63196
63501
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
63197
63502
  await (0, import_promises9.pipeline)(nodeStream, out);
63198
63503
  }
63199
63504
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
63200
- const work = import_node_path54.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
63201
- import_node_fs48.default.mkdirSync(work, { recursive: true });
63505
+ const work = import_node_path55.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
63506
+ import_node_fs49.default.mkdirSync(work, { recursive: true });
63202
63507
  try {
63203
63508
  await new Promise((resolve9, reject) => {
63204
63509
  const proc = (0, import_node_child_process12.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -63206,32 +63511,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
63206
63511
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
63207
63512
  });
63208
63513
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
63209
- const src = import_node_path54.default.join(work, dirName, "frpc");
63210
- if (!import_node_fs48.default.existsSync(src)) {
63514
+ const src = import_node_path55.default.join(work, dirName, "frpc");
63515
+ if (!import_node_fs49.default.existsSync(src)) {
63211
63516
  throw new Error(`frpc not found inside tarball at ${src}`);
63212
63517
  }
63213
- import_node_fs48.default.copyFileSync(src, destBin);
63518
+ import_node_fs49.default.copyFileSync(src, destBin);
63214
63519
  } finally {
63215
- import_node_fs48.default.rmSync(work, { recursive: true, force: true });
63520
+ import_node_fs49.default.rmSync(work, { recursive: true, force: true });
63216
63521
  }
63217
63522
  }
63218
63523
 
63219
63524
  // src/tunnel/frpc-process.ts
63220
- var import_node_fs49 = __toESM(require("fs"), 1);
63221
- var import_node_path55 = __toESM(require("path"), 1);
63525
+ var import_node_fs50 = __toESM(require("fs"), 1);
63526
+ var import_node_path56 = __toESM(require("path"), 1);
63222
63527
  var import_node_child_process13 = require("child_process");
63223
63528
  function frpcPidFilePath(dataDir) {
63224
- return import_node_path55.default.join(dataDir, "frpc.pid");
63529
+ return import_node_path56.default.join(dataDir, "frpc.pid");
63225
63530
  }
63226
63531
  function writeFrpcPid(dataDir, pid) {
63227
63532
  try {
63228
- import_node_fs49.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
63533
+ import_node_fs50.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
63229
63534
  } catch {
63230
63535
  }
63231
63536
  }
63232
63537
  function clearFrpcPid(dataDir) {
63233
63538
  try {
63234
- import_node_fs49.default.unlinkSync(frpcPidFilePath(dataDir));
63539
+ import_node_fs50.default.unlinkSync(frpcPidFilePath(dataDir));
63235
63540
  } catch {
63236
63541
  }
63237
63542
  }
@@ -63247,7 +63552,7 @@ function defaultIsPidAlive(pid) {
63247
63552
  }
63248
63553
  function defaultReadPidFile(file) {
63249
63554
  try {
63250
- return import_node_fs49.default.readFileSync(file, "utf8");
63555
+ return import_node_fs50.default.readFileSync(file, "utf8");
63251
63556
  } catch {
63252
63557
  return null;
63253
63558
  }
@@ -63263,7 +63568,7 @@ function defaultSleep2(ms) {
63263
63568
  }
63264
63569
  async function killStaleFrpc(deps) {
63265
63570
  const pidFile = frpcPidFilePath(deps.dataDir);
63266
- const tomlPath = import_node_path55.default.join(deps.dataDir, "frpc.toml");
63571
+ const tomlPath = import_node_path56.default.join(deps.dataDir, "frpc.toml");
63267
63572
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
63268
63573
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
63269
63574
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -63287,7 +63592,7 @@ async function killStaleFrpc(deps) {
63287
63592
  }
63288
63593
  if (victims.size === 0) {
63289
63594
  try {
63290
- import_node_fs49.default.unlinkSync(pidFile);
63595
+ import_node_fs50.default.unlinkSync(pidFile);
63291
63596
  } catch {
63292
63597
  }
63293
63598
  return;
@@ -63298,7 +63603,7 @@ async function killStaleFrpc(deps) {
63298
63603
  }
63299
63604
  await sleep2(deps.reapWaitMs ?? 300);
63300
63605
  try {
63301
- import_node_fs49.default.unlinkSync(pidFile);
63606
+ import_node_fs50.default.unlinkSync(pidFile);
63302
63607
  } catch {
63303
63608
  }
63304
63609
  }
@@ -63335,7 +63640,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
63335
63640
  var TunnelManager = class {
63336
63641
  constructor(deps) {
63337
63642
  this.deps = deps;
63338
- this.store = deps.store ?? new TunnelStore(import_node_path56.default.join(deps.dataDir, "tunnel.json"));
63643
+ this.store = deps.store ?? new TunnelStore(import_node_path57.default.join(deps.dataDir, "tunnel.json"));
63339
63644
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
63340
63645
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
63341
63646
  }
@@ -63462,7 +63767,7 @@ var TunnelManager = class {
63462
63767
  dataDir: this.deps.dataDir,
63463
63768
  override: this.deps.frpcBinaryOverride ?? void 0
63464
63769
  });
63465
- const tomlPath = import_node_path56.default.join(this.deps.dataDir, "frpc.toml");
63770
+ const tomlPath = import_node_path57.default.join(this.deps.dataDir, "frpc.toml");
63466
63771
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto13.default.randomBytes(3).toString("hex")}`;
63467
63772
  const toml = buildFrpcToml({
63468
63773
  serverAddr: t.frpsHost,
@@ -63473,14 +63778,14 @@ var TunnelManager = class {
63473
63778
  localPort,
63474
63779
  logLevel: "info"
63475
63780
  });
63476
- await import_node_fs50.default.promises.writeFile(tomlPath, toml, { mode: 384 });
63781
+ await import_node_fs51.default.promises.writeFile(tomlPath, toml, { mode: 384 });
63477
63782
  const proc = (this.deps.spawnImpl ?? import_node_child_process14.spawn)(frpcBin, ["-c", tomlPath], {
63478
63783
  stdio: ["ignore", "pipe", "pipe"]
63479
63784
  });
63480
- const logDir = import_node_path56.default.join(this.deps.dataDir, "log");
63481
- import_node_fs50.default.mkdirSync(logDir, { recursive: true });
63482
- const logFilePath = import_node_path56.default.join(logDir, "frpc.log");
63483
- const logStream = import_node_fs50.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
63785
+ const logDir = import_node_path57.default.join(this.deps.dataDir, "log");
63786
+ import_node_fs51.default.mkdirSync(logDir, { recursive: true });
63787
+ const logFilePath = import_node_path57.default.join(logDir, "frpc.log");
63788
+ const logStream = import_node_fs51.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
63484
63789
  logStream.on("error", () => {
63485
63790
  });
63486
63791
  const tee = (chunk) => {
@@ -63563,27 +63868,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
63563
63868
 
63564
63869
  // src/tunnel/device-key.ts
63565
63870
  var import_node_os18 = __toESM(require("os"), 1);
63566
- var import_node_path57 = __toESM(require("path"), 1);
63871
+ var import_node_path58 = __toESM(require("path"), 1);
63567
63872
  var import_node_crypto14 = __toESM(require("crypto"), 1);
63568
63873
  var DERIVE_SALT = "clawd-tunnel-device-v1";
63569
63874
  function deriveStableDeviceKey(opts = {}) {
63570
63875
  const hostname = opts.hostname ?? import_node_os18.default.hostname();
63571
63876
  const uid = opts.uid ?? (typeof import_node_os18.default.userInfo === "function" ? import_node_os18.default.userInfo().uid : 0);
63572
63877
  const home = opts.home ?? import_node_os18.default.homedir();
63573
- const defaultDataDir = import_node_path57.default.resolve(import_node_path57.default.join(home, ".clawd"));
63574
- const normalizedDataDir = opts.dataDir ? import_node_path57.default.resolve(opts.dataDir) : null;
63878
+ const defaultDataDir = import_node_path58.default.resolve(import_node_path58.default.join(home, ".clawd"));
63879
+ const normalizedDataDir = opts.dataDir ? import_node_path58.default.resolve(opts.dataDir) : null;
63575
63880
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
63576
63881
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
63577
63882
  return import_node_crypto14.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
63578
63883
  }
63579
63884
 
63580
63885
  // src/auth-store.ts
63581
- var import_node_fs51 = __toESM(require("fs"), 1);
63582
- var import_node_path58 = __toESM(require("path"), 1);
63886
+ var import_node_fs52 = __toESM(require("fs"), 1);
63887
+ var import_node_path59 = __toESM(require("path"), 1);
63583
63888
  var import_node_crypto15 = __toESM(require("crypto"), 1);
63584
63889
  var AUTH_FILE_NAME = "auth.json";
63585
63890
  function authFilePath(dataDir) {
63586
- return import_node_path58.default.join(dataDir, AUTH_FILE_NAME);
63891
+ return import_node_path59.default.join(dataDir, AUTH_FILE_NAME);
63587
63892
  }
63588
63893
  function loadOrCreateAuthFile(opts) {
63589
63894
  const file = authFilePath(opts.dataDir);
@@ -63615,7 +63920,7 @@ function defaultGenerateOwnerPrincipalId() {
63615
63920
  }
63616
63921
  function readAuthFile(file) {
63617
63922
  try {
63618
- const raw = import_node_fs51.default.readFileSync(file, "utf8");
63923
+ const raw = import_node_fs52.default.readFileSync(file, "utf8");
63619
63924
  const parsed = JSON.parse(raw);
63620
63925
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
63621
63926
  return null;
@@ -63635,26 +63940,26 @@ function readAuthFile(file) {
63635
63940
  }
63636
63941
  }
63637
63942
  function writeAuthFile(file, content) {
63638
- import_node_fs51.default.mkdirSync(import_node_path58.default.dirname(file), { recursive: true });
63639
- import_node_fs51.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
63943
+ import_node_fs52.default.mkdirSync(import_node_path59.default.dirname(file), { recursive: true });
63944
+ import_node_fs52.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
63640
63945
  try {
63641
- import_node_fs51.default.chmodSync(file, 384);
63946
+ import_node_fs52.default.chmodSync(file, 384);
63642
63947
  } catch {
63643
63948
  }
63644
63949
  }
63645
63950
 
63646
63951
  // src/owner-profile.ts
63647
- var import_node_fs52 = __toESM(require("fs"), 1);
63952
+ var import_node_fs53 = __toESM(require("fs"), 1);
63648
63953
  var import_node_os19 = __toESM(require("os"), 1);
63649
- var import_node_path59 = __toESM(require("path"), 1);
63954
+ var import_node_path60 = __toESM(require("path"), 1);
63650
63955
  var PROFILE_FILENAME = "profile.json";
63651
63956
  function profilePath(dataDir) {
63652
- return import_node_path59.default.join(dataDir, PROFILE_FILENAME);
63957
+ return import_node_path60.default.join(dataDir, PROFILE_FILENAME);
63653
63958
  }
63654
63959
  function loadOwnerProfile(dataDir) {
63655
63960
  let raw;
63656
63961
  try {
63657
- raw = import_node_fs52.default.readFileSync(profilePath(dataDir), "utf8");
63962
+ raw = import_node_fs53.default.readFileSync(profilePath(dataDir), "utf8");
63658
63963
  } catch {
63659
63964
  return {};
63660
63965
  }
@@ -63670,7 +63975,7 @@ function loadOwnerProfile(dataDir) {
63670
63975
  }
63671
63976
  function patchOwnerProfile(dataDir, patch) {
63672
63977
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
63673
- import_node_fs52.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
63978
+ import_node_fs53.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
63674
63979
  return merged;
63675
63980
  }
63676
63981
  function loadOwnerDisplayName(dataDir) {
@@ -63686,18 +63991,18 @@ function loadOwnerDisplayName(dataDir) {
63686
63991
  }
63687
63992
 
63688
63993
  // src/feishu-auth/owner-identity-store.ts
63689
- var import_node_fs53 = __toESM(require("fs"), 1);
63690
- var import_node_path60 = __toESM(require("path"), 1);
63994
+ var import_node_fs54 = __toESM(require("fs"), 1);
63995
+ var import_node_path61 = __toESM(require("path"), 1);
63691
63996
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
63692
63997
  var OwnerIdentityStore = class {
63693
63998
  file;
63694
63999
  constructor(dataDir) {
63695
- this.file = import_node_path60.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
64000
+ this.file = import_node_path61.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
63696
64001
  }
63697
64002
  read() {
63698
64003
  let raw;
63699
64004
  try {
63700
- raw = import_node_fs53.default.readFileSync(this.file, "utf8");
64005
+ raw = import_node_fs54.default.readFileSync(this.file, "utf8");
63701
64006
  } catch {
63702
64007
  return null;
63703
64008
  }
@@ -63725,16 +64030,16 @@ var OwnerIdentityStore = class {
63725
64030
  };
63726
64031
  }
63727
64032
  write(record3) {
63728
- import_node_fs53.default.mkdirSync(import_node_path60.default.dirname(this.file), { recursive: true });
63729
- import_node_fs53.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
64033
+ import_node_fs54.default.mkdirSync(import_node_path61.default.dirname(this.file), { recursive: true });
64034
+ import_node_fs54.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
63730
64035
  try {
63731
- import_node_fs53.default.chmodSync(this.file, 384);
64036
+ import_node_fs54.default.chmodSync(this.file, 384);
63732
64037
  } catch {
63733
64038
  }
63734
64039
  }
63735
64040
  clear() {
63736
64041
  try {
63737
- import_node_fs53.default.unlinkSync(this.file);
64042
+ import_node_fs54.default.unlinkSync(this.file);
63738
64043
  } catch (err) {
63739
64044
  const code = err?.code;
63740
64045
  if (code !== "ENOENT") throw err;
@@ -64195,8 +64500,8 @@ function verifyConnectToken(args) {
64195
64500
  }
64196
64501
 
64197
64502
  // src/feishu-auth/server-key.ts
64198
- var fs70 = __toESM(require("fs"), 1);
64199
- var path73 = __toESM(require("path"), 1);
64503
+ var fs71 = __toESM(require("fs"), 1);
64504
+ var path74 = __toESM(require("path"), 1);
64200
64505
  var FILE_NAME2 = "server-signing-key.json";
64201
64506
  var ServerKeyStore = class {
64202
64507
  constructor(dataDir) {
@@ -64204,12 +64509,12 @@ var ServerKeyStore = class {
64204
64509
  }
64205
64510
  dataDir;
64206
64511
  filePath() {
64207
- return path73.join(this.dataDir, FILE_NAME2);
64512
+ return path74.join(this.dataDir, FILE_NAME2);
64208
64513
  }
64209
64514
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
64210
64515
  read() {
64211
64516
  try {
64212
- const raw = fs70.readFileSync(this.filePath(), "utf8");
64517
+ const raw = fs71.readFileSync(this.filePath(), "utf8");
64213
64518
  const parsed = JSON.parse(raw);
64214
64519
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
64215
64520
  return parsed.publicKeyPem;
@@ -64224,12 +64529,12 @@ var ServerKeyStore = class {
64224
64529
  publicKeyPem,
64225
64530
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
64226
64531
  };
64227
- fs70.mkdirSync(this.dataDir, { recursive: true });
64228
- fs70.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
64532
+ fs71.mkdirSync(this.dataDir, { recursive: true });
64533
+ fs71.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
64229
64534
  }
64230
64535
  clear() {
64231
64536
  try {
64232
- fs70.unlinkSync(this.filePath());
64537
+ fs71.unlinkSync(this.filePath());
64233
64538
  } catch {
64234
64539
  }
64235
64540
  }
@@ -64239,19 +64544,19 @@ var ServerKeyStore = class {
64239
64544
  init_protocol();
64240
64545
 
64241
64546
  // src/handlers/index.ts
64242
- var import_node_path74 = __toESM(require("path"), 1);
64547
+ var import_node_path75 = __toESM(require("path"), 1);
64243
64548
 
64244
64549
  // src/handlers/session.ts
64245
64550
  init_protocol();
64246
64551
 
64247
64552
  // src/session/fork.ts
64248
- var import_node_fs54 = __toESM(require("fs"), 1);
64553
+ var import_node_fs55 = __toESM(require("fs"), 1);
64249
64554
  var import_node_os20 = __toESM(require("os"), 1);
64250
- var import_node_path61 = __toESM(require("path"), 1);
64555
+ var import_node_path62 = __toESM(require("path"), 1);
64251
64556
  var import_node_crypto17 = require("crypto");
64252
64557
  init_claude_history();
64253
64558
  function readJsonlEntries(file) {
64254
- const raw = import_node_fs54.default.readFileSync(file, "utf8");
64559
+ const raw = import_node_fs55.default.readFileSync(file, "utf8");
64255
64560
  const out = [];
64256
64561
  for (const line of raw.split("\n")) {
64257
64562
  const t = line.trim();
@@ -64264,19 +64569,19 @@ function readJsonlEntries(file) {
64264
64569
  return out;
64265
64570
  }
64266
64571
  function forkSession(input) {
64267
- const baseDir = input.baseDir ?? import_node_path61.default.join(import_node_os20.default.homedir(), ".claude");
64268
- let projectDir = import_node_path61.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
64269
- let sourceFile = import_node_path61.default.join(projectDir, `${input.toolSessionId}.jsonl`);
64270
- if (!import_node_fs54.default.existsSync(sourceFile)) {
64572
+ const baseDir = input.baseDir ?? import_node_path62.default.join(import_node_os20.default.homedir(), ".claude");
64573
+ let projectDir = import_node_path62.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
64574
+ let sourceFile = import_node_path62.default.join(projectDir, `${input.toolSessionId}.jsonl`);
64575
+ if (!import_node_fs55.default.existsSync(sourceFile)) {
64271
64576
  const found = findTranscriptByToolSessionId(
64272
- import_node_path61.default.join(baseDir, "projects"),
64577
+ import_node_path62.default.join(baseDir, "projects"),
64273
64578
  input.toolSessionId
64274
64579
  );
64275
64580
  if (!found) {
64276
64581
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
64277
64582
  }
64278
64583
  sourceFile = found;
64279
- projectDir = import_node_path61.default.dirname(found);
64584
+ projectDir = import_node_path62.default.dirname(found);
64280
64585
  }
64281
64586
  const entries = readJsonlEntries(sourceFile);
64282
64587
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -64305,27 +64610,27 @@ function forkSession(input) {
64305
64610
  }
64306
64611
  forkedLines.push(JSON.stringify(forked));
64307
64612
  }
64308
- const outDir = input.targetCwd ? import_node_path61.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
64309
- const forkedFilePath = import_node_path61.default.join(outDir, `${forkedToolSessionId}.jsonl`);
64310
- import_node_fs54.default.mkdirSync(outDir, { recursive: true });
64311
- import_node_fs54.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
64613
+ const outDir = input.targetCwd ? import_node_path62.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
64614
+ const forkedFilePath = import_node_path62.default.join(outDir, `${forkedToolSessionId}.jsonl`);
64615
+ import_node_fs55.default.mkdirSync(outDir, { recursive: true });
64616
+ import_node_fs55.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
64312
64617
  return { forkedToolSessionId, forkedFilePath };
64313
64618
  }
64314
64619
 
64315
64620
  // src/session/external-scan.ts
64316
- var import_node_fs55 = __toESM(require("fs"), 1);
64621
+ var import_node_fs56 = __toESM(require("fs"), 1);
64317
64622
  var import_promises10 = __toESM(require("fs/promises"), 1);
64318
64623
  var import_node_os21 = __toESM(require("os"), 1);
64319
- var import_node_path62 = __toESM(require("path"), 1);
64624
+ var import_node_path63 = __toESM(require("path"), 1);
64320
64625
  var import_node_module = require("module");
64321
64626
  var import_node_child_process15 = require("child_process");
64322
64627
  var import_meta5 = {};
64323
64628
  function defaultRoots() {
64324
64629
  const home = import_node_os21.default.homedir();
64325
64630
  return {
64326
- claudeProjectsDir: import_node_path62.default.join(home, ".claude", "projects"),
64327
- codexDir: import_node_path62.default.join(home, ".codex"),
64328
- clawdDir: import_node_path62.default.join(home, ".clawd")
64631
+ claudeProjectsDir: import_node_path63.default.join(home, ".claude", "projects"),
64632
+ codexDir: import_node_path63.default.join(home, ".codex"),
64633
+ clawdDir: import_node_path63.default.join(home, ".clawd")
64329
64634
  };
64330
64635
  }
64331
64636
  function width(s) {
@@ -64376,7 +64681,7 @@ function userText(msg) {
64376
64681
  }
64377
64682
  function isDir2(p2) {
64378
64683
  try {
64379
- return import_node_fs55.default.statSync(p2).isDirectory();
64684
+ return import_node_fs56.default.statSync(p2).isDirectory();
64380
64685
  } catch {
64381
64686
  return false;
64382
64687
  }
@@ -64385,7 +64690,7 @@ async function scanClaude(roots) {
64385
64690
  const out = [];
64386
64691
  let dirs;
64387
64692
  try {
64388
- dirs = import_node_fs55.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
64693
+ dirs = import_node_fs56.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
64389
64694
  } catch {
64390
64695
  return out;
64391
64696
  }
@@ -64393,16 +64698,16 @@ async function scanClaude(roots) {
64393
64698
  if (!d.isDirectory()) continue;
64394
64699
  let files;
64395
64700
  try {
64396
- files = import_node_fs55.default.readdirSync(import_node_path62.default.join(roots.claudeProjectsDir, d.name));
64701
+ files = import_node_fs56.default.readdirSync(import_node_path63.default.join(roots.claudeProjectsDir, d.name));
64397
64702
  } catch {
64398
64703
  continue;
64399
64704
  }
64400
64705
  for (const name of files) {
64401
64706
  if (!name.endsWith(".jsonl")) continue;
64402
- const file = import_node_path62.default.join(roots.claudeProjectsDir, d.name, name);
64707
+ const file = import_node_path63.default.join(roots.claudeProjectsDir, d.name, name);
64403
64708
  let st;
64404
64709
  try {
64405
- st = import_node_fs55.default.statSync(file);
64710
+ st = import_node_fs56.default.statSync(file);
64406
64711
  } catch {
64407
64712
  continue;
64408
64713
  }
@@ -64455,7 +64760,7 @@ async function scanClaude(roots) {
64455
64760
  return out;
64456
64761
  }
64457
64762
  async function countCodexTurns(rolloutPath) {
64458
- if (!rolloutPath || !import_node_fs55.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
64763
+ if (!rolloutPath || !import_node_fs56.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
64459
64764
  let turns = 0;
64460
64765
  let first = "";
64461
64766
  for await (const rec5 of jsonLines(rolloutPath)) {
@@ -64529,7 +64834,7 @@ async function codexFromRows(rows) {
64529
64834
  async function scanCodex(roots) {
64530
64835
  let dbs = [];
64531
64836
  try {
64532
- dbs = import_node_fs55.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path62.default.join(roots.codexDir, n));
64837
+ dbs = import_node_fs56.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path63.default.join(roots.codexDir, n));
64533
64838
  } catch {
64534
64839
  }
64535
64840
  if (!dbs.length) return [];
@@ -64538,14 +64843,14 @@ async function scanCodex(roots) {
64538
64843
  }
64539
64844
  async function scanExternalSessions(rootsIn) {
64540
64845
  const roots = { ...defaultRoots(), ...rootsIn };
64541
- const personaRoot = import_node_path62.default.join(roots.clawdDir, "personas");
64846
+ const personaRoot = import_node_path63.default.join(roots.clawdDir, "personas");
64542
64847
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
64543
64848
  const out = [];
64544
64849
  for (const c of all) {
64545
64850
  if (c.skip) continue;
64546
64851
  if (c.turns < 1) continue;
64547
64852
  if (!c.cwd || !isDir2(c.cwd)) continue;
64548
- if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path62.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path62.default.sep)) {
64853
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path63.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path63.default.sep)) {
64549
64854
  continue;
64550
64855
  }
64551
64856
  out.push({
@@ -64562,13 +64867,13 @@ async function scanExternalSessions(rootsIn) {
64562
64867
  }
64563
64868
 
64564
64869
  // src/session/import-ledger.ts
64565
- var import_node_fs56 = __toESM(require("fs"), 1);
64566
- var import_node_path63 = __toESM(require("path"), 1);
64870
+ var import_node_fs57 = __toESM(require("fs"), 1);
64871
+ var import_node_path64 = __toESM(require("path"), 1);
64567
64872
  var LEDGER_FILENAME = "session-import-ledger.json";
64568
64873
  function readImportLedger(dataDir) {
64569
64874
  try {
64570
64875
  const parsed = JSON.parse(
64571
- import_node_fs56.default.readFileSync(import_node_path63.default.join(dataDir, LEDGER_FILENAME), "utf8")
64876
+ import_node_fs57.default.readFileSync(import_node_path64.default.join(dataDir, LEDGER_FILENAME), "utf8")
64572
64877
  );
64573
64878
  return Array.isArray(parsed) ? parsed : [];
64574
64879
  } catch {
@@ -64576,10 +64881,10 @@ function readImportLedger(dataDir) {
64576
64881
  }
64577
64882
  }
64578
64883
  function appendImportLedger(dataDir, entry) {
64579
- const file = import_node_path63.default.join(dataDir, LEDGER_FILENAME);
64884
+ const file = import_node_path64.default.join(dataDir, LEDGER_FILENAME);
64580
64885
  const entries = readImportLedger(dataDir);
64581
64886
  entries.push(entry);
64582
- import_node_fs56.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
64887
+ import_node_fs57.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
64583
64888
  }
64584
64889
 
64585
64890
  // src/handlers/session.ts
@@ -65135,7 +65440,7 @@ function buildPermissionHandlers(deps) {
65135
65440
  }
65136
65441
 
65137
65442
  // src/handlers/history.ts
65138
- var path78 = __toESM(require("path"), 1);
65443
+ var path79 = __toESM(require("path"), 1);
65139
65444
  init_protocol();
65140
65445
 
65141
65446
  // src/session/recent-dirs.ts
@@ -65153,7 +65458,7 @@ function listRecentDirs(store, limit = 50) {
65153
65458
  }
65154
65459
 
65155
65460
  // src/permission/persona-paths.ts
65156
- var path77 = __toESM(require("path"), 1);
65461
+ var path78 = __toESM(require("path"), 1);
65157
65462
  function getAllowedPersonaIds(grants, action) {
65158
65463
  const ids = /* @__PURE__ */ new Set();
65159
65464
  for (const g2 of grants) {
@@ -65166,42 +65471,42 @@ function getAllowedPersonaIds(grants, action) {
65166
65471
  return ids;
65167
65472
  }
65168
65473
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
65169
- const target = path77.resolve(absPath);
65474
+ const target = path78.resolve(absPath);
65170
65475
  if (userWorkDir) {
65171
- const u = path77.resolve(userWorkDir);
65172
- const usep = u.endsWith(path77.sep) ? "" : path77.sep;
65476
+ const u = path78.resolve(userWorkDir);
65477
+ const usep = u.endsWith(path78.sep) ? "" : path78.sep;
65173
65478
  if (target === u || target.startsWith(u + usep)) return true;
65174
65479
  }
65175
- const root = path77.resolve(personaRoot);
65176
- const sep4 = root.endsWith(path77.sep) ? "" : path77.sep;
65480
+ const root = path78.resolve(personaRoot);
65481
+ const sep4 = root.endsWith(path78.sep) ? "" : path78.sep;
65177
65482
  if (!target.startsWith(root + sep4)) return false;
65178
- const rel = path77.relative(root, target);
65483
+ const rel = path78.relative(root, target);
65179
65484
  if (!rel || rel.startsWith("..")) return false;
65180
- const personaId2 = rel.split(path77.sep)[0];
65485
+ const personaId2 = rel.split(path78.sep)[0];
65181
65486
  if (!personaId2) return false;
65182
65487
  const allowed = getAllowedPersonaIds(grants, action);
65183
65488
  if (allowed === "*") return true;
65184
65489
  return allowed.has(personaId2);
65185
65490
  }
65186
65491
  function personaIdFromPath(absPath, personaRoot) {
65187
- const root = path77.resolve(personaRoot);
65188
- const target = path77.resolve(absPath);
65189
- const sep4 = root.endsWith(path77.sep) ? "" : path77.sep;
65492
+ const root = path78.resolve(personaRoot);
65493
+ const target = path78.resolve(absPath);
65494
+ const sep4 = root.endsWith(path78.sep) ? "" : path78.sep;
65190
65495
  if (!target.startsWith(root + sep4)) return null;
65191
- const rel = path77.relative(root, target);
65496
+ const rel = path78.relative(root, target);
65192
65497
  if (!rel || rel.startsWith("..")) return null;
65193
- const id = rel.split(path77.sep)[0];
65498
+ const id = rel.split(path78.sep)[0];
65194
65499
  return id || null;
65195
65500
  }
65196
65501
  function isPathWithin(dir, absPath) {
65197
- const d = path77.resolve(dir);
65198
- const t = path77.resolve(absPath);
65199
- const sep4 = d.endsWith(path77.sep) ? "" : path77.sep;
65502
+ const d = path78.resolve(dir);
65503
+ const t = path78.resolve(absPath);
65504
+ const sep4 = d.endsWith(path78.sep) ? "" : path78.sep;
65200
65505
  return t === d || t.startsWith(d + sep4);
65201
65506
  }
65202
65507
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
65203
65508
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
65204
- return personaIdFromPath(path77.resolve(absPath), personaRoot) === personaId2;
65509
+ return personaIdFromPath(path78.resolve(absPath), personaRoot) === personaId2;
65205
65510
  }
65206
65511
 
65207
65512
  // src/handlers/history.ts
@@ -65254,7 +65559,7 @@ function buildHistoryHandlers(deps) {
65254
65559
  if (!pid) return false;
65255
65560
  return isGuestPathAllowed(
65256
65561
  ctx.grants,
65257
- path78.join(personaRoot, pid),
65562
+ path79.join(personaRoot, pid),
65258
65563
  personaRoot,
65259
65564
  "read",
65260
65565
  userWorkDir
@@ -65266,7 +65571,7 @@ function buildHistoryHandlers(deps) {
65266
65571
  };
65267
65572
  const list = async (frame, _client, ctx) => {
65268
65573
  const args = HistoryListArgs.parse(frame);
65269
- assertGuestPath(ctx, path78.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
65574
+ assertGuestPath(ctx, path79.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
65270
65575
  const sessions = await history.listSessions(args);
65271
65576
  return { response: { type: "history:list", sessions } };
65272
65577
  };
@@ -65314,14 +65619,14 @@ function buildHistoryHandlers(deps) {
65314
65619
  };
65315
65620
  const subagents = async (frame, _client, ctx) => {
65316
65621
  const args = HistorySubagentsArgs.parse(frame);
65317
- assertGuestPath(ctx, path78.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
65622
+ assertGuestPath(ctx, path79.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
65318
65623
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
65319
65624
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
65320
65625
  return { response: { type: "history:subagents", subagents: subs } };
65321
65626
  };
65322
65627
  const subagentRead = async (frame, _client, ctx) => {
65323
65628
  const args = HistorySubagentReadArgs.parse(frame);
65324
- assertGuestPath(ctx, path78.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
65629
+ assertGuestPath(ctx, path79.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
65325
65630
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
65326
65631
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
65327
65632
  return { response: { type: "history:subagent-read", ...res } };
@@ -65331,7 +65636,7 @@ function buildHistoryHandlers(deps) {
65331
65636
  if (ctx?.principal.kind === "guest" && personaRoot) {
65332
65637
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
65333
65638
  const filtered = dirs.filter(
65334
- (d) => isGuestPathAllowed(ctx.grants, path78.resolve(d.cwd), personaRoot, "read", userWorkDir)
65639
+ (d) => isGuestPathAllowed(ctx.grants, path79.resolve(d.cwd), personaRoot, "read", userWorkDir)
65335
65640
  );
65336
65641
  return { response: { type: "history:recentDirs", dirs: filtered } };
65337
65642
  }
@@ -65348,17 +65653,17 @@ function buildHistoryHandlers(deps) {
65348
65653
  }
65349
65654
 
65350
65655
  // src/handlers/projects.ts
65351
- var fs74 = __toESM(require("fs"), 1);
65656
+ var fs75 = __toESM(require("fs"), 1);
65352
65657
  var os23 = __toESM(require("os"), 1);
65353
- var path79 = __toESM(require("path"), 1);
65658
+ var path80 = __toESM(require("path"), 1);
65354
65659
  var import_node_child_process16 = require("child_process");
65355
65660
  init_protocol();
65356
- var DEFAULT_PROJECTS_ROOT = path79.join(os23.homedir(), "Documents", "ChatGPT");
65661
+ var DEFAULT_PROJECTS_ROOT = path80.join(os23.homedir(), "Documents", "ChatGPT");
65357
65662
  function allocateDir(root, name) {
65358
- let candidate = path79.join(root, name);
65663
+ let candidate = path80.join(root, name);
65359
65664
  let n = 2;
65360
- while (fs74.existsSync(candidate)) {
65361
- candidate = path79.join(root, `${name} ${n}`);
65665
+ while (fs75.existsSync(candidate)) {
65666
+ candidate = path80.join(root, `${name} ${n}`);
65362
65667
  n += 1;
65363
65668
  }
65364
65669
  return candidate;
@@ -65386,7 +65691,7 @@ function buildProjectHandlers(deps) {
65386
65691
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
65387
65692
  }
65388
65693
  try {
65389
- if (!fs74.statSync(args.path).isDirectory()) throw new Error("not dir");
65694
+ if (!fs75.statSync(args.path).isDirectory()) throw new Error("not dir");
65390
65695
  } catch {
65391
65696
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
65392
65697
  }
@@ -65402,7 +65707,7 @@ function buildProjectHandlers(deps) {
65402
65707
  let target;
65403
65708
  if (args.path) {
65404
65709
  try {
65405
- if (!fs74.statSync(args.path).isDirectory()) throw new Error("not dir");
65710
+ if (!fs75.statSync(args.path).isDirectory()) throw new Error("not dir");
65406
65711
  } catch {
65407
65712
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
65408
65713
  }
@@ -65410,15 +65715,15 @@ function buildProjectHandlers(deps) {
65410
65715
  } else {
65411
65716
  const name = args.name;
65412
65717
  try {
65413
- fs74.mkdirSync(root, { recursive: true });
65718
+ fs75.mkdirSync(root, { recursive: true });
65414
65719
  target = allocateDir(root, name);
65415
- fs74.mkdirSync(target);
65720
+ fs75.mkdirSync(target);
65416
65721
  } catch (err) {
65417
65722
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
65418
65723
  }
65419
65724
  const git2 = (0, import_node_child_process16.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
65420
65725
  if (git2.status !== 0) {
65421
- fs74.rmSync(target, { recursive: true, force: true });
65726
+ fs75.rmSync(target, { recursive: true, force: true });
65422
65727
  throw new ClawdError(
65423
65728
  ERROR_CODES.INVALID_CWD,
65424
65729
  `git init \u5931\u8D25\uFF08${git2.error ? String(git2.error) : `exit ${git2.status}`}\uFF09: ${target}`
@@ -65443,7 +65748,7 @@ function buildProjectHandlers(deps) {
65443
65748
  }
65444
65749
 
65445
65750
  // src/handlers/workspace.ts
65446
- var path80 = __toESM(require("path"), 1);
65751
+ var path81 = __toESM(require("path"), 1);
65447
65752
  init_protocol();
65448
65753
  var os24 = __toESM(require("os"), 1);
65449
65754
  init_protocol();
@@ -65486,22 +65791,22 @@ function buildWorkspaceHandlers(deps) {
65486
65791
  const args = WorkspaceListArgs.parse(frame);
65487
65792
  const isGuest = ctx?.principal.kind === "guest";
65488
65793
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os24.homedir();
65489
- const resolvedCwd = path80.resolve(args.cwd ?? fallbackCwd);
65490
- const target = args.path ? path80.resolve(resolvedCwd, args.path) : resolvedCwd;
65794
+ const resolvedCwd = path81.resolve(args.cwd ?? fallbackCwd);
65795
+ const target = args.path ? path81.resolve(resolvedCwd, args.path) : resolvedCwd;
65491
65796
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
65492
65797
  const res = workspace.list({ ...args, cwd: resolvedCwd });
65493
65798
  return { response: { type: "workspace:list", ...res } };
65494
65799
  };
65495
65800
  const read = async (frame, _client, ctx) => {
65496
65801
  const args = WorkspaceReadArgs.parse(frame);
65497
- const target = path80.isAbsolute(args.path) ? path80.resolve(args.path) : path80.resolve(args.cwd, args.path);
65802
+ const target = path81.isAbsolute(args.path) ? path81.resolve(args.path) : path81.resolve(args.cwd, args.path);
65498
65803
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
65499
65804
  const res = workspace.read(args);
65500
65805
  return { response: { type: "workspace:read", ...res } };
65501
65806
  };
65502
65807
  const skillsList = async (frame, _client, ctx) => {
65503
65808
  const args = SkillsListArgs.parse(frame);
65504
- const cwdAbs = path80.resolve(args.cwd);
65809
+ const cwdAbs = path81.resolve(args.cwd);
65505
65810
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
65506
65811
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
65507
65812
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -65513,7 +65818,7 @@ function buildWorkspaceHandlers(deps) {
65513
65818
  };
65514
65819
  const agentsList = async (frame, _client, ctx) => {
65515
65820
  const args = AgentsListArgs.parse(frame);
65516
- const cwdAbs = path80.resolve(args.cwd);
65821
+ const cwdAbs = path81.resolve(args.cwd);
65517
65822
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
65518
65823
  if (isCodexFamily(args.tool) || args.tool === PI_TOOL_ID) {
65519
65824
  return { response: { type: "agents:list", agents: [] } };
@@ -65535,20 +65840,20 @@ function buildWorkspaceHandlers(deps) {
65535
65840
  }
65536
65841
 
65537
65842
  // src/handlers/git.ts
65538
- var path82 = __toESM(require("path"), 1);
65843
+ var path83 = __toESM(require("path"), 1);
65539
65844
  init_protocol();
65540
65845
  init_protocol();
65541
65846
 
65542
65847
  // src/workspace/git.ts
65543
65848
  var import_node_child_process17 = require("child_process");
65544
- var import_node_fs57 = __toESM(require("fs"), 1);
65545
- var import_node_path64 = __toESM(require("path"), 1);
65849
+ var import_node_fs58 = __toESM(require("fs"), 1);
65850
+ var import_node_path65 = __toESM(require("path"), 1);
65546
65851
  var import_node_util = require("util");
65547
65852
  var pexec = (0, import_node_util.promisify)(import_node_child_process17.execFile);
65548
65853
  function normalizePath(p2) {
65549
- const resolved = import_node_path64.default.resolve(p2);
65854
+ const resolved = import_node_path65.default.resolve(p2);
65550
65855
  try {
65551
- return import_node_fs57.default.realpathSync(resolved);
65856
+ return import_node_fs58.default.realpathSync(resolved);
65552
65857
  } catch {
65553
65858
  return resolved;
65554
65859
  }
@@ -65622,7 +65927,7 @@ async function listGitBranches(cwd) {
65622
65927
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
65623
65928
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
65624
65929
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
65625
- if (!isGuestPathAllowed(ctx.grants, path82.resolve(cwd), personaRoot, "read", userWorkDir)) {
65930
+ if (!isGuestPathAllowed(ctx.grants, path83.resolve(cwd), personaRoot, "read", userWorkDir)) {
65626
65931
  throw new ClawdError(
65627
65932
  ERROR_CODES.UNAUTHORIZED,
65628
65933
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -66191,6 +66496,54 @@ function buildFeishuAuthHandlers(deps) {
66191
66496
  };
66192
66497
  }
66193
66498
 
66499
+ // src/handlers/cloud-connectors.ts
66500
+ init_protocol();
66501
+ function ensureOwner5(ctx) {
66502
+ if (!ctx || ctx.principal.kind !== "owner") {
66503
+ throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: cloud:connectors:* requires owner ctx");
66504
+ }
66505
+ }
66506
+ var invalid2 = (msg) => new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_ERROR: ${msg}`);
66507
+ function buildCloudConnectorsHandlers(deps) {
66508
+ function requireLogin() {
66509
+ const rec5 = deps.readIdentity();
66510
+ if (!rec5) throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "FEISHU_LOGIN_REQUIRED: \u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u4E91\u4E0A persona \u7684\u8FDE\u63A5\u5668\u7528\u4E0D\u4E86");
66511
+ return rec5;
66512
+ }
66513
+ async function personalConnectors(personaId2) {
66514
+ const persona = deps.getPersona(personaId2);
66515
+ if (!persona) throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${personaId2}\uFF09`);
66516
+ if (!persona.cloud) throw invalid2(`${personaId2} \u4E0D\u662F\u4E91\u4E0A persona\uFF0C\u6CA1\u6709\u8FDE\u63A5\u5668\u533A`);
66517
+ const all = await deps.gatewayConnectors(persona.cloud.personaId);
66518
+ return { gatewayPersonaId: persona.cloud.personaId, connectors: all.filter((c) => c.credentialSource === "personal") };
66519
+ }
66520
+ const list = async (frame, _client, ctx) => {
66521
+ ensureOwner5(ctx);
66522
+ const { personaId: personaId2 } = parseArgs2(CloudConnectorsListArgsSchema, frame, "cloud:connectors:list");
66523
+ const { gatewayPersonaId, connectors } = await personalConnectors(personaId2);
66524
+ if (connectors.length === 0) return { response: { type: "cloud:connectors:list:ok", connectors: [] } };
66525
+ const login = requireLogin();
66526
+ const r = await deps.central.mine({ ...login, personaId: gatewayPersonaId, connectors });
66527
+ const parsed = CloudConnectorsListResultSchema.safeParse(r);
66528
+ if (!parsed.success) throw new ClawdError(ERROR_CODES.INTERNAL, `\u4E2D\u5FC3\u56DE\u7684\u8FDE\u63A5\u5668\u72B6\u6001\u4E0D\u5408\u5F62\u72B6\uFF1A${parsed.error.issues[0]?.message ?? ""}`);
66529
+ return { response: { type: "cloud:connectors:list:ok", connectors: parsed.data.connectors } };
66530
+ };
66531
+ const fill = async (frame, _client, ctx) => {
66532
+ ensureOwner5(ctx);
66533
+ const args = parseArgs2(CloudConnectorFillArgsSchema, frame, "cloud:connectors:fill");
66534
+ const { connectors } = await personalConnectors(args.personaId);
66535
+ const connector = connectors.find((c) => c.name === args.name);
66536
+ if (!connector) throw invalid2(`\u8FD9\u4E2A persona \u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u3001\u8981\u672C\u4EBA\u586B\u5199\u7684\u8FDE\u63A5\u5668`);
66537
+ const login = requireLogin();
66538
+ await deps.central.fill({ ...login, connector, values: args.values });
66539
+ return { response: { type: "cloud:connectors:fill:ok" } };
66540
+ };
66541
+ return {
66542
+ "cloud:connectors:list": list,
66543
+ "cloud:connectors:fill": fill
66544
+ };
66545
+ }
66546
+
66194
66547
  // src/handlers/meta.ts
66195
66548
  var import_node_os22 = __toESM(require("os"), 1);
66196
66549
  init_protocol();
@@ -66247,6 +66600,10 @@ var METHOD_GRANT_MAP = {
66247
66600
  "deploy:finishScan": ADMIN_ANY,
66248
66601
  "deploy:release": ADMIN_ANY,
66249
66602
  "deploy:rerunJob": ADMIN_ANY,
66603
+ // cloud:connectors:*(云 persona 卡片上的连接器;design 2026-09-11-mcp-connector):
66604
+ // 拿本机登录凭证向中心代查 / 代填使用者本人的凭据,guest 一律够不着
66605
+ "cloud:connectors:list": ADMIN_ANY,
66606
+ "cloud:connectors:fill": ADMIN_ANY,
66250
66607
  // ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
66251
66608
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
66252
66609
  // owner 自动通过(ctx 自带 '*':'admin' grant 一切 match);guest 在被授权 persona 内可调。
@@ -66508,21 +66865,21 @@ function computeMethodAccess(args) {
66508
66865
  }
66509
66866
 
66510
66867
  // src/version.ts
66511
- var version = "0.2.502".length > 0 ? "0.2.502" : "dev";
66868
+ var version = "0.2.504".length > 0 ? "0.2.504" : "dev";
66512
66869
 
66513
66870
  // src/cli-probe/probe.ts
66514
- var fs76 = __toESM(require("fs"), 1);
66515
- var path83 = __toESM(require("path"), 1);
66871
+ var fs77 = __toESM(require("fs"), 1);
66872
+ var path84 = __toESM(require("path"), 1);
66516
66873
  var PKG_NAME = "@clawos-dev/clawd";
66517
66874
  var BIN_NAME = "clawd";
66518
66875
  var MAX_PARENT_HOPS = 5;
66519
66876
  function probeGlobalCli(pathEnv) {
66520
66877
  if (!pathEnv) return null;
66521
- for (const dir of pathEnv.split(path83.delimiter)) {
66878
+ for (const dir of pathEnv.split(path84.delimiter)) {
66522
66879
  if (!dir) continue;
66523
66880
  let real;
66524
66881
  try {
66525
- real = fs76.realpathSync(path83.join(dir, BIN_NAME));
66882
+ real = fs77.realpathSync(path84.join(dir, BIN_NAME));
66526
66883
  } catch {
66527
66884
  continue;
66528
66885
  }
@@ -66532,15 +66889,15 @@ function probeGlobalCli(pathEnv) {
66532
66889
  return null;
66533
66890
  }
66534
66891
  function readOwnPackageVersion(entryPath) {
66535
- let dir = path83.dirname(entryPath);
66892
+ let dir = path84.dirname(entryPath);
66536
66893
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
66537
66894
  try {
66538
- const raw = fs76.readFileSync(path83.join(dir, "package.json"), "utf8");
66895
+ const raw = fs77.readFileSync(path84.join(dir, "package.json"), "utf8");
66539
66896
  const pkg = JSON.parse(raw);
66540
66897
  if (pkg.name !== PKG_NAME) return null;
66541
66898
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
66542
66899
  } catch {
66543
- const parent = path83.dirname(dir);
66900
+ const parent = path84.dirname(dir);
66544
66901
  if (parent === dir) return null;
66545
66902
  dir = parent;
66546
66903
  }
@@ -66716,7 +67073,7 @@ function buildPersonaHandlers(deps) {
66716
67073
  }
66717
67074
 
66718
67075
  // src/handlers/attachment.ts
66719
- var import_node_path65 = __toESM(require("path"), 1);
67076
+ var import_node_path66 = __toESM(require("path"), 1);
66720
67077
  init_protocol();
66721
67078
  init_protocol();
66722
67079
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -66796,12 +67153,12 @@ function buildAttachmentHandlers(deps) {
66796
67153
  `session ${args.sessionId} scope unresolved`
66797
67154
  );
66798
67155
  }
66799
- const cwdAbs = import_node_path65.default.resolve(sessionFile.cwd);
66800
- const candidateAbs = import_node_path65.default.isAbsolute(args.relPath) ? import_node_path65.default.resolve(args.relPath) : import_node_path65.default.resolve(cwdAbs, args.relPath);
67156
+ const cwdAbs = import_node_path66.default.resolve(sessionFile.cwd);
67157
+ const candidateAbs = import_node_path66.default.isAbsolute(args.relPath) ? import_node_path66.default.resolve(args.relPath) : import_node_path66.default.resolve(cwdAbs, args.relPath);
66801
67158
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
66802
67159
  const entries = deps.groupFileStore.list(scope, args.sessionId);
66803
67160
  const entry = entries.find((e) => {
66804
- const storedAbs = import_node_path65.default.isAbsolute(e.relPath) ? import_node_path65.default.resolve(e.relPath) : import_node_path65.default.resolve(cwdAbs, e.relPath);
67161
+ const storedAbs = import_node_path66.default.isAbsolute(e.relPath) ? import_node_path66.default.resolve(e.relPath) : import_node_path66.default.resolve(cwdAbs, e.relPath);
66805
67162
  return storedAbs === candidateAbs && !e.stale;
66806
67163
  });
66807
67164
  if (!entry) {
@@ -66826,7 +67183,7 @@ function buildAttachmentHandlers(deps) {
66826
67183
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
66827
67184
  const f = deps.sessionStore.read(sessionId);
66828
67185
  if (!f) return;
66829
- assertGuestAttachmentPath(ctx, import_node_path65.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
67186
+ assertGuestAttachmentPath(ctx, import_node_path66.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
66830
67187
  }
66831
67188
  const groupAdd = async (frame, _client, ctx) => {
66832
67189
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -66841,8 +67198,8 @@ function buildAttachmentHandlers(deps) {
66841
67198
  if (!scope) {
66842
67199
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
66843
67200
  }
66844
- const cwdAbs = import_node_path65.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
66845
- const candidateAbs = import_node_path65.default.isAbsolute(args.relPath) ? import_node_path65.default.resolve(args.relPath) : import_node_path65.default.resolve(cwdAbs, args.relPath);
67201
+ const cwdAbs = import_node_path66.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
67202
+ const candidateAbs = import_node_path66.default.isAbsolute(args.relPath) ? import_node_path66.default.resolve(args.relPath) : import_node_path66.default.resolve(cwdAbs, args.relPath);
66846
67203
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
66847
67204
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
66848
67205
  const size = 0;
@@ -66901,19 +67258,19 @@ function buildAttachmentHandlers(deps) {
66901
67258
 
66902
67259
  // src/handlers/extension.ts
66903
67260
  var import_promises14 = __toESM(require("fs/promises"), 1);
66904
- var import_node_path70 = __toESM(require("path"), 1);
67261
+ var import_node_path71 = __toESM(require("path"), 1);
66905
67262
  init_protocol();
66906
67263
 
66907
67264
  // src/extension/bundle-zip.ts
66908
67265
  var import_promises11 = __toESM(require("fs/promises"), 1);
66909
- var import_node_path66 = __toESM(require("path"), 1);
67266
+ var import_node_path67 = __toESM(require("path"), 1);
66910
67267
  var import_node_crypto18 = __toESM(require("crypto"), 1);
66911
67268
  var import_jszip2 = __toESM(require_lib3(), 1);
66912
67269
  async function bundleExtensionDir(dir) {
66913
67270
  const entries = await listFilesSorted(dir);
66914
67271
  const zip = new import_jszip2.default();
66915
67272
  for (const rel of entries) {
66916
- const abs = import_node_path66.default.join(dir, rel);
67273
+ const abs = import_node_path67.default.join(dir, rel);
66917
67274
  const content = await import_promises11.default.readFile(abs);
66918
67275
  zip.file(rel, content, { date: FIXED_DATE });
66919
67276
  }
@@ -66934,7 +67291,7 @@ async function listFilesSorted(rootDir) {
66934
67291
  return out;
66935
67292
  }
66936
67293
  async function walk(absRoot, relPrefix, out) {
66937
- const dirAbs = import_node_path66.default.join(absRoot, relPrefix);
67294
+ const dirAbs = import_node_path67.default.join(absRoot, relPrefix);
66938
67295
  const entries = await import_promises11.default.readdir(dirAbs, { withFileTypes: true });
66939
67296
  for (const e of entries) {
66940
67297
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -66988,25 +67345,25 @@ function computePublishCheck(args) {
66988
67345
 
66989
67346
  // src/extension/install-flow.ts
66990
67347
  var import_promises12 = __toESM(require("fs/promises"), 1);
66991
- var import_node_path68 = __toESM(require("path"), 1);
67348
+ var import_node_path69 = __toESM(require("path"), 1);
66992
67349
  var import_node_os24 = __toESM(require("os"), 1);
66993
67350
  var import_node_crypto19 = __toESM(require("crypto"), 1);
66994
67351
  var import_jszip3 = __toESM(require_lib3(), 1);
66995
67352
 
66996
67353
  // src/extension/paths.ts
66997
67354
  var import_node_os23 = __toESM(require("os"), 1);
66998
- var import_node_path67 = __toESM(require("path"), 1);
67355
+ var import_node_path68 = __toESM(require("path"), 1);
66999
67356
  function clawdHomeRoot(override) {
67000
- return override ?? process.env.CLAWD_HOME ?? import_node_path67.default.join(import_node_os23.default.homedir(), ".clawd");
67357
+ return override ?? process.env.CLAWD_HOME ?? import_node_path68.default.join(import_node_os23.default.homedir(), ".clawd");
67001
67358
  }
67002
67359
  function extensionsRoot(override) {
67003
- return import_node_path67.default.join(clawdHomeRoot(override), "extensions");
67360
+ return import_node_path68.default.join(clawdHomeRoot(override), "extensions");
67004
67361
  }
67005
67362
  function publishedChannelsFile(override) {
67006
- return import_node_path67.default.join(clawdHomeRoot(override), "extensions-published.json");
67363
+ return import_node_path68.default.join(clawdHomeRoot(override), "extensions-published.json");
67007
67364
  }
67008
67365
  function bundleCacheRoot(override) {
67009
- return import_node_path67.default.join(clawdHomeRoot(override), "extension-bundles");
67366
+ return import_node_path68.default.join(clawdHomeRoot(override), "extension-bundles");
67010
67367
  }
67011
67368
 
67012
67369
  // src/extension/install-flow.ts
@@ -67033,7 +67390,7 @@ async function installFromChannel(args, deps) {
67033
67390
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
67034
67391
  }
67035
67392
  for (const name of Object.keys(zip.files)) {
67036
- if (name.includes("..") || name.startsWith("/") || import_node_path68.default.isAbsolute(name)) {
67393
+ if (name.includes("..") || name.startsWith("/") || import_node_path69.default.isAbsolute(name)) {
67037
67394
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
67038
67395
  }
67039
67396
  }
@@ -67065,7 +67422,7 @@ async function installFromChannel(args, deps) {
67065
67422
  );
67066
67423
  }
67067
67424
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
67068
- const destDir = import_node_path68.default.join(deps.extensionsRoot, localExtId);
67425
+ const destDir = import_node_path69.default.join(deps.extensionsRoot, localExtId);
67069
67426
  let destExists = false;
67070
67427
  try {
67071
67428
  await import_promises12.default.access(destDir);
@@ -67079,16 +67436,16 @@ async function installFromChannel(args, deps) {
67079
67436
  );
67080
67437
  }
67081
67438
  const stage = await import_promises12.default.mkdtemp(
67082
- import_node_path68.default.join(import_node_os24.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
67439
+ import_node_path69.default.join(import_node_os24.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
67083
67440
  );
67084
67441
  try {
67085
67442
  for (const [name, entry] of Object.entries(zip.files)) {
67086
- const dest = import_node_path68.default.join(stage, name);
67443
+ const dest = import_node_path69.default.join(stage, name);
67087
67444
  if (entry.dir) {
67088
67445
  await import_promises12.default.mkdir(dest, { recursive: true });
67089
67446
  continue;
67090
67447
  }
67091
- await import_promises12.default.mkdir(import_node_path68.default.dirname(dest), { recursive: true });
67448
+ await import_promises12.default.mkdir(import_node_path69.default.dirname(dest), { recursive: true });
67092
67449
  if (name === "manifest.json") {
67093
67450
  const rewritten = { ...parsed.data, id: localExtId };
67094
67451
  await import_promises12.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -67109,7 +67466,7 @@ async function installFromChannel(args, deps) {
67109
67466
 
67110
67467
  // src/extension/update-flow.ts
67111
67468
  var import_promises13 = __toESM(require("fs/promises"), 1);
67112
- var import_node_path69 = __toESM(require("path"), 1);
67469
+ var import_node_path70 = __toESM(require("path"), 1);
67113
67470
  var import_node_os25 = __toESM(require("os"), 1);
67114
67471
  var import_node_crypto20 = __toESM(require("crypto"), 1);
67115
67472
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -67126,11 +67483,11 @@ async function updateFromChannel(args, deps) {
67126
67483
  channelRef.extId,
67127
67484
  channelRef.ownerPrincipalId
67128
67485
  );
67129
- const liveDir = import_node_path69.default.join(deps.extensionsRoot, localExtId);
67486
+ const liveDir = import_node_path70.default.join(deps.extensionsRoot, localExtId);
67130
67487
  const prevDir = `${liveDir}.prev`;
67131
67488
  let existingVersion;
67132
67489
  try {
67133
- const raw = await import_promises13.default.readFile(import_node_path69.default.join(liveDir, "manifest.json"), "utf8");
67490
+ const raw = await import_promises13.default.readFile(import_node_path70.default.join(liveDir, "manifest.json"), "utf8");
67134
67491
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
67135
67492
  if (!parsed2.success) {
67136
67493
  throw new UpdateError(
@@ -67163,7 +67520,7 @@ async function updateFromChannel(args, deps) {
67163
67520
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
67164
67521
  }
67165
67522
  for (const name of Object.keys(zip.files)) {
67166
- if (name.includes("..") || name.startsWith("/") || import_node_path69.default.isAbsolute(name)) {
67523
+ if (name.includes("..") || name.startsWith("/") || import_node_path70.default.isAbsolute(name)) {
67167
67524
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
67168
67525
  }
67169
67526
  }
@@ -67198,16 +67555,16 @@ async function updateFromChannel(args, deps) {
67198
67555
  await import_promises13.default.rm(prevDir, { recursive: true, force: true });
67199
67556
  await import_promises13.default.rename(liveDir, prevDir);
67200
67557
  const stage = await import_promises13.default.mkdtemp(
67201
- import_node_path69.default.join(import_node_os25.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
67558
+ import_node_path70.default.join(import_node_os25.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
67202
67559
  );
67203
67560
  try {
67204
67561
  for (const [name, entry] of Object.entries(zip.files)) {
67205
- const dest = import_node_path69.default.join(stage, name);
67562
+ const dest = import_node_path70.default.join(stage, name);
67206
67563
  if (entry.dir) {
67207
67564
  await import_promises13.default.mkdir(dest, { recursive: true });
67208
67565
  continue;
67209
67566
  }
67210
- await import_promises13.default.mkdir(import_node_path69.default.dirname(dest), { recursive: true });
67567
+ await import_promises13.default.mkdir(import_node_path70.default.dirname(dest), { recursive: true });
67211
67568
  if (name === "manifest.json") {
67212
67569
  const rewritten = { ...parsed.data, id: localExtId };
67213
67570
  await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -67274,7 +67631,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
67274
67631
  );
67275
67632
  }
67276
67633
  }
67277
- const manifestPath = import_node_path70.default.join(root, extId, "manifest.json");
67634
+ const manifestPath = import_node_path71.default.join(root, extId, "manifest.json");
67278
67635
  const manifest = await readManifest(root, extId);
67279
67636
  const next = { ...manifest, version: newVersion };
67280
67637
  const tmp = `${manifestPath}.tmp`;
@@ -67282,7 +67639,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
67282
67639
  await import_promises14.default.rename(tmp, manifestPath);
67283
67640
  }
67284
67641
  async function readManifest(root, extId) {
67285
- const file = import_node_path70.default.join(root, extId, "manifest.json");
67642
+ const file = import_node_path71.default.join(root, extId, "manifest.json");
67286
67643
  let raw;
67287
67644
  try {
67288
67645
  raw = await import_promises14.default.readFile(file, "utf8");
@@ -67366,7 +67723,7 @@ function buildExtensionHandlers(deps) {
67366
67723
  };
67367
67724
  async function buildSnapshotMeta(extId) {
67368
67725
  const manifest = await readManifest(deps.root, extId);
67369
- const { sha256, buffer } = await bundleExtensionDir(import_node_path70.default.join(deps.root, extId));
67726
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path71.default.join(deps.root, extId));
67370
67727
  return { manifest, contentHash: sha256, buffer };
67371
67728
  }
67372
67729
  const publish = async (frame, _client, ctx) => {
@@ -67609,8 +67966,8 @@ var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
67609
67966
 
67610
67967
  // src/handlers/app-builder.ts
67611
67968
  init_protocol();
67612
- var import_node_path71 = require("path");
67613
- var import_node_fs58 = require("fs");
67969
+ var import_node_path72 = require("path");
67970
+ var import_node_fs59 = require("fs");
67614
67971
  var DEFAULT_TEMPLATE = "nestjs-react";
67615
67972
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
67616
67973
  function buildAppBuilderHandlers(deps) {
@@ -67683,7 +68040,7 @@ function buildAppBuilderHandlers(deps) {
67683
68040
  async function listAllUsersProjects() {
67684
68041
  if (!deps.usersRoot || !deps.getStore) return [];
67685
68042
  const getStore = deps.getStore;
67686
- const userIds = await import_node_fs58.promises.readdir(deps.usersRoot).catch(() => []);
68043
+ const userIds = await import_node_fs59.promises.readdir(deps.usersRoot).catch(() => []);
67687
68044
  const perUser = await Promise.all(
67688
68045
  userIds.map((uid) => getStore(uid).list().catch(() => []))
67689
68046
  );
@@ -67756,13 +68113,13 @@ function buildAppBuilderHandlers(deps) {
67756
68113
  const created = await deps.createProjectOnDisk({
67757
68114
  store: userStore,
67758
68115
  name: f.name,
67759
- templateSrcDir: (0, import_node_path71.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
67760
- scaffoldScript: (0, import_node_path71.join)(deps.deployKitRoot, "scripts", "new-extension.sh"),
68116
+ templateSrcDir: (0, import_node_path72.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
68117
+ scaffoldScript: (0, import_node_path72.join)(deps.deployKitRoot, "scripts", "new-extension.sh"),
67761
68118
  reservedPorts,
67762
68119
  // 凭据只进 scaffold 子进程的 env,且**只给这个 persona 的 kit 模板声明要的那几个变量**
67763
68120
  // (M1b Step 5)。整表塞进去粒度只到「进程」——那会把 service-role key 交给一个用不到
67764
68121
  // 它的脚本。new-extension.sh 用它把模板的 `${VAR}` 渲成项目可跑的 server/.env。
67765
- extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path71.join)(personaRoot, "extension-kit")),
68122
+ extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path72.join)(personaRoot, "extension-kit")),
67766
68123
  ...deps.logger ? { logger: deps.logger } : {}
67767
68124
  });
67768
68125
  project = created.project;
@@ -67961,7 +68318,7 @@ function buildAppBuilderHandlers(deps) {
67961
68318
  await userStore.clearPublishJob(args.name);
67962
68319
  }
67963
68320
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
67964
- const scriptPath = (0, import_node_path71.join)(deps.deployKitRoot, "scripts", "publish.sh");
68321
+ const scriptPath = (0, import_node_path72.join)(deps.deployKitRoot, "scripts", "publish.sh");
67965
68322
  deps.logger?.info("app-builder.publish.start", {
67966
68323
  name: args.name,
67967
68324
  sessionId: boundSession.sessionId,
@@ -67977,7 +68334,7 @@ function buildAppBuilderHandlers(deps) {
67977
68334
  // 凭据只进 publish.sh 这个子进程的 env,且只给它的 kit 模板声明要的那几个变量
67978
68335
  // (M1b Step 5)。那个进程里跑着 `eval "$BUILD_CMD"`——项目自带的构建命令会继承这份
67979
68336
  // env,多给一个变量就是多交一个凭据给它。personaRoot 上面已按绑定 session 的 persona 解析。
67980
- extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path71.join)(personaRoot, "extension-kit")),
68337
+ extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path72.join)(personaRoot, "extension-kit")),
67981
68338
  hooks: {
67982
68339
  // 元数据每次写盘(publishJob 起落 / prodUrl 回填)后重推一帧:UI 渲染 PublishProgress
67983
68340
  // 三段 checklist 依赖 project.publishJob.status==='in-flight',而 publishJob 字段只有
@@ -68688,7 +69045,7 @@ function buildGithubHandlers(deps) {
68688
69045
 
68689
69046
  // src/handlers/visitor.ts
68690
69047
  init_protocol();
68691
- function ensureOwner5(ctx) {
69048
+ function ensureOwner6(ctx) {
68692
69049
  if (!ctx || ctx.principal.kind !== "owner") {
68693
69050
  throw new ClawdError(
68694
69051
  ERROR_CODES.UNAUTHORIZED,
@@ -68698,7 +69055,7 @@ function ensureOwner5(ctx) {
68698
69055
  }
68699
69056
  function buildVisitorHandlers(deps) {
68700
69057
  const list = async (_frame, _client, ctx) => {
68701
- ensureOwner5(ctx);
69058
+ ensureOwner6(ctx);
68702
69059
  return {
68703
69060
  response: {
68704
69061
  type: "visitor:list",
@@ -68713,7 +69070,7 @@ function buildVisitorHandlers(deps) {
68713
69070
 
68714
69071
  // src/extension/registry.ts
68715
69072
  var import_promises16 = __toESM(require("fs/promises"), 1);
68716
- var import_node_path72 = __toESM(require("path"), 1);
69073
+ var import_node_path73 = __toESM(require("path"), 1);
68717
69074
  async function loadAll(root) {
68718
69075
  let entries;
68719
69076
  try {
@@ -68726,13 +69083,13 @@ async function loadAll(root) {
68726
69083
  for (const ent of entries) {
68727
69084
  if (!ent.isDirectory()) continue;
68728
69085
  if (ent.name.startsWith(".")) continue;
68729
- records.push(await loadOne(import_node_path72.default.join(root, ent.name), ent.name));
69086
+ records.push(await loadOne(import_node_path73.default.join(root, ent.name), ent.name));
68730
69087
  }
68731
69088
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
68732
69089
  return records;
68733
69090
  }
68734
69091
  async function loadOne(dir, dirName) {
68735
- const manifestPath = import_node_path72.default.join(dir, "manifest.json");
69092
+ const manifestPath = import_node_path73.default.join(dir, "manifest.json");
68736
69093
  let raw;
68737
69094
  try {
68738
69095
  raw = await import_promises16.default.readFile(manifestPath, "utf8");
@@ -68777,7 +69134,7 @@ async function loadOne(dir, dirName) {
68777
69134
 
68778
69135
  // src/extension/uninstall.ts
68779
69136
  var import_promises17 = __toESM(require("fs/promises"), 1);
68780
- var import_node_path73 = __toESM(require("path"), 1);
69137
+ var import_node_path74 = __toESM(require("path"), 1);
68781
69138
  var UninstallError = class extends Error {
68782
69139
  constructor(code, message) {
68783
69140
  super(message);
@@ -68786,7 +69143,7 @@ var UninstallError = class extends Error {
68786
69143
  code;
68787
69144
  };
68788
69145
  async function uninstall(deps) {
68789
- const dir = import_node_path73.default.join(deps.root, deps.extId);
69146
+ const dir = import_node_path74.default.join(deps.root, deps.extId);
68790
69147
  try {
68791
69148
  await import_promises17.default.access(dir);
68792
69149
  } catch {
@@ -68985,6 +69342,7 @@ function buildMethodHandlers(deps) {
68985
69342
  }),
68986
69343
  ...buildFeishuAuthHandlers(deps.feishuAuth),
68987
69344
  ...buildDeviceHandlers(deps.feishuDevice),
69345
+ ...buildCloudConnectorsHandlers(deps.cloudConnectors),
68988
69346
  ...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {},
68989
69347
  ...buildExtensionHandlers({
68990
69348
  loadAll,
@@ -69023,7 +69381,7 @@ function buildMethodHandlers(deps) {
69023
69381
  broadcast: deps.broadcastToOwners
69024
69382
  }),
69025
69383
  ...buildMasterHandlers({
69026
- authorityTablePath: import_node_path74.default.join(deps.masterDataDir, "master-authority.json")
69384
+ authorityTablePath: import_node_path75.default.join(deps.masterDataDir, "master-authority.json")
69027
69385
  }),
69028
69386
  ...buildTopicHandlers({
69029
69387
  topicStore: deps.topicStore,
@@ -69070,8 +69428,8 @@ function refreshPathFromLoginShell() {
69070
69428
  timeout: 3e3,
69071
69429
  stdio: ["ignore", "pipe", "ignore"]
69072
69430
  });
69073
- const path100 = out.trim();
69074
- if (path100) process.env.PATH = path100;
69431
+ const path101 = out.trim();
69432
+ if (path101) process.env.PATH = path101;
69075
69433
  } catch {
69076
69434
  }
69077
69435
  }
@@ -69195,9 +69553,9 @@ function buildOnboardingHandlers(deps) {
69195
69553
  }
69196
69554
 
69197
69555
  // src/app-builder-plugin/project-store.ts
69198
- var import_node_fs59 = require("fs");
69556
+ var import_node_fs60 = require("fs");
69199
69557
  var import_node_child_process22 = require("child_process");
69200
- var import_node_path75 = require("path");
69558
+ var import_node_path76 = require("path");
69201
69559
  init_protocol();
69202
69560
  var PROJECTS_DIR = "projects";
69203
69561
  var META_FILE = ".clawd-project.json";
@@ -69227,19 +69585,19 @@ var ProjectStore = class {
69227
69585
  }
69228
69586
  /** projects/<name>/.clawd-project.json 路径 */
69229
69587
  metaPath(name) {
69230
- return (0, import_node_path75.join)(this.projectsRoot(), name, META_FILE);
69588
+ return (0, import_node_path76.join)(this.projectsRoot(), name, META_FILE);
69231
69589
  }
69232
69590
  /** projects/<name>/ 目录路径(cwd 用) */
69233
69591
  projectDir(name) {
69234
- return (0, import_node_path75.join)(this.projectsRoot(), name);
69592
+ return (0, import_node_path76.join)(this.projectsRoot(), name);
69235
69593
  }
69236
69594
  projectsRoot() {
69237
- return (0, import_node_path75.join)(this.root, PROJECTS_DIR);
69595
+ return (0, import_node_path76.join)(this.root, PROJECTS_DIR);
69238
69596
  }
69239
69597
  async list() {
69240
69598
  let entries;
69241
69599
  try {
69242
- entries = await import_node_fs59.promises.readdir(this.projectsRoot());
69600
+ entries = await import_node_fs60.promises.readdir(this.projectsRoot());
69243
69601
  } catch (err) {
69244
69602
  if (err.code === "ENOENT") return [];
69245
69603
  throw err;
@@ -69247,7 +69605,7 @@ var ProjectStore = class {
69247
69605
  const out = [];
69248
69606
  for (const name of entries) {
69249
69607
  try {
69250
- const raw = await import_node_fs59.promises.readFile(this.metaPath(name), "utf8");
69608
+ const raw = await import_node_fs60.promises.readFile(this.metaPath(name), "utf8");
69251
69609
  const json = JSON.parse(raw);
69252
69610
  let migrated = false;
69253
69611
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -69258,7 +69616,7 @@ var ProjectStore = class {
69258
69616
  if (parsed.success) {
69259
69617
  out.push(parsed.data);
69260
69618
  if (migrated) {
69261
- void import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
69619
+ void import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
69262
69620
  });
69263
69621
  }
69264
69622
  }
@@ -69302,8 +69660,8 @@ var ProjectStore = class {
69302
69660
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
69303
69661
  }
69304
69662
  const dir = this.projectDir(name);
69305
- await import_node_fs59.promises.mkdir(dir, { recursive: true });
69306
- await import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
69663
+ await import_node_fs60.promises.mkdir(dir, { recursive: true });
69664
+ await import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
69307
69665
  return meta;
69308
69666
  }
69309
69667
  /**
@@ -69348,7 +69706,7 @@ var ProjectStore = class {
69348
69706
  }
69349
69707
  async delete(name) {
69350
69708
  const dir = this.projectDir(name);
69351
- await import_node_fs59.promises.rm(dir, { recursive: true, force: true });
69709
+ await import_node_fs60.promises.rm(dir, { recursive: true, force: true });
69352
69710
  }
69353
69711
  async updatePort(name, newPort) {
69354
69712
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -69365,7 +69723,7 @@ var ProjectStore = class {
69365
69723
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
69366
69724
  }
69367
69725
  const updated = { ...target, port: newPort };
69368
- await import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
69726
+ await import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
69369
69727
  return updated;
69370
69728
  });
69371
69729
  }
@@ -69384,7 +69742,7 @@ var ProjectStore = class {
69384
69742
  if (!validated.success) {
69385
69743
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
69386
69744
  }
69387
- await import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69745
+ await import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69388
69746
  return validated.data;
69389
69747
  });
69390
69748
  }
@@ -69407,7 +69765,7 @@ var ProjectStore = class {
69407
69765
  if (!validated.success) {
69408
69766
  throw new Error(`invalid publishJob: ${validated.error.message}`);
69409
69767
  }
69410
- await import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69768
+ await import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69411
69769
  return validated.data;
69412
69770
  });
69413
69771
  }
@@ -69424,7 +69782,7 @@ var ProjectStore = class {
69424
69782
  if (!validated.success) {
69425
69783
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
69426
69784
  }
69427
- await import_node_fs59.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69785
+ await import_node_fs60.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
69428
69786
  return validated.data;
69429
69787
  });
69430
69788
  }
@@ -69739,8 +70097,8 @@ var PublishJobRegistry = class {
69739
70097
 
69740
70098
  // src/app-builder-plugin/publish-job-runner.ts
69741
70099
  var import_node_child_process24 = require("child_process");
69742
- var import_node_fs60 = require("fs");
69743
- var import_node_path76 = require("path");
70100
+ var import_node_fs61 = require("fs");
70101
+ var import_node_path77 = require("path");
69744
70102
 
69745
70103
  // src/app-builder-plugin/publish-stage-parser.ts
69746
70104
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -69772,10 +70130,10 @@ async function startPublishJob(deps, args) {
69772
70130
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
69773
70131
  }
69774
70132
  const projDir = projectDir(args.name);
69775
- const logPath = (0, import_node_path76.join)(projDir, ".publish.log");
70133
+ const logPath = (0, import_node_path77.join)(projDir, ".publish.log");
69776
70134
  let logStream = null;
69777
70135
  try {
69778
- logStream = (0, import_node_fs60.createWriteStream)(logPath, { flags: "w" });
70136
+ logStream = (0, import_node_fs61.createWriteStream)(logPath, { flags: "w" });
69779
70137
  } catch {
69780
70138
  logStream = null;
69781
70139
  }
@@ -70118,10 +70476,10 @@ async function recoverInterruptedPublishJobs(store, logger) {
70118
70476
  }
70119
70477
 
70120
70478
  // src/app-builder-plugin/mcp-config.ts
70121
- var import_node_fs61 = __toESM(require("fs"), 1);
70122
- var import_node_path77 = __toESM(require("path"), 1);
70479
+ var import_node_fs62 = __toESM(require("fs"), 1);
70480
+ var import_node_path78 = __toESM(require("path"), 1);
70123
70481
  function appBuilderMcpConfigPath(dataDir) {
70124
- return import_node_path77.default.join(dataDir, "app-builder.mcp.json");
70482
+ return import_node_path78.default.join(dataDir, "app-builder.mcp.json");
70125
70483
  }
70126
70484
  function writeAppBuilderMcpConfig(args) {
70127
70485
  const cfgPath = appBuilderMcpConfigPath(args.dataDir);
@@ -70135,15 +70493,15 @@ function writeAppBuilderMcpConfig(args) {
70135
70493
  env: {
70136
70494
  CLAWD_DAEMON_TOKEN: args.daemonToken,
70137
70495
  CLAWD_DAEMON_URL: args.daemonUrl,
70138
- CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path77.default.join(args.deployKitScriptsDir, "new-extension.sh"),
70139
- CLAWD_APP_BUILDER_PUBLISH_SCRIPT: import_node_path77.default.join(args.deployKitScriptsDir, "publish.sh"),
70496
+ CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path78.default.join(args.deployKitScriptsDir, "new-extension.sh"),
70497
+ CLAWD_APP_BUILDER_PUBLISH_SCRIPT: import_node_path78.default.join(args.deployKitScriptsDir, "publish.sh"),
70140
70498
  ...args.logPath ? { CLAWD_APP_BUILDER_LOG: args.logPath } : {}
70141
70499
  }
70142
70500
  }
70143
70501
  }
70144
70502
  };
70145
- import_node_fs61.default.mkdirSync(args.dataDir, { recursive: true });
70146
- import_node_fs61.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), "utf8");
70503
+ import_node_fs62.default.mkdirSync(args.dataDir, { recursive: true });
70504
+ import_node_fs62.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), "utf8");
70147
70505
  return cfgPath;
70148
70506
  }
70149
70507
 
@@ -70190,7 +70548,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
70190
70548
 
70191
70549
  // src/extension/runtime.ts
70192
70550
  var import_node_child_process26 = require("child_process");
70193
- var import_node_path78 = __toESM(require("path"), 1);
70551
+ var import_node_path79 = __toESM(require("path"), 1);
70194
70552
  var import_promises18 = require("timers/promises");
70195
70553
 
70196
70554
  // src/extension/port-allocator.ts
@@ -70291,7 +70649,7 @@ var Runtime = class {
70291
70649
  /\$CLAWOS_EXT_PORT/g,
70292
70650
  String(port)
70293
70651
  );
70294
- const dir = import_node_path78.default.join(this.root, extId);
70652
+ const dir = import_node_path79.default.join(this.root, extId);
70295
70653
  const env = {
70296
70654
  ...process.env,
70297
70655
  CLAWOS_EXT_PORT: String(port),
@@ -70403,7 +70761,7 @@ ${handle.stderrTail}`
70403
70761
 
70404
70762
  // src/extension/published-channels.ts
70405
70763
  var import_promises19 = __toESM(require("fs/promises"), 1);
70406
- var import_node_path79 = __toESM(require("path"), 1);
70764
+ var import_node_path80 = __toESM(require("path"), 1);
70407
70765
  init_zod();
70408
70766
  var PublishedChannelsError = class extends Error {
70409
70767
  constructor(code, message) {
@@ -70502,7 +70860,7 @@ var PublishedChannelStore = class {
70502
70860
  )
70503
70861
  };
70504
70862
  const tmp = `${this.filePath}.tmp`;
70505
- await import_promises19.default.mkdir(import_node_path79.default.dirname(this.filePath), { recursive: true });
70863
+ await import_promises19.default.mkdir(import_node_path80.default.dirname(this.filePath), { recursive: true });
70506
70864
  await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
70507
70865
  await import_promises19.default.rename(tmp, this.filePath);
70508
70866
  }
@@ -70510,7 +70868,7 @@ var PublishedChannelStore = class {
70510
70868
 
70511
70869
  // src/extension/bundle-cache.ts
70512
70870
  var import_promises20 = __toESM(require("fs/promises"), 1);
70513
- var import_node_path80 = __toESM(require("path"), 1);
70871
+ var import_node_path81 = __toESM(require("path"), 1);
70514
70872
  var BundleCache = class {
70515
70873
  constructor(rootDir) {
70516
70874
  this.rootDir = rootDir;
@@ -70519,14 +70877,14 @@ var BundleCache = class {
70519
70877
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
70520
70878
  async write(snapshotHash, buffer) {
70521
70879
  await import_promises20.default.mkdir(this.rootDir, { recursive: true });
70522
- const file = import_node_path80.default.join(this.rootDir, `${snapshotHash}.zip`);
70880
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
70523
70881
  const tmp = `${file}.tmp`;
70524
70882
  await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
70525
70883
  await import_promises20.default.rename(tmp, file);
70526
70884
  }
70527
70885
  /** Returns the bundle bytes, or null when the file doesn't exist. */
70528
70886
  async read(snapshotHash) {
70529
- const file = import_node_path80.default.join(this.rootDir, `${snapshotHash}.zip`);
70887
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
70530
70888
  try {
70531
70889
  return await import_promises20.default.readFile(file);
70532
70890
  } catch (e) {
@@ -70536,7 +70894,7 @@ var BundleCache = class {
70536
70894
  }
70537
70895
  /** Idempotent — missing file is not an error. */
70538
70896
  async delete(snapshotHash) {
70539
- const file = import_node_path80.default.join(this.rootDir, `${snapshotHash}.zip`);
70897
+ const file = import_node_path81.default.join(this.rootDir, `${snapshotHash}.zip`);
70540
70898
  await import_promises20.default.rm(file, { force: true });
70541
70899
  }
70542
70900
  };
@@ -70559,24 +70917,24 @@ async function startDaemon(config) {
70559
70917
  sampling: logShippingCfg.sampling,
70560
70918
  homeDir: import_node_os28.default.homedir()
70561
70919
  });
70562
- const logDir = import_node_path81.default.join(config.dataDir, "log");
70563
- import_node_fs62.default.mkdirSync(logDir, { recursive: true });
70920
+ const logDir = import_node_path82.default.join(config.dataDir, "log");
70921
+ import_node_fs63.default.mkdirSync(logDir, { recursive: true });
70564
70922
  const logger = createLogger({
70565
70923
  level: config.logLevel,
70566
- file: import_node_path81.default.join(logDir, "clawd.log"),
70924
+ file: import_node_path82.default.join(logDir, "clawd.log"),
70567
70925
  logClient
70568
70926
  });
70569
70927
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
70570
70928
  const screenIdleProbeLogger = createFileOnlyLogger({
70571
- file: import_node_path81.default.join(logDir, "screen-idle-probe.log"),
70929
+ file: import_node_path82.default.join(logDir, "screen-idle-probe.log"),
70572
70930
  level: "debug"
70573
70931
  });
70574
70932
  logger.info("screen-idle probe logger enabled", {
70575
- file: import_node_path81.default.join(logDir, "screen-idle-probe.log")
70933
+ file: import_node_path82.default.join(logDir, "screen-idle-probe.log")
70576
70934
  });
70577
70935
  const CAP_TARGETS = [
70578
- import_node_path81.default.join(logDir, "clawd.log"),
70579
- import_node_path81.default.join(logDir, "screen-idle-probe.log")
70936
+ import_node_path82.default.join(logDir, "clawd.log"),
70937
+ import_node_path82.default.join(logDir, "screen-idle-probe.log")
70580
70938
  ];
70581
70939
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
70582
70940
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -70698,8 +71056,8 @@ async function startDaemon(config) {
70698
71056
  const agents = new AgentsScanner();
70699
71057
  const history = new ClaudeHistoryReader();
70700
71058
  let transport = null;
70701
- const personaStore = new PersonaStore(import_node_path81.default.join(config.dataDir, "personas"));
70702
- const usersRoot = import_node_path81.default.join(config.dataDir, "users");
71059
+ const personaStore = new PersonaStore(import_node_path82.default.join(config.dataDir, "personas"));
71060
+ const usersRoot = import_node_path82.default.join(config.dataDir, "users");
70703
71061
  const defaultsRoot = findDefaultsRoot(logger);
70704
71062
  if (defaultsRoot) {
70705
71063
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -70723,7 +71081,7 @@ async function startDaemon(config) {
70723
71081
  retirePersonaBuilder({ store: personaStore, logger });
70724
71082
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
70725
71083
  const dispatchStore = createDispatchStore({
70726
- filePath: import_node_path81.default.join(config.dataDir, "dispatch.json"),
71084
+ filePath: import_node_path82.default.join(config.dataDir, "dispatch.json"),
70727
71085
  now: () => Date.now(),
70728
71086
  onFlushError: (err) => logger.error("dispatch store flush failed", {
70729
71087
  reason: err instanceof Error ? err.message : String(err)
@@ -70732,7 +71090,7 @@ async function startDaemon(config) {
70732
71090
  await dispatchStore.load();
70733
71091
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
70734
71092
  const channelStore = createChannelStore({
70735
- filePath: import_node_path81.default.join(config.dataDir, "channels.json"),
71093
+ filePath: import_node_path82.default.join(config.dataDir, "channels.json"),
70736
71094
  now: () => Date.now(),
70737
71095
  genId: () => `ch-${(0, import_node_crypto23.randomUUID)().slice(0, 8)}`,
70738
71096
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -70741,7 +71099,7 @@ async function startDaemon(config) {
70741
71099
  });
70742
71100
  await channelStore.load();
70743
71101
  const topicStore = createTopicStore({
70744
- filePath: import_node_path81.default.join(config.dataDir, "topics.json"),
71102
+ filePath: import_node_path82.default.join(config.dataDir, "topics.json"),
70745
71103
  now: () => Date.now(),
70746
71104
  genId: () => `tp-${(0, import_node_crypto23.randomUUID)().slice(0, 8)}`,
70747
71105
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -70768,28 +71126,28 @@ async function startDaemon(config) {
70768
71126
  });
70769
71127
  }
70770
71128
  });
70771
- const here = typeof __dirname === "string" ? __dirname : import_node_path81.default.dirname((0, import_node_url5.fileURLToPath)(import_meta8.url));
71129
+ const here = typeof __dirname === "string" ? __dirname : import_node_path82.default.dirname((0, import_node_url5.fileURLToPath)(import_meta8.url));
70772
71130
  const mcpConfigs = [];
70773
71131
  const secretsBundleRoot = findSecretsBundleRoot(logger);
70774
- const localSecretsDir = import_node_path81.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
71132
+ const localSecretsDir = import_node_path82.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
70775
71133
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
70776
71134
  const resolvePersonaMcpConfig = (personaId2) => renderPersonaMcpSecrets({
70777
71135
  personaId: personaId2,
70778
- personaDir: import_node_path81.default.join(config.dataDir, "personas", personaId2),
71136
+ personaDir: import_node_path82.default.join(config.dataDir, "personas", personaId2),
70779
71137
  secrets: readSecrets(),
70780
- outDir: import_node_path81.default.join(config.dataDir, "persona-mcp"),
71138
+ outDir: import_node_path82.default.join(config.dataDir, "persona-mcp"),
70781
71139
  logger
70782
71140
  });
70783
71141
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
70784
71142
  const dispatchServerCandidates = [
70785
- import_node_path81.default.join(here, "dispatch", "mcp-server.cjs"),
71143
+ import_node_path82.default.join(here, "dispatch", "mcp-server.cjs"),
70786
71144
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
70787
- import_node_path81.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
71145
+ import_node_path82.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
70788
71146
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
70789
71147
  ];
70790
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71148
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70791
71149
  if (dispatchServerScriptPath) {
70792
- const dispatchLogPath = import_node_path81.default.join(logDir, "dispatch-mcp-server.log");
71150
+ const dispatchLogPath = import_node_path82.default.join(logDir, "dispatch-mcp-server.log");
70793
71151
  const dispatchCfgPath = writeDispatchMcpConfig({
70794
71152
  dataDir: config.dataDir,
70795
71153
  serverScriptPath: dispatchServerScriptPath,
@@ -70809,12 +71167,12 @@ async function startDaemon(config) {
70809
71167
  });
70810
71168
  }
70811
71169
  const ticketServerCandidates = [
70812
- import_node_path81.default.join(here, "ticket", "mcp-server.cjs"),
70813
- import_node_path81.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
71170
+ import_node_path82.default.join(here, "ticket", "mcp-server.cjs"),
71171
+ import_node_path82.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
70814
71172
  ];
70815
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71173
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70816
71174
  if (ticketServerScriptPath) {
70817
- const ticketLogPath = import_node_path81.default.join(logDir, "ticket-mcp-server.log");
71175
+ const ticketLogPath = import_node_path82.default.join(logDir, "ticket-mcp-server.log");
70818
71176
  const ticketCfgPath = writeTicketMcpConfig({
70819
71177
  dataDir: config.dataDir,
70820
71178
  serverScriptPath: ticketServerScriptPath,
@@ -70836,12 +71194,12 @@ async function startDaemon(config) {
70836
71194
  });
70837
71195
  }
70838
71196
  const shiftServerCandidates = [
70839
- import_node_path81.default.join(here, "shift", "mcp-server.cjs"),
70840
- import_node_path81.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
71197
+ import_node_path82.default.join(here, "shift", "mcp-server.cjs"),
71198
+ import_node_path82.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
70841
71199
  ];
70842
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71200
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70843
71201
  if (shiftServerScriptPath) {
70844
- const shiftLogPath = import_node_path81.default.join(logDir, "shift-mcp-server.log");
71202
+ const shiftLogPath = import_node_path82.default.join(logDir, "shift-mcp-server.log");
70845
71203
  const shiftCfgPath = await writeShiftMcpConfig({
70846
71204
  dataDir: config.dataDir,
70847
71205
  serverScriptPath: shiftServerScriptPath,
@@ -70862,12 +71220,12 @@ async function startDaemon(config) {
70862
71220
  );
70863
71221
  }
70864
71222
  const inboxServerCandidates = [
70865
- import_node_path81.default.join(here, "inbox", "mcp-server.cjs"),
70866
- import_node_path81.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
71223
+ import_node_path82.default.join(here, "inbox", "mcp-server.cjs"),
71224
+ import_node_path82.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
70867
71225
  ];
70868
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71226
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70869
71227
  if (inboxServerScriptPath) {
70870
- const inboxLogPath = import_node_path81.default.join(logDir, "inbox-mcp-server.log");
71228
+ const inboxLogPath = import_node_path82.default.join(logDir, "inbox-mcp-server.log");
70871
71229
  const inboxCfgPath = await writeInboxMcpConfig({
70872
71230
  dataDir: config.dataDir,
70873
71231
  serverScriptPath: inboxServerScriptPath,
@@ -70888,10 +71246,10 @@ async function startDaemon(config) {
70888
71246
  );
70889
71247
  }
70890
71248
  const peerOpsServerCandidates = [
70891
- import_node_path81.default.join(here, "peer-ops", "mcp-server.cjs"),
70892
- import_node_path81.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
71249
+ import_node_path82.default.join(here, "peer-ops", "mcp-server.cjs"),
71250
+ import_node_path82.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
70893
71251
  ];
70894
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71252
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70895
71253
  if (peerOpsServerScriptPath) {
70896
71254
  const peerOpsCfgPath = writePeerOpsMcpConfig({
70897
71255
  dataDir: config.dataDir,
@@ -70911,12 +71269,12 @@ async function startDaemon(config) {
70911
71269
  );
70912
71270
  }
70913
71271
  const rpcToolServerCandidates = [
70914
- import_node_path81.default.join(here, "rpc-tool", "mcp-server.cjs"),
70915
- import_node_path81.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
71272
+ import_node_path82.default.join(here, "rpc-tool", "mcp-server.cjs"),
71273
+ import_node_path82.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
70916
71274
  ];
70917
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71275
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70918
71276
  if (rpcToolServerScriptPath) {
70919
- const rpcToolLogPath = import_node_path81.default.join(logDir, "rpc-tool-mcp-server.log");
71277
+ const rpcToolLogPath = import_node_path82.default.join(logDir, "rpc-tool-mcp-server.log");
70920
71278
  const rpcToolCfgPath = writeRpcToolMcpConfig({
70921
71279
  dataDir: config.dataDir,
70922
71280
  serverScriptPath: rpcToolServerScriptPath,
@@ -70937,18 +71295,18 @@ async function startDaemon(config) {
70937
71295
  );
70938
71296
  }
70939
71297
  const appBuilderServerCandidates = [
70940
- import_node_path81.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
70941
- import_node_path81.default.join(here, "..", "dist", "app-builder-plugin", "mcp-server.cjs")
71298
+ import_node_path82.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
71299
+ import_node_path82.default.join(here, "..", "dist", "app-builder-plugin", "mcp-server.cjs")
70942
71300
  ];
70943
- const appBuilderServerScriptPath = appBuilderServerCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71301
+ const appBuilderServerScriptPath = appBuilderServerCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
70944
71302
  if (appBuilderServerScriptPath) {
70945
- const appBuilderLogPath = import_node_path81.default.join(logDir, "app-builder-mcp-server.log");
71303
+ const appBuilderLogPath = import_node_path82.default.join(logDir, "app-builder-mcp-server.log");
70946
71304
  const appBuilderCfgPath = writeAppBuilderMcpConfig({
70947
71305
  dataDir: config.dataDir,
70948
71306
  serverScriptPath: appBuilderServerScriptPath,
70949
71307
  daemonToken: resolvedAuthToken,
70950
71308
  daemonUrl: mcpDaemonUrl,
70951
- deployKitScriptsDir: import_node_path81.default.join(config.dataDir, "deploy-kit", "scripts"),
71309
+ deployKitScriptsDir: import_node_path82.default.join(config.dataDir, "deploy-kit", "scripts"),
70952
71310
  logPath: appBuilderLogPath
70953
71311
  });
70954
71312
  mcpConfigs.push({ id: "app-builder", path: appBuilderCfgPath, personas: APP_BUILDER_PERSONAS });
@@ -70964,7 +71322,7 @@ async function startDaemon(config) {
70964
71322
  );
70965
71323
  }
70966
71324
  const shiftStore = createShiftStore({
70967
- filePath: import_node_path81.default.join(config.dataDir, "shift.json"),
71325
+ filePath: import_node_path82.default.join(config.dataDir, "shift.json"),
70968
71326
  ownerIdProvider: () => ownerPrincipalId,
70969
71327
  now: () => Date.now()
70970
71328
  });
@@ -70986,7 +71344,7 @@ async function startDaemon(config) {
70986
71344
  getAdapter,
70987
71345
  historyReader: history,
70988
71346
  dataDir: config.dataDir,
70989
- personaRoot: import_node_path81.default.join(config.dataDir, "personas"),
71347
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
70990
71348
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
70991
71349
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
70992
71350
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -71043,10 +71401,10 @@ async function startDaemon(config) {
71043
71401
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
71044
71402
  attachmentGroup: {
71045
71403
  onFileEdit: (input) => {
71046
- const absPath = import_node_path81.default.isAbsolute(input.relPath) ? input.relPath : import_node_path81.default.join(input.cwd, input.relPath);
71404
+ const absPath = import_node_path82.default.isAbsolute(input.relPath) ? input.relPath : import_node_path82.default.join(input.cwd, input.relPath);
71047
71405
  let size = 0;
71048
71406
  try {
71049
- size = import_node_fs62.default.statSync(absPath).size;
71407
+ size = import_node_fs63.default.statSync(absPath).size;
71050
71408
  } catch (err) {
71051
71409
  logger.warn("attachment.onFileEdit stat failed", {
71052
71410
  sessionId: input.sessionId,
@@ -71087,9 +71445,9 @@ async function startDaemon(config) {
71087
71445
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
71088
71446
  }
71089
71447
  const projectsStore = new ProjectsStore({
71090
- file: import_node_path81.default.join(config.dataDir, "projects.json"),
71448
+ file: import_node_path82.default.join(config.dataDir, "projects.json"),
71091
71449
  clawdDir: config.dataDir,
71092
- codexStateFile: import_node_path81.default.join(import_node_os28.default.homedir(), ".codex", ".codex-global-state.json"),
71450
+ codexStateFile: import_node_path82.default.join(import_node_os28.default.homedir(), ".codex", ".codex-global-state.json"),
71093
71451
  logger
71094
71452
  });
71095
71453
  const observer = new SessionObserver({
@@ -71157,13 +71515,13 @@ async function startDaemon(config) {
71157
71515
  logger
71158
71516
  });
71159
71517
  registerAdapter("claude", claudeAdapter);
71160
- const codexIsolatedHome = import_node_path81.default.join(config.dataDir, "codex-home");
71518
+ const codexIsolatedHome = import_node_path82.default.join(config.dataDir, "codex-home");
71161
71519
  try {
71162
- import_node_fs62.default.mkdirSync(codexIsolatedHome, { recursive: true });
71520
+ import_node_fs63.default.mkdirSync(codexIsolatedHome, { recursive: true });
71163
71521
  for (const f of ["auth.json", "config.toml"]) {
71164
- const link = import_node_path81.default.join(codexIsolatedHome, f);
71165
- const target = import_node_path81.default.join(import_node_os28.default.homedir(), ".codex", f);
71166
- if (!import_node_fs62.default.existsSync(link) && import_node_fs62.default.existsSync(target)) import_node_fs62.default.symlinkSync(target, link);
71522
+ const link = import_node_path82.default.join(codexIsolatedHome, f);
71523
+ const target = import_node_path82.default.join(import_node_os28.default.homedir(), ".codex", f);
71524
+ if (!import_node_fs63.default.existsSync(link) && import_node_fs63.default.existsSync(target)) import_node_fs63.default.symlinkSync(target, link);
71167
71525
  }
71168
71526
  } catch (err) {
71169
71527
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -71174,17 +71532,17 @@ async function startDaemon(config) {
71174
71532
  logger,
71175
71533
  historyReader: new CodexHistoryReader({
71176
71534
  roots: codexRolloutRoots(config.dataDir),
71177
- sharedHome: import_node_path81.default.join(import_node_os28.default.homedir(), ".codex"),
71535
+ sharedHome: import_node_path82.default.join(import_node_os28.default.homedir(), ".codex"),
71178
71536
  logger
71179
71537
  }),
71180
71538
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
71181
71539
  codexHomeFor: (cwd) => resolveCodexHome({
71182
71540
  cwd,
71183
- personaRoot: import_node_path81.default.join(config.dataDir, "personas"),
71541
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
71184
71542
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
71185
71543
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
71186
71544
  projectPaths: projectsStore.listMerged().map((x) => x.path),
71187
- sharedHome: import_node_path81.default.join(import_node_os28.default.homedir(), ".codex"),
71545
+ sharedHome: import_node_path82.default.join(import_node_os28.default.homedir(), ".codex"),
71188
71546
  isolatedHome: codexIsolatedHome
71189
71547
  }),
71190
71548
  // 附件图片验签:与 http-router /files 路由同一把 secret
@@ -71193,10 +71551,10 @@ async function startDaemon(config) {
71193
71551
  );
71194
71552
  registerAdapter(CODEX_CLOUD_TOOL_ID, new CloudCodexAdapter({ client: cloudGateway, logger, getSignSecret: () => authFile.token }));
71195
71553
  const piMcpBridgeCandidates = [
71196
- import_node_path81.default.join(here, "pi-mcp-bridge", "extension.cjs"),
71197
- import_node_path81.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
71554
+ import_node_path82.default.join(here, "pi-mcp-bridge", "extension.cjs"),
71555
+ import_node_path82.default.join(here, "..", "dist", "pi-mcp-bridge", "extension.cjs")
71198
71556
  ];
71199
- const piMcpBridgePath = piMcpBridgeCandidates.find((p2) => import_node_fs62.default.existsSync(p2));
71557
+ const piMcpBridgePath = piMcpBridgeCandidates.find((p2) => import_node_fs63.default.existsSync(p2));
71200
71558
  if (piMcpBridgePath) {
71201
71559
  logger.info("pi-mcp-bridge extension resolved", { path: piMcpBridgePath });
71202
71560
  } else {
@@ -71507,11 +71865,11 @@ async function startDaemon(config) {
71507
71865
  // 'persona/<pid>/owner',default 走 'default'。
71508
71866
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
71509
71867
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
71510
- personaRoot: import_node_path81.default.join(config.dataDir, "personas"),
71868
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
71511
71869
  usersRoot
71512
71870
  },
71513
71871
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
71514
- personaRoot: import_node_path81.default.join(config.dataDir, "personas"),
71872
+ personaRoot: import_node_path82.default.join(config.dataDir, "personas"),
71515
71873
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
71516
71874
  usersRoot,
71517
71875
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -71590,6 +71948,20 @@ async function startDaemon(config) {
71590
71948
  issue: (args) => centralIssueApiKey({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
71591
71949
  }
71592
71950
  },
71951
+ // 云 persona 卡片上的连接器区(design 2026-09-11-mcp-connector §3.8):装了什么以 gateway 登记行为真源,
71952
+ // 连没连上问中心。登录凭证只在 daemon 内部传给中心,与 apiKeyClient 同一条纪律。
71953
+ cloudConnectors: {
71954
+ getPersona: (personaId2) => personaRegistry.get(personaId2),
71955
+ gatewayConnectors: (gatewayPersonaId) => cloudGateway.personaConnectors(gatewayPersonaId),
71956
+ readIdentity: () => {
71957
+ const r = ownerIdentityStore.read();
71958
+ return r ? { ttcJwt: r.ttcToken, provider: r.identity.provider } : null;
71959
+ },
71960
+ central: {
71961
+ mine: (args) => centralConnectorsMine({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args }),
71962
+ fill: (args) => centralConnectorFill({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
71963
+ }
71964
+ },
71593
71965
  // 设备目录 + 连接(决策 #15:daemon 代理中心 server)。
71594
71966
  // exchange/listDevices 包掉 owner ttcJwt(每次现读 store——热切换后立即用新身份);
71595
71967
  // dispatcher 的 FEISHU_GATED_METHODS gate 已保证未登录时这些 RPC 到不了 handler,
@@ -71618,11 +71990,11 @@ async function startDaemon(config) {
71618
71990
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
71619
71991
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
71620
71992
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
71621
- appBuilderPersonaRoot: import_node_path81.default.join(config.dataDir, "personas", "persona-app-builder"),
71993
+ appBuilderPersonaRoot: import_node_path82.default.join(config.dataDir, "personas", "persona-app-builder"),
71622
71994
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
71623
- deployKitRoot: import_node_path81.default.join(config.dataDir, "deploy-kit"),
71995
+ deployKitRoot: import_node_path82.default.join(config.dataDir, "deploy-kit"),
71624
71996
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
71625
- resolvePersonaRoot: (personaId2) => import_node_path81.default.join(config.dataDir, "personas", personaId2),
71997
+ resolvePersonaRoot: (personaId2) => import_node_path82.default.join(config.dataDir, "personas", personaId2),
71626
71998
  // 凭据表(M1b Step 5):与 MCP 那条同一张表、同一个来源,只是交付给另一个子进程。
71627
71999
  readSecrets,
71628
72000
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
@@ -71819,7 +72191,7 @@ async function startDaemon(config) {
71819
72191
  });
71820
72192
  shiftScheduler.start();
71821
72193
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
71822
- const larkBotStore = createLarkBotBindingStore(import_node_path81.default.join(config.dataDir, "personas"));
72194
+ const larkBotStore = createLarkBotBindingStore(import_node_path82.default.join(config.dataDir, "personas"));
71823
72195
  const larkBotCloud = createLarkBotCloudClient({
71824
72196
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
71825
72197
  apiKey: resolveClawdTicketsApiKey(),
@@ -71833,7 +72205,7 @@ async function startDaemon(config) {
71833
72205
  store: larkBotStore,
71834
72206
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
71835
72207
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
71836
- mediaRootFor: (chatId) => import_node_path81.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
72208
+ mediaRootFor: (chatId) => import_node_path82.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
71837
72209
  isShuttingDown: () => larkDraining,
71838
72210
  logger: {
71839
72211
  warn: (msg) => logger.warn(msg),
@@ -72140,8 +72512,8 @@ async function startDaemon(config) {
72140
72512
  const lines = [
72141
72513
  `Tunnel: ${r.url}`,
72142
72514
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
72143
- `Frpc config: ${import_node_path81.default.join(config.dataDir, "frpc.toml")}`,
72144
- `Frpc log: ${import_node_path81.default.join(logDir, "frpc.log")}`
72515
+ `Frpc config: ${import_node_path82.default.join(config.dataDir, "frpc.toml")}`,
72516
+ `Frpc log: ${import_node_path82.default.join(logDir, "frpc.log")}`
72145
72517
  ];
72146
72518
  const width2 = Math.max(...lines.map((l) => l.length));
72147
72519
  const bar = "\u2550".repeat(width2 + 4);
@@ -72154,8 +72526,8 @@ ${bar}
72154
72526
 
72155
72527
  `);
72156
72528
  try {
72157
- const connectPath = import_node_path81.default.join(config.dataDir, "connect.txt");
72158
- import_node_fs62.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
72529
+ const connectPath = import_node_path82.default.join(config.dataDir, "connect.txt");
72530
+ import_node_fs63.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
72159
72531
  } catch {
72160
72532
  }
72161
72533
  } catch (err) {
@@ -72242,9 +72614,9 @@ ${bar}
72242
72614
  };
72243
72615
  }
72244
72616
  function migrateDropPersonsDir(dataDir) {
72245
- const dir = import_node_path81.default.join(dataDir, "persons");
72617
+ const dir = import_node_path82.default.join(dataDir, "persons");
72246
72618
  try {
72247
- import_node_fs62.default.rmSync(dir, { recursive: true, force: true });
72619
+ import_node_fs63.default.rmSync(dir, { recursive: true, force: true });
72248
72620
  } catch {
72249
72621
  }
72250
72622
  }