happy-imou-cloud 2.1.49 → 2.1.51

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 (55) hide show
  1. package/dist/AcpBackend-CqO3D07V.mjs +2619 -0
  2. package/dist/AcpBackend-XPiTd6ph.cjs +2621 -0
  3. package/dist/{BaseReasoningProcessor-Dn9NcoHz.cjs → BaseReasoningProcessor-BD9tiwep.cjs} +1 -144
  4. package/dist/{BaseReasoningProcessor-CAVeOdyo.mjs → BaseReasoningProcessor-CjlayL2f.mjs} +2 -144
  5. package/dist/ConversationHistory-Bl2doTA-.cjs +780 -0
  6. package/dist/ConversationHistory-CI5bBfuA.mjs +771 -0
  7. package/dist/{ProviderSelectionHandler-BJJc7qOR.cjs → ProviderSelectionHandler-C7GE5QjX.cjs} +6 -6
  8. package/dist/{ProviderSelectionHandler-DIYidT13.mjs → ProviderSelectionHandler-uQ8jzdzr.mjs} +2 -2
  9. package/dist/RuntimeShell-BDt42io_.mjs +252 -0
  10. package/dist/RuntimeShell-D_Te12wq.cjs +258 -0
  11. package/dist/bootstrapManagedProviderSession-Bln-TwyB.cjs +147 -0
  12. package/dist/bootstrapManagedProviderSession-D2Z6YU3n.mjs +145 -0
  13. package/dist/claude-BKNT-2fG.cjs +1080 -0
  14. package/dist/claude-CnN5WCWj.mjs +1073 -0
  15. package/dist/codex-DLGP8WF6.mjs +577 -0
  16. package/dist/codex-Fv2eali8.cjs +582 -0
  17. package/dist/{command-VcH4hbhi.cjs → command-BWPlJyCN.cjs} +16 -8
  18. package/dist/{command-CzfRRhVe.mjs → command-CELwsYoG.mjs} +15 -7
  19. package/dist/config-CFL0Gkqt.cjs +184 -0
  20. package/dist/config-ChSPe7p9.mjs +174 -0
  21. package/dist/createDefaultRuntimeShell-BXu3vCvT.cjs +33 -0
  22. package/dist/createDefaultRuntimeShell-DOg6g3-G.mjs +31 -0
  23. package/dist/cursor-Blq1cHdr.cjs +91 -0
  24. package/dist/cursor-CwPNSy_A.mjs +88 -0
  25. package/dist/future-Dq4Ha1Dn.cjs +24 -0
  26. package/dist/future-xRdLl3vf.mjs +22 -0
  27. package/dist/{index-xa1kwZoj.cjs → index-B_JYgMUS.cjs} +189 -5352
  28. package/dist/{index-7Z93BoVn.mjs → index-CX-F_fuk.mjs} +177 -5331
  29. package/dist/index.cjs +2 -2
  30. package/dist/index.mjs +2 -2
  31. package/dist/installFatalProcessHandlers-0vaw9MAz.mjs +55 -0
  32. package/dist/installFatalProcessHandlers-CyURn5Bp.cjs +57 -0
  33. package/dist/launch-BoCCEd5p.mjs +63 -0
  34. package/dist/launch-wZA5BcvS.cjs +66 -0
  35. package/dist/lib.cjs +2 -3
  36. package/dist/lib.d.cts +20 -17
  37. package/dist/lib.d.mts +20 -17
  38. package/dist/lib.mjs +1 -2
  39. package/dist/resolveCommand-B3BGyBE2.mjs +189 -0
  40. package/dist/resolveCommand-DYMd9PNC.cjs +193 -0
  41. package/dist/{runClaude-zCwRhpOw.mjs → runClaude-Be0myF9k.mjs} +8 -5
  42. package/dist/{runClaude-BBGNmGj6.cjs → runClaude-DZJt5er7.cjs} +46 -43
  43. package/dist/{runCodex-BbgLVjb9.mjs → runCodex-BSnyN4m7.mjs} +226 -117
  44. package/dist/{runCodex-jUU6U2tZ.cjs → runCodex-DTCcGRue.cjs} +269 -160
  45. package/dist/runCursor-Bn1PuwJy.cjs +506 -0
  46. package/dist/runCursor-M6dQ6bGF.mjs +504 -0
  47. package/dist/{runGemini-DcwNsudA.mjs → runGemini-BNm4vYKA.mjs} +279 -5
  48. package/dist/{runGemini-C0NT8MHK.cjs → runGemini-Bn3lFhz6.cjs} +309 -35
  49. package/dist/{registerKillSessionHandler-DLDg2EES.mjs → sessionControl-1bT_7OI6.mjs} +1643 -2405
  50. package/dist/{registerKillSessionHandler-CfCya6si.cjs → sessionControl-flKnQrx0.cjs} +1647 -2417
  51. package/dist/{api-DnqaNvyV.mjs → types-B5vtxa38.mjs} +55 -5
  52. package/dist/{api-D7nAeZi7.cjs → types-CttABk32.cjs} +55 -4
  53. package/package.json +2 -2
  54. package/dist/types-CiliQpqS.mjs +0 -52
  55. package/dist/types-DVk3crez.cjs +0 -54
@@ -3,10 +3,13 @@
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./api-D7nAeZi7.cjs');
7
- var registerKillSessionHandler = require('./registerKillSessionHandler-CfCya6si.cjs');
8
- var index = require('./index-xa1kwZoj.cjs');
9
- var BaseReasoningProcessor = require('./BaseReasoningProcessor-Dn9NcoHz.cjs');
6
+ var persistence = require('./types-CttABk32.cjs');
7
+ var ConversationHistory$1 = require('./ConversationHistory-Bl2doTA-.cjs');
8
+ var sessionControl = require('./sessionControl-flKnQrx0.cjs');
9
+ var index = require('./index-B_JYgMUS.cjs');
10
+ var AcpBackend = require('./AcpBackend-XPiTd6ph.cjs');
11
+ var config = require('./config-CFL0Gkqt.cjs');
12
+ var BaseReasoningProcessor = require('./BaseReasoningProcessor-BD9tiwep.cjs');
10
13
  require('cross-spawn');
11
14
  require('@agentclientprotocol/sdk');
12
15
  require('ps-list');
@@ -15,6 +18,7 @@ require('node:path');
15
18
  require('node:os');
16
19
  require('node:child_process');
17
20
  require('node:readline');
21
+ var bootstrapManagedProviderSession = require('./bootstrapManagedProviderSession-Bln-TwyB.cjs');
18
22
  require('tweetnacl');
19
23
  require('axios');
20
24
  require('open');
@@ -29,7 +33,7 @@ require('socket.io-client');
29
33
  require('fs/promises');
30
34
  require('crypto');
31
35
  require('expo-server-sdk');
32
- require('./types-DVk3crez.cjs');
36
+ require('./RuntimeShell-D_Te12wq.cjs');
33
37
  require('os');
34
38
  require('qrcode-terminal');
35
39
  require('node:module');
@@ -40,6 +44,276 @@ require('http');
40
44
  require('util');
41
45
  require('node:url');
42
46
 
47
+ const GEMINI_TIMEOUTS = {
48
+ /** Gemini CLI can be slow on first start (downloading models, etc.) */
49
+ init: 12e4,
50
+ /** Gemini ACP can swallow an initialize request sent too early after spawn */
51
+ initDelay: 2500,
52
+ /** Standard tool call timeout */
53
+ toolCall: 10 * 6e4,
54
+ /** Investigation tools (codebase_investigator) can run for a long time */
55
+ investigation: 30 * 6e4,
56
+ /** Think tools are usually quick */
57
+ think: 2 * 6e4,
58
+ /** Idle detection after last message chunk */
59
+ idle: 500
60
+ };
61
+ const GEMINI_TOOL_PATTERNS = [
62
+ {
63
+ name: "save_memory",
64
+ patterns: ["save_memory", "save-memory"],
65
+ inputFields: ["memory", "content"]
66
+ },
67
+ {
68
+ name: "think",
69
+ patterns: ["think"],
70
+ inputFields: ["thought", "thinking"]
71
+ }
72
+ ];
73
+ const AVAILABLE_MODELS = [
74
+ "gemini-2.5-pro",
75
+ "gemini-2.5-flash",
76
+ "gemini-2.5-flash-lite"
77
+ ];
78
+ class GeminiTransport {
79
+ agentName = "gemini";
80
+ getTimeoutProfile() {
81
+ return index.resolveAcpSessionPreferences({ agentName: this.agentName }).timeoutProfile;
82
+ }
83
+ /**
84
+ * Gemini CLI needs 2 minutes for first start (model download, warm-up)
85
+ */
86
+ getInitTimeout() {
87
+ return index.scaleAcpTimeoutMs(GEMINI_TIMEOUTS.init, "init", this.getTimeoutProfile());
88
+ }
89
+ getInitDelayMs() {
90
+ return GEMINI_TIMEOUTS.initDelay;
91
+ }
92
+ /**
93
+ * Filter Gemini CLI debug output from stdout.
94
+ *
95
+ * Gemini CLI outputs various debug info (experiments, flags, etc.) to stdout
96
+ * that breaks ACP JSON-RPC parsing. We only keep valid JSON lines.
97
+ */
98
+ filterStdoutLine(line) {
99
+ const trimmed = line.trim();
100
+ if (!trimmed) {
101
+ return null;
102
+ }
103
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
104
+ return null;
105
+ }
106
+ try {
107
+ const parsed = JSON.parse(trimmed);
108
+ if (typeof parsed !== "object" || parsed === null) {
109
+ return null;
110
+ }
111
+ return line;
112
+ } catch {
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Handle Gemini CLI stderr output.
118
+ *
119
+ * Detects:
120
+ * - Rate limit errors (429) - logged but not shown (CLI handles retries)
121
+ * - Model not found (404) - emit error with available models
122
+ * - Other errors during investigation - logged for debugging
123
+ */
124
+ handleStderr(text, context) {
125
+ const trimmed = text.trim();
126
+ if (!trimmed) {
127
+ return { message: null, suppress: true };
128
+ }
129
+ if (trimmed.includes("status 429") || trimmed.includes('code":429') || trimmed.includes("rateLimitExceeded") || trimmed.includes("RESOURCE_EXHAUSTED")) {
130
+ return {
131
+ message: null,
132
+ suppress: false
133
+ // Log for debugging but don't show to user
134
+ };
135
+ }
136
+ if (trimmed.includes("status 404") || trimmed.includes('code":404')) {
137
+ const errorMessage = {
138
+ type: "status",
139
+ status: "error",
140
+ detail: `Model not found. Available models: ${AVAILABLE_MODELS.join(", ")}`
141
+ };
142
+ return { message: errorMessage };
143
+ }
144
+ if (context.hasActiveInvestigation) {
145
+ const hasError = trimmed.includes("timeout") || trimmed.includes("Timeout") || trimmed.includes("failed") || trimmed.includes("Failed") || trimmed.includes("error") || trimmed.includes("Error");
146
+ if (hasError) {
147
+ return { message: null, suppress: false };
148
+ }
149
+ }
150
+ return { message: null };
151
+ }
152
+ /**
153
+ * Gemini-specific tool patterns
154
+ */
155
+ getToolPatterns() {
156
+ return GEMINI_TOOL_PATTERNS;
157
+ }
158
+ /**
159
+ * Check if tool is an investigation tool (needs longer timeout)
160
+ */
161
+ isInvestigationTool(toolCallId, toolKind) {
162
+ const lowerId = toolCallId.toLowerCase();
163
+ return lowerId.includes("codebase_investigator") || lowerId.includes("investigator") || typeof toolKind === "string" && toolKind.includes("investigator");
164
+ }
165
+ /**
166
+ * Get timeout for a tool call
167
+ */
168
+ getToolCallTimeout(toolCallId, toolKind) {
169
+ if (this.isInvestigationTool(toolCallId, toolKind)) {
170
+ return index.scaleAcpTimeoutMs(GEMINI_TIMEOUTS.investigation, "investigation", this.getTimeoutProfile());
171
+ }
172
+ if (toolKind === "think") {
173
+ return index.scaleAcpTimeoutMs(GEMINI_TIMEOUTS.think, "think", this.getTimeoutProfile());
174
+ }
175
+ return index.scaleAcpTimeoutMs(GEMINI_TIMEOUTS.toolCall, "tool", this.getTimeoutProfile());
176
+ }
177
+ /**
178
+ * Get idle detection timeout
179
+ */
180
+ getIdleTimeout() {
181
+ return GEMINI_TIMEOUTS.idle;
182
+ }
183
+ /**
184
+ * Extract tool name from toolCallId using Gemini patterns.
185
+ *
186
+ * Tool IDs often contain the tool name as a prefix (e.g., "save_memory-1765385846663" -> "save_memory")
187
+ */
188
+ extractToolNameFromId(toolCallId) {
189
+ const lowerId = toolCallId.toLowerCase();
190
+ for (const toolPattern of GEMINI_TOOL_PATTERNS) {
191
+ for (const pattern of toolPattern.patterns) {
192
+ if (lowerId.includes(pattern.toLowerCase())) {
193
+ return toolPattern.name;
194
+ }
195
+ }
196
+ }
197
+ return null;
198
+ }
199
+ /**
200
+ * Check if input is effectively empty
201
+ */
202
+ isEmptyInput(input) {
203
+ if (!input) return true;
204
+ if (Array.isArray(input)) return input.length === 0;
205
+ if (typeof input === "object") return Object.keys(input).length === 0;
206
+ return false;
207
+ }
208
+ /**
209
+ * Determine the real tool name from various sources.
210
+ *
211
+ * When Gemini sends "other" or "Unknown tool", tries to determine the real name from:
212
+ * 1. toolCallId patterns (most reliable - tool name often embedded in ID)
213
+ * 2. Input field signatures (specific fields indicate specific tools)
214
+ * 3. Empty input default (some tools like think have empty input)
215
+ *
216
+ * Context-based heuristics were removed as they were fragile and the above
217
+ * methods cover all known cases.
218
+ */
219
+ determineToolName(toolName, toolCallId, input, _context) {
220
+ if (toolName !== "other" && toolName !== "Unknown tool") {
221
+ return toolName;
222
+ }
223
+ const idToolName = this.extractToolNameFromId(toolCallId);
224
+ if (idToolName) {
225
+ return idToolName;
226
+ }
227
+ if (input && typeof input === "object" && !Array.isArray(input)) {
228
+ const inputKeys = Object.keys(input);
229
+ for (const toolPattern of GEMINI_TOOL_PATTERNS) {
230
+ if (toolPattern.inputFields) {
231
+ const hasMatchingField = toolPattern.inputFields.some(
232
+ (field) => inputKeys.some((key) => key.toLowerCase() === field.toLowerCase())
233
+ );
234
+ if (hasMatchingField) {
235
+ return toolPattern.name;
236
+ }
237
+ }
238
+ }
239
+ }
240
+ if (this.isEmptyInput(input) && toolName === "other") {
241
+ const defaultTool = GEMINI_TOOL_PATTERNS.find((p) => p.emptyInputDefault);
242
+ if (defaultTool) {
243
+ return defaultTool.name;
244
+ }
245
+ }
246
+ if (toolName === "other" || toolName === "Unknown tool") {
247
+ const inputKeys = input && typeof input === "object" ? Object.keys(input) : [];
248
+ persistence.logger.debug(
249
+ `[GeminiTransport] Unknown tool pattern - toolCallId: "${toolCallId}", toolName: "${toolName}", inputKeys: [${inputKeys.join(", ")}]. Consider adding a new pattern to GEMINI_TOOL_PATTERNS if this tool appears frequently.`
250
+ );
251
+ }
252
+ return toolName;
253
+ }
254
+ }
255
+ const geminiTransport = new GeminiTransport();
256
+
257
+ function createGeminiBackend(options) {
258
+ const localConfig = config.readGeminiLocalConfig();
259
+ let apiKey = options.cloudToken || localConfig.token || process.env[config.GEMINI_API_KEY_ENV] || process.env[config.GOOGLE_API_KEY_ENV] || options.apiKey;
260
+ if (!apiKey) {
261
+ persistence.logger.warn(`[Gemini] No API key found. Run 'happy connect gemini' to authenticate via Google OAuth, or set ${config.GEMINI_API_KEY_ENV} environment variable.`);
262
+ }
263
+ const geminiCommand = "gemini";
264
+ const model = config.determineGeminiModel(options.model, localConfig);
265
+ const geminiArgs = ["--experimental-acp"];
266
+ let googleCloudProject = null;
267
+ if (localConfig.googleCloudProject) {
268
+ const storedEmail = localConfig.googleCloudProjectEmail;
269
+ const currentEmail = options.currentUserEmail;
270
+ if (!storedEmail || storedEmail === currentEmail) {
271
+ googleCloudProject = localConfig.googleCloudProject;
272
+ persistence.logger.debug(`[Gemini] Using Google Cloud Project: ${googleCloudProject}${storedEmail ? ` (for ${storedEmail})` : " (global)"}`);
273
+ } else {
274
+ persistence.logger.debug(`[Gemini] Skipping stored Google Cloud Project (stored for ${storedEmail}, current user is ${currentEmail || "unknown"})`);
275
+ }
276
+ }
277
+ const backendOptions = {
278
+ agentName: "gemini",
279
+ cwd: options.cwd,
280
+ command: geminiCommand,
281
+ args: geminiArgs,
282
+ env: {
283
+ ...options.env,
284
+ ...apiKey ? { [config.GEMINI_API_KEY_ENV]: apiKey, [config.GOOGLE_API_KEY_ENV]: apiKey } : {},
285
+ // Pass model via env var - gemini CLI reads GEMINI_MODEL automatically
286
+ [config.GEMINI_MODEL_ENV]: model,
287
+ // Pass Google Cloud Project for Workspace accounts
288
+ ...googleCloudProject ? {
289
+ GOOGLE_CLOUD_PROJECT: googleCloudProject,
290
+ GOOGLE_CLOUD_PROJECT_ID: googleCloudProject
291
+ } : {},
292
+ // Suppress debug output from gemini CLI to avoid stdout pollution
293
+ NODE_ENV: "production",
294
+ DEBUG: ""
295
+ },
296
+ mcpServers: options.mcpServers,
297
+ permissionHandler: options.permissionHandler,
298
+ transportHandler: geminiTransport
299
+ };
300
+ const modelSource = config.getGeminiModelSource(options.model, localConfig);
301
+ persistence.logger.debug("[Gemini] Creating ACP SDK backend with options:", {
302
+ cwd: backendOptions.cwd,
303
+ command: backendOptions.command,
304
+ args: backendOptions.args,
305
+ hasApiKey: !!apiKey,
306
+ model,
307
+ modelSource,
308
+ mcpServerCount: options.mcpServers ? Object.keys(options.mcpServers).length : 0
309
+ });
310
+ return {
311
+ backend: new AcpBackend.AcpBackend(backendOptions),
312
+ model,
313
+ modelSource
314
+ };
315
+ }
316
+
43
317
  const GeminiDisplay = ({ messageBuffer, logPath, currentModel, onExit }) => {
44
318
  const [messages, setMessages] = React.useState([]);
45
319
  const [confirmationMode, setConfirmationMode] = React.useState(false);
@@ -183,7 +457,7 @@ const GeminiDisplay = ({ messageBuffer, logPath, currentModel, onExit }) => {
183
457
  ));
184
458
  };
185
459
 
186
- class GeminiPermissionHandler extends registerKillSessionHandler.BasePermissionHandler {
460
+ class GeminiPermissionHandler extends sessionControl.BasePermissionHandler {
187
461
  currentPermissionMode = "default";
188
462
  constructor(session) {
189
463
  super(session);
@@ -420,7 +694,7 @@ function formatOptionsXml(options) {
420
694
  return "\n<options>\n" + options.map((opt) => ` <option>${opt}</option>`).join("\n") + "\n</options>";
421
695
  }
422
696
 
423
- class ConversationHistory extends registerKillSessionHandler.ConversationHistory {
697
+ class ConversationHistory extends ConversationHistory$1.ConversationHistory {
424
698
  currentModel;
425
699
  setCurrentModel(model) {
426
700
  this.currentModel = model;
@@ -489,7 +763,7 @@ ${originalUserMessage}`;
489
763
  function bindGeminiUserMessageQueue(opts) {
490
764
  let currentState = { ...opts.initialState };
491
765
  opts.session.onUserMessage((message) => {
492
- const happyOrgResult = opts.happyOrg ? registerKillSessionHandler.resolveHappyOrgQueuedTurn({
766
+ const happyOrgResult = opts.happyOrg ? sessionControl.resolveHappyOrgQueuedTurn({
493
767
  metadata: opts.happyOrg.getMetadata(),
494
768
  message,
495
769
  sessionId: opts.happyOrg.getSessionId?.() ?? null
@@ -547,12 +821,12 @@ async function runGemini(opts) {
547
821
  const api = await persistence.ApiClient.create(opts.credentials);
548
822
  let machineId;
549
823
  try {
550
- machineId = await registerKillSessionHandler.ensureManagedProviderMachine({
824
+ machineId = await sessionControl.ensureManagedProviderMachine({
551
825
  api,
552
826
  missingMachineIdMessage: "[START] No machine ID found in settings, which is unexpected since authAndSetupMachineIfNeeded should have created it. Please report this issue on https://github.com/slopus/happy-cli/issues"
553
827
  });
554
828
  } catch (error) {
555
- if (error instanceof registerKillSessionHandler.MissingMachineIdError) {
829
+ if (error instanceof sessionControl.MissingMachineIdError) {
556
830
  console.error(error.message);
557
831
  process.exit(1);
558
832
  }
@@ -600,7 +874,7 @@ async function runGemini(opts) {
600
874
  pendingSessionSwap = null;
601
875
  }
602
876
  };
603
- const { metadata, session: initialSession, reconnectionHandle } = await BaseReasoningProcessor.bootstrapManagedProviderSession({
877
+ const { metadata, session: initialSession, reconnectionHandle } = await bootstrapManagedProviderSession.bootstrapManagedProviderSession({
604
878
  api,
605
879
  sessionTag,
606
880
  flavor: "gemini",
@@ -618,12 +892,12 @@ async function runGemini(opts) {
618
892
  }
619
893
  bindSessionTranscriptHistory?.(newSession);
620
894
  }
621
- void registerKillSessionHandler.syncControlledByUserState(newSession, false);
895
+ void sessionControl.syncControlledByUserState(newSession, false);
622
896
  }
623
897
  });
624
898
  session = initialSession;
625
- await registerKillSessionHandler.syncControlledByUserState(session, false);
626
- const messageQueue = new registerKillSessionHandler.MessageQueue2((mode) => persistence.hashObject({
899
+ await sessionControl.syncControlledByUserState(session, false);
900
+ const messageQueue = new sessionControl.MessageQueue2((mode) => persistence.hashObject({
627
901
  permissionMode: mode.permissionMode,
628
902
  model: mode.model,
629
903
  happyOrg: mode.happyOrg ? {
@@ -652,7 +926,7 @@ async function runGemini(opts) {
652
926
  return;
653
927
  }
654
928
  try {
655
- const notification = registerKillSessionHandler.buildReadyPushNotification({
929
+ const notification = ConversationHistory$1.buildReadyPushNotification({
656
930
  providerLabel: "Gemini",
657
931
  metadata: session.getMetadataSnapshot?.() ?? null,
658
932
  sessionId: session.sessionId
@@ -740,10 +1014,10 @@ async function runGemini(opts) {
740
1014
  }
741
1015
  };
742
1016
  session.rpcHandlerManager.registerHandler("abort", handleAbort);
743
- registerKillSessionHandler.registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
1017
+ sessionControl.registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
744
1018
  const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
745
- const messageBuffer = new registerKillSessionHandler.MessageBuffer({ enabled: hasTTY });
746
- const renderSessionTranscript = registerKillSessionHandler.createSessionTranscriptInkRenderer({ messageBuffer });
1019
+ const messageBuffer = new ConversationHistory$1.MessageBuffer({ enabled: hasTTY });
1020
+ const renderSessionTranscript = ConversationHistory$1.createSessionTranscriptInkRenderer({ messageBuffer });
747
1021
  let inkInstance = null;
748
1022
  bindSessionTranscriptHistory = (nextSession) => {
749
1023
  if (typeof nextSession.onSessionMessage !== "function") {
@@ -757,9 +1031,9 @@ async function runGemini(opts) {
757
1031
  });
758
1032
  };
759
1033
  bindSessionTranscriptHistory(session);
760
- let displayedModel = index.getInitialGeminiModel();
761
- const localConfig = index.readGeminiLocalConfig();
762
- persistence.logger.debug(`[gemini] Initial model setup: env[GEMINI_MODEL_ENV]=${process.env[index.GEMINI_MODEL_ENV] || "not set"}, localConfig=${localConfig.model || "not set"}, displayedModel=${displayedModel}`);
1034
+ let displayedModel = config.getInitialGeminiModel();
1035
+ const localConfig = config.readGeminiLocalConfig();
1036
+ persistence.logger.debug(`[gemini] Initial model setup: env[GEMINI_MODEL_ENV]=${process.env[config.GEMINI_MODEL_ENV] || "not set"}, localConfig=${localConfig.model || "not set"}, displayedModel=${displayedModel}`);
763
1037
  const updateDisplayedModel = (model, saveToConfig = false) => {
764
1038
  if (model === void 0) {
765
1039
  persistence.logger.debug(`[gemini] updateDisplayedModel called with undefined, skipping update`);
@@ -769,7 +1043,7 @@ async function runGemini(opts) {
769
1043
  displayedModel = model;
770
1044
  persistence.logger.debug(`[gemini] updateDisplayedModel called: oldModel=${oldModel}, newModel=${model}, saveToConfig=${saveToConfig}`);
771
1045
  if (saveToConfig) {
772
- index.saveGeminiModelToConfig(model);
1046
+ config.saveGeminiModelToConfig(model);
773
1047
  }
774
1048
  if (hasTTY && oldModel !== model) {
775
1049
  persistence.logger.debug(`[gemini] Adding model update message to buffer: [MODEL:${model}]`);
@@ -972,7 +1246,7 @@ async function runGemini(opts) {
972
1246
  };
973
1247
  function setupGeminiMessageHandler(activeRuntimeHandle) {
974
1248
  const forwardAgentMessage = (agentMessage) => {
975
- registerKillSessionHandler.forwardAgentMessageToProviderSession(agentMessage, {
1249
+ sessionControl.forwardAgentMessageToProviderSession(agentMessage, {
976
1250
  provider: "gemini",
977
1251
  send: (body) => session.sendAgentMessage("gemini", body)
978
1252
  });
@@ -1065,7 +1339,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1065
1339
  forwardAgentMessage(msg);
1066
1340
  break;
1067
1341
  case "tool-result":
1068
- const isError = registerKillSessionHandler.inferToolResultError(msg.result);
1342
+ const isError = sessionControl.inferToolResultError(msg.result);
1069
1343
  const resultText = typeof msg.result === "string" ? msg.result.substring(0, 200) : JSON.stringify(msg.result).substring(0, 200);
1070
1344
  const truncatedResult = resultText + (typeof msg.result === "string" && msg.result.length > 200 ? "..." : "");
1071
1345
  const resultSize = typeof msg.result === "string" ? msg.result.length : JSON.stringify(msg.result).length;
@@ -1091,12 +1365,12 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1091
1365
  forwardAgentMessage(msg);
1092
1366
  break;
1093
1367
  case "terminal-output": {
1094
- const terminalOutput = registerKillSessionHandler.renderTerminalOutputPreview(msg.data);
1368
+ const terminalOutput = sessionControl.renderTerminalOutputPreview(msg.data);
1095
1369
  if (!terminalOutput) {
1096
1370
  break;
1097
1371
  }
1098
1372
  messageBuffer.addMessage(terminalOutput, "result");
1099
- const forwardedOutput = registerKillSessionHandler.prepareTerminalOutputForForwarding(msg.data);
1373
+ const forwardedOutput = sessionControl.prepareTerminalOutputForForwarding(msg.data);
1100
1374
  if (forwardedOutput) {
1101
1375
  forwardAgentMessage({
1102
1376
  ...msg,
@@ -1107,8 +1381,8 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1107
1381
  }
1108
1382
  case "permission-request":
1109
1383
  try {
1110
- const permissionRequest = registerKillSessionHandler.extractPermissionRequestPushContext(msg);
1111
- const notification = registerKillSessionHandler.buildPermissionPushNotification({
1384
+ const permissionRequest = ConversationHistory$1.extractPermissionRequestPushContext(msg);
1385
+ const notification = ConversationHistory$1.buildPermissionPushNotification({
1112
1386
  providerLabel: "Gemini",
1113
1387
  metadata: session.getMetadataSnapshot?.() ?? null,
1114
1388
  sessionId: session.sessionId,
@@ -1185,11 +1459,11 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1185
1459
  const modelToUse = mode.model === void 0 ? void 0 : mode.model || null;
1186
1460
  let backendResult;
1187
1461
  updatePermissionMode(mode.permissionMode);
1188
- const { session: nextRuntimeHandle, factoryResult } = await registerKillSessionHandler.launchRuntimeHandleWithFactoryResult({
1462
+ const { session: nextRuntimeHandle, factoryResult } = await ConversationHistory$1.launchRuntimeHandleWithFactoryResult({
1189
1463
  provider: "gemini",
1190
1464
  cwd: process.cwd(),
1191
1465
  createBackendResult: (opts2) => {
1192
- const createdBackendResult = index.createGeminiBackend({
1466
+ const createdBackendResult = createGeminiBackend({
1193
1467
  ...opts2,
1194
1468
  mcpServers: {},
1195
1469
  permissionHandler,
@@ -1294,7 +1568,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1294
1568
  persistence.logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
1295
1569
  }
1296
1570
  if (message.mode.happyOrg) {
1297
- promptToSend = registerKillSessionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1571
+ promptToSend = sessionControl.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1298
1572
  }
1299
1573
  conversationHistory.addUserMessage(userMessageToShow);
1300
1574
  persistence.logger.debug(`[gemini] Sending prompt to Gemini (length: ${promptToSend.length}): ${promptToSend.substring(0, 100)}...`);
@@ -1306,7 +1580,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1306
1580
  try {
1307
1581
  await activeHandle.sendPrompt(promptToSend);
1308
1582
  persistence.logger.debug("[gemini] Prompt sent successfully");
1309
- await registerKillSessionHandler.waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal);
1583
+ await sessionControl.waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal);
1310
1584
  persistence.logger.debug("[gemini] Response complete");
1311
1585
  shouldInjectHistoryOnNextSession = false;
1312
1586
  break;
@@ -1404,7 +1678,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1404
1678
  permissionHandler.reset();
1405
1679
  reasoningProcessor.abort();
1406
1680
  diffProcessor.reset();
1407
- const finalizedTurn = await registerKillSessionHandler.finalizeHappyOrgTurnWithBusinessAck({
1681
+ const finalizedTurn = await sessionControl.finalizeHappyOrgTurnWithBusinessAck({
1408
1682
  metadata: session.getMetadataSnapshot?.() ?? null,
1409
1683
  queuedTurn: message.mode.happyOrg,
1410
1684
  responseText: accumulatedResponse,
@@ -1446,7 +1720,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1446
1720
  session.sendAgentMessage("gemini", messagePayload);
1447
1721
  if (!shouldExit) {
1448
1722
  try {
1449
- const notification = registerKillSessionHandler.buildTurnResultPushNotification({
1723
+ const notification = ConversationHistory$1.buildTurnResultPushNotification({
1450
1724
  providerLabel: "Gemini",
1451
1725
  metadata: finalizedTurn.nextMetadata ?? session.getMetadataSnapshot?.() ?? null,
1452
1726
  sessionId: session.sessionId,
@@ -1469,7 +1743,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1469
1743
  isResponseInProgress = false;
1470
1744
  } else if (!shouldExit && finalizedTurn.report) {
1471
1745
  try {
1472
- const notification = registerKillSessionHandler.buildTurnResultPushNotification({
1746
+ const notification = ConversationHistory$1.buildTurnResultPushNotification({
1473
1747
  providerLabel: "Gemini",
1474
1748
  metadata: finalizedTurn.nextMetadata ?? session.getMetadataSnapshot?.() ?? null,
1475
1749
  sessionId: session.sessionId,