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,249 @@
1
+ /**
2
+ * Accumulates pi's incremental message_update events and emits normalized
3
+ * AgentEvents. Content mapping: text→TextContent, thinking→ThinkingContent,
4
+ * toolCall→ToolUseContent (input:arguments), toolResult→ToolResultContent.
5
+ *
6
+ * Implements RunnerTranslator so the base SpawningRunner can drive it
7
+ * uniformly. pi has no agent-reported terminal error (no equivalent of codex
8
+ * `turn.failed`), so isTerminal/finish/getTerminalError/hasAgentTerminalError
9
+ * are no-ops — pi relies entirely on the base class's signal/code-based
10
+ * result event classification.
11
+ */
12
+ export class PiEventAccumulator {
13
+ content = [];
14
+ currentContentIndex = -1;
15
+ sessionId = '';
16
+ /**
17
+ * Accumulated (summed) token usage across all assistant messages in this run.
18
+ * pi emits per-message (non-cumulative) usage on each assistant `message_end`;
19
+ * summing yields the run's total consumption, aligned with ccusage (which sums
20
+ * per-message entries).
21
+ * `totalTokens` is NOT summed: it tracks the last message's total as the
22
+ * context-length water level (summing would overcount - design.md §usage:
23
+ * "N turn 累加得 N×context 虚假巨值").
24
+ */
25
+ accInput = 0;
26
+ accOutput = 0;
27
+ accCacheRead = 0;
28
+ accCacheCreation = 0;
29
+ lastTotalTokens;
30
+ /** stopReason of the most recent assistant message_end. "error" indicates a
31
+ * provider/LLM failure (pi retries internally; a later message_end may
32
+ * overwrite this with "stop" on eventual success). */
33
+ lastAssistantStopReason;
34
+ /** errorMessage paired with the last assistant message_end whose
35
+ * stopReason==="error". Surfaces the provider's failure text (e.g.
36
+ * "Connection error.") to the user via the result event. */
37
+ lastAssistantErrorMessage;
38
+ translate(raw) {
39
+ return this.normalize(raw);
40
+ }
41
+ isTerminal() {
42
+ // pi has no terminal event — agent_end is non-terminal (the process
43
+ // continues until exit). The base class's result event is the terminal.
44
+ return false;
45
+ }
46
+ finish(_reason) {
47
+ // No-op: pi has no stream-ended-early terminal error to record.
48
+ // The base class's signal/code-based result event handles all cases.
49
+ }
50
+ getTerminalError() {
51
+ // Surface provider/LLM failures reported via stopReason="error" on the
52
+ // final assistant message_end. pi has no other agent-reported terminal
53
+ // error; this lets SpawningRunner produce an error result event instead
54
+ // of a silent "success" with empty content.
55
+ // Empty-string errorMessage is treated as missing (defensive against
56
+ // providers that return stopReason="error" with no message) — fall back
57
+ // to a non-empty sentinel so the run card never shows an empty error.
58
+ if (this.lastAssistantStopReason === 'error') {
59
+ const msg = this.lastAssistantErrorMessage;
60
+ return msg && msg.trim() ? msg : 'pi reported an error';
61
+ }
62
+ return undefined;
63
+ }
64
+ hasAgentTerminalError() {
65
+ // True when the most recent assistant message_end reported stopReason
66
+ // "error" (provider/LLM failure). pi retries internally; if a later
67
+ // message_end succeeds, lastAssistantStopReason is overwritten to "stop"
68
+ // and this returns false — so transient retries that eventually succeed
69
+ // are NOT misclassified as errors.
70
+ return this.lastAssistantStopReason === 'error';
71
+ }
72
+ getSessionId() {
73
+ return this.sessionId;
74
+ }
75
+ getLastUsage() {
76
+ if (this.accInput === 0 &&
77
+ this.accOutput === 0 &&
78
+ this.accCacheRead === 0 &&
79
+ this.accCacheCreation === 0 &&
80
+ this.lastTotalTokens === undefined) {
81
+ return undefined;
82
+ }
83
+ return {
84
+ input_tokens: this.accInput,
85
+ output_tokens: this.accOutput,
86
+ cache_read_tokens: this.accCacheRead,
87
+ cache_creation_tokens: this.accCacheCreation,
88
+ ...(this.lastTotalTokens != null ? { total_tokens: this.lastTotalTokens } : {}),
89
+ };
90
+ }
91
+ /** Accumulate a per-message usage record into the run's cumulative totals. */
92
+ addUsage(u) {
93
+ this.accInput += u.input ?? 0;
94
+ this.accOutput += u.output ?? 0;
95
+ this.accCacheRead += u.cacheRead ?? 0;
96
+ this.accCacheCreation += u.cacheWrite ?? 0;
97
+ if (u.totalTokens != null) {
98
+ this.lastTotalTokens = u.totalTokens;
99
+ }
100
+ }
101
+ normalize(raw) {
102
+ switch (raw.type) {
103
+ case 'session': {
104
+ const s = raw;
105
+ this.sessionId = s.id;
106
+ return {
107
+ type: 'system',
108
+ subtype: 'init',
109
+ session_id: s.id,
110
+ cwd: s.cwd,
111
+ model: s.model ?? '',
112
+ timestamp: new Date().toISOString(),
113
+ };
114
+ }
115
+ case 'message_start': {
116
+ const m = raw.message;
117
+ if (m.role === 'assistant') {
118
+ // Initialize accumulator for new assistant message
119
+ this.content = [];
120
+ this.currentContentIndex = -1;
121
+ }
122
+ return null;
123
+ }
124
+ case 'message_update': {
125
+ const evt = raw.assistantMessageEvent;
126
+ this.applyUpdate(evt);
127
+ return null;
128
+ }
129
+ case 'message_end': {
130
+ const m = raw.message;
131
+ if (m.role === 'assistant') {
132
+ // Record provider/LLM failure signal: pi emits stopReason="error"
133
+ // with an errorMessage on transient provider outages. A subsequent
134
+ // successful message_end (stopReason="stop" after internal retry)
135
+ // overwrites these, so only the final state decides terminal error.
136
+ this.lastAssistantStopReason = m.stopReason;
137
+ if (m.stopReason === 'error') {
138
+ this.lastAssistantErrorMessage = m.errorMessage;
139
+ }
140
+ else {
141
+ this.lastAssistantErrorMessage = undefined;
142
+ }
143
+ // Emit accumulated AssistantEvent
144
+ const event = {
145
+ type: 'assistant',
146
+ message: { content: this.content },
147
+ timestamp: new Date().toISOString(),
148
+ };
149
+ this.content = [];
150
+ this.currentContentIndex = -1;
151
+ // Accumulate per-message usage (ccusage-aligned: input is non-cached).
152
+ if (m.usage) {
153
+ this.addUsage(m.usage);
154
+ }
155
+ return event;
156
+ }
157
+ if (m.role === 'toolResult') {
158
+ // Emit UserEvent with tool_result content
159
+ const toolResultContent = this.normalizeToolResult(m);
160
+ const event = {
161
+ type: 'user',
162
+ message: { content: [toolResultContent] },
163
+ timestamp: new Date().toISOString(),
164
+ };
165
+ return event;
166
+ }
167
+ return null;
168
+ }
169
+ case 'turn_end': {
170
+ // pi 0.80+ `message_end` always carries usage; `turn_end` is a no-op.
171
+ return null;
172
+ }
173
+ case 'agent_end': {
174
+ // P2#6: do NOT emit result here — base class emits after exit-code check.
175
+ return null;
176
+ }
177
+ default:
178
+ // Ignore unknown event types (agent_start, turn_start, tool_execution_*, etc.)
179
+ return null;
180
+ }
181
+ }
182
+ applyUpdate(evt) {
183
+ switch (evt.type) {
184
+ case 'text_start':
185
+ this.content.push({ type: 'text', text: '' });
186
+ this.currentContentIndex++;
187
+ break;
188
+ case 'text_delta':
189
+ if (this.currentContentIndex >= 0 &&
190
+ this.content[this.currentContentIndex]?.type === 'text') {
191
+ this.content[this.currentContentIndex].text += evt.delta ?? '';
192
+ }
193
+ break;
194
+ case 'text_end':
195
+ if (this.currentContentIndex >= 0 &&
196
+ this.content[this.currentContentIndex]?.type === 'text' &&
197
+ evt.content) {
198
+ this.content[this.currentContentIndex].text = evt.content;
199
+ }
200
+ break;
201
+ case 'thinking_start':
202
+ this.content.push({ type: 'thinking', thinking: '' });
203
+ this.currentContentIndex++;
204
+ break;
205
+ case 'thinking_delta':
206
+ if (this.currentContentIndex >= 0 &&
207
+ this.content[this.currentContentIndex]?.type === 'thinking') {
208
+ this.content[this.currentContentIndex].thinking +=
209
+ evt.delta ?? '';
210
+ }
211
+ break;
212
+ case 'thinking_end':
213
+ if (this.currentContentIndex >= 0 &&
214
+ this.content[this.currentContentIndex]?.type === 'thinking' &&
215
+ evt.content) {
216
+ this.content[this.currentContentIndex].thinking = evt.content;
217
+ }
218
+ break;
219
+ case 'toolcall_start':
220
+ this.content.push({ type: 'tool_use', id: '', name: '', input: {} });
221
+ this.currentContentIndex++;
222
+ break;
223
+ case 'toolcall_end':
224
+ if (this.currentContentIndex >= 0 &&
225
+ this.content[this.currentContentIndex]?.type === 'tool_use' &&
226
+ evt.toolCall) {
227
+ this.content[this.currentContentIndex] = {
228
+ type: 'tool_use',
229
+ id: evt.toolCall.id,
230
+ name: evt.toolCall.name,
231
+ input: evt.toolCall.arguments,
232
+ };
233
+ }
234
+ break;
235
+ default:
236
+ // toolcall_delta: pi provides complete arguments at toolcall_end, ignore delta
237
+ break;
238
+ }
239
+ }
240
+ normalizeToolResult(msg) {
241
+ return {
242
+ type: 'tool_result',
243
+ tool_use_id: msg.toolCallId ?? '',
244
+ content: msg.content ?? '',
245
+ is_error: msg.isError ?? false,
246
+ };
247
+ }
248
+ }
249
+ //# sourceMappingURL=jsonl.js.map
@@ -0,0 +1,37 @@
1
+ import type { AgentRunner, AgentSessionReader, SpawnOptions, AgentStatusInfo } from '../types.js';
2
+ import { SpawningRunner, type RunnerTranslator } from '../common/spawning-runner.js';
3
+ interface PiRunnerConfig {
4
+ binary?: string;
5
+ provider?: string;
6
+ model?: string;
7
+ thinking?: string;
8
+ tools?: string[];
9
+ stopGraceMs?: number;
10
+ pidDir?: string;
11
+ workspace: string;
12
+ spawnHeartbeatMs?: number;
13
+ sessionReader?: AgentSessionReader;
14
+ }
15
+ /**
16
+ * PiRunner: spawn-per-message runner using `pi --mode json -p <prompt> ...`.
17
+ *
18
+ * Inherits the spawn + completion + cleanup orchestration from SpawningRunner.
19
+ * This subclass overrides only the createTranslator()
20
+ * hook to return a PiEventAccumulator (which implements RunnerTranslator).
21
+ * Pi uses the default JSONL stream reader (createJSONLStream) and the default
22
+ * stdio ['ignore','pipe','pipe'] — no stdin writing, no env sync.
23
+ */
24
+ export declare class PiRunner extends SpawningRunner implements AgentRunner {
25
+ readonly kind: "pi";
26
+ readonly sessionReader: AgentSessionReader;
27
+ private provider;
28
+ private defaultModel;
29
+ private thinking;
30
+ private tools;
31
+ constructor(opts: PiRunnerConfig);
32
+ get pid(): number | undefined;
33
+ getStatusInfo(): AgentStatusInfo;
34
+ protected buildArgv(opts: SpawnOptions): string[];
35
+ protected createTranslator(_opts: SpawnOptions): RunnerTranslator;
36
+ }
37
+ export {};
@@ -0,0 +1,76 @@
1
+ import { SpawningRunner } from '../common/spawning-runner.js';
2
+ import { PiEventAccumulator } from './jsonl.js';
3
+ /**
4
+ * PiRunner: spawn-per-message runner using `pi --mode json -p <prompt> ...`.
5
+ *
6
+ * Inherits the spawn + completion + cleanup orchestration from SpawningRunner.
7
+ * This subclass overrides only the createTranslator()
8
+ * hook to return a PiEventAccumulator (which implements RunnerTranslator).
9
+ * Pi uses the default JSONL stream reader (createJSONLStream) and the default
10
+ * stdio ['ignore','pipe','pipe'] — no stdin writing, no env sync.
11
+ */
12
+ export class PiRunner extends SpawningRunner {
13
+ kind = 'pi';
14
+ sessionReader;
15
+ provider;
16
+ defaultModel;
17
+ thinking;
18
+ tools;
19
+ constructor(opts) {
20
+ super({
21
+ binary: opts.binary ?? 'pi',
22
+ pidDir: opts.pidDir,
23
+ workspace: opts.workspace,
24
+ stopGraceMs: opts.stopGraceMs,
25
+ spawnHeartbeatMs: opts.spawnHeartbeatMs,
26
+ pidFilePrefix: 'pi',
27
+ logTag: 'pi-runner',
28
+ });
29
+ this.provider = opts.provider ?? 'Volcano';
30
+ this.defaultModel = opts.model ?? 'glm-5.2';
31
+ this.thinking = opts.thinking ?? 'medium';
32
+ this.tools = opts.tools ?? ['read', 'bash', 'edit', 'write', 'grep', 'find', 'ls'];
33
+ this.sessionReader = opts.sessionReader ?? {
34
+ listSessions: () => ({ sessions: [], total: 0 }),
35
+ getNewestSession: () => null,
36
+ readSessionContent: () => ({ events: [] }),
37
+ isSessionActive: () => false,
38
+ };
39
+ }
40
+ get pid() {
41
+ return this.currentProcess?.pid;
42
+ }
43
+ getStatusInfo() {
44
+ return {
45
+ kind: 'pi',
46
+ model: this.defaultModel,
47
+ provider: this.provider,
48
+ reasoning: this.thinking,
49
+ };
50
+ }
51
+ buildArgv(opts) {
52
+ const args = [
53
+ '--mode',
54
+ 'json',
55
+ '-p',
56
+ this.currentMessage,
57
+ '--provider',
58
+ this.provider,
59
+ '--model',
60
+ opts.model ?? this.defaultModel,
61
+ '--tools',
62
+ this.tools.join(','),
63
+ ];
64
+ if (opts.sessionId)
65
+ args.push('--session-id', opts.sessionId);
66
+ if (this.thinking && this.thinking !== 'off')
67
+ args.push('--thinking', this.thinking);
68
+ return args;
69
+ }
70
+ // --- Hooks ---
71
+ createTranslator(_opts) {
72
+ // Fresh accumulator per run (stateful: content buffer, sessionId, lastUsage).
73
+ return new PiEventAccumulator();
74
+ }
75
+ }
76
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1,54 @@
1
+ import type { AgentKind, AgentRunner } from './index.js';
2
+ /**
3
+ * Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
4
+ * factory per available agent at startup; `Bridge.getRunner(workspace)` looks
5
+ * up `config.defaultAgent` here to pick the concrete runner.
6
+ *
7
+ * Singleton caching: the factory MAY cache its instance internally. All
8
+ * current agents (claude, codex, opencode, pi, kimi) are spawn-per-message,
9
+ * so per-workspace instantiation has no cost; each factory returns a fresh
10
+ * runner per call.
11
+ *
12
+ * Dynamic config reload: factory can read latest config via registry's
13
+ * configContainer, enabling runtime config changes to take effect.
14
+ */
15
+ export declare class AgentRegistry {
16
+ private readonly factories;
17
+ private readonly displayNames;
18
+ /** Container for runtime config updates (pi provider dynamic reload). */
19
+ private configContainer?;
20
+ register(kind: AgentKind, factory: (workspace: string) => AgentRunner): void;
21
+ /**
22
+ * 注册 agent 的显示名。应在 register(kind, factory) 后调用。
23
+ * 用于 agentDisplayName 等全局查询,实现单点真相。
24
+ */
25
+ registerDisplayName(kind: AgentKind, displayName: string): void;
26
+ /**
27
+ * 获取 agent 显示名。未注册时返回原始 kind。
28
+ */
29
+ getDisplayName(kind: AgentKind): string;
30
+ /**
31
+ * 设置全局 registry 实例,供 agentDisplayName 等全局函数使用。
32
+ * 在 index.ts 初始化所有 agents 后调用。
33
+ */
34
+ static setGlobalInstance(reg: AgentRegistry): void;
35
+ /**
36
+ * 获取全局 registry 实例。
37
+ */
38
+ static getGlobalInstance(): AgentRegistry | undefined;
39
+ /**
40
+ * Set config container reference. Call after bridge config is updated.
41
+ * Factory functions can read latest config from here.
42
+ */
43
+ setConfigContainer(container: {
44
+ current: unknown;
45
+ }): void;
46
+ /**
47
+ * Get the config container for factory functions to read latest config.
48
+ * Returns undefined if not set.
49
+ */
50
+ getConfigContainer(): {
51
+ current: unknown;
52
+ } | undefined;
53
+ get(kind: AgentKind, workspace: string): AgentRunner;
54
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * 单例 registry 实例,供 agentDisplayName 等全局查询使用。
3
+ * 在 index.ts 初始化后设置。
4
+ */
5
+ let globalRegistry;
6
+ /**
7
+ * Registry of agent factories, keyed by `AgentKind`. `index.ts` registers one
8
+ * factory per available agent at startup; `Bridge.getRunner(workspace)` looks
9
+ * up `config.defaultAgent` here to pick the concrete runner.
10
+ *
11
+ * Singleton caching: the factory MAY cache its instance internally. All
12
+ * current agents (claude, codex, opencode, pi, kimi) are spawn-per-message,
13
+ * so per-workspace instantiation has no cost; each factory returns a fresh
14
+ * runner per call.
15
+ *
16
+ * Dynamic config reload: factory can read latest config via registry's
17
+ * configContainer, enabling runtime config changes to take effect.
18
+ */
19
+ export class AgentRegistry {
20
+ factories = new Map();
21
+ displayNames = new Map();
22
+ /** Container for runtime config updates (pi provider dynamic reload). */
23
+ configContainer;
24
+ register(kind, factory) {
25
+ this.factories.set(kind, factory);
26
+ }
27
+ /**
28
+ * 注册 agent 的显示名。应在 register(kind, factory) 后调用。
29
+ * 用于 agentDisplayName 等全局查询,实现单点真相。
30
+ */
31
+ registerDisplayName(kind, displayName) {
32
+ this.displayNames.set(kind, displayName);
33
+ }
34
+ /**
35
+ * 获取 agent 显示名。未注册时返回原始 kind。
36
+ */
37
+ getDisplayName(kind) {
38
+ return this.displayNames.get(kind) ?? kind;
39
+ }
40
+ /**
41
+ * 设置全局 registry 实例,供 agentDisplayName 等全局函数使用。
42
+ * 在 index.ts 初始化所有 agents 后调用。
43
+ */
44
+ static setGlobalInstance(reg) {
45
+ globalRegistry = reg;
46
+ }
47
+ /**
48
+ * 获取全局 registry 实例。
49
+ */
50
+ static getGlobalInstance() {
51
+ return globalRegistry;
52
+ }
53
+ /**
54
+ * Set config container reference. Call after bridge config is updated.
55
+ * Factory functions can read latest config from here.
56
+ */
57
+ setConfigContainer(container) {
58
+ this.configContainer = container;
59
+ }
60
+ /**
61
+ * Get the config container for factory functions to read latest config.
62
+ * Returns undefined if not set.
63
+ */
64
+ getConfigContainer() {
65
+ return this.configContainer;
66
+ }
67
+ get(kind, workspace) {
68
+ const factory = this.factories.get(kind);
69
+ if (!factory) {
70
+ throw new Error(`agent not registered: ${kind}`);
71
+ }
72
+ return factory(workspace);
73
+ }
74
+ }
75
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Resolve agentChoices into agents config.
3
+ * Priority: explicit agents config > agentChoices > defaults
4
+ * This is called at startup to restore the last used configuration for the current agent.
5
+ */
6
+ import type { AppConfig } from '../config/index.js';
7
+ export declare function resolveAgentChoices(config: AppConfig): AppConfig;
@@ -0,0 +1,76 @@
1
+ export function resolveAgentChoices(config) {
2
+ const choices = config.agentChoices;
3
+ const agent = config.defaultAgent;
4
+ if (!choices || !agent) {
5
+ return config;
6
+ }
7
+ // Skip claude - it's stored at top-level config.claude, not in agentChoices
8
+ if (agent === 'claude') {
9
+ return config;
10
+ }
11
+ const agentChoices = choices[agent];
12
+ if (!agentChoices) {
13
+ return config;
14
+ }
15
+ // Clone to avoid mutation
16
+ const resolved = JSON.parse(JSON.stringify(config));
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const resolvedAny = resolved;
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ const agentChoicesAny = agentChoices;
21
+ switch (agent) {
22
+ case 'codex':
23
+ if (!resolvedAny.agents)
24
+ resolvedAny.agents = {};
25
+ if (!resolvedAny.agents.codex)
26
+ resolvedAny.agents.codex = {};
27
+ if (!resolvedAny.agents.codex.model && agentChoicesAny.model) {
28
+ resolvedAny.agents.codex.model = agentChoicesAny.model;
29
+ }
30
+ if (!resolvedAny.agents.codex.modelProvider && agentChoicesAny.modelProvider) {
31
+ resolvedAny.agents.codex.modelProvider = agentChoicesAny.modelProvider;
32
+ }
33
+ break;
34
+ case 'pi':
35
+ if (!resolvedAny.agents)
36
+ resolvedAny.agents = {};
37
+ if (!resolvedAny.agents.pi)
38
+ resolvedAny.agents.pi = {};
39
+ if (!resolvedAny.agents.pi.model && agentChoicesAny.model) {
40
+ resolvedAny.agents.pi.model = agentChoicesAny.model;
41
+ }
42
+ if (!resolvedAny.agents.pi.provider && agentChoicesAny.provider) {
43
+ resolvedAny.agents.pi.provider = agentChoicesAny.provider;
44
+ }
45
+ if (!resolvedAny.agents.pi.thinking && agentChoicesAny.thinking) {
46
+ resolvedAny.agents.pi.thinking = agentChoicesAny.thinking;
47
+ }
48
+ break;
49
+ case 'opencode':
50
+ if (!resolvedAny.agents)
51
+ resolvedAny.agents = {};
52
+ if (!resolvedAny.agents.opencode)
53
+ resolvedAny.agents.opencode = {};
54
+ if (!resolvedAny.agents.opencode.modelID && agentChoicesAny.modelID) {
55
+ resolvedAny.agents.opencode.modelID = agentChoicesAny.modelID;
56
+ }
57
+ if (!resolvedAny.agents.opencode.providerID && agentChoicesAny.providerID) {
58
+ resolvedAny.agents.opencode.providerID = agentChoicesAny.providerID;
59
+ }
60
+ break;
61
+ case 'kimi':
62
+ if (!resolvedAny.agents)
63
+ resolvedAny.agents = {};
64
+ if (!resolvedAny.agents.kimi)
65
+ resolvedAny.agents.kimi = {};
66
+ if (!resolvedAny.agents.kimi.model && agentChoicesAny.model) {
67
+ resolvedAny.agents.kimi.model = agentChoicesAny.model;
68
+ }
69
+ if (!resolvedAny.agents.kimi.thinkingEffort && agentChoicesAny.thinkingEffort) {
70
+ resolvedAny.agents.kimi.thinkingEffort = agentChoicesAny.thinkingEffort;
71
+ }
72
+ break;
73
+ }
74
+ return resolved;
75
+ }
76
+ //# sourceMappingURL=resolve-agent-choices.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Sync agent configuration to agentChoices.
3
+ * Called when user saves config to remember their choices for quick switching.
4
+ */
5
+ import type { AppConfig } from '../config/index.js';
6
+ export declare function syncAgentChoices(config: AppConfig, agent: string): AppConfig;
@@ -0,0 +1,73 @@
1
+ export function syncAgentChoices(config, agent) {
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ const configAny = config;
4
+ const agents = configAny.agents || {};
5
+ const agentCfg = agents[agent];
6
+ // claude reads from top-level config.claude, not agents.claude
7
+ if (agent !== 'claude' && !agentCfg) {
8
+ return config;
9
+ }
10
+ const updated = JSON.parse(JSON.stringify(config));
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const updatedAny = updated;
13
+ if (!updatedAny.agentChoices) {
14
+ updatedAny.agentChoices = {};
15
+ }
16
+ switch (agent) {
17
+ case 'codex':
18
+ if (agentCfg.model) {
19
+ if (!updatedAny.agentChoices.codex)
20
+ updatedAny.agentChoices.codex = {};
21
+ updatedAny.agentChoices.codex.model = agentCfg.model;
22
+ }
23
+ if (agentCfg.modelProvider) {
24
+ if (!updatedAny.agentChoices.codex)
25
+ updatedAny.agentChoices.codex = {};
26
+ updatedAny.agentChoices.codex.modelProvider = agentCfg.modelProvider;
27
+ }
28
+ break;
29
+ case 'pi':
30
+ if (agentCfg.model) {
31
+ if (!updatedAny.agentChoices.pi)
32
+ updatedAny.agentChoices.pi = {};
33
+ updatedAny.agentChoices.pi.model = agentCfg.model;
34
+ }
35
+ if (agentCfg.provider) {
36
+ if (!updatedAny.agentChoices.pi)
37
+ updatedAny.agentChoices.pi = {};
38
+ updatedAny.agentChoices.pi.provider = agentCfg.provider;
39
+ }
40
+ if (agentCfg.thinking) {
41
+ if (!updatedAny.agentChoices.pi)
42
+ updatedAny.agentChoices.pi = {};
43
+ updatedAny.agentChoices.pi.thinking = agentCfg.thinking;
44
+ }
45
+ break;
46
+ case 'opencode':
47
+ if (agentCfg.modelID) {
48
+ if (!updatedAny.agentChoices.opencode)
49
+ updatedAny.agentChoices.opencode = {};
50
+ updatedAny.agentChoices.opencode.modelID = agentCfg.modelID;
51
+ }
52
+ if (agentCfg.providerID) {
53
+ if (!updatedAny.agentChoices.opencode)
54
+ updatedAny.agentChoices.opencode = {};
55
+ updatedAny.agentChoices.opencode.providerID = agentCfg.providerID;
56
+ }
57
+ break;
58
+ case 'kimi':
59
+ if (agentCfg.model) {
60
+ if (!updatedAny.agentChoices.kimi)
61
+ updatedAny.agentChoices.kimi = {};
62
+ updatedAny.agentChoices.kimi.model = agentCfg.model;
63
+ }
64
+ if (agentCfg.thinkingEffort) {
65
+ if (!updatedAny.agentChoices.kimi)
66
+ updatedAny.agentChoices.kimi = {};
67
+ updatedAny.agentChoices.kimi.thinkingEffort = agentCfg.thinkingEffort;
68
+ }
69
+ break;
70
+ }
71
+ return updated;
72
+ }
73
+ //# sourceMappingURL=sync-agent-choices.js.map