@clawos-dev/clawd 0.2.459 → 0.2.461

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: path96, errorMaps, issueData } = params;
454
- const fullPath = [...path96, ...issueData.path || []];
453
+ const { data, path: path98, errorMaps, issueData } = params;
454
+ const fullPath = [...path98, ...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, path96, key) {
765
+ constructor(parent, value, path98, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path96;
769
+ this._path = path98;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -6022,7 +6022,7 @@ var init_environment_schemas = __esm({
6022
6022
  });
6023
6023
 
6024
6024
  // ../protocol/src/deploy-schemas.ts
6025
- var FulfillmentSchema, DeployStatusSchema, DeployGapSchema, DeployReceiptSchema, DeployStartArgsSchema, DeployIdArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, DeploySecretStatusSchema, DeployReceiptViewSchema, DeployListResultSchema;
6025
+ var FulfillmentSchema, DeployStatusSchema, TRIAL_ROUND_MAX, DeployGapSchema, DeployPlacementSchema, DeployReceiptSchema, DeployStartArgsSchema, DeployIdArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, DeploySecretStatusSchema, DeployReceiptViewSchema, DeployListResultSchema;
6026
6026
  var init_deploy_schemas = __esm({
6027
6027
  "../protocol/src/deploy-schemas.ts"() {
6028
6028
  "use strict";
@@ -6038,6 +6038,7 @@ var init_deploy_schemas = __esm({
6038
6038
  "failed",
6039
6039
  "deployed"
6040
6040
  ]);
6041
+ TRIAL_ROUND_MAX = 5;
6041
6042
  DeployGapSchema = external_exports.object({
6042
6043
  // agent 的自然语言错因,如「我要解析 aliyun 的 JSON 输出,但容器里没有 python3」
6043
6044
  errorText: external_exports.string().min(1),
@@ -6046,6 +6047,19 @@ var init_deploy_schemas = __esm({
6046
6047
  // 建议补的依赖:`cli:python3` 这种。拿不准就不给,让人自己决定。
6047
6048
  suggest: external_exports.string().optional()
6048
6049
  }).strict();
6050
+ DeployPlacementSchema = external_exports.object({
6051
+ /** gateway 的公网地址(入口 A 直接 POST 它;入口 B 由设备目录下发 ws 地址) */
6052
+ gatewayUrl: external_exports.string().min(1),
6053
+ /** 服务设备 id:别人的 clawd 用 `device:connect { deviceId }` 就能连上,本机侧零改动 */
6054
+ serviceDeviceId: external_exports.string().min(1),
6055
+ /** 这次登记为正式的镜像 tag(= 试装通过的那个) */
6056
+ image: external_exports.string().min(1),
6057
+ /** 使用者自带的凭据名字(= 单据里 fulfillment 选了 'user' 的那些)。**只有名字** */
6058
+ userSecrets: external_exports.array(external_exports.string()).default([]),
6059
+ /** 是否进公共设备目录。false = 只有拿到 deviceId 的人连得上 */
6060
+ publicDirectory: external_exports.boolean(),
6061
+ deployedAt: external_exports.number()
6062
+ }).strict();
6049
6063
  DeployReceiptSchema = external_exports.object({
6050
6064
  deployId: external_exports.string().min(1),
6051
6065
  personaId: external_exports.string().min(1),
@@ -6071,6 +6085,23 @@ var init_deploy_schemas = __esm({
6071
6085
  fulfillment: external_exports.record(external_exports.string(), FulfillmentSchema).default({}),
6072
6086
  /** 试装失败时的缺口清单;成功或没试装过是空数组 */
6073
6087
  gaps: external_exports.array(DeployGapSchema).default([]),
6088
+ /** 试装跑到第几轮了(每次 deploy:trial +1,上限 TRIAL_ROUND_MAX)。重扫清零 */
6089
+ trialRound: external_exports.number().default(0),
6090
+ /**
6091
+ * 试装当前在哪一步的一句人话(「在构镜像」「冒烟任务跑起来了」)。
6092
+ * 单据页要的是「到哪一步了」,不是逐 token 的过程——过程在 gateway 的任务台账里。
6093
+ */
6094
+ trialStage: external_exports.string().optional(),
6095
+ /**
6096
+ * 上一次试装通过的时刻。**deploy:deploy 的前置**——没试装过不让部署,那正是试装存在的理由。
6097
+ * 试装通过后单据回 `ready` 而不是直接 `deployed`:试装的产物是一个用完即弃的镜像,
6098
+ * 部署的产物是一个别人能派活的服务,中间那次决定得留给人。
6099
+ */
6100
+ trialPassedAt: external_exports.number().optional(),
6101
+ /** 试装通过的那个镜像 tag;deploy:deploy 登记的就是它,不重新构一遍 */
6102
+ trialImage: external_exports.string().optional(),
6103
+ /** 部署落点(status 是 deployed 才有) */
6104
+ placement: DeployPlacementSchema.optional(),
6074
6105
  // 扫描 / 试装失败的原因(status 是 scanFailed / failed 时才有意义)
6075
6106
  error: external_exports.string().optional(),
6076
6107
  createdAt: external_exports.number(),
@@ -6892,6 +6923,21 @@ var init_topic = __esm({
6892
6923
  TopicDecisionTypeSchema = external_exports.enum(TOPIC_DECISION_TYPES);
6893
6924
  TopicDecisionStatusSchema = external_exports.enum(TOPIC_DECISION_STATUSES);
6894
6925
  TopicDecisionSchema = external_exports.object({
6926
+ /**
6927
+ * 这条决策的标识,供后来的答复回指。可选:存量记录一条都没有,**不迁移**。
6928
+ *
6929
+ * 之所以要它——提问和答复是**两条**流水(`open` 一条、`resolved` 一条,见 `resolves`),
6930
+ * 两条之间没有任何关联时,展示层只能逐条渲染,于是**已经拍板完的待办永远挂在那儿**。
6931
+ */
6932
+ id: nonBlank2.optional(),
6933
+ /**
6934
+ * 本条解决的是哪条决策(填对方的 `id`)。展示层据此把提问与答复合并成一行。
6935
+ *
6936
+ * **只关联、不改写**:不去改动已落盘那条 `open` 记录的 status。原地改写会丢掉
6937
+ * 「什么时候提出 / 什么时候解决」的双时间戳,也丢掉「Master 建议了什么 vs
6938
+ * 老板最终定了什么」的差异——而老板事后要看的恰恰是这个差异。合并只发生在展示层。
6939
+ */
6940
+ resolves: nonBlank2.optional(),
6895
6941
  type: TopicDecisionTypeSchema,
6896
6942
  status: TopicDecisionStatusSchema,
6897
6943
  question: nonBlank2,
@@ -8863,6 +8909,14 @@ var init_methods = __esm({
8863
8909
  summary: "butler \u6536\u5C3E\uFF1A\u7ED9\u51FA\u5192\u70DF\u4EFB\u52A1\u4E0E\u5B58\u7591\u9879\uFF0C\u5355\u636E\u4ECE scanning \u8F6C draft\u3002\u6CA1\u8C03\u5230\u5B83\u5C31\u7B49\u4E8E\u6CA1\u626B\u5B8C\u2014\u2014butler \u4F1A\u8BDD\u7ED3\u675F\u65F6\u5355\u636E\u8FD8\u505C\u5728 scanning\uFF0Cdaemon \u636E\u6B64\u5224 scanFailed\uFF1Bowner-only",
8864
8910
  args: DeployFinishScanArgsSchema
8865
8911
  },
8912
+ "deploy:trial": {
8913
+ summary: "\u8D77\u4E00\u6B21\u8BD5\u88C5\uFF1A**\u4E00\u6B21\u5E26\u81EA\u6BC1\u7684\u771F\u90E8\u7F72**\u2014\u2014\u6309\u5355\u636E\u7684\u6E05\u5355\u6784\u955C\u50CF \u2192 \u63A8\u8FDB k3s \u2192 \u7ECF gateway \u6295\u5582\u5355\u636E\u4E0A\u90A3\u6761\u5192\u70DF\u4EFB\u52A1 \u2192 \u8BA9 persona \u7528\u81EA\u5DF1\u7684\u65B9\u5F0F\u5E72 \u2192 \u8DD1\u5B8C\u8BA9\u5B83\u628A\u5EFA\u51FA\u6765\u7684\u4E1C\u897F\u62C6\u6389\u3002\u524D\u7F6E\u662F `ready`\uFF08\u5C65\u7EA6\u90FD\u9009\u4E86\u3001\u9009\u4E86\u300C\u6211\u6765\u63D0\u4F9B\u300D\u7684\u51ED\u636E\u90FD\u586B\u9F50\u4E86\uFF09\uFF0C\u7F3A\u54EA\u6761\u4F1A\u5728\u9519\u8BEF\u91CC\u70B9\u540D\uFF1B\u8DD1\u51E0\u5341\u5206\u949F\uFF0C\u6240\u4EE5 RPC \u79D2\u56DE `trialing` \u6001\u5355\u636E\uFF0C\u7ED3\u679C\u7531\u540E\u53F0\u56DE\u5199\uFF08UI \u8F6E\u8BE2\uFF09\u3002\u901A\u8FC7 \u2192 \u56DE `ready` \u5E76\u8BB0\u4E0B trialPassedAt\uFF08\u90E8\u7F72\u662F\u4EBA\u7684\u7B2C\u4E8C\u6B21\u51B3\u5B9A\uFF09\uFF1B\u6CA1\u8FC7 \u2192 `failed` + gaps\uFF08agent \u7684\u4EBA\u8BDD\u9519\u56E0\uFF09\uFF0C\u6539\u5B8C\u6E05\u5355\u518D\u8C03\u4E00\u6B21\u5373\u53EF\u3002\u8F6E\u6B21\u6709\u4E0A\u9650\uFF1Bowner-only",
8914
+ args: DeployIdArgsSchema
8915
+ },
8916
+ "deploy:deploy": {
8917
+ summary: "\u628A\u8BD5\u88C5\u901A\u8FC7\u7684\u90A3\u4E2A\u955C\u50CF\u5728 gateway \u767B\u8BB0\u4E3A**\u6B63\u5F0F**\u90E8\u7F72\uFF1A\u4E4B\u540E\u522B\u4EBA\u7684 clawd \u6D3E\u6D3B\u7ED9\u8FD9\u4E2A\u670D\u52A1\u8BBE\u5907\uFF0C\u8D77\u7684\u5C31\u662F\u5B83\u3002\u524D\u7F6E\u662F\u8BD5\u88C5\u901A\u8FC7\u8FC7\uFF08\u6CA1\u9A8C\u8FC7\u4E0D\u8BA9\u53D1\uFF0C\u90A3\u6B63\u662F\u8BD5\u88C5\u5B58\u5728\u7684\u7406\u7531\uFF09\u3002\u56DE\u6765\u7684\u5355\u636E\u5E26 placement\u2014\u2014\u4E91\u4E0A\u5730\u5740 / \u670D\u52A1\u8BBE\u5907 id / \u8C01\u53EF\u8C03\u7528 / \u4F7F\u7528\u8005\u9700\u81EA\u5E26\u54EA\u4E9B\u51ED\u636E\uFF1Bowner-only",
8918
+ args: DeployIdArgsSchema
8919
+ },
8866
8920
  "deploy:remove": {
8867
8921
  summary: "\u5220\u6389\u4E00\u5F20\u90E8\u7F72\u5355\uFF0C\u8FDE\u5E26\u6E05\u6389\u5B83\u7684\u5168\u90E8\u51ED\u636E\u503C\uFF08\u503C\u4E0D\u8BE5\u6BD4\u5355\u636E\u6D3B\u5F97\u4E45\uFF09\uFF1Bowner-only",
8868
8922
  args: DeployIdArgsSchema
@@ -9851,8 +9905,8 @@ var require_req = __commonJS({
9851
9905
  if (req.originalUrl) {
9852
9906
  _req.url = req.originalUrl;
9853
9907
  } else {
9854
- const path96 = req.path;
9855
- _req.url = typeof path96 === "string" ? path96 : req.url ? req.url.path || req.url : void 0;
9908
+ const path98 = req.path;
9909
+ _req.url = typeof path98 === "string" ? path98 : req.url ? req.url.path || req.url : void 0;
9856
9910
  }
9857
9911
  if (req.query) {
9858
9912
  _req.query = req.query;
@@ -10017,14 +10071,14 @@ var require_redact = __commonJS({
10017
10071
  }
10018
10072
  return obj;
10019
10073
  }
10020
- function parsePath(path96) {
10074
+ function parsePath(path98) {
10021
10075
  const parts = [];
10022
10076
  let current = "";
10023
10077
  let inBrackets = false;
10024
10078
  let inQuotes = false;
10025
10079
  let quoteChar = "";
10026
- for (let i = 0; i < path96.length; i++) {
10027
- const char = path96[i];
10080
+ for (let i = 0; i < path98.length; i++) {
10081
+ const char = path98[i];
10028
10082
  if (!inBrackets && char === ".") {
10029
10083
  if (current) {
10030
10084
  parts.push(current);
@@ -10155,10 +10209,10 @@ var require_redact = __commonJS({
10155
10209
  return current;
10156
10210
  }
10157
10211
  function redactPaths(obj, paths, censor, remove = false) {
10158
- for (const path96 of paths) {
10159
- const parts = parsePath(path96);
10212
+ for (const path98 of paths) {
10213
+ const parts = parsePath(path98);
10160
10214
  if (parts.includes("*")) {
10161
- redactWildcardPath(obj, parts, censor, path96, remove);
10215
+ redactWildcardPath(obj, parts, censor, path98, remove);
10162
10216
  } else {
10163
10217
  if (remove) {
10164
10218
  removeKey(obj, parts);
@@ -10243,8 +10297,8 @@ var require_redact = __commonJS({
10243
10297
  }
10244
10298
  } else {
10245
10299
  if (afterWildcard.includes("*")) {
10246
- const wrappedCensor = typeof censor === "function" ? (value, path96) => {
10247
- const fullPath = [...pathArray.slice(0, pathLength), ...path96];
10300
+ const wrappedCensor = typeof censor === "function" ? (value, path98) => {
10301
+ const fullPath = [...pathArray.slice(0, pathLength), ...path98];
10248
10302
  return censor(value, fullPath);
10249
10303
  } : censor;
10250
10304
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10279,8 +10333,8 @@ var require_redact = __commonJS({
10279
10333
  return null;
10280
10334
  }
10281
10335
  const pathStructure = /* @__PURE__ */ new Map();
10282
- for (const path96 of pathsToClone) {
10283
- const parts = parsePath(path96);
10336
+ for (const path98 of pathsToClone) {
10337
+ const parts = parsePath(path98);
10284
10338
  let current = pathStructure;
10285
10339
  for (let i = 0; i < parts.length; i++) {
10286
10340
  const part = parts[i];
@@ -10332,24 +10386,24 @@ var require_redact = __commonJS({
10332
10386
  }
10333
10387
  return cloneSelectively(obj, pathStructure);
10334
10388
  }
10335
- function validatePath(path96) {
10336
- if (typeof path96 !== "string") {
10389
+ function validatePath(path98) {
10390
+ if (typeof path98 !== "string") {
10337
10391
  throw new Error("Paths must be (non-empty) strings");
10338
10392
  }
10339
- if (path96 === "") {
10393
+ if (path98 === "") {
10340
10394
  throw new Error("Invalid redaction path ()");
10341
10395
  }
10342
- if (path96.includes("..")) {
10343
- throw new Error(`Invalid redaction path (${path96})`);
10396
+ if (path98.includes("..")) {
10397
+ throw new Error(`Invalid redaction path (${path98})`);
10344
10398
  }
10345
- if (path96.includes(",")) {
10346
- throw new Error(`Invalid redaction path (${path96})`);
10399
+ if (path98.includes(",")) {
10400
+ throw new Error(`Invalid redaction path (${path98})`);
10347
10401
  }
10348
10402
  let bracketCount = 0;
10349
10403
  let inQuotes = false;
10350
10404
  let quoteChar = "";
10351
- for (let i = 0; i < path96.length; i++) {
10352
- const char = path96[i];
10405
+ for (let i = 0; i < path98.length; i++) {
10406
+ const char = path98[i];
10353
10407
  if ((char === '"' || char === "'") && bracketCount > 0) {
10354
10408
  if (!inQuotes) {
10355
10409
  inQuotes = true;
@@ -10363,20 +10417,20 @@ var require_redact = __commonJS({
10363
10417
  } else if (char === "]" && !inQuotes) {
10364
10418
  bracketCount--;
10365
10419
  if (bracketCount < 0) {
10366
- throw new Error(`Invalid redaction path (${path96})`);
10420
+ throw new Error(`Invalid redaction path (${path98})`);
10367
10421
  }
10368
10422
  }
10369
10423
  }
10370
10424
  if (bracketCount !== 0) {
10371
- throw new Error(`Invalid redaction path (${path96})`);
10425
+ throw new Error(`Invalid redaction path (${path98})`);
10372
10426
  }
10373
10427
  }
10374
10428
  function validatePaths(paths) {
10375
10429
  if (!Array.isArray(paths)) {
10376
10430
  throw new TypeError("paths must be an array");
10377
10431
  }
10378
- for (const path96 of paths) {
10379
- validatePath(path96);
10432
+ for (const path98 of paths) {
10433
+ validatePath(path98);
10380
10434
  }
10381
10435
  }
10382
10436
  function slowRedact(options = {}) {
@@ -10544,8 +10598,8 @@ var require_redaction = __commonJS({
10544
10598
  if (shape[k2] === null) {
10545
10599
  o[k2] = (value) => topCensor(value, [k2]);
10546
10600
  } else {
10547
- const wrappedCensor = typeof censor === "function" ? (value, path96) => {
10548
- return censor(value, [k2, ...path96]);
10601
+ const wrappedCensor = typeof censor === "function" ? (value, path98) => {
10602
+ return censor(value, [k2, ...path98]);
10549
10603
  } : censor;
10550
10604
  o[k2] = Redact({
10551
10605
  paths: shape[k2],
@@ -10763,10 +10817,10 @@ var require_atomic_sleep = __commonJS({
10763
10817
  var require_sonic_boom = __commonJS({
10764
10818
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10765
10819
  "use strict";
10766
- var fs85 = require("fs");
10820
+ var fs87 = require("fs");
10767
10821
  var EventEmitter3 = require("events");
10768
10822
  var inherits = require("util").inherits;
10769
- var path96 = require("path");
10823
+ var path98 = require("path");
10770
10824
  var sleep2 = require_atomic_sleep();
10771
10825
  var assert = require("assert");
10772
10826
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10820,20 +10874,20 @@ var require_sonic_boom = __commonJS({
10820
10874
  const mode = sonic.mode;
10821
10875
  if (sonic.sync) {
10822
10876
  try {
10823
- if (sonic.mkdir) fs85.mkdirSync(path96.dirname(file), { recursive: true });
10824
- const fd = fs85.openSync(file, flags, mode);
10877
+ if (sonic.mkdir) fs87.mkdirSync(path98.dirname(file), { recursive: true });
10878
+ const fd = fs87.openSync(file, flags, mode);
10825
10879
  fileOpened(null, fd);
10826
10880
  } catch (err) {
10827
10881
  fileOpened(err);
10828
10882
  throw err;
10829
10883
  }
10830
10884
  } else if (sonic.mkdir) {
10831
- fs85.mkdir(path96.dirname(file), { recursive: true }, (err) => {
10885
+ fs87.mkdir(path98.dirname(file), { recursive: true }, (err) => {
10832
10886
  if (err) return fileOpened(err);
10833
- fs85.open(file, flags, mode, fileOpened);
10887
+ fs87.open(file, flags, mode, fileOpened);
10834
10888
  });
10835
10889
  } else {
10836
- fs85.open(file, flags, mode, fileOpened);
10890
+ fs87.open(file, flags, mode, fileOpened);
10837
10891
  }
10838
10892
  }
10839
10893
  function SonicBoom(opts) {
@@ -10874,8 +10928,8 @@ var require_sonic_boom = __commonJS({
10874
10928
  this.flush = flushBuffer;
10875
10929
  this.flushSync = flushBufferSync;
10876
10930
  this._actualWrite = actualWriteBuffer;
10877
- fsWriteSync = () => fs85.writeSync(this.fd, this._writingBuf);
10878
- fsWrite = () => fs85.write(this.fd, this._writingBuf, this.release);
10931
+ fsWriteSync = () => fs87.writeSync(this.fd, this._writingBuf);
10932
+ fsWrite = () => fs87.write(this.fd, this._writingBuf, this.release);
10879
10933
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
10880
10934
  this._writingBuf = "";
10881
10935
  this.write = write;
@@ -10884,15 +10938,15 @@ var require_sonic_boom = __commonJS({
10884
10938
  this._actualWrite = actualWrite;
10885
10939
  fsWriteSync = () => {
10886
10940
  if (Buffer.isBuffer(this._writingBuf)) {
10887
- return fs85.writeSync(this.fd, this._writingBuf);
10941
+ return fs87.writeSync(this.fd, this._writingBuf);
10888
10942
  }
10889
- return fs85.writeSync(this.fd, this._writingBuf, "utf8");
10943
+ return fs87.writeSync(this.fd, this._writingBuf, "utf8");
10890
10944
  };
10891
10945
  fsWrite = () => {
10892
10946
  if (Buffer.isBuffer(this._writingBuf)) {
10893
- return fs85.write(this.fd, this._writingBuf, this.release);
10947
+ return fs87.write(this.fd, this._writingBuf, this.release);
10894
10948
  }
10895
- return fs85.write(this.fd, this._writingBuf, "utf8", this.release);
10949
+ return fs87.write(this.fd, this._writingBuf, "utf8", this.release);
10896
10950
  };
10897
10951
  } else {
10898
10952
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10949,7 +11003,7 @@ var require_sonic_boom = __commonJS({
10949
11003
  }
10950
11004
  }
10951
11005
  if (this._fsync) {
10952
- fs85.fsyncSync(this.fd);
11006
+ fs87.fsyncSync(this.fd);
10953
11007
  }
10954
11008
  const len = this._len;
10955
11009
  if (this._reopening) {
@@ -11063,7 +11117,7 @@ var require_sonic_boom = __commonJS({
11063
11117
  const onDrain = () => {
11064
11118
  if (!this._fsync) {
11065
11119
  try {
11066
- fs85.fsync(this.fd, (err) => {
11120
+ fs87.fsync(this.fd, (err) => {
11067
11121
  this._flushPending = false;
11068
11122
  cb(err);
11069
11123
  });
@@ -11165,7 +11219,7 @@ var require_sonic_boom = __commonJS({
11165
11219
  const fd = this.fd;
11166
11220
  this.once("ready", () => {
11167
11221
  if (fd !== this.fd) {
11168
- fs85.close(fd, (err) => {
11222
+ fs87.close(fd, (err) => {
11169
11223
  if (err) {
11170
11224
  return this.emit("error", err);
11171
11225
  }
@@ -11214,7 +11268,7 @@ var require_sonic_boom = __commonJS({
11214
11268
  buf = this._bufs[0];
11215
11269
  }
11216
11270
  try {
11217
- const n = Buffer.isBuffer(buf) ? fs85.writeSync(this.fd, buf) : fs85.writeSync(this.fd, buf, "utf8");
11271
+ const n = Buffer.isBuffer(buf) ? fs87.writeSync(this.fd, buf) : fs87.writeSync(this.fd, buf, "utf8");
11218
11272
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
11219
11273
  buf = releasedBufObj.writingBuf;
11220
11274
  this._len = releasedBufObj.len;
@@ -11230,7 +11284,7 @@ var require_sonic_boom = __commonJS({
11230
11284
  }
11231
11285
  }
11232
11286
  try {
11233
- fs85.fsyncSync(this.fd);
11287
+ fs87.fsyncSync(this.fd);
11234
11288
  } catch {
11235
11289
  }
11236
11290
  }
@@ -11251,7 +11305,7 @@ var require_sonic_boom = __commonJS({
11251
11305
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11252
11306
  }
11253
11307
  try {
11254
- const n = fs85.writeSync(this.fd, buf);
11308
+ const n = fs87.writeSync(this.fd, buf);
11255
11309
  buf = buf.subarray(n);
11256
11310
  this._len = Math.max(this._len - n, 0);
11257
11311
  if (buf.length <= 0) {
@@ -11279,13 +11333,13 @@ var require_sonic_boom = __commonJS({
11279
11333
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11280
11334
  if (this.sync) {
11281
11335
  try {
11282
- const written = Buffer.isBuffer(this._writingBuf) ? fs85.writeSync(this.fd, this._writingBuf) : fs85.writeSync(this.fd, this._writingBuf, "utf8");
11336
+ const written = Buffer.isBuffer(this._writingBuf) ? fs87.writeSync(this.fd, this._writingBuf) : fs87.writeSync(this.fd, this._writingBuf, "utf8");
11283
11337
  release(null, written);
11284
11338
  } catch (err) {
11285
11339
  release(err);
11286
11340
  }
11287
11341
  } else {
11288
- fs85.write(this.fd, this._writingBuf, release);
11342
+ fs87.write(this.fd, this._writingBuf, release);
11289
11343
  }
11290
11344
  }
11291
11345
  function actualWriteBuffer() {
@@ -11294,7 +11348,7 @@ var require_sonic_boom = __commonJS({
11294
11348
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11295
11349
  if (this.sync) {
11296
11350
  try {
11297
- const written = fs85.writeSync(this.fd, this._writingBuf);
11351
+ const written = fs87.writeSync(this.fd, this._writingBuf);
11298
11352
  release(null, written);
11299
11353
  } catch (err) {
11300
11354
  release(err);
@@ -11303,7 +11357,7 @@ var require_sonic_boom = __commonJS({
11303
11357
  if (kCopyBuffer) {
11304
11358
  this._writingBuf = Buffer.from(this._writingBuf);
11305
11359
  }
11306
- fs85.write(this.fd, this._writingBuf, release);
11360
+ fs87.write(this.fd, this._writingBuf, release);
11307
11361
  }
11308
11362
  }
11309
11363
  function actualClose(sonic) {
@@ -11319,12 +11373,12 @@ var require_sonic_boom = __commonJS({
11319
11373
  sonic._lens = [];
11320
11374
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11321
11375
  try {
11322
- fs85.fsync(sonic.fd, closeWrapped);
11376
+ fs87.fsync(sonic.fd, closeWrapped);
11323
11377
  } catch {
11324
11378
  }
11325
11379
  function closeWrapped() {
11326
11380
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11327
- fs85.close(sonic.fd, done);
11381
+ fs87.close(sonic.fd, done);
11328
11382
  } else {
11329
11383
  done();
11330
11384
  }
@@ -13688,7 +13742,7 @@ var require_multistream = __commonJS({
13688
13742
  var require_pino = __commonJS({
13689
13743
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
13690
13744
  "use strict";
13691
- var os31 = require("os");
13745
+ var os32 = require("os");
13692
13746
  var stdSerializers = require_pino_std_serializers();
13693
13747
  var caller = require_caller();
13694
13748
  var redaction = require_redaction();
@@ -13735,7 +13789,7 @@ var require_pino = __commonJS({
13735
13789
  } = symbols;
13736
13790
  var { epochTime, nullTime } = time;
13737
13791
  var { pid } = process;
13738
- var hostname = os31.hostname();
13792
+ var hostname = os32.hostname();
13739
13793
  var defaultErrorSerializer = stdSerializers.err;
13740
13794
  var defaultOptions2 = {
13741
13795
  level: "info",
@@ -14459,11 +14513,11 @@ var init_lib = __esm({
14459
14513
  }
14460
14514
  }
14461
14515
  },
14462
- addToPath: function addToPath(path96, added, removed, oldPosInc, options) {
14463
- var last = path96.lastComponent;
14516
+ addToPath: function addToPath(path98, added, removed, oldPosInc, options) {
14517
+ var last = path98.lastComponent;
14464
14518
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14465
14519
  return {
14466
- oldPos: path96.oldPos + oldPosInc,
14520
+ oldPos: path98.oldPos + oldPosInc,
14467
14521
  lastComponent: {
14468
14522
  count: last.count + 1,
14469
14523
  added,
@@ -14473,7 +14527,7 @@ var init_lib = __esm({
14473
14527
  };
14474
14528
  } else {
14475
14529
  return {
14476
- oldPos: path96.oldPos + oldPosInc,
14530
+ oldPos: path98.oldPos + oldPosInc,
14477
14531
  lastComponent: {
14478
14532
  count: 1,
14479
14533
  added,
@@ -15055,10 +15109,10 @@ function attachmentToHistoryMessage(o, ts) {
15055
15109
  const memories = raw.map((m2) => {
15056
15110
  if (!m2 || typeof m2 !== "object") return null;
15057
15111
  const rec4 = m2;
15058
- const path96 = typeof rec4.path === "string" ? rec4.path : null;
15112
+ const path98 = typeof rec4.path === "string" ? rec4.path : null;
15059
15113
  const content = typeof rec4.content === "string" ? rec4.content : null;
15060
- if (!path96 || content == null) return null;
15061
- const entry = { path: path96, content };
15114
+ if (!path98 || content == null) return null;
15115
+ const entry = { path: path98, content };
15062
15116
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
15063
15117
  return entry;
15064
15118
  }).filter((m2) => m2 !== null);
@@ -15924,10 +15978,10 @@ function parseAttachment(obj) {
15924
15978
  const memories = raw.map((m2) => {
15925
15979
  if (!m2 || typeof m2 !== "object") return null;
15926
15980
  const rec4 = m2;
15927
- const path96 = typeof rec4.path === "string" ? rec4.path : null;
15981
+ const path98 = typeof rec4.path === "string" ? rec4.path : null;
15928
15982
  const content = typeof rec4.content === "string" ? rec4.content : null;
15929
- if (!path96 || content == null) return null;
15930
- const out = { path: path96, content };
15983
+ if (!path98 || content == null) return null;
15984
+ const out = { path: path98, content };
15931
15985
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
15932
15986
  return out;
15933
15987
  }).filter((m2) => m2 !== null);
@@ -36901,8 +36955,8 @@ var require_utils = __commonJS({
36901
36955
  var result = transform[inputType][outputType](input);
36902
36956
  return result;
36903
36957
  };
36904
- exports2.resolve = function(path96) {
36905
- var parts = path96.split("/");
36958
+ exports2.resolve = function(path98) {
36959
+ var parts = path98.split("/");
36906
36960
  var result = [];
36907
36961
  for (var index = 0; index < parts.length; index++) {
36908
36962
  var part = parts[index];
@@ -42755,18 +42809,18 @@ var require_object = __commonJS({
42755
42809
  var object = new ZipObject(name, zipObjectContent, o);
42756
42810
  this.files[name] = object;
42757
42811
  };
42758
- var parentFolder = function(path96) {
42759
- if (path96.slice(-1) === "/") {
42760
- path96 = path96.substring(0, path96.length - 1);
42812
+ var parentFolder = function(path98) {
42813
+ if (path98.slice(-1) === "/") {
42814
+ path98 = path98.substring(0, path98.length - 1);
42761
42815
  }
42762
- var lastSlash = path96.lastIndexOf("/");
42763
- return lastSlash > 0 ? path96.substring(0, lastSlash) : "";
42816
+ var lastSlash = path98.lastIndexOf("/");
42817
+ return lastSlash > 0 ? path98.substring(0, lastSlash) : "";
42764
42818
  };
42765
- var forceTrailingSlash = function(path96) {
42766
- if (path96.slice(-1) !== "/") {
42767
- path96 += "/";
42819
+ var forceTrailingSlash = function(path98) {
42820
+ if (path98.slice(-1) !== "/") {
42821
+ path98 += "/";
42768
42822
  }
42769
- return path96;
42823
+ return path98;
42770
42824
  };
42771
42825
  var folderAdd = function(name, createFolders) {
42772
42826
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43768,7 +43822,7 @@ var require_lib3 = __commonJS({
43768
43822
  // src/run-case/recorder.ts
43769
43823
  function startRunCaseRecorder(opts) {
43770
43824
  const now = opts.now ?? Date.now;
43771
- const dir = import_node_path78.default.dirname(opts.recordPath);
43825
+ const dir = import_node_path80.default.dirname(opts.recordPath);
43772
43826
  let stream = null;
43773
43827
  let closing = false;
43774
43828
  let closedSettled = false;
@@ -43808,12 +43862,12 @@ function startRunCaseRecorder(opts) {
43808
43862
  };
43809
43863
  return { tap, close, closed };
43810
43864
  }
43811
- var import_node_fs57, import_node_path78;
43865
+ var import_node_fs57, import_node_path80;
43812
43866
  var init_recorder = __esm({
43813
43867
  "src/run-case/recorder.ts"() {
43814
43868
  "use strict";
43815
43869
  import_node_fs57 = __toESM(require("fs"), 1);
43816
- import_node_path78 = __toESM(require("path"), 1);
43870
+ import_node_path80 = __toESM(require("path"), 1);
43817
43871
  }
43818
43872
  });
43819
43873
 
@@ -43856,7 +43910,7 @@ var init_wire = __esm({
43856
43910
  // src/run-case/controller.ts
43857
43911
  async function runController(opts) {
43858
43912
  const now = opts.now ?? Date.now;
43859
- const cwd = opts.cwd ?? (0, import_node_fs58.mkdtempSync)(import_node_path79.default.join(import_node_os27.default.tmpdir(), "clawd-runcase-"));
43913
+ const cwd = opts.cwd ?? (0, import_node_fs58.mkdtempSync)(import_node_path81.default.join(import_node_os28.default.tmpdir(), "clawd-runcase-"));
43860
43914
  const ownsCwd = opts.cwd === void 0;
43861
43915
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
43862
43916
  const spawnCtx = { cwd };
@@ -44023,13 +44077,13 @@ async function runController(opts) {
44023
44077
  }
44024
44078
  return exitCode ?? 0;
44025
44079
  }
44026
- var import_node_fs58, import_node_os27, import_node_path79;
44080
+ var import_node_fs58, import_node_os28, import_node_path81;
44027
44081
  var init_controller = __esm({
44028
44082
  "src/run-case/controller.ts"() {
44029
44083
  "use strict";
44030
44084
  import_node_fs58 = require("fs");
44031
- import_node_os27 = __toESM(require("os"), 1);
44032
- import_node_path79 = __toESM(require("path"), 1);
44085
+ import_node_os28 = __toESM(require("os"), 1);
44086
+ import_node_path81 = __toESM(require("path"), 1);
44033
44087
  init_claude();
44034
44088
  init_stdout_splitter();
44035
44089
  init_permission_stdio();
@@ -44304,9 +44358,9 @@ Env (advanced):
44304
44358
  `;
44305
44359
 
44306
44360
  // src/index.ts
44307
- var import_node_path77 = __toESM(require("path"), 1);
44361
+ var import_node_path79 = __toESM(require("path"), 1);
44308
44362
  var import_node_fs56 = __toESM(require("fs"), 1);
44309
- var import_node_os26 = __toESM(require("os"), 1);
44363
+ var import_node_os27 = __toESM(require("os"), 1);
44310
44364
  var import_node_crypto22 = require("crypto");
44311
44365
  var import_node_url5 = require("url");
44312
44366
 
@@ -51562,8 +51616,8 @@ function turnStartInput(text) {
51562
51616
  const items = [];
51563
51617
  let leftover = text;
51564
51618
  for (const m2 of text.matchAll(SKILL_RE)) {
51565
- const [marker, name, path96] = m2;
51566
- items.push({ type: "skill", name, path: path96 });
51619
+ const [marker, name, path98] = m2;
51620
+ items.push({ type: "skill", name, path: path98 });
51567
51621
  leftover = leftover.replace(marker, "");
51568
51622
  }
51569
51623
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -54626,6 +54680,38 @@ function redactEvidence(evidence) {
54626
54680
  };
54627
54681
  }
54628
54682
 
54683
+ // src/deploy/readiness.ts
54684
+ function secretShortfalls(receipt, filledEnv) {
54685
+ const declared = receipt.manifest?.secrets ?? [];
54686
+ const out = [];
54687
+ for (const sec of declared) {
54688
+ const f = receipt.fulfillment[sec.name];
54689
+ if (!f) {
54690
+ out.push({ name: sec.name, why: "fulfillment", missingEnv: [] });
54691
+ continue;
54692
+ }
54693
+ const filled = new Set(filledEnv(sec.name));
54694
+ const missing = sec.env.filter((e) => !filled.has(e));
54695
+ if (missing.length === 0) continue;
54696
+ out.push({ name: sec.name, why: f === "deployer" ? "values" : "trial", missingEnv: missing });
54697
+ }
54698
+ return out;
54699
+ }
54700
+ function describeShortfalls(items) {
54701
+ return items.map((s) => {
54702
+ if (s.why === "fulfillment") return `\u300C${s.name}\u300D\u8FD8\u6CA1\u9009\u8C01\u6765\u63D0\u4F9B`;
54703
+ if (s.why === "trial") return `\u300C${s.name}\u300D\u8BF4\u597D\u4F7F\u7528\u8005\u81EA\u5E26\uFF0C\u4F46\u8BD5\u88C5\u8981\u771F\u8DD1\u4E00\u6B21\uFF0C\u5F97\u4F60\u5148\u57AB\u4E00\u4EFD\uFF08\u8FD8\u5DEE ${s.missingEnv.join(" / ")}\uFF09`;
54704
+ return `\u300C${s.name}\u300D\u8FD8\u5DEE ${s.missingEnv.join(" / ")}`;
54705
+ }).join("\uFF1B");
54706
+ }
54707
+ function nextReadiness(receipt, filledEnv) {
54708
+ if (receipt.status !== "draft" && receipt.status !== "ready") return void 0;
54709
+ if (!receipt.manifest) return void 0;
54710
+ const ready = secretShortfalls(receipt, filledEnv).length === 0;
54711
+ const next = ready ? "ready" : "draft";
54712
+ return next === receipt.status ? void 0 : next;
54713
+ }
54714
+
54629
54715
  // src/handlers/deploy.ts
54630
54716
  function ensureOwner(ctx) {
54631
54717
  if (!ctx || ctx.principal.kind !== "owner") {
@@ -54655,6 +54741,11 @@ function secretStatusOf(deps, receipt) {
54655
54741
  total: s.env.length
54656
54742
  }));
54657
54743
  }
54744
+ function applyReadiness(deps, receipt) {
54745
+ const next = nextReadiness(receipt, (name) => deps.secrets.filledKeys(receipt.deployId, name));
54746
+ if (!next) return receipt;
54747
+ return deps.receipts.update(receipt.deployId, { status: next }) ?? receipt;
54748
+ }
54658
54749
  function buildDeployHandlers(deps) {
54659
54750
  const view = (receipt) => ({
54660
54751
  response: { type: "deploy:receipt", receipt, secretStatus: secretStatusOf(deps, receipt) }
@@ -54690,6 +54781,12 @@ function buildDeployHandlers(deps) {
54690
54781
  if (receipt.status === "scanning") {
54691
54782
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u6B63\u5728\u626B\u63CF\u4E2D\uFF0C\u7B49\u5B83\u626B\u5B8C\u518D\u91CD\u626B");
54692
54783
  }
54784
+ if (receipt.status === "deployed") {
54785
+ throw new ClawdError(
54786
+ ERROR_CODES.VALIDATION_ERROR,
54787
+ "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u5DF2\u7ECF\u90E8\u7F72\u4E86\uFF0C\u4E0D\u80FD\u5C31\u5730\u91CD\u626B\u3002persona \u6539\u4E86\u8981\u91CD\u53D1\u7684\u8BDD\uFF0C\u56DE\u5361\u7247\u91CD\u65B0\u53D1\u8D77\u4E00\u6B21\u4E0A\u4E91\u2014\u2014\u90A3\u4F1A\u5F00\u4E00\u5F20\u65B0\u5355\u636E\uFF08\u51ED\u636E\u548C\u5C65\u7EA6\u4F1A\u7EE7\u627F\u8FC7\u6765\uFF09\uFF0C\u73B0\u5728\u8FD9\u4EFD\u90E8\u7F72\u5728\u65B0\u7684\u90E8\u7F72\u597D\u4E4B\u524D\u7167\u5E38\u670D\u52A1"
54788
+ );
54789
+ }
54693
54790
  deps.receipts.update(args.deployId, {
54694
54791
  status: "scanning",
54695
54792
  manifest: void 0,
@@ -54697,7 +54794,12 @@ function buildDeployHandlers(deps) {
54697
54794
  notes: [],
54698
54795
  smokeTask: void 0,
54699
54796
  error: void 0,
54700
- scanSessionId: void 0
54797
+ scanSessionId: void 0,
54798
+ // 重扫 = 一次新的判断,试装轮次跟着清零(不是同一条路上的第 N 次撞墙)
54799
+ trialRound: 0,
54800
+ gaps: [],
54801
+ trialPassedAt: void 0,
54802
+ trialImage: void 0
54701
54803
  });
54702
54804
  const scanSessionId = deps.startScan(args.deployId, receipt.personaId);
54703
54805
  if (scanSessionId) deps.receipts.update(args.deployId, { scanSessionId });
@@ -54727,8 +54829,9 @@ function buildDeployHandlers(deps) {
54727
54829
  }
54728
54830
  }
54729
54831
  }
54730
- const next = deps.receipts.update(args.deployId, args.patch);
54731
- return view(next ?? receipt);
54832
+ const invalidates = args.patch.manifest ? { trialPassedAt: void 0, trialImage: void 0 } : {};
54833
+ const next = deps.receipts.update(args.deployId, { ...args.patch, ...invalidates });
54834
+ return view(applyReadiness(deps, next ?? receipt));
54732
54835
  };
54733
54836
  const putSecret = async (frame, _client, ctx) => {
54734
54837
  ensureOwner(ctx);
@@ -54748,7 +54851,7 @@ function buildDeployHandlers(deps) {
54748
54851
  }
54749
54852
  }
54750
54853
  deps.secrets.put({ deployId: args.deployId, name: args.name, values: args.values });
54751
- return view(receipt);
54854
+ return view(applyReadiness(deps, receipt));
54752
54855
  };
54753
54856
  const reportFinding = async (frame, _client, ctx) => {
54754
54857
  ensureOwner(ctx);
@@ -54791,12 +54894,77 @@ function buildDeployHandlers(deps) {
54791
54894
  notes: args.notes?.map(redactSecretValues),
54792
54895
  error: void 0
54793
54896
  });
54794
- return view(next);
54897
+ return view(applyReadiness(deps, next));
54898
+ };
54899
+ const trial = async (frame, _client, ctx) => {
54900
+ ensureOwner(ctx);
54901
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:trial");
54902
+ const receipt = mustGet(deps, args.deployId);
54903
+ if (receipt.status === "scanning" || receipt.status === "scanFailed") {
54904
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u8FD8\u6CA1\u626B\u51FA\u6E05\u5355\uFF0C\u5148\u7B49\u626B\u63CF\u7ED3\u675F");
54905
+ }
54906
+ if (receipt.status === "trialing") {
54907
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u6B63\u5728\u8BD5\u88C5\u4E2D");
54908
+ }
54909
+ if (receipt.status === "deployed") {
54910
+ throw new ClawdError(
54911
+ ERROR_CODES.VALIDATION_ERROR,
54912
+ "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u5DF2\u7ECF\u90E8\u7F72\u4E86\u3002\u6539\u4E86\u4E1C\u897F\u8981\u91CD\u53D1\u7684\u8BDD\uFF0C\u56DE persona \u5361\u7247\u91CD\u65B0\u53D1\u8D77\u4E00\u6B21\u4E0A\u4E91"
54913
+ );
54914
+ }
54915
+ if (!receipt.manifest) {
54916
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u6CA1\u6709\u73AF\u5883\u6E05\u5355\uFF0C\u8BD5\u88C5\u65E0\u4ECE\u8C08\u8D77");
54917
+ }
54918
+ const short = secretShortfalls(receipt, (name) => deps.secrets.filledKeys(args.deployId, name));
54919
+ if (short.length > 0) {
54920
+ throw new ClawdError(
54921
+ ERROR_CODES.VALIDATION_ERROR,
54922
+ `VALIDATION_ERROR: \u51ED\u636E\u8FD8\u6CA1\u9F50\uFF0C\u8BD5\u88C5\u8DD1\u4E0D\u8D77\u6765\uFF1A${describeShortfalls(short)}`
54923
+ );
54924
+ }
54925
+ if (receipt.trialRound >= TRIAL_ROUND_MAX) {
54926
+ throw new ClawdError(
54927
+ ERROR_CODES.VALIDATION_ERROR,
54928
+ `VALIDATION_ERROR: \u5DF2\u7ECF\u8BD5\u88C5 ${receipt.trialRound} \u8F6E\u4E86\uFF08\u4E0A\u9650 ${TRIAL_ROUND_MAX}\uFF09\u3002\u4E00\u8F6E\u662F\u4E00\u6B21\u771F\u7684\u955C\u50CF\u6784\u5EFA\u52A0\u4E00\u6B21\u771F\u7684\u53D1\u5E03\uFF0C\u5230\u8FD9\u4E2A\u6570\u8BF4\u660E\u7F3A\u7684\u591A\u534A\u4E0D\u662F\u4E00\u6761\u4F9D\u8D56\u2014\u2014\u56DE\u53BB\u91CD\u626B\u4E00\u904D\uFF0C\u6216\u8005\u627E\u4EBA\u770B\u770B\u8FD9\u6761\u8DEF\u662F\u4E0D\u662F\u8D70\u4E0D\u901A`
54929
+ );
54930
+ }
54931
+ const next = deps.receipts.update(args.deployId, {
54932
+ status: "trialing",
54933
+ trialRound: receipt.trialRound + 1,
54934
+ trialStage: "\u6392\u961F\u51C6\u5907\u4E2D",
54935
+ // 上一轮的缺口不留到这一轮:人已经照着补过了,留着会让人以为没改动
54936
+ gaps: [],
54937
+ error: void 0
54938
+ });
54939
+ deps.startTrial(args.deployId);
54940
+ return view(next ?? receipt);
54941
+ };
54942
+ const deploy = async (frame, _client, ctx) => {
54943
+ ensureOwner(ctx);
54944
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:deploy");
54945
+ const receipt = mustGet(deps, args.deployId);
54946
+ if (receipt.status === "deployed") return view(receipt);
54947
+ if (!receipt.trialPassedAt || !receipt.trialImage) {
54948
+ throw new ClawdError(
54949
+ ERROR_CODES.VALIDATION_ERROR,
54950
+ "VALIDATION_ERROR: \u8FD8\u6CA1\u8BD5\u88C5\u901A\u8FC7\u8FC7\u3002\u5148\u70B9\u300C\u786E\u8BA4\u5E76\u8BD5\u88C5\u300D\u2014\u2014\u90A3\u4E00\u6B65\u624D\u77E5\u9053\u8FD9\u4EFD\u6E05\u5355\u5728\u4E91\u4E0A\u88C5\u4E0D\u88C5\u5F97\u8D77\u6765"
54951
+ );
54952
+ }
54953
+ if (receipt.status !== "ready") {
54954
+ throw new ClawdError(
54955
+ ERROR_CODES.VALIDATION_ERROR,
54956
+ `VALIDATION_ERROR: \u5F53\u524D\u72B6\u6001\u662F ${receipt.status}\uFF0C\u4E0D\u80FD\u90E8\u7F72`
54957
+ );
54958
+ }
54959
+ const placement = await deps.registerOfficial(receipt);
54960
+ const next = deps.receipts.update(args.deployId, { status: "deployed", placement, error: void 0 });
54961
+ return view(next ?? receipt);
54795
54962
  };
54796
54963
  const remove = async (frame, _client, ctx) => {
54797
54964
  ensureOwner(ctx);
54798
54965
  const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:remove");
54799
- mustGet(deps, args.deployId);
54966
+ const receipt = mustGet(deps, args.deployId);
54967
+ if (receipt.placement) await deps.unregisterDeployment(receipt.deployId);
54800
54968
  deps.receipts.remove(args.deployId);
54801
54969
  deps.secrets.removeDeploy(args.deployId);
54802
54970
  return { response: { type: "deploy:remove", deployId: args.deployId } };
@@ -54810,6 +54978,8 @@ function buildDeployHandlers(deps) {
54810
54978
  "deploy:putSecret": putSecret,
54811
54979
  "deploy:reportFinding": reportFinding,
54812
54980
  "deploy:finishScan": finishScan,
54981
+ "deploy:trial": trial,
54982
+ "deploy:deploy": deploy,
54813
54983
  "deploy:remove": remove
54814
54984
  };
54815
54985
  }
@@ -54866,6 +55036,7 @@ function createReceiptStore(deps) {
54866
55036
  notes: [],
54867
55037
  fulfillment: {},
54868
55038
  gaps: [],
55039
+ trialRound: 0,
54869
55040
  createdAt: ts,
54870
55041
  updatedAt: ts
54871
55042
  };
@@ -54994,6 +55165,384 @@ function createSecretStore(deps) {
54994
55165
  };
54995
55166
  }
54996
55167
 
55168
+ // src/deploy/cloud-host-config.ts
55169
+ var import_promises6 = __toESM(require("fs/promises"), 1);
55170
+ var import_node_path32 = __toESM(require("path"), 1);
55171
+ var CLOUD_HOST_CONFIG_FILE = "cloud-host.json";
55172
+ var REQUIRED = ["provisionDir", "gatewayUrl", "gatewayAdminKey", "gatewayApiKey", "k3sHost", "k3sKeyPath"];
55173
+ var CloudHostConfigError = class extends Error {
55174
+ };
55175
+ async function loadCloudHostConfig(dataDir) {
55176
+ const file = import_node_path32.default.join(dataDir, CLOUD_HOST_CONFIG_FILE);
55177
+ let raw;
55178
+ try {
55179
+ raw = await import_promises6.default.readFile(file, "utf8");
55180
+ } catch (err) {
55181
+ if (err.code === "ENOENT") {
55182
+ throw new CloudHostConfigError(
55183
+ `\u8FD8\u6CA1\u914D ${file}\u3002\u8BD5\u88C5\u8981\u77E5\u9053\u5F80\u54EA\u53F0\u673A\u5668\u63A8\u955C\u50CF\u3001\u8DDF\u54EA\u4E2A gateway \u8BF4\u8BDD\uFF0C\u5B57\u6BB5\u89C1 specs/2026-09-03-persona-cloud-m1b-trial-design.md \u7B2C\u4E94\u8282\u3002`
55184
+ );
55185
+ }
55186
+ throw err;
55187
+ }
55188
+ let parsed;
55189
+ try {
55190
+ parsed = JSON.parse(raw);
55191
+ } catch (err) {
55192
+ throw new CloudHostConfigError(`${file} \u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${String(err)}`);
55193
+ }
55194
+ const missing = REQUIRED.filter((k2) => !parsed[k2]);
55195
+ if (missing.length > 0) {
55196
+ throw new CloudHostConfigError(`${file} \u7F3A\u5B57\u6BB5\uFF1A${missing.join(" / ")}`);
55197
+ }
55198
+ return {
55199
+ provisionDir: parsed.provisionDir,
55200
+ gatewayUrl: parsed.gatewayUrl.replace(/\/+$/, ""),
55201
+ gatewayAdminKey: parsed.gatewayAdminKey,
55202
+ gatewayApiKey: parsed.gatewayApiKey,
55203
+ k3sHost: parsed.k3sHost,
55204
+ k3sKeyPath: parsed.k3sKeyPath,
55205
+ imageRepo: parsed.imageRepo ?? "clawd-persona-cloud",
55206
+ trialTimeoutMs: parsed.trialTimeoutMs ?? 45 * 6e4
55207
+ };
55208
+ }
55209
+
55210
+ // src/deploy/trial-runner.ts
55211
+ var import_promises7 = __toESM(require("fs/promises"), 1);
55212
+ var import_node_os8 = __toESM(require("os"), 1);
55213
+ var import_node_path33 = __toESM(require("path"), 1);
55214
+ var RAW_TAIL_CHARS = 2e3;
55215
+ var GATEWAY_ADMIN_TIMEOUT_MS = 3e4;
55216
+ var trialStamp = (nowMs) => Math.floor(nowMs / 1e3).toString(36);
55217
+ var trialImageTag = (repo2, deployId, round, stamp) => `${repo2}:${trialDeployId(deployId, round, stamp)}`;
55218
+ var trialDeployId = (deployId, round, stamp) => `${deployId}-t${round}-${stamp}`;
55219
+ var trialAppName = (deployId) => `trial-${deployId}`;
55220
+ var trialConversation = (deployId, round, stamp) => `trial-${deployId}-r${round}-${stamp}`;
55221
+ function secretTableFor(receipt, all, scope) {
55222
+ const declared = receipt.manifest?.secrets ?? [];
55223
+ const wanted = new Set(
55224
+ declared.filter((s) => scope === "all" || receipt.fulfillment[s.name] === "deployer").flatMap((s) => s.env)
55225
+ );
55226
+ return Object.fromEntries(Object.entries(all).filter(([k2]) => wanted.has(k2)));
55227
+ }
55228
+ function userSecretsOf(receipt) {
55229
+ return (receipt.manifest?.secrets ?? []).filter((s) => receipt.fulfillment[s.name] === "user").map((s) => ({ name: s.name, env: [...s.env] }));
55230
+ }
55231
+ var MISSING_MARKER = "::missing::";
55232
+ function buildSmokePrompt(smokeTask, appName) {
55233
+ return [
55234
+ "\u3010\u8BD5\u88C5\u3011\u8FD9\u662F\u4E00\u6B21\u6027\u7684\u73AF\u5883\u9A8C\u8BC1\uFF1A\u4F60\u5728\u4E00\u4E2A\u521A\u6784\u51FA\u6765\u7684\u4E91\u4E0A\u5BB9\u5668\u91CC\uFF0C\u8DD1\u5B8C\u8FD9\u6B21\u4EFB\u52A1\u5B83\u5C31\u4F1A\u88AB\u62C6\u6389\u3002",
55235
+ "",
55236
+ smokeTask,
55237
+ "",
55238
+ "\u4E09\u6761\u786C\u7EA6\u675F\uFF1A",
55239
+ `1. \u9879\u76EE\u540D\u5FC5\u987B\u53EB \`${appName}\`\uFF08\u62C6\u9664\u9760\u8FD9\u4E2A\u540D\u5B57\u8BC6\u522B\uFF0C\u7528\u522B\u7684\u540D\u5B57\u5C31\u6E05\u4E0D\u6389\u4E86\uFF09\u3002`,
55240
+ "2. \u4E00\u6B65\u90FD\u522B\u8DF3\uFF1A\u771F\u7684\u5EFA\u3001\u771F\u7684\u88C5\u4F9D\u8D56\u3001\u771F\u7684\u53D1\u5E03\u4E0A\u7EBF\uFF0C\u628A\u516C\u7F51\u5730\u5740\u56DE\u7ED9\u6211\u3002",
55241
+ `3. **\u6700\u540E\u5355\u72EC\u8D77\u4E00\u884C**\uFF0C\u628A\u8FD9\u6B21\u81EA\u5DF1\u52A8\u624B\u88C5\u4E0A\u7684**\u547D\u4EE4**\u5217\u51FA\u6765\uFF1A\`${MISSING_MARKER} \u540D\u5B57, \u540D\u5B57\`\uFF1B`,
55242
+ ` \u4E00\u6761\u90FD\u6CA1\u88C5\u5C31\u5199 \`${MISSING_MARKER} none\`\u3002`,
55243
+ "",
55244
+ "\u7B2C 3 \u6761\u662F\u8FD9\u6B21\u8DD1\u7684\u771F\u6B63\u76EE\u7684\u3002**\u4F60\u4E3A\u4E86\u8DD1\u901A\u81EA\u5DF1\u88C5\u7684\u547D\u4EE4\uFF0C\u6070\u6070\u5C31\u662F\u90E8\u7F72\u6E05\u5355\u6F0F\u6389\u7684\u90A3\u51E0\u6761**\u2014\u2014",
55245
+ "\u5178\u578B\u662F `command not found` \u4E4B\u540E\u4F60 apt / npm -g / curl \u88C5\u4E0A\u7684\u90A3\u4E9B\u3002\u4F60\u80FD\u81EA\u5DF1\u8865\u4E0A\u4E0D\u4EE3\u8868",
55246
+ "\u8FD9\u6B21\u8BD5\u88C5\u8FC7\u4E86\uFF1A\u5BB9\u5668\u6BCF\u6B21\u90FD\u662F\u65B0\u7684\uFF0C\u4E0B\u6B21\u7167\u6837\u7F3A\u3002",
55247
+ "",
55248
+ `**\u53EA\u5217\u547D\u4EE4\u540D**\uFF08\u88C5\u5B8C \`command -v <\u540D\u5B57>\` \u67E5\u5F97\u5230\u7684\u90A3\u79CD\uFF09\uFF0C\u4E00\u884C\u91CC\u7528\u9017\u53F7\u5206\u9694\uFF0C\u522B\u5199\u53E5\u5B50\u3002`,
55249
+ "\u8DD1\u7684\u65F6\u5019\u987A\u624B\u6539\u7684\u914D\u7F6E\u3001\u8981\u5148\u8DD1\u4E00\u6B21\u7684\u786E\u8BA4\u6B65\u9AA4\u3001\u52A0\u7684\u547D\u4EE4\u884C\u53C2\u6570\u2014\u2014\u8FD9\u4E9B\u90FD\u4E0D\u662F\u7F3A\u7684\u4F9D\u8D56\uFF0C",
55250
+ `**\u4E0D\u8981\u5199\u8FDB ${MISSING_MARKER}**\uFF0C\u653E\u6B63\u6587\u91CC\u8BF4\u5C31\u884C\u3002`,
55251
+ "",
55252
+ "\u7F3A\u51ED\u636E\u3001\u8DD1\u4E0D\u4E0B\u53BB\u7684\u65F6\u5019\u4E5F\u628A\u8BDD\u8BF4\u6E05\u695A\uFF1A\u7F3A\u7684\u662F\u54EA\u4E2A\u547D\u4EE4 / \u54EA\u4E2A\u51ED\u636E\u3001\u5728\u5E72\u54EA\u4E00\u6B65\u649E\u4E0A\u7684\u3002"
55253
+ ].join("\n");
55254
+ }
55255
+ function buildTeardownPrompt(appName, workspace = "/workspace") {
55256
+ return [
55257
+ `\u3010\u8BD5\u88C5\u6536\u5C3E\u3011\u628A\u521A\u624D\u5EFA\u7684 \`${appName}\` \u62C6\u5E72\u51C0\u3002`,
55258
+ "",
55259
+ `1. \u7528 clawd-app-builder \u7684 removeProject \u5DE5\u5177\uFF08name=${appName}\uFF09\u2014\u2014\u4E91\u4E0A\u7684\u963F\u91CC\u4E91\u51ED\u636E\u53EA\u5728\u90A3\u4E2A`,
55260
+ " \u5DE5\u5177\u7684\u8FDB\u7A0B\u91CC\uFF0C\u4F60\u81EA\u5DF1\u6572 bash \u8DD1 remove-extension.sh \u4F1A\u62A5\u300C\u7F3A ALIBABA_CLOUD_ACCESS_KEY_ID\u300D\u3002",
55261
+ " \u811A\u672C\u5982\u679C\u8BA9\u4F60\u7528 supabase MCP \u8DD1\u51E0\u6761 DROP\uFF0C\u4E00\u8D77\u8DD1\u6389\u3002",
55262
+ // 工作区是持久卷(每「使用者 × 部署」一份),跨轮活着。留着上一轮的项目目录,
55263
+ // 下一轮的 createProject 会撞名、agent 会直接接着用它 —— 于是 scaffold 那一段
55264
+ // 根本不再跑,清单里漏掉的 scaffold 依赖(rsync 就是)永远暴露不出来。
55265
+ // 这条是真机第三轮跑出来的:那一轮「通过」了,而它压根没建过项目。
55266
+ `2. \u518D\u628A\u9879\u76EE\u76EE\u5F55\u5220\u6389\uFF1A\`rm -rf ${workspace}/projects/${appName}\`\u3002`,
55267
+ " \u5DE5\u4F5C\u533A\u662F\u6301\u4E45\u5377\u3001\u8DE8\u8F6E\u6D3B\u7740\uFF0C\u7559\u7740\u5B83\u4E0B\u4E00\u8F6E\u5C31\u4E0D\u4F1A\u91CD\u65B0\u5EFA\u9879\u76EE\uFF0C\u7B49\u4E8E\u5C11\u9A8C\u4E86\u4E00\u6574\u6BB5\u3002",
55268
+ "",
55269
+ "\u6700\u540E\u4E00\u53E5\u8BDD\u544A\u8BC9\u6211\uFF1A\u62C6\u5E72\u51C0\u4E86\u6CA1\u6709\uFF0C\u8FD8\u5269\u4EC0\u4E48\u3002"
55270
+ ].join("\n");
55271
+ }
55272
+ var gap = (errorText, raw, suggest) => ({
55273
+ // 落单据的自由文本一律先过涂抹:这两段是 agent 的话和容器的原始输出,
55274
+ // 引到 `KEY=值` 那行是迟早的事(与扫描证据同一道,见 redact.ts)
55275
+ errorText: redactSecretValues(errorText),
55276
+ ...raw ? { raw: redactSecretValues(raw.slice(-RAW_TAIL_CHARS)) } : {},
55277
+ ...suggest ? { suggest } : {}
55278
+ });
55279
+ function missingFromAgentText(text) {
55280
+ const idx = text.lastIndexOf(MISSING_MARKER);
55281
+ if (idx === -1) return [];
55282
+ const line = text.slice(idx + MISSING_MARKER.length).split("\n")[0].trim();
55283
+ if (!line || /^(none|无|没有)[.。]?$/i.test(line)) return [];
55284
+ return line.replace(/[`*]/g, "").split(/[,,、]/).map((s) => s.trim()).filter((s) => s.length > 0 && s.length <= 40 && !/[\s((]/.test(s));
55285
+ }
55286
+ function gapsFromBuildOutput(r) {
55287
+ try {
55288
+ const parsed = JSON.parse(r.stdout.trim());
55289
+ if (parsed && parsed.ok === false && Array.isArray(parsed.gaps) && parsed.gaps.length > 0) {
55290
+ return parsed.gaps.map((g2) => gap(g2.errorText, g2.raw, g2.suggest));
55291
+ }
55292
+ } catch {
55293
+ }
55294
+ return [gap(
55295
+ `\u6784\u955C\u50CF\u6CA1\u6210\u529F\uFF08\u9000\u51FA\u7801 ${r.code}\uFF09\u3002`,
55296
+ `${r.stdout}
55297
+ ${r.stderr}`
55298
+ )];
55299
+ }
55300
+ async function chat(deps, args) {
55301
+ const { cloudHost } = deps;
55302
+ const ctl = new AbortController();
55303
+ const timer = setTimeout(() => ctl.abort(), args.timeoutMs);
55304
+ const notes = [];
55305
+ let text = "";
55306
+ try {
55307
+ const res = await deps.fetchImpl(`${cloudHost.gatewayUrl}/v1/chat/completions`, {
55308
+ method: "POST",
55309
+ headers: {
55310
+ "content-type": "application/json",
55311
+ authorization: `Bearer ${cloudHost.gatewayApiKey}`
55312
+ },
55313
+ body: JSON.stringify({
55314
+ model: args.deployId,
55315
+ stream: true,
55316
+ user: args.conversation,
55317
+ messages: [{ role: "user", content: args.prompt }]
55318
+ }),
55319
+ signal: ctl.signal
55320
+ });
55321
+ if (!res.ok) {
55322
+ const body = await res.text().catch(() => "");
55323
+ return { ok: false, text: `gateway \u62D2\u4E86\u8FD9\u6B21\u6295\u5582\uFF08HTTP ${res.status}\uFF09\uFF1A${body.slice(0, 500)}`, notes };
55324
+ }
55325
+ for await (const line of sseLines(res)) {
55326
+ if (line.startsWith(":")) {
55327
+ const note = line.slice(1).trim();
55328
+ if (note && !note.startsWith("clawd-gateway heartbeat")) {
55329
+ notes.push(note);
55330
+ deps.onStage(redactSecretValues(`\u8BD5\u88C5\u4E2D\uFF1A${note}`));
55331
+ }
55332
+ continue;
55333
+ }
55334
+ if (!line.startsWith("data:")) continue;
55335
+ const payload = line.slice(5).trim();
55336
+ if (payload === "[DONE]") break;
55337
+ try {
55338
+ const frame = JSON.parse(payload);
55339
+ text += frame.choices?.[0]?.delta?.content ?? "";
55340
+ } catch {
55341
+ }
55342
+ }
55343
+ } catch (err) {
55344
+ const aborted = err.name === "AbortError";
55345
+ return {
55346
+ ok: false,
55347
+ notes,
55348
+ text: aborted ? `\u7B49\u4E86 ${Math.round(args.timeoutMs / 6e4)} \u5206\u949F\uFF0C\u5BB9\u5668\u90A3\u8FB9\u8FD8\u6CA1\u8DD1\u5B8C` : `\u8DDF gateway \u8BF4\u4E0D\u4E0A\u8BDD\uFF1A${String(err)}`
55349
+ };
55350
+ } finally {
55351
+ clearTimeout(timer);
55352
+ }
55353
+ const failed = /\[gateway\]/.test(text);
55354
+ return { ok: !failed, text, notes };
55355
+ }
55356
+ async function* sseLines(res) {
55357
+ const reader = res.body?.getReader();
55358
+ if (!reader) return;
55359
+ const decoder = new TextDecoder();
55360
+ let buf = "";
55361
+ for (; ; ) {
55362
+ const { done, value } = await reader.read();
55363
+ if (done) break;
55364
+ buf += decoder.decode(value, { stream: true });
55365
+ let idx = buf.indexOf("\n");
55366
+ while (idx >= 0) {
55367
+ yield buf.slice(0, idx).trimEnd();
55368
+ buf = buf.slice(idx + 1);
55369
+ idx = buf.indexOf("\n");
55370
+ }
55371
+ }
55372
+ if (buf.trim()) yield buf.trim();
55373
+ }
55374
+ async function gatewayAdmin(deps, path98, body) {
55375
+ const res = await deps.fetchImpl(`${deps.cloudHost.gatewayUrl}${path98}`, {
55376
+ method: "POST",
55377
+ headers: {
55378
+ "content-type": "application/json",
55379
+ authorization: `Bearer ${deps.cloudHost.gatewayAdminKey}`
55380
+ },
55381
+ body: JSON.stringify(body),
55382
+ // 流水线其余每一步都有界(构建/推送有 timer、投喂有 AbortController),
55383
+ // 只有这两个 fetch 裸 await 的话,gateway 那头 TCP 挂住就没人救得了它:
55384
+ // 单据永久停在 trialing(trial 拒 trialing、启动对账只在启动时跑),得重启 daemon 才出得来。
55385
+ signal: AbortSignal.timeout(GATEWAY_ADMIN_TIMEOUT_MS)
55386
+ });
55387
+ const text = await res.text();
55388
+ if (!res.ok) throw new Error(`gateway ${path98} \u56DE\u4E86 HTTP ${res.status}\uFF1A${text.slice(0, 300)}`);
55389
+ try {
55390
+ return JSON.parse(text);
55391
+ } catch {
55392
+ throw new Error(`gateway ${path98} \u56DE\u7684\u4E0D\u662F JSON\uFF1A${text.slice(0, 300)}`);
55393
+ }
55394
+ }
55395
+ async function registerOfficialDeployment(deps, receipt, deployerSecrets) {
55396
+ const res = await gatewayAdmin(deps, "/admin/deployments", {
55397
+ deployId: receipt.deployId,
55398
+ personaId: receipt.personaId,
55399
+ image: receipt.trialImage,
55400
+ kind: "official",
55401
+ secrets: deployerSecrets,
55402
+ userSecrets: userSecretsOf(receipt)
55403
+ });
55404
+ const service = res.service ?? {};
55405
+ if (!service.deviceId || !service.publicUrl) {
55406
+ throw new Error(`gateway \u767B\u8BB0\u6210\u529F\u4E86\uFF0C\u4F46\u6CA1\u56DE\u670D\u52A1\u8EAB\u4EFD\uFF08deviceId / publicUrl\uFF09\uFF1A${JSON.stringify(res).slice(0, 300)}`);
55407
+ }
55408
+ return {
55409
+ gatewayUrl: deps.cloudHost.gatewayUrl,
55410
+ serviceDeviceId: service.deviceId,
55411
+ publicDirectory: Boolean(service.isPublic),
55412
+ image: receipt.trialImage,
55413
+ userSecrets: userSecretsOf(receipt).map((s) => s.name),
55414
+ deployedAt: deps.now()
55415
+ };
55416
+ }
55417
+ async function runTrial(deps, args) {
55418
+ const { receipt, round } = args;
55419
+ const { cloudHost } = deps;
55420
+ const manifest = receipt.manifest;
55421
+ const stamp = trialStamp(deps.now());
55422
+ const trialId = trialDeployId(receipt.deployId, round, stamp);
55423
+ const image = trialImageTag(cloudHost.imageRepo, receipt.deployId, round, stamp);
55424
+ const appName = trialAppName(receipt.deployId);
55425
+ const deadline = deps.now() + cloudHost.trialTimeoutMs;
55426
+ const left = () => Math.max(3e4, deadline - deps.now());
55427
+ deps.onStage("\u5728\u6309\u6E05\u5355\u6784\u955C\u50CF");
55428
+ const manifestFile = import_node_path33.default.join(import_node_os8.default.tmpdir(), `clawd-trial-${receipt.deployId}-t${round}-${stamp}.json`);
55429
+ let built;
55430
+ try {
55431
+ await import_promises7.default.writeFile(manifestFile, JSON.stringify({ manifest }, null, 2), { mode: 384 });
55432
+ built = await deps.runNode(
55433
+ `${cloudHost.provisionDir}/build-image.mjs`,
55434
+ ["--manifest", manifestFile, "--tag", image, "--platform", "linux/amd64"],
55435
+ { timeoutMs: left() }
55436
+ );
55437
+ await import_promises7.default.rm(manifestFile, { force: true });
55438
+ } catch (err) {
55439
+ return { ok: false, spent: false, gaps: [gap(`\u6784\u955C\u50CF\u8FD9\u4E00\u6B65\u8D77\u4E0D\u6765\uFF1A${String(err)}`)] };
55440
+ }
55441
+ if (built.code !== 0) return { ok: false, spent: false, gaps: gapsFromBuildOutput(built) };
55442
+ deps.onStage("\u628A\u955C\u50CF\u63A8\u5230\u4E91\u4E0A\u90A3\u53F0\u673A\u5668");
55443
+ const pushed = await deps.runNode(
55444
+ `${cloudHost.provisionDir}/push-to-k3s.mjs`,
55445
+ ["--host", cloudHost.k3sHost, "--key", cloudHost.k3sKeyPath, "--image", image],
55446
+ { timeoutMs: left() }
55447
+ );
55448
+ if (pushed.code !== 0) {
55449
+ return { ok: false, spent: false, gaps: [gap(`\u955C\u50CF\u63A8\u4E0D\u4E0A\u53BB\uFF08\u9000\u51FA\u7801 ${pushed.code}\uFF09\u3002`, `${pushed.stdout}
55450
+ ${pushed.stderr}`)] };
55451
+ }
55452
+ deps.onStage("\u5728\u4E91\u4E0A\u767B\u8BB0\u8FD9\u6B21\u8BD5\u88C5");
55453
+ try {
55454
+ await gatewayAdmin(deps, "/admin/deployments", {
55455
+ deployId: trialId,
55456
+ personaId: receipt.personaId,
55457
+ image,
55458
+ kind: "trial",
55459
+ secrets: args.secretTable,
55460
+ userSecrets: []
55461
+ });
55462
+ } catch (err) {
55463
+ return { ok: false, spent: false, gaps: [gap(`gateway \u4E0D\u6536\u8FD9\u4EFD\u8BD5\u88C5\u767B\u8BB0\uFF1A${String(err)}`)] };
55464
+ }
55465
+ try {
55466
+ deps.onStage("\u5192\u70DF\u4EFB\u52A1\u5DF2\u7ECF\u6295\u7ED9\u5B83\u4E86");
55467
+ const smoke = await chat(deps, {
55468
+ deployId: trialId,
55469
+ conversation: trialConversation(receipt.deployId, round, stamp),
55470
+ prompt: buildSmokePrompt(receipt.smokeTask ?? "\u5EFA\u4E00\u4E2A\u6700\u5C0F\u7684\u5E94\u7528\u5E76\u53D1\u5E03\u4E0A\u7EBF\uFF0C\u628A\u516C\u7F51\u5730\u5740\u56DE\u7ED9\u6211", appName),
55471
+ timeoutMs: left()
55472
+ });
55473
+ deps.onStage("\u8BA9\u5B83\u628A\u8BD5\u88C5\u5EFA\u51FA\u6765\u7684\u4E1C\u897F\u62C6\u6389");
55474
+ const teardown = await chat(deps, {
55475
+ deployId: trialId,
55476
+ conversation: trialConversation(receipt.deployId, round, stamp),
55477
+ prompt: buildTeardownPrompt(appName),
55478
+ timeoutMs: Math.min(left(), 15 * 6e4)
55479
+ });
55480
+ if (!smoke.ok) {
55481
+ return {
55482
+ ok: false,
55483
+ spent: true,
55484
+ gaps: [
55485
+ gap(smoke.text.trim() || "\u5BB9\u5668\u91CC\u90A3\u4E2A persona \u6CA1\u8BF4\u6E05\u695A\u4E3A\u4EC0\u4E48\u6CA1\u8DD1\u5B8C", smoke.notes.slice(-20).join("\n")),
55486
+ ...teardown.ok ? [] : [gap(`\u987A\u5E26\uFF1A\u8BD5\u88C5\u4EA7\u7269\u6CA1\u62C6\u5E72\u51C0\u2014\u2014${teardown.text.trim()}`)]
55487
+ ]
55488
+ };
55489
+ }
55490
+ if (!teardown.ok) {
55491
+ return { ok: false, spent: true, gaps: [gap(`\u5E94\u7528\u5EFA\u51FA\u6765\u5E76\u53D1\u5E03\u6210\u529F\u4E86\uFF0C\u4F46\u62C6\u4E0D\u5E72\u51C0\uFF1A${teardown.text.trim()}`, teardown.notes.slice(-20).join("\n"))] };
55492
+ }
55493
+ const missing = missingFromAgentText(smoke.text);
55494
+ if (missing.length > 0) {
55495
+ return {
55496
+ ok: false,
55497
+ spent: true,
55498
+ gaps: missing.map((name) => gap(
55499
+ `\u5BB9\u5668\u91CC\u6CA1\u6709 \`${name}\`\uFF0C\u662F\u5B83\u81EA\u5DF1\u52A8\u624B\u8865\u4E0A\u624D\u8DD1\u4E0B\u53BB\u7684\u2014\u2014\u6E05\u5355\u91CC\u6F0F\u4E86\u8FD9\u6761\uFF0C\u4E0B\u4E00\u4E2A\u5BB9\u5668\u7167\u6837\u7F3A\u3002`,
55500
+ smoke.text.slice(-RAW_TAIL_CHARS),
55501
+ `cli:${name}`
55502
+ ))
55503
+ };
55504
+ }
55505
+ deps.logger?.info("deploy.trial.passed", { deployId: receipt.deployId, round, image });
55506
+ const url = /https?:\/\/[^\s)"',。]+/.exec(smoke.text)?.[0];
55507
+ return { ok: true, image, ...url ? { publicUrl: url } : {} };
55508
+ } finally {
55509
+ deps.onStage("\u6536\u5C3E\uFF1A\u64A4\u9500\u8FD9\u6B21\u8BD5\u88C5\u7684\u767B\u8BB0");
55510
+ await gatewayAdmin(deps, "/admin/deployments:remove", { deployId: trialId }).catch((err) => {
55511
+ deps.logger?.warn("deploy.trial.unregister-failed", { deployId: receipt.deployId, error: String(err) });
55512
+ });
55513
+ }
55514
+ }
55515
+
55516
+ // src/deploy/run-node.ts
55517
+ var import_node_child_process8 = require("child_process");
55518
+ async function runNodeScript(script, args, timeoutMs) {
55519
+ return await new Promise((resolve9, reject) => {
55520
+ const child = (0, import_node_child_process8.spawn)(process.execPath, [script, ...args], { stdio: ["ignore", "pipe", "pipe"] });
55521
+ let stdout = "";
55522
+ let stderr = "";
55523
+ child.stdout.on("data", (d) => {
55524
+ stdout += d.toString("utf8");
55525
+ });
55526
+ child.stderr.on("data", (d) => {
55527
+ stderr += d.toString("utf8");
55528
+ });
55529
+ const timer = setTimeout(() => {
55530
+ child.kill("SIGKILL");
55531
+ stderr += `
55532
+ [clawd] \u8D85\u65F6\uFF08>${Math.round(timeoutMs / 1e3)}s\uFF09\uFF0C\u5DF2\u7ECF\u628A\u5B83\u6390\u4E86
55533
+ `;
55534
+ }, timeoutMs);
55535
+ child.on("error", (err) => {
55536
+ clearTimeout(timer);
55537
+ reject(new Error(`\u8D77\u4E0D\u6765 ${script}\uFF1A${err.message}`));
55538
+ });
55539
+ child.on("close", (code) => {
55540
+ clearTimeout(timer);
55541
+ resolve9({ code, stdout, stderr });
55542
+ });
55543
+ });
55544
+ }
55545
+
54997
55546
  // src/deploy/scan-task.ts
54998
55547
  var BUTLER_PERSONA_ID = "persona-clawd-butler";
54999
55548
  var SCANNABLE_ASSETS = ["deploy-kit"];
@@ -55011,6 +55560,17 @@ function reconcileInterruptedScans(deps) {
55011
55560
  }
55012
55561
  return stale.map((r) => r.deployId);
55013
55562
  }
55563
+ function reconcileInterruptedTrials(deps) {
55564
+ const stale = deps.list().filter((r) => r.status === "trialing");
55565
+ for (const r of stale) {
55566
+ deps.update(r.deployId, {
55567
+ status: "failed",
55568
+ trialStage: void 0,
55569
+ gaps: [{ errorText: "daemon \u91CD\u542F\uFF0C\u8FD9\u4E00\u8F6E\u8BD5\u88C5\u88AB\u6253\u65AD\u4E86\u2014\u2014\u6CA1\u7ED3\u8BBA\uFF0C\u91CD\u8DD1\u4E00\u6B21\u5373\u53EF\u3002" }]
55570
+ });
55571
+ }
55572
+ return stale.map((r) => r.deployId);
55573
+ }
55014
55574
 
55015
55575
  // src/handlers/lark-bot.ts
55016
55576
  init_protocol();
@@ -55400,9 +55960,9 @@ async function refreshTunnelUrlOnStartup(deps) {
55400
55960
 
55401
55961
  // src/lark-bot-connector/binding-store.ts
55402
55962
  var import_node_fs28 = __toESM(require("fs"), 1);
55403
- var import_node_path32 = __toESM(require("path"), 1);
55963
+ var import_node_path34 = __toESM(require("path"), 1);
55404
55964
  function createLarkBotBindingStore(personaRoot) {
55405
- const filePath = (personaId2) => import_node_path32.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
55965
+ const filePath = (personaId2) => import_node_path34.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
55406
55966
  const read = (personaId2) => {
55407
55967
  const file = filePath(personaId2);
55408
55968
  if (!import_node_fs28.default.existsSync(file)) return null;
@@ -55416,7 +55976,7 @@ function createLarkBotBindingStore(personaRoot) {
55416
55976
  };
55417
55977
  const write = (personaId2, meta) => {
55418
55978
  const file = filePath(personaId2);
55419
- import_node_fs28.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
55979
+ import_node_fs28.default.mkdirSync(import_node_path34.default.dirname(file), { recursive: true });
55420
55980
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
55421
55981
  import_node_fs28.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
55422
55982
  import_node_fs28.default.renameSync(tmp, file);
@@ -55584,7 +56144,7 @@ function createLarkBotCloudClient(opts) {
55584
56144
 
55585
56145
  // src/lark-bot-connector/chat-router.ts
55586
56146
  var import_node_fs29 = __toESM(require("fs"), 1);
55587
- var import_node_path33 = __toESM(require("path"), 1);
56147
+ var import_node_path35 = __toESM(require("path"), 1);
55588
56148
  init_protocol();
55589
56149
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
55590
56150
  var LOCAL_TURN_RETRIES = 2;
@@ -55651,7 +56211,7 @@ function createLarkChatRouter(deps) {
55651
56211
  }
55652
56212
  const dir = deps.mediaRootFor(env.chatId);
55653
56213
  import_node_fs29.default.mkdirSync(dir, { recursive: true });
55654
- const p2 = import_node_path33.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
56214
+ const p2 = import_node_path35.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
55655
56215
  import_node_fs29.default.writeFileSync(p2, r.data);
55656
56216
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
55657
56217
  } catch (err) {
@@ -55674,7 +56234,7 @@ function createLarkChatRouter(deps) {
55674
56234
  }
55675
56235
  const dir = deps.mediaRootFor(env.chatId);
55676
56236
  import_node_fs29.default.mkdirSync(dir, { recursive: true });
55677
- const p2 = import_node_path33.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
56237
+ const p2 = import_node_path35.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
55678
56238
  import_node_fs29.default.writeFileSync(p2, r.data);
55679
56239
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
55680
56240
  } catch (err) {
@@ -56764,7 +57324,7 @@ var CodexHistoryReader = class {
56764
57324
  };
56765
57325
 
56766
57326
  // src/tools/codex-skills.ts
56767
- var import_node_path34 = __toESM(require("path"), 1);
57327
+ var import_node_path36 = __toESM(require("path"), 1);
56768
57328
  function str3(v2) {
56769
57329
  return typeof v2 === "string" ? v2 : void 0;
56770
57330
  }
@@ -56779,13 +57339,13 @@ function mapSkillsListResponse(res) {
56779
57339
  const r = s ?? {};
56780
57340
  const name = str3(r.name);
56781
57341
  if (!name) continue;
56782
- const path96 = str3(r.path);
57342
+ const path98 = str3(r.path);
56783
57343
  const description = str3(r.description);
56784
57344
  const isPlugin = name.includes(":");
56785
57345
  out.push({
56786
57346
  name,
56787
57347
  source: isPlugin ? "plugin" : "project",
56788
- ...path96 ? { path: path96 } : {},
57348
+ ...path98 ? { path: path98 } : {},
56789
57349
  ...description ? { description } : {},
56790
57350
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
56791
57351
  });
@@ -56801,14 +57361,14 @@ async function listCodexSkills(cwd, deps = {}) {
56801
57361
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
56802
57362
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
56803
57363
  beforeRequest: (client) => {
56804
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path34.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
57364
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path36.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
56805
57365
  }
56806
57366
  });
56807
57367
  return mapSkillsListResponse(res);
56808
57368
  }
56809
57369
 
56810
57370
  // src/tools/codex-turn-context.ts
56811
- var import_promises6 = __toESM(require("fs/promises"), 1);
57371
+ var import_promises8 = __toESM(require("fs/promises"), 1);
56812
57372
  function parseTurnContextFromRollout(raw) {
56813
57373
  const lines = raw.split("\n");
56814
57374
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -56843,7 +57403,7 @@ async function readCodexTurnContext(args, deps = {}) {
56843
57403
  );
56844
57404
  const rolloutPath = str4(rec3(res?.thread)?.path);
56845
57405
  if (!rolloutPath) return null;
56846
- return parseTurnContextFromRollout(await import_promises6.default.readFile(rolloutPath, "utf8"));
57406
+ return parseTurnContextFromRollout(await import_promises8.default.readFile(rolloutPath, "utf8"));
56847
57407
  }
56848
57408
  function createCodexResolvedMetaHydrator(deps) {
56849
57409
  const fetchedThreadIds = /* @__PURE__ */ new Set();
@@ -56887,15 +57447,15 @@ function str4(v2) {
56887
57447
 
56888
57448
  // src/workspace/browser.ts
56889
57449
  var import_node_fs30 = __toESM(require("fs"), 1);
56890
- var import_node_os8 = __toESM(require("os"), 1);
56891
- var import_node_path35 = __toESM(require("path"), 1);
57450
+ var import_node_os9 = __toESM(require("os"), 1);
57451
+ var import_node_path37 = __toESM(require("path"), 1);
56892
57452
  init_protocol();
56893
57453
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
56894
57454
  function resolveInsideCwd(cwd, subpath) {
56895
- const absCwd = import_node_path35.default.resolve(cwd);
56896
- const joined = import_node_path35.default.resolve(absCwd, subpath ?? ".");
56897
- const rel = import_node_path35.default.relative(absCwd, joined);
56898
- if (rel.startsWith("..") || import_node_path35.default.isAbsolute(rel)) {
57455
+ const absCwd = import_node_path37.default.resolve(cwd);
57456
+ const joined = import_node_path37.default.resolve(absCwd, subpath ?? ".");
57457
+ const rel = import_node_path37.default.relative(absCwd, joined);
57458
+ if (rel.startsWith("..") || import_node_path37.default.isAbsolute(rel)) {
56899
57459
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
56900
57460
  }
56901
57461
  return joined;
@@ -56913,7 +57473,7 @@ function ensureCwd(cwd) {
56913
57473
  }
56914
57474
  var WorkspaceBrowser = class {
56915
57475
  list(args) {
56916
- const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
57476
+ const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os9.default.homedir();
56917
57477
  ensureCwd(cwd);
56918
57478
  const full = resolveInsideCwd(cwd, args.path);
56919
57479
  const dirents = import_node_fs30.default.readdirSync(full, { withFileTypes: true });
@@ -56926,7 +57486,7 @@ var WorkspaceBrowser = class {
56926
57486
  mtime: ""
56927
57487
  };
56928
57488
  try {
56929
- const st = import_node_fs30.default.statSync(import_node_path35.default.join(full, d.name));
57489
+ const st = import_node_fs30.default.statSync(import_node_path37.default.join(full, d.name));
56930
57490
  entry.mtime = new Date(st.mtimeMs).toISOString();
56931
57491
  if (d.isFile()) entry.size = st.size;
56932
57492
  } catch {
@@ -56972,8 +57532,8 @@ var WorkspaceBrowser = class {
56972
57532
 
56973
57533
  // src/skills/agents-scanner.ts
56974
57534
  var import_node_fs31 = __toESM(require("fs"), 1);
56975
- var import_node_os9 = __toESM(require("os"), 1);
56976
- var import_node_path36 = __toESM(require("path"), 1);
57535
+ var import_node_os10 = __toESM(require("os"), 1);
57536
+ var import_node_path38 = __toESM(require("path"), 1);
56977
57537
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
56978
57538
  function isDirLikeSync2(p2) {
56979
57539
  try {
@@ -57011,10 +57571,10 @@ function scanAgentsDir(dir, source, seen, out) {
57011
57571
  }
57012
57572
  for (const ent of entries) {
57013
57573
  if (!ent.name.endsWith(".md")) continue;
57014
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path36.default.join(dir, ent.name)))) {
57574
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path38.default.join(dir, ent.name)))) {
57015
57575
  continue;
57016
57576
  }
57017
- const filePath = import_node_path36.default.join(dir, ent.name);
57577
+ const filePath = import_node_path38.default.join(dir, ent.name);
57018
57578
  const baseName = ent.name.replace(/\.md$/, "");
57019
57579
  if (seen.has(baseName)) continue;
57020
57580
  seen.add(baseName);
@@ -57037,7 +57597,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
57037
57597
  return;
57038
57598
  }
57039
57599
  for (const ent of entries) {
57040
- const childPath = import_node_path36.default.join(dir, ent.name);
57600
+ const childPath = import_node_path38.default.join(dir, ent.name);
57041
57601
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
57042
57602
  walk2(childPath, [...namespaces, ent.name]);
57043
57603
  continue;
@@ -57062,9 +57622,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
57062
57622
  walk2(root, []);
57063
57623
  }
57064
57624
  function readInstalledPlugins2(home) {
57065
- const pluginsDir = import_node_path36.default.join(home, ".claude", "plugins");
57066
- const v2 = import_node_path36.default.join(pluginsDir, "installed_plugins_v2.json");
57067
- const v1 = import_node_path36.default.join(pluginsDir, "installed_plugins.json");
57625
+ const pluginsDir = import_node_path38.default.join(home, ".claude", "plugins");
57626
+ const v2 = import_node_path38.default.join(pluginsDir, "installed_plugins_v2.json");
57627
+ const v1 = import_node_path38.default.join(pluginsDir, "installed_plugins.json");
57068
57628
  let raw = null;
57069
57629
  for (const candidate of [v2, v1]) {
57070
57630
  try {
@@ -57093,19 +57653,19 @@ function readInstalledPlugins2(home) {
57093
57653
  return out;
57094
57654
  }
57095
57655
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
57096
- let cur = import_node_path36.default.resolve(startCwd);
57097
- const fsRoot = import_node_path36.default.parse(cur).root;
57656
+ let cur = import_node_path38.default.resolve(startCwd);
57657
+ const fsRoot = import_node_path38.default.parse(cur).root;
57098
57658
  while (true) {
57099
- scanAgentsDir(import_node_path36.default.join(cur, ".claude", "agents"), "project", seen, out);
57659
+ scanAgentsDir(import_node_path38.default.join(cur, ".claude", "agents"), "project", seen, out);
57100
57660
  let hasGit = false;
57101
57661
  try {
57102
- hasGit = import_node_fs31.default.existsSync(import_node_path36.default.join(cur, ".git"));
57662
+ hasGit = import_node_fs31.default.existsSync(import_node_path38.default.join(cur, ".git"));
57103
57663
  } catch {
57104
57664
  }
57105
57665
  if (hasGit) return;
57106
57666
  if (cur === home) return;
57107
57667
  if (cur === fsRoot) return;
57108
- const parent = import_node_path36.default.dirname(cur);
57668
+ const parent = import_node_path38.default.dirname(cur);
57109
57669
  if (parent === cur) return;
57110
57670
  cur = parent;
57111
57671
  }
@@ -57115,7 +57675,7 @@ var AgentsScanner = class {
57115
57675
  extraPluginRoots;
57116
57676
  policyDir;
57117
57677
  constructor(opts = {}) {
57118
- this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os9.default.homedir();
57678
+ this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os10.default.homedir();
57119
57679
  this.extraPluginRoots = opts.extraPluginRoots ?? [];
57120
57680
  if (opts.policyDir !== void 0) {
57121
57681
  this.policyDir = opts.policyDir;
@@ -57140,7 +57700,7 @@ var AgentsScanner = class {
57140
57700
  }
57141
57701
  const fsBlock = [];
57142
57702
  scanAgentsDir(
57143
- import_node_path36.default.join(this.home, ".claude", "agents"),
57703
+ import_node_path38.default.join(this.home, ".claude", "agents"),
57144
57704
  "global",
57145
57705
  seen,
57146
57706
  fsBlock
@@ -57154,7 +57714,7 @@ var AgentsScanner = class {
57154
57714
  ...this.extraPluginRoots
57155
57715
  ];
57156
57716
  for (const { name, root } of plugins) {
57157
- const agentsRoot = import_node_path36.default.join(root, "agents");
57717
+ const agentsRoot = import_node_path38.default.join(root, "agents");
57158
57718
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
57159
57719
  }
57160
57720
  return [...builtinBlock, ...fsBlock];
@@ -57163,27 +57723,27 @@ var AgentsScanner = class {
57163
57723
 
57164
57724
  // src/observer/session-observer.ts
57165
57725
  var import_node_fs33 = __toESM(require("fs"), 1);
57166
- var import_node_os11 = __toESM(require("os"), 1);
57167
- var import_node_path38 = __toESM(require("path"), 1);
57726
+ var import_node_os12 = __toESM(require("os"), 1);
57727
+ var import_node_path40 = __toESM(require("path"), 1);
57168
57728
  init_claude_history();
57169
57729
 
57170
57730
  // src/observer/subagent-meta-observer.ts
57171
57731
  var import_node_fs32 = __toESM(require("fs"), 1);
57172
- var import_node_os10 = __toESM(require("os"), 1);
57173
- var import_node_path37 = __toESM(require("path"), 1);
57732
+ var import_node_os11 = __toESM(require("os"), 1);
57733
+ var import_node_path39 = __toESM(require("path"), 1);
57174
57734
  init_claude_history();
57175
57735
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
57176
57736
  var SubagentMetaObserver = class {
57177
57737
  constructor(opts) {
57178
57738
  this.opts = opts;
57179
- this.home = opts.home ?? import_node_os10.default.homedir();
57739
+ this.home = opts.home ?? import_node_os11.default.homedir();
57180
57740
  }
57181
57741
  opts;
57182
57742
  home;
57183
57743
  watches = /* @__PURE__ */ new Map();
57184
57744
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
57185
57745
  resolveSubagentDir(cwd, toolSessionId) {
57186
- return import_node_path37.default.join(
57746
+ return import_node_path39.default.join(
57187
57747
  this.home,
57188
57748
  ".claude",
57189
57749
  "projects",
@@ -57239,7 +57799,7 @@ var SubagentMetaObserver = class {
57239
57799
  if (!m2) return;
57240
57800
  const agentId = m2[1];
57241
57801
  if (w2.emitted.has(agentId)) return;
57242
- const file = import_node_path37.default.join(w2.dirPath, name);
57802
+ const file = import_node_path39.default.join(w2.dirPath, name);
57243
57803
  let raw;
57244
57804
  try {
57245
57805
  raw = import_node_fs32.default.readFileSync(file, "utf8");
@@ -57287,7 +57847,7 @@ var SubagentMetaObserver = class {
57287
57847
  var SessionObserver = class {
57288
57848
  constructor(opts) {
57289
57849
  this.opts = opts;
57290
- this.home = opts.home ?? import_node_os11.default.homedir();
57850
+ this.home = opts.home ?? import_node_os12.default.homedir();
57291
57851
  this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
57292
57852
  }
57293
57853
  opts;
@@ -57299,7 +57859,7 @@ var SessionObserver = class {
57299
57859
  metaObserver;
57300
57860
  resolveJsonlPath(cwd, toolSessionId, override) {
57301
57861
  if (override) return override;
57302
- return import_node_path38.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
57862
+ return import_node_path40.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
57303
57863
  }
57304
57864
  start(args) {
57305
57865
  this.stop(args.sessionId);
@@ -57325,10 +57885,10 @@ var SessionObserver = class {
57325
57885
  lastDeriveMs: 0
57326
57886
  };
57327
57887
  try {
57328
- import_node_fs33.default.mkdirSync(import_node_path38.default.dirname(filePath), { recursive: true });
57888
+ import_node_fs33.default.mkdirSync(import_node_path40.default.dirname(filePath), { recursive: true });
57329
57889
  } catch {
57330
57890
  }
57331
- w2.watcher = import_node_fs33.default.watch(import_node_path38.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
57891
+ w2.watcher = import_node_fs33.default.watch(import_node_path40.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
57332
57892
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
57333
57893
  this.poll(w2);
57334
57894
  });
@@ -57425,7 +57985,7 @@ var SessionObserver = class {
57425
57985
  const now = Date.now();
57426
57986
  if (now - w2.lastRelocateScanMs < 1e3) return;
57427
57987
  w2.lastRelocateScanMs = now;
57428
- const projectsRoot = import_node_path38.default.join(this.home, ".claude", "projects");
57988
+ const projectsRoot = import_node_path40.default.join(this.home, ".claude", "projects");
57429
57989
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
57430
57990
  if (!found || found === w2.filePath) return;
57431
57991
  try {
@@ -57434,7 +57994,7 @@ var SessionObserver = class {
57434
57994
  }
57435
57995
  w2.filePath = found;
57436
57996
  try {
57437
- w2.watcher = import_node_fs33.default.watch(import_node_path38.default.dirname(found), { persistent: false }, (_event, changedName) => {
57997
+ w2.watcher = import_node_fs33.default.watch(import_node_path40.default.dirname(found), { persistent: false }, (_event, changedName) => {
57438
57998
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
57439
57999
  this.poll(w2);
57440
58000
  });
@@ -57554,10 +58114,10 @@ function listRegistered() {
57554
58114
  }
57555
58115
 
57556
58116
  // src/tools/title-generator.ts
57557
- var import_node_child_process8 = require("child_process");
58117
+ var import_node_child_process9 = require("child_process");
57558
58118
  var import_node_fs34 = __toESM(require("fs"), 1);
57559
- var import_node_os12 = __toESM(require("os"), 1);
57560
- var import_node_path39 = __toESM(require("path"), 1);
58119
+ var import_node_os13 = __toESM(require("os"), 1);
58120
+ var import_node_path41 = __toESM(require("path"), 1);
57561
58121
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
57562
58122
  var TITLE_MODEL_BY_TOOL = {
57563
58123
  claude: "haiku",
@@ -57628,7 +58188,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57628
58188
  if (!text) return null;
57629
58189
  let workDir;
57630
58190
  try {
57631
- workDir = import_node_fs34.default.mkdtempSync(import_node_path39.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
58191
+ workDir = import_node_fs34.default.mkdtempSync(import_node_path41.default.join(import_node_os13.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
57632
58192
  } catch {
57633
58193
  return null;
57634
58194
  }
@@ -57638,8 +58198,8 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57638
58198
  } catch {
57639
58199
  }
57640
58200
  };
57641
- const outFile = import_node_path39.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
57642
- const schemaFile = import_node_path39.default.join(workDir, "title-schema.json");
58201
+ const outFile = import_node_path41.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
58202
+ const schemaFile = import_node_path41.default.join(workDir, "title-schema.json");
57643
58203
  if (tool === "codex") {
57644
58204
  try {
57645
58205
  import_node_fs34.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
@@ -57650,7 +58210,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57650
58210
  }
57651
58211
  const cmd = tool === "claude" ? process.env.CLAUDE_BIN ?? "claude" : process.env.CODEX_BIN ?? "codex";
57652
58212
  const args = tool === "claude" ? buildClaudeTitleArgs(buildClaudeTitlePrompt(text)) : buildCodexTitleArgs(buildTitlePrompt(text), outFile, schemaFile);
57653
- const doSpawn = deps.spawnOverride ?? ((c, a, o) => (0, import_node_child_process8.spawn)(c, a, { ...o, stdio: ["ignore", "pipe", "pipe"] }));
58213
+ const doSpawn = deps.spawnOverride ?? ((c, a, o) => (0, import_node_child_process9.spawn)(c, a, { ...o, stdio: ["ignore", "pipe", "pipe"] }));
57654
58214
  const timeoutMs = deps.timeoutMs ?? DEFAULT_TITLE_GEN_TIMEOUT_MS;
57655
58215
  return await new Promise((resolve9) => {
57656
58216
  let proc;
@@ -58393,8 +58953,8 @@ async function authenticate(token, deps) {
58393
58953
  }
58394
58954
 
58395
58955
  // src/legacy-cleanup.ts
58396
- var fs45 = __toESM(require("fs/promises"), 1);
58397
- var path47 = __toESM(require("path"), 1);
58956
+ var fs47 = __toESM(require("fs/promises"), 1);
58957
+ var path49 = __toESM(require("path"), 1);
58398
58958
  var LEGACY_FILES = [
58399
58959
  "personal-capability.json",
58400
58960
  "received-capabilities.json",
@@ -58403,9 +58963,9 @@ var LEGACY_FILES = [
58403
58963
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
58404
58964
  const removed = [];
58405
58965
  for (const name of LEGACY_FILES) {
58406
- const p2 = path47.join(dataDir, name);
58966
+ const p2 = path49.join(dataDir, name);
58407
58967
  try {
58408
- await fs45.unlink(p2);
58968
+ await fs47.unlink(p2);
58409
58969
  removed.push(name);
58410
58970
  logger.debug("legacy capability file removed", { file: name });
58411
58971
  } catch (err) {
@@ -58417,13 +58977,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
58417
58977
  }
58418
58978
 
58419
58979
  // src/inbox/inbox-store.ts
58420
- var fs46 = __toESM(require("fs"), 1);
58421
- var path48 = __toESM(require("path"), 1);
58980
+ var fs48 = __toESM(require("fs"), 1);
58981
+ var path50 = __toESM(require("path"), 1);
58422
58982
  var INBOX_SUBDIR = "inbox";
58423
58983
  var InboxStore = class {
58424
58984
  constructor(dataDir) {
58425
58985
  this.dataDir = dataDir;
58426
- fs46.mkdirSync(this.dirPath(), { recursive: true });
58986
+ fs48.mkdirSync(this.dirPath(), { recursive: true });
58427
58987
  }
58428
58988
  dataDir;
58429
58989
  /**
@@ -58435,7 +58995,7 @@ var InboxStore = class {
58435
58995
  const file = this.filePath(peerDeviceId);
58436
58996
  let raw;
58437
58997
  try {
58438
- raw = fs46.readFileSync(file, "utf8");
58998
+ raw = fs48.readFileSync(file, "utf8");
58439
58999
  } catch (err) {
58440
59000
  if (err?.code === "ENOENT") return [];
58441
59001
  return [];
@@ -58451,7 +59011,7 @@ var InboxStore = class {
58451
59011
  const dir = this.dirPath();
58452
59012
  let entries;
58453
59013
  try {
58454
- entries = fs46.readdirSync(dir);
59014
+ entries = fs48.readdirSync(dir);
58455
59015
  } catch (err) {
58456
59016
  if (err?.code === "ENOENT") return [];
58457
59017
  return [];
@@ -58467,9 +59027,9 @@ var InboxStore = class {
58467
59027
  if (existing.some((m2) => m2.id === message.id)) return;
58468
59028
  const file = this.filePath(message.peerDeviceId);
58469
59029
  const line = JSON.stringify(message) + "\n";
58470
- fs46.appendFileSync(file, line, { mode: 384 });
59030
+ fs48.appendFileSync(file, line, { mode: 384 });
58471
59031
  try {
58472
- fs46.chmodSync(file, 384);
59032
+ fs48.chmodSync(file, 384);
58473
59033
  } catch {
58474
59034
  }
58475
59035
  }
@@ -58499,7 +59059,7 @@ var InboxStore = class {
58499
59059
  removeByPeerDeviceId(peerDeviceId) {
58500
59060
  const file = this.filePath(peerDeviceId);
58501
59061
  try {
58502
- fs46.unlinkSync(file);
59062
+ fs48.unlinkSync(file);
58503
59063
  } catch (err) {
58504
59064
  if (err?.code === "ENOENT") return;
58505
59065
  }
@@ -58508,18 +59068,18 @@ var InboxStore = class {
58508
59068
  const file = this.filePath(peerDeviceId);
58509
59069
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
58510
59070
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
58511
- fs46.writeFileSync(tmp, content, { mode: 384 });
58512
- fs46.renameSync(tmp, file);
59071
+ fs48.writeFileSync(tmp, content, { mode: 384 });
59072
+ fs48.renameSync(tmp, file);
58513
59073
  try {
58514
- fs46.chmodSync(file, 384);
59074
+ fs48.chmodSync(file, 384);
58515
59075
  } catch {
58516
59076
  }
58517
59077
  }
58518
59078
  dirPath() {
58519
- return path48.join(this.dataDir, INBOX_SUBDIR);
59079
+ return path50.join(this.dataDir, INBOX_SUBDIR);
58520
59080
  }
58521
59081
  filePath(peerDeviceId) {
58522
- return path48.join(this.dirPath(), `${peerDeviceId}.jsonl`);
59082
+ return path50.join(this.dirPath(), `${peerDeviceId}.jsonl`);
58523
59083
  }
58524
59084
  };
58525
59085
  function parseAllLines(raw) {
@@ -58607,8 +59167,8 @@ var InboxManager = class {
58607
59167
  };
58608
59168
 
58609
59169
  // src/state/contact-store.ts
58610
- var fs47 = __toESM(require("fs"), 1);
58611
- var path49 = __toESM(require("path"), 1);
59170
+ var fs49 = __toESM(require("fs"), 1);
59171
+ var path51 = __toESM(require("path"), 1);
58612
59172
  var FILE_NAME = "contacts.json";
58613
59173
  var ContactStore = class {
58614
59174
  constructor(dataDir) {
@@ -58618,10 +59178,10 @@ var ContactStore = class {
58618
59178
  contacts = /* @__PURE__ */ new Map();
58619
59179
  load() {
58620
59180
  this.contacts.clear();
58621
- const file = path49.join(this.dataDir, FILE_NAME);
59181
+ const file = path51.join(this.dataDir, FILE_NAME);
58622
59182
  let raw;
58623
59183
  try {
58624
- raw = fs47.readFileSync(file, "utf8");
59184
+ raw = fs49.readFileSync(file, "utf8");
58625
59185
  } catch (err) {
58626
59186
  if (err?.code !== "ENOENT") this.renameBak(file);
58627
59187
  return;
@@ -58702,20 +59262,20 @@ var ContactStore = class {
58702
59262
  return true;
58703
59263
  }
58704
59264
  flush() {
58705
- const file = path49.join(this.dataDir, FILE_NAME);
59265
+ const file = path51.join(this.dataDir, FILE_NAME);
58706
59266
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
58707
59267
  const content = JSON.stringify(
58708
59268
  { contacts: Array.from(this.contacts.values()) },
58709
59269
  null,
58710
59270
  2
58711
59271
  );
58712
- fs47.mkdirSync(this.dataDir, { recursive: true });
58713
- fs47.writeFileSync(tmp, content, { mode: 384 });
58714
- fs47.renameSync(tmp, file);
59272
+ fs49.mkdirSync(this.dataDir, { recursive: true });
59273
+ fs49.writeFileSync(tmp, content, { mode: 384 });
59274
+ fs49.renameSync(tmp, file);
58715
59275
  }
58716
59276
  renameBak(file) {
58717
59277
  try {
58718
- fs47.renameSync(file, `${file}.bak`);
59278
+ fs49.renameSync(file, `${file}.bak`);
58719
59279
  } catch {
58720
59280
  }
58721
59281
  }
@@ -58823,61 +59383,61 @@ async function connectRemote(args) {
58823
59383
  }
58824
59384
 
58825
59385
  // src/migrations/2026-05-20-flatten-sessions.ts
58826
- var fs48 = __toESM(require("fs"), 1);
58827
- var path50 = __toESM(require("path"), 1);
59386
+ var fs50 = __toESM(require("fs"), 1);
59387
+ var path52 = __toESM(require("path"), 1);
58828
59388
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
58829
59389
  function migrateFlattenSessions(opts) {
58830
59390
  const dataDir = opts.dataDir;
58831
59391
  const now = opts.now ?? Date.now;
58832
- const sessionsDir = path50.join(dataDir, "sessions");
58833
- const flagPath = path50.join(sessionsDir, MIGRATION_FLAG_NAME);
59392
+ const sessionsDir = path52.join(dataDir, "sessions");
59393
+ const flagPath = path52.join(sessionsDir, MIGRATION_FLAG_NAME);
58834
59394
  if (existsSync3(flagPath)) {
58835
59395
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
58836
59396
  }
58837
59397
  let movedBare = 0;
58838
59398
  let movedVmOwner = 0;
58839
59399
  let archivedListener = 0;
58840
- const defaultDir = path50.join(sessionsDir, "default");
59400
+ const defaultDir = path52.join(sessionsDir, "default");
58841
59401
  if (existsSync3(defaultDir)) {
58842
59402
  for (const entry of readdirSafe(defaultDir)) {
58843
59403
  if (!entry.endsWith(".json")) continue;
58844
- const src = path50.join(defaultDir, entry);
58845
- const dst = path50.join(sessionsDir, entry);
58846
- fs48.renameSync(src, dst);
59404
+ const src = path52.join(defaultDir, entry);
59405
+ const dst = path52.join(sessionsDir, entry);
59406
+ fs50.renameSync(src, dst);
58847
59407
  movedBare += 1;
58848
59408
  }
58849
59409
  rmdirIfEmpty(defaultDir);
58850
59410
  }
58851
59411
  for (const pid of readdirSafe(sessionsDir)) {
58852
- const personaDir = path50.join(sessionsDir, pid);
59412
+ const personaDir = path52.join(sessionsDir, pid);
58853
59413
  if (!isDir(personaDir)) continue;
58854
59414
  if (pid === "default") continue;
58855
- const ownerSrc = path50.join(personaDir, "owner");
59415
+ const ownerSrc = path52.join(personaDir, "owner");
58856
59416
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
58857
- const ownerDst = path50.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
58858
- fs48.mkdirSync(ownerDst, { recursive: true });
59417
+ const ownerDst = path52.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
59418
+ fs50.mkdirSync(ownerDst, { recursive: true });
58859
59419
  for (const file of readdirSafe(ownerSrc)) {
58860
59420
  if (!file.endsWith(".json")) continue;
58861
- fs48.renameSync(path50.join(ownerSrc, file), path50.join(ownerDst, file));
59421
+ fs50.renameSync(path52.join(ownerSrc, file), path52.join(ownerDst, file));
58862
59422
  movedVmOwner += 1;
58863
59423
  }
58864
59424
  rmdirIfEmpty(ownerSrc);
58865
59425
  }
58866
- const listenerSrc = path50.join(personaDir, "listener");
59426
+ const listenerSrc = path52.join(personaDir, "listener");
58867
59427
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
58868
- const archiveDst = path50.join(dataDir, ".legacy", `listener-${pid}`);
58869
- fs48.mkdirSync(archiveDst, { recursive: true });
59428
+ const archiveDst = path52.join(dataDir, ".legacy", `listener-${pid}`);
59429
+ fs50.mkdirSync(archiveDst, { recursive: true });
58870
59430
  for (const file of readdirSafe(listenerSrc)) {
58871
59431
  if (!file.endsWith(".json")) continue;
58872
- fs48.renameSync(path50.join(listenerSrc, file), path50.join(archiveDst, file));
59432
+ fs50.renameSync(path52.join(listenerSrc, file), path52.join(archiveDst, file));
58873
59433
  archivedListener += 1;
58874
59434
  }
58875
59435
  rmdirIfEmpty(listenerSrc);
58876
59436
  }
58877
59437
  rmdirIfEmpty(personaDir);
58878
59438
  }
58879
- fs48.mkdirSync(sessionsDir, { recursive: true });
58880
- fs48.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
59439
+ fs50.mkdirSync(sessionsDir, { recursive: true });
59440
+ fs50.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
58881
59441
  return {
58882
59442
  skipped: false,
58883
59443
  flagWritten: true,
@@ -58888,7 +59448,7 @@ function migrateFlattenSessions(opts) {
58888
59448
  }
58889
59449
  function existsSync3(p2) {
58890
59450
  try {
58891
- fs48.statSync(p2);
59451
+ fs50.statSync(p2);
58892
59452
  return true;
58893
59453
  } catch {
58894
59454
  return false;
@@ -58896,61 +59456,61 @@ function existsSync3(p2) {
58896
59456
  }
58897
59457
  function isDir(p2) {
58898
59458
  try {
58899
- return fs48.statSync(p2).isDirectory();
59459
+ return fs50.statSync(p2).isDirectory();
58900
59460
  } catch {
58901
59461
  return false;
58902
59462
  }
58903
59463
  }
58904
59464
  function readdirSafe(p2) {
58905
59465
  try {
58906
- return fs48.readdirSync(p2);
59466
+ return fs50.readdirSync(p2);
58907
59467
  } catch {
58908
59468
  return [];
58909
59469
  }
58910
59470
  }
58911
59471
  function rmdirIfEmpty(p2) {
58912
59472
  try {
58913
- fs48.rmdirSync(p2);
59473
+ fs50.rmdirSync(p2);
58914
59474
  } catch {
58915
59475
  }
58916
59476
  }
58917
59477
 
58918
59478
  // src/migrations/2026-08-18-drop-seeded-projects.ts
58919
- var fs49 = __toESM(require("fs"), 1);
58920
- var path51 = __toESM(require("path"), 1);
59479
+ var fs51 = __toESM(require("fs"), 1);
59480
+ var path53 = __toESM(require("path"), 1);
58921
59481
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
58922
59482
  function dropSeededProjects(opts) {
58923
- fs49.mkdirSync(opts.dataDir, { recursive: true });
58924
- const flag = path51.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
58925
- if (fs49.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
58926
- const file = path51.join(opts.dataDir, "projects.json");
59483
+ fs51.mkdirSync(opts.dataDir, { recursive: true });
59484
+ const flag = path53.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
59485
+ if (fs51.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
59486
+ const file = path53.join(opts.dataDir, "projects.json");
58927
59487
  let raw = null;
58928
59488
  let dropped = 0;
58929
59489
  try {
58930
- raw = fs49.readFileSync(file, "utf8");
59490
+ raw = fs51.readFileSync(file, "utf8");
58931
59491
  dropped = JSON.parse(raw).projects?.length ?? 0;
58932
59492
  } catch {
58933
59493
  }
58934
59494
  let backup = null;
58935
59495
  if (raw != null && dropped > 0) {
58936
- const dir = path51.join(opts.dataDir, "backups");
58937
- fs49.mkdirSync(dir, { recursive: true });
58938
- backup = path51.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
58939
- fs49.writeFileSync(backup, raw);
59496
+ const dir = path53.join(opts.dataDir, "backups");
59497
+ fs51.mkdirSync(dir, { recursive: true });
59498
+ backup = path53.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
59499
+ fs51.writeFileSync(backup, raw);
58940
59500
  }
58941
59501
  if (raw != null || dropped > 0) {
58942
- fs49.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
59502
+ fs51.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58943
59503
  }
58944
- fs49.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
59504
+ fs51.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58945
59505
  return { skipped: false, dropped, backup };
58946
59506
  }
58947
59507
 
58948
59508
  // src/transport/http-router.ts
58949
59509
  var import_node_fs36 = __toESM(require("fs"), 1);
58950
- var import_node_path43 = __toESM(require("path"), 1);
59510
+ var import_node_path45 = __toESM(require("path"), 1);
58951
59511
 
58952
59512
  // src/attachment/mime.ts
58953
- var import_node_path40 = __toESM(require("path"), 1);
59513
+ var import_node_path42 = __toESM(require("path"), 1);
58954
59514
  var TEXT_PLAIN = "text/plain; charset=utf-8";
58955
59515
  var EXT_TO_NATIVE_MIME = {
58956
59516
  // 图片
@@ -59057,7 +59617,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
59057
59617
  ".mk"
59058
59618
  ]);
59059
59619
  function lookupMime(filePathOrName) {
59060
- const ext = import_node_path40.default.extname(filePathOrName).toLowerCase();
59620
+ const ext = import_node_path42.default.extname(filePathOrName).toLowerCase();
59061
59621
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
59062
59622
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
59063
59623
  return "application/octet-stream";
@@ -59128,9 +59688,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
59128
59688
 
59129
59689
  // src/attachment/upload.ts
59130
59690
  var import_node_fs35 = __toESM(require("fs"), 1);
59131
- var import_node_path41 = __toESM(require("path"), 1);
59691
+ var import_node_path43 = __toESM(require("path"), 1);
59132
59692
  var import_node_crypto10 = __toESM(require("crypto"), 1);
59133
- var import_promises7 = require("stream/promises");
59693
+ var import_promises9 = require("stream/promises");
59134
59694
  var UploadError = class extends Error {
59135
59695
  constructor(code, message) {
59136
59696
  super(message);
@@ -59140,14 +59700,14 @@ var UploadError = class extends Error {
59140
59700
  code;
59141
59701
  };
59142
59702
  function assertValidFileName(fileName) {
59143
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path41.default.basename(fileName)) {
59703
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path43.default.basename(fileName)) {
59144
59704
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
59145
59705
  }
59146
59706
  }
59147
59707
  var HASH_PREFIX_LEN = 16;
59148
59708
  async function writeUploadedAttachment(args) {
59149
59709
  assertValidFileName(args.fileName);
59150
- const attachmentsRoot = import_node_path41.default.join(args.baseDir, ".attachments");
59710
+ const attachmentsRoot = import_node_path43.default.join(args.baseDir, ".attachments");
59151
59711
  try {
59152
59712
  import_node_fs35.default.mkdirSync(attachmentsRoot, { recursive: true });
59153
59713
  } catch (err) {
@@ -59155,12 +59715,12 @@ async function writeUploadedAttachment(args) {
59155
59715
  }
59156
59716
  const hasher = import_node_crypto10.default.createHash("sha256");
59157
59717
  let actualSize = 0;
59158
- const tmpPath = import_node_path41.default.join(
59718
+ const tmpPath = import_node_path43.default.join(
59159
59719
  attachmentsRoot,
59160
59720
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto10.default.randomBytes(4).toString("hex")}`
59161
59721
  );
59162
59722
  try {
59163
- await (0, import_promises7.pipeline)(
59723
+ await (0, import_promises9.pipeline)(
59164
59724
  args.body,
59165
59725
  async function* (source) {
59166
59726
  for await (const chunk of source) {
@@ -59190,7 +59750,7 @@ async function writeUploadedAttachment(args) {
59190
59750
  );
59191
59751
  }
59192
59752
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
59193
- const hashDir = import_node_path41.default.join(attachmentsRoot, attachmentId);
59753
+ const hashDir = import_node_path43.default.join(attachmentsRoot, attachmentId);
59194
59754
  let finalFileName;
59195
59755
  let hashDirExists = false;
59196
59756
  try {
@@ -59208,7 +59768,7 @@ async function writeUploadedAttachment(args) {
59208
59768
  try {
59209
59769
  import_node_fs35.default.mkdirSync(hashDir, { recursive: true });
59210
59770
  finalFileName = args.fileName;
59211
- import_node_fs35.default.renameSync(tmpPath, import_node_path41.default.join(hashDir, finalFileName));
59771
+ import_node_fs35.default.renameSync(tmpPath, import_node_path43.default.join(hashDir, finalFileName));
59212
59772
  } catch (err) {
59213
59773
  try {
59214
59774
  import_node_fs35.default.unlinkSync(tmpPath);
@@ -59217,7 +59777,7 @@ async function writeUploadedAttachment(args) {
59217
59777
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
59218
59778
  }
59219
59779
  }
59220
- const absPath = import_node_path41.default.join(hashDir, finalFileName);
59780
+ const absPath = import_node_path43.default.join(hashDir, finalFileName);
59221
59781
  const relPath = absPath;
59222
59782
  args.groupFileStore.upsert(args.scope, args.sessionId, {
59223
59783
  relPath: absPath,
@@ -59231,9 +59791,9 @@ async function writeUploadedAttachment(args) {
59231
59791
  }
59232
59792
 
59233
59793
  // src/extension/import.ts
59234
- var import_promises8 = __toESM(require("fs/promises"), 1);
59235
- var import_node_path42 = __toESM(require("path"), 1);
59236
- var import_node_os13 = __toESM(require("os"), 1);
59794
+ var import_promises10 = __toESM(require("fs/promises"), 1);
59795
+ var import_node_path44 = __toESM(require("path"), 1);
59796
+ var import_node_os14 = __toESM(require("os"), 1);
59237
59797
  var import_jszip = __toESM(require_lib3(), 1);
59238
59798
  var ImportError = class extends Error {
59239
59799
  constructor(code, message) {
@@ -59250,7 +59810,7 @@ async function importZip(buf, root) {
59250
59810
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
59251
59811
  }
59252
59812
  for (const name of Object.keys(zip.files)) {
59253
- if (name.includes("..") || name.startsWith("/") || import_node_path42.default.isAbsolute(name)) {
59813
+ if (name.includes("..") || name.startsWith("/") || import_node_path44.default.isAbsolute(name)) {
59254
59814
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
59255
59815
  }
59256
59816
  }
@@ -59283,33 +59843,33 @@ async function importZip(buf, root) {
59283
59843
  );
59284
59844
  }
59285
59845
  }
59286
- const destDir = import_node_path42.default.join(root, manifest.id);
59846
+ const destDir = import_node_path44.default.join(root, manifest.id);
59287
59847
  let destExists = false;
59288
59848
  try {
59289
- await import_promises8.default.access(destDir);
59849
+ await import_promises10.default.access(destDir);
59290
59850
  destExists = true;
59291
59851
  } catch {
59292
59852
  }
59293
59853
  if (destExists) {
59294
59854
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
59295
59855
  }
59296
- const stage = await import_promises8.default.mkdtemp(import_node_path42.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
59856
+ const stage = await import_promises10.default.mkdtemp(import_node_path44.default.join(import_node_os14.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
59297
59857
  try {
59298
59858
  for (const [name, entry] of Object.entries(zip.files)) {
59299
- const dest = import_node_path42.default.join(stage, name);
59859
+ const dest = import_node_path44.default.join(stage, name);
59300
59860
  if (entry.dir) {
59301
- await import_promises8.default.mkdir(dest, { recursive: true });
59861
+ await import_promises10.default.mkdir(dest, { recursive: true });
59302
59862
  continue;
59303
59863
  }
59304
- await import_promises8.default.mkdir(import_node_path42.default.dirname(dest), { recursive: true });
59864
+ await import_promises10.default.mkdir(import_node_path44.default.dirname(dest), { recursive: true });
59305
59865
  const content = await entry.async("nodebuffer");
59306
- await import_promises8.default.writeFile(dest, content);
59866
+ await import_promises10.default.writeFile(dest, content);
59307
59867
  }
59308
- await import_promises8.default.mkdir(root, { recursive: true });
59309
- await import_promises8.default.rename(stage, destDir);
59868
+ await import_promises10.default.mkdir(root, { recursive: true });
59869
+ await import_promises10.default.rename(stage, destDir);
59310
59870
  return { extId: manifest.id };
59311
59871
  } catch (e) {
59312
- await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
59872
+ await import_promises10.default.rm(stage, { recursive: true, force: true }).catch(() => {
59313
59873
  });
59314
59874
  throw e;
59315
59875
  }
@@ -59331,7 +59891,7 @@ var SHARE_UI_ASSET_MIME = {
59331
59891
  ".wasm": "application/wasm"
59332
59892
  };
59333
59893
  function shareUiAssetMime(filePath) {
59334
- const ext = import_node_path43.default.extname(filePath).toLowerCase();
59894
+ const ext = import_node_path45.default.extname(filePath).toLowerCase();
59335
59895
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
59336
59896
  }
59337
59897
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -59430,7 +59990,7 @@ function isValidUploadFileName(fileName) {
59430
59990
  if (fileName === "." || fileName === "..") return false;
59431
59991
  if (fileName.startsWith(".")) return false;
59432
59992
  if (fileName.includes("/") || fileName.includes("\\")) return false;
59433
- return fileName === import_node_path43.default.basename(fileName);
59993
+ return fileName === import_node_path45.default.basename(fileName);
59434
59994
  }
59435
59995
  function createHttpRouter(deps) {
59436
59996
  return async (req, res) => {
@@ -59666,7 +60226,7 @@ function createHttpRouter(deps) {
59666
60226
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
59667
60227
  return true;
59668
60228
  }
59669
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path43.default.basename(r.absPath)));
60229
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path45.default.basename(r.absPath)));
59670
60230
  return true;
59671
60231
  }
59672
60232
  const ctx = deps.authResolver.resolveFromHeader(
@@ -59787,7 +60347,7 @@ function createHttpRouter(deps) {
59787
60347
  return true;
59788
60348
  }
59789
60349
  let absPath;
59790
- if (import_node_path43.default.isAbsolute(pathParam)) {
60350
+ if (import_node_path45.default.isAbsolute(pathParam)) {
59791
60351
  absPath = pathParam;
59792
60352
  } else if (deps.sessionStore) {
59793
60353
  const file = deps.sessionStore.read(sid);
@@ -59795,7 +60355,7 @@ function createHttpRouter(deps) {
59795
60355
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
59796
60356
  return true;
59797
60357
  }
59798
- absPath = import_node_path43.default.join(file.cwd, pathParam);
60358
+ absPath = import_node_path45.default.join(file.cwd, pathParam);
59799
60359
  } else {
59800
60360
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
59801
60361
  return true;
@@ -59897,7 +60457,7 @@ function streamFile(res, absPath, logger) {
59897
60457
  return;
59898
60458
  }
59899
60459
  const mime = lookupMime(absPath);
59900
- const basename2 = import_node_path43.default.basename(absPath);
60460
+ const basename2 = import_node_path45.default.basename(absPath);
59901
60461
  res.writeHead(200, {
59902
60462
  "Content-Type": mime,
59903
60463
  "Content-Length": String(stat.size),
@@ -59915,7 +60475,7 @@ function streamFile(res, absPath, logger) {
59915
60475
 
59916
60476
  // src/attachment/gc.ts
59917
60477
  var import_node_fs37 = __toESM(require("fs"), 1);
59918
- var import_node_path44 = __toESM(require("path"), 1);
60478
+ var import_node_path46 = __toESM(require("path"), 1);
59919
60479
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
59920
60480
  function runAttachmentGc(args) {
59921
60481
  const now = (args.now ?? Date.now)();
@@ -59924,12 +60484,12 @@ function runAttachmentGc(args) {
59924
60484
  for (const { scope, sessionId } of args.sessionScopes) {
59925
60485
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
59926
60486
  if (entry.stale) continue;
59927
- if (import_node_path44.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
60487
+ if (import_node_path46.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
59928
60488
  }
59929
60489
  }
59930
60490
  const visited = /* @__PURE__ */ new Set();
59931
60491
  for (const { scope, sessionId } of args.sessionScopes) {
59932
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path44.default.join(
60492
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path46.default.join(
59933
60493
  args.dataDir,
59934
60494
  "sessions",
59935
60495
  ...scopeSubPath(scope).map(safeFileName),
@@ -59942,7 +60502,7 @@ function runAttachmentGc(args) {
59942
60502
  return true;
59943
60503
  });
59944
60504
  for (const rootDir of roots) {
59945
- const attRoot = import_node_path44.default.join(rootDir, ".attachments");
60505
+ const attRoot = import_node_path46.default.join(rootDir, ".attachments");
59946
60506
  let hashDirs;
59947
60507
  try {
59948
60508
  hashDirs = import_node_fs37.default.readdirSync(attRoot);
@@ -59952,7 +60512,7 @@ function runAttachmentGc(args) {
59952
60512
  continue;
59953
60513
  }
59954
60514
  for (const hashDir of hashDirs) {
59955
- const hashDirAbs = import_node_path44.default.join(attRoot, hashDir);
60515
+ const hashDirAbs = import_node_path46.default.join(attRoot, hashDir);
59956
60516
  let files;
59957
60517
  try {
59958
60518
  files = import_node_fs37.default.readdirSync(hashDirAbs);
@@ -59960,7 +60520,7 @@ function runAttachmentGc(args) {
59960
60520
  continue;
59961
60521
  }
59962
60522
  for (const name of files) {
59963
- const file = import_node_path44.default.join(hashDirAbs, name);
60523
+ const file = import_node_path46.default.join(hashDirAbs, name);
59964
60524
  let stat;
59965
60525
  try {
59966
60526
  stat = import_node_fs37.default.statSync(file);
@@ -59992,7 +60552,7 @@ function runAttachmentGc(args) {
59992
60552
 
59993
60553
  // src/attachment/group.ts
59994
60554
  var import_node_fs38 = __toESM(require("fs"), 1);
59995
- var import_node_path45 = __toESM(require("path"), 1);
60555
+ var import_node_path47 = __toESM(require("path"), 1);
59996
60556
  var import_node_crypto11 = __toESM(require("crypto"), 1);
59997
60557
  init_protocol();
59998
60558
  var GroupFileStore = class {
@@ -60004,11 +60564,11 @@ var GroupFileStore = class {
60004
60564
  this.logger = opts.logger;
60005
60565
  }
60006
60566
  rootForScope(scope) {
60007
- return import_node_path45.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
60567
+ return import_node_path47.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
60008
60568
  }
60009
60569
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
60010
60570
  filePath(scope, sessionId) {
60011
- return import_node_path45.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
60571
+ return import_node_path47.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
60012
60572
  }
60013
60573
  cacheKey(scope, sessionId) {
60014
60574
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -60043,7 +60603,7 @@ var GroupFileStore = class {
60043
60603
  }
60044
60604
  writeFile(scope, sessionId, entries) {
60045
60605
  const file = this.filePath(scope, sessionId);
60046
- import_node_fs38.default.mkdirSync(import_node_path45.default.dirname(file), { recursive: true });
60606
+ import_node_fs38.default.mkdirSync(import_node_path47.default.dirname(file), { recursive: true });
60047
60607
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
60048
60608
  import_node_fs38.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
60049
60609
  import_node_fs38.default.renameSync(tmp, file);
@@ -60133,9 +60693,9 @@ var GroupFileStore = class {
60133
60693
 
60134
60694
  // src/discovery/state-file.ts
60135
60695
  var import_node_fs39 = __toESM(require("fs"), 1);
60136
- var import_node_path46 = __toESM(require("path"), 1);
60696
+ var import_node_path48 = __toESM(require("path"), 1);
60137
60697
  function defaultStateFilePath(dataDir) {
60138
- return import_node_path46.default.join(dataDir, "state.json");
60698
+ return import_node_path48.default.join(dataDir, "state.json");
60139
60699
  }
60140
60700
  function isPidAlive(pid) {
60141
60701
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -60171,7 +60731,7 @@ var StateFileManager = class {
60171
60731
  return { status: "stale", existing };
60172
60732
  }
60173
60733
  write(state) {
60174
- import_node_fs39.default.mkdirSync(import_node_path46.default.dirname(this.file), { recursive: true });
60734
+ import_node_fs39.default.mkdirSync(import_node_path48.default.dirname(this.file), { recursive: true });
60175
60735
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
60176
60736
  import_node_fs39.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
60177
60737
  import_node_fs39.default.renameSync(tmp, this.file);
@@ -60199,13 +60759,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
60199
60759
 
60200
60760
  // src/tunnel/tunnel-manager.ts
60201
60761
  var import_node_fs43 = __toESM(require("fs"), 1);
60202
- var import_node_path50 = __toESM(require("path"), 1);
60762
+ var import_node_path52 = __toESM(require("path"), 1);
60203
60763
  var import_node_crypto12 = __toESM(require("crypto"), 1);
60204
- var import_node_child_process11 = require("child_process");
60764
+ var import_node_child_process12 = require("child_process");
60205
60765
 
60206
60766
  // src/tunnel/tunnel-store.ts
60207
60767
  var import_node_fs40 = __toESM(require("fs"), 1);
60208
- var import_node_path47 = __toESM(require("path"), 1);
60768
+ var import_node_path49 = __toESM(require("path"), 1);
60209
60769
  var TunnelStore = class {
60210
60770
  constructor(filePath) {
60211
60771
  this.filePath = filePath;
@@ -60224,7 +60784,7 @@ var TunnelStore = class {
60224
60784
  }
60225
60785
  }
60226
60786
  async set(v2) {
60227
- const dir = import_node_path47.default.dirname(this.filePath);
60787
+ const dir = import_node_path49.default.dirname(this.filePath);
60228
60788
  await import_node_fs40.default.promises.mkdir(dir, { recursive: true });
60229
60789
  const data = JSON.stringify(v2, null, 2);
60230
60790
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -60335,11 +60895,11 @@ function escape(v2) {
60335
60895
 
60336
60896
  // src/tunnel/frpc-binary.ts
60337
60897
  var import_node_fs41 = __toESM(require("fs"), 1);
60338
- var import_node_os14 = __toESM(require("os"), 1);
60339
- var import_node_path48 = __toESM(require("path"), 1);
60340
- var import_node_child_process9 = require("child_process");
60898
+ var import_node_os15 = __toESM(require("os"), 1);
60899
+ var import_node_path50 = __toESM(require("path"), 1);
60900
+ var import_node_child_process10 = require("child_process");
60341
60901
  var import_node_stream3 = require("stream");
60342
- var import_promises9 = require("stream/promises");
60902
+ var import_promises11 = require("stream/promises");
60343
60903
  var FRPC_VERSION = "0.68.0";
60344
60904
  var UnsupportedPlatformError = class extends Error {
60345
60905
  constructor(platform, arch) {
@@ -60375,13 +60935,13 @@ async function ensureFrpcBinary(opts) {
60375
60935
  }
60376
60936
  const version2 = opts.version ?? FRPC_VERSION;
60377
60937
  const platform = opts.platform ?? detectPlatform();
60378
- const binDir = import_node_path48.default.join(opts.dataDir, "bin");
60938
+ const binDir = import_node_path50.default.join(opts.dataDir, "bin");
60379
60939
  import_node_fs41.default.mkdirSync(binDir, { recursive: true });
60380
60940
  cleanupStaleArtifacts(binDir);
60381
- const stableBin = import_node_path48.default.join(binDir, "frpc");
60941
+ const stableBin = import_node_path50.default.join(binDir, "frpc");
60382
60942
  if (import_node_fs41.default.existsSync(stableBin)) return stableBin;
60383
60943
  const partialBin = `${stableBin}.partial`;
60384
- const tarballPath = import_node_path48.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
60944
+ const tarballPath = import_node_path50.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
60385
60945
  try {
60386
60946
  const url = frpcDownloadUrl(version2, platform);
60387
60947
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -60407,7 +60967,7 @@ function cleanupStaleArtifacts(binDir) {
60407
60967
  }
60408
60968
  for (const name of entries) {
60409
60969
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
60410
- const full = import_node_path48.default.join(binDir, name);
60970
+ const full = import_node_path50.default.join(binDir, name);
60411
60971
  try {
60412
60972
  import_node_fs41.default.rmSync(full, { recursive: true, force: true });
60413
60973
  } catch {
@@ -60430,19 +60990,19 @@ async function downloadToFile(url, dest, fetchImpl) {
60430
60990
  }
60431
60991
  const out = import_node_fs41.default.createWriteStream(dest);
60432
60992
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
60433
- await (0, import_promises9.pipeline)(nodeStream, out);
60993
+ await (0, import_promises11.pipeline)(nodeStream, out);
60434
60994
  }
60435
60995
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
60436
- const work = import_node_path48.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
60996
+ const work = import_node_path50.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
60437
60997
  import_node_fs41.default.mkdirSync(work, { recursive: true });
60438
60998
  try {
60439
60999
  await new Promise((resolve9, reject) => {
60440
- const proc = (0, import_node_child_process9.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
61000
+ const proc = (0, import_node_child_process10.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
60441
61001
  proc.on("error", reject);
60442
61002
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
60443
61003
  });
60444
61004
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
60445
- const src = import_node_path48.default.join(work, dirName, "frpc");
61005
+ const src = import_node_path50.default.join(work, dirName, "frpc");
60446
61006
  if (!import_node_fs41.default.existsSync(src)) {
60447
61007
  throw new Error(`frpc not found inside tarball at ${src}`);
60448
61008
  }
@@ -60454,10 +61014,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
60454
61014
 
60455
61015
  // src/tunnel/frpc-process.ts
60456
61016
  var import_node_fs42 = __toESM(require("fs"), 1);
60457
- var import_node_path49 = __toESM(require("path"), 1);
60458
- var import_node_child_process10 = require("child_process");
61017
+ var import_node_path51 = __toESM(require("path"), 1);
61018
+ var import_node_child_process11 = require("child_process");
60459
61019
  function frpcPidFilePath(dataDir) {
60460
- return import_node_path49.default.join(dataDir, "frpc.pid");
61020
+ return import_node_path51.default.join(dataDir, "frpc.pid");
60461
61021
  }
60462
61022
  function writeFrpcPid(dataDir, pid) {
60463
61023
  try {
@@ -60499,7 +61059,7 @@ function defaultSleep2(ms) {
60499
61059
  }
60500
61060
  async function killStaleFrpc(deps) {
60501
61061
  const pidFile = frpcPidFilePath(deps.dataDir);
60502
- const tomlPath = import_node_path49.default.join(deps.dataDir, "frpc.toml");
61062
+ const tomlPath = import_node_path51.default.join(deps.dataDir, "frpc.toml");
60503
61063
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
60504
61064
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
60505
61065
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -60541,7 +61101,7 @@ async function killStaleFrpc(deps) {
60541
61101
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
60542
61102
  if (process.platform === "win32") return [];
60543
61103
  return new Promise((resolve9) => {
60544
- const ps = (0, import_node_child_process10.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
61104
+ const ps = (0, import_node_child_process11.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
60545
61105
  let buf = "";
60546
61106
  ps.stdout.on("data", (c) => {
60547
61107
  buf += c.toString();
@@ -60571,7 +61131,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
60571
61131
  var TunnelManager = class {
60572
61132
  constructor(deps) {
60573
61133
  this.deps = deps;
60574
- this.store = deps.store ?? new TunnelStore(import_node_path50.default.join(deps.dataDir, "tunnel.json"));
61134
+ this.store = deps.store ?? new TunnelStore(import_node_path52.default.join(deps.dataDir, "tunnel.json"));
60575
61135
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
60576
61136
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
60577
61137
  }
@@ -60698,7 +61258,7 @@ var TunnelManager = class {
60698
61258
  dataDir: this.deps.dataDir,
60699
61259
  override: this.deps.frpcBinaryOverride ?? void 0
60700
61260
  });
60701
- const tomlPath = import_node_path50.default.join(this.deps.dataDir, "frpc.toml");
61261
+ const tomlPath = import_node_path52.default.join(this.deps.dataDir, "frpc.toml");
60702
61262
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto12.default.randomBytes(3).toString("hex")}`;
60703
61263
  const toml = buildFrpcToml({
60704
61264
  serverAddr: t.frpsHost,
@@ -60710,12 +61270,12 @@ var TunnelManager = class {
60710
61270
  logLevel: "info"
60711
61271
  });
60712
61272
  await import_node_fs43.default.promises.writeFile(tomlPath, toml, { mode: 384 });
60713
- const proc = (this.deps.spawnImpl ?? import_node_child_process11.spawn)(frpcBin, ["-c", tomlPath], {
61273
+ const proc = (this.deps.spawnImpl ?? import_node_child_process12.spawn)(frpcBin, ["-c", tomlPath], {
60714
61274
  stdio: ["ignore", "pipe", "pipe"]
60715
61275
  });
60716
- const logDir = import_node_path50.default.join(this.deps.dataDir, "log");
61276
+ const logDir = import_node_path52.default.join(this.deps.dataDir, "log");
60717
61277
  import_node_fs43.default.mkdirSync(logDir, { recursive: true });
60718
- const logFilePath = import_node_path50.default.join(logDir, "frpc.log");
61278
+ const logFilePath = import_node_path52.default.join(logDir, "frpc.log");
60719
61279
  const logStream = import_node_fs43.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
60720
61280
  logStream.on("error", () => {
60721
61281
  });
@@ -60798,16 +61358,16 @@ async function waitForFrpcReady(proc, timeoutMs) {
60798
61358
  }
60799
61359
 
60800
61360
  // src/tunnel/device-key.ts
60801
- var import_node_os15 = __toESM(require("os"), 1);
60802
- var import_node_path51 = __toESM(require("path"), 1);
61361
+ var import_node_os16 = __toESM(require("os"), 1);
61362
+ var import_node_path53 = __toESM(require("path"), 1);
60803
61363
  var import_node_crypto13 = __toESM(require("crypto"), 1);
60804
61364
  var DERIVE_SALT = "clawd-tunnel-device-v1";
60805
61365
  function deriveStableDeviceKey(opts = {}) {
60806
- const hostname = opts.hostname ?? import_node_os15.default.hostname();
60807
- const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
60808
- const home = opts.home ?? import_node_os15.default.homedir();
60809
- const defaultDataDir = import_node_path51.default.resolve(import_node_path51.default.join(home, ".clawd"));
60810
- const normalizedDataDir = opts.dataDir ? import_node_path51.default.resolve(opts.dataDir) : null;
61366
+ const hostname = opts.hostname ?? import_node_os16.default.hostname();
61367
+ const uid = opts.uid ?? (typeof import_node_os16.default.userInfo === "function" ? import_node_os16.default.userInfo().uid : 0);
61368
+ const home = opts.home ?? import_node_os16.default.homedir();
61369
+ const defaultDataDir = import_node_path53.default.resolve(import_node_path53.default.join(home, ".clawd"));
61370
+ const normalizedDataDir = opts.dataDir ? import_node_path53.default.resolve(opts.dataDir) : null;
60811
61371
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
60812
61372
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
60813
61373
  return import_node_crypto13.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -60815,11 +61375,11 @@ function deriveStableDeviceKey(opts = {}) {
60815
61375
 
60816
61376
  // src/auth-store.ts
60817
61377
  var import_node_fs44 = __toESM(require("fs"), 1);
60818
- var import_node_path52 = __toESM(require("path"), 1);
61378
+ var import_node_path54 = __toESM(require("path"), 1);
60819
61379
  var import_node_crypto14 = __toESM(require("crypto"), 1);
60820
61380
  var AUTH_FILE_NAME = "auth.json";
60821
61381
  function authFilePath(dataDir) {
60822
- return import_node_path52.default.join(dataDir, AUTH_FILE_NAME);
61382
+ return import_node_path54.default.join(dataDir, AUTH_FILE_NAME);
60823
61383
  }
60824
61384
  function loadOrCreateAuthFile(opts) {
60825
61385
  const file = authFilePath(opts.dataDir);
@@ -60871,7 +61431,7 @@ function readAuthFile(file) {
60871
61431
  }
60872
61432
  }
60873
61433
  function writeAuthFile(file, content) {
60874
- import_node_fs44.default.mkdirSync(import_node_path52.default.dirname(file), { recursive: true });
61434
+ import_node_fs44.default.mkdirSync(import_node_path54.default.dirname(file), { recursive: true });
60875
61435
  import_node_fs44.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
60876
61436
  try {
60877
61437
  import_node_fs44.default.chmodSync(file, 384);
@@ -60881,11 +61441,11 @@ function writeAuthFile(file, content) {
60881
61441
 
60882
61442
  // src/owner-profile.ts
60883
61443
  var import_node_fs45 = __toESM(require("fs"), 1);
60884
- var import_node_os16 = __toESM(require("os"), 1);
60885
- var import_node_path53 = __toESM(require("path"), 1);
61444
+ var import_node_os17 = __toESM(require("os"), 1);
61445
+ var import_node_path55 = __toESM(require("path"), 1);
60886
61446
  var PROFILE_FILENAME = "profile.json";
60887
61447
  function profilePath(dataDir) {
60888
- return import_node_path53.default.join(dataDir, PROFILE_FILENAME);
61448
+ return import_node_path55.default.join(dataDir, PROFILE_FILENAME);
60889
61449
  }
60890
61450
  function loadOwnerProfile(dataDir) {
60891
61451
  let raw;
@@ -60910,7 +61470,7 @@ function patchOwnerProfile(dataDir, patch) {
60910
61470
  return merged;
60911
61471
  }
60912
61472
  function loadOwnerDisplayName(dataDir) {
60913
- const fallback = import_node_os16.default.userInfo().username;
61473
+ const fallback = import_node_os17.default.userInfo().username;
60914
61474
  const displayName = loadOwnerProfile(dataDir).displayName;
60915
61475
  if (typeof displayName !== "string" || displayName.length === 0) {
60916
61476
  if (displayName !== void 0) {
@@ -60923,12 +61483,12 @@ function loadOwnerDisplayName(dataDir) {
60923
61483
 
60924
61484
  // src/feishu-auth/owner-identity-store.ts
60925
61485
  var import_node_fs46 = __toESM(require("fs"), 1);
60926
- var import_node_path54 = __toESM(require("path"), 1);
61486
+ var import_node_path56 = __toESM(require("path"), 1);
60927
61487
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
60928
61488
  var OwnerIdentityStore = class {
60929
61489
  file;
60930
61490
  constructor(dataDir) {
60931
- this.file = import_node_path54.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
61491
+ this.file = import_node_path56.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
60932
61492
  }
60933
61493
  read() {
60934
61494
  let raw;
@@ -60961,7 +61521,7 @@ var OwnerIdentityStore = class {
60961
61521
  };
60962
61522
  }
60963
61523
  write(record3) {
60964
- import_node_fs46.default.mkdirSync(import_node_path54.default.dirname(this.file), { recursive: true });
61524
+ import_node_fs46.default.mkdirSync(import_node_path56.default.dirname(this.file), { recursive: true });
60965
61525
  import_node_fs46.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
60966
61526
  try {
60967
61527
  import_node_fs46.default.chmodSync(this.file, 384);
@@ -61107,9 +61667,9 @@ var CentralClientError = class extends Error {
61107
61667
  code;
61108
61668
  cause;
61109
61669
  };
61110
- async function centralRequest(opts, path96, init) {
61670
+ async function centralRequest(opts, path98, init) {
61111
61671
  const f = opts.fetchImpl ?? globalThis.fetch;
61112
- const url = `${opts.api.replace(/\/+$/, "")}${path96}`;
61672
+ const url = `${opts.api.replace(/\/+$/, "")}${path98}`;
61113
61673
  const ctrl = new AbortController();
61114
61674
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
61115
61675
  let res;
@@ -61546,8 +62106,8 @@ function verifyConnectToken(args) {
61546
62106
  }
61547
62107
 
61548
62108
  // src/feishu-auth/server-key.ts
61549
- var fs63 = __toESM(require("fs"), 1);
61550
- var path67 = __toESM(require("path"), 1);
62109
+ var fs65 = __toESM(require("fs"), 1);
62110
+ var path69 = __toESM(require("path"), 1);
61551
62111
  var FILE_NAME2 = "server-signing-key.json";
61552
62112
  var ServerKeyStore = class {
61553
62113
  constructor(dataDir) {
@@ -61555,12 +62115,12 @@ var ServerKeyStore = class {
61555
62115
  }
61556
62116
  dataDir;
61557
62117
  filePath() {
61558
- return path67.join(this.dataDir, FILE_NAME2);
62118
+ return path69.join(this.dataDir, FILE_NAME2);
61559
62119
  }
61560
62120
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
61561
62121
  read() {
61562
62122
  try {
61563
- const raw = fs63.readFileSync(this.filePath(), "utf8");
62123
+ const raw = fs65.readFileSync(this.filePath(), "utf8");
61564
62124
  const parsed = JSON.parse(raw);
61565
62125
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
61566
62126
  return parsed.publicKeyPem;
@@ -61575,12 +62135,12 @@ var ServerKeyStore = class {
61575
62135
  publicKeyPem,
61576
62136
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
61577
62137
  };
61578
- fs63.mkdirSync(this.dataDir, { recursive: true });
61579
- fs63.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
62138
+ fs65.mkdirSync(this.dataDir, { recursive: true });
62139
+ fs65.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
61580
62140
  }
61581
62141
  clear() {
61582
62142
  try {
61583
- fs63.unlinkSync(this.filePath());
62143
+ fs65.unlinkSync(this.filePath());
61584
62144
  } catch {
61585
62145
  }
61586
62146
  }
@@ -61590,15 +62150,15 @@ var ServerKeyStore = class {
61590
62150
  init_protocol();
61591
62151
 
61592
62152
  // src/handlers/index.ts
61593
- var import_node_path70 = __toESM(require("path"), 1);
62153
+ var import_node_path72 = __toESM(require("path"), 1);
61594
62154
 
61595
62155
  // src/handlers/session.ts
61596
62156
  init_protocol();
61597
62157
 
61598
62158
  // src/session/fork.ts
61599
62159
  var import_node_fs47 = __toESM(require("fs"), 1);
61600
- var import_node_os17 = __toESM(require("os"), 1);
61601
- var import_node_path55 = __toESM(require("path"), 1);
62160
+ var import_node_os18 = __toESM(require("os"), 1);
62161
+ var import_node_path57 = __toESM(require("path"), 1);
61602
62162
  var import_node_crypto16 = require("crypto");
61603
62163
  init_claude_history();
61604
62164
  function readJsonlEntries(file) {
@@ -61615,19 +62175,19 @@ function readJsonlEntries(file) {
61615
62175
  return out;
61616
62176
  }
61617
62177
  function forkSession(input) {
61618
- const baseDir = input.baseDir ?? import_node_path55.default.join(import_node_os17.default.homedir(), ".claude");
61619
- let projectDir = import_node_path55.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
61620
- let sourceFile = import_node_path55.default.join(projectDir, `${input.toolSessionId}.jsonl`);
62178
+ const baseDir = input.baseDir ?? import_node_path57.default.join(import_node_os18.default.homedir(), ".claude");
62179
+ let projectDir = import_node_path57.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
62180
+ let sourceFile = import_node_path57.default.join(projectDir, `${input.toolSessionId}.jsonl`);
61621
62181
  if (!import_node_fs47.default.existsSync(sourceFile)) {
61622
62182
  const found = findTranscriptByToolSessionId(
61623
- import_node_path55.default.join(baseDir, "projects"),
62183
+ import_node_path57.default.join(baseDir, "projects"),
61624
62184
  input.toolSessionId
61625
62185
  );
61626
62186
  if (!found) {
61627
62187
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
61628
62188
  }
61629
62189
  sourceFile = found;
61630
- projectDir = import_node_path55.default.dirname(found);
62190
+ projectDir = import_node_path57.default.dirname(found);
61631
62191
  }
61632
62192
  const entries = readJsonlEntries(sourceFile);
61633
62193
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -61656,8 +62216,8 @@ function forkSession(input) {
61656
62216
  }
61657
62217
  forkedLines.push(JSON.stringify(forked));
61658
62218
  }
61659
- const outDir = input.targetCwd ? import_node_path55.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
61660
- const forkedFilePath = import_node_path55.default.join(outDir, `${forkedToolSessionId}.jsonl`);
62219
+ const outDir = input.targetCwd ? import_node_path57.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
62220
+ const forkedFilePath = import_node_path57.default.join(outDir, `${forkedToolSessionId}.jsonl`);
61661
62221
  import_node_fs47.default.mkdirSync(outDir, { recursive: true });
61662
62222
  import_node_fs47.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
61663
62223
  return { forkedToolSessionId, forkedFilePath };
@@ -61665,18 +62225,18 @@ function forkSession(input) {
61665
62225
 
61666
62226
  // src/session/external-scan.ts
61667
62227
  var import_node_fs48 = __toESM(require("fs"), 1);
61668
- var import_promises10 = __toESM(require("fs/promises"), 1);
61669
- var import_node_os18 = __toESM(require("os"), 1);
61670
- var import_node_path56 = __toESM(require("path"), 1);
62228
+ var import_promises12 = __toESM(require("fs/promises"), 1);
62229
+ var import_node_os19 = __toESM(require("os"), 1);
62230
+ var import_node_path58 = __toESM(require("path"), 1);
61671
62231
  var import_node_module = require("module");
61672
- var import_node_child_process12 = require("child_process");
62232
+ var import_node_child_process13 = require("child_process");
61673
62233
  var import_meta5 = {};
61674
62234
  function defaultRoots() {
61675
- const home = import_node_os18.default.homedir();
62235
+ const home = import_node_os19.default.homedir();
61676
62236
  return {
61677
- claudeProjectsDir: import_node_path56.default.join(home, ".claude", "projects"),
61678
- codexDir: import_node_path56.default.join(home, ".codex"),
61679
- clawdDir: import_node_path56.default.join(home, ".clawd")
62237
+ claudeProjectsDir: import_node_path58.default.join(home, ".claude", "projects"),
62238
+ codexDir: import_node_path58.default.join(home, ".codex"),
62239
+ clawdDir: import_node_path58.default.join(home, ".clawd")
61680
62240
  };
61681
62241
  }
61682
62242
  function width(s) {
@@ -61704,7 +62264,7 @@ function toMs(v2) {
61704
62264
  async function* jsonLines(file) {
61705
62265
  let raw;
61706
62266
  try {
61707
- raw = await import_promises10.default.readFile(file, "utf8");
62267
+ raw = await import_promises12.default.readFile(file, "utf8");
61708
62268
  } catch {
61709
62269
  return;
61710
62270
  }
@@ -61744,13 +62304,13 @@ async function scanClaude(roots) {
61744
62304
  if (!d.isDirectory()) continue;
61745
62305
  let files;
61746
62306
  try {
61747
- files = import_node_fs48.default.readdirSync(import_node_path56.default.join(roots.claudeProjectsDir, d.name));
62307
+ files = import_node_fs48.default.readdirSync(import_node_path58.default.join(roots.claudeProjectsDir, d.name));
61748
62308
  } catch {
61749
62309
  continue;
61750
62310
  }
61751
62311
  for (const name of files) {
61752
62312
  if (!name.endsWith(".jsonl")) continue;
61753
- const file = import_node_path56.default.join(roots.claudeProjectsDir, d.name, name);
62313
+ const file = import_node_path58.default.join(roots.claudeProjectsDir, d.name, name);
61754
62314
  let st;
61755
62315
  try {
61756
62316
  st = import_node_fs48.default.statSync(file);
@@ -61837,14 +62397,14 @@ function readCodexThreads(db) {
61837
62397
  } catch {
61838
62398
  }
61839
62399
  try {
61840
- const info = (0, import_node_child_process12.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
62400
+ const info = (0, import_node_child_process13.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
61841
62401
  if (info.status !== 0) return null;
61842
62402
  const have = new Set(
61843
62403
  info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
61844
62404
  );
61845
62405
  if (!["id", "cwd", "updated_at", "thread_source"].every((c) => have.has(c))) return null;
61846
62406
  const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
61847
- const res = (0, import_node_child_process12.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
62407
+ const res = (0, import_node_child_process13.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
61848
62408
  encoding: "utf8",
61849
62409
  maxBuffer: 64 * 1024 * 1024
61850
62410
  });
@@ -61880,7 +62440,7 @@ async function codexFromRows(rows) {
61880
62440
  async function scanCodex(roots) {
61881
62441
  let dbs = [];
61882
62442
  try {
61883
- dbs = import_node_fs48.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path56.default.join(roots.codexDir, n));
62443
+ dbs = import_node_fs48.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path58.default.join(roots.codexDir, n));
61884
62444
  } catch {
61885
62445
  }
61886
62446
  if (!dbs.length) return [];
@@ -61889,14 +62449,14 @@ async function scanCodex(roots) {
61889
62449
  }
61890
62450
  async function scanExternalSessions(rootsIn) {
61891
62451
  const roots = { ...defaultRoots(), ...rootsIn };
61892
- const personaRoot = import_node_path56.default.join(roots.clawdDir, "personas");
62452
+ const personaRoot = import_node_path58.default.join(roots.clawdDir, "personas");
61893
62453
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
61894
62454
  const out = [];
61895
62455
  for (const c of all) {
61896
62456
  if (c.skip) continue;
61897
62457
  if (c.turns < 1) continue;
61898
62458
  if (!c.cwd || !isDir2(c.cwd)) continue;
61899
- if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path56.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path56.default.sep)) {
62459
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path58.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path58.default.sep)) {
61900
62460
  continue;
61901
62461
  }
61902
62462
  out.push({
@@ -61914,12 +62474,12 @@ async function scanExternalSessions(rootsIn) {
61914
62474
 
61915
62475
  // src/session/import-ledger.ts
61916
62476
  var import_node_fs49 = __toESM(require("fs"), 1);
61917
- var import_node_path57 = __toESM(require("path"), 1);
62477
+ var import_node_path59 = __toESM(require("path"), 1);
61918
62478
  var LEDGER_FILENAME = "session-import-ledger.json";
61919
62479
  function readImportLedger(dataDir) {
61920
62480
  try {
61921
62481
  const parsed = JSON.parse(
61922
- import_node_fs49.default.readFileSync(import_node_path57.default.join(dataDir, LEDGER_FILENAME), "utf8")
62482
+ import_node_fs49.default.readFileSync(import_node_path59.default.join(dataDir, LEDGER_FILENAME), "utf8")
61923
62483
  );
61924
62484
  return Array.isArray(parsed) ? parsed : [];
61925
62485
  } catch {
@@ -61927,7 +62487,7 @@ function readImportLedger(dataDir) {
61927
62487
  }
61928
62488
  }
61929
62489
  function appendImportLedger(dataDir, entry) {
61930
- const file = import_node_path57.default.join(dataDir, LEDGER_FILENAME);
62490
+ const file = import_node_path59.default.join(dataDir, LEDGER_FILENAME);
61931
62491
  const entries = readImportLedger(dataDir);
61932
62492
  entries.push(entry);
61933
62493
  import_node_fs49.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
@@ -61935,7 +62495,7 @@ function appendImportLedger(dataDir, entry) {
61935
62495
 
61936
62496
  // src/tools/transcript-search.ts
61937
62497
  var import_node_fs50 = __toESM(require("fs"), 1);
61938
- var import_node_path58 = __toESM(require("path"), 1);
62498
+ var import_node_path60 = __toESM(require("path"), 1);
61939
62499
  var SNIPPET_PAD = 60;
61940
62500
  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/;
61941
62501
  var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
@@ -62028,7 +62588,7 @@ function createCodexRolloutLocator(roots) {
62028
62588
  return;
62029
62589
  }
62030
62590
  for (const entry of entries) {
62031
- const full = import_node_path58.default.join(dir, entry.name);
62591
+ const full = import_node_path60.default.join(dir, entry.name);
62032
62592
  if (entry.isDirectory()) {
62033
62593
  walk2(full, into);
62034
62594
  continue;
@@ -62048,16 +62608,16 @@ function createCodexRolloutLocator(roots) {
62048
62608
 
62049
62609
  // src/handlers/session.ts
62050
62610
  init_protocol();
62051
- var import_node_os19 = __toESM(require("os"), 1);
62052
- var import_node_path59 = __toESM(require("path"), 1);
62611
+ var import_node_os20 = __toESM(require("os"), 1);
62612
+ var import_node_path61 = __toESM(require("path"), 1);
62053
62613
  function canReadSearchHit(ctx, file) {
62054
62614
  if (!ctx || ctx.principal.kind === "owner") return true;
62055
62615
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
62056
62616
  }
62057
62617
  var DEFAULT_SEARCH_LIMIT = 9;
62058
62618
  function codexRolloutRoots(dataDir) {
62059
- const roots = [import_node_path59.default.join(import_node_os19.default.homedir(), ".codex", "sessions")];
62060
- if (dataDir) roots.push(import_node_path59.default.join(dataDir, "codex-home", "sessions"));
62619
+ const roots = [import_node_path61.default.join(import_node_os20.default.homedir(), ".codex", "sessions")];
62620
+ if (dataDir) roots.push(import_node_path61.default.join(dataDir, "codex-home", "sessions"));
62061
62621
  return roots;
62062
62622
  }
62063
62623
  function buildSessionHandlers(deps) {
@@ -62599,7 +63159,7 @@ function buildPermissionHandlers(deps) {
62599
63159
  }
62600
63160
 
62601
63161
  // src/handlers/history.ts
62602
- var path74 = __toESM(require("path"), 1);
63162
+ var path76 = __toESM(require("path"), 1);
62603
63163
  init_protocol();
62604
63164
 
62605
63165
  // src/session/recent-dirs.ts
@@ -62617,7 +63177,7 @@ function listRecentDirs(store, limit = 50) {
62617
63177
  }
62618
63178
 
62619
63179
  // src/permission/persona-paths.ts
62620
- var path73 = __toESM(require("path"), 1);
63180
+ var path75 = __toESM(require("path"), 1);
62621
63181
  function getAllowedPersonaIds(grants, action) {
62622
63182
  const ids = /* @__PURE__ */ new Set();
62623
63183
  for (const g2 of grants) {
@@ -62630,42 +63190,42 @@ function getAllowedPersonaIds(grants, action) {
62630
63190
  return ids;
62631
63191
  }
62632
63192
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
62633
- const target = path73.resolve(absPath);
63193
+ const target = path75.resolve(absPath);
62634
63194
  if (userWorkDir) {
62635
- const u = path73.resolve(userWorkDir);
62636
- const usep = u.endsWith(path73.sep) ? "" : path73.sep;
63195
+ const u = path75.resolve(userWorkDir);
63196
+ const usep = u.endsWith(path75.sep) ? "" : path75.sep;
62637
63197
  if (target === u || target.startsWith(u + usep)) return true;
62638
63198
  }
62639
- const root = path73.resolve(personaRoot);
62640
- const sep4 = root.endsWith(path73.sep) ? "" : path73.sep;
63199
+ const root = path75.resolve(personaRoot);
63200
+ const sep4 = root.endsWith(path75.sep) ? "" : path75.sep;
62641
63201
  if (!target.startsWith(root + sep4)) return false;
62642
- const rel = path73.relative(root, target);
63202
+ const rel = path75.relative(root, target);
62643
63203
  if (!rel || rel.startsWith("..")) return false;
62644
- const personaId2 = rel.split(path73.sep)[0];
63204
+ const personaId2 = rel.split(path75.sep)[0];
62645
63205
  if (!personaId2) return false;
62646
63206
  const allowed = getAllowedPersonaIds(grants, action);
62647
63207
  if (allowed === "*") return true;
62648
63208
  return allowed.has(personaId2);
62649
63209
  }
62650
63210
  function personaIdFromPath(absPath, personaRoot) {
62651
- const root = path73.resolve(personaRoot);
62652
- const target = path73.resolve(absPath);
62653
- const sep4 = root.endsWith(path73.sep) ? "" : path73.sep;
63211
+ const root = path75.resolve(personaRoot);
63212
+ const target = path75.resolve(absPath);
63213
+ const sep4 = root.endsWith(path75.sep) ? "" : path75.sep;
62654
63214
  if (!target.startsWith(root + sep4)) return null;
62655
- const rel = path73.relative(root, target);
63215
+ const rel = path75.relative(root, target);
62656
63216
  if (!rel || rel.startsWith("..")) return null;
62657
- const id = rel.split(path73.sep)[0];
63217
+ const id = rel.split(path75.sep)[0];
62658
63218
  return id || null;
62659
63219
  }
62660
63220
  function isPathWithin(dir, absPath) {
62661
- const d = path73.resolve(dir);
62662
- const t = path73.resolve(absPath);
62663
- const sep4 = d.endsWith(path73.sep) ? "" : path73.sep;
63221
+ const d = path75.resolve(dir);
63222
+ const t = path75.resolve(absPath);
63223
+ const sep4 = d.endsWith(path75.sep) ? "" : path75.sep;
62664
63224
  return t === d || t.startsWith(d + sep4);
62665
63225
  }
62666
63226
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
62667
63227
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
62668
- return personaIdFromPath(path73.resolve(absPath), personaRoot) === personaId2;
63228
+ return personaIdFromPath(path75.resolve(absPath), personaRoot) === personaId2;
62669
63229
  }
62670
63230
 
62671
63231
  // src/handlers/history.ts
@@ -62718,7 +63278,7 @@ function buildHistoryHandlers(deps) {
62718
63278
  if (!pid) return false;
62719
63279
  return isGuestPathAllowed(
62720
63280
  ctx.grants,
62721
- path74.join(personaRoot, pid),
63281
+ path76.join(personaRoot, pid),
62722
63282
  personaRoot,
62723
63283
  "read",
62724
63284
  userWorkDir
@@ -62730,7 +63290,7 @@ function buildHistoryHandlers(deps) {
62730
63290
  };
62731
63291
  const list = async (frame, _client, ctx) => {
62732
63292
  const args = HistoryListArgs.parse(frame);
62733
- assertGuestPath(ctx, path74.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
63293
+ assertGuestPath(ctx, path76.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
62734
63294
  const sessions = await history.listSessions(args);
62735
63295
  return { response: { type: "history:list", sessions } };
62736
63296
  };
@@ -62778,14 +63338,14 @@ function buildHistoryHandlers(deps) {
62778
63338
  };
62779
63339
  const subagents = async (frame, _client, ctx) => {
62780
63340
  const args = HistorySubagentsArgs.parse(frame);
62781
- assertGuestPath(ctx, path74.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
63341
+ assertGuestPath(ctx, path76.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
62782
63342
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
62783
63343
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
62784
63344
  return { response: { type: "history:subagents", subagents: subs } };
62785
63345
  };
62786
63346
  const subagentRead = async (frame, _client, ctx) => {
62787
63347
  const args = HistorySubagentReadArgs.parse(frame);
62788
- assertGuestPath(ctx, path74.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
63348
+ assertGuestPath(ctx, path76.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
62789
63349
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
62790
63350
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
62791
63351
  return { response: { type: "history:subagent-read", ...res } };
@@ -62795,7 +63355,7 @@ function buildHistoryHandlers(deps) {
62795
63355
  if (ctx?.principal.kind === "guest" && personaRoot) {
62796
63356
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
62797
63357
  const filtered = dirs.filter(
62798
- (d) => isGuestPathAllowed(ctx.grants, path74.resolve(d.cwd), personaRoot, "read", userWorkDir)
63358
+ (d) => isGuestPathAllowed(ctx.grants, path76.resolve(d.cwd), personaRoot, "read", userWorkDir)
62799
63359
  );
62800
63360
  return { response: { type: "history:recentDirs", dirs: filtered } };
62801
63361
  }
@@ -62812,17 +63372,17 @@ function buildHistoryHandlers(deps) {
62812
63372
  }
62813
63373
 
62814
63374
  // src/handlers/projects.ts
62815
- var fs68 = __toESM(require("fs"), 1);
62816
- var os21 = __toESM(require("os"), 1);
62817
- var path75 = __toESM(require("path"), 1);
62818
- var import_node_child_process13 = require("child_process");
63375
+ var fs70 = __toESM(require("fs"), 1);
63376
+ var os22 = __toESM(require("os"), 1);
63377
+ var path77 = __toESM(require("path"), 1);
63378
+ var import_node_child_process14 = require("child_process");
62819
63379
  init_protocol();
62820
- var DEFAULT_PROJECTS_ROOT = path75.join(os21.homedir(), "Documents", "ChatGPT");
63380
+ var DEFAULT_PROJECTS_ROOT = path77.join(os22.homedir(), "Documents", "ChatGPT");
62821
63381
  function allocateDir(root, name) {
62822
- let candidate = path75.join(root, name);
63382
+ let candidate = path77.join(root, name);
62823
63383
  let n = 2;
62824
- while (fs68.existsSync(candidate)) {
62825
- candidate = path75.join(root, `${name} ${n}`);
63384
+ while (fs70.existsSync(candidate)) {
63385
+ candidate = path77.join(root, `${name} ${n}`);
62826
63386
  n += 1;
62827
63387
  }
62828
63388
  return candidate;
@@ -62850,11 +63410,11 @@ function buildProjectHandlers(deps) {
62850
63410
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
62851
63411
  }
62852
63412
  try {
62853
- if (!fs68.statSync(args.path).isDirectory()) throw new Error("not dir");
63413
+ if (!fs70.statSync(args.path).isDirectory()) throw new Error("not dir");
62854
63414
  } catch {
62855
63415
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
62856
63416
  }
62857
- const r = (0, import_node_child_process13.spawnSync)("open", ["-R", args.path], { stdio: "ignore" });
63417
+ const r = (0, import_node_child_process14.spawnSync)("open", ["-R", args.path], { stdio: "ignore" });
62858
63418
  if (r.status !== 0) {
62859
63419
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `open -R \u5931\u8D25: exit ${r.status}`);
62860
63420
  }
@@ -62866,7 +63426,7 @@ function buildProjectHandlers(deps) {
62866
63426
  let target;
62867
63427
  if (args.path) {
62868
63428
  try {
62869
- if (!fs68.statSync(args.path).isDirectory()) throw new Error("not dir");
63429
+ if (!fs70.statSync(args.path).isDirectory()) throw new Error("not dir");
62870
63430
  } catch {
62871
63431
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
62872
63432
  }
@@ -62874,15 +63434,15 @@ function buildProjectHandlers(deps) {
62874
63434
  } else {
62875
63435
  const name = args.name;
62876
63436
  try {
62877
- fs68.mkdirSync(root, { recursive: true });
63437
+ fs70.mkdirSync(root, { recursive: true });
62878
63438
  target = allocateDir(root, name);
62879
- fs68.mkdirSync(target);
63439
+ fs70.mkdirSync(target);
62880
63440
  } catch (err) {
62881
63441
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
62882
63442
  }
62883
- const git = (0, import_node_child_process13.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
63443
+ const git = (0, import_node_child_process14.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
62884
63444
  if (git.status !== 0) {
62885
- fs68.rmSync(target, { recursive: true, force: true });
63445
+ fs70.rmSync(target, { recursive: true, force: true });
62886
63446
  throw new ClawdError(
62887
63447
  ERROR_CODES.INVALID_CWD,
62888
63448
  `git init \u5931\u8D25\uFF08${git.error ? String(git.error) : `exit ${git.status}`}\uFF09: ${target}`
@@ -62907,8 +63467,8 @@ function buildProjectHandlers(deps) {
62907
63467
  }
62908
63468
 
62909
63469
  // src/handlers/workspace.ts
62910
- var path76 = __toESM(require("path"), 1);
62911
- var os22 = __toESM(require("os"), 1);
63470
+ var path78 = __toESM(require("path"), 1);
63471
+ var os23 = __toESM(require("os"), 1);
62912
63472
  init_protocol();
62913
63473
  init_protocol();
62914
63474
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -62948,23 +63508,23 @@ function buildWorkspaceHandlers(deps) {
62948
63508
  const list = async (frame, _client, ctx) => {
62949
63509
  const args = WorkspaceListArgs.parse(frame);
62950
63510
  const isGuest = ctx?.principal.kind === "guest";
62951
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os22.homedir();
62952
- const resolvedCwd = path76.resolve(args.cwd ?? fallbackCwd);
62953
- const target = args.path ? path76.resolve(resolvedCwd, args.path) : resolvedCwd;
63511
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os23.homedir();
63512
+ const resolvedCwd = path78.resolve(args.cwd ?? fallbackCwd);
63513
+ const target = args.path ? path78.resolve(resolvedCwd, args.path) : resolvedCwd;
62954
63514
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
62955
63515
  const res = workspace.list({ ...args, cwd: resolvedCwd });
62956
63516
  return { response: { type: "workspace:list", ...res } };
62957
63517
  };
62958
63518
  const read = async (frame, _client, ctx) => {
62959
63519
  const args = WorkspaceReadArgs.parse(frame);
62960
- const target = path76.isAbsolute(args.path) ? path76.resolve(args.path) : path76.resolve(args.cwd, args.path);
63520
+ const target = path78.isAbsolute(args.path) ? path78.resolve(args.path) : path78.resolve(args.cwd, args.path);
62961
63521
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
62962
63522
  const res = workspace.read(args);
62963
63523
  return { response: { type: "workspace:read", ...res } };
62964
63524
  };
62965
63525
  const skillsList = async (frame, _client, ctx) => {
62966
63526
  const args = SkillsListArgs.parse(frame);
62967
- const cwdAbs = path76.resolve(args.cwd);
63527
+ const cwdAbs = path78.resolve(args.cwd);
62968
63528
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
62969
63529
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
62970
63530
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -62976,7 +63536,7 @@ function buildWorkspaceHandlers(deps) {
62976
63536
  };
62977
63537
  const agentsList = async (frame, _client, ctx) => {
62978
63538
  const args = AgentsListArgs.parse(frame);
62979
- const cwdAbs = path76.resolve(args.cwd);
63539
+ const cwdAbs = path78.resolve(args.cwd);
62980
63540
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
62981
63541
  if (args.tool === "codex") {
62982
63542
  return { response: { type: "agents:list", agents: [] } };
@@ -62998,18 +63558,18 @@ function buildWorkspaceHandlers(deps) {
62998
63558
  }
62999
63559
 
63000
63560
  // src/handlers/git.ts
63001
- var path78 = __toESM(require("path"), 1);
63561
+ var path80 = __toESM(require("path"), 1);
63002
63562
  init_protocol();
63003
63563
  init_protocol();
63004
63564
 
63005
63565
  // src/workspace/git.ts
63006
- var import_node_child_process14 = require("child_process");
63566
+ var import_node_child_process15 = require("child_process");
63007
63567
  var import_node_fs51 = __toESM(require("fs"), 1);
63008
- var import_node_path60 = __toESM(require("path"), 1);
63568
+ var import_node_path62 = __toESM(require("path"), 1);
63009
63569
  var import_node_util = require("util");
63010
- var pexec = (0, import_node_util.promisify)(import_node_child_process14.execFile);
63570
+ var pexec = (0, import_node_util.promisify)(import_node_child_process15.execFile);
63011
63571
  function normalizePath(p2) {
63012
- const resolved = import_node_path60.default.resolve(p2);
63572
+ const resolved = import_node_path62.default.resolve(p2);
63013
63573
  try {
63014
63574
  return import_node_fs51.default.realpathSync(resolved);
63015
63575
  } catch {
@@ -63085,7 +63645,7 @@ async function listGitBranches(cwd) {
63085
63645
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
63086
63646
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
63087
63647
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
63088
- if (!isGuestPathAllowed(ctx.grants, path78.resolve(cwd), personaRoot, "read", userWorkDir)) {
63648
+ if (!isGuestPathAllowed(ctx.grants, path80.resolve(cwd), personaRoot, "read", userWorkDir)) {
63089
63649
  throw new ClawdError(
63090
63650
  ERROR_CODES.UNAUTHORIZED,
63091
63651
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -63630,7 +64190,7 @@ function buildFeishuAuthHandlers(deps) {
63630
64190
  }
63631
64191
 
63632
64192
  // src/handlers/meta.ts
63633
- var import_node_os20 = __toESM(require("os"), 1);
64193
+ var import_node_os21 = __toESM(require("os"), 1);
63634
64194
  init_protocol();
63635
64195
 
63636
64196
  // src/handlers/method-grants.ts
@@ -63685,6 +64245,8 @@ var METHOD_GRANT_MAP = {
63685
64245
  "deploy:putSecret": ADMIN_ANY,
63686
64246
  "deploy:reportFinding": ADMIN_ANY,
63687
64247
  "deploy:finishScan": ADMIN_ANY,
64248
+ "deploy:trial": ADMIN_ANY,
64249
+ "deploy:deploy": ADMIN_ANY,
63688
64250
  "deploy:remove": ADMIN_ANY,
63689
64251
  // ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
63690
64252
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
@@ -63931,21 +64493,21 @@ function computeMethodAccess(args) {
63931
64493
  }
63932
64494
 
63933
64495
  // src/version.ts
63934
- var version = "0.2.459".length > 0 ? "0.2.459" : "dev";
64496
+ var version = "0.2.461".length > 0 ? "0.2.461" : "dev";
63935
64497
 
63936
64498
  // src/cli-probe/probe.ts
63937
- var fs70 = __toESM(require("fs"), 1);
63938
- var path79 = __toESM(require("path"), 1);
64499
+ var fs72 = __toESM(require("fs"), 1);
64500
+ var path81 = __toESM(require("path"), 1);
63939
64501
  var PKG_NAME = "@clawos-dev/clawd";
63940
64502
  var BIN_NAME = "clawd";
63941
64503
  var MAX_PARENT_HOPS = 5;
63942
64504
  function probeGlobalCli(pathEnv) {
63943
64505
  if (!pathEnv) return null;
63944
- for (const dir of pathEnv.split(path79.delimiter)) {
64506
+ for (const dir of pathEnv.split(path81.delimiter)) {
63945
64507
  if (!dir) continue;
63946
64508
  let real;
63947
64509
  try {
63948
- real = fs70.realpathSync(path79.join(dir, BIN_NAME));
64510
+ real = fs72.realpathSync(path81.join(dir, BIN_NAME));
63949
64511
  } catch {
63950
64512
  continue;
63951
64513
  }
@@ -63955,15 +64517,15 @@ function probeGlobalCli(pathEnv) {
63955
64517
  return null;
63956
64518
  }
63957
64519
  function readOwnPackageVersion(entryPath) {
63958
- let dir = path79.dirname(entryPath);
64520
+ let dir = path81.dirname(entryPath);
63959
64521
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
63960
64522
  try {
63961
- const raw = fs70.readFileSync(path79.join(dir, "package.json"), "utf8");
64523
+ const raw = fs72.readFileSync(path81.join(dir, "package.json"), "utf8");
63962
64524
  const pkg = JSON.parse(raw);
63963
64525
  if (pkg.name !== PKG_NAME) return null;
63964
64526
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
63965
64527
  } catch {
63966
- const parent = path79.dirname(dir);
64528
+ const parent = path81.dirname(dir);
63967
64529
  if (parent === dir) return null;
63968
64530
  dir = parent;
63969
64531
  }
@@ -63999,7 +64561,7 @@ function buildReadyFrame(deps, client) {
63999
64561
  return {
64000
64562
  version,
64001
64563
  protocolVersion: PROTOCOL_VERSION,
64002
- hostname: import_node_os20.default.hostname(),
64564
+ hostname: import_node_os21.default.hostname(),
64003
64565
  os: process.platform,
64004
64566
  tools,
64005
64567
  runningSessions: info.runningSessions,
@@ -64135,7 +64697,7 @@ function buildPersonaHandlers(deps) {
64135
64697
  }
64136
64698
 
64137
64699
  // src/handlers/attachment.ts
64138
- var import_node_path61 = __toESM(require("path"), 1);
64700
+ var import_node_path63 = __toESM(require("path"), 1);
64139
64701
  init_protocol();
64140
64702
  init_protocol();
64141
64703
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -64215,12 +64777,12 @@ function buildAttachmentHandlers(deps) {
64215
64777
  `session ${args.sessionId} scope unresolved`
64216
64778
  );
64217
64779
  }
64218
- const cwdAbs = import_node_path61.default.resolve(sessionFile.cwd);
64219
- const candidateAbs = import_node_path61.default.isAbsolute(args.relPath) ? import_node_path61.default.resolve(args.relPath) : import_node_path61.default.resolve(cwdAbs, args.relPath);
64780
+ const cwdAbs = import_node_path63.default.resolve(sessionFile.cwd);
64781
+ const candidateAbs = import_node_path63.default.isAbsolute(args.relPath) ? import_node_path63.default.resolve(args.relPath) : import_node_path63.default.resolve(cwdAbs, args.relPath);
64220
64782
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
64221
64783
  const entries = deps.groupFileStore.list(scope, args.sessionId);
64222
64784
  const entry = entries.find((e) => {
64223
- const storedAbs = import_node_path61.default.isAbsolute(e.relPath) ? import_node_path61.default.resolve(e.relPath) : import_node_path61.default.resolve(cwdAbs, e.relPath);
64785
+ const storedAbs = import_node_path63.default.isAbsolute(e.relPath) ? import_node_path63.default.resolve(e.relPath) : import_node_path63.default.resolve(cwdAbs, e.relPath);
64224
64786
  return storedAbs === candidateAbs && !e.stale;
64225
64787
  });
64226
64788
  if (!entry) {
@@ -64245,7 +64807,7 @@ function buildAttachmentHandlers(deps) {
64245
64807
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
64246
64808
  const f = deps.sessionStore.read(sessionId);
64247
64809
  if (!f) return;
64248
- assertGuestAttachmentPath(ctx, import_node_path61.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
64810
+ assertGuestAttachmentPath(ctx, import_node_path63.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
64249
64811
  }
64250
64812
  const groupAdd = async (frame, _client, ctx) => {
64251
64813
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -64260,8 +64822,8 @@ function buildAttachmentHandlers(deps) {
64260
64822
  if (!scope) {
64261
64823
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
64262
64824
  }
64263
- const cwdAbs = import_node_path61.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
64264
- const candidateAbs = import_node_path61.default.isAbsolute(args.relPath) ? import_node_path61.default.resolve(args.relPath) : import_node_path61.default.resolve(cwdAbs, args.relPath);
64825
+ const cwdAbs = import_node_path63.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
64826
+ const candidateAbs = import_node_path63.default.isAbsolute(args.relPath) ? import_node_path63.default.resolve(args.relPath) : import_node_path63.default.resolve(cwdAbs, args.relPath);
64265
64827
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
64266
64828
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
64267
64829
  const size = 0;
@@ -64319,21 +64881,21 @@ function buildAttachmentHandlers(deps) {
64319
64881
  }
64320
64882
 
64321
64883
  // src/handlers/extension.ts
64322
- var import_promises14 = __toESM(require("fs/promises"), 1);
64323
- var import_node_path66 = __toESM(require("path"), 1);
64884
+ var import_promises16 = __toESM(require("fs/promises"), 1);
64885
+ var import_node_path68 = __toESM(require("path"), 1);
64324
64886
  init_protocol();
64325
64887
 
64326
64888
  // src/extension/bundle-zip.ts
64327
- var import_promises11 = __toESM(require("fs/promises"), 1);
64328
- var import_node_path62 = __toESM(require("path"), 1);
64889
+ var import_promises13 = __toESM(require("fs/promises"), 1);
64890
+ var import_node_path64 = __toESM(require("path"), 1);
64329
64891
  var import_node_crypto17 = __toESM(require("crypto"), 1);
64330
64892
  var import_jszip2 = __toESM(require_lib3(), 1);
64331
64893
  async function bundleExtensionDir(dir) {
64332
64894
  const entries = await listFilesSorted(dir);
64333
64895
  const zip = new import_jszip2.default();
64334
64896
  for (const rel of entries) {
64335
- const abs = import_node_path62.default.join(dir, rel);
64336
- const content = await import_promises11.default.readFile(abs);
64897
+ const abs = import_node_path64.default.join(dir, rel);
64898
+ const content = await import_promises13.default.readFile(abs);
64337
64899
  zip.file(rel, content, { date: FIXED_DATE });
64338
64900
  }
64339
64901
  const buffer = await zip.generateAsync({
@@ -64353,8 +64915,8 @@ async function listFilesSorted(rootDir) {
64353
64915
  return out;
64354
64916
  }
64355
64917
  async function walk(absRoot, relPrefix, out) {
64356
- const dirAbs = import_node_path62.default.join(absRoot, relPrefix);
64357
- const entries = await import_promises11.default.readdir(dirAbs, { withFileTypes: true });
64918
+ const dirAbs = import_node_path64.default.join(absRoot, relPrefix);
64919
+ const entries = await import_promises13.default.readdir(dirAbs, { withFileTypes: true });
64358
64920
  for (const e of entries) {
64359
64921
  if (IGNORE_BASENAMES.has(e.name)) continue;
64360
64922
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -64406,26 +64968,26 @@ function computePublishCheck(args) {
64406
64968
  }
64407
64969
 
64408
64970
  // src/extension/install-flow.ts
64409
- var import_promises12 = __toESM(require("fs/promises"), 1);
64410
- var import_node_path64 = __toESM(require("path"), 1);
64411
- var import_node_os22 = __toESM(require("os"), 1);
64971
+ var import_promises14 = __toESM(require("fs/promises"), 1);
64972
+ var import_node_path66 = __toESM(require("path"), 1);
64973
+ var import_node_os23 = __toESM(require("os"), 1);
64412
64974
  var import_node_crypto18 = __toESM(require("crypto"), 1);
64413
64975
  var import_jszip3 = __toESM(require_lib3(), 1);
64414
64976
 
64415
64977
  // src/extension/paths.ts
64416
- var import_node_os21 = __toESM(require("os"), 1);
64417
- var import_node_path63 = __toESM(require("path"), 1);
64978
+ var import_node_os22 = __toESM(require("os"), 1);
64979
+ var import_node_path65 = __toESM(require("path"), 1);
64418
64980
  function clawdHomeRoot(override) {
64419
- return override ?? process.env.CLAWD_HOME ?? import_node_path63.default.join(import_node_os21.default.homedir(), ".clawd");
64981
+ return override ?? process.env.CLAWD_HOME ?? import_node_path65.default.join(import_node_os22.default.homedir(), ".clawd");
64420
64982
  }
64421
64983
  function extensionsRoot(override) {
64422
- return import_node_path63.default.join(clawdHomeRoot(override), "extensions");
64984
+ return import_node_path65.default.join(clawdHomeRoot(override), "extensions");
64423
64985
  }
64424
64986
  function publishedChannelsFile(override) {
64425
- return import_node_path63.default.join(clawdHomeRoot(override), "extensions-published.json");
64987
+ return import_node_path65.default.join(clawdHomeRoot(override), "extensions-published.json");
64426
64988
  }
64427
64989
  function bundleCacheRoot(override) {
64428
- return import_node_path63.default.join(clawdHomeRoot(override), "extension-bundles");
64990
+ return import_node_path65.default.join(clawdHomeRoot(override), "extension-bundles");
64429
64991
  }
64430
64992
 
64431
64993
  // src/extension/install-flow.ts
@@ -64452,7 +65014,7 @@ async function installFromChannel(args, deps) {
64452
65014
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
64453
65015
  }
64454
65016
  for (const name of Object.keys(zip.files)) {
64455
- if (name.includes("..") || name.startsWith("/") || import_node_path64.default.isAbsolute(name)) {
65017
+ if (name.includes("..") || name.startsWith("/") || import_node_path66.default.isAbsolute(name)) {
64456
65018
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
64457
65019
  }
64458
65020
  }
@@ -64484,10 +65046,10 @@ async function installFromChannel(args, deps) {
64484
65046
  );
64485
65047
  }
64486
65048
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
64487
- const destDir = import_node_path64.default.join(deps.extensionsRoot, localExtId);
65049
+ const destDir = import_node_path66.default.join(deps.extensionsRoot, localExtId);
64488
65050
  let destExists = false;
64489
65051
  try {
64490
- await import_promises12.default.access(destDir);
65052
+ await import_promises14.default.access(destDir);
64491
65053
  destExists = true;
64492
65054
  } catch {
64493
65055
  }
@@ -64497,28 +65059,28 @@ async function installFromChannel(args, deps) {
64497
65059
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
64498
65060
  );
64499
65061
  }
64500
- const stage = await import_promises12.default.mkdtemp(
64501
- import_node_path64.default.join(import_node_os22.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
65062
+ const stage = await import_promises14.default.mkdtemp(
65063
+ import_node_path66.default.join(import_node_os23.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
64502
65064
  );
64503
65065
  try {
64504
65066
  for (const [name, entry] of Object.entries(zip.files)) {
64505
- const dest = import_node_path64.default.join(stage, name);
65067
+ const dest = import_node_path66.default.join(stage, name);
64506
65068
  if (entry.dir) {
64507
- await import_promises12.default.mkdir(dest, { recursive: true });
65069
+ await import_promises14.default.mkdir(dest, { recursive: true });
64508
65070
  continue;
64509
65071
  }
64510
- await import_promises12.default.mkdir(import_node_path64.default.dirname(dest), { recursive: true });
65072
+ await import_promises14.default.mkdir(import_node_path66.default.dirname(dest), { recursive: true });
64511
65073
  if (name === "manifest.json") {
64512
65074
  const rewritten = { ...parsed.data, id: localExtId };
64513
- await import_promises12.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
65075
+ await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64514
65076
  } else {
64515
- await import_promises12.default.writeFile(dest, await entry.async("nodebuffer"));
65077
+ await import_promises14.default.writeFile(dest, await entry.async("nodebuffer"));
64516
65078
  }
64517
65079
  }
64518
- await import_promises12.default.mkdir(deps.extensionsRoot, { recursive: true });
64519
- await import_promises12.default.rename(stage, destDir);
65080
+ await import_promises14.default.mkdir(deps.extensionsRoot, { recursive: true });
65081
+ await import_promises14.default.rename(stage, destDir);
64520
65082
  } catch (e) {
64521
- await import_promises12.default.rm(stage, { recursive: true, force: true }).catch(() => {
65083
+ await import_promises14.default.rm(stage, { recursive: true, force: true }).catch(() => {
64522
65084
  });
64523
65085
  throw e;
64524
65086
  }
@@ -64527,9 +65089,9 @@ async function installFromChannel(args, deps) {
64527
65089
  }
64528
65090
 
64529
65091
  // src/extension/update-flow.ts
64530
- var import_promises13 = __toESM(require("fs/promises"), 1);
64531
- var import_node_path65 = __toESM(require("path"), 1);
64532
- var import_node_os23 = __toESM(require("os"), 1);
65092
+ var import_promises15 = __toESM(require("fs/promises"), 1);
65093
+ var import_node_path67 = __toESM(require("path"), 1);
65094
+ var import_node_os24 = __toESM(require("os"), 1);
64533
65095
  var import_node_crypto19 = __toESM(require("crypto"), 1);
64534
65096
  var import_jszip4 = __toESM(require_lib3(), 1);
64535
65097
  var UpdateError = class extends Error {
@@ -64545,11 +65107,11 @@ async function updateFromChannel(args, deps) {
64545
65107
  channelRef.extId,
64546
65108
  channelRef.ownerPrincipalId
64547
65109
  );
64548
- const liveDir = import_node_path65.default.join(deps.extensionsRoot, localExtId);
65110
+ const liveDir = import_node_path67.default.join(deps.extensionsRoot, localExtId);
64549
65111
  const prevDir = `${liveDir}.prev`;
64550
65112
  let existingVersion;
64551
65113
  try {
64552
- const raw = await import_promises13.default.readFile(import_node_path65.default.join(liveDir, "manifest.json"), "utf8");
65114
+ const raw = await import_promises15.default.readFile(import_node_path67.default.join(liveDir, "manifest.json"), "utf8");
64553
65115
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
64554
65116
  if (!parsed2.success) {
64555
65117
  throw new UpdateError(
@@ -64582,7 +65144,7 @@ async function updateFromChannel(args, deps) {
64582
65144
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
64583
65145
  }
64584
65146
  for (const name of Object.keys(zip.files)) {
64585
- if (name.includes("..") || name.startsWith("/") || import_node_path65.default.isAbsolute(name)) {
65147
+ if (name.includes("..") || name.startsWith("/") || import_node_path67.default.isAbsolute(name)) {
64586
65148
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
64587
65149
  }
64588
65150
  }
@@ -64614,31 +65176,31 @@ async function updateFromChannel(args, deps) {
64614
65176
  );
64615
65177
  }
64616
65178
  await deps.runtime.close(localExtId);
64617
- await import_promises13.default.rm(prevDir, { recursive: true, force: true });
64618
- await import_promises13.default.rename(liveDir, prevDir);
64619
- const stage = await import_promises13.default.mkdtemp(
64620
- import_node_path65.default.join(import_node_os23.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
65179
+ await import_promises15.default.rm(prevDir, { recursive: true, force: true });
65180
+ await import_promises15.default.rename(liveDir, prevDir);
65181
+ const stage = await import_promises15.default.mkdtemp(
65182
+ import_node_path67.default.join(import_node_os24.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
64621
65183
  );
64622
65184
  try {
64623
65185
  for (const [name, entry] of Object.entries(zip.files)) {
64624
- const dest = import_node_path65.default.join(stage, name);
65186
+ const dest = import_node_path67.default.join(stage, name);
64625
65187
  if (entry.dir) {
64626
- await import_promises13.default.mkdir(dest, { recursive: true });
65188
+ await import_promises15.default.mkdir(dest, { recursive: true });
64627
65189
  continue;
64628
65190
  }
64629
- await import_promises13.default.mkdir(import_node_path65.default.dirname(dest), { recursive: true });
65191
+ await import_promises15.default.mkdir(import_node_path67.default.dirname(dest), { recursive: true });
64630
65192
  if (name === "manifest.json") {
64631
65193
  const rewritten = { ...parsed.data, id: localExtId };
64632
- await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
65194
+ await import_promises15.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64633
65195
  } else {
64634
- await import_promises13.default.writeFile(dest, await entry.async("nodebuffer"));
65196
+ await import_promises15.default.writeFile(dest, await entry.async("nodebuffer"));
64635
65197
  }
64636
65198
  }
64637
- await import_promises13.default.rename(stage, liveDir);
65199
+ await import_promises15.default.rename(stage, liveDir);
64638
65200
  } catch (e) {
64639
- await import_promises13.default.rm(stage, { recursive: true, force: true }).catch(() => {
65201
+ await import_promises15.default.rm(stage, { recursive: true, force: true }).catch(() => {
64640
65202
  });
64641
- await import_promises13.default.rename(prevDir, liveDir).catch(() => {
65203
+ await import_promises15.default.rename(prevDir, liveDir).catch(() => {
64642
65204
  });
64643
65205
  await deps.runtime.open(localExtId).catch(() => {
64644
65206
  });
@@ -64660,7 +65222,7 @@ async function updateFromChannel(args, deps) {
64660
65222
  reason: e.message
64661
65223
  };
64662
65224
  }
64663
- await import_promises13.default.rm(prevDir, { recursive: true, force: true });
65225
+ await import_promises15.default.rm(prevDir, { recursive: true, force: true });
64664
65226
  return {
64665
65227
  kind: "updated",
64666
65228
  extId: localExtId,
@@ -64668,9 +65230,9 @@ async function updateFromChannel(args, deps) {
64668
65230
  };
64669
65231
  }
64670
65232
  async function rollback(deps, localExtId, liveDir, prevDir) {
64671
- await import_promises13.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
65233
+ await import_promises15.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
64672
65234
  });
64673
- await import_promises13.default.rename(prevDir, liveDir).catch(() => {
65235
+ await import_promises15.default.rename(prevDir, liveDir).catch(() => {
64674
65236
  });
64675
65237
  await deps.runtime.open(localExtId).catch(() => {
64676
65238
  });
@@ -64693,18 +65255,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
64693
65255
  );
64694
65256
  }
64695
65257
  }
64696
- const manifestPath = import_node_path66.default.join(root, extId, "manifest.json");
65258
+ const manifestPath = import_node_path68.default.join(root, extId, "manifest.json");
64697
65259
  const manifest = await readManifest(root, extId);
64698
65260
  const next = { ...manifest, version: newVersion };
64699
65261
  const tmp = `${manifestPath}.tmp`;
64700
- await import_promises14.default.writeFile(tmp, JSON.stringify(next, null, 2));
64701
- await import_promises14.default.rename(tmp, manifestPath);
65262
+ await import_promises16.default.writeFile(tmp, JSON.stringify(next, null, 2));
65263
+ await import_promises16.default.rename(tmp, manifestPath);
64702
65264
  }
64703
65265
  async function readManifest(root, extId) {
64704
- const file = import_node_path66.default.join(root, extId, "manifest.json");
65266
+ const file = import_node_path68.default.join(root, extId, "manifest.json");
64705
65267
  let raw;
64706
65268
  try {
64707
- raw = await import_promises14.default.readFile(file, "utf8");
65269
+ raw = await import_promises16.default.readFile(file, "utf8");
64708
65270
  } catch (e) {
64709
65271
  if (e.code === "ENOENT") {
64710
65272
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -64785,7 +65347,7 @@ function buildExtensionHandlers(deps) {
64785
65347
  };
64786
65348
  async function buildSnapshotMeta(extId) {
64787
65349
  const manifest = await readManifest(deps.root, extId);
64788
- const { sha256, buffer } = await bundleExtensionDir(import_node_path66.default.join(deps.root, extId));
65350
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path68.default.join(deps.root, extId));
64789
65351
  return { manifest, contentHash: sha256, buffer };
64790
65352
  }
64791
65353
  const publish = async (frame, _client, ctx) => {
@@ -64960,7 +65522,7 @@ function buildExtensionHandlers(deps) {
64960
65522
  }
64961
65523
 
64962
65524
  // src/app-builder/kill-port.ts
64963
- var import_node_child_process15 = require("child_process");
65525
+ var import_node_child_process16 = require("child_process");
64964
65526
  async function killPortOccupants(port, ownedPids, logger) {
64965
65527
  let pids;
64966
65528
  try {
@@ -65002,7 +65564,7 @@ async function killPortOccupants(port, ownedPids, logger) {
65002
65564
  }
65003
65565
  function listPidsOnPort(port) {
65004
65566
  return new Promise((resolve9, reject) => {
65005
- (0, import_node_child_process15.execFile)(
65567
+ (0, import_node_child_process16.execFile)(
65006
65568
  "lsof",
65007
65569
  ["-ti", `:${port}`],
65008
65570
  { timeout: 3e3 },
@@ -65028,7 +65590,7 @@ var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
65028
65590
 
65029
65591
  // src/handlers/app-builder.ts
65030
65592
  init_protocol();
65031
- var import_node_path67 = require("path");
65593
+ var import_node_path69 = require("path");
65032
65594
  var import_node_fs52 = require("fs");
65033
65595
  var DEFAULT_TEMPLATE = "nestjs-react";
65034
65596
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -65175,13 +65737,13 @@ function buildAppBuilderHandlers(deps) {
65175
65737
  const created = await deps.createProjectOnDisk({
65176
65738
  store: userStore,
65177
65739
  name: f.name,
65178
- templateSrcDir: (0, import_node_path67.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
65179
- scaffoldScript: (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "new-extension.sh"),
65740
+ templateSrcDir: (0, import_node_path69.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
65741
+ scaffoldScript: (0, import_node_path69.join)(deps.deployKitRoot, "scripts", "new-extension.sh"),
65180
65742
  reservedPorts,
65181
65743
  // 凭据只进 scaffold 子进程的 env,且**只给这个 persona 的 kit 模板声明要的那几个变量**
65182
65744
  // (M1b Step 5)。整表塞进去粒度只到「进程」——那会把 service-role key 交给一个用不到
65183
65745
  // 它的脚本。new-extension.sh 用它把模板的 `${VAR}` 渲成项目可跑的 server/.env。
65184
- extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path67.join)(personaRoot, "extension-kit")),
65746
+ extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path69.join)(personaRoot, "extension-kit")),
65185
65747
  ...deps.logger ? { logger: deps.logger } : {}
65186
65748
  });
65187
65749
  project = created.project;
@@ -65380,7 +65942,7 @@ function buildAppBuilderHandlers(deps) {
65380
65942
  await userStore.clearPublishJob(args.name);
65381
65943
  }
65382
65944
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
65383
- const scriptPath = (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "publish.sh");
65945
+ const scriptPath = (0, import_node_path69.join)(deps.deployKitRoot, "scripts", "publish.sh");
65384
65946
  deps.logger?.info("app-builder.publish.start", {
65385
65947
  name: args.name,
65386
65948
  sessionId: boundSession.sessionId,
@@ -65396,7 +65958,7 @@ function buildAppBuilderHandlers(deps) {
65396
65958
  // 凭据只进 publish.sh 这个子进程的 env,且只给它的 kit 模板声明要的那几个变量
65397
65959
  // (M1b Step 5)。那个进程里跑着 `eval "$BUILD_CMD"`——项目自带的构建命令会继承这份
65398
65960
  // env,多给一个变量就是多交一个凭据给它。personaRoot 上面已按绑定 session 的 persona 解析。
65399
- extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path67.join)(personaRoot, "extension-kit")),
65961
+ extraEnv: secretsForKit(deps.readSecrets?.(), (0, import_node_path69.join)(personaRoot, "extension-kit")),
65400
65962
  hooks: {
65401
65963
  // 元数据每次写盘(publishJob 起落 / prodUrl 回填)后重推一帧:UI 渲染 PublishProgress
65402
65964
  // 三段 checklist 依赖 project.publishJob.status==='in-flight',而 publishJob 字段只有
@@ -65804,7 +66366,7 @@ function buildTopicHandlers(deps) {
65804
66366
  init_protocol();
65805
66367
 
65806
66368
  // src/channel/authority.ts
65807
- var import_promises15 = __toESM(require("fs/promises"), 1);
66369
+ var import_promises17 = __toESM(require("fs/promises"), 1);
65808
66370
  init_protocol();
65809
66371
  var DEFAULT_AUTHORITY_RULES = [
65810
66372
  { id: "outbound-message", desc: "\u4EE5\u8001\u677F\u540D\u4E49\u7ED9\u5176\u4ED6\u4EBA\u53D1\u6D88\u606F\uFF08IM/\u90AE\u4EF6\uFF09", action: "ask" },
@@ -65822,7 +66384,7 @@ async function resolveAuthority(args) {
65822
66384
  let source;
65823
66385
  let raw = null;
65824
66386
  try {
65825
- raw = await import_promises15.default.readFile(args.tablePath, "utf8");
66387
+ raw = await import_promises17.default.readFile(args.tablePath, "utf8");
65826
66388
  } catch (e) {
65827
66389
  if (e.code !== "ENOENT") {
65828
66390
  return askBecause(`\u6388\u6743\u8BBE\u5B9A\u8BFB\u4E0D\u51FA\u6765\uFF08${args.tablePath}\uFF09\uFF1A${e.message}`);
@@ -66131,12 +66693,12 @@ function buildVisitorHandlers(deps) {
66131
66693
  }
66132
66694
 
66133
66695
  // src/extension/registry.ts
66134
- var import_promises16 = __toESM(require("fs/promises"), 1);
66135
- var import_node_path68 = __toESM(require("path"), 1);
66696
+ var import_promises18 = __toESM(require("fs/promises"), 1);
66697
+ var import_node_path70 = __toESM(require("path"), 1);
66136
66698
  async function loadAll(root) {
66137
66699
  let entries;
66138
66700
  try {
66139
- entries = await import_promises16.default.readdir(root, { withFileTypes: true });
66701
+ entries = await import_promises18.default.readdir(root, { withFileTypes: true });
66140
66702
  } catch (e) {
66141
66703
  if (e.code === "ENOENT") return [];
66142
66704
  throw e;
@@ -66145,16 +66707,16 @@ async function loadAll(root) {
66145
66707
  for (const ent of entries) {
66146
66708
  if (!ent.isDirectory()) continue;
66147
66709
  if (ent.name.startsWith(".")) continue;
66148
- records.push(await loadOne(import_node_path68.default.join(root, ent.name), ent.name));
66710
+ records.push(await loadOne(import_node_path70.default.join(root, ent.name), ent.name));
66149
66711
  }
66150
66712
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
66151
66713
  return records;
66152
66714
  }
66153
66715
  async function loadOne(dir, dirName) {
66154
- const manifestPath = import_node_path68.default.join(dir, "manifest.json");
66716
+ const manifestPath = import_node_path70.default.join(dir, "manifest.json");
66155
66717
  let raw;
66156
66718
  try {
66157
- raw = await import_promises16.default.readFile(manifestPath, "utf8");
66719
+ raw = await import_promises18.default.readFile(manifestPath, "utf8");
66158
66720
  } catch {
66159
66721
  return {
66160
66722
  extId: dirName,
@@ -66195,8 +66757,8 @@ async function loadOne(dir, dirName) {
66195
66757
  }
66196
66758
 
66197
66759
  // src/extension/uninstall.ts
66198
- var import_promises17 = __toESM(require("fs/promises"), 1);
66199
- var import_node_path69 = __toESM(require("path"), 1);
66760
+ var import_promises19 = __toESM(require("fs/promises"), 1);
66761
+ var import_node_path71 = __toESM(require("path"), 1);
66200
66762
  var UninstallError = class extends Error {
66201
66763
  constructor(code, message) {
66202
66764
  super(message);
@@ -66205,14 +66767,14 @@ var UninstallError = class extends Error {
66205
66767
  code;
66206
66768
  };
66207
66769
  async function uninstall(deps) {
66208
- const dir = import_node_path69.default.join(deps.root, deps.extId);
66770
+ const dir = import_node_path71.default.join(deps.root, deps.extId);
66209
66771
  try {
66210
- await import_promises17.default.access(dir);
66772
+ await import_promises19.default.access(dir);
66211
66773
  } catch {
66212
66774
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
66213
66775
  }
66214
66776
  await deps.runtime.close(deps.extId);
66215
- await import_promises17.default.rm(dir, { recursive: true, force: true });
66777
+ await import_promises19.default.rm(dir, { recursive: true, force: true });
66216
66778
  }
66217
66779
 
66218
66780
  // src/handlers/index.ts
@@ -66222,15 +66784,15 @@ var import_node_crypto20 = require("crypto");
66222
66784
  init_protocol();
66223
66785
 
66224
66786
  // src/peer-ops/run-command.ts
66225
- var import_node_child_process16 = require("child_process");
66226
- var import_node_os24 = __toESM(require("os"), 1);
66787
+ var import_node_child_process17 = require("child_process");
66788
+ var import_node_os25 = __toESM(require("os"), 1);
66227
66789
  var DEFAULT_TIMEOUT_MS5 = 3e4;
66228
66790
  var MAX_TIMEOUT_MS = 3e5;
66229
66791
  var MAX_OUTPUT_BYTES = 1048576;
66230
66792
  function runCommand(command, opts = {}) {
66231
66793
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
66232
66794
  return new Promise((resolve9) => {
66233
- const child = (0, import_node_child_process16.spawn)("bash", ["-c", command], { cwd: import_node_os24.default.homedir() });
66795
+ const child = (0, import_node_child_process17.spawn)("bash", ["-c", command], { cwd: import_node_os25.default.homedir() });
66234
66796
  const out = [];
66235
66797
  const err = [];
66236
66798
  let outBytes = 0;
@@ -66441,7 +67003,7 @@ function buildMethodHandlers(deps) {
66441
67003
  broadcast: deps.broadcastToOwners
66442
67004
  }),
66443
67005
  ...buildMasterHandlers({
66444
- authorityTablePath: import_node_path70.default.join(deps.masterDataDir, "master-authority.json")
67006
+ authorityTablePath: import_node_path72.default.join(deps.masterDataDir, "master-authority.json")
66445
67007
  }),
66446
67008
  ...buildTopicHandlers({
66447
67009
  topicStore: deps.topicStore,
@@ -66472,23 +67034,23 @@ function buildMethodHandlers(deps) {
66472
67034
  init_protocol();
66473
67035
 
66474
67036
  // src/tools/version-probe.ts
66475
- var import_node_child_process18 = require("child_process");
67037
+ var import_node_child_process19 = require("child_process");
66476
67038
  init_claude();
66477
67039
 
66478
67040
  // src/tools/shell-path.ts
66479
- var import_node_child_process17 = require("child_process");
66480
- var import_node_os25 = __toESM(require("os"), 1);
67041
+ var import_node_child_process18 = require("child_process");
67042
+ var import_node_os26 = __toESM(require("os"), 1);
66481
67043
  function refreshPathFromLoginShell() {
66482
67044
  if (process.platform === "win32") return;
66483
- const shell = process.env.SHELL ?? import_node_os25.default.userInfo().shell ?? "/bin/zsh";
67045
+ const shell = process.env.SHELL ?? import_node_os26.default.userInfo().shell ?? "/bin/zsh";
66484
67046
  try {
66485
- const out = (0, import_node_child_process17.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
67047
+ const out = (0, import_node_child_process18.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
66486
67048
  encoding: "utf8",
66487
67049
  timeout: 3e3,
66488
67050
  stdio: ["ignore", "pipe", "ignore"]
66489
67051
  });
66490
- const path96 = out.trim();
66491
- if (path96) process.env.PATH = path96;
67052
+ const path98 = out.trim();
67053
+ if (path98) process.env.PATH = path98;
66492
67054
  } catch {
66493
67055
  }
66494
67056
  }
@@ -66499,7 +67061,7 @@ function parseVersionOutput(out) {
66499
67061
  }
66500
67062
  function execVersion(bin) {
66501
67063
  return new Promise((resolve9, reject) => {
66502
- (0, import_node_child_process18.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
67064
+ (0, import_node_child_process19.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
66503
67065
  if (err) reject(err);
66504
67066
  else resolve9(String(stdout));
66505
67067
  });
@@ -66613,8 +67175,8 @@ function buildOnboardingHandlers(deps) {
66613
67175
 
66614
67176
  // src/app-builder-plugin/project-store.ts
66615
67177
  var import_node_fs53 = require("fs");
66616
- var import_node_child_process19 = require("child_process");
66617
- var import_node_path71 = require("path");
67178
+ var import_node_child_process20 = require("child_process");
67179
+ var import_node_path73 = require("path");
66618
67180
  init_protocol();
66619
67181
  var PROJECTS_DIR = "projects";
66620
67182
  var META_FILE = ".clawd-project.json";
@@ -66644,14 +67206,14 @@ var ProjectStore = class {
66644
67206
  }
66645
67207
  /** projects/<name>/.clawd-project.json 路径 */
66646
67208
  metaPath(name) {
66647
- return (0, import_node_path71.join)(this.projectsRoot(), name, META_FILE);
67209
+ return (0, import_node_path73.join)(this.projectsRoot(), name, META_FILE);
66648
67210
  }
66649
67211
  /** projects/<name>/ 目录路径(cwd 用) */
66650
67212
  projectDir(name) {
66651
- return (0, import_node_path71.join)(this.projectsRoot(), name);
67213
+ return (0, import_node_path73.join)(this.projectsRoot(), name);
66652
67214
  }
66653
67215
  projectsRoot() {
66654
- return (0, import_node_path71.join)(this.root, PROJECTS_DIR);
67216
+ return (0, import_node_path73.join)(this.root, PROJECTS_DIR);
66655
67217
  }
66656
67218
  async list() {
66657
67219
  let entries;
@@ -66734,7 +67296,7 @@ var ProjectStore = class {
66734
67296
  async scaffold(name, templateSrcDir, scaffoldScriptPath, extraEnv) {
66735
67297
  const destDir = this.projectDir(name);
66736
67298
  return await new Promise((resolve9, reject) => {
66737
- const child = (0, import_node_child_process19.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
67299
+ const child = (0, import_node_child_process20.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
66738
67300
  // extraEnv 排在 PATH **之前**:凭据表里若混进一条名叫 PATH 的条目,顶掉 PATH 会让
66739
67301
  // 脚本以「命令找不到」的形态崩在离现场很远的地方。
66740
67302
  env: { ...process.env, ...extraEnv ?? {}, PATH: process.env.PATH ?? "" },
@@ -66848,7 +67410,7 @@ var ProjectStore = class {
66848
67410
  };
66849
67411
 
66850
67412
  // src/app-builder/dev-server-supervisor.ts
66851
- var import_node_child_process20 = require("child_process");
67413
+ var import_node_child_process21 = require("child_process");
66852
67414
  var import_node_events2 = require("events");
66853
67415
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
66854
67416
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -66885,7 +67447,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
66885
67447
  tunnelHost: args.tunnelHost,
66886
67448
  devCommand: cmd
66887
67449
  });
66888
- const child = (0, import_node_child_process20.spawn)("sh", ["-c", cmd], {
67450
+ const child = (0, import_node_child_process21.spawn)("sh", ["-c", cmd], {
66889
67451
  cwd: args.cwd,
66890
67452
  env,
66891
67453
  stdio: "pipe",
@@ -67101,6 +67663,9 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
67101
67663
  }
67102
67664
  };
67103
67665
 
67666
+ // src/app-builder-plugin/core.ts
67667
+ var import_node_child_process23 = require("child_process");
67668
+
67104
67669
  // src/app-builder-plugin/publish-registry.ts
67105
67670
  var import_node_crypto21 = require("crypto");
67106
67671
  var PublishJobRegistry = class {
@@ -67152,9 +67717,9 @@ var PublishJobRegistry = class {
67152
67717
  };
67153
67718
 
67154
67719
  // src/app-builder-plugin/publish-job-runner.ts
67155
- var import_node_child_process21 = require("child_process");
67720
+ var import_node_child_process22 = require("child_process");
67156
67721
  var import_node_fs54 = require("fs");
67157
- var import_node_path72 = require("path");
67722
+ var import_node_path74 = require("path");
67158
67723
 
67159
67724
  // src/app-builder-plugin/publish-stage-parser.ts
67160
67725
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -67181,19 +67746,19 @@ function tailStderrLines(buf, n) {
67181
67746
  // src/app-builder-plugin/publish-job-runner.ts
67182
67747
  async function startPublishJob(deps, args) {
67183
67748
  const { registry: registry2, projectDir } = deps;
67184
- const spawn13 = deps.spawnImpl ?? import_node_child_process21.spawn;
67749
+ const spawn14 = deps.spawnImpl ?? import_node_child_process22.spawn;
67185
67750
  if (registry2.has(args.name)) {
67186
67751
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
67187
67752
  }
67188
67753
  const projDir = projectDir(args.name);
67189
- const logPath = (0, import_node_path72.join)(projDir, ".publish.log");
67754
+ const logPath = (0, import_node_path74.join)(projDir, ".publish.log");
67190
67755
  let logStream = null;
67191
67756
  try {
67192
67757
  logStream = (0, import_node_fs54.createWriteStream)(logPath, { flags: "w" });
67193
67758
  } catch {
67194
67759
  logStream = null;
67195
67760
  }
67196
- const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
67761
+ const child = spawn14("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
67197
67762
  cwd: projDir,
67198
67763
  // 宿主给的 env 覆盖在 process.env 之上:daemon 进程本身没有这些变量(它们只在这一个
67199
67764
  // 子进程里活着)。云上宿主不传 extraEnv,凭据本来就在容器 env 里。
@@ -67523,6 +68088,7 @@ async function createProjectOnDisk(args) {
67523
68088
  }
67524
68089
  return { project, projectDir: store.projectDir(name) };
67525
68090
  }
68091
+ var REMOVE_TIMEOUT_MS = 10 * 6e4;
67526
68092
  async function recoverInterruptedPublishJobs(store, logger) {
67527
68093
  await recoverInterruptedJobs({
67528
68094
  listAllProjects: async () => store.list(),
@@ -67532,9 +68098,9 @@ async function recoverInterruptedPublishJobs(store, logger) {
67532
68098
 
67533
68099
  // src/app-builder-plugin/mcp-config.ts
67534
68100
  var import_node_fs55 = __toESM(require("fs"), 1);
67535
- var import_node_path73 = __toESM(require("path"), 1);
68101
+ var import_node_path75 = __toESM(require("path"), 1);
67536
68102
  function appBuilderMcpConfigPath(dataDir) {
67537
- return import_node_path73.default.join(dataDir, "app-builder.mcp.json");
68103
+ return import_node_path75.default.join(dataDir, "app-builder.mcp.json");
67538
68104
  }
67539
68105
  function writeAppBuilderMcpConfig(args) {
67540
68106
  const cfgPath = appBuilderMcpConfigPath(args.dataDir);
@@ -67548,8 +68114,8 @@ function writeAppBuilderMcpConfig(args) {
67548
68114
  env: {
67549
68115
  CLAWD_DAEMON_TOKEN: args.daemonToken,
67550
68116
  CLAWD_DAEMON_URL: args.daemonUrl,
67551
- CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path73.default.join(args.deployKitScriptsDir, "new-extension.sh"),
67552
- CLAWD_APP_BUILDER_PUBLISH_SCRIPT: import_node_path73.default.join(args.deployKitScriptsDir, "publish.sh"),
68117
+ CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path75.default.join(args.deployKitScriptsDir, "new-extension.sh"),
68118
+ CLAWD_APP_BUILDER_PUBLISH_SCRIPT: import_node_path75.default.join(args.deployKitScriptsDir, "publish.sh"),
67553
68119
  ...args.logPath ? { CLAWD_APP_BUILDER_LOG: args.logPath } : {}
67554
68120
  }
67555
68121
  }
@@ -67596,9 +68162,9 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
67596
68162
  }
67597
68163
 
67598
68164
  // src/extension/runtime.ts
67599
- var import_node_child_process22 = require("child_process");
67600
- var import_node_path74 = __toESM(require("path"), 1);
67601
- var import_promises18 = require("timers/promises");
68165
+ var import_node_child_process24 = require("child_process");
68166
+ var import_node_path76 = __toESM(require("path"), 1);
68167
+ var import_promises20 = require("timers/promises");
67602
68168
 
67603
68169
  // src/extension/port-allocator.ts
67604
68170
  var import_node_net2 = __toESM(require("net"), 1);
@@ -67698,13 +68264,13 @@ var Runtime = class {
67698
68264
  /\$CLAWOS_EXT_PORT/g,
67699
68265
  String(port)
67700
68266
  );
67701
- const dir = import_node_path74.default.join(this.root, extId);
68267
+ const dir = import_node_path76.default.join(this.root, extId);
67702
68268
  const env = {
67703
68269
  ...process.env,
67704
68270
  CLAWOS_EXT_PORT: String(port),
67705
68271
  CLAWOS_EXT_ID: extId
67706
68272
  };
67707
- const child = (0, import_node_child_process22.spawn)("sh", ["-c", cmd], {
68273
+ const child = (0, import_node_child_process24.spawn)("sh", ["-c", cmd], {
67708
68274
  cwd: dir,
67709
68275
  env,
67710
68276
  stdio: ["ignore", "pipe", "pipe"],
@@ -67774,7 +68340,7 @@ ${handle.stderrTail}`
67774
68340
  if (res.ok) return;
67775
68341
  } catch {
67776
68342
  }
67777
- await (0, import_promises18.setTimeout)(this.healthzIntervalMs);
68343
+ await (0, import_promises20.setTimeout)(this.healthzIntervalMs);
67778
68344
  }
67779
68345
  throw new RuntimeError(
67780
68346
  "HEALTHZ_FAILED",
@@ -67799,7 +68365,7 @@ ${handle.stderrTail}`
67799
68365
  };
67800
68366
  killGroup("SIGTERM");
67801
68367
  const exited = new Promise((resolve9) => child.once("exit", () => resolve9()));
67802
- const timed = (0, import_promises18.setTimeout)(5e3).then(() => "timeout");
68368
+ const timed = (0, import_promises20.setTimeout)(5e3).then(() => "timeout");
67803
68369
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
67804
68370
  if (winner === "timeout" && child.exitCode === null) {
67805
68371
  killGroup("SIGKILL");
@@ -67809,8 +68375,8 @@ ${handle.stderrTail}`
67809
68375
  };
67810
68376
 
67811
68377
  // src/extension/published-channels.ts
67812
- var import_promises19 = __toESM(require("fs/promises"), 1);
67813
- var import_node_path75 = __toESM(require("path"), 1);
68378
+ var import_promises21 = __toESM(require("fs/promises"), 1);
68379
+ var import_node_path77 = __toESM(require("path"), 1);
67814
68380
  init_zod();
67815
68381
  var PublishedChannelsError = class extends Error {
67816
68382
  constructor(code, message) {
@@ -67840,7 +68406,7 @@ var PublishedChannelStore = class {
67840
68406
  this.channels.clear();
67841
68407
  let raw;
67842
68408
  try {
67843
- raw = await import_promises19.default.readFile(this.filePath, "utf8");
68409
+ raw = await import_promises21.default.readFile(this.filePath, "utf8");
67844
68410
  } catch (e) {
67845
68411
  if (e.code === "ENOENT") {
67846
68412
  this.loaded = true;
@@ -67909,15 +68475,15 @@ var PublishedChannelStore = class {
67909
68475
  )
67910
68476
  };
67911
68477
  const tmp = `${this.filePath}.tmp`;
67912
- await import_promises19.default.mkdir(import_node_path75.default.dirname(this.filePath), { recursive: true });
67913
- await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
67914
- await import_promises19.default.rename(tmp, this.filePath);
68478
+ await import_promises21.default.mkdir(import_node_path77.default.dirname(this.filePath), { recursive: true });
68479
+ await import_promises21.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
68480
+ await import_promises21.default.rename(tmp, this.filePath);
67915
68481
  }
67916
68482
  };
67917
68483
 
67918
68484
  // src/extension/bundle-cache.ts
67919
- var import_promises20 = __toESM(require("fs/promises"), 1);
67920
- var import_node_path76 = __toESM(require("path"), 1);
68485
+ var import_promises22 = __toESM(require("fs/promises"), 1);
68486
+ var import_node_path78 = __toESM(require("path"), 1);
67921
68487
  var BundleCache = class {
67922
68488
  constructor(rootDir) {
67923
68489
  this.rootDir = rootDir;
@@ -67925,17 +68491,17 @@ var BundleCache = class {
67925
68491
  rootDir;
67926
68492
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
67927
68493
  async write(snapshotHash, buffer) {
67928
- await import_promises20.default.mkdir(this.rootDir, { recursive: true });
67929
- const file = import_node_path76.default.join(this.rootDir, `${snapshotHash}.zip`);
68494
+ await import_promises22.default.mkdir(this.rootDir, { recursive: true });
68495
+ const file = import_node_path78.default.join(this.rootDir, `${snapshotHash}.zip`);
67930
68496
  const tmp = `${file}.tmp`;
67931
- await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
67932
- await import_promises20.default.rename(tmp, file);
68497
+ await import_promises22.default.writeFile(tmp, buffer, { mode: 384 });
68498
+ await import_promises22.default.rename(tmp, file);
67933
68499
  }
67934
68500
  /** Returns the bundle bytes, or null when the file doesn't exist. */
67935
68501
  async read(snapshotHash) {
67936
- const file = import_node_path76.default.join(this.rootDir, `${snapshotHash}.zip`);
68502
+ const file = import_node_path78.default.join(this.rootDir, `${snapshotHash}.zip`);
67937
68503
  try {
67938
- return await import_promises20.default.readFile(file);
68504
+ return await import_promises22.default.readFile(file);
67939
68505
  } catch (e) {
67940
68506
  if (e.code === "ENOENT") return null;
67941
68507
  throw e;
@@ -67943,8 +68509,8 @@ var BundleCache = class {
67943
68509
  }
67944
68510
  /** Idempotent — missing file is not an error. */
67945
68511
  async delete(snapshotHash) {
67946
- const file = import_node_path76.default.join(this.rootDir, `${snapshotHash}.zip`);
67947
- await import_promises20.default.rm(file, { force: true });
68512
+ const file = import_node_path78.default.join(this.rootDir, `${snapshotHash}.zip`);
68513
+ await import_promises22.default.rm(file, { force: true });
67948
68514
  }
67949
68515
  };
67950
68516
 
@@ -67964,26 +68530,26 @@ async function startDaemon(config) {
67964
68530
  },
67965
68531
  source: "daemon",
67966
68532
  sampling: logShippingCfg.sampling,
67967
- homeDir: import_node_os26.default.homedir()
68533
+ homeDir: import_node_os27.default.homedir()
67968
68534
  });
67969
- const logDir = import_node_path77.default.join(config.dataDir, "log");
68535
+ const logDir = import_node_path79.default.join(config.dataDir, "log");
67970
68536
  import_node_fs56.default.mkdirSync(logDir, { recursive: true });
67971
68537
  const logger = createLogger({
67972
68538
  level: config.logLevel,
67973
- file: import_node_path77.default.join(logDir, "clawd.log"),
68539
+ file: import_node_path79.default.join(logDir, "clawd.log"),
67974
68540
  logClient
67975
68541
  });
67976
68542
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
67977
68543
  const screenIdleProbeLogger = createFileOnlyLogger({
67978
- file: import_node_path77.default.join(logDir, "screen-idle-probe.log"),
68544
+ file: import_node_path79.default.join(logDir, "screen-idle-probe.log"),
67979
68545
  level: "debug"
67980
68546
  });
67981
68547
  logger.info("screen-idle probe logger enabled", {
67982
- file: import_node_path77.default.join(logDir, "screen-idle-probe.log")
68548
+ file: import_node_path79.default.join(logDir, "screen-idle-probe.log")
67983
68549
  });
67984
68550
  const CAP_TARGETS = [
67985
- import_node_path77.default.join(logDir, "clawd.log"),
67986
- import_node_path77.default.join(logDir, "screen-idle-probe.log")
68551
+ import_node_path79.default.join(logDir, "clawd.log"),
68552
+ import_node_path79.default.join(logDir, "screen-idle-probe.log")
67987
68553
  ];
67988
68554
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
67989
68555
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -68105,8 +68671,8 @@ async function startDaemon(config) {
68105
68671
  const agents = new AgentsScanner();
68106
68672
  const history = new ClaudeHistoryReader();
68107
68673
  let transport = null;
68108
- const personaStore = new PersonaStore(import_node_path77.default.join(config.dataDir, "personas"));
68109
- const usersRoot = import_node_path77.default.join(config.dataDir, "users");
68674
+ const personaStore = new PersonaStore(import_node_path79.default.join(config.dataDir, "personas"));
68675
+ const usersRoot = import_node_path79.default.join(config.dataDir, "users");
68110
68676
  const defaultsRoot = findDefaultsRoot(logger);
68111
68677
  if (defaultsRoot) {
68112
68678
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -68130,7 +68696,7 @@ async function startDaemon(config) {
68130
68696
  retirePersonaBuilder({ store: personaStore, logger });
68131
68697
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
68132
68698
  const dispatchStore = createDispatchStore({
68133
- filePath: import_node_path77.default.join(config.dataDir, "dispatch.json"),
68699
+ filePath: import_node_path79.default.join(config.dataDir, "dispatch.json"),
68134
68700
  now: () => Date.now(),
68135
68701
  onFlushError: (err) => logger.error("dispatch store flush failed", {
68136
68702
  reason: err instanceof Error ? err.message : String(err)
@@ -68139,7 +68705,7 @@ async function startDaemon(config) {
68139
68705
  await dispatchStore.load();
68140
68706
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
68141
68707
  const channelStore = createChannelStore({
68142
- filePath: import_node_path77.default.join(config.dataDir, "channels.json"),
68708
+ filePath: import_node_path79.default.join(config.dataDir, "channels.json"),
68143
68709
  now: () => Date.now(),
68144
68710
  genId: () => `ch-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68145
68711
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -68148,7 +68714,7 @@ async function startDaemon(config) {
68148
68714
  });
68149
68715
  await channelStore.load();
68150
68716
  const topicStore = createTopicStore({
68151
- filePath: import_node_path77.default.join(config.dataDir, "topics.json"),
68717
+ filePath: import_node_path79.default.join(config.dataDir, "topics.json"),
68152
68718
  now: () => Date.now(),
68153
68719
  genId: () => `tp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68154
68720
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -68175,28 +68741,28 @@ async function startDaemon(config) {
68175
68741
  });
68176
68742
  }
68177
68743
  });
68178
- const here = typeof __dirname === "string" ? __dirname : import_node_path77.default.dirname((0, import_node_url5.fileURLToPath)(import_meta8.url));
68744
+ const here = typeof __dirname === "string" ? __dirname : import_node_path79.default.dirname((0, import_node_url5.fileURLToPath)(import_meta8.url));
68179
68745
  const mcpConfigs = [];
68180
68746
  const secretsBundleRoot = findSecretsBundleRoot(logger);
68181
- const localSecretsDir = import_node_path77.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
68747
+ const localSecretsDir = import_node_path79.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
68182
68748
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
68183
68749
  const resolvePersonaMcpConfig = (personaId2) => renderPersonaMcpSecrets({
68184
68750
  personaId: personaId2,
68185
- personaDir: import_node_path77.default.join(config.dataDir, "personas", personaId2),
68751
+ personaDir: import_node_path79.default.join(config.dataDir, "personas", personaId2),
68186
68752
  secrets: readSecrets(),
68187
- outDir: import_node_path77.default.join(config.dataDir, "persona-mcp"),
68753
+ outDir: import_node_path79.default.join(config.dataDir, "persona-mcp"),
68188
68754
  logger
68189
68755
  });
68190
68756
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
68191
68757
  const dispatchServerCandidates = [
68192
- import_node_path77.default.join(here, "dispatch", "mcp-server.cjs"),
68758
+ import_node_path79.default.join(here, "dispatch", "mcp-server.cjs"),
68193
68759
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
68194
- import_node_path77.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
68760
+ import_node_path79.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
68195
68761
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
68196
68762
  ];
68197
68763
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68198
68764
  if (dispatchServerScriptPath) {
68199
- const dispatchLogPath = import_node_path77.default.join(logDir, "dispatch-mcp-server.log");
68765
+ const dispatchLogPath = import_node_path79.default.join(logDir, "dispatch-mcp-server.log");
68200
68766
  const dispatchCfgPath = writeDispatchMcpConfig({
68201
68767
  dataDir: config.dataDir,
68202
68768
  serverScriptPath: dispatchServerScriptPath,
@@ -68216,12 +68782,12 @@ async function startDaemon(config) {
68216
68782
  });
68217
68783
  }
68218
68784
  const ticketServerCandidates = [
68219
- import_node_path77.default.join(here, "ticket", "mcp-server.cjs"),
68220
- import_node_path77.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
68785
+ import_node_path79.default.join(here, "ticket", "mcp-server.cjs"),
68786
+ import_node_path79.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
68221
68787
  ];
68222
68788
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68223
68789
  if (ticketServerScriptPath) {
68224
- const ticketLogPath = import_node_path77.default.join(logDir, "ticket-mcp-server.log");
68790
+ const ticketLogPath = import_node_path79.default.join(logDir, "ticket-mcp-server.log");
68225
68791
  const ticketCfgPath = writeTicketMcpConfig({
68226
68792
  dataDir: config.dataDir,
68227
68793
  serverScriptPath: ticketServerScriptPath,
@@ -68243,12 +68809,12 @@ async function startDaemon(config) {
68243
68809
  });
68244
68810
  }
68245
68811
  const shiftServerCandidates = [
68246
- import_node_path77.default.join(here, "shift", "mcp-server.cjs"),
68247
- import_node_path77.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
68812
+ import_node_path79.default.join(here, "shift", "mcp-server.cjs"),
68813
+ import_node_path79.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
68248
68814
  ];
68249
68815
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68250
68816
  if (shiftServerScriptPath) {
68251
- const shiftLogPath = import_node_path77.default.join(logDir, "shift-mcp-server.log");
68817
+ const shiftLogPath = import_node_path79.default.join(logDir, "shift-mcp-server.log");
68252
68818
  const shiftCfgPath = await writeShiftMcpConfig({
68253
68819
  dataDir: config.dataDir,
68254
68820
  serverScriptPath: shiftServerScriptPath,
@@ -68269,12 +68835,12 @@ async function startDaemon(config) {
68269
68835
  );
68270
68836
  }
68271
68837
  const inboxServerCandidates = [
68272
- import_node_path77.default.join(here, "inbox", "mcp-server.cjs"),
68273
- import_node_path77.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
68838
+ import_node_path79.default.join(here, "inbox", "mcp-server.cjs"),
68839
+ import_node_path79.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
68274
68840
  ];
68275
68841
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68276
68842
  if (inboxServerScriptPath) {
68277
- const inboxLogPath = import_node_path77.default.join(logDir, "inbox-mcp-server.log");
68843
+ const inboxLogPath = import_node_path79.default.join(logDir, "inbox-mcp-server.log");
68278
68844
  const inboxCfgPath = await writeInboxMcpConfig({
68279
68845
  dataDir: config.dataDir,
68280
68846
  serverScriptPath: inboxServerScriptPath,
@@ -68295,8 +68861,8 @@ async function startDaemon(config) {
68295
68861
  );
68296
68862
  }
68297
68863
  const peerOpsServerCandidates = [
68298
- import_node_path77.default.join(here, "peer-ops", "mcp-server.cjs"),
68299
- import_node_path77.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
68864
+ import_node_path79.default.join(here, "peer-ops", "mcp-server.cjs"),
68865
+ import_node_path79.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
68300
68866
  ];
68301
68867
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68302
68868
  if (peerOpsServerScriptPath) {
@@ -68318,12 +68884,12 @@ async function startDaemon(config) {
68318
68884
  );
68319
68885
  }
68320
68886
  const rpcToolServerCandidates = [
68321
- import_node_path77.default.join(here, "rpc-tool", "mcp-server.cjs"),
68322
- import_node_path77.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
68887
+ import_node_path79.default.join(here, "rpc-tool", "mcp-server.cjs"),
68888
+ import_node_path79.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
68323
68889
  ];
68324
68890
  const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68325
68891
  if (rpcToolServerScriptPath) {
68326
- const rpcToolLogPath = import_node_path77.default.join(logDir, "rpc-tool-mcp-server.log");
68892
+ const rpcToolLogPath = import_node_path79.default.join(logDir, "rpc-tool-mcp-server.log");
68327
68893
  const rpcToolCfgPath = writeRpcToolMcpConfig({
68328
68894
  dataDir: config.dataDir,
68329
68895
  serverScriptPath: rpcToolServerScriptPath,
@@ -68344,18 +68910,18 @@ async function startDaemon(config) {
68344
68910
  );
68345
68911
  }
68346
68912
  const appBuilderServerCandidates = [
68347
- import_node_path77.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
68348
- import_node_path77.default.join(here, "..", "dist", "app-builder-plugin", "mcp-server.cjs")
68913
+ import_node_path79.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
68914
+ import_node_path79.default.join(here, "..", "dist", "app-builder-plugin", "mcp-server.cjs")
68349
68915
  ];
68350
68916
  const appBuilderServerScriptPath = appBuilderServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68351
68917
  if (appBuilderServerScriptPath) {
68352
- const appBuilderLogPath = import_node_path77.default.join(logDir, "app-builder-mcp-server.log");
68918
+ const appBuilderLogPath = import_node_path79.default.join(logDir, "app-builder-mcp-server.log");
68353
68919
  const appBuilderCfgPath = writeAppBuilderMcpConfig({
68354
68920
  dataDir: config.dataDir,
68355
68921
  serverScriptPath: appBuilderServerScriptPath,
68356
68922
  daemonToken: resolvedAuthToken,
68357
68923
  daemonUrl: mcpDaemonUrl,
68358
- deployKitScriptsDir: import_node_path77.default.join(config.dataDir, "deploy-kit", "scripts"),
68924
+ deployKitScriptsDir: import_node_path79.default.join(config.dataDir, "deploy-kit", "scripts"),
68359
68925
  logPath: appBuilderLogPath
68360
68926
  });
68361
68927
  mcpConfigs.push({ id: "app-builder", path: appBuilderCfgPath, personas: APP_BUILDER_PERSONAS });
@@ -68371,7 +68937,7 @@ async function startDaemon(config) {
68371
68937
  );
68372
68938
  }
68373
68939
  const shiftStore = createShiftStore({
68374
- filePath: import_node_path77.default.join(config.dataDir, "shift.json"),
68940
+ filePath: import_node_path79.default.join(config.dataDir, "shift.json"),
68375
68941
  ownerIdProvider: () => ownerPrincipalId,
68376
68942
  now: () => Date.now()
68377
68943
  });
@@ -68393,7 +68959,7 @@ async function startDaemon(config) {
68393
68959
  getAdapter,
68394
68960
  historyReader: history,
68395
68961
  dataDir: config.dataDir,
68396
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
68962
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68397
68963
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
68398
68964
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
68399
68965
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -68450,7 +69016,7 @@ async function startDaemon(config) {
68450
69016
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
68451
69017
  attachmentGroup: {
68452
69018
  onFileEdit: (input) => {
68453
- const absPath = import_node_path77.default.isAbsolute(input.relPath) ? input.relPath : import_node_path77.default.join(input.cwd, input.relPath);
69019
+ const absPath = import_node_path79.default.isAbsolute(input.relPath) ? input.relPath : import_node_path79.default.join(input.cwd, input.relPath);
68454
69020
  let size = 0;
68455
69021
  try {
68456
69022
  size = import_node_fs56.default.statSync(absPath).size;
@@ -68483,9 +69049,9 @@ async function startDaemon(config) {
68483
69049
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
68484
69050
  }
68485
69051
  const projectsStore = new ProjectsStore({
68486
- file: import_node_path77.default.join(config.dataDir, "projects.json"),
69052
+ file: import_node_path79.default.join(config.dataDir, "projects.json"),
68487
69053
  clawdDir: config.dataDir,
68488
- codexStateFile: import_node_path77.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
69054
+ codexStateFile: import_node_path79.default.join(import_node_os27.default.homedir(), ".codex", ".codex-global-state.json"),
68489
69055
  logger
68490
69056
  });
68491
69057
  const observer = new SessionObserver({
@@ -68545,12 +69111,12 @@ async function startDaemon(config) {
68545
69111
  screenIdleProbeLogger
68546
69112
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
68547
69113
  registerAdapter("claude", claudeAdapter);
68548
- const codexIsolatedHome = import_node_path77.default.join(config.dataDir, "codex-home");
69114
+ const codexIsolatedHome = import_node_path79.default.join(config.dataDir, "codex-home");
68549
69115
  try {
68550
69116
  import_node_fs56.default.mkdirSync(codexIsolatedHome, { recursive: true });
68551
69117
  for (const f of ["auth.json", "config.toml"]) {
68552
- const link = import_node_path77.default.join(codexIsolatedHome, f);
68553
- const target = import_node_path77.default.join(import_node_os26.default.homedir(), ".codex", f);
69118
+ const link = import_node_path79.default.join(codexIsolatedHome, f);
69119
+ const target = import_node_path79.default.join(import_node_os27.default.homedir(), ".codex", f);
68554
69120
  if (!import_node_fs56.default.existsSync(link) && import_node_fs56.default.existsSync(target)) import_node_fs56.default.symlinkSync(target, link);
68555
69121
  }
68556
69122
  } catch (err) {
@@ -68564,11 +69130,11 @@ async function startDaemon(config) {
68564
69130
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
68565
69131
  codexHomeFor: (cwd) => resolveCodexHome({
68566
69132
  cwd,
68567
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69133
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68568
69134
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
68569
69135
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
68570
69136
  projectPaths: projectsStore.listMerged().map((x) => x.path),
68571
- sharedHome: import_node_path77.default.join(import_node_os26.default.homedir(), ".codex"),
69137
+ sharedHome: import_node_path79.default.join(import_node_os27.default.homedir(), ".codex"),
68572
69138
  isolatedHome: codexIsolatedHome
68573
69139
  })
68574
69140
  })
@@ -68853,11 +69419,11 @@ async function startDaemon(config) {
68853
69419
  // 'persona/<pid>/owner',default 走 'default'。
68854
69420
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
68855
69421
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
68856
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69422
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68857
69423
  usersRoot
68858
69424
  },
68859
69425
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
68860
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69426
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68861
69427
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
68862
69428
  usersRoot,
68863
69429
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -68958,11 +69524,11 @@ async function startDaemon(config) {
68958
69524
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
68959
69525
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
68960
69526
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
68961
- appBuilderPersonaRoot: import_node_path77.default.join(config.dataDir, "personas", "persona-app-builder"),
69527
+ appBuilderPersonaRoot: import_node_path79.default.join(config.dataDir, "personas", "persona-app-builder"),
68962
69528
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
68963
- deployKitRoot: import_node_path77.default.join(config.dataDir, "deploy-kit"),
69529
+ deployKitRoot: import_node_path79.default.join(config.dataDir, "deploy-kit"),
68964
69530
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
68965
- resolvePersonaRoot: (personaId2) => import_node_path77.default.join(config.dataDir, "personas", personaId2),
69531
+ resolvePersonaRoot: (personaId2) => import_node_path79.default.join(config.dataDir, "personas", personaId2),
68966
69532
  // 凭据表(M1b Step 5):与 MCP 那条同一张表、同一个来源,只是交付给另一个子进程。
68967
69533
  readSecrets,
68968
69534
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
@@ -69019,7 +69585,7 @@ async function startDaemon(config) {
69019
69585
  sourceSessionId: args.sourceSessionId
69020
69586
  });
69021
69587
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
69022
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os26.default.homedir());
69588
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os27.default.homedir());
69023
69589
  logger.info("dispatch.spawnB.source-resolved", {
69024
69590
  dispatchId: args.dispatchId,
69025
69591
  sourceJsonlPath,
@@ -69077,12 +69643,12 @@ async function startDaemon(config) {
69077
69643
  });
69078
69644
  Object.assign(handlers, shiftHandlers);
69079
69645
  const deployReceipts = createReceiptStore({
69080
- filePath: import_node_path77.default.join(config.dataDir, "deploy.json"),
69646
+ filePath: import_node_path79.default.join(config.dataDir, "deploy.json"),
69081
69647
  now: () => Date.now(),
69082
69648
  onFlushError: (err) => logger.error("deploy receipts flush failed", { error: String(err) })
69083
69649
  });
69084
69650
  const deploySecrets = createSecretStore({
69085
- filePath: import_node_path77.default.join(config.dataDir, "deploy-secrets.json"),
69651
+ filePath: import_node_path79.default.join(config.dataDir, "deploy-secrets.json"),
69086
69652
  now: () => Date.now(),
69087
69653
  onFlushError: (err) => logger.error("deploy secrets flush failed", { error: String(err) })
69088
69654
  });
@@ -69090,13 +69656,72 @@ async function startDaemon(config) {
69090
69656
  await deploySecrets.load();
69091
69657
  const interrupted = reconcileInterruptedScans(deployReceipts);
69092
69658
  if (interrupted.length > 0) logger.warn("deploy scans interrupted by restart", { deployIds: interrupted });
69659
+ const interruptedTrials = reconcileInterruptedTrials(deployReceipts);
69660
+ if (interruptedTrials.length > 0) logger.warn("deploy trials interrupted by restart", { deployIds: interruptedTrials });
69661
+ async function runTrialForReceipt(deployId) {
69662
+ const receipt = deployReceipts.get(deployId);
69663
+ if (!receipt) return;
69664
+ let cloudHost;
69665
+ try {
69666
+ cloudHost = await loadCloudHostConfig(config.dataDir);
69667
+ } catch (err) {
69668
+ deployReceipts.update(deployId, {
69669
+ status: "failed",
69670
+ trialStage: void 0,
69671
+ // 同 gap 的其它两个来源:自由文本落单据前一律过涂抹
69672
+ gaps: [{ errorText: redactSecretValues(err instanceof CloudHostConfigError ? err.message : String(err)) }]
69673
+ });
69674
+ return;
69675
+ }
69676
+ const outcome = await runTrial(
69677
+ {
69678
+ cloudHost,
69679
+ runNode: (script, args, opts) => runNodeScript(script, args, opts.timeoutMs),
69680
+ fetchImpl: fetch,
69681
+ now: () => Date.now(),
69682
+ onStage: (stage) => {
69683
+ deployReceipts.update(deployId, { trialStage: stage });
69684
+ },
69685
+ logger: {
69686
+ info: (msg, meta) => logger.info(msg, meta),
69687
+ warn: (msg, meta) => logger.warn(msg, meta)
69688
+ }
69689
+ },
69690
+ {
69691
+ receipt,
69692
+ // 试装带全量(含使用者自带那几条的临时垫付值)——它要真跑一次发布
69693
+ secretTable: secretTableFor(receipt, deploySecrets.resolve(deployId), "all"),
69694
+ round: receipt.trialRound
69695
+ }
69696
+ );
69697
+ if (outcome.ok) {
69698
+ deployReceipts.update(deployId, {
69699
+ // 通过之后回 ready 而不是直接 deployed:部署是人的第二次决定(见 deploy-schemas 状态机)
69700
+ status: "ready",
69701
+ trialStage: void 0,
69702
+ trialPassedAt: Date.now(),
69703
+ trialImage: outcome.image,
69704
+ gaps: []
69705
+ });
69706
+ logger.info("deploy trial passed", { deployId, image: outcome.image });
69707
+ } else {
69708
+ const current = deployReceipts.get(deployId)?.trialRound ?? receipt.trialRound;
69709
+ deployReceipts.update(deployId, {
69710
+ status: "failed",
69711
+ trialStage: void 0,
69712
+ gaps: outcome.gaps,
69713
+ ...outcome.spent ? {} : { trialRound: Math.max(0, current - 1) }
69714
+ });
69715
+ logger.warn("deploy trial failed", { deployId, gaps: outcome.gaps.length, spent: outcome.spent });
69716
+ }
69717
+ }
69093
69718
  const deployHandlers = buildDeployHandlers({
69094
69719
  receipts: deployReceipts,
69095
69720
  secrets: deploySecrets,
69096
69721
  hasPersona: (personaId2) => personaStore.has(personaId2),
69097
69722
  startScan: (deployId, personaId2) => {
69098
69723
  const assetLines = SCANNABLE_ASSETS.map(
69099
- (name) => ` - ${name}\uFF1A${import_node_path77.default.join(config.dataDir, name)}`
69724
+ (name) => ` - ${name}\uFF1A${import_node_path79.default.join(config.dataDir, name)}`
69100
69725
  ).join("\n");
69101
69726
  const prompt = [
69102
69727
  `\u626B\u63CF persona\u300C${personaId2}\u300D\u7684\u90E8\u7F72\u73AF\u5883\uFF0CdeployId=${deployId}\u3002`,
@@ -69124,6 +69749,30 @@ async function startDaemon(config) {
69124
69749
  });
69125
69750
  return handle.sessionId;
69126
69751
  },
69752
+ startTrial: (deployId) => {
69753
+ void runTrialForReceipt(deployId).catch((err) => {
69754
+ logger.error("deploy trial crashed", { deployId, error: String(err) });
69755
+ deployReceipts.update(deployId, {
69756
+ status: "failed",
69757
+ trialStage: void 0,
69758
+ gaps: [{ errorText: redactSecretValues(`\u8BD5\u88C5\u8FD9\u6761\u6D41\u6C34\u7EBF\u81EA\u5DF1\u51FA\u9519\u4E86\uFF1A${String(err)}`) }]
69759
+ });
69760
+ });
69761
+ },
69762
+ registerOfficial: async (receipt) => {
69763
+ const cloudHost = await loadCloudHostConfig(config.dataDir);
69764
+ return await registerOfficialDeployment(
69765
+ { cloudHost, fetchImpl: fetch, now: () => Date.now() },
69766
+ receipt,
69767
+ // **只带部署者自供的那些**:使用者自带的由每个人各自绑,把部署者垫的试装临时值
69768
+ // 带上云等于所有人共用他的额度,跟单据上写的正好相反
69769
+ secretTableFor(receipt, deploySecrets.resolve(receipt.deployId), "deployer")
69770
+ );
69771
+ },
69772
+ unregisterDeployment: async (deployId) => {
69773
+ const cloudHost = await loadCloudHostConfig(config.dataDir);
69774
+ await gatewayAdmin({ cloudHost, fetchImpl: fetch }, "/admin/deployments:remove", { deployId });
69775
+ },
69127
69776
  genId: () => `dp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
69128
69777
  now: () => Date.now()
69129
69778
  });
@@ -69137,7 +69786,7 @@ async function startDaemon(config) {
69137
69786
  });
69138
69787
  shiftScheduler.start();
69139
69788
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
69140
- const larkBotStore = createLarkBotBindingStore(import_node_path77.default.join(config.dataDir, "personas"));
69789
+ const larkBotStore = createLarkBotBindingStore(import_node_path79.default.join(config.dataDir, "personas"));
69141
69790
  const larkBotCloud = createLarkBotCloudClient({
69142
69791
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
69143
69792
  apiKey: resolveClawdTicketsApiKey(),
@@ -69151,7 +69800,7 @@ async function startDaemon(config) {
69151
69800
  store: larkBotStore,
69152
69801
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
69153
69802
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
69154
- mediaRootFor: (chatId) => import_node_path77.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
69803
+ mediaRootFor: (chatId) => import_node_path79.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
69155
69804
  isShuttingDown: () => larkDraining,
69156
69805
  logger: {
69157
69806
  warn: (msg) => logger.warn(msg),
@@ -69456,8 +70105,8 @@ async function startDaemon(config) {
69456
70105
  const lines = [
69457
70106
  `Tunnel: ${r.url}`,
69458
70107
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
69459
- `Frpc config: ${import_node_path77.default.join(config.dataDir, "frpc.toml")}`,
69460
- `Frpc log: ${import_node_path77.default.join(logDir, "frpc.log")}`
70108
+ `Frpc config: ${import_node_path79.default.join(config.dataDir, "frpc.toml")}`,
70109
+ `Frpc log: ${import_node_path79.default.join(logDir, "frpc.log")}`
69461
70110
  ];
69462
70111
  const width2 = Math.max(...lines.map((l) => l.length));
69463
70112
  const bar = "\u2550".repeat(width2 + 4);
@@ -69470,7 +70119,7 @@ ${bar}
69470
70119
 
69471
70120
  `);
69472
70121
  try {
69473
- const connectPath = import_node_path77.default.join(config.dataDir, "connect.txt");
70122
+ const connectPath = import_node_path79.default.join(config.dataDir, "connect.txt");
69474
70123
  import_node_fs56.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
69475
70124
  } catch {
69476
70125
  }
@@ -69560,7 +70209,7 @@ ${bar}
69560
70209
  };
69561
70210
  }
69562
70211
  function migrateDropPersonsDir(dataDir) {
69563
- const dir = import_node_path77.default.join(dataDir, "persons");
70212
+ const dir = import_node_path79.default.join(dataDir, "persons");
69564
70213
  try {
69565
70214
  import_node_fs56.default.rmSync(dir, { recursive: true, force: true });
69566
70215
  } catch {