@pixelbyte-software/pixcode 1.50.5 → 1.50.7

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/server/index.js CHANGED
@@ -352,11 +352,12 @@ function detectProviderTerminalState(provider, output) {
352
352
  };
353
353
  }
354
354
 
355
- const lastBusy = Math.max(
356
- getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*[•*]\s*(?:Working|Running|Thinking)\b/giu),
355
+ const lastWeakBusy = getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*[•*]\s*(?:Working|Running|Thinking)\b/giu);
356
+ const lastStrongBusy = Math.max(
357
357
  getLastRegexMatchIndex(cleanOutput, /\bWorking\s*\([^)]*esc to interrupt[^)]*\)/giu),
358
358
  getLastRegexMatchIndex(cleanOutput, /\bmsg=interrupt\b/giu),
359
359
  );
360
+ const lastBusy = Math.max(lastWeakBusy, lastStrongBusy);
360
361
 
361
362
  if (provider === 'codex') {
362
363
  const lastPrompt = Math.max(
@@ -364,20 +365,20 @@ function detectProviderTerminalState(provider, output) {
364
365
  getLastRegexMatchIndex(cleanOutput, /(?:^|\n)\s*❯(?:\s|$)/gu),
365
366
  );
366
367
 
367
- if (lastBusy >= 0) {
368
- const isBusy = lastPrompt <= lastBusy;
368
+ if (lastPrompt >= 0) {
369
+ const isBusy = lastStrongBusy > lastPrompt;
369
370
  return {
370
371
  terminalState: isBusy ? 'busy' : 'idle',
371
372
  isBusy,
372
- terminalStateReason: isBusy ? 'codex_busy_marker_after_prompt' : 'codex_prompt_after_busy_marker',
373
+ terminalStateReason: isBusy ? 'codex_strong_busy_marker_after_prompt' : 'codex_prompt_after_busy_marker',
373
374
  };
374
375
  }
375
376
 
376
- if (lastPrompt >= 0 && /(?:Initialized|Baseline check passed|I did not modify files|Use \/skills)/iu.test(cleanOutput)) {
377
+ if (lastBusy >= 0) {
377
378
  return {
378
- terminalState: 'idle',
379
- isBusy: false,
380
- terminalStateReason: 'codex_idle_prompt',
379
+ terminalState: 'busy',
380
+ isBusy: true,
381
+ terminalStateReason: 'codex_busy_marker_without_prompt',
381
382
  };
382
383
  }
383
384
  }
@@ -434,6 +435,26 @@ function appendPtySessionBuffer(session, data) {
434
435
  }
435
436
  }
436
437
 
438
+ function normalizeTerminalStartupInput(input) {
439
+ return `${String(input || '').replace(/(?:\r\n|\r|\n)+$/u, '')}\r`;
440
+ }
441
+
442
+ function writeTerminalStartupInput(session, startupInput, reason, delayMs = 500) {
443
+ if (!session?.pty || !startupInput) return;
444
+ const submittedInput = normalizeTerminalStartupInput(startupInput);
445
+ setTimeout(() => {
446
+ try {
447
+ if (session.pty && session.lifecycleState === 'running') {
448
+ session.pty.write(submittedInput);
449
+ session.updatedAt = Date.now();
450
+ console.log(`⌨️ Submitted startup input to visible PTY (${reason})`);
451
+ }
452
+ } catch (error) {
453
+ console.warn('Failed to submit startup input to visible PTY:', error?.message || error);
454
+ }
455
+ }, delayMs);
456
+ }
457
+
437
458
  function normalizeShellPermissionMode(value) {
438
459
  return typeof value === 'string' ? value.trim() : '';
439
460
  }
@@ -2386,6 +2407,9 @@ function handleShellConnection(ws, request) {
2386
2407
  const startupInput = typeof data.startupInput === 'string' && data.startupInput.trim()
2387
2408
  ? data.startupInput.trim()
2388
2409
  : null;
2410
+ const startupInputDelivery = data.startupInputDelivery === 'terminal' ? 'terminal' : 'command';
2411
+ const commandStartupInput = startupInputDelivery === 'command' ? startupInput : null;
2412
+ const terminalStartupInput = startupInputDelivery === 'terminal' ? startupInput : null;
2389
2413
  const hermesLaunchId = Number.isFinite(Number(data.hermesLaunchId)) && Number(data.hermesLaunchId) > 0
2390
2414
  ? Number(data.hermesLaunchId)
2391
2415
  : null;
@@ -2473,6 +2497,9 @@ function handleShellConnection(ws, request) {
2473
2497
  }
2474
2498
 
2475
2499
  existingSession.ws = ws;
2500
+ if (terminalStartupInput && !isPlainShell) {
2501
+ writeTerminalStartupInput(existingSession, terminalStartupInput, 'reused provider session', 350);
2502
+ }
2476
2503
 
2477
2504
  return;
2478
2505
  }
@@ -2550,8 +2577,8 @@ function handleShellConnection(ws, request) {
2550
2577
  } else {
2551
2578
  shellCommand = `${command} resume "${sessionId}" || ${command}`;
2552
2579
  }
2553
- } else if (startupInput) {
2554
- shellCommand = `${command} ${quoteShellArgForPlatform(startupInput)}`;
2580
+ } else if (commandStartupInput) {
2581
+ shellCommand = `${command} ${quoteShellArgForPlatform(commandStartupInput)}`;
2555
2582
  } else {
2556
2583
  shellCommand = command;
2557
2584
  }
@@ -2683,6 +2710,10 @@ function handleShellConnection(ws, request) {
2683
2710
  keepAliveUntilExit: false,
2684
2711
  updatedAt: Date.now(),
2685
2712
  });
2713
+ const createdSession = ptySessionsMap.get(ptySessionKey);
2714
+ if (terminalStartupInput && !isPlainShell) {
2715
+ writeTerminalStartupInput(createdSession, terminalStartupInput, 'new provider session', 4500);
2716
+ }
2686
2717
 
2687
2718
  // Handle data output
2688
2719
  shellProcess.onData((data) => {
@@ -2749,6 +2780,11 @@ function handleShellConnection(ws, request) {
2749
2780
  shellProcess.onExit((exitCode) => {
2750
2781
  console.log('🔚 Shell process exited with code:', exitCode.exitCode, 'signal:', exitCode.signal);
2751
2782
  const session = ptySessionsMap.get(ptySessionKey);
2783
+ if (session?.pty && session.pty !== shellProcess) {
2784
+ console.log('↩️ Ignoring stale PTY exit for replacement session:', ptySessionKey);
2785
+ return;
2786
+ }
2787
+
2752
2788
  const exitMessage = `\r\n\x1b[33mProcess exited with code ${exitCode.exitCode}${exitCode.signal ? ` (${exitCode.signal})` : ''}\x1b[0m\r\n`;
2753
2789
  if (session) {
2754
2790
  session.lifecycleState = exitCode.exitCode === 0 && !exitCode.signal ? 'completed' : 'failed';
@@ -30,6 +30,7 @@ type HermesTerminalLaunchEvent = {
30
30
  projectPath: string | null;
31
31
  prompt: string | null;
32
32
  startupInput: string | null;
33
+ forceNewSession: boolean;
33
34
  permissionMode: string | null;
34
35
  skipPermissions: boolean;
35
36
  bypassPermissions: boolean;
@@ -473,6 +474,7 @@ export function createHermesRouter(options: HermesRouterOptions = {}): Router {
473
474
  const prompt = readTrimmedString(body.prompt ?? body.reason);
474
475
  const requestedStartupInput = readTrimmedString(body.startupInput ?? body.input);
475
476
  const startupInput = requestedStartupInput ?? (isLegacyPromptLikelyStartupInput(prompt) ? prompt : null);
477
+ const forceNewSession = readBoolean(body.forceNewSession ?? body.newSession ?? body.freshSession);
476
478
  const bypassPermissions = readBoolean(body.bypassPermissions);
477
479
  const skipPermissions = readBoolean(body.skipPermissions) || bypassPermissions;
478
480
  const requestedPermissionMode = readTrimmedString(body.permissionMode);
@@ -484,6 +486,7 @@ export function createHermesRouter(options: HermesRouterOptions = {}): Router {
484
486
  projectPath,
485
487
  prompt,
486
488
  startupInput,
489
+ forceNewSession,
487
490
  permissionMode,
488
491
  skipPermissions,
489
492
  bypassPermissions,