mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 09:01:22 +00:00
fix(workspace): persist bootstrap onboarding state
This commit is contained in:
@@ -5,8 +5,11 @@ import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace
|
||||
import {
|
||||
DEFAULT_AGENTS_FILENAME,
|
||||
DEFAULT_BOOTSTRAP_FILENAME,
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_MEMORY_ALT_FILENAME,
|
||||
DEFAULT_MEMORY_FILENAME,
|
||||
DEFAULT_TOOLS_FILENAME,
|
||||
DEFAULT_USER_FILENAME,
|
||||
ensureAgentWorkspace,
|
||||
loadWorkspaceBootstrapFiles,
|
||||
resolveDefaultAgentWorkspaceDir,
|
||||
@@ -23,8 +26,23 @@ describe("resolveDefaultAgentWorkspaceDir", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const WORKSPACE_STATE_PATH_SEGMENTS = [".openclaw", "workspace-state.json"] as const;
|
||||
|
||||
async function readOnboardingState(dir: string): Promise<{
|
||||
version: number;
|
||||
bootstrapSeededAt?: string;
|
||||
onboardingCompletedAt?: string;
|
||||
}> {
|
||||
const raw = await fs.readFile(path.join(dir, ...WORKSPACE_STATE_PATH_SEGMENTS), "utf-8");
|
||||
return JSON.parse(raw) as {
|
||||
version: number;
|
||||
bootstrapSeededAt?: string;
|
||||
onboardingCompletedAt?: string;
|
||||
};
|
||||
}
|
||||
|
||||
describe("ensureAgentWorkspace", () => {
|
||||
it("creates BOOTSTRAP.md for a brand new workspace", async () => {
|
||||
it("creates BOOTSTRAP.md and records a seeded marker for brand new workspaces", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
@@ -32,9 +50,12 @@ describe("ensureAgentWorkspace", () => {
|
||||
await expect(
|
||||
fs.access(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME)),
|
||||
).resolves.toBeUndefined();
|
||||
const state = await readOnboardingState(tempDir);
|
||||
expect(state.bootstrapSeededAt).toMatch(/\d{4}-\d{2}-\d{2}T/);
|
||||
expect(state.onboardingCompletedAt).toBeUndefined();
|
||||
});
|
||||
|
||||
it("creates BOOTSTRAP.md even when workspace already has other bootstrap files", async () => {
|
||||
it("recovers partial initialization by creating BOOTSTRAP.md when marker is missing", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_AGENTS_FILENAME, content: "existing" });
|
||||
|
||||
@@ -43,18 +64,41 @@ describe("ensureAgentWorkspace", () => {
|
||||
await expect(
|
||||
fs.access(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME)),
|
||||
).resolves.toBeUndefined();
|
||||
const state = await readOnboardingState(tempDir);
|
||||
expect(state.bootstrapSeededAt).toMatch(/\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
|
||||
it("does not recreate BOOTSTRAP.md after onboarding deletion", async () => {
|
||||
it("does not recreate BOOTSTRAP.md after completion, even when a core file is recreated", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_IDENTITY_FILENAME, content: "custom" });
|
||||
await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_USER_FILENAME, content: "custom" });
|
||||
await fs.unlink(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME));
|
||||
await fs.unlink(path.join(tempDir, DEFAULT_TOOLS_FILENAME));
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
|
||||
await expect(fs.access(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME))).rejects.toMatchObject({
|
||||
code: "ENOENT",
|
||||
});
|
||||
await expect(fs.access(path.join(tempDir, DEFAULT_TOOLS_FILENAME))).resolves.toBeUndefined();
|
||||
const state = await readOnboardingState(tempDir);
|
||||
expect(state.onboardingCompletedAt).toMatch(/\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
|
||||
it("does not re-seed BOOTSTRAP.md for legacy completed workspaces without state marker", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_IDENTITY_FILENAME, content: "custom" });
|
||||
await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_USER_FILENAME, content: "custom" });
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
|
||||
await expect(fs.access(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME))).rejects.toMatchObject({
|
||||
code: "ENOENT",
|
||||
});
|
||||
const state = await readOnboardingState(tempDir);
|
||||
expect(state.bootstrapSeededAt).toBeUndefined();
|
||||
expect(state.onboardingCompletedAt).toMatch(/\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user