@rallycry/conveyor-agent 10.3.1 → 10.4.4
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.
- package/dist/{chunk-HAH2S5AD.js → chunk-VCXKVINO.js} +261 -177
- package/dist/chunk-VCXKVINO.js.map +1 -0
- package/dist/cli.js +146 -54
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/runtime/entrypoint.sh +68 -0
- package/dist/chunk-HAH2S5AD.js.map +0 -1
|
@@ -719,13 +719,16 @@ var AgentConnection = class _AgentConnection {
|
|
|
719
719
|
};
|
|
720
720
|
}
|
|
721
721
|
// ── Convenience methods (thin wrappers around call / emit) ─────────
|
|
722
|
-
async emitStatus(status, reason) {
|
|
722
|
+
async emitStatus(status, reason, questionText) {
|
|
723
723
|
this.lastEmittedStatus = status;
|
|
724
724
|
await this.flushEvents();
|
|
725
725
|
const payload = {
|
|
726
726
|
sessionId: this.config.sessionId,
|
|
727
727
|
status,
|
|
728
|
-
...reason ? { reason } : {}
|
|
728
|
+
...reason ? { reason } : {},
|
|
729
|
+
// Only sent with a pending TUI questionnaire (reason "user_question") so
|
|
730
|
+
// the server can surface the real question text in the notification.
|
|
731
|
+
...questionText ? { questionText } : {}
|
|
729
732
|
};
|
|
730
733
|
const AWAIT_STATUSES = ["idle", "waiting_for_input", "connected"];
|
|
731
734
|
if (AWAIT_STATUSES.includes(status)) {
|
|
@@ -2046,7 +2049,14 @@ var ReportAgentStatusRequestSchema = z.object({
|
|
|
2046
2049
|
sessionId: z.string(),
|
|
2047
2050
|
status: z.string(),
|
|
2048
2051
|
/** Why the agent reports this status (e.g. "user_question" while an AskUserQuestion questionnaire is pending in the TUI). */
|
|
2049
|
-
reason: z.string().optional()
|
|
2052
|
+
reason: z.string().optional(),
|
|
2053
|
+
/**
|
|
2054
|
+
* The pending question text, sent only alongside `reason: "user_question"`
|
|
2055
|
+
* so the server can surface it in the user-question notification body (and
|
|
2056
|
+
* thus the Attention feed) instead of a generic string. Optional: older
|
|
2057
|
+
* agents omit it and the server falls back to the generic wording.
|
|
2058
|
+
*/
|
|
2059
|
+
questionText: z.string().optional()
|
|
2050
2060
|
});
|
|
2051
2061
|
var NotifyAgentVersionRequestSchema = z.object({
|
|
2052
2062
|
sessionId: z.string(),
|
|
@@ -2069,7 +2079,10 @@ var CreateSubtaskRequestSchema = z.object({
|
|
|
2069
2079
|
plan: z.string().optional(),
|
|
2070
2080
|
storyPointValue: z.number().int().positive().optional(),
|
|
2071
2081
|
ordinal: z.number().int().nonnegative().optional(),
|
|
2072
|
-
followParentStatus: z.boolean().optional()
|
|
2082
|
+
followParentStatus: z.boolean().optional(),
|
|
2083
|
+
/** Sibling subtask ids or slugs this subtask blocks on (explicit dependency
|
|
2084
|
+
* metadata — preferred over encoding order in plan text / ordinal). */
|
|
2085
|
+
dependsOn: z.array(z.string().min(1)).max(32).optional()
|
|
2073
2086
|
});
|
|
2074
2087
|
var UpdateSubtaskRequestSchema = z.object({
|
|
2075
2088
|
sessionId: z.string(),
|
|
@@ -2079,7 +2092,10 @@ var UpdateSubtaskRequestSchema = z.object({
|
|
|
2079
2092
|
plan: z.string().optional(),
|
|
2080
2093
|
status: z.string().optional(),
|
|
2081
2094
|
storyPointValue: z.number().int().positive().optional(),
|
|
2082
|
-
followParentStatus: z.boolean().optional()
|
|
2095
|
+
followParentStatus: z.boolean().optional(),
|
|
2096
|
+
/** Replace this subtask's dependency edges with these sibling ids/slugs.
|
|
2097
|
+
* Empty array clears all. Omit to leave dependencies unchanged. */
|
|
2098
|
+
dependsOn: z.array(z.string().min(1)).max(32).optional()
|
|
2083
2099
|
});
|
|
2084
2100
|
var DeleteSubtaskRequestSchema = z.object({
|
|
2085
2101
|
sessionId: z.string(),
|
|
@@ -2500,6 +2516,9 @@ var CreateProjectSubtaskRequestSchema = z2.object({
|
|
|
2500
2516
|
ordinal: z2.number().int().nonnegative().optional(),
|
|
2501
2517
|
storyPointValue: z2.number().int().positive().optional(),
|
|
2502
2518
|
followParentStatus: z2.boolean().optional(),
|
|
2519
|
+
/** Sibling subtask ids or slugs this subtask blocks on (explicit dependency
|
|
2520
|
+
* metadata — preferred over encoding order in plan text / ordinal). */
|
|
2521
|
+
dependsOn: z2.array(z2.string().min(1)).max(32).optional(),
|
|
2503
2522
|
requestingUserId: z2.string().optional()
|
|
2504
2523
|
});
|
|
2505
2524
|
var UpdateProjectSubtaskRequestSchema = z2.object({
|
|
@@ -2962,7 +2981,8 @@ function defineTool(name, description, schema, handler, options) {
|
|
|
2962
2981
|
description,
|
|
2963
2982
|
schema,
|
|
2964
2983
|
handler,
|
|
2965
|
-
annotations: options?.annotations
|
|
2984
|
+
annotations: options?.annotations,
|
|
2985
|
+
strict: options?.strict
|
|
2966
2986
|
};
|
|
2967
2987
|
}
|
|
2968
2988
|
|
|
@@ -3759,6 +3779,7 @@ var PtyOutputCoalescer = class {
|
|
|
3759
3779
|
|
|
3760
3780
|
// src/harness/pty/tool-server.ts
|
|
3761
3781
|
import { createServer as createServer2 } from "http";
|
|
3782
|
+
import { z as z3 } from "zod";
|
|
3762
3783
|
import { writeFile as writeFile3 } from "fs/promises";
|
|
3763
3784
|
import { join as join2 } from "path";
|
|
3764
3785
|
import { randomBytes } from "crypto";
|
|
@@ -3813,9 +3834,14 @@ var PtyToolServer = class {
|
|
|
3813
3834
|
/** Fresh McpServer with every tool registered — one per MCP session. */
|
|
3814
3835
|
buildMcpServer() {
|
|
3815
3836
|
const mcp = new McpServer({ name: this.name, version: "1.0.0" });
|
|
3816
|
-
const register = mcp.
|
|
3837
|
+
const register = mcp.registerTool.bind(mcp);
|
|
3817
3838
|
for (const tool2 of this.tools) {
|
|
3818
|
-
|
|
3839
|
+
const inputSchema = tool2.strict ? z3.strictObject(tool2.schema) : tool2.schema;
|
|
3840
|
+
register(
|
|
3841
|
+
tool2.name,
|
|
3842
|
+
{ description: tool2.description, inputSchema },
|
|
3843
|
+
(args) => tool2.handler(args)
|
|
3844
|
+
);
|
|
3819
3845
|
}
|
|
3820
3846
|
return mcp;
|
|
3821
3847
|
}
|
|
@@ -3943,6 +3969,9 @@ async function startToolServers(mcpServers, tempDir) {
|
|
|
3943
3969
|
}
|
|
3944
3970
|
|
|
3945
3971
|
// src/harness/pty/spawn-args.ts
|
|
3972
|
+
function resolveClaudeBinary() {
|
|
3973
|
+
return process.env.CONVEYOR_CLAUDE_BIN ?? "claude";
|
|
3974
|
+
}
|
|
3946
3975
|
function buildSpawnArgs(input) {
|
|
3947
3976
|
const args = [];
|
|
3948
3977
|
if (input.resume) {
|
|
@@ -4232,9 +4261,9 @@ function extractSpawn(mod) {
|
|
|
4232
4261
|
}
|
|
4233
4262
|
async function loadPtySpawn() {
|
|
4234
4263
|
const mod = await import("node-pty");
|
|
4235
|
-
const
|
|
4236
|
-
if (!
|
|
4237
|
-
return
|
|
4264
|
+
const spawn3 = extractSpawn(mod);
|
|
4265
|
+
if (!spawn3) throw new Error("node-pty: spawn export not found");
|
|
4266
|
+
return spawn3;
|
|
4238
4267
|
}
|
|
4239
4268
|
function inheritedEnv(socketPath) {
|
|
4240
4269
|
const env = {};
|
|
@@ -4733,8 +4762,8 @@ var PtySession = class {
|
|
|
4733
4762
|
// server doesn't load).
|
|
4734
4763
|
...this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath } : {}
|
|
4735
4764
|
});
|
|
4736
|
-
const
|
|
4737
|
-
const pty =
|
|
4765
|
+
const spawn3 = await loadPtySpawn();
|
|
4766
|
+
const pty = spawn3(spec.file, spec.args, {
|
|
4738
4767
|
name: "xterm-color",
|
|
4739
4768
|
cols: this.cols,
|
|
4740
4769
|
rows: this.rows,
|
|
@@ -5188,7 +5217,7 @@ function buildPackRunnerSystemPrompt(context, config, setupLog) {
|
|
|
5188
5217
|
``,
|
|
5189
5218
|
`## Important Rules`,
|
|
5190
5219
|
`- When dependencies are set on children, use them to determine execution order. Fire all ready tasks in parallel (up to the PACK_CHILD_LIMIT backpressure \u2014 see the loop above).`,
|
|
5191
|
-
`- When NO dependencies are set on any children, fall back to ordinal order (one at a time)
|
|
5220
|
+
`- Dependencies are explicit card metadata (set at creation via create_subtask's dependsOn, or rewired with update_subtask). Prefer them over reading order out of plan text. When NO dependencies are set on any children, fall back to ordinal order (one at a time) \u2014 this is legacy behavior; set dependsOn when a child truly blocks on another.`,
|
|
5192
5221
|
`- After firing builds OR when waiting on CI, explicitly state you are going idle. Go idle when waiting \u2014 the system wakes you (or relaunches this environment) when a child changes status.`,
|
|
5193
5222
|
`- Do NOT attempt to write code yourself. Your role is coordination only.`,
|
|
5194
5223
|
`- If a child is stuck in "InProgress" for an unusually long time, use get_execution_logs(childTaskId) to check its logs and escalate to the team if it appears stuck.`,
|
|
@@ -5809,7 +5838,8 @@ function buildDiscoveryPrompt(context, runnerMode) {
|
|
|
5809
5838
|
`### Parent Task Coordination`,
|
|
5810
5839
|
`You are a parent task with child tasks. Focus on breaking work into child tasks with detailed plans, not planning implementation for yourself.`,
|
|
5811
5840
|
`- Use \`list_subtasks\` to review existing children. Create or update child tasks using \`create_subtask\` / \`update_subtask\`.`,
|
|
5812
|
-
`- Each child task should be a self-contained unit of work with a clear plan
|
|
5841
|
+
`- Each child task should be a self-contained unit of work with a clear plan.`,
|
|
5842
|
+
`- Set ordering as explicit **card metadata**, not prose: pass \`dependsOn\` (sibling ids/slugs) on \`create_subtask\` for any child that blocks on another. Leave independent children with no dependencies so the pack runner fans them out in parallel. Do NOT encode "do X after Y" only in the plan text \u2014 the runner schedules off dependsOn, not narrative.`
|
|
5813
5843
|
] : [
|
|
5814
5844
|
`### Self-Update vs Subtasks`,
|
|
5815
5845
|
`- If the work fits in a single task (1-3 SP), update YOUR OWN plan and properties \u2014 do not create subtasks`,
|
|
@@ -5823,6 +5853,7 @@ function buildDiscoveryPrompt(context, runnerMode) {
|
|
|
5823
5853
|
`- Reference existing implementations when relevant (e.g., "follow the pattern in src/services/foo.ts")`,
|
|
5824
5854
|
`- Include testing requirements and acceptance criteria`,
|
|
5825
5855
|
`- Set \`storyPointValue\` based on estimated complexity`,
|
|
5856
|
+
`- Express cross-child ordering as \`dependsOn\` (sibling ids/slugs) on \`create_subtask\` \u2014 explicit dependency metadata, not "after task 2" phrasing in the plan. Independent children get no dependencies so they run in parallel.`,
|
|
5826
5857
|
``,
|
|
5827
5858
|
`### Plan Verification Requirements`,
|
|
5828
5859
|
`Every plan MUST include a **Testing / Verification** section so the build agent has a clear definition of "done". Enumerate:`,
|
|
@@ -5869,6 +5900,7 @@ function buildAutoPrompt(context, runnerMode) {
|
|
|
5869
5900
|
`- Reference existing implementations when relevant`,
|
|
5870
5901
|
`- Include testing requirements and acceptance criteria`,
|
|
5871
5902
|
`- Set \`storyPointValue\` based on estimated complexity`,
|
|
5903
|
+
`- Express cross-child ordering as \`dependsOn\` (sibling ids/slugs) on \`create_subtask\` \u2014 explicit dependency metadata, not "after task 2" phrasing in the plan. Independent children get no dependencies so they run in parallel.`,
|
|
5872
5904
|
``,
|
|
5873
5905
|
...buildPlanCitationFormat(),
|
|
5874
5906
|
``,
|
|
@@ -5877,7 +5909,8 @@ function buildAutoPrompt(context, runnerMode) {
|
|
|
5877
5909
|
`### Parent Task Guidance`,
|
|
5878
5910
|
`You are a parent task. Your plan should define child tasks with detailed plans, not direct implementation steps.`,
|
|
5879
5911
|
`After ExitPlanMode, you'll transition to Review mode to coordinate child task execution.`,
|
|
5880
|
-
`Child task status lifecycle: Open \u2192 InProgress \u2192 ReviewPR \u2192 ReviewDev \u2192 Complete
|
|
5912
|
+
`Child task status lifecycle: Open \u2192 InProgress \u2192 ReviewPR \u2192 ReviewDev \u2192 Complete.`,
|
|
5913
|
+
`Set child ordering with \`dependsOn\` (sibling ids/slugs) on \`create_subtask\` \u2014 explicit metadata the pack runner schedules off, not order described in plan text. Independent children get none and run in parallel.`
|
|
5881
5914
|
] : [],
|
|
5882
5915
|
``,
|
|
5883
5916
|
`### Autonomous Guidelines:`,
|
|
@@ -6078,7 +6111,9 @@ Environment (fully ready \u2014 do NOT verify or set up):`,
|
|
|
6078
6111
|
`- All dependencies are installed, database is migrated, and the dev server is running.`,
|
|
6079
6112
|
`- Git is configured. Commit and push directly to this branch.`,
|
|
6080
6113
|
`- The shell cwd resets between Bash calls \u2014 always use absolute paths (or \`git -C\`, \`bun run --cwd\`); never spend a tool call on a bare \`cd\`.`,
|
|
6081
|
-
`- When a build/lint/test run fails, capture its output to a file once and grep the file \u2014 never re-run the suite just to re-filter the same output
|
|
6114
|
+
`- When a build/lint/test run fails, capture its output to a file once and grep the file \u2014 never re-run the suite just to re-filter the same output.`,
|
|
6115
|
+
`- Waiting on long-running commands: if a gate finishes in under ~2 minutes, run it in the foreground with a timeout. Anything longer: launch it with run_in_background and STOP \u2014 a completion notification arrives when it finishes. Never busy-wait with sleep/pgrep/tail loops (foreground shell commands are killed at ~2 minutes), and never re-run the suite to escape a wait that looks stalled.`,
|
|
6116
|
+
`- Deferred tools have no schema loaded until fetched \u2014 before first use, load it via ToolSearch (query "select:<ToolName>", e.g. "select:Monitor"); never guess a deferred tool's parameters.`,
|
|
6082
6117
|
`- The \`gh\` CLI may not be installed \u2014 use the mcp__conveyor__* tools for PR and task state.`,
|
|
6083
6118
|
`- Read a file before your first Write/Edit to it, and batch multiple changes to the same file into a single call instead of many sequential edits.`,
|
|
6084
6119
|
`
|
|
@@ -6508,7 +6543,7 @@ async function buildInitialPrompt(mode, context, isAuto, agentMode) {
|
|
|
6508
6543
|
}
|
|
6509
6544
|
|
|
6510
6545
|
// src/tools/task-context-tools.ts
|
|
6511
|
-
import { z as
|
|
6546
|
+
import { z as z4 } from "zod";
|
|
6512
6547
|
|
|
6513
6548
|
// src/tools/helpers.ts
|
|
6514
6549
|
function textResult(text) {
|
|
@@ -6542,8 +6577,8 @@ function buildReadTaskChatTool(connection) {
|
|
|
6542
6577
|
"read_task_chat",
|
|
6543
6578
|
"Read recent human/user chat messages for a task. Omit task_id for the current task; pass a child ID for a child's chat. For agent logs use get_execution_logs.",
|
|
6544
6579
|
{
|
|
6545
|
-
limit:
|
|
6546
|
-
task_id:
|
|
6580
|
+
limit: z4.number().optional().describe("Number of recent messages to fetch (default 20)"),
|
|
6581
|
+
task_id: z4.string().optional().describe("Child task ID to read chat from. Omit to read the current task's chat.")
|
|
6547
6582
|
},
|
|
6548
6583
|
async ({ limit, task_id }) => {
|
|
6549
6584
|
try {
|
|
@@ -6587,7 +6622,7 @@ function buildGetTaskTool(connection) {
|
|
|
6587
6622
|
"get_task",
|
|
6588
6623
|
"Look up any task by slug or ID. Returns JSON with id, slug, title, description, plan, status, branch, githubPRNumber, githubPRUrl, storyPoints. For children use list_subtasks.",
|
|
6589
6624
|
{
|
|
6590
|
-
slug_or_id:
|
|
6625
|
+
slug_or_id: z4.string().describe("The task slug (e.g. 'my-task') or CUID")
|
|
6591
6626
|
},
|
|
6592
6627
|
async ({ slug_or_id }) => {
|
|
6593
6628
|
try {
|
|
@@ -6610,9 +6645,9 @@ function buildGetExecutionLogsTool(connection) {
|
|
|
6610
6645
|
"get_execution_logs",
|
|
6611
6646
|
"Read CLI execution logs \u2014 agent reasoning, tool calls, and setup/dev-server output. Filter via source='agent' or 'application'. For human chat use read_task_chat.",
|
|
6612
6647
|
{
|
|
6613
|
-
task_id:
|
|
6614
|
-
source:
|
|
6615
|
-
limit:
|
|
6648
|
+
task_id: z4.string().optional().describe("Task ID or slug. Omit to read logs from the current task."),
|
|
6649
|
+
source: z4.enum(["agent", "application"]).optional().describe("Filter by log source. Omit for all logs."),
|
|
6650
|
+
limit: z4.number().optional().describe("Max number of log entries to return (default 50, max 500).")
|
|
6616
6651
|
},
|
|
6617
6652
|
async ({ task_id, source, limit }) => {
|
|
6618
6653
|
try {
|
|
@@ -6672,7 +6707,7 @@ function buildGetAttachmentTool(connection) {
|
|
|
6672
6707
|
return defineTool(
|
|
6673
6708
|
"get_attachment",
|
|
6674
6709
|
"Fetch one task file's content plus metadata by file ID. Call list_task_files first to discover IDs and check sizes \u2014 large binaries may be truncated by the service's size limit.",
|
|
6675
|
-
{ fileId:
|
|
6710
|
+
{ fileId: z4.string().describe("The file ID to retrieve") },
|
|
6676
6711
|
async ({ fileId }) => {
|
|
6677
6712
|
try {
|
|
6678
6713
|
const file = await connection.call("getTaskFile", {
|
|
@@ -6710,7 +6745,7 @@ function buildTaskContextTools(connection) {
|
|
|
6710
6745
|
}
|
|
6711
6746
|
|
|
6712
6747
|
// src/tools/dependency-suggestion-tools.ts
|
|
6713
|
-
import { z as
|
|
6748
|
+
import { z as z5 } from "zod";
|
|
6714
6749
|
function buildGetDependenciesTool(connection) {
|
|
6715
6750
|
return defineTool(
|
|
6716
6751
|
"get_dependencies",
|
|
@@ -6736,10 +6771,10 @@ function buildGetSuggestionsTool(connection) {
|
|
|
6736
6771
|
"get_suggestions",
|
|
6737
6772
|
"List project suggestions sorted by vote score. Filter by status or cap with limit (default 20). Suggestions are project-level ideas, not tasks \u2014 use get_task for tasks.",
|
|
6738
6773
|
{
|
|
6739
|
-
status:
|
|
6774
|
+
status: z5.string().optional().describe(
|
|
6740
6775
|
"Filter by status: Planning, Open, InProgress, ReviewPR, ReviewDev, ReviewLive, Complete, Cancelled"
|
|
6741
6776
|
),
|
|
6742
|
-
limit:
|
|
6777
|
+
limit: z5.number().int().min(1).max(100).optional().describe("Max results (default 20)")
|
|
6743
6778
|
},
|
|
6744
6779
|
async ({ status, limit }) => {
|
|
6745
6780
|
try {
|
|
@@ -6763,14 +6798,14 @@ function buildGetSuggestionsTool(connection) {
|
|
|
6763
6798
|
}
|
|
6764
6799
|
|
|
6765
6800
|
// src/tools/mutation-tools.ts
|
|
6766
|
-
import { z as
|
|
6801
|
+
import { z as z6 } from "zod";
|
|
6767
6802
|
function buildPostToChatTool(connection) {
|
|
6768
6803
|
return defineTool(
|
|
6769
6804
|
"post_to_chat",
|
|
6770
6805
|
"Post a message to the task chat for the team to see. Your turn output is NOT shown in chat, so this is the only way the team sees your status, summaries, and questions. Omit task_id to post to the current task's chat; pass a child's ID to message its chat.",
|
|
6771
6806
|
{
|
|
6772
|
-
message:
|
|
6773
|
-
task_id:
|
|
6807
|
+
message: z6.string().describe("The message to post to the team"),
|
|
6808
|
+
task_id: z6.string().optional().describe("Child task ID to post to. Omit to post to the current task's chat.")
|
|
6774
6809
|
},
|
|
6775
6810
|
async ({ message, task_id }) => {
|
|
6776
6811
|
try {
|
|
@@ -6808,8 +6843,8 @@ function buildForceUpdateTaskStatusTool(connection) {
|
|
|
6808
6843
|
"force_update_task_status",
|
|
6809
6844
|
"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.",
|
|
6810
6845
|
{
|
|
6811
|
-
status:
|
|
6812
|
-
task_id:
|
|
6846
|
+
status: z6.enum(["InProgress", "ReviewPR", "ReviewDev", "Complete"]).describe("The new status for the task"),
|
|
6847
|
+
task_id: z6.string().optional().describe("Child task ID to update. Omit to update the current task.")
|
|
6813
6848
|
},
|
|
6814
6849
|
async ({ status, task_id }) => {
|
|
6815
6850
|
try {
|
|
@@ -6840,18 +6875,18 @@ function buildCreatePullRequestTool(connection, config) {
|
|
|
6840
6875
|
"create_pull_request",
|
|
6841
6876
|
"Create a GitHub PR for this task. Auto-stages, commits (commitMessage or title default), pushes to origin, then opens the PR. Always use this instead of gh CLI or raw git.",
|
|
6842
6877
|
{
|
|
6843
|
-
title:
|
|
6844
|
-
body:
|
|
6845
|
-
branch:
|
|
6878
|
+
title: z6.string().describe("The PR title"),
|
|
6879
|
+
body: z6.string().describe("The PR description/body in markdown"),
|
|
6880
|
+
branch: z6.string().optional().describe(
|
|
6846
6881
|
"The head branch name for the PR. If the task doesn't have a branch set, this will be used. Defaults to the task's existing branch."
|
|
6847
6882
|
),
|
|
6848
|
-
baseBranch:
|
|
6883
|
+
baseBranch: z6.string().optional().describe(
|
|
6849
6884
|
"The base branch to target for the PR (e.g. 'main', 'develop'). Defaults to the project's configured dev branch."
|
|
6850
6885
|
),
|
|
6851
|
-
commitMessage:
|
|
6886
|
+
commitMessage: z6.string().optional().describe(
|
|
6852
6887
|
"Commit message for staging uncommitted changes. If not provided, a default message based on the PR title will be used."
|
|
6853
6888
|
),
|
|
6854
|
-
skipVerify:
|
|
6889
|
+
skipVerify: z6.boolean().optional().describe(
|
|
6855
6890
|
"Controls the local pre-push quality gate (lint/typecheck/test). Defaults to true (--no-verify): the push skips the local gate because you should run gates yourself before opening the PR and CI re-runs them on the resulting PR. Running the full gate synchronously during the push would block the agent's event loop long enough to drop the Conveyor socket connection. Pass false to force the local pre-push hook to run."
|
|
6856
6891
|
)
|
|
6857
6892
|
},
|
|
@@ -6933,7 +6968,7 @@ function buildAddDependencyTool(connection) {
|
|
|
6933
6968
|
"add_dependency",
|
|
6934
6969
|
"Add a blocking dependency \u2014 this task cannot start until the named task is merged to dev. For post-task follow-ups use create_follow_up_task instead.",
|
|
6935
6970
|
{
|
|
6936
|
-
depends_on_slug_or_id:
|
|
6971
|
+
depends_on_slug_or_id: z6.string().describe("Slug or ID of the task this task depends on")
|
|
6937
6972
|
},
|
|
6938
6973
|
async ({ depends_on_slug_or_id }) => {
|
|
6939
6974
|
try {
|
|
@@ -6955,7 +6990,7 @@ function buildRemoveDependencyTool(connection) {
|
|
|
6955
6990
|
"remove_dependency",
|
|
6956
6991
|
"Remove a previously added dependency from this task. When to use: the dependency was added in error or is no longer relevant. Returns: confirmation string.",
|
|
6957
6992
|
{
|
|
6958
|
-
depends_on_slug_or_id:
|
|
6993
|
+
depends_on_slug_or_id: z6.string().describe("Slug or ID of the task to remove as dependency")
|
|
6959
6994
|
},
|
|
6960
6995
|
async ({ depends_on_slug_or_id }) => {
|
|
6961
6996
|
try {
|
|
@@ -6977,10 +7012,10 @@ function buildCreateFollowUpTaskTool(connection) {
|
|
|
6977
7012
|
"create_follow_up_task",
|
|
6978
7013
|
"Create a follow-up task that depends on the current task. Use for out-of-scope work or cleanup that should land after this task merges. For blockers use add_dependency.",
|
|
6979
7014
|
{
|
|
6980
|
-
title:
|
|
6981
|
-
description:
|
|
6982
|
-
plan:
|
|
6983
|
-
story_point_value:
|
|
7015
|
+
title: z6.string().describe("Follow-up task title"),
|
|
7016
|
+
description: z6.string().optional().describe("Brief description of the follow-up work"),
|
|
7017
|
+
plan: z6.string().optional().describe("Implementation plan if known"),
|
|
7018
|
+
story_point_value: z6.number().optional().describe("Story point estimate (1=Common, 2=Magic, 3=Rare, 5=Unique)")
|
|
6984
7019
|
},
|
|
6985
7020
|
async ({ title, description, plan, story_point_value }) => {
|
|
6986
7021
|
try {
|
|
@@ -7007,11 +7042,11 @@ function buildCreateSuggestionTool(connection) {
|
|
|
7007
7042
|
"create_suggestion",
|
|
7008
7043
|
"Suggest a feature, improvement, rule, or idea for the project. Duplicates are deduped and your upvote is recorded. For actionable work on this task open a follow-up task.",
|
|
7009
7044
|
{
|
|
7010
|
-
title:
|
|
7011
|
-
description:
|
|
7045
|
+
title: z6.string().describe("Short title for the suggestion"),
|
|
7046
|
+
description: z6.string().optional().describe(
|
|
7012
7047
|
"1-2 sentence description of what should change and why. Keep concise and project-focused."
|
|
7013
7048
|
),
|
|
7014
|
-
tag_names:
|
|
7049
|
+
tag_names: z6.array(z6.string()).optional().describe("Tag names to categorize the suggestion")
|
|
7015
7050
|
},
|
|
7016
7051
|
async ({ title, description, tag_names }) => {
|
|
7017
7052
|
try {
|
|
@@ -7040,8 +7075,8 @@ function buildVoteSuggestionTool(connection) {
|
|
|
7040
7075
|
"vote_suggestion",
|
|
7041
7076
|
"Vote +1 or -1 on a project suggestion. Use to express support or disagreement with a specific suggestion returned by get_suggestions.",
|
|
7042
7077
|
{
|
|
7043
|
-
suggestion_id:
|
|
7044
|
-
value:
|
|
7078
|
+
suggestion_id: z6.string().describe("The suggestion ID to vote on"),
|
|
7079
|
+
value: z6.number().refine((v) => v === 1 || v === -1, { message: "Value must be 1 or -1" }).describe("+1 to upvote, -1 to downvote")
|
|
7045
7080
|
},
|
|
7046
7081
|
async ({ suggestion_id, value }) => {
|
|
7047
7082
|
try {
|
|
@@ -7074,7 +7109,7 @@ function buildMutationTools(connection, config) {
|
|
|
7074
7109
|
// src/tools/attachment-tools.ts
|
|
7075
7110
|
import { readFile as readFile3, stat as stat5 } from "fs/promises";
|
|
7076
7111
|
import { basename, extname, isAbsolute, join as join5 } from "path";
|
|
7077
|
-
import { z as
|
|
7112
|
+
import { z as z7 } from "zod";
|
|
7078
7113
|
var IMAGE_MIME_BY_EXT = {
|
|
7079
7114
|
".png": "image/png",
|
|
7080
7115
|
".jpg": "image/jpeg",
|
|
@@ -7087,8 +7122,8 @@ function buildUploadAttachmentTool(connection, config) {
|
|
|
7087
7122
|
"upload_attachment",
|
|
7088
7123
|
"Upload an image file (e.g. a Playwright screenshot) as a task attachment AND post it to the task chat in one step \u2014 no follow-up post_to_chat call needed. Supports png/jpg/gif/webp.",
|
|
7089
7124
|
{
|
|
7090
|
-
path:
|
|
7091
|
-
title:
|
|
7125
|
+
path: z7.string().describe("Path to the image file \u2014 absolute, or relative to the workspace root"),
|
|
7126
|
+
title: z7.string().optional().describe("Short caption posted with the image (defaults to the file name)")
|
|
7092
7127
|
},
|
|
7093
7128
|
async ({ path: path4, title }) => {
|
|
7094
7129
|
try {
|
|
@@ -7144,7 +7179,7 @@ function buildUploadAttachmentTool(connection, config) {
|
|
|
7144
7179
|
}
|
|
7145
7180
|
|
|
7146
7181
|
// src/tools/checklist-tools.ts
|
|
7147
|
-
import { z as
|
|
7182
|
+
import { z as z8 } from "zod";
|
|
7148
7183
|
function buildListManualTestsTool(connection) {
|
|
7149
7184
|
return defineTool(
|
|
7150
7185
|
"list_manual_tests",
|
|
@@ -7196,8 +7231,8 @@ function buildQueryManualTestsTool(connection) {
|
|
|
7196
7231
|
"query_manual_tests",
|
|
7197
7232
|
"Query manual tests across many tasks in this project, grouped by task. Filter by card status (ReviewDev, ReviewLive, Complete, ...) and/or test status (open | approved | rejected). Use to answer 'show all OPEN manual tests in ReviewDev' or 'show all REJECTED manual tests with the failing reason'. With no filters it defaults to the needs-attention view: open+rejected tests on ReviewDev/ReviewLive cards.",
|
|
7198
7233
|
{
|
|
7199
|
-
cardStatuses:
|
|
7200
|
-
testStatuses:
|
|
7234
|
+
cardStatuses: z8.array(z8.string()).optional().describe('Filter tasks by card status, e.g. ["ReviewDev", "ReviewLive"]'),
|
|
7235
|
+
testStatuses: z8.array(z8.enum(["open", "approved", "rejected"])).optional().describe("Filter tests by status: open | approved | rejected")
|
|
7201
7236
|
},
|
|
7202
7237
|
async ({ cardStatuses, testStatuses }) => {
|
|
7203
7238
|
try {
|
|
@@ -7221,7 +7256,7 @@ function buildSetManualTestsTool(connection) {
|
|
|
7221
7256
|
"set_manual_tests",
|
|
7222
7257
|
"Add manual test steps to the task checklist. Existing items with the same title are automatically skipped (deduplication). Use to record specific manual verification steps that reviewers should follow when testing this PR.",
|
|
7223
7258
|
{
|
|
7224
|
-
items:
|
|
7259
|
+
items: z8.array(z8.object({ title: z8.string().min(1).describe("A concise, actionable test step") })).min(1).describe("List of manual test steps to add")
|
|
7225
7260
|
},
|
|
7226
7261
|
async ({ items }) => {
|
|
7227
7262
|
try {
|
|
@@ -7244,8 +7279,8 @@ function buildEditManualTestTool(connection) {
|
|
|
7244
7279
|
"edit_manual_test",
|
|
7245
7280
|
"Rename an existing manual test step. Identify the test by its current title (case-insensitive); pass the new title to replace it. Use to correct or refine a recorded manual verification step.",
|
|
7246
7281
|
{
|
|
7247
|
-
title:
|
|
7248
|
-
newTitle:
|
|
7282
|
+
title: z8.string().min(1).describe("The current title of the manual test to edit"),
|
|
7283
|
+
newTitle: z8.string().min(1).describe("The new title for the manual test")
|
|
7249
7284
|
},
|
|
7250
7285
|
async ({ title, newTitle }) => {
|
|
7251
7286
|
try {
|
|
@@ -7267,7 +7302,7 @@ function buildRemoveManualTestTool(connection) {
|
|
|
7267
7302
|
"remove_manual_test",
|
|
7268
7303
|
"Remove an existing manual test step from the task checklist. Identify the test by its title (case-insensitive). Use to delete a stale or incorrect manual verification step.",
|
|
7269
7304
|
{
|
|
7270
|
-
title:
|
|
7305
|
+
title: z8.string().min(1).describe("The title of the manual test to remove")
|
|
7271
7306
|
},
|
|
7272
7307
|
async ({ title }) => {
|
|
7273
7308
|
try {
|
|
@@ -7288,7 +7323,7 @@ function buildApproveManualTestTool(connection) {
|
|
|
7288
7323
|
"approve_manual_test",
|
|
7289
7324
|
"Sign off on (approve) a manual test step on behalf of your authenticated user. Identify the test by its title (case-insensitive). Use after you have verified the step passes.",
|
|
7290
7325
|
{
|
|
7291
|
-
title:
|
|
7326
|
+
title: z8.string().min(1).describe("The title of the manual test to approve")
|
|
7292
7327
|
},
|
|
7293
7328
|
async ({ title }) => {
|
|
7294
7329
|
try {
|
|
@@ -7309,8 +7344,8 @@ function buildRejectManualTestTool(connection) {
|
|
|
7309
7344
|
"reject_manual_test",
|
|
7310
7345
|
"Flag an issue with (reject) a manual test step on behalf of your authenticated user, recording the reason. Identify the test by its title (case-insensitive). Use when the step fails verification.",
|
|
7311
7346
|
{
|
|
7312
|
-
title:
|
|
7313
|
-
reason:
|
|
7347
|
+
title: z8.string().min(1).describe("The title of the manual test to reject"),
|
|
7348
|
+
reason: z8.string().min(1).max(2e3).describe("Why the test failed \u2014 what went wrong, shown to the team")
|
|
7314
7349
|
},
|
|
7315
7350
|
async ({ title, reason }) => {
|
|
7316
7351
|
try {
|
|
@@ -7347,16 +7382,17 @@ function buildCommonTools(connection, config) {
|
|
|
7347
7382
|
}
|
|
7348
7383
|
|
|
7349
7384
|
// src/tools/pm-tools.ts
|
|
7350
|
-
import { z as
|
|
7385
|
+
import { z as z9 } from "zod";
|
|
7351
7386
|
var SP_DESCRIPTION = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)";
|
|
7352
7387
|
var FOLLOW_PARENT_STATUS_DESCRIPTION = "Child mirrors the parent task's status automatically \u2014 for subtasks that ship on the parent's branch/PR with no build or PR of their own. Manual status writes on a follower stick only until the parent's next transition.";
|
|
7388
|
+
var DEPENDS_ON_DESCRIPTION = "Sibling subtask ids or slugs this subtask blocks on (it won't start until they merge to dev). Set explicit dependency metadata here instead of describing order in the plan text \u2014 the pack runner schedules children off these edges. Omit / leave empty for independent children so they run in parallel.";
|
|
7353
7389
|
function buildUpdateTaskTool(connection) {
|
|
7354
7390
|
return defineTool(
|
|
7355
7391
|
"update_task_plan",
|
|
7356
7392
|
"Save the finalized plan and/or description to the current task. Use in Plan mode after alignment. For children use update_subtask; for title/tags/PR use update_task_properties.",
|
|
7357
7393
|
{
|
|
7358
|
-
plan:
|
|
7359
|
-
description:
|
|
7394
|
+
plan: z9.string().optional().describe("The task plan in markdown"),
|
|
7395
|
+
description: z9.string().optional().describe("Updated task description")
|
|
7360
7396
|
},
|
|
7361
7397
|
async ({ plan, description }) => {
|
|
7362
7398
|
try {
|
|
@@ -7377,14 +7413,23 @@ function buildCreateSubtaskTool(connection) {
|
|
|
7377
7413
|
"create_subtask",
|
|
7378
7414
|
"Create a subtask under the current parent task. Use when breaking a complex parent into smaller pieces during planning. For post-task follow-ups use create_follow_up_task.",
|
|
7379
7415
|
{
|
|
7380
|
-
title:
|
|
7381
|
-
description:
|
|
7382
|
-
plan:
|
|
7383
|
-
ordinal:
|
|
7384
|
-
storyPointValue:
|
|
7385
|
-
followParentStatus:
|
|
7416
|
+
title: z9.string().describe("Subtask title"),
|
|
7417
|
+
description: z9.string().optional().describe("Brief description"),
|
|
7418
|
+
plan: z9.string().optional().describe("Implementation plan in markdown"),
|
|
7419
|
+
ordinal: z9.number().optional().describe("Step/order number (0-based)"),
|
|
7420
|
+
storyPointValue: z9.number().optional().describe(SP_DESCRIPTION),
|
|
7421
|
+
followParentStatus: z9.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),
|
|
7422
|
+
dependsOn: z9.array(z9.string()).optional().describe(DEPENDS_ON_DESCRIPTION)
|
|
7386
7423
|
},
|
|
7387
|
-
async ({
|
|
7424
|
+
async ({
|
|
7425
|
+
title,
|
|
7426
|
+
description,
|
|
7427
|
+
plan,
|
|
7428
|
+
ordinal,
|
|
7429
|
+
storyPointValue,
|
|
7430
|
+
followParentStatus,
|
|
7431
|
+
dependsOn
|
|
7432
|
+
}) => {
|
|
7388
7433
|
try {
|
|
7389
7434
|
const result = await connection.call("createSubtask", {
|
|
7390
7435
|
sessionId: connection.sessionId,
|
|
@@ -7393,9 +7438,10 @@ function buildCreateSubtaskTool(connection) {
|
|
|
7393
7438
|
...plan !== void 0 && { plan },
|
|
7394
7439
|
...storyPointValue !== void 0 && { storyPointValue },
|
|
7395
7440
|
...ordinal !== void 0 && { ordinal },
|
|
7396
|
-
...followParentStatus !== void 0 && { followParentStatus }
|
|
7441
|
+
...followParentStatus !== void 0 && { followParentStatus },
|
|
7442
|
+
...dependsOn !== void 0 && { dependsOn }
|
|
7397
7443
|
});
|
|
7398
|
-
return textResult(`Subtask created with ID: ${result.id}`);
|
|
7444
|
+
return textResult(`Subtask created with ID: ${result.id} (slug: ${result.slug})`);
|
|
7399
7445
|
} catch (error) {
|
|
7400
7446
|
return textResult(
|
|
7401
7447
|
`Failed to create subtask: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
@@ -7407,17 +7453,28 @@ function buildCreateSubtaskTool(connection) {
|
|
|
7407
7453
|
function buildUpdateSubtaskTool(connection) {
|
|
7408
7454
|
return defineTool(
|
|
7409
7455
|
"update_subtask",
|
|
7410
|
-
"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue). Use when refining a child's plan or
|
|
7456
|
+
"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue, dependsOn). Use when refining a child's plan, reordering, or rewiring dependencies. For the current task use update_task_plan.",
|
|
7411
7457
|
{
|
|
7412
|
-
subtaskId:
|
|
7413
|
-
title:
|
|
7414
|
-
description:
|
|
7415
|
-
plan:
|
|
7416
|
-
ordinal:
|
|
7417
|
-
storyPointValue:
|
|
7418
|
-
followParentStatus:
|
|
7458
|
+
subtaskId: z9.string().describe("The subtask ID to update"),
|
|
7459
|
+
title: z9.string().optional(),
|
|
7460
|
+
description: z9.string().optional(),
|
|
7461
|
+
plan: z9.string().optional(),
|
|
7462
|
+
ordinal: z9.number().optional(),
|
|
7463
|
+
storyPointValue: z9.number().optional().describe(SP_DESCRIPTION),
|
|
7464
|
+
followParentStatus: z9.boolean().optional().describe(FOLLOW_PARENT_STATUS_DESCRIPTION),
|
|
7465
|
+
dependsOn: z9.array(z9.string()).optional().describe(
|
|
7466
|
+
`${DEPENDS_ON_DESCRIPTION} Replaces the full dependency set \u2014 pass [] to clear all, omit to leave unchanged.`
|
|
7467
|
+
)
|
|
7419
7468
|
},
|
|
7420
|
-
async ({
|
|
7469
|
+
async ({
|
|
7470
|
+
subtaskId,
|
|
7471
|
+
title,
|
|
7472
|
+
description,
|
|
7473
|
+
plan,
|
|
7474
|
+
storyPointValue,
|
|
7475
|
+
followParentStatus,
|
|
7476
|
+
dependsOn
|
|
7477
|
+
}) => {
|
|
7421
7478
|
try {
|
|
7422
7479
|
await connection.call("updateSubtask", {
|
|
7423
7480
|
sessionId: connection.sessionId,
|
|
@@ -7426,7 +7483,8 @@ function buildUpdateSubtaskTool(connection) {
|
|
|
7426
7483
|
...description !== void 0 && { description },
|
|
7427
7484
|
...plan !== void 0 && { plan },
|
|
7428
7485
|
...storyPointValue !== void 0 && { storyPointValue },
|
|
7429
|
-
...followParentStatus !== void 0 && { followParentStatus }
|
|
7486
|
+
...followParentStatus !== void 0 && { followParentStatus },
|
|
7487
|
+
...dependsOn !== void 0 && { dependsOn }
|
|
7430
7488
|
});
|
|
7431
7489
|
return textResult("Subtask updated.");
|
|
7432
7490
|
} catch (error) {
|
|
@@ -7439,7 +7497,7 @@ function buildDeleteSubtaskTool(connection) {
|
|
|
7439
7497
|
return defineTool(
|
|
7440
7498
|
"delete_subtask",
|
|
7441
7499
|
"Delete a subtask by id. When to use: a subtask was created in error or is no longer needed. Returns: confirmation string.",
|
|
7442
|
-
{ subtaskId:
|
|
7500
|
+
{ subtaskId: z9.string().describe("The subtask ID to delete") },
|
|
7443
7501
|
async ({ subtaskId }) => {
|
|
7444
7502
|
try {
|
|
7445
7503
|
await connection.call("deleteSubtask", {
|
|
@@ -7477,7 +7535,7 @@ function buildPackTools(connection) {
|
|
|
7477
7535
|
"start_child_cloud_build",
|
|
7478
7536
|
"Start a cloud build (codespace) for a child task. Preconditions: child is in Open status, has a story point value, and has an agent assigned.",
|
|
7479
7537
|
{
|
|
7480
|
-
childTaskId:
|
|
7538
|
+
childTaskId: z9.string().describe("The child task ID to start a cloud build for")
|
|
7481
7539
|
},
|
|
7482
7540
|
async ({ childTaskId }) => {
|
|
7483
7541
|
try {
|
|
@@ -7497,7 +7555,7 @@ function buildPackTools(connection) {
|
|
|
7497
7555
|
"stop_child_build",
|
|
7498
7556
|
"Send a graceful stop signal to a running child build's agent. Not a force-kill \u2014 the agent may take a moment to wind down.",
|
|
7499
7557
|
{
|
|
7500
|
-
childTaskId:
|
|
7558
|
+
childTaskId: z9.string().describe("The child task ID whose build should be stopped")
|
|
7501
7559
|
},
|
|
7502
7560
|
async ({ childTaskId }) => {
|
|
7503
7561
|
try {
|
|
@@ -7517,7 +7575,7 @@ function buildPackTools(connection) {
|
|
|
7517
7575
|
"approve_and_merge_pr",
|
|
7518
7576
|
"Approve and merge a child task's PR. Preconditions: child in ReviewPR. Returns { merged }: true = merged (status\u2192ReviewDev); false = automerge queued, wait for ReviewDev.",
|
|
7519
7577
|
{
|
|
7520
|
-
childTaskId:
|
|
7578
|
+
childTaskId: z9.string().describe("The child task ID whose PR should be approved and merged")
|
|
7521
7579
|
},
|
|
7522
7580
|
async ({ childTaskId }) => {
|
|
7523
7581
|
try {
|
|
@@ -7555,22 +7613,29 @@ function buildPmTools(connection, options) {
|
|
|
7555
7613
|
}
|
|
7556
7614
|
|
|
7557
7615
|
// src/tools/discovery-tools.ts
|
|
7558
|
-
import { z as
|
|
7559
|
-
var SP_DESCRIPTION2 = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)";
|
|
7616
|
+
import { z as z10 } from "zod";
|
|
7617
|
+
var SP_DESCRIPTION2 = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique). The key is 'storyPointValue' \u2014 not 'storyPoints'.";
|
|
7618
|
+
var VALID_PROPERTY_KEYS = "title, storyPointValue, tagNames, githubPRUrl, githubBranch";
|
|
7560
7619
|
function buildDiscoveryTools(connection) {
|
|
7561
7620
|
return [
|
|
7562
7621
|
defineTool(
|
|
7563
7622
|
"update_task_properties",
|
|
7564
|
-
"Set one or more task properties in a single call. All
|
|
7623
|
+
"Set one or more task properties in a single call. Valid keys: title, storyPointValue, tagNames, githubPRUrl, githubBranch. All are optional \u2014 include only the ones you want to update (at least one). Unknown keys are rejected.",
|
|
7565
7624
|
{
|
|
7566
|
-
title:
|
|
7567
|
-
storyPointValue:
|
|
7568
|
-
tagNames:
|
|
7569
|
-
githubPRUrl:
|
|
7570
|
-
githubBranch:
|
|
7625
|
+
title: z10.string().optional().describe("The new task title"),
|
|
7626
|
+
storyPointValue: z10.number().optional().describe(SP_DESCRIPTION2),
|
|
7627
|
+
tagNames: z10.array(z10.string()).optional().describe("Array of tag names to assign"),
|
|
7628
|
+
githubPRUrl: z10.string().url().optional().describe("GitHub pull request URL to link to this task"),
|
|
7629
|
+
githubBranch: z10.string().optional().describe("Set the GitHub branch name for this task (e.g. 'conveyor/my-feature-abc123')")
|
|
7571
7630
|
},
|
|
7572
7631
|
async ({ title, storyPointValue, tagNames, githubPRUrl, githubBranch }) => {
|
|
7573
7632
|
try {
|
|
7633
|
+
const nothingToUpdate = title === void 0 && storyPointValue === void 0 && tagNames === void 0 && githubPRUrl === void 0 && githubBranch === void 0;
|
|
7634
|
+
if (nothingToUpdate) {
|
|
7635
|
+
return textResult(
|
|
7636
|
+
`No task properties were updated: none of the recognized keys were provided. Valid keys: ${VALID_PROPERTY_KEYS}. (Story points are set via 'storyPointValue', not 'storyPoints'.)`
|
|
7637
|
+
);
|
|
7638
|
+
}
|
|
7574
7639
|
await connection.call("updateTaskProperties", {
|
|
7575
7640
|
sessionId: connection.sessionId,
|
|
7576
7641
|
title,
|
|
@@ -7592,13 +7657,17 @@ function buildDiscoveryTools(connection) {
|
|
|
7592
7657
|
`Failed to update task properties: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
7593
7658
|
);
|
|
7594
7659
|
}
|
|
7595
|
-
}
|
|
7660
|
+
},
|
|
7661
|
+
// Reject unknown keys (e.g. "storyPoints") at validation instead of
|
|
7662
|
+
// stripping them into a silent no-op — every field here is optional, so
|
|
7663
|
+
// a stripped typo would otherwise report success while updating nothing.
|
|
7664
|
+
{ strict: true }
|
|
7596
7665
|
)
|
|
7597
7666
|
];
|
|
7598
7667
|
}
|
|
7599
7668
|
|
|
7600
7669
|
// src/tools/code-review-tools.ts
|
|
7601
|
-
import { z as
|
|
7670
|
+
import { z as z11 } from "zod";
|
|
7602
7671
|
async function endReviewSession(connection, reason) {
|
|
7603
7672
|
await connection.call("endReviewSession", {
|
|
7604
7673
|
sessionId: connection.sessionId,
|
|
@@ -7611,7 +7680,7 @@ function buildCodeReviewTools(connection) {
|
|
|
7611
7680
|
"approve_code_review",
|
|
7612
7681
|
"Approve the code review and exit. Use when the diff passes all review criteria. Takes only a summary \u2014 for changes, use request_code_changes with a structured issues[] list.",
|
|
7613
7682
|
{
|
|
7614
|
-
summary:
|
|
7683
|
+
summary: z11.string().describe("Brief summary of what was reviewed and why it looks good")
|
|
7615
7684
|
},
|
|
7616
7685
|
async ({ summary }) => {
|
|
7617
7686
|
const content = `**Code Review: Approved** :white_check_mark:
|
|
@@ -7635,15 +7704,15 @@ ${summary}`;
|
|
|
7635
7704
|
"request_code_changes",
|
|
7636
7705
|
"Request changes during code review and exit. Use when substantive issues must be fixed before merge. Each issue: { file, line?, severity: critical|major|minor, description }.",
|
|
7637
7706
|
{
|
|
7638
|
-
issues:
|
|
7639
|
-
|
|
7640
|
-
file:
|
|
7641
|
-
line:
|
|
7642
|
-
severity:
|
|
7643
|
-
description:
|
|
7707
|
+
issues: z11.array(
|
|
7708
|
+
z11.object({
|
|
7709
|
+
file: z11.string().describe("File path where the issue was found"),
|
|
7710
|
+
line: z11.number().optional().describe("Line number (if applicable)"),
|
|
7711
|
+
severity: z11.enum(["critical", "major", "minor"]).describe("Issue severity"),
|
|
7712
|
+
description: z11.string().describe("What is wrong and how to fix it")
|
|
7644
7713
|
})
|
|
7645
7714
|
).describe("List of issues found during review"),
|
|
7646
|
-
summary:
|
|
7715
|
+
summary: z11.string().describe("Brief overall summary of the review findings")
|
|
7647
7716
|
},
|
|
7648
7717
|
async ({ issues, summary }) => {
|
|
7649
7718
|
const issueLines = issues.map((issue) => {
|
|
@@ -8020,9 +8089,17 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
|
|
|
8020
8089
|
function hasAskUserQuestionBlock(event) {
|
|
8021
8090
|
return event.message.content.some((b) => b.type === "tool_use" && b.name === "AskUserQuestion");
|
|
8022
8091
|
}
|
|
8023
|
-
|
|
8092
|
+
function questionTextFromEvent(event) {
|
|
8093
|
+
const text = event.questions.map((q) => q.question.trim()).filter((q) => q.length > 0).join("\n");
|
|
8094
|
+
return text.length > 0 ? text : void 0;
|
|
8095
|
+
}
|
|
8096
|
+
async function armQuestionPending(host, state, event) {
|
|
8024
8097
|
state.questionPending = true;
|
|
8025
|
-
await host.connection.emitStatus(
|
|
8098
|
+
await host.connection.emitStatus(
|
|
8099
|
+
"waiting_for_input",
|
|
8100
|
+
AGENT_STATUS_REASON_USER_QUESTION,
|
|
8101
|
+
questionTextFromEvent(event)
|
|
8102
|
+
);
|
|
8026
8103
|
await host.callbacks.onStatusChange("waiting_for_input");
|
|
8027
8104
|
}
|
|
8028
8105
|
async function clearQuestionPending(host, state, options) {
|
|
@@ -8036,7 +8113,7 @@ async function clearQuestionPending(host, state, options) {
|
|
|
8036
8113
|
async function applyQuestionTransitions(event, host, state) {
|
|
8037
8114
|
switch (event.type) {
|
|
8038
8115
|
case "user_question":
|
|
8039
|
-
await armQuestionPending(host, state);
|
|
8116
|
+
await armQuestionPending(host, state, event);
|
|
8040
8117
|
return;
|
|
8041
8118
|
case "assistant":
|
|
8042
8119
|
if (!hasAskUserQuestionBlock(event)) {
|
|
@@ -9473,74 +9550,77 @@ function readAgentVersion() {
|
|
|
9473
9550
|
return null;
|
|
9474
9551
|
}
|
|
9475
9552
|
|
|
9476
|
-
// src/
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
"seven_day_sonnet"
|
|
9485
|
-
];
|
|
9486
|
-
function normalizeUtilization(raw) {
|
|
9487
|
-
if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
|
|
9488
|
-
const fraction = raw > 1 ? raw / 100 : raw;
|
|
9489
|
-
return Math.max(0, Math.min(1, fraction));
|
|
9490
|
-
}
|
|
9491
|
-
function extractBucket(value) {
|
|
9492
|
-
if (typeof value === "number") {
|
|
9493
|
-
const utilization = normalizeUtilization(value);
|
|
9494
|
-
return utilization === null ? null : { utilization, status: "allowed" };
|
|
9495
|
-
}
|
|
9496
|
-
if (value && typeof value === "object") {
|
|
9497
|
-
const obj = value;
|
|
9498
|
-
const utilization = normalizeUtilization(
|
|
9499
|
-
obj.utilization ?? obj.used ?? obj.percent ?? obj.percentage
|
|
9500
|
-
);
|
|
9501
|
-
if (utilization === null) return null;
|
|
9502
|
-
const status = typeof obj.status === "string" ? obj.status : "allowed";
|
|
9503
|
-
return { utilization, status };
|
|
9504
|
-
}
|
|
9505
|
-
return null;
|
|
9553
|
+
// src/usage/parse-usage.ts
|
|
9554
|
+
function parseUsageGauges(stdout) {
|
|
9555
|
+
const session = stdout.match(/Current session:\s*(\d+(?:\.\d+)?)%\s*used/i);
|
|
9556
|
+
const weekly = [...stdout.matchAll(/Current week[^:\n]*:\s*(\d+(?:\.\d+)?)%\s*used/gi)];
|
|
9557
|
+
return {
|
|
9558
|
+
sessionUsage: session ? Number(session[1]) / 100 : null,
|
|
9559
|
+
weeklyUsage: weekly.length ? Math.max(...weekly.map((m) => Number(m[1]))) / 100 : null
|
|
9560
|
+
};
|
|
9506
9561
|
}
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9562
|
+
|
|
9563
|
+
// src/usage/run-probe.ts
|
|
9564
|
+
import { spawn } from "child_process";
|
|
9565
|
+
var PROBE_TIMEOUT_MS = 15e3;
|
|
9566
|
+
function runUsageProbe(binary = resolveClaudeBinary(), args = ["-p", "/usage"]) {
|
|
9567
|
+
return new Promise((resolve) => {
|
|
9568
|
+
let stdout = "";
|
|
9569
|
+
let settled = false;
|
|
9570
|
+
const finish = (out) => {
|
|
9571
|
+
if (settled) return;
|
|
9572
|
+
settled = true;
|
|
9573
|
+
resolve(out);
|
|
9574
|
+
};
|
|
9575
|
+
let child;
|
|
9576
|
+
try {
|
|
9577
|
+
child = spawn(binary, args, { stdio: ["ignore", "pipe", "ignore"] });
|
|
9578
|
+
} catch {
|
|
9579
|
+
finish("");
|
|
9580
|
+
return;
|
|
9522
9581
|
}
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9582
|
+
const timer = setTimeout(() => {
|
|
9583
|
+
try {
|
|
9584
|
+
child.kill("SIGKILL");
|
|
9585
|
+
} catch {
|
|
9586
|
+
}
|
|
9587
|
+
finish("");
|
|
9588
|
+
}, PROBE_TIMEOUT_MS);
|
|
9589
|
+
timer.unref?.();
|
|
9590
|
+
child.stdout?.on("data", (d) => {
|
|
9591
|
+
stdout += d.toString();
|
|
9592
|
+
});
|
|
9593
|
+
child.on("error", () => {
|
|
9594
|
+
clearTimeout(timer);
|
|
9595
|
+
finish("");
|
|
9596
|
+
});
|
|
9597
|
+
child.on("close", (code) => {
|
|
9598
|
+
clearTimeout(timer);
|
|
9599
|
+
finish(code === 0 ? stdout : "");
|
|
9600
|
+
});
|
|
9601
|
+
});
|
|
9526
9602
|
}
|
|
9527
|
-
|
|
9603
|
+
|
|
9604
|
+
// src/execution/usage-sampler.ts
|
|
9605
|
+
var logger4 = createServiceLogger("usage-sampler");
|
|
9606
|
+
async function sampleKeyUsage(token, probe = runUsageProbe) {
|
|
9528
9607
|
if (!token) return [];
|
|
9529
9608
|
try {
|
|
9530
|
-
const
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
}
|
|
9535
|
-
}
|
|
9536
|
-
if (
|
|
9537
|
-
|
|
9538
|
-
return [];
|
|
9609
|
+
const stdout = await probe();
|
|
9610
|
+
const { sessionUsage, weeklyUsage } = parseUsageGauges(stdout);
|
|
9611
|
+
const samples = [];
|
|
9612
|
+
if (sessionUsage !== null) {
|
|
9613
|
+
samples.push({ rateLimitType: "five_hour", utilization: sessionUsage, status: "allowed" });
|
|
9614
|
+
}
|
|
9615
|
+
if (weeklyUsage !== null) {
|
|
9616
|
+
samples.push({ rateLimitType: "seven_day", utilization: weeklyUsage, status: "allowed" });
|
|
9539
9617
|
}
|
|
9540
|
-
|
|
9541
|
-
|
|
9618
|
+
if (samples.length === 0) {
|
|
9619
|
+
logger4.info("usage sample produced no gauges", { stdoutLength: stdout.length });
|
|
9620
|
+
}
|
|
9621
|
+
return samples;
|
|
9542
9622
|
} catch (error) {
|
|
9543
|
-
logger4.info("
|
|
9623
|
+
logger4.info("usage sample failed", {
|
|
9544
9624
|
error: error instanceof Error ? error.message : String(error)
|
|
9545
9625
|
});
|
|
9546
9626
|
return [];
|
|
@@ -10060,7 +10140,11 @@ var SessionRunner = class _SessionRunner {
|
|
|
10060
10140
|
const staleBatch = [...this.pendingMessages];
|
|
10061
10141
|
const didExecuteInitialQuery = await this.executeInitialMode();
|
|
10062
10142
|
if (staleBatch.length > 0 && didExecuteInitialQuery) {
|
|
10143
|
+
const historyContents = new Set(
|
|
10144
|
+
(this.fullContext?.chatHistory ?? []).filter((m) => m.role !== "assistant" && m.content.trim()).map((m) => m.content.trim())
|
|
10145
|
+
);
|
|
10063
10146
|
for (const stale of staleBatch) {
|
|
10147
|
+
if (stale.content.trim() && !historyContents.has(stale.content.trim())) continue;
|
|
10064
10148
|
const idx = this.pendingMessages.indexOf(stale);
|
|
10065
10149
|
if (idx !== -1) this.pendingMessages.splice(idx, 1);
|
|
10066
10150
|
}
|
|
@@ -10417,8 +10501,8 @@ var SessionRunner = class _SessionRunner {
|
|
|
10417
10501
|
this.periodicFlushInFlight = false;
|
|
10418
10502
|
}
|
|
10419
10503
|
}
|
|
10420
|
-
/** Sample the running Claude subscription key's rate-limit utilization from
|
|
10421
|
-
*
|
|
10504
|
+
/** Sample the running Claude subscription key's rate-limit utilization from
|
|
10505
|
+
* the Claude CLI `/usage` command and report it as `rate_limit_update` events.
|
|
10422
10506
|
* The API (`persistRateLimitSnapshot`) attributes them to the key this session
|
|
10423
10507
|
* launched under, keeping User Settings + the PtY-tab usage widget fresh and
|
|
10424
10508
|
* `selectBestKey` rotation honest. Best-effort — never throws, no-op when the
|
|
@@ -10913,10 +10997,10 @@ function loadConveyorConfig() {
|
|
|
10913
10997
|
}
|
|
10914
10998
|
|
|
10915
10999
|
// src/setup/commands.ts
|
|
10916
|
-
import { spawn, execSync } from "child_process";
|
|
11000
|
+
import { spawn as spawn2, execSync } from "child_process";
|
|
10917
11001
|
function runSetupCommand(cmd, cwd, onOutput) {
|
|
10918
11002
|
return new Promise((resolve, reject) => {
|
|
10919
|
-
const child =
|
|
11003
|
+
const child = spawn2("sh", ["-c", cmd], {
|
|
10920
11004
|
cwd,
|
|
10921
11005
|
stdio: ["ignore", "pipe", "pipe"],
|
|
10922
11006
|
env: { ...process.env }
|
|
@@ -10955,7 +11039,7 @@ function runAuthTokenCommand(cmd, userEmail, cwd) {
|
|
|
10955
11039
|
}
|
|
10956
11040
|
}
|
|
10957
11041
|
function runStartCommand(cmd, cwd, onOutput) {
|
|
10958
|
-
const child =
|
|
11042
|
+
const child = spawn2("sh", ["-c", cmd], {
|
|
10959
11043
|
cwd,
|
|
10960
11044
|
stdio: ["ignore", "pipe", "pipe"],
|
|
10961
11045
|
detached: true,
|
|
@@ -11026,4 +11110,4 @@ export {
|
|
|
11026
11110
|
runStartCommand,
|
|
11027
11111
|
unshallowRepo
|
|
11028
11112
|
};
|
|
11029
|
-
//# sourceMappingURL=chunk-
|
|
11113
|
+
//# sourceMappingURL=chunk-VCXKVINO.js.map
|