This commit is contained in:
Mateusz Tymek
2026-01-11 14:24:47 +01:00
parent 8345fff6e9
commit f2a12a24c8
4 changed files with 65 additions and 78 deletions

View File

@@ -4,13 +4,15 @@
### 0.1
* 3-4 sample skills useful in a vault
* Versioning and changelog
### 0.2
* AGENTS.md initialization
* Windows support
* 3-4 sample skills useful in a vault
### 0.3
* AGENTS.md initialization
### 1.0

View File

@@ -39,9 +39,8 @@ export class ProcessManager {
}
getUrl(): string {
const baseUrl = `http://${this.settings.hostname}:${this.settings.port}`;
const encodedPath = btoa(this.projectDirectory);
return `${baseUrl}/${encodedPath}`;
return `http://${this.settings.hostname}:${this.settings.port}/${encodedPath}`;
}
async start(): Promise<boolean> {
@@ -57,7 +56,6 @@ export class ProcessManager {
return this.setError("Project directory (vault) not configured");
}
// Check if server is already running on this port
if (await this.checkServerHealth()) {
console.log("[OpenCode] Server already running on port", this.settings.port);
this.setState("running");
@@ -125,19 +123,16 @@ export class ProcessManager {
}
});
// Wait for server to be ready
const ready = await this.waitForServerOrExit(this.settings.startupTimeout);
if (ready) {
this.setState("running");
return true;
}
// If already in error state from spawn error event, don't overwrite
if (this.state === "error") {
return false;
}
// Determine appropriate error message based on what happened
this.stop();
if (this.earlyExitCode !== null) {
return this.setError(`Process exited unexpectedly (exit code ${this.earlyExitCode})`);

View File

@@ -94,20 +94,17 @@ export default class OpenCodePlugin extends Plugin {
this.processManager.updateProjectDirectory(this.getProjectDirectory());
// Restart server if it's currently running
if (this.getProcessState() === "running") {
this.stopServer();
await this.startServer();
}
}
// Get existing view leaf if any
private getExistingLeaf(): WorkspaceLeaf | null {
const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
return leaves.length > 0 ? leaves[0] : null;
}
// Activate or create the view
async activateView(): Promise<void> {
const existingLeaf = this.getExistingLeaf();
@@ -133,7 +130,6 @@ export default class OpenCodePlugin extends Plugin {
}
}
// Toggle view visibility
async toggleView(): Promise<void> {
const existingLeaf = this.getExistingLeaf();

View File

@@ -21,6 +21,7 @@ function createTestSettings(port: number): OpenCodeSettings {
opencodePath: "opencode",
projectDirectory: "",
startupTimeout: TEST_TIMEOUT_MS,
defaultViewLocation: "sidebar",
};
}
@@ -55,17 +56,16 @@ afterEach(async () => {
describe("ProcessManager", () => {
describe("happy path", () => {
test("starts server and transitions to running state", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
test("starts server and transitions to running state", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
expect(currentManager.getState()).toBe("stopped");
@@ -77,16 +77,15 @@ describe("ProcessManager", () => {
expect(stateHistory).toContain("running");
});
test("reports correct server URL with encoded project directory", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
test("reports correct server URL with encoded project directory", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
() => {}
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
() => {}
);
const url = currentManager.getUrl();
const expectedBase = `http://127.0.0.1:${port}`;
@@ -95,17 +94,16 @@ describe("ProcessManager", () => {
expect(url).toBe(`${expectedBase}/${expectedPath}`);
});
test("stops server gracefully and transitions to stopped state", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
test("stops server gracefully and transitions to stopped state", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
await currentManager.start();
expect(currentManager.getState()).toBe("running");
@@ -116,17 +114,16 @@ describe("ProcessManager", () => {
expect(stateHistory).toContain("stopped");
});
test("state callbacks fire in correct order: starting -> running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
test("state callbacks fire in correct order: starting -> running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
const stateHistory: ProcessState[] = [];
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
(state) => stateHistory.push(state)
);
await currentManager.start();
@@ -138,16 +135,15 @@ describe("ProcessManager", () => {
expect(runningIndex).toBeGreaterThan(startingIndex);
});
test("can restart after stop", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
test("can restart after stop", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
() => {}
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
() => {}
);
// First start
const firstStart = await currentManager.start();
@@ -167,16 +163,15 @@ describe("ProcessManager", () => {
expect(currentManager.getState()).toBe("running");
});
test("returns true immediately if already running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
test("returns true immediately if already running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
() => {}
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
() => {}
);
// First start
await currentManager.start();
@@ -198,16 +193,15 @@ describe("ProcessManager", () => {
expect(stateHistory).toEqual([]);
});
test("health check endpoint is accessible when running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
test("health check endpoint is accessible when running", async () => {
const port = getNextPort();
const settings = createTestSettings(port);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
PROJECT_DIR,
() => {}
);
currentManager = new ProcessManager(
settings,
PROJECT_DIR,
() => {}
);
await currentManager.start();