Compare commits

..

2 commits

Author SHA1 Message Date
dev
4661892820 Merge pull request 'fix: remove --bare flag to restore OAuth login for Claude Pro/Max' (#32) from fix/remove-bare-flag into main
Some checks are pending
CI / build-and-test (ubuntu-latest) (push) Waiting to run
CI / build-and-test (windows-latest) (push) Waiting to run
CI / lint (push) Waiting to run
Reviewed-on: #32
2026-04-09 11:56:24 +00:00
Nick Tabeling
aad45b9637 fix: remove --bare flag to restore OAuth login for Claude Pro/Max
Some checks failed
CI / build-and-test (ubuntu-latest) (pull_request) Has been cancelled
CI / build-and-test (windows-latest) (pull_request) Has been cancelled
CI / lint (pull_request) Has been cancelled
--bare disables OAuth/keychain auth and requires ANTHROPIC_API_KEY,
breaking Claude Pro/Max subscriptions. CLAUDE.md isolation is now
achieved structurally: workspaces live under ~/.disclaw/workspaces/
(outside the repo) so walk-up never reaches DisClaw's CLAUDE.md.

Update integration test to assert --bare is absent and verify correct
args (-p, --output-format json). Fix sanitize-env tests to reflect
CI=true removal (was breaking OAuth headless-mode detection).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:48:45 +02:00
3 changed files with 27 additions and 23 deletions

View file

@ -163,19 +163,17 @@ export async function runAgent(options: RunAgentOptions): Promise<string> {
}
return new Promise<string>((resolve, reject) => {
// IMPORTANT: --bare prevents CLAUDE.md walk-up through parent directories.
// Without this flag every agent inherits the DisClaw project CLAUDE.md as
// its identity (and any other CLAUDE.md files up the directory tree).
// --append-system-prompt-file injects the workspace-specific CLAUDE.md
// explicitly so each agent keeps its own isolated identity.
// NOTE: --bare is intentionally NOT used here. --bare disables OAuth/keychain
// auth and requires ANTHROPIC_API_KEY, which breaks Claude Pro/Max subscriptions.
// CLAUDE.md isolation is handled structurally: workspaces live under
// ~/.disclaw/workspaces/ (outside the DisClaw repo), so walk-up will never
// reach the DisClaw project CLAUDE.md. The workspace CLAUDE.md is picked up
// automatically because cwd is set to workspacePath.
const args = [
"-p",
prompt,
"--output-format",
"json",
"--bare",
"--append-system-prompt-file",
path.join(workspacePath, "CLAUDE.md"),
];
const child = spawn(claudeCommand, args, {

View file

@ -4,9 +4,12 @@ import * as os from "os";
import * as path from "path";
/**
* Integration test: verifies that every Claude CLI invocation includes
* --bare (prevents CLAUDE.md walk-up through parent directories) and
* --append-system-prompt-file pointing to the workspace CLAUDE.md.
* Integration test: verifies that Claude CLI invocations use the correct args.
*
* 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
* 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({
workspacePath: workspaceDir,
channelName: "test-channel",
@ -124,10 +127,10 @@ describe("no-parent-claude-md-leak", () => {
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({
workspacePath: workspaceDir,
channelName: "test-channel",
@ -135,12 +138,12 @@ describe("no-parent-claude-md-leak", () => {
conversationHistory: [],
});
const idx = capturedArgs.indexOf("--append-system-prompt-file");
expect(idx).toBeGreaterThanOrEqual(0);
// Required args for non-interactive JSON output
expect(capturedArgs).toContain("-p");
expect(capturedArgs).toContain("--output-format");
expect(capturedArgs).toContain("json");
const systemPromptFile = capturedArgs[idx + 1];
expect(systemPromptFile).toMatch(/CLAUDE\.md$/);
// Must point to the workspace-specific CLAUDE.md, not a parent directory
expect(systemPromptFile).toBe(path.join(workspaceDir, "CLAUDE.md"));
// CLAUDE.md is auto-discovered via cwd (workspacePath), no flag needed
expect(capturedArgs).not.toContain("--append-system-prompt-file");
});
});

View file

@ -55,10 +55,13 @@ describe("sanitizedEnv", () => {
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();
expect(result["CI"]).toBe("true");
expect(result["CI"]).toBeUndefined();
expect(result["DISCLAW_AGENT"]).toBe("1");
});
@ -91,7 +94,7 @@ describe("sanitizedEnv", () => {
expect(result["ANOTHER_KEY"]).toBeUndefined();
// Extras and standard vars should still be present
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", () => {