lark-remote 0.1.5 → 0.1.7
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 +39 -0
- package/README.en.md +5 -1
- package/README.md +10 -2
- package/dist/bridge/approval-coordinator.d.ts +131 -0
- package/dist/bridge/approval-coordinator.js +409 -0
- package/dist/bridge/inbound-media.d.ts +62 -0
- package/dist/bridge/inbound-media.js +282 -0
- package/dist/bridge/index.d.ts +138 -5
- package/dist/bridge/index.js +569 -65
- package/dist/bridge/queue-manager.d.ts +11 -1
- package/dist/bridge/queue-manager.js +20 -11
- package/dist/card/approval-render.d.ts +16 -0
- package/dist/card/approval-render.js +363 -0
- package/dist/card/bash-card-session.d.ts +2 -24
- package/dist/card/bash-card-session.js +6 -73
- package/dist/card/bash-renderer.js +2 -3
- package/dist/card/card-budget.js +29 -75
- package/dist/card/card-session.d.ts +48 -0
- package/dist/card/card-session.js +86 -0
- package/dist/card/card-shared.d.ts +13 -10
- package/dist/card/card-shared.js +27 -24
- package/dist/card/run-card-session.d.ts +2 -55
- package/dist/card/run-card-session.js +6 -104
- package/dist/card/run-renderer.js +140 -202
- package/dist/card/run-state.d.ts +38 -3
- package/dist/card/run-state.js +221 -11
- package/dist/card/text-truncate.d.ts +13 -12
- package/dist/card/text-truncate.js +13 -63
- package/dist/common/fs.d.ts +8 -0
- package/dist/common/fs.js +17 -0
- package/dist/common/guards.d.ts +0 -20
- package/dist/common/guards.js +0 -43
- package/dist/common/sleep.d.ts +2 -0
- package/dist/common/sleep.js +5 -0
- package/dist/common/truncate.d.ts +39 -0
- package/dist/common/truncate.js +92 -0
- package/dist/config/codex-config.d.ts +1 -1
- package/dist/config/codex-config.js +1 -1
- package/dist/config/dir.js +1 -1
- package/dist/config/index.d.ts +116 -9
- package/dist/config/index.js +122 -29
- package/dist/connector/index.d.ts +74 -2
- package/dist/connector/index.js +119 -1
- package/dist/index.js +139 -99
- package/dist/instance-lock.js +4 -12
- package/dist/order/alias-resolve.d.ts +13 -0
- package/dist/order/alias-resolve.js +22 -0
- package/dist/order/alias-store.d.ts +38 -0
- package/dist/order/alias-store.js +106 -0
- package/dist/persistence/atomic-write.d.ts +8 -2
- package/dist/persistence/atomic-write.js +23 -7
- package/dist/restart.js +2 -1
- package/dist/router/card-helpers.d.ts +63 -0
- package/dist/router/card-helpers.js +146 -0
- package/dist/router/config/claude.js +25 -1
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +33 -5
- package/dist/router/config/common/model-patch.d.ts +22 -0
- package/dist/router/config/common/model-patch.js +26 -0
- package/dist/router/config/common/render.js +9 -4
- package/dist/router/config/index.d.ts +12 -0
- package/dist/router/config/index.js +25 -1
- package/dist/router/config/kimi.d.ts +4 -1
- package/dist/router/config/kimi.js +27 -0
- package/dist/router/config/opencode.js +18 -5
- package/dist/router/config/pi.js +4 -5
- package/dist/router/config/types.d.ts +12 -3
- package/dist/router/index.d.ts +77 -17
- package/dist/router/index.js +455 -549
- package/dist/router/utils.d.ts +4 -0
- package/dist/router/utils.js +9 -2
- package/dist/runner/agent-choices-common.d.ts +16 -0
- package/dist/runner/agent-choices-common.js +31 -0
- package/dist/runner/claude/runner.d.ts +47 -10
- package/dist/runner/claude/runner.js +117 -46
- package/dist/runner/claude/session.d.ts +166 -0
- package/dist/runner/claude/session.js +749 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +519 -0
- package/dist/runner/codex/app-server/protocol-types.js +56 -0
- package/dist/runner/codex/app-server/runner.d.ts +104 -0
- package/dist/runner/codex/app-server/runner.js +377 -0
- package/dist/runner/codex/app-server/translator.d.ts +89 -0
- package/dist/runner/codex/app-server/translator.js +716 -0
- package/dist/runner/codex/index.d.ts +1 -1
- package/dist/runner/codex/index.js +1 -1
- package/dist/runner/common/acp/protocol-helpers.d.ts +14 -0
- package/dist/runner/common/acp/protocol-helpers.js +21 -0
- package/dist/runner/common/acp/protocol-types.d.ts +238 -0
- package/dist/runner/common/acp/protocol-types.js +75 -0
- package/dist/runner/common/connection-based-runner.d.ts +111 -0
- package/dist/runner/common/connection-based-runner.js +261 -0
- package/dist/runner/common/jsonrpc/client.d.ts +89 -0
- package/dist/runner/common/jsonrpc/client.js +243 -0
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
- package/dist/runner/common/jsonrpc/connection-manager.js +205 -0
- package/dist/runner/common/jsonrpc/transport.d.ts +50 -0
- package/dist/runner/common/jsonrpc/transport.js +230 -0
- package/dist/runner/common/jsonrpc/types.d.ts +32 -0
- package/dist/runner/common/jsonrpc/types.js +9 -0
- package/dist/runner/common/process-stopper.d.ts +2 -1
- package/dist/runner/common/process-stopper.js +1 -0
- package/dist/runner/common/runner-utils.d.ts +6 -13
- package/dist/runner/common/runner-utils.js +6 -47
- package/dist/runner/common/spawning-runner.d.ts +24 -70
- package/dist/runner/common/spawning-runner.js +98 -152
- package/dist/runner/common/usage.d.ts +2 -0
- package/dist/runner/common/usage.js +2 -0
- package/dist/runner/index.d.ts +5 -5
- package/dist/runner/index.js +4 -4
- package/dist/runner/kimi/acp/runner.d.ts +106 -0
- package/dist/runner/kimi/acp/runner.js +448 -0
- package/dist/runner/kimi/acp/translator.d.ts +124 -0
- package/dist/runner/kimi/acp/translator.js +336 -0
- package/dist/runner/kimi/index.d.ts +1 -1
- package/dist/runner/kimi/index.js +1 -1
- package/dist/runner/opencode/acp/index.d.ts +1 -0
- package/dist/runner/opencode/acp/index.js +2 -0
- package/dist/runner/opencode/acp/runner.d.ts +121 -0
- package/dist/runner/opencode/acp/runner.js +429 -0
- package/dist/runner/opencode/acp/translator.d.ts +119 -0
- package/dist/runner/opencode/acp/translator.js +345 -0
- package/dist/runner/opencode/index.d.ts +1 -1
- package/dist/runner/opencode/index.js +1 -1
- package/dist/runner/pi/index.d.ts +1 -1
- package/dist/runner/pi/index.js +1 -1
- package/dist/runner/pi/rpc/client.d.ts +52 -0
- package/dist/runner/pi/rpc/client.js +114 -0
- package/dist/runner/pi/rpc/index.d.ts +4 -0
- package/dist/runner/pi/rpc/index.js +4 -0
- package/dist/runner/pi/rpc/protocol-types.d.ts +127 -0
- package/dist/runner/pi/rpc/protocol-types.js +21 -0
- package/dist/runner/pi/rpc/runner.d.ts +80 -0
- package/dist/runner/pi/rpc/runner.js +199 -0
- package/dist/runner/pi/rpc/translator.d.ts +55 -0
- package/dist/runner/pi/rpc/translator.js +258 -0
- package/dist/runner/registry.d.ts +7 -8
- package/dist/runner/registry.js +3 -4
- package/dist/runner/resolve-agent-choices.js +18 -59
- package/dist/runner/sync-agent-choices.js +16 -67
- package/dist/runner/types.d.ts +153 -2
- package/dist/session/claude/session-index.js +2 -3
- package/dist/session/claude/session-reader.js +3 -6
- package/dist/session/claude/sessions.js +6 -13
- package/dist/session/codex/rollout-reader.d.ts +2 -2
- package/dist/session/codex/rollout-reader.js +57 -17
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +2 -2
- package/dist/session/common/content-blocks.d.ts +7 -0
- package/dist/session/common/content-blocks.js +13 -9
- package/dist/session/common/jsonl.d.ts +8 -25
- package/dist/session/common/jsonl.js +126 -261
- package/dist/session/common/pagination.d.ts +28 -0
- package/dist/session/common/pagination.js +33 -0
- package/dist/session/kimi/sessions.d.ts +34 -1
- package/dist/session/kimi/sessions.js +208 -98
- package/dist/session/opencode/sessions.d.ts +17 -3
- package/dist/session/opencode/sessions.js +29 -29
- package/dist/session/pi/sessions.d.ts +5 -1
- package/dist/session/pi/sessions.js +12 -16
- package/dist/session/session-store.d.ts +11 -1
- package/dist/session/session-store.js +75 -178
- package/dist/update/index.d.ts +2 -2
- package/dist/update/index.js +2 -2
- package/dist/update/install.d.ts +20 -2
- package/dist/update/install.js +51 -7
- package/package.json +1 -1
- package/dist/runner/codex/argv.d.ts +0 -33
- package/dist/runner/codex/argv.js +0 -40
- package/dist/runner/codex/jsonl.d.ts +0 -37
- package/dist/runner/codex/jsonl.js +0 -221
- package/dist/runner/codex/runner.d.ts +0 -63
- package/dist/runner/codex/runner.js +0 -124
- package/dist/runner/common/exec-translator.d.ts +0 -73
- package/dist/runner/common/exec-translator.js +0 -105
- package/dist/runner/kimi/jsonl.d.ts +0 -28
- package/dist/runner/kimi/jsonl.js +0 -143
- package/dist/runner/kimi/runner.d.ts +0 -49
- package/dist/runner/kimi/runner.js +0 -105
- package/dist/runner/opencode/argv.d.ts +0 -32
- package/dist/runner/opencode/argv.js +0 -35
- package/dist/runner/opencode/jsonl.d.ts +0 -68
- package/dist/runner/opencode/jsonl.js +0 -295
- package/dist/runner/opencode/runner.d.ts +0 -61
- package/dist/runner/opencode/runner.js +0 -93
- package/dist/runner/pi/jsonl.d.ts +0 -128
- package/dist/runner/pi/jsonl.js +0 -249
- package/dist/runner/pi/runner.d.ts +0 -36
- package/dist/runner/pi/runner.js +0 -76
- package/dist/session/common/catch-up.d.ts +0 -12
- package/dist/session/common/catch-up.js +0 -31
package/dist/card/card-budget.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { truncateUtf8, truncateMarkdownTables, countMarkdownTables, FEISHU_MAX_TABLES, } from './text-truncate.js';
|
|
2
|
-
// 飞书卡片大小限制(安全阈值,取 run-renderer 相同值)
|
|
3
|
-
const CARD_BUDGET_BYTES = 28_000;
|
|
1
|
+
import { truncateUtf8, truncateMarkdownTables, countMarkdownTables, FEISHU_MAX_TABLES, CARD_BUDGET_BYTES, } from './text-truncate.js';
|
|
4
2
|
/**
|
|
5
3
|
* 静态卡片体积保护
|
|
6
4
|
*
|
|
@@ -17,7 +15,6 @@ export function enforceCardBudget(card, opts = {}) {
|
|
|
17
15
|
const totalTables = countCardTables(JSON.parse(cardStr));
|
|
18
16
|
if (totalTables > FEISHU_MAX_TABLES) {
|
|
19
17
|
// 深拷贝后对每个 lark_md 文本做 truncateMarkdownTables
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
18
|
const fixed = JSON.parse(cardStr);
|
|
22
19
|
truncateCardMarkdownTables(fixed);
|
|
23
20
|
const fixedStr = JSON.stringify(fixed);
|
|
@@ -38,7 +35,6 @@ export function enforceCardBudget(card, opts = {}) {
|
|
|
38
35
|
return { card, wasTruncated: false, bytesBefore, bytesAfter: bytesBefore };
|
|
39
36
|
}
|
|
40
37
|
// 字节超限但 table 不超限
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
38
|
return enforceByteBudget(JSON.parse(cardStr), opts, bytesBefore);
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
@@ -59,12 +55,9 @@ export function enforceCardBudget(card, opts = {}) {
|
|
|
59
55
|
* 阶段4 截断剩余顶层 div 文本
|
|
60
56
|
* 阶段5 最终兜底 minimal card(骨架本身已超限的病理场景)
|
|
61
57
|
*/
|
|
62
|
-
function enforceByteBudget(
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
-
truncated, opts = {}, bytesBefore) {
|
|
58
|
+
function enforceByteBudget(truncated, opts = {}, bytesBefore) {
|
|
65
59
|
const { maxEventPanels = 5, maxPanelContentBytes = 2000, truncationHint = '📜 还有 {count} 个事件未显示', } = opts;
|
|
66
60
|
const reasons = [];
|
|
67
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
61
|
const elements = truncated.body?.elements ?? [];
|
|
69
62
|
const size = () => Buffer.byteLength(JSON.stringify(truncated), 'utf8');
|
|
70
63
|
const done = (wasTruncated) => ({
|
|
@@ -173,7 +166,6 @@ truncated, opts = {}, bytesBefore) {
|
|
|
173
166
|
/**
|
|
174
167
|
* 在卡片头部插入「N 个事件未显示」提示(仅在有面板被移除时)。
|
|
175
168
|
*/
|
|
176
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
177
169
|
function insertOmittedHint(elements, omitted, truncationHint) {
|
|
178
170
|
if (omitted <= 0)
|
|
179
171
|
return;
|
|
@@ -185,7 +177,6 @@ function insertOmittedHint(elements, omitted, truncationHint) {
|
|
|
185
177
|
/**
|
|
186
178
|
* 获取所有 collapsible_panel 的索引(结构化判定,不看标题文本)。
|
|
187
179
|
*/
|
|
188
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
180
|
function getPanelIndices(elements) {
|
|
190
181
|
const indices = [];
|
|
191
182
|
for (let i = 0; i < elements.length; i++) {
|
|
@@ -196,84 +187,47 @@ function getPanelIndices(elements) {
|
|
|
196
187
|
return indices;
|
|
197
188
|
}
|
|
198
189
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
190
|
+
* 遍历卡片元素树(含 collapsible_panel.elements 与 column_set.columns[].elements)。
|
|
191
|
+
*
|
|
192
|
+
* count 与 truncate 两条路径共用同一遍历,避免两套递归漂移(G5 Duplication)。
|
|
201
193
|
*/
|
|
202
|
-
|
|
203
|
-
function countCardTables(card) {
|
|
204
|
-
let total = 0;
|
|
205
|
-
const elements = card?.body?.elements ?? [];
|
|
194
|
+
function walkCardElements(elements, visit) {
|
|
206
195
|
for (const el of elements) {
|
|
207
|
-
|
|
196
|
+
visit(el);
|
|
197
|
+
if (Array.isArray(el.elements))
|
|
198
|
+
walkCardElements(el.elements, visit);
|
|
199
|
+
if (Array.isArray(el.columns)) {
|
|
200
|
+
for (const col of el.columns) {
|
|
201
|
+
if (Array.isArray(col.elements))
|
|
202
|
+
walkCardElements(col.elements, visit);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
208
205
|
}
|
|
209
|
-
return total;
|
|
210
206
|
}
|
|
211
207
|
/**
|
|
212
|
-
*
|
|
208
|
+
* Count all markdown tables across every lark_md text field in a card JSON.
|
|
213
209
|
*/
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
count += countMarkdownTables(el.text.content);
|
|
220
|
-
}
|
|
221
|
-
// collapsible_panel inner elements
|
|
222
|
-
if (Array.isArray(el.elements)) {
|
|
223
|
-
for (const child of el.elements) {
|
|
224
|
-
count += countElementTables(child);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
// column_set → columns → elements
|
|
228
|
-
if (Array.isArray(el.columns)) {
|
|
229
|
-
for (const col of el.columns) {
|
|
230
|
-
if (Array.isArray(col.elements)) {
|
|
231
|
-
for (const child of col.elements) {
|
|
232
|
-
count += countElementTables(child);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
210
|
+
function countCardTables(card) {
|
|
211
|
+
let total = 0;
|
|
212
|
+
walkCardElements(card?.body?.elements ?? [], (el) => {
|
|
213
|
+
if (el.text?.tag === 'lark_md' && typeof el.text.content === 'string') {
|
|
214
|
+
total += countMarkdownTables(el.text.content);
|
|
235
215
|
}
|
|
236
|
-
}
|
|
237
|
-
return
|
|
216
|
+
});
|
|
217
|
+
return total;
|
|
238
218
|
}
|
|
239
219
|
/**
|
|
240
220
|
* In-place truncate markdown tables in every lark_md text field of a card,
|
|
241
221
|
* keeping at most FEISHU_MAX_TABLES per field.
|
|
242
222
|
*/
|
|
243
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
223
|
function truncateCardMarkdownTables(card) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Recursively truncate markdown tables in a single element and its children.
|
|
252
|
-
*/
|
|
253
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
|
-
function truncateElementTables(el) {
|
|
255
|
-
// lark_md div text
|
|
256
|
-
if (el.text?.tag === 'lark_md' && typeof el.text.content === 'string') {
|
|
257
|
-
const truncated = truncateMarkdownTables(el.text.content);
|
|
258
|
-
if (truncated !== el.text.content) {
|
|
259
|
-
el.text.content = truncated;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// collapsible_panel inner elements
|
|
263
|
-
if (Array.isArray(el.elements)) {
|
|
264
|
-
for (const child of el.elements) {
|
|
265
|
-
truncateElementTables(child);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// column_set → columns → elements
|
|
269
|
-
if (Array.isArray(el.columns)) {
|
|
270
|
-
for (const col of el.columns) {
|
|
271
|
-
if (Array.isArray(col.elements)) {
|
|
272
|
-
for (const child of col.elements) {
|
|
273
|
-
truncateElementTables(child);
|
|
274
|
-
}
|
|
224
|
+
walkCardElements(card?.body?.elements ?? [], (el) => {
|
|
225
|
+
if (el.text?.tag === 'lark_md' && typeof el.text.content === 'string') {
|
|
226
|
+
const truncated = truncateMarkdownTables(el.text.content);
|
|
227
|
+
if (truncated !== el.text.content) {
|
|
228
|
+
el.text.content = truncated;
|
|
275
229
|
}
|
|
276
230
|
}
|
|
277
|
-
}
|
|
231
|
+
});
|
|
278
232
|
}
|
|
279
233
|
//# sourceMappingURL=card-budget.js.map
|
|
@@ -52,10 +52,58 @@ export declare abstract class CardSession<S, RO = unknown> {
|
|
|
52
52
|
renderOptions?: RO;
|
|
53
53
|
startTimeoutMs?: number;
|
|
54
54
|
settleTimeoutMs?: number;
|
|
55
|
+
/** update/push 合批窗口,默认 100ms(0 = 禁用合批,每事件立即 flush)。 */
|
|
56
|
+
coalesceMs?: number;
|
|
55
57
|
});
|
|
58
|
+
/**
|
|
59
|
+
* 调度一次延迟 flush。已有 pending 调度则复用(合批核心);否则起一个
|
|
60
|
+
* coalesceMs 定时器。flushInFlight 期间不再起 timer(避免重入叠加),但置
|
|
61
|
+
* pendingReschedule 以便 in-flight flush 完成后重新调度——否则 in-flight 期间
|
|
62
|
+
* 到达的 push/update 会停留为 stale 中间帧(P2-1)。
|
|
63
|
+
*/
|
|
64
|
+
protected scheduleFlush(): void;
|
|
65
|
+
/**
|
|
66
|
+
* 执行一次 render + updateCard。合批窗口到期或 finish 即时 flush 时调用。
|
|
67
|
+
* flushInFlight 防止 timer 回调与 finish 的即时 flush 重入。
|
|
68
|
+
*
|
|
69
|
+
* 终态守卫:若 finish() 已把 state 转为终态,跳过本次 patch——避免 in-flight flush
|
|
70
|
+
* 用 pre-terminal state 覆盖 finish 已发的终态卡。finish() 自身会 await 任何
|
|
71
|
+
* in-flight flush 保证顺序,此守卫是双保险。
|
|
72
|
+
*/
|
|
73
|
+
protected flush(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the current state still permits a flush (i.e. is not yet terminal).
|
|
76
|
+
* Subclasses define their terminal set. Run treats 'finalizing' as non-terminal.
|
|
77
|
+
*/
|
|
78
|
+
protected abstract isFlushableState(): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态
|
|
81
|
+
* 渲染竞争)。返回是否有被取消的 pending 调度。同时清掉 pendingReschedule,
|
|
82
|
+
* 防止 in-flight flush 的 finally 在 finish await 之后又起 dangling timer
|
|
83
|
+
* (finish 自身会渲染含累积事件的终态卡,无需 follow-up)。
|
|
84
|
+
*/
|
|
85
|
+
protected cancelPendingFlush(): boolean;
|
|
56
86
|
get currentState(): S;
|
|
57
87
|
/** The messageId of the streaming card, available after `start()` resolves. */
|
|
58
88
|
get cardMessageId(): string | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* P1-3 合批窗口(ms)。连续事件各触发一次全卡 render + patch 是流式 CPU 主要
|
|
91
|
+
* 来源;窗口内多个事件复用同一次延迟 flush。窗口大小可通过 constructor 覆盖
|
|
92
|
+
* (测试用小窗口/0 禁用)。run/bash 子类共用的 flush 骨架(scheduleFlush/flush/
|
|
93
|
+
* cancelPendingFlush/settle)下沉到基类。
|
|
94
|
+
*/
|
|
95
|
+
protected readonly coalesceMs: number;
|
|
96
|
+
private flushTimer;
|
|
97
|
+
private flushInFlight; /** P2-1:in-flight flush 期间到达的 push/update 标记。scheduleFlush 在
|
|
98
|
+
* flushInFlight 时早退不调度新 timer,但事件已 reduce 进 state;若无此标志,
|
|
99
|
+
* in-flight flush 完成后该事件无 follow-up render,停留为 stale 中间帧。
|
|
100
|
+
* finally 检查此标志后重新 scheduleFlush,保证 in-flight 期间累积的事件最终被渲染。 */
|
|
101
|
+
private pendingReschedule;
|
|
102
|
+
/** 当前 in-flight flush 的 promise(若 flush 正在 await updateCard)。
|
|
103
|
+
* finish() 在终态 patch 前 await 它,保证 in-flight 的 pre-terminal patch 先落地、
|
|
104
|
+
* terminal patch 后落地——否则两条 controller.update 并发无 FIFO,
|
|
105
|
+
* pre-terminal 可能在 terminal 之后 resolve 留下"思考中"终帧(P2)。 */
|
|
106
|
+
protected flushP: Promise<void> | undefined;
|
|
59
107
|
start(): Promise<void>;
|
|
60
108
|
settle(): Promise<StreamSettleResult>;
|
|
61
109
|
/**
|
|
@@ -40,6 +40,74 @@ export class CardSession {
|
|
|
40
40
|
this.resolveController = resolve;
|
|
41
41
|
this.rejectController = reject;
|
|
42
42
|
});
|
|
43
|
+
this.coalesceMs = opts.coalesceMs ?? 100;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 调度一次延迟 flush。已有 pending 调度则复用(合批核心);否则起一个
|
|
47
|
+
* coalesceMs 定时器。flushInFlight 期间不再起 timer(避免重入叠加),但置
|
|
48
|
+
* pendingReschedule 以便 in-flight flush 完成后重新调度——否则 in-flight 期间
|
|
49
|
+
* 到达的 push/update 会停留为 stale 中间帧(P2-1)。
|
|
50
|
+
*/
|
|
51
|
+
scheduleFlush() {
|
|
52
|
+
if (this.flushTimer)
|
|
53
|
+
return;
|
|
54
|
+
if (this.flushInFlight) {
|
|
55
|
+
this.pendingReschedule = true;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.flushTimer = setTimeout(() => {
|
|
59
|
+
this.flushTimer = undefined;
|
|
60
|
+
void this.flush();
|
|
61
|
+
}, this.coalesceMs);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 执行一次 render + updateCard。合批窗口到期或 finish 即时 flush 时调用。
|
|
65
|
+
* flushInFlight 防止 timer 回调与 finish 的即时 flush 重入。
|
|
66
|
+
*
|
|
67
|
+
* 终态守卫:若 finish() 已把 state 转为终态,跳过本次 patch——避免 in-flight flush
|
|
68
|
+
* 用 pre-terminal state 覆盖 finish 已发的终态卡。finish() 自身会 await 任何
|
|
69
|
+
* in-flight flush 保证顺序,此守卫是双保险。
|
|
70
|
+
*/
|
|
71
|
+
async flush() {
|
|
72
|
+
if (this.flushInFlight)
|
|
73
|
+
return;
|
|
74
|
+
if (!this.isFlushableState())
|
|
75
|
+
return;
|
|
76
|
+
this.flushInFlight = true;
|
|
77
|
+
const flushPromise = (async () => {
|
|
78
|
+
try {
|
|
79
|
+
await this.updateCard();
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
this.flushInFlight = false;
|
|
83
|
+
// flushInFlight 守卫保证同一时刻只有一个 in-flight flush,故可无条件清空。
|
|
84
|
+
this.flushP = undefined;
|
|
85
|
+
// P2-1:in-flight 期间若有 push/update 到达(pendingReschedule),重新调度一次
|
|
86
|
+
// flush 渲染累积事件,避免 stale 中间帧。终态守卫在 flush() 入口已拦截,
|
|
87
|
+
// 故 finish 后不会误触发。
|
|
88
|
+
if (this.pendingReschedule) {
|
|
89
|
+
this.pendingReschedule = false;
|
|
90
|
+
this.scheduleFlush();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
this.flushP = flushPromise;
|
|
95
|
+
return flushPromise;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态
|
|
99
|
+
* 渲染竞争)。返回是否有被取消的 pending 调度。同时清掉 pendingReschedule,
|
|
100
|
+
* 防止 in-flight flush 的 finally 在 finish await 之后又起 dangling timer
|
|
101
|
+
* (finish 自身会渲染含累积事件的终态卡,无需 follow-up)。
|
|
102
|
+
*/
|
|
103
|
+
cancelPendingFlush() {
|
|
104
|
+
this.pendingReschedule = false;
|
|
105
|
+
if (this.flushTimer) {
|
|
106
|
+
clearTimeout(this.flushTimer);
|
|
107
|
+
this.flushTimer = undefined;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
43
111
|
}
|
|
44
112
|
get currentState() {
|
|
45
113
|
return this.state;
|
|
@@ -48,6 +116,24 @@ export class CardSession {
|
|
|
48
116
|
get cardMessageId() {
|
|
49
117
|
return this.messageId;
|
|
50
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* P1-3 合批窗口(ms)。连续事件各触发一次全卡 render + patch 是流式 CPU 主要
|
|
121
|
+
* 来源;窗口内多个事件复用同一次延迟 flush。窗口大小可通过 constructor 覆盖
|
|
122
|
+
* (测试用小窗口/0 禁用)。run/bash 子类共用的 flush 骨架(scheduleFlush/flush/
|
|
123
|
+
* cancelPendingFlush/settle)下沉到基类。
|
|
124
|
+
*/
|
|
125
|
+
coalesceMs;
|
|
126
|
+
flushTimer;
|
|
127
|
+
flushInFlight = false; /** P2-1:in-flight flush 期间到达的 push/update 标记。scheduleFlush 在
|
|
128
|
+
* flushInFlight 时早退不调度新 timer,但事件已 reduce 进 state;若无此标志,
|
|
129
|
+
* in-flight flush 完成后该事件无 follow-up render,停留为 stale 中间帧。
|
|
130
|
+
* finally 检查此标志后重新 scheduleFlush,保证 in-flight 期间累积的事件最终被渲染。 */
|
|
131
|
+
pendingReschedule = false;
|
|
132
|
+
/** 当前 in-flight flush 的 promise(若 flush 正在 await updateCard)。
|
|
133
|
+
* finish() 在终态 patch 前 await 它,保证 in-flight 的 pre-terminal patch 先落地、
|
|
134
|
+
* terminal patch 后落地——否则两条 controller.update 并发无 FIFO,
|
|
135
|
+
* pre-terminal 可能在 terminal 之后 resolve 留下"思考中"终帧(P2)。 */
|
|
136
|
+
flushP;
|
|
51
137
|
async start() {
|
|
52
138
|
if (this.streamOutcome) {
|
|
53
139
|
// 二次调用也套 timeout 保护:若 controllerReady 永不 settle(首次超时失败),
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { type AgentKind } from '../runner/index.js';
|
|
2
|
-
interface TruncateOptions {
|
|
3
|
-
suffix?: string;
|
|
4
|
-
normalizeWhitespace?: boolean;
|
|
5
|
-
}
|
|
6
2
|
/**
|
|
7
3
|
* Display name for an agent kind in the run card header.
|
|
8
4
|
*
|
|
@@ -11,7 +7,7 @@ interface TruncateOptions {
|
|
|
11
7
|
* wire up the registry (notably unit tests of pure render helpers).
|
|
12
8
|
*/
|
|
13
9
|
export declare function agentDisplayName(kind: string): string;
|
|
14
|
-
export
|
|
10
|
+
export { truncate } from '../common/truncate.js';
|
|
15
11
|
interface TerminalLabelOptions {
|
|
16
12
|
prefix?: string;
|
|
17
13
|
}
|
|
@@ -27,10 +23,17 @@ export declare function stopButton(runId: string): object;
|
|
|
27
23
|
*/
|
|
28
24
|
export declare function newSessionButton(): object;
|
|
29
25
|
/**
|
|
30
|
-
* Create a CardKit 2.0
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
* Create a CardKit 2.0 Compact button for Codex app-server mode.
|
|
27
|
+
* Triggers thread/compact/start via the codex.compact callback.
|
|
28
|
+
*/
|
|
29
|
+
export declare function compactButton(runId: string): object;
|
|
30
|
+
/**
|
|
31
|
+
* Create a CardKit 2.0 Compact button for resume cards (auto-resume / `/resume <id>`).
|
|
32
|
+
* Unlike compactButton (which targets a finished run's runId), this targets a
|
|
33
|
+
* sessionId directly: the bridge resolves the session and calls the app-server
|
|
34
|
+
* runner's runCompact() without a runId. Carries agent so the handler routes
|
|
35
|
+
* to the correct session reader + runner when the card was rendered for a
|
|
36
|
+
* non-default agent.
|
|
34
37
|
*/
|
|
38
|
+
export declare function resumeCompactButton(sessionId: string, agent: string): object;
|
|
35
39
|
export declare function resumeUseButton(sessionId: string, agent: AgentKind): object;
|
|
36
|
-
export {};
|
package/dist/card/card-shared.js
CHANGED
|
@@ -25,26 +25,7 @@ export function agentDisplayName(kind) {
|
|
|
25
25
|
return 'Kimi';
|
|
26
26
|
return kind;
|
|
27
27
|
}
|
|
28
|
-
export
|
|
29
|
-
const suffix = options?.suffix ?? '…';
|
|
30
|
-
const normalize = options?.normalizeWhitespace ?? false;
|
|
31
|
-
let s = str;
|
|
32
|
-
if (normalize)
|
|
33
|
-
s = s.replace(/\s+/g, ' ').trim();
|
|
34
|
-
if (s.length <= max)
|
|
35
|
-
return s;
|
|
36
|
-
const suffixLen = suffix.length;
|
|
37
|
-
const budget = max - suffixLen;
|
|
38
|
-
if (budget <= 0)
|
|
39
|
-
return suffix;
|
|
40
|
-
let end = 0;
|
|
41
|
-
for (const ch of s) {
|
|
42
|
-
if (end + ch.length > budget)
|
|
43
|
-
break;
|
|
44
|
-
end += ch.length;
|
|
45
|
-
}
|
|
46
|
-
return s.slice(0, end) + suffix;
|
|
47
|
-
}
|
|
28
|
+
export { truncate } from '../common/truncate.js';
|
|
48
29
|
const TERMINAL_LABELS = {
|
|
49
30
|
done: '已完成',
|
|
50
31
|
error: '出错',
|
|
@@ -97,11 +78,33 @@ export function newSessionButton() {
|
|
|
97
78
|
};
|
|
98
79
|
}
|
|
99
80
|
/**
|
|
100
|
-
* Create a CardKit 2.0
|
|
101
|
-
*
|
|
102
|
-
|
|
103
|
-
|
|
81
|
+
* Create a CardKit 2.0 Compact button for Codex app-server mode.
|
|
82
|
+
* Triggers thread/compact/start via the codex.compact callback.
|
|
83
|
+
*/
|
|
84
|
+
export function compactButton(runId) {
|
|
85
|
+
return {
|
|
86
|
+
tag: 'button',
|
|
87
|
+
text: { content: '🗜 Compact' },
|
|
88
|
+
type: 'primary',
|
|
89
|
+
behaviors: [{ type: 'callback', value: { cmd: 'codex.compact', runId } }],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a CardKit 2.0 Compact button for resume cards (auto-resume / `/resume <id>`).
|
|
94
|
+
* Unlike compactButton (which targets a finished run's runId), this targets a
|
|
95
|
+
* sessionId directly: the bridge resolves the session and calls the app-server
|
|
96
|
+
* runner's runCompact() without a runId. Carries agent so the handler routes
|
|
97
|
+
* to the correct session reader + runner when the card was rendered for a
|
|
98
|
+
* non-default agent.
|
|
104
99
|
*/
|
|
100
|
+
export function resumeCompactButton(sessionId, agent) {
|
|
101
|
+
return {
|
|
102
|
+
tag: 'button',
|
|
103
|
+
text: { content: '🗜 Compact' },
|
|
104
|
+
type: 'primary',
|
|
105
|
+
behaviors: [{ type: 'callback', value: { cmd: 'resume.compact', sessionId, agent } }],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
105
108
|
export function resumeUseButton(sessionId, agent) {
|
|
106
109
|
return {
|
|
107
110
|
tag: 'button',
|
|
@@ -1,34 +1,9 @@
|
|
|
1
|
-
import { CardSession, type CardChannel
|
|
1
|
+
import { CardSession, type CardChannel } from './card-session.js';
|
|
2
2
|
import type { AgentEvent } from '../runner/index.js';
|
|
3
3
|
import { type FinishMeta, type RunState, type RunTerminal } from './run-state.js';
|
|
4
4
|
import { type RunCardRenderOptions } from './run-renderer.js';
|
|
5
5
|
export type { CardChannel as RunCardChannel };
|
|
6
6
|
export declare class RunCardSession extends CardSession<RunState, RunCardRenderOptions> {
|
|
7
|
-
/**
|
|
8
|
-
* P1-3 push 合批窗口(ms)。连续 text delta 各触发一次全卡 render + patch 是
|
|
9
|
-
* 流式 CPU 主要来源(§P1-3)。窗口内多个事件复用同一次
|
|
10
|
-
* 延迟 flush,只 render + controller.update 一次。100ms 内人眼无感,且 text
|
|
11
|
-
* 流式 patch 次数 -80%。窗口大小可通过 constructor 覆盖(测试用小窗口)。
|
|
12
|
-
*/
|
|
13
|
-
private readonly coalesceMs;
|
|
14
|
-
private flushTimer;
|
|
15
|
-
private flushInFlight;
|
|
16
|
-
/**
|
|
17
|
-
* P2-1:in-flight flush 期间到达的 push 标记。scheduleFlush 在 flushInFlight
|
|
18
|
-
* 时早退不调度新 timer,但事件已 reduce 进 state;若无此标志,in-flight flush
|
|
19
|
-
* 完成后该事件无 follow-up render,停留为 stale 中间帧(生产 SDK 的
|
|
20
|
-
* controller.update 经 throttle + setTimeout 异步 resolve,故 flush 与
|
|
21
|
-
* 下一个 push 交叠是真实场景)。finally 检查此标志后重新 scheduleFlush,
|
|
22
|
-
* 保证 in-flight 期间累积的事件最终被渲染。
|
|
23
|
-
*/
|
|
24
|
-
private pendingReschedule;
|
|
25
|
-
/**
|
|
26
|
-
* 当前 in-flight flush 的 promise(若 flush 正在 await updateCard)。
|
|
27
|
-
* finish() 在终态 patch 前 await 它,保证 in-flight 的 pre-terminal patch
|
|
28
|
-
* 先落地、terminal patch 后落地——否则两条 controller.update 并发无 FIFO,
|
|
29
|
-
* pre-terminal 可能在 terminal 之后 resolve 留下"思考中"终帧(P2)。
|
|
30
|
-
*/
|
|
31
|
-
private flushP;
|
|
32
7
|
constructor(opts: {
|
|
33
8
|
connector: CardChannel;
|
|
34
9
|
chatId: string;
|
|
@@ -44,35 +19,7 @@ export declare class RunCardSession extends CardSession<RunState, RunCardRenderO
|
|
|
44
19
|
protected get errorPrefix(): string;
|
|
45
20
|
protected renderCard(state: RunState, options: RunCardRenderOptions): object;
|
|
46
21
|
protected hasOwnBudgetProtection(): boolean;
|
|
22
|
+
protected isFlushableState(): boolean;
|
|
47
23
|
push(event: AgentEvent): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* 调度一次延迟 flush。已有 pending 调度则复用(合批核心);否则起一个
|
|
50
|
-
* coalesceMs 定时器。flushInFlight 期间不再起 timer(避免重入叠加),但置
|
|
51
|
-
* pendingReschedule 以便 in-flight flush 完成后重新调度——否则 in-flight 期间
|
|
52
|
-
* 到达的 push 会停留为 stale 中间帧(P2-1)。
|
|
53
|
-
*/
|
|
54
|
-
private scheduleFlush;
|
|
55
|
-
/**
|
|
56
|
-
* 执行一次 render + updateCard。合批窗口到期或 finish 立即 flush 时调用。
|
|
57
|
-
* flushInFlight 防止 timer 回调与 finish 的即时 flush 重入。
|
|
58
|
-
*
|
|
59
|
-
* 终态守卫:若 finish() 已把 state 转为终态(done/error/interrupted/idle_timeout),
|
|
60
|
-
* 跳过本次 patch——避免 in-flight flush 用 pre-terminal state 覆盖 finish 已发的
|
|
61
|
-
* 终态卡。finish() 自身会 await 任何 in-flight flush 保证顺序,此守卫是双保险。
|
|
62
|
-
*/
|
|
63
|
-
private flush;
|
|
64
|
-
/**
|
|
65
|
-
* 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态
|
|
66
|
-
* 渲染竞争)。返回是否有被取消的 pending 调度。同时清掉 pendingReschedule,
|
|
67
|
-
* 防止 in-flight flush 的 finally 在 finish await 之后又起 dangling timer
|
|
68
|
-
* (finish 自身会渲染含累积事件的终态卡,无需 follow-up)。
|
|
69
|
-
*/
|
|
70
|
-
private cancelPendingFlush;
|
|
71
24
|
finish(terminal: Exclude<RunTerminal, 'running' | 'finalizing'>, meta?: FinishMeta): Promise<void>;
|
|
72
|
-
/**
|
|
73
|
-
* settle 前兜底取消合批调度。bridge 正常流程 finish→settle,finish 已 cancel;
|
|
74
|
-
* 但若未来有直调 settle(未经 finish)的路径,避免 dangling timer 在 release
|
|
75
|
-
* 后触发 void flush() 去更新已释放的 stream(harmless 但无谓)。
|
|
76
|
-
*/
|
|
77
|
-
settle(): Promise<StreamSettleResult>;
|
|
78
25
|
}
|
|
@@ -2,31 +2,6 @@ import { CardSession } from './card-session.js';
|
|
|
2
2
|
import { createInitialRunState, finishRun, reduceRunState, } from './run-state.js';
|
|
3
3
|
import { renderRunCard } from './run-renderer.js';
|
|
4
4
|
export class RunCardSession extends CardSession {
|
|
5
|
-
/**
|
|
6
|
-
* P1-3 push 合批窗口(ms)。连续 text delta 各触发一次全卡 render + patch 是
|
|
7
|
-
* 流式 CPU 主要来源(§P1-3)。窗口内多个事件复用同一次
|
|
8
|
-
* 延迟 flush,只 render + controller.update 一次。100ms 内人眼无感,且 text
|
|
9
|
-
* 流式 patch 次数 -80%。窗口大小可通过 constructor 覆盖(测试用小窗口)。
|
|
10
|
-
*/
|
|
11
|
-
coalesceMs;
|
|
12
|
-
flushTimer;
|
|
13
|
-
flushInFlight = false;
|
|
14
|
-
/**
|
|
15
|
-
* P2-1:in-flight flush 期间到达的 push 标记。scheduleFlush 在 flushInFlight
|
|
16
|
-
* 时早退不调度新 timer,但事件已 reduce 进 state;若无此标志,in-flight flush
|
|
17
|
-
* 完成后该事件无 follow-up render,停留为 stale 中间帧(生产 SDK 的
|
|
18
|
-
* controller.update 经 throttle + setTimeout 异步 resolve,故 flush 与
|
|
19
|
-
* 下一个 push 交叠是真实场景)。finally 检查此标志后重新 scheduleFlush,
|
|
20
|
-
* 保证 in-flight 期间累积的事件最终被渲染。
|
|
21
|
-
*/
|
|
22
|
-
pendingReschedule = false;
|
|
23
|
-
/**
|
|
24
|
-
* 当前 in-flight flush 的 promise(若 flush 正在 await updateCard)。
|
|
25
|
-
* finish() 在终态 patch 前 await 它,保证 in-flight 的 pre-terminal patch
|
|
26
|
-
* 先落地、terminal patch 后落地——否则两条 controller.update 并发无 FIFO,
|
|
27
|
-
* pre-terminal 可能在 terminal 之后 resolve 留下"思考中"终帧(P2)。
|
|
28
|
-
*/
|
|
29
|
-
flushP;
|
|
30
5
|
constructor(opts) {
|
|
31
6
|
super(createInitialRunState(opts.runId), {
|
|
32
7
|
connector: opts.connector,
|
|
@@ -35,8 +10,8 @@ export class RunCardSession extends CardSession {
|
|
|
35
10
|
renderOptions: opts.renderOptions,
|
|
36
11
|
startTimeoutMs: opts.startTimeoutMs,
|
|
37
12
|
settleTimeoutMs: opts.settleTimeoutMs,
|
|
13
|
+
coalesceMs: opts.coalesceMs,
|
|
38
14
|
});
|
|
39
|
-
this.coalesceMs = opts.coalesceMs ?? 100;
|
|
40
15
|
}
|
|
41
16
|
get logPrefix() {
|
|
42
17
|
return '[card]';
|
|
@@ -53,6 +28,11 @@ export class RunCardSession extends CardSession {
|
|
|
53
28
|
// enforceCardBudget stringify pass is redundant for run cards.
|
|
54
29
|
return true;
|
|
55
30
|
}
|
|
31
|
+
isFlushableState() {
|
|
32
|
+
// finish() 已转终态(done/error/interrupted/idle_timeout)时不再 patch;
|
|
33
|
+
// 'finalizing' 是非终态,in-flight/延迟 flush 仍可渲染累积事件。
|
|
34
|
+
return this.state.terminal === 'running' || this.state.terminal === 'finalizing';
|
|
35
|
+
}
|
|
56
36
|
async push(event) {
|
|
57
37
|
// state 每事件立即 reduce(始终最新),但 updateCard 延迟到合批窗口末尾。
|
|
58
38
|
// 窗口内多次 push 复用同一 flushTimer,只 render + controller.update 一次
|
|
@@ -70,75 +50,6 @@ export class RunCardSession extends CardSession {
|
|
|
70
50
|
}
|
|
71
51
|
this.scheduleFlush();
|
|
72
52
|
}
|
|
73
|
-
/**
|
|
74
|
-
* 调度一次延迟 flush。已有 pending 调度则复用(合批核心);否则起一个
|
|
75
|
-
* coalesceMs 定时器。flushInFlight 期间不再起 timer(避免重入叠加),但置
|
|
76
|
-
* pendingReschedule 以便 in-flight flush 完成后重新调度——否则 in-flight 期间
|
|
77
|
-
* 到达的 push 会停留为 stale 中间帧(P2-1)。
|
|
78
|
-
*/
|
|
79
|
-
scheduleFlush() {
|
|
80
|
-
if (this.flushTimer)
|
|
81
|
-
return;
|
|
82
|
-
if (this.flushInFlight) {
|
|
83
|
-
this.pendingReschedule = true;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
this.flushTimer = setTimeout(() => {
|
|
87
|
-
this.flushTimer = undefined;
|
|
88
|
-
void this.flush();
|
|
89
|
-
}, this.coalesceMs);
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* 执行一次 render + updateCard。合批窗口到期或 finish 立即 flush 时调用。
|
|
93
|
-
* flushInFlight 防止 timer 回调与 finish 的即时 flush 重入。
|
|
94
|
-
*
|
|
95
|
-
* 终态守卫:若 finish() 已把 state 转为终态(done/error/interrupted/idle_timeout),
|
|
96
|
-
* 跳过本次 patch——避免 in-flight flush 用 pre-terminal state 覆盖 finish 已发的
|
|
97
|
-
* 终态卡。finish() 自身会 await 任何 in-flight flush 保证顺序,此守卫是双保险。
|
|
98
|
-
*/
|
|
99
|
-
async flush() {
|
|
100
|
-
if (this.flushInFlight)
|
|
101
|
-
return;
|
|
102
|
-
// finish() 已转终态:in-flight/延迟 flush 不再用旧 state patch
|
|
103
|
-
if (this.state.terminal !== 'running' && this.state.terminal !== 'finalizing') {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
this.flushInFlight = true;
|
|
107
|
-
const flushPromise = (async () => {
|
|
108
|
-
try {
|
|
109
|
-
await this.updateCard();
|
|
110
|
-
}
|
|
111
|
-
finally {
|
|
112
|
-
this.flushInFlight = false;
|
|
113
|
-
// flushInFlight 守卫保证同一时刻只有一个 in-flight flush,故可无条件清空。
|
|
114
|
-
this.flushP = undefined;
|
|
115
|
-
// P2-1:in-flight 期间若有 push 到达(pendingReschedule),重新调度一次
|
|
116
|
-
// flush 渲染累积事件,避免 stale 中间帧。终态守卫在 flush() 入口已拦截,
|
|
117
|
-
// 故 finish 后不会误触发。
|
|
118
|
-
if (this.pendingReschedule) {
|
|
119
|
-
this.pendingReschedule = false;
|
|
120
|
-
this.scheduleFlush();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
})();
|
|
124
|
-
this.flushP = flushPromise;
|
|
125
|
-
return flushPromise;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态
|
|
129
|
-
* 渲染竞争)。返回是否有被取消的 pending 调度。同时清掉 pendingReschedule,
|
|
130
|
-
* 防止 in-flight flush 的 finally 在 finish await 之后又起 dangling timer
|
|
131
|
-
* (finish 自身会渲染含累积事件的终态卡,无需 follow-up)。
|
|
132
|
-
*/
|
|
133
|
-
cancelPendingFlush() {
|
|
134
|
-
this.pendingReschedule = false;
|
|
135
|
-
if (this.flushTimer) {
|
|
136
|
-
clearTimeout(this.flushTimer);
|
|
137
|
-
this.flushTimer = undefined;
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
53
|
async finish(terminal, meta = {}) {
|
|
143
54
|
// 终态必须即时显示(spec):取消合批窗口,不等延迟 flush 调度。
|
|
144
55
|
this.cancelPendingFlush();
|
|
@@ -152,14 +63,5 @@ export class RunCardSession extends CardSession {
|
|
|
152
63
|
await this.updateCard();
|
|
153
64
|
this.release();
|
|
154
65
|
}
|
|
155
|
-
/**
|
|
156
|
-
* settle 前兜底取消合批调度。bridge 正常流程 finish→settle,finish 已 cancel;
|
|
157
|
-
* 但若未来有直调 settle(未经 finish)的路径,避免 dangling timer 在 release
|
|
158
|
-
* 后触发 void flush() 去更新已释放的 stream(harmless 但无谓)。
|
|
159
|
-
*/
|
|
160
|
-
async settle() {
|
|
161
|
-
this.cancelPendingFlush();
|
|
162
|
-
return super.settle();
|
|
163
|
-
}
|
|
164
66
|
}
|
|
165
67
|
//# sourceMappingURL=run-card-session.js.map
|