@warlock.js/ai-cli 0.0.0-stage → 5.31.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 (139) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +69 -2
  4. package/cjs/index.cjs +4576 -0
  5. package/cjs/index.cjs.map +1 -0
  6. package/esm/adapters/aider.d.mts +41 -0
  7. package/esm/adapters/aider.d.mts.map +1 -0
  8. package/esm/adapters/aider.mjs +294 -0
  9. package/esm/adapters/aider.mjs.map +1 -0
  10. package/esm/adapters/amp.d.mts +33 -0
  11. package/esm/adapters/amp.d.mts.map +1 -0
  12. package/esm/adapters/amp.mjs +119 -0
  13. package/esm/adapters/amp.mjs.map +1 -0
  14. package/esm/adapters/antigravity.d.mts +37 -0
  15. package/esm/adapters/antigravity.d.mts.map +1 -0
  16. package/esm/adapters/antigravity.mjs +235 -0
  17. package/esm/adapters/antigravity.mjs.map +1 -0
  18. package/esm/adapters/claude-code.d.mts +30 -0
  19. package/esm/adapters/claude-code.d.mts.map +1 -0
  20. package/esm/adapters/claude-code.mjs +121 -0
  21. package/esm/adapters/claude-code.mjs.map +1 -0
  22. package/esm/adapters/claude-stream.d.mts +32 -0
  23. package/esm/adapters/claude-stream.d.mts.map +1 -0
  24. package/esm/adapters/claude-stream.mjs +140 -0
  25. package/esm/adapters/claude-stream.mjs.map +1 -0
  26. package/esm/adapters/codex.d.mts +37 -0
  27. package/esm/adapters/codex.d.mts.map +1 -0
  28. package/esm/adapters/codex.mjs +320 -0
  29. package/esm/adapters/codex.mjs.map +1 -0
  30. package/esm/adapters/copilot.d.mts +35 -0
  31. package/esm/adapters/copilot.d.mts.map +1 -0
  32. package/esm/adapters/copilot.mjs +244 -0
  33. package/esm/adapters/copilot.mjs.map +1 -0
  34. package/esm/adapters/cursor.d.mts +35 -0
  35. package/esm/adapters/cursor.d.mts.map +1 -0
  36. package/esm/adapters/cursor.mjs +203 -0
  37. package/esm/adapters/cursor.mjs.map +1 -0
  38. package/esm/adapters/droid.d.mts +32 -0
  39. package/esm/adapters/droid.d.mts.map +1 -0
  40. package/esm/adapters/droid.mjs +183 -0
  41. package/esm/adapters/droid.mjs.map +1 -0
  42. package/esm/adapters/grok.d.mts +32 -0
  43. package/esm/adapters/grok.d.mts.map +1 -0
  44. package/esm/adapters/grok.mjs +199 -0
  45. package/esm/adapters/grok.mjs.map +1 -0
  46. package/esm/adapters/index.d.mts +16 -0
  47. package/esm/adapters/index.mjs +18 -0
  48. package/esm/adapters/kimi.d.mts +34 -0
  49. package/esm/adapters/kimi.d.mts.map +1 -0
  50. package/esm/adapters/kimi.mjs +162 -0
  51. package/esm/adapters/kimi.mjs.map +1 -0
  52. package/esm/adapters/mistral-vibe.d.mts +32 -0
  53. package/esm/adapters/mistral-vibe.d.mts.map +1 -0
  54. package/esm/adapters/mistral-vibe.mjs +252 -0
  55. package/esm/adapters/mistral-vibe.mjs.map +1 -0
  56. package/esm/adapters/opencode.d.mts +36 -0
  57. package/esm/adapters/opencode.d.mts.map +1 -0
  58. package/esm/adapters/opencode.mjs +219 -0
  59. package/esm/adapters/opencode.mjs.map +1 -0
  60. package/esm/adapters/qwen-code.d.mts +30 -0
  61. package/esm/adapters/qwen-code.d.mts.map +1 -0
  62. package/esm/adapters/qwen-code.mjs +94 -0
  63. package/esm/adapters/qwen-code.mjs.map +1 -0
  64. package/esm/adapters/reasonix.d.mts +31 -0
  65. package/esm/adapters/reasonix.d.mts.map +1 -0
  66. package/esm/adapters/reasonix.mjs +250 -0
  67. package/esm/adapters/reasonix.mjs.map +1 -0
  68. package/esm/adapters/shared.d.mts +78 -0
  69. package/esm/adapters/shared.d.mts.map +1 -0
  70. package/esm/adapters/shared.mjs +161 -0
  71. package/esm/adapters/shared.mjs.map +1 -0
  72. package/esm/cli-agent.d.mts +40 -0
  73. package/esm/cli-agent.d.mts.map +1 -0
  74. package/esm/cli-agent.mjs +207 -0
  75. package/esm/cli-agent.mjs.map +1 -0
  76. package/esm/cli.d.mts +53 -0
  77. package/esm/cli.d.mts.map +1 -0
  78. package/esm/cli.mjs +61 -0
  79. package/esm/cli.mjs.map +1 -0
  80. package/esm/contracts/adapter.contract.d.mts +154 -0
  81. package/esm/contracts/adapter.contract.d.mts.map +1 -0
  82. package/esm/contracts/events.type.d.mts +111 -0
  83. package/esm/contracts/events.type.d.mts.map +1 -0
  84. package/esm/contracts/index.d.mts +4 -0
  85. package/esm/contracts/mcp.type.d.mts +29 -0
  86. package/esm/contracts/mcp.type.d.mts.map +1 -0
  87. package/esm/contracts/options.type.d.mts +87 -0
  88. package/esm/contracts/options.type.d.mts.map +1 -0
  89. package/esm/errors.d.mts +46 -0
  90. package/esm/errors.d.mts.map +1 -0
  91. package/esm/errors.mjs +32 -0
  92. package/esm/errors.mjs.map +1 -0
  93. package/esm/index.d.mts +31 -0
  94. package/esm/index.mjs +28 -0
  95. package/esm/model/cli-model.d.mts +48 -0
  96. package/esm/model/cli-model.d.mts.map +1 -0
  97. package/esm/model/cli-model.mjs +133 -0
  98. package/esm/model/cli-model.mjs.map +1 -0
  99. package/esm/probe/probe.d.mts +18 -0
  100. package/esm/probe/probe.d.mts.map +1 -0
  101. package/esm/probe/probe.mjs +148 -0
  102. package/esm/probe/probe.mjs.map +1 -0
  103. package/esm/session/aggregate.mjs +86 -0
  104. package/esm/session/aggregate.mjs.map +1 -0
  105. package/esm/session/environment.mjs +71 -0
  106. package/esm/session/environment.mjs.map +1 -0
  107. package/esm/session/run-directory.mjs +74 -0
  108. package/esm/session/run-directory.mjs.map +1 -0
  109. package/esm/session/session.mjs +188 -0
  110. package/esm/session/session.mjs.map +1 -0
  111. package/esm/spawn/invocation.d.mts +35 -0
  112. package/esm/spawn/invocation.d.mts.map +1 -0
  113. package/esm/spawn/invocation.mjs +76 -0
  114. package/esm/spawn/invocation.mjs.map +1 -0
  115. package/esm/spawn/process-tree.mjs +57 -0
  116. package/esm/spawn/process-tree.mjs.map +1 -0
  117. package/esm/spawn/resolve-command.d.mts +73 -0
  118. package/esm/spawn/resolve-command.d.mts.map +1 -0
  119. package/esm/spawn/resolve-command.mjs +109 -0
  120. package/esm/spawn/resolve-command.mjs.map +1 -0
  121. package/esm/stream/event-log.mjs +52 -0
  122. package/esm/stream/event-log.mjs.map +1 -0
  123. package/esm/stream/json-lines.d.mts +33 -0
  124. package/esm/stream/json-lines.d.mts.map +1 -0
  125. package/esm/stream/json-lines.mjs +65 -0
  126. package/esm/stream/json-lines.mjs.map +1 -0
  127. package/esm/stream/line-splitter.mjs +53 -0
  128. package/esm/stream/line-splitter.mjs.map +1 -0
  129. package/esm/utils/toml.d.mts +22 -0
  130. package/esm/utils/toml.d.mts.map +1 -0
  131. package/esm/utils/toml.mjs +53 -0
  132. package/esm/utils/toml.mjs.map +1 -0
  133. package/llms-full.txt +373 -0
  134. package/llms.txt +10 -0
  135. package/package.json +39 -4
  136. package/skills/README.md +13 -0
  137. package/skills/index.md +22 -0
  138. package/skills/run-cli-agents/SKILL.md +186 -0
  139. package/skills/write-a-cli-adapter/SKILL.md +173 -0
@@ -0,0 +1,244 @@
1
+ import { asRecord, jsonLinesParser, numberField, outputText, parseJsonLine, recordField, stringField } from "../stream/json-lines.mjs";
2
+ import { argvPrompt, jsonFile, mcpServersJson, usageOf } from "./shared.mjs";
3
+ import { readFileSync } from "node:fs";
4
+ import path from "node:path";
5
+
6
+ //#region ../../packages/ai-cli/src/adapters/copilot.ts
7
+ /** Usage file (inside the run directory) Copilot writes on exit. */
8
+ const USAGE_FILE = "copilot-usage.json";
9
+ /**
10
+ * GitHub Copilot CLI (`copilot`, npm `@github/copilot`).
11
+ *
12
+ * Verified against the real `copilot --help` of 1.0.98, the JSONL writer in
13
+ * the shipped CLI, the event types of `@github/copilot-sdk` 1.0.22 and the
14
+ * docs (`docs.github.com/copilot/how-tos/copilot-cli/…`, programmatic and
15
+ * command references), 2026-10-17.
16
+ *
17
+ * - Headless: `copilot -p <prompt> --output-format json --stream on`
18
+ * (piped stdin is the prompt when `-p` is absent). Stream lines are
19
+ * session events `{type,data,id,timestamp}`: `assistant.message_delta`
20
+ * (`deltaContent`), `assistant.message` (`content`),
21
+ * `tool.execution_start` (`toolCallId`, `toolName`, `arguments`),
22
+ * `tool.execution_complete` (`success`, `result.content`,
23
+ * `error.message`), `session.error`, and a final CLI-built `result`
24
+ * (`sessionId`, `exitCode`, premium-request usage).
25
+ * - Tokens are not in the stream; the adapter passes `--usage-output-file`
26
+ * and reads `modelMetrics.*.usage` from it when the stream ends. Billing
27
+ * is in premium requests, so no USD cost is reported.
28
+ * - Permissions: unapproved tool requests are auto-denied in `-p` mode;
29
+ * bypass is `--allow-all` (tools, paths and URLs). `--no-ask-user` and
30
+ * `--no-auto-update` are always passed.
31
+ * - MCP: `--additional-mcp-config @<file>` (`mcpServers`, `type`
32
+ * `local`/`http`/`sse`, `tools: ["*"]`), written to the run directory.
33
+ * - Home `COPILOT_HOME`; auth `COPILOT_GITHUB_TOKEN`. Resume with
34
+ * `--session-id <id>`.
35
+ */
36
+ const copilotAdapter = {
37
+ name: "copilot",
38
+ title: "Copilot CLI",
39
+ command: "copilot",
40
+ apiKeyEnv: ["COPILOT_GITHUB_TOKEN"],
41
+ homeEnv: ["COPILOT_HOME"],
42
+ transports: ["argv", "stdin"],
43
+ effort: true,
44
+ mcp: true,
45
+ probe: {
46
+ help: [["--help"]],
47
+ version: ["--version"]
48
+ },
49
+ verification: {
50
+ version: "1.0.98",
51
+ verifiedBy: "help",
52
+ sources: [
53
+ "https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically",
54
+ "https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference",
55
+ "https://www.npmjs.com/package/@github/copilot"
56
+ ],
57
+ checkedAt: "2026-10-17"
58
+ },
59
+ plan(context) {
60
+ const args = [
61
+ "--output-format",
62
+ "json",
63
+ "--stream",
64
+ "on",
65
+ "--no-ask-user",
66
+ "--no-auto-update",
67
+ "--usage-output-file",
68
+ path.join(context.runDir, USAGE_FILE)
69
+ ];
70
+ const requires = [
71
+ "--output-format",
72
+ "--stream",
73
+ "--no-ask-user",
74
+ "--no-auto-update",
75
+ "--usage-output-file"
76
+ ];
77
+ const files = [];
78
+ if (context.model !== void 0) {
79
+ args.push("--model", context.model);
80
+ requires.push("--model");
81
+ }
82
+ if (context.effort !== void 0) {
83
+ args.push("--reasoning-effort", context.effort);
84
+ requires.push("--reasoning-effort");
85
+ }
86
+ if (context.resume !== void 0) {
87
+ args.push("--session-id", context.resume);
88
+ requires.push("--session-id");
89
+ }
90
+ if (context.permission === "bypass") {
91
+ args.push("--allow-all");
92
+ requires.push("--allow-all");
93
+ }
94
+ if (context.mcp !== void 0) {
95
+ const file = path.join(context.runDir, "copilot-mcp.json");
96
+ const servers = mcpServersJson(context.mcp, {
97
+ typeField: true,
98
+ extra: { tools: ["*"] }
99
+ });
100
+ for (const server of Object.values(servers)) if (server.type === "stdio") server.type = "local";
101
+ files.push({
102
+ path: file,
103
+ content: jsonFile({ mcpServers: servers })
104
+ });
105
+ args.push("--additional-mcp-config", `@${file}`);
106
+ requires.push("--additional-mcp-config");
107
+ }
108
+ return {
109
+ args,
110
+ tail: context.transport === "argv" ? ["-p", argvPrompt(context.prompt)] : [],
111
+ stdin: context.transport === "stdin" ? context.prompt : void 0,
112
+ env: context.home !== void 0 ? { COPILOT_HOME: context.home } : void 0,
113
+ files,
114
+ requires: context.transport === "argv" ? [...requires, "-p"] : requires
115
+ };
116
+ },
117
+ parser: createCopilotParser
118
+ };
119
+ /** Token usage summed over `modelMetrics` of the usage file. */
120
+ function usageFileEvent(context) {
121
+ if (context === void 0) return;
122
+ let report;
123
+ try {
124
+ report = parseJsonLine(readFileSync(path.join(context.runDir, USAGE_FILE), "utf8"));
125
+ } catch {
126
+ return;
127
+ }
128
+ const metrics = recordField(report, "modelMetrics");
129
+ if (metrics === void 0) return;
130
+ let input = 0;
131
+ let output = 0;
132
+ let cached = 0;
133
+ let written = 0;
134
+ let reasoning = 0;
135
+ for (const value of Object.values(metrics)) {
136
+ const usage = recordField(asRecord(value), "usage");
137
+ input += numberField(usage, "inputTokens") ?? 0;
138
+ output += numberField(usage, "outputTokens") ?? 0;
139
+ cached += numberField(usage, "cacheReadTokens") ?? 0;
140
+ written += numberField(usage, "cacheWriteTokens") ?? 0;
141
+ reasoning += numberField(usage, "reasoningTokens") ?? 0;
142
+ }
143
+ return {
144
+ type: "usage",
145
+ cumulative: true,
146
+ usage: usageOf({
147
+ input,
148
+ output,
149
+ cachedTokens: cached > 0 ? cached : void 0,
150
+ cacheWriteTokens: written > 0 ? written : void 0,
151
+ reasoningTokens: reasoning > 0 ? reasoning : void 0
152
+ }),
153
+ raw: report
154
+ };
155
+ }
156
+ /** Parser for `copilot -p … --output-format json` (plus its usage file). */
157
+ function createCopilotParser(context) {
158
+ let started = false;
159
+ let sessionRef;
160
+ return {
161
+ ...jsonLinesParser((record) => {
162
+ const events = [];
163
+ const type = stringField(record, "type");
164
+ const data = recordField(record, "data");
165
+ if (!started) {
166
+ started = true;
167
+ events.push({
168
+ type: "session.started",
169
+ sessionRef: stringField(data, "sessionId"),
170
+ raw: record
171
+ });
172
+ }
173
+ switch (type) {
174
+ case "assistant.message_delta": {
175
+ const text = stringField(data, "deltaContent") ?? "";
176
+ if (text.length > 0) events.push({
177
+ type: "message",
178
+ text,
179
+ delta: true,
180
+ raw: record
181
+ });
182
+ break;
183
+ }
184
+ case "assistant.message": {
185
+ const text = stringField(data, "content") ?? "";
186
+ if (text.length > 0) events.push({
187
+ type: "message",
188
+ text,
189
+ delta: false,
190
+ raw: record
191
+ });
192
+ break;
193
+ }
194
+ case "tool.execution_start":
195
+ events.push({
196
+ type: "tool.call",
197
+ id: stringField(data, "toolCallId") ?? "",
198
+ name: stringField(data, "toolName") ?? "",
199
+ input: data?.arguments,
200
+ raw: record
201
+ });
202
+ break;
203
+ case "tool.execution_complete": {
204
+ const success = data?.success === true;
205
+ events.push({
206
+ type: "tool.result",
207
+ id: stringField(data, "toolCallId") ?? "",
208
+ output: success ? outputText(recordField(data, "result")?.content) : stringField(recordField(data, "error"), "message") ?? "tool failed",
209
+ isError: !success,
210
+ raw: record
211
+ });
212
+ break;
213
+ }
214
+ case "session.error":
215
+ events.push({
216
+ type: "error",
217
+ message: stringField(data, "message") ?? "Copilot session error",
218
+ fatal: true,
219
+ raw: record
220
+ });
221
+ break;
222
+ case "result":
223
+ sessionRef = stringField(record, "sessionId") ?? sessionRef;
224
+ break;
225
+ case "error":
226
+ events.push({
227
+ type: "error",
228
+ message: stringField(record, "message") ?? "error",
229
+ raw: record
230
+ });
231
+ break;
232
+ }
233
+ return events;
234
+ }, () => {
235
+ const usage = usageFileEvent(context);
236
+ return usage !== void 0 ? [usage] : [];
237
+ }),
238
+ sessionRef: () => sessionRef
239
+ };
240
+ }
241
+
242
+ //#endregion
243
+ export { copilotAdapter, createCopilotParser };
244
+ //# sourceMappingURL=copilot.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/copilot.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n CliAdapter,\n CliLaunchContext,\n CliLaunchFile,\n CliParsedEvent,\n CliStreamParser,\n} from \"../contracts\";\nimport {\n asRecord,\n jsonLinesParser,\n numberField,\n outputText,\n parseJsonLine,\n recordField,\n stringField,\n} from \"../stream/json-lines\";\nimport { argvPrompt, jsonFile, mcpServersJson, usageOf } from \"./shared\";\n\n/** Usage file (inside the run directory) Copilot writes on exit. */\nconst USAGE_FILE = \"copilot-usage.json\";\n\n/**\n * GitHub Copilot CLI (`copilot`, npm `@github/copilot`).\n *\n * Verified against the real `copilot --help` of 1.0.98, the JSONL writer in\n * the shipped CLI, the event types of `@github/copilot-sdk` 1.0.22 and the\n * docs (`docs.github.com/copilot/how-tos/copilot-cli/…`, programmatic and\n * command references), 2026-10-17.\n *\n * - Headless: `copilot -p <prompt> --output-format json --stream on`\n * (piped stdin is the prompt when `-p` is absent). Stream lines are\n * session events `{type,data,id,timestamp}`: `assistant.message_delta`\n * (`deltaContent`), `assistant.message` (`content`),\n * `tool.execution_start` (`toolCallId`, `toolName`, `arguments`),\n * `tool.execution_complete` (`success`, `result.content`,\n * `error.message`), `session.error`, and a final CLI-built `result`\n * (`sessionId`, `exitCode`, premium-request usage).\n * - Tokens are not in the stream; the adapter passes `--usage-output-file`\n * and reads `modelMetrics.*.usage` from it when the stream ends. Billing\n * is in premium requests, so no USD cost is reported.\n * - Permissions: unapproved tool requests are auto-denied in `-p` mode;\n * bypass is `--allow-all` (tools, paths and URLs). `--no-ask-user` and\n * `--no-auto-update` are always passed.\n * - MCP: `--additional-mcp-config @<file>` (`mcpServers`, `type`\n * `local`/`http`/`sse`, `tools: [\"*\"]`), written to the run directory.\n * - Home `COPILOT_HOME`; auth `COPILOT_GITHUB_TOKEN`. Resume with\n * `--session-id <id>`.\n */\nexport const copilotAdapter: CliAdapter = {\n name: \"copilot\",\n title: \"Copilot CLI\",\n command: \"copilot\",\n apiKeyEnv: [\"COPILOT_GITHUB_TOKEN\"],\n homeEnv: [\"COPILOT_HOME\"],\n transports: [\"argv\", \"stdin\"],\n effort: true,\n mcp: true,\n probe: { help: [[\"--help\"]], version: [\"--version\"] },\n verification: {\n version: \"1.0.98\",\n verifiedBy: \"help\",\n sources: [\n \"https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically\",\n \"https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference\",\n \"https://www.npmjs.com/package/@github/copilot\",\n ],\n checkedAt: \"2026-10-17\",\n },\n plan(context) {\n const args = [\n \"--output-format\",\n \"json\",\n \"--stream\",\n \"on\",\n \"--no-ask-user\",\n \"--no-auto-update\",\n \"--usage-output-file\",\n path.join(context.runDir, USAGE_FILE),\n ];\n const requires = [\n \"--output-format\",\n \"--stream\",\n \"--no-ask-user\",\n \"--no-auto-update\",\n \"--usage-output-file\",\n ];\n const files: CliLaunchFile[] = [];\n\n if (context.model !== undefined) {\n args.push(\"--model\", context.model);\n requires.push(\"--model\");\n }\n\n if (context.effort !== undefined) {\n // Copilot accepts the framework scale verbatim: none … max.\n args.push(\"--reasoning-effort\", context.effort);\n requires.push(\"--reasoning-effort\");\n }\n\n if (context.resume !== undefined) {\n args.push(\"--session-id\", context.resume);\n requires.push(\"--session-id\");\n }\n\n if (context.permission === \"bypass\") {\n args.push(\"--allow-all\");\n requires.push(\"--allow-all\");\n }\n\n if (context.mcp !== undefined) {\n const file = path.join(context.runDir, \"copilot-mcp.json\");\n const servers = mcpServersJson(context.mcp, { typeField: true, extra: { tools: [\"*\"] } });\n\n for (const server of Object.values(servers)) {\n if (server.type === \"stdio\") {\n server.type = \"local\";\n }\n }\n\n files.push({ path: file, content: jsonFile({ mcpServers: servers }) });\n args.push(\"--additional-mcp-config\", `@${file}`);\n requires.push(\"--additional-mcp-config\");\n }\n\n return {\n args,\n tail: context.transport === \"argv\" ? [\"-p\", argvPrompt(context.prompt)] : [],\n stdin: context.transport === \"stdin\" ? context.prompt : undefined,\n env: context.home !== undefined ? { COPILOT_HOME: context.home } : undefined,\n files,\n requires: context.transport === \"argv\" ? [...requires, \"-p\"] : requires,\n };\n },\n parser: createCopilotParser,\n};\n\n/** Token usage summed over `modelMetrics` of the usage file. */\nfunction usageFileEvent(context: CliLaunchContext | undefined): CliParsedEvent | undefined {\n if (context === undefined) {\n return undefined;\n }\n\n let report: Record<string, unknown> | undefined;\n\n try {\n report = parseJsonLine(readFileSync(path.join(context.runDir, USAGE_FILE), \"utf8\"));\n } catch {\n return undefined;\n }\n\n const metrics = recordField(report, \"modelMetrics\");\n\n if (metrics === undefined) {\n return undefined;\n }\n\n let input = 0;\n let output = 0;\n let cached = 0;\n let written = 0;\n let reasoning = 0;\n\n for (const value of Object.values(metrics)) {\n const usage = recordField(asRecord(value), \"usage\");\n\n input += numberField(usage, \"inputTokens\") ?? 0;\n output += numberField(usage, \"outputTokens\") ?? 0;\n cached += numberField(usage, \"cacheReadTokens\") ?? 0;\n written += numberField(usage, \"cacheWriteTokens\") ?? 0;\n reasoning += numberField(usage, \"reasoningTokens\") ?? 0;\n }\n\n return {\n type: \"usage\",\n cumulative: true,\n usage: usageOf({\n input,\n output,\n cachedTokens: cached > 0 ? cached : undefined,\n cacheWriteTokens: written > 0 ? written : undefined,\n reasoningTokens: reasoning > 0 ? reasoning : undefined,\n }),\n raw: report,\n };\n}\n\n/** Parser for `copilot -p … --output-format json` (plus its usage file). */\nexport function createCopilotParser(context?: CliLaunchContext): CliStreamParser {\n let started = false;\n let sessionRef: string | undefined;\n\n const parser = jsonLinesParser(\n (record): CliParsedEvent[] => {\n const events: CliParsedEvent[] = [];\n const type = stringField(record, \"type\");\n const data = recordField(record, \"data\");\n\n if (!started) {\n started = true;\n events.push({\n type: \"session.started\",\n sessionRef: stringField(data, \"sessionId\"),\n raw: record,\n });\n }\n\n switch (type) {\n case \"assistant.message_delta\": {\n const text = stringField(data, \"deltaContent\") ?? \"\";\n\n if (text.length > 0) {\n events.push({ type: \"message\", text, delta: true, raw: record });\n }\n break;\n }\n case \"assistant.message\": {\n const text = stringField(data, \"content\") ?? \"\";\n\n if (text.length > 0) {\n events.push({ type: \"message\", text, delta: false, raw: record });\n }\n break;\n }\n case \"tool.execution_start\":\n events.push({\n type: \"tool.call\",\n id: stringField(data, \"toolCallId\") ?? \"\",\n name: stringField(data, \"toolName\") ?? \"\",\n input: data?.arguments,\n raw: record,\n });\n break;\n case \"tool.execution_complete\": {\n const success = data?.success === true;\n\n events.push({\n type: \"tool.result\",\n id: stringField(data, \"toolCallId\") ?? \"\",\n output: success\n ? outputText(recordField(data, \"result\")?.content)\n : (stringField(recordField(data, \"error\"), \"message\") ?? \"tool failed\"),\n isError: !success,\n raw: record,\n });\n break;\n }\n case \"session.error\":\n events.push({\n type: \"error\",\n message: stringField(data, \"message\") ?? \"Copilot session error\",\n fatal: true,\n raw: record,\n });\n break;\n case \"result\":\n sessionRef = stringField(record, \"sessionId\") ?? sessionRef;\n break;\n case \"error\":\n events.push({\n type: \"error\",\n message: stringField(record, \"message\") ?? \"error\",\n raw: record,\n });\n break;\n }\n\n return events;\n },\n () => {\n const usage = usageFileEvent(context);\n\n return usage !== undefined ? [usage] : [];\n },\n );\n\n return { ...parser, sessionRef: () => sessionRef };\n}\n"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { CliAdapter, CliStreamParser } from "../contracts/adapter.contract.mjs";
2
+ //#region ../../packages/ai-cli/src/adapters/cursor.d.ts
3
+ /**
4
+ * Cursor CLI (`cursor-agent`, also installed as `agent`), installed by the
5
+ * `cursor.com/install` script (no official npm package).
6
+ *
7
+ * Verified against the official docs (`cursor.com/docs/cli/{headless,mcp}`,
8
+ * `/docs/cli/reference/{output-format,parameters,authentication,
9
+ * permissions,configuration}`) and the option strings of the
10
+ * 2026.10.16-e3cb207 release bundle (read, not executed), 2026-10-17. The
11
+ * capability probe checks every flag against the installed `--help`.
12
+ *
13
+ * - Headless: `cursor-agent -p --output-format stream-json --trust <prompt>`;
14
+ * with no positional prompt, stdin is the prompt. `--trust` is passed
15
+ * because print mode exits in a directory that was never trusted — the
16
+ * run's `cwd` is the caller's explicit choice.
17
+ * - Stream: `system/init` (`session_id`, `model`), `user` echo, `assistant`
18
+ * messages (`message.content[].text`), `tool_call` `started`/`completed`
19
+ * (`call_id`; the tool is the single key of `tool_call`, e.g.
20
+ * `readToolCall{args,result{success}}`), and a final `result` with
21
+ * `usage{inputTokens (net of cache), outputTokens, cacheReadTokens,
22
+ * cacheWriteTokens}`. Errors are not JSON: stderr and a non-zero exit.
23
+ * - Permissions: headless default is the allowlist mode (unlisted actions are
24
+ * rejected, changes only proposed); bypass is `--force`.
25
+ * - MCP: no flag; `$HOME/.cursor/mcp.json` (the path ignores
26
+ * `CURSOR_CONFIG_DIR`), plus `--approve-mcps` — needs a private home.
27
+ * - Home: `HOME`/`USERPROFILE`, `CURSOR_CONFIG_DIR` and `CURSOR_DATA_DIR`
28
+ * are pointed into it. Auth: `CURSOR_API_KEY`.
29
+ */
30
+ declare const cursorAdapter: CliAdapter;
31
+ /** Parser for `cursor-agent -p --output-format stream-json`. */
32
+ declare function createCursorParser(): CliStreamParser;
33
+ //#endregion
34
+ export { createCursorParser, cursorAdapter };
35
+ //# sourceMappingURL=cursor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.mts","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/cursor.ts"],"mappings":";;;;;AA+CA;;;;AAwEC;AAmBD;;;;AAAqD;;;;;;;;;;;;;;;cA3FxC,aAAA,EAAe,UAwE3B;;iBAmBe,kBAAA,IAAsB,eAAe"}
@@ -0,0 +1,203 @@
1
+ import { asArray, asRecord, jsonLinesParser, numberField, outputText, recordField, stringField } from "../stream/json-lines.mjs";
2
+ import { argvPrompt, jsonFile, mcpServersJson, parseArguments, requirePrivateHome, usageOf } from "./shared.mjs";
3
+ import path from "node:path";
4
+
5
+ //#region ../../packages/ai-cli/src/adapters/cursor.ts
6
+ /**
7
+ * Cursor CLI (`cursor-agent`, also installed as `agent`), installed by the
8
+ * `cursor.com/install` script (no official npm package).
9
+ *
10
+ * Verified against the official docs (`cursor.com/docs/cli/{headless,mcp}`,
11
+ * `/docs/cli/reference/{output-format,parameters,authentication,
12
+ * permissions,configuration}`) and the option strings of the
13
+ * 2026.10.16-e3cb207 release bundle (read, not executed), 2026-10-17. The
14
+ * capability probe checks every flag against the installed `--help`.
15
+ *
16
+ * - Headless: `cursor-agent -p --output-format stream-json --trust <prompt>`;
17
+ * with no positional prompt, stdin is the prompt. `--trust` is passed
18
+ * because print mode exits in a directory that was never trusted — the
19
+ * run's `cwd` is the caller's explicit choice.
20
+ * - Stream: `system/init` (`session_id`, `model`), `user` echo, `assistant`
21
+ * messages (`message.content[].text`), `tool_call` `started`/`completed`
22
+ * (`call_id`; the tool is the single key of `tool_call`, e.g.
23
+ * `readToolCall{args,result{success}}`), and a final `result` with
24
+ * `usage{inputTokens (net of cache), outputTokens, cacheReadTokens,
25
+ * cacheWriteTokens}`. Errors are not JSON: stderr and a non-zero exit.
26
+ * - Permissions: headless default is the allowlist mode (unlisted actions are
27
+ * rejected, changes only proposed); bypass is `--force`.
28
+ * - MCP: no flag; `$HOME/.cursor/mcp.json` (the path ignores
29
+ * `CURSOR_CONFIG_DIR`), plus `--approve-mcps` — needs a private home.
30
+ * - Home: `HOME`/`USERPROFILE`, `CURSOR_CONFIG_DIR` and `CURSOR_DATA_DIR`
31
+ * are pointed into it. Auth: `CURSOR_API_KEY`.
32
+ */
33
+ const cursorAdapter = {
34
+ name: "cursor",
35
+ title: "Cursor CLI",
36
+ command: "cursor-agent",
37
+ apiKeyEnv: ["CURSOR_API_KEY"],
38
+ homeEnv: [
39
+ "HOME",
40
+ "USERPROFILE",
41
+ "CURSOR_CONFIG_DIR",
42
+ "CURSOR_DATA_DIR"
43
+ ],
44
+ transports: ["argv", "stdin"],
45
+ effort: false,
46
+ mcp: true,
47
+ probe: {
48
+ help: [["--help"]],
49
+ version: ["--version"]
50
+ },
51
+ verification: {
52
+ version: "2026.10.16-e3cb207",
53
+ verifiedBy: "docs",
54
+ sources: [
55
+ "https://cursor.com/docs/cli/headless",
56
+ "https://cursor.com/docs/cli/reference/output-format",
57
+ "https://cursor.com/docs/cli/reference/parameters",
58
+ "https://cursor.com/docs/cli/mcp"
59
+ ],
60
+ checkedAt: "2026-10-17"
61
+ },
62
+ plan(context) {
63
+ const args = [
64
+ "--print",
65
+ "--output-format",
66
+ "stream-json",
67
+ "--trust"
68
+ ];
69
+ const requires = [
70
+ "--print",
71
+ "--output-format",
72
+ "stream-json",
73
+ "--trust"
74
+ ];
75
+ const files = [];
76
+ if (context.model !== void 0) {
77
+ args.push("--model", context.model);
78
+ requires.push("--model");
79
+ }
80
+ if (context.resume !== void 0) {
81
+ args.push("--resume", context.resume);
82
+ requires.push("--resume");
83
+ }
84
+ if (context.permission === "bypass") {
85
+ args.push("--force");
86
+ requires.push("--force");
87
+ }
88
+ if (context.mcp !== void 0) {
89
+ const home = requirePrivateHome(context, cursorAdapter, "MCP servers");
90
+ files.push({
91
+ path: path.join(home, ".cursor", "mcp.json"),
92
+ content: jsonFile({ mcpServers: mcpServersJson(context.mcp, { typeField: true }) })
93
+ });
94
+ args.push("--approve-mcps");
95
+ requires.push("--approve-mcps");
96
+ }
97
+ const env = context.home !== void 0 ? {
98
+ HOME: context.home,
99
+ USERPROFILE: context.home,
100
+ CURSOR_CONFIG_DIR: path.join(context.home, ".cursor"),
101
+ CURSOR_DATA_DIR: path.join(context.home, ".cursor")
102
+ } : {};
103
+ return {
104
+ args,
105
+ tail: context.transport === "argv" ? [argvPrompt(context.prompt)] : [],
106
+ stdin: context.transport === "stdin" ? context.prompt : void 0,
107
+ env,
108
+ files,
109
+ requires
110
+ };
111
+ },
112
+ parser: createCursorParser
113
+ };
114
+ /** `readToolCall` → `read`; the documented `function{name}` fallback is used as-is. */
115
+ function toolOf(toolCall) {
116
+ const fn = recordField(toolCall, "function");
117
+ if (fn !== void 0) return {
118
+ name: stringField(fn, "name") ?? "function",
119
+ body: fn
120
+ };
121
+ const key = Object.keys(toolCall ?? {})[0] ?? "tool";
122
+ return {
123
+ name: key.replace(/ToolCall$/, ""),
124
+ body: recordField(toolCall, key)
125
+ };
126
+ }
127
+ /** Parser for `cursor-agent -p --output-format stream-json`. */
128
+ function createCursorParser() {
129
+ return jsonLinesParser((record) => {
130
+ switch (stringField(record, "type")) {
131
+ case "system": return stringField(record, "subtype") === "init" ? [{
132
+ type: "session.started",
133
+ sessionRef: stringField(record, "session_id"),
134
+ model: stringField(record, "model"),
135
+ raw: record
136
+ }] : [];
137
+ case "assistant": {
138
+ const text = asArray(recordField(record, "message")?.content).map((block) => stringField(asRecord(block), "text") ?? "").join("");
139
+ return text.length > 0 ? [{
140
+ type: "message",
141
+ text,
142
+ delta: false,
143
+ raw: record
144
+ }] : [];
145
+ }
146
+ case "tool_call": {
147
+ const id = stringField(record, "call_id") ?? "";
148
+ const { name, body } = toolOf(recordField(record, "tool_call"));
149
+ if (stringField(record, "subtype") === "started") return [{
150
+ type: "tool.call",
151
+ id,
152
+ name,
153
+ input: body?.args ?? parseArguments(body?.arguments),
154
+ raw: record
155
+ }];
156
+ if (stringField(record, "subtype") === "completed") {
157
+ const result = recordField(body, "result");
158
+ const success = recordField(result, "success");
159
+ const content = stringField(success, "content");
160
+ return [{
161
+ type: "tool.result",
162
+ id,
163
+ output: success !== void 0 ? content ?? outputText(success) : outputText(result),
164
+ isError: success === void 0,
165
+ raw: record
166
+ }];
167
+ }
168
+ return [];
169
+ }
170
+ case "result": {
171
+ const events = [];
172
+ const usage = recordField(record, "usage");
173
+ if (usage !== void 0) {
174
+ const cacheRead = numberField(usage, "cacheReadTokens") ?? 0;
175
+ const cacheWrite = numberField(usage, "cacheWriteTokens") ?? 0;
176
+ events.push({
177
+ type: "usage",
178
+ cumulative: true,
179
+ usage: usageOf({
180
+ input: (numberField(usage, "inputTokens") ?? 0) + cacheRead + cacheWrite,
181
+ output: numberField(usage, "outputTokens"),
182
+ cachedTokens: cacheRead > 0 ? cacheRead : void 0,
183
+ cacheWriteTokens: cacheWrite > 0 ? cacheWrite : void 0
184
+ }),
185
+ raw: record
186
+ });
187
+ }
188
+ if (record.is_error === true) events.push({
189
+ type: "error",
190
+ message: stringField(record, "result") || "Cursor CLI reported an error",
191
+ fatal: true,
192
+ raw: record
193
+ });
194
+ return events;
195
+ }
196
+ default: return [];
197
+ }
198
+ });
199
+ }
200
+
201
+ //#endregion
202
+ export { createCursorParser, cursorAdapter };
203
+ //# sourceMappingURL=cursor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/cursor.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { CliAdapter, CliLaunchFile, CliParsedEvent, CliStreamParser } from \"../contracts\";\nimport {\n asArray,\n asRecord,\n jsonLinesParser,\n numberField,\n outputText,\n recordField,\n stringField,\n} from \"../stream/json-lines\";\nimport {\n argvPrompt,\n jsonFile,\n mcpServersJson,\n parseArguments,\n requirePrivateHome,\n usageOf,\n} from \"./shared\";\n\n/**\n * Cursor CLI (`cursor-agent`, also installed as `agent`), installed by the\n * `cursor.com/install` script (no official npm package).\n *\n * Verified against the official docs (`cursor.com/docs/cli/{headless,mcp}`,\n * `/docs/cli/reference/{output-format,parameters,authentication,\n * permissions,configuration}`) and the option strings of the\n * 2026.10.16-e3cb207 release bundle (read, not executed), 2026-10-17. The\n * capability probe checks every flag against the installed `--help`.\n *\n * - Headless: `cursor-agent -p --output-format stream-json --trust <prompt>`;\n * with no positional prompt, stdin is the prompt. `--trust` is passed\n * because print mode exits in a directory that was never trusted — the\n * run's `cwd` is the caller's explicit choice.\n * - Stream: `system/init` (`session_id`, `model`), `user` echo, `assistant`\n * messages (`message.content[].text`), `tool_call` `started`/`completed`\n * (`call_id`; the tool is the single key of `tool_call`, e.g.\n * `readToolCall{args,result{success}}`), and a final `result` with\n * `usage{inputTokens (net of cache), outputTokens, cacheReadTokens,\n * cacheWriteTokens}`. Errors are not JSON: stderr and a non-zero exit.\n * - Permissions: headless default is the allowlist mode (unlisted actions are\n * rejected, changes only proposed); bypass is `--force`.\n * - MCP: no flag; `$HOME/.cursor/mcp.json` (the path ignores\n * `CURSOR_CONFIG_DIR`), plus `--approve-mcps` — needs a private home.\n * - Home: `HOME`/`USERPROFILE`, `CURSOR_CONFIG_DIR` and `CURSOR_DATA_DIR`\n * are pointed into it. Auth: `CURSOR_API_KEY`.\n */\nexport const cursorAdapter: CliAdapter = {\n name: \"cursor\",\n title: \"Cursor CLI\",\n command: \"cursor-agent\",\n apiKeyEnv: [\"CURSOR_API_KEY\"],\n homeEnv: [\"HOME\", \"USERPROFILE\", \"CURSOR_CONFIG_DIR\", \"CURSOR_DATA_DIR\"],\n transports: [\"argv\", \"stdin\"],\n effort: false,\n mcp: true,\n probe: { help: [[\"--help\"]], version: [\"--version\"] },\n verification: {\n version: \"2026.10.16-e3cb207\",\n verifiedBy: \"docs\",\n sources: [\n \"https://cursor.com/docs/cli/headless\",\n \"https://cursor.com/docs/cli/reference/output-format\",\n \"https://cursor.com/docs/cli/reference/parameters\",\n \"https://cursor.com/docs/cli/mcp\",\n ],\n checkedAt: \"2026-10-17\",\n },\n plan(context) {\n const args = [\"--print\", \"--output-format\", \"stream-json\", \"--trust\"];\n const requires = [\"--print\", \"--output-format\", \"stream-json\", \"--trust\"];\n const files: CliLaunchFile[] = [];\n\n if (context.model !== undefined) {\n args.push(\"--model\", context.model);\n requires.push(\"--model\");\n }\n\n if (context.resume !== undefined) {\n args.push(\"--resume\", context.resume);\n requires.push(\"--resume\");\n }\n\n if (context.permission === \"bypass\") {\n args.push(\"--force\");\n requires.push(\"--force\");\n }\n\n if (context.mcp !== undefined) {\n const home = requirePrivateHome(context, cursorAdapter, \"MCP servers\");\n\n files.push({\n path: path.join(home, \".cursor\", \"mcp.json\"),\n content: jsonFile({ mcpServers: mcpServersJson(context.mcp, { typeField: true }) }),\n });\n args.push(\"--approve-mcps\");\n requires.push(\"--approve-mcps\");\n }\n\n const env: Record<string, string> =\n context.home !== undefined\n ? {\n HOME: context.home,\n USERPROFILE: context.home,\n CURSOR_CONFIG_DIR: path.join(context.home, \".cursor\"),\n CURSOR_DATA_DIR: path.join(context.home, \".cursor\"),\n }\n : {};\n\n return {\n args,\n tail: context.transport === \"argv\" ? [argvPrompt(context.prompt)] : [],\n stdin: context.transport === \"stdin\" ? context.prompt : undefined,\n env,\n files,\n requires,\n };\n },\n parser: createCursorParser,\n};\n\n/** `readToolCall` → `read`; the documented `function{name}` fallback is used as-is. */\nfunction toolOf(toolCall: Record<string, unknown> | undefined): {\n name: string;\n body: Record<string, unknown> | undefined;\n} {\n const fn = recordField(toolCall, \"function\");\n\n if (fn !== undefined) {\n return { name: stringField(fn, \"name\") ?? \"function\", body: fn };\n }\n\n const key = Object.keys(toolCall ?? {})[0] ?? \"tool\";\n\n return { name: key.replace(/ToolCall$/, \"\"), body: recordField(toolCall, key) };\n}\n\n/** Parser for `cursor-agent -p --output-format stream-json`. */\nexport function createCursorParser(): CliStreamParser {\n return jsonLinesParser((record): CliParsedEvent[] => {\n switch (stringField(record, \"type\")) {\n case \"system\":\n return stringField(record, \"subtype\") === \"init\"\n ? [\n {\n type: \"session.started\",\n sessionRef: stringField(record, \"session_id\"),\n model: stringField(record, \"model\"),\n raw: record,\n },\n ]\n : [];\n case \"assistant\": {\n const text = asArray(recordField(record, \"message\")?.content)\n .map((block) => stringField(asRecord(block), \"text\") ?? \"\")\n .join(\"\");\n\n return text.length > 0 ? [{ type: \"message\", text, delta: false, raw: record }] : [];\n }\n case \"tool_call\": {\n const id = stringField(record, \"call_id\") ?? \"\";\n const { name, body } = toolOf(recordField(record, \"tool_call\"));\n\n if (stringField(record, \"subtype\") === \"started\") {\n return [\n {\n type: \"tool.call\",\n id,\n name,\n input: body?.args ?? parseArguments(body?.arguments),\n raw: record,\n },\n ];\n }\n\n if (stringField(record, \"subtype\") === \"completed\") {\n const result = recordField(body, \"result\");\n const success = recordField(result, \"success\");\n const content = stringField(success, \"content\");\n\n return [\n {\n type: \"tool.result\",\n id,\n output: success !== undefined ? (content ?? outputText(success)) : outputText(result),\n isError: success === undefined,\n raw: record,\n },\n ];\n }\n\n return [];\n }\n case \"result\": {\n const events: CliParsedEvent[] = [];\n const usage = recordField(record, \"usage\");\n\n if (usage !== undefined) {\n const cacheRead = numberField(usage, \"cacheReadTokens\") ?? 0;\n const cacheWrite = numberField(usage, \"cacheWriteTokens\") ?? 0;\n\n events.push({\n type: \"usage\",\n cumulative: true,\n usage: usageOf({\n input: (numberField(usage, \"inputTokens\") ?? 0) + cacheRead + cacheWrite,\n output: numberField(usage, \"outputTokens\"),\n cachedTokens: cacheRead > 0 ? cacheRead : undefined,\n cacheWriteTokens: cacheWrite > 0 ? cacheWrite : undefined,\n }),\n raw: record,\n });\n }\n\n if (record.is_error === true) {\n events.push({\n type: \"error\",\n message: stringField(record, \"result\") || \"Cursor CLI reported an error\",\n fatal: true,\n raw: record,\n });\n }\n\n // `result` concatenates every assistant message, so the final answer\n // is taken from the last assistant message instead.\n return events;\n }\n default:\n return [];\n }\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { CliAdapter, CliStreamParser } from "../contracts/adapter.contract.mjs";
2
+ //#region ../../packages/ai-cli/src/adapters/droid.d.ts
3
+ /**
4
+ * Factory Droid (`droid`, npm `droid` / `@factory/cli`).
5
+ *
6
+ * Verified against the real `droid exec --help` of 0.244.0, a real
7
+ * `droid exec` run without credentials (init and error lines), the field
8
+ * names in the shipped code and the docs (`docs.factory.ai/cli/droid-exec`,
9
+ * `/cli/configuration/mcp`), 2026-10-17.
10
+ *
11
+ * - Headless: `droid exec -o stream-json <prompt>` (or `-f <file>`).
12
+ * - Stream: `system/init` (`session_id`, `model`), whole `message` records
13
+ * (`role`, `text`), `tool_call` (`id`, `toolName`, `parameters`),
14
+ * `tool_result` (`id`, `isError`, `value` | `error.message`), a final
15
+ * `completion` (`finalText`, `usage` with Anthropic-style
16
+ * `input_tokens`/`cache_read_input_tokens`/`cache_creation_input_tokens`,
17
+ * read with Anthropic semantics) and `error` (`source`, `message`).
18
+ * Billing is in Factory credits; no USD cost is reported.
19
+ * - Permissions: `standard` is Droid's default **read-only** autonomy; raise
20
+ * it with `args: ["--auto", "medium"]` (low | medium | high). Bypass is
21
+ * `--skip-permissions-unsafe`. Blocked actions end the run non-zero.
22
+ * - MCP: `<home>/.factory/mcp.json` (`mcpServers`); the home is relocated
23
+ * with `FACTORY_HOME_OVERRIDE` (found in the shipped code and confirmed
24
+ * with `droid mcp list`), so per-run MCP needs a private home.
25
+ * - Auth: `FACTORY_API_KEY`.
26
+ */
27
+ declare const droidAdapter: CliAdapter;
28
+ /** Parser for `droid exec -o stream-json`. */
29
+ declare function createDroidParser(): CliStreamParser;
30
+ //#endregion
31
+ export { createDroidParser, droidAdapter };
32
+ //# sourceMappingURL=droid.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"droid.d.mts","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/droid.ts"],"mappings":";;;;;AAoCA;;;;AA8EC;AAGD;;;;AAAoD;;;;;;;;;;;;cAjFvC,YAAA,EAAc,UA8E1B;;iBAGe,iBAAA,IAAqB,eAAe"}