lark-remote 0.4.5 → 0.5.0
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 +18 -0
- package/dist/bridge/approval-coordinator.d.ts +1 -1
- package/dist/bridge/approval-coordinator.js +3 -3
- package/dist/bridge/inbound-media.js +10 -7
- package/dist/bridge/index.d.ts +9 -9
- package/dist/bridge/index.js +41 -41
- package/dist/bridge/queue-manager.d.ts +12 -12
- package/dist/bridge/queue-manager.js +19 -19
- package/dist/card/approval-render.d.ts +1 -1
- package/dist/card/approval-render.js +6 -6
- package/dist/card/bash-card-session.d.ts +3 -3
- package/dist/card/bash-card-session.js +3 -3
- package/dist/card/bash-renderer.js +1 -1
- package/dist/card/card-session.d.ts +4 -4
- package/dist/card/card-session.js +6 -6
- package/dist/card/run-card-session.js +2 -2
- package/dist/card/run-renderer.d.ts +1 -1
- package/dist/card/run-renderer.js +14 -14
- package/dist/card/run-state.d.ts +2 -2
- package/dist/card/run-state.js +3 -3
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +6 -6
- package/dist/clone.d.ts +5 -3
- package/dist/clone.js +8 -4
- package/dist/common/truncate.d.ts +1 -1
- package/dist/common/truncate.js +2 -2
- package/dist/common/ttl-cache.d.ts +2 -2
- package/dist/common/ttl-cache.js +2 -2
- package/dist/config/codex-config.d.ts +9 -9
- package/dist/config/codex-config.js +18 -18
- package/dist/config/dir.js +5 -2
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +6 -6
- package/dist/config/opencode-config.js +3 -3
- package/dist/connector/index.d.ts +5 -5
- package/dist/connector/index.js +24 -11
- package/dist/inbound/event.d.ts +1 -1
- package/dist/inbound/event.js +1 -1
- package/dist/inbound/placeholder.d.ts +2 -2
- package/dist/inbound/placeholder.js +2 -2
- package/dist/index.js +9 -9
- package/dist/instance-lock.js +4 -3
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.js +4 -4
- package/dist/persistence/atomic-write.d.ts +1 -1
- package/dist/persistence/atomic-write.js +6 -2
- package/dist/platform/agent-stopper.d.ts +1 -1
- package/dist/platform/identity.d.ts +7 -1
- package/dist/platform/identity.js +2 -2
- package/dist/platform/path.d.ts +6 -0
- package/dist/platform/path.js +14 -8
- package/dist/platform/select.d.ts +1 -1
- package/dist/platform/select.js +1 -1
- package/dist/platform/shell.d.ts +2 -3
- package/dist/platform/spawn.d.ts +2 -2
- package/dist/platform/spawn.js +2 -2
- package/dist/platform/terminator-posix.js +1 -1
- package/dist/platform/terminator-win32.js +2 -2
- package/dist/platform/terminator.d.ts +3 -3
- package/dist/platform/terminator.js +2 -2
- package/dist/platform/types.d.ts +1 -1
- package/dist/restart.d.ts +1 -1
- package/dist/restart.js +5 -3
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +2 -2
- package/dist/router/config/opencode.js +1 -1
- package/dist/router/index.d.ts +9 -9
- package/dist/router/index.js +34 -34
- package/dist/router/order-exec-dispatch.js +2 -2
- package/dist/runner/bash/runner.d.ts +2 -2
- package/dist/runner/bash/runner.js +6 -6
- package/dist/runner/claude/runner.js +1 -1
- package/dist/runner/claude/session.d.ts +2 -2
- package/dist/runner/claude/session.js +14 -14
- package/dist/runner/codex/app-server/runner.js +3 -3
- package/dist/runner/codex/app-server/translator.d.ts +2 -2
- package/dist/runner/codex/app-server/translator.js +5 -5
- package/dist/runner/common/acp/acp-approval.d.ts +2 -2
- package/dist/runner/common/acp/acp-approval.js +3 -3
- package/dist/runner/common/acp/base-acp-runner.js +1 -1
- package/dist/runner/common/acp/base-translator.d.ts +3 -3
- package/dist/runner/common/acp/base-translator.js +4 -4
- package/dist/runner/common/acp/protocol-types.js +1 -1
- package/dist/runner/common/connection-based-runner.d.ts +1 -1
- package/dist/runner/common/connection-based-runner.js +2 -2
- package/dist/runner/common/jsonl-stream.d.ts +2 -2
- package/dist/runner/common/jsonl-stream.js +12 -12
- package/dist/runner/common/jsonrpc/client.d.ts +1 -1
- package/dist/runner/common/jsonrpc/client.js +1 -1
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +1 -1
- 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 +2 -2
- package/dist/runner/common/spawning-runner.d.ts +21 -8
- package/dist/runner/common/spawning-runner.js +41 -15
- package/dist/runner/dsh/runner.js +2 -2
- package/dist/runner/kimi/acp/runner.d.ts +3 -3
- package/dist/runner/kimi/acp/runner.js +9 -9
- package/dist/runner/kimi/acp/translator.d.ts +2 -2
- package/dist/runner/kimi/acp/translator.js +4 -4
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +3 -3
- package/dist/runner/opencode/acp/translator.js +1 -1
- package/dist/runner/pi/rpc/runner.js +2 -2
- package/dist/runner/pi/rpc/translator.d.ts +1 -1
- package/dist/runner/pi/rpc/translator.js +4 -4
- package/dist/runner/types.d.ts +1 -1
- package/dist/session/claude/session-index.d.ts +12 -0
- package/dist/session/claude/session-index.js +20 -5
- package/dist/session/claude/sessions.js +10 -10
- package/dist/session/codex/rollout-reader.d.ts +4 -4
- package/dist/session/codex/rollout-reader.js +12 -12
- package/dist/session/common/two-pass.js +2 -2
- package/dist/session/common/usage-accumulator.d.ts +2 -2
- package/dist/session/common/usage-accumulator.js +2 -2
- package/dist/session/dsh/sessions.js +2 -2
- package/dist/session/kimi/sessions.d.ts +2 -2
- package/dist/session/kimi/sessions.js +11 -11
- package/dist/session/opencode/sessions.d.ts +3 -3
- package/dist/session/opencode/sessions.js +12 -10
- package/dist/session/pi/sessions.js +13 -12
- package/dist/session/session-store.d.ts +1 -1
- package/dist/session/session-store.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2026-10-07
|
|
9
|
+
|
|
10
|
+
### 新增
|
|
11
|
+
|
|
12
|
+
- **CI 增加 Windows 全量验证**:新增 `windows-latest` job(install → typecheck → test → build → `--version`/`--help` 冒烟)。此前只有 ubuntu job,被平台门控跳过的用例在 CI 里是盲区,win32 独有回归只能靠本地发现
|
|
13
|
+
|
|
14
|
+
### 修复
|
|
15
|
+
|
|
16
|
+
- **一次发多图/多文件不再只保存 1 个**:飞书客户端「一次选多图/多文件」会背靠背秒发成多条独立消息,SDK 层 600ms 去抖把它们合并成一条——只保留最后一条的 `messageId`,却把多条消息的附件求并集。下载侧于是拿同一个 `messageId` 去下所有文件,除最后一条外全部报 234003(HTTP 400)。现关掉 SDK 这层合批(`chatQueue` 串行与卡片动作通道保留),合批交回项目自身的合并窗口
|
|
17
|
+
- **Windows 上会话偶尔「消失」**:按工作目录查会话时,大小写/分隔符/尾斜杠的归一不统一,`C:\Work` 与 `c:/work/` 被当成两个目录,`/resume` 列表会漏列。现统一走同一套判等键
|
|
18
|
+
- **Windows 上含 `<>:"|?*` 或尾点的文件名落盘失败**:入站附件名现在会剥掉 win32 非法字符与尾部点/空格(win32 会静默剥离它们,导致落盘名与记录名不一致)
|
|
19
|
+
- **Windows 上可能误杀其他工作目录的 agent**:pid 文件名此前只按消毒后的目录名区分,`/w/a+b` 与 `/w/a_b` 会撞同一个文件,启动时的孤儿回收可能杀掉对方工作目录里存活的 agent。现后缀掺入原始目录的哈希
|
|
20
|
+
- **`~` 开头的配置目录在 Windows 上不展开**:`~\` 形式此前不识别
|
|
21
|
+
|
|
22
|
+
### 变更
|
|
23
|
+
|
|
24
|
+
- **注释与测试命名清理**:去掉源码、测试注释与用例名中指向未发布内部文档的引用(评审条目号、场景号、轮次号、文件名前缀),让公开仓库里的引用都能落地。无行为变化
|
|
25
|
+
|
|
8
26
|
## [0.4.5] - 2026-10-07
|
|
9
27
|
|
|
10
28
|
### 修复
|
|
@@ -95,7 +95,7 @@ export declare class ApprovalCoordinator {
|
|
|
95
95
|
nonce?: string;
|
|
96
96
|
}): Promise<void>;
|
|
97
97
|
/**
|
|
98
|
-
* AskUserQuestion 自定义答案(Other
|
|
98
|
+
* AskUserQuestion 自定义答案(Other):自由文本直接作为该
|
|
99
99
|
* 单选问题的答案。与单选 toggle 同语义:全部问题答完自动提交。
|
|
100
100
|
*/
|
|
101
101
|
answerCustom(action: {
|
|
@@ -180,7 +180,7 @@ export class ApprovalCoordinator {
|
|
|
180
180
|
}
|
|
181
181
|
const selected = new Set(q.selected ?? []);
|
|
182
182
|
if (q.multiSelect) {
|
|
183
|
-
//
|
|
183
|
+
// 多选切换按钮同一 nonce 重复投递(双击/飞书重投递)只应
|
|
184
184
|
// toggle 一次,否则勾选会被二次 toggle 抵消。单选用例的重复防护在
|
|
185
185
|
// respondQuestionAnswers(提交即幂等,选中是 set 语义)。
|
|
186
186
|
this.assertFreshNonce(ctx.requestId, ctx.nonce);
|
|
@@ -226,7 +226,7 @@ export class ApprovalCoordinator {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
/**
|
|
229
|
-
* AskUserQuestion 自定义答案(Other
|
|
229
|
+
* AskUserQuestion 自定义答案(Other):自由文本直接作为该
|
|
230
230
|
* 单选问题的答案。与单选 toggle 同语义:全部问题答完自动提交。
|
|
231
231
|
*/
|
|
232
232
|
async answerCustom(action, ctx) {
|
|
@@ -451,7 +451,7 @@ export class ApprovalCoordinator {
|
|
|
451
451
|
void this.responder(requestId, { action: 'cancel' }).catch((err) => {
|
|
452
452
|
getLogger().warn(`[approval-coordinator] expiry cancel failed requestId=${requestId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
453
453
|
// 响应失败不是「正常过期」:状态升级为 failed,避免误判为已正常通知
|
|
454
|
-
// server(spec
|
|
454
|
+
// server(spec responder 抛错时状态置 failed)。
|
|
455
455
|
tracked.state = 'failed';
|
|
456
456
|
// 兜底:cancel 未能送达时主动中断 turn,避免 server 无限等待审批响应。
|
|
457
457
|
void this.interruptTurn().catch((interruptErr) => {
|
|
@@ -63,7 +63,9 @@ function timestampHms(d) {
|
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* 文件名 sanitize:
|
|
66
|
-
* path.basename 剥离目录(防 `../`
|
|
66
|
+
* path.basename 剥离目录(防 `../` 穿越),再替换控制字符、路径分隔符与
|
|
67
|
+
* win32 非法字符(`<>:"|?*`,NTFS/Win32 API 拒绝,落盘直接 EPERM/EINVAL),
|
|
68
|
+
* 并剥掉尾部的点与空格(win32 会静默剥离它们,导致落盘名 ≠ originalName);
|
|
67
69
|
* 空名 / `.` / `..` 视为无效(返回空串由调用方生成兜底名)。
|
|
68
70
|
*/
|
|
69
71
|
function sanitizeFileName(name) {
|
|
@@ -71,19 +73,20 @@ function sanitizeFileName(name) {
|
|
|
71
73
|
const chars = [];
|
|
72
74
|
for (const ch of base) {
|
|
73
75
|
const code = ch.charCodeAt(0);
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
if (code <= 0x1f || code === 0x7f ||
|
|
76
|
+
// 控制字符、路径分隔符与 win32 非法字符一律替换为下划线(no-control-regex
|
|
77
|
+
// 不允许字面控制字符转义出现在正则里,逐字符判断语义等价且无 lint 冲突)。
|
|
78
|
+
if (code <= 0x1f || code === 0x7f || '/\\<>:"|?*'.includes(ch)) {
|
|
77
79
|
chars.push('_');
|
|
78
80
|
}
|
|
79
81
|
else {
|
|
80
82
|
chars.push(ch);
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
// 尾部的点与空格:win32 落盘时被静默剥离,提前剥掉保证记录名与磁盘名一致
|
|
86
|
+
const trimmedEnd = chars.join('').replace(/[. ]+$/, '');
|
|
87
|
+
if (trimmedEnd === '' || trimmedEnd === '.' || trimmedEnd === '..')
|
|
85
88
|
return '';
|
|
86
|
-
return
|
|
89
|
+
return trimmedEnd;
|
|
87
90
|
}
|
|
88
91
|
/**
|
|
89
92
|
* 资源扩展名(图片/视频/语音):优先 MIME 映射,未知时按魔数兜底;
|
package/dist/bridge/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export interface CommandContext {
|
|
|
36
36
|
/**
|
|
37
37
|
* 本轮(装配窗口)全部入站 messageId,`messageId` 是其中最后一条。
|
|
38
38
|
* 只有走入站装配器的路径会填;卡片动作等单消息路径留空,收尾退化为只处理
|
|
39
|
-
* `messageId`。缺它会导致合并轮次里先到的消息挂着 Typing
|
|
39
|
+
* `messageId`。缺它会导致合并轮次里先到的消息挂着 Typing 不撤。
|
|
40
40
|
*/
|
|
41
41
|
turnMessageIds?: string[];
|
|
42
42
|
}
|
|
@@ -127,7 +127,7 @@ export declare class Bridge {
|
|
|
127
127
|
*/
|
|
128
128
|
private runners;
|
|
129
129
|
/**
|
|
130
|
-
* Runner 槽位在「活跃运行期间配置变更」时被标 stale
|
|
130
|
+
* Runner 槽位在「活跃运行期间配置变更」时被标 stale:clearRunners() 对
|
|
131
131
|
* 活跃 cwd 只标 stale、不立即 evict(避免误杀长驻连接),当前 run 结束后由
|
|
132
132
|
* finalizeRun 安全 evict+dispose,下一轮 getRunner 创建新配置的 runner。
|
|
133
133
|
* key 为 `${cwd}\u0000${agentKind}`。
|
|
@@ -174,17 +174,17 @@ export declare class Bridge {
|
|
|
174
174
|
syncActiveApprovalModes(): void;
|
|
175
175
|
/** Per-agent approval-mode settings snapshot from the current config. */
|
|
176
176
|
private approvalModeSettingsFor;
|
|
177
|
-
/** Get the current runner for a cwd. Used by router for agent-specific commands (
|
|
177
|
+
/** Get the current runner for a cwd. Used by router for agent-specific commands (.2). */
|
|
178
178
|
getCurrentRunner(cwd: string): AgentRunner;
|
|
179
179
|
/**
|
|
180
180
|
* Whether the runner for the given agent kind has runCompact capability.
|
|
181
|
-
* Used by router for compact button gating (
|
|
181
|
+
* Used by router for compact button gating (duck-typing
|
|
182
182
|
* instead of hardcoding agentKind === 'codex').
|
|
183
183
|
*/
|
|
184
184
|
hasRunCompact(cwd: string, kind?: AgentKind): boolean;
|
|
185
185
|
/** 入队时刻快照:当前 defaultAgent + 该 agent 的 sessionId(无 session 则 undefined)。
|
|
186
|
-
*
|
|
187
|
-
* 执行时刻,避免 /new、/config 在排队期间改写 live
|
|
186
|
+
* 唯一捕获点:排队消息在入队时刻把 agent+session 钉进 AgentBinding,随任务闭包带到执行时刻
|
|
187
|
+
* 执行时刻,避免 /new、/config 在排队期间改写 live 状态导致语义漂移。 */
|
|
188
188
|
currentBinding(userId: string): AgentBinding;
|
|
189
189
|
/**
|
|
190
190
|
* Clear all cached runner instances. Call after config changes that affect runner config.
|
|
@@ -192,7 +192,7 @@ export declare class Bridge {
|
|
|
192
192
|
clearRunners(): void;
|
|
193
193
|
/**
|
|
194
194
|
* Evict a (cwd, agentKind) runner cache slot. Unregisters the runner from the
|
|
195
|
-
* process-level exit dispatcher first (
|
|
195
|
+
* process-level exit dispatcher first (without removal the singleton
|
|
196
196
|
* Set<Runner> retains every historical runner instance, so memory still grows
|
|
197
197
|
* with run count), then deletes the slot. Every runner-discarding path
|
|
198
198
|
* (clearRunners / finalizeRun / interruptCurrentRun) must go through this.
|
|
@@ -354,7 +354,7 @@ export declare class Bridge {
|
|
|
354
354
|
*/
|
|
355
355
|
private createRunSession;
|
|
356
356
|
/**
|
|
357
|
-
* §9.12 空闲看门狗:单 interval +
|
|
357
|
+
* §9.12 空闲看门狗:单 interval + 截止时间判定,普通 run 与 compact
|
|
358
358
|
* 共用同一套兜底。事件到达只 `touch()` 刷新时间戳(无 timer 操作);静默超过
|
|
359
359
|
* `idleTimeoutMs` 才 finish('idle_timeout') + runner.stop(),让该工作区的串行
|
|
360
360
|
* 队列继续推进(否则一个挂死的 run 永久堵住后续消息)。
|
|
@@ -443,7 +443,7 @@ export declare class Bridge {
|
|
|
443
443
|
nonce: string;
|
|
444
444
|
}): Promise<void>;
|
|
445
445
|
/**
|
|
446
|
-
* Claude AskUserQuestion 自定义答案(Other
|
|
446
|
+
* Claude AskUserQuestion 自定义答案(Other):自由文本直接
|
|
447
447
|
* 作为该单选问题的答案提交。路由到 ApprovalCoordinator.answerCustom。
|
|
448
448
|
*/
|
|
449
449
|
handleApprovalAnswerCustom(opts: {
|
package/dist/bridge/index.js
CHANGED
|
@@ -18,13 +18,13 @@ import { InboundMediaHandler } from './inbound-media.js';
|
|
|
18
18
|
* Max events to read for the completion notification card (mirror router's
|
|
19
19
|
* AUTO_RESUME_MAX_EVENTS = 5). Without a cap, readSessionContent returns every
|
|
20
20
|
* event after the last user message and the card blows past Feishu's 28KB
|
|
21
|
-
* budget
|
|
21
|
+
* budget.
|
|
22
22
|
*/
|
|
23
23
|
const COMPLETION_NOTIFICATION_MAX_EVENTS = 5;
|
|
24
24
|
/** Approval request timeout (ms) — pending approval expires after this. */
|
|
25
25
|
const APPROVAL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
26
26
|
/**
|
|
27
|
-
* runner
|
|
27
|
+
* runner 缓存的工作区数量上限:超过后创建新工作区槽位时
|
|
28
28
|
* 顺带回收「非 active 且进程已停」的死缓存,防止随访问过的工作区数量
|
|
29
29
|
* 无界增长。活进程/在途 run 一律保留(workspace-lifetime 长驻连接不能误杀)。
|
|
30
30
|
*/
|
|
@@ -50,8 +50,8 @@ function terminalReactionEmoji(terminal) {
|
|
|
50
50
|
return TERMINAL_REACTION_EMOJI[terminal] ?? 'Done';
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* 单点化:`'runCompact' in runner` 鸭子探测
|
|
54
|
+
* codex app-server + kimi/opencode ACP runner 满足。
|
|
55
55
|
*/
|
|
56
56
|
function runnerHasRunCompact(runner) {
|
|
57
57
|
return ('runCompact' in runner && typeof runner.runCompact === 'function');
|
|
@@ -98,7 +98,7 @@ export class Bridge {
|
|
|
98
98
|
*/
|
|
99
99
|
runners = new Map();
|
|
100
100
|
/**
|
|
101
|
-
* Runner 槽位在「活跃运行期间配置变更」时被标 stale
|
|
101
|
+
* Runner 槽位在「活跃运行期间配置变更」时被标 stale:clearRunners() 对
|
|
102
102
|
* 活跃 cwd 只标 stale、不立即 evict(避免误杀长驻连接),当前 run 结束后由
|
|
103
103
|
* finalizeRun 安全 evict+dispose,下一轮 getRunner 创建新配置的 runner。
|
|
104
104
|
* key 为 `${cwd}\u0000${agentKind}`。
|
|
@@ -150,7 +150,7 @@ export class Bridge {
|
|
|
150
150
|
if (workspaceMap?.has(kind)) {
|
|
151
151
|
return workspaceMap.get(kind);
|
|
152
152
|
}
|
|
153
|
-
//
|
|
153
|
+
// 缓存超过上限且是新工作区时才回收死槽位——刚创建未 run
|
|
154
154
|
// 的 runner 同样是 isRunning=false,小缓存下立即回收会破坏「创建即注册」
|
|
155
155
|
// 的既有语义(exit-dispatcher 计数回归)。
|
|
156
156
|
if (this.runners.size >= MAX_CACHED_RUNNER_WORKSPACES && !this.runners.has(cwd)) {
|
|
@@ -241,13 +241,13 @@ export class Bridge {
|
|
|
241
241
|
return undefined;
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
-
/** Get the current runner for a cwd. Used by router for agent-specific commands (
|
|
244
|
+
/** Get the current runner for a cwd. Used by router for agent-specific commands (.2). */
|
|
245
245
|
getCurrentRunner(cwd) {
|
|
246
246
|
return this.getRunner(cwd);
|
|
247
247
|
}
|
|
248
248
|
/**
|
|
249
249
|
* Whether the runner for the given agent kind has runCompact capability.
|
|
250
|
-
* Used by router for compact button gating (
|
|
250
|
+
* Used by router for compact button gating (duck-typing
|
|
251
251
|
* instead of hardcoding agentKind === 'codex').
|
|
252
252
|
*/
|
|
253
253
|
hasRunCompact(cwd, kind = this.config.defaultAgent) {
|
|
@@ -255,8 +255,8 @@ export class Bridge {
|
|
|
255
255
|
return runnerHasRunCompact(runner);
|
|
256
256
|
}
|
|
257
257
|
/** 入队时刻快照:当前 defaultAgent + 该 agent 的 sessionId(无 session 则 undefined)。
|
|
258
|
-
*
|
|
259
|
-
* 执行时刻,避免 /new、/config 在排队期间改写 live
|
|
258
|
+
* 唯一捕获点:排队消息在入队时刻把 agent+session 钉进 AgentBinding,随任务闭包带到执行时刻
|
|
259
|
+
* 执行时刻,避免 /new、/config 在排队期间改写 live 状态导致语义漂移。 */
|
|
260
260
|
currentBinding(userId) {
|
|
261
261
|
const agent = this.config.defaultAgent;
|
|
262
262
|
return {
|
|
@@ -278,7 +278,7 @@ export class Bridge {
|
|
|
278
278
|
// ends, and the next run picks up the new config/agent via getRunner.
|
|
279
279
|
for (const cwd of [...this.runners.keys()]) {
|
|
280
280
|
if (this.activeRuns.has(cwd)) {
|
|
281
|
-
//
|
|
281
|
+
// 活跃 cwd 不能立即 evict(会误杀长驻连接),但必须标记 stale,
|
|
282
282
|
// 否则 finalizeRun 对 workspace-lifetime runner 也不 evict → 下一轮复用旧配置实例。
|
|
283
283
|
// 这里只标待淘汰,当前 run 结束后由 finalizeRun 安全 evict。
|
|
284
284
|
for (const kind of [...this.runners.get(cwd).keys()]) {
|
|
@@ -294,7 +294,7 @@ export class Bridge {
|
|
|
294
294
|
}
|
|
295
295
|
/**
|
|
296
296
|
* Evict a (cwd, agentKind) runner cache slot. Unregisters the runner from the
|
|
297
|
-
* process-level exit dispatcher first (
|
|
297
|
+
* process-level exit dispatcher first (without removal the singleton
|
|
298
298
|
* Set<Runner> retains every historical runner instance, so memory still grows
|
|
299
299
|
* with run count), then deletes the slot. Every runner-discarding path
|
|
300
300
|
* (clearRunners / finalizeRun / interruptCurrentRun) must go through this.
|
|
@@ -535,7 +535,7 @@ export class Bridge {
|
|
|
535
535
|
// below may outlive the task's settle, letting the serial chain advance
|
|
536
536
|
// to a successor that begins executing before we resume. An
|
|
537
537
|
// unconditional reset would then zero the successor's count and mark
|
|
538
|
-
// its slot interrupted, hiding it from queue cards
|
|
538
|
+
// its slot interrupted, hiding it from queue cards.
|
|
539
539
|
const stoppedSlot = this.queueManager.getExecutingSlot(cwd);
|
|
540
540
|
await Promise.allSettled([
|
|
541
541
|
// 用户主动中断(/stop、stop 卡按钮、queue.immediate)显式打标
|
|
@@ -551,8 +551,8 @@ export class Bridge {
|
|
|
551
551
|
this.activeRuns.delete(cwd);
|
|
552
552
|
}
|
|
553
553
|
// Fix 4: Clean up this specific (cwd, agentKind) runner slot
|
|
554
|
-
// (
|
|
555
|
-
//
|
|
554
|
+
// (eviction must also unregister the runner from the exit dispatcher)
|
|
555
|
+
// evict by the run's captured agentKind, not the live
|
|
556
556
|
// defaultAgent (may have changed mid-run via /config).
|
|
557
557
|
this.evictRunnerSlot(cwd, active.agentKind);
|
|
558
558
|
// Reset queue executing count: the task was interrupted externally, so
|
|
@@ -709,9 +709,9 @@ export class Bridge {
|
|
|
709
709
|
* updates the same run card, and terminal events finalize that card.
|
|
710
710
|
*/
|
|
711
711
|
async forwardToClaude(message, ctx, opts) {
|
|
712
|
-
//
|
|
712
|
+
// agentKind 一律来自绑定。无 binding 时保持现状(live defaultAgent)。
|
|
713
713
|
const agentKind = opts?.binding?.agent ?? this.config.defaultAgent;
|
|
714
|
-
//
|
|
714
|
+
// lane 与执行 cwd 同源。消息入队时(index.ts 闭包)捕获的 cwd
|
|
715
715
|
// 作为 cwdOverride 显式传入;执行时若 sessionStore cwd 已被 /cd 等命令改写,
|
|
716
716
|
// 以 lane 为准 —— 否则旧 lane 的排队消息会被 busy-drop 静默丢失。空串视为
|
|
717
717
|
// 未提供(与入队前无 cwd 的兜底语义一致)。
|
|
@@ -732,12 +732,12 @@ export class Bridge {
|
|
|
732
732
|
}
|
|
733
733
|
// Note: Multiple workspaces can have runs in parallel. If runner is busy,
|
|
734
734
|
// runner.run() will throw and we'll catch it below.
|
|
735
|
-
//
|
|
735
|
+
// sessionId 钉死语义——binding 有 sessionId 时用它(入队时刻快照),
|
|
736
736
|
// 否则跟随 live store(无 binding 或入队时无 session 的正常路径)。
|
|
737
737
|
const sessionId = opts?.binding?.sessionId ?? this.sessionStore.getSessionId(ctx.userId, agentKind);
|
|
738
738
|
// 会话代际快照(2026-08-09,2026-10-07 前移):/new、/cd、/resume 会 bump
|
|
739
739
|
// epoch,该 run 后续 system.init 的 sessionId 写回即判 stale 跳过。
|
|
740
|
-
// 快照点优先取 binding.sessionEpoch(入队/commit
|
|
740
|
+
// 快照点优先取 binding.sessionEpoch(入队/commit 时刻,与 sessionId 同刻):
|
|
741
741
|
// 排队消息在「commit 后、开跑前」被 reset 时,执行起点捕获会漏判(epoch 已是
|
|
742
742
|
// bump 后的值)→ 旧 sessionId 被写回复活 reset。无 binding 时回退执行起点捕获,
|
|
743
743
|
// 保持非排队路径(如 /compact)的既有语义。
|
|
@@ -761,8 +761,8 @@ export class Bridge {
|
|
|
761
761
|
createRunSession(ctx, cwd, runner, agentKind = this.config.defaultAgent) {
|
|
762
762
|
const runId = randomUUID();
|
|
763
763
|
getLogger().debug(`[lark-remote] creating runCard runId=${runId}`);
|
|
764
|
-
//
|
|
765
|
-
// 缓存键 (cwd, agentKind) 和 eviction
|
|
764
|
+
// agentKind 来自入队绑定(forwardToClaude 解析),不再读 live config。
|
|
765
|
+
// 缓存键 (cwd, agentKind) 和 eviction 都用这个值。
|
|
766
766
|
const cardSession = new RunCardSession({
|
|
767
767
|
connector: this.connector,
|
|
768
768
|
chatId: ctx.chatId,
|
|
@@ -790,7 +790,7 @@ export class Bridge {
|
|
|
790
790
|
return { runId, cardSession, activeRun };
|
|
791
791
|
}
|
|
792
792
|
/**
|
|
793
|
-
* §9.12 空闲看门狗:单 interval +
|
|
793
|
+
* §9.12 空闲看门狗:单 interval + 截止时间判定,普通 run 与 compact
|
|
794
794
|
* 共用同一套兜底。事件到达只 `touch()` 刷新时间戳(无 timer 操作);静默超过
|
|
795
795
|
* `idleTimeoutMs` 才 finish('idle_timeout') + runner.stop(),让该工作区的串行
|
|
796
796
|
* 队列继续推进(否则一个挂死的 run 永久堵住后续消息)。
|
|
@@ -839,7 +839,7 @@ export class Bridge {
|
|
|
839
839
|
* Handles idle watchdog, event processing, session sync, and state transitions.
|
|
840
840
|
*/
|
|
841
841
|
async runAgentStreamToEnd(runner, cardSession, sessionId, sessionEpochAtStart, ctx, cwd, runId, message, agentKind = this.config.defaultAgent) {
|
|
842
|
-
// Runner 声明的 usage
|
|
842
|
+
// Runner 声明的 usage 权威来源:codex app-server = 'live'
|
|
843
843
|
// (turn/started 的 tokenUsage.last 是本 turn 增量)。其余 runner 未声明。
|
|
844
844
|
const usageAuthority = runner.getUsageAuthority?.();
|
|
845
845
|
// §9.12 空闲看门狗:判定口径见 startIdleWatchdog;武装点在 cardSession.start() 之后。
|
|
@@ -914,7 +914,7 @@ export class Bridge {
|
|
|
914
914
|
// Card session did not enter running state - still try to send static fallback
|
|
915
915
|
getLogger().info(`[lark-remote] cardSession not running, using static fallback`);
|
|
916
916
|
}
|
|
917
|
-
//
|
|
917
|
+
// 单 interval 看门狗。事件到来时只刷新时间戳(无 timer 操作);
|
|
918
918
|
// interval 周期检查静默时长,超时才 finish('idle_timeout') + stop()。
|
|
919
919
|
// 武装点在建卡之后,与原实现一致(宽限期不含 cardSession.start() 耗时)。
|
|
920
920
|
watchdog = this.startIdleWatchdog({
|
|
@@ -955,8 +955,8 @@ export class Bridge {
|
|
|
955
955
|
getLogger().info(`[lark-remote] system.init write-back skipped: session pointer moved since run start runId=${runId} sessionId=${event.session_id}`);
|
|
956
956
|
}
|
|
957
957
|
else {
|
|
958
|
-
//
|
|
959
|
-
//
|
|
958
|
+
// Use session's real directory from event.cwd (not runner's cwd parameter)
|
|
959
|
+
// guard empty string too -- `??` only catches null/undefined, but a
|
|
960
960
|
// translator (or older build) may emit cwd="", which must NOT overwrite
|
|
961
961
|
// the good runner cwd.
|
|
962
962
|
const hasCwd = !!this.sessionStore.getCwd(ctx.userId);
|
|
@@ -1028,7 +1028,7 @@ export class Bridge {
|
|
|
1028
1028
|
: `[lark-remote] result event received runId=${runId}`);
|
|
1029
1029
|
// app-server 模式 setup 失败路径(thread/start 成功后 turn/start 失败)
|
|
1030
1030
|
// 不会有 turn_started 事件,store 不会写回新线程 id;runner 已在 result
|
|
1031
|
-
//
|
|
1031
|
+
// 里兜底上报。此处仅当 runner 声明 live usage(app-server)
|
|
1032
1032
|
// 且会话指针未动时写回,避免下条消息再开一个孤儿线程。其余 agent 不在
|
|
1033
1033
|
// 此列(它们各自有 system.init / turn_started 写回)。
|
|
1034
1034
|
if (usageAuthority === 'live' &&
|
|
@@ -1121,7 +1121,7 @@ export class Bridge {
|
|
|
1121
1121
|
const coordinator = this.approvalCoordinators.get(runId);
|
|
1122
1122
|
coordinator?.updateView(event.requestId, event.view);
|
|
1123
1123
|
}
|
|
1124
|
-
// §9.12
|
|
1124
|
+
// §9.12 红线:每个事件(含 result)无条件刷新
|
|
1125
1125
|
// lastEventTs 重新武装看门狗。result 后 CLI 进程做 jsonl flush/清理(finalizing
|
|
1126
1126
|
// 过渡)期间,宽限期恢复为完整的 idleTimeoutMs,避免已产出结果的 turn 被误标
|
|
1127
1127
|
// idle_timeout。旧实现 `else { resetIdle(); }` 漏掉 result 分支。
|
|
@@ -1129,9 +1129,9 @@ export class Bridge {
|
|
|
1129
1129
|
await cardSession.push(event);
|
|
1130
1130
|
}
|
|
1131
1131
|
getLogger().info(`[lark-remote] runner stream end runId=${runId} sawResult=${sawResult}`);
|
|
1132
|
-
// §9.12
|
|
1132
|
+
// §9.12 红线:for-await 自然结束 = CLI 已退出,
|
|
1133
1133
|
// 看门狗使命结束,立即摘除 interval(不再等 finally),堵掉「stream 已结束、
|
|
1134
|
-
// 收尾处理跨过死线被误标 idle_timeout
|
|
1134
|
+
// 收尾处理跨过死线被误标 idle_timeout」的同源小窗口(随本修复一并关闭)。
|
|
1135
1135
|
watchdog?.stop();
|
|
1136
1136
|
// stream 结束 = CLI 退出 = jsonl 已落盘。读 jsonl 拿准确的 contextLength + compactCount:
|
|
1137
1137
|
// live stream-json 不发 compact_boundary,live contextLength 会被 result 的 input+output 兜底失真。
|
|
@@ -1210,7 +1210,7 @@ export class Bridge {
|
|
|
1210
1210
|
}
|
|
1211
1211
|
catch (err) {
|
|
1212
1212
|
getLogger().error(`[lark-remote] claude run error runId=${runId}:`, err);
|
|
1213
|
-
//
|
|
1213
|
+
// 双保险:run() 的 finally 已负责杀子进程,但 catch 路径再补一次
|
|
1214
1214
|
// runner.stop()(与 bash 路径对齐),覆盖任何 finally 之外的残留窗口。
|
|
1215
1215
|
try {
|
|
1216
1216
|
await runner.stop();
|
|
@@ -1299,7 +1299,7 @@ export class Bridge {
|
|
|
1299
1299
|
this.finishTurnReactions(ctx, terminalReactionEmoji(cardSession.currentState.terminal));
|
|
1300
1300
|
}
|
|
1301
1301
|
finally {
|
|
1302
|
-
//
|
|
1302
|
+
// cleanup must survive mid-finalize errors. The only unguarded
|
|
1303
1303
|
// expression in finalizeRun is the renderRunCard(...) argument evaluated
|
|
1304
1304
|
// at the sendResult call site; if it throws, the run must still release
|
|
1305
1305
|
// its activeRuns slot — otherwise the cwd is permanently busy
|
|
@@ -1312,7 +1312,7 @@ export class Bridge {
|
|
|
1312
1312
|
// evicted+disposed by clearRunners (/config) and interruptCurrentRun
|
|
1313
1313
|
// (/stop). Spawn-per-message runners are evicted as before to prevent
|
|
1314
1314
|
// stale process references accumulating.
|
|
1315
|
-
//
|
|
1315
|
+
// 配置变更期间(clearRunners 标了 stale)的 workspace-lifetime
|
|
1316
1316
|
// runner 也必须在 run 结束后 evict,否则下一轮复用旧配置实例。
|
|
1317
1317
|
const slotKey = `${cwd}\u0000${activeRun.agentKind}`;
|
|
1318
1318
|
if (activeRun.runner.lifetime !== 'workspace' || this.staleRunnerSlots.has(slotKey)) {
|
|
@@ -1322,7 +1322,7 @@ export class Bridge {
|
|
|
1322
1322
|
// Compact 卡片需要 runId + sessionId;record 供终态卡上的 Compact 按钮
|
|
1323
1323
|
// 校验与取参(activeRuns 已清空,无法再查到)。异常退出(error/
|
|
1324
1324
|
// interrupted/idle_timeout)同样记录——上下文往往更大,压缩后再续。
|
|
1325
|
-
//
|
|
1325
|
+
// 写入条件从「codex 终态」放宽为「runner 有 runCompact 的终态」
|
|
1326
1326
|
// (codex app-server + kimi acp 均满足)。
|
|
1327
1327
|
const runTerminal = cardSession.currentState.terminal;
|
|
1328
1328
|
const runnerHasCompact = runnerHasRunCompact(activeRun.runner);
|
|
@@ -1354,7 +1354,7 @@ export class Bridge {
|
|
|
1354
1354
|
*/
|
|
1355
1355
|
async sendCompletionNotificationCard(sessionId, cwd, ctx, agentKind = this.config.defaultAgent) {
|
|
1356
1356
|
try {
|
|
1357
|
-
//
|
|
1357
|
+
// cap the events read for the notification card — without
|
|
1358
1358
|
// maxEvents claude returns every event after the last user message and
|
|
1359
1359
|
// the card blows past Feishu's 28KB budget.
|
|
1360
1360
|
const content = this.sessionReaderRegistry.get(agentKind).readSessionContent(sessionId, cwd, {
|
|
@@ -1374,7 +1374,7 @@ export class Bridge {
|
|
|
1374
1374
|
actions: [resumeUseButton(sessionId, agentKind)],
|
|
1375
1375
|
headerTemplate: 'green',
|
|
1376
1376
|
});
|
|
1377
|
-
//
|
|
1377
|
+
// send through sendResult so enforceCardBudget guards the card
|
|
1378
1378
|
// (previously sent via connector directly, bypassing the budget — long
|
|
1379
1379
|
// sessions produced >28KB cards that Feishu silently rejected).
|
|
1380
1380
|
const sent = await this.sendResult({ card }, ctx);
|
|
@@ -1399,7 +1399,7 @@ export class Bridge {
|
|
|
1399
1399
|
withCoordinator(runId, fn) {
|
|
1400
1400
|
const coordinator = this.approvalCoordinators.get(runId);
|
|
1401
1401
|
if (!coordinator) {
|
|
1402
|
-
//
|
|
1402
|
+
// run 已结束(coordinator 已释放)时点击审批按钮必须给用户明确反馈,
|
|
1403
1403
|
// 不能静默。router 会把该异常转成 error toast。
|
|
1404
1404
|
getLogger().warn(`[lark-remote] no approval coordinator for runId=${runId.slice(0, 8)}`);
|
|
1405
1405
|
throw new Error('任务已结束,审批无法响应');
|
|
@@ -1463,7 +1463,7 @@ export class Bridge {
|
|
|
1463
1463
|
return this.withCoordinator(opts.runId, (coordinator) => coordinator.submitAnswers({ questionIndex: opts.questionIndex }, { requestId: opts.requestId, nonce: opts.nonce }));
|
|
1464
1464
|
}
|
|
1465
1465
|
/**
|
|
1466
|
-
* Claude AskUserQuestion 自定义答案(Other
|
|
1466
|
+
* Claude AskUserQuestion 自定义答案(Other):自由文本直接
|
|
1467
1467
|
* 作为该单选问题的答案提交。路由到 ApprovalCoordinator.answerCustom。
|
|
1468
1468
|
*/
|
|
1469
1469
|
async handleApprovalAnswerCustom(opts) {
|
|
@@ -1599,7 +1599,7 @@ export class Bridge {
|
|
|
1599
1599
|
agentKind,
|
|
1600
1600
|
},
|
|
1601
1601
|
});
|
|
1602
|
-
//
|
|
1602
|
+
// 压缩与普通 run 共用同一套生命周期——注册进 activeRuns(/stop 有对象可停、
|
|
1603
1603
|
// /active 看得见)、挂 §9.12 空闲看门狗、终态后补 reaction。缺任何一环,卡住的
|
|
1604
1604
|
// 压缩都只能等 runner 级超时,用户既停不掉也看不出它还在跑。
|
|
1605
1605
|
const activeRun = {
|
|
@@ -1845,7 +1845,7 @@ export class Bridge {
|
|
|
1845
1845
|
}
|
|
1846
1846
|
for await (const event of bashRunner.run(command, { cwd })) {
|
|
1847
1847
|
if (event.type === 'stdout') {
|
|
1848
|
-
//
|
|
1848
|
+
// 层④:bridge 本地 output 也必须 store-time 截断——仅 session state
|
|
1849
1849
|
// 有界并不会让 `output +=` 自然有界(review 第④条表述不成立),!yes 洪峰
|
|
1850
1850
|
// 下本地字符串仍全量驻留。capBashOutput 增量调用 O(CAP+chunk),不会带回
|
|
1851
1851
|
// O(n²) 截断成本(output 恒 ≤ CAP,拼接后 ≤ CAP+chunk 再 slice 尾部)。
|
|
@@ -1884,7 +1884,7 @@ export class Bridge {
|
|
|
1884
1884
|
const settleResult = await cardSession.settle();
|
|
1885
1885
|
if (settleResult === 'unsent') {
|
|
1886
1886
|
// Stream never established a card — send a static terminal card as fallback.
|
|
1887
|
-
// Use 2.0 schema to match the streaming card (
|
|
1887
|
+
// Use 2.0 schema to match the streaming card (avoid 2.0→1.x downgrade).
|
|
1888
1888
|
try {
|
|
1889
1889
|
await this.connector.sendWithRetry(ctx.chatId, { card: renderBashCard(cardSession.currentState, {}) }, { replyTo: ctx.messageId });
|
|
1890
1890
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentKind } from '../runner/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* 入队时刻快照:当前 defaultAgent + 该 agent 的 sessionId(无 session 则 undefined)。
|
|
4
|
-
*
|
|
5
|
-
* 执行时刻,避免 /new、/config 在排队期间改写 live
|
|
4
|
+
* 唯一捕获点:排队消息在入队时刻把 agent+session 钉进 AgentBinding,随任务闭包带到执行时刻
|
|
5
|
+
* 执行时刻,避免 /new、/config 在排队期间改写 live 状态导致语义漂移。
|
|
6
6
|
*/
|
|
7
7
|
export interface AgentBinding {
|
|
8
8
|
agent: AgentKind;
|
|
@@ -51,7 +51,7 @@ export interface QueuedTask {
|
|
|
51
51
|
* `handleQueueImmediate`).
|
|
52
52
|
*/
|
|
53
53
|
editedMessage?: string;
|
|
54
|
-
/** 入队时刻捕获的 agent+session
|
|
54
|
+
/** 入队时刻捕获的 agent+session 绑定,随任务闭包带到执行时刻。 */
|
|
55
55
|
binding?: AgentBinding;
|
|
56
56
|
}
|
|
57
57
|
/** Options for enqueue operation */
|
|
@@ -70,7 +70,7 @@ export interface EnqueueOptions {
|
|
|
70
70
|
feishuReplyTo?: string;
|
|
71
71
|
/** Whether the queued task is editable (queue card ✏️ 编辑 button). Defaults to true. */
|
|
72
72
|
editable?: boolean;
|
|
73
|
-
/** 入队时刻捕获的 agent+session
|
|
73
|
+
/** 入队时刻捕获的 agent+session 绑定。 */
|
|
74
74
|
binding?: AgentBinding;
|
|
75
75
|
};
|
|
76
76
|
}
|
|
@@ -90,7 +90,7 @@ export declare class QueueManager {
|
|
|
90
90
|
/** Per-workspace queued tasks for queue display cards. Key = cwd, value = task list. */
|
|
91
91
|
private queuedTasks;
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
93
|
+
* per-workspace `messageId → QueuedTask` index mirroring `queuedTasks`.
|
|
94
94
|
* O(1) lookup for the task-start removal path (replacing the old double
|
|
95
95
|
* `find`+`findIndex` O(N) scan) and for `getQueuedTask`/`removeFromQueue`/
|
|
96
96
|
* `updateQueuedTaskMessage`. The ordered array remains the source of truth
|
|
@@ -117,7 +117,7 @@ export declare class QueueManager {
|
|
|
117
117
|
* identifies one task's execution period for the interrupt bookkeeping in
|
|
118
118
|
* `executingSlot`/`interruptedSlots` — replacing the unowned skip-credit
|
|
119
119
|
* counter, which any settle could consume and which therefore leaked a
|
|
120
|
-
* re-armed count after repeated resets
|
|
120
|
+
* re-armed count after repeated resets.
|
|
121
121
|
*/
|
|
122
122
|
private slotCounter;
|
|
123
123
|
/**
|
|
@@ -141,7 +141,7 @@ export declare class QueueManager {
|
|
|
141
141
|
/**
|
|
142
142
|
* MessageIds of tasks that have actually begun executing (cancellation check
|
|
143
143
|
* passed, task removed from the queue). Entries are sticky: they remain
|
|
144
|
-
* after the task settles
|
|
144
|
+
* after the task settles. `handleQueueImmediate` step 6 uses this to
|
|
145
145
|
* distinguish "target was cancelled (never began)" from "target began while
|
|
146
146
|
* the interrupt was in flight" so the final feedback can report the true
|
|
147
147
|
* state instead of telling a running task's user that nothing was
|
|
@@ -162,11 +162,11 @@ export declare class QueueManager {
|
|
|
162
162
|
constructor(isWorkspaceRunning: (cwd: string) => boolean, sendCard: (chatId: string, card: object, opts?: {
|
|
163
163
|
replyTo?: string;
|
|
164
164
|
}) => Promise<string>, updateCard: (messageId: string, card: object) => Promise<void>);
|
|
165
|
-
/**
|
|
165
|
+
/** register a queued task in the per-workspace `messageId → task` index. */
|
|
166
166
|
private indexAdd;
|
|
167
|
-
/**
|
|
167
|
+
/** drop a task from the per-workspace index by messageId. */
|
|
168
168
|
private indexRemove;
|
|
169
|
-
/**
|
|
169
|
+
/** O(1) lookup of a queued task by messageId via the index. */
|
|
170
170
|
private indexGet;
|
|
171
171
|
/**
|
|
172
172
|
* Enqueue a task into the workspace-level serial queue.
|
|
@@ -198,7 +198,7 @@ export declare class QueueManager {
|
|
|
198
198
|
* state — pending cards enable both, executing/cancelled cards disable
|
|
199
199
|
* both. Centralizing the pair here eliminates the 3-way duplication
|
|
200
200
|
* between `buildQueueStatusCardElements`, `updateQueueCardToExecuting`,
|
|
201
|
-
* and `updateQueueCardToCancelled` (Clean Code
|
|
201
|
+
* and `updateQueueCardToCancelled` (Clean Code).
|
|
202
202
|
*/
|
|
203
203
|
private buildQueueActionButtons;
|
|
204
204
|
/**
|
|
@@ -283,7 +283,7 @@ export declare class QueueManager {
|
|
|
283
283
|
* slot no longer matches the interrupted task's slot, the interrupted task
|
|
284
284
|
* already decremented normally — resetting now would zero the count of the
|
|
285
285
|
* running successor and mark ITS slot interrupted, hiding it from the
|
|
286
|
-
* queue card
|
|
286
|
+
* queue card.
|
|
287
287
|
*/
|
|
288
288
|
resetExecutingCount(cwd: string, expectedSlot: number): void;
|
|
289
289
|
/**
|