fix: isolate concurrent OpenCode chat runs

This commit is contained in:
2026-08-17 22:03:37 +08:00
parent 7e8d9e3811
commit 65040730ec
29 changed files with 5207 additions and 427 deletions

View File

@@ -23,6 +23,7 @@ import {
import { promisify } from 'node:util';
export type OpencodeLifecycleState = 'stopped' | 'starting' | 'running' | 'error';
export type OpencodeRuntimeGenerationProvenance = 'unknown' | 'starting' | 'fresh' | 'attached';
export interface OpencodeStatus {
state: OpencodeLifecycleState;
@@ -400,6 +401,7 @@ export class OpencodeManager extends EventEmitter {
private cancelStartsBeforeSequence = 0;
private runtimeGeneration = 0;
private activeRuntimeGeneration: number | null = null;
private activeRuntimeGenerationProvenance: OpencodeRuntimeGenerationProvenance = 'unknown';
private activeStartAttempt: RuntimeStartAttempt | null = null;
private readonly trackedUnreleasedPorts = new Set<number>();
private lifecycleBusy = false;
@@ -423,6 +425,18 @@ export class OpencodeManager extends EventEmitter {
return { ...this.status };
}
getRuntimeGeneration(): number {
return this.status.state === 'starting' || this.status.state === 'running'
? this.activeRuntimeGeneration ?? 0
: 0;
}
getRuntimeGenerationProvenance(): OpencodeRuntimeGenerationProvenance {
return this.status.state === 'starting' || this.status.state === 'running'
? this.activeRuntimeGenerationProvenance
: 'unknown';
}
getManagedConfigDir(): string | null {
const userDataDir = this.options.userDataDir?.trim();
return userDataDir ? getManagedOpencodeConfigDir(userDataDir) : null;
@@ -518,6 +532,7 @@ export class OpencodeManager extends EventEmitter {
}
if (this.activeRuntimeGeneration === generation) {
this.activeRuntimeGeneration = null;
this.activeRuntimeGenerationProvenance = 'unknown';
}
this.setStatus({ state: 'stopped', port: this.options.port });
} catch (error) {
@@ -685,6 +700,7 @@ export class OpencodeManager extends EventEmitter {
if (!listeningPort) return;
finish(() => {
this.activeRuntimeGenerationProvenance = 'fresh';
this.setStatus({
state: 'running',
port: listeningPort,
@@ -738,6 +754,7 @@ export class OpencodeManager extends EventEmitter {
url: existingServer.url,
},
);
this.activeRuntimeGenerationProvenance = 'attached';
this.setStatus(existingServer);
resolve(this.getStatus());
});
@@ -805,6 +822,7 @@ export class OpencodeManager extends EventEmitter {
controller: new AbortController(),
};
this.activeRuntimeGeneration = attempt.generation;
this.activeRuntimeGenerationProvenance = 'starting';
this.activeStartAttempt = attempt;
return attempt;
}
@@ -997,6 +1015,7 @@ export class OpencodeManager extends EventEmitter {
this.recordPortReleaseOutcome(port, true, released);
if (released) {
this.activeRuntimeGeneration = null;
this.activeRuntimeGenerationProvenance = 'unknown';
this.setStatus({
state: 'stopped',
port: this.options.port,