Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/clawsweeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
repositoryProfileForSlug,
type RepositoryProfile,
} from "./repository-profiles.js";
import { codexEnv } from "./codex-env.js";
import { codexEnv, codexLoginMethodConfig } from "./codex-env.js";
import {
ghRetryKind,
ghRetryWaitMs,
Expand Down Expand Up @@ -66,7 +66,7 @@ import {
} from "./clawsweeper-args.js";
import { escapeRegExp, safeOutputTail, trimMiddle, truncateText } from "./clawsweeper-text.js";

export { codexEnv } from "./codex-env.js";
export { codexEnv, resolveCodexLoginMethod, codexLoginMethodConfig } from "./codex-env.js";
export { parseGhJson, parseGhJsonLines } from "./github-json.js";
export { itemNumbersArg } from "./clawsweeper-args.js";
export { safeOutputTail } from "./clawsweeper-text.js";
Expand Down Expand Up @@ -6174,7 +6174,7 @@ function runCodex(options: {
}
const codexConfig = [
`model_reasoning_effort="${options.reasoningEffort}"`,
'forced_login_method="api"',
codexLoginMethodConfig(),
'approval_policy="never"',
];
if (options.serviceTier) codexConfig.splice(1, 0, `service_tier="${options.serviceTier}"`);
Expand Down Expand Up @@ -6434,7 +6434,7 @@ function runCodexAssist(options: {
writeFileSync(promptPath, prompt, "utf8");
const codexConfig = [
`model_reasoning_effort="${options.reasoningEffort}"`,
'forced_login_method="api"',
codexLoginMethodConfig(),
'approval_policy="never"',
];
const result = spawnSync(
Expand Down
14 changes: 14 additions & 0 deletions src/codex-env.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
const VALID_LOGIN_METHODS = new Set(["api", "chatgpt"]);

export function resolveCodexLoginMethod(): string {
const value = process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD?.trim().toLowerCase();
if (value && VALID_LOGIN_METHODS.has(value)) {
return value;
}
return "api";
}

export function codexLoginMethodConfig(): string {
return `forced_login_method="${resolveCodexLoginMethod()}"`;
}

export type CodexEnvOptions = {
ghToken?: string | undefined;
};
Expand Down
4 changes: 2 additions & 2 deletions src/commit-sweeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { publishCheckFromReport, splitFrontMatter } from "./commit-checks.js";
import { argBool, argNumber, argString, parseArgs, type Args } from "./clawsweeper-args.js";
import { safeOutputTail } from "./clawsweeper-text.js";
import { codexEnv } from "./codex-env.js";
import { codexEnv, codexLoginMethodConfig } from "./codex-env.js";
import { runText } from "./command.js";
import { ghRetryKind, ghRetryWaitMs } from "./github-retry.js";
import { DEFAULT_TARGET_REPO, repositoryProfileFor } from "./repository-profiles.js";
Expand Down Expand Up @@ -296,7 +296,7 @@ function runCodex(options: {
);
const codexConfig = [
`model_reasoning_effort="${options.reasoningEffort}"`,
'forced_login_method="api"',
codexLoginMethodConfig(),
'approval_policy="never"',
];
if (options.serviceTier) codexConfig.splice(1, 0, `service_tier="${options.serviceTier}"`);
Expand Down
4 changes: 2 additions & 2 deletions src/pr-close-coverage-proof.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { codexEnv } from "./codex-env.js";
import { codexEnv, codexLoginMethodConfig } from "./codex-env.js";
import { safeOutputTail, truncateText } from "./clawsweeper-text.js";

export type PrCloseCoverageProofModelDecision = "covered" | "keep_open";
Expand Down Expand Up @@ -252,7 +252,7 @@ export function runPrCloseCoverageProofModel(options: {
if (existsSync(outputPath)) unlinkSync(outputPath);
const codexConfig = [
`model_reasoning_effort="${options.runtime.reasoningEffort}"`,
'forced_login_method="api"',
codexLoginMethodConfig(),
'approval_policy="never"',
];
if (options.runtime.serviceTier) {
Expand Down
50 changes: 50 additions & 0 deletions test/clawsweeper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
referencingMergedPullRequestsForIssueForTest,
configSurfaceChangeFromPullFilesForTest,
codexEnv,
resolveCodexLoginMethod,
codexLoginMethodConfig,
dashboardClosedAt,
extractLatestClawSweeperReviewForTest,
filterReviewContextCommentsForTest,
Expand Down Expand Up @@ -16727,6 +16729,54 @@ test("codex subprocess env can expose an explicit read-only GitHub token", () =>
}
});

test("resolveCodexLoginMethod defaults to api", () => {
const original = process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
try {
delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
assert.equal(resolveCodexLoginMethod(), "api");
} finally {
if (original === undefined) delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
else process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = original;
}
});

test("resolveCodexLoginMethod accepts chatgpt", () => {
const original = process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
try {
process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = "chatgpt";
assert.equal(resolveCodexLoginMethod(), "chatgpt");
} finally {
if (original === undefined) delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
else process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = original;
}
});

test("resolveCodexLoginMethod rejects invalid values", () => {
const original = process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
try {
process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = "oauth-browser";
assert.equal(resolveCodexLoginMethod(), "api");
process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = "";
assert.equal(resolveCodexLoginMethod(), "api");
} finally {
if (original === undefined) delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
else process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = original;
}
});

test("codexLoginMethodConfig produces valid Codex config string", () => {
const original = process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
try {
delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
assert.equal(codexLoginMethodConfig(), 'forced_login_method="api"');
process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = "chatgpt";
assert.equal(codexLoginMethodConfig(), 'forced_login_method="chatgpt"');
} finally {
if (original === undefined) delete process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD;
else process.env.CLAWSWEEPER_CODEX_LOGIN_METHOD = original;
}
});

test("related title search terms keep issue-specific words", () => {
assert.deepEqual(
relatedTitleSearchTerms(
Expand Down