@rallycry/conveyor-agent 5.10.0 → 5.10.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.
@@ -459,6 +459,7 @@ var ProjectConnection = class {
459
459
  onSwitchBranch = null;
460
460
  onSyncEnvironment = null;
461
461
  onGetEnvStatus = null;
462
+ onRestartStartCommand = null;
462
463
  constructor(config) {
463
464
  this.config = config;
464
465
  }
@@ -522,6 +523,13 @@ var ProjectConnection = class {
522
523
  if (this.onGetEnvStatus) this.onGetEnvStatus(cb);
523
524
  else cb({ ok: false, data: void 0 });
524
525
  });
526
+ this.socket.on(
527
+ "projectRunner:restartStartCommand",
528
+ (_data, cb) => {
529
+ if (this.onRestartStartCommand) this.onRestartStartCommand(cb);
530
+ else cb({ ok: false, error: "restartStartCommand handler not registered" });
531
+ }
532
+ );
525
533
  this.socket.on(
526
534
  "projectRunner:runAuthTokenCommand",
527
535
  (data, cb) => this.handleRunAuthTokenCommand(data.userEmail, cb)
@@ -784,6 +792,14 @@ import { randomUUID as randomUUID2 } from "crypto";
784
792
  import { execSync as execSync4 } from "child_process";
785
793
 
786
794
  // src/execution/event-handlers.ts
795
+ function safeVoid(promise, context) {
796
+ if (promise && typeof promise.catch === "function") {
797
+ promise.catch((err) => {
798
+ process.stderr.write(`[safeVoid] ${context}: ${err}
799
+ `);
800
+ });
801
+ }
802
+ }
787
803
  function epochSecondsToISO(value) {
788
804
  if (typeof value === "string") return value;
789
805
  if (typeof value !== "number" || value <= 0) return void 0;
@@ -960,13 +976,13 @@ function handleRateLimitEvent(event, host) {
960
976
  const resetsAtDisplay = resetsAt ?? "unknown";
961
977
  const message = `Rate limit rejected (type: ${rate_limit_info.rateLimitType ?? "unknown"}, resets at: ${resetsAtDisplay})`;
962
978
  host.connection.sendEvent({ type: "error", message });
963
- void host.callbacks.onEvent({ type: "error", message });
979
+ safeVoid(host.callbacks.onEvent({ type: "error", message }), "rateLimitRejected");
964
980
  return resetsAt;
965
981
  } else if (status === "allowed_warning") {
966
982
  const utilization = rate_limit_info.utilization ? `${Math.round(rate_limit_info.utilization * 100)}%` : "high";
967
983
  const message = `Rate limit warning: ${utilization} utilization (type: ${rate_limit_info.rateLimitType ?? "unknown"})`;
968
984
  host.connection.sendEvent({ type: "thinking", message });
969
- void host.callbacks.onEvent({ type: "thinking", message });
985
+ safeVoid(host.callbacks.onEvent({ type: "thinking", message }), "rateLimitWarning");
970
986
  }
971
987
  return void 0;
972
988
  }
@@ -984,34 +1000,46 @@ async function handleSystemEvent(event, host, context, sessionIdStored) {
984
1000
  }
985
1001
  function handleSystemSubevents(systemEvent, host) {
986
1002
  if (systemEvent.subtype === "compact_boundary") {
987
- void host.callbacks.onEvent({
988
- type: "context_compacted",
989
- trigger: systemEvent.compact_metadata.trigger,
990
- preTokens: systemEvent.compact_metadata.pre_tokens
991
- });
1003
+ safeVoid(
1004
+ host.callbacks.onEvent({
1005
+ type: "context_compacted",
1006
+ trigger: systemEvent.compact_metadata.trigger,
1007
+ preTokens: systemEvent.compact_metadata.pre_tokens
1008
+ }),
1009
+ "compactBoundary"
1010
+ );
992
1011
  } else if (systemEvent.subtype === "task_started") {
993
- void host.callbacks.onEvent({
994
- type: "subagent_started",
995
- sdkTaskId: systemEvent.task_id,
996
- description: systemEvent.description
997
- });
1012
+ safeVoid(
1013
+ host.callbacks.onEvent({
1014
+ type: "subagent_started",
1015
+ sdkTaskId: systemEvent.task_id,
1016
+ description: systemEvent.description
1017
+ }),
1018
+ "taskStarted"
1019
+ );
998
1020
  } else if (systemEvent.subtype === "task_progress") {
999
- void host.callbacks.onEvent({
1000
- type: "subagent_progress",
1001
- sdkTaskId: systemEvent.task_id,
1002
- description: systemEvent.description,
1003
- toolUses: systemEvent.usage?.tool_uses ?? 0,
1004
- durationMs: systemEvent.usage?.duration_ms ?? 0
1005
- });
1021
+ safeVoid(
1022
+ host.callbacks.onEvent({
1023
+ type: "subagent_progress",
1024
+ sdkTaskId: systemEvent.task_id,
1025
+ description: systemEvent.description,
1026
+ toolUses: systemEvent.usage?.tool_uses ?? 0,
1027
+ durationMs: systemEvent.usage?.duration_ms ?? 0
1028
+ }),
1029
+ "taskProgress"
1030
+ );
1006
1031
  }
1007
1032
  }
1008
1033
  function handleToolProgressEvent(event, host) {
1009
1034
  const msg = event;
1010
- void host.callbacks.onEvent({
1011
- type: "tool_progress",
1012
- toolName: msg.tool_name ?? "",
1013
- elapsedSeconds: msg.elapsed_time_seconds ?? 0
1014
- });
1035
+ safeVoid(
1036
+ host.callbacks.onEvent({
1037
+ type: "tool_progress",
1038
+ toolName: msg.tool_name ?? "",
1039
+ elapsedSeconds: msg.elapsed_time_seconds ?? 0
1040
+ }),
1041
+ "toolProgress"
1042
+ );
1015
1043
  }
1016
1044
  async function handleAssistantCase(event, host, turnToolCalls) {
1017
1045
  await processAssistantEvent(event, host, turnToolCalls);
@@ -1034,6 +1062,7 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
1034
1062
  }
1035
1063
 
1036
1064
  // src/execution/event-processor.ts
1065
+ var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
1037
1066
  function stopTypingIfNeeded(host, isTyping) {
1038
1067
  if (isTyping) host.connection.sendTypingStop();
1039
1068
  }
@@ -1055,6 +1084,12 @@ async function processAssistantCase(event, host, state) {
1055
1084
  }
1056
1085
  const usage = await handleAssistantCase(event, host, state.turnToolCalls);
1057
1086
  if (usage) state.lastAssistantUsage = usage;
1087
+ if (!state.sawApiError) {
1088
+ const fullText = event.message.content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
1089
+ if (API_ERROR_PATTERN2.test(fullText)) {
1090
+ state.sawApiError = true;
1091
+ }
1092
+ }
1058
1093
  }
1059
1094
  async function processResultCase(event, host, context, startTime, state) {
1060
1095
  const info = await handleResultCase(
@@ -1078,6 +1113,7 @@ async function processEvents(events, context, host) {
1078
1113
  sessionIdStored: false,
1079
1114
  isTyping: false,
1080
1115
  retriable: false,
1116
+ sawApiError: false,
1081
1117
  resultSummary: void 0,
1082
1118
  rateLimitResetsAt: void 0,
1083
1119
  staleSession: void 0,
@@ -1117,7 +1153,7 @@ async function processEvents(events, context, host) {
1117
1153
  }
1118
1154
  stopTypingIfNeeded(host, state.isTyping);
1119
1155
  return {
1120
- retriable: state.retriable,
1156
+ retriable: state.retriable || state.sawApiError,
1121
1157
  resultSummary: state.resultSummary,
1122
1158
  rateLimitResetsAt: state.rateLimitResetsAt,
1123
1159
  ...state.staleSession && { staleSession: state.staleSession }
@@ -1478,6 +1514,8 @@ function buildDiscoveryPrompt(context) {
1478
1514
  `You are in Discovery mode \u2014 helping plan and scope this task.`,
1479
1515
  `- You have read-only codebase access (can read files, run git commands, search code)`,
1480
1516
  `- You can write plan files in .claude/plans/ only \u2014 no other file writes`,
1517
+ `- Do NOT attempt to edit, write, or modify source code files \u2014 these operations will be denied`,
1518
+ `- If you identify code changes needed, describe them in the plan instead of implementing them`,
1481
1519
  `- You can create and manage subtasks`,
1482
1520
  `- Goal: collaborate with the user to create a clear plan`,
1483
1521
  `- Proactively fill task properties (SP, tags, icon) as the plan takes shape`,
@@ -1742,7 +1780,7 @@ function detectRelaunchScenario(context, trustChatHistory = false) {
1742
1780
  const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === "user");
1743
1781
  return hasNewUserMessages ? "feedback_relaunch" : "idle_relaunch";
1744
1782
  }
1745
- function buildRelaunchWithSession(mode, context, agentMode) {
1783
+ function buildRelaunchWithSession(mode, context, agentMode, isAuto) {
1746
1784
  const scenario = detectRelaunchScenario(context);
1747
1785
  if (!context.claudeSessionId || scenario === "fresh") return null;
1748
1786
  const parts = [];
@@ -1790,7 +1828,7 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
1790
1828
  `Run \`git log --oneline -10\` to review what you already committed.`,
1791
1829
  `Review the current state of the codebase and verify everything is working correctly.`
1792
1830
  );
1793
- if (agentMode === "auto" || agentMode === "building") {
1831
+ if (agentMode === "auto" || agentMode === "building" && isAuto) {
1794
1832
  parts.push(
1795
1833
  `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
1796
1834
  `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
@@ -1996,7 +2034,7 @@ Address the requested changes directly. Do NOT re-investigate the codebase from
1996
2034
  }
1997
2035
  return parts;
1998
2036
  }
1999
- function buildInstructions(mode, context, scenario, agentMode) {
2037
+ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
2000
2038
  const parts = [`
2001
2039
  ## Instructions`];
2002
2040
  const isPm = mode === "pm";
@@ -2028,7 +2066,7 @@ function buildInstructions(mode, context, scenario, agentMode) {
2028
2066
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
2029
2067
  `Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`
2030
2068
  );
2031
- if (agentMode === "auto" || agentMode === "building") {
2069
+ if (agentMode === "auto" || agentMode === "building" && isAuto) {
2032
2070
  parts.push(
2033
2071
  `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
2034
2072
  `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
@@ -2051,13 +2089,13 @@ function buildInstructions(mode, context, scenario, agentMode) {
2051
2089
  async function buildInitialPrompt(mode, context, isAuto, agentMode) {
2052
2090
  const isPackRunner = mode === "pm" && !!isAuto && !!context.isParentTask;
2053
2091
  if (!isPackRunner) {
2054
- const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode);
2092
+ const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode, isAuto);
2055
2093
  if (sessionRelaunch) return sessionRelaunch;
2056
2094
  }
2057
2095
  const isPm = mode === "pm";
2058
2096
  const scenario = detectRelaunchScenario(context, isPm);
2059
2097
  const body = await buildTaskBody(context);
2060
- const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode);
2098
+ const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode, isAuto);
2061
2099
  return [...body, ...instructions].join("\n");
2062
2100
  }
2063
2101
 
@@ -2811,7 +2849,9 @@ async function handleAskUserQuestion(host, input) {
2811
2849
  }
2812
2850
  return { behavior: "allow", updatedInput: { questions: input.questions, answers } };
2813
2851
  }
2852
+ var DENIAL_WARNING_THRESHOLD = 3;
2814
2853
  function buildCanUseTool(host) {
2854
+ let consecutiveDenials = 0;
2815
2855
  return async (toolName, input) => {
2816
2856
  if (toolName === "ExitPlanMode" && (host.agentMode === "auto" || host.agentMode === "discovery") && !host.hasExitedPlanMode) {
2817
2857
  return await handleExitPlanMode(host, input);
@@ -2819,23 +2859,39 @@ function buildCanUseTool(host) {
2819
2859
  if (toolName === "AskUserQuestion") {
2820
2860
  return await handleAskUserQuestion(host, input);
2821
2861
  }
2862
+ let result;
2822
2863
  switch (host.agentMode) {
2823
2864
  case "discovery":
2824
- return handleDiscoveryToolAccess(toolName, input);
2865
+ result = handleDiscoveryToolAccess(toolName, input);
2866
+ break;
2825
2867
  case "building":
2826
- return handleBuildingToolAccess(toolName, input);
2868
+ result = handleBuildingToolAccess(toolName, input);
2869
+ break;
2827
2870
  case "review":
2828
- return handleReviewToolAccess(toolName, input, host.isParentTask);
2871
+ result = handleReviewToolAccess(toolName, input, host.isParentTask);
2872
+ break;
2829
2873
  case "auto":
2830
- return handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);
2874
+ result = handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);
2875
+ break;
2831
2876
  default:
2832
- return { behavior: "allow", updatedInput: input };
2877
+ result = { behavior: "allow", updatedInput: input };
2878
+ }
2879
+ if (result.behavior === "deny") {
2880
+ consecutiveDenials++;
2881
+ if (consecutiveDenials === DENIAL_WARNING_THRESHOLD) {
2882
+ host.connection.postChatMessage(
2883
+ `\u26A0\uFE0F Multiple tool denials detected. You are in ${host.agentMode} mode \u2014 file writes outside .claude/plans/ are not permitted. Focus on creating a plan instead of implementing code changes.`
2884
+ );
2885
+ }
2886
+ } else {
2887
+ consecutiveDenials = 0;
2833
2888
  }
2889
+ return result;
2834
2890
  };
2835
2891
  }
2836
2892
 
2837
2893
  // src/execution/query-executor.ts
2838
- var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
2894
+ var API_ERROR_PATTERN3 = /API Error: [45]\d\d/;
2839
2895
  var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
2840
2896
  var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
2841
2897
  function buildHooks(host) {
@@ -3083,12 +3139,17 @@ function isStaleOrExitedSession(error, context) {
3083
3139
  if (error.message.includes("No conversation found with session ID")) return true;
3084
3140
  return !!context.claudeSessionId && error.message.includes("process exited");
3085
3141
  }
3142
+ function getErrorMessage(error) {
3143
+ if (error instanceof Error) return error.message;
3144
+ if (typeof error === "string") return error;
3145
+ return String(error);
3146
+ }
3086
3147
  function isRetriableError(error) {
3087
- if (!(error instanceof Error)) return false;
3088
- return API_ERROR_PATTERN2.test(error.message) || IMAGE_ERROR_PATTERN2.test(error.message);
3148
+ const message = getErrorMessage(error);
3149
+ return API_ERROR_PATTERN3.test(message) || IMAGE_ERROR_PATTERN2.test(message);
3089
3150
  }
3090
3151
  function classifyImageError(error) {
3091
- return error instanceof Error && IMAGE_ERROR_PATTERN2.test(error.message);
3152
+ return IMAGE_ERROR_PATTERN2.test(getErrorMessage(error));
3092
3153
  }
3093
3154
  async function emitRetryStatus(host, attempt, delayMs) {
3094
3155
  const delayMin = Math.round(delayMs / 6e4);
@@ -4166,6 +4227,41 @@ function buildChatQueryOptions(agentCtx, projectDir) {
4166
4227
  thinking: settings.thinking
4167
4228
  };
4168
4229
  }
4230
+ function emitResultCostAndContext(event, connection) {
4231
+ const resultEvent = event;
4232
+ if (resultEvent.total_cost_usd !== void 0 && resultEvent.total_cost_usd > 0) {
4233
+ connection.emitEvent({
4234
+ type: "cost_update",
4235
+ costUsd: resultEvent.total_cost_usd
4236
+ });
4237
+ }
4238
+ if (resultEvent.modelUsage && typeof resultEvent.modelUsage === "object") {
4239
+ const modelUsage = resultEvent.modelUsage;
4240
+ let contextWindow = 0;
4241
+ let totalInputTokens = 0;
4242
+ let totalCacheRead = 0;
4243
+ let totalCacheCreation = 0;
4244
+ for (const data of Object.values(modelUsage)) {
4245
+ const d = data;
4246
+ totalInputTokens += d.inputTokens ?? 0;
4247
+ totalCacheRead += d.cacheReadInputTokens ?? 0;
4248
+ totalCacheCreation += d.cacheCreationInputTokens ?? 0;
4249
+ const cw = d.contextWindow ?? 0;
4250
+ if (cw > contextWindow) contextWindow = cw;
4251
+ }
4252
+ if (contextWindow > 0) {
4253
+ const queryInputTokens = totalInputTokens + totalCacheRead + totalCacheCreation;
4254
+ connection.emitEvent({
4255
+ type: "context_update",
4256
+ contextTokens: queryInputTokens,
4257
+ contextWindow,
4258
+ inputTokens: totalInputTokens,
4259
+ cacheReadInputTokens: totalCacheRead,
4260
+ cacheCreationInputTokens: totalCacheCreation
4261
+ });
4262
+ }
4263
+ }
4264
+ }
4169
4265
  function processEventStream(event, connection, responseParts, turnToolCalls, isTyping) {
4170
4266
  if (event.type === "assistant") {
4171
4267
  if (!isTyping.value) {
@@ -4187,6 +4283,7 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
4187
4283
  connection.emitEvent({ type: "agent_typing_stop" });
4188
4284
  isTyping.value = false;
4189
4285
  }
4286
+ emitResultCostAndContext(event, connection);
4190
4287
  return true;
4191
4288
  }
4192
4289
  return false;
@@ -4308,14 +4405,15 @@ var TOOL_MAPPERS = {
4308
4405
  recommend_merge_tags: mapMergeTags,
4309
4406
  recommend_rename_tag: mapRenameTag
4310
4407
  };
4311
- function collectRecommendation(toolName, input, collector) {
4408
+ function collectRecommendation(toolName, input, collector, onRecommendation) {
4312
4409
  const mapper = TOOL_MAPPERS[toolName];
4313
4410
  if (!mapper) return JSON.stringify({ error: `Unknown tool: ${toolName}` });
4314
4411
  const rec = { id: randomUUID3(), ...mapper(input) };
4315
4412
  collector.recommendations.push(rec);
4413
+ onRecommendation?.({ tagName: rec.tagName ?? rec.type, type: rec.type });
4316
4414
  return JSON.stringify({ success: true, recommendationId: rec.id });
4317
4415
  }
4318
- function createAuditMcpServer(collector) {
4416
+ function createAuditMcpServer(collector, onRecommendation) {
4319
4417
  const auditTools = [
4320
4418
  tool4(
4321
4419
  "recommend_create_tag",
@@ -4330,7 +4428,8 @@ function createAuditMcpServer(collector) {
4330
4428
  const result = collectRecommendation(
4331
4429
  "recommend_create_tag",
4332
4430
  args,
4333
- collector
4431
+ collector,
4432
+ onRecommendation
4334
4433
  );
4335
4434
  return { content: [{ type: "text", text: result }] };
4336
4435
  }
@@ -4348,7 +4447,8 @@ function createAuditMcpServer(collector) {
4348
4447
  const result = collectRecommendation(
4349
4448
  "recommend_update_description",
4350
4449
  args,
4351
- collector
4450
+ collector,
4451
+ onRecommendation
4352
4452
  );
4353
4453
  return { content: [{ type: "text", text: result }] };
4354
4454
  }
@@ -4368,7 +4468,8 @@ function createAuditMcpServer(collector) {
4368
4468
  const result = collectRecommendation(
4369
4469
  "recommend_context_link",
4370
4470
  args,
4371
- collector
4471
+ collector,
4472
+ onRecommendation
4372
4473
  );
4373
4474
  return { content: [{ type: "text", text: result }] };
4374
4475
  }
@@ -4388,7 +4489,8 @@ function createAuditMcpServer(collector) {
4388
4489
  const result = collectRecommendation(
4389
4490
  "flag_documentation_gap",
4390
4491
  args,
4391
- collector
4492
+ collector,
4493
+ onRecommendation
4392
4494
  );
4393
4495
  return { content: [{ type: "text", text: result }] };
4394
4496
  }
@@ -4407,7 +4509,8 @@ function createAuditMcpServer(collector) {
4407
4509
  const result = collectRecommendation(
4408
4510
  "recommend_merge_tags",
4409
4511
  args,
4410
- collector
4512
+ collector,
4513
+ onRecommendation
4411
4514
  );
4412
4515
  return { content: [{ type: "text", text: result }] };
4413
4516
  }
@@ -4425,7 +4528,8 @@ function createAuditMcpServer(collector) {
4425
4528
  const result = collectRecommendation(
4426
4529
  "recommend_rename_tag",
4427
4530
  args,
4428
- collector
4531
+ collector,
4532
+ onRecommendation
4429
4533
  );
4430
4534
  return { content: [{ type: "text", text: result }] };
4431
4535
  }
@@ -4500,12 +4604,14 @@ function buildAuditSystemPrompt(projectName, tags, heatmapData, projectDir) {
4500
4604
  ].join("\n");
4501
4605
  }
4502
4606
  async function runAuditQuery(request, connection, projectDir) {
4607
+ connection.emitAgentStatus("fetching_context");
4503
4608
  let agentCtx = null;
4504
4609
  try {
4505
4610
  agentCtx = await connection.fetchAgentContext();
4506
4611
  } catch {
4507
4612
  logger5.warn("Could not fetch agent context for audit, using defaults");
4508
4613
  }
4614
+ connection.emitAgentStatus("running");
4509
4615
  const model = agentCtx?.model || FALLBACK_MODEL2;
4510
4616
  const settings = agentCtx?.agentSettings ?? {};
4511
4617
  const collector = {
@@ -4513,6 +4619,13 @@ async function runAuditQuery(request, connection, projectDir) {
4513
4619
  summary: "Audit completed.",
4514
4620
  complete: false
4515
4621
  };
4622
+ const onRecommendation = (rec) => {
4623
+ connection.emitEvent({
4624
+ type: "audit_recommendation",
4625
+ tagName: rec.tagName,
4626
+ recommendationType: rec.type
4627
+ });
4628
+ };
4516
4629
  const systemPrompt = buildAuditSystemPrompt(
4517
4630
  request.projectName,
4518
4631
  request.tags,
@@ -4536,20 +4649,27 @@ async function runAuditQuery(request, connection, projectDir) {
4536
4649
  permissionMode: "bypassPermissions",
4537
4650
  allowDangerouslySkipPermissions: true,
4538
4651
  tools: { type: "preset", preset: "claude_code" },
4539
- mcpServers: { "tag-audit": createAuditMcpServer(collector) },
4652
+ mcpServers: { "tag-audit": createAuditMcpServer(collector, onRecommendation) },
4540
4653
  maxTurns: settings.maxTurns ?? 30,
4541
4654
  maxBudgetUsd: settings.maxBudgetUsd ?? 5,
4542
4655
  effort: settings.effort,
4543
4656
  thinking: settings.thinking
4544
4657
  }
4545
4658
  });
4659
+ const responseParts = [];
4660
+ const turnToolCalls = [];
4661
+ const isTyping = { value: false };
4546
4662
  for await (const event of events) {
4547
- if (event.type === "result") break;
4663
+ const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
4664
+ if (done) break;
4665
+ }
4666
+ if (isTyping.value) {
4667
+ connection.emitEvent({ type: "agent_typing_stop" });
4548
4668
  }
4549
4669
  return collector;
4550
4670
  }
4551
4671
  async function handleProjectAuditRequest(request, connection, projectDir) {
4552
- connection.emitAgentStatus("busy");
4672
+ connection.emitAgentStatus("running");
4553
4673
  try {
4554
4674
  const collector = await runAuditQuery(request, connection, projectDir);
4555
4675
  const result = {
@@ -5027,6 +5147,11 @@ var ProjectRunner = class {
5027
5147
  this.connection.onGetEnvStatus = (cb) => {
5028
5148
  this.handleGetEnvStatus(cb);
5029
5149
  };
5150
+ this.connection.onRestartStartCommand = (cb) => {
5151
+ void this.restartStartCommand().then(() => cb({ ok: true })).catch(
5152
+ (err) => cb({ ok: false, error: err instanceof Error ? err.message : "Restart failed" })
5153
+ );
5154
+ };
5030
5155
  try {
5031
5156
  const context = await this.connection.fetchAgentContext();
5032
5157
  this.branchSwitchCommand = context?.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
@@ -5238,4 +5363,4 @@ export {
5238
5363
  ProjectRunner,
5239
5364
  FileCache
5240
5365
  };
5241
- //# sourceMappingURL=chunk-MRTSBPY7.js.map
5366
+ //# sourceMappingURL=chunk-ASK2L7IU.js.map