lark-remote 0.5.20 → 0.5.21

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 (55) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/bridge/inbound-media.js +71 -45
  3. package/dist/bridge/index.d.ts +9 -0
  4. package/dist/bridge/index.js +230 -203
  5. package/dist/card/approval-render.js +32 -33
  6. package/dist/card/card-budget.js +123 -98
  7. package/dist/card/run-renderer.js +82 -68
  8. package/dist/card/run-state.d.ts +0 -14
  9. package/dist/card/run-state.js +335 -207
  10. package/dist/card/tool-render.js +20 -16
  11. package/dist/card/usage-format.d.ts +12 -9
  12. package/dist/card/usage-format.js +111 -97
  13. package/dist/common/text-width.js +36 -24
  14. package/dist/common/tool-summary.js +132 -90
  15. package/dist/index.js +226 -190
  16. package/dist/message-handlers.js +253 -236
  17. package/dist/router/commands/ls.d.ts +3 -0
  18. package/dist/router/commands/ls.js +256 -175
  19. package/dist/router/commands/order.js +184 -159
  20. package/dist/router/commands/resume.js +189 -133
  21. package/dist/router/commands/ws.js +219 -174
  22. package/dist/router/index.js +192 -201
  23. package/dist/runner/bash/runner.js +2 -4
  24. package/dist/runner/codex/app-server/translator.d.ts +2 -0
  25. package/dist/runner/codex/app-server/translator.js +287 -221
  26. package/dist/runner/common/acp/base-translator.js +19 -17
  27. package/dist/runner/common/jsonl-stream.js +154 -187
  28. package/dist/runner/common/jsonrpc/client.d.ts +29 -0
  29. package/dist/runner/common/jsonrpc/client.js +43 -12
  30. package/dist/runner/common/spawning-runner.d.ts +5 -0
  31. package/dist/runner/common/spawning-runner.js +8 -3
  32. package/dist/runner/common/turn-started.d.ts +8 -0
  33. package/dist/runner/common/turn-started.js +11 -0
  34. package/dist/runner/dsh/approval.js +84 -51
  35. package/dist/runner/dsh/client.d.ts +7 -9
  36. package/dist/runner/dsh/client.js +356 -287
  37. package/dist/runner/dsh/mux-stream.js +28 -8
  38. package/dist/runner/dsh/runner.d.ts +4 -3
  39. package/dist/runner/dsh/runner.js +88 -64
  40. package/dist/runner/dsh/translator.d.ts +1 -31
  41. package/dist/runner/dsh/translator.js +180 -178
  42. package/dist/runner/kimi/acp/runner.js +81 -44
  43. package/dist/runner/opencode/acp/error-monitor.js +5 -5
  44. package/dist/runner/pi/rpc/client.js +4 -13
  45. package/dist/runner/pi/rpc/translator.js +61 -60
  46. package/dist/session/claude/sessions.js +113 -101
  47. package/dist/session/codex/rollout-reader.js +179 -180
  48. package/dist/session/dsh/sessions.js +281 -231
  49. package/dist/session/kimi/sessions.d.ts +0 -7
  50. package/dist/session/kimi/sessions.js +129 -109
  51. package/dist/session/opencode/sessions.d.ts +0 -11
  52. package/dist/session/opencode/sessions.js +161 -137
  53. package/dist/session/session-store.d.ts +8 -0
  54. package/dist/session/session-store.js +98 -98
  55. package/package.json +1 -1
@@ -9,6 +9,70 @@
9
9
  * first.
10
10
  */
11
11
  import { getLogger } from '../../logger/index.js';
12
+ // --- 模块级命名函数:把状态显式传入,避免在方法内定义带决策点的闭包 ---
13
+ // crapper 会把方法内部闭包的决策点计入外层方法;抽到模块顶层后
14
+ // onWaterfall / waitForBinding 只剩选路。
15
+ /** 重连重投:刷新已绑定 waterfall 的应答通道,不产新 binding。 */
16
+ function refreshRedeliveredWaterfall(bindings, waterfallByCallId, approvalId, waterfall) {
17
+ const binding = bindings.get(approvalId);
18
+ if (!binding)
19
+ return;
20
+ binding.waterfall.clientId = waterfall.clientId;
21
+ if (waterfall.reason)
22
+ binding.waterfall.reason = waterfall.reason;
23
+ if (waterfall.callId)
24
+ waterfallByCallId.set(waterfall.callId, binding.waterfall);
25
+ }
26
+ /** 第一段:按 callId 精确匹配未绑定 audit。 */
27
+ function auditWithCallId(audits, bindings, callId) {
28
+ for (const audit of audits) {
29
+ if (audit.callId === callId && !bindings.has(audit.approvalId))
30
+ return audit;
31
+ }
32
+ return undefined;
33
+ }
34
+ /** 第二段:无 callId 的 audit,按 toolName 兜底配对。 */
35
+ function unboundAuditWithoutCallId(audits, bindings, toolName) {
36
+ for (const audit of audits) {
37
+ if (!audit.callId && !bindings.has(audit.approvalId) && audit.toolName === toolName) {
38
+ return audit;
39
+ }
40
+ }
41
+ return undefined;
42
+ }
43
+ /** 第三段:waterfall 无 callId 时,按 toolName 找最老未绑定 audit。 */
44
+ function unboundAuditByToolName(audits, bindings, toolName) {
45
+ for (const audit of audits) {
46
+ if (!bindings.has(audit.approvalId) && audit.toolName === toolName)
47
+ return audit;
48
+ }
49
+ return undefined;
50
+ }
51
+ /** 按 waterfall 是否有 callId 选路,顺序与原实现三段 for 循环一致。 */
52
+ function findPairableAudit(audits, bindings, waterfall) {
53
+ if (waterfall.callId) {
54
+ return (auditWithCallId(audits.values(), bindings, waterfall.callId) ??
55
+ unboundAuditWithoutCallId(audits.values(), bindings, waterfall.toolName));
56
+ }
57
+ return unboundAuditByToolName(audits.values(), bindings, waterfall.toolName);
58
+ }
59
+ /** 结束一次等待(幂等):清 timer、摘监听、从 waiters 移除、resolve。 */
60
+ function finishBindingWait(state, binding) {
61
+ if (state.settled)
62
+ return;
63
+ state.settled = true;
64
+ if (state.timer !== undefined)
65
+ clearTimeout(state.timer);
66
+ state.signal?.removeEventListener('abort', state.onAbort);
67
+ const set = state.waiters.get(state.approvalId);
68
+ set?.delete(state.finish);
69
+ if (set && set.size === 0)
70
+ state.waiters.delete(state.approvalId);
71
+ state.resolve(binding);
72
+ }
73
+ function abortBindingWait(state) {
74
+ finishBindingWait(state, undefined);
75
+ }
12
76
  export class DshApprovalTracker {
13
77
  audits = new Map();
14
78
  waterfallByCallId = new Map();
@@ -43,45 +107,15 @@ export class DshApprovalTracker {
43
107
  if (existingApprovalId) {
44
108
  // A reconnect re-delivers the same pending event with a new Client
45
109
  // identity. Keep the card binding but refresh the answer channel.
46
- const binding = this.bindings.get(existingApprovalId);
47
- if (binding) {
48
- binding.waterfall.clientId = waterfall.clientId;
49
- if (waterfall.reason)
50
- binding.waterfall.reason = waterfall.reason;
51
- if (waterfall.callId) {
52
- this.waterfallByCallId.set(waterfall.callId, binding.waterfall);
53
- }
54
- }
110
+ refreshRedeliveredWaterfall(this.bindings, this.waterfallByCallId, existingApprovalId, waterfall);
55
111
  return undefined;
56
112
  }
57
113
  if (waterfall.callId)
58
114
  this.waterfallByCallId.set(waterfall.callId, waterfall);
59
- if (waterfall.callId) {
60
- for (const audit of this.audits.values()) {
61
- if (audit.callId === waterfall.callId && !this.bindings.has(audit.approvalId)) {
62
- return this.bind(audit, waterfall);
63
- }
64
- }
65
- // Some approval types omit callId on the durable audit. Pair with the
66
- // oldest unbound audit for the same tool before falling back to Web UI.
67
- for (const audit of this.audits.values()) {
68
- if (!audit.callId &&
69
- !this.bindings.has(audit.approvalId) &&
70
- audit.toolName === waterfall.toolName) {
71
- return this.bind(audit, waterfall);
72
- }
73
- }
74
- }
75
- // A missing callId is unusual but not fatal: pair with the oldest unbound
76
- // audit for the same tool, preserving the audit id on the card.
77
- if (!waterfall.callId) {
78
- for (const audit of this.audits.values()) {
79
- if (!this.bindings.has(audit.approvalId) && audit.toolName === waterfall.toolName) {
80
- return this.bind(audit, waterfall);
81
- }
82
- }
83
- }
84
- return undefined;
115
+ // Some approval types omit callId on the durable audit: pair with the
116
+ // oldest unbound audit for the same tool before falling back to Web UI.
117
+ const audit = findPairableAudit(this.audits, this.bindings, waterfall);
118
+ return audit ? this.bind(audit, waterfall) : undefined;
85
119
  }
86
120
  /** Mark an audit resolved (local response or an external decision). */
87
121
  onDecided(approvalId) {
@@ -125,24 +159,23 @@ export class DshApprovalTracker {
125
159
  if (signal?.aborted)
126
160
  return undefined;
127
161
  return new Promise((resolve) => {
128
- let settled = false;
129
- const finish = (binding) => {
130
- if (settled)
131
- return;
132
- settled = true;
133
- clearTimeout(timer);
134
- signal?.removeEventListener('abort', onAbort);
135
- const set = this.waiters.get(approvalId);
136
- set?.delete(finish);
137
- if (set && set.size === 0)
138
- this.waiters.delete(approvalId);
139
- resolve(binding);
162
+ // 状态显式打包;finish/onAbort 用模块级函数 + bind 绑定状态,
163
+ // 不在方法内定义带决策点的闭包。
164
+ const state = {
165
+ settled: false,
166
+ onAbort: () => { },
167
+ approvalId,
168
+ waiters: this.waiters,
169
+ resolve,
170
+ signal,
171
+ finish: () => { },
140
172
  };
141
- const onAbort = () => finish(undefined);
142
- const timer = setTimeout(() => finish(undefined), timeoutMs);
143
- signal?.addEventListener('abort', onAbort, { once: true });
173
+ state.finish = finishBindingWait.bind(null, state);
174
+ state.onAbort = abortBindingWait.bind(null, state);
175
+ state.timer = setTimeout(abortBindingWait.bind(null, state), timeoutMs);
176
+ signal?.addEventListener('abort', state.onAbort, { once: true });
144
177
  const set = this.waiters.get(approvalId) ?? new Set();
145
- set.add(finish);
178
+ set.add(state.finish);
146
179
  this.waiters.set(approvalId, set);
147
180
  });
148
181
  }
@@ -19,7 +19,7 @@
19
19
  * `sessionEvents()` adds per-session filtering, reconnect + follow-snapshot
20
20
  * replay, and seq-based dedup.
21
21
  */
22
- import type { DshApprovalStreamItem, DshCommandResult, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionPageValue, DshStreamItem } from '../../dsh/types.js';
22
+ import type { DshApprovalStreamItem, DshCommandResult, DshFollowSnapshot, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionEvent, DshSessionPageValue, DshStreamItem } from '../../dsh/types.js';
23
23
  import type { GoalView } from '../types.js';
24
24
  export { DshError } from './errors.js';
25
25
  interface WebSocketMessageEvent {
@@ -105,8 +105,11 @@ export declare class DshClient {
105
105
  signal?: AbortSignal;
106
106
  timeoutMs?: number;
107
107
  }): Promise<unknown>;
108
- /** Distinguish "run stopped" (abort) from "server did not answer" (timeout). */
109
- private abortError;
108
+ /** One unary POST attempt: obtain cookie, then post; both stages may ask to
109
+ * retry once (401 → re-mint cookie); all other failures throw DshError. */
110
+ private attemptUnary;
111
+ private obtainUnaryCookie;
112
+ private postUnary;
110
113
  /** Create a session. Pass `agentPreset` to pin the session's preset (fixed at
111
114
  * creation). */
112
115
  createSession(payload: {
@@ -157,8 +160,6 @@ export declare class DshClient {
157
160
  signal?: AbortSignal;
158
161
  timeoutMs?: number;
159
162
  }): Promise<void>;
160
- /** Hand one waterfall delivery back with `next` (another answerer owns it). */
161
- private delegateWaterfall;
162
163
  /**
163
164
  * Return the highest event `seq` currently persisted for the session.
164
165
  *
@@ -279,9 +280,6 @@ export declare class DshClient {
279
280
  * `next` so a different lark-remote workspace cannot park it.
280
281
  */
281
282
  approvalEvents(sessionId: string, signal: AbortSignal): AsyncGenerator<DshApprovalStreamItem>;
282
- /** Translate one durable event into a stream item (approvals are surfaced
283
- * separately; everything else is forwarded to the runner). */
284
- private eventItem;
285
283
  /**
286
284
  * Per-session subscription: yields session events, assistant stream chunks
287
285
  * and approval notices for `sessionId`, auto-reconnecting on stream
@@ -312,7 +310,7 @@ export declare class DshClient {
312
310
  * 返回 seq 升序的完整回放序列(回填 + 快照记录;与 lastSeq 重叠的条目
313
311
  * 由回放循环的 seq 去重兜住)。
314
312
  */
315
- private replaySnapshotGap;
313
+ replaySnapshotGap(sessionId: string, signal: AbortSignal, lastSeq: number, frame: DshFollowSnapshot): Promise<DshSessionEvent[]>;
316
314
  /**
317
315
  * Host-wide live projection stream (`session/control`).
318
316
  *