@clawos-dev/clawd 0.2.451 → 0.2.453
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 +23 -4
- package/dist/deploy-kit/scripts/ensure-credentials.sh +24 -2
- package/dist/deploy-kit/scripts/ensure-credentials.spec.ts +49 -9
- package/dist/deploy-kit/scripts/ensure-toolchain.sh +6 -3
- package/dist/deploy-kit/scripts/publish.sh +1 -1
- package/dist/dispatch/mcp-server.cjs +1 -1
- package/dist/persona-defaults/persona-app-builder/.mcp.json +1 -1
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +6 -3
- package/dist/persona-defaults/persona-app-builder/extension-kit/config.env +3 -3
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.env.example +6 -5
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/guest-D_OYvJIg.css +32 -0
- package/dist/share-ui/assets/{guest-CilettnR.js → guest-Dh-ssMM-.js} +124 -124
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-7QsWRy9Q.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -8804,7 +8804,7 @@ var init_methods = __esm({
|
|
|
8804
8804
|
args: WorkspaceReadArgs
|
|
8805
8805
|
},
|
|
8806
8806
|
"deploy:start": {
|
|
8807
|
-
summary: "\
|
|
8807
|
+
summary: "\u5BF9\u67D0\u4E2A persona \u8D77\u4E00\u6B21**\u65B0\u7684**\u4E0A\u4E91\u626B\u63CF\uFF1A\u5EFA\u4E00\u5F20\u65B0\u5355\u636E\u5E76\u5F02\u6B65\u626B\uFF08\u4EBA\u4F1A\u70B9\u8FD9\u4E2A\u53EA\u53EF\u80FD\u662F\u56E0\u4E3A persona \u8FED\u4EE3\u4E86\uFF0C\u62FF\u65E7\u6E05\u5355\u53BB\u90E8\u7F72\u662F\u9519\u7684\uFF09\u3002**\u5DF2\u586B\u7684\u51ED\u636E\u503C\u548C\u5C65\u7EA6\u9009\u62E9\u4ECE\u4E0A\u4E00\u5F20\u5355\u7EE7\u627F\u8FC7\u6765**\uFF0C\u4E0D\u7528\u6BCF\u8FED\u4EE3\u4E00\u6B21\u91CD\u8D34\u4E00\u904D key\u3002\u5DF2\u7ECF\u5728\u626B\u7684\u8BDD\u8FD4\u56DE\u90A3\u5F20\u3001\u4E0D\u5E76\u53D1\u8D77\u7B2C\u4E8C\u4E2A\u626B\u63CF\u4F1A\u8BDD\u3002\u56DE\u770B\u65E7\u7684\u90A3\u6B21\u8D70 deploy:list + deploy:get\uFF1Bowner-only",
|
|
8808
8808
|
args: DeployStartArgsSchema
|
|
8809
8809
|
},
|
|
8810
8810
|
"deploy:rescan": {
|
|
@@ -54423,13 +54423,20 @@ function buildDeployHandlers(deps) {
|
|
|
54423
54423
|
if (!deps.hasPersona(args.personaId)) {
|
|
54424
54424
|
throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${args.personaId}\uFF09`);
|
|
54425
54425
|
}
|
|
54426
|
-
const
|
|
54427
|
-
if (
|
|
54426
|
+
const inFlight = deps.receipts.list().find((r) => r.personaId === args.personaId && r.status === "scanning");
|
|
54427
|
+
if (inFlight) return view(inFlight);
|
|
54428
|
+
const prev = deps.receipts.list().find((r) => r.personaId === args.personaId);
|
|
54428
54429
|
const receipt = deps.receipts.create({
|
|
54429
54430
|
deployId: deps.genId(),
|
|
54430
54431
|
personaId: args.personaId,
|
|
54431
54432
|
status: "scanning"
|
|
54432
54433
|
});
|
|
54434
|
+
if (prev) {
|
|
54435
|
+
deps.secrets.copyDeployment(prev.deployId, receipt.deployId);
|
|
54436
|
+
if (Object.keys(prev.fulfillment).length > 0) {
|
|
54437
|
+
deps.receipts.update(receipt.deployId, { fulfillment: prev.fulfillment });
|
|
54438
|
+
}
|
|
54439
|
+
}
|
|
54433
54440
|
const scanSessionId = deps.startScan(receipt.deployId, args.personaId);
|
|
54434
54441
|
if (scanSessionId) deps.receipts.update(receipt.deployId, { scanSessionId });
|
|
54435
54442
|
return view(deps.receipts.get(receipt.deployId) ?? receipt);
|
|
@@ -54704,6 +54711,18 @@ function createSecretStore(deps) {
|
|
|
54704
54711
|
}
|
|
54705
54712
|
scheduleFlush();
|
|
54706
54713
|
},
|
|
54714
|
+
copyDeployment(fromDeployId, toDeployId) {
|
|
54715
|
+
const src = entries.filter((e) => e.deployId === fromDeployId);
|
|
54716
|
+
let copied = 0;
|
|
54717
|
+
for (const e of src) {
|
|
54718
|
+
const exists = entries.some((x) => sameScope(x, toDeployId, e.name, e.userId));
|
|
54719
|
+
if (exists) continue;
|
|
54720
|
+
entries.push({ ...e, deployId: toDeployId, updatedAt: deps.now() });
|
|
54721
|
+
copied++;
|
|
54722
|
+
}
|
|
54723
|
+
if (copied > 0) scheduleFlush();
|
|
54724
|
+
return copied;
|
|
54725
|
+
},
|
|
54707
54726
|
resolve(deployId, userId) {
|
|
54708
54727
|
const out = {};
|
|
54709
54728
|
for (const e of entries) {
|
|
@@ -63670,7 +63689,7 @@ function computeMethodAccess(args) {
|
|
|
63670
63689
|
}
|
|
63671
63690
|
|
|
63672
63691
|
// src/version.ts
|
|
63673
|
-
var version = "0.2.
|
|
63692
|
+
var version = "0.2.453".length > 0 ? "0.2.453" : "dev";
|
|
63674
63693
|
|
|
63675
63694
|
// src/cli-probe/probe.ts
|
|
63676
63695
|
var fs68 = __toESM(require("fs"), 1);
|
|
@@ -34,6 +34,25 @@ ensure_aliyun_env() {
|
|
|
34
34
|
export ALIBABA_CLOUD_REGION_ID="${REGION:?config.env 缺 REGION}"
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
# 调 aliyun CLI 的**唯一入口**:把凭证和 region 作为显式参数交出去,不依赖环境变量的隐式优先级。
|
|
38
|
+
#
|
|
39
|
+
# 为什么非这样不可(实测 aliyun 3.3.17,`--mode AK`):`ALIBABA_CLOUD_ACCESS_KEY_ID` /
|
|
40
|
+
# `_SECRET` / `_REGION_ID` 这三个环境变量在这个模式下**根本不被消费**,于是
|
|
41
|
+
# - 机器上没有 `~/.aliyun/config.json`(全新用户的常态,ensure_toolchain 只装 CLI、
|
|
42
|
+
# 从不跑 `aliyun configure`)→ `ERROR: region can't be empty`,第一次发布就跑不起来;
|
|
43
|
+
# - 机器上有 profile(比如用户自己配过阿里云)→ **静默走用户自己的 profile**,等于拿
|
|
44
|
+
# 用户的阿里云身份去部署 extension,跟 access.yaml 那个坑是同一类。
|
|
45
|
+
# 补 `--region` 一个 flag 不够,AK 也必须是 flag——两者都试过。
|
|
46
|
+
#
|
|
47
|
+
# 用法跟 aliyun 一样,省掉 `--mode AK` 和三个凭证参数:aliyun_ak sts GetCallerIdentity
|
|
48
|
+
aliyun_ak() {
|
|
49
|
+
aliyun --mode AK \
|
|
50
|
+
--access-key-id "${ALIBABA_CLOUD_ACCESS_KEY_ID:?aliyun_ak 需要先 ensure_aliyun_env}" \
|
|
51
|
+
--access-key-secret "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:?aliyun_ak 需要先 ensure_aliyun_env}" \
|
|
52
|
+
--region "${ALIBABA_CLOUD_REGION_ID:?aliyun_ak 需要先 ensure_aliyun_env}" \
|
|
53
|
+
"$@"
|
|
54
|
+
}
|
|
55
|
+
|
|
37
56
|
# 把 Serverless Devs 的配置家目录(access.yaml / 组件缓存 / 日志)指到 deploy-kit 名下,
|
|
38
57
|
# 再把当前 env 里的凭证写成 $S_ACCESS_ALIAS profile。
|
|
39
58
|
# s v3 的 rootHome = `$serverless_devs_config_home/.s`(默认 `$HOME/.s`),`s -v` 打印的 s-home 就是它——
|
|
@@ -46,9 +65,12 @@ ensure_s_access() {
|
|
|
46
65
|
local s_home="$kit/.s-home"
|
|
47
66
|
local ident acc
|
|
48
67
|
|
|
49
|
-
ident="$(
|
|
50
|
-
|
|
68
|
+
ident="$(aliyun_ak sts GetCallerIdentity 2>&1)" || {
|
|
69
|
+
# 别只说「检查凭证」——凭证不对只是可能之一,region 缺失 / CLI 装坏 / 网络不通报的是别的话。
|
|
70
|
+
# 把 CLI 原文摆出来,让读的人按原文判断。
|
|
71
|
+
echo "❌ aliyun sts GetCallerIdentity 失败,拿不到 AccountId。aliyun 原文:" >&2
|
|
51
72
|
echo "$ident" >&2
|
|
73
|
+
echo " 排查顺序:① 上面这行 CLI 原文说的是什么 ② $kit/.secrets/aliyun.env(及 .local)里的 AK 是否有效 ③ config.env 的 REGION" >&2
|
|
52
74
|
return 1
|
|
53
75
|
}
|
|
54
76
|
# 用 node 不用 python3:目标机器保证有 node(clawd 本身就是 node 跑的),不保证有 python
|
|
@@ -29,11 +29,33 @@ const USER_ACCESS_YAML = `default:
|
|
|
29
29
|
AccessKeySecret: user-own-secret
|
|
30
30
|
`
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* aliyun CLI shim —— **照真 CLI 的凭证优先级建模**(实测 aliyun 3.3.17,`--mode AK`):
|
|
34
|
+
*
|
|
35
|
+
* - `--access-key-id` / `--access-key-secret` / `--region` 三个 **flag 缺一不可**;
|
|
36
|
+
* - `ALIBABA_CLOUD_*` 环境变量在这个模式下**根本不被消费**——没有 `~/.aliyun/config.json`
|
|
37
|
+
* 的干净机器上只会得到 `region can't be empty`(rc=3),有 profile 的机器上则**静默走用户
|
|
38
|
+
* 自己的 profile**(等于拿用户身份部署)。
|
|
39
|
+
*
|
|
40
|
+
* 所以 shim 只认 flag、不认 env:脚本要是退回去依赖 env 优先级,这里当场红。
|
|
41
|
+
*/
|
|
42
|
+
function writeAliyunShim(bin: string, accountId = '5566778899001122', argvLog?: string): void {
|
|
34
43
|
writeFileSync(
|
|
35
44
|
join(bin, 'aliyun'),
|
|
36
|
-
`#!/usr/bin/env bash
|
|
45
|
+
`#!/usr/bin/env bash
|
|
46
|
+
${argvLog ? `printf '%s\\n' "$*" >> "${argvLog}"` : ''}
|
|
47
|
+
argv=" $* "
|
|
48
|
+
for f in --access-key-id --access-key-secret --region; do
|
|
49
|
+
case "$argv" in
|
|
50
|
+
*" $f "*) ;;
|
|
51
|
+
*) echo "ERROR: region can't be empty" >&2; exit 3 ;;
|
|
52
|
+
esac
|
|
53
|
+
done
|
|
54
|
+
case "$argv" in
|
|
55
|
+
*" sts "*) printf '{"AccountId":"${accountId}","Arn":"acs:ram::${accountId}:user/clawd-fc-developer"}\\n' ;;
|
|
56
|
+
*) printf '{"customDomains":[]}\\n' ;;
|
|
57
|
+
esac
|
|
58
|
+
`,
|
|
37
59
|
{ mode: 0o755 },
|
|
38
60
|
)
|
|
39
61
|
}
|
|
@@ -139,6 +161,27 @@ describe('ensure_credentials', () => {
|
|
|
139
161
|
expect(kitAccessYaml()).toContain('AccessKeySecret: my-own-secret')
|
|
140
162
|
})
|
|
141
163
|
|
|
164
|
+
it('调 aliyun 时显式传 AK 和 region,不靠环境变量的隐式优先级', () => {
|
|
165
|
+
// 真 CLI 在 `--mode AK` 下不消费 ALIBABA_CLOUD_*:干净机器上报 `region can't be empty`
|
|
166
|
+
// 直接跑不起来;有 ~/.aliyun/config.json 的机器上更坏——静默走用户自己的 profile,
|
|
167
|
+
// 等于拿用户的阿里云身份去部署。两种都必须由显式 flag 堵死。
|
|
168
|
+
const log = join(box.root, 'aliyun-argv.log')
|
|
169
|
+
writeAliyunShim(box.bin, '5566778899001122', log)
|
|
170
|
+
runInKit('ensure_credentials')
|
|
171
|
+
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')
|
|
174
|
+
expect(argv).toContain('--region cn-hangzhou')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('机器上没有 aliyun profile 也能拿到 AccountId', () => {
|
|
178
|
+
// 全新用户机器:ensure_toolchain 只装 CLI、从不跑 `aliyun configure`,所以 HOME 下
|
|
179
|
+
// 没有 .aliyun/config.json。严格 shim 复现真 CLI 的这条路径。
|
|
180
|
+
rmSync(join(box.home, '.aliyun'), { recursive: true, force: true })
|
|
181
|
+
runInKit('ensure_credentials')
|
|
182
|
+
expect(kitAccessYaml()).toContain("AccountID: '5566778899001122'")
|
|
183
|
+
})
|
|
184
|
+
|
|
142
185
|
it('缺共享凭证文件时 fail-loud', () => {
|
|
143
186
|
rmSync(join(box.kit, '.secrets', 'aliyun.env'))
|
|
144
187
|
expect(() => runInKit('ensure_credentials')).toThrow()
|
|
@@ -150,13 +193,10 @@ describe('publish.sh', () => {
|
|
|
150
193
|
it('用 clawd-fc profile 调 s deploy,不碰用户全局 ~/.s', () => {
|
|
151
194
|
const log = join(box.root, 's-argv.log')
|
|
152
195
|
writeSShim(box.bin, log)
|
|
153
|
-
//
|
|
196
|
+
// 严格 shim 的自定义域名查询回空 → publish.sh 在 verify 段 exit 1。deploy 之后的事,
|
|
154
197
|
// 不影响本用例要断言的凭证行为,省掉 curl shim。
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`#!/usr/bin/env bash\ncase " $* " in\n *" sts "*) printf '{"AccountId":"5566778899001122"}\\n' ;;\n *) printf '{"customDomains":[]}\\n' ;;\nesac\n`,
|
|
158
|
-
{ mode: 0o755 },
|
|
159
|
-
)
|
|
198
|
+
const aliyunLog = join(box.root, 'aliyun-argv.log')
|
|
199
|
+
writeAliyunShim(box.bin, '5566778899001122', aliyunLog)
|
|
160
200
|
|
|
161
201
|
const ext = join(box.root, 'proj')
|
|
162
202
|
const persona = join(box.root, 'persona')
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
# 在调用 aliyun/s 之前 `source` 进来,再调 ensure_toolchain。
|
|
6
6
|
#
|
|
7
7
|
# 为什么需要它:FC 发布全靠 aliyun CLI + s 两个外部命令,二者都不随 clawd 安装。
|
|
8
|
-
# 新机器上它们不在 PATH →
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# 新机器上它们不在 PATH → ensure-credentials.sh 的 `aliyun_ak sts ...` stdout 为空 →
|
|
9
|
+
# JSON.parse 空串报错,且死在第一个 ::stage:: marker 之前 → daemon 只能报 [unknown] 阶段。
|
|
10
|
+
# 这个脚本补的就是这一环。
|
|
11
|
+
#
|
|
12
|
+
# 注意它**只装不配**:不会跑 `aliyun configure`,所以机器上不会因此有 `~/.aliyun/config.json`
|
|
13
|
+
# ——凭证由 ensure-credentials.sh 的 aliyun_ak 每次显式传参,不依赖任何本机 profile。
|
|
11
14
|
# ============================================================
|
|
12
15
|
|
|
13
16
|
# aliyun CLI 官方 release 兜底版本(仅在无 brew、走二进制下载时用;brew 路径不读它)。
|
|
@@ -86,7 +86,7 @@ echo "==> s deploy ($DEPLOY_NAME)"
|
|
|
86
86
|
echo "::stage::verify"
|
|
87
87
|
# 精确匹配 s.yaml.tmpl 里写死的 domainName 模式: <DEPLOY_NAME>.app.clawos.chat
|
|
88
88
|
EXPECTED_DOM="${DEPLOY_NAME}.app.clawos.chat"
|
|
89
|
-
DOM="$(
|
|
89
|
+
DOM="$(aliyun_ak fc GET /2023-03-30/custom-domains 2>/dev/null | python3 -c "
|
|
90
90
|
import sys,json
|
|
91
91
|
d=json.load(sys.stdin)
|
|
92
92
|
target='$EXPECTED_DOM'
|
|
@@ -23848,7 +23848,7 @@ var METHOD_DOCS = {
|
|
|
23848
23848
|
args: WorkspaceReadArgs
|
|
23849
23849
|
},
|
|
23850
23850
|
"deploy:start": {
|
|
23851
|
-
summary: "\
|
|
23851
|
+
summary: "\u5BF9\u67D0\u4E2A persona \u8D77\u4E00\u6B21**\u65B0\u7684**\u4E0A\u4E91\u626B\u63CF\uFF1A\u5EFA\u4E00\u5F20\u65B0\u5355\u636E\u5E76\u5F02\u6B65\u626B\uFF08\u4EBA\u4F1A\u70B9\u8FD9\u4E2A\u53EA\u53EF\u80FD\u662F\u56E0\u4E3A persona \u8FED\u4EE3\u4E86\uFF0C\u62FF\u65E7\u6E05\u5355\u53BB\u90E8\u7F72\u662F\u9519\u7684\uFF09\u3002**\u5DF2\u586B\u7684\u51ED\u636E\u503C\u548C\u5C65\u7EA6\u9009\u62E9\u4ECE\u4E0A\u4E00\u5F20\u5355\u7EE7\u627F\u8FC7\u6765**\uFF0C\u4E0D\u7528\u6BCF\u8FED\u4EE3\u4E00\u6B21\u91CD\u8D34\u4E00\u904D key\u3002\u5DF2\u7ECF\u5728\u626B\u7684\u8BDD\u8FD4\u56DE\u90A3\u5F20\u3001\u4E0D\u5E76\u53D1\u8D77\u7B2C\u4E8C\u4E2A\u626B\u63CF\u4F1A\u8BDD\u3002\u56DE\u770B\u65E7\u7684\u90A3\u6B21\u8D70 deploy:list + deploy:get\uFF1Bowner-only",
|
|
23852
23852
|
args: DeployStartArgsSchema
|
|
23853
23853
|
},
|
|
23854
23854
|
"deploy:rescan": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "preinstall ship 进 daemon defaults,daemon 启动时 refreshDaemonManagedDirs 把这文件同步到 ~/.clawd*/personas/persona-app-builder/.mcp.json。cc CLI 启动时(cwd=projects/<name>/)会向上找 persona dir 的 .mcp.json 自动加载。用 @aliyun-rds/supabase-mcp-server Mode 2 单实例直连(不再用 aliyun AK),底下接阿里云托管 supabase(公网 endpoint 121.196.249.178:80,项目 ra-ae0i57kef06s6ix / clawd-app-builder,杭州可用区J
|
|
2
|
+
"_comment": "preinstall ship 进 daemon defaults,daemon 启动时 refreshDaemonManagedDirs 把这文件同步到 ~/.clawd*/personas/persona-app-builder/.mcp.json。cc CLI 启动时(cwd=projects/<name>/)会向上找 persona dir 的 .mcp.json 自动加载。用 @aliyun-rds/supabase-mcp-server Mode 2 单实例直连(不再用 aliyun AK),底下接阿里云托管 supabase(公网 endpoint 121.196.249.178:80,项目 ra-ae0i57kef06s6ix / clawd-app-builder,杭州可用区J)。**不要往这里加 --jwt-secret**:jwt-secret 是该实例的 JWT 签发密钥,拿到它可以自签任意 role/任意 user 的 token(含 service_role),下发出去等于把 anon/service key 的轮换能力一起交出去;而 MCP server 里它唯一的用处是 verify_jwt_secret 这个自检工具报个 found/preview(--jwt-secret 在其 CLI 里就标了 optional),建表读写和 auth user 管理都不经过它。**这份文件随 OTA 发给所有用户,所以这里放的每一把 key 都等于公开**:该实例上除 demo 数据外还有 clawd 自己的 clawd_prod/clawd_int schema(device_bindings 等),收敛方案见 doc/glossary/persona-cloud.md。",
|
|
3
3
|
"mcpServers": {
|
|
4
4
|
"supabase": {
|
|
5
5
|
"type": "stdio",
|
|
@@ -158,13 +158,13 @@ createProject 成功后 daemon 自动:
|
|
|
158
158
|
|
|
159
159
|
## 后端:supabase MCP
|
|
160
160
|
|
|
161
|
-
**`supabase`** —— 后端数据/认证/存储,唯一的 MCP 支柱。这份 Supabase **是阿里云托管 supabase 实例**(`http://121.196.249.178:80`),全局 MCP / clawos / lovagent / moltoffer / clawd 都指向这一台。**不是**云上 `supabase.com`
|
|
161
|
+
**`supabase`** —— 后端数据/认证/存储,唯一的 MCP 支柱。这份 Supabase **是阿里云托管 supabase 实例**(`http://121.196.249.178:80`),全局 MCP / clawos / lovagent / moltoffer / clawd 都指向这一台。**不是**云上 `supabase.com` 的实例。开工前确认能连上:
|
|
162
162
|
|
|
163
163
|
- 读表结构、跑 SQL、看 auth 用户都走这个 MCP,不要凭记忆猜 schema
|
|
164
164
|
- 模板里 `extension-kit/config.env` + `server/.env.example` 已对齐这台阿里云托管实例(SUPABASE_URL / SUPABASE_KEY),创建 project 时拷进项目目录的 `.env` 也是同一套
|
|
165
165
|
- **红线**:这是共享生产库。建表 / 迁移前先 `list_tables` 看清现状,新项目的表**必须**用 `${APP_NAME}_${SLUG}_` 前缀沉到 `public` schema(如 `helloworld_a1b2_click_counter`,`APP_NAME` 和 `SLUG` 都从项目 `ext.conf` 读,scaffold 时 bake,**不要自己另起一套 slug**),避免和 clawos / 其它项目 / 别人同名 app 的表撞名;**绝不** drop / alter clawos 已有的表,不确定哪些是 clawos 的就先问老板
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
**易踩的坑**:`config.env` 的 `SUPABASE_URL` 是**唯一真源** —— MCP 工具连它,`publish.sh` 也把它渲染进 s.yaml 给线上用。任何一处(项目 `.env`、`.env.example`)写成别的地址,就会**MCP 建表落一台 / server 通过 supabase-js 查另一台**,两边 PostgREST 的 schema cache 各自独立 → `PGRST205 schema cache 找不到表`。看到 PGRST 系列错码,先拿项目里的 `SUPABASE_URL` 跟 `config.env` 逐字比对,一致了再怀疑 schema cache。
|
|
168
168
|
|
|
169
169
|
## 阿里云凭证:在共享 deploy-kit 的 `.secrets/`,分层 override
|
|
170
170
|
|
|
@@ -184,7 +184,10 @@ source "$KIT_DIR/scripts/ensure-credentials.sh" && ensure_credentials
|
|
|
184
184
|
|
|
185
185
|
⚠️ **上面这几行和后续的 `aliyun` / `s` 命令必须在同一个 Bash 调用里跑完**——你的 Bash tool 每次调用是独立进程,shell 变量不跨调用留存。分两次跑 = 第二次丢了 `serverless_devs_config_home`,`s` 会回头去读 `~/.s` 然后报 `Not found access: clawd-fc`。**这时正确做法是把 source 那几行和 `s` 命令拼进同一条命令重跑,绝不是去写 `~/.s/access.yaml`。**
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
之后两个 CLI **都不能裸调**,各有各的入口:
|
|
188
|
+
|
|
189
|
+
- **`aliyun` 一律走 `aliyun_ak`**(`ensure-credentials.sh` 里的函数),例:`aliyun_ak fc GET /2023-03-30/custom-domains`。它把 AK 和 region 作为显式参数传进去。**别写 `aliyun --mode AK ...` 让它自己找凭证**:那个模式下 `ALIBABA_CLOUD_*` 环境变量根本不被消费,机器上没配过 `aliyun configure` 就报 `region can't be empty`,配过的话更糟——静默走用户自己的 profile,等于拿用户的阿里云账号部署。
|
|
190
|
+
- **`s` 要显式带 profile**:凭证写在 deploy-kit 私有的 `.s-home/` 里、profile 名 `clawd-fc`,所以每次都是 `s deploy -y --access "$S_ACCESS_ALIAS"` / `s remove -y --access "$S_ACCESS_ALIAS"`。
|
|
188
191
|
|
|
189
192
|
**红线:绝不写用户全局 `~/.s/access.yaml`**。那里的 `default` 是用户自己账号的凭证,clawd 用的是共享 demo AK,盖上去用户的就没了、不可恢复。
|
|
190
193
|
|
|
@@ -11,9 +11,9 @@ NODE_LAYER=acs:fc:cn-hangzhou:official:layers/Nodejs22/versions/1
|
|
|
11
11
|
# Supabase(阿里云托管 supabase 实例!建表务必加 <app>_ 前缀沉到 public schema,避免撞名)
|
|
12
12
|
# 公网 endpoint 121.196.249.178:80(项目 ra-ae0i57kef06s6ix / clawd-app-builder,杭州可用区J)
|
|
13
13
|
# 全局 MCP / clawos / lovagent / moltoffer / clawd 都指向这一台。
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
14
|
+
# 下面两行是**唯一真源**:examples/*/server/.env.example 必须跟这里逐值一致
|
|
15
|
+
# (defaults-supabase-parity.spec.ts 守这条)。不一致 = 本地连一台、线上连另一台,
|
|
16
|
+
# 两边 PostgREST 的 schema cache 各自独立 → PGRST205 找不到表。
|
|
17
17
|
SUPABASE_URL=http://121.196.249.178:80
|
|
18
18
|
# anon/publishable key(公开可暴露,客户端用)。阿里云托管实例的 anon key,跟 supabase MCP 用同一把。
|
|
19
19
|
SUPABASE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNzgzMzEwODU1LCJleHAiOjEzMjkzOTUwODU1fQ.sHLZH8q2SGWYbNPEFOzTFlQEtjVK3z1DlEqoU_5Uyyg
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
# Supabase
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
# Supabase 连接串。**唯一真源是 extension-kit/config.env**——publish.sh 从那里读值渲染进
|
|
2
|
+
# s.yaml 的 environmentVariables,线上跑的就是那一份。这里是本地 dev 用的副本(copy 成 .env),
|
|
3
|
+
# 改实例地址时两处要一起改,否则本地连一台、线上连另一台,两边 PostgREST schema cache 各自独立,
|
|
4
|
+
# 症状是 PGRST205 找不到表。(defaults-supabase-parity.spec.ts 守这条一致性。)
|
|
5
|
+
SUPABASE_URL=http://121.196.249.178:80
|
|
6
|
+
SUPABASE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNzgzMzEwODU1LCJleHAiOjEzMjkzOTUwODU1fQ.sHLZH8q2SGWYbNPEFOzTFlQEtjVK3z1DlEqoU_5Uyyg
|
|
6
7
|
PORT=3000
|