fix: remove --bare flag to restore OAuth login for Claude Pro/Max #32
3 changed files with 27 additions and 23 deletions
|
|
@ -163,19 +163,17 @@ export async function runAgent(options: RunAgentOptions): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
// IMPORTANT: --bare prevents CLAUDE.md walk-up through parent directories.
|
// NOTE: --bare is intentionally NOT used here. --bare disables OAuth/keychain
|
||||||
// Without this flag every agent inherits the DisClaw project CLAUDE.md as
|
// auth and requires ANTHROPIC_API_KEY, which breaks Claude Pro/Max subscriptions.
|
||||||
// its identity (and any other CLAUDE.md files up the directory tree).
|
// CLAUDE.md isolation is handled structurally: workspaces live under
|
||||||
// --append-system-prompt-file injects the workspace-specific CLAUDE.md
|
// ~/.disclaw/workspaces/ (outside the DisClaw repo), so walk-up will never
|
||||||
// explicitly so each agent keeps its own isolated identity.
|
// reach the DisClaw project CLAUDE.md. The workspace CLAUDE.md is picked up
|
||||||
|
// automatically because cwd is set to workspacePath.
|
||||||
const args = [
|
const args = [
|
||||||
"-p",
|
"-p",
|
||||||
prompt,
|
prompt,
|
||||||
"--output-format",
|
"--output-format",
|
||||||
"json",
|
"json",
|
||||||
"--bare",
|
|
||||||
"--append-system-prompt-file",
|
|
||||||
path.join(workspacePath, "CLAUDE.md"),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const child = spawn(claudeCommand, args, {
|
const child = spawn(claudeCommand, args, {
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@ import * as os from "os";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration test: verifies that every Claude CLI invocation includes
|
* Integration test: verifies that Claude CLI invocations use the correct args.
|
||||||
* --bare (prevents CLAUDE.md walk-up through parent directories) and
|
*
|
||||||
* --append-system-prompt-file pointing to the workspace CLAUDE.md.
|
* CLAUDE.md isolation is achieved structurally (workspaces live outside the
|
||||||
|
* repo under ~/.disclaw/workspaces/) — NOT via --bare or --append-system-prompt-file.
|
||||||
|
* --bare was removed because it disables OAuth/keychain auth, breaking Claude
|
||||||
|
* Pro/Max subscriptions.
|
||||||
*
|
*
|
||||||
* We mock cross-spawn so no real process is launched, and capture the exact
|
* We mock cross-spawn so no real process is launched, and capture the exact
|
||||||
* args array that runner.ts would pass to the CLI.
|
* args array that runner.ts would pass to the CLI.
|
||||||
|
|
@ -116,7 +119,7 @@ describe("no-parent-claude-md-leak", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes --bare flag to the Claude CLI", async () => {
|
it("does NOT pass --bare flag (--bare disables OAuth and breaks Claude Pro/Max)", async () => {
|
||||||
await runAgent({
|
await runAgent({
|
||||||
workspacePath: workspaceDir,
|
workspacePath: workspaceDir,
|
||||||
channelName: "test-channel",
|
channelName: "test-channel",
|
||||||
|
|
@ -124,10 +127,10 @@ describe("no-parent-claude-md-leak", () => {
|
||||||
conversationHistory: [],
|
conversationHistory: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(capturedArgs).toContain("--bare");
|
expect(capturedArgs).not.toContain("--bare");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes --append-system-prompt-file pointing to workspace CLAUDE.md", async () => {
|
it("passes -p and --output-format json; does NOT pass --append-system-prompt-file", async () => {
|
||||||
await runAgent({
|
await runAgent({
|
||||||
workspacePath: workspaceDir,
|
workspacePath: workspaceDir,
|
||||||
channelName: "test-channel",
|
channelName: "test-channel",
|
||||||
|
|
@ -135,12 +138,12 @@ describe("no-parent-claude-md-leak", () => {
|
||||||
conversationHistory: [],
|
conversationHistory: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const idx = capturedArgs.indexOf("--append-system-prompt-file");
|
// Required args for non-interactive JSON output
|
||||||
expect(idx).toBeGreaterThanOrEqual(0);
|
expect(capturedArgs).toContain("-p");
|
||||||
|
expect(capturedArgs).toContain("--output-format");
|
||||||
|
expect(capturedArgs).toContain("json");
|
||||||
|
|
||||||
const systemPromptFile = capturedArgs[idx + 1];
|
// CLAUDE.md is auto-discovered via cwd (workspacePath), no flag needed
|
||||||
expect(systemPromptFile).toMatch(/CLAUDE\.md$/);
|
expect(capturedArgs).not.toContain("--append-system-prompt-file");
|
||||||
// Must point to the workspace-specific CLAUDE.md, not a parent directory
|
|
||||||
expect(systemPromptFile).toBe(path.join(workspaceDir, "CLAUDE.md"));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,13 @@ describe("sanitizedEnv", () => {
|
||||||
expect(result["SOME_SAFE_VAR"]).toBe("safe-value");
|
expect(result["SOME_SAFE_VAR"]).toBe("safe-value");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("(c) sets CI=true and DISCLAW_AGENT=1 as mandatory markers", () => {
|
it("(c) sets DISCLAW_AGENT=1 but does NOT set CI=true (breaks Claude Code OAuth)", () => {
|
||||||
|
// CI=true was removed: Claude Code interprets it as headless CI mode
|
||||||
|
// and requires ANTHROPIC_API_KEY instead of OAuth/keychain login.
|
||||||
|
delete process.env["CI"];
|
||||||
const result = sanitizedEnv();
|
const result = sanitizedEnv();
|
||||||
|
|
||||||
expect(result["CI"]).toBe("true");
|
expect(result["CI"]).toBeUndefined();
|
||||||
expect(result["DISCLAW_AGENT"]).toBe("1");
|
expect(result["DISCLAW_AGENT"]).toBe("1");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -91,7 +94,7 @@ describe("sanitizedEnv", () => {
|
||||||
expect(result["ANOTHER_KEY"]).toBeUndefined();
|
expect(result["ANOTHER_KEY"]).toBeUndefined();
|
||||||
// Extras and standard vars should still be present
|
// Extras and standard vars should still be present
|
||||||
expect(result["DISCLAW_AGENT_NAME"]).toBe("test-agent");
|
expect(result["DISCLAW_AGENT_NAME"]).toBe("test-agent");
|
||||||
expect(result["CI"]).toBe("true");
|
expect(result["DISCLAW_AGENT"]).toBe("1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not mutate process.env", () => {
|
it("does not mutate process.env", () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue