@rallycry/conveyor-agent 9.0.2 → 9.1.0
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-5W6MHROF.js → chunk-P3QCTUHC.js} +135 -26
- package/dist/chunk-P3QCTUHC.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5W6MHROF.js.map +0 -1
|
@@ -541,24 +541,23 @@ var AgentConnection = class _AgentConnection {
|
|
|
541
541
|
};
|
|
542
542
|
}
|
|
543
543
|
// ── Convenience methods (thin wrappers around call / emit) ─────────
|
|
544
|
-
async emitStatus(status) {
|
|
544
|
+
async emitStatus(status, reason) {
|
|
545
545
|
this.lastEmittedStatus = status;
|
|
546
546
|
await this.flushEvents();
|
|
547
|
+
const payload = {
|
|
548
|
+
sessionId: this.config.sessionId,
|
|
549
|
+
status,
|
|
550
|
+
...reason ? { reason } : {}
|
|
551
|
+
};
|
|
547
552
|
const AWAIT_STATUSES = ["idle", "waiting_for_input", "connected"];
|
|
548
553
|
if (AWAIT_STATUSES.includes(status)) {
|
|
549
554
|
try {
|
|
550
|
-
await this.call("reportAgentStatus",
|
|
551
|
-
sessionId: this.config.sessionId,
|
|
552
|
-
status
|
|
553
|
-
});
|
|
555
|
+
await this.call("reportAgentStatus", payload);
|
|
554
556
|
this.lastReportedStatus = status;
|
|
555
557
|
} catch {
|
|
556
558
|
}
|
|
557
559
|
} else {
|
|
558
|
-
void this.call("reportAgentStatus", {
|
|
559
|
-
sessionId: this.config.sessionId,
|
|
560
|
-
status
|
|
561
|
-
}).then(() => {
|
|
560
|
+
void this.call("reportAgentStatus", payload).then(() => {
|
|
562
561
|
this.lastReportedStatus = status;
|
|
563
562
|
}).catch(() => {
|
|
564
563
|
});
|
|
@@ -1058,7 +1057,18 @@ function restoreWipSnapshot(cwd, branch) {
|
|
|
1058
1057
|
stdio: ["ignore", "pipe", "ignore"]
|
|
1059
1058
|
}).toString().trim();
|
|
1060
1059
|
const head = execSync("git rev-parse HEAD", { cwd, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
1061
|
-
if (parent !== head)
|
|
1060
|
+
if (parent !== head) {
|
|
1061
|
+
try {
|
|
1062
|
+
execSync(`git stash apply ${sha}`, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
1063
|
+
return "applied";
|
|
1064
|
+
} catch {
|
|
1065
|
+
try {
|
|
1066
|
+
execSync("git reset --merge", { cwd, stdio: "ignore" });
|
|
1067
|
+
} catch {
|
|
1068
|
+
}
|
|
1069
|
+
return "stale";
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1062
1072
|
execSync(`git stash apply ${sha}`, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
1063
1073
|
return "applied";
|
|
1064
1074
|
} catch {
|
|
@@ -1276,6 +1286,7 @@ const net = require("node:net");
|
|
|
1276
1286
|
const crypto = require("node:crypto");
|
|
1277
1287
|
|
|
1278
1288
|
const PRE_TOOL_USE_TIMEOUT_MS = 110000;
|
|
1289
|
+
const ASK_USER_QUESTION_TIMEOUT_MS = 5000;
|
|
1279
1290
|
|
|
1280
1291
|
let raw = "";
|
|
1281
1292
|
process.stdin.setEncoding("utf8");
|
|
@@ -1347,17 +1358,26 @@ function preToolUse(payload) {
|
|
|
1347
1358
|
);
|
|
1348
1359
|
process.exit(0);
|
|
1349
1360
|
};
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1361
|
+
// AskUserQuestion is observe-only (status reporting) \u2014 fail OPEN so a
|
|
1362
|
+
// missing/slow socket never denies the questionnaire. Everything else
|
|
1363
|
+
// (ExitPlanMode) is a Conveyor gate \u2014 fail CLOSED.
|
|
1364
|
+
const failOpen = payload.tool_name === "AskUserQuestion";
|
|
1365
|
+
const respondUnavailable = () =>
|
|
1366
|
+
failOpen
|
|
1367
|
+
? respond("allow")
|
|
1368
|
+
: respond(
|
|
1369
|
+
"deny",
|
|
1370
|
+
"Conveyor validation is unavailable right now. Wait a moment and call the tool again.",
|
|
1371
|
+
);
|
|
1355
1372
|
if (!socketPath) {
|
|
1356
|
-
|
|
1373
|
+
respondUnavailable();
|
|
1357
1374
|
return;
|
|
1358
1375
|
}
|
|
1359
1376
|
const id = crypto.randomBytes(8).toString("hex");
|
|
1360
|
-
const timer = setTimeout(
|
|
1377
|
+
const timer = setTimeout(
|
|
1378
|
+
respondUnavailable,
|
|
1379
|
+
failOpen ? ASK_USER_QUESTION_TIMEOUT_MS : PRE_TOOL_USE_TIMEOUT_MS,
|
|
1380
|
+
);
|
|
1361
1381
|
const client = net.connect(socketPath, () => {
|
|
1362
1382
|
client.write(
|
|
1363
1383
|
JSON.stringify({
|
|
@@ -1392,11 +1412,11 @@ function preToolUse(payload) {
|
|
|
1392
1412
|
});
|
|
1393
1413
|
client.on("error", () => {
|
|
1394
1414
|
clearTimeout(timer);
|
|
1395
|
-
|
|
1415
|
+
respondUnavailable();
|
|
1396
1416
|
});
|
|
1397
1417
|
client.on("close", () => {
|
|
1398
1418
|
clearTimeout(timer);
|
|
1399
|
-
|
|
1419
|
+
respondUnavailable();
|
|
1400
1420
|
});
|
|
1401
1421
|
}
|
|
1402
1422
|
`;
|
|
@@ -1434,6 +1454,13 @@ async function writeHookSettings(dir) {
|
|
|
1434
1454
|
{
|
|
1435
1455
|
matcher: "ExitPlanMode",
|
|
1436
1456
|
hooks: [{ type: "command", command: `node ${JSON.stringify(helperPath)}`, timeout: 120 }]
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
// Observe-only: lets the session report waiting_for_input the moment
|
|
1460
|
+
// the planning questionnaire renders. The helper fails open for this
|
|
1461
|
+
// tool, so the questionnaire is never blocked by Conveyor.
|
|
1462
|
+
matcher: "AskUserQuestion",
|
|
1463
|
+
hooks: [{ type: "command", command: `node ${JSON.stringify(helperPath)}`, timeout: 30 }]
|
|
1437
1464
|
}
|
|
1438
1465
|
],
|
|
1439
1466
|
PostToolUse: [
|
|
@@ -1671,7 +1698,9 @@ var ConnectAgentRequestSchema = z.object({
|
|
|
1671
1698
|
});
|
|
1672
1699
|
var ReportAgentStatusRequestSchema = z.object({
|
|
1673
1700
|
sessionId: z.string(),
|
|
1674
|
-
status: z.string()
|
|
1701
|
+
status: z.string(),
|
|
1702
|
+
/** Why the agent reports this status (e.g. "user_question" while an AskUserQuestion questionnaire is pending in the TUI). */
|
|
1703
|
+
reason: z.string().optional()
|
|
1675
1704
|
});
|
|
1676
1705
|
var NotifyAgentVersionRequestSchema = z.object({
|
|
1677
1706
|
sessionId: z.string(),
|
|
@@ -1986,6 +2015,20 @@ var GetProjectTaskSessionsRequestSchema = z2.object({
|
|
|
1986
2015
|
projectId: z2.string(),
|
|
1987
2016
|
taskId: z2.string()
|
|
1988
2017
|
});
|
|
2018
|
+
var QueryProjectGcpLogsRequestSchema = z2.object({
|
|
2019
|
+
projectId: z2.string(),
|
|
2020
|
+
env: z2.enum(["prod", "dev", "claudespace"]).optional(),
|
|
2021
|
+
severity: z2.enum(["DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "CRITICAL", "ALERT", "EMERGENCY"]).optional(),
|
|
2022
|
+
services: z2.array(z2.string().min(1).max(200)).max(25).optional(),
|
|
2023
|
+
sqlInstances: z2.array(z2.string().min(1).max(200)).max(25).optional(),
|
|
2024
|
+
allServices: z2.boolean().optional(),
|
|
2025
|
+
search: z2.string().max(256).optional(),
|
|
2026
|
+
filter: z2.string().max(1e3).optional(),
|
|
2027
|
+
startTime: z2.string().optional(),
|
|
2028
|
+
endTime: z2.string().optional(),
|
|
2029
|
+
limit: z2.number().int().min(1).max(200).optional().default(50),
|
|
2030
|
+
pageToken: z2.string().max(4096).optional()
|
|
2031
|
+
});
|
|
1989
2032
|
var StartProjectBuildRequestSchema = z2.object({
|
|
1990
2033
|
projectId: z2.string(),
|
|
1991
2034
|
taskId: z2.string(),
|
|
@@ -2164,6 +2207,7 @@ var CreateProjectSuggestionRequestSchema = z2.object({
|
|
|
2164
2207
|
tagNames: z2.array(z2.string()).optional(),
|
|
2165
2208
|
requestingUserId: z2.string().optional()
|
|
2166
2209
|
});
|
|
2210
|
+
var AGENT_STATUS_REASON_USER_QUESTION = "user_question";
|
|
2167
2211
|
var TASK_CHAT_HISTORY_LIMIT = 20;
|
|
2168
2212
|
var PM_CHAT_HISTORY_LIMIT = 40;
|
|
2169
2213
|
var AGENT_CHAT_HISTORY_FETCH_LIMIT = Math.max(TASK_CHAT_HISTORY_LIMIT, PM_CHAT_HISTORY_LIMIT) + 10;
|
|
@@ -3096,6 +3140,25 @@ async function transcriptSize(path) {
|
|
|
3096
3140
|
return 0;
|
|
3097
3141
|
}
|
|
3098
3142
|
}
|
|
3143
|
+
function parseUserQuestions(input) {
|
|
3144
|
+
if (!Array.isArray(input.questions)) return [];
|
|
3145
|
+
const questions = [];
|
|
3146
|
+
for (const entry of input.questions) {
|
|
3147
|
+
if (!isRecord2(entry)) continue;
|
|
3148
|
+
if (typeof entry.question !== "string") continue;
|
|
3149
|
+
const options = Array.isArray(entry.options) ? entry.options.filter(isRecord2).filter((o) => typeof o.label === "string").map((o) => ({
|
|
3150
|
+
label: o.label,
|
|
3151
|
+
description: typeof o.description === "string" ? o.description : ""
|
|
3152
|
+
})) : [];
|
|
3153
|
+
questions.push({
|
|
3154
|
+
question: entry.question,
|
|
3155
|
+
header: typeof entry.header === "string" ? entry.header : "",
|
|
3156
|
+
options,
|
|
3157
|
+
...typeof entry.multiSelect === "boolean" ? { multiSelect: entry.multiSelect } : {}
|
|
3158
|
+
});
|
|
3159
|
+
}
|
|
3160
|
+
return questions;
|
|
3161
|
+
}
|
|
3099
3162
|
var PtySession = class {
|
|
3100
3163
|
constructor(prompt, options, resume, bridge) {
|
|
3101
3164
|
this.prompt = prompt;
|
|
@@ -3373,11 +3436,17 @@ var PtySession = class {
|
|
|
3373
3436
|
}
|
|
3374
3437
|
/**
|
|
3375
3438
|
* PreToolUse request from the hook helper → the runner's `canUseTool`
|
|
3376
|
-
* verdict.
|
|
3377
|
-
*
|
|
3378
|
-
*
|
|
3439
|
+
* verdict. ExitPlanMode is the Conveyor plan-exit gate (validation +
|
|
3440
|
+
* identification trigger run inside the callback); AskUserQuestion is
|
|
3441
|
+
* observed and always allowed. Absent callback → allow (mirrors the SDK
|
|
3442
|
+
* default).
|
|
3379
3443
|
*/
|
|
3380
3444
|
async handlePreToolUse(request) {
|
|
3445
|
+
if (request.tool_name === "AskUserQuestion") {
|
|
3446
|
+
this.disarmSubmitNudge();
|
|
3447
|
+
this.queue.push({ type: "user_question", questions: parseUserQuestions(request.tool_input) });
|
|
3448
|
+
return { decision: "allow" };
|
|
3449
|
+
}
|
|
3381
3450
|
const canUseTool = this.options.canUseTool;
|
|
3382
3451
|
let verdict;
|
|
3383
3452
|
if (canUseTool) {
|
|
@@ -6445,6 +6514,44 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
|
|
|
6445
6514
|
}
|
|
6446
6515
|
|
|
6447
6516
|
// src/execution/event-processor.ts
|
|
6517
|
+
function hasAskUserQuestionBlock(event) {
|
|
6518
|
+
return event.message.content.some((b) => b.type === "tool_use" && b.name === "AskUserQuestion");
|
|
6519
|
+
}
|
|
6520
|
+
async function armQuestionPending(host, state) {
|
|
6521
|
+
state.questionPending = true;
|
|
6522
|
+
await host.connection.emitStatus("waiting_for_input", AGENT_STATUS_REASON_USER_QUESTION);
|
|
6523
|
+
await host.callbacks.onStatusChange("waiting_for_input");
|
|
6524
|
+
}
|
|
6525
|
+
async function clearQuestionPending(host, state, options) {
|
|
6526
|
+
if (!state.questionPending) return;
|
|
6527
|
+
state.questionPending = false;
|
|
6528
|
+
if (options.emitRunning) {
|
|
6529
|
+
await host.connection.emitStatus("running");
|
|
6530
|
+
await host.callbacks.onStatusChange("running");
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
async function applyQuestionTransitions(event, host, state) {
|
|
6534
|
+
switch (event.type) {
|
|
6535
|
+
case "user_question":
|
|
6536
|
+
await armQuestionPending(host, state);
|
|
6537
|
+
return;
|
|
6538
|
+
case "assistant":
|
|
6539
|
+
if (!hasAskUserQuestionBlock(event)) {
|
|
6540
|
+
await clearQuestionPending(host, state, { emitRunning: true });
|
|
6541
|
+
}
|
|
6542
|
+
return;
|
|
6543
|
+
case "tool_progress":
|
|
6544
|
+
if (event.tool_name === "AskUserQuestion") {
|
|
6545
|
+
await clearQuestionPending(host, state, { emitRunning: true });
|
|
6546
|
+
}
|
|
6547
|
+
return;
|
|
6548
|
+
case "result":
|
|
6549
|
+
await clearQuestionPending(host, state, { emitRunning: false });
|
|
6550
|
+
return;
|
|
6551
|
+
default:
|
|
6552
|
+
break;
|
|
6553
|
+
}
|
|
6554
|
+
}
|
|
6448
6555
|
function stopTypingIfNeeded(host, isTyping) {
|
|
6449
6556
|
if (isTyping) host.connection.sendTypingStop();
|
|
6450
6557
|
}
|
|
@@ -6524,13 +6631,14 @@ async function processEvents(events, context, host) {
|
|
|
6524
6631
|
staleSession: void 0,
|
|
6525
6632
|
authError: void 0,
|
|
6526
6633
|
lastAssistantUsage: void 0,
|
|
6527
|
-
turnToolCalls: []
|
|
6634
|
+
turnToolCalls: [],
|
|
6635
|
+
questionPending: false
|
|
6528
6636
|
};
|
|
6529
6637
|
for await (const event of events) {
|
|
6530
6638
|
if (host.isStopped()) break;
|
|
6531
6639
|
flushPendingToolCalls(host, state.turnToolCalls);
|
|
6532
6640
|
const now = Date.now();
|
|
6533
|
-
if (now - lastStatusEmit >= STATUS_REEMIT_INTERVAL_MS) {
|
|
6641
|
+
if (now - lastStatusEmit >= STATUS_REEMIT_INTERVAL_MS && !state.questionPending) {
|
|
6534
6642
|
host.connection.emitStatus("running");
|
|
6535
6643
|
lastStatusEmit = now;
|
|
6536
6644
|
}
|
|
@@ -6538,6 +6646,7 @@ async function processEvents(events, context, host) {
|
|
|
6538
6646
|
stopTypingIfNeeded(host, state.isTyping);
|
|
6539
6647
|
return { retriable: false, modeRestart: true };
|
|
6540
6648
|
}
|
|
6649
|
+
await applyQuestionTransitions(event, host, state);
|
|
6541
6650
|
switch (event.type) {
|
|
6542
6651
|
case "system":
|
|
6543
6652
|
await processSystemCase(event, host, context, state);
|
|
@@ -8882,4 +8991,4 @@ export {
|
|
|
8882
8991
|
runStartCommand,
|
|
8883
8992
|
unshallowRepo
|
|
8884
8993
|
};
|
|
8885
|
-
//# sourceMappingURL=chunk-
|
|
8994
|
+
//# sourceMappingURL=chunk-P3QCTUHC.js.map
|