lark-remote 0.5.7 → 0.5.9
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 +35 -0
- package/dist/bridge/index.d.ts +47 -7
- package/dist/bridge/index.js +300 -129
- package/dist/bridge/queue-manager.d.ts +6 -0
- package/dist/bridge/queue-manager.js +61 -63
- package/dist/card/approval-render.js +2 -1
- package/dist/card/bash-card-session.d.ts +0 -1
- package/dist/card/bash-card-session.js +0 -8
- package/dist/card/bash-renderer.js +2 -1
- package/dist/card/card-budget.js +15 -19
- package/dist/card/card-session.d.ts +3 -13
- package/dist/card/card-session.js +4 -18
- package/dist/card/card-shared.d.ts +11 -0
- package/dist/card/card-shared.js +23 -13
- package/dist/card/run-card-session.d.ts +0 -1
- package/dist/card/run-card-session.js +0 -6
- package/dist/card/run-renderer.d.ts +11 -10
- package/dist/card/run-renderer.js +198 -35
- package/dist/card/run-state.d.ts +29 -2
- package/dist/card/run-state.js +23 -4
- package/dist/card/text-truncate.d.ts +3 -5
- package/dist/card/text-truncate.js +3 -5
- package/dist/card/tool-render.js +7 -21
- package/dist/common/tool-summary.d.ts +8 -0
- package/dist/common/tool-summary.js +38 -20
- package/dist/common/turn-failure.d.ts +13 -0
- package/dist/common/turn-failure.js +18 -0
- package/dist/index.js +13 -14
- package/dist/order/index.d.ts +2 -0
- package/dist/order/index.js +2 -0
- package/dist/router/card-helpers.js +23 -42
- package/dist/router/config/codex.js +2 -3
- package/dist/router/config/common/model-patch.d.ts +8 -0
- package/dist/router/config/common/model-patch.js +13 -0
- package/dist/router/config/common/render.js +30 -77
- package/dist/router/config/dsh.js +2 -1
- package/dist/router/config/kimi.js +3 -3
- package/dist/router/index.d.ts +0 -11
- package/dist/router/index.js +119 -360
- package/dist/router/order-exec-dispatch.js +2 -1
- package/dist/router/usage-format.d.ts +5 -0
- package/dist/router/usage-format.js +1 -1
- package/dist/runner/common/defaults.d.ts +2 -0
- package/dist/runner/common/defaults.js +3 -0
- package/dist/runner/common/jsonrpc/connection-manager.js +1 -1
- package/dist/runner/dsh/client.d.ts +15 -0
- package/dist/runner/dsh/client.js +28 -2
- package/dist/runner/dsh/goal-view.d.ts +36 -0
- package/dist/runner/dsh/goal-view.js +106 -0
- package/dist/runner/dsh/runner.js +51 -2
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/types.d.ts +59 -1
- package/dist/runner/types.js +9 -0
- package/dist/session/claude/session-index.d.ts +0 -4
- package/dist/session/claude/session-index.js +0 -8
- package/dist/session/dsh/sessions.js +58 -2
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getLogger } from '../logger/index.js';
|
|
2
|
+
import { cardWithHeader } from '../card/card-shared.js';
|
|
2
3
|
import { displayName } from '../platform/path.js';
|
|
3
4
|
/**
|
|
4
5
|
* Per-workspace cap on the number of tasks WAITING to execute.
|
|
@@ -171,25 +172,19 @@ export class QueueManager {
|
|
|
171
172
|
// a rejected task never executes, so it must not occupy a slot.
|
|
172
173
|
if (currentQueueLength >= MAX_WAITING_QUEUE) {
|
|
173
174
|
getLogger().warn(`[queue-manager] queue full cwd=${cwd} depth=${currentQueueLength} rejecting task messageId=${taskMeta.messageId}`);
|
|
174
|
-
void this.sendCard(taskMeta.chatId, {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
tag: 'div',
|
|
185
|
-
text: {
|
|
186
|
-
tag: 'lark_md',
|
|
187
|
-
content: `当前工作目录已有 ${MAX_WAITING_QUEUE} 条消息排队等待,为防止积压已拒收本条消息。请等待队列消化后重发,或用 \`/stop\` 清空当前任务。`,
|
|
188
|
-
},
|
|
175
|
+
void this.sendCard(taskMeta.chatId, cardWithHeader({
|
|
176
|
+
template: 'red',
|
|
177
|
+
title: '🚫 队列已满',
|
|
178
|
+
elements: [
|
|
179
|
+
{
|
|
180
|
+
tag: 'div',
|
|
181
|
+
text: {
|
|
182
|
+
tag: 'lark_md',
|
|
183
|
+
content: `当前工作目录已有 ${MAX_WAITING_QUEUE} 条消息排队等待,为防止积压已拒收本条消息。请等待队列消化后重发,或用 \`/stop\` 清空当前任务。`,
|
|
189
184
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}, { replyTo: taskMeta.feishuReplyTo ?? taskMeta.messageId }).catch((err) => {
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
}), { replyTo: taskMeta.feishuReplyTo ?? taskMeta.messageId }).catch((err) => {
|
|
193
188
|
getLogger().error('[queue-manager] failed to send queue-full rejection card:', err);
|
|
194
189
|
});
|
|
195
190
|
return;
|
|
@@ -559,27 +554,21 @@ export class QueueManager {
|
|
|
559
554
|
return;
|
|
560
555
|
}
|
|
561
556
|
const previewForCard = liveTask?.messagePreview ?? messagePreview;
|
|
562
|
-
const card = {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
{ tag: 'hr' },
|
|
578
|
-
...this.buildQueueActionButtons(cwd, messageId, true),
|
|
579
|
-
],
|
|
580
|
-
},
|
|
581
|
-
};
|
|
582
|
-
await this.updateCard(cardMessageId, card);
|
|
557
|
+
const card = cardWithHeader({
|
|
558
|
+
template: 'green',
|
|
559
|
+
title: '▶️ 已开始执行',
|
|
560
|
+
elements: [
|
|
561
|
+
{
|
|
562
|
+
tag: 'div',
|
|
563
|
+
text: { tag: 'lark_md', content: `**当前 Workspace:** \`${workspaceName}\`` },
|
|
564
|
+
},
|
|
565
|
+
{ tag: 'hr' },
|
|
566
|
+
{ tag: 'div', text: { tag: 'lark_md', content: `📝 \`${previewForCard}\`` } },
|
|
567
|
+
{ tag: 'hr' },
|
|
568
|
+
...this.buildQueueActionButtons(cwd, messageId, true),
|
|
569
|
+
],
|
|
570
|
+
});
|
|
571
|
+
await this.updateCardWithRetry(cardMessageId, card);
|
|
583
572
|
getLogger().debug(`[queue-manager] queue card updated to executing messageId=${messageId}`);
|
|
584
573
|
}
|
|
585
574
|
catch (err) {
|
|
@@ -608,9 +597,9 @@ export class QueueManager {
|
|
|
608
597
|
taskList.splice(index, 1);
|
|
609
598
|
}
|
|
610
599
|
this.indexRemove(cwd, messageId);
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
//
|
|
600
|
+
// queueCardMessages mapping 仍不在这里删:卡片更新由 Bridge.removeFromQueue
|
|
601
|
+
// 统一触发(单一收口),updateQueueCardToCancelled 成功/失败后都会清掉映射。
|
|
602
|
+
// 直接调 QueueManager.removeFromQueue 的测试/内部用途不会自动更新卡片。
|
|
614
603
|
getLogger().info(`[queue-manager] removed from queue cwd=${cwd} messageId=${messageId}`);
|
|
615
604
|
return true;
|
|
616
605
|
}
|
|
@@ -622,28 +611,22 @@ export class QueueManager {
|
|
|
622
611
|
return;
|
|
623
612
|
}
|
|
624
613
|
const workspaceName = displayName(cwd);
|
|
625
|
-
const card = {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
{ tag: 'div', text: { tag: 'lark_md', content: `📝 该消息已从队列中撤销` } },
|
|
640
|
-
{ tag: 'hr' },
|
|
641
|
-
...this.buildQueueActionButtons(cwd, messageId, true),
|
|
642
|
-
],
|
|
643
|
-
},
|
|
644
|
-
};
|
|
614
|
+
const card = cardWithHeader({
|
|
615
|
+
template: 'gray',
|
|
616
|
+
title: '❌ 已撤销',
|
|
617
|
+
elements: [
|
|
618
|
+
{
|
|
619
|
+
tag: 'div',
|
|
620
|
+
text: { tag: 'lark_md', content: `**当前 Workspace:** \`${workspaceName}\`` },
|
|
621
|
+
},
|
|
622
|
+
{ tag: 'hr' },
|
|
623
|
+
{ tag: 'div', text: { tag: 'lark_md', content: `📝 该消息已从队列中撤销` } },
|
|
624
|
+
{ tag: 'hr' },
|
|
625
|
+
...this.buildQueueActionButtons(cwd, messageId, true),
|
|
626
|
+
],
|
|
627
|
+
});
|
|
645
628
|
try {
|
|
646
|
-
await this.
|
|
629
|
+
await this.updateCardWithRetry(cardMessageId, card);
|
|
647
630
|
getLogger().debug(`[queue-manager] queue card updated to cancelled, messageId=${messageId}`);
|
|
648
631
|
}
|
|
649
632
|
catch (err) {
|
|
@@ -653,6 +636,21 @@ export class QueueManager {
|
|
|
653
636
|
this.queueCardMessages.delete(messageId);
|
|
654
637
|
}
|
|
655
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* 卡片 PATCH 带一次重试:一次网络抖动不该让排队卡永久停在旧状态——映射
|
|
641
|
+
* 会在本次调用结束时被清理,之后没有任何自动修正机会。
|
|
642
|
+
* 第二次仍失败则向上抛,由调用方 catch 记日志(行为与改前一致)。
|
|
643
|
+
*/
|
|
644
|
+
async updateCardWithRetry(messageId, card) {
|
|
645
|
+
try {
|
|
646
|
+
await this.updateCard(messageId, card);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
catch (err) {
|
|
650
|
+
getLogger().warn(`[queue-manager] queue card update failed, retrying once messageId=${messageId}: ${err.message}`);
|
|
651
|
+
}
|
|
652
|
+
await this.updateCard(messageId, card);
|
|
653
|
+
}
|
|
656
654
|
/** Get task metadata from queue. */
|
|
657
655
|
getQueuedTask(cwd, messageId) {
|
|
658
656
|
// O(1) index lookup instead of array `find`.
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Uses CardKit 2.0 (no tag:"action" container — 200861 rule).
|
|
6
6
|
*/
|
|
7
7
|
import { collapsibleMarkdownPanel } from './collapsible.js';
|
|
8
|
-
import {
|
|
8
|
+
import { truncateMarkdownTables } from './text-truncate.js';
|
|
9
|
+
import { truncateUtf8 } from '../common/truncate.js';
|
|
9
10
|
import { cardButton } from './card-shared.js';
|
|
10
11
|
/** Unique nonce for card button callbacks (SDK dedup + router validation). */
|
|
11
12
|
function mkNonce() {
|
|
@@ -38,7 +38,6 @@ export declare class BashCardSession extends CardSession<BashState, BashRenderOp
|
|
|
38
38
|
protected get logPrefix(): string;
|
|
39
39
|
protected get errorPrefix(): string;
|
|
40
40
|
protected renderCard(state: BashState, options: BashRenderOptions): object;
|
|
41
|
-
protected hasOwnBudgetProtection(): boolean;
|
|
42
41
|
protected isFlushableState(): boolean;
|
|
43
42
|
/** Patch the card with updated bash state (e.g. new stdout/stderr). */
|
|
44
43
|
update(patch: Partial<BashState>): Promise<void>;
|
|
@@ -53,14 +53,6 @@ export class BashCardSession extends CardSession {
|
|
|
53
53
|
renderCard(state, options) {
|
|
54
54
|
return renderBashCard(state, options);
|
|
55
55
|
}
|
|
56
|
-
hasOwnBudgetProtection() {
|
|
57
|
-
// renderBashCard 自带 stringify 级 degraded/extreme fallback 预算保护
|
|
58
|
-
// (与 renderRunCard 对称),保证返回卡 ≤28KB 且保留 command/exitCode。
|
|
59
|
-
// enforceCardBudget 是会话事件面板专用的静态裁剪层,对 bash 卡的普通
|
|
60
|
-
// markdownDiv output 是 misfit(超限时极端降级丢 command/exitCode),bash
|
|
61
|
-
// 卡应跳过它,靠自身 renderer 保护。
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
56
|
isFlushableState() {
|
|
65
57
|
// finish() 已把 state 转终态后,in-flight/延迟 flush 不再用旧 state patch。
|
|
66
58
|
return this.state.terminal === 'running';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { terminalToColor, terminalToLabel, stopButton } from './card-shared.js';
|
|
2
2
|
import { markdownDiv } from './collapsible.js';
|
|
3
|
-
import {
|
|
3
|
+
import { CARD_BUDGET_BYTES } from './text-truncate.js';
|
|
4
|
+
import { truncateUtf8 } from '../common/truncate.js';
|
|
4
5
|
/**
|
|
5
6
|
* 飞书卡片大小限制(安全阈值,与 run-renderer 一致)。
|
|
6
7
|
* 从共享的 text-truncate.ts 导入,避免三处各自定义后数值漂移。
|
package/dist/card/card-budget.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dropOldestMarkdownTables, countMarkdownTables, FEISHU_MAX_TABLES, CARD_BUDGET_BYTES, } from './text-truncate.js';
|
|
2
|
+
import { truncateUtf8 } from '../common/truncate.js';
|
|
3
|
+
import { cardWithHeader } from './card-shared.js';
|
|
2
4
|
/**
|
|
3
5
|
* 静态卡片体积保护
|
|
4
6
|
*
|
|
@@ -257,25 +259,19 @@ function enforceByteBudget(truncated, opts = {}, bytesBefore) {
|
|
|
257
259
|
return done(true);
|
|
258
260
|
}
|
|
259
261
|
// ========== 阶段5:最终兜底(原 extreme_fallback) ==========
|
|
260
|
-
const minimalCard = {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
{
|
|
270
|
-
tag: 'div',
|
|
271
|
-
text: {
|
|
272
|
-
tag: 'lark_md',
|
|
273
|
-
content: '会话内容过大,已自动截断。\n\n请使用 `/active` 查看完整列表。',
|
|
274
|
-
},
|
|
262
|
+
const minimalCard = cardWithHeader({
|
|
263
|
+
template: 'orange',
|
|
264
|
+
title: '⚠️ 内容已截断',
|
|
265
|
+
elements: [
|
|
266
|
+
{
|
|
267
|
+
tag: 'div',
|
|
268
|
+
text: {
|
|
269
|
+
tag: 'lark_md',
|
|
270
|
+
content: '会话内容过大,已自动截断。\n\n请使用 `/active` 查看完整列表。',
|
|
275
271
|
},
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
};
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
});
|
|
279
275
|
return {
|
|
280
276
|
card: minimalCard,
|
|
281
277
|
wasTruncated: true,
|
|
@@ -107,19 +107,9 @@ export declare abstract class CardSession<S, RO = unknown> {
|
|
|
107
107
|
start(): Promise<void>;
|
|
108
108
|
settle(): Promise<StreamSettleResult>;
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* extreme fallback) should override this to return true.
|
|
114
|
-
*/
|
|
115
|
-
protected hasOwnBudgetProtection(): boolean;
|
|
116
|
-
/**
|
|
117
|
-
* Render the current card and apply stringify-level budget enforcement unless
|
|
118
|
-
* the subclass renderer has its own budget protection. Centralizes the budget
|
|
119
|
-
* decision so start()/updateCard()/settle() stay symmetric — previously only
|
|
120
|
-
* updateCard() guarded, while start() producer and settle() fallback sent bare
|
|
121
|
-
* renderCard output (risking >28KB for BashCardSession, which has no own
|
|
122
|
-
* stringify-level safety net).
|
|
110
|
+
* 渲染当前卡片。所有生产子类的 renderer 都自带 stringify 级预算保护
|
|
111
|
+
* (run/bash 的 degraded/extreme 路径);发送前 Bridge 还会再走一次
|
|
112
|
+
* enforceCardBudget,因此这里不再重复裁剪。
|
|
123
113
|
*/
|
|
124
114
|
protected safeRenderCard(): object;
|
|
125
115
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getLogger } from '../logger/index.js';
|
|
2
|
-
import { enforceCardBudget } from './card-budget.js';
|
|
3
2
|
/**
|
|
4
3
|
* Base class for single-card streaming sessions (RunCardSession, BashCardSession).
|
|
5
4
|
* Provides the shared lifecycle: start → (push/update) → finish → settle.
|
|
@@ -216,25 +215,12 @@ export class CardSession {
|
|
|
216
215
|
}
|
|
217
216
|
}
|
|
218
217
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* extreme fallback) should override this to return true.
|
|
223
|
-
*/
|
|
224
|
-
hasOwnBudgetProtection() {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Render the current card and apply stringify-level budget enforcement unless
|
|
229
|
-
* the subclass renderer has its own budget protection. Centralizes the budget
|
|
230
|
-
* decision so start()/updateCard()/settle() stay symmetric — previously only
|
|
231
|
-
* updateCard() guarded, while start() producer and settle() fallback sent bare
|
|
232
|
-
* renderCard output (risking >28KB for BashCardSession, which has no own
|
|
233
|
-
* stringify-level safety net).
|
|
218
|
+
* 渲染当前卡片。所有生产子类的 renderer 都自带 stringify 级预算保护
|
|
219
|
+
* (run/bash 的 degraded/extreme 路径);发送前 Bridge 还会再走一次
|
|
220
|
+
* enforceCardBudget,因此这里不再重复裁剪。
|
|
234
221
|
*/
|
|
235
222
|
safeRenderCard() {
|
|
236
|
-
|
|
237
|
-
return this.hasOwnBudgetProtection() ? card : enforceCardBudget(card).card;
|
|
223
|
+
return this.renderCard(this.state, this.renderOptions);
|
|
238
224
|
}
|
|
239
225
|
/**
|
|
240
226
|
* Push an update to the card. Tries controller.update first, falls back to
|
|
@@ -9,6 +9,15 @@ import { type AgentKind } from '../runner/index.js';
|
|
|
9
9
|
export declare function agentDisplayName(kind: string): string;
|
|
10
10
|
export declare function terminalToLabel(terminal: string): string;
|
|
11
11
|
export declare function terminalToColor(terminal: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* CardKit 2.0 静态卡骨架:schema/config/header + 给定 body elements。
|
|
14
|
+
* 队列状态卡、预算兜底卡等"只有 header 文案 + 少量 div"的卡共用。
|
|
15
|
+
*/
|
|
16
|
+
export declare function cardWithHeader(opts: {
|
|
17
|
+
template: string;
|
|
18
|
+
title: string;
|
|
19
|
+
elements: object[];
|
|
20
|
+
}): object;
|
|
12
21
|
/**
|
|
13
22
|
* Create a CardKit 2.0 button with a callback behavior. Shared constructor
|
|
14
23
|
* for every callback button in the card module (stop/new-session/compact/
|
|
@@ -21,6 +30,8 @@ export declare function cardButton(text: string, value: Record<string, unknown>,
|
|
|
21
30
|
size?: 'small' | 'medium' | 'large';
|
|
22
31
|
/** Fixed width, e.g. '100px' (keeps option-row buttons left-aligned). */
|
|
23
32
|
width?: string;
|
|
33
|
+
/** 置灰(当前项 / 不可执行),仍保留回调 payload。 */
|
|
34
|
+
disabled?: boolean;
|
|
24
35
|
}): object;
|
|
25
36
|
/**
|
|
26
37
|
* Create a CardKit 2.0 stop button with behaviors callback.
|
package/dist/card/card-shared.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentRegistry } from '../runner/index.js';
|
|
2
|
+
import { AGENT_DISPLAY_NAMES } from '../runner/types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Display name for an agent kind in the run card header.
|
|
4
5
|
*
|
|
@@ -11,19 +12,8 @@ export function agentDisplayName(kind) {
|
|
|
11
12
|
if (globalReg) {
|
|
12
13
|
return globalReg.getDisplayName(kind);
|
|
13
14
|
}
|
|
14
|
-
// Fallback
|
|
15
|
-
|
|
16
|
-
if (kind === 'claude')
|
|
17
|
-
return 'Claude';
|
|
18
|
-
if (kind === 'codex')
|
|
19
|
-
return 'Codex';
|
|
20
|
-
if (kind === 'opencode')
|
|
21
|
-
return 'Opencode';
|
|
22
|
-
if (kind === 'pi')
|
|
23
|
-
return 'Pi';
|
|
24
|
-
if (kind === 'kimi')
|
|
25
|
-
return 'Kimi';
|
|
26
|
-
return kind;
|
|
15
|
+
// Fallback for render helpers that run without the global registry.
|
|
16
|
+
return AGENT_DISPLAY_NAMES[kind] ?? kind;
|
|
27
17
|
}
|
|
28
18
|
const TERMINAL_LABELS = {
|
|
29
19
|
done: '已完成',
|
|
@@ -32,6 +22,8 @@ const TERMINAL_LABELS = {
|
|
|
32
22
|
idle_timeout: '已超时',
|
|
33
23
|
running: '运行中',
|
|
34
24
|
finalizing: '完成中',
|
|
25
|
+
// 本轮结束、goal 仍 active:任务没结束,标签不能说"完成"。
|
|
26
|
+
goal_continuing: '目标继续',
|
|
35
27
|
};
|
|
36
28
|
export function terminalToLabel(terminal) {
|
|
37
29
|
return TERMINAL_LABELS[terminal] ?? '运行中';
|
|
@@ -47,10 +39,27 @@ export function terminalToColor(terminal) {
|
|
|
47
39
|
return 'orange';
|
|
48
40
|
if (terminal === 'finalizing')
|
|
49
41
|
return 'orange';
|
|
42
|
+
if (terminal === 'goal_continuing')
|
|
43
|
+
return 'orange';
|
|
50
44
|
if (terminal === 'running')
|
|
51
45
|
return 'blue';
|
|
52
46
|
return 'red';
|
|
53
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* CardKit 2.0 静态卡骨架:schema/config/header + 给定 body elements。
|
|
50
|
+
* 队列状态卡、预算兜底卡等"只有 header 文案 + 少量 div"的卡共用。
|
|
51
|
+
*/
|
|
52
|
+
export function cardWithHeader(opts) {
|
|
53
|
+
return {
|
|
54
|
+
schema: '2.0',
|
|
55
|
+
config: { wide_screen_mode: true },
|
|
56
|
+
header: {
|
|
57
|
+
template: opts.template,
|
|
58
|
+
title: { tag: 'plain_text', content: opts.title },
|
|
59
|
+
},
|
|
60
|
+
body: { elements: opts.elements },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
54
63
|
/**
|
|
55
64
|
* Create a CardKit 2.0 button with a callback behavior. Shared constructor
|
|
56
65
|
* for every callback button in the card module (stop/new-session/compact/
|
|
@@ -65,6 +74,7 @@ export function cardButton(text, value, opts = {}) {
|
|
|
65
74
|
...(opts.type ? { type: opts.type } : {}),
|
|
66
75
|
...(opts.size ? { size: opts.size } : {}),
|
|
67
76
|
...(opts.width ? { width: opts.width } : {}),
|
|
77
|
+
...(opts.disabled !== undefined ? { disabled: opts.disabled } : {}),
|
|
68
78
|
behaviors: [{ type: 'callback', value }],
|
|
69
79
|
};
|
|
70
80
|
}
|
|
@@ -18,7 +18,6 @@ export declare class RunCardSession extends CardSession<RunState, RunCardRenderO
|
|
|
18
18
|
protected get logPrefix(): string;
|
|
19
19
|
protected get errorPrefix(): string;
|
|
20
20
|
protected renderCard(state: RunState, options: RunCardRenderOptions): object;
|
|
21
|
-
protected hasOwnBudgetProtection(): boolean;
|
|
22
21
|
protected isFlushableState(): boolean;
|
|
23
22
|
push(event: AgentEvent): Promise<void>;
|
|
24
23
|
finish(terminal: Exclude<RunTerminal, 'running' | 'finalizing'>, meta?: FinishMeta): Promise<void>;
|
|
@@ -22,12 +22,6 @@ export class RunCardSession extends CardSession {
|
|
|
22
22
|
renderCard(state, options) {
|
|
23
23
|
return renderRunCard(state, options);
|
|
24
24
|
}
|
|
25
|
-
hasOwnBudgetProtection() {
|
|
26
|
-
// renderRunCard has 3-tier degraded/extreme fallback budget protection
|
|
27
|
-
// that guarantees the returned card is <= 28KB, so the base-class
|
|
28
|
-
// enforceCardBudget stringify pass is redundant for run cards.
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
25
|
isFlushableState() {
|
|
32
26
|
// finish() 已转终态(done/error/interrupted/idle_timeout)时不再 patch;
|
|
33
27
|
// 'finalizing' 是非终态,in-flight/延迟 flush 仍可渲染累积事件。
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/**
|
|
3
|
-
* 带「详情」按钮的工具行数上限(从最新往回数)。
|
|
4
|
-
*
|
|
5
|
-
* 按钮行是节点大户:`column_set` + 2 个 `column` + 标题 div/text + button/text/
|
|
6
|
-
* behaviors/value ≈ 10 个 JSON 节点;纯标题行只有 2 个。24 行全带按钮 ≈ 240 节点,
|
|
7
|
-
* 直接撞飞书的元素总数上限(实测 203 通过 / 204 失败,见 card-budget.ts)。
|
|
8
|
-
* 最近 8 行保留按钮(用户最可能展开的就是刚跑完的),更早的行退化成一行标题。
|
|
9
|
-
*/
|
|
10
|
-
export declare const MAX_TOOL_ROWS_WITH_BUTTON = 8;
|
|
1
|
+
import { type RunState, type ToolEntry } from './run-state.js';
|
|
11
2
|
export interface RunCardRenderOptions {
|
|
12
3
|
/**
|
|
13
4
|
* Agent kind for the run card header title (e.g. "Claude · 思考中").
|
|
@@ -21,6 +12,13 @@ export interface RunCardRenderOptions {
|
|
|
21
12
|
* 无 turn_started → operationKind undefined)同样能拿到按钮。
|
|
22
13
|
*/
|
|
23
14
|
compactSupported?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 卡片没有 `state.sessionId` 时,是否仍有可压缩的会话(bridge 在开跑前从
|
|
17
|
+
* sessionStore 探到的会话)。`false` 表示「本轮没有 init,之前也没有任何
|
|
18
|
+
* 会话」——此时 Compact 按钮点了必然反查不到记录,不渲染。缺省(undefined)
|
|
19
|
+
* 保持原有「按钮可见」语义,供渲染层独立调用方使用。
|
|
20
|
+
*/
|
|
21
|
+
sessionFallbackAvailable?: boolean;
|
|
24
22
|
}
|
|
25
23
|
type BlockGroup = {
|
|
26
24
|
kind: 'thinking';
|
|
@@ -60,6 +58,9 @@ type GroupContentPrepared = Map<BlockGroup, string>;
|
|
|
60
58
|
* 状态标签(运行中/已完成…)不再重复:header 已经写了(`🔧 dsh · 调用工具`
|
|
61
59
|
* / `✅ dsh · 已完成`),终态 summary 还有一次。
|
|
62
60
|
*
|
|
61
|
+
* 终态也保留状态行:耗时定格,DSH 的步数/上下文投影展示最后一次快照
|
|
62
|
+
* (2026-10-21 用户要求)。summary 的最终 usage 与状态行并存。
|
|
63
|
+
*
|
|
63
64
|
* 导出供窄屏守卫测试断言分段宽度(与 `estimateCardBytes` 同一惯例)。
|
|
64
65
|
*/
|
|
65
66
|
export declare function statusLine(state: RunState): string;
|