@spzxg/cli-ui 0.4.0 → 0.6.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 CHANGED
@@ -18,11 +18,25 @@ import "@spzxg/cli-ui/styles.css";
18
18
 
19
19
  <CliChat jobId="job_xxx" /> // 打开已有对话(对话任务的第一个对话)
20
20
  <CliChat jobId="job_xxx" taskId="task_yyy" /> // 对话任务里的某个对话;taskId="new" 新开一个
21
- <CliChat jobId="job_batch" taskId="task_zzz" /> // 一次性任务 / 续派的子任务:只读查看执行过程
21
+ <CliChat jobId="job_batch" taskId="task_zzz" /> // 一次性任务 / 续派的子任务:运行中只能看,结束后可以接着它聊
22
22
  <CliChat jobId={null} newConversation={{ title: "周报", businessId: "biz-1" }} /> // 新对话
23
23
  <CliMsgList jobIds={["job_xxx"]} onSelect={setJobId} /> // 列表
24
24
  ```
25
25
 
26
+ 列表只显示 `jobIds` 里的任务(加上本页新建的对话)。不传 `jobIds` 就是空列表:组件不会去中枢列出这个产品线令牌下的全部对话,哪些任务给哪个用户看由宿主决定。
27
+
28
+ 三栏想左右拖动改宽度,用 `CliSplit`(Web Component:`<cli-split>`)包起来:
29
+
30
+ ```tsx
31
+ <CliCenterProvider baseUrl="/api/center">
32
+ <CliSplit storageKey="strategy"> {/* 记住拖好的宽度;panes 可改每栏初始 / 最小 / 最大宽度 */}
33
+ <CliMsgList jobIds={ids} />
34
+ <CliChat />
35
+ <CliBoard />
36
+ </CliSplit>
37
+ </CliCenterProvider>
38
+ ```
39
+
26
40
  组件请求同源的 `/api/center`(可以用 `baseUrl` 改),由代理转到中枢并注入令牌:
27
41
 
28
42
  ```nginx
@@ -108,17 +122,54 @@ location /api/center/ {
108
122
  <CliCenterProvider> // 和对话联动:对话里点文件 / 「查看浏览器」在看板里打开
109
123
  <CliChat />
110
124
  <CliBoard collapsed={!open} onExpand={() => setOpen(true)} onCollapse={() => setOpen(false)}
111
- fileActions={[{ label: "引用", onClick: (file) => quote(file.path) }]} />
125
+ extraTabs={[{ id: "term", label: "终端", render: ({ jobId, quote }) => <MyTerminal jobId={jobId} onQuote={(t) => quote({ kind: "terminal", label: "终端输出", text: t })} /> }]} />
112
126
  </CliCenterProvider>
113
127
  ```
114
128
 
115
129
  - 页签:文件(目录、预览、下载)、改动(diff,只读)、浏览器(实时画面,接管后可直接操作)。`tabs={["files","changes"]}` 选页签。
116
130
  - 预览:Markdown、代码、文本、CSV、图片、PDF、HTML(沙箱 iframe)、Word(.docx,mammoth 转 HTML 放进无脚本沙箱)。其他类型下载。
117
- - 自动同步:实时流有进展就刷新(节流 1.5 秒),运行中每 4 秒(`pollMs`)再刷一次;改过的文件标「有更新」,打开着的文件改了自动重读。
131
+ - 自动同步:实时流有进展就刷新(节流 1.5 秒),运行中每 15 秒(`pollMs`)兜底再刷一次;改过的文件标「有更新」,打开着的文件改了自动重读。
118
132
  - 没有看板时,对话自己弹窗预览(`<CliChat fileOpen="auto|board|modal|link">`)。宿主也可以 `store.openInBoard(jobId, { kind: "file", path })`。
133
+ - 下载:单个文件;文件夹(页签右上角 / 文件夹行尾)在浏览器里打包成 ZIP,最多 2000 个文件、共 300 MB。
134
+ - 弱网 / 节点忙:读文件 30 秒没响应、或传输中 60 秒没收到数据就报错,预览里有「重试」;读超过 8 秒提示「网络较慢」。打包下载时每个文件失败会自动重试 3 次,一直读不到的跳过,其余照样打包,失败清单在压缩包里的 `_下载失败的文件.txt`。
135
+ - 放大:文件预览、浏览器画面都能放大到整页(Esc 还原);接管浏览器时自动放大。图片可缩放(Ctrl / ⌘ + 滚轮)。
136
+ - 引用到对话:文件预览、浏览器的「引用到对话」把它带进下一条消息(`store.addRef`),对话输入框上方显示、可去掉;发出时合成「看板上下文」附件。自定义页签(`extraTabs`)的 `quote` 同理——终端之类的交互以后都走这条路进对话。
137
+ - 多个文件页签:点开的文件各占一个页签(最多 8 个,再开关掉最早的),可关闭(× 或鼠标中键),按对话记在 sessionStorage,刷新后还在。
138
+ - 选中引用:在预览里选中文字浮出「引用到对话」;在浏览器网页里复制(⌘C / Ctrl+C)后提示里也有「引用到对话」。
139
+ - 正在看:打开着的文件 / 浏览器页面缺省随下一条消息带上一次(输入框上方虚线卡片「正在看」,× 这次不带;`autoQuoteOpenFile={false}` 关掉)。状态在 `store.getState().viewing`。
140
+ - 浏览器弱网:操作没送达时提示(不自动重发,免得点两次);接管时发了操作 8 秒画面没变化提示并给「重连画面」;按住鼠标切走窗口自动补发松开;地址栏自动补 `https://`。
119
141
  - 数据都经中枢:`/api/jobs/:id/board`、`/files`、`/files/raw/<路径>`、`/diff`、`/browser`(+ `events` / `frames` / `input`)。
120
142
  - 链路、交互、故障与重试的设计见 [BOARD-DESIGN.md](BOARD-DESIGN.md)。
121
- - 浏览器里带令牌时(传了 `token` / `headers` / `line`),图片、PDF、HTML、下载先 fetch 成 blob 再显示;走同源代理时直接用地址。
143
+ - 浏览器里带令牌时(传了 `token` / `headers` / `line`,或代理跨域),图片、PDF、HTML、下载用中枢发的 30 分钟短期链接(令牌在路径里,HTML 的相对资源也能加载,大文件流式下载、不进内存);走同源代理时直接用地址。中枢太旧发不了短期链接时退回先 fetch 成 blob(超过 50 MB 的不预览)。
144
+
145
+ ## 对接业务数据
146
+
147
+ 页面通过 `store` 拿文件、追加背景、发消息;看板可以不显示(不放 `CliBoard`,或 `<cli-board hidden>`)。
148
+
149
+ ```tsx
150
+ const store = createCliStore({ baseUrl: "/api/center" }); // 或 Provider 里 useCliStore();Web Component:el.store
151
+ <CliCenterProvider store={store} onTurnEnd={async (p) => { // 每轮结束拿产出
152
+ const files = await store.workspace(p.job_id).listAll();
153
+ }}>…</CliCenterProvider>
154
+
155
+ const ws = store.workspace(); // 当前选中的对话;或 store.workspace("job_xxx");Web Component:el.workspace()
156
+ await ws.list(dir); await ws.listAll(dir);
157
+ await ws.readText(path); // ≤ 20 MB,GBK 自动转码
158
+ await ws.readFile(path); // Blob,≤ 500 MB(maxBytes 可调),更大的用 fileUrl / download
159
+ await ws.zip(dir); // { blob, name, files, failed }
160
+ await ws.download(path); await ws.downloadFolder(dir);
161
+ await ws.fileUrl(path, { download: true });
162
+ ws.openFile(); ws.openFiles(); ws.open(path); await ws.info();
163
+
164
+ store.appendContext(jobId, text, { title, id }); // 随下一条消息带给智能体;null = 新对话的第一条
165
+ store.removeContext(jobId, id);
166
+ await store.send(jobId, text);
167
+ ```
168
+
169
+ - 追加的背景显示在输入框上方(「补充背景」),发出后在这个对话里一直有效;同一任务里新开的对话不会自动带上。创建时的项目背景用 `newConversation.workspace.context`。每条最长 20000 字,同 `id` 替换。
170
+ - 事件:`board_change`(看板切换文件)、`context`(补充背景变化 / 发出)、`board_ref`。
171
+ - Web Component 的方法在元素注册后才有:`await customElements.whenDefined("cli-chat")`。元素上还有 `store`、`appendContext`、`removeContext`,TypeScript 里 `document.querySelector("cli-board")` 自带类型。
172
+ - 服务端渲染:组件和 `@spzxg/cli-ui/elements` 都能在服务端导入 / 渲染(`defineCliElements()` 在服务端什么都不做);Next.js 在用到组件的文件写 `"use client"`。
122
173
 
123
174
  ## 界面配置
124
175
 
@@ -169,14 +220,31 @@ Agent 回复里指向本地文件的链接(`report.md`、`src/a.ts:12`、`file
169
220
 
170
221
  ## 开发
171
222
 
223
+ 源码在 **operator-oss/packages/cli-ui**(这里)。三个工程的关系:
224
+
225
+ | 工程 | 放什么 | 和组件的关系 |
226
+ | --- | --- | --- |
227
+ | `operator-oss` | 执行节点(Operator)+ **组件源码** `packages/cli-ui` | 改组件都在这里改;组件的样式从同仓库的 `app/globals.css` 同步(`css:sync`) |
228
+ | `clawbizx` | 业务协同工程,统一发布 `@spzxg/*` 包 | `packages/cli-ui` 是指向 `../../operator-oss/packages/cli-ui` 的链接,`scripts/publish-shared-packages.sh` 从这里发布到 npm |
229
+ | `cli-task-center` | 中枢(组件的数据都来自它) | 组件的使用文档在中枢 API 文档的「前端组件」页签(`backend/public/api.html`) |
230
+
231
+ 两个仓库要并排放在同一个目录下(`~/operator-oss`、`~/clawbizx`),链接才有效。组件有自己的依赖,不和 Operator 共用:
232
+
172
233
  ```bash
173
- npm run demo -w @spzxg/cli-ui # 假中枢 + 演示页 http://localhost:12790(?mode=chat / ?mode=wired / elements.html;看板用 e2e-local.sh 的 ?mode=board,单独集成看 blocks.html?job=…,先 build:embed)
174
- npm test -w @spzxg/cli-ui
175
- npm run lint -w @spzxg/cli-ui
176
- npm run css:sync -w @spzxg/cli-ui # Operator 改了样式后重新同步
177
- npm run build:embed -w @spzxg/cli-ui # 第三方一体化产物 dist/cli-ui.js + cli-ui.css
234
+ cd operator-oss/packages/cli-ui
235
+ npm install # 第一次
236
+ npm test # 测试
237
+ npm run lint # 类型检查
238
+ npm run demo # 假中枢 + 演示页 http://localhost:12790(?mode=chat / ?mode=wired / elements.html;看板用 e2e-local.sh 的 ?mode=board,单独集成看 blocks.html?job=…,先 build:embed)
239
+ npm run css:sync # Operator 改了样式后重新同步
240
+ npm run build:embed # 第三方一体化产物 dist/cli-ui.js + cli-ui.css
178
241
  bash demo/e2e-local.sh # 连真实 center 联调:本地 center + 假节点 + 一次性本地库,演示页代理过去
179
242
  bash demo/e2e-local.sh stop
243
+ bash demo/e2e-real.sh # 真实整条链路:本地 center + 源码跑的真实节点 + 本机 ego lite(看板浏览器、故障演练;不跑智能体)
244
+ bash demo/e2e-real.sh stop
245
+
246
+ # 发布(在 clawbizx 里)
247
+ cd clawbizx && bash scripts/publish-shared-packages.sh
180
248
  ```
181
249
 
182
- 演示用的是 `demo/mock-center.mjs` 里的内存数据,不要把演示页指向生产中枢。
250
+ 演示用的是 `demo/mock-center.mjs` 里的内存数据,不要把演示页指向生产中枢。Operator 的 `tsconfig.json`、`.dockerignore` 排除了 `packages/`,组件不进 Operator 的构建和镜像。