@rallycry/conveyor-agent 5.2.0 → 5.4.0

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.
@@ -752,7 +752,7 @@ function aggregateModelUsage(modelUsage) {
752
752
  }
753
753
  return { queryInputTokens, contextWindow, totalInputTokens, totalCacheRead, totalCacheCreation };
754
754
  }
755
- function emitContextUpdate(modelUsage, host, context) {
755
+ function emitContextUpdate(modelUsage, host, context, lastAssistantUsage) {
756
756
  const usage = aggregateModelUsage(modelUsage);
757
757
  let { contextWindow } = usage;
758
758
  const settings = context.agentSettings ?? host.config.agentSettings ?? {};
@@ -761,13 +761,15 @@ function emitContextUpdate(modelUsage, host, context) {
761
761
  contextWindow = 1e6;
762
762
  }
763
763
  if (contextWindow > 0) {
764
+ const currentContextTokens = lastAssistantUsage ? (lastAssistantUsage.input_tokens ?? 0) + (lastAssistantUsage.cache_read_input_tokens ?? 0) + (lastAssistantUsage.cache_creation_input_tokens ?? 0) : usage.queryInputTokens;
764
765
  host.connection.sendEvent({
765
766
  type: "context_update",
766
- contextTokens: usage.queryInputTokens,
767
+ contextTokens: currentContextTokens,
767
768
  contextWindow,
768
769
  inputTokens: usage.totalInputTokens,
769
770
  cacheReadInputTokens: usage.totalCacheRead,
770
- cacheCreationInputTokens: usage.totalCacheCreation
771
+ cacheCreationInputTokens: usage.totalCacheCreation,
772
+ totalTokensUsed: usage.queryInputTokens
771
773
  });
772
774
  }
773
775
  }
@@ -783,7 +785,7 @@ function trackCostSpending(host, context, cumulativeTotal) {
783
785
  });
784
786
  }
785
787
  }
786
- function handleSuccessResult(event, host, context, startTime) {
788
+ function handleSuccessResult(event, host, context, startTime, lastAssistantUsage) {
787
789
  const durationMs = Date.now() - startTime;
788
790
  const summary = event.result || "Task completed.";
789
791
  const retriable = isRetriableMessage(summary);
@@ -794,28 +796,38 @@ function handleSuccessResult(event, host, context, startTime) {
794
796
  }
795
797
  host.connection.sendEvent({ type: "completed", summary, costUsd: cumulativeTotal, durationMs });
796
798
  if (modelUsage && typeof modelUsage === "object") {
797
- emitContextUpdate(modelUsage, host, context);
799
+ emitContextUpdate(modelUsage, host, context, lastAssistantUsage);
798
800
  }
799
801
  trackCostSpending(host, context, cumulativeTotal);
800
802
  return { totalCostUsd: cumulativeTotal, retriable };
801
803
  }
802
804
  function handleErrorResult(event, host) {
803
805
  const errorMsg = event.errors.length > 0 ? event.errors.join(", ") : `Agent stopped: ${event.subtype}`;
806
+ const isStaleSession = errorMsg.includes("No conversation found with session ID");
807
+ if (isStaleSession) {
808
+ return { retriable: false, staleSession: true };
809
+ }
804
810
  const retriable = isRetriableMessage(errorMsg);
805
811
  host.connection.sendEvent({ type: "error", message: errorMsg });
806
812
  return { retriable };
807
813
  }
808
- function handleResultEvent(event, host, context, startTime) {
814
+ function handleResultEvent(event, host, context, startTime, lastAssistantUsage) {
809
815
  const resultSummary = event.subtype === "success" ? event.result : event.errors.join(", ");
810
816
  if (event.subtype === "success") {
811
- const result2 = handleSuccessResult(event, host, context, startTime);
817
+ const result2 = handleSuccessResult(
818
+ event,
819
+ host,
820
+ context,
821
+ startTime,
822
+ lastAssistantUsage
823
+ );
812
824
  return { ...result2, resultSummary };
813
825
  }
814
826
  const result = handleErrorResult(event, host);
815
827
  return { totalCostUsd: 0, ...result, resultSummary };
816
828
  }
817
- async function emitResultEvent(event, host, context, startTime) {
818
- const result = handleResultEvent(event, host, context, startTime);
829
+ async function emitResultEvent(event, host, context, startTime, lastAssistantUsage) {
830
+ const result = handleResultEvent(event, host, context, startTime, lastAssistantUsage);
819
831
  const durationMs = Date.now() - startTime;
820
832
  if (event.subtype === "success") {
821
833
  const successEvent = event;
@@ -826,12 +838,16 @@ async function emitResultEvent(event, host, context, startTime) {
826
838
  costUsd: result.totalCostUsd,
827
839
  durationMs
828
840
  });
829
- } else {
841
+ } else if (!result.staleSession) {
830
842
  const errorEvent = event;
831
843
  const errorMsg = errorEvent.errors.length > 0 ? errorEvent.errors.join(", ") : `Agent stopped: ${errorEvent.subtype}`;
832
844
  await host.callbacks.onEvent({ type: "error", message: errorMsg });
833
845
  }
834
- return { retriable: result.retriable, resultSummary: result.resultSummary };
846
+ return {
847
+ retriable: result.retriable,
848
+ resultSummary: result.resultSummary,
849
+ staleSession: result.staleSession
850
+ };
835
851
  }
836
852
  function handleRateLimitEvent(event, host) {
837
853
  const { rate_limit_info } = event;
@@ -878,6 +894,8 @@ async function processEvents(events, context, host) {
878
894
  let retriable = false;
879
895
  let resultSummary;
880
896
  let rateLimitResetsAt;
897
+ let staleSession;
898
+ let lastAssistantUsage;
881
899
  const turnToolCalls = [];
882
900
  for await (const event of events) {
883
901
  if (host.isStopped()) break;
@@ -890,8 +908,35 @@ async function processEvents(events, context, host) {
890
908
  switch (event.type) {
891
909
  case "system": {
892
910
  const systemEvent = event;
893
- const stored = await handleSystemEvent(systemEvent, host, context, sessionIdStored);
894
- if (stored) sessionIdStored = true;
911
+ if (systemEvent.subtype === "init") {
912
+ const stored = await handleSystemEvent(systemEvent, host, context, sessionIdStored);
913
+ if (stored) sessionIdStored = true;
914
+ } else if (systemEvent.subtype === "compact_boundary") {
915
+ const meta = systemEvent.compact_metadata;
916
+ if (meta) {
917
+ void host.callbacks.onEvent({
918
+ type: "context_compacted",
919
+ trigger: meta.trigger,
920
+ preTokens: meta.pre_tokens
921
+ });
922
+ }
923
+ } else if (systemEvent.subtype === "task_started") {
924
+ const msg = systemEvent;
925
+ void host.callbacks.onEvent({
926
+ type: "subagent_started",
927
+ sdkTaskId: msg.task_id ?? "",
928
+ description: msg.description ?? ""
929
+ });
930
+ } else if (systemEvent.subtype === "task_progress") {
931
+ const msg = systemEvent;
932
+ void host.callbacks.onEvent({
933
+ type: "subagent_progress",
934
+ sdkTaskId: msg.task_id ?? "",
935
+ description: msg.description ?? "",
936
+ toolUses: msg.usage?.tool_uses ?? 0,
937
+ durationMs: msg.usage?.duration_ms ?? 0
938
+ });
939
+ }
895
940
  break;
896
941
  }
897
942
  case "assistant": {
@@ -899,7 +944,12 @@ async function processEvents(events, context, host) {
899
944
  setTimeout(() => host.connection.sendTypingStart(), 200);
900
945
  isTyping = true;
901
946
  }
902
- await processAssistantEvent(event, host, turnToolCalls);
947
+ const assistantEvent = event;
948
+ await processAssistantEvent(assistantEvent, host, turnToolCalls);
949
+ const msgUsage = assistantEvent.message.usage;
950
+ if (msgUsage) {
951
+ lastAssistantUsage = msgUsage;
952
+ }
903
953
  break;
904
954
  }
905
955
  case "result": {
@@ -911,10 +961,14 @@ async function processEvents(events, context, host) {
911
961
  event,
912
962
  host,
913
963
  context,
914
- startTime
964
+ startTime,
965
+ lastAssistantUsage
915
966
  );
916
967
  retriable = resultInfo.retriable;
917
968
  resultSummary = resultInfo.resultSummary;
969
+ if (resultInfo.staleSession) {
970
+ staleSession = true;
971
+ }
918
972
  break;
919
973
  }
920
974
  case "rate_limit_event": {
@@ -922,12 +976,26 @@ async function processEvents(events, context, host) {
922
976
  if (resetsAt) rateLimitResetsAt = resetsAt;
923
977
  break;
924
978
  }
979
+ case "tool_progress": {
980
+ const msg = event;
981
+ void host.callbacks.onEvent({
982
+ type: "tool_progress",
983
+ toolName: msg.tool_name ?? "",
984
+ elapsedSeconds: msg.elapsed_time_seconds ?? 0
985
+ });
986
+ break;
987
+ }
925
988
  }
926
989
  }
927
990
  if (isTyping) {
928
991
  host.connection.sendTypingStop();
929
992
  }
930
- return { retriable, resultSummary, rateLimitResetsAt };
993
+ return {
994
+ retriable,
995
+ resultSummary,
996
+ rateLimitResetsAt,
997
+ ...staleSession && { staleSession }
998
+ };
931
999
  }
932
1000
 
933
1001
  // src/execution/query-executor.ts
@@ -1323,7 +1391,7 @@ Your responses are sent directly to the task chat \u2014 the team sees everythin
1323
1391
  );
1324
1392
  if (!isPm || isPmActive) {
1325
1393
  parts.push(
1326
- `Use the create_pull_request tool to open PRs \u2014 do NOT use gh CLI or shell commands for PR creation.`
1394
+ `Use the mcp__conveyor__create_pull_request tool to open PRs \u2014 do NOT use gh CLI or shell commands for PR creation.`
1327
1395
  );
1328
1396
  }
1329
1397
  const modePrompt = buildModePrompt(agentMode, context);
@@ -1394,7 +1462,7 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
1394
1462
  );
1395
1463
  } else {
1396
1464
  parts.push(
1397
- `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI.`
1465
+ `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`
1398
1466
  );
1399
1467
  }
1400
1468
  } else {
@@ -1501,12 +1569,12 @@ function buildFreshInstructions(isPm, isAutoMode, context, agentMode) {
1501
1569
  `Your plan has been approved. Begin implementing it now.`,
1502
1570
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
1503
1571
  `Start by reading the relevant source files mentioned in the plan, then write code.`,
1504
- `When finished, commit and push your changes, then use the create_pull_request tool to open a PR. Do NOT use gh CLI.`,
1572
+ `When finished, commit and push your changes, then use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,
1505
1573
  `
1506
1574
  CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
1507
1575
  `Your FIRST action must be reading source files from the plan, then immediately writing code.`,
1508
1576
  `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing.`,
1509
- `When all changes are committed and pushed, use create_pull_request to open a PR.`,
1577
+ `When all changes are committed and pushed, use mcp__conveyor__create_pull_request to open a PR.`,
1510
1578
  `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
1511
1579
  ];
1512
1580
  }
@@ -1540,14 +1608,14 @@ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or g
1540
1608
  `Your FIRST action should be reading the relevant source files mentioned in the plan, then writing code. Do NOT run install, build, lint, test, or dev server commands first \u2014 the environment is already set up.`,
1541
1609
  `Work on the git branch "${context.githubBranch}". Stay on this branch for the entire task. Do not checkout or create other branches.`,
1542
1610
  `Your replies are visible to the team in chat \u2014 briefly describe what you're doing when you begin meaningful implementation, and again when the PR is ready.`,
1543
- `When finished, commit your changes, then run \`git fetch origin ${context.githubBranch}\` and \`git push origin ${context.githubBranch}\` (use --force-with-lease if push fails). Then use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1611
+ `When finished, commit your changes, then run \`git fetch origin ${context.githubBranch}\` and \`git push origin ${context.githubBranch}\` (use --force-with-lease if push fails). Then use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1544
1612
  ];
1545
1613
  if (isAutoMode) {
1546
1614
  parts.push(
1547
1615
  `
1548
1616
  CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
1549
1617
  `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing immediately.`,
1550
- `When all changes are committed and pushed, you MUST use create_pull_request to open a PR before finishing.`,
1618
+ `When all changes are committed and pushed, you MUST use mcp__conveyor__create_pull_request to open a PR before finishing.`,
1551
1619
  `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
1552
1620
  );
1553
1621
  }
@@ -1584,7 +1652,7 @@ Address the requested changes directly. Do NOT re-investigate the codebase from
1584
1652
  );
1585
1653
  } else {
1586
1654
  parts.push(
1587
- `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1655
+ `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1588
1656
  );
1589
1657
  }
1590
1658
  return parts;
@@ -1896,6 +1964,30 @@ function buildGetTaskIncidentsTool(connection) {
1896
1964
  { annotations: { readOnlyHint: true } }
1897
1965
  );
1898
1966
  }
1967
+ function buildCreatePullRequestTool(connection) {
1968
+ return tool(
1969
+ "create_pull_request",
1970
+ "Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
1971
+ {
1972
+ title: z.string().describe("The PR title"),
1973
+ body: z.string().describe("The PR description/body in markdown")
1974
+ },
1975
+ async ({ title, body }) => {
1976
+ try {
1977
+ const result = await connection.createPR({ title, body });
1978
+ connection.sendEvent({
1979
+ type: "pr_created",
1980
+ url: result.url,
1981
+ number: result.number
1982
+ });
1983
+ return textResult(`Pull request #${result.number} created: ${result.url}`);
1984
+ } catch (error) {
1985
+ const msg = error instanceof Error ? error.message : "Unknown error";
1986
+ return textResult(`Failed to create pull request: ${msg}`);
1987
+ }
1988
+ }
1989
+ );
1990
+ }
1899
1991
  function buildCommonTools(connection, config) {
1900
1992
  return [
1901
1993
  buildReadTaskChatTool(connection),
@@ -1907,7 +1999,8 @@ function buildCommonTools(connection, config) {
1907
1999
  buildListTaskFilesTool(connection),
1908
2000
  buildGetTaskFileTool(connection),
1909
2001
  buildSearchIncidentsTool(connection),
1910
- buildGetTaskIncidentsTool(connection)
2002
+ buildGetTaskIncidentsTool(connection),
2003
+ buildCreatePullRequestTool(connection)
1911
2004
  ];
1912
2005
  }
1913
2006
 
@@ -2075,42 +2168,12 @@ function buildPackTools(connection) {
2075
2168
  ];
2076
2169
  }
2077
2170
 
2078
- // src/tools/task-tools.ts
2171
+ // src/tools/discovery-tools.ts
2079
2172
  import { tool as tool3 } from "@anthropic-ai/claude-agent-sdk";
2080
2173
  import { z as z3 } from "zod";
2081
- function buildTaskTools(connection) {
2082
- return [
2083
- tool3(
2084
- "create_pull_request",
2085
- "Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
2086
- {
2087
- title: z3.string().describe("The PR title"),
2088
- body: z3.string().describe("The PR description/body in markdown")
2089
- },
2090
- async ({ title, body }) => {
2091
- try {
2092
- const result = await connection.createPR({ title, body });
2093
- connection.sendEvent({
2094
- type: "pr_created",
2095
- url: result.url,
2096
- number: result.number
2097
- });
2098
- return textResult(`Pull request #${result.number} created: ${result.url}`);
2099
- } catch (error) {
2100
- const msg = error instanceof Error ? error.message : "Unknown error";
2101
- return textResult(`Failed to create pull request: ${msg}`);
2102
- }
2103
- }
2104
- )
2105
- ];
2106
- }
2107
-
2108
- // src/tools/discovery-tools.ts
2109
- import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
2110
- import { z as z4 } from "zod";
2111
2174
  function buildIconTools(connection) {
2112
2175
  return [
2113
- tool4(
2176
+ tool3(
2114
2177
  "list_icons",
2115
2178
  "List available icons (default library + user-created). Returns icon IDs, names, and whether they're defaults. Call this FIRST before set_task_icon to check for existing matches.",
2116
2179
  {},
@@ -2126,11 +2189,11 @@ function buildIconTools(connection) {
2126
2189
  },
2127
2190
  { annotations: { readOnlyHint: true } }
2128
2191
  ),
2129
- tool4(
2192
+ tool3(
2130
2193
  "set_task_icon",
2131
2194
  "Assign an existing icon to this task by its ID. Use list_icons first to find a matching icon.",
2132
2195
  {
2133
- iconId: z4.string().describe("The icon ID to assign")
2196
+ iconId: z3.string().describe("The icon ID to assign")
2134
2197
  },
2135
2198
  async ({ iconId }) => {
2136
2199
  try {
@@ -2143,14 +2206,14 @@ function buildIconTools(connection) {
2143
2206
  }
2144
2207
  }
2145
2208
  ),
2146
- tool4(
2209
+ tool3(
2147
2210
  "generate_task_icon",
2148
2211
  "Generate a new SVG icon using AI and assign it to this task. Only use if no existing icon from list_icons is a good fit. Provide a concise visual description.",
2149
2212
  {
2150
- prompt: z4.string().describe(
2213
+ prompt: z3.string().describe(
2151
2214
  "Description of the icon to generate (e.g. 'minimal flat gear and wrench icon')"
2152
2215
  ),
2153
- aspectRatio: z4.enum(["auto", "portrait", "landscape", "square"]).optional().describe("Icon aspect ratio, defaults to square")
2216
+ aspectRatio: z3.enum(["auto", "portrait", "landscape", "square"]).optional().describe("Icon aspect ratio, defaults to square")
2154
2217
  },
2155
2218
  async ({ prompt, aspectRatio }) => {
2156
2219
  try {
@@ -2168,10 +2231,10 @@ function buildIconTools(connection) {
2168
2231
  function buildDiscoveryTools(connection, context) {
2169
2232
  const spDescription = buildStoryPointDescription(context?.storyPoints);
2170
2233
  return [
2171
- tool4(
2234
+ tool3(
2172
2235
  "set_story_points",
2173
2236
  "Set the story point estimate for this task. Use after understanding the scope of the work.",
2174
- { value: z4.number().describe(spDescription) },
2237
+ { value: z3.number().describe(spDescription) },
2175
2238
  async ({ value }) => {
2176
2239
  try {
2177
2240
  await Promise.resolve(connection.updateTaskProperties({ storyPointValue: value }));
@@ -2183,11 +2246,11 @@ function buildDiscoveryTools(connection, context) {
2183
2246
  }
2184
2247
  }
2185
2248
  ),
2186
- tool4(
2249
+ tool3(
2187
2250
  "set_task_tags",
2188
2251
  "Assign tags to this task from the project's available tags. Use the tag IDs from the project tags list.",
2189
2252
  {
2190
- tagIds: z4.array(z4.string()).describe("Array of tag IDs to assign")
2253
+ tagIds: z3.array(z3.string()).describe("Array of tag IDs to assign")
2191
2254
  },
2192
2255
  async ({ tagIds }) => {
2193
2256
  try {
@@ -2200,11 +2263,11 @@ function buildDiscoveryTools(connection, context) {
2200
2263
  }
2201
2264
  }
2202
2265
  ),
2203
- tool4(
2266
+ tool3(
2204
2267
  "set_task_title",
2205
2268
  "Update the task title to better reflect the planned work.",
2206
2269
  {
2207
- title: z4.string().describe("The new task title")
2270
+ title: z3.string().describe("The new task title")
2208
2271
  },
2209
2272
  async ({ title }) => {
2210
2273
  try {
@@ -2231,10 +2294,7 @@ function imageBlock(data, mimeType) {
2231
2294
  function getModeTools(agentMode, connection, config, context) {
2232
2295
  switch (agentMode) {
2233
2296
  case "building":
2234
- return context?.isParentTask ? [
2235
- ...buildTaskTools(connection),
2236
- ...buildPmTools(connection, context?.storyPoints, { includePackTools: true })
2237
- ] : buildTaskTools(connection);
2297
+ return context?.isParentTask ? buildPmTools(connection, context?.storyPoints, { includePackTools: true }) : [];
2238
2298
  case "review":
2239
2299
  case "auto":
2240
2300
  case "discovery":
@@ -2243,7 +2303,7 @@ function getModeTools(agentMode, connection, config, context) {
2243
2303
  includePackTools: !!context?.isParentTask
2244
2304
  });
2245
2305
  default:
2246
- return config.mode === "pm" ? buildPmTools(connection, context?.storyPoints, { includePackTools: false }) : buildTaskTools(connection);
2306
+ return config.mode === "pm" ? buildPmTools(connection, context?.storyPoints, { includePackTools: false }) : [];
2247
2307
  }
2248
2308
  }
2249
2309
  function createConveyorMcpServer(connection, config, context, agentMode) {
@@ -2696,16 +2756,15 @@ async function runWithRetry(initialQuery, context, host, options) {
2696
2756
  if (host.isStopped()) return;
2697
2757
  const agentQuery = attempt === 0 ? initialQuery : buildRetryQuery(host, context, options, lastErrorWasImage);
2698
2758
  try {
2699
- const { retriable, resultSummary, modeRestart, rateLimitResetsAt } = await processEvents(
2700
- agentQuery,
2701
- context,
2702
- host
2703
- );
2759
+ const { retriable, resultSummary, modeRestart, rateLimitResetsAt, staleSession } = await processEvents(agentQuery, context, host);
2704
2760
  if (modeRestart || host.isStopped()) return;
2705
2761
  if (rateLimitResetsAt) {
2706
2762
  handleRateLimitPause(host, rateLimitResetsAt);
2707
2763
  return;
2708
2764
  }
2765
+ if (staleSession && context.claudeSessionId) {
2766
+ return handleStaleSession(context, host, options);
2767
+ }
2709
2768
  if (!retriable) return;
2710
2769
  lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
2711
2770
  } catch (error) {
@@ -2859,7 +2918,6 @@ function pushSetupLog(setupLog, line) {
2859
2918
  }
2860
2919
  }
2861
2920
  async function executeSetupConfig(config, runnerConfig, connection, setupLog) {
2862
- let deferredStartConfig = null;
2863
2921
  if (config.setupCommand) {
2864
2922
  pushSetupLog(setupLog, `$ ${config.setupCommand}`);
2865
2923
  await runSetupCommand(config.setupCommand, runnerConfig.workspaceDir, (stream, data) => {
@@ -2876,7 +2934,6 @@ async function executeSetupConfig(config, runnerConfig, connection, setupLog) {
2876
2934
  connection.sendEvent({ type: "start_command_output", stream, data });
2877
2935
  });
2878
2936
  }
2879
- return deferredStartConfig;
2880
2937
  }
2881
2938
  async function checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog) {
2882
2939
  const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
@@ -2923,62 +2980,23 @@ async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, _effe
2923
2980
  );
2924
2981
  }
2925
2982
  if (!await checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog)) {
2926
- return { ok: false, deferredStartConfig: null };
2927
- }
2928
- const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
2929
- if (taskBranch) {
2930
- pushSetupLog(setupLog, `[conveyor] Switching to task branch ${taskBranch}...`);
2931
- connection.sendEvent({
2932
- type: "setup_output",
2933
- stream: "stdout",
2934
- data: `Switching to task branch ${taskBranch}...
2935
- `
2936
- });
2937
- try {
2938
- await runSetupCommand(
2939
- `git fetch origin ${taskBranch} && git checkout ${taskBranch}`,
2940
- runnerConfig.workspaceDir,
2941
- (stream, data) => {
2942
- connection.sendEvent({ type: "setup_output", stream, data });
2943
- for (const line of data.split("\n").filter(Boolean)) {
2944
- pushSetupLog(setupLog, `[${stream}] ${line}`);
2945
- }
2946
- }
2947
- );
2948
- pushSetupLog(setupLog, `[conveyor] Switched to ${taskBranch}`);
2949
- } catch (error) {
2950
- const message = `Failed to checkout ${taskBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2951
- connection.sendEvent({ type: "setup_error", message });
2952
- await callbacks.onEvent({ type: "setup_error", message });
2953
- connection.postChatMessage(
2954
- `Failed to switch to task branch \`${taskBranch}\`.
2955
-
2956
- ${message}`
2957
- );
2958
- return { ok: false, deferredStartConfig: null };
2959
- }
2983
+ return { ok: false, conveyorConfig: null };
2960
2984
  }
2961
2985
  const config = await loadConveyorConfig(runnerConfig.workspaceDir);
2962
2986
  if (!config) {
2963
2987
  connection.sendEvent({ type: "setup_complete" });
2964
2988
  await callbacks.onEvent({ type: "setup_complete" });
2965
- return { ok: true, deferredStartConfig: null };
2989
+ return { ok: true, conveyorConfig: null };
2966
2990
  }
2967
2991
  try {
2968
- const deferredStartConfig = await executeSetupConfig(
2969
- config,
2970
- runnerConfig,
2971
- connection,
2972
- setupLog
2973
- );
2992
+ await executeSetupConfig(config, runnerConfig, connection, setupLog);
2974
2993
  const setupEvent = {
2975
2994
  type: "setup_complete",
2976
- previewPort: config.previewPort ?? void 0,
2977
- startCommandDeferred: deferredStartConfig === null ? void 0 : true
2995
+ previewPort: config.previewPort ?? void 0
2978
2996
  };
2979
2997
  connection.sendEvent(setupEvent);
2980
2998
  await callbacks.onEvent(setupEvent);
2981
- return { ok: true, deferredStartConfig };
2999
+ return { ok: true, conveyorConfig: config };
2982
3000
  } catch (error) {
2983
3001
  const message = error instanceof Error ? error.message : "Setup failed";
2984
3002
  connection.sendEvent({ type: "setup_error", message });
@@ -2987,7 +3005,7 @@ ${message}`
2987
3005
  `Environment setup failed: ${message}
2988
3006
  The agent cannot start until this is resolved.`
2989
3007
  );
2990
- return { ok: false, deferredStartConfig: null };
3008
+ return { ok: false, conveyorConfig: null };
2991
3009
  }
2992
3010
  }
2993
3011
  function runAuthTokenSafe(config, connection, taskContext) {
@@ -3001,16 +3019,16 @@ function runAuthTokenSafe(config, connection, taskContext) {
3001
3019
  } catch {
3002
3020
  }
3003
3021
  }
3004
- function runDeferredStartCommand(deferredStartConfig, runnerConfig, connection, setupLog) {
3005
- if (!deferredStartConfig?.startCommand) return;
3006
- pushSetupLog(setupLog, `$ ${deferredStartConfig.startCommand} & (background, deferred)`);
3022
+ function rerunStartCommand(conveyorConfig, runnerConfig, connection, setupLog) {
3023
+ if (!conveyorConfig.startCommand) return;
3024
+ pushSetupLog(setupLog, `$ ${conveyorConfig.startCommand} & (background, re-trigger)`);
3007
3025
  connection.sendEvent({ type: "start_command_started" });
3008
- runStartCommand(deferredStartConfig.startCommand, runnerConfig.workspaceDir, (stream, data) => {
3026
+ runStartCommand(conveyorConfig.startCommand, runnerConfig.workspaceDir, (stream, data) => {
3009
3027
  connection.sendEvent({ type: "start_command_output", stream, data });
3010
3028
  });
3011
3029
  const setupEvent = {
3012
3030
  type: "setup_complete",
3013
- previewPort: deferredStartConfig.previewPort ?? void 0
3031
+ previewPort: conveyorConfig.previewPort ?? void 0
3014
3032
  };
3015
3033
  connection.sendEvent(setupEvent);
3016
3034
  }
@@ -3153,7 +3171,7 @@ var AgentRunner = class {
3153
3171
  prNudgeCount = 0;
3154
3172
  idleTimer = null;
3155
3173
  idleCheckInterval = null;
3156
- deferredStartConfig = null;
3174
+ conveyorConfig = null;
3157
3175
  _queryHost = null;
3158
3176
  constructor(config, callbacks) {
3159
3177
  this.config = config;
@@ -3225,7 +3243,7 @@ var AgentRunner = class {
3225
3243
  this.connection.disconnect();
3226
3244
  return;
3227
3245
  }
3228
- this.deferredStartConfig = result.deferredStartConfig;
3246
+ this.conveyorConfig = result.conveyorConfig;
3229
3247
  }
3230
3248
  this.tryInitWorktree();
3231
3249
  if (!await this.fetchAndInitContext()) return;
@@ -3295,47 +3313,38 @@ var AgentRunner = class {
3295
3313
  } catch {
3296
3314
  }
3297
3315
  }
3298
- async maybeSendPRNudge() {
3316
+ needsPRNudge() {
3299
3317
  if (!this.config.isAuto || this.stopped) return false;
3300
3318
  const maxNudges = this.taskContext?.agentSettings?.maxPrNudges ?? this.config.agentSettings?.maxPrNudges ?? 3;
3301
3319
  if (this.prNudgeCount >= maxNudges) return false;
3320
+ const status = this.taskContext?.status;
3321
+ return status === "InProgress" && !this.taskContext?.githubPRUrl;
3322
+ }
3323
+ async maybeSendPRNudge() {
3302
3324
  const fresh = await this.connection.fetchTaskContext().catch(() => null);
3303
3325
  if (fresh) this.taskContext = fresh;
3304
- const status = this.taskContext?.status;
3305
- const hasPR = !!this.taskContext?.githubPRUrl;
3306
- if (status === "InProgress" && !hasPR) {
3307
- this.prNudgeCount++;
3308
- const ctx = this.taskContext ?? fresh;
3309
- if (!ctx) return false;
3310
- if (this.prNudgeCount >= maxNudges) {
3311
- this.connection.postChatMessage(
3312
- `Auto-mode agent failed to open a PR after ${maxNudges} nudges. Shutting down.`
3313
- );
3314
- this.stop();
3315
- return true;
3316
- }
3317
- if (this.prNudgeCount === 1) {
3318
- this.connection.postChatMessage(
3319
- "Auto-nudge: Task is still In Progress with no PR. Prompting agent to continue..."
3320
- );
3321
- await this.setState("running");
3322
- await this.runQuerySafe(
3323
- ctx,
3324
- "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR."
3325
- );
3326
- } else {
3327
- this.connection.postChatMessage(
3328
- `Auto-nudge (attempt ${this.prNudgeCount}/${maxNudges}): Task still has no PR. Prompting agent again...`
3329
- );
3330
- await this.setState("running");
3331
- await this.runQuerySafe(
3332
- ctx,
3333
- `This is reminder ${this.prNudgeCount} of ${maxNudges}. You MUST open a pull request using create_pull_request NOW or explain what is blocking you. Do NOT go idle \u2014 either create the PR or describe the specific blocker.`
3334
- );
3335
- }
3326
+ if (!this.needsPRNudge()) return false;
3327
+ this.prNudgeCount++;
3328
+ const ctx = this.taskContext ?? fresh;
3329
+ if (!ctx) return false;
3330
+ const maxNudges = this.taskContext?.agentSettings?.maxPrNudges ?? this.config.agentSettings?.maxPrNudges ?? 3;
3331
+ if (this.prNudgeCount >= maxNudges) {
3332
+ this.connection.postChatMessage(
3333
+ `Auto-mode agent failed to open a PR after ${maxNudges} nudges. Shutting down.`
3334
+ );
3335
+ this.stop();
3336
3336
  return true;
3337
3337
  }
3338
- return false;
3338
+ await this.sendPRNudgeQuery(ctx, maxNudges);
3339
+ return true;
3340
+ }
3341
+ async sendPRNudgeQuery(ctx, maxNudges) {
3342
+ const isFirst = this.prNudgeCount === 1;
3343
+ const chatMsg = isFirst ? "Auto-nudge: Task is still In Progress with no PR. Prompting agent to continue..." : `Auto-nudge (attempt ${this.prNudgeCount}/${maxNudges}): Task still has no PR. Prompting agent again...`;
3344
+ const prompt = isFirst ? "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR." : `This is reminder ${this.prNudgeCount} of ${maxNudges}. You MUST open a pull request using create_pull_request NOW or explain what is blocking you. Do NOT go idle \u2014 either create the PR or describe the specific blocker.`;
3345
+ this.connection.postChatMessage(chatMsg);
3346
+ await this.setState("running");
3347
+ await this.runQuerySafe(ctx, prompt);
3339
3348
  }
3340
3349
  async executeInitialMode() {
3341
3350
  if (!this.taskContext) return;
@@ -3418,15 +3427,9 @@ var AgentRunner = class {
3418
3427
  }
3419
3428
  }
3420
3429
  handleRunStartCommand() {
3421
- if (!this.deferredStartConfig?.startCommand || this.startCommandStarted) return;
3430
+ if (!this.conveyorConfig?.startCommand || this.startCommandStarted) return;
3422
3431
  this.startCommandStarted = true;
3423
- runDeferredStartCommand(
3424
- this.deferredStartConfig,
3425
- this.config,
3426
- this.connection,
3427
- this.setupLog
3428
- );
3429
- this.deferredStartConfig = null;
3432
+ rerunStartCommand(this.conveyorConfig, this.config, this.connection, this.setupLog);
3430
3433
  }
3431
3434
  logEffectiveSettings() {
3432
3435
  if (!this.taskContext) return;
@@ -3459,6 +3462,9 @@ var AgentRunner = class {
3459
3462
  resolve2(msg);
3460
3463
  } else {
3461
3464
  this.pendingMessages.push(msg);
3465
+ if (this._queryHost?.activeQuery) {
3466
+ this.softStop();
3467
+ }
3462
3468
  }
3463
3469
  }
3464
3470
  waitForMessage() {
@@ -3838,7 +3844,7 @@ var ProjectRunner = class {
3838
3844
  projectId: config.projectId
3839
3845
  });
3840
3846
  }
3841
- async checkoutWorkspaceBranch() {
3847
+ checkoutWorkspaceBranch() {
3842
3848
  const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
3843
3849
  if (!workspaceBranch) return;
3844
3850
  try {
@@ -3853,7 +3859,7 @@ var ProjectRunner = class {
3853
3859
  }
3854
3860
  }
3855
3861
  async start() {
3856
- await this.checkoutWorkspaceBranch();
3862
+ this.checkoutWorkspaceBranch();
3857
3863
  await this.connection.connect();
3858
3864
  this.connection.onTaskAssignment((assignment) => {
3859
3865
  this.handleAssignment(assignment);
@@ -4068,4 +4074,4 @@ export {
4068
4074
  ProjectRunner,
4069
4075
  FileCache
4070
4076
  };
4071
- //# sourceMappingURL=chunk-R37YJZWE.js.map
4077
+ //# sourceMappingURL=chunk-DJJBHD4H.js.map