@rallycry/conveyor-agent 8.8.1 → 8.10.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-4ZZXIHJV.js → chunk-D7JSB2IF.js} +73 -25
- package/dist/chunk-D7JSB2IF.js.map +1 -0
- package/dist/{chunk-EOGZOS2H.js → chunk-TN2YYT2V.js} +1 -1
- package/dist/{chunk-EOGZOS2H.js.map → chunk-TN2YYT2V.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +27 -3
- package/dist/index.js +2 -2
- package/dist/{tag-audit-handler-S4VT47XG.js → tag-audit-handler-X3LEX63H.js} +2 -2
- package/dist/{task-audit-handler-QK7S4LWO.js → task-audit-handler-BRCXB5V6.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-4ZZXIHJV.js.map +0 -1
- /package/dist/{tag-audit-handler-S4VT47XG.js.map → tag-audit-handler-X3LEX63H.js.map} +0 -0
- /package/dist/{task-audit-handler-QK7S4LWO.js.map → task-audit-handler-BRCXB5V6.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
ensureClaudeCredentials,
|
|
13
13
|
removeConveyorCredentials,
|
|
14
14
|
sessionTranscriptPath
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-TN2YYT2V.js";
|
|
16
16
|
|
|
17
17
|
// src/setup/bootstrap.ts
|
|
18
18
|
var BOOTSTRAP_TIMEOUT_MS = 3e4;
|
|
@@ -1878,6 +1878,10 @@ var SearchProjectTasksRequestSchema = z2.object({
|
|
|
1878
1878
|
tagNames: z2.array(z2.string()).optional(),
|
|
1879
1879
|
searchQuery: z2.string().optional(),
|
|
1880
1880
|
statusFilters: z2.array(z2.string()).optional(),
|
|
1881
|
+
// Card types to include. Omitted/empty → defaults to ["task"] in the handler so
|
|
1882
|
+
// search doesn't surface incidents/suggestions unless asked. Enum validation lives
|
|
1883
|
+
// at the MCP tool layer (mirrors statusFilters).
|
|
1884
|
+
typeFilters: z2.array(z2.string()).optional(),
|
|
1881
1885
|
assigneeId: z2.string().optional(),
|
|
1882
1886
|
unassigned: z2.boolean().optional(),
|
|
1883
1887
|
limit: z2.number().int().positive().optional().default(20)
|
|
@@ -7402,7 +7406,7 @@ var ExplorationTracker = class {
|
|
|
7402
7406
|
// src/runner/query-bridge.ts
|
|
7403
7407
|
var logger3 = createServiceLogger("QueryBridge");
|
|
7404
7408
|
function resolveHarnessKind() {
|
|
7405
|
-
return process.env.
|
|
7409
|
+
return process.env.CONVEYOR_FORCE_SDK_CARDS === "1" ? "sdk" : "pty";
|
|
7406
7410
|
}
|
|
7407
7411
|
function buildPtyBridge(connection) {
|
|
7408
7412
|
return {
|
|
@@ -7431,7 +7435,8 @@ var QueryBridge = class {
|
|
|
7431
7435
|
runnerConfig;
|
|
7432
7436
|
callbacks;
|
|
7433
7437
|
harness;
|
|
7434
|
-
/** Which harness drives this bridge ("pty" task chat
|
|
7438
|
+
/** Which harness drives this bridge ("pty" task chat; "sdk" only under the
|
|
7439
|
+
* CONVEYOR_FORCE_SDK_CARDS maintainer override). */
|
|
7435
7440
|
harnessKind;
|
|
7436
7441
|
costTracker;
|
|
7437
7442
|
planSync;
|
|
@@ -7687,6 +7692,9 @@ function handlePullBranch(workDir, branch) {
|
|
|
7687
7692
|
}
|
|
7688
7693
|
|
|
7689
7694
|
// src/runner/session-runner.ts
|
|
7695
|
+
function isPostToChatTool(name) {
|
|
7696
|
+
return typeof name === "string" && (name === "post_to_chat" || name.endsWith("__post_to_chat"));
|
|
7697
|
+
}
|
|
7690
7698
|
var SessionRunner = class _SessionRunner {
|
|
7691
7699
|
connection;
|
|
7692
7700
|
mode;
|
|
@@ -7712,6 +7720,12 @@ var SessionRunner = class _SessionRunner {
|
|
|
7712
7720
|
inputResolver = null;
|
|
7713
7721
|
pendingMessages = [];
|
|
7714
7722
|
prNudgeCount = 0;
|
|
7723
|
+
/** Set when the agent posts a substantive message to the task chat (the
|
|
7724
|
+
* `post_to_chat` tool) during the current turn; reset at the start of every
|
|
7725
|
+
* query. Read by the stuck-detection: an auto agent that finished without a
|
|
7726
|
+
* PR but DID explain itself / ask for help in chat is waiting on a human,
|
|
7727
|
+
* not silently stuck, so it is left attached rather than nudged. */
|
|
7728
|
+
agentSpokeThisTurn = false;
|
|
7715
7729
|
/** Guards overlapping runs of the periodic git flush. */
|
|
7716
7730
|
periodicFlushInFlight = false;
|
|
7717
7731
|
constructor(config, callbacks) {
|
|
@@ -7852,7 +7866,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
7852
7866
|
this.queryBridge.isDiscoveryCompleted = false;
|
|
7853
7867
|
}
|
|
7854
7868
|
if (!this.stopped && this.pendingMessages.length === 0) {
|
|
7855
|
-
await this.
|
|
7869
|
+
await this.maybeHandleStuckAuto();
|
|
7856
7870
|
}
|
|
7857
7871
|
if (!this.stopped) {
|
|
7858
7872
|
process.stderr.write(
|
|
@@ -7925,7 +7939,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
7925
7939
|
continue;
|
|
7926
7940
|
}
|
|
7927
7941
|
if (!this.stopped && this.pendingMessages.length === 0) {
|
|
7928
|
-
await this.
|
|
7942
|
+
await this.maybeHandleStuckAuto();
|
|
7929
7943
|
}
|
|
7930
7944
|
if (!this.stopped) await this.setState("idle");
|
|
7931
7945
|
} else if (this._state === "error") {
|
|
@@ -8116,6 +8130,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8116
8130
|
/** Run queryBridge.execute, swallowing abort errors from stop/softStop. */
|
|
8117
8131
|
async executeQuery(followUpContent, promptDelivery) {
|
|
8118
8132
|
if (!this.fullContext || !this.queryBridge) return;
|
|
8133
|
+
this.agentSpokeThisTurn = false;
|
|
8119
8134
|
try {
|
|
8120
8135
|
await this.queryBridge.execute(this.fullContext, followUpContent, promptDelivery);
|
|
8121
8136
|
} catch (err) {
|
|
@@ -8209,15 +8224,38 @@ var SessionRunner = class _SessionRunner {
|
|
|
8209
8224
|
resolver(null);
|
|
8210
8225
|
}
|
|
8211
8226
|
}
|
|
8212
|
-
// ── Auto-mode
|
|
8213
|
-
static
|
|
8214
|
-
|
|
8227
|
+
// ── Auto-mode stuck detection & nudge ───────────────────────────────
|
|
8228
|
+
static MAX_STUCK_NUDGES = 3;
|
|
8229
|
+
/** The prompt delivered into the live TUI when an auto agent looks stuck. It
|
|
8230
|
+
* must offer BOTH escape routes so the agent never just goes idle. */
|
|
8231
|
+
static STUCK_PROMPT = "You are in Auto mode, your task is still In Progress, and there is no open pull request. Do ONE of these right now: (1) open a pull request with the create_pull_request tool, OR (2) call post_to_chat to explain exactly where you are stuck and what you need from a human. Do not finish or go idle silently.";
|
|
8232
|
+
/**
|
|
8233
|
+
* An auto task is "stuck" when its last turn ended (the call sites run
|
|
8234
|
+
* post-turn, so the TUI is no longer actively working), it has no open PR,
|
|
8235
|
+
* AND the agent did not communicate in chat this turn. If the agent posted a
|
|
8236
|
+
* message (explained itself / asked for help) it is waiting on a human, not
|
|
8237
|
+
* silently stuck, so we leave it attached instead of nudging.
|
|
8238
|
+
*/
|
|
8239
|
+
isAutoStuck() {
|
|
8215
8240
|
if (!this.mode.isAuto || this.stopped) return false;
|
|
8216
8241
|
if (this.queryBridge?.wasRateLimited) return false;
|
|
8217
|
-
if (this.prNudgeCount > _SessionRunner.
|
|
8242
|
+
if (this.prNudgeCount > _SessionRunner.MAX_STUCK_NUDGES) return false;
|
|
8243
|
+
if (this.agentSpokeThisTurn) return false;
|
|
8218
8244
|
if (!this.taskContext) return false;
|
|
8219
8245
|
return this.taskContext.status === "InProgress" && !this.taskContext.githubPRUrl;
|
|
8220
8246
|
}
|
|
8247
|
+
/**
|
|
8248
|
+
* Stop driving the agent and route the core loop into dormant idle —
|
|
8249
|
+
* connected and attachable, but NOT running (so no tokens are spent while it
|
|
8250
|
+
* waits). A human reply (chat or TUI keystroke after the next wake) resumes
|
|
8251
|
+
* it. This replaces the old hard `stop()`: the auto agent must never kill its
|
|
8252
|
+
* own session, so a person can always take over.
|
|
8253
|
+
*/
|
|
8254
|
+
enterDormantForHumanTakeover(message) {
|
|
8255
|
+
this.connection.postChatMessage(message);
|
|
8256
|
+
this.completedThisTurn = true;
|
|
8257
|
+
void this.connection.sendHeartbeat();
|
|
8258
|
+
}
|
|
8221
8259
|
async refreshTaskContext() {
|
|
8222
8260
|
try {
|
|
8223
8261
|
const ctx = await this.connection.call("getTaskContext", {
|
|
@@ -8240,28 +8278,32 @@ var SessionRunner = class _SessionRunner {
|
|
|
8240
8278
|
} catch {
|
|
8241
8279
|
}
|
|
8242
8280
|
}
|
|
8243
|
-
async
|
|
8281
|
+
async maybeHandleStuckAuto() {
|
|
8244
8282
|
await this.refreshTaskContext();
|
|
8245
|
-
if (!this.
|
|
8246
|
-
while (!this.stopped && !this.interrupted && this.
|
|
8283
|
+
if (!this.isAutoStuck()) return;
|
|
8284
|
+
while (!this.stopped && !this.interrupted && this.isAutoStuck()) {
|
|
8247
8285
|
this.prNudgeCount++;
|
|
8248
|
-
if (this.prNudgeCount > _SessionRunner.
|
|
8249
|
-
this.
|
|
8250
|
-
`Auto-mode
|
|
8286
|
+
if (this.prNudgeCount > _SessionRunner.MAX_STUCK_NUDGES) {
|
|
8287
|
+
this.enterDormantForHumanTakeover(
|
|
8288
|
+
`Auto-mode: I couldn't open a PR or get unstuck after ${_SessionRunner.MAX_STUCK_NUDGES} attempts. Staying connected \u2014 reply here or in the terminal and I'll keep working.`
|
|
8251
8289
|
);
|
|
8252
|
-
this.stop();
|
|
8253
8290
|
return;
|
|
8254
8291
|
}
|
|
8255
|
-
const
|
|
8256
|
-
const chatMsg =
|
|
8257
|
-
const prompt = isFirst ? "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR." : `This is reminder ${this.prNudgeCount} of ${_SessionRunner.MAX_PR_NUDGES}. You MUST open a pull request using create_pull_request NOW or explain what is blocking you. Do NOT go idle \u2014 either create the PR or describe the specific blocker.`;
|
|
8292
|
+
const attempt = this.prNudgeCount;
|
|
8293
|
+
const chatMsg = attempt === 1 ? "Auto-nudge: still In Progress with no PR \u2014 prompting the agent to finish or explain where it's stuck..." : `Auto-nudge (attempt ${attempt}/${_SessionRunner.MAX_STUCK_NUDGES}): still no PR \u2014 prompting the agent again...`;
|
|
8258
8294
|
this.connection.postChatMessage(chatMsg);
|
|
8259
8295
|
await this.setState("running");
|
|
8260
|
-
await this.callbacks.onEvent({ type: "pr_nudge", prompt });
|
|
8296
|
+
await this.callbacks.onEvent({ type: "pr_nudge", prompt: _SessionRunner.STUCK_PROMPT });
|
|
8261
8297
|
if (this.interrupted || this.stopped) return;
|
|
8262
|
-
await this.executeQuery(
|
|
8298
|
+
await this.executeQuery(_SessionRunner.STUCK_PROMPT);
|
|
8263
8299
|
if (this.interrupted || this.stopped) return;
|
|
8264
8300
|
await this.refreshTaskContext();
|
|
8301
|
+
if (this.agentSpokeThisTurn && !this.taskContext?.githubPRUrl) {
|
|
8302
|
+
this.enterDormantForHumanTakeover(
|
|
8303
|
+
"Auto-mode: the agent posted an update and is waiting for input. Staying connected \u2014 reply here or in the terminal to continue."
|
|
8304
|
+
);
|
|
8305
|
+
return;
|
|
8306
|
+
}
|
|
8265
8307
|
}
|
|
8266
8308
|
}
|
|
8267
8309
|
// ── Context & bridge construction ────────────────────────────────
|
|
@@ -8324,6 +8366,10 @@ var SessionRunner = class _SessionRunner {
|
|
|
8324
8366
|
return this.callbacks.onStatusChange(status);
|
|
8325
8367
|
},
|
|
8326
8368
|
onEvent: (event) => {
|
|
8369
|
+
const evt = event;
|
|
8370
|
+
if (evt.type === "tool_use" && isPostToChatTool(evt.tool)) {
|
|
8371
|
+
this.agentSpokeThisTurn = true;
|
|
8372
|
+
}
|
|
8327
8373
|
if (event.type === "completed") {
|
|
8328
8374
|
this.completedThisTurn = true;
|
|
8329
8375
|
void this.connection.sendHeartbeat();
|
|
@@ -9394,6 +9440,7 @@ function errorMessage(error) {
|
|
|
9394
9440
|
return error instanceof Error ? error.message : "Unknown error";
|
|
9395
9441
|
}
|
|
9396
9442
|
var DESCRIPTION_PREVIEW_CHARS = 300;
|
|
9443
|
+
var CARD_TYPE_ENUM = ["task", "incident", "suggestion"];
|
|
9397
9444
|
function summarizeTask(task) {
|
|
9398
9445
|
if (typeof task !== "object" || task === null) return task;
|
|
9399
9446
|
const { plan, description, ...rest } = task;
|
|
@@ -9448,11 +9495,12 @@ function buildSearchTasksTool(connection) {
|
|
|
9448
9495
|
const projectId = connection.projectId;
|
|
9449
9496
|
return defineTool(
|
|
9450
9497
|
"search_tasks",
|
|
9451
|
-
"Search
|
|
9498
|
+
"Search cards by tags, text query, status, type, or assignment. Defaults to type=task \u2014 pass typeFilters to include incidents/suggestions. Returns summaries \u2014 plan omitted, description truncated; use get_project_task for full details.",
|
|
9452
9499
|
{
|
|
9453
9500
|
tagNames: z17.array(z17.string()).optional().describe("Filter by tag names"),
|
|
9454
9501
|
searchQuery: z17.string().optional().describe("Text search in title/description"),
|
|
9455
9502
|
statusFilters: z17.array(z17.string()).optional().describe("Filter by statuses"),
|
|
9503
|
+
typeFilters: z17.array(z17.enum(CARD_TYPE_ENUM)).optional().describe('Card types to include (default ["task"]). Pass e.g. ["incident"] or several.'),
|
|
9456
9504
|
assigneeId: z17.string().optional().describe("Filter by assigned user ID"),
|
|
9457
9505
|
unassigned: z17.boolean().optional().describe("Only return tasks with no assignee (mutually exclusive with assigneeId)"),
|
|
9458
9506
|
limit: z17.number().optional().describe("Max results (default 20)")
|
|
@@ -10582,7 +10630,7 @@ var ProjectRunner = class {
|
|
|
10582
10630
|
async handleAuditTags(request) {
|
|
10583
10631
|
this.connection.emitStatus("busy");
|
|
10584
10632
|
try {
|
|
10585
|
-
const { handleTagAudit } = await import("./tag-audit-handler-
|
|
10633
|
+
const { handleTagAudit } = await import("./tag-audit-handler-X3LEX63H.js");
|
|
10586
10634
|
await handleTagAudit(request, this.connection, this.projectDir);
|
|
10587
10635
|
} catch (error) {
|
|
10588
10636
|
const msg = parseErrorMessage(error);
|
|
@@ -10605,7 +10653,7 @@ var ProjectRunner = class {
|
|
|
10605
10653
|
async handleAuditTasks(request) {
|
|
10606
10654
|
this.connection.emitStatus("busy");
|
|
10607
10655
|
try {
|
|
10608
|
-
const { handleTaskAudit } = await import("./task-audit-handler-
|
|
10656
|
+
const { handleTaskAudit } = await import("./task-audit-handler-BRCXB5V6.js");
|
|
10609
10657
|
await handleTaskAudit(request, this.connection, this.projectDir);
|
|
10610
10658
|
} catch (error) {
|
|
10611
10659
|
const msg = parseErrorMessage(error);
|
|
@@ -10746,4 +10794,4 @@ export {
|
|
|
10746
10794
|
loadConveyorConfig,
|
|
10747
10795
|
unshallowRepo
|
|
10748
10796
|
};
|
|
10749
|
-
//# sourceMappingURL=chunk-
|
|
10797
|
+
//# sourceMappingURL=chunk-D7JSB2IF.js.map
|