@clawos-dev/clawd 0.2.460 → 0.2.462

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(),
@@ -8878,6 +8909,14 @@ var init_methods = __esm({
8878
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",
8879
8910
  args: DeployFinishScanArgsSchema
8880
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
+ },
8881
8920
  "deploy:remove": {
8882
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",
8883
8922
  args: DeployIdArgsSchema
@@ -9866,8 +9905,8 @@ var require_req = __commonJS({
9866
9905
  if (req.originalUrl) {
9867
9906
  _req.url = req.originalUrl;
9868
9907
  } else {
9869
- const path96 = req.path;
9870
- _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;
9871
9910
  }
9872
9911
  if (req.query) {
9873
9912
  _req.query = req.query;
@@ -10032,14 +10071,14 @@ var require_redact = __commonJS({
10032
10071
  }
10033
10072
  return obj;
10034
10073
  }
10035
- function parsePath(path96) {
10074
+ function parsePath(path98) {
10036
10075
  const parts = [];
10037
10076
  let current = "";
10038
10077
  let inBrackets = false;
10039
10078
  let inQuotes = false;
10040
10079
  let quoteChar = "";
10041
- for (let i = 0; i < path96.length; i++) {
10042
- const char = path96[i];
10080
+ for (let i = 0; i < path98.length; i++) {
10081
+ const char = path98[i];
10043
10082
  if (!inBrackets && char === ".") {
10044
10083
  if (current) {
10045
10084
  parts.push(current);
@@ -10170,10 +10209,10 @@ var require_redact = __commonJS({
10170
10209
  return current;
10171
10210
  }
10172
10211
  function redactPaths(obj, paths, censor, remove = false) {
10173
- for (const path96 of paths) {
10174
- const parts = parsePath(path96);
10212
+ for (const path98 of paths) {
10213
+ const parts = parsePath(path98);
10175
10214
  if (parts.includes("*")) {
10176
- redactWildcardPath(obj, parts, censor, path96, remove);
10215
+ redactWildcardPath(obj, parts, censor, path98, remove);
10177
10216
  } else {
10178
10217
  if (remove) {
10179
10218
  removeKey(obj, parts);
@@ -10258,8 +10297,8 @@ var require_redact = __commonJS({
10258
10297
  }
10259
10298
  } else {
10260
10299
  if (afterWildcard.includes("*")) {
10261
- const wrappedCensor = typeof censor === "function" ? (value, path96) => {
10262
- const fullPath = [...pathArray.slice(0, pathLength), ...path96];
10300
+ const wrappedCensor = typeof censor === "function" ? (value, path98) => {
10301
+ const fullPath = [...pathArray.slice(0, pathLength), ...path98];
10263
10302
  return censor(value, fullPath);
10264
10303
  } : censor;
10265
10304
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10294,8 +10333,8 @@ var require_redact = __commonJS({
10294
10333
  return null;
10295
10334
  }
10296
10335
  const pathStructure = /* @__PURE__ */ new Map();
10297
- for (const path96 of pathsToClone) {
10298
- const parts = parsePath(path96);
10336
+ for (const path98 of pathsToClone) {
10337
+ const parts = parsePath(path98);
10299
10338
  let current = pathStructure;
10300
10339
  for (let i = 0; i < parts.length; i++) {
10301
10340
  const part = parts[i];
@@ -10347,24 +10386,24 @@ var require_redact = __commonJS({
10347
10386
  }
10348
10387
  return cloneSelectively(obj, pathStructure);
10349
10388
  }
10350
- function validatePath(path96) {
10351
- if (typeof path96 !== "string") {
10389
+ function validatePath(path98) {
10390
+ if (typeof path98 !== "string") {
10352
10391
  throw new Error("Paths must be (non-empty) strings");
10353
10392
  }
10354
- if (path96 === "") {
10393
+ if (path98 === "") {
10355
10394
  throw new Error("Invalid redaction path ()");
10356
10395
  }
10357
- if (path96.includes("..")) {
10358
- throw new Error(`Invalid redaction path (${path96})`);
10396
+ if (path98.includes("..")) {
10397
+ throw new Error(`Invalid redaction path (${path98})`);
10359
10398
  }
10360
- if (path96.includes(",")) {
10361
- throw new Error(`Invalid redaction path (${path96})`);
10399
+ if (path98.includes(",")) {
10400
+ throw new Error(`Invalid redaction path (${path98})`);
10362
10401
  }
10363
10402
  let bracketCount = 0;
10364
10403
  let inQuotes = false;
10365
10404
  let quoteChar = "";
10366
- for (let i = 0; i < path96.length; i++) {
10367
- const char = path96[i];
10405
+ for (let i = 0; i < path98.length; i++) {
10406
+ const char = path98[i];
10368
10407
  if ((char === '"' || char === "'") && bracketCount > 0) {
10369
10408
  if (!inQuotes) {
10370
10409
  inQuotes = true;
@@ -10378,20 +10417,20 @@ var require_redact = __commonJS({
10378
10417
  } else if (char === "]" && !inQuotes) {
10379
10418
  bracketCount--;
10380
10419
  if (bracketCount < 0) {
10381
- throw new Error(`Invalid redaction path (${path96})`);
10420
+ throw new Error(`Invalid redaction path (${path98})`);
10382
10421
  }
10383
10422
  }
10384
10423
  }
10385
10424
  if (bracketCount !== 0) {
10386
- throw new Error(`Invalid redaction path (${path96})`);
10425
+ throw new Error(`Invalid redaction path (${path98})`);
10387
10426
  }
10388
10427
  }
10389
10428
  function validatePaths(paths) {
10390
10429
  if (!Array.isArray(paths)) {
10391
10430
  throw new TypeError("paths must be an array");
10392
10431
  }
10393
- for (const path96 of paths) {
10394
- validatePath(path96);
10432
+ for (const path98 of paths) {
10433
+ validatePath(path98);
10395
10434
  }
10396
10435
  }
10397
10436
  function slowRedact(options = {}) {
@@ -10559,8 +10598,8 @@ var require_redaction = __commonJS({
10559
10598
  if (shape[k2] === null) {
10560
10599
  o[k2] = (value) => topCensor(value, [k2]);
10561
10600
  } else {
10562
- const wrappedCensor = typeof censor === "function" ? (value, path96) => {
10563
- return censor(value, [k2, ...path96]);
10601
+ const wrappedCensor = typeof censor === "function" ? (value, path98) => {
10602
+ return censor(value, [k2, ...path98]);
10564
10603
  } : censor;
10565
10604
  o[k2] = Redact({
10566
10605
  paths: shape[k2],
@@ -10778,10 +10817,10 @@ var require_atomic_sleep = __commonJS({
10778
10817
  var require_sonic_boom = __commonJS({
10779
10818
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10780
10819
  "use strict";
10781
- var fs85 = require("fs");
10820
+ var fs87 = require("fs");
10782
10821
  var EventEmitter3 = require("events");
10783
10822
  var inherits = require("util").inherits;
10784
- var path96 = require("path");
10823
+ var path98 = require("path");
10785
10824
  var sleep2 = require_atomic_sleep();
10786
10825
  var assert = require("assert");
10787
10826
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10835,20 +10874,20 @@ var require_sonic_boom = __commonJS({
10835
10874
  const mode = sonic.mode;
10836
10875
  if (sonic.sync) {
10837
10876
  try {
10838
- if (sonic.mkdir) fs85.mkdirSync(path96.dirname(file), { recursive: true });
10839
- 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);
10840
10879
  fileOpened(null, fd);
10841
10880
  } catch (err) {
10842
10881
  fileOpened(err);
10843
10882
  throw err;
10844
10883
  }
10845
10884
  } else if (sonic.mkdir) {
10846
- fs85.mkdir(path96.dirname(file), { recursive: true }, (err) => {
10885
+ fs87.mkdir(path98.dirname(file), { recursive: true }, (err) => {
10847
10886
  if (err) return fileOpened(err);
10848
- fs85.open(file, flags, mode, fileOpened);
10887
+ fs87.open(file, flags, mode, fileOpened);
10849
10888
  });
10850
10889
  } else {
10851
- fs85.open(file, flags, mode, fileOpened);
10890
+ fs87.open(file, flags, mode, fileOpened);
10852
10891
  }
10853
10892
  }
10854
10893
  function SonicBoom(opts) {
@@ -10889,8 +10928,8 @@ var require_sonic_boom = __commonJS({
10889
10928
  this.flush = flushBuffer;
10890
10929
  this.flushSync = flushBufferSync;
10891
10930
  this._actualWrite = actualWriteBuffer;
10892
- fsWriteSync = () => fs85.writeSync(this.fd, this._writingBuf);
10893
- 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);
10894
10933
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
10895
10934
  this._writingBuf = "";
10896
10935
  this.write = write;
@@ -10899,15 +10938,15 @@ var require_sonic_boom = __commonJS({
10899
10938
  this._actualWrite = actualWrite;
10900
10939
  fsWriteSync = () => {
10901
10940
  if (Buffer.isBuffer(this._writingBuf)) {
10902
- return fs85.writeSync(this.fd, this._writingBuf);
10941
+ return fs87.writeSync(this.fd, this._writingBuf);
10903
10942
  }
10904
- return fs85.writeSync(this.fd, this._writingBuf, "utf8");
10943
+ return fs87.writeSync(this.fd, this._writingBuf, "utf8");
10905
10944
  };
10906
10945
  fsWrite = () => {
10907
10946
  if (Buffer.isBuffer(this._writingBuf)) {
10908
- return fs85.write(this.fd, this._writingBuf, this.release);
10947
+ return fs87.write(this.fd, this._writingBuf, this.release);
10909
10948
  }
10910
- return fs85.write(this.fd, this._writingBuf, "utf8", this.release);
10949
+ return fs87.write(this.fd, this._writingBuf, "utf8", this.release);
10911
10950
  };
10912
10951
  } else {
10913
10952
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10964,7 +11003,7 @@ var require_sonic_boom = __commonJS({
10964
11003
  }
10965
11004
  }
10966
11005
  if (this._fsync) {
10967
- fs85.fsyncSync(this.fd);
11006
+ fs87.fsyncSync(this.fd);
10968
11007
  }
10969
11008
  const len = this._len;
10970
11009
  if (this._reopening) {
@@ -11078,7 +11117,7 @@ var require_sonic_boom = __commonJS({
11078
11117
  const onDrain = () => {
11079
11118
  if (!this._fsync) {
11080
11119
  try {
11081
- fs85.fsync(this.fd, (err) => {
11120
+ fs87.fsync(this.fd, (err) => {
11082
11121
  this._flushPending = false;
11083
11122
  cb(err);
11084
11123
  });
@@ -11180,7 +11219,7 @@ var require_sonic_boom = __commonJS({
11180
11219
  const fd = this.fd;
11181
11220
  this.once("ready", () => {
11182
11221
  if (fd !== this.fd) {
11183
- fs85.close(fd, (err) => {
11222
+ fs87.close(fd, (err) => {
11184
11223
  if (err) {
11185
11224
  return this.emit("error", err);
11186
11225
  }
@@ -11229,7 +11268,7 @@ var require_sonic_boom = __commonJS({
11229
11268
  buf = this._bufs[0];
11230
11269
  }
11231
11270
  try {
11232
- 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");
11233
11272
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
11234
11273
  buf = releasedBufObj.writingBuf;
11235
11274
  this._len = releasedBufObj.len;
@@ -11245,7 +11284,7 @@ var require_sonic_boom = __commonJS({
11245
11284
  }
11246
11285
  }
11247
11286
  try {
11248
- fs85.fsyncSync(this.fd);
11287
+ fs87.fsyncSync(this.fd);
11249
11288
  } catch {
11250
11289
  }
11251
11290
  }
@@ -11266,7 +11305,7 @@ var require_sonic_boom = __commonJS({
11266
11305
  buf = mergeBuf(this._bufs[0], this._lens[0]);
11267
11306
  }
11268
11307
  try {
11269
- const n = fs85.writeSync(this.fd, buf);
11308
+ const n = fs87.writeSync(this.fd, buf);
11270
11309
  buf = buf.subarray(n);
11271
11310
  this._len = Math.max(this._len - n, 0);
11272
11311
  if (buf.length <= 0) {
@@ -11294,13 +11333,13 @@ var require_sonic_boom = __commonJS({
11294
11333
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11295
11334
  if (this.sync) {
11296
11335
  try {
11297
- 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");
11298
11337
  release(null, written);
11299
11338
  } catch (err) {
11300
11339
  release(err);
11301
11340
  }
11302
11341
  } else {
11303
- fs85.write(this.fd, this._writingBuf, release);
11342
+ fs87.write(this.fd, this._writingBuf, release);
11304
11343
  }
11305
11344
  }
11306
11345
  function actualWriteBuffer() {
@@ -11309,7 +11348,7 @@ var require_sonic_boom = __commonJS({
11309
11348
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11310
11349
  if (this.sync) {
11311
11350
  try {
11312
- const written = fs85.writeSync(this.fd, this._writingBuf);
11351
+ const written = fs87.writeSync(this.fd, this._writingBuf);
11313
11352
  release(null, written);
11314
11353
  } catch (err) {
11315
11354
  release(err);
@@ -11318,7 +11357,7 @@ var require_sonic_boom = __commonJS({
11318
11357
  if (kCopyBuffer) {
11319
11358
  this._writingBuf = Buffer.from(this._writingBuf);
11320
11359
  }
11321
- fs85.write(this.fd, this._writingBuf, release);
11360
+ fs87.write(this.fd, this._writingBuf, release);
11322
11361
  }
11323
11362
  }
11324
11363
  function actualClose(sonic) {
@@ -11334,12 +11373,12 @@ var require_sonic_boom = __commonJS({
11334
11373
  sonic._lens = [];
11335
11374
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11336
11375
  try {
11337
- fs85.fsync(sonic.fd, closeWrapped);
11376
+ fs87.fsync(sonic.fd, closeWrapped);
11338
11377
  } catch {
11339
11378
  }
11340
11379
  function closeWrapped() {
11341
11380
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11342
- fs85.close(sonic.fd, done);
11381
+ fs87.close(sonic.fd, done);
11343
11382
  } else {
11344
11383
  done();
11345
11384
  }
@@ -13703,7 +13742,7 @@ var require_multistream = __commonJS({
13703
13742
  var require_pino = __commonJS({
13704
13743
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
13705
13744
  "use strict";
13706
- var os31 = require("os");
13745
+ var os32 = require("os");
13707
13746
  var stdSerializers = require_pino_std_serializers();
13708
13747
  var caller = require_caller();
13709
13748
  var redaction = require_redaction();
@@ -13750,7 +13789,7 @@ var require_pino = __commonJS({
13750
13789
  } = symbols;
13751
13790
  var { epochTime, nullTime } = time;
13752
13791
  var { pid } = process;
13753
- var hostname = os31.hostname();
13792
+ var hostname = os32.hostname();
13754
13793
  var defaultErrorSerializer = stdSerializers.err;
13755
13794
  var defaultOptions2 = {
13756
13795
  level: "info",
@@ -14474,11 +14513,11 @@ var init_lib = __esm({
14474
14513
  }
14475
14514
  }
14476
14515
  },
14477
- addToPath: function addToPath(path96, added, removed, oldPosInc, options) {
14478
- var last = path96.lastComponent;
14516
+ addToPath: function addToPath(path98, added, removed, oldPosInc, options) {
14517
+ var last = path98.lastComponent;
14479
14518
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14480
14519
  return {
14481
- oldPos: path96.oldPos + oldPosInc,
14520
+ oldPos: path98.oldPos + oldPosInc,
14482
14521
  lastComponent: {
14483
14522
  count: last.count + 1,
14484
14523
  added,
@@ -14488,7 +14527,7 @@ var init_lib = __esm({
14488
14527
  };
14489
14528
  } else {
14490
14529
  return {
14491
- oldPos: path96.oldPos + oldPosInc,
14530
+ oldPos: path98.oldPos + oldPosInc,
14492
14531
  lastComponent: {
14493
14532
  count: 1,
14494
14533
  added,
@@ -15070,10 +15109,10 @@ function attachmentToHistoryMessage(o, ts) {
15070
15109
  const memories = raw.map((m2) => {
15071
15110
  if (!m2 || typeof m2 !== "object") return null;
15072
15111
  const rec4 = m2;
15073
- const path96 = typeof rec4.path === "string" ? rec4.path : null;
15112
+ const path98 = typeof rec4.path === "string" ? rec4.path : null;
15074
15113
  const content = typeof rec4.content === "string" ? rec4.content : null;
15075
- if (!path96 || content == null) return null;
15076
- const entry = { path: path96, content };
15114
+ if (!path98 || content == null) return null;
15115
+ const entry = { path: path98, content };
15077
15116
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
15078
15117
  return entry;
15079
15118
  }).filter((m2) => m2 !== null);
@@ -15939,10 +15978,10 @@ function parseAttachment(obj) {
15939
15978
  const memories = raw.map((m2) => {
15940
15979
  if (!m2 || typeof m2 !== "object") return null;
15941
15980
  const rec4 = m2;
15942
- const path96 = typeof rec4.path === "string" ? rec4.path : null;
15981
+ const path98 = typeof rec4.path === "string" ? rec4.path : null;
15943
15982
  const content = typeof rec4.content === "string" ? rec4.content : null;
15944
- if (!path96 || content == null) return null;
15945
- const out = { path: path96, content };
15983
+ if (!path98 || content == null) return null;
15984
+ const out = { path: path98, content };
15946
15985
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
15947
15986
  return out;
15948
15987
  }).filter((m2) => m2 !== null);
@@ -36916,8 +36955,8 @@ var require_utils = __commonJS({
36916
36955
  var result = transform[inputType][outputType](input);
36917
36956
  return result;
36918
36957
  };
36919
- exports2.resolve = function(path96) {
36920
- var parts = path96.split("/");
36958
+ exports2.resolve = function(path98) {
36959
+ var parts = path98.split("/");
36921
36960
  var result = [];
36922
36961
  for (var index = 0; index < parts.length; index++) {
36923
36962
  var part = parts[index];
@@ -42770,18 +42809,18 @@ var require_object = __commonJS({
42770
42809
  var object = new ZipObject(name, zipObjectContent, o);
42771
42810
  this.files[name] = object;
42772
42811
  };
42773
- var parentFolder = function(path96) {
42774
- if (path96.slice(-1) === "/") {
42775
- 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);
42776
42815
  }
42777
- var lastSlash = path96.lastIndexOf("/");
42778
- return lastSlash > 0 ? path96.substring(0, lastSlash) : "";
42816
+ var lastSlash = path98.lastIndexOf("/");
42817
+ return lastSlash > 0 ? path98.substring(0, lastSlash) : "";
42779
42818
  };
42780
- var forceTrailingSlash = function(path96) {
42781
- if (path96.slice(-1) !== "/") {
42782
- path96 += "/";
42819
+ var forceTrailingSlash = function(path98) {
42820
+ if (path98.slice(-1) !== "/") {
42821
+ path98 += "/";
42783
42822
  }
42784
- return path96;
42823
+ return path98;
42785
42824
  };
42786
42825
  var folderAdd = function(name, createFolders) {
42787
42826
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43783,7 +43822,7 @@ var require_lib3 = __commonJS({
43783
43822
  // src/run-case/recorder.ts
43784
43823
  function startRunCaseRecorder(opts) {
43785
43824
  const now = opts.now ?? Date.now;
43786
- const dir = import_node_path78.default.dirname(opts.recordPath);
43825
+ const dir = import_node_path80.default.dirname(opts.recordPath);
43787
43826
  let stream = null;
43788
43827
  let closing = false;
43789
43828
  let closedSettled = false;
@@ -43823,12 +43862,12 @@ function startRunCaseRecorder(opts) {
43823
43862
  };
43824
43863
  return { tap, close, closed };
43825
43864
  }
43826
- var import_node_fs57, import_node_path78;
43865
+ var import_node_fs57, import_node_path80;
43827
43866
  var init_recorder = __esm({
43828
43867
  "src/run-case/recorder.ts"() {
43829
43868
  "use strict";
43830
43869
  import_node_fs57 = __toESM(require("fs"), 1);
43831
- import_node_path78 = __toESM(require("path"), 1);
43870
+ import_node_path80 = __toESM(require("path"), 1);
43832
43871
  }
43833
43872
  });
43834
43873
 
@@ -43871,7 +43910,7 @@ var init_wire = __esm({
43871
43910
  // src/run-case/controller.ts
43872
43911
  async function runController(opts) {
43873
43912
  const now = opts.now ?? Date.now;
43874
- 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-"));
43875
43914
  const ownsCwd = opts.cwd === void 0;
43876
43915
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
43877
43916
  const spawnCtx = { cwd };
@@ -44038,13 +44077,13 @@ async function runController(opts) {
44038
44077
  }
44039
44078
  return exitCode ?? 0;
44040
44079
  }
44041
- var import_node_fs58, import_node_os27, import_node_path79;
44080
+ var import_node_fs58, import_node_os28, import_node_path81;
44042
44081
  var init_controller = __esm({
44043
44082
  "src/run-case/controller.ts"() {
44044
44083
  "use strict";
44045
44084
  import_node_fs58 = require("fs");
44046
- import_node_os27 = __toESM(require("os"), 1);
44047
- import_node_path79 = __toESM(require("path"), 1);
44085
+ import_node_os28 = __toESM(require("os"), 1);
44086
+ import_node_path81 = __toESM(require("path"), 1);
44048
44087
  init_claude();
44049
44088
  init_stdout_splitter();
44050
44089
  init_permission_stdio();
@@ -44319,9 +44358,9 @@ Env (advanced):
44319
44358
  `;
44320
44359
 
44321
44360
  // src/index.ts
44322
- var import_node_path77 = __toESM(require("path"), 1);
44361
+ var import_node_path79 = __toESM(require("path"), 1);
44323
44362
  var import_node_fs56 = __toESM(require("fs"), 1);
44324
- var import_node_os26 = __toESM(require("os"), 1);
44363
+ var import_node_os27 = __toESM(require("os"), 1);
44325
44364
  var import_node_crypto22 = require("crypto");
44326
44365
  var import_node_url5 = require("url");
44327
44366
 
@@ -51577,8 +51616,8 @@ function turnStartInput(text) {
51577
51616
  const items = [];
51578
51617
  let leftover = text;
51579
51618
  for (const m2 of text.matchAll(SKILL_RE)) {
51580
- const [marker, name, path96] = m2;
51581
- items.push({ type: "skill", name, path: path96 });
51619
+ const [marker, name, path98] = m2;
51620
+ items.push({ type: "skill", name, path: path98 });
51582
51621
  leftover = leftover.replace(marker, "");
51583
51622
  }
51584
51623
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -54641,6 +54680,38 @@ function redactEvidence(evidence) {
54641
54680
  };
54642
54681
  }
54643
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
+
54644
54715
  // src/handlers/deploy.ts
54645
54716
  function ensureOwner(ctx) {
54646
54717
  if (!ctx || ctx.principal.kind !== "owner") {
@@ -54670,6 +54741,11 @@ function secretStatusOf(deps, receipt) {
54670
54741
  total: s.env.length
54671
54742
  }));
54672
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
+ }
54673
54749
  function buildDeployHandlers(deps) {
54674
54750
  const view = (receipt) => ({
54675
54751
  response: { type: "deploy:receipt", receipt, secretStatus: secretStatusOf(deps, receipt) }
@@ -54705,6 +54781,12 @@ function buildDeployHandlers(deps) {
54705
54781
  if (receipt.status === "scanning") {
54706
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");
54707
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
+ }
54708
54790
  deps.receipts.update(args.deployId, {
54709
54791
  status: "scanning",
54710
54792
  manifest: void 0,
@@ -54712,7 +54794,12 @@ function buildDeployHandlers(deps) {
54712
54794
  notes: [],
54713
54795
  smokeTask: void 0,
54714
54796
  error: void 0,
54715
- scanSessionId: void 0
54797
+ scanSessionId: void 0,
54798
+ // 重扫 = 一次新的判断,试装轮次跟着清零(不是同一条路上的第 N 次撞墙)
54799
+ trialRound: 0,
54800
+ gaps: [],
54801
+ trialPassedAt: void 0,
54802
+ trialImage: void 0
54716
54803
  });
54717
54804
  const scanSessionId = deps.startScan(args.deployId, receipt.personaId);
54718
54805
  if (scanSessionId) deps.receipts.update(args.deployId, { scanSessionId });
@@ -54742,8 +54829,9 @@ function buildDeployHandlers(deps) {
54742
54829
  }
54743
54830
  }
54744
54831
  }
54745
- const next = deps.receipts.update(args.deployId, args.patch);
54746
- 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));
54747
54835
  };
54748
54836
  const putSecret = async (frame, _client, ctx) => {
54749
54837
  ensureOwner(ctx);
@@ -54763,7 +54851,7 @@ function buildDeployHandlers(deps) {
54763
54851
  }
54764
54852
  }
54765
54853
  deps.secrets.put({ deployId: args.deployId, name: args.name, values: args.values });
54766
- return view(receipt);
54854
+ return view(applyReadiness(deps, receipt));
54767
54855
  };
54768
54856
  const reportFinding = async (frame, _client, ctx) => {
54769
54857
  ensureOwner(ctx);
@@ -54806,12 +54894,77 @@ function buildDeployHandlers(deps) {
54806
54894
  notes: args.notes?.map(redactSecretValues),
54807
54895
  error: void 0
54808
54896
  });
54809
- 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);
54810
54962
  };
54811
54963
  const remove = async (frame, _client, ctx) => {
54812
54964
  ensureOwner(ctx);
54813
54965
  const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:remove");
54814
- mustGet(deps, args.deployId);
54966
+ const receipt = mustGet(deps, args.deployId);
54967
+ if (receipt.placement) await deps.unregisterDeployment(receipt.deployId);
54815
54968
  deps.receipts.remove(args.deployId);
54816
54969
  deps.secrets.removeDeploy(args.deployId);
54817
54970
  return { response: { type: "deploy:remove", deployId: args.deployId } };
@@ -54825,6 +54978,8 @@ function buildDeployHandlers(deps) {
54825
54978
  "deploy:putSecret": putSecret,
54826
54979
  "deploy:reportFinding": reportFinding,
54827
54980
  "deploy:finishScan": finishScan,
54981
+ "deploy:trial": trial,
54982
+ "deploy:deploy": deploy,
54828
54983
  "deploy:remove": remove
54829
54984
  };
54830
54985
  }
@@ -54881,6 +55036,7 @@ function createReceiptStore(deps) {
54881
55036
  notes: [],
54882
55037
  fulfillment: {},
54883
55038
  gaps: [],
55039
+ trialRound: 0,
54884
55040
  createdAt: ts,
54885
55041
  updatedAt: ts
54886
55042
  };
@@ -55009,6 +55165,384 @@ function createSecretStore(deps) {
55009
55165
  };
55010
55166
  }
55011
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
+
55012
55546
  // src/deploy/scan-task.ts
55013
55547
  var BUTLER_PERSONA_ID = "persona-clawd-butler";
55014
55548
  var SCANNABLE_ASSETS = ["deploy-kit"];
@@ -55026,6 +55560,17 @@ function reconcileInterruptedScans(deps) {
55026
55560
  }
55027
55561
  return stale.map((r) => r.deployId);
55028
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
+ }
55029
55574
 
55030
55575
  // src/handlers/lark-bot.ts
55031
55576
  init_protocol();
@@ -55415,9 +55960,9 @@ async function refreshTunnelUrlOnStartup(deps) {
55415
55960
 
55416
55961
  // src/lark-bot-connector/binding-store.ts
55417
55962
  var import_node_fs28 = __toESM(require("fs"), 1);
55418
- var import_node_path32 = __toESM(require("path"), 1);
55963
+ var import_node_path34 = __toESM(require("path"), 1);
55419
55964
  function createLarkBotBindingStore(personaRoot) {
55420
- 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");
55421
55966
  const read = (personaId2) => {
55422
55967
  const file = filePath(personaId2);
55423
55968
  if (!import_node_fs28.default.existsSync(file)) return null;
@@ -55431,7 +55976,7 @@ function createLarkBotBindingStore(personaRoot) {
55431
55976
  };
55432
55977
  const write = (personaId2, meta) => {
55433
55978
  const file = filePath(personaId2);
55434
- 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 });
55435
55980
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
55436
55981
  import_node_fs28.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
55437
55982
  import_node_fs28.default.renameSync(tmp, file);
@@ -55599,7 +56144,7 @@ function createLarkBotCloudClient(opts) {
55599
56144
 
55600
56145
  // src/lark-bot-connector/chat-router.ts
55601
56146
  var import_node_fs29 = __toESM(require("fs"), 1);
55602
- var import_node_path33 = __toESM(require("path"), 1);
56147
+ var import_node_path35 = __toESM(require("path"), 1);
55603
56148
  init_protocol();
55604
56149
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
55605
56150
  var LOCAL_TURN_RETRIES = 2;
@@ -55666,7 +56211,7 @@ function createLarkChatRouter(deps) {
55666
56211
  }
55667
56212
  const dir = deps.mediaRootFor(env.chatId);
55668
56213
  import_node_fs29.default.mkdirSync(dir, { recursive: true });
55669
- 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}`);
55670
56215
  import_node_fs29.default.writeFileSync(p2, r.data);
55671
56216
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
55672
56217
  } catch (err) {
@@ -55689,7 +56234,7 @@ function createLarkChatRouter(deps) {
55689
56234
  }
55690
56235
  const dir = deps.mediaRootFor(env.chatId);
55691
56236
  import_node_fs29.default.mkdirSync(dir, { recursive: true });
55692
- 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)}`);
55693
56238
  import_node_fs29.default.writeFileSync(p2, r.data);
55694
56239
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
55695
56240
  } catch (err) {
@@ -56779,7 +57324,7 @@ var CodexHistoryReader = class {
56779
57324
  };
56780
57325
 
56781
57326
  // src/tools/codex-skills.ts
56782
- var import_node_path34 = __toESM(require("path"), 1);
57327
+ var import_node_path36 = __toESM(require("path"), 1);
56783
57328
  function str3(v2) {
56784
57329
  return typeof v2 === "string" ? v2 : void 0;
56785
57330
  }
@@ -56794,13 +57339,13 @@ function mapSkillsListResponse(res) {
56794
57339
  const r = s ?? {};
56795
57340
  const name = str3(r.name);
56796
57341
  if (!name) continue;
56797
- const path96 = str3(r.path);
57342
+ const path98 = str3(r.path);
56798
57343
  const description = str3(r.description);
56799
57344
  const isPlugin = name.includes(":");
56800
57345
  out.push({
56801
57346
  name,
56802
57347
  source: isPlugin ? "plugin" : "project",
56803
- ...path96 ? { path: path96 } : {},
57348
+ ...path98 ? { path: path98 } : {},
56804
57349
  ...description ? { description } : {},
56805
57350
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
56806
57351
  });
@@ -56816,14 +57361,14 @@ async function listCodexSkills(cwd, deps = {}) {
56816
57361
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
56817
57362
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
56818
57363
  beforeRequest: (client) => {
56819
- 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);
56820
57365
  }
56821
57366
  });
56822
57367
  return mapSkillsListResponse(res);
56823
57368
  }
56824
57369
 
56825
57370
  // src/tools/codex-turn-context.ts
56826
- var import_promises6 = __toESM(require("fs/promises"), 1);
57371
+ var import_promises8 = __toESM(require("fs/promises"), 1);
56827
57372
  function parseTurnContextFromRollout(raw) {
56828
57373
  const lines = raw.split("\n");
56829
57374
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -56858,7 +57403,7 @@ async function readCodexTurnContext(args, deps = {}) {
56858
57403
  );
56859
57404
  const rolloutPath = str4(rec3(res?.thread)?.path);
56860
57405
  if (!rolloutPath) return null;
56861
- return parseTurnContextFromRollout(await import_promises6.default.readFile(rolloutPath, "utf8"));
57406
+ return parseTurnContextFromRollout(await import_promises8.default.readFile(rolloutPath, "utf8"));
56862
57407
  }
56863
57408
  function createCodexResolvedMetaHydrator(deps) {
56864
57409
  const fetchedThreadIds = /* @__PURE__ */ new Set();
@@ -56902,15 +57447,15 @@ function str4(v2) {
56902
57447
 
56903
57448
  // src/workspace/browser.ts
56904
57449
  var import_node_fs30 = __toESM(require("fs"), 1);
56905
- var import_node_os8 = __toESM(require("os"), 1);
56906
- 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);
56907
57452
  init_protocol();
56908
57453
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
56909
57454
  function resolveInsideCwd(cwd, subpath) {
56910
- const absCwd = import_node_path35.default.resolve(cwd);
56911
- const joined = import_node_path35.default.resolve(absCwd, subpath ?? ".");
56912
- const rel = import_node_path35.default.relative(absCwd, joined);
56913
- 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)) {
56914
57459
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
56915
57460
  }
56916
57461
  return joined;
@@ -56928,7 +57473,7 @@ function ensureCwd(cwd) {
56928
57473
  }
56929
57474
  var WorkspaceBrowser = class {
56930
57475
  list(args) {
56931
- 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();
56932
57477
  ensureCwd(cwd);
56933
57478
  const full = resolveInsideCwd(cwd, args.path);
56934
57479
  const dirents = import_node_fs30.default.readdirSync(full, { withFileTypes: true });
@@ -56941,7 +57486,7 @@ var WorkspaceBrowser = class {
56941
57486
  mtime: ""
56942
57487
  };
56943
57488
  try {
56944
- 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));
56945
57490
  entry.mtime = new Date(st.mtimeMs).toISOString();
56946
57491
  if (d.isFile()) entry.size = st.size;
56947
57492
  } catch {
@@ -56987,8 +57532,8 @@ var WorkspaceBrowser = class {
56987
57532
 
56988
57533
  // src/skills/agents-scanner.ts
56989
57534
  var import_node_fs31 = __toESM(require("fs"), 1);
56990
- var import_node_os9 = __toESM(require("os"), 1);
56991
- 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);
56992
57537
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
56993
57538
  function isDirLikeSync2(p2) {
56994
57539
  try {
@@ -57026,10 +57571,10 @@ function scanAgentsDir(dir, source, seen, out) {
57026
57571
  }
57027
57572
  for (const ent of entries) {
57028
57573
  if (!ent.name.endsWith(".md")) continue;
57029
- 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)))) {
57030
57575
  continue;
57031
57576
  }
57032
- const filePath = import_node_path36.default.join(dir, ent.name);
57577
+ const filePath = import_node_path38.default.join(dir, ent.name);
57033
57578
  const baseName = ent.name.replace(/\.md$/, "");
57034
57579
  if (seen.has(baseName)) continue;
57035
57580
  seen.add(baseName);
@@ -57052,7 +57597,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
57052
57597
  return;
57053
57598
  }
57054
57599
  for (const ent of entries) {
57055
- const childPath = import_node_path36.default.join(dir, ent.name);
57600
+ const childPath = import_node_path38.default.join(dir, ent.name);
57056
57601
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
57057
57602
  walk2(childPath, [...namespaces, ent.name]);
57058
57603
  continue;
@@ -57077,9 +57622,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
57077
57622
  walk2(root, []);
57078
57623
  }
57079
57624
  function readInstalledPlugins2(home) {
57080
- const pluginsDir = import_node_path36.default.join(home, ".claude", "plugins");
57081
- const v2 = import_node_path36.default.join(pluginsDir, "installed_plugins_v2.json");
57082
- 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");
57083
57628
  let raw = null;
57084
57629
  for (const candidate of [v2, v1]) {
57085
57630
  try {
@@ -57108,19 +57653,19 @@ function readInstalledPlugins2(home) {
57108
57653
  return out;
57109
57654
  }
57110
57655
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
57111
- let cur = import_node_path36.default.resolve(startCwd);
57112
- 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;
57113
57658
  while (true) {
57114
- 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);
57115
57660
  let hasGit = false;
57116
57661
  try {
57117
- 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"));
57118
57663
  } catch {
57119
57664
  }
57120
57665
  if (hasGit) return;
57121
57666
  if (cur === home) return;
57122
57667
  if (cur === fsRoot) return;
57123
- const parent = import_node_path36.default.dirname(cur);
57668
+ const parent = import_node_path38.default.dirname(cur);
57124
57669
  if (parent === cur) return;
57125
57670
  cur = parent;
57126
57671
  }
@@ -57130,7 +57675,7 @@ var AgentsScanner = class {
57130
57675
  extraPluginRoots;
57131
57676
  policyDir;
57132
57677
  constructor(opts = {}) {
57133
- 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();
57134
57679
  this.extraPluginRoots = opts.extraPluginRoots ?? [];
57135
57680
  if (opts.policyDir !== void 0) {
57136
57681
  this.policyDir = opts.policyDir;
@@ -57155,7 +57700,7 @@ var AgentsScanner = class {
57155
57700
  }
57156
57701
  const fsBlock = [];
57157
57702
  scanAgentsDir(
57158
- import_node_path36.default.join(this.home, ".claude", "agents"),
57703
+ import_node_path38.default.join(this.home, ".claude", "agents"),
57159
57704
  "global",
57160
57705
  seen,
57161
57706
  fsBlock
@@ -57169,7 +57714,7 @@ var AgentsScanner = class {
57169
57714
  ...this.extraPluginRoots
57170
57715
  ];
57171
57716
  for (const { name, root } of plugins) {
57172
- const agentsRoot = import_node_path36.default.join(root, "agents");
57717
+ const agentsRoot = import_node_path38.default.join(root, "agents");
57173
57718
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
57174
57719
  }
57175
57720
  return [...builtinBlock, ...fsBlock];
@@ -57178,27 +57723,27 @@ var AgentsScanner = class {
57178
57723
 
57179
57724
  // src/observer/session-observer.ts
57180
57725
  var import_node_fs33 = __toESM(require("fs"), 1);
57181
- var import_node_os11 = __toESM(require("os"), 1);
57182
- 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);
57183
57728
  init_claude_history();
57184
57729
 
57185
57730
  // src/observer/subagent-meta-observer.ts
57186
57731
  var import_node_fs32 = __toESM(require("fs"), 1);
57187
- var import_node_os10 = __toESM(require("os"), 1);
57188
- 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);
57189
57734
  init_claude_history();
57190
57735
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
57191
57736
  var SubagentMetaObserver = class {
57192
57737
  constructor(opts) {
57193
57738
  this.opts = opts;
57194
- this.home = opts.home ?? import_node_os10.default.homedir();
57739
+ this.home = opts.home ?? import_node_os11.default.homedir();
57195
57740
  }
57196
57741
  opts;
57197
57742
  home;
57198
57743
  watches = /* @__PURE__ */ new Map();
57199
57744
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
57200
57745
  resolveSubagentDir(cwd, toolSessionId) {
57201
- return import_node_path37.default.join(
57746
+ return import_node_path39.default.join(
57202
57747
  this.home,
57203
57748
  ".claude",
57204
57749
  "projects",
@@ -57254,7 +57799,7 @@ var SubagentMetaObserver = class {
57254
57799
  if (!m2) return;
57255
57800
  const agentId = m2[1];
57256
57801
  if (w2.emitted.has(agentId)) return;
57257
- const file = import_node_path37.default.join(w2.dirPath, name);
57802
+ const file = import_node_path39.default.join(w2.dirPath, name);
57258
57803
  let raw;
57259
57804
  try {
57260
57805
  raw = import_node_fs32.default.readFileSync(file, "utf8");
@@ -57302,7 +57847,7 @@ var SubagentMetaObserver = class {
57302
57847
  var SessionObserver = class {
57303
57848
  constructor(opts) {
57304
57849
  this.opts = opts;
57305
- this.home = opts.home ?? import_node_os11.default.homedir();
57850
+ this.home = opts.home ?? import_node_os12.default.homedir();
57306
57851
  this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
57307
57852
  }
57308
57853
  opts;
@@ -57314,7 +57859,7 @@ var SessionObserver = class {
57314
57859
  metaObserver;
57315
57860
  resolveJsonlPath(cwd, toolSessionId, override) {
57316
57861
  if (override) return override;
57317
- 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`);
57318
57863
  }
57319
57864
  start(args) {
57320
57865
  this.stop(args.sessionId);
@@ -57340,10 +57885,10 @@ var SessionObserver = class {
57340
57885
  lastDeriveMs: 0
57341
57886
  };
57342
57887
  try {
57343
- 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 });
57344
57889
  } catch {
57345
57890
  }
57346
- 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) => {
57347
57892
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
57348
57893
  this.poll(w2);
57349
57894
  });
@@ -57440,7 +57985,7 @@ var SessionObserver = class {
57440
57985
  const now = Date.now();
57441
57986
  if (now - w2.lastRelocateScanMs < 1e3) return;
57442
57987
  w2.lastRelocateScanMs = now;
57443
- const projectsRoot = import_node_path38.default.join(this.home, ".claude", "projects");
57988
+ const projectsRoot = import_node_path40.default.join(this.home, ".claude", "projects");
57444
57989
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
57445
57990
  if (!found || found === w2.filePath) return;
57446
57991
  try {
@@ -57449,7 +57994,7 @@ var SessionObserver = class {
57449
57994
  }
57450
57995
  w2.filePath = found;
57451
57996
  try {
57452
- 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) => {
57453
57998
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
57454
57999
  this.poll(w2);
57455
58000
  });
@@ -57569,10 +58114,10 @@ function listRegistered() {
57569
58114
  }
57570
58115
 
57571
58116
  // src/tools/title-generator.ts
57572
- var import_node_child_process8 = require("child_process");
58117
+ var import_node_child_process9 = require("child_process");
57573
58118
  var import_node_fs34 = __toESM(require("fs"), 1);
57574
- var import_node_os12 = __toESM(require("os"), 1);
57575
- 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);
57576
58121
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
57577
58122
  var TITLE_MODEL_BY_TOOL = {
57578
58123
  claude: "haiku",
@@ -57643,7 +58188,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57643
58188
  if (!text) return null;
57644
58189
  let workDir;
57645
58190
  try {
57646
- 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));
57647
58192
  } catch {
57648
58193
  return null;
57649
58194
  }
@@ -57653,8 +58198,8 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57653
58198
  } catch {
57654
58199
  }
57655
58200
  };
57656
- const outFile = import_node_path39.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
57657
- 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");
57658
58203
  if (tool === "codex") {
57659
58204
  try {
57660
58205
  import_node_fs34.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
@@ -57665,7 +58210,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
57665
58210
  }
57666
58211
  const cmd = tool === "claude" ? process.env.CLAUDE_BIN ?? "claude" : process.env.CODEX_BIN ?? "codex";
57667
58212
  const args = tool === "claude" ? buildClaudeTitleArgs(buildClaudeTitlePrompt(text)) : buildCodexTitleArgs(buildTitlePrompt(text), outFile, schemaFile);
57668
- 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"] }));
57669
58214
  const timeoutMs = deps.timeoutMs ?? DEFAULT_TITLE_GEN_TIMEOUT_MS;
57670
58215
  return await new Promise((resolve9) => {
57671
58216
  let proc;
@@ -58408,8 +58953,8 @@ async function authenticate(token, deps) {
58408
58953
  }
58409
58954
 
58410
58955
  // src/legacy-cleanup.ts
58411
- var fs45 = __toESM(require("fs/promises"), 1);
58412
- var path47 = __toESM(require("path"), 1);
58956
+ var fs47 = __toESM(require("fs/promises"), 1);
58957
+ var path49 = __toESM(require("path"), 1);
58413
58958
  var LEGACY_FILES = [
58414
58959
  "personal-capability.json",
58415
58960
  "received-capabilities.json",
@@ -58418,9 +58963,9 @@ var LEGACY_FILES = [
58418
58963
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
58419
58964
  const removed = [];
58420
58965
  for (const name of LEGACY_FILES) {
58421
- const p2 = path47.join(dataDir, name);
58966
+ const p2 = path49.join(dataDir, name);
58422
58967
  try {
58423
- await fs45.unlink(p2);
58968
+ await fs47.unlink(p2);
58424
58969
  removed.push(name);
58425
58970
  logger.debug("legacy capability file removed", { file: name });
58426
58971
  } catch (err) {
@@ -58432,13 +58977,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
58432
58977
  }
58433
58978
 
58434
58979
  // src/inbox/inbox-store.ts
58435
- var fs46 = __toESM(require("fs"), 1);
58436
- var path48 = __toESM(require("path"), 1);
58980
+ var fs48 = __toESM(require("fs"), 1);
58981
+ var path50 = __toESM(require("path"), 1);
58437
58982
  var INBOX_SUBDIR = "inbox";
58438
58983
  var InboxStore = class {
58439
58984
  constructor(dataDir) {
58440
58985
  this.dataDir = dataDir;
58441
- fs46.mkdirSync(this.dirPath(), { recursive: true });
58986
+ fs48.mkdirSync(this.dirPath(), { recursive: true });
58442
58987
  }
58443
58988
  dataDir;
58444
58989
  /**
@@ -58450,7 +58995,7 @@ var InboxStore = class {
58450
58995
  const file = this.filePath(peerDeviceId);
58451
58996
  let raw;
58452
58997
  try {
58453
- raw = fs46.readFileSync(file, "utf8");
58998
+ raw = fs48.readFileSync(file, "utf8");
58454
58999
  } catch (err) {
58455
59000
  if (err?.code === "ENOENT") return [];
58456
59001
  return [];
@@ -58466,7 +59011,7 @@ var InboxStore = class {
58466
59011
  const dir = this.dirPath();
58467
59012
  let entries;
58468
59013
  try {
58469
- entries = fs46.readdirSync(dir);
59014
+ entries = fs48.readdirSync(dir);
58470
59015
  } catch (err) {
58471
59016
  if (err?.code === "ENOENT") return [];
58472
59017
  return [];
@@ -58482,9 +59027,9 @@ var InboxStore = class {
58482
59027
  if (existing.some((m2) => m2.id === message.id)) return;
58483
59028
  const file = this.filePath(message.peerDeviceId);
58484
59029
  const line = JSON.stringify(message) + "\n";
58485
- fs46.appendFileSync(file, line, { mode: 384 });
59030
+ fs48.appendFileSync(file, line, { mode: 384 });
58486
59031
  try {
58487
- fs46.chmodSync(file, 384);
59032
+ fs48.chmodSync(file, 384);
58488
59033
  } catch {
58489
59034
  }
58490
59035
  }
@@ -58514,7 +59059,7 @@ var InboxStore = class {
58514
59059
  removeByPeerDeviceId(peerDeviceId) {
58515
59060
  const file = this.filePath(peerDeviceId);
58516
59061
  try {
58517
- fs46.unlinkSync(file);
59062
+ fs48.unlinkSync(file);
58518
59063
  } catch (err) {
58519
59064
  if (err?.code === "ENOENT") return;
58520
59065
  }
@@ -58523,18 +59068,18 @@ var InboxStore = class {
58523
59068
  const file = this.filePath(peerDeviceId);
58524
59069
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
58525
59070
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
58526
- fs46.writeFileSync(tmp, content, { mode: 384 });
58527
- fs46.renameSync(tmp, file);
59071
+ fs48.writeFileSync(tmp, content, { mode: 384 });
59072
+ fs48.renameSync(tmp, file);
58528
59073
  try {
58529
- fs46.chmodSync(file, 384);
59074
+ fs48.chmodSync(file, 384);
58530
59075
  } catch {
58531
59076
  }
58532
59077
  }
58533
59078
  dirPath() {
58534
- return path48.join(this.dataDir, INBOX_SUBDIR);
59079
+ return path50.join(this.dataDir, INBOX_SUBDIR);
58535
59080
  }
58536
59081
  filePath(peerDeviceId) {
58537
- return path48.join(this.dirPath(), `${peerDeviceId}.jsonl`);
59082
+ return path50.join(this.dirPath(), `${peerDeviceId}.jsonl`);
58538
59083
  }
58539
59084
  };
58540
59085
  function parseAllLines(raw) {
@@ -58622,8 +59167,8 @@ var InboxManager = class {
58622
59167
  };
58623
59168
 
58624
59169
  // src/state/contact-store.ts
58625
- var fs47 = __toESM(require("fs"), 1);
58626
- var path49 = __toESM(require("path"), 1);
59170
+ var fs49 = __toESM(require("fs"), 1);
59171
+ var path51 = __toESM(require("path"), 1);
58627
59172
  var FILE_NAME = "contacts.json";
58628
59173
  var ContactStore = class {
58629
59174
  constructor(dataDir) {
@@ -58633,10 +59178,10 @@ var ContactStore = class {
58633
59178
  contacts = /* @__PURE__ */ new Map();
58634
59179
  load() {
58635
59180
  this.contacts.clear();
58636
- const file = path49.join(this.dataDir, FILE_NAME);
59181
+ const file = path51.join(this.dataDir, FILE_NAME);
58637
59182
  let raw;
58638
59183
  try {
58639
- raw = fs47.readFileSync(file, "utf8");
59184
+ raw = fs49.readFileSync(file, "utf8");
58640
59185
  } catch (err) {
58641
59186
  if (err?.code !== "ENOENT") this.renameBak(file);
58642
59187
  return;
@@ -58717,20 +59262,20 @@ var ContactStore = class {
58717
59262
  return true;
58718
59263
  }
58719
59264
  flush() {
58720
- const file = path49.join(this.dataDir, FILE_NAME);
59265
+ const file = path51.join(this.dataDir, FILE_NAME);
58721
59266
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
58722
59267
  const content = JSON.stringify(
58723
59268
  { contacts: Array.from(this.contacts.values()) },
58724
59269
  null,
58725
59270
  2
58726
59271
  );
58727
- fs47.mkdirSync(this.dataDir, { recursive: true });
58728
- fs47.writeFileSync(tmp, content, { mode: 384 });
58729
- fs47.renameSync(tmp, file);
59272
+ fs49.mkdirSync(this.dataDir, { recursive: true });
59273
+ fs49.writeFileSync(tmp, content, { mode: 384 });
59274
+ fs49.renameSync(tmp, file);
58730
59275
  }
58731
59276
  renameBak(file) {
58732
59277
  try {
58733
- fs47.renameSync(file, `${file}.bak`);
59278
+ fs49.renameSync(file, `${file}.bak`);
58734
59279
  } catch {
58735
59280
  }
58736
59281
  }
@@ -58838,61 +59383,61 @@ async function connectRemote(args) {
58838
59383
  }
58839
59384
 
58840
59385
  // src/migrations/2026-05-20-flatten-sessions.ts
58841
- var fs48 = __toESM(require("fs"), 1);
58842
- var path50 = __toESM(require("path"), 1);
59386
+ var fs50 = __toESM(require("fs"), 1);
59387
+ var path52 = __toESM(require("path"), 1);
58843
59388
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
58844
59389
  function migrateFlattenSessions(opts) {
58845
59390
  const dataDir = opts.dataDir;
58846
59391
  const now = opts.now ?? Date.now;
58847
- const sessionsDir = path50.join(dataDir, "sessions");
58848
- const flagPath = path50.join(sessionsDir, MIGRATION_FLAG_NAME);
59392
+ const sessionsDir = path52.join(dataDir, "sessions");
59393
+ const flagPath = path52.join(sessionsDir, MIGRATION_FLAG_NAME);
58849
59394
  if (existsSync3(flagPath)) {
58850
59395
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
58851
59396
  }
58852
59397
  let movedBare = 0;
58853
59398
  let movedVmOwner = 0;
58854
59399
  let archivedListener = 0;
58855
- const defaultDir = path50.join(sessionsDir, "default");
59400
+ const defaultDir = path52.join(sessionsDir, "default");
58856
59401
  if (existsSync3(defaultDir)) {
58857
59402
  for (const entry of readdirSafe(defaultDir)) {
58858
59403
  if (!entry.endsWith(".json")) continue;
58859
- const src = path50.join(defaultDir, entry);
58860
- const dst = path50.join(sessionsDir, entry);
58861
- fs48.renameSync(src, dst);
59404
+ const src = path52.join(defaultDir, entry);
59405
+ const dst = path52.join(sessionsDir, entry);
59406
+ fs50.renameSync(src, dst);
58862
59407
  movedBare += 1;
58863
59408
  }
58864
59409
  rmdirIfEmpty(defaultDir);
58865
59410
  }
58866
59411
  for (const pid of readdirSafe(sessionsDir)) {
58867
- const personaDir = path50.join(sessionsDir, pid);
59412
+ const personaDir = path52.join(sessionsDir, pid);
58868
59413
  if (!isDir(personaDir)) continue;
58869
59414
  if (pid === "default") continue;
58870
- const ownerSrc = path50.join(personaDir, "owner");
59415
+ const ownerSrc = path52.join(personaDir, "owner");
58871
59416
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
58872
- const ownerDst = path50.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
58873
- fs48.mkdirSync(ownerDst, { recursive: true });
59417
+ const ownerDst = path52.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
59418
+ fs50.mkdirSync(ownerDst, { recursive: true });
58874
59419
  for (const file of readdirSafe(ownerSrc)) {
58875
59420
  if (!file.endsWith(".json")) continue;
58876
- fs48.renameSync(path50.join(ownerSrc, file), path50.join(ownerDst, file));
59421
+ fs50.renameSync(path52.join(ownerSrc, file), path52.join(ownerDst, file));
58877
59422
  movedVmOwner += 1;
58878
59423
  }
58879
59424
  rmdirIfEmpty(ownerSrc);
58880
59425
  }
58881
- const listenerSrc = path50.join(personaDir, "listener");
59426
+ const listenerSrc = path52.join(personaDir, "listener");
58882
59427
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
58883
- const archiveDst = path50.join(dataDir, ".legacy", `listener-${pid}`);
58884
- fs48.mkdirSync(archiveDst, { recursive: true });
59428
+ const archiveDst = path52.join(dataDir, ".legacy", `listener-${pid}`);
59429
+ fs50.mkdirSync(archiveDst, { recursive: true });
58885
59430
  for (const file of readdirSafe(listenerSrc)) {
58886
59431
  if (!file.endsWith(".json")) continue;
58887
- fs48.renameSync(path50.join(listenerSrc, file), path50.join(archiveDst, file));
59432
+ fs50.renameSync(path52.join(listenerSrc, file), path52.join(archiveDst, file));
58888
59433
  archivedListener += 1;
58889
59434
  }
58890
59435
  rmdirIfEmpty(listenerSrc);
58891
59436
  }
58892
59437
  rmdirIfEmpty(personaDir);
58893
59438
  }
58894
- fs48.mkdirSync(sessionsDir, { recursive: true });
58895
- 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));
58896
59441
  return {
58897
59442
  skipped: false,
58898
59443
  flagWritten: true,
@@ -58903,7 +59448,7 @@ function migrateFlattenSessions(opts) {
58903
59448
  }
58904
59449
  function existsSync3(p2) {
58905
59450
  try {
58906
- fs48.statSync(p2);
59451
+ fs50.statSync(p2);
58907
59452
  return true;
58908
59453
  } catch {
58909
59454
  return false;
@@ -58911,61 +59456,61 @@ function existsSync3(p2) {
58911
59456
  }
58912
59457
  function isDir(p2) {
58913
59458
  try {
58914
- return fs48.statSync(p2).isDirectory();
59459
+ return fs50.statSync(p2).isDirectory();
58915
59460
  } catch {
58916
59461
  return false;
58917
59462
  }
58918
59463
  }
58919
59464
  function readdirSafe(p2) {
58920
59465
  try {
58921
- return fs48.readdirSync(p2);
59466
+ return fs50.readdirSync(p2);
58922
59467
  } catch {
58923
59468
  return [];
58924
59469
  }
58925
59470
  }
58926
59471
  function rmdirIfEmpty(p2) {
58927
59472
  try {
58928
- fs48.rmdirSync(p2);
59473
+ fs50.rmdirSync(p2);
58929
59474
  } catch {
58930
59475
  }
58931
59476
  }
58932
59477
 
58933
59478
  // src/migrations/2026-08-18-drop-seeded-projects.ts
58934
- var fs49 = __toESM(require("fs"), 1);
58935
- var path51 = __toESM(require("path"), 1);
59479
+ var fs51 = __toESM(require("fs"), 1);
59480
+ var path53 = __toESM(require("path"), 1);
58936
59481
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
58937
59482
  function dropSeededProjects(opts) {
58938
- fs49.mkdirSync(opts.dataDir, { recursive: true });
58939
- const flag = path51.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
58940
- if (fs49.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
58941
- 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");
58942
59487
  let raw = null;
58943
59488
  let dropped = 0;
58944
59489
  try {
58945
- raw = fs49.readFileSync(file, "utf8");
59490
+ raw = fs51.readFileSync(file, "utf8");
58946
59491
  dropped = JSON.parse(raw).projects?.length ?? 0;
58947
59492
  } catch {
58948
59493
  }
58949
59494
  let backup = null;
58950
59495
  if (raw != null && dropped > 0) {
58951
- const dir = path51.join(opts.dataDir, "backups");
58952
- fs49.mkdirSync(dir, { recursive: true });
58953
- backup = path51.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
58954
- 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);
58955
59500
  }
58956
59501
  if (raw != null || dropped > 0) {
58957
- fs49.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
59502
+ fs51.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58958
59503
  }
58959
- fs49.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
59504
+ fs51.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58960
59505
  return { skipped: false, dropped, backup };
58961
59506
  }
58962
59507
 
58963
59508
  // src/transport/http-router.ts
58964
59509
  var import_node_fs36 = __toESM(require("fs"), 1);
58965
- var import_node_path43 = __toESM(require("path"), 1);
59510
+ var import_node_path45 = __toESM(require("path"), 1);
58966
59511
 
58967
59512
  // src/attachment/mime.ts
58968
- var import_node_path40 = __toESM(require("path"), 1);
59513
+ var import_node_path42 = __toESM(require("path"), 1);
58969
59514
  var TEXT_PLAIN = "text/plain; charset=utf-8";
58970
59515
  var EXT_TO_NATIVE_MIME = {
58971
59516
  // 图片
@@ -59072,7 +59617,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
59072
59617
  ".mk"
59073
59618
  ]);
59074
59619
  function lookupMime(filePathOrName) {
59075
- const ext = import_node_path40.default.extname(filePathOrName).toLowerCase();
59620
+ const ext = import_node_path42.default.extname(filePathOrName).toLowerCase();
59076
59621
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
59077
59622
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
59078
59623
  return "application/octet-stream";
@@ -59143,9 +59688,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
59143
59688
 
59144
59689
  // src/attachment/upload.ts
59145
59690
  var import_node_fs35 = __toESM(require("fs"), 1);
59146
- var import_node_path41 = __toESM(require("path"), 1);
59691
+ var import_node_path43 = __toESM(require("path"), 1);
59147
59692
  var import_node_crypto10 = __toESM(require("crypto"), 1);
59148
- var import_promises7 = require("stream/promises");
59693
+ var import_promises9 = require("stream/promises");
59149
59694
  var UploadError = class extends Error {
59150
59695
  constructor(code, message) {
59151
59696
  super(message);
@@ -59155,14 +59700,14 @@ var UploadError = class extends Error {
59155
59700
  code;
59156
59701
  };
59157
59702
  function assertValidFileName(fileName) {
59158
- 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)) {
59159
59704
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
59160
59705
  }
59161
59706
  }
59162
59707
  var HASH_PREFIX_LEN = 16;
59163
59708
  async function writeUploadedAttachment(args) {
59164
59709
  assertValidFileName(args.fileName);
59165
- const attachmentsRoot = import_node_path41.default.join(args.baseDir, ".attachments");
59710
+ const attachmentsRoot = import_node_path43.default.join(args.baseDir, ".attachments");
59166
59711
  try {
59167
59712
  import_node_fs35.default.mkdirSync(attachmentsRoot, { recursive: true });
59168
59713
  } catch (err) {
@@ -59170,12 +59715,12 @@ async function writeUploadedAttachment(args) {
59170
59715
  }
59171
59716
  const hasher = import_node_crypto10.default.createHash("sha256");
59172
59717
  let actualSize = 0;
59173
- const tmpPath = import_node_path41.default.join(
59718
+ const tmpPath = import_node_path43.default.join(
59174
59719
  attachmentsRoot,
59175
59720
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto10.default.randomBytes(4).toString("hex")}`
59176
59721
  );
59177
59722
  try {
59178
- await (0, import_promises7.pipeline)(
59723
+ await (0, import_promises9.pipeline)(
59179
59724
  args.body,
59180
59725
  async function* (source) {
59181
59726
  for await (const chunk of source) {
@@ -59205,7 +59750,7 @@ async function writeUploadedAttachment(args) {
59205
59750
  );
59206
59751
  }
59207
59752
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
59208
- const hashDir = import_node_path41.default.join(attachmentsRoot, attachmentId);
59753
+ const hashDir = import_node_path43.default.join(attachmentsRoot, attachmentId);
59209
59754
  let finalFileName;
59210
59755
  let hashDirExists = false;
59211
59756
  try {
@@ -59223,7 +59768,7 @@ async function writeUploadedAttachment(args) {
59223
59768
  try {
59224
59769
  import_node_fs35.default.mkdirSync(hashDir, { recursive: true });
59225
59770
  finalFileName = args.fileName;
59226
- 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));
59227
59772
  } catch (err) {
59228
59773
  try {
59229
59774
  import_node_fs35.default.unlinkSync(tmpPath);
@@ -59232,7 +59777,7 @@ async function writeUploadedAttachment(args) {
59232
59777
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
59233
59778
  }
59234
59779
  }
59235
- const absPath = import_node_path41.default.join(hashDir, finalFileName);
59780
+ const absPath = import_node_path43.default.join(hashDir, finalFileName);
59236
59781
  const relPath = absPath;
59237
59782
  args.groupFileStore.upsert(args.scope, args.sessionId, {
59238
59783
  relPath: absPath,
@@ -59246,9 +59791,9 @@ async function writeUploadedAttachment(args) {
59246
59791
  }
59247
59792
 
59248
59793
  // src/extension/import.ts
59249
- var import_promises8 = __toESM(require("fs/promises"), 1);
59250
- var import_node_path42 = __toESM(require("path"), 1);
59251
- 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);
59252
59797
  var import_jszip = __toESM(require_lib3(), 1);
59253
59798
  var ImportError = class extends Error {
59254
59799
  constructor(code, message) {
@@ -59265,7 +59810,7 @@ async function importZip(buf, root) {
59265
59810
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
59266
59811
  }
59267
59812
  for (const name of Object.keys(zip.files)) {
59268
- if (name.includes("..") || name.startsWith("/") || import_node_path42.default.isAbsolute(name)) {
59813
+ if (name.includes("..") || name.startsWith("/") || import_node_path44.default.isAbsolute(name)) {
59269
59814
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
59270
59815
  }
59271
59816
  }
@@ -59298,33 +59843,33 @@ async function importZip(buf, root) {
59298
59843
  );
59299
59844
  }
59300
59845
  }
59301
- const destDir = import_node_path42.default.join(root, manifest.id);
59846
+ const destDir = import_node_path44.default.join(root, manifest.id);
59302
59847
  let destExists = false;
59303
59848
  try {
59304
- await import_promises8.default.access(destDir);
59849
+ await import_promises10.default.access(destDir);
59305
59850
  destExists = true;
59306
59851
  } catch {
59307
59852
  }
59308
59853
  if (destExists) {
59309
59854
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
59310
59855
  }
59311
- 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}-`));
59312
59857
  try {
59313
59858
  for (const [name, entry] of Object.entries(zip.files)) {
59314
- const dest = import_node_path42.default.join(stage, name);
59859
+ const dest = import_node_path44.default.join(stage, name);
59315
59860
  if (entry.dir) {
59316
- await import_promises8.default.mkdir(dest, { recursive: true });
59861
+ await import_promises10.default.mkdir(dest, { recursive: true });
59317
59862
  continue;
59318
59863
  }
59319
- 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 });
59320
59865
  const content = await entry.async("nodebuffer");
59321
- await import_promises8.default.writeFile(dest, content);
59866
+ await import_promises10.default.writeFile(dest, content);
59322
59867
  }
59323
- await import_promises8.default.mkdir(root, { recursive: true });
59324
- await import_promises8.default.rename(stage, destDir);
59868
+ await import_promises10.default.mkdir(root, { recursive: true });
59869
+ await import_promises10.default.rename(stage, destDir);
59325
59870
  return { extId: manifest.id };
59326
59871
  } catch (e) {
59327
- await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
59872
+ await import_promises10.default.rm(stage, { recursive: true, force: true }).catch(() => {
59328
59873
  });
59329
59874
  throw e;
59330
59875
  }
@@ -59346,7 +59891,7 @@ var SHARE_UI_ASSET_MIME = {
59346
59891
  ".wasm": "application/wasm"
59347
59892
  };
59348
59893
  function shareUiAssetMime(filePath) {
59349
- const ext = import_node_path43.default.extname(filePath).toLowerCase();
59894
+ const ext = import_node_path45.default.extname(filePath).toLowerCase();
59350
59895
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
59351
59896
  }
59352
59897
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -59445,7 +59990,7 @@ function isValidUploadFileName(fileName) {
59445
59990
  if (fileName === "." || fileName === "..") return false;
59446
59991
  if (fileName.startsWith(".")) return false;
59447
59992
  if (fileName.includes("/") || fileName.includes("\\")) return false;
59448
- return fileName === import_node_path43.default.basename(fileName);
59993
+ return fileName === import_node_path45.default.basename(fileName);
59449
59994
  }
59450
59995
  function createHttpRouter(deps) {
59451
59996
  return async (req, res) => {
@@ -59681,7 +60226,7 @@ function createHttpRouter(deps) {
59681
60226
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
59682
60227
  return true;
59683
60228
  }
59684
- 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)));
59685
60230
  return true;
59686
60231
  }
59687
60232
  const ctx = deps.authResolver.resolveFromHeader(
@@ -59802,7 +60347,7 @@ function createHttpRouter(deps) {
59802
60347
  return true;
59803
60348
  }
59804
60349
  let absPath;
59805
- if (import_node_path43.default.isAbsolute(pathParam)) {
60350
+ if (import_node_path45.default.isAbsolute(pathParam)) {
59806
60351
  absPath = pathParam;
59807
60352
  } else if (deps.sessionStore) {
59808
60353
  const file = deps.sessionStore.read(sid);
@@ -59810,7 +60355,7 @@ function createHttpRouter(deps) {
59810
60355
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
59811
60356
  return true;
59812
60357
  }
59813
- absPath = import_node_path43.default.join(file.cwd, pathParam);
60358
+ absPath = import_node_path45.default.join(file.cwd, pathParam);
59814
60359
  } else {
59815
60360
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
59816
60361
  return true;
@@ -59912,7 +60457,7 @@ function streamFile(res, absPath, logger) {
59912
60457
  return;
59913
60458
  }
59914
60459
  const mime = lookupMime(absPath);
59915
- const basename2 = import_node_path43.default.basename(absPath);
60460
+ const basename2 = import_node_path45.default.basename(absPath);
59916
60461
  res.writeHead(200, {
59917
60462
  "Content-Type": mime,
59918
60463
  "Content-Length": String(stat.size),
@@ -59930,7 +60475,7 @@ function streamFile(res, absPath, logger) {
59930
60475
 
59931
60476
  // src/attachment/gc.ts
59932
60477
  var import_node_fs37 = __toESM(require("fs"), 1);
59933
- var import_node_path44 = __toESM(require("path"), 1);
60478
+ var import_node_path46 = __toESM(require("path"), 1);
59934
60479
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
59935
60480
  function runAttachmentGc(args) {
59936
60481
  const now = (args.now ?? Date.now)();
@@ -59939,12 +60484,12 @@ function runAttachmentGc(args) {
59939
60484
  for (const { scope, sessionId } of args.sessionScopes) {
59940
60485
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
59941
60486
  if (entry.stale) continue;
59942
- 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);
59943
60488
  }
59944
60489
  }
59945
60490
  const visited = /* @__PURE__ */ new Set();
59946
60491
  for (const { scope, sessionId } of args.sessionScopes) {
59947
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path44.default.join(
60492
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path46.default.join(
59948
60493
  args.dataDir,
59949
60494
  "sessions",
59950
60495
  ...scopeSubPath(scope).map(safeFileName),
@@ -59957,7 +60502,7 @@ function runAttachmentGc(args) {
59957
60502
  return true;
59958
60503
  });
59959
60504
  for (const rootDir of roots) {
59960
- const attRoot = import_node_path44.default.join(rootDir, ".attachments");
60505
+ const attRoot = import_node_path46.default.join(rootDir, ".attachments");
59961
60506
  let hashDirs;
59962
60507
  try {
59963
60508
  hashDirs = import_node_fs37.default.readdirSync(attRoot);
@@ -59967,7 +60512,7 @@ function runAttachmentGc(args) {
59967
60512
  continue;
59968
60513
  }
59969
60514
  for (const hashDir of hashDirs) {
59970
- const hashDirAbs = import_node_path44.default.join(attRoot, hashDir);
60515
+ const hashDirAbs = import_node_path46.default.join(attRoot, hashDir);
59971
60516
  let files;
59972
60517
  try {
59973
60518
  files = import_node_fs37.default.readdirSync(hashDirAbs);
@@ -59975,7 +60520,7 @@ function runAttachmentGc(args) {
59975
60520
  continue;
59976
60521
  }
59977
60522
  for (const name of files) {
59978
- const file = import_node_path44.default.join(hashDirAbs, name);
60523
+ const file = import_node_path46.default.join(hashDirAbs, name);
59979
60524
  let stat;
59980
60525
  try {
59981
60526
  stat = import_node_fs37.default.statSync(file);
@@ -60007,7 +60552,7 @@ function runAttachmentGc(args) {
60007
60552
 
60008
60553
  // src/attachment/group.ts
60009
60554
  var import_node_fs38 = __toESM(require("fs"), 1);
60010
- var import_node_path45 = __toESM(require("path"), 1);
60555
+ var import_node_path47 = __toESM(require("path"), 1);
60011
60556
  var import_node_crypto11 = __toESM(require("crypto"), 1);
60012
60557
  init_protocol();
60013
60558
  var GroupFileStore = class {
@@ -60019,11 +60564,11 @@ var GroupFileStore = class {
60019
60564
  this.logger = opts.logger;
60020
60565
  }
60021
60566
  rootForScope(scope) {
60022
- 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));
60023
60568
  }
60024
60569
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
60025
60570
  filePath(scope, sessionId) {
60026
- 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`);
60027
60572
  }
60028
60573
  cacheKey(scope, sessionId) {
60029
60574
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -60058,7 +60603,7 @@ var GroupFileStore = class {
60058
60603
  }
60059
60604
  writeFile(scope, sessionId, entries) {
60060
60605
  const file = this.filePath(scope, sessionId);
60061
- 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 });
60062
60607
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
60063
60608
  import_node_fs38.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
60064
60609
  import_node_fs38.default.renameSync(tmp, file);
@@ -60148,9 +60693,9 @@ var GroupFileStore = class {
60148
60693
 
60149
60694
  // src/discovery/state-file.ts
60150
60695
  var import_node_fs39 = __toESM(require("fs"), 1);
60151
- var import_node_path46 = __toESM(require("path"), 1);
60696
+ var import_node_path48 = __toESM(require("path"), 1);
60152
60697
  function defaultStateFilePath(dataDir) {
60153
- return import_node_path46.default.join(dataDir, "state.json");
60698
+ return import_node_path48.default.join(dataDir, "state.json");
60154
60699
  }
60155
60700
  function isPidAlive(pid) {
60156
60701
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -60186,7 +60731,7 @@ var StateFileManager = class {
60186
60731
  return { status: "stale", existing };
60187
60732
  }
60188
60733
  write(state) {
60189
- 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 });
60190
60735
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
60191
60736
  import_node_fs39.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
60192
60737
  import_node_fs39.default.renameSync(tmp, this.file);
@@ -60214,13 +60759,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
60214
60759
 
60215
60760
  // src/tunnel/tunnel-manager.ts
60216
60761
  var import_node_fs43 = __toESM(require("fs"), 1);
60217
- var import_node_path50 = __toESM(require("path"), 1);
60762
+ var import_node_path52 = __toESM(require("path"), 1);
60218
60763
  var import_node_crypto12 = __toESM(require("crypto"), 1);
60219
- var import_node_child_process11 = require("child_process");
60764
+ var import_node_child_process12 = require("child_process");
60220
60765
 
60221
60766
  // src/tunnel/tunnel-store.ts
60222
60767
  var import_node_fs40 = __toESM(require("fs"), 1);
60223
- var import_node_path47 = __toESM(require("path"), 1);
60768
+ var import_node_path49 = __toESM(require("path"), 1);
60224
60769
  var TunnelStore = class {
60225
60770
  constructor(filePath) {
60226
60771
  this.filePath = filePath;
@@ -60239,7 +60784,7 @@ var TunnelStore = class {
60239
60784
  }
60240
60785
  }
60241
60786
  async set(v2) {
60242
- const dir = import_node_path47.default.dirname(this.filePath);
60787
+ const dir = import_node_path49.default.dirname(this.filePath);
60243
60788
  await import_node_fs40.default.promises.mkdir(dir, { recursive: true });
60244
60789
  const data = JSON.stringify(v2, null, 2);
60245
60790
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -60350,11 +60895,11 @@ function escape(v2) {
60350
60895
 
60351
60896
  // src/tunnel/frpc-binary.ts
60352
60897
  var import_node_fs41 = __toESM(require("fs"), 1);
60353
- var import_node_os14 = __toESM(require("os"), 1);
60354
- var import_node_path48 = __toESM(require("path"), 1);
60355
- 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");
60356
60901
  var import_node_stream3 = require("stream");
60357
- var import_promises9 = require("stream/promises");
60902
+ var import_promises11 = require("stream/promises");
60358
60903
  var FRPC_VERSION = "0.68.0";
60359
60904
  var UnsupportedPlatformError = class extends Error {
60360
60905
  constructor(platform, arch) {
@@ -60390,13 +60935,13 @@ async function ensureFrpcBinary(opts) {
60390
60935
  }
60391
60936
  const version2 = opts.version ?? FRPC_VERSION;
60392
60937
  const platform = opts.platform ?? detectPlatform();
60393
- const binDir = import_node_path48.default.join(opts.dataDir, "bin");
60938
+ const binDir = import_node_path50.default.join(opts.dataDir, "bin");
60394
60939
  import_node_fs41.default.mkdirSync(binDir, { recursive: true });
60395
60940
  cleanupStaleArtifacts(binDir);
60396
- const stableBin = import_node_path48.default.join(binDir, "frpc");
60941
+ const stableBin = import_node_path50.default.join(binDir, "frpc");
60397
60942
  if (import_node_fs41.default.existsSync(stableBin)) return stableBin;
60398
60943
  const partialBin = `${stableBin}.partial`;
60399
- 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`);
60400
60945
  try {
60401
60946
  const url = frpcDownloadUrl(version2, platform);
60402
60947
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -60422,7 +60967,7 @@ function cleanupStaleArtifacts(binDir) {
60422
60967
  }
60423
60968
  for (const name of entries) {
60424
60969
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
60425
- const full = import_node_path48.default.join(binDir, name);
60970
+ const full = import_node_path50.default.join(binDir, name);
60426
60971
  try {
60427
60972
  import_node_fs41.default.rmSync(full, { recursive: true, force: true });
60428
60973
  } catch {
@@ -60445,19 +60990,19 @@ async function downloadToFile(url, dest, fetchImpl) {
60445
60990
  }
60446
60991
  const out = import_node_fs41.default.createWriteStream(dest);
60447
60992
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
60448
- await (0, import_promises9.pipeline)(nodeStream, out);
60993
+ await (0, import_promises11.pipeline)(nodeStream, out);
60449
60994
  }
60450
60995
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
60451
- 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()}`);
60452
60997
  import_node_fs41.default.mkdirSync(work, { recursive: true });
60453
60998
  try {
60454
60999
  await new Promise((resolve9, reject) => {
60455
- 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" });
60456
61001
  proc.on("error", reject);
60457
61002
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
60458
61003
  });
60459
61004
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
60460
- const src = import_node_path48.default.join(work, dirName, "frpc");
61005
+ const src = import_node_path50.default.join(work, dirName, "frpc");
60461
61006
  if (!import_node_fs41.default.existsSync(src)) {
60462
61007
  throw new Error(`frpc not found inside tarball at ${src}`);
60463
61008
  }
@@ -60469,10 +61014,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
60469
61014
 
60470
61015
  // src/tunnel/frpc-process.ts
60471
61016
  var import_node_fs42 = __toESM(require("fs"), 1);
60472
- var import_node_path49 = __toESM(require("path"), 1);
60473
- 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");
60474
61019
  function frpcPidFilePath(dataDir) {
60475
- return import_node_path49.default.join(dataDir, "frpc.pid");
61020
+ return import_node_path51.default.join(dataDir, "frpc.pid");
60476
61021
  }
60477
61022
  function writeFrpcPid(dataDir, pid) {
60478
61023
  try {
@@ -60514,7 +61059,7 @@ function defaultSleep2(ms) {
60514
61059
  }
60515
61060
  async function killStaleFrpc(deps) {
60516
61061
  const pidFile = frpcPidFilePath(deps.dataDir);
60517
- const tomlPath = import_node_path49.default.join(deps.dataDir, "frpc.toml");
61062
+ const tomlPath = import_node_path51.default.join(deps.dataDir, "frpc.toml");
60518
61063
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
60519
61064
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
60520
61065
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -60556,7 +61101,7 @@ async function killStaleFrpc(deps) {
60556
61101
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
60557
61102
  if (process.platform === "win32") return [];
60558
61103
  return new Promise((resolve9) => {
60559
- 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"] });
60560
61105
  let buf = "";
60561
61106
  ps.stdout.on("data", (c) => {
60562
61107
  buf += c.toString();
@@ -60586,7 +61131,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
60586
61131
  var TunnelManager = class {
60587
61132
  constructor(deps) {
60588
61133
  this.deps = deps;
60589
- 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"));
60590
61135
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
60591
61136
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
60592
61137
  }
@@ -60713,7 +61258,7 @@ var TunnelManager = class {
60713
61258
  dataDir: this.deps.dataDir,
60714
61259
  override: this.deps.frpcBinaryOverride ?? void 0
60715
61260
  });
60716
- 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");
60717
61262
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto12.default.randomBytes(3).toString("hex")}`;
60718
61263
  const toml = buildFrpcToml({
60719
61264
  serverAddr: t.frpsHost,
@@ -60725,12 +61270,12 @@ var TunnelManager = class {
60725
61270
  logLevel: "info"
60726
61271
  });
60727
61272
  await import_node_fs43.default.promises.writeFile(tomlPath, toml, { mode: 384 });
60728
- 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], {
60729
61274
  stdio: ["ignore", "pipe", "pipe"]
60730
61275
  });
60731
- const logDir = import_node_path50.default.join(this.deps.dataDir, "log");
61276
+ const logDir = import_node_path52.default.join(this.deps.dataDir, "log");
60732
61277
  import_node_fs43.default.mkdirSync(logDir, { recursive: true });
60733
- const logFilePath = import_node_path50.default.join(logDir, "frpc.log");
61278
+ const logFilePath = import_node_path52.default.join(logDir, "frpc.log");
60734
61279
  const logStream = import_node_fs43.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
60735
61280
  logStream.on("error", () => {
60736
61281
  });
@@ -60813,16 +61358,16 @@ async function waitForFrpcReady(proc, timeoutMs) {
60813
61358
  }
60814
61359
 
60815
61360
  // src/tunnel/device-key.ts
60816
- var import_node_os15 = __toESM(require("os"), 1);
60817
- 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);
60818
61363
  var import_node_crypto13 = __toESM(require("crypto"), 1);
60819
61364
  var DERIVE_SALT = "clawd-tunnel-device-v1";
60820
61365
  function deriveStableDeviceKey(opts = {}) {
60821
- const hostname = opts.hostname ?? import_node_os15.default.hostname();
60822
- const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
60823
- const home = opts.home ?? import_node_os15.default.homedir();
60824
- const defaultDataDir = import_node_path51.default.resolve(import_node_path51.default.join(home, ".clawd"));
60825
- 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;
60826
61371
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
60827
61372
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
60828
61373
  return import_node_crypto13.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -60830,11 +61375,11 @@ function deriveStableDeviceKey(opts = {}) {
60830
61375
 
60831
61376
  // src/auth-store.ts
60832
61377
  var import_node_fs44 = __toESM(require("fs"), 1);
60833
- var import_node_path52 = __toESM(require("path"), 1);
61378
+ var import_node_path54 = __toESM(require("path"), 1);
60834
61379
  var import_node_crypto14 = __toESM(require("crypto"), 1);
60835
61380
  var AUTH_FILE_NAME = "auth.json";
60836
61381
  function authFilePath(dataDir) {
60837
- return import_node_path52.default.join(dataDir, AUTH_FILE_NAME);
61382
+ return import_node_path54.default.join(dataDir, AUTH_FILE_NAME);
60838
61383
  }
60839
61384
  function loadOrCreateAuthFile(opts) {
60840
61385
  const file = authFilePath(opts.dataDir);
@@ -60886,7 +61431,7 @@ function readAuthFile(file) {
60886
61431
  }
60887
61432
  }
60888
61433
  function writeAuthFile(file, content) {
60889
- 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 });
60890
61435
  import_node_fs44.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
60891
61436
  try {
60892
61437
  import_node_fs44.default.chmodSync(file, 384);
@@ -60896,11 +61441,11 @@ function writeAuthFile(file, content) {
60896
61441
 
60897
61442
  // src/owner-profile.ts
60898
61443
  var import_node_fs45 = __toESM(require("fs"), 1);
60899
- var import_node_os16 = __toESM(require("os"), 1);
60900
- 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);
60901
61446
  var PROFILE_FILENAME = "profile.json";
60902
61447
  function profilePath(dataDir) {
60903
- return import_node_path53.default.join(dataDir, PROFILE_FILENAME);
61448
+ return import_node_path55.default.join(dataDir, PROFILE_FILENAME);
60904
61449
  }
60905
61450
  function loadOwnerProfile(dataDir) {
60906
61451
  let raw;
@@ -60925,7 +61470,7 @@ function patchOwnerProfile(dataDir, patch) {
60925
61470
  return merged;
60926
61471
  }
60927
61472
  function loadOwnerDisplayName(dataDir) {
60928
- const fallback = import_node_os16.default.userInfo().username;
61473
+ const fallback = import_node_os17.default.userInfo().username;
60929
61474
  const displayName = loadOwnerProfile(dataDir).displayName;
60930
61475
  if (typeof displayName !== "string" || displayName.length === 0) {
60931
61476
  if (displayName !== void 0) {
@@ -60938,12 +61483,12 @@ function loadOwnerDisplayName(dataDir) {
60938
61483
 
60939
61484
  // src/feishu-auth/owner-identity-store.ts
60940
61485
  var import_node_fs46 = __toESM(require("fs"), 1);
60941
- var import_node_path54 = __toESM(require("path"), 1);
61486
+ var import_node_path56 = __toESM(require("path"), 1);
60942
61487
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
60943
61488
  var OwnerIdentityStore = class {
60944
61489
  file;
60945
61490
  constructor(dataDir) {
60946
- 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);
60947
61492
  }
60948
61493
  read() {
60949
61494
  let raw;
@@ -60976,7 +61521,7 @@ var OwnerIdentityStore = class {
60976
61521
  };
60977
61522
  }
60978
61523
  write(record3) {
60979
- 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 });
60980
61525
  import_node_fs46.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
60981
61526
  try {
60982
61527
  import_node_fs46.default.chmodSync(this.file, 384);
@@ -61122,9 +61667,9 @@ var CentralClientError = class extends Error {
61122
61667
  code;
61123
61668
  cause;
61124
61669
  };
61125
- async function centralRequest(opts, path96, init) {
61670
+ async function centralRequest(opts, path98, init) {
61126
61671
  const f = opts.fetchImpl ?? globalThis.fetch;
61127
- const url = `${opts.api.replace(/\/+$/, "")}${path96}`;
61672
+ const url = `${opts.api.replace(/\/+$/, "")}${path98}`;
61128
61673
  const ctrl = new AbortController();
61129
61674
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
61130
61675
  let res;
@@ -61561,8 +62106,8 @@ function verifyConnectToken(args) {
61561
62106
  }
61562
62107
 
61563
62108
  // src/feishu-auth/server-key.ts
61564
- var fs63 = __toESM(require("fs"), 1);
61565
- var path67 = __toESM(require("path"), 1);
62109
+ var fs65 = __toESM(require("fs"), 1);
62110
+ var path69 = __toESM(require("path"), 1);
61566
62111
  var FILE_NAME2 = "server-signing-key.json";
61567
62112
  var ServerKeyStore = class {
61568
62113
  constructor(dataDir) {
@@ -61570,12 +62115,12 @@ var ServerKeyStore = class {
61570
62115
  }
61571
62116
  dataDir;
61572
62117
  filePath() {
61573
- return path67.join(this.dataDir, FILE_NAME2);
62118
+ return path69.join(this.dataDir, FILE_NAME2);
61574
62119
  }
61575
62120
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
61576
62121
  read() {
61577
62122
  try {
61578
- const raw = fs63.readFileSync(this.filePath(), "utf8");
62123
+ const raw = fs65.readFileSync(this.filePath(), "utf8");
61579
62124
  const parsed = JSON.parse(raw);
61580
62125
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
61581
62126
  return parsed.publicKeyPem;
@@ -61590,12 +62135,12 @@ var ServerKeyStore = class {
61590
62135
  publicKeyPem,
61591
62136
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
61592
62137
  };
61593
- fs63.mkdirSync(this.dataDir, { recursive: true });
61594
- 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 });
61595
62140
  }
61596
62141
  clear() {
61597
62142
  try {
61598
- fs63.unlinkSync(this.filePath());
62143
+ fs65.unlinkSync(this.filePath());
61599
62144
  } catch {
61600
62145
  }
61601
62146
  }
@@ -61605,15 +62150,15 @@ var ServerKeyStore = class {
61605
62150
  init_protocol();
61606
62151
 
61607
62152
  // src/handlers/index.ts
61608
- var import_node_path70 = __toESM(require("path"), 1);
62153
+ var import_node_path72 = __toESM(require("path"), 1);
61609
62154
 
61610
62155
  // src/handlers/session.ts
61611
62156
  init_protocol();
61612
62157
 
61613
62158
  // src/session/fork.ts
61614
62159
  var import_node_fs47 = __toESM(require("fs"), 1);
61615
- var import_node_os17 = __toESM(require("os"), 1);
61616
- 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);
61617
62162
  var import_node_crypto16 = require("crypto");
61618
62163
  init_claude_history();
61619
62164
  function readJsonlEntries(file) {
@@ -61630,19 +62175,19 @@ function readJsonlEntries(file) {
61630
62175
  return out;
61631
62176
  }
61632
62177
  function forkSession(input) {
61633
- const baseDir = input.baseDir ?? import_node_path55.default.join(import_node_os17.default.homedir(), ".claude");
61634
- let projectDir = import_node_path55.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
61635
- 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`);
61636
62181
  if (!import_node_fs47.default.existsSync(sourceFile)) {
61637
62182
  const found = findTranscriptByToolSessionId(
61638
- import_node_path55.default.join(baseDir, "projects"),
62183
+ import_node_path57.default.join(baseDir, "projects"),
61639
62184
  input.toolSessionId
61640
62185
  );
61641
62186
  if (!found) {
61642
62187
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
61643
62188
  }
61644
62189
  sourceFile = found;
61645
- projectDir = import_node_path55.default.dirname(found);
62190
+ projectDir = import_node_path57.default.dirname(found);
61646
62191
  }
61647
62192
  const entries = readJsonlEntries(sourceFile);
61648
62193
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -61671,8 +62216,8 @@ function forkSession(input) {
61671
62216
  }
61672
62217
  forkedLines.push(JSON.stringify(forked));
61673
62218
  }
61674
- const outDir = input.targetCwd ? import_node_path55.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
61675
- 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`);
61676
62221
  import_node_fs47.default.mkdirSync(outDir, { recursive: true });
61677
62222
  import_node_fs47.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
61678
62223
  return { forkedToolSessionId, forkedFilePath };
@@ -61680,18 +62225,18 @@ function forkSession(input) {
61680
62225
 
61681
62226
  // src/session/external-scan.ts
61682
62227
  var import_node_fs48 = __toESM(require("fs"), 1);
61683
- var import_promises10 = __toESM(require("fs/promises"), 1);
61684
- var import_node_os18 = __toESM(require("os"), 1);
61685
- 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);
61686
62231
  var import_node_module = require("module");
61687
- var import_node_child_process12 = require("child_process");
62232
+ var import_node_child_process13 = require("child_process");
61688
62233
  var import_meta5 = {};
61689
62234
  function defaultRoots() {
61690
- const home = import_node_os18.default.homedir();
62235
+ const home = import_node_os19.default.homedir();
61691
62236
  return {
61692
- claudeProjectsDir: import_node_path56.default.join(home, ".claude", "projects"),
61693
- codexDir: import_node_path56.default.join(home, ".codex"),
61694
- 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")
61695
62240
  };
61696
62241
  }
61697
62242
  function width(s) {
@@ -61719,7 +62264,7 @@ function toMs(v2) {
61719
62264
  async function* jsonLines(file) {
61720
62265
  let raw;
61721
62266
  try {
61722
- raw = await import_promises10.default.readFile(file, "utf8");
62267
+ raw = await import_promises12.default.readFile(file, "utf8");
61723
62268
  } catch {
61724
62269
  return;
61725
62270
  }
@@ -61759,13 +62304,13 @@ async function scanClaude(roots) {
61759
62304
  if (!d.isDirectory()) continue;
61760
62305
  let files;
61761
62306
  try {
61762
- 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));
61763
62308
  } catch {
61764
62309
  continue;
61765
62310
  }
61766
62311
  for (const name of files) {
61767
62312
  if (!name.endsWith(".jsonl")) continue;
61768
- 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);
61769
62314
  let st;
61770
62315
  try {
61771
62316
  st = import_node_fs48.default.statSync(file);
@@ -61852,14 +62397,14 @@ function readCodexThreads(db) {
61852
62397
  } catch {
61853
62398
  }
61854
62399
  try {
61855
- 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" });
61856
62401
  if (info.status !== 0) return null;
61857
62402
  const have = new Set(
61858
62403
  info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
61859
62404
  );
61860
62405
  if (!["id", "cwd", "updated_at", "thread_source"].every((c) => have.has(c))) return null;
61861
62406
  const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
61862
- 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;`], {
61863
62408
  encoding: "utf8",
61864
62409
  maxBuffer: 64 * 1024 * 1024
61865
62410
  });
@@ -61895,7 +62440,7 @@ async function codexFromRows(rows) {
61895
62440
  async function scanCodex(roots) {
61896
62441
  let dbs = [];
61897
62442
  try {
61898
- 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));
61899
62444
  } catch {
61900
62445
  }
61901
62446
  if (!dbs.length) return [];
@@ -61904,14 +62449,14 @@ async function scanCodex(roots) {
61904
62449
  }
61905
62450
  async function scanExternalSessions(rootsIn) {
61906
62451
  const roots = { ...defaultRoots(), ...rootsIn };
61907
- const personaRoot = import_node_path56.default.join(roots.clawdDir, "personas");
62452
+ const personaRoot = import_node_path58.default.join(roots.clawdDir, "personas");
61908
62453
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
61909
62454
  const out = [];
61910
62455
  for (const c of all) {
61911
62456
  if (c.skip) continue;
61912
62457
  if (c.turns < 1) continue;
61913
62458
  if (!c.cwd || !isDir2(c.cwd)) continue;
61914
- 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)) {
61915
62460
  continue;
61916
62461
  }
61917
62462
  out.push({
@@ -61929,12 +62474,12 @@ async function scanExternalSessions(rootsIn) {
61929
62474
 
61930
62475
  // src/session/import-ledger.ts
61931
62476
  var import_node_fs49 = __toESM(require("fs"), 1);
61932
- var import_node_path57 = __toESM(require("path"), 1);
62477
+ var import_node_path59 = __toESM(require("path"), 1);
61933
62478
  var LEDGER_FILENAME = "session-import-ledger.json";
61934
62479
  function readImportLedger(dataDir) {
61935
62480
  try {
61936
62481
  const parsed = JSON.parse(
61937
- 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")
61938
62483
  );
61939
62484
  return Array.isArray(parsed) ? parsed : [];
61940
62485
  } catch {
@@ -61942,7 +62487,7 @@ function readImportLedger(dataDir) {
61942
62487
  }
61943
62488
  }
61944
62489
  function appendImportLedger(dataDir, entry) {
61945
- const file = import_node_path57.default.join(dataDir, LEDGER_FILENAME);
62490
+ const file = import_node_path59.default.join(dataDir, LEDGER_FILENAME);
61946
62491
  const entries = readImportLedger(dataDir);
61947
62492
  entries.push(entry);
61948
62493
  import_node_fs49.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
@@ -61950,7 +62495,7 @@ function appendImportLedger(dataDir, entry) {
61950
62495
 
61951
62496
  // src/tools/transcript-search.ts
61952
62497
  var import_node_fs50 = __toESM(require("fs"), 1);
61953
- var import_node_path58 = __toESM(require("path"), 1);
62498
+ var import_node_path60 = __toESM(require("path"), 1);
61954
62499
  var SNIPPET_PAD = 60;
61955
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/;
61956
62501
  var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
@@ -62043,7 +62588,7 @@ function createCodexRolloutLocator(roots) {
62043
62588
  return;
62044
62589
  }
62045
62590
  for (const entry of entries) {
62046
- const full = import_node_path58.default.join(dir, entry.name);
62591
+ const full = import_node_path60.default.join(dir, entry.name);
62047
62592
  if (entry.isDirectory()) {
62048
62593
  walk2(full, into);
62049
62594
  continue;
@@ -62063,16 +62608,16 @@ function createCodexRolloutLocator(roots) {
62063
62608
 
62064
62609
  // src/handlers/session.ts
62065
62610
  init_protocol();
62066
- var import_node_os19 = __toESM(require("os"), 1);
62067
- 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);
62068
62613
  function canReadSearchHit(ctx, file) {
62069
62614
  if (!ctx || ctx.principal.kind === "owner") return true;
62070
62615
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
62071
62616
  }
62072
62617
  var DEFAULT_SEARCH_LIMIT = 9;
62073
62618
  function codexRolloutRoots(dataDir) {
62074
- const roots = [import_node_path59.default.join(import_node_os19.default.homedir(), ".codex", "sessions")];
62075
- 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"));
62076
62621
  return roots;
62077
62622
  }
62078
62623
  function buildSessionHandlers(deps) {
@@ -62614,7 +63159,7 @@ function buildPermissionHandlers(deps) {
62614
63159
  }
62615
63160
 
62616
63161
  // src/handlers/history.ts
62617
- var path74 = __toESM(require("path"), 1);
63162
+ var path76 = __toESM(require("path"), 1);
62618
63163
  init_protocol();
62619
63164
 
62620
63165
  // src/session/recent-dirs.ts
@@ -62632,7 +63177,7 @@ function listRecentDirs(store, limit = 50) {
62632
63177
  }
62633
63178
 
62634
63179
  // src/permission/persona-paths.ts
62635
- var path73 = __toESM(require("path"), 1);
63180
+ var path75 = __toESM(require("path"), 1);
62636
63181
  function getAllowedPersonaIds(grants, action) {
62637
63182
  const ids = /* @__PURE__ */ new Set();
62638
63183
  for (const g2 of grants) {
@@ -62645,42 +63190,42 @@ function getAllowedPersonaIds(grants, action) {
62645
63190
  return ids;
62646
63191
  }
62647
63192
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
62648
- const target = path73.resolve(absPath);
63193
+ const target = path75.resolve(absPath);
62649
63194
  if (userWorkDir) {
62650
- const u = path73.resolve(userWorkDir);
62651
- const usep = u.endsWith(path73.sep) ? "" : path73.sep;
63195
+ const u = path75.resolve(userWorkDir);
63196
+ const usep = u.endsWith(path75.sep) ? "" : path75.sep;
62652
63197
  if (target === u || target.startsWith(u + usep)) return true;
62653
63198
  }
62654
- const root = path73.resolve(personaRoot);
62655
- const sep4 = root.endsWith(path73.sep) ? "" : path73.sep;
63199
+ const root = path75.resolve(personaRoot);
63200
+ const sep4 = root.endsWith(path75.sep) ? "" : path75.sep;
62656
63201
  if (!target.startsWith(root + sep4)) return false;
62657
- const rel = path73.relative(root, target);
63202
+ const rel = path75.relative(root, target);
62658
63203
  if (!rel || rel.startsWith("..")) return false;
62659
- const personaId2 = rel.split(path73.sep)[0];
63204
+ const personaId2 = rel.split(path75.sep)[0];
62660
63205
  if (!personaId2) return false;
62661
63206
  const allowed = getAllowedPersonaIds(grants, action);
62662
63207
  if (allowed === "*") return true;
62663
63208
  return allowed.has(personaId2);
62664
63209
  }
62665
63210
  function personaIdFromPath(absPath, personaRoot) {
62666
- const root = path73.resolve(personaRoot);
62667
- const target = path73.resolve(absPath);
62668
- 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;
62669
63214
  if (!target.startsWith(root + sep4)) return null;
62670
- const rel = path73.relative(root, target);
63215
+ const rel = path75.relative(root, target);
62671
63216
  if (!rel || rel.startsWith("..")) return null;
62672
- const id = rel.split(path73.sep)[0];
63217
+ const id = rel.split(path75.sep)[0];
62673
63218
  return id || null;
62674
63219
  }
62675
63220
  function isPathWithin(dir, absPath) {
62676
- const d = path73.resolve(dir);
62677
- const t = path73.resolve(absPath);
62678
- 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;
62679
63224
  return t === d || t.startsWith(d + sep4);
62680
63225
  }
62681
63226
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
62682
63227
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
62683
- return personaIdFromPath(path73.resolve(absPath), personaRoot) === personaId2;
63228
+ return personaIdFromPath(path75.resolve(absPath), personaRoot) === personaId2;
62684
63229
  }
62685
63230
 
62686
63231
  // src/handlers/history.ts
@@ -62733,7 +63278,7 @@ function buildHistoryHandlers(deps) {
62733
63278
  if (!pid) return false;
62734
63279
  return isGuestPathAllowed(
62735
63280
  ctx.grants,
62736
- path74.join(personaRoot, pid),
63281
+ path76.join(personaRoot, pid),
62737
63282
  personaRoot,
62738
63283
  "read",
62739
63284
  userWorkDir
@@ -62745,7 +63290,7 @@ function buildHistoryHandlers(deps) {
62745
63290
  };
62746
63291
  const list = async (frame, _client, ctx) => {
62747
63292
  const args = HistoryListArgs.parse(frame);
62748
- assertGuestPath(ctx, path74.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
63293
+ assertGuestPath(ctx, path76.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
62749
63294
  const sessions = await history.listSessions(args);
62750
63295
  return { response: { type: "history:list", sessions } };
62751
63296
  };
@@ -62793,14 +63338,14 @@ function buildHistoryHandlers(deps) {
62793
63338
  };
62794
63339
  const subagents = async (frame, _client, ctx) => {
62795
63340
  const args = HistorySubagentsArgs.parse(frame);
62796
- assertGuestPath(ctx, path74.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
63341
+ assertGuestPath(ctx, path76.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
62797
63342
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
62798
63343
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
62799
63344
  return { response: { type: "history:subagents", subagents: subs } };
62800
63345
  };
62801
63346
  const subagentRead = async (frame, _client, ctx) => {
62802
63347
  const args = HistorySubagentReadArgs.parse(frame);
62803
- assertGuestPath(ctx, path74.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
63348
+ assertGuestPath(ctx, path76.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
62804
63349
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
62805
63350
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
62806
63351
  return { response: { type: "history:subagent-read", ...res } };
@@ -62810,7 +63355,7 @@ function buildHistoryHandlers(deps) {
62810
63355
  if (ctx?.principal.kind === "guest" && personaRoot) {
62811
63356
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
62812
63357
  const filtered = dirs.filter(
62813
- (d) => isGuestPathAllowed(ctx.grants, path74.resolve(d.cwd), personaRoot, "read", userWorkDir)
63358
+ (d) => isGuestPathAllowed(ctx.grants, path76.resolve(d.cwd), personaRoot, "read", userWorkDir)
62814
63359
  );
62815
63360
  return { response: { type: "history:recentDirs", dirs: filtered } };
62816
63361
  }
@@ -62827,17 +63372,17 @@ function buildHistoryHandlers(deps) {
62827
63372
  }
62828
63373
 
62829
63374
  // src/handlers/projects.ts
62830
- var fs68 = __toESM(require("fs"), 1);
62831
- var os21 = __toESM(require("os"), 1);
62832
- var path75 = __toESM(require("path"), 1);
62833
- 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");
62834
63379
  init_protocol();
62835
- var DEFAULT_PROJECTS_ROOT = path75.join(os21.homedir(), "Documents", "ChatGPT");
63380
+ var DEFAULT_PROJECTS_ROOT = path77.join(os22.homedir(), "Documents", "ChatGPT");
62836
63381
  function allocateDir(root, name) {
62837
- let candidate = path75.join(root, name);
63382
+ let candidate = path77.join(root, name);
62838
63383
  let n = 2;
62839
- while (fs68.existsSync(candidate)) {
62840
- candidate = path75.join(root, `${name} ${n}`);
63384
+ while (fs70.existsSync(candidate)) {
63385
+ candidate = path77.join(root, `${name} ${n}`);
62841
63386
  n += 1;
62842
63387
  }
62843
63388
  return candidate;
@@ -62865,11 +63410,11 @@ function buildProjectHandlers(deps) {
62865
63410
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
62866
63411
  }
62867
63412
  try {
62868
- if (!fs68.statSync(args.path).isDirectory()) throw new Error("not dir");
63413
+ if (!fs70.statSync(args.path).isDirectory()) throw new Error("not dir");
62869
63414
  } catch {
62870
63415
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
62871
63416
  }
62872
- 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" });
62873
63418
  if (r.status !== 0) {
62874
63419
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `open -R \u5931\u8D25: exit ${r.status}`);
62875
63420
  }
@@ -62881,7 +63426,7 @@ function buildProjectHandlers(deps) {
62881
63426
  let target;
62882
63427
  if (args.path) {
62883
63428
  try {
62884
- if (!fs68.statSync(args.path).isDirectory()) throw new Error("not dir");
63429
+ if (!fs70.statSync(args.path).isDirectory()) throw new Error("not dir");
62885
63430
  } catch {
62886
63431
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
62887
63432
  }
@@ -62889,15 +63434,15 @@ function buildProjectHandlers(deps) {
62889
63434
  } else {
62890
63435
  const name = args.name;
62891
63436
  try {
62892
- fs68.mkdirSync(root, { recursive: true });
63437
+ fs70.mkdirSync(root, { recursive: true });
62893
63438
  target = allocateDir(root, name);
62894
- fs68.mkdirSync(target);
63439
+ fs70.mkdirSync(target);
62895
63440
  } catch (err) {
62896
63441
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
62897
63442
  }
62898
- 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" });
62899
63444
  if (git.status !== 0) {
62900
- fs68.rmSync(target, { recursive: true, force: true });
63445
+ fs70.rmSync(target, { recursive: true, force: true });
62901
63446
  throw new ClawdError(
62902
63447
  ERROR_CODES.INVALID_CWD,
62903
63448
  `git init \u5931\u8D25\uFF08${git.error ? String(git.error) : `exit ${git.status}`}\uFF09: ${target}`
@@ -62922,8 +63467,8 @@ function buildProjectHandlers(deps) {
62922
63467
  }
62923
63468
 
62924
63469
  // src/handlers/workspace.ts
62925
- var path76 = __toESM(require("path"), 1);
62926
- var os22 = __toESM(require("os"), 1);
63470
+ var path78 = __toESM(require("path"), 1);
63471
+ var os23 = __toESM(require("os"), 1);
62927
63472
  init_protocol();
62928
63473
  init_protocol();
62929
63474
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -62963,23 +63508,23 @@ function buildWorkspaceHandlers(deps) {
62963
63508
  const list = async (frame, _client, ctx) => {
62964
63509
  const args = WorkspaceListArgs.parse(frame);
62965
63510
  const isGuest = ctx?.principal.kind === "guest";
62966
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os22.homedir();
62967
- const resolvedCwd = path76.resolve(args.cwd ?? fallbackCwd);
62968
- 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;
62969
63514
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
62970
63515
  const res = workspace.list({ ...args, cwd: resolvedCwd });
62971
63516
  return { response: { type: "workspace:list", ...res } };
62972
63517
  };
62973
63518
  const read = async (frame, _client, ctx) => {
62974
63519
  const args = WorkspaceReadArgs.parse(frame);
62975
- 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);
62976
63521
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
62977
63522
  const res = workspace.read(args);
62978
63523
  return { response: { type: "workspace:read", ...res } };
62979
63524
  };
62980
63525
  const skillsList = async (frame, _client, ctx) => {
62981
63526
  const args = SkillsListArgs.parse(frame);
62982
- const cwdAbs = path76.resolve(args.cwd);
63527
+ const cwdAbs = path78.resolve(args.cwd);
62983
63528
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
62984
63529
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
62985
63530
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -62991,7 +63536,7 @@ function buildWorkspaceHandlers(deps) {
62991
63536
  };
62992
63537
  const agentsList = async (frame, _client, ctx) => {
62993
63538
  const args = AgentsListArgs.parse(frame);
62994
- const cwdAbs = path76.resolve(args.cwd);
63539
+ const cwdAbs = path78.resolve(args.cwd);
62995
63540
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
62996
63541
  if (args.tool === "codex") {
62997
63542
  return { response: { type: "agents:list", agents: [] } };
@@ -63013,18 +63558,18 @@ function buildWorkspaceHandlers(deps) {
63013
63558
  }
63014
63559
 
63015
63560
  // src/handlers/git.ts
63016
- var path78 = __toESM(require("path"), 1);
63561
+ var path80 = __toESM(require("path"), 1);
63017
63562
  init_protocol();
63018
63563
  init_protocol();
63019
63564
 
63020
63565
  // src/workspace/git.ts
63021
- var import_node_child_process14 = require("child_process");
63566
+ var import_node_child_process15 = require("child_process");
63022
63567
  var import_node_fs51 = __toESM(require("fs"), 1);
63023
- var import_node_path60 = __toESM(require("path"), 1);
63568
+ var import_node_path62 = __toESM(require("path"), 1);
63024
63569
  var import_node_util = require("util");
63025
- 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);
63026
63571
  function normalizePath(p2) {
63027
- const resolved = import_node_path60.default.resolve(p2);
63572
+ const resolved = import_node_path62.default.resolve(p2);
63028
63573
  try {
63029
63574
  return import_node_fs51.default.realpathSync(resolved);
63030
63575
  } catch {
@@ -63100,7 +63645,7 @@ async function listGitBranches(cwd) {
63100
63645
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
63101
63646
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
63102
63647
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
63103
- if (!isGuestPathAllowed(ctx.grants, path78.resolve(cwd), personaRoot, "read", userWorkDir)) {
63648
+ if (!isGuestPathAllowed(ctx.grants, path80.resolve(cwd), personaRoot, "read", userWorkDir)) {
63104
63649
  throw new ClawdError(
63105
63650
  ERROR_CODES.UNAUTHORIZED,
63106
63651
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -63645,7 +64190,7 @@ function buildFeishuAuthHandlers(deps) {
63645
64190
  }
63646
64191
 
63647
64192
  // src/handlers/meta.ts
63648
- var import_node_os20 = __toESM(require("os"), 1);
64193
+ var import_node_os21 = __toESM(require("os"), 1);
63649
64194
  init_protocol();
63650
64195
 
63651
64196
  // src/handlers/method-grants.ts
@@ -63700,6 +64245,8 @@ var METHOD_GRANT_MAP = {
63700
64245
  "deploy:putSecret": ADMIN_ANY,
63701
64246
  "deploy:reportFinding": ADMIN_ANY,
63702
64247
  "deploy:finishScan": ADMIN_ANY,
64248
+ "deploy:trial": ADMIN_ANY,
64249
+ "deploy:deploy": ADMIN_ANY,
63703
64250
  "deploy:remove": ADMIN_ANY,
63704
64251
  // ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
63705
64252
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
@@ -63946,21 +64493,21 @@ function computeMethodAccess(args) {
63946
64493
  }
63947
64494
 
63948
64495
  // src/version.ts
63949
- var version = "0.2.460".length > 0 ? "0.2.460" : "dev";
64496
+ var version = "0.2.462".length > 0 ? "0.2.462" : "dev";
63950
64497
 
63951
64498
  // src/cli-probe/probe.ts
63952
- var fs70 = __toESM(require("fs"), 1);
63953
- var path79 = __toESM(require("path"), 1);
64499
+ var fs72 = __toESM(require("fs"), 1);
64500
+ var path81 = __toESM(require("path"), 1);
63954
64501
  var PKG_NAME = "@clawos-dev/clawd";
63955
64502
  var BIN_NAME = "clawd";
63956
64503
  var MAX_PARENT_HOPS = 5;
63957
64504
  function probeGlobalCli(pathEnv) {
63958
64505
  if (!pathEnv) return null;
63959
- for (const dir of pathEnv.split(path79.delimiter)) {
64506
+ for (const dir of pathEnv.split(path81.delimiter)) {
63960
64507
  if (!dir) continue;
63961
64508
  let real;
63962
64509
  try {
63963
- real = fs70.realpathSync(path79.join(dir, BIN_NAME));
64510
+ real = fs72.realpathSync(path81.join(dir, BIN_NAME));
63964
64511
  } catch {
63965
64512
  continue;
63966
64513
  }
@@ -63970,15 +64517,15 @@ function probeGlobalCli(pathEnv) {
63970
64517
  return null;
63971
64518
  }
63972
64519
  function readOwnPackageVersion(entryPath) {
63973
- let dir = path79.dirname(entryPath);
64520
+ let dir = path81.dirname(entryPath);
63974
64521
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
63975
64522
  try {
63976
- const raw = fs70.readFileSync(path79.join(dir, "package.json"), "utf8");
64523
+ const raw = fs72.readFileSync(path81.join(dir, "package.json"), "utf8");
63977
64524
  const pkg = JSON.parse(raw);
63978
64525
  if (pkg.name !== PKG_NAME) return null;
63979
64526
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
63980
64527
  } catch {
63981
- const parent = path79.dirname(dir);
64528
+ const parent = path81.dirname(dir);
63982
64529
  if (parent === dir) return null;
63983
64530
  dir = parent;
63984
64531
  }
@@ -64014,7 +64561,7 @@ function buildReadyFrame(deps, client) {
64014
64561
  return {
64015
64562
  version,
64016
64563
  protocolVersion: PROTOCOL_VERSION,
64017
- hostname: import_node_os20.default.hostname(),
64564
+ hostname: import_node_os21.default.hostname(),
64018
64565
  os: process.platform,
64019
64566
  tools,
64020
64567
  runningSessions: info.runningSessions,
@@ -64150,7 +64697,7 @@ function buildPersonaHandlers(deps) {
64150
64697
  }
64151
64698
 
64152
64699
  // src/handlers/attachment.ts
64153
- var import_node_path61 = __toESM(require("path"), 1);
64700
+ var import_node_path63 = __toESM(require("path"), 1);
64154
64701
  init_protocol();
64155
64702
  init_protocol();
64156
64703
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -64230,12 +64777,12 @@ function buildAttachmentHandlers(deps) {
64230
64777
  `session ${args.sessionId} scope unresolved`
64231
64778
  );
64232
64779
  }
64233
- const cwdAbs = import_node_path61.default.resolve(sessionFile.cwd);
64234
- 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);
64235
64782
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
64236
64783
  const entries = deps.groupFileStore.list(scope, args.sessionId);
64237
64784
  const entry = entries.find((e) => {
64238
- 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);
64239
64786
  return storedAbs === candidateAbs && !e.stale;
64240
64787
  });
64241
64788
  if (!entry) {
@@ -64260,7 +64807,7 @@ function buildAttachmentHandlers(deps) {
64260
64807
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
64261
64808
  const f = deps.sessionStore.read(sessionId);
64262
64809
  if (!f) return;
64263
- 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);
64264
64811
  }
64265
64812
  const groupAdd = async (frame, _client, ctx) => {
64266
64813
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -64275,8 +64822,8 @@ function buildAttachmentHandlers(deps) {
64275
64822
  if (!scope) {
64276
64823
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
64277
64824
  }
64278
- const cwdAbs = import_node_path61.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
64279
- 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);
64280
64827
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
64281
64828
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
64282
64829
  const size = 0;
@@ -64334,21 +64881,21 @@ function buildAttachmentHandlers(deps) {
64334
64881
  }
64335
64882
 
64336
64883
  // src/handlers/extension.ts
64337
- var import_promises14 = __toESM(require("fs/promises"), 1);
64338
- 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);
64339
64886
  init_protocol();
64340
64887
 
64341
64888
  // src/extension/bundle-zip.ts
64342
- var import_promises11 = __toESM(require("fs/promises"), 1);
64343
- 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);
64344
64891
  var import_node_crypto17 = __toESM(require("crypto"), 1);
64345
64892
  var import_jszip2 = __toESM(require_lib3(), 1);
64346
64893
  async function bundleExtensionDir(dir) {
64347
64894
  const entries = await listFilesSorted(dir);
64348
64895
  const zip = new import_jszip2.default();
64349
64896
  for (const rel of entries) {
64350
- const abs = import_node_path62.default.join(dir, rel);
64351
- 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);
64352
64899
  zip.file(rel, content, { date: FIXED_DATE });
64353
64900
  }
64354
64901
  const buffer = await zip.generateAsync({
@@ -64368,8 +64915,8 @@ async function listFilesSorted(rootDir) {
64368
64915
  return out;
64369
64916
  }
64370
64917
  async function walk(absRoot, relPrefix, out) {
64371
- const dirAbs = import_node_path62.default.join(absRoot, relPrefix);
64372
- 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 });
64373
64920
  for (const e of entries) {
64374
64921
  if (IGNORE_BASENAMES.has(e.name)) continue;
64375
64922
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -64421,26 +64968,26 @@ function computePublishCheck(args) {
64421
64968
  }
64422
64969
 
64423
64970
  // src/extension/install-flow.ts
64424
- var import_promises12 = __toESM(require("fs/promises"), 1);
64425
- var import_node_path64 = __toESM(require("path"), 1);
64426
- 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);
64427
64974
  var import_node_crypto18 = __toESM(require("crypto"), 1);
64428
64975
  var import_jszip3 = __toESM(require_lib3(), 1);
64429
64976
 
64430
64977
  // src/extension/paths.ts
64431
- var import_node_os21 = __toESM(require("os"), 1);
64432
- 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);
64433
64980
  function clawdHomeRoot(override) {
64434
- 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");
64435
64982
  }
64436
64983
  function extensionsRoot(override) {
64437
- return import_node_path63.default.join(clawdHomeRoot(override), "extensions");
64984
+ return import_node_path65.default.join(clawdHomeRoot(override), "extensions");
64438
64985
  }
64439
64986
  function publishedChannelsFile(override) {
64440
- return import_node_path63.default.join(clawdHomeRoot(override), "extensions-published.json");
64987
+ return import_node_path65.default.join(clawdHomeRoot(override), "extensions-published.json");
64441
64988
  }
64442
64989
  function bundleCacheRoot(override) {
64443
- return import_node_path63.default.join(clawdHomeRoot(override), "extension-bundles");
64990
+ return import_node_path65.default.join(clawdHomeRoot(override), "extension-bundles");
64444
64991
  }
64445
64992
 
64446
64993
  // src/extension/install-flow.ts
@@ -64467,7 +65014,7 @@ async function installFromChannel(args, deps) {
64467
65014
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
64468
65015
  }
64469
65016
  for (const name of Object.keys(zip.files)) {
64470
- if (name.includes("..") || name.startsWith("/") || import_node_path64.default.isAbsolute(name)) {
65017
+ if (name.includes("..") || name.startsWith("/") || import_node_path66.default.isAbsolute(name)) {
64471
65018
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
64472
65019
  }
64473
65020
  }
@@ -64499,10 +65046,10 @@ async function installFromChannel(args, deps) {
64499
65046
  );
64500
65047
  }
64501
65048
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
64502
- const destDir = import_node_path64.default.join(deps.extensionsRoot, localExtId);
65049
+ const destDir = import_node_path66.default.join(deps.extensionsRoot, localExtId);
64503
65050
  let destExists = false;
64504
65051
  try {
64505
- await import_promises12.default.access(destDir);
65052
+ await import_promises14.default.access(destDir);
64506
65053
  destExists = true;
64507
65054
  } catch {
64508
65055
  }
@@ -64512,28 +65059,28 @@ async function installFromChannel(args, deps) {
64512
65059
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
64513
65060
  );
64514
65061
  }
64515
- const stage = await import_promises12.default.mkdtemp(
64516
- 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}-`)
64517
65064
  );
64518
65065
  try {
64519
65066
  for (const [name, entry] of Object.entries(zip.files)) {
64520
- const dest = import_node_path64.default.join(stage, name);
65067
+ const dest = import_node_path66.default.join(stage, name);
64521
65068
  if (entry.dir) {
64522
- await import_promises12.default.mkdir(dest, { recursive: true });
65069
+ await import_promises14.default.mkdir(dest, { recursive: true });
64523
65070
  continue;
64524
65071
  }
64525
- 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 });
64526
65073
  if (name === "manifest.json") {
64527
65074
  const rewritten = { ...parsed.data, id: localExtId };
64528
- await import_promises12.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
65075
+ await import_promises14.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64529
65076
  } else {
64530
- await import_promises12.default.writeFile(dest, await entry.async("nodebuffer"));
65077
+ await import_promises14.default.writeFile(dest, await entry.async("nodebuffer"));
64531
65078
  }
64532
65079
  }
64533
- await import_promises12.default.mkdir(deps.extensionsRoot, { recursive: true });
64534
- 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);
64535
65082
  } catch (e) {
64536
- await import_promises12.default.rm(stage, { recursive: true, force: true }).catch(() => {
65083
+ await import_promises14.default.rm(stage, { recursive: true, force: true }).catch(() => {
64537
65084
  });
64538
65085
  throw e;
64539
65086
  }
@@ -64542,9 +65089,9 @@ async function installFromChannel(args, deps) {
64542
65089
  }
64543
65090
 
64544
65091
  // src/extension/update-flow.ts
64545
- var import_promises13 = __toESM(require("fs/promises"), 1);
64546
- var import_node_path65 = __toESM(require("path"), 1);
64547
- 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);
64548
65095
  var import_node_crypto19 = __toESM(require("crypto"), 1);
64549
65096
  var import_jszip4 = __toESM(require_lib3(), 1);
64550
65097
  var UpdateError = class extends Error {
@@ -64560,11 +65107,11 @@ async function updateFromChannel(args, deps) {
64560
65107
  channelRef.extId,
64561
65108
  channelRef.ownerPrincipalId
64562
65109
  );
64563
- const liveDir = import_node_path65.default.join(deps.extensionsRoot, localExtId);
65110
+ const liveDir = import_node_path67.default.join(deps.extensionsRoot, localExtId);
64564
65111
  const prevDir = `${liveDir}.prev`;
64565
65112
  let existingVersion;
64566
65113
  try {
64567
- 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");
64568
65115
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
64569
65116
  if (!parsed2.success) {
64570
65117
  throw new UpdateError(
@@ -64597,7 +65144,7 @@ async function updateFromChannel(args, deps) {
64597
65144
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
64598
65145
  }
64599
65146
  for (const name of Object.keys(zip.files)) {
64600
- if (name.includes("..") || name.startsWith("/") || import_node_path65.default.isAbsolute(name)) {
65147
+ if (name.includes("..") || name.startsWith("/") || import_node_path67.default.isAbsolute(name)) {
64601
65148
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
64602
65149
  }
64603
65150
  }
@@ -64629,31 +65176,31 @@ async function updateFromChannel(args, deps) {
64629
65176
  );
64630
65177
  }
64631
65178
  await deps.runtime.close(localExtId);
64632
- await import_promises13.default.rm(prevDir, { recursive: true, force: true });
64633
- await import_promises13.default.rename(liveDir, prevDir);
64634
- const stage = await import_promises13.default.mkdtemp(
64635
- 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}-`)
64636
65183
  );
64637
65184
  try {
64638
65185
  for (const [name, entry] of Object.entries(zip.files)) {
64639
- const dest = import_node_path65.default.join(stage, name);
65186
+ const dest = import_node_path67.default.join(stage, name);
64640
65187
  if (entry.dir) {
64641
- await import_promises13.default.mkdir(dest, { recursive: true });
65188
+ await import_promises15.default.mkdir(dest, { recursive: true });
64642
65189
  continue;
64643
65190
  }
64644
- 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 });
64645
65192
  if (name === "manifest.json") {
64646
65193
  const rewritten = { ...parsed.data, id: localExtId };
64647
- await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
65194
+ await import_promises15.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64648
65195
  } else {
64649
- await import_promises13.default.writeFile(dest, await entry.async("nodebuffer"));
65196
+ await import_promises15.default.writeFile(dest, await entry.async("nodebuffer"));
64650
65197
  }
64651
65198
  }
64652
- await import_promises13.default.rename(stage, liveDir);
65199
+ await import_promises15.default.rename(stage, liveDir);
64653
65200
  } catch (e) {
64654
- await import_promises13.default.rm(stage, { recursive: true, force: true }).catch(() => {
65201
+ await import_promises15.default.rm(stage, { recursive: true, force: true }).catch(() => {
64655
65202
  });
64656
- await import_promises13.default.rename(prevDir, liveDir).catch(() => {
65203
+ await import_promises15.default.rename(prevDir, liveDir).catch(() => {
64657
65204
  });
64658
65205
  await deps.runtime.open(localExtId).catch(() => {
64659
65206
  });
@@ -64675,7 +65222,7 @@ async function updateFromChannel(args, deps) {
64675
65222
  reason: e.message
64676
65223
  };
64677
65224
  }
64678
- await import_promises13.default.rm(prevDir, { recursive: true, force: true });
65225
+ await import_promises15.default.rm(prevDir, { recursive: true, force: true });
64679
65226
  return {
64680
65227
  kind: "updated",
64681
65228
  extId: localExtId,
@@ -64683,9 +65230,9 @@ async function updateFromChannel(args, deps) {
64683
65230
  };
64684
65231
  }
64685
65232
  async function rollback(deps, localExtId, liveDir, prevDir) {
64686
- await import_promises13.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
65233
+ await import_promises15.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
64687
65234
  });
64688
- await import_promises13.default.rename(prevDir, liveDir).catch(() => {
65235
+ await import_promises15.default.rename(prevDir, liveDir).catch(() => {
64689
65236
  });
64690
65237
  await deps.runtime.open(localExtId).catch(() => {
64691
65238
  });
@@ -64708,18 +65255,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
64708
65255
  );
64709
65256
  }
64710
65257
  }
64711
- const manifestPath = import_node_path66.default.join(root, extId, "manifest.json");
65258
+ const manifestPath = import_node_path68.default.join(root, extId, "manifest.json");
64712
65259
  const manifest = await readManifest(root, extId);
64713
65260
  const next = { ...manifest, version: newVersion };
64714
65261
  const tmp = `${manifestPath}.tmp`;
64715
- await import_promises14.default.writeFile(tmp, JSON.stringify(next, null, 2));
64716
- 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);
64717
65264
  }
64718
65265
  async function readManifest(root, extId) {
64719
- const file = import_node_path66.default.join(root, extId, "manifest.json");
65266
+ const file = import_node_path68.default.join(root, extId, "manifest.json");
64720
65267
  let raw;
64721
65268
  try {
64722
- raw = await import_promises14.default.readFile(file, "utf8");
65269
+ raw = await import_promises16.default.readFile(file, "utf8");
64723
65270
  } catch (e) {
64724
65271
  if (e.code === "ENOENT") {
64725
65272
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -64800,7 +65347,7 @@ function buildExtensionHandlers(deps) {
64800
65347
  };
64801
65348
  async function buildSnapshotMeta(extId) {
64802
65349
  const manifest = await readManifest(deps.root, extId);
64803
- 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));
64804
65351
  return { manifest, contentHash: sha256, buffer };
64805
65352
  }
64806
65353
  const publish = async (frame, _client, ctx) => {
@@ -64975,7 +65522,7 @@ function buildExtensionHandlers(deps) {
64975
65522
  }
64976
65523
 
64977
65524
  // src/app-builder/kill-port.ts
64978
- var import_node_child_process15 = require("child_process");
65525
+ var import_node_child_process16 = require("child_process");
64979
65526
  async function killPortOccupants(port, ownedPids, logger) {
64980
65527
  let pids;
64981
65528
  try {
@@ -65017,7 +65564,7 @@ async function killPortOccupants(port, ownedPids, logger) {
65017
65564
  }
65018
65565
  function listPidsOnPort(port) {
65019
65566
  return new Promise((resolve9, reject) => {
65020
- (0, import_node_child_process15.execFile)(
65567
+ (0, import_node_child_process16.execFile)(
65021
65568
  "lsof",
65022
65569
  ["-ti", `:${port}`],
65023
65570
  { timeout: 3e3 },
@@ -65043,7 +65590,7 @@ var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
65043
65590
 
65044
65591
  // src/handlers/app-builder.ts
65045
65592
  init_protocol();
65046
- var import_node_path67 = require("path");
65593
+ var import_node_path69 = require("path");
65047
65594
  var import_node_fs52 = require("fs");
65048
65595
  var DEFAULT_TEMPLATE = "nestjs-react";
65049
65596
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -65190,13 +65737,13 @@ function buildAppBuilderHandlers(deps) {
65190
65737
  const created = await deps.createProjectOnDisk({
65191
65738
  store: userStore,
65192
65739
  name: f.name,
65193
- templateSrcDir: (0, import_node_path67.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
65194
- 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"),
65195
65742
  reservedPorts,
65196
65743
  // 凭据只进 scaffold 子进程的 env,且**只给这个 persona 的 kit 模板声明要的那几个变量**
65197
65744
  // (M1b Step 5)。整表塞进去粒度只到「进程」——那会把 service-role key 交给一个用不到
65198
65745
  // 它的脚本。new-extension.sh 用它把模板的 `${VAR}` 渲成项目可跑的 server/.env。
65199
- 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")),
65200
65747
  ...deps.logger ? { logger: deps.logger } : {}
65201
65748
  });
65202
65749
  project = created.project;
@@ -65395,7 +65942,7 @@ function buildAppBuilderHandlers(deps) {
65395
65942
  await userStore.clearPublishJob(args.name);
65396
65943
  }
65397
65944
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
65398
- 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");
65399
65946
  deps.logger?.info("app-builder.publish.start", {
65400
65947
  name: args.name,
65401
65948
  sessionId: boundSession.sessionId,
@@ -65411,7 +65958,7 @@ function buildAppBuilderHandlers(deps) {
65411
65958
  // 凭据只进 publish.sh 这个子进程的 env,且只给它的 kit 模板声明要的那几个变量
65412
65959
  // (M1b Step 5)。那个进程里跑着 `eval "$BUILD_CMD"`——项目自带的构建命令会继承这份
65413
65960
  // env,多给一个变量就是多交一个凭据给它。personaRoot 上面已按绑定 session 的 persona 解析。
65414
- 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")),
65415
65962
  hooks: {
65416
65963
  // 元数据每次写盘(publishJob 起落 / prodUrl 回填)后重推一帧:UI 渲染 PublishProgress
65417
65964
  // 三段 checklist 依赖 project.publishJob.status==='in-flight',而 publishJob 字段只有
@@ -65819,7 +66366,7 @@ function buildTopicHandlers(deps) {
65819
66366
  init_protocol();
65820
66367
 
65821
66368
  // src/channel/authority.ts
65822
- var import_promises15 = __toESM(require("fs/promises"), 1);
66369
+ var import_promises17 = __toESM(require("fs/promises"), 1);
65823
66370
  init_protocol();
65824
66371
  var DEFAULT_AUTHORITY_RULES = [
65825
66372
  { id: "outbound-message", desc: "\u4EE5\u8001\u677F\u540D\u4E49\u7ED9\u5176\u4ED6\u4EBA\u53D1\u6D88\u606F\uFF08IM/\u90AE\u4EF6\uFF09", action: "ask" },
@@ -65837,7 +66384,7 @@ async function resolveAuthority(args) {
65837
66384
  let source;
65838
66385
  let raw = null;
65839
66386
  try {
65840
- raw = await import_promises15.default.readFile(args.tablePath, "utf8");
66387
+ raw = await import_promises17.default.readFile(args.tablePath, "utf8");
65841
66388
  } catch (e) {
65842
66389
  if (e.code !== "ENOENT") {
65843
66390
  return askBecause(`\u6388\u6743\u8BBE\u5B9A\u8BFB\u4E0D\u51FA\u6765\uFF08${args.tablePath}\uFF09\uFF1A${e.message}`);
@@ -66146,12 +66693,12 @@ function buildVisitorHandlers(deps) {
66146
66693
  }
66147
66694
 
66148
66695
  // src/extension/registry.ts
66149
- var import_promises16 = __toESM(require("fs/promises"), 1);
66150
- 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);
66151
66698
  async function loadAll(root) {
66152
66699
  let entries;
66153
66700
  try {
66154
- entries = await import_promises16.default.readdir(root, { withFileTypes: true });
66701
+ entries = await import_promises18.default.readdir(root, { withFileTypes: true });
66155
66702
  } catch (e) {
66156
66703
  if (e.code === "ENOENT") return [];
66157
66704
  throw e;
@@ -66160,16 +66707,16 @@ async function loadAll(root) {
66160
66707
  for (const ent of entries) {
66161
66708
  if (!ent.isDirectory()) continue;
66162
66709
  if (ent.name.startsWith(".")) continue;
66163
- 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));
66164
66711
  }
66165
66712
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
66166
66713
  return records;
66167
66714
  }
66168
66715
  async function loadOne(dir, dirName) {
66169
- const manifestPath = import_node_path68.default.join(dir, "manifest.json");
66716
+ const manifestPath = import_node_path70.default.join(dir, "manifest.json");
66170
66717
  let raw;
66171
66718
  try {
66172
- raw = await import_promises16.default.readFile(manifestPath, "utf8");
66719
+ raw = await import_promises18.default.readFile(manifestPath, "utf8");
66173
66720
  } catch {
66174
66721
  return {
66175
66722
  extId: dirName,
@@ -66210,8 +66757,8 @@ async function loadOne(dir, dirName) {
66210
66757
  }
66211
66758
 
66212
66759
  // src/extension/uninstall.ts
66213
- var import_promises17 = __toESM(require("fs/promises"), 1);
66214
- 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);
66215
66762
  var UninstallError = class extends Error {
66216
66763
  constructor(code, message) {
66217
66764
  super(message);
@@ -66220,14 +66767,14 @@ var UninstallError = class extends Error {
66220
66767
  code;
66221
66768
  };
66222
66769
  async function uninstall(deps) {
66223
- const dir = import_node_path69.default.join(deps.root, deps.extId);
66770
+ const dir = import_node_path71.default.join(deps.root, deps.extId);
66224
66771
  try {
66225
- await import_promises17.default.access(dir);
66772
+ await import_promises19.default.access(dir);
66226
66773
  } catch {
66227
66774
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
66228
66775
  }
66229
66776
  await deps.runtime.close(deps.extId);
66230
- await import_promises17.default.rm(dir, { recursive: true, force: true });
66777
+ await import_promises19.default.rm(dir, { recursive: true, force: true });
66231
66778
  }
66232
66779
 
66233
66780
  // src/handlers/index.ts
@@ -66237,15 +66784,15 @@ var import_node_crypto20 = require("crypto");
66237
66784
  init_protocol();
66238
66785
 
66239
66786
  // src/peer-ops/run-command.ts
66240
- var import_node_child_process16 = require("child_process");
66241
- 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);
66242
66789
  var DEFAULT_TIMEOUT_MS5 = 3e4;
66243
66790
  var MAX_TIMEOUT_MS = 3e5;
66244
66791
  var MAX_OUTPUT_BYTES = 1048576;
66245
66792
  function runCommand(command, opts = {}) {
66246
66793
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
66247
66794
  return new Promise((resolve9) => {
66248
- 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() });
66249
66796
  const out = [];
66250
66797
  const err = [];
66251
66798
  let outBytes = 0;
@@ -66456,7 +67003,7 @@ function buildMethodHandlers(deps) {
66456
67003
  broadcast: deps.broadcastToOwners
66457
67004
  }),
66458
67005
  ...buildMasterHandlers({
66459
- authorityTablePath: import_node_path70.default.join(deps.masterDataDir, "master-authority.json")
67006
+ authorityTablePath: import_node_path72.default.join(deps.masterDataDir, "master-authority.json")
66460
67007
  }),
66461
67008
  ...buildTopicHandlers({
66462
67009
  topicStore: deps.topicStore,
@@ -66487,23 +67034,23 @@ function buildMethodHandlers(deps) {
66487
67034
  init_protocol();
66488
67035
 
66489
67036
  // src/tools/version-probe.ts
66490
- var import_node_child_process18 = require("child_process");
67037
+ var import_node_child_process19 = require("child_process");
66491
67038
  init_claude();
66492
67039
 
66493
67040
  // src/tools/shell-path.ts
66494
- var import_node_child_process17 = require("child_process");
66495
- 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);
66496
67043
  function refreshPathFromLoginShell() {
66497
67044
  if (process.platform === "win32") return;
66498
- 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";
66499
67046
  try {
66500
- 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"'], {
66501
67048
  encoding: "utf8",
66502
67049
  timeout: 3e3,
66503
67050
  stdio: ["ignore", "pipe", "ignore"]
66504
67051
  });
66505
- const path96 = out.trim();
66506
- if (path96) process.env.PATH = path96;
67052
+ const path98 = out.trim();
67053
+ if (path98) process.env.PATH = path98;
66507
67054
  } catch {
66508
67055
  }
66509
67056
  }
@@ -66514,7 +67061,7 @@ function parseVersionOutput(out) {
66514
67061
  }
66515
67062
  function execVersion(bin) {
66516
67063
  return new Promise((resolve9, reject) => {
66517
- (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) => {
66518
67065
  if (err) reject(err);
66519
67066
  else resolve9(String(stdout));
66520
67067
  });
@@ -66628,8 +67175,8 @@ function buildOnboardingHandlers(deps) {
66628
67175
 
66629
67176
  // src/app-builder-plugin/project-store.ts
66630
67177
  var import_node_fs53 = require("fs");
66631
- var import_node_child_process19 = require("child_process");
66632
- var import_node_path71 = require("path");
67178
+ var import_node_child_process20 = require("child_process");
67179
+ var import_node_path73 = require("path");
66633
67180
  init_protocol();
66634
67181
  var PROJECTS_DIR = "projects";
66635
67182
  var META_FILE = ".clawd-project.json";
@@ -66659,14 +67206,14 @@ var ProjectStore = class {
66659
67206
  }
66660
67207
  /** projects/<name>/.clawd-project.json 路径 */
66661
67208
  metaPath(name) {
66662
- return (0, import_node_path71.join)(this.projectsRoot(), name, META_FILE);
67209
+ return (0, import_node_path73.join)(this.projectsRoot(), name, META_FILE);
66663
67210
  }
66664
67211
  /** projects/<name>/ 目录路径(cwd 用) */
66665
67212
  projectDir(name) {
66666
- return (0, import_node_path71.join)(this.projectsRoot(), name);
67213
+ return (0, import_node_path73.join)(this.projectsRoot(), name);
66667
67214
  }
66668
67215
  projectsRoot() {
66669
- return (0, import_node_path71.join)(this.root, PROJECTS_DIR);
67216
+ return (0, import_node_path73.join)(this.root, PROJECTS_DIR);
66670
67217
  }
66671
67218
  async list() {
66672
67219
  let entries;
@@ -66749,7 +67296,7 @@ var ProjectStore = class {
66749
67296
  async scaffold(name, templateSrcDir, scaffoldScriptPath, extraEnv) {
66750
67297
  const destDir = this.projectDir(name);
66751
67298
  return await new Promise((resolve9, reject) => {
66752
- 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], {
66753
67300
  // extraEnv 排在 PATH **之前**:凭据表里若混进一条名叫 PATH 的条目,顶掉 PATH 会让
66754
67301
  // 脚本以「命令找不到」的形态崩在离现场很远的地方。
66755
67302
  env: { ...process.env, ...extraEnv ?? {}, PATH: process.env.PATH ?? "" },
@@ -66863,7 +67410,7 @@ var ProjectStore = class {
66863
67410
  };
66864
67411
 
66865
67412
  // src/app-builder/dev-server-supervisor.ts
66866
- var import_node_child_process20 = require("child_process");
67413
+ var import_node_child_process21 = require("child_process");
66867
67414
  var import_node_events2 = require("events");
66868
67415
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
66869
67416
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -66900,7 +67447,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
66900
67447
  tunnelHost: args.tunnelHost,
66901
67448
  devCommand: cmd
66902
67449
  });
66903
- const child = (0, import_node_child_process20.spawn)("sh", ["-c", cmd], {
67450
+ const child = (0, import_node_child_process21.spawn)("sh", ["-c", cmd], {
66904
67451
  cwd: args.cwd,
66905
67452
  env,
66906
67453
  stdio: "pipe",
@@ -67116,6 +67663,9 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
67116
67663
  }
67117
67664
  };
67118
67665
 
67666
+ // src/app-builder-plugin/core.ts
67667
+ var import_node_child_process23 = require("child_process");
67668
+
67119
67669
  // src/app-builder-plugin/publish-registry.ts
67120
67670
  var import_node_crypto21 = require("crypto");
67121
67671
  var PublishJobRegistry = class {
@@ -67167,9 +67717,9 @@ var PublishJobRegistry = class {
67167
67717
  };
67168
67718
 
67169
67719
  // src/app-builder-plugin/publish-job-runner.ts
67170
- var import_node_child_process21 = require("child_process");
67720
+ var import_node_child_process22 = require("child_process");
67171
67721
  var import_node_fs54 = require("fs");
67172
- var import_node_path72 = require("path");
67722
+ var import_node_path74 = require("path");
67173
67723
 
67174
67724
  // src/app-builder-plugin/publish-stage-parser.ts
67175
67725
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -67196,19 +67746,19 @@ function tailStderrLines(buf, n) {
67196
67746
  // src/app-builder-plugin/publish-job-runner.ts
67197
67747
  async function startPublishJob(deps, args) {
67198
67748
  const { registry: registry2, projectDir } = deps;
67199
- const spawn13 = deps.spawnImpl ?? import_node_child_process21.spawn;
67749
+ const spawn14 = deps.spawnImpl ?? import_node_child_process22.spawn;
67200
67750
  if (registry2.has(args.name)) {
67201
67751
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
67202
67752
  }
67203
67753
  const projDir = projectDir(args.name);
67204
- const logPath = (0, import_node_path72.join)(projDir, ".publish.log");
67754
+ const logPath = (0, import_node_path74.join)(projDir, ".publish.log");
67205
67755
  let logStream = null;
67206
67756
  try {
67207
67757
  logStream = (0, import_node_fs54.createWriteStream)(logPath, { flags: "w" });
67208
67758
  } catch {
67209
67759
  logStream = null;
67210
67760
  }
67211
- const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
67761
+ const child = spawn14("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
67212
67762
  cwd: projDir,
67213
67763
  // 宿主给的 env 覆盖在 process.env 之上:daemon 进程本身没有这些变量(它们只在这一个
67214
67764
  // 子进程里活着)。云上宿主不传 extraEnv,凭据本来就在容器 env 里。
@@ -67538,6 +68088,7 @@ async function createProjectOnDisk(args) {
67538
68088
  }
67539
68089
  return { project, projectDir: store.projectDir(name) };
67540
68090
  }
68091
+ var REMOVE_TIMEOUT_MS = 10 * 6e4;
67541
68092
  async function recoverInterruptedPublishJobs(store, logger) {
67542
68093
  await recoverInterruptedJobs({
67543
68094
  listAllProjects: async () => store.list(),
@@ -67547,9 +68098,9 @@ async function recoverInterruptedPublishJobs(store, logger) {
67547
68098
 
67548
68099
  // src/app-builder-plugin/mcp-config.ts
67549
68100
  var import_node_fs55 = __toESM(require("fs"), 1);
67550
- var import_node_path73 = __toESM(require("path"), 1);
68101
+ var import_node_path75 = __toESM(require("path"), 1);
67551
68102
  function appBuilderMcpConfigPath(dataDir) {
67552
- return import_node_path73.default.join(dataDir, "app-builder.mcp.json");
68103
+ return import_node_path75.default.join(dataDir, "app-builder.mcp.json");
67553
68104
  }
67554
68105
  function writeAppBuilderMcpConfig(args) {
67555
68106
  const cfgPath = appBuilderMcpConfigPath(args.dataDir);
@@ -67563,8 +68114,8 @@ function writeAppBuilderMcpConfig(args) {
67563
68114
  env: {
67564
68115
  CLAWD_DAEMON_TOKEN: args.daemonToken,
67565
68116
  CLAWD_DAEMON_URL: args.daemonUrl,
67566
- CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path73.default.join(args.deployKitScriptsDir, "new-extension.sh"),
67567
- 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"),
67568
68119
  ...args.logPath ? { CLAWD_APP_BUILDER_LOG: args.logPath } : {}
67569
68120
  }
67570
68121
  }
@@ -67611,9 +68162,9 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
67611
68162
  }
67612
68163
 
67613
68164
  // src/extension/runtime.ts
67614
- var import_node_child_process22 = require("child_process");
67615
- var import_node_path74 = __toESM(require("path"), 1);
67616
- 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");
67617
68168
 
67618
68169
  // src/extension/port-allocator.ts
67619
68170
  var import_node_net2 = __toESM(require("net"), 1);
@@ -67713,13 +68264,13 @@ var Runtime = class {
67713
68264
  /\$CLAWOS_EXT_PORT/g,
67714
68265
  String(port)
67715
68266
  );
67716
- const dir = import_node_path74.default.join(this.root, extId);
68267
+ const dir = import_node_path76.default.join(this.root, extId);
67717
68268
  const env = {
67718
68269
  ...process.env,
67719
68270
  CLAWOS_EXT_PORT: String(port),
67720
68271
  CLAWOS_EXT_ID: extId
67721
68272
  };
67722
- const child = (0, import_node_child_process22.spawn)("sh", ["-c", cmd], {
68273
+ const child = (0, import_node_child_process24.spawn)("sh", ["-c", cmd], {
67723
68274
  cwd: dir,
67724
68275
  env,
67725
68276
  stdio: ["ignore", "pipe", "pipe"],
@@ -67789,7 +68340,7 @@ ${handle.stderrTail}`
67789
68340
  if (res.ok) return;
67790
68341
  } catch {
67791
68342
  }
67792
- await (0, import_promises18.setTimeout)(this.healthzIntervalMs);
68343
+ await (0, import_promises20.setTimeout)(this.healthzIntervalMs);
67793
68344
  }
67794
68345
  throw new RuntimeError(
67795
68346
  "HEALTHZ_FAILED",
@@ -67814,7 +68365,7 @@ ${handle.stderrTail}`
67814
68365
  };
67815
68366
  killGroup("SIGTERM");
67816
68367
  const exited = new Promise((resolve9) => child.once("exit", () => resolve9()));
67817
- const timed = (0, import_promises18.setTimeout)(5e3).then(() => "timeout");
68368
+ const timed = (0, import_promises20.setTimeout)(5e3).then(() => "timeout");
67818
68369
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
67819
68370
  if (winner === "timeout" && child.exitCode === null) {
67820
68371
  killGroup("SIGKILL");
@@ -67824,8 +68375,8 @@ ${handle.stderrTail}`
67824
68375
  };
67825
68376
 
67826
68377
  // src/extension/published-channels.ts
67827
- var import_promises19 = __toESM(require("fs/promises"), 1);
67828
- 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);
67829
68380
  init_zod();
67830
68381
  var PublishedChannelsError = class extends Error {
67831
68382
  constructor(code, message) {
@@ -67855,7 +68406,7 @@ var PublishedChannelStore = class {
67855
68406
  this.channels.clear();
67856
68407
  let raw;
67857
68408
  try {
67858
- raw = await import_promises19.default.readFile(this.filePath, "utf8");
68409
+ raw = await import_promises21.default.readFile(this.filePath, "utf8");
67859
68410
  } catch (e) {
67860
68411
  if (e.code === "ENOENT") {
67861
68412
  this.loaded = true;
@@ -67924,15 +68475,15 @@ var PublishedChannelStore = class {
67924
68475
  )
67925
68476
  };
67926
68477
  const tmp = `${this.filePath}.tmp`;
67927
- await import_promises19.default.mkdir(import_node_path75.default.dirname(this.filePath), { recursive: true });
67928
- await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
67929
- 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);
67930
68481
  }
67931
68482
  };
67932
68483
 
67933
68484
  // src/extension/bundle-cache.ts
67934
- var import_promises20 = __toESM(require("fs/promises"), 1);
67935
- 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);
67936
68487
  var BundleCache = class {
67937
68488
  constructor(rootDir) {
67938
68489
  this.rootDir = rootDir;
@@ -67940,17 +68491,17 @@ var BundleCache = class {
67940
68491
  rootDir;
67941
68492
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
67942
68493
  async write(snapshotHash, buffer) {
67943
- await import_promises20.default.mkdir(this.rootDir, { recursive: true });
67944
- 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`);
67945
68496
  const tmp = `${file}.tmp`;
67946
- await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
67947
- 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);
67948
68499
  }
67949
68500
  /** Returns the bundle bytes, or null when the file doesn't exist. */
67950
68501
  async read(snapshotHash) {
67951
- const file = import_node_path76.default.join(this.rootDir, `${snapshotHash}.zip`);
68502
+ const file = import_node_path78.default.join(this.rootDir, `${snapshotHash}.zip`);
67952
68503
  try {
67953
- return await import_promises20.default.readFile(file);
68504
+ return await import_promises22.default.readFile(file);
67954
68505
  } catch (e) {
67955
68506
  if (e.code === "ENOENT") return null;
67956
68507
  throw e;
@@ -67958,8 +68509,8 @@ var BundleCache = class {
67958
68509
  }
67959
68510
  /** Idempotent — missing file is not an error. */
67960
68511
  async delete(snapshotHash) {
67961
- const file = import_node_path76.default.join(this.rootDir, `${snapshotHash}.zip`);
67962
- 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 });
67963
68514
  }
67964
68515
  };
67965
68516
 
@@ -67979,26 +68530,26 @@ async function startDaemon(config) {
67979
68530
  },
67980
68531
  source: "daemon",
67981
68532
  sampling: logShippingCfg.sampling,
67982
- homeDir: import_node_os26.default.homedir()
68533
+ homeDir: import_node_os27.default.homedir()
67983
68534
  });
67984
- const logDir = import_node_path77.default.join(config.dataDir, "log");
68535
+ const logDir = import_node_path79.default.join(config.dataDir, "log");
67985
68536
  import_node_fs56.default.mkdirSync(logDir, { recursive: true });
67986
68537
  const logger = createLogger({
67987
68538
  level: config.logLevel,
67988
- file: import_node_path77.default.join(logDir, "clawd.log"),
68539
+ file: import_node_path79.default.join(logDir, "clawd.log"),
67989
68540
  logClient
67990
68541
  });
67991
68542
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
67992
68543
  const screenIdleProbeLogger = createFileOnlyLogger({
67993
- file: import_node_path77.default.join(logDir, "screen-idle-probe.log"),
68544
+ file: import_node_path79.default.join(logDir, "screen-idle-probe.log"),
67994
68545
  level: "debug"
67995
68546
  });
67996
68547
  logger.info("screen-idle probe logger enabled", {
67997
- file: import_node_path77.default.join(logDir, "screen-idle-probe.log")
68548
+ file: import_node_path79.default.join(logDir, "screen-idle-probe.log")
67998
68549
  });
67999
68550
  const CAP_TARGETS = [
68000
- import_node_path77.default.join(logDir, "clawd.log"),
68001
- 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")
68002
68553
  ];
68003
68554
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
68004
68555
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -68120,8 +68671,8 @@ async function startDaemon(config) {
68120
68671
  const agents = new AgentsScanner();
68121
68672
  const history = new ClaudeHistoryReader();
68122
68673
  let transport = null;
68123
- const personaStore = new PersonaStore(import_node_path77.default.join(config.dataDir, "personas"));
68124
- 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");
68125
68676
  const defaultsRoot = findDefaultsRoot(logger);
68126
68677
  if (defaultsRoot) {
68127
68678
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -68145,7 +68696,7 @@ async function startDaemon(config) {
68145
68696
  retirePersonaBuilder({ store: personaStore, logger });
68146
68697
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
68147
68698
  const dispatchStore = createDispatchStore({
68148
- filePath: import_node_path77.default.join(config.dataDir, "dispatch.json"),
68699
+ filePath: import_node_path79.default.join(config.dataDir, "dispatch.json"),
68149
68700
  now: () => Date.now(),
68150
68701
  onFlushError: (err) => logger.error("dispatch store flush failed", {
68151
68702
  reason: err instanceof Error ? err.message : String(err)
@@ -68154,7 +68705,7 @@ async function startDaemon(config) {
68154
68705
  await dispatchStore.load();
68155
68706
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
68156
68707
  const channelStore = createChannelStore({
68157
- filePath: import_node_path77.default.join(config.dataDir, "channels.json"),
68708
+ filePath: import_node_path79.default.join(config.dataDir, "channels.json"),
68158
68709
  now: () => Date.now(),
68159
68710
  genId: () => `ch-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68160
68711
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -68163,7 +68714,7 @@ async function startDaemon(config) {
68163
68714
  });
68164
68715
  await channelStore.load();
68165
68716
  const topicStore = createTopicStore({
68166
- filePath: import_node_path77.default.join(config.dataDir, "topics.json"),
68717
+ filePath: import_node_path79.default.join(config.dataDir, "topics.json"),
68167
68718
  now: () => Date.now(),
68168
68719
  genId: () => `tp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68169
68720
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -68190,28 +68741,28 @@ async function startDaemon(config) {
68190
68741
  });
68191
68742
  }
68192
68743
  });
68193
- 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));
68194
68745
  const mcpConfigs = [];
68195
68746
  const secretsBundleRoot = findSecretsBundleRoot(logger);
68196
- 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);
68197
68748
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
68198
68749
  const resolvePersonaMcpConfig = (personaId2) => renderPersonaMcpSecrets({
68199
68750
  personaId: personaId2,
68200
- personaDir: import_node_path77.default.join(config.dataDir, "personas", personaId2),
68751
+ personaDir: import_node_path79.default.join(config.dataDir, "personas", personaId2),
68201
68752
  secrets: readSecrets(),
68202
- outDir: import_node_path77.default.join(config.dataDir, "persona-mcp"),
68753
+ outDir: import_node_path79.default.join(config.dataDir, "persona-mcp"),
68203
68754
  logger
68204
68755
  });
68205
68756
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
68206
68757
  const dispatchServerCandidates = [
68207
- import_node_path77.default.join(here, "dispatch", "mcp-server.cjs"),
68758
+ import_node_path79.default.join(here, "dispatch", "mcp-server.cjs"),
68208
68759
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
68209
- import_node_path77.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
68760
+ import_node_path79.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
68210
68761
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
68211
68762
  ];
68212
68763
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68213
68764
  if (dispatchServerScriptPath) {
68214
- 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");
68215
68766
  const dispatchCfgPath = writeDispatchMcpConfig({
68216
68767
  dataDir: config.dataDir,
68217
68768
  serverScriptPath: dispatchServerScriptPath,
@@ -68231,12 +68782,12 @@ async function startDaemon(config) {
68231
68782
  });
68232
68783
  }
68233
68784
  const ticketServerCandidates = [
68234
- import_node_path77.default.join(here, "ticket", "mcp-server.cjs"),
68235
- 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")
68236
68787
  ];
68237
68788
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68238
68789
  if (ticketServerScriptPath) {
68239
- 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");
68240
68791
  const ticketCfgPath = writeTicketMcpConfig({
68241
68792
  dataDir: config.dataDir,
68242
68793
  serverScriptPath: ticketServerScriptPath,
@@ -68258,12 +68809,12 @@ async function startDaemon(config) {
68258
68809
  });
68259
68810
  }
68260
68811
  const shiftServerCandidates = [
68261
- import_node_path77.default.join(here, "shift", "mcp-server.cjs"),
68262
- 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")
68263
68814
  ];
68264
68815
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68265
68816
  if (shiftServerScriptPath) {
68266
- 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");
68267
68818
  const shiftCfgPath = await writeShiftMcpConfig({
68268
68819
  dataDir: config.dataDir,
68269
68820
  serverScriptPath: shiftServerScriptPath,
@@ -68284,12 +68835,12 @@ async function startDaemon(config) {
68284
68835
  );
68285
68836
  }
68286
68837
  const inboxServerCandidates = [
68287
- import_node_path77.default.join(here, "inbox", "mcp-server.cjs"),
68288
- 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")
68289
68840
  ];
68290
68841
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68291
68842
  if (inboxServerScriptPath) {
68292
- 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");
68293
68844
  const inboxCfgPath = await writeInboxMcpConfig({
68294
68845
  dataDir: config.dataDir,
68295
68846
  serverScriptPath: inboxServerScriptPath,
@@ -68310,8 +68861,8 @@ async function startDaemon(config) {
68310
68861
  );
68311
68862
  }
68312
68863
  const peerOpsServerCandidates = [
68313
- import_node_path77.default.join(here, "peer-ops", "mcp-server.cjs"),
68314
- 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")
68315
68866
  ];
68316
68867
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68317
68868
  if (peerOpsServerScriptPath) {
@@ -68333,12 +68884,12 @@ async function startDaemon(config) {
68333
68884
  );
68334
68885
  }
68335
68886
  const rpcToolServerCandidates = [
68336
- import_node_path77.default.join(here, "rpc-tool", "mcp-server.cjs"),
68337
- 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")
68338
68889
  ];
68339
68890
  const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68340
68891
  if (rpcToolServerScriptPath) {
68341
- 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");
68342
68893
  const rpcToolCfgPath = writeRpcToolMcpConfig({
68343
68894
  dataDir: config.dataDir,
68344
68895
  serverScriptPath: rpcToolServerScriptPath,
@@ -68359,18 +68910,18 @@ async function startDaemon(config) {
68359
68910
  );
68360
68911
  }
68361
68912
  const appBuilderServerCandidates = [
68362
- import_node_path77.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
68363
- 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")
68364
68915
  ];
68365
68916
  const appBuilderServerScriptPath = appBuilderServerCandidates.find((p2) => import_node_fs56.default.existsSync(p2));
68366
68917
  if (appBuilderServerScriptPath) {
68367
- 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");
68368
68919
  const appBuilderCfgPath = writeAppBuilderMcpConfig({
68369
68920
  dataDir: config.dataDir,
68370
68921
  serverScriptPath: appBuilderServerScriptPath,
68371
68922
  daemonToken: resolvedAuthToken,
68372
68923
  daemonUrl: mcpDaemonUrl,
68373
- deployKitScriptsDir: import_node_path77.default.join(config.dataDir, "deploy-kit", "scripts"),
68924
+ deployKitScriptsDir: import_node_path79.default.join(config.dataDir, "deploy-kit", "scripts"),
68374
68925
  logPath: appBuilderLogPath
68375
68926
  });
68376
68927
  mcpConfigs.push({ id: "app-builder", path: appBuilderCfgPath, personas: APP_BUILDER_PERSONAS });
@@ -68386,7 +68937,7 @@ async function startDaemon(config) {
68386
68937
  );
68387
68938
  }
68388
68939
  const shiftStore = createShiftStore({
68389
- filePath: import_node_path77.default.join(config.dataDir, "shift.json"),
68940
+ filePath: import_node_path79.default.join(config.dataDir, "shift.json"),
68390
68941
  ownerIdProvider: () => ownerPrincipalId,
68391
68942
  now: () => Date.now()
68392
68943
  });
@@ -68408,7 +68959,7 @@ async function startDaemon(config) {
68408
68959
  getAdapter,
68409
68960
  historyReader: history,
68410
68961
  dataDir: config.dataDir,
68411
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
68962
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68412
68963
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
68413
68964
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
68414
68965
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -68465,7 +69016,7 @@ async function startDaemon(config) {
68465
69016
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
68466
69017
  attachmentGroup: {
68467
69018
  onFileEdit: (input) => {
68468
- 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);
68469
69020
  let size = 0;
68470
69021
  try {
68471
69022
  size = import_node_fs56.default.statSync(absPath).size;
@@ -68498,9 +69049,9 @@ async function startDaemon(config) {
68498
69049
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
68499
69050
  }
68500
69051
  const projectsStore = new ProjectsStore({
68501
- file: import_node_path77.default.join(config.dataDir, "projects.json"),
69052
+ file: import_node_path79.default.join(config.dataDir, "projects.json"),
68502
69053
  clawdDir: config.dataDir,
68503
- 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"),
68504
69055
  logger
68505
69056
  });
68506
69057
  const observer = new SessionObserver({
@@ -68560,12 +69111,12 @@ async function startDaemon(config) {
68560
69111
  screenIdleProbeLogger
68561
69112
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
68562
69113
  registerAdapter("claude", claudeAdapter);
68563
- const codexIsolatedHome = import_node_path77.default.join(config.dataDir, "codex-home");
69114
+ const codexIsolatedHome = import_node_path79.default.join(config.dataDir, "codex-home");
68564
69115
  try {
68565
69116
  import_node_fs56.default.mkdirSync(codexIsolatedHome, { recursive: true });
68566
69117
  for (const f of ["auth.json", "config.toml"]) {
68567
- const link = import_node_path77.default.join(codexIsolatedHome, f);
68568
- 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);
68569
69120
  if (!import_node_fs56.default.existsSync(link) && import_node_fs56.default.existsSync(target)) import_node_fs56.default.symlinkSync(target, link);
68570
69121
  }
68571
69122
  } catch (err) {
@@ -68579,11 +69130,11 @@ async function startDaemon(config) {
68579
69130
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
68580
69131
  codexHomeFor: (cwd) => resolveCodexHome({
68581
69132
  cwd,
68582
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69133
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68583
69134
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
68584
69135
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
68585
69136
  projectPaths: projectsStore.listMerged().map((x) => x.path),
68586
- 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"),
68587
69138
  isolatedHome: codexIsolatedHome
68588
69139
  })
68589
69140
  })
@@ -68868,11 +69419,11 @@ async function startDaemon(config) {
68868
69419
  // 'persona/<pid>/owner',default 走 'default'。
68869
69420
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
68870
69421
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
68871
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69422
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68872
69423
  usersRoot
68873
69424
  },
68874
69425
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
68875
- personaRoot: import_node_path77.default.join(config.dataDir, "personas"),
69426
+ personaRoot: import_node_path79.default.join(config.dataDir, "personas"),
68876
69427
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
68877
69428
  usersRoot,
68878
69429
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -68973,11 +69524,11 @@ async function startDaemon(config) {
68973
69524
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
68974
69525
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
68975
69526
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
68976
- 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"),
68977
69528
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
68978
- deployKitRoot: import_node_path77.default.join(config.dataDir, "deploy-kit"),
69529
+ deployKitRoot: import_node_path79.default.join(config.dataDir, "deploy-kit"),
68979
69530
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
68980
- resolvePersonaRoot: (personaId2) => import_node_path77.default.join(config.dataDir, "personas", personaId2),
69531
+ resolvePersonaRoot: (personaId2) => import_node_path79.default.join(config.dataDir, "personas", personaId2),
68981
69532
  // 凭据表(M1b Step 5):与 MCP 那条同一张表、同一个来源,只是交付给另一个子进程。
68982
69533
  readSecrets,
68983
69534
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
@@ -69034,7 +69585,7 @@ async function startDaemon(config) {
69034
69585
  sourceSessionId: args.sourceSessionId
69035
69586
  });
69036
69587
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
69037
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os26.default.homedir());
69588
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os27.default.homedir());
69038
69589
  logger.info("dispatch.spawnB.source-resolved", {
69039
69590
  dispatchId: args.dispatchId,
69040
69591
  sourceJsonlPath,
@@ -69092,12 +69643,12 @@ async function startDaemon(config) {
69092
69643
  });
69093
69644
  Object.assign(handlers, shiftHandlers);
69094
69645
  const deployReceipts = createReceiptStore({
69095
- filePath: import_node_path77.default.join(config.dataDir, "deploy.json"),
69646
+ filePath: import_node_path79.default.join(config.dataDir, "deploy.json"),
69096
69647
  now: () => Date.now(),
69097
69648
  onFlushError: (err) => logger.error("deploy receipts flush failed", { error: String(err) })
69098
69649
  });
69099
69650
  const deploySecrets = createSecretStore({
69100
- filePath: import_node_path77.default.join(config.dataDir, "deploy-secrets.json"),
69651
+ filePath: import_node_path79.default.join(config.dataDir, "deploy-secrets.json"),
69101
69652
  now: () => Date.now(),
69102
69653
  onFlushError: (err) => logger.error("deploy secrets flush failed", { error: String(err) })
69103
69654
  });
@@ -69105,13 +69656,72 @@ async function startDaemon(config) {
69105
69656
  await deploySecrets.load();
69106
69657
  const interrupted = reconcileInterruptedScans(deployReceipts);
69107
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
+ }
69108
69718
  const deployHandlers = buildDeployHandlers({
69109
69719
  receipts: deployReceipts,
69110
69720
  secrets: deploySecrets,
69111
69721
  hasPersona: (personaId2) => personaStore.has(personaId2),
69112
69722
  startScan: (deployId, personaId2) => {
69113
69723
  const assetLines = SCANNABLE_ASSETS.map(
69114
- (name) => ` - ${name}\uFF1A${import_node_path77.default.join(config.dataDir, name)}`
69724
+ (name) => ` - ${name}\uFF1A${import_node_path79.default.join(config.dataDir, name)}`
69115
69725
  ).join("\n");
69116
69726
  const prompt = [
69117
69727
  `\u626B\u63CF persona\u300C${personaId2}\u300D\u7684\u90E8\u7F72\u73AF\u5883\uFF0CdeployId=${deployId}\u3002`,
@@ -69139,6 +69749,30 @@ async function startDaemon(config) {
69139
69749
  });
69140
69750
  return handle.sessionId;
69141
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
+ },
69142
69776
  genId: () => `dp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
69143
69777
  now: () => Date.now()
69144
69778
  });
@@ -69152,7 +69786,7 @@ async function startDaemon(config) {
69152
69786
  });
69153
69787
  shiftScheduler.start();
69154
69788
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
69155
- const larkBotStore = createLarkBotBindingStore(import_node_path77.default.join(config.dataDir, "personas"));
69789
+ const larkBotStore = createLarkBotBindingStore(import_node_path79.default.join(config.dataDir, "personas"));
69156
69790
  const larkBotCloud = createLarkBotCloudClient({
69157
69791
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
69158
69792
  apiKey: resolveClawdTicketsApiKey(),
@@ -69166,7 +69800,7 @@ async function startDaemon(config) {
69166
69800
  store: larkBotStore,
69167
69801
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
69168
69802
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
69169
- 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"),
69170
69804
  isShuttingDown: () => larkDraining,
69171
69805
  logger: {
69172
69806
  warn: (msg) => logger.warn(msg),
@@ -69471,8 +70105,8 @@ async function startDaemon(config) {
69471
70105
  const lines = [
69472
70106
  `Tunnel: ${r.url}`,
69473
70107
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
69474
- `Frpc config: ${import_node_path77.default.join(config.dataDir, "frpc.toml")}`,
69475
- `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")}`
69476
70110
  ];
69477
70111
  const width2 = Math.max(...lines.map((l) => l.length));
69478
70112
  const bar = "\u2550".repeat(width2 + 4);
@@ -69485,7 +70119,7 @@ ${bar}
69485
70119
 
69486
70120
  `);
69487
70121
  try {
69488
- const connectPath = import_node_path77.default.join(config.dataDir, "connect.txt");
70122
+ const connectPath = import_node_path79.default.join(config.dataDir, "connect.txt");
69489
70123
  import_node_fs56.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
69490
70124
  } catch {
69491
70125
  }
@@ -69575,7 +70209,7 @@ ${bar}
69575
70209
  };
69576
70210
  }
69577
70211
  function migrateDropPersonsDir(dataDir) {
69578
- const dir = import_node_path77.default.join(dataDir, "persons");
70212
+ const dir = import_node_path79.default.join(dataDir, "persons");
69579
70213
  try {
69580
70214
  import_node_fs56.default.rmSync(dir, { recursive: true, force: true });
69581
70215
  } catch {