@spencer-kit/coder-studio 0.4.6 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [#64](https://github.com/spencerkit/coder-studio/pull/64) [`d14fe08`](https://github.com/spencerkit/coder-studio/commit/d14fe08d7861652a9290559d5a59aa766c286309) Thanks [@pallyoung](https://github.com/pallyoung)! - Refine workspace theming and session ergonomics by adding pane drag reordering,
8
+ stabilizing update checks, hardening PTY color environment isolation, and
9
+ polishing shared desktop surfaces across the app.
10
+
3
11
  ## 0.4.6
4
12
 
5
13
  ### Patch Changes
package/dist/esm/bin.mjs CHANGED
@@ -12253,6 +12253,13 @@ var init_manager5 = __esm({
12253
12253
  ...derivedColorFgBg ? { COLORFGBG: derivedColorFgBg } : {},
12254
12254
  ...spec.env
12255
12255
  };
12256
+ delete terminalEnv.COLORFGBG;
12257
+ if (derivedColorFgBg) {
12258
+ terminalEnv.COLORFGBG = derivedColorFgBg;
12259
+ }
12260
+ if (spec.env?.COLORFGBG) {
12261
+ terminalEnv.COLORFGBG = spec.env.COLORFGBG;
12262
+ }
12256
12263
  let pty;
12257
12264
  try {
12258
12265
  pty = this.deps.ptyHost.spawn(spec.argv, {
@@ -12652,7 +12659,7 @@ var init_update_service = __esm({
12652
12659
  "packages/server/src/update/update-service.ts"() {
12653
12660
  "use strict";
12654
12661
  init_src3();
12655
- UpdateService = class {
12662
+ UpdateService = class _UpdateService {
12656
12663
  constructor(deps) {
12657
12664
  this.deps = deps;
12658
12665
  this.now = deps.now ?? Date.now;
@@ -12674,12 +12681,14 @@ var init_update_service = __esm({
12674
12681
  this.spawnDetachedWorkerImpl = deps.spawnDetachedWorker;
12675
12682
  }
12676
12683
  deps;
12684
+ static CHECK_TIMEOUT_MS = 15e3;
12677
12685
  now;
12678
12686
  runtime;
12679
12687
  updateWorkerLogFilePath;
12680
12688
  runLatestVersionLookup;
12681
12689
  spawnDetachedWorkerImpl;
12682
12690
  scheduleTimer = null;
12691
+ inFlightCheck = null;
12683
12692
  start() {
12684
12693
  this.reconcileOnStartup();
12685
12694
  this.reloadScheduleFromSettings();
@@ -12710,10 +12719,8 @@ var init_update_service = __esm({
12710
12719
  this.scheduleTimer.unref?.();
12711
12720
  }
12712
12721
  getStateView() {
12713
- return {
12714
- ...this.deps.updateStateRepo.get(),
12715
- ...this.getSupportInfo()
12716
- };
12722
+ const persisted = this.deps.updateStateRepo.get();
12723
+ return this.composeStateView(persisted);
12717
12724
  }
12718
12725
  getPrepareInstallState() {
12719
12726
  const state = this.getStateView();
@@ -12730,36 +12737,15 @@ var init_update_service = __esm({
12730
12737
  if (current.updateStatus === "installing" || current.updateStatus === "restarting") {
12731
12738
  throw createBusyError("Update installation is already in progress");
12732
12739
  }
12733
- if (current.updateStatus === "checking") {
12740
+ if (this.inFlightCheck) {
12734
12741
  throw createBusyError("Update check is already in progress");
12735
12742
  }
12736
- this.persistAndBroadcast({
12737
- updateStatus: "checking",
12738
- finishedAt: null,
12739
- errorSummary: null
12740
- });
12743
+ this.inFlightCheck = this.runCheckForUpdates();
12744
+ this.broadcastStateChange();
12741
12745
  try {
12742
- const latestVersion = await this.runLatestVersionLookup(this.runtime.packageName);
12743
- const availability = compareVersions(latestVersion, this.runtime.currentVersion) > 0 ? "update_available" : "up_to_date";
12744
- return this.persistAndBroadcast({
12745
- currentVersion: this.runtime.currentVersion,
12746
- latestVersion,
12747
- availability,
12748
- updateStatus: "idle",
12749
- lastCheckedAt: this.now(),
12750
- errorSummary: null,
12751
- requiresManualStep: false,
12752
- manualCommand: null
12753
- });
12754
- } catch (error) {
12755
- const message = error instanceof Error ? error.message : String(error);
12756
- return this.persistAndBroadcast({
12757
- currentVersion: this.runtime.currentVersion,
12758
- availability: "check_failed",
12759
- updateStatus: "idle",
12760
- lastCheckedAt: this.now(),
12761
- errorSummary: message
12762
- });
12746
+ return await this.inFlightCheck;
12747
+ } finally {
12748
+ this.inFlightCheck = null;
12763
12749
  }
12764
12750
  }
12765
12751
  prepareInstall() {
@@ -12774,6 +12760,9 @@ var init_update_service = __esm({
12774
12760
  if (state.updateStatus === "installing" || state.updateStatus === "restarting") {
12775
12761
  throw createBusyError("Update installation is already in progress");
12776
12762
  }
12763
+ if (this.inFlightCheck) {
12764
+ throw createBusyError("Update check is already in progress");
12765
+ }
12777
12766
  const targetVersion = input2.targetVersion ?? state.latestVersion;
12778
12767
  if (!targetVersion) {
12779
12768
  throw createValidationError("update_no_target", "No target version is available");
@@ -12848,6 +12837,15 @@ var init_update_service = __esm({
12848
12837
  errorSummary: null
12849
12838
  });
12850
12839
  }
12840
+ if (current.updateStatus === "checking") {
12841
+ return this.persistAndBroadcast({
12842
+ currentVersion: this.runtime.currentVersion,
12843
+ availability: "check_failed",
12844
+ updateStatus: "failed",
12845
+ finishedAt: this.now(),
12846
+ errorSummary: "Update check did not complete before the service restarted"
12847
+ });
12848
+ }
12851
12849
  if (current.updateStatus === "installing" || current.updateStatus === "restarting") {
12852
12850
  return this.persistAndBroadcast({
12853
12851
  currentVersion: this.runtime.currentVersion,
@@ -12898,18 +12896,6 @@ var init_update_service = __esm({
12898
12896
  hasActiveWork: runningTerminalCount > 0 || runningSessionCount > 0 || runningSupervisorCount > 0
12899
12897
  };
12900
12898
  }
12901
- persistAndBroadcast(patch) {
12902
- const snapshot = this.deps.updateStateRepo.update((current) => ({
12903
- ...patch,
12904
- currentVersion: patch.currentVersion ?? current.currentVersion
12905
- }));
12906
- const view = {
12907
- ...snapshot,
12908
- ...this.getSupportInfo()
12909
- };
12910
- this.deps.broadcaster.broadcast("update.state.changed", view);
12911
- return view;
12912
- }
12913
12899
  buildManualCommand(targetVersion) {
12914
12900
  return [
12915
12901
  `${this.runtime.npmCommand ?? "npm"} install -g ${this.runtime.packageName}@${targetVersion}`,
@@ -12939,6 +12925,83 @@ var init_update_service = __esm({
12939
12925
  });
12940
12926
  child.unref();
12941
12927
  }
12928
+ composeStateView(snapshot, options) {
12929
+ if (options?.includeInFlightCheck !== false && this.inFlightCheck) {
12930
+ return {
12931
+ ...snapshot,
12932
+ ...this.getSupportInfo(),
12933
+ updateStatus: "checking",
12934
+ errorSummary: null
12935
+ };
12936
+ }
12937
+ return {
12938
+ ...snapshot,
12939
+ ...this.getSupportInfo()
12940
+ };
12941
+ }
12942
+ broadcastStateChange() {
12943
+ this.deps.broadcaster.broadcast("update.state.changed", this.getStateView());
12944
+ }
12945
+ async runCheckForUpdates() {
12946
+ try {
12947
+ const latestVersion = await this.withCheckTimeout(
12948
+ this.runLatestVersionLookup(this.runtime.packageName)
12949
+ );
12950
+ const availability = compareVersions(latestVersion, this.runtime.currentVersion) > 0 ? "update_available" : "up_to_date";
12951
+ return this.persistAndBroadcast(
12952
+ {
12953
+ currentVersion: this.runtime.currentVersion,
12954
+ latestVersion,
12955
+ availability,
12956
+ updateStatus: "idle",
12957
+ lastCheckedAt: this.now(),
12958
+ errorSummary: null,
12959
+ requiresManualStep: false,
12960
+ manualCommand: null
12961
+ },
12962
+ false
12963
+ );
12964
+ } catch (error) {
12965
+ const message = error instanceof Error ? error.message : String(error);
12966
+ return this.persistAndBroadcast(
12967
+ {
12968
+ currentVersion: this.runtime.currentVersion,
12969
+ availability: "check_failed",
12970
+ updateStatus: "idle",
12971
+ lastCheckedAt: this.now(),
12972
+ errorSummary: message
12973
+ },
12974
+ false
12975
+ );
12976
+ }
12977
+ }
12978
+ async withCheckTimeout(promise) {
12979
+ let timeoutHandle = null;
12980
+ try {
12981
+ return await Promise.race([
12982
+ promise,
12983
+ new Promise((_, reject) => {
12984
+ timeoutHandle = setTimeout(() => {
12985
+ reject(new Error(`Update check timed out after ${_UpdateService.CHECK_TIMEOUT_MS}ms`));
12986
+ }, _UpdateService.CHECK_TIMEOUT_MS);
12987
+ timeoutHandle.unref?.();
12988
+ })
12989
+ ]);
12990
+ } finally {
12991
+ if (timeoutHandle) {
12992
+ clearTimeout(timeoutHandle);
12993
+ }
12994
+ }
12995
+ }
12996
+ persistAndBroadcast(patch, includeInFlightCheck = true) {
12997
+ const snapshot = this.deps.updateStateRepo.update((current) => ({
12998
+ ...patch,
12999
+ currentVersion: patch.currentVersion ?? current.currentVersion
13000
+ }));
13001
+ const view = this.composeStateView(snapshot, { includeInFlightCheck });
13002
+ this.deps.broadcaster.broadcast("update.state.changed", view);
13003
+ return view;
13004
+ }
12942
13005
  };
12943
13006
  }
12944
13007
  });