@triflux/remote 10.25.1 → 10.27.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 +244 -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 +63 -14
  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
@@ -12,11 +12,9 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
13
  import * as z from "zod";
14
14
  import { resolveBashExecutable } from "@triflux/core/hub/lib/bash-path.mjs";
15
- import { whichCommand } from "@triflux/core/hub/platform.mjs";
16
15
  import { runHeadlessWithCleanup } from "../team/headless.mjs";
17
16
  import { buildWorkerSandboxEnv } from "../team/worker-sandbox.mjs";
18
17
  import { CodexMcpWorker } from "./codex-mcp.mjs";
19
- import { GeminiWorker } from "./gemini-worker.mjs";
20
18
 
21
19
  const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
22
20
 
@@ -34,7 +32,6 @@ if (!mcpFilterPath) {
34
32
  const {
35
33
  buildPromptHint,
36
34
  getCodexMcpConfig,
37
- getGeminiAllowedServers,
38
35
  SUPPORTED_MCP_PROFILES,
39
36
  } = await import(pathToFileURL(mcpFilterPath).href);
40
37
  const SERVER_INFO = { name: "triflux-delegator", version: "1.0.0" };
@@ -70,30 +67,24 @@ const AGENT_TIMEOUT_SEC = Object.freeze({
70
67
  });
71
68
 
72
69
  const CODEX_PROFILE_BY_AGENT = Object.freeze({
73
- executor: "codex53_high",
74
- "build-fixer": "codex53_low",
75
- debugger: "codex53_high",
76
- "deep-executor": "gpt54_xhigh",
77
- architect: "gpt54_xhigh",
78
- planner: "gpt54_xhigh",
79
- critic: "gpt54_xhigh",
80
- analyst: "gpt54_xhigh",
81
- "code-reviewer": "codex53_high",
82
- "security-reviewer": "codex53_high",
83
- "quality-reviewer": "codex53_high",
84
- scientist: "codex53_high",
85
- "scientist-deep": "gpt54_high",
86
- "document-specialist": "codex53_high",
87
- verifier: "codex53_high",
88
- designer: "gpt54_xhigh", // Gemini primary, codex fallback — UI/UX는 5.4 에이전틱
89
- writer: "codex53_high", // Gemini primary, codex fallback용
90
- spark: "spark53_low",
91
- });
92
-
93
- const GEMINI_MODEL_BY_AGENT = Object.freeze({
94
- "build-fixer": "gemini-3-flash-preview",
95
- writer: "gemini-3-flash-preview",
96
- spark: "gemini-3-flash-preview",
70
+ executor: "gpt55_high",
71
+ "build-fixer": "gpt55_low",
72
+ debugger: "gpt55_xhigh",
73
+ "deep-executor": "gpt55_xhigh",
74
+ architect: "gpt55_xhigh",
75
+ planner: "gpt55_xhigh",
76
+ critic: "gpt55_xhigh",
77
+ analyst: "gpt55_xhigh",
78
+ "code-reviewer": "gpt55_high",
79
+ "security-reviewer": "gpt55_xhigh",
80
+ "quality-reviewer": "gpt55_high",
81
+ scientist: "gpt55_high",
82
+ "scientist-deep": "gpt55_xhigh",
83
+ "document-specialist": "gpt55_high",
84
+ verifier: "gpt55_high",
85
+ designer: "gpt55_xhigh",
86
+ writer: "gpt55_low",
87
+ spark: "gpt55_low",
97
88
  });
98
89
 
99
90
  const REVIEW_INSTRUCTION_BY_AGENT = Object.freeze({
@@ -152,8 +143,13 @@ function resolveCodexProfile(agentType) {
152
143
  return CODEX_PROFILE_BY_AGENT[agentType] || "high";
153
144
  }
154
145
 
155
- function resolveGeminiModel(agentType) {
156
- return GEMINI_MODEL_BY_AGENT[agentType] || "gemini-3.1-pro-preview";
146
+ function normalizeProvider(provider = "auto") {
147
+ const value = provider || "auto";
148
+ return value === "gemini" ? "antigravity" : value;
149
+ }
150
+
151
+ function normalizeDelegateArgs(args = {}) {
152
+ return { ...args, provider: normalizeProvider(args.provider) };
157
153
  }
158
154
 
159
155
  function resolveTimeoutMs(agentType, timeoutMs) {
@@ -187,21 +183,6 @@ function withContext(prompt, contextFile) {
187
183
  return `${prompt}\n\n<prior_context>\n${context}\n</prior_context>`;
188
184
  }
189
185
 
190
- function withPromptHint(prompt, args) {
191
- const promptWithContext = withContext(prompt, args.contextFile);
192
- const hint = buildPromptHint({
193
- agentType: args.agentType,
194
- requestedProfile: args.mcpProfile,
195
- searchTool: args.searchTool,
196
- workerIndex: Number.isInteger(args.workerIndex)
197
- ? args.workerIndex
198
- : undefined,
199
- taskText: promptWithContext,
200
- });
201
- if (!hint) return promptWithContext;
202
- return `${promptWithContext}. ${hint}`;
203
- }
204
-
205
186
  function joinInstructions(...values) {
206
187
  return values
207
188
  .filter((value) => typeof value === "string" && value.trim())
@@ -231,7 +212,7 @@ function parseRouteType(stderr = "") {
231
212
  const match = stderr.match(/type=([a-z-]+)/);
232
213
  if (!match) return null;
233
214
  if (match[1] === "codex") return "codex";
234
- if (match[1] === "gemini") return "gemini";
215
+ if (match[1] === "gemini") return "antigravity";
235
216
  return match[1];
236
217
  }
237
218
 
@@ -265,7 +246,7 @@ function createErrorPayload(message, extras = {}) {
265
246
  const DelegateInputSchema = z.object({
266
247
  prompt: z.string().min(1).describe("위임할 프롬프트"),
267
248
  provider: z
268
- .enum(["auto", "codex", "gemini"])
249
+ .enum(["auto", "codex", "antigravity", "gemini"])
269
250
  .default("auto")
270
251
  .describe("사용할 provider"),
271
252
  mode: z
@@ -327,7 +308,9 @@ const DelegateInputSchema = z.object({
327
308
  workers: z
328
309
  .array(
329
310
  z.object({
330
- provider: z.enum(["codex", "gemini"]).describe("워커 provider"),
311
+ provider: z
312
+ .enum(["codex", "antigravity", "gemini"])
313
+ .describe("워커 provider"),
331
314
  agentType: z.string().default("executor").describe("역할명"),
332
315
  prompt: z.string().describe("워커별 프롬프트"),
333
316
  mcpProfile: z.string().default("auto").describe("MCP 프로필"),
@@ -399,12 +382,13 @@ function isTeamRouteRequested(args) {
399
382
  }
400
383
 
401
384
  function pickRouteMode(provider) {
402
- return provider === "auto" ? "auto" : provider;
385
+ const normalized = normalizeProvider(provider);
386
+ return normalized === "auto" ? "auto" : normalized;
403
387
  }
404
388
 
405
389
  function sanitizeDelegateArgs(args = {}) {
406
390
  return {
407
- provider: args.provider || "auto",
391
+ provider: normalizeProvider(args.provider),
408
392
  agentType: args.agentType || "executor",
409
393
  cwd: args.cwd || null,
410
394
  timeoutMs: Number.isFinite(Number(args.timeoutMs))
@@ -433,18 +417,6 @@ function sanitizeDelegateArgs(args = {}) {
433
417
  };
434
418
  }
435
419
 
436
- function formatConversationTranscript(turns = []) {
437
- return turns
438
- .map((turn, index) => {
439
- const parts = [`Turn ${index + 1} user:\n${turn.user}`];
440
- if (typeof turn.assistant === "string" && turn.assistant.trim()) {
441
- parts.push(`Turn ${index + 1} assistant:\n${turn.assistant}`);
442
- }
443
- return parts.join("\n\n");
444
- })
445
- .join("\n\n");
446
- }
447
-
448
420
  async function emitProgress(extra, progress, total, message) {
449
421
  if (extra?._meta?.progressToken === undefined) return;
450
422
  await extra.sendNotification({
@@ -486,17 +458,9 @@ export class DelegatorMcpWorker {
486
458
  clientInfo: { name: SERVER_INFO.name, version: SERVER_INFO.version },
487
459
  });
488
460
 
489
- this.geminiCommand =
490
- options.geminiCommand || this.env.GEMINI_BIN || "gemini";
491
- this.geminiCommandArgs =
492
- Array.isArray(options.geminiArgs) && options.geminiArgs.length
493
- ? [...options.geminiArgs]
494
- : parseJsonArray(this.env.GEMINI_BIN_ARGS_JSON, []);
495
-
496
461
  this.server = null;
497
462
  this.transport = null;
498
463
  this.jobs = new Map();
499
- this.geminiConversations = new Map();
500
464
  this.routeChildren = new Set();
501
465
  this.ready = false;
502
466
  }
@@ -519,7 +483,7 @@ export class DelegatorMcpWorker {
519
483
  "triflux-delegate",
520
484
  {
521
485
  description:
522
- "새 위임을 실행합니다. codex/gemini direct 경로와 tfx-route 기반 auto 라우팅을 모두 지원합니다.",
486
+ "새 위임을 실행합니다. codex direct 경로와 antigravity/tfx-route 기반 auto 라우팅을 지원합니다.",
523
487
  inputSchema: DelegateInputSchema,
524
488
  outputSchema: DelegateOutputSchema,
525
489
  },
@@ -548,7 +512,7 @@ export class DelegatorMcpWorker {
548
512
  "triflux-delegate-reply",
549
513
  {
550
514
  description:
551
- "기존 delegate job에 후속 응답을 보내고, Gemini direct job이면 multi-turn 대화를 이어갑니다.",
515
+ "기존 delegate job에 후속 응답을 보냅니다. 현재 route 기반 Antigravity job은 후속 응답을 지원하지 않습니다.",
552
516
  inputSchema: DelegateReplyInputSchema,
553
517
  outputSchema: DelegateOutputSchema,
554
518
  },
@@ -581,15 +545,6 @@ export class DelegatorMcpWorker {
581
545
  this.routeChildren.clear();
582
546
 
583
547
  await this.codexWorker.stop().catch(() => {});
584
-
585
- for (const job of this.jobs.values()) {
586
- if (job.worker) {
587
- await job.worker.stop().catch(() => {});
588
- job.worker = null;
589
- }
590
- }
591
- this.geminiConversations.clear();
592
-
593
548
  if (this.server) {
594
549
  await this.server.close().catch(() => {});
595
550
  }
@@ -599,11 +554,13 @@ export class DelegatorMcpWorker {
599
554
  }
600
555
 
601
556
  async run(prompt, options = {}) {
602
- return this._executeDirect({ prompt, ...options });
557
+ return this._executeDirect(normalizeDelegateArgs({ prompt, ...options }));
603
558
  }
604
559
 
605
560
  async execute(prompt, options = {}) {
606
- const result = await this._executeDirect({ prompt, ...options });
561
+ const result = await this._executeDirect(
562
+ normalizeDelegateArgs({ prompt, ...options }),
563
+ );
607
564
  return {
608
565
  output: result.output || result.error || "",
609
566
  exitCode: result.exitCode ?? (result.ok ? 0 : 1),
@@ -614,10 +571,11 @@ export class DelegatorMcpWorker {
614
571
  }
615
572
 
616
573
  async delegate(args, extra) {
617
- if (args.mode === "async") {
618
- return this._startAsyncJob(args, extra);
574
+ const normalizedArgs = normalizeDelegateArgs(args);
575
+ if (normalizedArgs.mode === "async") {
576
+ return this._startAsyncJob(normalizedArgs, extra);
619
577
  }
620
- return this._runSyncJob(args, extra);
578
+ return this._runSyncJob(normalizedArgs, extra);
621
579
  }
622
580
 
623
581
  async getJobStatus(jobId, extra) {
@@ -637,7 +595,7 @@ export class DelegatorMcpWorker {
637
595
  return payload;
638
596
  }
639
597
 
640
- async reply({ job_id, reply, done = false }, extra) {
598
+ async reply({ job_id }, extra) {
641
599
  const job = this.jobs.get(job_id);
642
600
  if (!job) {
643
601
  return createErrorPayload(`알 수 없는 jobId: ${job_id}`, {
@@ -651,145 +609,20 @@ export class DelegatorMcpWorker {
651
609
  job_id,
652
610
  });
653
611
  }
654
- if (
655
- job.providerRequested !== "gemini" ||
656
- job.transport !== "gemini-worker"
657
- ) {
658
- return createErrorPayload(
659
- "delegate-reply는 현재 direct Gemini job에만 지원됩니다.",
660
- {
661
- jobId: job_id,
662
- job_id,
663
- },
664
- );
665
- }
666
-
667
- const conversation = this.geminiConversations.get(job_id);
668
- if (!conversation) {
669
- return createErrorPayload(`Gemini 대화 컨텍스트가 없습니다: ${job_id}`, {
670
- jobId: job_id,
671
- job_id,
672
- });
673
- }
674
- if (conversation.closed) {
675
- return createErrorPayload(`이미 종료된 대화입니다: ${job_id}`, {
612
+ void extra;
613
+ return createErrorPayload(
614
+ "delegate-reply는 route 기반 Antigravity job에 지원되지 않습니다.",
615
+ {
676
616
  jobId: job_id,
677
617
  job_id,
678
- });
679
- }
680
-
681
- await emitProgress(
682
- extra,
683
- DIRECT_PROGRESS_START,
684
- 100,
685
- `job ${job_id} 후속 응답을 시작합니다.`,
618
+ },
686
619
  );
687
- job.status = "running";
688
- job.updatedAt = new Date().toISOString();
689
-
690
- const worker = this._createGeminiWorker();
691
- job.worker = worker;
692
- const prompt = this._buildGeminiReplyPrompt(conversation, reply);
693
-
694
- try {
695
- const result = await worker.execute(prompt, {
696
- cwd: job.requestArgs.cwd || this.cwd,
697
- timeoutMs: resolveTimeoutMs(job.agentType, job.requestArgs.timeoutMs),
698
- model: job.requestArgs.model || resolveGeminiModel(job.agentType),
699
- approvalMode: "yolo",
700
- allowedMcpServerNames: getGeminiAllowedServers(
701
- this._getMcpPolicyOptions(job.requestArgs),
702
- ),
703
- });
704
-
705
- conversation.turns.push({
706
- user: reply,
707
- assistant: result.output,
708
- });
709
- conversation.updatedAt = new Date().toISOString();
710
- conversation.closed = Boolean(done);
711
- if (done) {
712
- this.geminiConversations.delete(job_id);
713
- }
714
-
715
- this._applyJobResult(job, {
716
- ok: result.exitCode === 0,
717
- status: result.exitCode === 0 ? "completed" : "failed",
718
- providerRequested: "gemini",
719
- providerResolved: "gemini",
720
- agentType: job.agentType,
721
- transport: "gemini-worker",
722
- exitCode: result.exitCode,
723
- output: result.output,
724
- sessionKey: result.sessionKey || job.sessionKey || null,
725
- });
726
- await emitProgress(
727
- extra,
728
- DIRECT_PROGRESS_DONE,
729
- 100,
730
- `job ${job_id} 후속 응답이 완료되었습니다.`,
731
- );
732
- return this._serializeJob(job);
733
- } catch (error) {
734
- const message = error instanceof Error ? error.message : String(error);
735
- this._applyJobResult(
736
- job,
737
- createErrorPayload(message, {
738
- mode: job.mode,
739
- providerRequested: "gemini",
740
- providerResolved: "gemini",
741
- agentType: job.agentType,
742
- transport: "gemini-worker",
743
- }),
744
- );
745
- return this._serializeJob(job);
746
- } finally {
747
- await worker.stop().catch(() => {});
748
- job.worker = null;
749
- }
750
- }
751
-
752
- _createGeminiWorker() {
753
- const resolved = whichCommand(this.geminiCommand) || this.geminiCommand;
754
- return new GeminiWorker({
755
- command: resolved,
756
- commandArgs: this.geminiCommandArgs,
757
- cwd: this.cwd,
758
- env: this.env,
759
- });
760
620
  }
761
621
 
762
622
  _buildDirectPrompt(args) {
763
623
  return withContext(String(args.prompt ?? ""), args.contextFile);
764
624
  }
765
625
 
766
- _buildDirectPromptWithHint(args) {
767
- return withPromptHint(String(args.prompt ?? ""), {
768
- agentType: args.agentType || "executor",
769
- mcpProfile: args.mcpProfile || "auto",
770
- searchTool: args.searchTool,
771
- workerIndex: Number.isInteger(args.workerIndex)
772
- ? args.workerIndex
773
- : undefined,
774
- contextFile: args.contextFile,
775
- });
776
- }
777
-
778
- _buildGeminiReplyPrompt(conversation, reply) {
779
- const transcript = formatConversationTranscript(conversation.turns);
780
- return [
781
- "Continue the conversation using the prior transcript below.",
782
- "",
783
- "<conversation_history>",
784
- transcript,
785
- "</conversation_history>",
786
- "",
787
- "<latest_user_reply>",
788
- reply,
789
- "</latest_user_reply>",
790
- ].join("\n");
791
- }
792
-
793
626
  _getMcpPolicyOptions(args) {
794
627
  return {
795
628
  agentType: args.agentType || "executor",
@@ -810,7 +643,12 @@ export class DelegatorMcpWorker {
810
643
  }
811
644
 
812
645
  _shouldUseRoute(args) {
813
- return args.provider === "auto" || isTeamRouteRequested(args);
646
+ return (
647
+ args.provider === "auto" ||
648
+ args.provider === "antigravity" ||
649
+ args.provider === "gemini" ||
650
+ isTeamRouteRequested(args)
651
+ );
814
652
  }
815
653
 
816
654
  async _executeDirect(args, extra = null) {
@@ -878,8 +716,8 @@ export class DelegatorMcpWorker {
878
716
 
879
717
  // workers 배열을 headless assignments 형식으로 변환
880
718
  const assignments = args.workers.map((w) => {
881
- // provider를 CLI 이름으로 매핑 (codex/gemini 그대로)
882
- const cli = w.provider;
719
+ // provider를 CLI 이름으로 매핑. gemini는 deprecated alias로 antigravity에 합류한다.
720
+ const cli = normalizeProvider(w.provider);
883
721
  const role = w.agentType || "executor";
884
722
  // buildDirectPrompt와 동일한 context 처리
885
723
  const prompt = withContext(String(w.prompt || ""), args.contextFile);
@@ -1003,38 +841,6 @@ export class DelegatorMcpWorker {
1003
841
  };
1004
842
  }
1005
843
 
1006
- if (args.provider === "gemini") {
1007
- const worker = this._createGeminiWorker();
1008
- const prompt = this._buildDirectPromptWithHint(args);
1009
- try {
1010
- const result = await worker.execute(prompt, {
1011
- cwd: args.cwd || this.cwd,
1012
- timeoutMs: resolveTimeoutMs(args.agentType, args.timeoutMs),
1013
- model: args.model || resolveGeminiModel(args.agentType),
1014
- approvalMode: "yolo",
1015
- allowedMcpServerNames: getGeminiAllowedServers(
1016
- this._getMcpPolicyOptions(args),
1017
- ),
1018
- });
1019
-
1020
- return {
1021
- ok: result.exitCode === 0,
1022
- mode: "sync",
1023
- status: result.exitCode === 0 ? "completed" : "failed",
1024
- providerRequested: "gemini",
1025
- providerResolved: "gemini",
1026
- agentType: args.agentType,
1027
- transport: "gemini-worker",
1028
- exitCode: result.exitCode,
1029
- output: result.output,
1030
- sessionKey: result.sessionKey,
1031
- _geminiPrompt: prompt,
1032
- };
1033
- } finally {
1034
- await worker.stop().catch(() => {});
1035
- }
1036
- }
1037
-
1038
844
  return createErrorPayload(
1039
845
  `지원하지 않는 direct provider: ${args.provider}`,
1040
846
  {
@@ -1155,30 +961,6 @@ export class DelegatorMcpWorker {
1155
961
  };
1156
962
  }
1157
963
 
1158
- if (args.provider === "gemini") {
1159
- const worker = this._createGeminiWorker();
1160
- job.worker = worker;
1161
- const prompt = this._buildDirectPromptWithHint(args);
1162
- const result = await worker.execute(prompt, {
1163
- cwd: args.cwd || this.cwd,
1164
- timeoutMs: resolveTimeoutMs(args.agentType, args.timeoutMs),
1165
- model: args.model || resolveGeminiModel(args.agentType),
1166
- approvalMode: "yolo",
1167
- allowedMcpServerNames: getGeminiAllowedServers(
1168
- this._getMcpPolicyOptions(args),
1169
- ),
1170
- });
1171
-
1172
- return {
1173
- ok: result.exitCode === 0,
1174
- providerResolved: "gemini",
1175
- output: result.output,
1176
- exitCode: result.exitCode,
1177
- sessionKey: result.sessionKey,
1178
- _geminiPrompt: prompt,
1179
- };
1180
- }
1181
-
1182
964
  throw new Error(`지원하지 않는 async provider: ${args.provider}`);
1183
965
  }
1184
966
 
@@ -1287,7 +1069,7 @@ export class DelegatorMcpWorker {
1287
1069
  error: "",
1288
1070
  thread_id: job.threadId,
1289
1071
  session_key: job.sessionKey,
1290
- conversation_open: this.geminiConversations.has(job.jobId),
1072
+ conversation_open: false,
1291
1073
  };
1292
1074
  }
1293
1075
 
@@ -1332,44 +1114,6 @@ export class DelegatorMcpWorker {
1332
1114
  job.sessionKey = result.sessionKey || job.sessionKey || null;
1333
1115
  job.completedAt = new Date().toISOString();
1334
1116
  job.updatedAt = job.completedAt;
1335
-
1336
- if (
1337
- job.providerRequested === "gemini" &&
1338
- job.transport === "gemini-worker" &&
1339
- typeof result._geminiPrompt === "string"
1340
- ) {
1341
- this._storeGeminiConversation(
1342
- job,
1343
- result._geminiPrompt,
1344
- result.output || "",
1345
- );
1346
- }
1347
- }
1348
-
1349
- _storeGeminiConversation(job, userPrompt, assistantReply) {
1350
- const existing = this.geminiConversations.get(job.jobId);
1351
- if (existing) {
1352
- if (typeof assistantReply === "string") {
1353
- const lastTurn = existing.turns.at(-1);
1354
- if (lastTurn && lastTurn.assistant !== assistantReply) {
1355
- lastTurn.assistant = assistantReply;
1356
- }
1357
- }
1358
- existing.updatedAt = new Date().toISOString();
1359
- return;
1360
- }
1361
-
1362
- this.geminiConversations.set(job.jobId, {
1363
- jobId: job.jobId,
1364
- closed: false,
1365
- updatedAt: new Date().toISOString(),
1366
- turns: [
1367
- {
1368
- user: userPrompt,
1369
- assistant: assistantReply,
1370
- },
1371
- ],
1372
- });
1373
1117
  }
1374
1118
 
1375
1119
  async _runSyncJob(args, extra) {
@@ -1,7 +1,8 @@
1
1
  // hub/workers/factory.mjs — Worker 생성 팩토리
2
2
  //
3
3
  // Supported worker types:
4
- // - 'gemini' → GeminiWorker
4
+ // - 'gemini' → AntigravityRouteWorker (deprecated alias)
5
+ // - 'antigravity' → AntigravityRouteWorker
5
6
  // - 'claude' → ClaudeWorker
6
7
  // - 'codex' → CodexMcpWorker (default) or CodexAppServerWorker when
7
8
  // opts.transport === 'app-server'
@@ -14,8 +15,8 @@
14
15
  // `publishCallback` or swap the transport with `requestJsonFn`.
15
16
 
16
17
  import { ClaudeWorker } from "./claude-worker.mjs";
18
+ import { AntigravityRouteWorker } from "./antigravity-route-worker.mjs";
17
19
  import { CodexAppServerWorker } from "./codex-app-server-worker.mjs";
18
- import { GeminiWorker } from "./gemini-worker.mjs";
19
20
 
20
21
  /**
21
22
  * Build a best-effort publishCallback that posts the envelope to
@@ -76,14 +77,16 @@ async function createCodexWorker(opts = {}) {
76
77
  }
77
78
 
78
79
  /**
79
- * @param {'gemini'|'claude'|'codex'|'codex-app-server'|'delegator'} type
80
+ * @param {'gemini'|'antigravity'|'agy'|'claude'|'codex'|'codex-app-server'|'delegator'} type
80
81
  * @param {object} [opts]
81
82
  * @returns {Promise<import('./interface.mjs').IWorker>}
82
83
  */
83
84
  export async function createWorker(type, opts = {}) {
84
85
  switch (type) {
85
86
  case "gemini":
86
- return new GeminiWorker(opts);
87
+ case "antigravity":
88
+ case "agy":
89
+ return new AntigravityRouteWorker(opts);
87
90
  case "claude":
88
91
  return new ClaudeWorker(opts);
89
92
  case "codex":