refactor: unify env vars (UWF_HOME, OCAS_HOME) + env only in CLI (#37)
CI / check (pull_request) Failing after 3m6s

Breaking changes:
- UWF_STORAGE_ROOT → UWF_HOME
- WORKFLOW_STORAGE_ROOT removed (no fallback)
- OCAS_DIR → OCAS_HOME (aligned with ocas CLI)

Library functions no longer read process.env:
- util-agent/storage.ts: resolveStorageRoot(override), getGlobalCasDir(override)
- agent-hermes: isResumeDisabled(flag) pure function, CLI reads env
- agent-claude-code: CLI reads CLAUDE_MODEL and passes to agent

Fixes #37
This commit is contained in:
2026-06-04 05:12:05 +00:00
parent 84bdd81317
commit 6b7636b088
45 changed files with 394 additions and 333 deletions
+2 -3
View File
@@ -216,7 +216,6 @@ src/
| Variable | Purpose | Default |
|----------|---------|---------|
| `OCAS_DIR` | Override the global CAS directory location | `~/.ocas` |
| `UWF_STORAGE_ROOT` | Internal override for workflow metadata storage | `~/.uwf` |
| `WORKFLOW_STORAGE_ROOT` | User override for workflow metadata storage | `~/.uwf` |
| `OCAS_HOME` | Override the global CAS directory location | `~/.ocas` |
| `UWF_HOME` | Override the workflow metadata storage root | `~/.uwf` |
@@ -68,7 +68,7 @@ describe("C1: adapter JSON round-trip integration", () => {
prompt: "Test round-trip task",
});
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const threadId = "01ROUNDTRIPTEST0000000000" as ThreadId;
await seedThreads(tmpDir, { [threadId]: startHash });
@@ -134,8 +134,8 @@ describe("C1: adapter JSON round-trip integration", () => {
stdio: ["ignore", "pipe", "pipe"],
env: {
...process.env,
WORKFLOW_STORAGE_ROOT: tmpDir,
OCAS_DIR: casDir,
UWF_HOME: tmpDir,
OCAS_HOME: casDir,
},
cwd: tmpDir,
timeout: 30000,
@@ -225,9 +225,9 @@ describe("currentRole field", () => {
await mkdir(storageRoot, { recursive: true });
await mkdir(casDir, { recursive: true });
// Set OCAS_DIR for this test
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
// Set OCAS_HOME for this test
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
}
async function teardown() {
@@ -236,9 +236,9 @@ describe("currentRole field", () => {
}
// Restore original environment
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
}
@@ -12,7 +12,7 @@ beforeEach(async () => {
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-resolve-head-"));
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
});
afterEach(async () => {
+18 -18
View File
@@ -70,16 +70,16 @@ let originalEnv: string | undefined;
beforeEach(async () => {
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-step-read-test-"));
originalEnv = process.env.OCAS_DIR;
originalEnv = process.env.OCAS_HOME;
});
afterEach(async () => {
await rm(tmpDir, { recursive: true, force: true });
// Restore original environment
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
});
@@ -88,10 +88,10 @@ afterEach(async () => {
describe("step read", () => {
test("test 1: basic single-step read with 3 turns", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
const detailSchemas = await registerDetailSchemas(store);
@@ -177,9 +177,9 @@ describe("step read", () => {
test("test 2: quota enforcement - multiple turns", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
const detailSchemas = await registerDetailSchemas(store);
@@ -263,9 +263,9 @@ describe("step read", () => {
test("test 3: minimal quota edge case - always show at least one turn", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
const detailSchemas = await registerDetailSchemas(store);
@@ -340,9 +340,9 @@ describe("step read", () => {
test("test 4: step with no detail field", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
@@ -401,9 +401,9 @@ describe("step read", () => {
test("test 5: step with detail but no turns array", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
await registerDetailSchemas(store);
@@ -479,9 +479,9 @@ describe("step read", () => {
test("test 6: displays role and tool calls in turn body", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
const detailSchemas = await registerDetailSchemas(store);
@@ -553,9 +553,9 @@ describe("step read", () => {
test("test 7: turn content with special characters", async () => {
const casDir = join(tmpDir, "cas");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
const store = await openStore(casDir);
const schemas = await registerUwfSchemas(store);
const detailSchemas = await registerDetailSchemas(store);
@@ -131,16 +131,16 @@ describe("cmdStepShow JSON serialization", () => {
testDir = await mkdtemp(join(tmpdir(), "uwf-test-"));
casDir = join(testDir, "cas");
await mkdir(casDir, { recursive: true });
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
});
afterEach(async () => {
await rm(testDir, { recursive: true, force: true });
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
});
@@ -67,17 +67,17 @@ let originalEnv: string | undefined;
beforeEach(async () => {
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-step-timing-test-"));
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = join(tmpDir, "cas");
await mkdir(process.env.OCAS_DIR, { recursive: true });
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = join(tmpDir, "cas");
await mkdir(process.env.OCAS_HOME, { recursive: true });
});
afterEach(async () => {
await rm(tmpDir, { recursive: true, force: true });
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
});
@@ -20,7 +20,7 @@ describe("Global CAS directory", () => {
beforeEach(async () => {
tmpDir = join(tmpdir(), `uwf-test-global-cas-${Date.now()}`);
await mkdir(tmpDir, { recursive: true });
originalOcasDir = process.env.OCAS_DIR;
originalOcasDir = process.env.OCAS_HOME;
});
afterEach(async () => {
@@ -28,27 +28,27 @@ describe("Global CAS directory", () => {
await rm(tmpDir, { recursive: true, force: true });
}
if (originalOcasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalOcasDir;
process.env.OCAS_HOME = originalOcasDir;
}
});
test("getGlobalCasDir returns default path when no env var set", () => {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
const casDir = getGlobalCasDir();
expect(casDir).toContain(".ocas");
});
test("getGlobalCasDir respects OCAS_DIR environment variable", () => {
test("getGlobalCasDir respects OCAS_HOME environment variable", () => {
const customPath = join(tmpDir, "custom-cas");
process.env.OCAS_DIR = customPath;
process.env.OCAS_HOME = customPath;
const casDir = getGlobalCasDir();
expect(casDir).toBe(customPath);
});
test("getGlobalCasDir ignores empty OCAS_DIR", () => {
process.env.OCAS_DIR = "";
test("getGlobalCasDir ignores empty OCAS_HOME", () => {
process.env.OCAS_HOME = "";
const casDir = getGlobalCasDir();
expect(casDir).toContain(".ocas");
});
@@ -61,7 +61,7 @@ describe("Global CAS directory", () => {
test("createUwfStore uses global CAS directory", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -82,7 +82,7 @@ describe("Global CAS directory", () => {
test("createUwfStore creates global CAS directory if it does not exist", async () => {
const globalCasDir = join(tmpDir, "new-global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -97,7 +97,7 @@ describe("Global CAS directory", () => {
test("multiple uwfStore instances share the same global CAS filesystem", async () => {
const globalCasDir = join(tmpDir, "shared-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot1 = join(tmpDir, "storage1");
const storageRoot2 = join(tmpDir, "storage2");
@@ -127,7 +127,7 @@ describe("Global CAS directory", () => {
test("workflow registry is stored in global CAS variable store", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -148,7 +148,7 @@ describe("Global CAS directory", () => {
test("migrates workflows.yaml to variable store and renames file", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage-migrate");
await mkdir(storageRoot, { recursive: true });
@@ -173,7 +173,7 @@ describe("Global CAS directory", () => {
test("migrates threads.yaml to variable store and renames file", async () => {
const globalCasDir = join(tmpDir, "global-cas-threads");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage-threads-migrate");
await mkdir(storageRoot, { recursive: true });
@@ -197,7 +197,7 @@ describe("Global CAS directory", () => {
test("thread metadata stored in ocas variable store", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -218,7 +218,7 @@ describe("Global CAS directory", () => {
test("history is stored in global CAS variable store", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -249,7 +249,7 @@ describe("Global CAS directory", () => {
test("migrates history.jsonl to variable store and renames file", async () => {
const globalCasDir = join(tmpDir, "global-cas-history");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage-history-migrate");
await mkdir(storageRoot, { recursive: true });
@@ -292,7 +292,7 @@ describe("Global CAS directory", () => {
test("CAS nodes are stored in global directory", async () => {
const globalCasDir = join(tmpDir, "global-cas");
process.env.OCAS_DIR = globalCasDir;
process.env.OCAS_HOME = globalCasDir;
const storageRoot = join(tmpDir, "storage");
await mkdir(storageRoot, { recursive: true });
@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, test } from "vitest";
import { getDefaultStorageRoot, getGlobalCasDir, resolveStorageRoot } from "../store.js";
describe("Storage root resolution", () => {
const envKeys = ["UWF_STORAGE_ROOT", "WORKFLOW_STORAGE_ROOT", "OCAS_DIR"] as const;
const envKeys = ["UWF_HOME", "OCAS_HOME"] as const;
const savedEnv: Partial<Record<(typeof envKeys)[number], string | undefined>> = {};
beforeEach(() => {
@@ -28,15 +28,13 @@ describe("Storage root resolution", () => {
expect(getDefaultStorageRoot()).toBe(join(homedir(), ".uwf"));
});
test("resolveStorageRoot prefers UWF_STORAGE_ROOT", () => {
process.env.UWF_STORAGE_ROOT = "/tmp/uwf-primary";
process.env.WORKFLOW_STORAGE_ROOT = "/tmp/uwf-fallback";
test("resolveStorageRoot uses UWF_HOME", () => {
process.env.UWF_HOME = "/tmp/uwf-primary";
expect(resolveStorageRoot()).toBe("/tmp/uwf-primary");
});
test("resolveStorageRoot falls back to WORKFLOW_STORAGE_ROOT", () => {
process.env.WORKFLOW_STORAGE_ROOT = "/tmp/uwf-fallback";
expect(resolveStorageRoot()).toBe("/tmp/uwf-fallback");
test("resolveStorageRoot falls back to default when UWF_HOME unset", () => {
expect(resolveStorageRoot()).toBe(getDefaultStorageRoot());
});
test("getGlobalCasDir returns ~/.ocas by default", () => {
@@ -44,8 +42,8 @@ describe("Storage root resolution", () => {
expect(casDir).toBe(join(homedir(), ".ocas"));
});
test("getGlobalCasDir respects OCAS_DIR", () => {
process.env.OCAS_DIR = "/tmp/ocas-primary";
test("getGlobalCasDir respects OCAS_HOME", () => {
process.env.OCAS_HOME = "/tmp/ocas-primary";
expect(getGlobalCasDir()).toBe("/tmp/ocas-primary");
});
});
@@ -8,7 +8,7 @@ import { addHistoryEntry, createUwfStore, loadAllHistory } from "../store.js";
async function makeUwfStore(storageRoot: string) {
const casDir = join(storageRoot, "cas");
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
return createUwfStore(storageRoot);
}
@@ -22,8 +22,8 @@ import {
async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
const casDir = join(storageRoot, "cas");
await mkdir(casDir, { recursive: true });
// Set OCAS_DIR to use the test's CAS directory
process.env.OCAS_DIR = casDir;
// Set OCAS_HOME to use the test's CAS directory
process.env.OCAS_HOME = casDir;
return createUwfStore(storageRoot);
}
@@ -19,9 +19,9 @@ describe("Thread and edge location integration", () => {
await mkdir(storageRoot, { recursive: true });
await mkdir(casDir, { recursive: true });
// Set OCAS_DIR for this test
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
// Set OCAS_HOME for this test
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
}
async function teardown() {
@@ -30,9 +30,9 @@ describe("Thread and edge location integration", () => {
}
// Restore original environment
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
}
@@ -71,17 +71,17 @@ let originalEnv: string | undefined;
beforeEach(async () => {
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-quota-test-"));
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = join(tmpDir, "cas");
await mkdir(process.env.OCAS_DIR, { recursive: true });
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = join(tmpDir, "cas");
await mkdir(process.env.OCAS_HOME, { recursive: true });
});
afterEach(async () => {
await rm(tmpDir, { recursive: true, force: true });
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
});
@@ -52,7 +52,7 @@ const DETAIL_SCHEMA = {
async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
const casDir = join(storageRoot, "cas");
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
return createUwfStore(storageRoot);
}
@@ -89,7 +89,7 @@ async function setupSuspendedThread(mode: MockAgentMode): Promise<{
cwd: tmpDir,
});
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await seedThreads(tmpDir, { [THREAD_ID]: startHash });
const outputHash = await store.cas.put(outputSchemaHash, {
@@ -189,8 +189,8 @@ function runUwf(
stdio: ["ignore", "pipe", "pipe"],
env: {
...process.env,
WORKFLOW_STORAGE_ROOT: tmpDir,
OCAS_DIR: casDir,
UWF_HOME: tmpDir,
OCAS_HOME: casDir,
},
cwd: tmpDir,
timeout: 30000,
@@ -242,7 +242,7 @@ describe("uwf thread resume", () => {
cwd: tmpDir,
});
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
await seedThreads(tmpDir, { [THREAD_ID]: startHash });
const result = runUwf(["thread", "resume", THREAD_ID], casDir);
@@ -251,9 +251,9 @@ describe("uwf thread resume", () => {
});
test("resume suspended thread executes step and becomes idle", async () => {
const originalCasDir = process.env.OCAS_DIR;
const originalCasDir = process.env.OCAS_HOME;
const { casDir, mockAgentPath } = await setupSuspendedThread("ok");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
try {
const result = runUwf(["thread", "resume", THREAD_ID, "--agent", mockAgentPath], casDir);
@@ -279,17 +279,17 @@ describe("uwf thread resume", () => {
expect(showResult.suspendMessage).toBeNull();
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
test("resume without -p uses suspend message as agent prompt", async () => {
const originalCasDir = process.env.OCAS_DIR;
const originalCasDir = process.env.OCAS_HOME;
const { casDir, mockAgentPath, promptCapturePath } = await setupSuspendedThread("ok");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
try {
const result = runUwf(["thread", "resume", THREAD_ID, "--agent", mockAgentPath], casDir);
@@ -299,17 +299,17 @@ describe("uwf thread resume", () => {
expect(capturedPrompt).toBe(SUSPEND_MESSAGE);
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
test("resume with -p appends supplementary info to agent prompt", async () => {
const originalCasDir = process.env.OCAS_DIR;
const originalCasDir = process.env.OCAS_HOME;
const { casDir, mockAgentPath, promptCapturePath } = await setupSuspendedThread("ok");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
try {
const supplement = "Use the REST API.";
@@ -323,17 +323,17 @@ describe("uwf thread resume", () => {
expect(capturedPrompt).toBe(`${SUSPEND_MESSAGE}\n\n${supplement}`);
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
test("multiple suspend/resume cycles", async () => {
const originalCasDir = process.env.OCAS_DIR;
const originalCasDir = process.env.OCAS_HOME;
const { casDir, mockAgentPath, promptCapturePath } = await setupSuspendedThread("suspend");
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
try {
const firstResult = runUwf(["thread", "resume", THREAD_ID, "--agent", mockAgentPath], casDir);
@@ -371,9 +371,9 @@ describe("uwf thread resume", () => {
expect(capturedPrompt).toBe(SUSPEND_MESSAGE);
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
@@ -305,8 +305,8 @@ describe("thread show status field", () => {
await setupTestEnv();
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
const originalCasDir = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
const originalCasDir = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
try {
const workflowPath = join(tmpDir, "test-suspend-status.yaml");
@@ -331,9 +331,9 @@ describe("thread show status field", () => {
expect(result.thread).toBe(threadId);
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
await teardown();
}
@@ -21,9 +21,9 @@ describe("thread start --cwd CLI option", () => {
await mkdir(storageRoot, { recursive: true });
await mkdir(casDir, { recursive: true });
// Set OCAS_DIR for this test
originalEnv = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
// Set OCAS_HOME for this test
originalEnv = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
}
async function teardown() {
@@ -32,9 +32,9 @@ describe("thread start --cwd CLI option", () => {
}
// Restore original environment
if (originalEnv === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalEnv;
process.env.OCAS_HOME = originalEnv;
}
}
@@ -139,7 +139,7 @@ graph:
// Register the workflow
execFileSync(process.execPath, [uwfBin, "workflow", "add", workflowPath], {
env: { ...process.env, UWF_STORAGE_ROOT: storageRoot, OCAS_DIR: casDir },
env: { ...process.env, UWF_HOME: storageRoot, OCAS_HOME: casDir },
encoding: "utf8",
});
@@ -148,7 +148,7 @@ graph:
process.execPath,
[uwfBin, "thread", "start", "test-cwd-cli", "-p", "test prompt", "--cwd", testCwd],
{
env: { ...process.env, UWF_STORAGE_ROOT: storageRoot, OCAS_DIR: casDir },
env: { ...process.env, UWF_HOME: storageRoot, OCAS_HOME: casDir },
encoding: "utf8",
},
);
@@ -9,7 +9,7 @@ function runCli(args: string[]): { stdout: string; stderr: string; exitCode: num
try {
const stdout = execFileSync("npx", ["tsx", CLI_PATH, ...args], {
encoding: "utf8",
env: { ...process.env, WORKFLOW_STORAGE_ROOT: "/tmp/uwf-test-nonexistent" },
env: { ...process.env, UWF_HOME: "/tmp/uwf-test-nonexistent" },
stdio: ["ignore", "pipe", "pipe"],
});
return { stdout, stderr: "", exitCode: 0 };
@@ -35,8 +35,8 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
test("thread exec records suspend step in CAS and suspend metadata in threads.yaml", async () => {
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
const originalCasDir = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
const originalCasDir = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
try {
const store = await openStore(casDir);
@@ -128,8 +128,8 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
stdio: ["ignore", "pipe", "pipe"],
env: {
...process.env,
WORKFLOW_STORAGE_ROOT: tmpDir,
OCAS_DIR: casDir,
UWF_HOME: tmpDir,
OCAS_HOME: casDir,
},
cwd: tmpDir,
timeout: 30000,
@@ -170,9 +170,9 @@ describe("suspend step CAS chain and threads.yaml metadata", () => {
expect(showResult.suspendedRole).toBe("worker");
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
@@ -33,8 +33,8 @@ describe("suspended thread display", () => {
test("thread list shows [suspended] marker for suspended threads", async () => {
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
const originalCasDir = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
const originalCasDir = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
try {
const uwf = await createUwfStore(tmpDir);
@@ -131,9 +131,9 @@ describe("suspended thread display", () => {
expect(idleItem!.statusDisplay).toBe("idle");
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
@@ -141,8 +141,8 @@ describe("suspended thread display", () => {
test("thread show displays suspend info and resume hint", async () => {
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
const originalCasDir = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
const originalCasDir = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
try {
const uwf = await createUwfStore(tmpDir);
@@ -219,9 +219,9 @@ describe("suspended thread display", () => {
);
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
@@ -229,8 +229,8 @@ describe("suspended thread display", () => {
test("non-suspended threads do not show suspend markers or hints", async () => {
const casDir = join(tmpDir, "cas");
await mkdir(casDir, { recursive: true });
const originalCasDir = process.env.OCAS_DIR;
process.env.OCAS_DIR = casDir;
const originalCasDir = process.env.OCAS_HOME;
process.env.OCAS_HOME = casDir;
try {
const uwf = await createUwfStore(tmpDir);
@@ -278,9 +278,9 @@ describe("suspended thread display", () => {
expect(threadItem!.statusDisplay).toBe("idle");
} finally {
if (originalCasDir === undefined) {
delete process.env.OCAS_DIR;
delete process.env.OCAS_HOME;
} else {
process.env.OCAS_DIR = originalCasDir;
process.env.OCAS_HOME = originalCasDir;
}
}
});
+1 -1
View File
@@ -57,7 +57,7 @@ const DETAIL_SCHEMA = {
async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
const casDir = join(storageRoot, "cas");
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
return createUwfStore(storageRoot);
}
@@ -13,7 +13,7 @@ import { createUwfStore, saveWorkflowRegistry } from "../store.js";
async function makeUwfStore(storageRoot: string): Promise<UwfStore> {
const casDir = join(storageRoot, "cas");
await mkdir(casDir, { recursive: true });
process.env.OCAS_DIR = casDir;
process.env.OCAS_HOME = casDir;
return createUwfStore(storageRoot);
}
+4 -8
View File
@@ -118,17 +118,13 @@ export function getDefaultStorageRoot(): string {
/**
* Resolve storage root.
* Priority: `UWF_STORAGE_ROOT` → `WORKFLOW_STORAGE_ROOT` → default.
* Priority: `UWF_HOME` → default.
*/
export function resolveStorageRoot(): string {
const primary = process.env.UWF_STORAGE_ROOT;
const primary = process.env.UWF_HOME;
if (primary !== undefined && primary !== "") {
return primary;
}
const userOverride = process.env.WORKFLOW_STORAGE_ROOT;
if (userOverride !== undefined && userOverride !== "") {
return userOverride;
}
return getDefaultStorageRoot();
}
@@ -142,10 +138,10 @@ export function getCasDir(storageRoot: string): string {
/**
* Returns the global CAS directory shared by all uwf and ocas tools.
* Priority: `OCAS_DIR` → default ~/.ocas
* Priority: `OCAS_HOME` → default ~/.ocas
*/
export function getGlobalCasDir(): string {
const primary = process.env.OCAS_DIR;
const primary = process.env.OCAS_HOME;
if (primary !== undefined && primary !== "") {
return primary;
}