@songsid/agend 2.1.0-beta.17 → 2.1.0-beta.18
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/README.md +1 -0
- package/dist/backend/factory.js +5 -1
- package/dist/backend/factory.js.map +1 -1
- package/dist/backend/grok.d.ts +40 -0
- package/dist/backend/grok.js +213 -0
- package/dist/backend/grok.js.map +1 -0
- package/dist/backend/types.d.ts +12 -2
- package/dist/backend/types.js +1 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +1 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +18 -4
- package/dist/daemon.js.map +1 -1
- package/dist/setup-wizard.js +8 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tmux-manager.d.ts +1 -1
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.d.ts +9 -0
- package/dist/topic-commands.js +36 -13
- package/dist/topic-commands.js.map +1 -1
- package/dist/ui/dashboard.html +2 -2
- package/dist/ui/settings.html +2 -2
- package/dist/web-api.js +2 -0
- package/dist/web-api.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ graph LR
|
|
|
121
121
|
| OpenCode | `curl -fsSL https://opencode.ai/install \| bash` | `opencode` (configure provider) |
|
|
122
122
|
| Kiro CLI | `curl -fsSL https://cli.kiro.dev/install | bash` | `kiro-cli login` (AWS Builder ID) |
|
|
123
123
|
| Antigravity CLI | `curl -fsSL https://antigravity.google/cli/install.sh \| bash` | `agy` (Google Sign-In) |
|
|
124
|
+
| Grok Build | `curl -fsSL https://x.ai/cli/install.sh \| bash` | `grok` (x.ai OAuth device flow) ⚠️ Experimental |
|
|
124
125
|
|
|
125
126
|
## Requirements
|
|
126
127
|
|
package/dist/backend/factory.js
CHANGED
|
@@ -4,6 +4,7 @@ import { CodexBackend } from "./codex.js";
|
|
|
4
4
|
import { OpenCodeBackend } from "./opencode.js";
|
|
5
5
|
import { KiroBackend } from "./kiro.js";
|
|
6
6
|
import { AntigravityBackend } from "./antigravity.js";
|
|
7
|
+
import { GrokBackend } from "./grok.js";
|
|
7
8
|
import { MockBackend } from "./mock.js";
|
|
8
9
|
export function createBackend(name, instanceDir) {
|
|
9
10
|
switch (name) {
|
|
@@ -20,10 +21,13 @@ export function createBackend(name, instanceDir) {
|
|
|
20
21
|
return new KiroBackend(instanceDir);
|
|
21
22
|
case "antigravity":
|
|
22
23
|
return new AntigravityBackend(instanceDir);
|
|
24
|
+
case "grok":
|
|
25
|
+
console.warn("⚠️ grok backend is experimental — some patterns may need tuning.");
|
|
26
|
+
return new GrokBackend(instanceDir);
|
|
23
27
|
case "mock":
|
|
24
28
|
return new MockBackend(instanceDir);
|
|
25
29
|
default:
|
|
26
|
-
throw new Error(`Unknown backend: ${name}. Available: claude-code, gemini-cli, codex, opencode, kiro-cli, antigravity, mock`);
|
|
30
|
+
throw new Error(`Unknown backend: ${name}. Available: claude-code, gemini-cli, codex, opencode, kiro-cli, antigravity, grok, mock`);
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
33
|
//# sourceMappingURL=factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/backend/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,WAAmB;IAC7D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,aAAa;YAChB,OAAO,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC5C,KAAK,YAAY;YACf,OAAO,CAAC,IAAI,CAAC,6FAA6F,CAAC,CAAC;YAC5G,OAAO,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAC3C,KAAK,OAAO;YACV,OAAO,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC;QACvC,KAAK,UAAU;YACb,OAAO,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;QAC1C,KAAK,UAAU;YACb,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC,KAAK,aAAa;YAChB,OAAO,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC7C,KAAK,MAAM;YACT,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC;YACE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/backend/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,WAAmB;IAC7D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,aAAa;YAChB,OAAO,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC5C,KAAK,YAAY;YACf,OAAO,CAAC,IAAI,CAAC,6FAA6F,CAAC,CAAC;YAC5G,OAAO,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAC3C,KAAK,OAAO;YACV,OAAO,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC;QACvC,KAAK,UAAU;YACb,OAAO,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;QAC1C,KAAK,UAAU;YACb,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC,KAAK,aAAa;YAChB,OAAO,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC7C,KAAK,MAAM;YACT,OAAO,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;YACjF,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC,KAAK,MAAM;YACT,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC;YACE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,0FAA0F,CAAC,CAAC;IACxI,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type CliBackend, type CliBackendConfig, type ErrorPattern, type RuntimeDialog, type StartupDialog } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Grok Build (xAI) — https://docs.x.ai/build/cli
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT — why the interactive TUI, not `grok agent stdio`:
|
|
6
|
+
* Grok Build exposes three surfaces: the interactive TUI (`grok`), headless
|
|
7
|
+
* (`grok -p "<prompt>"`), and an ACP agent (`grok agent stdio`) that speaks
|
|
8
|
+
* JSON-RPC over stdin/stdout. AgEnD drives a backend through a tmux PTY — it
|
|
9
|
+
* scans human-readable pane text for ready/error patterns and injects
|
|
10
|
+
* keystrokes (cancel key, slash commands). An ACP JSON-RPC agent has no
|
|
11
|
+
* human-readable prompt, ready banner, or slash commands, so the CliBackend
|
|
12
|
+
* interface does not map onto it. The interactive TUI is the correct surface,
|
|
13
|
+
* the same choice made for codex/opencode/kiro.
|
|
14
|
+
*
|
|
15
|
+
* Phase 2: ready pattern, cancel/quit keys, /compact, context format, and the
|
|
16
|
+
* device-flow login dialog were confirmed against a live grok session. Error
|
|
17
|
+
* strings beyond the cancellation notice are still best-effort and may need
|
|
18
|
+
* tuning — the backend is registered as experimental (see factory.ts).
|
|
19
|
+
*/
|
|
20
|
+
export declare class GrokBackend implements CliBackend {
|
|
21
|
+
private instanceDir;
|
|
22
|
+
readonly binaryName = "grok";
|
|
23
|
+
private binaryPath;
|
|
24
|
+
constructor(instanceDir: string);
|
|
25
|
+
buildCommand(config: CliBackendConfig): string;
|
|
26
|
+
/** The daemon's persisted session id (written from getSessionId()), for --resume. */
|
|
27
|
+
private storedSessionId;
|
|
28
|
+
writeConfig(config: CliBackendConfig): void;
|
|
29
|
+
getReadyPattern(): RegExp;
|
|
30
|
+
getErrorPatterns(): ErrorPattern[];
|
|
31
|
+
getStartupDialogs(): StartupDialog[];
|
|
32
|
+
getContextUsage(): number | null;
|
|
33
|
+
getSessionId(): string | null;
|
|
34
|
+
getRuntimeDialogs(): RuntimeDialog[];
|
|
35
|
+
getQuitCommand(): string | null;
|
|
36
|
+
getQuitKey(): string;
|
|
37
|
+
getCompactCommand(): string;
|
|
38
|
+
getCancelKey(): string;
|
|
39
|
+
cleanup(config: CliBackendConfig): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { isModelCompatible, resolveBinary, validateModel } from "./types.js";
|
|
5
|
+
import { appendWithMarker, removeMarker } from "./marker-utils.js";
|
|
6
|
+
/** Session ids are UUIDs (e.g. "019f82d4-…"); guard before shell interpolation. */
|
|
7
|
+
const SESSION_ID_RE = /^[A-Za-z0-9-]+$/;
|
|
8
|
+
/**
|
|
9
|
+
* Grok Build (xAI) — https://docs.x.ai/build/cli
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT — why the interactive TUI, not `grok agent stdio`:
|
|
12
|
+
* Grok Build exposes three surfaces: the interactive TUI (`grok`), headless
|
|
13
|
+
* (`grok -p "<prompt>"`), and an ACP agent (`grok agent stdio`) that speaks
|
|
14
|
+
* JSON-RPC over stdin/stdout. AgEnD drives a backend through a tmux PTY — it
|
|
15
|
+
* scans human-readable pane text for ready/error patterns and injects
|
|
16
|
+
* keystrokes (cancel key, slash commands). An ACP JSON-RPC agent has no
|
|
17
|
+
* human-readable prompt, ready banner, or slash commands, so the CliBackend
|
|
18
|
+
* interface does not map onto it. The interactive TUI is the correct surface,
|
|
19
|
+
* the same choice made for codex/opencode/kiro.
|
|
20
|
+
*
|
|
21
|
+
* Phase 2: ready pattern, cancel/quit keys, /compact, context format, and the
|
|
22
|
+
* device-flow login dialog were confirmed against a live grok session. Error
|
|
23
|
+
* strings beyond the cancellation notice are still best-effort and may need
|
|
24
|
+
* tuning — the backend is registered as experimental (see factory.ts).
|
|
25
|
+
*/
|
|
26
|
+
export class GrokBackend {
|
|
27
|
+
instanceDir;
|
|
28
|
+
binaryName = "grok";
|
|
29
|
+
binaryPath;
|
|
30
|
+
constructor(instanceDir) {
|
|
31
|
+
this.instanceDir = instanceDir;
|
|
32
|
+
this.binaryPath = resolveBinary("grok");
|
|
33
|
+
}
|
|
34
|
+
buildCommand(config) {
|
|
35
|
+
// Flags: -m/--model, --always-approve, -r/--resume <ID>, -p/--single, --no-auto-update.
|
|
36
|
+
// --no-auto-update: an auto-update prompt on launch would corrupt ready detection.
|
|
37
|
+
let cmd = `${this.binaryPath} --no-auto-update`;
|
|
38
|
+
// --always-approve auto-approves tool executions (documented flag). If a grok
|
|
39
|
+
// build ignores it, getRuntimeDialogs() auto-approves the prompt as a net.
|
|
40
|
+
if (config.skipPermissions !== false)
|
|
41
|
+
cmd += " --always-approve";
|
|
42
|
+
// Resume by explicit session id (verified: grok prints
|
|
43
|
+
// "Resume this session with: grok --resume <uuid>" on exit — there is no
|
|
44
|
+
// bare --continue that reliably resumes). The id is persisted by the daemon
|
|
45
|
+
// from getSessionId(); skip on crash recovery (skipResume) for a clean start.
|
|
46
|
+
if (!config.skipResume) {
|
|
47
|
+
const sid = this.storedSessionId();
|
|
48
|
+
if (sid)
|
|
49
|
+
cmd += ` --resume ${sid}`;
|
|
50
|
+
}
|
|
51
|
+
if (config.model) {
|
|
52
|
+
if (isModelCompatible("grok", config.model)) {
|
|
53
|
+
cmd += ` --model ${validateModel(config.model)}`;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.warn(`[agend] model "${config.model}" is not compatible with grok — skipping --model, using the CLI's default`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return cmd;
|
|
60
|
+
}
|
|
61
|
+
/** The daemon's persisted session id (written from getSessionId()), for --resume. */
|
|
62
|
+
storedSessionId() {
|
|
63
|
+
try {
|
|
64
|
+
const sid = readFileSync(join(this.instanceDir, "session-id"), "utf-8").trim();
|
|
65
|
+
return SESSION_ID_RE.test(sid) ? sid : null;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
writeConfig(config) {
|
|
72
|
+
// Grok Build merges MCP servers from a project-level .mcp.json (loaded below
|
|
73
|
+
// ~/.grok/config.toml in priority). Using the project file means we never
|
|
74
|
+
// clobber the user's global config. Standard mcpServers format: { command, args, env }.
|
|
75
|
+
const mcpPath = join(config.workingDirectory, ".mcp.json");
|
|
76
|
+
let root = {};
|
|
77
|
+
try {
|
|
78
|
+
root = JSON.parse(readFileSync(mcpPath, "utf-8"));
|
|
79
|
+
}
|
|
80
|
+
catch { /* new file */ }
|
|
81
|
+
const servers = (root.mcpServers ?? {});
|
|
82
|
+
// Drop stale agend entries whose command binary no longer exists.
|
|
83
|
+
for (const [key, val] of Object.entries(servers)) {
|
|
84
|
+
if (key.startsWith("agend-")) {
|
|
85
|
+
const cmd = val?.command;
|
|
86
|
+
if (typeof cmd === "string" && !existsSync(cmd))
|
|
87
|
+
delete servers[key];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Namespace each server by instance so multiple instances can share a working dir.
|
|
91
|
+
for (const [name, entry] of Object.entries(config.mcpServers)) {
|
|
92
|
+
const instanceKey = `${name}-${config.instanceName}`;
|
|
93
|
+
servers[instanceKey] = {
|
|
94
|
+
command: entry.command,
|
|
95
|
+
args: entry.args,
|
|
96
|
+
env: { ...entry.env, AGEND_INSTANCE_NAME: config.instanceName },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Clean up any legacy non-namespaced key.
|
|
100
|
+
delete servers["agend"];
|
|
101
|
+
root.mcpServers = servers;
|
|
102
|
+
writeFileSync(mcpPath, JSON.stringify(root, null, 2));
|
|
103
|
+
// Fleet instructions → AGENTS.md marker block (Grok reads AGENTS.md project docs,
|
|
104
|
+
// same convention as Codex). Additive + idempotent via the AGEND marker.
|
|
105
|
+
if (config.instructions) {
|
|
106
|
+
try {
|
|
107
|
+
appendWithMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName, config.instructions);
|
|
108
|
+
}
|
|
109
|
+
catch { /* best effort */ }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
getReadyPattern() {
|
|
113
|
+
// Verified: `❯` is the idle input prompt inside the TUI box; the Grok Build
|
|
114
|
+
// header ("Grok Build" / "Grok <n>") also identifies the ready screen.
|
|
115
|
+
return /❯|Grok \d|Grok Build/m;
|
|
116
|
+
}
|
|
117
|
+
getErrorPatterns() {
|
|
118
|
+
// NOTE: "Turn cancelled by user" is NORMAL behaviour (user interrupt), not an
|
|
119
|
+
// error — none of the patterns below match it, and none should be added that do.
|
|
120
|
+
// Error strings below are best-effort generic API shapes; tune once observed live.
|
|
121
|
+
return [
|
|
122
|
+
{ pattern: /rate.?limit|too many requests|\b429\b/i, type: "rate_limit", action: "failover", message: "Grok rate limit reached" },
|
|
123
|
+
{ pattern: /unauthorized|authentication (failed|error)|\b401\b/i, type: "auth_error", action: "pause", message: "Grok authentication error" },
|
|
124
|
+
{ pattern: /quota|insufficient credits|out of credits/i, type: "quota", action: "notify", message: "Grok quota/credits exhausted" },
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
getStartupDialogs() {
|
|
128
|
+
return [
|
|
129
|
+
// Device-flow login is BLOCKING and cannot be auto-dismissed — the user must
|
|
130
|
+
// approve externally. Empty keys => the daemon sends nothing but treats the
|
|
131
|
+
// screen as "not ready yet" and keeps polling, so the login screen is never
|
|
132
|
+
// mistaken for the idle prompt. (The "[Click here to Upgrade]" banner is
|
|
133
|
+
// non-blocking and is intentionally NOT listed — nothing to dismiss.)
|
|
134
|
+
{ pattern: /Waiting for approval|Log in to continue|device.*approval/i, keys: [], description: "Grok device-flow login — wait for user authorization (no auto-dismiss)" },
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
getContextUsage() {
|
|
138
|
+
// Grok shows context as "12K / 500K" (used / total) in the TUI, not in a file.
|
|
139
|
+
// getContextUsage() has no pane access, so parsing lives in the pane scanners
|
|
140
|
+
// (parseContextPercent in topic-commands.ts + defaultParser in cli.ts), which
|
|
141
|
+
// is what /ctx and `agend ls` use. Nothing file-based to report here.
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
getSessionId() {
|
|
145
|
+
// grok stores sessions under ~/.grok/sessions/ (verified). Return the id of
|
|
146
|
+
// the most-recently-modified session so the daemon can persist it for
|
|
147
|
+
// --resume. The daemon calls this at stop/pause, right after the active
|
|
148
|
+
// session was last written, so "newest" is normally this instance's session.
|
|
149
|
+
//
|
|
150
|
+
// ⚠️ CAVEAT: ~/.grok/sessions/ is GLOBAL, not per-working-directory. If the
|
|
151
|
+
// fleet runs multiple grok instances concurrently, "newest" could belong to
|
|
152
|
+
// another instance. Correct scoping needs either per-project session storage
|
|
153
|
+
// from grok or capturing the printed "grok --resume <id>" line — see report.
|
|
154
|
+
try {
|
|
155
|
+
const dir = join(homedir(), ".grok", "sessions");
|
|
156
|
+
let newestId = null;
|
|
157
|
+
let newestMtime = -1;
|
|
158
|
+
for (const name of readdirSync(dir)) {
|
|
159
|
+
const id = name.replace(/\.[^.]+$/, ""); // strip extension if any
|
|
160
|
+
if (!SESSION_ID_RE.test(id) || id.length < 8)
|
|
161
|
+
continue;
|
|
162
|
+
const mtime = statSync(join(dir, name)).mtimeMs;
|
|
163
|
+
if (mtime > newestMtime) {
|
|
164
|
+
newestMtime = mtime;
|
|
165
|
+
newestId = id;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return newestId;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
getRuntimeDialogs() {
|
|
175
|
+
return [
|
|
176
|
+
// Mid-task tool-approval prompt ("1. Yes, always 2. Yes 3. No"). Select
|
|
177
|
+
// option 1 so the fleet runs unattended. Primary mechanism is
|
|
178
|
+
// --always-approve at launch; this is the net if that flag is absent/ignored.
|
|
179
|
+
// ⚠️ key needs live confirmation — assumes a numeric hotkey (types "1"+Enter);
|
|
180
|
+
// if grok uses an arrow-select cursor instead, switch to ["Enter"] or nav keys.
|
|
181
|
+
{ pattern: /1\.\s*Yes,?\s*always|Yes,?\s*always[\s\S]{0,40}\bNo\b/i, keys: ["1"], description: "Grok tool-approval prompt — select 'Yes, always'" },
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
// grok has no slash quit command — it quits via the Ctrl+Q key chord (getQuitKey).
|
|
185
|
+
getQuitCommand() { return null; }
|
|
186
|
+
getQuitKey() { return "C-q"; }
|
|
187
|
+
getCompactCommand() { return "/compact"; } // verified present
|
|
188
|
+
// Verified: grok interrupts generation on Ctrl+C.
|
|
189
|
+
getCancelKey() { return "C-c"; }
|
|
190
|
+
cleanup(config) {
|
|
191
|
+
// Remove only this instance's namespaced MCP entries — a non-namespaced key
|
|
192
|
+
// may belong to another instance sharing the working directory.
|
|
193
|
+
try {
|
|
194
|
+
const mcpPath = join(config.workingDirectory, ".mcp.json");
|
|
195
|
+
if (existsSync(mcpPath)) {
|
|
196
|
+
const root = JSON.parse(readFileSync(mcpPath, "utf-8"));
|
|
197
|
+
if (root.mcpServers) {
|
|
198
|
+
for (const name of Object.keys(config.mcpServers)) {
|
|
199
|
+
delete root.mcpServers[`${name}-${config.instanceName}`];
|
|
200
|
+
}
|
|
201
|
+
writeFileSync(mcpPath, JSON.stringify(root, null, 2));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch { /* best effort */ }
|
|
206
|
+
// Remove fleet instructions marker block from AGENTS.md.
|
|
207
|
+
try {
|
|
208
|
+
removeMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName);
|
|
209
|
+
}
|
|
210
|
+
catch { /* best effort */ }
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=grok.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.js","sourceRoot":"","sources":["../../src/backend/grok.ts"],"names":[],"mappings":"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"}
|
package/dist/backend/types.d.ts
CHANGED
|
@@ -92,8 +92,18 @@ export interface CliBackend {
|
|
|
92
92
|
preTrust?(workingDirectory: string): void;
|
|
93
93
|
/** Resolve working directory (e.g. create symlink to avoid hidden paths). Returns resolved path. */
|
|
94
94
|
resolveWorkingDirectory?(workingDirectory: string, instanceName?: string): string;
|
|
95
|
-
/**
|
|
96
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Slash/text command to gracefully quit the CLI (e.g. "/exit", "/quit"),
|
|
97
|
+
* typed then followed by Enter. Return null when the CLI has no quit command
|
|
98
|
+
* and quits via a key chord instead — implement getQuitKey() in that case.
|
|
99
|
+
*/
|
|
100
|
+
getQuitCommand(): string | null;
|
|
101
|
+
/**
|
|
102
|
+
* The tmux key chord that quits the CLI, for backends whose quit is a keypress
|
|
103
|
+
* rather than a typed command (e.g. grok Ctrl+Q). Consulted only when
|
|
104
|
+
* getQuitCommand() returns null. Values are tmux send-keys names (e.g. "C-q").
|
|
105
|
+
*/
|
|
106
|
+
getQuitKey?(): string;
|
|
97
107
|
/**
|
|
98
108
|
* In-session command to compact/reset the conversation context. Most CLIs use
|
|
99
109
|
* "/compact"; some (e.g. Codex) use "/compact" too, OpenCode uses "/compact".
|
package/dist/backend/types.js
CHANGED
|
@@ -34,6 +34,7 @@ const BACKEND_MODEL_PATTERNS = {
|
|
|
34
34
|
"gemini-cli": /^gemini/i,
|
|
35
35
|
"opencode": /./, // opencode accepts anything (provider-dependent)
|
|
36
36
|
"antigravity": / /, // agy models always contain spaces (display names like "Gemini 3.5 Flash (High)")
|
|
37
|
+
"grok": /^grok/i, // grok-4.5, grok-4.3, grok-code, grok-build-0.1
|
|
37
38
|
};
|
|
38
39
|
/** Check if a model name is compatible with the given backend. */
|
|
39
40
|
export function isModelCompatible(backendName, model) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAqJlD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,wBAAwB;IACvC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAC5C,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,iBAAiB,aAAa,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,0GAA0G;AAC1G,MAAM,sBAAsB,GAA2B;IACrD,aAAa,EAAE,4CAA4C;IAC3D,UAAU,EAAE,8BAA8B;IAC1C,OAAO,EAAE,wBAAwB;IACjC,YAAY,EAAE,UAAU;IACxB,UAAU,EAAE,GAAG,EAAG,iDAAiD;IACnE,aAAa,EAAE,GAAG,EAAG,kFAAkF;IACvG,MAAM,EAAE,QAAQ,EAAG,gDAAgD;CACpE,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,KAAa;IAClE,MAAM,OAAO,GAAG,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC,CAAC,iCAAiC;IAC5D,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,KAAa;IACpE,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,kBAAkB,KAAK,uCAAuC,WAAW,0BAA0B,CAAC,CAAC;IACpH,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACzC,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1938,6 +1938,7 @@ function formatTimeSince(isoStr) {
|
|
|
1938
1938
|
* kiro classic "8% !>" / TUI "◔ 1%" / bracket "[8%]" / prompt "8% ❯"
|
|
1939
1939
|
* codex "Context N% left" (remaining → 100-N) or "Context N% used"
|
|
1940
1940
|
* opencode "1.2K (6%)"
|
|
1941
|
+
* grok "12K / 500K" (used tokens / context window)
|
|
1941
1942
|
* Duplicated (not imported) so this CLI entry point stays free of the daemon's
|
|
1942
1943
|
* dependency graph. All returned values are context USED (low % = fresh).
|
|
1943
1944
|
*/
|
|
@@ -1948,6 +1949,18 @@ const defaultParser = (output) => {
|
|
|
1948
1949
|
const left = line.match(/Context\s+(\d+)%\s+left/i);
|
|
1949
1950
|
if (left)
|
|
1950
1951
|
return 100 - parseInt(left[1], 10);
|
|
1952
|
+
const ratio = line.match(/(\d+\.?\d*[KkMm]?)\s*\/\s*(\d+\.?\d*[KkMm]?)/);
|
|
1953
|
+
if (ratio) {
|
|
1954
|
+
const tokenCount = (value) => {
|
|
1955
|
+
const suffix = value.at(-1)?.toLowerCase();
|
|
1956
|
+
const multiplier = suffix === "k" ? 1_000 : suffix === "m" ? 1_000_000 : 1;
|
|
1957
|
+
return parseFloat(value) * multiplier;
|
|
1958
|
+
};
|
|
1959
|
+
const used = tokenCount(ratio[1]);
|
|
1960
|
+
const total = tokenCount(ratio[2]);
|
|
1961
|
+
if (Number.isFinite(used) && Number.isFinite(total) && total > 0)
|
|
1962
|
+
return used / total * 100;
|
|
1963
|
+
}
|
|
1951
1964
|
const m = line.match(/(\d+)%.*[!❯>]/)
|
|
1952
1965
|
|| line.match(/◔\s*(\d+)%/)
|
|
1953
1966
|
|| line.match(/\[(\d+)%\]/)
|