@pixelbyte-software/pixcode 1.50.2 → 1.50.4
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-cXJ8K8Bi.js → index-DYQjBZrd.js} +164 -165
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +78 -2
- package/dist-server/server/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/hermes/pixcode-mcp-server.mjs +103 -14
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +61 -2
- package/scripts/smoke/hermes-rest-codex-launch.mjs +14 -0
- package/scripts/smoke/hermes-settings-commands.mjs +53 -2
- package/scripts/smoke/pixcode-workbench-1-48.mjs +5 -1
- package/scripts/smoke/vscode-workbench-polish.mjs +2 -2
- package/server/index.js +94 -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-DYQjBZrd.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">
|
|
@@ -264,6 +264,61 @@ function killProviderPtySessions(projectPath, provider) {
|
|
|
264
264
|
}
|
|
265
265
|
return killed;
|
|
266
266
|
}
|
|
267
|
+
function getLastRegexMatchIndex(text, pattern) {
|
|
268
|
+
let lastIndex = -1;
|
|
269
|
+
for (const match of text.matchAll(pattern)) {
|
|
270
|
+
lastIndex = match.index ?? lastIndex;
|
|
271
|
+
}
|
|
272
|
+
return lastIndex;
|
|
273
|
+
}
|
|
274
|
+
function detectProviderTerminalState(provider, output) {
|
|
275
|
+
const cleanOutput = String(output || '');
|
|
276
|
+
if (!cleanOutput.trim()) {
|
|
277
|
+
return {
|
|
278
|
+
terminalState: 'unknown',
|
|
279
|
+
isBusy: false,
|
|
280
|
+
terminalStateReason: 'empty_output',
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
if (/Process exited with code/iu.test(cleanOutput)) {
|
|
284
|
+
return {
|
|
285
|
+
terminalState: 'exited',
|
|
286
|
+
isBusy: false,
|
|
287
|
+
terminalStateReason: 'process_exit',
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const lastBusy = Math.max(getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*[•*]\s*(?:Working|Running|Thinking)\b/giu), getLastRegexMatchIndex(cleanOutput, /\bWorking\s*\([^)]*esc to interrupt[^)]*\)/giu), getLastRegexMatchIndex(cleanOutput, /\bmsg=interrupt\b/giu));
|
|
291
|
+
if (provider === 'codex') {
|
|
292
|
+
const lastPrompt = Math.max(getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*›(?:\s|$)/gu), getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*❯(?:\s|$)/gu));
|
|
293
|
+
if (lastBusy >= 0) {
|
|
294
|
+
const isBusy = lastPrompt <= lastBusy;
|
|
295
|
+
return {
|
|
296
|
+
terminalState: isBusy ? 'busy' : 'idle',
|
|
297
|
+
isBusy,
|
|
298
|
+
terminalStateReason: isBusy ? 'codex_busy_marker_after_prompt' : 'codex_prompt_after_busy_marker',
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (lastPrompt >= 0 && /(?:Initialized|Baseline check passed|I did not modify files|Use \/skills)/iu.test(cleanOutput)) {
|
|
302
|
+
return {
|
|
303
|
+
terminalState: 'idle',
|
|
304
|
+
isBusy: false,
|
|
305
|
+
terminalStateReason: 'codex_idle_prompt',
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (lastBusy >= 0) {
|
|
310
|
+
return {
|
|
311
|
+
terminalState: 'busy',
|
|
312
|
+
isBusy: true,
|
|
313
|
+
terminalStateReason: 'generic_busy_marker',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
terminalState: 'unknown',
|
|
318
|
+
isBusy: false,
|
|
319
|
+
terminalStateReason: 'no_known_marker',
|
|
320
|
+
};
|
|
321
|
+
}
|
|
267
322
|
function normalizeShellPermissionMode(value) {
|
|
268
323
|
return typeof value === 'string' ? value.trim() : '';
|
|
269
324
|
}
|
|
@@ -331,6 +386,9 @@ function quoteBashArg(value) {
|
|
|
331
386
|
function quotePowerShellArg(value) {
|
|
332
387
|
return `"${String(value).replace(/`/g, '``').replace(/\$/g, '`$').replace(/"/g, '`"')}"`;
|
|
333
388
|
}
|
|
389
|
+
function quoteShellArgForPlatform(value) {
|
|
390
|
+
return os.platform() === 'win32' ? quotePowerShellArg(value) : quoteBashArg(value);
|
|
391
|
+
}
|
|
334
392
|
const HERMES_CLI_COMMAND_PATTERN = /^hermes(?:\s+[A-Za-z0-9._:/=@+-]+)*\s*$/;
|
|
335
393
|
function isHermesCliCommand(command) {
|
|
336
394
|
return typeof command === 'string' && HERMES_CLI_COMMAND_PATTERN.test(command.trim());
|
|
@@ -436,6 +494,8 @@ app.get('/api/shell/sessions/provider-output', authenticateToken, (req, res) =>
|
|
|
436
494
|
const projectPath = typeof req.query.projectPath === 'string' && req.query.projectPath.trim()
|
|
437
495
|
? req.query.projectPath.trim()
|
|
438
496
|
: null;
|
|
497
|
+
const launchId = Number.parseInt(String(req.query.launchId || ''), 10);
|
|
498
|
+
const requestedLaunchId = Number.isFinite(launchId) && launchId > 0 ? launchId : null;
|
|
439
499
|
const maxChars = Math.min(20000, Math.max(1000, Number.parseInt(String(req.query.maxChars || '12000'), 10) || 12000));
|
|
440
500
|
if (!SHELL_CLI_PROVIDERS.has(provider)) {
|
|
441
501
|
return res.status(400).json({ error: 'Unsupported provider' });
|
|
@@ -445,7 +505,8 @@ app.get('/api/shell/sessions/provider-output', authenticateToken, (req, res) =>
|
|
|
445
505
|
for (const session of ptySessionsMap.values()) {
|
|
446
506
|
if (session?.provider === provider &&
|
|
447
507
|
!session?.isPlainShell &&
|
|
448
|
-
(!requestedProjectPath || path.resolve(session.projectPath || os.homedir()) === requestedProjectPath)
|
|
508
|
+
(!requestedProjectPath || path.resolve(session.projectPath || os.homedir()) === requestedProjectPath) &&
|
|
509
|
+
(!requestedLaunchId || session.hermesLaunchId === requestedLaunchId)) {
|
|
449
510
|
if (!matchedSession || (session.updatedAt || 0) > (matchedSession.updatedAt || 0)) {
|
|
450
511
|
matchedSession = session;
|
|
451
512
|
}
|
|
@@ -456,18 +517,23 @@ app.get('/api/shell/sessions/provider-output', authenticateToken, (req, res) =>
|
|
|
456
517
|
active: false,
|
|
457
518
|
provider,
|
|
458
519
|
projectPath: requestedProjectPath,
|
|
520
|
+
launchId: requestedLaunchId,
|
|
459
521
|
output: '',
|
|
460
522
|
message: 'No active provider terminal session found for this project.',
|
|
461
523
|
});
|
|
462
524
|
}
|
|
463
525
|
const rawOutput = matchedSession.buffer.join('').slice(-maxChars);
|
|
526
|
+
const output = stripAnsiSequences(rawOutput);
|
|
527
|
+
const terminalState = detectProviderTerminalState(provider, output);
|
|
464
528
|
res.json({
|
|
465
529
|
active: true,
|
|
466
530
|
provider,
|
|
467
531
|
projectPath: path.resolve(matchedSession.projectPath || os.homedir()),
|
|
468
532
|
sessionId: matchedSession.sessionId || null,
|
|
533
|
+
launchId: matchedSession.hermesLaunchId || null,
|
|
469
534
|
updatedAt: matchedSession.updatedAt || null,
|
|
470
|
-
|
|
535
|
+
...terminalState,
|
|
536
|
+
output,
|
|
471
537
|
});
|
|
472
538
|
});
|
|
473
539
|
// Authentication routes (public)
|
|
@@ -2074,6 +2140,12 @@ function handleShellConnection(ws, request) {
|
|
|
2074
2140
|
const hasSession = data.hasSession;
|
|
2075
2141
|
const provider = data.provider || 'claude';
|
|
2076
2142
|
const initialCommand = data.initialCommand;
|
|
2143
|
+
const startupInput = typeof data.startupInput === 'string' && data.startupInput.trim()
|
|
2144
|
+
? data.startupInput.trim()
|
|
2145
|
+
: null;
|
|
2146
|
+
const hermesLaunchId = Number.isFinite(Number(data.hermesLaunchId)) && Number(data.hermesLaunchId) > 0
|
|
2147
|
+
? Number(data.hermesLaunchId)
|
|
2148
|
+
: null;
|
|
2077
2149
|
const isPlainShell = data.isPlainShell || (!!initialCommand && !hasSession) || provider === 'plain-shell';
|
|
2078
2150
|
const isHermesCliLaunch = isPlainShell && isHermesCliCommand(initialCommand);
|
|
2079
2151
|
const forceNewSession = Boolean(data.forceNewSession);
|
|
@@ -2223,6 +2295,9 @@ function handleShellConnection(ws, request) {
|
|
|
2223
2295
|
shellCommand = `${command} resume "${sessionId}" || ${command}`;
|
|
2224
2296
|
}
|
|
2225
2297
|
}
|
|
2298
|
+
else if (startupInput) {
|
|
2299
|
+
shellCommand = `${command} ${quoteShellArgForPlatform(startupInput)}`;
|
|
2300
|
+
}
|
|
2226
2301
|
else {
|
|
2227
2302
|
shellCommand = command;
|
|
2228
2303
|
}
|
|
@@ -2347,6 +2422,7 @@ function handleShellConnection(ws, request) {
|
|
|
2347
2422
|
timeoutId: null,
|
|
2348
2423
|
projectPath,
|
|
2349
2424
|
sessionId,
|
|
2425
|
+
hermesLaunchId,
|
|
2350
2426
|
provider,
|
|
2351
2427
|
isPlainShell,
|
|
2352
2428
|
keepAliveUntilExit: false,
|