@spzxg/cli-ui 0.4.0 → 0.6.1

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 (44) hide show
  1. package/README.md +84 -10
  2. package/dist/cli-ui-embed-Dk2QGHxn.js +41146 -0
  3. package/dist/cli-ui-index-BFpRZXn4.js +11209 -0
  4. package/dist/cli-ui-jszip.min-B9tqMA-e.js +2324 -0
  5. package/dist/cli-ui-jszip.min-DIavJzUG.js +26 -0
  6. package/dist/cli-ui-xlsx-BKHhqcoa.js +93 -0
  7. package/dist/cli-ui.css +1 -1
  8. package/dist/cli-ui.js +1 -1
  9. package/package.json +3 -1
  10. package/src/board/BrowserPane.tsx +396 -96
  11. package/src/board/ChangesPane.tsx +13 -4
  12. package/src/board/CliBoard.tsx +219 -37
  13. package/src/board/FileViewer.tsx +387 -73
  14. package/src/board/FilesPane.tsx +51 -4
  15. package/src/board/blocks.tsx +3 -2
  16. package/src/board/fileKind.ts +31 -0
  17. package/src/board/fileOps.ts +55 -0
  18. package/src/board/folderDownload.ts +161 -0
  19. package/src/board/frameQuote.ts +50 -0
  20. package/src/board/textLoad.ts +99 -0
  21. package/src/board/workspace.ts +129 -0
  22. package/src/board/zip.ts +85 -0
  23. package/src/chat/CliChat.tsx +122 -23
  24. package/src/chat/Composer.tsx +4 -4
  25. package/src/core/blocks.ts +69 -11
  26. package/src/core/client.ts +285 -41
  27. package/src/core/config.ts +18 -5
  28. package/src/core/conversation.ts +17 -7
  29. package/src/core/store.ts +340 -71
  30. package/src/core/textDecode.ts +24 -0
  31. package/src/core/types.ts +21 -6
  32. package/src/core/xlsx.ts +142 -0
  33. package/src/elements.tsx +106 -11
  34. package/src/index.ts +7 -2
  35. package/src/layout/CliSplit.tsx +53 -0
  36. package/src/layout/split.ts +214 -0
  37. package/src/msglist/CliMsgList.tsx +50 -22
  38. package/src/styles.css +101 -0
  39. package/src/ui/ErrorBoundary.tsx +38 -0
  40. package/src/ui/TextBlock.tsx +1 -1
  41. package/src/ui/Transcript.tsx +10 -5
  42. package/src/ui/transcriptModel.ts +66 -9
  43. package/dist/cli-ui-embed-D7xtcvGG.js +0 -37967
  44. package/dist/cli-ui-index-O0krpZBg.js +0 -13516
@@ -7,7 +7,7 @@
7
7
  * 界面以节点转录为主;转录还没有(没派发、节点连不上)时用轮次的 input / reply 兜底。
8
8
  */
9
9
  import { isBatchSnapshot, type AskAnswers, type AskQuestion, type BatchStreamSnapshot, type BatchStreamTask, type CenterTurn, type ConversationClosedCallback, type ConversationTurnCallback, type JobStatus, type Message, type Msg, type NodeEvent, type StreamItem, type StreamSnapshot, type StreamTask, type ToolData, type TurnUsage } from "./types.js";
10
- import { indexFromEnd, mergeSnapshot, toolDataOf } from "../ui/transcriptModel.js";
10
+ import { indexFromEnd, mergeSnapshot, prependOlder, toolDataOf } from "../ui/transcriptModel.js";
11
11
  import { formatAnswersText } from "../ui/format.js";
12
12
 
13
13
  export const TERMINAL_TURN = new Set(["succeeded", "failed", "cancelled", "merged"]);
@@ -68,6 +68,8 @@ export interface ConvState {
68
68
  /** 节点转录(Operator 消息)。 */
69
69
  msgs: Msg[];
70
70
  hasTranscript: boolean;
71
+ /** 节点转录里比 msgs 更早、还没取的条数(实时流只给最新一段;往上翻时 store.loadOlder 分页取)。 */
72
+ older: number;
71
73
  nodeRunning: boolean;
72
74
  resolvedModel: string | null;
73
75
  /** 上次刷新任务详情之后,实时流里累计的用量(usage 事件)。 */
@@ -89,7 +91,7 @@ export interface ConvState {
89
91
  }
90
92
 
91
93
  export const emptyConv = (key: string): ConvState => ({
92
- key, ...parseConvKey(key), job: null, task: null, turns: [], msgs: [], hasTranscript: false, nodeRunning: false, resolvedModel: null,
94
+ key, ...parseConvKey(key), job: null, task: null, turns: [], msgs: [], hasTranscript: false, older: 0, nodeRunning: false, resolvedModel: null,
93
95
  liveUsage: { fresh: 0, cacheRead: 0 }, stream: "idle", streamError: null, endReason: null, continuedBy: null, localAnswers: {},
94
96
  batch: false, batchTask: null, remoteTaskId: null,
95
97
  });
@@ -152,7 +154,7 @@ function focusBatchTask(conv: ConvState, task: BatchStreamTask | null): ConvStat
152
154
  const batchTask = task ? { ...kept, ...task } : null;
153
155
  return {
154
156
  ...conv, batch: true, batchTask, task: batchTask ? batchStreamTask(batchTask) : null, remoteTaskId: remote,
155
- ...(sameRemote ? {} : { msgs: [], hasTranscript: false, nodeRunning: false }),
157
+ ...(sameRemote ? {} : { msgs: [], hasTranscript: false, older: 0, nodeRunning: false }),
156
158
  };
157
159
  }
158
160
 
@@ -175,7 +177,7 @@ function applyBatchTask(conv: ConvState, task: BatchStreamTask): ConvState {
175
177
  }
176
178
 
177
179
  // 缺字段时兜底:generation 缺省 1(按它分会话,缺了会把顺序排乱);时间缺就不显示。
178
- const toMsg = (m: Message): Msg => ({ id: m.id, role: m.role, content: m.content, generation: typeof m.generation === "number" ? m.generation : 1, ...(typeof m.created_at === "number" ? { ts: m.created_at } : {}) });
180
+ export const toMsg = (m: Message): Msg => ({ id: m.id, role: m.role, content: m.content, generation: typeof m.generation === "number" ? m.generation : 1, ...(typeof m.created_at === "number" ? { ts: m.created_at } : {}) });
179
181
 
180
182
  export function applyItems(conv: ConvState, items: StreamItem[]): ConvState {
181
183
  let next = conv;
@@ -185,7 +187,8 @@ export function applyItems(conv: ConvState, items: StreamItem[]): ConvState {
185
187
  if (item.type === "transcript") {
186
188
  // 节点转录全量(连上 / 重连节点时各一次):整体替换,没变的消息保留对象引用。
187
189
  const messages = Array.isArray(item.messages) ? item.messages.map(toMsg) : [];
188
- next = { ...next, msgs: mergeSnapshot(next.msgs, messages), hasTranscript: true, nodeRunning: item.running === true };
190
+ const merged = mergeSnapshot(next.msgs, messages, typeof item.older === "number" ? item.older : 0);
191
+ next = { ...next, msgs: merged.msgs, older: merged.older, hasTranscript: true, nodeRunning: item.running === true };
189
192
  } else if (item.type === "node") {
190
193
  next = applyNodeEvent(next, item.event);
191
194
  } else if (item.type === "turn") {
@@ -285,6 +288,11 @@ export function applyNodeEvent(conv: ConvState, ev: NodeEvent): ConvState {
285
288
  }
286
289
  }
287
290
 
291
+ /** 往上翻取到的一页更早的节点消息(旧的在前)。older:再往前还剩几条。 */
292
+ export function applyOlderPage(conv: ConvState, page: Message[], older: number): ConvState {
293
+ return { ...conv, msgs: prependOlder(conv.msgs, page.map(toMsg)), older: Math.max(0, older) };
294
+ }
295
+
288
296
  /** 这个对话结束了:整个对话任务结束,或者只是这一个对话被关闭。 */
289
297
  export const convEnded = (conv: Pick<ConvState, "job" | "task">) => !!conv.task?.closed || (!!conv.job && TERMINAL_JOB.has(conv.job.status));
290
298
 
@@ -312,7 +320,8 @@ export function viewMessages(conv: ConvState): Msg[] {
312
320
  // 转录里的第一条用户消息、内容又不是开出会话那一轮的原文,就是它;措辞以后变了也认得出。
313
321
  // 之后的消息里再出现这句固定语句(例如会话被重启),按原文匹配。
314
322
  const openerText = opener ? opener.sent_input ?? opener.input : null;
315
- let replaced = false;
323
+ // 更早的消息还没取(older > 0)时,手里的第一条用户消息不是会话的开场:不按位置认。
324
+ let replaced = conv.older > 0;
316
325
  for (const m of conv.msgs) {
317
326
  const firstUser = !replaced && m.role === "user";
318
327
  if (firstUser) replaced = true;
@@ -378,7 +387,8 @@ function batchViewMessages(conv: ConvState): Msg[] {
378
387
  const out: Msg[] = [];
379
388
  const task = conv.batchTask;
380
389
  const opener = task?.opener_prompt ?? null;
381
- const firstUserId = conv.msgs.find((m) => m.role === "user")?.id;
390
+ // 更早的消息还没取时,手里的第一条用户消息不是开场语句。
391
+ const firstUserId = conv.older > 0 ? undefined : conv.msgs.find((m) => m.role === "user")?.id;
382
392
  for (let i = 0; i < conv.msgs.length; i++) {
383
393
  const m = conv.msgs[i];
384
394
  if (m.role === "user" && m.content.includes(CONFIRM_MARK)) {