@rallycry/conveyor-agent 10.13.8 → 10.13.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-AJZIO5QI.js → chunk-PXQJ4NVO.js} +286 -164
- package/dist/chunk-PXQJ4NVO.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AJZIO5QI.js.map +0 -1
|
@@ -2318,7 +2318,10 @@ var UpdateTaskPropertiesRequestSchema = z3.object({
|
|
|
2318
2318
|
tagIds: z3.array(z3.string()).optional(),
|
|
2319
2319
|
tagNames: z3.array(z3.string()).optional(),
|
|
2320
2320
|
githubPRUrl: z3.string().url().optional(),
|
|
2321
|
-
githubBranch: z3.string().optional()
|
|
2321
|
+
githubBranch: z3.string().optional(),
|
|
2322
|
+
// Canonical risk level, or null to clear — same semantics as the headless
|
|
2323
|
+
// update_task boundary (resolved to the project's Risk row in the handler).
|
|
2324
|
+
risk: riskLevelSchema.nullable().optional()
|
|
2322
2325
|
});
|
|
2323
2326
|
var ListIconsRequestSchema = z3.object({
|
|
2324
2327
|
sessionId: z3.string()
|
|
@@ -2650,7 +2653,13 @@ var UpdateProjectTaskRequestSchema = z4.object({
|
|
|
2650
2653
|
projectId: z4.string(),
|
|
2651
2654
|
taskId: z4.string(),
|
|
2652
2655
|
title: z4.string().optional(),
|
|
2656
|
+
description: z4.string().optional(),
|
|
2653
2657
|
plan: z4.string().optional(),
|
|
2658
|
+
// Enum validation lives at the MCP tool layer (mirrors createProjectTask);
|
|
2659
|
+
// the handler routes through the shared updateStatus core (InProgress
|
|
2660
|
+
// dependency check + cleanup/board/Slack side effects), not the stricter
|
|
2661
|
+
// card-type-validating path the Socket.IO updateTaskStatus mutation uses.
|
|
2662
|
+
status: z4.string().optional(),
|
|
2654
2663
|
// Canonical risk level, or null to clear. Resolved to the project's
|
|
2655
2664
|
// configured Risk row (by rank) in the handler.
|
|
2656
2665
|
risk: riskLevelSchema.nullable().optional(),
|
|
@@ -2660,9 +2669,9 @@ var UpdateProjectTaskRequestSchema = z4.object({
|
|
|
2660
2669
|
subProjectId: z4.string().nullable().optional(),
|
|
2661
2670
|
requestingUserId: z4.string().optional()
|
|
2662
2671
|
}).strict().refine(
|
|
2663
|
-
(v) => v.title !== void 0 || v.plan !== void 0 || v.risk !== void 0 || v.assignedUserId !== void 0 || v.subProjectId !== void 0,
|
|
2672
|
+
(v) => v.title !== void 0 || v.description !== void 0 || v.plan !== void 0 || v.status !== void 0 || v.risk !== void 0 || v.assignedUserId !== void 0 || v.subProjectId !== void 0,
|
|
2664
2673
|
{
|
|
2665
|
-
message: "update_task requires at least one field to change (title, plan, risk, assignedUserId, or subProjectId)"
|
|
2674
|
+
message: "update_task requires at least one field to change (title, description, plan, status, risk, assignedUserId, or subProjectId)"
|
|
2666
2675
|
}
|
|
2667
2676
|
);
|
|
2668
2677
|
var TransitionProjectTaskStatusRequestSchema = z4.object({
|
|
@@ -2814,6 +2823,9 @@ var UpdateProjectSubtaskRequestSchema = z4.object({
|
|
|
2814
2823
|
ordinal: z4.number().int().nonnegative().optional(),
|
|
2815
2824
|
storyPointValue: z4.number().int().positive().optional(),
|
|
2816
2825
|
followParentStatus: z4.boolean().optional(),
|
|
2826
|
+
/** Replace-set of sibling subtask ids/slugs this subtask blocks on ([] clears).
|
|
2827
|
+
* Mirrors the in-pod updateSubtask semantics. */
|
|
2828
|
+
dependsOn: z4.array(z4.string().min(1)).max(32).optional(),
|
|
2817
2829
|
requestingUserId: z4.string().optional()
|
|
2818
2830
|
});
|
|
2819
2831
|
var DeleteProjectSubtaskRequestSchema = z4.object({
|
|
@@ -3389,6 +3401,7 @@ var ClaudeCodeHarness = class {
|
|
|
3389
3401
|
};
|
|
3390
3402
|
|
|
3391
3403
|
// src/harness/pty/session.ts
|
|
3404
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3392
3405
|
import { mkdtemp as mkdtemp2, mkdir as mkdir3, rm as rm5 } from "fs/promises";
|
|
3393
3406
|
import { tmpdir as tmpdir3 } from "os";
|
|
3394
3407
|
import { join as join4, dirname } from "path";
|
|
@@ -3787,11 +3800,131 @@ function matchUsageLimitBanner(text, now = Date.now()) {
|
|
|
3787
3800
|
};
|
|
3788
3801
|
}
|
|
3789
3802
|
|
|
3803
|
+
// src/harness/pty/pty-support.ts
|
|
3804
|
+
import { stat as stat2 } from "fs/promises";
|
|
3805
|
+
var MAX_DIAGNOSTIC_OUTPUT = 4e3;
|
|
3806
|
+
var MAX_BETWEEN_TURN_BUFFER = 500;
|
|
3807
|
+
var SUBMIT_SETTLE_MS = 300;
|
|
3808
|
+
var SUBMIT_NUDGE_INTERVAL_MS = 2e3;
|
|
3809
|
+
var SUBMIT_NUDGE_MAX_PRESSES = 5;
|
|
3810
|
+
var SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5e3;
|
|
3811
|
+
var SUBMIT_NUDGE_WINDOW_MS = 9e4;
|
|
3812
|
+
var PLAN_DIALOG_FIRST_PRESS_MS = 700;
|
|
3813
|
+
var PLAN_DIALOG_INTERVAL_MS = 1500;
|
|
3814
|
+
var PLAN_DIALOG_SLOW_INTERVAL_MS = 5e3;
|
|
3815
|
+
var PLAN_DIALOG_FAST_WINDOW_MS = 1e4;
|
|
3816
|
+
var PLAN_DIALOG_WINDOW_MS = 9e4;
|
|
3817
|
+
function envMs(name, fallback) {
|
|
3818
|
+
const raw = Number(process.env[name]);
|
|
3819
|
+
return Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
3820
|
+
}
|
|
3821
|
+
function resolveSubmitSettleMs() {
|
|
3822
|
+
return envMs("CONVEYOR_PTY_SUBMIT_SETTLE_MS", SUBMIT_SETTLE_MS);
|
|
3823
|
+
}
|
|
3824
|
+
function resolveSubmitNudgeTiming() {
|
|
3825
|
+
return {
|
|
3826
|
+
intervalMs: envMs("CONVEYOR_PTY_NUDGE_INTERVAL_MS", SUBMIT_NUDGE_INTERVAL_MS),
|
|
3827
|
+
slowIntervalMs: envMs("CONVEYOR_PTY_NUDGE_SLOW_INTERVAL_MS", SUBMIT_NUDGE_SLOW_INTERVAL_MS),
|
|
3828
|
+
maxPresses: SUBMIT_NUDGE_MAX_PRESSES,
|
|
3829
|
+
windowMs: envMs("CONVEYOR_PTY_NUDGE_WINDOW_MS", SUBMIT_NUDGE_WINDOW_MS)
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
function resolvePlanDialogTiming() {
|
|
3833
|
+
return {
|
|
3834
|
+
firstPressMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FIRST_PRESS_MS", PLAN_DIALOG_FIRST_PRESS_MS),
|
|
3835
|
+
intervalMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_INTERVAL_MS", PLAN_DIALOG_INTERVAL_MS),
|
|
3836
|
+
slowIntervalMs: envMs(
|
|
3837
|
+
"CONVEYOR_PTY_PLAN_DIALOG_SLOW_INTERVAL_MS",
|
|
3838
|
+
PLAN_DIALOG_SLOW_INTERVAL_MS
|
|
3839
|
+
),
|
|
3840
|
+
fastWindowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FAST_WINDOW_MS", PLAN_DIALOG_FAST_WINDOW_MS),
|
|
3841
|
+
windowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_WINDOW_MS", PLAN_DIALOG_WINDOW_MS)
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
function turnOptionsFrom(options) {
|
|
3845
|
+
return {
|
|
3846
|
+
canUseTool: options.canUseTool,
|
|
3847
|
+
promptDelivery: options.promptDelivery,
|
|
3848
|
+
planDialogAutoAccept: options.planDialogAutoAccept,
|
|
3849
|
+
abortController: options.abortController
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3852
|
+
function isRecord2(value) {
|
|
3853
|
+
return typeof value === "object" && value !== null;
|
|
3854
|
+
}
|
|
3855
|
+
function extractSpawn(mod) {
|
|
3856
|
+
if (!isRecord2(mod)) return null;
|
|
3857
|
+
if (typeof mod.spawn === "function") return mod.spawn;
|
|
3858
|
+
const def = mod.default;
|
|
3859
|
+
if (isRecord2(def) && typeof def.spawn === "function") return def.spawn;
|
|
3860
|
+
return null;
|
|
3861
|
+
}
|
|
3862
|
+
async function loadPtySpawn() {
|
|
3863
|
+
const mod = await import("node-pty");
|
|
3864
|
+
const spawn2 = extractSpawn(mod);
|
|
3865
|
+
if (!spawn2) throw new Error("node-pty: spawn export not found");
|
|
3866
|
+
return spawn2;
|
|
3867
|
+
}
|
|
3868
|
+
function inheritedEnv(socketPath) {
|
|
3869
|
+
const env = {};
|
|
3870
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
3871
|
+
if (typeof value === "string") env[key] = value;
|
|
3872
|
+
}
|
|
3873
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
3874
|
+
delete env.ANTHROPIC_API_KEY;
|
|
3875
|
+
}
|
|
3876
|
+
if (socketPath) {
|
|
3877
|
+
env.CONVEYOR_HOOK_SOCKET = socketPath;
|
|
3878
|
+
}
|
|
3879
|
+
env.MCP_TIMEOUT ??= "60000";
|
|
3880
|
+
env.MCP_TOOL_TIMEOUT ??= "180000";
|
|
3881
|
+
return env;
|
|
3882
|
+
}
|
|
3883
|
+
function buildPromptBytes(text) {
|
|
3884
|
+
return `\x1B[200~${text}\x1B[201~`;
|
|
3885
|
+
}
|
|
3886
|
+
function renderPromptContentText(content) {
|
|
3887
|
+
return content.map((block) => {
|
|
3888
|
+
const b = block;
|
|
3889
|
+
if (b?.type === "text" && typeof b.text === "string") return b.text;
|
|
3890
|
+
if (b?.type === "image") {
|
|
3891
|
+
return `[Image attachment \u2014 use list_task_files / get_attachment to view]`;
|
|
3892
|
+
}
|
|
3893
|
+
return JSON.stringify(block);
|
|
3894
|
+
}).join("\n\n");
|
|
3895
|
+
}
|
|
3896
|
+
async function transcriptSize(path4) {
|
|
3897
|
+
try {
|
|
3898
|
+
return (await stat2(path4)).size;
|
|
3899
|
+
} catch {
|
|
3900
|
+
return 0;
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
function parseUserQuestions(input) {
|
|
3904
|
+
if (!Array.isArray(input.questions)) return [];
|
|
3905
|
+
const questions = [];
|
|
3906
|
+
for (const entry of input.questions) {
|
|
3907
|
+
if (!isRecord2(entry)) continue;
|
|
3908
|
+
if (typeof entry.question !== "string") continue;
|
|
3909
|
+
const options = Array.isArray(entry.options) ? entry.options.filter(isRecord2).filter((o) => typeof o.label === "string").map((o) => ({
|
|
3910
|
+
label: o.label,
|
|
3911
|
+
description: typeof o.description === "string" ? o.description : ""
|
|
3912
|
+
})) : [];
|
|
3913
|
+
questions.push({
|
|
3914
|
+
question: entry.question,
|
|
3915
|
+
header: typeof entry.header === "string" ? entry.header : "",
|
|
3916
|
+
options,
|
|
3917
|
+
...typeof entry.multiSelect === "boolean" ? { multiSelect: entry.multiSelect } : {}
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
return questions;
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3790
3923
|
// src/harness/pty/chat-record-mapper.ts
|
|
3791
3924
|
var TEXT_MAX = 16e3;
|
|
3792
3925
|
var TOOL_INPUT_MAX = 1900;
|
|
3793
3926
|
var TOOL_OUTPUT_MAX = 1900;
|
|
3794
|
-
function
|
|
3927
|
+
function isRecord3(value) {
|
|
3795
3928
|
return typeof value === "object" && value !== null;
|
|
3796
3929
|
}
|
|
3797
3930
|
function isUnknownArray2(value) {
|
|
@@ -3807,6 +3940,27 @@ function stringField2(record, ...keys) {
|
|
|
3807
3940
|
function truncate(text, max) {
|
|
3808
3941
|
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
3809
3942
|
}
|
|
3943
|
+
function compactQuestionsJson(questions) {
|
|
3944
|
+
const serialize = (qs) => JSON.stringify({ questions: qs });
|
|
3945
|
+
const withDescriptions = (max) => questions.map((q) => ({
|
|
3946
|
+
...q,
|
|
3947
|
+
options: q.options.map((o) => ({ ...o, description: truncate(o.description, max) }))
|
|
3948
|
+
}));
|
|
3949
|
+
const full = serialize(questions);
|
|
3950
|
+
if (full.length <= TOOL_INPUT_MAX) return full;
|
|
3951
|
+
const shortened = serialize(withDescriptions(80));
|
|
3952
|
+
if (shortened.length <= TOOL_INPUT_MAX) return shortened;
|
|
3953
|
+
const bare = serialize(withDescriptions(0));
|
|
3954
|
+
if (bare.length <= TOOL_INPUT_MAX) return bare;
|
|
3955
|
+
return bare.slice(0, TOOL_INPUT_MAX);
|
|
3956
|
+
}
|
|
3957
|
+
function compactToolInput(name, input) {
|
|
3958
|
+
if (name === "AskUserQuestion" && isRecord3(input)) {
|
|
3959
|
+
const questions = parseUserQuestions(input);
|
|
3960
|
+
if (questions.length > 0) return compactQuestionsJson(questions);
|
|
3961
|
+
}
|
|
3962
|
+
return JSON.stringify(input ?? {}).slice(0, TOOL_INPUT_MAX);
|
|
3963
|
+
}
|
|
3810
3964
|
function isNonConversationText(text) {
|
|
3811
3965
|
const trimmed = text.trimStart();
|
|
3812
3966
|
return trimmed.startsWith("<command-name>") || trimmed.startsWith("<local-command-") || trimmed.startsWith("<task-notification>");
|
|
@@ -3826,11 +3980,11 @@ function mapSystem2(record) {
|
|
|
3826
3980
|
}
|
|
3827
3981
|
function mapAssistant2(record) {
|
|
3828
3982
|
const message = record.message;
|
|
3829
|
-
if (!
|
|
3983
|
+
if (!isRecord3(message)) return [];
|
|
3830
3984
|
const content = isUnknownArray2(message.content) ? message.content : [];
|
|
3831
3985
|
const events = [];
|
|
3832
3986
|
for (const raw of content) {
|
|
3833
|
-
if (!
|
|
3987
|
+
if (!isRecord3(raw)) continue;
|
|
3834
3988
|
if (raw.type === "text") {
|
|
3835
3989
|
const text = stringField2(raw, "text");
|
|
3836
3990
|
if (text && text.length > 0) {
|
|
@@ -3843,7 +3997,7 @@ function mapAssistant2(record) {
|
|
|
3843
3997
|
const event = {
|
|
3844
3998
|
kind: "tool_use",
|
|
3845
3999
|
name: truncate(name, 200),
|
|
3846
|
-
input:
|
|
4000
|
+
input: compactToolInput(name, input)
|
|
3847
4001
|
};
|
|
3848
4002
|
const id = stringField2(raw, "id");
|
|
3849
4003
|
if (id !== void 0) event.id = id;
|
|
@@ -3857,14 +4011,14 @@ function toolResultText(block) {
|
|
|
3857
4011
|
const content = block.content;
|
|
3858
4012
|
if (typeof content === "string") return content;
|
|
3859
4013
|
if (isUnknownArray2(content)) {
|
|
3860
|
-
return content.filter((b) =>
|
|
4014
|
+
return content.filter((b) => isRecord3(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
|
|
3861
4015
|
}
|
|
3862
4016
|
return "";
|
|
3863
4017
|
}
|
|
3864
4018
|
function mapToolResults(content) {
|
|
3865
4019
|
const events = [];
|
|
3866
4020
|
for (const raw of content) {
|
|
3867
|
-
if (!
|
|
4021
|
+
if (!isRecord3(raw) || raw.type !== "tool_result") continue;
|
|
3868
4022
|
const event = {
|
|
3869
4023
|
kind: "tool_result",
|
|
3870
4024
|
output: truncate(toolResultText(raw), TOOL_OUTPUT_MAX),
|
|
@@ -3878,15 +4032,15 @@ function mapToolResults(content) {
|
|
|
3878
4032
|
}
|
|
3879
4033
|
function mapUser(record) {
|
|
3880
4034
|
const message = record.message;
|
|
3881
|
-
if (!
|
|
4035
|
+
if (!isRecord3(message)) return [];
|
|
3882
4036
|
const content = message.content;
|
|
3883
4037
|
let text;
|
|
3884
4038
|
if (typeof content === "string") {
|
|
3885
4039
|
text = content;
|
|
3886
4040
|
} else if (isUnknownArray2(content)) {
|
|
3887
|
-
const hasToolResult = content.some((b) =>
|
|
4041
|
+
const hasToolResult = content.some((b) => isRecord3(b) && b.type === "tool_result");
|
|
3888
4042
|
if (hasToolResult) return mapToolResults(content);
|
|
3889
|
-
text = content.filter((b) =>
|
|
4043
|
+
text = content.filter((b) => isRecord3(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
|
|
3890
4044
|
} else {
|
|
3891
4045
|
return [];
|
|
3892
4046
|
}
|
|
@@ -3895,7 +4049,7 @@ function mapUser(record) {
|
|
|
3895
4049
|
return [{ kind: "user_text", text: truncate(trimmed, TEXT_MAX) }];
|
|
3896
4050
|
}
|
|
3897
4051
|
function mapChatRecords(raw) {
|
|
3898
|
-
if (!
|
|
4052
|
+
if (!isRecord3(raw)) return [];
|
|
3899
4053
|
if (raw.isSidechain === true || raw.isMeta === true) return [];
|
|
3900
4054
|
switch (raw.type) {
|
|
3901
4055
|
case "system":
|
|
@@ -4799,126 +4953,6 @@ async function removeConveyorCredentials(env = process.env) {
|
|
|
4799
4953
|
}
|
|
4800
4954
|
}
|
|
4801
4955
|
|
|
4802
|
-
// src/harness/pty/pty-support.ts
|
|
4803
|
-
import { stat as stat2 } from "fs/promises";
|
|
4804
|
-
var MAX_DIAGNOSTIC_OUTPUT = 4e3;
|
|
4805
|
-
var MAX_BETWEEN_TURN_BUFFER = 500;
|
|
4806
|
-
var SUBMIT_SETTLE_MS = 300;
|
|
4807
|
-
var SUBMIT_NUDGE_INTERVAL_MS = 2e3;
|
|
4808
|
-
var SUBMIT_NUDGE_MAX_PRESSES = 5;
|
|
4809
|
-
var SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5e3;
|
|
4810
|
-
var SUBMIT_NUDGE_WINDOW_MS = 9e4;
|
|
4811
|
-
var PLAN_DIALOG_FIRST_PRESS_MS = 700;
|
|
4812
|
-
var PLAN_DIALOG_INTERVAL_MS = 1500;
|
|
4813
|
-
var PLAN_DIALOG_SLOW_INTERVAL_MS = 5e3;
|
|
4814
|
-
var PLAN_DIALOG_FAST_WINDOW_MS = 1e4;
|
|
4815
|
-
var PLAN_DIALOG_WINDOW_MS = 9e4;
|
|
4816
|
-
function envMs(name, fallback) {
|
|
4817
|
-
const raw = Number(process.env[name]);
|
|
4818
|
-
return Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
4819
|
-
}
|
|
4820
|
-
function resolveSubmitSettleMs() {
|
|
4821
|
-
return envMs("CONVEYOR_PTY_SUBMIT_SETTLE_MS", SUBMIT_SETTLE_MS);
|
|
4822
|
-
}
|
|
4823
|
-
function resolveSubmitNudgeTiming() {
|
|
4824
|
-
return {
|
|
4825
|
-
intervalMs: envMs("CONVEYOR_PTY_NUDGE_INTERVAL_MS", SUBMIT_NUDGE_INTERVAL_MS),
|
|
4826
|
-
slowIntervalMs: envMs("CONVEYOR_PTY_NUDGE_SLOW_INTERVAL_MS", SUBMIT_NUDGE_SLOW_INTERVAL_MS),
|
|
4827
|
-
maxPresses: SUBMIT_NUDGE_MAX_PRESSES,
|
|
4828
|
-
windowMs: envMs("CONVEYOR_PTY_NUDGE_WINDOW_MS", SUBMIT_NUDGE_WINDOW_MS)
|
|
4829
|
-
};
|
|
4830
|
-
}
|
|
4831
|
-
function resolvePlanDialogTiming() {
|
|
4832
|
-
return {
|
|
4833
|
-
firstPressMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FIRST_PRESS_MS", PLAN_DIALOG_FIRST_PRESS_MS),
|
|
4834
|
-
intervalMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_INTERVAL_MS", PLAN_DIALOG_INTERVAL_MS),
|
|
4835
|
-
slowIntervalMs: envMs(
|
|
4836
|
-
"CONVEYOR_PTY_PLAN_DIALOG_SLOW_INTERVAL_MS",
|
|
4837
|
-
PLAN_DIALOG_SLOW_INTERVAL_MS
|
|
4838
|
-
),
|
|
4839
|
-
fastWindowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FAST_WINDOW_MS", PLAN_DIALOG_FAST_WINDOW_MS),
|
|
4840
|
-
windowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_WINDOW_MS", PLAN_DIALOG_WINDOW_MS)
|
|
4841
|
-
};
|
|
4842
|
-
}
|
|
4843
|
-
function turnOptionsFrom(options) {
|
|
4844
|
-
return {
|
|
4845
|
-
canUseTool: options.canUseTool,
|
|
4846
|
-
promptDelivery: options.promptDelivery,
|
|
4847
|
-
planDialogAutoAccept: options.planDialogAutoAccept,
|
|
4848
|
-
abortController: options.abortController
|
|
4849
|
-
};
|
|
4850
|
-
}
|
|
4851
|
-
function isRecord3(value) {
|
|
4852
|
-
return typeof value === "object" && value !== null;
|
|
4853
|
-
}
|
|
4854
|
-
function extractSpawn(mod) {
|
|
4855
|
-
if (!isRecord3(mod)) return null;
|
|
4856
|
-
if (typeof mod.spawn === "function") return mod.spawn;
|
|
4857
|
-
const def = mod.default;
|
|
4858
|
-
if (isRecord3(def) && typeof def.spawn === "function") return def.spawn;
|
|
4859
|
-
return null;
|
|
4860
|
-
}
|
|
4861
|
-
async function loadPtySpawn() {
|
|
4862
|
-
const mod = await import("node-pty");
|
|
4863
|
-
const spawn2 = extractSpawn(mod);
|
|
4864
|
-
if (!spawn2) throw new Error("node-pty: spawn export not found");
|
|
4865
|
-
return spawn2;
|
|
4866
|
-
}
|
|
4867
|
-
function inheritedEnv(socketPath) {
|
|
4868
|
-
const env = {};
|
|
4869
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
4870
|
-
if (typeof value === "string") env[key] = value;
|
|
4871
|
-
}
|
|
4872
|
-
if (env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
4873
|
-
delete env.ANTHROPIC_API_KEY;
|
|
4874
|
-
}
|
|
4875
|
-
if (socketPath) {
|
|
4876
|
-
env.CONVEYOR_HOOK_SOCKET = socketPath;
|
|
4877
|
-
}
|
|
4878
|
-
env.MCP_TIMEOUT ??= "60000";
|
|
4879
|
-
env.MCP_TOOL_TIMEOUT ??= "180000";
|
|
4880
|
-
return env;
|
|
4881
|
-
}
|
|
4882
|
-
function buildPromptBytes(text) {
|
|
4883
|
-
return `\x1B[200~${text}\x1B[201~`;
|
|
4884
|
-
}
|
|
4885
|
-
function renderPromptContentText(content) {
|
|
4886
|
-
return content.map((block) => {
|
|
4887
|
-
const b = block;
|
|
4888
|
-
if (b?.type === "text" && typeof b.text === "string") return b.text;
|
|
4889
|
-
if (b?.type === "image") {
|
|
4890
|
-
return `[Image attachment \u2014 use list_task_files / get_attachment to view]`;
|
|
4891
|
-
}
|
|
4892
|
-
return JSON.stringify(block);
|
|
4893
|
-
}).join("\n\n");
|
|
4894
|
-
}
|
|
4895
|
-
async function transcriptSize(path4) {
|
|
4896
|
-
try {
|
|
4897
|
-
return (await stat2(path4)).size;
|
|
4898
|
-
} catch {
|
|
4899
|
-
return 0;
|
|
4900
|
-
}
|
|
4901
|
-
}
|
|
4902
|
-
function parseUserQuestions(input) {
|
|
4903
|
-
if (!Array.isArray(input.questions)) return [];
|
|
4904
|
-
const questions = [];
|
|
4905
|
-
for (const entry of input.questions) {
|
|
4906
|
-
if (!isRecord3(entry)) continue;
|
|
4907
|
-
if (typeof entry.question !== "string") continue;
|
|
4908
|
-
const options = Array.isArray(entry.options) ? entry.options.filter(isRecord3).filter((o) => typeof o.label === "string").map((o) => ({
|
|
4909
|
-
label: o.label,
|
|
4910
|
-
description: typeof o.description === "string" ? o.description : ""
|
|
4911
|
-
})) : [];
|
|
4912
|
-
questions.push({
|
|
4913
|
-
question: entry.question,
|
|
4914
|
-
header: typeof entry.header === "string" ? entry.header : "",
|
|
4915
|
-
options,
|
|
4916
|
-
...typeof entry.multiSelect === "boolean" ? { multiSelect: entry.multiSelect } : {}
|
|
4917
|
-
});
|
|
4918
|
-
}
|
|
4919
|
-
return questions;
|
|
4920
|
-
}
|
|
4921
|
-
|
|
4922
4956
|
// src/harness/pty/adapters/claude.ts
|
|
4923
4957
|
var ClaudeTuiAdapter = class {
|
|
4924
4958
|
id = "claude-code";
|
|
@@ -5029,6 +5063,18 @@ var PtySession = class {
|
|
|
5029
5063
|
// Submit-nudge state (see armSubmitNudge).
|
|
5030
5064
|
pendingSubmitNudge = false;
|
|
5031
5065
|
submitNudgeTimer = null;
|
|
5066
|
+
// Synthetic AskUserQuestion chat-card state. The CLI does NOT flush the
|
|
5067
|
+
// assistant record holding a pending AskUserQuestion tool_use to the
|
|
5068
|
+
// transcript until the questionnaire resolves (verified live on CLI 2.1.209:
|
|
5069
|
+
// dialog parked on screen, transcript untouched) — so a transcript-derived
|
|
5070
|
+
// question card could only ever render AFTER the human answered in the raw
|
|
5071
|
+
// terminal. Instead the PreToolUse hook (which fires at ask time and carries
|
|
5072
|
+
// the full questions input) emits a synthetic `tool_use` chat event under an
|
|
5073
|
+
// `aq-…` id. When the real records eventually flush, the duplicate tool_use
|
|
5074
|
+
// is dropped (FIFO match below) and its tool_result is re-pointed at the
|
|
5075
|
+
// synthetic id so the card flips to answered.
|
|
5076
|
+
pendingSyntheticQuestionIds = [];
|
|
5077
|
+
questionResultRemap = /* @__PURE__ */ new Map();
|
|
5032
5078
|
// Per-turn state: the prompt to feed and the per-turn options subset. Both
|
|
5033
5079
|
// start from the constructor args (turn 1) and are replaced by beginTurn.
|
|
5034
5080
|
turnPrompt;
|
|
@@ -5150,6 +5196,7 @@ var PtySession = class {
|
|
|
5150
5196
|
this.passiveSignaled = false;
|
|
5151
5197
|
this.disarmSubmitNudge();
|
|
5152
5198
|
this.disarmPlanDialogAutoAccept();
|
|
5199
|
+
this.closeSyntheticQuestionCards();
|
|
5153
5200
|
}
|
|
5154
5201
|
/**
|
|
5155
5202
|
* (Re)register the abort→teardown listener on the current turn's controller,
|
|
@@ -5181,6 +5228,7 @@ var PtySession = class {
|
|
|
5181
5228
|
*/
|
|
5182
5229
|
endTurn(clean) {
|
|
5183
5230
|
this.lastTurnCleanResult = clean;
|
|
5231
|
+
this.closeSyntheticQuestionCards();
|
|
5184
5232
|
this.activeQueue?.close();
|
|
5185
5233
|
this.activeQueue = null;
|
|
5186
5234
|
if (this.abortHandler && this.turn.abortController) {
|
|
@@ -5255,17 +5303,72 @@ var PtySession = class {
|
|
|
5255
5303
|
const transcriptPath = sessionTranscriptPath(this.options.cwd, sessionId);
|
|
5256
5304
|
await mkdir3(dirname(transcriptPath), { recursive: true });
|
|
5257
5305
|
const startOffset = this.resume ? await transcriptSize(transcriptPath) : 0;
|
|
5258
|
-
const sendChat = this.bridge?.sendChatEvent?.bind(this.bridge);
|
|
5259
5306
|
this.tailer = new JsonlTailer(
|
|
5260
5307
|
transcriptPath,
|
|
5261
5308
|
(event) => this.handleTranscriptEvent(event),
|
|
5262
|
-
|
|
5263
|
-
for (const chatEvent of mapChatRecords(raw)) sendChat(chatEvent);
|
|
5264
|
-
} : void 0
|
|
5309
|
+
typeof this.bridge?.sendChatEvent === "function" ? (raw) => this.relayChatRecord(raw) : void 0
|
|
5265
5310
|
);
|
|
5266
5311
|
this.tailer.start(startOffset);
|
|
5267
5312
|
return { settingsPath, socketPath };
|
|
5268
5313
|
}
|
|
5314
|
+
/**
|
|
5315
|
+
* Project a tailed transcript record to chat events, reconciling them with
|
|
5316
|
+
* any synthetic question card already emitted at hook time: the flushed
|
|
5317
|
+
* AskUserQuestion `tool_use` duplicate is dropped (its real id remembered),
|
|
5318
|
+
* and the paired `tool_result` is re-pointed at the synthetic id so the
|
|
5319
|
+
* live-rendered card is the one that flips to answered.
|
|
5320
|
+
*/
|
|
5321
|
+
relayChatRecord(raw) {
|
|
5322
|
+
for (const event of mapChatRecords(raw)) {
|
|
5323
|
+
if (event.kind === "tool_use" && event.name === "AskUserQuestion") {
|
|
5324
|
+
const syntheticId = this.pendingSyntheticQuestionIds.shift();
|
|
5325
|
+
if (syntheticId) {
|
|
5326
|
+
if (event.id) this.questionResultRemap.set(event.id, syntheticId);
|
|
5327
|
+
continue;
|
|
5328
|
+
}
|
|
5329
|
+
} else if (event.kind === "tool_result" && event.toolUseId) {
|
|
5330
|
+
const syntheticId = this.questionResultRemap.get(event.toolUseId);
|
|
5331
|
+
if (syntheticId) {
|
|
5332
|
+
this.questionResultRemap.delete(event.toolUseId);
|
|
5333
|
+
this.sendChatEvent({ ...event, toolUseId: syntheticId });
|
|
5334
|
+
continue;
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
this.sendChatEvent(event);
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
sendChatEvent(event) {
|
|
5341
|
+
this.bridge?.sendChatEvent?.(event);
|
|
5342
|
+
}
|
|
5343
|
+
/** Render the question card in the web chat NOW — at hook time — instead of
|
|
5344
|
+
* whenever the CLI flushes the transcript records (which is only after the
|
|
5345
|
+
* questionnaire resolves; see the field comment). */
|
|
5346
|
+
emitSyntheticQuestionCard(questions) {
|
|
5347
|
+
if (questions.length === 0 || typeof this.bridge?.sendChatEvent !== "function") return;
|
|
5348
|
+
const id = `aq-${randomUUID2()}`;
|
|
5349
|
+
this.pendingSyntheticQuestionIds.push(id);
|
|
5350
|
+
this.sendChatEvent({
|
|
5351
|
+
kind: "tool_use",
|
|
5352
|
+
name: "AskUserQuestion",
|
|
5353
|
+
input: compactQuestionsJson(questions),
|
|
5354
|
+
id
|
|
5355
|
+
});
|
|
5356
|
+
}
|
|
5357
|
+
/**
|
|
5358
|
+
* Close any still-open synthetic question cards. The questionnaire can only
|
|
5359
|
+
* outlive its card via a path that never flushes the paired records — Esc /
|
|
5360
|
+
* interrupt, a superseding turn, or process teardown — so an answering
|
|
5361
|
+
* tool_result will never arrive for these ids; emit one so the web card
|
|
5362
|
+
* stops soliciting input for a dialog that no longer exists.
|
|
5363
|
+
*/
|
|
5364
|
+
closeSyntheticQuestionCards() {
|
|
5365
|
+
const orphaned = [...this.pendingSyntheticQuestionIds, ...this.questionResultRemap.values()];
|
|
5366
|
+
this.pendingSyntheticQuestionIds = [];
|
|
5367
|
+
this.questionResultRemap.clear();
|
|
5368
|
+
for (const toolUseId of orphaned) {
|
|
5369
|
+
this.sendChatEvent({ kind: "tool_result", toolUseId, output: "", isError: false });
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5269
5372
|
writeStdin(text) {
|
|
5270
5373
|
this.pty?.write(text);
|
|
5271
5374
|
}
|
|
@@ -5299,6 +5402,7 @@ var PtySession = class {
|
|
|
5299
5402
|
this._toreDown = true;
|
|
5300
5403
|
this.disarmPlanDialogAutoAccept();
|
|
5301
5404
|
this.disarmSubmitNudge();
|
|
5405
|
+
this.closeSyntheticQuestionCards();
|
|
5302
5406
|
this.unsubInput?.();
|
|
5303
5407
|
this.unsubInput = null;
|
|
5304
5408
|
this.unsubResize?.();
|
|
@@ -5469,10 +5573,9 @@ var PtySession = class {
|
|
|
5469
5573
|
if (request.tool_name === "AskUserQuestion") {
|
|
5470
5574
|
this.disarmSubmitNudge();
|
|
5471
5575
|
this.disarmPlanDialogAutoAccept();
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
});
|
|
5576
|
+
const questions = parseUserQuestions(request.tool_input);
|
|
5577
|
+
this.pushEvent({ type: "user_question", questions });
|
|
5578
|
+
this.emitSyntheticQuestionCard(questions);
|
|
5476
5579
|
return { decision: "allow" };
|
|
5477
5580
|
}
|
|
5478
5581
|
const canUseTool = this.turn.canUseTool;
|
|
@@ -7582,7 +7685,16 @@ function buildForceUpdateTaskStatusTool(connection) {
|
|
|
7582
7685
|
"force_update_task_status",
|
|
7583
7686
|
"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.",
|
|
7584
7687
|
{
|
|
7585
|
-
status: z9.enum([
|
|
7688
|
+
status: z9.enum([
|
|
7689
|
+
"Planning",
|
|
7690
|
+
"Open",
|
|
7691
|
+
"InProgress",
|
|
7692
|
+
"ReviewPR",
|
|
7693
|
+
"ReviewDev",
|
|
7694
|
+
"ReviewLive",
|
|
7695
|
+
"Complete",
|
|
7696
|
+
"Cancelled"
|
|
7697
|
+
]).describe("The new status for the task"),
|
|
7586
7698
|
task_id: z9.string().optional().describe("Child task ID to update. Omit to update the current task.")
|
|
7587
7699
|
},
|
|
7588
7700
|
async ({ status, task_id }) => {
|
|
@@ -8399,42 +8511,52 @@ function buildPmTools(connection, options) {
|
|
|
8399
8511
|
// src/tools/discovery-tools.ts
|
|
8400
8512
|
import { z as z13 } from "zod";
|
|
8401
8513
|
var SP_DESCRIPTION2 = "Story point value (1=Common, 2=Magic, 3=Rare, 5=Unique). The key is 'storyPointValue' \u2014 not 'storyPoints'.";
|
|
8402
|
-
var VALID_PROPERTY_KEYS = "title, storyPointValue, tagNames, githubPRUrl, githubBranch";
|
|
8514
|
+
var VALID_PROPERTY_KEYS = "title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk";
|
|
8515
|
+
function describeUpdatedFields(p) {
|
|
8516
|
+
const fields = [];
|
|
8517
|
+
if (p.title !== void 0) fields.push(`title to "${p.title}"`);
|
|
8518
|
+
if (p.storyPointValue !== void 0) fields.push(`story points to ${p.storyPointValue}`);
|
|
8519
|
+
if (p.tagNames !== void 0) fields.push(`tags (${p.tagNames.length} tag(s))`);
|
|
8520
|
+
if (p.githubPRUrl !== void 0) fields.push(`PR link to "${p.githubPRUrl}"`);
|
|
8521
|
+
if (p.githubBranch !== void 0) fields.push(`branch to "${p.githubBranch}"`);
|
|
8522
|
+
if (p.risk !== void 0) fields.push(`risk to ${p.risk ?? "cleared"}`);
|
|
8523
|
+
return fields;
|
|
8524
|
+
}
|
|
8403
8525
|
function buildDiscoveryTools(connection) {
|
|
8404
8526
|
return [
|
|
8405
8527
|
defineTool(
|
|
8406
8528
|
"update_task_properties",
|
|
8407
|
-
"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.",
|
|
8529
|
+
"Set one or more task properties in a single call. Valid keys: title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk. All are optional \u2014 include only the ones you want to update (at least one). Unknown keys are rejected.",
|
|
8408
8530
|
{
|
|
8409
8531
|
title: z13.string().optional().describe("The new task title"),
|
|
8410
8532
|
storyPointValue: z13.number().optional().describe(SP_DESCRIPTION2),
|
|
8411
8533
|
tagNames: z13.array(z13.string()).optional().describe("Array of tag names to assign"),
|
|
8412
8534
|
githubPRUrl: z13.string().url().optional().describe("GitHub pull request URL to link to this task"),
|
|
8413
|
-
githubBranch: z13.string().optional().describe("Set the GitHub branch name for this task (e.g. 'conveyor/my-feature-abc123')")
|
|
8535
|
+
githubBranch: z13.string().optional().describe("Set the GitHub branch name for this task (e.g. 'conveyor/my-feature-abc123')"),
|
|
8536
|
+
risk: z13.enum(["critical", "high", "medium", "low"]).nullable().optional().describe(
|
|
8537
|
+
"Risk level \u2014 how much important surface the task touches (critical/high/medium/low). Pass null to clear."
|
|
8538
|
+
)
|
|
8414
8539
|
},
|
|
8415
|
-
async ({ title, storyPointValue, tagNames, githubPRUrl, githubBranch }) => {
|
|
8540
|
+
async ({ title, storyPointValue, tagNames, githubPRUrl, githubBranch, risk }) => {
|
|
8416
8541
|
try {
|
|
8417
|
-
const
|
|
8418
|
-
|
|
8542
|
+
const params = {
|
|
8543
|
+
title,
|
|
8544
|
+
storyPointValue,
|
|
8545
|
+
tagNames,
|
|
8546
|
+
githubPRUrl,
|
|
8547
|
+
githubBranch,
|
|
8548
|
+
risk
|
|
8549
|
+
};
|
|
8550
|
+
const updatedFields = describeUpdatedFields(params);
|
|
8551
|
+
if (updatedFields.length === 0) {
|
|
8419
8552
|
return textResult(
|
|
8420
8553
|
`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'.)`
|
|
8421
8554
|
);
|
|
8422
8555
|
}
|
|
8423
8556
|
await connection.call("updateTaskProperties", {
|
|
8424
8557
|
sessionId: connection.sessionId,
|
|
8425
|
-
|
|
8426
|
-
storyPointValue,
|
|
8427
|
-
tagNames,
|
|
8428
|
-
githubPRUrl,
|
|
8429
|
-
githubBranch
|
|
8558
|
+
...params
|
|
8430
8559
|
});
|
|
8431
|
-
const updatedFields = [];
|
|
8432
|
-
if (title !== void 0) updatedFields.push(`title to "${title}"`);
|
|
8433
|
-
if (storyPointValue !== void 0)
|
|
8434
|
-
updatedFields.push(`story points to ${storyPointValue}`);
|
|
8435
|
-
if (tagNames !== void 0) updatedFields.push(`tags (${tagNames.length} tag(s))`);
|
|
8436
|
-
if (githubPRUrl !== void 0) updatedFields.push(`PR link to "${githubPRUrl}"`);
|
|
8437
|
-
if (githubBranch !== void 0) updatedFields.push(`branch to "${githubBranch}"`);
|
|
8438
8560
|
return textResult(`Task properties updated: ${updatedFields.join(", ")}`);
|
|
8439
8561
|
} catch (error) {
|
|
8440
8562
|
return textResult(
|
|
@@ -12107,12 +12229,12 @@ export {
|
|
|
12107
12229
|
DEFAULT_LIFECYCLE_CONFIG,
|
|
12108
12230
|
Lifecycle,
|
|
12109
12231
|
defineTool,
|
|
12110
|
-
cleanTerminalOutput,
|
|
12111
|
-
buildSynthesizedCredentials,
|
|
12112
|
-
claudeJsonPath,
|
|
12113
12232
|
loadPtySpawn,
|
|
12114
12233
|
inheritedEnv,
|
|
12115
12234
|
buildPromptBytes,
|
|
12235
|
+
cleanTerminalOutput,
|
|
12236
|
+
buildSynthesizedCredentials,
|
|
12237
|
+
claudeJsonPath,
|
|
12116
12238
|
ClaudeTuiAdapter,
|
|
12117
12239
|
createServiceLogger,
|
|
12118
12240
|
PtyHarness,
|
|
@@ -12150,4 +12272,4 @@ export {
|
|
|
12150
12272
|
runStartCommand,
|
|
12151
12273
|
unshallowRepo
|
|
12152
12274
|
};
|
|
12153
|
-
//# sourceMappingURL=chunk-
|
|
12275
|
+
//# sourceMappingURL=chunk-PXQJ4NVO.js.map
|