@rallycry/conveyor-agent 11.0.1 → 11.0.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-QETNCXIR.js → chunk-DHKAY7HQ.js} +54 -16
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +36 -11
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/conveyor-local-loop/SKILL.md +4 -1
|
@@ -13150,7 +13150,9 @@ function taskIdToSessionUuid(lineageKey) {
|
|
|
13150
13150
|
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-8${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
|
|
13151
13151
|
}
|
|
13152
13152
|
function sessionLineageKey(taskId, agentMode, runnerMode) {
|
|
13153
|
-
|
|
13153
|
+
if (agentMode === "review" || runnerMode === "code-review") return `${taskId}:review`;
|
|
13154
|
+
if (runnerMode === "plan") return `${taskId}:plan`;
|
|
13155
|
+
return taskId;
|
|
13154
13156
|
}
|
|
13155
13157
|
function sessionFileExists(sessionUuid, cwd) {
|
|
13156
13158
|
try {
|
|
@@ -13417,7 +13419,7 @@ async function handleTurnSilence(host, state, waitMs, silenceTimeoutMs, probeMou
|
|
|
13417
13419
|
host,
|
|
13418
13420
|
`[conveyor-agent] Turn produced no events for ${minutes}m with no heavy gate running \u2014 aborting the wedged turn
|
|
13419
13421
|
`,
|
|
13420
|
-
`Turn silent for ${minutes}m \u2014 aborting it so the agent can go idle
|
|
13422
|
+
`Turn silent for ${minutes}m \u2014 aborting it so the agent can go idle. A first turn retries automatically; otherwise the conversation resumes on the next message.`
|
|
13421
13423
|
);
|
|
13422
13424
|
return "keep_waiting";
|
|
13423
13425
|
}
|
|
@@ -14632,7 +14634,6 @@ function findLiveChild(sources) {
|
|
|
14632
14634
|
|
|
14633
14635
|
// src/runner/session-runner.ts
|
|
14634
14636
|
var AUTO_RUN_MODES = /* @__PURE__ */ new Set(["building", "auto", "review", "discovery", "chat"]);
|
|
14635
|
-
var AUTONOMOUS_RUNNER_MODES = /* @__PURE__ */ new Set(["pack", "pm", "code-review"]);
|
|
14636
14637
|
var CHILD_DEFER_RECHECK_MS = 60 * 1e3;
|
|
14637
14638
|
var SessionRunner = class _SessionRunner {
|
|
14638
14639
|
connection;
|
|
@@ -15113,26 +15114,48 @@ var SessionRunner = class _SessionRunner {
|
|
|
15113
15114
|
return true;
|
|
15114
15115
|
}
|
|
15115
15116
|
/**
|
|
15116
|
-
* The mid-turn
|
|
15117
|
-
*
|
|
15118
|
-
* `--resume`" — assumes a human or a follow-up is
|
|
15119
|
-
*
|
|
15120
|
-
*
|
|
15117
|
+
* The mid-turn watchdog aborts a turn that produced no events for 30 minutes
|
|
15118
|
+
* (or one whose config-home mount died). Its documented recovery — "the next
|
|
15119
|
+
* message respawns with `--resume`" — assumes a human or a follow-up is
|
|
15120
|
+
* coming. A KICKOFF turn has neither by construction: it is the turn that
|
|
15121
|
+
* starts the conversation, so there is no next message, and the runner goes
|
|
15122
|
+
* idle with the card parked until a human notices.
|
|
15121
15123
|
*
|
|
15122
|
-
*
|
|
15123
|
-
*
|
|
15124
|
-
*
|
|
15125
|
-
*
|
|
15126
|
-
*
|
|
15127
|
-
*
|
|
15124
|
+
* Observed live 2026-08-28 (card cmtd78iql): a spawned builder child's
|
|
15125
|
+
* kickoff turn produced nothing for 30 minutes, was aborted, and the child
|
|
15126
|
+
* then heartbeated idle for another 43 minutes until a human typed
|
|
15127
|
+
* "@[agent:builder] continue".
|
|
15128
|
+
*
|
|
15129
|
+
* So any submit-delivery INITIAL query killed by the watchdog is re-run once
|
|
15130
|
+
* against the (durable, on-disk) resumed session. Bounded to a single retry:
|
|
15131
|
+
* a second wedge is a real failure that should surface as a parked card
|
|
15132
|
+
* rather than loop the pod.
|
|
15133
|
+
*
|
|
15134
|
+
* Nothing recovers a card from there automatically, and that is the honest
|
|
15135
|
+
* state of it. The server's session sweep does NOT catch this shape: its
|
|
15136
|
+
* predicate is `agentRunningAt` still null, and a turn that started and then
|
|
15137
|
+
* wedged has already stamped it. The sweep covers a builder that never took a
|
|
15138
|
+
* turn at all; this retry covers one whose first turn stalled. Twice-wedged
|
|
15139
|
+
* needs a human, and a card left that way keeps its Builder tab and its
|
|
15140
|
+
* heartbeat, so it is visible rather than silently gone.
|
|
15141
|
+
*
|
|
15142
|
+
* Skipped when a pending message already exists, because the core loop
|
|
15143
|
+
* delivers that instead, which is the path the watchdog's original recovery
|
|
15144
|
+
* assumed.
|
|
15145
|
+
*
|
|
15146
|
+
* A mount-death abort retries too, and must: the repair for a dead config
|
|
15147
|
+
* home is the respawn that follows the abort, so a kickoff with nothing
|
|
15148
|
+
* behind it would otherwise never get one.
|
|
15149
|
+
*
|
|
15150
|
+
* NOT for follow-up turns — there "the conversation resumes on the next
|
|
15151
|
+
* message" is exactly right.
|
|
15128
15152
|
*/
|
|
15129
15153
|
async requeueWedgedInitialQuery(delivery) {
|
|
15130
15154
|
if (!this.queryBridge?.lastTurnWedgeAborted) return;
|
|
15131
15155
|
if (this.stopped || this.interrupted || this.completedThisTurn) return;
|
|
15132
15156
|
if (this.pendingMessages.length > 0) return;
|
|
15133
|
-
if (!this.mode.isAuto && !AUTONOMOUS_RUNNER_MODES.has(this.config.runnerMode ?? "")) return;
|
|
15134
15157
|
process.stderr.write(
|
|
15135
|
-
"[conveyor-agent] Initial query was aborted as wedged with nothing queued behind it \u2014 re-running it once (
|
|
15158
|
+
"[conveyor-agent] Initial query was aborted as wedged with nothing queued behind it \u2014 re-running it once (a kickoff turn has no follow-up message coming)\n"
|
|
15136
15159
|
);
|
|
15137
15160
|
this.connection.sendEvent({
|
|
15138
15161
|
type: "error",
|
|
@@ -15730,6 +15753,15 @@ ${outcome.failures.join("\n")}
|
|
|
15730
15753
|
get finalState() {
|
|
15731
15754
|
return this._finalState;
|
|
15732
15755
|
}
|
|
15756
|
+
/** Does a transcript already exist for this session's lineage? */
|
|
15757
|
+
resolvesToTranscriptResume() {
|
|
15758
|
+
const taskId = this.fullContext?.taskId;
|
|
15759
|
+
if (!taskId) return false;
|
|
15760
|
+
return hasExistingSessionFile(taskId, this.config.workspaceDir, {
|
|
15761
|
+
agentMode: this.mode.effectiveMode,
|
|
15762
|
+
runnerMode: this.config.runnerMode
|
|
15763
|
+
});
|
|
15764
|
+
}
|
|
15733
15765
|
buildTaskContextSnapshot() {
|
|
15734
15766
|
return {
|
|
15735
15767
|
isParentTask: this.fullContext?.isParentTask ?? false,
|
|
@@ -15746,6 +15778,12 @@ ${outcome.failures.join("\n")}
|
|
|
15746
15778
|
mode: this.mode.effectiveMode,
|
|
15747
15779
|
runnerMode: this.config.runnerMode ?? "task",
|
|
15748
15780
|
sessionId: this.sessionId,
|
|
15781
|
+
// Whether this run will RESUME a transcript, read from disk under this
|
|
15782
|
+
// session's own lineage. `hasExistingSession` below answers a different
|
|
15783
|
+
// question — does the server hold an sdkSessionId — and the two disagree
|
|
15784
|
+
// whenever a role's lineage is fresh. Resume is filesystem-driven, so
|
|
15785
|
+
// this is the field to read when a session's context looks wrong.
|
|
15786
|
+
resumesTranscript: this.resolvesToTranscriptResume(),
|
|
15749
15787
|
...this.buildTaskContextSnapshot(),
|
|
15750
15788
|
model: this.taskContext?.model,
|
|
15751
15789
|
isAuto: this.config.isAuto ?? false,
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -802,18 +802,41 @@ declare class SessionRunner {
|
|
|
802
802
|
/** Returns true if an initial query was executed, false otherwise. */
|
|
803
803
|
private executeInitialMode;
|
|
804
804
|
/**
|
|
805
|
-
* The mid-turn
|
|
806
|
-
*
|
|
807
|
-
* `--resume`" — assumes a human or a follow-up is
|
|
808
|
-
*
|
|
809
|
-
*
|
|
805
|
+
* The mid-turn watchdog aborts a turn that produced no events for 30 minutes
|
|
806
|
+
* (or one whose config-home mount died). Its documented recovery — "the next
|
|
807
|
+
* message respawns with `--resume`" — assumes a human or a follow-up is
|
|
808
|
+
* coming. A KICKOFF turn has neither by construction: it is the turn that
|
|
809
|
+
* starts the conversation, so there is no next message, and the runner goes
|
|
810
|
+
* idle with the card parked until a human notices.
|
|
810
811
|
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
812
|
+
* Observed live 2026-08-28 (card cmtd78iql): a spawned builder child's
|
|
813
|
+
* kickoff turn produced nothing for 30 minutes, was aborted, and the child
|
|
814
|
+
* then heartbeated idle for another 43 minutes until a human typed
|
|
815
|
+
* "@[agent:builder] continue".
|
|
816
|
+
*
|
|
817
|
+
* So any submit-delivery INITIAL query killed by the watchdog is re-run once
|
|
818
|
+
* against the (durable, on-disk) resumed session. Bounded to a single retry:
|
|
819
|
+
* a second wedge is a real failure that should surface as a parked card
|
|
820
|
+
* rather than loop the pod.
|
|
821
|
+
*
|
|
822
|
+
* Nothing recovers a card from there automatically, and that is the honest
|
|
823
|
+
* state of it. The server's session sweep does NOT catch this shape: its
|
|
824
|
+
* predicate is `agentRunningAt` still null, and a turn that started and then
|
|
825
|
+
* wedged has already stamped it. The sweep covers a builder that never took a
|
|
826
|
+
* turn at all; this retry covers one whose first turn stalled. Twice-wedged
|
|
827
|
+
* needs a human, and a card left that way keeps its Builder tab and its
|
|
828
|
+
* heartbeat, so it is visible rather than silently gone.
|
|
829
|
+
*
|
|
830
|
+
* Skipped when a pending message already exists, because the core loop
|
|
831
|
+
* delivers that instead, which is the path the watchdog's original recovery
|
|
832
|
+
* assumed.
|
|
833
|
+
*
|
|
834
|
+
* A mount-death abort retries too, and must: the repair for a dead config
|
|
835
|
+
* home is the respawn that follows the abort, so a kickoff with nothing
|
|
836
|
+
* behind it would otherwise never get one.
|
|
837
|
+
*
|
|
838
|
+
* NOT for follow-up turns — there "the conversation resumes on the next
|
|
839
|
+
* message" is exactly right.
|
|
817
840
|
*/
|
|
818
841
|
private requeueWedgedInitialQuery;
|
|
819
842
|
/**
|
|
@@ -957,6 +980,8 @@ declare class SessionRunner {
|
|
|
957
980
|
private _finalState;
|
|
958
981
|
/** The final status after run() completes. Use to determine exit code. */
|
|
959
982
|
get finalState(): AgentRunnerStatus | null;
|
|
983
|
+
/** Does a transcript already exist for this session's lineage? */
|
|
984
|
+
private resolvesToTranscriptResume;
|
|
960
985
|
private buildTaskContextSnapshot;
|
|
961
986
|
private buildInitializationContext;
|
|
962
987
|
private logInitialization;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-agent",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.3",
|
|
4
4
|
"description": "Conveyor Agent Runner v10 - PTY harness for the task chat (SDK harness for audit/project-chat). Agent-as-User architecture with BaseService patterns. Works locally too.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -173,7 +173,10 @@ notification is the wake. The `ScheduleWakeup` you still arm is the fallback for
|
|
|
173
173
|
the case where the wait dies silently — use the pacing table's background-gate
|
|
174
174
|
row (1200–1800s), not a second, shorter timer.
|
|
175
175
|
|
|
176
|
-
- Prefer `node_modules/.bin/conveyor-wait`.
|
|
176
|
+
- Prefer `node_modules/.bin/conveyor-wait`. Gate on
|
|
177
|
+
`[ -x node_modules/.bin/conveyor-wait ]`, not on the path existing: in a
|
|
178
|
+
checkout that has not been built the bin is a symlink into an unbuilt
|
|
179
|
+
`dist/`, so it looks present and fails to run. When that test is false, use
|
|
177
180
|
`npx -y -p @rallycry/conveyor-mcp@latest conveyor-wait`. The `-p` form
|
|
178
181
|
matters: inside the conveyor monorepo a bare
|
|
179
182
|
`npx @rallycry/conveyor-mcp` misresolves.
|