@zonease/happy 0.6.38 → 0.6.40

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 (112) hide show
  1. package/bin/happy.mjs +10 -0
  2. package/dist/{types-DvTsFaqR.cjs → api-C7FyJfZ1.cjs} +400 -1964
  3. package/dist/{types-BWpRU1VN.mjs → api-D6WL40-U.mjs} +220 -1729
  4. package/dist/auth-C7ZScWEw.cjs +274 -0
  5. package/dist/auth-DCsIoZLT.cjs +183 -0
  6. package/dist/auth-DO9GexAR.mjs +181 -0
  7. package/dist/auth-DxJ3VvrX.mjs +270 -0
  8. package/dist/browser-AoVGRX7y.mjs +20 -0
  9. package/dist/browser-DzgO4oaD.cjs +22 -0
  10. package/dist/claudeLocal-C6BdzhDx.cjs +352 -0
  11. package/dist/claudeLocal-CWNGpJ0-.mjs +344 -0
  12. package/dist/codex/happyMcpStdioBridge.cjs +4 -1
  13. package/dist/codex/happyMcpStdioBridge.mjs +4 -1
  14. package/dist/common-BdNgghUJ.mjs +75 -0
  15. package/dist/common-CZvSRU4p.cjs +83 -0
  16. package/dist/{config-0Xnc8ARM.cjs → config-CclB3QW9.cjs} +21 -34
  17. package/dist/{config-_GW4YBCP.mjs → config-DZk-mJ0K.mjs} +7 -20
  18. package/dist/connect-BXLUKJ5P.mjs +679 -0
  19. package/dist/connect-k9CqDJ-T.cjs +681 -0
  20. package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
  21. package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
  22. package/dist/controlClient-B23M-WPp.cjs +177 -0
  23. package/dist/controlClient-DB5tDU7V.mjs +167 -0
  24. package/dist/deviceKeys-BTdo34Uz.mjs +175 -0
  25. package/dist/deviceKeys-C540DcXl.cjs +182 -0
  26. package/dist/diagnose-B3D1a_v0.cjs +60 -0
  27. package/dist/diagnose-CuRKXxt1.mjs +58 -0
  28. package/dist/doctor-BQGLhrcI.cjs +214 -0
  29. package/dist/doctor-C08m5Z9f.cjs +78 -0
  30. package/dist/doctor-CU4JLGQ1.mjs +211 -0
  31. package/dist/doctor-ON7pN5G5.mjs +74 -0
  32. package/dist/downloadImage-DZXI3mXL.mjs +887 -0
  33. package/dist/downloadImage-cQ1Z7hkC.cjs +897 -0
  34. package/dist/enroll-B55BQR56.mjs +113 -0
  35. package/dist/enroll-Bo-CNio1.cjs +115 -0
  36. package/dist/evidence-DQp8QWcv.cjs +129 -0
  37. package/dist/evidence-DTYRAaOZ.mjs +127 -0
  38. package/dist/formatImageMessage-CixDYY6G.cjs +46 -0
  39. package/dist/formatImageMessage-DbKSSjMx.mjs +43 -0
  40. package/dist/github-DKcyF1zp.mjs +57 -0
  41. package/dist/github-h9GhJJ_C.cjs +59 -0
  42. package/dist/index-CDTNgfUf.cjs +578 -0
  43. package/dist/index-CPKdvi7J.mjs +554 -0
  44. package/dist/index.cjs +812 -40
  45. package/dist/index.mjs +813 -40
  46. package/dist/install-B1e6rdy7.mjs +94 -0
  47. package/dist/install-CgUPGIoF.mjs +95 -0
  48. package/dist/install-D7Ir7ciZ.cjs +96 -0
  49. package/dist/install-DSDufaPd.cjs +98 -0
  50. package/dist/lib.cjs +18 -12
  51. package/dist/lib.d.cts +77 -0
  52. package/dist/lib.d.mts +77 -0
  53. package/dist/lib.mjs +13 -7
  54. package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Bfei9wPq.mjs} +4 -2
  55. package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-CbLGtvST.cjs} +63 -61
  56. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  57. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  58. package/dist/persistence-CBTtC_dm.cjs +996 -0
  59. package/dist/persistence-DKfF81pd.mjs +944 -0
  60. package/dist/projectPath-BTBIMB57.mjs +10 -0
  61. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  62. package/dist/prompt-BTWDZZO0.cjs +25 -0
  63. package/dist/prompt-BsAZsPbo.mjs +22 -0
  64. package/dist/release-BMEzNONE.mjs +168 -0
  65. package/dist/release-EhOJeAZe.cjs +171 -0
  66. package/dist/run-BVZsMNwN.mjs +2164 -0
  67. package/dist/run-CURx7LhK.cjs +2188 -0
  68. package/dist/runClaude-6Gi0sYQy.mjs +3763 -0
  69. package/dist/runClaude-CL3Kt5ex.cjs +3766 -0
  70. package/dist/{runCodex-DiKzBf9q.mjs → runCodex-ClwEgJ7M.mjs} +36 -20
  71. package/dist/{runCodex-skq0j05d.cjs → runCodex-YKyVBkJ3.cjs} +169 -153
  72. package/dist/{runGemini-BeqrVq8R.mjs → runGemini-BPWxVr60.mjs} +34 -17
  73. package/dist/{runGemini-CVp-CEIh.cjs → runGemini-Xz2W1spn.cjs} +212 -195
  74. package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-CdCWiiLr.mjs} +14 -38
  75. package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-DjZyCvDI.cjs} +31 -55
  76. package/dist/{serve-BNdoEDVx.mjs → serve-B48JttQ3.mjs} +12 -35
  77. package/dist/{serve-BECdtivY.cjs → serve-B8vaWQA0.cjs} +35 -58
  78. package/dist/session-BXboDn2V.mjs +108 -0
  79. package/dist/session-BZO25zxp.cjs +110 -0
  80. package/dist/sessionKeyCache-B6cGadYL.mjs +33 -0
  81. package/dist/sessionKeyCache-CDmexJ9p.cjs +36 -0
  82. package/dist/sessionList-CgAYZpNj.mjs +51 -0
  83. package/dist/sessionList-lQ-nqEhc.cjs +54 -0
  84. package/dist/sessionSummary-CcORiQSq.cjs +393 -0
  85. package/dist/sessionSummary-DCWQoaDP.mjs +387 -0
  86. package/dist/spawnHappyCLI-KiazE3kL.cjs +70 -0
  87. package/dist/spawnHappyCLI-yBIP_Oqi.mjs +66 -0
  88. package/dist/ssh-q5uZhqBf.mjs +359 -0
  89. package/dist/ssh-yMllSHu5.cjs +365 -0
  90. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  91. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  92. package/dist/task-_nr7J19j.cjs +167 -0
  93. package/dist/task-wNX1N2i4.mjs +165 -0
  94. package/dist/time-Bj2HRkKH.cjs +33 -0
  95. package/dist/time-DgsBLJA_.mjs +29 -0
  96. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  97. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  98. package/dist/types-BoJh4Qfv.mjs +57 -0
  99. package/dist/types-DWeB7aqh.cjs +59 -0
  100. package/dist/uninstall-Buaz7d-X.cjs +77 -0
  101. package/dist/uninstall-Dxf6_4mQ.mjs +75 -0
  102. package/dist/update-CGlIfa8e.cjs +111 -0
  103. package/dist/update-CnnoX2cV.mjs +109 -0
  104. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  105. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  106. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  107. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  108. package/package.json +1 -1
  109. package/dist/index-BbCDDvoB.cjs +0 -11376
  110. package/dist/index-vvZXdswy.mjs +0 -11336
  111. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  112. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
@@ -3,52 +3,69 @@
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
- var persistence = require('./types-DvTsFaqR.cjs');
7
- var loadableToolOutput = require('./loadableToolOutput-5vdQB98M.cjs');
8
- var index = require('./index-BbCDDvoB.cjs');
6
+ var api = require('./api-C7FyJfZ1.cjs');
7
+ var logger = require('./persistence-CBTtC_dm.cjs');
8
+ var loadableToolOutput = require('./loadableToolOutput-CbLGtvST.cjs');
9
+ var run = require('./run-CURx7LhK.cjs');
10
+ var downloadImage = require('./downloadImage-cQ1Z7hkC.cjs');
11
+ var controlClient = require('./controlClient-B23M-WPp.cjs');
9
12
  var node_child_process = require('node:child_process');
10
13
  var sdk = require('@agentclientprotocol/sdk');
11
- var constants = require('./constants-B4x1K7by.cjs');
12
- var config = require('./config-0Xnc8ARM.cjs');
14
+ var time = require('./time-Bj2HRkKH.cjs');
15
+ var index = require('./index-CDTNgfUf.cjs');
16
+ var constants = require('./constants-E_UWYTo3.cjs');
17
+ var config = require('./config-CclB3QW9.cjs');
18
+ var formatImageMessage = require('./formatImageMessage-CixDYY6G.cjs');
13
19
  require('axios');
14
- require('chalk');
15
- require('fs');
16
- require('node:fs');
17
- require('node:os');
18
- require('node:path');
19
20
  require('node:events');
20
21
  require('socket.io-client');
21
22
  require('zod');
22
- require('@paralleldrive/cuid2');
23
- require('tweetnacl');
23
+ require('node:fs');
24
+ require('node:path');
24
25
  require('node:fs/promises');
26
+ require('node:os');
25
27
  require('node:util');
26
28
  require('child_process');
27
29
  require('util');
28
30
  require('fs/promises');
29
31
  require('path');
32
+ require('./projectPath-ChLhdOyt.cjs');
30
33
  require('url');
31
34
  require('node:module');
32
35
  require('ws');
33
36
  require('crypto');
37
+ require('tweetnacl');
34
38
  require('@stablelib/base64');
35
39
  require('node:readline');
36
40
  require('expo-server-sdk');
37
- require('./mcpToolSchemas-f-kttjFw.cjs');
38
- require('node:url');
39
- require('ps-list');
40
- require('cross-spawn');
41
+ require('./sessionKeyCache-CDmexJ9p.cjs');
42
+ require('chalk');
43
+ require('fs');
41
44
  require('os');
42
45
  require('tmp');
46
+ require('./auth-C7ZScWEw.cjs');
43
47
  require('qrcode-terminal');
48
+ require('./browser-DzgO4oaD.cjs');
44
49
  require('open');
50
+ require('./doctor-BQGLhrcI.cjs');
51
+ require('./doctor-C08m5Z9f.cjs');
52
+ require('ps-list');
53
+ require('cross-spawn');
54
+ require('./spawnHappyCLI-KiazE3kL.cjs');
55
+ require('./deviceKeys-C540DcXl.cjs');
56
+ require('./install-DSDufaPd.cjs');
57
+ require('./trimIdent-4gvk9Wk6.cjs');
45
58
  require('fastify');
46
59
  require('fastify-type-provider-zod');
60
+ require('./common-CZvSRU4p.cjs');
47
61
  require('@modelcontextprotocol/sdk/server/mcp.js');
48
62
  require('node:http');
49
63
  require('@modelcontextprotocol/sdk/server/streamableHttp.js');
50
64
  require('@modelcontextprotocol/sdk/types.js');
51
- require('http');
65
+ require('./prompt-BTWDZZO0.cjs');
66
+ require('./mcpToolSchemas-DK42yoZ_.cjs');
67
+ require('./types-DWeB7aqh.cjs');
68
+ require('@paralleldrive/cuid2');
52
69
 
53
70
  const DEFAULT_TIMEOUTS = {
54
71
  /** Default initialization timeout: 60 seconds */
@@ -229,7 +246,7 @@ class GeminiTransport {
229
246
  const errorMessage = {
230
247
  type: "status",
231
248
  status: "error",
232
- detail: `Model not found. Available models: ${persistence.GEMINI_MODEL_MODES.join(", ")}`
249
+ detail: `Model not found. Available models: ${index.GEMINI_MODEL_MODES.join(", ")}`
233
250
  };
234
251
  return { message: errorMessage };
235
252
  }
@@ -337,7 +354,7 @@ class GeminiTransport {
337
354
  }
338
355
  if (toolName === "other" || toolName === "Unknown tool") {
339
356
  const inputKeys = input && typeof input === "object" ? Object.keys(input) : [];
340
- persistence.logger.debug(
357
+ logger.logger.debug(
341
358
  `[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.`
342
359
  );
343
360
  }
@@ -361,7 +378,7 @@ function nodeToWebStreams(stdin, stdout) {
361
378
  return new Promise((resolve, reject) => {
362
379
  const ok = stdin.write(chunk, (err) => {
363
380
  if (err) {
364
- persistence.logger.debug(`[AcpBackend] Error writing to stdin:`, err);
381
+ logger.logger.debug(`[AcpBackend] Error writing to stdin:`, err);
365
382
  reject(err);
366
383
  }
367
384
  });
@@ -390,7 +407,7 @@ function nodeToWebStreams(stdin, stdout) {
390
407
  controller.close();
391
408
  });
392
409
  stdout.on("error", (err) => {
393
- persistence.logger.debug(`[AcpBackend] Stdout error:`, err);
410
+ logger.logger.debug(`[AcpBackend] Stdout error:`, err);
394
411
  controller.error(err);
395
412
  });
396
413
  },
@@ -413,9 +430,9 @@ async function withRetry(operation, options) {
413
430
  options.baseDelayMs * Math.pow(2, attempt - 1),
414
431
  options.maxDelayMs
415
432
  );
416
- persistence.logger.debug(`[AcpBackend] ${options.operationName} failed (attempt ${attempt}/${options.maxAttempts}): ${lastError.message}. Retrying in ${delayMs}ms...`);
433
+ logger.logger.debug(`[AcpBackend] ${options.operationName} failed (attempt ${attempt}/${options.maxAttempts}): ${lastError.message}. Retrying in ${delayMs}ms...`);
417
434
  options.onRetry?.(attempt, lastError);
418
- await persistence.delay(delayMs);
435
+ await time.delay(delayMs);
419
436
  } else {
420
437
  break;
421
438
  }
@@ -467,7 +484,7 @@ class AcpBackend {
467
484
  try {
468
485
  listener(msg);
469
486
  } catch (error) {
470
- persistence.logger.warn("[AcpBackend] Error in message handler:", error);
487
+ logger.logger.warn("[AcpBackend] Error in message handler:", error);
471
488
  }
472
489
  }
473
490
  }
@@ -479,7 +496,7 @@ class AcpBackend {
479
496
  this.emit({ type: "status", status: "starting" });
480
497
  let startupStatusErrorEmitted = false;
481
498
  try {
482
- persistence.logger.debug(`[AcpBackend] Starting session: ${sessionId}`);
499
+ logger.logger.debug(`[AcpBackend] Starting session: ${sessionId}`);
483
500
  const args = this.options.args || [];
484
501
  if (process.platform === "win32") {
485
502
  const fullCommand = [this.options.command, ...args].join(" ");
@@ -528,9 +545,9 @@ class AcpBackend {
528
545
  hasActiveInvestigation
529
546
  };
530
547
  if (hasActiveInvestigation) {
531
- persistence.logger.debug(`[AcpBackend] \u{1F50D} Agent stderr (during investigation): ${text.trim()}`);
548
+ logger.logger.debug(`[AcpBackend] \u{1F50D} Agent stderr (during investigation): ${text.trim()}`);
532
549
  } else {
533
- persistence.logger.debug(`[AcpBackend] Agent stderr: ${text.trim()}`);
550
+ logger.logger.debug(`[AcpBackend] Agent stderr: ${text.trim()}`);
534
551
  }
535
552
  if (this.transport.handleStderr) {
536
553
  const result = this.transport.handleStderr(text, context);
@@ -541,14 +558,14 @@ class AcpBackend {
541
558
  });
542
559
  this.process.on("error", (err) => {
543
560
  signalStartupFailure(err);
544
- persistence.logger.debug(`[AcpBackend] Process error:`, err);
561
+ logger.logger.debug(`[AcpBackend] Process error:`, err);
545
562
  startupStatusErrorEmitted = true;
546
563
  this.emit({ type: "status", status: "error", detail: err.message });
547
564
  });
548
565
  this.process.on("exit", (code, signal) => {
549
566
  if (!this.disposed && code !== 0 && code !== null) {
550
567
  signalStartupFailure(new Error(`Exit code: ${code}`));
551
- persistence.logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
568
+ logger.logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
552
569
  this.emit({ type: "status", status: "stopped", detail: `Exit code: ${code}` });
553
570
  }
554
571
  });
@@ -581,7 +598,7 @@ class AcpBackend {
581
598
  }
582
599
  }
583
600
  if (filteredCount > 0) {
584
- persistence.logger.debug(`[AcpBackend] Filtered out ${filteredCount} non-JSON lines from ${transport.agentName} stdout`);
601
+ logger.logger.debug(`[AcpBackend] Filtered out ${filteredCount} non-JSON lines from ${transport.agentName} stdout`);
585
602
  }
586
603
  controller.close();
587
604
  break;
@@ -602,7 +619,7 @@ class AcpBackend {
602
619
  }
603
620
  }
604
621
  } catch (error) {
605
- persistence.logger.debug(`[AcpBackend] Error filtering stdout stream:`, error);
622
+ logger.logger.debug(`[AcpBackend] Error filtering stdout stream:`, error);
606
623
  controller.error(error);
607
624
  } finally {
608
625
  reader.releaseLock();
@@ -650,19 +667,19 @@ class AcpBackend {
650
667
  toolName = this.transport.determineToolName?.(toolName, toolCallId, input, context) ?? toolName;
651
668
  const originalToolName = toolCall?.toolName || rawKind || extendedParams.kind || "Unknown tool";
652
669
  if (toolName !== originalToolName) {
653
- persistence.logger.debug(`[AcpBackend] Detected tool name: ${toolName} from toolCallId: ${toolCallId}`);
670
+ logger.logger.debug(`[AcpBackend] Detected tool name: ${toolName} from toolCallId: ${toolCallId}`);
654
671
  }
655
672
  if (this.options.normalizeToolName) {
656
673
  const normalized = this.options.normalizeToolName(toolName);
657
674
  if (normalized !== toolName) {
658
- persistence.logger.debug(`[AcpBackend] Normalized tool name: ${toolName} \u2192 ${normalized}`);
675
+ logger.logger.debug(`[AcpBackend] Normalized tool name: ${toolName} \u2192 ${normalized}`);
659
676
  toolName = normalized;
660
677
  }
661
678
  }
662
679
  this.toolCallCountSincePrompt++;
663
680
  const options = extendedParams.options || [];
664
- persistence.logger.debug(`[AcpBackend] Permission request: tool=${toolName}, toolCallId=${toolCallId}, input=`, JSON.stringify(input));
665
- persistence.logger.debug(`[AcpBackend] Permission request params structure:`, JSON.stringify({
681
+ logger.logger.debug(`[AcpBackend] Permission request: tool=${toolName}, toolCallId=${toolCallId}, input=`, JSON.stringify(input));
682
+ logger.logger.debug(`[AcpBackend] Permission request params structure:`, JSON.stringify({
666
683
  hasToolCall: !!toolCall,
667
684
  toolCallKind: toolCall?.kind,
668
685
  toolCallId: toolCall?.toolCallId || toolCall?.id,
@@ -732,7 +749,7 @@ class AcpBackend {
732
749
  }
733
750
  return { outcome: { outcome: "selected", optionId } };
734
751
  } catch (error) {
735
- persistence.logger.debug("[AcpBackend] Error in permission handler:", error);
752
+ logger.logger.debug("[AcpBackend] Error in permission handler:", error);
736
753
  return { outcome: { outcome: "selected", optionId: "cancel" } };
737
754
  }
738
755
  }
@@ -757,11 +774,11 @@ class AcpBackend {
757
774
  },
758
775
  clientInfo: {
759
776
  name: "happy-cli",
760
- version: persistence.packageJson.version
777
+ version: logger.packageJson.version
761
778
  }
762
779
  };
763
780
  const initTimeout = this.transport.getInitTimeout();
764
- persistence.logger.debug(`[AcpBackend] Initializing connection (timeout: ${initTimeout}ms)...`);
781
+ logger.logger.debug(`[AcpBackend] Initializing connection (timeout: ${initTimeout}ms)...`);
765
782
  const isNonRetryableStartupError = (error) => {
766
783
  const maybeErr = error;
767
784
  if (startupFailure && error === startupFailure) {
@@ -803,7 +820,7 @@ class AcpBackend {
803
820
  shouldRetry: (error) => !isNonRetryableStartupError(error)
804
821
  }
805
822
  );
806
- persistence.logger.debug(`[AcpBackend] Initialize completed`);
823
+ logger.logger.debug(`[AcpBackend] Initialize completed`);
807
824
  const mcpServers = this.options.mcpServers ? Object.entries(this.options.mcpServers).map(([name, config]) => {
808
825
  if ("type" in config && config.type === "http") {
809
826
  return {
@@ -825,7 +842,7 @@ class AcpBackend {
825
842
  cwd: this.options.cwd,
826
843
  mcpServers
827
844
  };
828
- persistence.logger.debug(`[AcpBackend] Creating new session...`);
845
+ logger.logger.debug(`[AcpBackend] Creating new session...`);
829
846
  const sessionResponse = await withRetry(
830
847
  async () => {
831
848
  let timeoutHandle = null;
@@ -861,7 +878,7 @@ class AcpBackend {
861
878
  }
862
879
  );
863
880
  this.acpSessionId = sessionResponse.sessionId;
864
- persistence.logger.debug(`[AcpBackend] Session created: ${this.acpSessionId}`);
881
+ logger.logger.debug(`[AcpBackend] Session created: ${this.acpSessionId}`);
865
882
  this.emitInitialSessionMetadata(sessionResponse);
866
883
  this.emitIdleStatus();
867
884
  if (initialPrompt) {
@@ -869,19 +886,19 @@ class AcpBackend {
869
886
  const mcpDelay = hasHttpMcp ? MCP_DISCOVERY_DELAY_MS : 0;
870
887
  const sendInitialPrompt = async () => {
871
888
  if (mcpDelay > 0) {
872
- persistence.logger.debug(`[AcpBackend] Waiting ${mcpDelay}ms for MCP discovery before first prompt`);
889
+ logger.logger.debug(`[AcpBackend] Waiting ${mcpDelay}ms for MCP discovery before first prompt`);
873
890
  await new Promise((r) => setTimeout(r, mcpDelay));
874
891
  }
875
892
  await this.sendPrompt(sessionId, initialPrompt);
876
893
  };
877
894
  sendInitialPrompt().catch((error) => {
878
- persistence.logger.debug("[AcpBackend] Error sending initial prompt:", error);
895
+ logger.logger.debug("[AcpBackend] Error sending initial prompt:", error);
879
896
  this.emit({ type: "status", status: "error", detail: String(error) });
880
897
  });
881
898
  }
882
899
  return { sessionId };
883
900
  } catch (error) {
884
- persistence.logger.debug("[AcpBackend] Error starting session:", error);
901
+ logger.logger.debug("[AcpBackend] Error starting session:", error);
885
902
  if (!startupStatusErrorEmitted) {
886
903
  this.emit({
887
904
  type: "status",
@@ -952,13 +969,13 @@ class AcpBackend {
952
969
  const notification = params;
953
970
  const update = notification.update;
954
971
  if (!update) {
955
- persistence.logger.debug("[AcpBackend] Received session update without update field:", params);
972
+ logger.logger.debug("[AcpBackend] Received session update without update field:", params);
956
973
  return;
957
974
  }
958
975
  const sessionUpdateType = update.sessionUpdate;
959
976
  const updateType = sessionUpdateType;
960
977
  if (sessionUpdateType !== "agent_message_chunk") {
961
- persistence.logger.debug(`[AcpBackend] Received session update: ${sessionUpdateType}`, JSON.stringify({
978
+ logger.logger.debug(`[AcpBackend] Received session update: ${sessionUpdateType}`, JSON.stringify({
962
979
  sessionUpdate: sessionUpdateType,
963
980
  toolCallId: update.toolCallId,
964
981
  status: update.status,
@@ -1036,7 +1053,7 @@ class AcpBackend {
1036
1053
  "current_mode_update"
1037
1054
  ];
1038
1055
  if (updateType && !handledTypes.includes(updateType) && !update.messageChunk && !update.plan && !update.thinking) {
1039
- persistence.logger.debug(`[AcpBackend] Unhandled session update type: ${updateType}`, JSON.stringify(update, null, 2));
1056
+ logger.logger.debug(`[AcpBackend] Unhandled session update type: ${updateType}`, JSON.stringify(update, null, 2));
1040
1057
  }
1041
1058
  }
1042
1059
  // Promise resolver for waitForIdle - set when waiting for response to complete
@@ -1047,7 +1064,7 @@ class AcpBackend {
1047
1064
  this.toolCallCountSincePrompt = 0;
1048
1065
  this.recentPromptHadChangeTitle = promptHasChangeTitle;
1049
1066
  if (promptHasChangeTitle) {
1050
- persistence.logger.debug('[AcpBackend] Prompt contains change_title instruction - will auto-approve first "other" tool call if it matches pattern');
1067
+ logger.logger.debug('[AcpBackend] Prompt contains change_title instruction - will auto-approve first "other" tool call if it matches pattern');
1051
1068
  }
1052
1069
  if (this.disposed) {
1053
1070
  throw new Error("Backend has been disposed");
@@ -1058,11 +1075,11 @@ class AcpBackend {
1058
1075
  this.emit({ type: "status", status: "running" });
1059
1076
  this.waitingForResponse = true;
1060
1077
  try {
1061
- persistence.logger.debug(`[AcpBackend] Sending prompt (length: ${prompt.length}): ${prompt.substring(0, 100)}...`);
1062
- persistence.logger.debug(`[AcpBackend] Full prompt: ${prompt}`);
1078
+ logger.logger.debug(`[AcpBackend] Sending prompt (length: ${prompt.length}): ${prompt.substring(0, 100)}...`);
1079
+ logger.logger.debug(`[AcpBackend] Full prompt: ${prompt}`);
1063
1080
  const contentBlocks = [];
1064
1081
  if (options?.images && options.images.length > 0) {
1065
- persistence.logger.debug(`[AcpBackend] Including ${options.images.length} image(s) in prompt`);
1082
+ logger.logger.debug(`[AcpBackend] Including ${options.images.length} image(s) in prompt`);
1066
1083
  for (const image of options.images) {
1067
1084
  contentBlocks.push({
1068
1085
  type: "image",
@@ -1079,11 +1096,11 @@ class AcpBackend {
1079
1096
  sessionId: this.acpSessionId,
1080
1097
  prompt: contentBlocks
1081
1098
  };
1082
- persistence.logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2).substring(0, 1e3));
1099
+ logger.logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2).substring(0, 1e3));
1083
1100
  await this.connection.prompt(promptRequest);
1084
- persistence.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
1101
+ logger.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
1085
1102
  } catch (error) {
1086
- persistence.logger.debug("[AcpBackend] Error sending prompt:", error);
1103
+ logger.logger.debug("[AcpBackend] Error sending prompt:", error);
1087
1104
  this.waitingForResponse = false;
1088
1105
  let errorDetail;
1089
1106
  if (error instanceof Error) {
@@ -1154,7 +1171,7 @@ class AcpBackend {
1154
1171
  }
1155
1172
  return true;
1156
1173
  } catch (error) {
1157
- persistence.logger.debug("[AcpBackend] Failed to set session config option:", {
1174
+ logger.logger.debug("[AcpBackend] Failed to set session config option:", {
1158
1175
  configId,
1159
1176
  value,
1160
1177
  error
@@ -1182,7 +1199,7 @@ class AcpBackend {
1182
1199
  });
1183
1200
  return true;
1184
1201
  } catch (error) {
1185
- persistence.logger.debug("[AcpBackend] Failed to set session mode:", { modeId, error });
1202
+ logger.logger.debug("[AcpBackend] Failed to set session mode:", { modeId, error });
1186
1203
  return false;
1187
1204
  }
1188
1205
  }
@@ -1204,7 +1221,7 @@ class AcpBackend {
1204
1221
  });
1205
1222
  return true;
1206
1223
  } catch (error) {
1207
- persistence.logger.debug("[AcpBackend] Failed to set session model:", { modelId, error });
1224
+ logger.logger.debug("[AcpBackend] Failed to set session model:", { modelId, error });
1208
1225
  return false;
1209
1226
  }
1210
1227
  }
@@ -1214,7 +1231,7 @@ class AcpBackend {
1214
1231
  emitIdleStatus() {
1215
1232
  this.emit({ type: "status", status: "idle" });
1216
1233
  if (this.idleResolver) {
1217
- persistence.logger.debug("[AcpBackend] Resolving idle waiter");
1234
+ logger.logger.debug("[AcpBackend] Resolving idle waiter");
1218
1235
  this.idleResolver();
1219
1236
  }
1220
1237
  }
@@ -1226,11 +1243,11 @@ class AcpBackend {
1226
1243
  await this.connection.cancel({ sessionId: this.acpSessionId });
1227
1244
  this.emit({ type: "status", status: "stopped", detail: "Cancelled by user" });
1228
1245
  } catch (error) {
1229
- persistence.logger.debug("[AcpBackend] Error cancelling:", error);
1246
+ logger.logger.debug("[AcpBackend] Error cancelling:", error);
1230
1247
  }
1231
1248
  this.waitingForResponse = false;
1232
1249
  if (this.idleResolver) {
1233
- persistence.logger.debug("[AcpBackend] Resolving idle waiter after cancel");
1250
+ logger.logger.debug("[AcpBackend] Resolving idle waiter after cancel");
1234
1251
  this.idleResolver();
1235
1252
  }
1236
1253
  }
@@ -1250,12 +1267,12 @@ class AcpBackend {
1250
1267
  * @param approved - Whether the permission was granted
1251
1268
  */
1252
1269
  async respondToPermission(requestId, approved) {
1253
- persistence.logger.debug(`[AcpBackend] Permission response event (UI only): ${requestId} = ${approved}`);
1270
+ logger.logger.debug(`[AcpBackend] Permission response event (UI only): ${requestId} = ${approved}`);
1254
1271
  this.emit({ type: "permission-response", id: requestId, approved });
1255
1272
  }
1256
1273
  async dispose() {
1257
1274
  if (this.disposed) return;
1258
- persistence.logger.debug("[AcpBackend] Disposing backend");
1275
+ logger.logger.debug("[AcpBackend] Disposing backend");
1259
1276
  this.disposed = true;
1260
1277
  if (this.connection && this.acpSessionId) {
1261
1278
  try {
@@ -1265,7 +1282,7 @@ class AcpBackend {
1265
1282
  // 2s timeout for graceful shutdown
1266
1283
  ]);
1267
1284
  } catch (error) {
1268
- persistence.logger.debug("[AcpBackend] Error during graceful shutdown:", error);
1285
+ logger.logger.debug("[AcpBackend] Error during graceful shutdown:", error);
1269
1286
  }
1270
1287
  }
1271
1288
  if (this.process) {
@@ -1273,7 +1290,7 @@ class AcpBackend {
1273
1290
  await new Promise((resolve) => {
1274
1291
  const timeout = setTimeout(() => {
1275
1292
  if (this.process) {
1276
- persistence.logger.debug("[AcpBackend] Force killing process");
1293
+ logger.logger.debug("[AcpBackend] Force killing process");
1277
1294
  this.process.kill("SIGKILL");
1278
1295
  }
1279
1296
  resolve();
@@ -1306,7 +1323,7 @@ function createGeminiBackend(options) {
1306
1323
  const localConfig = config.readGeminiLocalConfig();
1307
1324
  let apiKey = options.cloudToken || localConfig.token || process.env[constants.GEMINI_API_KEY_ENV] || process.env[constants.GOOGLE_API_KEY_ENV] || options.apiKey;
1308
1325
  if (!apiKey) {
1309
- persistence.logger.warn(`[Gemini] No API key found. Run 'happy connect gemini' to authenticate via Google OAuth, or set ${constants.GEMINI_API_KEY_ENV} environment variable.`);
1326
+ logger.logger.warn(`[Gemini] No API key found. Run 'happy connect gemini' to authenticate via Google OAuth, or set ${constants.GEMINI_API_KEY_ENV} environment variable.`);
1310
1327
  }
1311
1328
  const geminiCommand = "gemini";
1312
1329
  const model = config.determineGeminiModel(options.model, localConfig);
@@ -1317,9 +1334,9 @@ function createGeminiBackend(options) {
1317
1334
  const currentEmail = options.currentUserEmail;
1318
1335
  if (!storedEmail || storedEmail === currentEmail) {
1319
1336
  googleCloudProject = localConfig.googleCloudProject;
1320
- persistence.logger.debug(`[Gemini] Using Google Cloud Project: ${googleCloudProject}${storedEmail ? ` (for ${storedEmail})` : " (global)"}`);
1337
+ logger.logger.debug(`[Gemini] Using Google Cloud Project: ${googleCloudProject}${storedEmail ? ` (for ${storedEmail})` : " (global)"}`);
1321
1338
  } else {
1322
- persistence.logger.debug(`[Gemini] Skipping stored Google Cloud Project (stored for ${storedEmail}, current user is ${currentEmail || "unknown"})`);
1339
+ logger.logger.debug(`[Gemini] Skipping stored Google Cloud Project (stored for ${storedEmail}, current user is ${currentEmail || "unknown"})`);
1323
1340
  }
1324
1341
  }
1325
1342
  const backendOptions = {
@@ -1352,7 +1369,7 @@ function createGeminiBackend(options) {
1352
1369
  }
1353
1370
  };
1354
1371
  const modelSource = config.getGeminiModelSource(options.model, localConfig);
1355
- persistence.logger.debug("[Gemini] Creating ACP SDK backend with options:", {
1372
+ logger.logger.debug("[Gemini] Creating ACP SDK backend with options:", {
1356
1373
  cwd: backendOptions.cwd,
1357
1374
  command: backendOptions.command,
1358
1375
  args: backendOptions.args,
@@ -1507,7 +1524,7 @@ const GeminiDisplay = ({ messageBuffer, logPath, currentModel, onExit }) => {
1507
1524
  alignItems: "center",
1508
1525
  flexDirection: "column"
1509
1526
  },
1510
- /* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(ink.Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ink.Text, { color: "cyan", bold: true }, "\u2728 Gemini Agent Running \u2022 Ctrl-C to exit"), model && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Model: ", model)), persistence.isDebug() && logPath && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
1527
+ /* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(ink.Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ink.Text, { color: "cyan", bold: true }, "\u2728 Gemini Agent Running \u2022 Ctrl-C to exit"), model && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Model: ", model)), logger.isDebug() && logPath && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
1511
1528
  ));
1512
1529
  };
1513
1530
 
@@ -1534,7 +1551,7 @@ class GeminiPermissionHandler extends loadableToolOutput.BasePermissionHandler {
1534
1551
  */
1535
1552
  setPermissionMode(mode) {
1536
1553
  this.currentPermissionMode = mode;
1537
- persistence.logger.debug(`${this.getLogPrefix()} Permission mode set to: ${mode}`);
1554
+ logger.logger.debug(`${this.getLogPrefix()} Permission mode set to: ${mode}`);
1538
1555
  }
1539
1556
  /**
1540
1557
  * Check if a tool should be auto-approved based on permission mode
@@ -1571,7 +1588,7 @@ class GeminiPermissionHandler extends loadableToolOutput.BasePermissionHandler {
1571
1588
  */
1572
1589
  async handleToolCall(toolCallId, toolName, input) {
1573
1590
  if (this.shouldAutoApprove(toolName, toolCallId, input)) {
1574
- persistence.logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId}) in ${this.currentPermissionMode} mode`);
1591
+ logger.logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId}) in ${this.currentPermissionMode} mode`);
1575
1592
  return {
1576
1593
  decision: this.currentPermissionMode === "yolo" ? "approved_for_session" : "approved"
1577
1594
  };
@@ -1584,7 +1601,7 @@ class GeminiPermissionHandler extends loadableToolOutput.BasePermissionHandler {
1584
1601
  input
1585
1602
  });
1586
1603
  this.addPendingRequestToState(toolCallId, toolName, input);
1587
- persistence.logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId}) in ${this.currentPermissionMode} mode`);
1604
+ logger.logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId}) in ${this.currentPermissionMode} mode`);
1588
1605
  });
1589
1606
  }
1590
1607
  }
@@ -1666,7 +1683,7 @@ class GeminiDiffProcessor {
1666
1683
  * Process an fs-edit event and check if it contains diff information
1667
1684
  */
1668
1685
  processFsEdit(path, description, diff) {
1669
- persistence.logger.debug(`[GeminiDiffProcessor] Processing fs-edit for path: ${path}`);
1686
+ logger.logger.debug(`[GeminiDiffProcessor] Processing fs-edit for path: ${path}`);
1670
1687
  if (diff) {
1671
1688
  this.processDiff(path, diff, description);
1672
1689
  } else {
@@ -1681,7 +1698,7 @@ class GeminiDiffProcessor {
1681
1698
  const diff = result.diff || result.unified_diff || result.patch;
1682
1699
  const path = result.path || result.file;
1683
1700
  if (diff && path) {
1684
- persistence.logger.debug(`[GeminiDiffProcessor] Found diff in tool result: ${toolName} (${callId})`);
1701
+ logger.logger.debug(`[GeminiDiffProcessor] Found diff in tool result: ${toolName} (${callId})`);
1685
1702
  this.processDiff(path, diff, result.description);
1686
1703
  } else if (result.changes && typeof result.changes === "object") {
1687
1704
  for (const [filePath, change] of Object.entries(result.changes)) {
@@ -1697,7 +1714,7 @@ class GeminiDiffProcessor {
1697
1714
  processDiff(path, unifiedDiff, description) {
1698
1715
  const previousDiff = this.previousDiffs.get(path);
1699
1716
  if (previousDiff !== unifiedDiff) {
1700
- persistence.logger.debug(`[GeminiDiffProcessor] Unified diff changed for ${path}, sending GeminiDiff tool call`);
1717
+ logger.logger.debug(`[GeminiDiffProcessor] Unified diff changed for ${path}, sending GeminiDiff tool call`);
1701
1718
  const { files, stats, fileStats } = summarizeUnifiedDiff(unifiedDiff);
1702
1719
  if (!files.includes(path) && path) {
1703
1720
  files.unshift(path);
@@ -1705,7 +1722,7 @@ class GeminiDiffProcessor {
1705
1722
  const callId = node_crypto.randomUUID();
1706
1723
  if (this.sessionId) {
1707
1724
  const uniqueFiles = [...new Set(files)];
1708
- persistence.saveDiffRecords(this.sessionId, uniqueFiles.map((fp) => ({
1725
+ api.saveDiffRecords(this.sessionId, uniqueFiles.map((fp) => ({
1709
1726
  callId,
1710
1727
  agent: "gemini",
1711
1728
  filePath: fp,
@@ -1734,13 +1751,13 @@ class GeminiDiffProcessor {
1734
1751
  this.onMessage?.(toolResult);
1735
1752
  }
1736
1753
  this.previousDiffs.set(path, unifiedDiff);
1737
- persistence.logger.debug(`[GeminiDiffProcessor] Updated stored diff for ${path}`);
1754
+ logger.logger.debug(`[GeminiDiffProcessor] Updated stored diff for ${path}`);
1738
1755
  }
1739
1756
  /**
1740
1757
  * Reset the processor state (called on task_complete or turn_aborted)
1741
1758
  */
1742
1759
  reset() {
1743
- persistence.logger.debug("[GeminiDiffProcessor] Resetting diff state");
1760
+ logger.logger.debug("[GeminiDiffProcessor] Resetting diff state");
1744
1761
  this.previousDiffs.clear();
1745
1762
  }
1746
1763
  /**
@@ -1816,7 +1833,7 @@ class ConversationHistory {
1816
1833
  if (!content.trim()) return;
1817
1834
  const trimmedContent = content.trim();
1818
1835
  if (this.isDuplicate("user", trimmedContent)) {
1819
- persistence.logger.debug(`[ConversationHistory] Skipping duplicate user message (${trimmedContent.length} chars)`);
1836
+ logger.logger.debug(`[ConversationHistory] Skipping duplicate user message (${trimmedContent.length} chars)`);
1820
1837
  return;
1821
1838
  }
1822
1839
  this.messages.push({
@@ -1825,7 +1842,7 @@ class ConversationHistory {
1825
1842
  timestamp: Date.now()
1826
1843
  });
1827
1844
  this.trimHistory();
1828
- persistence.logger.debug(`[ConversationHistory] Added user message (${trimmedContent.length} chars), total: ${this.messages.length}`);
1845
+ logger.logger.debug(`[ConversationHistory] Added user message (${trimmedContent.length} chars), total: ${this.messages.length}`);
1829
1846
  }
1830
1847
  /**
1831
1848
  * Add an assistant response to history
@@ -1835,7 +1852,7 @@ class ConversationHistory {
1835
1852
  if (!content.trim()) return;
1836
1853
  const trimmedContent = content.trim();
1837
1854
  if (this.isDuplicate("assistant", trimmedContent)) {
1838
- persistence.logger.debug(`[ConversationHistory] Skipping duplicate assistant message (${trimmedContent.length} chars)`);
1855
+ logger.logger.debug(`[ConversationHistory] Skipping duplicate assistant message (${trimmedContent.length} chars)`);
1839
1856
  return;
1840
1857
  }
1841
1858
  this.messages.push({
@@ -1845,7 +1862,7 @@ class ConversationHistory {
1845
1862
  model: this.currentModel
1846
1863
  });
1847
1864
  this.trimHistory();
1848
- persistence.logger.debug(`[ConversationHistory] Added assistant message (${trimmedContent.length} chars), total: ${this.messages.length}`);
1865
+ logger.logger.debug(`[ConversationHistory] Added assistant message (${trimmedContent.length} chars), total: ${this.messages.length}`);
1849
1866
  }
1850
1867
  /**
1851
1868
  * Get the number of messages in history
@@ -1864,7 +1881,7 @@ class ConversationHistory {
1864
1881
  */
1865
1882
  clear() {
1866
1883
  this.messages = [];
1867
- persistence.logger.debug("[ConversationHistory] History cleared");
1884
+ logger.logger.debug("[ConversationHistory] History cleared");
1868
1885
  }
1869
1886
  /**
1870
1887
  * Get formatted context for injecting into a new session.
@@ -2030,10 +2047,10 @@ async function backfillGeminiSessionHistory(opts) {
2030
2047
  const maxMessages = opts.maxMessages ?? 200;
2031
2048
  const maxUserMessages = opts.maxUserMessages ?? 20;
2032
2049
  const maxBytes = opts.maxBytes ?? 3 * 1024 * 1024;
2033
- const allLines = await persistence.readGeminiSessionLog(opts.sessionId);
2050
+ const allLines = await api.readGeminiSessionLog(opts.sessionId);
2034
2051
  const conversationLines = allLines.filter(isConversationLine);
2035
2052
  if (conversationLines.length === 0) {
2036
- persistence.logger.debug("[GEMINI-BACKFILL] No messages to backfill");
2053
+ logger.logger.debug("[GEMINI-BACKFILL] No messages to backfill");
2037
2054
  return;
2038
2055
  }
2039
2056
  const selected = [];
@@ -2060,7 +2077,7 @@ async function backfillGeminiSessionHistory(opts) {
2060
2077
  callIdToName.set(line.callId, line.name);
2061
2078
  }
2062
2079
  }
2063
- persistence.logger.debug(`[GEMINI-BACKFILL] Backfilling ${selected.length} messages (users: ${userCount}, total: ${totalCount}, bytes: ${totalBytes})`);
2080
+ logger.logger.debug(`[GEMINI-BACKFILL] Backfilling ${selected.length} messages (users: ${userCount}, total: ${totalCount}, bytes: ${totalBytes})`);
2064
2081
  const batch = [];
2065
2082
  for (const line of selected) {
2066
2083
  const content = buildMessageContent(line, callIdToName);
@@ -2075,26 +2092,26 @@ async function backfillGeminiSessionHistory(opts) {
2075
2092
 
2076
2093
  async function runGemini(opts) {
2077
2094
  const sessionTag = node_crypto.randomUUID();
2078
- persistence.connectionState.setBackend("Gemini");
2079
- const api = await persistence.ApiClient.create(opts.credentials);
2080
- const settings = await persistence.readSettings();
2095
+ api.connectionState.setBackend("Gemini");
2096
+ const api$1 = await api.ApiClient.create(opts.credentials);
2097
+ const settings = await logger.readSettings();
2081
2098
  const machineId = settings?.machineId;
2082
2099
  if (!machineId) {
2083
2100
  console.error(`[START] No machine ID found in settings, which is unexpected since authAndSetupMachineIfNeeded should have created it. Please report this issue on https://github.com/ZonEaseTech/happy-wfs/issues`);
2084
2101
  process.exit(1);
2085
2102
  }
2086
- persistence.logger.debug(`Using machineId: ${machineId}`);
2087
- await api.getOrCreateMachine({
2103
+ logger.logger.debug(`Using machineId: ${machineId}`);
2104
+ await api$1.getOrCreateMachine({
2088
2105
  machineId,
2089
- metadata: index.initialMachineMetadata
2106
+ metadata: run.initialMachineMetadata
2090
2107
  });
2091
2108
  let cloudToken = void 0;
2092
2109
  let currentUserEmail = void 0;
2093
2110
  try {
2094
- const vendorToken = await api.getVendorToken("gemini");
2111
+ const vendorToken = await api$1.getVendorToken("gemini");
2095
2112
  if (vendorToken?.oauth?.access_token) {
2096
2113
  cloudToken = vendorToken.oauth.access_token;
2097
- persistence.logger.debug("[Gemini] Using OAuth token from Happy cloud");
2114
+ logger.logger.debug("[Gemini] Using OAuth token from Happy cloud");
2098
2115
  if (vendorToken.oauth.id_token) {
2099
2116
  try {
2100
2117
  const parts = vendorToken.oauth.id_token.split(".");
@@ -2102,24 +2119,24 @@ async function runGemini(opts) {
2102
2119
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
2103
2120
  if (payload.email) {
2104
2121
  currentUserEmail = payload.email;
2105
- persistence.logger.debug(`[Gemini] Current user email: ${currentUserEmail}`);
2122
+ logger.logger.debug(`[Gemini] Current user email: ${currentUserEmail}`);
2106
2123
  }
2107
2124
  }
2108
2125
  } catch {
2109
- persistence.logger.debug("[Gemini] Failed to decode id_token for email");
2126
+ logger.logger.debug("[Gemini] Failed to decode id_token for email");
2110
2127
  }
2111
2128
  }
2112
2129
  }
2113
2130
  } catch (error) {
2114
- persistence.logger.debug("[Gemini] Failed to fetch cloud token:", error);
2131
+ logger.logger.debug("[Gemini] Failed to fetch cloud token:", error);
2115
2132
  }
2116
2133
  const { state, metadata } = loadableToolOutput.createSessionMetadata({
2117
2134
  flavor: "gemini",
2118
2135
  machineId,
2119
2136
  startedBy: opts.startedBy
2120
2137
  });
2121
- const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
2122
- const sessionWriter = new persistence.GeminiSessionWriter(response?.id || sessionTag);
2138
+ const response = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
2139
+ const sessionWriter = new api.GeminiSessionWriter(response?.id || sessionTag);
2123
2140
  await sessionWriter.init({ model: config.getInitialGeminiModel(), cwd: process.cwd() });
2124
2141
  let session;
2125
2142
  let permissionHandler;
@@ -2127,7 +2144,7 @@ async function runGemini(opts) {
2127
2144
  let pendingSessionSwap = null;
2128
2145
  const applyPendingSessionSwap = () => {
2129
2146
  if (pendingSessionSwap) {
2130
- persistence.logger.debug("[gemini] Applying pending session swap");
2147
+ logger.logger.debug("[gemini] Applying pending session swap");
2131
2148
  session = pendingSessionSwap;
2132
2149
  if (permissionHandler) {
2133
2150
  permissionHandler.updateSession(pendingSessionSwap);
@@ -2136,14 +2153,14 @@ async function runGemini(opts) {
2136
2153
  }
2137
2154
  };
2138
2155
  const { session: initialSession, reconnectionHandle } = loadableToolOutput.setupOfflineReconnection({
2139
- api,
2156
+ api: api$1,
2140
2157
  sessionTag,
2141
2158
  metadata,
2142
2159
  state,
2143
2160
  response,
2144
2161
  onSessionSwap: (newSession) => {
2145
2162
  if (isProcessingMessage) {
2146
- persistence.logger.debug("[gemini] Session swap requested during message processing - queueing");
2163
+ logger.logger.debug("[gemini] Session swap requested during message processing - queueing");
2147
2164
  pendingSessionSwap = newSession;
2148
2165
  } else {
2149
2166
  session = newSession;
@@ -2166,18 +2183,18 @@ async function runGemini(opts) {
2166
2183
  }
2167
2184
  if (response) {
2168
2185
  try {
2169
- persistence.logger.debug(`[START] Reporting session ${response.id} to daemon`);
2170
- const result = await index.notifyDaemonSessionStarted(response.id, metadata);
2186
+ logger.logger.debug(`[START] Reporting session ${response.id} to daemon`);
2187
+ const result = await controlClient.notifyDaemonSessionStarted(response.id, metadata);
2171
2188
  if (result.error) {
2172
- persistence.logger.debug(`[START] Failed to report to daemon (may not be running):`, result.error);
2189
+ logger.logger.debug(`[START] Failed to report to daemon (may not be running):`, result.error);
2173
2190
  } else {
2174
- persistence.logger.debug(`[START] Reported session ${response.id} to daemon`);
2191
+ logger.logger.debug(`[START] Reported session ${response.id} to daemon`);
2175
2192
  }
2176
2193
  } catch (error) {
2177
- persistence.logger.debug("[START] Failed to report to daemon (may not be running):", error);
2194
+ logger.logger.debug("[START] Failed to report to daemon (may not be running):", error);
2178
2195
  }
2179
2196
  }
2180
- const messageQueue = new index.MessageQueue2((mode) => index.hashObject({
2197
+ const messageQueue = new downloadImage.MessageQueue2((mode) => downloadImage.hashObject({
2181
2198
  permissionMode: mode.permissionMode,
2182
2199
  model: mode.model
2183
2200
  }));
@@ -2218,12 +2235,12 @@ async function runGemini(opts) {
2218
2235
  messagePermissionMode = message.meta.permissionMode;
2219
2236
  currentPermissionMode = messagePermissionMode;
2220
2237
  updatePermissionMode(messagePermissionMode);
2221
- persistence.logger.debug(`[Gemini] Permission mode updated from user message to: ${currentPermissionMode}`);
2238
+ logger.logger.debug(`[Gemini] Permission mode updated from user message to: ${currentPermissionMode}`);
2222
2239
  } else {
2223
- persistence.logger.debug(`[Gemini] Invalid permission mode received: ${message.meta.permissionMode}`);
2240
+ logger.logger.debug(`[Gemini] Invalid permission mode received: ${message.meta.permissionMode}`);
2224
2241
  }
2225
2242
  } else {
2226
- persistence.logger.debug(`[Gemini] User message received with no permission mode override, using current: ${currentPermissionMode ?? "default (effective)"}`);
2243
+ logger.logger.debug(`[Gemini] User message received with no permission mode override, using current: ${currentPermissionMode ?? "default (effective)"}`);
2227
2244
  }
2228
2245
  if (currentPermissionMode === void 0) {
2229
2246
  currentPermissionMode = "default";
@@ -2241,7 +2258,7 @@ async function runGemini(opts) {
2241
2258
  if (previousModel !== messageModel) {
2242
2259
  updateDisplayedModel(messageModel, true);
2243
2260
  messageBuffer.addMessage(`Model changed to: ${messageModel}`, "system");
2244
- persistence.logger.debug(`[Gemini] Model changed from ${previousModel} to ${messageModel}`);
2261
+ logger.logger.debug(`[Gemini] Model changed from ${previousModel} to ${messageModel}`);
2245
2262
  }
2246
2263
  }
2247
2264
  }
@@ -2249,7 +2266,7 @@ async function runGemini(opts) {
2249
2266
  const originalUserMessage = message.content.text;
2250
2267
  const images = isMixedContent && "images" in message.content ? message.content.images : [];
2251
2268
  if (images.length > 0) {
2252
- persistence.logger.debug(`[Gemini] Received mixed message with ${images.length} image(s)`);
2269
+ logger.logger.debug(`[Gemini] Received mixed message with ${images.length} image(s)`);
2253
2270
  }
2254
2271
  let fullPrompt = originalUserMessage;
2255
2272
  if (isFirstMessage) {
@@ -2281,13 +2298,13 @@ async function runGemini(opts) {
2281
2298
  const sendReady = () => {
2282
2299
  session.sendSessionEvent({ type: "ready" });
2283
2300
  try {
2284
- api.push().sendToAllDevices(
2301
+ api$1.push().sendToAllDevices(
2285
2302
  "It's ready!",
2286
2303
  "Gemini is waiting for your command",
2287
2304
  { sessionId: session.sessionId }
2288
2305
  );
2289
2306
  } catch (pushError) {
2290
- persistence.logger.debug("[Gemini] Failed to send ready push", pushError);
2307
+ logger.logger.debug("[Gemini] Failed to send ready push", pushError);
2291
2308
  }
2292
2309
  session.flush().finally(() => {
2293
2310
  session.updateAgentState((state2) => ({
@@ -2320,7 +2337,7 @@ async function runGemini(opts) {
2320
2337
  let acpSessionId = null;
2321
2338
  let wasSessionCreated = false;
2322
2339
  async function handleAbort() {
2323
- persistence.logger.debug("[Gemini] Abort requested - stopping current task");
2340
+ logger.logger.debug("[Gemini] Abort requested - stopping current task");
2324
2341
  abortRequested = true;
2325
2342
  thinking = false;
2326
2343
  session.keepAlive(thinking, "remote");
@@ -2341,17 +2358,17 @@ async function runGemini(opts) {
2341
2358
  if (geminiBackend && acpSessionId) {
2342
2359
  await geminiBackend.cancel(acpSessionId);
2343
2360
  }
2344
- persistence.logger.debug("[Gemini] Abort completed - session remains active");
2361
+ logger.logger.debug("[Gemini] Abort completed - session remains active");
2345
2362
  } catch (error) {
2346
- persistence.logger.debug("[Gemini] Error during abort:", error);
2363
+ logger.logger.debug("[Gemini] Error during abort:", error);
2347
2364
  } finally {
2348
2365
  abortController = new AbortController();
2349
2366
  }
2350
2367
  }
2351
2368
  const handleKillSession = async () => {
2352
- persistence.logger.debug("[Gemini] Kill session requested - terminating process");
2369
+ logger.logger.debug("[Gemini] Kill session requested - terminating process");
2353
2370
  await handleAbort();
2354
- persistence.logger.debug("[Gemini] Abort completed, proceeding with termination");
2371
+ logger.logger.debug("[Gemini] Abort completed, proceeding with termination");
2355
2372
  try {
2356
2373
  if (session) {
2357
2374
  session.updateMetadata((currentMetadata) => ({
@@ -2365,43 +2382,43 @@ async function runGemini(opts) {
2365
2382
  await session.flush();
2366
2383
  await session.close();
2367
2384
  }
2368
- index.stopCaffeinate();
2385
+ run.stopCaffeinate();
2369
2386
  mcp.stop();
2370
2387
  if (geminiBackend) {
2371
2388
  await geminiBackend.dispose();
2372
2389
  }
2373
- persistence.logger.debug("[Gemini] Session termination complete, exiting");
2390
+ logger.logger.debug("[Gemini] Session termination complete, exiting");
2374
2391
  process.exit(0);
2375
2392
  } catch (error) {
2376
- persistence.logger.debug("[Gemini] Error during session termination:", error);
2393
+ logger.logger.debug("[Gemini] Error during session termination:", error);
2377
2394
  process.exit(1);
2378
2395
  }
2379
2396
  };
2380
2397
  session.rpcHandlerManager.registerHandler("abort", handleAbort);
2381
- index.registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
2382
- const messageBuffer = new index.MessageBuffer();
2398
+ downloadImage.registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
2399
+ const messageBuffer = new downloadImage.MessageBuffer();
2383
2400
  const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
2384
2401
  let inkInstance = null;
2385
2402
  let displayedModel = config.getInitialGeminiModel();
2386
2403
  const localConfig = config.readGeminiLocalConfig();
2387
- persistence.logger.debug(`[gemini] Initial model setup: env[GEMINI_MODEL_ENV]=${process.env[constants.GEMINI_MODEL_ENV] || "not set"}, localConfig=${localConfig.model || "not set"}, displayedModel=${displayedModel}`);
2404
+ logger.logger.debug(`[gemini] Initial model setup: env[GEMINI_MODEL_ENV]=${process.env[constants.GEMINI_MODEL_ENV] || "not set"}, localConfig=${localConfig.model || "not set"}, displayedModel=${displayedModel}`);
2388
2405
  const updateDisplayedModel = (model, saveToConfig = false) => {
2389
2406
  if (model === void 0) {
2390
- persistence.logger.debug(`[gemini] updateDisplayedModel called with undefined, skipping update`);
2407
+ logger.logger.debug(`[gemini] updateDisplayedModel called with undefined, skipping update`);
2391
2408
  return;
2392
2409
  }
2393
2410
  const oldModel = displayedModel;
2394
2411
  displayedModel = model;
2395
- persistence.logger.debug(`[gemini] updateDisplayedModel called: oldModel=${oldModel}, newModel=${model}, saveToConfig=${saveToConfig}`);
2412
+ logger.logger.debug(`[gemini] updateDisplayedModel called: oldModel=${oldModel}, newModel=${model}, saveToConfig=${saveToConfig}`);
2396
2413
  syncSessionModel(model);
2397
2414
  if (saveToConfig) {
2398
2415
  config.saveGeminiModelToConfig(model);
2399
2416
  }
2400
2417
  if (hasTTY && oldModel !== model) {
2401
- persistence.logger.debug(`[gemini] Adding model update message to buffer: [MODEL:${model}]`);
2418
+ logger.logger.debug(`[gemini] Adding model update message to buffer: [MODEL:${model}]`);
2402
2419
  messageBuffer.addMessage(`[MODEL:${model}]`, "system");
2403
2420
  } else if (hasTTY) {
2404
- persistence.logger.debug(`[gemini] Model unchanged, skipping update message`);
2421
+ logger.logger.debug(`[gemini] Model unchanged, skipping update message`);
2405
2422
  }
2406
2423
  };
2407
2424
  if (hasTTY) {
@@ -2410,10 +2427,10 @@ async function runGemini(opts) {
2410
2427
  const currentModelValue = displayedModel || "gemini-2.5-pro";
2411
2428
  return React.createElement(GeminiDisplay, {
2412
2429
  messageBuffer,
2413
- logPath: persistence.isDebug() ? persistence.logger.getLogPath() : void 0,
2430
+ logPath: logger.isDebug() ? logger.logger.getLogPath() : void 0,
2414
2431
  currentModel: currentModelValue,
2415
2432
  onExit: async () => {
2416
- persistence.logger.debug("[gemini]: Exiting agent via Ctrl-C");
2433
+ logger.logger.debug("[gemini]: Exiting agent via Ctrl-C");
2417
2434
  shouldExit = true;
2418
2435
  await handleAbort();
2419
2436
  }
@@ -2424,7 +2441,7 @@ async function runGemini(opts) {
2424
2441
  patchConsole: false
2425
2442
  });
2426
2443
  const initialModelName = displayedModel || "gemini-2.5-pro";
2427
- persistence.logger.debug(`[gemini] Sending initial model to UI: ${initialModelName}`);
2444
+ logger.logger.debug(`[gemini] Sending initial model to UI: ${initialModelName}`);
2428
2445
  messageBuffer.addMessage(`[MODEL:${initialModelName}]`, "system");
2429
2446
  }
2430
2447
  if (hasTTY) {
@@ -2434,9 +2451,9 @@ async function runGemini(opts) {
2434
2451
  }
2435
2452
  process.stdin.setEncoding("utf8");
2436
2453
  }
2437
- const mcp = await index.createMcpContext(session);
2454
+ const mcp = await downloadImage.createMcpContext(session);
2438
2455
  const mcpServers = mcp.configForHttp();
2439
- permissionHandler = new GeminiPermissionHandler(session, api.push());
2456
+ permissionHandler = new GeminiPermissionHandler(session, api$1.push());
2440
2457
  const reasoningProcessor = new GeminiReasoningProcessor((message) => {
2441
2458
  session.sendAgentMessage("gemini", message);
2442
2459
  });
@@ -2453,12 +2470,12 @@ async function runGemini(opts) {
2453
2470
  async (payload) => {
2454
2471
  const mode = payload?.mode;
2455
2472
  if (!mode || !validPermissionModes.includes(mode)) {
2456
- persistence.logger.debug("[gemini] Invalid permission mode via rpc", { mode });
2473
+ logger.logger.debug("[gemini] Invalid permission mode via rpc", { mode });
2457
2474
  return false;
2458
2475
  }
2459
2476
  currentPermissionMode = mode;
2460
2477
  updatePermissionMode(mode);
2461
- persistence.logger.debug(`[gemini] Permission mode updated via rpc to ${mode}`);
2478
+ logger.logger.debug(`[gemini] Permission mode updated via rpc to ${mode}`);
2462
2479
  return true;
2463
2480
  }
2464
2481
  );
@@ -2477,19 +2494,19 @@ async function runGemini(opts) {
2477
2494
  messageBuffer.removeLastMessage("system");
2478
2495
  messageBuffer.addMessage(msg.textDelta, "assistant");
2479
2496
  isResponseInProgress = true;
2480
- persistence.logger.debug(`[gemini] Started new response, first chunk length: ${msg.textDelta.length}`);
2497
+ logger.logger.debug(`[gemini] Started new response, first chunk length: ${msg.textDelta.length}`);
2481
2498
  } else {
2482
2499
  messageBuffer.updateLastMessage(msg.textDelta, "assistant");
2483
- persistence.logger.debug(`[gemini] Updated response, chunk length: ${msg.textDelta.length}, total accumulated: ${accumulatedResponse.length + msg.textDelta.length}`);
2500
+ logger.logger.debug(`[gemini] Updated response, chunk length: ${msg.textDelta.length}, total accumulated: ${accumulatedResponse.length + msg.textDelta.length}`);
2484
2501
  }
2485
2502
  accumulatedResponse += msg.textDelta;
2486
2503
  }
2487
2504
  break;
2488
2505
  case "status":
2489
2506
  const statusDetail = msg.detail ? typeof msg.detail === "object" ? JSON.stringify(msg.detail) : String(msg.detail) : "";
2490
- persistence.logger.debug(`[gemini] Status changed: ${msg.status}${statusDetail ? ` - ${statusDetail}` : ""}`);
2507
+ logger.logger.debug(`[gemini] Status changed: ${msg.status}${statusDetail ? ` - ${statusDetail}` : ""}`);
2491
2508
  if (msg.status === "error") {
2492
- persistence.logger.debug(`[gemini] \u26A0\uFE0F Error status received: ${statusDetail || "Unknown error"}`);
2509
+ logger.logger.debug(`[gemini] \u26A0\uFE0F Error status received: ${statusDetail || "Unknown error"}`);
2493
2510
  if (abortRequested && !abortFeedbackSent) {
2494
2511
  abortFeedbackSent = true;
2495
2512
  session.sendAgentMessage("gemini", {
@@ -2542,9 +2559,9 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2542
2559
  hadToolCallInTurn = true;
2543
2560
  const toolArgs = msg.args ? JSON.stringify(msg.args).substring(0, 100) : "";
2544
2561
  const isInvestigationTool = msg.toolName === "codebase_investigator" || typeof msg.toolName === "string" && msg.toolName.includes("investigator");
2545
- persistence.logger.debug(`[gemini] \u{1F527} Tool call received: ${msg.toolName} (${msg.callId})${isInvestigationTool ? " [INVESTIGATION]" : ""}`);
2562
+ logger.logger.debug(`[gemini] \u{1F527} Tool call received: ${msg.toolName} (${msg.callId})${isInvestigationTool ? " [INVESTIGATION]" : ""}`);
2546
2563
  if (isInvestigationTool && msg.args && typeof msg.args === "object" && "objective" in msg.args) {
2547
- persistence.logger.debug(`[gemini] \u{1F50D} Investigation objective: ${String(msg.args.objective).substring(0, 150)}...`);
2564
+ logger.logger.debug(`[gemini] \u{1F50D} Investigation objective: ${String(msg.args.objective).substring(0, 150)}...`);
2548
2565
  }
2549
2566
  messageBuffer.addMessage(`Executing: ${msg.toolName}${toolArgs ? ` ${toolArgs}${toolArgs.length >= 100 ? "..." : ""}` : ""}`, "tool");
2550
2567
  session.sendAgentMessage("gemini", {
@@ -2559,23 +2576,23 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2559
2576
  case "tool-result":
2560
2577
  if (msg.toolName === "change_title" || msg.callId?.includes("change_title") || msg.toolName === "happy__change_title") {
2561
2578
  changeTitleCompleted = true;
2562
- persistence.logger.debug("[gemini] change_title completed");
2579
+ logger.logger.debug("[gemini] change_title completed");
2563
2580
  }
2564
2581
  const isError = msg.result && typeof msg.result === "object" && "error" in msg.result;
2565
2582
  const resultText = typeof msg.result === "string" ? msg.result.substring(0, 200) : JSON.stringify(msg.result).substring(0, 200);
2566
2583
  const truncatedResult = resultText + (typeof msg.result === "string" && msg.result.length > 200 ? "..." : "");
2567
2584
  const resultSize = typeof msg.result === "string" ? msg.result.length : JSON.stringify(msg.result).length;
2568
- persistence.logger.debug(`[gemini] ${isError ? "\u274C" : "\u2705"} Tool result received: ${msg.toolName} (${msg.callId}) - Size: ${resultSize} bytes${isError ? " [ERROR]" : ""}`);
2585
+ logger.logger.debug(`[gemini] ${isError ? "\u274C" : "\u2705"} Tool result received: ${msg.toolName} (${msg.callId}) - Size: ${resultSize} bytes${isError ? " [ERROR]" : ""}`);
2569
2586
  if (!isError) {
2570
2587
  diffProcessor.processToolResult(msg.toolName, msg.result, msg.callId);
2571
2588
  }
2572
2589
  if (isError) {
2573
2590
  const errorMsg = msg.result.error || "Tool call failed";
2574
- persistence.logger.debug(`[gemini] \u274C Tool call error: ${errorMsg.substring(0, 300)}`);
2591
+ logger.logger.debug(`[gemini] \u274C Tool call error: ${errorMsg.substring(0, 300)}`);
2575
2592
  messageBuffer.addMessage(`Error: ${errorMsg}`, "status");
2576
2593
  } else {
2577
2594
  if (resultSize > 1e3) {
2578
- persistence.logger.debug(`[gemini] \u2705 Large tool result (${resultSize} bytes) - first 200 chars: ${truncatedResult}`);
2595
+ logger.logger.debug(`[gemini] \u2705 Large tool result (${resultSize} bytes) - first 200 chars: ${truncatedResult}`);
2579
2596
  }
2580
2597
  messageBuffer.addMessage(`Result: ${truncatedResult}`, "result");
2581
2598
  }
@@ -2636,13 +2653,13 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2636
2653
  });
2637
2654
  break;
2638
2655
  case "permission-response":
2639
- persistence.logger.debug(`[gemini] Permission ${msg.approved ? "approved" : "denied"} for ${msg.toolName} (${msg.id})`);
2656
+ logger.logger.debug(`[gemini] Permission ${msg.approved ? "approved" : "denied"} for ${msg.toolName} (${msg.id})`);
2640
2657
  break;
2641
2658
  case "exec-approval-request":
2642
2659
  const execApprovalMsg = msg;
2643
2660
  const callId = execApprovalMsg.call_id || execApprovalMsg.callId || node_crypto.randomUUID();
2644
2661
  const { call_id, type, ...inputs } = execApprovalMsg;
2645
- persistence.logger.debug(`[gemini] Exec approval request received: ${callId}`);
2662
+ logger.logger.debug(`[gemini] Exec approval request received: ${callId}`);
2646
2663
  messageBuffer.addMessage(`Exec approval requested: ${callId}`, "tool");
2647
2664
  session.sendAgentMessage("gemini", {
2648
2665
  type: "tool-call",
@@ -2660,7 +2677,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2660
2677
  const changeCount = changes ? Object.keys(changes).length : 0;
2661
2678
  const filesMsg = changeCount === 1 ? "1 file" : `${changeCount} files`;
2662
2679
  messageBuffer.addMessage(`Modifying ${filesMsg}...`, "tool");
2663
- persistence.logger.debug(`[gemini] Patch apply begin: ${patchCallId}, files: ${changeCount}`);
2680
+ logger.logger.debug(`[gemini] Patch apply begin: ${patchCallId}, files: ${changeCount}`);
2664
2681
  const trimmedChanges = {};
2665
2682
  if (changes && typeof changes === "object") {
2666
2683
  for (const [filePath, change] of Object.entries(changes)) {
@@ -2693,7 +2710,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2693
2710
  const errorMsg = stderr || "Failed to modify files";
2694
2711
  messageBuffer.addMessage(`Error: ${errorMsg.substring(0, 200)}`, "result");
2695
2712
  }
2696
- persistence.logger.debug(`[gemini] Patch apply end: ${patchEndCallId}, success: ${success}`);
2713
+ logger.logger.debug(`[gemini] Patch apply end: ${patchEndCallId}, success: ${success}`);
2697
2714
  session.sendAgentMessage("gemini", {
2698
2715
  type: "tool-result",
2699
2716
  callId: patchEndCallId,
@@ -2714,7 +2731,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2714
2731
  const thinkingText = thinkingPayload && typeof thinkingPayload === "object" && "text" in thinkingPayload ? String(thinkingPayload.text || "") : "";
2715
2732
  if (thinkingText) {
2716
2733
  reasoningProcessor.processChunk(thinkingText);
2717
- persistence.logger.debug(`[gemini] \u{1F4AD} Thinking chunk received: ${thinkingText.length} chars - Preview: ${thinkingText.substring(0, 100)}...`);
2734
+ logger.logger.debug(`[gemini] \u{1F4AD} Thinking chunk received: ${thinkingText.length} chars - Preview: ${thinkingText.substring(0, 100)}...`);
2718
2735
  if (!thinkingText.startsWith("**")) {
2719
2736
  const thinkingPreview = thinkingText.substring(0, 100);
2720
2737
  messageBuffer.updateLastMessage(`[Thinking] ${thinkingPreview}...`, "system");
@@ -2733,14 +2750,14 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2733
2750
  let resumeContextPrefix = "";
2734
2751
  if (geminiResumeSessionId) {
2735
2752
  try {
2736
- const resumeLines = await persistence.readGeminiSessionLog(geminiResumeSessionId);
2753
+ const resumeLines = await api.readGeminiSessionLog(geminiResumeSessionId);
2737
2754
  if (resumeLines.length > 0) {
2738
- resumeContextPrefix = persistence.buildResumeContextFromSessionLog(resumeLines);
2739
- persistence.logger.debug(`[gemini] Loaded resume context from session ${geminiResumeSessionId} (${resumeContextPrefix.length} chars)`);
2755
+ resumeContextPrefix = api.buildResumeContextFromSessionLog(resumeLines);
2756
+ logger.logger.debug(`[gemini] Loaded resume context from session ${geminiResumeSessionId} (${resumeContextPrefix.length} chars)`);
2740
2757
  messageBuffer.addMessage("Resuming from previous session...", "status");
2741
2758
  }
2742
2759
  } catch (error) {
2743
- persistence.logger.debug(`[gemini] Failed to load resume session:`, error);
2760
+ logger.logger.debug(`[gemini] Failed to load resume session:`, error);
2744
2761
  }
2745
2762
  }
2746
2763
  if (geminiResumeSessionId && ["1", "true", "yes"].includes(String(process.env.HAPPY_GEMINI_BACKFILL).toLowerCase())) {
@@ -2756,10 +2773,10 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2756
2773
  }
2757
2774
  });
2758
2775
  } else {
2759
- persistence.logger.debug("[gemini] Backfill skipped: socket not connected");
2776
+ logger.logger.debug("[gemini] Backfill skipped: socket not connected");
2760
2777
  }
2761
2778
  } catch (error) {
2762
- persistence.logger.debug("[gemini] Backfill failed:", error);
2779
+ logger.logger.debug("[gemini] Backfill failed:", error);
2763
2780
  }
2764
2781
  }
2765
2782
  let first = true;
@@ -2770,25 +2787,25 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2770
2787
  let message = pending;
2771
2788
  pending = null;
2772
2789
  if (!message) {
2773
- persistence.logger.debug("[gemini] Main loop: waiting for messages from queue...");
2790
+ logger.logger.debug("[gemini] Main loop: waiting for messages from queue...");
2774
2791
  const waitSignal = abortController.signal;
2775
2792
  const batch = await messageQueue.waitForMessagesAndGetAsString(waitSignal);
2776
2793
  if (!batch) {
2777
2794
  if (waitSignal.aborted && !shouldExit) {
2778
- persistence.logger.debug("[gemini] Main loop: wait aborted, continuing...");
2795
+ logger.logger.debug("[gemini] Main loop: wait aborted, continuing...");
2779
2796
  continue;
2780
2797
  }
2781
- persistence.logger.debug("[gemini] Main loop: no batch received, breaking...");
2798
+ logger.logger.debug("[gemini] Main loop: no batch received, breaking...");
2782
2799
  break;
2783
2800
  }
2784
- persistence.logger.debug(`[gemini] Main loop: received message from queue (length: ${batch.message.length})`);
2801
+ logger.logger.debug(`[gemini] Main loop: received message from queue (length: ${batch.message.length})`);
2785
2802
  message = batch;
2786
2803
  }
2787
2804
  if (!message) {
2788
2805
  break;
2789
2806
  }
2790
- if (index.parseClear(message.message).isClear) {
2791
- persistence.logger.debug("[Gemini] /clear command detected - resetting session");
2807
+ if (downloadImage.parseClear(message.message).isClear) {
2808
+ logger.logger.debug("[Gemini] /clear command detected - resetting session");
2792
2809
  messageBuffer.addMessage("Context was reset", "status");
2793
2810
  session.sendSessionEvent({ type: "message", message: "Context was reset" });
2794
2811
  if (geminiBackend) {
@@ -2807,12 +2824,12 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2807
2824
  }
2808
2825
  let injectHistoryContext = false;
2809
2826
  if (wasSessionCreated && currentModeHash && message.hash !== currentModeHash) {
2810
- persistence.logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
2827
+ logger.logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
2811
2828
  messageBuffer.addMessage("\u2550".repeat(40), "status");
2812
2829
  if (conversationHistory.hasHistory()) {
2813
2830
  messageBuffer.addMessage(`Switching model (preserving ${conversationHistory.size()} messages of context)...`, "status");
2814
2831
  injectHistoryContext = true;
2815
- persistence.logger.debug(`[Gemini] Will inject conversation history: ${conversationHistory.getSummary()}`);
2832
+ logger.logger.debug(`[Gemini] Will inject conversation history: ${conversationHistory.getSummary()}`);
2816
2833
  } else {
2817
2834
  messageBuffer.addMessage("Starting new Gemini session (mode changed)...", "status");
2818
2835
  }
@@ -2837,13 +2854,13 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2837
2854
  geminiBackend = backendResult.backend;
2838
2855
  setupGeminiMessageHandler(geminiBackend);
2839
2856
  const actualModel = backendResult.model;
2840
- persistence.logger.debug(`[gemini] Model change - modelToUse=${modelToUse}, actualModel=${actualModel} (from ${backendResult.modelSource})`);
2857
+ logger.logger.debug(`[gemini] Model change - modelToUse=${modelToUse}, actualModel=${actualModel} (from ${backendResult.modelSource})`);
2841
2858
  conversationHistory.setCurrentModel(actualModel);
2842
- persistence.logger.debug("[gemini] Starting new ACP session with model:", actualModel);
2859
+ logger.logger.debug("[gemini] Starting new ACP session with model:", actualModel);
2843
2860
  const { sessionId } = await geminiBackend.startSession();
2844
2861
  acpSessionId = sessionId;
2845
- persistence.logger.debug(`[gemini] New ACP session started: ${acpSessionId}`);
2846
- persistence.logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
2862
+ logger.logger.debug(`[gemini] New ACP session started: ${acpSessionId}`);
2863
+ logger.logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
2847
2864
  updateDisplayedModel(actualModel, false);
2848
2865
  updatePermissionMode(message.mode.permissionMode);
2849
2866
  wasSessionCreated = true;
@@ -2874,20 +2891,20 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2874
2891
  geminiBackend = backendResult.backend;
2875
2892
  setupGeminiMessageHandler(geminiBackend);
2876
2893
  const actualModel = backendResult.model;
2877
- persistence.logger.debug(`[gemini] Backend created, model will be: ${actualModel} (from ${backendResult.modelSource})`);
2878
- persistence.logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
2894
+ logger.logger.debug(`[gemini] Backend created, model will be: ${actualModel} (from ${backendResult.modelSource})`);
2895
+ logger.logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
2879
2896
  updateDisplayedModel(actualModel, false);
2880
2897
  conversationHistory.setCurrentModel(actualModel);
2881
2898
  }
2882
2899
  if (!acpSessionId) {
2883
- persistence.logger.debug("[gemini] Starting ACP session...");
2900
+ logger.logger.debug("[gemini] Starting ACP session...");
2884
2901
  updatePermissionMode(message.mode.permissionMode);
2885
2902
  const { sessionId } = await geminiBackend.startSession();
2886
2903
  acpSessionId = sessionId;
2887
- persistence.logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
2904
+ logger.logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
2888
2905
  wasSessionCreated = true;
2889
2906
  currentModeHash = message.hash;
2890
- persistence.logger.debug(`[gemini] Displaying model in UI: ${displayedModel || "gemini-2.5-pro"}, displayedModel: ${displayedModel}`);
2907
+ logger.logger.debug(`[gemini] Displaying model in UI: ${displayedModel || "gemini-2.5-pro"}, displayedModel: ${displayedModel}`);
2891
2908
  }
2892
2909
  }
2893
2910
  if (!acpSessionId) {
@@ -2908,26 +2925,26 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2908
2925
  if (first && resumeContextPrefix) {
2909
2926
  promptToSend = resumeContextPrefix + promptToSend;
2910
2927
  resumeContextPrefix = "";
2911
- persistence.logger.debug(`[gemini] Injected resume context into first prompt`);
2928
+ logger.logger.debug(`[gemini] Injected resume context into first prompt`);
2912
2929
  }
2913
2930
  if (injectHistoryContext && conversationHistory.hasHistory()) {
2914
2931
  const historyContext = conversationHistory.getContextForNewSession();
2915
2932
  promptToSend = historyContext + promptToSend;
2916
- persistence.logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
2933
+ logger.logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
2917
2934
  }
2918
- persistence.logger.debug(`[gemini] Sending prompt to Gemini (length: ${promptToSend.length}): ${promptToSend.substring(0, 100)}...`);
2919
- persistence.logger.debug(`[gemini] Full prompt: ${promptToSend}`);
2935
+ logger.logger.debug(`[gemini] Sending prompt to Gemini (length: ${promptToSend.length}): ${promptToSend.substring(0, 100)}...`);
2936
+ logger.logger.debug(`[gemini] Full prompt: ${promptToSend}`);
2920
2937
  let promptImages;
2921
2938
  if (message.mode.images && message.mode.images.length > 0) {
2922
- persistence.logger.debug(`[gemini] Downloading ${message.mode.images.length} image(s) for prompt`);
2923
- const formattedContent = await index.formatMessageForGemini(promptToSend, message.mode.images);
2939
+ logger.logger.debug(`[gemini] Downloading ${message.mode.images.length} image(s) for prompt`);
2940
+ const formattedContent = await formatImageMessage.formatMessageForGemini(promptToSend, message.mode.images);
2924
2941
  promptImages = formattedContent.parts.filter(
2925
2942
  (part) => "inlineData" in part && part.inlineData !== void 0
2926
2943
  ).map((part) => ({
2927
2944
  data: part.inlineData.data,
2928
2945
  mimeType: part.inlineData.mimeType
2929
2946
  }));
2930
- persistence.logger.debug(`[gemini] Prepared ${promptImages.length} image(s) for ACP prompt`);
2947
+ logger.logger.debug(`[gemini] Prepared ${promptImages.length} image(s) for ACP prompt`);
2931
2948
  }
2932
2949
  const MAX_RETRIES = 3;
2933
2950
  const RETRY_DELAY_MS = 2e3;
@@ -2935,10 +2952,10 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2935
2952
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
2936
2953
  try {
2937
2954
  await geminiBackend.sendPrompt(acpSessionId, promptToSend, { images: promptImages });
2938
- persistence.logger.debug("[gemini] Prompt sent successfully");
2955
+ logger.logger.debug("[gemini] Prompt sent successfully");
2939
2956
  if (geminiBackend.waitForResponseComplete) {
2940
2957
  await geminiBackend.waitForResponseComplete(12e4);
2941
- persistence.logger.debug("[gemini] Response complete");
2958
+ logger.logger.debug("[gemini] Response complete");
2942
2959
  }
2943
2960
  break;
2944
2961
  } catch (promptError) {
@@ -2963,7 +2980,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2963
2980
  const isInternalError = errorCode === -32603;
2964
2981
  const isRetryable = isEmptyResponseError || isInternalError;
2965
2982
  if (isRetryable && attempt < MAX_RETRIES) {
2966
- persistence.logger.debug(`[gemini] Retryable error on attempt ${attempt}/${MAX_RETRIES}: ${errorDetails}`);
2983
+ logger.logger.debug(`[gemini] Retryable error on attempt ${attempt}/${MAX_RETRIES}: ${errorDetails}`);
2967
2984
  messageBuffer.addMessage(`Gemini returned empty response, retrying (${attempt}/${MAX_RETRIES})...`, "status");
2968
2985
  await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt));
2969
2986
  continue;
@@ -2972,13 +2989,13 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
2972
2989
  }
2973
2990
  }
2974
2991
  if (lastError && MAX_RETRIES > 1) {
2975
- persistence.logger.debug("[gemini] Prompt succeeded after retries");
2992
+ logger.logger.debug("[gemini] Prompt succeeded after retries");
2976
2993
  }
2977
2994
  if (first) {
2978
2995
  first = false;
2979
2996
  }
2980
2997
  } catch (error) {
2981
- persistence.logger.debug("[gemini] Error in gemini session:", error);
2998
+ logger.logger.debug("[gemini] Error in gemini session:", error);
2982
2999
  const isAbortError = error instanceof Error && error.name === "AbortError";
2983
3000
  const isUserAbort = isAbortError || abortRequested;
2984
3001
  if (isUserAbort && !abortFeedbackSent) {
@@ -3042,9 +3059,9 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
3042
3059
  let finalMessageText = messageText;
3043
3060
  if (options.length > 0) {
3044
3061
  finalMessageText = messageText + rawOptionsXml;
3045
- persistence.logger.debug(`[gemini] Found ${options.length} options in response:`, options);
3062
+ logger.logger.debug(`[gemini] Found ${options.length} options in response:`, options);
3046
3063
  } else if (hasIncompleteOptions(accumulatedResponse)) {
3047
- persistence.logger.debug(`[gemini] Warning: Incomplete options block detected`);
3064
+ logger.logger.debug(`[gemini] Warning: Incomplete options block detected`);
3048
3065
  }
3049
3066
  const messagePayload = {
3050
3067
  type: "message",
@@ -3052,7 +3069,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
3052
3069
  id: node_crypto.randomUUID(),
3053
3070
  ...options.length > 0 && { options }
3054
3071
  };
3055
- persistence.logger.debug(`[gemini] Sending complete message to mobile (length: ${finalMessageText.length}): ${finalMessageText.substring(0, 100)}...`);
3072
+ logger.logger.debug(`[gemini] Sending complete message to mobile (length: ${finalMessageText.length}): ${finalMessageText.substring(0, 100)}...`);
3056
3073
  session.sendAgentMessage("gemini", messagePayload);
3057
3074
  accumulatedResponse = "";
3058
3075
  isResponseInProgress = false;
@@ -3083,13 +3100,13 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
3083
3100
  emitReadyIfIdle();
3084
3101
  isProcessingMessage = false;
3085
3102
  applyPendingSessionSwap();
3086
- persistence.logger.debug(`[gemini] Main loop: turn completed, continuing to next iteration (queue size: ${messageQueue.size()})`);
3103
+ logger.logger.debug(`[gemini] Main loop: turn completed, continuing to next iteration (queue size: ${messageQueue.size()})`);
3087
3104
  }
3088
3105
  }
3089
3106
  } finally {
3090
- persistence.logger.debug("[gemini]: Final cleanup start");
3107
+ logger.logger.debug("[gemini]: Final cleanup start");
3091
3108
  if (reconnectionHandle) {
3092
- persistence.logger.debug("[gemini]: Cancelling offline reconnection");
3109
+ logger.logger.debug("[gemini]: Cancelling offline reconnection");
3093
3110
  reconnectionHandle.cancel();
3094
3111
  }
3095
3112
  try {
@@ -3097,7 +3114,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
3097
3114
  await session.flush();
3098
3115
  await session.close();
3099
3116
  } catch (e) {
3100
- persistence.logger.debug("[gemini]: Error while closing session", e);
3117
+ logger.logger.debug("[gemini]: Error while closing session", e);
3101
3118
  }
3102
3119
  if (geminiBackend) {
3103
3120
  await geminiBackend.dispose();
@@ -3120,7 +3137,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
3120
3137
  inkInstance.unmount();
3121
3138
  }
3122
3139
  messageBuffer.clear();
3123
- persistence.logger.debug("[gemini]: Final cleanup completed");
3140
+ logger.logger.debug("[gemini]: Final cleanup completed");
3124
3141
  }
3125
3142
  }
3126
3143