@rallycry/conveyor-agent 7.3.1 → 7.3.3
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-2YHZHOR2.js → chunk-COJPX2QI.js} +202 -50
- package/dist/chunk-COJPX2QI.js.map +1 -0
- package/dist/cli.js +44 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2YHZHOR2.js.map +0 -1
|
@@ -411,12 +411,22 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
|
|
|
411
411
|
triggerIdentification() {
|
|
412
412
|
return this.call("triggerIdentification", { sessionId: this.config.sessionId });
|
|
413
413
|
}
|
|
414
|
+
getCumulativeSpending() {
|
|
415
|
+
return this.call("getCumulativeSpending", { sessionId: this.config.sessionId });
|
|
416
|
+
}
|
|
414
417
|
async refreshAuthToken() {
|
|
415
418
|
const codespaceName = process.env.CODESPACE_NAME || process.env.CLAUDESPACE_NAME;
|
|
416
419
|
const apiUrl = this.config.apiUrl;
|
|
417
420
|
if (!codespaceName || !apiUrl) return false;
|
|
418
421
|
try {
|
|
419
|
-
const
|
|
422
|
+
const bootstrapToken = process.env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
423
|
+
const headers = {};
|
|
424
|
+
if (bootstrapToken) {
|
|
425
|
+
headers["x-codespace-token"] = bootstrapToken;
|
|
426
|
+
}
|
|
427
|
+
const response = await fetch(`${apiUrl}/api/codespace/bootstrap/${codespaceName}`, {
|
|
428
|
+
headers
|
|
429
|
+
});
|
|
420
430
|
if (!response.ok) return false;
|
|
421
431
|
const config = await response.json();
|
|
422
432
|
if (config.envVars?.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
@@ -2253,7 +2263,7 @@ import { z } from "zod";
|
|
|
2253
2263
|
function buildReadTaskChatTool(connection) {
|
|
2254
2264
|
return defineTool(
|
|
2255
2265
|
"read_task_chat",
|
|
2256
|
-
"Read recent messages
|
|
2266
|
+
"Read recent human/user chat messages for a task. When to use: you need to see user instructions, questions, or feedback posted to the task chat. Omit task_id for the current task, or pass a child task ID to read a child's chat. When NOT to use: for agent reasoning, tool calls, or setup/dev-server output \u2014 use get_task_cli instead. Returns: JSON array of recent chat messages (default 20).",
|
|
2257
2267
|
{
|
|
2258
2268
|
limit: z.number().optional().describe("Number of recent messages to fetch (default 20)"),
|
|
2259
2269
|
task_id: z.string().optional().describe("Child task ID to read chat from. Omit to read the current task's chat.")
|
|
@@ -2280,7 +2290,7 @@ function buildReadTaskChatTool(connection) {
|
|
|
2280
2290
|
function buildGetTaskPlanTool(connection) {
|
|
2281
2291
|
return defineTool(
|
|
2282
2292
|
"get_task_plan",
|
|
2283
|
-
"Re-read the
|
|
2293
|
+
"Re-read the current task's plan. When to use: the user just said they updated the plan mid-session or explicitly asked you to re-read it. When NOT to use: to fetch general task info (title, status, description) \u2014 use get_task. The plan was already included in your initial context, so do not call this speculatively. Returns: the plan markdown string.",
|
|
2284
2294
|
{},
|
|
2285
2295
|
async () => {
|
|
2286
2296
|
try {
|
|
@@ -2298,7 +2308,7 @@ function buildGetTaskPlanTool(connection) {
|
|
|
2298
2308
|
function buildGetTaskTool(connection) {
|
|
2299
2309
|
return defineTool(
|
|
2300
2310
|
"get_task",
|
|
2301
|
-
"Look up
|
|
2311
|
+
"Look up any task by slug or ID. When to use: you need the current title, description, plan, status, branch, PR info, or story points for this or a related task. When NOT to use: to list child tasks (use list_subtasks), or to re-read only the current plan (use get_task_plan). Returns: JSON task object including id, slug, title, description, plan, status, branch, githubPRNumber, githubPRUrl, storyPointValue.",
|
|
2302
2312
|
{
|
|
2303
2313
|
slug_or_id: z.string().describe("The task slug (e.g. 'my-task') or CUID")
|
|
2304
2314
|
},
|
|
@@ -2321,7 +2331,7 @@ function buildGetTaskTool(connection) {
|
|
|
2321
2331
|
function buildGetTaskCliTool(connection) {
|
|
2322
2332
|
return defineTool(
|
|
2323
2333
|
"get_task_cli",
|
|
2324
|
-
"Read CLI execution logs from a task
|
|
2334
|
+
"Read CLI execution logs from a task \u2014 agent reasoning, tool calls, and setup/dev-server output. When to use: inspecting what another agent did, debugging build/setup output, or reviewing prior tool calls. Filter with source='agent' for reasoning and tool calls only, source='application' for setup/dev-server output only. When NOT to use: for human/user chat \u2014 use read_task_chat. Returns: newline-joined event log lines each prefixed with `[timestamp] [type]` and formatted content.",
|
|
2325
2335
|
{
|
|
2326
2336
|
task_id: z.string().optional().describe("Task ID or slug. Omit to read logs from the current task."),
|
|
2327
2337
|
source: z.enum(["agent", "application"]).optional().describe("Filter by log source. Omit for all logs."),
|
|
@@ -2354,7 +2364,7 @@ function buildGetTaskCliTool(connection) {
|
|
|
2354
2364
|
function buildListTaskFilesTool(connection) {
|
|
2355
2365
|
return defineTool(
|
|
2356
2366
|
"list_task_files",
|
|
2357
|
-
"List all files attached to this task with metadata (name,
|
|
2367
|
+
"List all files attached to this task with metadata. When to use: before fetching a specific file, to see what is available and how large each is. When NOT to use: to read a file's contents \u2014 use get_task_file. Returns: JSON array of file metadata (id, name, mimeType, size, downloadUrl), plus inline image blocks for any attached images.",
|
|
2358
2368
|
{},
|
|
2359
2369
|
async () => {
|
|
2360
2370
|
try {
|
|
@@ -2384,7 +2394,7 @@ function buildListTaskFilesTool(connection) {
|
|
|
2384
2394
|
function buildGetTaskFileTool(connection) {
|
|
2385
2395
|
return defineTool(
|
|
2386
2396
|
"get_task_file",
|
|
2387
|
-
"
|
|
2397
|
+
"Fetch one task file's content plus metadata by file ID. When to use: you have a file ID from list_task_files and need its content or download URL. Call list_task_files first to discover IDs and check sizes \u2014 large binaries may be truncated by the service's size limit. When NOT to use: to enumerate attachments \u2014 use list_task_files. Returns: JSON metadata; for images an inline image block is also returned, and text content is embedded inline when available.",
|
|
2388
2398
|
{ fileId: z.string().describe("The file ID to retrieve") },
|
|
2389
2399
|
async ({ fileId }) => {
|
|
2390
2400
|
try {
|
|
@@ -2427,7 +2437,7 @@ import { z as z2 } from "zod";
|
|
|
2427
2437
|
function buildGetDependenciesTool(connection) {
|
|
2428
2438
|
return defineTool(
|
|
2429
2439
|
"get_dependencies",
|
|
2430
|
-
"Get this task's dependencies and their current status (met
|
|
2440
|
+
"Get this task's dependencies and their current met/unmet status. When to use: confirming that blockers have been merged before starting work, or investigating why a task cannot start. When NOT to use: to look up a specific task's state \u2014 use get_task. Returns: JSON array of dependency objects (slug, title, status, and whether the dependency is met \u2014 met means merged to dev).",
|
|
2431
2441
|
{},
|
|
2432
2442
|
async () => {
|
|
2433
2443
|
try {
|
|
@@ -2447,15 +2457,19 @@ function buildGetDependenciesTool(connection) {
|
|
|
2447
2457
|
function buildGetSuggestionsTool(connection) {
|
|
2448
2458
|
return defineTool(
|
|
2449
2459
|
"get_suggestions",
|
|
2450
|
-
"List project suggestions sorted by vote score.
|
|
2460
|
+
"List project suggestions sorted by vote score. When to use: seeing what the team thinks is important, finding a suggestion to vote on, or checking for duplicates before create_suggestion. Filter by status (Planning, Open, InProgress, ReviewPR, ReviewDev, ReviewLive, Complete, Cancelled) or cap results with limit (default 20). When NOT to use: for task lists \u2014 suggestions are project-level idea records, not tasks. Returns: JSON array of suggestions with id, title, description, status, score.",
|
|
2451
2461
|
{
|
|
2452
|
-
status: z2.string().optional().describe(
|
|
2453
|
-
|
|
2462
|
+
status: z2.string().optional().describe(
|
|
2463
|
+
"Filter by status: Planning, Open, InProgress, ReviewPR, ReviewDev, ReviewLive, Complete, Cancelled"
|
|
2464
|
+
),
|
|
2465
|
+
limit: z2.number().int().min(1).max(100).optional().describe("Max results (default 20)")
|
|
2454
2466
|
},
|
|
2455
|
-
async ({ status
|
|
2467
|
+
async ({ status, limit }) => {
|
|
2456
2468
|
try {
|
|
2457
2469
|
const suggestions = await connection.call("getSuggestions", {
|
|
2458
|
-
sessionId: connection.sessionId
|
|
2470
|
+
sessionId: connection.sessionId,
|
|
2471
|
+
status,
|
|
2472
|
+
limit
|
|
2459
2473
|
});
|
|
2460
2474
|
if (suggestions.length === 0) {
|
|
2461
2475
|
return textResult("No suggestions found.");
|
|
@@ -2476,7 +2490,7 @@ import { z as z3 } from "zod";
|
|
|
2476
2490
|
function buildPostToChatTool(connection) {
|
|
2477
2491
|
return defineTool(
|
|
2478
2492
|
"post_to_chat",
|
|
2479
|
-
"Post
|
|
2493
|
+
"Post an out-of-band message to a task chat. When to use: the user explicitly asked for a status update that must appear in chat, or you need to message a child task's chat (pass its ID as task_id). When NOT to use: for normal responses \u2014 your regular replies already appear in the current task's chat automatically. Returns: confirmation string.",
|
|
2480
2494
|
{
|
|
2481
2495
|
message: z3.string().describe("The message to post to the team"),
|
|
2482
2496
|
task_id: z3.string().optional().describe("Child task ID to post to. Omit to post to the current task's chat.")
|
|
@@ -2504,7 +2518,7 @@ function buildPostToChatTool(connection) {
|
|
|
2504
2518
|
function buildForceUpdateTaskStatusTool(connection) {
|
|
2505
2519
|
return defineTool(
|
|
2506
2520
|
"force_update_task_status",
|
|
2507
|
-
"EMERGENCY ONLY:
|
|
2521
|
+
"EMERGENCY ONLY: force-override a task's Kanban status. When to use: an automatic transition failed and the task is wedged \u2014 e.g. a PR was merged but status did not advance to ReviewDev, a build completed but status is still InProgress with no session running, or a child is stuck in ReviewPR after its PR was closed. When NOT to use: in normal flow \u2014 building, PR creation, and merge each transition status automatically. Omit task_id for the current task; pass a child task ID to update a child. Returns: confirmation string.",
|
|
2508
2522
|
{
|
|
2509
2523
|
status: z3.enum(["InProgress", "ReviewPR", "ReviewDev", "Complete"]).describe("The new status for the task"),
|
|
2510
2524
|
task_id: z3.string().optional().describe("Child task ID to update. Omit to update the current task.")
|
|
@@ -2536,7 +2550,7 @@ function buildForceUpdateTaskStatusTool(connection) {
|
|
|
2536
2550
|
function buildCreatePullRequestTool(connection, config) {
|
|
2537
2551
|
return defineTool(
|
|
2538
2552
|
"create_pull_request",
|
|
2539
|
-
"Create a GitHub pull request for this task.
|
|
2553
|
+
"Create a GitHub pull request for this task. Runs in order: 1) stage any uncommitted changes, 2) commit them (using commitMessage, or a default derived from title), 3) push to origin, 4) create the PR via GitHub API. When to use: opening the PR for this task \u2014 always use this instead of the gh CLI or raw git. Common failures: missing remote branch, a PR already open for this branch, or an expired git token (retry after the refresh). Returns: confirmation string with the new PR number and URL.",
|
|
2540
2554
|
{
|
|
2541
2555
|
title: z3.string().describe("The PR title"),
|
|
2542
2556
|
body: z3.string().describe("The PR description/body in markdown"),
|
|
@@ -2622,7 +2636,7 @@ Troubleshooting:
|
|
|
2622
2636
|
function buildAddDependencyTool(connection) {
|
|
2623
2637
|
return defineTool(
|
|
2624
2638
|
"add_dependency",
|
|
2625
|
-
"Add a dependency \u2014 this task cannot start until the
|
|
2639
|
+
"Add a blocking dependency \u2014 this task cannot start until the named task is merged to dev. When to use: you discovered work that must land before this task can proceed. When NOT to use: to track work that should happen after this task \u2014 use create_follow_up_task instead. Returns: confirmation string.",
|
|
2626
2640
|
{
|
|
2627
2641
|
depends_on_slug_or_id: z3.string().describe("Slug or ID of the task this task depends on")
|
|
2628
2642
|
},
|
|
@@ -2644,7 +2658,7 @@ function buildAddDependencyTool(connection) {
|
|
|
2644
2658
|
function buildRemoveDependencyTool(connection) {
|
|
2645
2659
|
return defineTool(
|
|
2646
2660
|
"remove_dependency",
|
|
2647
|
-
"Remove a dependency from this task",
|
|
2661
|
+
"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.",
|
|
2648
2662
|
{
|
|
2649
2663
|
depends_on_slug_or_id: z3.string().describe("Slug or ID of the task to remove as dependency")
|
|
2650
2664
|
},
|
|
@@ -2666,7 +2680,7 @@ function buildRemoveDependencyTool(connection) {
|
|
|
2666
2680
|
function buildCreateFollowUpTaskTool(connection) {
|
|
2667
2681
|
return defineTool(
|
|
2668
2682
|
"create_follow_up_task",
|
|
2669
|
-
"Create a follow-up task
|
|
2683
|
+
"Create a follow-up task that depends on the current task. When to use: out-of-scope work, v1.1 features, or cleanup that should happen after this task merges. The new task will be unblocked once the current task is merged. When NOT to use: to add a blocker to this task \u2014 use add_dependency instead. Returns: confirmation string with the new task's slug.",
|
|
2670
2684
|
{
|
|
2671
2685
|
title: z3.string().describe("Follow-up task title"),
|
|
2672
2686
|
description: z3.string().optional().describe("Brief description of the follow-up work"),
|
|
@@ -2696,7 +2710,7 @@ function buildCreateFollowUpTaskTool(connection) {
|
|
|
2696
2710
|
function buildCreateSuggestionTool(connection) {
|
|
2697
2711
|
return defineTool(
|
|
2698
2712
|
"create_suggestion",
|
|
2699
|
-
"Suggest a feature, improvement, or idea for the project.
|
|
2713
|
+
"Suggest a feature, improvement, rule, or idea for the project. When to use: recommending anything project-scoped \u2014 a document, a rule, a feature, a task, an optimization. If a similar suggestion already exists the service will dedupe and record your upvote instead. When NOT to use: for actionable work scoped to the current task \u2014 open a follow-up task. Returns: confirmation string with the suggestion id (and mergedIntoId if deduped).",
|
|
2700
2714
|
{
|
|
2701
2715
|
title: z3.string().describe("Short title for the suggestion"),
|
|
2702
2716
|
description: z3.string().optional().describe(
|
|
@@ -2729,7 +2743,7 @@ function buildCreateSuggestionTool(connection) {
|
|
|
2729
2743
|
function buildVoteSuggestionTool(connection) {
|
|
2730
2744
|
return defineTool(
|
|
2731
2745
|
"vote_suggestion",
|
|
2732
|
-
"Vote on a project suggestion.
|
|
2746
|
+
"Vote +1 or -1 on a project suggestion. When to use: expressing support or disagreement with a specific suggestion returned from get_suggestions. Returns: confirmation string with the suggestion's updated score.",
|
|
2733
2747
|
{
|
|
2734
2748
|
suggestion_id: z3.string().describe("The suggestion ID to vote on"),
|
|
2735
2749
|
value: z3.number().refine((v) => v === 1 || v === -1, { message: "Value must be 1 or -1" }).describe("+1 to upvote, -1 to downvote")
|
|
@@ -2778,7 +2792,7 @@ var SP_DESCRIPTION = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique)";
|
|
|
2778
2792
|
function buildUpdateTaskTool(connection) {
|
|
2779
2793
|
return defineTool(
|
|
2780
2794
|
"update_task",
|
|
2781
|
-
"Save the finalized
|
|
2795
|
+
"Save the finalized plan and/or description to the current task. When to use: in Plan mode, after reaching alignment with the user on the approach. When NOT to use: for child/subtasks \u2014 use update_subtask. This tool does not change status or other properties. Returns: confirmation string.",
|
|
2782
2796
|
{
|
|
2783
2797
|
plan: z4.string().optional().describe("The task plan in markdown"),
|
|
2784
2798
|
description: z4.string().optional().describe("Updated task description")
|
|
@@ -2800,7 +2814,7 @@ function buildUpdateTaskTool(connection) {
|
|
|
2800
2814
|
function buildCreateSubtaskTool(connection) {
|
|
2801
2815
|
return defineTool(
|
|
2802
2816
|
"create_subtask",
|
|
2803
|
-
"Create a subtask under the current parent task.
|
|
2817
|
+
"Create a subtask under the current parent task. When to use: breaking a complex parent task into smaller pieces during planning. When NOT to use: for follow-ups that depend on this task but are not children \u2014 use create_follow_up_task. Returns: confirmation string with the new subtask id.",
|
|
2804
2818
|
{
|
|
2805
2819
|
title: z4.string().describe("Subtask title"),
|
|
2806
2820
|
description: z4.string().optional().describe("Brief description"),
|
|
@@ -2830,7 +2844,7 @@ function buildCreateSubtaskTool(connection) {
|
|
|
2830
2844
|
function buildUpdateSubtaskTool(connection) {
|
|
2831
2845
|
return defineTool(
|
|
2832
2846
|
"update_subtask",
|
|
2833
|
-
"Update an existing subtask's fields",
|
|
2847
|
+
"Update an existing subtask's fields (title, description, plan, ordinal, storyPointValue). When to use: refining a child's plan or reordering the subtask queue. When NOT to use: to change status (pack tools do that automatically) or to update the current task itself (use update_task). Returns: confirmation string.",
|
|
2834
2848
|
{
|
|
2835
2849
|
subtaskId: z4.string().describe("The subtask ID to update"),
|
|
2836
2850
|
title: z4.string().optional(),
|
|
@@ -2859,7 +2873,7 @@ function buildUpdateSubtaskTool(connection) {
|
|
|
2859
2873
|
function buildDeleteSubtaskTool(connection) {
|
|
2860
2874
|
return defineTool(
|
|
2861
2875
|
"delete_subtask",
|
|
2862
|
-
"Delete a subtask",
|
|
2876
|
+
"Delete a subtask by id. When to use: a subtask was created in error or is no longer needed. Returns: confirmation string.",
|
|
2863
2877
|
{ subtaskId: z4.string().describe("The subtask ID to delete") },
|
|
2864
2878
|
async ({ subtaskId }) => {
|
|
2865
2879
|
try {
|
|
@@ -2877,7 +2891,7 @@ function buildDeleteSubtaskTool(connection) {
|
|
|
2877
2891
|
function buildListSubtasksTool(connection) {
|
|
2878
2892
|
return defineTool(
|
|
2879
2893
|
"list_subtasks",
|
|
2880
|
-
"List all subtasks under the current parent task. Returns status,
|
|
2894
|
+
"List all subtasks under the current parent task. When to use: coordinating child work \u2014 check who is running, which children are ready for review, or which are blocked. When NOT to use: for non-child related tasks \u2014 use get_task. Returns: JSON array with id, slug, title, status, storyPointValue, githubPRNumber, githubPRUrl, agentId, and plan for each child.",
|
|
2881
2895
|
{},
|
|
2882
2896
|
async () => {
|
|
2883
2897
|
try {
|
|
@@ -2896,7 +2910,7 @@ function buildPackTools(connection) {
|
|
|
2896
2910
|
return [
|
|
2897
2911
|
defineTool(
|
|
2898
2912
|
"start_child_cloud_build",
|
|
2899
|
-
"Start a cloud build for a child task.
|
|
2913
|
+
"Start a cloud build (codespace) for a child task. Preconditions: the child must be in Open status, have a story point value, and have an agent assigned. When NOT to use: if the child is already InProgress or past Open \u2014 it is already building or done. Returns: confirmation string including the child task id that the build was started for.",
|
|
2900
2914
|
{
|
|
2901
2915
|
childTaskId: z4.string().describe("The child task ID to start a cloud build for")
|
|
2902
2916
|
},
|
|
@@ -2916,7 +2930,7 @@ function buildPackTools(connection) {
|
|
|
2916
2930
|
),
|
|
2917
2931
|
defineTool(
|
|
2918
2932
|
"stop_child_build",
|
|
2919
|
-
"
|
|
2933
|
+
"Send a graceful stop signal to a running child build's agent. When to use: you decided the child should halt (plan changed, deadlock, scope pivot) and want the agent to exit cleanly. This is not a force-kill \u2014 the agent may take a moment to wind down. Returns: confirmation string.",
|
|
2920
2934
|
{
|
|
2921
2935
|
childTaskId: z4.string().describe("The child task ID whose build should be stopped")
|
|
2922
2936
|
},
|
|
@@ -2936,7 +2950,7 @@ function buildPackTools(connection) {
|
|
|
2936
2950
|
),
|
|
2937
2951
|
defineTool(
|
|
2938
2952
|
"approve_and_merge_pr",
|
|
2939
|
-
"Approve and merge a child task's
|
|
2953
|
+
"Approve and merge a child task's PR. Preconditions: child is in ReviewPR and you have reviewed the diff. When NOT to use: if review surfaced issues \u2014 post to the child's chat or escalate instead. Returns: { childTaskId, prNumber, merged }. merged=true means the merge happened and status is now ReviewDev. merged=false means the merge is queued for GitHub automerge (CI still running) \u2014 do NOT proceed as if merged; wait for the child's status to transition to ReviewDev. If checks have failed, this call errors \u2014 investigate the failure.",
|
|
2940
2954
|
{
|
|
2941
2955
|
childTaskId: z4.string().describe("The child task ID whose PR should be approved and merged")
|
|
2942
2956
|
},
|
|
@@ -3024,7 +3038,7 @@ function buildCodeReviewTools(connection) {
|
|
|
3024
3038
|
return [
|
|
3025
3039
|
defineTool(
|
|
3026
3040
|
"approve_code_review",
|
|
3027
|
-
"Approve the code review.
|
|
3041
|
+
"Approve the code review and exit. When to use: the diff passes all review criteria and is ready to merge. When NOT to use: if any substantive issue remains \u2014 call request_code_changes with a structured issues[] list. This tool takes only a summary; it does not accept an issues array (by design \u2014 an approval should have no blocking issues). Returns: confirmation string.",
|
|
3028
3042
|
{
|
|
3029
3043
|
summary: z6.string().describe("Brief summary of what was reviewed and why it looks good")
|
|
3030
3044
|
},
|
|
@@ -3047,7 +3061,7 @@ ${summary}`;
|
|
|
3047
3061
|
),
|
|
3048
3062
|
defineTool(
|
|
3049
3063
|
"request_code_changes",
|
|
3050
|
-
"Request changes during code review.
|
|
3064
|
+
"Request changes during code review and exit. When to use: substantive issues were found that must be fixed before merge. Each entry in issues[] is { file: string, line?: number, severity: 'critical' | 'major' | 'minor', description: string }. When NOT to use: for an approval \u2014 use approve_code_review. Returns: confirmation string.",
|
|
3051
3065
|
{
|
|
3052
3066
|
issues: z6.array(
|
|
3053
3067
|
z6.object({
|
|
@@ -3641,7 +3655,7 @@ function buildClientInspectionTools(manager) {
|
|
|
3641
3655
|
return [
|
|
3642
3656
|
defineTool(
|
|
3643
3657
|
"debug_inspect_client_paused",
|
|
3644
|
-
"When the client-side debugger is paused at a breakpoint, returns the call stack and local variables.
|
|
3658
|
+
"When the client-side (browser) debugger is paused at a breakpoint, returns the call stack and local variables from the paused frame. When to use: after a client breakpoint hits, to see what is in scope in the browser. When NOT to use: for server pauses \u2014 use debug_inspect_paused. Returns: JSON with side='client', reason, hitBreakpoints, callStack, and localVariables. If the debugger paused between turns and has since resumed, queued breakpoint hits are returned instead.",
|
|
3645
3659
|
{},
|
|
3646
3660
|
async () => {
|
|
3647
3661
|
const clientOrErr = requirePlaywrightClient(manager);
|
|
@@ -3684,7 +3698,7 @@ ${JSON.stringify(queuedHits, null, 2)}`
|
|
|
3684
3698
|
),
|
|
3685
3699
|
defineTool(
|
|
3686
3700
|
"debug_evaluate_client",
|
|
3687
|
-
"Evaluate a JavaScript expression in the
|
|
3701
|
+
"Evaluate a JavaScript expression in the browser context. When paused at a client breakpoint, runs in the paused scope (use frameIndex to pick a frame); otherwise runs in the page's global scope with access to DOM, window, and React internals. Side effects are real \u2014 navigations, DOM mutations, and function calls execute. Prefer read-only expressions unless you specifically want to mutate page state. Returns: `(type) value`.",
|
|
3688
3702
|
{
|
|
3689
3703
|
expression: z8.string().describe("JavaScript expression to evaluate in the browser context"),
|
|
3690
3704
|
frameIndex: z8.number().optional().describe("Call stack frame index (0 = top frame). Defaults to the top frame.")
|
|
@@ -3758,7 +3772,7 @@ function buildClientInteractionTools(manager) {
|
|
|
3758
3772
|
),
|
|
3759
3773
|
defineTool(
|
|
3760
3774
|
"debug_navigate_client",
|
|
3761
|
-
"Navigate the headless browser to a
|
|
3775
|
+
"Navigate the headless browser to a URL. When to use: reproducing a specific flow or visiting a different page. Waits for `domcontentloaded` before returning (Playwright's default ~30s navigation timeout applies). Returns: confirmation string with the resolved current URL.",
|
|
3762
3776
|
{
|
|
3763
3777
|
url: z8.string().describe("URL to navigate to (e.g., http://localhost:3000/dashboard)")
|
|
3764
3778
|
},
|
|
@@ -3775,7 +3789,7 @@ function buildClientInteractionTools(manager) {
|
|
|
3775
3789
|
),
|
|
3776
3790
|
defineTool(
|
|
3777
3791
|
"debug_click_client",
|
|
3778
|
-
"Click an element
|
|
3792
|
+
"Click an element in the headless browser by CSS selector. When to use: reproducing bugs by interacting with the UI programmatically. Playwright auto-waits for the element to be visible, stable, and enabled before clicking, up to a 10s timeout \u2014 a miss throws and is reported in the failure message. Returns: confirmation string.",
|
|
3779
3793
|
{
|
|
3780
3794
|
selector: z8.string().describe(
|
|
3781
3795
|
"CSS selector of the element to click (e.g., 'button.submit', '#login-form input[type=submit]')"
|
|
@@ -3948,7 +3962,7 @@ function buildDebugLifecycleTools(manager) {
|
|
|
3948
3962
|
return [
|
|
3949
3963
|
defineTool(
|
|
3950
3964
|
"debug_enter_mode",
|
|
3951
|
-
"Activate debug mode:
|
|
3965
|
+
"Activate debug mode. When to use: at the start of a debug session before setting breakpoints or probes. Restarts the dev server with Node.js --inspect for server-side CDP, and/or launches a headless Chromium via Playwright for client-side. Default: if neither serverSide nor clientSide is passed, server-side only is activated. Pass clientSide=true for frontend debugging (previewUrl required), or set both for full-stack. Returns: activation status string listing active modes, an echoed hypothesis if given, and a warning if source maps are missing.",
|
|
3952
3966
|
{
|
|
3953
3967
|
hypothesis: z9.string().optional().describe("Your hypothesis about the bug \u2014 helps track debugging intent"),
|
|
3954
3968
|
serverSide: z9.boolean().optional().describe(
|
|
@@ -4094,7 +4108,7 @@ ${JSON.stringify(queuedHits, null, 2)}`
|
|
|
4094
4108
|
),
|
|
4095
4109
|
defineTool(
|
|
4096
4110
|
"debug_evaluate",
|
|
4097
|
-
"Evaluate a JavaScript expression in the
|
|
4111
|
+
"Evaluate a JavaScript expression server-side in the Node process. When paused at a breakpoint the expression runs in that frame's scope (use frameIndex to pick a different frame); otherwise it runs in the global scope. Side effects are real \u2014 assignments, function calls, and I/O all execute. Prefer read-only expressions unless you specifically want to mutate state. Returns: `(type) value`.",
|
|
4098
4112
|
{
|
|
4099
4113
|
expression: z9.string().describe("The JavaScript expression to evaluate"),
|
|
4100
4114
|
frameIndex: z9.number().optional().describe("Call stack frame index (0 = top frame). Defaults to the top frame.")
|
|
@@ -4193,7 +4207,7 @@ function buildProbeResultTools(manager) {
|
|
|
4193
4207
|
return [
|
|
4194
4208
|
defineTool(
|
|
4195
4209
|
"debug_get_probe_results",
|
|
4196
|
-
"Fetch captured probe hit data.
|
|
4210
|
+
"Fetch captured probe hit data. When to use: after triggering the code path for a probe set by debug_add_probe. Filtering: pass label to filter directly, or probeId to look up and filter by that probe's label; if both are passed, label wins and probeId is ignored. Returns: grouped text with per-probe hit count, timestamps, and captured expression values.",
|
|
4197
4211
|
{
|
|
4198
4212
|
probeId: z9.string().optional().describe("Filter results by probe ID (resolves to its label)"),
|
|
4199
4213
|
label: z9.string().optional().describe("Filter results by probe label"),
|
|
@@ -4800,7 +4814,31 @@ function collectMissingProps(taskProps) {
|
|
|
4800
4814
|
|
|
4801
4815
|
// src/execution/tool-access.ts
|
|
4802
4816
|
var PM_PLAN_FILE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit"]);
|
|
4803
|
-
var
|
|
4817
|
+
var DESTRUCTIVE_PATTERNS = [
|
|
4818
|
+
{
|
|
4819
|
+
name: "git push --force (without --force-with-lease)",
|
|
4820
|
+
re: /git\s+push\s+(?:-f\b|--force(?!-with-lease))/
|
|
4821
|
+
},
|
|
4822
|
+
{ name: "git push --delete", re: /git\s+push\s+(?:-d\b|--delete\b)/ },
|
|
4823
|
+
{ name: "git reset --hard", re: /git\s+reset\s+--hard\b/ },
|
|
4824
|
+
{
|
|
4825
|
+
name: "rm -rf /",
|
|
4826
|
+
re: /rm\s+(?:-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r|--recursive\s+--force)\s+\/(?!\S)/
|
|
4827
|
+
},
|
|
4828
|
+
{ name: "sudo rm", re: /\bsudo\s+rm\b/ },
|
|
4829
|
+
{ name: "chmod world-writable", re: /\bchmod\s+(?:-R\s+)?[0-7]*7{2,3}\b/ },
|
|
4830
|
+
{ name: "dd to device", re: /\bdd\s+.*\bof=\/dev\// },
|
|
4831
|
+
{ name: "redirect to block device", re: />\s*\/dev\/(?:sd[a-z]|nvme\d|xvd[a-z])/ },
|
|
4832
|
+
{ name: "mkfs filesystem creation", re: /\bmkfs(?:\.|\s)/ },
|
|
4833
|
+
{ name: "shutdown/poweroff/halt/reboot", re: /\b(?:shutdown|poweroff|halt|reboot)\b/ },
|
|
4834
|
+
{ name: "fork bomb", re: /:\(\)\s*\{\s*:\|\s*:&\s*\}\s*;\s*:/ }
|
|
4835
|
+
];
|
|
4836
|
+
function matchesDestructive(cmd) {
|
|
4837
|
+
for (const { name, re } of DESTRUCTIVE_PATTERNS) {
|
|
4838
|
+
if (re.test(cmd)) return name;
|
|
4839
|
+
}
|
|
4840
|
+
return null;
|
|
4841
|
+
}
|
|
4804
4842
|
function isPlanFile(input) {
|
|
4805
4843
|
const filePath = String(input.file_path ?? input.path ?? "");
|
|
4806
4844
|
return filePath.includes(".claude/plans/");
|
|
@@ -4820,10 +4858,11 @@ function handleDiscoveryToolAccess(toolName, input) {
|
|
|
4820
4858
|
function handleBuildingToolAccess(toolName, input) {
|
|
4821
4859
|
if (toolName === "Bash") {
|
|
4822
4860
|
const cmd = String(input.command ?? "");
|
|
4823
|
-
|
|
4861
|
+
const matched = matchesDestructive(cmd);
|
|
4862
|
+
if (matched) {
|
|
4824
4863
|
return {
|
|
4825
4864
|
behavior: "deny",
|
|
4826
|
-
message:
|
|
4865
|
+
message: `Destructive operation blocked (${matched}). Use safer alternatives.`
|
|
4827
4866
|
};
|
|
4828
4867
|
}
|
|
4829
4868
|
}
|
|
@@ -5006,6 +5045,65 @@ function buildCanUseTool(host) {
|
|
|
5006
5045
|
};
|
|
5007
5046
|
}
|
|
5008
5047
|
|
|
5048
|
+
// src/execution/redactor.ts
|
|
5049
|
+
var REDACTED = "<redacted>";
|
|
5050
|
+
var BEARER_RE = /\b(Bearer\s+)[A-Za-z0-9_\-.]{20,}/g;
|
|
5051
|
+
var VENDOR_KEY_RE = /\b(?:sk-[a-zA-Z0-9_-]{20,}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,}|xoxb-[A-Za-z0-9-]+|xai-[A-Za-z0-9-]{20,})\b/g;
|
|
5052
|
+
var AWS_ACCESS_KEY_RE = /\bAKIA[0-9A-Z]{16}\b/g;
|
|
5053
|
+
var JWT_RE = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g;
|
|
5054
|
+
var ENV_SECRET_RE = /^(\s*(?:export\s+)?([A-Z][A-Z0-9_]*(?:TOKEN|SECRET|KEY|PASSWORD|PASS|CREDENTIAL|CREDENTIALS)[A-Z0-9_]*)\s*=\s*)['"]?([^\s'"]+)['"]?/gm;
|
|
5055
|
+
var COOKIE_HEADER_RE = /(Cookie:\s*)[^\r\n]+/gi;
|
|
5056
|
+
var BASIC_AUTH_URL_RE = /(https?:\/\/)([^:@\s/]+):([^@\s]+)@/g;
|
|
5057
|
+
var AWS_SECRET_LINE_RE = /^.*(?:secret|aws_secret).*$/gim;
|
|
5058
|
+
var AWS_SECRET_VALUE_RE = /\b([A-Za-z0-9/+=]{40})\b/g;
|
|
5059
|
+
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
5060
|
+
function redact(input) {
|
|
5061
|
+
if (!input) return { output: input, redacted: 0 };
|
|
5062
|
+
let count = 0;
|
|
5063
|
+
let output = input;
|
|
5064
|
+
output = output.replace(SYSTEM_REMINDER_RE, () => {
|
|
5065
|
+
count++;
|
|
5066
|
+
return "<!-- stripped injection -->";
|
|
5067
|
+
});
|
|
5068
|
+
output = output.replace(BEARER_RE, (_match, prefix) => {
|
|
5069
|
+
count++;
|
|
5070
|
+
return `${prefix}${REDACTED}`;
|
|
5071
|
+
});
|
|
5072
|
+
output = output.replace(VENDOR_KEY_RE, () => {
|
|
5073
|
+
count++;
|
|
5074
|
+
return REDACTED;
|
|
5075
|
+
});
|
|
5076
|
+
output = output.replace(AWS_ACCESS_KEY_RE, () => {
|
|
5077
|
+
count++;
|
|
5078
|
+
return REDACTED;
|
|
5079
|
+
});
|
|
5080
|
+
output = output.replace(JWT_RE, () => {
|
|
5081
|
+
count++;
|
|
5082
|
+
return REDACTED;
|
|
5083
|
+
});
|
|
5084
|
+
output = output.replace(
|
|
5085
|
+
AWS_SECRET_LINE_RE,
|
|
5086
|
+
(line) => line.replace(AWS_SECRET_VALUE_RE, (match) => {
|
|
5087
|
+
if (/^[a-f0-9]+$/i.test(match)) return match;
|
|
5088
|
+
count++;
|
|
5089
|
+
return REDACTED;
|
|
5090
|
+
})
|
|
5091
|
+
);
|
|
5092
|
+
output = output.replace(ENV_SECRET_RE, (_match, prefix, _key, _value) => {
|
|
5093
|
+
count++;
|
|
5094
|
+
return `${prefix}${REDACTED}`;
|
|
5095
|
+
});
|
|
5096
|
+
output = output.replace(COOKIE_HEADER_RE, (_match, prefix) => {
|
|
5097
|
+
count++;
|
|
5098
|
+
return `${prefix}${REDACTED}`;
|
|
5099
|
+
});
|
|
5100
|
+
output = output.replace(BASIC_AUTH_URL_RE, (_match, scheme, user) => {
|
|
5101
|
+
count++;
|
|
5102
|
+
return `${scheme}${user}:${REDACTED}@`;
|
|
5103
|
+
});
|
|
5104
|
+
return { output, redacted: count };
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5009
5107
|
// src/execution/query-executor.ts
|
|
5010
5108
|
var logger2 = createServiceLogger("QueryExecutor");
|
|
5011
5109
|
var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
|
|
@@ -5018,12 +5116,15 @@ function buildHooks(host) {
|
|
|
5018
5116
|
async (input) => {
|
|
5019
5117
|
if (host.isStopped()) return await Promise.resolve({ continue: false });
|
|
5020
5118
|
if (input.hook_event_name === "PostToolUse") {
|
|
5021
|
-
const
|
|
5119
|
+
const raw = typeof input.tool_response === "string" ? input.tool_response : JSON.stringify(input.tool_response);
|
|
5120
|
+
const { output: redacted, redacted: redactedCount } = redact(raw);
|
|
5121
|
+
const output = redacted.slice(0, 500);
|
|
5022
5122
|
host.connection.sendEvent({
|
|
5023
5123
|
type: "tool_result",
|
|
5024
5124
|
tool: input.tool_name,
|
|
5025
5125
|
output,
|
|
5026
|
-
isError: false
|
|
5126
|
+
isError: false,
|
|
5127
|
+
...redactedCount > 0 ? { redactedCount } : {}
|
|
5027
5128
|
});
|
|
5028
5129
|
host.pendingToolOutputs.push({ tool: input.tool_name, output });
|
|
5029
5130
|
if (input.tool_name === "mcp__conveyor__create_pull_request") {
|
|
@@ -5390,6 +5491,22 @@ async function runWithRetry(initialQuery, context, host, options) {
|
|
|
5390
5491
|
var CostTracker = class {
|
|
5391
5492
|
cumulativeCostUsd = 0;
|
|
5392
5493
|
modelUsage = /* @__PURE__ */ new Map();
|
|
5494
|
+
seeded = false;
|
|
5495
|
+
/**
|
|
5496
|
+
* Rehydrate cumulative spend from the server so `maxBudgetUsd` enforcement
|
|
5497
|
+
* accounts for costs incurred by prior agent runs on the same task. Must be
|
|
5498
|
+
* called before any `addQueryCost` / `addModelUsage` — re-seeding after
|
|
5499
|
+
* costs have accumulated would clobber in-process totals.
|
|
5500
|
+
*/
|
|
5501
|
+
seed(totalCostUsd, modelUsage) {
|
|
5502
|
+
if (this.seeded) return;
|
|
5503
|
+
if (this.cumulativeCostUsd > 0 || this.modelUsage.size > 0) return;
|
|
5504
|
+
this.cumulativeCostUsd = totalCostUsd;
|
|
5505
|
+
for (const entry of modelUsage) {
|
|
5506
|
+
this.modelUsage.set(entry.model, { ...entry });
|
|
5507
|
+
}
|
|
5508
|
+
this.seeded = true;
|
|
5509
|
+
}
|
|
5393
5510
|
/** Add cost from a completed query and return the running total */
|
|
5394
5511
|
addQueryCost(queryCostUsd) {
|
|
5395
5512
|
this.cumulativeCostUsd += queryCostUsd;
|
|
@@ -5580,6 +5697,10 @@ var QueryBridge = class {
|
|
|
5580
5697
|
resume() {
|
|
5581
5698
|
this._stopped = false;
|
|
5582
5699
|
}
|
|
5700
|
+
/** Rehydrate CostTracker from server-side cumulative spend on agent boot. */
|
|
5701
|
+
seedCostTracker(totalCostUsd, modelUsage) {
|
|
5702
|
+
this.costTracker.seed(totalCostUsd, modelUsage);
|
|
5703
|
+
}
|
|
5583
5704
|
/**
|
|
5584
5705
|
* Execute a Claude SDK query.
|
|
5585
5706
|
* Without followUpContent: runs initial mode execution (build/plan).
|
|
@@ -5845,6 +5966,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
5845
5966
|
});
|
|
5846
5967
|
}
|
|
5847
5968
|
this.queryBridge = this.createQueryBridge();
|
|
5969
|
+
await this.seedCostTrackerFromServer();
|
|
5848
5970
|
this.logInitialization();
|
|
5849
5971
|
const staleMessageCount = this.pendingMessages.length;
|
|
5850
5972
|
const didExecuteInitialQuery = await this.executeInitialMode();
|
|
@@ -6206,6 +6328,36 @@ var SessionRunner = class _SessionRunner {
|
|
|
6206
6328
|
}
|
|
6207
6329
|
});
|
|
6208
6330
|
}
|
|
6331
|
+
/**
|
|
6332
|
+
* Rehydrate CostTracker from server. Caps at 3s so a slow API call never
|
|
6333
|
+
* blocks agent startup — on timeout/error we fall through with a $0 tracker
|
|
6334
|
+
* (the existing behavior before this rehydration path was added).
|
|
6335
|
+
*/
|
|
6336
|
+
async seedCostTrackerFromServer() {
|
|
6337
|
+
if (!this.queryBridge) return;
|
|
6338
|
+
const TIMEOUT_MS = 3e3;
|
|
6339
|
+
try {
|
|
6340
|
+
const timeout = new Promise((resolve2) => {
|
|
6341
|
+
setTimeout(() => resolve2(null), TIMEOUT_MS);
|
|
6342
|
+
});
|
|
6343
|
+
const fetched = await Promise.race([this.connection.getCumulativeSpending(), timeout]);
|
|
6344
|
+
if (fetched) {
|
|
6345
|
+
this.queryBridge.seedCostTracker(fetched.totalCostUsd, fetched.modelUsage);
|
|
6346
|
+
process.stderr.write(
|
|
6347
|
+
`[conveyor-agent] CostTracker seeded: $${fetched.totalCostUsd.toFixed(4)} across ${fetched.modelUsage.length} model(s)
|
|
6348
|
+
`
|
|
6349
|
+
);
|
|
6350
|
+
} else {
|
|
6351
|
+
process.stderr.write(
|
|
6352
|
+
"[conveyor-agent] CostTracker seed timed out after 3s \u2014 starting at $0\n"
|
|
6353
|
+
);
|
|
6354
|
+
}
|
|
6355
|
+
} catch (err) {
|
|
6356
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
6357
|
+
process.stderr.write(`[conveyor-agent] CostTracker seed failed: ${msg} \u2014 starting at $0
|
|
6358
|
+
`);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6209
6361
|
/** Proactively refresh the GitHub token before the 1-hour expiry. */
|
|
6210
6362
|
async refreshGithubToken() {
|
|
6211
6363
|
try {
|
|
@@ -6709,8 +6861,8 @@ function buildTaskListTools(connection) {
|
|
|
6709
6861
|
{ annotations: { readOnlyHint: true } }
|
|
6710
6862
|
),
|
|
6711
6863
|
defineTool(
|
|
6712
|
-
"
|
|
6713
|
-
"Get detailed information about a task
|
|
6864
|
+
"get_project_task",
|
|
6865
|
+
"Get detailed information about a task in this project (chat messages, child tasks, session). Project-runner scope.",
|
|
6714
6866
|
{ task_id: z10.string().describe("The task ID to look up") },
|
|
6715
6867
|
async ({ task_id }) => {
|
|
6716
6868
|
try {
|
|
@@ -6808,8 +6960,8 @@ function buildMutationTools2(connection) {
|
|
|
6808
6960
|
}
|
|
6809
6961
|
),
|
|
6810
6962
|
defineTool(
|
|
6811
|
-
"
|
|
6812
|
-
"Update an existing task's title, description, plan, status, or assignee.",
|
|
6963
|
+
"update_project_task",
|
|
6964
|
+
"Update an existing task's title, description, plan, status, or assignee. Project-runner scope.",
|
|
6813
6965
|
{
|
|
6814
6966
|
task_id: z10.string().describe("The task ID to update"),
|
|
6815
6967
|
title: z10.string().optional().describe("New title"),
|
|
@@ -7359,7 +7511,7 @@ function spawnChildAgent(assignment, workDir) {
|
|
|
7359
7511
|
CONVEYOR_TASK_TOKEN: taskToken,
|
|
7360
7512
|
CONVEYOR_TASK_ID: taskId,
|
|
7361
7513
|
...sessionId ? { CONVEYOR_SESSION_ID: sessionId } : {},
|
|
7362
|
-
CONVEYOR_MODE:
|
|
7514
|
+
CONVEYOR_MODE: mode,
|
|
7363
7515
|
CONVEYOR_WORKSPACE: workDir,
|
|
7364
7516
|
CONVEYOR_USE_WORKTREE: "false",
|
|
7365
7517
|
CONVEYOR_AGENT_MODE: effectiveAgentMode,
|
|
@@ -7413,7 +7565,7 @@ async function killAgent(agent, taskId) {
|
|
|
7413
7565
|
async function handleAssignment(assignment, activeAgents, projectDir, connection) {
|
|
7414
7566
|
const { taskId, mode } = assignment;
|
|
7415
7567
|
const shortId = taskId.slice(0, 8);
|
|
7416
|
-
const agentKey =
|
|
7568
|
+
const agentKey = mode === "code-review" ? `${taskId}:code-review` : taskId;
|
|
7417
7569
|
const existing = activeAgents.get(agentKey);
|
|
7418
7570
|
if (existing) {
|
|
7419
7571
|
if (existing.process.exitCode === null) {
|
|
@@ -7814,4 +7966,4 @@ export {
|
|
|
7814
7966
|
loadForwardPorts,
|
|
7815
7967
|
loadConveyorConfig
|
|
7816
7968
|
};
|
|
7817
|
-
//# sourceMappingURL=chunk-
|
|
7969
|
+
//# sourceMappingURL=chunk-COJPX2QI.js.map
|