@pixelbyte-software/pixcode 1.50.7 → 1.50.9
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-CR4j4iu_.js → index-CXTCtUku.js} +149 -149
- package/dist/assets/localMonaco-DFIbtDNp.js +1 -0
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +121 -14
- package/dist-server/server/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/hermes/pixcode-mcp-server.mjs +35 -14
- package/scripts/smoke/code-editor-vscode-engine.mjs +31 -0
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +22 -1
- package/scripts/smoke/hermes-settings-commands.mjs +45 -0
- package/server/index.js +134 -13
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{loader as r}from"./index-ak1p_4ew.js";import"./vendor-react-DB6V5Fl1.js";const e="/vendor/monaco-editor/min/vs";let o=!1;function i(){o||(r.config({paths:{vs:e}}),o=!0)}export{e as LOCAL_MONACO_BASE_PATH,i as ensureLocalMonaco};
|
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-CXTCtUku.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">
|
|
@@ -7,6 +7,7 @@ import path from 'path';
|
|
|
7
7
|
import os from 'os';
|
|
8
8
|
import http from 'http';
|
|
9
9
|
import net from 'node:net';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
10
11
|
import { spawn } from 'child_process';
|
|
11
12
|
import express from 'express';
|
|
12
13
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
@@ -17,6 +18,8 @@ const __dirname = getModuleDir(import.meta.url);
|
|
|
17
18
|
// The server source runs from /server, while the compiled output runs from /dist-server/server.
|
|
18
19
|
// Resolving the app root once keeps every repo-level lookup below aligned across both layouts.
|
|
19
20
|
const APP_ROOT = findAppRoot(__dirname);
|
|
21
|
+
const require = createRequire(import.meta.url);
|
|
22
|
+
const MONACO_ASSETS_ROUTE = '/vendor/monaco-editor/min/vs';
|
|
20
23
|
const installMode = fs.existsSync(path.join(APP_ROOT, '.git')) ? 'git' : 'npm';
|
|
21
24
|
const SERVER_VERSION = (() => {
|
|
22
25
|
try {
|
|
@@ -32,6 +35,21 @@ const DAEMON_COMMAND_CONTEXT = {
|
|
|
32
35
|
cliEntry: path.join(APP_ROOT, 'server', 'cli.js'),
|
|
33
36
|
nodeExecPath: process.execPath,
|
|
34
37
|
};
|
|
38
|
+
function resolveMonacoAssetsPath() {
|
|
39
|
+
const candidates = [
|
|
40
|
+
path.join(APP_ROOT, 'node_modules', 'monaco-editor', 'min', 'vs'),
|
|
41
|
+
];
|
|
42
|
+
try {
|
|
43
|
+
const monacoPackagePath = require.resolve('monaco-editor/package.json', {
|
|
44
|
+
paths: [APP_ROOT, __dirname],
|
|
45
|
+
});
|
|
46
|
+
candidates.push(path.join(path.dirname(monacoPackagePath), 'min', 'vs'));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// The editor will show its normal load failure if the dependency is unavailable.
|
|
50
|
+
}
|
|
51
|
+
return candidates.find((candidate) => fs.existsSync(path.join(candidate, 'loader.js'))) || null;
|
|
52
|
+
}
|
|
35
53
|
import { c } from './utils/colors.js';
|
|
36
54
|
console.log('SERVER_PORT from env:', process.env.SERVER_PORT);
|
|
37
55
|
import pty from 'node-pty';
|
|
@@ -118,6 +136,8 @@ let projectsWatchers = [];
|
|
|
118
136
|
let projectsWatcherDebounceTimer = null;
|
|
119
137
|
const connectedClients = new Set();
|
|
120
138
|
let isGetProjectsRunning = false; // Flag to prevent reentrant calls
|
|
139
|
+
const STARTUP_INPUT_READY_TIMEOUT_MS = 10 * 60 * 1000;
|
|
140
|
+
const STARTUP_INPUT_POLL_MS = 750;
|
|
121
141
|
// Broadcast progress to all connected WebSocket clients
|
|
122
142
|
function broadcastProgress(progress) {
|
|
123
143
|
const message = JSON.stringify({
|
|
@@ -244,6 +264,10 @@ function terminatePtySession(sessionKey, session, reason) {
|
|
|
244
264
|
if (session.timeoutId) {
|
|
245
265
|
clearTimeout(session.timeoutId);
|
|
246
266
|
}
|
|
267
|
+
if (session.startupInputTimerId) {
|
|
268
|
+
clearTimeout(session.startupInputTimerId);
|
|
269
|
+
session.startupInputTimerId = null;
|
|
270
|
+
}
|
|
247
271
|
try {
|
|
248
272
|
if (session.pty && session.pty.kill) {
|
|
249
273
|
session.pty.kill();
|
|
@@ -360,24 +384,86 @@ function appendPtySessionBuffer(session, data) {
|
|
|
360
384
|
}
|
|
361
385
|
}
|
|
362
386
|
function normalizeTerminalStartupInput(input) {
|
|
363
|
-
return
|
|
387
|
+
return `\x15${String(input || '').replace(/(?:\r\n|\r|\n)+$/u, '')}\r`;
|
|
364
388
|
}
|
|
365
|
-
function
|
|
366
|
-
|
|
389
|
+
function readSessionOutputForState(session, maxChars = 12000) {
|
|
390
|
+
return stripAnsiSequences((session?.buffer || []).join('').slice(-maxChars));
|
|
391
|
+
}
|
|
392
|
+
function shouldWaitForProviderIdle(provider) {
|
|
393
|
+
return provider === 'codex';
|
|
394
|
+
}
|
|
395
|
+
function isTerminalReadyForStartupInput(session) {
|
|
396
|
+
if (!session?.pty || session.lifecycleState !== 'running') {
|
|
397
|
+
return { ready: false, retry: false, terminalState: 'exited' };
|
|
398
|
+
}
|
|
399
|
+
const output = readSessionOutputForState(session);
|
|
400
|
+
const state = resolveProviderTerminalState(session, session.provider, output);
|
|
401
|
+
if (state.terminalState === 'busy') {
|
|
402
|
+
return { ready: false, retry: true, terminalState: state.terminalState };
|
|
403
|
+
}
|
|
404
|
+
if (state.terminalState === 'idle') {
|
|
405
|
+
return { ready: true, retry: false, terminalState: state.terminalState };
|
|
406
|
+
}
|
|
407
|
+
if (shouldWaitForProviderIdle(session.provider)) {
|
|
408
|
+
return { ready: false, retry: true, terminalState: state.terminalState };
|
|
409
|
+
}
|
|
410
|
+
return { ready: true, retry: false, terminalState: state.terminalState };
|
|
411
|
+
}
|
|
412
|
+
function processTerminalStartupInputQueue(session) {
|
|
413
|
+
if (!session?.pendingStartupInputs?.length) {
|
|
414
|
+
session.startupInputTimerId = null;
|
|
367
415
|
return;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
416
|
+
}
|
|
417
|
+
const item = session.pendingStartupInputs[0];
|
|
418
|
+
const readiness = isTerminalReadyForStartupInput(session);
|
|
419
|
+
if (!readiness.ready) {
|
|
420
|
+
if (!readiness.retry || Date.now() - item.queuedAt > STARTUP_INPUT_READY_TIMEOUT_MS) {
|
|
421
|
+
session.pendingStartupInputs.shift();
|
|
422
|
+
session.startupInputTimerId = null;
|
|
423
|
+
const message = `\r\n\x1b[33m[Pixcode] Startup input was not sent because ${session.provider} is still ${readiness.terminalState || 'unavailable'}.\x1b[0m\r\n`;
|
|
424
|
+
try {
|
|
425
|
+
session.ws?.send?.(JSON.stringify({ type: 'output', data: message }));
|
|
375
426
|
}
|
|
427
|
+
catch { /* websocket gone */ }
|
|
428
|
+
if (session.pendingStartupInputs.length > 0) {
|
|
429
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
430
|
+
}
|
|
431
|
+
return;
|
|
376
432
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
433
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
session.pendingStartupInputs.shift();
|
|
437
|
+
session.startupInputTimerId = null;
|
|
438
|
+
try {
|
|
439
|
+
session.pty.write(normalizeTerminalStartupInput(item.startupInput));
|
|
440
|
+
session.updatedAt = Date.now();
|
|
441
|
+
console.log(`⌨️ Submitted startup input to visible PTY (${item.reason})`);
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
console.warn('Failed to submit startup input to visible PTY:', error?.message || error);
|
|
445
|
+
}
|
|
446
|
+
if (session.pendingStartupInputs.length > 0) {
|
|
447
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), STARTUP_INPUT_POLL_MS);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function queueTerminalStartupInput(session, startupInput, reason, delayMs = 500) {
|
|
451
|
+
if (!session?.pty || !startupInput)
|
|
452
|
+
return;
|
|
453
|
+
if (!Array.isArray(session.pendingStartupInputs)) {
|
|
454
|
+
session.pendingStartupInputs = [];
|
|
455
|
+
}
|
|
456
|
+
session.pendingStartupInputs.push({
|
|
457
|
+
startupInput,
|
|
458
|
+
reason,
|
|
459
|
+
queuedAt: Date.now(),
|
|
460
|
+
});
|
|
461
|
+
if (session.startupInputTimerId)
|
|
462
|
+
return;
|
|
463
|
+
session.startupInputTimerId = setTimeout(() => processTerminalStartupInputQueue(session), delayMs);
|
|
464
|
+
}
|
|
465
|
+
function writeTerminalStartupInput(session, startupInput, reason, delayMs = 500) {
|
|
466
|
+
queueTerminalStartupInput(session, startupInput, reason, delayMs);
|
|
381
467
|
}
|
|
382
468
|
function normalizeShellPermissionMode(value) {
|
|
383
469
|
return typeof value === 'string' ? value.trim() : '';
|
|
@@ -664,6 +750,18 @@ app.use('/api/agent', agentRoutes);
|
|
|
664
750
|
// Static app files served after API routes. Keep dist before public so
|
|
665
751
|
// / and /index.html always resolve to the Pixcode app, not the GitHub Pages
|
|
666
752
|
// landing page that also lives in public/index.html.
|
|
753
|
+
const monacoAssetsPath = resolveMonacoAssetsPath();
|
|
754
|
+
if (monacoAssetsPath) {
|
|
755
|
+
app.use(MONACO_ASSETS_ROUTE, express.static(monacoAssetsPath, {
|
|
756
|
+
index: false,
|
|
757
|
+
setHeaders: (res) => {
|
|
758
|
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
759
|
+
},
|
|
760
|
+
}));
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
console.warn('[monaco] Local Monaco assets not found; code editor loader may fail.');
|
|
764
|
+
}
|
|
667
765
|
app.use(express.static(path.join(APP_ROOT, 'dist'), {
|
|
668
766
|
setHeaders: (res, filePath) => {
|
|
669
767
|
if (filePath.endsWith('.html')) {
|
|
@@ -2286,6 +2384,8 @@ function handleShellConnection(ws, request) {
|
|
|
2286
2384
|
});
|
|
2287
2385
|
}
|
|
2288
2386
|
existingSession.ws = ws;
|
|
2387
|
+
existingSession.hermesLaunchId = hermesLaunchId || existingSession.hermesLaunchId;
|
|
2388
|
+
existingSession.updatedAt = Date.now();
|
|
2289
2389
|
if (terminalStartupInput && !isPlainShell) {
|
|
2290
2390
|
writeTerminalStartupInput(existingSession, terminalStartupInput, 'reused provider session', 350);
|
|
2291
2391
|
}
|
|
@@ -2501,6 +2601,8 @@ function handleShellConnection(ws, request) {
|
|
|
2501
2601
|
exitSignal: null,
|
|
2502
2602
|
completedAt: null,
|
|
2503
2603
|
keepAliveUntilExit: false,
|
|
2604
|
+
pendingStartupInputs: [],
|
|
2605
|
+
startupInputTimerId: null,
|
|
2504
2606
|
updatedAt: Date.now(),
|
|
2505
2607
|
});
|
|
2506
2608
|
const createdSession = ptySessionsMap.get(ptySessionKey);
|
|
@@ -2565,6 +2667,11 @@ function handleShellConnection(ws, request) {
|
|
|
2565
2667
|
session.exitSignal = exitCode.signal || null;
|
|
2566
2668
|
session.completedAt = new Date().toISOString();
|
|
2567
2669
|
session.updatedAt = Date.now();
|
|
2670
|
+
if (session.startupInputTimerId) {
|
|
2671
|
+
clearTimeout(session.startupInputTimerId);
|
|
2672
|
+
session.startupInputTimerId = null;
|
|
2673
|
+
}
|
|
2674
|
+
session.pendingStartupInputs = [];
|
|
2568
2675
|
session.pty = null;
|
|
2569
2676
|
appendPtySessionBuffer(session, exitMessage);
|
|
2570
2677
|
}
|