@rallycry/conveyor-agent 5.11.1 → 6.0.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.
@@ -427,23 +427,6 @@ var ConveyorConnection = class _ConveyorConnection {
427
427
  triggerIdentification() {
428
428
  return triggerIdentification(this.socket);
429
429
  }
430
- async refreshAuthToken() {
431
- const codespaceName = process.env.CODESPACE_NAME;
432
- const apiUrl = process.env.CONVEYOR_API_URL ?? this.config.conveyorApiUrl;
433
- if (!codespaceName || !apiUrl) return false;
434
- try {
435
- const response = await fetch(`${apiUrl}/api/codespace/bootstrap/${codespaceName}`);
436
- if (!response.ok) return false;
437
- const config = await response.json();
438
- if (config.envVars?.CLAUDE_CODE_OAUTH_TOKEN) {
439
- process.env.CLAUDE_CODE_OAUTH_TOKEN = config.envVars.CLAUDE_CODE_OAUTH_TOKEN;
440
- return true;
441
- }
442
- return false;
443
- } catch {
444
- return false;
445
- }
446
- }
447
430
  emitModeTransition(payload) {
448
431
  if (!this.socket) return;
449
432
  this.socket.emit("agentRunner:modeTransition", payload);
@@ -471,16 +454,9 @@ var ProjectConnection = class {
471
454
  shutdownCallback = null;
472
455
  chatMessageCallback = null;
473
456
  earlyChatMessages = [];
474
- auditRequestCallback = null;
475
- // Branch switching callbacks
476
- onSwitchBranch = null;
477
- onSyncEnvironment = null;
478
- onGetEnvStatus = null;
479
- onRestartStartCommand = null;
480
457
  constructor(config) {
481
458
  this.config = config;
482
459
  }
483
- // oxlint-disable-next-line max-lines-per-function -- socket event registration requires co-located handlers
484
460
  connect() {
485
461
  return new Promise((resolve2, reject) => {
486
462
  let settled = false;
@@ -520,37 +496,6 @@ var ProjectConnection = class {
520
496
  this.earlyChatMessages.push(msg);
521
497
  }
522
498
  });
523
- this.socket.on("projectRunner:auditTags", (data) => {
524
- if (this.auditRequestCallback) {
525
- this.auditRequestCallback(data);
526
- }
527
- });
528
- this.socket.on(
529
- "projectRunner:switchBranch",
530
- (data, cb) => {
531
- if (this.onSwitchBranch) this.onSwitchBranch(data, cb);
532
- else cb({ ok: false, error: "switchBranch handler not registered" });
533
- }
534
- );
535
- this.socket.on("projectRunner:syncEnvironment", (cb) => {
536
- if (this.onSyncEnvironment) this.onSyncEnvironment(cb);
537
- else cb({ ok: false, error: "syncEnvironment handler not registered" });
538
- });
539
- this.socket.on("projectRunner:getEnvStatus", (cb) => {
540
- if (this.onGetEnvStatus) this.onGetEnvStatus(cb);
541
- else cb({ ok: false, data: void 0 });
542
- });
543
- this.socket.on(
544
- "projectRunner:restartStartCommand",
545
- (_data, cb) => {
546
- if (this.onRestartStartCommand) this.onRestartStartCommand(cb);
547
- else cb({ ok: false, error: "restartStartCommand handler not registered" });
548
- }
549
- );
550
- this.socket.on(
551
- "projectRunner:runAuthTokenCommand",
552
- (data, cb) => this.handleRunAuthTokenCommand(data.userEmail, cb)
553
- );
554
499
  this.socket.on("connect", () => {
555
500
  if (!settled) {
556
501
  settled = true;
@@ -582,17 +527,6 @@ var ProjectConnection = class {
582
527
  }
583
528
  this.earlyChatMessages = [];
584
529
  }
585
- onAuditRequest(callback) {
586
- this.auditRequestCallback = callback;
587
- }
588
- emitAuditResult(data) {
589
- if (!this.socket) return;
590
- this.socket.emit("conveyor:tagAuditResult", data);
591
- }
592
- emitAuditProgress(data) {
593
- if (!this.socket) return;
594
- this.socket.emit("conveyor:tagAuditProgress", data);
595
- }
596
530
  sendHeartbeat() {
597
531
  if (!this.socket) return;
598
532
  this.socket.emit("projectRunner:heartbeat", {});
@@ -654,46 +588,6 @@ var ProjectConnection = class {
654
588
  );
655
589
  });
656
590
  }
657
- emitNewCommitsDetected(data) {
658
- if (!this.socket) return;
659
- this.socket.emit("projectRunner:newCommitsDetected", data);
660
- }
661
- emitEnvironmentReady(data) {
662
- if (!this.socket) return;
663
- this.socket.emit("projectRunner:environmentReady", data);
664
- }
665
- emitEnvSwitchProgress(data) {
666
- if (!this.socket) return;
667
- this.socket.emit("projectRunner:envSwitchProgress", data);
668
- }
669
- handleRunAuthTokenCommand(userEmail, cb) {
670
- try {
671
- if (process.env.CODESPACES !== "true") {
672
- cb({ ok: false, error: "Auth token command only available in codespace environments" });
673
- return;
674
- }
675
- const authCmd = process.env.CONVEYOR_AUTH_TOKEN_COMMAND;
676
- if (!authCmd) {
677
- cb({ ok: false, error: "CONVEYOR_AUTH_TOKEN_COMMAND not configured" });
678
- return;
679
- }
680
- const cwd = this.config.projectDir ?? process.cwd();
681
- const token = runAuthTokenCommand(authCmd, userEmail, cwd);
682
- if (!token) {
683
- cb({
684
- ok: false,
685
- error: `Auth token command returned empty output. Command: ${authCmd}`
686
- });
687
- return;
688
- }
689
- cb({ ok: true, token });
690
- } catch (error) {
691
- cb({
692
- ok: false,
693
- error: error instanceof Error ? error.message : "Auth token command failed"
694
- });
695
- }
696
- }
697
591
  disconnect() {
698
592
  this.socket?.disconnect();
699
593
  this.socket = null;
@@ -813,14 +707,6 @@ import { randomUUID as randomUUID2 } from "crypto";
813
707
  import { execSync as execSync4 } from "child_process";
814
708
 
815
709
  // src/execution/event-handlers.ts
816
- function safeVoid(promise, context) {
817
- if (promise && typeof promise.catch === "function") {
818
- promise.catch((err) => {
819
- process.stderr.write(`[safeVoid] ${context}: ${err}
820
- `);
821
- });
822
- }
823
- }
824
710
  function epochSecondsToISO(value) {
825
711
  if (typeof value === "string") return value;
826
712
  if (typeof value !== "number" || value <= 0) return void 0;
@@ -859,10 +745,6 @@ async function processAssistantEvent(event, host, turnToolCalls) {
859
745
  }
860
746
  var API_ERROR_PATTERN = /API Error: [45]\d\d/;
861
747
  var IMAGE_ERROR_PATTERN = /Could not process image/i;
862
- var AUTH_ERROR_PATTERN = /Not logged in|Please run \/login|authentication failed|invalid.*token|unauthorized/i;
863
- function isAuthError(msg) {
864
- return AUTH_ERROR_PATTERN.test(msg);
865
- }
866
748
  function isRetriableMessage(msg) {
867
749
  if (IMAGE_ERROR_PATTERN.test(msg)) return true;
868
750
  if (API_ERROR_PATTERN.test(msg)) return true;
@@ -943,10 +825,6 @@ function handleErrorResult(event, host) {
943
825
  if (isStaleSession) {
944
826
  return { retriable: false, staleSession: true };
945
827
  }
946
- if (isAuthError(errorMsg)) {
947
- host.connection.sendEvent({ type: "error", message: errorMsg });
948
- return { retriable: false, authError: true };
949
- }
950
828
  const retriable = isRetriableMessage(errorMsg);
951
829
  host.connection.sendEvent({ type: "error", message: errorMsg });
952
830
  return { retriable };
@@ -986,8 +864,7 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
986
864
  return {
987
865
  retriable: result.retriable,
988
866
  resultSummary: result.resultSummary,
989
- staleSession: result.staleSession,
990
- authError: result.authError
867
+ staleSession: result.staleSession
991
868
  };
992
869
  }
993
870
  function handleRateLimitEvent(event, host) {
@@ -1006,13 +883,13 @@ function handleRateLimitEvent(event, host) {
1006
883
  const resetsAtDisplay = resetsAt ?? "unknown";
1007
884
  const message = `Rate limit rejected (type: ${rate_limit_info.rateLimitType ?? "unknown"}, resets at: ${resetsAtDisplay})`;
1008
885
  host.connection.sendEvent({ type: "error", message });
1009
- safeVoid(host.callbacks.onEvent({ type: "error", message }), "rateLimitRejected");
886
+ void host.callbacks.onEvent({ type: "error", message });
1010
887
  return resetsAt;
1011
888
  } else if (status === "allowed_warning") {
1012
889
  const utilization = rate_limit_info.utilization ? `${Math.round(rate_limit_info.utilization * 100)}%` : "high";
1013
890
  const message = `Rate limit warning: ${utilization} utilization (type: ${rate_limit_info.rateLimitType ?? "unknown"})`;
1014
891
  host.connection.sendEvent({ type: "thinking", message });
1015
- safeVoid(host.callbacks.onEvent({ type: "thinking", message }), "rateLimitWarning");
892
+ void host.callbacks.onEvent({ type: "thinking", message });
1016
893
  }
1017
894
  return void 0;
1018
895
  }
@@ -1030,46 +907,34 @@ async function handleSystemEvent(event, host, context, sessionIdStored) {
1030
907
  }
1031
908
  function handleSystemSubevents(systemEvent, host) {
1032
909
  if (systemEvent.subtype === "compact_boundary") {
1033
- safeVoid(
1034
- host.callbacks.onEvent({
1035
- type: "context_compacted",
1036
- trigger: systemEvent.compact_metadata.trigger,
1037
- preTokens: systemEvent.compact_metadata.pre_tokens
1038
- }),
1039
- "compactBoundary"
1040
- );
910
+ void host.callbacks.onEvent({
911
+ type: "context_compacted",
912
+ trigger: systemEvent.compact_metadata.trigger,
913
+ preTokens: systemEvent.compact_metadata.pre_tokens
914
+ });
1041
915
  } else if (systemEvent.subtype === "task_started") {
1042
- safeVoid(
1043
- host.callbacks.onEvent({
1044
- type: "subagent_started",
1045
- sdkTaskId: systemEvent.task_id,
1046
- description: systemEvent.description
1047
- }),
1048
- "taskStarted"
1049
- );
916
+ void host.callbacks.onEvent({
917
+ type: "subagent_started",
918
+ sdkTaskId: systemEvent.task_id,
919
+ description: systemEvent.description
920
+ });
1050
921
  } else if (systemEvent.subtype === "task_progress") {
1051
- safeVoid(
1052
- host.callbacks.onEvent({
1053
- type: "subagent_progress",
1054
- sdkTaskId: systemEvent.task_id,
1055
- description: systemEvent.description,
1056
- toolUses: systemEvent.usage?.tool_uses ?? 0,
1057
- durationMs: systemEvent.usage?.duration_ms ?? 0
1058
- }),
1059
- "taskProgress"
1060
- );
922
+ void host.callbacks.onEvent({
923
+ type: "subagent_progress",
924
+ sdkTaskId: systemEvent.task_id,
925
+ description: systemEvent.description,
926
+ toolUses: systemEvent.usage?.tool_uses ?? 0,
927
+ durationMs: systemEvent.usage?.duration_ms ?? 0
928
+ });
1061
929
  }
1062
930
  }
1063
931
  function handleToolProgressEvent(event, host) {
1064
932
  const msg = event;
1065
- safeVoid(
1066
- host.callbacks.onEvent({
1067
- type: "tool_progress",
1068
- toolName: msg.tool_name ?? "",
1069
- elapsedSeconds: msg.elapsed_time_seconds ?? 0
1070
- }),
1071
- "toolProgress"
1072
- );
933
+ void host.callbacks.onEvent({
934
+ type: "tool_progress",
935
+ toolName: msg.tool_name ?? "",
936
+ elapsedSeconds: msg.elapsed_time_seconds ?? 0
937
+ });
1073
938
  }
1074
939
  async function handleAssistantCase(event, host, turnToolCalls) {
1075
940
  await processAssistantEvent(event, host, turnToolCalls);
@@ -1087,13 +952,11 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
1087
952
  retriable: resultInfo.retriable,
1088
953
  resultSummary: resultInfo.resultSummary,
1089
954
  staleSession: resultInfo.staleSession,
1090
- authError: resultInfo.authError,
1091
955
  stoppedTyping
1092
956
  };
1093
957
  }
1094
958
 
1095
959
  // src/execution/event-processor.ts
1096
- var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
1097
960
  function stopTypingIfNeeded(host, isTyping) {
1098
961
  if (isTyping) host.connection.sendTypingStop();
1099
962
  }
@@ -1115,12 +978,6 @@ async function processAssistantCase(event, host, state) {
1115
978
  }
1116
979
  const usage = await handleAssistantCase(event, host, state.turnToolCalls);
1117
980
  if (usage) state.lastAssistantUsage = usage;
1118
- if (!state.sawApiError) {
1119
- const fullText = event.message.content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
1120
- if (API_ERROR_PATTERN2.test(fullText)) {
1121
- state.sawApiError = true;
1122
- }
1123
- }
1124
981
  }
1125
982
  async function processResultCase(event, host, context, startTime, state) {
1126
983
  const info = await handleResultCase(
@@ -1135,7 +992,6 @@ async function processResultCase(event, host, context, startTime, state) {
1135
992
  state.retriable = info.retriable;
1136
993
  state.resultSummary = info.resultSummary;
1137
994
  if (info.staleSession) state.staleSession = true;
1138
- if (info.authError) state.authError = true;
1139
995
  }
1140
996
  async function processEvents(events, context, host) {
1141
997
  const startTime = Date.now();
@@ -1145,11 +1001,9 @@ async function processEvents(events, context, host) {
1145
1001
  sessionIdStored: false,
1146
1002
  isTyping: false,
1147
1003
  retriable: false,
1148
- sawApiError: false,
1149
1004
  resultSummary: void 0,
1150
1005
  rateLimitResetsAt: void 0,
1151
1006
  staleSession: void 0,
1152
- authError: void 0,
1153
1007
  lastAssistantUsage: void 0,
1154
1008
  turnToolCalls: []
1155
1009
  };
@@ -1186,11 +1040,10 @@ async function processEvents(events, context, host) {
1186
1040
  }
1187
1041
  stopTypingIfNeeded(host, state.isTyping);
1188
1042
  return {
1189
- retriable: state.retriable || state.sawApiError,
1043
+ retriable: state.retriable,
1190
1044
  resultSummary: state.resultSummary,
1191
1045
  rateLimitResetsAt: state.rateLimitResetsAt,
1192
- ...state.staleSession && { staleSession: state.staleSession },
1193
- ...state.authError && { authError: state.authError }
1046
+ ...state.staleSession && { staleSession: state.staleSession }
1194
1047
  };
1195
1048
  }
1196
1049
 
@@ -1548,8 +1401,6 @@ function buildDiscoveryPrompt(context) {
1548
1401
  `You are in Discovery mode \u2014 helping plan and scope this task.`,
1549
1402
  `- You have read-only codebase access (can read files, run git commands, search code)`,
1550
1403
  `- You can write plan files in .claude/plans/ only \u2014 no other file writes`,
1551
- `- Do NOT attempt to edit, write, or modify source code files \u2014 these operations will be denied`,
1552
- `- If you identify code changes needed, describe them in the plan instead of implementing them`,
1553
1404
  `- You can create and manage subtasks`,
1554
1405
  `- Goal: collaborate with the user to create a clear plan`,
1555
1406
  `- Proactively fill task properties (SP, tags, icon) as the plan takes shape`,
@@ -1684,14 +1535,6 @@ Project Agents:`);
1684
1535
  parts.push(formatProjectAgentLine(pa));
1685
1536
  }
1686
1537
  }
1687
- if (context.projectObjectives && context.projectObjectives.length > 0) {
1688
- parts.push(`
1689
- Project Objectives:`);
1690
- for (const obj of context.projectObjectives) {
1691
- const dates = `${obj.startDate.split("T")[0]} to ${obj.endDate.split("T")[0]}`;
1692
- parts.push(`- **${obj.name}** (${dates})${obj.description ? ": " + obj.description : ""}`);
1693
- }
1694
- }
1695
1538
  return parts;
1696
1539
  }
1697
1540
  function buildActivePreamble(context, workspaceDir) {
@@ -1814,7 +1657,7 @@ function detectRelaunchScenario(context, trustChatHistory = false) {
1814
1657
  const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === "user");
1815
1658
  return hasNewUserMessages ? "feedback_relaunch" : "idle_relaunch";
1816
1659
  }
1817
- function buildRelaunchWithSession(mode, context, agentMode, isAuto) {
1660
+ function buildRelaunchWithSession(mode, context, agentMode) {
1818
1661
  const scenario = detectRelaunchScenario(context);
1819
1662
  if (!context.claudeSessionId || scenario === "fresh") return null;
1820
1663
  const parts = [];
@@ -1862,7 +1705,7 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
1862
1705
  `Run \`git log --oneline -10\` to review what you already committed.`,
1863
1706
  `Review the current state of the codebase and verify everything is working correctly.`
1864
1707
  );
1865
- if (agentMode === "auto" || agentMode === "building" && isAuto) {
1708
+ if (agentMode === "auto" || agentMode === "building") {
1866
1709
  parts.push(
1867
1710
  `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
1868
1711
  `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
@@ -2068,7 +1911,7 @@ Address the requested changes directly. Do NOT re-investigate the codebase from
2068
1911
  }
2069
1912
  return parts;
2070
1913
  }
2071
- function buildInstructions(mode, context, scenario, agentMode, isAuto) {
1914
+ function buildInstructions(mode, context, scenario, agentMode) {
2072
1915
  const parts = [`
2073
1916
  ## Instructions`];
2074
1917
  const isPm = mode === "pm";
@@ -2100,7 +1943,7 @@ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
2100
1943
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
2101
1944
  `Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`
2102
1945
  );
2103
- if (agentMode === "auto" || agentMode === "building" && isAuto) {
1946
+ if (agentMode === "auto" || agentMode === "building") {
2104
1947
  parts.push(
2105
1948
  `If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
2106
1949
  `Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
@@ -2123,13 +1966,13 @@ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
2123
1966
  async function buildInitialPrompt(mode, context, isAuto, agentMode) {
2124
1967
  const isPackRunner = mode === "pm" && !!isAuto && !!context.isParentTask;
2125
1968
  if (!isPackRunner) {
2126
- const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode, isAuto);
1969
+ const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode);
2127
1970
  if (sessionRelaunch) return sessionRelaunch;
2128
1971
  }
2129
1972
  const isPm = mode === "pm";
2130
1973
  const scenario = detectRelaunchScenario(context, isPm);
2131
1974
  const body = await buildTaskBody(context);
2132
- const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode, isAuto);
1975
+ const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode);
2133
1976
  return [...body, ...instructions].join("\n");
2134
1977
  }
2135
1978
 
@@ -2391,14 +2234,11 @@ function buildCreatePullRequestTool(connection) {
2391
2234
  "Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
2392
2235
  {
2393
2236
  title: z.string().describe("The PR title"),
2394
- body: z.string().describe("The PR description/body in markdown"),
2395
- branch: z.string().optional().describe(
2396
- "The head branch name for the PR. If the task doesn't have a branch set, this will be used. Defaults to the task's existing branch."
2397
- )
2237
+ body: z.string().describe("The PR description/body in markdown")
2398
2238
  },
2399
- async ({ title, body, branch }) => {
2239
+ async ({ title, body }) => {
2400
2240
  try {
2401
- const result = await connection.createPR({ title, body, branch });
2241
+ const result = await connection.createPR({ title, body });
2402
2242
  connection.sendEvent({
2403
2243
  type: "pr_created",
2404
2244
  url: result.url,
@@ -2886,9 +2726,7 @@ async function handleAskUserQuestion(host, input) {
2886
2726
  }
2887
2727
  return { behavior: "allow", updatedInput: { questions: input.questions, answers } };
2888
2728
  }
2889
- var DENIAL_WARNING_THRESHOLD = 3;
2890
2729
  function buildCanUseTool(host) {
2891
- let consecutiveDenials = 0;
2892
2730
  return async (toolName, input) => {
2893
2731
  if (toolName === "ExitPlanMode" && (host.agentMode === "auto" || host.agentMode === "discovery") && !host.hasExitedPlanMode) {
2894
2732
  return await handleExitPlanMode(host, input);
@@ -2896,39 +2734,23 @@ function buildCanUseTool(host) {
2896
2734
  if (toolName === "AskUserQuestion") {
2897
2735
  return await handleAskUserQuestion(host, input);
2898
2736
  }
2899
- let result;
2900
2737
  switch (host.agentMode) {
2901
2738
  case "discovery":
2902
- result = handleDiscoveryToolAccess(toolName, input);
2903
- break;
2739
+ return handleDiscoveryToolAccess(toolName, input);
2904
2740
  case "building":
2905
- result = handleBuildingToolAccess(toolName, input);
2906
- break;
2741
+ return handleBuildingToolAccess(toolName, input);
2907
2742
  case "review":
2908
- result = handleReviewToolAccess(toolName, input, host.isParentTask);
2909
- break;
2743
+ return handleReviewToolAccess(toolName, input, host.isParentTask);
2910
2744
  case "auto":
2911
- result = handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);
2912
- break;
2745
+ return handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);
2913
2746
  default:
2914
- result = { behavior: "allow", updatedInput: input };
2915
- }
2916
- if (result.behavior === "deny") {
2917
- consecutiveDenials++;
2918
- if (consecutiveDenials === DENIAL_WARNING_THRESHOLD) {
2919
- host.connection.postChatMessage(
2920
- `\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.`
2921
- );
2922
- }
2923
- } else {
2924
- consecutiveDenials = 0;
2747
+ return { behavior: "allow", updatedInput: input };
2925
2748
  }
2926
- return result;
2927
2749
  };
2928
2750
  }
2929
2751
 
2930
2752
  // src/execution/query-executor.ts
2931
- var API_ERROR_PATTERN3 = /API Error: [45]\d\d/;
2753
+ var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
2932
2754
  var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
2933
2755
  var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
2934
2756
  function buildHooks(host) {
@@ -3145,29 +2967,6 @@ async function buildRetryQuery(host, context, options, lastErrorWasImage) {
3145
2967
  options: { ...options, resume: void 0 }
3146
2968
  });
3147
2969
  }
3148
- async function handleAuthError(context, host, options) {
3149
- host.connection.postChatMessage("Authentication expired. Re-bootstrapping credentials...");
3150
- const refreshed = await host.connection.refreshAuthToken();
3151
- if (!refreshed) {
3152
- host.connection.postChatMessage("Failed to refresh authentication. Agent will restart.");
3153
- host.connection.sendEvent({
3154
- type: "error",
3155
- message: "Auth re-bootstrap failed, exiting for restart"
3156
- });
3157
- process.exit(1);
3158
- }
3159
- context.claudeSessionId = null;
3160
- host.connection.storeSessionId("");
3161
- const freshPrompt = buildMultimodalPrompt(
3162
- await buildInitialPrompt(host.config.mode, context, host.config.isAuto, host.agentMode),
3163
- context
3164
- );
3165
- const freshQuery = query({
3166
- prompt: host.createInputStream(freshPrompt),
3167
- options: { ...options, resume: void 0 }
3168
- });
3169
- return runWithRetry(freshQuery, context, host, options);
3170
- }
3171
2970
  async function handleStaleSession(context, host, options) {
3172
2971
  context.claudeSessionId = null;
3173
2972
  host.connection.storeSessionId("");
@@ -3199,17 +2998,12 @@ function isStaleOrExitedSession(error, context) {
3199
2998
  if (error.message.includes("No conversation found with session ID")) return true;
3200
2999
  return !!context.claudeSessionId && error.message.includes("process exited");
3201
3000
  }
3202
- function getErrorMessage(error) {
3203
- if (error instanceof Error) return error.message;
3204
- if (typeof error === "string") return error;
3205
- return String(error);
3206
- }
3207
3001
  function isRetriableError(error) {
3208
- const message = getErrorMessage(error);
3209
- return API_ERROR_PATTERN3.test(message) || IMAGE_ERROR_PATTERN2.test(message);
3002
+ if (!(error instanceof Error)) return false;
3003
+ return API_ERROR_PATTERN2.test(error.message) || IMAGE_ERROR_PATTERN2.test(error.message);
3210
3004
  }
3211
3005
  function classifyImageError(error) {
3212
- return IMAGE_ERROR_PATTERN2.test(getErrorMessage(error));
3006
+ return error instanceof Error && IMAGE_ERROR_PATTERN2.test(error.message);
3213
3007
  }
3214
3008
  async function emitRetryStatus(host, attempt, delayMs) {
3215
3009
  const delayMin = Math.round(delayMs / 6e4);
@@ -3236,41 +3030,26 @@ function handleRetryError(error, context, host, options, prevImageError) {
3236
3030
  if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {
3237
3031
  return handleStaleSession(context, host, options);
3238
3032
  }
3239
- if (isAuthError(getErrorMessage(error))) {
3240
- return handleAuthError(context, host, options);
3241
- }
3242
3033
  if (!isRetriableError(error)) throw error;
3243
3034
  return { action: "continue", lastErrorWasImage: classifyImageError(error) || prevImageError };
3244
3035
  }
3245
- function handleProcessResult(result, context, host, options) {
3246
- if (result.modeRestart || host.isStopped()) return { action: "return" };
3247
- if (result.rateLimitResetsAt) {
3248
- handleRateLimitPause(host, result.rateLimitResetsAt);
3249
- return { action: "return" };
3250
- }
3251
- if (result.staleSession && context.claudeSessionId) {
3252
- return { action: "return_promise", promise: handleStaleSession(context, host, options) };
3253
- }
3254
- if (result.authError) {
3255
- return { action: "return_promise", promise: handleAuthError(context, host, options) };
3256
- }
3257
- if (!result.retriable) return { action: "return" };
3258
- return {
3259
- action: "continue",
3260
- lastErrorWasImage: IMAGE_ERROR_PATTERN2.test(result.resultSummary ?? "")
3261
- };
3262
- }
3263
3036
  async function runWithRetry(initialQuery, context, host, options) {
3264
3037
  let lastErrorWasImage = false;
3265
3038
  for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
3266
3039
  if (host.isStopped()) return;
3267
3040
  const agentQuery = attempt === 0 ? initialQuery : await buildRetryQuery(host, context, options, lastErrorWasImage);
3268
3041
  try {
3269
- const result = await processEvents(agentQuery, context, host);
3270
- const outcome = handleProcessResult(result, context, host, options);
3271
- if (outcome.action === "return") return;
3272
- if (outcome.action === "return_promise") return outcome.promise;
3273
- lastErrorWasImage = outcome.lastErrorWasImage;
3042
+ const { retriable, resultSummary, modeRestart, rateLimitResetsAt, staleSession } = await processEvents(agentQuery, context, host);
3043
+ if (modeRestart || host.isStopped()) return;
3044
+ if (rateLimitResetsAt) {
3045
+ handleRateLimitPause(host, rateLimitResetsAt);
3046
+ return;
3047
+ }
3048
+ if (staleSession && context.claudeSessionId) {
3049
+ return handleStaleSession(context, host, options);
3050
+ }
3051
+ if (!retriable) return;
3052
+ lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
3274
3053
  } catch (error) {
3275
3054
  const outcome = handleRetryError(error, context, host, options, lastErrorWasImage);
3276
3055
  if (outcome instanceof Promise) return outcome;
@@ -4100,118 +3879,13 @@ var AgentRunner = class {
4100
3879
 
4101
3880
  // src/runner/project-runner.ts
4102
3881
  import { fork } from "child_process";
4103
- import { execSync as execSync6 } from "child_process";
3882
+ import { execSync as execSync5 } from "child_process";
4104
3883
  import * as path from "path";
4105
3884
  import { fileURLToPath } from "url";
4106
3885
 
4107
- // src/runner/commit-watcher.ts
4108
- import { execSync as execSync5 } from "child_process";
4109
- var logger3 = createServiceLogger("CommitWatcher");
4110
- var CommitWatcher = class {
4111
- constructor(config, callbacks) {
4112
- this.config = config;
4113
- this.callbacks = callbacks;
4114
- }
4115
- interval = null;
4116
- lastKnownRemoteSha = null;
4117
- branch = null;
4118
- debounceTimer = null;
4119
- isSyncing = false;
4120
- start(branch) {
4121
- this.stop();
4122
- this.branch = branch;
4123
- this.lastKnownRemoteSha = this.getLocalHeadSha();
4124
- this.interval = setInterval(() => void this.poll(), this.config.pollIntervalMs);
4125
- logger3.info("Commit watcher started", {
4126
- branch,
4127
- baseSha: this.lastKnownRemoteSha?.slice(0, 8)
4128
- });
4129
- }
4130
- stop() {
4131
- if (this.interval) clearInterval(this.interval);
4132
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
4133
- this.interval = null;
4134
- this.debounceTimer = null;
4135
- this.branch = null;
4136
- this.lastKnownRemoteSha = null;
4137
- this.isSyncing = false;
4138
- }
4139
- getLocalHeadSha() {
4140
- return execSync5("git rev-parse HEAD", {
4141
- cwd: this.config.projectDir,
4142
- stdio: ["ignore", "pipe", "ignore"]
4143
- }).toString().trim();
4144
- }
4145
- poll() {
4146
- if (!this.branch || this.isSyncing) return;
4147
- try {
4148
- execSync5(`git fetch origin ${this.branch} --quiet`, {
4149
- cwd: this.config.projectDir,
4150
- stdio: "ignore",
4151
- timeout: 3e4
4152
- });
4153
- const remoteSha = execSync5(`git rev-parse origin/${this.branch}`, {
4154
- cwd: this.config.projectDir,
4155
- stdio: ["ignore", "pipe", "ignore"]
4156
- }).toString().trim();
4157
- if (remoteSha !== this.lastKnownRemoteSha) {
4158
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
4159
- this.debounceTimer = setTimeout(
4160
- () => void this.handleNewCommits(remoteSha),
4161
- this.config.debounceMs
4162
- );
4163
- }
4164
- } catch {
4165
- }
4166
- }
4167
- async handleNewCommits(remoteSha) {
4168
- if (!this.branch) return;
4169
- const previousSha = this.lastKnownRemoteSha ?? "HEAD";
4170
- let commitCount = 1;
4171
- let latestMessage = "";
4172
- let latestAuthor = "";
4173
- try {
4174
- const countOutput = execSync5(`git rev-list --count ${previousSha}..origin/${this.branch}`, {
4175
- cwd: this.config.projectDir,
4176
- stdio: ["ignore", "pipe", "ignore"]
4177
- }).toString().trim();
4178
- commitCount = parseInt(countOutput, 10) || 1;
4179
- const logOutput = execSync5(`git log -1 --format="%s|||%an" origin/${this.branch}`, {
4180
- cwd: this.config.projectDir,
4181
- stdio: ["ignore", "pipe", "ignore"]
4182
- }).toString().trim();
4183
- const parts = logOutput.split("|||");
4184
- latestMessage = parts[0] ?? "";
4185
- latestAuthor = parts[1] ?? "";
4186
- } catch {
4187
- }
4188
- this.lastKnownRemoteSha = remoteSha;
4189
- this.isSyncing = true;
4190
- logger3.info("New commits detected", {
4191
- branch: this.branch,
4192
- commitCount,
4193
- sha: remoteSha.slice(0, 8)
4194
- });
4195
- try {
4196
- await this.callbacks.onNewCommits({
4197
- branch: this.branch,
4198
- previousSha,
4199
- newCommitSha: remoteSha,
4200
- commitCount,
4201
- latestMessage,
4202
- latestAuthor
4203
- });
4204
- } catch (err) {
4205
- logger3.error("Error handling new commits", errorMeta(err));
4206
- } finally {
4207
- this.isSyncing = false;
4208
- }
4209
- }
4210
- };
4211
-
4212
3886
  // src/runner/project-chat-handler.ts
4213
3887
  import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
4214
- var logger4 = createServiceLogger("ProjectChat");
3888
+ var logger3 = createServiceLogger("ProjectChat");
4215
3889
  var FALLBACK_MODEL = "claude-sonnet-4-20250514";
4216
3890
  function buildSystemPrompt2(projectDir, agentCtx) {
4217
3891
  const parts = [];
@@ -4264,7 +3938,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
4264
3938
  input: inputStr.slice(0, 1e4),
4265
3939
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
4266
3940
  });
4267
- logger4.debug("Tool use", { tool: block.name });
3941
+ logger3.debug("Tool use", { tool: block.name });
4268
3942
  }
4269
3943
  }
4270
3944
  async function fetchContext(connection) {
@@ -4272,13 +3946,13 @@ async function fetchContext(connection) {
4272
3946
  try {
4273
3947
  agentCtx = await connection.fetchAgentContext();
4274
3948
  } catch {
4275
- logger4.warn("Could not fetch agent context, using defaults");
3949
+ logger3.warn("Could not fetch agent context, using defaults");
4276
3950
  }
4277
3951
  let chatHistory = [];
4278
3952
  try {
4279
3953
  chatHistory = await connection.fetchChatHistory(30);
4280
3954
  } catch {
4281
- logger4.warn("Could not fetch chat history, proceeding without it");
3955
+ logger3.warn("Could not fetch chat history, proceeding without it");
4282
3956
  }
4283
3957
  return { agentCtx, chatHistory };
4284
3958
  }
@@ -4302,41 +3976,6 @@ function buildChatQueryOptions(agentCtx, projectDir) {
4302
3976
  thinking: settings.thinking
4303
3977
  };
4304
3978
  }
4305
- function emitResultCostAndContext(event, connection) {
4306
- const resultEvent = event;
4307
- if (resultEvent.total_cost_usd !== void 0 && resultEvent.total_cost_usd > 0) {
4308
- connection.emitEvent({
4309
- type: "cost_update",
4310
- costUsd: resultEvent.total_cost_usd
4311
- });
4312
- }
4313
- if (resultEvent.modelUsage && typeof resultEvent.modelUsage === "object") {
4314
- const modelUsage = resultEvent.modelUsage;
4315
- let contextWindow = 0;
4316
- let totalInputTokens = 0;
4317
- let totalCacheRead = 0;
4318
- let totalCacheCreation = 0;
4319
- for (const data of Object.values(modelUsage)) {
4320
- const d = data;
4321
- totalInputTokens += d.inputTokens ?? 0;
4322
- totalCacheRead += d.cacheReadInputTokens ?? 0;
4323
- totalCacheCreation += d.cacheCreationInputTokens ?? 0;
4324
- const cw = d.contextWindow ?? 0;
4325
- if (cw > contextWindow) contextWindow = cw;
4326
- }
4327
- if (contextWindow > 0) {
4328
- const queryInputTokens = totalInputTokens + totalCacheRead + totalCacheCreation;
4329
- connection.emitEvent({
4330
- type: "context_update",
4331
- contextTokens: queryInputTokens,
4332
- contextWindow,
4333
- inputTokens: totalInputTokens,
4334
- cacheReadInputTokens: totalCacheRead,
4335
- cacheCreationInputTokens: totalCacheCreation
4336
- });
4337
- }
4338
- }
4339
- }
4340
3979
  function processEventStream(event, connection, responseParts, turnToolCalls, isTyping) {
4341
3980
  if (event.type === "assistant") {
4342
3981
  if (!isTyping.value) {
@@ -4358,7 +3997,6 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
4358
3997
  connection.emitEvent({ type: "agent_typing_stop" });
4359
3998
  isTyping.value = false;
4360
3999
  }
4361
- emitResultCostAndContext(event, connection);
4362
4000
  return true;
4363
4001
  }
4364
4002
  return false;
@@ -4367,7 +4005,6 @@ async function runChatQuery(message, connection, projectDir) {
4367
4005
  const { agentCtx, chatHistory } = await fetchContext(connection);
4368
4006
  const options = buildChatQueryOptions(agentCtx, projectDir);
4369
4007
  const prompt = buildPrompt(message, chatHistory);
4370
- connection.emitAgentStatus("running");
4371
4008
  const events = query2({ prompt, options });
4372
4009
  const responseParts = [];
4373
4010
  const turnToolCalls = [];
@@ -4385,12 +4022,11 @@ async function runChatQuery(message, connection, projectDir) {
4385
4022
  }
4386
4023
  }
4387
4024
  async function handleProjectChatMessage(message, connection, projectDir) {
4388
- connection.emitAgentStatus("fetching_context");
4025
+ connection.emitAgentStatus("busy");
4389
4026
  try {
4390
4027
  await runChatQuery(message, connection, projectDir);
4391
4028
  } catch (error) {
4392
- logger4.error("Failed to handle message", errorMeta(error));
4393
- connection.emitAgentStatus("error");
4029
+ logger3.error("Failed to handle message", errorMeta(error));
4394
4030
  try {
4395
4031
  await connection.emitChatMessage(
4396
4032
  "I encountered an error processing your message. Please try again."
@@ -4402,395 +4038,8 @@ async function handleProjectChatMessage(message, connection, projectDir) {
4402
4038
  }
4403
4039
  }
4404
4040
 
4405
- // src/runner/project-audit-handler.ts
4406
- import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
4407
-
4408
- // src/tools/audit-tools.ts
4409
- import { randomUUID as randomUUID3 } from "crypto";
4410
- import { tool as tool4, createSdkMcpServer as createSdkMcpServer2 } from "@anthropic-ai/claude-agent-sdk";
4411
- import { z as z4 } from "zod";
4412
- function mapCreateTag(input) {
4413
- return {
4414
- type: "create_tag",
4415
- tagName: input.name,
4416
- suggestion: `Create new tag "${input.name}"${input.description ? `: ${input.description}` : ""}`,
4417
- reasoning: input.reasoning,
4418
- payload: { name: input.name, color: input.color ?? "#6B7280", description: input.description }
4419
- };
4420
- }
4421
- function mapUpdateDescription(input) {
4422
- return {
4423
- type: "update_description",
4424
- tagId: input.tagId,
4425
- tagName: input.tagName,
4426
- suggestion: `Update description for "${input.tagName}"`,
4427
- reasoning: input.reasoning,
4428
- payload: { description: input.description }
4429
- };
4430
- }
4431
- function mapContextLink(input) {
4432
- return {
4433
- type: "add_context_link",
4434
- tagId: input.tagId,
4435
- tagName: input.tagName,
4436
- suggestion: `Link ${input.linkType}:${input.path} to "${input.tagName}"`,
4437
- reasoning: input.reasoning,
4438
- payload: { contextLink: { type: input.linkType, path: input.path, label: input.label } }
4439
- };
4440
- }
4441
- function mapDocGap(input) {
4442
- return {
4443
- type: "documentation_gap",
4444
- tagId: input.tagId,
4445
- tagName: input.tagName,
4446
- suggestion: `Documentation gap: ${input.filePath} (${input.readCount} reads)`,
4447
- reasoning: input.reasoning,
4448
- payload: {
4449
- filePath: input.filePath,
4450
- readCount: input.readCount,
4451
- suggestedAction: input.suggestedAction
4452
- }
4453
- };
4454
- }
4455
- function mapMergeTags(input) {
4456
- return {
4457
- type: "merge_tags",
4458
- tagId: input.tagId,
4459
- tagName: input.tagName,
4460
- suggestion: `Merge "${input.tagName}" into "${input.mergeIntoTagName}"`,
4461
- reasoning: input.reasoning,
4462
- payload: { mergeIntoTagId: input.mergeIntoTagId }
4463
- };
4464
- }
4465
- function mapRenameTag(input) {
4466
- return {
4467
- type: "rename_tag",
4468
- tagId: input.tagId,
4469
- tagName: input.tagName,
4470
- suggestion: `Rename "${input.tagName}" to "${input.newName}"`,
4471
- reasoning: input.reasoning,
4472
- payload: { newName: input.newName }
4473
- };
4474
- }
4475
- var TOOL_MAPPERS = {
4476
- recommend_create_tag: mapCreateTag,
4477
- recommend_update_description: mapUpdateDescription,
4478
- recommend_context_link: mapContextLink,
4479
- flag_documentation_gap: mapDocGap,
4480
- recommend_merge_tags: mapMergeTags,
4481
- recommend_rename_tag: mapRenameTag
4482
- };
4483
- function collectRecommendation(toolName, input, collector, onRecommendation) {
4484
- const mapper = TOOL_MAPPERS[toolName];
4485
- if (!mapper) return JSON.stringify({ error: `Unknown tool: ${toolName}` });
4486
- const rec = { id: randomUUID3(), ...mapper(input) };
4487
- collector.recommendations.push(rec);
4488
- onRecommendation?.({ tagName: rec.tagName ?? rec.type, type: rec.type });
4489
- return JSON.stringify({ success: true, recommendationId: rec.id });
4490
- }
4491
- function createAuditMcpServer(collector, onRecommendation) {
4492
- const auditTools = [
4493
- tool4(
4494
- "recommend_create_tag",
4495
- "Recommend creating a new tag for an uncovered subsystem or area",
4496
- {
4497
- name: z4.string().describe("Proposed tag name (lowercase, hyphenated)"),
4498
- color: z4.string().optional().describe("Hex color code"),
4499
- description: z4.string().describe("What this tag covers"),
4500
- reasoning: z4.string().describe("Why this tag should be created")
4501
- },
4502
- async (args) => {
4503
- const result = collectRecommendation(
4504
- "recommend_create_tag",
4505
- args,
4506
- collector,
4507
- onRecommendation
4508
- );
4509
- return { content: [{ type: "text", text: result }] };
4510
- }
4511
- ),
4512
- tool4(
4513
- "recommend_update_description",
4514
- "Recommend updating a tag's description to better reflect its scope",
4515
- {
4516
- tagId: z4.string(),
4517
- tagName: z4.string(),
4518
- description: z4.string().describe("Proposed new description"),
4519
- reasoning: z4.string()
4520
- },
4521
- async (args) => {
4522
- const result = collectRecommendation(
4523
- "recommend_update_description",
4524
- args,
4525
- collector,
4526
- onRecommendation
4527
- );
4528
- return { content: [{ type: "text", text: result }] };
4529
- }
4530
- ),
4531
- tool4(
4532
- "recommend_context_link",
4533
- "Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
4534
- {
4535
- tagId: z4.string(),
4536
- tagName: z4.string(),
4537
- linkType: z4.enum(["rule", "doc", "file", "folder"]),
4538
- path: z4.string(),
4539
- label: z4.string().optional(),
4540
- reasoning: z4.string()
4541
- },
4542
- async (args) => {
4543
- const result = collectRecommendation(
4544
- "recommend_context_link",
4545
- args,
4546
- collector,
4547
- onRecommendation
4548
- );
4549
- return { content: [{ type: "text", text: result }] };
4550
- }
4551
- ),
4552
- tool4(
4553
- "flag_documentation_gap",
4554
- "Flag a file that agents read heavily but has no tag documentation linked",
4555
- {
4556
- tagName: z4.string().describe("Tag whose agents read this file"),
4557
- tagId: z4.string().optional(),
4558
- filePath: z4.string(),
4559
- readCount: z4.number(),
4560
- suggestedAction: z4.string().describe("What doc or rule should be created"),
4561
- reasoning: z4.string()
4562
- },
4563
- async (args) => {
4564
- const result = collectRecommendation(
4565
- "flag_documentation_gap",
4566
- args,
4567
- collector,
4568
- onRecommendation
4569
- );
4570
- return { content: [{ type: "text", text: result }] };
4571
- }
4572
- ),
4573
- tool4(
4574
- "recommend_merge_tags",
4575
- "Recommend merging one tag into another",
4576
- {
4577
- tagId: z4.string().describe("Tag ID to be merged (removed after merge)"),
4578
- tagName: z4.string().describe("Name of the tag to be merged"),
4579
- mergeIntoTagId: z4.string().describe("Tag ID to merge into (kept)"),
4580
- mergeIntoTagName: z4.string(),
4581
- reasoning: z4.string()
4582
- },
4583
- async (args) => {
4584
- const result = collectRecommendation(
4585
- "recommend_merge_tags",
4586
- args,
4587
- collector,
4588
- onRecommendation
4589
- );
4590
- return { content: [{ type: "text", text: result }] };
4591
- }
4592
- ),
4593
- tool4(
4594
- "recommend_rename_tag",
4595
- "Recommend renaming a tag",
4596
- {
4597
- tagId: z4.string(),
4598
- tagName: z4.string().describe("Current tag name"),
4599
- newName: z4.string().describe("Proposed new name"),
4600
- reasoning: z4.string()
4601
- },
4602
- async (args) => {
4603
- const result = collectRecommendation(
4604
- "recommend_rename_tag",
4605
- args,
4606
- collector,
4607
- onRecommendation
4608
- );
4609
- return { content: [{ type: "text", text: result }] };
4610
- }
4611
- ),
4612
- tool4(
4613
- "complete_audit",
4614
- "Signal that the audit is complete with a summary of all findings",
4615
- { summary: z4.string().describe("Brief overview of all findings") },
4616
- async (args) => {
4617
- collector.complete = true;
4618
- collector.summary = args.summary ?? "Audit completed.";
4619
- return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
4620
- }
4621
- )
4622
- ];
4623
- return createSdkMcpServer2({
4624
- name: "tag-audit",
4625
- tools: auditTools
4626
- });
4627
- }
4628
-
4629
- // src/runner/project-audit-handler.ts
4630
- var logger5 = createServiceLogger("ProjectAudit");
4631
- var FALLBACK_MODEL2 = "claude-sonnet-4-20250514";
4632
- function buildTagSection(tags) {
4633
- if (tags.length === 0) return "No tags configured yet.";
4634
- return tags.map((t) => {
4635
- const paths = t.contextPaths ?? [];
4636
- const pathStr = paths.length > 0 ? `
4637
- Context links: ${paths.map((p) => `${p.type}:${p.path}`).join(", ")}` : "";
4638
- return ` - ${t.name} (id: ${t.id})${t.description ? `: ${t.description}` : " [no description]"}${pathStr}
4639
- Active tasks: ${t.activeTaskCount}`;
4640
- }).join("\n");
4641
- }
4642
- function buildHeatmapSection(entries) {
4643
- if (entries.length === 0) return "No file read analytics data available.";
4644
- return entries.slice(0, 50).map((e) => {
4645
- const tagBreakdown = Object.entries(e.byTag).sort(([, a], [, b]) => b - a).map(([tag, count]) => `${tag}:${count}`).join(", ");
4646
- return ` ${e.filePath} \u2014 ${e.totalReads} reads${tagBreakdown ? ` (${tagBreakdown})` : ""}`;
4647
- }).join("\n");
4648
- }
4649
- function buildAuditSystemPrompt(projectName, tags, heatmapData, projectDir) {
4650
- return [
4651
- "You are a project organization expert analyzing tag taxonomy for a software project.",
4652
- "Tags are used to categorize tasks and link relevant documentation/rules/files to subsystems.",
4653
- "",
4654
- `PROJECT: ${projectName}`,
4655
- "",
4656
- `EXISTING TAGS (${tags.length}):`,
4657
- buildTagSection(tags),
4658
- "",
4659
- "FILE READ ANALYTICS (what agents actually read, by tag):",
4660
- buildHeatmapSection(heatmapData),
4661
- "",
4662
- `You have full access to the codebase at: ${projectDir}`,
4663
- "Use your file reading and searching tools to understand the codebase structure,",
4664
- "module boundaries, and architectural patterns before making recommendations.",
4665
- "",
4666
- "ANALYSIS TASKS:",
4667
- "1. Read actual source files to understand code areas and module boundaries",
4668
- "2. Search for imports, class definitions, and architectural patterns",
4669
- "3. Coverage: Are all major subsystems/services represented by tags?",
4670
- "4. Descriptions: Do all tags have clear, useful descriptions?",
4671
- "5. Context Links: Are relevant rules/docs/folders linked to tags via contextPaths?",
4672
- "6. Documentation Gaps: Which high-read files lack linked documentation?",
4673
- "7. Cleanup: Any tags that should be merged, renamed, or removed?",
4674
- "",
4675
- "Use the tag-audit MCP tools to submit each recommendation.",
4676
- "Call complete_audit when you are done with a thorough summary.",
4677
- "Be comprehensive \u2014 recommend all improvements your analysis supports.",
4678
- "Analyze actual file contents, not just file names."
4679
- ].join("\n");
4680
- }
4681
- function emitToolCallProgress(event, request, connection) {
4682
- if (event.type !== "assistant") return;
4683
- const assistantEvent = event;
4684
- for (const block of assistantEvent.message.content) {
4685
- if (block.type === "tool_use" && block.name) {
4686
- const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
4687
- connection.emitAuditProgress({
4688
- requestId: request.requestId,
4689
- activity: {
4690
- tool: block.name,
4691
- input: inputStr.slice(0, 500),
4692
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4693
- }
4694
- });
4695
- }
4696
- }
4697
- }
4698
- async function runAuditQuery(request, connection, projectDir) {
4699
- connection.emitAgentStatus("fetching_context");
4700
- let agentCtx = null;
4701
- try {
4702
- agentCtx = await connection.fetchAgentContext();
4703
- } catch {
4704
- logger5.warn("Could not fetch agent context for audit, using defaults");
4705
- }
4706
- connection.emitAgentStatus("running");
4707
- const model = agentCtx?.model || FALLBACK_MODEL2;
4708
- const settings = agentCtx?.agentSettings ?? {};
4709
- const collector = {
4710
- recommendations: [],
4711
- summary: "Audit completed.",
4712
- complete: false
4713
- };
4714
- const onRecommendation = (rec) => {
4715
- connection.emitEvent({
4716
- type: "audit_recommendation",
4717
- tagName: rec.tagName,
4718
- recommendationType: rec.type
4719
- });
4720
- };
4721
- const systemPrompt = buildAuditSystemPrompt(
4722
- request.projectName,
4723
- request.tags,
4724
- request.fileHeatmap,
4725
- projectDir
4726
- );
4727
- const userPrompt = [
4728
- "Analyze the project's tag taxonomy and submit recommendations using the tag-audit MCP tools.",
4729
- `There are currently ${request.tags.length} tags configured.`,
4730
- request.fileHeatmap.length > 0 ? `File analytics show ${request.fileHeatmap.length} files with read activity.` : "No file read analytics available.",
4731
- "",
4732
- "Start by exploring the codebase structure, then analyze each tag for accuracy and completeness.",
4733
- "Call complete_audit when done."
4734
- ].join("\n");
4735
- const events = query3({
4736
- prompt: userPrompt,
4737
- options: {
4738
- model,
4739
- systemPrompt: { type: "preset", preset: "claude_code", append: systemPrompt },
4740
- cwd: projectDir,
4741
- permissionMode: "bypassPermissions",
4742
- allowDangerouslySkipPermissions: true,
4743
- tools: { type: "preset", preset: "claude_code" },
4744
- mcpServers: { "tag-audit": createAuditMcpServer(collector, onRecommendation) },
4745
- maxTurns: settings.maxTurns ?? 75,
4746
- maxBudgetUsd: settings.maxBudgetUsd ?? 5,
4747
- effort: settings.effort,
4748
- thinking: settings.thinking
4749
- }
4750
- });
4751
- const responseParts = [];
4752
- const turnToolCalls = [];
4753
- const isTyping = { value: false };
4754
- for await (const event of events) {
4755
- emitToolCallProgress(event, request, connection);
4756
- const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
4757
- if (done) break;
4758
- }
4759
- if (isTyping.value) {
4760
- connection.emitEvent({ type: "agent_typing_stop" });
4761
- }
4762
- return collector;
4763
- }
4764
- async function handleProjectAuditRequest(request, connection, projectDir) {
4765
- connection.emitAgentStatus("running");
4766
- try {
4767
- const collector = await runAuditQuery(request, connection, projectDir);
4768
- const result = {
4769
- recommendations: collector.recommendations,
4770
- summary: collector.summary,
4771
- analyzedAt: (/* @__PURE__ */ new Date()).toISOString()
4772
- };
4773
- logger5.info("Tag audit completed", {
4774
- requestId: request.requestId,
4775
- recommendationCount: result.recommendations.length
4776
- });
4777
- connection.emitAuditResult({ requestId: request.requestId, result });
4778
- } catch (error) {
4779
- logger5.error("Tag audit failed", {
4780
- requestId: request.requestId,
4781
- ...errorMeta(error)
4782
- });
4783
- connection.emitAuditResult({
4784
- requestId: request.requestId,
4785
- error: error instanceof Error ? error.message : "Tag audit failed"
4786
- });
4787
- } finally {
4788
- connection.emitAgentStatus("idle");
4789
- }
4790
- }
4791
-
4792
4041
  // src/runner/project-runner.ts
4793
- var logger6 = createServiceLogger("ProjectRunner");
4042
+ var logger4 = createServiceLogger("ProjectRunner");
4794
4043
  var __filename = fileURLToPath(import.meta.url);
4795
4044
  var __dirname = path.dirname(__filename);
4796
4045
  var HEARTBEAT_INTERVAL_MS2 = 3e4;
@@ -4809,12 +4058,12 @@ function setupWorkDir(projectDir, assignment) {
4809
4058
  }
4810
4059
  if (branch && branch !== devBranch) {
4811
4060
  try {
4812
- execSync6(`git checkout ${branch}`, { cwd: workDir, stdio: "ignore" });
4061
+ execSync5(`git checkout ${branch}`, { cwd: workDir, stdio: "ignore" });
4813
4062
  } catch {
4814
4063
  try {
4815
- execSync6(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
4064
+ execSync5(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
4816
4065
  } catch {
4817
- logger6.warn("Could not checkout branch", { taskId: shortId, branch });
4066
+ logger4.warn("Could not checkout branch", { taskId: shortId, branch });
4818
4067
  }
4819
4068
  }
4820
4069
  }
@@ -4853,13 +4102,13 @@ function spawnChildAgent(assignment, workDir) {
4853
4102
  child.stdout?.on("data", (data) => {
4854
4103
  const lines = data.toString().trimEnd().split("\n");
4855
4104
  for (const line of lines) {
4856
- logger6.info(line, { taskId: shortId });
4105
+ logger4.info(line, { taskId: shortId });
4857
4106
  }
4858
4107
  });
4859
4108
  child.stderr?.on("data", (data) => {
4860
4109
  const lines = data.toString().trimEnd().split("\n");
4861
4110
  for (const line of lines) {
4862
- logger6.error(line, { taskId: shortId });
4111
+ logger4.error(line, { taskId: shortId });
4863
4112
  }
4864
4113
  });
4865
4114
  return child;
@@ -4875,55 +4124,23 @@ var ProjectRunner = class {
4875
4124
  startCommandChild = null;
4876
4125
  startCommandRunning = false;
4877
4126
  setupComplete = false;
4878
- branchSwitchCommand;
4879
- commitWatcher;
4880
4127
  constructor(config) {
4881
4128
  this.projectDir = config.projectDir;
4882
4129
  this.connection = new ProjectConnection({
4883
4130
  apiUrl: config.conveyorApiUrl,
4884
4131
  projectToken: config.projectToken,
4885
- projectId: config.projectId,
4886
- projectDir: config.projectDir
4132
+ projectId: config.projectId
4887
4133
  });
4888
- this.commitWatcher = new CommitWatcher(
4889
- {
4890
- projectDir: this.projectDir,
4891
- pollIntervalMs: Number(process.env.CONVEYOR_COMMIT_POLL_INTERVAL) || 1e4,
4892
- debounceMs: 3e3
4893
- },
4894
- {
4895
- onNewCommits: async (data) => {
4896
- this.connection.emitNewCommitsDetected({
4897
- branch: data.branch,
4898
- commitCount: data.commitCount,
4899
- latestCommit: {
4900
- sha: data.newCommitSha,
4901
- message: data.latestMessage,
4902
- author: data.latestAuthor
4903
- },
4904
- autoSyncing: true
4905
- });
4906
- const startTime = Date.now();
4907
- const stepsRun = await this.smartSync(data.previousSha, data.newCommitSha, data.branch);
4908
- this.connection.emitEnvironmentReady({
4909
- branch: data.branch,
4910
- commitsSynced: data.commitCount,
4911
- syncDurationMs: Date.now() - startTime,
4912
- stepsRun
4913
- });
4914
- }
4915
- }
4916
- );
4917
4134
  }
4918
4135
  checkoutWorkspaceBranch() {
4919
4136
  const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
4920
4137
  if (!workspaceBranch) return;
4921
4138
  try {
4922
- execSync6(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
4923
- execSync6(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
4924
- logger6.info("Checked out workspace branch", { workspaceBranch });
4139
+ execSync5(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
4140
+ execSync5(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
4141
+ logger4.info("Checked out workspace branch", { workspaceBranch });
4925
4142
  } catch (err) {
4926
- logger6.warn("Failed to checkout workspace branch, continuing on current branch", {
4143
+ logger4.warn("Failed to checkout workspace branch, continuing on current branch", {
4927
4144
  workspaceBranch,
4928
4145
  ...errorMeta(err)
4929
4146
  });
@@ -4932,15 +4149,15 @@ var ProjectRunner = class {
4932
4149
  async executeSetupCommand() {
4933
4150
  const cmd = process.env.CONVEYOR_SETUP_COMMAND;
4934
4151
  if (!cmd) return;
4935
- logger6.info("Running setup command", { command: cmd });
4152
+ logger4.info("Running setup command", { command: cmd });
4936
4153
  try {
4937
4154
  await runSetupCommand(cmd, this.projectDir, (stream, data) => {
4938
4155
  this.connection.emitEvent({ type: "setup_output", stream, data });
4939
4156
  (stream === "stderr" ? process.stderr : process.stdout).write(data);
4940
4157
  });
4941
- logger6.info("Setup command completed");
4158
+ logger4.info("Setup command completed");
4942
4159
  } catch (error) {
4943
- logger6.error("Setup command failed", errorMeta(error));
4160
+ logger4.error("Setup command failed", errorMeta(error));
4944
4161
  this.connection.emitEvent({
4945
4162
  type: "setup_error",
4946
4163
  message: error instanceof Error ? error.message : "Setup command failed"
@@ -4951,7 +4168,7 @@ var ProjectRunner = class {
4951
4168
  executeStartCommand() {
4952
4169
  const cmd = process.env.CONVEYOR_START_COMMAND;
4953
4170
  if (!cmd) return;
4954
- logger6.info("Running start command", { command: cmd });
4171
+ logger4.info("Running start command", { command: cmd });
4955
4172
  const child = runStartCommand(cmd, this.projectDir, (stream, data) => {
4956
4173
  this.connection.emitEvent({ type: "start_command_output", stream, data });
4957
4174
  (stream === "stderr" ? process.stderr : process.stdout).write(data);
@@ -4961,7 +4178,7 @@ var ProjectRunner = class {
4961
4178
  child.on("exit", (code, signal) => {
4962
4179
  this.startCommandRunning = false;
4963
4180
  this.startCommandChild = null;
4964
- logger6.info("Start command exited", { code, signal });
4181
+ logger4.info("Start command exited", { code, signal });
4965
4182
  this.connection.emitEvent({
4966
4183
  type: "start_command_exited",
4967
4184
  code,
@@ -4972,13 +4189,13 @@ var ProjectRunner = class {
4972
4189
  child.on("error", (err) => {
4973
4190
  this.startCommandRunning = false;
4974
4191
  this.startCommandChild = null;
4975
- logger6.error("Start command error", errorMeta(err));
4192
+ logger4.error("Start command error", errorMeta(err));
4976
4193
  });
4977
4194
  }
4978
4195
  async killStartCommand() {
4979
4196
  const child = this.startCommandChild;
4980
4197
  if (!child || !this.startCommandRunning) return;
4981
- logger6.info("Killing start command");
4198
+ logger4.info("Killing start command");
4982
4199
  try {
4983
4200
  if (child.pid) process.kill(-child.pid, "SIGTERM");
4984
4201
  } catch {
@@ -5010,7 +4227,7 @@ var ProjectRunner = class {
5010
4227
  getEnvironmentStatus() {
5011
4228
  let currentBranch = "unknown";
5012
4229
  try {
5013
- currentBranch = execSync6("git branch --show-current", {
4230
+ currentBranch = execSync5("git branch --show-current", {
5014
4231
  cwd: this.projectDir,
5015
4232
  stdio: ["ignore", "pipe", "ignore"]
5016
4233
  }).toString().trim();
@@ -5023,180 +4240,6 @@ var ProjectRunner = class {
5023
4240
  previewPort: Number(process.env.CONVEYOR_PREVIEW_PORT) || null
5024
4241
  };
5025
4242
  }
5026
- getCurrentBranch() {
5027
- try {
5028
- return execSync6("git branch --show-current", {
5029
- cwd: this.projectDir,
5030
- stdio: ["ignore", "pipe", "ignore"]
5031
- }).toString().trim() || null;
5032
- } catch {
5033
- return null;
5034
- }
5035
- }
5036
- // oxlint-disable-next-line max-lines-per-function, complexity -- sequential sync steps with per-step error handling
5037
- async smartSync(previousSha, newSha, branch) {
5038
- const stepsRun = [];
5039
- const status = execSync6("git status --porcelain", {
5040
- cwd: this.projectDir,
5041
- stdio: ["ignore", "pipe", "ignore"]
5042
- }).toString().trim();
5043
- if (status) {
5044
- this.connection.emitEvent({
5045
- type: "commit_watch_warning",
5046
- message: "Working tree has uncommitted changes. Auto-pull skipped."
5047
- });
5048
- return ["skipped:dirty_tree"];
5049
- }
5050
- await this.killStartCommand();
5051
- this.connection.emitEnvSwitchProgress({ step: "pull", status: "running" });
5052
- try {
5053
- execSync6(`git pull origin ${branch}`, {
5054
- cwd: this.projectDir,
5055
- stdio: "pipe",
5056
- timeout: 6e4
5057
- });
5058
- stepsRun.push("pull");
5059
- this.connection.emitEnvSwitchProgress({ step: "pull", status: "success" });
5060
- } catch (err) {
5061
- const message = err instanceof Error ? err.message : "Pull failed";
5062
- this.connection.emitEnvSwitchProgress({ step: "pull", status: "error", message });
5063
- logger6.error("Git pull failed during commit sync", errorMeta(err));
5064
- this.executeStartCommand();
5065
- return ["error:pull"];
5066
- }
5067
- let changedFiles = [];
5068
- try {
5069
- changedFiles = execSync6(`git diff --name-only ${previousSha}..${newSha}`, {
5070
- cwd: this.projectDir,
5071
- stdio: ["ignore", "pipe", "ignore"]
5072
- }).toString().trim().split("\n").filter(Boolean);
5073
- } catch {
5074
- }
5075
- const needsInstall = changedFiles.some(
5076
- (f) => f === "package.json" || f === "bun.lockb" || f === "bunfig.toml" || f.endsWith("/package.json") || f.endsWith("/bun.lockb")
5077
- );
5078
- const needsPrisma = changedFiles.some(
5079
- (f) => f.includes("prisma/schema.prisma") || f.includes("prisma/migrations/")
5080
- );
5081
- const cmd = this.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
5082
- if (cmd && (needsInstall || needsPrisma)) {
5083
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "running" });
5084
- try {
5085
- await runSetupCommand(cmd, this.projectDir, (stream, data) => {
5086
- this.connection.emitEvent({ type: "sync_output", stream, data });
5087
- });
5088
- stepsRun.push("branchSwitchCommand");
5089
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "success" });
5090
- } catch (err) {
5091
- const message = err instanceof Error ? err.message : "Sync command failed";
5092
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "error", message });
5093
- logger6.error("Branch switch command failed during commit sync", errorMeta(err));
5094
- }
5095
- } else if (!cmd) {
5096
- if (needsInstall) {
5097
- this.connection.emitEnvSwitchProgress({ step: "install", status: "running" });
5098
- try {
5099
- execSync6("bun install", { cwd: this.projectDir, timeout: 12e4, stdio: "pipe" });
5100
- stepsRun.push("install");
5101
- this.connection.emitEnvSwitchProgress({ step: "install", status: "success" });
5102
- } catch (err) {
5103
- const message = err instanceof Error ? err.message : "Install failed";
5104
- this.connection.emitEnvSwitchProgress({ step: "install", status: "error", message });
5105
- logger6.error("bun install failed during commit sync", errorMeta(err));
5106
- }
5107
- }
5108
- if (needsPrisma) {
5109
- this.connection.emitEnvSwitchProgress({ step: "prisma", status: "running" });
5110
- try {
5111
- execSync6("bunx prisma generate", {
5112
- cwd: this.projectDir,
5113
- timeout: 6e4,
5114
- stdio: "pipe"
5115
- });
5116
- execSync6("bunx prisma db push --accept-data-loss", {
5117
- cwd: this.projectDir,
5118
- timeout: 6e4,
5119
- stdio: "pipe"
5120
- });
5121
- stepsRun.push("prisma");
5122
- this.connection.emitEnvSwitchProgress({ step: "prisma", status: "success" });
5123
- } catch (err) {
5124
- const message = err instanceof Error ? err.message : "Prisma sync failed";
5125
- this.connection.emitEnvSwitchProgress({ step: "prisma", status: "error", message });
5126
- logger6.error("Prisma sync failed during commit sync", errorMeta(err));
5127
- }
5128
- }
5129
- }
5130
- this.executeStartCommand();
5131
- stepsRun.push("startCommand");
5132
- return stepsRun;
5133
- }
5134
- async handleSwitchBranch(data, callback) {
5135
- const { branch, syncAfter } = data;
5136
- try {
5137
- this.connection.emitEnvSwitchProgress({ step: "fetch", status: "running" });
5138
- try {
5139
- execSync6("git fetch origin", { cwd: this.projectDir, stdio: "pipe" });
5140
- } catch {
5141
- logger6.warn("Git fetch failed during branch switch");
5142
- }
5143
- this.connection.emitEnvSwitchProgress({ step: "fetch", status: "success" });
5144
- this.connection.emitEnvSwitchProgress({ step: "checkout", status: "running" });
5145
- try {
5146
- execSync6(`git checkout ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
5147
- } catch (err) {
5148
- const message = err instanceof Error ? err.message : "Checkout failed";
5149
- this.connection.emitEnvSwitchProgress({ step: "checkout", status: "error", message });
5150
- callback({ ok: false, error: `Failed to checkout branch: ${message}` });
5151
- return;
5152
- }
5153
- try {
5154
- execSync6(`git pull origin ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
5155
- } catch {
5156
- logger6.warn("Git pull failed during branch switch", { branch });
5157
- }
5158
- this.connection.emitEnvSwitchProgress({ step: "checkout", status: "success" });
5159
- if (syncAfter !== false) {
5160
- await this.handleSyncEnvironment();
5161
- }
5162
- this.commitWatcher.start(branch);
5163
- callback({ ok: true, data: this.getEnvironmentStatus() });
5164
- } catch (err) {
5165
- const message = err instanceof Error ? err.message : "Branch switch failed";
5166
- logger6.error("Branch switch failed", errorMeta(err));
5167
- callback({ ok: false, error: message });
5168
- }
5169
- }
5170
- async handleSyncEnvironment(callback) {
5171
- try {
5172
- await this.killStartCommand();
5173
- const cmd = this.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
5174
- if (cmd) {
5175
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "running" });
5176
- try {
5177
- await runSetupCommand(cmd, this.projectDir, (stream, data) => {
5178
- this.connection.emitEvent({ type: "sync_output", stream, data });
5179
- (stream === "stderr" ? process.stderr : process.stdout).write(data);
5180
- });
5181
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "success" });
5182
- } catch (err) {
5183
- const message = err instanceof Error ? err.message : "Sync command failed";
5184
- this.connection.emitEnvSwitchProgress({ step: "sync", status: "error", message });
5185
- logger6.error("Branch switch sync command failed", errorMeta(err));
5186
- }
5187
- }
5188
- this.executeStartCommand();
5189
- this.connection.emitEnvSwitchProgress({ step: "startCommand", status: "success" });
5190
- callback?.({ ok: true, data: this.getEnvironmentStatus() });
5191
- } catch (err) {
5192
- const message = err instanceof Error ? err.message : "Sync failed";
5193
- logger6.error("Environment sync failed", errorMeta(err));
5194
- callback?.({ ok: false, error: message });
5195
- }
5196
- }
5197
- handleGetEnvStatus(callback) {
5198
- callback({ ok: true, data: this.getEnvironmentStatus() });
5199
- }
5200
4243
  async start() {
5201
4244
  this.checkoutWorkspaceBranch();
5202
4245
  await this.connection.connect();
@@ -5210,7 +4253,7 @@ var ProjectRunner = class {
5210
4253
  startCommandRunning: this.startCommandRunning
5211
4254
  });
5212
4255
  } catch (error) {
5213
- logger6.error("Environment setup failed", errorMeta(error));
4256
+ logger4.error("Environment setup failed", errorMeta(error));
5214
4257
  this.setupComplete = false;
5215
4258
  }
5216
4259
  this.connection.onTaskAssignment((assignment) => {
@@ -5220,45 +4263,17 @@ var ProjectRunner = class {
5220
4263
  this.handleStopTask(data.taskId);
5221
4264
  });
5222
4265
  this.connection.onShutdown(() => {
5223
- logger6.info("Received shutdown signal from server");
4266
+ logger4.info("Received shutdown signal from server");
5224
4267
  void this.stop();
5225
4268
  });
5226
4269
  this.connection.onChatMessage((msg) => {
5227
- logger6.debug("Received project chat message");
4270
+ logger4.debug("Received project chat message");
5228
4271
  void handleProjectChatMessage(msg, this.connection, this.projectDir);
5229
4272
  });
5230
- this.connection.onAuditRequest((request) => {
5231
- logger6.debug("Received tag audit request", { requestId: request.requestId });
5232
- void handleProjectAuditRequest(request, this.connection, this.projectDir);
5233
- });
5234
- this.connection.onSwitchBranch = (data, cb) => {
5235
- void this.handleSwitchBranch(data, cb);
5236
- };
5237
- this.connection.onSyncEnvironment = (cb) => {
5238
- void this.handleSyncEnvironment(cb);
5239
- };
5240
- this.connection.onGetEnvStatus = (cb) => {
5241
- this.handleGetEnvStatus(cb);
5242
- };
5243
- this.connection.onRestartStartCommand = (cb) => {
5244
- void this.restartStartCommand().then(() => cb({ ok: true })).catch(
5245
- (err) => cb({ ok: false, error: err instanceof Error ? err.message : "Restart failed" })
5246
- );
5247
- };
5248
- try {
5249
- const context = await this.connection.fetchAgentContext();
5250
- this.branchSwitchCommand = context?.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
5251
- } catch {
5252
- this.branchSwitchCommand = process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
5253
- }
5254
4273
  this.heartbeatTimer = setInterval(() => {
5255
4274
  this.connection.sendHeartbeat();
5256
4275
  }, HEARTBEAT_INTERVAL_MS2);
5257
- const currentBranch = this.getCurrentBranch();
5258
- if (currentBranch) {
5259
- this.commitWatcher.start(currentBranch);
5260
- }
5261
- logger6.info("Connected, waiting for task assignments");
4276
+ logger4.info("Connected, waiting for task assignments");
5262
4277
  await new Promise((resolve2) => {
5263
4278
  this.resolveLifecycle = resolve2;
5264
4279
  process.on("SIGTERM", () => void this.stop());
@@ -5269,11 +4284,11 @@ var ProjectRunner = class {
5269
4284
  const { taskId, mode } = assignment;
5270
4285
  const shortId = taskId.slice(0, 8);
5271
4286
  if (this.activeAgents.has(taskId)) {
5272
- logger6.info("Task already running, skipping", { taskId: shortId });
4287
+ logger4.info("Task already running, skipping", { taskId: shortId });
5273
4288
  return;
5274
4289
  }
5275
4290
  if (this.activeAgents.size >= MAX_CONCURRENT) {
5276
- logger6.warn("Max concurrent agents reached, rejecting task", {
4291
+ logger4.warn("Max concurrent agents reached, rejecting task", {
5277
4292
  maxConcurrent: MAX_CONCURRENT,
5278
4293
  taskId: shortId
5279
4294
  });
@@ -5282,9 +4297,9 @@ var ProjectRunner = class {
5282
4297
  }
5283
4298
  try {
5284
4299
  try {
5285
- execSync6("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
4300
+ execSync5("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
5286
4301
  } catch {
5287
- logger6.warn("Git fetch failed", { taskId: shortId });
4302
+ logger4.warn("Git fetch failed", { taskId: shortId });
5288
4303
  }
5289
4304
  const { workDir, usesWorktree } = setupWorkDir(this.projectDir, assignment);
5290
4305
  const child = spawnChildAgent(assignment, workDir);
@@ -5295,12 +4310,12 @@ var ProjectRunner = class {
5295
4310
  usesWorktree
5296
4311
  });
5297
4312
  this.connection.emitTaskStarted(taskId);
5298
- logger6.info("Started task", { taskId: shortId, mode, workDir });
4313
+ logger4.info("Started task", { taskId: shortId, mode, workDir });
5299
4314
  child.on("exit", (code) => {
5300
4315
  this.activeAgents.delete(taskId);
5301
4316
  const reason = code === 0 ? "completed" : `exited with code ${code}`;
5302
4317
  this.connection.emitTaskStopped(taskId, reason);
5303
- logger6.info("Task exited", { taskId: shortId, reason });
4318
+ logger4.info("Task exited", { taskId: shortId, reason });
5304
4319
  if (code === 0 && usesWorktree) {
5305
4320
  try {
5306
4321
  removeWorktree(this.projectDir, taskId);
@@ -5309,7 +4324,7 @@ var ProjectRunner = class {
5309
4324
  }
5310
4325
  });
5311
4326
  } catch (error) {
5312
- logger6.error("Failed to start task", {
4327
+ logger4.error("Failed to start task", {
5313
4328
  taskId: shortId,
5314
4329
  ...errorMeta(error)
5315
4330
  });
@@ -5323,7 +4338,7 @@ var ProjectRunner = class {
5323
4338
  const agent = this.activeAgents.get(taskId);
5324
4339
  if (!agent) return;
5325
4340
  const shortId = taskId.slice(0, 8);
5326
- logger6.info("Stopping task", { taskId: shortId });
4341
+ logger4.info("Stopping task", { taskId: shortId });
5327
4342
  agent.process.kill("SIGTERM");
5328
4343
  const timer = setTimeout(() => {
5329
4344
  if (this.activeAgents.has(taskId)) {
@@ -5343,8 +4358,7 @@ var ProjectRunner = class {
5343
4358
  async stop() {
5344
4359
  if (this.stopping) return;
5345
4360
  this.stopping = true;
5346
- logger6.info("Shutting down");
5347
- this.commitWatcher.stop();
4361
+ logger4.info("Shutting down");
5348
4362
  await this.killStartCommand();
5349
4363
  if (this.heartbeatTimer) {
5350
4364
  clearInterval(this.heartbeatTimer);
@@ -5370,7 +4384,7 @@ var ProjectRunner = class {
5370
4384
  })
5371
4385
  ]);
5372
4386
  this.connection.disconnect();
5373
- logger6.info("Shutdown complete");
4387
+ logger4.info("Shutdown complete");
5374
4388
  if (this.resolveLifecycle) {
5375
4389
  this.resolveLifecycle();
5376
4390
  this.resolveLifecycle = null;
@@ -5456,4 +4470,4 @@ export {
5456
4470
  ProjectRunner,
5457
4471
  FileCache
5458
4472
  };
5459
- //# sourceMappingURL=chunk-U3YWTVH3.js.map
4473
+ //# sourceMappingURL=chunk-JFIWJVOH.js.map