opencara 0.24.3 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +99 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -499,6 +499,7 @@ function ensureConfigDir() {
|
|
|
499
499
|
fs.mkdirSync(dir, { recursive: true });
|
|
500
500
|
}
|
|
501
501
|
var DEFAULT_MAX_DIFF_SIZE_KB = 100;
|
|
502
|
+
var DEFAULT_MAX_SUMMARY_INPUT_KB = 500;
|
|
502
503
|
var DEFAULT_MAX_CONSECUTIVE_ERRORS = 10;
|
|
503
504
|
var DEFAULT_MAX_REPO_SIZE_MB = 100;
|
|
504
505
|
var DEFAULT_COMMAND_TEST_TIMEOUT_MS = 1e4;
|
|
@@ -705,6 +706,12 @@ function validateConfigData(data, envPlatformUrl) {
|
|
|
705
706
|
);
|
|
706
707
|
overrides.maxDiffSizeKb = DEFAULT_MAX_DIFF_SIZE_KB;
|
|
707
708
|
}
|
|
709
|
+
if (typeof data.max_summary_input_kb === "number" && data.max_summary_input_kb <= 0) {
|
|
710
|
+
console.warn(
|
|
711
|
+
`\u26A0 Config warning: max_summary_input_kb must be > 0, got ${data.max_summary_input_kb}, using default (${DEFAULT_MAX_SUMMARY_INPUT_KB})`
|
|
712
|
+
);
|
|
713
|
+
overrides.maxSummaryInputKb = DEFAULT_MAX_SUMMARY_INPUT_KB;
|
|
714
|
+
}
|
|
708
715
|
if (typeof data.max_consecutive_errors === "number" && data.max_consecutive_errors <= 0) {
|
|
709
716
|
console.warn(
|
|
710
717
|
`\u26A0 Config warning: max_consecutive_errors must be > 0, got ${data.max_consecutive_errors}, using default (${DEFAULT_MAX_CONSECUTIVE_ERRORS})`
|
|
@@ -745,6 +752,7 @@ function loadConfig() {
|
|
|
745
752
|
platformUrl: envPlatformUrl || DEFAULT_PLATFORM_URL,
|
|
746
753
|
authFile: null,
|
|
747
754
|
maxDiffSizeKb: DEFAULT_MAX_DIFF_SIZE_KB,
|
|
755
|
+
maxSummaryInputKb: DEFAULT_MAX_SUMMARY_INPUT_KB,
|
|
748
756
|
maxConsecutiveErrors: DEFAULT_MAX_CONSECUTIVE_ERRORS,
|
|
749
757
|
maxRepoSizeMb: DEFAULT_MAX_REPO_SIZE_MB,
|
|
750
758
|
codebaseDir: null,
|
|
@@ -804,6 +812,7 @@ function loadConfig() {
|
|
|
804
812
|
platformUrl: envPlatformUrl || (typeof data.platform_url === "string" ? data.platform_url : DEFAULT_PLATFORM_URL),
|
|
805
813
|
authFile: typeof data.auth_file === "string" && data.auth_file.trim() ? resolveFilePath(data.auth_file) : null,
|
|
806
814
|
maxDiffSizeKb: overrides.maxDiffSizeKb ?? (typeof data.max_diff_size_kb === "number" ? data.max_diff_size_kb : DEFAULT_MAX_DIFF_SIZE_KB),
|
|
815
|
+
maxSummaryInputKb: overrides.maxSummaryInputKb ?? (typeof data.max_summary_input_kb === "number" ? data.max_summary_input_kb : DEFAULT_MAX_SUMMARY_INPUT_KB),
|
|
807
816
|
maxConsecutiveErrors: overrides.maxConsecutiveErrors ?? (typeof data.max_consecutive_errors === "number" ? data.max_consecutive_errors : DEFAULT_MAX_CONSECUTIVE_ERRORS),
|
|
808
817
|
maxRepoSizeMb: overrides.maxRepoSizeMb ?? (typeof data.max_repo_size_mb === "number" ? data.max_repo_size_mb : DEFAULT_MAX_REPO_SIZE_MB),
|
|
809
818
|
codebaseDir: typeof data.codebase_dir === "string" ? data.codebase_dir : null,
|
|
@@ -1880,18 +1889,71 @@ function gitExec(command, args, cwd, opts) {
|
|
|
1880
1889
|
throw new Error(sanitizeTokens(message));
|
|
1881
1890
|
}
|
|
1882
1891
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1892
|
+
var DEFAULT_BRANCH_FALLBACKS = ["main", "master"];
|
|
1893
|
+
function isValidBranchName(name) {
|
|
1894
|
+
if (!name) return false;
|
|
1895
|
+
if (name.startsWith("-")) return false;
|
|
1896
|
+
if (name.includes("..")) return false;
|
|
1897
|
+
return /^[A-Za-z0-9_./-]+$/.test(name);
|
|
1898
|
+
}
|
|
1899
|
+
function fetchBranch(bareRepoPath, branch, ghAvailable) {
|
|
1887
1900
|
const credArgs = ghAvailable ? ["-c", `credential.helper=${GH_CREDENTIAL_HELPER}`] : [];
|
|
1888
1901
|
gitExec(
|
|
1889
1902
|
"git",
|
|
1890
|
-
[...credArgs, "fetch", "--force", "origin", `${
|
|
1903
|
+
[...credArgs, "fetch", "--force", "origin", `${branch}:refs/remotes/origin/${branch}`],
|
|
1891
1904
|
bareRepoPath
|
|
1892
1905
|
);
|
|
1906
|
+
}
|
|
1907
|
+
function isRemoteRefMissingError(err) {
|
|
1908
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1909
|
+
return /couldn't find remote ref/i.test(msg) || /couldnt find remote ref/i.test(msg) || /no such ref/i.test(msg) || /remote ref.*not found/i.test(msg) || /unknown revision or path not in the working tree/i.test(msg);
|
|
1910
|
+
}
|
|
1911
|
+
function deriveDefaultBranch(bareRepoPath, ghAvailable) {
|
|
1912
|
+
try {
|
|
1913
|
+
const out = gitExec("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], bareRepoPath).trim();
|
|
1914
|
+
const prefix = "refs/remotes/origin/";
|
|
1915
|
+
if (out.startsWith(prefix)) {
|
|
1916
|
+
const branch = out.slice(prefix.length);
|
|
1917
|
+
if (isValidBranchName(branch)) {
|
|
1918
|
+
try {
|
|
1919
|
+
fetchBranch(bareRepoPath, branch, ghAvailable);
|
|
1920
|
+
return branch;
|
|
1921
|
+
} catch {
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
} catch {
|
|
1926
|
+
}
|
|
1927
|
+
for (const candidate of DEFAULT_BRANCH_FALLBACKS) {
|
|
1928
|
+
try {
|
|
1929
|
+
fetchBranch(bareRepoPath, candidate, ghAvailable);
|
|
1930
|
+
return candidate;
|
|
1931
|
+
} catch {
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
throw new Error("Cannot derive default branch: origin/HEAD, main, and master all failed");
|
|
1935
|
+
}
|
|
1936
|
+
function diffFromWorktree(bareRepoPath, worktreePath, baseRef, ghAvailable, maxDiffBytes = 128 * 1024 * 1024) {
|
|
1937
|
+
let resolvedBaseRef;
|
|
1938
|
+
if (baseRef) {
|
|
1939
|
+
if (!isValidBranchName(baseRef)) {
|
|
1940
|
+
throw new Error(`Invalid base ref: ${baseRef}`);
|
|
1941
|
+
}
|
|
1942
|
+
try {
|
|
1943
|
+
fetchBranch(bareRepoPath, baseRef, ghAvailable);
|
|
1944
|
+
resolvedBaseRef = baseRef;
|
|
1945
|
+
} catch (err) {
|
|
1946
|
+
if (!isRemoteRefMissingError(err)) {
|
|
1947
|
+
throw err;
|
|
1948
|
+
}
|
|
1949
|
+
resolvedBaseRef = void 0;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (!resolvedBaseRef) {
|
|
1953
|
+
resolvedBaseRef = deriveDefaultBranch(bareRepoPath, ghAvailable);
|
|
1954
|
+
}
|
|
1893
1955
|
try {
|
|
1894
|
-
return gitExec("git", ["diff", `origin/${
|
|
1956
|
+
return gitExec("git", ["diff", `origin/${resolvedBaseRef}...HEAD`], worktreePath, {
|
|
1895
1957
|
maxBuffer: maxDiffBytes
|
|
1896
1958
|
});
|
|
1897
1959
|
} catch (err) {
|
|
@@ -2560,7 +2622,7 @@ function sleep(ms, signal) {
|
|
|
2560
2622
|
|
|
2561
2623
|
// src/summary.ts
|
|
2562
2624
|
var TIMEOUT_SAFETY_MARGIN_MS2 = 3e4;
|
|
2563
|
-
var MAX_INPUT_SIZE_BYTES =
|
|
2625
|
+
var MAX_INPUT_SIZE_BYTES = 500 * 1024;
|
|
2564
2626
|
var InputTooLargeError = class extends Error {
|
|
2565
2627
|
constructor(message) {
|
|
2566
2628
|
super(message);
|
|
@@ -2610,9 +2672,10 @@ function calculateInputSize(prompt2, reviews, diffContent, contextBlock) {
|
|
|
2610
2672
|
}
|
|
2611
2673
|
async function executeSummary(req, deps, runTool = executeTool) {
|
|
2612
2674
|
const inputSize = calculateInputSize(req.prompt, req.reviews, req.diffContent, req.contextBlock);
|
|
2613
|
-
|
|
2675
|
+
const maxInputBytes = deps.maxSummaryInputKb !== void 0 ? deps.maxSummaryInputKb * 1024 : MAX_INPUT_SIZE_BYTES;
|
|
2676
|
+
if (inputSize > maxInputBytes) {
|
|
2614
2677
|
throw new InputTooLargeError(
|
|
2615
|
-
`Summary input too large (${Math.round(inputSize / 1024)}KB > ${Math.round(
|
|
2678
|
+
`Summary input too large (${Math.round(inputSize / 1024)}KB > ${Math.round(maxInputBytes / 1024)}KB limit)`
|
|
2616
2679
|
);
|
|
2617
2680
|
}
|
|
2618
2681
|
const timeoutMs = req.timeout * 1e3;
|
|
@@ -4687,6 +4750,12 @@ function registerShutdownHandlers(controller, log, graceMs = SHUTDOWN_GRACE_MS)
|
|
|
4687
4750
|
};
|
|
4688
4751
|
}
|
|
4689
4752
|
var NON_RETRYABLE_STATUSES = /* @__PURE__ */ new Set([401, 403, 404]);
|
|
4753
|
+
function build404Hint(isGhAuthenticated) {
|
|
4754
|
+
if (isGhAuthenticated) {
|
|
4755
|
+
return ". Diff fetch returned 404. Possible causes: (a) PR not found, (b) the installation can't access this repo, or (c) a transient GitHub outage. See any `[fetchDiffViaGh]` warning above for the underlying `gh api` error.";
|
|
4756
|
+
}
|
|
4757
|
+
return ". If this is a private repo, ensure gh CLI is installed and authenticated: gh auth login";
|
|
4758
|
+
}
|
|
4690
4759
|
function toApiDiffUrl(webUrl) {
|
|
4691
4760
|
const match = webUrl.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)(?:\.diff)?$/);
|
|
4692
4761
|
if (!match) return null;
|
|
@@ -4748,7 +4817,7 @@ function computeRoles(agent) {
|
|
|
4748
4817
|
return ["review", "summary", "implement", "fix"];
|
|
4749
4818
|
}
|
|
4750
4819
|
var DIFF_FETCH_TIMEOUT_MS = 6e4;
|
|
4751
|
-
async function fetchDiffHttp(url, headers, signal, maxDiffSizeKb) {
|
|
4820
|
+
async function fetchDiffHttp(url, headers, signal, maxDiffSizeKb, isGhAuthenticatedFn = isGhAvailable) {
|
|
4752
4821
|
const maxBytes = maxDiffSizeKb ? maxDiffSizeKb * 1024 : Infinity;
|
|
4753
4822
|
const controller = new AbortController();
|
|
4754
4823
|
const timer = setTimeout(() => controller.abort(), DIFF_FETCH_TIMEOUT_MS);
|
|
@@ -4769,7 +4838,7 @@ async function fetchDiffHttp(url, headers, signal, maxDiffSizeKb) {
|
|
|
4769
4838
|
clearTimeout(timer);
|
|
4770
4839
|
signal?.removeEventListener("abort", onParentAbort);
|
|
4771
4840
|
if (!response.ok) {
|
|
4772
|
-
const hint = response.status === 404 ?
|
|
4841
|
+
const hint = response.status === 404 ? build404Hint(isGhAuthenticatedFn()) : "";
|
|
4773
4842
|
const msg = `Failed to fetch diff: ${response.status} ${response.statusText}${hint}`;
|
|
4774
4843
|
if (NON_RETRYABLE_STATUSES.has(response.status)) {
|
|
4775
4844
|
throw new NonRetryableError(msg);
|
|
@@ -5054,7 +5123,12 @@ async function handleTask(client, agentId, task, reviewDeps, consumptionDeps, ag
|
|
|
5054
5123
|
);
|
|
5055
5124
|
taskReviewDeps = { ...reviewDeps, codebaseDir: null };
|
|
5056
5125
|
}
|
|
5057
|
-
if (taskCheckoutPath && taskBareRepoPath
|
|
5126
|
+
if (taskCheckoutPath && taskBareRepoPath) {
|
|
5127
|
+
if (!base_ref) {
|
|
5128
|
+
logWarn(
|
|
5129
|
+
` Warning: task ${task_id} has no base_ref \u2014 deriving default branch from worktree`
|
|
5130
|
+
);
|
|
5131
|
+
}
|
|
5058
5132
|
try {
|
|
5059
5133
|
const ghAvailable = isGhAvailable();
|
|
5060
5134
|
const maxDiffBytes = reviewDeps.maxDiffSizeKb ? reviewDeps.maxDiffSizeKb * 1024 : void 0;
|
|
@@ -5077,23 +5151,16 @@ async function handleTask(client, agentId, task, reviewDeps, consumptionDeps, ag
|
|
|
5077
5151
|
diffContent = gitDiff;
|
|
5078
5152
|
log(` Diff generated via git (${Math.round(diffContent.length / 1024)}KB)`);
|
|
5079
5153
|
} catch (err) {
|
|
5154
|
+
const message = err.message;
|
|
5080
5155
|
if (err instanceof DiffTooLargeError) {
|
|
5081
|
-
logError(` ${
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
task_id,
|
|
5085
|
-
agentId,
|
|
5086
|
-
`Cannot access diff: ${err.message}`,
|
|
5087
|
-
logger
|
|
5088
|
-
);
|
|
5089
|
-
return { diffFetchFailed: true };
|
|
5156
|
+
logError(` ${message}`);
|
|
5157
|
+
} else {
|
|
5158
|
+
logError(` git diff failed for task ${task_id}: ${message}`);
|
|
5090
5159
|
}
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
);
|
|
5160
|
+
await safeReject(client, task_id, agentId, `Cannot access diff: ${message}`, logger);
|
|
5161
|
+
return { diffFetchFailed: true };
|
|
5094
5162
|
}
|
|
5095
|
-
}
|
|
5096
|
-
if (!diffContent) {
|
|
5163
|
+
} else {
|
|
5097
5164
|
try {
|
|
5098
5165
|
const result = await fetchDiff(diff_url, owner, repo, pr_number, {
|
|
5099
5166
|
githubToken: client.currentToken,
|
|
@@ -5736,7 +5803,7 @@ function sleep2(ms, signal) {
|
|
|
5736
5803
|
async function startAgent(agentId, platformUrl, agentInfo, reviewDeps, consumptionDeps, options) {
|
|
5737
5804
|
const client = new ApiClient(platformUrl, {
|
|
5738
5805
|
authToken: options?.authToken,
|
|
5739
|
-
cliVersion: "0.
|
|
5806
|
+
cliVersion: "0.25.1",
|
|
5740
5807
|
versionOverride: options?.versionOverride,
|
|
5741
5808
|
onTokenRefresh: options?.onTokenRefresh
|
|
5742
5809
|
});
|
|
@@ -6101,7 +6168,7 @@ async function startBatchAgents(config, agents, pollIntervalMs, oauthToken, opti
|
|
|
6101
6168
|
const { versionOverride, verbose, instancesOverride, agentOwner, userOrgs } = options;
|
|
6102
6169
|
const client = new ApiClient(config.platformUrl, {
|
|
6103
6170
|
authToken: oauthToken,
|
|
6104
|
-
cliVersion: "0.
|
|
6171
|
+
cliVersion: "0.25.1",
|
|
6105
6172
|
versionOverride,
|
|
6106
6173
|
onTokenRefresh: () => getValidToken(config.platformUrl, { configPath: config.authFile })
|
|
6107
6174
|
});
|
|
@@ -6307,6 +6374,7 @@ async function startAgentRouter() {
|
|
|
6307
6374
|
const reviewDeps = {
|
|
6308
6375
|
commandTemplate: commandTemplate ?? "",
|
|
6309
6376
|
maxDiffSizeKb: config.maxDiffSizeKb,
|
|
6377
|
+
maxSummaryInputKb: config.maxSummaryInputKb,
|
|
6310
6378
|
maxRepoSizeMb: config.maxRepoSizeMb,
|
|
6311
6379
|
codebaseDir,
|
|
6312
6380
|
livenessTimeoutMs: agentConfig?.livenessTimeout != null ? agentConfig.livenessTimeout * 1e3 : void 0
|
|
@@ -6373,6 +6441,7 @@ function startAgentByIndex(config, agentIndex, pollIntervalMs, oauthToken, versi
|
|
|
6373
6441
|
const reviewDeps = {
|
|
6374
6442
|
commandTemplate,
|
|
6375
6443
|
maxDiffSizeKb: config.maxDiffSizeKb,
|
|
6444
|
+
maxSummaryInputKb: config.maxSummaryInputKb,
|
|
6376
6445
|
maxRepoSizeMb: config.maxRepoSizeMb,
|
|
6377
6446
|
codebaseDir,
|
|
6378
6447
|
livenessTimeoutMs: agentConfig?.livenessTimeout != null ? agentConfig.livenessTimeout * 1e3 : void 0
|
|
@@ -6450,7 +6519,7 @@ agentCommand.command("start").description("Start agents in polling mode").option
|
|
|
6450
6519
|
}
|
|
6451
6520
|
config = loadConfig();
|
|
6452
6521
|
}
|
|
6453
|
-
console.log(formatVersionBanner("0.
|
|
6522
|
+
console.log(formatVersionBanner("0.25.1", "085f9a8"));
|
|
6454
6523
|
if (config.agents && config.agents.length > 0) {
|
|
6455
6524
|
const toolEntries = config.agents.map((a) => ({
|
|
6456
6525
|
tool: a.tool,
|
|
@@ -7272,7 +7341,7 @@ var statusCommand = new Command4("status").description("Show agent config, conne
|
|
|
7272
7341
|
});
|
|
7273
7342
|
|
|
7274
7343
|
// src/index.ts
|
|
7275
|
-
var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.
|
|
7344
|
+
var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.25.1"} (${"085f9a8"})`);
|
|
7276
7345
|
program.addCommand(agentCommand);
|
|
7277
7346
|
program.addCommand(authCommand());
|
|
7278
7347
|
program.addCommand(dedupCommand());
|