@rallycry/conveyor-agent 11.0.5 → 11.0.6
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-J2NPWBVZ.js → chunk-GUYMLASA.js} +112 -4
- package/dist/{chunk-SLUBOIYE.js → chunk-HFUVAHII.js} +9 -0
- package/dist/{chunk-URYBO32C.js → chunk-UHMCBCQL.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.d.ts +63 -0
- package/dist/index.js +2 -2
- package/dist/{serve-boot-B4BIZMNB.js → serve-boot-IFUIGFEH.js} +2 -2
- package/package.json +1 -1
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
statWorkspacePath,
|
|
58
58
|
updateRemoteToken,
|
|
59
59
|
verifyGitCredential
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-HFUVAHII.js";
|
|
61
61
|
import {
|
|
62
62
|
registerBootMilestoneSocketFallback,
|
|
63
63
|
reportBootMilestone
|
|
@@ -4640,6 +4640,12 @@ var PtySession = class {
|
|
|
4640
4640
|
// synthetic id so the card flips to answered.
|
|
4641
4641
|
pendingSyntheticQuestionIds = [];
|
|
4642
4642
|
questionResultRemap = /* @__PURE__ */ new Map();
|
|
4643
|
+
// An AskUserQuestion questionnaire is parked on screen (PreToolUse hook
|
|
4644
|
+
// fired, no PostToolUse envelope yet). While set the parked process must
|
|
4645
|
+
// not be reused: feeding follow-up prompt bytes into the live dialog would
|
|
4646
|
+
// type chat text into the questionnaire. Fail-safe — a stale flag only
|
|
4647
|
+
// costs a teardown + respawn (`--resume` recovers the conversation).
|
|
4648
|
+
questionnairePending = false;
|
|
4643
4649
|
// Per-turn state: the prompt to feed and the per-turn options subset. Both
|
|
4644
4650
|
// start from the constructor args (turn 1) and are replaced by beginTurn.
|
|
4645
4651
|
turnPrompt;
|
|
@@ -4732,7 +4738,9 @@ var PtySession = class {
|
|
|
4732
4738
|
*/
|
|
4733
4739
|
canReuse(resume, fingerprint) {
|
|
4734
4740
|
const resumeMatches = resume === void 0 ? this.reportedOpenCodeId !== null : resume === this.sessionUuid;
|
|
4735
|
-
return !this._toreDown && !this.exited && this.activeQueue === null &&
|
|
4741
|
+
return !this._toreDown && !this.exited && this.activeQueue === null && // A parked questionnaire owns the terminal — a fed prompt would type
|
|
4742
|
+
// into the dialog. Force teardown + respawn instead.
|
|
4743
|
+
!this.questionnairePending && resumeMatches && fingerprint === this.spawnFingerprint;
|
|
4736
4744
|
}
|
|
4737
4745
|
get hookSocketPath() {
|
|
4738
4746
|
return this.socket ? this.socket.socketPath : null;
|
|
@@ -4807,6 +4815,7 @@ var PtySession = class {
|
|
|
4807
4815
|
this.deliveredTexts = [];
|
|
4808
4816
|
this.disarmSubmitNudge();
|
|
4809
4817
|
this.disarmPlanDialogAutoAccept();
|
|
4818
|
+
this.questionnairePending = false;
|
|
4810
4819
|
this.closeSyntheticQuestionCards();
|
|
4811
4820
|
}
|
|
4812
4821
|
/**
|
|
@@ -5116,6 +5125,7 @@ var PtySession = class {
|
|
|
5116
5125
|
async teardown() {
|
|
5117
5126
|
if (this._toreDown) return;
|
|
5118
5127
|
this._toreDown = true;
|
|
5128
|
+
this.questionnairePending = false;
|
|
5119
5129
|
this.disarmPlanDialogAutoAccept();
|
|
5120
5130
|
this.disarmSubmitNudge();
|
|
5121
5131
|
this.closeSyntheticQuestionCards();
|
|
@@ -5391,6 +5401,7 @@ var PtySession = class {
|
|
|
5391
5401
|
if (this.pendingPlanApproval && progress.tool_name === "ExitPlanMode") {
|
|
5392
5402
|
this.disarmPlanDialogAutoAccept();
|
|
5393
5403
|
}
|
|
5404
|
+
if (progress.tool_name === "AskUserQuestion") this.questionnairePending = false;
|
|
5394
5405
|
if (this.pendingSubmitNudge) this.disarmSubmitNudge();
|
|
5395
5406
|
this.pushEvent({
|
|
5396
5407
|
type: "tool_progress",
|
|
@@ -5411,6 +5422,7 @@ var PtySession = class {
|
|
|
5411
5422
|
if (request.tool_name === "AskUserQuestion") {
|
|
5412
5423
|
this.disarmSubmitNudge();
|
|
5413
5424
|
this.disarmPlanDialogAutoAccept();
|
|
5425
|
+
this.questionnairePending = true;
|
|
5414
5426
|
const questions = parseUserQuestions(request.tool_input);
|
|
5415
5427
|
this.pushEvent({ type: "user_question", questions });
|
|
5416
5428
|
this.emitSyntheticQuestionCard(questions);
|
|
@@ -5519,6 +5531,7 @@ var PtySession = class {
|
|
|
5519
5531
|
async finalizeOnExit(exitCode) {
|
|
5520
5532
|
this.coalescer?.flush();
|
|
5521
5533
|
this.exited = true;
|
|
5534
|
+
this.questionnairePending = false;
|
|
5522
5535
|
if (this._toreDown) return;
|
|
5523
5536
|
if (this.tailer) {
|
|
5524
5537
|
this.tailer.close();
|
|
@@ -12539,16 +12552,22 @@ function questionTextFromEvent(event) {
|
|
|
12539
12552
|
}
|
|
12540
12553
|
async function armQuestionPending(host, state, event) {
|
|
12541
12554
|
state.questionPending = true;
|
|
12555
|
+
const questionText = questionTextFromEvent(event);
|
|
12556
|
+
host.callbacks.onUserQuestion?.({
|
|
12557
|
+
kind: "armed",
|
|
12558
|
+
...questionText === void 0 ? {} : { questionText }
|
|
12559
|
+
});
|
|
12542
12560
|
await host.connection.emitStatus(
|
|
12543
12561
|
"waiting_for_input",
|
|
12544
12562
|
AGENT_STATUS_REASON_USER_QUESTION,
|
|
12545
|
-
|
|
12563
|
+
questionText
|
|
12546
12564
|
);
|
|
12547
12565
|
await host.callbacks.onStatusChange("waiting_for_input");
|
|
12548
12566
|
}
|
|
12549
12567
|
async function clearQuestionPending(host, state, options) {
|
|
12550
12568
|
if (!state.questionPending) return;
|
|
12551
12569
|
state.questionPending = false;
|
|
12570
|
+
host.callbacks.onUserQuestion?.({ kind: options.emitRunning ? "answered" : "turn_ended" });
|
|
12552
12571
|
if (options.emitRunning) {
|
|
12553
12572
|
await host.connection.emitStatus("running");
|
|
12554
12573
|
await host.callbacks.onStatusChange("running");
|
|
@@ -14740,6 +14759,15 @@ function findLiveChild(sources) {
|
|
|
14740
14759
|
var AUTO_RUN_MODES = /* @__PURE__ */ new Set(["building", "auto", "review", "discovery", "chat"]);
|
|
14741
14760
|
var CHILD_DEFER_RECHECK_MS = 60 * 1e3;
|
|
14742
14761
|
var ORPHAN_WAKE_GRACE_MS = 3 * 60 * 1e3;
|
|
14762
|
+
var QUESTION_GRACE_MS = 10 * 6e4;
|
|
14763
|
+
var QUESTION_HOLD_SLACK_MS = 6e4;
|
|
14764
|
+
function resolveQuestionGraceMs() {
|
|
14765
|
+
const raw = Number(process.env.CONVEYOR_QUESTION_GRACE_MS ?? "");
|
|
14766
|
+
return Number.isFinite(raw) && raw > 0 ? raw : QUESTION_GRACE_MS;
|
|
14767
|
+
}
|
|
14768
|
+
var QUESTION_TYPING_RECENT_MS = 6e4;
|
|
14769
|
+
var QUESTION_TYPING_DEFER_MS = 2 * 6e4;
|
|
14770
|
+
var QUESTION_TIMEOUT_PROMPT = 'No one answered your clarifying questions within 10 minutes. Do this now: (1) Save your findings-so-far as the card plan (`update_task`). (2) Post the unanswered questions to chat with `post_to_chat` using `milestone: "blocked"`, stating the assumption you would make for each. (3) If you can safely proceed on your best-judgment answers, state the assumptions and continue; otherwise end your turn \u2014 answers posted in chat will be delivered when you resume.';
|
|
14743
14771
|
var SessionRunner = class _SessionRunner {
|
|
14744
14772
|
connection;
|
|
14745
14773
|
mode;
|
|
@@ -14793,6 +14821,18 @@ var SessionRunner = class _SessionRunner {
|
|
|
14793
14821
|
/** Guards the one-shot `agent_live` boot-milestone report — fired on the
|
|
14794
14822
|
* first harness event (createQueryBridge's onEvent hook). */
|
|
14795
14823
|
agentLiveReported = false;
|
|
14824
|
+
/** Epoch ms since a TUI questionnaire has been parked on a human with no
|
|
14825
|
+
* answer; null when none is pending. While set (and within the grace +
|
|
14826
|
+
* slack bound) `resolveLoopStatus` reports `waiting`, which reaches the API
|
|
14827
|
+
* as `active` and keeps the workspace activity clock fresh — the pod must
|
|
14828
|
+
* not be slept out from under an unanswered question. Deliberately KEPT
|
|
14829
|
+
* when the turn ends with the questionnaire still parked (the Shape-B
|
|
14830
|
+
* silent death this hold exists for). */
|
|
14831
|
+
questionPendingSince = null;
|
|
14832
|
+
/** Single-shot unref'd timer driving `handleQuestionGraceExpiry`. The
|
|
14833
|
+
* liveness hold above is bounded by timestamp arithmetic, so a lost timer
|
|
14834
|
+
* still expires the hold — it just skips the un-park injection. */
|
|
14835
|
+
questionGraceTimer = null;
|
|
14796
14836
|
constructor(config, callbacks, deps = {}) {
|
|
14797
14837
|
this.config = config;
|
|
14798
14838
|
this.callbacks = callbacks;
|
|
@@ -15495,6 +15535,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
15495
15535
|
}
|
|
15496
15536
|
/** Inject a message (from connection callback or external source) */
|
|
15497
15537
|
injectMessage(msg) {
|
|
15538
|
+
this.clearQuestionHold();
|
|
15498
15539
|
if (this.inputResolver) {
|
|
15499
15540
|
const resolve = this.inputResolver;
|
|
15500
15541
|
this.inputResolver = null;
|
|
@@ -15702,6 +15743,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
15702
15743
|
}
|
|
15703
15744
|
stop() {
|
|
15704
15745
|
this.stopped = true;
|
|
15746
|
+
this.clearQuestionHold();
|
|
15705
15747
|
this.queryBridge?.stop();
|
|
15706
15748
|
void this.queryBridge?.dispose().catch(() => {
|
|
15707
15749
|
});
|
|
@@ -15796,7 +15838,8 @@ var SessionRunner = class _SessionRunner {
|
|
|
15796
15838
|
void this.connection.sendHeartbeat();
|
|
15797
15839
|
}
|
|
15798
15840
|
return this.callbacks.onEvent(event);
|
|
15799
|
-
}
|
|
15841
|
+
},
|
|
15842
|
+
onUserQuestion: (signal) => this.handleUserQuestionSignal(signal)
|
|
15800
15843
|
});
|
|
15801
15844
|
bridge.isParentTask = this.fullContext?.isParentTask ?? false;
|
|
15802
15845
|
bridge.onBackgroundTaskDone = () => this.backgroundWork.noteCompletion();
|
|
@@ -15947,8 +15990,72 @@ ${outcome.failures.join("\n")}
|
|
|
15947
15990
|
*/
|
|
15948
15991
|
resolveLoopStatus() {
|
|
15949
15992
|
if (loopStatusForRunnerStatus(this._state) === "active") return "active";
|
|
15993
|
+
if (this.questionPendingSince !== null && Date.now() - this.questionPendingSince < resolveQuestionGraceMs() + QUESTION_HOLD_SLACK_MS) {
|
|
15994
|
+
return "waiting";
|
|
15995
|
+
}
|
|
15950
15996
|
return this.backgroundWork.hasPending() || isHeavyGateActive() ? "waiting" : "idle";
|
|
15951
15997
|
}
|
|
15998
|
+
// ── Question grace hold ────────────────────────────────────────────
|
|
15999
|
+
/**
|
|
16000
|
+
* Question-pending transitions from the event loop. `armed` starts the
|
|
16001
|
+
* bounded liveness hold + the grace timer; `answered` clears both.
|
|
16002
|
+
* `turn_ended` — the turn's result arrived with the questionnaire still
|
|
16003
|
+
* parked — deliberately KEEPS them: that is the Shape-B silent death
|
|
16004
|
+
* (idle heartbeats stop bumping the activity clock and the reconciler
|
|
16005
|
+
* sleeps the pod minutes later) this hold exists to prevent.
|
|
16006
|
+
*/
|
|
16007
|
+
handleUserQuestionSignal(signal) {
|
|
16008
|
+
if (signal.kind === "armed") {
|
|
16009
|
+
this.questionPendingSince = Date.now();
|
|
16010
|
+
this.armQuestionGraceTimer(resolveQuestionGraceMs());
|
|
16011
|
+
this.refreshLoopStatus();
|
|
16012
|
+
} else if (signal.kind === "answered") {
|
|
16013
|
+
this.clearQuestionHold();
|
|
16014
|
+
}
|
|
16015
|
+
}
|
|
16016
|
+
armQuestionGraceTimer(delayMs) {
|
|
16017
|
+
if (this.questionGraceTimer) clearTimeout(this.questionGraceTimer);
|
|
16018
|
+
this.questionGraceTimer = setTimeout(() => this.handleQuestionGraceExpiry(), delayMs);
|
|
16019
|
+
this.questionGraceTimer.unref();
|
|
16020
|
+
}
|
|
16021
|
+
clearQuestionHold() {
|
|
16022
|
+
if (this.questionGraceTimer) {
|
|
16023
|
+
clearTimeout(this.questionGraceTimer);
|
|
16024
|
+
this.questionGraceTimer = null;
|
|
16025
|
+
}
|
|
16026
|
+
if (this.questionPendingSince === null) return;
|
|
16027
|
+
this.questionPendingSince = null;
|
|
16028
|
+
this.refreshLoopStatus();
|
|
16029
|
+
}
|
|
16030
|
+
/**
|
|
16031
|
+
* The grace expired with the questionnaire still unanswered. Un-park the
|
|
16032
|
+
* agent by injecting the timeout prompt as a superseding system message —
|
|
16033
|
+
* the proven supersede path (mid-turn: queue + queryBridge.stop(), teardown
|
|
16034
|
+
* kills the parked dialog and the respawn `--resume`s cleanly; idle: the
|
|
16035
|
+
* inputResolver picks it up). Never synthetic keypresses: Enter would
|
|
16036
|
+
* fabricate an answer and Esc handling is CLI-version-dependent.
|
|
16037
|
+
*
|
|
16038
|
+
* A human actively typing in the Connected-TUI defers the expiry — they may
|
|
16039
|
+
* be mid-answer, and superseding would yank the dialog out from under them.
|
|
16040
|
+
*/
|
|
16041
|
+
handleQuestionGraceExpiry() {
|
|
16042
|
+
this.questionGraceTimer = null;
|
|
16043
|
+
if (this.questionPendingSince === null || this.stopped) return;
|
|
16044
|
+
const lastInput = this.connection.lastPtyInputAt;
|
|
16045
|
+
if (lastInput !== null && Date.now() - lastInput < QUESTION_TYPING_RECENT_MS) {
|
|
16046
|
+
this.questionPendingSince = Date.now();
|
|
16047
|
+
this.armQuestionGraceTimer(QUESTION_TYPING_DEFER_MS);
|
|
16048
|
+
return;
|
|
16049
|
+
}
|
|
16050
|
+
process.stderr.write(
|
|
16051
|
+
"[conveyor-agent] Question grace expired with no answer \u2014 un-parking the agent\n"
|
|
16052
|
+
);
|
|
16053
|
+
this.injectMessage({
|
|
16054
|
+
content: QUESTION_TIMEOUT_PROMPT,
|
|
16055
|
+
userId: "system",
|
|
16056
|
+
source: "question_timeout"
|
|
16057
|
+
});
|
|
16058
|
+
}
|
|
15952
16059
|
/** Mirror the resolved status into the loop-lag buffer so the starvation-proof
|
|
15953
16060
|
* heartbeat worker reports it too. Returns what it wrote. */
|
|
15954
16061
|
refreshLoopStatus() {
|
|
@@ -15977,6 +16084,7 @@ ${outcome.failures.join("\n")}
|
|
|
15977
16084
|
process.stderr.write(`[conveyor-agent] Shutdown: reason=${finalState}
|
|
15978
16085
|
`);
|
|
15979
16086
|
this.connection.sendEvent({ type: "shutdown", reason: finalState });
|
|
16087
|
+
this.clearQuestionHold();
|
|
15980
16088
|
this.portDiscovery.stop();
|
|
15981
16089
|
this.backgroundWork.clear();
|
|
15982
16090
|
this.loopLag.stop();
|
|
@@ -287,6 +287,10 @@ var AgentConnection = class _AgentConnection {
|
|
|
287
287
|
// PTY relay (S5 terminal). Single-slot callbacks, set per PtySession run.
|
|
288
288
|
ptyInputCallback = null;
|
|
289
289
|
ptyResizeCallback = null;
|
|
290
|
+
/** Epoch ms of the last relayed keystroke, or null before any input. The
|
|
291
|
+
* question-grace expiry reads it to defer un-parking while a human is
|
|
292
|
+
* actively typing into the Connected-TUI (they may be mid-answer). */
|
|
293
|
+
_lastPtyInputAt = null;
|
|
290
294
|
constructor(config) {
|
|
291
295
|
this.config = config;
|
|
292
296
|
}
|
|
@@ -475,6 +479,7 @@ var AgentConnection = class _AgentConnection {
|
|
|
475
479
|
});
|
|
476
480
|
this.socket.on("pty:input", (data) => {
|
|
477
481
|
if (data.sessionId && data.sessionId !== this.config.sessionId) return;
|
|
482
|
+
this._lastPtyInputAt = Date.now();
|
|
478
483
|
this.ptyInputCallback?.(data.data);
|
|
479
484
|
});
|
|
480
485
|
this.socket.on("pty:resize", (data) => {
|
|
@@ -925,6 +930,10 @@ var AgentConnection = class _AgentConnection {
|
|
|
925
930
|
}).catch(() => {
|
|
926
931
|
});
|
|
927
932
|
}
|
|
933
|
+
/** Epoch ms of the last relayed TUI keystroke, or null before any. */
|
|
934
|
+
get lastPtyInputAt() {
|
|
935
|
+
return this._lastPtyInputAt;
|
|
936
|
+
}
|
|
928
937
|
/** Subscribe to relayed keystrokes. Returns an unsubscribe fn. */
|
|
929
938
|
onPtyInput(handler) {
|
|
930
939
|
this.ptyInputCallback = handler;
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
WorkspaceCommandSupervisor,
|
|
8
8
|
startWorkspaceCommandsAfterConnect,
|
|
9
9
|
stopWorkspaceCommands
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UHMCBCQL.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_SONNET_MODEL,
|
|
13
13
|
PtyHarness,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
resolveTuiKindFromEnv,
|
|
28
28
|
runUsageProbe,
|
|
29
29
|
sampleKeyUsage
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-GUYMLASA.js";
|
|
31
31
|
import "./chunk-XORJ6SII.js";
|
|
32
32
|
import {
|
|
33
33
|
inheritedEnv,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
createServiceLogger,
|
|
45
45
|
fetchBootstrap,
|
|
46
46
|
loadConveyorConfig
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-HFUVAHII.js";
|
|
48
48
|
import "./chunk-GL2DIQEQ.js";
|
|
49
49
|
import "./chunk-W4LZ7R6Z.js";
|
|
50
50
|
import "./chunk-7P6QZHXZ.js";
|
|
@@ -1454,7 +1454,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
|
|
|
1454
1454
|
process.exit(1);
|
|
1455
1455
|
}
|
|
1456
1456
|
if (CONVEYOR_MODE === "serving") {
|
|
1457
|
-
const { runServingSession } = await import("./serve-boot-
|
|
1457
|
+
const { runServingSession } = await import("./serve-boot-IFUIGFEH.js");
|
|
1458
1458
|
exitContext.runnerMode = "serving";
|
|
1459
1459
|
exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
|
|
1460
1460
|
const outcome = await runServingSession({
|
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,10 @@ declare class AgentConnection {
|
|
|
131
131
|
private earlyProbeUsage;
|
|
132
132
|
private ptyInputCallback;
|
|
133
133
|
private ptyResizeCallback;
|
|
134
|
+
/** Epoch ms of the last relayed keystroke, or null before any input. The
|
|
135
|
+
* question-grace expiry reads it to defer un-parking while a human is
|
|
136
|
+
* actively typing into the Connected-TUI (they may be mid-answer). */
|
|
137
|
+
private _lastPtyInputAt;
|
|
134
138
|
constructor(config: AgentConnectionConfig);
|
|
135
139
|
get sessionId(): string;
|
|
136
140
|
get connected(): boolean;
|
|
@@ -282,6 +286,8 @@ declare class AgentConnection {
|
|
|
282
286
|
* just stays on the relay transport.
|
|
283
287
|
*/
|
|
284
288
|
reportPtyStream(port: number | null): void;
|
|
289
|
+
/** Epoch ms of the last relayed TUI keystroke, or null before any. */
|
|
290
|
+
get lastPtyInputAt(): number | null;
|
|
285
291
|
/** Subscribe to relayed keystrokes. Returns an unsubscribe fn. */
|
|
286
292
|
onPtyInput(handler: (data: string) => void): () => void;
|
|
287
293
|
/** Subscribe to relayed (reconciled) terminal resizes. Returns an unsubscribe fn. */
|
|
@@ -729,6 +735,18 @@ declare class SessionRunner {
|
|
|
729
735
|
/** Guards the one-shot `agent_live` boot-milestone report — fired on the
|
|
730
736
|
* first harness event (createQueryBridge's onEvent hook). */
|
|
731
737
|
private agentLiveReported;
|
|
738
|
+
/** Epoch ms since a TUI questionnaire has been parked on a human with no
|
|
739
|
+
* answer; null when none is pending. While set (and within the grace +
|
|
740
|
+
* slack bound) `resolveLoopStatus` reports `waiting`, which reaches the API
|
|
741
|
+
* as `active` and keeps the workspace activity clock fresh — the pod must
|
|
742
|
+
* not be slept out from under an unanswered question. Deliberately KEPT
|
|
743
|
+
* when the turn ends with the questionnaire still parked (the Shape-B
|
|
744
|
+
* silent death this hold exists for). */
|
|
745
|
+
private questionPendingSince;
|
|
746
|
+
/** Single-shot unref'd timer driving `handleQuestionGraceExpiry`. The
|
|
747
|
+
* liveness hold above is bounded by timestamp arithmetic, so a lost timer
|
|
748
|
+
* still expires the hold — it just skips the un-park injection. */
|
|
749
|
+
private questionGraceTimer;
|
|
732
750
|
constructor(config: SessionRunnerConfig, callbacks: SessionRunnerCallbacks, deps?: SessionRunnerDependencies);
|
|
733
751
|
get state(): AgentRunnerStatus;
|
|
734
752
|
/**
|
|
@@ -1016,6 +1034,29 @@ declare class SessionRunner {
|
|
|
1016
1034
|
* for why an unknown status still fails open to `active`.
|
|
1017
1035
|
*/
|
|
1018
1036
|
private resolveLoopStatus;
|
|
1037
|
+
/**
|
|
1038
|
+
* Question-pending transitions from the event loop. `armed` starts the
|
|
1039
|
+
* bounded liveness hold + the grace timer; `answered` clears both.
|
|
1040
|
+
* `turn_ended` — the turn's result arrived with the questionnaire still
|
|
1041
|
+
* parked — deliberately KEEPS them: that is the Shape-B silent death
|
|
1042
|
+
* (idle heartbeats stop bumping the activity clock and the reconciler
|
|
1043
|
+
* sleeps the pod minutes later) this hold exists to prevent.
|
|
1044
|
+
*/
|
|
1045
|
+
private handleUserQuestionSignal;
|
|
1046
|
+
private armQuestionGraceTimer;
|
|
1047
|
+
private clearQuestionHold;
|
|
1048
|
+
/**
|
|
1049
|
+
* The grace expired with the questionnaire still unanswered. Un-park the
|
|
1050
|
+
* agent by injecting the timeout prompt as a superseding system message —
|
|
1051
|
+
* the proven supersede path (mid-turn: queue + queryBridge.stop(), teardown
|
|
1052
|
+
* kills the parked dialog and the respawn `--resume`s cleanly; idle: the
|
|
1053
|
+
* inputResolver picks it up). Never synthetic keypresses: Enter would
|
|
1054
|
+
* fabricate an answer and Esc handling is CLI-version-dependent.
|
|
1055
|
+
*
|
|
1056
|
+
* A human actively typing in the Connected-TUI defers the expiry — they may
|
|
1057
|
+
* be mid-answer, and superseding would yank the dialog out from under them.
|
|
1058
|
+
*/
|
|
1059
|
+
private handleQuestionGraceExpiry;
|
|
1019
1060
|
/** Mirror the resolved status into the loop-lag buffer so the starvation-proof
|
|
1020
1061
|
* heartbeat worker reports it too. Returns what it wrote. */
|
|
1021
1062
|
private refreshLoopStatus;
|
|
@@ -1055,9 +1096,31 @@ interface AgentRunnerConfig {
|
|
|
1055
1096
|
*/
|
|
1056
1097
|
packExecution?: _project_shared.PackExecution;
|
|
1057
1098
|
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Question-pending transitions surfaced to the runner by the event loop
|
|
1101
|
+
* (`applyQuestionTransitions` in execution/event-processor.ts):
|
|
1102
|
+
* - `armed` — the PTY hook observed an AskUserQuestion; a questionnaire is
|
|
1103
|
+
* parked on a human.
|
|
1104
|
+
* - `answered` — the questionnaire resolved (PostToolUse envelope, or a new
|
|
1105
|
+
* assistant record without the question block).
|
|
1106
|
+
* - `turn_ended` — the turn's `result` arrived while the questionnaire was
|
|
1107
|
+
* still parked. The dialog is still on screen with nobody answering — the
|
|
1108
|
+
* silent-death shape the question grace hold exists for — so the runner
|
|
1109
|
+
* must KEEP its pending hold rather than clear it.
|
|
1110
|
+
*/
|
|
1111
|
+
type UserQuestionSignal = {
|
|
1112
|
+
kind: "armed";
|
|
1113
|
+
questionText?: string;
|
|
1114
|
+
} | {
|
|
1115
|
+
kind: "answered";
|
|
1116
|
+
} | {
|
|
1117
|
+
kind: "turn_ended";
|
|
1118
|
+
};
|
|
1058
1119
|
interface AgentRunnerCallbacks {
|
|
1059
1120
|
onEvent: (event: Record<string, unknown>) => void | Promise<void>;
|
|
1060
1121
|
onStatusChange: (status: string) => void | Promise<void>;
|
|
1122
|
+
/** Optional — fired on question-pending transitions (see UserQuestionSignal). */
|
|
1123
|
+
onUserQuestion?: (signal: UserQuestionSignal) => void;
|
|
1061
1124
|
}
|
|
1062
1125
|
|
|
1063
1126
|
interface GithubTokenFileSync {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SessionRunner,
|
|
3
3
|
unshallowRepo
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GUYMLASA.js";
|
|
5
5
|
import "./chunk-XORJ6SII.js";
|
|
6
6
|
import "./chunk-W6VILPQE.js";
|
|
7
7
|
import {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
stageAndCommit,
|
|
18
18
|
updateRemoteToken,
|
|
19
19
|
workspacePathExists
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-HFUVAHII.js";
|
|
21
21
|
import "./chunk-GL2DIQEQ.js";
|
|
22
22
|
import {
|
|
23
23
|
runAuthTokenCommand,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WorkspaceCommandSupervisor
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UHMCBCQL.js";
|
|
4
4
|
import {
|
|
5
5
|
AgentConnection,
|
|
6
6
|
CodespacePortVisibility,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
createServiceLogger,
|
|
12
12
|
ensureOnTaskBranch,
|
|
13
13
|
loadConveyorConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HFUVAHII.js";
|
|
15
15
|
import "./chunk-GL2DIQEQ.js";
|
|
16
16
|
import "./chunk-W4LZ7R6Z.js";
|
|
17
17
|
import "./chunk-IA45XHOA.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-agent",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.6",
|
|
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",
|