@leanandmean/coding-agent 0.74.1-scramjet.72 → 0.74.1-scramjet.73

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.
@@ -3265,21 +3265,25 @@ export class InteractiveMode {
3265
3265
  if (this.isShuttingDown)
3266
3266
  return;
3267
3267
  this.isShuttingDown = true;
3268
- this.unregisterSignalHandlers();
3269
- // Drain any in-flight Kitty key release events before stopping.
3270
- // This prevents escape sequences from leaking to the parent shell over slow SSH.
3271
- await this.ui.terminal.drainInput(1000);
3272
- await this.settingsManager.flush();
3273
3268
  let exitCode = 0;
3274
3269
  try {
3275
- this.stop({ retainContent: this.settingsManager.getRetainTranscriptOnExit() });
3270
+ await this.ui.terminal.drainInput(1000);
3271
+ await this.settingsManager.flush();
3272
+ try {
3273
+ this.stop({ retainContent: this.settingsManager.getRetainTranscriptOnExit() });
3274
+ }
3275
+ catch (error) {
3276
+ await this.ui.terminal.flush?.();
3277
+ throw error;
3278
+ }
3279
+ await this.ui.terminal.flush?.();
3276
3280
  }
3277
3281
  catch (error) {
3278
3282
  exitCode = 1;
3279
- console.error(`Could not retain terminal history: ${error instanceof Error ? error.message : String(error)}`);
3283
+ console.error(`Could not stop terminal safely: ${error instanceof Error ? error.message : String(error)}`);
3280
3284
  }
3281
- await this.ui.terminal.flush?.();
3282
3285
  await this.runtimeHost.dispose();
3286
+ this.unregisterSignalHandlers();
3283
3287
  process.exit(exitCode);
3284
3288
  }
3285
3289
  emergencyTerminalExit() {
@@ -3317,7 +3321,9 @@ export class InteractiveMode {
3317
3321
  try {
3318
3322
  this.ui.stop();
3319
3323
  }
3320
- catch { }
3324
+ catch (releaseError) {
3325
+ console.error("Terminal release failed; exiting without restart:", releaseError);
3326
+ }
3321
3327
  console.error("pi exiting due to uncaughtException:");
3322
3328
  console.error(error);
3323
3329
  process.exit(1);
@@ -3384,12 +3390,13 @@ export class InteractiveMode {
3384
3390
  const ignoreSigint = () => { };
3385
3391
  process.on("SIGINT", ignoreSigint);
3386
3392
  // Set up handler to restore TUI when resumed
3387
- process.once("SIGCONT", () => {
3393
+ const resume = () => {
3388
3394
  clearInterval(suspendKeepAlive);
3389
3395
  process.removeListener("SIGINT", ignoreSigint);
3390
3396
  this.ui.start();
3391
3397
  this.ui.rebuild();
3392
- });
3398
+ };
3399
+ process.once("SIGCONT", resume);
3393
3400
  try {
3394
3401
  // SCRAMJET-DIVERGENCE: drain releases before handing keyboard ownership back to the shell.
3395
3402
  await this.ui.terminal.drainInput();
@@ -3400,6 +3407,7 @@ export class InteractiveMode {
3400
3407
  catch (error) {
3401
3408
  clearInterval(suspendKeepAlive);
3402
3409
  process.removeListener("SIGINT", ignoreSigint);
3410
+ process.removeListener("SIGCONT", resume);
3403
3411
  throw error;
3404
3412
  }
3405
3413
  }
@@ -3523,12 +3531,14 @@ export class InteractiveMode {
3523
3531
  }
3524
3532
  const currentText = this.editor.getExpandedText?.() ?? this.editor.getText();
3525
3533
  const tmpFile = path.join(os.tmpdir(), `pi-editor-${Date.now()}.pi.md`);
3534
+ let released = false;
3526
3535
  try {
3527
3536
  // Write current content to temp file
3528
3537
  fs.writeFileSync(tmpFile, currentText, "utf-8");
3529
3538
  // SCRAMJET-DIVERGENCE: the editor must not inherit the key release that opened it.
3530
3539
  await this.ui.terminal.drainInput();
3531
3540
  this.ui.stop();
3541
+ released = true;
3532
3542
  // Split by space to support editor arguments (e.g., "code --wait")
3533
3543
  const [editor, ...editorArgs] = editorCmd.split(" ");
3534
3544
  // Spawn editor synchronously with inherited stdio for interactive editing
@@ -3551,9 +3561,11 @@ export class InteractiveMode {
3551
3561
  catch {
3552
3562
  // Ignore cleanup errors
3553
3563
  }
3554
- // Restart TUI
3555
- this.ui.start();
3556
- this.ui.rebuild();
3564
+ // SCRAMJET-DIVERGENCE: failed release is not permission to reacquire inherited stdin.
3565
+ if (released) {
3566
+ this.ui.start();
3567
+ this.ui.rebuild();
3568
+ }
3557
3569
  }
3558
3570
  }
3559
3571
  // =========================================================================
@@ -5223,17 +5235,20 @@ export class InteractiveMode {
5223
5235
  }
5224
5236
  }
5225
5237
  stop(options) {
5238
+ let released = false;
5226
5239
  try {
5227
5240
  if (this.isInitialized) {
5228
- this.isInitialized = false;
5229
5241
  this.ui.stop(options);
5242
+ this.isInitialized = false;
5230
5243
  }
5244
+ released = true;
5231
5245
  }
5232
5246
  finally {
5233
5247
  this.selectorOpenGeneration++;
5234
5248
  this.pendingSelectorOpenGeneration = undefined;
5235
- this.unregisterSignalHandlers();
5236
- if (this.settingsManager.getShowTerminalProgress()) {
5249
+ if (!this.isShuttingDown)
5250
+ this.unregisterSignalHandlers();
5251
+ if (released && this.settingsManager.getShowTerminalProgress()) {
5237
5252
  this.ui.terminal.setProgress(false);
5238
5253
  }
5239
5254
  if (this.loadingAnimation) {