Gateway: refine BOOTSTRAP post-onboarding filtering

This commit is contained in:
Gustavo Madeira Santana
2026-02-15 15:37:04 -05:00
parent d7881a2b57
commit f95f6dd052
3 changed files with 26 additions and 15 deletions

View File

@@ -102,11 +102,6 @@ type WorkspaceOnboardingState = {
onboardingCompletedAt?: string;
};
export type WorkspaceOnboardingStateSnapshot = {
bootstrapSeededAt?: string;
onboardingCompletedAt?: string;
};
/** Set of recognized bootstrap filenames for runtime validation */
const VALID_BOOTSTRAP_NAMES: ReadonlySet<string> = new Set([
DEFAULT_AGENTS_FILENAME,
@@ -189,15 +184,9 @@ async function readWorkspaceOnboardingState(statePath: string): Promise<Workspac
}
}
export async function readWorkspaceOnboardingStateForDir(
dir: string,
): Promise<WorkspaceOnboardingStateSnapshot> {
async function readWorkspaceOnboardingStateForDir(dir: string): Promise<WorkspaceOnboardingState> {
const statePath = resolveWorkspaceStatePath(resolveUserPath(dir));
const state = await readWorkspaceOnboardingState(statePath);
return {
bootstrapSeededAt: state.bootstrapSeededAt,
onboardingCompletedAt: state.onboardingCompletedAt,
};
return await readWorkspaceOnboardingState(statePath);
}
export async function isWorkspaceOnboardingCompleted(dir: string): Promise<boolean> {

View File

@@ -119,6 +119,12 @@ function createEnoentError() {
return err;
}
function createErrnoError(code: string) {
const err = new Error(code) as NodeJS.ErrnoException;
err.code = code;
return err;
}
beforeEach(() => {
mocks.fsReadFile.mockImplementation(async () => {
throw createEnoentError();
@@ -423,4 +429,20 @@ describe("agents.files.list", () => {
const files = (result as { files: Array<{ name: string }> }).files;
expect(files.some((file) => file.name === "BOOTSTRAP.md")).toBe(false);
});
it("falls back to showing BOOTSTRAP.md when workspace state cannot be read", async () => {
mocks.fsReadFile.mockImplementation(async (filePath: string | URL | number) => {
if (String(filePath).endsWith("workspace-state.json")) {
throw createErrnoError("EACCES");
}
throw createEnoentError();
});
const { respond, promise } = makeCall("agents.files.list", { agentId: "main" });
await promise;
const [, result] = respond.mock.calls[0] ?? [];
const files = (result as { files: Array<{ name: string }> }).files;
expect(files.some((file) => file.name === "BOOTSTRAP.md")).toBe(true);
});
});

View File

@@ -53,7 +53,7 @@ const BOOTSTRAP_FILE_NAMES = [
DEFAULT_HEARTBEAT_FILENAME,
DEFAULT_BOOTSTRAP_FILENAME,
] as const;
const BOOTSTRAP_FILE_NAMES_WITHOUT_ONBOARDING = BOOTSTRAP_FILE_NAMES.filter(
const BOOTSTRAP_FILE_NAMES_POST_ONBOARDING = BOOTSTRAP_FILE_NAMES.filter(
(name) => name !== DEFAULT_BOOTSTRAP_FILENAME,
);
@@ -122,7 +122,7 @@ async function listAgentFiles(workspaceDir: string, options?: { hideBootstrap?:
}> = [];
const bootstrapFileNames = options?.hideBootstrap
? BOOTSTRAP_FILE_NAMES_WITHOUT_ONBOARDING
? BOOTSTRAP_FILE_NAMES_POST_ONBOARDING
: BOOTSTRAP_FILE_NAMES;
for (const name of bootstrapFileNames) {
const filePath = path.join(workspaceDir, name);