@rallycry/conveyor-agent 10.0.3 → 10.0.5

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.
@@ -944,8 +944,10 @@ function createServiceLogger(service) {
944
944
  }
945
945
 
946
946
  // src/runner/git-utils.ts
947
- import { execSync } from "child_process";
947
+ import { execSync, exec } from "child_process";
948
948
  import { realpathSync } from "fs";
949
+ import { promisify } from "util";
950
+ var execAsync = promisify(exec);
949
951
  function syncWithBaseBranch(cwd, baseBranch) {
950
952
  if (!baseBranch) return true;
951
953
  try {
@@ -1057,20 +1059,15 @@ function stageAndCommit(cwd, message) {
1057
1059
  return null;
1058
1060
  }
1059
1061
  }
1060
- function tryPush(cwd, branch, skipVerify = false) {
1062
+ async function tryPush(cwd, branch, skipVerify = false) {
1061
1063
  const noVerify = skipVerify ? "--no-verify " : "";
1062
1064
  try {
1063
- execSync(`git push ${noVerify}origin ${branch}`, {
1064
- cwd,
1065
- stdio: ["ignore", "pipe", "pipe"],
1066
- timeout: 3e4
1067
- });
1065
+ await execAsync(`git push ${noVerify}origin ${branch}`, { cwd, timeout: 3e4 });
1068
1066
  return true;
1069
1067
  } catch {
1070
1068
  try {
1071
- execSync(`git push ${noVerify}--force-with-lease origin ${branch}`, {
1069
+ await execAsync(`git push ${noVerify}--force-with-lease origin ${branch}`, {
1072
1070
  cwd,
1073
- stdio: ["ignore", "pipe", "pipe"],
1074
1071
  timeout: 3e4
1075
1072
  });
1076
1073
  return true;
@@ -1079,9 +1076,9 @@ function tryPush(cwd, branch, skipVerify = false) {
1079
1076
  }
1080
1077
  }
1081
1078
  }
1082
- function isAuthError(cwd) {
1079
+ async function isAuthError(cwd) {
1083
1080
  try {
1084
- execSync("git push --dry-run", { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
1081
+ await execAsync("git push --dry-run", { cwd, timeout: 3e4 });
1085
1082
  return false;
1086
1083
  } catch (err) {
1087
1084
  if (err.killed) return true;
@@ -1243,14 +1240,14 @@ async function pushToOrigin(cwd, refreshToken, skipVerify = false) {
1243
1240
  } catch {
1244
1241
  }
1245
1242
  }
1246
- if (tryPush(cwd, currentBranch, skipVerify)) return true;
1247
- if (refreshToken && isAuthError(cwd)) {
1243
+ if (await tryPush(cwd, currentBranch, skipVerify)) return true;
1244
+ if (refreshToken && await isAuthError(cwd)) {
1248
1245
  const token = await refreshToken();
1249
1246
  if (token) {
1250
1247
  updateRemoteToken(cwd, token);
1251
1248
  process.env.GITHUB_TOKEN = token;
1252
1249
  process.env.GH_TOKEN = token;
1253
- return tryPush(cwd, currentBranch, skipVerify);
1250
+ return await tryPush(cwd, currentBranch, skipVerify);
1254
1251
  }
1255
1252
  }
1256
1253
  return false;
@@ -1779,11 +1776,11 @@ function execErrorDetail(err) {
1779
1776
  const message = withStreams.message ?? String(err);
1780
1777
  return stderr ? `${message} \u2014 stderr: ${stderr}` : message;
1781
1778
  }
1782
- function dumpPostgresIfPresent(exec = execSync2) {
1779
+ function dumpPostgresIfPresent(exec2 = execSync2) {
1783
1780
  if (!hasPostgresDep()) return Promise.resolve({ dumped: false });
1784
1781
  const outputPath = path.join(tmpdir(), `conveyor-pgdump-${randomUUID()}.sql`);
1785
1782
  try {
1786
- exec(buildPgDumpCommand({ outputPath }), {
1783
+ exec2(buildPgDumpCommand({ outputPath }), {
1787
1784
  stdio: ["ignore", "pipe", "pipe"],
1788
1785
  timeout: 6e4
1789
1786
  });
@@ -1794,10 +1791,10 @@ function dumpPostgresIfPresent(exec = execSync2) {
1794
1791
  return Promise.resolve({ dumped: false });
1795
1792
  }
1796
1793
  }
1797
- function applyPgDumpIfConfigured(dumpPath, exec = execSync2) {
1794
+ function applyPgDumpIfConfigured(dumpPath, exec2 = execSync2) {
1798
1795
  if (!hasPostgresDep()) return false;
1799
1796
  try {
1800
- exec(buildPsqlRestoreCommand({ dumpPath }), {
1797
+ exec2(buildPsqlRestoreCommand({ dumpPath }), {
1801
1798
  stdio: ["ignore", "pipe", "pipe"],
1802
1799
  timeout: 12e4
1803
1800
  });
@@ -4890,6 +4887,95 @@ function truncatePlanForPrompt(plan) {
4890
4887
  return `${head}${PLAN_TRUNCATION_MARKER}${tail}`;
4891
4888
  }
4892
4889
 
4890
+ // src/execution/pm-relaunch-instructions.ts
4891
+ function resolvePmRelaunchIntent(context, isAuto, agentMode) {
4892
+ switch (agentMode) {
4893
+ case "building":
4894
+ return "build" /* Build */;
4895
+ case "review":
4896
+ return "review" /* Review */;
4897
+ default:
4898
+ break;
4899
+ }
4900
+ if (!isAuto) return "wait_for_team" /* WaitForTeam */;
4901
+ return context.plan?.trim() ? "auto_with_plan" /* AutoWithPlan */ : "auto_planning" /* AutoPlanning */;
4902
+ }
4903
+ function buildRelaunchMessageSummary(context, lastAgentIdx) {
4904
+ const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
4905
+ if (newMessages.length === 0) {
4906
+ return [`You have been relaunched. No new messages since your last session.`];
4907
+ }
4908
+ return [
4909
+ `You have been relaunched. Here are new messages since your last session:`,
4910
+ ...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`)
4911
+ ];
4912
+ }
4913
+ function buildPmBuildRelaunchParts(context, isAuto) {
4914
+ const parts = [
4915
+ `
4916
+ Your plan has been approved. Begin implementing it now.`,
4917
+ `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
4918
+ `Start by reading the relevant source files mentioned in the plan, then write code.`,
4919
+ `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`
4920
+ ];
4921
+ if (isAuto) {
4922
+ parts.push(
4923
+ `
4924
+ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
4925
+ `Your FIRST action must be reading source files from the plan, then immediately writing code.`,
4926
+ `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing.`,
4927
+ `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
4928
+ );
4929
+ }
4930
+ return parts;
4931
+ }
4932
+ function buildPmReviewRelaunchParts() {
4933
+ return [
4934
+ `
4935
+ Resume reviewing and coordinating this task.`,
4936
+ `Call list_subtasks to check current child-task state and progress.`,
4937
+ `Review children in ReviewPR status first, then approve and merge passing PRs.`,
4938
+ `Fire next child builds with start_child_cloud_build when ready.`,
4939
+ `Do not implement code directly or create a new PR from the PM review session.`
4940
+ ];
4941
+ }
4942
+ function buildPmAutoWithPlanRelaunchParts() {
4943
+ return [
4944
+ `
4945
+ You are in auto mode. A plan already exists for this task.`,
4946
+ `Verify that story points, title, and tags are set via get_current_plan, then call ExitPlanMode immediately to transition to building.`,
4947
+ `Do NOT wait for team input \u2014 proceed autonomously.`
4948
+ ];
4949
+ }
4950
+ function buildPmAutoPlanningRelaunchParts() {
4951
+ return [
4952
+ `
4953
+ You are in auto mode. Continue planning autonomously.`,
4954
+ `When the plan and all required properties are set, call ExitPlanMode to transition to building.`,
4955
+ `Do NOT wait for team input \u2014 proceed autonomously.`
4956
+ ];
4957
+ }
4958
+ function buildPmWaitForTeamRelaunchParts() {
4959
+ return [
4960
+ `
4961
+ You are the project manager for this task.`,
4962
+ `Review the context above and wait for the team to provide instructions before taking action.`
4963
+ ];
4964
+ }
4965
+ function buildPmRelaunchParts(context, lastAgentIdx, isAuto, agentMode) {
4966
+ const parts = buildRelaunchMessageSummary(context, lastAgentIdx);
4967
+ const intent = resolvePmRelaunchIntent(context, isAuto, agentMode);
4968
+ const intentPartsByIntent = {
4969
+ ["build" /* Build */]: () => buildPmBuildRelaunchParts(context, isAuto),
4970
+ ["review" /* Review */]: buildPmReviewRelaunchParts,
4971
+ ["auto_with_plan" /* AutoWithPlan */]: buildPmAutoWithPlanRelaunchParts,
4972
+ ["auto_planning" /* AutoPlanning */]: buildPmAutoPlanningRelaunchParts,
4973
+ ["wait_for_team" /* WaitForTeam */]: buildPmWaitForTeamRelaunchParts
4974
+ };
4975
+ parts.push(...intentPartsByIntent[intent]());
4976
+ return parts;
4977
+ }
4978
+
4893
4979
  // src/execution/mode-prompt.ts
4894
4980
  var SP_DESC_MAX_CHARS = 80;
4895
4981
  function truncateDescription(desc, maxChars) {
@@ -5360,59 +5446,6 @@ function detectRelaunchScenario(context, trustChatHistory = false) {
5360
5446
  const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === "user");
5361
5447
  return hasNewUserMessages ? "feedback_relaunch" : "idle_relaunch";
5362
5448
  }
5363
- function buildPmRelaunchParts(context, lastAgentIdx, isAuto, agentMode) {
5364
- const parts = [];
5365
- const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
5366
- if (newMessages.length > 0) {
5367
- parts.push(
5368
- `You have been relaunched. Here are new messages since your last session:`,
5369
- ...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`)
5370
- );
5371
- } else {
5372
- parts.push(`You have been relaunched. No new messages since your last session.`);
5373
- }
5374
- if (agentMode === "building" || agentMode === "review") {
5375
- parts.push(
5376
- `
5377
- Your plan has been approved. Begin implementing it now.`,
5378
- `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
5379
- `Start by reading the relevant source files mentioned in the plan, then write code.`,
5380
- `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`
5381
- );
5382
- if (isAuto) {
5383
- parts.push(
5384
- `
5385
- CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
5386
- `Your FIRST action must be reading source files from the plan, then immediately writing code.`,
5387
- `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing.`,
5388
- `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
5389
- );
5390
- }
5391
- } else if (isAuto) {
5392
- if (context.plan?.trim()) {
5393
- parts.push(
5394
- `
5395
- You are in auto mode. A plan already exists for this task.`,
5396
- `Verify that story points, title, and tags are set via get_current_plan, then call ExitPlanMode immediately to transition to building.`,
5397
- `Do NOT wait for team input \u2014 proceed autonomously.`
5398
- );
5399
- } else {
5400
- parts.push(
5401
- `
5402
- You are in auto mode. Continue planning autonomously.`,
5403
- `When the plan and all required properties are set, call ExitPlanMode to transition to building.`,
5404
- `Do NOT wait for team input \u2014 proceed autonomously.`
5405
- );
5406
- }
5407
- } else {
5408
- parts.push(
5409
- `
5410
- You are the project manager for this task.`,
5411
- `Review the context above and wait for the team to provide instructions before taking action.`
5412
- );
5413
- }
5414
- return parts;
5415
- }
5416
5449
  function buildRelaunchWithSession(mode, context, agentMode, isAuto) {
5417
5450
  const scenario = detectRelaunchScenario(context);
5418
5451
  const hasPriorTurn = !!context.lastSeenMessageId || !!context.claudeSessionId;
@@ -5527,7 +5560,10 @@ ${truncatePlanForPrompt(context.plan)}`);
5527
5560
  }
5528
5561
  return parts;
5529
5562
  }
5530
- function buildFreshInstructions(isPm, isAutoMode, context, agentMode) {
5563
+ function buildFreshInstructions(isPm, isCodeReview, isAutoMode, context, agentMode) {
5564
+ if (isCodeReview) {
5565
+ return buildFreshCodeReviewInstructions(context);
5566
+ }
5531
5567
  if (isPm && agentMode === "building") {
5532
5568
  return [
5533
5569
  `Your plan has been approved. Begin implementing it now.`,
@@ -5595,6 +5631,21 @@ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or g
5595
5631
  }
5596
5632
  return parts;
5597
5633
  }
5634
+ function buildFreshCodeReviewInstructions(context) {
5635
+ const parts = [
5636
+ `Perform the automated code review for this PR.`,
5637
+ `Work on the git branch "${context.githubBranch}". Stay on this branch for the entire review. Do not checkout or create other branches.`,
5638
+ `Start by running \`git diff ${context.baseBranch ?? "dev"}..HEAD\` to inspect the submitted changes, then read the task plan and surrounding code as needed.`,
5639
+ `Review for correctness, security, performance, error handling, test coverage, and consistency with existing patterns.`,
5640
+ `If small fixes are needed, make them directly, commit, push, and re-review the result.`,
5641
+ `Use approve_code_review when the PR passes review.`,
5642
+ `Use request_code_changes when substantive issues remain that you cannot fix directly.`
5643
+ ];
5644
+ if (context.githubPRUrl) {
5645
+ parts.push(`The PR under review is ${context.githubPRUrl}. Do not create a new PR.`);
5646
+ }
5647
+ return parts;
5648
+ }
5598
5649
  function buildFeedbackInstructions(context, isPm, agentMode, isAuto) {
5599
5650
  const lastAgentIdx = findLastAgentMessageIndex2(context.chatHistory);
5600
5651
  const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
@@ -5700,8 +5751,11 @@ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
5700
5751
  const parts = [`
5701
5752
  ## Instructions`];
5702
5753
  const isPm = mode === "pm";
5754
+ const isCodeReview = mode === "code-review" || !isPm && agentMode === "review";
5703
5755
  if (scenario === "fresh") {
5704
- parts.push(...buildFreshInstructions(isPm, agentMode === "auto", context, agentMode));
5756
+ parts.push(
5757
+ ...buildFreshInstructions(isPm, isCodeReview, agentMode === "auto", context, agentMode)
5758
+ );
5705
5759
  return parts;
5706
5760
  }
5707
5761
  if (scenario === "idle_relaunch") {
@@ -6072,7 +6126,7 @@ function buildCreatePullRequestTool(connection, config) {
6072
6126
  "Commit message for staging uncommitted changes. If not provided, a default message based on the PR title will be used."
6073
6127
  ),
6074
6128
  skipVerify: z5.boolean().optional().describe(
6075
- "Pass --no-verify to the git push, bypassing the local pre-push quality gate (lint/typecheck/test). Use this if a previous attempt failed on the pre-push hook in an environment where you've already run the gates yourself \u2014 CI still runs on the resulting PR."
6129
+ "Controls the local pre-push quality gate (lint/typecheck/test). Defaults to true (--no-verify): the push skips the local gate because you should run gates yourself before opening the PR and CI re-runs them on the resulting PR. Running the full gate synchronously during the push would block the agent's event loop long enough to drop the Conveyor socket connection. Pass false to force the local pre-push hook to run."
6076
6130
  )
6077
6131
  },
6078
6132
  async ({ title, body, branch, baseBranch, commitMessage, skipVerify }) => {
@@ -6107,7 +6161,7 @@ Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>`;
6107
6161
  return void 0;
6108
6162
  }
6109
6163
  },
6110
- skipVerify ?? false
6164
+ skipVerify ?? true
6111
6165
  );
6112
6166
  if (pushSuccess) {
6113
6167
  connection.sendEvent({
@@ -9859,4 +9913,4 @@ export {
9859
9913
  runStartCommand,
9860
9914
  unshallowRepo
9861
9915
  };
9862
- //# sourceMappingURL=chunk-QKRPJ7DB.js.map
9916
+ //# sourceMappingURL=chunk-S72TAMGA.js.map