fix: prepend IS_SANDBOX and PATH exports in buildFixScript (#2604)

Fixes #2603

Agent: code-health

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
A 2026-03-13 20:35:49 -07:00 committed by GitHub
parent 46646a29b5
commit f1f8b53dde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 17 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@openrouter/spawn",
"version": "0.17.14",
"version": "0.17.15",
"type": "module",
"bin": {
"spawn": "cli.js"

View file

@ -49,6 +49,10 @@ describe("buildFixScript", () => {
expect(script).toContain("set -eo pipefail");
expect(script).toContain("Re-injecting credentials");
expect(script).toContain("IS_SANDBOX");
expect(script).toContain(".npm-global/bin");
expect(script).toContain(".bun/bin");
expect(script).toContain(".cargo/bin");
expect(script).toContain("ANTHROPIC_API_KEY");
expect(script).toContain("~/.spawnrc");
expect(script).toContain("Re-installing agent");
@ -104,7 +108,7 @@ describe("buildFixScript", () => {
expect(script).toContain("Done!");
});
it("handles agents without env vars", () => {
it("handles agents without env vars — still writes IS_SANDBOX and PATH", () => {
const manifest = {
...mockManifest,
agents: {
@ -119,10 +123,30 @@ describe("buildFixScript", () => {
};
const script = buildFixScript(manifest, "claude");
expect(script).not.toContain(".spawnrc");
// IS_SANDBOX and PATH should always be written even without agent env vars
expect(script).toContain("IS_SANDBOX");
expect(script).toContain(".npm-global/bin");
expect(script).toContain("~/.spawnrc");
expect(script).toContain("Re-installing agent");
});
it("prepends IS_SANDBOX and PATH before agent env vars (matches generateEnvConfig)", () => {
const script = buildFixScript(mockManifest, "claude");
const isSandboxIdx = script.indexOf("IS_SANDBOX");
const pathIdx = script.indexOf(".npm-global/bin");
const anthropicIdx = script.indexOf("ANTHROPIC_API_KEY");
// All three must be present
expect(isSandboxIdx).toBeGreaterThan(-1);
expect(pathIdx).toBeGreaterThan(-1);
expect(anthropicIdx).toBeGreaterThan(-1);
// IS_SANDBOX and PATH must come before agent-specific env vars
expect(isSandboxIdx).toBeLessThan(anthropicIdx);
expect(pathIdx).toBeLessThan(anthropicIdx);
});
it("throws for unknown agent", () => {
expect(() => buildFixScript(mockManifest, "unknown-agent")).toThrow("Unknown agent: unknown-agent");
});

View file

@ -42,23 +42,26 @@ export function buildFixScript(manifest: Manifest, agentKey: string): string {
"",
];
// Re-inject env vars into ~/.spawnrc
// Re-inject env vars into ~/.spawnrc (must match generateEnvConfig() output)
const env = agentDef.env ?? {};
const envEntries = Object.entries(env);
if (envEntries.length > 0) {
lines.push("echo '==> Re-injecting credentials...'");
// Write new .spawnrc atomically: write to .new then mv into place
lines.push("{");
for (const [key, template] of envEntries) {
const value = resolveEnvTemplate(template);
lines.push(` printf 'export %s=%s\\n' ${shellSingleQuote(key)} ${shellSingleQuote(value)}`);
}
lines.push("} > ~/.spawnrc.new");
lines.push("mv ~/.spawnrc.new ~/.spawnrc");
lines.push("chmod 600 ~/.spawnrc");
lines.push("echo ' Credentials updated in ~/.spawnrc'");
lines.push("");
lines.push("echo '==> Re-injecting credentials...'");
// Write new .spawnrc atomically: write to .new then mv into place
lines.push("{");
// Always prepend IS_SANDBOX and PATH — matches generateEnvConfig() in shared/agents.ts
lines.push(" printf 'export IS_SANDBOX=\\x271\\x27\\n'");
lines.push(
" printf 'export PATH=\"$HOME/.npm-global/bin:$HOME/.bun/bin:$HOME/.local/bin:$HOME/.cargo/bin:$HOME/.claude/local/bin:$PATH\"\\n'",
);
for (const [key, template] of envEntries) {
const value = resolveEnvTemplate(template);
lines.push(` printf 'export %s=%s\\n' ${shellSingleQuote(key)} ${shellSingleQuote(value)}`);
}
lines.push("} > ~/.spawnrc.new");
lines.push("mv ~/.spawnrc.new ~/.spawnrc");
lines.push("chmod 600 ~/.spawnrc");
lines.push("echo ' Credentials updated in ~/.spawnrc'");
lines.push("");
// Re-run the agent's install command to get the latest version
const installCmd = agentDef.install;