happy-imou-cloud 2.0.6 → 2.0.8
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/bin/happy-cloud.mjs +1 -1
- package/dist/{api-DccDghmF.cjs → api-CN-WqYd_.cjs} +3 -4
- package/dist/{api-Emo3rSZH.mjs → api-D-uiH_TF.mjs} +3 -4
- package/dist/{command-D8Zz6B4t.mjs → command-DGFsZx58.mjs} +3 -3
- package/dist/{command-C2v0VkPq.cjs → command-DjIfRZQS.cjs} +3 -3
- package/dist/{index-Buq7nurH.cjs → index-DM6z3aeG.cjs} +189 -27
- package/dist/{index-Dh8UTgm4.mjs → index-DhheEtRl.mjs} +187 -25
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{BaseReasoningProcessor-1EzrE03x.mjs → names-BjEof0E2.mjs} +98 -3
- package/dist/{BaseReasoningProcessor-BMyfwx3p.cjs → names-BnV67N_O.cjs} +100 -2
- package/dist/{persistence-BrTyBuT7.cjs → persistence-DBGkO8gB.cjs} +110 -1
- package/dist/{persistence-Blm1hTQA.mjs → persistence-DiNg1DPF.mjs} +100 -4
- package/dist/{registerKillSessionHandler-EFAsOnR_.cjs → registerKillSessionHandler-CYc0SIjF.cjs} +26 -2
- package/dist/{registerKillSessionHandler-Bm7E-03E.mjs → registerKillSessionHandler-Cu9rHGsI.mjs} +26 -2
- package/dist/{runClaude-COy1pLhn.cjs → runClaude-CPhWaFrX.cjs} +5 -5
- package/dist/{runClaude-CwA5UCO-.mjs → runClaude-DAR_hw3C.mjs} +4 -4
- package/dist/{runCodex-BRMOT2dJ.cjs → runCodex--QLrOs8X.cjs} +53 -82
- package/dist/{runCodex-DTPmqCyS.mjs → runCodex-B4QAb-Go.mjs} +35 -63
- package/dist/{runGemini-BVPmTGxQ.cjs → runGemini-CDyhCucw.cjs} +20 -21
- package/dist/{runGemini-DDSR8BtO.mjs → runGemini-DqowSR2w.mjs} +5 -6
- package/package.json +3 -4
- package/scripts/build.mjs +66 -0
- package/scripts/release-smoke.mjs +166 -30
package/bin/happy-cloud.mjs
CHANGED
|
@@ -19,7 +19,7 @@ var path = require('path');
|
|
|
19
19
|
var expoServerSdk = require('expo-server-sdk');
|
|
20
20
|
|
|
21
21
|
var name = "happy-imou-cloud";
|
|
22
|
-
var version = "2.0.
|
|
22
|
+
var version = "2.0.8";
|
|
23
23
|
var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
|
|
24
24
|
var author = "long.zhu";
|
|
25
25
|
var license = "MIT";
|
|
@@ -62,7 +62,7 @@ var scripts = {
|
|
|
62
62
|
"// ==== TypeScript & Build ====": "",
|
|
63
63
|
"why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
|
|
64
64
|
typecheck: "tsc --noEmit",
|
|
65
|
-
build: "
|
|
65
|
+
build: "node ./scripts/build.mjs",
|
|
66
66
|
"// ==== Testing ====": "",
|
|
67
67
|
test: "yarn build && vitest run",
|
|
68
68
|
"test:integration": "yarn build && vitest run --config vitest.integration.config.ts",
|
|
@@ -118,7 +118,6 @@ var dependencies = {
|
|
|
118
118
|
"expo-server-sdk": "^3.15.0",
|
|
119
119
|
fastify: "^5.6.2",
|
|
120
120
|
"fastify-type-provider-zod": "4.0.2",
|
|
121
|
-
"happy-protocol": "0.1.0",
|
|
122
121
|
"http-proxy": "^1.18.1",
|
|
123
122
|
"http-proxy-middleware": "^3.0.5",
|
|
124
123
|
ink: "^6.5.1",
|
|
@@ -433,7 +432,7 @@ async function listDaemonLogFiles(limit = 50) {
|
|
|
433
432
|
return { file, path: fullPath, modified: stats.mtime };
|
|
434
433
|
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
435
434
|
try {
|
|
436
|
-
const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-
|
|
435
|
+
const { readDaemonState } = await Promise.resolve().then(function () { return require('./persistence-DBGkO8gB.cjs'); });
|
|
437
436
|
const state = await readDaemonState();
|
|
438
437
|
if (!state) {
|
|
439
438
|
return logs;
|
|
@@ -17,7 +17,7 @@ import { resolve, join as join$1 } from 'path';
|
|
|
17
17
|
import { Expo } from 'expo-server-sdk';
|
|
18
18
|
|
|
19
19
|
var name = "happy-imou-cloud";
|
|
20
|
-
var version = "2.0.
|
|
20
|
+
var version = "2.0.8";
|
|
21
21
|
var description = "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI";
|
|
22
22
|
var author = "long.zhu";
|
|
23
23
|
var license = "MIT";
|
|
@@ -60,7 +60,7 @@ var scripts = {
|
|
|
60
60
|
"// ==== TypeScript & Build ====": "",
|
|
61
61
|
"why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
|
|
62
62
|
typecheck: "tsc --noEmit",
|
|
63
|
-
build: "
|
|
63
|
+
build: "node ./scripts/build.mjs",
|
|
64
64
|
"// ==== Testing ====": "",
|
|
65
65
|
test: "yarn build && vitest run",
|
|
66
66
|
"test:integration": "yarn build && vitest run --config vitest.integration.config.ts",
|
|
@@ -116,7 +116,6 @@ var dependencies = {
|
|
|
116
116
|
"expo-server-sdk": "^3.15.0",
|
|
117
117
|
fastify: "^5.6.2",
|
|
118
118
|
"fastify-type-provider-zod": "4.0.2",
|
|
119
|
-
"happy-protocol": "0.1.0",
|
|
120
119
|
"http-proxy": "^1.18.1",
|
|
121
120
|
"http-proxy-middleware": "^3.0.5",
|
|
122
121
|
ink: "^6.5.1",
|
|
@@ -431,7 +430,7 @@ async function listDaemonLogFiles(limit = 50) {
|
|
|
431
430
|
return { file, path: fullPath, modified: stats.mtime };
|
|
432
431
|
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
433
432
|
try {
|
|
434
|
-
const { readDaemonState } = await import('./persistence-
|
|
433
|
+
const { readDaemonState } = await import('./persistence-DiNg1DPF.mjs');
|
|
435
434
|
const state = await readDaemonState();
|
|
436
435
|
if (!state) {
|
|
437
436
|
return logs;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { c as createDefaultRuntimeShell } from './index-
|
|
1
|
+
import { c as createDefaultRuntimeShell } from './index-DhheEtRl.mjs';
|
|
2
2
|
import 'chalk';
|
|
3
|
-
import './api-
|
|
3
|
+
import './api-D-uiH_TF.mjs';
|
|
4
4
|
import 'axios';
|
|
5
5
|
import 'fs';
|
|
6
6
|
import 'node:fs';
|
|
@@ -17,7 +17,7 @@ import 'fs/promises';
|
|
|
17
17
|
import 'crypto';
|
|
18
18
|
import 'path';
|
|
19
19
|
import 'expo-server-sdk';
|
|
20
|
-
import './persistence-
|
|
20
|
+
import './persistence-DiNg1DPF.mjs';
|
|
21
21
|
import 'node:fs/promises';
|
|
22
22
|
import 'os';
|
|
23
23
|
import 'tmp';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-DM6z3aeG.cjs');
|
|
4
4
|
require('chalk');
|
|
5
|
-
require('./api-
|
|
5
|
+
require('./api-CN-WqYd_.cjs');
|
|
6
6
|
require('axios');
|
|
7
7
|
require('fs');
|
|
8
8
|
require('node:fs');
|
|
@@ -19,7 +19,7 @@ require('fs/promises');
|
|
|
19
19
|
require('crypto');
|
|
20
20
|
require('path');
|
|
21
21
|
require('expo-server-sdk');
|
|
22
|
-
require('./persistence-
|
|
22
|
+
require('./persistence-DBGkO8gB.cjs');
|
|
23
23
|
require('node:fs/promises');
|
|
24
24
|
require('os');
|
|
25
25
|
require('tmp');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var api = require('./api-
|
|
5
|
-
var persistence = require('./persistence-
|
|
4
|
+
var api = require('./api-CN-WqYd_.cjs');
|
|
5
|
+
var persistence = require('./persistence-DBGkO8gB.cjs');
|
|
6
6
|
var z = require('zod');
|
|
7
7
|
var fs$1 = require('fs/promises');
|
|
8
8
|
var os$1 = require('os');
|
|
@@ -70,7 +70,7 @@ async function openBrowser(url) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
73
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DM6z3aeG.cjs', document.baseURI).href)));
|
|
74
74
|
const QRCode = require$1("qrcode-terminal/vendor/QRCode");
|
|
75
75
|
const QRErrorCorrectLevel = require$1("qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel");
|
|
76
76
|
const pendingTempFiles = /* @__PURE__ */ new Set();
|
|
@@ -693,7 +693,7 @@ function setupCleanupHandlers() {
|
|
|
693
693
|
});
|
|
694
694
|
}
|
|
695
695
|
|
|
696
|
-
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
696
|
+
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DM6z3aeG.cjs', document.baseURI).href))));
|
|
697
697
|
function projectPath() {
|
|
698
698
|
const path$1 = path.resolve(__dirname$1, "..");
|
|
699
699
|
return path$1;
|
|
@@ -4213,6 +4213,9 @@ class DefaultTransport {
|
|
|
4213
4213
|
getInitTimeout() {
|
|
4214
4214
|
return DEFAULT_TIMEOUTS.init;
|
|
4215
4215
|
}
|
|
4216
|
+
getInitDelayMs() {
|
|
4217
|
+
return 0;
|
|
4218
|
+
}
|
|
4216
4219
|
/**
|
|
4217
4220
|
* Default: pass through all lines that are valid JSON objects/arrays
|
|
4218
4221
|
*/
|
|
@@ -4273,11 +4276,16 @@ class DefaultTransport {
|
|
|
4273
4276
|
determineToolName(toolName, _toolCallId, _input, _context) {
|
|
4274
4277
|
return toolName;
|
|
4275
4278
|
}
|
|
4279
|
+
getPostPromptNoUpdatesTimeoutMs() {
|
|
4280
|
+
return 3e4;
|
|
4281
|
+
}
|
|
4276
4282
|
}
|
|
4277
4283
|
|
|
4278
4284
|
const GEMINI_TIMEOUTS = {
|
|
4279
4285
|
/** Gemini CLI can be slow on first start (downloading models, etc.) */
|
|
4280
4286
|
init: 12e4,
|
|
4287
|
+
/** Gemini ACP can swallow an initialize request sent too early after spawn */
|
|
4288
|
+
initDelay: 2500,
|
|
4281
4289
|
/** Standard tool call timeout */
|
|
4282
4290
|
toolCall: 12e4,
|
|
4283
4291
|
/** Investigation tools (codebase_investigator) can run for a long time */
|
|
@@ -4312,6 +4320,9 @@ class GeminiTransport {
|
|
|
4312
4320
|
getInitTimeout() {
|
|
4313
4321
|
return GEMINI_TIMEOUTS.init;
|
|
4314
4322
|
}
|
|
4323
|
+
getInitDelayMs() {
|
|
4324
|
+
return GEMINI_TIMEOUTS.initDelay;
|
|
4325
|
+
}
|
|
4315
4326
|
/**
|
|
4316
4327
|
* Filter Gemini CLI debug output from stdout.
|
|
4317
4328
|
*
|
|
@@ -5048,6 +5059,10 @@ ${line}` : line;
|
|
|
5048
5059
|
controller.error(error);
|
|
5049
5060
|
} finally {
|
|
5050
5061
|
reader.releaseLock();
|
|
5062
|
+
try {
|
|
5063
|
+
params.onDone?.();
|
|
5064
|
+
} catch {
|
|
5065
|
+
}
|
|
5051
5066
|
if (!controllerErrored) {
|
|
5052
5067
|
controller.close();
|
|
5053
5068
|
}
|
|
@@ -5110,7 +5125,7 @@ async function killProcessTree(proc, options) {
|
|
|
5110
5125
|
if (!pid) {
|
|
5111
5126
|
return;
|
|
5112
5127
|
}
|
|
5113
|
-
const graceMs = Math.max(1, options?.graceMs);
|
|
5128
|
+
const graceMs = Math.max(1, options?.graceMs ?? 1e3);
|
|
5114
5129
|
const descendants = await resolveDescendantPids(pid).catch(() => []);
|
|
5115
5130
|
const allPids = [...descendants, pid];
|
|
5116
5131
|
for (const targetPid of allPids) {
|
|
@@ -5135,6 +5150,29 @@ const RETRY_CONFIG = {
|
|
|
5135
5150
|
/** Maximum delay between retries in ms */
|
|
5136
5151
|
maxDelayMs: 5e3
|
|
5137
5152
|
};
|
|
5153
|
+
const DEFAULT_POST_PROMPT_NO_UPDATES_TIMEOUT_MS = 3e4;
|
|
5154
|
+
function readPositiveIntegerEnv(name) {
|
|
5155
|
+
const raw = typeof process.env[name] === "string" ? process.env[name].trim() : "";
|
|
5156
|
+
if (!raw) {
|
|
5157
|
+
return null;
|
|
5158
|
+
}
|
|
5159
|
+
const value = Number(raw);
|
|
5160
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
5161
|
+
return null;
|
|
5162
|
+
}
|
|
5163
|
+
return value;
|
|
5164
|
+
}
|
|
5165
|
+
function resolvePostPromptNoUpdatesTimeoutMs(transport) {
|
|
5166
|
+
const transportValue = transport.getPostPromptNoUpdatesTimeoutMs?.();
|
|
5167
|
+
if (typeof transportValue === "number" && Number.isFinite(transportValue) && transportValue > 0) {
|
|
5168
|
+
return Math.trunc(transportValue);
|
|
5169
|
+
}
|
|
5170
|
+
const envValue = readPositiveIntegerEnv("HAPPY_ACP_POST_PROMPT_NO_UPDATES_TIMEOUT_MS") ?? readPositiveIntegerEnv("HAPPIER_ACP_POST_PROMPT_NO_UPDATES_TIMEOUT_MS");
|
|
5171
|
+
if (envValue != null) {
|
|
5172
|
+
return envValue;
|
|
5173
|
+
}
|
|
5174
|
+
return DEFAULT_POST_PROMPT_NO_UPDATES_TIMEOUT_MS;
|
|
5175
|
+
}
|
|
5138
5176
|
function getSessionUpdates(params) {
|
|
5139
5177
|
const notification = params;
|
|
5140
5178
|
const updates = Array.isArray(notification.updates) ? notification.updates.filter((update) => Boolean(update && typeof update === "object")) : [];
|
|
@@ -5310,6 +5348,17 @@ function normalizeAcpError(error) {
|
|
|
5310
5348
|
}
|
|
5311
5349
|
return normalized;
|
|
5312
5350
|
}
|
|
5351
|
+
function getStatusErrorDetail(message) {
|
|
5352
|
+
if (message.type !== "status" || message.status !== "error") {
|
|
5353
|
+
return null;
|
|
5354
|
+
}
|
|
5355
|
+
const detail = typeof message.detail === "string" ? message.detail.trim() : "";
|
|
5356
|
+
return detail || "Unknown ACP transport error";
|
|
5357
|
+
}
|
|
5358
|
+
function looksLikeDroppedStdoutError(text) {
|
|
5359
|
+
const lower = text.toLowerCase();
|
|
5360
|
+
return lower.startsWith("error") || lower.includes("error:") || lower.includes("exception") || lower.includes("traceback") || lower.includes("invalid request") || lower.includes("invalid_request") || lower.includes("unauthorized") || lower.includes("forbidden") || lower.includes("permission denied") || /\b(4\d\d|5\d\d)\b/.test(lower) && (lower.includes("http") || lower.includes("status") || lower.includes("request"));
|
|
5361
|
+
}
|
|
5313
5362
|
function createAcpAbortError(message) {
|
|
5314
5363
|
const error = new Error(message);
|
|
5315
5364
|
error.name = "AbortError";
|
|
@@ -5432,6 +5481,12 @@ class AcpBackend {
|
|
|
5432
5481
|
responseCompletionOutcome = null;
|
|
5433
5482
|
/** Whether the current prompt is still waiting for completion */
|
|
5434
5483
|
waitingForResponse = false;
|
|
5484
|
+
/** First fatal prompt-level error observed for the current turn */
|
|
5485
|
+
responseCompletionError = null;
|
|
5486
|
+
/** Fallback completion when prompt returns but the agent emits no session updates */
|
|
5487
|
+
postPromptCompletionIdleTimeout = null;
|
|
5488
|
+
/** Whether at least one session/update arrived after the current prompt */
|
|
5489
|
+
sawSessionUpdateSincePrompt = false;
|
|
5435
5490
|
/** Transport handler for agent-specific behavior */
|
|
5436
5491
|
transport;
|
|
5437
5492
|
/** Keep a short rolling stderr buffer so startup failures can surface the real cause. */
|
|
@@ -5455,6 +5510,12 @@ class AcpBackend {
|
|
|
5455
5510
|
this.idleTimeout = null;
|
|
5456
5511
|
}
|
|
5457
5512
|
}
|
|
5513
|
+
clearPostPromptCompletionIdleTimeout() {
|
|
5514
|
+
if (this.postPromptCompletionIdleTimeout) {
|
|
5515
|
+
clearTimeout(this.postPromptCompletionIdleTimeout);
|
|
5516
|
+
this.postPromptCompletionIdleTimeout = null;
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5458
5519
|
clearToolCallTracking() {
|
|
5459
5520
|
this.activeToolCalls.clear();
|
|
5460
5521
|
for (const timeout of this.toolCallTimeouts.values()) {
|
|
@@ -5468,9 +5529,26 @@ class AcpBackend {
|
|
|
5468
5529
|
}
|
|
5469
5530
|
resetResponseTrackingForNewPrompt() {
|
|
5470
5531
|
this.responseCompletionOutcome = null;
|
|
5532
|
+
this.responseCompletionError = null;
|
|
5533
|
+
this.sawSessionUpdateSincePrompt = false;
|
|
5471
5534
|
this.clearIdleTimeoutState();
|
|
5535
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
5472
5536
|
this.clearToolCallTracking();
|
|
5473
5537
|
}
|
|
5538
|
+
failPendingResponseWait(error) {
|
|
5539
|
+
if (this.responseCompletionError) {
|
|
5540
|
+
return;
|
|
5541
|
+
}
|
|
5542
|
+
this.responseCompletionError = error;
|
|
5543
|
+
this.responseCompletionOutcome = null;
|
|
5544
|
+
this.waitingForResponse = false;
|
|
5545
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
5546
|
+
if (this.idleRejecter) {
|
|
5547
|
+
this.idleRejecter(error);
|
|
5548
|
+
}
|
|
5549
|
+
this.idleResolver = null;
|
|
5550
|
+
this.idleRejecter = null;
|
|
5551
|
+
}
|
|
5474
5552
|
settleResponseWaiter(outcome) {
|
|
5475
5553
|
const hasActiveWaiter = Boolean(this.idleResolver || this.idleRejecter);
|
|
5476
5554
|
if (!this.waitingForResponse && !hasActiveWaiter) {
|
|
@@ -5506,6 +5584,38 @@ class AcpBackend {
|
|
|
5506
5584
|
}
|
|
5507
5585
|
}
|
|
5508
5586
|
}
|
|
5587
|
+
handleDroppedStdoutLine(entry) {
|
|
5588
|
+
if (entry.reason !== "transport_filter_null" || !this.waitingForResponse || this.responseCompletionError) {
|
|
5589
|
+
return;
|
|
5590
|
+
}
|
|
5591
|
+
const raw = entry.line.trim();
|
|
5592
|
+
if (!raw) {
|
|
5593
|
+
return;
|
|
5594
|
+
}
|
|
5595
|
+
const context = {
|
|
5596
|
+
activeToolCalls: this.activeToolCalls,
|
|
5597
|
+
hasActiveInvestigation: this.transport.isInvestigationTool ? Array.from(this.activeToolCalls).some((id) => this.transport.isInvestigationTool(id)) : false
|
|
5598
|
+
};
|
|
5599
|
+
const transportResult = this.transport.handleStderr?.(entry.line, context);
|
|
5600
|
+
const transportMessage = transportResult?.message ?? null;
|
|
5601
|
+
if (transportMessage) {
|
|
5602
|
+
this.emit(transportMessage);
|
|
5603
|
+
const errorDetail = getStatusErrorDetail(transportMessage);
|
|
5604
|
+
if (errorDetail) {
|
|
5605
|
+
this.failPendingResponseWait(new Error(errorDetail));
|
|
5606
|
+
}
|
|
5607
|
+
return;
|
|
5608
|
+
}
|
|
5609
|
+
if (!looksLikeDroppedStdoutError(raw)) {
|
|
5610
|
+
return;
|
|
5611
|
+
}
|
|
5612
|
+
this.emit({
|
|
5613
|
+
type: "status",
|
|
5614
|
+
status: "error",
|
|
5615
|
+
detail: raw
|
|
5616
|
+
});
|
|
5617
|
+
this.failPendingResponseWait(new Error(raw));
|
|
5618
|
+
}
|
|
5509
5619
|
async startSession(initialPrompt) {
|
|
5510
5620
|
if (this.disposed) {
|
|
5511
5621
|
throw new Error("Backend has been disposed");
|
|
@@ -5545,20 +5655,27 @@ class AcpBackend {
|
|
|
5545
5655
|
const result = this.transport.handleStderr(text, context);
|
|
5546
5656
|
if (result.message) {
|
|
5547
5657
|
this.emit(result.message);
|
|
5658
|
+
const errorDetail = getStatusErrorDetail(result.message);
|
|
5659
|
+
if (errorDetail && this.waitingForResponse) {
|
|
5660
|
+
this.failPendingResponseWait(new Error(errorDetail));
|
|
5661
|
+
}
|
|
5548
5662
|
}
|
|
5549
5663
|
}
|
|
5550
5664
|
});
|
|
5551
5665
|
this.process.on("error", (err) => {
|
|
5552
5666
|
api.logger.debug(`[AcpBackend] Process error:`, err);
|
|
5553
|
-
this.
|
|
5667
|
+
if (this.waitingForResponse) {
|
|
5668
|
+
this.failPendingResponseWait(err);
|
|
5669
|
+
}
|
|
5554
5670
|
this.emit({ type: "status", status: "error", detail: err.message });
|
|
5555
5671
|
});
|
|
5556
5672
|
this.process.on("exit", (code, signal) => {
|
|
5557
5673
|
if (!this.disposed && code !== 0 && code !== null) {
|
|
5558
|
-
this.
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5674
|
+
if (this.waitingForResponse) {
|
|
5675
|
+
this.failPendingResponseWait(
|
|
5676
|
+
new Error(`ACP process exited with code ${code}${signal ? ` (${signal})` : ""}`)
|
|
5677
|
+
);
|
|
5678
|
+
}
|
|
5562
5679
|
api.logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
|
|
5563
5680
|
this.emit({ type: "status", status: "stopped", detail: `Exit code: ${code}` });
|
|
5564
5681
|
}
|
|
@@ -5575,14 +5692,17 @@ class AcpBackend {
|
|
|
5575
5692
|
transport: this.transport,
|
|
5576
5693
|
onDroppedLine: (entry) => {
|
|
5577
5694
|
droppedStdoutLines.push(entry);
|
|
5695
|
+
this.handleDroppedStdoutLine(entry);
|
|
5696
|
+
},
|
|
5697
|
+
onDone: () => {
|
|
5698
|
+
if (droppedStdoutLines.length > 0) {
|
|
5699
|
+
api.logger.debug(
|
|
5700
|
+
`[AcpBackend] Filtered out ${droppedStdoutLines.length} stdout lines from ${this.transport.agentName}`,
|
|
5701
|
+
droppedStdoutLines.slice(0, 5)
|
|
5702
|
+
);
|
|
5703
|
+
}
|
|
5578
5704
|
}
|
|
5579
5705
|
});
|
|
5580
|
-
if (droppedStdoutLines.length > 0) {
|
|
5581
|
-
api.logger.debug(
|
|
5582
|
-
`[AcpBackend] Filtered out ${droppedStdoutLines.length} stdout lines from ${this.transport.agentName}`,
|
|
5583
|
-
droppedStdoutLines.slice(0, 5)
|
|
5584
|
-
);
|
|
5585
|
-
}
|
|
5586
5706
|
const stream = sdk.ndJsonStream(writable, filteredReadable);
|
|
5587
5707
|
const client = {
|
|
5588
5708
|
sessionUpdate: async (params) => {
|
|
@@ -5744,6 +5864,11 @@ class AcpBackend {
|
|
|
5744
5864
|
}
|
|
5745
5865
|
};
|
|
5746
5866
|
const initTimeout = this.transport.getInitTimeout();
|
|
5867
|
+
const initDelayMs = this.transport.getInitDelayMs?.() ?? 0;
|
|
5868
|
+
if (initDelayMs > 0) {
|
|
5869
|
+
api.logger.debug(`[AcpBackend] Waiting ${initDelayMs}ms before initialize (${this.transport.agentName})...`);
|
|
5870
|
+
await api.delay(initDelayMs);
|
|
5871
|
+
}
|
|
5747
5872
|
api.logger.debug(`[AcpBackend] Initializing connection (timeout: ${initTimeout}ms)...`);
|
|
5748
5873
|
await withRetry(
|
|
5749
5874
|
async () => {
|
|
@@ -5849,6 +5974,16 @@ class AcpBackend {
|
|
|
5849
5974
|
return { sessionId };
|
|
5850
5975
|
} catch (error) {
|
|
5851
5976
|
const enrichedError = enrichAcpError(error, this.getRecentStderrExcerpt());
|
|
5977
|
+
if (this.process) {
|
|
5978
|
+
try {
|
|
5979
|
+
await killProcessTree(this.process, { graceMs: 250 });
|
|
5980
|
+
} catch {
|
|
5981
|
+
} finally {
|
|
5982
|
+
this.process = null;
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
this.connection = null;
|
|
5986
|
+
this.acpSessionId = null;
|
|
5852
5987
|
api.logger.debug("[AcpBackend] Error starting session:", enrichedError);
|
|
5853
5988
|
this.emit({
|
|
5854
5989
|
type: "status",
|
|
@@ -5909,6 +6044,8 @@ class AcpBackend {
|
|
|
5909
6044
|
api.logger.debug("[AcpBackend] Received session update without update field:", params);
|
|
5910
6045
|
return;
|
|
5911
6046
|
}
|
|
6047
|
+
this.sawSessionUpdateSincePrompt = true;
|
|
6048
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
5912
6049
|
for (const update of updates) {
|
|
5913
6050
|
const sessionUpdateType = update.sessionUpdate;
|
|
5914
6051
|
if (sessionUpdateType !== "agent_message_chunk") {
|
|
@@ -5988,6 +6125,29 @@ class AcpBackend {
|
|
|
5988
6125
|
api.logger.debug(`[AcpBackend] Prompt request:`, JSON.stringify(promptRequest, null, 2));
|
|
5989
6126
|
await this.connection.prompt(promptRequest);
|
|
5990
6127
|
api.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
|
|
6128
|
+
if (this.waitingForResponse && this.activeToolCalls.size === 0 && this.sawSessionUpdateSincePrompt === false) {
|
|
6129
|
+
const noUpdatesTimeoutMs = resolvePostPromptNoUpdatesTimeoutMs(this.transport);
|
|
6130
|
+
this.postPromptCompletionIdleTimeout = setTimeout(() => {
|
|
6131
|
+
this.postPromptCompletionIdleTimeout = null;
|
|
6132
|
+
if (this.responseCompletionError || !this.waitingForResponse) {
|
|
6133
|
+
return;
|
|
6134
|
+
}
|
|
6135
|
+
if (this.sawSessionUpdateSincePrompt || this.activeToolCalls.size > 0) {
|
|
6136
|
+
return;
|
|
6137
|
+
}
|
|
6138
|
+
const exitCode = this.process?.exitCode;
|
|
6139
|
+
if (typeof exitCode === "number" && Number.isFinite(exitCode) && exitCode !== 0) {
|
|
6140
|
+
this.failPendingResponseWait(new Error(`Exit code: ${exitCode}`));
|
|
6141
|
+
return;
|
|
6142
|
+
}
|
|
6143
|
+
const signalCode = this.process?.signalCode;
|
|
6144
|
+
if (typeof signalCode === "string" && signalCode.trim().length > 0) {
|
|
6145
|
+
this.failPendingResponseWait(new Error(`Signal: ${signalCode}`));
|
|
6146
|
+
return;
|
|
6147
|
+
}
|
|
6148
|
+
this.emitIdleStatus();
|
|
6149
|
+
}, Math.max(100, noUpdatesTimeoutMs));
|
|
6150
|
+
}
|
|
5991
6151
|
} catch (error) {
|
|
5992
6152
|
api.logger.debug("[AcpBackend] Error sending prompt:", error);
|
|
5993
6153
|
let errorDetail;
|
|
@@ -6003,10 +6163,7 @@ class AcpBackend {
|
|
|
6003
6163
|
status: "error",
|
|
6004
6164
|
detail: errorDetail
|
|
6005
6165
|
});
|
|
6006
|
-
this.
|
|
6007
|
-
kind: "rejected",
|
|
6008
|
-
error: error instanceof Error ? error : normalizeAcpError(error)
|
|
6009
|
-
});
|
|
6166
|
+
this.failPendingResponseWait(error instanceof Error ? error : normalizeAcpError(error));
|
|
6010
6167
|
throw error;
|
|
6011
6168
|
}
|
|
6012
6169
|
}
|
|
@@ -6015,6 +6172,9 @@ class AcpBackend {
|
|
|
6015
6172
|
* Call this after sendPrompt to wait for Gemini to finish responding
|
|
6016
6173
|
*/
|
|
6017
6174
|
async waitForResponseComplete(timeoutMs = 12e4) {
|
|
6175
|
+
if (this.responseCompletionError) {
|
|
6176
|
+
throw this.responseCompletionError;
|
|
6177
|
+
}
|
|
6018
6178
|
const pendingOutcome = this.responseCompletionOutcome;
|
|
6019
6179
|
if (pendingOutcome) {
|
|
6020
6180
|
this.responseCompletionOutcome = null;
|
|
@@ -6053,12 +6213,14 @@ class AcpBackend {
|
|
|
6053
6213
|
* Helper to emit idle status and resolve any waiting promises
|
|
6054
6214
|
*/
|
|
6055
6215
|
emitIdleStatus() {
|
|
6216
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
6056
6217
|
this.emit({ type: "status", status: "idle" });
|
|
6057
6218
|
this.settleResponseWaiter({ kind: "resolved" });
|
|
6058
6219
|
}
|
|
6059
6220
|
async cancel(sessionId) {
|
|
6060
6221
|
const cancelError = createAcpAbortError("Cancelled by user");
|
|
6061
6222
|
this.clearIdleTimeoutState();
|
|
6223
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
6062
6224
|
this.clearToolCallTracking();
|
|
6063
6225
|
this.settleResponseWaiter({ kind: "rejected", error: cancelError });
|
|
6064
6226
|
this.emit({ type: "status", status: "stopped", detail: "Cancelled by user" });
|
|
@@ -6119,6 +6281,7 @@ class AcpBackend {
|
|
|
6119
6281
|
}
|
|
6120
6282
|
}
|
|
6121
6283
|
this.clearIdleTimeoutState();
|
|
6284
|
+
this.clearPostPromptCompletionIdleTimeout();
|
|
6122
6285
|
this.listeners = [];
|
|
6123
6286
|
this.connection = null;
|
|
6124
6287
|
this.acpSessionId = null;
|
|
@@ -6560,7 +6723,6 @@ function createCodexBackend(options) {
|
|
|
6560
6723
|
...options.env,
|
|
6561
6724
|
NODE_ENV: "production"
|
|
6562
6725
|
},
|
|
6563
|
-
mcpServers: options.mcpServers,
|
|
6564
6726
|
permissionHandler: options.permissionHandler,
|
|
6565
6727
|
selectionHandler: options.selectionHandler,
|
|
6566
6728
|
transportHandler: resolveCodexTransport(spawn.command)
|
|
@@ -6768,12 +6930,12 @@ async function ensureUnifiedDaemonStarted() {
|
|
|
6768
6930
|
async function executeUnifiedProvider(opts) {
|
|
6769
6931
|
const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials);
|
|
6770
6932
|
if (opts.provider === "claude") {
|
|
6771
|
-
const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-
|
|
6933
|
+
const { runClaude } = await Promise.resolve().then(function () { return require('./runClaude-CPhWaFrX.cjs'); });
|
|
6772
6934
|
await runClaude(credentials, opts.claudeOptions ?? {});
|
|
6773
6935
|
return;
|
|
6774
6936
|
}
|
|
6775
6937
|
if (opts.provider === "codex") {
|
|
6776
|
-
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex
|
|
6938
|
+
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex--QLrOs8X.cjs'); });
|
|
6777
6939
|
await runCodex({
|
|
6778
6940
|
credentials,
|
|
6779
6941
|
startedBy: opts.startedBy,
|
|
@@ -6783,7 +6945,7 @@ async function executeUnifiedProvider(opts) {
|
|
|
6783
6945
|
return;
|
|
6784
6946
|
}
|
|
6785
6947
|
if (opts.provider === "gemini") {
|
|
6786
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
6948
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CDyhCucw.cjs'); });
|
|
6787
6949
|
await runGemini({
|
|
6788
6950
|
credentials,
|
|
6789
6951
|
startedBy: opts.startedBy
|
|
@@ -6825,7 +6987,7 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
6825
6987
|
return;
|
|
6826
6988
|
} else if (subcommand === "runtime") {
|
|
6827
6989
|
if (args[1] === "providers") {
|
|
6828
|
-
const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-
|
|
6990
|
+
const { renderRuntimeProviders } = await Promise.resolve().then(function () { return require('./command-DjIfRZQS.cjs'); });
|
|
6829
6991
|
console.log(renderRuntimeProviders());
|
|
6830
6992
|
return;
|
|
6831
6993
|
}
|
|
@@ -7003,8 +7165,8 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
7003
7165
|
const projectId = args[3];
|
|
7004
7166
|
try {
|
|
7005
7167
|
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
|
|
7006
|
-
const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-
|
|
7007
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-
|
|
7168
|
+
const { readCredentials: readCredentials2 } = await Promise.resolve().then(function () { return require('./persistence-DBGkO8gB.cjs'); });
|
|
7169
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./api-CN-WqYd_.cjs'); }).then(function (n) { return n.api; });
|
|
7008
7170
|
let userEmail = void 0;
|
|
7009
7171
|
try {
|
|
7010
7172
|
const credentials = await readCredentials2();
|