fix: port prepareClaudePromptBundle flow to claude_k8s adapter (FAR-11)
K8s Job pods were starting without the Paperclip skill loaded, so agents could not find their heartbeat procedure and reported "no issue content in my workspace" on every wake. Root cause: claude_local materialises skills into a PVC-backed prompt-bundle directory and passes --add-dir to Claude, but claude_k8s did neither. Changes: - Add src/server/prompt-cache.ts with prepareClaudePromptBundle (ported from adapter-claude-local). Writes skill symlinks and the agent's instructions file into a content-addressed bundle directory under the shared PVC (/paperclip/instances/.../claude-prompt-cache/<hash>/). - execute.ts: read desired skills and instructions file before building the Job manifest, then call prepareClaudePromptBundle and pass the resulting bundle to buildJobManifest. - job-manifest.ts: accept optional promptBundle in JobBuildInput; when present, pass --add-dir <bundle.addDir> and use bundle.instructionsFilePath for --append-system-prompt-file. Also fix: skip --append-system-prompt-file on session resumes to avoid wasting tokens on re-injection. - skills.ts: correct the detail string to reflect actual materialisation. - job-manifest.test.ts: add 5 new tests covering --add-dir injection, bundle path preference, session-resume skipping, and fallback behaviour. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -517,13 +517,66 @@ describe("buildJobManifest", () => {
|
||||
expect(claudeArgs).toContain("--dangerously-skip-permissions");
|
||||
});
|
||||
|
||||
it("adds --append-system-prompt-file when instructionsFilePath set", () => {
|
||||
it("adds --append-system-prompt-file (config fallback) when instructionsFilePath set and no session", () => {
|
||||
ctx.config = { instructionsFilePath: "/paperclip/instructions.md" };
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod });
|
||||
expect(claudeArgs).toContain("--append-system-prompt-file");
|
||||
expect(claudeArgs).toContain("/paperclip/instructions.md");
|
||||
});
|
||||
|
||||
it("omits --append-system-prompt-file on session resume (avoids token waste)", () => {
|
||||
ctx.config = { instructionsFilePath: "/paperclip/instructions.md" };
|
||||
ctx.runtime.sessionId = "sess_existing";
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod });
|
||||
expect(claudeArgs).not.toContain("--append-system-prompt-file");
|
||||
});
|
||||
|
||||
it("adds --add-dir when promptBundle is provided", () => {
|
||||
const promptBundle = {
|
||||
bundleKey: "abc123",
|
||||
rootDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
addDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
instructionsFilePath: null,
|
||||
};
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod, promptBundle });
|
||||
expect(claudeArgs).toContain("--add-dir");
|
||||
expect(claudeArgs).toContain(promptBundle.addDir);
|
||||
});
|
||||
|
||||
it("uses bundle instructionsFilePath for --append-system-prompt-file when promptBundle provided", () => {
|
||||
const promptBundle = {
|
||||
bundleKey: "abc123",
|
||||
rootDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
addDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
instructionsFilePath: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123/agent-instructions.md",
|
||||
};
|
||||
ctx.config = { instructionsFilePath: "/raw/path/AGENTS.md" };
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod, promptBundle });
|
||||
expect(claudeArgs).toContain("--append-system-prompt-file");
|
||||
const idx = claudeArgs.indexOf("--append-system-prompt-file");
|
||||
expect(claudeArgs[idx + 1]).toBe(promptBundle.instructionsFilePath);
|
||||
expect(claudeArgs).not.toContain("/raw/path/AGENTS.md");
|
||||
});
|
||||
|
||||
it("omits --append-system-prompt-file from bundle on session resume", () => {
|
||||
const promptBundle = {
|
||||
bundleKey: "abc123",
|
||||
rootDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
addDir: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123",
|
||||
instructionsFilePath: "/paperclip/instances/default/companies/co1/claude-prompt-cache/abc123/agent-instructions.md",
|
||||
};
|
||||
ctx.runtime.sessionId = "sess_existing";
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod, promptBundle });
|
||||
expect(claudeArgs).not.toContain("--append-system-prompt-file");
|
||||
// --add-dir must still be present even on resume
|
||||
expect(claudeArgs).toContain("--add-dir");
|
||||
});
|
||||
|
||||
it("omits --add-dir when no promptBundle", () => {
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod });
|
||||
expect(claudeArgs).not.toContain("--add-dir");
|
||||
});
|
||||
|
||||
it("appends extraArgs when configured", () => {
|
||||
ctx.config = { extraArgs: ["--no-input", "--verbose"] };
|
||||
const { claudeArgs } = buildJobManifest({ ctx, selfPod });
|
||||
|
||||
Reference in New Issue
Block a user