@clawos-dev/clawd 0.2.112-beta.216.545c7ca → 0.2.112-beta.218.6282fa2

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.
Files changed (29) hide show
  1. package/dist/cli.cjs +1124 -1070
  2. package/dist/persona-defaults/persona-app-builder/CLAUDE.md +168 -0
  3. package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +96 -0
  4. package/dist/persona-defaults/persona-app-builder/extension-kit/config.env +20 -0
  5. package/dist/persona-defaults/persona-app-builder/extension-kit/contract/bootstrap +22 -0
  6. package/dist/persona-defaults/persona-app-builder/extension-kit/contract/s.yaml.tmpl +54 -0
  7. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.env.example +3 -0
  8. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/.fcignore +7 -0
  9. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/nest-cli.json +8 -0
  10. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package-lock.json +4531 -0
  11. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/package.json +28 -0
  12. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +10 -0
  13. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/main.ts +49 -0
  14. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.controller.ts +27 -0
  15. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.module.ts +9 -0
  16. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/messages/messages.service.ts +38 -0
  17. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +8 -0
  18. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/tsconfig.json +14 -0
  19. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/index.html +12 -0
  20. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package-lock.json +1680 -0
  21. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/package.json +18 -0
  22. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/App.jsx +161 -0
  23. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/main.jsx +5 -0
  24. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/vite.config.js +30 -0
  25. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/new-extension.sh +49 -0
  26. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/publish.sh +78 -0
  27. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/remove-extension.sh +57 -0
  28. package/dist/persona-defaults/persona-app-builder/extension-kit/scripts/verify.sh +20 -0
  29. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "guestbook-web",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build"
9
+ },
10
+ "dependencies": {
11
+ "react": "^18.3.1",
12
+ "react-dom": "^18.3.1"
13
+ },
14
+ "devDependencies": {
15
+ "@vitejs/plugin-react": "^4.3.1",
16
+ "vite": "^5.4.0"
17
+ }
18
+ }
@@ -0,0 +1,161 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ const styles = {
4
+ page: {
5
+ minHeight: '100vh',
6
+ margin: 0,
7
+ background: 'linear-gradient(160deg, #0f172a 0%, #1e293b 100%)',
8
+ color: '#e2e8f0',
9
+ fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
10
+ display: 'flex',
11
+ justifyContent: 'center',
12
+ padding: '48px 16px',
13
+ },
14
+ card: {
15
+ width: '100%',
16
+ maxWidth: 560,
17
+ },
18
+ title: { fontSize: 28, fontWeight: 700, margin: '0 0 4px' },
19
+ subtitle: { color: '#94a3b8', margin: '0 0 24px', fontSize: 14 },
20
+ form: { display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 28 },
21
+ row: { display: 'flex', gap: 10 },
22
+ input: {
23
+ flex: 1,
24
+ padding: '10px 12px',
25
+ borderRadius: 8,
26
+ border: '1px solid #334155',
27
+ background: '#0f172a',
28
+ color: '#e2e8f0',
29
+ fontSize: 14,
30
+ outline: 'none',
31
+ },
32
+ textarea: {
33
+ padding: '10px 12px',
34
+ borderRadius: 8,
35
+ border: '1px solid #334155',
36
+ background: '#0f172a',
37
+ color: '#e2e8f0',
38
+ fontSize: 14,
39
+ outline: 'none',
40
+ resize: 'vertical',
41
+ minHeight: 64,
42
+ },
43
+ button: {
44
+ padding: '10px 20px',
45
+ borderRadius: 8,
46
+ border: 'none',
47
+ background: '#6366f1',
48
+ color: '#fff',
49
+ fontSize: 14,
50
+ fontWeight: 600,
51
+ cursor: 'pointer',
52
+ },
53
+ msg: {
54
+ padding: '12px 14px',
55
+ borderRadius: 10,
56
+ background: '#1e293b',
57
+ border: '1px solid #334155',
58
+ marginBottom: 10,
59
+ },
60
+ msgHead: { display: 'flex', justifyContent: 'space-between', marginBottom: 4 },
61
+ msgName: { fontWeight: 600, color: '#a5b4fc', fontSize: 14 },
62
+ msgTime: { color: '#64748b', fontSize: 12 },
63
+ msgBody: { fontSize: 14, lineHeight: 1.5, whiteSpace: 'pre-wrap' },
64
+ error: { color: '#f87171', fontSize: 13, marginBottom: 12 },
65
+ empty: { color: '#64748b', fontSize: 14, textAlign: 'center', padding: '24px 0' },
66
+ };
67
+
68
+ export default function App() {
69
+ const [messages, setMessages] = useState([]);
70
+ const [name, setName] = useState('');
71
+ const [content, setContent] = useState('');
72
+ const [error, setError] = useState('');
73
+ const [loading, setLoading] = useState(false);
74
+
75
+ async function load() {
76
+ try {
77
+ const res = await fetch('/api/messages');
78
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
79
+ setMessages(await res.json());
80
+ setError('');
81
+ } catch (e) {
82
+ setError(`加载失败: ${e.message}`);
83
+ }
84
+ }
85
+
86
+ useEffect(() => {
87
+ load();
88
+ }, []);
89
+
90
+ async function submit(e) {
91
+ e.preventDefault();
92
+ if (!content.trim()) return;
93
+ setLoading(true);
94
+ try {
95
+ const res = await fetch('/api/messages', {
96
+ method: 'POST',
97
+ headers: { 'Content-Type': 'application/json' },
98
+ body: JSON.stringify({ name, content }),
99
+ });
100
+ if (!res.ok) {
101
+ const body = await res.json().catch(() => ({}));
102
+ throw new Error(body.message || `HTTP ${res.status}`);
103
+ }
104
+ setContent('');
105
+ await load();
106
+ } catch (e) {
107
+ setError(`提交失败: ${e.message}`);
108
+ } finally {
109
+ setLoading(false);
110
+ }
111
+ }
112
+
113
+ return (
114
+ <div style={styles.page}>
115
+ <div style={styles.card}>
116
+ <h1 style={styles.title}>留言板</h1>
117
+ <p style={styles.subtitle}>
118
+ 前端 React → NestJS → Supabase 全链路连通性测试
119
+ </p>
120
+
121
+ <form style={styles.form} onSubmit={submit}>
122
+ <input
123
+ style={styles.input}
124
+ placeholder="你的名字(可选)"
125
+ value={name}
126
+ onChange={(e) => setName(e.target.value)}
127
+ />
128
+ <textarea
129
+ style={styles.textarea}
130
+ placeholder="写点什么…"
131
+ value={content}
132
+ onChange={(e) => setContent(e.target.value)}
133
+ />
134
+ <div style={styles.row}>
135
+ <button style={styles.button} type="submit" disabled={loading}>
136
+ {loading ? '提交中…' : '提交留言'}
137
+ </button>
138
+ </div>
139
+ </form>
140
+
141
+ {error && <div style={styles.error}>{error}</div>}
142
+
143
+ {messages.length === 0 ? (
144
+ <div style={styles.empty}>还没有留言,来写第一条吧</div>
145
+ ) : (
146
+ messages.map((m) => (
147
+ <div key={m.id} style={styles.msg}>
148
+ <div style={styles.msgHead}>
149
+ <span style={styles.msgName}>{m.name}</span>
150
+ <span style={styles.msgTime}>
151
+ {new Date(m.created_at).toLocaleString('zh-CN')}
152
+ </span>
153
+ </div>
154
+ <div style={styles.msgBody}>{m.content}</div>
155
+ </div>
156
+ ))
157
+ )}
158
+ </div>
159
+ </div>
160
+ );
161
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import App from './App.jsx';
4
+
5
+ createRoot(document.getElementById('root')).render(<App />);
@@ -0,0 +1,30 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ // app-builder G 方案:dev 时 vite 不独立跑,而是被 server/src/main.ts 的
5
+ // `createViteServer({ middlewareMode: true })` 当 middleware 挂进 nest,前端 HMR
6
+ // 和 /api 都从 nest 监听的 CLAWD_PREVIEW_PORT 出(spec 2026-06-01 §5.6)。
7
+ // 这个 config 仅用于:
8
+ // 1. `vite build` 生成 web/dist 静态资源(prod 由 nest serve)
9
+ // 2. 脱离 clawd 直接 `pnpm dev` 跑 vite 独立模式(本地调试)
10
+ const tunnelHost = process.env.CLAWD_TUNNEL_HOST ?? '';
11
+ const port = Number(process.env.CLAWD_PREVIEW_PORT ?? 5173);
12
+
13
+ export default defineConfig({
14
+ plugins: [react()],
15
+ build: {
16
+ outDir: 'dist',
17
+ emptyOutDir: true,
18
+ },
19
+ // 隧道经 nest 主进程进来,vite middleware 自己识别 base。standalone 模式(无 tunnel)
20
+ // 走 base: '/' 方便本地直接打开。
21
+ base: tunnelHost ? `/preview/${port}/` : '/',
22
+ server: {
23
+ host: '127.0.0.1',
24
+ port,
25
+ strictPort: true,
26
+ hmr: tunnelHost
27
+ ? { protocol: 'wss', clientPort: 443, path: `/preview/${port}/`, host: tunnelHost }
28
+ : undefined,
29
+ },
30
+ });
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+ # 从示例模板生成一个新 extension
3
+ # 用法: new-extension.sh <name> [示例模板, 默认 nestjs-react]
4
+ #
5
+ # 目标目录解析:
6
+ # - picker 模式(推荐):persona-app-builder/projects/<name>/ 已由 daemon createProject
7
+ # 建好(含 .clawd-project.json)→ 把模板内容展开到此目录,保留 .clawd-project.json。
8
+ # - 老路径兼容:projects/<name>/ 不存在时回退到 persona-app-builder/<name>/。
9
+ set -euo pipefail
10
+ KIT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
11
+ PERSONA_DIR="$(cd "$KIT_DIR/.." && pwd)"
12
+
13
+ NAME="${1:?用法: new-extension.sh <name> [模板,默认 nestjs-react]}"
14
+ TMPL="${2:-nestjs-react}"
15
+ SRC="$KIT_DIR/examples/$TMPL"
16
+
17
+ [ -d "$SRC" ] || { echo "示例模板不存在: $SRC (现有: $(ls "$KIT_DIR/examples"))"; exit 1; }
18
+
19
+ PICKER_DEST="$PERSONA_DIR/projects/$NAME"
20
+ if [ -d "$PICKER_DEST" ] && [ -f "$PICKER_DEST/.clawd-project.json" ]; then
21
+ DEST="$PICKER_DEST"
22
+ # picker 模式:目录已存在且仅含 .clawd-project.json,把模板内容展开进去
23
+ REMAINING="$(find "$DEST" -mindepth 1 -maxdepth 1 ! -name '.clawd-project.json' -print -quit)"
24
+ [ -z "$REMAINING" ] || { echo "目标已有内容(非空目录): $DEST"; exit 1; }
25
+ cp -R "$SRC/." "$DEST/"
26
+ else
27
+ DEST="$PERSONA_DIR/$NAME"
28
+ [ -e "$DEST" ] && { echo "目标已存在: $DEST"; exit 1; }
29
+ cp -r "$SRC" "$DEST"
30
+ fi
31
+
32
+ # 写 ext.conf(框架相关配置,publish.sh 会读)
33
+ cat > "$DEST/ext.conf" <<EOF
34
+ APP_NAME=$NAME
35
+ CODE_DIR=./server
36
+ FC_ENTRY=dist/main.js
37
+ BUILD_CMD="cd web && npm install && npm run build && cd ../server && npm install && npm run build"
38
+ # 本 extension 拥有的 Supabase 表(空格分隔,必须 ${NAME}_ 前缀);remove-extension.sh 据此清理
39
+ SUPABASE_TABLES=""
40
+ EOF
41
+
42
+ echo "✅ 新 extension: $DEST"
43
+ echo ""
44
+ echo "接下来:"
45
+ echo " 1) 设计 Supabase 表(务必用 ${NAME}_ 前缀,别碰 clawos 已有表)"
46
+ echo " 2) 改前端(web/)和后端(server/)业务逻辑"
47
+ echo " 3) 本地验证后发布: extension-kit/scripts/publish.sh $DEST"
48
+ echo ""
49
+ echo "换框架/语言: 改 ext.conf 的 BUILD_CMD/FC_ENTRY;换语言再看 extension-kit/README.md"
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================
3
+ # 一键发布 extension 到阿里云 FC(框架无关)
4
+ # 用法: publish.sh <extension目录>
5
+ # extension 目录里可放 ext.conf 声明框架相关的: APP_NAME/CODE_DIR/FC_ENTRY/BUILD_CMD
6
+ # ============================================================
7
+ set -euo pipefail
8
+
9
+ KIT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
10
+ PERSONA_DIR="$(cd "$KIT_DIR/.." && pwd)"
11
+
12
+ EXT_DIR="${1:?用法: publish.sh <extension目录>}"
13
+ EXT_DIR="$(cd "$EXT_DIR" && pwd)"
14
+
15
+ # 1) 平台变量 + extension 自身配置(后者覆盖前者)
16
+ source "$KIT_DIR/config.env"
17
+ [ -f "$EXT_DIR/ext.conf" ] && source "$EXT_DIR/ext.conf"
18
+ APP_NAME="${APP_NAME:-$(basename "$EXT_DIR")}"
19
+ CODE_DIR="${CODE_DIR:-./server}"
20
+ FC_ENTRY="${FC_ENTRY:-dist/main.js}"
21
+ BUILD_CMD="${BUILD_CMD:-}"
22
+
23
+ # 2) 阿里云凭证(现读)+ Serverless Devs 认证(必须含 AccountID,SK 走 heredoc 不进命令行)
24
+ set -a; . "$PERSONA_DIR/.secrets/aliyun.env"; set +a
25
+ ACC="$(aliyun sts GetCallerIdentity 2>/dev/null | python3 -c 'import sys,json;print(json.load(sys.stdin)["AccountId"])')"
26
+ mkdir -p ~/.s
27
+ cat > ~/.s/access.yaml <<EOF
28
+ default:
29
+ AccountID: '$ACC'
30
+ AccessKeyID: $ALIBABA_CLOUD_ACCESS_KEY_ID
31
+ AccessKeySecret: $ALIBABA_CLOUD_ACCESS_KEY_SECRET
32
+ EOF
33
+ chmod 600 ~/.s/access.yaml
34
+
35
+ # 3) 构建产物(框架相关,由 ext.conf 的 BUILD_CMD 定义)
36
+ if [ -n "$BUILD_CMD" ]; then
37
+ echo "==> build: $BUILD_CMD"
38
+ ( cd "$EXT_DIR" && eval "$BUILD_CMD" )
39
+ fi
40
+
41
+ # 4) 放置框架无关的 bootstrap 到 code 目录
42
+ cp "$KIT_DIR/contract/bootstrap" "$EXT_DIR/$CODE_DIR/bootstrap"
43
+ chmod +x "$EXT_DIR/$CODE_DIR/bootstrap"
44
+
45
+ # 5) 渲染 s.yaml(| 作分隔符,避免 URL/层 ARN 里的 / : 冲突)
46
+ sed -e "s|__APP_NAME__|$APP_NAME|g" \
47
+ -e "s|__REGION__|$REGION|g" \
48
+ -e "s|__FC_RUNTIME__|$FC_RUNTIME|g" \
49
+ -e "s|__NODE_LAYER__|$NODE_LAYER|g" \
50
+ -e "s|__FC_CPU__|$FC_CPU|g" \
51
+ -e "s|__FC_MEMORY__|$FC_MEMORY|g" \
52
+ -e "s|__FC_TIMEOUT__|$FC_TIMEOUT|g" \
53
+ -e "s|__CODE_DIR__|$CODE_DIR|g" \
54
+ -e "s|__FC_ENTRY__|$FC_ENTRY|g" \
55
+ -e "s|__SUPABASE_URL__|$SUPABASE_URL|g" \
56
+ -e "s|__SUPABASE_KEY__|$SUPABASE_KEY|g" \
57
+ "$KIT_DIR/contract/s.yaml.tmpl" > "$EXT_DIR/s.yaml"
58
+
59
+ # 6) 部署
60
+ echo "==> s deploy ($APP_NAME)"
61
+ ( cd "$EXT_DIR" && s deploy -y )
62
+
63
+ # 7) 取自定义域名 + 验证
64
+ DOM="$(aliyun fc GET /2023-03-30/custom-domains --region "$REGION" 2>/dev/null | python3 -c "
65
+ import sys,json
66
+ d=json.load(sys.stdin)
67
+ m=[c['domainName'] for c in d.get('customDomains',[]) if '$APP_NAME' in c.get('domainName','')]
68
+ print(m[0] if m else '')")"
69
+
70
+ echo ""
71
+ echo "=================================================="
72
+ if [ -n "$DOM" ]; then
73
+ echo " ✅ 发布完成: http://$DOM"
74
+ echo "=================================================="
75
+ "$KIT_DIR/scripts/verify.sh" "http://$DOM" || true
76
+ else
77
+ echo " ⚠️ 部署完成但未取到自定义域名,检查 fc3-domain 是否成功"
78
+ fi
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================
3
+ # 清理一个 extension:删 FC 资源(函数+触发器+域名)+ 可选删它的 Supabase 表
4
+ # 用法: remove-extension.sh <extension目录>
5
+ # 删哪些表:读 ext.conf 的 SUPABASE_TABLES(extension 自己声明的)
6
+ # 安全:① 校验 <app>_ 前缀防误删 clawos ② 列出+二次确认 ③ 数据不可逆
7
+ # ============================================================
8
+ set -euo pipefail
9
+
10
+ KIT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
11
+ PERSONA_DIR="$(cd "$KIT_DIR/.." && pwd)"
12
+
13
+ EXT_DIR="${1:?用法: remove-extension.sh <extension目录>}"
14
+ EXT_DIR="$(cd "$EXT_DIR" && pwd)"
15
+
16
+ source "$KIT_DIR/config.env"
17
+ [ -f "$EXT_DIR/ext.conf" ] && source "$EXT_DIR/ext.conf"
18
+ APP_NAME="${APP_NAME:-$(basename "$EXT_DIR")}"
19
+ SUPABASE_TABLES="${SUPABASE_TABLES:-}"
20
+
21
+ set -a; . "$PERSONA_DIR/.secrets/aliyun.env"; set +a
22
+
23
+ # 1) 删 FC 侧(函数 + 触发器 + 自定义域名)
24
+ echo "==> 删 FC 资源: $APP_NAME"
25
+ ( cd "$EXT_DIR" && s remove -y )
26
+
27
+ # 2) 删 Supabase 表(仅当 ext.conf 声明了 SUPABASE_TABLES)
28
+ if [ -n "$SUPABASE_TABLES" ]; then
29
+ echo ""
30
+ echo "⚠️ 即将删除以下 Supabase 表(数据不可逆):"
31
+ for t in $SUPABASE_TABLES; do echo " - public.$t"; done
32
+
33
+ # 安全锁:每个表必须 <app>_ 前缀,否则拒绝(防误伤 clawos 共享库)
34
+ for t in $SUPABASE_TABLES; do
35
+ case "$t" in
36
+ ${APP_NAME}_*) ;;
37
+ *) echo "❌ 表 '$t' 不是 '${APP_NAME}_' 前缀,拒绝删除(可能误伤 clawos)"; exit 1 ;;
38
+ esac
39
+ done
40
+
41
+ read -r -p "确认删表? 输入 yes 继续: " ans
42
+ if [ "$ans" = "yes" ]; then
43
+ TOKEN="$(python3 -c "import json;print(json.load(open('$PERSONA_DIR/.mcp.json'))['mcpServers']['supabase']['env']['SUPABASE_ACCESS_TOKEN'])")"
44
+ for t in $SUPABASE_TABLES; do
45
+ curl -s -X POST "https://api.supabase.com/v1/projects/$SUPABASE_PROJECT_REF/database/query" \
46
+ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
47
+ -d "{\"query\":\"drop table if exists public.$t cascade;\"}" >/dev/null \
48
+ && echo " ✓ dropped public.$t"
49
+ done
50
+ else
51
+ echo "跳过删表(FC 已删;表保留)。"
52
+ fi
53
+ else
54
+ echo "ext.conf 未声明 SUPABASE_TABLES,跳过删表。如有表请手动确认清理。"
55
+ fi
56
+
57
+ echo "✅ $APP_NAME 清理完成。"
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+ # 发布后健康检查:可达性 + Content-Type + 【是否被强制下载】
3
+ # 用法: verify.sh <url>
4
+ set -euo pipefail
5
+ URL="${1:?用法: verify.sh <url>}"
6
+
7
+ echo "== 健康检查: $URL =="
8
+ code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$URL/" || echo 000)
9
+ ctype=$(curl -s -o /dev/null -w "%{content_type}" --max-time 30 "$URL/" || echo "")
10
+ echo "首页: HTTP $code ($ctype)"
11
+
12
+ # 关键检查: 有 Content-Disposition 说明会被浏览器当文件下载(没绑自定义域名的典型症状)
13
+ hdr=$(curl -s -D - -o /dev/null --max-time 30 "$URL/" || true)
14
+ if echo "$hdr" | grep -qi 'content-disposition'; then
15
+ echo "❌ 检测到 Content-Disposition —— 浏览器会下载而非渲染!确认走的是 fc3-domain 自定义域名,而不是 fcapp.run"
16
+ else
17
+ echo "✓ 无 Content-Disposition,浏览器可正常渲染网页"
18
+ fi
19
+
20
+ [ "$code" = "200" ] && echo "✓ 全链路 OK" || echo "⚠️ 首页非 200,查 s logs"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.112-beta.216.545c7ca",
3
+ "version": "0.2.112-beta.218.6282fa2",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",