@zonease/happy 0.6.37 → 0.6.39
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.
- package/dist/{types-DYCJXXdA.mjs → api-CIZKyfSn.mjs} +136 -1725
- package/dist/{types-BrTorNAy.cjs → api-CwOCQeLH.cjs} +317 -1961
- package/dist/auth-0VnlXT9f.mjs +181 -0
- package/dist/auth-BE8dD20T.mjs +270 -0
- package/dist/auth-BIleVCw0.cjs +274 -0
- package/dist/auth-Cas9DR3b.cjs +183 -0
- package/dist/browser-Cc08m7of.cjs +22 -0
- package/dist/browser-Dll5hxOV.mjs +20 -0
- package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
- package/dist/claudeLocal-WkgLbl1a.cjs +352 -0
- package/dist/codex/happyMcpStdioBridge.cjs +4 -1
- package/dist/codex/happyMcpStdioBridge.mjs +4 -1
- package/dist/common-BdNgghUJ.mjs +75 -0
- package/dist/common-CZvSRU4p.cjs +83 -0
- package/dist/{config-D_g6ohaV.cjs → config-Draa-5XC.cjs} +21 -34
- package/dist/{config-DPn-cbpz.mjs → config-rTT4qTU5.mjs} +7 -20
- package/dist/connect-BfC1tYP_.mjs +679 -0
- package/dist/connect-CJZ73syK.cjs +681 -0
- package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
- package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
- package/dist/controlClient-CM_QcJnB.mjs +159 -0
- package/dist/controlClient-DZMIsKsT.cjs +168 -0
- package/dist/deviceExec-CU1R9CRb.cjs +84 -0
- package/dist/deviceExec-D93AOVV4.mjs +81 -0
- package/dist/diagnose-B3D1a_v0.cjs +60 -0
- package/dist/diagnose-CuRKXxt1.mjs +58 -0
- package/dist/doctor-C08m5Z9f.cjs +78 -0
- package/dist/doctor-Cya9YSA0.cjs +214 -0
- package/dist/doctor-DZYB6IVc.mjs +211 -0
- package/dist/doctor-ON7pN5G5.mjs +74 -0
- package/dist/downloadImage-DfSFLb-h.mjs +887 -0
- package/dist/downloadImage-MQMrUUxS.cjs +897 -0
- package/dist/enroll-BxlbVftP.cjs +115 -0
- package/dist/enroll-C52x8oly.mjs +113 -0
- package/dist/evidence-Ccd9iYcj.mjs +127 -0
- package/dist/evidence-CjWBG5rX.cjs +129 -0
- package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
- package/dist/formatImageMessage-DbyG8c2j.cjs +46 -0
- package/dist/github-DKcyF1zp.mjs +57 -0
- package/dist/github-h9GhJJ_C.cjs +59 -0
- package/dist/index-CDTNgfUf.cjs +578 -0
- package/dist/index-CPKdvi7J.mjs +554 -0
- package/dist/index.cjs +812 -40
- package/dist/index.mjs +813 -40
- package/dist/install-BokHRgFW.cjs +98 -0
- package/dist/install-C_cp8b2-.cjs +96 -0
- package/dist/install-DAeCn8ae.mjs +94 -0
- package/dist/install-oRAjVLjP.mjs +95 -0
- package/dist/lib.cjs +18 -12
- package/dist/lib.d.cts +16 -16
- package/dist/lib.d.mts +16 -16
- package/dist/lib.mjs +13 -7
- package/dist/{loadableToolOutput-lQH8Kb_w.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
- package/dist/{loadableToolOutput-CasonFIt.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
- package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
- package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
- package/dist/persistence-BFjvtUad.mjs +944 -0
- package/dist/persistence-JLUn_Nou.cjs +996 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/prompt-BTWDZZO0.cjs +25 -0
- package/dist/prompt-BsAZsPbo.mjs +22 -0
- package/dist/release-BMEzNONE.mjs +168 -0
- package/dist/release-EhOJeAZe.cjs +171 -0
- package/dist/run-BDn2aE3Q.cjs +2152 -0
- package/dist/run-DBZqN6Kn.mjs +2128 -0
- package/dist/runClaude-DNHvERX0.mjs +3763 -0
- package/dist/runClaude-uaKxPZPm.cjs +3766 -0
- package/dist/{runCodex-BTt3fxG4.cjs → runCodex-82UrZLme.cjs} +169 -153
- package/dist/{runCodex-BXCB5trB.mjs → runCodex-C-RTM0wA.mjs} +36 -20
- package/dist/{runGemini-37HHbp9n.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
- package/dist/{runGemini-C-0nSFBv.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
- package/dist/{runOneShot-CXhbFJ2j.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
- package/dist/{runOneShot-USX8QPfE.mjs → runOneShot-ioARRHrx.mjs} +14 -38
- package/dist/{serve-DZAq-_1F.cjs → serve-BtdAhkIE.cjs} +35 -58
- package/dist/{serve-BRedJPzL.mjs → serve-CwibwU6N.mjs} +12 -35
- package/dist/session-2sU4Bu1R.mjs +108 -0
- package/dist/session-D--F87zL.cjs +110 -0
- package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
- package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
- package/dist/sessionList-BCSw3qYt.mjs +51 -0
- package/dist/sessionList-ICJsjNtJ.cjs +54 -0
- package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
- package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
- package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
- package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
- package/dist/ssh-BTOlhhxi.cjs +333 -0
- package/dist/ssh-DL_AkRAD.mjs +328 -0
- package/dist/systemdScope-BeOtAkhk.mjs +25 -0
- package/dist/systemdScope-DW3-UoKB.cjs +29 -0
- package/dist/task-CQzrHRZe.mjs +165 -0
- package/dist/task-CSpaC9HX.cjs +167 -0
- package/dist/time-Bj2HRkKH.cjs +33 -0
- package/dist/time-DgsBLJA_.mjs +29 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-BoJh4Qfv.mjs +57 -0
- package/dist/types-DWeB7aqh.cjs +59 -0
- package/dist/uninstall-BiKyRAb1.cjs +77 -0
- package/dist/uninstall-nFMFGUVM.mjs +75 -0
- package/dist/update-BcqRHXf2.mjs +109 -0
- package/dist/update-Dw8pgsAT.cjs +111 -0
- package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
- package/dist/workflowCommon-Bl568-rt.cjs +62 -0
- package/dist/workflowReports-BEWuQesA.cjs +113 -0
- package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
- package/package.json +1 -1
- package/dist/index-BlkHOkB3.cjs +0 -11312
- package/dist/index-DJ2VpGiR.mjs +0 -11272
- package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
- 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
|
|
7
|
-
var
|
|
8
|
-
var
|
|
6
|
+
var api = require('./api-CwOCQeLH.cjs');
|
|
7
|
+
var logger = require('./persistence-JLUn_Nou.cjs');
|
|
8
|
+
var loadableToolOutput = require('./loadableToolOutput-DDCJjywt.cjs');
|
|
9
|
+
var run = require('./run-BDn2aE3Q.cjs');
|
|
10
|
+
var downloadImage = require('./downloadImage-MQMrUUxS.cjs');
|
|
11
|
+
var controlClient = require('./controlClient-DZMIsKsT.cjs');
|
|
9
12
|
var node_child_process = require('node:child_process');
|
|
10
13
|
var sdk = require('@agentclientprotocol/sdk');
|
|
11
|
-
var
|
|
12
|
-
var
|
|
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-Draa-5XC.cjs');
|
|
18
|
+
var formatImageMessage = require('./formatImageMessage-DbyG8c2j.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('
|
|
23
|
-
require('
|
|
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('./
|
|
38
|
-
require('
|
|
39
|
-
require('
|
|
40
|
-
require('cross-spawn');
|
|
41
|
+
require('./sessionKeyCache-4Tp8pJ3N.cjs');
|
|
42
|
+
require('chalk');
|
|
43
|
+
require('fs');
|
|
41
44
|
require('os');
|
|
42
45
|
require('tmp');
|
|
46
|
+
require('./auth-BIleVCw0.cjs');
|
|
43
47
|
require('qrcode-terminal');
|
|
48
|
+
require('./browser-Cc08m7of.cjs');
|
|
44
49
|
require('open');
|
|
50
|
+
require('./doctor-Cya9YSA0.cjs');
|
|
51
|
+
require('./doctor-C08m5Z9f.cjs');
|
|
52
|
+
require('ps-list');
|
|
53
|
+
require('cross-spawn');
|
|
54
|
+
require('./spawnHappyCLI-D_V-AAoP.cjs');
|
|
55
|
+
require('./install-BokHRgFW.cjs');
|
|
56
|
+
require('./trimIdent-4gvk9Wk6.cjs');
|
|
45
57
|
require('fastify');
|
|
46
58
|
require('fastify-type-provider-zod');
|
|
59
|
+
require('./common-CZvSRU4p.cjs');
|
|
47
60
|
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
48
61
|
require('node:http');
|
|
49
62
|
require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
50
63
|
require('@modelcontextprotocol/sdk/types.js');
|
|
51
|
-
require('
|
|
64
|
+
require('./deviceExec-CU1R9CRb.cjs');
|
|
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: ${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
548
|
+
logger.logger.debug(`[AcpBackend] \u{1F50D} Agent stderr (during investigation): ${text.trim()}`);
|
|
532
549
|
} else {
|
|
533
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
665
|
-
|
|
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
|
-
|
|
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:
|
|
777
|
+
version: logger.packageJson.version
|
|
761
778
|
}
|
|
762
779
|
};
|
|
763
780
|
const initTimeout = this.transport.getInitTimeout();
|
|
764
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1062
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1099
|
+
logger.logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2).substring(0, 1e3));
|
|
1083
1100
|
await this.connection.prompt(promptRequest);
|
|
1084
|
-
|
|
1101
|
+
logger.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
|
|
1085
1102
|
} catch (error) {
|
|
1086
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1246
|
+
logger.logger.debug("[AcpBackend] Error cancelling:", error);
|
|
1230
1247
|
}
|
|
1231
1248
|
this.waitingForResponse = false;
|
|
1232
1249
|
if (this.idleResolver) {
|
|
1233
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1337
|
+
logger.logger.debug(`[Gemini] Using Google Cloud Project: ${googleCloudProject}${storedEmail ? ` (for ${storedEmail})` : " (global)"}`);
|
|
1321
1338
|
} else {
|
|
1322
|
-
|
|
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
|
-
|
|
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)),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2050
|
+
const allLines = await api.readGeminiSessionLog(opts.sessionId);
|
|
2034
2051
|
const conversationLines = allLines.filter(isConversationLine);
|
|
2035
2052
|
if (conversationLines.length === 0) {
|
|
2036
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2079
|
-
const api = await
|
|
2080
|
-
const settings = await
|
|
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
|
-
|
|
2087
|
-
await api.getOrCreateMachine({
|
|
2103
|
+
logger.logger.debug(`Using machineId: ${machineId}`);
|
|
2104
|
+
await api$1.getOrCreateMachine({
|
|
2088
2105
|
machineId,
|
|
2089
|
-
metadata:
|
|
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
|
-
|
|
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
|
-
|
|
2122
|
+
logger.logger.debug(`[Gemini] Current user email: ${currentUserEmail}`);
|
|
2106
2123
|
}
|
|
2107
2124
|
}
|
|
2108
2125
|
} catch {
|
|
2109
|
-
|
|
2126
|
+
logger.logger.debug("[Gemini] Failed to decode id_token for email");
|
|
2110
2127
|
}
|
|
2111
2128
|
}
|
|
2112
2129
|
}
|
|
2113
2130
|
} catch (error) {
|
|
2114
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2170
|
-
const result = await
|
|
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
|
-
|
|
2189
|
+
logger.logger.debug(`[START] Failed to report to daemon (may not be running):`, result.error);
|
|
2173
2190
|
} else {
|
|
2174
|
-
|
|
2191
|
+
logger.logger.debug(`[START] Reported session ${response.id} to daemon`);
|
|
2175
2192
|
}
|
|
2176
2193
|
} catch (error) {
|
|
2177
|
-
|
|
2194
|
+
logger.logger.debug("[START] Failed to report to daemon (may not be running):", error);
|
|
2178
2195
|
}
|
|
2179
2196
|
}
|
|
2180
|
-
const messageQueue = new
|
|
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
|
-
|
|
2238
|
+
logger.logger.debug(`[Gemini] Permission mode updated from user message to: ${currentPermissionMode}`);
|
|
2222
2239
|
} else {
|
|
2223
|
-
|
|
2240
|
+
logger.logger.debug(`[Gemini] Invalid permission mode received: ${message.meta.permissionMode}`);
|
|
2224
2241
|
}
|
|
2225
2242
|
} else {
|
|
2226
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2361
|
+
logger.logger.debug("[Gemini] Abort completed - session remains active");
|
|
2345
2362
|
} catch (error) {
|
|
2346
|
-
|
|
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
|
-
|
|
2369
|
+
logger.logger.debug("[Gemini] Kill session requested - terminating process");
|
|
2353
2370
|
await handleAbort();
|
|
2354
|
-
|
|
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
|
-
|
|
2385
|
+
run.stopCaffeinate();
|
|
2369
2386
|
mcp.stop();
|
|
2370
2387
|
if (geminiBackend) {
|
|
2371
2388
|
await geminiBackend.dispose();
|
|
2372
2389
|
}
|
|
2373
|
-
|
|
2390
|
+
logger.logger.debug("[Gemini] Session termination complete, exiting");
|
|
2374
2391
|
process.exit(0);
|
|
2375
2392
|
} catch (error) {
|
|
2376
|
-
|
|
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
|
-
|
|
2382
|
-
const messageBuffer = new
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
2430
|
+
logPath: logger.isDebug() ? logger.logger.getLogPath() : void 0,
|
|
2414
2431
|
currentModel: currentModelValue,
|
|
2415
2432
|
onExit: async () => {
|
|
2416
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2507
|
+
logger.logger.debug(`[gemini] Status changed: ${msg.status}${statusDetail ? ` - ${statusDetail}` : ""}`);
|
|
2491
2508
|
if (msg.status === "error") {
|
|
2492
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2753
|
+
const resumeLines = await api.readGeminiSessionLog(geminiResumeSessionId);
|
|
2737
2754
|
if (resumeLines.length > 0) {
|
|
2738
|
-
resumeContextPrefix =
|
|
2739
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2776
|
+
logger.logger.debug("[gemini] Backfill skipped: socket not connected");
|
|
2760
2777
|
}
|
|
2761
2778
|
} catch (error) {
|
|
2762
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2795
|
+
logger.logger.debug("[gemini] Main loop: wait aborted, continuing...");
|
|
2779
2796
|
continue;
|
|
2780
2797
|
}
|
|
2781
|
-
|
|
2798
|
+
logger.logger.debug("[gemini] Main loop: no batch received, breaking...");
|
|
2782
2799
|
break;
|
|
2783
2800
|
}
|
|
2784
|
-
|
|
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 (
|
|
2791
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2857
|
+
logger.logger.debug(`[gemini] Model change - modelToUse=${modelToUse}, actualModel=${actualModel} (from ${backendResult.modelSource})`);
|
|
2841
2858
|
conversationHistory.setCurrentModel(actualModel);
|
|
2842
|
-
|
|
2859
|
+
logger.logger.debug("[gemini] Starting new ACP session with model:", actualModel);
|
|
2843
2860
|
const { sessionId } = await geminiBackend.startSession();
|
|
2844
2861
|
acpSessionId = sessionId;
|
|
2845
|
-
|
|
2846
|
-
|
|
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
|
-
|
|
2878
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2904
|
+
logger.logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
|
|
2888
2905
|
wasSessionCreated = true;
|
|
2889
2906
|
currentModeHash = message.hash;
|
|
2890
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2933
|
+
logger.logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
|
|
2917
2934
|
}
|
|
2918
|
-
|
|
2919
|
-
|
|
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
|
-
|
|
2923
|
-
const formattedContent = await
|
|
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
|
-
|
|
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
|
-
|
|
2955
|
+
logger.logger.debug("[gemini] Prompt sent successfully");
|
|
2939
2956
|
if (geminiBackend.waitForResponseComplete) {
|
|
2940
2957
|
await geminiBackend.waitForResponseComplete(12e4);
|
|
2941
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3062
|
+
logger.logger.debug(`[gemini] Found ${options.length} options in response:`, options);
|
|
3046
3063
|
} else if (hasIncompleteOptions(accumulatedResponse)) {
|
|
3047
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3107
|
+
logger.logger.debug("[gemini]: Final cleanup start");
|
|
3091
3108
|
if (reconnectionHandle) {
|
|
3092
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3140
|
+
logger.logger.debug("[gemini]: Final cleanup completed");
|
|
3124
3141
|
}
|
|
3125
3142
|
}
|
|
3126
3143
|
|