lark-remote 0.5.6 → 0.5.8
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 +46 -6
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/dist/bridge/index.d.ts +63 -1
- package/dist/bridge/index.js +147 -14
- package/dist/bridge/queue-manager.js +41 -58
- 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.d.ts +37 -0
- package/dist/card/card-budget.js +143 -24
- 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 +19 -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 +18 -0
- package/dist/card/run-renderer.js +330 -62
- package/dist/card/run-state.d.ts +26 -0
- package/dist/card/run-state.js +45 -0
- package/dist/card/text-truncate.d.ts +3 -5
- package/dist/card/text-truncate.js +3 -5
- package/dist/card/time.d.ts +14 -0
- package/dist/card/time.js +30 -0
- package/dist/card/tool-render.d.ts +15 -2
- package/dist/card/tool-render.js +42 -82
- package/dist/common/text-width.d.ts +24 -0
- package/dist/common/text-width.js +93 -0
- package/dist/common/tool-summary.d.ts +19 -0
- package/dist/common/tool-summary.js +171 -0
- package/dist/common/turn-failure.d.ts +13 -0
- package/dist/common/turn-failure.js +18 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +1 -1
- package/dist/connector/index.js +1 -1
- package/dist/index.js +66 -13
- package/dist/order/index.d.ts +2 -0
- package/dist/order/index.js +2 -0
- package/dist/platform/command.js +1 -1
- package/dist/platform/shell.d.ts +2 -2
- package/dist/platform/spawn.d.ts +1 -1
- package/dist/platform/spawn.js +2 -2
- package/dist/platform/types.d.ts +1 -1
- package/dist/router/card-helpers.d.ts +18 -16
- package/dist/router/card-helpers.js +88 -46
- 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 +9 -11
- package/dist/router/index.js +165 -356
- package/dist/router/order-exec-dispatch.js +2 -1
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +3 -3
- 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/common/jsonrpc/transport.d.ts +1 -1
- package/dist/runner/common/jsonrpc/transport.js +3 -3
- package/dist/runner/common/spawning-runner.d.ts +1 -1
- package/dist/runner/common/spawning-runner.js +2 -2
- package/dist/runner/dsh/auth.js +2 -1
- package/dist/runner/dsh/client.d.ts +100 -3
- package/dist/runner/dsh/client.js +290 -6
- package/dist/runner/dsh/exit-cancel.d.ts +32 -0
- package/dist/runner/dsh/exit-cancel.js +72 -0
- package/dist/runner/dsh/inflight.d.ts +62 -0
- package/dist/runner/dsh/inflight.js +140 -0
- package/dist/runner/dsh/runner.d.ts +90 -4
- package/dist/runner/dsh/runner.js +436 -18
- package/dist/runner/dsh/translator.d.ts +1 -1
- package/dist/runner/dsh/translator.js +103 -1
- package/dist/runner/dsh/types.d.ts +60 -0
- package/dist/runner/types.d.ts +95 -2
- 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/claude/sessions.js +2 -2
- package/dist/session/dsh/sessions.js +157 -17
- package/dist/update/install.js +1 -1
- package/package.json +1 -1
|
@@ -6,6 +6,43 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Docs: https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukz/feishu-cards/card-components/containers/collapsible-panel
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* 飞书单卡「元素」总量上限(实测)。
|
|
11
|
+
*
|
|
12
|
+
* 2026-10-19 用真实 API 在测试会话探测(`tests/feishu-live/feishu-card-element-total-limit.test.ts`
|
|
13
|
+
* 与 `feishu-workspace-card-limit` / `feishu-order-active-card-limit`):
|
|
14
|
+
*
|
|
15
|
+
* | 形状 | 结果 | elements 计数 |
|
|
16
|
+
* | --- | --- | --- |
|
|
17
|
+
* | 顶层平铺 99 个 div | ✅ | 99 |
|
|
18
|
+
* | 顶层平铺 100 个 div | ❌ 11310 | 100 |
|
|
19
|
+
* | 单列 column_set 内嵌 98 个 div | ✅ | 99 |
|
|
20
|
+
* | 单列 column_set 内嵌 99 个 div | ❌ | 100 |
|
|
21
|
+
* | `/order` 旧结构 20 行 | ❌ | 103 |
|
|
22
|
+
* | `/ws` 旧结构 20 行 | ❌ | 101 |
|
|
23
|
+
* | `/ws` 分页 15 行(整卡 227 个 JSON 对象) | ✅ | 80 |
|
|
24
|
+
*
|
|
25
|
+
* 判据是**递归统计 `elements` 数组成员**(不含 `columns`)**≤ 99**:所有实测的
|
|
26
|
+
* 成功/失败点都被它分开,而"整卡 JSON 对象数"分不开(`/ws` 分页卡 227 个对象
|
|
27
|
+
* 能发出去,平铺 100 个 div 只有 205 个对象却失败)。
|
|
28
|
+
*
|
|
29
|
+
* 另一个独立维度:单个 `column_set` 的列数(实测 66 列通过、67 列失败)。本仓库
|
|
30
|
+
* 所有卡片的列数都在 3 以内,用不到这个上限,仅在此记录以免再次误判。
|
|
31
|
+
*
|
|
32
|
+
* **旧结论勘误**:仓库曾把 `230025` 记为「elements 过多」。本次探测中它一次都
|
|
33
|
+
* 没有出现;元素超限统一是 `230099 / ErrCode: 11310 element exceeds the limit`。
|
|
34
|
+
*
|
|
35
|
+
* `MAX_CARD_ELEMENTS` 取 90(相对实测 99 留 10% 余量),用于渲染前的保守裁剪。
|
|
36
|
+
*/
|
|
37
|
+
export declare const MAX_CARD_ELEMENTS = 90;
|
|
38
|
+
/**
|
|
39
|
+
* 卡片递归的 `elements` 数组成员数(`columns` 不计数)——与飞书实测边界对齐。
|
|
40
|
+
*
|
|
41
|
+
* 注意与"JSON 对象总数"不同:`column_set` 的 `column` 对象不计入,button 的
|
|
42
|
+
* `behaviors`/`value` 也不计入。用它做预算才既不误伤能发出去的卡片,也不放过
|
|
43
|
+
* 真正超限的卡片。
|
|
44
|
+
*/
|
|
45
|
+
export declare function countCardElements(card: unknown): number;
|
|
9
46
|
interface CardBudgetOptions {
|
|
10
47
|
/** 最大事件面板数量(保留最新的) */
|
|
11
48
|
maxEventPanels?: number;
|
package/dist/card/card-budget.js
CHANGED
|
@@ -1,4 +1,79 @@
|
|
|
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';
|
|
4
|
+
/**
|
|
5
|
+
* 静态卡片体积保护
|
|
6
|
+
*
|
|
7
|
+
* 用于:auto-resume, /active, completion notification 等静态卡片
|
|
8
|
+
* 不适用于:run-renderer 的流式卡片(已有独立保护)
|
|
9
|
+
*
|
|
10
|
+
* Docs: https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukz/feishu-cards/card-components/containers/collapsible-panel
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* 飞书单卡「元素」总量上限(实测)。
|
|
14
|
+
*
|
|
15
|
+
* 2026-10-19 用真实 API 在测试会话探测(`tests/feishu-live/feishu-card-element-total-limit.test.ts`
|
|
16
|
+
* 与 `feishu-workspace-card-limit` / `feishu-order-active-card-limit`):
|
|
17
|
+
*
|
|
18
|
+
* | 形状 | 结果 | elements 计数 |
|
|
19
|
+
* | --- | --- | --- |
|
|
20
|
+
* | 顶层平铺 99 个 div | ✅ | 99 |
|
|
21
|
+
* | 顶层平铺 100 个 div | ❌ 11310 | 100 |
|
|
22
|
+
* | 单列 column_set 内嵌 98 个 div | ✅ | 99 |
|
|
23
|
+
* | 单列 column_set 内嵌 99 个 div | ❌ | 100 |
|
|
24
|
+
* | `/order` 旧结构 20 行 | ❌ | 103 |
|
|
25
|
+
* | `/ws` 旧结构 20 行 | ❌ | 101 |
|
|
26
|
+
* | `/ws` 分页 15 行(整卡 227 个 JSON 对象) | ✅ | 80 |
|
|
27
|
+
*
|
|
28
|
+
* 判据是**递归统计 `elements` 数组成员**(不含 `columns`)**≤ 99**:所有实测的
|
|
29
|
+
* 成功/失败点都被它分开,而"整卡 JSON 对象数"分不开(`/ws` 分页卡 227 个对象
|
|
30
|
+
* 能发出去,平铺 100 个 div 只有 205 个对象却失败)。
|
|
31
|
+
*
|
|
32
|
+
* 另一个独立维度:单个 `column_set` 的列数(实测 66 列通过、67 列失败)。本仓库
|
|
33
|
+
* 所有卡片的列数都在 3 以内,用不到这个上限,仅在此记录以免再次误判。
|
|
34
|
+
*
|
|
35
|
+
* **旧结论勘误**:仓库曾把 `230025` 记为「elements 过多」。本次探测中它一次都
|
|
36
|
+
* 没有出现;元素超限统一是 `230099 / ErrCode: 11310 element exceeds the limit`。
|
|
37
|
+
*
|
|
38
|
+
* `MAX_CARD_ELEMENTS` 取 90(相对实测 99 留 10% 余量),用于渲染前的保守裁剪。
|
|
39
|
+
*/
|
|
40
|
+
export const MAX_CARD_ELEMENTS = 90;
|
|
41
|
+
/**
|
|
42
|
+
* 卡片递归的 `elements` 数组成员数(`columns` 不计数)——与飞书实测边界对齐。
|
|
43
|
+
*
|
|
44
|
+
* 注意与"JSON 对象总数"不同:`column_set` 的 `column` 对象不计入,button 的
|
|
45
|
+
* `behaviors`/`value` 也不计入。用它做预算才既不误伤能发出去的卡片,也不放过
|
|
46
|
+
* 真正超限的卡片。
|
|
47
|
+
*/
|
|
48
|
+
export function countCardElements(card) {
|
|
49
|
+
let total = 0;
|
|
50
|
+
const walk = (value) => {
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
for (const item of value)
|
|
53
|
+
walk(item);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!value || typeof value !== 'object')
|
|
57
|
+
return;
|
|
58
|
+
const rec = value;
|
|
59
|
+
if (Array.isArray(rec.elements)) {
|
|
60
|
+
total += rec.elements.length;
|
|
61
|
+
walk(rec.elements);
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(rec.columns)) {
|
|
64
|
+
walk(rec.columns);
|
|
65
|
+
}
|
|
66
|
+
// 继续下潜其余字段(`body`、`header` 等):卡片根对象本身没有 elements,
|
|
67
|
+
// 不遍历字段就永远数到 0(曾因此让整条元素预算静默失效)。
|
|
68
|
+
for (const [key, child] of Object.entries(value)) {
|
|
69
|
+
if (key === 'elements' || key === 'columns')
|
|
70
|
+
continue;
|
|
71
|
+
walk(child);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
walk(card);
|
|
75
|
+
return total;
|
|
76
|
+
}
|
|
2
77
|
/**
|
|
3
78
|
* 静态卡片体积保护
|
|
4
79
|
*
|
|
@@ -13,11 +88,12 @@ export function enforceCardBudget(card, opts = {}) {
|
|
|
13
88
|
const cardStr = JSON.stringify(card);
|
|
14
89
|
const bytesBefore = Buffer.byteLength(cardStr, 'utf8');
|
|
15
90
|
const parsed = JSON.parse(cardStr);
|
|
91
|
+
const elementsBefore = countCardElements(parsed);
|
|
16
92
|
const droppedTables = capCardMarkdownTables(parsed, FEISHU_MAX_TABLES);
|
|
17
93
|
if (droppedTables > 0) {
|
|
18
94
|
const fixedStr = JSON.stringify(parsed);
|
|
19
|
-
// table
|
|
20
|
-
if (Buffer.byteLength(fixedStr, 'utf8')
|
|
95
|
+
// table 截断后可能仍超预算(字节或元素总数),继续走后续阶段
|
|
96
|
+
if (fitsBudget(Buffer.byteLength(fixedStr, 'utf8'), countCardElements(parsed))) {
|
|
21
97
|
return {
|
|
22
98
|
card: parsed,
|
|
23
99
|
wasTruncated: true,
|
|
@@ -26,15 +102,64 @@ export function enforceCardBudget(card, opts = {}) {
|
|
|
26
102
|
bytesAfter: Buffer.byteLength(fixedStr, 'utf8'),
|
|
27
103
|
};
|
|
28
104
|
}
|
|
29
|
-
|
|
30
|
-
return enforceByteBudget(parsed, opts, bytesBefore);
|
|
105
|
+
return enforceElementBudget(parsed, opts, bytesBefore);
|
|
31
106
|
}
|
|
32
|
-
if (bytesBefore
|
|
107
|
+
if (fitsBudget(bytesBefore, elementsBefore)) {
|
|
33
108
|
return { card, wasTruncated: false, bytesBefore, bytesAfter: bytesBefore };
|
|
34
109
|
}
|
|
110
|
+
// 元素总数超限:table 与字节可能都正常,必须先按元素数裁剪。
|
|
111
|
+
if (bytesBefore <= CARD_BUDGET_BYTES && elementsBefore > MAX_CARD_ELEMENTS) {
|
|
112
|
+
return enforceElementBudget(parsed, opts, bytesBefore);
|
|
113
|
+
}
|
|
35
114
|
// 字节超限但 table 不超限
|
|
36
115
|
return enforceByteBudget(JSON.parse(cardStr), opts, bytesBefore);
|
|
37
116
|
}
|
|
117
|
+
/** 同时满足字节与元素总数两个预算。 */
|
|
118
|
+
function fitsBudget(bytes, elements) {
|
|
119
|
+
return bytes <= CARD_BUDGET_BYTES && elements <= MAX_CARD_ELEMENTS;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 元素总数超限时的裁剪:先丢最老的面板,再交给字节路径继续降级。
|
|
123
|
+
*
|
|
124
|
+
* 与字节路径分开是因为成因正交:字节超限来自内容长度(截断内容即可),元素
|
|
125
|
+
* 超限来自元素个数(只能删元素)。两条路径共用 `getPanelIndices`。
|
|
126
|
+
*/
|
|
127
|
+
function enforceElementBudget(card, opts = {}, bytesBefore) {
|
|
128
|
+
const reasons = [];
|
|
129
|
+
const elements = card.body?.elements ?? [];
|
|
130
|
+
const size = () => Buffer.byteLength(JSON.stringify(card), 'utf8');
|
|
131
|
+
const done = (wasTruncated) => ({
|
|
132
|
+
card,
|
|
133
|
+
wasTruncated,
|
|
134
|
+
reason: reasons.join('+') || undefined,
|
|
135
|
+
bytesBefore: bytesBefore ?? size(),
|
|
136
|
+
bytesAfter: size(),
|
|
137
|
+
});
|
|
138
|
+
const dropPanels = (count) => {
|
|
139
|
+
const indices = getPanelIndices(elements)
|
|
140
|
+
.slice(0, count)
|
|
141
|
+
.sort((a, b) => b - a);
|
|
142
|
+
for (const idx of indices)
|
|
143
|
+
elements.splice(idx, 1);
|
|
144
|
+
return indices.length;
|
|
145
|
+
};
|
|
146
|
+
// 阶段1:面板按数量砍(面板是节点大户:一个面板外壳 + 内容)
|
|
147
|
+
const panelCount = getPanelIndices(elements).length;
|
|
148
|
+
if (panelCount > 0) {
|
|
149
|
+
let dropped = 0;
|
|
150
|
+
while (countCardElements(card) > MAX_CARD_ELEMENTS && getPanelIndices(elements).length > 0) {
|
|
151
|
+
dropped += dropPanels(1);
|
|
152
|
+
}
|
|
153
|
+
if (dropped > 0)
|
|
154
|
+
reasons.push('element_budget_panels_dropped');
|
|
155
|
+
}
|
|
156
|
+
if (countCardElements(card) <= MAX_CARD_ELEMENTS && size() <= CARD_BUDGET_BYTES) {
|
|
157
|
+
return done(true);
|
|
158
|
+
}
|
|
159
|
+
// 阶段2:仍超限(既不是面板、或字节同时超)→ 交给字节路径继续降级,
|
|
160
|
+
// 它最终会落到最小卡(节点数固定很小)。
|
|
161
|
+
return enforceByteBudget(card, opts, bytesBefore);
|
|
162
|
+
}
|
|
38
163
|
/**
|
|
39
164
|
* Byte-budget enforcement, extracted so table-limit fix can delegate to it
|
|
40
165
|
* when table truncation alone doesn't bring the card under the byte limit.
|
|
@@ -134,25 +259,19 @@ function enforceByteBudget(truncated, opts = {}, bytesBefore) {
|
|
|
134
259
|
return done(true);
|
|
135
260
|
}
|
|
136
261
|
// ========== 阶段5:最终兜底(原 extreme_fallback) ==========
|
|
137
|
-
const minimalCard = {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
tag: 'div',
|
|
148
|
-
text: {
|
|
149
|
-
tag: 'lark_md',
|
|
150
|
-
content: '会话内容过大,已自动截断。\n\n请使用 `/active` 查看完整列表。',
|
|
151
|
-
},
|
|
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` 查看完整列表。',
|
|
152
271
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
};
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
});
|
|
156
275
|
return {
|
|
157
276
|
card: minimalCard,
|
|
158
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: '已完成',
|
|
@@ -51,6 +41,21 @@ export function terminalToColor(terminal) {
|
|
|
51
41
|
return 'blue';
|
|
52
42
|
return 'red';
|
|
53
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* CardKit 2.0 静态卡骨架:schema/config/header + 给定 body elements。
|
|
46
|
+
* 队列状态卡、预算兜底卡等"只有 header 文案 + 少量 div"的卡共用。
|
|
47
|
+
*/
|
|
48
|
+
export function cardWithHeader(opts) {
|
|
49
|
+
return {
|
|
50
|
+
schema: '2.0',
|
|
51
|
+
config: { wide_screen_mode: true },
|
|
52
|
+
header: {
|
|
53
|
+
template: opts.template,
|
|
54
|
+
title: { tag: 'plain_text', content: opts.title },
|
|
55
|
+
},
|
|
56
|
+
body: { elements: opts.elements },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
54
59
|
/**
|
|
55
60
|
* Create a CardKit 2.0 button with a callback behavior. Shared constructor
|
|
56
61
|
* for every callback button in the card module (stop/new-session/compact/
|
|
@@ -65,6 +70,7 @@ export function cardButton(text, value, opts = {}) {
|
|
|
65
70
|
...(opts.type ? { type: opts.type } : {}),
|
|
66
71
|
...(opts.size ? { size: opts.size } : {}),
|
|
67
72
|
...(opts.width ? { width: opts.width } : {}),
|
|
73
|
+
...(opts.disabled !== undefined ? { disabled: opts.disabled } : {}),
|
|
68
74
|
behaviors: [{ type: 'callback', value }],
|
|
69
75
|
};
|
|
70
76
|
}
|
|
@@ -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 仍可渲染累积事件。
|
|
@@ -39,6 +39,24 @@ type BlockGroup = {
|
|
|
39
39
|
};
|
|
40
40
|
/** 每个块的截断后内容(thinking/plan/text),测量与渲染共用(建议项)。 */
|
|
41
41
|
type GroupContentPrepared = Map<BlockGroup, string>;
|
|
42
|
+
/**
|
|
43
|
+
* 状态行内容:**一行、一个 div、窄屏不换行**。
|
|
44
|
+
*
|
|
45
|
+
* 设计约束(2026-10-19 手机端实测):旧版把「状态标签」和「耗时/指标」放进
|
|
46
|
+
* `column_set` 的 auto + grow 两列,窄屏上 auto 列被挤到只剩两个字宽,
|
|
47
|
+
* "运行中" 被拆成 "运行 / 中"。列式布局的可用宽度取决于对端渲染,服务端无法
|
|
48
|
+
* 保证;所以这里改成单 div,段间用 " · " 分隔——换行只会发生在分隔符处,
|
|
49
|
+
* 而且整行控制在 ~26 个半角宽度内,320px 宽的手机也能放下。
|
|
50
|
+
*
|
|
51
|
+
* 状态标签(运行中/已完成…)不再重复:header 已经写了(`🔧 dsh · 调用工具`
|
|
52
|
+
* / `✅ dsh · 已完成`),终态 summary 还有一次。
|
|
53
|
+
*
|
|
54
|
+
* 终态也保留状态行:耗时定格,DSH 的步数/上下文投影展示最后一次快照
|
|
55
|
+
* (2026-10-21 用户要求)。summary 的最终 usage 与状态行并存。
|
|
56
|
+
*
|
|
57
|
+
* 导出供窄屏守卫测试断言分段宽度(与 `estimateCardBytes` 同一惯例)。
|
|
58
|
+
*/
|
|
59
|
+
export declare function statusLine(state: RunState): string;
|
|
42
60
|
/** 导出供测试断言估算精度(估算 ≈ 实际渲染字节,见 tests/anchor/run-card/run-card.test.ts)。 */
|
|
43
61
|
export declare function estimateCardBytes(state: RunState, options?: RunCardRenderOptions, shared?: {
|
|
44
62
|
groups?: BlockGroup[];
|