@pixelbyte-software/pixcode 1.50.4 → 1.50.5
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/assets/{index-DYQjBZrd.js → index-BSxc8Vid.js} +1 -1
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +92 -27
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/routes/network.js +2 -2
- package/dist-server/server/routes/network.js.map +1 -1
- package/dist-server/server/services/external-access.js +193 -11
- package/dist-server/server/services/external-access.js.map +1 -1
- package/package.json +1 -1
- package/scripts/hermes/pixcode-mcp-server.mjs +48 -3
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +10 -3
- package/scripts/smoke/hermes-settings-commands.mjs +30 -0
- package/scripts/smoke/tunnel-persistence.mjs +56 -0
- package/server/index.js +95 -29
- package/server/routes/network.js +2 -2
- package/server/services/external-access.js +199 -11
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
2
5
|
/**
|
|
3
6
|
* External-access service.
|
|
4
7
|
*
|
|
@@ -27,15 +30,58 @@ export const getUpnpState = () => UPNP_UNAVAILABLE;
|
|
|
27
30
|
// stdout. We keep a single live tunnel per process — starting a new one
|
|
28
31
|
// stops the previous one to avoid dangling child processes.
|
|
29
32
|
// ============================================================================
|
|
33
|
+
export const TUNNEL_PERSISTENCE_PATH = process.env.PIXCODE_TUNNEL_STATE_PATH
|
|
34
|
+
|| path.join(os.homedir(), '.pixcode', 'external-access.json');
|
|
30
35
|
let tunnelProc = null;
|
|
36
|
+
let suppressNextTunnelRestore = false;
|
|
37
|
+
let restoreTimer = null;
|
|
38
|
+
let restoreInFlight = null;
|
|
31
39
|
let tunnelState = {
|
|
32
40
|
running: false,
|
|
33
41
|
binary: null, // 'cloudflared' | 'ngrok'
|
|
34
42
|
url: null,
|
|
35
43
|
error: null,
|
|
36
44
|
installHint: null,
|
|
45
|
+
desired: false,
|
|
46
|
+
restoring: false,
|
|
37
47
|
log: [],
|
|
38
48
|
};
|
|
49
|
+
const DEFAULT_TUNNEL_PREFERENCE = Object.freeze({
|
|
50
|
+
desired: false,
|
|
51
|
+
port: null,
|
|
52
|
+
provider: null,
|
|
53
|
+
lastUrl: null,
|
|
54
|
+
lastStartedAt: null,
|
|
55
|
+
lastStoppedAt: null,
|
|
56
|
+
updatedAt: null,
|
|
57
|
+
});
|
|
58
|
+
const readTunnelPreference = async () => {
|
|
59
|
+
try {
|
|
60
|
+
const raw = await fs.readFile(TUNNEL_PERSISTENCE_PATH, 'utf8');
|
|
61
|
+
const parsed = JSON.parse(raw);
|
|
62
|
+
return {
|
|
63
|
+
...DEFAULT_TUNNEL_PREFERENCE,
|
|
64
|
+
...(parsed && typeof parsed === 'object' ? parsed : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error?.code !== 'ENOENT') {
|
|
69
|
+
console.warn('[external-access] Failed to read tunnel preference:', error?.message || error);
|
|
70
|
+
}
|
|
71
|
+
return { ...DEFAULT_TUNNEL_PREFERENCE };
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
export const persistTunnelPreference = async (patch) => {
|
|
75
|
+
const current = await readTunnelPreference();
|
|
76
|
+
const next = {
|
|
77
|
+
...current,
|
|
78
|
+
...patch,
|
|
79
|
+
updatedAt: new Date().toISOString(),
|
|
80
|
+
};
|
|
81
|
+
await fs.mkdir(path.dirname(TUNNEL_PERSISTENCE_PATH), { recursive: true });
|
|
82
|
+
await fs.writeFile(TUNNEL_PERSISTENCE_PATH, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
83
|
+
return next;
|
|
84
|
+
};
|
|
39
85
|
const appendLog = (line) => {
|
|
40
86
|
// Tunnels can be noisy. Cap the tail we retain so a long-running tunnel
|
|
41
87
|
// doesn't grow the log into an OOM risk.
|
|
@@ -89,16 +135,33 @@ const extractUrl = (binary, text) => {
|
|
|
89
135
|
return text.match(ngrokUrlRegex)?.[0] ?? null;
|
|
90
136
|
return null;
|
|
91
137
|
};
|
|
92
|
-
export const startTunnel = async ({ port }) => {
|
|
138
|
+
export const startTunnel = async ({ port, persistPreference = false, restoring = false } = {}) => {
|
|
93
139
|
if (tunnelProc) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
140
|
+
if (persistPreference) {
|
|
141
|
+
await persistTunnelPreference({
|
|
142
|
+
desired: true,
|
|
143
|
+
port,
|
|
144
|
+
provider: tunnelState.binary,
|
|
145
|
+
lastUrl: tunnelState.url,
|
|
146
|
+
});
|
|
147
|
+
tunnelState = { ...tunnelState, desired: true, restoring: false };
|
|
148
|
+
}
|
|
149
|
+
return tunnelState;
|
|
97
150
|
}
|
|
151
|
+
suppressNextTunnelRestore = false;
|
|
98
152
|
const binary = await detectBinary();
|
|
99
153
|
if (!binary) {
|
|
100
154
|
const installHint = createTunnelInstallHint();
|
|
101
|
-
tunnelState = {
|
|
155
|
+
tunnelState = {
|
|
156
|
+
running: false,
|
|
157
|
+
binary: null,
|
|
158
|
+
url: null,
|
|
159
|
+
error: 'No tunnel binary found',
|
|
160
|
+
installHint,
|
|
161
|
+
desired: Boolean(persistPreference || restoring),
|
|
162
|
+
restoring,
|
|
163
|
+
log: [],
|
|
164
|
+
};
|
|
102
165
|
const err = new Error('No tunnel binary found (tried cloudflared, ngrok)');
|
|
103
166
|
err.code = 'ENOENT_TUNNEL';
|
|
104
167
|
err.installHint = installHint;
|
|
@@ -107,7 +170,16 @@ export const startTunnel = async ({ port }) => {
|
|
|
107
170
|
const args = buildTunnelArgs(binary, port);
|
|
108
171
|
const child = spawn(binary, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
109
172
|
tunnelProc = child;
|
|
110
|
-
tunnelState = {
|
|
173
|
+
tunnelState = {
|
|
174
|
+
running: true,
|
|
175
|
+
binary,
|
|
176
|
+
url: null,
|
|
177
|
+
error: null,
|
|
178
|
+
installHint: null,
|
|
179
|
+
desired: Boolean(persistPreference || restoring),
|
|
180
|
+
restoring,
|
|
181
|
+
log: [],
|
|
182
|
+
};
|
|
111
183
|
const handleChunk = (chunk) => {
|
|
112
184
|
const text = chunk.toString();
|
|
113
185
|
text.split(/\r?\n/).filter(Boolean).forEach(appendLog);
|
|
@@ -127,35 +199,86 @@ export const startTunnel = async ({ port }) => {
|
|
|
127
199
|
url: null,
|
|
128
200
|
error: code === 0 ? null : `Tunnel exited with code ${code}`,
|
|
129
201
|
installHint: null,
|
|
202
|
+
desired: tunnelState.desired,
|
|
203
|
+
restoring: false,
|
|
130
204
|
log: tunnelState.log,
|
|
131
205
|
};
|
|
206
|
+
if (suppressNextTunnelRestore) {
|
|
207
|
+
suppressNextTunnelRestore = false;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
void readTunnelPreference().then((preference) => {
|
|
211
|
+
if (!preference.desired)
|
|
212
|
+
return;
|
|
213
|
+
if (restoreTimer)
|
|
214
|
+
clearTimeout(restoreTimer);
|
|
215
|
+
restoreTimer = setTimeout(() => {
|
|
216
|
+
restoreTimer = null;
|
|
217
|
+
restoreRequestedTunnel({ port: Number(preference.port || port) || port }).catch((error) => {
|
|
218
|
+
console.warn('[external-access] Tunnel restore failed after exit:', error?.message || error);
|
|
219
|
+
});
|
|
220
|
+
}, 3000);
|
|
221
|
+
});
|
|
132
222
|
});
|
|
133
223
|
// Wait up to 15s for the public URL to appear in the log. We don't block
|
|
134
224
|
// indefinitely — if the binary is hanging on login/auth, the UI should see
|
|
135
225
|
// a clear failure instead of a spinner that never resolves.
|
|
136
226
|
const start = Date.now();
|
|
137
227
|
while (Date.now() - start < 15000) {
|
|
138
|
-
if (tunnelState.url)
|
|
228
|
+
if (tunnelState.url) {
|
|
229
|
+
if (persistPreference || restoring) {
|
|
230
|
+
await persistTunnelPreference({
|
|
231
|
+
desired: true,
|
|
232
|
+
port,
|
|
233
|
+
provider: binary,
|
|
234
|
+
lastUrl: tunnelState.url,
|
|
235
|
+
lastStartedAt: new Date().toISOString(),
|
|
236
|
+
});
|
|
237
|
+
tunnelState = { ...tunnelState, desired: true, restoring: false };
|
|
238
|
+
}
|
|
139
239
|
return tunnelState;
|
|
240
|
+
}
|
|
140
241
|
if (!tunnelProc)
|
|
141
242
|
break; // process died early
|
|
142
243
|
await new Promise((r) => setTimeout(r, 250));
|
|
143
244
|
}
|
|
144
245
|
if (!tunnelState.url) {
|
|
145
246
|
// If we never captured a URL, kill the child so we don't leak it.
|
|
247
|
+
suppressNextTunnelRestore = true;
|
|
146
248
|
try {
|
|
147
249
|
child.kill();
|
|
148
250
|
}
|
|
149
251
|
catch { /* ignore */ }
|
|
150
252
|
tunnelProc = null;
|
|
151
|
-
tunnelState = { ...tunnelState, running: false, error: 'Tunnel did not report a public URL', installHint: null };
|
|
253
|
+
tunnelState = { ...tunnelState, running: false, error: 'Tunnel did not report a public URL', installHint: null, restoring: false };
|
|
152
254
|
throw new Error(tunnelState.error);
|
|
153
255
|
}
|
|
154
256
|
return tunnelState;
|
|
155
257
|
};
|
|
156
|
-
export const stopTunnel = async () => {
|
|
258
|
+
export const stopTunnel = async ({ persistPreference = true } = {}) => {
|
|
259
|
+
suppressNextTunnelRestore = Boolean(tunnelProc);
|
|
260
|
+
if (restoreTimer) {
|
|
261
|
+
clearTimeout(restoreTimer);
|
|
262
|
+
restoreTimer = null;
|
|
263
|
+
}
|
|
264
|
+
if (persistPreference) {
|
|
265
|
+
await persistTunnelPreference({
|
|
266
|
+
desired: false,
|
|
267
|
+
lastStoppedAt: new Date().toISOString(),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
157
270
|
if (!tunnelProc) {
|
|
158
|
-
|
|
271
|
+
suppressNextTunnelRestore = false;
|
|
272
|
+
tunnelState = {
|
|
273
|
+
running: false,
|
|
274
|
+
binary: null,
|
|
275
|
+
url: null,
|
|
276
|
+
error: null,
|
|
277
|
+
installHint: null,
|
|
278
|
+
desired: false,
|
|
279
|
+
restoring: false,
|
|
280
|
+
log: [],
|
|
281
|
+
};
|
|
159
282
|
return tunnelState;
|
|
160
283
|
}
|
|
161
284
|
try {
|
|
@@ -165,9 +288,68 @@ export const stopTunnel = async () => {
|
|
|
165
288
|
// already dead
|
|
166
289
|
}
|
|
167
290
|
tunnelProc = null;
|
|
168
|
-
tunnelState = {
|
|
291
|
+
tunnelState = {
|
|
292
|
+
running: false,
|
|
293
|
+
binary: null,
|
|
294
|
+
url: null,
|
|
295
|
+
error: null,
|
|
296
|
+
installHint: null,
|
|
297
|
+
desired: false,
|
|
298
|
+
restoring: false,
|
|
299
|
+
log: [],
|
|
300
|
+
};
|
|
169
301
|
return tunnelState;
|
|
170
302
|
};
|
|
303
|
+
export const restoreRequestedTunnel = async ({ port } = {}) => {
|
|
304
|
+
if (restoreInFlight)
|
|
305
|
+
return restoreInFlight;
|
|
306
|
+
restoreInFlight = (async () => {
|
|
307
|
+
const preference = await readTunnelPreference();
|
|
308
|
+
if (!preference.desired) {
|
|
309
|
+
tunnelState = { ...tunnelState, desired: false, restoring: false };
|
|
310
|
+
return tunnelState;
|
|
311
|
+
}
|
|
312
|
+
if (tunnelProc) {
|
|
313
|
+
tunnelState = { ...tunnelState, desired: true, restoring: false };
|
|
314
|
+
return tunnelState;
|
|
315
|
+
}
|
|
316
|
+
const restorePort = Number(port || preference.port);
|
|
317
|
+
if (!Number.isFinite(restorePort) || restorePort <= 0) {
|
|
318
|
+
tunnelState = {
|
|
319
|
+
...tunnelState,
|
|
320
|
+
running: false,
|
|
321
|
+
desired: true,
|
|
322
|
+
restoring: false,
|
|
323
|
+
error: 'Tunnel restore skipped: no valid server port',
|
|
324
|
+
};
|
|
325
|
+
return tunnelState;
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
return await startTunnel({
|
|
329
|
+
port: restorePort,
|
|
330
|
+
persistPreference: true,
|
|
331
|
+
restoring: true,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
tunnelState = {
|
|
336
|
+
...tunnelState,
|
|
337
|
+
running: false,
|
|
338
|
+
desired: true,
|
|
339
|
+
restoring: false,
|
|
340
|
+
error: `Tunnel restore failed: ${error?.message || error}`,
|
|
341
|
+
installHint: error?.installHint || tunnelState.installHint || null,
|
|
342
|
+
};
|
|
343
|
+
return tunnelState;
|
|
344
|
+
}
|
|
345
|
+
})();
|
|
346
|
+
try {
|
|
347
|
+
return await restoreInFlight;
|
|
348
|
+
}
|
|
349
|
+
finally {
|
|
350
|
+
restoreInFlight = null;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
171
353
|
export const getTunnelState = () => tunnelState;
|
|
172
354
|
// Explicit cleanup so the server process can shut down without leaking the
|
|
173
355
|
// child tunnel process.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-access.js","sourceRoot":"","sources":["../../../server/services/external-access.js"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"external-access.js","sourceRoot":"","sources":["../../../server/services/external-access.js"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelbyte-software/pixcode",
|
|
3
|
-
"version": "1.50.
|
|
3
|
+
"version": "1.50.5",
|
|
4
4
|
"description": "Self-hosted AI coding agent control room for Claude Code, Cursor CLI, OpenAI Codex, Gemini CLI, Qwen Code, and OpenCode with chat, files, shell, Git, orchestration, API keys, Telegram, MCP, plugins, themes, and desktop/server deployment.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist-server/server/index.js",
|
|
@@ -7,6 +7,7 @@ const baseUrl = (process.env.PIXCODE_BASE_URL || '').replace(/\/$/, '');
|
|
|
7
7
|
const apiKey = process.env.PIXCODE_API_KEY || '';
|
|
8
8
|
const appRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
9
9
|
const mcpServerPath = path.join(appRoot, 'scripts', 'hermes', 'pixcode-mcp-server.mjs');
|
|
10
|
+
const READBACK_IDLE_STABLE_MS = 2500;
|
|
10
11
|
|
|
11
12
|
const tools = [
|
|
12
13
|
{
|
|
@@ -245,12 +246,30 @@ function inferTerminalState(provider, terminalOutput) {
|
|
|
245
246
|
|
|
246
247
|
function isTerminalReadbackFinal(provider, terminalOutput) {
|
|
247
248
|
const terminalState = inferTerminalState(provider, terminalOutput);
|
|
248
|
-
return terminalState === 'idle' || terminalState === 'completed' || terminalState === 'exited';
|
|
249
|
+
return terminalState === 'idle' || terminalState === 'completed' || terminalState === 'exited' || terminalState === 'failed';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function isTerminalReadbackHardFinal(provider, terminalOutput) {
|
|
253
|
+
const terminalState = inferTerminalState(provider, terminalOutput);
|
|
254
|
+
return terminalState === 'completed' || terminalState === 'exited' || terminalState === 'failed' || Boolean(terminalOutput?.terminalFailed);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function getReadbackFingerprint(terminalOutput) {
|
|
258
|
+
return [
|
|
259
|
+
terminalOutput?.terminalState || '',
|
|
260
|
+
terminalOutput?.lifecycleState || '',
|
|
261
|
+
terminalOutput?.exitCode ?? '',
|
|
262
|
+
terminalOutput?.exitSignal || '',
|
|
263
|
+
String(terminalOutput?.output || '').slice(-12000),
|
|
264
|
+
].join('\n---pixcode-readback---\n');
|
|
249
265
|
}
|
|
250
266
|
|
|
251
267
|
async function waitForProviderTerminalOutput(provider, projectPath, waitMs, launchId = null) {
|
|
252
268
|
const startedAt = Date.now();
|
|
253
269
|
let latestOutput = null;
|
|
270
|
+
let stableFingerprint = null;
|
|
271
|
+
let stableSince = 0;
|
|
272
|
+
let stableFinal = false;
|
|
254
273
|
do {
|
|
255
274
|
const elapsed = Date.now() - startedAt;
|
|
256
275
|
const remaining = Math.max(0, waitMs - elapsed);
|
|
@@ -262,7 +281,23 @@ async function waitForProviderTerminalOutput(provider, projectPath, waitMs, laun
|
|
|
262
281
|
}));
|
|
263
282
|
|
|
264
283
|
if (latestOutput?.output && isTerminalReadbackFinal(provider, latestOutput)) {
|
|
265
|
-
|
|
284
|
+
if (isTerminalReadbackHardFinal(provider, latestOutput)) {
|
|
285
|
+
stableFinal = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const fingerprint = getReadbackFingerprint(latestOutput);
|
|
290
|
+
if (fingerprint !== stableFingerprint) {
|
|
291
|
+
stableFingerprint = fingerprint;
|
|
292
|
+
stableSince = Date.now();
|
|
293
|
+
}
|
|
294
|
+
if (Date.now() - stableSince >= READBACK_IDLE_STABLE_MS) {
|
|
295
|
+
stableFinal = true;
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
stableFingerprint = null;
|
|
300
|
+
stableSince = 0;
|
|
266
301
|
}
|
|
267
302
|
} while (Date.now() - startedAt < waitMs);
|
|
268
303
|
|
|
@@ -272,6 +307,10 @@ async function waitForProviderTerminalOutput(provider, projectPath, waitMs, laun
|
|
|
272
307
|
if (latestOutput && typeof latestOutput.isBusy !== 'boolean') {
|
|
273
308
|
latestOutput.isBusy = latestOutput.terminalState === 'busy';
|
|
274
309
|
}
|
|
310
|
+
if (latestOutput) {
|
|
311
|
+
latestOutput.readbackStable = stableFinal;
|
|
312
|
+
latestOutput.terminalOutputFinal = stableFinal;
|
|
313
|
+
}
|
|
275
314
|
return latestOutput;
|
|
276
315
|
}
|
|
277
316
|
|
|
@@ -375,7 +414,9 @@ async function callTool(name, args = {}) {
|
|
|
375
414
|
if (waitForOutputMs > 0) {
|
|
376
415
|
terminalOutput = await waitForProviderTerminalOutput(provider, projectPath, waitForOutputMs, launchId);
|
|
377
416
|
}
|
|
378
|
-
const terminalOutputFinal = terminalOutput
|
|
417
|
+
const terminalOutputFinal = terminalOutput
|
|
418
|
+
? Boolean(terminalOutput.terminalOutputFinal ?? isTerminalReadbackFinal(provider, terminalOutput))
|
|
419
|
+
: false;
|
|
379
420
|
return textResult(JSON.stringify({
|
|
380
421
|
launched: true,
|
|
381
422
|
launchId,
|
|
@@ -385,8 +426,11 @@ async function callTool(name, args = {}) {
|
|
|
385
426
|
permissionBypass: bypassPermissions,
|
|
386
427
|
status,
|
|
387
428
|
terminalOutputFinal,
|
|
429
|
+
terminalFailed: Boolean(terminalOutput?.terminalFailed),
|
|
388
430
|
message: terminalOutput && !terminalOutputFinal
|
|
389
431
|
? 'Provider terminal is still running or not at an idle prompt yet. Do not summarize this as final output; call pixcode_read_cli_terminal with launchId later.'
|
|
432
|
+
: terminalOutput?.terminalFailed
|
|
433
|
+
? 'Provider terminal exited with a failure. Do not report this as successful; tell the user the visible CLI failed and include the exit code/output.'
|
|
390
434
|
: undefined,
|
|
391
435
|
terminalOutput,
|
|
392
436
|
}, null, 2));
|
|
@@ -407,6 +451,7 @@ async function callTool(name, args = {}) {
|
|
|
407
451
|
body.isBusy = body.terminalState === 'busy';
|
|
408
452
|
}
|
|
409
453
|
body.terminalOutputFinal = isTerminalReadbackFinal(provider, body);
|
|
454
|
+
body.terminalFailed = Boolean(body.terminalFailed);
|
|
410
455
|
return textResult(JSON.stringify(body, null, 2));
|
|
411
456
|
}
|
|
412
457
|
|
|
@@ -122,6 +122,13 @@ const server = createServer(async (req, res) => {
|
|
|
122
122
|
terminalState: 'busy',
|
|
123
123
|
output: 'OpenAI Codex\n› /init\n\n• Ran npm test\n• Working (30s • esc to interrupt)\n',
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
active: true,
|
|
127
|
+
provider: 'codex',
|
|
128
|
+
projectPath: '/root/pixcode',
|
|
129
|
+
terminalState: 'idle',
|
|
130
|
+
output: 'OpenAI Codex\n› /init\n\n• Ran npm test\n\n› Implement {feature}\n',
|
|
131
|
+
},
|
|
125
132
|
{
|
|
126
133
|
active: true,
|
|
127
134
|
provider: 'codex',
|
|
@@ -155,7 +162,7 @@ function callMcp(child, method, params = undefined) {
|
|
|
155
162
|
return new Promise((resolve, reject) => {
|
|
156
163
|
const timeout = setTimeout(() => {
|
|
157
164
|
reject(new Error(`MCP call timed out: ${method}`));
|
|
158
|
-
},
|
|
165
|
+
}, 10000);
|
|
159
166
|
const onLine = (line) => {
|
|
160
167
|
if (!line.trim()) return;
|
|
161
168
|
const message = JSON.parse(line);
|
|
@@ -232,11 +239,11 @@ try {
|
|
|
232
239
|
projectPath: '/root/pixcode',
|
|
233
240
|
prompt: 'read final output',
|
|
234
241
|
startupInput: '/init',
|
|
235
|
-
waitForOutputMs:
|
|
242
|
+
waitForOutputMs: 7000,
|
|
236
243
|
},
|
|
237
244
|
});
|
|
238
245
|
assert(
|
|
239
|
-
providerOutputReads.length >=
|
|
246
|
+
providerOutputReads.length >= 5,
|
|
240
247
|
`readback should keep polling until the provider terminal is idle, reads=${providerOutputReads.length}`,
|
|
241
248
|
);
|
|
242
249
|
assert.match(
|
|
@@ -98,6 +98,26 @@ assert.match(
|
|
|
98
98
|
/requestedLaunchId[\s\S]+session\.hermesLaunchId === requestedLaunchId/,
|
|
99
99
|
'Provider output API should filter by Hermes terminal launch id when supplied.',
|
|
100
100
|
);
|
|
101
|
+
assert.match(
|
|
102
|
+
serverIndex,
|
|
103
|
+
/lifecycleState/,
|
|
104
|
+
'Provider output API should expose provider-agnostic PTY lifecycle state instead of relying only on terminal text regex.',
|
|
105
|
+
);
|
|
106
|
+
assert.match(
|
|
107
|
+
serverIndex,
|
|
108
|
+
/terminalFailed/,
|
|
109
|
+
'Provider output API should expose non-zero visible terminal exits as failures for Hermes readback.',
|
|
110
|
+
);
|
|
111
|
+
assert.match(
|
|
112
|
+
serverIndex,
|
|
113
|
+
/existingSession[\s\S]+existingSession\.pty/,
|
|
114
|
+
'Completed visible terminal records should not be reattached as live PTYs.',
|
|
115
|
+
);
|
|
116
|
+
assert.match(
|
|
117
|
+
pixcodeMcpServer,
|
|
118
|
+
/terminalFailed/,
|
|
119
|
+
'Pixcode MCP should tell Hermes when the visible provider terminal failed.',
|
|
120
|
+
);
|
|
101
121
|
assert.match(
|
|
102
122
|
serverIndex,
|
|
103
123
|
/const hermesLaunchId = Number\.isFinite\(Number\(data\.hermesLaunchId\)\)/,
|
|
@@ -113,6 +133,16 @@ assert.match(
|
|
|
113
133
|
/terminalState is busy|terminalState.+busy|terminal to become idle/i,
|
|
114
134
|
'Pixcode MCP should not summarize the first busy terminal frame as final output.',
|
|
115
135
|
);
|
|
136
|
+
assert.match(
|
|
137
|
+
pixcodeMcpServer,
|
|
138
|
+
/READBACK_IDLE_STABLE_MS/,
|
|
139
|
+
'Pixcode MCP should require a stable idle readback before reporting provider output as final.',
|
|
140
|
+
);
|
|
141
|
+
assert.match(
|
|
142
|
+
pixcodeMcpServer,
|
|
143
|
+
/readbackStable/,
|
|
144
|
+
'Pixcode MCP should mark whether a visible provider readback was stable before Hermes summarizes it.',
|
|
145
|
+
);
|
|
116
146
|
assert.match(
|
|
117
147
|
pixcodeMcpServer,
|
|
118
148
|
/startup input typed into the provider CLI/,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const externalAccess = readFileSync('server/services/external-access.js', 'utf8');
|
|
7
|
+
const networkRoutes = readFileSync('server/routes/network.js', 'utf8');
|
|
8
|
+
const serverIndex = readFileSync('server/index.js', 'utf8');
|
|
9
|
+
|
|
10
|
+
assert.match(
|
|
11
|
+
externalAccess,
|
|
12
|
+
/TUNNEL_PERSISTENCE_PATH/,
|
|
13
|
+
'Tunnel service should persist the user-requested tunnel state outside process memory.',
|
|
14
|
+
);
|
|
15
|
+
assert.match(
|
|
16
|
+
externalAccess,
|
|
17
|
+
/persistTunnelPreference/,
|
|
18
|
+
'Tunnel service should write tunnel start/stop intent to disk.',
|
|
19
|
+
);
|
|
20
|
+
assert.match(
|
|
21
|
+
externalAccess,
|
|
22
|
+
/desired:\s*true/,
|
|
23
|
+
'Starting a tunnel should mark tunnel intent as desired until the user stops it.',
|
|
24
|
+
);
|
|
25
|
+
assert.match(
|
|
26
|
+
externalAccess,
|
|
27
|
+
/desired:\s*false/,
|
|
28
|
+
'Stopping a tunnel should clear persisted tunnel intent.',
|
|
29
|
+
);
|
|
30
|
+
assert.match(
|
|
31
|
+
externalAccess,
|
|
32
|
+
/restoreRequestedTunnel/,
|
|
33
|
+
'Tunnel service should expose a startup restore hook.',
|
|
34
|
+
);
|
|
35
|
+
assert.match(
|
|
36
|
+
externalAccess,
|
|
37
|
+
/restoring/,
|
|
38
|
+
'Tunnel restore should distinguish automatic restart attempts from direct user starts.',
|
|
39
|
+
);
|
|
40
|
+
assert.match(
|
|
41
|
+
networkRoutes,
|
|
42
|
+
/persistPreference:\s*true/,
|
|
43
|
+
'Manual tunnel starts should persist the user preference through the network route.',
|
|
44
|
+
);
|
|
45
|
+
assert.match(
|
|
46
|
+
serverIndex,
|
|
47
|
+
/restoreRequestedTunnel/,
|
|
48
|
+
'Server startup should restore a requested tunnel after updates/restarts.',
|
|
49
|
+
);
|
|
50
|
+
assert.match(
|
|
51
|
+
serverIndex,
|
|
52
|
+
/restoreRequestedTunnel\(\{ port: Number\(SERVER_PORT\) \}\)/,
|
|
53
|
+
'Server startup should restore the tunnel against the current backend port.',
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
console.log('tunnel persistence smoke passed');
|