@clawos-dev/clawd 0.2.540 → 0.2.542

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
@@ -50195,11 +50195,12 @@ var DEFAULT_PERSONAS = [
50195
50195
  // 与 app-builder 对齐"调用阿里云的工作方式"(owner 2026-06-17 要求):开发型 profile —— 放开文件/web
50196
50196
  // 工具 + node/pnpm 工具链精确路径 + 出站 TLD 通配白名单。html-slides 需要联网(git clone frontend-slides
50197
50197
  // skill、调阿里云 CLI/SDK)。
50198
- // 阿里云凭证:**复用共享 deploy-kit 单源**($HOME/.clawd/deploy-kit/.secrets/aliyun.env,全 FC persona 共用、
50199
- // seedDeployKit 每次安装都铺),不在 persona 目录另存一份。app-builder 的 FC 部署走 daemon 侧脚本(沙箱外)
50200
- // 故其 profile 无需 carve 这个路径;html-slides 没有 daemon 侧流程、要在 cc 沙箱内直接 `set -a; . $HOME/.clawd/
50201
- // deploy-kit/.secrets/aliyun.env; set +a` 后调 aliyun CLI(env 凭证绕过沙箱外的 ~/.aliyun/),所以这里**额外**把
50202
- // 这个凭证文件加进 allowRead(denyRead '~/' 之上的精确凿洞,单文件、最小暴露,同 ~/.npmrc 先例)。
50198
+ // 阿里云凭证:**复用共享 deploy-kit 单源**($HOME/.clawd/deploy-kit/.secrets/aliyun.env.local,使用者自己写、
50199
+ // 全 FC persona 共用;bundle 不再 ship AK,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md),不在 persona
50200
+ // 目录另存一份。app-builder 的 FC 部署走 daemon 侧脚本(沙箱外)故其 profile 无需 carve 这个路径;html-slides
50201
+ // 没有 daemon 侧流程、要在 cc 沙箱内直接 `set -a; . $HOME/.clawd/deploy-kit/.secrets/aliyun.env.local; set +a`
50202
+ // 后调 aliyun CLI(env 凭证绕过沙箱外的 ~/.aliyun/),所以这里**额外**把这两个凭证文件加进 allowRead
50203
+ // (denyRead '~/' 之上的精确凿洞,单文件、最小暴露,同 ~/.npmrc 先例;aliyun.env 是老机器上的遗留文件)。
50203
50204
  // excludedCommands: ['aliyun *'] —— 额外把 aliyun CLI 放沙箱外跑(逃出 seatbelt 直接用宿主凭证/网络),
50204
50205
  // 与上面沙箱内 env 凭证方案并存,按运行时实际命令前缀匹配生效。
50205
50206
  sandboxProfile: {
@@ -50209,7 +50210,7 @@ var DEFAULT_PERSONAS = [
50209
50210
  },
50210
50211
  sandbox: {
50211
50212
  filesystem: {
50212
- allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store", "~/.clawd/deploy-kit/.secrets/aliyun.env"],
50213
+ allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store", "~/.clawd/deploy-kit/.secrets/aliyun.env", "~/.clawd/deploy-kit/.secrets/aliyun.env.local"],
50213
50214
  allowWrite: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"]
50214
50215
  },
50215
50216
  network: {
@@ -70910,7 +70911,7 @@ function computeMethodAccess(args) {
70910
70911
  }
70911
70912
 
70912
70913
  // src/version.ts
70913
- var version = "0.2.540".length > 0 ? "0.2.540" : "dev";
70914
+ var version = "0.2.542".length > 0 ? "0.2.542" : "dev";
70914
70915
 
70915
70916
  // src/cli-probe/probe.ts
70916
70917
  var fs78 = __toESM(require("fs"), 1);
@@ -1,4 +1,7 @@
1
- # 阿里云访问凭证(所有 FC persona 共用一份)。复制为同目录 aliyun.env 并填实际值;
2
- # aliyun.env 不进 git(见 .gitignore),daemon 启动不覆盖。
1
+ # 阿里云 RAM AccessKey(publish.sh / remove-extension.sh 经 ensure-credentials.sh source)。
2
+ # clawd 不随包 ship 任何一把 AK:把自己的 AK/SK 写进同目录的 aliyun.env.local(推荐,永不被 OTA 覆盖)
3
+ # 或 aliyun.env;两个都不进 git(clawd/.gitignore 只放行 *.example)。云上不用文件,gateway 经 env 注入。
4
+ # 需要权限(按 90 天 ActionTrail 反推):FC(cn-hangzhou)+ SLS 的 serverless-cn-hangzhou-* project + 证书只读;
5
+ # 没见到 OSS 调用(大代码包是否走 OSS 中转未验证,缺了 s deploy 会在 ActionTrail 里报 NoPermission)。
3
6
  ALIBABA_CLOUD_ACCESS_KEY_ID=replace-me
4
7
  ALIBABA_CLOUD_ACCESS_KEY_SECRET=replace-me
@@ -1,15 +1,12 @@
1
- # 阿里云 RAM AccessKey 个人 override(本机专用)
1
+ # 阿里云 RAM AccessKey(本机专用)
2
2
  #
3
- # 复制这份为同目录下 aliyun.env.local,填自己的 AK/SK,publish.sh / remove-extension.sh 会在
4
- # source 完 shared 的 aliyun.env 之后再 source 这份(.local 里的值覆盖 shared 里的)。
3
+ # 复制这份为同目录下 aliyun.env.local,填自己的 AK/SK。publish.sh / remove-extension.sh 会依次
4
+ # source aliyun.env(如果有)→ aliyun.env.local,后者的值覆盖前者。
5
5
  #
6
- # .local 后缀由 daemon refreshDeployKit 特判:**永远不会被 OTA 覆盖**,跟 shared aliyun.env
7
- # (每次 daemon 启动会被 defaults 里的新版覆盖)是两回事。
6
+ # .local 后缀由 daemon refreshDeployKit 特判:**永远不会被 OTA 覆盖**。
8
7
  #
9
- # 什么时候需要用 .local:
10
- # - 你想用自己的阿里云账号部署 FC(不想让别人用 clawd ship 的 demo AK 部到你账号)
11
- # - 你有权限收敛过的自定义 AK(比如只在某个特定 region 有 FC 权限)
12
- #
13
- # 不需要用 .local 时(大部分情况):删掉这个 .local 文件、直接跑 clawd defaults,OTA 后自动拿到新 demo 凭证。
8
+ # 2026-09-18 起 clawd 不再随包 ship 共享 demo AK(上一把随 npm 包发出去 69 秒就被 TruffleHog 收割,
9
+ # 主账号被阿里云风控锁;见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md)——本机发布必须配这份。
10
+ # 老机器上 OTA 留下的 aliyun.env 里那把 AK 已泄露、不可再用,不用删,配了 .local 就会盖过它。
14
11
  ALIBABA_CLOUD_ACCESS_KEY_ID=replace-me
15
12
  ALIBABA_CLOUD_ACCESS_KEY_SECRET=replace-me
@@ -4,9 +4,9 @@
4
4
  # 被 `source` 进来,再调 ensure_credentials。跟 ensure-toolchain.sh 是一对:
5
5
  # 那个管「命令在不在」,这个管「命令拿什么身份跑」。
6
6
  #
7
- # 硬约束:**全程不碰用户全局 ~/.s**。clawd 发布用的是 ship 出来的共享 demo AK,
8
- # 而 ~/.s/access.yaml 里的 default 是用户自己账号的 Serverless Devs 凭证——它是用户的
9
- # 东西,不是我们的。做法对齐本 kit 处理 aliyun CLI 的方式(凭证只进本次进程的 env,
7
+ # 硬约束:**全程不碰用户全局 ~/.s**。clawd 发布用的是 deploy-kit 自己那份 AK(本机 .secrets/
8
+ # 下使用者写的文件,云上是 gateway 注入的 env),而 ~/.s/access.yaml 里的 default 是用户自己账号的
9
+ # Serverless Devs 凭证——它是用户的东西,不是我们的。做法对齐本 kit 处理 aliyun CLI 的方式(凭证只进本次进程的 env,
10
10
  # 全局 ~/.aliyun/ 一个字节不碰):把 Serverless Devs 的配置家目录整个指到 deploy-kit
11
11
  # 名下,access.yaml 写在那里。
12
12
  # ============================================================
@@ -18,27 +18,27 @@
18
18
  # 里的 access 字段,本改动前 scaffold 的老项目(s.yaml 写着 default)照样走这条。
19
19
  S_ACCESS_ALIAS=clawd-fc
20
20
 
21
- # 分层加载阿里云 AK 进 env:shared demo(OTA 每次启动覆盖)→ 本机 .local override(永不被覆盖)。
21
+ # 分层加载阿里云 AK 进 env,三层平铺、后读的覆盖先读的:
22
+ # 1. `$KIT_DIR/.secrets/aliyun.env` —— 使用者自己写的(或 2026-09-18 之前 OTA 留下的旧文件);
23
+ # 2. `$KIT_DIR/.secrets/aliyun.env.local` —— 使用者自己写的,refreshDeployKit 永不覆盖;
24
+ # 3. 进程 env 里已有的 `ALIBABA_CLOUD_ACCESS_KEY_ID/_SECRET` —— 云上容器那条路:Pod 里没有
25
+ # `.secrets/`(`cloud-host/provision/build-image.mjs` 刻意把它剔出镜像层——镜像要分发,凭据
26
+ # 进层就洗不掉了),AK 由 gateway 经 **MCP server 的 per-server env** 交到调用本脚本的那个
27
+ # 进程里(M1b Step 9)。不落盘是有意的:写成文件的话 agent 一个 `cat` 就看见了。
22
28
  #
23
- # 两种来源,**文件优先、env 兜底**:
24
- # - 本机:`$KIT_DIR/.secrets/aliyun.env`(+ 可选 .local),OTA 刷新;
25
- # - 云上容器:没有 `.secrets/`(`cloud-host/provision/build-image.mjs` 刻意把它剔出镜像层
26
- # ——镜像要分发,凭据进层就洗不掉了),AK 由 gateway 经 **MCP server 的 per-server env**
27
- # 交到调用本脚本的那个进程里(M1b Step 9)。这条分支不落盘是有意的:写成文件的话
28
- # agent 一个 `cat` 就看见了,而 env 只有这个子进程有。
29
+ # clawd **不再随包 ship 任何一把 AK**(2026-09-18 起,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md:
30
+ # 上一把随 npm 包发出去 69 秒就被 TruffleHog 收割,主账号被风控锁)。三层都空 = 使用者还没配,fail-loud。
29
31
  ensure_aliyun_env() {
30
32
  local kit="${KIT_DIR:?ensure_aliyun_env 需要调用方先设 KIT_DIR}"
31
- if [ -f "$kit/.secrets/aliyun.env" ]; then
32
- set -a; . "$kit/.secrets/aliyun.env"; set +a
33
- # aliyun.env.local: 本机个人 override(永远不被 OTA 覆盖,见 refreshDeployKit)。有就后 source 覆盖 env。
34
- # 写成 if 而不是 `[ -f ] && { }`:后者在函数末尾会把「文件不存在」变成函数返回 1,调用方 set -e 直接中止。
35
- if [ -f "$kit/.secrets/aliyun.env.local" ]; then
36
- set -a; . "$kit/.secrets/aliyun.env.local"; set +a
33
+ local f
34
+ # 写成 if 而不是 `[ -f ] && { }`:后者在函数末尾会把「文件不存在」变成函数返回 1,调用方 set -e 直接中止。
35
+ for f in "$kit/.secrets/aliyun.env" "$kit/.secrets/aliyun.env.local"; do
36
+ if [ -f "$f" ]; then
37
+ set -a; . "$f"; set +a
37
38
  fi
38
- elif [ -n "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ] && [ -n "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]; then
39
- : # 云上:值已经在本进程 env 里,不落文件
40
- else
41
- echo "❌ 缺 $kit/.secrets/aliyun.env(clawd ship 的共享 demo 凭证,OTA 自动刷新),env 里也没有 ALIBABA_CLOUD_ACCESS_KEY_ID/_SECRET。参考 .secrets/aliyun.env.example 填写。" >&2
39
+ done
40
+ if [ -z "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ] || [ -z "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]; then
41
+ echo "❌ 没有阿里云 AK:把自己的 AK/SK 写进 $kit/.secrets/aliyun.env.local(参考同目录 aliyun.env.local.example;这个文件不会被 OTA 覆盖),云上则由 gateway 经 env 注入。" >&2
42
42
  return 1
43
43
  fi
44
44
  export ALIBABA_CLOUD_REGION_ID="${REGION:?config.env 缺 REGION}"
@@ -80,7 +80,7 @@ ensure_s_access() {
80
80
  # 把 CLI 原文摆出来,让读的人按原文判断。
81
81
  echo "❌ aliyun sts GetCallerIdentity 失败,拿不到 AccountId。aliyun 原文:" >&2
82
82
  echo "$ident" >&2
83
- echo " 排查顺序:① 上面这行 CLI 原文说的是什么 ② $kit/.secrets/aliyun.env(及 .local)里的 AK 是否有效 ③ config.env 的 REGION" >&2
83
+ echo " 排查顺序:① 上面这行 CLI 原文说的是什么 ② $kit/.secrets/aliyun.env.local(或 aliyun.env)里的 AK 是否有效——2026-09-18 之前 OTA 发的那把已泄露、不可再用,得换自己的 ③ config.env 的 REGION" >&2
84
84
  return 1
85
85
  }
86
86
  # 用 node 不用 python3:目标机器保证有 node(clawd 本身就是 node 跑的),不保证有 python
@@ -78,11 +78,12 @@ beforeEach(() => {
78
78
  mkdirSync(join(home, '.s'), { recursive: true })
79
79
  mkdirSync(bin, { recursive: true })
80
80
 
81
- // 真脚本进沙箱 kit(.secrets 用假凭证,绝不碰 repo 里 ship 的那份)
81
+ // 真脚本进沙箱 kit。.secrets 按生产形状:bundle 只带 *.example(2026-09-18 起 AK 不再随包
82
+ // 分发,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md),本机凭证是使用者自己写的 .local。
82
83
  cpSync(SCRIPTS_DIR, join(kit, 'scripts'), { recursive: true })
83
84
  writeFileSync(
84
- join(kit, '.secrets', 'aliyun.env'),
85
- 'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-SHARED-DEMO\nALIBABA_CLOUD_ACCESS_KEY_SECRET=shared-demo-secret\n',
85
+ join(kit, '.secrets', 'aliyun.env.local'),
86
+ 'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-MY-OWN\nALIBABA_CLOUD_ACCESS_KEY_SECRET=my-own-secret\n',
86
87
  )
87
88
  writeFileSync(join(home, '.s', 'access.yaml'), USER_ACCESS_YAML)
88
89
  writeAliyunShim(bin)
@@ -127,8 +128,8 @@ describe('ensure_credentials', () => {
127
128
  runInKit('ensure_credentials')
128
129
  const yaml = kitAccessYaml()
129
130
  expect(yaml).toContain("AccountID: '5566778899001122'")
130
- expect(yaml).toContain('AccessKeyID: LTAI-SHARED-DEMO')
131
- expect(yaml).toContain('AccessKeySecret: shared-demo-secret')
131
+ expect(yaml).toContain('AccessKeyID: LTAI-MY-OWN')
132
+ expect(yaml).toContain('AccessKeySecret: my-own-secret')
132
133
  })
133
134
 
134
135
  it('profile 名是 clawd-fc 而不是 default', () => {
@@ -151,14 +152,26 @@ describe('ensure_credentials', () => {
151
152
  expect(mode.toString(8)).toBe('600')
152
153
  })
153
154
 
154
- it('aliyun.env.local 覆盖 shared 凭证', () => {
155
+ // 存量机器:OTA 停发 aliyun.env 之后 refreshDeployKit 不再覆盖也不删它,旧文件会留在盘上。
156
+ // 有 .local 时 .local 必须盖过它(否则老用户配了自己的 AK 还在用那把已停用的)。
157
+ it('legacy aliyun.env 仍被读,但 .local 覆盖它', () => {
155
158
  writeFileSync(
156
- join(box.kit, '.secrets', 'aliyun.env.local'),
157
- 'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-MY-OWN\nALIBABA_CLOUD_ACCESS_KEY_SECRET=my-own-secret\n',
159
+ join(box.kit, '.secrets', 'aliyun.env'),
160
+ 'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-STALE-OTA\nALIBABA_CLOUD_ACCESS_KEY_SECRET=stale-ota-secret\n',
158
161
  )
159
162
  runInKit('ensure_credentials')
160
163
  expect(kitAccessYaml()).toContain('AccessKeyID: LTAI-MY-OWN')
161
- expect(kitAccessYaml()).toContain('AccessKeySecret: my-own-secret')
164
+ expect(kitAccessYaml()).not.toContain('LTAI-STALE-OTA')
165
+ })
166
+
167
+ it('只有 aliyun.env 没有 .local 也能用(使用者直接写 aliyun.env 的老习惯)', () => {
168
+ rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
169
+ writeFileSync(
170
+ join(box.kit, '.secrets', 'aliyun.env'),
171
+ 'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-PLAIN-FILE\nALIBABA_CLOUD_ACCESS_KEY_SECRET=plain-file-secret\n',
172
+ )
173
+ runInKit('ensure_credentials')
174
+ expect(kitAccessYaml()).toContain('AccessKeyID: LTAI-PLAIN-FILE')
162
175
  })
163
176
 
164
177
  it('调 aliyun 时显式传 AK 和 region,不靠环境变量的隐式优先级', () => {
@@ -169,8 +182,8 @@ describe('ensure_credentials', () => {
169
182
  writeAliyunShim(box.bin, '5566778899001122', log)
170
183
  runInKit('ensure_credentials')
171
184
  const argv = readFileSync(log, 'utf8')
172
- expect(argv).toContain('--access-key-id LTAI-SHARED-DEMO')
173
- expect(argv).toContain('--access-key-secret shared-demo-secret')
185
+ expect(argv).toContain('--access-key-id LTAI-MY-OWN')
186
+ expect(argv).toContain('--access-key-secret my-own-secret')
174
187
  expect(argv).toContain('--region cn-hangzhou')
175
188
  })
176
189
 
@@ -182,17 +195,17 @@ describe('ensure_credentials', () => {
182
195
  expect(kitAccessYaml()).toContain("AccountID: '5566778899001122'")
183
196
  })
184
197
 
185
- it('缺共享凭证文件、env 里也没有 AK 时 fail-loud', () => {
186
- rmSync(join(box.kit, '.secrets', 'aliyun.env'))
187
- expect(() => runInKit('ensure_credentials')).toThrow()
198
+ it('aliyun.env / .local 都没有、env 里也没有 AK 时 fail-loud,文案指到 .local', () => {
199
+ rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
200
+ expect(() => runInKit('ensure_credentials')).toThrow(/aliyun\.env\.local/)
188
201
  expect(existsSync(join(box.kit, '.s-home', '.s', 'access.yaml'))).toBe(false)
189
202
  })
190
203
 
191
204
  // 云上分支(persona 上云 M1b Step 9):容器里没有 `.secrets/`——`build-image.mjs` 刻意把它
192
205
  // 剔出镜像层(镜像要分发,凭据进层洗不掉)。AK 由 gateway 经 **MCP server 的 per-server env**
193
206
  // 交到调用本脚本的那个子进程里,不落文件:写成文件的话 agent 一个 `cat` 就看见了。
194
- it('没有 .secrets/aliyun.env 但 env 里有 AK 时用 env(云上容器那条路)', () => {
195
- rmSync(join(box.kit, '.secrets', 'aliyun.env'))
207
+ it('没有 .secrets/ 凭证文件但 env 里有 AK 时用 env(云上容器那条路)', () => {
208
+ rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
196
209
  const out = execFileSync(
197
210
  'bash',
198
211
  [
@@ -221,7 +234,7 @@ printf 'ok %s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
221
234
  expect(userAccessYaml()).toContain('LTAI-USER-OWN-KEY')
222
235
  })
223
236
 
224
- it('文件在就优先用文件(云上那条只是兜底,不能反过来盖掉本机 shared 凭证)', () => {
237
+ it('文件在就优先用文件(云上那条只是兜底,不能反过来盖掉本机 .local 凭证)', () => {
225
238
  const out = execFileSync(
226
239
  'bash',
227
240
  [
@@ -244,6 +257,7 @@ printf 'id=%s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
244
257
  encoding: 'utf8',
245
258
  },
246
259
  )
260
+ expect(out).toContain('id=LTAI-MY-OWN')
247
261
  expect(out).not.toContain('LTAI-FROM-ENV')
248
262
  })
249
263
  })
@@ -58,7 +58,7 @@ if ! grep -qxF 's.*.yaml' "$EXT_DIR/.gitignore" 2>/dev/null; then
58
58
  echo " 📝 .gitignore 补 s.*.yaml (渲出的 s.int.yaml / s.prod.yaml 含 key,不进仓库;记得把 .gitignore 推上去)"
59
59
  fi
60
60
 
61
- # 2) 工具链 + 阿里云凭证(分层:shared demo + 可选 local override)
61
+ # 2) 工具链 + 阿里云凭证(使用者自己的 .secrets/aliyun.env.local,云上是 env;见 ensure-credentials.sh)
62
62
  source "$KIT_DIR/scripts/ensure-toolchain.sh"
63
63
  ensure_toolchain
64
64
  source "$KIT_DIR/scripts/ensure-credentials.sh"
@@ -28,7 +28,7 @@ TABLE_PREFIX_INT="${TABLE_PREFIX}int_"
28
28
  source "$KIT_DIR/scripts/ensure-toolchain.sh"
29
29
  ensure_toolchain
30
30
 
31
- # 阿里云凭证(分层:shared demo + 可选 local override)+ deploy-kit 私有的 s profile
31
+ # 阿里云凭证(使用者自己的 .secrets/aliyun.env.local,云上是 env)+ deploy-kit 私有的 s profile
32
32
  source "$KIT_DIR/scripts/ensure-credentials.sh"
33
33
  ensure_credentials
34
34
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "_comment": "preinstall ship 进 daemon defaults,daemon 启动时 refreshDaemonManagedDirs 把这文件同步到 ~/.clawd*/personas/persona-app-builder/.mcp.json。**这里只有声明,没有值**:`${VAR}` 占位由 daemon 在 spawn 时从凭据表渲进 per-server env / headers(见 daemon/src/persona/mcp-secret-render.ts),渲染产物是另一份 0600 文件、同名 server 压过本文件,所以 agent 在 persona 目录里读不到任何 key。supabase:用 @aliyun-rds/supabase-mcp-server Mode 2 单实例直连(不再用 aliyun AK),底下接阿里云托管 supabase。这三个 env 名不是我们发明的——该包的 commander option 默认值就取 process.env.SUPABASE_URL / SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY,所以不再传 --supabase-* CLI 参数(参数会进 ps 输出,等于没藏)。**不要往这里加 --jwt-secret / SUPABASE_AUTH_JWT_SECRET**:jwt-secret 是该实例的 JWT 签发密钥,拿到它可以自签任意 role/任意 user 的 token(含 service_role),下发出去等于把 anon/service key 的轮换能力一起交出去;而 MCP server 里它唯一的用处是 verify_jwt_secret 这个自检工具报个 found/preview。github:GitHub 官方远程 MCP(spec 2026-09-14-app-builder-github-mcp-design),建仓 / 提交文件都由 agent 按 .claude/skills/app-builder-projects 走它,本机不再依赖 gh CLI。Authorization 走 `${GITHUB_TOKEN}` 占位而不是留空让 Claude Code 自己 OAuth:没占位的 http server 不进 daemon 的渲染产物,只剩 cwd 里这份项目级声明,daemon 起的 headless 会话过不了 Claude Code 的「项目 MCP 待批准」和交互式 OAuth 两关(2026-09-14 实测)。`GITHUB_TOKEN` 是保留变量名 = 当前用户的 GitHub 身份(spec 2026-09-15-github-auth-unify §4.1):本机由 daemon 从机器级身份(设置 → 账号关联,存在 git 的凭据存储;~/.clawd/secrets/github.env 是 git 没配 helper 时的退路)渲进产物;云上由中心从使用者的 GitHub 身份供值、代理时注 Bearer,不填 PAT。值本身随 OTA 下发的边界与收敛方向见 doc/glossary/persona-cloud.md。",
2
+ "_comment": "preinstall ship 进 daemon defaults,daemon 启动时 refreshDaemonManagedDirs 把这文件同步到 ~/.clawd*/personas/persona-app-builder/.mcp.json。**这里只有声明,没有值**:`${VAR}` 占位由 daemon 在 spawn 时从凭据表渲进 per-server env / headers(见 daemon/src/persona/mcp-secret-render.ts),渲染产物是另一份 0600 文件、同名 server 压过本文件,所以 agent 在 persona 目录里读不到任何 key。supabase:用 @aliyun-rds/supabase-mcp-server Mode 2 单实例直连(不再用 aliyun AK),底下接阿里云托管 supabase。这三个 env 名不是我们发明的——该包的 commander option 默认值就取 process.env.SUPABASE_URL / SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY,所以不再传 --supabase-* CLI 参数(参数会进 ps 输出,等于没藏)。**不要往这里加 --jwt-secret / SUPABASE_AUTH_JWT_SECRET**:jwt-secret 是该实例的 JWT 签发密钥,拿到它可以自签任意 role/任意 user 的 token(含 service_role),下发出去等于把 anon/service key 的轮换能力一起交出去;而 MCP server 里它唯一的用处是 verify_jwt_secret 这个自检工具报个 found/preview。github:GitHub 官方远程 MCP(spec 2026-09-14-app-builder-github-mcp-design),建仓 / 提交文件都由 agent 按 .claude/skills/app-builder-projects 走它,本机不再依赖 gh CLI。Authorization 走 `${GITHUB_TOKEN}` 占位而不是留空让 Claude Code 自己 OAuth:没占位的 http server 不进 daemon 的渲染产物,只剩 cwd 里这份项目级声明,daemon 起的 headless 会话过不了 Claude Code 的「项目 MCP 待批准」和交互式 OAuth 两关(2026-09-14 实测)。`GITHUB_TOKEN` 是保留变量名 = 当前用户的 GitHub 身份(spec 2026-09-15-github-auth-unify §4.1):本机由 daemon 从机器级身份(设置 → 账号关联,存在 git 的凭据存储;~/.clawd/secrets/github.env 是 git 没配 helper 时的退路)渲进产物;云上由中心从使用者的 GitHub 身份供值、代理时注 Bearer,不填 PAT。值不随 OTA 下发(本机 ~/.clawd/secrets/supabase.env,云上 gateway 注入),来龙去脉见 doc/glossary/persona-cloud.md。",
3
3
  "mcpServers": {
4
4
  "github": {
5
5
  "type": "http",
@@ -92,15 +92,15 @@
92
92
 
93
93
  ## 后端:supabase MCP
94
94
 
95
- **`supabase`** —— 后端数据/认证/存储,唯一的 MCP 支柱。这份 Supabase **是阿里云托管 supabase 实例**(`http://121.196.249.178:80`),全局 MCP / clawos / lovagent / moltoffer / clawd 都指向这一台。**不是**云上 `supabase.com` 的实例。开工前确认能连上:
95
+ **`supabase`** —— 后端数据/认证/存储,唯一的 MCP 支柱。这份 Supabase **是阿里云托管 supabase 实例**(地址就是凭据表里的 `SUPABASE_URL`,你看不到值也不用看),**不是**云上 `supabase.com` 的实例。开工前确认能连上:
96
96
 
97
97
  - 读表结构、跑 SQL、看 auth 用户都走这个 MCP,不要凭记忆猜 schema
98
- - **凭据值你看不到,也不需要看到**:`extension-kit/config.env` 与 `server/.env.example` 里只有变量名(`${SUPABASE_URL}` / `${SUPABASE_KEY}`),值由 daemon 在起 MCP server 时才注进那个子进程。`createProject` 时 scaffold 会把项目的 `server/.env` 渲好,直接 `pnpm dev` 就能连上——**不要**去别处找 key 往文件里抄
98
+ - **凭据值你看不到,也不需要看到**:`extension-kit/config.env` 与 `server/.env.example` 里只有变量名(`${SUPABASE_URL}` / `${SUPABASE_KEY}`),值由 daemon 在起 MCP server 时才注进那个子进程。`createProject` 时 scaffold 会把项目的 `server/.env` 渲好(前提是这台机器配了凭据表:云上由 gateway 注入,本机要有 `~/.clawd/secrets/supabase.env`;没配会渲成空串并 warn),直接 `pnpm dev` 就能连上——**不要**去别处找 key 往文件里抄
99
99
  - **红线**:这是共享生产库。建表 / 迁移前先 `list_tables` 看清现状,新项目的表**必须**带 `TABLE_PREFIX` 沉到 `public` schema(integration 是 `${APP_NAME}_${SLUG}_int_`,prod 是 `${APP_NAME}_${SLUG}_`,如 `helloworld_a1b2_int_click_counter` / `helloworld_a1b2_click_counter`;`APP_NAME` 和 `SLUG` 都从项目 `ext.conf` 读,**不要自己另起一套 slug**),避免和 clawos / 其它项目 / 别人同名 app 的表撞名;**绝不** drop / alter clawos 已有的表,不确定哪些是 clawos 的就先问老板
100
100
  - **表两套,DDL 一份**:表结构写在 `server/db/schema.sql`,表名用 `__TABLE_PREFIX__visits` 占位;`node <skill>/scripts/render-sql.mjs --project <projectDir> --env integration` 渲出 SQL 用 supabase MCP `execute_sql` 跑(`apply_migration` 在阿里云自建实例上不可用),在测试地址验过再 `--env prod` 跑一次。server 代码里表名只经 `tableName('visits')`(`server/src/table-name.ts`,读 env `TABLE_PREFIX`),不写死
101
101
  - 建了表记得把**基础名**(如 `visits`)填进 `ext.conf` 的 `SUPABASE_TABLES`(空格分隔),`removeProject` 据此打印两套清理语句
102
102
 
103
- **易踩的坑**:唯一真源是 **daemon 的凭据表**(`~/.clawd/secrets/` 覆盖 clawd 自带的那份)—— supabase MCP 连它,`publish.sh` 也把它渲染进 s.yaml 给线上用,scaffold 渲项目 `.env` 还是它。项目 `.env` 被手改成别的地址,就会 **MCP 建表落一台 / server 通过 supabase-js 查另一台**,两边 PostgREST 的 schema cache 各自独立 → `PGRST205 schema cache 找不到表`。看到 PGRST 系列错码,先看项目 `.env` 的 `SUPABASE_URL` 是不是被人动过。
103
+ **易踩的坑**:唯一真源是 **daemon 的凭据表**(本机 `~/.clawd/secrets/supabase.env`,云上 gateway 经 env 注入;clawd 自带的只有占位模板)—— supabase MCP 连它,`publish.sh` 也把它渲染进 s.yaml 给线上用,scaffold 渲项目 `.env` 还是它。项目 `.env` 被手改成别的地址,就会 **MCP 建表落一台 / server 通过 supabase-js 查另一台**,两边 PostgREST 的 schema cache 各自独立 → `PGRST205 schema cache 找不到表`。看到 PGRST 系列错码,先看项目 `.env` 的 `SUPABASE_URL` 是不是被人动过。
104
104
 
105
105
  ## 部署:阿里云 FC(serverless)
106
106
 
@@ -111,12 +111,13 @@
111
111
  - 工具链 `aliyun` CLI + Serverless Devs(`s`)由 `deploy-kit/scripts/ensure-toolchain.sh` 在 publish / remove 前自动检测 + 安装,接管发布失败时**不必再排查「CLI 没装」**
112
112
  - 实时推送用 Supabase Realtime(FC 不维持长连接)
113
113
 
114
- ## 阿里云凭证:在共享 deploy-kit 的 `.secrets/`,分层 override
114
+ ## 阿里云凭证:使用者自带,放共享 deploy-kit 的 `.secrets/`
115
115
 
116
- AK/SK 分两层,都放在 `$HOME/.clawd/deploy-kit/.secrets/`、全 FC persona 共用,不在系统环境变量里:
116
+ clawd **不随包 ship 任何一把 AK**。AK/SK 放在 `$HOME/.clawd/deploy-kit/.secrets/`、全 FC persona 共用,不在系统环境变量里:
117
117
 
118
- - **`aliyun.env`** — clawd ship 的**共享 demo 凭证**(RAM 用户 `clawd-fc-developer`,权限收敛)。每次 daemon 启动会用 defaults 里的最新版覆盖本文件(OTA 即升级)
119
- - **`aliyun.env.local`**(可选)— 本机个人 override,永远不被 OTA 覆盖。用户想用自己的 AK 就复制 `aliyun.env.local.example` → `aliyun.env.local` 填自己的值
118
+ - **`aliyun.env.local`** — 使用者自己的 AK,永远不被 OTA 覆盖。复制 `aliyun.env.local.example` → `aliyun.env.local` 填值
119
+ - **`aliyun.env`**(可有可无)— 也会被读,`.local` 覆盖它。老机器上 2026-09-18 之前 OTA 留下的这份里的 AK 已泄露、不可再用
120
+ - 云上没有这两个文件,AK 由 gateway 经 MCP server 的 env 注入
120
121
 
121
122
  手动排障要跑 `aliyun` / `s` 命令时,在**同一条 Bash** 里加载再用(shell 变量不跨调用留存):
122
123
 
@@ -129,7 +130,7 @@ aliyun_ak fc GET /2023-03-30/custom-domains # aliyun 一律走 aliyun_a
129
130
  s deploy -y -t s.int.yaml --access "$S_ACCESS_ALIAS" # s 一律显式带 profile + 指明哪个环境的 s 文件(s.int.yaml / s.prod.yaml)
130
131
  ```
131
132
 
132
- **红线**:绝不写用户全局 `~/.s/access.yaml`(那里是用户自己账号的凭证,盖上去不可恢复);绝不 `echo` / 打印 / 写进日志或提交记录里暴露 SK;绝不把 `.secrets/` 拷进项目代码;shared `aliyun.env` 为空先停下提醒老板。
133
+ **红线**:绝不写用户全局 `~/.s/access.yaml`(那里是用户自己账号的凭证,盖上去不可恢复);绝不 `echo` / 打印 / 写进日志或提交记录里暴露 SK;绝不把 `.secrets/` 拷进项目代码;`ensure_credentials` 报「没有阿里云 AK」就停下提醒老板配 `aliyun.env.local`,别自己去找别的 AK 填。
133
134
 
134
135
  ## 任务分级与节奏
135
136
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以固化的是「发布管道」,不是技术栈。
8
8
 
9
- - **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env`)
9
+ - **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env.local`)
10
10
  - **persona 特化(本目录)**:`config.env`(注入值) + `contract/s.yaml.tmpl`(占位符清单) + `examples/`(默认 `nestjs-react`)
11
11
 
12
12
  ## 目录
@@ -14,7 +14,7 @@ FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以
14
14
  ```
15
15
  # 共享 deploy-kit($HOME/.clawd/deploy-kit/,daemon 维护,全 persona 共用)
16
16
  deploy-kit/
17
- ├── .secrets/aliyun.env 阿里云凭证(单源)
17
+ ├── .secrets/aliyun.env.local 阿里云凭证(单源,使用者自己写;bundle 只带 *.example)
18
18
  ├── contract/bootstrap FC 启动入口(Node 参考实现:find node + cd + exec)
19
19
  └── scripts/
20
20
  ├── new-extension.sh 从示例生成新 extension(纯 copy,daemon 自动跑)
@@ -1,4 +1,4 @@
1
- # supabase 连接串的**唯一真源是 daemon 的凭据表**(`~/.clawd/secrets/` 覆盖 clawd 自带那份)。
1
+ # supabase 连接串的**唯一真源是 daemon 的凭据表**(本机 `~/.clawd/secrets/supabase.env`,云上 gateway 经 env 注入)。
2
2
  # 本文件是模板:scaffold(new-extension.sh)把下面的占位引用展开成同目录的 `.env` 给本地 dev 用;
3
3
  # 线上那份由 publish.sh 渲进 s.yaml 的 environmentVariables。两条路取同一张表的同一个变量名,
4
4
  # 所以不会出现「本地连一台、线上连另一台」的漂移(那会表现成 PGRST205 找不到表)。
@@ -6,7 +6,7 @@
6
6
 
7
7
  FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以固化的是「发布管道」,不是技术栈。
8
8
 
9
- - **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env`)
9
+ - **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env.local`)
10
10
  - **persona 特化(本目录)**:`config.env`(dataclaw 注入值) + `contract/s.yaml.tmpl`(占位符清单) + `hooks/pre-deploy.sh`(发布前置) + `examples/`(默认 `nestjs-react`)
11
11
 
12
12
  ## 目录
@@ -14,7 +14,7 @@ FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以
14
14
  ```
15
15
  # 共享 deploy-kit($HOME/.clawd/deploy-kit/,daemon 维护,全 persona 共用)
16
16
  deploy-kit/
17
- ├── .secrets/aliyun.env 阿里云凭证(单源)
17
+ ├── .secrets/aliyun.env.local 阿里云凭证(单源,使用者自己写;bundle 只带 *.example)
18
18
  ├── contract/bootstrap FC 启动入口(Node 参考实现:find node + cd + exec)
19
19
  └── scripts/
20
20
  ├── new-extension.sh 从示例生成新 extension(纯 copy,daemon 自动跑)
@@ -1,5 +1,5 @@
1
1
  # ===== 平台级固定变量(一次配好,所有 extension 共用)=====
2
- # 阿里云凭证不在这里:从 .secrets/aliyun.env 现读(见 CLAUDE.md)
2
+ # 阿里云凭证不在这里:从 .secrets/aliyun.env.local 现读(见 CLAUDE.md)
3
3
 
4
4
  REGION=cn-hangzhou
5
5
 
@@ -1,29 +1,47 @@
1
- # `src/secrets/` —— 随 OTA 下发的共享凭据表
1
+ # `src/secrets/` —— 凭据表的 bundle 目录(只有占位模板,没有值)
2
2
 
3
- 这里的每个 `<name>.env` 是一条**命名凭据**的值,`name` 对齐环境清单
4
- (`EnvironmentManifest.secrets[].name`)。daemon 在 spawn 时把它们合成一张
3
+ 每个 `<name>.env.example` 是一条**命名凭据**的占位模板,`name` 对齐环境清单
4
+ (`EnvironmentManifest.secrets[].name`)。daemon 在 spawn 时把凭据表合成一张
5
5
  `Record<envName, value>`,只交给**真正用它的那个子进程**(MCP server / deploy-kit 发布脚本),
6
6
  agent 主进程 env 一条都不放。读法与合并顺序见 `../deploy/secret-table.ts`。
7
7
 
8
- ## 为什么单独一个目录,而不是继续写在 persona bundle 里
8
+ ## 这里不放值:clawd 不随包 ship 任何凭据
9
9
 
10
- 原先 supabase 的 url / anon / service-role 是**明文 CLI 参数**硬写在
11
- `persona-app-builder/.mcp.json` 里的。那个文件在 persona 目录下,agent 一个 `Read` 就看得见
12
- ——等于每次会话都把 key 摊给模型。挪到这里之后:
10
+ 本目录随 npm 包 / OTA 发给所有用户,**放进来的每一把 key 都等于公开**——不是比喻:
11
+
12
+ - deploy-kit 的阿里云 AK 曾以「共享 demo 凭证」身份放在 `deploy-kit/.secrets/aliyun.env`,随 npm 包发出去
13
+ **69 秒**就被 TruffleHog 收割、90 天内被 100+ 个境外 IP 验证约 600 次,最后主账号被阿里云风控锁
14
+ (`specs/2026-09-18-aliyun-ak-leak-rotate-design.md`)。
15
+ - 这里的 supabase 三件套(url / anon / **service-role**)曾经也是这么 ship 的。service-role 绕过 RLS,
16
+ 等于整库管理员;而那台实例除 app-builder 的 demo 表外还承载 clawd 自己的 `clawd_prod` schema
17
+ (`persona_cloud_api_keys` / `device_bindings` / `lark_bot_bindings` 的明文 app_secret……)——
18
+ 随包公开等于把中心库交出去(`specs/2026-09-18-supabase-key-leak-design.md`)。
19
+
20
+ 所以 2026-09-18 起:`*.env` 不进 git(`clawd/.gitignore`),不进 dist(`scripts/copy-defaults.mjs`
21
+ 平移时只放行 `*.example` 与本 README),desktop OTA 打的是 dist 所以同样没有。
13
22
 
14
- - persona 目录(agent 的 cwd 及其上级)里没有任何凭据值;
15
- - 「哪些 key 随 OTA 下发」在**目录层面就是可数的**——将来做收敛(见
16
- `doc/glossary/persona-cloud.md` 的「随 OTA 下发的凭据 = 公开凭据」)时,要删的就是这个目录。
23
+ ## 值从哪来
17
24
 
18
- ## 信任层级:这里的每一把 key 都等于公开
25
+ | 环境 | 来源 |
26
+ | --- | --- |
27
+ | 本机 | **`~/.clawd/secrets/<name>.env`**(凭据表覆盖目录,不随 OTA 覆盖)。照同名 `.example` 抄一份填值即可。改了下一个会话就生效,不用重启 daemon |
28
+ | 云上 | persona 仓库的 GitHub Secrets(同名)→ `register.mjs` → gateway 起 Pod 时经容器 env 交进来,走同一个交付点。**不读这两个目录** |
19
29
 
20
- 本目录随 npm 包 ship 给所有用户,跟 `deploy-kit/.secrets/aliyun.env` 同级。判断风险时按
21
- 「这把 key 落在所有用户手上」算。把 service-role key 换成受限 role 的收敛方向记在 glossary,
22
- 不在 M1b 范围。
30
+ 本机什么都没配:凭据表为空,`persona/mcp-secret-render.ts` 会 warn 缺哪个变量名并渲成空串,MCP server
31
+ 起不来时在会话里响亮报错;deploy-kit 的 `publish.sh` 对缺失占位符 fail-loud。**不会静默用错实例。**
23
32
 
24
- ## 本机覆盖
33
+ 开发者在 repo checkout 里跑 `tsx src/index.ts` 想图省事,也可以把真值放在本目录的 `<name>.env`——它是
34
+ gitignored 的,且 `pnpm build` 不会把它带进 dist。
35
+
36
+ ## 为什么单独一个目录,而不是写在 persona bundle 里
37
+
38
+ 原先 supabase 的 url / anon / service-role 是**明文 CLI 参数**硬写在
39
+ `persona-app-builder/.mcp.json` 里的。那个文件在 persona 目录下,agent 一个 `Read` 就看得见
40
+ ——等于每次会话都把 key 摊给模型。挪到凭据表之后:
25
41
 
26
- `~/.clawd/secrets/<name>.env` 覆盖同名条目(逐个 env 变量覆盖,不是整份替换)。用途:
27
- 部署者用自己的 supabase 实例、或轮换出新 key 又不想等 OTA。该目录不随 OTA 覆盖。
42
+ - persona 目录(agent 的 cwd 及其上级)里没有任何凭据值,只有 `${VAR}` 占位;
43
+ - 「消费方要哪些变量名」在**目录层面就是可数的**——就是这里的 `*.example`。
28
44
 
29
- 云上没有这两个文件——gateway 起 Pod 时把同一张表经容器 env 交进来,走同一个交付点。
45
+ **不放 JWT 签发密钥**(`SUPABASE_AUTH_JWT_SECRET`):它能自签任意 role / 任意 user 的 token(含
46
+ `service_role`),交出去等于连「日后轮换 anon/service key」这个能力一起交出去;MCP server 里它唯一的用处是
47
+ `verify_jwt_secret` 自检。
@@ -0,0 +1,17 @@
1
+ # supabase 凭据(app-builder 系 persona 的 supabase MCP + deploy-kit 发布脚本用)。
2
+ #
3
+ # clawd 不随包 ship 任何一把 supabase key:把自己实例的值写进 **~/.clawd/secrets/supabase.env**
4
+ # (daemon 的凭据表覆盖目录,不随 OTA 覆盖,见 ../deploy/secret-table.ts)。这个目录里的 *.env
5
+ # 不进 git(clawd/.gitignore)、不进 dist(scripts/copy-defaults.mjs 只平移 *.example 与 README)。
6
+ # 云上不用文件:persona 仓库的 GitHub Secrets(同名四个)→ register.mjs → gateway 起 Pod 时经 env 注入。
7
+ #
8
+ # 四个名字都要给:前三个是 @aliyun-rds/supabase-mcp-server 的 commander option 默认值
9
+ # (process.env.SUPABASE_URL / SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY);SUPABASE_KEY 是
10
+ # deploy-kit(s.yaml environmentVariables / 项目 server/.env)的历史名字,值同 anon。
11
+ #
12
+ # **不放 JWT 签发密钥**(SUPABASE_AUTH_JWT_SECRET):它能自签任意 role 的 token,MCP 里唯一用途是
13
+ # verify_jwt_secret 自检,摘掉零功能损失。
14
+ SUPABASE_URL=http://replace-me:80
15
+ SUPABASE_ANON_KEY=replace-me
16
+ SUPABASE_SERVICE_ROLE_KEY=replace-me
17
+ SUPABASE_KEY=replace-me
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.540",
3
+ "version": "0.2.542",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,7 +0,0 @@
1
- # 阿里云 RAM AccessKey — clawd ship 的共享 demo 凭证(publish.sh 先 source 这个)
2
- # 归属 RAM 用户 clawd-fc-developer(独立收敛权限用户,跟 owner 主账号解耦)
3
- # 每次 daemon 启动 refreshDeployKit 会用 defaults 里的最新版覆盖本文件(OTA 即升级)。
4
- # 想用自己的 AK 覆盖:复制 aliyun.env.local.example → aliyun.env.local 并填自己的值。
5
- # 需要权限:AliyunFCFullAccess + AliyunSTSAssumeRoleAccess
6
- ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI5tAi7P7oySa3ohAzaYbj
7
- ALIBABA_CLOUD_ACCESS_KEY_SECRET=NS470lOWTLeeAP9RUADXkpKNOrH5QX
@@ -1,16 +0,0 @@
1
- # supabase —— 阿里云托管 supabase 实例(公网 endpoint 121.196.249.178:80,
2
- # 项目 ra-ae0i57kef06s6ix / clawd-app-builder,杭州可用区J)。
3
- # 消费方两处,都经 daemon 的凭据表交付、都不落 persona 目录:
4
- # - supabase MCP server(persona-app-builder/.mcp.json 的 ${...} 占位)
5
- # —— @aliyun-rds/supabase-mcp-server 的 commander option 默认值就读这三个名字,
6
- # 所以不再传 --supabase-* CLI 参数(参数会出现在 ps 输出里)。
7
- # - deploy-kit 的 publish.sh / new-extension.sh(渲染进 s.yaml 的 environmentVariables
8
- # 与项目 server/.env)—— 那两处历史上叫 SUPABASE_KEY,值同 anon。
9
- #
10
- # **不放 JWT 签发密钥**:它能自签任意 role / 任意 user 的 token(含 service_role),
11
- # 下发出去等于把 anon/service key 的轮换能力一起交出去;而 MCP server 里它唯一的用处是
12
- # verify_jwt_secret 这个自检工具报个 found/preview。摘掉零功能损失。
13
- SUPABASE_URL=http://121.196.249.178:80
14
- SUPABASE_ANON_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNzgzMzEwODU1LCJleHAiOjEzMjkzOTUwODU1fQ.sHLZH8q2SGWYbNPEFOzTFlQEtjVK3z1DlEqoU_5Uyyg
15
- SUPABASE_SERVICE_ROLE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJzZXJ2aWNlX3JvbGUiLCJpYXQiOjE3ODMzMTA4NTUsImV4cCI6MTMyOTM5NTA4NTV9.MdlymSh0DaJdiOVRmM3QnukUDtkOf_Eljh8_fpdLi8Q
16
- SUPABASE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNzgzMzEwODU1LCJleHAiOjEzMjkzOTUwODU1fQ.sHLZH8q2SGWYbNPEFOzTFlQEtjVK3z1DlEqoU_5Uyyg