@geteigen/cli 0.0.0-stage → 3.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 (172) hide show
  1. package/README.md +154 -2
  2. package/dist/agent.d.ts +32 -0
  3. package/dist/agent.js +246 -0
  4. package/dist/auth.d.ts +5 -0
  5. package/dist/auth.js +33 -0
  6. package/dist/cli/src/agent.d.ts +24 -0
  7. package/dist/cli/src/agent.js +263 -0
  8. package/dist/cli/src/agentTools.d.ts +6 -0
  9. package/dist/cli/src/agentTools.js +104 -0
  10. package/dist/cli/src/auth.d.ts +5 -0
  11. package/dist/cli/src/auth.js +33 -0
  12. package/dist/cli/src/cliEnv.d.ts +6 -0
  13. package/dist/cli/src/cliEnv.js +26 -0
  14. package/dist/cli/src/config.d.ts +11 -0
  15. package/dist/cli/src/config.js +51 -0
  16. package/dist/cli/src/cursorAuth.d.ts +10 -0
  17. package/dist/cli/src/cursorAuth.js +92 -0
  18. package/dist/cli/src/gitAuthEnv.d.ts +5 -0
  19. package/dist/cli/src/gitAuthEnv.js +35 -0
  20. package/dist/cli/src/index.d.ts +2 -0
  21. package/dist/cli/src/index.js +244 -0
  22. package/dist/cli/src/listModels.d.ts +14 -0
  23. package/dist/cli/src/listModels.js +196 -0
  24. package/dist/cli/src/listSessions.d.ts +9 -0
  25. package/dist/cli/src/listSessions.js +37 -0
  26. package/dist/cli/src/machineConfig.d.ts +20 -0
  27. package/dist/cli/src/machineConfig.js +66 -0
  28. package/dist/cli/src/pickFolder.d.ts +5 -0
  29. package/dist/cli/src/pickFolder.js +65 -0
  30. package/dist/cli/src/proc.d.ts +31 -0
  31. package/dist/cli/src/proc.js +97 -0
  32. package/dist/cli/src/service.d.ts +17 -0
  33. package/dist/cli/src/service.js +255 -0
  34. package/dist/cli/src/workRoots.d.ts +30 -0
  35. package/dist/cli/src/workRoots.js +228 -0
  36. package/dist/cli/src/worker.d.ts +8 -0
  37. package/dist/cli/src/worker.js +51 -0
  38. package/dist/cli/src/workerCore.d.ts +47 -0
  39. package/dist/cli/src/workerCore.js +721 -0
  40. package/dist/cli/src/workspace.d.ts +10 -0
  41. package/dist/cli/src/workspace.js +329 -0
  42. package/dist/config.d.ts +11 -0
  43. package/dist/config.js +51 -0
  44. package/dist/cursorAuth.d.ts +10 -0
  45. package/dist/cursorAuth.js +95 -0
  46. package/dist/index.d.ts +2 -0
  47. package/dist/index.js +108 -0
  48. package/dist/listModels.d.ts +6 -0
  49. package/dist/listModels.js +62 -0
  50. package/dist/listSessions.d.ts +9 -0
  51. package/dist/listSessions.js +37 -0
  52. package/dist/pickFolder.d.ts +5 -0
  53. package/dist/pickFolder.js +65 -0
  54. package/dist/shared/actionDrafts.d.ts +83 -0
  55. package/dist/shared/actionDrafts.js +169 -0
  56. package/dist/shared/agentArtifacts.d.ts +49 -0
  57. package/dist/shared/agentArtifacts.js +169 -0
  58. package/dist/shared/agentLabel.d.ts +18 -0
  59. package/dist/shared/agentLabel.js +22 -0
  60. package/dist/shared/agentMentions.d.ts +38 -0
  61. package/dist/shared/agentMentions.js +110 -0
  62. package/dist/shared/agentRepos.d.ts +28 -0
  63. package/dist/shared/agentRepos.js +60 -0
  64. package/dist/shared/agentRunStatus.d.ts +12 -0
  65. package/dist/shared/agentRunStatus.js +17 -0
  66. package/dist/shared/agentUsage.d.ts +24 -0
  67. package/dist/shared/agentUsage.js +139 -0
  68. package/dist/shared/approvals.d.ts +44 -0
  69. package/dist/shared/approvals.js +97 -0
  70. package/dist/shared/askEigen.d.ts +190 -0
  71. package/dist/shared/askEigen.js +76 -0
  72. package/dist/shared/attribution.d.ts +25 -0
  73. package/dist/shared/attribution.js +63 -0
  74. package/dist/shared/automations.d.ts +135 -0
  75. package/dist/shared/automations.js +553 -0
  76. package/dist/shared/backends/claudeCode.d.ts +44 -0
  77. package/dist/shared/backends/claudeCode.js +548 -0
  78. package/dist/shared/backends/codex.d.ts +15 -0
  79. package/dist/shared/backends/codex.js +287 -0
  80. package/dist/shared/backends/cursor.d.ts +111 -0
  81. package/dist/shared/backends/cursor.js +1216 -0
  82. package/dist/shared/backends/index.d.ts +18 -0
  83. package/dist/shared/backends/index.js +58 -0
  84. package/dist/shared/backends/opencode.d.ts +43 -0
  85. package/dist/shared/backends/opencode.js +415 -0
  86. package/dist/shared/backends/types.d.ts +171 -0
  87. package/dist/shared/backends/types.js +19 -0
  88. package/dist/shared/backends/usage.d.ts +8 -0
  89. package/dist/shared/backends/usage.js +71 -0
  90. package/dist/shared/billingPlans.d.ts +60 -0
  91. package/dist/shared/billingPlans.js +262 -0
  92. package/dist/shared/brain.d.ts +353 -0
  93. package/dist/shared/brain.js +487 -0
  94. package/dist/shared/clarifyingQuestions.d.ts +13 -0
  95. package/dist/shared/clarifyingQuestions.js +207 -0
  96. package/dist/shared/claudeModels.d.ts +10 -0
  97. package/dist/shared/claudeModels.js +52 -0
  98. package/dist/shared/cloudBackends.d.ts +21 -0
  99. package/dist/shared/cloudBackends.js +29 -0
  100. package/dist/shared/codexModels.d.ts +10 -0
  101. package/dist/shared/codexModels.js +28 -0
  102. package/dist/shared/contextWindows.d.ts +2 -0
  103. package/dist/shared/contextWindows.js +30 -0
  104. package/dist/shared/cursorMcpConfig.d.ts +14 -0
  105. package/dist/shared/cursorMcpConfig.js +43 -0
  106. package/dist/shared/cursorProjectMcp.d.ts +10 -0
  107. package/dist/shared/cursorProjectMcp.js +42 -0
  108. package/dist/shared/docs.d.ts +59 -0
  109. package/dist/shared/docs.js +87 -0
  110. package/dist/shared/events.d.ts +932 -0
  111. package/dist/shared/events.js +57 -0
  112. package/dist/shared/integrations.d.ts +266 -0
  113. package/dist/shared/integrations.js +449 -0
  114. package/dist/shared/issueTranscript.d.ts +64 -0
  115. package/dist/shared/issueTranscript.js +387 -0
  116. package/dist/shared/issues.d.ts +139 -0
  117. package/dist/shared/issues.js +217 -0
  118. package/dist/shared/machines.d.ts +119 -0
  119. package/dist/shared/machines.js +58 -0
  120. package/dist/shared/markdownMedia.d.ts +13 -0
  121. package/dist/shared/markdownMedia.js +41 -0
  122. package/dist/shared/notificationText.d.ts +6 -0
  123. package/dist/shared/notificationText.js +38 -0
  124. package/dist/shared/opencodeModels.d.ts +19 -0
  125. package/dist/shared/opencodeModels.js +62 -0
  126. package/dist/shared/opencodeSession.d.ts +7 -0
  127. package/dist/shared/opencodeSession.js +30 -0
  128. package/dist/shared/orchestration.d.ts +58 -0
  129. package/dist/shared/orchestration.js +12 -0
  130. package/dist/shared/orgs.d.ts +47 -0
  131. package/dist/shared/orgs.js +49 -0
  132. package/dist/shared/personalOrg.d.ts +5 -0
  133. package/dist/shared/personalOrg.js +12 -0
  134. package/dist/shared/plans.d.ts +3 -0
  135. package/dist/shared/plans.js +19 -0
  136. package/dist/shared/providerModels.d.ts +40 -0
  137. package/dist/shared/providerModels.js +503 -0
  138. package/dist/shared/roomAttention.d.ts +17 -0
  139. package/dist/shared/roomAttention.js +36 -0
  140. package/dist/shared/roomContext.d.ts +120 -0
  141. package/dist/shared/roomContext.js +133 -0
  142. package/dist/shared/roomPermissions.d.ts +56 -0
  143. package/dist/shared/roomPermissions.js +133 -0
  144. package/dist/shared/sessionSeats.d.ts +29 -0
  145. package/dist/shared/sessionSeats.js +57 -0
  146. package/dist/shared/slashCommands.d.ts +39 -0
  147. package/dist/shared/slashCommands.js +166 -0
  148. package/dist/shared/space.d.ts +33 -0
  149. package/dist/shared/space.js +54 -0
  150. package/dist/shared/spaceFeed.d.ts +78 -0
  151. package/dist/shared/spaceFeed.js +194 -0
  152. package/dist/shared/stringifyUnknown.d.ts +1 -0
  153. package/dist/shared/stringifyUnknown.js +1 -0
  154. package/dist/shared/swarm.d.ts +320 -0
  155. package/dist/shared/swarm.js +328 -0
  156. package/dist/shared/swarmVisual.d.ts +79 -0
  157. package/dist/shared/swarmVisual.js +212 -0
  158. package/dist/shared/terminalFilter.d.ts +13 -0
  159. package/dist/shared/terminalFilter.js +46 -0
  160. package/dist/shared/toolIntegration.d.ts +56 -0
  161. package/dist/shared/toolIntegration.js +180 -0
  162. package/dist/shared/typing.d.ts +9 -0
  163. package/dist/shared/typing.js +37 -0
  164. package/dist/shared/uploads.d.ts +31 -0
  165. package/dist/shared/uploads.js +65 -0
  166. package/dist/shared/voiceApprovals.d.ts +36 -0
  167. package/dist/shared/voiceApprovals.js +229 -0
  168. package/dist/shared/workspace.d.ts +49 -0
  169. package/dist/shared/workspace.js +53 -0
  170. package/dist/worker.d.ts +1 -0
  171. package/dist/worker.js +266 -0
  172. package/package.json +51 -4
@@ -0,0 +1,287 @@
1
+ import { extractThinkingText, formatToolResultDetail, isEditTool, mergeThinkingText, TOOL_RESULT_DETAIL_LIMIT, stringifyUnknown, } from "./cursor.js";
2
+ import { codexToolIntegration } from "../toolIntegration.js";
3
+ import { codexTurnUsage } from "./usage.js";
4
+ /** Text of a Codex MCP result: `{ content: [{ type: "text", text }] }` or an error. */
5
+ function mcpResultText(rec) {
6
+ const error = rec.error;
7
+ if (typeof error === "string" && error.trim())
8
+ return error;
9
+ if (error && typeof error === "object" && typeof error.message === "string") {
10
+ return error.message;
11
+ }
12
+ const result = rec.result;
13
+ if (result && Array.isArray(result.content)) {
14
+ const text = result.content
15
+ .map((part) => part && typeof part === "object" && typeof part.text === "string"
16
+ ? part.text
17
+ : "")
18
+ .filter(Boolean)
19
+ .join("\n");
20
+ if (text)
21
+ return text;
22
+ }
23
+ return result ? stringifyUnknown(result) : "";
24
+ }
25
+ /**
26
+ * OpenAI Codex CLI headless backend.
27
+ * Spawns: `codex exec --json --dangerously-bypass-approvals-and-sandbox …`
28
+ *
29
+ * Event stream is JSONL (`thread.*`, `item.*`, `turn.*`).
30
+ */
31
+ export class CodexBackend {
32
+ kind = "codex";
33
+ available = true;
34
+ command = "codex";
35
+ buildArgs(opts) {
36
+ const args = ["exec", "--json"];
37
+ // Always pin the workspace — Blaxel process workingDir alone is not enough
38
+ // for Codex to discover the cloned repo (it asks the user for `ls`/`README`).
39
+ if (opts.cwd?.trim()) {
40
+ args.push("--cd", opts.cwd.trim());
41
+ }
42
+ if (opts.mode === "plan") {
43
+ args.push("--sandbox", "read-only");
44
+ }
45
+ else {
46
+ args.push("--dangerously-bypass-approvals-and-sandbox");
47
+ }
48
+ if (opts.modelId && opts.modelId !== "auto") {
49
+ args.push("--model", opts.modelId);
50
+ }
51
+ for (const [name, server] of Object.entries(opts.mcpServers || {})) {
52
+ const key = name.replace(/[^A-Za-z0-9_-]/g, "_");
53
+ const headers = Object.entries(server.headers)
54
+ .map(([h, v]) => `${JSON.stringify(h)}=${JSON.stringify(v)}`)
55
+ .join(", ");
56
+ args.push("-c", `mcp_servers.${key}.url=${JSON.stringify(server.url)}`);
57
+ if (headers)
58
+ args.push("-c", `mcp_servers.${key}.http_headers={${headers}}`);
59
+ }
60
+ if (opts.sessionId) {
61
+ args.push("resume", opts.sessionId);
62
+ }
63
+ args.push(opts.prompt);
64
+ return args;
65
+ }
66
+ parseLine(json, ctx = {
67
+ assistantBuf: { value: "" },
68
+ gotTerminalEvent: { value: false },
69
+ }) {
70
+ if (!json || typeof json !== "object")
71
+ return [];
72
+ const ev = json;
73
+ const type = String(ev.type ?? "");
74
+ const out = [];
75
+ if (type === "thread.started" && ev.thread_id) {
76
+ out.push({ kind: "session", sessionId: String(ev.thread_id) });
77
+ return out;
78
+ }
79
+ if (type === "error") {
80
+ ctx.gotTerminalEvent.value = true;
81
+ out.push({
82
+ kind: "error",
83
+ message: stringifyUnknown(ev.message) ||
84
+ stringifyUnknown(ev.error) ||
85
+ ctx.stderr ||
86
+ "Codex error",
87
+ });
88
+ return out;
89
+ }
90
+ if (type === "turn.failed") {
91
+ ctx.gotTerminalEvent.value = true;
92
+ out.push({
93
+ kind: "error",
94
+ message: stringifyUnknown(ev.error) ||
95
+ stringifyUnknown(ev.message) ||
96
+ ctx.stderr ||
97
+ "Codex turn failed",
98
+ });
99
+ return out;
100
+ }
101
+ if (type === "turn.completed") {
102
+ ctx.gotTerminalEvent.value = true;
103
+ out.push({
104
+ kind: "done",
105
+ result: ctx.assistantBuf.value || "",
106
+ usage: codexTurnUsage(ev),
107
+ });
108
+ return out;
109
+ }
110
+ if (type === "item.started" ||
111
+ type === "item.updated" ||
112
+ type === "item.completed") {
113
+ const item = ev.item;
114
+ if (!item || typeof item !== "object")
115
+ return out;
116
+ const rec = item;
117
+ const itemType = String(rec.type ?? "");
118
+ const callId = String(rec.id ?? `${itemType}-${type}`);
119
+ if (itemType === "agent_message") {
120
+ const text = typeof rec.text === "string" ? rec.text : "";
121
+ if (!text)
122
+ return out;
123
+ if (type === "item.completed") {
124
+ ctx.assistantBuf.value = text;
125
+ out.push({ kind: "assistant_final", text });
126
+ }
127
+ else if (text.length >= ctx.assistantBuf.value.length) {
128
+ ctx.assistantBuf.value = text;
129
+ out.push({ kind: "assistant_delta", text });
130
+ }
131
+ return out;
132
+ }
133
+ if (itemType === "reasoning" ||
134
+ itemType === "agent_reasoning" ||
135
+ itemType === "reasoning_text") {
136
+ if (ctx.toolsOnly)
137
+ return out;
138
+ const text = extractThinkingText(rec);
139
+ if (!text)
140
+ return out;
141
+ ctx.thinkingBuf ??= { value: "" };
142
+ const merged = mergeThinkingText(ctx.thinkingBuf.value, text);
143
+ if (merged === ctx.thinkingBuf.value)
144
+ return out;
145
+ ctx.thinkingBuf.value = merged;
146
+ out.push({
147
+ kind: type === "item.completed" ? "thinking_final" : "thinking_delta",
148
+ text: merged,
149
+ });
150
+ return out;
151
+ }
152
+ if (itemType === "command_execution") {
153
+ const command = typeof rec.command === "string" ? rec.command : "shell";
154
+ const path = firstPath(rec);
155
+ if (type === "item.started") {
156
+ out.push({
157
+ kind: "tool_start",
158
+ callId,
159
+ name: "Bash",
160
+ detail: command,
161
+ path,
162
+ });
163
+ }
164
+ else if (type === "item.completed") {
165
+ const output = typeof rec.aggregated_output === "string"
166
+ ? rec.aggregated_output
167
+ : typeof rec.output === "string"
168
+ ? rec.output
169
+ : command;
170
+ out.push({
171
+ kind: "tool_done",
172
+ callId,
173
+ name: "Bash",
174
+ detail: formatToolResultDetail("Bash", { command }, { success: { content: output } }, output),
175
+ path,
176
+ });
177
+ }
178
+ return out;
179
+ }
180
+ if (itemType === "mcp_tool_call") {
181
+ const integration = codexToolIntegration(rec);
182
+ const server = typeof rec.server === "string" ? rec.server : "mcp";
183
+ const tool = typeof rec.tool === "string" ? rec.tool : "tool";
184
+ const name = `mcp__${server}__${tool}`;
185
+ let args = "";
186
+ try {
187
+ args = rec.arguments == null ? "" : JSON.stringify(rec.arguments);
188
+ }
189
+ catch {
190
+ args = "";
191
+ }
192
+ if (type === "item.started") {
193
+ out.push({
194
+ kind: "tool_start",
195
+ callId,
196
+ name,
197
+ detail: args || tool,
198
+ ...(integration ? { integration } : {}),
199
+ });
200
+ }
201
+ else if (type === "item.completed") {
202
+ out.push({
203
+ kind: "tool_done",
204
+ callId,
205
+ name,
206
+ detail: (mcpResultText(rec) || args || "Done").slice(0, TOOL_RESULT_DETAIL_LIMIT),
207
+ ...(integration ? { integration } : {}),
208
+ });
209
+ }
210
+ return out;
211
+ }
212
+ if (itemType === "file_change") {
213
+ const name = "Edit";
214
+ const path = firstPath(rec);
215
+ const detail = typeof rec.command === "string"
216
+ ? rec.command
217
+ : path || name;
218
+ if (type === "item.started") {
219
+ out.push({
220
+ kind: "tool_start",
221
+ callId,
222
+ name: isEditTool(name) ? name : name,
223
+ detail: String(detail),
224
+ path,
225
+ });
226
+ }
227
+ else if (type === "item.completed") {
228
+ out.push({
229
+ kind: "tool_done",
230
+ callId,
231
+ name,
232
+ detail: String(detail).slice(0, TOOL_RESULT_DETAIL_LIMIT),
233
+ path,
234
+ });
235
+ }
236
+ return out;
237
+ }
238
+ if (itemType === "todo_list" && Array.isArray(rec.items)) {
239
+ const todos = rec.items
240
+ .filter((row) => Boolean(row && typeof row === "object"))
241
+ .map((row, index) => {
242
+ const raw = String(row.status ?? "");
243
+ const status = raw === "completed" ||
244
+ raw === "in_progress" ||
245
+ raw === "cancelled"
246
+ ? raw
247
+ : "pending";
248
+ return {
249
+ id: String(row.id ?? `todo-${index}`),
250
+ content: String(row.text ?? row.content ?? ""),
251
+ status,
252
+ };
253
+ });
254
+ if (todos.length) {
255
+ out.push({
256
+ kind: type === "item.started" ? "tool_start" : "tool_done",
257
+ callId,
258
+ name: "todo",
259
+ detail: `${todos.length} todos`,
260
+ todos,
261
+ });
262
+ }
263
+ return out;
264
+ }
265
+ }
266
+ return out;
267
+ }
268
+ }
269
+ function firstPath(rec) {
270
+ for (const key of ["path", "file_path", "filePath", "target_file"]) {
271
+ if (typeof rec[key] === "string" && rec[key].trim()) {
272
+ return String(rec[key]).trim();
273
+ }
274
+ }
275
+ const changes = rec.changes;
276
+ if (Array.isArray(changes)) {
277
+ for (const change of changes) {
278
+ if (change && typeof change === "object" && "path" in change) {
279
+ const path = String(change.path ?? "").trim();
280
+ if (path)
281
+ return path;
282
+ }
283
+ }
284
+ }
285
+ return undefined;
286
+ }
287
+ export const codexBackend = new CodexBackend();
@@ -0,0 +1,111 @@
1
+ import type { AgentTodoItem, ClarifyingQuestion } from "../events.js";
2
+ import type { BuildArgsOptions, NormalizedAgentEvent, ParseLineContext, WorkerBackend } from "./types.js";
3
+ /**
4
+ * Turn unknown thrown values / CLI payloads into a user-visible string.
5
+ * Never returns "[object Object]". Lives here so Next (extensionless) and
6
+ * Node ESM (`*.js`) both resolve it without a new shared module.
7
+ */
8
+ export declare function stringifyUnknown(value: unknown, fallback?: string, depth?: number): string;
9
+ export declare function errorMessage(err: unknown, fallback?: string): string;
10
+ /** Whether a tool name represents an agent asking the user clarifying questions. */
11
+ export declare function isQuestionTool(name: string): boolean;
12
+ /** Parse structured clarifying questions from a tool's args (Claude AskUserQuestion, etc). */
13
+ export declare function parseQuestionToolArgs(args: Record<string, unknown> | unknown): ClarifyingQuestion[];
14
+ /**
15
+ * Merge a new assistant payload into the accumulated stream.
16
+ * Cursor `--stream-partial-output` may send either token deltas or a growing
17
+ * snapshot of the same message. Blind concatenation duplicates the paragraph;
18
+ * blindly replacing with a shorter payload truncates it.
19
+ */
20
+ export declare function mergeAssistantText(prev: string, incoming: string): string;
21
+ /** Collapse hard wraps so thinking reads as prose, not one phrase per line. */
22
+ export declare function normalizeThinkingText(text: string): string;
23
+ /** Merge streamed thinking: snapshots replace, deltas append with a space. */
24
+ export declare function mergeThinkingText(prev: string, incoming: string): string;
25
+ /**
26
+ * Cursor CLI streams thinking as phrase-sized JSON lines that are not prefixes
27
+ * of each other. Always concatenate; a new thought starts only after tools
28
+ * (`afterTools` in RoomManager).
29
+ */
30
+ export declare function advanceThinking(prev: string, incoming: string): {
31
+ finalize?: string;
32
+ current: string;
33
+ };
34
+ /** Pull visible model thinking / reasoning out of a CLI or SDK payload. */
35
+ export declare function extractThinkingText(source: unknown): string;
36
+ /**
37
+ * Failure message for a finished tool call, or null when it succeeded.
38
+ * Covers SDK `{status:"error", error}` results / call status, CLI
39
+ * `{failure}` / `{error}` / `{rejected}` results and MCP `isError` replies.
40
+ */
41
+ export declare function toolResultError(result: unknown, callStatus?: string): string | null;
42
+ /** Readable start-of-call detail for tools whose args aren't a path/command. */
43
+ export declare function structuredToolDetail(name: string, args: Record<string, unknown>): string | undefined;
44
+ /** Max chars of tool result text we persist into chat content. */
45
+ export declare const TOOL_RESULT_DETAIL_LIMIT = 100000;
46
+ /** `$ command` plus its full stdout/stderr for the tool-call card. */
47
+ export declare function formatToolTranscript(command: string | undefined, output: string | undefined): string;
48
+ /**
49
+ * Keep the start-time command/args when a tool_done only has the result,
50
+ * so the chat card can show input and output together.
51
+ */
52
+ export declare function mergeToolStartAndResult(name: string, start: string | undefined, result: string): string;
53
+ /** Unwrap CLI `{success:{…}}` / SDK `{status,value}` / bare object result shapes. */
54
+ export declare function unwrapToolResultPayload(result: unknown): Record<string, unknown> | null;
55
+ /**
56
+ * Human-readable tool output for chat. Prefers completed `result` payloads
57
+ * (stdout, file content, diff summary) over the start-time args summary.
58
+ */
59
+ export declare function formatToolResultDetail(name: string, args: Record<string, unknown> | undefined, result: unknown, fallback?: string): string;
60
+ /**
61
+ * Pull a unified diff out of a completed tool `result` payload.
62
+ * Cursor editToolCall puts the real patch in `result.success.diffString`.
63
+ */
64
+ export declare function diffFromToolResult(result: unknown, pathHint?: string): string;
65
+ export declare function diffFromToolArgs(toolName: string, args?: Record<string, unknown>): string;
66
+ /** Prefer result.diffString, then synthesize from args. */
67
+ export declare function diffFromToolEvent(toolName: string, args?: Record<string, unknown>, result?: unknown): string;
68
+ export declare function isEditTool(name: string): boolean;
69
+ export declare function isTodoTool(name: string): boolean;
70
+ export declare function todosFromToolArgs(args?: unknown): AgentTodoItem[];
71
+ /**
72
+ * Recover structured todos from a chat message — prefers `message.todos`,
73
+ * then parses JSON tool args that older servers stored as `content`.
74
+ */
75
+ export declare function resolveMessageTodos(message: {
76
+ todos?: AgentTodoItem[];
77
+ content?: string;
78
+ toolName?: string;
79
+ }): AgentTodoItem[];
80
+ /** Whether a chat tool message should render as the Todos card. */
81
+ export declare function messageHasTodos(message: {
82
+ role?: string;
83
+ todos?: AgentTodoItem[];
84
+ content?: string;
85
+ toolName?: string;
86
+ }): boolean;
87
+ /**
88
+ * Keep only the latest todos card per agent so successive TodoWrite updates
89
+ * (2 → 3 → 4 items) don't stack as separate groups in the timeline.
90
+ */
91
+ export declare function coalesceTodoMessages<T extends {
92
+ id: string;
93
+ role: string;
94
+ agentId?: string;
95
+ todos?: AgentTodoItem[];
96
+ content?: string;
97
+ toolName?: string;
98
+ }>(messages: T[]): T[];
99
+ export declare function todoStatusSummary(todos: AgentTodoItem[]): string;
100
+ /**
101
+ * Cursor CLI headless agent backend.
102
+ * Spawns: `cursor agent --print --output-format stream-json ...`
103
+ */
104
+ export declare class CursorAgentBackend implements WorkerBackend {
105
+ readonly kind: "cursor";
106
+ readonly available = true;
107
+ readonly command = "cursor";
108
+ buildArgs(opts: BuildArgsOptions): string[];
109
+ parseLine(json: unknown, ctx?: ParseLineContext): NormalizedAgentEvent[];
110
+ }
111
+ export declare const cursorAgentBackend: CursorAgentBackend;