Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions src/remote/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ export class Remote {
this.vscodeProposed,
this.contextManager,
);
disposables.push(monitor);
disposables.push(
monitor,
monitor.onChange.event((w) => (this.commands.workspace = w)),
);

Expand All @@ -310,7 +310,7 @@ export class Remote {
disposables.push(stateMachine);

try {
await this.vscodeProposed.window.withProgress(
workspace = await this.vscodeProposed.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
cancellable: false,
Expand All @@ -320,10 +320,8 @@ export class Remote {
let inProgress = false;
let pendingWorkspace: Workspace | null = null;

await new Promise<void>((resolve, reject) => {
return new Promise<Workspace>((resolve, reject) => {
const processWorkspace = async (w: Workspace) => {
workspace = w;

if (inProgress) {
// Process one workspace at a time, keeping only the last
pendingWorkspace = w;
Expand All @@ -340,26 +338,19 @@ export class Remote {
);
if (isReady) {
subscription.dispose();
resolve();
resolve(w);
return;
}

if (pendingWorkspace) {
const isReadyAfter = await stateMachine.processWorkspace(
pendingWorkspace,
progress,
);
if (isReadyAfter) {
subscription.dispose();
resolve();
}
}
} catch (error) {
subscription.dispose();
reject(error);
} finally {
inProgress = false;
}

if (pendingWorkspace) {
processWorkspace(pendingWorkspace);
}
};

processWorkspace(workspace);
Expand All @@ -373,6 +364,9 @@ export class Remote {
stateMachine.dispose();
}

// Mark initial setup as complete so the monitor can start notifying about state changes
monitor.markInitialSetupComplete();

const agents = extractAgents(workspace.latest_build.resources);
const agent = agents.find(
(agent) => agent.id === stateMachine.getAgentId(),
Expand Down
2 changes: 2 additions & 0 deletions src/remote/workspaceStateMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export class WorkspaceStateMachine implements vscode.Disposable {
case "pending":
case "starting":
case "stopping":
// Clear the agent ID since it could change after a restart
this.agentId = undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to clear the agent socket here as well or something, when I stop my workspace and it starts again, I do not see the agent script logs the second time.

Or, maybe we clear the socket when the agent closes, or both.

progress?.report({ message: "Waiting for workspace build..." });
Copy link
Member

@code-asher code-asher Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about putting the build state in here? Waiting for workspace build: stopping or Waiting for workspace to queue/start/stop if we want to be fancy.

this.logger.info(`Waiting for ${workspaceName}...`);

Expand Down
15 changes: 6 additions & 9 deletions src/workspace/workspaceMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class WorkspaceMonitor implements vscode.Disposable {
private notifiedDeletion = false;
private notifiedOutdated = false;
private notifiedNotRunning = false;
private isReady = false;
private completedInitialSetup = false;

readonly onChange = new vscode.EventEmitter<Workspace>();
private readonly statusBarItem: vscode.StatusBarItem;
Expand Down Expand Up @@ -111,6 +111,10 @@ export class WorkspaceMonitor implements vscode.Disposable {
return monitor;
}

public markInitialSetupComplete(): void {
this.completedInitialSetup = true;
}

/**
* Permanently close the websocket.
*/
Expand All @@ -124,7 +128,6 @@ export class WorkspaceMonitor implements vscode.Disposable {
}

private update(workspace: Workspace) {
this.updateReadyState(workspace);
this.updateContext(workspace);
this.updateStatusBar(workspace);
}
Expand All @@ -133,7 +136,7 @@ export class WorkspaceMonitor implements vscode.Disposable {
this.maybeNotifyOutdated(workspace);
this.maybeNotifyAutostop(workspace);
this.maybeNotifyDeletion(workspace);
Comment on lines 136 to 138
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was thinking about this some more, and we probably want to skip the deletion notification while in the setup phase too, otherwise I think we would get one notification here, and then another from the error thrown during setup.

Autostop and outdated I think are OK to show even during setup.

if (this.isReady) {
if (this.completedInitialSetup) {
// This instance might be created before the workspace is running
this.maybeNotifyNotRunning(workspace);
}
Expand Down Expand Up @@ -249,12 +252,6 @@ export class WorkspaceMonitor implements vscode.Disposable {
this.logger.error(message);
}

private updateReadyState(workspace: Workspace): void {
if (workspace.latest_build.status === "running") {
this.isReady = true;
}
}

private updateContext(workspace: Workspace) {
this.contextManager.set("coder.workspace.updatable", workspace.outdated);
}
Expand Down