@triflux/remote 10.25.1 → 10.26.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 (45) hide show
  1. package/hub/server.mjs +21 -8
  2. package/hub/team/agent-map.json +3 -3
  3. package/hub/team/backend.mjs +3 -9
  4. package/hub/team/build-worker-prompt.mjs +33 -2
  5. package/hub/team/claude-daemon-control.mjs +911 -0
  6. package/hub/team/claude-native-bridge.mjs +238 -11
  7. package/hub/team/claude-session-projection.mjs +10 -1
  8. package/hub/team/cli/commands/start/index.mjs +3 -6
  9. package/hub/team/cli/commands/start/parse-args.mjs +10 -3
  10. package/hub/team/cli/commands/start/start-headless.mjs +50 -20
  11. package/hub/team/cli/help.mjs +1 -1
  12. package/hub/team/cli/services/runtime-mode.mjs +6 -3
  13. package/hub/team/execution-mode.mjs +27 -12
  14. package/hub/team/headless.mjs +191 -43
  15. package/hub/team/interactive-native-launcher.mjs +106 -0
  16. package/hub/team/interactive-native-worker.mjs +80 -0
  17. package/hub/team/interactive-tui-transport.mjs +465 -0
  18. package/hub/team/launcher-template.mjs +28 -6
  19. package/hub/team/native.mjs +46 -7
  20. package/hub/team/pane.mjs +0 -5
  21. package/hub/team/psmux.mjs +3 -3
  22. package/hub/team/retry-state-machine.mjs +83 -14
  23. package/hub/team/session.mjs +5 -36
  24. package/hub/team/swarm-hypervisor.mjs +28 -6
  25. package/hub/team/swarm-preflight.mjs +3 -1
  26. package/hub/team/terminal-opener.mjs +1 -1
  27. package/hub/team/tui-core.mjs +4 -0
  28. package/hub/team/tui-lite.mjs +3 -2
  29. package/hub/team/tui-viewer.mjs +4 -4
  30. package/hub/team/tui.mjs +4 -2
  31. package/hub/team/worker-sandbox.mjs +4 -0
  32. package/hub/tools.mjs +4 -1
  33. package/hub/workers/antigravity-route-worker.mjs +169 -0
  34. package/hub/workers/delegator-mcp.mjs +58 -314
  35. package/hub/workers/factory.mjs +7 -4
  36. package/hub/workers/gemini-worker.mjs +55 -306
  37. package/hub/workers/interface.mjs +2 -1
  38. package/hub/workers/worker-utils.mjs +1 -1
  39. package/package.json +1 -1
  40. package/scripts/lib/cli-codex.mjs +3 -3
  41. package/scripts/lib/cli-gemini.mjs +20 -50
  42. package/scripts/lib/keyword-rules.mjs +1 -1
  43. package/scripts/lib/mcp-gateway-health-check.mjs +159 -0
  44. package/scripts/lib/mcp-gateway-wrapper-check.mjs +35 -0
  45. package/scripts/lib/psmux-info.mjs +50 -5
@@ -1,15 +1,12 @@
1
- // hub/workers/gemini-worker.mjs — Gemini headless subprocess 래퍼
2
- // ADR-006: --output-format stream-json 기반 단발 실행 워커.
1
+ // hub/workers/gemini-worker.mjs
2
+ // Deprecated compatibility surface. Direct Gemini CLI execution is removed;
3
+ // old imports now route through Antigravity.
3
4
 
4
- import { spawn } from "node:child_process";
5
5
  import { existsSync } from "node:fs";
6
6
  import { extname } from "node:path";
7
- import readline from "node:readline";
8
7
 
9
- import { extractText, terminateChild, withRetry } from "./worker-utils.mjs";
10
-
11
- const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
12
- const DEFAULT_KILL_GRACE_MS = 1000;
8
+ import { AntigravityRouteWorker } from "./antigravity-route-worker.mjs";
9
+ import { withRetry } from "./worker-utils.mjs";
13
10
 
14
11
  function toStringList(value) {
15
12
  if (!Array.isArray(value)) return [];
@@ -18,7 +15,6 @@ function toStringList(value) {
18
15
 
19
16
  /**
20
17
  * Windows에서 cmd.exe에 전달할 인자를 안전하게 quoting한다.
21
- * 빈 문자열은 ""로, 특수문자 포함 시 큰따옴표로 감싼다.
22
18
  */
23
19
  function quoteWindowsCmdArg(value) {
24
20
  const raw = String(value ?? "").replace(/[\r\n]/g, " ");
@@ -33,10 +29,6 @@ function quoteWindowsCmdArg(value) {
33
29
 
34
30
  /**
35
31
  * Windows npm shim(.cmd) spawn 문제를 해결한다.
36
- * - command -v가 확장자 없는 경로를 반환하면 .exe → .cmd → .bat 순으로 탐색
37
- * - .cmd/.bat는 CVE-2024-27980 이후 shell:false에서 실행 불가하므로 cmd.exe /d /s /c 경유
38
- * - .exe는 직접 실행
39
- * - non-Windows는 그대로 통과
40
32
  */
41
33
  function buildSpawnSpec(command, args) {
42
34
  if (process.platform !== "win32") {
@@ -65,48 +57,6 @@ function buildSpawnSpec(command, args) {
65
57
  return { command: resolved, args, shell: false };
66
58
  }
67
59
 
68
- function safeJsonParse(line) {
69
- try {
70
- return JSON.parse(line);
71
- } catch {
72
- return null;
73
- }
74
- }
75
-
76
- function findLastEvent(events, predicate) {
77
- for (let index = events.length - 1; index >= 0; index -= 1) {
78
- if (predicate(events[index])) return events[index];
79
- }
80
- return null;
81
- }
82
-
83
- function buildGeminiArgs(options) {
84
- const args = [];
85
-
86
- if (options.model) {
87
- args.push("--model", options.model);
88
- }
89
-
90
- if (options.approvalMode) {
91
- args.push("--approval-mode", options.approvalMode);
92
- } else if (options.yolo !== false) {
93
- args.push("--yolo");
94
- }
95
-
96
- const allowedMcpServers = toStringList(options.allowedMcpServerNames);
97
- if (allowedMcpServers.length) {
98
- args.push("--allowed-mcp-server-names", ...allowedMcpServers);
99
- }
100
-
101
- const extraArgs = toStringList(options.extraArgs);
102
- if (extraArgs.length) args.push(...extraArgs);
103
-
104
- args.push("--prompt", options.promptArgument ?? "");
105
- args.push("--output-format", "stream-json");
106
-
107
- return args;
108
- }
109
-
110
60
  function createWorkerError(message, details = {}) {
111
61
  const error = new Error(message);
112
62
  Object.assign(error, details);
@@ -120,7 +70,7 @@ function normalizeRetryOptions(retryOptions) {
120
70
  return Object.freeze({ ...retryOptions });
121
71
  }
122
72
 
123
- function isGeminiRetryable(error) {
73
+ function isAntigravityRetryable(error) {
124
74
  return (
125
75
  error?.code === "WORKER_EXIT" &&
126
76
  error?.result?.exitCode !== 0 &&
@@ -128,7 +78,7 @@ function isGeminiRetryable(error) {
128
78
  );
129
79
  }
130
80
 
131
- function detectGeminiCategory(error) {
81
+ function detectAntigravityCategory(error) {
132
82
  const combined =
133
83
  `${error?.message || ""}\n${error?.stderr || ""}`.toLowerCase();
134
84
 
@@ -141,32 +91,27 @@ function detectGeminiCategory(error) {
141
91
  }
142
92
  if (
143
93
  error?.result?.exitCode === 2 ||
144
- /expected stream-json|unknown option|invalid option|config/.test(combined)
94
+ /unknown option|invalid option|config|route script/.test(combined)
145
95
  ) {
146
96
  return "config";
147
97
  }
148
- if (error?.code === "WORKER_EVENT_ERROR") {
149
- return "input";
150
- }
151
98
 
152
99
  return "transient";
153
100
  }
154
101
 
155
- function buildGeminiErrorInfo(error, attempts) {
156
- const category = detectGeminiCategory(error);
157
- const retryable = isGeminiRetryable(error);
158
- let recovery = "Retry the Gemini worker after correcting the reported issue.";
102
+ function buildAntigravityErrorInfo(error, attempts) {
103
+ const category = detectAntigravityCategory(error);
104
+ const retryable = isAntigravityRetryable(error);
105
+ let recovery = "Retry the Antigravity route worker after correcting the issue.";
159
106
 
160
107
  if (category === "auth") {
161
- recovery = "Refresh the Gemini authentication state and retry.";
108
+ recovery = "Refresh the Antigravity authentication state and retry.";
162
109
  } else if (category === "config") {
163
- recovery = "Check the Gemini CLI flags and worker configuration.";
164
- } else if (category === "input") {
165
- recovery = "Check the Gemini request payload and streamed event format.";
110
+ recovery = "Check the Antigravity route worker configuration.";
166
111
  }
167
112
 
168
113
  return Object.freeze({
169
- code: error?.code || "GEMINI_EXECUTION_ERROR",
114
+ code: error?.code || "ANTIGRAVITY_EXECUTION_ERROR",
170
115
  retryable,
171
116
  attempts,
172
117
  category,
@@ -174,260 +119,64 @@ function buildGeminiErrorInfo(error, attempts) {
174
119
  });
175
120
  }
176
121
 
177
- /**
178
- * Gemini stream-json 래퍼
179
- */
180
- export class GeminiWorker {
181
- type = "gemini";
122
+ export class GeminiWorker extends AntigravityRouteWorker {
123
+ type = "antigravity";
182
124
 
183
125
  constructor(options = {}) {
184
- this.command = options.command || "gemini";
185
- this.commandArgs = toStringList(options.commandArgs || options.args);
186
- this.cwd = options.cwd || process.cwd();
187
- this.env = { ...process.env, ...(options.env || {}) };
188
- this.model = options.model || null;
189
- this.approvalMode = options.approvalMode || null;
190
- this.yolo = options.yolo !== false;
191
- this.allowedMcpServerNames = toStringList(options.allowedMcpServerNames);
192
- this.extraArgs = toStringList(options.extraArgs);
193
- this.timeoutMs =
194
- Number(options.timeoutMs) > 0
195
- ? Number(options.timeoutMs)
196
- : DEFAULT_TIMEOUT_MS;
197
- this.killGraceMs =
198
- Number(options.killGraceMs) > 0
199
- ? Number(options.killGraceMs)
200
- : DEFAULT_KILL_GRACE_MS;
126
+ const { command, commandArgs, args, model, approvalMode, yolo, ...rest } =
127
+ options;
128
+ void commandArgs;
129
+ void args;
130
+ void model;
131
+ void approvalMode;
132
+ void yolo;
133
+ super(rest);
134
+ this.command = command || "agy";
201
135
  this.retryOptions = normalizeRetryOptions(options.retryOptions);
202
- this.onEvent =
203
- typeof options.onEvent === "function" ? options.onEvent : null;
204
-
205
- this.state = "idle";
206
- this.child = null;
207
136
  this.lastRun = null;
208
137
  }
209
138
 
210
139
  getStatus() {
211
140
  return {
212
- type: "gemini",
213
- state: this.state,
214
- pid: this.child?.pid || null,
141
+ type: "antigravity",
142
+ state: this.children.size > 0 ? "running" : "idle",
143
+ pid: null,
215
144
  last_run_at_ms: this.lastRun?.finishedAtMs || null,
216
145
  last_exit_code: this.lastRun?.exitCode ?? null,
217
146
  };
218
147
  }
219
148
 
220
- async start() {
221
- if (this.state === "stopped") {
222
- this.state = "idle";
223
- }
224
- return this.getStatus();
225
- }
226
-
227
- async stop() {
228
- if (!this.child) {
229
- this.state = "stopped";
230
- return this.getStatus();
231
- }
232
- const child = this.child;
233
- terminateChild(child, this.killGraceMs);
234
- await new Promise((resolve) => {
235
- child.once("close", resolve);
236
- setTimeout(resolve, this.killGraceMs + 50).unref?.();
237
- });
238
- this.child = null;
239
- this.state = "stopped";
240
- return this.getStatus();
241
- }
242
-
243
- async restart() {
244
- await this.stop();
245
- this.state = "idle";
246
- return this.getStatus();
247
- }
248
-
249
149
  async run(prompt, options = {}) {
250
- if (this.child) {
251
- throw createWorkerError("GeminiWorker is already running", {
252
- code: "WORKER_BUSY",
253
- });
254
- }
255
-
256
- await this.start();
257
-
258
- const timeoutMs =
259
- Number(options.timeoutMs) > 0
260
- ? Number(options.timeoutMs)
261
- : this.timeoutMs;
262
150
  const startedAtMs = Date.now();
263
- const args = [
264
- ...this.commandArgs,
265
- ...buildGeminiArgs({
266
- model: options.model || this.model,
267
- approvalMode: options.approvalMode || this.approvalMode,
268
- yolo: options.yolo ?? this.yolo,
269
- allowedMcpServerNames:
270
- options.allowedMcpServerNames || this.allowedMcpServerNames,
271
- extraArgs: options.extraArgs || this.extraArgs,
272
- promptArgument: options.promptArgument ?? "",
273
- }),
274
- ];
275
-
276
- const {
277
- command: spawnCmd,
278
- args: spawnArgs,
279
- shell,
280
- } = buildSpawnSpec(this.command, args);
281
- const child = spawn(spawnCmd, spawnArgs, {
282
- cwd: options.cwd || this.cwd,
283
- env: { ...this.env, ...(options.env || {}) },
284
- stdio: ["pipe", "pipe", "pipe"],
285
- windowsHide: true,
286
- shell,
287
- });
288
-
289
- this.child = child;
290
- this.state = "running";
291
-
292
- const events = [];
293
- const stdoutLines = [];
294
- const stderrLines = [];
295
- let lastErrorEvent = null;
296
- let timedOut = false;
297
- let exitCode = null;
298
- let exitSignal = null;
299
-
300
- const stdoutReader = readline.createInterface({
301
- input: child.stdout,
302
- crlfDelay: Infinity,
303
- });
304
- const stderrReader = readline.createInterface({
305
- input: child.stderr,
306
- crlfDelay: Infinity,
307
- });
308
-
309
- stdoutReader.on("line", (line) => {
310
- if (!line) return;
311
- const event = safeJsonParse(line);
312
- if (!event) {
313
- stdoutLines.push(line);
314
- return;
315
- }
316
-
317
- events.push(event);
318
- if (event.type === "error") lastErrorEvent = event;
319
- if (this.onEvent) {
320
- try {
321
- this.onEvent(event);
322
- } catch {}
323
- }
324
- });
325
-
326
- stderrReader.on("line", (line) => {
327
- if (!line) return;
328
- stderrLines.push(line);
329
- });
330
-
331
- const closePromise = new Promise((resolve, reject) => {
332
- child.once("error", reject);
333
- child.once("close", (code, signal) => {
334
- exitCode = code;
335
- exitSignal = signal;
336
- resolve();
337
- });
338
- });
339
-
340
- const timeout = setTimeout(() => {
341
- timedOut = true;
342
- terminateChild(child, this.killGraceMs);
343
- }, timeoutMs);
344
- timeout.unref?.();
345
-
346
- child.stdin.on("error", () => {});
347
- child.stdin.end(String(prompt ?? ""));
348
-
349
- try {
350
- await closePromise;
351
- } finally {
352
- clearTimeout(timeout);
353
- stdoutReader.close();
354
- stderrReader.close();
355
- if (this.child === child) {
356
- this.child = null;
357
- }
358
- this.state = "idle";
359
- }
360
-
361
- const resultEvent = findLastEvent(
362
- events,
363
- (event) => event?.type === "result",
364
- );
365
- const response = [
366
- extractText(resultEvent),
367
- ...events
368
- .filter(
369
- (event) => event?.type === "message" || event?.type === "assistant",
370
- )
371
- .map((event) => extractText(event))
372
- .filter(Boolean),
373
- ...stdoutLines,
374
- ]
375
- .filter(Boolean)
376
- .join("\n")
377
- .trim();
378
-
379
- const result = {
380
- type: "gemini",
151
+ const result = await super.run(prompt, options);
152
+ const normalized = {
153
+ type: "antigravity",
381
154
  command: this.command,
382
- args,
383
- response,
384
- events,
385
- resultEvent,
386
- usage: resultEvent?.usage || null,
387
- stdout: stdoutLines.join("\n").trim(),
388
- stderr: stderrLines.join("\n").trim(),
389
- exitCode,
390
- exitSignal,
391
- timedOut,
155
+ args: toStringList(options.extraArgs),
156
+ response: result.response || result.output || "",
157
+ output: result.output || result.response || "",
158
+ stderr: result.stderr || "",
159
+ exitCode: result.exitCode ?? 1,
160
+ exitSignal: null,
161
+ timedOut: result.exitCode === 124,
392
162
  startedAtMs,
393
163
  finishedAtMs: Date.now(),
164
+ raw: result.raw || result,
394
165
  };
166
+ this.lastRun = normalized;
395
167
 
396
- this.lastRun = result;
397
-
398
- if (timedOut) {
399
- throw createWorkerError(`Gemini worker timed out after ${timeoutMs}ms`, {
400
- code: "ETIMEDOUT",
401
- result,
402
- stderr: result.stderr,
403
- });
404
- }
405
-
406
- if (exitCode !== 0) {
407
- // Build a descriptive message when stderr is empty to aid debugging
408
- const errMsg = result.stderr
409
- ? `Gemini worker exited with code ${exitCode}`
410
- : `Gemini worker exited with code ${exitCode} (stderr empty, signal=${exitSignal ?? "none"}, events=${events.length}, stdout=${result.stdout.length}B)`;
411
- throw createWorkerError(errMsg, {
412
- code: "WORKER_EXIT",
413
- result,
414
- stderr: result.stderr,
415
- });
416
- }
417
-
418
- if (lastErrorEvent) {
419
- throw createWorkerError("Gemini worker emitted an error event", {
420
- code: "WORKER_EVENT_ERROR",
421
- result,
422
- stderr: result.stderr,
423
- });
168
+ if (normalized.exitCode !== 0) {
169
+ throw createWorkerError(
170
+ `Antigravity route worker exited with code ${normalized.exitCode}`,
171
+ {
172
+ code: "WORKER_EXIT",
173
+ result: normalized,
174
+ stderr: normalized.stderr,
175
+ },
176
+ );
424
177
  }
425
178
 
426
- return result;
427
- }
428
-
429
- isReady() {
430
- return this.state !== "stopped";
179
+ return normalized;
431
180
  }
432
181
 
433
182
  async execute(prompt, options = {}) {
@@ -441,7 +190,7 @@ export class GeminiWorker {
441
190
  },
442
191
  {
443
192
  ...this.retryOptions,
444
- shouldRetry: (error) => isGeminiRetryable(error),
193
+ shouldRetry: (error) => isAntigravityRetryable(error),
445
194
  },
446
195
  );
447
196
 
@@ -453,15 +202,15 @@ export class GeminiWorker {
453
202
  };
454
203
  } catch (error) {
455
204
  return {
456
- output: error.stderr || error.message || "Gemini worker failed",
205
+ output: error.stderr || error.message || "Antigravity worker failed",
457
206
  exitCode: error.code === "ETIMEDOUT" ? 124 : 1,
458
207
  sessionKey: options.sessionKey || null,
459
- error: buildGeminiErrorInfo(error, attempts || 1),
208
+ error: buildAntigravityErrorInfo(error, attempts || 1),
460
209
  raw: error.result || null,
461
210
  };
462
211
  }
463
212
  }
464
213
  }
465
214
 
466
- /** @visibleForTesting — 테스트 전용 export. 외부 소비 금지. */
215
+ /** @visibleForTesting - 테스트 전용 export. 외부 소비 금지. */
467
216
  export { buildSpawnSpec, quoteWindowsCmdArg };
@@ -61,13 +61,14 @@
61
61
  * @property {() => Promise<void>} start
62
62
  * @property {() => Promise<void>} stop
63
63
  * @property {() => boolean} isReady
64
- * @property {'codex'|'codex-app-server'|'gemini'|'claude'|'delegator'} type
64
+ * @property {'codex'|'codex-app-server'|'gemini'|'antigravity'|'claude'|'delegator'} type
65
65
  */
66
66
 
67
67
  export const WORKER_TYPES = Object.freeze([
68
68
  "codex",
69
69
  "codex-app-server",
70
70
  "gemini",
71
+ "antigravity",
71
72
  "claude",
72
73
  "delegator",
73
74
  ]);
@@ -1,5 +1,5 @@
1
1
  // hub/workers/worker-utils.mjs — 워커 공통 유틸리티
2
- // claude-worker, gemini-worker, pipe 등에서 공유하는 순수 유틸 함수 모음.
2
+ // claude-worker, Antigravity route compatibility worker, pipe 등에서 공유하는 순수 유틸 함수 모음.
3
3
 
4
4
  export const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
5
5
  export const DEFAULT_KILL_GRACE_MS = 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triflux/remote",
3
- "version": "10.25.1",
3
+ "version": "10.26.0",
4
4
  "description": "triflux remote — team mode, psmux, MCP workers, SQLite store.",
5
5
  "type": "module",
6
6
  "main": "hub/index.mjs",
@@ -33,14 +33,14 @@ const AGENT_PROFILES = {
33
33
  mcpHint: "implement",
34
34
  },
35
35
  cleanup: {
36
- profile: "mini54_med",
36
+ profile: "gpt55_med",
37
37
  timeoutSec: 540,
38
38
  runMode: "fg",
39
39
  opusOversight: false,
40
40
  mcpHint: "implement",
41
41
  },
42
42
  deslop: {
43
- profile: "mini54_med",
43
+ profile: "gpt55_med",
44
44
  timeoutSec: 540,
45
45
  runMode: "fg",
46
46
  opusOversight: false,
@@ -157,7 +157,7 @@ const AGENT_PROFILES = {
157
157
  subcommand: "review",
158
158
  },
159
159
  spark: {
160
- profile: "spark53_low",
160
+ profile: "gpt55_low",
161
161
  timeoutSec: 180,
162
162
  runMode: "fg",
163
163
  opusOversight: false,
@@ -1,39 +1,11 @@
1
- // cli-gemini.mjs — Gemini CLI adapter (Phase 0 PoC).
2
- //
3
- // 책임: Gemini 프로파일/모델/timeout 매핑. resolve_gemini_profile() 의 결과는 Phase 1 에서
4
- // 통합한다 (Phase 0 은 라벨만 전달).
5
- //
6
- // 출처: scripts/tfx-route.sh route_agent() L1045-L1050.
1
+ // cli-gemini.mjs — legacy Gemini adapter alias.
2
+ // The public "gemini" label remains accepted, but the executable plan is AGY.
7
3
 
8
- export const id = "gemini";
9
- export const cliType = "gemini";
10
- export const command = "gemini";
11
-
12
- const AGENT_PROFILES = {
13
- designer: {
14
- profile: "pro31",
15
- timeoutSec: 900,
16
- runMode: "bg",
17
- opusOversight: false,
18
- mcpHint: "docs",
19
- },
20
- gemini: {
21
- profile: "pro31",
22
- timeoutSec: 900,
23
- runMode: "bg",
24
- opusOversight: false,
25
- mcpHint: "docs",
26
- },
27
- writer: {
28
- profile: "flash3",
29
- timeoutSec: 900,
30
- runMode: "bg",
31
- opusOversight: false,
32
- mcpHint: "docs",
33
- },
34
- };
4
+ import * as agyAdapter from "./cli-agy.mjs";
35
5
 
36
- const DEFAULT_PROFILE = AGENT_PROFILES.gemini;
6
+ export const id = "gemini";
7
+ export const cliType = "antigravity";
8
+ export const command = "agy";
37
9
 
38
10
  export function plan({
39
11
  agent,
@@ -45,23 +17,21 @@ export function plan({
45
17
  if (!agent) {
46
18
  throw new Error("[cli-gemini] agent required");
47
19
  }
48
- const cfg = AGENT_PROFILES[agent] ?? DEFAULT_PROFILE;
49
- const effectiveTimeoutSec =
50
- Number.isFinite(timeoutSec) && timeoutSec > 0 ? timeoutSec : cfg.timeoutSec;
51
- return {
52
- command,
53
- profile: cfg.profile,
54
- effort: cfg.profile,
55
- args: ["-m", cfg.profile, "-y", "--prompt"],
56
- timeoutMs: effectiveTimeoutSec * 1000,
57
- runMode: cfg.runMode,
58
- opusOversight: cfg.opusOversight,
59
- mcpProfile: mcpProfile === "auto" ? cfg.mcpHint : mcpProfile,
60
- promptLength: prompt.length,
61
- contextFile: contextFile || null,
62
- };
20
+ return agyAdapter.plan({
21
+ agent: agent === "gemini" ? "antigravity" : agent,
22
+ prompt,
23
+ mcpProfile,
24
+ timeoutSec,
25
+ contextFile,
26
+ });
63
27
  }
64
28
 
65
29
  export function describe() {
66
- return { id, cliType, command, agents: Object.keys(AGENT_PROFILES) };
30
+ return {
31
+ id,
32
+ cliType,
33
+ command,
34
+ aliases: ["gemini"],
35
+ agents: ["gemini", "designer", "writer", "antigravity", "agy"],
36
+ };
67
37
  }
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from "node:fs";
2
2
 
3
- const VALID_MCP_ROUTES = new Set(["codex", "gemini", "claude"]);
3
+ const VALID_MCP_ROUTES = new Set(["codex", "antigravity", "gemini", "claude"]);
4
4
 
5
5
  function logRuleError(message, error) {
6
6
  if (error) {