lark-remote 0.1.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.
Files changed (201) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +162 -0
  4. package/README.md +161 -0
  5. package/dist/binder.d.ts +57 -0
  6. package/dist/binder.js +105 -0
  7. package/dist/bridge/index.d.ts +338 -0
  8. package/dist/bridge/index.js +1281 -0
  9. package/dist/bridge/queue-manager.d.ts +277 -0
  10. package/dist/bridge/queue-manager.js +729 -0
  11. package/dist/card/bash-card-session.d.ts +78 -0
  12. package/dist/card/bash-card-session.js +174 -0
  13. package/dist/card/bash-renderer.d.ts +24 -0
  14. package/dist/card/bash-renderer.js +187 -0
  15. package/dist/card/card-budget.d.ts +31 -0
  16. package/dist/card/card-budget.js +280 -0
  17. package/dist/card/card-session.d.ts +83 -0
  18. package/dist/card/card-session.js +185 -0
  19. package/dist/card/card-shared.d.ts +28 -0
  20. package/dist/card/card-shared.js +99 -0
  21. package/dist/card/collapsible.d.ts +26 -0
  22. package/dist/card/collapsible.js +87 -0
  23. package/dist/card/run-card-session.d.ts +78 -0
  24. package/dist/card/run-card-session.js +165 -0
  25. package/dist/card/run-renderer.d.ts +66 -0
  26. package/dist/card/run-renderer.js +841 -0
  27. package/dist/card/run-state.d.ts +103 -0
  28. package/dist/card/run-state.js +313 -0
  29. package/dist/card/text-truncate.d.ts +56 -0
  30. package/dist/card/text-truncate.js +184 -0
  31. package/dist/card/time.d.ts +1 -0
  32. package/dist/card/time.js +14 -0
  33. package/dist/card/tool-render.d.ts +25 -0
  34. package/dist/card/tool-render.js +176 -0
  35. package/dist/cli.d.ts +28 -0
  36. package/dist/cli.js +89 -0
  37. package/dist/common/guards.d.ts +37 -0
  38. package/dist/common/guards.js +65 -0
  39. package/dist/config/codex-config.d.ts +113 -0
  40. package/dist/config/codex-config.js +428 -0
  41. package/dist/config/dir.d.ts +17 -0
  42. package/dist/config/dir.js +81 -0
  43. package/dist/config/index.d.ts +219 -0
  44. package/dist/config/index.js +388 -0
  45. package/dist/config/kimi-config.d.ts +33 -0
  46. package/dist/config/kimi-config.js +111 -0
  47. package/dist/config/opencode-config.d.ts +20 -0
  48. package/dist/config/opencode-config.js +124 -0
  49. package/dist/config/pi-config.d.ts +49 -0
  50. package/dist/config/pi-config.js +151 -0
  51. package/dist/config/wizard.d.ts +12 -0
  52. package/dist/config/wizard.js +84 -0
  53. package/dist/connector/file-limits.d.ts +7 -0
  54. package/dist/connector/file-limits.js +8 -0
  55. package/dist/connector/index.d.ts +86 -0
  56. package/dist/connector/index.js +340 -0
  57. package/dist/error-classification.d.ts +15 -0
  58. package/dist/error-classification.js +24 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +580 -0
  61. package/dist/instance-lock.d.ts +30 -0
  62. package/dist/instance-lock.js +184 -0
  63. package/dist/logger/index.d.ts +57 -0
  64. package/dist/logger/index.js +178 -0
  65. package/dist/order/index.d.ts +27 -0
  66. package/dist/order/index.js +90 -0
  67. package/dist/persistence/atomic-write.d.ts +10 -0
  68. package/dist/persistence/atomic-write.js +65 -0
  69. package/dist/persistence/load-json-file.d.ts +9 -0
  70. package/dist/persistence/load-json-file.js +23 -0
  71. package/dist/restart.d.ts +24 -0
  72. package/dist/restart.js +73 -0
  73. package/dist/router/card-helpers.d.ts +28 -0
  74. package/dist/router/card-helpers.js +65 -0
  75. package/dist/router/config/claude.d.ts +14 -0
  76. package/dist/router/config/claude.js +72 -0
  77. package/dist/router/config/codex.d.ts +22 -0
  78. package/dist/router/config/codex.js +100 -0
  79. package/dist/router/config/common/render.d.ts +16 -0
  80. package/dist/router/config/common/render.js +158 -0
  81. package/dist/router/config/index.d.ts +18 -0
  82. package/dist/router/config/index.js +38 -0
  83. package/dist/router/config/kimi.d.ts +21 -0
  84. package/dist/router/config/kimi.js +63 -0
  85. package/dist/router/config/opencode.d.ts +12 -0
  86. package/dist/router/config/opencode.js +44 -0
  87. package/dist/router/config/pi.d.ts +12 -0
  88. package/dist/router/config/pi.js +50 -0
  89. package/dist/router/config/types.d.ts +43 -0
  90. package/dist/router/config/types.js +8 -0
  91. package/dist/router/index.d.ts +318 -0
  92. package/dist/router/index.js +2715 -0
  93. package/dist/router/order-exec-dispatch.d.ts +30 -0
  94. package/dist/router/order-exec-dispatch.js +48 -0
  95. package/dist/router/utils.d.ts +44 -0
  96. package/dist/router/utils.js +116 -0
  97. package/dist/runner/bash/index.d.ts +4 -0
  98. package/dist/runner/bash/index.js +5 -0
  99. package/dist/runner/bash/runner.d.ts +55 -0
  100. package/dist/runner/bash/runner.js +213 -0
  101. package/dist/runner/claude/index.d.ts +4 -0
  102. package/dist/runner/claude/index.js +5 -0
  103. package/dist/runner/claude/runner.d.ts +29 -0
  104. package/dist/runner/claude/runner.js +83 -0
  105. package/dist/runner/codex/argv.d.ts +33 -0
  106. package/dist/runner/codex/argv.js +40 -0
  107. package/dist/runner/codex/index.d.ts +1 -0
  108. package/dist/runner/codex/index.js +2 -0
  109. package/dist/runner/codex/jsonl.d.ts +37 -0
  110. package/dist/runner/codex/jsonl.js +221 -0
  111. package/dist/runner/codex/runner.d.ts +65 -0
  112. package/dist/runner/codex/runner.js +124 -0
  113. package/dist/runner/common/exec-translator.d.ts +73 -0
  114. package/dist/runner/common/exec-translator.js +105 -0
  115. package/dist/runner/common/jsonl-stream.d.ts +39 -0
  116. package/dist/runner/common/jsonl-stream.js +203 -0
  117. package/dist/runner/common/process-stopper.d.ts +28 -0
  118. package/dist/runner/common/process-stopper.js +79 -0
  119. package/dist/runner/common/runner-utils.d.ts +21 -0
  120. package/dist/runner/common/runner-utils.js +65 -0
  121. package/dist/runner/common/spawn-heartbeat.d.ts +33 -0
  122. package/dist/runner/common/spawn-heartbeat.js +51 -0
  123. package/dist/runner/common/spawning-runner.d.ts +321 -0
  124. package/dist/runner/common/spawning-runner.js +634 -0
  125. package/dist/runner/common/usage.d.ts +31 -0
  126. package/dist/runner/common/usage.js +29 -0
  127. package/dist/runner/index.d.ts +19 -0
  128. package/dist/runner/index.js +24 -0
  129. package/dist/runner/kimi/index.d.ts +1 -0
  130. package/dist/runner/kimi/index.js +2 -0
  131. package/dist/runner/kimi/jsonl.d.ts +28 -0
  132. package/dist/runner/kimi/jsonl.js +143 -0
  133. package/dist/runner/kimi/runner.d.ts +50 -0
  134. package/dist/runner/kimi/runner.js +105 -0
  135. package/dist/runner/opencode/argv.d.ts +32 -0
  136. package/dist/runner/opencode/argv.js +35 -0
  137. package/dist/runner/opencode/index.d.ts +1 -0
  138. package/dist/runner/opencode/index.js +2 -0
  139. package/dist/runner/opencode/jsonl.d.ts +68 -0
  140. package/dist/runner/opencode/jsonl.js +295 -0
  141. package/dist/runner/opencode/runner.d.ts +63 -0
  142. package/dist/runner/opencode/runner.js +93 -0
  143. package/dist/runner/pi/index.d.ts +1 -0
  144. package/dist/runner/pi/index.js +2 -0
  145. package/dist/runner/pi/jsonl.d.ts +128 -0
  146. package/dist/runner/pi/jsonl.js +249 -0
  147. package/dist/runner/pi/runner.d.ts +37 -0
  148. package/dist/runner/pi/runner.js +76 -0
  149. package/dist/runner/registry.d.ts +54 -0
  150. package/dist/runner/registry.js +75 -0
  151. package/dist/runner/resolve-agent-choices.d.ts +7 -0
  152. package/dist/runner/resolve-agent-choices.js +76 -0
  153. package/dist/runner/sync-agent-choices.d.ts +6 -0
  154. package/dist/runner/sync-agent-choices.js +73 -0
  155. package/dist/runner/types.d.ts +250 -0
  156. package/dist/runner/types.js +8 -0
  157. package/dist/session/claude/index.d.ts +1 -0
  158. package/dist/session/claude/index.js +2 -0
  159. package/dist/session/claude/session-reader.d.ts +34 -0
  160. package/dist/session/claude/session-reader.js +46 -0
  161. package/dist/session/claude/sessions.d.ts +53 -0
  162. package/dist/session/claude/sessions.js +528 -0
  163. package/dist/session/codex/index.d.ts +1 -0
  164. package/dist/session/codex/index.js +2 -0
  165. package/dist/session/codex/rollout-reader.d.ts +88 -0
  166. package/dist/session/codex/rollout-reader.js +473 -0
  167. package/dist/session/codex/sessions.d.ts +21 -0
  168. package/dist/session/codex/sessions.js +40 -0
  169. package/dist/session/common/catch-up.d.ts +12 -0
  170. package/dist/session/common/catch-up.js +31 -0
  171. package/dist/session/common/constants.d.ts +11 -0
  172. package/dist/session/common/constants.js +12 -0
  173. package/dist/session/common/content-blocks.d.ts +37 -0
  174. package/dist/session/common/content-blocks.js +68 -0
  175. package/dist/session/common/jsonl.d.ts +77 -0
  176. package/dist/session/common/jsonl.js +351 -0
  177. package/dist/session/common/usage-accumulator.d.ts +58 -0
  178. package/dist/session/common/usage-accumulator.js +72 -0
  179. package/dist/session/index.d.ts +7 -0
  180. package/dist/session/index.js +11 -0
  181. package/dist/session/kimi/index.d.ts +1 -0
  182. package/dist/session/kimi/index.js +2 -0
  183. package/dist/session/kimi/sessions.d.ts +81 -0
  184. package/dist/session/kimi/sessions.js +527 -0
  185. package/dist/session/opencode/index.d.ts +1 -0
  186. package/dist/session/opencode/index.js +2 -0
  187. package/dist/session/opencode/sessions.d.ts +81 -0
  188. package/dist/session/opencode/sessions.js +388 -0
  189. package/dist/session/pi/index.d.ts +1 -0
  190. package/dist/session/pi/index.js +2 -0
  191. package/dist/session/pi/sessions.d.ts +27 -0
  192. package/dist/session/pi/sessions.js +399 -0
  193. package/dist/session/registry.d.ts +12 -0
  194. package/dist/session/registry.js +20 -0
  195. package/dist/session/session-store.d.ts +86 -0
  196. package/dist/session/session-store.js +450 -0
  197. package/dist/startup-contact.d.ts +18 -0
  198. package/dist/startup-contact.js +51 -0
  199. package/dist/workspace/index.d.ts +19 -0
  200. package/dist/workspace/index.js +53 -0
  201. package/package.json +93 -0
@@ -0,0 +1,78 @@
1
+ import { CardSession, type CardChannel, type StreamSettleResult } from './card-session.js';
2
+ import { type BashState, type BashRenderOptions } from './bash-renderer.js';
3
+ /**
4
+ * Store-time 输出上限(字符,P1-3 层①)。§P1-3 建议「store-time 截断,
5
+ * 保留尾部,上限如 24~64KB」——取区间下界 24_000 字符(字符上限 ×4 字节最坏
6
+ * ~96KB/字段)。渲染层本就只展示尾部(bash-renderer 截断到 12KB 字节),store 截断
7
+ * 不影响显示内容,只保证内存有界:!yes / !cat 大文件不再把全部输出驻留在 session
8
+ * state 与 bridge 局部变量。
9
+ */
10
+ export declare const BASH_OUTPUT_STORE_CAP = 24000;
11
+ /**
12
+ * Store-time 截断入口(P1-3 层①/层④共用)。bridge 本地 output/stderr 与 session
13
+ * state 都走它,保证任意路径驻留的字符串 ≤ BASH_OUTPUT_STORE_CAP 字符。
14
+ * 调用方传入的 value 通常已 ≤ CAP(增量场景 output 恒 ≤ CAP,+chunk 后 ≤ CAP+chunk),
15
+ * slice(-CAP) 成本 O(CAP+chunk),不会把 O(n²) 截断问题带回桥接循环。
16
+ */
17
+ export declare function capBashOutput(value: string): string;
18
+ /**
19
+ * Streaming card session for `!` bash commands — the bash analogue of
20
+ * RunCardSession. Holds a single BashState, renders renderBashCard, and
21
+ * patches ONE card via connector.streamCard across the run's lifetime
22
+ * (initial running → output updates → terminal), instead of sending many
23
+ * independent cards.
24
+ */
25
+ export declare class BashCardSession extends CardSession<BashState, BashRenderOptions> {
26
+ /**
27
+ * P1-3 层③:push 合批窗口(ms),与 RunCardSession 同语义。连续 update 各触发
28
+ * 一次全卡 render + patch 是 PATCH 风暴主源;窗口内多个事件复用同一次延迟 flush。
29
+ * 窗口大小可通过 constructor 覆盖(测试用小窗口/0 禁用)。
30
+ */
31
+ private readonly coalesceMs;
32
+ private flushTimer;
33
+ private flushInFlight;
34
+ /** in-flight flush 期间到达的 update 标记:flush 完成后需重新调度(防 stale 帧)。 */
35
+ private pendingReschedule;
36
+ /** 当前 in-flight flush 的 promise:finish 在终态 patch 前 await 它保证顺序。 */
37
+ private flushP;
38
+ constructor(opts: {
39
+ connector: CardChannel;
40
+ chatId: string;
41
+ replyTo?: string;
42
+ runId: string;
43
+ command: string;
44
+ renderOptions?: BashRenderOptions;
45
+ startTimeoutMs?: number;
46
+ settleTimeoutMs?: number;
47
+ /** update 合批窗口,默认 100ms(0 = 禁用合批,每 update 立即 flush)。 */
48
+ coalesceMs?: number;
49
+ });
50
+ protected get logPrefix(): string;
51
+ protected get errorPrefix(): string;
52
+ protected renderCard(state: BashState, options: BashRenderOptions): object;
53
+ protected hasOwnBudgetProtection(): boolean;
54
+ /** Patch the card with updated bash state (e.g. new stdout/stderr). */
55
+ update(patch: Partial<BashState>): Promise<void>;
56
+ /** Transition to a terminal state and patch the card. */
57
+ finish(terminal: Exclude<BashState['terminal'], 'running'>, meta?: {
58
+ exitCode?: number | null;
59
+ stderr?: string;
60
+ output?: string;
61
+ }): Promise<void>;
62
+ /**
63
+ * 调度一次延迟 flush:已有 pending 调度则复用(合批核心);flushInFlight 期间
64
+ * 不再起 timer(防重入叠加),但置 pendingReschedule 让 in-flight 完成后补渲染。
65
+ */
66
+ private scheduleFlush;
67
+ /** 执行一次 render + updateCard(合批窗口到期或 finish 即时 flush 时调用)。 */
68
+ private flush;
69
+ /** 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态竞争)。 */
70
+ private cancelPendingFlush;
71
+ /** settle 前兜底取消合批调度,避免 release 后 dangling timer 更新已释放的 stream。 */
72
+ settle(): Promise<StreamSettleResult>;
73
+ /**
74
+ * 合并 patch 并对 output/stderr 做 store-time 截断(P1-3 层①)。
75
+ * 截断发生在入口(store 时),渲染层无需再为大 state 付代价。
76
+ */
77
+ private applyCap;
78
+ }
@@ -0,0 +1,174 @@
1
+ import { CardSession } from './card-session.js';
2
+ import { renderBashCard } from './bash-renderer.js';
3
+ /**
4
+ * Store-time 输出上限(字符,P1-3 层①)。§P1-3 建议「store-time 截断,
5
+ * 保留尾部,上限如 24~64KB」——取区间下界 24_000 字符(字符上限 ×4 字节最坏
6
+ * ~96KB/字段)。渲染层本就只展示尾部(bash-renderer 截断到 12KB 字节),store 截断
7
+ * 不影响显示内容,只保证内存有界:!yes / !cat 大文件不再把全部输出驻留在 session
8
+ * state 与 bridge 局部变量。
9
+ */
10
+ export const BASH_OUTPUT_STORE_CAP = 24_000;
11
+ /** 字符级 tail 保留(与 run-state.keepLatest 的 slice(-maxChars) 语义一致)。 */
12
+ function keepTail(value, maxChars) {
13
+ return value.length <= maxChars ? value : value.slice(-maxChars);
14
+ }
15
+ /**
16
+ * Store-time 截断入口(P1-3 层①/层④共用)。bridge 本地 output/stderr 与 session
17
+ * state 都走它,保证任意路径驻留的字符串 ≤ BASH_OUTPUT_STORE_CAP 字符。
18
+ * 调用方传入的 value 通常已 ≤ CAP(增量场景 output 恒 ≤ CAP,+chunk 后 ≤ CAP+chunk),
19
+ * slice(-CAP) 成本 O(CAP+chunk),不会把 O(n²) 截断问题带回桥接循环。
20
+ */
21
+ export function capBashOutput(value) {
22
+ return keepTail(value, BASH_OUTPUT_STORE_CAP);
23
+ }
24
+ /**
25
+ * Streaming card session for `!` bash commands — the bash analogue of
26
+ * RunCardSession. Holds a single BashState, renders renderBashCard, and
27
+ * patches ONE card via connector.streamCard across the run's lifetime
28
+ * (initial running → output updates → terminal), instead of sending many
29
+ * independent cards.
30
+ */
31
+ export class BashCardSession extends CardSession {
32
+ /**
33
+ * P1-3 层③:push 合批窗口(ms),与 RunCardSession 同语义。连续 update 各触发
34
+ * 一次全卡 render + patch 是 PATCH 风暴主源;窗口内多个事件复用同一次延迟 flush。
35
+ * 窗口大小可通过 constructor 覆盖(测试用小窗口/0 禁用)。
36
+ */
37
+ coalesceMs;
38
+ flushTimer;
39
+ flushInFlight = false;
40
+ /** in-flight flush 期间到达的 update 标记:flush 完成后需重新调度(防 stale 帧)。 */
41
+ pendingReschedule = false;
42
+ /** 当前 in-flight flush 的 promise:finish 在终态 patch 前 await 它保证顺序。 */
43
+ flushP;
44
+ constructor(opts) {
45
+ super({
46
+ runId: opts.runId,
47
+ terminal: 'running',
48
+ output: '',
49
+ stderr: '',
50
+ exitCode: null,
51
+ command: opts.command,
52
+ }, {
53
+ connector: opts.connector,
54
+ chatId: opts.chatId,
55
+ replyTo: opts.replyTo,
56
+ renderOptions: opts.renderOptions,
57
+ startTimeoutMs: opts.startTimeoutMs,
58
+ settleTimeoutMs: opts.settleTimeoutMs,
59
+ });
60
+ this.coalesceMs = opts.coalesceMs ?? 100;
61
+ }
62
+ get logPrefix() {
63
+ return '[bash-card]';
64
+ }
65
+ get errorPrefix() {
66
+ return 'bash card';
67
+ }
68
+ renderCard(state, options) {
69
+ return renderBashCard(state, options);
70
+ }
71
+ hasOwnBudgetProtection() {
72
+ // renderBashCard 自带 stringify 级 degraded/extreme fallback 预算保护
73
+ // (与 renderRunCard 对称),保证返回卡 ≤28KB 且保留 command/exitCode。
74
+ // enforceCardBudget 是会话事件面板专用的静态裁剪层,对 bash 卡的普通
75
+ // markdownDiv output 是 misfit(超限时极端降级丢 command/exitCode),bash
76
+ // 卡应跳过它,靠自身 renderer 保护。
77
+ return true;
78
+ }
79
+ /** Patch the card with updated bash state (e.g. new stdout/stderr). */
80
+ async update(patch) {
81
+ this.state = this.applyCap(patch);
82
+ if (this.coalesceMs <= 0) {
83
+ await this.flush();
84
+ return;
85
+ }
86
+ this.scheduleFlush();
87
+ }
88
+ /** Transition to a terminal state and patch the card. */
89
+ async finish(terminal, meta = {}) {
90
+ this.cancelPendingFlush();
91
+ // 若有 in-flight flush 正在 await updateCard,必须等它完成后再发终态 patch,
92
+ // 保证顺序(pre-terminal 先落地 → terminal 后落地 → terminal 胜出)。
93
+ if (this.flushP)
94
+ await this.flushP;
95
+ this.state = {
96
+ ...this.state,
97
+ terminal,
98
+ ...(meta.exitCode !== undefined ? { exitCode: meta.exitCode } : {}),
99
+ ...(meta.stderr !== undefined ? { stderr: capBashOutput(meta.stderr) } : {}),
100
+ ...(meta.output !== undefined ? { output: capBashOutput(meta.output) } : {}),
101
+ };
102
+ await this.updateCard();
103
+ this.release();
104
+ }
105
+ /**
106
+ * 调度一次延迟 flush:已有 pending 调度则复用(合批核心);flushInFlight 期间
107
+ * 不再起 timer(防重入叠加),但置 pendingReschedule 让 in-flight 完成后补渲染。
108
+ */
109
+ scheduleFlush() {
110
+ if (this.flushTimer)
111
+ return;
112
+ if (this.flushInFlight) {
113
+ this.pendingReschedule = true;
114
+ return;
115
+ }
116
+ this.flushTimer = setTimeout(() => {
117
+ this.flushTimer = undefined;
118
+ void this.flush();
119
+ }, this.coalesceMs);
120
+ }
121
+ /** 执行一次 render + updateCard(合批窗口到期或 finish 即时 flush 时调用)。 */
122
+ async flush() {
123
+ if (this.flushInFlight)
124
+ return;
125
+ // 终态守卫:finish 已把 state 转终态后,in-flight/延迟 flush 不再用旧 state patch
126
+ if (this.state.terminal !== 'running')
127
+ return;
128
+ this.flushInFlight = true;
129
+ const flushPromise = (async () => {
130
+ try {
131
+ await this.updateCard();
132
+ }
133
+ finally {
134
+ this.flushInFlight = false;
135
+ this.flushP = undefined;
136
+ // in-flight 期间若有 update 到达(pendingReschedule),重新调度一次渲染
137
+ if (this.pendingReschedule) {
138
+ this.pendingReschedule = false;
139
+ this.scheduleFlush();
140
+ }
141
+ }
142
+ })();
143
+ this.flushP = flushPromise;
144
+ return flushPromise;
145
+ }
146
+ /** 取消待 flush 的合批调度(finish/settle 前清理,避免延迟 update 与终态竞争)。 */
147
+ cancelPendingFlush() {
148
+ this.pendingReschedule = false;
149
+ if (this.flushTimer) {
150
+ clearTimeout(this.flushTimer);
151
+ this.flushTimer = undefined;
152
+ return true;
153
+ }
154
+ return false;
155
+ }
156
+ /** settle 前兜底取消合批调度,避免 release 后 dangling timer 更新已释放的 stream。 */
157
+ async settle() {
158
+ this.cancelPendingFlush();
159
+ return super.settle();
160
+ }
161
+ /**
162
+ * 合并 patch 并对 output/stderr 做 store-time 截断(P1-3 层①)。
163
+ * 截断发生在入口(store 时),渲染层无需再为大 state 付代价。
164
+ */
165
+ applyCap(patch) {
166
+ return {
167
+ ...this.state,
168
+ ...patch,
169
+ ...(patch.output !== undefined ? { output: capBashOutput(patch.output) } : {}),
170
+ ...(patch.stderr !== undefined ? { stderr: capBashOutput(patch.stderr) } : {}),
171
+ };
172
+ }
173
+ }
174
+ //# sourceMappingURL=bash-card-session.js.map
@@ -0,0 +1,24 @@
1
+ import type { RunCardRenderOptions } from './run-renderer.js';
2
+ export interface BashRenderOptions extends RunCardRenderOptions {
3
+ }
4
+ /**
5
+ * Minimal card state for bash command output.
6
+ */
7
+ export interface BashState {
8
+ runId: string;
9
+ terminal: 'running' | 'done' | 'error' | 'interrupted';
10
+ output: string;
11
+ stderr: string;
12
+ exitCode: number | null;
13
+ command: string;
14
+ }
15
+ /**
16
+ * Render a bash command output card (CardKit 2.0).
17
+ *
18
+ * 自带 stringify 级预算保护(与 renderRunCard 对称):
19
+ * - 正常路径:output/stderr 各 ≤ OUTPUT_MAX_BYTES,组装后检查总卡字节
20
+ * - 超限 → degraded:output/stderr 各截到 DEGRADED_OUTPUT_BYTES 重新组装
21
+ * - 仍超限 → extreme:省略 output/stderr,保留 command + exitCode + 提示
22
+ * 所有返回路径保证 ≤ CARD_BUDGET_BYTES 且保留 command 与 exitCode(终态)。
23
+ */
24
+ export declare function renderBashCard(state: BashState, _options?: BashRenderOptions): object;
@@ -0,0 +1,187 @@
1
+ import { terminalToColor, terminalToLabel, stopButton } from './card-shared.js';
2
+ import { markdownDiv } from './collapsible.js';
3
+ import { truncateUtf8 } from './text-truncate.js';
4
+ /**
5
+ * 飞书卡片大小限制(安全阈值,与 run-renderer 一致)。
6
+ * 本地定义,不从 card-budget.ts 导入(避免流式/静态耦合)。
7
+ */
8
+ const CARD_BUDGET_BYTES = 28_000;
9
+ /**
10
+ * 单个输出字段的默认最大字节数(保守值,用于正常路径)。
11
+ * 飞书卡片限制约 28KB,留余量给卡片其他部分(header、status row、footer)
12
+ * output + stderr 各自截断,组合后不超过限制(约 28KB - 2KB = 26KB)
13
+ * 每个字段上限 12KB 可确保组合不超限。
14
+ */
15
+ const OUTPUT_MAX_BYTES = 12_000;
16
+ /**
17
+ * Degraded 路径:output/stderr 各自更保守的上限。
18
+ * 高转义字符 JSON.stringify 膨胀约 1.8x,4KB 原始 → ~7.2KB JSON,
19
+ * 两字段合计 ~14.4KB,加 header/status/footer 余量充足。
20
+ */
21
+ const DEGRADED_OUTPUT_BYTES = 4_000;
22
+ /**
23
+ * Truncate long commands for display.
24
+ */
25
+ function truncateCommand(cmd, maxLen = 40) {
26
+ if (cmd.length <= maxLen)
27
+ return cmd;
28
+ return cmd.slice(0, maxLen - 3) + '...';
29
+ }
30
+ /**
31
+ * Build the status row (status tag + command) element.
32
+ */
33
+ function buildStatusRow(state) {
34
+ const { terminal, exitCode, command } = state;
35
+ const statusLabel = bashStatusTagLabel(terminal, exitCode);
36
+ return {
37
+ tag: 'column_set',
38
+ columns: [
39
+ {
40
+ tag: 'column',
41
+ width: 'auto',
42
+ elements: [{ tag: 'div', text: { content: statusLabel, tag: 'lark_md' } }],
43
+ },
44
+ {
45
+ tag: 'column',
46
+ width: 'grow',
47
+ elements: [
48
+ { tag: 'div', text: { content: `⏱ ${truncateCommand(command, 40)}`, tag: 'lark_md' } },
49
+ ],
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ /**
55
+ * Build the exit code footer elements (terminal states only).
56
+ */
57
+ function buildExitFooter(state) {
58
+ if (state.terminal === 'running')
59
+ return [];
60
+ const statusText = state.exitCode !== null
61
+ ? `退出码: ${state.exitCode}`
62
+ : state.terminal === 'interrupted'
63
+ ? '已手动终止'
64
+ : '已完成';
65
+ return [{ tag: 'hr' }, markdownDiv(statusText)];
66
+ }
67
+ /**
68
+ * Assemble the card JSON from elements.
69
+ */
70
+ function assembleCard(state, elements) {
71
+ return {
72
+ schema: '2.0',
73
+ config: { wide_screen_mode: true, update_multi: true },
74
+ header: {
75
+ template: bashHeaderTemplate2(state.terminal),
76
+ title: { content: bashHeaderTitle2(state.terminal), tag: 'plain_text' },
77
+ },
78
+ body: { elements },
79
+ };
80
+ }
81
+ /**
82
+ * Build elements for the normal path: full output/stderr (each ≤ OUTPUT_MAX_BYTES).
83
+ */
84
+ function buildNormalElements(state) {
85
+ const { terminal, runId, output, stderr } = state;
86
+ const elements = [buildStatusRow(state)];
87
+ const truncatedOutput = output
88
+ ? truncateUtf8(output, OUTPUT_MAX_BYTES, true, '…(输出已截断,共 ' + output.length + ' 字符)')
89
+ : '';
90
+ const truncatedStderr = stderr
91
+ ? truncateUtf8(stderr, OUTPUT_MAX_BYTES, true, '…(诊断输出已截断,共 ' + stderr.length + ' 字符)')
92
+ : '';
93
+ if (truncatedOutput)
94
+ elements.push(markdownDiv(`\`\`\`\n${truncatedOutput}\n\`\`\``));
95
+ if (truncatedStderr)
96
+ elements.push(markdownDiv(`📋 诊断输出:\n\`\`\`\n${truncatedStderr}\n\`\`\``));
97
+ if (terminal === 'running') {
98
+ elements.push({ tag: 'div', text: { content: '‎', tag: 'lark_md' } }, stopButton(runId));
99
+ }
100
+ elements.push(...buildExitFooter(state));
101
+ return elements;
102
+ }
103
+ /**
104
+ * Build elements for the degraded path: output/stderr truncated to a smaller
105
+ * budget. Preserves command (status row) and exitCode (footer).
106
+ */
107
+ function buildDegradedElements(state) {
108
+ const { terminal, runId, output, stderr } = state;
109
+ const elements = [buildStatusRow(state)];
110
+ const truncatedOutput = output
111
+ ? truncateUtf8(output, DEGRADED_OUTPUT_BYTES, true, '…(输出已截断,共 ' + output.length + ' 字符)')
112
+ : '';
113
+ const truncatedStderr = stderr
114
+ ? truncateUtf8(stderr, DEGRADED_OUTPUT_BYTES, true, '…(诊断输出已截断,共 ' + stderr.length + ' 字符)')
115
+ : '';
116
+ if (truncatedOutput)
117
+ elements.push(markdownDiv(`\`\`\`\n${truncatedOutput}\n\`\`\``));
118
+ if (truncatedStderr)
119
+ elements.push(markdownDiv(`📋 诊断输出:\n\`\`\`\n${truncatedStderr}\n\`\`\``));
120
+ if (terminal === 'running') {
121
+ elements.push({ tag: 'div', text: { content: '‎', tag: 'lark_md' } }, stopButton(runId));
122
+ }
123
+ elements.push(...buildExitFooter(state));
124
+ return elements;
125
+ }
126
+ /**
127
+ * Build elements for the extreme fallback: no output/stderr body, only
128
+ * status row (command) + exit footer + "output too large" hint.
129
+ * Guarantees a minimal card that still preserves command and exitCode.
130
+ */
131
+ function buildExtremeFallbackElements(state) {
132
+ const { terminal, runId } = state;
133
+ const elements = [buildStatusRow(state)];
134
+ elements.push(markdownDiv('_⚠️ 输出过大已省略_'));
135
+ if (terminal === 'running') {
136
+ elements.push({ tag: 'div', text: { content: '‎', tag: 'lark_md' } }, stopButton(runId));
137
+ }
138
+ elements.push(...buildExitFooter(state));
139
+ return elements;
140
+ }
141
+ /**
142
+ * Render a bash command output card (CardKit 2.0).
143
+ *
144
+ * 自带 stringify 级预算保护(与 renderRunCard 对称):
145
+ * - 正常路径:output/stderr 各 ≤ OUTPUT_MAX_BYTES,组装后检查总卡字节
146
+ * - 超限 → degraded:output/stderr 各截到 DEGRADED_OUTPUT_BYTES 重新组装
147
+ * - 仍超限 → extreme:省略 output/stderr,保留 command + exitCode + 提示
148
+ * 所有返回路径保证 ≤ CARD_BUDGET_BYTES 且保留 command 与 exitCode(终态)。
149
+ */
150
+ export function renderBashCard(state, _options = {}) {
151
+ // Normal path
152
+ const card = assembleCard(state, buildNormalElements(state));
153
+ if (Buffer.byteLength(JSON.stringify(card), 'utf8') <= CARD_BUDGET_BYTES)
154
+ return card;
155
+ // Degraded: shrink output/stderr budgets
156
+ const degradedCard = assembleCard(state, buildDegradedElements(state));
157
+ if (Buffer.byteLength(JSON.stringify(degradedCard), 'utf8') <= CARD_BUDGET_BYTES) {
158
+ return degradedCard;
159
+ }
160
+ // Extreme fallback: drop output/stderr, keep command + exitCode + hint
161
+ return assembleCard(state, buildExtremeFallbackElements(state));
162
+ }
163
+ /** Bash status tag label */
164
+ function bashStatusTagLabel(terminal, exitCode) {
165
+ if (terminal === 'running' || terminal === 'interrupted')
166
+ return terminalToLabel(terminal);
167
+ if (exitCode === 0)
168
+ return '成功';
169
+ if (exitCode !== null)
170
+ return '失败';
171
+ return '出错';
172
+ }
173
+ /** CardKit 2.0 header title */
174
+ function bashHeaderTitle2(terminal) {
175
+ if (terminal === 'running')
176
+ return '💻 执行命令...';
177
+ if (terminal === 'error')
178
+ return '❌ 命令执行失败';
179
+ if (terminal === 'interrupted')
180
+ return '⏹ 已终止';
181
+ return '✅ 命令执行完成';
182
+ }
183
+ /** CardKit 2.0 header template */
184
+ function bashHeaderTemplate2(terminal) {
185
+ return terminalToColor(terminal);
186
+ }
187
+ //# sourceMappingURL=bash-renderer.js.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 静态卡片体积保护
3
+ *
4
+ * 用于:auto-resume, /active, completion notification 等静态卡片
5
+ * 不适用于:run-renderer 的流式卡片(已有独立保护)
6
+ *
7
+ * Docs: https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukz/feishu-cards/card-components/containers/collapsible-panel
8
+ */
9
+ interface CardBudgetOptions {
10
+ /** 最大事件面板数量(保留最新的) */
11
+ maxEventPanels?: number;
12
+ /** 单个面板内容最大字节数 */
13
+ maxPanelContentBytes?: number;
14
+ /** 截断提示文本 */
15
+ truncationHint?: string;
16
+ }
17
+ /**
18
+ * 静态卡片体积保护
19
+ *
20
+ * @param card - 原始卡片 JSON
21
+ * @param opts - 裁剪选项
22
+ * @returns 裁剪后的卡片 + 是否发生了裁剪 + 原因 + 截断前后字节数
23
+ */
24
+ export declare function enforceCardBudget(card: object, opts?: CardBudgetOptions): {
25
+ card: object;
26
+ wasTruncated: boolean;
27
+ reason?: string;
28
+ bytesBefore: number;
29
+ bytesAfter: number;
30
+ };
31
+ export {};