autodev-cli 1.4.173 → 1.4.175
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/commands/mcpOperate.js +151 -0
- package/out/commands/mcpOperate.js.map +1 -1
- package/out/core/grokEvents.d.ts +61 -0
- package/out/core/grokEvents.js +213 -0
- package/out/core/grokEvents.js.map +1 -0
- package/out/providers/grok/sessions.d.ts +11 -0
- package/out/providers/grok/sessions.js +64 -0
- package/out/providers/grok/sessions.js.map +1 -1
- package/out/providers/grok/tui.js +83 -2
- package/out/providers/grok/tui.js.map +1 -1
- package/out/taskLoop.js +14 -0
- package/out/taskLoop.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// grokEvents — pure parser/classifier for grok's OWN session event log.
|
|
4
|
+
//
|
|
5
|
+
// A grok session (loop OR operate) writes structured telemetry to
|
|
6
|
+
// ~/.grok/sessions/<url-encoded-cwd>/<session-id>/events.jsonl
|
|
7
|
+
// one JSON object per line. Observed record types (schema_version 1.0):
|
|
8
|
+
// • turn_started {turn_number, model_id, …} — a turn began
|
|
9
|
+
// • loop_started {loop_index} — an agent loop iteration began
|
|
10
|
+
// • phase_changed {phase} — phase transitions; observed
|
|
11
|
+
// phases: waiting_for_model, streaming_reasoning, streaming_text,
|
|
12
|
+
// tool_execution, permission_prompt (all NON-idle = actively working)
|
|
13
|
+
// • first_token {} — model started emitting
|
|
14
|
+
// • tool_started {tool_name, tool_call_id?} — a native tool call began
|
|
15
|
+
// • tool_completed {tool_name, outcome, duration_ms, tool_call_id?}
|
|
16
|
+
// outcome: "success" | "error"
|
|
17
|
+
// • permission_requested / permission_resolved {tool_name, decision?}
|
|
18
|
+
// • turn_ended {outcome} — the turn finished;
|
|
19
|
+
// outcome "completed" = a CLEAN turn end (grok 4.5 AND 4.7).
|
|
20
|
+
//
|
|
21
|
+
// These functions are intentionally PURE (no I/O): the operate bridge and the
|
|
22
|
+
// grok loop turn-detector both feed lines/objects in and share the exact same
|
|
23
|
+
// classification, so the mapping is unit-testable without a socket / tmux pane.
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.GROK_IDLE_PHASES = void 0;
|
|
27
|
+
exports.parseGrokEventLine = parseGrokEventLine;
|
|
28
|
+
exports.classifyGrokActivity = classifyGrokActivity;
|
|
29
|
+
exports.grokEventToHook = grokEventToHook;
|
|
30
|
+
exports.isOfficeMcpToolName = isOfficeMcpToolName;
|
|
31
|
+
exports.isCleanTurnOutcome = isCleanTurnOutcome;
|
|
32
|
+
exports.scanGrokTurnEnd = scanGrokTurnEnd;
|
|
33
|
+
exports.grokAssistantText = grokAssistantText;
|
|
34
|
+
/** Parse one events.jsonl line into a GrokEvent, or null for blank/non-JSON. */
|
|
35
|
+
function parseGrokEventLine(line) {
|
|
36
|
+
const s = (line || '').trim();
|
|
37
|
+
if (!s) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const o = JSON.parse(s);
|
|
42
|
+
if (o && typeof o === 'object' && typeof o.type === 'string') {
|
|
43
|
+
return o;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { /* not JSON */ }
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
// grok phases that mean the turn is NOT actively working (idle / waiting for the
|
|
50
|
+
// user / done). None are observed in real dumps today — every real phase
|
|
51
|
+
// (streaming_*, tool_execution, waiting_for_model, permission_prompt) is active —
|
|
52
|
+
// but this list makes a future "idle"-style phase decay the badge instead of
|
|
53
|
+
// pinning it 'working'. `waiting_for_model` is explicitly ACTIVE (grok is mid-turn
|
|
54
|
+
// awaiting the model), so it is NOT here.
|
|
55
|
+
exports.GROK_IDLE_PHASES = new Set([
|
|
56
|
+
'idle', 'done', 'complete', 'completed', 'finished', 'ready', 'waiting_for_input', 'awaiting_input',
|
|
57
|
+
]);
|
|
58
|
+
/**
|
|
59
|
+
* Classify a grok event into a status signal for the operate status controller:
|
|
60
|
+
* 'working' — the session is actively doing work (keep/refresh the 'working'
|
|
61
|
+
* badge + re-arm the inactivity→idle timer)
|
|
62
|
+
* 'end' — the turn/loop finished (flip to idle NOW, don't wait 120s)
|
|
63
|
+
* null — no status meaning (ignore for status)
|
|
64
|
+
* The existing 120s inactivity timer still decays a stuck 'working' to idle.
|
|
65
|
+
*/
|
|
66
|
+
function classifyGrokActivity(ev) {
|
|
67
|
+
if (!ev) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
switch (ev.type) {
|
|
71
|
+
case 'turn_started':
|
|
72
|
+
case 'loop_started':
|
|
73
|
+
case 'first_token':
|
|
74
|
+
case 'tool_started':
|
|
75
|
+
case 'tool_completed': // a tool finished — still mid-turn activity
|
|
76
|
+
case 'permission_requested':
|
|
77
|
+
case 'permission_resolved':
|
|
78
|
+
return 'working';
|
|
79
|
+
case 'phase_changed':
|
|
80
|
+
return ev.phase && exports.GROK_IDLE_PHASES.has(ev.phase) ? 'end' : 'working';
|
|
81
|
+
case 'turn_ended':
|
|
82
|
+
case 'loop_ended':
|
|
83
|
+
return 'end';
|
|
84
|
+
default:
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Map a grok event to a tool hook the office renders, or null when the event is
|
|
90
|
+
* not a tool boundary (status-only). `tool_started` → PreToolUse; `tool_completed`
|
|
91
|
+
* → PostToolUse, or PostToolUseFailure when outcome === "error". Carries tool_name
|
|
92
|
+
* (+ tool_use_id when grok supplied one, so Pre/Post pair into one step card).
|
|
93
|
+
*/
|
|
94
|
+
function grokEventToHook(ev) {
|
|
95
|
+
if (!ev) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const name = (ev.tool_name || '').trim();
|
|
99
|
+
if (!name) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
if (ev.type === 'tool_started') {
|
|
103
|
+
return { hook_event_name: 'PreToolUse', tool_name: name, tool_use_id: ev.tool_call_id };
|
|
104
|
+
}
|
|
105
|
+
if (ev.type === 'tool_completed') {
|
|
106
|
+
const failed = String(ev.outcome || '').toLowerCase() === 'error';
|
|
107
|
+
return {
|
|
108
|
+
hook_event_name: failed ? 'PostToolUseFailure' : 'PostToolUse',
|
|
109
|
+
tool_name: name,
|
|
110
|
+
tool_use_id: ev.tool_call_id,
|
|
111
|
+
outcome: ev.outcome,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
// Office-operator MCP tool verbs (+ the bridge-synthesized tools). The office
|
|
117
|
+
// logs its OWN MCP tools server-side (OfficeMcpController → provider
|
|
118
|
+
// 'mcp-operator'), so re-forwarding a grok tool event for them would double-render
|
|
119
|
+
// the same call in the Events feed. grok's NATIVE tools (read_file/edit/bash/…) are
|
|
120
|
+
// the high-value signal and are NOT in this set. Any `mcp__`-prefixed name is also
|
|
121
|
+
// treated as an office/MCP tool (the standard MCP tool prefix).
|
|
122
|
+
const OFFICE_TOOL_NAMES = new Set([
|
|
123
|
+
'whoami', 'get_tasks', 'start_task', 'complete_task', 'update_task', 'create_task',
|
|
124
|
+
'check_messages', 'send_message', 'set_status', 'get_events', 'get_office', 'get_agents',
|
|
125
|
+
'create_choice_request', 'get_choice_answer', 'wait_for_events', 'ask_user',
|
|
126
|
+
'graph_add_node', 'graph_add_edge', 'graph_query', 'graph_map', 'graph_search',
|
|
127
|
+
'graph_neighbors', 'graph_toc', 'graph_rollup', 'graph_pin', 'graph_supersede', 'graph_stats',
|
|
128
|
+
]);
|
|
129
|
+
/** True when a tool name is an office/MCP tool (logged server-side) rather than a
|
|
130
|
+
* grok native tool — such events must be skipped to avoid double-forwarding. */
|
|
131
|
+
function isOfficeMcpToolName(name) {
|
|
132
|
+
const n = (name || '').trim();
|
|
133
|
+
if (!n) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (n.startsWith('mcp__')) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return OFFICE_TOOL_NAMES.has(n);
|
|
140
|
+
}
|
|
141
|
+
// grok `turn_ended` outcomes that mean the turn finished CLEANLY (no failure).
|
|
142
|
+
const CLEAN_TURN_OUTCOMES = new Set(['completed', 'complete', 'success', 'succeeded', 'done', 'ok']);
|
|
143
|
+
// Outcomes that mean the turn ended in a genuine failure/abort.
|
|
144
|
+
const ERROR_TURN_OUTCOMES = new Set(['error', 'failed', 'failure', 'cancelled', 'canceled', 'aborted', 'interrupted', 'timeout', 'timed_out']);
|
|
145
|
+
/** Is a grok `turn_ended` outcome a clean completion? Unknown/empty → false. */
|
|
146
|
+
function isCleanTurnOutcome(outcome) {
|
|
147
|
+
return CLEAN_TURN_OUTCOMES.has(String(outcome || '').toLowerCase());
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Scan grok event lines (or objects) for the LAST `turn_ended` and classify it:
|
|
151
|
+
* 'clean' — outcome is a completed/success value (the turn finished normally)
|
|
152
|
+
* 'error' — outcome is a failure/abort value
|
|
153
|
+
* null — no turn_ended present (turn still running / not seen this batch)
|
|
154
|
+
* Used by the grok loop turn-detector as CORROBORATION: a clean turn_ended is a
|
|
155
|
+
* positive done-signal, so a finished grok 4.7 turn (which may not print the
|
|
156
|
+
* grok-4.5 "Worked for N.Ns." pane marker) is recognized as a clean finish and
|
|
157
|
+
* NEVER misread as a StopFailure/watchdog hard-fail.
|
|
158
|
+
*/
|
|
159
|
+
function scanGrokTurnEnd(lines) {
|
|
160
|
+
let result = null;
|
|
161
|
+
for (const raw of lines) {
|
|
162
|
+
const ev = typeof raw === 'string' ? parseGrokEventLine(raw) : raw;
|
|
163
|
+
if (!ev || ev.type !== 'turn_ended') {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const oc = String(ev.outcome || '').toLowerCase();
|
|
167
|
+
if (isCleanTurnOutcome(oc)) {
|
|
168
|
+
result = 'clean';
|
|
169
|
+
}
|
|
170
|
+
else if (ERROR_TURN_OUTCOMES.has(oc)) {
|
|
171
|
+
result = 'error';
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
result = 'error';
|
|
175
|
+
} // an unknown non-clean outcome is treated as a failure signal
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Extract assistant prose from ONE grok chat_history.jsonl line, or null when the
|
|
181
|
+
* line is not assistant text (user/system/reasoning/tool_result/tool_calls-only).
|
|
182
|
+
* grok `content` is a plain string or an array of {type:'text',text} blocks.
|
|
183
|
+
*/
|
|
184
|
+
function grokAssistantText(line) {
|
|
185
|
+
const s = (line || '').trim();
|
|
186
|
+
if (!s) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
let o;
|
|
190
|
+
try {
|
|
191
|
+
o = JSON.parse(s);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const kind = o.type || o.role;
|
|
197
|
+
if (kind !== 'assistant') {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const c = o.content;
|
|
201
|
+
let text = '';
|
|
202
|
+
if (typeof c === 'string') {
|
|
203
|
+
text = c;
|
|
204
|
+
}
|
|
205
|
+
else if (Array.isArray(c)) {
|
|
206
|
+
text = c
|
|
207
|
+
.map(b => (b && b['type'] === 'text' ? String(b['text'] ?? '') : ''))
|
|
208
|
+
.filter(Boolean).join('\n');
|
|
209
|
+
}
|
|
210
|
+
text = text.trim();
|
|
211
|
+
return text || null;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=grokEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokEvents.js","sourceRoot":"","sources":["../../src/core/grokEvents.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,17 @@ export declare function listAllGrokSessions(): Array<{
|
|
|
13
13
|
updated: number;
|
|
14
14
|
cwd: string;
|
|
15
15
|
}>;
|
|
16
|
+
/** The per-session dir for `cwd`+`sessionId`: <base>/<encodeURIComponent(cwd)>/<id>. */
|
|
17
|
+
export declare function grokSessionDirFor(cwd: string, sessionId: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the NEWEST grok session directory for a workspace `cwd` — the folder
|
|
20
|
+
* holding that session's events.jsonl / chat_history.jsonl. Picks the most
|
|
21
|
+
* recently active session by the mtime of its events.jsonl (falling back to
|
|
22
|
+
* chat_history.jsonl, then the dir itself), so a resumed/active session is found
|
|
23
|
+
* even before grok's shared sqlite index catches up. Honors GROK_HOME. Returns
|
|
24
|
+
* undefined when grok has never run for this cwd. Read-only; never throws.
|
|
25
|
+
*/
|
|
26
|
+
export declare function newestGrokSessionDir(cwd: string): string | undefined;
|
|
16
27
|
export interface TranscriptMsg {
|
|
17
28
|
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
18
29
|
text: string;
|
|
@@ -46,6 +46,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
47
|
exports.listGrokSessions = listGrokSessions;
|
|
48
48
|
exports.listAllGrokSessions = listAllGrokSessions;
|
|
49
|
+
exports.grokSessionDirFor = grokSessionDirFor;
|
|
50
|
+
exports.newestGrokSessionDir = newestGrokSessionDir;
|
|
49
51
|
exports.readGrokTranscript = readGrokTranscript;
|
|
50
52
|
const fs = __importStar(require("fs"));
|
|
51
53
|
const os = __importStar(require("os"));
|
|
@@ -128,6 +130,68 @@ function listAllGrokSessions() {
|
|
|
128
130
|
catch { /* ignore */ }
|
|
129
131
|
}
|
|
130
132
|
}
|
|
133
|
+
/** grok's sessions base dir (honors GROK_HOME), e.g. ~/.grok/sessions. */
|
|
134
|
+
function grokSessionsBase() {
|
|
135
|
+
const base = process.env['GROK_HOME'] || path.join(os.homedir(), '.grok');
|
|
136
|
+
return path.join(base, 'sessions');
|
|
137
|
+
}
|
|
138
|
+
/** The per-session dir for `cwd`+`sessionId`: <base>/<encodeURIComponent(cwd)>/<id>. */
|
|
139
|
+
function grokSessionDirFor(cwd, sessionId) {
|
|
140
|
+
return path.join(grokSessionsBase(), encodeURIComponent(cwd), sessionId);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Resolve the NEWEST grok session directory for a workspace `cwd` — the folder
|
|
144
|
+
* holding that session's events.jsonl / chat_history.jsonl. Picks the most
|
|
145
|
+
* recently active session by the mtime of its events.jsonl (falling back to
|
|
146
|
+
* chat_history.jsonl, then the dir itself), so a resumed/active session is found
|
|
147
|
+
* even before grok's shared sqlite index catches up. Honors GROK_HOME. Returns
|
|
148
|
+
* undefined when grok has never run for this cwd. Read-only; never throws.
|
|
149
|
+
*/
|
|
150
|
+
function newestGrokSessionDir(cwd) {
|
|
151
|
+
let encDir = '';
|
|
152
|
+
try {
|
|
153
|
+
encDir = path.join(grokSessionsBase(), encodeURIComponent(path.resolve(cwd)));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
encDir = path.join(grokSessionsBase(), encodeURIComponent(cwd));
|
|
157
|
+
}
|
|
158
|
+
let entries;
|
|
159
|
+
try {
|
|
160
|
+
entries = fs.readdirSync(encDir);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
let best;
|
|
166
|
+
let bestMs = -1;
|
|
167
|
+
for (const id of entries) {
|
|
168
|
+
const dir = path.join(encDir, id);
|
|
169
|
+
let stat;
|
|
170
|
+
try {
|
|
171
|
+
if (!fs.statSync(dir).isDirectory()) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const candidates = [path.join(dir, 'events.jsonl'), path.join(dir, 'chat_history.jsonl'), dir];
|
|
179
|
+
let ms = -1;
|
|
180
|
+
for (const c of candidates) {
|
|
181
|
+
try {
|
|
182
|
+
stat = fs.statSync(c);
|
|
183
|
+
ms = stat.mtimeMs;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
catch { /* try next */ }
|
|
187
|
+
}
|
|
188
|
+
if (ms > bestMs) {
|
|
189
|
+
bestMs = ms;
|
|
190
|
+
best = dir;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return best;
|
|
194
|
+
}
|
|
131
195
|
/** Path to grok's clean structured transcript for a session under a given cwd. */
|
|
132
196
|
function grokChatHistoryPath(cwd, sessionId) {
|
|
133
197
|
const base = process.env['GROK_HOME'] || path.join(os.homedir(), '.grok');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/providers/grok/sessions.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,wEAAwE;AACxE,EAAE;AACF,8CAA8C;AAC9C,kEAAkE;AAClE,8DAA8D;AAC9D,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,qDAAqD;AACrD,8EAA8E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmB9E,4CAmBC;AAKD,kDAkBC;AAwCD,gDA4CC;
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/providers/grok/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -94,6 +94,7 @@ const rateLimit_1 = require("../../rateLimit");
|
|
|
94
94
|
const sessionState_1 = require("../../sessionState");
|
|
95
95
|
const mcpStartupTimeout_1 = require("../../core/mcpStartupTimeout");
|
|
96
96
|
const authClassify_1 = require("./authClassify");
|
|
97
|
+
const grokEvents_1 = require("../../core/grokEvents");
|
|
97
98
|
// ---------------------------------------------------------------------------
|
|
98
99
|
// Constants
|
|
99
100
|
// ---------------------------------------------------------------------------
|
|
@@ -1171,6 +1172,63 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1171
1172
|
// are emitted, not the resumed history.
|
|
1172
1173
|
let toolOffset = chatOffset;
|
|
1173
1174
|
const pendingTools = new Map();
|
|
1175
|
+
// FIX 3 — clean-turn CORROBORATION from grok's OWN events.jsonl (same session
|
|
1176
|
+
// dir as chat_history.jsonl). The pane "Worked for N.Ns." DONE_MARKER is
|
|
1177
|
+
// calibrated for grok 4.5; grok 4.7's clean turn-end may not print it, so a
|
|
1178
|
+
// finished turn could hang until the 45s quiescence fallback — or, if a footer
|
|
1179
|
+
// kept matching the running-indicator, run to the watchdog and surface as a
|
|
1180
|
+
// FALSE StopFailure (the "finished but shows ❗" bug). grok writes
|
|
1181
|
+
// {"type":"turn_ended","outcome":"completed"} on every clean turn end (4.5 AND
|
|
1182
|
+
// 4.7). Seed the offset at the current size so we only see THIS turn's records
|
|
1183
|
+
// (never a resumed session's prior turn_ended). A clean turn_ended is treated
|
|
1184
|
+
// as a positive done-signal (like the pane marker); an error outcome is left to
|
|
1185
|
+
// the existing pane/exit detectors. Purely additive — the pane heuristic and
|
|
1186
|
+
// its quiescence fallback stay intact as the fallback path.
|
|
1187
|
+
const eventsPath = path.join(path.dirname(chatPath), 'events.jsonl');
|
|
1188
|
+
let eventsOffset = (() => { try {
|
|
1189
|
+
return fs.statSync(eventsPath).size;
|
|
1190
|
+
}
|
|
1191
|
+
catch {
|
|
1192
|
+
return 0;
|
|
1193
|
+
} })();
|
|
1194
|
+
let sawCleanTurnEnd = false;
|
|
1195
|
+
const drainEventsForTurnEnd = () => {
|
|
1196
|
+
let size = 0;
|
|
1197
|
+
try {
|
|
1198
|
+
size = fs.statSync(eventsPath).size;
|
|
1199
|
+
}
|
|
1200
|
+
catch {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
if (size <= eventsOffset) {
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
let raw = '';
|
|
1207
|
+
try {
|
|
1208
|
+
const len = size - eventsOffset;
|
|
1209
|
+
const buf = Buffer.alloc(len);
|
|
1210
|
+
const fd = fs.openSync(eventsPath, 'r');
|
|
1211
|
+
try {
|
|
1212
|
+
fs.readSync(fd, buf, 0, len, eventsOffset);
|
|
1213
|
+
}
|
|
1214
|
+
finally {
|
|
1215
|
+
fs.closeSync(fd);
|
|
1216
|
+
}
|
|
1217
|
+
raw = buf.toString('utf8');
|
|
1218
|
+
}
|
|
1219
|
+
catch {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
const lastNl = raw.lastIndexOf('\n');
|
|
1223
|
+
if (lastNl < 0) {
|
|
1224
|
+
return;
|
|
1225
|
+
} // no complete line yet
|
|
1226
|
+
const complete = raw.slice(0, lastNl);
|
|
1227
|
+
eventsOffset += Buffer.byteLength(complete, 'utf8') + 1;
|
|
1228
|
+
if ((0, grokEvents_1.scanGrokTurnEnd)(complete.split('\n')) === 'clean') {
|
|
1229
|
+
sawCleanTurnEnd = true;
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1174
1232
|
// Submit the prompt.
|
|
1175
1233
|
log(`Grok TUI: sending turn (${(() => { try {
|
|
1176
1234
|
return fs.statSync(promptFilePath).size;
|
|
@@ -1252,12 +1310,18 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1252
1310
|
// this banner had no detector, so the pane went quiet and the turn
|
|
1253
1311
|
// was misread as a clean idle (a FALSE success that lost the task).
|
|
1254
1312
|
const snap = capturePane(sess.name);
|
|
1313
|
+
// Drain grok's own events.jsonl FIRST so a confirmed clean turn_ended can
|
|
1314
|
+
// veto a pane-scraped false 'turn-failed' below (FIX 3). A clean turn_ended
|
|
1315
|
+
// means grok finished the turn cleanly — grok never writes it after a real
|
|
1316
|
+
// mid-turn process blip — so a lingering pane banner must not force a
|
|
1317
|
+
// StopFailure. reauth is NEVER vetoed (a missing login is real regardless).
|
|
1318
|
+
drainEventsForTurnEnd();
|
|
1255
1319
|
const turnClass = (0, authClassify_1.classifyGrokTurn)(snap, grokAuthPresent());
|
|
1256
1320
|
if (turnClass === 'reauth') {
|
|
1257
1321
|
finishReauth('auth failure detected mid-turn');
|
|
1258
1322
|
return;
|
|
1259
1323
|
}
|
|
1260
|
-
if (turnClass === 'turn-failed') {
|
|
1324
|
+
if (turnClass === 'turn-failed' && !sawCleanTurnEnd) {
|
|
1261
1325
|
log('Grok TUI: grok reported a turn failure (transient) — surfacing for retry');
|
|
1262
1326
|
try {
|
|
1263
1327
|
fs.appendFileSync(stdoutFile, `\n[Grok TUI: turn failed — grok stopped before this turn finished (transient); the loop will retry]\n`, 'utf8');
|
|
@@ -1283,6 +1347,15 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1283
1347
|
if (DONE_MARKER.test(snap)) {
|
|
1284
1348
|
sawDoneMarker = true;
|
|
1285
1349
|
}
|
|
1350
|
+
// events.jsonl was drained above (before the turn-failed check). A clean
|
|
1351
|
+
// {"turn_ended","completed"} this turn is a build-agnostic positive
|
|
1352
|
+
// done-signal (recognizes grok 4.7's clean finish, which may omit the
|
|
1353
|
+
// grok-4.5 pane marker) → treat it exactly like the pane marker so the turn
|
|
1354
|
+
// ends cleanly + fast as finish(0)=Stop instead of hanging to the quiescence
|
|
1355
|
+
// fallback or the watchdog StopFailure.
|
|
1356
|
+
if (sawCleanTurnEnd) {
|
|
1357
|
+
sawDoneMarker = true;
|
|
1358
|
+
}
|
|
1286
1359
|
if (snap === lastSnap) {
|
|
1287
1360
|
stable++;
|
|
1288
1361
|
}
|
|
@@ -1293,9 +1366,17 @@ function runGrokTmuxTurn(root, promptFilePath, resolvedSessionId, stdoutFile, ex
|
|
|
1293
1366
|
const running = RUNNING_INDICATOR.test(snap);
|
|
1294
1367
|
const quietMs = Date.now() - lastGrowthMs;
|
|
1295
1368
|
const readyToJudge = sawOutput || (Date.now() - turnStart >= NOOUTPUT_MS);
|
|
1369
|
+
// A clean events.jsonl turn_ended is authoritative that grok finished — allow
|
|
1370
|
+
// it to end the turn even if a stale footer still matches the running-indicator
|
|
1371
|
+
// (grok 4.7 can leave a "Ctrl+c"-style footer painted after a completed turn),
|
|
1372
|
+
// gated on the same DEBOUNCE_MS quiet window so trailing output still flushes.
|
|
1296
1373
|
const doneFast = sawDoneMarker && quietMs >= DEBOUNCE_MS;
|
|
1297
1374
|
const doneSlow = readyToJudge && quietMs >= QUIET_FALLBACK_MS && stable >= STABLE_POLLS;
|
|
1298
|
-
|
|
1375
|
+
// grok's own log confirmed a clean turn_ended → end even if a stale footer
|
|
1376
|
+
// still trips the running-indicator (still gated on the quiet window so
|
|
1377
|
+
// trailing transcript records flush first).
|
|
1378
|
+
const doneClean = sawCleanTurnEnd && quietMs >= DEBOUNCE_MS;
|
|
1379
|
+
if (doneClean || (!running && (doneFast || doneSlow))) {
|
|
1299
1380
|
// Final drain of the transcript to catch records written between the last
|
|
1300
1381
|
// poll and turn-end.
|
|
1301
1382
|
const tail = drainChatHistory(chatPath, chatOffset);
|