lark-remote 0.5.8 → 0.5.10

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 CHANGED
@@ -5,12 +5,42 @@ 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.10] - 2026-10-24
9
+
10
+ ### 修复
11
+
12
+ - **点「立即执行」后,run 卡片不再抢在最终 toast 前面**:立即执行的 run 起始会等当前排队卡完成交接再建卡。否则 toast 会成为点击后最后一条新消息,聊天列表预览停在 toast 文案上,而 run 卡片后续的「思考中 / 工具 / 完成」变化不点进会话就看不到
13
+ - **长时间运行不再被过期的空闲定时器误杀**:工作区连接自行退出(如 codex app-server 偶发 exit 0)后,挂在旧连接上的空闲回收定时器此前不会被取消,约 30 分钟后会按工作目录回收后来接替的新连接,正在跑的回合被杀、卡片误报「连接已关闭」。现在定时器只回收自己武装时那个连接,进程自退时同时撤掉定时器,继任连接自己的空闲回收仍然照常生效
14
+
15
+ ### 变更
16
+
17
+ - **英文架构文档补齐排队卡叙述**:立即执行时的 run 起始闸门与 toast 排序,中英两侧一致
18
+
19
+ ## [0.5.9] - 2026-10-22
20
+
21
+ ### 新增
22
+
23
+ - **运行卡片看得出长期目标跑到哪了**:DSH 会话可以带一个跨回合自动续跑的目标(objective / phase / 轮次)。此前卡片只看单个回合,目标还在续跑时你从卡上看不出来。现在状态行下方直接显示 `🎯 目标进行中 · 第 r/N 轮` 与目标摘要,长目标收进折叠面板并保留全文,回合开始就能看见而不是等收尾;摘要与轮次来自宿主投影,卡片不自行推断
24
+ - **`goal_continuing` 终态**:本轮结束但目标仍 active 时,卡片标题写「本轮结束(目标继续)」,摘要首行同调,并附一句「宿主会自动开始第 r+1 轮」。它与「已完成」是两件事:任务还在跑
25
+
26
+ ### 修复
27
+
28
+ - **本轮结束不再被当成任务完成**:目标仍 active 时宿主会立刻起下一轮,会话永远不空闲。旧实现按回合收尾,卡片写着「已完成」而任务还在跑,你随后点压缩会被服务端拒。现在终态与按钮都以目标为准,这类卡片不给压缩按钮
29
+ - **中断后的卡片上压缩按钮不再是死按钮**:可压缩记录改在运行收尾的 `finally` 里写,且在「这个工作区的槽位还归不归本轮」守卫之外。停止(`/stop`、卡片上的停止按钮、抢占式立即执行)都会先摘掉槽位,等收尾走到守卫时已经不成立——记录跟着守卫走就永远不落,中断后的终态卡点压缩一律回「该任务已结束或不属于当前会话」。渲染侧共用同一判据:本轮没有会话、开跑前也没有会话时不渲染按钮,不给一个注定失败的点击
30
+ - **`/stop` 在多个工作区并行时不再假报已停止**:槽位按工作区为键,旧实现停在第一条命中就返回,只停一个却回「已停止」,另一个无声继续。现在遍历所有命中的运行与后台任务,并把实际停止数量回报出来(多条时提示已停止 N 个);按 runId 停某一条仍然只停那一条
31
+ - **停止不会把配置变更多拖一轮**:中断时不再立即回收常驻的 runner 实例——队列链可能在等待窗口里推进下一条消息并拿走同一实例,立即回收会让那条回合并无人托管长驻连接,进程残留到空闲超时且占着写锁。改为只标记待替换,由下一次即将开跑、且该工作区确实空闲时换新实例;只看一眼的调用(探压缩能力、杀后台任务)不会被顺手换实例
32
+ - **排队卡不再停在旧状态**:移除排队条目与「已撤销」卡更新收口到同一处,调用方不再需要手工配对(漏一处就永久停在「等待中」,而映射已被消费、之后再无修正机会);卡片的更新请求失败会重试一次,一次网络抖动不再让卡停在旧视图
33
+
34
+ ### 变更
35
+
36
+ - **英文架构文档补齐本轮叙述**:停止范围与中断交接、可压缩记录与槽位所有权解耦、按钮可见性判据、队列移除与撤销卡收口,以及目标终态与目标视图,中英两侧一致,不再一边落后
37
+
8
38
  ## [0.5.8] - 2026-10-21
9
39
 
10
40
  ### 修复
11
41
 
12
- - **DSH 的 `/resume` 列表卡看得出会话内容**:此前 DSH 会话的列表卡只有 session id 和时间,必须逐条点进详情才知道哪一条是要找的会话。DSH 0.2.x 的列表响应里已带着会话标题与每轮的输入/输出,现在把它们映射成「标题 / 最近输入 / 最后输出」直接渲染,行上有预览就不再逐条去拉分页详情(那是上万条事件的大响应);字段缺失或标题只是占位符时回退原有行为。详情卡头部同样优先用服务端的末轮输入作「最近输入」,并在它与会话标题不同时分成两段展示,不再把用户自己说的话挂在「AI 标题」下面
13
- - **后台任务卡里的命令不再被截断**:活过本轮的后台任务(终端里起的后台进程)原先按固定字数截断,用户没法核对卡上那条命令到底是要停哪个。现在短命令内联展示、中等长度用代码块整段展示、只有确实很长的脚本或链式命令才收进折叠面板,且面板里保留完整原文——命令是你都要核对或复制的对象,任何情况下不再 truncate
42
+ - **DSH 的 `/resume` 列表卡看得出会话内容**:此前 DSH 会话的列表卡只有 session id 和时间,必须逐条点进详情才知道哪一条是要找的会话。DSH 0.2.x 的列表响应里已带着会话标题与每轮的输入/输出,现在把它们映射成「标题 / 最近输入 / 最后输出」直接渲染,行上有预览就不再逐条去拉分页详情(那一次会按上限把整段历史拉回来);字段缺失或标题只是占位符时回退原有行为。详情卡头部同样优先用服务端的末轮输入作「最近输入」,并在它与会话标题不同时分成两段展示,不再把用户自己说的话挂在「AI 标题」下面
43
+ - **后台任务卡里的命令不再被截断**:活过本轮的后台任务(终端里起的后台进程)原先按固定字数截断,用户没法核对卡上那条命令到底是要停哪个。现在短命令内联展示、中等长度用代码块整段展示、只有确实很长的脚本或链式命令才收进折叠面板,且面板里保留完整原文——命令正是你要核对、要复制的对象,任何情况下不再 truncate
14
44
  - **停止按钮不再被挤成「🟥…」**:命令与停止按钮原先并排同一行(命令列 `grow`、按钮列 `auto`),长命令的最小内容宽度会把按钮压成一个色块。现在命令独占一行,停止按钮在下一行独占一列
15
45
  - **运行卡片收尾后保留状态行**:终态原先会把「⏱ 耗时 · 🧰 步数 · 📊 上下文」整行去掉,回看卡片时看不出这一跑花了多久、做了多少步。现在保留:耗时定格,步数与上下文显示该回合最后一次投影的快照
16
46
 
@@ -3,7 +3,7 @@ import type { AgentRegistry } from '../runner/registry.js';
3
3
  import type { SessionReaderRegistry, SessionStore } from '../session/index.js';
4
4
  import type { AppConfig } from '../config/index.js';
5
5
  import { type RunCardChannel } from '../card/run-card-session.js';
6
- import type { RunTerminal } from '../card/run-state.js';
6
+ import { type RunTerminal } from '../card/run-state.js';
7
7
  import { type AgentKind, type StopOutcome } from '../runner/types.js';
8
8
  import { QueueManager, type QueuedTask, type EnqueueOptions, type AgentBinding, type ExecutingInfo } from './queue-manager.js';
9
9
  import type { InboundMediaPayload } from '../connector/index.js';
@@ -49,6 +49,8 @@ export interface CommandResult {
49
49
  /** Detailed result of one interrupt, for callers that must not over-promise. */
50
50
  export interface InterruptOutcome {
51
51
  stopped: boolean;
52
+ /** 本次实际停掉的 run 数(activeRuns + bash)。多个 workspace 并行时可能 >1。 */
53
+ stoppedCount?: number;
52
54
  agentKind?: AgentKind;
53
55
  /** Present for DSH: what the remote stop actually achieved. */
54
56
  stop?: StopOutcome;
@@ -159,12 +161,11 @@ export declare class Bridge {
159
161
  */
160
162
  private compactableRuns;
161
163
  /**
162
- * 终态卡片的渲染快照(runId → state + options),供「详情」在 run 结束后
163
- * 仍能二次渲染。
164
- *
165
- * run 结束时 activeRuns 被清空,而卡片上的「详情」按钮还活着;没有快照,
166
- * 点终态卡上的「详情」只能得到一句「已失效」。只保留最近若干条:单条快照
167
- * 受 MAX_BLOCKS 约束(几十 KB 以内),用户只会点刚收到的卡。
164
+ * 终态卡片的渲染快照(runId → state + options):run 结束后 activeRuns 已
165
+ * 清空,而卡片上的「⏹ 停止」后台任务按钮(job.kill)还活着,需要按 runId
166
+ * 反查该 run 的 sessionId/cwd 才能停对任务。只保留最近若干条:单条快照受
167
+ * MAX_BLOCKS 约束(几十 KB 以内),用户只会点刚收到的卡;超出窗口的旧卡
168
+ * 会得到明确的「记录已回收」提示,不假装任务仍在。
168
169
  */
169
170
  private runCardSnapshots;
170
171
  private static readonly RUN_CARD_SNAPSHOT_MAX;
@@ -269,6 +270,15 @@ export declare class Bridge {
269
270
  * user edits a queued message (see router handleQueueImmediate).
270
271
  */
271
272
  setTaskReplacement(cwd: string, messageId: string, task: () => Promise<void>): void;
273
+ /**
274
+ * One-shot: hold the target's run-card start until the returned release is
275
+ * called. queue.immediate uses it so its final toast is sent before the run
276
+ * card — the toast would otherwise be the newest message and the chat list
277
+ * would stop previewing the run card's title changes. The queue slot itself
278
+ * still begins normally; only run-card creation waits (see
279
+ * QueueManager.holdTaskRunStart).
280
+ */
281
+ holdQueueTaskRun(cwd: string, messageId: string): () => void;
272
282
  /** Update queue card to "cancelled" status when user clicks 撤销. */
273
283
  updateQueueCardToCancelled(cwd: string, messageId: string): Promise<void>;
274
284
  /** Mark a queued task's card as executing immediately (grey out buttons).
@@ -349,6 +359,14 @@ export declare class Bridge {
349
359
  runId?: string;
350
360
  cwd?: string;
351
361
  }): Promise<InterruptOutcome>;
362
+ /**
363
+ * 停掉一条已注册的 active run:置终态、停 runner、摘槽位、标 stale、
364
+ * 归零该 cwd 的队列执行计数。返回 runner 的停止结果(DSH 才有)。
365
+ *
366
+ * 只做「这一条 run」的事——跨多个 workspace 的遍历在调用方,避免再次
367
+ * 出现「停第一条就 return」的漏停。
368
+ */
369
+ private interruptActiveRun;
352
370
  /** Send a result message to the user (§7). Returns true on success, false on failure. */
353
371
  sendResult(result: CommandResult, ctx: CommandContext): Promise<boolean>;
354
372
  /**
@@ -556,6 +574,22 @@ export declare class Bridge {
556
574
  * 先 delete 再 set 以刷新位置)。
557
575
  */
558
576
  private recordCompactableRun;
577
+ /**
578
+ * 终态 Compact 记账:把本次 run 实际使用的 sessionId 记进
579
+ * {@link compactableRuns},供终态卡上的 Compact 按钮按 runId 反查。
580
+ *
581
+ * 调用点固定在 `finalizeRun` 的 `finally` 里、**槽位所有权守卫之外**。
582
+ * 所有权守卫只回答「cwd 槽位还归不归本 run」(决定能否删槽位 / evict
583
+ * runner);记账回答「本次 run 结束了吗、用的哪个 sessionId」。两者在不同
584
+ * 维度上:外部中断(`/stop`、停止卡按钮、`queue.immediate`)会先摘槽位,
585
+ * 记账若跟着守卫走就永远不会落,中断卡片的按钮必然反查不到(中断
586
+ * 后点 Compact 一律回「该任务已结束或不属于当前会话」)。
587
+ *
588
+ * 覆盖所有终态入口(正常结束、error、interrupted、idle_timeout、
589
+ * goal_continuing)——这些卡片都渲染 Compact 按钮(`goal` 仍 active 时
590
+ * 除外)。记账失败不能影响清理,故内部兜错。
591
+ */
592
+ private recordCompactableRunForTerminal;
559
593
  /**
560
594
  * 按 runId 反查可压缩 run 记录(跨 cwd 扫描)。
561
595
  *