@clawos-dev/clawd 0.2.445 → 0.2.447

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({
@@ -7413,6 +7594,14 @@ var init_schemas = __esm({
7413
7594
  // 快速问答临时会话标记(spec 2026-06-23-fork-quick-ask):true = 关闭抽屉即删、
7414
7595
  // 不进 sidebar 树、daemon 启动清扫孤儿。普通会话缺省。
7415
7596
  ephemeral: external_exports.boolean().optional(),
7597
+ /**
7598
+ * 这条会话属于哪张部署单(persona 上云的环境扫描会话)。
7599
+ *
7600
+ * 有值 = 它在单据页右栏里活着,**sidebar 不再列它**——同一条会话两处出现,和话题 worker
7601
+ * 会话不进「最近」是同一条规矩。不复用 `ephemeral`:那个标记会被 daemon 启动清扫**删掉**,
7602
+ * 而扫描会话要跟单据一样长期留着(人隔天回来还要翻管家当时是怎么判的、还要接着追问)。
7603
+ */
7604
+ deployId: external_exports.string().min(1).optional(),
7416
7605
  // owner-mode persona session 身份标识;UI 用它在 SessionList 过滤 + jump,
7417
7606
  // daemon 用它做 idempotent dedupe + spawn 时派生 ctx.personaMode='owner'
7418
7607
  ownerPersonaId: external_exports.string().min(1).optional(),
@@ -8410,6 +8599,7 @@ var init_methods = __esm({
8410
8599
  init_esm();
8411
8600
  init_attachment_schemas();
8412
8601
  init_contact_handshake();
8602
+ init_deploy_schemas();
8413
8603
  init_contact_remote_access();
8414
8604
  init_contact();
8415
8605
  init_feishu_auth();
@@ -8613,6 +8803,42 @@ var init_methods = __esm({
8613
8803
  summary: "\u8BFB\u6587\u4EF6\u5185\u5BB9\uFF1Bguest \u8DEF\u5F84\u8FB9\u754C\u4E0E workspace:list \u540C",
8614
8804
  args: WorkspaceReadArgs
8615
8805
  },
8806
+ "deploy:start": {
8807
+ summary: "\u6253\u5F00\u67D0\u4E2A persona \u7684\u90E8\u7F72\u5355\uFF1A**\u5DF2\u6709\u5C31\u539F\u6837\u8FD4\u56DE\u90A3\u5F20**\uFF08\u8349\u7A3F\u7EED\u586B\uFF0C\u4E0D\u91CD\u626B\uFF0C\u4E5F\u4E0D\u65B0\u5EFA\uFF09\uFF0C\u6CA1\u6709\u624D\u5EFA\u4E00\u5F20\u5E76**\u5F02\u6B65**\u8D77\u73AF\u5883\u626B\u63CF\u3002\u4E00\u4E2A persona \u540C\u65F6\u53EA\u6709\u4E00\u5F20\u5355\uFF0C\u8981\u91CD\u626B\u8D70 deploy:rescan\uFF1Bowner-only",
8808
+ args: DeployStartArgsSchema
8809
+ },
8810
+ "deploy:rescan": {
8811
+ summary: "\u5C31\u5730\u91CD\u626B\u4E00\u5F20\u5DF2\u6709\u7684\u90E8\u7F72\u5355\uFF1A\u6E05\u6389\u4E0A\u6B21\u626B\u51FA\u6765\u7684\u6E05\u5355 / \u8BC1\u636E / \u5B58\u7591\u9879\uFF0C\u72B6\u6001\u56DE scanning\uFF0C\u8D77\u4E00\u4E2A\u65B0\u7684\u626B\u63CF\u4F1A\u8BDD\u3002**\u5DF2\u586B\u7684\u51ED\u636E\u503C\u548C\u5C65\u7EA6\u9009\u62E9\u539F\u6837\u4FDD\u7559**\uFF08\u5B83\u4EEC\u6309\u5355\u636E id \u5B58\uFF0C\u4E0D\u968F\u626B\u63CF\u7ED3\u679C\u8D70\uFF09\uFF0C\u6240\u4EE5\u91CD\u626B\u4E0D\u4F1A\u8BA9\u4EBA\u767D\u586B\u4E00\u904D\uFF1Bowner-only",
8812
+ args: DeployIdArgsSchema
8813
+ },
8814
+ "deploy:list": {
8815
+ summary: "\u5217\u51FA\u5168\u90E8\u90E8\u7F72\u5355\uFF08\u65B0\u7684\u5728\u524D\uFF09\uFF1Bowner-only\u3002\u65E0\u53C2\u6570",
8816
+ args: NO_ARGS
8817
+ },
8818
+ "deploy:get": {
8819
+ 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",
8820
+ args: DeployIdArgsSchema
8821
+ },
8822
+ "deploy:patch": {
8823
+ 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",
8824
+ args: DeployPatchArgsSchema
8825
+ },
8826
+ "deploy:putSecret": {
8827
+ 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",
8828
+ args: DeployPutSecretArgsSchema
8829
+ },
8830
+ "deploy:reportFinding": {
8831
+ 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",
8832
+ args: DeployReportFindingArgsSchema
8833
+ },
8834
+ "deploy:finishScan": {
8835
+ 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",
8836
+ args: DeployFinishScanArgsSchema
8837
+ },
8838
+ "deploy:remove": {
8839
+ 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",
8840
+ args: DeployIdArgsSchema
8841
+ },
8616
8842
  "shift:list": {
8617
8843
  summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
8618
8844
  args: NO_ARGS
@@ -9119,7 +9345,9 @@ var init_errors2 = __esm({
9119
9345
  DISPATCH_NOT_FOUND: "DISPATCH_NOT_FOUND",
9120
9346
  // persona:get 查不到该 personaId,或 guest ctx 查非 public / 无 read grant 的 persona
9121
9347
  // (与 DISPATCH_NOT_FOUND 同款:越权与未知 id 同码,不泄露存在性)。
9122
- PERSONA_NOT_FOUND: "PERSONA_NOT_FOUND"
9348
+ PERSONA_NOT_FOUND: "PERSONA_NOT_FOUND",
9349
+ // deploy:* 查不到该部署单(persona 上云的单据)。同上口径:未知 id 与越权同码。
9350
+ DEPLOY_NOT_FOUND: "DEPLOY_NOT_FOUND"
9123
9351
  };
9124
9352
  ClawdError = class extends Error {
9125
9353
  constructor(code, message) {
@@ -9295,6 +9523,8 @@ var init_runtime = __esm({
9295
9523
  init_errors2();
9296
9524
  init_schemas();
9297
9525
  init_frames();
9526
+ init_environment_schemas();
9527
+ init_deploy_schemas();
9298
9528
  init_persona_schemas();
9299
9529
  init_persona_mode();
9300
9530
  init_attachment_schemas();
@@ -9593,8 +9823,8 @@ var require_req = __commonJS({
9593
9823
  if (req.originalUrl) {
9594
9824
  _req.url = req.originalUrl;
9595
9825
  } else {
9596
- const path91 = req.path;
9597
- _req.url = typeof path91 === "string" ? path91 : req.url ? req.url.path || req.url : void 0;
9826
+ const path93 = req.path;
9827
+ _req.url = typeof path93 === "string" ? path93 : req.url ? req.url.path || req.url : void 0;
9598
9828
  }
9599
9829
  if (req.query) {
9600
9830
  _req.query = req.query;
@@ -9759,14 +9989,14 @@ var require_redact = __commonJS({
9759
9989
  }
9760
9990
  return obj;
9761
9991
  }
9762
- function parsePath(path91) {
9992
+ function parsePath(path93) {
9763
9993
  const parts = [];
9764
9994
  let current = "";
9765
9995
  let inBrackets = false;
9766
9996
  let inQuotes = false;
9767
9997
  let quoteChar = "";
9768
- for (let i = 0; i < path91.length; i++) {
9769
- const char = path91[i];
9998
+ for (let i = 0; i < path93.length; i++) {
9999
+ const char = path93[i];
9770
10000
  if (!inBrackets && char === ".") {
9771
10001
  if (current) {
9772
10002
  parts.push(current);
@@ -9897,10 +10127,10 @@ var require_redact = __commonJS({
9897
10127
  return current;
9898
10128
  }
9899
10129
  function redactPaths(obj, paths, censor, remove = false) {
9900
- for (const path91 of paths) {
9901
- const parts = parsePath(path91);
10130
+ for (const path93 of paths) {
10131
+ const parts = parsePath(path93);
9902
10132
  if (parts.includes("*")) {
9903
- redactWildcardPath(obj, parts, censor, path91, remove);
10133
+ redactWildcardPath(obj, parts, censor, path93, remove);
9904
10134
  } else {
9905
10135
  if (remove) {
9906
10136
  removeKey(obj, parts);
@@ -9985,8 +10215,8 @@ var require_redact = __commonJS({
9985
10215
  }
9986
10216
  } else {
9987
10217
  if (afterWildcard.includes("*")) {
9988
- const wrappedCensor = typeof censor === "function" ? (value, path91) => {
9989
- const fullPath = [...pathArray.slice(0, pathLength), ...path91];
10218
+ const wrappedCensor = typeof censor === "function" ? (value, path93) => {
10219
+ const fullPath = [...pathArray.slice(0, pathLength), ...path93];
9990
10220
  return censor(value, fullPath);
9991
10221
  } : censor;
9992
10222
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -10021,8 +10251,8 @@ var require_redact = __commonJS({
10021
10251
  return null;
10022
10252
  }
10023
10253
  const pathStructure = /* @__PURE__ */ new Map();
10024
- for (const path91 of pathsToClone) {
10025
- const parts = parsePath(path91);
10254
+ for (const path93 of pathsToClone) {
10255
+ const parts = parsePath(path93);
10026
10256
  let current = pathStructure;
10027
10257
  for (let i = 0; i < parts.length; i++) {
10028
10258
  const part = parts[i];
@@ -10074,24 +10304,24 @@ var require_redact = __commonJS({
10074
10304
  }
10075
10305
  return cloneSelectively(obj, pathStructure);
10076
10306
  }
10077
- function validatePath(path91) {
10078
- if (typeof path91 !== "string") {
10307
+ function validatePath(path93) {
10308
+ if (typeof path93 !== "string") {
10079
10309
  throw new Error("Paths must be (non-empty) strings");
10080
10310
  }
10081
- if (path91 === "") {
10311
+ if (path93 === "") {
10082
10312
  throw new Error("Invalid redaction path ()");
10083
10313
  }
10084
- if (path91.includes("..")) {
10085
- throw new Error(`Invalid redaction path (${path91})`);
10314
+ if (path93.includes("..")) {
10315
+ throw new Error(`Invalid redaction path (${path93})`);
10086
10316
  }
10087
- if (path91.includes(",")) {
10088
- throw new Error(`Invalid redaction path (${path91})`);
10317
+ if (path93.includes(",")) {
10318
+ throw new Error(`Invalid redaction path (${path93})`);
10089
10319
  }
10090
10320
  let bracketCount = 0;
10091
10321
  let inQuotes = false;
10092
10322
  let quoteChar = "";
10093
- for (let i = 0; i < path91.length; i++) {
10094
- const char = path91[i];
10323
+ for (let i = 0; i < path93.length; i++) {
10324
+ const char = path93[i];
10095
10325
  if ((char === '"' || char === "'") && bracketCount > 0) {
10096
10326
  if (!inQuotes) {
10097
10327
  inQuotes = true;
@@ -10105,20 +10335,20 @@ var require_redact = __commonJS({
10105
10335
  } else if (char === "]" && !inQuotes) {
10106
10336
  bracketCount--;
10107
10337
  if (bracketCount < 0) {
10108
- throw new Error(`Invalid redaction path (${path91})`);
10338
+ throw new Error(`Invalid redaction path (${path93})`);
10109
10339
  }
10110
10340
  }
10111
10341
  }
10112
10342
  if (bracketCount !== 0) {
10113
- throw new Error(`Invalid redaction path (${path91})`);
10343
+ throw new Error(`Invalid redaction path (${path93})`);
10114
10344
  }
10115
10345
  }
10116
10346
  function validatePaths(paths) {
10117
10347
  if (!Array.isArray(paths)) {
10118
10348
  throw new TypeError("paths must be an array");
10119
10349
  }
10120
- for (const path91 of paths) {
10121
- validatePath(path91);
10350
+ for (const path93 of paths) {
10351
+ validatePath(path93);
10122
10352
  }
10123
10353
  }
10124
10354
  function slowRedact(options = {}) {
@@ -10286,8 +10516,8 @@ var require_redaction = __commonJS({
10286
10516
  if (shape[k2] === null) {
10287
10517
  o[k2] = (value) => topCensor(value, [k2]);
10288
10518
  } else {
10289
- const wrappedCensor = typeof censor === "function" ? (value, path91) => {
10290
- return censor(value, [k2, ...path91]);
10519
+ const wrappedCensor = typeof censor === "function" ? (value, path93) => {
10520
+ return censor(value, [k2, ...path93]);
10291
10521
  } : censor;
10292
10522
  o[k2] = Redact({
10293
10523
  paths: shape[k2],
@@ -10505,10 +10735,10 @@ var require_atomic_sleep = __commonJS({
10505
10735
  var require_sonic_boom = __commonJS({
10506
10736
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10507
10737
  "use strict";
10508
- var fs80 = require("fs");
10738
+ var fs82 = require("fs");
10509
10739
  var EventEmitter3 = require("events");
10510
10740
  var inherits = require("util").inherits;
10511
- var path91 = require("path");
10741
+ var path93 = require("path");
10512
10742
  var sleep2 = require_atomic_sleep();
10513
10743
  var assert = require("assert");
10514
10744
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10562,20 +10792,20 @@ var require_sonic_boom = __commonJS({
10562
10792
  const mode = sonic.mode;
10563
10793
  if (sonic.sync) {
10564
10794
  try {
10565
- if (sonic.mkdir) fs80.mkdirSync(path91.dirname(file), { recursive: true });
10566
- const fd = fs80.openSync(file, flags, mode);
10795
+ if (sonic.mkdir) fs82.mkdirSync(path93.dirname(file), { recursive: true });
10796
+ const fd = fs82.openSync(file, flags, mode);
10567
10797
  fileOpened(null, fd);
10568
10798
  } catch (err) {
10569
10799
  fileOpened(err);
10570
10800
  throw err;
10571
10801
  }
10572
10802
  } else if (sonic.mkdir) {
10573
- fs80.mkdir(path91.dirname(file), { recursive: true }, (err) => {
10803
+ fs82.mkdir(path93.dirname(file), { recursive: true }, (err) => {
10574
10804
  if (err) return fileOpened(err);
10575
- fs80.open(file, flags, mode, fileOpened);
10805
+ fs82.open(file, flags, mode, fileOpened);
10576
10806
  });
10577
10807
  } else {
10578
- fs80.open(file, flags, mode, fileOpened);
10808
+ fs82.open(file, flags, mode, fileOpened);
10579
10809
  }
10580
10810
  }
10581
10811
  function SonicBoom(opts) {
@@ -10616,8 +10846,8 @@ var require_sonic_boom = __commonJS({
10616
10846
  this.flush = flushBuffer;
10617
10847
  this.flushSync = flushBufferSync;
10618
10848
  this._actualWrite = actualWriteBuffer;
10619
- fsWriteSync = () => fs80.writeSync(this.fd, this._writingBuf);
10620
- fsWrite = () => fs80.write(this.fd, this._writingBuf, this.release);
10849
+ fsWriteSync = () => fs82.writeSync(this.fd, this._writingBuf);
10850
+ fsWrite = () => fs82.write(this.fd, this._writingBuf, this.release);
10621
10851
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
10622
10852
  this._writingBuf = "";
10623
10853
  this.write = write;
@@ -10626,15 +10856,15 @@ var require_sonic_boom = __commonJS({
10626
10856
  this._actualWrite = actualWrite;
10627
10857
  fsWriteSync = () => {
10628
10858
  if (Buffer.isBuffer(this._writingBuf)) {
10629
- return fs80.writeSync(this.fd, this._writingBuf);
10859
+ return fs82.writeSync(this.fd, this._writingBuf);
10630
10860
  }
10631
- return fs80.writeSync(this.fd, this._writingBuf, "utf8");
10861
+ return fs82.writeSync(this.fd, this._writingBuf, "utf8");
10632
10862
  };
10633
10863
  fsWrite = () => {
10634
10864
  if (Buffer.isBuffer(this._writingBuf)) {
10635
- return fs80.write(this.fd, this._writingBuf, this.release);
10865
+ return fs82.write(this.fd, this._writingBuf, this.release);
10636
10866
  }
10637
- return fs80.write(this.fd, this._writingBuf, "utf8", this.release);
10867
+ return fs82.write(this.fd, this._writingBuf, "utf8", this.release);
10638
10868
  };
10639
10869
  } else {
10640
10870
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10691,7 +10921,7 @@ var require_sonic_boom = __commonJS({
10691
10921
  }
10692
10922
  }
10693
10923
  if (this._fsync) {
10694
- fs80.fsyncSync(this.fd);
10924
+ fs82.fsyncSync(this.fd);
10695
10925
  }
10696
10926
  const len = this._len;
10697
10927
  if (this._reopening) {
@@ -10805,7 +11035,7 @@ var require_sonic_boom = __commonJS({
10805
11035
  const onDrain = () => {
10806
11036
  if (!this._fsync) {
10807
11037
  try {
10808
- fs80.fsync(this.fd, (err) => {
11038
+ fs82.fsync(this.fd, (err) => {
10809
11039
  this._flushPending = false;
10810
11040
  cb(err);
10811
11041
  });
@@ -10907,7 +11137,7 @@ var require_sonic_boom = __commonJS({
10907
11137
  const fd = this.fd;
10908
11138
  this.once("ready", () => {
10909
11139
  if (fd !== this.fd) {
10910
- fs80.close(fd, (err) => {
11140
+ fs82.close(fd, (err) => {
10911
11141
  if (err) {
10912
11142
  return this.emit("error", err);
10913
11143
  }
@@ -10956,7 +11186,7 @@ var require_sonic_boom = __commonJS({
10956
11186
  buf = this._bufs[0];
10957
11187
  }
10958
11188
  try {
10959
- const n = Buffer.isBuffer(buf) ? fs80.writeSync(this.fd, buf) : fs80.writeSync(this.fd, buf, "utf8");
11189
+ const n = Buffer.isBuffer(buf) ? fs82.writeSync(this.fd, buf) : fs82.writeSync(this.fd, buf, "utf8");
10960
11190
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10961
11191
  buf = releasedBufObj.writingBuf;
10962
11192
  this._len = releasedBufObj.len;
@@ -10972,7 +11202,7 @@ var require_sonic_boom = __commonJS({
10972
11202
  }
10973
11203
  }
10974
11204
  try {
10975
- fs80.fsyncSync(this.fd);
11205
+ fs82.fsyncSync(this.fd);
10976
11206
  } catch {
10977
11207
  }
10978
11208
  }
@@ -10993,7 +11223,7 @@ var require_sonic_boom = __commonJS({
10993
11223
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10994
11224
  }
10995
11225
  try {
10996
- const n = fs80.writeSync(this.fd, buf);
11226
+ const n = fs82.writeSync(this.fd, buf);
10997
11227
  buf = buf.subarray(n);
10998
11228
  this._len = Math.max(this._len - n, 0);
10999
11229
  if (buf.length <= 0) {
@@ -11021,13 +11251,13 @@ var require_sonic_boom = __commonJS({
11021
11251
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
11022
11252
  if (this.sync) {
11023
11253
  try {
11024
- const written = Buffer.isBuffer(this._writingBuf) ? fs80.writeSync(this.fd, this._writingBuf) : fs80.writeSync(this.fd, this._writingBuf, "utf8");
11254
+ const written = Buffer.isBuffer(this._writingBuf) ? fs82.writeSync(this.fd, this._writingBuf) : fs82.writeSync(this.fd, this._writingBuf, "utf8");
11025
11255
  release(null, written);
11026
11256
  } catch (err) {
11027
11257
  release(err);
11028
11258
  }
11029
11259
  } else {
11030
- fs80.write(this.fd, this._writingBuf, release);
11260
+ fs82.write(this.fd, this._writingBuf, release);
11031
11261
  }
11032
11262
  }
11033
11263
  function actualWriteBuffer() {
@@ -11036,7 +11266,7 @@ var require_sonic_boom = __commonJS({
11036
11266
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
11037
11267
  if (this.sync) {
11038
11268
  try {
11039
- const written = fs80.writeSync(this.fd, this._writingBuf);
11269
+ const written = fs82.writeSync(this.fd, this._writingBuf);
11040
11270
  release(null, written);
11041
11271
  } catch (err) {
11042
11272
  release(err);
@@ -11045,7 +11275,7 @@ var require_sonic_boom = __commonJS({
11045
11275
  if (kCopyBuffer) {
11046
11276
  this._writingBuf = Buffer.from(this._writingBuf);
11047
11277
  }
11048
- fs80.write(this.fd, this._writingBuf, release);
11278
+ fs82.write(this.fd, this._writingBuf, release);
11049
11279
  }
11050
11280
  }
11051
11281
  function actualClose(sonic) {
@@ -11061,12 +11291,12 @@ var require_sonic_boom = __commonJS({
11061
11291
  sonic._lens = [];
11062
11292
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
11063
11293
  try {
11064
- fs80.fsync(sonic.fd, closeWrapped);
11294
+ fs82.fsync(sonic.fd, closeWrapped);
11065
11295
  } catch {
11066
11296
  }
11067
11297
  function closeWrapped() {
11068
11298
  if (sonic.fd !== 1 && sonic.fd !== 2) {
11069
- fs80.close(sonic.fd, done);
11299
+ fs82.close(sonic.fd, done);
11070
11300
  } else {
11071
11301
  done();
11072
11302
  }
@@ -14201,11 +14431,11 @@ var init_lib = __esm({
14201
14431
  }
14202
14432
  }
14203
14433
  },
14204
- addToPath: function addToPath(path91, added, removed, oldPosInc, options) {
14205
- var last = path91.lastComponent;
14434
+ addToPath: function addToPath(path93, added, removed, oldPosInc, options) {
14435
+ var last = path93.lastComponent;
14206
14436
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
14207
14437
  return {
14208
- oldPos: path91.oldPos + oldPosInc,
14438
+ oldPos: path93.oldPos + oldPosInc,
14209
14439
  lastComponent: {
14210
14440
  count: last.count + 1,
14211
14441
  added,
@@ -14215,7 +14445,7 @@ var init_lib = __esm({
14215
14445
  };
14216
14446
  } else {
14217
14447
  return {
14218
- oldPos: path91.oldPos + oldPosInc,
14448
+ oldPos: path93.oldPos + oldPosInc,
14219
14449
  lastComponent: {
14220
14450
  count: 1,
14221
14451
  added,
@@ -14797,10 +15027,10 @@ function attachmentToHistoryMessage(o, ts) {
14797
15027
  const memories = raw.map((m2) => {
14798
15028
  if (!m2 || typeof m2 !== "object") return null;
14799
15029
  const rec4 = m2;
14800
- const path91 = typeof rec4.path === "string" ? rec4.path : null;
15030
+ const path93 = typeof rec4.path === "string" ? rec4.path : null;
14801
15031
  const content = typeof rec4.content === "string" ? rec4.content : null;
14802
- if (!path91 || content == null) return null;
14803
- const entry = { path: path91, content };
15032
+ if (!path93 || content == null) return null;
15033
+ const entry = { path: path93, content };
14804
15034
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
14805
15035
  return entry;
14806
15036
  }).filter((m2) => m2 !== null);
@@ -15666,10 +15896,10 @@ function parseAttachment(obj) {
15666
15896
  const memories = raw.map((m2) => {
15667
15897
  if (!m2 || typeof m2 !== "object") return null;
15668
15898
  const rec4 = m2;
15669
- const path91 = typeof rec4.path === "string" ? rec4.path : null;
15899
+ const path93 = typeof rec4.path === "string" ? rec4.path : null;
15670
15900
  const content = typeof rec4.content === "string" ? rec4.content : null;
15671
- if (!path91 || content == null) return null;
15672
- const out = { path: path91, content };
15901
+ if (!path93 || content == null) return null;
15902
+ const out = { path: path93, content };
15673
15903
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
15674
15904
  return out;
15675
15905
  }).filter((m2) => m2 !== null);
@@ -36643,8 +36873,8 @@ var require_utils = __commonJS({
36643
36873
  var result = transform[inputType][outputType](input);
36644
36874
  return result;
36645
36875
  };
36646
- exports2.resolve = function(path91) {
36647
- var parts = path91.split("/");
36876
+ exports2.resolve = function(path93) {
36877
+ var parts = path93.split("/");
36648
36878
  var result = [];
36649
36879
  for (var index = 0; index < parts.length; index++) {
36650
36880
  var part = parts[index];
@@ -42497,18 +42727,18 @@ var require_object = __commonJS({
42497
42727
  var object = new ZipObject(name, zipObjectContent, o);
42498
42728
  this.files[name] = object;
42499
42729
  };
42500
- var parentFolder = function(path91) {
42501
- if (path91.slice(-1) === "/") {
42502
- path91 = path91.substring(0, path91.length - 1);
42730
+ var parentFolder = function(path93) {
42731
+ if (path93.slice(-1) === "/") {
42732
+ path93 = path93.substring(0, path93.length - 1);
42503
42733
  }
42504
- var lastSlash = path91.lastIndexOf("/");
42505
- return lastSlash > 0 ? path91.substring(0, lastSlash) : "";
42734
+ var lastSlash = path93.lastIndexOf("/");
42735
+ return lastSlash > 0 ? path93.substring(0, lastSlash) : "";
42506
42736
  };
42507
- var forceTrailingSlash = function(path91) {
42508
- if (path91.slice(-1) !== "/") {
42509
- path91 += "/";
42737
+ var forceTrailingSlash = function(path93) {
42738
+ if (path93.slice(-1) !== "/") {
42739
+ path93 += "/";
42510
42740
  }
42511
- return path91;
42741
+ return path93;
42512
42742
  };
42513
42743
  var folderAdd = function(name, createFolders) {
42514
42744
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43510,7 +43740,7 @@ var require_lib3 = __commonJS({
43510
43740
  // src/run-case/recorder.ts
43511
43741
  function startRunCaseRecorder(opts) {
43512
43742
  const now = opts.now ?? Date.now;
43513
- const dir = import_node_path73.default.dirname(opts.recordPath);
43743
+ const dir = import_node_path75.default.dirname(opts.recordPath);
43514
43744
  let stream = null;
43515
43745
  let closing = false;
43516
43746
  let closedSettled = false;
@@ -43550,12 +43780,12 @@ function startRunCaseRecorder(opts) {
43550
43780
  };
43551
43781
  return { tap, close, closed };
43552
43782
  }
43553
- var import_node_fs54, import_node_path73;
43783
+ var import_node_fs54, import_node_path75;
43554
43784
  var init_recorder = __esm({
43555
43785
  "src/run-case/recorder.ts"() {
43556
43786
  "use strict";
43557
43787
  import_node_fs54 = __toESM(require("fs"), 1);
43558
- import_node_path73 = __toESM(require("path"), 1);
43788
+ import_node_path75 = __toESM(require("path"), 1);
43559
43789
  }
43560
43790
  });
43561
43791
 
@@ -43598,7 +43828,7 @@ var init_wire = __esm({
43598
43828
  // src/run-case/controller.ts
43599
43829
  async function runController(opts) {
43600
43830
  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-"));
43831
+ const cwd = opts.cwd ?? (0, import_node_fs55.mkdtempSync)(import_node_path76.default.join(import_node_os27.default.tmpdir(), "clawd-runcase-"));
43602
43832
  const ownsCwd = opts.cwd === void 0;
43603
43833
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
43604
43834
  const spawnCtx = { cwd };
@@ -43765,13 +43995,13 @@ async function runController(opts) {
43765
43995
  }
43766
43996
  return exitCode ?? 0;
43767
43997
  }
43768
- var import_node_fs55, import_node_os27, import_node_path74;
43998
+ var import_node_fs55, import_node_os27, import_node_path76;
43769
43999
  var init_controller = __esm({
43770
44000
  "src/run-case/controller.ts"() {
43771
44001
  "use strict";
43772
44002
  import_node_fs55 = require("fs");
43773
44003
  import_node_os27 = __toESM(require("os"), 1);
43774
- import_node_path74 = __toESM(require("path"), 1);
44004
+ import_node_path76 = __toESM(require("path"), 1);
43775
44005
  init_claude();
43776
44006
  init_stdout_splitter();
43777
44007
  init_permission_stdio();
@@ -44046,7 +44276,7 @@ Env (advanced):
44046
44276
  `;
44047
44277
 
44048
44278
  // src/index.ts
44049
- var import_node_path72 = __toESM(require("path"), 1);
44279
+ var import_node_path74 = __toESM(require("path"), 1);
44050
44280
  var import_node_fs53 = __toESM(require("fs"), 1);
44051
44281
  var import_node_os26 = __toESM(require("os"), 1);
44052
44282
  var import_node_crypto22 = require("crypto");
@@ -48427,6 +48657,7 @@ var SessionManager = class {
48427
48657
  // persona 绑定的 model / effort 快照进 SessionFile(spec 2026-08-12)
48428
48658
  ...personaDefaultFields(personaDefaults),
48429
48659
  ...args.sourceSessionId ? { shiftFiredFromSessionId: args.sourceSessionId } : {},
48660
+ ...args.deployId ? { deployId: args.deployId } : {},
48430
48661
  createdAt: now,
48431
48662
  updatedAt: now
48432
48663
  };
@@ -51189,8 +51420,8 @@ function turnStartInput(text) {
51189
51420
  const items = [];
51190
51421
  let leftover = text;
51191
51422
  for (const m2 of text.matchAll(SKILL_RE)) {
51192
- const [marker, name, path91] = m2;
51193
- items.push({ type: "skill", name, path: path91 });
51423
+ const [marker, name, path93] = m2;
51424
+ items.push({ type: "skill", name, path: path93 });
51194
51425
  leftover = leftover.replace(marker, "");
51195
51426
  }
51196
51427
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -54110,6 +54341,412 @@ function buildShiftInternalHandlers(deps) {
54110
54341
  };
54111
54342
  }
54112
54343
 
54344
+ // src/handlers/deploy.ts
54345
+ init_protocol();
54346
+
54347
+ // src/deploy/redact.ts
54348
+ var SECRET_KEY_HINT = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIAL|AKID|ACCESS_?ID)/i;
54349
+ var KNOWN_SECRET_SHAPES = [
54350
+ /LTAI[A-Za-z0-9]{6,}/,
54351
+ /eyJ[A-Za-z0-9_-]{10,}/,
54352
+ /sk-[A-Za-z0-9_-]{16,}/,
54353
+ /gh[pousr]_[A-Za-z0-9]{20,}/,
54354
+ /AKIA[A-Z0-9]{12,}/
54355
+ ];
54356
+ var BARE_SECRET = new RegExp(KNOWN_SECRET_SHAPES.map((re) => re.source).join("|"), "g");
54357
+ var REDACTED = "<\u5DF2\u7565\u53BB>";
54358
+ function isPlaceholder(value) {
54359
+ return value.length === 0 || value === REDACTED || /^\$\{?[A-Za-z_]/.test(value) || // ${VAR} / $VAR
54360
+ /^["']?[<(]/.test(value) || // <your-key> / (填这里)
54361
+ /^["']?(your|xxx+|todo|placeholder|change[-_]?me|填)/i.test(value);
54362
+ }
54363
+ var ASSIGNMENT = /((?:export\s+)?)(["']?)([A-Za-z_][A-Za-z0-9_.-]*)\2(\s*[:=]\s*)(["']?)([^\s"'`,;)\]}]+)/g;
54364
+ function redactSecretValues(text) {
54365
+ const byAssignment = text.replace(
54366
+ ASSIGNMENT,
54367
+ (whole, exp, kq, key, sep4, vq, value) => {
54368
+ if (isPlaceholder(value)) return whole;
54369
+ const looksSecret = SECRET_KEY_HINT.test(key) || KNOWN_SECRET_SHAPES.some((re) => re.test(value));
54370
+ return looksSecret ? `${exp}${kq}${key}${kq}${sep4}${vq}${REDACTED}` : whole;
54371
+ }
54372
+ );
54373
+ return byAssignment.replace(BARE_SECRET, REDACTED);
54374
+ }
54375
+ function redactEvidence(evidence) {
54376
+ return {
54377
+ ...evidence,
54378
+ reason: redactSecretValues(evidence.reason),
54379
+ quote: redactSecretValues(evidence.quote)
54380
+ };
54381
+ }
54382
+
54383
+ // src/handlers/deploy.ts
54384
+ function ensureOwner(ctx) {
54385
+ if (!ctx || ctx.principal.kind !== "owner") {
54386
+ throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: deploy:* requires owner ctx");
54387
+ }
54388
+ }
54389
+ function mustGet(deps, deployId) {
54390
+ const receipt = deps.receipts.get(deployId);
54391
+ if (!receipt) throw new ClawdError(ERROR_CODES.DEPLOY_NOT_FOUND, `DEPLOY_NOT_FOUND: \u6CA1\u6709\u8FD9\u5F20\u90E8\u7F72\u5355\uFF08${deployId}\uFF09`);
54392
+ return receipt;
54393
+ }
54394
+ function mustBeScanning(receipt, method) {
54395
+ if (receipt.status !== "scanning") {
54396
+ throw new ClawdError(
54397
+ ERROR_CODES.VALIDATION_ERROR,
54398
+ `VALIDATION_ERROR: ${method} \u53EA\u5728\u626B\u63CF\u671F\u53EF\u7528\uFF08\u5F53\u524D ${receipt.status}\uFF09`
54399
+ );
54400
+ }
54401
+ return receipt;
54402
+ }
54403
+ function secretStatusOf(deps, receipt) {
54404
+ const declared = receipt.manifest?.secrets ?? [];
54405
+ return declared.map((s) => ({
54406
+ name: s.name,
54407
+ // 只看部署级:使用者自带的那部分由使用者各自绑定,不在部署者这张单据的进度里
54408
+ filled: deps.secrets.filledKeys(receipt.deployId, s.name).length,
54409
+ total: s.env.length
54410
+ }));
54411
+ }
54412
+ function buildDeployHandlers(deps) {
54413
+ const view = (receipt) => ({
54414
+ response: { type: "deploy:receipt", receipt, secretStatus: secretStatusOf(deps, receipt) }
54415
+ });
54416
+ const start = async (frame, _client, ctx) => {
54417
+ ensureOwner(ctx);
54418
+ const args = parseArgs2(DeployStartArgsSchema, frame, "deploy:start");
54419
+ if (!deps.hasPersona(args.personaId)) {
54420
+ throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${args.personaId}\uFF09`);
54421
+ }
54422
+ const existing = deps.receipts.list().find((r) => r.personaId === args.personaId);
54423
+ if (existing) return view(existing);
54424
+ const receipt = deps.receipts.create({
54425
+ deployId: deps.genId(),
54426
+ personaId: args.personaId,
54427
+ status: "scanning"
54428
+ });
54429
+ const scanSessionId = deps.startScan(receipt.deployId, args.personaId);
54430
+ if (scanSessionId) deps.receipts.update(receipt.deployId, { scanSessionId });
54431
+ return view(deps.receipts.get(receipt.deployId) ?? receipt);
54432
+ };
54433
+ const rescan = async (frame, _client, ctx) => {
54434
+ ensureOwner(ctx);
54435
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:rescan");
54436
+ const receipt = mustGet(deps, args.deployId);
54437
+ if (receipt.status === "scanning") {
54438
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "VALIDATION_ERROR: \u8FD9\u5F20\u5355\u6B63\u5728\u626B\u63CF\u4E2D\uFF0C\u7B49\u5B83\u626B\u5B8C\u518D\u91CD\u626B");
54439
+ }
54440
+ deps.receipts.update(args.deployId, {
54441
+ status: "scanning",
54442
+ manifest: void 0,
54443
+ evidence: [],
54444
+ notes: [],
54445
+ smokeTask: void 0,
54446
+ error: void 0,
54447
+ scanSessionId: void 0
54448
+ });
54449
+ const scanSessionId = deps.startScan(args.deployId, receipt.personaId);
54450
+ if (scanSessionId) deps.receipts.update(args.deployId, { scanSessionId });
54451
+ return view(deps.receipts.get(args.deployId) ?? receipt);
54452
+ };
54453
+ const list = async (_frame, _client, ctx) => {
54454
+ ensureOwner(ctx);
54455
+ return { response: { type: "deploy:list", receipts: deps.receipts.list() } };
54456
+ };
54457
+ const get = async (frame, _client, ctx) => {
54458
+ ensureOwner(ctx);
54459
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:get");
54460
+ return view(mustGet(deps, args.deployId));
54461
+ };
54462
+ const patch = async (frame, _client, ctx) => {
54463
+ ensureOwner(ctx);
54464
+ const args = parseArgs2(DeployPatchArgsSchema, frame, "deploy:patch");
54465
+ const receipt = mustGet(deps, args.deployId);
54466
+ if (args.patch.fulfillment) {
54467
+ const declared = new Set((args.patch.manifest ?? receipt.manifest)?.secrets.map((s) => s.name) ?? []);
54468
+ for (const name of Object.keys(args.patch.fulfillment)) {
54469
+ if (!declared.has(name)) {
54470
+ throw new ClawdError(
54471
+ ERROR_CODES.VALIDATION_ERROR,
54472
+ `VALIDATION_ERROR: \u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${name}\u300D\u7684\u51ED\u636E`
54473
+ );
54474
+ }
54475
+ }
54476
+ }
54477
+ const next = deps.receipts.update(args.deployId, args.patch);
54478
+ return view(next ?? receipt);
54479
+ };
54480
+ const putSecret = async (frame, _client, ctx) => {
54481
+ ensureOwner(ctx);
54482
+ const args = parseArgs2(DeployPutSecretArgsSchema, frame, "deploy:putSecret");
54483
+ const receipt = mustGet(deps, args.deployId);
54484
+ const declared = receipt.manifest?.secrets.find((s) => s.name === args.name);
54485
+ if (!declared) {
54486
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_ERROR: \u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u51ED\u636E`);
54487
+ }
54488
+ const allowed = new Set(declared.env);
54489
+ for (const key of Object.keys(args.values)) {
54490
+ if (!allowed.has(key)) {
54491
+ throw new ClawdError(
54492
+ ERROR_CODES.VALIDATION_ERROR,
54493
+ `VALIDATION_ERROR: \u300C${args.name}\u300D\u6CA1\u6709\u58F0\u660E\u73AF\u5883\u53D8\u91CF ${key}`
54494
+ );
54495
+ }
54496
+ }
54497
+ deps.secrets.put({ deployId: args.deployId, name: args.name, values: args.values });
54498
+ return view(receipt);
54499
+ };
54500
+ const reportFinding = async (frame, _client, ctx) => {
54501
+ ensureOwner(ctx);
54502
+ const args = parseArgs2(DeployReportFindingArgsSchema, frame, "deploy:reportFinding");
54503
+ const receipt = mustBeScanning(mustGet(deps, args.deployId), "deploy:reportFinding");
54504
+ const schema = args.kind === "cli" ? EnvCliSchema : args.kind === "secret" ? EnvSecretSchema : EnvAssetSchema;
54505
+ const parsed = schema.safeParse(args.item);
54506
+ if (!parsed.success) {
54507
+ const first = parsed.error.issues[0];
54508
+ throw new ClawdError(
54509
+ ERROR_CODES.VALIDATION_ERROR,
54510
+ `VALIDATION_ERROR: ${args.kind} \u6761\u76EE\u4E0D\u5408\u6CD5\uFF1A${first ? `${first.path.join(".")} ${first.message}` : ""}`
54511
+ );
54512
+ }
54513
+ const item = parsed.data;
54514
+ const base = receipt.manifest ?? { version: 1, clis: [], secrets: [], assets: [] };
54515
+ const key = args.kind === "cli" ? "clis" : args.kind === "secret" ? "secrets" : "assets";
54516
+ const list2 = [...base[key]];
54517
+ const idx = list2.findIndex((x) => x.name === item.name);
54518
+ if (idx === -1) list2.push(item);
54519
+ else list2[idx] = item;
54520
+ const target = `${args.kind}:${item.name}`;
54521
+ const evidence = [
54522
+ ...(receipt.evidence ?? []).filter((e) => e.target !== target),
54523
+ redactEvidence({ target, ...args.evidence })
54524
+ ];
54525
+ const next = deps.receipts.update(args.deployId, {
54526
+ manifest: { ...base, [key]: list2 },
54527
+ evidence
54528
+ });
54529
+ return view(next ?? receipt);
54530
+ };
54531
+ const finishScan = async (frame, _client, ctx) => {
54532
+ ensureOwner(ctx);
54533
+ const args = parseArgs2(DeployFinishScanArgsSchema, frame, "deploy:finishScan");
54534
+ mustBeScanning(mustGet(deps, args.deployId), "deploy:finishScan");
54535
+ const next = deps.receipts.update(args.deployId, {
54536
+ status: "draft",
54537
+ smokeTask: args.smokeTask ? redactSecretValues(args.smokeTask) : args.smokeTask,
54538
+ notes: args.notes?.map(redactSecretValues),
54539
+ error: void 0
54540
+ });
54541
+ return view(next);
54542
+ };
54543
+ const remove = async (frame, _client, ctx) => {
54544
+ ensureOwner(ctx);
54545
+ const args = parseArgs2(DeployIdArgsSchema, frame, "deploy:remove");
54546
+ mustGet(deps, args.deployId);
54547
+ deps.receipts.remove(args.deployId);
54548
+ deps.secrets.removeDeploy(args.deployId);
54549
+ return { response: { type: "deploy:remove", deployId: args.deployId } };
54550
+ };
54551
+ return {
54552
+ "deploy:start": start,
54553
+ "deploy:rescan": rescan,
54554
+ "deploy:list": list,
54555
+ "deploy:get": get,
54556
+ "deploy:patch": patch,
54557
+ "deploy:putSecret": putSecret,
54558
+ "deploy:reportFinding": reportFinding,
54559
+ "deploy:finishScan": finishScan,
54560
+ "deploy:remove": remove
54561
+ };
54562
+ }
54563
+
54564
+ // src/deploy/receipt-store.ts
54565
+ var import_promises4 = __toESM(require("fs/promises"), 1);
54566
+ var import_node_path28 = __toESM(require("path"), 1);
54567
+ init_protocol();
54568
+ function createReceiptStore(deps) {
54569
+ let receipts = [];
54570
+ let flushTimer = null;
54571
+ async function load() {
54572
+ let raw;
54573
+ try {
54574
+ raw = await import_promises4.default.readFile(deps.filePath, "utf8");
54575
+ } catch (err) {
54576
+ if (err.code === "ENOENT") {
54577
+ receipts = [];
54578
+ return;
54579
+ }
54580
+ throw err;
54581
+ }
54582
+ const parsed = JSON.parse(raw);
54583
+ if (parsed.version !== 1) throw new Error(`deploy.json: unsupported version ${parsed.version}`);
54584
+ receipts = (parsed.receipts ?? []).map((r) => DeployReceiptSchema.parse(r));
54585
+ }
54586
+ async function flushNow() {
54587
+ if (flushTimer) {
54588
+ clearTimeout(flushTimer);
54589
+ flushTimer = null;
54590
+ }
54591
+ const content = { version: 1, receipts };
54592
+ await import_promises4.default.mkdir(import_node_path28.default.dirname(deps.filePath), { recursive: true });
54593
+ const tmp = `${deps.filePath}.tmp-${process.pid}-${deps.now()}`;
54594
+ await import_promises4.default.writeFile(tmp, JSON.stringify(content, null, 2), { encoding: "utf8", mode: 384 });
54595
+ await import_promises4.default.rename(tmp, deps.filePath);
54596
+ }
54597
+ function scheduleFlush() {
54598
+ if (flushTimer) return;
54599
+ flushTimer = setTimeout(() => {
54600
+ flushTimer = null;
54601
+ flushNow().catch((err) => deps.onFlushError?.(err));
54602
+ }, STORE_FLUSH_DEBOUNCE_MS);
54603
+ }
54604
+ return {
54605
+ load,
54606
+ flushNow,
54607
+ create(input) {
54608
+ const ts = deps.now();
54609
+ const receipt = {
54610
+ deployId: input.deployId,
54611
+ personaId: input.personaId,
54612
+ status: input.status,
54613
+ notes: [],
54614
+ fulfillment: {},
54615
+ gaps: [],
54616
+ createdAt: ts,
54617
+ updatedAt: ts
54618
+ };
54619
+ receipts.push(receipt);
54620
+ scheduleFlush();
54621
+ return receipt;
54622
+ },
54623
+ update(deployId, patch) {
54624
+ const idx = receipts.findIndex((r) => r.deployId === deployId);
54625
+ if (idx === -1) return void 0;
54626
+ const next = DeployReceiptSchema.parse({ ...receipts[idx], ...patch, updatedAt: deps.now() });
54627
+ receipts[idx] = next;
54628
+ scheduleFlush();
54629
+ return next;
54630
+ },
54631
+ get(deployId) {
54632
+ return receipts.find((r) => r.deployId === deployId);
54633
+ },
54634
+ list() {
54635
+ return [...receipts].sort((a, b2) => b2.createdAt - a.createdAt);
54636
+ },
54637
+ remove(deployId) {
54638
+ const idx = receipts.findIndex((r) => r.deployId === deployId);
54639
+ if (idx === -1) return false;
54640
+ receipts.splice(idx, 1);
54641
+ scheduleFlush();
54642
+ return true;
54643
+ }
54644
+ };
54645
+ }
54646
+
54647
+ // src/deploy/secret-store.ts
54648
+ var import_promises5 = __toESM(require("fs/promises"), 1);
54649
+ var import_node_path29 = __toESM(require("path"), 1);
54650
+ function createSecretStore(deps) {
54651
+ let entries = [];
54652
+ let flushTimer = null;
54653
+ const sameScope = (e, deployId, name, userId) => e.deployId === deployId && e.name === name && (e.userId ?? void 0) === (userId ?? void 0);
54654
+ async function load() {
54655
+ let raw;
54656
+ try {
54657
+ raw = await import_promises5.default.readFile(deps.filePath, "utf8");
54658
+ } catch (err) {
54659
+ if (err.code === "ENOENT") {
54660
+ entries = [];
54661
+ return;
54662
+ }
54663
+ throw err;
54664
+ }
54665
+ const parsed = JSON.parse(raw);
54666
+ if (parsed.version !== 1) throw new Error(`deploy-secrets.json: unsupported version ${parsed.version}`);
54667
+ entries = parsed.entries ?? [];
54668
+ }
54669
+ async function flushNow() {
54670
+ if (flushTimer) {
54671
+ clearTimeout(flushTimer);
54672
+ flushTimer = null;
54673
+ }
54674
+ const content = { version: 1, entries };
54675
+ await import_promises5.default.mkdir(import_node_path29.default.dirname(deps.filePath), { recursive: true });
54676
+ const tmp = `${deps.filePath}.tmp-${process.pid}-${deps.now()}`;
54677
+ await import_promises5.default.writeFile(tmp, JSON.stringify(content, null, 2), { encoding: "utf8", mode: 384 });
54678
+ await import_promises5.default.rename(tmp, deps.filePath);
54679
+ }
54680
+ function scheduleFlush() {
54681
+ if (flushTimer) return;
54682
+ flushTimer = setTimeout(() => {
54683
+ flushTimer = null;
54684
+ flushNow().catch((err) => deps.onFlushError?.(err));
54685
+ }, STORE_FLUSH_DEBOUNCE_MS);
54686
+ }
54687
+ return {
54688
+ load,
54689
+ flushNow,
54690
+ put(entry) {
54691
+ const idx = entries.findIndex((e) => sameScope(e, entry.deployId, entry.name, entry.userId));
54692
+ if (idx === -1) {
54693
+ entries.push({ ...entry, updatedAt: deps.now() });
54694
+ } else {
54695
+ entries[idx] = {
54696
+ ...entries[idx],
54697
+ values: { ...entries[idx].values, ...entry.values },
54698
+ updatedAt: deps.now()
54699
+ };
54700
+ }
54701
+ scheduleFlush();
54702
+ },
54703
+ resolve(deployId, userId) {
54704
+ const out = {};
54705
+ for (const e of entries) {
54706
+ if (e.deployId !== deployId || e.userId !== void 0) continue;
54707
+ Object.assign(out, e.values);
54708
+ }
54709
+ if (userId !== void 0) {
54710
+ for (const e of entries) {
54711
+ if (e.deployId !== deployId || e.userId !== userId) continue;
54712
+ Object.assign(out, e.values);
54713
+ }
54714
+ }
54715
+ return out;
54716
+ },
54717
+ filledKeys(deployId, name, userId) {
54718
+ const e = entries.find((x) => sameScope(x, deployId, name, userId));
54719
+ if (!e) return [];
54720
+ return Object.keys(e.values).filter((k2) => e.values[k2].length > 0);
54721
+ },
54722
+ removeDeploy(deployId) {
54723
+ const before = entries.length;
54724
+ entries = entries.filter((e) => e.deployId !== deployId);
54725
+ const removed = before - entries.length;
54726
+ if (removed > 0) scheduleFlush();
54727
+ return removed;
54728
+ }
54729
+ };
54730
+ }
54731
+
54732
+ // src/deploy/scan-task.ts
54733
+ var BUTLER_PERSONA_ID = "persona-clawd-butler";
54734
+ var SCANNABLE_ASSETS = ["deploy-kit"];
54735
+ function settleEndedScan(outcome, current) {
54736
+ if (current?.status !== "scanning") return void 0;
54737
+ return {
54738
+ status: "scanFailed",
54739
+ error: "error" in outcome ? outcome.error : "butler \u4F1A\u8BDD\u7ED3\u675F\u4E86\u4F46\u6CA1\u6709\u8C03 finishScan"
54740
+ };
54741
+ }
54742
+ function reconcileInterruptedScans(deps) {
54743
+ const stale = deps.list().filter((r) => r.status === "scanning");
54744
+ for (const r of stale) {
54745
+ 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" });
54746
+ }
54747
+ return stale.map((r) => r.deployId);
54748
+ }
54749
+
54113
54750
  // src/handlers/lark-bot.ts
54114
54751
  init_protocol();
54115
54752
  var PROVISION_ERROR_SET = new Set(LARK_BOT_PROVISION_ERROR_REASONS);
@@ -54498,9 +55135,9 @@ async function refreshTunnelUrlOnStartup(deps) {
54498
55135
 
54499
55136
  // src/lark-bot-connector/binding-store.ts
54500
55137
  var import_node_fs26 = __toESM(require("fs"), 1);
54501
- var import_node_path28 = __toESM(require("path"), 1);
55138
+ var import_node_path30 = __toESM(require("path"), 1);
54502
55139
  function createLarkBotBindingStore(personaRoot) {
54503
- const filePath = (personaId2) => import_node_path28.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
55140
+ const filePath = (personaId2) => import_node_path30.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
54504
55141
  const read = (personaId2) => {
54505
55142
  const file = filePath(personaId2);
54506
55143
  if (!import_node_fs26.default.existsSync(file)) return null;
@@ -54514,7 +55151,7 @@ function createLarkBotBindingStore(personaRoot) {
54514
55151
  };
54515
55152
  const write = (personaId2, meta) => {
54516
55153
  const file = filePath(personaId2);
54517
- import_node_fs26.default.mkdirSync(import_node_path28.default.dirname(file), { recursive: true });
55154
+ import_node_fs26.default.mkdirSync(import_node_path30.default.dirname(file), { recursive: true });
54518
55155
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
54519
55156
  import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
54520
55157
  import_node_fs26.default.renameSync(tmp, file);
@@ -54682,7 +55319,7 @@ function createLarkBotCloudClient(opts) {
54682
55319
 
54683
55320
  // src/lark-bot-connector/chat-router.ts
54684
55321
  var import_node_fs27 = __toESM(require("fs"), 1);
54685
- var import_node_path29 = __toESM(require("path"), 1);
55322
+ var import_node_path31 = __toESM(require("path"), 1);
54686
55323
  init_protocol();
54687
55324
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
54688
55325
  var LOCAL_TURN_RETRIES = 2;
@@ -54749,7 +55386,7 @@ function createLarkChatRouter(deps) {
54749
55386
  }
54750
55387
  const dir = deps.mediaRootFor(env.chatId);
54751
55388
  import_node_fs27.default.mkdirSync(dir, { recursive: true });
54752
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
55389
+ const p2 = import_node_path31.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
54753
55390
  import_node_fs27.default.writeFileSync(p2, r.data);
54754
55391
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
54755
55392
  } catch (err) {
@@ -54772,7 +55409,7 @@ function createLarkChatRouter(deps) {
54772
55409
  }
54773
55410
  const dir = deps.mediaRootFor(env.chatId);
54774
55411
  import_node_fs27.default.mkdirSync(dir, { recursive: true });
54775
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
55412
+ const p2 = import_node_path31.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
54776
55413
  import_node_fs27.default.writeFileSync(p2, r.data);
54777
55414
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
54778
55415
  } catch (err) {
@@ -55862,7 +56499,7 @@ var CodexHistoryReader = class {
55862
56499
  };
55863
56500
 
55864
56501
  // src/tools/codex-skills.ts
55865
- var import_node_path30 = __toESM(require("path"), 1);
56502
+ var import_node_path32 = __toESM(require("path"), 1);
55866
56503
  function str3(v2) {
55867
56504
  return typeof v2 === "string" ? v2 : void 0;
55868
56505
  }
@@ -55877,13 +56514,13 @@ function mapSkillsListResponse(res) {
55877
56514
  const r = s ?? {};
55878
56515
  const name = str3(r.name);
55879
56516
  if (!name) continue;
55880
- const path91 = str3(r.path);
56517
+ const path93 = str3(r.path);
55881
56518
  const description = str3(r.description);
55882
56519
  const isPlugin = name.includes(":");
55883
56520
  out.push({
55884
56521
  name,
55885
56522
  source: isPlugin ? "plugin" : "project",
55886
- ...path91 ? { path: path91 } : {},
56523
+ ...path93 ? { path: path93 } : {},
55887
56524
  ...description ? { description } : {},
55888
56525
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
55889
56526
  });
@@ -55899,14 +56536,14 @@ async function listCodexSkills(cwd, deps = {}) {
55899
56536
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
55900
56537
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
55901
56538
  beforeRequest: (client) => {
55902
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path30.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
56539
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path32.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
55903
56540
  }
55904
56541
  });
55905
56542
  return mapSkillsListResponse(res);
55906
56543
  }
55907
56544
 
55908
56545
  // src/tools/codex-turn-context.ts
55909
- var import_promises4 = __toESM(require("fs/promises"), 1);
56546
+ var import_promises6 = __toESM(require("fs/promises"), 1);
55910
56547
  function parseTurnContextFromRollout(raw) {
55911
56548
  const lines = raw.split("\n");
55912
56549
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -55941,7 +56578,7 @@ async function readCodexTurnContext(args, deps = {}) {
55941
56578
  );
55942
56579
  const rolloutPath = str4(rec3(res?.thread)?.path);
55943
56580
  if (!rolloutPath) return null;
55944
- return parseTurnContextFromRollout(await import_promises4.default.readFile(rolloutPath, "utf8"));
56581
+ return parseTurnContextFromRollout(await import_promises6.default.readFile(rolloutPath, "utf8"));
55945
56582
  }
55946
56583
  function createCodexResolvedMetaHydrator(deps) {
55947
56584
  const fetchedThreadIds = /* @__PURE__ */ new Set();
@@ -55986,14 +56623,14 @@ function str4(v2) {
55986
56623
  // src/workspace/browser.ts
55987
56624
  var import_node_fs28 = __toESM(require("fs"), 1);
55988
56625
  var import_node_os8 = __toESM(require("os"), 1);
55989
- var import_node_path31 = __toESM(require("path"), 1);
56626
+ var import_node_path33 = __toESM(require("path"), 1);
55990
56627
  init_protocol();
55991
56628
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
55992
56629
  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)) {
56630
+ const absCwd = import_node_path33.default.resolve(cwd);
56631
+ const joined = import_node_path33.default.resolve(absCwd, subpath ?? ".");
56632
+ const rel = import_node_path33.default.relative(absCwd, joined);
56633
+ if (rel.startsWith("..") || import_node_path33.default.isAbsolute(rel)) {
55997
56634
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
55998
56635
  }
55999
56636
  return joined;
@@ -56024,7 +56661,7 @@ var WorkspaceBrowser = class {
56024
56661
  mtime: ""
56025
56662
  };
56026
56663
  try {
56027
- const st = import_node_fs28.default.statSync(import_node_path31.default.join(full, d.name));
56664
+ const st = import_node_fs28.default.statSync(import_node_path33.default.join(full, d.name));
56028
56665
  entry.mtime = new Date(st.mtimeMs).toISOString();
56029
56666
  if (d.isFile()) entry.size = st.size;
56030
56667
  } catch {
@@ -56071,7 +56708,7 @@ var WorkspaceBrowser = class {
56071
56708
  // src/skills/agents-scanner.ts
56072
56709
  var import_node_fs29 = __toESM(require("fs"), 1);
56073
56710
  var import_node_os9 = __toESM(require("os"), 1);
56074
- var import_node_path32 = __toESM(require("path"), 1);
56711
+ var import_node_path34 = __toESM(require("path"), 1);
56075
56712
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
56076
56713
  function isDirLikeSync2(p2) {
56077
56714
  try {
@@ -56109,10 +56746,10 @@ function scanAgentsDir(dir, source, seen, out) {
56109
56746
  }
56110
56747
  for (const ent of entries) {
56111
56748
  if (!ent.name.endsWith(".md")) continue;
56112
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path32.default.join(dir, ent.name)))) {
56749
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path34.default.join(dir, ent.name)))) {
56113
56750
  continue;
56114
56751
  }
56115
- const filePath = import_node_path32.default.join(dir, ent.name);
56752
+ const filePath = import_node_path34.default.join(dir, ent.name);
56116
56753
  const baseName = ent.name.replace(/\.md$/, "");
56117
56754
  if (seen.has(baseName)) continue;
56118
56755
  seen.add(baseName);
@@ -56135,7 +56772,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
56135
56772
  return;
56136
56773
  }
56137
56774
  for (const ent of entries) {
56138
- const childPath = import_node_path32.default.join(dir, ent.name);
56775
+ const childPath = import_node_path34.default.join(dir, ent.name);
56139
56776
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
56140
56777
  walk2(childPath, [...namespaces, ent.name]);
56141
56778
  continue;
@@ -56160,9 +56797,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
56160
56797
  walk2(root, []);
56161
56798
  }
56162
56799
  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");
56800
+ const pluginsDir = import_node_path34.default.join(home, ".claude", "plugins");
56801
+ const v2 = import_node_path34.default.join(pluginsDir, "installed_plugins_v2.json");
56802
+ const v1 = import_node_path34.default.join(pluginsDir, "installed_plugins.json");
56166
56803
  let raw = null;
56167
56804
  for (const candidate of [v2, v1]) {
56168
56805
  try {
@@ -56191,19 +56828,19 @@ function readInstalledPlugins2(home) {
56191
56828
  return out;
56192
56829
  }
56193
56830
  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;
56831
+ let cur = import_node_path34.default.resolve(startCwd);
56832
+ const fsRoot = import_node_path34.default.parse(cur).root;
56196
56833
  while (true) {
56197
- scanAgentsDir(import_node_path32.default.join(cur, ".claude", "agents"), "project", seen, out);
56834
+ scanAgentsDir(import_node_path34.default.join(cur, ".claude", "agents"), "project", seen, out);
56198
56835
  let hasGit = false;
56199
56836
  try {
56200
- hasGit = import_node_fs29.default.existsSync(import_node_path32.default.join(cur, ".git"));
56837
+ hasGit = import_node_fs29.default.existsSync(import_node_path34.default.join(cur, ".git"));
56201
56838
  } catch {
56202
56839
  }
56203
56840
  if (hasGit) return;
56204
56841
  if (cur === home) return;
56205
56842
  if (cur === fsRoot) return;
56206
- const parent = import_node_path32.default.dirname(cur);
56843
+ const parent = import_node_path34.default.dirname(cur);
56207
56844
  if (parent === cur) return;
56208
56845
  cur = parent;
56209
56846
  }
@@ -56238,7 +56875,7 @@ var AgentsScanner = class {
56238
56875
  }
56239
56876
  const fsBlock = [];
56240
56877
  scanAgentsDir(
56241
- import_node_path32.default.join(this.home, ".claude", "agents"),
56878
+ import_node_path34.default.join(this.home, ".claude", "agents"),
56242
56879
  "global",
56243
56880
  seen,
56244
56881
  fsBlock
@@ -56252,7 +56889,7 @@ var AgentsScanner = class {
56252
56889
  ...this.extraPluginRoots
56253
56890
  ];
56254
56891
  for (const { name, root } of plugins) {
56255
- const agentsRoot = import_node_path32.default.join(root, "agents");
56892
+ const agentsRoot = import_node_path34.default.join(root, "agents");
56256
56893
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
56257
56894
  }
56258
56895
  return [...builtinBlock, ...fsBlock];
@@ -56262,13 +56899,13 @@ var AgentsScanner = class {
56262
56899
  // src/observer/session-observer.ts
56263
56900
  var import_node_fs31 = __toESM(require("fs"), 1);
56264
56901
  var import_node_os11 = __toESM(require("os"), 1);
56265
- var import_node_path34 = __toESM(require("path"), 1);
56902
+ var import_node_path36 = __toESM(require("path"), 1);
56266
56903
  init_claude_history();
56267
56904
 
56268
56905
  // src/observer/subagent-meta-observer.ts
56269
56906
  var import_node_fs30 = __toESM(require("fs"), 1);
56270
56907
  var import_node_os10 = __toESM(require("os"), 1);
56271
- var import_node_path33 = __toESM(require("path"), 1);
56908
+ var import_node_path35 = __toESM(require("path"), 1);
56272
56909
  init_claude_history();
56273
56910
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
56274
56911
  var SubagentMetaObserver = class {
@@ -56281,7 +56918,7 @@ var SubagentMetaObserver = class {
56281
56918
  watches = /* @__PURE__ */ new Map();
56282
56919
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
56283
56920
  resolveSubagentDir(cwd, toolSessionId) {
56284
- return import_node_path33.default.join(
56921
+ return import_node_path35.default.join(
56285
56922
  this.home,
56286
56923
  ".claude",
56287
56924
  "projects",
@@ -56337,7 +56974,7 @@ var SubagentMetaObserver = class {
56337
56974
  if (!m2) return;
56338
56975
  const agentId = m2[1];
56339
56976
  if (w2.emitted.has(agentId)) return;
56340
- const file = import_node_path33.default.join(w2.dirPath, name);
56977
+ const file = import_node_path35.default.join(w2.dirPath, name);
56341
56978
  let raw;
56342
56979
  try {
56343
56980
  raw = import_node_fs30.default.readFileSync(file, "utf8");
@@ -56397,7 +57034,7 @@ var SessionObserver = class {
56397
57034
  metaObserver;
56398
57035
  resolveJsonlPath(cwd, toolSessionId, override) {
56399
57036
  if (override) return override;
56400
- return import_node_path34.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
57037
+ return import_node_path36.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
56401
57038
  }
56402
57039
  start(args) {
56403
57040
  this.stop(args.sessionId);
@@ -56423,10 +57060,10 @@ var SessionObserver = class {
56423
57060
  lastDeriveMs: 0
56424
57061
  };
56425
57062
  try {
56426
- import_node_fs31.default.mkdirSync(import_node_path34.default.dirname(filePath), { recursive: true });
57063
+ import_node_fs31.default.mkdirSync(import_node_path36.default.dirname(filePath), { recursive: true });
56427
57064
  } catch {
56428
57065
  }
56429
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
57066
+ w2.watcher = import_node_fs31.default.watch(import_node_path36.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
56430
57067
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
56431
57068
  this.poll(w2);
56432
57069
  });
@@ -56523,7 +57160,7 @@ var SessionObserver = class {
56523
57160
  const now = Date.now();
56524
57161
  if (now - w2.lastRelocateScanMs < 1e3) return;
56525
57162
  w2.lastRelocateScanMs = now;
56526
- const projectsRoot = import_node_path34.default.join(this.home, ".claude", "projects");
57163
+ const projectsRoot = import_node_path36.default.join(this.home, ".claude", "projects");
56527
57164
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
56528
57165
  if (!found || found === w2.filePath) return;
56529
57166
  try {
@@ -56532,7 +57169,7 @@ var SessionObserver = class {
56532
57169
  }
56533
57170
  w2.filePath = found;
56534
57171
  try {
56535
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(found), { persistent: false }, (_event, changedName) => {
57172
+ w2.watcher = import_node_fs31.default.watch(import_node_path36.default.dirname(found), { persistent: false }, (_event, changedName) => {
56536
57173
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
56537
57174
  this.poll(w2);
56538
57175
  });
@@ -56655,7 +57292,7 @@ function listRegistered() {
56655
57292
  var import_node_child_process8 = require("child_process");
56656
57293
  var import_node_fs32 = __toESM(require("fs"), 1);
56657
57294
  var import_node_os12 = __toESM(require("os"), 1);
56658
- var import_node_path35 = __toESM(require("path"), 1);
57295
+ var import_node_path37 = __toESM(require("path"), 1);
56659
57296
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
56660
57297
  var TITLE_MODEL_BY_TOOL = {
56661
57298
  claude: "haiku",
@@ -56726,7 +57363,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
56726
57363
  if (!text) return null;
56727
57364
  let workDir;
56728
57365
  try {
56729
- workDir = import_node_fs32.default.mkdtempSync(import_node_path35.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
57366
+ workDir = import_node_fs32.default.mkdtempSync(import_node_path37.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
56730
57367
  } catch {
56731
57368
  return null;
56732
57369
  }
@@ -56736,8 +57373,8 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
56736
57373
  } catch {
56737
57374
  }
56738
57375
  };
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");
57376
+ const outFile = import_node_path37.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
57377
+ const schemaFile = import_node_path37.default.join(workDir, "title-schema.json");
56741
57378
  if (tool === "codex") {
56742
57379
  try {
56743
57380
  import_node_fs32.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
@@ -57491,8 +58128,8 @@ async function authenticate(token, deps) {
57491
58128
  }
57492
58129
 
57493
58130
  // src/legacy-cleanup.ts
57494
- var fs41 = __toESM(require("fs/promises"), 1);
57495
- var path43 = __toESM(require("path"), 1);
58131
+ var fs43 = __toESM(require("fs/promises"), 1);
58132
+ var path45 = __toESM(require("path"), 1);
57496
58133
  var LEGACY_FILES = [
57497
58134
  "personal-capability.json",
57498
58135
  "received-capabilities.json",
@@ -57501,9 +58138,9 @@ var LEGACY_FILES = [
57501
58138
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
57502
58139
  const removed = [];
57503
58140
  for (const name of LEGACY_FILES) {
57504
- const p2 = path43.join(dataDir, name);
58141
+ const p2 = path45.join(dataDir, name);
57505
58142
  try {
57506
- await fs41.unlink(p2);
58143
+ await fs43.unlink(p2);
57507
58144
  removed.push(name);
57508
58145
  logger.debug("legacy capability file removed", { file: name });
57509
58146
  } catch (err) {
@@ -57515,13 +58152,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
57515
58152
  }
57516
58153
 
57517
58154
  // src/inbox/inbox-store.ts
57518
- var fs42 = __toESM(require("fs"), 1);
57519
- var path44 = __toESM(require("path"), 1);
58155
+ var fs44 = __toESM(require("fs"), 1);
58156
+ var path46 = __toESM(require("path"), 1);
57520
58157
  var INBOX_SUBDIR = "inbox";
57521
58158
  var InboxStore = class {
57522
58159
  constructor(dataDir) {
57523
58160
  this.dataDir = dataDir;
57524
- fs42.mkdirSync(this.dirPath(), { recursive: true });
58161
+ fs44.mkdirSync(this.dirPath(), { recursive: true });
57525
58162
  }
57526
58163
  dataDir;
57527
58164
  /**
@@ -57533,7 +58170,7 @@ var InboxStore = class {
57533
58170
  const file = this.filePath(peerDeviceId);
57534
58171
  let raw;
57535
58172
  try {
57536
- raw = fs42.readFileSync(file, "utf8");
58173
+ raw = fs44.readFileSync(file, "utf8");
57537
58174
  } catch (err) {
57538
58175
  if (err?.code === "ENOENT") return [];
57539
58176
  return [];
@@ -57549,7 +58186,7 @@ var InboxStore = class {
57549
58186
  const dir = this.dirPath();
57550
58187
  let entries;
57551
58188
  try {
57552
- entries = fs42.readdirSync(dir);
58189
+ entries = fs44.readdirSync(dir);
57553
58190
  } catch (err) {
57554
58191
  if (err?.code === "ENOENT") return [];
57555
58192
  return [];
@@ -57565,9 +58202,9 @@ var InboxStore = class {
57565
58202
  if (existing.some((m2) => m2.id === message.id)) return;
57566
58203
  const file = this.filePath(message.peerDeviceId);
57567
58204
  const line = JSON.stringify(message) + "\n";
57568
- fs42.appendFileSync(file, line, { mode: 384 });
58205
+ fs44.appendFileSync(file, line, { mode: 384 });
57569
58206
  try {
57570
- fs42.chmodSync(file, 384);
58207
+ fs44.chmodSync(file, 384);
57571
58208
  } catch {
57572
58209
  }
57573
58210
  }
@@ -57597,7 +58234,7 @@ var InboxStore = class {
57597
58234
  removeByPeerDeviceId(peerDeviceId) {
57598
58235
  const file = this.filePath(peerDeviceId);
57599
58236
  try {
57600
- fs42.unlinkSync(file);
58237
+ fs44.unlinkSync(file);
57601
58238
  } catch (err) {
57602
58239
  if (err?.code === "ENOENT") return;
57603
58240
  }
@@ -57606,18 +58243,18 @@ var InboxStore = class {
57606
58243
  const file = this.filePath(peerDeviceId);
57607
58244
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
57608
58245
  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);
58246
+ fs44.writeFileSync(tmp, content, { mode: 384 });
58247
+ fs44.renameSync(tmp, file);
57611
58248
  try {
57612
- fs42.chmodSync(file, 384);
58249
+ fs44.chmodSync(file, 384);
57613
58250
  } catch {
57614
58251
  }
57615
58252
  }
57616
58253
  dirPath() {
57617
- return path44.join(this.dataDir, INBOX_SUBDIR);
58254
+ return path46.join(this.dataDir, INBOX_SUBDIR);
57618
58255
  }
57619
58256
  filePath(peerDeviceId) {
57620
- return path44.join(this.dirPath(), `${peerDeviceId}.jsonl`);
58257
+ return path46.join(this.dirPath(), `${peerDeviceId}.jsonl`);
57621
58258
  }
57622
58259
  };
57623
58260
  function parseAllLines(raw) {
@@ -57705,8 +58342,8 @@ var InboxManager = class {
57705
58342
  };
57706
58343
 
57707
58344
  // src/state/contact-store.ts
57708
- var fs43 = __toESM(require("fs"), 1);
57709
- var path45 = __toESM(require("path"), 1);
58345
+ var fs45 = __toESM(require("fs"), 1);
58346
+ var path47 = __toESM(require("path"), 1);
57710
58347
  var FILE_NAME = "contacts.json";
57711
58348
  var ContactStore = class {
57712
58349
  constructor(dataDir) {
@@ -57716,10 +58353,10 @@ var ContactStore = class {
57716
58353
  contacts = /* @__PURE__ */ new Map();
57717
58354
  load() {
57718
58355
  this.contacts.clear();
57719
- const file = path45.join(this.dataDir, FILE_NAME);
58356
+ const file = path47.join(this.dataDir, FILE_NAME);
57720
58357
  let raw;
57721
58358
  try {
57722
- raw = fs43.readFileSync(file, "utf8");
58359
+ raw = fs45.readFileSync(file, "utf8");
57723
58360
  } catch (err) {
57724
58361
  if (err?.code !== "ENOENT") this.renameBak(file);
57725
58362
  return;
@@ -57800,20 +58437,20 @@ var ContactStore = class {
57800
58437
  return true;
57801
58438
  }
57802
58439
  flush() {
57803
- const file = path45.join(this.dataDir, FILE_NAME);
58440
+ const file = path47.join(this.dataDir, FILE_NAME);
57804
58441
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
57805
58442
  const content = JSON.stringify(
57806
58443
  { contacts: Array.from(this.contacts.values()) },
57807
58444
  null,
57808
58445
  2
57809
58446
  );
57810
- fs43.mkdirSync(this.dataDir, { recursive: true });
57811
- fs43.writeFileSync(tmp, content, { mode: 384 });
57812
- fs43.renameSync(tmp, file);
58447
+ fs45.mkdirSync(this.dataDir, { recursive: true });
58448
+ fs45.writeFileSync(tmp, content, { mode: 384 });
58449
+ fs45.renameSync(tmp, file);
57813
58450
  }
57814
58451
  renameBak(file) {
57815
58452
  try {
57816
- fs43.renameSync(file, `${file}.bak`);
58453
+ fs45.renameSync(file, `${file}.bak`);
57817
58454
  } catch {
57818
58455
  }
57819
58456
  }
@@ -57921,61 +58558,61 @@ async function connectRemote(args) {
57921
58558
  }
57922
58559
 
57923
58560
  // src/migrations/2026-05-20-flatten-sessions.ts
57924
- var fs44 = __toESM(require("fs"), 1);
57925
- var path46 = __toESM(require("path"), 1);
58561
+ var fs46 = __toESM(require("fs"), 1);
58562
+ var path48 = __toESM(require("path"), 1);
57926
58563
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
57927
58564
  function migrateFlattenSessions(opts) {
57928
58565
  const dataDir = opts.dataDir;
57929
58566
  const now = opts.now ?? Date.now;
57930
- const sessionsDir = path46.join(dataDir, "sessions");
57931
- const flagPath = path46.join(sessionsDir, MIGRATION_FLAG_NAME);
58567
+ const sessionsDir = path48.join(dataDir, "sessions");
58568
+ const flagPath = path48.join(sessionsDir, MIGRATION_FLAG_NAME);
57932
58569
  if (existsSync3(flagPath)) {
57933
58570
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
57934
58571
  }
57935
58572
  let movedBare = 0;
57936
58573
  let movedVmOwner = 0;
57937
58574
  let archivedListener = 0;
57938
- const defaultDir = path46.join(sessionsDir, "default");
58575
+ const defaultDir = path48.join(sessionsDir, "default");
57939
58576
  if (existsSync3(defaultDir)) {
57940
58577
  for (const entry of readdirSafe(defaultDir)) {
57941
58578
  if (!entry.endsWith(".json")) continue;
57942
- const src = path46.join(defaultDir, entry);
57943
- const dst = path46.join(sessionsDir, entry);
57944
- fs44.renameSync(src, dst);
58579
+ const src = path48.join(defaultDir, entry);
58580
+ const dst = path48.join(sessionsDir, entry);
58581
+ fs46.renameSync(src, dst);
57945
58582
  movedBare += 1;
57946
58583
  }
57947
58584
  rmdirIfEmpty(defaultDir);
57948
58585
  }
57949
58586
  for (const pid of readdirSafe(sessionsDir)) {
57950
- const personaDir = path46.join(sessionsDir, pid);
58587
+ const personaDir = path48.join(sessionsDir, pid);
57951
58588
  if (!isDir(personaDir)) continue;
57952
58589
  if (pid === "default") continue;
57953
- const ownerSrc = path46.join(personaDir, "owner");
58590
+ const ownerSrc = path48.join(personaDir, "owner");
57954
58591
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
57955
- const ownerDst = path46.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
57956
- fs44.mkdirSync(ownerDst, { recursive: true });
58592
+ const ownerDst = path48.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
58593
+ fs46.mkdirSync(ownerDst, { recursive: true });
57957
58594
  for (const file of readdirSafe(ownerSrc)) {
57958
58595
  if (!file.endsWith(".json")) continue;
57959
- fs44.renameSync(path46.join(ownerSrc, file), path46.join(ownerDst, file));
58596
+ fs46.renameSync(path48.join(ownerSrc, file), path48.join(ownerDst, file));
57960
58597
  movedVmOwner += 1;
57961
58598
  }
57962
58599
  rmdirIfEmpty(ownerSrc);
57963
58600
  }
57964
- const listenerSrc = path46.join(personaDir, "listener");
58601
+ const listenerSrc = path48.join(personaDir, "listener");
57965
58602
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
57966
- const archiveDst = path46.join(dataDir, ".legacy", `listener-${pid}`);
57967
- fs44.mkdirSync(archiveDst, { recursive: true });
58603
+ const archiveDst = path48.join(dataDir, ".legacy", `listener-${pid}`);
58604
+ fs46.mkdirSync(archiveDst, { recursive: true });
57968
58605
  for (const file of readdirSafe(listenerSrc)) {
57969
58606
  if (!file.endsWith(".json")) continue;
57970
- fs44.renameSync(path46.join(listenerSrc, file), path46.join(archiveDst, file));
58607
+ fs46.renameSync(path48.join(listenerSrc, file), path48.join(archiveDst, file));
57971
58608
  archivedListener += 1;
57972
58609
  }
57973
58610
  rmdirIfEmpty(listenerSrc);
57974
58611
  }
57975
58612
  rmdirIfEmpty(personaDir);
57976
58613
  }
57977
- fs44.mkdirSync(sessionsDir, { recursive: true });
57978
- fs44.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
58614
+ fs46.mkdirSync(sessionsDir, { recursive: true });
58615
+ fs46.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
57979
58616
  return {
57980
58617
  skipped: false,
57981
58618
  flagWritten: true,
@@ -57986,7 +58623,7 @@ function migrateFlattenSessions(opts) {
57986
58623
  }
57987
58624
  function existsSync3(p2) {
57988
58625
  try {
57989
- fs44.statSync(p2);
58626
+ fs46.statSync(p2);
57990
58627
  return true;
57991
58628
  } catch {
57992
58629
  return false;
@@ -57994,61 +58631,61 @@ function existsSync3(p2) {
57994
58631
  }
57995
58632
  function isDir(p2) {
57996
58633
  try {
57997
- return fs44.statSync(p2).isDirectory();
58634
+ return fs46.statSync(p2).isDirectory();
57998
58635
  } catch {
57999
58636
  return false;
58000
58637
  }
58001
58638
  }
58002
58639
  function readdirSafe(p2) {
58003
58640
  try {
58004
- return fs44.readdirSync(p2);
58641
+ return fs46.readdirSync(p2);
58005
58642
  } catch {
58006
58643
  return [];
58007
58644
  }
58008
58645
  }
58009
58646
  function rmdirIfEmpty(p2) {
58010
58647
  try {
58011
- fs44.rmdirSync(p2);
58648
+ fs46.rmdirSync(p2);
58012
58649
  } catch {
58013
58650
  }
58014
58651
  }
58015
58652
 
58016
58653
  // src/migrations/2026-08-18-drop-seeded-projects.ts
58017
- var fs45 = __toESM(require("fs"), 1);
58018
- var path47 = __toESM(require("path"), 1);
58654
+ var fs47 = __toESM(require("fs"), 1);
58655
+ var path49 = __toESM(require("path"), 1);
58019
58656
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
58020
58657
  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");
58658
+ fs47.mkdirSync(opts.dataDir, { recursive: true });
58659
+ const flag = path49.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
58660
+ if (fs47.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
58661
+ const file = path49.join(opts.dataDir, "projects.json");
58025
58662
  let raw = null;
58026
58663
  let dropped = 0;
58027
58664
  try {
58028
- raw = fs45.readFileSync(file, "utf8");
58665
+ raw = fs47.readFileSync(file, "utf8");
58029
58666
  dropped = JSON.parse(raw).projects?.length ?? 0;
58030
58667
  } catch {
58031
58668
  }
58032
58669
  let backup = null;
58033
58670
  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);
58671
+ const dir = path49.join(opts.dataDir, "backups");
58672
+ fs47.mkdirSync(dir, { recursive: true });
58673
+ backup = path49.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
58674
+ fs47.writeFileSync(backup, raw);
58038
58675
  }
58039
58676
  if (raw != null || dropped > 0) {
58040
- fs45.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58677
+ fs47.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
58041
58678
  }
58042
- fs45.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58679
+ fs47.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
58043
58680
  return { skipped: false, dropped, backup };
58044
58681
  }
58045
58682
 
58046
58683
  // src/transport/http-router.ts
58047
58684
  var import_node_fs34 = __toESM(require("fs"), 1);
58048
- var import_node_path39 = __toESM(require("path"), 1);
58685
+ var import_node_path41 = __toESM(require("path"), 1);
58049
58686
 
58050
58687
  // src/attachment/mime.ts
58051
- var import_node_path36 = __toESM(require("path"), 1);
58688
+ var import_node_path38 = __toESM(require("path"), 1);
58052
58689
  var TEXT_PLAIN = "text/plain; charset=utf-8";
58053
58690
  var EXT_TO_NATIVE_MIME = {
58054
58691
  // 图片
@@ -58155,7 +58792,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
58155
58792
  ".mk"
58156
58793
  ]);
58157
58794
  function lookupMime(filePathOrName) {
58158
- const ext = import_node_path36.default.extname(filePathOrName).toLowerCase();
58795
+ const ext = import_node_path38.default.extname(filePathOrName).toLowerCase();
58159
58796
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
58160
58797
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
58161
58798
  return "application/octet-stream";
@@ -58226,9 +58863,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
58226
58863
 
58227
58864
  // src/attachment/upload.ts
58228
58865
  var import_node_fs33 = __toESM(require("fs"), 1);
58229
- var import_node_path37 = __toESM(require("path"), 1);
58866
+ var import_node_path39 = __toESM(require("path"), 1);
58230
58867
  var import_node_crypto10 = __toESM(require("crypto"), 1);
58231
- var import_promises5 = require("stream/promises");
58868
+ var import_promises7 = require("stream/promises");
58232
58869
  var UploadError = class extends Error {
58233
58870
  constructor(code, message) {
58234
58871
  super(message);
@@ -58238,14 +58875,14 @@ var UploadError = class extends Error {
58238
58875
  code;
58239
58876
  };
58240
58877
  function assertValidFileName(fileName) {
58241
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path37.default.basename(fileName)) {
58878
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path39.default.basename(fileName)) {
58242
58879
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
58243
58880
  }
58244
58881
  }
58245
58882
  var HASH_PREFIX_LEN = 16;
58246
58883
  async function writeUploadedAttachment(args) {
58247
58884
  assertValidFileName(args.fileName);
58248
- const attachmentsRoot = import_node_path37.default.join(args.baseDir, ".attachments");
58885
+ const attachmentsRoot = import_node_path39.default.join(args.baseDir, ".attachments");
58249
58886
  try {
58250
58887
  import_node_fs33.default.mkdirSync(attachmentsRoot, { recursive: true });
58251
58888
  } catch (err) {
@@ -58253,12 +58890,12 @@ async function writeUploadedAttachment(args) {
58253
58890
  }
58254
58891
  const hasher = import_node_crypto10.default.createHash("sha256");
58255
58892
  let actualSize = 0;
58256
- const tmpPath = import_node_path37.default.join(
58893
+ const tmpPath = import_node_path39.default.join(
58257
58894
  attachmentsRoot,
58258
58895
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto10.default.randomBytes(4).toString("hex")}`
58259
58896
  );
58260
58897
  try {
58261
- await (0, import_promises5.pipeline)(
58898
+ await (0, import_promises7.pipeline)(
58262
58899
  args.body,
58263
58900
  async function* (source) {
58264
58901
  for await (const chunk of source) {
@@ -58288,7 +58925,7 @@ async function writeUploadedAttachment(args) {
58288
58925
  );
58289
58926
  }
58290
58927
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
58291
- const hashDir = import_node_path37.default.join(attachmentsRoot, attachmentId);
58928
+ const hashDir = import_node_path39.default.join(attachmentsRoot, attachmentId);
58292
58929
  let finalFileName;
58293
58930
  let hashDirExists = false;
58294
58931
  try {
@@ -58306,7 +58943,7 @@ async function writeUploadedAttachment(args) {
58306
58943
  try {
58307
58944
  import_node_fs33.default.mkdirSync(hashDir, { recursive: true });
58308
58945
  finalFileName = args.fileName;
58309
- import_node_fs33.default.renameSync(tmpPath, import_node_path37.default.join(hashDir, finalFileName));
58946
+ import_node_fs33.default.renameSync(tmpPath, import_node_path39.default.join(hashDir, finalFileName));
58310
58947
  } catch (err) {
58311
58948
  try {
58312
58949
  import_node_fs33.default.unlinkSync(tmpPath);
@@ -58315,7 +58952,7 @@ async function writeUploadedAttachment(args) {
58315
58952
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
58316
58953
  }
58317
58954
  }
58318
- const absPath = import_node_path37.default.join(hashDir, finalFileName);
58955
+ const absPath = import_node_path39.default.join(hashDir, finalFileName);
58319
58956
  const relPath = absPath;
58320
58957
  args.groupFileStore.upsert(args.scope, args.sessionId, {
58321
58958
  relPath: absPath,
@@ -58329,8 +58966,8 @@ async function writeUploadedAttachment(args) {
58329
58966
  }
58330
58967
 
58331
58968
  // src/extension/import.ts
58332
- var import_promises6 = __toESM(require("fs/promises"), 1);
58333
- var import_node_path38 = __toESM(require("path"), 1);
58969
+ var import_promises8 = __toESM(require("fs/promises"), 1);
58970
+ var import_node_path40 = __toESM(require("path"), 1);
58334
58971
  var import_node_os13 = __toESM(require("os"), 1);
58335
58972
  var import_jszip = __toESM(require_lib3(), 1);
58336
58973
  var ImportError = class extends Error {
@@ -58348,7 +58985,7 @@ async function importZip(buf, root) {
58348
58985
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
58349
58986
  }
58350
58987
  for (const name of Object.keys(zip.files)) {
58351
- if (name.includes("..") || name.startsWith("/") || import_node_path38.default.isAbsolute(name)) {
58988
+ if (name.includes("..") || name.startsWith("/") || import_node_path40.default.isAbsolute(name)) {
58352
58989
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
58353
58990
  }
58354
58991
  }
@@ -58381,33 +59018,33 @@ async function importZip(buf, root) {
58381
59018
  );
58382
59019
  }
58383
59020
  }
58384
- const destDir = import_node_path38.default.join(root, manifest.id);
59021
+ const destDir = import_node_path40.default.join(root, manifest.id);
58385
59022
  let destExists = false;
58386
59023
  try {
58387
- await import_promises6.default.access(destDir);
59024
+ await import_promises8.default.access(destDir);
58388
59025
  destExists = true;
58389
59026
  } catch {
58390
59027
  }
58391
59028
  if (destExists) {
58392
59029
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
58393
59030
  }
58394
- const stage = await import_promises6.default.mkdtemp(import_node_path38.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
59031
+ const stage = await import_promises8.default.mkdtemp(import_node_path40.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
58395
59032
  try {
58396
59033
  for (const [name, entry] of Object.entries(zip.files)) {
58397
- const dest = import_node_path38.default.join(stage, name);
59034
+ const dest = import_node_path40.default.join(stage, name);
58398
59035
  if (entry.dir) {
58399
- await import_promises6.default.mkdir(dest, { recursive: true });
59036
+ await import_promises8.default.mkdir(dest, { recursive: true });
58400
59037
  continue;
58401
59038
  }
58402
- await import_promises6.default.mkdir(import_node_path38.default.dirname(dest), { recursive: true });
59039
+ await import_promises8.default.mkdir(import_node_path40.default.dirname(dest), { recursive: true });
58403
59040
  const content = await entry.async("nodebuffer");
58404
- await import_promises6.default.writeFile(dest, content);
59041
+ await import_promises8.default.writeFile(dest, content);
58405
59042
  }
58406
- await import_promises6.default.mkdir(root, { recursive: true });
58407
- await import_promises6.default.rename(stage, destDir);
59043
+ await import_promises8.default.mkdir(root, { recursive: true });
59044
+ await import_promises8.default.rename(stage, destDir);
58408
59045
  return { extId: manifest.id };
58409
59046
  } catch (e) {
58410
- await import_promises6.default.rm(stage, { recursive: true, force: true }).catch(() => {
59047
+ await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
58411
59048
  });
58412
59049
  throw e;
58413
59050
  }
@@ -58429,7 +59066,7 @@ var SHARE_UI_ASSET_MIME = {
58429
59066
  ".wasm": "application/wasm"
58430
59067
  };
58431
59068
  function shareUiAssetMime(filePath) {
58432
- const ext = import_node_path39.default.extname(filePath).toLowerCase();
59069
+ const ext = import_node_path41.default.extname(filePath).toLowerCase();
58433
59070
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
58434
59071
  }
58435
59072
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -58528,7 +59165,7 @@ function isValidUploadFileName(fileName) {
58528
59165
  if (fileName === "." || fileName === "..") return false;
58529
59166
  if (fileName.startsWith(".")) return false;
58530
59167
  if (fileName.includes("/") || fileName.includes("\\")) return false;
58531
- return fileName === import_node_path39.default.basename(fileName);
59168
+ return fileName === import_node_path41.default.basename(fileName);
58532
59169
  }
58533
59170
  function createHttpRouter(deps) {
58534
59171
  return async (req, res) => {
@@ -58764,7 +59401,7 @@ function createHttpRouter(deps) {
58764
59401
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
58765
59402
  return true;
58766
59403
  }
58767
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path39.default.basename(r.absPath)));
59404
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path41.default.basename(r.absPath)));
58768
59405
  return true;
58769
59406
  }
58770
59407
  const ctx = deps.authResolver.resolveFromHeader(
@@ -58885,7 +59522,7 @@ function createHttpRouter(deps) {
58885
59522
  return true;
58886
59523
  }
58887
59524
  let absPath;
58888
- if (import_node_path39.default.isAbsolute(pathParam)) {
59525
+ if (import_node_path41.default.isAbsolute(pathParam)) {
58889
59526
  absPath = pathParam;
58890
59527
  } else if (deps.sessionStore) {
58891
59528
  const file = deps.sessionStore.read(sid);
@@ -58893,7 +59530,7 @@ function createHttpRouter(deps) {
58893
59530
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
58894
59531
  return true;
58895
59532
  }
58896
- absPath = import_node_path39.default.join(file.cwd, pathParam);
59533
+ absPath = import_node_path41.default.join(file.cwd, pathParam);
58897
59534
  } else {
58898
59535
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
58899
59536
  return true;
@@ -58995,7 +59632,7 @@ function streamFile(res, absPath, logger) {
58995
59632
  return;
58996
59633
  }
58997
59634
  const mime = lookupMime(absPath);
58998
- const basename2 = import_node_path39.default.basename(absPath);
59635
+ const basename2 = import_node_path41.default.basename(absPath);
58999
59636
  res.writeHead(200, {
59000
59637
  "Content-Type": mime,
59001
59638
  "Content-Length": String(stat.size),
@@ -59013,7 +59650,7 @@ function streamFile(res, absPath, logger) {
59013
59650
 
59014
59651
  // src/attachment/gc.ts
59015
59652
  var import_node_fs35 = __toESM(require("fs"), 1);
59016
- var import_node_path40 = __toESM(require("path"), 1);
59653
+ var import_node_path42 = __toESM(require("path"), 1);
59017
59654
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
59018
59655
  function runAttachmentGc(args) {
59019
59656
  const now = (args.now ?? Date.now)();
@@ -59022,12 +59659,12 @@ function runAttachmentGc(args) {
59022
59659
  for (const { scope, sessionId } of args.sessionScopes) {
59023
59660
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
59024
59661
  if (entry.stale) continue;
59025
- if (import_node_path40.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
59662
+ if (import_node_path42.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
59026
59663
  }
59027
59664
  }
59028
59665
  const visited = /* @__PURE__ */ new Set();
59029
59666
  for (const { scope, sessionId } of args.sessionScopes) {
59030
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path40.default.join(
59667
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path42.default.join(
59031
59668
  args.dataDir,
59032
59669
  "sessions",
59033
59670
  ...scopeSubPath(scope).map(safeFileName),
@@ -59040,7 +59677,7 @@ function runAttachmentGc(args) {
59040
59677
  return true;
59041
59678
  });
59042
59679
  for (const rootDir of roots) {
59043
- const attRoot = import_node_path40.default.join(rootDir, ".attachments");
59680
+ const attRoot = import_node_path42.default.join(rootDir, ".attachments");
59044
59681
  let hashDirs;
59045
59682
  try {
59046
59683
  hashDirs = import_node_fs35.default.readdirSync(attRoot);
@@ -59050,7 +59687,7 @@ function runAttachmentGc(args) {
59050
59687
  continue;
59051
59688
  }
59052
59689
  for (const hashDir of hashDirs) {
59053
- const hashDirAbs = import_node_path40.default.join(attRoot, hashDir);
59690
+ const hashDirAbs = import_node_path42.default.join(attRoot, hashDir);
59054
59691
  let files;
59055
59692
  try {
59056
59693
  files = import_node_fs35.default.readdirSync(hashDirAbs);
@@ -59058,7 +59695,7 @@ function runAttachmentGc(args) {
59058
59695
  continue;
59059
59696
  }
59060
59697
  for (const name of files) {
59061
- const file = import_node_path40.default.join(hashDirAbs, name);
59698
+ const file = import_node_path42.default.join(hashDirAbs, name);
59062
59699
  let stat;
59063
59700
  try {
59064
59701
  stat = import_node_fs35.default.statSync(file);
@@ -59090,7 +59727,7 @@ function runAttachmentGc(args) {
59090
59727
 
59091
59728
  // src/attachment/group.ts
59092
59729
  var import_node_fs36 = __toESM(require("fs"), 1);
59093
- var import_node_path41 = __toESM(require("path"), 1);
59730
+ var import_node_path43 = __toESM(require("path"), 1);
59094
59731
  var import_node_crypto11 = __toESM(require("crypto"), 1);
59095
59732
  init_protocol();
59096
59733
  var GroupFileStore = class {
@@ -59102,11 +59739,11 @@ var GroupFileStore = class {
59102
59739
  this.logger = opts.logger;
59103
59740
  }
59104
59741
  rootForScope(scope) {
59105
- return import_node_path41.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
59742
+ return import_node_path43.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
59106
59743
  }
59107
59744
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
59108
59745
  filePath(scope, sessionId) {
59109
- return import_node_path41.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
59746
+ return import_node_path43.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
59110
59747
  }
59111
59748
  cacheKey(scope, sessionId) {
59112
59749
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -59141,7 +59778,7 @@ var GroupFileStore = class {
59141
59778
  }
59142
59779
  writeFile(scope, sessionId, entries) {
59143
59780
  const file = this.filePath(scope, sessionId);
59144
- import_node_fs36.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true });
59781
+ import_node_fs36.default.mkdirSync(import_node_path43.default.dirname(file), { recursive: true });
59145
59782
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
59146
59783
  import_node_fs36.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
59147
59784
  import_node_fs36.default.renameSync(tmp, file);
@@ -59231,9 +59868,9 @@ var GroupFileStore = class {
59231
59868
 
59232
59869
  // src/discovery/state-file.ts
59233
59870
  var import_node_fs37 = __toESM(require("fs"), 1);
59234
- var import_node_path42 = __toESM(require("path"), 1);
59871
+ var import_node_path44 = __toESM(require("path"), 1);
59235
59872
  function defaultStateFilePath(dataDir) {
59236
- return import_node_path42.default.join(dataDir, "state.json");
59873
+ return import_node_path44.default.join(dataDir, "state.json");
59237
59874
  }
59238
59875
  function isPidAlive(pid) {
59239
59876
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -59269,7 +59906,7 @@ var StateFileManager = class {
59269
59906
  return { status: "stale", existing };
59270
59907
  }
59271
59908
  write(state) {
59272
- import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(this.file), { recursive: true });
59909
+ import_node_fs37.default.mkdirSync(import_node_path44.default.dirname(this.file), { recursive: true });
59273
59910
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
59274
59911
  import_node_fs37.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
59275
59912
  import_node_fs37.default.renameSync(tmp, this.file);
@@ -59297,13 +59934,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
59297
59934
 
59298
59935
  // src/tunnel/tunnel-manager.ts
59299
59936
  var import_node_fs41 = __toESM(require("fs"), 1);
59300
- var import_node_path46 = __toESM(require("path"), 1);
59937
+ var import_node_path48 = __toESM(require("path"), 1);
59301
59938
  var import_node_crypto12 = __toESM(require("crypto"), 1);
59302
59939
  var import_node_child_process11 = require("child_process");
59303
59940
 
59304
59941
  // src/tunnel/tunnel-store.ts
59305
59942
  var import_node_fs38 = __toESM(require("fs"), 1);
59306
- var import_node_path43 = __toESM(require("path"), 1);
59943
+ var import_node_path45 = __toESM(require("path"), 1);
59307
59944
  var TunnelStore = class {
59308
59945
  constructor(filePath) {
59309
59946
  this.filePath = filePath;
@@ -59322,7 +59959,7 @@ var TunnelStore = class {
59322
59959
  }
59323
59960
  }
59324
59961
  async set(v2) {
59325
- const dir = import_node_path43.default.dirname(this.filePath);
59962
+ const dir = import_node_path45.default.dirname(this.filePath);
59326
59963
  await import_node_fs38.default.promises.mkdir(dir, { recursive: true });
59327
59964
  const data = JSON.stringify(v2, null, 2);
59328
59965
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -59434,10 +60071,10 @@ function escape(v2) {
59434
60071
  // src/tunnel/frpc-binary.ts
59435
60072
  var import_node_fs39 = __toESM(require("fs"), 1);
59436
60073
  var import_node_os14 = __toESM(require("os"), 1);
59437
- var import_node_path44 = __toESM(require("path"), 1);
60074
+ var import_node_path46 = __toESM(require("path"), 1);
59438
60075
  var import_node_child_process9 = require("child_process");
59439
60076
  var import_node_stream3 = require("stream");
59440
- var import_promises7 = require("stream/promises");
60077
+ var import_promises9 = require("stream/promises");
59441
60078
  var FRPC_VERSION = "0.68.0";
59442
60079
  var UnsupportedPlatformError = class extends Error {
59443
60080
  constructor(platform, arch) {
@@ -59473,13 +60110,13 @@ async function ensureFrpcBinary(opts) {
59473
60110
  }
59474
60111
  const version2 = opts.version ?? FRPC_VERSION;
59475
60112
  const platform = opts.platform ?? detectPlatform();
59476
- const binDir = import_node_path44.default.join(opts.dataDir, "bin");
60113
+ const binDir = import_node_path46.default.join(opts.dataDir, "bin");
59477
60114
  import_node_fs39.default.mkdirSync(binDir, { recursive: true });
59478
60115
  cleanupStaleArtifacts(binDir);
59479
- const stableBin = import_node_path44.default.join(binDir, "frpc");
60116
+ const stableBin = import_node_path46.default.join(binDir, "frpc");
59480
60117
  if (import_node_fs39.default.existsSync(stableBin)) return stableBin;
59481
60118
  const partialBin = `${stableBin}.partial`;
59482
- const tarballPath = import_node_path44.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
60119
+ const tarballPath = import_node_path46.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
59483
60120
  try {
59484
60121
  const url = frpcDownloadUrl(version2, platform);
59485
60122
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -59505,7 +60142,7 @@ function cleanupStaleArtifacts(binDir) {
59505
60142
  }
59506
60143
  for (const name of entries) {
59507
60144
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
59508
- const full = import_node_path44.default.join(binDir, name);
60145
+ const full = import_node_path46.default.join(binDir, name);
59509
60146
  try {
59510
60147
  import_node_fs39.default.rmSync(full, { recursive: true, force: true });
59511
60148
  } catch {
@@ -59528,10 +60165,10 @@ async function downloadToFile(url, dest, fetchImpl) {
59528
60165
  }
59529
60166
  const out = import_node_fs39.default.createWriteStream(dest);
59530
60167
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
59531
- await (0, import_promises7.pipeline)(nodeStream, out);
60168
+ await (0, import_promises9.pipeline)(nodeStream, out);
59532
60169
  }
59533
60170
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
59534
- const work = import_node_path44.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
60171
+ const work = import_node_path46.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
59535
60172
  import_node_fs39.default.mkdirSync(work, { recursive: true });
59536
60173
  try {
59537
60174
  await new Promise((resolve9, reject) => {
@@ -59540,7 +60177,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
59540
60177
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
59541
60178
  });
59542
60179
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
59543
- const src = import_node_path44.default.join(work, dirName, "frpc");
60180
+ const src = import_node_path46.default.join(work, dirName, "frpc");
59544
60181
  if (!import_node_fs39.default.existsSync(src)) {
59545
60182
  throw new Error(`frpc not found inside tarball at ${src}`);
59546
60183
  }
@@ -59552,10 +60189,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
59552
60189
 
59553
60190
  // src/tunnel/frpc-process.ts
59554
60191
  var import_node_fs40 = __toESM(require("fs"), 1);
59555
- var import_node_path45 = __toESM(require("path"), 1);
60192
+ var import_node_path47 = __toESM(require("path"), 1);
59556
60193
  var import_node_child_process10 = require("child_process");
59557
60194
  function frpcPidFilePath(dataDir) {
59558
- return import_node_path45.default.join(dataDir, "frpc.pid");
60195
+ return import_node_path47.default.join(dataDir, "frpc.pid");
59559
60196
  }
59560
60197
  function writeFrpcPid(dataDir, pid) {
59561
60198
  try {
@@ -59597,7 +60234,7 @@ function defaultSleep2(ms) {
59597
60234
  }
59598
60235
  async function killStaleFrpc(deps) {
59599
60236
  const pidFile = frpcPidFilePath(deps.dataDir);
59600
- const tomlPath = import_node_path45.default.join(deps.dataDir, "frpc.toml");
60237
+ const tomlPath = import_node_path47.default.join(deps.dataDir, "frpc.toml");
59601
60238
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
59602
60239
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
59603
60240
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -59669,7 +60306,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
59669
60306
  var TunnelManager = class {
59670
60307
  constructor(deps) {
59671
60308
  this.deps = deps;
59672
- this.store = deps.store ?? new TunnelStore(import_node_path46.default.join(deps.dataDir, "tunnel.json"));
60309
+ this.store = deps.store ?? new TunnelStore(import_node_path48.default.join(deps.dataDir, "tunnel.json"));
59673
60310
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
59674
60311
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
59675
60312
  }
@@ -59796,7 +60433,7 @@ var TunnelManager = class {
59796
60433
  dataDir: this.deps.dataDir,
59797
60434
  override: this.deps.frpcBinaryOverride ?? void 0
59798
60435
  });
59799
- const tomlPath = import_node_path46.default.join(this.deps.dataDir, "frpc.toml");
60436
+ const tomlPath = import_node_path48.default.join(this.deps.dataDir, "frpc.toml");
59800
60437
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto12.default.randomBytes(3).toString("hex")}`;
59801
60438
  const toml = buildFrpcToml({
59802
60439
  serverAddr: t.frpsHost,
@@ -59811,9 +60448,9 @@ var TunnelManager = class {
59811
60448
  const proc = (this.deps.spawnImpl ?? import_node_child_process11.spawn)(frpcBin, ["-c", tomlPath], {
59812
60449
  stdio: ["ignore", "pipe", "pipe"]
59813
60450
  });
59814
- const logDir = import_node_path46.default.join(this.deps.dataDir, "log");
60451
+ const logDir = import_node_path48.default.join(this.deps.dataDir, "log");
59815
60452
  import_node_fs41.default.mkdirSync(logDir, { recursive: true });
59816
- const logFilePath = import_node_path46.default.join(logDir, "frpc.log");
60453
+ const logFilePath = import_node_path48.default.join(logDir, "frpc.log");
59817
60454
  const logStream = import_node_fs41.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
59818
60455
  logStream.on("error", () => {
59819
60456
  });
@@ -59897,15 +60534,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
59897
60534
 
59898
60535
  // src/tunnel/device-key.ts
59899
60536
  var import_node_os15 = __toESM(require("os"), 1);
59900
- var import_node_path47 = __toESM(require("path"), 1);
60537
+ var import_node_path49 = __toESM(require("path"), 1);
59901
60538
  var import_node_crypto13 = __toESM(require("crypto"), 1);
59902
60539
  var DERIVE_SALT = "clawd-tunnel-device-v1";
59903
60540
  function deriveStableDeviceKey(opts = {}) {
59904
60541
  const hostname = opts.hostname ?? import_node_os15.default.hostname();
59905
60542
  const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
59906
60543
  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;
60544
+ const defaultDataDir = import_node_path49.default.resolve(import_node_path49.default.join(home, ".clawd"));
60545
+ const normalizedDataDir = opts.dataDir ? import_node_path49.default.resolve(opts.dataDir) : null;
59909
60546
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
59910
60547
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
59911
60548
  return import_node_crypto13.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -59913,11 +60550,11 @@ function deriveStableDeviceKey(opts = {}) {
59913
60550
 
59914
60551
  // src/auth-store.ts
59915
60552
  var import_node_fs42 = __toESM(require("fs"), 1);
59916
- var import_node_path48 = __toESM(require("path"), 1);
60553
+ var import_node_path50 = __toESM(require("path"), 1);
59917
60554
  var import_node_crypto14 = __toESM(require("crypto"), 1);
59918
60555
  var AUTH_FILE_NAME = "auth.json";
59919
60556
  function authFilePath(dataDir) {
59920
- return import_node_path48.default.join(dataDir, AUTH_FILE_NAME);
60557
+ return import_node_path50.default.join(dataDir, AUTH_FILE_NAME);
59921
60558
  }
59922
60559
  function loadOrCreateAuthFile(opts) {
59923
60560
  const file = authFilePath(opts.dataDir);
@@ -59969,7 +60606,7 @@ function readAuthFile(file) {
59969
60606
  }
59970
60607
  }
59971
60608
  function writeAuthFile(file, content) {
59972
- import_node_fs42.default.mkdirSync(import_node_path48.default.dirname(file), { recursive: true });
60609
+ import_node_fs42.default.mkdirSync(import_node_path50.default.dirname(file), { recursive: true });
59973
60610
  import_node_fs42.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
59974
60611
  try {
59975
60612
  import_node_fs42.default.chmodSync(file, 384);
@@ -59980,10 +60617,10 @@ function writeAuthFile(file, content) {
59980
60617
  // src/owner-profile.ts
59981
60618
  var import_node_fs43 = __toESM(require("fs"), 1);
59982
60619
  var import_node_os16 = __toESM(require("os"), 1);
59983
- var import_node_path49 = __toESM(require("path"), 1);
60620
+ var import_node_path51 = __toESM(require("path"), 1);
59984
60621
  var PROFILE_FILENAME = "profile.json";
59985
60622
  function profilePath(dataDir) {
59986
- return import_node_path49.default.join(dataDir, PROFILE_FILENAME);
60623
+ return import_node_path51.default.join(dataDir, PROFILE_FILENAME);
59987
60624
  }
59988
60625
  function loadOwnerProfile(dataDir) {
59989
60626
  let raw;
@@ -60021,12 +60658,12 @@ function loadOwnerDisplayName(dataDir) {
60021
60658
 
60022
60659
  // src/feishu-auth/owner-identity-store.ts
60023
60660
  var import_node_fs44 = __toESM(require("fs"), 1);
60024
- var import_node_path50 = __toESM(require("path"), 1);
60661
+ var import_node_path52 = __toESM(require("path"), 1);
60025
60662
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
60026
60663
  var OwnerIdentityStore = class {
60027
60664
  file;
60028
60665
  constructor(dataDir) {
60029
- this.file = import_node_path50.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
60666
+ this.file = import_node_path52.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
60030
60667
  }
60031
60668
  read() {
60032
60669
  let raw;
@@ -60059,7 +60696,7 @@ var OwnerIdentityStore = class {
60059
60696
  };
60060
60697
  }
60061
60698
  write(record3) {
60062
- import_node_fs44.default.mkdirSync(import_node_path50.default.dirname(this.file), { recursive: true });
60699
+ import_node_fs44.default.mkdirSync(import_node_path52.default.dirname(this.file), { recursive: true });
60063
60700
  import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
60064
60701
  try {
60065
60702
  import_node_fs44.default.chmodSync(this.file, 384);
@@ -60205,9 +60842,9 @@ var CentralClientError = class extends Error {
60205
60842
  code;
60206
60843
  cause;
60207
60844
  };
60208
- async function centralRequest(opts, path91, init) {
60845
+ async function centralRequest(opts, path93, init) {
60209
60846
  const f = opts.fetchImpl ?? globalThis.fetch;
60210
- const url = `${opts.api.replace(/\/+$/, "")}${path91}`;
60847
+ const url = `${opts.api.replace(/\/+$/, "")}${path93}`;
60211
60848
  const ctrl = new AbortController();
60212
60849
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
60213
60850
  let res;
@@ -60461,7 +61098,7 @@ async function syncOrgMesh(deps) {
60461
61098
 
60462
61099
  // src/handlers/device.ts
60463
61100
  init_protocol();
60464
- function ensureOwner(ctx) {
61101
+ function ensureOwner2(ctx) {
60465
61102
  if (!ctx || ctx.principal.kind !== "owner") {
60466
61103
  throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: device:* requires owner ctx");
60467
61104
  }
@@ -60556,14 +61193,14 @@ function createConnectToDevice(deps) {
60556
61193
  function buildDeviceHandlers(deps) {
60557
61194
  const connectToDevice = createConnectToDevice(deps);
60558
61195
  const list = async (_frame, _client, ctx) => {
60559
- ensureOwner(ctx);
61196
+ ensureOwner2(ctx);
60560
61197
  const devices = await deps.listDevices().catch(rethrowLoginExpired);
60561
61198
  return {
60562
61199
  response: { type: "device:list:ok", devices }
60563
61200
  };
60564
61201
  };
60565
61202
  const connect = async (frame, _client, ctx) => {
60566
- ensureOwner(ctx);
61203
+ ensureOwner2(ctx);
60567
61204
  const { type: _t, requestId: _r, ...rest } = frame;
60568
61205
  const args = DeviceConnectArgsSchema.parse(rest);
60569
61206
  const contact = await connectToDevice(args);
@@ -60578,7 +61215,7 @@ function buildDeviceHandlers(deps) {
60578
61215
  };
60579
61216
  };
60580
61217
  const connections = async (_frame, client, ctx) => {
60581
- ensureOwner(ctx);
61218
+ ensureOwner2(ctx);
60582
61219
  const entries = deps.listOwnerConnections();
60583
61220
  return {
60584
61221
  response: {
@@ -60644,8 +61281,8 @@ function verifyConnectToken(args) {
60644
61281
  }
60645
61282
 
60646
61283
  // src/feishu-auth/server-key.ts
60647
- var fs59 = __toESM(require("fs"), 1);
60648
- var path63 = __toESM(require("path"), 1);
61284
+ var fs61 = __toESM(require("fs"), 1);
61285
+ var path65 = __toESM(require("path"), 1);
60649
61286
  var FILE_NAME2 = "server-signing-key.json";
60650
61287
  var ServerKeyStore = class {
60651
61288
  constructor(dataDir) {
@@ -60653,12 +61290,12 @@ var ServerKeyStore = class {
60653
61290
  }
60654
61291
  dataDir;
60655
61292
  filePath() {
60656
- return path63.join(this.dataDir, FILE_NAME2);
61293
+ return path65.join(this.dataDir, FILE_NAME2);
60657
61294
  }
60658
61295
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
60659
61296
  read() {
60660
61297
  try {
60661
- const raw = fs59.readFileSync(this.filePath(), "utf8");
61298
+ const raw = fs61.readFileSync(this.filePath(), "utf8");
60662
61299
  const parsed = JSON.parse(raw);
60663
61300
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
60664
61301
  return parsed.publicKeyPem;
@@ -60673,12 +61310,12 @@ var ServerKeyStore = class {
60673
61310
  publicKeyPem,
60674
61311
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
60675
61312
  };
60676
- fs59.mkdirSync(this.dataDir, { recursive: true });
60677
- fs59.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
61313
+ fs61.mkdirSync(this.dataDir, { recursive: true });
61314
+ fs61.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
60678
61315
  }
60679
61316
  clear() {
60680
61317
  try {
60681
- fs59.unlinkSync(this.filePath());
61318
+ fs61.unlinkSync(this.filePath());
60682
61319
  } catch {
60683
61320
  }
60684
61321
  }
@@ -60688,7 +61325,7 @@ var ServerKeyStore = class {
60688
61325
  init_protocol();
60689
61326
 
60690
61327
  // src/handlers/index.ts
60691
- var import_node_path68 = __toESM(require("path"), 1);
61328
+ var import_node_path70 = __toESM(require("path"), 1);
60692
61329
 
60693
61330
  // src/handlers/session.ts
60694
61331
  init_protocol();
@@ -60696,7 +61333,7 @@ init_protocol();
60696
61333
  // src/session/fork.ts
60697
61334
  var import_node_fs45 = __toESM(require("fs"), 1);
60698
61335
  var import_node_os17 = __toESM(require("os"), 1);
60699
- var import_node_path51 = __toESM(require("path"), 1);
61336
+ var import_node_path53 = __toESM(require("path"), 1);
60700
61337
  var import_node_crypto16 = require("crypto");
60701
61338
  init_claude_history();
60702
61339
  function readJsonlEntries(file) {
@@ -60713,19 +61350,19 @@ function readJsonlEntries(file) {
60713
61350
  return out;
60714
61351
  }
60715
61352
  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`);
61353
+ const baseDir = input.baseDir ?? import_node_path53.default.join(import_node_os17.default.homedir(), ".claude");
61354
+ let projectDir = import_node_path53.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
61355
+ let sourceFile = import_node_path53.default.join(projectDir, `${input.toolSessionId}.jsonl`);
60719
61356
  if (!import_node_fs45.default.existsSync(sourceFile)) {
60720
61357
  const found = findTranscriptByToolSessionId(
60721
- import_node_path51.default.join(baseDir, "projects"),
61358
+ import_node_path53.default.join(baseDir, "projects"),
60722
61359
  input.toolSessionId
60723
61360
  );
60724
61361
  if (!found) {
60725
61362
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
60726
61363
  }
60727
61364
  sourceFile = found;
60728
- projectDir = import_node_path51.default.dirname(found);
61365
+ projectDir = import_node_path53.default.dirname(found);
60729
61366
  }
60730
61367
  const entries = readJsonlEntries(sourceFile);
60731
61368
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -60754,8 +61391,8 @@ function forkSession(input) {
60754
61391
  }
60755
61392
  forkedLines.push(JSON.stringify(forked));
60756
61393
  }
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`);
61394
+ const outDir = input.targetCwd ? import_node_path53.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
61395
+ const forkedFilePath = import_node_path53.default.join(outDir, `${forkedToolSessionId}.jsonl`);
60759
61396
  import_node_fs45.default.mkdirSync(outDir, { recursive: true });
60760
61397
  import_node_fs45.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
60761
61398
  return { forkedToolSessionId, forkedFilePath };
@@ -60763,18 +61400,18 @@ function forkSession(input) {
60763
61400
 
60764
61401
  // src/session/external-scan.ts
60765
61402
  var import_node_fs46 = __toESM(require("fs"), 1);
60766
- var import_promises8 = __toESM(require("fs/promises"), 1);
61403
+ var import_promises10 = __toESM(require("fs/promises"), 1);
60767
61404
  var import_node_os18 = __toESM(require("os"), 1);
60768
- var import_node_path52 = __toESM(require("path"), 1);
61405
+ var import_node_path54 = __toESM(require("path"), 1);
60769
61406
  var import_node_module = require("module");
60770
61407
  var import_node_child_process12 = require("child_process");
60771
61408
  var import_meta4 = {};
60772
61409
  function defaultRoots() {
60773
61410
  const home = import_node_os18.default.homedir();
60774
61411
  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")
61412
+ claudeProjectsDir: import_node_path54.default.join(home, ".claude", "projects"),
61413
+ codexDir: import_node_path54.default.join(home, ".codex"),
61414
+ clawdDir: import_node_path54.default.join(home, ".clawd")
60778
61415
  };
60779
61416
  }
60780
61417
  function width(s) {
@@ -60802,7 +61439,7 @@ function toMs(v2) {
60802
61439
  async function* jsonLines(file) {
60803
61440
  let raw;
60804
61441
  try {
60805
- raw = await import_promises8.default.readFile(file, "utf8");
61442
+ raw = await import_promises10.default.readFile(file, "utf8");
60806
61443
  } catch {
60807
61444
  return;
60808
61445
  }
@@ -60842,13 +61479,13 @@ async function scanClaude(roots) {
60842
61479
  if (!d.isDirectory()) continue;
60843
61480
  let files;
60844
61481
  try {
60845
- files = import_node_fs46.default.readdirSync(import_node_path52.default.join(roots.claudeProjectsDir, d.name));
61482
+ files = import_node_fs46.default.readdirSync(import_node_path54.default.join(roots.claudeProjectsDir, d.name));
60846
61483
  } catch {
60847
61484
  continue;
60848
61485
  }
60849
61486
  for (const name of files) {
60850
61487
  if (!name.endsWith(".jsonl")) continue;
60851
- const file = import_node_path52.default.join(roots.claudeProjectsDir, d.name, name);
61488
+ const file = import_node_path54.default.join(roots.claudeProjectsDir, d.name, name);
60852
61489
  let st;
60853
61490
  try {
60854
61491
  st = import_node_fs46.default.statSync(file);
@@ -60978,7 +61615,7 @@ async function codexFromRows(rows) {
60978
61615
  async function scanCodex(roots) {
60979
61616
  let dbs = [];
60980
61617
  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));
61618
+ 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
61619
  } catch {
60983
61620
  }
60984
61621
  if (!dbs.length) return [];
@@ -60987,14 +61624,14 @@ async function scanCodex(roots) {
60987
61624
  }
60988
61625
  async function scanExternalSessions(rootsIn) {
60989
61626
  const roots = { ...defaultRoots(), ...rootsIn };
60990
- const personaRoot = import_node_path52.default.join(roots.clawdDir, "personas");
61627
+ const personaRoot = import_node_path54.default.join(roots.clawdDir, "personas");
60991
61628
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
60992
61629
  const out = [];
60993
61630
  for (const c of all) {
60994
61631
  if (c.skip) continue;
60995
61632
  if (c.turns < 1) continue;
60996
61633
  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)) {
61634
+ 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
61635
  continue;
60999
61636
  }
61000
61637
  out.push({
@@ -61012,12 +61649,12 @@ async function scanExternalSessions(rootsIn) {
61012
61649
 
61013
61650
  // src/session/import-ledger.ts
61014
61651
  var import_node_fs47 = __toESM(require("fs"), 1);
61015
- var import_node_path53 = __toESM(require("path"), 1);
61652
+ var import_node_path55 = __toESM(require("path"), 1);
61016
61653
  var LEDGER_FILENAME = "session-import-ledger.json";
61017
61654
  function readImportLedger(dataDir) {
61018
61655
  try {
61019
61656
  const parsed = JSON.parse(
61020
- import_node_fs47.default.readFileSync(import_node_path53.default.join(dataDir, LEDGER_FILENAME), "utf8")
61657
+ import_node_fs47.default.readFileSync(import_node_path55.default.join(dataDir, LEDGER_FILENAME), "utf8")
61021
61658
  );
61022
61659
  return Array.isArray(parsed) ? parsed : [];
61023
61660
  } catch {
@@ -61025,7 +61662,7 @@ function readImportLedger(dataDir) {
61025
61662
  }
61026
61663
  }
61027
61664
  function appendImportLedger(dataDir, entry) {
61028
- const file = import_node_path53.default.join(dataDir, LEDGER_FILENAME);
61665
+ const file = import_node_path55.default.join(dataDir, LEDGER_FILENAME);
61029
61666
  const entries = readImportLedger(dataDir);
61030
61667
  entries.push(entry);
61031
61668
  import_node_fs47.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
@@ -61033,7 +61670,7 @@ function appendImportLedger(dataDir, entry) {
61033
61670
 
61034
61671
  // src/tools/transcript-search.ts
61035
61672
  var import_node_fs48 = __toESM(require("fs"), 1);
61036
- var import_node_path54 = __toESM(require("path"), 1);
61673
+ var import_node_path56 = __toESM(require("path"), 1);
61037
61674
  var SNIPPET_PAD = 60;
61038
61675
  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
61676
  var CODEX_WRAPPER_RE = /<(related-dir|environment_context|user_instructions)>[\s\S]*?<\/\1>/g;
@@ -61126,7 +61763,7 @@ function createCodexRolloutLocator(roots) {
61126
61763
  return;
61127
61764
  }
61128
61765
  for (const entry of entries) {
61129
- const full = import_node_path54.default.join(dir, entry.name);
61766
+ const full = import_node_path56.default.join(dir, entry.name);
61130
61767
  if (entry.isDirectory()) {
61131
61768
  walk2(full, into);
61132
61769
  continue;
@@ -61147,15 +61784,15 @@ function createCodexRolloutLocator(roots) {
61147
61784
  // src/handlers/session.ts
61148
61785
  init_protocol();
61149
61786
  var import_node_os19 = __toESM(require("os"), 1);
61150
- var import_node_path55 = __toESM(require("path"), 1);
61787
+ var import_node_path57 = __toESM(require("path"), 1);
61151
61788
  function canReadSearchHit(ctx, file) {
61152
61789
  if (!ctx || ctx.principal.kind === "owner") return true;
61153
61790
  return canAccessPersona(ctx.grants, file.ownerPersonaId, "read") && file.creatorPrincipalId === ctx.principal.id;
61154
61791
  }
61155
61792
  var DEFAULT_SEARCH_LIMIT = 9;
61156
61793
  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"));
61794
+ const roots = [import_node_path57.default.join(import_node_os19.default.homedir(), ".codex", "sessions")];
61795
+ if (dataDir) roots.push(import_node_path57.default.join(dataDir, "codex-home", "sessions"));
61159
61796
  return roots;
61160
61797
  }
61161
61798
  function buildSessionHandlers(deps) {
@@ -61697,7 +62334,7 @@ function buildPermissionHandlers(deps) {
61697
62334
  }
61698
62335
 
61699
62336
  // src/handlers/history.ts
61700
- var path70 = __toESM(require("path"), 1);
62337
+ var path72 = __toESM(require("path"), 1);
61701
62338
  init_protocol();
61702
62339
 
61703
62340
  // src/session/recent-dirs.ts
@@ -61715,7 +62352,7 @@ function listRecentDirs(store, limit = 50) {
61715
62352
  }
61716
62353
 
61717
62354
  // src/permission/persona-paths.ts
61718
- var path69 = __toESM(require("path"), 1);
62355
+ var path71 = __toESM(require("path"), 1);
61719
62356
  function getAllowedPersonaIds(grants, action) {
61720
62357
  const ids = /* @__PURE__ */ new Set();
61721
62358
  for (const g2 of grants) {
@@ -61728,42 +62365,42 @@ function getAllowedPersonaIds(grants, action) {
61728
62365
  return ids;
61729
62366
  }
61730
62367
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
61731
- const target = path69.resolve(absPath);
62368
+ const target = path71.resolve(absPath);
61732
62369
  if (userWorkDir) {
61733
- const u = path69.resolve(userWorkDir);
61734
- const usep = u.endsWith(path69.sep) ? "" : path69.sep;
62370
+ const u = path71.resolve(userWorkDir);
62371
+ const usep = u.endsWith(path71.sep) ? "" : path71.sep;
61735
62372
  if (target === u || target.startsWith(u + usep)) return true;
61736
62373
  }
61737
- const root = path69.resolve(personaRoot);
61738
- const sep4 = root.endsWith(path69.sep) ? "" : path69.sep;
62374
+ const root = path71.resolve(personaRoot);
62375
+ const sep4 = root.endsWith(path71.sep) ? "" : path71.sep;
61739
62376
  if (!target.startsWith(root + sep4)) return false;
61740
- const rel = path69.relative(root, target);
62377
+ const rel = path71.relative(root, target);
61741
62378
  if (!rel || rel.startsWith("..")) return false;
61742
- const personaId2 = rel.split(path69.sep)[0];
62379
+ const personaId2 = rel.split(path71.sep)[0];
61743
62380
  if (!personaId2) return false;
61744
62381
  const allowed = getAllowedPersonaIds(grants, action);
61745
62382
  if (allowed === "*") return true;
61746
62383
  return allowed.has(personaId2);
61747
62384
  }
61748
62385
  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;
62386
+ const root = path71.resolve(personaRoot);
62387
+ const target = path71.resolve(absPath);
62388
+ const sep4 = root.endsWith(path71.sep) ? "" : path71.sep;
61752
62389
  if (!target.startsWith(root + sep4)) return null;
61753
- const rel = path69.relative(root, target);
62390
+ const rel = path71.relative(root, target);
61754
62391
  if (!rel || rel.startsWith("..")) return null;
61755
- const id = rel.split(path69.sep)[0];
62392
+ const id = rel.split(path71.sep)[0];
61756
62393
  return id || null;
61757
62394
  }
61758
62395
  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;
62396
+ const d = path71.resolve(dir);
62397
+ const t = path71.resolve(absPath);
62398
+ const sep4 = d.endsWith(path71.sep) ? "" : path71.sep;
61762
62399
  return t === d || t.startsWith(d + sep4);
61763
62400
  }
61764
62401
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
61765
62402
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
61766
- return personaIdFromPath(path69.resolve(absPath), personaRoot) === personaId2;
62403
+ return personaIdFromPath(path71.resolve(absPath), personaRoot) === personaId2;
61767
62404
  }
61768
62405
 
61769
62406
  // src/handlers/history.ts
@@ -61816,7 +62453,7 @@ function buildHistoryHandlers(deps) {
61816
62453
  if (!pid) return false;
61817
62454
  return isGuestPathAllowed(
61818
62455
  ctx.grants,
61819
- path70.join(personaRoot, pid),
62456
+ path72.join(personaRoot, pid),
61820
62457
  personaRoot,
61821
62458
  "read",
61822
62459
  userWorkDir
@@ -61828,7 +62465,7 @@ function buildHistoryHandlers(deps) {
61828
62465
  };
61829
62466
  const list = async (frame, _client, ctx) => {
61830
62467
  const args = HistoryListArgs.parse(frame);
61831
- assertGuestPath(ctx, path70.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
62468
+ assertGuestPath(ctx, path72.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
61832
62469
  const sessions = await history.listSessions(args);
61833
62470
  return { response: { type: "history:list", sessions } };
61834
62471
  };
@@ -61876,14 +62513,14 @@ function buildHistoryHandlers(deps) {
61876
62513
  };
61877
62514
  const subagents = async (frame, _client, ctx) => {
61878
62515
  const args = HistorySubagentsArgs.parse(frame);
61879
- assertGuestPath(ctx, path70.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
62516
+ assertGuestPath(ctx, path72.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
61880
62517
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
61881
62518
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
61882
62519
  return { response: { type: "history:subagents", subagents: subs } };
61883
62520
  };
61884
62521
  const subagentRead = async (frame, _client, ctx) => {
61885
62522
  const args = HistorySubagentReadArgs.parse(frame);
61886
- assertGuestPath(ctx, path70.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
62523
+ assertGuestPath(ctx, path72.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
61887
62524
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
61888
62525
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
61889
62526
  return { response: { type: "history:subagent-read", ...res } };
@@ -61893,7 +62530,7 @@ function buildHistoryHandlers(deps) {
61893
62530
  if (ctx?.principal.kind === "guest" && personaRoot) {
61894
62531
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
61895
62532
  const filtered = dirs.filter(
61896
- (d) => isGuestPathAllowed(ctx.grants, path70.resolve(d.cwd), personaRoot, "read", userWorkDir)
62533
+ (d) => isGuestPathAllowed(ctx.grants, path72.resolve(d.cwd), personaRoot, "read", userWorkDir)
61897
62534
  );
61898
62535
  return { response: { type: "history:recentDirs", dirs: filtered } };
61899
62536
  }
@@ -61910,17 +62547,17 @@ function buildHistoryHandlers(deps) {
61910
62547
  }
61911
62548
 
61912
62549
  // src/handlers/projects.ts
61913
- var fs64 = __toESM(require("fs"), 1);
62550
+ var fs66 = __toESM(require("fs"), 1);
61914
62551
  var os21 = __toESM(require("os"), 1);
61915
- var path71 = __toESM(require("path"), 1);
62552
+ var path73 = __toESM(require("path"), 1);
61916
62553
  var import_node_child_process13 = require("child_process");
61917
62554
  init_protocol();
61918
- var DEFAULT_PROJECTS_ROOT = path71.join(os21.homedir(), "Documents", "ChatGPT");
62555
+ var DEFAULT_PROJECTS_ROOT = path73.join(os21.homedir(), "Documents", "ChatGPT");
61919
62556
  function allocateDir(root, name) {
61920
- let candidate = path71.join(root, name);
62557
+ let candidate = path73.join(root, name);
61921
62558
  let n = 2;
61922
- while (fs64.existsSync(candidate)) {
61923
- candidate = path71.join(root, `${name} ${n}`);
62559
+ while (fs66.existsSync(candidate)) {
62560
+ candidate = path73.join(root, `${name} ${n}`);
61924
62561
  n += 1;
61925
62562
  }
61926
62563
  return candidate;
@@ -61948,7 +62585,7 @@ function buildProjectHandlers(deps) {
61948
62585
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
61949
62586
  }
61950
62587
  try {
61951
- if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
62588
+ if (!fs66.statSync(args.path).isDirectory()) throw new Error("not dir");
61952
62589
  } catch {
61953
62590
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
61954
62591
  }
@@ -61964,7 +62601,7 @@ function buildProjectHandlers(deps) {
61964
62601
  let target;
61965
62602
  if (args.path) {
61966
62603
  try {
61967
- if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
62604
+ if (!fs66.statSync(args.path).isDirectory()) throw new Error("not dir");
61968
62605
  } catch {
61969
62606
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
61970
62607
  }
@@ -61972,15 +62609,15 @@ function buildProjectHandlers(deps) {
61972
62609
  } else {
61973
62610
  const name = args.name;
61974
62611
  try {
61975
- fs64.mkdirSync(root, { recursive: true });
62612
+ fs66.mkdirSync(root, { recursive: true });
61976
62613
  target = allocateDir(root, name);
61977
- fs64.mkdirSync(target);
62614
+ fs66.mkdirSync(target);
61978
62615
  } catch (err) {
61979
62616
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
61980
62617
  }
61981
62618
  const git = (0, import_node_child_process13.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
61982
62619
  if (git.status !== 0) {
61983
- fs64.rmSync(target, { recursive: true, force: true });
62620
+ fs66.rmSync(target, { recursive: true, force: true });
61984
62621
  throw new ClawdError(
61985
62622
  ERROR_CODES.INVALID_CWD,
61986
62623
  `git init \u5931\u8D25\uFF08${git.error ? String(git.error) : `exit ${git.status}`}\uFF09: ${target}`
@@ -62005,7 +62642,7 @@ function buildProjectHandlers(deps) {
62005
62642
  }
62006
62643
 
62007
62644
  // src/handlers/workspace.ts
62008
- var path72 = __toESM(require("path"), 1);
62645
+ var path74 = __toESM(require("path"), 1);
62009
62646
  var os22 = __toESM(require("os"), 1);
62010
62647
  init_protocol();
62011
62648
  init_protocol();
@@ -62047,22 +62684,22 @@ function buildWorkspaceHandlers(deps) {
62047
62684
  const args = WorkspaceListArgs.parse(frame);
62048
62685
  const isGuest = ctx?.principal.kind === "guest";
62049
62686
  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;
62687
+ const resolvedCwd = path74.resolve(args.cwd ?? fallbackCwd);
62688
+ const target = args.path ? path74.resolve(resolvedCwd, args.path) : resolvedCwd;
62052
62689
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
62053
62690
  const res = workspace.list({ ...args, cwd: resolvedCwd });
62054
62691
  return { response: { type: "workspace:list", ...res } };
62055
62692
  };
62056
62693
  const read = async (frame, _client, ctx) => {
62057
62694
  const args = WorkspaceReadArgs.parse(frame);
62058
- const target = path72.isAbsolute(args.path) ? path72.resolve(args.path) : path72.resolve(args.cwd, args.path);
62695
+ const target = path74.isAbsolute(args.path) ? path74.resolve(args.path) : path74.resolve(args.cwd, args.path);
62059
62696
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
62060
62697
  const res = workspace.read(args);
62061
62698
  return { response: { type: "workspace:read", ...res } };
62062
62699
  };
62063
62700
  const skillsList = async (frame, _client, ctx) => {
62064
62701
  const args = SkillsListArgs.parse(frame);
62065
- const cwdAbs = path72.resolve(args.cwd);
62702
+ const cwdAbs = path74.resolve(args.cwd);
62066
62703
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
62067
62704
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
62068
62705
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -62074,7 +62711,7 @@ function buildWorkspaceHandlers(deps) {
62074
62711
  };
62075
62712
  const agentsList = async (frame, _client, ctx) => {
62076
62713
  const args = AgentsListArgs.parse(frame);
62077
- const cwdAbs = path72.resolve(args.cwd);
62714
+ const cwdAbs = path74.resolve(args.cwd);
62078
62715
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
62079
62716
  if (args.tool === "codex") {
62080
62717
  return { response: { type: "agents:list", agents: [] } };
@@ -62096,18 +62733,18 @@ function buildWorkspaceHandlers(deps) {
62096
62733
  }
62097
62734
 
62098
62735
  // src/handlers/git.ts
62099
- var path74 = __toESM(require("path"), 1);
62736
+ var path76 = __toESM(require("path"), 1);
62100
62737
  init_protocol();
62101
62738
  init_protocol();
62102
62739
 
62103
62740
  // src/workspace/git.ts
62104
62741
  var import_node_child_process14 = require("child_process");
62105
62742
  var import_node_fs49 = __toESM(require("fs"), 1);
62106
- var import_node_path56 = __toESM(require("path"), 1);
62743
+ var import_node_path58 = __toESM(require("path"), 1);
62107
62744
  var import_node_util = require("util");
62108
62745
  var pexec = (0, import_node_util.promisify)(import_node_child_process14.execFile);
62109
62746
  function normalizePath(p2) {
62110
- const resolved = import_node_path56.default.resolve(p2);
62747
+ const resolved = import_node_path58.default.resolve(p2);
62111
62748
  try {
62112
62749
  return import_node_fs49.default.realpathSync(resolved);
62113
62750
  } catch {
@@ -62183,7 +62820,7 @@ async function listGitBranches(cwd) {
62183
62820
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
62184
62821
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
62185
62822
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
62186
- if (!isGuestPathAllowed(ctx.grants, path74.resolve(cwd), personaRoot, "read", userWorkDir)) {
62823
+ if (!isGuestPathAllowed(ctx.grants, path76.resolve(cwd), personaRoot, "read", userWorkDir)) {
62187
62824
  throw new ClawdError(
62188
62825
  ERROR_CODES.UNAUTHORIZED,
62189
62826
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -62438,7 +63075,7 @@ function upsertPeerContact(args) {
62438
63075
  }
62439
63076
 
62440
63077
  // src/handlers/contact.ts
62441
- function ensureOwner2(ctx) {
63078
+ function ensureOwner3(ctx) {
62442
63079
  if (!ctx || ctx.principal.kind !== "owner") {
62443
63080
  throw new ClawdError(
62444
63081
  ERROR_CODES.UNAUTHORIZED,
@@ -62448,7 +63085,7 @@ function ensureOwner2(ctx) {
62448
63085
  }
62449
63086
  function buildContactHandlers(deps) {
62450
63087
  const list = async (_frame, _client, ctx) => {
62451
- ensureOwner2(ctx);
63088
+ ensureOwner3(ctx);
62452
63089
  return {
62453
63090
  response: {
62454
63091
  type: "contact:list:ok",
@@ -62457,7 +63094,7 @@ function buildContactHandlers(deps) {
62457
63094
  };
62458
63095
  };
62459
63096
  const pin = async (frame, _client, ctx) => {
62460
- ensureOwner2(ctx);
63097
+ ensureOwner3(ctx);
62461
63098
  const args = parseArgs2(ContactPinArgsSchema, frame, "contact:pin");
62462
63099
  const pinnedAt = args.pinned ? deps.now() : null;
62463
63100
  const hit = deps.store.setPin(args.deviceId, pinnedAt);
@@ -62481,7 +63118,7 @@ function buildContactHandlers(deps) {
62481
63118
  };
62482
63119
  };
62483
63120
  const setNote = async (frame, _client, ctx) => {
62484
- ensureOwner2(ctx);
63121
+ ensureOwner3(ctx);
62485
63122
  const args = parseArgs2(ContactSetNoteArgsSchema, frame, "contact:setNote");
62486
63123
  const hit = deps.store.setNote(args.deviceId, args.note);
62487
63124
  if (!hit) {
@@ -62504,13 +63141,13 @@ function buildContactHandlers(deps) {
62504
63141
  };
62505
63142
  };
62506
63143
  const orgPeers = async (_frame, _client, ctx) => {
62507
- ensureOwner2(ctx);
63144
+ ensureOwner3(ctx);
62508
63145
  return {
62509
63146
  response: { type: "org:peers:ok", peers: getCachedOrgPeers() }
62510
63147
  };
62511
63148
  };
62512
63149
  const remove = async (frame, _client, ctx) => {
62513
- ensureOwner2(ctx);
63150
+ ensureOwner3(ctx);
62514
63151
  const args = parseArgs2(ContactRemoveArgsSchema, frame, "contact:remove");
62515
63152
  deps.store.removeByDeviceId(args.deviceId);
62516
63153
  deps.broadcast({
@@ -62584,7 +63221,7 @@ function buildContactHandlers(deps) {
62584
63221
 
62585
63222
  // src/handlers/contact-remote-access.ts
62586
63223
  init_protocol();
62587
- function ensureOwner3(ctx) {
63224
+ function ensureOwner4(ctx) {
62588
63225
  if (!ctx || ctx.principal.kind !== "owner") {
62589
63226
  throw new ClawdError(
62590
63227
  ERROR_CODES.UNAUTHORIZED,
@@ -62594,7 +63231,7 @@ function ensureOwner3(ctx) {
62594
63231
  }
62595
63232
  function buildContactRemoteAccessHandlers(deps) {
62596
63233
  const setRemoteAccess = async (frame, _client, ctx) => {
62597
- ensureOwner3(ctx);
63234
+ ensureOwner4(ctx);
62598
63235
  const args = parseArgs2(ContactSetRemoteAccessArgsSchema, frame, "contact:setRemoteAccess");
62599
63236
  const hit = deps.store.setRemoteAccess(args.deviceId, {
62600
63237
  remoteAccessAllowed: args.remoteAccessAllowed
@@ -62773,6 +63410,17 @@ var METHOD_GRANT_MAP = {
62773
63410
  // ---- visitor:* (访客名单,owner-only) ----
62774
63411
  // owner 看完整访客名单(含没开会话的);guest 不可调(handler 内再 assertOwner 兜底)。
62775
63412
  "visitor:list": ADMIN_ANY,
63413
+ // deploy:*(persona 上云的部署单):全部 owner-only。单据里有履约决策、凭据录入口,
63414
+ // guest 不该看见更不该动。
63415
+ "deploy:start": ADMIN_ANY,
63416
+ "deploy:rescan": ADMIN_ANY,
63417
+ "deploy:list": ADMIN_ANY,
63418
+ "deploy:get": ADMIN_ANY,
63419
+ "deploy:patch": ADMIN_ANY,
63420
+ "deploy:putSecret": ADMIN_ANY,
63421
+ "deploy:reportFinding": ADMIN_ANY,
63422
+ "deploy:finishScan": ADMIN_ANY,
63423
+ "deploy:remove": ADMIN_ANY,
62776
63424
  // ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
62777
63425
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
62778
63426
  // owner 自动通过(ctx 自带 '*':'admin' grant 一切 match);guest 在被授权 persona 内可调。
@@ -63018,21 +63666,21 @@ function computeMethodAccess(args) {
63018
63666
  }
63019
63667
 
63020
63668
  // src/version.ts
63021
- var version = "0.2.445".length > 0 ? "0.2.445" : "dev";
63669
+ var version = "0.2.447".length > 0 ? "0.2.447" : "dev";
63022
63670
 
63023
63671
  // src/cli-probe/probe.ts
63024
- var fs66 = __toESM(require("fs"), 1);
63025
- var path75 = __toESM(require("path"), 1);
63672
+ var fs68 = __toESM(require("fs"), 1);
63673
+ var path77 = __toESM(require("path"), 1);
63026
63674
  var PKG_NAME = "@clawos-dev/clawd";
63027
63675
  var BIN_NAME = "clawd";
63028
63676
  var MAX_PARENT_HOPS = 5;
63029
63677
  function probeGlobalCli(pathEnv) {
63030
63678
  if (!pathEnv) return null;
63031
- for (const dir of pathEnv.split(path75.delimiter)) {
63679
+ for (const dir of pathEnv.split(path77.delimiter)) {
63032
63680
  if (!dir) continue;
63033
63681
  let real;
63034
63682
  try {
63035
- real = fs66.realpathSync(path75.join(dir, BIN_NAME));
63683
+ real = fs68.realpathSync(path77.join(dir, BIN_NAME));
63036
63684
  } catch {
63037
63685
  continue;
63038
63686
  }
@@ -63042,15 +63690,15 @@ function probeGlobalCli(pathEnv) {
63042
63690
  return null;
63043
63691
  }
63044
63692
  function readOwnPackageVersion(entryPath) {
63045
- let dir = path75.dirname(entryPath);
63693
+ let dir = path77.dirname(entryPath);
63046
63694
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
63047
63695
  try {
63048
- const raw = fs66.readFileSync(path75.join(dir, "package.json"), "utf8");
63696
+ const raw = fs68.readFileSync(path77.join(dir, "package.json"), "utf8");
63049
63697
  const pkg = JSON.parse(raw);
63050
63698
  if (pkg.name !== PKG_NAME) return null;
63051
63699
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
63052
63700
  } catch {
63053
- const parent = path75.dirname(dir);
63701
+ const parent = path77.dirname(dir);
63054
63702
  if (parent === dir) return null;
63055
63703
  dir = parent;
63056
63704
  }
@@ -63222,7 +63870,7 @@ function buildPersonaHandlers(deps) {
63222
63870
  }
63223
63871
 
63224
63872
  // src/handlers/attachment.ts
63225
- var import_node_path57 = __toESM(require("path"), 1);
63873
+ var import_node_path59 = __toESM(require("path"), 1);
63226
63874
  init_protocol();
63227
63875
  init_protocol();
63228
63876
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -63302,12 +63950,12 @@ function buildAttachmentHandlers(deps) {
63302
63950
  `session ${args.sessionId} scope unresolved`
63303
63951
  );
63304
63952
  }
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);
63953
+ const cwdAbs = import_node_path59.default.resolve(sessionFile.cwd);
63954
+ 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
63955
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
63308
63956
  const entries = deps.groupFileStore.list(scope, args.sessionId);
63309
63957
  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);
63958
+ 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
63959
  return storedAbs === candidateAbs && !e.stale;
63312
63960
  });
63313
63961
  if (!entry) {
@@ -63332,7 +63980,7 @@ function buildAttachmentHandlers(deps) {
63332
63980
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
63333
63981
  const f = deps.sessionStore.read(sessionId);
63334
63982
  if (!f) return;
63335
- assertGuestAttachmentPath(ctx, import_node_path57.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
63983
+ assertGuestAttachmentPath(ctx, import_node_path59.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
63336
63984
  }
63337
63985
  const groupAdd = async (frame, _client, ctx) => {
63338
63986
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -63347,8 +63995,8 @@ function buildAttachmentHandlers(deps) {
63347
63995
  if (!scope) {
63348
63996
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
63349
63997
  }
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);
63998
+ const cwdAbs = import_node_path59.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
63999
+ 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
64000
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
63353
64001
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
63354
64002
  const size = 0;
@@ -63406,21 +64054,21 @@ function buildAttachmentHandlers(deps) {
63406
64054
  }
63407
64055
 
63408
64056
  // src/handlers/extension.ts
63409
- var import_promises12 = __toESM(require("fs/promises"), 1);
63410
- var import_node_path62 = __toESM(require("path"), 1);
64057
+ var import_promises14 = __toESM(require("fs/promises"), 1);
64058
+ var import_node_path64 = __toESM(require("path"), 1);
63411
64059
  init_protocol();
63412
64060
 
63413
64061
  // src/extension/bundle-zip.ts
63414
- var import_promises9 = __toESM(require("fs/promises"), 1);
63415
- var import_node_path58 = __toESM(require("path"), 1);
64062
+ var import_promises11 = __toESM(require("fs/promises"), 1);
64063
+ var import_node_path60 = __toESM(require("path"), 1);
63416
64064
  var import_node_crypto17 = __toESM(require("crypto"), 1);
63417
64065
  var import_jszip2 = __toESM(require_lib3(), 1);
63418
64066
  async function bundleExtensionDir(dir) {
63419
64067
  const entries = await listFilesSorted(dir);
63420
64068
  const zip = new import_jszip2.default();
63421
64069
  for (const rel of entries) {
63422
- const abs = import_node_path58.default.join(dir, rel);
63423
- const content = await import_promises9.default.readFile(abs);
64070
+ const abs = import_node_path60.default.join(dir, rel);
64071
+ const content = await import_promises11.default.readFile(abs);
63424
64072
  zip.file(rel, content, { date: FIXED_DATE });
63425
64073
  }
63426
64074
  const buffer = await zip.generateAsync({
@@ -63440,8 +64088,8 @@ async function listFilesSorted(rootDir) {
63440
64088
  return out;
63441
64089
  }
63442
64090
  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 });
64091
+ const dirAbs = import_node_path60.default.join(absRoot, relPrefix);
64092
+ const entries = await import_promises11.default.readdir(dirAbs, { withFileTypes: true });
63445
64093
  for (const e of entries) {
63446
64094
  if (IGNORE_BASENAMES.has(e.name)) continue;
63447
64095
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -63493,26 +64141,26 @@ function computePublishCheck(args) {
63493
64141
  }
63494
64142
 
63495
64143
  // src/extension/install-flow.ts
63496
- var import_promises10 = __toESM(require("fs/promises"), 1);
63497
- var import_node_path60 = __toESM(require("path"), 1);
64144
+ var import_promises12 = __toESM(require("fs/promises"), 1);
64145
+ var import_node_path62 = __toESM(require("path"), 1);
63498
64146
  var import_node_os22 = __toESM(require("os"), 1);
63499
64147
  var import_node_crypto18 = __toESM(require("crypto"), 1);
63500
64148
  var import_jszip3 = __toESM(require_lib3(), 1);
63501
64149
 
63502
64150
  // src/extension/paths.ts
63503
64151
  var import_node_os21 = __toESM(require("os"), 1);
63504
- var import_node_path59 = __toESM(require("path"), 1);
64152
+ var import_node_path61 = __toESM(require("path"), 1);
63505
64153
  function clawdHomeRoot(override) {
63506
- return override ?? process.env.CLAWD_HOME ?? import_node_path59.default.join(import_node_os21.default.homedir(), ".clawd");
64154
+ return override ?? process.env.CLAWD_HOME ?? import_node_path61.default.join(import_node_os21.default.homedir(), ".clawd");
63507
64155
  }
63508
64156
  function extensionsRoot(override) {
63509
- return import_node_path59.default.join(clawdHomeRoot(override), "extensions");
64157
+ return import_node_path61.default.join(clawdHomeRoot(override), "extensions");
63510
64158
  }
63511
64159
  function publishedChannelsFile(override) {
63512
- return import_node_path59.default.join(clawdHomeRoot(override), "extensions-published.json");
64160
+ return import_node_path61.default.join(clawdHomeRoot(override), "extensions-published.json");
63513
64161
  }
63514
64162
  function bundleCacheRoot(override) {
63515
- return import_node_path59.default.join(clawdHomeRoot(override), "extension-bundles");
64163
+ return import_node_path61.default.join(clawdHomeRoot(override), "extension-bundles");
63516
64164
  }
63517
64165
 
63518
64166
  // src/extension/install-flow.ts
@@ -63539,7 +64187,7 @@ async function installFromChannel(args, deps) {
63539
64187
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
63540
64188
  }
63541
64189
  for (const name of Object.keys(zip.files)) {
63542
- if (name.includes("..") || name.startsWith("/") || import_node_path60.default.isAbsolute(name)) {
64190
+ if (name.includes("..") || name.startsWith("/") || import_node_path62.default.isAbsolute(name)) {
63543
64191
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
63544
64192
  }
63545
64193
  }
@@ -63571,10 +64219,10 @@ async function installFromChannel(args, deps) {
63571
64219
  );
63572
64220
  }
63573
64221
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
63574
- const destDir = import_node_path60.default.join(deps.extensionsRoot, localExtId);
64222
+ const destDir = import_node_path62.default.join(deps.extensionsRoot, localExtId);
63575
64223
  let destExists = false;
63576
64224
  try {
63577
- await import_promises10.default.access(destDir);
64225
+ await import_promises12.default.access(destDir);
63578
64226
  destExists = true;
63579
64227
  } catch {
63580
64228
  }
@@ -63584,28 +64232,28 @@ async function installFromChannel(args, deps) {
63584
64232
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
63585
64233
  );
63586
64234
  }
63587
- const stage = await import_promises10.default.mkdtemp(
63588
- import_node_path60.default.join(import_node_os22.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
64235
+ const stage = await import_promises12.default.mkdtemp(
64236
+ import_node_path62.default.join(import_node_os22.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
63589
64237
  );
63590
64238
  try {
63591
64239
  for (const [name, entry] of Object.entries(zip.files)) {
63592
- const dest = import_node_path60.default.join(stage, name);
64240
+ const dest = import_node_path62.default.join(stage, name);
63593
64241
  if (entry.dir) {
63594
- await import_promises10.default.mkdir(dest, { recursive: true });
64242
+ await import_promises12.default.mkdir(dest, { recursive: true });
63595
64243
  continue;
63596
64244
  }
63597
- await import_promises10.default.mkdir(import_node_path60.default.dirname(dest), { recursive: true });
64245
+ await import_promises12.default.mkdir(import_node_path62.default.dirname(dest), { recursive: true });
63598
64246
  if (name === "manifest.json") {
63599
64247
  const rewritten = { ...parsed.data, id: localExtId };
63600
- await import_promises10.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64248
+ await import_promises12.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
63601
64249
  } else {
63602
- await import_promises10.default.writeFile(dest, await entry.async("nodebuffer"));
64250
+ await import_promises12.default.writeFile(dest, await entry.async("nodebuffer"));
63603
64251
  }
63604
64252
  }
63605
- await import_promises10.default.mkdir(deps.extensionsRoot, { recursive: true });
63606
- await import_promises10.default.rename(stage, destDir);
64253
+ await import_promises12.default.mkdir(deps.extensionsRoot, { recursive: true });
64254
+ await import_promises12.default.rename(stage, destDir);
63607
64255
  } catch (e) {
63608
- await import_promises10.default.rm(stage, { recursive: true, force: true }).catch(() => {
64256
+ await import_promises12.default.rm(stage, { recursive: true, force: true }).catch(() => {
63609
64257
  });
63610
64258
  throw e;
63611
64259
  }
@@ -63614,8 +64262,8 @@ async function installFromChannel(args, deps) {
63614
64262
  }
63615
64263
 
63616
64264
  // src/extension/update-flow.ts
63617
- var import_promises11 = __toESM(require("fs/promises"), 1);
63618
- var import_node_path61 = __toESM(require("path"), 1);
64265
+ var import_promises13 = __toESM(require("fs/promises"), 1);
64266
+ var import_node_path63 = __toESM(require("path"), 1);
63619
64267
  var import_node_os23 = __toESM(require("os"), 1);
63620
64268
  var import_node_crypto19 = __toESM(require("crypto"), 1);
63621
64269
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -63632,11 +64280,11 @@ async function updateFromChannel(args, deps) {
63632
64280
  channelRef.extId,
63633
64281
  channelRef.ownerPrincipalId
63634
64282
  );
63635
- const liveDir = import_node_path61.default.join(deps.extensionsRoot, localExtId);
64283
+ const liveDir = import_node_path63.default.join(deps.extensionsRoot, localExtId);
63636
64284
  const prevDir = `${liveDir}.prev`;
63637
64285
  let existingVersion;
63638
64286
  try {
63639
- const raw = await import_promises11.default.readFile(import_node_path61.default.join(liveDir, "manifest.json"), "utf8");
64287
+ const raw = await import_promises13.default.readFile(import_node_path63.default.join(liveDir, "manifest.json"), "utf8");
63640
64288
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
63641
64289
  if (!parsed2.success) {
63642
64290
  throw new UpdateError(
@@ -63669,7 +64317,7 @@ async function updateFromChannel(args, deps) {
63669
64317
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
63670
64318
  }
63671
64319
  for (const name of Object.keys(zip.files)) {
63672
- if (name.includes("..") || name.startsWith("/") || import_node_path61.default.isAbsolute(name)) {
64320
+ if (name.includes("..") || name.startsWith("/") || import_node_path63.default.isAbsolute(name)) {
63673
64321
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
63674
64322
  }
63675
64323
  }
@@ -63701,31 +64349,31 @@ async function updateFromChannel(args, deps) {
63701
64349
  );
63702
64350
  }
63703
64351
  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}-`)
64352
+ await import_promises13.default.rm(prevDir, { recursive: true, force: true });
64353
+ await import_promises13.default.rename(liveDir, prevDir);
64354
+ const stage = await import_promises13.default.mkdtemp(
64355
+ import_node_path63.default.join(import_node_os23.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
63708
64356
  );
63709
64357
  try {
63710
64358
  for (const [name, entry] of Object.entries(zip.files)) {
63711
- const dest = import_node_path61.default.join(stage, name);
64359
+ const dest = import_node_path63.default.join(stage, name);
63712
64360
  if (entry.dir) {
63713
- await import_promises11.default.mkdir(dest, { recursive: true });
64361
+ await import_promises13.default.mkdir(dest, { recursive: true });
63714
64362
  continue;
63715
64363
  }
63716
- await import_promises11.default.mkdir(import_node_path61.default.dirname(dest), { recursive: true });
64364
+ await import_promises13.default.mkdir(import_node_path63.default.dirname(dest), { recursive: true });
63717
64365
  if (name === "manifest.json") {
63718
64366
  const rewritten = { ...parsed.data, id: localExtId };
63719
- await import_promises11.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
64367
+ await import_promises13.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
63720
64368
  } else {
63721
- await import_promises11.default.writeFile(dest, await entry.async("nodebuffer"));
64369
+ await import_promises13.default.writeFile(dest, await entry.async("nodebuffer"));
63722
64370
  }
63723
64371
  }
63724
- await import_promises11.default.rename(stage, liveDir);
64372
+ await import_promises13.default.rename(stage, liveDir);
63725
64373
  } catch (e) {
63726
- await import_promises11.default.rm(stage, { recursive: true, force: true }).catch(() => {
64374
+ await import_promises13.default.rm(stage, { recursive: true, force: true }).catch(() => {
63727
64375
  });
63728
- await import_promises11.default.rename(prevDir, liveDir).catch(() => {
64376
+ await import_promises13.default.rename(prevDir, liveDir).catch(() => {
63729
64377
  });
63730
64378
  await deps.runtime.open(localExtId).catch(() => {
63731
64379
  });
@@ -63747,7 +64395,7 @@ async function updateFromChannel(args, deps) {
63747
64395
  reason: e.message
63748
64396
  };
63749
64397
  }
63750
- await import_promises11.default.rm(prevDir, { recursive: true, force: true });
64398
+ await import_promises13.default.rm(prevDir, { recursive: true, force: true });
63751
64399
  return {
63752
64400
  kind: "updated",
63753
64401
  extId: localExtId,
@@ -63755,9 +64403,9 @@ async function updateFromChannel(args, deps) {
63755
64403
  };
63756
64404
  }
63757
64405
  async function rollback(deps, localExtId, liveDir, prevDir) {
63758
- await import_promises11.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
64406
+ await import_promises13.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
63759
64407
  });
63760
- await import_promises11.default.rename(prevDir, liveDir).catch(() => {
64408
+ await import_promises13.default.rename(prevDir, liveDir).catch(() => {
63761
64409
  });
63762
64410
  await deps.runtime.open(localExtId).catch(() => {
63763
64411
  });
@@ -63780,18 +64428,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
63780
64428
  );
63781
64429
  }
63782
64430
  }
63783
- const manifestPath = import_node_path62.default.join(root, extId, "manifest.json");
64431
+ const manifestPath = import_node_path64.default.join(root, extId, "manifest.json");
63784
64432
  const manifest = await readManifest(root, extId);
63785
64433
  const next = { ...manifest, version: newVersion };
63786
64434
  const tmp = `${manifestPath}.tmp`;
63787
- await import_promises12.default.writeFile(tmp, JSON.stringify(next, null, 2));
63788
- await import_promises12.default.rename(tmp, manifestPath);
64435
+ await import_promises14.default.writeFile(tmp, JSON.stringify(next, null, 2));
64436
+ await import_promises14.default.rename(tmp, manifestPath);
63789
64437
  }
63790
64438
  async function readManifest(root, extId) {
63791
- const file = import_node_path62.default.join(root, extId, "manifest.json");
64439
+ const file = import_node_path64.default.join(root, extId, "manifest.json");
63792
64440
  let raw;
63793
64441
  try {
63794
- raw = await import_promises12.default.readFile(file, "utf8");
64442
+ raw = await import_promises14.default.readFile(file, "utf8");
63795
64443
  } catch (e) {
63796
64444
  if (e.code === "ENOENT") {
63797
64445
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -63872,7 +64520,7 @@ function buildExtensionHandlers(deps) {
63872
64520
  };
63873
64521
  async function buildSnapshotMeta(extId) {
63874
64522
  const manifest = await readManifest(deps.root, extId);
63875
- const { sha256, buffer } = await bundleExtensionDir(import_node_path62.default.join(deps.root, extId));
64523
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path64.default.join(deps.root, extId));
63876
64524
  return { manifest, contentHash: sha256, buffer };
63877
64525
  }
63878
64526
  const publish = async (frame, _client, ctx) => {
@@ -64049,7 +64697,7 @@ function buildExtensionHandlers(deps) {
64049
64697
  // src/app-builder/project-store.ts
64050
64698
  var import_node_fs50 = require("fs");
64051
64699
  var import_node_child_process15 = require("child_process");
64052
- var import_node_path63 = require("path");
64700
+ var import_node_path65 = require("path");
64053
64701
  init_protocol();
64054
64702
  var PROJECTS_DIR = "projects";
64055
64703
  var META_FILE = ".clawd-project.json";
@@ -64063,14 +64711,14 @@ var ProjectStore = class {
64063
64711
  root;
64064
64712
  /** projects/<name>/.clawd-project.json 路径 */
64065
64713
  metaPath(name) {
64066
- return (0, import_node_path63.join)(this.projectsRoot(), name, META_FILE);
64714
+ return (0, import_node_path65.join)(this.projectsRoot(), name, META_FILE);
64067
64715
  }
64068
64716
  /** projects/<name>/ 目录路径(cwd 用) */
64069
64717
  projectDir(name) {
64070
- return (0, import_node_path63.join)(this.projectsRoot(), name);
64718
+ return (0, import_node_path65.join)(this.projectsRoot(), name);
64071
64719
  }
64072
64720
  projectsRoot() {
64073
- return (0, import_node_path63.join)(this.root, PROJECTS_DIR);
64721
+ return (0, import_node_path65.join)(this.root, PROJECTS_DIR);
64074
64722
  }
64075
64723
  async list() {
64076
64724
  let entries;
@@ -64373,7 +65021,7 @@ var PublishJobRegistry = class {
64373
65021
  // src/app-builder/publish-job-runner.ts
64374
65022
  var import_node_child_process17 = require("child_process");
64375
65023
  var import_node_fs51 = require("fs");
64376
- var import_node_path64 = require("path");
65024
+ var import_node_path66 = require("path");
64377
65025
 
64378
65026
  // src/app-builder/publish-stage-parser.ts
64379
65027
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -64405,7 +65053,7 @@ async function startPublishJob(deps, args) {
64405
65053
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
64406
65054
  }
64407
65055
  const projDir = projectDir(args.name);
64408
- const logPath = (0, import_node_path64.join)(projDir, ".publish.log");
65056
+ const logPath = (0, import_node_path66.join)(projDir, ".publish.log");
64409
65057
  let logStream = null;
64410
65058
  try {
64411
65059
  logStream = (0, import_node_fs51.createWriteStream)(logPath, { flags: "w" });
@@ -64665,7 +65313,7 @@ async function recoverInterruptedJobs(deps) {
64665
65313
 
64666
65314
  // src/handlers/app-builder.ts
64667
65315
  init_protocol();
64668
- var import_node_path65 = require("path");
65316
+ var import_node_path67 = require("path");
64669
65317
  var import_node_fs52 = require("fs");
64670
65318
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
64671
65319
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -64816,8 +65464,8 @@ function buildAppBuilderHandlers(deps) {
64816
65464
  const project = await userStore.create(f.name, reservedPorts);
64817
65465
  try {
64818
65466
  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");
65467
+ const templateSrcDir = (0, import_node_path67.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
65468
+ const scaffoldScript = (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
64821
65469
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
64822
65470
  deps.logger?.info("app-builder.scaffold.done", {
64823
65471
  name: project.name,
@@ -65021,7 +65669,7 @@ function buildAppBuilderHandlers(deps) {
65021
65669
  await userStore.clearPublishJob(args.name);
65022
65670
  }
65023
65671
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
65024
- const scriptPath = (0, import_node_path65.join)(deps.deployKitRoot, "scripts", "publish.sh");
65672
+ const scriptPath = (0, import_node_path67.join)(deps.deployKitRoot, "scripts", "publish.sh");
65025
65673
  deps.logger?.info("app-builder.publish.start", {
65026
65674
  name: args.name,
65027
65675
  sessionId: boundSession.sessionId,
@@ -65250,7 +65898,7 @@ function joinLines(records, lineMeta) {
65250
65898
  return out;
65251
65899
  }
65252
65900
  function buildTopicHandlers(deps) {
65253
- const mustGet = (topicId) => {
65901
+ const mustGet2 = (topicId) => {
65254
65902
  const t = deps.topicStore.get(topicId);
65255
65903
  if (!t) throw new ClawdError(ERROR_CODES.INVALID_PARAM, `topic not found: ${topicId}`);
65256
65904
  return t;
@@ -65283,7 +65931,7 @@ function buildTopicHandlers(deps) {
65283
65931
  },
65284
65932
  "topic:get": async (frame) => {
65285
65933
  const args = TopicGetArgsSchema.parse(frame);
65286
- const topic = args.topicId ? mustGet(args.topicId) : deps.topicStore.getByMasterSession(args.sessionId);
65934
+ const topic = args.topicId ? mustGet2(args.topicId) : deps.topicStore.getByMasterSession(args.sessionId);
65287
65935
  if (!topic) {
65288
65936
  throw new ClawdError(
65289
65937
  ERROR_CODES.INVALID_PARAM,
@@ -65314,7 +65962,7 @@ function buildTopicHandlers(deps) {
65314
65962
  },
65315
65963
  "topic:setPlan": async (frame) => {
65316
65964
  const args = TopicSetPlanArgsSchema.parse(frame);
65317
- mustGet(args.topicId);
65965
+ mustGet2(args.topicId);
65318
65966
  const topic = deps.topicStore.setPlan(args.topicId, {
65319
65967
  ...args.title ? { title: args.title } : {},
65320
65968
  goal: args.goal,
@@ -65326,7 +65974,7 @@ function buildTopicHandlers(deps) {
65326
65974
  },
65327
65975
  "topic:append": async (frame) => {
65328
65976
  const args = TopicAppendArgsSchema.parse(frame);
65329
- const topic = mustGet(args.topicId);
65977
+ const topic = mustGet2(args.topicId);
65330
65978
  deps.topicStore.appendActivity(args.topicId, {
65331
65979
  actor: "master",
65332
65980
  action: args.action,
@@ -65339,7 +65987,7 @@ function buildTopicHandlers(deps) {
65339
65987
  },
65340
65988
  "topic:reject": async (frame) => {
65341
65989
  const args = TopicRejectArgsSchema.parse(frame);
65342
- const topic = mustGet(args.topicId);
65990
+ const topic = mustGet2(args.topicId);
65343
65991
  const { rejectCount } = deps.topicStore.bumpReject(args.topicId, args.lineId);
65344
65992
  if (topic.state === "done") deps.topicStore.setState(args.topicId, "running");
65345
65993
  deps.topicStore.appendActivity(args.topicId, {
@@ -65358,7 +66006,7 @@ function buildTopicHandlers(deps) {
65358
66006
  },
65359
66007
  "topic:accept": async (frame) => {
65360
66008
  const args = TopicAcceptArgsSchema.parse(frame);
65361
- const topic = mustGet(args.topicId);
66009
+ const topic = mustGet2(args.topicId);
65362
66010
  if (!linesOf(topic).some((l) => l.lineId === args.lineId)) {
65363
66011
  throw new ClawdError(
65364
66012
  ERROR_CODES.INVALID_PARAM,
@@ -65382,11 +66030,11 @@ function buildTopicHandlers(deps) {
65382
66030
  reason: args.reason,
65383
66031
  ...args.artifacts ? { artifacts: args.artifacts } : {}
65384
66032
  });
65385
- const lines = linesOf(mustGet(args.topicId));
66033
+ const lines = linesOf(mustGet2(args.topicId));
65386
66034
  const acceptedLines = lines.filter((l) => l.accepted).length;
65387
66035
  const allAccepted = lines.length > 0 && acceptedLines === lines.length;
65388
66036
  if (allAccepted) deps.topicStore.setState(args.topicId, "done");
65389
- const overrides = Object.values(mustGet(args.topicId).lineMeta).reduce(
66037
+ const overrides = Object.values(mustGet2(args.topicId).lineMeta).reduce(
65390
66038
  (n, m2) => n + (m2.overrideCount ?? 0),
65391
66039
  0
65392
66040
  );
@@ -65403,21 +66051,21 @@ function buildTopicHandlers(deps) {
65403
66051
  },
65404
66052
  "topic:close": async (frame) => {
65405
66053
  const args = TopicCloseArgsSchema.parse(frame);
65406
- mustGet(args.topicId);
66054
+ mustGet2(args.topicId);
65407
66055
  const topic = deps.topicStore.setState(args.topicId, args.state);
65408
66056
  announceChanged(topic);
65409
66057
  return { response: TopicResultSchema.parse({ topic }) };
65410
66058
  },
65411
66059
  "topic:rename": async (frame) => {
65412
66060
  const args = TopicRenameArgsSchema.parse(frame);
65413
- mustGet(args.topicId);
66061
+ mustGet2(args.topicId);
65414
66062
  const topic = deps.topicStore.rename(args.topicId, args.title);
65415
66063
  announceChanged(topic);
65416
66064
  return { response: TopicResultSchema.parse({ topic }) };
65417
66065
  },
65418
66066
  "topic:delete": async (frame) => {
65419
66067
  const { topicId } = TopicDeleteArgsSchema.parse(frame);
65420
- const topic = mustGet(topicId);
66068
+ const topic = mustGet2(topicId);
65421
66069
  const { removed, broadcast } = deps.deleteSession(topic.masterSessionId);
65422
66070
  const removedWorkerSessionIds = [];
65423
66071
  const allBroadcast = [...broadcast];
@@ -65452,7 +66100,7 @@ function buildTopicHandlers(deps) {
65452
66100
  init_protocol();
65453
66101
 
65454
66102
  // src/channel/authority.ts
65455
- var import_promises13 = __toESM(require("fs/promises"), 1);
66103
+ var import_promises15 = __toESM(require("fs/promises"), 1);
65456
66104
  init_protocol();
65457
66105
  var DEFAULT_AUTHORITY_RULES = [
65458
66106
  { id: "outbound-message", desc: "\u4EE5\u8001\u677F\u540D\u4E49\u7ED9\u5176\u4ED6\u4EBA\u53D1\u6D88\u606F\uFF08IM/\u90AE\u4EF6\uFF09", action: "ask" },
@@ -65470,7 +66118,7 @@ async function resolveAuthority(args) {
65470
66118
  let source;
65471
66119
  let raw = null;
65472
66120
  try {
65473
- raw = await import_promises13.default.readFile(args.tablePath, "utf8");
66121
+ raw = await import_promises15.default.readFile(args.tablePath, "utf8");
65474
66122
  } catch (e) {
65475
66123
  if (e.code !== "ENOENT") {
65476
66124
  return askBecause(`\u6388\u6743\u8BBE\u5B9A\u8BFB\u4E0D\u51FA\u6765\uFF08${args.tablePath}\uFF09\uFF1A${e.message}`);
@@ -65755,7 +66403,7 @@ function buildGithubHandlers(deps) {
65755
66403
 
65756
66404
  // src/handlers/visitor.ts
65757
66405
  init_protocol();
65758
- function ensureOwner4(ctx) {
66406
+ function ensureOwner5(ctx) {
65759
66407
  if (!ctx || ctx.principal.kind !== "owner") {
65760
66408
  throw new ClawdError(
65761
66409
  ERROR_CODES.UNAUTHORIZED,
@@ -65765,7 +66413,7 @@ function ensureOwner4(ctx) {
65765
66413
  }
65766
66414
  function buildVisitorHandlers(deps) {
65767
66415
  const list = async (_frame, _client, ctx) => {
65768
- ensureOwner4(ctx);
66416
+ ensureOwner5(ctx);
65769
66417
  return {
65770
66418
  response: {
65771
66419
  type: "visitor:list",
@@ -65779,12 +66427,12 @@ function buildVisitorHandlers(deps) {
65779
66427
  }
65780
66428
 
65781
66429
  // src/extension/registry.ts
65782
- var import_promises14 = __toESM(require("fs/promises"), 1);
65783
- var import_node_path66 = __toESM(require("path"), 1);
66430
+ var import_promises16 = __toESM(require("fs/promises"), 1);
66431
+ var import_node_path68 = __toESM(require("path"), 1);
65784
66432
  async function loadAll(root) {
65785
66433
  let entries;
65786
66434
  try {
65787
- entries = await import_promises14.default.readdir(root, { withFileTypes: true });
66435
+ entries = await import_promises16.default.readdir(root, { withFileTypes: true });
65788
66436
  } catch (e) {
65789
66437
  if (e.code === "ENOENT") return [];
65790
66438
  throw e;
@@ -65793,16 +66441,16 @@ async function loadAll(root) {
65793
66441
  for (const ent of entries) {
65794
66442
  if (!ent.isDirectory()) continue;
65795
66443
  if (ent.name.startsWith(".")) continue;
65796
- records.push(await loadOne(import_node_path66.default.join(root, ent.name), ent.name));
66444
+ records.push(await loadOne(import_node_path68.default.join(root, ent.name), ent.name));
65797
66445
  }
65798
66446
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
65799
66447
  return records;
65800
66448
  }
65801
66449
  async function loadOne(dir, dirName) {
65802
- const manifestPath = import_node_path66.default.join(dir, "manifest.json");
66450
+ const manifestPath = import_node_path68.default.join(dir, "manifest.json");
65803
66451
  let raw;
65804
66452
  try {
65805
- raw = await import_promises14.default.readFile(manifestPath, "utf8");
66453
+ raw = await import_promises16.default.readFile(manifestPath, "utf8");
65806
66454
  } catch {
65807
66455
  return {
65808
66456
  extId: dirName,
@@ -65843,8 +66491,8 @@ async function loadOne(dir, dirName) {
65843
66491
  }
65844
66492
 
65845
66493
  // src/extension/uninstall.ts
65846
- var import_promises15 = __toESM(require("fs/promises"), 1);
65847
- var import_node_path67 = __toESM(require("path"), 1);
66494
+ var import_promises17 = __toESM(require("fs/promises"), 1);
66495
+ var import_node_path69 = __toESM(require("path"), 1);
65848
66496
  var UninstallError = class extends Error {
65849
66497
  constructor(code, message) {
65850
66498
  super(message);
@@ -65853,14 +66501,14 @@ var UninstallError = class extends Error {
65853
66501
  code;
65854
66502
  };
65855
66503
  async function uninstall(deps) {
65856
- const dir = import_node_path67.default.join(deps.root, deps.extId);
66504
+ const dir = import_node_path69.default.join(deps.root, deps.extId);
65857
66505
  try {
65858
- await import_promises15.default.access(dir);
66506
+ await import_promises17.default.access(dir);
65859
66507
  } catch {
65860
66508
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
65861
66509
  }
65862
66510
  await deps.runtime.close(deps.extId);
65863
- await import_promises15.default.rm(dir, { recursive: true, force: true });
66511
+ await import_promises17.default.rm(dir, { recursive: true, force: true });
65864
66512
  }
65865
66513
 
65866
66514
  // src/handlers/index.ts
@@ -66086,7 +66734,7 @@ function buildMethodHandlers(deps) {
66086
66734
  broadcast: deps.broadcastToOwners
66087
66735
  }),
66088
66736
  ...buildMasterHandlers({
66089
- authorityTablePath: import_node_path68.default.join(deps.masterDataDir, "master-authority.json")
66737
+ authorityTablePath: import_node_path70.default.join(deps.masterDataDir, "master-authority.json")
66090
66738
  }),
66091
66739
  ...buildTopicHandlers({
66092
66740
  topicStore: deps.topicStore,
@@ -66132,8 +66780,8 @@ function refreshPathFromLoginShell() {
66132
66780
  timeout: 3e3,
66133
66781
  stdio: ["ignore", "pipe", "ignore"]
66134
66782
  });
66135
- const path91 = out.trim();
66136
- if (path91) process.env.PATH = path91;
66783
+ const path93 = out.trim();
66784
+ if (path93) process.env.PATH = path93;
66137
66785
  } catch {
66138
66786
  }
66139
66787
  }
@@ -66547,8 +67195,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
66547
67195
 
66548
67196
  // src/extension/runtime.ts
66549
67197
  var import_node_child_process22 = require("child_process");
66550
- var import_node_path69 = __toESM(require("path"), 1);
66551
- var import_promises16 = require("timers/promises");
67198
+ var import_node_path71 = __toESM(require("path"), 1);
67199
+ var import_promises18 = require("timers/promises");
66552
67200
 
66553
67201
  // src/extension/port-allocator.ts
66554
67202
  var import_node_net2 = __toESM(require("net"), 1);
@@ -66648,7 +67296,7 @@ var Runtime = class {
66648
67296
  /\$CLAWOS_EXT_PORT/g,
66649
67297
  String(port)
66650
67298
  );
66651
- const dir = import_node_path69.default.join(this.root, extId);
67299
+ const dir = import_node_path71.default.join(this.root, extId);
66652
67300
  const env = {
66653
67301
  ...process.env,
66654
67302
  CLAWOS_EXT_PORT: String(port),
@@ -66724,7 +67372,7 @@ ${handle.stderrTail}`
66724
67372
  if (res.ok) return;
66725
67373
  } catch {
66726
67374
  }
66727
- await (0, import_promises16.setTimeout)(this.healthzIntervalMs);
67375
+ await (0, import_promises18.setTimeout)(this.healthzIntervalMs);
66728
67376
  }
66729
67377
  throw new RuntimeError(
66730
67378
  "HEALTHZ_FAILED",
@@ -66749,7 +67397,7 @@ ${handle.stderrTail}`
66749
67397
  };
66750
67398
  killGroup("SIGTERM");
66751
67399
  const exited = new Promise((resolve9) => child.once("exit", () => resolve9()));
66752
- const timed = (0, import_promises16.setTimeout)(5e3).then(() => "timeout");
67400
+ const timed = (0, import_promises18.setTimeout)(5e3).then(() => "timeout");
66753
67401
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
66754
67402
  if (winner === "timeout" && child.exitCode === null) {
66755
67403
  killGroup("SIGKILL");
@@ -66759,8 +67407,8 @@ ${handle.stderrTail}`
66759
67407
  };
66760
67408
 
66761
67409
  // src/extension/published-channels.ts
66762
- var import_promises17 = __toESM(require("fs/promises"), 1);
66763
- var import_node_path70 = __toESM(require("path"), 1);
67410
+ var import_promises19 = __toESM(require("fs/promises"), 1);
67411
+ var import_node_path72 = __toESM(require("path"), 1);
66764
67412
  init_zod();
66765
67413
  var PublishedChannelsError = class extends Error {
66766
67414
  constructor(code, message) {
@@ -66790,7 +67438,7 @@ var PublishedChannelStore = class {
66790
67438
  this.channels.clear();
66791
67439
  let raw;
66792
67440
  try {
66793
- raw = await import_promises17.default.readFile(this.filePath, "utf8");
67441
+ raw = await import_promises19.default.readFile(this.filePath, "utf8");
66794
67442
  } catch (e) {
66795
67443
  if (e.code === "ENOENT") {
66796
67444
  this.loaded = true;
@@ -66859,15 +67507,15 @@ var PublishedChannelStore = class {
66859
67507
  )
66860
67508
  };
66861
67509
  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);
67510
+ await import_promises19.default.mkdir(import_node_path72.default.dirname(this.filePath), { recursive: true });
67511
+ await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
67512
+ await import_promises19.default.rename(tmp, this.filePath);
66865
67513
  }
66866
67514
  };
66867
67515
 
66868
67516
  // src/extension/bundle-cache.ts
66869
- var import_promises18 = __toESM(require("fs/promises"), 1);
66870
- var import_node_path71 = __toESM(require("path"), 1);
67517
+ var import_promises20 = __toESM(require("fs/promises"), 1);
67518
+ var import_node_path73 = __toESM(require("path"), 1);
66871
67519
  var BundleCache = class {
66872
67520
  constructor(rootDir) {
66873
67521
  this.rootDir = rootDir;
@@ -66875,17 +67523,17 @@ var BundleCache = class {
66875
67523
  rootDir;
66876
67524
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
66877
67525
  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`);
67526
+ await import_promises20.default.mkdir(this.rootDir, { recursive: true });
67527
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
66880
67528
  const tmp = `${file}.tmp`;
66881
- await import_promises18.default.writeFile(tmp, buffer, { mode: 384 });
66882
- await import_promises18.default.rename(tmp, file);
67529
+ await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
67530
+ await import_promises20.default.rename(tmp, file);
66883
67531
  }
66884
67532
  /** Returns the bundle bytes, or null when the file doesn't exist. */
66885
67533
  async read(snapshotHash) {
66886
- const file = import_node_path71.default.join(this.rootDir, `${snapshotHash}.zip`);
67534
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
66887
67535
  try {
66888
- return await import_promises18.default.readFile(file);
67536
+ return await import_promises20.default.readFile(file);
66889
67537
  } catch (e) {
66890
67538
  if (e.code === "ENOENT") return null;
66891
67539
  throw e;
@@ -66893,8 +67541,8 @@ var BundleCache = class {
66893
67541
  }
66894
67542
  /** Idempotent — missing file is not an error. */
66895
67543
  async delete(snapshotHash) {
66896
- const file = import_node_path71.default.join(this.rootDir, `${snapshotHash}.zip`);
66897
- await import_promises18.default.rm(file, { force: true });
67544
+ const file = import_node_path73.default.join(this.rootDir, `${snapshotHash}.zip`);
67545
+ await import_promises20.default.rm(file, { force: true });
66898
67546
  }
66899
67547
  };
66900
67548
 
@@ -66916,24 +67564,24 @@ async function startDaemon(config) {
66916
67564
  sampling: logShippingCfg.sampling,
66917
67565
  homeDir: import_node_os26.default.homedir()
66918
67566
  });
66919
- const logDir = import_node_path72.default.join(config.dataDir, "log");
67567
+ const logDir = import_node_path74.default.join(config.dataDir, "log");
66920
67568
  import_node_fs53.default.mkdirSync(logDir, { recursive: true });
66921
67569
  const logger = createLogger({
66922
67570
  level: config.logLevel,
66923
- file: import_node_path72.default.join(logDir, "clawd.log"),
67571
+ file: import_node_path74.default.join(logDir, "clawd.log"),
66924
67572
  logClient
66925
67573
  });
66926
67574
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
66927
67575
  const screenIdleProbeLogger = createFileOnlyLogger({
66928
- file: import_node_path72.default.join(logDir, "screen-idle-probe.log"),
67576
+ file: import_node_path74.default.join(logDir, "screen-idle-probe.log"),
66929
67577
  level: "debug"
66930
67578
  });
66931
67579
  logger.info("screen-idle probe logger enabled", {
66932
- file: import_node_path72.default.join(logDir, "screen-idle-probe.log")
67580
+ file: import_node_path74.default.join(logDir, "screen-idle-probe.log")
66933
67581
  });
66934
67582
  const CAP_TARGETS = [
66935
- import_node_path72.default.join(logDir, "clawd.log"),
66936
- import_node_path72.default.join(logDir, "screen-idle-probe.log")
67583
+ import_node_path74.default.join(logDir, "clawd.log"),
67584
+ import_node_path74.default.join(logDir, "screen-idle-probe.log")
66937
67585
  ];
66938
67586
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
66939
67587
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -67055,8 +67703,8 @@ async function startDaemon(config) {
67055
67703
  const agents = new AgentsScanner();
67056
67704
  const history = new ClaudeHistoryReader();
67057
67705
  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");
67706
+ const personaStore = new PersonaStore(import_node_path74.default.join(config.dataDir, "personas"));
67707
+ const usersRoot = import_node_path74.default.join(config.dataDir, "users");
67060
67708
  const defaultsRoot = findDefaultsRoot(logger);
67061
67709
  if (defaultsRoot) {
67062
67710
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -67080,7 +67728,7 @@ async function startDaemon(config) {
67080
67728
  retirePersonaBuilder({ store: personaStore, logger });
67081
67729
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
67082
67730
  const dispatchStore = createDispatchStore({
67083
- filePath: import_node_path72.default.join(config.dataDir, "dispatch.json"),
67731
+ filePath: import_node_path74.default.join(config.dataDir, "dispatch.json"),
67084
67732
  now: () => Date.now(),
67085
67733
  onFlushError: (err) => logger.error("dispatch store flush failed", {
67086
67734
  reason: err instanceof Error ? err.message : String(err)
@@ -67089,7 +67737,7 @@ async function startDaemon(config) {
67089
67737
  await dispatchStore.load();
67090
67738
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
67091
67739
  const channelStore = createChannelStore({
67092
- filePath: import_node_path72.default.join(config.dataDir, "channels.json"),
67740
+ filePath: import_node_path74.default.join(config.dataDir, "channels.json"),
67093
67741
  now: () => Date.now(),
67094
67742
  genId: () => `ch-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
67095
67743
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -67098,7 +67746,7 @@ async function startDaemon(config) {
67098
67746
  });
67099
67747
  await channelStore.load();
67100
67748
  const topicStore = createTopicStore({
67101
- filePath: import_node_path72.default.join(config.dataDir, "topics.json"),
67749
+ filePath: import_node_path74.default.join(config.dataDir, "topics.json"),
67102
67750
  now: () => Date.now(),
67103
67751
  genId: () => `tp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
67104
67752
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -67125,18 +67773,18 @@ async function startDaemon(config) {
67125
67773
  });
67126
67774
  }
67127
67775
  });
67128
- const here = typeof __dirname === "string" ? __dirname : import_node_path72.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
67776
+ const here = typeof __dirname === "string" ? __dirname : import_node_path74.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
67129
67777
  const mcpConfigs = [];
67130
67778
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
67131
67779
  const dispatchServerCandidates = [
67132
- import_node_path72.default.join(here, "dispatch", "mcp-server.cjs"),
67780
+ import_node_path74.default.join(here, "dispatch", "mcp-server.cjs"),
67133
67781
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
67134
- import_node_path72.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
67782
+ import_node_path74.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
67135
67783
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
67136
67784
  ];
67137
67785
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67138
67786
  if (dispatchServerScriptPath) {
67139
- const dispatchLogPath = import_node_path72.default.join(logDir, "dispatch-mcp-server.log");
67787
+ const dispatchLogPath = import_node_path74.default.join(logDir, "dispatch-mcp-server.log");
67140
67788
  const dispatchCfgPath = writeDispatchMcpConfig({
67141
67789
  dataDir: config.dataDir,
67142
67790
  serverScriptPath: dispatchServerScriptPath,
@@ -67156,12 +67804,12 @@ async function startDaemon(config) {
67156
67804
  });
67157
67805
  }
67158
67806
  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")
67807
+ import_node_path74.default.join(here, "ticket", "mcp-server.cjs"),
67808
+ import_node_path74.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
67161
67809
  ];
67162
67810
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67163
67811
  if (ticketServerScriptPath) {
67164
- const ticketLogPath = import_node_path72.default.join(logDir, "ticket-mcp-server.log");
67812
+ const ticketLogPath = import_node_path74.default.join(logDir, "ticket-mcp-server.log");
67165
67813
  const ticketCfgPath = writeTicketMcpConfig({
67166
67814
  dataDir: config.dataDir,
67167
67815
  serverScriptPath: ticketServerScriptPath,
@@ -67183,12 +67831,12 @@ async function startDaemon(config) {
67183
67831
  });
67184
67832
  }
67185
67833
  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")
67834
+ import_node_path74.default.join(here, "shift", "mcp-server.cjs"),
67835
+ import_node_path74.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
67188
67836
  ];
67189
67837
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67190
67838
  if (shiftServerScriptPath) {
67191
- const shiftLogPath = import_node_path72.default.join(logDir, "shift-mcp-server.log");
67839
+ const shiftLogPath = import_node_path74.default.join(logDir, "shift-mcp-server.log");
67192
67840
  const shiftCfgPath = await writeShiftMcpConfig({
67193
67841
  dataDir: config.dataDir,
67194
67842
  serverScriptPath: shiftServerScriptPath,
@@ -67209,12 +67857,12 @@ async function startDaemon(config) {
67209
67857
  );
67210
67858
  }
67211
67859
  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")
67860
+ import_node_path74.default.join(here, "inbox", "mcp-server.cjs"),
67861
+ import_node_path74.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
67214
67862
  ];
67215
67863
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67216
67864
  if (inboxServerScriptPath) {
67217
- const inboxLogPath = import_node_path72.default.join(logDir, "inbox-mcp-server.log");
67865
+ const inboxLogPath = import_node_path74.default.join(logDir, "inbox-mcp-server.log");
67218
67866
  const inboxCfgPath = await writeInboxMcpConfig({
67219
67867
  dataDir: config.dataDir,
67220
67868
  serverScriptPath: inboxServerScriptPath,
@@ -67235,8 +67883,8 @@ async function startDaemon(config) {
67235
67883
  );
67236
67884
  }
67237
67885
  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")
67886
+ import_node_path74.default.join(here, "peer-ops", "mcp-server.cjs"),
67887
+ import_node_path74.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
67240
67888
  ];
67241
67889
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67242
67890
  if (peerOpsServerScriptPath) {
@@ -67258,12 +67906,12 @@ async function startDaemon(config) {
67258
67906
  );
67259
67907
  }
67260
67908
  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")
67909
+ import_node_path74.default.join(here, "rpc-tool", "mcp-server.cjs"),
67910
+ import_node_path74.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
67263
67911
  ];
67264
67912
  const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
67265
67913
  if (rpcToolServerScriptPath) {
67266
- const rpcToolLogPath = import_node_path72.default.join(logDir, "rpc-tool-mcp-server.log");
67914
+ const rpcToolLogPath = import_node_path74.default.join(logDir, "rpc-tool-mcp-server.log");
67267
67915
  const rpcToolCfgPath = writeRpcToolMcpConfig({
67268
67916
  dataDir: config.dataDir,
67269
67917
  serverScriptPath: rpcToolServerScriptPath,
@@ -67284,7 +67932,7 @@ async function startDaemon(config) {
67284
67932
  );
67285
67933
  }
67286
67934
  const shiftStore = createShiftStore({
67287
- filePath: import_node_path72.default.join(config.dataDir, "shift.json"),
67935
+ filePath: import_node_path74.default.join(config.dataDir, "shift.json"),
67288
67936
  ownerIdProvider: () => ownerPrincipalId,
67289
67937
  now: () => Date.now()
67290
67938
  });
@@ -67306,7 +67954,7 @@ async function startDaemon(config) {
67306
67954
  getAdapter,
67307
67955
  historyReader: history,
67308
67956
  dataDir: config.dataDir,
67309
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
67957
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67310
67958
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
67311
67959
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
67312
67960
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -67360,7 +68008,7 @@ async function startDaemon(config) {
67360
68008
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
67361
68009
  attachmentGroup: {
67362
68010
  onFileEdit: (input) => {
67363
- const absPath = import_node_path72.default.isAbsolute(input.relPath) ? input.relPath : import_node_path72.default.join(input.cwd, input.relPath);
68011
+ const absPath = import_node_path74.default.isAbsolute(input.relPath) ? input.relPath : import_node_path74.default.join(input.cwd, input.relPath);
67364
68012
  let size = 0;
67365
68013
  try {
67366
68014
  size = import_node_fs53.default.statSync(absPath).size;
@@ -67393,9 +68041,9 @@ async function startDaemon(config) {
67393
68041
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
67394
68042
  }
67395
68043
  const projectsStore = new ProjectsStore({
67396
- file: import_node_path72.default.join(config.dataDir, "projects.json"),
68044
+ file: import_node_path74.default.join(config.dataDir, "projects.json"),
67397
68045
  clawdDir: config.dataDir,
67398
- codexStateFile: import_node_path72.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
68046
+ codexStateFile: import_node_path74.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
67399
68047
  logger
67400
68048
  });
67401
68049
  const observer = new SessionObserver({
@@ -67455,12 +68103,12 @@ async function startDaemon(config) {
67455
68103
  screenIdleProbeLogger
67456
68104
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
67457
68105
  registerAdapter("claude", claudeAdapter);
67458
- const codexIsolatedHome = import_node_path72.default.join(config.dataDir, "codex-home");
68106
+ const codexIsolatedHome = import_node_path74.default.join(config.dataDir, "codex-home");
67459
68107
  try {
67460
68108
  import_node_fs53.default.mkdirSync(codexIsolatedHome, { recursive: true });
67461
68109
  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);
68110
+ const link = import_node_path74.default.join(codexIsolatedHome, f);
68111
+ const target = import_node_path74.default.join(import_node_os26.default.homedir(), ".codex", f);
67464
68112
  if (!import_node_fs53.default.existsSync(link) && import_node_fs53.default.existsSync(target)) import_node_fs53.default.symlinkSync(target, link);
67465
68113
  }
67466
68114
  } catch (err) {
@@ -67474,11 +68122,11 @@ async function startDaemon(config) {
67474
68122
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
67475
68123
  codexHomeFor: (cwd) => resolveCodexHome({
67476
68124
  cwd,
67477
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68125
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67478
68126
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
67479
68127
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
67480
68128
  projectPaths: projectsStore.listMerged().map((x) => x.path),
67481
- sharedHome: import_node_path72.default.join(import_node_os26.default.homedir(), ".codex"),
68129
+ sharedHome: import_node_path74.default.join(import_node_os26.default.homedir(), ".codex"),
67482
68130
  isolatedHome: codexIsolatedHome
67483
68131
  })
67484
68132
  })
@@ -67762,11 +68410,11 @@ async function startDaemon(config) {
67762
68410
  // 'persona/<pid>/owner',default 走 'default'。
67763
68411
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
67764
68412
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
67765
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68413
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67766
68414
  usersRoot
67767
68415
  },
67768
68416
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
67769
- personaRoot: import_node_path72.default.join(config.dataDir, "personas"),
68417
+ personaRoot: import_node_path74.default.join(config.dataDir, "personas"),
67770
68418
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
67771
68419
  usersRoot,
67772
68420
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -67865,11 +68513,11 @@ async function startDaemon(config) {
67865
68513
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
67866
68514
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
67867
68515
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
67868
- appBuilderPersonaRoot: import_node_path72.default.join(config.dataDir, "personas", "persona-app-builder"),
68516
+ appBuilderPersonaRoot: import_node_path74.default.join(config.dataDir, "personas", "persona-app-builder"),
67869
68517
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
67870
- deployKitRoot: import_node_path72.default.join(config.dataDir, "deploy-kit"),
68518
+ deployKitRoot: import_node_path74.default.join(config.dataDir, "deploy-kit"),
67871
68519
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
67872
- resolvePersonaRoot: (personaId2) => import_node_path72.default.join(config.dataDir, "personas", personaId2),
68520
+ resolvePersonaRoot: (personaId2) => import_node_path74.default.join(config.dataDir, "personas", personaId2),
67873
68521
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
67874
68522
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
67875
68523
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -67981,6 +68629,58 @@ async function startDaemon(config) {
67981
68629
  ownerIdProvider: () => ownerPrincipalId
67982
68630
  });
67983
68631
  Object.assign(handlers, shiftHandlers);
68632
+ const deployReceipts = createReceiptStore({
68633
+ filePath: import_node_path74.default.join(config.dataDir, "deploy.json"),
68634
+ now: () => Date.now(),
68635
+ onFlushError: (err) => logger.error("deploy receipts flush failed", { error: String(err) })
68636
+ });
68637
+ const deploySecrets = createSecretStore({
68638
+ filePath: import_node_path74.default.join(config.dataDir, "deploy-secrets.json"),
68639
+ now: () => Date.now(),
68640
+ onFlushError: (err) => logger.error("deploy secrets flush failed", { error: String(err) })
68641
+ });
68642
+ await deployReceipts.load();
68643
+ await deploySecrets.load();
68644
+ const interrupted = reconcileInterruptedScans(deployReceipts);
68645
+ if (interrupted.length > 0) logger.warn("deploy scans interrupted by restart", { deployIds: interrupted });
68646
+ const deployHandlers = buildDeployHandlers({
68647
+ receipts: deployReceipts,
68648
+ secrets: deploySecrets,
68649
+ hasPersona: (personaId2) => personaStore.has(personaId2),
68650
+ startScan: (deployId, personaId2) => {
68651
+ const assetLines = SCANNABLE_ASSETS.map(
68652
+ (name) => ` - ${name}\uFF1A${import_node_path74.default.join(config.dataDir, name)}`
68653
+ ).join("\n");
68654
+ const prompt = [
68655
+ `\u626B\u63CF persona\u300C${personaId2}\u300D\u7684\u90E8\u7F72\u73AF\u5883\uFF0CdeployId=${deployId}\u3002`,
68656
+ "",
68657
+ `persona \u76EE\u5F55\uFF1A${personaStore.personaDirPath(personaId2)}`,
68658
+ "\u53EF\u4EE5\u8BFB\u5230\u7684 persona \u76EE\u5F55\u4E4B\u5916\u7684\u5171\u4EAB\u8D44\u4EA7\uFF1A",
68659
+ assetLines || " \uFF08\u65E0\uFF09",
68660
+ "",
68661
+ "\u6309 scan-persona-for-deploy skill \u5E72\u6D3B\uFF1A\u8FB9\u67E5\u8FB9\u7528 deploy:reportFinding \u4E0A\u62A5\uFF0C",
68662
+ "\u5168\u90E8\u67E5\u5B8C\u8C03 deploy:finishScan \u6536\u5C3E\u3002"
68663
+ ].join("\n");
68664
+ let handle;
68665
+ try {
68666
+ handle = manager.createShiftSession({ targetPersona: BUTLER_PERSONA_ID, prompt, deployId });
68667
+ } catch (err) {
68668
+ deployReceipts.update(deployId, { status: "scanFailed", error: `\u8D77\u626B\u63CF\u4F1A\u8BDD\u5931\u8D25\uFF1A${String(err)}` });
68669
+ logger.error("deploy scan session failed to start", { deployId, personaId: personaId2, error: String(err) });
68670
+ return void 0;
68671
+ }
68672
+ void handle.ended.then((outcome) => {
68673
+ const patch = settleEndedScan(outcome, deployReceipts.get(deployId));
68674
+ if (!patch) return;
68675
+ deployReceipts.update(deployId, patch);
68676
+ logger.warn("deploy scan ended without finishScan", { deployId, personaId: personaId2, why: patch.error });
68677
+ });
68678
+ return handle.sessionId;
68679
+ },
68680
+ genId: () => `dp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
68681
+ now: () => Date.now()
68682
+ });
68683
+ Object.assign(handlers, deployHandlers);
67984
68684
  const shiftSpawnFn = createShiftSpawnFn({ sessionManager: manager });
67985
68685
  const shiftScheduler = createShiftScheduler({
67986
68686
  store: shiftStore,
@@ -67990,7 +68690,7 @@ async function startDaemon(config) {
67990
68690
  });
67991
68691
  shiftScheduler.start();
67992
68692
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
67993
- const larkBotStore = createLarkBotBindingStore(import_node_path72.default.join(config.dataDir, "personas"));
68693
+ const larkBotStore = createLarkBotBindingStore(import_node_path74.default.join(config.dataDir, "personas"));
67994
68694
  const larkBotCloud = createLarkBotCloudClient({
67995
68695
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
67996
68696
  apiKey: resolveClawdTicketsApiKey(),
@@ -68004,7 +68704,7 @@ async function startDaemon(config) {
68004
68704
  store: larkBotStore,
68005
68705
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
68006
68706
  // 图片落 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"),
68707
+ mediaRootFor: (chatId) => import_node_path74.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
68008
68708
  isShuttingDown: () => larkDraining,
68009
68709
  logger: {
68010
68710
  warn: (msg) => logger.warn(msg),
@@ -68309,8 +69009,8 @@ async function startDaemon(config) {
68309
69009
  const lines = [
68310
69010
  `Tunnel: ${r.url}`,
68311
69011
  ...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")}`
69012
+ `Frpc config: ${import_node_path74.default.join(config.dataDir, "frpc.toml")}`,
69013
+ `Frpc log: ${import_node_path74.default.join(logDir, "frpc.log")}`
68314
69014
  ];
68315
69015
  const width2 = Math.max(...lines.map((l) => l.length));
68316
69016
  const bar = "\u2550".repeat(width2 + 4);
@@ -68323,7 +69023,7 @@ ${bar}
68323
69023
 
68324
69024
  `);
68325
69025
  try {
68326
- const connectPath = import_node_path72.default.join(config.dataDir, "connect.txt");
69026
+ const connectPath = import_node_path74.default.join(config.dataDir, "connect.txt");
68327
69027
  import_node_fs53.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
68328
69028
  } catch {
68329
69029
  }
@@ -68390,7 +69090,9 @@ ${bar}
68390
69090
  await wss.stop();
68391
69091
  for (const [name, store2] of [
68392
69092
  ["channels", channelStore],
68393
- ["topics", topicStore]
69093
+ ["topics", topicStore],
69094
+ ["deploy-receipts", deployReceipts],
69095
+ ["deploy-secrets", deploySecrets]
68394
69096
  ]) {
68395
69097
  await store2.flushNow().catch((err) => {
68396
69098
  logger.warn("shutdown.store-flush-failed", {
@@ -68411,7 +69113,7 @@ ${bar}
68411
69113
  };
68412
69114
  }
68413
69115
  function migrateDropPersonsDir(dataDir) {
68414
- const dir = import_node_path72.default.join(dataDir, "persons");
69116
+ const dir = import_node_path74.default.join(dataDir, "persons");
68415
69117
  try {
68416
69118
  import_node_fs53.default.rmSync(dir, { recursive: true, force: true });
68417
69119
  } catch {