@rallycry/conveyor-agent 5.11.1 → 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.
@@ -640,13 +640,13 @@ var ProjectConnection = class {
640
640
  );
641
641
  });
642
642
  }
643
- fetchChatHistory(limit) {
643
+ fetchChatHistory(limit, chatId) {
644
644
  const socket = this.socket;
645
645
  if (!socket) return Promise.reject(new Error("Not connected"));
646
646
  return new Promise((resolve2, reject) => {
647
647
  socket.emit(
648
648
  "projectRunner:getChatHistory",
649
- { limit },
649
+ { limit, chatId },
650
650
  (response) => {
651
651
  if (response.success && response.data) resolve2(response.data);
652
652
  else reject(new Error(response.error ?? "Failed to fetch chat history"));
@@ -654,6 +654,38 @@ var ProjectConnection = class {
654
654
  );
655
655
  });
656
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
+ }
657
689
  emitNewCommitsDetected(data) {
658
690
  if (!this.socket) return;
659
691
  this.socket.emit("projectRunner:newCommitsDetected", data);
@@ -4210,7 +4242,159 @@ var CommitWatcher = class {
4210
4242
  };
4211
4243
 
4212
4244
  // src/runner/project-chat-handler.ts
4213
- 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
4214
4398
  var logger4 = createServiceLogger("ProjectChat");
4215
4399
  var FALLBACK_MODEL = "claude-sonnet-4-20250514";
4216
4400
  function buildSystemPrompt2(projectDir, agentCtx) {
@@ -4267,7 +4451,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
4267
4451
  logger4.debug("Tool use", { tool: block.name });
4268
4452
  }
4269
4453
  }
4270
- async function fetchContext(connection) {
4454
+ async function fetchContext(connection, chatId) {
4271
4455
  let agentCtx = null;
4272
4456
  try {
4273
4457
  agentCtx = await connection.fetchAgentContext();
@@ -4276,15 +4460,19 @@ async function fetchContext(connection) {
4276
4460
  }
4277
4461
  let chatHistory = [];
4278
4462
  try {
4279
- chatHistory = await connection.fetchChatHistory(30);
4463
+ chatHistory = await connection.fetchChatHistory(30, chatId);
4280
4464
  } catch {
4281
4465
  logger4.warn("Could not fetch chat history, proceeding without it");
4282
4466
  }
4283
4467
  return { agentCtx, chatHistory };
4284
4468
  }
4285
- function buildChatQueryOptions(agentCtx, projectDir) {
4469
+ function buildChatQueryOptions(agentCtx, projectDir, connection) {
4286
4470
  const model = agentCtx?.model || FALLBACK_MODEL;
4287
4471
  const settings = agentCtx?.agentSettings ?? {};
4472
+ const mcpServer = createSdkMcpServer2({
4473
+ name: "conveyor",
4474
+ tools: buildProjectTools(connection)
4475
+ });
4288
4476
  return {
4289
4477
  model,
4290
4478
  systemPrompt: {
@@ -4296,8 +4484,9 @@ function buildChatQueryOptions(agentCtx, projectDir) {
4296
4484
  permissionMode: "bypassPermissions",
4297
4485
  allowDangerouslySkipPermissions: true,
4298
4486
  tools: { type: "preset", preset: "claude_code" },
4299
- maxTurns: settings.maxTurns ?? 15,
4300
- maxBudgetUsd: settings.maxBudgetUsd ?? 5,
4487
+ mcpServers: { conveyor: mcpServer },
4488
+ maxTurns: settings.maxTurns ?? 30,
4489
+ maxBudgetUsd: settings.maxBudgetUsd ?? 50,
4301
4490
  effort: settings.effort,
4302
4491
  thinking: settings.thinking
4303
4492
  };
@@ -4363,16 +4552,25 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
4363
4552
  }
4364
4553
  return false;
4365
4554
  }
4366
- async function runChatQuery(message, connection, projectDir) {
4367
- const { agentCtx, chatHistory } = await fetchContext(connection);
4368
- 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);
4369
4558
  const prompt = buildPrompt(message, chatHistory);
4370
4559
  connection.emitAgentStatus("running");
4371
- const events = query2({ prompt, options });
4560
+ const events = query2({
4561
+ prompt,
4562
+ options,
4563
+ ...sessionId ? { resume: sessionId } : {}
4564
+ });
4372
4565
  const responseParts = [];
4373
4566
  const turnToolCalls = [];
4374
4567
  const isTyping = { value: false };
4568
+ let resultSessionId;
4375
4569
  for await (const event of events) {
4570
+ if (event.type === "result") {
4571
+ const resultEvent = event;
4572
+ resultSessionId = resultEvent.sessionId;
4573
+ }
4376
4574
  const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
4377
4575
  if (done) break;
4378
4576
  }
@@ -4383,11 +4581,12 @@ async function runChatQuery(message, connection, projectDir) {
4383
4581
  if (responseText) {
4384
4582
  await connection.emitChatMessage(responseText);
4385
4583
  }
4584
+ return resultSessionId;
4386
4585
  }
4387
- async function handleProjectChatMessage(message, connection, projectDir) {
4586
+ async function handleProjectChatMessage(message, connection, projectDir, sessionId) {
4388
4587
  connection.emitAgentStatus("fetching_context");
4389
4588
  try {
4390
- await runChatQuery(message, connection, projectDir);
4589
+ return await runChatQuery(message, connection, projectDir, sessionId);
4391
4590
  } catch (error) {
4392
4591
  logger4.error("Failed to handle message", errorMeta(error));
4393
4592
  connection.emitAgentStatus("error");
@@ -4397,6 +4596,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
4397
4596
  );
4398
4597
  } catch {
4399
4598
  }
4599
+ return void 0;
4400
4600
  } finally {
4401
4601
  connection.emitAgentStatus("idle");
4402
4602
  }
@@ -4407,8 +4607,8 @@ import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
4407
4607
 
4408
4608
  // src/tools/audit-tools.ts
4409
4609
  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";
4610
+ import { tool as tool5, createSdkMcpServer as createSdkMcpServer3 } from "@anthropic-ai/claude-agent-sdk";
4611
+ import { z as z5 } from "zod";
4412
4612
  function mapCreateTag(input) {
4413
4613
  return {
4414
4614
  type: "create_tag",
@@ -4490,14 +4690,14 @@ function collectRecommendation(toolName, input, collector, onRecommendation) {
4490
4690
  }
4491
4691
  function createAuditMcpServer(collector, onRecommendation) {
4492
4692
  const auditTools = [
4493
- tool4(
4693
+ tool5(
4494
4694
  "recommend_create_tag",
4495
4695
  "Recommend creating a new tag for an uncovered subsystem or area",
4496
4696
  {
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")
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")
4501
4701
  },
4502
4702
  async (args) => {
4503
4703
  const result = collectRecommendation(
@@ -4509,14 +4709,14 @@ function createAuditMcpServer(collector, onRecommendation) {
4509
4709
  return { content: [{ type: "text", text: result }] };
4510
4710
  }
4511
4711
  ),
4512
- tool4(
4712
+ tool5(
4513
4713
  "recommend_update_description",
4514
4714
  "Recommend updating a tag's description to better reflect its scope",
4515
4715
  {
4516
- tagId: z4.string(),
4517
- tagName: z4.string(),
4518
- description: z4.string().describe("Proposed new description"),
4519
- reasoning: z4.string()
4716
+ tagId: z5.string(),
4717
+ tagName: z5.string(),
4718
+ description: z5.string().describe("Proposed new description"),
4719
+ reasoning: z5.string()
4520
4720
  },
4521
4721
  async (args) => {
4522
4722
  const result = collectRecommendation(
@@ -4528,16 +4728,16 @@ function createAuditMcpServer(collector, onRecommendation) {
4528
4728
  return { content: [{ type: "text", text: result }] };
4529
4729
  }
4530
4730
  ),
4531
- tool4(
4731
+ tool5(
4532
4732
  "recommend_context_link",
4533
4733
  "Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
4534
4734
  {
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()
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()
4541
4741
  },
4542
4742
  async (args) => {
4543
4743
  const result = collectRecommendation(
@@ -4549,16 +4749,16 @@ function createAuditMcpServer(collector, onRecommendation) {
4549
4749
  return { content: [{ type: "text", text: result }] };
4550
4750
  }
4551
4751
  ),
4552
- tool4(
4752
+ tool5(
4553
4753
  "flag_documentation_gap",
4554
4754
  "Flag a file that agents read heavily but has no tag documentation linked",
4555
4755
  {
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()
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()
4562
4762
  },
4563
4763
  async (args) => {
4564
4764
  const result = collectRecommendation(
@@ -4570,15 +4770,15 @@ function createAuditMcpServer(collector, onRecommendation) {
4570
4770
  return { content: [{ type: "text", text: result }] };
4571
4771
  }
4572
4772
  ),
4573
- tool4(
4773
+ tool5(
4574
4774
  "recommend_merge_tags",
4575
4775
  "Recommend merging one tag into another",
4576
4776
  {
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()
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()
4582
4782
  },
4583
4783
  async (args) => {
4584
4784
  const result = collectRecommendation(
@@ -4590,14 +4790,14 @@ function createAuditMcpServer(collector, onRecommendation) {
4590
4790
  return { content: [{ type: "text", text: result }] };
4591
4791
  }
4592
4792
  ),
4593
- tool4(
4793
+ tool5(
4594
4794
  "recommend_rename_tag",
4595
4795
  "Recommend renaming a tag",
4596
4796
  {
4597
- tagId: z4.string(),
4598
- tagName: z4.string().describe("Current tag name"),
4599
- newName: z4.string().describe("Proposed new name"),
4600
- 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()
4601
4801
  },
4602
4802
  async (args) => {
4603
4803
  const result = collectRecommendation(
@@ -4609,10 +4809,10 @@ function createAuditMcpServer(collector, onRecommendation) {
4609
4809
  return { content: [{ type: "text", text: result }] };
4610
4810
  }
4611
4811
  ),
4612
- tool4(
4812
+ tool5(
4613
4813
  "complete_audit",
4614
4814
  "Signal that the audit is complete with a summary of all findings",
4615
- { summary: z4.string().describe("Brief overview of all findings") },
4815
+ { summary: z5.string().describe("Brief overview of all findings") },
4616
4816
  async (args) => {
4617
4817
  collector.complete = true;
4618
4818
  collector.summary = args.summary ?? "Audit completed.";
@@ -4620,7 +4820,7 @@ function createAuditMcpServer(collector, onRecommendation) {
4620
4820
  }
4621
4821
  )
4622
4822
  ];
4623
- return createSdkMcpServer2({
4823
+ return createSdkMcpServer3({
4624
4824
  name: "tag-audit",
4625
4825
  tools: auditTools
4626
4826
  });
@@ -4871,6 +5071,7 @@ var ProjectRunner = class {
4871
5071
  heartbeatTimer = null;
4872
5072
  stopping = false;
4873
5073
  resolveLifecycle = null;
5074
+ chatSessionIds = /* @__PURE__ */ new Map();
4874
5075
  // Start command process management
4875
5076
  startCommandChild = null;
4876
5077
  startCommandRunning = false;
@@ -5225,7 +5426,15 @@ var ProjectRunner = class {
5225
5426
  });
5226
5427
  this.connection.onChatMessage((msg) => {
5227
5428
  logger6.debug("Received project chat message");
5228
- 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
+ );
5229
5438
  });
5230
5439
  this.connection.onAuditRequest((request) => {
5231
5440
  logger6.debug("Received tag audit request", { requestId: request.requestId });
@@ -5456,4 +5665,4 @@ export {
5456
5665
  ProjectRunner,
5457
5666
  FileCache
5458
5667
  };
5459
- //# sourceMappingURL=chunk-U3YWTVH3.js.map
5668
+ //# sourceMappingURL=chunk-SQJJL2PU.js.map