github-router 0.3.150 → 0.3.151
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/browser-ext/manifest.json +1 -1
- package/dist/engine-DBIfCSAl.js +6 -0
- package/dist/main.js +9 -4
- package/dist/main.js.map +1 -1
- package/dist/{peer-mcp-personas-D_HyWhUb.js → peer-mcp-personas-Dm3UCpXz.js} +557 -14
- package/dist/peer-mcp-personas-Dm3UCpXz.js.map +1 -0
- package/package.json +1 -1
- package/dist/engine-Dtu1TDpQ.js +0 -6
- package/dist/peer-mcp-personas-D_HyWhUb.js.map +0 -1
|
@@ -2673,6 +2673,464 @@ var MergedFleetRegistry = class {
|
|
|
2673
2673
|
}
|
|
2674
2674
|
};
|
|
2675
2675
|
|
|
2676
|
+
//#endregion
|
|
2677
|
+
//#region src/lib/fleet/driver.ts
|
|
2678
|
+
/** ai-or-die named keys (raw:false maps these; never a literal "\r"). C4. */
|
|
2679
|
+
const SUBMIT_KEY = "enter";
|
|
2680
|
+
const INTERRUPT_KEY = "ctrl-c";
|
|
2681
|
+
/** The control events that RELIABLY mark a turn boundary (transcript-derived). */
|
|
2682
|
+
const TURN_SETTLE_KINDS = ["turn_ended", "waiting_input"];
|
|
2683
|
+
const DEFAULT_READY_POLL_MS = 500;
|
|
2684
|
+
const DEFAULT_TURN_POLL_MS = 25e3;
|
|
2685
|
+
const DEFAULT_PRIME_TIMEOUT_MS = 0;
|
|
2686
|
+
const DEFAULT_IDLE_WAIT_MS = 2e3;
|
|
2687
|
+
const DEFAULT_RECOVER_MS = 15e3;
|
|
2688
|
+
const DEFAULT_TAIL_LINES = 200;
|
|
2689
|
+
function realSleep(ms) {
|
|
2690
|
+
if (ms <= 0) return Promise.resolve();
|
|
2691
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2692
|
+
}
|
|
2693
|
+
/** Map a named op to the ai-or-die named key. `submit` = Enter, `interrupt` = Ctrl-C.
|
|
2694
|
+
* Callers send the returned key with raw:false so ai-or-die interprets the NAMED
|
|
2695
|
+
* key — never a literal control byte. */
|
|
2696
|
+
function mapNamedKeyOp(op) {
|
|
2697
|
+
switch (op) {
|
|
2698
|
+
case "submit": return SUBMIT_KEY;
|
|
2699
|
+
case "interrupt": return INTERRUPT_KEY;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
function isNamedKeyOp(value) {
|
|
2703
|
+
return value === "submit" || value === "interrupt";
|
|
2704
|
+
}
|
|
2705
|
+
/** Read `awaiting.kind` off a status defensively (the shape is `{ kind, ... }`). */
|
|
2706
|
+
function readAwaitingKind(status) {
|
|
2707
|
+
const awaiting = status?.awaiting;
|
|
2708
|
+
if (awaiting && typeof awaiting === "object") {
|
|
2709
|
+
const kind = awaiting.kind;
|
|
2710
|
+
if (typeof kind === "string" && kind.trim() !== "") return kind;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Classify whether a free-text message may be submitted to a session RIGHT NOW.
|
|
2715
|
+
* Ready only when the session is idle or explicitly awaiting the next message.
|
|
2716
|
+
* A pending non-message prompt (plan_approval / choice_question / tool_approval /
|
|
2717
|
+
* trust_prompt) is `awaiting_other` — the caller should use `respond`, not a raw
|
|
2718
|
+
* message. `busy` / `terminal` are hard refusals; `unknown` carries no positive
|
|
2719
|
+
* evidence of a busy composer (the caller fails OPEN and lets the send surface its
|
|
2720
|
+
* own transport result).
|
|
2721
|
+
*/
|
|
2722
|
+
function classifyMessageReadiness(status) {
|
|
2723
|
+
const interactionState = typeof status?.interactionState === "string" ? status.interactionState : void 0;
|
|
2724
|
+
const awaitingKind = readAwaitingKind(status);
|
|
2725
|
+
if (interactionState === "busy") return {
|
|
2726
|
+
ready: false,
|
|
2727
|
+
reason: "busy",
|
|
2728
|
+
interactionState,
|
|
2729
|
+
awaitingKind
|
|
2730
|
+
};
|
|
2731
|
+
if (interactionState === "exited" || interactionState === "crashed") return {
|
|
2732
|
+
ready: false,
|
|
2733
|
+
reason: "terminal",
|
|
2734
|
+
interactionState
|
|
2735
|
+
};
|
|
2736
|
+
if (awaitingKind !== void 0 && awaitingKind !== "next_message") return {
|
|
2737
|
+
ready: false,
|
|
2738
|
+
reason: "awaiting_other",
|
|
2739
|
+
interactionState,
|
|
2740
|
+
awaitingKind
|
|
2741
|
+
};
|
|
2742
|
+
if (interactionState === "idle") return {
|
|
2743
|
+
ready: true,
|
|
2744
|
+
reason: "idle",
|
|
2745
|
+
interactionState
|
|
2746
|
+
};
|
|
2747
|
+
if (awaitingKind === "next_message" || interactionState === "waiting_input") return {
|
|
2748
|
+
ready: true,
|
|
2749
|
+
reason: "awaiting_message",
|
|
2750
|
+
interactionState,
|
|
2751
|
+
awaitingKind
|
|
2752
|
+
};
|
|
2753
|
+
return {
|
|
2754
|
+
ready: false,
|
|
2755
|
+
reason: "unknown",
|
|
2756
|
+
interactionState,
|
|
2757
|
+
awaitingKind
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
/** A refusal reason with POSITIVE evidence the composer must not be typed into. */
|
|
2761
|
+
function isHardNotReady(reason) {
|
|
2762
|
+
return reason === "busy" || reason === "awaiting_other" || reason === "terminal";
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Poll `/status` until the session is ready for a message or the wait budget is
|
|
2766
|
+
* spent. A status probe that THROWS fails OPEN (reports `unknown` and returns) so a
|
|
2767
|
+
* transient status hiccup never wedges a legitimate send — the send itself carries
|
|
2768
|
+
* ai-or-die's own submission signal.
|
|
2769
|
+
*/
|
|
2770
|
+
async function waitForMessageReady(client, localId, options = {}) {
|
|
2771
|
+
const now = options.now ?? Date.now;
|
|
2772
|
+
const sleep$1 = options.sleep ?? realSleep;
|
|
2773
|
+
const waitMs = Math.max(0, options.waitMs ?? 0);
|
|
2774
|
+
const pollMs = Math.max(1, options.pollMs ?? DEFAULT_READY_POLL_MS);
|
|
2775
|
+
const deadline = now() + waitMs;
|
|
2776
|
+
let last = {
|
|
2777
|
+
ready: false,
|
|
2778
|
+
reason: "unknown"
|
|
2779
|
+
};
|
|
2780
|
+
for (;;) {
|
|
2781
|
+
let status;
|
|
2782
|
+
try {
|
|
2783
|
+
status = (await client.status(localId, options.signal)).status;
|
|
2784
|
+
} catch {
|
|
2785
|
+
return {
|
|
2786
|
+
ready: false,
|
|
2787
|
+
readiness: {
|
|
2788
|
+
ready: false,
|
|
2789
|
+
reason: "unknown"
|
|
2790
|
+
},
|
|
2791
|
+
statusError: true
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2794
|
+
last = classifyMessageReadiness(status);
|
|
2795
|
+
if (last.ready) return {
|
|
2796
|
+
ready: true,
|
|
2797
|
+
readiness: last
|
|
2798
|
+
};
|
|
2799
|
+
const remaining = deadline - now();
|
|
2800
|
+
if (remaining <= 0) return {
|
|
2801
|
+
ready: false,
|
|
2802
|
+
readiness: last
|
|
2803
|
+
};
|
|
2804
|
+
await sleep$1(Math.min(pollMs, remaining));
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* Classify a batch of already-stamped events per session for the `await_turn`
|
|
2809
|
+
* summary. `turn_ended` -> completed, `waiting_input` -> awaiting_input (both
|
|
2810
|
+
* reliable / transcript-derived); a bare `became_idle` is surfaced as `idle_flicker`
|
|
2811
|
+
* with reliable:false so a caller NEVER mistakes the PTY heuristic for completion.
|
|
2812
|
+
* `became_busy` and other kinds are ignored (not a settle signal).
|
|
2813
|
+
*/
|
|
2814
|
+
function classifyTurnEvents(events$1) {
|
|
2815
|
+
const rank = {
|
|
2816
|
+
completed: 3,
|
|
2817
|
+
awaiting_input: 2,
|
|
2818
|
+
idle_flicker: 1
|
|
2819
|
+
};
|
|
2820
|
+
const best = /* @__PURE__ */ new Map();
|
|
2821
|
+
for (const event of events$1) {
|
|
2822
|
+
const sessionId = typeof event.sessionId === "string" ? event.sessionId : void 0;
|
|
2823
|
+
const kind = typeof event.kind === "string" ? event.kind : void 0;
|
|
2824
|
+
if (sessionId === void 0 || kind === void 0) continue;
|
|
2825
|
+
let status;
|
|
2826
|
+
if (kind === "turn_ended") status = "completed";
|
|
2827
|
+
else if (kind === "waiting_input") status = "awaiting_input";
|
|
2828
|
+
else if (kind === "became_idle") status = "idle_flicker";
|
|
2829
|
+
if (status === void 0) continue;
|
|
2830
|
+
const prior = best.get(sessionId);
|
|
2831
|
+
if (prior === void 0 || rank[status] > rank[prior]) best.set(sessionId, status);
|
|
2832
|
+
}
|
|
2833
|
+
return [...best.entries()].map(([sessionId, status]) => ({
|
|
2834
|
+
sessionId,
|
|
2835
|
+
status,
|
|
2836
|
+
reliable: status !== "idle_flicker"
|
|
2837
|
+
}));
|
|
2838
|
+
}
|
|
2839
|
+
function pickSettleEvent(events$1, localId) {
|
|
2840
|
+
let awaiting;
|
|
2841
|
+
for (const event of events$1) {
|
|
2842
|
+
if (event.sessionId !== localId) continue;
|
|
2843
|
+
if (event.kind === "turn_ended") return event;
|
|
2844
|
+
if (event.kind === "waiting_input" && awaiting === void 0) awaiting = event;
|
|
2845
|
+
}
|
|
2846
|
+
return awaiting;
|
|
2847
|
+
}
|
|
2848
|
+
/** Client-side backoff after a transient waitEvents failure so the loop cannot
|
|
2849
|
+
* hot-spin (hammer the control plane) when polls fail fast (network down). */
|
|
2850
|
+
const TURN_POLL_ERROR_BACKOFF_MS = 250;
|
|
2851
|
+
/** Attempts to obtain a starting cursor before a drive send (see driveTask step 2). */
|
|
2852
|
+
const PRIME_CURSOR_ATTEMPTS = 3;
|
|
2853
|
+
/**
|
|
2854
|
+
* Obtain a starting `/events` cursor before sending, retrying a bounded number of
|
|
2855
|
+
* times. A cursor is what prevents a stale prior-turn `turn_ended` from satisfying
|
|
2856
|
+
* the post-send wait; a cursorless request may replay history. Retries are cheap
|
|
2857
|
+
* (a zero/short poll). Returns undefined only if every attempt fails (rare) or the
|
|
2858
|
+
* signal aborts — the caller then proceeds best-effort.
|
|
2859
|
+
*/
|
|
2860
|
+
async function primeTurnCursor(client, localId, timeoutMs, signal) {
|
|
2861
|
+
for (let attempt = 0; attempt < PRIME_CURSOR_ATTEMPTS; attempt++) {
|
|
2862
|
+
if (signal?.aborted) return void 0;
|
|
2863
|
+
try {
|
|
2864
|
+
return (await client.waitEvents({
|
|
2865
|
+
sessionIds: [localId],
|
|
2866
|
+
kinds: [...TURN_SETTLE_KINDS],
|
|
2867
|
+
timeoutMs
|
|
2868
|
+
}, signal)).cursor;
|
|
2869
|
+
} catch {}
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Wait until the CURRENT turn actually ends (`turn_ended`) or the session is
|
|
2874
|
+
* awaiting input (`waiting_input`), long-polling `/events` filtered to those kinds
|
|
2875
|
+
* and advancing the server cursor across windows. Returns `{settled:false,
|
|
2876
|
+
* reason:"timeout"}` when neither fires within `timeoutMs`. It NEVER settles on
|
|
2877
|
+
* `became_idle`. Prime a cursor BEFORE the send (a zero/short poll) and pass it in
|
|
2878
|
+
* so a stale prior-turn event cannot satisfy the wait.
|
|
2879
|
+
*/
|
|
2880
|
+
async function waitForTurnSettled(client, localId, options) {
|
|
2881
|
+
const now = options.now ?? Date.now;
|
|
2882
|
+
const sleep$1 = options.sleep ?? realSleep;
|
|
2883
|
+
const pollTimeoutMs = Math.max(1, options.pollTimeoutMs ?? DEFAULT_TURN_POLL_MS);
|
|
2884
|
+
const budget = Number.isFinite(options.timeoutMs) ? Math.max(0, options.timeoutMs) : 0;
|
|
2885
|
+
const deadline = now() + budget;
|
|
2886
|
+
let cursor = options.cursor;
|
|
2887
|
+
do {
|
|
2888
|
+
if (options.signal?.aborted) return {
|
|
2889
|
+
settled: false,
|
|
2890
|
+
reason: "aborted",
|
|
2891
|
+
cursor
|
|
2892
|
+
};
|
|
2893
|
+
const remaining = deadline - now();
|
|
2894
|
+
const poll = remaining <= 0 ? 0 : Math.min(pollTimeoutMs, remaining);
|
|
2895
|
+
let response;
|
|
2896
|
+
try {
|
|
2897
|
+
response = await client.waitEvents({
|
|
2898
|
+
sessionIds: [localId],
|
|
2899
|
+
kinds: [...TURN_SETTLE_KINDS],
|
|
2900
|
+
timeoutMs: poll,
|
|
2901
|
+
cursor
|
|
2902
|
+
}, options.signal);
|
|
2903
|
+
} catch {
|
|
2904
|
+
if (options.signal?.aborted) return {
|
|
2905
|
+
settled: false,
|
|
2906
|
+
reason: "aborted",
|
|
2907
|
+
cursor
|
|
2908
|
+
};
|
|
2909
|
+
if (now() >= deadline) return {
|
|
2910
|
+
settled: false,
|
|
2911
|
+
reason: "timeout",
|
|
2912
|
+
cursor
|
|
2913
|
+
};
|
|
2914
|
+
await sleep$1(Math.min(TURN_POLL_ERROR_BACKOFF_MS, Math.max(0, deadline - now())));
|
|
2915
|
+
continue;
|
|
2916
|
+
}
|
|
2917
|
+
cursor = response.cursor;
|
|
2918
|
+
const hit = pickSettleEvent(response.events, localId);
|
|
2919
|
+
if (hit) return {
|
|
2920
|
+
settled: true,
|
|
2921
|
+
reason: hit.kind === "turn_ended" ? "turn_ended" : "waiting_input",
|
|
2922
|
+
cursor,
|
|
2923
|
+
event: hit
|
|
2924
|
+
};
|
|
2925
|
+
} while (now() < deadline);
|
|
2926
|
+
return {
|
|
2927
|
+
settled: false,
|
|
2928
|
+
reason: "timeout",
|
|
2929
|
+
cursor
|
|
2930
|
+
};
|
|
2931
|
+
}
|
|
2932
|
+
const OPERATOR_REPORT_HEADER = "=== OPERATOR REPORT ===";
|
|
2933
|
+
const OPERATOR_REPORT_FOOTER = "=== END OPERATOR REPORT ===";
|
|
2934
|
+
const OPERATOR_REPORT_LABELS = [
|
|
2935
|
+
"REPORT_ID",
|
|
2936
|
+
"STATE",
|
|
2937
|
+
"SUMMARY",
|
|
2938
|
+
"ASK",
|
|
2939
|
+
"ARTIFACT"
|
|
2940
|
+
];
|
|
2941
|
+
/**
|
|
2942
|
+
* Parse the LAST OPERATOR REPORT trailer in a transcript tail into typed fields.
|
|
2943
|
+
* Robust to: no trailer (returns state:"unknown", found:false), a missing footer,
|
|
2944
|
+
* multi-line field values (a value runs until the next known label or the footer),
|
|
2945
|
+
* and case-insensitive labels. Lines before the first label are ignored.
|
|
2946
|
+
*/
|
|
2947
|
+
function parseOperatorReport(text) {
|
|
2948
|
+
const raw = text ?? "";
|
|
2949
|
+
const headerIdx = raw.lastIndexOf(OPERATOR_REPORT_HEADER);
|
|
2950
|
+
if (headerIdx === -1) return {
|
|
2951
|
+
state: "unknown",
|
|
2952
|
+
raw,
|
|
2953
|
+
found: false
|
|
2954
|
+
};
|
|
2955
|
+
let block = raw.slice(headerIdx + 23);
|
|
2956
|
+
const footerIdx = block.indexOf(OPERATOR_REPORT_FOOTER);
|
|
2957
|
+
if (footerIdx !== -1) block = block.slice(0, footerIdx);
|
|
2958
|
+
const values = {};
|
|
2959
|
+
let current;
|
|
2960
|
+
for (const line of block.split(/\r?\n/)) {
|
|
2961
|
+
const match = /^\s*([A-Za-z_]+)\s*:\s*(.*)$/.exec(line);
|
|
2962
|
+
const label = match?.[1]?.toUpperCase();
|
|
2963
|
+
if (match && label && OPERATOR_REPORT_LABELS.includes(label)) {
|
|
2964
|
+
current = label;
|
|
2965
|
+
values[current] = [match[2] ?? ""];
|
|
2966
|
+
} else if (current) values[current].push(line);
|
|
2967
|
+
}
|
|
2968
|
+
const join$1 = (key) => {
|
|
2969
|
+
const parts = values[key];
|
|
2970
|
+
if (parts === void 0) return void 0;
|
|
2971
|
+
const joined = parts.join("\n").trim();
|
|
2972
|
+
if (joined === "") return void 0;
|
|
2973
|
+
if (/^<[^>\n]*\s[^>\n]*>$/.test(joined)) return void 0;
|
|
2974
|
+
return joined;
|
|
2975
|
+
};
|
|
2976
|
+
return {
|
|
2977
|
+
state: join$1("STATE") ?? "unknown",
|
|
2978
|
+
summary: join$1("SUMMARY"),
|
|
2979
|
+
ask: join$1("ASK"),
|
|
2980
|
+
artifact: join$1("ARTIFACT"),
|
|
2981
|
+
reportId: join$1("REPORT_ID"),
|
|
2982
|
+
raw,
|
|
2983
|
+
found: true
|
|
2984
|
+
};
|
|
2985
|
+
}
|
|
2986
|
+
/** The trailer instruction `drive_task` appends when `expectReport` is on, so a
|
|
2987
|
+
* driven session ends its turn with a parseable {@link parseOperatorReport} block.
|
|
2988
|
+
* When `reportId` is supplied it is embedded as a `REPORT_ID` line the session must
|
|
2989
|
+
* copy verbatim, so the driver can confirm the parsed report is for THIS turn and not
|
|
2990
|
+
* a stale prior-turn trailer still inside the transcript tail window. */
|
|
2991
|
+
function operatorReportInstruction(reportId) {
|
|
2992
|
+
const lines = [
|
|
2993
|
+
"",
|
|
2994
|
+
reportId !== void 0 ? "When you have completely finished this task, end your FINAL message with EXACTLY this trailer. Copy the REPORT_ID line verbatim and fill in each other field:" : "When you have completely finished this task, end your FINAL message with EXACTLY this trailer, filling in each field:",
|
|
2995
|
+
OPERATOR_REPORT_HEADER
|
|
2996
|
+
];
|
|
2997
|
+
if (reportId !== void 0) lines.push(`REPORT_ID: ${reportId}`);
|
|
2998
|
+
lines.push("STATE: <done | blocked | needs_input | in_progress>", "SUMMARY: <1-3 sentence summary of what you did>", "ASK: <what you need from the operator, or 'none'>", "ARTIFACT: <path or URL to the primary artifact, or 'none'>", OPERATOR_REPORT_FOOTER);
|
|
2999
|
+
return lines.join("\n");
|
|
3000
|
+
}
|
|
3001
|
+
function notReadyState(reason) {
|
|
3002
|
+
switch (reason) {
|
|
3003
|
+
case "busy": return "busy";
|
|
3004
|
+
case "awaiting_other": return "awaiting_other";
|
|
3005
|
+
case "terminal": return "dead";
|
|
3006
|
+
default: return "unknown";
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
async function readTail(client, localId, lines, signal) {
|
|
3010
|
+
try {
|
|
3011
|
+
const response = await client.readSession(localId, lines, signal);
|
|
3012
|
+
return typeof response.text === "string" ? response.text : "";
|
|
3013
|
+
} catch {
|
|
3014
|
+
return "";
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Drive one prompt on a session to completion and return the parsed operator report.
|
|
3019
|
+
* Flow: ensure the composer is idle (C1) -> send + surface whether the bytes reached
|
|
3020
|
+
* the composer (C2 `submitted`; a delivered-but-unconfirmed send still proceeds, since
|
|
3021
|
+
* the turn wait + timeout recovery covers the "nothing landed" case) -> wait for
|
|
3022
|
+
* `turn_ended`/`waiting_input` (C2) -> read the transcript tail -> parse the operator
|
|
3023
|
+
* report trailer -> if the turn did not settle in `timeoutMs`, AUTO-RECOVER via a
|
|
3024
|
+
* Ctrl-C interrupt (C4) rather than blocking (~10 min stop-hook hang), then re-wait
|
|
3025
|
+
* briefly and re-read. Robust to a busy session, a missing trailer (state:"unknown"),
|
|
3026
|
+
* and a hung stop hook.
|
|
3027
|
+
*/
|
|
3028
|
+
async function driveTask(deps) {
|
|
3029
|
+
const { client, localId, prompt, timeoutMs, expectReport, idempotencyKey, interruptKey, reportId, signal } = deps;
|
|
3030
|
+
const now = deps.now ?? Date.now;
|
|
3031
|
+
const sleep$1 = deps.sleep ?? realSleep;
|
|
3032
|
+
const tailLines = deps.tailLines ?? DEFAULT_TAIL_LINES;
|
|
3033
|
+
const pollTimeoutMs = deps.pollTimeoutMs;
|
|
3034
|
+
const readyResult = await waitForMessageReady(client, localId, {
|
|
3035
|
+
waitMs: deps.idleWaitMs ?? DEFAULT_IDLE_WAIT_MS,
|
|
3036
|
+
now,
|
|
3037
|
+
sleep: sleep$1,
|
|
3038
|
+
signal
|
|
3039
|
+
});
|
|
3040
|
+
if (!readyResult.ready && isHardNotReady(readyResult.readiness.reason)) return {
|
|
3041
|
+
submitted: false,
|
|
3042
|
+
delivered: false,
|
|
3043
|
+
settled: "timeout",
|
|
3044
|
+
state: notReadyState(readyResult.readiness.reason),
|
|
3045
|
+
raw: "",
|
|
3046
|
+
reportFound: false,
|
|
3047
|
+
interrupted: false,
|
|
3048
|
+
recovered: false,
|
|
3049
|
+
notReady: true,
|
|
3050
|
+
readiness: readyResult.readiness,
|
|
3051
|
+
error: "not_ready"
|
|
3052
|
+
};
|
|
3053
|
+
let cursor = await primeTurnCursor(client, localId, deps.primeTimeoutMs ?? DEFAULT_PRIME_TIMEOUT_MS, signal);
|
|
3054
|
+
const cursorPrimed = cursor !== void 0;
|
|
3055
|
+
const message = expectReport ? `${prompt}\n${operatorReportInstruction(reportId)}` : prompt;
|
|
3056
|
+
const send = await client.sendMessage(localId, {
|
|
3057
|
+
message,
|
|
3058
|
+
idempotencyKey,
|
|
3059
|
+
awaitMs: 0
|
|
3060
|
+
}, signal);
|
|
3061
|
+
const submitted = send.submission?.status === "submitted";
|
|
3062
|
+
if (send.delivered === false || send.delivery?.status === "failed" || send.delivery?.status === "error") return {
|
|
3063
|
+
submitted: false,
|
|
3064
|
+
delivered: false,
|
|
3065
|
+
settled: "timeout",
|
|
3066
|
+
state: "send_failed",
|
|
3067
|
+
raw: "",
|
|
3068
|
+
reportFound: false,
|
|
3069
|
+
interrupted: false,
|
|
3070
|
+
recovered: false,
|
|
3071
|
+
cursorPrimed,
|
|
3072
|
+
sendConfirmation: send.confirmation,
|
|
3073
|
+
error: "delivery_failed"
|
|
3074
|
+
};
|
|
3075
|
+
let settle = await waitForTurnSettled(client, localId, {
|
|
3076
|
+
timeoutMs,
|
|
3077
|
+
pollTimeoutMs,
|
|
3078
|
+
cursor,
|
|
3079
|
+
now,
|
|
3080
|
+
sleep: sleep$1,
|
|
3081
|
+
signal
|
|
3082
|
+
});
|
|
3083
|
+
cursor = settle.cursor;
|
|
3084
|
+
const isCurrentReport = (r) => expectReport && r.found && r.reportId !== void 0 && r.reportId === reportId;
|
|
3085
|
+
let tail = signal?.aborted ? "" : await readTail(client, localId, tailLines, signal);
|
|
3086
|
+
let report = parseOperatorReport(tail);
|
|
3087
|
+
let interrupted = false;
|
|
3088
|
+
let recovered = false;
|
|
3089
|
+
const aborted = settle.reason === "aborted" || signal?.aborted === true;
|
|
3090
|
+
if (!settle.settled && !aborted) {
|
|
3091
|
+
interrupted = true;
|
|
3092
|
+
await client.sendKeys(localId, {
|
|
3093
|
+
keys: INTERRUPT_KEY,
|
|
3094
|
+
idempotencyKey: interruptKey,
|
|
3095
|
+
raw: false
|
|
3096
|
+
}, signal).catch(() => {});
|
|
3097
|
+
const recovery = await waitForTurnSettled(client, localId, {
|
|
3098
|
+
timeoutMs: deps.recoverTimeoutMs ?? DEFAULT_RECOVER_MS,
|
|
3099
|
+
pollTimeoutMs,
|
|
3100
|
+
cursor,
|
|
3101
|
+
now,
|
|
3102
|
+
sleep: sleep$1,
|
|
3103
|
+
signal
|
|
3104
|
+
});
|
|
3105
|
+
recovered = recovery.settled;
|
|
3106
|
+
if (recovery.settled) settle = recovery;
|
|
3107
|
+
const recoveredTail = await readTail(client, localId, tailLines, signal);
|
|
3108
|
+
const recoveredReport = parseOperatorReport(recoveredTail);
|
|
3109
|
+
if (recoveredTail !== "" && (isCurrentReport(recoveredReport) || !isCurrentReport(report))) {
|
|
3110
|
+
tail = recoveredTail;
|
|
3111
|
+
report = recoveredReport;
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
const settledReason = settle.settled ? settle.reason : settle.reason === "aborted" || signal?.aborted === true ? "aborted" : "timeout";
|
|
3115
|
+
const settleDerivedState = settledReason === "waiting_input" ? "awaiting_input" : settledReason === "aborted" ? "aborted" : settledReason === "timeout" ? "timeout" : "unknown";
|
|
3116
|
+
const reportCurrent = isCurrentReport(report);
|
|
3117
|
+
return {
|
|
3118
|
+
submitted,
|
|
3119
|
+
delivered: true,
|
|
3120
|
+
settled: settledReason,
|
|
3121
|
+
state: settledReason === "waiting_input" ? "awaiting_input" : reportCurrent && report.state !== "unknown" ? report.state : settleDerivedState,
|
|
3122
|
+
summary: reportCurrent ? report.summary : void 0,
|
|
3123
|
+
ask: reportCurrent ? report.ask : void 0,
|
|
3124
|
+
artifact: reportCurrent ? report.artifact : void 0,
|
|
3125
|
+
raw: tail,
|
|
3126
|
+
reportFound: reportCurrent,
|
|
3127
|
+
interrupted,
|
|
3128
|
+
recovered,
|
|
3129
|
+
cursorPrimed,
|
|
3130
|
+
sendConfirmation: send.confirmation
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
|
|
2676
3134
|
//#endregion
|
|
2677
3135
|
//#region src/lib/fleet/tools.ts
|
|
2678
3136
|
const FLEET_GROUP = "fleet";
|
|
@@ -2681,6 +3139,7 @@ const INSTANCE_PROBE_CACHE_TTL_MS = 5e3;
|
|
|
2681
3139
|
const CAPABILITIES_CACHE_TTL_MS = 6e4;
|
|
2682
3140
|
const AWAIT_TURN_DEFAULT_TIMEOUT_MS = 3e4;
|
|
2683
3141
|
const AWAIT_TURN_TIMEOUT_SLACK_MS = 5e3;
|
|
3142
|
+
const DRIVE_TASK_DEFAULT_TIMEOUT_MS = 12e4;
|
|
2684
3143
|
const LIST_INSTANCES_FANOUT_CONCURRENCY = 16;
|
|
2685
3144
|
const AWAIT_TURN_FANOUT_CONCURRENCY = 256;
|
|
2686
3145
|
const INSTANCE_PROBE_RATE_LIMIT_MAX_RETRIES = 1;
|
|
@@ -2874,22 +3333,47 @@ function createFleetTools(options = {}) {
|
|
|
2874
3333
|
sessionId: globalId
|
|
2875
3334
|
});
|
|
2876
3335
|
}),
|
|
2877
|
-
tool$1("send_message", "Send a message to a fleet session.
|
|
3336
|
+
tool$1("send_message", "Send a message to a fleet session. By DEFAULT it first checks the session is idle / awaiting the next message and REFUSES (structured notReady, isError) rather than blind-type into a busy composer or a pending prompt — set requireIdle:false to force the legacy unconditional send, or waitForIdleMs to wait briefly for idle first. isError reflects DELIVERY: true when the message was not delivered (transport/precondition failure) OR refused as notReady. A delivered message whose confirmation did not arrive within awaitMs is NOT an error — it returns delivered:true with confirmationPending/confirmationTimedOut, because a long turn legitimately outruns awaitMs. The additive `submitted` field is true only when ai-or-die's submission sub-status proves the message reached the composer. Recommended pattern: send with awaitMs:0 for a fast delivery ack, then call await_turn (filtered to this sessionId) to observe the session's actual turn completion. The idempotencyKey makes a retried send safe (a retry never re-types the message).", objectSchema$1({
|
|
2878
3337
|
sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
|
|
2879
3338
|
instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
|
|
2880
3339
|
message: stringProp$1("Message text to deliver to the session."),
|
|
2881
3340
|
idempotencyKey: stringProp$1("Optional caller idempotency key; AUTO-GENERATED when omitted, so you normally never pass it. Supply your OWN stable key only when you will retry the SAME send and need the upstream to dedupe it."),
|
|
2882
|
-
awaitMs: numberProp$1("Optional best-effort confirmation wait (ms) — NOT a deadline. Prefer awaitMs:0 plus await_turn; a turn that outruns awaitMs returns confirmationPending, not an error.")
|
|
3341
|
+
awaitMs: numberProp$1("Optional best-effort confirmation wait (ms) — NOT a deadline. Prefer awaitMs:0 plus await_turn; a turn that outruns awaitMs returns confirmationPending, not an error."),
|
|
3342
|
+
requireIdle: booleanProp("Default true: check status and refuse a busy/awaiting-prompt/dead session with a structured notReady result. Set false to force an unconditional send (unsafe: may type into a busy composer)."),
|
|
3343
|
+
waitForIdleMs: numberProp$1("When requireIdle, wait up to this many ms for the session to become idle before deciding (default 0 = decide immediately).")
|
|
2883
3344
|
}, ["sessionId", "message"]), async (args, signal) => {
|
|
2884
3345
|
const { instance, localId, globalId } = await resolveSession(args);
|
|
2885
3346
|
const awaitMs = optionalNumber$1(args, "awaitMs");
|
|
2886
|
-
const
|
|
3347
|
+
const requireIdle = optionalBoolean(args, "requireIdle") ?? true;
|
|
3348
|
+
const client = clientFor(instance);
|
|
3349
|
+
if (requireIdle) {
|
|
3350
|
+
const readyResult = await waitForMessageReady(client, localId, {
|
|
3351
|
+
waitMs: optionalNumber$1(args, "waitForIdleMs") ?? 0,
|
|
3352
|
+
signal
|
|
3353
|
+
});
|
|
3354
|
+
if (!readyResult.ready && isHardNotReady(readyResult.readiness.reason)) {
|
|
3355
|
+
const advise = readyResult.readiness.reason === "awaiting_other" ? " The session is awaiting a prompt — use `respond`, not a free-text message." : readyResult.readiness.reason === "terminal" ? " The session has exited." : " Wait for it to go idle (await_turn) or set requireIdle:false to force.";
|
|
3356
|
+
return jsonResult$1({
|
|
3357
|
+
resolvedInstance: publicInstance(instance),
|
|
3358
|
+
sessionId: globalId,
|
|
3359
|
+
delivered: false,
|
|
3360
|
+
submitted: false,
|
|
3361
|
+
notReady: true,
|
|
3362
|
+
reason: readyResult.readiness.reason,
|
|
3363
|
+
interactionState: readyResult.readiness.interactionState,
|
|
3364
|
+
awaitingKind: readyResult.readiness.awaitingKind,
|
|
3365
|
+
message: `not sent: session is not ready for a message (${readyResult.readiness.reason}).${advise}`
|
|
3366
|
+
}, true);
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
const response = await client.sendMessage(localId, {
|
|
2887
3370
|
message: requiredString$1(args, "message"),
|
|
2888
3371
|
idempotencyKey: optionalString$1(args, "idempotencyKey") ?? randomUUID(),
|
|
2889
3372
|
...awaitMs === void 0 ? {} : { awaitMs }
|
|
2890
3373
|
}, signal);
|
|
2891
3374
|
const delivered = !(response.delivered === false || response.delivery?.status === "failed" || response.delivery?.status === "error");
|
|
2892
3375
|
const confirmed = delivered && response.confirmed === true;
|
|
3376
|
+
const submitted = delivered && response.submission?.status === "submitted";
|
|
2893
3377
|
const confirmationTimedOut = delivered && !confirmed && (awaitMs !== void 0 && awaitMs > 0 || response.confirmationTimedOut === true);
|
|
2894
3378
|
const isError = !delivered;
|
|
2895
3379
|
return jsonResult$1({
|
|
@@ -2898,6 +3382,7 @@ function createFleetTools(options = {}) {
|
|
|
2898
3382
|
...response,
|
|
2899
3383
|
delivered,
|
|
2900
3384
|
confirmed,
|
|
3385
|
+
submitted,
|
|
2901
3386
|
...confirmationTimedOut ? {
|
|
2902
3387
|
confirmationPending: true,
|
|
2903
3388
|
confirmationTimedOut: true
|
|
@@ -2905,23 +3390,41 @@ function createFleetTools(options = {}) {
|
|
|
2905
3390
|
...isError ? { message: "message was not delivered to the session by the upstream instance" } : confirmationTimedOut ? { message: "delivered; turn completion not confirmed in the await window. Use await_turn filtered to this sessionId to observe completion (the idempotencyKey makes a retried send safe)." } : {}
|
|
2906
3391
|
}, isError);
|
|
2907
3392
|
}),
|
|
2908
|
-
tool$1("send_keys", "Send key input to a fleet session.", objectSchema$1({
|
|
3393
|
+
tool$1("send_keys", "Send key input to a fleet session. Prefer the higher-level `op`: 'submit' presses Enter and 'interrupt' sends Ctrl-C, each mapped to ai-or-die's NAMED key (never a literal control byte like \"\\r\"). Use `keys` only for literal input; `raw` is strictly for literal bytes. Provide exactly one of `op` or `keys`.", objectSchema$1({
|
|
2909
3394
|
sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
|
|
2910
3395
|
instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
|
|
2911
|
-
|
|
3396
|
+
op: stringProp$1("Higher-level named op: 'submit' (Enter) or 'interrupt' (Ctrl-C). Mapped to the ai-or-die named key with raw off. Do NOT also pass keys."),
|
|
3397
|
+
keys: stringProp$1("Literal key sequence to send. Provide instead of op."),
|
|
2912
3398
|
idempotencyKey: stringProp$1("Optional caller idempotency key; auto-generated when omitted."),
|
|
2913
|
-
raw: booleanProp("Pass keys through as raw
|
|
2914
|
-
}, ["sessionId"
|
|
3399
|
+
raw: booleanProp("Pass keys through as raw literal bytes when the instance supports it. Ignored when op is set.")
|
|
3400
|
+
}, ["sessionId"]), async (args, signal) => {
|
|
2915
3401
|
const { instance, localId, globalId } = await resolveSession(args);
|
|
2916
|
-
const
|
|
3402
|
+
const op = optionalString$1(args, "op");
|
|
3403
|
+
const literalKeys = optionalString$1(args, "keys");
|
|
3404
|
+
if (op !== void 0 && literalKeys !== void 0) throw new FleetToolInputError("INVALID_ARGUMENT", "provide either arguments.op or arguments.keys, not both");
|
|
3405
|
+
if (op === void 0 && literalKeys === void 0) throw new FleetToolInputError("INVALID_ARGUMENT", "one of arguments.op or arguments.keys is required");
|
|
3406
|
+
let keys;
|
|
3407
|
+
let raw;
|
|
3408
|
+
if (op !== void 0) {
|
|
3409
|
+
if (!isNamedKeyOp(op)) throw new FleetToolInputError("INVALID_ARGUMENT", `arguments.op must be 'submit' or 'interrupt' (got ${JSON.stringify(op)})`);
|
|
3410
|
+
keys = mapNamedKeyOp(op);
|
|
3411
|
+
raw = false;
|
|
3412
|
+
} else {
|
|
3413
|
+
keys = literalKeys;
|
|
3414
|
+
raw = optionalBoolean(args, "raw");
|
|
3415
|
+
}
|
|
2917
3416
|
const response = await clientFor(instance).sendKeys(localId, {
|
|
2918
|
-
keys
|
|
3417
|
+
keys,
|
|
2919
3418
|
idempotencyKey: optionalString$1(args, "idempotencyKey") ?? randomUUID(),
|
|
2920
3419
|
...raw === void 0 ? {} : { raw }
|
|
2921
3420
|
}, signal);
|
|
2922
3421
|
return ok$1({
|
|
2923
3422
|
resolvedInstance: publicInstance(instance),
|
|
2924
3423
|
sessionId: globalId,
|
|
3424
|
+
...op === void 0 ? {} : {
|
|
3425
|
+
op,
|
|
3426
|
+
mappedKeys: keys
|
|
3427
|
+
},
|
|
2925
3428
|
...response
|
|
2926
3429
|
});
|
|
2927
3430
|
}),
|
|
@@ -2956,15 +3459,18 @@ function createFleetTools(options = {}) {
|
|
|
2956
3459
|
start: booleanProp("Whether the remote instance should start the session immediately."),
|
|
2957
3460
|
readyTimeoutMs: numberProp$1("F17: bounded ms to wait for the agent to become driveable before returning. The response carries ready/bound/blocker."),
|
|
2958
3461
|
permissionMode: stringProp$1("F10 (claude only): permission mode the launched agent starts in — one of plan | acceptEdits | default | bypassPermissions. Rejected with BAD_REQUEST if unknown or if agentArgs also sets it."),
|
|
2959
|
-
agentArgs: arrayProp("F10 (claude only): extra launcher args appended after the github-router prefix. Must NOT include --permission-mode or --dangerously-skip-permissions (use permissionMode) — rejected with BAD_REQUEST.")
|
|
3462
|
+
agentArgs: arrayProp("F10 (claude only): extra launcher args appended after the github-router prefix. Must NOT include --permission-mode or --dangerously-skip-permissions (use permissionMode) — rejected with BAD_REQUEST."),
|
|
3463
|
+
disableStopGate: booleanProp("C3 (claude only): disable the structural Stop-gate on the launched session by injecting --no-stop-gate into agentArgs, so a driven session's turn-end never hangs on a blocking Stop hook. Requires a remote github-router that understands the flag (uses the agent_args capability).")
|
|
2960
3464
|
}, ["instance", "agent"]), async (args, signal) => {
|
|
2961
3465
|
const instance = await resolve(requiredString$1(args, "instance"));
|
|
2962
3466
|
const agent = requiredString$1(args, "agent");
|
|
2963
3467
|
const idempotencyKey = optionalString$1(args, "idempotencyKey") ?? randomUUID();
|
|
2964
3468
|
const permissionMode = optionalString$1(args, "permissionMode");
|
|
2965
|
-
const
|
|
3469
|
+
const disableStopGate = optionalBoolean(args, "disableStopGate") === true;
|
|
3470
|
+
const requestedAgentArgs = optionalStringArray(args, "agentArgs");
|
|
3471
|
+
const agentArgs = disableStopGate ? [...requestedAgentArgs ?? [], "--no-stop-gate"] : requestedAgentArgs;
|
|
2966
3472
|
if (permissionMode !== void 0) await assertCapability(instance, "permission_mode", "permissionMode", signal);
|
|
2967
|
-
if (agentArgs !== void 0) await assertCapability(instance, "agent_args", "agentArgs", signal);
|
|
3473
|
+
if (agentArgs !== void 0) await assertCapability(instance, "agent_args", disableStopGate ? "disableStopGate" : "agentArgs", signal);
|
|
2968
3474
|
const response = await clientFor(instance).createSession(definedObject({
|
|
2969
3475
|
agent,
|
|
2970
3476
|
name: optionalString$1(args, "name"),
|
|
@@ -3052,10 +3558,12 @@ function createFleetTools(options = {}) {
|
|
|
3052
3558
|
instance: publicInstance(instance),
|
|
3053
3559
|
...gap
|
|
3054
3560
|
})));
|
|
3561
|
+
const settled = classifyTurnEvents(events$1);
|
|
3055
3562
|
return ok$1({
|
|
3056
3563
|
resolvedInstances: target.instances.map(publicInstance),
|
|
3057
3564
|
events: events$1,
|
|
3058
3565
|
gaps,
|
|
3566
|
+
...settled.length > 0 ? { settled } : {},
|
|
3059
3567
|
cursors: responses.map(({ instance, response }) => ({
|
|
3060
3568
|
instance: publicInstance(instance),
|
|
3061
3569
|
cursor: response.cursor
|
|
@@ -3064,6 +3572,31 @@ function createFleetTools(options = {}) {
|
|
|
3064
3572
|
...errors.length > 0 ? { errors } : {}
|
|
3065
3573
|
});
|
|
3066
3574
|
}),
|
|
3575
|
+
tool$1("drive_task", "Drive one prompt on a session to completion and return the parsed operator report. Composes the reliable path: ensure the composer is idle (else return a structured busy/not-ready result), send and surface whether the message reached the composer (submitted; a delivered-but-unconfirmed send still proceeds), wait for the RELIABLE turn boundary (turn_ended / waiting_input — never the became_idle flicker), read the transcript tail, and parse the OPERATOR REPORT trailer into {state, summary, ask, artifact, raw}. A per-call REPORT_ID nonce is embedded in the trailer instruction and the parsed report is trusted ONLY when it echoes that nonce, so a stale prior-turn trailer left in the tail can never be returned as this turn's result. A reliable waiting_input outranks the model's self-reported STATE (a still-blocked session is never reported as done). If the turn does not end within timeoutMs (e.g. a blocking Stop hook that would otherwise hang ~10 min), it AUTO-RECOVERS with a Ctrl-C interrupt rather than blocking, then re-waits briefly and re-reads; a caller ABORT is distinct (settled:'aborted', state:'aborted') and never injects a Ctrl-C. Read `state` TOGETHER with `settled`/`interrupted`/`recovered`: state:'done' with settled:'timeout' + interrupted:true means the model reported done but the turn had to be interrupted to recover, so treat it as needs-verification rather than a clean completion; `submitted` is a best-effort positive signal that CAN be false even on a successful turn. Robust to a busy session (state:'busy'), a missing/stale/placeholder trailer (state falls back to the settle-derived value, reportFound:false), and a hung hook (interrupted:true, recovered:true/false). By default it appends the trailer instruction so the driven session emits a parseable report; set expectReport:false to send the prompt verbatim (a trailer left in the tail is then never trusted).", objectSchema$1({
|
|
3576
|
+
sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
|
|
3577
|
+
instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
|
|
3578
|
+
prompt: stringProp$1("The task/prompt to drive on the session."),
|
|
3579
|
+
timeoutMs: numberProp$1(`Ms to wait for the turn to end before auto-recovering via interrupt (default ${DRIVE_TASK_DEFAULT_TIMEOUT_MS}). Set generously — exceeding it triggers a Ctrl-C recovery.`),
|
|
3580
|
+
expectReport: booleanProp("Default true: append the OPERATOR REPORT trailer instruction so the driven session ends its turn with a parseable {state,summary,ask,artifact}. Set false to send the prompt verbatim.")
|
|
3581
|
+
}, ["sessionId", "prompt"]), async (args, signal) => {
|
|
3582
|
+
const { instance, localId, globalId } = await resolveSession(args);
|
|
3583
|
+
const result = await driveTask({
|
|
3584
|
+
client: clientFor(instance),
|
|
3585
|
+
localId,
|
|
3586
|
+
prompt: requiredString$1(args, "prompt"),
|
|
3587
|
+
timeoutMs: optionalNumber$1(args, "timeoutMs") ?? DRIVE_TASK_DEFAULT_TIMEOUT_MS,
|
|
3588
|
+
expectReport: optionalBoolean(args, "expectReport") ?? true,
|
|
3589
|
+
idempotencyKey: randomUUID(),
|
|
3590
|
+
interruptKey: randomUUID(),
|
|
3591
|
+
reportId: randomUUID(),
|
|
3592
|
+
signal
|
|
3593
|
+
});
|
|
3594
|
+
return jsonResult$1({
|
|
3595
|
+
resolvedInstance: publicInstance(instance),
|
|
3596
|
+
sessionId: globalId,
|
|
3597
|
+
...result
|
|
3598
|
+
}, result.error !== void 0);
|
|
3599
|
+
}),
|
|
3067
3600
|
tool$1("read_file", "Read a file from one fleet instance via its existing /api/files/content endpoint.", objectSchema$1({
|
|
3068
3601
|
instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance."),
|
|
3069
3602
|
path: stringProp$1("Remote file path to read.")
|
|
@@ -24305,6 +24838,16 @@ function stopGateId(env = process.env) {
|
|
|
24305
24838
|
const v = (env.GH_ROUTER_STOP_GATE_ID ?? "").trim();
|
|
24306
24839
|
return v.length > 0 ? v : "default-ci";
|
|
24307
24840
|
}
|
|
24841
|
+
/**
|
|
24842
|
+
* C3: whether the structural Stop-gate is disabled for THIS launch. True when the
|
|
24843
|
+
* `GH_ROUTER_DISABLE_STOP_GATE` env is set OR the `--no-stop-gate` launcher flag was
|
|
24844
|
+
* passed (`args["no-stop-gate"] === true`). A DRIVEN session sets the flag so a
|
|
24845
|
+
* blocking Stop hook never hangs its turn-end (~10 min) waiting on the fleet driver.
|
|
24846
|
+
* Pure so it is unit-testable without the live launch path.
|
|
24847
|
+
*/
|
|
24848
|
+
function stopGateDisabled(args, env = process.env) {
|
|
24849
|
+
return parseBoolEnv(env.GH_ROUTER_DISABLE_STOP_GATE) === true || args["no-stop-gate"] === true;
|
|
24850
|
+
}
|
|
24308
24851
|
/** True when a settings `Stop` entry already registers `command` (so the merge
|
|
24309
24852
|
* is idempotent across re-launches). */
|
|
24310
24853
|
function entryHasCommand(entry, command) {
|
|
@@ -26346,5 +26889,5 @@ async function runStandInToolCall(args, signal) {
|
|
|
26346
26889
|
}
|
|
26347
26890
|
|
|
26348
26891
|
//#endregion
|
|
26349
|
-
export {
|
|
26350
|
-
//# sourceMappingURL=peer-mcp-personas-
|
|
26892
|
+
export { logStreamError as $, copilotBaseUrl as $t, BROWSE_DEFAULT_MODEL as A, UPSTREAM_FETCH_TIMEOUT_MS as At, toolbeltEnabled as B, cacheCopilotVersion as Bt, repoFingerprint as C, ArtifactClient as Ct, trustRepo as D, DEFAULT_CODEX_MODEL as Dt, stopReviewStateDir as E, DEFAULT_CLAUDE_MODEL_FALLBACKS as Et, appendPlanReminder as F, withInstallLock as Ft, searchWeb as G, resolveCodexModel as Gt, vscodeRipgrepPath as H, cacheVSCodeVersion as Ht, runWorkerAgent as I, setupCopilotToken as It, buildAdvisorStream as J, getModels as Jt, ADVISOR_INTERNAL_TOOL_NAME as K, resolveModel as Kt, withNoOutputRetry as L, setupGitHubAgentToken as Lt, IMPLEMENT_DEFAULT_MODEL as M, generateRandomPort as Mt, PLAN_DEFAULT_MODEL as N, pickClaudeDefault as Nt, resolveSealedGate as O, DEFAULT_CODEX_MODEL_FALLBACKS as Ot, REVIEW_DEFAULT_MODEL as P, getPackageVersion as Pt, isControllerClosedError as Q, GITHUB_API_BASE_URL as Qt, availableToolCommands as R, setupGitHubToken as Rt, isSubagentContext as S, shouldUseInsecureTls as St, stopGateEnabledForRepo as T, toolbeltPathOverride as Tt, TOOLBELT_TOOLS$1 as U, filterBetaHeader as Ut, toolbeltSkipSet as V, cacheModels as Vt, assetFor as W, isNullish as Wt, isAdvisorRequested as X, HTTPError as Xt, injectAdvisorTool as Y, fetchWithTransientRetry as Yt, buildOpenAIErrorEvent as Z, forwardError as Zt, stopReviewEnabled as _, provisionBrowserAssets as _t, buildPeerAwarenessSnippet as a, browserToolsEnabled as at, fileLastPromptStore as b, extractTarGzMember as bt, buildSessionBindHookCommand as c, workerToolsEnabled as ct, decideStopHook as d, getTokenCount as dt, copilotHeaders as en, readIteratorWithTimeout as et, fileBlockBudget as f, createResponses as ft, stopGateId as g, parseJsonOrDiagnose as gt, stopGateDisabled as h, readResponseBodyCapped as ht, buildAgentPrompt as i, agentToolsEnabled as it, DEFAULT_MODEL as j, UPSTREAM_INACTIVITY_TIMEOUT_MS as jt, liveExec as k, DEFAULT_PORT as kt, buildStopHookCommand as l, countTokens as lt, launchBaselineKey as m, MAX_RESPONSE_BODY_BYTES as mt, MCP_GROUPS as n, state as nn, handleMcpDelete as nt, personasFor as o, fleetToolsEnabled as ot, injectStopHookIntoSettingsFile as p, createChatCompletions as pt, ADVISOR_TOOL_INSTRUCTIONS as q, sleep as qt, assertMcpToolSurfaceConsistent as r, handleMcpPost as rt, buildArtifactOpenHookCommand as s, standInToolEnabled as st, GROUP_META as t, githubHeaders as tn, relayAnthropicStream as tt, captureLaunchBaseline as u, createMessages as ut, fileBaselineStore as v, hasSupportedBrowserInstalled as vt, repoRoot as w, collapsePathKeys as wt, fileReviewDebounce as x, extractZipMember as xt, fileFindingsStore as y, provisionAndIndexColbert as yt, buildToolbeltAwareness as z, tryRefreshAndRetry as zt };
|
|
26893
|
+
//# sourceMappingURL=peer-mcp-personas-Dm3UCpXz.js.map
|