@clawos-dev/clawd 0.2.731 → 0.2.733

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.
@@ -31378,12 +31378,6 @@ var EnvPackageSchema = external_exports.object({
31378
31378
  */
31379
31379
  aptVersion: external_exports.string().optional()
31380
31380
  });
31381
- var EnvSecretSchema = external_exports.object({
31382
- name: external_exports.string().min(1),
31383
- // 解析出的值注入到哪些环境变量。一份凭据可含多个字段(AK 是 id+secret 两个,
31384
- // supabase 是 url/anon/service-role/jwt 四个),所以是数组不是单值。
31385
- env: external_exports.array(external_exports.string().min(1)).min(1)
31386
- });
31387
31381
  var ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
31388
31382
  var CONNECTOR_KINDS = ["proxy", "env"];
31389
31383
  var CONNECTOR_RUNNERS = ["mcp", "cli"];
@@ -31391,6 +31385,10 @@ var CONNECTOR_PROTOCOLS = ["bearer", "lark-sidecar"];
31391
31385
  var CREDENTIAL_SOURCES = ["none", "shared", "personal"];
31392
31386
  var CONNECTOR_AUTHS = ["oauth", "fields"];
31393
31387
  var ConnectorFieldSchema = external_exports.string().regex(/^[A-Z][A-Z0-9_]*$/, "\u8981\u586B\u7684\u53D8\u91CF\u540D\u53EA\u80FD\u662F\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF\uFF0C\u4E14\u4EE5\u5B57\u6BCD\u5F00\u5934");
31388
+ var EnvVarSchema = external_exports.object({
31389
+ name: external_exports.string().min(1),
31390
+ env: external_exports.array(ConnectorFieldSchema).min(1)
31391
+ });
31394
31392
  var EnvConnectorSchema = external_exports.object({
31395
31393
  name: ConnectorNameSchema,
31396
31394
  kind: external_exports.enum(CONNECTOR_KINDS),
@@ -31415,6 +31413,12 @@ var normalizeLegacyManifest = (v) => {
31415
31413
  const { assets: _dropped, ...rest } = o;
31416
31414
  o = rest;
31417
31415
  }
31416
+ if ("secrets" in o && Array.isArray(o.secrets)) {
31417
+ const { secrets, ...rest } = o;
31418
+ const fields = new Set((Array.isArray(rest.connectors) ? rest.connectors : []).flatMap((c) => Array.isArray(c?.fields) ? c.fields : []));
31419
+ const legacy = secrets.map((g) => ({ ...g, env: Array.isArray(g?.env) ? g.env.filter((e) => !fields.has(e)) : g?.env })).filter((g) => !Array.isArray(g.env) || g.env.length > 0);
31420
+ o = { ...rest, envVars: [...Array.isArray(rest.envVars) ? rest.envVars : [], ...legacy] };
31421
+ }
31418
31422
  return o;
31419
31423
  };
31420
31424
  var PublisherTestSchema = external_exports.object({
@@ -31426,12 +31430,13 @@ var PublisherTestSchema = external_exports.object({
31426
31430
  var MANIFEST_BODY = {
31427
31431
  test: PublisherTestSchema.optional(),
31428
31432
  packages: external_exports.array(EnvPackageSchema),
31429
- secrets: external_exports.array(EnvSecretSchema),
31433
+ /** 环境变量(见 `EnvVarSchema`)。缺省空:没声明就是没有。 */
31434
+ envVars: external_exports.array(EnvVarSchema).default([]),
31430
31435
  /**
31431
31436
  * 装了哪些连接器(design 2026-09-11-mcp-connector §3.1)。一条一个对象,形状见 `EnvConnectorSchema`。
31432
31437
  *
31433
- * 不复用 secrets:那段说的是「需要一份值,由部署者填」;连接器的凭据谁出是单据上点出来的,
31434
- * 三种来源里只有「共享」才落到 Secrets,而且靠 `sharedConnectorSecrets` 在消费处并入,不写进那段。
31438
+ * 凭据归连接器自己(`fields`),不进 envVars:谁出是单据上点出来的,
31439
+ * 三种来源里只有「共享」才落到 Secrets,而且靠 `sharedConnectorSecrets` 在消费处并入。
31435
31440
  *
31436
31441
  * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装。
31437
31442
  */
@@ -31445,7 +31450,7 @@ var EnvironmentManifestSchema = external_exports.preprocess(normalizeLegacyManif
31445
31450
  ...MANIFEST_BODY
31446
31451
  }).strict());
31447
31452
  var EnvEvidenceSchema = external_exports.object({
31448
- // 这条证据支持的是哪一项:`${kind}:${name}`,如 'package:aliyun' / 'secret:aliyun-ak' / 'connector:feishu'
31453
+ // 这条证据支持的是哪一项:`${kind}:${name}`,如 'package:aliyun' / 'env:aliyun-ak' / 'connector:feishu'
31449
31454
  target: external_exports.string().min(1),
31450
31455
  reason: external_exports.string().min(1),
31451
31456
  file: external_exports.string().min(1),
@@ -31950,7 +31955,7 @@ var DeployRerunJobArgsSchema = external_exports.object({
31950
31955
  }).strict();
31951
31956
  var DeployReportFindingArgsSchema = external_exports.object({
31952
31957
  personaId: external_exports.string().min(1),
31953
- kind: external_exports.enum(["package", "secret", "connector"]),
31958
+ kind: external_exports.enum(["package", "env", "connector"]),
31954
31959
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
31955
31960
  // connector 的 item 是 butler 报的 CLI 连接器({ name, fields? }),daemon 补齐 kind / runner / id 后落进清单;
31956
31961
  // MCP 连接器不经这里——由 daemon 从 .mcp.json 机械列出(design 2026-09-11-mcp-connector §3.2)
@@ -34013,7 +34018,7 @@ var METHOD_DOCS = {
34013
34018
  }
34014
34019
  },
34015
34020
  "deploy:reportFinding": {
34016
- summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08cli / secret / asset\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u9875\u9762\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002\u53EA\u56DE\u626B\u63CF\u5386\u53F2 `scans`\uFF08\u540C deploy:patch\uFF09\uFF0C\u4E0D\u56DE\u6574\u4EFD\u72B6\u6001\uFF1Bowner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
34021
+ summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08package / env / connector\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u9875\u9762\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002\u53EA\u56DE\u626B\u63CF\u5386\u53F2 `scans`\uFF08\u540C deploy:patch\uFF09\uFF0C\u4E0D\u56DE\u6574\u4EFD\u72B6\u6001\uFF1Bowner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
34017
34022
  args: DeployReportFindingArgsSchema
34018
34023
  },
34019
34024
  "deploy:finishScan": {
package/dist/cli.cjs CHANGED
@@ -6174,9 +6174,13 @@ function sharedConnectorSecrets(m3) {
6174
6174
  return m3.connectors.filter((c2) => c2.credentialSource === "shared" && c2.fields.length > 0).map((c2) => ({ name: c2.name, env: [...c2.fields] }));
6175
6175
  }
6176
6176
  function requiredSecretEnvNames(m3) {
6177
- return [.../* @__PURE__ */ new Set([...m3.secrets.flatMap((s2) => s2.env), ...sharedConnectorSecrets(m3).flatMap((s2) => s2.env)])];
6177
+ return [.../* @__PURE__ */ new Set([...m3.envVars.flatMap((s2) => s2.env), ...sharedConnectorSecrets(m3).flatMap((s2) => s2.env)])];
6178
6178
  }
6179
- var EnvArtifactSchema, CLOUD_DEBIAN, CLOUD_ROOT_PROVIDES, CLOUD_BASE_PROVIDES, EnvPackageSchema, EnvSecretSchema, ConnectorNameSchema, CONNECTOR_KINDS, CONNECTOR_RUNNERS, CONNECTOR_PROTOCOLS, CREDENTIAL_SOURCES, CONNECTOR_AUTHS, ConnectorFieldSchema, EnvConnectorSchema, FEISHU_BOT_FIELDS, GO_SPEC_RE, GO_MOVING_REFS, normalizeLegacyManifest, PUBLISHER_TEST_NOTE_PREFIX, PublisherTestSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
6179
+ function envVarBlockers(m3) {
6180
+ const fields = new Set(m3.connectors.flatMap((c2) => c2.fields));
6181
+ return [...new Set(m3.envVars.flatMap((v3) => v3.env))].filter((env) => fields.has(env)).map((env) => `${env} \u540C\u65F6\u662F\u73AF\u5883\u53D8\u91CF\u548C\u8FDE\u63A5\u5668\u7684\u5B57\u6BB5\uFF0C\u53EA\u80FD\u7559\u4E00\u5904\u2014\u2014\u91CD\u65B0\u626B\u63CF`);
6182
+ }
6183
+ var EnvArtifactSchema, CLOUD_DEBIAN, CLOUD_ROOT_PROVIDES, CLOUD_BASE_PROVIDES, EnvPackageSchema, ConnectorNameSchema, CONNECTOR_KINDS, CONNECTOR_RUNNERS, CONNECTOR_PROTOCOLS, CREDENTIAL_SOURCES, CONNECTOR_AUTHS, ConnectorFieldSchema, EnvVarSchema, EnvConnectorSchema, FEISHU_BOT_FIELDS, GO_SPEC_RE, GO_MOVING_REFS, normalizeLegacyManifest, PUBLISHER_TEST_NOTE_PREFIX, PublisherTestSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
6180
6184
  var init_environment_schemas = __esm({
6181
6185
  "../protocol/src/environment-schemas.ts"() {
6182
6186
  "use strict";
@@ -6246,12 +6250,6 @@ var init_environment_schemas = __esm({
6246
6250
  */
6247
6251
  aptVersion: external_exports.string().optional()
6248
6252
  });
6249
- EnvSecretSchema = external_exports.object({
6250
- name: external_exports.string().min(1),
6251
- // 解析出的值注入到哪些环境变量。一份凭据可含多个字段(AK 是 id+secret 两个,
6252
- // supabase 是 url/anon/service-role/jwt 四个),所以是数组不是单值。
6253
- env: external_exports.array(external_exports.string().min(1)).min(1)
6254
- });
6255
6253
  ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
6256
6254
  CONNECTOR_KINDS = ["proxy", "env"];
6257
6255
  CONNECTOR_RUNNERS = ["mcp", "cli"];
@@ -6259,6 +6257,10 @@ var init_environment_schemas = __esm({
6259
6257
  CREDENTIAL_SOURCES = ["none", "shared", "personal"];
6260
6258
  CONNECTOR_AUTHS = ["oauth", "fields"];
6261
6259
  ConnectorFieldSchema = external_exports.string().regex(/^[A-Z][A-Z0-9_]*$/, "\u8981\u586B\u7684\u53D8\u91CF\u540D\u53EA\u80FD\u662F\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF\uFF0C\u4E14\u4EE5\u5B57\u6BCD\u5F00\u5934");
6260
+ EnvVarSchema = external_exports.object({
6261
+ name: external_exports.string().min(1),
6262
+ env: external_exports.array(ConnectorFieldSchema).min(1)
6263
+ });
6262
6264
  EnvConnectorSchema = external_exports.object({
6263
6265
  name: ConnectorNameSchema,
6264
6266
  kind: external_exports.enum(CONNECTOR_KINDS),
@@ -6286,6 +6288,12 @@ var init_environment_schemas = __esm({
6286
6288
  const { assets: _dropped, ...rest } = o2;
6287
6289
  o2 = rest;
6288
6290
  }
6291
+ if ("secrets" in o2 && Array.isArray(o2.secrets)) {
6292
+ const { secrets, ...rest } = o2;
6293
+ const fields = new Set((Array.isArray(rest.connectors) ? rest.connectors : []).flatMap((c2) => Array.isArray(c2?.fields) ? c2.fields : []));
6294
+ const legacy = secrets.map((g3) => ({ ...g3, env: Array.isArray(g3?.env) ? g3.env.filter((e) => !fields.has(e)) : g3?.env })).filter((g3) => !Array.isArray(g3.env) || g3.env.length > 0);
6295
+ o2 = { ...rest, envVars: [...Array.isArray(rest.envVars) ? rest.envVars : [], ...legacy] };
6296
+ }
6289
6297
  return o2;
6290
6298
  };
6291
6299
  PUBLISHER_TEST_NOTE_PREFIX = "Publisher test: ";
@@ -6298,12 +6306,13 @@ var init_environment_schemas = __esm({
6298
6306
  MANIFEST_BODY = {
6299
6307
  test: PublisherTestSchema.optional(),
6300
6308
  packages: external_exports.array(EnvPackageSchema),
6301
- secrets: external_exports.array(EnvSecretSchema),
6309
+ /** 环境变量(见 `EnvVarSchema`)。缺省空:没声明就是没有。 */
6310
+ envVars: external_exports.array(EnvVarSchema).default([]),
6302
6311
  /**
6303
6312
  * 装了哪些连接器(design 2026-09-11-mcp-connector §3.1)。一条一个对象,形状见 `EnvConnectorSchema`。
6304
6313
  *
6305
- * 不复用 secrets:那段说的是「需要一份值,由部署者填」;连接器的凭据谁出是单据上点出来的,
6306
- * 三种来源里只有「共享」才落到 Secrets,而且靠 `sharedConnectorSecrets` 在消费处并入,不写进那段。
6314
+ * 凭据归连接器自己(`fields`),不进 envVars:谁出是单据上点出来的,
6315
+ * 三种来源里只有「共享」才落到 Secrets,而且靠 `sharedConnectorSecrets` 在消费处并入。
6307
6316
  *
6308
6317
  * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装。
6309
6318
  */
@@ -6317,7 +6326,7 @@ var init_environment_schemas = __esm({
6317
6326
  ...MANIFEST_BODY
6318
6327
  }).strict());
6319
6328
  EnvEvidenceSchema = external_exports.object({
6320
- // 这条证据支持的是哪一项:`${kind}:${name}`,如 'package:aliyun' / 'secret:aliyun-ak' / 'connector:feishu'
6329
+ // 这条证据支持的是哪一项:`${kind}:${name}`,如 'package:aliyun' / 'env:aliyun-ak' / 'connector:feishu'
6321
6330
  target: external_exports.string().min(1),
6322
6331
  reason: external_exports.string().min(1),
6323
6332
  file: external_exports.string().min(1),
@@ -6934,7 +6943,7 @@ var init_deploy_schemas = __esm({
6934
6943
  DEPLOY_STALE_BASE_ERROR = "\u5E95\u5EA7\u5DF2\u66F4\u65B0\uFF0C\u91CD\u8BD5\u4ECD\u4F1A\u7528\u65E7\u5E95\u5EA7\u6784\u5EFA\u2014\u2014\u8BF7\u91CD\u65B0\u53D1\u5E03\u6D4B\u8BD5\u73AF\u5883";
6935
6944
  DeployReportFindingArgsSchema = external_exports.object({
6936
6945
  personaId: external_exports.string().min(1),
6937
- kind: external_exports.enum(["package", "secret", "connector"]),
6946
+ kind: external_exports.enum(["package", "env", "connector"]),
6938
6947
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
6939
6948
  // connector 的 item 是 butler 报的 CLI 连接器({ name, fields? }),daemon 补齐 kind / runner / id 后落进清单;
6940
6949
  // MCP 连接器不经这里——由 daemon 从 .mcp.json 机械列出(design 2026-09-11-mcp-connector §3.2)
@@ -9286,7 +9295,7 @@ var init_methods = __esm({
9286
9295
  }
9287
9296
  },
9288
9297
  "deploy:reportFinding": {
9289
- summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08cli / secret / asset\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u9875\u9762\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002\u53EA\u56DE\u626B\u63CF\u5386\u53F2 `scans`\uFF08\u540C deploy:patch\uFF09\uFF0C\u4E0D\u56DE\u6574\u4EFD\u72B6\u6001\uFF1Bowner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
9298
+ summary: "\u626B\u63CF\u4E2D\u7684 butler \u9010\u6761\u4E0A\u62A5\u4E00\u4E2A\u53D1\u73B0\uFF08package / env / connector\uFF09\u3002**\u8FB9\u626B\u8FB9\u62A5**\uFF0C\u9875\u9762\u968F\u4E4B\u4E00\u70B9\u70B9\u586B\u5145\uFF1B\u540C (kind,name) \u91CD\u590D\u4E0A\u62A5\u5373\u8986\u76D6\u3002\u53EA\u56DE\u626B\u63CF\u5386\u53F2 `scans`\uFF08\u540C deploy:patch\uFF09\uFF0C\u4E0D\u56DE\u6574\u4EFD\u72B6\u6001\uFF1Bowner-only\u2014\u2014butler \u4F1A\u8BDD\u672C\u8EAB\u8DD1\u5728 owner \u6A21\u5F0F",
9290
9299
  args: DeployReportFindingArgsSchema
9291
9300
  },
9292
9301
  "deploy:finishScan": {
@@ -49195,6 +49204,33 @@ function attachPersonaSecretMcp(ctx, resolve9) {
49195
49204
  return { ...ctx, mcpConfigs: [...ctx.mcpConfigs ?? [], ref] };
49196
49205
  }
49197
49206
 
49207
+ // src/persona/persona-env-vars.ts
49208
+ init_protocol();
49209
+ function personaEnvVars(args) {
49210
+ let parsed;
49211
+ try {
49212
+ parsed = DeployFileSchema.safeParse(JSON.parse(args.manifestText));
49213
+ } catch {
49214
+ throw new Error("deploy.json \u4E0D\u662F\u5408\u6CD5 JSON");
49215
+ }
49216
+ if (!parsed.success) throw new Error("deploy.json \u8BFB\u4E0D\u51FA\u6E05\u5355");
49217
+ const names = [...new Set(parsed.data.manifest.envVars.flatMap((v3) => v3.env))];
49218
+ const env = {};
49219
+ const missing = [];
49220
+ for (const name of names) {
49221
+ const value = args.secrets[name];
49222
+ if (value) env[name] = value;
49223
+ else missing.push(name);
49224
+ }
49225
+ return { env, missing };
49226
+ }
49227
+ function attachPersonaEnvVars(ctx, resolve9) {
49228
+ if (!resolve9 || !ctx.personaId) return ctx;
49229
+ const vars = resolve9(ctx.personaId);
49230
+ if (Object.keys(vars).length === 0) return ctx;
49231
+ return { ...ctx, env: { ...vars, ...ctx.env } };
49232
+ }
49233
+
49198
49234
  // src/ipc-recorder.ts
49199
49235
  var import_node_fs15 = __toESM(require("fs"), 1);
49200
49236
  var import_node_path14 = __toESM(require("path"), 1);
@@ -49696,6 +49732,7 @@ var SessionRunner = class {
49696
49732
  let ctx;
49697
49733
  try {
49698
49734
  ctx = attachPersonaSecretMcp(rawCtx, this.hooks.resolvePersonaMcpConfig);
49735
+ if (!this.state.file.larkChatId) ctx = attachPersonaEnvVars(ctx, this.hooks.resolvePersonaEnvVars);
49699
49736
  } catch (err) {
49700
49737
  const message = `persona secret mcp render failed: ${err instanceof Error ? err.message : String(err)}`;
49701
49738
  this.hooks.logger?.error("persona.mcp-secret.render-failed", {
@@ -50236,6 +50273,7 @@ var SessionManager = class {
50236
50273
  getClawosApi: this.deps.getClawosApi,
50237
50274
  getMcpConfigs: () => this.deps.mcpConfigs ?? [],
50238
50275
  resolvePersonaMcpConfig: this.deps.resolvePersonaMcpConfig,
50276
+ resolvePersonaEnvVars: this.deps.resolvePersonaEnvVars,
50239
50277
  // 只传人格补充层读闭包,避免把整个 store 下沉;缺 store 不追加。
50240
50278
  readPersonalityLocal: this.deps.personaStore ? (id) => this.deps.personaStore?.readPersonalityLocal(id) ?? null : void 0,
50241
50279
  lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
@@ -58985,7 +59023,9 @@ function normalizeLegacyScan(raw) {
58985
59023
  rest.evidence = rest.evidence.map((e) => {
58986
59024
  if (!e || typeof e !== "object" || typeof e.target !== "string") return e;
58987
59025
  const target = e.target;
58988
- return target.startsWith("cli:") ? { ...e, target: `package:${target.slice("cli:".length)}` } : e;
59026
+ if (target.startsWith("cli:")) return { ...e, target: `package:${target.slice("cli:".length)}` };
59027
+ if (target.startsWith("secret:")) return { ...e, target: `env:${target.slice("secret:".length)}` };
59028
+ return e;
58989
59029
  });
58990
59030
  }
58991
59031
  return rest;
@@ -59029,14 +59069,14 @@ function replaceScan(file, entry) {
59029
59069
  return { ...file, scans: idx === -1 ? [...file.scans, entry] : file.scans.map((s2, i2) => i2 === idx ? entry : s2) };
59030
59070
  }
59031
59071
  function emptyDeployFile() {
59032
- return { version: 1, manifest: { version: 1, packages: [], secrets: [], connectors: [] } };
59072
+ return { version: 1, manifest: { version: 1, packages: [], envVars: [], connectors: [] } };
59033
59073
  }
59034
59074
  var PackageFindingSchema = EnvPackageSchema.omit({ localVersion: true, artifact: true, aptMissing: true, aptVersion: true }).extend({
59035
59075
  artifact: external_exports.object({ url: external_exports.string().url(), bin: external_exports.string() }).strict().optional()
59036
59076
  });
59037
59077
  var FINDING_SCHEMAS = {
59038
59078
  package: PackageFindingSchema,
59039
- secret: EnvSecretSchema,
59079
+ env: EnvVarSchema,
59040
59080
  // 仅收 CLI 连接器发现;MCP 由 scanMcpConnectors 从配置列出。
59041
59081
  connector: CliConnectorFindingSchema
59042
59082
  };
@@ -59090,7 +59130,7 @@ function upsertFinding(manifest, kind, item) {
59090
59130
  const connectors = idx2 === -1 ? [...have, merged] : have.map((c2, i2) => i2 === idx2 ? merged : c2);
59091
59131
  return { ...manifest, connectors };
59092
59132
  }
59093
- const key = kind === "package" ? "packages" : "secrets";
59133
+ const key = kind === "package" ? "packages" : "envVars";
59094
59134
  const list = [...manifest[key]];
59095
59135
  const idx = list.findIndex((x2) => x2.name === item.name);
59096
59136
  if (idx === -1) list.push(item);
@@ -63114,6 +63154,7 @@ var UNPUBLISH_WORKFLOW_FILE = "clawd-unpublish.yml";
63114
63154
  var UNPUBLISH_WORKFLOW_PATH = `.github/workflows/${UNPUBLISH_WORKFLOW_FILE}`;
63115
63155
  var DOCKERFILE_PATH = "Dockerfile";
63116
63156
  var DOCKERIGNORE_PATH = ".dockerignore";
63157
+ var INSTALL_FILE_PATH = ".clawd/deploy-install.json";
63117
63158
  var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
63118
63159
  var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
63119
63160
  var ACR_NAMESPACE = "ttc-prod";
@@ -63140,6 +63181,13 @@ function mergeGitignore(existing) {
63140
63181
  function personaIdOf(repoName) {
63141
63182
  return String(repoName).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
63142
63183
  }
63184
+ function renderInstallFile(deployFileRaw) {
63185
+ const parsed = JSON.parse(deployFileRaw);
63186
+ const manifest = parsed.manifest ?? parsed;
63187
+ const assets = Array.isArray(manifest.assets) && manifest.assets.length ? { assets: manifest.assets } : {};
63188
+ return `${JSON.stringify({ version: 1, manifest: { packages: manifest.packages ?? manifest.clis ?? [], ...assets } }, null, 2)}
63189
+ `;
63190
+ }
63143
63191
  function renderDockerfile(personaId2, baseImage) {
63144
63192
  if (typeof baseImage !== "string" || !/^[a-z0-9.-]+(?::[0-9]+)?\/[a-z0-9._/-]+@sha256:[a-f0-9]{64}$/.test(baseImage)) throw new Error("base image must be a complete digest reference");
63145
63193
  if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(personaId2)) throw new Error(`persona id \u4E0D\u5408\u5F62\u72B6\uFF08[a-z0-9-]\uFF0C\u226440\uFF09\uFF1A${JSON.stringify(personaId2)}`);
@@ -63149,9 +63197,11 @@ function renderDockerfile(personaId2, baseImage) {
63149
63197
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
63150
63198
  "# \u963F\u91CC\u4E91\u5BB9\u5668\u955C\u50CF\u670D\u52A1\uFF08ACR\uFF09\u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\u65F6\u7528\u5B83\uFF1BGitHub \u7684 runner \u4E0D\u6784\u3001\u4E0D\u63A8\u955C\u50CF\u3002",
63151
63199
  "# \u8981\u88C5\u4EC0\u4E48\u5199\u5728 .clawd/deploy.json \u91CC\uFF0C\u7531\u5E95\u5EA7\u81EA\u5E26\u7684\u5B89\u88C5\u5668\u5728\u6784\u5EFA\u65F6\u73B0\u88C5\u2014\u2014\u8FD9\u91CC\u4E0D\u5217\u4EFB\u4F55\u4E00\u6761\u4F9D\u8D56\uFF0C",
63152
- "# \u6240\u4EE5\u6587\u4EF6\u4E0D\u968F\u6E05\u5355\u53D8\uFF1B\u5148\u53EA\u62F7\u6E05\u5355\u518D\u88C5\uFF0Cpersona \u5185\u5BB9\u6539\u4E86\u4E5F\u4E0D\u7528\u91CD\u88C5\u3002",
63200
+ "# \u6240\u4EE5\u6587\u4EF6\u4E0D\u968F\u6E05\u5355\u53D8\uFF1B\u5148\u53EA\u62F7\u5B89\u88C5\u6E05\u5355\uFF08deploy-install.json\uFF0C\u53EA\u542B\u8981\u88C5\u7684\u4E1C\u897F\uFF09\u518D\u88C5\uFF0Cpersona \u5185\u5BB9\u6216\u51ED\u636E\u914D\u7F6E\u6539\u4E86\u4E5F\u4E0D\u7528\u91CD\u88C5\u3002",
63201
+ "# deploy-install.json \u7531\u53D1\u5E03\u65F6\u4ECE deploy.json \u751F\u6210\uFF1A\u6539\u8981\u88C5\u7684\u5305\u987B\u7ECF clawd \u53D1\u5E03\uFF0C\u624B\u6539 deploy.json \u518D push \u4E0D\u4F1A\u751F\u6548\u3002",
63153
63202
  `FROM ${fromImage}`,
63154
- `COPY .clawd/deploy.json ${dir}/.clawd/deploy.json`,
63203
+ // 拷到安装器读的位置;最后一条 COPY . 再用完整的 deploy.json 盖回来
63204
+ `COPY ${INSTALL_FILE_PATH} ${dir}/.clawd/deploy.json`,
63155
63205
  `RUN node ${PERSONA_LAYER_SCRIPT} ${dir}`,
63156
63206
  `COPY . ${dir}/`,
63157
63207
  ""
@@ -63293,7 +63343,7 @@ var runCommand = (cmd, args, opts = {}) => new Promise((resolve9) => {
63293
63343
  // src/deploy/repo.ts
63294
63344
  var DEPLOY_FILE_REL = DEPLOY_FILE.split(import_node_path44.default.sep).join("/");
63295
63345
  var PERSONA_FILE_REL = ".clawd/persona.json";
63296
- var DIRTY_IGNORED = [DEPLOY_FILE_REL, PERSONA_FILE_REL];
63346
+ var DIRTY_IGNORED = [DEPLOY_FILE_REL, PERSONA_FILE_REL, INSTALL_FILE_PATH];
63297
63347
  var RepoError = class extends Error {
63298
63348
  };
63299
63349
  var tail = (s2, n2 = 400) => s2.trim().slice(-n2);
@@ -63452,6 +63502,8 @@ async function writeDockerfile(dir, personaId2, image) {
63452
63502
  `);
63453
63503
  await import_promises5.default.writeFile(import_node_path44.default.join(dir, DOCKERFILE_PATH), renderDockerfile(personaId2, baseImage));
63454
63504
  await import_promises5.default.writeFile(import_node_path44.default.join(dir, DOCKERIGNORE_PATH), DOCKERIGNORE_TEMPLATE);
63505
+ const deployFile = await readDeployFileRaw(dir);
63506
+ if (deployFile !== void 0) await import_promises5.default.writeFile(import_node_path44.default.join(dir, INSTALL_FILE_PATH), renderInstallFile(deployFile));
63455
63507
  }
63456
63508
  var RepoAlreadyExistsError = class extends RepoError {
63457
63509
  constructor(slug) {
@@ -64594,8 +64646,8 @@ function buildDeployHandlers(deps) {
64594
64646
  const args = parseArgs2(DeployPutSecretArgsSchema, frame, "deploy:putSecret");
64595
64647
  const dir = mustPersona(args.personaId);
64596
64648
  const { manifest } = mustScan(await readHistory(dir), args.scanId);
64597
- const declared = [...manifest.secrets, ...sharedConnectorSecrets(manifest)].find((s2) => s2.name === args.name);
64598
- if (!declared) throw invalid(`\u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u51ED\u636E`);
64649
+ const declared = [...manifest.envVars, ...sharedConnectorSecrets(manifest)].find((s2) => s2.name === args.name);
64650
+ if (!declared) throw invalid(`\u6E05\u5355\u91CC\u6CA1\u6709\u53EB\u300C${args.name}\u300D\u7684\u73AF\u5883\u53D8\u91CF\u6216\u5171\u4EAB\u8FDE\u63A5\u5668`);
64599
64651
  const allowed = new Set(declared.env);
64600
64652
  for (const key of Object.keys(args.values)) {
64601
64653
  if (!allowed.has(key)) throw invalid(`\u300C${args.name}\u300D\u6CA1\u6709\u58F0\u660E\u73AF\u5883\u53D8\u91CF ${key}`);
@@ -64881,6 +64933,7 @@ function buildDeployHandlers(deps) {
64881
64933
  if (missing.length > 0) blockers.push(`${missing.join(" / ")} \u8FD8\u6CA1\u586B`);
64882
64934
  if (engineAuthState(secrets) === "partial") blockers.push(ENGINE_AUTH_PARTIAL_BLOCKER);
64883
64935
  for (const c2 of entry.manifest.connectors) blockers.push(...connectorBlockers(c2));
64936
+ blockers.push(...envVarBlockers(entry.manifest));
64884
64937
  for (const p3 of entry.manifest.packages) blockers.push(...packageBlockers(p3));
64885
64938
  const cloudEngine = cloudEngineSettings(deps.personaEngine(personaId2) ?? {});
64886
64939
  if (!cloudEngine.model) {
@@ -76169,7 +76222,7 @@ function computeMethodAccess(args) {
76169
76222
  }
76170
76223
 
76171
76224
  // src/version.ts
76172
- var version = "0.2.731".length > 0 ? "0.2.731" : "dev";
76225
+ var version = "0.2.733".length > 0 ? "0.2.733" : "dev";
76173
76226
 
76174
76227
  // src/cli-probe/probe.ts
76175
76228
  var fs87 = __toESM(require("fs"), 1);
@@ -78949,6 +79002,23 @@ async function startDaemon(config) {
78949
79002
  logger
78950
79003
  });
78951
79004
  };
79005
+ const resolvePersonaEnvVars = (personaId2) => {
79006
+ const file = import_node_path90.default.join(config.dataDir, "personas", personaId2, DEPLOY_FILE);
79007
+ let manifestText;
79008
+ try {
79009
+ manifestText = import_node_fs69.default.readFileSync(file, "utf8");
79010
+ } catch {
79011
+ return {};
79012
+ }
79013
+ try {
79014
+ const { env, missing } = personaEnvVars({ manifestText, secrets: readSecrets() });
79015
+ if (missing.length > 0) logger.warn("persona.env-vars.missing", { personaId: personaId2, names: missing });
79016
+ return env;
79017
+ } catch (err) {
79018
+ logger.warn("persona.env-vars.unreadable", { personaId: personaId2, message: err instanceof Error ? err.message : String(err) });
79019
+ return {};
79020
+ }
79021
+ };
78952
79022
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
78953
79023
  const dispatchServerCandidates = [
78954
79024
  import_node_path90.default.join(here, "dispatch", "mcp-server.cjs"),
@@ -79140,6 +79210,7 @@ async function startDaemon(config) {
79140
79210
  mcpConfigs,
79141
79211
  // Render MCP configs outside the pure reducer because rendering performs filesystem IO.
79142
79212
  resolvePersonaMcpConfig,
79213
+ resolvePersonaEnvVars,
79143
79214
  generateTitle: (file, firstMessage, signal) => generateSessionTitle(file, firstMessage, {
79144
79215
  logger,
79145
79216
  signal,