feat: add multi-session desktop workspace
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
rm,
|
||||
stat,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import test from "node:test";
|
||||
import { createWorkspaceStore } from "../src/bridge/workspace-store.js";
|
||||
|
||||
test("persists an owner-only versioned workspace manifest atomically", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "pi-workspace-store-"));
|
||||
const store = createWorkspaceStore(join(root, "sessions"));
|
||||
const first = await store.load();
|
||||
assert.equal(first.migrating, true);
|
||||
|
||||
await store.save({
|
||||
version: 2,
|
||||
migrated: true,
|
||||
runtimes: [
|
||||
{
|
||||
runtimeId: "runtime-1",
|
||||
worktreePath: join(root, "home"),
|
||||
sessionPath: join(root, "sessions", "agent", "one.jsonl"),
|
||||
sessionId: "session-1",
|
||||
},
|
||||
],
|
||||
});
|
||||
const metadata = await stat(store.filePath);
|
||||
assert.equal(metadata.mode & 0o777, 0o600);
|
||||
const restored = (await store.load()).manifest;
|
||||
assert.equal(restored.runtimes[0].runtimeId, "runtime-1");
|
||||
assert.deepEqual(restored.directories, [join(root, "home")]);
|
||||
assert.equal((await readFile(store.filePath, "utf8")).endsWith("\n"), true);
|
||||
});
|
||||
|
||||
test("accepts old manifests and persists managed empty directories", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "pi-workspace-directories-"));
|
||||
const store = createWorkspaceStore(join(root, "sessions"));
|
||||
await store.save({
|
||||
version: 2,
|
||||
migrated: true,
|
||||
directories: [join(root, "empty")],
|
||||
runtimes: [],
|
||||
});
|
||||
assert.deepEqual((await store.load()).manifest.directories, [
|
||||
join(root, "empty"),
|
||||
]);
|
||||
await writeFile(
|
||||
store.filePath,
|
||||
JSON.stringify({ version: 2, migrated: true, runtimes: [] }),
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
assert.deepEqual((await store.load()).manifest.directories, []);
|
||||
});
|
||||
|
||||
test("reports a corrupt manifest without treating it as first migration", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "pi-workspace-corrupt-"));
|
||||
const store = createWorkspaceStore(join(root, "sessions"));
|
||||
await store.save({ version: 2, migrated: true, runtimes: [] });
|
||||
await writeFile(store.filePath, "{broken", { mode: 0o600 });
|
||||
|
||||
const loaded = await store.load();
|
||||
assert.equal(loaded.migrating, false);
|
||||
assert.equal(loaded.manifest.runtimes.length, 0);
|
||||
assert.equal(loaded.issue.code, "invalid_workspace_manifest");
|
||||
});
|
||||
|
||||
test("recovers its serialized write queue after a failed save", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "pi-workspace-retry-"));
|
||||
const sessionRoot = join(root, "sessions");
|
||||
const store = createWorkspaceStore(sessionRoot);
|
||||
await mkdir(sessionRoot);
|
||||
await mkdir(store.filePath);
|
||||
await assert.rejects(
|
||||
store.save({ version: 2, migrated: true, runtimes: [] }),
|
||||
);
|
||||
await rm(store.filePath, { recursive: true });
|
||||
await store.save({ version: 2, migrated: true, runtimes: [] });
|
||||
assert.deepEqual((await store.load()).manifest.runtimes, []);
|
||||
});
|
||||
Reference in New Issue
Block a user