happy-imou-cloud 2.1.0 → 2.1.2

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/bin/happy-cloud.mjs +4 -0
  2. package/compat/acp-sdk-schema/index.js +28 -0
  3. package/compat/acp-sdk-schema/types.gen.js +3 -0
  4. package/compat/acp-sdk-schema/zod.gen.js +1554 -0
  5. package/compat/ink-build/components/Cursor.d.ts +83 -0
  6. package/compat/ink-build/components/Cursor.js +53 -0
  7. package/compat/ink-build/components/CursorContext.d.ts +11 -0
  8. package/compat/ink-build/components/CursorContext.js +8 -0
  9. package/compat/ink-build/components/ErrorBoundary.d.ts +18 -0
  10. package/compat/ink-build/components/ErrorBoundary.js +23 -0
  11. package/compat/ink-build/hooks/use-cursor.d.ts +12 -0
  12. package/compat/ink-build/hooks/use-cursor.js +29 -0
  13. package/dist/{BaseReasoningProcessor-DQkzwRuf.mjs → BaseReasoningProcessor-BaOWkVcu.mjs} +3 -3
  14. package/dist/{BaseReasoningProcessor-C9mH8EVn.cjs → BaseReasoningProcessor-CzvqwxuY.cjs} +3 -3
  15. package/dist/{ProviderSelectionHandler-BlrrLPlo.mjs → ProviderSelectionHandler-Q8pl7e-d.mjs} +2 -2
  16. package/dist/{ProviderSelectionHandler-5Dedbm8j.cjs → ProviderSelectionHandler-wwbfeK_s.cjs} +2 -2
  17. package/dist/{api-w_CUxb9Q.mjs → api-Cxifhw5r.mjs} +4 -3
  18. package/dist/{api-Bd-MnOS4.cjs → api-DZimmN4C.cjs} +4 -3
  19. package/dist/{command-mTWwCqTY.mjs → command-B6LM3Nml.mjs} +3 -3
  20. package/dist/{command-DoDmHNxR.cjs → command-RcCJI1jl.cjs} +3 -3
  21. package/dist/{index-BQmJ4NAa.cjs → index-Cuvs0lFS.cjs} +11 -11
  22. package/dist/{index-GuXV-pxB.mjs → index-Des7I5WX.mjs} +8 -8
  23. package/dist/index.cjs +3 -3
  24. package/dist/index.mjs +3 -3
  25. package/dist/lib.cjs +1 -1
  26. package/dist/lib.d.cts +82 -81
  27. package/dist/lib.d.mts +82 -81
  28. package/dist/lib.mjs +1 -1
  29. package/dist/{persistence-MSy70is3.mjs → persistence-6d4U4Sh8.mjs} +1 -1
  30. package/dist/{persistence-BL06LLVz.cjs → persistence-C8-MtdQK.cjs} +1 -1
  31. package/dist/{registerKillSessionHandler-CjWfUfc3.mjs → registerKillSessionHandler-BFBkz_XT.mjs} +3 -3
  32. package/dist/{registerKillSessionHandler-D9kwxy6B.cjs → registerKillSessionHandler-BapPCRmp.cjs} +3 -3
  33. package/dist/{runClaude-DpZ95Twb.mjs → runClaude-CPV5Uap2.mjs} +34 -5
  34. package/dist/{runClaude-D2ZEXue8.cjs → runClaude-DVnqKa1q.cjs} +34 -5
  35. package/dist/{runCodex-Dz_1ho8d.cjs → runCodex-Bzsp8gFO.cjs} +26 -18
  36. package/dist/{runCodex-CJwaep2R.mjs → runCodex-CwtLSTMJ.mjs} +26 -18
  37. package/dist/{runGemini-Dfu6LltX.cjs → runGemini-6Dwyk_Km.cjs} +83 -17
  38. package/dist/{runGemini-BehqjM73.mjs → runGemini-Bmoxehlh.mjs} +83 -17
  39. package/package.json +3 -2
  40. package/scripts/build.mjs +2 -0
  41. package/scripts/devtools/README.md +9 -9
  42. package/scripts/e2e/fake-codex-acp-agent.mjs +139 -139
  43. package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -1063
  44. package/scripts/ensureAcpSdkCompat.mjs +171 -0
  45. package/scripts/release-smoke.mjs +14 -0
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var api = require('./api-Bd-MnOS4.cjs');
4
+ var api = require('./api-DZimmN4C.cjs');
5
5
  require('cross-spawn');
6
6
  require('@agentclientprotocol/sdk');
7
- var index = require('./index-BQmJ4NAa.cjs');
7
+ var index = require('./index-Cuvs0lFS.cjs');
8
8
  require('ps-list');
9
9
  require('fs');
10
10
  require('path');
@@ -15,7 +15,7 @@ var path = require('node:path');
15
15
  var os = require('node:os');
16
16
  var node_child_process = require('node:child_process');
17
17
  require('node:readline');
18
- require('./persistence-BL06LLVz.cjs');
18
+ require('./persistence-C8-MtdQK.cjs');
19
19
  var promises = require('node:fs/promises');
20
20
  var fs = require('fs/promises');
21
21
  require('crypto');
@@ -26,9 +26,9 @@ require('tweetnacl');
26
26
  require('open');
27
27
  var React = require('react');
28
28
  var ink = require('ink');
29
- var ProviderSelectionHandler = require('./ProviderSelectionHandler-5Dedbm8j.cjs');
29
+ var ProviderSelectionHandler = require('./ProviderSelectionHandler-wwbfeK_s.cjs');
30
30
  var types = require('./types-DVk3crez.cjs');
31
- var registerKillSessionHandler = require('./registerKillSessionHandler-D9kwxy6B.cjs');
31
+ var registerKillSessionHandler = require('./registerKillSessionHandler-BapPCRmp.cjs');
32
32
  require('socket.io-client');
33
33
  require('expo-server-sdk');
34
34
  var node_util = require('node:util');
@@ -995,6 +995,7 @@ async function claudeAcpRemoteLauncher(session) {
995
995
  let inkInstance = null;
996
996
  let shouldExit = false;
997
997
  let abortController = new AbortController();
998
+ let turnInFlight = false;
998
999
  let runtimeHandle = null;
999
1000
  let unsubscribeRuntimeMessages = null;
1000
1001
  let currentModeHash = null;
@@ -1005,6 +1006,7 @@ async function claudeAcpRemoteLauncher(session) {
1005
1006
  let currentAssistantMessageId = null;
1006
1007
  let currentThinkingMessageId = null;
1007
1008
  let shouldInjectHistoryOnNextSession = false;
1009
+ let unexpectedRuntimeStopRecovery = null;
1008
1010
  let readyAlreadySent = false;
1009
1011
  const permissionHandler = new ClaudeAcpPermissionHandler(session.client);
1010
1012
  const selectionHandler = new ProviderSelectionHandler.ProviderSelectionHandler(session.client, "Claude");
@@ -1113,6 +1115,28 @@ async function claudeAcpRemoteLauncher(session) {
1113
1115
  }
1114
1116
  emitStatusMessage(reason);
1115
1117
  };
1118
+ const recoverUnexpectedRuntimeStop = async (detail) => {
1119
+ if (shouldExit || session.queue.isClosed() || unexpectedRuntimeStopRecovery) {
1120
+ return;
1121
+ }
1122
+ const errorMessage = normalizeClaudeBackendError(detail);
1123
+ unexpectedRuntimeStopRecovery = (async () => {
1124
+ queueHistoryInjectionForRestart(
1125
+ `Claude runtime stopped unexpectedly (${errorMessage}). Starting a new Claude ACP session on the next message...`
1126
+ );
1127
+ await disposeRuntimeHandle();
1128
+ session.clearSessionId();
1129
+ currentModeHash = null;
1130
+ permissionHandler.reset();
1131
+ selectionHandler.reset();
1132
+ resetTurnState();
1133
+ })();
1134
+ try {
1135
+ await unexpectedRuntimeStopRecovery;
1136
+ } finally {
1137
+ unexpectedRuntimeStopRecovery = null;
1138
+ }
1139
+ };
1116
1140
  const setupRuntimeMessageHandler = (activeRuntimeHandle) => {
1117
1141
  const forwardAgentMessage = (agentMessage) => {
1118
1142
  registerKillSessionHandler.forwardAgentMessageToProviderSession(agentMessage, {
@@ -1161,6 +1185,9 @@ async function claudeAcpRemoteLauncher(session) {
1161
1185
  }
1162
1186
  if (msg.status === "idle" || msg.status === "stopped") {
1163
1187
  session.onThinkingChange(false);
1188
+ if (msg.status === "stopped" && !turnInFlight) {
1189
+ void recoverUnexpectedRuntimeStop(msg.detail);
1190
+ }
1164
1191
  return;
1165
1192
  }
1166
1193
  if (msg.status === "error") {
@@ -1378,6 +1405,7 @@ ${systemPrompt}` : systemPrompt,
1378
1405
  let shouldClearHistoryAfterTurn = false;
1379
1406
  let turnStatus = "task_complete";
1380
1407
  try {
1408
+ turnInFlight = true;
1381
1409
  const activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
1382
1410
  let promptToSend = message.message;
1383
1411
  if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
@@ -1420,6 +1448,7 @@ ${systemPrompt}` : systemPrompt,
1420
1448
  currentModeHash = null;
1421
1449
  }
1422
1450
  } finally {
1451
+ turnInFlight = false;
1423
1452
  const finalizedTurn = registerKillSessionHandler.finalizeHappyOrgTurn({
1424
1453
  metadata: session.client.getMetadataSnapshot?.() ?? null,
1425
1454
  queuedTurn: message.mode.happyOrg,
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var api = require('./api-Bd-MnOS4.cjs');
5
- var registerKillSessionHandler = require('./registerKillSessionHandler-D9kwxy6B.cjs');
6
- var index = require('./index-BQmJ4NAa.cjs');
4
+ var api = require('./api-DZimmN4C.cjs');
5
+ var registerKillSessionHandler = require('./registerKillSessionHandler-BapPCRmp.cjs');
6
+ var index = require('./index-Cuvs0lFS.cjs');
7
7
  require('cross-spawn');
8
8
  require('@agentclientprotocol/sdk');
9
9
  require('ps-list');
@@ -16,7 +16,7 @@ require('node:path');
16
16
  require('node:os');
17
17
  require('node:child_process');
18
18
  require('node:readline');
19
- require('./persistence-BL06LLVz.cjs');
19
+ require('./persistence-C8-MtdQK.cjs');
20
20
  require('node:fs/promises');
21
21
  require('fs/promises');
22
22
  require('crypto');
@@ -27,8 +27,8 @@ require('tweetnacl');
27
27
  require('open');
28
28
  var React = require('react');
29
29
  var ink = require('ink');
30
- var ProviderSelectionHandler = require('./ProviderSelectionHandler-5Dedbm8j.cjs');
31
- var BaseReasoningProcessor = require('./BaseReasoningProcessor-C9mH8EVn.cjs');
30
+ var ProviderSelectionHandler = require('./ProviderSelectionHandler-wwbfeK_s.cjs');
31
+ var BaseReasoningProcessor = require('./BaseReasoningProcessor-CzvqwxuY.cjs');
32
32
  require('zod');
33
33
  require('socket.io-client');
34
34
  require('expo-server-sdk');
@@ -575,8 +575,8 @@ async function codexRemoteLauncher(session) {
575
575
  let shouldCommitAccumulatedResponse = false;
576
576
  let currentAssistantMessageId = null;
577
577
  let currentThinkingMessageId = null;
578
- let fatalRuntimeStopError = null;
579
578
  let currentHappyOrgTurn = null;
579
+ let unexpectedRuntimeStopRecovery = null;
580
580
  const permissionHandler = new CodexPermissionHandler(session.client);
581
581
  const selectionHandler = new CodexSelectionHandler(session.client);
582
582
  const conversationHistory = new registerKillSessionHandler.ConversationHistory({ maxMessages: 20, maxCharacters: 5e4 });
@@ -656,16 +656,27 @@ async function codexRemoteLauncher(session) {
656
656
  report
657
657
  });
658
658
  };
659
- const handleUnexpectedRuntimeStop = (detail) => {
660
- if (shouldExit || fatalRuntimeStopError) {
659
+ const recoverUnexpectedRuntimeStop = async (detail) => {
660
+ if (shouldExit || session.queue.isClosed() || unexpectedRuntimeStopRecovery) {
661
661
  return;
662
662
  }
663
663
  const errorMessage = normalizeCodexBackendError(detail);
664
- fatalRuntimeStopError = new Error(errorMessage);
665
- emitUserVisibleErrorMessage(errorMessage);
666
- session.runtimeSession.sendSessionDeath();
667
- shouldExit = true;
668
- abortController.abort();
664
+ unexpectedRuntimeStopRecovery = (async () => {
665
+ queueHistoryInjectionForRestart(
666
+ `Codex runtime stopped unexpectedly (${errorMessage}). Starting a new Codex session on the next message...`
667
+ );
668
+ await disposeRuntimeHandle();
669
+ session.clearSessionId();
670
+ currentModeHash = null;
671
+ permissionHandler.reset();
672
+ selectionHandler.reset();
673
+ resetTurnState();
674
+ })();
675
+ try {
676
+ await unexpectedRuntimeStopRecovery;
677
+ } finally {
678
+ unexpectedRuntimeStopRecovery = null;
679
+ }
669
680
  };
670
681
  const queueHistoryInjectionForRestart = (reason) => {
671
682
  messageBuffer.addMessage("\u2550".repeat(40), "status");
@@ -768,7 +779,7 @@ async function codexRemoteLauncher(session) {
768
779
  emitPendingAssistantMessageDelta();
769
780
  reasoningProcessor.completeCurrent();
770
781
  if (msg.status === "stopped" && !turnInFlight) {
771
- handleUnexpectedRuntimeStop(msg.detail);
782
+ void recoverUnexpectedRuntimeStop(msg.detail);
772
783
  }
773
784
  return;
774
785
  }
@@ -1116,9 +1127,6 @@ async function codexRemoteLauncher(session) {
1116
1127
  }
1117
1128
  messageBuffer.clear();
1118
1129
  }
1119
- if (fatalRuntimeStopError) {
1120
- throw fatalRuntimeStopError;
1121
- }
1122
1130
  api.logger.debug("[Codex] ACP remote launcher returning: exit", {
1123
1131
  shouldExit,
1124
1132
  queueClosed: session.queue.isClosed(),
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { l as logger, b as connectionState, A as ApiClient } from './api-w_CUxb9Q.mjs';
3
- import { B as BasePermissionHandler, h as hashObject, f as MessageBuffer, C as ConversationHistory$1, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, d as registerKillSessionHandler, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession, k as closeProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, r as resolveHappyOrgQueuedTurn, s as syncControlledByUserState } from './registerKillSessionHandler-CjWfUfc3.mjs';
4
- import { f as formatDisplayMessage, v as validateCodexAcpSpawn, d as createCodexBackend, t as truncateDisplayMessage, b as stopCaffeinate } from './index-GuXV-pxB.mjs';
2
+ import { l as logger, b as connectionState, A as ApiClient } from './api-Cxifhw5r.mjs';
3
+ import { B as BasePermissionHandler, h as hashObject, f as MessageBuffer, C as ConversationHistory$1, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, d as registerKillSessionHandler, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession, k as closeProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, r as resolveHappyOrgQueuedTurn, s as syncControlledByUserState } from './registerKillSessionHandler-BFBkz_XT.mjs';
4
+ import { f as formatDisplayMessage, v as validateCodexAcpSpawn, d as createCodexBackend, t as truncateDisplayMessage, b as stopCaffeinate } from './index-Des7I5WX.mjs';
5
5
  import 'cross-spawn';
6
6
  import '@agentclientprotocol/sdk';
7
7
  import 'ps-list';
@@ -14,7 +14,7 @@ import 'node:path';
14
14
  import 'node:os';
15
15
  import 'node:child_process';
16
16
  import 'node:readline';
17
- import './persistence-MSy70is3.mjs';
17
+ import './persistence-6d4U4Sh8.mjs';
18
18
  import 'node:fs/promises';
19
19
  import 'fs/promises';
20
20
  import 'crypto';
@@ -25,8 +25,8 @@ import 'tweetnacl';
25
25
  import 'open';
26
26
  import React, { useState, useRef, useEffect, useCallback } from 'react';
27
27
  import { useStdout, useInput, Box, Text, render } from 'ink';
28
- import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-BlrrLPlo.mjs';
29
- import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-DQkzwRuf.mjs';
28
+ import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-Q8pl7e-d.mjs';
29
+ import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-BaOWkVcu.mjs';
30
30
  import 'zod';
31
31
  import 'socket.io-client';
32
32
  import 'expo-server-sdk';
@@ -573,8 +573,8 @@ async function codexRemoteLauncher(session) {
573
573
  let shouldCommitAccumulatedResponse = false;
574
574
  let currentAssistantMessageId = null;
575
575
  let currentThinkingMessageId = null;
576
- let fatalRuntimeStopError = null;
577
576
  let currentHappyOrgTurn = null;
577
+ let unexpectedRuntimeStopRecovery = null;
578
578
  const permissionHandler = new CodexPermissionHandler(session.client);
579
579
  const selectionHandler = new CodexSelectionHandler(session.client);
580
580
  const conversationHistory = new ConversationHistory$1({ maxMessages: 20, maxCharacters: 5e4 });
@@ -654,16 +654,27 @@ async function codexRemoteLauncher(session) {
654
654
  report
655
655
  });
656
656
  };
657
- const handleUnexpectedRuntimeStop = (detail) => {
658
- if (shouldExit || fatalRuntimeStopError) {
657
+ const recoverUnexpectedRuntimeStop = async (detail) => {
658
+ if (shouldExit || session.queue.isClosed() || unexpectedRuntimeStopRecovery) {
659
659
  return;
660
660
  }
661
661
  const errorMessage = normalizeCodexBackendError(detail);
662
- fatalRuntimeStopError = new Error(errorMessage);
663
- emitUserVisibleErrorMessage(errorMessage);
664
- session.runtimeSession.sendSessionDeath();
665
- shouldExit = true;
666
- abortController.abort();
662
+ unexpectedRuntimeStopRecovery = (async () => {
663
+ queueHistoryInjectionForRestart(
664
+ `Codex runtime stopped unexpectedly (${errorMessage}). Starting a new Codex session on the next message...`
665
+ );
666
+ await disposeRuntimeHandle();
667
+ session.clearSessionId();
668
+ currentModeHash = null;
669
+ permissionHandler.reset();
670
+ selectionHandler.reset();
671
+ resetTurnState();
672
+ })();
673
+ try {
674
+ await unexpectedRuntimeStopRecovery;
675
+ } finally {
676
+ unexpectedRuntimeStopRecovery = null;
677
+ }
667
678
  };
668
679
  const queueHistoryInjectionForRestart = (reason) => {
669
680
  messageBuffer.addMessage("\u2550".repeat(40), "status");
@@ -766,7 +777,7 @@ async function codexRemoteLauncher(session) {
766
777
  emitPendingAssistantMessageDelta();
767
778
  reasoningProcessor.completeCurrent();
768
779
  if (msg.status === "stopped" && !turnInFlight) {
769
- handleUnexpectedRuntimeStop(msg.detail);
780
+ void recoverUnexpectedRuntimeStop(msg.detail);
770
781
  }
771
782
  return;
772
783
  }
@@ -1114,9 +1125,6 @@ async function codexRemoteLauncher(session) {
1114
1125
  }
1115
1126
  messageBuffer.clear();
1116
1127
  }
1117
- if (fatalRuntimeStopError) {
1118
- throw fatalRuntimeStopError;
1119
- }
1120
1128
  logger.debug("[Codex] ACP remote launcher returning: exit", {
1121
1129
  shouldExit,
1122
1130
  queueClosed: session.queue.isClosed(),
@@ -3,10 +3,10 @@
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
- var api = require('./api-Bd-MnOS4.cjs');
7
- var registerKillSessionHandler = require('./registerKillSessionHandler-D9kwxy6B.cjs');
8
- var index = require('./index-BQmJ4NAa.cjs');
9
- var BaseReasoningProcessor = require('./BaseReasoningProcessor-C9mH8EVn.cjs');
6
+ var api = require('./api-DZimmN4C.cjs');
7
+ var registerKillSessionHandler = require('./registerKillSessionHandler-BapPCRmp.cjs');
8
+ var index = require('./index-Cuvs0lFS.cjs');
9
+ var BaseReasoningProcessor = require('./BaseReasoningProcessor-CzvqwxuY.cjs');
10
10
  require('cross-spawn');
11
11
  require('@agentclientprotocol/sdk');
12
12
  require('ps-list');
@@ -17,7 +17,7 @@ require('node:child_process');
17
17
  require('node:readline');
18
18
  require('tweetnacl');
19
19
  require('axios');
20
- require('./persistence-BL06LLVz.cjs');
20
+ require('./persistence-C8-MtdQK.cjs');
21
21
  require('open');
22
22
  require('chalk');
23
23
  require('fs');
@@ -519,6 +519,29 @@ function bindGeminiUserMessageQueue(opts) {
519
519
  });
520
520
  }
521
521
 
522
+ function normalizeGeminiBackendError(error) {
523
+ if (typeof error === "string") {
524
+ return error.trim() || "Gemini runtime exited unexpectedly";
525
+ }
526
+ if (error instanceof Error) {
527
+ return error.message.trim() || "Gemini runtime exited unexpectedly";
528
+ }
529
+ if (typeof error === "object" && error !== null) {
530
+ const record = error;
531
+ const fields = [record.message, record.details, record.detail, record.stderr].map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
532
+ if (fields.length > 0) {
533
+ return fields.join("\n");
534
+ }
535
+ try {
536
+ const serialized = JSON.stringify(record);
537
+ if (serialized && serialized !== "{}") {
538
+ return serialized;
539
+ }
540
+ } catch {
541
+ }
542
+ }
543
+ return "Gemini runtime exited unexpectedly";
544
+ }
522
545
  async function runGemini(opts) {
523
546
  const sessionTag = node_crypto.randomUUID();
524
547
  api.connectionState.setBackend("Gemini");
@@ -650,6 +673,10 @@ async function runGemini(opts) {
650
673
  let handleQueuedUserMessage = null;
651
674
  let emitGeminiStatusMessage = null;
652
675
  let turnAbortedSent = false;
676
+ let turnInFlight = false;
677
+ let shouldInjectHistoryOnNextSession = false;
678
+ let currentModeHash = null;
679
+ let unexpectedRuntimeStopRecovery = null;
653
680
  async function handleAbort() {
654
681
  api.logger.debug("[Gemini] Abort requested - stopping current task");
655
682
  if (!turnAbortedSent) {
@@ -802,6 +829,17 @@ async function runGemini(opts) {
802
829
  let isResponseInProgress = false;
803
830
  let hadToolCallInTurn = false;
804
831
  let taskStartedSent = false;
832
+ const resetTurnState = () => {
833
+ reasoningProcessor.abort();
834
+ diffProcessor.reset();
835
+ accumulatedResponse = "";
836
+ isResponseInProgress = false;
837
+ hadToolCallInTurn = false;
838
+ taskStartedSent = false;
839
+ turnAbortedSent = false;
840
+ thinking = false;
841
+ session.keepAlive(thinking, "remote");
842
+ };
805
843
  const disposeRuntimeHandle = async () => {
806
844
  if (!runtimeHandle) {
807
845
  return;
@@ -816,6 +854,37 @@ async function runGemini(opts) {
816
854
  api.logger.debug("[Gemini] Error disposing runtime session:", error);
817
855
  }
818
856
  };
857
+ const queueHistoryInjectionForRestart = (reason) => {
858
+ messageBuffer.addMessage("\u2550".repeat(40), "status");
859
+ if (conversationHistory.hasHistory()) {
860
+ shouldInjectHistoryOnNextSession = true;
861
+ const message = `${reason} Preserving ${conversationHistory.size()} earlier messages of context.`;
862
+ emitGeminiStatusMessage?.(message);
863
+ api.logger.debug(`[Gemini] Will inject conversation history after restart: ${conversationHistory.getSummary()}`);
864
+ return;
865
+ }
866
+ emitGeminiStatusMessage?.(reason);
867
+ };
868
+ const recoverUnexpectedRuntimeStop = async (detail) => {
869
+ if (shouldExit || messageQueue.isClosed() || unexpectedRuntimeStopRecovery) {
870
+ return;
871
+ }
872
+ const errorMessage = normalizeGeminiBackendError(detail);
873
+ unexpectedRuntimeStopRecovery = (async () => {
874
+ queueHistoryInjectionForRestart(
875
+ `Gemini runtime stopped unexpectedly (${errorMessage}). Starting a new Gemini session on the next message...`
876
+ );
877
+ await disposeRuntimeHandle();
878
+ currentModeHash = null;
879
+ permissionHandler.reset();
880
+ resetTurnState();
881
+ })();
882
+ try {
883
+ await unexpectedRuntimeStopRecovery;
884
+ } finally {
885
+ unexpectedRuntimeStopRecovery = null;
886
+ }
887
+ };
819
888
  function setupGeminiMessageHandler(activeRuntimeHandle) {
820
889
  const forwardAgentMessage = (agentMessage) => {
821
890
  registerKillSessionHandler.forwardAgentMessageToProviderSession(agentMessage, {
@@ -866,6 +935,9 @@ async function runGemini(opts) {
866
935
  messageBuffer.addMessage("Thinking...", "system");
867
936
  } else if (msg.status === "idle" || msg.status === "stopped") {
868
937
  reasoningProcessor.complete();
938
+ if (msg.status === "stopped" && !turnInFlight) {
939
+ void recoverUnexpectedRuntimeStop(msg.detail);
940
+ }
869
941
  } else if (msg.status === "error") {
870
942
  thinking = false;
871
943
  session.keepAlive(thinking, "remote");
@@ -1025,7 +1097,6 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1025
1097
  };
1026
1098
  }
1027
1099
  try {
1028
- let currentModeHash = null;
1029
1100
  let pending = null;
1030
1101
  while (!shouldExit) {
1031
1102
  let message = pending;
@@ -1048,19 +1119,11 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1048
1119
  if (!message) {
1049
1120
  break;
1050
1121
  }
1051
- let injectHistoryContext = false;
1052
1122
  if (runtimeHandle && currentModeHash && message.hash !== currentModeHash) {
1053
1123
  api.logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
1054
- messageBuffer.addMessage("\u2550".repeat(40), "status");
1055
- if (conversationHistory.hasHistory()) {
1056
- messageBuffer.addMessage(`Switching model (preserving ${conversationHistory.size()} messages of context)...`, "status");
1057
- injectHistoryContext = true;
1058
- api.logger.debug(`[Gemini] Will inject conversation history: ${conversationHistory.getSummary()}`);
1059
- } else {
1060
- messageBuffer.addMessage("Starting new Gemini session (mode changed)...", "status");
1061
- }
1124
+ queueHistoryInjectionForRestart("Starting new Gemini session (execution settings changed)...");
1062
1125
  permissionHandler.reset();
1063
- reasoningProcessor.abort();
1126
+ resetTurnState();
1064
1127
  await disposeRuntimeHandle();
1065
1128
  const launchedRuntime = await launchGeminiRuntimeHandle(message.mode);
1066
1129
  const actualModel = launchedRuntime.model;
@@ -1078,6 +1141,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1078
1141
  isProcessingMessage = true;
1079
1142
  let turnStatus = "task_complete";
1080
1143
  try {
1144
+ turnInFlight = true;
1081
1145
  let activeHandle = runtimeHandle;
1082
1146
  if (!activeHandle) {
1083
1147
  const launchedRuntime = await launchGeminiRuntimeHandle(message.mode);
@@ -1099,7 +1163,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1099
1163
  taskStartedSent = false;
1100
1164
  turnAbortedSent = false;
1101
1165
  let promptToSend = message.message;
1102
- if (injectHistoryContext && conversationHistory.hasHistory()) {
1166
+ if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
1103
1167
  const historyContext = conversationHistory.getContextForNewSession();
1104
1168
  promptToSend = historyContext + promptToSend;
1105
1169
  api.logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
@@ -1119,6 +1183,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1119
1183
  api.logger.debug("[gemini] Prompt sent successfully");
1120
1184
  await registerKillSessionHandler.waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal, 10 * 6e4);
1121
1185
  api.logger.debug("[gemini] Response complete");
1186
+ shouldInjectHistoryOnNextSession = false;
1122
1187
  break;
1123
1188
  } catch (promptError) {
1124
1189
  lastError = promptError;
@@ -1210,6 +1275,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1210
1275
  });
1211
1276
  }
1212
1277
  } finally {
1278
+ turnInFlight = false;
1213
1279
  permissionHandler.reset();
1214
1280
  reasoningProcessor.abort();
1215
1281
  diffProcessor.reset();
@@ -1,10 +1,10 @@
1
1
  import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { l as logger, b as connectionState, A as ApiClient } from './api-w_CUxb9Q.mjs';
5
- import { B as BasePermissionHandler, C as ConversationHistory$1, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, s as syncControlledByUserState, b as MessageQueue2, h as hashObject, d as registerKillSessionHandler, f as MessageBuffer, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, k as closeProviderSession, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession } from './registerKillSessionHandler-CjWfUfc3.mjs';
6
- import { g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-GuXV-pxB.mjs';
7
- import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-DQkzwRuf.mjs';
4
+ import { l as logger, b as connectionState, A as ApiClient } from './api-Cxifhw5r.mjs';
5
+ import { B as BasePermissionHandler, C as ConversationHistory$1, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, s as syncControlledByUserState, b as MessageQueue2, h as hashObject, d as registerKillSessionHandler, f as MessageBuffer, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, k as closeProviderSession, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession } from './registerKillSessionHandler-BFBkz_XT.mjs';
6
+ import { g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-Des7I5WX.mjs';
7
+ import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-BaOWkVcu.mjs';
8
8
  import 'cross-spawn';
9
9
  import '@agentclientprotocol/sdk';
10
10
  import 'ps-list';
@@ -15,7 +15,7 @@ import 'node:child_process';
15
15
  import 'node:readline';
16
16
  import 'tweetnacl';
17
17
  import 'axios';
18
- import './persistence-MSy70is3.mjs';
18
+ import './persistence-6d4U4Sh8.mjs';
19
19
  import 'open';
20
20
  import 'chalk';
21
21
  import 'fs';
@@ -517,6 +517,29 @@ function bindGeminiUserMessageQueue(opts) {
517
517
  });
518
518
  }
519
519
 
520
+ function normalizeGeminiBackendError(error) {
521
+ if (typeof error === "string") {
522
+ return error.trim() || "Gemini runtime exited unexpectedly";
523
+ }
524
+ if (error instanceof Error) {
525
+ return error.message.trim() || "Gemini runtime exited unexpectedly";
526
+ }
527
+ if (typeof error === "object" && error !== null) {
528
+ const record = error;
529
+ const fields = [record.message, record.details, record.detail, record.stderr].map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
530
+ if (fields.length > 0) {
531
+ return fields.join("\n");
532
+ }
533
+ try {
534
+ const serialized = JSON.stringify(record);
535
+ if (serialized && serialized !== "{}") {
536
+ return serialized;
537
+ }
538
+ } catch {
539
+ }
540
+ }
541
+ return "Gemini runtime exited unexpectedly";
542
+ }
520
543
  async function runGemini(opts) {
521
544
  const sessionTag = randomUUID();
522
545
  connectionState.setBackend("Gemini");
@@ -648,6 +671,10 @@ async function runGemini(opts) {
648
671
  let handleQueuedUserMessage = null;
649
672
  let emitGeminiStatusMessage = null;
650
673
  let turnAbortedSent = false;
674
+ let turnInFlight = false;
675
+ let shouldInjectHistoryOnNextSession = false;
676
+ let currentModeHash = null;
677
+ let unexpectedRuntimeStopRecovery = null;
651
678
  async function handleAbort() {
652
679
  logger.debug("[Gemini] Abort requested - stopping current task");
653
680
  if (!turnAbortedSent) {
@@ -800,6 +827,17 @@ async function runGemini(opts) {
800
827
  let isResponseInProgress = false;
801
828
  let hadToolCallInTurn = false;
802
829
  let taskStartedSent = false;
830
+ const resetTurnState = () => {
831
+ reasoningProcessor.abort();
832
+ diffProcessor.reset();
833
+ accumulatedResponse = "";
834
+ isResponseInProgress = false;
835
+ hadToolCallInTurn = false;
836
+ taskStartedSent = false;
837
+ turnAbortedSent = false;
838
+ thinking = false;
839
+ session.keepAlive(thinking, "remote");
840
+ };
803
841
  const disposeRuntimeHandle = async () => {
804
842
  if (!runtimeHandle) {
805
843
  return;
@@ -814,6 +852,37 @@ async function runGemini(opts) {
814
852
  logger.debug("[Gemini] Error disposing runtime session:", error);
815
853
  }
816
854
  };
855
+ const queueHistoryInjectionForRestart = (reason) => {
856
+ messageBuffer.addMessage("\u2550".repeat(40), "status");
857
+ if (conversationHistory.hasHistory()) {
858
+ shouldInjectHistoryOnNextSession = true;
859
+ const message = `${reason} Preserving ${conversationHistory.size()} earlier messages of context.`;
860
+ emitGeminiStatusMessage?.(message);
861
+ logger.debug(`[Gemini] Will inject conversation history after restart: ${conversationHistory.getSummary()}`);
862
+ return;
863
+ }
864
+ emitGeminiStatusMessage?.(reason);
865
+ };
866
+ const recoverUnexpectedRuntimeStop = async (detail) => {
867
+ if (shouldExit || messageQueue.isClosed() || unexpectedRuntimeStopRecovery) {
868
+ return;
869
+ }
870
+ const errorMessage = normalizeGeminiBackendError(detail);
871
+ unexpectedRuntimeStopRecovery = (async () => {
872
+ queueHistoryInjectionForRestart(
873
+ `Gemini runtime stopped unexpectedly (${errorMessage}). Starting a new Gemini session on the next message...`
874
+ );
875
+ await disposeRuntimeHandle();
876
+ currentModeHash = null;
877
+ permissionHandler.reset();
878
+ resetTurnState();
879
+ })();
880
+ try {
881
+ await unexpectedRuntimeStopRecovery;
882
+ } finally {
883
+ unexpectedRuntimeStopRecovery = null;
884
+ }
885
+ };
817
886
  function setupGeminiMessageHandler(activeRuntimeHandle) {
818
887
  const forwardAgentMessage = (agentMessage) => {
819
888
  forwardAgentMessageToProviderSession(agentMessage, {
@@ -864,6 +933,9 @@ async function runGemini(opts) {
864
933
  messageBuffer.addMessage("Thinking...", "system");
865
934
  } else if (msg.status === "idle" || msg.status === "stopped") {
866
935
  reasoningProcessor.complete();
936
+ if (msg.status === "stopped" && !turnInFlight) {
937
+ void recoverUnexpectedRuntimeStop(msg.detail);
938
+ }
867
939
  } else if (msg.status === "error") {
868
940
  thinking = false;
869
941
  session.keepAlive(thinking, "remote");
@@ -1023,7 +1095,6 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1023
1095
  };
1024
1096
  }
1025
1097
  try {
1026
- let currentModeHash = null;
1027
1098
  let pending = null;
1028
1099
  while (!shouldExit) {
1029
1100
  let message = pending;
@@ -1046,19 +1117,11 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1046
1117
  if (!message) {
1047
1118
  break;
1048
1119
  }
1049
- let injectHistoryContext = false;
1050
1120
  if (runtimeHandle && currentModeHash && message.hash !== currentModeHash) {
1051
1121
  logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
1052
- messageBuffer.addMessage("\u2550".repeat(40), "status");
1053
- if (conversationHistory.hasHistory()) {
1054
- messageBuffer.addMessage(`Switching model (preserving ${conversationHistory.size()} messages of context)...`, "status");
1055
- injectHistoryContext = true;
1056
- logger.debug(`[Gemini] Will inject conversation history: ${conversationHistory.getSummary()}`);
1057
- } else {
1058
- messageBuffer.addMessage("Starting new Gemini session (mode changed)...", "status");
1059
- }
1122
+ queueHistoryInjectionForRestart("Starting new Gemini session (execution settings changed)...");
1060
1123
  permissionHandler.reset();
1061
- reasoningProcessor.abort();
1124
+ resetTurnState();
1062
1125
  await disposeRuntimeHandle();
1063
1126
  const launchedRuntime = await launchGeminiRuntimeHandle(message.mode);
1064
1127
  const actualModel = launchedRuntime.model;
@@ -1076,6 +1139,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1076
1139
  isProcessingMessage = true;
1077
1140
  let turnStatus = "task_complete";
1078
1141
  try {
1142
+ turnInFlight = true;
1079
1143
  let activeHandle = runtimeHandle;
1080
1144
  if (!activeHandle) {
1081
1145
  const launchedRuntime = await launchGeminiRuntimeHandle(message.mode);
@@ -1097,7 +1161,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1097
1161
  taskStartedSent = false;
1098
1162
  turnAbortedSent = false;
1099
1163
  let promptToSend = message.message;
1100
- if (injectHistoryContext && conversationHistory.hasHistory()) {
1164
+ if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
1101
1165
  const historyContext = conversationHistory.getContextForNewSession();
1102
1166
  promptToSend = historyContext + promptToSend;
1103
1167
  logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
@@ -1117,6 +1181,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1117
1181
  logger.debug("[gemini] Prompt sent successfully");
1118
1182
  await waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal, 10 * 6e4);
1119
1183
  logger.debug("[gemini] Response complete");
1184
+ shouldInjectHistoryOnNextSession = false;
1120
1185
  break;
1121
1186
  } catch (promptError) {
1122
1187
  lastError = promptError;
@@ -1208,6 +1273,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1208
1273
  });
1209
1274
  }
1210
1275
  } finally {
1276
+ turnInFlight = false;
1211
1277
  permissionHandler.reset();
1212
1278
  reasoningProcessor.abort();
1213
1279
  diffProcessor.reset();