@elyracode/coding-agent 0.9.1 → 0.9.2

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.
@@ -3031,8 +3031,8 @@ export class InteractiveMode {
3031
3031
  this.ui.requestRender();
3032
3032
  }
3033
3033
  showPackageUpdateNotification(packages) {
3034
- const action = theme.fg("accent", `${APP_NAME} update`);
3035
- const updateInstruction = theme.fg("muted", "Package updates are available. Run ") + action;
3034
+ const action = theme.fg("accent", "/update");
3035
+ const updateInstruction = theme.fg("muted", "Extension updates are available. Type ") + action;
3036
3036
  const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
3037
3037
  this.chatContainer.addChild(new Spacer(1));
3038
3038
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
@@ -3528,71 +3528,114 @@ export class InteractiveMode {
3528
3528
  }
3529
3529
  }
3530
3530
  async handleInAppUpdate() {
3531
- // If no update detected yet, check now
3531
+ if (process.env.ELYRA_OFFLINE) {
3532
+ this.showStatus("Updates are disabled in offline mode.");
3533
+ return;
3534
+ }
3535
+ this.chatContainer.addChild(new Spacer(1));
3536
+ const statusText = new Text(theme.fg("dim", "Checking for updates..."), 1, 0);
3537
+ this.chatContainer.addChild(statusText);
3538
+ this.ui.requestRender();
3539
+ // Check for an Elyra version update (populates this._availableUpdate).
3532
3540
  if (!this._availableUpdate) {
3533
3541
  await this.checkForVersionUpdate();
3534
3542
  }
3535
- if (!this._availableUpdate) {
3536
- this.showStatus(`Already on latest version (${this.version})`);
3543
+ const elyraUpdate = this._availableUpdate;
3544
+ // Check for installed-extension updates.
3545
+ const packageManager = new DefaultPackageManager({
3546
+ cwd: this.sessionManager.getCwd(),
3547
+ agentDir: getAgentDir(),
3548
+ settingsManager: this.settingsManager,
3549
+ });
3550
+ let extensionUpdates = [];
3551
+ try {
3552
+ extensionUpdates = await packageManager.checkForAvailableUpdates();
3553
+ }
3554
+ catch {
3555
+ // Best-effort: a failed extension check shouldn't block an Elyra update.
3556
+ }
3557
+ if (!elyraUpdate && extensionUpdates.length === 0) {
3558
+ statusText.setText(theme.fg("dim", `Already up to date (Elyra ${this.version}, all extensions current)`));
3559
+ this.ui.requestRender();
3537
3560
  return;
3538
3561
  }
3539
- const { latest, current } = this._availableUpdate;
3540
- // Get the self-update command for this installation
3541
- const settingsManager = this.settingsManager;
3542
- const npmCommand = settingsManager.getGlobalSettings().npmCommand;
3543
- const selfUpdateCommand = getSelfUpdateCommand(PACKAGE_NAME, npmCommand);
3544
- if (!selfUpdateCommand) {
3545
- this.showError(`Cannot self-update this installation. Run manually:\n ${theme.fg("accent", `npm install -g ${PACKAGE_NAME}`)}`);
3562
+ // If an Elyra update is available, make sure we can actually self-update.
3563
+ let selfUpdateCommand;
3564
+ if (elyraUpdate) {
3565
+ const npmCommand = this.settingsManager.getGlobalSettings().npmCommand;
3566
+ selfUpdateCommand = getSelfUpdateCommand(PACKAGE_NAME, npmCommand);
3567
+ if (!selfUpdateCommand) {
3568
+ statusText.setText(theme.fg("error", `Cannot self-update this installation. Update Elyra manually: npm install -g ${PACKAGE_NAME}`));
3569
+ this.ui.requestRender();
3570
+ // We can still update extensions below.
3571
+ }
3572
+ }
3573
+ // Nothing actionable: Elyra can't self-update and there are no extension updates.
3574
+ if (extensionUpdates.length === 0 && !(elyraUpdate && selfUpdateCommand)) {
3546
3575
  return;
3547
3576
  }
3548
- // Show progress
3549
- this.chatContainer.addChild(new Spacer(1));
3550
- const updateText = new Text(theme.fg("accent", `Updating ${current} \u2192 ${latest}...`), 1, 0);
3551
- this.chatContainer.addChild(updateText);
3577
+ // Announce what is being updated.
3578
+ const parts = [];
3579
+ if (elyraUpdate && selfUpdateCommand)
3580
+ parts.push(`Elyra ${elyraUpdate.current} \u2192 ${elyraUpdate.latest}`);
3581
+ if (extensionUpdates.length > 0) {
3582
+ parts.push(`${extensionUpdates.length} extension${extensionUpdates.length === 1 ? "" : "s"}`);
3583
+ }
3584
+ statusText.setText(theme.fg("accent", `Updating ${parts.join(" and ")}...`));
3552
3585
  this.ui.requestRender();
3553
- try {
3554
- // Run each step of the update command
3555
- for (const step of selfUpdateCommand.steps ?? [selfUpdateCommand]) {
3556
- await new Promise((resolve, reject) => {
3557
- const child = spawn(step.command, step.args, {
3558
- stdio: ["ignore", "pipe", "pipe"],
3559
- shell: process.platform === "win32",
3560
- });
3561
- let stderr = "";
3562
- child.stderr?.on("data", (data) => {
3563
- stderr += data.toString();
3564
- });
3565
- child.on("close", (code) => {
3566
- if (code === 0)
3567
- resolve();
3568
- else
3569
- reject(new Error(stderr.trim() || `Exit code ${code}`));
3570
- });
3571
- child.on("error", reject);
3572
- });
3586
+ // 1. Update extensions while Elyra is still running.
3587
+ if (extensionUpdates.length > 0) {
3588
+ try {
3589
+ await packageManager.update();
3590
+ }
3591
+ catch (error) {
3592
+ const msg = error instanceof Error ? error.message : String(error);
3593
+ this.showError(`Extension update failed: ${msg}`);
3573
3594
  }
3574
- // Success — show message and restart
3575
- updateText.setText(theme.fg("accent", `Updated to ${latest}. Restarting...`));
3576
- this.ui.requestRender();
3577
- // Brief pause so the user sees the message
3578
- await new Promise((r) => setTimeout(r, 500));
3579
- // Restart: stop TUI, then exec the same command
3580
- this.stop();
3581
- await this.runtimeHost.dispose();
3582
- // Re-exec elyra with the same arguments
3583
- const args = process.argv.slice(1);
3584
- const child = spawn(process.argv[0], args, {
3585
- stdio: "inherit",
3586
- shell: false,
3587
- });
3588
- child.on("close", (code) => {
3589
- process.exit(code ?? 0);
3590
- });
3591
3595
  }
3592
- catch (error) {
3593
- const msg = error instanceof Error ? error.message : String(error);
3594
- this.showError(`Update failed: ${msg}\n\nRun manually: ${selfUpdateCommand.display}`);
3596
+ // 2. Self-update Elyra if a newer version is available and updatable.
3597
+ if (elyraUpdate && selfUpdateCommand) {
3598
+ try {
3599
+ for (const step of selfUpdateCommand.steps ?? [selfUpdateCommand]) {
3600
+ await new Promise((resolve, reject) => {
3601
+ const child = spawn(step.command, step.args, {
3602
+ stdio: ["ignore", "pipe", "pipe"],
3603
+ shell: process.platform === "win32",
3604
+ });
3605
+ let stderr = "";
3606
+ child.stderr?.on("data", (data) => {
3607
+ stderr += data.toString();
3608
+ });
3609
+ child.on("close", (code) => {
3610
+ if (code === 0)
3611
+ resolve();
3612
+ else
3613
+ reject(new Error(stderr.trim() || `Exit code ${code}`));
3614
+ });
3615
+ child.on("error", reject);
3616
+ });
3617
+ }
3618
+ }
3619
+ catch (error) {
3620
+ const msg = error instanceof Error ? error.message : String(error);
3621
+ this.showError(`Elyra update failed: ${msg}\n\nRun manually: ${selfUpdateCommand.display}`);
3622
+ return;
3623
+ }
3595
3624
  }
3625
+ // 3. Restart so the new Elyra and/or updated extensions load fresh.
3626
+ statusText.setText(theme.fg("accent", "Updated. Restarting..."));
3627
+ this.ui.requestRender();
3628
+ await new Promise((r) => setTimeout(r, 500));
3629
+ this.stop();
3630
+ await this.runtimeHost.dispose();
3631
+ const args = process.argv.slice(1);
3632
+ const child = spawn(process.argv[0], args, {
3633
+ stdio: "inherit",
3634
+ shell: false,
3635
+ });
3636
+ child.on("close", (code) => {
3637
+ process.exit(code ?? 0);
3638
+ });
3596
3639
  }
3597
3640
  handleGoalCommand(args) {
3598
3641
  // No args = show or clear goal