@enderfga/claw-orchestrator 5.0.0 → 5.1.0

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.
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Grok Build (xAI) session wrapper.
3
+ *
4
+ * One-shot per send: `grok -p <msg> --output-format json`, which prints a single
5
+ * JSON object and exits. That object is unusually complete for this engine class
6
+ * — it carries the reply, a terminal `stopReason`, a resumable `sessionId`, real
7
+ * token usage, the model that actually answered, and the engine's own
8
+ * `total_cost_usd`.
9
+ *
10
+ * Two consequences shape this file:
11
+ *
12
+ * 1. **Cost is passed through, not priced.** Every other engine here multiplies
13
+ * token counts by a rate in `models.ts`, which is the metadata that rots
14
+ * silently between releases. Grok reports what it charged, so this wrapper
15
+ * writes that number into `_stats.costUsd` directly and the registry is never
16
+ * consulted for it. The run ledger and the `maxBudgetUsd` gate both read that
17
+ * field, so both get the engine's own figure.
18
+ * 2. **The binary is `grok`, never `agent`.** xAI's installer also symlinks the
19
+ * generic `agent` name, which Cursor's CLI already used; whichever installer
20
+ * ran last wins. Both wrappers now name the vendor-specific binary so the
21
+ * engine you asked for is the engine you get.
22
+ *
23
+ * Usage and cost are per-turn, not cumulative over the thread — verified against
24
+ * 1.0.5 by resuming a session and reading the second turn (29,711 in / $0.0597,
25
+ * then 70 in / $0.0152). Accumulating them is therefore correct here, unlike
26
+ * codex, where the same-looking field is a running total.
27
+ */
28
+ import { spawn } from 'node:child_process';
29
+ import { sanitizeSecrets } from './sanitize.js';
30
+ import { BaseOneShotSession } from './base-oneshot-session.js';
31
+ import { SESSION_EVENT } from './constants.js';
32
+ export class PersistentGrokSession extends BaseOneShotSession {
33
+ /** Grok's own session UUID, captured from turn 1 and replayed via `--resume`. */
34
+ grokSessionId;
35
+ constructor(config, grokBin) {
36
+ super(config, grokBin || process.env.GROK_BIN || 'grok', {
37
+ enginePrefix: 'grok',
38
+ defaultModel: 'grok-4.6',
39
+ defaultModelDisplay: 'grok-4.6',
40
+ supportsCachedTokens: true,
41
+ engineDisplayName: 'Grok Build',
42
+ });
43
+ // Same shape cursor and opencode use: the real id is surfaced through
44
+ // `sessionId` behind a `grok-live-` prefix so SessionManager can persist it,
45
+ // and the prefix is stripped again on the way back in. A synthetic wrapper id
46
+ // (`grok-<ts>-<rand>`) must never be handed to `--resume`.
47
+ if (config.resumeSessionId && !/^grok-\d+-/.test(config.resumeSessionId)) {
48
+ this.grokSessionId = config.resumeSessionId.replace(/^grok-live-/, '');
49
+ }
50
+ }
51
+ _buildArgs(message, options) {
52
+ const args = ['-p', message, '--output-format', 'json'];
53
+ if (this.options.cwd)
54
+ args.push('--cwd', this.options.cwd);
55
+ // Resume grok's own thread rather than starting fresh. `--continue` is
56
+ // deliberately not used: it means "the most recent session for this cwd",
57
+ // which collides between concurrent sessions on the same project.
58
+ if (this.grokSessionId)
59
+ args.push('--resume', this.grokSessionId);
60
+ const model = this.options.resolvedModel || this.options.model;
61
+ if (model)
62
+ args.push('--model', this.resolveModel(model.replace(/^grok\//, '')));
63
+ // grok's --permission-mode vocabulary is the same set as ours, so this is a
64
+ // passthrough rather than a mapping. 'manual' is ours alone; grok calls the
65
+ // equivalent 'default'.
66
+ const mode = this.options.permissionMode === 'manual' ? 'default' : this.options.permissionMode;
67
+ if (mode)
68
+ args.push('--permission-mode', mode);
69
+ const effort = options.effort ?? this.options.effort;
70
+ if (effort && effort !== 'auto') {
71
+ // grok takes low|medium|high; the two higher aliases in our union clamp.
72
+ args.push('--effort', effort === 'max' || effort === 'xhigh' ? 'high' : effort);
73
+ }
74
+ if (this.options.maxTurns)
75
+ args.push('--max-turns', String(this.options.maxTurns));
76
+ if (this.options.systemPrompt)
77
+ args.push('--system-prompt-override', this.options.systemPrompt);
78
+ return args;
79
+ }
80
+ _run(message, options) {
81
+ // Read-only is refused rather than approximated. grok exposes --permission-mode
82
+ // plan and --deny rules, but plan mode alone is model-cooperative — the same
83
+ // shape that let an adversarial prompt write through Cursor's plan mode — and
84
+ // the deny rules have not been put through the write × shell × subagent ×
85
+ // resumed-turn matrix this project requires before a read-only claim. Failing
86
+ // loudly beats a session that believes it cannot write and can.
87
+ if (this.options.sandboxMode === 'read-only') {
88
+ return Promise.reject(new Error('Grok sessions do not support sandboxMode: read-only yet — its enforcement has not been ' +
89
+ 'adversarially verified, and this engine will not claim a boundary it has not proven. ' +
90
+ 'Use a different engine for read-only work.'));
91
+ }
92
+ const args = this._buildArgs(message, options);
93
+ const timeout = options.timeout || 300_000;
94
+ return new Promise((resolve, reject) => {
95
+ let stdout = '';
96
+ let stderr = '';
97
+ let settled = false;
98
+ const proc = spawn(this.engineBin, args, {
99
+ cwd: this.options.cwd,
100
+ env: { ...process.env },
101
+ stdio: ['pipe', 'pipe', 'pipe'],
102
+ });
103
+ this.currentProc = proc;
104
+ proc.stdin?.end();
105
+ const timer = setTimeout(() => {
106
+ if (!settled) {
107
+ settled = true;
108
+ proc.kill('SIGKILL');
109
+ reject(new Error('Timeout waiting for Grok response'));
110
+ }
111
+ }, timeout);
112
+ proc.stdout?.on('data', (d) => {
113
+ stdout += d.toString();
114
+ });
115
+ proc.stderr?.on('data', (d) => {
116
+ const sanitized = sanitizeSecrets(d.toString());
117
+ stderr += sanitized;
118
+ this.emit(SESSION_EVENT.LOG, `[grok-stderr] ${sanitized}`);
119
+ });
120
+ proc.on('error', (err) => {
121
+ clearTimeout(timer);
122
+ this.currentProc = null;
123
+ if (!settled) {
124
+ settled = true;
125
+ reject(err);
126
+ }
127
+ });
128
+ proc.on('close', (code) => {
129
+ clearTimeout(timer);
130
+ this.currentProc = null;
131
+ if (settled)
132
+ return;
133
+ settled = true;
134
+ let parsed;
135
+ try {
136
+ const trimmed = stdout.trim();
137
+ if (trimmed)
138
+ parsed = JSON.parse(trimmed);
139
+ }
140
+ catch {
141
+ parsed = undefined;
142
+ }
143
+ // A turn that produced no parseable result object failed, whatever the
144
+ // exit code says: there is no reply to hand back.
145
+ const turnError = parsed?.error?.trim() ||
146
+ (!parsed ? stderr.trim() || `Grok exited with code ${code} and no JSON result` : undefined);
147
+ if (parsed?.sessionId) {
148
+ this.grokSessionId = parsed.sessionId;
149
+ if (!this.sessionId?.startsWith('grok-live-'))
150
+ this.sessionId = `grok-live-${parsed.sessionId}`;
151
+ }
152
+ const text = parsed?.text ?? '';
153
+ const ok = !turnError && code === 0 && parsed?.stopReason !== 'error';
154
+ this._recordTurnComplete(ok);
155
+ const usage = parsed?.usage;
156
+ if (usage) {
157
+ // Per-turn values (see the file header), so accumulate.
158
+ this._stats.tokensIn += usage.input_tokens ?? 0;
159
+ this._stats.tokensOut += usage.output_tokens ?? 0;
160
+ this._stats.cachedTokens += usage.cache_read_input_tokens ?? 0;
161
+ this._reportTurnInputTokens(usage.input_tokens ?? 0);
162
+ }
163
+ // Engine-reported spend, not a registry lookup — see the file header.
164
+ if (typeof parsed?.total_cost_usd === 'number' && Number.isFinite(parsed.total_cost_usd)) {
165
+ this._stats.costUsd += parsed.total_cost_usd;
166
+ }
167
+ this._addHistory({ text, code });
168
+ if (text) {
169
+ try {
170
+ options.callbacks?.onText?.(text);
171
+ }
172
+ catch {
173
+ /* user callback */
174
+ }
175
+ this.emit(SESSION_EVENT.TEXT, text);
176
+ }
177
+ const event = {
178
+ type: 'result',
179
+ result: text,
180
+ stop_reason: ok ? 'end_turn' : 'error',
181
+ session_id: this.grokSessionId,
182
+ };
183
+ this.emit(SESSION_EVENT.RESULT, event);
184
+ this.emit(SESSION_EVENT.TURN_COMPLETE, event);
185
+ if (turnError)
186
+ reject(new Error(turnError));
187
+ else
188
+ resolve({ text, event });
189
+ });
190
+ });
191
+ }
192
+ /** Grok's resumable session id, surfaced through getStats(). */
193
+ getStats() {
194
+ return { ...super.getStats(), grokSessionId: this.grokSessionId };
195
+ }
196
+ }
197
+ //# sourceMappingURL=persistent-grok-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-grok-session.js","sourceRoot":"","sources":["../../src/persistent-grok-session.ts"],"names":[],"mappings":"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"}
@@ -112,6 +112,7 @@ import { PersistentGeminiSession } from './persistent-gemini-session.js';
112
112
  import { PersistentCodexSession } from './persistent-codex-session.js';
113
113
  import { PersistentCodexAppServerSession } from './persistent-codex-app-session.js';
114
114
  import { PersistentCursorSession } from './persistent-cursor-session.js';
115
+ import { PersistentGrokSession } from './persistent-grok-session.js';
115
116
  import { PersistentOpencodeSession } from './persistent-opencode-session.js';
116
117
  import { PersistentAgySession } from './persistent-agy-session.js';
117
118
  import { PersistentCustomSession } from './persistent-custom-session.js';
@@ -1862,6 +1863,8 @@ export class SessionManager {
1862
1863
  return isAgyConversationId(id) ? id : undefined;
1863
1864
  if (engine === 'codex')
1864
1865
  return id && !/^codex-\d+-/.test(id) ? id : undefined;
1866
+ if (engine === 'grok')
1867
+ return id && !/^grok-\d+-/.test(id) ? id : undefined;
1865
1868
  return id;
1866
1869
  }
1867
1870
  _listMdFiles(dir) {
@@ -1888,6 +1891,8 @@ export class SessionManager {
1888
1891
  return new PersistentCodexAppServerSession(config, process.env.CODEX_BIN);
1889
1892
  case 'cursor':
1890
1893
  return new PersistentCursorSession(config, process.env.CURSOR_BIN);
1894
+ case 'grok':
1895
+ return new PersistentGrokSession(config, process.env.GROK_BIN);
1891
1896
  case 'opencode':
1892
1897
  return new PersistentOpencodeSession(config, process.env.OPENCODE_BIN);
1893
1898
  case 'custom':