@pixelbyte-software/pixcode 1.50.6 → 1.50.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/dist/assets/{index-DVEXTVKy.js → index-gecaamTl.js} +156 -156
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +109 -2
- package/dist-server/server/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/hermes/pixcode-mcp-server.mjs +35 -14
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +22 -1
- package/scripts/smoke/hermes-settings-commands.mjs +76 -5
- package/scripts/smoke/pixcode-workbench-1-48.mjs +4 -3
- package/scripts/smoke/vscode-workbench-polish.mjs +11 -1
- package/server/index.js +121 -2
package/dist/index.html
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
<!-- Prevent zoom on iOS -->
|
|
37
37
|
<meta name="format-detection" content="telephone=no" />
|
|
38
|
-
<script type="module" crossorigin src="/assets/index-
|
|
38
|
+
<script type="module" crossorigin src="/assets/index-gecaamTl.js"></script>
|
|
39
39
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DB6V5Fl1.js">
|
|
40
40
|
<link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-CIYNS698.js">
|
|
41
41
|
<link rel="modulepreload" crossorigin href="/assets/vendor-xterm-C7tpxJl7.js">
|
|
@@ -118,6 +118,8 @@ let projectsWatchers = [];
|
|
|
118
118
|
let projectsWatcherDebounceTimer = null;
|
|
119
119
|
const connectedClients = new Set();
|
|
120
120
|
let isGetProjectsRunning = false; // Flag to prevent reentrant calls
|
|
121
|
+
const STARTUP_INPUT_READY_TIMEOUT_MS = 10 * 60 * 1000;
|
|
122
|
+
const STARTUP_INPUT_POLL_MS = 750;
|
|
121
123
|
// Broadcast progress to all connected WebSocket clients
|
|
122
124
|
function broadcastProgress(progress) {
|
|
123
125
|
const message = JSON.stringify({
|
|
@@ -244,6 +246,10 @@ function terminatePtySession(sessionKey, session, reason) {
|
|
|
244
246
|
if (session.timeoutId) {
|
|
245
247
|
clearTimeout(session.timeoutId);
|
|
246
248
|
}
|
|
249
|
+
if (session.startupInputTimerId) {
|
|
250
|
+
clearTimeout(session.startupInputTimerId);
|
|
251
|
+
session.startupInputTimerId = null;
|
|
252
|
+
}
|
|
247
253
|
try {
|
|
248
254
|
if (session.pty && session.pty.kill) {
|
|
249
255
|
session.pty.kill();
|
|
@@ -359,6 +365,88 @@ function appendPtySessionBuffer(session, data) {
|
|
|
359
365
|
session.buffer.push(data);
|
|
360
366
|
}
|
|
361
367
|
}
|
|
368
|
+
function normalizeTerminalStartupInput(input) {
|
|
369
|
+
return `\x15${String(input || '').replace(/(?:\r\n|\r|\n)+$/u, '')}\r`;
|
|
370
|
+
}
|
|
371
|
+
function readSessionOutputForState(session, maxChars = 12000) {
|
|
372
|
+
return stripAnsiSequences((session?.buffer || []).join('').slice(-maxChars));
|
|
373
|
+
}
|
|
374
|
+
function shouldWaitForProviderIdle(provider) {
|
|
375
|
+
return provider === 'codex';
|
|
376
|
+
}
|
|
377
|
+
function isTerminalReadyForStartupInput(session) {
|
|
378
|
+
if (!session?.pty || session.lifecycleState !== 'running') {
|
|
379
|
+
return { ready: false, retry: false, terminalState: 'exited' };
|
|
380
|
+
}
|
|
381
|
+
const output = readSessionOutputForState(session);
|
|
382
|
+
const state = resolveProviderTerminalState(session, session.provider, output);
|
|
383
|
+
if (state.terminalState === 'busy') {
|
|
384
|
+
return { ready: false, retry: true, terminalState: state.terminalState };
|
|
385
|
+
}
|
|
386
|
+
if (state.terminalState === 'idle') {
|
|
387
|
+
return { ready: true, retry: false, terminalState: state.terminalState };
|
|
388
|
+
}
|
|
389
|
+
if (shouldWaitForProviderIdle(session.provider)) {
|
|
390
|
+
return { ready: false, retry: true, terminalState: state.terminalState };
|
|
391
|
+
}
|
|
392
|
+
return { ready: true, retry: false, terminalState: state.terminalState };
|
|
393
|
+
}
|
|
394
|
+
function processTerminalStartupInputQueue(session) {
|
|
395
|
+
if (!session?.pendingStartupInputs?.length) {
|
|
396
|
+
session.startupInputTimerId = null;
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const item = session.pendingStartupInputs[0];
|
|
400
|
+
const readiness = isTerminalReadyForStartupInput(session);
|
|
401
|
+
if (!readiness.ready) {
|
|
402
|
+
if (!readiness.retry || Date.now() - item.queuedAt > STARTUP_INPUT_READY_TIMEOUT_MS) {
|
|
403
|
+
session.pendingStartupInputs.shift();
|
|
404
|
+
session.startupInputTimerId = null;
|
|
405
|
+
const message = `\r\n\x1b[33m[Pixcode] Startup input was not sent because ${session.provider} is still ${readiness.terminalState || 'unavailable'}.\x1b[0m\r\n`;
|
|
406
|
+
try {
|
|
407
|
+
session.ws?.send?.(JSON.stringify({ type: 'output', data: message }));
|
|
408
|
+
}
|
|
409
|
+
catch { /* websocket gone */ }
|
|
410
|
+
if (session.pendingStartupInputs.length > 0) {
|
|
411
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
session.pendingStartupInputs.shift();
|
|
419
|
+
session.startupInputTimerId = null;
|
|
420
|
+
try {
|
|
421
|
+
session.pty.write(normalizeTerminalStartupInput(item.startupInput));
|
|
422
|
+
session.updatedAt = Date.now();
|
|
423
|
+
console.log(`⌨️ Submitted startup input to visible PTY (${item.reason})`);
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
console.warn('Failed to submit startup input to visible PTY:', error?.message || error);
|
|
427
|
+
}
|
|
428
|
+
if (session.pendingStartupInputs.length > 0) {
|
|
429
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function queueTerminalStartupInput(session, startupInput, reason, delayMs = 500) {
|
|
433
|
+
if (!session?.pty || !startupInput)
|
|
434
|
+
return;
|
|
435
|
+
if (!Array.isArray(session.pendingStartupInputs)) {
|
|
436
|
+
session.pendingStartupInputs = [];
|
|
437
|
+
}
|
|
438
|
+
session.pendingStartupInputs.push({
|
|
439
|
+
startupInput,
|
|
440
|
+
reason,
|
|
441
|
+
queuedAt: Date.now(),
|
|
442
|
+
});
|
|
443
|
+
if (session.startupInputTimerId)
|
|
444
|
+
return;
|
|
445
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), delayMs);
|
|
446
|
+
}
|
|
447
|
+
function writeTerminalStartupInput(session, startupInput, reason, delayMs = 500) {
|
|
448
|
+
queueTerminalStartupInput(session, startupInput, reason, delayMs);
|
|
449
|
+
}
|
|
362
450
|
function normalizeShellPermissionMode(value) {
|
|
363
451
|
return typeof value === 'string' ? value.trim() : '';
|
|
364
452
|
}
|
|
@@ -2183,6 +2271,9 @@ function handleShellConnection(ws, request) {
|
|
|
2183
2271
|
const startupInput = typeof data.startupInput === 'string' && data.startupInput.trim()
|
|
2184
2272
|
? data.startupInput.trim()
|
|
2185
2273
|
: null;
|
|
2274
|
+
const startupInputDelivery = data.startupInputDelivery === 'terminal' ? 'terminal' : 'command';
|
|
2275
|
+
const commandStartupInput = startupInputDelivery === 'command' ? startupInput : null;
|
|
2276
|
+
const terminalStartupInput = startupInputDelivery === 'terminal' ? startupInput : null;
|
|
2186
2277
|
const hermesLaunchId = Number.isFinite(Number(data.hermesLaunchId)) && Number(data.hermesLaunchId) > 0
|
|
2187
2278
|
? Number(data.hermesLaunchId)
|
|
2188
2279
|
: null;
|
|
@@ -2263,6 +2354,11 @@ function handleShellConnection(ws, request) {
|
|
|
2263
2354
|
});
|
|
2264
2355
|
}
|
|
2265
2356
|
existingSession.ws = ws;
|
|
2357
|
+
existingSession.hermesLaunchId = hermesLaunchId || existingSession.hermesLaunchId;
|
|
2358
|
+
existingSession.updatedAt = Date.now();
|
|
2359
|
+
if (terminalStartupInput && !isPlainShell) {
|
|
2360
|
+
writeTerminalStartupInput(existingSession, terminalStartupInput, 'reused provider session', 350);
|
|
2361
|
+
}
|
|
2266
2362
|
return;
|
|
2267
2363
|
}
|
|
2268
2364
|
}
|
|
@@ -2340,8 +2436,8 @@ function handleShellConnection(ws, request) {
|
|
|
2340
2436
|
shellCommand = `${command} resume "${sessionId}" || ${command}`;
|
|
2341
2437
|
}
|
|
2342
2438
|
}
|
|
2343
|
-
else if (
|
|
2344
|
-
shellCommand = `${command} ${quoteShellArgForPlatform(
|
|
2439
|
+
else if (commandStartupInput) {
|
|
2440
|
+
shellCommand = `${command} ${quoteShellArgForPlatform(commandStartupInput)}`;
|
|
2345
2441
|
}
|
|
2346
2442
|
else {
|
|
2347
2443
|
shellCommand = command;
|
|
@@ -2475,8 +2571,14 @@ function handleShellConnection(ws, request) {
|
|
|
2475
2571
|
exitSignal: null,
|
|
2476
2572
|
completedAt: null,
|
|
2477
2573
|
keepAliveUntilExit: false,
|
|
2574
|
+
pendingStartupInputs: [],
|
|
2575
|
+
startupInputTimerId: null,
|
|
2478
2576
|
updatedAt: Date.now(),
|
|
2479
2577
|
});
|
|
2578
|
+
const createdSession = ptySessionsMap.get(ptySessionKey);
|
|
2579
|
+
if (terminalStartupInput && !isPlainShell) {
|
|
2580
|
+
writeTerminalStartupInput(createdSession, terminalStartupInput, 'new provider session', 4500);
|
|
2581
|
+
}
|
|
2480
2582
|
// Handle data output
|
|
2481
2583
|
shellProcess.onData((data) => {
|
|
2482
2584
|
const session = ptySessionsMap.get(ptySessionKey);
|
|
@@ -2535,6 +2637,11 @@ function handleShellConnection(ws, request) {
|
|
|
2535
2637
|
session.exitSignal = exitCode.signal || null;
|
|
2536
2638
|
session.completedAt = new Date().toISOString();
|
|
2537
2639
|
session.updatedAt = Date.now();
|
|
2640
|
+
if (session.startupInputTimerId) {
|
|
2641
|
+
clearTimeout(session.startupInputTimerId);
|
|
2642
|
+
session.startupInputTimerId = null;
|
|
2643
|
+
}
|
|
2644
|
+
session.pendingStartupInputs = [];
|
|
2538
2645
|
session.pty = null;
|
|
2539
2646
|
appendPtySessionBuffer(session, exitMessage);
|
|
2540
2647
|
}
|