Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"test:events": "node scripts/events.mjs",
"test:todos": "node scripts/todos.mjs",
"test:permissions": "node scripts/permissions.mjs",
"test:workspace-path": "bun scripts/workspace-path.ts",
"test:session-scope": "bun scripts/session-scope.ts",
"test:session-switch": "node scripts/session-switch.mjs",
"test:fs-engine": "node scripts/fs-engine.mjs",
Expand Down
117 changes: 117 additions & 0 deletions apps/app/scripts/workspace-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import assert from "node:assert/strict";

import { resolveCreatedLocalWorkspacePath } from "../src/app/lib/workspace-path.ts";

const winRaw = "C:/Users/Test/OpenWork/starter";
const winCanonical = String.raw`C:\Users\Test\OpenWork\starter`;

const results = {
ok: true,
steps: [] as Array<Record<string, unknown>>,
};

async function step(name: string, fn: () => void | Promise<void>) {
results.steps.push({ name, status: "running" });
const index = results.steps.length - 1;

try {
await fn();
results.steps[index] = { name, status: "ok" };
} catch (error) {
results.ok = false;
results.steps[index] = {
name,
status: "error",
error: error instanceof Error ? error.message : String(error),
};
throw error;
}
}

try {
await step("prefers persisted local workspace path over raw picker path", () => {
assert.equal(
resolveCreatedLocalWorkspacePath({
workspaceId: "ws_test",
fallbackPath: winRaw,
workspaces: [
{
id: "ws_test",
name: "starter",
path: winCanonical,
preset: "starter",
workspaceType: "local",
remoteType: null,
baseUrl: null,
directory: null,
displayName: null,
openworkHostUrl: null,
openworkToken: null,
openworkWorkspaceId: null,
openworkWorkspaceName: null,
sandboxBackend: null,
sandboxRunId: null,
sandboxContainerName: null,
},
],
}),
winCanonical,
);
});

await step("falls back to the original path when no workspace match exists", () => {
assert.equal(
resolveCreatedLocalWorkspacePath({
workspaceId: "ws_missing",
fallbackPath: winRaw,
workspaces: [],
}),
winRaw,
);
});

await step("ignores remote workspace rows when resolving a local workspace path", () => {
assert.equal(
resolveCreatedLocalWorkspacePath({
workspaceId: "ws_test",
fallbackPath: winRaw,
workspaces: [
{
id: "ws_test",
name: "starter",
path: "",
preset: "remote",
workspaceType: "remote",
remoteType: "openwork",
baseUrl: "https://example.com",
directory: winCanonical,
displayName: null,
openworkHostUrl: "https://example.com",
openworkToken: null,
openworkWorkspaceId: "ow_ws_test",
openworkWorkspaceName: "starter",
sandboxBackend: null,
sandboxRunId: null,
sandboxContainerName: null,
},
],
}),
winRaw,
);
});

console.log(JSON.stringify(results, null, 2));
} catch (error) {
results.ok = false;
console.error(
JSON.stringify(
{
...results,
error: error instanceof Error ? error.message : String(error),
},
null,
2,
),
);
process.exitCode = 1;
}
21 changes: 16 additions & 5 deletions apps/app/src/app/context/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import type { OpencodeConnectStatus, ProviderListItem } from "../types";
import { t, currentLocale } from "../../i18n";
import { filterProviderList, mapConfigProvidersToList } from "../utils/providers";
import { buildDefaultWorkspaceBlueprint, normalizeWorkspaceOpenworkConfig } from "../lib/workspace-blueprints";
import { resolveCreatedLocalWorkspacePath } from "../lib/workspace-path";
import type { OpenworkServerStore } from "../connections/openwork-server-store";

export type WorkspaceStore = ReturnType<typeof createWorkspaceStore>;
Expand Down Expand Up @@ -2185,6 +2186,11 @@ export function createWorkspaceStore(options: {
}

const nextSelectedId = createdWorkspaceId;
const createdWorkspacePath = resolveCreatedLocalWorkspacePath({
workspaceId: nextSelectedId,
workspaces: ws.workspaces,
fallbackPath: resolvedFolder,
});
applyServerLocalWorkspaces(ws.workspaces, nextSelectedId);
if (nextSelectedId) {
const nextSelectedWorkspace = ws.workspaces.find((workspace) => workspace.id === nextSelectedId) ?? null;
Expand All @@ -2200,15 +2206,15 @@ export function createWorkspaceStore(options: {

setCreateWorkspaceOpen(false);

const opened = await activateFreshLocalWorkspace(nextSelectedId || null, resolvedFolder);
const opened = await activateFreshLocalWorkspace(nextSelectedId || null, createdWorkspacePath);
if (!opened) {
options.setPendingInitialSessionSelection?.(null);
return false;
}

if (preset === "starter") {
const materialized = await materializeStarterSessions(resolvedFolder, name, preset);
const sessionsReady = await waitForWorkspaceSessionsReady(resolvedFolder);
const materialized = await materializeStarterSessions(createdWorkspacePath, name, preset);
const sessionsReady = await waitForWorkspaceSessionsReady(createdWorkspacePath);
if (!sessionsReady) {
throw new Error("Starter sessions did not finish loading for the new workspace.");
}
Expand All @@ -2225,7 +2231,7 @@ export function createWorkspaceStore(options: {
}

if (!nextSelectedId) {
await openEmptySession(resolvedFolder);
await openEmptySession(createdWorkspacePath);
}

return true;
Expand Down Expand Up @@ -3270,11 +3276,16 @@ export function createWorkspaceStore(options: {

setWorkspaces(ws.workspaces);
const nextSelectedId = pickSelectedWorkspaceId(ws.workspaces, [resolveWorkspaceListSelectedId(ws)], ws);
const createdWorkspacePath = resolveCreatedLocalWorkspacePath({
workspaceId: nextSelectedId,
workspaces: ws.workspaces,
fallbackPath: resolvedFolder,
});
syncSelectedWorkspaceId(nextSelectedId);
setCreateWorkspaceOpen(false);
setCreateRemoteWorkspaceOpen(false);

const opened = await activateFreshLocalWorkspace(nextSelectedId || null, resolvedFolder);
const opened = await activateFreshLocalWorkspace(nextSelectedId || null, createdWorkspacePath);
if (!opened) {
return;
}
Expand Down
15 changes: 15 additions & 0 deletions apps/app/src/app/lib/workspace-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { WorkspaceInfo } from "./tauri";

export function resolveCreatedLocalWorkspacePath(input: {
workspaceId?: string | null;
workspaces: WorkspaceInfo[];
fallbackPath?: string | null;
}) {
const fallbackPath = input.fallbackPath?.trim() ?? "";
const workspaceId = input.workspaceId?.trim() ?? "";
if (!workspaceId) return fallbackPath;

const created = input.workspaces.find((workspace) => workspace.id === workspaceId && workspace.workspaceType === "local");
const path = created?.path?.trim() ?? "";
return path || fallbackPath;
}
Loading