autodev-cli 1.4.171 → 1.4.173
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/out/cliExit.js +5 -0
- package/out/cliExit.js.map +1 -1
- package/out/core/retryBackoff.d.ts +55 -0
- package/out/core/retryBackoff.js +88 -0
- package/out/core/retryBackoff.js.map +1 -0
- package/out/core/settingsLoader.d.ts +9 -0
- package/out/core/settingsLoader.js +1 -0
- package/out/core/settingsLoader.js.map +1 -1
- package/out/providers/grok/authClassify.d.ts +48 -0
- package/out/providers/grok/authClassify.js +81 -0
- package/out/providers/grok/authClassify.js.map +1 -0
- package/out/providers/grok/tui.js +87 -14
- package/out/providers/grok/tui.js.map +1 -1
- package/out/rateLimit.js +10 -0
- package/out/rateLimit.js.map +1 -1
- package/out/taskLoop.d.ts +21 -0
- package/out/taskLoop.js +130 -10
- package/out/taskLoop.js.map +1 -1
- package/package.json +2 -2
package/out/cliExit.js
CHANGED
|
@@ -69,6 +69,11 @@ const rateLimit_1 = require("./rateLimit");
|
|
|
69
69
|
const FAIL_REASONS = new Set([
|
|
70
70
|
'reauth_required', 'startup-exit', 'session-exit', 'launch-failed',
|
|
71
71
|
'watchdog', 'error', 'session.error',
|
|
72
|
+
// grok's native "Turn failed: Grok stopped before this turn finished" banner
|
|
73
|
+
// (process exited/restarted mid-turn) with credentials present — a TRANSIENT
|
|
74
|
+
// provider failure. Precise label; retryable via shouldRetryHardFail. Without
|
|
75
|
+
// this, the turn used to be misread as a clean idle (a false green).
|
|
76
|
+
'turn-failed',
|
|
72
77
|
]);
|
|
73
78
|
/**
|
|
74
79
|
* Hook events that prove the turn actually produced work this cycle. Their
|
package/out/cliExit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliExit.js","sourceRoot":"","sources":["../src/cliExit.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,2CAA2C;AAC3C,EAAE;AACF,2BAA2B;AAC3B,gEAAgE;AAChE,yEAAyE;AACzE,EAAE;AACF,6BAA6B;AAC7B,mEAAmE;AACnE,2EAA2E;AAC3E,+EAA+E;AAC/E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,wEAAwE;AACxE,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,0DAA0D;AAC1D,8EAA8E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9E,uCAAyB;AACzB,2CAA6B;AAC7B,iCAAyC;AACzC,2CAAgE;AAyBhE;;;;;GAKG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACnC,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe;IAClE,UAAU,EAAE,OAAO,EAAE,eAAe;
|
|
1
|
+
{"version":3,"file":"cliExit.js","sourceRoot":"","sources":["../src/cliExit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the provider hard-failure retry-with-backoff mechanic.
|
|
3
|
+
*
|
|
4
|
+
* A transient provider turn failure (token blip, timeout, watchdog no-output,
|
|
5
|
+
* crash, "provider stopped or timed out", session-error) must NOT lose the
|
|
6
|
+
* task. The task loop retries the SAME task up to `maxProviderRetries` times
|
|
7
|
+
* (default 10) with exponential backoff before finally reporting it
|
|
8
|
+
* failed/blocked and marking it needs-attention.
|
|
9
|
+
*
|
|
10
|
+
* These two functions are intentionally pure (no I/O, no clock beyond
|
|
11
|
+
* Math.random for jitter) so they can be unit-tested in isolation and reused.
|
|
12
|
+
*/
|
|
13
|
+
/** Base delay for the first retry, in ms. */
|
|
14
|
+
export declare const RETRY_BASE_MS = 2000;
|
|
15
|
+
/** Growth factor per attempt. */
|
|
16
|
+
export declare const RETRY_FACTOR = 2;
|
|
17
|
+
/** Hard cap on any single backoff, in ms. */
|
|
18
|
+
export declare const RETRY_CAP_MS = 120000;
|
|
19
|
+
/** Jitter fraction applied to the (pre-cap) deterministic delay (±15%). */
|
|
20
|
+
export declare const RETRY_JITTER = 0.15;
|
|
21
|
+
/**
|
|
22
|
+
* Deterministic (jitter-free) center of the backoff curve for a 1-based attempt:
|
|
23
|
+
* attempt 1 → 2s, 2 → 4s, 3 → 8s, 4 → 16s, 5 → 32s, 6 → 64s,
|
|
24
|
+
* 7 → 120s (cap), 8 → 120s, 9 → 120s, 10 → 120s.
|
|
25
|
+
* Exposed so tests (and callers that want the schedule) can reason about it
|
|
26
|
+
* without depending on the random jitter.
|
|
27
|
+
*/
|
|
28
|
+
export declare function providerRetryBackoffCenterMs(attempt: number): number;
|
|
29
|
+
/**
|
|
30
|
+
* Exponential backoff for provider hard-failure retries, with light jitter.
|
|
31
|
+
*
|
|
32
|
+
* `attempt` is 1-based. The deterministic center doubles each attempt until it
|
|
33
|
+
* hits the 120s cap; ±15% jitter is applied around that center, and the result
|
|
34
|
+
* is clamped to [0, RETRY_CAP_MS] AFTER jitter so it can never exceed the cap
|
|
35
|
+
* even on the high side of the jitter band.
|
|
36
|
+
*
|
|
37
|
+
* Because the center doubles (×2) while the jitter band is only ±15%, adjacent
|
|
38
|
+
* attempts' jittered ranges never overlap below the cap — so the schedule is
|
|
39
|
+
* monotonically increasing until it saturates at the cap.
|
|
40
|
+
*/
|
|
41
|
+
export declare function providerRetryBackoffMs(attempt: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Should a provider hard-failure be retried before we give up on the task?
|
|
44
|
+
*
|
|
45
|
+
* Returns true when we still have budget (attempt <= max) AND the reason is a
|
|
46
|
+
* TRANSIENT/retryable provider failure. Every non-reauth hard_fail reason is
|
|
47
|
+
* treated as transient: watchdog / no-output, session-error / session.error,
|
|
48
|
+
* timeout, "provider stopped", crash / exit_nonzero, model-unavailable,
|
|
49
|
+
* startup-exit / session-exit / launch-failed, stop_failure, error, etc.
|
|
50
|
+
*
|
|
51
|
+
* @param reason the hard_fail reason label from CliExitHandler
|
|
52
|
+
* @param attempt 1-based number of the retry we are about to schedule
|
|
53
|
+
* @param max maximum number of retries (settings.maxProviderRetries ?? 10)
|
|
54
|
+
*/
|
|
55
|
+
export declare function shouldRetryHardFail(reason: string, attempt: number, max: number): boolean;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pure helpers for the provider hard-failure retry-with-backoff mechanic.
|
|
4
|
+
*
|
|
5
|
+
* A transient provider turn failure (token blip, timeout, watchdog no-output,
|
|
6
|
+
* crash, "provider stopped or timed out", session-error) must NOT lose the
|
|
7
|
+
* task. The task loop retries the SAME task up to `maxProviderRetries` times
|
|
8
|
+
* (default 10) with exponential backoff before finally reporting it
|
|
9
|
+
* failed/blocked and marking it needs-attention.
|
|
10
|
+
*
|
|
11
|
+
* These two functions are intentionally pure (no I/O, no clock beyond
|
|
12
|
+
* Math.random for jitter) so they can be unit-tested in isolation and reused.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.RETRY_JITTER = exports.RETRY_CAP_MS = exports.RETRY_FACTOR = exports.RETRY_BASE_MS = void 0;
|
|
16
|
+
exports.providerRetryBackoffCenterMs = providerRetryBackoffCenterMs;
|
|
17
|
+
exports.providerRetryBackoffMs = providerRetryBackoffMs;
|
|
18
|
+
exports.shouldRetryHardFail = shouldRetryHardFail;
|
|
19
|
+
/** Base delay for the first retry, in ms. */
|
|
20
|
+
exports.RETRY_BASE_MS = 2_000;
|
|
21
|
+
/** Growth factor per attempt. */
|
|
22
|
+
exports.RETRY_FACTOR = 2;
|
|
23
|
+
/** Hard cap on any single backoff, in ms. */
|
|
24
|
+
exports.RETRY_CAP_MS = 120_000;
|
|
25
|
+
/** Jitter fraction applied to the (pre-cap) deterministic delay (±15%). */
|
|
26
|
+
exports.RETRY_JITTER = 0.15;
|
|
27
|
+
/**
|
|
28
|
+
* Deterministic (jitter-free) center of the backoff curve for a 1-based attempt:
|
|
29
|
+
* attempt 1 → 2s, 2 → 4s, 3 → 8s, 4 → 16s, 5 → 32s, 6 → 64s,
|
|
30
|
+
* 7 → 120s (cap), 8 → 120s, 9 → 120s, 10 → 120s.
|
|
31
|
+
* Exposed so tests (and callers that want the schedule) can reason about it
|
|
32
|
+
* without depending on the random jitter.
|
|
33
|
+
*/
|
|
34
|
+
function providerRetryBackoffCenterMs(attempt) {
|
|
35
|
+
const n = Math.max(1, Math.floor(attempt));
|
|
36
|
+
const raw = exports.RETRY_BASE_MS * Math.pow(exports.RETRY_FACTOR, n - 1);
|
|
37
|
+
return Math.min(raw, exports.RETRY_CAP_MS);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Exponential backoff for provider hard-failure retries, with light jitter.
|
|
41
|
+
*
|
|
42
|
+
* `attempt` is 1-based. The deterministic center doubles each attempt until it
|
|
43
|
+
* hits the 120s cap; ±15% jitter is applied around that center, and the result
|
|
44
|
+
* is clamped to [0, RETRY_CAP_MS] AFTER jitter so it can never exceed the cap
|
|
45
|
+
* even on the high side of the jitter band.
|
|
46
|
+
*
|
|
47
|
+
* Because the center doubles (×2) while the jitter band is only ±15%, adjacent
|
|
48
|
+
* attempts' jittered ranges never overlap below the cap — so the schedule is
|
|
49
|
+
* monotonically increasing until it saturates at the cap.
|
|
50
|
+
*/
|
|
51
|
+
function providerRetryBackoffMs(attempt) {
|
|
52
|
+
const center = providerRetryBackoffCenterMs(attempt);
|
|
53
|
+
const jitterDelta = center * exports.RETRY_JITTER * (Math.random() * 2 - 1);
|
|
54
|
+
const withJitter = center + jitterDelta;
|
|
55
|
+
return Math.max(0, Math.min(Math.round(withJitter), exports.RETRY_CAP_MS));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reasons that are NEVER retried by the backoff mechanic — they own a different
|
|
59
|
+
* handling path and hammering them with retries would be wrong.
|
|
60
|
+
* - reauth_required: genuine auth/token expiry. The loop already pauses,
|
|
61
|
+
* notifies (reauth_required event + hook), and resumes on re-auth; burning
|
|
62
|
+
* 10 blind retries against an expired token helps nobody.
|
|
63
|
+
*/
|
|
64
|
+
const NON_RETRYABLE = new Set(['reauth_required']);
|
|
65
|
+
/**
|
|
66
|
+
* Should a provider hard-failure be retried before we give up on the task?
|
|
67
|
+
*
|
|
68
|
+
* Returns true when we still have budget (attempt <= max) AND the reason is a
|
|
69
|
+
* TRANSIENT/retryable provider failure. Every non-reauth hard_fail reason is
|
|
70
|
+
* treated as transient: watchdog / no-output, session-error / session.error,
|
|
71
|
+
* timeout, "provider stopped", crash / exit_nonzero, model-unavailable,
|
|
72
|
+
* startup-exit / session-exit / launch-failed, stop_failure, error, etc.
|
|
73
|
+
*
|
|
74
|
+
* @param reason the hard_fail reason label from CliExitHandler
|
|
75
|
+
* @param attempt 1-based number of the retry we are about to schedule
|
|
76
|
+
* @param max maximum number of retries (settings.maxProviderRetries ?? 10)
|
|
77
|
+
*/
|
|
78
|
+
function shouldRetryHardFail(reason, attempt, max) {
|
|
79
|
+
if (attempt > max) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const r = String(reason ?? '').trim().toLowerCase();
|
|
83
|
+
if (NON_RETRYABLE.has(r)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=retryBackoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryBackoff.js","sourceRoot":"","sources":["../../src/core/retryBackoff.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAkBH,oEAIC;AAcD,wDAKC;AAwBD,kDAKC;AApED,6CAA6C;AAChC,QAAA,aAAa,GAAG,KAAK,CAAC;AACnC,iCAAiC;AACpB,QAAA,YAAY,GAAG,CAAC,CAAC;AAC9B,6CAA6C;AAChC,QAAA,YAAY,GAAG,OAAO,CAAC;AACpC,2EAA2E;AAC9D,QAAA,YAAY,GAAG,IAAI,CAAC;AAEjC;;;;;;GAMG;AACH,SAAgB,4BAA4B,CAAC,OAAe;IAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,qBAAa,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAY,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAY,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,sBAAsB,CAAC,OAAe;IACpD,MAAM,MAAM,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,GAAG,oBAAY,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,oBAAY,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAE3D;;;;;;;;;;;;GAYG;AACH,SAAgB,mBAAmB,CAAC,MAAc,EAAE,OAAe,EAAE,GAAW;IAC9E,IAAI,OAAO,GAAG,GAAG,EAAE,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;IACpC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpD,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;IAC3C,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -188,6 +188,15 @@ export interface AutodevSettings {
|
|
|
188
188
|
* indefinitely. Default: 3. Set to 0 to disable (never force-done).
|
|
189
189
|
*/
|
|
190
190
|
maxTaskAttempts: number;
|
|
191
|
+
/**
|
|
192
|
+
* How many times a PROVIDER hard-failure (token blip, timeout, watchdog
|
|
193
|
+
* no-output, crash, session-error, "provider stopped") on the SAME task is
|
|
194
|
+
* retried with exponential backoff before the task is finally reported
|
|
195
|
+
* failed/blocked. This is distinct from maxTaskAttempts (which counts turns
|
|
196
|
+
* that RAN but did not mark the task done). Default: 10. `reauth_required`
|
|
197
|
+
* is never retried here — it has its own pause/resume path.
|
|
198
|
+
*/
|
|
199
|
+
maxProviderRetries: number;
|
|
191
200
|
/**
|
|
192
201
|
* Move completed [x] tasks from TODO.md into DONE.md every N
|
|
193
202
|
* completed tasks (0 = disabled). Keeps the active TODO file short.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settingsLoader.js","sourceRoot":"","sources":["../../src/core/settingsLoader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"settingsLoader.js","sourceRoot":"","sources":["../../src/core/settingsLoader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markers that mean grok hit an AUTH gate / failure rather than doing work:
|
|
3
|
+
* - the interactive OAuth/login gate (waiting for approval / device code / …)
|
|
4
|
+
* - grok's manual-login fallback outcome `Failed(ManualLogin)`
|
|
5
|
+
* - a failed silent token refresh
|
|
6
|
+
* - an explicit "please log in" / "manual login required" prompt
|
|
7
|
+
* Calibrated to grok's own strings; the loose "not logged in" / "session
|
|
8
|
+
* expired" prose is deliberately EXCLUDED so ordinary assistant output rendered
|
|
9
|
+
* in the pane can't trip a false reauth. The deterministic backstop for the
|
|
10
|
+
* proven root cause (auth.json missing) is the auth-file presence check the
|
|
11
|
+
* caller passes in, not a prose match.
|
|
12
|
+
*/
|
|
13
|
+
export declare const GROK_AUTH_MARKERS: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* grok's NATIVE turn-failure banner. This is grok-native text (not something
|
|
16
|
+
* autodev prints): grok emits it when its own turn/process is interrupted —
|
|
17
|
+
* "Turn failed: Grok stopped before this turn finished (the agent process
|
|
18
|
+
* exited or was restarted). Committed tool results were kept." On its own this
|
|
19
|
+
* is a TRANSIENT failure; only when credentials are ALSO absent is it auth.
|
|
20
|
+
*/
|
|
21
|
+
export declare const GROK_TURN_FAIL_MARKERS: RegExp;
|
|
22
|
+
/**
|
|
23
|
+
* The sentinel autodev writes to the grok stdout capture + the human-facing
|
|
24
|
+
* message on an auth failure. It contains the phrase `reauthentication required`
|
|
25
|
+
* which rateLimit.ts's AuthDetector matches, so the LOOP raises an AuthError and
|
|
26
|
+
* takes its dedicated reauth PAUSE (webhook + hooks-events 🔑 state) rather than
|
|
27
|
+
* reporting a generic hard-failure.
|
|
28
|
+
*/
|
|
29
|
+
export declare const GROK_REAUTH_MESSAGE = "reauthentication required \u2014 grok is not logged in (auth.json missing / manual login). Please run: grok login";
|
|
30
|
+
export type GrokTurnClass = 'reauth' | 'turn-failed' | null;
|
|
31
|
+
/**
|
|
32
|
+
* Classify a grok pane snapshot + auth-file state into a turn outcome.
|
|
33
|
+
*
|
|
34
|
+
* - 'reauth' → an AUTH failure (login gate, Failed(ManualLogin), failed
|
|
35
|
+
* refresh, OR a turn-failure banner while auth.json is
|
|
36
|
+
* absent). NEVER retried; surfaced as reauth_required.
|
|
37
|
+
* - 'turn-failed' → a TRANSIENT turn failure (grok's process exited/restarted
|
|
38
|
+
* mid-turn) with credentials present. Retryable with backoff.
|
|
39
|
+
* - null → no failure signal.
|
|
40
|
+
*
|
|
41
|
+
* `authPresent` = does `~/.grok/auth.json` exist and is it non-empty. A missing
|
|
42
|
+
* auth.json is itself the proven root cause (grok's silent refresh →
|
|
43
|
+
* Failed(ManualLogin) → the turn dies), so ANY turn-failure banner seen while
|
|
44
|
+
* auth is absent is treated as reauth, not a transient blip. Auth presence only
|
|
45
|
+
* DISAMBIGUATES an actual failure banner — a healthy, still-producing turn (no
|
|
46
|
+
* banner) is never flagged, so a mis-located auth.json can't brick a good turn.
|
|
47
|
+
*/
|
|
48
|
+
export declare function classifyGrokTurn(snapshot: string, authPresent: boolean): GrokTurnClass;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Pure classifiers for grok turn-end signals.
|
|
4
|
+
//
|
|
5
|
+
// A grok turn can end three ways we care about:
|
|
6
|
+
// - AUTH failure → grok is not logged in: `~/.grok/auth.json` went missing,
|
|
7
|
+
// its silent token refresh failed, or grok fell back to a
|
|
8
|
+
// manual-login gate (`Failed(ManualLogin)`). This can NEVER
|
|
9
|
+
// be retried away — the user must re-login — so it must be
|
|
10
|
+
// surfaced as `reauth_required` (the loop pauses + the office
|
|
11
|
+
// shows the 🔑 needs-auth state), NOT hammered with retries.
|
|
12
|
+
// - TRANSIENT turn failure → grok printed its native banner "Turn failed: Grok
|
|
13
|
+
// stopped before this turn finished (the agent process exited
|
|
14
|
+
// or was restarted)" while credentials are still present. The
|
|
15
|
+
// process blipped; the turn is retryable with backoff.
|
|
16
|
+
// - neither → no failure signal in this snapshot.
|
|
17
|
+
//
|
|
18
|
+
// These functions are intentionally PURE (no I/O) so tui.ts and the unit tests
|
|
19
|
+
// share the exact same detection. tui.ts supplies the live pane snapshot and the
|
|
20
|
+
// `~/.grok/auth.json` presence check; this module decides the outcome.
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.GROK_REAUTH_MESSAGE = exports.GROK_TURN_FAIL_MARKERS = exports.GROK_AUTH_MARKERS = void 0;
|
|
24
|
+
exports.classifyGrokTurn = classifyGrokTurn;
|
|
25
|
+
/**
|
|
26
|
+
* Markers that mean grok hit an AUTH gate / failure rather than doing work:
|
|
27
|
+
* - the interactive OAuth/login gate (waiting for approval / device code / …)
|
|
28
|
+
* - grok's manual-login fallback outcome `Failed(ManualLogin)`
|
|
29
|
+
* - a failed silent token refresh
|
|
30
|
+
* - an explicit "please log in" / "manual login required" prompt
|
|
31
|
+
* Calibrated to grok's own strings; the loose "not logged in" / "session
|
|
32
|
+
* expired" prose is deliberately EXCLUDED so ordinary assistant output rendered
|
|
33
|
+
* in the pane can't trip a false reauth. The deterministic backstop for the
|
|
34
|
+
* proven root cause (auth.json missing) is the auth-file presence check the
|
|
35
|
+
* caller passes in, not a prose match.
|
|
36
|
+
*/
|
|
37
|
+
exports.GROK_AUTH_MARKERS = /waiting for approval|approve in your browser|sign(?:ing)? in to grok|finish signing in|device code|please (?:log ?in|sign ?in)|manual[- ]?login(?: required)?|Failed\(\s*ManualLogin\s*\)|silent refresh (?:failed|error)/i;
|
|
38
|
+
/**
|
|
39
|
+
* grok's NATIVE turn-failure banner. This is grok-native text (not something
|
|
40
|
+
* autodev prints): grok emits it when its own turn/process is interrupted —
|
|
41
|
+
* "Turn failed: Grok stopped before this turn finished (the agent process
|
|
42
|
+
* exited or was restarted). Committed tool results were kept." On its own this
|
|
43
|
+
* is a TRANSIENT failure; only when credentials are ALSO absent is it auth.
|
|
44
|
+
*/
|
|
45
|
+
exports.GROK_TURN_FAIL_MARKERS = /turn failed:|stopped before this turn finished|the agent process (?:exited|was restarted)/i;
|
|
46
|
+
/**
|
|
47
|
+
* The sentinel autodev writes to the grok stdout capture + the human-facing
|
|
48
|
+
* message on an auth failure. It contains the phrase `reauthentication required`
|
|
49
|
+
* which rateLimit.ts's AuthDetector matches, so the LOOP raises an AuthError and
|
|
50
|
+
* takes its dedicated reauth PAUSE (webhook + hooks-events 🔑 state) rather than
|
|
51
|
+
* reporting a generic hard-failure.
|
|
52
|
+
*/
|
|
53
|
+
exports.GROK_REAUTH_MESSAGE = 'reauthentication required — grok is not logged in (auth.json missing / manual login). Please run: grok login';
|
|
54
|
+
/**
|
|
55
|
+
* Classify a grok pane snapshot + auth-file state into a turn outcome.
|
|
56
|
+
*
|
|
57
|
+
* - 'reauth' → an AUTH failure (login gate, Failed(ManualLogin), failed
|
|
58
|
+
* refresh, OR a turn-failure banner while auth.json is
|
|
59
|
+
* absent). NEVER retried; surfaced as reauth_required.
|
|
60
|
+
* - 'turn-failed' → a TRANSIENT turn failure (grok's process exited/restarted
|
|
61
|
+
* mid-turn) with credentials present. Retryable with backoff.
|
|
62
|
+
* - null → no failure signal.
|
|
63
|
+
*
|
|
64
|
+
* `authPresent` = does `~/.grok/auth.json` exist and is it non-empty. A missing
|
|
65
|
+
* auth.json is itself the proven root cause (grok's silent refresh →
|
|
66
|
+
* Failed(ManualLogin) → the turn dies), so ANY turn-failure banner seen while
|
|
67
|
+
* auth is absent is treated as reauth, not a transient blip. Auth presence only
|
|
68
|
+
* DISAMBIGUATES an actual failure banner — a healthy, still-producing turn (no
|
|
69
|
+
* banner) is never flagged, so a mis-located auth.json can't brick a good turn.
|
|
70
|
+
*/
|
|
71
|
+
function classifyGrokTurn(snapshot, authPresent) {
|
|
72
|
+
const s = snapshot || '';
|
|
73
|
+
if (exports.GROK_AUTH_MARKERS.test(s)) {
|
|
74
|
+
return 'reauth';
|
|
75
|
+
}
|
|
76
|
+
if (exports.GROK_TURN_FAIL_MARKERS.test(s)) {
|
|
77
|
+
return authPresent ? 'turn-failed' : 'reauth';
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=authClassify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authClassify.js","sourceRoot":"","sources":["../../../src/providers/grok/authClassify.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,8CAA8C;AAC9C,EAAE;AACF,gDAAgD;AAChD,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,kFAAkF;AAClF,iFAAiF;AACjF,iFAAiF;AACjF,kFAAkF;AAClF,kFAAkF;AAClF,2EAA2E;AAC3E,0DAA0D;AAC1D,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,uEAAuE;AACvE,8EAA8E;;;AAwD9E,4CAKC;AA3DD;;;;;;;;;;;GAWG;AACU,QAAA,iBAAiB,GAC5B,4NAA4N,CAAC;AAE/N;;;;;;GAMG;AACU,QAAA,sBAAsB,GACjC,4FAA4F,CAAC;AAE/F;;;;;;GAMG;AACU,QAAA,mBAAmB,GAC9B,8GAA8G,CAAC;AAIjH;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,gBAAgB,CAAC,QAAgB,EAAE,WAAoB;IACrE,MAAM,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC;IACzB,IAAI,yBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,OAAO,QAAQ,CAAC;IAAC,CAAC;IACnD,IAAI,8BAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,OAAO,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IAAC,CAAC;IACtF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -93,6 +93,7 @@ const hookEventNormalizer_1 = require("../../hookEventNormalizer");
|
|
|
93
93
|
const rateLimit_1 = require("../../rateLimit");
|
|
94
94
|
const sessionState_1 = require("../../sessionState");
|
|
95
95
|
const mcpStartupTimeout_1 = require("../../core/mcpStartupTimeout");
|
|
96
|
+
const authClassify_1 = require("./authClassify");
|
|
96
97
|
// ---------------------------------------------------------------------------
|
|
97
98
|
// Constants
|
|
98
99
|
// ---------------------------------------------------------------------------
|
|
@@ -271,10 +272,34 @@ function stripAnsi(s) {
|
|
|
271
272
|
// Turn-end / auth detectors (calibrate against a live authed grok — see risks).
|
|
272
273
|
// ---------------------------------------------------------------------------
|
|
273
274
|
/**
|
|
274
|
-
* Markers that mean grok hit the OAuth/expired-token gate
|
|
275
|
-
*
|
|
275
|
+
* Markers that mean grok hit the OAuth/expired-token gate or a manual-login /
|
|
276
|
+
* failed-refresh auth failure instead of doing work. The loop must treat this
|
|
277
|
+
* as reauth, NOT a hung turn. Sourced from ./authClassify (shared with the unit
|
|
278
|
+
* tests) — broadened beyond the old login-gate-only set to also catch grok's
|
|
279
|
+
* `Failed(ManualLogin)` / failed silent-refresh signals that previously slipped
|
|
280
|
+
* through as a plain turn-failure (or a false idle).
|
|
276
281
|
*/
|
|
277
|
-
const REAUTH_MARKERS =
|
|
282
|
+
const REAUTH_MARKERS = authClassify_1.GROK_AUTH_MARKERS;
|
|
283
|
+
/**
|
|
284
|
+
* True when grok's credential file (`~/.grok/auth.json`) exists and is
|
|
285
|
+
* non-empty. The PROVEN root cause of the failing Windows agent is this file
|
|
286
|
+
* intermittently going MISSING → grok's silent token refresh fails
|
|
287
|
+
* (`Failed(ManualLogin)`) → the turn dies. A missing/empty auth.json is a
|
|
288
|
+
* deterministic auth-failure signal we can check directly, independent of what
|
|
289
|
+
* the pane happens to render. `GROK_AUTH_JSON` overrides the path for non-default
|
|
290
|
+
* installs. Absence is only USED to disambiguate an actual turn-failure/death —
|
|
291
|
+
* never to flag a healthy, still-producing turn.
|
|
292
|
+
*/
|
|
293
|
+
function grokAuthPresent() {
|
|
294
|
+
try {
|
|
295
|
+
const p = process.env['GROK_AUTH_JSON'] || path.join(os.homedir(), '.grok', 'auth.json');
|
|
296
|
+
const st = fs.statSync(p);
|
|
297
|
+
return st.isFile() && st.size > 0;
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
278
303
|
/**
|
|
279
304
|
* "grok finished this turn" affordance — CALIBRATED against grok 4.5 build 0.2.93:
|
|
280
305
|
* a completed turn prints "Worked for 4.1s." (a summary line) and the footer drops
|
|
@@ -964,6 +989,27 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
964
989
|
}
|
|
965
990
|
catch { /* ignore */ }
|
|
966
991
|
};
|
|
992
|
+
// Surface a grok AUTH failure (needs re-login) LOUDLY and consistently on both
|
|
993
|
+
// the loop and operate paths:
|
|
994
|
+
// - a first-class `reauth_required` hook → the operate bridge forwards it to
|
|
995
|
+
// the office (🔑 needs-auth state) and cliExit classifies it directly;
|
|
996
|
+
// - the GROK_REAUTH_MESSAGE sentinel in the stdout capture → the loop's
|
|
997
|
+
// AuthDetector raises an AuthError and takes its dedicated reauth PAUSE
|
|
998
|
+
// (reauth_required webhook + hooks-events line), instead of a generic fail;
|
|
999
|
+
// - finish(1, 'reauth_required') → cliExit maps it to a NON-retryable
|
|
1000
|
+
// hard-failure (shouldRetryHardFail excludes it), so a missing token is
|
|
1001
|
+
// never hammered with blind retries — the user is asked to re-login.
|
|
1002
|
+
const finishReauth = (where) => {
|
|
1003
|
+
log(`Grok TUI: reauthentication required — ${where}`);
|
|
1004
|
+
_emitGrokHook(root, 'reauth_required', {
|
|
1005
|
+
message: authClassify_1.GROK_REAUTH_MESSAGE, title: 'Authentication required', tool_name: '',
|
|
1006
|
+
});
|
|
1007
|
+
try {
|
|
1008
|
+
fs.appendFileSync(stdoutFile, `\n[Grok TUI: ${authClassify_1.GROK_REAUTH_MESSAGE}]\n`, 'utf8');
|
|
1009
|
+
}
|
|
1010
|
+
catch { /* ignore */ }
|
|
1011
|
+
finish(1, 'reauth_required');
|
|
1012
|
+
};
|
|
967
1013
|
void (async () => {
|
|
968
1014
|
let sess;
|
|
969
1015
|
let justLaunched = false;
|
|
@@ -1056,12 +1102,7 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1056
1102
|
}
|
|
1057
1103
|
}
|
|
1058
1104
|
if (reauth) {
|
|
1059
|
-
|
|
1060
|
-
try {
|
|
1061
|
-
fs.appendFileSync(stdoutFile, `\n[Grok TUI: reauthentication required — please login]\n`, 'utf8');
|
|
1062
|
-
}
|
|
1063
|
-
catch { /* ignore */ }
|
|
1064
|
-
finish(1, 'reauth_required');
|
|
1105
|
+
finishReauth('auth gate at startup');
|
|
1065
1106
|
return;
|
|
1066
1107
|
}
|
|
1067
1108
|
if (!died) {
|
|
@@ -1091,6 +1132,14 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1091
1132
|
sidForLaunch = undefined; // force a fresh mint on the retry
|
|
1092
1133
|
}
|
|
1093
1134
|
if (!startupOk) {
|
|
1135
|
+
// A session that keeps dying during startup while grok's credentials are
|
|
1136
|
+
// ABSENT is an auth failure (silent refresh → Failed(ManualLogin) → exit),
|
|
1137
|
+
// not a transient startup race — surface it as reauth so the user re-logs in
|
|
1138
|
+
// instead of the loop retrying a login it can never satisfy.
|
|
1139
|
+
if (!grokAuthPresent()) {
|
|
1140
|
+
finishReauth('auth.json missing — session exited during startup');
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1094
1143
|
try {
|
|
1095
1144
|
fs.appendFileSync(stdoutFile, `\n[Grok TUI: session kept exiting during startup — a fresh session will be tried next turn]\n`, 'utf8');
|
|
1096
1145
|
}
|
|
@@ -1144,11 +1193,19 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1144
1193
|
await sleep(POLL_MS);
|
|
1145
1194
|
// Session died mid-turn (grok crashed / was killed).
|
|
1146
1195
|
if (!hasSession(sess.name)) {
|
|
1196
|
+
_tmuxSessions.delete(root);
|
|
1197
|
+
// A mid-turn death with grok's credentials ABSENT is the proven
|
|
1198
|
+
// auth-failure signature (auth.json vanished → silent refresh failed →
|
|
1199
|
+
// grok exited). Surface it as reauth, not a generic session-exit, so the
|
|
1200
|
+
// user is asked to re-login instead of the turn being retried blindly.
|
|
1201
|
+
if (!grokAuthPresent()) {
|
|
1202
|
+
finishReauth('auth.json missing — grok exited mid-turn');
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1147
1205
|
try {
|
|
1148
1206
|
fs.appendFileSync(stdoutFile, `\n[Grok TUI: session exited]\n`, 'utf8');
|
|
1149
1207
|
}
|
|
1150
1208
|
catch { /* ignore */ }
|
|
1151
|
-
_tmuxSessions.delete(root);
|
|
1152
1209
|
finish(1, 'session-exit');
|
|
1153
1210
|
return;
|
|
1154
1211
|
}
|
|
@@ -1183,14 +1240,30 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1183
1240
|
// 1c) Emit rich per-tool hook events (Pre/PostToolUse with payload) from the
|
|
1184
1241
|
// SAME transcript, on an independent offset.
|
|
1185
1242
|
toolOffset = scanGrokToolEvents(root, chatPath, toolOffset, pendingTools);
|
|
1186
|
-
// 2) Snapshot for detection (also catches a mid-turn
|
|
1243
|
+
// 2) Snapshot for detection (also catches a mid-turn auth failure and
|
|
1244
|
+
// grok's native "Turn failed: Grok stopped before this turn finished"
|
|
1245
|
+
// banner). classifyGrokTurn disambiguates the two using the pane text +
|
|
1246
|
+
// grok's credential-file presence:
|
|
1247
|
+
// - 'reauth' → auth gate / Failed(ManualLogin) / a turn-failure
|
|
1248
|
+
// while auth.json is absent → surface reauth (NEVER retried).
|
|
1249
|
+
// - 'turn-failed' → grok's process blipped mid-turn with credentials
|
|
1250
|
+
// present → a TRANSIENT hard-failure that IS retried with backoff by
|
|
1251
|
+
// the loop (shouldRetryHardFail treats it as retryable). Previously
|
|
1252
|
+
// this banner had no detector, so the pane went quiet and the turn
|
|
1253
|
+
// was misread as a clean idle (a FALSE success that lost the task).
|
|
1187
1254
|
const snap = capturePane(sess.name);
|
|
1188
|
-
|
|
1255
|
+
const turnClass = (0, authClassify_1.classifyGrokTurn)(snap, grokAuthPresent());
|
|
1256
|
+
if (turnClass === 'reauth') {
|
|
1257
|
+
finishReauth('auth failure detected mid-turn');
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
if (turnClass === 'turn-failed') {
|
|
1261
|
+
log('Grok TUI: grok reported a turn failure (transient) — surfacing for retry');
|
|
1189
1262
|
try {
|
|
1190
|
-
fs.appendFileSync(stdoutFile, `\n[Grok TUI:
|
|
1263
|
+
fs.appendFileSync(stdoutFile, `\n[Grok TUI: turn failed — grok stopped before this turn finished (transient); the loop will retry]\n`, 'utf8');
|
|
1191
1264
|
}
|
|
1192
1265
|
catch { /* ignore */ }
|
|
1193
|
-
finish(1, '
|
|
1266
|
+
finish(1, 'turn-failed');
|
|
1194
1267
|
return;
|
|
1195
1268
|
}
|
|
1196
1269
|
// Backstop: the project-directory picker appears AFTER the first prompt is
|