opencara 0.23.1 → 0.23.3

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.
Files changed (2) hide show
  1. package/dist/index.js +99 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3754,7 +3754,7 @@ async function executeIssueReviewTask(client, agentId, task, deps, timeoutSecond
3754
3754
  }
3755
3755
 
3756
3756
  // src/implement.ts
3757
- import { execFileSync as execFileSync6 } from "child_process";
3757
+ import { execFileSync as execFileSync6, spawn as spawn2 } from "child_process";
3758
3758
  import * as fs8 from "fs";
3759
3759
  import * as path8 from "path";
3760
3760
  var TIMEOUT_SAFETY_MARGIN_MS6 = 3e4;
@@ -3869,7 +3869,7 @@ function checkoutForImplement(owner, repo, issueNumber, branchName, baseDir) {
3869
3869
  }
3870
3870
  }
3871
3871
  const credArgs = ghAvailable ? ["-c", `credential.helper=${GH_CREDENTIAL_HELPER2}`] : [];
3872
- gitExec2([...credArgs, "fetch", "--force", "origin"], bareRepoPath);
3872
+ gitExec2([...credArgs, "fetch", "--force", "origin", "+refs/heads/*:refs/heads/*"], bareRepoPath);
3873
3873
  let defaultBranch;
3874
3874
  try {
3875
3875
  defaultBranch = gitExec2(
@@ -3953,6 +3953,57 @@ function createPR(worktreePath, issueNumber, issueTitle, summary, branchName) {
3953
3953
  const prNumber = parseInt(prNumberMatch[1], 10);
3954
3954
  return { prNumber, prUrl };
3955
3955
  }
3956
+ function isAgenticCommand(commandTemplate) {
3957
+ return commandTemplate.includes("${PROMPT}") && !commandTemplate.includes("--print");
3958
+ }
3959
+ function executeAgentic(commandTemplate, prompt2, timeoutMs, cwd, signal) {
3960
+ const allVars = { PROMPT: prompt2, CODEBASE_DIR: cwd };
3961
+ const { command, args } = parseCommandTemplate(commandTemplate, allVars);
3962
+ return new Promise((resolve2, reject) => {
3963
+ if (signal?.aborted) {
3964
+ reject(new ToolTimeoutError("Tool execution aborted"));
3965
+ return;
3966
+ }
3967
+ const child = spawn2(command, args, {
3968
+ stdio: "inherit",
3969
+ cwd
3970
+ });
3971
+ let settled = false;
3972
+ const timer = setTimeout(() => {
3973
+ if (!settled) {
3974
+ child.kill("SIGTERM");
3975
+ setTimeout(() => {
3976
+ if (!settled) child.kill("SIGKILL");
3977
+ }, 5e3);
3978
+ }
3979
+ }, timeoutMs);
3980
+ let onAbort;
3981
+ if (signal) {
3982
+ onAbort = () => {
3983
+ if (!settled) child.kill("SIGTERM");
3984
+ };
3985
+ signal.addEventListener("abort", onAbort, { once: true });
3986
+ }
3987
+ child.on("error", (err) => {
3988
+ clearTimeout(timer);
3989
+ if (onAbort && signal) signal.removeEventListener("abort", onAbort);
3990
+ if (settled) return;
3991
+ settled = true;
3992
+ reject(err);
3993
+ });
3994
+ child.on("close", (code, sig) => {
3995
+ clearTimeout(timer);
3996
+ if (onAbort && signal) signal.removeEventListener("abort", onAbort);
3997
+ if (settled) return;
3998
+ settled = true;
3999
+ if (sig === "SIGTERM" || sig === "SIGKILL") {
4000
+ reject(new ToolTimeoutError(`Tool timed out after ${Math.round(timeoutMs / 1e3)}s`));
4001
+ return;
4002
+ }
4003
+ resolve2({ exitCode: code ?? 1 });
4004
+ });
4005
+ });
4006
+ }
3956
4007
  async function executeImplement(task, worktreePath, deps, timeoutSeconds, signal, runTool = executeTool) {
3957
4008
  const timeoutMs = timeoutSeconds * 1e3;
3958
4009
  if (timeoutMs <= TIMEOUT_SAFETY_MARGIN_MS6) {
@@ -3960,6 +4011,25 @@ async function executeImplement(task, worktreePath, deps, timeoutSeconds, signal
3960
4011
  }
3961
4012
  const effectiveTimeout = timeoutMs - TIMEOUT_SAFETY_MARGIN_MS6;
3962
4013
  const prompt2 = buildImplementPrompt(task);
4014
+ if (isAgenticCommand(deps.commandTemplate)) {
4015
+ const result2 = await executeAgentic(
4016
+ deps.commandTemplate,
4017
+ prompt2,
4018
+ effectiveTimeout,
4019
+ worktreePath,
4020
+ signal
4021
+ );
4022
+ return {
4023
+ output: {
4024
+ summary: result2.exitCode === 0 ? "Implementation completed" : "Implementation failed",
4025
+ filesChanged: []
4026
+ },
4027
+ tokensUsed: 0,
4028
+ tokensEstimated: true,
4029
+ tokenDetail: { input: 0, output: 0, total: 0, parsed: false },
4030
+ agentic: true
4031
+ };
4032
+ }
3963
4033
  const result = await runTool(
3964
4034
  deps.commandTemplate,
3965
4035
  prompt2,
@@ -3980,7 +4050,8 @@ async function executeImplement(task, worktreePath, deps, timeoutSeconds, signal
3980
4050
  output,
3981
4051
  tokensUsed: result.tokensUsed + inputTokens,
3982
4052
  tokensEstimated: !result.tokensParsed,
3983
- tokenDetail
4053
+ tokenDetail,
4054
+ agentic: false
3984
4055
  };
3985
4056
  }
3986
4057
  async function executeImplementTask(client, agentId, task, deps, timeoutSeconds, logger, signal, runTool, role = "implement", gitOps = { checkoutForImplement, commitAndPush, createPR, cleanupImplementWorktree }) {
@@ -4011,6 +4082,27 @@ async function executeImplementTask(client, agentId, task, deps, timeoutSeconds,
4011
4082
  runTool
4012
4083
  );
4013
4084
  logger.log(` AI completed (${aiResult.tokensUsed.toLocaleString()} tokens)`);
4085
+ if (aiResult.agentic) {
4086
+ logger.log(" Agentic mode \u2014 AI handled commit/push/PR/review/merge");
4087
+ try {
4088
+ await client.post(`/api/tasks/${task.task_id}/result`, {
4089
+ agent_id: agentId,
4090
+ type: role,
4091
+ review_text: sanitizeTokens(aiResult.output.summary),
4092
+ tokens_used: aiResult.tokensUsed
4093
+ });
4094
+ logger.log(" Result submitted");
4095
+ } catch {
4096
+ logger.log(
4097
+ " Result submission skipped (claim may have expired \u2014 normal for agentic mode)"
4098
+ );
4099
+ }
4100
+ return {
4101
+ tokensUsed: aiResult.tokensUsed,
4102
+ tokensEstimated: aiResult.tokensEstimated,
4103
+ tokenDetail: aiResult.tokenDetail
4104
+ };
4105
+ }
4014
4106
  let filesChanged = 0;
4015
4107
  let uncommitted = 0;
4016
4108
  try {
@@ -5571,7 +5663,7 @@ function sleep2(ms, signal) {
5571
5663
  async function startAgent(agentId, platformUrl, agentInfo, reviewDeps, consumptionDeps, options) {
5572
5664
  const client = new ApiClient(platformUrl, {
5573
5665
  authToken: options?.authToken,
5574
- cliVersion: "0.23.1",
5666
+ cliVersion: "0.23.3",
5575
5667
  versionOverride: options?.versionOverride,
5576
5668
  onTokenRefresh: options?.onTokenRefresh
5577
5669
  });
@@ -5857,7 +5949,7 @@ async function startBatchAgents(config, agents, pollIntervalMs, oauthToken, opti
5857
5949
  const { versionOverride, verbose, instancesOverride, agentOwner, userOrgs } = options;
5858
5950
  const client = new ApiClient(config.platformUrl, {
5859
5951
  authToken: oauthToken,
5860
- cliVersion: "0.23.1",
5952
+ cliVersion: "0.23.3",
5861
5953
  versionOverride,
5862
5954
  onTokenRefresh: () => getValidToken(config.platformUrl, { configPath: config.authFile })
5863
5955
  });
@@ -6200,7 +6292,7 @@ agentCommand.command("start").description("Start agents in polling mode").option
6200
6292
  }
6201
6293
  config = loadConfig();
6202
6294
  }
6203
- console.log(formatVersionBanner("0.23.1", "4d7d9ed"));
6295
+ console.log(formatVersionBanner("0.23.3", "fb13aac"));
6204
6296
  if (config.agents && config.agents.length > 0) {
6205
6297
  const toolEntries = config.agents.map((a) => ({
6206
6298
  tool: a.tool,
@@ -7023,7 +7115,7 @@ var statusCommand = new Command4("status").description("Show agent config, conne
7023
7115
  });
7024
7116
 
7025
7117
  // src/index.ts
7026
- var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.23.1"} (${"4d7d9ed"})`);
7118
+ var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.23.3"} (${"fb13aac"})`);
7027
7119
  program.addCommand(agentCommand);
7028
7120
  program.addCommand(authCommand());
7029
7121
  program.addCommand(dedupCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.23.1",
3
+ "version": "0.23.3",
4
4
  "description": "Distributed AI code review agent — poll, review, and submit PR reviews using your own AI tools",
5
5
  "type": "module",
6
6
  "license": "MIT",