lark-remote 0.5.19 → 0.5.20
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/CHANGELOG.md +19 -0
- package/dist/bridge/approval-actions.d.ts +1 -1
- package/dist/bridge/approval-actions.js +1 -1
- package/dist/bridge/bash-run.d.ts +71 -0
- package/dist/bridge/bash-run.js +217 -0
- package/dist/bridge/compact.d.ts +155 -0
- package/dist/bridge/compact.js +450 -0
- package/dist/bridge/final-usage.js +4 -4
- package/dist/bridge/inbound-media.js +1 -1
- package/dist/bridge/index.d.ts +97 -153
- package/dist/bridge/index.js +182 -809
- package/dist/bridge/job-watch.d.ts +68 -0
- package/dist/bridge/job-watch.js +146 -0
- package/dist/bridge/queue-manager.d.ts +3 -3
- package/dist/bridge/queue-manager.js +10 -29
- package/dist/card/approval-render.d.ts +2 -2
- package/dist/card/approval-render.js +109 -97
- package/dist/card/card-budget.js +1 -1
- package/dist/card/card-helpers.d.ts +3 -3
- package/dist/card/card-helpers.js +6 -6
- package/dist/card/final-answer-file.js +1 -1
- package/dist/card/run-renderer.d.ts +3 -3
- package/dist/card/run-renderer.js +34 -93
- package/dist/card/run-state.d.ts +1 -1
- package/dist/card/run-state.js +28 -90
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +1 -1
- package/dist/card/usage-format.d.ts +12 -0
- package/dist/card/usage-format.js +8 -3
- package/dist/cli.js +15 -3
- package/dist/clone.js +2 -2
- package/dist/config/codex-config.js +130 -106
- package/dist/config/index.d.ts +16 -2
- package/dist/config/index.js +23 -8
- package/dist/connector/index.js +6 -6
- package/dist/error-classification.js +3 -2
- package/dist/inbound/placeholder.d.ts +1 -1
- package/dist/inbound/placeholder.js +1 -1
- package/dist/index.js +203 -133
- package/dist/logger/index.js +6 -6
- package/dist/message-handlers.d.ts +0 -5
- package/dist/message-handlers.js +1 -1
- package/dist/model-catalog.d.ts +2 -2
- package/dist/model-catalog.js +3 -8
- package/dist/platform/identity.js +1 -1
- package/dist/platform/path.d.ts +1 -1
- package/dist/platform/path.js +1 -1
- package/dist/platform/sleep-blocker.js +1 -1
- package/dist/platform/terminator-win32.js +2 -1
- package/dist/router/commands/resume.js +2 -20
- package/dist/router/config/dsh.d.ts +4 -8
- package/dist/router/config/dsh.js +3 -10
- package/dist/router/config/kimi.js +1 -1
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/config-diff.js +1 -1
- package/dist/router/index.d.ts +56 -11
- package/dist/router/index.js +219 -200
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +6 -4
- package/dist/runner/codex/app-server/runner.d.ts +9 -2
- package/dist/runner/codex/app-server/runner.js +30 -25
- package/dist/runner/codex/app-server/translator.d.ts +0 -5
- package/dist/runner/codex/app-server/translator.js +4 -17
- package/dist/runner/common/acp/acp-approval.d.ts +1 -1
- package/dist/runner/common/acp/acp-approval.js +1 -1
- package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
- package/dist/runner/common/acp/base-acp-runner.js +26 -65
- package/dist/runner/common/acp/base-translator.d.ts +12 -2
- package/dist/runner/common/acp/base-translator.js +31 -9
- package/dist/runner/common/acp/protocol-types.d.ts +1 -1
- package/dist/runner/common/acp/protocol-types.js +2 -2
- package/dist/runner/common/connection-based-runner.d.ts +32 -1
- package/dist/runner/common/connection-based-runner.js +32 -2
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
- package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
- package/dist/runner/common/spawning-runner.d.ts +1 -1
- package/dist/runner/common/spawning-runner.js +1 -1
- package/dist/runner/dsh/catalog-probe.d.ts +17 -0
- package/dist/runner/dsh/catalog-probe.js +10 -0
- package/dist/runner/dsh/client.d.ts +1 -3
- package/dist/runner/dsh/client.js +2 -4
- package/dist/runner/dsh/exit-cancel.d.ts +2 -2
- package/dist/runner/dsh/exit-cancel.js +2 -2
- package/dist/runner/dsh/inflight.d.ts +1 -1
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/runner.d.ts +40 -1
- package/dist/runner/dsh/runner.js +272 -199
- package/dist/runner/dsh/translator.d.ts +1 -1
- package/dist/runner/dsh/translator.js +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -2
- package/dist/runner/kimi/acp/runner.js +1 -2
- package/dist/runner/kimi/acp/translator.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +3 -4
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
- package/dist/runner/pi/rpc/protocol-types.js +1 -1
- package/dist/runner/pi/rpc/runner.d.ts +3 -0
- package/dist/runner/pi/rpc/runner.js +27 -42
- package/dist/runner/types.d.ts +2 -2
- package/dist/runner/types.js +1 -1
- package/dist/session/claude/sessions.d.ts +45 -0
- package/dist/session/claude/sessions.js +97 -71
- package/dist/session/codex/rollout-reader.js +4 -4
- package/dist/session/common/throw-session-list-error.d.ts +10 -0
- package/dist/session/common/throw-session-list-error.js +16 -0
- package/dist/session/dsh/sessions.js +11 -5
- package/dist/session/kimi/sessions.d.ts +40 -1
- package/dist/session/kimi/sessions.js +244 -192
- package/dist/session/opencode/sessions.d.ts +153 -1
- package/dist/session/opencode/sessions.js +354 -321
- package/dist/session/pi/sessions.js +4 -5
- package/dist/session/session-store.d.ts +1 -1
- package/dist/session/session-store.js +1 -1
- package/dist/update/version-check.js +2 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.js +1 -1
- package/package.json +1 -1
|
@@ -36,7 +36,7 @@ const SESSION_PANEL_TITLE_MAX = 42;
|
|
|
36
36
|
export function sessionEventPanel(ev, index, totalEvents, tailExpandedCount = 2, agentKind = 'claude') {
|
|
37
37
|
// reader 可以给事件一个"标题即摘要"的名字(工具调用:`🔧 bash — npm test`);
|
|
38
38
|
// 缺省用类型标签。标题连同时间戳一起收进一行显示宽度——手机上折叠面板只有
|
|
39
|
-
//
|
|
39
|
+
// 一行可用,长 URL 把标题撑成两行会断在 URL 中间。
|
|
40
40
|
const label = ev.title ?? eventLabel(ev, agentKind);
|
|
41
41
|
const ts = formatMonthDayClock(ev.timestamp);
|
|
42
42
|
const suffix = ts ? ` (${ts})` : '';
|
|
@@ -103,7 +103,7 @@ export function parseJumpOffset(inputValue, pageSize) {
|
|
|
103
103
|
* Build the CardKit 2.0 pagination block shared by /ls, /ws, /resume, /active,
|
|
104
104
|
* /order.
|
|
105
105
|
*
|
|
106
|
-
*
|
|
106
|
+
* 第一性原理(窄屏):分页栏要同时承载「页码信息」和「翻页
|
|
107
107
|
* 控件」两类需求。旧布局把两者塞进同一行 `column_set`(文案 weighted 4 : 输入
|
|
108
108
|
* weighted 2),手机窄屏下 auto 按钮先占走固有宽度,剩余宽度按 4:2 切分后文案
|
|
109
109
|
* 列只有百来像素、输入框只有几十像素——文案折行、输入框窄到没法点。
|
|
@@ -253,8 +253,8 @@ export function searchBar(opts) {
|
|
|
253
253
|
*
|
|
254
254
|
* 旧口径是 `events.slice(-max)`:按**原始事件条数**截尾。工具往返(bash 调用 →
|
|
255
255
|
* job 登记 → 结果)一段就能把窗口占满,于是重返会话的用户真正需要的两条信息
|
|
256
|
-
*
|
|
257
|
-
*
|
|
256
|
+
* ——最后一句我说了什么、最后一句它答了什么——被挤出窗口:自动恢复卡 5 个
|
|
257
|
+
* 面板全是 bash 调用,一条用户消息、一条 assistant 正文都没有。
|
|
258
258
|
*
|
|
259
259
|
* 契约:先取最新 `max` 条,再把最后一条 `user` 与最后一条 `assistant`(正文)
|
|
260
260
|
* 不在窗口内时补进来——补位时淘汰最早的**非锚点**事件。输出保持时间顺序,
|
|
@@ -313,7 +313,7 @@ export function buildSessionHistoryCard(state, opts) {
|
|
|
313
313
|
// (DSH 的 projections.title / claude 的 ai-title),后者是最近一条用户输入。
|
|
314
314
|
// claude 的 displayTitle 本身就取 aiTitle,两者相等 → 保持旧的「AI 标题」
|
|
315
315
|
// 单段文案;DSH 两者都有(标题 + 末轮 prompt)→ 各占一段,别把用户那句话
|
|
316
|
-
// 挂在「AI
|
|
316
|
+
// 挂在「AI 标题」下面。
|
|
317
317
|
if (displayTitle) {
|
|
318
318
|
if (aiTitle && aiTitle !== displayTitle) {
|
|
319
319
|
sections.push(`🏷️ **标题**\n${preview(aiTitle)}`);
|
|
@@ -357,7 +357,7 @@ export function buildSessionHistoryCard(state, opts) {
|
|
|
357
357
|
elements.push(markdownDiv(usageStr));
|
|
358
358
|
}
|
|
359
359
|
// Remove trailing hr
|
|
360
|
-
if (elements
|
|
360
|
+
if (elements[elements.length - 1].tag === 'hr') {
|
|
361
361
|
elements.pop();
|
|
362
362
|
}
|
|
363
363
|
if (opts.actions && opts.actions.length > 0) {
|
|
@@ -55,7 +55,7 @@ type GroupContentPrepared = Map<BlockGroup, string>;
|
|
|
55
55
|
/**
|
|
56
56
|
* 状态行内容:**一行、一个 div、窄屏不换行**。
|
|
57
57
|
*
|
|
58
|
-
*
|
|
58
|
+
* 设计约束(手机端):旧版把「状态标签」和「耗时/指标」放进
|
|
59
59
|
* `column_set` 的 auto + grow 两列,窄屏上 auto 列被挤到只剩两个字宽,
|
|
60
60
|
* "运行中" 被拆成 "运行 / 中"。列式布局的可用宽度取决于对端渲染,服务端无法
|
|
61
61
|
* 保证;所以这里改成单 div,段间用 " · " 分隔——换行只会发生在分隔符处,
|
|
@@ -64,8 +64,8 @@ type GroupContentPrepared = Map<BlockGroup, string>;
|
|
|
64
64
|
* 状态标签(运行中/已完成…)不再重复:header 已经写了(`🔧 dsh · 调用工具`
|
|
65
65
|
* / `✅ dsh · 已完成`),终态 summary 还有一次。
|
|
66
66
|
*
|
|
67
|
-
* 终态也保留状态行:耗时定格,DSH
|
|
68
|
-
*
|
|
67
|
+
* 终态也保留状态行:耗时定格,DSH 的步数/上下文投影展示最后一次快照。
|
|
68
|
+
* summary 的最终 usage 与状态行并存。
|
|
69
69
|
*
|
|
70
70
|
* 导出供窄屏守卫测试断言分段宽度(与 `estimateCardBytes` 同一惯例)。
|
|
71
71
|
*/
|
|
@@ -8,7 +8,7 @@ import { countCardElements, MAX_CARD_ELEMENTS } from './card-budget.js';
|
|
|
8
8
|
import { displayWidth, truncateToDisplayWidth } from '../common/text-width.js';
|
|
9
9
|
import { isContentFilterFailure } from '../common/turn-failure.js';
|
|
10
10
|
import { formatClock, formatTimestamp } from './time.js';
|
|
11
|
-
import { formatUsageStats } from './usage-format.js';
|
|
11
|
+
import { formatTokenK, formatUsageStats } from './usage-format.js';
|
|
12
12
|
import { renderApprovalArea, renderApprovalAreaCompact } from './approval-render.js';
|
|
13
13
|
const REASONING_BYTES = 4_500;
|
|
14
14
|
const TEXT_BYTES = 10_000;
|
|
@@ -38,7 +38,7 @@ const EMPTY_MD_DIV_BYTES = measureJson(markdownDiv('', 'notation'));
|
|
|
38
38
|
* 能力门控(compactSupported !== false)与执行侧 `'runCompact' in runner`
|
|
39
39
|
* 鸭子探测对齐:claude 走 stream-json,不发射 turn_started,operationKind
|
|
40
40
|
* 恒 undefined——若以 operationKind==='turn' 作门控,claude 终态卡永远拿
|
|
41
|
-
*
|
|
41
|
+
* 不到按钮。compaction 卡的「防递归」仍由 operationKind
|
|
42
42
|
* 保证,两者是不同质的判断。
|
|
43
43
|
*/
|
|
44
44
|
function shouldShowCompactButton(state, options) {
|
|
@@ -121,37 +121,21 @@ function buildGoalSection(state) {
|
|
|
121
121
|
* This unifies timestamp position across all block types (thinking/plan/file_change/tool/text).
|
|
122
122
|
*
|
|
123
123
|
* Panel title: `💬 **输出** (ts)` when timestamp present, `💬 **输出**` otherwise.
|
|
124
|
-
*
|
|
124
|
+
* The panel is always expanded — streaming and finalized states render identically.
|
|
125
125
|
*
|
|
126
126
|
* @param content - The text content to render
|
|
127
127
|
* @param timestamp - Optional timestamp for the block
|
|
128
|
-
* @param finalized - Whether the run is in a terminal state
|
|
129
128
|
* @returns elements
|
|
130
129
|
*/
|
|
131
|
-
function renderTextBlock(content, timestamp
|
|
130
|
+
function renderTextBlock(content, timestamp) {
|
|
132
131
|
if (!content.trim()) {
|
|
133
132
|
return [];
|
|
134
133
|
}
|
|
135
134
|
const ts = formatTimestamp(timestamp);
|
|
136
|
-
//
|
|
135
|
+
// Render in collapsible_panel with expanded=true.
|
|
137
136
|
// NOTE: collapsible_panel does NOT shield markdown tables from Feishu's 11310 table count
|
|
138
137
|
// limit — tables inside lark_md text are still counted regardless of container.
|
|
139
138
|
// We must explicitly truncate excess tables via truncateMarkdownTables before rendering.
|
|
140
|
-
if (finalized) {
|
|
141
|
-
const title = '💬 **输出**';
|
|
142
|
-
const header = ts ? `${title} (${ts})` : title;
|
|
143
|
-
const safeContent = truncateMarkdownTables(content);
|
|
144
|
-
return [
|
|
145
|
-
collapsibleMarkdownPanel({
|
|
146
|
-
title: header,
|
|
147
|
-
expanded: true, // Always expanded in finalized state for full visibility
|
|
148
|
-
border: 'grey',
|
|
149
|
-
content: safeContent,
|
|
150
|
-
textSize: 'notation',
|
|
151
|
-
}),
|
|
152
|
-
];
|
|
153
|
-
}
|
|
154
|
-
// Running/finalizing: panel provides visual grouping with timestamp in header
|
|
155
139
|
const title = '💬 **输出**';
|
|
156
140
|
const header = ts ? `${title} (${ts})` : title;
|
|
157
141
|
const safeContent = truncateMarkdownTables(content);
|
|
@@ -302,7 +286,7 @@ function groupBlocks(blocks) {
|
|
|
302
286
|
*
|
|
303
287
|
* 早先试过"一行 + 服务端「详情」按钮":折叠不省字节所以正文不入 payload,展开
|
|
304
288
|
* 只能回服务端重出卡。代价是手机上要多点一次、按钮还占掉标题宽度(长 URL 被挤
|
|
305
|
-
*
|
|
289
|
+
* 成两行)。现在改成折叠面板 + **按工具数量缩放的正文截断**:
|
|
306
290
|
* 正文始终随卡下发(面板折叠时不显示),点标题即展开,无往返、无按钮。
|
|
307
291
|
*
|
|
308
292
|
* 展开态:运行中/失败的默认展开(用户在等结果、错误要立刻可见),其余折叠。
|
|
@@ -493,8 +477,6 @@ function assembleRunCard(state, options, elements) {
|
|
|
493
477
|
function insertAfterStatusRow(elements, extra) {
|
|
494
478
|
if (extra.length === 0)
|
|
495
479
|
return elements;
|
|
496
|
-
if (elements.length === 0)
|
|
497
|
-
return extra;
|
|
498
480
|
return [elements[0], ...extra, ...elements.slice(1)];
|
|
499
481
|
}
|
|
500
482
|
/**
|
|
@@ -573,16 +555,13 @@ function buildFallbackElements(state, options, tier) {
|
|
|
573
555
|
else if (group.kind === 'text') {
|
|
574
556
|
const content = truncateUtf8(group.content, tier.textBytes, true, '…(已截断)\n');
|
|
575
557
|
const ts = formatTimestamp(group.timestamp);
|
|
576
|
-
elements.push(...renderTextBlock(content, ts
|
|
558
|
+
elements.push(...renderTextBlock(content, ts));
|
|
577
559
|
}
|
|
578
560
|
else if (group.kind === 'tool') {
|
|
579
561
|
// Show tool individually (each tool is independent now)
|
|
580
562
|
elements.push(renderTool(group.tool, outputMax));
|
|
581
563
|
}
|
|
582
564
|
}
|
|
583
|
-
if (elements.length === 0 && tier === EXTREME_TIER) {
|
|
584
|
-
elements.push(markdownDiv('_暂无输出_'));
|
|
585
|
-
}
|
|
586
565
|
elements.push(...buildSummaryContent(state, { includeNotices: false }));
|
|
587
566
|
elements.push(...actionRow(state, options));
|
|
588
567
|
elements.push(...approvalArea(state));
|
|
@@ -606,7 +585,7 @@ function buildExtremeFallbackElements(state, options) {
|
|
|
606
585
|
/**
|
|
607
586
|
* 状态行内容:**一行、一个 div、窄屏不换行**。
|
|
608
587
|
*
|
|
609
|
-
*
|
|
588
|
+
* 设计约束(手机端):旧版把「状态标签」和「耗时/指标」放进
|
|
610
589
|
* `column_set` 的 auto + grow 两列,窄屏上 auto 列被挤到只剩两个字宽,
|
|
611
590
|
* "运行中" 被拆成 "运行 / 中"。列式布局的可用宽度取决于对端渲染,服务端无法
|
|
612
591
|
* 保证;所以这里改成单 div,段间用 " · " 分隔——换行只会发生在分隔符处,
|
|
@@ -615,8 +594,8 @@ function buildExtremeFallbackElements(state, options) {
|
|
|
615
594
|
* 状态标签(运行中/已完成…)不再重复:header 已经写了(`🔧 dsh · 调用工具`
|
|
616
595
|
* / `✅ dsh · 已完成`),终态 summary 还有一次。
|
|
617
596
|
*
|
|
618
|
-
* 终态也保留状态行:耗时定格,DSH
|
|
619
|
-
*
|
|
597
|
+
* 终态也保留状态行:耗时定格,DSH 的步数/上下文投影展示最后一次快照。
|
|
598
|
+
* summary 的最终 usage 与状态行并存。
|
|
620
599
|
*
|
|
621
600
|
* 导出供窄屏守卫测试断言分段宽度(与 `estimateCardBytes` 同一惯例)。
|
|
622
601
|
*/
|
|
@@ -629,7 +608,7 @@ export function statusLine(state) {
|
|
|
629
608
|
const elapsed = elapsedLabel(state);
|
|
630
609
|
if (elapsed)
|
|
631
610
|
parts.push(`⏱ ${elapsed}`);
|
|
632
|
-
//
|
|
611
|
+
// 运行期投影在终态也保留:DSH 卡片完成时,耗时/步数/
|
|
633
612
|
// 上下文百分比是这一跑留下的最后快照,撤掉后用户只能从 summary 的累计口径
|
|
634
613
|
// 重新推算。summary 仍展示最终 usage,两者口径不同、并存不冲突。
|
|
635
614
|
const live = state.liveStatus;
|
|
@@ -644,12 +623,12 @@ export function statusLine(state) {
|
|
|
644
623
|
parts.push(`📊 ~${pct}%`);
|
|
645
624
|
}
|
|
646
625
|
else if (live.contextUsed !== undefined) {
|
|
647
|
-
parts.push(`📊 ${
|
|
626
|
+
parts.push(`📊 ${formatTokenK(live.contextUsed)}`);
|
|
648
627
|
}
|
|
649
628
|
}
|
|
650
629
|
if (parts.length === 0) {
|
|
651
630
|
// 没有任何可用指标时退回状态词(骨架卡/测试构造的状态没有时间戳)。
|
|
652
|
-
return
|
|
631
|
+
return terminalToLabel(state.terminal);
|
|
653
632
|
}
|
|
654
633
|
return parts.join(' · ');
|
|
655
634
|
}
|
|
@@ -672,15 +651,6 @@ function elapsedLabel(state) {
|
|
|
672
651
|
return `${hours}h${String(minutes % 60).padStart(2, '0')}m`;
|
|
673
652
|
return `${Math.floor(hours / 24)}d${String(hours % 24).padStart(2, '0')}h`;
|
|
674
653
|
}
|
|
675
|
-
/** token 数量的紧凑写法:`950` / `12K` / `1.0M`。 */
|
|
676
|
-
function formatTokens(tokens) {
|
|
677
|
-
if (tokens < 1000)
|
|
678
|
-
return String(tokens);
|
|
679
|
-
// 千位边界取 M 档:999_500 起四舍五入会得到 "1000K",直接按 M 档展示。
|
|
680
|
-
if (tokens < 999_500)
|
|
681
|
-
return `${Math.round(tokens / 1000)}K`;
|
|
682
|
-
return `${(tokens / 1_000_000).toFixed(1)}M`;
|
|
683
|
-
}
|
|
684
654
|
/**
|
|
685
655
|
* 状态行元素(full/degraded/extreme/skeleton 共用)。
|
|
686
656
|
*
|
|
@@ -955,7 +925,7 @@ export const FINAL_ANSWER_OVERFLOW_MARKER = '_最终回答较长,完整内容
|
|
|
955
925
|
* 「卡片装不下正文」与「表格数超上限」是两件事,只有前者才走补发通道:
|
|
956
926
|
* 飞书单卡最多 5 张 markdown 表(11310),多出来的最旧表格会被删掉并在原位
|
|
957
927
|
* 留 `_💡 前 N 个表格已省略_`——正文仍在卡片里,再补发一遍就是把用户已经看到
|
|
958
|
-
*
|
|
928
|
+
* 的整篇回答重复。
|
|
959
929
|
*/
|
|
960
930
|
function buildFinalAnswerPriorityCard(state, options) {
|
|
961
931
|
const finalAnswer = state.finalAnswer;
|
|
@@ -963,12 +933,12 @@ function buildFinalAnswerPriorityCard(state, options) {
|
|
|
963
933
|
const prepared = prepareGroupContent(groups);
|
|
964
934
|
const safeAnswer = truncateMarkdownTables(finalAnswer.content);
|
|
965
935
|
const ts = formatTimestamp(finalAnswer.timestamp);
|
|
966
|
-
const answerElements = renderTextBlock(safeAnswer, ts
|
|
936
|
+
const answerElements = renderTextBlock(safeAnswer, ts);
|
|
967
937
|
const fixedStart = [statusRow(state), ...omittedBlocksHint(state)];
|
|
968
938
|
const summary = buildSummaryContent(state, { includeNotices: false });
|
|
969
939
|
const controls = [...actionRow(state, options), ...approvalArea(state)];
|
|
970
940
|
const buildWithProgress = (start, includeSummary) => {
|
|
971
|
-
const renderedProgress =
|
|
941
|
+
const renderedProgress = renderContentGroups(state, prepared, groups.slice(start));
|
|
972
942
|
const progress = start < groups.length
|
|
973
943
|
? [markdownDiv(`_💡 已省略 ${start} 个早期步骤_`), ...renderedProgress]
|
|
974
944
|
: renderedProgress;
|
|
@@ -1009,8 +979,17 @@ function buildFinalAnswerPriorityCard(state, options) {
|
|
|
1009
979
|
finalAnswerText: finalAnswer.content,
|
|
1010
980
|
};
|
|
1011
981
|
}
|
|
1012
|
-
/**
|
|
1013
|
-
|
|
982
|
+
/**
|
|
983
|
+
* 正常路径内容循环,时间线卡(buildChronologicalContent)与答案优先卡的进度
|
|
984
|
+
* 后缀(buildFinalAnswerPriorityCard)共用:notices 作为普通消息按到达时间
|
|
985
|
+
* 插入内容流(有内容时不再沉到 summary),tool/text/panel 组逐个渲染。
|
|
986
|
+
*
|
|
987
|
+
* prepared 的键是组对象引用:传入的组数组必须保持元素引用(slice 可以,重建
|
|
988
|
+
* 数组会让 prepared.get 永远 miss,退化为二次截断)。面板组描述经
|
|
989
|
+
* describePanelGroup 与估算共享同一份模板。
|
|
990
|
+
* 「已省略 N 个早期步骤」提示与空态兜底 `_暂无输出_` 由调用方各自负责。
|
|
991
|
+
*/
|
|
992
|
+
function renderContentGroups(state, prepared, visible) {
|
|
1014
993
|
const elements = [];
|
|
1015
994
|
const outputMax = toolOutputBudget(state);
|
|
1016
995
|
const contentItems = mergeNoticesIntoContent(visible, state.notices);
|
|
@@ -1027,7 +1006,7 @@ function buildAnswerProgressContent(state, prepared, visible) {
|
|
|
1027
1006
|
if (group.kind === 'text') {
|
|
1028
1007
|
const content = prepared.get(group) ?? '';
|
|
1029
1008
|
const ts = formatTimestamp(group.timestamp);
|
|
1030
|
-
elements.push(...renderTextBlock(content, ts
|
|
1009
|
+
elements.push(...renderTextBlock(content, ts));
|
|
1031
1010
|
continue;
|
|
1032
1011
|
}
|
|
1033
1012
|
const spec = describePanelGroup(group, prepared);
|
|
@@ -1058,46 +1037,12 @@ function withinRunCardBudget(card) {
|
|
|
1058
1037
|
}
|
|
1059
1038
|
/** Build content in chronological order using groupBlocks to interleave thinking/text/tools. */
|
|
1060
1039
|
function buildChronologicalContent(state, prepared, groups) {
|
|
1061
|
-
const elements = [];
|
|
1062
|
-
// finalized = 非 running(含 finalizing:主结果已出,thinking 折叠)
|
|
1063
|
-
const finalized = state.terminal !== 'running';
|
|
1064
1040
|
// 节点预算内从最新往回选择可见组:超限时只省略最旧的几步,不整卡降级。
|
|
1065
1041
|
const { visible, omitted } = selectVisibleGroups(groups);
|
|
1066
|
-
const
|
|
1042
|
+
const elements = [];
|
|
1067
1043
|
if (omitted > 0)
|
|
1068
1044
|
elements.push(markdownDiv(`_💡 已省略 ${omitted} 个早期步骤_`));
|
|
1069
|
-
|
|
1070
|
-
// 引用,重建数组会让 prepared.get 永远 miss,退化为二次截断)。
|
|
1071
|
-
// 面板组描述经 describePanelGroup 与估算共享同一份模板。
|
|
1072
|
-
// notices 作为普通消息按到达时间插入内容流(有内容时不再沉到 summary)。
|
|
1073
|
-
const contentItems = mergeNoticesIntoContent(visible, state.notices);
|
|
1074
|
-
for (const item of contentItems) {
|
|
1075
|
-
if (item.kind === 'notice') {
|
|
1076
|
-
elements.push(renderNoticeRow(item.notice));
|
|
1077
|
-
continue;
|
|
1078
|
-
}
|
|
1079
|
-
const group = item;
|
|
1080
|
-
if (group.kind === 'tool') {
|
|
1081
|
-
elements.push(renderTool(group.tool, outputMax));
|
|
1082
|
-
continue;
|
|
1083
|
-
}
|
|
1084
|
-
if (group.kind === 'text') {
|
|
1085
|
-
const content = prepared.get(group) ?? '';
|
|
1086
|
-
const ts = formatTimestamp(group.timestamp);
|
|
1087
|
-
elements.push(...renderTextBlock(content, ts, finalized));
|
|
1088
|
-
continue;
|
|
1089
|
-
}
|
|
1090
|
-
const spec = describePanelGroup(group, prepared);
|
|
1091
|
-
if (!spec)
|
|
1092
|
-
continue;
|
|
1093
|
-
elements.push(collapsibleMarkdownPanel({
|
|
1094
|
-
title: spec.title,
|
|
1095
|
-
expanded: spec.expanded,
|
|
1096
|
-
border: spec.border,
|
|
1097
|
-
content: spec.content,
|
|
1098
|
-
textSize: 'notation',
|
|
1099
|
-
}));
|
|
1100
|
-
}
|
|
1045
|
+
elements.push(...renderContentGroups(state, prepared, visible));
|
|
1101
1046
|
if (elements.length === 0) {
|
|
1102
1047
|
elements.push(markdownDiv('_暂无输出_'));
|
|
1103
1048
|
}
|
|
@@ -1154,8 +1099,8 @@ function buildSummaryContent(state, options = {}) {
|
|
|
1154
1099
|
const result = state.resultSubtype ?? 'success';
|
|
1155
1100
|
const hasContent = state.blocks.length > 0 || !!state.finalAnswer?.content.trim();
|
|
1156
1101
|
// 压缩(operationKind='compaction')不会返回 agent 正文——引擎只压缩上下文
|
|
1157
|
-
// 窗口,空内容属正常,不能沿用普通 run
|
|
1158
|
-
//
|
|
1102
|
+
// 窗口,空内容属正常,不能沿用普通 run 的「(未返回内容)」异常信号。
|
|
1103
|
+
// 所有会压缩的 agent(codex/claude/kimi/opencode/pi)
|
|
1159
1104
|
// 都经 streamCompact 走这条共享渲染路径,一处覆盖全部。
|
|
1160
1105
|
const empty = hasContent
|
|
1161
1106
|
? ''
|
|
@@ -1243,7 +1188,7 @@ function codeFenceFor(content) {
|
|
|
1243
1188
|
/**
|
|
1244
1189
|
* 后台任务小节:命令独占一行,停止按钮单独一行。
|
|
1245
1190
|
*
|
|
1246
|
-
*
|
|
1191
|
+
* 布局约束(手机端):
|
|
1247
1192
|
* - 命令 + 按钮不再并排(grow + auto):窄屏下 auto 列会被挤成「🟥…」,
|
|
1248
1193
|
* 命令也被截断。按钮现在独占一个单列 column_set,宽度由按钮自身决定。
|
|
1249
1194
|
* - 命令不 truncate:短命令/单行直接内联;中等长度的多行命令用代码块
|
|
@@ -1326,10 +1271,6 @@ function buildBackgroundJobsSection(state) {
|
|
|
1326
1271
|
}
|
|
1327
1272
|
return elements;
|
|
1328
1273
|
}
|
|
1329
|
-
/** Status tag label */
|
|
1330
|
-
function statusTagLabel(terminal) {
|
|
1331
|
-
return terminalToLabel(terminal);
|
|
1332
|
-
}
|
|
1333
1274
|
/** CardKit 2.0 header title — agent-aware via options.agentKind. */
|
|
1334
1275
|
function headerTitle(state, options = {}) {
|
|
1335
1276
|
const agent = agentDisplayName(options.agentKind ?? 'claude');
|
|
@@ -1359,7 +1300,7 @@ function headerTitle(state, options = {}) {
|
|
|
1359
1300
|
if (state.terminal === 'finalizing')
|
|
1360
1301
|
return `⏳ ${agent} · 完成中`;
|
|
1361
1302
|
// 审批等待期间 server 暂停 turn,命令工具停在 tool_running——标题必须提示
|
|
1362
|
-
//
|
|
1303
|
+
// 正在等人工决策,而不是「调用工具」。
|
|
1363
1304
|
if (hasPendingApproval(state))
|
|
1364
1305
|
return `✋ ${agent} · 等待审批`;
|
|
1365
1306
|
if (state.footer === 'thinking')
|
package/dist/card/run-state.d.ts
CHANGED
|
@@ -154,7 +154,7 @@ export interface RunState extends UsageSnapshot {
|
|
|
154
154
|
* 审批是否曾过期(桥侧 timer 触发,approval_expired 事件置位)。
|
|
155
155
|
* 独立于 approvals 数组持久保存:cancel 送达后 server 会回
|
|
156
156
|
* approval_resolved,把对应审批条目从数组移除,但过期原因必须活到
|
|
157
|
-
*
|
|
157
|
+
* 终态渲染(否则标记被消费后卡片误报「已被用户终止」)。
|
|
158
158
|
*/
|
|
159
159
|
approvalExpired?: boolean;
|
|
160
160
|
/**
|