@prismatic-io/lux 0.0.2-preview.22 → 0.0.2-preview.24
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.
- package/lib/answerers/persona/index.d.ts.map +1 -1
- package/lib/answerers/persona/index.js +3 -2
- package/lib/answerers/persona/index.js.map +1 -1
- package/lib/cli/init-templates.d.ts +1 -1
- package/lib/cli/init-templates.d.ts.map +1 -1
- package/lib/cli/init-templates.js +1 -0
- package/lib/cli/init-templates.js.map +1 -1
- package/lib/cli/init.d.ts +1 -0
- package/lib/cli/init.d.ts.map +1 -1
- package/lib/cli/init.js +10 -2
- package/lib/cli/init.js.map +1 -1
- package/lib/cli/program.d.ts +1 -1
- package/lib/cli/program.d.ts.map +1 -1
- package/lib/cli/program.js +9 -1
- package/lib/cli/program.js.map +1 -1
- package/lib/core/harness-catalogs/grok-build.d.ts +7 -0
- package/lib/core/harness-catalogs/grok-build.d.ts.map +1 -0
- package/lib/core/harness-catalogs/grok-build.js +18 -0
- package/lib/core/harness-catalogs/grok-build.js.map +1 -0
- package/lib/core/harness-catalogs/index.d.ts +7 -1
- package/lib/core/harness-catalogs/index.d.ts.map +1 -1
- package/lib/core/harness-catalogs/index.js +3 -1
- package/lib/core/harness-catalogs/index.js.map +1 -1
- package/lib/drivers/antigravity/config.d.ts +6 -0
- package/lib/drivers/antigravity/config.d.ts.map +1 -1
- package/lib/drivers/antigravity/config.js +4 -0
- package/lib/drivers/antigravity/config.js.map +1 -1
- package/lib/drivers/antigravity/index.d.ts +7 -0
- package/lib/drivers/antigravity/index.d.ts.map +1 -1
- package/lib/drivers/grok-build/config.d.ts +65 -0
- package/lib/drivers/grok-build/config.d.ts.map +1 -0
- package/lib/drivers/grok-build/config.js +37 -0
- package/lib/drivers/grok-build/config.js.map +1 -0
- package/lib/drivers/grok-build/index.d.ts +83 -0
- package/lib/drivers/grok-build/index.d.ts.map +1 -0
- package/lib/drivers/grok-build/index.js +291 -0
- package/lib/drivers/grok-build/index.js.map +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/orchestrator/config.d.ts.map +1 -1
- package/lib/orchestrator/config.js +2 -0
- package/lib/orchestrator/config.js.map +1 -1
- package/package.json +1 -1
- package/skills/lux-answerer/SKILL.md +1 -1
- package/src/answerers/persona/index.ts +3 -2
- package/src/cli/init-templates.ts +9 -1
- package/src/cli/init.ts +10 -2
- package/src/cli/program.ts +9 -1
- package/src/core/harness-catalogs/grok-build.ts +19 -0
- package/src/core/harness-catalogs/index.ts +10 -1
- package/src/drivers/antigravity/README.md +15 -0
- package/src/drivers/antigravity/config.ts +4 -0
- package/src/drivers/grok-build/README.md +112 -0
- package/src/drivers/grok-build/config.ts +40 -0
- package/src/drivers/grok-build/index.ts +329 -0
- package/src/index.ts +7 -2
- package/src/orchestrator/config.ts +2 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import {
|
|
3
|
+
type AgentDriver,
|
|
4
|
+
type Answer,
|
|
5
|
+
type Artifact,
|
|
6
|
+
type DriverEventMap,
|
|
7
|
+
defineDriver,
|
|
8
|
+
discoverCliVersion,
|
|
9
|
+
type ReadyState,
|
|
10
|
+
type StartContext,
|
|
11
|
+
selectModelAndReasoningEffort,
|
|
12
|
+
TypedEmitter,
|
|
13
|
+
} from "../../core/index.js";
|
|
14
|
+
import { AcpEvents } from "../shared/acp-events.js";
|
|
15
|
+
import { permissionAnswer, permissionRequestText, records } from "../shared/acp-interaction.js";
|
|
16
|
+
import { AcpTransport, asRecord, type RpcId, type RpcRecord } from "../shared/acp-transport.js";
|
|
17
|
+
import { walkArtifacts } from "../shared/artifacts.js";
|
|
18
|
+
import {
|
|
19
|
+
buildGrokBuildArgs,
|
|
20
|
+
type GrokBuildDriverConfig,
|
|
21
|
+
GrokBuildDriverConfigSchema,
|
|
22
|
+
} from "./config.js";
|
|
23
|
+
|
|
24
|
+
class GrokBuildDriver implements AgentDriver {
|
|
25
|
+
private readonly emitter = new TypedEmitter<DriverEventMap>();
|
|
26
|
+
private readonly events: AcpEvents;
|
|
27
|
+
private transport: AcpTransport | undefined;
|
|
28
|
+
private sessionId: string | undefined;
|
|
29
|
+
private cwd: string | undefined;
|
|
30
|
+
private artifactsDir: string | undefined;
|
|
31
|
+
private ready = false;
|
|
32
|
+
private runPromise: Promise<void> | undefined;
|
|
33
|
+
private terminal = false;
|
|
34
|
+
private idleTimer: NodeJS.Timeout | undefined;
|
|
35
|
+
private interruptCount = 0;
|
|
36
|
+
private readonly interrupts = new Map<
|
|
37
|
+
string,
|
|
38
|
+
{ id: RpcId; params: RpcRecord; timer: NodeJS.Timeout }
|
|
39
|
+
>();
|
|
40
|
+
|
|
41
|
+
private readonly config: GrokBuildDriverConfig;
|
|
42
|
+
|
|
43
|
+
constructor(config: GrokBuildDriverConfig) {
|
|
44
|
+
this.config = config;
|
|
45
|
+
this.events = new AcpEvents("grok-build", config.maxToolCalls, config.maxQueuedBytes);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
on<K extends keyof DriverEventMap>(
|
|
49
|
+
event: K,
|
|
50
|
+
handler: (e: DriverEventMap[K]) => void | Promise<void>,
|
|
51
|
+
): void {
|
|
52
|
+
this.emitter.on(event, handler);
|
|
53
|
+
}
|
|
54
|
+
off<K extends keyof DriverEventMap>(
|
|
55
|
+
event: K,
|
|
56
|
+
handler: (e: DriverEventMap[K]) => void | Promise<void>,
|
|
57
|
+
): void {
|
|
58
|
+
this.emitter.off(event, handler);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async start(ctx: StartContext): Promise<ReadyState> {
|
|
62
|
+
if (this.transport || this.terminal)
|
|
63
|
+
throw new Error("Grok.build driver cannot be started twice or after close");
|
|
64
|
+
this.cwd = await realpath(this.config.cwd ?? ctx.artifactsDir);
|
|
65
|
+
this.artifactsDir = await realpath(ctx.artifactsDir);
|
|
66
|
+
const cliVersion = await discoverCliVersion(this.config.command);
|
|
67
|
+
const transport = new AcpTransport({
|
|
68
|
+
label: "Grok.build ACP",
|
|
69
|
+
command: this.config.command,
|
|
70
|
+
args: buildGrokBuildArgs(this.config),
|
|
71
|
+
cwd: this.cwd,
|
|
72
|
+
env: { ...process.env, ...this.config.env },
|
|
73
|
+
signal: ctx.abortSignal,
|
|
74
|
+
maxLineBytes: this.config.maxLineBytes,
|
|
75
|
+
maxQueuedBytes: this.config.maxQueuedBytes,
|
|
76
|
+
onMessage: (message) => this.message(message),
|
|
77
|
+
onFailure: (error) => this.fail(error),
|
|
78
|
+
onActivity: () => this.bumpIdleTimer(),
|
|
79
|
+
});
|
|
80
|
+
this.transport = transport;
|
|
81
|
+
try {
|
|
82
|
+
await transport.spawned();
|
|
83
|
+
const initialized = await this.request("initialize", {
|
|
84
|
+
protocolVersion: 1,
|
|
85
|
+
clientInfo: { name: "lux", version: "1" },
|
|
86
|
+
clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },
|
|
87
|
+
});
|
|
88
|
+
if (initialized.protocolVersion !== 1)
|
|
89
|
+
throw new Error("Grok.build ACP returned an unsupported protocol version");
|
|
90
|
+
if (asRecord(initialized._meta)?.grokShell !== true)
|
|
91
|
+
throw new Error("Expected Grok.build ACP; check the configured command points to grok");
|
|
92
|
+
const session = await this.request("session/new", {
|
|
93
|
+
cwd: this.cwd,
|
|
94
|
+
mcpServers: [],
|
|
95
|
+
_meta: { autoMode: this.config.permissionMode === "auto", yoloMode: false },
|
|
96
|
+
});
|
|
97
|
+
if (typeof session.sessionId !== "string")
|
|
98
|
+
throw new Error("Grok.build ACP omitted sessionId");
|
|
99
|
+
this.sessionId = session.sessionId;
|
|
100
|
+
let nativeConfig = session.configOptions;
|
|
101
|
+
for (const [configId, value] of [
|
|
102
|
+
["model", this.config.model],
|
|
103
|
+
["reasoning_effort", this.config.reasoningEffort],
|
|
104
|
+
] as const) {
|
|
105
|
+
const updated = await this.request("session/set_config_option", {
|
|
106
|
+
sessionId: this.sessionId,
|
|
107
|
+
configId,
|
|
108
|
+
value,
|
|
109
|
+
});
|
|
110
|
+
nativeConfig = updated.configOptions;
|
|
111
|
+
if (records(nativeConfig).find((option) => option.id === configId)?.currentValue !== value)
|
|
112
|
+
throw new Error(`Grok.build ACP did not apply requested ${configId} '${value}'`);
|
|
113
|
+
}
|
|
114
|
+
this.ready = true;
|
|
115
|
+
this.bumpIdleTimer();
|
|
116
|
+
this.runPromise = this.run(ctx.prompt).catch((error: unknown) => this.fail(error));
|
|
117
|
+
return {
|
|
118
|
+
agentId: "grok-build",
|
|
119
|
+
model: this.config.model,
|
|
120
|
+
...(typeof asRecord(initialized._meta)?.agentVersion === "string"
|
|
121
|
+
? { agentVersion: String(asRecord(initialized._meta)?.agentVersion) }
|
|
122
|
+
: {}),
|
|
123
|
+
detail: {
|
|
124
|
+
sessionId: this.sessionId,
|
|
125
|
+
transport: "acp",
|
|
126
|
+
protocolVersion: 1,
|
|
127
|
+
...(cliVersion ? { cliVersion } : {}),
|
|
128
|
+
permissionMode: this.config.permissionMode,
|
|
129
|
+
sandbox: this.config.sandbox,
|
|
130
|
+
trustProject: this.config.trustProject,
|
|
131
|
+
reasoningEffort: this.config.reasoningEffort,
|
|
132
|
+
modelResolution: "reported",
|
|
133
|
+
nativeConfig: nativeConfig ?? [],
|
|
134
|
+
usageAvailability: "unknown",
|
|
135
|
+
isolation: "none",
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
} catch (error) {
|
|
139
|
+
await this.close();
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private request(method: string, params: RpcRecord): Promise<RpcRecord> {
|
|
145
|
+
if (!this.transport) throw new Error("Grok.build ACP has not started");
|
|
146
|
+
return this.transport.request(method, params, this.config.startupTimeoutMs);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private async run(prompt: string): Promise<void> {
|
|
150
|
+
const result = await this.transport?.request("session/prompt", {
|
|
151
|
+
sessionId: this.sessionId,
|
|
152
|
+
prompt: [{ type: "text", text: prompt }],
|
|
153
|
+
});
|
|
154
|
+
await this.transport?.drained();
|
|
155
|
+
if (this.terminal) return;
|
|
156
|
+
if (result?.stopReason !== "end_turn")
|
|
157
|
+
throw new Error(`Grok.build stopped with ${String(result?.stopReason ?? "unknown reason")}`);
|
|
158
|
+
if (this.interrupts.size > 0)
|
|
159
|
+
throw new Error("Grok.build ended with pending permission requests");
|
|
160
|
+
this.terminal = true;
|
|
161
|
+
clearTimeout(this.idleTimer);
|
|
162
|
+
await this.emitter.emit("done", {
|
|
163
|
+
exitReason: "done",
|
|
164
|
+
summary: {
|
|
165
|
+
sessionId: this.sessionId,
|
|
166
|
+
stopReason: result.stopReason,
|
|
167
|
+
usageAvailability: "unknown",
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private async message(message: RpcRecord): Promise<void> {
|
|
173
|
+
if (this.terminal) return;
|
|
174
|
+
const method = String(message.method);
|
|
175
|
+
const params = asRecord(message.params) ?? {};
|
|
176
|
+
const id = message.id;
|
|
177
|
+
if (typeof id === "number" || typeof id === "string") {
|
|
178
|
+
if (params.sessionId !== this.sessionId) {
|
|
179
|
+
this.transport?.write({ id, error: { code: -32602, message: "Unknown session" } });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (method !== "session/request_permission") {
|
|
183
|
+
this.transport?.write({
|
|
184
|
+
id,
|
|
185
|
+
error: { code: -32601, message: `Unsupported method: ${method}` },
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (++this.interruptCount > this.config.maxInterrupts) {
|
|
190
|
+
this.transport?.write({ id, result: { outcome: { outcome: "cancelled" } } });
|
|
191
|
+
throw new Error("Grok.build exceeded maxInterrupts");
|
|
192
|
+
}
|
|
193
|
+
const interruptId = `grok-build-${id}`;
|
|
194
|
+
if (this.interrupts.has(interruptId))
|
|
195
|
+
throw new Error("Grok.build reused a pending request ID");
|
|
196
|
+
const timer = setTimeout(() => {
|
|
197
|
+
this.transport?.write({ id, result: { outcome: { outcome: "cancelled" } } });
|
|
198
|
+
this.interrupts.delete(interruptId);
|
|
199
|
+
this.fail(
|
|
200
|
+
new Error(
|
|
201
|
+
`Grok.build permission review timed out after ${this.config.permissionTimeoutMs}ms`,
|
|
202
|
+
),
|
|
203
|
+
);
|
|
204
|
+
}, this.config.permissionTimeoutMs);
|
|
205
|
+
this.interrupts.set(interruptId, { id, params, timer });
|
|
206
|
+
clearTimeout(this.idleTimer);
|
|
207
|
+
void this.emitter
|
|
208
|
+
.emit("interrupt", {
|
|
209
|
+
kind: "approve",
|
|
210
|
+
id: interruptId,
|
|
211
|
+
request: `${permissionRequestText(params)}\n\nOperation details:\n${JSON.stringify(params.toolCall)}`,
|
|
212
|
+
context: params,
|
|
213
|
+
})
|
|
214
|
+
.catch((error: unknown) => this.fail(error));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (method === "session/update") {
|
|
218
|
+
if (params.sessionId !== this.sessionId) return;
|
|
219
|
+
const update = asRecord(params.update);
|
|
220
|
+
if (update)
|
|
221
|
+
for (const event of this.events.update(update)) await this.emitter.emit("progress", event);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async respond(answer: Answer): Promise<void> {
|
|
226
|
+
if (this.terminal) throw new Error("Grok.build is closed");
|
|
227
|
+
const pending = this.interrupts.get(answer.id);
|
|
228
|
+
if (!pending) throw new Error(`Grok.build has no pending interrupt '${answer.id}'`);
|
|
229
|
+
const result = permissionAnswer(pending.params, answer);
|
|
230
|
+
this.transport?.write({ id: pending.id, result });
|
|
231
|
+
if (asRecord(result.outcome)?.outcome === "cancelled") {
|
|
232
|
+
this.fail(new Error("Grok.build offered no matching one-operation permission option"));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
clearTimeout(pending.timer);
|
|
236
|
+
this.interrupts.delete(answer.id);
|
|
237
|
+
this.bumpIdleTimer();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private bumpIdleTimer(): void {
|
|
241
|
+
clearTimeout(this.idleTimer);
|
|
242
|
+
if (!this.ready || this.terminal || this.interrupts.size > 0) return;
|
|
243
|
+
this.idleTimer = setTimeout(
|
|
244
|
+
() =>
|
|
245
|
+
this.fail(
|
|
246
|
+
new Error(`Grok.build emitted no event for ${this.config.idleTimeoutMs}ms`),
|
|
247
|
+
"idle-timeout",
|
|
248
|
+
),
|
|
249
|
+
this.config.idleTimeoutMs,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private fail(error: unknown, exitReason: "error" | "idle-timeout" = "error"): void {
|
|
254
|
+
if (this.terminal) return;
|
|
255
|
+
this.terminal = true;
|
|
256
|
+
clearTimeout(this.idleTimer);
|
|
257
|
+
for (const pending of this.interrupts.values()) clearTimeout(pending.timer);
|
|
258
|
+
if (this.ready)
|
|
259
|
+
void this.transport?.drained().then(() =>
|
|
260
|
+
this.emitter.emit("error", {
|
|
261
|
+
exitReason,
|
|
262
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
265
|
+
void this.transport?.close();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async quiesce(): Promise<void> {
|
|
269
|
+
clearTimeout(this.idleTimer);
|
|
270
|
+
const cancelling = !this.terminal && this.sessionId !== undefined;
|
|
271
|
+
this.terminal = true;
|
|
272
|
+
for (const pending of this.interrupts.values()) clearTimeout(pending.timer);
|
|
273
|
+
if (cancelling) {
|
|
274
|
+
for (const pending of this.interrupts.values())
|
|
275
|
+
this.transport?.write({ id: pending.id, result: { outcome: { outcome: "cancelled" } } });
|
|
276
|
+
this.transport?.write({ method: "session/cancel", params: { sessionId: this.sessionId } });
|
|
277
|
+
let timer: NodeJS.Timeout | undefined;
|
|
278
|
+
try {
|
|
279
|
+
await Promise.race([
|
|
280
|
+
this.runPromise,
|
|
281
|
+
new Promise<void>((resolve) => {
|
|
282
|
+
timer = setTimeout(resolve, 200);
|
|
283
|
+
}),
|
|
284
|
+
]);
|
|
285
|
+
} finally {
|
|
286
|
+
clearTimeout(timer);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
for (const pending of this.interrupts.values()) clearTimeout(pending.timer);
|
|
290
|
+
this.interrupts.clear();
|
|
291
|
+
await this.transport?.close();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async collect(): Promise<Artifact[]> {
|
|
295
|
+
await this.quiesce();
|
|
296
|
+
if (!this.cwd) return [];
|
|
297
|
+
const artifacts = await walkArtifacts(this.cwd);
|
|
298
|
+
return this.cwd === this.artifactsDir
|
|
299
|
+
? artifacts
|
|
300
|
+
: artifacts.map((artifact) => ({ ...artifact, root: this.cwd as string }));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async close(): Promise<void> {
|
|
304
|
+
await this.quiesce();
|
|
305
|
+
this.emitter.removeAllListeners();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const grokBuildDriver = defineDriver({
|
|
310
|
+
name: "grok-build",
|
|
311
|
+
configSchema: GrokBuildDriverConfigSchema,
|
|
312
|
+
runtime: (config) => ({
|
|
313
|
+
commands: [config.command],
|
|
314
|
+
capabilities: {
|
|
315
|
+
interactive: true,
|
|
316
|
+
"tool-calls": true,
|
|
317
|
+
"tool-results": true,
|
|
318
|
+
artifacts: true,
|
|
319
|
+
usage: false,
|
|
320
|
+
cost: false,
|
|
321
|
+
isolation: false,
|
|
322
|
+
},
|
|
323
|
+
}),
|
|
324
|
+
selectHarness: selectModelAndReasoningEffort,
|
|
325
|
+
create: (config) => new GrokBuildDriver(config),
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
export type { GrokBuildDriverConfig };
|
|
329
|
+
export { buildGrokBuildArgs, GrokBuildDriverConfigSchema };
|
package/src/index.ts
CHANGED
|
@@ -364,6 +364,7 @@ export {
|
|
|
364
364
|
codexCatalog,
|
|
365
365
|
copilotCatalog,
|
|
366
366
|
cursorCatalog,
|
|
367
|
+
grokBuildCatalog,
|
|
367
368
|
harnessCatalogFor,
|
|
368
369
|
} from "./core/harness-catalogs/index.js";
|
|
369
370
|
export {
|
|
@@ -528,6 +529,12 @@ export {
|
|
|
528
529
|
CursorDriverConfigSchema,
|
|
529
530
|
cursorDriver,
|
|
530
531
|
} from "./drivers/cursor/index.js";
|
|
532
|
+
export {
|
|
533
|
+
buildGrokBuildArgs,
|
|
534
|
+
type GrokBuildDriverConfig,
|
|
535
|
+
GrokBuildDriverConfigSchema,
|
|
536
|
+
grokBuildDriver,
|
|
537
|
+
} from "./drivers/grok-build/index.js";
|
|
531
538
|
export {
|
|
532
539
|
type McpProbeDriverConfig,
|
|
533
540
|
McpProbeDriverConfigSchema,
|
|
@@ -539,13 +546,11 @@ export {
|
|
|
539
546
|
SubprocessDriverConfigSchema,
|
|
540
547
|
subprocessDriver,
|
|
541
548
|
} from "./drivers/subprocess/index.js";
|
|
542
|
-
|
|
543
549
|
export {
|
|
544
550
|
createReflectiveOptimizer,
|
|
545
551
|
type ReflectiveOptimizerConfig,
|
|
546
552
|
ReflectiveOptimizerConfigSchema,
|
|
547
553
|
} from "./optimization/reflective.js";
|
|
548
|
-
|
|
549
554
|
// Supported programmatic orchestration.
|
|
550
555
|
export {
|
|
551
556
|
applyCandidate,
|
|
@@ -29,6 +29,7 @@ import { claudeCodeDriver } from "../drivers/claude-code/index.js";
|
|
|
29
29
|
import { codexDriver } from "../drivers/codex/index.js";
|
|
30
30
|
import { copilotDriver } from "../drivers/copilot/index.js";
|
|
31
31
|
import { cursorDriver } from "../drivers/cursor/index.js";
|
|
32
|
+
import { grokBuildDriver } from "../drivers/grok-build/index.js";
|
|
32
33
|
import { mcpProbeDriver } from "../drivers/mcp/index.js";
|
|
33
34
|
import { subprocessDriver } from "../drivers/subprocess/index.js";
|
|
34
35
|
|
|
@@ -188,6 +189,7 @@ const builtinDrivers: DriverPlugin<never>[] = [
|
|
|
188
189
|
codexDriver,
|
|
189
190
|
cursorDriver,
|
|
190
191
|
copilotDriver,
|
|
192
|
+
grokBuildDriver,
|
|
191
193
|
antigravityDriver,
|
|
192
194
|
subprocessDriver,
|
|
193
195
|
mcpProbeDriver,
|