@rallycry/conveyor-agent 7.3.8 → 7.3.9

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.
@@ -1395,6 +1395,8 @@ var DeleteSubtaskResponseSchema = z.object({
1395
1395
  });
1396
1396
  var RegisterProjectAgentResponseSchema = z.object({
1397
1397
  registered: z.boolean(),
1398
+ /** ProjectCodespaceSession id — used by the runner to filter targeted chat messages. */
1399
+ sessionId: z.string(),
1398
1400
  agentName: z.string(),
1399
1401
  agentInstructions: z.string(),
1400
1402
  model: z.string(),
@@ -1467,7 +1469,8 @@ var CreateProjectTaskRequestSchema = z2.object({
1467
1469
  title: z2.string().min(1),
1468
1470
  description: z2.string().optional(),
1469
1471
  plan: z2.string().optional(),
1470
- status: z2.string().optional()
1472
+ status: z2.string().optional(),
1473
+ requestingUserId: z2.string().optional()
1471
1474
  });
1472
1475
  var UpdateProjectTaskRequestSchema = z2.object({
1473
1476
  projectId: z2.string(),
@@ -1476,7 +1479,8 @@ var UpdateProjectTaskRequestSchema = z2.object({
1476
1479
  description: z2.string().optional(),
1477
1480
  plan: z2.string().optional(),
1478
1481
  status: z2.string().optional(),
1479
- assignedUserId: z2.string().nullish()
1482
+ assignedUserId: z2.string().nullish(),
1483
+ requestingUserId: z2.string().optional()
1480
1484
  });
1481
1485
  var ReportProjectAgentEventRequestSchema = z2.object({
1482
1486
  projectId: z2.string(),
@@ -1539,7 +1543,8 @@ var GetProjectCliHistoryRequestSchema = z2.object({
1539
1543
  var PostToProjectTaskChatRequestSchema = z2.object({
1540
1544
  projectId: z2.string(),
1541
1545
  taskId: z2.string(),
1542
- content: z2.string()
1546
+ content: z2.string(),
1547
+ requestingUserId: z2.string().optional()
1543
1548
  });
1544
1549
  var GetProjectTaskCliRequestSchema = z2.object({
1545
1550
  projectId: z2.string(),
@@ -1549,15 +1554,71 @@ var GetProjectTaskCliRequestSchema = z2.object({
1549
1554
  });
1550
1555
  var StartProjectBuildRequestSchema = z2.object({
1551
1556
  projectId: z2.string(),
1552
- taskId: z2.string()
1557
+ taskId: z2.string(),
1558
+ requestingUserId: z2.string().optional()
1553
1559
  });
1554
1560
  var StopProjectBuildRequestSchema = z2.object({
1555
1561
  projectId: z2.string(),
1556
- taskId: z2.string()
1562
+ taskId: z2.string(),
1563
+ requestingUserId: z2.string().optional()
1557
1564
  });
1558
1565
  var ApproveProjectMergePRRequestSchema = z2.object({
1559
1566
  projectId: z2.string(),
1560
- childTaskId: z2.string()
1567
+ childTaskId: z2.string(),
1568
+ requestingUserId: z2.string().optional()
1569
+ });
1570
+ var ListProjectSubtasksRequestSchema = z2.object({
1571
+ projectId: z2.string(),
1572
+ taskId: z2.string()
1573
+ });
1574
+ var CreateProjectSubtaskRequestSchema = z2.object({
1575
+ projectId: z2.string(),
1576
+ parentTaskId: z2.string(),
1577
+ title: z2.string().min(1),
1578
+ description: z2.string().optional(),
1579
+ plan: z2.string().optional(),
1580
+ ordinal: z2.number().int().nonnegative().optional(),
1581
+ storyPointValue: z2.number().int().positive().optional(),
1582
+ requestingUserId: z2.string().optional()
1583
+ });
1584
+ var UpdateProjectSubtaskRequestSchema = z2.object({
1585
+ projectId: z2.string(),
1586
+ subtaskId: z2.string(),
1587
+ title: z2.string().optional(),
1588
+ description: z2.string().optional(),
1589
+ plan: z2.string().optional(),
1590
+ status: z2.string().optional(),
1591
+ ordinal: z2.number().int().nonnegative().optional(),
1592
+ storyPointValue: z2.number().int().positive().optional(),
1593
+ requestingUserId: z2.string().optional()
1594
+ });
1595
+ var DeleteProjectSubtaskRequestSchema = z2.object({
1596
+ projectId: z2.string(),
1597
+ subtaskId: z2.string(),
1598
+ requestingUserId: z2.string().optional()
1599
+ });
1600
+ var GetProjectTaskChatRequestSchema = z2.object({
1601
+ projectId: z2.string(),
1602
+ taskId: z2.string(),
1603
+ limit: z2.number().int().positive().optional().default(20)
1604
+ });
1605
+ var AddProjectTaskDependencyRequestSchema = z2.object({
1606
+ projectId: z2.string(),
1607
+ taskId: z2.string(),
1608
+ dependsOnSlugOrId: z2.string(),
1609
+ requestingUserId: z2.string().optional()
1610
+ });
1611
+ var RemoveProjectTaskDependencyRequestSchema = z2.object({
1612
+ projectId: z2.string(),
1613
+ taskId: z2.string(),
1614
+ dependsOnSlugOrId: z2.string(),
1615
+ requestingUserId: z2.string().optional()
1616
+ });
1617
+ var VoteProjectSuggestionRequestSchema = z2.object({
1618
+ projectId: z2.string(),
1619
+ suggestionId: z2.string(),
1620
+ value: z2.union([z2.literal(1), z2.literal(-1)]),
1621
+ requestingUserId: z2.string().optional()
1561
1622
  });
1562
1623
  var StartTaskAuditRequestSchema = z3.object({
1563
1624
  projectId: z3.string(),
@@ -1577,7 +1638,8 @@ var CreateProjectSuggestionRequestSchema = z3.object({
1577
1638
  projectId: z3.string(),
1578
1639
  title: z3.string().min(1),
1579
1640
  description: z3.string().optional(),
1580
- tagNames: z3.array(z3.string()).optional()
1641
+ tagNames: z3.array(z3.string()).optional(),
1642
+ requestingUserId: z3.string().optional()
1581
1643
  });
1582
1644
  var ReportTaskAuditBatchCompleteRequestSchema = z3.object({
1583
1645
  projectId: z3.string(),
@@ -7706,158 +7768,645 @@ function runStartCommand(cmd, cwd, onOutput) {
7706
7768
  }
7707
7769
 
7708
7770
  // src/tools/project-tools.ts
7771
+ import { z as z14 } from "zod";
7772
+
7773
+ // src/tools/project-action-tools.ts
7709
7774
  import { z as z13 } from "zod";
7710
- function buildTaskListTools(connection) {
7775
+ var SP_DESCRIPTION3 = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)";
7776
+ function withRequestingUser(payload, getRequestingUserId) {
7777
+ const requestingUserId = getRequestingUserId();
7778
+ return requestingUserId ? { ...payload, requestingUserId } : payload;
7779
+ }
7780
+ function buildCreateTaskTool(connection, getRequestingUserId) {
7711
7781
  const projectId = connection.projectId;
7712
- return [
7713
- defineTool(
7714
- "list_tasks",
7715
- "List tasks in the project. Optionally filter by status or assignee.",
7716
- {
7717
- status: z13.string().optional().describe("Filter by task status"),
7718
- assigneeId: z13.string().optional().describe("Filter by assigned user ID"),
7719
- limit: z13.number().optional().describe("Max number of tasks to return (default 50)")
7720
- },
7721
- async (params) => {
7722
- try {
7723
- const tasks = await connection.call("listProjectTasks", { projectId, ...params });
7724
- return textResult(JSON.stringify(tasks, null, 2));
7725
- } catch (error) {
7726
- return textResult(
7727
- `Failed to list tasks: ${error instanceof Error ? error.message : "Unknown error"}`
7728
- );
7729
- }
7730
- },
7731
- { annotations: { readOnlyHint: true } }
7732
- ),
7733
- defineTool(
7734
- "get_project_task",
7735
- "Get detailed information about a task in this project (chat messages, child tasks, session). Project-runner scope.",
7736
- { task_id: z13.string().describe("The task ID to look up") },
7737
- async ({ task_id }) => {
7738
- try {
7739
- const task = await connection.call("getProjectTask", { projectId, taskId: task_id });
7740
- return textResult(JSON.stringify(task, null, 2));
7741
- } catch (error) {
7782
+ return defineTool(
7783
+ "create_task",
7784
+ "Create a new task in the project.",
7785
+ {
7786
+ title: z13.string().describe("Task title"),
7787
+ description: z13.string().optional().describe("Task description"),
7788
+ plan: z13.string().optional().describe("Implementation plan in markdown"),
7789
+ status: z13.string().optional().describe("Initial status (default: Planning)")
7790
+ },
7791
+ async (params) => {
7792
+ try {
7793
+ const result = await connection.call(
7794
+ "createProjectTask",
7795
+ withRequestingUser({ projectId, ...params }, getRequestingUserId)
7796
+ );
7797
+ return textResult(`Task created: ${result.slug} (ID: ${result.id})`);
7798
+ } catch (error) {
7799
+ return textResult(`Failed to create task: ${errorMessage(error)}`);
7800
+ }
7801
+ }
7802
+ );
7803
+ }
7804
+ function buildUpdateProjectTaskTool(connection, getRequestingUserId) {
7805
+ const projectId = connection.projectId;
7806
+ return defineTool(
7807
+ "update_project_task",
7808
+ "Update an existing task's title, description, plan, status, or assignee. Project-runner scope.",
7809
+ {
7810
+ task_id: z13.string().describe("The task ID to update"),
7811
+ title: z13.string().optional().describe("New title"),
7812
+ description: z13.string().optional().describe("New description"),
7813
+ plan: z13.string().optional().describe("New plan in markdown"),
7814
+ status: z13.string().optional().describe("New status"),
7815
+ assignedUserId: z13.string().nullable().optional().describe("Assign to user ID, or null to unassign")
7816
+ },
7817
+ async ({ task_id, ...fields }) => {
7818
+ try {
7819
+ await connection.call(
7820
+ "updateProjectTask",
7821
+ withRequestingUser({ projectId, taskId: task_id, ...fields }, getRequestingUserId)
7822
+ );
7823
+ return textResult("Task updated successfully.");
7824
+ } catch (error) {
7825
+ return textResult(`Failed to update task: ${errorMessage(error)}`);
7826
+ }
7827
+ }
7828
+ );
7829
+ }
7830
+ function buildUpdateTaskPlanTool(connection, getRequestingUserId) {
7831
+ const projectId = connection.projectId;
7832
+ return defineTool(
7833
+ "update_task_plan",
7834
+ "Save a plan or description to a task. Convenience wrapper around update_project_task for the common Plan-mode case.",
7835
+ {
7836
+ task_id: z13.string().describe("The task ID to update"),
7837
+ plan: z13.string().optional().describe("The task plan in markdown"),
7838
+ description: z13.string().optional().describe("Updated task description")
7839
+ },
7840
+ async ({ task_id, plan, description }) => {
7841
+ try {
7842
+ await connection.call(
7843
+ "updateProjectTask",
7844
+ withRequestingUser(
7845
+ {
7846
+ projectId,
7847
+ taskId: task_id,
7848
+ ...plan !== void 0 && { plan },
7849
+ ...description !== void 0 && { description }
7850
+ },
7851
+ getRequestingUserId
7852
+ )
7853
+ );
7854
+ return textResult("Task updated successfully.");
7855
+ } catch (error) {
7856
+ return textResult(`Failed to update task: ${errorMessage(error)}`);
7857
+ }
7858
+ }
7859
+ );
7860
+ }
7861
+ function buildForceUpdateStatusTool(connection, getRequestingUserId) {
7862
+ const projectId = connection.projectId;
7863
+ return defineTool(
7864
+ "force_update_task_status",
7865
+ "EMERGENCY ONLY: force-override a task's Kanban status. Use when an automatic transition failed and the task is wedged. Normal flow transitions status automatically.",
7866
+ {
7867
+ task_id: z13.string().describe("The task ID to update"),
7868
+ status: z13.enum(["Planning", "Open", "InProgress", "ReviewPR", "ReviewDev", "ReviewLive", "Complete"]).describe("The new status for the task")
7869
+ },
7870
+ async ({ task_id, status }) => {
7871
+ try {
7872
+ await connection.call(
7873
+ "updateProjectTask",
7874
+ withRequestingUser({ projectId, taskId: task_id, status }, getRequestingUserId)
7875
+ );
7876
+ return textResult(`Task status updated to ${status}.`);
7877
+ } catch (error) {
7878
+ return textResult(`Failed to update status: ${errorMessage(error)}`);
7879
+ }
7880
+ }
7881
+ );
7882
+ }
7883
+ function buildCreateSubtaskTool2(connection, getRequestingUserId) {
7884
+ const projectId = connection.projectId;
7885
+ return defineTool(
7886
+ "create_subtask",
7887
+ "Create a subtask under a parent task in this project. Use for breaking parent tasks into smaller pieces during planning.",
7888
+ {
7889
+ parent_task_id: z13.string().describe("The parent task ID"),
7890
+ title: z13.string().describe("Subtask title"),
7891
+ description: z13.string().optional().describe("Brief description"),
7892
+ plan: z13.string().optional().describe("Implementation plan in markdown"),
7893
+ ordinal: z13.number().optional().describe("Step/order number (0-based)"),
7894
+ storyPointValue: z13.number().optional().describe(SP_DESCRIPTION3)
7895
+ },
7896
+ async ({ parent_task_id, title, description, plan, ordinal, storyPointValue }) => {
7897
+ try {
7898
+ const result = await connection.call(
7899
+ "createProjectSubtask",
7900
+ withRequestingUser(
7901
+ {
7902
+ projectId,
7903
+ parentTaskId: parent_task_id,
7904
+ title,
7905
+ ...description !== void 0 && { description },
7906
+ ...plan !== void 0 && { plan },
7907
+ ...ordinal !== void 0 && { ordinal },
7908
+ ...storyPointValue !== void 0 && { storyPointValue }
7909
+ },
7910
+ getRequestingUserId
7911
+ )
7912
+ );
7913
+ return textResult(`Subtask created: ${result.slug} (ID: ${result.id})`);
7914
+ } catch (error) {
7915
+ return textResult(`Failed to create subtask: ${errorMessage(error)}`);
7916
+ }
7917
+ }
7918
+ );
7919
+ }
7920
+ function buildUpdateSubtaskTool2(connection, getRequestingUserId) {
7921
+ const projectId = connection.projectId;
7922
+ return defineTool(
7923
+ "update_subtask",
7924
+ "Update an existing subtask's fields (title, description, plan, status, ordinal, storyPointValue).",
7925
+ {
7926
+ subtask_id: z13.string().describe("The subtask ID to update"),
7927
+ title: z13.string().optional(),
7928
+ description: z13.string().optional(),
7929
+ plan: z13.string().optional(),
7930
+ status: z13.string().optional(),
7931
+ ordinal: z13.number().optional(),
7932
+ storyPointValue: z13.number().optional().describe(SP_DESCRIPTION3)
7933
+ },
7934
+ async ({ subtask_id, ...fields }) => {
7935
+ try {
7936
+ await connection.call(
7937
+ "updateProjectSubtask",
7938
+ withRequestingUser({ projectId, subtaskId: subtask_id, ...fields }, getRequestingUserId)
7939
+ );
7940
+ return textResult("Subtask updated.");
7941
+ } catch (error) {
7942
+ return textResult(`Failed: ${errorMessage(error)}`);
7943
+ }
7944
+ }
7945
+ );
7946
+ }
7947
+ function buildDeleteSubtaskTool2(connection, getRequestingUserId) {
7948
+ const projectId = connection.projectId;
7949
+ return defineTool(
7950
+ "delete_subtask",
7951
+ "Delete a subtask by id. Use when a subtask was created in error or is no longer needed.",
7952
+ { subtask_id: z13.string().describe("The subtask ID to delete") },
7953
+ async ({ subtask_id }) => {
7954
+ try {
7955
+ await connection.call(
7956
+ "deleteProjectSubtask",
7957
+ withRequestingUser({ projectId, subtaskId: subtask_id }, getRequestingUserId)
7958
+ );
7959
+ return textResult("Subtask deleted.");
7960
+ } catch (error) {
7961
+ return textResult(`Failed: ${errorMessage(error)}`);
7962
+ }
7963
+ }
7964
+ );
7965
+ }
7966
+ function buildStartTaskTool(connection, getRequestingUserId) {
7967
+ const projectId = connection.projectId;
7968
+ return defineTool(
7969
+ "start_task",
7970
+ "Start a cloud build (codespace) for a task. Preconditions: task has a story point value and an agent assigned.",
7971
+ { task_id: z13.string().describe("The task ID to start a build for") },
7972
+ async ({ task_id }) => {
7973
+ try {
7974
+ const result = await connection.call(
7975
+ "startProjectBuild",
7976
+ withRequestingUser({ projectId, taskId: task_id }, getRequestingUserId)
7977
+ );
7978
+ return textResult(
7979
+ `Cloud build started for task ${result.taskId} (status: ${result.status})`
7980
+ );
7981
+ } catch (error) {
7982
+ return textResult(`Failed to start task: ${errorMessage(error)}`);
7983
+ }
7984
+ }
7985
+ );
7986
+ }
7987
+ function buildStopTaskTool(connection, getRequestingUserId) {
7988
+ const projectId = connection.projectId;
7989
+ return defineTool(
7990
+ "stop_task",
7991
+ "Send a stop signal to a running task's cloud build. Not a force-kill \u2014 the agent may take a moment to wind down.",
7992
+ { task_id: z13.string().describe("The task ID whose build should be stopped") },
7993
+ async ({ task_id }) => {
7994
+ try {
7995
+ await connection.call(
7996
+ "stopProjectBuild",
7997
+ withRequestingUser({ projectId, taskId: task_id }, getRequestingUserId)
7998
+ );
7999
+ return textResult(`Stop signal sent for task ${task_id}.`);
8000
+ } catch (error) {
8001
+ return textResult(`Failed to stop task: ${errorMessage(error)}`);
8002
+ }
8003
+ }
8004
+ );
8005
+ }
8006
+ function buildMergePRTool(connection, getRequestingUserId) {
8007
+ const projectId = connection.projectId;
8008
+ return defineTool(
8009
+ "merge_pr",
8010
+ "Approve and merge a task's PR. Preconditions: task in ReviewPR with an open PR. Returns { merged }: false means automerge queued \u2014 wait for status to flip to ReviewDev.",
8011
+ { task_id: z13.string().describe("The task ID whose PR should be approved and merged") },
8012
+ async ({ task_id }) => {
8013
+ try {
8014
+ const result = await connection.call(
8015
+ "approveProjectMergePR",
8016
+ withRequestingUser({ projectId, childTaskId: task_id }, getRequestingUserId)
8017
+ );
8018
+ if (result.merged) {
7742
8019
  return textResult(
7743
- `Failed to get task: ${error instanceof Error ? error.message : "Unknown error"}`
8020
+ `PR #${result.prNumber} approved and merged for task ${result.childTaskId}.`
7744
8021
  );
7745
8022
  }
7746
- },
7747
- { annotations: { readOnlyHint: true } }
7748
- ),
7749
- defineTool(
7750
- "search_tasks",
7751
- "Search tasks by tags, text query, or status filters.",
7752
- {
7753
- tagNames: z13.array(z13.string()).optional().describe("Filter by tag names"),
7754
- searchQuery: z13.string().optional().describe("Text search in title/description"),
7755
- statusFilters: z13.array(z13.string()).optional().describe("Filter by statuses"),
7756
- limit: z13.number().optional().describe("Max results (default 20)")
7757
- },
7758
- async (params) => {
7759
- try {
7760
- const tasks = await connection.call("searchProjectTasks", { projectId, ...params });
7761
- return textResult(JSON.stringify(tasks, null, 2));
7762
- } catch (error) {
8023
+ return textResult(
8024
+ `PR #${result.prNumber} merge queued for task ${result.childTaskId}. The PR will auto-merge when checks pass \u2014 wait for status to flip to ReviewDev.`
8025
+ );
8026
+ } catch (error) {
8027
+ return textResult(`Failed to merge PR: ${errorMessage(error)}`);
8028
+ }
8029
+ }
8030
+ );
8031
+ }
8032
+ function buildCreateSuggestionTool2(connection, getRequestingUserId) {
8033
+ const projectId = connection.projectId;
8034
+ return defineTool(
8035
+ "create_suggestion",
8036
+ "Suggest a feature, improvement, rule, or idea for the project. Duplicates are deduped and your upvote is recorded.",
8037
+ {
8038
+ title: z13.string().describe("Short title for the suggestion"),
8039
+ description: z13.string().optional().describe("1-2 sentence description of what should change and why."),
8040
+ tag_names: z13.array(z13.string()).optional().describe("Tag names to categorize the suggestion")
8041
+ },
8042
+ async ({ title, description, tag_names }) => {
8043
+ try {
8044
+ const result = await connection.call(
8045
+ "createProjectSuggestion",
8046
+ withRequestingUser(
8047
+ {
8048
+ projectId,
8049
+ title,
8050
+ ...description !== void 0 && { description },
8051
+ ...tag_names !== void 0 && { tagNames: tag_names }
8052
+ },
8053
+ getRequestingUserId
8054
+ )
8055
+ );
8056
+ if (result.merged) {
7763
8057
  return textResult(
7764
- `Failed to search tasks: ${error instanceof Error ? error.message : "Unknown error"}`
8058
+ `Your suggestion was merged into an existing one (ID: ${result.mergedIntoId ?? result.id}). Your upvote has been recorded.`
7765
8059
  );
7766
8060
  }
7767
- },
7768
- { annotations: { readOnlyHint: true } }
7769
- )
7770
- ];
8061
+ return textResult(`Suggestion created (ID: ${result.id}).`);
8062
+ } catch (error) {
8063
+ return textResult(`Failed to create suggestion: ${errorMessage(error)}`);
8064
+ }
8065
+ }
8066
+ );
7771
8067
  }
7772
- function buildProjectInfoTools(connection) {
8068
+ function buildVoteSuggestionTool2(connection, getRequestingUserId) {
7773
8069
  const projectId = connection.projectId;
8070
+ return defineTool(
8071
+ "vote_suggestion",
8072
+ "Vote +1 or -1 on a project suggestion.",
8073
+ {
8074
+ suggestion_id: z13.string().describe("The suggestion ID to vote on"),
8075
+ value: z13.number().refine((v) => v === 1 || v === -1, { message: "Value must be 1 or -1" }).describe("+1 to upvote, -1 to downvote")
8076
+ },
8077
+ async ({ suggestion_id, value }) => {
8078
+ try {
8079
+ const result = await connection.call(
8080
+ "voteProjectSuggestion",
8081
+ withRequestingUser(
8082
+ {
8083
+ projectId,
8084
+ suggestionId: suggestion_id,
8085
+ value
8086
+ },
8087
+ getRequestingUserId
8088
+ )
8089
+ );
8090
+ return textResult(`Vote recorded. Current score: ${result.score}`);
8091
+ } catch (error) {
8092
+ return textResult(`Failed to vote: ${errorMessage(error)}`);
8093
+ }
8094
+ }
8095
+ );
8096
+ }
8097
+ function buildAddDependencyTool2(connection, getRequestingUserId) {
8098
+ const projectId = connection.projectId;
8099
+ return defineTool(
8100
+ "add_dependency",
8101
+ "Add a blocking dependency \u2014 a task cannot start until the named task is merged to dev.",
8102
+ {
8103
+ task_id: z13.string().describe("The task that should be blocked"),
8104
+ depends_on_slug_or_id: z13.string().describe("Slug or ID of the task this task depends on")
8105
+ },
8106
+ async ({ task_id, depends_on_slug_or_id }) => {
8107
+ try {
8108
+ await connection.call(
8109
+ "addProjectTaskDependency",
8110
+ withRequestingUser(
8111
+ {
8112
+ projectId,
8113
+ taskId: task_id,
8114
+ dependsOnSlugOrId: depends_on_slug_or_id
8115
+ },
8116
+ getRequestingUserId
8117
+ )
8118
+ );
8119
+ return textResult(
8120
+ `Dependency added: task ${task_id} now depends on "${depends_on_slug_or_id}"`
8121
+ );
8122
+ } catch (error) {
8123
+ return textResult(`Failed to add dependency: ${errorMessage(error)}`);
8124
+ }
8125
+ }
8126
+ );
8127
+ }
8128
+ function buildRemoveDependencyTool2(connection, getRequestingUserId) {
8129
+ const projectId = connection.projectId;
8130
+ return defineTool(
8131
+ "remove_dependency",
8132
+ "Remove a previously added dependency from a task.",
8133
+ {
8134
+ task_id: z13.string().describe("The task to update"),
8135
+ depends_on_slug_or_id: z13.string().describe("Slug or ID of the task to remove as dependency")
8136
+ },
8137
+ async ({ task_id, depends_on_slug_or_id }) => {
8138
+ try {
8139
+ await connection.call(
8140
+ "removeProjectTaskDependency",
8141
+ withRequestingUser(
8142
+ {
8143
+ projectId,
8144
+ taskId: task_id,
8145
+ dependsOnSlugOrId: depends_on_slug_or_id
8146
+ },
8147
+ getRequestingUserId
8148
+ )
8149
+ );
8150
+ return textResult("Dependency removed");
8151
+ } catch (error) {
8152
+ return textResult(`Failed to remove dependency: ${errorMessage(error)}`);
8153
+ }
8154
+ }
8155
+ );
8156
+ }
8157
+ function buildProjectActionTools(connection, getRequestingUserId = () => void 0) {
7774
8158
  return [
7775
- defineTool(
7776
- "list_tags",
7777
- "List all tags available in the project.",
7778
- {},
7779
- async () => {
7780
- try {
7781
- const tags = await connection.call("listProjectTags", { projectId });
7782
- return textResult(JSON.stringify(tags, null, 2));
7783
- } catch (error) {
7784
- return textResult(
7785
- `Failed to list tags: ${error instanceof Error ? error.message : "Unknown error"}`
7786
- );
7787
- }
7788
- },
7789
- { annotations: { readOnlyHint: true } }
7790
- ),
7791
- defineTool(
7792
- "get_project_summary",
7793
- "Get a summary of the project including task counts by status and active builds.",
7794
- {},
7795
- async () => {
7796
- try {
7797
- const summary = await connection.call("getProjectSummary", { projectId });
7798
- return textResult(JSON.stringify(summary, null, 2));
7799
- } catch (error) {
7800
- return textResult(
7801
- `Failed to get project summary: ${error instanceof Error ? error.message : "Unknown error"}`
7802
- );
7803
- }
7804
- },
7805
- { annotations: { readOnlyHint: true } }
7806
- )
8159
+ buildCreateTaskTool(connection, getRequestingUserId),
8160
+ buildUpdateProjectTaskTool(connection, getRequestingUserId),
8161
+ buildUpdateTaskPlanTool(connection, getRequestingUserId),
8162
+ buildForceUpdateStatusTool(connection, getRequestingUserId),
8163
+ buildCreateSubtaskTool2(connection, getRequestingUserId),
8164
+ buildUpdateSubtaskTool2(connection, getRequestingUserId),
8165
+ buildDeleteSubtaskTool2(connection, getRequestingUserId),
8166
+ buildStartTaskTool(connection, getRequestingUserId),
8167
+ buildStopTaskTool(connection, getRequestingUserId),
8168
+ buildMergePRTool(connection, getRequestingUserId),
8169
+ buildCreateSuggestionTool2(connection, getRequestingUserId),
8170
+ buildVoteSuggestionTool2(connection, getRequestingUserId),
8171
+ buildAddDependencyTool2(connection, getRequestingUserId),
8172
+ buildRemoveDependencyTool2(connection, getRequestingUserId)
7807
8173
  ];
7808
8174
  }
7809
- function buildMutationTools2(connection) {
8175
+
8176
+ // src/tools/project-tools.ts
8177
+ function errorMessage(error) {
8178
+ return error instanceof Error ? error.message : "Unknown error";
8179
+ }
8180
+ function buildListTasksTool(connection) {
7810
8181
  const projectId = connection.projectId;
7811
- return [
7812
- defineTool(
7813
- "create_task",
7814
- "Create a new task in the project.",
7815
- {
7816
- title: z13.string().describe("Task title"),
7817
- description: z13.string().optional().describe("Task description"),
7818
- plan: z13.string().optional().describe("Implementation plan in markdown"),
7819
- status: z13.string().optional().describe("Initial status (default: Planning)")
7820
- },
7821
- async (params) => {
7822
- try {
7823
- const result = await connection.call("createProjectTask", { projectId, ...params });
7824
- return textResult(`Task created: ${result.slug} (ID: ${result.id})`);
7825
- } catch (error) {
7826
- return textResult(
7827
- `Failed to create task: ${error instanceof Error ? error.message : "Unknown error"}`
7828
- );
7829
- }
8182
+ return defineTool(
8183
+ "list_tasks",
8184
+ "List tasks in the project. Optionally filter by status or assignee.",
8185
+ {
8186
+ status: z14.string().optional().describe("Filter by task status"),
8187
+ assigneeId: z14.string().optional().describe("Filter by assigned user ID"),
8188
+ limit: z14.number().optional().describe("Max number of tasks to return (default 50)")
8189
+ },
8190
+ async (params) => {
8191
+ try {
8192
+ const tasks = await connection.call("listProjectTasks", { projectId, ...params });
8193
+ return textResult(JSON.stringify(tasks, null, 2));
8194
+ } catch (error) {
8195
+ return textResult(`Failed to list tasks: ${errorMessage(error)}`);
7830
8196
  }
7831
- ),
7832
- defineTool(
7833
- "update_project_task",
7834
- "Update an existing task's title, description, plan, status, or assignee. Project-runner scope.",
7835
- {
7836
- task_id: z13.string().describe("The task ID to update"),
7837
- title: z13.string().optional().describe("New title"),
7838
- description: z13.string().optional().describe("New description"),
7839
- plan: z13.string().optional().describe("New plan in markdown"),
7840
- status: z13.string().optional().describe("New status"),
7841
- assignedUserId: z13.string().nullable().optional().describe("Assign to user ID, or null to unassign")
7842
- },
7843
- async ({ task_id, ...fields }) => {
7844
- try {
7845
- await connection.call("updateProjectTask", { projectId, taskId: task_id, ...fields });
7846
- return textResult("Task updated successfully.");
7847
- } catch (error) {
7848
- return textResult(
7849
- `Failed to update task: ${error instanceof Error ? error.message : "Unknown error"}`
7850
- );
8197
+ },
8198
+ { annotations: { readOnlyHint: true } }
8199
+ );
8200
+ }
8201
+ function buildGetProjectTaskTool(connection) {
8202
+ const projectId = connection.projectId;
8203
+ return defineTool(
8204
+ "get_project_task",
8205
+ "Get detailed information about a task in this project (chat messages, child tasks, session). Project-runner scope.",
8206
+ { task_id: z14.string().describe("The task ID to look up") },
8207
+ async ({ task_id }) => {
8208
+ try {
8209
+ const task = await connection.call("getProjectTask", { projectId, taskId: task_id });
8210
+ return textResult(JSON.stringify(task, null, 2));
8211
+ } catch (error) {
8212
+ return textResult(`Failed to get task: ${errorMessage(error)}`);
8213
+ }
8214
+ },
8215
+ { annotations: { readOnlyHint: true } }
8216
+ );
8217
+ }
8218
+ function buildSearchTasksTool(connection) {
8219
+ const projectId = connection.projectId;
8220
+ return defineTool(
8221
+ "search_tasks",
8222
+ "Search tasks by tags, text query, or status filters.",
8223
+ {
8224
+ tagNames: z14.array(z14.string()).optional().describe("Filter by tag names"),
8225
+ searchQuery: z14.string().optional().describe("Text search in title/description"),
8226
+ statusFilters: z14.array(z14.string()).optional().describe("Filter by statuses"),
8227
+ limit: z14.number().optional().describe("Max results (default 20)")
8228
+ },
8229
+ async (params) => {
8230
+ try {
8231
+ const tasks = await connection.call("searchProjectTasks", { projectId, ...params });
8232
+ return textResult(JSON.stringify(tasks, null, 2));
8233
+ } catch (error) {
8234
+ return textResult(`Failed to search tasks: ${errorMessage(error)}`);
8235
+ }
8236
+ },
8237
+ { annotations: { readOnlyHint: true } }
8238
+ );
8239
+ }
8240
+ function buildListSubtasksTool2(connection) {
8241
+ const projectId = connection.projectId;
8242
+ return defineTool(
8243
+ "list_subtasks",
8244
+ "List the immediate child tasks under a parent task. Use to coordinate subtask work \u2014 see status, ordering, and PR state.",
8245
+ { task_id: z14.string().describe("Parent task ID") },
8246
+ async ({ task_id }) => {
8247
+ try {
8248
+ const subtasks = await connection.call("listProjectSubtasks", {
8249
+ projectId,
8250
+ taskId: task_id
8251
+ });
8252
+ return textResult(JSON.stringify(subtasks, null, 2));
8253
+ } catch (error) {
8254
+ return textResult(`Failed to list subtasks: ${errorMessage(error)}`);
8255
+ }
8256
+ },
8257
+ { annotations: { readOnlyHint: true } }
8258
+ );
8259
+ }
8260
+ function buildListTagsTool(connection) {
8261
+ const projectId = connection.projectId;
8262
+ return defineTool(
8263
+ "list_tags",
8264
+ "List all tags available in the project.",
8265
+ {},
8266
+ async () => {
8267
+ try {
8268
+ const tags = await connection.call("listProjectTags", { projectId });
8269
+ return textResult(JSON.stringify(tags, null, 2));
8270
+ } catch (error) {
8271
+ return textResult(`Failed to list tags: ${errorMessage(error)}`);
8272
+ }
8273
+ },
8274
+ { annotations: { readOnlyHint: true } }
8275
+ );
8276
+ }
8277
+ function buildGetProjectSummaryTool(connection) {
8278
+ const projectId = connection.projectId;
8279
+ return defineTool(
8280
+ "get_project_summary",
8281
+ "Get a summary of the project including task counts by status and active builds.",
8282
+ {},
8283
+ async () => {
8284
+ try {
8285
+ const summary = await connection.call("getProjectSummary", { projectId });
8286
+ return textResult(JSON.stringify(summary, null, 2));
8287
+ } catch (error) {
8288
+ return textResult(`Failed to get project summary: ${errorMessage(error)}`);
8289
+ }
8290
+ },
8291
+ { annotations: { readOnlyHint: true } }
8292
+ );
8293
+ }
8294
+ function buildPostToChatTool2(connection, getRequestingUserId) {
8295
+ const projectId = connection.projectId;
8296
+ return defineTool(
8297
+ "post_to_chat",
8298
+ "Post an out-of-band message into a chat. Omit task_id to post into the project chat; pass task_id to post into a specific task's chat. Normal replies already appear in chat automatically.",
8299
+ {
8300
+ message: z14.string().describe("The message content to post"),
8301
+ task_id: z14.string().optional().describe("Task ID to post into a specific task's chat. Omit for the project chat.")
8302
+ },
8303
+ async ({ message, task_id }) => {
8304
+ try {
8305
+ const requestingUserId = getRequestingUserId();
8306
+ if (task_id) {
8307
+ await connection.call("postToProjectTaskChat", {
8308
+ projectId,
8309
+ taskId: task_id,
8310
+ content: message,
8311
+ ...requestingUserId ? { requestingUserId } : {}
8312
+ });
8313
+ return textResult(JSON.stringify({ posted: true, target: `task:${task_id}` }));
7851
8314
  }
8315
+ await connection.call("postProjectAgentMessage", { projectId, content: message });
8316
+ return textResult(JSON.stringify({ posted: true, target: "project" }));
8317
+ } catch (error) {
8318
+ return textResult(`Failed to post message: ${errorMessage(error)}`);
7852
8319
  }
7853
- )
7854
- ];
8320
+ }
8321
+ );
8322
+ }
8323
+ function buildReadChatHistoryTool(connection) {
8324
+ const projectId = connection.projectId;
8325
+ return defineTool(
8326
+ "read_chat_history",
8327
+ "Read recent messages from a chat. Omit chat_id to read the project chat; pass a chat_id to read a specific chat.",
8328
+ {
8329
+ chat_id: z14.string().optional().describe("Chat ID to read. Omit for the project chat."),
8330
+ limit: z14.number().optional().describe("Number of recent messages to fetch (default 50)")
8331
+ },
8332
+ async ({ chat_id, limit }) => {
8333
+ try {
8334
+ const messages = await connection.call("getProjectChatHistory", {
8335
+ projectId,
8336
+ ...chat_id !== void 0 && { chatId: chat_id },
8337
+ ...limit !== void 0 && { limit }
8338
+ });
8339
+ return textResult(JSON.stringify(messages, null, 2));
8340
+ } catch (error) {
8341
+ return textResult(`Failed to read chat history: ${errorMessage(error)}`);
8342
+ }
8343
+ },
8344
+ { annotations: { readOnlyHint: true } }
8345
+ );
8346
+ }
8347
+ function buildReadTaskChatTool2(connection) {
8348
+ const projectId = connection.projectId;
8349
+ return defineTool(
8350
+ "read_task_chat",
8351
+ "Read recent human/user chat messages for a specific task in this project. For agent execution logs use get_task_logs.",
8352
+ {
8353
+ task_id: z14.string().describe("The task ID whose chat to read"),
8354
+ limit: z14.number().optional().describe("Number of recent messages to fetch (default 20)")
8355
+ },
8356
+ async ({ task_id, limit }) => {
8357
+ try {
8358
+ const messages = await connection.call("getProjectTaskChat", {
8359
+ projectId,
8360
+ taskId: task_id,
8361
+ ...limit !== void 0 && { limit }
8362
+ });
8363
+ return textResult(JSON.stringify(messages, null, 2));
8364
+ } catch (error) {
8365
+ return textResult(`Failed to read task chat: ${errorMessage(error)}`);
8366
+ }
8367
+ },
8368
+ { annotations: { readOnlyHint: true } }
8369
+ );
7855
8370
  }
7856
- function buildProjectTools(connection) {
8371
+ function buildGetTaskLogsTool(connection) {
8372
+ const projectId = connection.projectId;
8373
+ return defineTool(
8374
+ "get_task_logs",
8375
+ "Read CLI execution logs for a task \u2014 agent reasoning, tool calls, and setup/dev-server output. For human chat use read_task_chat.",
8376
+ {
8377
+ task_id: z14.string().describe("Task ID to read logs from"),
8378
+ source: z14.enum(["agent", "application"]).optional().describe("Filter by log source. Omit for all logs."),
8379
+ limit: z14.number().optional().describe("Max number of log entries to return (default 50, max 500).")
8380
+ },
8381
+ async ({ task_id, source, limit }) => {
8382
+ try {
8383
+ const logs = await connection.call("getProjectTaskCli", {
8384
+ projectId,
8385
+ taskId: task_id,
8386
+ ...source !== void 0 && { source },
8387
+ ...limit !== void 0 && { limit }
8388
+ });
8389
+ return textResult(JSON.stringify(logs, null, 2));
8390
+ } catch (error) {
8391
+ return textResult(`Failed to fetch task logs: ${errorMessage(error)}`);
8392
+ }
8393
+ },
8394
+ { annotations: { readOnlyHint: true } }
8395
+ );
8396
+ }
8397
+ function buildProjectTools(connection, getRequestingUserId = () => void 0) {
7857
8398
  return [
7858
- ...buildTaskListTools(connection),
7859
- ...buildProjectInfoTools(connection),
7860
- ...buildMutationTools2(connection)
8399
+ buildListTasksTool(connection),
8400
+ buildGetProjectTaskTool(connection),
8401
+ buildSearchTasksTool(connection),
8402
+ buildListSubtasksTool2(connection),
8403
+ buildListTagsTool(connection),
8404
+ buildGetProjectSummaryTool(connection),
8405
+ buildPostToChatTool2(connection, getRequestingUserId),
8406
+ buildReadChatHistoryTool(connection),
8407
+ buildReadTaskChatTool2(connection),
8408
+ buildGetTaskLogsTool(connection),
8409
+ ...buildProjectActionTools(connection, getRequestingUserId)
7861
8410
  ];
7862
8411
  }
7863
8412
 
@@ -7923,13 +8472,13 @@ async function fetchContext(connection, chatId) {
7923
8472
  }
7924
8473
  return { agentCtx, chatHistory };
7925
8474
  }
7926
- function buildChatQueryOptions(agentCtx, projectDir, connection) {
8475
+ function buildChatQueryOptions(agentCtx, projectDir, connection, getRequestingUserId) {
7927
8476
  const model = agentCtx?.model || FALLBACK_MODEL;
7928
8477
  const settings = agentCtx?.agentSettings ?? {};
7929
8478
  const harness = createHarness();
7930
8479
  const mcpServer = harness.createMcpServer({
7931
8480
  name: "conveyor",
7932
- tools: buildProjectTools(connection)
8481
+ tools: buildProjectTools(connection, getRequestingUserId)
7933
8482
  });
7934
8483
  return {
7935
8484
  options: {
@@ -7998,7 +8547,13 @@ function emitResultCost(event, connection) {
7998
8547
  }
7999
8548
  async function runChatQuery(message, connection, projectDir, sessionId) {
8000
8549
  const { agentCtx, chatHistory } = await fetchContext(connection, message.chatId);
8001
- const { options, harness } = buildChatQueryOptions(agentCtx, projectDir, connection);
8550
+ const requestingUserId = message.userId;
8551
+ const { options, harness } = buildChatQueryOptions(
8552
+ agentCtx,
8553
+ projectDir,
8554
+ connection,
8555
+ () => requestingUserId
8556
+ );
8002
8557
  const prompt = buildPrompt(message, chatHistory);
8003
8558
  connection.emitStatus("busy");
8004
8559
  const events = harness.executeQuery({
@@ -8514,6 +9069,10 @@ var ProjectRunner = class {
8514
9069
  stopping = false;
8515
9070
  resolveLifecycle = null;
8516
9071
  chatSessionIds = /* @__PURE__ */ new Map();
9072
+ /** ProjectCodespaceSession id assigned at register time. Used to filter
9073
+ * targeted incoming chat messages so we only react to ones addressed
9074
+ * to this specific runner. */
9075
+ projectSessionId = null;
8517
9076
  startCmd = { child: null, running: false };
8518
9077
  setupComplete = false;
8519
9078
  branchSwitchCommand;
@@ -8553,6 +9112,7 @@ var ProjectRunner = class {
8553
9112
  projectId: this.connection.projectId,
8554
9113
  capabilities: ["task", "pm", "code-review", "audit"]
8555
9114
  });
9115
+ this.projectSessionId = registration.sessionId;
8556
9116
  this.branchSwitchCommand = registration.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
8557
9117
  logger10.info("Registered as project agent", { agentName: registration.agentName });
8558
9118
  try {
@@ -8659,6 +9219,9 @@ var ProjectRunner = class {
8659
9219
  );
8660
9220
  this.connection.onShutdown(() => void this.stop());
8661
9221
  this.connection.onChatMessage((msg) => {
9222
+ if (msg.targetSessionId && this.projectSessionId && msg.targetSessionId !== this.projectSessionId) {
9223
+ return;
9224
+ }
8662
9225
  const chatId = msg.chatId ?? "default";
8663
9226
  const existingSessionId = this.chatSessionIds.get(chatId);
8664
9227
  void handleProjectChatMessage(msg, this.connection, this.projectDir, existingSessionId).then(
@@ -8697,10 +9260,11 @@ var ProjectRunner = class {
8697
9260
  }
8698
9261
  async handleReconnect() {
8699
9262
  try {
8700
- await this.connection.call("registerProjectAgent", {
9263
+ const registration = await this.connection.call("registerProjectAgent", {
8701
9264
  projectId: this.connection.projectId,
8702
9265
  capabilities: ["task", "pm", "code-review", "audit"]
8703
9266
  });
9267
+ this.projectSessionId = registration.sessionId;
8704
9268
  this.connection.emitStatus(this.activeAgents.size > 0 ? "busy" : "idle");
8705
9269
  logger10.info("Re-registered after reconnect");
8706
9270
  } catch (error) {
@@ -8860,4 +9424,4 @@ export {
8860
9424
  buildSessionPreviewPorts,
8861
9425
  loadConveyorConfig
8862
9426
  };
8863
- //# sourceMappingURL=chunk-RX7NQCWK.js.map
9427
+ //# sourceMappingURL=chunk-Y6IHF32X.js.map