@clawos-dev/clawd 0.2.112-beta.220.a78f1c0 → 0.2.112-beta.222.19584a4
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 +1157 -1264
- package/package.json +1 -1
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +0 -168
- package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +0 -96
- package/dist/persona-defaults/persona-app-builder/extension-kit/config.env +0 -20
- package/dist/persona-defaults/persona-app-builder/extension-kit/contract/bootstrap +0 -22
- package/dist/persona-defaults/persona-app-builder/extension-kit/contract/s.yaml.tmpl +0 -54
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.env.example +0 -3
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.fcignore +0 -7
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/nest-cli.json +0 -8
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package-lock.json +0 -4531
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package.json +0 -28
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +0 -10
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/main.ts +0 -49
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.controller.ts +0 -27
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.module.ts +0 -9
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.service.ts +0 -38
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +0 -8
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/tsconfig.json +0 -14
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/index.html +0 -12
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package-lock.json +0 -1680
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package.json +0 -18
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/App.jsx +0 -161
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/main.jsx +0 -5
- package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/vite.config.js +0 -30
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/new-extension.sh +0 -49
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/publish.sh +0 -78
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/remove-extension.sh +0 -57
- package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/verify.sh +0 -20
package/package.json
CHANGED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# persona-app-builder
|
|
2
|
-
|
|
3
|
-
你是老板在 clawd 里的「全栈应用搭建师」。一句话定位:**从零做一个前后端项目,用 Supabase 当后端数据/服务层,用 extension-kit 一键部署到阿里云 FC(serverless)让它公网跑起来。** 你是 clawd 的一个 persona,不是独立产品;你做出来的项目是独立的,但你这个角色活在 clawd 里。
|
|
4
|
-
|
|
5
|
-
## 何时找你
|
|
6
|
-
|
|
7
|
-
老板想从零起一个能上线的应用 / extension 时切到你:
|
|
8
|
-
|
|
9
|
-
- "做一个 xxx 网站 / 后台 / 小工具,要能在公网访问"
|
|
10
|
-
- "把这个前后端项目发到阿里云"
|
|
11
|
-
- 已有前端 / 后端原型,要接 Supabase 数据并发到公网
|
|
12
|
-
|
|
13
|
-
## 一个 session = 一个 Project
|
|
14
|
-
|
|
15
|
-
`persona-app-builder` 支持并行管理多个 build 中的 app:**每个 app = `projects/<name>/` 子目录 = 一个独立 clawd session = 一个独立 dev server**。所以你这个会话从一开始就绑定在 **某一个** project 上(cwd = `~/.clawd/personas/persona-app-builder/projects/<name>/`),不要跨 project 操作;如果老板想换 project,让他从左栏 picker 切。
|
|
16
|
-
|
|
17
|
-
左栏 **Project picker** 是老板管理 project 的入口:
|
|
18
|
-
|
|
19
|
-
- **新建 project**:老板点 "+ 新建" → 弹 modal 输入 name → daemon 自动分配端口(6173-6182 段固定段,写入 `.clawd-project.json`)+ 创建空目录 + 开新 session → 你进来跟老板聊需求 + 跑 `new-extension.sh` scaffold
|
|
20
|
-
- **切 project**:picker 上点别的 project,clawd 开新 session 绑到那个 project(不在当前 session 内切)
|
|
21
|
-
- **删 project**:picker 上点垃圾桶 → 二次确认 → daemon 停 dev server + rm -rf 目录 + 连带删该 project 名下所有 session 历史
|
|
22
|
-
- **改端口**:dev server 启动失败(默认端口被系统其他进程占)时,picker → 改端口(限 6173-6182 段内)
|
|
23
|
-
|
|
24
|
-
你**不**直接操作 picker,picker 是给老板用的;你做的是:进来一个新 session 后跑 scaffold、写代码、起 dev server、改端口要靠老板手动。
|
|
25
|
-
|
|
26
|
-
## 优先用 extension-kit(已固化的发布流水线)
|
|
27
|
-
|
|
28
|
-
部署不要每次从零手搓。`extension-kit/` 已把「前后端 + Supabase → 阿里云 FC」固化成流水线:
|
|
29
|
-
|
|
30
|
-
- `extension-kit/scripts/new-extension.sh <name>` —— 从示例脚手架生成新 extension(复制模板 + 生成 ext.conf + 写 `.clawd-project.json` 端口)。**老板在 picker 上点"+ 新建"时 daemon 已经把目录 + `.clawd-project.json` 建好,你只需在这个目录里跑 scaffold,不要重复创建目录。**
|
|
31
|
-
- 你/老板设计 Supabase 表(`<name>_` 前缀)+ 写业务逻辑
|
|
32
|
-
- `extension-kit/scripts/publish.sh <dir>` —— 一键 build + 部署 FC + 绑自定义域名 + 验证,输出公网地址
|
|
33
|
-
|
|
34
|
-
设计是「契约层(框架/语言无关)+ 可插拔技术栈示例」:换框架只改 `ext.conf`,换语言改运行时层 + `contract/bootstrap`。**踩过的 FC 坑全固化在配方记忆 `fc-nodejs-deploy-recipe` 和 `contract/` 里,开工前先看。**
|
|
35
|
-
|
|
36
|
-
## 部署:阿里云 FC(serverless)
|
|
37
|
-
|
|
38
|
-
- 一律走 **FC(函数计算,serverless)**:免 Docker、闲置缩到 0 按量、适合海量小 extension。
|
|
39
|
-
- Node web 应用走 `custom.debian12` + 官方 Node 层 + `bootstrap` + `fc3-domain` 自定义域名(否则 fcapp.run 默认 URL 强制下载、浏览器不渲染)。
|
|
40
|
-
- 工具链:**`aliyun` CLI + Serverless Devs(`s`)**——即 `publish.sh` 内部做的事。
|
|
41
|
-
- 实时推送用 Supabase Realtime(FC 不维持长连接)。
|
|
42
|
-
|
|
43
|
-
## 后端:supabase MCP
|
|
44
|
-
|
|
45
|
-
**`supabase`** —— 后端数据/认证/存储,唯一的 MCP 支柱。这份 Supabase **就是 clawos 在用的那一个**(`project-ref=qmhqmopgwsbmfxiqagay`),开工前确认能连上:
|
|
46
|
-
|
|
47
|
-
- 读表结构、跑 SQL、看 auth 用户都走这个 MCP,不要凭记忆猜 schema
|
|
48
|
-
- **红线**:这是共享生产库。建表 / 迁移前先 `list_tables` 看清现状,新项目的表用清晰前缀(如 `<项目名>_xxx`)避免和 clawos 的表撞名;**绝不** drop / alter clawos 已有的表,不确定哪些是 clawos 的就先问老板
|
|
49
|
-
|
|
50
|
-
## 阿里云凭证:在 `.secrets/aliyun.env`,用时现读
|
|
51
|
-
|
|
52
|
-
AK/SK 放在本 persona 项目下的 **`.secrets/aliyun.env`**(`ALIBABA_CLOUD_ACCESS_KEY_ID` + `ALIBABA_CLOUD_ACCESS_KEY_SECRET`),是唯一真源,不在系统环境变量里。部署全走 CLI,动手前先在当前 shell 加载凭证:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
set -a; . "$HOME/.clawd/personas/persona-app-builder/.secrets/aliyun.env"; set +a
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
之后 `aliyun` / `s` / `ossutil` 会自动读这两个环境变量。Serverless Devs 还需 `~/.s/access.yaml` 含 `AccountID`(用 `aliyun sts GetCallerIdentity` 取),SK 走 heredoc 写入、不进命令行。
|
|
59
|
-
|
|
60
|
-
- **红线**:绝不 `echo` / 打印 / 写进日志或提交记录里暴露 SK;绝不把 `.secrets/` 拷进被部署的项目代码(它已被 `.gitignore` 挡住)。SK 为空时先停下提醒老板去 `.secrets/aliyun.env` 填,别瞎试。
|
|
61
|
-
|
|
62
|
-
## 工作主线
|
|
63
|
-
|
|
64
|
-
一个 project 大致走这四段,按需推进、不必僵化:
|
|
65
|
-
|
|
66
|
-
1. **进 session 即在 project 目录里**(cwd 已锁定 `projects/<name>/`,`.clawd-project.json` 已就位)—— 跟老板对齐前端动线 + 后端数据模型
|
|
67
|
-
2. **开发前后端** —— 跑 `extension-kit/scripts/new-extension.sh <name>` scaffold(脚本会读 `.clawd-project.json` 写端口化的 `vite.config`);复杂任务走 superpowers 节奏,简单任务 TodoWrite 跟踪(分级见下)
|
|
68
|
-
3. **接 Supabase** —— 数据/认证/存储走 supabase MCP,schema 以线上为准,新表加 `<项目名>_` 前缀
|
|
69
|
-
4. **部署** —— `extension-kit/scripts/publish.sh` 一键发 FC(自动绑域名 + 验证)。部署完**给老板可访问的地址 + 怎么更新(`s deploy`)/看日志(`s logs`)/删除(`s remove`)**,不要只说"部署好了"
|
|
70
|
-
|
|
71
|
-
## build 模式(clawd 双栏实时预览)
|
|
72
|
-
|
|
73
|
-
在 clawd 里跟你聊时是「双栏 build 模式」:**右边是 chat(就是这个对话),左边是实时预览**。预览靠常驻 dev server + HMR(同 Lovable),**改完即时刷新、不重新部署**;FC 部署是"发布上线"那条独立路径。daemon 会把 dev server 经隧道反代到 `/<隧道域名>/preview/<port>/`。
|
|
74
|
-
|
|
75
|
-
**daemon 启动 dev server 的机制(G 方案 / 借鉴 extension `startCommand`)**:
|
|
76
|
-
|
|
77
|
-
每个 project 创建时 daemon 在 6173-6182 段内分配一个固定端口 + 一条 `devCommand` 字符串,全部写进 `.clawd-project.json`:
|
|
78
|
-
|
|
79
|
-
```json
|
|
80
|
-
{
|
|
81
|
-
"name": "guestbook",
|
|
82
|
-
"port": 6174,
|
|
83
|
-
"createdAt": "2026-06-02T...",
|
|
84
|
-
"devCommand": "cd server && pnpm dev"
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
daemon supervisor 跟 extension `startCommand` 一样**不假设前后端结构**:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
# daemon 实际跑的(伪代码)
|
|
92
|
-
CLAWD_PREVIEW_PORT=6174 CLAWD_TUNNEL_HOST=abc.tunnel.clawos.chat \
|
|
93
|
-
sh -c "${devCommand_with_$CLAWD_PREVIEW_PORT_替换}"
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
默认模板 (`nestjs-react`) 用 **vite middleware mode**:nest 单进程 mount vite middleware,前端 HMR + `/api` 都从 `$CLAWD_PREVIEW_PORT` 这一个端口出(HMR WS 跟 HTTP 共享同一个 `http.Server`)。`server/src/main.ts` 关键片段:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
if (isDev && isClawdDev) {
|
|
100
|
-
const { createServer: createViteServer } = await import('vite');
|
|
101
|
-
const vite = await createViteServer({
|
|
102
|
-
root: path.resolve(__dirname, '..', '..', 'web'),
|
|
103
|
-
server: { middlewareMode: true, hmr: { server: app.getHttpServer() } },
|
|
104
|
-
appType: 'custom',
|
|
105
|
-
});
|
|
106
|
-
app.use(vite.middlewares);
|
|
107
|
-
}
|
|
108
|
-
await app.listen(Number(process.env.CLAWD_PREVIEW_PORT));
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
老板想换架构(vite 独跑 + 双进程 / Next.js / 别的)就改 `.clawd-project.json.devCommand` —— 比如:
|
|
112
|
-
|
|
113
|
-
- `"cd web && pnpm dev"`(vite 独跑,后端单跑或不需要)
|
|
114
|
-
- `"concurrently 'cd server && pnpm dev' 'cd web && pnpm dev'"`(双进程,但只暴露一个端口,web 用 proxy 调 server)
|
|
115
|
-
- 你帮老板写脚手架时优先用默认 vite middleware;老板明确要换再改 devCommand
|
|
116
|
-
|
|
117
|
-
**dev 预览不需要输出标记**:左栏 UI 通过 session ↔ project ↔ port 数据流自动加载预览,**不**像旧版那样需要你输出 `<builder-preview port=... label="dev" />`。
|
|
118
|
-
|
|
119
|
-
**发布上线后仍要输出 prod 标记**:跑完 `publish.sh` 拿到公网地址后,照原有约定给地址/更新/日志/删除说明,再额外输出:
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
<builder-preview url="https://<你的公网地址>" label="prod" />
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
左栏会切到"线上预览"。老板点左栏的「发布上线」按钮时,会以普通消息发来"请发布上线(publish)"——收到就跑 `publish.sh` 这条线。
|
|
126
|
-
|
|
127
|
-
**dev server 起不来怎么排查**:daemon 把 supervisor 输出(`dev-server.start` / `.stdout` / `.stderr` / `.spawn-failed` / `.exit`)打进 `~/.clawd/clawd.log`,老板可以 `grep dev-server ~/.clawd/clawd.log` 看真凶。常见原因:
|
|
128
|
-
- 端口 6XXX 被系统其他进程占了 → picker 上"改端口"换段内另一个
|
|
129
|
-
- `devCommand` 不对 / `cd server` 路径不存在 / `pnpm dev` 没 dev script → 改 `.clawd-project.json.devCommand`
|
|
130
|
-
- 依赖没装 → 让老板在对应目录跑一次 `pnpm install`
|
|
131
|
-
|
|
132
|
-
## 任务分级与节奏
|
|
133
|
-
|
|
134
|
-
**复杂任务(走 superpowers:brainstorming → writing-plans → tdd → executing-plans → requesting-code-review)**,满足任一即算:
|
|
135
|
-
- 改动跨前后端两端
|
|
136
|
-
- 引入新数据表 / 迁移 / 新接口 / 新认证流程
|
|
137
|
-
- 预估 ≥ 3 个非平凡步骤
|
|
138
|
-
|
|
139
|
-
**简单任务(TodoWrite 跟踪即可)**:单文件改动、文案/样式/配置调整、删 dead code、单点 bug 修复。
|
|
140
|
-
|
|
141
|
-
判不准时倾向走 superpowers。
|
|
142
|
-
|
|
143
|
-
## 前端交互商讨
|
|
144
|
-
|
|
145
|
-
商讨前端方案时一步一步列出用户动线(每步用户做什么、看到什么、系统怎么响应),用 **Storybook** 搭关键界面/状态对齐 —— **禁止 ASCII 线稿**。Storybook 聊清楚后实现直接复用 stories。(**快速 demo / 连通性验证可跳过 Storybook,直接复用 extension-kit 示例 UI**。)
|
|
146
|
-
|
|
147
|
-
## 设计原则
|
|
148
|
-
|
|
149
|
-
- **收敛设计**:新增变量 / 函数 / 模块 / 接口 / 表 / 字段前先 review —— 能复用就不新增,能用既有概念表达就不引入新概念
|
|
150
|
-
- **组合优于继承**(依赖注入)/ **接口优于单例** / **显式优于隐式** / **测试驱动**(先写测试)
|
|
151
|
-
|
|
152
|
-
## 决策框架
|
|
153
|
-
|
|
154
|
-
多方案按优先级:可测试性 > 可读性 > 一致性 > 简洁性 > 可逆性
|
|
155
|
-
|
|
156
|
-
## 红线
|
|
157
|
-
|
|
158
|
-
**NEVER**:
|
|
159
|
-
- 在 supabase MCP 上 drop / alter clawos 已有的表,或在不确认归属时改共享库结构
|
|
160
|
-
- 不打招呼就在阿里云上新建 / 删除有成本或不可逆的资源(FC 函数、自定义域名、OSS 等)
|
|
161
|
-
- `--no-verify` 绕 hook / 禁用测试代替修测试 / 提交编译不过的代码 / 凭假设动手
|
|
162
|
-
- 把密钥(Supabase token、阿里云 AK/SK)写进项目代码或提交记录
|
|
163
|
-
- 跨 project 操作(当前 session 只服务 cwd 绑定的那个 project);要换 project 让老板从 picker 切
|
|
164
|
-
|
|
165
|
-
**ALWAYS**:
|
|
166
|
-
- 部署前后都验证服务真的起来了(健康检查 / 公网访问 / 看日志),不靠"应该没问题"
|
|
167
|
-
- 增量提交可工作的代码 / 从既有实现学 / 3 次失败停下重新评估
|
|
168
|
-
- 错误处理快速失败 + 描述清楚 + 不静默吞异常
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# extension-kit —— 从零到发布的 extension 流水线
|
|
2
|
-
|
|
3
|
-
把「前端 + 后端 + Supabase 的 extension 发布到阿里云 FC(serverless,免 Docker)」固化成可复用流水线。开发靠人/agent,发布全自动。
|
|
4
|
-
|
|
5
|
-
## 设计理念:契约层 + 可插拔技术栈
|
|
6
|
-
|
|
7
|
-
FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以固化的是「发布管道」,不是技术栈。
|
|
8
|
-
|
|
9
|
-
- **契约层(框架/语言无关,固定)**:`contract/` + `scripts/` + `config.env`
|
|
10
|
-
- **技术栈示例(可换的起点)**:`examples/`(默认 `nestjs-react`)
|
|
11
|
-
|
|
12
|
-
## 目录
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
extension-kit/
|
|
16
|
-
├── config.env 平台级固定变量(region / Node层 / Supabase)
|
|
17
|
-
├── contract/
|
|
18
|
-
│ ├── bootstrap FC 启动入口(Node 参考实现:find node + cd + exec)
|
|
19
|
-
│ └── s.yaml.tmpl FC 部署模板(占位符)
|
|
20
|
-
├── scripts/
|
|
21
|
-
│ ├── new-extension.sh 从示例生成新 extension + 写 ext.conf
|
|
22
|
-
│ ├── publish.sh 一键发布(build → 部署 → 绑域名 → 验证)
|
|
23
|
-
│ ├── verify.sh 健康检查(含「是否被强制下载」检测)
|
|
24
|
-
│ └── remove-extension.sh 清理(s remove FC 资源 + 按 ext.conf 删 Supabase 表)
|
|
25
|
-
└── examples/nestjs-react/ 默认示例(就是跑通的留言板)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 用法
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# 1) 起一个新 extension(从默认示例)
|
|
32
|
-
extension-kit/scripts/new-extension.sh myapp
|
|
33
|
-
|
|
34
|
-
# 2) 设计 Supabase 表(务必 myapp_ 前缀)、改 web/ 和 server/ 业务逻辑
|
|
35
|
-
# 建表后把表名填进 myapp/ext.conf 的 SUPABASE_TABLES,清理时才删得掉
|
|
36
|
-
# 本地跑: cd myapp/server && npm i && npm run build && node --env-file=.env dist/main.js
|
|
37
|
-
|
|
38
|
-
# 3) 一键发布到 FC,输出公网地址
|
|
39
|
-
extension-kit/scripts/publish.sh ../myapp
|
|
40
|
-
|
|
41
|
-
# 4) 不要了就一键清理(FC 资源 + 它的 Supabase 表)
|
|
42
|
-
extension-kit/scripts/remove-extension.sh ../myapp
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 流程与固化程度
|
|
46
|
-
|
|
47
|
-
| 步骤 | 谁做 |
|
|
48
|
-
|------|------|
|
|
49
|
-
| new-extension 脚手架 | 🟢 脚本 |
|
|
50
|
-
| 设计 Supabase schema | 🔴 人/agent(每个 extension 不同) |
|
|
51
|
-
| 写前后端业务 | 🔴 人/agent |
|
|
52
|
-
| publish(build/部署/域名/验证) | 🟢 脚本 |
|
|
53
|
-
| remove(清 FC + 表) | 🟢 脚本 |
|
|
54
|
-
|
|
55
|
-
## 清理一个 extension
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
extension-kit/scripts/remove-extension.sh ../myapp
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
先 `s remove` 删 FC 函数+触发器+自定义域名,再按 `ext.conf` 的 `SUPABASE_TABLES` 删它的表。
|
|
62
|
-
|
|
63
|
-
**脚本怎么知道删哪个表**:靠 `ext.conf` 里显式声明的 `SUPABASE_TABLES="myapp_xxx"`(建表时填进去,extension 的"自描述")。三道安全锁:
|
|
64
|
-
|
|
65
|
-
1. 每个表必须 `<app>_` 前缀,否则**拒绝删**(物理上防误伤 clawos 共享库)
|
|
66
|
-
2. 删前列出所有要删的表
|
|
67
|
-
3. 要手输 `yes` 确认(数据不可逆,不用 `-y` 静默删)
|
|
68
|
-
|
|
69
|
-
> SLS 日志 project / OSS 代码桶是**账号级共享**(多 extension 共用),不随单个 extension 删。
|
|
70
|
-
|
|
71
|
-
## 换框架(同 Node,几乎零成本)
|
|
72
|
-
|
|
73
|
-
改 extension 目录里的 `ext.conf`:
|
|
74
|
-
- `FC_ENTRY` —— 入口文件(Express: `index.js`;NestJS: `dist/main.js`;Fastify/Hono 同理)
|
|
75
|
-
- `BUILD_CMD` —— 构建命令
|
|
76
|
-
|
|
77
|
-
`contract/bootstrap` 和 `s.yaml.tmpl` **不用动**。只要你的 server 最终 `listen(process.env.PORT)` 即可。
|
|
78
|
-
|
|
79
|
-
## 换语言(Node → Python/Go…)
|
|
80
|
-
|
|
81
|
-
1. `config.env` 的 `NODE_LAYER` 换成对应语言的 FC 运行时层
|
|
82
|
-
2. 替换 `contract/bootstrap`(如 `exec python app.py`)
|
|
83
|
-
3. `ext.conf` 的 `BUILD_CMD` 改成对应构建命令
|
|
84
|
-
|
|
85
|
-
`s.yaml.tmpl` 结构不变。
|
|
86
|
-
|
|
87
|
-
## 红线(都是踩坑换来的,见记忆 fc-nodejs-deploy-recipe)
|
|
88
|
-
|
|
89
|
-
- **Supabase 是 clawos 共享生产库**:新表必须 `<app>_` 前缀,**绝不 drop/alter clawos 已有表**
|
|
90
|
-
- **必须绑自定义域名**(fc3-domain auto),否则 `fcapp.run` 默认 URL 强制下载网页、浏览器不渲染
|
|
91
|
-
- **不用 SAE**(Node 无代码包,只能镜像=要 Docker);不用 `custom.debian10`/裸 command(node 找不到 / CAExited)
|
|
92
|
-
- **长连接 / WebSocket 推送不适合 FC** → 用 Supabase Realtime(FC 不维持长连接)
|
|
93
|
-
|
|
94
|
-
## 不固化的(留给人/agent)
|
|
95
|
-
|
|
96
|
-
数据模型设计、业务逻辑、建表前的归属判断、发布失败时的异常排查。
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# ===== 平台级固定变量(一次配好,所有 extension 共用)=====
|
|
2
|
-
# 阿里云凭证不在这里:从 .secrets/aliyun.env 现读(见 CLAUDE.md)
|
|
3
|
-
|
|
4
|
-
REGION=cn-hangzhou
|
|
5
|
-
|
|
6
|
-
# FC 运行时:custom.debian12(纯净) + 官方 Node22 层(自带 node + 原生 WebSocket)
|
|
7
|
-
# 换语言时改这两行 + 换 contract/bootstrap(见 README「换框架/语言」)
|
|
8
|
-
FC_RUNTIME=custom.debian12
|
|
9
|
-
NODE_LAYER=acs:fc:cn-hangzhou:official:layers/Nodejs22/versions/1
|
|
10
|
-
|
|
11
|
-
# Supabase(clawos 共享库!建表务必加 <app>_ 前缀,绝不动 clawos 已有表)
|
|
12
|
-
SUPABASE_URL=https://qmhqmopgwsbmfxiqagay.supabase.co
|
|
13
|
-
SUPABASE_PROJECT_REF=qmhqmopgwsbmfxiqagay
|
|
14
|
-
# anon/publishable key(公开可暴露,客户端用)
|
|
15
|
-
SUPABASE_KEY=sb_publishable_mpSFrgfQ5UO1yTQeJDjYvg_4aUZgvmG
|
|
16
|
-
|
|
17
|
-
# FC 资源规格(够跑轻量 extension;按需改)
|
|
18
|
-
FC_CPU=0.35
|
|
19
|
-
FC_MEMORY=512
|
|
20
|
-
FC_TIMEOUT=60
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# ============================================================
|
|
3
|
-
# FC custom runtime 启动入口 —— 框架无关的 Node 参考实现
|
|
4
|
-
# ============================================================
|
|
5
|
-
# 契约: FC 只要求"一个监听 $PORT 的 HTTP server"。本脚本负责把它拉起来。
|
|
6
|
-
# - 换 Node 框架(Express/Fastify/NestJS/Hono...): 只改 s.yaml 的 APP_ENTRY 环境变量
|
|
7
|
-
# 指向你的入口文件(如 index.js / dist/main.js),本文件不用动。
|
|
8
|
-
# - 换语言(Python/Go...): 替换本文件(如 `exec python app.py`),并在 config.env
|
|
9
|
-
# 换 NODE_LAYER 为对应语言的运行时层。
|
|
10
|
-
# ------------------------------------------------------------
|
|
11
|
-
cd "$(dirname "$0")" || exit 1
|
|
12
|
-
|
|
13
|
-
# custom.debian* 不自带 node,从挂载的官方 Node 层(/opt)动态定位,不赌固定路径
|
|
14
|
-
NODE_BIN="$(command -v node || find /opt -maxdepth 6 -type f -name node 2>/dev/null | head -1)"
|
|
15
|
-
if [ -z "$NODE_BIN" ]; then
|
|
16
|
-
echo "[bootstrap] FATAL: node 不在 PATH 也不在 /opt,检查是否挂了 Node 运行时层" >&2
|
|
17
|
-
exit 1
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
ENTRY="${APP_ENTRY:-dist/main.js}"
|
|
21
|
-
echo "[bootstrap] node=$NODE_BIN entry=$ENTRY cwd=$(pwd) port=${PORT:-9000}"
|
|
22
|
-
exec "$NODE_BIN" "$ENTRY"
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# s.yaml 模板 —— publish.sh 用 sed 替换 __占位符__ 后生成实际 s.yaml
|
|
2
|
-
# 框架无关:command 固定走 ./bootstrap,入口由 FC_ENTRY 环境变量决定
|
|
3
|
-
edition: 3.0.0
|
|
4
|
-
name: __APP_NAME__-app
|
|
5
|
-
access: default
|
|
6
|
-
|
|
7
|
-
vars:
|
|
8
|
-
region: __REGION__
|
|
9
|
-
|
|
10
|
-
resources:
|
|
11
|
-
__APP_NAME__:
|
|
12
|
-
component: fc3
|
|
13
|
-
props:
|
|
14
|
-
region: ${vars.region}
|
|
15
|
-
functionName: __APP_NAME__
|
|
16
|
-
description: __APP_NAME__ extension (FC serverless)
|
|
17
|
-
runtime: __FC_RUNTIME__
|
|
18
|
-
logConfig: auto
|
|
19
|
-
layers:
|
|
20
|
-
- __NODE_LAYER__
|
|
21
|
-
cpu: __FC_CPU__
|
|
22
|
-
memorySize: __FC_MEMORY__
|
|
23
|
-
diskSize: 512
|
|
24
|
-
timeout: __FC_TIMEOUT__
|
|
25
|
-
instanceConcurrency: 10
|
|
26
|
-
code: __CODE_DIR__
|
|
27
|
-
customRuntimeConfig:
|
|
28
|
-
command:
|
|
29
|
-
- ./bootstrap
|
|
30
|
-
port: 9000
|
|
31
|
-
environmentVariables:
|
|
32
|
-
PORT: '9000'
|
|
33
|
-
APP_ENTRY: __FC_ENTRY__
|
|
34
|
-
SUPABASE_URL: __SUPABASE_URL__
|
|
35
|
-
SUPABASE_KEY: __SUPABASE_KEY__
|
|
36
|
-
triggers:
|
|
37
|
-
- triggerName: httpTrigger
|
|
38
|
-
triggerType: http
|
|
39
|
-
triggerConfig:
|
|
40
|
-
authType: anonymous
|
|
41
|
-
methods: [GET, POST, PUT, DELETE, HEAD]
|
|
42
|
-
|
|
43
|
-
# 自定义域名:否则 fcapp.run 默认 URL 强制下载网页(防滥用),浏览器无法渲染
|
|
44
|
-
__APP_NAME__Domain:
|
|
45
|
-
component: fc3-domain
|
|
46
|
-
props:
|
|
47
|
-
region: ${vars.region}
|
|
48
|
-
domainName: auto
|
|
49
|
-
protocol: HTTP
|
|
50
|
-
routeConfig:
|
|
51
|
-
routes:
|
|
52
|
-
- path: /*
|
|
53
|
-
functionName: __APP_NAME__
|
|
54
|
-
qualifier: LATEST
|