6488b7bbb4
- garbageCollectCas() mark-and-sweep: scan .data.jsonl refs, delete orphans - 'uncaged-workflow gc' CLI command - thread rm triggers GC automatically - 141 tests passing Fixes #32
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import { unlink } from "node:fs/promises";
|
|
import { dirname, join } from "node:path";
|
|
|
|
import { err, garbageCollectCas, ok, type Result } from "@uncaged/workflow";
|
|
|
|
import { readTextFileIfExists } from "./fs-utils.js";
|
|
import { resolveThreadDataPath } from "./thread-scan.js";
|
|
|
|
export async function cmdThreadShow(
|
|
storageRoot: string,
|
|
threadId: string,
|
|
): Promise<Result<string, string>> {
|
|
const dataPath = await resolveThreadDataPath(storageRoot, threadId);
|
|
if (dataPath === null) {
|
|
return err(`thread not found: ${threadId}`);
|
|
}
|
|
const text = await readTextFileIfExists(dataPath);
|
|
if (text === null) {
|
|
return err(`thread data missing: ${threadId}`);
|
|
}
|
|
return ok(text.endsWith("\n") ? text.slice(0, -1) : text);
|
|
}
|
|
|
|
export async function cmdThreadRemove(
|
|
storageRoot: string,
|
|
threadId: string,
|
|
): Promise<Result<void, string>> {
|
|
const dataPath = await resolveThreadDataPath(storageRoot, threadId);
|
|
if (dataPath === null) {
|
|
return err(`thread not found: ${threadId}`);
|
|
}
|
|
|
|
const dir = dirname(dataPath);
|
|
const infoPath = join(dir, `${threadId}.info.jsonl`);
|
|
const runningPath = join(dir, `${threadId}.running`);
|
|
|
|
await unlink(dataPath);
|
|
await unlink(infoPath).catch(() => {});
|
|
await unlink(runningPath).catch(() => {});
|
|
|
|
await garbageCollectCas(storageRoot);
|
|
|
|
return ok(undefined);
|
|
}
|