Treat Codex bootstrap logs as stdout
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -94,7 +94,7 @@ export async function prepareWorktreeCodexHome(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await onLog(
|
await onLog(
|
||||||
"stderr",
|
"stdout",
|
||||||
`[paperclip] Using worktree-isolated Codex home "${targetHome}" (seeded from "${sourceHome}").\n`,
|
`[paperclip] Using worktree-isolated Codex home "${targetHome}" (seeded from "${sourceHome}").\n`,
|
||||||
);
|
);
|
||||||
return targetHome;
|
return targetHome;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export async function ensureCodexSkillsInjected(
|
|||||||
);
|
);
|
||||||
for (const skillName of removedSkills) {
|
for (const skillName of removedSkills) {
|
||||||
await onLog(
|
await onLog(
|
||||||
"stderr",
|
"stdout",
|
||||||
`[paperclip] Removed maintainer-only Codex skill "${skillName}" from ${skillsHome}\n`,
|
`[paperclip] Removed maintainer-only Codex skill "${skillName}" from ${skillsHome}\n`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ export async function ensureCodexSkillsInjected(
|
|||||||
await fs.symlink(entry.source, target);
|
await fs.symlink(entry.source, target);
|
||||||
}
|
}
|
||||||
await onLog(
|
await onLog(
|
||||||
"stderr",
|
"stdout",
|
||||||
`[paperclip] Repaired Codex skill "${entry.name}" into ${skillsHome}\n`,
|
`[paperclip] Repaired Codex skill "${entry.name}" into ${skillsHome}\n`,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@@ -154,7 +154,7 @@ export async function ensureCodexSkillsInjected(
|
|||||||
if (result === "skipped") continue;
|
if (result === "skipped") continue;
|
||||||
|
|
||||||
await onLog(
|
await onLog(
|
||||||
"stderr",
|
"stdout",
|
||||||
`[paperclip] ${result === "repaired" ? "Repaired" : "Injected"} Codex skill "${entry.name}" into ${skillsHome}\n`,
|
`[paperclip] ${result === "repaired" ? "Repaired" : "Injected"} Codex skill "${entry.name}" into ${skillsHome}\n`,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -364,7 +364,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||||||
`Resolve any relative file references from ${instructionsDir}.\n\n`;
|
`Resolve any relative file references from ${instructionsDir}.\n\n`;
|
||||||
instructionsChars = instructionsPrefix.length;
|
instructionsChars = instructionsPrefix.length;
|
||||||
await onLog(
|
await onLog(
|
||||||
"stderr",
|
"stdout",
|
||||||
`[paperclip] Loaded agent instructions file: ${instructionsFilePath}\n`,
|
`[paperclip] Loaded agent instructions file: ${instructionsFilePath}\n`,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ type CapturePayload = {
|
|||||||
paperclipEnvKeys: string[];
|
paperclipEnvKeys: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LogEntry = {
|
||||||
|
stream: "stdout" | "stderr";
|
||||||
|
chunk: string;
|
||||||
|
};
|
||||||
|
|
||||||
describe("codex execute", () => {
|
describe("codex execute", () => {
|
||||||
it("uses a worktree-isolated CODEX_HOME while preserving shared auth and config", async () => {
|
it("uses a worktree-isolated CODEX_HOME while preserving shared auth and config", async () => {
|
||||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-execute-"));
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-codex-execute-"));
|
||||||
@@ -62,6 +67,7 @@ describe("codex execute", () => {
|
|||||||
process.env.CODEX_HOME = sharedCodexHome;
|
process.env.CODEX_HOME = sharedCodexHome;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const logs: LogEntry[] = [];
|
||||||
const result = await execute({
|
const result = await execute({
|
||||||
runId: "run-1",
|
runId: "run-1",
|
||||||
agent: {
|
agent: {
|
||||||
@@ -87,7 +93,9 @@ describe("codex execute", () => {
|
|||||||
},
|
},
|
||||||
context: {},
|
context: {},
|
||||||
authToken: "run-jwt-token",
|
authToken: "run-jwt-token",
|
||||||
onLog: async () => {},
|
onLog: async (stream, chunk) => {
|
||||||
|
logs.push({ stream, chunk });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
@@ -116,6 +124,18 @@ describe("codex execute", () => {
|
|||||||
expect((await fs.lstat(isolatedConfig)).isFile()).toBe(true);
|
expect((await fs.lstat(isolatedConfig)).isFile()).toBe(true);
|
||||||
expect(await fs.readFile(isolatedConfig, "utf8")).toBe('model = "codex-mini-latest"\n');
|
expect(await fs.readFile(isolatedConfig, "utf8")).toBe('model = "codex-mini-latest"\n');
|
||||||
expect((await fs.lstat(isolatedSkill)).isSymbolicLink()).toBe(true);
|
expect((await fs.lstat(isolatedSkill)).isSymbolicLink()).toBe(true);
|
||||||
|
expect(logs).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
stream: "stdout",
|
||||||
|
chunk: expect.stringContaining("Using worktree-isolated Codex home"),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(logs).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
stream: "stdout",
|
||||||
|
chunk: expect.stringContaining('Injected Codex skill "paperclip"'),
|
||||||
|
}),
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
if (previousHome === undefined) delete process.env.HOME;
|
if (previousHome === undefined) delete process.env.HOME;
|
||||||
else process.env.HOME = previousHome;
|
else process.env.HOME = previousHome;
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ describe("codex local adapter skill injection", () => {
|
|||||||
await createPaperclipRepoSkill(oldRepo, "paperclip");
|
await createPaperclipRepoSkill(oldRepo, "paperclip");
|
||||||
await fs.symlink(path.join(oldRepo, "skills", "paperclip"), path.join(skillsHome, "paperclip"));
|
await fs.symlink(path.join(oldRepo, "skills", "paperclip"), path.join(skillsHome, "paperclip"));
|
||||||
|
|
||||||
const logs: string[] = [];
|
const logs: Array<{ stream: "stdout" | "stderr"; chunk: string }> = [];
|
||||||
await ensureCodexSkillsInjected(
|
await ensureCodexSkillsInjected(
|
||||||
async (_stream, chunk) => {
|
async (stream, chunk) => {
|
||||||
logs.push(chunk);
|
logs.push({ stream, chunk });
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skillsHome,
|
skillsHome,
|
||||||
@@ -64,7 +64,12 @@ describe("codex local adapter skill injection", () => {
|
|||||||
expect(await fs.realpath(path.join(skillsHome, "paperclip"))).toBe(
|
expect(await fs.realpath(path.join(skillsHome, "paperclip"))).toBe(
|
||||||
await fs.realpath(path.join(currentRepo, "skills", "paperclip")),
|
await fs.realpath(path.join(currentRepo, "skills", "paperclip")),
|
||||||
);
|
);
|
||||||
expect(logs.some((line) => line.includes('Repaired Codex skill "paperclip"'))).toBe(true);
|
expect(logs).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
stream: "stdout",
|
||||||
|
chunk: expect.stringContaining('Repaired Codex skill "paperclip"'),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("preserves a custom Codex skill symlink outside Paperclip repo checkouts", async () => {
|
it("preserves a custom Codex skill symlink outside Paperclip repo checkouts", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user