@rallycry/conveyor-agent 5.11.0 → 5.12.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,6 +427,23 @@ 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
+ }
430
447
  emitModeTransition(payload) {
431
448
  if (!this.socket) return;
432
449
  this.socket.emit("agentRunner:modeTransition", payload);
@@ -623,13 +640,13 @@ var ProjectConnection = class {
623
640
  );
624
641
  });
625
642
  }
626
- fetchChatHistory(limit) {
643
+ fetchChatHistory(limit, chatId) {
627
644
  const socket = this.socket;
628
645
  if (!socket) return Promise.reject(new Error("Not connected"));
629
646
  return new Promise((resolve2, reject) => {
630
647
  socket.emit(
631
648
  "projectRunner:getChatHistory",
632
- { limit },
649
+ { limit, chatId },
633
650
  (response) => {
634
651
  if (response.success && response.data) resolve2(response.data);
635
652
  else reject(new Error(response.error ?? "Failed to fetch chat history"));
@@ -637,6 +654,38 @@ var ProjectConnection = class {
637
654
  );
638
655
  });
639
656
  }
657
+ // ── Project MCP tool request methods ──
658
+ requestListTasks(params) {
659
+ return this.requestWithCallback("projectRunner:listTasks", params);
660
+ }
661
+ requestGetTask(taskId) {
662
+ return this.requestWithCallback("projectRunner:getTask", { taskId });
663
+ }
664
+ requestCreateTask(params) {
665
+ return this.requestWithCallback("projectRunner:createTask", params);
666
+ }
667
+ requestUpdateTask(params) {
668
+ return this.requestWithCallback("projectRunner:updateTask", params);
669
+ }
670
+ requestSearchTasks(params) {
671
+ return this.requestWithCallback("projectRunner:searchTasks", params);
672
+ }
673
+ requestListTags() {
674
+ return this.requestWithCallback("projectRunner:listTags", {});
675
+ }
676
+ requestGetProjectSummary() {
677
+ return this.requestWithCallback("projectRunner:getProjectSummary", {});
678
+ }
679
+ requestWithCallback(event, data) {
680
+ const socket = this.socket;
681
+ if (!socket) return Promise.reject(new Error("Not connected"));
682
+ return new Promise((resolve2, reject) => {
683
+ socket.emit(event, data, (response) => {
684
+ if (response.success) resolve2(response.data);
685
+ else reject(new Error(response.error ?? `${event} failed`));
686
+ });
687
+ });
688
+ }
640
689
  emitNewCommitsDetected(data) {
641
690
  if (!this.socket) return;
642
691
  this.socket.emit("projectRunner:newCommitsDetected", data);
@@ -842,6 +891,10 @@ async function processAssistantEvent(event, host, turnToolCalls) {
842
891
  }
843
892
  var API_ERROR_PATTERN = /API Error: [45]\d\d/;
844
893
  var IMAGE_ERROR_PATTERN = /Could not process image/i;
894
+ var AUTH_ERROR_PATTERN = /Not logged in|Please run \/login|authentication failed|invalid.*token|unauthorized/i;
895
+ function isAuthError(msg) {
896
+ return AUTH_ERROR_PATTERN.test(msg);
897
+ }
845
898
  function isRetriableMessage(msg) {
846
899
  if (IMAGE_ERROR_PATTERN.test(msg)) return true;
847
900
  if (API_ERROR_PATTERN.test(msg)) return true;
@@ -922,6 +975,10 @@ function handleErrorResult(event, host) {
922
975
  if (isStaleSession) {
923
976
  return { retriable: false, staleSession: true };
924
977
  }
978
+ if (isAuthError(errorMsg)) {
979
+ host.connection.sendEvent({ type: "error", message: errorMsg });
980
+ return { retriable: false, authError: true };
981
+ }
925
982
  const retriable = isRetriableMessage(errorMsg);
926
983
  host.connection.sendEvent({ type: "error", message: errorMsg });
927
984
  return { retriable };
@@ -961,7 +1018,8 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
961
1018
  return {
962
1019
  retriable: result.retriable,
963
1020
  resultSummary: result.resultSummary,
964
- staleSession: result.staleSession
1021
+ staleSession: result.staleSession,
1022
+ authError: result.authError
965
1023
  };
966
1024
  }
967
1025
  function handleRateLimitEvent(event, host) {
@@ -1061,6 +1119,7 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
1061
1119
  retriable: resultInfo.retriable,
1062
1120
  resultSummary: resultInfo.resultSummary,
1063
1121
  staleSession: resultInfo.staleSession,
1122
+ authError: resultInfo.authError,
1064
1123
  stoppedTyping
1065
1124
  };
1066
1125
  }
@@ -1108,6 +1167,7 @@ async function processResultCase(event, host, context, startTime, state) {
1108
1167
  state.retriable = info.retriable;
1109
1168
  state.resultSummary = info.resultSummary;
1110
1169
  if (info.staleSession) state.staleSession = true;
1170
+ if (info.authError) state.authError = true;
1111
1171
  }
1112
1172
  async function processEvents(events, context, host) {
1113
1173
  const startTime = Date.now();
@@ -1121,6 +1181,7 @@ async function processEvents(events, context, host) {
1121
1181
  resultSummary: void 0,
1122
1182
  rateLimitResetsAt: void 0,
1123
1183
  staleSession: void 0,
1184
+ authError: void 0,
1124
1185
  lastAssistantUsage: void 0,
1125
1186
  turnToolCalls: []
1126
1187
  };
@@ -1160,7 +1221,8 @@ async function processEvents(events, context, host) {
1160
1221
  retriable: state.retriable || state.sawApiError,
1161
1222
  resultSummary: state.resultSummary,
1162
1223
  rateLimitResetsAt: state.rateLimitResetsAt,
1163
- ...state.staleSession && { staleSession: state.staleSession }
1224
+ ...state.staleSession && { staleSession: state.staleSession },
1225
+ ...state.authError && { authError: state.authError }
1164
1226
  };
1165
1227
  }
1166
1228
 
@@ -3115,6 +3177,29 @@ async function buildRetryQuery(host, context, options, lastErrorWasImage) {
3115
3177
  options: { ...options, resume: void 0 }
3116
3178
  });
3117
3179
  }
3180
+ async function handleAuthError(context, host, options) {
3181
+ host.connection.postChatMessage("Authentication expired. Re-bootstrapping credentials...");
3182
+ const refreshed = await host.connection.refreshAuthToken();
3183
+ if (!refreshed) {
3184
+ host.connection.postChatMessage("Failed to refresh authentication. Agent will restart.");
3185
+ host.connection.sendEvent({
3186
+ type: "error",
3187
+ message: "Auth re-bootstrap failed, exiting for restart"
3188
+ });
3189
+ process.exit(1);
3190
+ }
3191
+ context.claudeSessionId = null;
3192
+ host.connection.storeSessionId("");
3193
+ const freshPrompt = buildMultimodalPrompt(
3194
+ await buildInitialPrompt(host.config.mode, context, host.config.isAuto, host.agentMode),
3195
+ context
3196
+ );
3197
+ const freshQuery = query({
3198
+ prompt: host.createInputStream(freshPrompt),
3199
+ options: { ...options, resume: void 0 }
3200
+ });
3201
+ return runWithRetry(freshQuery, context, host, options);
3202
+ }
3118
3203
  async function handleStaleSession(context, host, options) {
3119
3204
  context.claudeSessionId = null;
3120
3205
  host.connection.storeSessionId("");
@@ -3183,26 +3268,41 @@ function handleRetryError(error, context, host, options, prevImageError) {
3183
3268
  if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {
3184
3269
  return handleStaleSession(context, host, options);
3185
3270
  }
3271
+ if (isAuthError(getErrorMessage(error))) {
3272
+ return handleAuthError(context, host, options);
3273
+ }
3186
3274
  if (!isRetriableError(error)) throw error;
3187
3275
  return { action: "continue", lastErrorWasImage: classifyImageError(error) || prevImageError };
3188
3276
  }
3277
+ function handleProcessResult(result, context, host, options) {
3278
+ if (result.modeRestart || host.isStopped()) return { action: "return" };
3279
+ if (result.rateLimitResetsAt) {
3280
+ handleRateLimitPause(host, result.rateLimitResetsAt);
3281
+ return { action: "return" };
3282
+ }
3283
+ if (result.staleSession && context.claudeSessionId) {
3284
+ return { action: "return_promise", promise: handleStaleSession(context, host, options) };
3285
+ }
3286
+ if (result.authError) {
3287
+ return { action: "return_promise", promise: handleAuthError(context, host, options) };
3288
+ }
3289
+ if (!result.retriable) return { action: "return" };
3290
+ return {
3291
+ action: "continue",
3292
+ lastErrorWasImage: IMAGE_ERROR_PATTERN2.test(result.resultSummary ?? "")
3293
+ };
3294
+ }
3189
3295
  async function runWithRetry(initialQuery, context, host, options) {
3190
3296
  let lastErrorWasImage = false;
3191
3297
  for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
3192
3298
  if (host.isStopped()) return;
3193
3299
  const agentQuery = attempt === 0 ? initialQuery : await buildRetryQuery(host, context, options, lastErrorWasImage);
3194
3300
  try {
3195
- const { retriable, resultSummary, modeRestart, rateLimitResetsAt, staleSession } = await processEvents(agentQuery, context, host);
3196
- if (modeRestart || host.isStopped()) return;
3197
- if (rateLimitResetsAt) {
3198
- handleRateLimitPause(host, rateLimitResetsAt);
3199
- return;
3200
- }
3201
- if (staleSession && context.claudeSessionId) {
3202
- return handleStaleSession(context, host, options);
3203
- }
3204
- if (!retriable) return;
3205
- lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
3301
+ const result = await processEvents(agentQuery, context, host);
3302
+ const outcome = handleProcessResult(result, context, host, options);
3303
+ if (outcome.action === "return") return;
3304
+ if (outcome.action === "return_promise") return outcome.promise;
3305
+ lastErrorWasImage = outcome.lastErrorWasImage;
3206
3306
  } catch (error) {
3207
3307
  const outcome = handleRetryError(error, context, host, options, lastErrorWasImage);
3208
3308
  if (outcome instanceof Promise) return outcome;
@@ -4142,7 +4242,159 @@ var CommitWatcher = class {
4142
4242
  };
4143
4243
 
4144
4244
  // src/runner/project-chat-handler.ts
4145
- import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
4245
+ import {
4246
+ query as query2,
4247
+ createSdkMcpServer as createSdkMcpServer2
4248
+ } from "@anthropic-ai/claude-agent-sdk";
4249
+
4250
+ // src/tools/project-tools.ts
4251
+ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
4252
+ import { z as z4 } from "zod";
4253
+ function buildReadTools(connection) {
4254
+ return [
4255
+ tool4(
4256
+ "list_tasks",
4257
+ "List tasks in the project. Optionally filter by status or assignee.",
4258
+ {
4259
+ status: z4.string().optional().describe("Filter by task status (e.g. Planning, Open, InProgress, ReviewPR, Complete)"),
4260
+ assigneeId: z4.string().optional().describe("Filter by assigned user ID"),
4261
+ limit: z4.number().optional().describe("Max number of tasks to return (default 50)")
4262
+ },
4263
+ async (params) => {
4264
+ try {
4265
+ const tasks = await connection.requestListTasks(params);
4266
+ return textResult(JSON.stringify(tasks, null, 2));
4267
+ } catch (error) {
4268
+ return textResult(
4269
+ `Failed to list tasks: ${error instanceof Error ? error.message : "Unknown error"}`
4270
+ );
4271
+ }
4272
+ },
4273
+ { annotations: { readOnlyHint: true } }
4274
+ ),
4275
+ tool4(
4276
+ "get_task",
4277
+ "Get detailed information about a task including its chat messages, child tasks, and codespace status.",
4278
+ { task_id: z4.string().describe("The task ID to look up") },
4279
+ async ({ task_id }) => {
4280
+ try {
4281
+ const task = await connection.requestGetTask(task_id);
4282
+ return textResult(JSON.stringify(task, null, 2));
4283
+ } catch (error) {
4284
+ return textResult(
4285
+ `Failed to get task: ${error instanceof Error ? error.message : "Unknown error"}`
4286
+ );
4287
+ }
4288
+ },
4289
+ { annotations: { readOnlyHint: true } }
4290
+ ),
4291
+ tool4(
4292
+ "search_tasks",
4293
+ "Search tasks by tags, text query, or status filters.",
4294
+ {
4295
+ tagNames: z4.array(z4.string()).optional().describe("Filter by tag names"),
4296
+ searchQuery: z4.string().optional().describe("Text search in title/description"),
4297
+ statusFilters: z4.array(z4.string()).optional().describe("Filter by statuses"),
4298
+ limit: z4.number().optional().describe("Max results (default 20)")
4299
+ },
4300
+ async (params) => {
4301
+ try {
4302
+ const tasks = await connection.requestSearchTasks(params);
4303
+ return textResult(JSON.stringify(tasks, null, 2));
4304
+ } catch (error) {
4305
+ return textResult(
4306
+ `Failed to search tasks: ${error instanceof Error ? error.message : "Unknown error"}`
4307
+ );
4308
+ }
4309
+ },
4310
+ { annotations: { readOnlyHint: true } }
4311
+ ),
4312
+ tool4(
4313
+ "list_tags",
4314
+ "List all tags available in the project.",
4315
+ {},
4316
+ async () => {
4317
+ try {
4318
+ const tags = await connection.requestListTags();
4319
+ return textResult(JSON.stringify(tags, null, 2));
4320
+ } catch (error) {
4321
+ return textResult(
4322
+ `Failed to list tags: ${error instanceof Error ? error.message : "Unknown error"}`
4323
+ );
4324
+ }
4325
+ },
4326
+ { annotations: { readOnlyHint: true } }
4327
+ ),
4328
+ tool4(
4329
+ "get_project_summary",
4330
+ "Get a summary of the project including task counts by status and active builds.",
4331
+ {},
4332
+ async () => {
4333
+ try {
4334
+ const summary = await connection.requestGetProjectSummary();
4335
+ return textResult(JSON.stringify(summary, null, 2));
4336
+ } catch (error) {
4337
+ return textResult(
4338
+ `Failed to get project summary: ${error instanceof Error ? error.message : "Unknown error"}`
4339
+ );
4340
+ }
4341
+ },
4342
+ { annotations: { readOnlyHint: true } }
4343
+ )
4344
+ ];
4345
+ }
4346
+ function buildMutationTools(connection) {
4347
+ return [
4348
+ tool4(
4349
+ "create_task",
4350
+ "Create a new task in the project.",
4351
+ {
4352
+ title: z4.string().describe("Task title"),
4353
+ description: z4.string().optional().describe("Task description"),
4354
+ plan: z4.string().optional().describe("Implementation plan in markdown"),
4355
+ status: z4.string().optional().describe("Initial status (default: Planning)"),
4356
+ isBug: z4.boolean().optional().describe("Whether this is a bug report")
4357
+ },
4358
+ async (params) => {
4359
+ try {
4360
+ const result = await connection.requestCreateTask(params);
4361
+ return textResult(`Task created: ${result.slug} (ID: ${result.id})`);
4362
+ } catch (error) {
4363
+ return textResult(
4364
+ `Failed to create task: ${error instanceof Error ? error.message : "Unknown error"}`
4365
+ );
4366
+ }
4367
+ }
4368
+ ),
4369
+ tool4(
4370
+ "update_task",
4371
+ "Update an existing task's title, description, plan, status, or assignee.",
4372
+ {
4373
+ task_id: z4.string().describe("The task ID to update"),
4374
+ title: z4.string().optional().describe("New title"),
4375
+ description: z4.string().optional().describe("New description"),
4376
+ plan: z4.string().optional().describe("New plan in markdown"),
4377
+ status: z4.string().optional().describe("New status"),
4378
+ assignedUserId: z4.string().nullable().optional().describe("Assign to user ID, or null to unassign")
4379
+ },
4380
+ async ({ task_id, ...fields }) => {
4381
+ try {
4382
+ await connection.requestUpdateTask({ taskId: task_id, ...fields });
4383
+ return textResult("Task updated successfully.");
4384
+ } catch (error) {
4385
+ return textResult(
4386
+ `Failed to update task: ${error instanceof Error ? error.message : "Unknown error"}`
4387
+ );
4388
+ }
4389
+ }
4390
+ )
4391
+ ];
4392
+ }
4393
+ function buildProjectTools(connection) {
4394
+ return [...buildReadTools(connection), ...buildMutationTools(connection)];
4395
+ }
4396
+
4397
+ // src/runner/project-chat-handler.ts
4146
4398
  var logger4 = createServiceLogger("ProjectChat");
4147
4399
  var FALLBACK_MODEL = "claude-sonnet-4-20250514";
4148
4400
  function buildSystemPrompt2(projectDir, agentCtx) {
@@ -4199,7 +4451,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
4199
4451
  logger4.debug("Tool use", { tool: block.name });
4200
4452
  }
4201
4453
  }
4202
- async function fetchContext(connection) {
4454
+ async function fetchContext(connection, chatId) {
4203
4455
  let agentCtx = null;
4204
4456
  try {
4205
4457
  agentCtx = await connection.fetchAgentContext();
@@ -4208,15 +4460,19 @@ async function fetchContext(connection) {
4208
4460
  }
4209
4461
  let chatHistory = [];
4210
4462
  try {
4211
- chatHistory = await connection.fetchChatHistory(30);
4463
+ chatHistory = await connection.fetchChatHistory(30, chatId);
4212
4464
  } catch {
4213
4465
  logger4.warn("Could not fetch chat history, proceeding without it");
4214
4466
  }
4215
4467
  return { agentCtx, chatHistory };
4216
4468
  }
4217
- function buildChatQueryOptions(agentCtx, projectDir) {
4469
+ function buildChatQueryOptions(agentCtx, projectDir, connection) {
4218
4470
  const model = agentCtx?.model || FALLBACK_MODEL;
4219
4471
  const settings = agentCtx?.agentSettings ?? {};
4472
+ const mcpServer = createSdkMcpServer2({
4473
+ name: "conveyor",
4474
+ tools: buildProjectTools(connection)
4475
+ });
4220
4476
  return {
4221
4477
  model,
4222
4478
  systemPrompt: {
@@ -4228,8 +4484,9 @@ function buildChatQueryOptions(agentCtx, projectDir) {
4228
4484
  permissionMode: "bypassPermissions",
4229
4485
  allowDangerouslySkipPermissions: true,
4230
4486
  tools: { type: "preset", preset: "claude_code" },
4231
- maxTurns: settings.maxTurns ?? 15,
4232
- maxBudgetUsd: settings.maxBudgetUsd ?? 5,
4487
+ mcpServers: { conveyor: mcpServer },
4488
+ maxTurns: settings.maxTurns ?? 30,
4489
+ maxBudgetUsd: settings.maxBudgetUsd ?? 50,
4233
4490
  effort: settings.effort,
4234
4491
  thinking: settings.thinking
4235
4492
  };
@@ -4295,16 +4552,25 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
4295
4552
  }
4296
4553
  return false;
4297
4554
  }
4298
- async function runChatQuery(message, connection, projectDir) {
4299
- const { agentCtx, chatHistory } = await fetchContext(connection);
4300
- const options = buildChatQueryOptions(agentCtx, projectDir);
4555
+ async function runChatQuery(message, connection, projectDir, sessionId) {
4556
+ const { agentCtx, chatHistory } = await fetchContext(connection, message.chatId);
4557
+ const options = buildChatQueryOptions(agentCtx, projectDir, connection);
4301
4558
  const prompt = buildPrompt(message, chatHistory);
4302
4559
  connection.emitAgentStatus("running");
4303
- const events = query2({ prompt, options });
4560
+ const events = query2({
4561
+ prompt,
4562
+ options,
4563
+ ...sessionId ? { resume: sessionId } : {}
4564
+ });
4304
4565
  const responseParts = [];
4305
4566
  const turnToolCalls = [];
4306
4567
  const isTyping = { value: false };
4568
+ let resultSessionId;
4307
4569
  for await (const event of events) {
4570
+ if (event.type === "result") {
4571
+ const resultEvent = event;
4572
+ resultSessionId = resultEvent.sessionId;
4573
+ }
4308
4574
  const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
4309
4575
  if (done) break;
4310
4576
  }
@@ -4315,11 +4581,12 @@ async function runChatQuery(message, connection, projectDir) {
4315
4581
  if (responseText) {
4316
4582
  await connection.emitChatMessage(responseText);
4317
4583
  }
4584
+ return resultSessionId;
4318
4585
  }
4319
- async function handleProjectChatMessage(message, connection, projectDir) {
4586
+ async function handleProjectChatMessage(message, connection, projectDir, sessionId) {
4320
4587
  connection.emitAgentStatus("fetching_context");
4321
4588
  try {
4322
- await runChatQuery(message, connection, projectDir);
4589
+ return await runChatQuery(message, connection, projectDir, sessionId);
4323
4590
  } catch (error) {
4324
4591
  logger4.error("Failed to handle message", errorMeta(error));
4325
4592
  connection.emitAgentStatus("error");
@@ -4329,6 +4596,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
4329
4596
  );
4330
4597
  } catch {
4331
4598
  }
4599
+ return void 0;
4332
4600
  } finally {
4333
4601
  connection.emitAgentStatus("idle");
4334
4602
  }
@@ -4339,8 +4607,8 @@ import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
4339
4607
 
4340
4608
  // src/tools/audit-tools.ts
4341
4609
  import { randomUUID as randomUUID3 } from "crypto";
4342
- import { tool as tool4, createSdkMcpServer as createSdkMcpServer2 } from "@anthropic-ai/claude-agent-sdk";
4343
- import { z as z4 } from "zod";
4610
+ import { tool as tool5, createSdkMcpServer as createSdkMcpServer3 } from "@anthropic-ai/claude-agent-sdk";
4611
+ import { z as z5 } from "zod";
4344
4612
  function mapCreateTag(input) {
4345
4613
  return {
4346
4614
  type: "create_tag",
@@ -4422,14 +4690,14 @@ function collectRecommendation(toolName, input, collector, onRecommendation) {
4422
4690
  }
4423
4691
  function createAuditMcpServer(collector, onRecommendation) {
4424
4692
  const auditTools = [
4425
- tool4(
4693
+ tool5(
4426
4694
  "recommend_create_tag",
4427
4695
  "Recommend creating a new tag for an uncovered subsystem or area",
4428
4696
  {
4429
- name: z4.string().describe("Proposed tag name (lowercase, hyphenated)"),
4430
- color: z4.string().optional().describe("Hex color code"),
4431
- description: z4.string().describe("What this tag covers"),
4432
- reasoning: z4.string().describe("Why this tag should be created")
4697
+ name: z5.string().describe("Proposed tag name (lowercase, hyphenated)"),
4698
+ color: z5.string().optional().describe("Hex color code"),
4699
+ description: z5.string().describe("What this tag covers"),
4700
+ reasoning: z5.string().describe("Why this tag should be created")
4433
4701
  },
4434
4702
  async (args) => {
4435
4703
  const result = collectRecommendation(
@@ -4441,14 +4709,14 @@ function createAuditMcpServer(collector, onRecommendation) {
4441
4709
  return { content: [{ type: "text", text: result }] };
4442
4710
  }
4443
4711
  ),
4444
- tool4(
4712
+ tool5(
4445
4713
  "recommend_update_description",
4446
4714
  "Recommend updating a tag's description to better reflect its scope",
4447
4715
  {
4448
- tagId: z4.string(),
4449
- tagName: z4.string(),
4450
- description: z4.string().describe("Proposed new description"),
4451
- reasoning: z4.string()
4716
+ tagId: z5.string(),
4717
+ tagName: z5.string(),
4718
+ description: z5.string().describe("Proposed new description"),
4719
+ reasoning: z5.string()
4452
4720
  },
4453
4721
  async (args) => {
4454
4722
  const result = collectRecommendation(
@@ -4460,16 +4728,16 @@ function createAuditMcpServer(collector, onRecommendation) {
4460
4728
  return { content: [{ type: "text", text: result }] };
4461
4729
  }
4462
4730
  ),
4463
- tool4(
4731
+ tool5(
4464
4732
  "recommend_context_link",
4465
4733
  "Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
4466
4734
  {
4467
- tagId: z4.string(),
4468
- tagName: z4.string(),
4469
- linkType: z4.enum(["rule", "doc", "file", "folder"]),
4470
- path: z4.string(),
4471
- label: z4.string().optional(),
4472
- reasoning: z4.string()
4735
+ tagId: z5.string(),
4736
+ tagName: z5.string(),
4737
+ linkType: z5.enum(["rule", "doc", "file", "folder"]),
4738
+ path: z5.string(),
4739
+ label: z5.string().optional(),
4740
+ reasoning: z5.string()
4473
4741
  },
4474
4742
  async (args) => {
4475
4743
  const result = collectRecommendation(
@@ -4481,16 +4749,16 @@ function createAuditMcpServer(collector, onRecommendation) {
4481
4749
  return { content: [{ type: "text", text: result }] };
4482
4750
  }
4483
4751
  ),
4484
- tool4(
4752
+ tool5(
4485
4753
  "flag_documentation_gap",
4486
4754
  "Flag a file that agents read heavily but has no tag documentation linked",
4487
4755
  {
4488
- tagName: z4.string().describe("Tag whose agents read this file"),
4489
- tagId: z4.string().optional(),
4490
- filePath: z4.string(),
4491
- readCount: z4.number(),
4492
- suggestedAction: z4.string().describe("What doc or rule should be created"),
4493
- reasoning: z4.string()
4756
+ tagName: z5.string().describe("Tag whose agents read this file"),
4757
+ tagId: z5.string().optional(),
4758
+ filePath: z5.string(),
4759
+ readCount: z5.number(),
4760
+ suggestedAction: z5.string().describe("What doc or rule should be created"),
4761
+ reasoning: z5.string()
4494
4762
  },
4495
4763
  async (args) => {
4496
4764
  const result = collectRecommendation(
@@ -4502,15 +4770,15 @@ function createAuditMcpServer(collector, onRecommendation) {
4502
4770
  return { content: [{ type: "text", text: result }] };
4503
4771
  }
4504
4772
  ),
4505
- tool4(
4773
+ tool5(
4506
4774
  "recommend_merge_tags",
4507
4775
  "Recommend merging one tag into another",
4508
4776
  {
4509
- tagId: z4.string().describe("Tag ID to be merged (removed after merge)"),
4510
- tagName: z4.string().describe("Name of the tag to be merged"),
4511
- mergeIntoTagId: z4.string().describe("Tag ID to merge into (kept)"),
4512
- mergeIntoTagName: z4.string(),
4513
- reasoning: z4.string()
4777
+ tagId: z5.string().describe("Tag ID to be merged (removed after merge)"),
4778
+ tagName: z5.string().describe("Name of the tag to be merged"),
4779
+ mergeIntoTagId: z5.string().describe("Tag ID to merge into (kept)"),
4780
+ mergeIntoTagName: z5.string(),
4781
+ reasoning: z5.string()
4514
4782
  },
4515
4783
  async (args) => {
4516
4784
  const result = collectRecommendation(
@@ -4522,14 +4790,14 @@ function createAuditMcpServer(collector, onRecommendation) {
4522
4790
  return { content: [{ type: "text", text: result }] };
4523
4791
  }
4524
4792
  ),
4525
- tool4(
4793
+ tool5(
4526
4794
  "recommend_rename_tag",
4527
4795
  "Recommend renaming a tag",
4528
4796
  {
4529
- tagId: z4.string(),
4530
- tagName: z4.string().describe("Current tag name"),
4531
- newName: z4.string().describe("Proposed new name"),
4532
- reasoning: z4.string()
4797
+ tagId: z5.string(),
4798
+ tagName: z5.string().describe("Current tag name"),
4799
+ newName: z5.string().describe("Proposed new name"),
4800
+ reasoning: z5.string()
4533
4801
  },
4534
4802
  async (args) => {
4535
4803
  const result = collectRecommendation(
@@ -4541,10 +4809,10 @@ function createAuditMcpServer(collector, onRecommendation) {
4541
4809
  return { content: [{ type: "text", text: result }] };
4542
4810
  }
4543
4811
  ),
4544
- tool4(
4812
+ tool5(
4545
4813
  "complete_audit",
4546
4814
  "Signal that the audit is complete with a summary of all findings",
4547
- { summary: z4.string().describe("Brief overview of all findings") },
4815
+ { summary: z5.string().describe("Brief overview of all findings") },
4548
4816
  async (args) => {
4549
4817
  collector.complete = true;
4550
4818
  collector.summary = args.summary ?? "Audit completed.";
@@ -4552,7 +4820,7 @@ function createAuditMcpServer(collector, onRecommendation) {
4552
4820
  }
4553
4821
  )
4554
4822
  ];
4555
- return createSdkMcpServer2({
4823
+ return createSdkMcpServer3({
4556
4824
  name: "tag-audit",
4557
4825
  tools: auditTools
4558
4826
  });
@@ -4674,7 +4942,7 @@ async function runAuditQuery(request, connection, projectDir) {
4674
4942
  allowDangerouslySkipPermissions: true,
4675
4943
  tools: { type: "preset", preset: "claude_code" },
4676
4944
  mcpServers: { "tag-audit": createAuditMcpServer(collector, onRecommendation) },
4677
- maxTurns: settings.maxTurns ?? 30,
4945
+ maxTurns: settings.maxTurns ?? 75,
4678
4946
  maxBudgetUsd: settings.maxBudgetUsd ?? 5,
4679
4947
  effort: settings.effort,
4680
4948
  thinking: settings.thinking
@@ -4803,6 +5071,7 @@ var ProjectRunner = class {
4803
5071
  heartbeatTimer = null;
4804
5072
  stopping = false;
4805
5073
  resolveLifecycle = null;
5074
+ chatSessionIds = /* @__PURE__ */ new Map();
4806
5075
  // Start command process management
4807
5076
  startCommandChild = null;
4808
5077
  startCommandRunning = false;
@@ -5157,7 +5426,15 @@ var ProjectRunner = class {
5157
5426
  });
5158
5427
  this.connection.onChatMessage((msg) => {
5159
5428
  logger6.debug("Received project chat message");
5160
- void handleProjectChatMessage(msg, this.connection, this.projectDir);
5429
+ const chatId = msg.chatId ?? "default";
5430
+ const existingSessionId = this.chatSessionIds.get(chatId);
5431
+ void handleProjectChatMessage(msg, this.connection, this.projectDir, existingSessionId).then(
5432
+ (newSessionId) => {
5433
+ if (newSessionId) {
5434
+ this.chatSessionIds.set(chatId, newSessionId);
5435
+ }
5436
+ }
5437
+ );
5161
5438
  });
5162
5439
  this.connection.onAuditRequest((request) => {
5163
5440
  logger6.debug("Received tag audit request", { requestId: request.requestId });
@@ -5388,4 +5665,4 @@ export {
5388
5665
  ProjectRunner,
5389
5666
  FileCache
5390
5667
  };
5391
- //# sourceMappingURL=chunk-LBEAK2VJ.js.map
5668
+ //# sourceMappingURL=chunk-SQJJL2PU.js.map