@vitex/nook 0.0.0-stage → 0.1.0
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/README.md +248 -2
- package/bin/nook.js +13 -0
- package/dist/frontend/assets/index-BjWGt3e9.css +1 -0
- package/dist/frontend/assets/index-Cu74B6FQ.js +38 -0
- package/dist/frontend/icon.svg +8 -0
- package/dist/frontend/icons/apple-touch-icon.png +0 -0
- package/dist/frontend/icons/icon-192.png +0 -0
- package/dist/frontend/icons/icon-512.png +0 -0
- package/dist/frontend/icons/maskable-192.png +0 -0
- package/dist/frontend/icons/maskable-512.png +0 -0
- package/dist/frontend/index.html +24 -0
- package/dist/frontend/manifest.webmanifest +49 -0
- package/dist/frontend/sw.js +83 -0
- package/package.json +37 -4
- package/src/backend/agent/pool.js +229 -0
- package/src/backend/agent/runtime.js +17 -0
- package/src/backend/agent/serialize.js +180 -0
- package/src/backend/agent/tools.js +34 -0
- package/src/backend/cli.js +237 -0
- package/src/backend/config.js +69 -0
- package/src/backend/fs-browser.js +121 -0
- package/src/backend/index.js +3 -0
- package/src/backend/logging.js +9 -0
- package/src/backend/net.js +43 -0
- package/src/backend/package.json +15 -0
- package/src/backend/projects.js +89 -0
- package/src/backend/server.js +433 -0
- package/src/backend/service.js +337 -0
- package/src/backend/sessions.js +187 -0
- package/src/backend/text.js +4 -0
package/README.md
CHANGED
|
@@ -1,3 +1,249 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nook
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
给 Pi coding agent 用的轻量 Web 界面。前端 Vue 3 + Vite,后端 Node。
|
|
4
|
+
|
|
5
|
+
## 结构
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
src/frontend/ Vue 3 + Vite 前端
|
|
9
|
+
src/backend/ Node 后端、Pi SDK、CLI、launchd 服务
|
|
10
|
+
bin/nook.js CLI 入口
|
|
11
|
+
scripts/build.js 构建脚本
|
|
12
|
+
dist/ build 产物
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
前后端各自有独立的 `package.json`,可以单独启动、单独维护。
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 开发
|
|
24
|
+
|
|
25
|
+
前后端分开启动:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 终端 A:后端 API
|
|
29
|
+
npm run dev:backend
|
|
30
|
+
|
|
31
|
+
# 终端 B:前端 Vite
|
|
32
|
+
npm run dev:frontend
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
默认地址:
|
|
36
|
+
|
|
37
|
+
- 后端:`http://127.0.0.1:4317`
|
|
38
|
+
- 前端:`http://localhost:5173`(5173 被占用时会自动用 5174)
|
|
39
|
+
- Vite 会把 `/api` 代理到后端
|
|
40
|
+
|
|
41
|
+
也可以直接进入各自目录:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd src/backend && npm run dev
|
|
45
|
+
cd src/frontend && npm run dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
如果后台服务已经占用了 4317:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
nook service stop
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
或者换端口启动:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
NOOK_PORT=4320 npm run dev:backend
|
|
58
|
+
NOOK_BACKEND=http://127.0.0.1:4320 npm run dev:frontend
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
只想单独启动前端、后端直接用正在运行的服务时:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
NOOK_BACKEND=http://100.x.x.x:4317 npm run dev:frontend
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
地址可以用 `nook status` 查看。
|
|
68
|
+
|
|
69
|
+
从其他设备预览 Vite 时,用终端里打印的 Network 地址,例如 `http://192.168.x.x:5173`。
|
|
70
|
+
|
|
71
|
+
## 构建
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm run build
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
产物:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
dist/frontend/ 构建后的前端
|
|
81
|
+
dist/backend/ 后端副本
|
|
82
|
+
dist/nook 最终可执行命令
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
运行构建后的版本:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
./dist/nook start --host 127.0.0.1 --port 4317
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
也可以用它管理后台服务:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
./dist/nook service install
|
|
95
|
+
./dist/nook service status
|
|
96
|
+
./dist/nook service restart
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 访问方式
|
|
100
|
+
|
|
101
|
+
Nook 只按传入的 `host` / `port` 监听,不依赖任何特定网络服务。
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
nook start --host 127.0.0.1 --port 4317 # 只本机
|
|
105
|
+
nook start --host 0.0.0.0 --port 4317 # 所有网卡
|
|
106
|
+
nook start --host 192.168.1.10 --port 4317 # 指定网卡 IP
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`nook status` 会给出一个访问地址。页面本身没有登录,请只在可信网络里使用。
|
|
110
|
+
|
|
111
|
+
后台服务同样接受这两个参数:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
nook service install --host 0.0.0.0 --port 4317
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## CLI
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
nook start 前台启动
|
|
121
|
+
nook status 查看运行状态
|
|
122
|
+
nook service install 安装并启动后台服务
|
|
123
|
+
nook service uninstall 卸载后台服务
|
|
124
|
+
nook service start 启动后台服务
|
|
125
|
+
nook service stop 停止后台服务
|
|
126
|
+
nook service restart 重启后台服务
|
|
127
|
+
nook service status 查看后台服务状态
|
|
128
|
+
nook help
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 后台服务
|
|
132
|
+
|
|
133
|
+
macOS 使用 launchd,Linux 使用 systemd 用户服务(Ubuntu 24.04+)。
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
nook service install
|
|
137
|
+
nook service status
|
|
138
|
+
nook service restart # 改完后端代码后重启
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
服务直接使用当前仓库目录,不复制代码;服务文件里的路径由安装时的环境动态生成,不依赖固定位置。
|
|
142
|
+
|
|
143
|
+
Linux 下请直接用当前用户运行,不要加 `sudo`。安装时会尝试启用 linger,让服务在未登录时也能运行。如果提示失败,可以手动执行:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
sudo loginctl enable-linger "$USER"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
前端改动后需要重新构建,服务才会在 4317 端口展示新页面:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npm run build:frontend
|
|
153
|
+
nook service restart
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
开发时更推荐用 Vite dev server,带热更新。
|
|
157
|
+
|
|
158
|
+
### macOS 权限提示
|
|
159
|
+
|
|
160
|
+
如果某个项目目录位于 `~/Desktop`、`~/Documents` 或 `~/Downloads`,后台服务里的 agent 可能没有权限读写(macOS 隐私保护)。遇到这种情况,可以:
|
|
161
|
+
|
|
162
|
+
- 用 `nook start` 在当前终端前台运行(继承终端的权限),或
|
|
163
|
+
- 在「系统设置 → 隐私与安全性 → 完全磁盘访问权限」里给 Node 可执行文件授权。
|
|
164
|
+
|
|
165
|
+
服务日志:
|
|
166
|
+
|
|
167
|
+
- macOS:`~/.nook/logs/stdout.log`、`~/.nook/logs/stderr.log`
|
|
168
|
+
- Linux:`journalctl --user -u com.nook.server -f`
|
|
169
|
+
|
|
170
|
+
## Agent
|
|
171
|
+
|
|
172
|
+
- 底层使用 `@earendil-works/pi-coding-agent` SDK
|
|
173
|
+
- 模型完全由 Pi 设置决定,Nook 不指定默认模型
|
|
174
|
+
- 内置工具:Pi 默认的 `read` / `bash` / `edit` / `write`,外加 `server_time`
|
|
175
|
+
- 思考、工具调用参数、工具结果、重试/压缩状态通过 SSE 实时推送
|
|
176
|
+
|
|
177
|
+
### 运行中的消息:插话 / 跟进
|
|
178
|
+
|
|
179
|
+
Agent 运行时输入框仍然可用,发送前可以切换两种模式:
|
|
180
|
+
|
|
181
|
+
- **插话**(`steer`):等当前工具调用结束后插入,改变接下来的方向
|
|
182
|
+
- **跟进**(`followUp`):等这一轮所有工作结束、Agent 停下来后再处理
|
|
183
|
+
|
|
184
|
+
排队中的消息显示在输入框上方,可以点「取回」放回输入框。点「停止」会中止当前运行,并把排队消息一起放回输入框。
|
|
185
|
+
|
|
186
|
+
桌面键盘:`Enter` 发送当前模式,`Alt+Enter` 直接发送跟进。
|
|
187
|
+
|
|
188
|
+
## 会话
|
|
189
|
+
|
|
190
|
+
Nook 直接读 Pi 的 session 文件,不另存格式,也不再扫描项目目录里的旧会话目录:
|
|
191
|
+
|
|
192
|
+
`~/.pi/agent/sessions/` 下当前项目的历史会话(Pi CLI `pi -r` 也能看到 Nook 新建的会话)
|
|
193
|
+
|
|
194
|
+
项目本身只是 `{ name, path }` 记录,存在 `~/.nook/projects.json`。删除项目不会删除目录或会话文件。
|
|
195
|
+
|
|
196
|
+
## 数据
|
|
197
|
+
|
|
198
|
+
Nook 是 Pi 的 Web 包装层,不保存自己的模型或服务配置,只保存管理的项目索引:
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
~/.nook/projects.json 项目索引
|
|
202
|
+
~/.nook/logs macOS 服务日志
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
模型、密钥等配置由 Pi 自己管理(`~/.pi`)。Nook 不写入 `.env`,也没有初始化命令。
|
|
206
|
+
|
|
207
|
+
## 运行参数
|
|
208
|
+
|
|
209
|
+
| 变量 | 说明 |
|
|
210
|
+
| --- | --- |
|
|
211
|
+
| `NOOK_PORT` | 端口,默认 `4317` |
|
|
212
|
+
| `NOOK_HOST` | 监听地址,默认 `127.0.0.1`;`0.0.0.0` 表示所有网卡 |
|
|
213
|
+
| `NOOK_WEB_DIR` | 自定义构建后前端目录 |
|
|
214
|
+
| `NOOK_ALLOW_PROTECTED` | macOS:设为 `1` 允许后台服务访问桌面/文稿/下载 |
|
|
215
|
+
|
|
216
|
+
## PWA / 添加到桌面
|
|
217
|
+
|
|
218
|
+
前端已包含:
|
|
219
|
+
|
|
220
|
+
- `manifest.webmanifest`:fullscreen、start_url、scope、图标
|
|
221
|
+
- 192 / 512 普通图标,192 / 512 maskable 图标
|
|
222
|
+
- `apple-touch-icon` 180
|
|
223
|
+
- `sw.js`:缓存页面壳和静态资源,不缓存 `/api/` 和 SSE
|
|
224
|
+
|
|
225
|
+
安装和 Service Worker 需要安全上下文(HTTPS 或 localhost)。直接通过 `http://100.x.x.x:4317` 打开时可以正常使用页面,但不会注册 Service Worker,Chrome 也不会出现安装入口。
|
|
226
|
+
|
|
227
|
+
本机可以用 `http://localhost:4317` 测试。要在手机上安装,建议用 Tailscale Serve 提供 HTTPS:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
tailscale serve --bg --https=443 http://127.0.0.1:4317
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
然后打开:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
https://<machine>.<tailnet>.ts.net/
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Service Worker 只负责页面壳和静态资源;API 和 SSE 始终走网络。
|
|
240
|
+
|
|
241
|
+
## Android App
|
|
242
|
+
|
|
243
|
+
不想折腾 HTTPS / PWA 的话,`android/` 里有一个原生 WebView 壳,直接把页面打成 APK:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
./android/build.sh # 产物:dist/nook.apk
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
安装后填一次服务地址(`http://电脑IP:4317`)即可,支持明文 http,外链走系统浏览器,返回键按网页栈后退。细节见 [android/README.md](android/README.md)。
|
package/bin/nook.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
process.env.NOOK_LAUNCHER = fileURLToPath(import.meta.url);
|
|
5
|
+
|
|
6
|
+
const { main } = await import('../src/backend/index.js');
|
|
7
|
+
|
|
8
|
+
main(process.argv.slice(2)).then((code) => {
|
|
9
|
+
process.exitCode = code ?? 0;
|
|
10
|
+
}).catch((err) => {
|
|
11
|
+
console.error(err?.stack || String(err));
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{color-scheme:light;--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;--ease: cubic-bezier(.2, .8, .2, 1);--ease-out: cubic-bezier(.16, 1, .3, 1);--dur: .22s;--r-sm: 8px;--r-md: 12px;--r-lg: 18px;--r-xl: 26px}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}html{height:100%}body{min-height:100%;margin:0;background:var(--bg);color:var(--text);font-family:var(--font);font-size:16px;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}::selection{background:var(--accent);color:var(--accent-ink)}button,input,textarea{font:inherit;color:inherit}button{background:none;border:0;padding:0;cursor:pointer;touch-action:manipulation}a{color:inherit}svg{display:block}:focus{outline:none}:focus-visible{outline:2px solid var(--accent);outline-offset:2px}input,textarea{caret-color:var(--text)}.page{min-height:100dvh;display:flex;flex-direction:column;animation:page-in .2s var(--ease-out) both}.topbar{position:sticky;top:0;z-index:30;padding-top:env(safe-area-inset-top);background:var(--header-bg);backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5);border-bottom:1px solid var(--line)}.topbar-inner{width:100%;max-width:760px;margin:0 auto;height:56px;padding:0 12px;display:flex;align-items:center;gap:4px}.topbar-actions{flex:none;display:flex;align-items:center;gap:2px}.icon{display:inline-flex;align-items:center;justify-content:center}.topbar h1{flex:1;min-width:0;margin:0;font-size:15.5px;font-weight:600;letter-spacing:-.015em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.brand{flex:1;display:flex;align-items:center;gap:6px;font-size:20px;font-weight:700;letter-spacing:-.045em}.brand .dot{width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.icon-btn{width:38px;height:38px;flex:none;display:grid;place-items:center;border-radius:50%;color:var(--text);transition:background .16s var(--ease),color .16s var(--ease),transform .12s var(--ease)}.icon-btn:active{background:var(--surface-2);transform:scale(.94)}.icon-btn.muted{color:var(--muted)}.text-btn{flex:none;padding:8px;border-radius:9px;color:var(--muted);font-size:13.5px;transition:background .16s var(--ease),color .16s var(--ease)}.text-btn:active{background:var(--surface-2);color:var(--text)}.text-btn.danger{color:var(--danger)}.content{flex:1;width:100%;max-width:760px;margin:0 auto;padding:10px 16px calc(32px + env(safe-area-inset-bottom))}.list{display:flex;flex-direction:column}.row{width:100%;min-height:66px;padding:12px 6px;display:flex;align-items:center;gap:13px;border-bottom:1px solid var(--line);border-radius:10px;text-align:left;transition:background .16s var(--ease),border-color .16s var(--ease)}.row[role=button]{cursor:pointer}.row:last-child{border-bottom-color:transparent}.row:active{background:var(--surface-2)}.row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.row-title{display:flex;align-items:center;gap:7px;min-width:0;color:var(--text);font-size:15.5px;font-weight:500;letter-spacing:-.012em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.row-title .label{min-width:0;overflow:hidden;text-overflow:ellipsis}.row-sub{color:var(--muted);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}.row-mark{flex:none;width:36px;height:36px;display:grid;place-items:center;border-radius:11px;background:var(--surface);box-shadow:inset 0 0 0 1px var(--line);color:var(--muted);font-size:13px;font-weight:600;letter-spacing:0}.row-chevron{flex:none;color:var(--faint)}.running-dot{flex:none;width:6px;height:6px;border-radius:50%;background:var(--accent);animation:pulse 1.8s var(--ease) infinite}.row .trash-btn{flex:none;width:38px;height:38px;display:grid;place-items:center;border-radius:50%;color:var(--muted);transition:background .16s var(--ease),color .16s var(--ease)}.row .trash-btn:active{background:var(--surface-2);color:var(--danger)}.row.editing{cursor:default}.empty{flex:1;display:grid;place-items:center;min-height:58vh}.empty-add{width:72px;height:72px;display:grid;place-items:center;border:1px solid var(--line);border-radius:50%;background:var(--surface);color:var(--muted);box-shadow:var(--shadow-sm);transition:transform .18s var(--ease),box-shadow .18s var(--ease),color .18s var(--ease)}.empty-add:active{transform:scale(.95);color:var(--text)}.loading{min-height:58vh;display:grid;place-items:center;color:var(--muted)}.spinner{width:18px;height:18px;border:2px solid var(--line-strong);border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite}.chat-page{height:100dvh;display:flex;flex-direction:column;overflow:hidden}.chat-scroll{flex:1;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent;mask-image:linear-gradient(to bottom,transparent 0,#000 18px,#000 100%);-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 18px,#000 100%)}.chat-scroll::-webkit-scrollbar{width:8px}.chat-scroll::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:4px}.chat-inner{width:100%;max-width:760px;margin:0 auto;padding:24px 16px 36px}.msg{margin:0 0 26px}.msg.enter{animation:msg-in .24s var(--ease-out) both}.msg.user{display:flex;justify-content:flex-end}.msg.user .bubble{max-width:min(84%,560px);padding:11px 15px;border-radius:18px 18px 6px;background:var(--user-bubble);color:var(--user-ink);font-size:15.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word;text-wrap:pretty}.msg.assistant{display:block;max-width:700px}.msg.assistant .blocks>:last-child{margin-bottom:0}.markdown{color:var(--text);font-size:15.5px;line-height:1.7;word-break:break-word;overflow-wrap:anywhere}.markdown>:first-child{margin-top:0}.markdown>:last-child{margin-bottom:0}.markdown p{margin:0 0 .85em;text-wrap:pretty}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{margin:1.2em 0 .45em;font-weight:600;line-height:1.3;letter-spacing:-.02em}.markdown h1{font-size:1.36em}.markdown h2{font-size:1.2em}.markdown h3{font-size:1.07em}.markdown h4,.markdown h5,.markdown h6{font-size:1em}.markdown ul,.markdown ol{margin:.15em 0 .9em;padding-left:1.4em}.markdown li{margin:.18em 0;padding-left:.1em}.markdown li::marker{color:var(--muted)}.markdown li>ul,.markdown li>ol{margin:.12em 0 .18em}.markdown blockquote{margin:.6em 0 .95em;padding:.08em 0 .08em 13px;border-left:2px solid var(--line-strong);color:var(--muted)}.markdown hr{margin:1.3em 0;border:0;border-top:1px solid var(--line)}.markdown strong{font-weight:600}.markdown a{text-decoration:underline;text-underline-offset:3px;text-decoration-color:color-mix(in srgb,var(--accent) 75%,transparent)}.markdown code{padding:.14em .36em;border-radius:6px;background:var(--code-bg);font-family:var(--mono);font-size:.88em}.markdown pre{margin:.8em 0 1.05em;padding:13px 15px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--code-bg);overflow-x:auto;scrollbar-width:thin}.markdown pre code{padding:0;background:none;font-size:12.5px;line-height:1.6;white-space:pre}.markdown table{display:block;max-width:100%;margin:.6em 0 1.1em;border-collapse:collapse;overflow-x:auto;scrollbar-width:thin;font-size:13.5px}.markdown th,.markdown td{padding:6px 10px;border:1px solid var(--line-strong);text-align:left;white-space:nowrap}.markdown th{background:var(--surface-2);font-weight:600}details>summary{list-style:none}details>summary::-webkit-details-marker{display:none}.block-think{margin:0 0 12px;padding-left:13px;border-left:1.5px solid var(--line-strong);color:var(--muted);font-size:13px}.block-think summary{display:flex;align-items:center;gap:6px;width:fit-content;color:var(--muted);font-size:12px;letter-spacing:.01em;-webkit-user-select:none;user-select:none;cursor:pointer;transition:color .16s var(--ease)}.block-think summary .chev{opacity:.72;transition:transform .2s var(--ease)}.block-think[open] summary .chev{transform:rotate(90deg)}details[open]>.think-body,details[open]>.tool-body{animation:fade .16s var(--ease) both}.block-think .think-body{margin-top:7px;padding-bottom:2px;line-height:1.68;white-space:pre-wrap;word-break:break-word;text-wrap:pretty;opacity:.95}.block-tool{margin:10px 0;border:1px solid var(--line);border-radius:13px;background:var(--surface);overflow:hidden;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.block-tool summary{display:flex;align-items:baseline;gap:8px;padding:9px 12px;cursor:pointer;font-family:var(--mono);font-size:11.8px;line-height:1.45}.block-tool .tool-icon{flex:none;width:16px;text-align:center;font-size:11.5px;color:var(--muted)}.block-tool .tool-name{flex:none;color:var(--text);font-weight:600;letter-spacing:-.01em}.block-tool .tool-args{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted)}.block-tool .tool-meta{flex:none;color:var(--faint);font-size:10px;letter-spacing:.02em}.block-tool .tool-body{border-top:1px solid var(--line);padding:10px 12px 12px;background:color-mix(in srgb,var(--bg) 55%,var(--surface));color:var(--muted);font-family:var(--mono);font-size:11.3px;line-height:1.6}.block-tool .tool-body pre{margin:0;max-height:260px;overflow:auto;white-space:pre-wrap;word-break:break-word;scrollbar-width:thin}.block-tool .tool-label{margin:9px 0 5px;color:var(--faint);font-family:var(--font);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase}.block-tool .tool-label:first-child{margin-top:0}.block-tool.is-error{border-color:color-mix(in srgb,var(--danger) 32%,var(--line))}.block-tool.is-error .tool-body{color:var(--danger);background:var(--danger-soft)}.block-error{margin:10px 0;padding:10px 12px;border:1px solid color-mix(in srgb,var(--danger) 30%,var(--line));border-radius:var(--r-md);background:var(--danger-soft);color:var(--danger);font-size:13px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.msg.live .blocks>.markdown:last-child:after{content:"";display:inline-block;width:2px;height:1.05em;margin-left:2px;border-radius:1px;background:var(--accent);vertical-align:-.16em;animation:blink 1s steps(1,end) infinite}.run-status{max-width:760px;width:100%;margin:0 auto;padding:0 18px 8px;display:flex;align-items:center;justify-content:space-between;gap:10px;color:var(--muted);font-size:12.5px;letter-spacing:.01em;font-variant-numeric:tabular-nums}.run-status[hidden]{display:none}.run-status #run-status-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.stop-btn{flex:none;padding:3px 9px;border:1px solid var(--line);border-radius:999px;color:var(--muted);font-size:11.5px;transition:color .16s var(--ease),border-color .16s var(--ease),background .16s var(--ease)}.stop-btn:active{background:var(--surface-2);color:var(--text)}.stop-btn:disabled{opacity:.4}.queue{max-width:760px;width:100%;margin:0 auto;padding:0 18px 7px;animation:fade .18s var(--ease) both}.queue[hidden]{display:none}.queue-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:3px;color:var(--faint);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase}.queue-clear{padding:2px 5px;border-radius:6px;color:var(--muted);font-size:11px;letter-spacing:0;text-transform:none}.queue-clear:active{color:var(--text);background:var(--surface-2)}.queue-items{max-height:112px;overflow-y:auto;scrollbar-width:thin}.queue-item{display:flex;align-items:baseline;gap:8px;padding:2px 0;color:var(--muted);font-size:12.5px;font-variant-numeric:tabular-nums}.queue-mode{flex:none;padding:0 4px;border:1px solid var(--line);border-radius:5px;color:var(--muted);font-size:9.5px;line-height:1.6}.queue-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.composer-wrap{position:relative;z-index:20;padding:6px 12px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(to bottom,transparent 0%,var(--bg) 30%,var(--bg) 100%)}.composer{width:100%;max-width:760px;margin:0 auto;display:flex;align-items:flex-end;gap:8px;padding:6px 7px 6px 15px;border:1px solid var(--line-strong);border-radius:var(--r-xl);background:var(--surface);box-shadow:var(--shadow-sm),0 10px 30px var(--shadow-color-1);transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}.composer:focus-within{border-color:color-mix(in srgb,var(--text) 22%,var(--line-strong));box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-md)}.composer textarea{flex:1;min-height:36px;max-height:132px;padding:7px 0;border:0;outline:0;resize:none;background:none;font-size:16px;line-height:1.45}.composer textarea::placeholder{color:var(--faint)}.composer textarea:disabled{opacity:.55}.send-btn{flex:none;width:38px;height:38px;display:grid;place-items:center;border-radius:50%;background:var(--accent);color:var(--accent-ink);box-shadow:0 1px 0 var(--shadow-color-1);transition:transform .12s var(--ease),opacity .16s var(--ease),background .16s var(--ease)}.send-btn:disabled{opacity:.28}.send-btn:active:not(:disabled){transform:scale(.92)}.mode-switch{flex:none;display:flex;gap:2px;padding:2px;border:1px solid var(--line);border-radius:999px;background:var(--bg)}.mode-switch[hidden]{display:none}.mode-switch button{height:28px;padding:0 7px;border-radius:999px;color:var(--muted);font-size:11.5px;line-height:28px;transition:background .16s var(--ease),color .16s var(--ease),box-shadow .16s var(--ease)}.mode-switch button.active{background:var(--surface);color:var(--text);box-shadow:var(--shadow-sm)}.jump-btn{position:absolute;left:50%;bottom:calc(100% + 2px);z-index:25;width:38px;height:38px;display:grid;place-items:center;transform:translate(-50%);border:1px solid var(--line);border-radius:50%;background:var(--surface);color:var(--muted);box-shadow:var(--shadow-md);transition:transform .12s var(--ease),opacity .16s var(--ease)}.jump-btn[hidden]{display:none}.jump-btn:active{transform:translate(-50%) scale(.92)}.sheet-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:60;display:flex;align-items:flex-end;justify-content:center;background:var(--overlay);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);animation:fade .16s var(--ease) both}.sheet{width:100%;max-width:520px;padding:18px 18px calc(20px + env(safe-area-inset-bottom));border-radius:24px 24px 0 0;background:var(--surface);box-shadow:var(--shadow-lg);animation:sheet-up .28s var(--ease-out) both}.sheet:before{content:"";display:block;width:34px;height:4px;margin:-6px auto 16px;border-radius:999px;background:var(--line-strong)}.sheet h2{margin:0 0 14px;font-size:18px;font-weight:600;letter-spacing:-.02em}.field{display:flex;flex-direction:column;gap:7px;margin-bottom:14px}.field label{color:var(--muted);font-size:11.5px;letter-spacing:.02em}.field input{width:100%;padding:12px 13px;border:1px solid var(--line);border-radius:13px;outline:none;background:var(--bg);font-size:16px;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.field input:focus{border-color:var(--line-strong);box-shadow:0 0 0 3px var(--accent-soft)}.sheet-error{min-height:17px;margin:2px 0 0;color:var(--danger);font-size:12.5px}.sheet-actions{display:flex;justify-content:flex-end;gap:6px;margin-top:16px}.btn{padding:10px 16px;border-radius:13px;font-size:14px;font-weight:500;transition:transform .12s var(--ease),opacity .16s var(--ease),background .16s var(--ease),color .16s var(--ease)}.btn:disabled{opacity:.4}.btn:active:not(:disabled){transform:scale(.97)}.btn-ghost{color:var(--muted)}.btn-primary{background:var(--text);color:var(--bg)}.toast{position:fixed;top:calc(14px + env(safe-area-inset-top));left:50%;z-index:100;max-width:calc(100vw - 32px);padding:10px 15px;transform:translate(-50%);border-radius:999px;background:var(--text);color:var(--bg);font-size:12.5px;box-shadow:var(--shadow-md);animation:toast-in .2s var(--ease-out) both}.toast[hidden]{display:none}.dir-field{display:flex;align-items:center;gap:6px}.dir-trigger{flex:1;min-width:0;height:46px;padding:0 12px;display:flex;align-items:center;gap:9px;border:1px solid var(--line);border-radius:13px;background:var(--bg);text-align:left;transition:background .16s var(--ease),border-color .16s var(--ease)}.dir-trigger:active{background:var(--surface-2)}.dir-trigger-icon{flex:none;color:var(--muted)}.dir-trigger-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14.5px}.dir-trigger-chevron{flex:none;color:var(--faint)}.dir-reset{flex:none;padding:8px 5px;color:var(--muted);font-size:12px}.dir-reset:active{color:var(--text)}.dir-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;display:flex;justify-content:center;background:var(--bg);animation:fade .12s var(--ease) both}.dir-panel{width:100%;max-width:680px;height:100dvh;display:flex;flex-direction:column;background:var(--bg)}.dir-head{flex:none;height:calc(56px + env(safe-area-inset-top));padding:env(safe-area-inset-top) 10px 0;display:flex;align-items:center;gap:6px;border-bottom:1px solid var(--line);background:var(--header-bg);backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5)}.dir-title{flex:1;font-size:16px;font-weight:600;letter-spacing:-.015em}.dir-location{flex:none;display:flex;align-items:center;gap:7px;padding:12px 16px 8px}.dir-up{flex:none;width:34px;height:34px;display:grid;place-items:center;border-radius:50%;color:var(--muted);transition:background .16s var(--ease),opacity .16s var(--ease)}.dir-up:disabled{opacity:.25}.dir-path{flex:1;min-width:0;padding:7px 10px;border-radius:9px;background:var(--surface-2);color:var(--muted);font-family:var(--mono);font-size:11.5px;line-height:1.4;white-space:nowrap;overflow-x:auto;scrollbar-width:none}.dir-path::-webkit-scrollbar{display:none}.dir-mkdir{flex:none;display:flex;gap:8px;padding:0 16px 12px}.dir-mkdir[hidden]{display:none}.dir-mkdir input{flex:1;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:11px;outline:none;background:var(--bg);font-size:15px;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.dir-mkdir input:focus{border-color:var(--line-strong);box-shadow:0 0 0 3px var(--accent-soft)}.dir-mkdir .btn{flex:none}.dir-list{flex:1;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:0 8px 8px;scrollbar-width:thin}.dir-row{width:100%;min-height:50px;padding:10px 12px;display:flex;align-items:center;gap:11px;border-radius:11px;text-align:left;transition:background .16s var(--ease)}.dir-row:active{background:var(--surface-2)}.dir-row-icon{flex:none;color:var(--muted)}.dir-row-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14.5px}.dir-row-chevron{flex:none;color:var(--faint)}.dir-empty{min-height:30vh;padding:40px 20px;display:grid;place-items:center;color:var(--muted);font-size:13px;text-align:center}.dir-more{padding:10px;color:var(--faint);font-size:11.5px;text-align:center}.dir-actions{flex:none;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--line);background:var(--bg)}.dir-actions .btn-primary{min-width:132px}@keyframes spin{to{transform:rotate(360deg)}}@keyframes fade{0%{opacity:0}to{opacity:1}}@keyframes page-in{0%{opacity:.6}to{opacity:1}}@keyframes msg-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}@keyframes sheet-up{0%{opacity:.4;transform:translateY(32px)}to{opacity:1;transform:none}}@keyframes toast-in{0%{opacity:0;transform:translate(-50%) translateY(-6px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@keyframes blink{0%,55%{opacity:1}56%,to{opacity:0}}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 0 0 var(--accent-soft)}50%{opacity:.72;box-shadow:0 0 0 5px transparent}}@media(hover:hover){.row:hover{background:color-mix(in srgb,var(--surface-2) 55%,transparent)}.icon-btn:hover{background:var(--surface-2)}.text-btn:hover{color:var(--text)}.empty-add:hover{color:var(--text);box-shadow:0 0 0 8px var(--accent-soft),var(--shadow-sm)}.stop-btn:hover{color:var(--text);border-color:var(--line-strong)}.queue-clear:hover,.btn-ghost:hover{color:var(--text)}.dir-trigger:hover,.dir-row:hover{background:var(--surface-2)}.block-tool:hover{border-color:var(--line-strong);box-shadow:var(--shadow-sm)}.block-think summary:hover{color:var(--text)}}@media(min-width:720px){.topbar-inner{padding:0 20px}.content{padding-top:16px}.chat-inner{padding-top:32px}.sheet-backdrop{align-items:center;padding:24px}.sheet{max-width:480px;padding-bottom:20px;border-radius:22px}.sheet:before{display:none}.dir-backdrop{align-items:center;padding:24px;background:var(--overlay);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}.dir-panel{height:min(760px,88dvh);border-radius:18px;overflow:hidden;box-shadow:var(--shadow-lg)}.dir-head{height:56px;padding-top:0;border-radius:18px 18px 0 0}}@media(max-width:380px){.row-mark{width:32px;height:32px;border-radius:10px}.msg.user .bubble{max-width:88%}.mode-switch button{padding:0 5px;font-size:11px}.composer{padding-left:12px}.chat-inner{padding-left:14px;padding-right:14px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}:root{color-scheme:light;--porcelain: #F4F6F8;--cobalt: #2456A6;--ink: #182026;--emerald: #1F7A6B;--bg: var(--porcelain);--page-gutter: 16px;--surface: #FFFFFF;--surface-2: #EDF1F4;--surface-3: #E5EBEF;--surface-4: #F7F9FA;--surface-hover: #F0F4F6;--text: var(--ink);--text-strong: #11171C;--text-2: #5B6773;--muted: #7E8A95;--faint: #A8B3BD;--on-primary: #F7FAFF;--code-ink: #3B4B59;--primary: var(--cobalt);--primary-press: #1B437F;--primary-soft: #E7EFFA;--primary-soft-2: #F0F5FD;--primary-soft-3: #F6F9FE;--primary-line: #C8D8F0;--primary-glow: rgba(36, 86, 166, .24);--focus-ring: rgba(36, 86, 166, .16);--accent: var(--emerald);--accent-press: #176153;--accent-soft: #E1F2ED;--accent-soft-2: #EEF8F5;--accent-ink: #176153;--accent-line: #C6E6DD;--line: #E9EDF1;--line-soft: #F1F4F7;--line-strong: #DFE5EA;--line-ink: rgba(24, 32, 38, .08);--success: #1F9D7A;--success-ink: #176153;--success-soft: #E1F2ED;--success-line: #C6E6DD;--danger: #C4453C;--danger-press: #A63830;--danger-soft: #F9E9E7;--danger-soft-2: #FCF3F2;--danger-line: #EAC7C3;--outgoing: #E3F5EF;--outgoing-ink: #16352E;--outgoing-time: #4F8B7A;--outgoing-line: rgba(31, 122, 107, .14);--avatar-1-bg: #E8EFFA;--avatar-1-fg: #2C5B9E;--avatar-2-bg: #E3F4EF;--avatar-2-fg: #1F7A6B;--avatar-3-bg: #ECEFF3;--avatar-3-fg: #4A5A6A;--avatar-4-bg: #EEEAF8;--avatar-4-fg: #665A92;--overlay: rgba(16, 24, 32, .42);--overlay-strong: rgba(16, 24, 32, .52);--overlay-solid: #101820;--shadow-color-1: rgba(16, 24, 32, .05);--shadow-color-2: rgba(16, 24, 32, .08);--shadow-color-3: rgba(16, 24, 32, .12);--shadow-color-4: rgba(16, 24, 32, .18);--elev-1: 0 0 0 0 transparent;--elev-2: 0 0 0 0 transparent;--elev-3: 0 0 0 0 transparent;--elev-4: 0 0 0 0 transparent;--white-90: rgba(255, 255, 255, .92);--white-85: rgba(255, 255, 255, .86);--white-80: rgba(255, 255, 255, .82);--white-70: rgba(255, 255, 255, .72);--white-58: rgba(255, 255, 255, .6);--white-50: rgba(255, 255, 255, .52);--composer-fade: rgba(244, 246, 248, .75);--composer-fade-0: rgba(244, 246, 248, 0);--text-soft: var(--text-2);--code-bg: #EDF1F4;--user-bubble: var(--outgoing);--user-ink: var(--outgoing-ink);--header-bg: rgba(255, 255, 255, .86);--shadow-sm: var(--elev-1);--shadow-md: var(--elev-2);--shadow-lg: var(--elev-4)}.tg{position:fixed;top:0;right:0;bottom:0;left:0;height:auto;display:flex;flex-direction:column;overflow:hidden;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Inter,PingFang SC,Helvetica Neue,sans-serif;font-feature-settings:"tnum" 1;-webkit-font-smoothing:antialiased}.tg-masthead{flex:none;padding:calc(18px + env(safe-area-inset-top)) var(--page-gutter) 14px;background:transparent}.tg-masthead h1{margin:0;color:var(--primary);font-size:28px;line-height:1;font-weight:700;letter-spacing:-.045em}.tg-new{flex:none;width:32px;height:32px;display:grid;place-items:center;border-radius:0;border:1px solid var(--primary-line);background:var(--primary-soft);color:var(--primary);font-size:19px;font-weight:400;line-height:1;box-shadow:var(--elev-2);transition:background .15s,transform .12s}.tg-new:active{background:var(--primary-soft);transform:scale(.94)}.tg-list.sessions{padding:0 var(--page-gutter) calc(24px + env(safe-area-inset-bottom));gap:8px}.tg-project-scroll{flex:1;min-height:0;overflow-y:auto;padding:2px var(--page-gutter) calc(24px + env(safe-area-inset-bottom));scrollbar-width:none}.tg-project-scroll::-webkit-scrollbar{display:none}.tg-project-grid{display:flex;flex-direction:column;gap:10px}.tg-project-card{min-height:0;padding:12px 14px;display:flex;flex-direction:row;align-items:center;gap:12px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-2);text-align:left;transition:transform .14s,box-shadow .14s,border-color .14s}.tg-project-card:active{transform:scale(.985);box-shadow:var(--elev-1);border-color:var(--line)}.tg-avatar.card-avatar{width:40px;height:40px;font-size:14px}.tg-card-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.tg-card-date{flex:none;align-self:flex-start;padding-top:2px;color:var(--faint);font-size:9px;white-space:nowrap}.tg-card-name{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:14px;font-weight:600;letter-spacing:-.015em}.tg-card-path{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:9.5px}.tg-project-card.new{justify-content:flex-start;border-style:dashed;border-color:var(--line-strong);background:var(--surface-2);box-shadow:none;color:var(--muted)}.tg-new-card-icon{flex:none;width:32px;height:32px;display:grid;place-items:center;border-radius:0;background:var(--primary-soft);color:var(--primary);font-size:18px}.tg-new-card-main{display:flex;flex-direction:column;gap:2px}.tg-new-card-title{font-size:11px;font-weight:600;color:var(--text-2)}.tg-new-card-sub{font-size:9px;color:var(--muted)}.tg-list{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;padding:4px 0 0;scrollbar-width:none}.tg-list::-webkit-scrollbar{display:none}.tg-row{position:relative;width:100%;display:flex;align-items:center;gap:12px;padding:9px var(--page-gutter);text-align:left;transition:background .12s}.tg-row:active{background:var(--surface-2)}.tg-row:after{content:"";position:absolute;left:74px;right:0;bottom:0;height:1px;background:var(--line-soft)}.tg-row:last-of-type:after{display:none}.tg-avatar{flex:none;width:46px;height:46px;display:grid;place-items:center;border-radius:0;font-size:15px;font-weight:600;letter-spacing:-.01em}.tg-avatar.small{width:36px;height:36px;font-size:13px}.tg-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.tg-row-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;letter-spacing:-.012em;color:var(--text)}.tg-row-end{flex:none;margin-left:2px;color:var(--muted);font-size:9.5px;white-space:nowrap}.tg-row-sub{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:1.3;color:var(--muted)}.tg-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:40px 20px;text-align:center}.tg-empty-icon{width:52px;height:52px;display:grid;place-items:center;margin-bottom:6px;border-radius:0;background:var(--primary-soft-3);color:var(--primary);font-size:22px}.tg-empty b{font-size:13px;font-weight:600;color:var(--text)}.tg-empty span{color:var(--muted);font-size:10.5px}.tg-empty-btn{margin-top:8px;padding:7px 13px;border-radius:0;background:var(--primary);color:var(--on-primary);font-size:10px;font-weight:600}.tg-pagehead{flex:none;min-height:56px;padding:calc(8px + env(safe-area-inset-top)) var(--page-gutter) 8px;display:flex;align-items:center;gap:9px;background:transparent}.tg-circle{flex:none;width:30px;height:30px;display:grid;place-items:center;border-radius:0;background:var(--surface-2);color:var(--text-2);font-size:13px;transition:background .14s}.tg-circle:active{background:var(--surface-3)}.tg-pagehead-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tg-pagehead-main h1{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:16px;font-weight:600;letter-spacing:-.025em}.tg-pagehead-main p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:10px}.tg-pagehead .tg-new{width:32px;height:32px;font-size:18px}.tg-pagehead .tg-avatar-button{border:1px solid var(--line);box-shadow:var(--elev-2)}.tg-session-search{flex:none;display:flex;align-items:center;gap:8px;height:36px;margin:8px var(--page-gutter) 10px;padding:0 10px;border:1px solid var(--line);background:var(--surface);color:var(--muted);box-shadow:var(--elev-2)}.tg-session-search:focus-within{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring),var(--elev-2)}.tg-session-search svg{flex:none}.tg-session-search input{flex:1;min-width:0;border:0;outline:0;background:transparent;color:var(--text);font-family:inherit;font-size:11.5px}.tg-session-search input::placeholder{color:var(--faint)}.tg-session-search input::-webkit-search-cancel-button{display:none}.tg-row.session{padding:11px 12px;background:var(--surface);border:1px solid var(--line);box-shadow:var(--elev-1);transition:background .14s,border-color .14s,box-shadow .14s}.tg-row.session:after{display:none}.tg-row.session .tg-row-end{align-self:flex-start;padding-top:3px}.tg-row-sub.live{color:var(--success-ink)}.tg-wall{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--bg)}.tg-wall:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(var(--white-85) .7px,transparent .7px);background-size:13px 13px;opacity:.5}.tg-chat-back{position:absolute;top:calc(8px + env(safe-area-inset-top));left:12px;z-index:7}.tg-circle.glass{width:32px;height:32px;border:1px solid var(--line);background:var(--white-90);box-shadow:var(--elev-2)}.tg-circle.glass:active{background:var(--white-80);transform:scale(.94)}.tg-chatscroll{position:relative;z-index:2;flex:1;min-height:0;overflow-y:auto;overscroll-behavior:none;overflow-anchor:none;-webkit-overflow-scrolling:touch;scrollbar-width:none}.tg-chatscroll::-webkit-scrollbar{display:none}.tg-chatbody{padding:calc(52px + env(safe-area-inset-top)) 12px calc(84px + env(safe-area-inset-bottom))}.tg-date{display:flex;justify-content:center;margin:2px 0 10px}.tg-date span{padding:3px 9px;border-radius:0;background:var(--white-58);color:var(--muted);font-size:9px;box-shadow:var(--elev-1)}.tg-msg{display:flex;flex-direction:column;margin-bottom:7px}.tg-msg.user{align-items:flex-end}.tg-msg.assistant{align-items:flex-start}.tg-bubble{position:relative;max-width:85%;padding:8px 11px 6px;border-radius:0;box-shadow:var(--elev-1)}.tg-bubble.in{background:var(--surface);border:1px solid var(--line-soft);border-bottom-left-radius:0}.tg-bubble.out{background:var(--outgoing);border:1px solid var(--outgoing-line);border-bottom-right-radius:0}.tg-bubble.in:before,.tg-bubble.out:before{content:"";position:absolute;bottom:0;width:8px;height:10px;background:inherit}.tg-bubble.in:before{left:-4px;clip-path:polygon(100% 0,100% 100%,0 100%)}.tg-bubble.out:before{right:-4px;clip-path:polygon(0 0,100% 100%,0 100%)}.tg-bubble p{margin:0;color:var(--text);font-size:12.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word}.tg-msg-time{margin-top:4px;color:var(--faint);font-size:8.5px;line-height:1;white-space:nowrap}.tg-bubble.out p{color:var(--outgoing-ink)}.rich{color:var(--text);font-size:13px;line-height:1.66}:deep(.rich p){margin:0 0 .55em}:deep(.rich > :last-child){margin-bottom:0}:deep(.rich ul){margin:.1em 0 .55em;padding-left:1.1em}:deep(.rich li){margin:.18em 0}:deep(.rich li::marker){color:var(--primary)}:deep(.rich code){padding:1px 3px;border-radius:0;background:var(--surface-2);color:var(--code-ink);font-family:SF Mono,Menlo,Consolas,monospace;font-size:.86em}:deep(.rich strong){font-weight:600}.tg-think{width:fit-content;max-width:88%;margin-bottom:5px;padding:5px 9px;border-radius:0;background:var(--white-58);color:var(--muted);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}.tg-think summary{display:flex;align-items:center;gap:4px;list-style:none;color:var(--muted);font-size:9.5px;cursor:pointer}.tg-think summary::-webkit-details-marker{display:none}.tg-chev{font-size:10px;transition:transform .18s}.tg-think[open] .tg-chev{transform:rotate(90deg)}.tg-think p{margin:4px 0 1px;color:var(--muted);font-size:10px;line-height:1.6;white-space:pre-wrap}.tg-tool{width:88%;margin-bottom:5px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-1);overflow:hidden}.tg-tool summary{display:flex;align-items:center;gap:8px;padding:7px 9px;list-style:none;cursor:pointer}.tg-tool summary::-webkit-details-marker{display:none}.tg-tool-icon{flex:none;width:26px;height:26px;display:grid;place-items:center;border-radius:0;background:var(--primary-soft-2);color:var(--primary);font-family:SF Mono,Menlo,monospace;font-size:9px}.tg-tool-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tg-tool-main b{color:var(--text);font-size:9.5px;font-weight:600}.tg-tool-main span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-family:SF Mono,Menlo,monospace;font-size:9px}.tg-tool-state{flex:none;color:var(--success-ink);font-size:8.5px;white-space:nowrap}.tg-tool-chev{flex:none;color:var(--faint);font-size:11px;transition:transform .18s}.tg-tool[open] .tg-tool-chev{transform:rotate(90deg)}.tg-tool-body{padding:0 9px 8px;border-top:1px solid var(--line-soft);background:var(--surface-2)}.tg-tool-label{margin:7px 0 3px;color:var(--faint);font-size:8px;letter-spacing:.08em;text-transform:uppercase}.tg-tool-body pre{margin:0;max-height:78px;overflow:auto;color:var(--muted);font-family:SF Mono,Menlo,Consolas,monospace;font-size:8px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.tg-tool.running{border-color:var(--accent-line)}.tg-tool.running .tg-tool-icon{background:var(--accent-soft);color:var(--accent-ink);animation:tg-pulse 1.3s infinite}.tg-tool.error{border-color:var(--danger-line)}.tg-tool.error .tg-tool-icon{background:var(--danger-soft);color:var(--danger)}.tg-tool.error .tg-tool-main b{color:var(--danger)}.tg-error{max-width:85%;margin-bottom:5px;padding:8px 10px;border:1px solid var(--danger-line);border-radius:0;background:var(--danger-soft-2);color:var(--danger);font-size:10.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word}.tg-caret{display:inline-block;width:5px;height:11px;margin:2px 0 0 8px;border-radius:0;background:var(--primary);animation:tg-blink 1s steps(2) infinite}.tg-bottom-dock{position:absolute;left:0;right:0;bottom:0;z-index:5;display:flex;flex-direction:column;pointer-events:none}.tg-bottom-dock>*{pointer-events:auto}.tg-queue{position:relative;z-index:4;flex:none;margin:0 10px 4px;padding:7px 9px;border:1px solid var(--white-70);border-radius:0;background:var(--white-80);box-shadow:var(--elev-2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}.tg-queue-head{display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:9px}.tg-queue-head button{color:var(--primary);font-size:8.5px}.tg-queue-row{display:flex;align-items:center;gap:6px;margin-top:4px}.tg-queue-mode{flex:none;padding:1px 5px;border-radius:0;background:var(--primary-soft);color:var(--primary);font-size:8px}.tg-queue-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-2);font-size:10px}.tg-queue-row button{flex:none;color:var(--muted);font-size:8.5px}.tg-run{position:relative;z-index:4;flex:none;display:flex;align-items:center;gap:6px;margin:0 12px 5px;padding:4px 9px;border:1px solid var(--white-70);border-radius:0;background:var(--white-80);box-shadow:var(--elev-2);color:var(--text-2);font-size:9.5px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}.tg-spinner{flex:none;width:6px;height:6px;background:var(--primary);border-radius:0;animation:tg-pulse 1.2s infinite}.tg-run-time{margin-left:auto;color:var(--muted);font-variant-numeric:tabular-nums}.tg-run button{flex:none;color:var(--danger);font-size:8.5px}.tg-composer{position:relative;z-index:4;flex:none;padding:2px 10px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(to top,var(--composer-fade),var(--composer-fade-0))}.tg-inputbar{display:flex;align-items:flex-end;gap:5px;padding:4px 4px 4px 11px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-2);transition:border-color .16s,box-shadow .16s}.tg-inputbar:focus-within{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring),var(--elev-2)}.tg-inputbar textarea{flex:1;min-height:28px;max-height:80px;padding:6px 0;border:0;outline:0;resize:none;overflow-y:hidden;background:transparent;color:var(--text);font-family:inherit;font-size:13px;line-height:1.45}.tg-inputbar textarea::placeholder{color:var(--faint)}.tg-mode{flex:none;display:flex;gap:1px;padding:2px;border-radius:0;background:var(--surface-2);margin-bottom:3px}.tg-mode button{height:22px;padding:0 6px;border-radius:0;color:var(--muted);font-size:9px;line-height:22px;transition:background .14s,color .14s}.tg-mode button.active{background:var(--surface);color:var(--primary);box-shadow:var(--elev-1)}.tg-send{flex:none;width:31px;height:31px;display:grid;place-items:center;margin-bottom:1px;border-radius:0;background:var(--primary);color:var(--on-primary);font-size:15px;font-weight:500;box-shadow:var(--elev-2);transition:opacity .15s,transform .12s}.tg-send:disabled{opacity:.3;box-shadow:none}.tg-send:active:not(:disabled){transform:scale(.94)}@keyframes tg-spin{to{transform:rotate(360deg)}}@keyframes tg-blink{50%{opacity:0}}@keyframes tg-pulse{50%{opacity:.45}}.tg-msg.enter{animation:tg-msg-in .18s ease-out both}.tg-loading{min-height:50vh;display:grid;place-items:center}.tg-loading .spinner{width:18px;height:18px;border:2px solid var(--line);border-top-color:var(--primary);border-radius:0;animation:tg-spin .7s linear infinite}.tg-jump{position:absolute;left:50%;bottom:calc(100% + 6px);transform:translate(-50%);width:32px;height:32px;display:grid;place-items:center;border:1px solid var(--line);background:var(--white-90);color:var(--text-2);box-shadow:var(--elev-2);z-index:6}.tg-jump:active{background:var(--white-80);transform:translate(-50%) scale(.94)}@keyframes tg-msg-in{0%{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}*,*:before,*:after{border-radius:0!important}.sheet-backdrop{background:var(--overlay)}.sheet{background:var(--surface);color:var(--text);border:1px solid var(--line);padding:18px;max-width:420px;box-shadow:var(--elev-4)}.sheet:before{display:none}.sheet h2{color:var(--text);font-size:18px;font-weight:600;letter-spacing:-.02em}.field label{color:var(--muted);font-size:10px}.field input{border:1px solid var(--line);background:var(--surface-2);color:var(--text);font-size:15px}.field input:focus{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring)}.sheet-error{color:var(--danger)}.btn{border-radius:0}.btn-primary{background:var(--primary);color:var(--on-primary)}.btn-primary:active{background:var(--primary-press)}.btn-ghost{color:var(--text-2)}.dir-trigger{border:1px solid var(--line);background:var(--surface-2);color:var(--text)}.dir-trigger.placeholder .dir-trigger-label{color:var(--faint)}.dir-trigger-icon,.dir-trigger-chevron{color:var(--muted)}.dir-reset{color:var(--primary)}.dir-backdrop{background:var(--overlay-solid)}.dir-panel{background:var(--surface);color:var(--text)}.dir-head{background:var(--surface);border-bottom:1px solid var(--line)}.dir-title{color:var(--text)}.dir-path{background:var(--surface-2);color:var(--text-2)}.dir-row{color:var(--text)}.dir-row-icon,.dir-row-chevron{color:var(--muted)}.dir-mkdir input{background:var(--surface-2);border-color:var(--line);color:var(--text)}.dir-actions{background:var(--surface);border-top:1px solid var(--line)}.dir-empty{color:var(--muted)}.dir-up{color:var(--text-2)}.toast{background:var(--text);color:var(--on-primary)}.spinner{border-top-color:var(--primary)}.tg-masthead{display:flex;align-items:center;justify-content:space-between;gap:12px}.tg-edit{flex:none;color:var(--muted);font-size:10px;padding:4px 0}.tg-card-delete{flex:none;align-self:flex-start;color:var(--danger);font-size:9px;padding:4px 0}.tg-row.session .tg-card-delete{align-self:flex-start;padding-top:3px}.tg-run-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dir-head .icon-btn{color:var(--text-2)}.dir-head .icon-btn:active,.dir-row:active,.dir-trigger:active{background:var(--surface-2)}.dir-mkdir input:focus{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring)}.rich{overflow-wrap:anywhere}.rich>:first-child{margin-top:0}.rich>:last-child{margin-bottom:0}.rich h1,.rich h2,.rich h3,.rich h4,.rich h5,.rich h6{margin:1.1em 0 .4em;font-weight:600;line-height:1.3;letter-spacing:-.015em}.rich h1{font-size:1.3em}.rich h2{font-size:1.18em}.rich h3{font-size:1.06em}.rich h4,.rich h5,.rich h6{font-size:1em}.rich ol{margin:.1em 0 .55em;padding-left:1.25em}.rich li::marker{color:var(--primary)}.rich pre{margin:.7em 0 .8em;padding:9px 10px;border:1px solid var(--line);background:var(--surface-2);overflow-x:auto;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin}.rich pre code{padding:0;background:none;border:0;color:var(--code-ink);font-size:10.5px;line-height:1.6;white-space:pre}.rich blockquote{margin:.6em 0 .7em;padding:.1em 0 .1em 10px;border-left:2px solid var(--line-strong);color:var(--muted)}.rich hr{margin:1em 0;border:0;border-top:1px solid var(--line)}.rich a{color:var(--primary);text-decoration:underline;text-underline-offset:2px}.rich table{display:block;max-width:100%;margin:.5em 0 .8em;border-collapse:collapse;overflow-x:auto;font-size:10.5px}.rich th,.rich td{padding:5px 8px;border:1px solid var(--line);text-align:left;white-space:nowrap}.rich th{background:var(--surface-2);font-weight:600}@media(max-width:899px){.tg-bubble.in.has-code{max-width:100%}.rich pre{scrollbar-width:none;-ms-overflow-style:none}.rich pre::-webkit-scrollbar{display:none;width:0;height:0}}:root{color-scheme:light}::selection{background:var(--primary-soft-2);color:var(--text)}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}input::placeholder,textarea::placeholder{color:var(--faint)}.dir-more{color:var(--muted)}.tg-project-card[role=button],.tg-row[role=button]{cursor:pointer;touch-action:manipulation}.dir-up:active:not(:disabled){background:var(--surface-2)}.btn-ghost:active{background:var(--surface-2)}.tg-project-card{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.tg-menu-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:16px;background:var(--overlay);animation:tg-fade .14s ease-out both}.tg-menu{width:100%;max-width:420px;padding:6px;border:1px solid var(--line);background:var(--surface);box-shadow:var(--elev-4);animation:tg-menu-in .16s ease-out both}.tg-menu-item{width:100%;padding:12px 10px;border-bottom:1px solid var(--line-soft);text-align:left;color:var(--text);font-size:13px}.tg-menu-item:last-child{border-bottom:0}.tg-menu-item:active{background:var(--surface-2)}.tg-menu-item.danger{color:var(--danger)}@keyframes tg-fade{0%{opacity:0}to{opacity:1}}@keyframes tg-menu-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.sheet-backdrop{align-items:center;justify-content:center;padding:16px}.sheet{width:100%;max-width:420px;animation:tg-dialog-in .16s ease-out both}@keyframes tg-dialog-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.tg-avatar-button{cursor:pointer}.tg-avatar-button:active{opacity:.65}.tg-row{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}body{overscroll-behavior:none}html,body{touch-action:pan-x pan-y}.tg-logo{flex:none;width:32px;height:32px;display:block;box-shadow:var(--elev-2)}.tg-logo svg{width:100%;height:100%}@media(hover:hover){.tg-project-card:hover{border-color:var(--line-strong);box-shadow:var(--elev-3)}.tg-row.session:hover{border-color:var(--line-strong);box-shadow:var(--elev-2)}.tg-new:hover{background:var(--primary-soft-2)}.tg-circle.glass:hover,.tg-jump:hover{background:var(--white-85)}.tg-mode button:hover{color:var(--text-2)}.tg-mode button.active:hover{color:var(--primary)}}.tg-masthead,.tg-project-scroll{width:100%;max-width:none;margin:0}.tg-project-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}.tg-project-card{width:100%;min-width:0;min-height:70px}.tg-project-console{background:var(--bg)}.tg-console-head{flex:none;width:100%;max-width:none;margin:0;padding:calc(14px + env(safe-area-inset-top)) var(--page-gutter) 14px;display:flex;align-items:center;gap:12px}.tg-logo-button{cursor:pointer;transition:transform .12s,opacity .12s}.tg-logo-button:active{transform:scale(.94);opacity:.8}.tg-console-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.tg-console-meta h1{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:17px;line-height:1.2;font-weight:600;letter-spacing:-.025em}.tg-console-meta p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:10.5px}.tg-console-body{flex:1;min-height:0;width:100%;max-width:none;margin:0;display:flex;flex-direction:column;overflow:hidden}.tg-session-pane{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.tg-session-pane-top{flex:none;padding:2px var(--page-gutter) 0}.tg-session-pane .tg-session-search{margin:6px 0}.tg-session-pane .tg-list.sessions{padding:0 var(--page-gutter) calc(20px + env(safe-area-inset-bottom));scrollbar-width:none;-ms-overflow-style:none}.tg-session-pane .tg-list.sessions::-webkit-scrollbar{width:0;height:0;display:none}.tg-row.session.active{border-color:var(--primary-line);background:var(--primary-soft-3)}.tg-row.session.active:before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:2px;background:var(--primary)}.tg-row.session.active .tg-row-title{color:var(--primary)}.tg-chat-pane{flex:1;min-height:0;display:none;position:relative;overflow:hidden}.tg-project-console.has-session .tg-session-pane{display:none}.tg-project-console.has-session .tg-chat-pane{display:flex}.tg-chat-panel{position:relative;flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:var(--bg)}@media(min-width:900px){.tg-console-head{padding:10px 16px 8px;gap:8px}.tg-console-meta h1{font-size:14px}.tg-console-meta p{font-size:10px}.tg-session-pane .tg-console-head .tg-logo{width:26px;height:26px}.tg-session-pane .tg-console-head .tg-new{width:26px;height:26px;font-size:15px}.tg-console-body{flex-direction:row;padding:0}.tg-session-pane{flex:0 0 340px;width:340px;display:flex!important;border:1px solid var(--line);border-right:0;background:var(--surface)}.tg-chat-pane{display:flex!important;border:1px solid var(--line);background:var(--bg)}.tg-session-pane-top{padding:2px 16px 0}.tg-session-pane .tg-list.sessions{padding:0 16px 18px}.tg-session-pane .tg-session-search{margin:10px 0 6px}.tg-session-pane .tg-session-search input{font-size:12.5px}.tg-session-pane .tg-row.session{padding:10px 12px}.tg-session-pane .tg-row-title{font-size:13px}.tg-session-pane .tg-row-sub{font-size:10.5px}.tg-session-pane .tg-row.session .tg-row-end{font-size:9.5px}.tg-chat-back{display:none}.tg-chatbody{width:100%;max-width:948px;margin:0 auto;padding:22px 24px 90px}.tg-composer{padding:4px 24px 20px}.tg-composer>.tg-inputbar{width:100%;max-width:900px;margin:0 auto}.tg-composer .tg-jump{bottom:calc(100% + 4px)}.tg-queue{width:calc(100% - 48px);max-width:900px;margin:0 auto 6px}.tg-bubble p{font-size:14px}.tg-bubble{max-width:78%;padding:10px 13px 8px}.rich{font-size:14px;line-height:1.7}.tg-think{max-width:82%}.tg-think p{font-size:12px}.tg-tool{width:82%}.tg-tool-main b{font-size:11px}.tg-tool-main span{font-size:10px}.tg-tool-body pre{font-size:10.5px;max-height:220px}.tg-error{font-size:12.5px;max-width:78%}.tg-date span{font-size:10.5px}.tg-msg{margin-bottom:10px}.tg-inputbar textarea{font-size:14px;max-height:180px}.tg-send{width:34px;height:34px}.tg-mode button{height:24px;padding:0 8px;font-size:10px;line-height:24px}.tg-project-card{min-height:76px;padding:14px 16px}.tg-card-name{font-size:15px}.tg-card-path{font-size:11px}.tg-card-date{font-size:10.5px}.tg-row-title{font-size:14.5px}.tg-row-sub{font-size:11.5px}}@media(hover:hover){.tg-logo-button:hover{opacity:.82}.tg-row.session.active:hover{border-color:var(--primary);background:var(--primary-soft-2)}}input:focus,input:focus-visible,textarea:focus,textarea:focus-visible{outline:none}.tg-inputbar:focus-within,.tg-session-search:focus-within,.field input:focus,.dir-mkdir input:focus{border-color:var(--line);box-shadow:none}
|