@rallycry/conveyor-agent 4.0.0 → 4.0.1

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.
@@ -82,13 +82,13 @@ var ConveyorConnection = class _ConveyorConnection {
82
82
  });
83
83
  });
84
84
  }
85
- fetchChatMessages(limit) {
85
+ fetchChatMessages(limit, taskId) {
86
86
  const socket = this.socket;
87
87
  if (!socket) throw new Error("Not connected");
88
88
  return new Promise((resolve2, reject) => {
89
89
  socket.emit(
90
90
  "agentRunner:getChatMessages",
91
- { limit },
91
+ { limit, taskId },
92
92
  (response) => {
93
93
  if (response.success && response.data) {
94
94
  resolve2(response.data);
@@ -339,6 +339,48 @@ var ConveyorConnection = class _ConveyorConnection {
339
339
  );
340
340
  });
341
341
  }
342
+ postChildChatMessage(childTaskId, content) {
343
+ const socket = this.socket;
344
+ if (!socket) throw new Error("Not connected");
345
+ return new Promise((resolve2, reject) => {
346
+ socket.emit(
347
+ "agentRunner:postChildChatMessage",
348
+ { childTaskId, content },
349
+ (response) => {
350
+ if (response.success) resolve2();
351
+ else reject(new Error(response.error ?? "Failed to post to child chat"));
352
+ }
353
+ );
354
+ });
355
+ }
356
+ updateChildStatus(childTaskId, status) {
357
+ const socket = this.socket;
358
+ if (!socket) throw new Error("Not connected");
359
+ return new Promise((resolve2, reject) => {
360
+ socket.emit(
361
+ "agentRunner:updateChildStatus",
362
+ { childTaskId, status },
363
+ (response) => {
364
+ if (response.success) resolve2();
365
+ else reject(new Error(response.error ?? "Failed to update child status"));
366
+ }
367
+ );
368
+ });
369
+ }
370
+ stopChildBuild(childTaskId) {
371
+ const socket = this.socket;
372
+ if (!socket) throw new Error("Not connected");
373
+ return new Promise((resolve2, reject) => {
374
+ socket.emit(
375
+ "agentRunner:stopChildBuild",
376
+ { childTaskId },
377
+ (response) => {
378
+ if (response.success) resolve2();
379
+ else reject(new Error(response.error ?? "Failed to stop child build"));
380
+ }
381
+ );
382
+ });
383
+ }
342
384
  fetchTask(slugOrId) {
343
385
  const socket = this.socket;
344
386
  if (!socket) throw new Error("Not connected");
@@ -1585,13 +1627,14 @@ function buildCommonTools(connection, config) {
1585
1627
  return [
1586
1628
  tool(
1587
1629
  "read_task_chat",
1588
- "Read recent messages from the task chat to see team feedback or instructions",
1630
+ "Read recent messages from a task chat. Omit task_id to read the current task's chat, or provide a child task ID to read a child's chat.",
1589
1631
  {
1590
- limit: z.number().optional().describe("Number of recent messages to fetch (default 20)")
1632
+ limit: z.number().optional().describe("Number of recent messages to fetch (default 20)"),
1633
+ task_id: z.string().optional().describe("Child task ID to read chat from. Omit to read the current task's chat.")
1591
1634
  },
1592
- async ({ limit }) => {
1635
+ async ({ limit, task_id }) => {
1593
1636
  try {
1594
- const messages = await connection.fetchChatMessages(limit);
1637
+ const messages = await connection.fetchChatMessages(limit, task_id);
1595
1638
  return textResult(JSON.stringify(messages, null, 2));
1596
1639
  } catch {
1597
1640
  return textResult(
@@ -1605,22 +1648,46 @@ function buildCommonTools(connection, config) {
1605
1648
  ),
1606
1649
  tool(
1607
1650
  "post_to_chat",
1608
- "Post a message to the task chat. Your normal replies already appear in chat \u2014 only use this for explicit out-of-band updates or posting to a different task's chat",
1609
- { message: z.string().describe("The message to post to the team") },
1610
- ({ message }) => {
1611
- connection.postChatMessage(message);
1612
- return Promise.resolve(textResult("Message posted to task chat."));
1651
+ "Post a message to a task chat. Your normal replies already appear in chat \u2014 only use this for explicit out-of-band updates or posting to a child task's chat.",
1652
+ {
1653
+ message: z.string().describe("The message to post to the team"),
1654
+ task_id: z.string().optional().describe("Child task ID to post to. Omit to post to the current task's chat.")
1655
+ },
1656
+ async ({ message, task_id }) => {
1657
+ try {
1658
+ if (task_id) {
1659
+ await connection.postChildChatMessage(task_id, message);
1660
+ return textResult(`Message posted to child task ${task_id} chat.`);
1661
+ }
1662
+ connection.postChatMessage(message);
1663
+ return textResult("Message posted to task chat.");
1664
+ } catch (error) {
1665
+ return textResult(
1666
+ `Failed to post message: ${error instanceof Error ? error.message : "Unknown error"}`
1667
+ );
1668
+ }
1613
1669
  }
1614
1670
  ),
1615
1671
  tool(
1616
1672
  "update_task_status",
1617
- "Update the task status on the Kanban board",
1673
+ "Update a task's status on the Kanban board. Omit task_id to update the current task, or provide a child task ID to update a child's status.",
1618
1674
  {
1619
- status: z.enum(["InProgress", "ReviewPR", "Complete"]).describe("The new status for the task")
1675
+ status: z.enum(["InProgress", "ReviewPR", "ReviewDev", "Complete"]).describe("The new status for the task"),
1676
+ task_id: z.string().optional().describe("Child task ID to update. Omit to update the current task.")
1620
1677
  },
1621
- ({ status }) => {
1622
- connection.updateStatus(status);
1623
- return Promise.resolve(textResult(`Task status updated to ${status}.`));
1678
+ async ({ status, task_id }) => {
1679
+ try {
1680
+ if (task_id) {
1681
+ await connection.updateChildStatus(task_id, status);
1682
+ return textResult(`Child task ${task_id} status updated to ${status}.`);
1683
+ }
1684
+ connection.updateStatus(status);
1685
+ return textResult(`Task status updated to ${status}.`);
1686
+ } catch (error) {
1687
+ return textResult(
1688
+ `Failed to update status: ${error instanceof Error ? error.message : "Unknown error"}`
1689
+ );
1690
+ }
1624
1691
  }
1625
1692
  ),
1626
1693
  tool(
@@ -1851,6 +1918,23 @@ function buildPmTools(connection, storyPoints, options) {
1851
1918
  }
1852
1919
  }
1853
1920
  ),
1921
+ tool2(
1922
+ "stop_child_build",
1923
+ "Stop a running cloud build for a child task. Sends a stop signal to the child agent.",
1924
+ {
1925
+ childTaskId: z2.string().describe("The child task ID whose build should be stopped")
1926
+ },
1927
+ async ({ childTaskId }) => {
1928
+ try {
1929
+ await connection.stopChildBuild(childTaskId);
1930
+ return textResult(`Stop signal sent to child task: ${childTaskId}`);
1931
+ } catch (error) {
1932
+ return textResult(
1933
+ `Failed to stop child build: ${error instanceof Error ? error.message : "Unknown error"}`
1934
+ );
1935
+ }
1936
+ }
1937
+ ),
1854
1938
  tool2(
1855
1939
  "approve_and_merge_pr",
1856
1940
  "Approve and merge a child task's pull request. Only succeeds if all CI/CD checks are passing. Returns an error if checks are pending (retry after waiting) or failed (investigate). The child task must be in ReviewPR status.",
@@ -2035,6 +2119,10 @@ function createConveyorMcpServer(connection, config, context) {
2035
2119
  });
2036
2120
  break;
2037
2121
  case "auto":
2122
+ modeTools = buildPmTools(connection, context?.storyPoints, {
2123
+ includePackTools: !!context?.isParentTask
2124
+ });
2125
+ break;
2038
2126
  case "discovery":
2039
2127
  case "help":
2040
2128
  modeTools = buildPmTools(connection, context?.storyPoints, { includePackTools: false });
@@ -2600,6 +2688,8 @@ var AgentRunner = class _AgentRunner {
2600
2688
  lastQueryModeRestart = false;
2601
2689
  deferredStartConfig = null;
2602
2690
  startCommandStarted = false;
2691
+ idleTimer = null;
2692
+ idleCheckInterval = null;
2603
2693
  static MAX_SETUP_LOG_LINES = 50;
2604
2694
  constructor(config, callbacks) {
2605
2695
  this.config = config;
@@ -2640,6 +2730,16 @@ var AgentRunner = class _AgentRunner {
2640
2730
  this.heartbeatTimer = null;
2641
2731
  }
2642
2732
  }
2733
+ clearIdleTimers() {
2734
+ if (this.idleTimer) {
2735
+ clearTimeout(this.idleTimer);
2736
+ this.idleTimer = null;
2737
+ }
2738
+ if (this.idleCheckInterval) {
2739
+ clearInterval(this.idleCheckInterval);
2740
+ this.idleCheckInterval = null;
2741
+ }
2742
+ }
2643
2743
  async start() {
2644
2744
  await this.setState("connecting");
2645
2745
  await this.connection.connect();
@@ -3000,17 +3100,17 @@ ${f.content}
3000
3100
  }
3001
3101
  }
3002
3102
  waitForMessage() {
3103
+ this.clearIdleTimers();
3003
3104
  return new Promise((resolve2) => {
3004
- const checkStopped = setInterval(() => {
3105
+ this.idleCheckInterval = setInterval(() => {
3005
3106
  if (this.stopped) {
3006
- clearInterval(checkStopped);
3007
- clearTimeout(idleTimer);
3107
+ this.clearIdleTimers();
3008
3108
  this.inputResolver = null;
3009
3109
  resolve2(null);
3010
3110
  }
3011
3111
  }, 1e3);
3012
- const idleTimer = setTimeout(() => {
3013
- clearInterval(checkStopped);
3112
+ this.idleTimer = setTimeout(() => {
3113
+ this.clearIdleTimers();
3014
3114
  this.inputResolver = null;
3015
3115
  console.log(
3016
3116
  `[conveyor-agent] Idle for ${IDLE_TIMEOUT_MS / 6e4} minutes \u2014 shutting down.`
@@ -3021,8 +3121,7 @@ ${f.content}
3021
3121
  resolve2(null);
3022
3122
  }, IDLE_TIMEOUT_MS);
3023
3123
  this.inputResolver = (msg) => {
3024
- clearInterval(checkStopped);
3025
- clearTimeout(idleTimer);
3124
+ this.clearIdleTimers();
3026
3125
  resolve2(msg);
3027
3126
  };
3028
3127
  });
@@ -3048,19 +3147,23 @@ ${f.content}
3048
3147
  parent_tool_use_id: null
3049
3148
  });
3050
3149
  yield makeUserMessage(initialPrompt);
3051
- while (!this.stopped) {
3052
- if (this.pendingMessages.length > 0) {
3053
- const next = this.pendingMessages.shift();
3054
- if (next) yield next;
3055
- continue;
3150
+ try {
3151
+ while (!this.stopped) {
3152
+ if (this.pendingMessages.length > 0) {
3153
+ const next = this.pendingMessages.shift();
3154
+ if (next) yield next;
3155
+ continue;
3156
+ }
3157
+ this.connection.emitStatus("waiting_for_input");
3158
+ await this.callbacks.onStatusChange("waiting_for_input");
3159
+ const msg = await this.waitForMessage();
3160
+ if (!msg) break;
3161
+ this.connection.emitStatus("running");
3162
+ await this.callbacks.onStatusChange("running");
3163
+ yield msg;
3056
3164
  }
3057
- this.connection.emitStatus("waiting_for_input");
3058
- await this.callbacks.onStatusChange("waiting_for_input");
3059
- const msg = await this.waitForMessage();
3060
- if (!msg) break;
3061
- this.connection.emitStatus("running");
3062
- await this.callbacks.onStatusChange("running");
3063
- yield msg;
3165
+ } finally {
3166
+ this.clearIdleTimers();
3064
3167
  }
3065
3168
  }
3066
3169
  asQueryHost() {
@@ -3121,6 +3224,7 @@ ${f.content}
3121
3224
  }
3122
3225
  stop() {
3123
3226
  this.stopped = true;
3227
+ this.clearIdleTimers();
3124
3228
  if (this.inputResolver) {
3125
3229
  this.inputResolver(null);
3126
3230
  this.inputResolver = null;
@@ -3553,4 +3657,4 @@ export {
3553
3657
  ProjectRunner,
3554
3658
  FileCache
3555
3659
  };
3556
- //# sourceMappingURL=chunk-Y4TAVPZV.js.map
3660
+ //# sourceMappingURL=chunk-Q2LN2YBW.js.map