lark-remote 0.5.12 → 0.5.13

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.
Files changed (95) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/README.en.md +1 -14
  3. package/README.md +1 -14
  4. package/dist/bridge/approval-coordinator.d.ts +1 -0
  5. package/dist/bridge/approval-coordinator.js +12 -24
  6. package/dist/bridge/index.d.ts +7 -0
  7. package/dist/bridge/index.js +77 -227
  8. package/dist/bridge/run-approval.d.ts +15 -0
  9. package/dist/bridge/run-approval.js +41 -0
  10. package/dist/bridge/run-usage.d.ts +46 -0
  11. package/dist/bridge/run-usage.js +96 -0
  12. package/dist/bridge/session-writeback.d.ts +18 -0
  13. package/dist/bridge/session-writeback.js +36 -0
  14. package/dist/card/bash-card-session.js +2 -5
  15. package/dist/card/card-session.d.ts +2 -0
  16. package/dist/card/card-session.js +20 -22
  17. package/dist/card/card-shared.d.ts +4 -4
  18. package/dist/card/card-shared.js +3 -9
  19. package/dist/card/collapsible.js +3 -2
  20. package/dist/card/final-answer-overflow.d.ts +7 -0
  21. package/dist/card/final-answer-overflow.js +46 -0
  22. package/dist/card/run-card-session.js +2 -7
  23. package/dist/card/run-renderer.d.ts +14 -0
  24. package/dist/card/run-renderer.js +119 -1
  25. package/dist/card/run-state.d.ts +12 -1
  26. package/dist/card/run-state.js +73 -34
  27. package/dist/config/codex-config.js +4 -4
  28. package/dist/config/index.d.ts +4 -2
  29. package/dist/config/index.js +6 -4
  30. package/dist/inbound/turn-assembler.js +6 -0
  31. package/dist/index.js +15 -409
  32. package/dist/message-handlers.d.ts +26 -0
  33. package/dist/message-handlers.js +275 -0
  34. package/dist/router/card-action-payload.d.ts +1 -1
  35. package/dist/router/card-action-payload.js +1 -1
  36. package/dist/router/commands/ls.d.ts +9 -0
  37. package/dist/router/commands/ls.js +243 -0
  38. package/dist/router/commands/order.d.ts +12 -0
  39. package/dist/router/commands/order.js +178 -0
  40. package/dist/router/commands/resume.d.ts +47 -0
  41. package/dist/router/commands/resume.js +246 -0
  42. package/dist/router/commands/ws.d.ts +15 -0
  43. package/dist/router/commands/ws.js +189 -0
  44. package/dist/router/config/claude.js +3 -3
  45. package/dist/router/config/codex.js +2 -6
  46. package/dist/router/config/common/turn-idle.d.ts +2 -0
  47. package/dist/router/config/common/turn-idle.js +9 -0
  48. package/dist/router/config/kimi.js +2 -6
  49. package/dist/router/config/opencode.js +2 -6
  50. package/dist/router/index.d.ts +14 -22
  51. package/dist/router/index.js +70 -1152
  52. package/dist/router/paging.d.ts +13 -0
  53. package/dist/router/paging.js +20 -0
  54. package/dist/router/path-validation.d.ts +27 -0
  55. package/dist/router/path-validation.js +45 -0
  56. package/dist/runner/claude/runner.d.ts +3 -4
  57. package/dist/runner/claude/runner.js +4 -5
  58. package/dist/runner/claude/session.js +1 -1
  59. package/dist/runner/codex/app-server/translator.d.ts +2 -0
  60. package/dist/runner/codex/app-server/translator.js +65 -9
  61. package/dist/runner/common/acp/base-translator.d.ts +3 -8
  62. package/dist/runner/common/acp/base-translator.js +16 -7
  63. package/dist/runner/common/spawning-runner.js +10 -4
  64. package/dist/runner/common/turn-started.d.ts +2 -0
  65. package/dist/runner/common/turn-started.js +10 -0
  66. package/dist/runner/dsh/auth.js +2 -3
  67. package/dist/runner/dsh/client.d.ts +1 -6
  68. package/dist/runner/dsh/client.js +11 -165
  69. package/dist/runner/dsh/daemon.d.ts +0 -2
  70. package/dist/runner/dsh/daemon.js +1 -6
  71. package/dist/runner/dsh/errors.d.ts +5 -0
  72. package/dist/runner/dsh/errors.js +11 -0
  73. package/dist/runner/dsh/exit-cancel.d.ts +0 -2
  74. package/dist/runner/dsh/exit-cancel.js +1 -1
  75. package/dist/runner/dsh/home.d.ts +2 -0
  76. package/dist/runner/dsh/home.js +8 -0
  77. package/dist/runner/dsh/inflight.d.ts +0 -2
  78. package/dist/runner/dsh/inflight.js +1 -1
  79. package/dist/runner/dsh/mux-stream.d.ts +26 -0
  80. package/dist/runner/dsh/mux-stream.js +157 -0
  81. package/dist/runner/dsh/translator.d.ts +0 -10
  82. package/dist/runner/dsh/translator.js +1 -1
  83. package/dist/runner/index.d.ts +1 -1
  84. package/dist/runner/kimi/acp/translator.js +1 -12
  85. package/dist/runner/opencode/acp/translator.js +1 -12
  86. package/dist/runner/pi/rpc/translator.d.ts +2 -8
  87. package/dist/runner/pi/rpc/translator.js +2 -7
  88. package/dist/runner/registry.d.ts +0 -19
  89. package/dist/runner/registry.js +0 -32
  90. package/dist/runner/types.d.ts +17 -1
  91. package/dist/session/claude/session-index.js +4 -2
  92. package/dist/session/kimi/sessions.js +2 -2
  93. package/dist/session/opencode/sessions.js +2 -1
  94. package/dist/session/pi/sessions.js +3 -2
  95. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ 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.13] - 2026-10-26
9
+
10
+ ### 修复
11
+
12
+ - **长回合的最终回答不再被进度内容挤掉**:工具输出、思考、通知此前与最终回答共用同一份卡片预算,回合越长越容易把回答截断甚至整段挤没。现在最终回答独立保存,不受进度文本窗口和工具块上限淘汰;终态渲染先排状态、审批与操作控件,再放完整回答,剩余空间才从新到旧回填进度内容。协议带 `final_answer` 标记的(Codex app-server)直接采用,没有标记的 agent 在收尾时把最后一条非空 assistant 文本提升为最终回答,Claude、opencode、Kimi、Pi、DSH 共用同一套保护
13
+ - **回答放不下时随后补发完整文本**:单张卡片连「最终回答 + 必要控件」都装不下时,原卡提示「最终回答较长,完整内容已随后发送」,完整回答按 UTF-8 字节边界拆成多条纯文本消息补发(优先落在换行处,单条上限 20000 字节),拼接后与原文逐字一致,不再静默截断;补发失败会在原卡给出「完整回答补发失败」的可见回执
14
+
15
+ ### 维护
16
+
17
+ - **入口与路由/桥接层拆分为独立模块**:消息入站装配、命令实现(`ls` / `order` / `resume` / `ws`)、分页与路径校验、审批转发、用量聚合、会话回写、DSH 多路复用流各自成模块,`src/index.ts`、`src/bridge/index.ts`、`src/router/index.ts` 只保留编排职责;同时为拆分中暴露的状态竞争(中断与自然结束并发写同一张卡的终态、审批重投递、bash 卡片收尾)补上回归用例。无行为变化
18
+
8
19
  ## [0.5.12] - 2026-10-24
9
20
 
10
21
  ### 修复
@@ -562,8 +573,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
562
573
  ### 修复
563
574
 
564
575
  - `displayTitle`/`summary` 跳过 task-notification 注入
565
- - 修复 `scanClaudeSessions` 对迁移到其他目录的会话的遗漏(S2)
566
- - 修复 probe 生命周期、工厂回退、卡片回调等评审发现的问题(F1-F8)
576
+ - 修复 `scanClaudeSessions` 对迁移到其他目录的会话的遗漏
577
+ - 修复 probe 生命周期、工厂回退、卡片回调等问题
567
578
 
568
579
  ### 变更
569
580
 
package/README.en.md CHANGED
@@ -14,19 +14,6 @@ Designed for a single-user, peer-to-peer private chat. The agent's system prompt
14
14
 
15
15
  > **New here? Start with [docs/en/getting-started.md](docs/en/getting-started.md).**
16
16
 
17
- ## ⚠️ Security Warning (read first)
18
-
19
- This tool turns Feishu messages directly into local agent executions. **Out of the box, agents run without approval prompts**: Claude defaults to `bypassPermissions` (no approval card), but that permission mode is **configurable** — set it to anything other than `bypassPermissions` (`default` / `acceptEdits` / `auto` / `dontAsk` / `plan`) to enable interactive approval, where high-risk actions wait for your confirmation on the Feishu card. Codex uses the **app-server approval mode** (default `approvalPolicy=on-request` — command execution requires your confirmation on the Feishu card, sandbox defaults to `workspace-write`); Kimi defaults to `manual` (per-action approval; note that since kimi 0.40, `yolo` means Ask-When-Needed rather than allow-everything — use `auto` for fully unattended, no-approval execution); other agents run with their CLI defaults. **In any mode**, agents can read and write the local directories you specify. You MUST:
20
-
21
- - **Use it only in your own private (p2p) chat.** Never add the bot to any group chat; never let anyone else talk to it.
22
- - Restrict the app's visibility to **yourself only** in the Feishu Open Platform.
23
- - Don't run it on a machine holding data you can't afford to lose; prefer a dedicated user / machine / container.
24
- - Keep credentials such as `appSecret` in your local `config.yaml` only — **never commit them anywhere**.
25
-
26
- In approval mode (Claude, Codex, Kimi), an approval card arrives before a command runs — approve or reject it right in Feishu:
27
-
28
- ![Command approval card example](docs/images/approval-card.png)
29
-
30
17
  ## Prerequisites
31
18
 
32
19
  - OS: macOS / Linux / Windows 10+ (native Windows support is verified on real hardware, with behavior matching macOS/Linux)
@@ -70,7 +57,7 @@ defaultAgent: claude
70
57
  claude:
71
58
  model: claude-opus-4-8
72
59
  effort: medium # low | medium | high | xhigh | max
73
- permissionMode: bypassPermissions # Claude official --permission-mode: default | acceptEdits | auto | bypassPermissions | manual | dontAsk | plan (switchable via /config card; anything other than bypassPermissions enables approval)
60
+ permissionMode: auto # Claude official --permission-mode: default | acceptEdits | auto | bypassPermissions | manual | dontAsk | plan (switchable via /config card; auto is the default: low-risk actions run, high-risk actions ask)
74
61
  stopGraceMs: 5000
75
62
 
76
63
  logging:
package/README.md CHANGED
@@ -14,19 +14,6 @@
14
14
 
15
15
  > **第一次接触本项目?先看 [docs/zh/getting-started.md](docs/zh/getting-started.md)。**
16
16
 
17
- ## ⚠️ 安全警告(必读)
18
-
19
- 本工具会把飞书消息直接转为本地 agent 执行。**开箱默认是不弹审批的**:Claude 默认以 `bypassPermissions` 运行(无审批卡),但该权限模式**可配置**——把它改成 `bypassPermissions` 以外的值(`default` / `acceptEdits` / `auto` / `dontAsk` / `plan`)即启用交互式审批,高风险操作会在飞书卡片上等你确认;Codex 采用 **app-server 审批模式**(默认 `approvalPolicy=on-request`,执行命令需在飞书卡片上确认,沙箱默认 `workspace-write`);Kimi 默认 `manual`(逐条审批;注意 kimi 0.40+ 起 `yolo` 已改为「必要时询问」而非全部放行,要完全不弹审批需选 `auto`);其他 agent 以各自 CLI 的默认权限运行。**无论哪种模式**,agent 都能读写你指定的本地目录,请务必:
20
-
21
- - **仅限你自己的私聊(p2p)使用**。不要把机器人拉进任何群聊,不要让任何其他人能与它对话。
22
- - 在飞书开放平台把应用可见范围限制到**只有你自己**。
23
- - 运行本工具的机器上不要存放与损失承受力不符的数据;建议在独立用户/机器/容器里运行。
24
- - `appSecret` 等凭据只在本地 `config.yaml`,**不要提交到任何仓库**。
25
-
26
- 审批模式下(Claude、Codex、Kimi),执行命令前会收到审批卡片,可直接在飞书里允许或拒绝:
27
-
28
- ![命令审批卡片示例](docs/images/approval-card.png)
29
-
30
17
  ## 前置条件
31
18
 
32
19
  - 操作系统:macOS / Linux / Windows 10+(原生 Windows 支持已完成真机验证,行为与 macOS/Linux 对齐)
@@ -70,7 +57,7 @@ defaultAgent: claude
70
57
  claude:
71
58
  model: claude-opus-4-8
72
59
  effort: medium # low | medium | high | xhigh | max
73
- permissionMode: bypassPermissions # Claude 官方 --permission-mode:default | acceptEdits | auto | bypassPermissions | manual | dontAsk | plan(`/config` 卡片可切换;非 bypassPermissions 会启用审批)
60
+ permissionMode: auto # Claude 官方 --permission-mode:default | acceptEdits | auto | bypassPermissions | manual | dontAsk | plan(`/config` 卡片可切换;auto 为默认:低风险放行、高风险审批)
74
61
  stopGraceMs: 5000
75
62
 
76
63
  logging:
@@ -179,6 +179,7 @@ export declare class ApprovalCoordinator {
179
179
  /** 记录问题答案到 tracked.answers(懒初始化 Map)。 */
180
180
  private recordAnswer;
181
181
  private getPendingQuestion;
182
+ private getPendingQuestionAt;
182
183
  private allQuestionsAnswered;
183
184
  /** 推送审批卡视图更新(approval_view_updated 重渲染;失败仅记日志)。 */
184
185
  private pushApprovalViewUpdate;
@@ -178,12 +178,7 @@ export class ApprovalCoordinator {
178
178
  * submitAnswers() 显式提交。
179
179
  */
180
180
  async toggleAnswer(action, ctx) {
181
- const tracked = this.getPendingQuestion(ctx.requestId);
182
- const questions = tracked.view.questions;
183
- const q = questions[action.questionIndex];
184
- if (!q) {
185
- throw new Error(`Question ${action.questionIndex} not found in request ${ctx.requestId}`);
186
- }
181
+ const { tracked, question: q } = this.getPendingQuestionAt(ctx.requestId, action.questionIndex);
187
182
  const option = q.options.find((o) => o.label === action.option);
188
183
  if (!option) {
189
184
  throw new Error(`Option "${action.option}" not found in question ${action.questionIndex}`);
@@ -217,12 +212,7 @@ export class ApprovalCoordinator {
217
212
  * 提交该问题当前勾选的选项;全部问题答完时通过 responder 提交。
218
213
  */
219
214
  async submitAnswers(action, ctx) {
220
- const tracked = this.getPendingQuestion(ctx.requestId);
221
- const questions = tracked.view.questions;
222
- const q = questions[action.questionIndex];
223
- if (!q) {
224
- throw new Error(`Question ${action.questionIndex} not found in request ${ctx.requestId}`);
225
- }
215
+ const { tracked, question: q } = this.getPendingQuestionAt(ctx.requestId, action.questionIndex);
226
216
  if (!q.multiSelect) {
227
217
  throw new Error('该问题为单选,请直接点击选项');
228
218
  }
@@ -240,12 +230,7 @@ export class ApprovalCoordinator {
240
230
  * 单选问题的答案。与单选 toggle 同语义:全部问题答完自动提交。
241
231
  */
242
232
  async answerCustom(action, ctx) {
243
- const tracked = this.getPendingQuestion(ctx.requestId);
244
- const questions = tracked.view.questions;
245
- const q = questions[action.questionIndex];
246
- if (!q) {
247
- throw new Error(`Question ${action.questionIndex} not found in request ${ctx.requestId}`);
248
- }
233
+ const { tracked, question: q } = this.getPendingQuestionAt(ctx.requestId, action.questionIndex);
249
234
  if (q.multiSelect) {
250
235
  throw new Error('自定义答案仅支持单选');
251
236
  }
@@ -266,12 +251,7 @@ export class ApprovalCoordinator {
266
251
  * 后回流视图(卡片回显),同一请求可多次修改(新 nonce 来自新渲染)。
267
252
  */
268
253
  async answerNote(action, ctx) {
269
- const tracked = this.getPendingQuestion(ctx.requestId);
270
- const questions = tracked.view.questions;
271
- const q = questions[action.questionIndex];
272
- if (!q) {
273
- throw new Error(`Question ${action.questionIndex} not found in request ${ctx.requestId}`);
274
- }
254
+ const { tracked, question: q } = this.getPendingQuestionAt(ctx.requestId, action.questionIndex);
275
255
  const text = action.text.trim();
276
256
  if (!text) {
277
257
  throw new Error('请输入补充说明');
@@ -443,6 +423,14 @@ export class ApprovalCoordinator {
443
423
  }
444
424
  return tracked;
445
425
  }
426
+ getPendingQuestionAt(requestId, questionIndex) {
427
+ const tracked = this.getPendingQuestion(requestId);
428
+ const question = tracked.view.questions?.[questionIndex];
429
+ if (!question) {
430
+ throw new Error(`Question ${questionIndex} not found in request ${requestId}`);
431
+ }
432
+ return { tracked, question };
433
+ }
446
434
  allQuestionsAnswered(tracked) {
447
435
  const questions = tracked.view.questions ?? [];
448
436
  if (questions.length === 0)
@@ -369,6 +369,12 @@ export declare class Bridge {
369
369
  private interruptActiveRun;
370
370
  /** Send a result message to the user (§7). Returns true on success, false on failure. */
371
371
  sendResult(result: CommandResult, ctx: CommandContext): Promise<boolean>;
372
+ /**
373
+ * Deliver a final answer that cannot fit in the run card. Plain text avoids
374
+ * markdown parser limits and preserves every character; sequence labels make
375
+ * multi-message delivery unambiguous.
376
+ */
377
+ private sendFinalAnswerOverflow;
372
378
  /**
373
379
  * Update an existing card in place (原地更新) instead of sending a new one.
374
380
  *
@@ -567,6 +573,7 @@ export declare class Bridge {
567
573
  text: string;
568
574
  nonce: string;
569
575
  }): Promise<void>;
576
+ private dispatchQuestionAction;
570
577
  /**
571
578
  * 记下一次「可压缩 run」:终态卡上的 Compact 按钮点击时据此反查
572
579
  * sessionId + agentKind。runId 是按钮自带的唯一键,同 cwd 内唯一。