@songsid/agend 2.1.0-beta.3 → 2.1.0-beta.31

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.
Files changed (97) hide show
  1. package/README.md +1 -0
  2. package/README.zh-TW.md +2 -1
  3. package/dist/access-path.js +3 -3
  4. package/dist/access-path.js.map +1 -1
  5. package/dist/agent-cli.js +1 -1
  6. package/dist/agent-cli.js.map +1 -1
  7. package/dist/agent-endpoint.d.ts +8 -0
  8. package/dist/agent-endpoint.js +36 -8
  9. package/dist/agent-endpoint.js.map +1 -1
  10. package/dist/backend/antigravity.js +3 -2
  11. package/dist/backend/antigravity.js.map +1 -1
  12. package/dist/backend/claude-code.js +4 -4
  13. package/dist/backend/claude-code.js.map +1 -1
  14. package/dist/backend/factory.js +4 -1
  15. package/dist/backend/factory.js.map +1 -1
  16. package/dist/backend/grok.d.ts +51 -0
  17. package/dist/backend/grok.js +282 -0
  18. package/dist/backend/grok.js.map +1 -0
  19. package/dist/backend/kiro.js +3 -2
  20. package/dist/backend/kiro.js.map +1 -1
  21. package/dist/backend/types.d.ts +12 -2
  22. package/dist/backend/types.js +1 -0
  23. package/dist/backend/types.js.map +1 -1
  24. package/dist/channel/adapters/discord.d.ts +20 -0
  25. package/dist/channel/adapters/discord.js +85 -11
  26. package/dist/channel/adapters/discord.js.map +1 -1
  27. package/dist/channel/adapters/telegram.js +4 -1
  28. package/dist/channel/adapters/telegram.js.map +1 -1
  29. package/dist/channel/mcp-tools.js +17 -1
  30. package/dist/channel/mcp-tools.js.map +1 -1
  31. package/dist/classic-channel-manager.d.ts +14 -1
  32. package/dist/classic-channel-manager.js +65 -4
  33. package/dist/classic-channel-manager.js.map +1 -1
  34. package/dist/cli.js +108 -16
  35. package/dist/cli.js.map +1 -1
  36. package/dist/config-validator.js +68 -1
  37. package/dist/config-validator.js.map +1 -1
  38. package/dist/config.d.ts +3 -1
  39. package/dist/config.js +13 -1
  40. package/dist/config.js.map +1 -1
  41. package/dist/context-guardian.d.ts +2 -0
  42. package/dist/context-guardian.js +10 -2
  43. package/dist/context-guardian.js.map +1 -1
  44. package/dist/daemon-entry.js +2 -1
  45. package/dist/daemon-entry.js.map +1 -1
  46. package/dist/daemon.d.ts +76 -6
  47. package/dist/daemon.js +451 -113
  48. package/dist/daemon.js.map +1 -1
  49. package/dist/fleet-context.d.ts +4 -0
  50. package/dist/fleet-manager.d.ts +88 -7
  51. package/dist/fleet-manager.js +712 -129
  52. package/dist/fleet-manager.js.map +1 -1
  53. package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -1
  54. package/dist/general-knowledge/skills/model-discovery/SKILL.md +1 -0
  55. package/dist/instance-lifecycle.d.ts +11 -1
  56. package/dist/instance-lifecycle.js +64 -22
  57. package/dist/instance-lifecycle.js.map +1 -1
  58. package/dist/locale.js +26 -2
  59. package/dist/locale.js.map +1 -1
  60. package/dist/logger.d.ts +6 -0
  61. package/dist/logger.js +29 -10
  62. package/dist/logger.js.map +1 -1
  63. package/dist/outbound-handlers.d.ts +3 -0
  64. package/dist/outbound-handlers.js +203 -2
  65. package/dist/outbound-handlers.js.map +1 -1
  66. package/dist/outbound-schemas.d.ts +40 -1
  67. package/dist/outbound-schemas.js +36 -1
  68. package/dist/outbound-schemas.js.map +1 -1
  69. package/dist/pause-marker.d.ts +5 -0
  70. package/dist/pause-marker.js +36 -0
  71. package/dist/pause-marker.js.map +1 -0
  72. package/dist/settings-api.d.ts +20 -2
  73. package/dist/settings-api.js +213 -9
  74. package/dist/settings-api.js.map +1 -1
  75. package/dist/setup-wizard.js +8 -0
  76. package/dist/setup-wizard.js.map +1 -1
  77. package/dist/statusline-watcher.d.ts +1 -1
  78. package/dist/statusline-watcher.js +3 -2
  79. package/dist/statusline-watcher.js.map +1 -1
  80. package/dist/tmux-control.d.ts +7 -0
  81. package/dist/tmux-control.js +22 -1
  82. package/dist/tmux-control.js.map +1 -1
  83. package/dist/tmux-manager.d.ts +1 -1
  84. package/dist/tmux-manager.js.map +1 -1
  85. package/dist/topic-commands.d.ts +19 -1
  86. package/dist/topic-commands.js +132 -23
  87. package/dist/topic-commands.js.map +1 -1
  88. package/dist/transcript-monitor.js +2 -0
  89. package/dist/transcript-monitor.js.map +1 -1
  90. package/dist/types.d.ts +23 -1
  91. package/dist/ui/dashboard.html +2 -2
  92. package/dist/ui/settings.html +453 -74
  93. package/dist/web-api.d.ts +1 -0
  94. package/dist/web-api.js +24 -15
  95. package/dist/web-api.js.map +1 -1
  96. package/dist/workflow-templates/default.md +0 -4
  97. package/package.json +2 -1
@@ -0,0 +1,282 @@
1
+ import { join } from "node:path";
2
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, chmodSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { createHash } from "node:crypto";
5
+ import { isModelCompatible, resolveBinary, validateModel } from "./types.js";
6
+ import { appendWithMarker, removeMarker } from "./marker-utils.js";
7
+ /** Session ids are UUIDs (e.g. "019f82d4-…"); guard before shell interpolation. */
8
+ const SESSION_ID_RE = /^[A-Za-z0-9-]+$/;
9
+ /**
10
+ * Grok Build (xAI) — https://docs.x.ai/build/cli
11
+ *
12
+ * IMPORTANT — why the interactive TUI, not `grok agent stdio`:
13
+ * Grok Build exposes three surfaces: the interactive TUI (`grok`), headless
14
+ * (`grok -p "<prompt>"`), and an ACP agent (`grok agent stdio`) that speaks
15
+ * JSON-RPC over stdin/stdout. AgEnD drives a backend through a tmux PTY — it
16
+ * scans human-readable pane text for ready/error patterns and injects
17
+ * keystrokes (cancel key, slash commands). An ACP JSON-RPC agent has no
18
+ * human-readable prompt, ready banner, or slash commands, so the CliBackend
19
+ * interface does not map onto it. The interactive TUI is the correct surface,
20
+ * the same choice made for codex/opencode/kiro.
21
+ *
22
+ * Phase 2: ready pattern, cancel/quit keys, /compact, context format, and the
23
+ * device-flow login dialog were confirmed against a live grok session. Error
24
+ * strings beyond the cancellation notice are still best-effort and may need
25
+ * tuning.
26
+ */
27
+ export class GrokBackend {
28
+ instanceDir;
29
+ binaryName = "grok";
30
+ binaryPath;
31
+ // Cached from buildCommand/writeConfig so getSessionId() (which takes no args)
32
+ // can scope to grok's per-cwd session directory.
33
+ workingDirectory;
34
+ constructor(instanceDir) {
35
+ this.instanceDir = instanceDir;
36
+ this.binaryPath = resolveBinary("grok");
37
+ }
38
+ buildCommand(config) {
39
+ this.workingDirectory = config.workingDirectory;
40
+ // Flags: -m/--model, --always-approve, -r/--resume <ID>, -p/--single, --no-auto-update.
41
+ // --no-auto-update: an auto-update prompt on launch would corrupt ready detection.
42
+ let cmd = `${this.binaryPath} --no-auto-update`;
43
+ // --always-approve auto-approves tool executions (documented flag). If a grok
44
+ // build ignores it, getRuntimeDialogs() auto-approves the prompt as a net.
45
+ if (config.skipPermissions !== false)
46
+ cmd += " --always-approve";
47
+ // Resume by explicit session id (verified: grok prints
48
+ // "Resume this session with: grok --resume <uuid>" on exit — there is no
49
+ // bare --continue that reliably resumes). The id is persisted by the daemon
50
+ // from getSessionId(); skip on crash recovery (skipResume) for a clean start.
51
+ if (!config.skipResume) {
52
+ const sid = this.storedSessionId();
53
+ if (sid)
54
+ cmd += ` --resume ${sid}`;
55
+ }
56
+ if (config.model) {
57
+ if (isModelCompatible("grok", config.model)) {
58
+ cmd += ` --model ${validateModel(config.model)}`;
59
+ }
60
+ else {
61
+ console.warn(`[agend] model "${config.model}" is not compatible with grok — skipping --model, using the CLI's default`);
62
+ }
63
+ }
64
+ return cmd;
65
+ }
66
+ /**
67
+ * Build an ASCII-only, per-instance MCP server key. Grok Build's MCP client has
68
+ * a bug where a non-ASCII (e.g. CJK) server name connects but drops ALL tools
69
+ * (tool_count=0, misreported as "connection failed"). Instance names can be CJK
70
+ * (persona ClassicBot channels), so sanitize: pure-ASCII names pass through
71
+ * unchanged (readable + already unique); names with non-ASCII are stripped to an
72
+ * ASCII slug plus a short hash of the ORIGINAL name, so two distinct CJK names
73
+ * sharing a working directory can't collide to the same key.
74
+ */
75
+ mcpKey(mcpName, instanceName) {
76
+ const ascii = instanceName.replace(/[^\x20-\x7E]/g, "");
77
+ if (ascii === instanceName)
78
+ return `${mcpName}-${instanceName}`;
79
+ const slug = ascii.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
80
+ const hash = createHash("md5").update(instanceName).digest("hex").slice(0, 8);
81
+ return slug ? `${mcpName}-${slug}-${hash}` : `${mcpName}-${hash}`;
82
+ }
83
+ /** The daemon's persisted session id (written from getSessionId()), for --resume. */
84
+ storedSessionId() {
85
+ try {
86
+ const sid = readFileSync(join(this.instanceDir, "session-id"), "utf-8").trim();
87
+ return SESSION_ID_RE.test(sid) ? sid : null;
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ writeConfig(config) {
94
+ this.workingDirectory = config.workingDirectory;
95
+ // Grok Build merges MCP servers from a project-level .mcp.json (loaded below
96
+ // ~/.grok/config.toml in priority). Using the project file means we never
97
+ // clobber the user's global config. Standard mcpServers format: { command, args, env }.
98
+ const mcpPath = join(config.workingDirectory, ".mcp.json");
99
+ let root = {};
100
+ try {
101
+ root = JSON.parse(readFileSync(mcpPath, "utf-8"));
102
+ }
103
+ catch { /* new file */ }
104
+ const servers = (root.mcpServers ?? {});
105
+ // Drop stale agend entries whose wrapper script no longer exists, plus any
106
+ // legacy non-ASCII key (grok drops all tools on a CJK key — we now always
107
+ // write ASCII keys, so a lingering CJK entry is dead weight to remove).
108
+ for (const [key, val] of Object.entries(servers)) {
109
+ if (key.startsWith("agend-")) {
110
+ const cmd = val?.command;
111
+ if ((typeof cmd === "string" && !existsSync(cmd)) || /[^\x20-\x7E]/.test(key)) {
112
+ delete servers[key];
113
+ }
114
+ }
115
+ }
116
+ // Namespace each server by instance so multiple instances can share a working
117
+ // dir. Key is ASCII-sanitized (grok's MCP client drops tools on a CJK key).
118
+ for (const [name, entry] of Object.entries(config.mcpServers)) {
119
+ const instanceKey = this.mcpKey(name, config.instanceName);
120
+ const allEnv = { ...entry.env, AGEND_INSTANCE_NAME: config.instanceName };
121
+ // WORKAROUND (same as kiro-cli): grok does not reliably pass the mcp.json
122
+ // "env" block to the MCP server subprocess — the process would inherit grok's
123
+ // env, which has NO AGEND_SOCKET_PATH (the daemon keeps it out of process.env),
124
+ // so the server can't connect and every MCP tool (reply/react/…) fails. Emit a
125
+ // wrapper that exports the env explicitly, waits for the IPC socket, then execs
126
+ // the real server. This is env-delivery-independent and works either way.
127
+ const wrapperPath = join(this.instanceDir, `mcp-wrapper-${name}.sh`);
128
+ const envExports = Object.entries(allEnv)
129
+ .map(([k, v]) => `export ${k}='${String(v).replace(/'/g, "'\\''")}'`)
130
+ .join("\n");
131
+ // 0o700: wrapper inlines sensitive env (tokens, socket paths) — owner-only.
132
+ writeFileSync(wrapperPath, `#!/bin/bash\n${envExports}\n# Wait for IPC socket to be ready (up to 10s)\nfor i in $(seq 1 20); do [ -S "$AGEND_SOCKET_PATH" ] && break; sleep 0.5; done\nexec ${entry.command} ${entry.args.map((a) => JSON.stringify(a)).join(" ")}\n`, { mode: 0o700 });
133
+ chmodSync(wrapperPath, 0o700);
134
+ servers[instanceKey] = { command: wrapperPath, args: [] };
135
+ }
136
+ // Clean up any legacy non-namespaced key.
137
+ delete servers["agend"];
138
+ root.mcpServers = servers;
139
+ writeFileSync(mcpPath, JSON.stringify(root, null, 2));
140
+ // Fleet instructions → AGENTS.md marker block (Grok reads AGENTS.md project docs,
141
+ // same convention as Codex). Additive + idempotent via the AGEND marker.
142
+ if (config.instructions) {
143
+ try {
144
+ appendWithMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName, config.instructions);
145
+ }
146
+ catch { /* best effort */ }
147
+ }
148
+ }
149
+ getReadyPattern() {
150
+ // Verified: `❯` is the idle input prompt inside the TUI box; the Grok Build
151
+ // header ("Grok Build" / "Grok <n>") also identifies the ready screen.
152
+ return /❯|Grok \d|Grok Build/m;
153
+ }
154
+ getErrorPatterns() {
155
+ // NOTE: "Turn cancelled by user" is NORMAL behaviour (user interrupt), not an
156
+ // error — none of the patterns below match it, and none should be added that do.
157
+ // Error strings below are best-effort generic API shapes; tune once observed live.
158
+ return [
159
+ { pattern: /rate.?limit|too many requests|\b429\b/i, type: "rate_limit", action: "failover", message: "Grok rate limit reached" },
160
+ { pattern: /unauthorized|authentication (failed|error)|\b401\b/i, type: "auth_error", action: "pause", message: "Grok authentication error" },
161
+ { pattern: /quota|insufficient credits|out of credits/i, type: "quota", action: "notify", message: "Grok quota/credits exhausted" },
162
+ ];
163
+ }
164
+ getStartupDialogs() {
165
+ return [
166
+ // Workspace trust confirmation ("Do you trust the contents of this directory?")
167
+ // appears BEFORE the login screen — auto-approve with the 'y' hotkey.
168
+ { pattern: /Do you trust the contents|trust.*directory/i, keys: ["y"], description: "Grok workspace trust — auto-approve" },
169
+ // Device-flow login is BLOCKING and cannot be auto-dismissed — the user must
170
+ // approve externally. Empty keys => the daemon sends nothing but treats the
171
+ // screen as "not ready yet" and keeps polling, so the login screen is never
172
+ // mistaken for the idle prompt. (The "[Click here to Upgrade]" banner is
173
+ // non-blocking and is intentionally NOT listed — nothing to dismiss.)
174
+ { pattern: /Waiting for approval|Log in to continue|device.*approval/i, keys: [], description: "Grok device-flow login — wait for user authorization (no auto-dismiss)" },
175
+ ];
176
+ }
177
+ getContextUsage() {
178
+ // Grok shows context as "12K / 500K" (used / total) in the TUI, not in a file.
179
+ // getContextUsage() has no pane access, so parsing lives in the pane scanners
180
+ // (parseContextPercent in topic-commands.ts + defaultParser in cli.ts), which
181
+ // is what /ctx and `agend ls` use. Nothing file-based to report here.
182
+ return null;
183
+ }
184
+ getSessionId() {
185
+ // grok stores sessions per working directory (verified):
186
+ // ~/.grok/sessions/<encodeURIComponent(cwd)>/<session-uuid>/{events.jsonl,…}
187
+ // Scoping by cwd means multiple concurrent grok instances (distinct cwds)
188
+ // never pick up each other's session. Return the UUID of the most-recently
189
+ // ACTIVE session in this instance's cwd for the daemon to persist (--resume).
190
+ if (!this.workingDirectory)
191
+ return null;
192
+ try {
193
+ const base = join(homedir(), ".grok", "sessions", encodeURIComponent(this.workingDirectory));
194
+ let newestId = null;
195
+ let newestMtime = -1;
196
+ for (const name of readdirSync(base)) {
197
+ // Session dirs are named by UUID; skip prompt_history.jsonl etc.
198
+ if (!SESSION_ID_RE.test(name) || name.length < 8)
199
+ continue;
200
+ const sessionDir = join(base, name);
201
+ let st;
202
+ try {
203
+ st = statSync(sessionDir);
204
+ }
205
+ catch {
206
+ continue;
207
+ }
208
+ if (!st.isDirectory())
209
+ continue;
210
+ // Activity = latest INNER-file mtime. The dir's own mtime doesn't move on
211
+ // append AND is misleadingly recent for a just-created dir, so it must NOT
212
+ // outweigh a resumed older session whose logs were just appended. Only fall
213
+ // back to dir mtime when the session has no inner files yet.
214
+ let activity = -1;
215
+ try {
216
+ for (const f of readdirSync(sessionDir)) {
217
+ try {
218
+ const m = statSync(join(sessionDir, f)).mtimeMs;
219
+ if (m > activity)
220
+ activity = m;
221
+ }
222
+ catch { /* skip */ }
223
+ }
224
+ }
225
+ catch { /* unreadable dir */ }
226
+ if (activity < 0)
227
+ activity = st.mtimeMs;
228
+ if (activity > newestMtime) {
229
+ newestMtime = activity;
230
+ newestId = name;
231
+ }
232
+ }
233
+ return newestId;
234
+ }
235
+ catch {
236
+ return null;
237
+ }
238
+ }
239
+ getRuntimeDialogs() {
240
+ return [
241
+ // Mid-task tool-approval prompt ("1. Yes, always 2. Yes 3. No"). Select
242
+ // option 1 so the fleet runs unattended. Primary mechanism is
243
+ // --always-approve at launch; this is the net if that flag is absent/ignored.
244
+ // ⚠️ key needs live confirmation — assumes a numeric hotkey (types "1"+Enter);
245
+ // if grok uses an arrow-select cursor instead, switch to ["Enter"] or nav keys.
246
+ { 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'" },
247
+ ];
248
+ }
249
+ // grok has no slash quit command — it quits via the Ctrl+Q key chord (getQuitKey).
250
+ getQuitCommand() { return null; }
251
+ getQuitKey() { return "C-q"; }
252
+ // Trailing space commits the exact slash command before Grok's autocomplete
253
+ // can expand the partial token to `/compact-mode`.
254
+ getCompactCommand() { return "/compact "; }
255
+ // Verified: grok interrupts generation on Ctrl+C.
256
+ getCancelKey() { return "C-c"; }
257
+ cleanup(config) {
258
+ // Remove only this instance's namespaced MCP entries — a non-namespaced key
259
+ // may belong to another instance sharing the working directory.
260
+ try {
261
+ const mcpPath = join(config.workingDirectory, ".mcp.json");
262
+ if (existsSync(mcpPath)) {
263
+ const root = JSON.parse(readFileSync(mcpPath, "utf-8"));
264
+ if (root.mcpServers) {
265
+ for (const name of Object.keys(config.mcpServers)) {
266
+ delete root.mcpServers[this.mcpKey(name, config.instanceName)];
267
+ // Also drop any legacy raw (pre-sanitize) key for this instance.
268
+ delete root.mcpServers[`${name}-${config.instanceName}`];
269
+ }
270
+ writeFileSync(mcpPath, JSON.stringify(root, null, 2));
271
+ }
272
+ }
273
+ }
274
+ catch { /* best effort */ }
275
+ // Remove fleet instructions marker block from AGENTS.md.
276
+ try {
277
+ removeMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName);
278
+ }
279
+ catch { /* best effort */ }
280
+ }
281
+ }
282
+ //# sourceMappingURL=grok.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grok.js","sourceRoot":"","sources":["../../src/backend/grok.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAqG,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChL,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEnE,mFAAmF;AACnF,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,WAAW;IAOF;IANX,UAAU,GAAG,MAAM,CAAC;IACrB,UAAU,CAAS;IAC3B,+EAA+E;IAC/E,iDAAiD;IACzC,gBAAgB,CAAU;IAElC,YAAoB,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;QACrC,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,YAAY,CAAC,MAAwB;QACnC,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAChD,wFAAwF;QACxF,mFAAmF;QACnF,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,mBAAmB,CAAC;QAChD,8EAA8E;QAC9E,2EAA2E;QAC3E,IAAI,MAAM,CAAC,eAAe,KAAK,KAAK;YAAE,GAAG,IAAI,mBAAmB,CAAC;QACjE,uDAAuD;QACvD,yEAAyE;QACzE,4EAA4E;QAC5E,8EAA8E;QAC9E,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACnC,IAAI,GAAG;gBAAE,GAAG,IAAI,aAAa,GAAG,EAAE,CAAC;QACrC,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5C,GAAG,IAAI,YAAY,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,KAAK,2EAA2E,CAAC,CAAC;YAC1H,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;;;;OAQG;IACK,MAAM,CAAC,OAAe,EAAE,YAAoB;QAClD,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QACxD,IAAI,KAAK,KAAK,YAAY;YAAE,OAAO,GAAG,OAAO,IAAI,YAAY,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACpE,CAAC;IAED,qFAAqF;IAC7E,eAAe;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/E,OAAO,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;IAC1B,CAAC;IAED,WAAW,CAAC,MAAwB;QAClC,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAChD,6EAA6E;QAC7E,0EAA0E;QAC1E,wFAAwF;QACxF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC3D,IAAI,IAAI,GAA4B,EAAE,CAAC;QACvC,IAAI,CAAC;YAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;QAEnF,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;QACnE,2EAA2E;QAC3E,0EAA0E;QAC1E,wEAAwE;QACxE,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,MAAM,GAAG,GAAI,GAA+B,EAAE,OAAO,CAAC;gBACtD,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC9E,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QACD,8EAA8E;QAC9E,4EAA4E;QAC5E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,mBAAmB,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;YAE1E,0EAA0E;YAC1E,8EAA8E;YAC9E,gFAAgF;YAChF,+EAA+E;YAC/E,gFAAgF;YAChF,0EAA0E;YAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,IAAI,KAAK,CAAC,CAAC;YACrE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;iBACtC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;iBACpE,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,4EAA4E;YAC5E,aAAa,CACX,WAAW,EACX,gBAAgB,UAAU,yIAAyI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAClP,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAC;YACF,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAE9B,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAC5D,CAAC;QACD,0CAA0C;QAC1C,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC;QAC1B,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAEtD,kFAAkF;QAClF,yEAAyE;QACzE,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;YACzG,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,eAAe;QACb,4EAA4E;QAC5E,uEAAuE;QACvE,OAAO,uBAAuB,CAAC;IACjC,CAAC;IAED,gBAAgB;QACd,8EAA8E;QAC9E,iFAAiF;QACjF,mFAAmF;QACnF,OAAO;YACL,EAAE,OAAO,EAAE,wCAAwC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,yBAAyB,EAAE;YACjI,EAAE,OAAO,EAAE,qDAAqD,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,2BAA2B,EAAE;YAC7I,EAAE,OAAO,EAAE,4CAA4C,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,8BAA8B,EAAE;SACpI,CAAC;IACJ,CAAC;IAED,iBAAiB;QACf,OAAO;YACL,gFAAgF;YAChF,sEAAsE;YACtE,EAAE,OAAO,EAAE,6CAA6C,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,qCAAqC,EAAE;YAC3H,6EAA6E;YAC7E,4EAA4E;YAC5E,4EAA4E;YAC5E,yEAAyE;YACzE,sEAAsE;YACtE,EAAE,OAAO,EAAE,2DAA2D,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,wEAAwE,EAAE;SAC1K,CAAC;IACJ,CAAC;IAED,eAAe;QACb,+EAA+E;QAC/E,8EAA8E;QAC9E,8EAA8E;QAC9E,sEAAsE;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY;QACV,yDAAyD;QACzD,+EAA+E;QAC/E,0EAA0E;QAC1E,2EAA2E;QAC3E,8EAA8E;QAC9E,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAC7F,IAAI,QAAQ,GAAkB,IAAI,CAAC;YACnC,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;YACrB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,iEAAiE;gBACjE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;oBAAE,SAAS;gBAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACpC,IAAI,EAAE,CAAC;gBACP,IAAI,CAAC;oBAAC,EAAE,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC;oBAAC,SAAS;gBAAC,CAAC;gBACtD,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE;oBAAE,SAAS;gBAChC,0EAA0E;gBAC1E,2EAA2E;gBAC3E,4EAA4E;gBAC5E,6DAA6D;gBAC7D,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;gBAClB,IAAI,CAAC;oBACH,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;wBACxC,IAAI,CAAC;4BAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;4BAAC,IAAI,CAAC,GAAG,QAAQ;gCAAE,QAAQ,GAAG,CAAC,CAAC;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;oBAC/G,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;gBAChC,IAAI,QAAQ,GAAG,CAAC;oBAAE,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC;gBACxC,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;oBAAC,WAAW,GAAG,QAAQ,CAAC;oBAAC,QAAQ,GAAG,IAAI,CAAC;gBAAC,CAAC;YAC1E,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;IAC1B,CAAC;IAED,iBAAiB;QACf,OAAO;YACL,0EAA0E;YAC1E,8DAA8D;YAC9D,8EAA8E;YAC9E,+EAA+E;YAC/E,gFAAgF;YAChF,EAAE,OAAO,EAAE,wDAAwD,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE;SACpJ,CAAC;IACJ,CAAC;IAED,mFAAmF;IACnF,cAAc,KAAoB,OAAO,IAAI,CAAC,CAAC,CAAC;IAChD,UAAU,KAAa,OAAO,KAAK,CAAC,CAAC,CAAC;IAEtC,4EAA4E;IAC5E,mDAAmD;IACnD,iBAAiB,KAAa,OAAO,WAAW,CAAC,CAAC,CAAC;IAEnD,kDAAkD;IAClD,YAAY,KAAa,OAAO,KAAK,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,MAAwB;QAC9B,4EAA4E;QAC5E,gEAAgE;QAChE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;YAC3D,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBACxD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACpB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;wBAClD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;wBAC/D,iEAAiE;wBACjE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;oBAC3D,CAAC;oBACD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAE7B,yDAAyD;QACzD,IAAI,CAAC;YACH,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -89,9 +89,10 @@ export class KiroBackend {
89
89
  }
90
90
  }
91
91
  getReadyPattern() {
92
- // Startup: trust/banner text. Daily prompt: "22% !>" / "8% ❯".
92
+ // Startup: trust/banner text. Daily prompt: "22% !>" / "8% ❯";
93
+ // Kiro may insert mode glyphs between them, e.g. "20% λ !>".
93
94
  // TUI statusline: "◔ 22%" context indicator shown while waiting for input.
94
- return /All tools are now trusted|Trust All Tools active|Credits:.*Time:|ask a question or describe a task|\d+%\s*[!❯>]|◔\s*\d+%/m;
95
+ return /All tools are now trusted|Trust All Tools active|Credits:.*Time:|ask a question or describe a task|\d+%.*[!❯>]|◔\s*\d+%/m;
95
96
  }
96
97
  getErrorPatterns() {
97
98
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"kiro.js","sourceRoot":"","sources":["../../src/backend/kiro.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kiro.js","sourceRoot":"","sources":["../../src/backend/kiro.ts"],"names":[],"mappings":"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"}
@@ -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
- /** Command to gracefully quit the CLI (e.g. "/exit", "/quit"). */
96
- getQuitCommand(): string;
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".
@@ -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;AA0IlD;;;;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;CACxG,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"}
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"}
@@ -1,6 +1,26 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import type { ChannelAdapter, ApprovalHandle, SendOpts, SentMessage, PermissionPrompt, Choice, AlertData } from "../types.js";
3
3
  import type { AccessManager } from "../access-manager.js";
4
+ /** Curated ClassicBot backends for Discord's native slash-option dropdown. */
5
+ export declare const DISCORD_START_BACKEND_CHOICES: readonly [{
6
+ readonly name: "Claude Code";
7
+ readonly value: "claude-code";
8
+ }, {
9
+ readonly name: "Kiro CLI";
10
+ readonly value: "kiro-cli";
11
+ }, {
12
+ readonly name: "Codex";
13
+ readonly value: "codex";
14
+ }, {
15
+ readonly name: "OpenCode";
16
+ readonly value: "opencode";
17
+ }, {
18
+ readonly name: "Antigravity";
19
+ readonly value: "antigravity";
20
+ }, {
21
+ readonly name: "Grok Build";
22
+ readonly value: "grok";
23
+ }];
4
24
  export interface DiscordAdapterOptions {
5
25
  id: string;
6
26
  botToken: string;
@@ -6,9 +6,19 @@ import { join } from "node:path";
6
6
  import { pipeline } from "node:stream/promises";
7
7
  import { Readable } from "node:stream";
8
8
  import { createWriteStream } from "node:fs";
9
- import { Client, GatewayIntentBits, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, MessageFlags, } from "discord.js";
9
+ import { Client, GatewayIntentBits, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, ApplicationCommandOptionType, ChannelType, MessageFlags, } from "discord.js";
10
10
  import { MessageQueue } from "../message-queue.js";
11
11
  const DISCORD_MAX_LENGTH = 2000;
12
+ /** Curated ClassicBot backends for Discord's native slash-option dropdown. */
13
+ export const DISCORD_START_BACKEND_CHOICES = [
14
+ { name: "Claude Code", value: "claude-code" },
15
+ { name: "Kiro CLI", value: "kiro-cli" },
16
+ { name: "Codex", value: "codex" },
17
+ { name: "OpenCode", value: "opencode" },
18
+ { name: "Antigravity", value: "antigravity" },
19
+ { name: "Grok Build", value: "grok" },
20
+ ];
21
+ const CLASSIC_START_BACKEND_SELECT_ID = "classic-start-backend";
12
22
  export class DiscordAdapter extends EventEmitter {
13
23
  type = "discord";
14
24
  topology = "channels";
@@ -215,6 +225,35 @@ export class DiscordAdapter extends EventEmitter {
215
225
  chatId: this.guildId,
216
226
  threadId: interaction.channelId,
217
227
  messageId: interaction.message.id,
228
+ userId: interaction.user.id,
229
+ });
230
+ return;
231
+ }
232
+ // Select menus use the selected option value as the callback payload.
233
+ // Acknowledge before routing for the same 3-second constraint as buttons.
234
+ if (interaction.isStringSelectMenu()) {
235
+ try {
236
+ await interaction.deferUpdate();
237
+ }
238
+ catch { /* already acknowledged / unknown interaction */ }
239
+ // `/start` is allowed in configured secondary guilds, but its channel
240
+ // is not in openChannels until AFTER the selection creates a Classic
241
+ // instance. Let this one coordinator-owned menu through; fleet-manager
242
+ // still validates its nonce, channel and initiating user. Other select
243
+ // menus retain the normal primary/open-channel boundary.
244
+ if (interaction.customId !== CLASSIC_START_BACKEND_SELECT_ID
245
+ && interaction.guildId !== this.guildId
246
+ && !this.openChannels.has(interaction.channelId ?? ""))
247
+ return;
248
+ const callbackData = interaction.values[0];
249
+ if (!callbackData)
250
+ return;
251
+ this.emit("callback_query", {
252
+ callbackData,
253
+ chatId: this.guildId,
254
+ threadId: interaction.channelId,
255
+ messageId: interaction.message.id,
256
+ userId: interaction.user.id,
218
257
  });
219
258
  return;
220
259
  }
@@ -265,6 +304,23 @@ export class DiscordAdapter extends EventEmitter {
265
304
  await this._editReplyLong(interaction, reply);
266
305
  }
267
306
  catch { /* expired */ } },
307
+ respondChoices: async (text, choices) => {
308
+ const select = new StringSelectMenuBuilder()
309
+ .setCustomId(CLASSIC_START_BACKEND_SELECT_ID)
310
+ .setPlaceholder("Choose a backend")
311
+ .addOptions(choices.map(choice => ({
312
+ label: choice.label.slice(0, 100),
313
+ value: choice.id.slice(0, 100),
314
+ })));
315
+ const row = new ActionRowBuilder().addComponents(select);
316
+ try {
317
+ const message = await interaction.editReply({ content: text, components: [row] });
318
+ return message.id;
319
+ }
320
+ catch {
321
+ return undefined;
322
+ }
323
+ },
268
324
  });
269
325
  }
270
326
  }
@@ -309,8 +365,25 @@ export class DiscordAdapter extends EventEmitter {
309
365
  if (this.registerCommands)
310
366
  try {
311
367
  await this.client.application?.commands.set([
312
- { name: "start", description: t("slash.start") },
368
+ {
369
+ name: "start", description: t("slash.start"),
370
+ options: [{
371
+ name: "backend",
372
+ description: "Backend to start",
373
+ type: ApplicationCommandOptionType.String,
374
+ required: true,
375
+ choices: DISCORD_START_BACKEND_CHOICES,
376
+ }],
377
+ },
313
378
  { name: "stop", description: t("slash.stop") },
379
+ {
380
+ name: "pause", description: "🔒 Pause an idle instance",
381
+ options: [{ name: "instance", description: "Instance name (required in General)", type: ApplicationCommandOptionType.String, required: false }],
382
+ },
383
+ {
384
+ name: "wake", description: "🔒 Wake a paused instance",
385
+ options: [{ name: "instance", description: "Instance name (required in General)", type: ApplicationCommandOptionType.String, required: false }],
386
+ },
314
387
  {
315
388
  name: "chat", description: t("slash.chat"),
316
389
  options: [{ name: "message", description: "Your message", type: 3, required: true }],
@@ -361,11 +434,11 @@ export class DiscordAdapter extends EventEmitter {
361
434
  async _editReplyLong(interaction, reply) {
362
435
  const EMBED_MAX = 4096;
363
436
  if (reply.length <= DISCORD_MAX_LENGTH) {
364
- await interaction.editReply(reply);
437
+ await interaction.editReply({ content: reply, components: [] });
365
438
  return;
366
439
  }
367
440
  const chunks = splitText(reply, EMBED_MAX);
368
- await interaction.editReply({ content: "", embeds: [{ description: chunks[0] }] });
441
+ await interaction.editReply({ content: "", embeds: [{ description: chunks[0] }], components: [] });
369
442
  for (let i = 1; i < chunks.length; i++) {
370
443
  await interaction.followUp({ ephemeral: true, embeds: [{ description: chunks[i] }] });
371
444
  }
@@ -591,13 +664,14 @@ export class DiscordAdapter extends EventEmitter {
591
664
  async promptUser(chatId, text, choices, opts) {
592
665
  const channelId = opts?.threadId ?? chatId;
593
666
  const channel = await this._fetchTextChannel(channelId);
594
- const row = new ActionRowBuilder();
595
- for (const choice of choices) {
596
- row.addComponents(new ButtonBuilder()
597
- .setCustomId(choice.id)
598
- .setLabel(choice.label.slice(0, 80)) // Discord button label max 80 chars
599
- .setStyle(ButtonStyle.Primary));
600
- }
667
+ const select = new StringSelectMenuBuilder()
668
+ .setCustomId(`prompt-${randomBytes(6).toString("hex")}`)
669
+ .setPlaceholder("Choose an option")
670
+ .addOptions(choices.map(choice => ({
671
+ label: choice.label.slice(0, 100),
672
+ value: choice.id.slice(0, 100),
673
+ })));
674
+ const row = new ActionRowBuilder().addComponents(select);
601
675
  const msg = await channel.send({ content: text, components: [row] });
602
676
  return msg.id;
603
677
  }