@clawos-dev/clawd 0.2.445 → 0.2.446

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: path91, errorMaps, issueData } = params;
454
- const fullPath = [...path91, ...issueData.path || []];
453
+ const { data, path: path93, errorMaps, issueData } = params;
454
+ const fullPath = [...path93, ...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, path91, key) {
765
+ constructor(parent, value, path93, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path91;
769
+ this._path = path93;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -5950,6 +5950,187 @@ var init_contact_handshake = __esm({
5950
5950
  }
5951
5951
  });
5952
5952
 
5953
+ // ../protocol/src/environment-schemas.ts
5954
+ var EnvCliSchema, EnvSecretSchema, EnvAssetSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
5955
+ var init_environment_schemas = __esm({
5956
+ "../protocol/src/environment-schemas.ts"() {
5957
+ "use strict";
5958
+ init_zod();
5959
+ EnvCliSchema = external_exports.object({
5960
+ // 可执行文件名,装配后要能在 PATH 里直接调到('aliyun' / 's' / 'pnpm' / 'python3')
5961
+ name: external_exports.string().min(1),
5962
+ /**
5963
+ * 从哪装,约定 `<kind>:<ref>`:`npm:@serverless-devs/s` / `github:aliyun/aliyun-cli` /
5964
+ * `apt:python3`。
5965
+ *
5966
+ * **不是装饰字段,是构建器的必需输入**:可执行名往往推不出安装源——Serverless Devs 的命令
5967
+ * 就叫单个字母 `s`,没人能从 's' 猜到要 `npm i -g @serverless-devs/s`;`aliyun` 也不在
5968
+ * apt 源里,得从 GitHub release 拉 tarball。扫描器读 ensure-toolchain.sh 的时候本来就看见
5969
+ * 了这些,顺手带出来即可。
5970
+ *
5971
+ * 它同时解决人的阅读问题:单据上只写一个 `s`,看的人不知道那是什么东西。
5972
+ *
5973
+ * 允许缺省:扫描器拿不准安装源时不该编一个(编错了构建期才炸,还查不出来源)。缺省时构建
5974
+ * 器会失败或猜错,试装当场暴露——这跟整体「宁可让试装发现,不要靠猜」的取向一致。
5975
+ *
5976
+ * 只给一个源,不给平台回落链:本地那套 brew → GitHub → npm 的三级兜底是
5977
+ * ensure-toolchain.sh 的事,云上只构一个镜像、一个基础环境,多给反而要求构建器做选择。
5978
+ */
5979
+ from: external_exports.string().optional(),
5980
+ // 精确版本;缺省 = 不挑版本,装配器自选
5981
+ version: external_exports.string().optional(),
5982
+ // 版本下限('20.6' 这种)。与 version 的区别:version 是「就要这个」,min 是「不低于」。
5983
+ // 两者都缺省即完全不约束。
5984
+ min: external_exports.string().optional()
5985
+ });
5986
+ EnvSecretSchema = external_exports.object({
5987
+ // 凭据的命名引用('aliyun-ak' / 'supabase-shared')。部署时按这个名字去解析实际的值。
5988
+ name: external_exports.string().min(1),
5989
+ // 解析出的值注入到哪些环境变量。一份凭据可含多个字段(AK 是 id+secret 两个,
5990
+ // supabase 是 url/anon/service-role/jwt 四个),所以是数组不是单值。
5991
+ env: external_exports.array(external_exports.string().min(1)).min(1)
5992
+ });
5993
+ EnvAssetSchema = external_exports.object({
5994
+ name: external_exports.string().min(1)
5995
+ });
5996
+ MANIFEST_BODY = {
5997
+ clis: external_exports.array(EnvCliSchema),
5998
+ secrets: external_exports.array(EnvSecretSchema),
5999
+ assets: external_exports.array(EnvAssetSchema)
6000
+ };
6001
+ EnvManifestBodySchema = external_exports.object(MANIFEST_BODY);
6002
+ EnvironmentManifestSchema = external_exports.object({
6003
+ // 格式版本。manifest 要跨进程(daemon 扫 → 镜像构建器读)也跨时间(部署记录留档),
6004
+ // 加字段兼容但改语义不兼容,留一个显式版本位。
6005
+ version: external_exports.literal(1),
6006
+ ...MANIFEST_BODY
6007
+ }).strict();
6008
+ EnvEvidenceSchema = external_exports.object({
6009
+ // 这条证据支持的是哪一项:`${kind}:${name}`,如 'cli:aliyun' / 'secret:aliyun-ak'
6010
+ target: external_exports.string().min(1),
6011
+ // 一句人话:为什么需要它 + 从哪看出来的。单据默认显示这句。
6012
+ reason: external_exports.string().min(1),
6013
+ // persona 目录内的相对路径('CLAUDE.md' / '.claude/skills/foo/SKILL.md')
6014
+ file: external_exports.string().min(1),
6015
+ // 原文摘录(一两句即可,不是整段)。默认收起,起疑时才看。
6016
+ //
6017
+ // **自由文本,schema 守不住凭据值**:这里只验得了非空,而 agent 被要求「引原文不要转述」,
6018
+ // 引到 `KEY=值` 那行是迟早的事。落盘前由 daemon 的 deploy/redact.ts 涂抹(reason 同理)。
6019
+ quote: external_exports.string().min(1)
6020
+ });
6021
+ }
6022
+ });
6023
+
6024
+ // ../protocol/src/deploy-schemas.ts
6025
+ var FulfillmentSchema, DeployStatusSchema, DeployGapSchema, DeployReceiptSchema, DeployStartArgsSchema, DeployIdArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, DeploySecretStatusSchema, DeployReceiptViewSchema, DeployListResultSchema;
6026
+ var init_deploy_schemas = __esm({
6027
+ "../protocol/src/deploy-schemas.ts"() {
6028
+ "use strict";
6029
+ init_zod();
6030
+ init_environment_schemas();
6031
+ FulfillmentSchema = external_exports.enum(["deployer", "user"]);
6032
+ DeployStatusSchema = external_exports.enum([
6033
+ "scanning",
6034
+ "scanFailed",
6035
+ "draft",
6036
+ "ready",
6037
+ "trialing",
6038
+ "failed",
6039
+ "deployed"
6040
+ ]);
6041
+ DeployGapSchema = external_exports.object({
6042
+ // agent 的自然语言错因,如「我要解析 aliyun 的 JSON 输出,但容器里没有 python3」
6043
+ errorText: external_exports.string().min(1),
6044
+ // 原始输出片段,给人自己判断用
6045
+ raw: external_exports.string().optional(),
6046
+ // 建议补的依赖:`cli:python3` 这种。拿不准就不给,让人自己决定。
6047
+ suggest: external_exports.string().optional()
6048
+ }).strict();
6049
+ DeployReceiptSchema = external_exports.object({
6050
+ deployId: external_exports.string().min(1),
6051
+ personaId: external_exports.string().min(1),
6052
+ status: DeployStatusSchema,
6053
+ /**
6054
+ * 干这次扫描的 butler 会话 id。单据上「看它怎么干的」入口靠它把工作过程调出来。
6055
+ *
6056
+ * 扫描不是 daemon 里一个闷头跑的黑盒进程,是 persona-butler 的一次真实会话——用户能翻
6057
+ * 看它读了哪些文件、搜了什么。这条也顺带解决「它到底有没有上网查」这类问题:不用另造
6058
+ * 探针去抓证据,看一眼就知道。
6059
+ */
6060
+ scanSessionId: external_exports.string().optional(),
6061
+ // 扫描产物;scanning / scanFailed 时还没有
6062
+ manifest: EnvironmentManifestSchema.optional(),
6063
+ evidence: external_exports.array(EnvEvidenceSchema).optional(),
6064
+ smokeTask: external_exports.string().optional(),
6065
+ notes: external_exports.array(external_exports.string()).default([]),
6066
+ /**
6067
+ * 每条凭据的履约选择:secret name → 'deployer' | 'user'。
6068
+ * **只记「谁出」,不记值。** 没做选择的凭据不在这个 map 里(缺席即未定),
6069
+ * 用缺席而不是 'unset' 枚举值表达未定,省掉一个下游要处处判的第三态。
6070
+ */
6071
+ fulfillment: external_exports.record(external_exports.string(), FulfillmentSchema).default({}),
6072
+ /** 试装失败时的缺口清单;成功或没试装过是空数组 */
6073
+ gaps: external_exports.array(DeployGapSchema).default([]),
6074
+ // 扫描 / 试装失败的原因(status 是 scanFailed / failed 时才有意义)
6075
+ error: external_exports.string().optional(),
6076
+ createdAt: external_exports.number(),
6077
+ updatedAt: external_exports.number()
6078
+ }).strict();
6079
+ DeployStartArgsSchema = external_exports.object({
6080
+ personaId: external_exports.string().min(1)
6081
+ }).strict();
6082
+ DeployIdArgsSchema = external_exports.object({
6083
+ deployId: external_exports.string().min(1)
6084
+ }).strict();
6085
+ DeployPatchArgsSchema = external_exports.object({
6086
+ deployId: external_exports.string().min(1),
6087
+ patch: external_exports.object({
6088
+ fulfillment: external_exports.record(external_exports.string(), FulfillmentSchema).optional(),
6089
+ smokeTask: external_exports.string().min(1).optional(),
6090
+ // 人工补依赖(试装失败后补 python3 这种);整份替换 manifest
6091
+ manifest: EnvironmentManifestSchema.optional()
6092
+ }).strict()
6093
+ }).strict();
6094
+ DeployPutSecretArgsSchema = external_exports.object({
6095
+ deployId: external_exports.string().min(1),
6096
+ // 对应 manifest.secrets[].name
6097
+ name: external_exports.string().min(1),
6098
+ // 环境变量名 → 值。key 必须是该 secret 声明过的 env 之一,handler 校验。
6099
+ values: external_exports.record(external_exports.string(), external_exports.string())
6100
+ }).strict();
6101
+ DeployReportFindingArgsSchema = external_exports.object({
6102
+ deployId: external_exports.string().min(1),
6103
+ kind: external_exports.enum(["cli", "secret", "asset"]),
6104
+ // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
6105
+ item: external_exports.record(external_exports.string(), external_exports.unknown()),
6106
+ // 这条发现的来历(一句人话 + 原文出处),形状同 EnvEvidence,target 由 handler 从 kind+name 派生
6107
+ evidence: external_exports.object({
6108
+ reason: external_exports.string().min(1),
6109
+ file: external_exports.string().min(1),
6110
+ quote: external_exports.string().min(1)
6111
+ })
6112
+ }).strict();
6113
+ DeployFinishScanArgsSchema = external_exports.object({
6114
+ deployId: external_exports.string().min(1),
6115
+ smokeTask: external_exports.string().min(1),
6116
+ notes: external_exports.array(external_exports.string()).default([])
6117
+ }).strict();
6118
+ DeploySecretStatusSchema = external_exports.object({
6119
+ name: external_exports.string(),
6120
+ // 该 secret 声明的 env 里已有值的个数
6121
+ filled: external_exports.number(),
6122
+ total: external_exports.number()
6123
+ }).strict();
6124
+ DeployReceiptViewSchema = external_exports.object({
6125
+ receipt: DeployReceiptSchema,
6126
+ secretStatus: external_exports.array(DeploySecretStatusSchema)
6127
+ }).strict();
6128
+ DeployListResultSchema = external_exports.object({
6129
+ receipts: external_exports.array(DeployReceiptSchema)
6130
+ }).strict();
6131
+ }
6132
+ });
6133
+
5953
6134
  // ../protocol/src/contact-remote-access.ts
5954
6135
  var ContactSetRemoteAccessArgsSchema, ContactSetRemoteAccessOkSchema, ContactRemoteAccessUpdatedFrameSchema;
5955
6136
  var init_contact_remote_access = __esm({
@@ -8410,6 +8591,7 @@ var init_methods = __esm({
8410
8591
  init_esm();
8411
8592
  init_attachment_schemas();
8412
8593
  init_contact_handshake();
8594
+ init_deploy_schemas();
8413
8595
  init_contact_remote_access();
8414
8596
  init_contact();
8415
8597
  init_feishu_auth();
@@ -8613,6 +8795,38 @@ var init_methods = __esm({
8613
8795
  summary: "\u8BFB\u6587\u4EF6\u5185\u5BB9\uFF1Bguest \u8DEF\u5F84\u8FB9\u754C\u4E0E workspace:list \u540C",
8614
8796
  args: WorkspaceReadArgs
8615
8797
  },
8798
+ "deploy:start": {
8799
+ summary: "\u5BF9\u67D0\u4E2A persona \u53D1\u8D77\u4E00\u6B21\u4E0A\u4E91\u90E8\u7F72\uFF1A\u5EFA\u5355\u636E\u5E76**\u5F02\u6B65**\u8D77\u73AF\u5883\u626B\u63CF\u3002\u7ACB\u523B\u8FD4\u56DE scanning \u6001\u5355\u636E\uFF0C\u626B\u63CF\u8981\u8DD1\u51E0\u5206\u949F\u3001\u626B\u5B8C\u7531\u540E\u53F0\u56DE\u5199\uFF1Bowner-only",
8800
+ args: DeployStartArgsSchema
8801
+ },
8802
+ "deploy:list": {
8803
+ summary: "\u5217\u51FA\u5168\u90E8\u90E8\u7F72\u5355\uFF08\u65B0\u7684\u5728\u524D\uFF09\uFF1Bowner-only\u3002\u65E0\u53C2\u6570",
8804
+ args: NO_ARGS
8805
+ },
8806
+ "deploy:get": {
8807
+ summary: "\u53D6\u4E00\u5F20\u90E8\u7F72\u5355 + \u6BCF\u6761\u51ED\u636E\u7684\u586B\u5199\u8FDB\u5EA6\u3002**\u8FDB\u5EA6\u53EA\u6709\u4E2A\u6570\u4E0D\u542B\u503C**\u2014\u2014\u51ED\u636E\u503C\u4E0D\u7ECF\u8FC7\u8FD9\u6761\u8DEF\uFF1Bowner-only",
8808
+ args: DeployIdArgsSchema
8809
+ },
8810
+ "deploy:patch": {
8811
+ summary: "\u7F16\u8F91\u90E8\u7F72\u5355\uFF1A\u9009\u5C65\u7EA6\uFF08\u8C01\u51FA\u8FD9\u6761\u51ED\u636E\uFF09/ \u6539\u5192\u70DF\u4EFB\u52A1 / \u624B\u5DE5\u8865\u4F9D\u8D56\u3002**\u4E0D\u80FD\u4ECE\u8FD9\u91CC\u4F20\u51ED\u636E\u7684\u503C**\uFF08\u503C\u8D70 deploy:putSecret\uFF09\uFF1B\u5C65\u7EA6\u540D\u5FC5\u987B\u662F\u6E05\u5355\u91CC\u58F0\u660E\u8FC7\u7684\u51ED\u636E\uFF1Bowner-only",
8812
+ args: DeployPatchArgsSchema
8813
+ },
8814
+ "deploy:putSecret": {
8815
+ summary: "\u5F55\u5165\u4E00\u6761\u51ED\u636E\u7684\u503C\u3002**\u8FD9\u662F\u503C\u552F\u4E00\u7684\u5165\u53E3**\uFF1A\u5165\u53C2\u4E0D\u8FDB\u65E5\u5FD7\u3001\u54CD\u5E94\u53EA\u56DE\u586B\u5199\u8FDB\u5EA6\u4E0D\u56DE\u663E\u503C\u3002env \u540D\u5FC5\u987B\u662F\u8BE5\u51ED\u636E\u5728\u6E05\u5355\u91CC\u58F0\u660E\u8FC7\u7684\uFF0C\u5426\u5219\u503C\u5B58\u4E86\u4E5F\u6C38\u8FDC\u6CE8\u5165\u4E0D\u5230\uFF1Bowner-only",
8816
+ args: DeployPutSecretArgsSchema
8817
+ },
8818
+ "deploy:reportFinding": {
8819
+ summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08cli / secret / asset\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u5355\u636E\u9875\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002owner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
8820
+ args: DeployReportFindingArgsSchema
8821
+ },
8822
+ "deploy:finishScan": {
8823
+ 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",
8824
+ args: DeployFinishScanArgsSchema
8825
+ },
8826
+ "deploy:remove": {
8827
+ 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",
8828
+ args: DeployIdArgsSchema
8829
+ },
8616
8830
  "shift:list": {
8617
8831
  summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
8618
8832
  args: NO_ARGS
@@ -9119,7 +9333,9 @@ var init_errors2 = __esm({
9119
9333
  DISPATCH_NOT_FOUND: "DISPATCH_NOT_FOUND",
9120
9334
  // persona:get 查不到该 personaId,或 guest ctx 查非 public / 无 read grant 的 persona
9121
9335
  // (与 DISPATCH_NOT_FOUND 同款:越权与未知 id 同码,不泄露存在性)。
9122
- PERSONA_NOT_FOUND: "PERSONA_NOT_FOUND"
9336
+ PERSONA_NOT_FOUND: "PERSONA_NOT_FOUND",
9337
+ // deploy:* 查不到该部署单(persona 上云的单据)。同上口径:未知 id 与越权同码。
9338
+ DEPLOY_NOT_FOUND: "DEPLOY_NOT_FOUND"
9123
9339
  };
9124
9340
  ClawdError = class extends Error {
9125
9341
  constructor(code, message) {
@@ -9295,6 +9511,8 @@ var init_runtime = __esm({
9295
9511
  init_errors2();
9296
9512
  init_schemas();
9297
9513
  init_frames();
9514
+ init_environment_schemas();
9515
+ init_deploy_schemas();
9298
9516
  init_persona_schemas();
9299
9517
  init_persona_mode();
9300
9518
  init_attachment_schemas();
@@ -9593,8 +9811,8 @@ var require_req = __commonJS({
9593
9811
  if (req.originalUrl) {
9594
9812
  _req.url = req.originalUrl;
9595
9813
  } else {
9596
- const path91 = req.path;
9597
- _req.url = typeof path91 === "string" ? path91 : req.url ? req.url.path || req.url : void 0;
9814
+ const path93 = req.path;
9815
+ _req.url = typeof path93 === "string" ? path93 : req.url ? req.url.path || req.url : void 0;
9598
9816
  }
9599
9817
  if (req.query) {
9600
9818
  _req.query = req.query;
@@ -9759,14 +9977,14 @@ var require_redact = __commonJS({
9759
9977
  }
9760
9978
  return obj;
9761
9979
  }
9762
- function parsePath(path91) {
9980
+ function parsePath(path93) {
9763
9981
  const parts = [];
9764
9982
  let current = "";
9765
9983
  let inBrackets = false;
9766
9984
  let inQuotes = false;
9767
9985
  let quoteChar = "";
9768
- for (let i = 0; i < path91.length; i++) {
9769
- const char = path91[i];
9986
+ for (let i = 0; i < path93.length; i++) {
9987
+ const char = path93[i];
9770
9988
  if (!inBrackets && char === ".") {
9771
9989
  if (current) {
9772
9990
  parts.push(current);
@@ -9897,10 +10115,10 @@ var require_redact = __commonJS({
9897
10115
  return current;
9898
10116
  }
9899
10117
  function redactPaths(obj, paths, censor, remove = false) {
9900
- for (const path91 of paths) {
9901
- const parts = parsePath(path91);
10118
+ for (const path93 of paths) {
10119
+ const parts = parsePath(path93);
9902
10120
  if (parts.includes("*")) {
9903
- redactWildcardPath(obj, parts, censor, path91, remove);
10121
+ redactWildcardPath(obj, parts, censor, path93, remove);
9904
10122
  } else {
9905
10123
  if (remove) {
9906
10124
  removeKey(obj, parts);
@@ -9985,8 +10203,8 @@ var require_redact = __commonJS({
9985
10203
  }
9986
10204
  } else {
9987
10205
  if (afterWildcard.includes("*")) {
9988
- const wrappedCensor = typeof censor === "function" ? (value, path91) => {
9989
- const fullPath = [...pathArray.slice(0, pathLength), ...path91];
10206
+ const wrappedCensor = typeof censor === "function" ? (value, path93) => {
10207
+ const fullPath = [...pathArray.slice(0, pathLength), ...path93];
9990
10208
  return censor(value, fullPath);
9991
10209
  } : censor;
9992
10210
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10021,8 +10239,8 @@ var require_redact = __commonJS({
10021
10239
  return null;
10022
10240
  }
10023
10241
  const pathStructure = /* @__PURE__ */ new Map();
10024
- for (const path91 of pathsToClone) {
10025
- const parts = parsePath(path91);
10242
+ for (const path93 of pathsToClone) {
10243
+ const parts = parsePath(path93);
10026
10244
  let current = pathStructure;
10027
10245
  for (let i = 0; i < parts.length; i++) {
10028
10246
  const part = parts[i];
@@ -10074,24 +10292,24 @@ var require_redact = __commonJS({
10074
10292
  }
10075
10293
  return cloneSelectively(obj, pathStructure);
10076
10294
  }
10077
- function validatePath(path91) {
10078
- if (typeof path91 !== "string") {
10295
+ function validatePath(path93) {
10296
+ if (typeof path93 !== "string") {
10079
10297
  throw new Error("Paths must be (non-empty) strings");
10080
10298
  }
10081
- if (path91 === "") {
10299
+ if (path93 === "") {
10082
10300
  throw new Error("Invalid redaction path ()");
10083
10301
  }
10084
- if (path91.includes("..")) {
10085
- throw new Error(`Invalid redaction path (${path91})`);
10302
+ if (path93.includes("..")) {
10303
+ throw new Error(`Invalid redaction path (${path93})`);
10086
10304
  }
10087
- if (path91.includes(",")) {
10088
- throw new Error(`Invalid redaction path (${path91})`);
10305
+ if (path93.includes(",")) {
10306
+ throw new Error(`Invalid redaction path (${path93})`);
10089
10307
  }
10090
10308
  let bracketCount = 0;
10091
10309
  let inQuotes = false;
10092
10310
  let quoteChar = "";
10093
- for (let i = 0; i < path91.length; i++) {
10094
- const char = path91[i];
10311
+ for (let i = 0; i < path93.length; i++) {
10312
+ const char = path93[i];
10095
10313
  if ((char === '"' || char === "'") && bracketCount > 0) {
10096
10314
  if (!inQuotes) {
10097
10315
  inQuotes = true;
@@ -10105,20 +10323,20 @@ var require_redact = __commonJS({
10105
10323
  } else if (char === "]" && !inQuotes) {
10106
10324
  bracketCount--;
10107
10325
  if (bracketCount < 0) {
10108
- throw new Error(`Invalid redaction path (${path91})`);
10326
+ throw new Error(`Invalid redaction path (${path93})`);
10109
10327
  }
10110
10328
  }
10111
10329
  }
10112
10330
  if (bracketCount !== 0) {
10113
- throw new Error(`Invalid redaction path (${path91})`);
10331
+ throw new Error(`Invalid redaction path (${path93})`);
10114
10332
  }
10115
10333
  }
10116
10334
  function validatePaths(paths) {
10117
10335
  if (!Array.isArray(paths)) {
10118
10336
  throw new TypeError("paths must be an array");
10119
10337
  }
10120
- for (const path91 of paths) {
10121
- validatePath(path91);
10338
+ for (const path93 of paths) {
10339
+ validatePath(path93);
10122
10340
  }
10123
10341
  }
10124
10342
  function slowRedact(options = {}) {
@@ -10286,8 +10504,8 @@ var require_redaction = __commonJS({
10286
10504
  if (shape[k2] === null) {
10287
10505
  o[k2] = (value) => topCensor(value, [k2]);
10288
10506
  } else {
10289
- const wrappedCensor = typeof censor === "function" ? (value, path91) => {
10290
- return censor(value, [k2, ...path91]);
10507
+ const wrappedCensor = typeof censor === "function" ? (value, path93) => {
10508
+ return censor(value, [k2, ...path93]);
10291
10509
  } : censor;
10292
10510
  o[k2] = Redact({
10293
10511
  paths: shape[k2],
@@ -10505,10 +10723,10 @@ var require_atomic_sleep = __commonJS({
10505
10723
  var require_sonic_boom = __commonJS({
10506
10724
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10507
10725
  "use strict";
10508
- var fs80 = require("fs");
10726
+ var fs82 = require("fs");
10509
10727
  var EventEmitter3 = require("events");
10510
10728
  var inherits = require("util").inherits;
10511
- var path91 = require("path");
10729
+ var path93 = require("path");
10512
10730
  var sleep2 = require_atomic_sleep();
10513
10731
  var assert = require("assert");
10514
10732
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10562,20 +10780,20 @@ var require_sonic_boom = __commonJS({
10562
10780
  const mode = sonic.mode;
10563
10781
  if (sonic.sync) {
10564
10782
  try {
10565
- if (sonic.mkdir) fs80.mkdirSync(path91.dirname(file), { recursive: true });
10566
- const fd = fs80.openSync(file, flags, mode);
10783
+ if (sonic.mkdir) fs82.mkdirSync(path93.dirname(file), { recursive: true });
10784
+ const fd = fs82.openSync(file, flags, mode);
10567
10785
  fileOpened(null, fd);
10568
10786
  } catch (err) {
10569
10787
  fileOpened(err);
10570
10788
  throw err;
10571
10789
  }
10572
10790
  } else if (sonic.mkdir) {
10573
- fs80.mkdir(path91.dirname(file), { recursive: true }, (err) => {
10791
+ fs82.mkdir(path93.dirname(file), { recursive: true }, (err) => {
10574
10792
  if (err) return fileOpened(err);
10575
- fs80.open(file, flags, mode, fileOpened);
10793
+ fs82.open(file, flags, mode, fileOpened);
10576
10794
  });
10577
10795
  } else {
10578
- fs80.open(file, flags, mode, fileOpened);
10796
+ fs82.open(file, flags, mode, fileOpened);
10579
10797
  }
10580
10798
  }
10581
10799
  function SonicBoom(opts) {
@@ -10616,8 +10834,8 @@ var require_sonic_boom = __commonJS({
10616
10834
  this.flush = flushBuffer;
10617
10835
  this.flushSync = flushBufferSync;
10618
10836
  this._actualWrite = actualWriteBuffer;
10619
- fsWriteSync = () => fs80.writeSync(this.fd, this._writingBuf);
10620
- fsWrite = () => fs80.write(this.fd, this._writingBuf, this.release);
10837
+ fsWriteSync = () => fs82.writeSync(this.fd, this._writingBuf);
10838
+ fsWrite = () => fs82.write(this.fd, this._writingBuf, this.release);
10621
10839
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
10622
10840
  this._writingBuf = "";
10623
10841
  this.write = write;
@@ -10626,15 +10844,15 @@ var require_sonic_boom = __commonJS({
10626
10844
  this._actualWrite = actualWrite;
10627
10845
  fsWriteSync = () => {
10628
10846
  if (Buffer.isBuffer(this._writingBuf)) {
10629
- return fs80.writeSync(this.fd, this._writingBuf);
10847
+ return fs82.writeSync(this.fd, this._writingBuf);
10630
10848
  }
10631
- return fs80.writeSync(this.fd, this._writingBuf, "utf8");
10849
+ return fs82.writeSync(this.fd, this._writingBuf, "utf8");
10632
10850
  };
10633
10851
  fsWrite = () => {
10634
10852
  if (Buffer.isBuffer(this._writingBuf)) {
10635
- return fs80.write(this.fd, this._writingBuf, this.release);
10853
+ return fs82.write(this.fd, this._writingBuf, this.release);
10636
10854
  }
10637
- return fs80.write(this.fd, this._writingBuf, "utf8", this.release);
10855
+ return fs82.write(this.fd, this._writingBuf, "utf8", this.release);
10638
10856
  };
10639
10857
  } else {
10640
10858
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10691,7 +10909,7 @@ var require_sonic_boom = __commonJS({
10691
10909
  }
10692
10910
  }
10693
10911
  if (this._fsync) {
10694
- fs80.fsyncSync(this.fd);
10912
+ fs82.fsyncSync(this.fd);
10695
10913
  }
10696
10914
  const len = this._len;
10697
10915
  if (this._reopening) {
@@ -10805,7 +11023,7 @@ var require_sonic_boom = __commonJS({
10805
11023
  const onDrain = () => {
10806
11024
  if (!this._fsync) {
10807
11025
  try {
10808
- fs80.fsync(this.fd, (err) => {
11026
+ fs82.fsync(this.fd, (err) => {
10809
11027
  this._flushPending = false;
10810
11028
  cb(err);
10811
11029
  });
@@ -10907,7 +11125,7 @@ var require_sonic_boom = __commonJS({
10907
11125
  const fd = this.fd;
10908
11126
  this.once("ready", () => {
10909
11127
  if (fd !== this.fd) {
10910
- fs80.close(fd, (err) => {
11128
+ fs82.close(fd, (err) => {
10911
11129
  if (err) {
10912
11130
  return this.emit("error", err);
10913
11131
  }
@@ -10956,7 +11174,7 @@ var require_sonic_boom = __commonJS({
10956
11174
  buf = this._bufs[0];
10957
11175
  }
10958
11176
  try {
10959
- const n = Buffer.isBuffer(buf) ? fs80.writeSync(this.fd, buf) : fs80.writeSync(this.fd, buf, "utf8");
11177
+ const n = Buffer.isBuffer(buf) ? fs82.writeSync(this.fd, buf) : fs82.writeSync(this.fd, buf, "utf8");
10960
11178
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10961
11179
  buf = releasedBufObj.writingBuf;
10962
11180
  this._len = releasedBufObj.len;
@@ -10972,7 +11190,7 @@ var require_sonic_boom = __commonJS({
10972
11190
  }
10973
11191
  }
10974
11192
  try {
10975
- fs80.fsyncSync(this.fd);
11193
+ fs82.fsyncSync(this.fd);
10976
11194
  } catch {
10977
11195
  }
10978
11196
  }
@@ -10993,7 +11211,7 @@ var require_sonic_boom = __commonJS({
10993
11211
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10994
11212
  }
10995
11213
  try {
10996
- const n = fs80.writeSync(this.fd, buf);
11214
+ const n = fs82.writeSync(this.fd, buf);
10997
11215
  buf = buf.subarray(n);
10998
11216
  this._len = Math.max(this._len - n, 0);
10999
11217
  if (buf.length <= 0) {
@@ -11021,13 +11239,13 @@ var require_sonic_boom = __commonJS({
11021
11239
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11022
11240
  if (this.sync) {
11023
11241
  try {
11024
- const written = Buffer.isBuffer(this._writingBuf) ? fs80.writeSync(this.fd, this._writingBuf) : fs80.writeSync(this.fd, this._writingBuf, "utf8");
11242
+ const written = Buffer.isBuffer(this._writingBuf) ? fs82.writeSync(this.fd, this._writingBuf) : fs82.writeSync(this.fd, this._writingBuf, "utf8");
11025
11243
  release(null, written);
11026
11244
  } catch (err) {
11027
11245
  release(err);
11028
11246
  }
11029
11247
  } else {
11030
- fs80.write(this.fd, this._writingBuf, release);
11248
+ fs82.write(this.fd, this._writingBuf, release);
11031
11249
  }
11032
11250
  }
11033
11251
  function actualWriteBuffer() {
@@ -11036,7 +11254,7 @@ var require_sonic_boom = __commonJS({
11036
11254
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11037
11255
  if (this.sync) {
11038
11256
  try {
11039
- const written = fs80.writeSync(this.fd, this._writingBuf);
11257
+ const written = fs82.writeSync(this.fd, this._writingBuf);
11040
11258
  release(null, written);
11041
11259
  } catch (err) {
11042
11260
  release(err);
@@ -11045,7 +11263,7 @@ var require_sonic_boom = __commonJS({
11045
11263
  if (kCopyBuffer) {
11046
11264
  this._writingBuf = Buffer.from(this._writingBuf);
11047
11265
  }
11048
- fs80.write(this.fd, this._writingBuf, release);
11266
+ fs82.write(this.fd, this._writingBuf, release);
11049
11267
  }
11050
11268
  }
11051
11269
  function actualClose(sonic) {
@@ -11061,12 +11279,12 @@ var require_sonic_boom = __commonJS({
11061
11279
  sonic._lens = [];
11062
11280
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11063
11281
  try {
11064
- fs80.fsync(sonic.fd, closeWrapped);
11282
+ fs82.fsync(sonic.fd, closeWrapped);
11065
11283
  } catch {
11066
11284
  }
11067
11285
  function closeWrapped() {
11068
11286
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11069
- fs80.close(sonic.fd, done);
11287
+ fs82.close(sonic.fd, done);
11070
11288
  } else {
11071
11289
  done();
11072
11290
  }
@@ -14201,11 +14419,11 @@ var init_lib = __esm({
14201
14419
  }
14202
14420
  }
14203
14421
  },
14204
- addToPath: function addToPath(path91, added, removed, oldPosInc, options) {
14205
- var last = path91.lastComponent;
14422
+ addToPath: function addToPath(path93, added, removed, oldPosInc, options) {
14423
+ var last = path93.lastComponent;
14206
14424
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14207
14425
  return {
14208
- oldPos: path91.oldPos + oldPosInc,
14426
+ oldPos: path93.oldPos + oldPosInc,
14209
14427
  lastComponent: {
14210
14428
  count: last.count + 1,
14211
14429
  added,
@@ -14215,7 +14433,7 @@ var init_lib = __esm({
14215
14433
  };
14216
14434
  } else {
14217
14435
  return {
14218
- oldPos: path91.oldPos + oldPosInc,
14436
+ oldPos: path93.oldPos + oldPosInc,
14219
14437
  lastComponent: {
14220
14438
  count: 1,
14221
14439
  added,
@@ -14797,10 +15015,10 @@ function attachmentToHistoryMessage(o, ts) {
14797
15015
  const memories = raw.map((m2) => {
14798
15016
  if (!m2 || typeof m2 !== "object") return null;
14799
15017
  const rec4 = m2;
14800
- const path91 = typeof rec4.path === "string" ? rec4.path : null;
15018
+ const path93 = typeof rec4.path === "string" ? rec4.path : null;
14801
15019
  const content = typeof rec4.content === "string" ? rec4.content : null;
14802
- if (!path91 || content == null) return null;
14803
- const entry = { path: path91, content };
15020
+ if (!path93 || content == null) return null;
15021
+ const entry = { path: path93, content };
14804
15022
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
14805
15023
  return entry;
14806
15024
  }).filter((m2) => m2 !== null);
@@ -15666,10 +15884,10 @@ function parseAttachment(obj) {
15666
15884
  const memories = raw.map((m2) => {
15667
15885
  if (!m2 || typeof m2 !== "object") return null;
15668
15886
  const rec4 = m2;
15669
- const path91 = typeof rec4.path === "string" ? rec4.path : null;
15887
+ const path93 = typeof rec4.path === "string" ? rec4.path : null;
15670
15888
  const content = typeof rec4.content === "string" ? rec4.content : null;
15671
- if (!path91 || content == null) return null;
15672
- const out = { path: path91, content };
15889
+ if (!path93 || content == null) return null;
15890
+ const out = { path: path93, content };
15673
15891
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
15674
15892
  return out;
15675
15893
  }).filter((m2) => m2 !== null);
@@ -36643,8 +36861,8 @@ var require_utils = __commonJS({
36643
36861
  var result = transform[inputType][outputType](input);
36644
36862
  return result;
36645
36863
  };
36646
- exports2.resolve = function(path91) {
36647
- var parts = path91.split("/");
36864
+ exports2.resolve = function(path93) {
36865
+ var parts = path93.split("/");
36648
36866
  var result = [];
36649
36867
  for (var index = 0; index < parts.length; index++) {
36650
36868
  var part = parts[index];
@@ -42497,18 +42715,18 @@ var require_object = __commonJS({
42497
42715
  var object = new ZipObject(name, zipObjectContent, o);
42498
42716
  this.files[name] = object;
42499
42717
  };
42500
- var parentFolder = function(path91) {
42501
- if (path91.slice(-1) === "/") {
42502
- path91 = path91.substring(0, path91.length - 1);
42718
+ var parentFolder = function(path93) {
42719
+ if (path93.slice(-1) === "/") {
42720
+ path93 = path93.substring(0, path93.length - 1);
42503
42721
  }
42504
- var lastSlash = path91.lastIndexOf("/");
42505
- return lastSlash > 0 ? path91.substring(0, lastSlash) : "";
42722
+ var lastSlash = path93.lastIndexOf("/");
42723
+ return lastSlash > 0 ? path93.substring(0, lastSlash) : "";
42506
42724
  };
42507
- var forceTrailingSlash = function(path91) {
42508
- if (path91.slice(-1) !== "/") {
42509
- path91 += "/";
42725
+ var forceTrailingSlash = function(path93) {
42726
+ if (path93.slice(-1) !== "/") {
42727
+ path93 += "/";
42510
42728
  }
42511
- return path91;
42729
+ return path93;
42512
42730
  };
42513
42731
  var folderAdd = function(name, createFolders) {
42514
42732
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43510,7 +43728,7 @@ var require_lib3 = __commonJS({
43510
43728
  // src/run-case/recorder.ts
43511
43729
  function startRunCaseRecorder(opts) {
43512
43730
  const now = opts.now ?? Date.now;
43513
- const dir = import_node_path73.default.dirname(opts.recordPath);
43731
+ const dir = import_node_path75.default.dirname(opts.recordPath);
43514
43732
  let stream = null;
43515
43733
  let closing = false;
43516
43734
  let closedSettled = false;
@@ -43550,12 +43768,12 @@ function startRunCaseRecorder(opts) {
43550
43768
  };
43551
43769
  return { tap, close, closed };
43552
43770
  }
43553
- var import_node_fs54, import_node_path73;
43771
+ var import_node_fs54, import_node_path75;
43554
43772
  var init_recorder = __esm({
43555
43773
  "src/run-case/recorder.ts"() {
43556
43774
  "use strict";
43557
43775
  import_node_fs54 = __toESM(require("fs"), 1);
43558
- import_node_path73 = __toESM(require("path"), 1);
43776
+ import_node_path75 = __toESM(require("path"), 1);
43559
43777
  }
43560
43778
  });
43561
43779
 
@@ -43598,7 +43816,7 @@ var init_wire = __esm({
43598
43816
  // src/run-case/controller.ts
43599
43817
  async function runController(opts) {
43600
43818
  const now = opts.now ?? Date.now;
43601
- const cwd = opts.cwd ?? (0, import_node_fs55.mkdtempSync)(import_node_path74.default.join(import_node_os27.default.tmpdir(), "clawd-runcase-"));
43819
+ const cwd = opts.cwd ?? (0, import_node_fs55.mkdtempSync)(import_node_path76.default.join(import_node_os27.default.tmpdir(), "clawd-runcase-"));
43602
43820
  const ownsCwd = opts.cwd === void 0;
43603
43821
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
43604
43822
  const spawnCtx = { cwd };
@@ -43765,13 +43983,13 @@ async function runController(opts) {
43765
43983
  }
43766
43984
  return exitCode ?? 0;
43767
43985
  }
43768
- var import_node_fs55, import_node_os27, import_node_path74;
43986
+ var import_node_fs55, import_node_os27, import_node_path76;
43769
43987
  var init_controller = __esm({
43770
43988
  "src/run-case/controller.ts"() {
43771
43989
  "use strict";
43772
43990
  import_node_fs55 = require("fs");
43773
43991
  import_node_os27 = __toESM(require("os"), 1);
43774
- import_node_path74 = __toESM(require("path"), 1);
43992
+ import_node_path76 = __toESM(require("path"), 1);
43775
43993
  init_claude();
43776
43994
  init_stdout_splitter();
43777
43995
  init_permission_stdio();
@@ -44046,7 +44264,7 @@ Env (advanced):
44046
44264
  `;
44047
44265
 
44048
44266
  // src/index.ts
44049
- var import_node_path72 = __toESM(require("path"), 1);
44267
+ var import_node_path74 = __toESM(require("path"), 1);
44050
44268
  var import_node_fs53 = __toESM(require("fs"), 1);
44051
44269
  var import_node_os26 = __toESM(require("os"), 1);
44052
44270
  var import_node_crypto22 = require("crypto");
@@ -51189,8 +51407,8 @@ function turnStartInput(text) {
51189
51407
  const items = [];
51190
51408
  let leftover = text;
51191
51409
  for (const m2 of text.matchAll(SKILL_RE)) {
51192
- const [marker, name, path91] = m2;
51193
- items.push({ type: "skill", name, path: path91 });
51410
+ const [marker, name, path93] = m2;
51411
+ items.push({ type: "skill", name, path: path93 });
51194
51412
  leftover = leftover.replace(marker, "");
51195
51413
  }
51196
51414
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -54110,6 +54328,391 @@ function buildShiftInternalHandlers(deps) {
54110
54328
  };
54111
54329
  }
54112
54330
 
54331
+ // src/handlers/deploy.ts
54332
+ init_protocol();
54333
+
54334
+ // src/deploy/redact.ts
54335
+ var SECRET_KEY_HINT = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIAL|AKID|ACCESS_?ID)/i;
54336
+ var KNOWN_SECRET_SHAPES = [
54337
+ /LTAI[A-Za-z0-9]{6,}/,
54338
+ /eyJ[A-Za-z0-9_-]{10,}/,
54339
+ /sk-[A-Za-z0-9_-]{16,}/,
54340
+ /gh[pousr]_[A-Za-z0-9]{20,}/,
54341
+ /AKIA[A-Z0-9]{12,}/
54342
+ ];
54343
+ var BARE_SECRET = new RegExp(KNOWN_SECRET_SHAPES.map((re) => re.source).join("|"), "g");
54344
+ var REDACTED = "<\u5DF2\u7565\u53BB>";
54345
+ function isPlaceholder(value) {
54346
+ return value.length === 0 || value === REDACTED || /^\$\{?[A-Za-z_]/.test(value) || // ${VAR} / $VAR
54347
+ /^["']?[<(]/.test(value) || // <your-key> / (填这里)
54348
+ /^["']?(your|xxx+|todo|placeholder|change[-_]?me|填)/i.test(value);
54349
+ }
54350
+ var ASSIGNMENT = /((?:export\s+)?)(["']?)([A-Za-z_][A-Za-z0-9_.-]*)\2(\s*[:=]\s*)(["']?)([^\s"'`,;)\]}]+)/g;
54351
+ function redactSecretValues(text) {
54352
+ const byAssignment = text.replace(
54353
+ ASSIGNMENT,
54354
+ (whole, exp, kq, key, sep4, vq, value) => {
54355
+ if (isPlaceholder(value)) return whole;
54356
+ const looksSecret = SECRET_KEY_HINT.test(key) || KNOWN_SECRET_SHAPES.some((re) => re.test(value));
54357
+ return looksSecret ? `${exp}${kq}${key}${kq}${sep4}${vq}${REDACTED}` : whole;
54358
+ }
54359
+ );
54360
+ return byAssignment.replace(BARE_SECRET, REDACTED);
54361
+ }
54362
+ function redactEvidence(evidence) {
54363
+ return {
54364
+ ...evidence,
54365
+ reason: redactSecretValues(evidence.reason),
54366
+ quote: redactSecretValues(evidence.quote)
54367
+ };
54368
+ }
54369
+
54370
+ // src/handlers/deploy.ts
54371
+ function ensureOwner(ctx) {
54372
+ if (!ctx || ctx.principal.kind !== "owner") {
54373
+ throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: deploy:* requires owner ctx");
54374
+ }
54375
+ }
54376
+ function mustGet(deps, deployId) {
54377
+ const receipt = deps.receipts.get(deployId);
54378
+ if (!receipt) throw new ClawdError(ERROR_CODES.DEPLOY_NOT_FOUND, `DEPLOY_NOT_FOUND: \u6CA1\u6709\u8FD9\u5F20\u90E8\u7F72\u5355\uFF08${deployId}\uFF09`);
54379
+ return receipt;
54380
+ }
54381
+ function mustBeScanning(receipt, method) {
54382
+ if (receipt.status !== "scanning") {
54383
+ throw new ClawdError(
54384
+ ERROR_CODES.VALIDATION_ERROR,
54385
+ `VALIDATION_ERROR: ${method} \u53EA\u5728\u626B\u63CF\u671F\u53EF\u7528\uFF08\u5F53\u524D ${receipt.status}\uFF09`
54386
+ );
54387
+ }
54388
+ return receipt;
54389
+ }
54390
+ function secretStatusOf(deps, receipt) {
54391
+ const declared = receipt.manifest?.secrets ?? [];
54392
+ return declared.map((s) => ({
54393
+ name: s.name,
54394
+ // 只看部署级:使用者自带的那部分由使用者各自绑定,不在部署者这张单据的进度里
54395
+ filled: deps.secrets.filledKeys(receipt.deployId, s.name).length,
54396
+ total: s.env.length
54397
+ }));
54398
+ }
54399
+ function buildDeployHandlers(deps) {
54400
+ const view = (receipt) => ({
54401
+ response: { type: "deploy:receipt", receipt, secretStatus: secretStatusOf(deps, receipt) }
54402
+ });
54403
+ const start = async (frame, _client, ctx) => {
54404
+ ensureOwner(ctx);
54405
+ const args = parseArgs2(DeployStartArgsSchema, frame, "deploy:start");
54406
+ if (!deps.hasPersona(args.personaId)) {
54407
+ throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${args.personaId}\uFF09`);
54408
+ }
54409
+ const inFlight = deps.receipts.list().find((r) => r.personaId === args.personaId && r.status === "scanning");
54410
+ if (inFlight) return view(inFlight);
54411
+ const receipt = deps.receipts.create({
54412
+ deployId: deps.genId(),
54413
+ personaId: args.personaId,
54414
+ status: "scanning"
54415
+ });
54416
+ const scanSessionId = deps.startScan(receipt.deployId, args.personaId);
54417
+ if (scanSessionId) deps.receipts.update(receipt.deployId, { scanSessionId });
54418
+ return view(deps.receipts.get(receipt.deployId) ?? receipt);
54419
+ };
54420
+ const list = async (_frame, _client, ctx) => {
54421
+ ensureOwner(ctx);
54422
+ return { response: { type: "deploy:list", receipts: deps.receipts.list() } };
54423
+ };
54424
+ const get = async (frame, _client, ctx) => {
54425
+ ensureOwner(ctx);
54426
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:get");
54427
+ return view(mustGet(deps, args.deployId));
54428
+ };
54429
+ const patch = async (frame, _client, ctx) => {
54430
+ ensureOwner(ctx);
54431
+ const args = parseArgs2(DeployPatchArgsSchema, frame, "deploy:patch");
54432
+ const receipt = mustGet(deps, args.deployId);
54433
+ if (args.patch.fulfillment) {
54434
+ const declared = new Set((args.patch.manifest ?? receipt.manifest)?.secrets.map((s) => s.name) ?? []);
54435
+ for (const name of Object.keys(args.patch.fulfillment)) {
54436
+ if (!declared.has(name)) {
54437
+ throw new ClawdError(
54438
+ ERROR_CODES.VALIDATION_ERROR,
54439
+ `VALIDATION_ERROR: \u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${name}\u300D\u7684\u51ED\u636E`
54440
+ );
54441
+ }
54442
+ }
54443
+ }
54444
+ const next = deps.receipts.update(args.deployId, args.patch);
54445
+ return view(next ?? receipt);
54446
+ };
54447
+ const putSecret = async (frame, _client, ctx) => {
54448
+ ensureOwner(ctx);
54449
+ const args = parseArgs2(DeployPutSecretArgsSchema, frame, "deploy:putSecret");
54450
+ const receipt = mustGet(deps, args.deployId);
54451
+ const declared = receipt.manifest?.secrets.find((s) => s.name === args.name);
54452
+ if (!declared) {
54453
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_ERROR: \u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u51ED\u636E`);
54454
+ }
54455
+ const allowed = new Set(declared.env);
54456
+ for (const key of Object.keys(args.values)) {
54457
+ if (!allowed.has(key)) {
54458
+ throw new ClawdError(
54459
+ ERROR_CODES.VALIDATION_ERROR,
54460
+ `VALIDATION_ERROR: \u300C${args.name}\u300D\u6CA1\u6709\u58F0\u660E\u73AF\u5883\u53D8\u91CF ${key}`
54461
+ );
54462
+ }
54463
+ }
54464
+ deps.secrets.put({ deployId: args.deployId, name: args.name, values: args.values });
54465
+ return view(receipt);
54466
+ };
54467
+ const reportFinding = async (frame, _client, ctx) => {
54468
+ ensureOwner(ctx);
54469
+ const args = parseArgs2(DeployReportFindingArgsSchema, frame, "deploy:reportFinding");
54470
+ const receipt = mustBeScanning(mustGet(deps, args.deployId), "deploy:reportFinding");
54471
+ const schema = args.kind === "cli" ? EnvCliSchema : args.kind === "secret" ? EnvSecretSchema : EnvAssetSchema;
54472
+ const parsed = schema.safeParse(args.item);
54473
+ if (!parsed.success) {
54474
+ const first = parsed.error.issues[0];
54475
+ throw new ClawdError(
54476
+ ERROR_CODES.VALIDATION_ERROR,
54477
+ `VALIDATION_ERROR: ${args.kind} \u6761\u76EE\u4E0D\u5408\u6CD5\uFF1A${first ? `${first.path.join(".")} ${first.message}` : ""}`
54478
+ );
54479
+ }
54480
+ const item = parsed.data;
54481
+ const base = receipt.manifest ?? { version: 1, clis: [], secrets: [], assets: [] };
54482
+ const key = args.kind === "cli" ? "clis" : args.kind === "secret" ? "secrets" : "assets";
54483
+ const list2 = [...base[key]];
54484
+ const idx = list2.findIndex((x) => x.name === item.name);
54485
+ if (idx === -1) list2.push(item);
54486
+ else list2[idx] = item;
54487
+ const target = `${args.kind}:${item.name}`;
54488
+ const evidence = [
54489
+ ...(receipt.evidence ?? []).filter((e) => e.target !== target),
54490
+ redactEvidence({ target, ...args.evidence })
54491
+ ];
54492
+ const next = deps.receipts.update(args.deployId, {
54493
+ manifest: { ...base, [key]: list2 },
54494
+ evidence
54495
+ });
54496
+ return view(next ?? receipt);
54497
+ };
54498
+ const finishScan = async (frame, _client, ctx) => {
54499
+ ensureOwner(ctx);
54500
+ const args = parseArgs2(DeployFinishScanArgsSchema, frame, "deploy:finishScan");
54501
+ mustBeScanning(mustGet(deps, args.deployId), "deploy:finishScan");
54502
+ const next = deps.receipts.update(args.deployId, {
54503
+ status: "draft",
54504
+ smokeTask: args.smokeTask ? redactSecretValues(args.smokeTask) : args.smokeTask,
54505
+ notes: args.notes?.map(redactSecretValues),
54506
+ error: void 0
54507
+ });
54508
+ return view(next);
54509
+ };
54510
+ const remove = async (frame, _client, ctx) => {
54511
+ ensureOwner(ctx);
54512
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:remove");
54513
+ mustGet(deps, args.deployId);
54514
+ deps.receipts.remove(args.deployId);
54515
+ deps.secrets.removeDeploy(args.deployId);
54516
+ return { response: { type: "deploy:remove", deployId: args.deployId } };
54517
+ };
54518
+ return {
54519
+ "deploy:start": start,
54520
+ "deploy:list": list,
54521
+ "deploy:get": get,
54522
+ "deploy:patch": patch,
54523
+ "deploy:putSecret": putSecret,
54524
+ "deploy:reportFinding": reportFinding,
54525
+ "deploy:finishScan": finishScan,
54526
+ "deploy:remove": remove
54527
+ };
54528
+ }
54529
+
54530
+ // src/deploy/receipt-store.ts
54531
+ var import_promises4 = __toESM(require("fs/promises"), 1);
54532
+ var import_node_path28 = __toESM(require("path"), 1);
54533
+ init_protocol();
54534
+ function createReceiptStore(deps) {
54535
+ let receipts = [];
54536
+ let flushTimer = null;
54537
+ async function load() {
54538
+ let raw;
54539
+ try {
54540
+ raw = await import_promises4.default.readFile(deps.filePath, "utf8");
54541
+ } catch (err) {
54542
+ if (err.code === "ENOENT") {
54543
+ receipts = [];
54544
+ return;
54545
+ }
54546
+ throw err;
54547
+ }
54548
+ const parsed = JSON.parse(raw);
54549
+ if (parsed.version !== 1) throw new Error(`deploy.json: unsupported version ${parsed.version}`);
54550
+ receipts = (parsed.receipts ?? []).map((r) => DeployReceiptSchema.parse(r));
54551
+ }
54552
+ async function flushNow() {
54553
+ if (flushTimer) {
54554
+ clearTimeout(flushTimer);
54555
+ flushTimer = null;
54556
+ }
54557
+ const content = { version: 1, receipts };
54558
+ await import_promises4.default.mkdir(import_node_path28.default.dirname(deps.filePath), { recursive: true });
54559
+ const tmp = `${deps.filePath}.tmp-${process.pid}-${deps.now()}`;
54560
+ await import_promises4.default.writeFile(tmp, JSON.stringify(content, null, 2), { encoding: "utf8", mode: 384 });
54561
+ await import_promises4.default.rename(tmp, deps.filePath);
54562
+ }
54563
+ function scheduleFlush() {
54564
+ if (flushTimer) return;
54565
+ flushTimer = setTimeout(() => {
54566
+ flushTimer = null;
54567
+ flushNow().catch((err) => deps.onFlushError?.(err));
54568
+ }, STORE_FLUSH_DEBOUNCE_MS);
54569
+ }
54570
+ return {
54571
+ load,
54572
+ flushNow,
54573
+ create(input) {
54574
+ const ts = deps.now();
54575
+ const receipt = {
54576
+ deployId: input.deployId,
54577
+ personaId: input.personaId,
54578
+ status: input.status,
54579
+ notes: [],
54580
+ fulfillment: {},
54581
+ gaps: [],
54582
+ createdAt: ts,
54583
+ updatedAt: ts
54584
+ };
54585
+ receipts.push(receipt);
54586
+ scheduleFlush();
54587
+ return receipt;
54588
+ },
54589
+ update(deployId, patch) {
54590
+ const idx = receipts.findIndex((r) => r.deployId === deployId);
54591
+ if (idx === -1) return void 0;
54592
+ const next = DeployReceiptSchema.parse({ ...receipts[idx], ...patch, updatedAt: deps.now() });
54593
+ receipts[idx] = next;
54594
+ scheduleFlush();
54595
+ return next;
54596
+ },
54597
+ get(deployId) {
54598
+ return receipts.find((r) => r.deployId === deployId);
54599
+ },
54600
+ list() {
54601
+ return [...receipts].sort((a, b2) => b2.createdAt - a.createdAt);
54602
+ },
54603
+ remove(deployId) {
54604
+ const idx = receipts.findIndex((r) => r.deployId === deployId);
54605
+ if (idx === -1) return false;
54606
+ receipts.splice(idx, 1);
54607
+ scheduleFlush();
54608
+ return true;
54609
+ }
54610
+ };
54611
+ }
54612
+
54613
+ // src/deploy/secret-store.ts
54614
+ var import_promises5 = __toESM(require("fs/promises"), 1);
54615
+ var import_node_path29 = __toESM(require("path"), 1);
54616
+ function createSecretStore(deps) {
54617
+ let entries = [];
54618
+ let flushTimer = null;
54619
+ const sameScope = (e, deployId, name, userId) => e.deployId === deployId && e.name === name && (e.userId ?? void 0) === (userId ?? void 0);
54620
+ async function load() {
54621
+ let raw;
54622
+ try {
54623
+ raw = await import_promises5.default.readFile(deps.filePath, "utf8");
54624
+ } catch (err) {
54625
+ if (err.code === "ENOENT") {
54626
+ entries = [];
54627
+ return;
54628
+ }
54629
+ throw err;
54630
+ }
54631
+ const parsed = JSON.parse(raw);
54632
+ if (parsed.version !== 1) throw new Error(`deploy-secrets.json: unsupported version ${parsed.version}`);
54633
+ entries = parsed.entries ?? [];
54634
+ }
54635
+ async function flushNow() {
54636
+ if (flushTimer) {
54637
+ clearTimeout(flushTimer);
54638
+ flushTimer = null;
54639
+ }
54640
+ const content = { version: 1, entries };
54641
+ await import_promises5.default.mkdir(import_node_path29.default.dirname(deps.filePath), { recursive: true });
54642
+ const tmp = `${deps.filePath}.tmp-${process.pid}-${deps.now()}`;
54643
+ await import_promises5.default.writeFile(tmp, JSON.stringify(content, null, 2), { encoding: "utf8", mode: 384 });
54644
+ await import_promises5.default.rename(tmp, deps.filePath);
54645
+ }
54646
+ function scheduleFlush() {
54647
+ if (flushTimer) return;
54648
+ flushTimer = setTimeout(() => {
54649
+ flushTimer = null;
54650
+ flushNow().catch((err) => deps.onFlushError?.(err));
54651
+ }, STORE_FLUSH_DEBOUNCE_MS);
54652
+ }
54653
+ return {
54654
+ load,
54655
+ flushNow,
54656
+ put(entry) {
54657
+ const idx = entries.findIndex((e) => sameScope(e, entry.deployId, entry.name, entry.userId));
54658
+ if (idx === -1) {
54659
+ entries.push({ ...entry, updatedAt: deps.now() });
54660
+ } else {
54661
+ entries[idx] = {
54662
+ ...entries[idx],
54663
+ values: { ...entries[idx].values, ...entry.values },
54664
+ updatedAt: deps.now()
54665
+ };
54666
+ }
54667
+ scheduleFlush();
54668
+ },
54669
+ resolve(deployId, userId) {
54670
+ const out = {};
54671
+ for (const e of entries) {
54672
+ if (e.deployId !== deployId || e.userId !== void 0) continue;
54673
+ Object.assign(out, e.values);
54674
+ }
54675
+ if (userId !== void 0) {
54676
+ for (const e of entries) {
54677
+ if (e.deployId !== deployId || e.userId !== userId) continue;
54678
+ Object.assign(out, e.values);
54679
+ }
54680
+ }
54681
+ return out;
54682
+ },
54683
+ filledKeys(deployId, name, userId) {
54684
+ const e = entries.find((x) => sameScope(x, deployId, name, userId));
54685
+ if (!e) return [];
54686
+ return Object.keys(e.values).filter((k2) => e.values[k2].length > 0);
54687
+ },
54688
+ removeDeploy(deployId) {
54689
+ const before = entries.length;
54690
+ entries = entries.filter((e) => e.deployId !== deployId);
54691
+ const removed = before - entries.length;
54692
+ if (removed > 0) scheduleFlush();
54693
+ return removed;
54694
+ }
54695
+ };
54696
+ }
54697
+
54698
+ // src/deploy/scan-task.ts
54699
+ var BUTLER_PERSONA_ID = "persona-clawd-butler";
54700
+ var SCANNABLE_ASSETS = ["deploy-kit"];
54701
+ function settleEndedScan(outcome, current) {
54702
+ if (current?.status !== "scanning") return void 0;
54703
+ return {
54704
+ status: "scanFailed",
54705
+ error: "error" in outcome ? outcome.error : "butler \u4F1A\u8BDD\u7ED3\u675F\u4E86\u4F46\u6CA1\u6709\u8C03 finishScan"
54706
+ };
54707
+ }
54708
+ function reconcileInterruptedScans(deps) {
54709
+ const stale = deps.list().filter((r) => r.status === "scanning");
54710
+ for (const r of stale) {
54711
+ deps.update(r.deployId, { status: "scanFailed", error: "daemon \u91CD\u542F\uFF0C\u626B\u63CF\u4F1A\u8BDD\u5DF2\u4E2D\u65AD\u2014\u2014\u8BF7\u91CD\u65B0\u626B\u63CF" });
54712
+ }
54713
+ return stale.map((r) => r.deployId);
54714
+ }
54715
+
54113
54716
  // src/handlers/lark-bot.ts
54114
54717
  init_protocol();
54115
54718
  var PROVISION_ERROR_SET = new Set(LARK_BOT_PROVISION_ERROR_REASONS);
@@ -54498,9 +55101,9 @@ async function refreshTunnelUrlOnStartup(deps) {
54498
55101
 
54499
55102
  // src/lark-bot-connector/binding-store.ts
54500
55103
  var import_node_fs26 = __toESM(require("fs"), 1);
54501
- var import_node_path28 = __toESM(require("path"), 1);
55104
+ var import_node_path30 = __toESM(require("path"), 1);
54502
55105
  function createLarkBotBindingStore(personaRoot) {
54503
- const filePath = (personaId2) => import_node_path28.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
55106
+ const filePath = (personaId2) => import_node_path30.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
54504
55107
  const read = (personaId2) => {
54505
55108
  const file = filePath(personaId2);
54506
55109
  if (!import_node_fs26.default.existsSync(file)) return null;
@@ -54514,7 +55117,7 @@ function createLarkBotBindingStore(personaRoot) {
54514
55117
  };
54515
55118
  const write = (personaId2, meta) => {
54516
55119
  const file = filePath(personaId2);
54517
- import_node_fs26.default.mkdirSync(import_node_path28.default.dirname(file), { recursive: true });
55120
+ import_node_fs26.default.mkdirSync(import_node_path30.default.dirname(file), { recursive: true });
54518
55121
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
54519
55122
  import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
54520
55123
  import_node_fs26.default.renameSync(tmp, file);
@@ -54682,7 +55285,7 @@ function createLarkBotCloudClient(opts) {
54682
55285
 
54683
55286
  // src/lark-bot-connector/chat-router.ts
54684
55287
  var import_node_fs27 = __toESM(require("fs"), 1);
54685
- var import_node_path29 = __toESM(require("path"), 1);
55288
+ var import_node_path31 = __toESM(require("path"), 1);
54686
55289
  init_protocol();
54687
55290
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
54688
55291
  var LOCAL_TURN_RETRIES = 2;
@@ -54749,7 +55352,7 @@ function createLarkChatRouter(deps) {
54749
55352
  }
54750
55353
  const dir = deps.mediaRootFor(env.chatId);
54751
55354
  import_node_fs27.default.mkdirSync(dir, { recursive: true });
54752
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
55355
+ const p2 = import_node_path31.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
54753
55356
  import_node_fs27.default.writeFileSync(p2, r.data);
54754
55357
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
54755
55358
  } catch (err) {
@@ -54772,7 +55375,7 @@ function createLarkChatRouter(deps) {
54772
55375
  }
54773
55376
  const dir = deps.mediaRootFor(env.chatId);
54774
55377
  import_node_fs27.default.mkdirSync(dir, { recursive: true });
54775
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
55378
+ const p2 = import_node_path31.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
54776
55379
  import_node_fs27.default.writeFileSync(p2, r.data);
54777
55380
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
54778
55381
  } catch (err) {
@@ -55862,7 +56465,7 @@ var CodexHistoryReader = class {
55862
56465
  };
55863
56466
 
55864
56467
  // src/tools/codex-skills.ts
55865
- var import_node_path30 = __toESM(require("path"), 1);
56468
+ var import_node_path32 = __toESM(require("path"), 1);
55866
56469
  function str3(v2) {
55867
56470
  return typeof v2 === "string" ? v2 : void 0;
55868
56471
  }
@@ -55877,13 +56480,13 @@ function mapSkillsListResponse(res) {
55877
56480
  const r = s ?? {};
55878
56481
  const name = str3(r.name);
55879
56482
  if (!name) continue;
55880
- const path91 = str3(r.path);
56483
+ const path93 = str3(r.path);
55881
56484
  const description = str3(r.description);
55882
56485
  const isPlugin = name.includes(":");
55883
56486
  out.push({
55884
56487
  name,
55885
56488
  source: isPlugin ? "plugin" : "project",
55886
- ...path91 ? { path: path91 } : {},
56489
+ ...path93 ? { path: path93 } : {},
55887
56490
  ...description ? { description } : {},
55888
56491
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
55889
56492
  });
@@ -55899,14 +56502,14 @@ async function listCodexSkills(cwd, deps = {}) {
55899
56502
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
55900
56503
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
55901
56504
  beforeRequest: (client) => {
55902
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path30.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
56505
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path32.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
55903
56506
  }
55904
56507
  });
55905
56508
  return mapSkillsListResponse(res);
55906
56509
  }
55907
56510
 
55908
56511
  // src/tools/codex-turn-context.ts
55909
- var import_promises4 = __toESM(require("fs/promises"), 1);
56512
+ var import_promises6 = __toESM(require("fs/promises"), 1);
55910
56513
  function parseTurnContextFromRollout(raw) {
55911
56514
  const lines = raw.split("\n");
55912
56515
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -55941,7 +56544,7 @@ async function readCodexTurnContext(args, deps = {}) {
55941
56544
  );
55942
56545
  const rolloutPath = str4(rec3(res?.thread)?.path);
55943
56546
  if (!rolloutPath) return null;
55944
- return parseTurnContextFromRollout(await import_promises4.default.readFile(rolloutPath, "utf8"));
56547
+ return parseTurnContextFromRollout(await import_promises6.default.readFile(rolloutPath, "utf8"));
55945
56548
  }
55946
56549
  function createCodexResolvedMetaHydrator(deps) {
55947
56550
  const fetchedThreadIds = /* @__PURE__ */ new Set();
@@ -55986,14 +56589,14 @@ function str4(v2) {
55986
56589
  // src/workspace/browser.ts
55987
56590
  var import_node_fs28 = __toESM(require("fs"), 1);
55988
56591
  var import_node_os8 = __toESM(require("os"), 1);
55989
- var import_node_path31 = __toESM(require("path"), 1);
56592
+ var import_node_path33 = __toESM(require("path"), 1);
55990
56593
  init_protocol();
55991
56594
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
55992
56595
  function resolveInsideCwd(cwd, subpath) {
55993
- const absCwd = import_node_path31.default.resolve(cwd);
55994
- const joined = import_node_path31.default.resolve(absCwd, subpath ?? ".");
55995
- const rel = import_node_path31.default.relative(absCwd, joined);
55996
- if (rel.startsWith("..") || import_node_path31.default.isAbsolute(rel)) {
56596
+ const absCwd = import_node_path33.default.resolve(cwd);
56597
+ const joined = import_node_path33.default.resolve(absCwd, subpath ?? ".");
56598
+ const rel = import_node_path33.default.relative(absCwd, joined);
56599
+ if (rel.startsWith("..") || import_node_path33.default.isAbsolute(rel)) {
55997
56600
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
55998
56601
  }
55999
56602
  return joined;
@@ -56024,7 +56627,7 @@ var WorkspaceBrowser = class {
56024
56627
  mtime: ""
56025
56628
  };
56026
56629
  try {
56027
- const st = import_node_fs28.default.statSync(import_node_path31.default.join(full, d.name));
56630
+ const st = import_node_fs28.default.statSync(import_node_path33.default.join(full, d.name));
56028
56631
  entry.mtime = new Date(st.mtimeMs).toISOString();
56029
56632
  if (d.isFile()) entry.size = st.size;
56030
56633
  } catch {
@@ -56071,7 +56674,7 @@ var WorkspaceBrowser = class {
56071
56674
  // src/skills/agents-scanner.ts
56072
56675
  var import_node_fs29 = __toESM(require("fs"), 1);
56073
56676
  var import_node_os9 = __toESM(require("os"), 1);
56074
- var import_node_path32 = __toESM(require("path"), 1);
56677
+ var import_node_path34 = __toESM(require("path"), 1);
56075
56678
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
56076
56679
  function isDirLikeSync2(p2) {
56077
56680
  try {
@@ -56109,10 +56712,10 @@ function scanAgentsDir(dir, source, seen, out) {
56109
56712
  }
56110
56713
  for (const ent of entries) {
56111
56714
  if (!ent.name.endsWith(".md")) continue;
56112
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path32.default.join(dir, ent.name)))) {
56715
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path34.default.join(dir, ent.name)))) {
56113
56716
  continue;
56114
56717
  }
56115
- const filePath = import_node_path32.default.join(dir, ent.name);
56718
+ const filePath = import_node_path34.default.join(dir, ent.name);
56116
56719
  const baseName = ent.name.replace(/\.md$/, "");
56117
56720
  if (seen.has(baseName)) continue;
56118
56721
  seen.add(baseName);
@@ -56135,7 +56738,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
56135
56738
  return;
56136
56739
  }
56137
56740
  for (const ent of entries) {
56138
- const childPath = import_node_path32.default.join(dir, ent.name);
56741
+ const childPath = import_node_path34.default.join(dir, ent.name);
56139
56742
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
56140
56743
  walk2(childPath, [...namespaces, ent.name]);
56141
56744
  continue;
@@ -56160,9 +56763,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
56160
56763
  walk2(root, []);
56161
56764
  }
56162
56765
  function readInstalledPlugins2(home) {
56163
- const pluginsDir = import_node_path32.default.join(home, ".claude", "plugins");
56164
- const v2 = import_node_path32.default.join(pluginsDir, "installed_plugins_v2.json");
56165
- const v1 = import_node_path32.default.join(pluginsDir, "installed_plugins.json");
56766
+ const pluginsDir = import_node_path34.default.join(home, ".claude", "plugins");
56767
+ const v2 = import_node_path34.default.join(pluginsDir, "installed_plugins_v2.json");
56768
+ const v1 = import_node_path34.default.join(pluginsDir, "installed_plugins.json");
56166
56769
  let raw = null;
56167
56770
  for (const candidate of [v2, v1]) {
56168
56771
  try {
@@ -56191,19 +56794,19 @@ function readInstalledPlugins2(home) {
56191
56794
  return out;
56192
56795
  }
56193
56796
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
56194
- let cur = import_node_path32.default.resolve(startCwd);
56195
- const fsRoot = import_node_path32.default.parse(cur).root;
56797
+ let cur = import_node_path34.default.resolve(startCwd);
56798
+ const fsRoot = import_node_path34.default.parse(cur).root;
56196
56799
  while (true) {
56197
- scanAgentsDir(import_node_path32.default.join(cur, ".claude", "agents"), "project", seen, out);
56800
+ scanAgentsDir(import_node_path34.default.join(cur, ".claude", "agents"), "project", seen, out);
56198
56801
  let hasGit = false;
56199
56802
  try {
56200
- hasGit = import_node_fs29.default.existsSync(import_node_path32.default.join(cur, ".git"));
56803
+ hasGit = import_node_fs29.default.existsSync(import_node_path34.default.join(cur, ".git"));
56201
56804
  } catch {
56202
56805
  }
56203
56806
  if (hasGit) return;
56204
56807
  if (cur === home) return;
56205
56808
  if (cur === fsRoot) return;
56206
- const parent = import_node_path32.default.dirname(cur);
56809
+ const parent = import_node_path34.default.dirname(cur);
56207
56810
  if (parent === cur) return;
56208
56811
  cur = parent;
56209
56812
  }
@@ -56238,7 +56841,7 @@ var AgentsScanner = class {
56238
56841
  }
56239
56842
  const fsBlock = [];
56240
56843
  scanAgentsDir(
56241
- import_node_path32.default.join(this.home, ".claude", "agents"),
56844
+ import_node_path34.default.join(this.home, ".claude", "agents"),
56242
56845
  "global",
56243
56846
  seen,
56244
56847
  fsBlock
@@ -56252,7 +56855,7 @@ var AgentsScanner = class {
56252
56855
  ...this.extraPluginRoots
56253
56856
  ];
56254
56857
  for (const { name, root } of plugins) {
56255
- const agentsRoot = import_node_path32.default.join(root, "agents");
56858
+ const agentsRoot = import_node_path34.default.join(root, "agents");
56256
56859
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
56257
56860
  }
56258
56861
  return [...builtinBlock, ...fsBlock];
@@ -56262,13 +56865,13 @@ var AgentsScanner = class {
56262
56865
  // src/observer/session-observer.ts
56263
56866
  var import_node_fs31 = __toESM(require("fs"), 1);
56264
56867
  var import_node_os11 = __toESM(require("os"), 1);
56265
- var import_node_path34 = __toESM(require("path"), 1);
56868
+ var import_node_path36 = __toESM(require("path"), 1);
56266
56869
  init_claude_history();
56267
56870
 
56268
56871
  // src/observer/subagent-meta-observer.ts
56269
56872
  var import_node_fs30 = __toESM(require("fs"), 1);
56270
56873
  var import_node_os10 = __toESM(require("os"), 1);
56271
- var import_node_path33 = __toESM(require("path"), 1);
56874
+ var import_node_path35 = __toESM(require("path"), 1);
56272
56875
  init_claude_history();
56273
56876
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
56274
56877
  var SubagentMetaObserver = class {
@@ -56281,7 +56884,7 @@ var SubagentMetaObserver = class {
56281
56884
  watches = /* @__PURE__ */ new Map();
56282
56885
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
56283
56886
  resolveSubagentDir(cwd, toolSessionId) {
56284
- return import_node_path33.default.join(
56887
+ return import_node_path35.default.join(
56285
56888
  this.home,
56286
56889
  ".claude",
56287
56890
  "projects",
@@ -56337,7 +56940,7 @@ var SubagentMetaObserver = class {
56337
56940
  if (!m2) return;
56338
56941
  const agentId = m2[1];
56339
56942
  if (w2.emitted.has(agentId)) return;
56340
- const file = import_node_path33.default.join(w2.dirPath, name);
56943
+ const file = import_node_path35.default.join(w2.dirPath, name);
56341
56944
  let raw;
56342
56945
  try {
56343
56946
  raw = import_node_fs30.default.readFileSync(file, "utf8");
@@ -56397,7 +57000,7 @@ var SessionObserver = class {
56397
57000
  metaObserver;
56398
57001
  resolveJsonlPath(cwd, toolSessionId, override) {
56399
57002
  if (override) return override;
56400
- return import_node_path34.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
57003
+ return import_node_path36.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
56401
57004
  }
56402
57005
  start(args) {
56403
57006
  this.stop(args.sessionId);
@@ -56423,10 +57026,10 @@ var SessionObserver = class {
56423
57026
  lastDeriveMs: 0
56424
57027
  };
56425
57028
  try {
56426
- import_node_fs31.default.mkdirSync(import_node_path34.default.dirname(filePath), { recursive: true });
57029
+ import_node_fs31.default.mkdirSync(import_node_path36.default.dirname(filePath), { recursive: true });
56427
57030
  } catch {
56428
57031
  }
56429
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
57032
+ w2.watcher = import_node_fs31.default.watch(import_node_path36.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
56430
57033
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
56431
57034
  this.poll(w2);
56432
57035
  });
@@ -56523,7 +57126,7 @@ var SessionObserver = class {
56523
57126
  const now = Date.now();
56524
57127
  if (now - w2.lastRelocateScanMs < 1e3) return;
56525
57128
  w2.lastRelocateScanMs = now;
56526
- const projectsRoot = import_node_path34.default.join(this.home, ".claude", "projects");
57129
+ const projectsRoot = import_node_path36.default.join(this.home, ".claude", "projects");
56527
57130
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
56528
57131
  if (!found || found === w2.filePath) return;
56529
57132
  try {
@@ -56532,7 +57135,7 @@ var SessionObserver = class {
56532
57135
  }
56533
57136
  w2.filePath = found;
56534
57137
  try {
56535
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(found), { persistent: false }, (_event, changedName) => {
57138
+ w2.watcher = import_node_fs31.default.watch(import_node_path36.default.dirname(found), { persistent: false }, (_event, changedName) => {
56536
57139
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
56537
57140
  this.poll(w2);
56538
57141
  });
@@ -56655,7 +57258,7 @@ function listRegistered() {
56655
57258
  var import_node_child_process8 = require("child_process");
56656
57259
  var import_node_fs32 = __toESM(require("fs"), 1);
56657
57260
  var import_node_os12 = __toESM(require("os"), 1);
56658
- var import_node_path35 = __toESM(require("path"), 1);
57261
+ var import_node_path37 = __toESM(require("path"), 1);
56659
57262
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
56660
57263
  var TITLE_MODEL_BY_TOOL = {
56661
57264
  claude: "haiku",
@@ -56726,7 +57329,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
56726
57329
  if (!text) return null;
56727
57330
  let workDir;
56728
57331
  try {
56729
- workDir = import_node_fs32.default.mkdtempSync(import_node_path35.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
57332
+ workDir = import_node_fs32.default.mkdtempSync(import_node_path37.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
56730
57333
  } catch {
56731
57334
  return null;
56732
57335
  }
@@ -56736,8 +57339,8 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
56736
57339
  } catch {
56737
57340
  }
56738
57341
  };
56739
- const outFile = import_node_path35.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
56740
- const schemaFile = import_node_path35.default.join(workDir, "title-schema.json");
57342
+ const outFile = import_node_path37.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
57343
+ const schemaFile = import_node_path37.default.join(workDir, "title-schema.json");
56741
57344
  if (tool === "codex") {
56742
57345
  try {
56743
57346
  import_node_fs32.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
@@ -57491,8 +58094,8 @@ async function authenticate(token, deps) {
57491
58094
  }
57492
58095
 
57493
58096
  // src/legacy-cleanup.ts
57494
- var fs41 = __toESM(require("fs/promises"), 1);
57495
- var path43 = __toESM(require("path"), 1);
58097
+ var fs43 = __toESM(require("fs/promises"), 1);
58098
+ var path45 = __toESM(require("path"), 1);
57496
58099
  var LEGACY_FILES = [
57497
58100
  "personal-capability.json",
57498
58101
  "received-capabilities.json",
@@ -57501,9 +58104,9 @@ var LEGACY_FILES = [
57501
58104
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
57502
58105
  const removed = [];
57503
58106
  for (const name of LEGACY_FILES) {
57504
- const p2 = path43.join(dataDir, name);
58107
+ const p2 = path45.join(dataDir, name);
57505
58108
  try {
57506
- await fs41.unlink(p2);
58109
+ await fs43.unlink(p2);
57507
58110
  removed.push(name);
57508
58111
  logger.debug("legacy capability file removed", { file: name });
57509
58112
  } catch (err) {
@@ -57515,13 +58118,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
57515
58118
  }
57516
58119
 
57517
58120
  // src/inbox/inbox-store.ts
57518
- var fs42 = __toESM(require("fs"), 1);
57519
- var path44 = __toESM(require("path"), 1);
58121
+ var fs44 = __toESM(require("fs"), 1);
58122
+ var path46 = __toESM(require("path"), 1);
57520
58123
  var INBOX_SUBDIR = "inbox";
57521
58124
  var InboxStore = class {
57522
58125
  constructor(dataDir) {
57523
58126
  this.dataDir = dataDir;
57524
- fs42.mkdirSync(this.dirPath(), { recursive: true });
58127
+ fs44.mkdirSync(this.dirPath(), { recursive: true });
57525
58128
  }
57526
58129
  dataDir;
57527
58130
  /**
@@ -57533,7 +58136,7 @@ var InboxStore = class {
57533
58136
  const file = this.filePath(peerDeviceId);
57534
58137
  let raw;
57535
58138
  try {
57536
- raw = fs42.readFileSync(file, "utf8");
58139
+ raw = fs44.readFileSync(file, "utf8");
57537
58140
  } catch (err) {
57538
58141
  if (err?.code === "ENOENT") return [];
57539
58142
  return [];
@@ -57549,7 +58152,7 @@ var InboxStore = class {
57549
58152
  const dir = this.dirPath();
57550
58153
  let entries;
57551
58154
  try {
57552
- entries = fs42.readdirSync(dir);
58155
+ entries = fs44.readdirSync(dir);
57553
58156
  } catch (err) {
57554
58157
  if (err?.code === "ENOENT") return [];
57555
58158
  return [];
@@ -57565,9 +58168,9 @@ var InboxStore = class {
57565
58168
  if (existing.some((m2) => m2.id === message.id)) return;
57566
58169
  const file = this.filePath(message.peerDeviceId);
57567
58170
  const line = JSON.stringify(message) + "\n";
57568
- fs42.appendFileSync(file, line, { mode: 384 });
58171
+ fs44.appendFileSync(file, line, { mode: 384 });
57569
58172
  try {
57570
- fs42.chmodSync(file, 384);
58173
+ fs44.chmodSync(file, 384);
57571
58174
  } catch {
57572
58175
  }
57573
58176
  }
@@ -57597,7 +58200,7 @@ var InboxStore = class {
57597
58200
  removeByPeerDeviceId(peerDeviceId) {
57598
58201
  const file = this.filePath(peerDeviceId);
57599
58202
  try {
57600
- fs42.unlinkSync(file);
58203
+ fs44.unlinkSync(file);
57601
58204
  } catch (err) {
57602
58205
  if (err?.code === "ENOENT") return;
57603
58206
  }
@@ -57606,18 +58209,18 @@ var InboxStore = class {
57606
58209
  const file = this.filePath(peerDeviceId);
57607
58210
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
57608
58211
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
57609
- fs42.writeFileSync(tmp, content, { mode: 384 });
57610
- fs42.renameSync(tmp, file);
58212
+ fs44.writeFileSync(tmp, content, { mode: 384 });
58213
+ fs44.renameSync(tmp, file);
57611
58214
  try {
57612
- fs42.chmodSync(file, 384);
58215
+ fs44.chmodSync(file, 384);
57613
58216
  } catch {
57614
58217
  }
57615
58218
  }
57616
58219
  dirPath() {
57617
- return path44.join(this.dataDir, INBOX_SUBDIR);
58220
+ return path46.join(this.dataDir, INBOX_SUBDIR);
57618
58221
  }
57619
58222
  filePath(peerDeviceId) {
57620
- return path44.join(this.dirPath(), `${peerDeviceId}.jsonl`);
58223
+ return path46.join(this.dirPath(), `${peerDeviceId}.jsonl`);
57621
58224
  }
57622
58225
  };
57623
58226
  function parseAllLines(raw) {
@@ -57705,8 +58308,8 @@ var InboxManager = class {
57705
58308
  };
57706
58309
 
57707
58310
  // src/state/contact-store.ts
57708
- var fs43 = __toESM(require("fs"), 1);
57709
- var path45 = __toESM(require("path"), 1);
58311
+ var fs45 = __toESM(require("fs"), 1);
58312
+ var path47 = __toESM(require("path"), 1);
57710
58313
  var FILE_NAME = "contacts.json";
57711
58314
  var ContactStore = class {
57712
58315
  constructor(dataDir) {
@@ -57716,10 +58319,10 @@ var ContactStore = class {
57716
58319
  contacts = /* @__PURE__ */ new Map();
57717
58320
  load() {
57718
58321
  this.contacts.clear();
57719
- const file = path45.join(this.dataDir, FILE_NAME);
58322
+ const file = path47.join(this.dataDir, FILE_NAME);
57720
58323
  let raw;
57721
58324
  try {
57722
- raw = fs43.readFileSync(file, "utf8");
58325
+ raw = fs45.readFileSync(file, "utf8");
57723
58326
  } catch (err) {
57724
58327
  if (err?.code !== "ENOENT") this.renameBak(file);
57725
58328
  return;
@@ -57800,20 +58403,20 @@ var ContactStore = class {
57800
58403
  return true;
57801
58404
  }
57802
58405
  flush() {
57803
- const file = path45.join(this.dataDir, FILE_NAME);
58406
+ const file = path47.join(this.dataDir, FILE_NAME);
57804
58407
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
57805
58408
  const content = JSON.stringify(
57806
58409
  { contacts: Array.from(this.contacts.values()) },
57807
58410
  null,
57808
58411
  2
57809
58412
  );
57810
- fs43.mkdirSync(this.dataDir, { recursive: true });
57811
- fs43.writeFileSync(tmp, content, { mode: 384 });
57812
- fs43.renameSync(tmp, file);
58413
+ fs45.mkdirSync(this.dataDir, { recursive: true });
58414
+ fs45.writeFileSync(tmp, content, { mode: 384 });
58415
+ fs45.renameSync(tmp, file);
57813
58416
  }
57814
58417
  renameBak(file) {
57815
58418
  try {
57816
- fs43.renameSync(file, `${file}.bak`);
58419
+ fs45.renameSync(file, `${file}.bak`);
57817
58420
  } catch {
57818
58421
  }
57819
58422
  }
@@ -57921,61 +58524,61 @@ async function connectRemote(args) {
57921
58524
  }
57922
58525
 
57923
58526
  // src/migrations/2026-05-20-flatten-sessions.ts
57924
- var fs44 = __toESM(require("fs"), 1);
57925
- var path46 = __toESM(require("path"), 1);
58527
+ var fs46 = __toESM(require("fs"), 1);
58528
+ var path48 = __toESM(require("path"), 1);
57926
58529
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
57927
58530
  function migrateFlattenSessions(opts) {
57928
58531
  const dataDir = opts.dataDir;
57929
58532
  const now = opts.now ?? Date.now;
57930
- const sessionsDir = path46.join(dataDir, "sessions");
57931
- const flagPath = path46.join(sessionsDir, MIGRATION_FLAG_NAME);
58533
+ const sessionsDir = path48.join(dataDir, "sessions");
58534
+ const flagPath = path48.join(sessionsDir, MIGRATION_FLAG_NAME);
57932
58535
  if (existsSync3(flagPath)) {
57933
58536
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
57934
58537
  }
57935
58538
  let movedBare = 0;
57936
58539
  let movedVmOwner = 0;
57937
58540
  let archivedListener = 0;
57938
- const defaultDir = path46.join(sessionsDir, "default");
58541
+ const defaultDir = path48.join(sessionsDir, "default");
57939
58542
  if (existsSync3(defaultDir)) {
57940
58543
  for (const entry of readdirSafe(defaultDir)) {
57941
58544
  if (!entry.endsWith(".json")) continue;
57942
- const src = path46.join(defaultDir, entry);
57943
- const dst = path46.join(sessionsDir, entry);
57944
- fs44.renameSync(src, dst);
58545
+ const src = path48.join(defaultDir, entry);
58546
+ const dst = path48.join(sessionsDir, entry);
58547
+ fs46.renameSync(src, dst);
57945
58548
  movedBare += 1;
57946
58549
  }
57947
58550
  rmdirIfEmpty(defaultDir);
57948
58551
  }
57949
58552
  for (const pid of readdirSafe(sessionsDir)) {
57950
- const personaDir = path46.join(sessionsDir, pid);
58553
+ const personaDir = path48.join(sessionsDir, pid);
57951
58554
  if (!isDir(personaDir)) continue;
57952
58555
  if (pid === "default") continue;
57953
- const ownerSrc = path46.join(personaDir, "owner");
58556
+ const ownerSrc = path48.join(personaDir, "owner");
57954
58557
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
57955
- const ownerDst = path46.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
57956
- fs44.mkdirSync(ownerDst, { recursive: true });
58558
+ const ownerDst = path48.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
58559
+ fs46.mkdirSync(ownerDst, { recursive: true });
57957
58560
  for (const file of readdirSafe(ownerSrc)) {
57958
58561
  if (!file.endsWith(".json")) continue;
57959
- fs44.renameSync(path46.join(ownerSrc, file), path46.join(ownerDst, file));
58562
+ fs46.renameSync(path48.join(ownerSrc, file), path48.join(ownerDst, file));
57960
58563
  movedVmOwner += 1;
57961
58564
  }
57962
58565
  rmdirIfEmpty(ownerSrc);
57963
58566
  }
57964
- const listenerSrc = path46.join(personaDir, "listener");
58567
+ const listenerSrc = path48.join(personaDir, "listener");
57965
58568
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
57966
- const archiveDst = path46.join(dataDir, ".legacy", `listener-${pid}`);
57967
- fs44.mkdirSync(archiveDst, { recursive: true });
58569
+ const archiveDst = path48.join(dataDir, ".legacy", `listener-${pid}`);
58570
+ fs46.mkdirSync(archiveDst, { recursive: true });
57968
58571
  for (const file of readdirSafe(listenerSrc)) {
57969
58572
  if (!file.endsWith(".json")) continue;
57970
- fs44.renameSync(path46.join(listenerSrc, file), path46.join(archiveDst, file));
58573
+ fs46.renameSync(path48.join(listenerSrc, file), path48.join(archiveDst, file));
57971
58574
  archivedListener += 1;
57972
58575
  }
57973
58576
  rmdirIfEmpty(listenerSrc);
57974
58577
  }
57975
58578
  rmdirIfEmpty(personaDir);
57976
58579
  }
57977
- fs44.mkdirSync(sessionsDir, { recursive: true });
57978
- fs44.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
58580
+ fs46.mkdirSync(sessionsDir, { recursive: true });
58581
+ fs46.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
57979
58582
  return {
57980
58583
  skipped: false,
57981
58584
  flagWritten: true,
@@ -57986,7 +58589,7 @@ function migrateFlattenSessions(opts) {
57986
58589
  }
57987
58590
  function existsSync3(p2) {
57988
58591
  try {
57989
- fs44.statSync(p2);
58592
+ fs46.statSync(p2);
57990
58593
  return true;
57991
58594
  } catch {
57992
58595
  return false;
@@ -57994,61 +58597,61 @@ function existsSync3(p2) {
57994
58597
  }
57995
58598
  function isDir(p2) {
57996
58599
  try {
57997
- return fs44.statSync(p2).isDirectory();
58600
+ return fs46.statSync(p2).isDirectory();
57998
58601
  } catch {
57999
58602
  return false;
58000
58603
  }
58001
58604
  }
58002
58605
  function readdirSafe(p2) {
58003
58606
  try {
58004
- return fs44.readdirSync(p2);
58607
+ return fs46.readdirSync(p2);
58005
58608
  } catch {
58006
58609
  return [];
58007
58610
  }
58008
58611
  }
58009
58612
  function rmdirIfEmpty(p2) {
58010
58613
  try {
58011
- fs44.rmdirSync(p2);
58614
+ fs46.rmdirSync(p2);
58012
58615
  } catch {
58013
58616
  }
58014
58617
  }
58015
58618
 
58016
58619
  // src/migrations/2026-08-18-drop-seeded-projects.ts
58017
- var fs45 = __toESM(require("fs"), 1);
58018
- var path47 = __toESM(require("path"), 1);
58620
+ var fs47 = __toESM(require("fs"), 1);
58621
+ var path49 = __toESM(require("path"), 1);
58019
58622
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
58020
58623
  function dropSeededProjects(opts) {
58021
- fs45.mkdirSync(opts.dataDir, { recursive: true });
58022
- const flag = path47.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
58023
- if (fs45.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
58024
- const file = path47.join(opts.dataDir, "projects.json");
58624
+ fs47.mkdirSync(opts.dataDir, { recursive: true });
58625
+ const flag = path49.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
58626
+ if (fs47.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
58627
+ const file = path49.join(opts.dataDir, "projects.json");
58025
58628
  let raw = null;
58026
58629
  let dropped = 0;
58027
58630
  try {
58028
- raw = fs45.readFileSync(file, "utf8");
58631
+ raw = fs47.readFileSync(file, "utf8");
58029
58632
  dropped = JSON.parse(raw).projects?.length ?? 0;
58030
58633
  } catch {
58031
58634
  }
58032
58635
  let backup = null;
58033
58636
  if (raw != null && dropped > 0) {
58034
- const dir = path47.join(opts.dataDir, "backups");
58035
- fs45.mkdirSync(dir, { recursive: true });
58036
- backup = path47.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
58037
- fs45.writeFileSync(backup, raw);
58637
+ const dir = path49.join(opts.dataDir, "backups");
58638
+ fs47.mkdirSync(dir, { recursive: true });
58639
+ backup = path49.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
58640
+ fs47.writeFileSync(backup, raw);
58038
58641
  }
58039
58642
  if (raw != null || dropped > 0) {
58040
- fs45.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58643
+ fs47.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58041
58644
  }
58042
- fs45.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58645
+ fs47.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58043
58646
  return { skipped: false, dropped, backup };
58044
58647
  }
58045
58648
 
58046
58649
  // src/transport/http-router.ts
58047
58650
  var import_node_fs34 = __toESM(require("fs"), 1);
58048
- var import_node_path39 = __toESM(require("path"), 1);
58651
+ var import_node_path41 = __toESM(require("path"), 1);
58049
58652
 
58050
58653
  // src/attachment/mime.ts
58051
- var import_node_path36 = __toESM(require("path"), 1);
58654
+ var import_node_path38 = __toESM(require("path"), 1);
58052
58655
  var TEXT_PLAIN = "text/plain; charset=utf-8";
58053
58656
  var EXT_TO_NATIVE_MIME = {
58054
58657
  // 图片
@@ -58155,7 +58758,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
58155
58758
  ".mk"
58156
58759
  ]);
58157
58760
  function lookupMime(filePathOrName) {
58158
- const ext = import_node_path36.default.extname(filePathOrName).toLowerCase();
58761
+ const ext = import_node_path38.default.extname(filePathOrName).toLowerCase();
58159
58762
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
58160
58763
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
58161
58764
  return "application/octet-stream";
@@ -58226,9 +58829,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
58226
58829
 
58227
58830
  // src/attachment/upload.ts
58228
58831
  var import_node_fs33 = __toESM(require("fs"), 1);
58229
- var import_node_path37 = __toESM(require("path"), 1);
58832
+ var import_node_path39 = __toESM(require("path"), 1);
58230
58833
  var import_node_crypto10 = __toESM(require("crypto"), 1);
58231
- var import_promises5 = require("stream/promises");
58834
+ var import_promises7 = require("stream/promises");
58232
58835
  var UploadError = class extends Error {
58233
58836
  constructor(code, message) {
58234
58837
  super(message);
@@ -58238,14 +58841,14 @@ var UploadError = class extends Error {
58238
58841
  code;
58239
58842
  };
58240
58843
  function assertValidFileName(fileName) {
58241
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path37.default.basename(fileName)) {
58844
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path39.default.basename(fileName)) {
58242
58845
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
58243
58846
  }
58244
58847
  }
58245
58848
  var HASH_PREFIX_LEN = 16;
58246
58849
  async function writeUploadedAttachment(args) {
58247
58850
  assertValidFileName(args.fileName);
58248
- const attachmentsRoot = import_node_path37.default.join(args.baseDir, ".attachments");
58851
+ const attachmentsRoot = import_node_path39.default.join(args.baseDir, ".attachments");
58249
58852
  try {
58250
58853
  import_node_fs33.default.mkdirSync(attachmentsRoot, { recursive: true });
58251
58854
  } catch (err) {
@@ -58253,12 +58856,12 @@ async function writeUploadedAttachment(args) {
58253
58856
  }
58254
58857
  const hasher = import_node_crypto10.default.createHash("sha256");
58255
58858
  let actualSize = 0;
58256
- const tmpPath = import_node_path37.default.join(
58859
+ const tmpPath = import_node_path39.default.join(
58257
58860
  attachmentsRoot,
58258
58861
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto10.default.randomBytes(4).toString("hex")}`
58259
58862
  );
58260
58863
  try {
58261
- await (0, import_promises5.pipeline)(
58864
+ await (0, import_promises7.pipeline)(
58262
58865
  args.body,
58263
58866
  async function* (source) {
58264
58867
  for await (const chunk of source) {
@@ -58288,7 +58891,7 @@ async function writeUploadedAttachment(args) {
58288
58891
  );
58289
58892
  }
58290
58893
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
58291
- const hashDir = import_node_path37.default.join(attachmentsRoot, attachmentId);
58894
+ const hashDir = import_node_path39.default.join(attachmentsRoot, attachmentId);
58292
58895
  let finalFileName;
58293
58896
  let hashDirExists = false;
58294
58897
  try {
@@ -58306,7 +58909,7 @@ async function writeUploadedAttachment(args) {
58306
58909
  try {
58307
58910
  import_node_fs33.default.mkdirSync(hashDir, { recursive: true });
58308
58911
  finalFileName = args.fileName;
58309
- import_node_fs33.default.renameSync(tmpPath, import_node_path37.default.join(hashDir, finalFileName));
58912
+ import_node_fs33.default.renameSync(tmpPath, import_node_path39.default.join(hashDir, finalFileName));
58310
58913
  } catch (err) {
58311
58914
  try {
58312
58915
  import_node_fs33.default.unlinkSync(tmpPath);
@@ -58315,7 +58918,7 @@ async function writeUploadedAttachment(args) {
58315
58918
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
58316
58919
  }
58317
58920
  }
58318
- const absPath = import_node_path37.default.join(hashDir, finalFileName);
58921
+ const absPath = import_node_path39.default.join(hashDir, finalFileName);
58319
58922
  const relPath = absPath;
58320
58923
  args.groupFileStore.upsert(args.scope, args.sessionId, {
58321
58924
  relPath: absPath,
@@ -58329,8 +58932,8 @@ async function writeUploadedAttachment(args) {
58329
58932
  }
58330
58933
 
58331
58934
  // src/extension/import.ts
58332
- var import_promises6 = __toESM(require("fs/promises"), 1);
58333
- var import_node_path38 = __toESM(require("path"), 1);
58935
+ var import_promises8 = __toESM(require("fs/promises"), 1);
58936
+ var import_node_path40 = __toESM(require("path"), 1);
58334
58937
  var import_node_os13 = __toESM(require("os"), 1);
58335
58938
  var import_jszip = __toESM(require_lib3(), 1);
58336
58939
  var ImportError = class extends Error {
@@ -58348,7 +58951,7 @@ async function importZip(buf, root) {
58348
58951
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
58349
58952
  }
58350
58953
  for (const name of Object.keys(zip.files)) {
58351
- if (name.includes("..") || name.startsWith("/") || import_node_path38.default.isAbsolute(name)) {
58954
+ if (name.includes("..") || name.startsWith("/") || import_node_path40.default.isAbsolute(name)) {
58352
58955
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
58353
58956
  }
58354
58957
  }
@@ -58381,33 +58984,33 @@ async function importZip(buf, root) {
58381
58984
  );
58382
58985
  }
58383
58986
  }
58384
- const destDir = import_node_path38.default.join(root, manifest.id);
58987
+ const destDir = import_node_path40.default.join(root, manifest.id);
58385
58988
  let destExists = false;
58386
58989
  try {
58387
- await import_promises6.default.access(destDir);
58990
+ await import_promises8.default.access(destDir);
58388
58991
  destExists = true;
58389
58992
  } catch {
58390
58993
  }
58391
58994
  if (destExists) {
58392
58995
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
58393
58996
  }
58394
- const stage = await import_promises6.default.mkdtemp(import_node_path38.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
58997
+ const stage = await import_promises8.default.mkdtemp(import_node_path40.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
58395
58998
  try {
58396
58999
  for (const [name, entry] of Object.entries(zip.files)) {
58397
- const dest = import_node_path38.default.join(stage, name);
59000
+ const dest = import_node_path40.default.join(stage, name);
58398
59001
  if (entry.dir) {
58399
- await import_promises6.default.mkdir(dest, { recursive: true });
59002
+ await import_promises8.default.mkdir(dest, { recursive: true });
58400
59003
  continue;
58401
59004
  }
58402
- await import_promises6.default.mkdir(import_node_path38.default.dirname(dest), { recursive: true });
59005
+ await import_promises8.default.mkdir(import_node_path40.default.dirname(dest), { recursive: true });
58403
59006
  const content = await entry.async("nodebuffer");
58404
- await import_promises6.default.writeFile(dest, content);
59007
+ await import_promises8.default.writeFile(dest, content);
58405
59008
  }
58406
- await import_promises6.default.mkdir(root, { recursive: true });
58407
- await import_promises6.default.rename(stage, destDir);
59009
+ await import_promises8.default.mkdir(root, { recursive: true });
59010
+ await import_promises8.default.rename(stage, destDir);
58408
59011
  return { extId: manifest.id };
58409
59012
  } catch (e) {
58410
- await import_promises6.default.rm(stage, { recursive: true, force: true }).catch(() => {
59013
+ await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
58411
59014
  });
58412
59015
  throw e;
58413
59016
  }
@@ -58429,7 +59032,7 @@ var SHARE_UI_ASSET_MIME = {
58429
59032
  ".wasm": "application/wasm"
58430
59033
  };
58431
59034
  function shareUiAssetMime(filePath) {
58432
- const ext = import_node_path39.default.extname(filePath).toLowerCase();
59035
+ const ext = import_node_path41.default.extname(filePath).toLowerCase();
58433
59036
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
58434
59037
  }
58435
59038
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -58528,7 +59131,7 @@ function isValidUploadFileName(fileName) {
58528
59131
  if (fileName === "." || fileName === "..") return false;
58529
59132
  if (fileName.startsWith(".")) return false;
58530
59133
  if (fileName.includes("/") || fileName.includes("\\")) return false;
58531
- return fileName === import_node_path39.default.basename(fileName);
59134
+ return fileName === import_node_path41.default.basename(fileName);
58532
59135
  }
58533
59136
  function createHttpRouter(deps) {
58534
59137
  return async (req, res) => {
@@ -58764,7 +59367,7 @@ function createHttpRouter(deps) {
58764
59367
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
58765
59368
  return true;
58766
59369
  }
58767
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path39.default.basename(r.absPath)));
59370
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path41.default.basename(r.absPath)));
58768
59371
  return true;
58769
59372
  }
58770
59373
  const ctx = deps.authResolver.resolveFromHeader(
@@ -58885,7 +59488,7 @@ function createHttpRouter(deps) {
58885
59488
  return true;
58886
59489
  }
58887
59490
  let absPath;
58888
- if (import_node_path39.default.isAbsolute(pathParam)) {
59491
+ if (import_node_path41.default.isAbsolute(pathParam)) {
58889
59492
  absPath = pathParam;
58890
59493
  } else if (deps.sessionStore) {
58891
59494
  const file = deps.sessionStore.read(sid);
@@ -58893,7 +59496,7 @@ function createHttpRouter(deps) {
58893
59496
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
58894
59497
  return true;
58895
59498
  }
58896
- absPath = import_node_path39.default.join(file.cwd, pathParam);
59499
+ absPath = import_node_path41.default.join(file.cwd, pathParam);
58897
59500
  } else {
58898
59501
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
58899
59502
  return true;
@@ -58995,7 +59598,7 @@ function streamFile(res, absPath, logger) {
58995
59598
  return;
58996
59599
  }
58997
59600
  const mime = lookupMime(absPath);
58998
- const basename2 = import_node_path39.default.basename(absPath);
59601
+ const basename2 = import_node_path41.default.basename(absPath);
58999
59602
  res.writeHead(200, {
59000
59603
  "Content-Type": mime,
59001
59604
  "Content-Length": String(stat.size),
@@ -59013,7 +59616,7 @@ function streamFile(res, absPath, logger) {
59013
59616
 
59014
59617
  // src/attachment/gc.ts
59015
59618
  var import_node_fs35 = __toESM(require("fs"), 1);
59016
- var import_node_path40 = __toESM(require("path"), 1);
59619
+ var import_node_path42 = __toESM(require("path"), 1);
59017
59620
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
59018
59621
  function runAttachmentGc(args) {
59019
59622
  const now = (args.now ?? Date.now)();
@@ -59022,12 +59625,12 @@ function runAttachmentGc(args) {
59022
59625
  for (const { scope, sessionId } of args.sessionScopes) {
59023
59626
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
59024
59627
  if (entry.stale) continue;
59025
- if (import_node_path40.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
59628
+ if (import_node_path42.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
59026
59629
  }
59027
59630
  }
59028
59631
  const visited = /* @__PURE__ */ new Set();
59029
59632
  for (const { scope, sessionId } of args.sessionScopes) {
59030
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path40.default.join(
59633
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path42.default.join(
59031
59634
  args.dataDir,
59032
59635
  "sessions",
59033
59636
  ...scopeSubPath(scope).map(safeFileName),
@@ -59040,7 +59643,7 @@ function runAttachmentGc(args) {
59040
59643
  return true;
59041
59644
  });
59042
59645
  for (const rootDir of roots) {
59043
- const attRoot = import_node_path40.default.join(rootDir, ".attachments");
59646
+ const attRoot = import_node_path42.default.join(rootDir, ".attachments");
59044
59647
  let hashDirs;
59045
59648
  try {
59046
59649
  hashDirs = import_node_fs35.default.readdirSync(attRoot);
@@ -59050,7 +59653,7 @@ function runAttachmentGc(args) {
59050
59653
  continue;
59051
59654
  }
59052
59655
  for (const hashDir of hashDirs) {
59053
- const hashDirAbs = import_node_path40.default.join(attRoot, hashDir);
59656
+ const hashDirAbs = import_node_path42.default.join(attRoot, hashDir);
59054
59657
  let files;
59055
59658
  try {
59056
59659
  files = import_node_fs35.default.readdirSync(hashDirAbs);
@@ -59058,7 +59661,7 @@ function runAttachmentGc(args) {
59058
59661
  continue;
59059
59662
  }
59060
59663
  for (const name of files) {
59061
- const file = import_node_path40.default.join(hashDirAbs, name);
59664
+ const file = import_node_path42.default.join(hashDirAbs, name);
59062
59665
  let stat;
59063
59666
  try {
59064
59667
  stat = import_node_fs35.default.statSync(file);
@@ -59090,7 +59693,7 @@ function runAttachmentGc(args) {
59090
59693
 
59091
59694
  // src/attachment/group.ts
59092
59695
  var import_node_fs36 = __toESM(require("fs"), 1);
59093
- var import_node_path41 = __toESM(require("path"), 1);
59696
+ var import_node_path43 = __toESM(require("path"), 1);
59094
59697
  var import_node_crypto11 = __toESM(require("crypto"), 1);
59095
59698
  init_protocol();
59096
59699
  var GroupFileStore = class {
@@ -59102,11 +59705,11 @@ var GroupFileStore = class {
59102
59705
  this.logger = opts.logger;
59103
59706
  }
59104
59707
  rootForScope(scope) {
59105
- return import_node_path41.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
59708
+ return import_node_path43.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
59106
59709
  }
59107
59710
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
59108
59711
  filePath(scope, sessionId) {
59109
- return import_node_path41.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
59712
+ return import_node_path43.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
59110
59713
  }
59111
59714
  cacheKey(scope, sessionId) {
59112
59715
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -59141,7 +59744,7 @@ var GroupFileStore = class {
59141
59744
  }
59142
59745
  writeFile(scope, sessionId, entries) {
59143
59746
  const file = this.filePath(scope, sessionId);
59144
- import_node_fs36.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true });
59747
+ import_node_fs36.default.mkdirSync(import_node_path43.default.dirname(file), { recursive: true });
59145
59748
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
59146
59749
  import_node_fs36.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
59147
59750
  import_node_fs36.default.renameSync(tmp, file);
@@ -59231,9 +59834,9 @@ var GroupFileStore = class {
59231
59834
 
59232
59835
  // src/discovery/state-file.ts
59233
59836
  var import_node_fs37 = __toESM(require("fs"), 1);
59234
- var import_node_path42 = __toESM(require("path"), 1);
59837
+ var import_node_path44 = __toESM(require("path"), 1);
59235
59838
  function defaultStateFilePath(dataDir) {
59236
- return import_node_path42.default.join(dataDir, "state.json");
59839
+ return import_node_path44.default.join(dataDir, "state.json");
59237
59840
  }
59238
59841
  function isPidAlive(pid) {
59239
59842
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -59269,7 +59872,7 @@ var StateFileManager = class {
59269
59872
  return { status: "stale", existing };
59270
59873
  }
59271
59874
  write(state) {
59272
- import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(this.file), { recursive: true });
59875
+ import_node_fs37.default.mkdirSync(import_node_path44.default.dirname(this.file), { recursive: true });
59273
59876
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
59274
59877
  import_node_fs37.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
59275
59878
  import_node_fs37.default.renameSync(tmp, this.file);
@@ -59297,13 +59900,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
59297
59900
 
59298
59901
  // src/tunnel/tunnel-manager.ts
59299
59902
  var import_node_fs41 = __toESM(require("fs"), 1);
59300
- var import_node_path46 = __toESM(require("path"), 1);
59903
+ var import_node_path48 = __toESM(require("path"), 1);
59301
59904
  var import_node_crypto12 = __toESM(require("crypto"), 1);
59302
59905
  var import_node_child_process11 = require("child_process");
59303
59906
 
59304
59907
  // src/tunnel/tunnel-store.ts
59305
59908
  var import_node_fs38 = __toESM(require("fs"), 1);
59306
- var import_node_path43 = __toESM(require("path"), 1);
59909
+ var import_node_path45 = __toESM(require("path"), 1);
59307
59910
  var TunnelStore = class {
59308
59911
  constructor(filePath) {
59309
59912
  this.filePath = filePath;
@@ -59322,7 +59925,7 @@ var TunnelStore = class {
59322
59925
  }
59323
59926
  }
59324
59927
  async set(v2) {
59325
- const dir = import_node_path43.default.dirname(this.filePath);
59928
+ const dir = import_node_path45.default.dirname(this.filePath);
59326
59929
  await import_node_fs38.default.promises.mkdir(dir, { recursive: true });
59327
59930
  const data = JSON.stringify(v2, null, 2);
59328
59931
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -59434,10 +60037,10 @@ function escape(v2) {
59434
60037
  // src/tunnel/frpc-binary.ts
59435
60038
  var import_node_fs39 = __toESM(require("fs"), 1);
59436
60039
  var import_node_os14 = __toESM(require("os"), 1);
59437
- var import_node_path44 = __toESM(require("path"), 1);
60040
+ var import_node_path46 = __toESM(require("path"), 1);
59438
60041
  var import_node_child_process9 = require("child_process");
59439
60042
  var import_node_stream3 = require("stream");
59440
- var import_promises7 = require("stream/promises");
60043
+ var import_promises9 = require("stream/promises");
59441
60044
  var FRPC_VERSION = "0.68.0";
59442
60045
  var UnsupportedPlatformError = class extends Error {
59443
60046
  constructor(platform, arch) {
@@ -59473,13 +60076,13 @@ async function ensureFrpcBinary(opts) {
59473
60076
  }
59474
60077
  const version2 = opts.version ?? FRPC_VERSION;
59475
60078
  const platform = opts.platform ?? detectPlatform();
59476
- const binDir = import_node_path44.default.join(opts.dataDir, "bin");
60079
+ const binDir = import_node_path46.default.join(opts.dataDir, "bin");
59477
60080
  import_node_fs39.default.mkdirSync(binDir, { recursive: true });
59478
60081
  cleanupStaleArtifacts(binDir);
59479
- const stableBin = import_node_path44.default.join(binDir, "frpc");
60082
+ const stableBin = import_node_path46.default.join(binDir, "frpc");
59480
60083
  if (import_node_fs39.default.existsSync(stableBin)) return stableBin;
59481
60084
  const partialBin = `${stableBin}.partial`;
59482
- const tarballPath = import_node_path44.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
60085
+ const tarballPath = import_node_path46.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
59483
60086
  try {
59484
60087
  const url = frpcDownloadUrl(version2, platform);
59485
60088
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -59505,7 +60108,7 @@ function cleanupStaleArtifacts(binDir) {
59505
60108
  }
59506
60109
  for (const name of entries) {
59507
60110
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
59508
- const full = import_node_path44.default.join(binDir, name);
60111
+ const full = import_node_path46.default.join(binDir, name);
59509
60112
  try {
59510
60113
  import_node_fs39.default.rmSync(full, { recursive: true, force: true });
59511
60114
  } catch {
@@ -59528,10 +60131,10 @@ async function downloadToFile(url, dest, fetchImpl) {
59528
60131
  }
59529
60132
  const out = import_node_fs39.default.createWriteStream(dest);
59530
60133
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
59531
- await (0, import_promises7.pipeline)(nodeStream, out);
60134
+ await (0, import_promises9.pipeline)(nodeStream, out);
59532
60135
  }
59533
60136
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
59534
- const work = import_node_path44.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
60137
+ const work = import_node_path46.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
59535
60138
  import_node_fs39.default.mkdirSync(work, { recursive: true });
59536
60139
  try {
59537
60140
  await new Promise((resolve9, reject) => {
@@ -59540,7 +60143,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
59540
60143
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
59541
60144
  });
59542
60145
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
59543
- const src = import_node_path44.default.join(work, dirName, "frpc");
60146
+ const src = import_node_path46.default.join(work, dirName, "frpc");
59544
60147
  if (!import_node_fs39.default.existsSync(src)) {
59545
60148
  throw new Error(`frpc not found inside tarball at ${src}`);
59546
60149
  }
@@ -59552,10 +60155,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
59552
60155
 
59553
60156
  // src/tunnel/frpc-process.ts
59554
60157
  var import_node_fs40 = __toESM(require("fs"), 1);
59555
- var import_node_path45 = __toESM(require("path"), 1);
60158
+ var import_node_path47 = __toESM(require("path"), 1);
59556
60159
  var import_node_child_process10 = require("child_process");
59557
60160
  function frpcPidFilePath(dataDir) {
59558
- return import_node_path45.default.join(dataDir, "frpc.pid");
60161
+ return import_node_path47.default.join(dataDir, "frpc.pid");
59559
60162
  }
59560
60163
  function writeFrpcPid(dataDir, pid) {
59561
60164
  try {
@@ -59597,7 +60200,7 @@ function defaultSleep2(ms) {
59597
60200
  }
59598
60201
  async function killStaleFrpc(deps) {
59599
60202
  const pidFile = frpcPidFilePath(deps.dataDir);
59600
- const tomlPath = import_node_path45.default.join(deps.dataDir, "frpc.toml");
60203
+ const tomlPath = import_node_path47.default.join(deps.dataDir, "frpc.toml");
59601
60204
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
59602
60205
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
59603
60206
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -59669,7 +60272,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
59669
60272
  var TunnelManager = class {
59670
60273
  constructor(deps) {
59671
60274
  this.deps = deps;
59672
- this.store = deps.store ?? new TunnelStore(import_node_path46.default.join(deps.dataDir, "tunnel.json"));
60275
+ this.store = deps.store ?? new TunnelStore(import_node_path48.default.join(deps.dataDir, "tunnel.json"));
59673
60276
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
59674
60277
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
59675
60278
  }
@@ -59796,7 +60399,7 @@ var TunnelManager = class {
59796
60399
  dataDir: this.deps.dataDir,
59797
60400
  override: this.deps.frpcBinaryOverride ?? void 0
59798
60401
  });
59799
- const tomlPath = import_node_path46.default.join(this.deps.dataDir, "frpc.toml");
60402
+ const tomlPath = import_node_path48.default.join(this.deps.dataDir, "frpc.toml");
59800
60403
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto12.default.randomBytes(3).toString("hex")}`;
59801
60404
  const toml = buildFrpcToml({
59802
60405
  serverAddr: t.frpsHost,
@@ -59811,9 +60414,9 @@ var TunnelManager = class {
59811
60414
  const proc = (this.deps.spawnImpl ?? import_node_child_process11.spawn)(frpcBin, ["-c", tomlPath], {
59812
60415
  stdio: ["ignore", "pipe", "pipe"]
59813
60416
  });
59814
- const logDir = import_node_path46.default.join(this.deps.dataDir, "log");
60417
+ const logDir = import_node_path48.default.join(this.deps.dataDir, "log");
59815
60418
  import_node_fs41.default.mkdirSync(logDir, { recursive: true });
59816
- const logFilePath = import_node_path46.default.join(logDir, "frpc.log");
60419
+ const logFilePath = import_node_path48.default.join(logDir, "frpc.log");
59817
60420
  const logStream = import_node_fs41.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
59818
60421
  logStream.on("error", () => {
59819
60422
  });
@@ -59897,15 +60500,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
59897
60500
 
59898
60501
  // src/tunnel/device-key.ts
59899
60502
  var import_node_os15 = __toESM(require("os"), 1);
59900
- var import_node_path47 = __toESM(require("path"), 1);
60503
+ var import_node_path49 = __toESM(require("path"), 1);
59901
60504
  var import_node_crypto13 = __toESM(require("crypto"), 1);
59902
60505
  var DERIVE_SALT = "clawd-tunnel-device-v1";
59903
60506
  function deriveStableDeviceKey(opts = {}) {
59904
60507
  const hostname = opts.hostname ?? import_node_os15.default.hostname();
59905
60508
  const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
59906
60509
  const home = opts.home ?? import_node_os15.default.homedir();
59907
- const defaultDataDir = import_node_path47.default.resolve(import_node_path47.default.join(home, ".clawd"));
59908
- const normalizedDataDir = opts.dataDir ? import_node_path47.default.resolve(opts.dataDir) : null;
60510
+ const defaultDataDir = import_node_path49.default.resolve(import_node_path49.default.join(home, ".clawd"));
60511
+ const normalizedDataDir = opts.dataDir ? import_node_path49.default.resolve(opts.dataDir) : null;
59909
60512
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
59910
60513
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
59911
60514
  return import_node_crypto13.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -59913,11 +60516,11 @@ function deriveStableDeviceKey(opts = {}) {
59913
60516
 
59914
60517
  // src/auth-store.ts
59915
60518
  var import_node_fs42 = __toESM(require("fs"), 1);
59916
- var import_node_path48 = __toESM(require("path"), 1);
60519
+ var import_node_path50 = __toESM(require("path"), 1);
59917
60520
  var import_node_crypto14 = __toESM(require("crypto"), 1);
59918
60521
  var AUTH_FILE_NAME = "auth.json";
59919
60522
  function authFilePath(dataDir) {
59920
- return import_node_path48.default.join(dataDir, AUTH_FILE_NAME);
60523
+ return import_node_path50.default.join(dataDir, AUTH_FILE_NAME);
59921
60524
  }
59922
60525
  function loadOrCreateAuthFile(opts) {
59923
60526
  const file = authFilePath(opts.dataDir);
@@ -59969,7 +60572,7 @@ function readAuthFile(file) {
59969
60572
  }
59970
60573
  }
59971
60574
  function writeAuthFile(file, content) {
59972
- import_node_fs42.default.mkdirSync(import_node_path48.default.dirname(file), { recursive: true });
60575
+ import_node_fs42.default.mkdirSync(import_node_path50.default.dirname(file), { recursive: true });
59973
60576
  import_node_fs42.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
59974
60577
  try {
59975
60578
  import_node_fs42.default.chmodSync(file, 384);
@@ -59980,10 +60583,10 @@ function writeAuthFile(file, content) {
59980
60583
  // src/owner-profile.ts
59981
60584
  var import_node_fs43 = __toESM(require("fs"), 1);
59982
60585
  var import_node_os16 = __toESM(require("os"), 1);
59983
- var import_node_path49 = __toESM(require("path"), 1);
60586
+ var import_node_path51 = __toESM(require("path"), 1);
59984
60587
  var PROFILE_FILENAME = "profile.json";
59985
60588
  function profilePath(dataDir) {
59986
- return import_node_path49.default.join(dataDir, PROFILE_FILENAME);
60589
+ return import_node_path51.default.join(dataDir, PROFILE_FILENAME);
59987
60590
  }
59988
60591
  function loadOwnerProfile(dataDir) {
59989
60592
  let raw;
@@ -60021,12 +60624,12 @@ function loadOwnerDisplayName(dataDir) {
60021
60624
 
60022
60625
  // src/feishu-auth/owner-identity-store.ts
60023
60626
  var import_node_fs44 = __toESM(require("fs"), 1);
60024
- var import_node_path50 = __toESM(require("path"), 1);
60627
+ var import_node_path52 = __toESM(require("path"), 1);
60025
60628
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
60026
60629
  var OwnerIdentityStore = class {
60027
60630
  file;
60028
60631
  constructor(dataDir) {
60029
- this.file = import_node_path50.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
60632
+ this.file = import_node_path52.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
60030
60633
  }
60031
60634
  read() {
60032
60635
  let raw;
@@ -60059,7 +60662,7 @@ var OwnerIdentityStore = class {
60059
60662
  };
60060
60663
  }
60061
60664
  write(record3) {
60062
- import_node_fs44.default.mkdirSync(import_node_path50.default.dirname(this.file), { recursive: true });
60665
+ import_node_fs44.default.mkdirSync(import_node_path52.default.dirname(this.file), { recursive: true });
60063
60666
  import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
60064
60667
  try {
60065
60668
  import_node_fs44.default.chmodSync(this.file, 384);
@@ -60205,9 +60808,9 @@ var CentralClientError = class extends Error {
60205
60808
  code;
60206
60809
  cause;
60207
60810
  };
60208
- async function centralRequest(opts, path91, init) {
60811
+ async function centralRequest(opts, path93, init) {
60209
60812
  const f = opts.fetchImpl ?? globalThis.fetch;
60210
- const url = `${opts.api.replace(/\/+$/, "")}${path91}`;
60813
+ const url = `${opts.api.replace(/\/+$/, "")}${path93}`;
60211
60814
  const ctrl = new AbortController();
60212
60815
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
60213
60816
  let res;
@@ -60461,7 +61064,7 @@ async function syncOrgMesh(deps) {
60461
61064
 
60462
61065
  // src/handlers/device.ts
60463
61066
  init_protocol();
60464
- function ensureOwner(ctx) {
61067
+ function ensureOwner2(ctx) {
60465
61068
  if (!ctx || ctx.principal.kind !== "owner") {
60466
61069
  throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: device:* requires owner ctx");
60467
61070
  }
@@ -60556,14 +61159,14 @@ function createConnectToDevice(deps) {
60556
61159
  function buildDeviceHandlers(deps) {
60557
61160
  const connectToDevice = createConnectToDevice(deps);
60558
61161
  const list = async (_frame, _client, ctx) => {
60559
- ensureOwner(ctx);
61162
+ ensureOwner2(ctx);
60560
61163
  const devices = await deps.listDevices().catch(rethrowLoginExpired);
60561
61164
  return {
60562
61165
  response: { type: "device:list:ok", devices }
60563
61166
  };
60564
61167
  };
60565
61168
  const connect = async (frame, _client, ctx) => {
60566
- ensureOwner(ctx);
61169
+ ensureOwner2(ctx);
60567
61170
  const { type: _t, requestId: _r, ...rest } = frame;
60568
61171
  const args = DeviceConnectArgsSchema.parse(rest);
60569
61172
  const contact = await connectToDevice(args);
@@ -60578,7 +61181,7 @@ function buildDeviceHandlers(deps) {
60578
61181
  };
60579
61182
  };
60580
61183
  const connections = async (_frame, client, ctx) => {
60581
- ensureOwner(ctx);
61184
+ ensureOwner2(ctx);
60582
61185
  const entries = deps.listOwnerConnections();
60583
61186
  return {
60584
61187
  response: {
@@ -60644,8 +61247,8 @@ function verifyConnectToken(args) {
60644
61247
  }
60645
61248
 
60646
61249
  // src/feishu-auth/server-key.ts
60647
- var fs59 = __toESM(require("fs"), 1);
60648
- var path63 = __toESM(require("path"), 1);
61250
+ var fs61 = __toESM(require("fs"), 1);
61251
+ var path65 = __toESM(require("path"), 1);
60649
61252
  var FILE_NAME2 = "server-signing-key.json";
60650
61253
  var ServerKeyStore = class {
60651
61254
  constructor(dataDir) {
@@ -60653,12 +61256,12 @@ var ServerKeyStore = class {
60653
61256
  }
60654
61257
  dataDir;
60655
61258
  filePath() {
60656
- return path63.join(this.dataDir, FILE_NAME2);
61259
+ return path65.join(this.dataDir, FILE_NAME2);
60657
61260
  }
60658
61261
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
60659
61262
  read() {
60660
61263
  try {
60661
- const raw = fs59.readFileSync(this.filePath(), "utf8");
61264
+ const raw = fs61.readFileSync(this.filePath(), "utf8");
60662
61265
  const parsed = JSON.parse(raw);
60663
61266
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
60664
61267
  return parsed.publicKeyPem;
@@ -60673,12 +61276,12 @@ var ServerKeyStore = class {
60673
61276
  publicKeyPem,
60674
61277
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
60675
61278
  };
60676
- fs59.mkdirSync(this.dataDir, { recursive: true });
60677
- fs59.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
61279
+ fs61.mkdirSync(this.dataDir, { recursive: true });
61280
+ fs61.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
60678
61281
  }
60679
61282
  clear() {
60680
61283
  try {
60681
- fs59.unlinkSync(this.filePath());
61284
+ fs61.unlinkSync(this.filePath());
60682
61285
  } catch {
60683
61286
  }
60684
61287
  }
@@ -60688,7 +61291,7 @@ var ServerKeyStore = class {
60688
61291
  init_protocol();
60689
61292
 
60690
61293
  // src/handlers/index.ts
60691
- var import_node_path68 = __toESM(require("path"), 1);
61294
+ var import_node_path70 = __toESM(require("path"), 1);
60692
61295
 
60693
61296
  // src/handlers/session.ts
60694
61297
  init_protocol();
@@ -60696,7 +61299,7 @@ init_protocol();
60696
61299
  // src/session/fork.ts
60697
61300
  var import_node_fs45 = __toESM(require("fs"), 1);
60698
61301
  var import_node_os17 = __toESM(require("os"), 1);
60699
- var import_node_path51 = __toESM(require("path"), 1);
61302
+ var import_node_path53 = __toESM(require("path"), 1);
60700
61303
  var import_node_crypto16 = require("crypto");
60701
61304
  init_claude_history();
60702
61305
  function readJsonlEntries(file) {
@@ -60713,19 +61316,19 @@ function readJsonlEntries(file) {
60713
61316
  return out;
60714
61317
  }
60715
61318
  function forkSession(input) {
60716
- const baseDir = input.baseDir ?? import_node_path51.default.join(import_node_os17.default.homedir(), ".claude");
60717
- let projectDir = import_node_path51.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
60718
- let sourceFile = import_node_path51.default.join(projectDir, `${input.toolSessionId}.jsonl`);
61319
+ const baseDir = input.baseDir ?? import_node_path53.default.join(import_node_os17.default.homedir(), ".claude");
61320
+ let projectDir = import_node_path53.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
61321
+ let sourceFile = import_node_path53.default.join(projectDir, `${input.toolSessionId}.jsonl`);
60719
61322
  if (!import_node_fs45.default.existsSync(sourceFile)) {
60720
61323
  const found = findTranscriptByToolSessionId(
60721
- import_node_path51.default.join(baseDir, "projects"),
61324
+ import_node_path53.default.join(baseDir, "projects"),
60722
61325
  input.toolSessionId
60723
61326
  );
60724
61327
  if (!found) {
60725
61328
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
60726
61329
  }
60727
61330
  sourceFile = found;
60728
- projectDir = import_node_path51.default.dirname(found);
61331
+ projectDir = import_node_path53.default.dirname(found);
60729
61332
  }
60730
61333
  const entries = readJsonlEntries(sourceFile);
60731
61334
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -60754,8 +61357,8 @@ function forkSession(input) {
60754
61357
  }
60755
61358
  forkedLines.push(JSON.stringify(forked));
60756
61359
  }
60757
- const outDir = input.targetCwd ? import_node_path51.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
60758
- const forkedFilePath = import_node_path51.default.join(outDir, `${forkedToolSessionId}.jsonl`);
61360
+ const outDir = input.targetCwd ? import_node_path53.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
61361
+ const forkedFilePath = import_node_path53.default.join(outDir, `${forkedToolSessionId}.jsonl`);
60759
61362
  import_node_fs45.default.mkdirSync(outDir, { recursive: true });
60760
61363
  import_node_fs45.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
60761
61364
  return { forkedToolSessionId, forkedFilePath };
@@ -60763,18 +61366,18 @@ function forkSession(input) {
60763
61366
 
60764
61367
  // src/session/external-scan.ts
60765
61368
  var import_node_fs46 = __toESM(require("fs"), 1);
60766
- var import_promises8 = __toESM(require("fs/promises"), 1);
61369
+ var import_promises10 = __toESM(require("fs/promises"), 1);
60767
61370
  var import_node_os18 = __toESM(require("os"), 1);
60768
- var import_node_path52 = __toESM(require("path"), 1);
61371
+ var import_node_path54 = __toESM(require("path"), 1);
60769
61372
  var import_node_module = require("module");
60770
61373
  var import_node_child_process12 = require("child_process");
60771
61374
  var import_meta4 = {};
60772
61375
  function defaultRoots() {
60773
61376
  const home = import_node_os18.default.homedir();
60774
61377
  return {
60775
- claudeProjectsDir: import_node_path52.default.join(home, ".claude", "projects"),
60776
- codexDir: import_node_path52.default.join(home, ".codex"),
60777
- clawdDir: import_node_path52.default.join(home, ".clawd")
61378
+ claudeProjectsDir: import_node_path54.default.join(home, ".claude", "projects"),
61379
+ codexDir: import_node_path54.default.join(home, ".codex"),
61380
+ clawdDir: import_node_path54.default.join(home, ".clawd")
60778
61381
  };
60779
61382
  }
60780
61383
  function width(s) {
@@ -60802,7 +61405,7 @@ function toMs(v2) {
60802
61405
  async function* jsonLines(file) {
60803
61406
  let raw;
60804
61407
  try {
60805
- raw = await import_promises8.default.readFile(file, "utf8");
61408
+ raw = await import_promises10.default.readFile(file, "utf8");
60806
61409
  } catch {
60807
61410
  return;
60808
61411
  }
@@ -60842,13 +61445,13 @@ async function scanClaude(roots) {
60842
61445
  if (!d.isDirectory()) continue;
60843
61446
  let files;
60844
61447
  try {
60845
- files = import_node_fs46.default.readdirSync(import_node_path52.default.join(roots.claudeProjectsDir, d.name));
61448
+ files = import_node_fs46.default.readdirSync(import_node_path54.default.join(roots.claudeProjectsDir, d.name));
60846
61449
  } catch {
60847
61450
  continue;
60848
61451
  }
60849
61452
  for (const name of files) {
60850
61453
  if (!name.endsWith(".jsonl")) continue;
60851
- const file = import_node_path52.default.join(roots.claudeProjectsDir, d.name, name);
61454
+ const file = import_node_path54.default.join(roots.claudeProjectsDir, d.name, name);
60852
61455
  let st;
60853
61456
  try {
60854
61457
  st = import_node_fs46.default.statSync(file);
@@ -60978,7 +61581,7 @@ async function codexFromRows(rows) {
60978
61581
  async function scanCodex(roots) {
60979
61582
  let dbs = [];
60980
61583
  try {
60981
- dbs = import_node_fs46.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path52.default.join(roots.codexDir, n));
61584
+ dbs = import_node_fs46.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path54.default.join(roots.codexDir, n));
60982
61585
  } catch {
60983
61586
  }
60984
61587
  if (!dbs.length) return [];
@@ -60987,14 +61590,14 @@ async function scanCodex(roots) {
60987
61590
  }
60988
61591
  async function scanExternalSessions(rootsIn) {
60989
61592
  const roots = { ...defaultRoots(), ...rootsIn };
60990
- const personaRoot = import_node_path52.default.join(roots.clawdDir, "personas");
61593
+ const personaRoot = import_node_path54.default.join(roots.clawdDir, "personas");
60991
61594
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
60992
61595
  const out = [];
60993
61596
  for (const c of all) {
60994
61597
  if (c.skip) continue;
60995
61598
  if (c.turns < 1) continue;
60996
61599
  if (!c.cwd || !isDir2(c.cwd)) continue;
60997
- if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path52.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path52.default.sep)) {
61600
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path54.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path54.default.sep)) {
60998
61601
  continue;
60999
61602
  }
61000
61603
  out.push({
@@ -61012,12 +61615,12 @@ async function scanExternalSessions(rootsIn) {
61012
61615
 
61013
61616
  // src/session/import-ledger.ts
61014
61617
  var import_node_fs47 = __toESM(require("fs"), 1);
61015
- var import_node_path53 = __toESM(require("path"), 1);
61618
+ var import_node_path55 = __toESM(require("path"), 1);
61016
61619
  var LEDGER_FILENAME = "session-import-ledger.json";
61017
61620
  function readImportLedger(dataDir) {
61018
61621
  try {
61019
61622
  const parsed = JSON.parse(
61020
- import_node_fs47.default.readFileSync(import_node_path53.default.join(dataDir, LEDGER_FILENAME), "utf8")
61623
+ import_node_fs47.default.readFileSync(import_node_path55.default.join(dataDir, LEDGER_FILENAME), "utf8")
61021
61624
  );
61022
61625
  return Array.isArray(parsed) ? parsed : [];
61023
61626
  } catch {
@@ -61025,7 +61628,7 @@ function readImportLedger(dataDir) {
61025
61628
  }
61026
61629
  }
61027
61630
  function appendImportLedger(dataDir, entry) {
61028
- const file = import_node_path53.default.join(dataDir, LEDGER_FILENAME);
61631
+ const file = import_node_path55.default.join(dataDir, LEDGER_FILENAME);
61029
61632
  const entries = readImportLedger(dataDir);
61030
61633
  entries.push(entry);
61031
61634
  import_node_fs47.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
@@ -61033,7 +61636,7 @@ function appendImportLedger(dataDir, entry) {
61033
61636
 
61034
61637
  // src/tools/transcript-search.ts
61035
61638
  var import_node_fs48 = __toESM(require("fs"), 1);
61036
- var import_node_path54 = __toESM(require("path"), 1);
61639
+ var import_node_path56 = __toESM(require("path"), 1);
61037
61640
  var SNIPPET_PAD = 60;
61038
61641
  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/;
61039
61642
  var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
@@ -61126,7 +61729,7 @@ function createCodexRolloutLocator(roots) {
61126
61729
  return;
61127
61730
  }
61128
61731
  for (const entry of entries) {
61129
- const full = import_node_path54.default.join(dir, entry.name);
61732
+ const full = import_node_path56.default.join(dir, entry.name);
61130
61733
  if (entry.isDirectory()) {
61131
61734
  walk2(full, into);
61132
61735
  continue;
@@ -61147,15 +61750,15 @@ function createCodexRolloutLocator(roots) {
61147
61750
  // src/handlers/session.ts
61148
61751
  init_protocol();
61149
61752
  var import_node_os19 = __toESM(require("os"), 1);
61150
- var import_node_path55 = __toESM(require("path"), 1);
61753
+ var import_node_path57 = __toESM(require("path"), 1);
61151
61754
  function canReadSearchHit(ctx, file) {
61152
61755
  if (!ctx || ctx.principal.kind === "owner") return true;
61153
61756
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
61154
61757
  }
61155
61758
  var DEFAULT_SEARCH_LIMIT = 9;
61156
61759
  function codexRolloutRoots(dataDir) {
61157
- const roots = [import_node_path55.default.join(import_node_os19.default.homedir(), ".codex", "sessions")];
61158
- if (dataDir) roots.push(import_node_path55.default.join(dataDir, "codex-home", "sessions"));
61760
+ const roots = [import_node_path57.default.join(import_node_os19.default.homedir(), ".codex", "sessions")];
61761
+ if (dataDir) roots.push(import_node_path57.default.join(dataDir, "codex-home", "sessions"));
61159
61762
  return roots;
61160
61763
  }
61161
61764
  function buildSessionHandlers(deps) {
@@ -61697,7 +62300,7 @@ function buildPermissionHandlers(deps) {
61697
62300
  }
61698
62301
 
61699
62302
  // src/handlers/history.ts
61700
- var path70 = __toESM(require("path"), 1);
62303
+ var path72 = __toESM(require("path"), 1);
61701
62304
  init_protocol();
61702
62305
 
61703
62306
  // src/session/recent-dirs.ts
@@ -61715,7 +62318,7 @@ function listRecentDirs(store, limit = 50) {
61715
62318
  }
61716
62319
 
61717
62320
  // src/permission/persona-paths.ts
61718
- var path69 = __toESM(require("path"), 1);
62321
+ var path71 = __toESM(require("path"), 1);
61719
62322
  function getAllowedPersonaIds(grants, action) {
61720
62323
  const ids = /* @__PURE__ */ new Set();
61721
62324
  for (const g2 of grants) {
@@ -61728,42 +62331,42 @@ function getAllowedPersonaIds(grants, action) {
61728
62331
  return ids;
61729
62332
  }
61730
62333
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
61731
- const target = path69.resolve(absPath);
62334
+ const target = path71.resolve(absPath);
61732
62335
  if (userWorkDir) {
61733
- const u = path69.resolve(userWorkDir);
61734
- const usep = u.endsWith(path69.sep) ? "" : path69.sep;
62336
+ const u = path71.resolve(userWorkDir);
62337
+ const usep = u.endsWith(path71.sep) ? "" : path71.sep;
61735
62338
  if (target === u || target.startsWith(u + usep)) return true;
61736
62339
  }
61737
- const root = path69.resolve(personaRoot);
61738
- const sep4 = root.endsWith(path69.sep) ? "" : path69.sep;
62340
+ const root = path71.resolve(personaRoot);
62341
+ const sep4 = root.endsWith(path71.sep) ? "" : path71.sep;
61739
62342
  if (!target.startsWith(root + sep4)) return false;
61740
- const rel = path69.relative(root, target);
62343
+ const rel = path71.relative(root, target);
61741
62344
  if (!rel || rel.startsWith("..")) return false;
61742
- const personaId2 = rel.split(path69.sep)[0];
62345
+ const personaId2 = rel.split(path71.sep)[0];
61743
62346
  if (!personaId2) return false;
61744
62347
  const allowed = getAllowedPersonaIds(grants, action);
61745
62348
  if (allowed === "*") return true;
61746
62349
  return allowed.has(personaId2);
61747
62350
  }
61748
62351
  function personaIdFromPath(absPath, personaRoot) {
61749
- const root = path69.resolve(personaRoot);
61750
- const target = path69.resolve(absPath);
61751
- const sep4 = root.endsWith(path69.sep) ? "" : path69.sep;
62352
+ const root = path71.resolve(personaRoot);
62353
+ const target = path71.resolve(absPath);
62354
+ const sep4 = root.endsWith(path71.sep) ? "" : path71.sep;
61752
62355
  if (!target.startsWith(root + sep4)) return null;
61753
- const rel = path69.relative(root, target);
62356
+ const rel = path71.relative(root, target);
61754
62357
  if (!rel || rel.startsWith("..")) return null;
61755
- const id = rel.split(path69.sep)[0];
62358
+ const id = rel.split(path71.sep)[0];
61756
62359
  return id || null;
61757
62360
  }
61758
62361
  function isPathWithin(dir, absPath) {
61759
- const d = path69.resolve(dir);
61760
- const t = path69.resolve(absPath);
61761
- const sep4 = d.endsWith(path69.sep) ? "" : path69.sep;
62362
+ const d = path71.resolve(dir);
62363
+ const t = path71.resolve(absPath);
62364
+ const sep4 = d.endsWith(path71.sep) ? "" : path71.sep;
61762
62365
  return t === d || t.startsWith(d + sep4);
61763
62366
  }
61764
62367
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
61765
62368
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
61766
- return personaIdFromPath(path69.resolve(absPath), personaRoot) === personaId2;
62369
+ return personaIdFromPath(path71.resolve(absPath), personaRoot) === personaId2;
61767
62370
  }
61768
62371
 
61769
62372
  // src/handlers/history.ts
@@ -61816,7 +62419,7 @@ function buildHistoryHandlers(deps) {
61816
62419
  if (!pid) return false;
61817
62420
  return isGuestPathAllowed(
61818
62421
  ctx.grants,
61819
- path70.join(personaRoot, pid),
62422
+ path72.join(personaRoot, pid),
61820
62423
  personaRoot,
61821
62424
  "read",
61822
62425
  userWorkDir
@@ -61828,7 +62431,7 @@ function buildHistoryHandlers(deps) {
61828
62431
  };
61829
62432
  const list = async (frame, _client, ctx) => {
61830
62433
  const args = HistoryListArgs.parse(frame);
61831
- assertGuestPath(ctx, path70.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
62434
+ assertGuestPath(ctx, path72.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
61832
62435
  const sessions = await history.listSessions(args);
61833
62436
  return { response: { type: "history:list", sessions } };
61834
62437
  };
@@ -61876,14 +62479,14 @@ function buildHistoryHandlers(deps) {
61876
62479
  };
61877
62480
  const subagents = async (frame, _client, ctx) => {
61878
62481
  const args = HistorySubagentsArgs.parse(frame);
61879
- assertGuestPath(ctx, path70.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
62482
+ assertGuestPath(ctx, path72.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
61880
62483
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
61881
62484
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
61882
62485
  return { response: { type: "history:subagents", subagents: subs } };
61883
62486
  };
61884
62487
  const subagentRead = async (frame, _client, ctx) => {
61885
62488
  const args = HistorySubagentReadArgs.parse(frame);
61886
- assertGuestPath(ctx, path70.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
62489
+ assertGuestPath(ctx, path72.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
61887
62490
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
61888
62491
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
61889
62492
  return { response: { type: "history:subagent-read", ...res } };
@@ -61893,7 +62496,7 @@ function buildHistoryHandlers(deps) {
61893
62496
  if (ctx?.principal.kind === "guest" && personaRoot) {
61894
62497
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
61895
62498
  const filtered = dirs.filter(
61896
- (d) => isGuestPathAllowed(ctx.grants, path70.resolve(d.cwd), personaRoot, "read", userWorkDir)
62499
+ (d) => isGuestPathAllowed(ctx.grants, path72.resolve(d.cwd), personaRoot, "read", userWorkDir)
61897
62500
  );
61898
62501
  return { response: { type: "history:recentDirs", dirs: filtered } };
61899
62502
  }
@@ -61910,17 +62513,17 @@ function buildHistoryHandlers(deps) {
61910
62513
  }
61911
62514
 
61912
62515
  // src/handlers/projects.ts
61913
- var fs64 = __toESM(require("fs"), 1);
62516
+ var fs66 = __toESM(require("fs"), 1);
61914
62517
  var os21 = __toESM(require("os"), 1);
61915
- var path71 = __toESM(require("path"), 1);
62518
+ var path73 = __toESM(require("path"), 1);
61916
62519
  var import_node_child_process13 = require("child_process");
61917
62520
  init_protocol();
61918
- var DEFAULT_PROJECTS_ROOT = path71.join(os21.homedir(), "Documents", "ChatGPT");
62521
+ var DEFAULT_PROJECTS_ROOT = path73.join(os21.homedir(), "Documents", "ChatGPT");
61919
62522
  function allocateDir(root, name) {
61920
- let candidate = path71.join(root, name);
62523
+ let candidate = path73.join(root, name);
61921
62524
  let n = 2;
61922
- while (fs64.existsSync(candidate)) {
61923
- candidate = path71.join(root, `${name} ${n}`);
62525
+ while (fs66.existsSync(candidate)) {
62526
+ candidate = path73.join(root, `${name} ${n}`);
61924
62527
  n += 1;
61925
62528
  }
61926
62529
  return candidate;
@@ -61948,7 +62551,7 @@ function buildProjectHandlers(deps) {
61948
62551
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
61949
62552
  }
61950
62553
  try {
61951
- if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
62554
+ if (!fs66.statSync(args.path).isDirectory()) throw new Error("not dir");
61952
62555
  } catch {
61953
62556
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
61954
62557
  }
@@ -61964,7 +62567,7 @@ function buildProjectHandlers(deps) {
61964
62567
  let target;
61965
62568
  if (args.path) {
61966
62569
  try {
61967
- if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
62570
+ if (!fs66.statSync(args.path).isDirectory()) throw new Error("not dir");
61968
62571
  } catch {
61969
62572
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
61970
62573
  }
@@ -61972,15 +62575,15 @@ function buildProjectHandlers(deps) {
61972
62575
  } else {
61973
62576
  const name = args.name;
61974
62577
  try {
61975
- fs64.mkdirSync(root, { recursive: true });
62578
+ fs66.mkdirSync(root, { recursive: true });
61976
62579
  target = allocateDir(root, name);
61977
- fs64.mkdirSync(target);
62580
+ fs66.mkdirSync(target);
61978
62581
  } catch (err) {
61979
62582
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
61980
62583
  }
61981
62584
  const git = (0, import_node_child_process13.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
61982
62585
  if (git.status !== 0) {
61983
- fs64.rmSync(target, { recursive: true, force: true });
62586
+ fs66.rmSync(target, { recursive: true, force: true });
61984
62587
  throw new ClawdError(
61985
62588
  ERROR_CODES.INVALID_CWD,
61986
62589
  `git init \u5931\u8D25\uFF08${git.error ? String(git.error) : `exit ${git.status}`}\uFF09: ${target}`
@@ -62005,7 +62608,7 @@ function buildProjectHandlers(deps) {
62005
62608
  }
62006
62609
 
62007
62610
  // src/handlers/workspace.ts
62008
- var path72 = __toESM(require("path"), 1);
62611
+ var path74 = __toESM(require("path"), 1);
62009
62612
  var os22 = __toESM(require("os"), 1);
62010
62613
  init_protocol();
62011
62614
  init_protocol();
@@ -62047,22 +62650,22 @@ function buildWorkspaceHandlers(deps) {
62047
62650
  const args = WorkspaceListArgs.parse(frame);
62048
62651
  const isGuest = ctx?.principal.kind === "guest";
62049
62652
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os22.homedir();
62050
- const resolvedCwd = path72.resolve(args.cwd ?? fallbackCwd);
62051
- const target = args.path ? path72.resolve(resolvedCwd, args.path) : resolvedCwd;
62653
+ const resolvedCwd = path74.resolve(args.cwd ?? fallbackCwd);
62654
+ const target = args.path ? path74.resolve(resolvedCwd, args.path) : resolvedCwd;
62052
62655
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
62053
62656
  const res = workspace.list({ ...args, cwd: resolvedCwd });
62054
62657
  return { response: { type: "workspace:list", ...res } };
62055
62658
  };
62056
62659
  const read = async (frame, _client, ctx) => {
62057
62660
  const args = WorkspaceReadArgs.parse(frame);
62058
- const target = path72.isAbsolute(args.path) ? path72.resolve(args.path) : path72.resolve(args.cwd, args.path);
62661
+ const target = path74.isAbsolute(args.path) ? path74.resolve(args.path) : path74.resolve(args.cwd, args.path);
62059
62662
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
62060
62663
  const res = workspace.read(args);
62061
62664
  return { response: { type: "workspace:read", ...res } };
62062
62665
  };
62063
62666
  const skillsList = async (frame, _client, ctx) => {
62064
62667
  const args = SkillsListArgs.parse(frame);
62065
- const cwdAbs = path72.resolve(args.cwd);
62668
+ const cwdAbs = path74.resolve(args.cwd);
62066
62669
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
62067
62670
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
62068
62671
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -62074,7 +62677,7 @@ function buildWorkspaceHandlers(deps) {
62074
62677
  };
62075
62678
  const agentsList = async (frame, _client, ctx) => {
62076
62679
  const args = AgentsListArgs.parse(frame);
62077
- const cwdAbs = path72.resolve(args.cwd);
62680
+ const cwdAbs = path74.resolve(args.cwd);
62078
62681
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
62079
62682
  if (args.tool === "codex") {
62080
62683
  return { response: { type: "agents:list", agents: [] } };
@@ -62096,18 +62699,18 @@ function buildWorkspaceHandlers(deps) {
62096
62699
  }
62097
62700
 
62098
62701
  // src/handlers/git.ts
62099
- var path74 = __toESM(require("path"), 1);
62702
+ var path76 = __toESM(require("path"), 1);
62100
62703
  init_protocol();
62101
62704
  init_protocol();
62102
62705
 
62103
62706
  // src/workspace/git.ts
62104
62707
  var import_node_child_process14 = require("child_process");
62105
62708
  var import_node_fs49 = __toESM(require("fs"), 1);
62106
- var import_node_path56 = __toESM(require("path"), 1);
62709
+ var import_node_path58 = __toESM(require("path"), 1);
62107
62710
  var import_node_util = require("util");
62108
62711
  var pexec = (0, import_node_util.promisify)(import_node_child_process14.execFile);
62109
62712
  function normalizePath(p2) {
62110
- const resolved = import_node_path56.default.resolve(p2);
62713
+ const resolved = import_node_path58.default.resolve(p2);
62111
62714
  try {
62112
62715
  return import_node_fs49.default.realpathSync(resolved);
62113
62716
  } catch {
@@ -62183,7 +62786,7 @@ async function listGitBranches(cwd) {
62183
62786
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
62184
62787
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
62185
62788
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
62186
- if (!isGuestPathAllowed(ctx.grants, path74.resolve(cwd), personaRoot, "read", userWorkDir)) {
62789
+ if (!isGuestPathAllowed(ctx.grants, path76.resolve(cwd), personaRoot, "read", userWorkDir)) {
62187
62790
  throw new ClawdError(
62188
62791
  ERROR_CODES.UNAUTHORIZED,
62189
62792
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -62438,7 +63041,7 @@ function upsertPeerContact(args) {
62438
63041
  }
62439
63042
 
62440
63043
  // src/handlers/contact.ts
62441
- function ensureOwner2(ctx) {
63044
+ function ensureOwner3(ctx) {
62442
63045
  if (!ctx || ctx.principal.kind !== "owner") {
62443
63046
  throw new ClawdError(
62444
63047
  ERROR_CODES.UNAUTHORIZED,
@@ -62448,7 +63051,7 @@ function ensureOwner2(ctx) {
62448
63051
  }
62449
63052
  function buildContactHandlers(deps) {
62450
63053
  const list = async (_frame, _client, ctx) => {
62451
- ensureOwner2(ctx);
63054
+ ensureOwner3(ctx);
62452
63055
  return {
62453
63056
  response: {
62454
63057
  type: "contact:list:ok",
@@ -62457,7 +63060,7 @@ function buildContactHandlers(deps) {
62457
63060
  };
62458
63061
  };
62459
63062
  const pin = async (frame, _client, ctx) => {
62460
- ensureOwner2(ctx);
63063
+ ensureOwner3(ctx);
62461
63064
  const args = parseArgs2(ContactPinArgsSchema, frame, "contact:pin");
62462
63065
  const pinnedAt = args.pinned ? deps.now() : null;
62463
63066
  const hit = deps.store.setPin(args.deviceId, pinnedAt);
@@ -62481,7 +63084,7 @@ function buildContactHandlers(deps) {
62481
63084
  };
62482
63085
  };
62483
63086
  const setNote = async (frame, _client, ctx) => {
62484
- ensureOwner2(ctx);
63087
+ ensureOwner3(ctx);
62485
63088
  const args = parseArgs2(ContactSetNoteArgsSchema, frame, "contact:setNote");
62486
63089
  const hit = deps.store.setNote(args.deviceId, args.note);
62487
63090
  if (!hit) {
@@ -62504,13 +63107,13 @@ function buildContactHandlers(deps) {
62504
63107
  };
62505
63108
  };
62506
63109
  const orgPeers = async (_frame, _client, ctx) => {
62507
- ensureOwner2(ctx);
63110
+ ensureOwner3(ctx);
62508
63111
  return {
62509
63112
  response: { type: "org:peers:ok", peers: getCachedOrgPeers() }
62510
63113
  };
62511
63114
  };
62512
63115
  const remove = async (frame, _client, ctx) => {
62513
- ensureOwner2(ctx);
63116
+ ensureOwner3(ctx);
62514
63117
  const args = parseArgs2(ContactRemoveArgsSchema, frame, "contact:remove");
62515
63118
  deps.store.removeByDeviceId(args.deviceId);
62516
63119
  deps.broadcast({
@@ -62584,7 +63187,7 @@ function buildContactHandlers(deps) {
62584
63187
 
62585
63188
  // src/handlers/contact-remote-access.ts
62586
63189
  init_protocol();
62587
- function ensureOwner3(ctx) {
63190
+ function ensureOwner4(ctx) {
62588
63191
  if (!ctx || ctx.principal.kind !== "owner") {
62589
63192
  throw new ClawdError(
62590
63193
  ERROR_CODES.UNAUTHORIZED,
@@ -62594,7 +63197,7 @@ function ensureOwner3(ctx) {
62594
63197
  }
62595
63198
  function buildContactRemoteAccessHandlers(deps) {
62596
63199
  const setRemoteAccess = async (frame, _client, ctx) => {
62597
- ensureOwner3(ctx);
63200
+ ensureOwner4(ctx);
62598
63201
  const args = parseArgs2(ContactSetRemoteAccessArgsSchema, frame, "contact:setRemoteAccess");
62599
63202
  const hit = deps.store.setRemoteAccess(args.deviceId, {
62600
63203
  remoteAccessAllowed: args.remoteAccessAllowed
@@ -62773,6 +63376,16 @@ var METHOD_GRANT_MAP = {
62773
63376
  // ---- visitor:* (访客名单,owner-only) ----
62774
63377
  // owner 看完整访客名单(含没开会话的);guest 不可调(handler 内再 assertOwner 兜底)。
62775
63378
  "visitor:list": ADMIN_ANY,
63379
+ // deploy:*(persona 上云的部署单):全部 owner-only。单据里有履约决策、凭据录入口,
63380
+ // guest 不该看见更不该动。
63381
+ "deploy:start": ADMIN_ANY,
63382
+ "deploy:list": ADMIN_ANY,
63383
+ "deploy:get": ADMIN_ANY,
63384
+ "deploy:patch": ADMIN_ANY,
63385
+ "deploy:putSecret": ADMIN_ANY,
63386
+ "deploy:reportFinding": ADMIN_ANY,
63387
+ "deploy:finishScan": ADMIN_ANY,
63388
+ "deploy:remove": ADMIN_ANY,
62776
63389
  // ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
62777
63390
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
62778
63391
  // owner 自动通过(ctx 自带 '*':'admin' grant 一切 match);guest 在被授权 persona 内可调。
@@ -63018,21 +63631,21 @@ function computeMethodAccess(args) {
63018
63631
  }
63019
63632
 
63020
63633
  // src/version.ts
63021
- var version = "0.2.445".length > 0 ? "0.2.445" : "dev";
63634
+ var version = "0.2.446".length > 0 ? "0.2.446" : "dev";
63022
63635
 
63023
63636
  // src/cli-probe/probe.ts
63024
- var fs66 = __toESM(require("fs"), 1);
63025
- var path75 = __toESM(require("path"), 1);
63637
+ var fs68 = __toESM(require("fs"), 1);
63638
+ var path77 = __toESM(require("path"), 1);
63026
63639
  var PKG_NAME = "@clawos-dev/clawd";
63027
63640
  var BIN_NAME = "clawd";
63028
63641
  var MAX_PARENT_HOPS = 5;
63029
63642
  function probeGlobalCli(pathEnv) {
63030
63643
  if (!pathEnv) return null;
63031
- for (const dir of pathEnv.split(path75.delimiter)) {
63644
+ for (const dir of pathEnv.split(path77.delimiter)) {
63032
63645
  if (!dir) continue;
63033
63646
  let real;
63034
63647
  try {
63035
- real = fs66.realpathSync(path75.join(dir, BIN_NAME));
63648
+ real = fs68.realpathSync(path77.join(dir, BIN_NAME));
63036
63649
  } catch {
63037
63650
  continue;
63038
63651
  }
@@ -63042,15 +63655,15 @@ function probeGlobalCli(pathEnv) {
63042
63655
  return null;
63043
63656
  }
63044
63657
  function readOwnPackageVersion(entryPath) {
63045
- let dir = path75.dirname(entryPath);
63658
+ let dir = path77.dirname(entryPath);
63046
63659
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
63047
63660
  try {
63048
- const raw = fs66.readFileSync(path75.join(dir, "package.json"), "utf8");
63661
+ const raw = fs68.readFileSync(path77.join(dir, "package.json"), "utf8");
63049
63662
  const pkg = JSON.parse(raw);
63050
63663
  if (pkg.name !== PKG_NAME) return null;
63051
63664
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
63052
63665
  } catch {
63053
- const parent = path75.dirname(dir);
63666
+ const parent = path77.dirname(dir);
63054
63667
  if (parent === dir) return null;
63055
63668
  dir = parent;
63056
63669
  }
@@ -63222,7 +63835,7 @@ function buildPersonaHandlers(deps) {
63222
63835
  }
63223
63836
 
63224
63837
  // src/handlers/attachment.ts
63225
- var import_node_path57 = __toESM(require("path"), 1);
63838
+ var import_node_path59 = __toESM(require("path"), 1);
63226
63839
  init_protocol();
63227
63840
  init_protocol();
63228
63841
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -63302,12 +63915,12 @@ function buildAttachmentHandlers(deps) {
63302
63915
  `session ${args.sessionId} scope unresolved`
63303
63916
  );
63304
63917
  }
63305
- const cwdAbs = import_node_path57.default.resolve(sessionFile.cwd);
63306
- const candidateAbs = import_node_path57.default.isAbsolute(args.relPath) ? import_node_path57.default.resolve(args.relPath) : import_node_path57.default.resolve(cwdAbs, args.relPath);
63918
+ const cwdAbs = import_node_path59.default.resolve(sessionFile.cwd);
63919
+ const candidateAbs = import_node_path59.default.isAbsolute(args.relPath) ? import_node_path59.default.resolve(args.relPath) : import_node_path59.default.resolve(cwdAbs, args.relPath);
63307
63920
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
63308
63921
  const entries = deps.groupFileStore.list(scope, args.sessionId);
63309
63922
  const entry = entries.find((e) => {
63310
- const storedAbs = import_node_path57.default.isAbsolute(e.relPath) ? import_node_path57.default.resolve(e.relPath) : import_node_path57.default.resolve(cwdAbs, e.relPath);
63923
+ const storedAbs = import_node_path59.default.isAbsolute(e.relPath) ? import_node_path59.default.resolve(e.relPath) : import_node_path59.default.resolve(cwdAbs, e.relPath);
63311
63924
  return storedAbs === candidateAbs && !e.stale;
63312
63925
  });
63313
63926
  if (!entry) {
@@ -63332,7 +63945,7 @@ function buildAttachmentHandlers(deps) {
63332
63945
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
63333
63946
  const f = deps.sessionStore.read(sessionId);
63334
63947
  if (!f) return;
63335
- assertGuestAttachmentPath(ctx, import_node_path57.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
63948
+ assertGuestAttachmentPath(ctx, import_node_path59.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
63336
63949
  }
63337
63950
  const groupAdd = async (frame, _client, ctx) => {
63338
63951
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -63347,8 +63960,8 @@ function buildAttachmentHandlers(deps) {
63347
63960
  if (!scope) {
63348
63961
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
63349
63962
  }
63350
- const cwdAbs = import_node_path57.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
63351
- const candidateAbs = import_node_path57.default.isAbsolute(args.relPath) ? import_node_path57.default.resolve(args.relPath) : import_node_path57.default.resolve(cwdAbs, args.relPath);
63963
+ const cwdAbs = import_node_path59.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
63964
+ const candidateAbs = import_node_path59.default.isAbsolute(args.relPath) ? import_node_path59.default.resolve(args.relPath) : import_node_path59.default.resolve(cwdAbs, args.relPath);
63352
63965
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
63353
63966
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
63354
63967
  const size = 0;
@@ -63406,21 +64019,21 @@ function buildAttachmentHandlers(deps) {
63406
64019
  }
63407
64020
 
63408
64021
  // src/handlers/extension.ts
63409
- var import_promises12 = __toESM(require("fs/promises"), 1);
63410
- var import_node_path62 = __toESM(require("path"), 1);
64022
+ var import_promises14 = __toESM(require("fs/promises"), 1);
64023
+ var import_node_path64 = __toESM(require("path"), 1);
63411
64024
  init_protocol();
63412
64025
 
63413
64026
  // src/extension/bundle-zip.ts
63414
- var import_promises9 = __toESM(require("fs/promises"), 1);
63415
- var import_node_path58 = __toESM(require("path"), 1);
64027
+ var import_promises11 = __toESM(require("fs/promises"), 1);
64028
+ var import_node_path60 = __toESM(require("path"), 1);
63416
64029
  var import_node_crypto17 = __toESM(require("crypto"), 1);
63417
64030
  var import_jszip2 = __toESM(require_lib3(), 1);
63418
64031
  async function bundleExtensionDir(dir) {
63419
64032
  const entries = await listFilesSorted(dir);
63420
64033
  const zip = new import_jszip2.default();
63421
64034
  for (const rel of entries) {
63422
- const abs = import_node_path58.default.join(dir, rel);
63423
- const content = await import_promises9.default.readFile(abs);
64035
+ const abs = import_node_path60.default.join(dir, rel);
64036
+ const content = await import_promises11.default.readFile(abs);
63424
64037
  zip.file(rel, content, { date: FIXED_DATE });
63425
64038
  }
63426
64039
  const buffer = await zip.generateAsync({
@@ -63440,8 +64053,8 @@ async function listFilesSorted(rootDir) {
63440
64053
  return out;
63441
64054
  }
63442
64055
  async function walk(absRoot, relPrefix, out) {
63443
- const dirAbs = import_node_path58.default.join(absRoot, relPrefix);
63444
- const entries = await import_promises9.default.readdir(dirAbs, { withFileTypes: true });
64056
+ const dirAbs = import_node_path60.default.join(absRoot, relPrefix);
64057
+ const entries = await import_promises11.default.readdir(dirAbs, { withFileTypes: true });
63445
64058
  for (const e of entries) {
63446
64059
  if (IGNORE_BASENAMES.has(e.name)) continue;
63447
64060
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -63493,26 +64106,26 @@ function computePublishCheck(args) {
63493
64106
  }
63494
64107
 
63495
64108
  // src/extension/install-flow.ts
63496
- var import_promises10 = __toESM(require("fs/promises"), 1);
63497
- var import_node_path60 = __toESM(require("path"), 1);
64109
+ var import_promises12 = __toESM(require("fs/promises"), 1);
64110
+ var import_node_path62 = __toESM(require("path"), 1);
63498
64111
  var import_node_os22 = __toESM(require("os"), 1);
63499
64112
  var import_node_crypto18 = __toESM(require("crypto"), 1);
63500
64113
  var import_jszip3 = __toESM(require_lib3(), 1);
63501
64114
 
63502
64115
  // src/extension/paths.ts
63503
64116
  var import_node_os21 = __toESM(require("os"), 1);
63504
- var import_node_path59 = __toESM(require("path"), 1);
64117
+ var import_node_path61 = __toESM(require("path"), 1);
63505
64118
  function clawdHomeRoot(override) {
63506
- return override ?? process.env.CLAWD_HOME ?? import_node_path59.default.join(import_node_os21.default.homedir(), ".clawd");
64119
+ return override ?? process.env.CLAWD_HOME ?? import_node_path61.default.join(import_node_os21.default.homedir(), ".clawd");
63507
64120
  }
63508
64121
  function extensionsRoot(override) {
63509
- return import_node_path59.default.join(clawdHomeRoot(override), "extensions");
64122
+ return import_node_path61.default.join(clawdHomeRoot(override), "extensions");
63510
64123
  }
63511
64124
  function publishedChannelsFile(override) {
63512
- return import_node_path59.default.join(clawdHomeRoot(override), "extensions-published.json");
64125
+ return import_node_path61.default.join(clawdHomeRoot(override), "extensions-published.json");
63513
64126
  }
63514
64127
  function bundleCacheRoot(override) {
63515
- return import_node_path59.default.join(clawdHomeRoot(override), "extension-bundles");
64128
+ return import_node_path61.default.join(clawdHomeRoot(override), "extension-bundles");
63516
64129
  }
63517
64130
 
63518
64131
  // src/extension/install-flow.ts
@@ -63539,7 +64152,7 @@ async function installFromChannel(args, deps) {
63539
64152
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
63540
64153
  }
63541
64154
  for (const name of Object.keys(zip.files)) {
63542
- if (name.includes("..") || name.startsWith("/") || import_node_path60.default.isAbsolute(name)) {
64155
+ if (name.includes("..") || name.startsWith("/") || import_node_path62.default.isAbsolute(name)) {
63543
64156
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
63544
64157
  }
63545
64158
  }
@@ -63571,10 +64184,10 @@ async function installFromChannel(args, deps) {
63571
64184
  );
63572
64185
  }
63573
64186
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
63574
- const destDir = import_node_path60.default.join(deps.extensionsRoot, localExtId);
64187
+ const destDir = import_node_path62.default.join(deps.extensionsRoot, localExtId);
63575
64188
  let destExists = false;
63576
64189
  try {
63577
- await import_promises10.default.access(destDir);
64190
+ await import_promises12.default.access(destDir);
63578
64191
  destExists = true;
63579
64192
  } catch {
63580
64193
  }
@@ -63584,28 +64197,28 @@ async function installFromChannel(args, deps) {
63584
64197
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
63585
64198
  );
63586
64199
  }
63587
- const stage = await import_promises10.default.mkdtemp(
63588
- import_node_path60.default.join(import_node_os22.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
64200
+ const stage = await import_promises12.default.mkdtemp(
64201
+ import_node_path62.default.join(import_node_os22.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
63589
64202
  );
63590
64203
  try {
63591
64204
  for (const [name, entry] of Object.entries(zip.files)) {
63592
- const dest = import_node_path60.default.join(stage, name);
64205
+ const dest = import_node_path62.default.join(stage, name);
63593
64206
  if (entry.dir) {
63594
- await import_promises10.default.mkdir(dest, { recursive: true });
64207
+ await import_promises12.default.mkdir(dest, { recursive: true });
63595
64208
  continue;
63596
64209
  }
63597
- await import_promises10.default.mkdir(import_node_path60.default.dirname(dest), { recursive: true });
64210
+ await import_promises12.default.mkdir(import_node_path62.default.dirname(dest), { recursive: true });
63598
64211
  if (name === "manifest.json") {
63599
64212
  const rewritten = { ...parsed.data, id: localExtId };
63600
- await import_promises10.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64213
+ await import_promises12.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
63601
64214
  } else {
63602
- await import_promises10.default.writeFile(dest, await entry.async("nodebuffer"));
64215
+ await import_promises12.default.writeFile(dest, await entry.async("nodebuffer"));
63603
64216
  }
63604
64217
  }
63605
- await import_promises10.default.mkdir(deps.extensionsRoot, { recursive: true });
63606
- await import_promises10.default.rename(stage, destDir);
64218
+ await import_promises12.default.mkdir(deps.extensionsRoot, { recursive: true });
64219
+ await import_promises12.default.rename(stage, destDir);
63607
64220
  } catch (e) {
63608
- await import_promises10.default.rm(stage, { recursive: true, force: true }).catch(() => {
64221
+ await import_promises12.default.rm(stage, { recursive: true, force: true }).catch(() => {
63609
64222
  });
63610
64223
  throw e;
63611
64224
  }
@@ -63614,8 +64227,8 @@ async function installFromChannel(args, deps) {
63614
64227
  }
63615
64228
 
63616
64229
  // src/extension/update-flow.ts
63617
- var import_promises11 = __toESM(require("fs/promises"), 1);
63618
- var import_node_path61 = __toESM(require("path"), 1);
64230
+ var import_promises13 = __toESM(require("fs/promises"), 1);
64231
+ var import_node_path63 = __toESM(require("path"), 1);
63619
64232
  var import_node_os23 = __toESM(require("os"), 1);
63620
64233
  var import_node_crypto19 = __toESM(require("crypto"), 1);
63621
64234
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -63632,11 +64245,11 @@ async function updateFromChannel(args, deps) {
63632
64245
  channelRef.extId,
63633
64246
  channelRef.ownerPrincipalId
63634
64247
  );
63635
- const liveDir = import_node_path61.default.join(deps.extensionsRoot, localExtId);
64248
+ const liveDir = import_node_path63.default.join(deps.extensionsRoot, localExtId);
63636
64249
  const prevDir = `${liveDir}.prev`;
63637
64250
  let existingVersion;
63638
64251
  try {
63639
- const raw = await import_promises11.default.readFile(import_node_path61.default.join(liveDir, "manifest.json"), "utf8");
64252
+ const raw = await import_promises13.default.readFile(import_node_path63.default.join(liveDir, "manifest.json"), "utf8");
63640
64253
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
63641
64254
  if (!parsed2.success) {
63642
64255
  throw new UpdateError(
@@ -63669,7 +64282,7 @@ async function updateFromChannel(args, deps) {
63669
64282
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
63670
64283
  }
63671
64284
  for (const name of Object.keys(zip.files)) {
63672
- if (name.includes("..") || name.startsWith("/") || import_node_path61.default.isAbsolute(name)) {
64285
+ if (name.includes("..") || name.startsWith("/") || import_node_path63.default.isAbsolute(name)) {
63673
64286
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
63674
64287
  }
63675
64288
  }
@@ -63701,31 +64314,31 @@ async function updateFromChannel(args, deps) {
63701
64314
  );
63702
64315
  }
63703
64316
  await deps.runtime.close(localExtId);
63704
- await import_promises11.default.rm(prevDir, { recursive: true, force: true });
63705
- await import_promises11.default.rename(liveDir, prevDir);
63706
- const stage = await import_promises11.default.mkdtemp(
63707
- import_node_path61.default.join(import_node_os23.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
64317
+ await import_promises13.default.rm(prevDir, { recursive: true, force: true });
64318
+ await import_promises13.default.rename(liveDir, prevDir);
64319
+ const stage = await import_promises13.default.mkdtemp(
64320
+ import_node_path63.default.join(import_node_os23.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
63708
64321
  );
63709
64322
  try {
63710
64323
  for (const [name, entry] of Object.entries(zip.files)) {
63711
- const dest = import_node_path61.default.join(stage, name);
64324
+ const dest = import_node_path63.default.join(stage, name);
63712
64325
  if (entry.dir) {
63713
- await import_promises11.default.mkdir(dest, { recursive: true });
64326
+ await import_promises13.default.mkdir(dest, { recursive: true });
63714
64327
  continue;
63715
64328
  }
63716
- await import_promises11.default.mkdir(import_node_path61.default.dirname(dest), { recursive: true });
64329
+ await import_promises13.default.mkdir(import_node_path63.default.dirname(dest), { recursive: true });
63717
64330
  if (name === "manifest.json") {
63718
64331
  const rewritten = { ...parsed.data, id: localExtId };
63719
- await import_promises11.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64332
+ await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
63720
64333
  } else {
63721
- await import_promises11.default.writeFile(dest, await entry.async("nodebuffer"));
64334
+ await import_promises13.default.writeFile(dest, await entry.async("nodebuffer"));
63722
64335
  }
63723
64336
  }
63724
- await import_promises11.default.rename(stage, liveDir);
64337
+ await import_promises13.default.rename(stage, liveDir);
63725
64338
  } catch (e) {
63726
- await import_promises11.default.rm(stage, { recursive: true, force: true }).catch(() => {
64339
+ await import_promises13.default.rm(stage, { recursive: true, force: true }).catch(() => {
63727
64340
  });
63728
- await import_promises11.default.rename(prevDir, liveDir).catch(() => {
64341
+ await import_promises13.default.rename(prevDir, liveDir).catch(() => {
63729
64342
  });
63730
64343
  await deps.runtime.open(localExtId).catch(() => {
63731
64344
  });
@@ -63747,7 +64360,7 @@ async function updateFromChannel(args, deps) {
63747
64360
  reason: e.message
63748
64361
  };
63749
64362
  }
63750
- await import_promises11.default.rm(prevDir, { recursive: true, force: true });
64363
+ await import_promises13.default.rm(prevDir, { recursive: true, force: true });
63751
64364
  return {
63752
64365
  kind: "updated",
63753
64366
  extId: localExtId,
@@ -63755,9 +64368,9 @@ async function updateFromChannel(args, deps) {
63755
64368
  };
63756
64369
  }
63757
64370
  async function rollback(deps, localExtId, liveDir, prevDir) {
63758
- await import_promises11.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
64371
+ await import_promises13.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
63759
64372
  });
63760
- await import_promises11.default.rename(prevDir, liveDir).catch(() => {
64373
+ await import_promises13.default.rename(prevDir, liveDir).catch(() => {
63761
64374
  });
63762
64375
  await deps.runtime.open(localExtId).catch(() => {
63763
64376
  });
@@ -63780,18 +64393,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
63780
64393
  );
63781
64394
  }
63782
64395
  }
63783
- const manifestPath = import_node_path62.default.join(root, extId, "manifest.json");
64396
+ const manifestPath = import_node_path64.default.join(root, extId, "manifest.json");
63784
64397
  const manifest = await readManifest(root, extId);
63785
64398
  const next = { ...manifest, version: newVersion };
63786
64399
  const tmp = `${manifestPath}.tmp`;
63787
- await import_promises12.default.writeFile(tmp, JSON.stringify(next, null, 2));
63788
- await import_promises12.default.rename(tmp, manifestPath);
64400
+ await import_promises14.default.writeFile(tmp, JSON.stringify(next, null, 2));
64401
+ await import_promises14.default.rename(tmp, manifestPath);
63789
64402
  }
63790
64403
  async function readManifest(root, extId) {
63791
- const file = import_node_path62.default.join(root, extId, "manifest.json");
64404
+ const file = import_node_path64.default.join(root, extId, "manifest.json");
63792
64405
  let raw;
63793
64406
  try {
63794
- raw = await import_promises12.default.readFile(file, "utf8");
64407
+ raw = await import_promises14.default.readFile(file, "utf8");
63795
64408
  } catch (e) {
63796
64409
  if (e.code === "ENOENT") {
63797
64410
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -63872,7 +64485,7 @@ function buildExtensionHandlers(deps) {
63872
64485
  };
63873
64486
  async function buildSnapshotMeta(extId) {
63874
64487
  const manifest = await readManifest(deps.root, extId);
63875
- const { sha256, buffer } = await bundleExtensionDir(import_node_path62.default.join(deps.root, extId));
64488
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path64.default.join(deps.root, extId));
63876
64489
  return { manifest, contentHash: sha256, buffer };
63877
64490
  }
63878
64491
  const publish = async (frame, _client, ctx) => {
@@ -64049,7 +64662,7 @@ function buildExtensionHandlers(deps) {
64049
64662
  // src/app-builder/project-store.ts
64050
64663
  var import_node_fs50 = require("fs");
64051
64664
  var import_node_child_process15 = require("child_process");
64052
- var import_node_path63 = require("path");
64665
+ var import_node_path65 = require("path");
64053
64666
  init_protocol();
64054
64667
  var PROJECTS_DIR = "projects";
64055
64668
  var META_FILE = ".clawd-project.json";
@@ -64063,14 +64676,14 @@ var ProjectStore = class {
64063
64676
  root;
64064
64677
  /** projects/<name>/.clawd-project.json 路径 */
64065
64678
  metaPath(name) {
64066
- return (0, import_node_path63.join)(this.projectsRoot(), name, META_FILE);
64679
+ return (0, import_node_path65.join)(this.projectsRoot(), name, META_FILE);
64067
64680
  }
64068
64681
  /** projects/<name>/ 目录路径(cwd 用) */
64069
64682
  projectDir(name) {
64070
- return (0, import_node_path63.join)(this.projectsRoot(), name);
64683
+ return (0, import_node_path65.join)(this.projectsRoot(), name);
64071
64684
  }
64072
64685
  projectsRoot() {
64073
- return (0, import_node_path63.join)(this.root, PROJECTS_DIR);
64686
+ return (0, import_node_path65.join)(this.root, PROJECTS_DIR);
64074
64687
  }
64075
64688
  async list() {
64076
64689
  let entries;
@@ -64373,7 +64986,7 @@ var PublishJobRegistry = class {
64373
64986
  // src/app-builder/publish-job-runner.ts
64374
64987
  var import_node_child_process17 = require("child_process");
64375
64988
  var import_node_fs51 = require("fs");
64376
- var import_node_path64 = require("path");
64989
+ var import_node_path66 = require("path");
64377
64990
 
64378
64991
  // src/app-builder/publish-stage-parser.ts
64379
64992
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -64405,7 +65018,7 @@ async function startPublishJob(deps, args) {
64405
65018
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
64406
65019
  }
64407
65020
  const projDir = projectDir(args.name);
64408
- const logPath = (0, import_node_path64.join)(projDir, ".publish.log");
65021
+ const logPath = (0, import_node_path66.join)(projDir, ".publish.log");
64409
65022
  let logStream = null;
64410
65023
  try {
64411
65024
  logStream = (0, import_node_fs51.createWriteStream)(logPath, { flags: "w" });
@@ -64665,7 +65278,7 @@ async function recoverInterruptedJobs(deps) {
64665
65278
 
64666
65279
  // src/handlers/app-builder.ts
64667
65280
  init_protocol();
64668
- var import_node_path65 = require("path");
65281
+ var import_node_path67 = require("path");
64669
65282
  var import_node_fs52 = require("fs");
64670
65283
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
64671
65284
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -64816,8 +65429,8 @@ function buildAppBuilderHandlers(deps) {
64816
65429
  const project = await userStore.create(f.name, reservedPorts);
64817
65430
  try {
64818
65431
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
64819
- const templateSrcDir = (0, import_node_path65.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
64820
- const scaffoldScript = (0, import_node_path65.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
65432
+ const templateSrcDir = (0, import_node_path67.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
65433
+ const scaffoldScript = (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
64821
65434
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
64822
65435
  deps.logger?.info("app-builder.scaffold.done", {
64823
65436
  name: project.name,
@@ -65021,7 +65634,7 @@ function buildAppBuilderHandlers(deps) {
65021
65634
  await userStore.clearPublishJob(args.name);
65022
65635
  }
65023
65636
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
65024
- const scriptPath = (0, import_node_path65.join)(deps.deployKitRoot, "scripts", "publish.sh");
65637
+ const scriptPath = (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "publish.sh");
65025
65638
  deps.logger?.info("app-builder.publish.start", {
65026
65639
  name: args.name,
65027
65640
  sessionId: boundSession.sessionId,
@@ -65250,7 +65863,7 @@ function joinLines(records, lineMeta) {
65250
65863
  return out;
65251
65864
  }
65252
65865
  function buildTopicHandlers(deps) {
65253
- const mustGet = (topicId) => {
65866
+ const mustGet2 = (topicId) => {
65254
65867
  const t = deps.topicStore.get(topicId);
65255
65868
  if (!t) throw new ClawdError(ERROR_CODES.INVALID_PARAM, `topic not found: ${topicId}`);
65256
65869
  return t;
@@ -65283,7 +65896,7 @@ function buildTopicHandlers(deps) {
65283
65896
  },
65284
65897
  "topic:get": async (frame) => {
65285
65898
  const args = TopicGetArgsSchema.parse(frame);
65286
- const topic = args.topicId ? mustGet(args.topicId) : deps.topicStore.getByMasterSession(args.sessionId);
65899
+ const topic = args.topicId ? mustGet2(args.topicId) : deps.topicStore.getByMasterSession(args.sessionId);
65287
65900
  if (!topic) {
65288
65901
  throw new ClawdError(
65289
65902
  ERROR_CODES.INVALID_PARAM,
@@ -65314,7 +65927,7 @@ function buildTopicHandlers(deps) {
65314
65927
  },
65315
65928
  "topic:setPlan": async (frame) => {
65316
65929
  const args = TopicSetPlanArgsSchema.parse(frame);
65317
- mustGet(args.topicId);
65930
+ mustGet2(args.topicId);
65318
65931
  const topic = deps.topicStore.setPlan(args.topicId, {
65319
65932
  ...args.title ? { title: args.title } : {},
65320
65933
  goal: args.goal,
@@ -65326,7 +65939,7 @@ function buildTopicHandlers(deps) {
65326
65939
  },
65327
65940
  "topic:append": async (frame) => {
65328
65941
  const args = TopicAppendArgsSchema.parse(frame);
65329
- const topic = mustGet(args.topicId);
65942
+ const topic = mustGet2(args.topicId);
65330
65943
  deps.topicStore.appendActivity(args.topicId, {
65331
65944
  actor: "master",
65332
65945
  action: args.action,
@@ -65339,7 +65952,7 @@ function buildTopicHandlers(deps) {
65339
65952
  },
65340
65953
  "topic:reject": async (frame) => {
65341
65954
  const args = TopicRejectArgsSchema.parse(frame);
65342
- const topic = mustGet(args.topicId);
65955
+ const topic = mustGet2(args.topicId);
65343
65956
  const { rejectCount } = deps.topicStore.bumpReject(args.topicId, args.lineId);
65344
65957
  if (topic.state === "done") deps.topicStore.setState(args.topicId, "running");
65345
65958
  deps.topicStore.appendActivity(args.topicId, {
@@ -65358,7 +65971,7 @@ function buildTopicHandlers(deps) {
65358
65971
  },
65359
65972
  "topic:accept": async (frame) => {
65360
65973
  const args = TopicAcceptArgsSchema.parse(frame);
65361
- const topic = mustGet(args.topicId);
65974
+ const topic = mustGet2(args.topicId);
65362
65975
  if (!linesOf(topic).some((l) => l.lineId === args.lineId)) {
65363
65976
  throw new ClawdError(
65364
65977
  ERROR_CODES.INVALID_PARAM,
@@ -65382,11 +65995,11 @@ function buildTopicHandlers(deps) {
65382
65995
  reason: args.reason,
65383
65996
  ...args.artifacts ? { artifacts: args.artifacts } : {}
65384
65997
  });
65385
- const lines = linesOf(mustGet(args.topicId));
65998
+ const lines = linesOf(mustGet2(args.topicId));
65386
65999
  const acceptedLines = lines.filter((l) => l.accepted).length;
65387
66000
  const allAccepted = lines.length > 0 && acceptedLines === lines.length;
65388
66001
  if (allAccepted) deps.topicStore.setState(args.topicId, "done");
65389
- const overrides = Object.values(mustGet(args.topicId).lineMeta).reduce(
66002
+ const overrides = Object.values(mustGet2(args.topicId).lineMeta).reduce(
65390
66003
  (n, m2) => n + (m2.overrideCount ?? 0),
65391
66004
  0
65392
66005
  );
@@ -65403,21 +66016,21 @@ function buildTopicHandlers(deps) {
65403
66016
  },
65404
66017
  "topic:close": async (frame) => {
65405
66018
  const args = TopicCloseArgsSchema.parse(frame);
65406
- mustGet(args.topicId);
66019
+ mustGet2(args.topicId);
65407
66020
  const topic = deps.topicStore.setState(args.topicId, args.state);
65408
66021
  announceChanged(topic);
65409
66022
  return { response: TopicResultSchema.parse({ topic }) };
65410
66023
  },
65411
66024
  "topic:rename": async (frame) => {
65412
66025
  const args = TopicRenameArgsSchema.parse(frame);
65413
- mustGet(args.topicId);
66026
+ mustGet2(args.topicId);
65414
66027
  const topic = deps.topicStore.rename(args.topicId, args.title);
65415
66028
  announceChanged(topic);
65416
66029
  return { response: TopicResultSchema.parse({ topic }) };
65417
66030
  },
65418
66031
  "topic:delete": async (frame) => {
65419
66032
  const { topicId } = TopicDeleteArgsSchema.parse(frame);
65420
- const topic = mustGet(topicId);
66033
+ const topic = mustGet2(topicId);
65421
66034
  const { removed, broadcast } = deps.deleteSession(topic.masterSessionId);
65422
66035
  const removedWorkerSessionIds = [];
65423
66036
  const allBroadcast = [...broadcast];
@@ -65452,7 +66065,7 @@ function buildTopicHandlers(deps) {
65452
66065
  init_protocol();
65453
66066
 
65454
66067
  // src/channel/authority.ts
65455
- var import_promises13 = __toESM(require("fs/promises"), 1);
66068
+ var import_promises15 = __toESM(require("fs/promises"), 1);
65456
66069
  init_protocol();
65457
66070
  var DEFAULT_AUTHORITY_RULES = [
65458
66071
  { id: "outbound-message", desc: "\u4EE5\u8001\u677F\u540D\u4E49\u7ED9\u5176\u4ED6\u4EBA\u53D1\u6D88\u606F\uFF08IM/\u90AE\u4EF6\uFF09", action: "ask" },
@@ -65470,7 +66083,7 @@ async function resolveAuthority(args) {
65470
66083
  let source;
65471
66084
  let raw = null;
65472
66085
  try {
65473
- raw = await import_promises13.default.readFile(args.tablePath, "utf8");
66086
+ raw = await import_promises15.default.readFile(args.tablePath, "utf8");
65474
66087
  } catch (e) {
65475
66088
  if (e.code !== "ENOENT") {
65476
66089
  return askBecause(`\u6388\u6743\u8BBE\u5B9A\u8BFB\u4E0D\u51FA\u6765\uFF08${args.tablePath}\uFF09\uFF1A${e.message}`);
@@ -65755,7 +66368,7 @@ function buildGithubHandlers(deps) {
65755
66368
 
65756
66369
  // src/handlers/visitor.ts
65757
66370
  init_protocol();
65758
- function ensureOwner4(ctx) {
66371
+ function ensureOwner5(ctx) {
65759
66372
  if (!ctx || ctx.principal.kind !== "owner") {
65760
66373
  throw new ClawdError(
65761
66374
  ERROR_CODES.UNAUTHORIZED,
@@ -65765,7 +66378,7 @@ function ensureOwner4(ctx) {
65765
66378
  }
65766
66379
  function buildVisitorHandlers(deps) {
65767
66380
  const list = async (_frame, _client, ctx) => {
65768
- ensureOwner4(ctx);
66381
+ ensureOwner5(ctx);
65769
66382
  return {
65770
66383
  response: {
65771
66384
  type: "visitor:list",
@@ -65779,12 +66392,12 @@ function buildVisitorHandlers(deps) {
65779
66392
  }
65780
66393
 
65781
66394
  // src/extension/registry.ts
65782
- var import_promises14 = __toESM(require("fs/promises"), 1);
65783
- var import_node_path66 = __toESM(require("path"), 1);
66395
+ var import_promises16 = __toESM(require("fs/promises"), 1);
66396
+ var import_node_path68 = __toESM(require("path"), 1);
65784
66397
  async function loadAll(root) {
65785
66398
  let entries;
65786
66399
  try {
65787
- entries = await import_promises14.default.readdir(root, { withFileTypes: true });
66400
+ entries = await import_promises16.default.readdir(root, { withFileTypes: true });
65788
66401
  } catch (e) {
65789
66402
  if (e.code === "ENOENT") return [];
65790
66403
  throw e;
@@ -65793,16 +66406,16 @@ async function loadAll(root) {
65793
66406
  for (const ent of entries) {
65794
66407
  if (!ent.isDirectory()) continue;
65795
66408
  if (ent.name.startsWith(".")) continue;
65796
- records.push(await loadOne(import_node_path66.default.join(root, ent.name), ent.name));
66409
+ records.push(await loadOne(import_node_path68.default.join(root, ent.name), ent.name));
65797
66410
  }
65798
66411
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
65799
66412
  return records;
65800
66413
  }
65801
66414
  async function loadOne(dir, dirName) {
65802
- const manifestPath = import_node_path66.default.join(dir, "manifest.json");
66415
+ const manifestPath = import_node_path68.default.join(dir, "manifest.json");
65803
66416
  let raw;
65804
66417
  try {
65805
- raw = await import_promises14.default.readFile(manifestPath, "utf8");
66418
+ raw = await import_promises16.default.readFile(manifestPath, "utf8");
65806
66419
  } catch {
65807
66420
  return {
65808
66421
  extId: dirName,
@@ -65843,8 +66456,8 @@ async function loadOne(dir, dirName) {
65843
66456
  }
65844
66457
 
65845
66458
  // src/extension/uninstall.ts
65846
- var import_promises15 = __toESM(require("fs/promises"), 1);
65847
- var import_node_path67 = __toESM(require("path"), 1);
66459
+ var import_promises17 = __toESM(require("fs/promises"), 1);
66460
+ var import_node_path69 = __toESM(require("path"), 1);
65848
66461
  var UninstallError = class extends Error {
65849
66462
  constructor(code, message) {
65850
66463
  super(message);
@@ -65853,14 +66466,14 @@ var UninstallError = class extends Error {
65853
66466
  code;
65854
66467
  };
65855
66468
  async function uninstall(deps) {
65856
- const dir = import_node_path67.default.join(deps.root, deps.extId);
66469
+ const dir = import_node_path69.default.join(deps.root, deps.extId);
65857
66470
  try {
65858
- await import_promises15.default.access(dir);
66471
+ await import_promises17.default.access(dir);
65859
66472
  } catch {
65860
66473
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
65861
66474
  }
65862
66475
  await deps.runtime.close(deps.extId);
65863
- await import_promises15.default.rm(dir, { recursive: true, force: true });
66476
+ await import_promises17.default.rm(dir, { recursive: true, force: true });
65864
66477
  }
65865
66478
 
65866
66479
  // src/handlers/index.ts
@@ -66086,7 +66699,7 @@ function buildMethodHandlers(deps) {
66086
66699
  broadcast: deps.broadcastToOwners
66087
66700
  }),
66088
66701
  ...buildMasterHandlers({
66089
- authorityTablePath: import_node_path68.default.join(deps.masterDataDir, "master-authority.json")
66702
+ authorityTablePath: import_node_path70.default.join(deps.masterDataDir, "master-authority.json")
66090
66703
  }),
66091
66704
  ...buildTopicHandlers({
66092
66705
  topicStore: deps.topicStore,
@@ -66132,8 +66745,8 @@ function refreshPathFromLoginShell() {
66132
66745
  timeout: 3e3,
66133
66746
  stdio: ["ignore", "pipe", "ignore"]
66134
66747
  });
66135
- const path91 = out.trim();
66136
- if (path91) process.env.PATH = path91;
66748
+ const path93 = out.trim();
66749
+ if (path93) process.env.PATH = path93;
66137
66750
  } catch {
66138
66751
  }
66139
66752
  }
@@ -66547,8 +67160,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
66547
67160
 
66548
67161
  // src/extension/runtime.ts
66549
67162
  var import_node_child_process22 = require("child_process");
66550
- var import_node_path69 = __toESM(require("path"), 1);
66551
- var import_promises16 = require("timers/promises");
67163
+ var import_node_path71 = __toESM(require("path"), 1);
67164
+ var import_promises18 = require("timers/promises");
66552
67165
 
66553
67166
  // src/extension/port-allocator.ts
66554
67167
  var import_node_net2 = __toESM(require("net"), 1);
@@ -66648,7 +67261,7 @@ var Runtime = class {
66648
67261
  /\$CLAWOS_EXT_PORT/g,
66649
67262
  String(port)
66650
67263
  );
66651
- const dir = import_node_path69.default.join(this.root, extId);
67264
+ const dir = import_node_path71.default.join(this.root, extId);
66652
67265
  const env = {
66653
67266
  ...process.env,
66654
67267
  CLAWOS_EXT_PORT: String(port),
@@ -66724,7 +67337,7 @@ ${handle.stderrTail}`
66724
67337
  if (res.ok) return;
66725
67338
  } catch {
66726
67339
  }
66727
- await (0, import_promises16.setTimeout)(this.healthzIntervalMs);
67340
+ await (0, import_promises18.setTimeout)(this.healthzIntervalMs);
66728
67341
  }
66729
67342
  throw new RuntimeError(
66730
67343
  "HEALTHZ_FAILED",
@@ -66749,7 +67362,7 @@ ${handle.stderrTail}`
66749
67362
  };
66750
67363
  killGroup("SIGTERM");
66751
67364
  const exited = new Promise((resolve9) => child.once("exit", () => resolve9()));
66752
- const timed = (0, import_promises16.setTimeout)(5e3).then(() => "timeout");
67365
+ const timed = (0, import_promises18.setTimeout)(5e3).then(() => "timeout");
66753
67366
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
66754
67367
  if (winner === "timeout" && child.exitCode === null) {
66755
67368
  killGroup("SIGKILL");
@@ -66759,8 +67372,8 @@ ${handle.stderrTail}`
66759
67372
  };
66760
67373
 
66761
67374
  // src/extension/published-channels.ts
66762
- var import_promises17 = __toESM(require("fs/promises"), 1);
66763
- var import_node_path70 = __toESM(require("path"), 1);
67375
+ var import_promises19 = __toESM(require("fs/promises"), 1);
67376
+ var import_node_path72 = __toESM(require("path"), 1);
66764
67377
  init_zod();
66765
67378
  var PublishedChannelsError = class extends Error {
66766
67379
  constructor(code, message) {
@@ -66790,7 +67403,7 @@ var PublishedChannelStore = class {
66790
67403
  this.channels.clear();
66791
67404
  let raw;
66792
67405
  try {
66793
- raw = await import_promises17.default.readFile(this.filePath, "utf8");
67406
+ raw = await import_promises19.default.readFile(this.filePath, "utf8");
66794
67407
  } catch (e) {
66795
67408
  if (e.code === "ENOENT") {
66796
67409
  this.loaded = true;
@@ -66859,15 +67472,15 @@ var PublishedChannelStore = class {
66859
67472
  )
66860
67473
  };
66861
67474
  const tmp = `${this.filePath}.tmp`;
66862
- await import_promises17.default.mkdir(import_node_path70.default.dirname(this.filePath), { recursive: true });
66863
- await import_promises17.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
66864
- await import_promises17.default.rename(tmp, this.filePath);
67475
+ await import_promises19.default.mkdir(import_node_path72.default.dirname(this.filePath), { recursive: true });
67476
+ await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
67477
+ await import_promises19.default.rename(tmp, this.filePath);
66865
67478
  }
66866
67479
  };
66867
67480
 
66868
67481
  // src/extension/bundle-cache.ts
66869
- var import_promises18 = __toESM(require("fs/promises"), 1);
66870
- var import_node_path71 = __toESM(require("path"), 1);
67482
+ var import_promises20 = __toESM(require("fs/promises"), 1);
67483
+ var import_node_path73 = __toESM(require("path"), 1);
66871
67484
  var BundleCache = class {
66872
67485
  constructor(rootDir) {
66873
67486
  this.rootDir = rootDir;
@@ -66875,17 +67488,17 @@ var BundleCache = class {
66875
67488
  rootDir;
66876
67489
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
66877
67490
  async write(snapshotHash, buffer) {
66878
- await import_promises18.default.mkdir(this.rootDir, { recursive: true });
66879
- const file = import_node_path71.default.join(this.rootDir, `${snapshotHash}.zip`);
67491
+ await import_promises20.default.mkdir(this.rootDir, { recursive: true });
67492
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
66880
67493
  const tmp = `${file}.tmp`;
66881
- await import_promises18.default.writeFile(tmp, buffer, { mode: 384 });
66882
- await import_promises18.default.rename(tmp, file);
67494
+ await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
67495
+ await import_promises20.default.rename(tmp, file);
66883
67496
  }
66884
67497
  /** Returns the bundle bytes, or null when the file doesn't exist. */
66885
67498
  async read(snapshotHash) {
66886
- const file = import_node_path71.default.join(this.rootDir, `${snapshotHash}.zip`);
67499
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
66887
67500
  try {
66888
- return await import_promises18.default.readFile(file);
67501
+ return await import_promises20.default.readFile(file);
66889
67502
  } catch (e) {
66890
67503
  if (e.code === "ENOENT") return null;
66891
67504
  throw e;
@@ -66893,8 +67506,8 @@ var BundleCache = class {
66893
67506
  }
66894
67507
  /** Idempotent — missing file is not an error. */
66895
67508
  async delete(snapshotHash) {
66896
- const file = import_node_path71.default.join(this.rootDir, `${snapshotHash}.zip`);
66897
- await import_promises18.default.rm(file, { force: true });
67509
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
67510
+ await import_promises20.default.rm(file, { force: true });
66898
67511
  }
66899
67512
  };
66900
67513
 
@@ -66916,24 +67529,24 @@ async function startDaemon(config) {
66916
67529
  sampling: logShippingCfg.sampling,
66917
67530
  homeDir: import_node_os26.default.homedir()
66918
67531
  });
66919
- const logDir = import_node_path72.default.join(config.dataDir, "log");
67532
+ const logDir = import_node_path74.default.join(config.dataDir, "log");
66920
67533
  import_node_fs53.default.mkdirSync(logDir, { recursive: true });
66921
67534
  const logger = createLogger({
66922
67535
  level: config.logLevel,
66923
- file: import_node_path72.default.join(logDir, "clawd.log"),
67536
+ file: import_node_path74.default.join(logDir, "clawd.log"),
66924
67537
  logClient
66925
67538
  });
66926
67539
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
66927
67540
  const screenIdleProbeLogger = createFileOnlyLogger({
66928
- file: import_node_path72.default.join(logDir, "screen-idle-probe.log"),
67541
+ file: import_node_path74.default.join(logDir, "screen-idle-probe.log"),
66929
67542
  level: "debug"
66930
67543
  });
66931
67544
  logger.info("screen-idle probe logger enabled", {
66932
- file: import_node_path72.default.join(logDir, "screen-idle-probe.log")
67545
+ file: import_node_path74.default.join(logDir, "screen-idle-probe.log")
66933
67546
  });
66934
67547
  const CAP_TARGETS = [
66935
- import_node_path72.default.join(logDir, "clawd.log"),
66936
- import_node_path72.default.join(logDir, "screen-idle-probe.log")
67548
+ import_node_path74.default.join(logDir, "clawd.log"),
67549
+ import_node_path74.default.join(logDir, "screen-idle-probe.log")
66937
67550
  ];
66938
67551
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
66939
67552
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -67055,8 +67668,8 @@ async function startDaemon(config) {
67055
67668
  const agents = new AgentsScanner();
67056
67669
  const history = new ClaudeHistoryReader();
67057
67670
  let transport = null;
67058
- const personaStore = new PersonaStore(import_node_path72.default.join(config.dataDir, "personas"));
67059
- const usersRoot = import_node_path72.default.join(config.dataDir, "users");
67671
+ const personaStore = new PersonaStore(import_node_path74.default.join(config.dataDir, "personas"));
67672
+ const usersRoot = import_node_path74.default.join(config.dataDir, "users");
67060
67673
  const defaultsRoot = findDefaultsRoot(logger);
67061
67674
  if (defaultsRoot) {
67062
67675
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -67080,7 +67693,7 @@ async function startDaemon(config) {
67080
67693
  retirePersonaBuilder({ store: personaStore, logger });
67081
67694
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
67082
67695
  const dispatchStore = createDispatchStore({
67083
- filePath: import_node_path72.default.join(config.dataDir, "dispatch.json"),
67696
+ filePath: import_node_path74.default.join(config.dataDir, "dispatch.json"),
67084
67697
  now: () => Date.now(),
67085
67698
  onFlushError: (err) => logger.error("dispatch store flush failed", {
67086
67699
  reason: err instanceof Error ? err.message : String(err)
@@ -67089,7 +67702,7 @@ async function startDaemon(config) {
67089
67702
  await dispatchStore.load();
67090
67703
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
67091
67704
  const channelStore = createChannelStore({
67092
- filePath: import_node_path72.default.join(config.dataDir, "channels.json"),
67705
+ filePath: import_node_path74.default.join(config.dataDir, "channels.json"),
67093
67706
  now: () => Date.now(),
67094
67707
  genId: () => `ch-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
67095
67708
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -67098,7 +67711,7 @@ async function startDaemon(config) {
67098
67711
  });
67099
67712
  await channelStore.load();
67100
67713
  const topicStore = createTopicStore({
67101
- filePath: import_node_path72.default.join(config.dataDir, "topics.json"),
67714
+ filePath: import_node_path74.default.join(config.dataDir, "topics.json"),
67102
67715
  now: () => Date.now(),
67103
67716
  genId: () => `tp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
67104
67717
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -67125,18 +67738,18 @@ async function startDaemon(config) {
67125
67738
  });
67126
67739
  }
67127
67740
  });
67128
- const here = typeof __dirname === "string" ? __dirname : import_node_path72.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
67741
+ const here = typeof __dirname === "string" ? __dirname : import_node_path74.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
67129
67742
  const mcpConfigs = [];
67130
67743
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
67131
67744
  const dispatchServerCandidates = [
67132
- import_node_path72.default.join(here, "dispatch", "mcp-server.cjs"),
67745
+ import_node_path74.default.join(here, "dispatch", "mcp-server.cjs"),
67133
67746
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
67134
- import_node_path72.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
67747
+ import_node_path74.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
67135
67748
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
67136
67749
  ];
67137
67750
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67138
67751
  if (dispatchServerScriptPath) {
67139
- const dispatchLogPath = import_node_path72.default.join(logDir, "dispatch-mcp-server.log");
67752
+ const dispatchLogPath = import_node_path74.default.join(logDir, "dispatch-mcp-server.log");
67140
67753
  const dispatchCfgPath = writeDispatchMcpConfig({
67141
67754
  dataDir: config.dataDir,
67142
67755
  serverScriptPath: dispatchServerScriptPath,
@@ -67156,12 +67769,12 @@ async function startDaemon(config) {
67156
67769
  });
67157
67770
  }
67158
67771
  const ticketServerCandidates = [
67159
- import_node_path72.default.join(here, "ticket", "mcp-server.cjs"),
67160
- import_node_path72.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
67772
+ import_node_path74.default.join(here, "ticket", "mcp-server.cjs"),
67773
+ import_node_path74.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
67161
67774
  ];
67162
67775
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67163
67776
  if (ticketServerScriptPath) {
67164
- const ticketLogPath = import_node_path72.default.join(logDir, "ticket-mcp-server.log");
67777
+ const ticketLogPath = import_node_path74.default.join(logDir, "ticket-mcp-server.log");
67165
67778
  const ticketCfgPath = writeTicketMcpConfig({
67166
67779
  dataDir: config.dataDir,
67167
67780
  serverScriptPath: ticketServerScriptPath,
@@ -67183,12 +67796,12 @@ async function startDaemon(config) {
67183
67796
  });
67184
67797
  }
67185
67798
  const shiftServerCandidates = [
67186
- import_node_path72.default.join(here, "shift", "mcp-server.cjs"),
67187
- import_node_path72.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
67799
+ import_node_path74.default.join(here, "shift", "mcp-server.cjs"),
67800
+ import_node_path74.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
67188
67801
  ];
67189
67802
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67190
67803
  if (shiftServerScriptPath) {
67191
- const shiftLogPath = import_node_path72.default.join(logDir, "shift-mcp-server.log");
67804
+ const shiftLogPath = import_node_path74.default.join(logDir, "shift-mcp-server.log");
67192
67805
  const shiftCfgPath = await writeShiftMcpConfig({
67193
67806
  dataDir: config.dataDir,
67194
67807
  serverScriptPath: shiftServerScriptPath,
@@ -67209,12 +67822,12 @@ async function startDaemon(config) {
67209
67822
  );
67210
67823
  }
67211
67824
  const inboxServerCandidates = [
67212
- import_node_path72.default.join(here, "inbox", "mcp-server.cjs"),
67213
- import_node_path72.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
67825
+ import_node_path74.default.join(here, "inbox", "mcp-server.cjs"),
67826
+ import_node_path74.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
67214
67827
  ];
67215
67828
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67216
67829
  if (inboxServerScriptPath) {
67217
- const inboxLogPath = import_node_path72.default.join(logDir, "inbox-mcp-server.log");
67830
+ const inboxLogPath = import_node_path74.default.join(logDir, "inbox-mcp-server.log");
67218
67831
  const inboxCfgPath = await writeInboxMcpConfig({
67219
67832
  dataDir: config.dataDir,
67220
67833
  serverScriptPath: inboxServerScriptPath,
@@ -67235,8 +67848,8 @@ async function startDaemon(config) {
67235
67848
  );
67236
67849
  }
67237
67850
  const peerOpsServerCandidates = [
67238
- import_node_path72.default.join(here, "peer-ops", "mcp-server.cjs"),
67239
- import_node_path72.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
67851
+ import_node_path74.default.join(here, "peer-ops", "mcp-server.cjs"),
67852
+ import_node_path74.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
67240
67853
  ];
67241
67854
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67242
67855
  if (peerOpsServerScriptPath) {
@@ -67258,12 +67871,12 @@ async function startDaemon(config) {
67258
67871
  );
67259
67872
  }
67260
67873
  const rpcToolServerCandidates = [
67261
- import_node_path72.default.join(here, "rpc-tool", "mcp-server.cjs"),
67262
- import_node_path72.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
67874
+ import_node_path74.default.join(here, "rpc-tool", "mcp-server.cjs"),
67875
+ import_node_path74.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
67263
67876
  ];
67264
67877
  const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67265
67878
  if (rpcToolServerScriptPath) {
67266
- const rpcToolLogPath = import_node_path72.default.join(logDir, "rpc-tool-mcp-server.log");
67879
+ const rpcToolLogPath = import_node_path74.default.join(logDir, "rpc-tool-mcp-server.log");
67267
67880
  const rpcToolCfgPath = writeRpcToolMcpConfig({
67268
67881
  dataDir: config.dataDir,
67269
67882
  serverScriptPath: rpcToolServerScriptPath,
@@ -67284,7 +67897,7 @@ async function startDaemon(config) {
67284
67897
  );
67285
67898
  }
67286
67899
  const shiftStore = createShiftStore({
67287
- filePath: import_node_path72.default.join(config.dataDir, "shift.json"),
67900
+ filePath: import_node_path74.default.join(config.dataDir, "shift.json"),
67288
67901
  ownerIdProvider: () => ownerPrincipalId,
67289
67902
  now: () => Date.now()
67290
67903
  });
@@ -67306,7 +67919,7 @@ async function startDaemon(config) {
67306
67919
  getAdapter,
67307
67920
  historyReader: history,
67308
67921
  dataDir: config.dataDir,
67309
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
67922
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67310
67923
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
67311
67924
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
67312
67925
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -67360,7 +67973,7 @@ async function startDaemon(config) {
67360
67973
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
67361
67974
  attachmentGroup: {
67362
67975
  onFileEdit: (input) => {
67363
- const absPath = import_node_path72.default.isAbsolute(input.relPath) ? input.relPath : import_node_path72.default.join(input.cwd, input.relPath);
67976
+ const absPath = import_node_path74.default.isAbsolute(input.relPath) ? input.relPath : import_node_path74.default.join(input.cwd, input.relPath);
67364
67977
  let size = 0;
67365
67978
  try {
67366
67979
  size = import_node_fs53.default.statSync(absPath).size;
@@ -67393,9 +68006,9 @@ async function startDaemon(config) {
67393
68006
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
67394
68007
  }
67395
68008
  const projectsStore = new ProjectsStore({
67396
- file: import_node_path72.default.join(config.dataDir, "projects.json"),
68009
+ file: import_node_path74.default.join(config.dataDir, "projects.json"),
67397
68010
  clawdDir: config.dataDir,
67398
- codexStateFile: import_node_path72.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
68011
+ codexStateFile: import_node_path74.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
67399
68012
  logger
67400
68013
  });
67401
68014
  const observer = new SessionObserver({
@@ -67455,12 +68068,12 @@ async function startDaemon(config) {
67455
68068
  screenIdleProbeLogger
67456
68069
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
67457
68070
  registerAdapter("claude", claudeAdapter);
67458
- const codexIsolatedHome = import_node_path72.default.join(config.dataDir, "codex-home");
68071
+ const codexIsolatedHome = import_node_path74.default.join(config.dataDir, "codex-home");
67459
68072
  try {
67460
68073
  import_node_fs53.default.mkdirSync(codexIsolatedHome, { recursive: true });
67461
68074
  for (const f of ["auth.json", "config.toml"]) {
67462
- const link = import_node_path72.default.join(codexIsolatedHome, f);
67463
- const target = import_node_path72.default.join(import_node_os26.default.homedir(), ".codex", f);
68075
+ const link = import_node_path74.default.join(codexIsolatedHome, f);
68076
+ const target = import_node_path74.default.join(import_node_os26.default.homedir(), ".codex", f);
67464
68077
  if (!import_node_fs53.default.existsSync(link) && import_node_fs53.default.existsSync(target)) import_node_fs53.default.symlinkSync(target, link);
67465
68078
  }
67466
68079
  } catch (err) {
@@ -67474,11 +68087,11 @@ async function startDaemon(config) {
67474
68087
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
67475
68088
  codexHomeFor: (cwd) => resolveCodexHome({
67476
68089
  cwd,
67477
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68090
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67478
68091
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
67479
68092
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
67480
68093
  projectPaths: projectsStore.listMerged().map((x) => x.path),
67481
- sharedHome: import_node_path72.default.join(import_node_os26.default.homedir(), ".codex"),
68094
+ sharedHome: import_node_path74.default.join(import_node_os26.default.homedir(), ".codex"),
67482
68095
  isolatedHome: codexIsolatedHome
67483
68096
  })
67484
68097
  })
@@ -67762,11 +68375,11 @@ async function startDaemon(config) {
67762
68375
  // 'persona/<pid>/owner',default 走 'default'。
67763
68376
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
67764
68377
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
67765
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68378
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67766
68379
  usersRoot
67767
68380
  },
67768
68381
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
67769
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68382
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67770
68383
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
67771
68384
  usersRoot,
67772
68385
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -67865,11 +68478,11 @@ async function startDaemon(config) {
67865
68478
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
67866
68479
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
67867
68480
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
67868
- appBuilderPersonaRoot: import_node_path72.default.join(config.dataDir, "personas", "persona-app-builder"),
68481
+ appBuilderPersonaRoot: import_node_path74.default.join(config.dataDir, "personas", "persona-app-builder"),
67869
68482
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
67870
- deployKitRoot: import_node_path72.default.join(config.dataDir, "deploy-kit"),
68483
+ deployKitRoot: import_node_path74.default.join(config.dataDir, "deploy-kit"),
67871
68484
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
67872
- resolvePersonaRoot: (personaId2) => import_node_path72.default.join(config.dataDir, "personas", personaId2),
68485
+ resolvePersonaRoot: (personaId2) => import_node_path74.default.join(config.dataDir, "personas", personaId2),
67873
68486
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
67874
68487
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
67875
68488
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -67981,6 +68594,58 @@ async function startDaemon(config) {
67981
68594
  ownerIdProvider: () => ownerPrincipalId
67982
68595
  });
67983
68596
  Object.assign(handlers, shiftHandlers);
68597
+ const deployReceipts = createReceiptStore({
68598
+ filePath: import_node_path74.default.join(config.dataDir, "deploy.json"),
68599
+ now: () => Date.now(),
68600
+ onFlushError: (err) => logger.error("deploy receipts flush failed", { error: String(err) })
68601
+ });
68602
+ const deploySecrets = createSecretStore({
68603
+ filePath: import_node_path74.default.join(config.dataDir, "deploy-secrets.json"),
68604
+ now: () => Date.now(),
68605
+ onFlushError: (err) => logger.error("deploy secrets flush failed", { error: String(err) })
68606
+ });
68607
+ await deployReceipts.load();
68608
+ await deploySecrets.load();
68609
+ const interrupted = reconcileInterruptedScans(deployReceipts);
68610
+ if (interrupted.length > 0) logger.warn("deploy scans interrupted by restart", { deployIds: interrupted });
68611
+ const deployHandlers = buildDeployHandlers({
68612
+ receipts: deployReceipts,
68613
+ secrets: deploySecrets,
68614
+ hasPersona: (personaId2) => personaStore.has(personaId2),
68615
+ startScan: (deployId, personaId2) => {
68616
+ const assetLines = SCANNABLE_ASSETS.map(
68617
+ (name) => ` - ${name}\uFF1A${import_node_path74.default.join(config.dataDir, name)}`
68618
+ ).join("\n");
68619
+ const prompt = [
68620
+ `\u626B\u63CF persona\u300C${personaId2}\u300D\u7684\u90E8\u7F72\u73AF\u5883\uFF0CdeployId=${deployId}\u3002`,
68621
+ "",
68622
+ `persona \u76EE\u5F55\uFF1A${personaStore.personaDirPath(personaId2)}`,
68623
+ "\u53EF\u4EE5\u8BFB\u5230\u7684 persona \u76EE\u5F55\u4E4B\u5916\u7684\u5171\u4EAB\u8D44\u4EA7\uFF1A",
68624
+ assetLines || " \uFF08\u65E0\uFF09",
68625
+ "",
68626
+ "\u6309 scan-persona-for-deploy skill \u5E72\u6D3B\uFF1A\u8FB9\u67E5\u8FB9\u7528 deploy:reportFinding \u4E0A\u62A5\uFF0C",
68627
+ "\u5168\u90E8\u67E5\u5B8C\u8C03 deploy:finishScan \u6536\u5C3E\u3002"
68628
+ ].join("\n");
68629
+ let handle;
68630
+ try {
68631
+ handle = manager.createShiftSession({ targetPersona: BUTLER_PERSONA_ID, prompt });
68632
+ } catch (err) {
68633
+ deployReceipts.update(deployId, { status: "scanFailed", error: `\u8D77\u626B\u63CF\u4F1A\u8BDD\u5931\u8D25\uFF1A${String(err)}` });
68634
+ logger.error("deploy scan session failed to start", { deployId, personaId: personaId2, error: String(err) });
68635
+ return void 0;
68636
+ }
68637
+ void handle.ended.then((outcome) => {
68638
+ const patch = settleEndedScan(outcome, deployReceipts.get(deployId));
68639
+ if (!patch) return;
68640
+ deployReceipts.update(deployId, patch);
68641
+ logger.warn("deploy scan ended without finishScan", { deployId, personaId: personaId2, why: patch.error });
68642
+ });
68643
+ return handle.sessionId;
68644
+ },
68645
+ genId: () => `dp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68646
+ now: () => Date.now()
68647
+ });
68648
+ Object.assign(handlers, deployHandlers);
67984
68649
  const shiftSpawnFn = createShiftSpawnFn({ sessionManager: manager });
67985
68650
  const shiftScheduler = createShiftScheduler({
67986
68651
  store: shiftStore,
@@ -67990,7 +68655,7 @@ async function startDaemon(config) {
67990
68655
  });
67991
68656
  shiftScheduler.start();
67992
68657
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
67993
- const larkBotStore = createLarkBotBindingStore(import_node_path72.default.join(config.dataDir, "personas"));
68658
+ const larkBotStore = createLarkBotBindingStore(import_node_path74.default.join(config.dataDir, "personas"));
67994
68659
  const larkBotCloud = createLarkBotCloudClient({
67995
68660
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
67996
68661
  apiKey: resolveClawdTicketsApiKey(),
@@ -68004,7 +68669,7 @@ async function startDaemon(config) {
68004
68669
  store: larkBotStore,
68005
68670
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
68006
68671
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
68007
- mediaRootFor: (chatId) => import_node_path72.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
68672
+ mediaRootFor: (chatId) => import_node_path74.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
68008
68673
  isShuttingDown: () => larkDraining,
68009
68674
  logger: {
68010
68675
  warn: (msg) => logger.warn(msg),
@@ -68309,8 +68974,8 @@ async function startDaemon(config) {
68309
68974
  const lines = [
68310
68975
  `Tunnel: ${r.url}`,
68311
68976
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
68312
- `Frpc config: ${import_node_path72.default.join(config.dataDir, "frpc.toml")}`,
68313
- `Frpc log: ${import_node_path72.default.join(logDir, "frpc.log")}`
68977
+ `Frpc config: ${import_node_path74.default.join(config.dataDir, "frpc.toml")}`,
68978
+ `Frpc log: ${import_node_path74.default.join(logDir, "frpc.log")}`
68314
68979
  ];
68315
68980
  const width2 = Math.max(...lines.map((l) => l.length));
68316
68981
  const bar = "\u2550".repeat(width2 + 4);
@@ -68323,7 +68988,7 @@ ${bar}
68323
68988
 
68324
68989
  `);
68325
68990
  try {
68326
- const connectPath = import_node_path72.default.join(config.dataDir, "connect.txt");
68991
+ const connectPath = import_node_path74.default.join(config.dataDir, "connect.txt");
68327
68992
  import_node_fs53.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
68328
68993
  } catch {
68329
68994
  }
@@ -68390,7 +69055,9 @@ ${bar}
68390
69055
  await wss.stop();
68391
69056
  for (const [name, store2] of [
68392
69057
  ["channels", channelStore],
68393
- ["topics", topicStore]
69058
+ ["topics", topicStore],
69059
+ ["deploy-receipts", deployReceipts],
69060
+ ["deploy-secrets", deploySecrets]
68394
69061
  ]) {
68395
69062
  await store2.flushNow().catch((err) => {
68396
69063
  logger.warn("shutdown.store-flush-failed", {
@@ -68411,7 +69078,7 @@ ${bar}
68411
69078
  };
68412
69079
  }
68413
69080
  function migrateDropPersonsDir(dataDir) {
68414
- const dir = import_node_path72.default.join(dataDir, "persons");
69081
+ const dir = import_node_path74.default.join(dataDir, "persons");
68415
69082
  try {
68416
69083
  import_node_fs53.default.rmSync(dir, { recursive: true, force: true });
68417
69084
  } catch {