@barnaby.build/barnaby 0.0.128

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,3705 @@
1
+ var Tt = Object.defineProperty;
2
+ var $t = (n, t, e) => t in n ? Tt(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
+ var P = (n, t, e) => $t(n, typeof t != "symbol" ? t + "" : t, e);
4
+ import { ipcMain as f, app as $, BrowserWindow as L, nativeTheme as Ae, shell as z, dialog as me, Menu as xe, screen as _t } from "electron";
5
+ import { pathToFileURL as Mt, fileURLToPath as It } from "node:url";
6
+ import h from "node:path";
7
+ import d from "node:fs";
8
+ import Q from "node:os";
9
+ import { spawn as I, execFile as Rt } from "node:child_process";
10
+ import { promisify as Ot } from "node:util";
11
+ import { createRequire as Ft } from "node:module";
12
+ import { EventEmitter as ne } from "node:events";
13
+ import Dt from "node:readline";
14
+ class Lt extends ne {
15
+ constructor() {
16
+ super(...arguments);
17
+ P(this, "proc", null);
18
+ P(this, "rl", null);
19
+ P(this, "nextId", 1);
20
+ P(this, "pending", /* @__PURE__ */ new Map());
21
+ P(this, "threadId", null);
22
+ P(this, "activeTurnId", null);
23
+ P(this, "permissionMode", "verify-first");
24
+ P(this, "allowedCommandPrefixes", []);
25
+ P(this, "allowedAutoReadPrefixes", []);
26
+ P(this, "allowedAutoWritePrefixes", []);
27
+ P(this, "deniedAutoReadPrefixes", []);
28
+ P(this, "deniedAutoWritePrefixes", []);
29
+ P(this, "lastStderr", "");
30
+ }
31
+ emitEvent(e) {
32
+ this.emit("event", e);
33
+ }
34
+ isConnected() {
35
+ return this.proc !== null;
36
+ }
37
+ getThreadId() {
38
+ return this.threadId;
39
+ }
40
+ async connect(e) {
41
+ var a;
42
+ if (e.provider && e.provider !== "codex")
43
+ throw new Error(
44
+ `Provider "${e.provider}" is not implemented yet. Select a Codex model/provider for now.`
45
+ );
46
+ this.permissionMode = e.permissionMode ?? "verify-first", this.allowedCommandPrefixes = this.normalizeAllowedCommandPrefixes(e.allowedCommandPrefixes), this.allowedAutoReadPrefixes = this.normalizeAllowedCommandPrefixes(e.allowedAutoReadPrefixes), this.allowedAutoWritePrefixes = this.normalizeAllowedCommandPrefixes(e.allowedAutoWritePrefixes), this.deniedAutoReadPrefixes = this.normalizeAllowedCommandPrefixes(e.deniedAutoReadPrefixes), this.deniedAutoWritePrefixes = this.normalizeAllowedCommandPrefixes(e.deniedAutoWritePrefixes), this.proc && await this.close(), this.emitEvent({ type: "status", status: "starting", message: "Starting codex app-server..." });
47
+ const r = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "codex app-server"], {
48
+ stdio: ["pipe", "pipe", "pipe"],
49
+ windowsHide: !0
50
+ }) : I("codex", ["app-server"], {
51
+ stdio: ["pipe", "pipe", "pipe"]
52
+ });
53
+ this.proc = r, r.on("exit", (c, u) => {
54
+ const l = c !== null ? `codex app-server exited (${c})` : `codex app-server exited (${u ?? "unknown"})`;
55
+ this.emitEvent({ type: "status", status: "closed", message: l }), this.cleanupAfterExit();
56
+ }), r.on("error", (c) => {
57
+ this.emitEvent({ type: "status", status: "error", message: String((c == null ? void 0 : c.message) ?? c) }), this.cleanupAfterExit();
58
+ }), r.stderr.setEncoding("utf8"), r.stderr.on("data", (c) => {
59
+ const u = String(c).trim();
60
+ this.lastStderr = `${this.lastStderr}
61
+ ${u}`.trim().slice(-2e3), u && this.emitEvent({ type: "status", status: "error", message: u });
62
+ }), r.stdout.setEncoding("utf8");
63
+ const s = Dt.createInterface({ input: r.stdout });
64
+ this.rl = s, s.on("line", (c) => this.onLine(c)), await this.sendRequest("initialize", {
65
+ clientInfo: { name: "agent_orchestrator", title: "Agent Orchestrator", version: "0.0.2" }
66
+ // Keep full stream; we can ignore what we don't use.
67
+ }), this.sendNotification("initialized", {});
68
+ const i = await this.sendRequest("thread/start", {
69
+ model: e.model,
70
+ cwd: e.cwd,
71
+ approvalPolicy: e.approvalPolicy ?? (this.permissionMode === "proceed-always" ? "never" : "on-request"),
72
+ sandbox: e.sandbox ?? "workspace-write"
73
+ });
74
+ this.writeCliConfig(e.cwd);
75
+ const o = (a = i == null ? void 0 : i.thread) == null ? void 0 : a.id;
76
+ if (!o || typeof o != "string")
77
+ throw new Error("codex app-server did not return a thread id");
78
+ return this.threadId = o, this.emitEvent({ type: "status", status: "ready", message: "Connected" }), { threadId: o };
79
+ }
80
+ async sendUserMessage(e) {
81
+ var o;
82
+ if (!this.threadId) throw new Error("Not connected (no threadId).");
83
+ const r = e.trim();
84
+ if (!r) return;
85
+ const s = await this.sendRequest("turn/start", {
86
+ threadId: this.threadId,
87
+ input: [{ type: "text", text: r }]
88
+ }), i = (o = s == null ? void 0 : s.turn) == null ? void 0 : o.id;
89
+ i && typeof i == "string" && (this.activeTurnId = i);
90
+ }
91
+ async sendUserMessageWithImages(e, r) {
92
+ var u;
93
+ if (!this.threadId) throw new Error("Not connected (no threadId).");
94
+ const s = e.trim(), i = (r ?? []).filter((l) => typeof l == "string" && l.trim());
95
+ if (!s && i.length === 0) return;
96
+ const o = [];
97
+ s && o.push({ type: "text", text: s });
98
+ for (const l of i) o.push({ type: "localImage", path: l });
99
+ const a = await this.sendRequest("turn/start", {
100
+ threadId: this.threadId,
101
+ input: o
102
+ }), c = (u = a == null ? void 0 : a.turn) == null ? void 0 : u.id;
103
+ c && typeof c == "string" && (this.activeTurnId = c);
104
+ }
105
+ async interruptActiveTurn() {
106
+ !this.threadId || !this.activeTurnId || await this.sendRequest("turn/interrupt", { threadId: this.threadId, turnId: this.activeTurnId });
107
+ }
108
+ async close() {
109
+ if (this.proc) {
110
+ try {
111
+ this.proc.stdin.end();
112
+ } catch {
113
+ }
114
+ try {
115
+ this.proc.kill();
116
+ } catch {
117
+ }
118
+ this.cleanupAfterExit();
119
+ }
120
+ }
121
+ cleanupAfterExit() {
122
+ var r;
123
+ (r = this.rl) == null || r.close(), this.rl = null, this.proc = null;
124
+ const e = this.lastStderr ? ` | stderr: ${this.lastStderr}` : "";
125
+ this.pending.forEach(
126
+ ({ reject: s }) => s(
127
+ new Error(
128
+ `codex app-server closed. Check codex login/PATH/workspace/model selection${e}`
129
+ )
130
+ )
131
+ ), this.pending.clear(), this.threadId = null, this.activeTurnId = null, this.lastStderr = "";
132
+ }
133
+ onLine(e) {
134
+ var i;
135
+ const r = e.trim();
136
+ if (!r) return;
137
+ let s;
138
+ try {
139
+ s = JSON.parse(r);
140
+ } catch {
141
+ this.emitEvent({ type: "status", status: "error", message: `Bad JSON from codex: ${r.slice(0, 200)}` });
142
+ return;
143
+ }
144
+ if (typeof s.id == "number" && ("result" in s || "error" in s)) {
145
+ const o = s.id, a = this.pending.get(o);
146
+ if (!a) return;
147
+ this.pending.delete(o), "error" in s && s.error ? a.reject(new Error(((i = s.error) == null ? void 0 : i.message) ?? "Unknown JSON-RPC error")) : a.resolve(s.result);
148
+ return;
149
+ }
150
+ if (typeof s.id == "number" && typeof s.method == "string") {
151
+ const o = s.id, a = s.method;
152
+ if (this.emitEvent({ type: "rawNotification", method: a, params: s.params }), a.endsWith("/requestApproval"))
153
+ if (this.permissionMode === "proceed-always") {
154
+ const c = this.extractApprovalCommand(s.params), u = this.extractApprovalPath(s.params);
155
+ if (u) {
156
+ const l = a.includes("read") ? "read" : "write";
157
+ this.shouldAutoApprovePath(u, l) ? this.sendResponse(o, { decision: "accept" }) : (this.emitEvent({
158
+ type: "status",
159
+ status: "error",
160
+ message: `Action blocked by allowed command prefixes (${u}). Update workspace prefix allowlist to permit this command.`
161
+ }), this.sendResponse(o, { decision: "decline" }));
162
+ } else if (c)
163
+ if (this.shouldAutoApproveCommand(c))
164
+ this.sendResponse(o, { decision: "accept" });
165
+ else {
166
+ const l = c ? ` (${this.shorten(c, 120)})` : "";
167
+ this.emitEvent({
168
+ type: "status",
169
+ status: "error",
170
+ message: `Action blocked by allowed command prefixes${l}. Update workspace prefix allowlist to permit this command.`
171
+ }), this.sendResponse(o, { decision: "decline" });
172
+ }
173
+ else
174
+ this.sendResponse(o, { decision: "decline" });
175
+ } else
176
+ this.emitEvent({
177
+ type: "status",
178
+ status: "error",
179
+ message: "Action requires approval. Set permissions to Proceed always to allow writes."
180
+ }), this.sendResponse(o, { decision: "decline" });
181
+ else
182
+ this.sendResponse(o, null);
183
+ return;
184
+ }
185
+ if (typeof s.method == "string") {
186
+ const o = s.method, a = s.params;
187
+ this.handleNotification(o, a);
188
+ }
189
+ }
190
+ handleNotification(e, r) {
191
+ var s, i, o, a;
192
+ if (e === "item/agentMessage/delta") {
193
+ const c = typeof (r == null ? void 0 : r.delta) == "string" ? r.delta : typeof (r == null ? void 0 : r.text) == "string" ? r.text : typeof (r == null ? void 0 : r.textDelta) == "string" ? r.textDelta : typeof ((s = r == null ? void 0 : r.delta) == null ? void 0 : s.text) == "string" ? r.delta.text : "";
194
+ c && this.emitEvent({ type: "assistantDelta", delta: c });
195
+ return;
196
+ }
197
+ if (!(e === "item/completed" && ((i = r == null ? void 0 : r.item) == null ? void 0 : i.type) === "agentMessage")) {
198
+ if (e === "turn/completed") {
199
+ this.activeTurnId = null, this.emitEvent({ type: "assistantCompleted" });
200
+ return;
201
+ }
202
+ if (e === "thread/tokenUsage/updated") {
203
+ this.emitEvent({ type: "usageUpdated", usage: r });
204
+ return;
205
+ }
206
+ if (e === "codex/event/token_count") {
207
+ const c = (o = r == null ? void 0 : r.rate_limits) == null ? void 0 : o.primary, u = (a = r == null ? void 0 : r.rate_limits) == null ? void 0 : a.secondary;
208
+ this.emitEvent({
209
+ type: "usageUpdated",
210
+ usage: {
211
+ kind: "rateLimits",
212
+ primary: c ? {
213
+ usedPercent: c.used_percent,
214
+ windowMinutes: c.window_minutes,
215
+ resetsAt: c.resets_at
216
+ } : null,
217
+ secondary: u ? {
218
+ usedPercent: u.used_percent,
219
+ windowMinutes: u.window_minutes,
220
+ resetsAt: u.resets_at
221
+ } : null
222
+ }
223
+ });
224
+ return;
225
+ }
226
+ if (e === "turn/plan/updated") {
227
+ this.emitEvent({ type: "planUpdated", plan: r });
228
+ return;
229
+ }
230
+ this.emitEvent({ type: "rawNotification", method: e, params: r });
231
+ }
232
+ }
233
+ sendNotification(e, r) {
234
+ this.writeMessage({ method: e, params: r });
235
+ }
236
+ sendResponse(e, r) {
237
+ this.writeMessage({ id: e, result: r });
238
+ }
239
+ sendRequest(e, r) {
240
+ const s = this.nextId++, i = { id: s, method: e, params: r };
241
+ return new Promise((o, a) => {
242
+ this.pending.set(s, { resolve: o, reject: a }), this.writeMessage(i);
243
+ });
244
+ }
245
+ writeMessage(e) {
246
+ if (!this.proc) throw new Error("codex app-server process not running");
247
+ this.proc.stdin.write(`${JSON.stringify(e)}
248
+ `);
249
+ }
250
+ writeCliConfig(e) {
251
+ if (this.permissionMode !== "proceed-always") return;
252
+ const r = h.join(e, ".cursor"), s = h.join(r, "cli.json");
253
+ if (this.allowedCommandPrefixes.length === 0 && this.allowedAutoReadPrefixes.length === 0 && this.allowedAutoWritePrefixes.length === 0 && this.deniedAutoReadPrefixes.length === 0 && this.deniedAutoWritePrefixes.length === 0) {
254
+ if (d.existsSync(s))
255
+ try {
256
+ d.unlinkSync(s);
257
+ } catch {
258
+ }
259
+ return;
260
+ }
261
+ const i = /* @__PURE__ */ new Set();
262
+ if (this.allowedCommandPrefixes.length === 0)
263
+ i.add("Shell(npm)"), i.add("Shell(node)"), i.add("Shell(git)");
264
+ else
265
+ for (const p of this.allowedCommandPrefixes) {
266
+ const m = p.trim().split(/\s+/);
267
+ m[0] && i.add(`Shell(${m[0]})`);
268
+ }
269
+ const o = this.allowedAutoReadPrefixes.length > 0 ? this.allowedAutoReadPrefixes.map((p) => `Read(${p}**)`) : ["Read(**)"], a = this.allowedAutoWritePrefixes.length > 0 ? this.allowedAutoWritePrefixes.map((p) => `Write(${p}**)`) : ["Write(**)"], c = this.deniedAutoReadPrefixes.map((p) => `Read(${p}**)`), u = this.deniedAutoWritePrefixes.map((p) => `Write(${p}**)`), l = {
270
+ permissions: {
271
+ allow: [
272
+ ...Array.from(i),
273
+ ...o,
274
+ ...a
275
+ ],
276
+ deny: [
277
+ ...c,
278
+ ...u
279
+ ]
280
+ }
281
+ };
282
+ try {
283
+ d.existsSync(r) || d.mkdirSync(r, { recursive: !0 }), d.writeFileSync(
284
+ s,
285
+ JSON.stringify(l, null, 2),
286
+ "utf8"
287
+ );
288
+ } catch (p) {
289
+ this.emitEvent({
290
+ type: "status",
291
+ status: "error",
292
+ message: `Failed to write permission config: ${String(p)}`
293
+ });
294
+ }
295
+ }
296
+ extractApprovalPath(e) {
297
+ var s;
298
+ const r = this.pickString(e, ["path", "file", "filename"]) ?? this.pickString(e == null ? void 0 : e.path, ["path", "file", "filename"]) ?? this.pickString(e == null ? void 0 : e.request, ["path", "file", "filename"]) ?? this.pickString((s = e == null ? void 0 : e.request) == null ? void 0 : s.path, ["path", "file", "filename"]) ?? this.pickString(e == null ? void 0 : e.action, ["path", "file", "filename"]) ?? this.pickString(e == null ? void 0 : e.toolInput, ["path", "file", "filename"]) ?? this.pickString(e == null ? void 0 : e.input, ["path", "file", "filename"]) ?? null;
299
+ return r || (typeof (e == null ? void 0 : e.path) == "string" && e.path.trim() ? e.path.trim() : null);
300
+ }
301
+ shouldAutoApprovePath(e, r) {
302
+ const s = r === "read" ? this.allowedAutoReadPrefixes : this.allowedAutoWritePrefixes, i = r === "read" ? this.deniedAutoReadPrefixes : this.deniedAutoWritePrefixes;
303
+ if (s.length === 0 && i.length === 0) return !0;
304
+ const o = e.trim().replace(/\\/g, "/");
305
+ for (const a of i)
306
+ if (o.startsWith(a)) return !1;
307
+ if (s.length === 0) return !0;
308
+ for (const a of s)
309
+ if (o.startsWith(a)) return !0;
310
+ return !1;
311
+ }
312
+ normalizeAllowedCommandPrefixes(e) {
313
+ if (!Array.isArray(e)) return [];
314
+ const r = /* @__PURE__ */ new Set(), s = [];
315
+ for (const i of e) {
316
+ if (typeof i != "string") continue;
317
+ const o = i.trim();
318
+ if (!o) continue;
319
+ const a = o.toLowerCase();
320
+ r.has(a) || (r.add(a), s.push(o));
321
+ }
322
+ return s.slice(0, 64);
323
+ }
324
+ shouldAutoApproveCommand(e) {
325
+ if (this.allowedCommandPrefixes.length === 0) return !0;
326
+ if (!e) return !1;
327
+ const r = e.trim().toLowerCase();
328
+ return this.allowedCommandPrefixes.some(
329
+ (s) => r.startsWith(s.toLowerCase())
330
+ );
331
+ }
332
+ extractApprovalCommand(e) {
333
+ var s;
334
+ const r = this.pickString(e, ["command", "cmd"]) ?? this.pickString(e == null ? void 0 : e.command, ["command", "cmd", "raw"]) ?? this.pickString(e == null ? void 0 : e.request, ["command", "cmd"]) ?? this.pickString((s = e == null ? void 0 : e.request) == null ? void 0 : s.command, ["command", "cmd", "raw"]) ?? this.pickString(e == null ? void 0 : e.action, ["command", "cmd"]) ?? this.pickString(e == null ? void 0 : e.toolInput, ["command", "cmd"]) ?? this.pickString(e == null ? void 0 : e.input, ["command", "cmd"]) ?? null;
335
+ return r || (typeof (e == null ? void 0 : e.command) == "string" && e.command.trim() ? e.command.trim() : typeof (e == null ? void 0 : e.cmd) == "string" && e.cmd.trim() ? e.cmd.trim() : null);
336
+ }
337
+ pickString(e, r) {
338
+ if (!e || typeof e != "object") return null;
339
+ for (const s of r) {
340
+ const i = e == null ? void 0 : e[s];
341
+ if (typeof i == "string" && i.trim()) return i.trim();
342
+ }
343
+ return null;
344
+ }
345
+ shorten(e, r) {
346
+ return e.length <= r ? e : `${e.slice(0, r)}...`;
347
+ }
348
+ }
349
+ const Be = 100 * 1024;
350
+ function Y(n, t) {
351
+ const e = /(?:^|\s)@([\w./-]+(?:\.[\w]+))/g, r = /* @__PURE__ */ new Set(), s = [];
352
+ let i;
353
+ for (; (i = e.exec(n)) !== null; ) {
354
+ const o = i[1];
355
+ if (r.has(o)) continue;
356
+ r.add(o);
357
+ const a = h.isAbsolute(o) ? o : h.resolve(t, o);
358
+ try {
359
+ const c = d.statSync(a);
360
+ if (!c.isFile()) continue;
361
+ if (c.size > Be) {
362
+ s.push(`--- ${o} (truncated, ${Math.round(c.size / 1024)} KB) ---
363
+ ${d.readFileSync(a, "utf8").slice(0, Be)}
364
+ ...`);
365
+ continue;
366
+ }
367
+ const u = d.readFileSync(a, "utf8");
368
+ s.push(`--- ${o} ---
369
+ ${u}`);
370
+ } catch {
371
+ }
372
+ }
373
+ return s.length > 0 ? `
374
+
375
+ Referenced file contents:
376
+
377
+ ` + s.join(`
378
+
379
+ `) : "";
380
+ }
381
+ function ze() {
382
+ const n = { ...process.env };
383
+ if (process.platform === "win32") {
384
+ const t = process.env.APPDATA ? h.join(process.env.APPDATA, "npm") : "";
385
+ t && n.PATH && !n.PATH.includes(t) && (n.PATH = `${t}${h.delimiter}${n.PATH}`);
386
+ }
387
+ return n.GEMINI_SANDBOX = "false", n;
388
+ }
389
+ const fe = class fe extends ne {
390
+ constructor() {
391
+ super(...arguments);
392
+ P(this, "model", "gemini-2.0-flash");
393
+ P(this, "cwd", process.cwd());
394
+ P(this, "history", []);
395
+ P(this, "activeProc", null);
396
+ }
397
+ normalizeModelId(e) {
398
+ return {
399
+ "gemini-1.5-pro": "pro",
400
+ "gemini-1.5-flash": "flash",
401
+ "gemini-2.0-flash": "flash",
402
+ "gemini-3-pro": "pro",
403
+ "gemini-pro": "flash",
404
+ "gemini-1.0-pro": "flash"
405
+ }[e] ?? e;
406
+ }
407
+ isModelNotFoundError(e) {
408
+ const r = e.toLowerCase();
409
+ return r.includes("modelnotfound") || r.includes("requested entity was not found") || r.includes("not found") && r.includes("model");
410
+ }
411
+ /** Map Gemini CLI exit codes to user-friendly messages (per Gemini CLI docs) */
412
+ formatGeminiExitError(e, r, s) {
413
+ const i = s.trim();
414
+ if (i) {
415
+ const u = i.split(`
416
+ `).map((l) => l.trim()).filter((l) => l && !fe.STDERR_NOISE.test(l))[0] ?? i.split(`
417
+ `).find((l) => l.trim()) ?? i.split(`
418
+ `)[0];
419
+ return u.length > 300 ? u.slice(0, 300) + "..." : u;
420
+ }
421
+ if (r) return `Gemini CLI was terminated (${r})`;
422
+ const a = {
423
+ 1: "Gemini CLI failed. Model may be at capacity — try again in a moment or switch to a different model.",
424
+ 41: "Authentication failed. Run `gemini` in a terminal and log in with Google.",
425
+ 42: "Invalid or missing input. Check your prompt or model selection.",
426
+ 44: "Sandbox error. Try without sandbox or check your Docker/Podman setup.",
427
+ 52: "Invalid config. Check your Gemini CLI settings.json.",
428
+ 53: "Session turn limit reached. Start a new session."
429
+ }[e ?? 0];
430
+ return a || `Gemini CLI exited with code ${e ?? "unknown"}`;
431
+ }
432
+ emitEvent(e) {
433
+ this.emit("event", e);
434
+ }
435
+ async connect(e) {
436
+ var i;
437
+ const r = e.model || "gemini-2.0-flash", s = this.normalizeModelId(r);
438
+ return this.model = s, this.cwd = e.cwd || process.cwd(), s !== r && this.emitEvent({
439
+ type: "status",
440
+ status: "starting",
441
+ message: `Model ${r} mapped to ${s} for Gemini CLI.`
442
+ }), this.emitEvent({ type: "status", status: "starting", message: "Connecting to Gemini CLI..." }), await this.assertGeminiCliAvailable(), this.history = (((i = e.initialHistory) == null ? void 0 : i.length) ?? 0) > 0 ? e.initialHistory.slice(-24) : [], this.emitEvent({ type: "status", status: "ready", message: "Connected" }), { threadId: "gemini" };
443
+ }
444
+ async sendUserMessageWithImages(e, r) {
445
+ const s = e.trim(), i = (r ?? []).filter((p) => typeof p == "string" && p.trim());
446
+ if (!s && i.length === 0) return;
447
+ const o = i.length > 0 ? `
448
+
449
+ ` + i.map((p) => `@${p}`).join(`
450
+ `) : "", a = s ? s + o : i.map((p) => `@${p}`).join(`
451
+ `), c = Y(a, this.cwd), u = a + c;
452
+ this.history.push({ role: "user", text: u });
453
+ const l = this.buildGeminiPrompt(u);
454
+ await this.runTurn(l);
455
+ }
456
+ async sendUserMessage(e) {
457
+ const r = e.trim();
458
+ if (!r) return;
459
+ const s = Y(r, this.cwd), i = r + s;
460
+ this.history.push({ role: "user", text: i });
461
+ const o = this.buildGeminiPrompt(i);
462
+ await this.runTurn(o);
463
+ }
464
+ async runTurn(e) {
465
+ const r = (s) => new Promise((i, o) => {
466
+ const a = ["-m", s, "--yolo", "--output-format", "stream-json"], c = {
467
+ cwd: this.cwd,
468
+ stdio: ["pipe", "pipe", "pipe"],
469
+ env: ze()
470
+ }, u = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "gemini", ...a], {
471
+ ...c,
472
+ windowsHide: !0
473
+ }) : I("gemini", a, c);
474
+ this.activeProc = u, u.stdin.write(e), u.stdin.end(), u.stdout.setEncoding("utf8"), u.stderr.setEncoding("utf8");
475
+ let l = "", p = "", m = !1, g = "";
476
+ const x = /quota|retrying after|rate.?limit|capacity.*exhausted|reset after|YOLO mode|Loaded cached credentials|All tool calls will be/i, E = /status 429|Retrying with backoff|Attempt \d+ failed(?!.*Max attempts)|No capacity available/i;
477
+ u.stdout.on("data", (w) => {
478
+ if (!w) return;
479
+ g += w;
480
+ const b = g.split(`
481
+ `);
482
+ g = b.pop() ?? "";
483
+ for (const y of b) {
484
+ const A = y.trim();
485
+ if (!A) continue;
486
+ let v;
487
+ try {
488
+ v = JSON.parse(A);
489
+ } catch {
490
+ if (x.test(A)) continue;
491
+ const S = A.length > 300 ? A.slice(0, 300) + "..." : A;
492
+ /Max attempts reached/i.test(A) ? this.emitEvent({ type: "status", status: "error", message: S }) : E.test(A) ? this.emitEvent({ type: "thinking", message: "Rate limited — CLI is retrying..." }) : this.emitEvent({ type: "thinking", message: S });
493
+ continue;
494
+ }
495
+ switch (v.type) {
496
+ case "message":
497
+ if ((v.role === "assistant" || v.role === "model") && typeof v.content == "string" && (this.emitEvent({ type: "assistantDelta", delta: v.content }), l += v.content, v.delta)) {
498
+ const S = v.content.trim();
499
+ S.length > 0 && S.length < 200 && this.emitEvent({ type: "thinking", message: S });
500
+ }
501
+ break;
502
+ case "tool_use":
503
+ case "toolUse":
504
+ case "functionCall": {
505
+ const S = v.tool_name ?? v.name ?? v.toolName ?? "tool", C = v.parameters ?? v.args ?? v.input ?? {}, R = C.file_path ?? C.command ?? C.dir_path ?? C.pattern ?? C.query ?? C.path ?? C.url ?? "", Ue = `Using ${S}${R ? `: ${R}` : ""}`;
506
+ this.emitEvent({ type: "thinking", message: Ue });
507
+ break;
508
+ }
509
+ case "tool_result":
510
+ case "toolResult":
511
+ case "functionResponse": {
512
+ const S = v.status === "success" ? "done" : v.status ?? "done", C = typeof v.output == "string" ? v.output : typeof v.result == "string" ? v.result : typeof v.response == "string" ? v.response : "", R = C.length > 160 ? C.slice(0, 160) + "..." : C;
513
+ this.emitEvent({ type: "thinking", message: R || S });
514
+ break;
515
+ }
516
+ case "thinking":
517
+ case "thought": {
518
+ const S = typeof v.content == "string" ? v.content : typeof v.message == "string" ? v.message : typeof v.text == "string" ? v.text : "";
519
+ if (S) {
520
+ const C = S.length > 200 ? S.slice(0, 200) + "..." : S;
521
+ this.emitEvent({ type: "thinking", message: C });
522
+ }
523
+ break;
524
+ }
525
+ case "result":
526
+ v.stats && this.emitEvent({ type: "usageUpdated", usage: v.stats });
527
+ break;
528
+ case "error": {
529
+ const S = v.message ?? v.content ?? "Unknown error", C = typeof S == "string" ? S.length > 300 ? S.slice(0, 300) + "..." : S : "Gemini error";
530
+ if (x.test(C)) break;
531
+ /status 429|Retrying with backoff|Attempt \d+ failed/i.test(C) ? this.emitEvent({ type: "thinking", message: "Rate limited — CLI is retrying..." }) : this.emitEvent({ type: "status", status: "error", message: C });
532
+ break;
533
+ }
534
+ case "init":
535
+ break;
536
+ default: {
537
+ const S = v.message ?? v.content ?? v.text ?? "";
538
+ if (typeof S == "string" && S.trim()) {
539
+ const C = S.length > 200 ? S.slice(0, 200) + "..." : S;
540
+ this.emitEvent({ type: "thinking", message: `[${v.type}] ${C}` });
541
+ }
542
+ }
543
+ }
544
+ }
545
+ }), u.stderr.on("data", (w) => {
546
+ p += w;
547
+ const b = w.trim();
548
+ if (b && !x.test(b)) {
549
+ const y = b.length > 200 ? b.slice(0, 200) + "..." : b;
550
+ this.emitEvent({ type: "thinking", message: y });
551
+ }
552
+ }), u.on("error", (w) => {
553
+ m || (m = !0, o(w));
554
+ }), u.on("exit", (w, b) => {
555
+ if (this.activeProc = null, g.trim())
556
+ try {
557
+ const y = JSON.parse(g.trim());
558
+ y.type === "message" && y.role === "assistant" && typeof y.content == "string" ? (this.emitEvent({ type: "assistantDelta", delta: y.content }), l += y.content) : y.type === "result" && y.stats && this.emitEvent({ type: "usageUpdated", usage: y.stats });
559
+ } catch {
560
+ }
561
+ m || (m = !0, w === 0 ? i() : o(new Error(this.formatGeminiExitError(w, b, p)))), w === 0 ? (this.history.push({ role: "assistant", text: l.trim() || l }), this.emitEvent({ type: "assistantCompleted" })) : (this.emitEvent({ type: "status", status: "error", message: this.formatGeminiExitError(w, b, p) }), this.emitEvent({ type: "assistantCompleted" }));
562
+ });
563
+ });
564
+ try {
565
+ await r(this.model);
566
+ } catch (s) {
567
+ const i = s instanceof Error ? s.message : String(s);
568
+ if (this.isModelNotFoundError(i) && this.model !== "gemini-2.0-flash")
569
+ try {
570
+ this.emitEvent({
571
+ type: "status",
572
+ status: "starting",
573
+ message: `Model "${this.model}" not found. Retrying with gemini-2.0-flash...`
574
+ }), this.model = "gemini-2.0-flash", await r(this.model);
575
+ } catch (o) {
576
+ const a = o instanceof Error ? o.message : String(o);
577
+ this.emitEvent({ type: "status", status: "error", message: a }), this.emitEvent({ type: "assistantCompleted" });
578
+ }
579
+ else
580
+ this.emitEvent({ type: "status", status: "error", message: i }), this.emitEvent({ type: "assistantCompleted" });
581
+ }
582
+ }
583
+ async interruptActiveTurn() {
584
+ if (this.activeProc)
585
+ try {
586
+ this.activeProc.kill();
587
+ } catch {
588
+ } finally {
589
+ this.activeProc = null;
590
+ }
591
+ }
592
+ async close() {
593
+ await this.interruptActiveTurn(), this.history = [];
594
+ }
595
+ buildGeminiPrompt(e) {
596
+ const r = [...this.history].reverse().find((i) => i.role === "assistant");
597
+ return `${r ? `
598
+
599
+ For context, your previous response was:
600
+ ${r.text.slice(0, 1200)}
601
+
602
+ ` : ""}${e}`;
603
+ }
604
+ async assertGeminiCliAvailable() {
605
+ await new Promise((e, r) => {
606
+ const s = {
607
+ cwd: this.cwd,
608
+ stdio: ["ignore", "pipe", "pipe"],
609
+ env: ze()
610
+ }, i = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "gemini", "--version"], {
611
+ ...s,
612
+ windowsHide: !0
613
+ }) : I("gemini", ["--version"], s);
614
+ let o = "";
615
+ i.stderr.setEncoding("utf8"), i.stderr.on("data", (a) => {
616
+ o += a;
617
+ }), i.on("error", (a) => r(a)), i.on("exit", (a) => {
618
+ a === 0 ? e() : r(new Error(o.trim() || "Gemini CLI not available. Install and login with `gemini`."));
619
+ });
620
+ }).catch((e) => {
621
+ const r = e instanceof Error ? e.message : "Gemini CLI not available. Install and login with `gemini` first.";
622
+ throw new Error(
623
+ `${r}
624
+ Use terminal: \`gemini\` and choose "Login with Google" (subscription).`
625
+ );
626
+ });
627
+ }
628
+ };
629
+ P(fe, "STDERR_NOISE", /YOLO mode|Loaded cached credentials|All tool calls will be|^\s*at /i);
630
+ let Pe = fe;
631
+ const Nt = /* @__PURE__ */ new Set([
632
+ ".git",
633
+ ".svn",
634
+ ".hg",
635
+ ".DS_Store",
636
+ "node_modules",
637
+ "dist",
638
+ "dist-electron",
639
+ "build",
640
+ "release",
641
+ "coverage",
642
+ ".next",
643
+ ".nuxt",
644
+ ".output",
645
+ ".barnaby",
646
+ "target",
647
+ "vendor",
648
+ "bower_components",
649
+ "__pycache__"
650
+ ]), Wt = 3, jt = 150;
651
+ function ce(n) {
652
+ let t = `Current Workspace Structure:
653
+ `, e = 0, r = !1;
654
+ function s(i, o, a) {
655
+ if (!(o > Wt || r))
656
+ try {
657
+ const c = d.readdirSync(i, { withFileTypes: !0 });
658
+ c.sort((l, p) => l.isDirectory() !== p.isDirectory() ? l.isDirectory() ? -1 : 1 : l.name.localeCompare(p.name));
659
+ const u = c.filter((l) => !(l.name.startsWith(".") || l.isDirectory() && Nt.has(l.name)));
660
+ for (let l = 0; l < u.length; l++) {
661
+ const p = u[l];
662
+ if (e++, e > jt) {
663
+ r || (r = !0, t += `${a}- ... (truncated)
664
+ `);
665
+ return;
666
+ }
667
+ t += `${a}- ${p.name}${p.isDirectory() ? "/" : ""}
668
+ `, p.isDirectory() && s(h.join(i, p.name), o + 1, `${a} `);
669
+ }
670
+ } catch {
671
+ }
672
+ }
673
+ return s(n, 0, ""), r && (t += `
674
+ (Note: File tree truncated for brevity)`), t;
675
+ }
676
+ function qe() {
677
+ const n = { ...process.env };
678
+ if (process.platform === "win32") {
679
+ const t = process.env.APPDATA ? h.join(process.env.APPDATA, "npm") : "";
680
+ t && n.PATH && !n.PATH.includes(t) && (n.PATH = `${t}${h.delimiter}${n.PATH}`);
681
+ }
682
+ return n;
683
+ }
684
+ class Ht extends ne {
685
+ constructor() {
686
+ super(...arguments);
687
+ P(this, "model", "sonnet");
688
+ P(this, "cwd", process.cwd());
689
+ P(this, "permissionMode", "verify-first");
690
+ P(this, "history", []);
691
+ P(this, "activeProc", null);
692
+ }
693
+ normalizeModelId(e) {
694
+ const r = e.trim().toLowerCase(), s = {
695
+ "claude-sonnet-4-5-20250929": "sonnet",
696
+ "claude-opus-4-1-20250805": "opus",
697
+ "claude-haiku-3-5-20241022": "haiku"
698
+ };
699
+ return r ? s[r] ?? r : "sonnet";
700
+ }
701
+ isModelNotFoundError(e) {
702
+ const r = e.toLowerCase();
703
+ return r.includes("model") && (r.includes("not found") || r.includes("unknown") || r.includes("invalid"));
704
+ }
705
+ formatClaudeExitError(e, r, s) {
706
+ const i = s.trim();
707
+ return i || (r ? `Claude CLI was terminated (${r})` : `Claude CLI exited with code ${e ?? "unknown"}`);
708
+ }
709
+ emitEvent(e) {
710
+ this.emit("event", e);
711
+ }
712
+ async connect(e) {
713
+ var i;
714
+ const r = e.model || "sonnet", s = this.normalizeModelId(r);
715
+ return this.model = s, this.cwd = e.cwd || process.cwd(), this.permissionMode = e.permissionMode ?? "verify-first", s !== r && this.emitEvent({
716
+ type: "status",
717
+ status: "starting",
718
+ message: `Model ${r} normalized to ${s}.`
719
+ }), this.emitEvent({ type: "status", status: "starting", message: "Connecting to Claude CLI..." }), await this.assertClaudeCliAvailable(), this.history = (((i = e.initialHistory) == null ? void 0 : i.length) ?? 0) > 0 ? e.initialHistory.slice(-24) : [], this.emitEvent({ type: "status", status: "ready", message: "Connected" }), { threadId: "claude" };
720
+ }
721
+ async sendUserMessage(e) {
722
+ const r = e.trim();
723
+ if (!r) return;
724
+ const s = Y(r, this.cwd);
725
+ this.history.push({ role: "user", text: r + s });
726
+ const o = `You are a coding assistant running inside Barnaby. I have provided the workspace structure below. I will provide file contents when you ask or when I reference them (e.g. @filename).
727
+
728
+ ${ce(this.cwd)}`, a = this.buildPrompt(), c = this.permissionMode === "proceed-always" ? "acceptEdits" : "default", u = async (l) => {
729
+ let p = "";
730
+ return await new Promise((m, g) => {
731
+ const x = [
732
+ "--print",
733
+ "--output-format",
734
+ "text",
735
+ "--model",
736
+ l,
737
+ "--permission-mode",
738
+ c,
739
+ "--append-system-prompt",
740
+ o
741
+ ], E = {
742
+ cwd: this.cwd,
743
+ stdio: ["pipe", "pipe", "pipe"],
744
+ env: qe()
745
+ }, w = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "claude", ...x], {
746
+ ...E,
747
+ windowsHide: !0
748
+ }) : I("claude", x, E);
749
+ this.activeProc = w, w.stdin.write(a), w.stdin.end(), w.stdout.setEncoding("utf8"), w.stderr.setEncoding("utf8");
750
+ let b = "";
751
+ w.stdout.on("data", (y) => {
752
+ y && (p += y, this.emitEvent({ type: "assistantDelta", delta: y }));
753
+ }), w.stderr.on("data", (y) => {
754
+ b += y;
755
+ }), w.on("error", (y) => g(y)), w.on("exit", (y, A) => {
756
+ this.activeProc = null, y === 0 ? m(p) : g(new Error(this.formatClaudeExitError(y, A, b)));
757
+ });
758
+ }), p;
759
+ };
760
+ try {
761
+ let l = await u(this.model);
762
+ l.trim(), this.history.push({ role: "assistant", text: l.trim() || l }), this.emitEvent({ type: "assistantCompleted" });
763
+ } catch (l) {
764
+ const p = l instanceof Error ? l.message : String(l);
765
+ if (this.isModelNotFoundError(p) && this.model !== "sonnet")
766
+ try {
767
+ this.emitEvent({
768
+ type: "status",
769
+ status: "starting",
770
+ message: `Model "${this.model}" not found. Retrying with sonnet...`
771
+ }), this.model = "sonnet";
772
+ const m = await u(this.model);
773
+ this.history.push({ role: "assistant", text: m.trim() || m }), this.emitEvent({ type: "status", status: "ready", message: `Connected (using ${this.model})` }), this.emitEvent({ type: "assistantCompleted" });
774
+ return;
775
+ } catch (m) {
776
+ const g = m instanceof Error ? m.message : String(m);
777
+ this.emitEvent({ type: "status", status: "error", message: g }), this.emitEvent({ type: "assistantCompleted" });
778
+ return;
779
+ }
780
+ this.emitEvent({ type: "status", status: "error", message: p }), this.emitEvent({ type: "assistantCompleted" });
781
+ }
782
+ }
783
+ async interruptActiveTurn() {
784
+ if (this.activeProc)
785
+ try {
786
+ this.activeProc.kill();
787
+ } catch {
788
+ } finally {
789
+ this.activeProc = null;
790
+ }
791
+ }
792
+ async close() {
793
+ await this.interruptActiveTurn(), this.history = [];
794
+ }
795
+ buildPrompt() {
796
+ return [this.history.slice(-12).map((s) => `${s.role === "user" ? "User" : "Assistant"}:
797
+ ${s.text}`).join(`
798
+
799
+ `), "Assistant:"].filter(Boolean).join(`
800
+
801
+ `);
802
+ }
803
+ async assertClaudeCliAvailable() {
804
+ await new Promise((e, r) => {
805
+ const s = {
806
+ cwd: this.cwd,
807
+ stdio: ["ignore", "pipe", "pipe"],
808
+ env: qe()
809
+ }, i = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "claude", "--version"], {
810
+ ...s,
811
+ windowsHide: !0
812
+ }) : I("claude", ["--version"], s);
813
+ let o = "";
814
+ i.stderr.setEncoding("utf8"), i.stderr.on("data", (a) => {
815
+ o += a;
816
+ }), i.on("error", (a) => r(a)), i.on("exit", (a) => {
817
+ a === 0 ? e() : r(new Error(o.trim() || "Claude CLI not available. Install and login with `claude`."));
818
+ });
819
+ }).catch((e) => {
820
+ const r = e instanceof Error ? e.message : "Claude CLI not available. Install and login with `claude` first.";
821
+ throw new Error(`${r}
822
+ Use terminal: \`claude\` and complete login, then retry.`);
823
+ });
824
+ }
825
+ }
826
+ const Ut = 12e4;
827
+ class Bt extends ne {
828
+ constructor() {
829
+ super(...arguments);
830
+ P(this, "model", "openrouter/auto");
831
+ P(this, "cwd", process.cwd());
832
+ P(this, "apiKey", "");
833
+ P(this, "baseUrl", "https://openrouter.ai/api/v1");
834
+ P(this, "history", []);
835
+ P(this, "activeController", null);
836
+ }
837
+ emitEvent(e) {
838
+ this.emit("event", e);
839
+ }
840
+ async connect(e) {
841
+ var r;
842
+ if (this.model = (e.model || "openrouter/auto").trim(), this.cwd = e.cwd || process.cwd(), this.apiKey = (e.apiKey || "").trim(), this.baseUrl = (e.baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, ""), this.history = (((r = e.initialHistory) == null ? void 0 : r.length) ?? 0) > 0 ? e.initialHistory.slice(-24) : [], !this.apiKey) throw new Error("OpenRouter API key is missing. Configure it in Settings -> Connectivity.");
843
+ return this.emitEvent({ type: "status", status: "ready", message: "Connected" }), { threadId: "openrouter" };
844
+ }
845
+ async sendUserMessage(e) {
846
+ var m, g, x;
847
+ const r = e.trim();
848
+ if (!r) return;
849
+ const s = Y(r, this.cwd), i = r + s;
850
+ this.history.push({ role: "user", text: i });
851
+ const o = ce(this.cwd), a = `You are a coding assistant running inside Barnaby.
852
+ Workspace root: ${this.cwd}
853
+
854
+ ${o}`, c = this.history.slice(-12), u = [
855
+ { role: "system", content: a },
856
+ ...c.map((E) => ({ role: E.role, content: E.text }))
857
+ ], l = new AbortController();
858
+ this.activeController = l;
859
+ const p = setTimeout(() => l.abort("timeout"), Ut);
860
+ this.emitEvent({ type: "status", status: "starting", message: "Sending request to OpenRouter..." });
861
+ try {
862
+ const E = await fetch(`${this.baseUrl}/chat/completions`, {
863
+ method: "POST",
864
+ headers: {
865
+ "Content-Type": "application/json",
866
+ Authorization: `Bearer ${this.apiKey}`,
867
+ "HTTP-Referer": "https://barnaby.build",
868
+ "X-Title": "Barnaby"
869
+ },
870
+ body: JSON.stringify({
871
+ model: this.model,
872
+ messages: u,
873
+ temperature: 0.2,
874
+ stream: !1
875
+ }),
876
+ signal: l.signal
877
+ });
878
+ if (!E.ok) {
879
+ const A = await E.text().catch(() => ""), v = A ? ` ${A.slice(0, 400)}` : "";
880
+ throw new Error(`OpenRouter request failed (${E.status}).${v}`);
881
+ }
882
+ const w = await E.json(), b = (x = (g = (m = w == null ? void 0 : w.choices) == null ? void 0 : m[0]) == null ? void 0 : g.message) == null ? void 0 : x.content, y = Array.isArray(b) ? b.map((A) => typeof (A == null ? void 0 : A.text) == "string" ? A.text : "").join("") : typeof b == "string" ? b : "";
883
+ this.history.push({ role: "assistant", text: y }), w != null && w.usage && this.emitEvent({ type: "usageUpdated", usage: w.usage }), this.emitEvent({ type: "assistantDelta", delta: y }), this.emitEvent({ type: "assistantCompleted" }), this.emitEvent({ type: "status", status: "ready", message: "Connected" });
884
+ } catch (E) {
885
+ const w = E instanceof Error ? E.name === "AbortError" ? "OpenRouter request timed out." : E.message : String(E);
886
+ this.emitEvent({ type: "status", status: "error", message: w }), this.emitEvent({ type: "assistantCompleted" });
887
+ } finally {
888
+ clearTimeout(p), this.activeController === l && (this.activeController = null);
889
+ }
890
+ }
891
+ async interruptActiveTurn() {
892
+ if (this.activeController)
893
+ try {
894
+ this.activeController.abort("interrupted");
895
+ } catch {
896
+ } finally {
897
+ this.activeController = null;
898
+ }
899
+ }
900
+ async close() {
901
+ await this.interruptActiveTurn(), this.history = [];
902
+ }
903
+ }
904
+ const zt = 12e4, qt = 8, Ke = 14e3, be = 35e4, Je = 60, Ge = 1200, Kt = 4, Jt = 12e4, Gt = 3e5;
905
+ class Vt extends ne {
906
+ constructor() {
907
+ super(...arguments);
908
+ P(this, "model", "gpt-4o");
909
+ P(this, "cwd", process.cwd());
910
+ P(this, "apiKey", "");
911
+ P(this, "baseUrl", "https://api.openai.com/v1");
912
+ P(this, "permissionMode", "verify-first");
913
+ P(this, "sandbox", "workspace-write");
914
+ P(this, "allowedCommandPrefixes", []);
915
+ P(this, "history", []);
916
+ P(this, "activeController", null);
917
+ }
918
+ emitEvent(e) {
919
+ this.emit("event", e);
920
+ }
921
+ async connect(e) {
922
+ var r;
923
+ if (this.model = (e.model || "gpt-4o").trim(), this.cwd = e.cwd || process.cwd(), this.apiKey = (e.apiKey || "").trim(), this.baseUrl = (e.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, ""), this.permissionMode = e.permissionMode === "proceed-always" ? "proceed-always" : "verify-first", this.sandbox = e.sandbox === "read-only" ? "read-only" : "workspace-write", this.allowedCommandPrefixes = Array.isArray(e.allowedCommandPrefixes) ? e.allowedCommandPrefixes.filter((s) => typeof s == "string").map((s) => s.trim()).filter(Boolean) : [], this.history = (((r = e.initialHistory) == null ? void 0 : r.length) ?? 0) > 0 ? e.initialHistory.slice(-24) : [], !this.apiKey) throw new Error("OpenAI API key is missing. Configure it in Settings -> Connectivity.");
924
+ return this.emitEvent({ type: "status", status: "ready", message: "Connected" }), { threadId: "openai" };
925
+ }
926
+ async sendUserMessage(e) {
927
+ const r = e.trim();
928
+ if (!r) return;
929
+ const s = Y(r, this.cwd), i = r + s;
930
+ await this.sendUserMessageInternal(i, i);
931
+ }
932
+ async sendUserMessageWithImages(e, r) {
933
+ const s = e.trim(), i = (r ?? []).filter((l) => typeof l == "string" && l.trim().length > 0).slice(0, Kt);
934
+ if (!s && i.length === 0) return;
935
+ const o = Y(s, this.cwd), a = `${s}${o}`.trim(), c = [];
936
+ a && c.push({ type: "text", text: a });
937
+ for (const l of i) {
938
+ const p = this.pathToDataUrl(l);
939
+ p && c.push({ type: "image_url", image_url: { url: p } });
940
+ }
941
+ if (c.length === 0) return;
942
+ const u = i.length > 0 ? `
943
+
944
+ Attached images:
945
+ ${i.map((l) => `- ${h.basename(l)}`).join(`
946
+ `)}` : "";
947
+ await this.sendUserMessageInternal(a + u, c);
948
+ }
949
+ async sendUserMessageInternal(e, r) {
950
+ var l;
951
+ this.history.push({ role: "user", text: e });
952
+ const s = ce(this.cwd), i = `You are Barnaby's OpenAI API coding agent.
953
+ Workspace root: ${this.cwd}
954
+ Permission mode: ${this.permissionMode}
955
+ Sandbox mode: ${this.sandbox}
956
+
957
+ ${s}
958
+
959
+ Rules:
960
+ - If the user asks for code/config changes, implement them directly using tools in this turn whenever possible.
961
+ - Prefer action over deferral: locate files, apply edits, and report what changed.
962
+ - Use tools for repository contents, symbols, behavior, implementation details, and file edits.
963
+ - If the user asks to run build/test/dev commands, use run_shell_command instead of returning a checklist.
964
+ - Never invent file names, symbols, or behavior. If not verified via tool output, say so.
965
+ - Cite concrete evidence in your answer (file path and line numbers when available).
966
+ - Keep working until you have either completed the requested change or can clearly explain the precise blocker.`, o = this.history.slice(-12), a = [
967
+ { role: "system", content: i },
968
+ ...o.map((p) => ({ role: p.role, content: p.text }))
969
+ ];
970
+ a.length > 0 && ((l = a[a.length - 1]) == null ? void 0 : l.role) === "user" && (a[a.length - 1] = { role: "user", content: r });
971
+ const c = new AbortController();
972
+ this.activeController = c;
973
+ const u = setTimeout(() => c.abort("timeout"), zt);
974
+ this.emitEvent({ type: "status", status: "starting", message: "Running OpenAI agent turn..." });
975
+ try {
976
+ const p = await this.runAgentLoop(a, c);
977
+ this.history.push({ role: "assistant", text: p }), this.emitEvent({ type: "assistantDelta", delta: p }), this.emitEvent({ type: "assistantCompleted" }), this.emitEvent({ type: "status", status: "ready", message: "Connected" });
978
+ } catch (p) {
979
+ const m = c.signal.aborted, g = String(c.signal.reason ?? ""), x = p instanceof Error ? m && g === "interrupted" ? "OpenAI request interrupted." : m && g === "timeout" ? "OpenAI request timed out." : p.message : String(p);
980
+ this.emitEvent({ type: "status", status: "error", message: x }), this.emitEvent({ type: "assistantCompleted" });
981
+ } finally {
982
+ clearTimeout(u), this.activeController === c && (this.activeController = null);
983
+ }
984
+ }
985
+ async runAgentLoop(e, r) {
986
+ var o, a, c, u, l;
987
+ const s = [...e];
988
+ let i = "";
989
+ for (let p = 0; p < qt; p++) {
990
+ const m = await this.fetchCompletionWithRetries(s, r);
991
+ m != null && m.usage && this.emitEvent({ type: "usageUpdated", usage: m.usage });
992
+ const g = (a = (o = m == null ? void 0 : m.choices) == null ? void 0 : o[0]) == null ? void 0 : a.message, x = this.extractAssistantText(g == null ? void 0 : g.content);
993
+ x && (i = x);
994
+ const E = Array.isArray(g == null ? void 0 : g.tool_calls) ? g.tool_calls : [];
995
+ if (E.length === 0)
996
+ return x || "No response content returned by OpenAI.";
997
+ const w = E.map((y, A) => ({
998
+ ...y,
999
+ id: y.id || `tool_${p}_${A}`,
1000
+ type: y.type || "function"
1001
+ })), b = {
1002
+ role: "assistant",
1003
+ content: x || null,
1004
+ tool_calls: w
1005
+ };
1006
+ s.push(b);
1007
+ for (let y = 0; y < w.length; y++) {
1008
+ const A = w[y], v = A.id, S = ((c = A.function) == null ? void 0 : c.name) || "unknown_tool", C = this.safeToolArgsPreview((u = A.function) == null ? void 0 : u.arguments);
1009
+ this.emitEvent({
1010
+ type: "thinking",
1011
+ message: C ? `Using ${S}(${C})` : `Using ${S}`
1012
+ });
1013
+ const R = await this.runTool(S, (l = A.function) == null ? void 0 : l.arguments);
1014
+ s.push({
1015
+ role: "tool",
1016
+ tool_call_id: v,
1017
+ content: R
1018
+ });
1019
+ }
1020
+ }
1021
+ return i || "Stopped after too many tool steps without a final answer.";
1022
+ }
1023
+ async fetchCompletionWithRetries(e, r) {
1024
+ for (let i = 0; i <= 3; i++) {
1025
+ const o = await fetch(`${this.baseUrl}/chat/completions`, {
1026
+ method: "POST",
1027
+ headers: {
1028
+ "Content-Type": "application/json",
1029
+ Authorization: `Bearer ${this.apiKey}`
1030
+ },
1031
+ body: JSON.stringify({
1032
+ model: this.model,
1033
+ messages: e,
1034
+ tools: this.agentTools(),
1035
+ tool_choice: "auto",
1036
+ temperature: 0.1,
1037
+ stream: !1
1038
+ }),
1039
+ signal: r.signal
1040
+ });
1041
+ if (o.ok)
1042
+ return o.json();
1043
+ const a = o.headers.get("retry-after"), c = await o.text().catch(() => ""), u = this.getRetryDelayMs(o.status, a, c, i);
1044
+ if (u > 0 && i < 3) {
1045
+ const m = (u / 1e3).toFixed(1).replace(/\.0$/, "");
1046
+ this.emitEvent({
1047
+ type: "thinking",
1048
+ message: `OpenAI rate limited — retrying in ${m}s...`
1049
+ }), await this.sleepWithAbort(u, r.signal);
1050
+ continue;
1051
+ }
1052
+ const p = c ? ` ${c.slice(0, 500)}` : "";
1053
+ throw new Error(`OpenAI request failed (${o.status}).${p}`);
1054
+ }
1055
+ throw new Error("OpenAI request failed after retries.");
1056
+ }
1057
+ getRetryDelayMs(e, r, s, i) {
1058
+ if (e !== 429) return 0;
1059
+ if (r) {
1060
+ const a = Number(r);
1061
+ if (Number.isFinite(a) && a > 0)
1062
+ return Math.max(250, Math.round(a * 1e3));
1063
+ const c = Date.parse(r);
1064
+ if (!Number.isNaN(c)) {
1065
+ const u = c - Date.now();
1066
+ if (u > 0) return u;
1067
+ }
1068
+ }
1069
+ const o = s.match(/try again in\s*([\d.]+)\s*s/i);
1070
+ if (o) {
1071
+ const a = Number(o[1]);
1072
+ if (Number.isFinite(a) && a > 0)
1073
+ return Math.max(250, Math.round(a * 1e3));
1074
+ }
1075
+ return Math.min(12e3, 2e3 * 2 ** i);
1076
+ }
1077
+ async sleepWithAbort(e, r) {
1078
+ if (r.aborted) throw new Error("aborted");
1079
+ await new Promise((s, i) => {
1080
+ const o = setTimeout(() => {
1081
+ r.removeEventListener("abort", a), s();
1082
+ }, e), a = () => {
1083
+ clearTimeout(o), r.removeEventListener("abort", a), i(new Error("aborted"));
1084
+ };
1085
+ r.addEventListener("abort", a);
1086
+ });
1087
+ }
1088
+ extractAssistantText(e) {
1089
+ return typeof e == "string" ? e : Array.isArray(e) ? e.map((r) => typeof (r == null ? void 0 : r.text) == "string" ? r.text : "").join("") : "";
1090
+ }
1091
+ agentTools() {
1092
+ return [
1093
+ {
1094
+ type: "function",
1095
+ function: {
1096
+ name: "list_workspace_tree",
1097
+ description: "List the current workspace tree (truncated).",
1098
+ parameters: {
1099
+ type: "object",
1100
+ additionalProperties: !1,
1101
+ properties: {}
1102
+ }
1103
+ }
1104
+ },
1105
+ {
1106
+ type: "function",
1107
+ function: {
1108
+ name: "search_workspace",
1109
+ description: "Search text in workspace files. Returns file:line snippets.",
1110
+ parameters: {
1111
+ type: "object",
1112
+ additionalProperties: !1,
1113
+ properties: {
1114
+ query: { type: "string", description: "Text to search for." },
1115
+ caseSensitive: { type: "boolean" }
1116
+ },
1117
+ required: ["query"]
1118
+ }
1119
+ }
1120
+ },
1121
+ {
1122
+ type: "function",
1123
+ function: {
1124
+ name: "read_workspace_file",
1125
+ description: "Read a text file from the workspace with optional line range.",
1126
+ parameters: {
1127
+ type: "object",
1128
+ additionalProperties: !1,
1129
+ properties: {
1130
+ path: { type: "string", description: "Relative path from workspace root." },
1131
+ startLine: { type: "integer" },
1132
+ endLine: { type: "integer" }
1133
+ },
1134
+ required: ["path"]
1135
+ }
1136
+ }
1137
+ },
1138
+ {
1139
+ type: "function",
1140
+ function: {
1141
+ name: "write_workspace_file",
1142
+ description: "Write UTF-8 text to a workspace file path. Use this to apply requested code changes.",
1143
+ parameters: {
1144
+ type: "object",
1145
+ additionalProperties: !1,
1146
+ properties: {
1147
+ path: { type: "string", description: "Relative path from workspace root." },
1148
+ content: { type: "string", description: "Full file content to write." }
1149
+ },
1150
+ required: ["path", "content"]
1151
+ }
1152
+ }
1153
+ },
1154
+ {
1155
+ type: "function",
1156
+ function: {
1157
+ name: "run_shell_command",
1158
+ description: "Run a shell command in the workspace root (subject to permission mode and allowed command prefixes).",
1159
+ parameters: {
1160
+ type: "object",
1161
+ additionalProperties: !1,
1162
+ properties: {
1163
+ command: { type: "string", description: "Command line to execute." },
1164
+ timeoutMs: { type: "integer", description: "Optional timeout in milliseconds." }
1165
+ },
1166
+ required: ["command"]
1167
+ }
1168
+ }
1169
+ }
1170
+ ];
1171
+ }
1172
+ async runTool(e, r) {
1173
+ let s = {};
1174
+ if (typeof r == "string" && r.trim())
1175
+ try {
1176
+ s = JSON.parse(r);
1177
+ } catch {
1178
+ return "Tool error: Invalid JSON arguments.";
1179
+ }
1180
+ if (e === "list_workspace_tree")
1181
+ return this.limitToolOutput(ce(this.cwd));
1182
+ if (e === "search_workspace")
1183
+ return this.limitToolOutput(this.searchWorkspace(s));
1184
+ if (e === "read_workspace_file")
1185
+ return this.limitToolOutput(this.readWorkspaceFile(s));
1186
+ if (e === "write_workspace_file")
1187
+ return this.limitToolOutput(this.writeWorkspaceFile(s));
1188
+ if (e === "run_shell_command") {
1189
+ const i = await this.runShellCommand(s);
1190
+ return this.limitToolOutput(i);
1191
+ }
1192
+ return `Tool error: Unknown tool "${e}".`;
1193
+ }
1194
+ resolveWorkspacePath(e) {
1195
+ if (typeof e != "string" || !e.trim())
1196
+ return { ok: !1, error: "Path is required." };
1197
+ const r = h.resolve(this.cwd), s = e.trim(), i = h.resolve(r, s), o = h.relative(r, i);
1198
+ return !o || o === "." ? { ok: !1, error: "Path must point to a file inside the workspace." } : o.startsWith("..") || h.isAbsolute(o) ? { ok: !1, error: "Path escapes workspace root." } : { ok: !0, absolute: i, relative: o.replace(/\\/g, "/") };
1199
+ }
1200
+ readWorkspaceFile(e) {
1201
+ const r = this.resolveWorkspacePath(e.path);
1202
+ if (!r.ok) return `Tool error: ${r.error}`;
1203
+ let s;
1204
+ try {
1205
+ s = d.statSync(r.absolute);
1206
+ } catch {
1207
+ return `Tool error: File not found: ${r.relative}`;
1208
+ }
1209
+ if (!s.isFile()) return `Tool error: Not a file: ${r.relative}`;
1210
+ const i = d.readFileSync(r.absolute);
1211
+ if (i.includes(0)) return `Tool error: File appears binary and cannot be read as text: ${r.relative}`;
1212
+ const o = i.toString("utf8");
1213
+ if (o.length > be)
1214
+ return `Tool error: File too large (${o.length} chars). Use search_workspace or narrower line range.`;
1215
+ const a = o.split(/\r?\n/), c = a.length, u = typeof e.startLine == "number" ? Math.floor(e.startLine) : 1, l = typeof e.endLine == "number" ? Math.floor(e.endLine) : Math.min(c, u + 220), p = Math.min(Math.max(u, 1), c), m = Math.min(Math.max(l, p), c), g = a.slice(p - 1, m).map((x, E) => `${p + E}: ${x}`).join(`
1216
+ `);
1217
+ return `File: ${r.relative}
1218
+ Lines: ${p}-${m} of ${c}
1219
+
1220
+ ${g}`;
1221
+ }
1222
+ writeWorkspaceFile(e) {
1223
+ if (this.sandbox === "read-only")
1224
+ return "Tool error: Workspace is read-only (sandbox mode).";
1225
+ if (this.permissionMode !== "proceed-always")
1226
+ return "Tool error: Write denied in verify-first mode. Set permissions to Proceed always for autonomous edits.";
1227
+ const r = this.resolveWorkspacePath(e.path);
1228
+ if (!r.ok) return `Tool error: ${r.error}`;
1229
+ if (typeof e.content != "string")
1230
+ return "Tool error: content must be a string.";
1231
+ const s = e.content;
1232
+ if (s.length > be)
1233
+ return `Tool error: Refusing to write large payload (${s.length} chars).`;
1234
+ try {
1235
+ const i = h.dirname(r.absolute);
1236
+ if (!d.existsSync(i))
1237
+ return `Tool error: Parent directory does not exist: ${h.relative(this.cwd, i).replace(/\\/g, "/")}`;
1238
+ d.writeFileSync(r.absolute, s, "utf8");
1239
+ const o = s.length === 0 ? 0 : s.split(/\r?\n/).length;
1240
+ return `Wrote file: ${r.relative} (${s.length} chars, ${o} lines).`;
1241
+ } catch (i) {
1242
+ const o = i instanceof Error ? i.message : String(i);
1243
+ return `Tool error: Failed writing ${r.relative}: ${o}`;
1244
+ }
1245
+ }
1246
+ async runShellCommand(e) {
1247
+ if (this.sandbox === "read-only")
1248
+ return "Tool error: Workspace is read-only (sandbox mode).";
1249
+ if (this.permissionMode !== "proceed-always")
1250
+ return "Tool error: Command execution denied in verify-first mode. Set permissions to Proceed always.";
1251
+ const r = typeof e.command == "string" ? e.command.trim() : "";
1252
+ if (!r) return "Tool error: command is required.";
1253
+ if (this.allowedCommandPrefixes.length > 0 && !this.allowedCommandPrefixes.some((a) => r.startsWith(a)))
1254
+ return `Tool error: Command not in allowlist. Allowed prefixes: ${this.allowedCommandPrefixes.join(", ")}`;
1255
+ const s = typeof e.timeoutMs == "number" ? Math.floor(e.timeoutMs) : Jt, i = Math.max(500, Math.min(Gt, s));
1256
+ return this.runShellCommandAsync(r, i);
1257
+ }
1258
+ async runShellCommandAsync(e, r) {
1259
+ const s = process.platform === "win32" ? process.env.ComSpec || "cmd.exe" : "/bin/sh", i = process.platform === "win32" ? ["/d", "/s", "/c", e] : ["-lc", e];
1260
+ try {
1261
+ const o = I(s, i, {
1262
+ cwd: this.cwd,
1263
+ env: process.env,
1264
+ windowsHide: !0
1265
+ });
1266
+ let a = "", c = "", u = !1;
1267
+ o.stdout && (o.stdout.setEncoding("utf8"), o.stdout.on("data", (b) => {
1268
+ a += b;
1269
+ })), o.stderr && (o.stderr.setEncoding("utf8"), o.stderr.on("data", (b) => {
1270
+ c += b;
1271
+ }));
1272
+ const l = new Promise((b) => {
1273
+ o.on("exit", (y, A) => b({ code: y, signal: A }));
1274
+ });
1275
+ let p = null;
1276
+ const m = new Promise((b) => {
1277
+ p = setTimeout(() => {
1278
+ u = !0;
1279
+ try {
1280
+ o.kill("SIGTERM");
1281
+ } catch {
1282
+ }
1283
+ b({ timeout: !0 });
1284
+ }, r);
1285
+ }), g = await Promise.race([l, m]);
1286
+ if (p && clearTimeout(p), "timeout" in g)
1287
+ return `Command timed out after ${r}ms.
1288
+
1289
+ stdout:
1290
+ ${a || "(empty)"}
1291
+
1292
+ stderr:
1293
+ ${c || "(empty)"}`;
1294
+ const x = g.code ?? -1, E = g.signal ?? "";
1295
+ return `${`exit_code=${x}${E ? ` signal=${E}` : ""}${u ? " timeout=true" : ""}`}
1296
+
1297
+ stdout:
1298
+ ${a || "(empty)"}
1299
+
1300
+ stderr:
1301
+ ${c || "(empty)"}`;
1302
+ } catch (o) {
1303
+ return `Tool error: Failed to run command: ${o instanceof Error ? o.message : String(o)}`;
1304
+ }
1305
+ }
1306
+ searchWorkspace(e) {
1307
+ const r = typeof e.query == "string" ? e.query.trim() : "";
1308
+ if (!r) return "Tool error: query is required.";
1309
+ const s = !!e.caseSensitive, i = h.resolve(this.cwd), o = /* @__PURE__ */ new Set([
1310
+ ".git",
1311
+ "node_modules",
1312
+ "dist",
1313
+ "dist-electron",
1314
+ "release",
1315
+ "build",
1316
+ ".barnaby",
1317
+ ".next",
1318
+ ".nuxt",
1319
+ ".output",
1320
+ "coverage"
1321
+ ]), a = /* @__PURE__ */ new Set([
1322
+ ".png",
1323
+ ".jpg",
1324
+ ".jpeg",
1325
+ ".gif",
1326
+ ".webp",
1327
+ ".ico",
1328
+ ".pdf",
1329
+ ".zip",
1330
+ ".gz",
1331
+ ".exe",
1332
+ ".dll",
1333
+ ".woff",
1334
+ ".woff2",
1335
+ ".ttf",
1336
+ ".mp4",
1337
+ ".mp3",
1338
+ ".icns",
1339
+ ".bin",
1340
+ ".map",
1341
+ ".lock"
1342
+ ]), c = [i], u = [];
1343
+ let l = 0, p = !1;
1344
+ const m = s ? r : r.toLowerCase();
1345
+ for (; c.length > 0 && u.length < Je; ) {
1346
+ const x = c.pop();
1347
+ let E;
1348
+ try {
1349
+ E = d.readdirSync(x, { withFileTypes: !0 });
1350
+ } catch {
1351
+ continue;
1352
+ }
1353
+ for (const w of E) {
1354
+ const b = w.name;
1355
+ if (!b || b.startsWith(".")) continue;
1356
+ const y = h.join(x, b);
1357
+ if (w.isDirectory()) {
1358
+ if (o.has(b)) continue;
1359
+ c.push(y);
1360
+ continue;
1361
+ }
1362
+ if (!w.isFile()) continue;
1363
+ const A = h.extname(b).toLowerCase();
1364
+ if (a.has(A)) continue;
1365
+ if (l++, l > Ge) {
1366
+ p = !0;
1367
+ break;
1368
+ }
1369
+ let v = "";
1370
+ try {
1371
+ if (d.statSync(y).size > be) continue;
1372
+ const R = d.readFileSync(y);
1373
+ if (R.includes(0)) continue;
1374
+ v = R.toString("utf8");
1375
+ } catch {
1376
+ continue;
1377
+ }
1378
+ const S = v.split(/\r?\n/);
1379
+ for (let C = 0; C < S.length; C++) {
1380
+ const R = S[C];
1381
+ if (!(s ? R : R.toLowerCase()).includes(m)) continue;
1382
+ const Et = h.relative(i, y).replace(/\\/g, "/"), Ct = R.length > 220 ? R.slice(0, 220) + "..." : R;
1383
+ if (u.push(`${Et}:${C + 1}: ${Ct}`), u.length >= Je) break;
1384
+ }
1385
+ }
1386
+ if (p) break;
1387
+ }
1388
+ return u.length === 0 ? `No matches for "${r}".` : `${p ? `Results for "${r}" (truncated after scanning ${Ge} files):` : `Results for "${r}":`}
1389
+ ${u.join(`
1390
+ `)}`;
1391
+ }
1392
+ limitToolOutput(e) {
1393
+ return e.length <= Ke ? e : `${e.slice(0, Ke)}
1394
+ ... [truncated]`;
1395
+ }
1396
+ safeToolArgsPreview(e) {
1397
+ if (!e || !e.trim()) return "";
1398
+ const r = e.replace(/\s+/g, " ").trim();
1399
+ return r.length > 120 ? r.slice(0, 120) + "..." : r;
1400
+ }
1401
+ pathToDataUrl(e) {
1402
+ const r = h.isAbsolute(e) ? e : h.resolve(this.cwd, e);
1403
+ let s;
1404
+ try {
1405
+ s = d.statSync(r);
1406
+ } catch {
1407
+ return null;
1408
+ }
1409
+ if (!s.isFile() || s.size > 8 * 1024 * 1024) return null;
1410
+ let i;
1411
+ try {
1412
+ i = d.readFileSync(r);
1413
+ } catch {
1414
+ return null;
1415
+ }
1416
+ const o = h.extname(r).toLowerCase(), a = o === ".png" ? "image/png" : o === ".jpg" || o === ".jpeg" ? "image/jpeg" : o === ".webp" ? "image/webp" : o === ".gif" ? "image/gif" : null;
1417
+ return a ? `data:${a};base64,${i.toString("base64")}` : null;
1418
+ }
1419
+ async interruptActiveTurn() {
1420
+ if (this.activeController)
1421
+ try {
1422
+ this.activeController.abort("interrupted");
1423
+ } catch {
1424
+ } finally {
1425
+ this.activeController = null;
1426
+ }
1427
+ }
1428
+ async close() {
1429
+ await this.interruptActiveTurn(), this.history = [];
1430
+ }
1431
+ }
1432
+ function Oe(n) {
1433
+ const t = h.join(n(), "orchestrator-secrets.json");
1434
+ if (!d.existsSync(t)) return {};
1435
+ try {
1436
+ const e = d.readFileSync(t, "utf8");
1437
+ if (!e.trim()) return {};
1438
+ const r = JSON.parse(e);
1439
+ if (!r || typeof r != "object" || Array.isArray(r)) return {};
1440
+ const s = r;
1441
+ return { licenseKey: typeof s.licenseKey == "string" ? s.licenseKey : void 0 };
1442
+ } catch {
1443
+ return {};
1444
+ }
1445
+ }
1446
+ function Xt(n, t) {
1447
+ const e = n(), r = h.join(e, "orchestrator-secrets.json");
1448
+ d.mkdirSync(h.dirname(r), { recursive: !0 }), d.writeFileSync(r, JSON.stringify(t, null, 2), "utf8");
1449
+ }
1450
+ function Yt(n) {
1451
+ const t = h.join(n(), "orchestrator-settings.json");
1452
+ if (!d.existsSync(t)) return {};
1453
+ try {
1454
+ const e = d.readFileSync(t, "utf8");
1455
+ if (!e.trim()) return {};
1456
+ const r = JSON.parse(e);
1457
+ return !r || typeof r != "object" || Array.isArray(r) ? {} : r;
1458
+ } catch {
1459
+ return {};
1460
+ }
1461
+ }
1462
+ function Zt(n, t) {
1463
+ const e = n(), r = h.join(e, "orchestrator-settings.json");
1464
+ d.mkdirSync(h.dirname(r), { recursive: !0 }), d.writeFileSync(r, JSON.stringify(t, null, 2), "utf8");
1465
+ }
1466
+ const Qt = [
1467
+ "node_modules/@barnaby",
1468
+ "node_modules/@barnaby.build"
1469
+ ], er = 1e4, tr = 5e3;
1470
+ let V = null;
1471
+ const Z = /* @__PURE__ */ new Map();
1472
+ let K = null, O = null, q = null;
1473
+ const J = /* @__PURE__ */ new Map(), le = /* @__PURE__ */ new Set(), G = /* @__PURE__ */ new Map();
1474
+ function rr(n) {
1475
+ V = n;
1476
+ }
1477
+ function nr(n) {
1478
+ O = n;
1479
+ }
1480
+ function Fe(n, ...t) {
1481
+ !V || V.isDestroyed() || V.webContents.send(n, ...t);
1482
+ }
1483
+ function ee(n, ...t) {
1484
+ return new Promise((e, r) => {
1485
+ if (!V || V.isDestroyed()) {
1486
+ r(new Error("No renderer window available"));
1487
+ return;
1488
+ }
1489
+ const s = `${n}:response:${Date.now()}-${Math.random().toString(16).slice(2)}`, i = setTimeout(() => {
1490
+ f.removeHandler(s), r(new Error(`Plugin host IPC timeout on ${n}`));
1491
+ }, 3e4);
1492
+ f.handleOnce(s, (o, a) => {
1493
+ clearTimeout(i), a.ok ? e(a.data) : r(new Error(a.error ?? "Unknown renderer error"));
1494
+ }), Fe("barnaby:plugin-host:request", { channel: n, responseChannel: s, args: t });
1495
+ });
1496
+ }
1497
+ function sr() {
1498
+ return {
1499
+ async createPanel(n) {
1500
+ return ee("plugin:createPanel", n ?? {});
1501
+ },
1502
+ async closePanel(n) {
1503
+ return ee("plugin:closePanel", n);
1504
+ },
1505
+ async sendMessage(n, t, e) {
1506
+ return ee("plugin:sendMessage", n, t, e ?? []);
1507
+ },
1508
+ async interruptPanel(n) {
1509
+ return ee("plugin:interruptPanel", n);
1510
+ },
1511
+ getPanelInfo(n) {
1512
+ return null;
1513
+ },
1514
+ getPanelMessages(n) {
1515
+ return [];
1516
+ },
1517
+ listPanels() {
1518
+ return [];
1519
+ },
1520
+ onPanelEvent(n, t) {
1521
+ return J.has(n) || J.set(n, /* @__PURE__ */ new Set()), J.get(n).add(t), {
1522
+ dispose() {
1523
+ var e;
1524
+ (e = J.get(n)) == null || e.delete(t);
1525
+ }
1526
+ };
1527
+ },
1528
+ onAnyPanelEvent(n) {
1529
+ return le.add(n), {
1530
+ dispose() {
1531
+ le.delete(n);
1532
+ }
1533
+ };
1534
+ },
1535
+ onPanelTurnComplete(n, t) {
1536
+ return G.has(n) || G.set(n, /* @__PURE__ */ new Set()), G.get(n).add(t), {
1537
+ dispose() {
1538
+ var e;
1539
+ (e = G.get(n)) == null || e.delete(t);
1540
+ }
1541
+ };
1542
+ },
1543
+ async readFile(n) {
1544
+ const t = (O == null ? void 0 : O()) ?? "";
1545
+ if (!t) throw new Error("No workspace root set");
1546
+ const e = h.join(t, n), r = d.statSync(e), s = d.readFileSync(e, "utf-8");
1547
+ return { relativePath: n, size: r.size, content: s };
1548
+ },
1549
+ async writeFile(n, t) {
1550
+ const e = (O == null ? void 0 : O()) ?? "";
1551
+ if (!e) throw new Error("No workspace root set");
1552
+ const r = h.join(e, n);
1553
+ d.mkdirSync(h.dirname(r), { recursive: !0 }), d.writeFileSync(r, t, "utf-8");
1554
+ const s = d.statSync(r);
1555
+ return { relativePath: n, size: s.size };
1556
+ },
1557
+ async listFiles(n) {
1558
+ return ee("plugin:listFiles", n ?? {});
1559
+ },
1560
+ getWorkspaceRoot() {
1561
+ return (O == null ? void 0 : O()) ?? "";
1562
+ },
1563
+ registerDockPane(n, t) {
1564
+ Fe("barnaby:plugin-host:dock-pane-registered", { pluginId: n });
1565
+ },
1566
+ getSetting(n) {
1567
+ const t = q == null ? void 0 : q();
1568
+ if (t) {
1569
+ const e = Yt(() => t), s = {
1570
+ "orchestrator.orchestratorModel": "orchestratorModel",
1571
+ "orchestrator.workerProvider": "workerProvider",
1572
+ "orchestrator.workerModel": "workerModel",
1573
+ "orchestrator.maxParallelPanels": "maxParallelPanels",
1574
+ "orchestrator.maxTaskAttempts": "maxTaskAttempts"
1575
+ }[n];
1576
+ if (s && e[s] !== void 0) return e[s];
1577
+ }
1578
+ try {
1579
+ const e = (O == null ? void 0 : O()) ?? "";
1580
+ if (!e) return;
1581
+ const r = h.join(e, ".barnaby", "plugin-settings.json");
1582
+ return d.existsSync(r) ? JSON.parse(d.readFileSync(r, "utf-8"))[n] : void 0;
1583
+ } catch {
1584
+ return;
1585
+ }
1586
+ },
1587
+ setSetting(n, t) {
1588
+ try {
1589
+ const e = (O == null ? void 0 : O()) ?? "";
1590
+ if (!e) return;
1591
+ const r = h.join(e, ".barnaby"), s = h.join(r, "plugin-settings.json");
1592
+ d.mkdirSync(r, { recursive: !0 });
1593
+ let i = {};
1594
+ try {
1595
+ i = JSON.parse(d.readFileSync(s, "utf-8"));
1596
+ } catch {
1597
+ }
1598
+ i[n] = t, d.writeFileSync(s, JSON.stringify(i, null, 2), "utf-8");
1599
+ } catch {
1600
+ }
1601
+ },
1602
+ getOrchestratorLicenseKeyState() {
1603
+ const n = q == null ? void 0 : q();
1604
+ return n ? { hasKey: (Oe(() => n).licenseKey ?? "").trim().length > 0 } : { hasKey: !1 };
1605
+ },
1606
+ log(n, t, e) {
1607
+ const r = `[plugin:${n}]`;
1608
+ t === "error" ? console.error(r, e) : t === "warn" ? console.warn(r, e) : console.log(r, e);
1609
+ }
1610
+ };
1611
+ }
1612
+ function ir(n, t) {
1613
+ const e = J.get(n);
1614
+ if (e)
1615
+ for (const r of e)
1616
+ try {
1617
+ r(t);
1618
+ } catch (s) {
1619
+ console.error("[pluginHost] panel event handler error:", s);
1620
+ }
1621
+ for (const r of le)
1622
+ try {
1623
+ r(n, t);
1624
+ } catch (s) {
1625
+ console.error("[pluginHost] anyPanel event handler error:", s);
1626
+ }
1627
+ }
1628
+ function or(n) {
1629
+ const t = G.get(n);
1630
+ if (t)
1631
+ for (const e of t)
1632
+ try {
1633
+ e();
1634
+ } catch (r) {
1635
+ console.error("[pluginHost] turn complete handler error:", r);
1636
+ }
1637
+ }
1638
+ function ar(n) {
1639
+ var r, s, i;
1640
+ const t = [];
1641
+ for (const o of Qt) {
1642
+ const a = h.join(n, o);
1643
+ if (d.existsSync(a))
1644
+ try {
1645
+ const c = d.readdirSync(a, { withFileTypes: !0 });
1646
+ for (const u of c) {
1647
+ if (!u.isDirectory() && !u.isSymbolicLink()) continue;
1648
+ const l = h.join(a, u.name, "package.json");
1649
+ if (d.existsSync(l))
1650
+ try {
1651
+ ((r = JSON.parse(d.readFileSync(l, "utf-8")).barnaby) == null ? void 0 : r.plugin) === !0 && t.push(h.join(a, u.name));
1652
+ } catch {
1653
+ }
1654
+ }
1655
+ } catch {
1656
+ }
1657
+ }
1658
+ const e = h.join(Q.homedir(), ".barnaby", "plugins");
1659
+ if (d.existsSync(e))
1660
+ try {
1661
+ const o = d.readdirSync(e, { withFileTypes: !0 });
1662
+ for (const a of o) {
1663
+ if (!a.isDirectory() && !a.isSymbolicLink()) continue;
1664
+ const c = h.join(e, a.name, "package.json");
1665
+ if (d.existsSync(c))
1666
+ try {
1667
+ ((s = JSON.parse(d.readFileSync(c, "utf-8")).barnaby) == null ? void 0 : s.plugin) === !0 && t.push(h.join(e, a.name));
1668
+ } catch {
1669
+ }
1670
+ }
1671
+ } catch {
1672
+ }
1673
+ for (const o of ["@barnaby", "@barnaby.build"]) {
1674
+ const a = h.join(e, "node_modules", o);
1675
+ if (d.existsSync(a))
1676
+ try {
1677
+ const c = d.readdirSync(a, { withFileTypes: !0 });
1678
+ for (const u of c) {
1679
+ if (!u.isDirectory() && !u.isSymbolicLink()) continue;
1680
+ const l = h.join(a, u.name, "package.json");
1681
+ if (d.existsSync(l))
1682
+ try {
1683
+ ((i = JSON.parse(d.readFileSync(l, "utf-8")).barnaby) == null ? void 0 : i.plugin) === !0 && t.push(h.join(a, u.name));
1684
+ } catch {
1685
+ }
1686
+ }
1687
+ } catch {
1688
+ }
1689
+ }
1690
+ return t;
1691
+ }
1692
+ async function Qe(n, t) {
1693
+ var s;
1694
+ q = t ?? null, console.log(`[pluginHost] Initializing plugin host (appRoot: ${n})`);
1695
+ const e = ar(n);
1696
+ console.log(`[pluginHost] Discovered ${e.length} plugin(s): ${e.join(", ") || "(none)"}`);
1697
+ const r = sr();
1698
+ for (const i of e)
1699
+ try {
1700
+ const a = JSON.parse(d.readFileSync(h.join(i, "package.json"), "utf-8")).main ?? "index.js", c = h.resolve(i, a), u = await import(Mt(c).href), l = u.default ?? u;
1701
+ if (!l.pluginId || typeof l.activate != "function") {
1702
+ console.warn(`[pluginHost] Skipping invalid plugin at ${i}`);
1703
+ continue;
1704
+ }
1705
+ if (Z.has(l.pluginId)) {
1706
+ console.warn(`[pluginHost] Duplicate plugin ID "${l.pluginId}" at ${i}, skipping`);
1707
+ continue;
1708
+ }
1709
+ await l.activate(r);
1710
+ const p = ((s = l.getLifecycleConfig) == null ? void 0 : s.call(l)) ?? null;
1711
+ Z.set(l.pluginId, { plugin: l, lifecycleConfig: p, active: !0 }), console.log(`[pluginHost] Activated plugin: ${l.displayName} v${l.version}`);
1712
+ } catch (o) {
1713
+ console.error(`[pluginHost] Failed to load plugin at ${i}:`, o);
1714
+ }
1715
+ cr();
1716
+ }
1717
+ function cr() {
1718
+ K || (K = setInterval(() => {
1719
+ for (const [n, t] of Z) {
1720
+ if (!t.active || !t.lifecycleConfig) continue;
1721
+ const e = t.lifecycleConfig;
1722
+ try {
1723
+ if (!d.existsSync(e.stateFilePath)) continue;
1724
+ const r = d.readFileSync(e.stateFilePath, "utf-8"), i = JSON.parse(r)[e.heartbeatField];
1725
+ if (typeof i != "number" || !Number.isFinite(i)) continue;
1726
+ const o = Date.now() - i;
1727
+ o > e.staleThresholdMs + tr && (console.warn(`[pluginHost] Plugin "${n}" heartbeat is stale (${Math.round(o / 1e3)}s). Sending recovery signal.`), Fe("barnaby:plugin-host:recovery", {
1728
+ pluginId: n,
1729
+ recoveryPrompt: e.recoveryPrompt,
1730
+ stateFilePath: e.stateFilePath,
1731
+ staleness: o
1732
+ }));
1733
+ } catch {
1734
+ }
1735
+ }
1736
+ }, er), typeof K.unref == "function" && K.unref());
1737
+ }
1738
+ async function De() {
1739
+ var n, t;
1740
+ K && (clearInterval(K), K = null);
1741
+ for (const [e, r] of Z)
1742
+ if (r.active)
1743
+ try {
1744
+ await ((t = (n = r.plugin).deactivate) == null ? void 0 : t.call(n)), r.active = !1, console.log(`[pluginHost] Deactivated plugin: ${e}`);
1745
+ } catch (s) {
1746
+ console.error(`[pluginHost] Error deactivating plugin "${e}":`, s);
1747
+ }
1748
+ Z.clear(), J.clear(), le.clear(), G.clear();
1749
+ }
1750
+ function lr() {
1751
+ return Z;
1752
+ }
1753
+ const dr = Ft(import.meta.url);
1754
+ function ur() {
1755
+ try {
1756
+ return dr("node-pty");
1757
+ } catch {
1758
+ return null;
1759
+ }
1760
+ }
1761
+ const pr = ".agentorchestrator.json", hr = ".barnaby", fr = "active-token.json", mr = 5e3, gr = 3e4, yr = "Agent Orchestrator", et = ".legacy-storage-migration-v1.json", Se = "agentorchestrator.chatHistory", Le = ".storage", tt = "chat-history.json", rt = "app-state.json", nt = "provider-secrets.json", wr = "runtime.log", vr = 200, kr = 2500, Ve = 1024 * 1024, br = 3e4, Sr = /* @__PURE__ */ new Set([
1762
+ ".git",
1763
+ "dist",
1764
+ "dist-electron",
1765
+ "release",
1766
+ ".next",
1767
+ "out",
1768
+ ".turbo"
1769
+ ]), N = Ot(Rt), st = h.dirname(It(import.meta.url));
1770
+ process.env.APP_ROOT = h.join(st, "../..");
1771
+ const _n = h.join(process.env.APP_ROOT, "dist-electron"), it = h.join(process.env.APP_ROOT, "dist"), X = process.env.VITE_DEV_SERVER_URL;
1772
+ process.env.VITE_PUBLIC = X ? h.join(process.env.APP_ROOT, "public") : it;
1773
+ const Ar = "com.agentorchestrator.app", xr = "Barnaby";
1774
+ Q.release().startsWith("6.1") && $.disableHardwareAcceleration();
1775
+ process.platform === "win32" && ($.setName(xr), $.setAppUserModelId(Ar));
1776
+ let k = null, B = null, Ee = [], de = !1;
1777
+ const ot = h.join(st, "../preload/index.mjs"), at = h.join(it, "index.html");
1778
+ let ie = null, Ce = !1, re = !1, oe = !1, ue = !1;
1779
+ const M = /* @__PURE__ */ new Map(), ct = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
1780
+ let F = null;
1781
+ const W = /* @__PURE__ */ new Map();
1782
+ let H = null;
1783
+ function Pr() {
1784
+ return process.defaultApp ? !process.argv.slice(1).filter(Boolean).some((e) => !e.startsWith("-")) : !1;
1785
+ }
1786
+ function j(n) {
1787
+ return n.replace(/\\/g, "/");
1788
+ }
1789
+ function Te(n) {
1790
+ try {
1791
+ return d.statSync(n).isDirectory();
1792
+ } catch {
1793
+ return !1;
1794
+ }
1795
+ }
1796
+ function ge() {
1797
+ ie && (clearTimeout(ie), ie = null);
1798
+ }
1799
+ function ye() {
1800
+ B && (B.isDestroyed() || B.close(), B = null);
1801
+ }
1802
+ function Xe(n) {
1803
+ let t = "";
1804
+ try {
1805
+ d.existsSync(n) && (t = `data:image/png;base64,${d.readFileSync(n).toString("base64")}`);
1806
+ } catch (s) {
1807
+ D("splash-image-base64-failed", { splashImagePath: n, error: _(s) }, "warn");
1808
+ }
1809
+ const e = $.getVersion(), r = `<!doctype html>
1810
+ <html lang="en">
1811
+ <head>
1812
+ <meta charset="utf-8" />
1813
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1814
+ <title>Barnaby Splash</title>
1815
+ <style>
1816
+ html, body {
1817
+ margin: 0;
1818
+ width: 100%;
1819
+ height: 100%;
1820
+ background: #0b0b0b;
1821
+ overflow: hidden;
1822
+ }
1823
+ .root {
1824
+ width: 100%;
1825
+ height: 100%;
1826
+ display: flex;
1827
+ align-items: center;
1828
+ justify-content: center;
1829
+ }
1830
+ img {
1831
+ max-width: 90%;
1832
+ max-height: 90%;
1833
+ object-fit: contain;
1834
+ user-select: none;
1835
+ -webkit-user-drag: none;
1836
+ }
1837
+ .version {
1838
+ position: fixed;
1839
+ bottom: 8px;
1840
+ right: 12px;
1841
+ font-size: 11px;
1842
+ color: white;
1843
+ font-family: system-ui, sans-serif;
1844
+ opacity: 0.8;
1845
+ }
1846
+ </style>
1847
+ </head>
1848
+ <body>
1849
+ <div class="root">
1850
+ ${t ? `<img src="${t}" alt="Barnaby splash" />` : ""}
1851
+ </div>
1852
+ <div class="version">${String(e).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>
1853
+ </body>
1854
+ </html>`;
1855
+ return `data:text/html;charset=utf-8,${encodeURIComponent(r)}`;
1856
+ }
1857
+ function Er() {
1858
+ const n = process.env.VITE_PUBLIC;
1859
+ if (!n)
1860
+ return D("splash-skipped", { reason: "vite-public-missing" }, "warn"), null;
1861
+ const t = h.join(n, "splash.png"), e = h.join(n, "splash.html");
1862
+ if (!d.existsSync(t))
1863
+ return D("splash-skipped", { reason: "splash-image-missing", splashImagePath: t }, "warn"), null;
1864
+ const r = d.existsSync(e), s = new L({
1865
+ width: 560,
1866
+ height: 360,
1867
+ center: !0,
1868
+ show: !0,
1869
+ frame: !1,
1870
+ resizable: !1,
1871
+ minimizable: !1,
1872
+ maximizable: !1,
1873
+ fullscreenable: !1,
1874
+ alwaysOnTop: !0,
1875
+ skipTaskbar: !0,
1876
+ backgroundColor: "#0b0b0b",
1877
+ autoHideMenuBar: !0
1878
+ });
1879
+ s.setMenuBarVisibility(!1);
1880
+ const i = () => {
1881
+ s.webContents.executeJavaScript(
1882
+ `(function(){var el=document.getElementById('version');if(el)el.textContent=${JSON.stringify($.getVersion())};})()`
1883
+ ).catch(() => {
1884
+ });
1885
+ };
1886
+ return r ? (s.webContents.once("did-finish-load", i), s.loadFile(e).catch((o) => {
1887
+ D("splash-loadfile-failed", { splashHtmlPath: e, error: _(o) }, "warn"), s.loadURL(Xe(t)).catch(() => {
1888
+ });
1889
+ })) : (D("splash-html-missing-fallback", { splashHtmlPath: e }, "warn"), s.loadURL(Xe(t)).catch((o) => {
1890
+ D("splash-fallback-loadurl-failed", { splashImagePath: t, error: _(o) }, "warn");
1891
+ })), s.on("closed", () => {
1892
+ B === s && (B = null);
1893
+ }), s;
1894
+ }
1895
+ function Cr() {
1896
+ !k || ue || (ue = !0, ge(), ye(), k.maximize(), k.show());
1897
+ }
1898
+ function $e() {
1899
+ k && (ue || Ce && (oe && !re || Cr()));
1900
+ }
1901
+ function _e(n, t, e = /* @__PURE__ */ new Set()) {
1902
+ d.mkdirSync(t, { recursive: !0 });
1903
+ const r = d.readdirSync(n, { withFileTypes: !0 });
1904
+ for (const s of r) {
1905
+ if (e.has(s.name)) continue;
1906
+ const i = h.join(n, s.name), o = h.join(t, s.name);
1907
+ if (s.isDirectory()) {
1908
+ _e(i, o, e);
1909
+ continue;
1910
+ }
1911
+ s.isFile() && d.copyFileSync(i, o);
1912
+ }
1913
+ }
1914
+ function Ye(n) {
1915
+ if (!Te(n)) return !1;
1916
+ const t = d.readdirSync(n, { withFileTypes: !0 }).filter((e) => e.isFile() && (e.name.endsWith(".ldb") || e.name.endsWith(".log"))).map((e) => h.join(n, e.name));
1917
+ for (const e of t) {
1918
+ let r = "";
1919
+ try {
1920
+ r = d.readFileSync(e, "latin1");
1921
+ } catch {
1922
+ continue;
1923
+ }
1924
+ let s = r.indexOf(Se);
1925
+ for (; s >= 0; ) {
1926
+ const i = r.slice(s, s + 240);
1927
+ if (i.includes("[{") || i.includes("[\0{\0")) return !0;
1928
+ s = r.indexOf(Se, s + Se.length);
1929
+ }
1930
+ }
1931
+ return !1;
1932
+ }
1933
+ function se(n, t) {
1934
+ try {
1935
+ const e = h.join(n, et);
1936
+ d.writeFileSync(
1937
+ e,
1938
+ JSON.stringify({ version: 1, status: t, at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
1939
+ "utf8"
1940
+ );
1941
+ } catch {
1942
+ }
1943
+ }
1944
+ function Tr() {
1945
+ const n = $.getPath("userData"), t = h.join(n, et);
1946
+ if (d.existsSync(t)) return;
1947
+ const e = h.join($.getPath("appData"), yr, "Local Storage", "leveldb"), r = h.join(n, "Local Storage", "leveldb");
1948
+ if (!Te(e)) {
1949
+ se(n, "skipped");
1950
+ return;
1951
+ }
1952
+ if (!Ye(e)) {
1953
+ se(n, "skipped");
1954
+ return;
1955
+ }
1956
+ if (Ye(r)) {
1957
+ se(n, "skipped");
1958
+ return;
1959
+ }
1960
+ try {
1961
+ if (Te(r)) {
1962
+ const s = h.join(n, "Local Storage", `leveldb-pre-legacy-import-${Date.now()}`);
1963
+ _e(r, s, /* @__PURE__ */ new Set(["LOCK"])), d.rmSync(r, { recursive: !0, force: !0 });
1964
+ }
1965
+ _e(e, r, /* @__PURE__ */ new Set(["LOCK"])), se(n, "migrated"), console.info("[Barnaby] Imported legacy chat history from Agent Orchestrator.");
1966
+ } catch (s) {
1967
+ console.warn("[Barnaby] Legacy chat history migration failed:", _(s));
1968
+ }
1969
+ }
1970
+ function we(n, t) {
1971
+ const e = h.resolve(n), r = t.split("/").filter(Boolean).join(h.sep), s = h.resolve(e, r), i = h.relative(e, s);
1972
+ if (i.startsWith("..") || h.isAbsolute(i))
1973
+ throw new Error("Path is outside the workspace root.");
1974
+ return s;
1975
+ }
1976
+ function lt(n, t) {
1977
+ const e = h.resolve(n), r = h.resolve(t), s = h.relative(e, r);
1978
+ if (s.startsWith("..") || h.isAbsolute(s))
1979
+ throw new Error("Path is outside the workspace root.");
1980
+ return j(s);
1981
+ }
1982
+ function ve() {
1983
+ return h.join($.getPath("userData"), Le, tt);
1984
+ }
1985
+ function U() {
1986
+ return h.join($.getPath("userData"), Le);
1987
+ }
1988
+ function Ne() {
1989
+ return h.join(U(), rt);
1990
+ }
1991
+ function We() {
1992
+ return h.join(U(), wr);
1993
+ }
1994
+ function D(n, t, e = "info") {
1995
+ try {
1996
+ const r = We();
1997
+ d.mkdirSync(h.dirname(r), { recursive: !0 });
1998
+ const s = {
1999
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2000
+ level: e,
2001
+ pid: process.pid,
2002
+ event: n,
2003
+ detail: t ?? null
2004
+ };
2005
+ d.appendFileSync(r, `${JSON.stringify(s)}
2006
+ `, "utf8");
2007
+ } catch {
2008
+ }
2009
+ }
2010
+ function $r() {
2011
+ const n = Ne();
2012
+ if (!d.existsSync(n)) return null;
2013
+ try {
2014
+ const t = d.readFileSync(n, "utf8");
2015
+ if (!t.trim()) return null;
2016
+ const e = JSON.parse(t);
2017
+ return e && typeof e == "object" && !Array.isArray(e) && "state" in e ? e.state ?? null : e;
2018
+ } catch (t) {
2019
+ return D("read-app-state-failed", _(t), "warn"), null;
2020
+ }
2021
+ }
2022
+ function _r(n) {
2023
+ const t = Ne(), e = {
2024
+ version: 1,
2025
+ savedAt: Date.now(),
2026
+ state: n ?? null
2027
+ };
2028
+ return d.mkdirSync(h.dirname(t), { recursive: !0 }), d.writeFileSync(t, JSON.stringify(e, null, 2), "utf8"), {
2029
+ ok: !0,
2030
+ path: t,
2031
+ savedAt: e.savedAt
2032
+ };
2033
+ }
2034
+ function dt() {
2035
+ return h.join(U(), nt);
2036
+ }
2037
+ function ut() {
2038
+ const n = dt();
2039
+ if (!d.existsSync(n)) return {};
2040
+ try {
2041
+ const t = d.readFileSync(n, "utf8");
2042
+ if (!t.trim()) return {};
2043
+ const e = JSON.parse(t);
2044
+ return !e || typeof e != "object" || Array.isArray(e) ? {} : e;
2045
+ } catch (t) {
2046
+ return D("read-provider-secrets-failed", _(t), "warn"), {};
2047
+ }
2048
+ }
2049
+ function Mr(n) {
2050
+ const t = dt();
2051
+ d.mkdirSync(h.dirname(t), { recursive: !0 }), d.writeFileSync(t, JSON.stringify(n, null, 2), "utf8");
2052
+ }
2053
+ function pe(n) {
2054
+ var e;
2055
+ return (((e = ut()[n]) == null ? void 0 : e.apiKey) ?? "").trim();
2056
+ }
2057
+ function pt(n, t) {
2058
+ const e = ut(), r = t.trim();
2059
+ return r ? e[n] = { ...e[n] ?? {}, apiKey: r } : delete e[n], Mr(e), { ok: !0, hasKey: r.length > 0 };
2060
+ }
2061
+ function Ir(n) {
2062
+ const e = {
2063
+ openrouter: "OPENROUTER_API_KEY",
2064
+ codex: "OPENAI_API_KEY"
2065
+ }[n];
2066
+ if (!e)
2067
+ return { ok: !1, hasKey: !1, imported: !1, detail: `No environment mapping for provider "${n}".` };
2068
+ const r = (process.env[e] ?? "").trim();
2069
+ return r ? { ok: !0, hasKey: pt(n, r).hasKey, imported: !0, detail: `Imported API key from ${e}.` } : { ok: !1, hasKey: !1, imported: !1, detail: `${e} is not set in this process environment.` };
2070
+ }
2071
+ function ht() {
2072
+ return {
2073
+ userDataPath: $.getPath("userData"),
2074
+ storageDir: U(),
2075
+ chatHistoryPath: ve(),
2076
+ appStatePath: Ne(),
2077
+ runtimeLogPath: We()
2078
+ };
2079
+ }
2080
+ function ft(n) {
2081
+ const t = ht();
2082
+ switch (n) {
2083
+ case "userData":
2084
+ return { path: t.userDataPath, kind: "directory" };
2085
+ case "storage":
2086
+ return { path: t.storageDir, kind: "directory" };
2087
+ case "chatHistory":
2088
+ return { path: t.chatHistoryPath, kind: "file" };
2089
+ case "appState":
2090
+ return { path: t.appStatePath, kind: "file" };
2091
+ case "runtimeLog":
2092
+ return { path: t.runtimeLogPath, kind: "file" };
2093
+ }
2094
+ }
2095
+ async function Rr(n) {
2096
+ const t = typeof n == "string" ? n : void 0;
2097
+ if (t !== "userData" && t !== "storage" && t !== "chatHistory" && t !== "appState" && t !== "runtimeLog")
2098
+ return {
2099
+ ok: !1,
2100
+ path: "",
2101
+ error: "Unknown diagnostics path target."
2102
+ };
2103
+ const e = ft(t);
2104
+ if (!e)
2105
+ return {
2106
+ ok: !1,
2107
+ path: "",
2108
+ error: "Unknown diagnostics path target."
2109
+ };
2110
+ try {
2111
+ e.kind === "directory" ? d.mkdirSync(e.path, { recursive: !0 }) : t === "runtimeLog" && (d.mkdirSync(h.dirname(e.path), { recursive: !0 }), d.existsSync(e.path) || d.writeFileSync(e.path, "", "utf8"));
2112
+ } catch (s) {
2113
+ return {
2114
+ ok: !1,
2115
+ path: e.path,
2116
+ error: _(s)
2117
+ };
2118
+ }
2119
+ const r = await z.openPath(e.path);
2120
+ return {
2121
+ ok: !r,
2122
+ path: e.path,
2123
+ error: r || void 0
2124
+ };
2125
+ }
2126
+ function mt(n) {
2127
+ return n === "chatHistory" || n === "appState" || n === "runtimeLog";
2128
+ }
2129
+ function Or(n, t) {
2130
+ d.mkdirSync(h.dirname(t), { recursive: !0 }), d.existsSync(t) || d.writeFileSync(t, "", "utf8");
2131
+ }
2132
+ async function Fr(n) {
2133
+ if (!mt(n))
2134
+ return { ok: !1, path: "", error: "Unknown diagnostics file target." };
2135
+ const t = ft(n);
2136
+ if (!t || t.kind !== "file")
2137
+ return { ok: !1, path: "", error: "Diagnostics target is not a file." };
2138
+ try {
2139
+ Or(n, t.path);
2140
+ const e = d.readFileSync(t.path, "utf8");
2141
+ return {
2142
+ ok: !0,
2143
+ path: t.path,
2144
+ content: e,
2145
+ writable: !1
2146
+ };
2147
+ } catch (e) {
2148
+ return { ok: !1, path: t.path, error: _(e) };
2149
+ }
2150
+ }
2151
+ async function Dr(n, t) {
2152
+ return mt(n) ? { ok: !1, path: "", error: "Diagnostics files are read-only in this view." } : { ok: !1, path: "", error: "Unknown diagnostics file target." };
2153
+ }
2154
+ async function Lr() {
2155
+ const n = ve(), t = h.dirname(n);
2156
+ try {
2157
+ d.mkdirSync(t, { recursive: !0 });
2158
+ } catch (r) {
2159
+ return {
2160
+ ok: !1,
2161
+ path: t,
2162
+ error: _(r)
2163
+ };
2164
+ }
2165
+ const e = await z.openPath(t);
2166
+ return {
2167
+ ok: !e,
2168
+ path: t,
2169
+ error: e || void 0
2170
+ };
2171
+ }
2172
+ function Nr() {
2173
+ const n = We();
2174
+ try {
2175
+ d.mkdirSync(h.dirname(n), { recursive: !0 }), d.existsSync(n) || d.writeFileSync(n, "", "utf8");
2176
+ } catch (t) {
2177
+ return {
2178
+ ok: !1,
2179
+ path: n,
2180
+ error: _(t)
2181
+ };
2182
+ }
2183
+ return z.openPath(n).then((t) => ({
2184
+ ok: !t,
2185
+ path: n,
2186
+ error: t || void 0
2187
+ }));
2188
+ }
2189
+ function Wr() {
2190
+ process.on("uncaughtException", (n) => {
2191
+ D("uncaughtException", { message: n == null ? void 0 : n.message, stack: n == null ? void 0 : n.stack }, "error");
2192
+ }), process.on("unhandledRejection", (n) => {
2193
+ D("unhandledRejection", n, "error");
2194
+ }), $.on("render-process-gone", (n, t, e) => {
2195
+ D(
2196
+ "render-process-gone",
2197
+ {
2198
+ url: t.getURL(),
2199
+ reason: e.reason,
2200
+ exitCode: e.exitCode
2201
+ },
2202
+ "error"
2203
+ );
2204
+ }), $.on("child-process-gone", (n, t) => {
2205
+ D(
2206
+ "child-process-gone",
2207
+ {
2208
+ type: t.type,
2209
+ reason: t.reason,
2210
+ name: t.name,
2211
+ serviceName: t.serviceName,
2212
+ exitCode: t.exitCode
2213
+ },
2214
+ t.reason === "clean-exit" ? "info" : "warn"
2215
+ );
2216
+ });
2217
+ }
2218
+ function gt(n) {
2219
+ if (!Array.isArray(n)) return [];
2220
+ const t = process.env.APP_ROOT || process.cwd(), e = [];
2221
+ for (const r of n) {
2222
+ if (!r || typeof r != "object") continue;
2223
+ const s = r;
2224
+ if (!Array.isArray(s.messages) || s.messages.length === 0) continue;
2225
+ const i = [];
2226
+ for (const o of s.messages) {
2227
+ if (!o || typeof o != "object") continue;
2228
+ const a = o, c = a.role === "user" || a.role === "assistant" || a.role === "system" ? a.role : "system", u = a.format === "text" || a.format === "markdown" ? a.format : void 0, l = Array.isArray(a.attachments) ? a.attachments.filter((p) => !!(p && typeof p == "object")).map((p) => ({
2229
+ id: typeof p.id == "string" && p.id.trim() ? p.id.trim() : `${Date.now()}-${Math.random().toString(16).slice(2)}`,
2230
+ path: typeof p.path == "string" ? p.path : "",
2231
+ label: typeof p.label == "string" && p.label.trim() ? p.label.trim() : "attachment",
2232
+ mimeType: typeof p.mimeType == "string" && p.mimeType.trim() ? p.mimeType.trim() : void 0
2233
+ })).filter((p) => !!p.path) : void 0;
2234
+ i.push({
2235
+ id: typeof a.id == "string" && a.id.trim() ? a.id.trim() : `${Date.now()}-${Math.random().toString(16).slice(2)}`,
2236
+ role: c,
2237
+ content: typeof a.content == "string" ? a.content : "",
2238
+ format: u,
2239
+ attachments: l && l.length > 0 ? l : void 0
2240
+ });
2241
+ }
2242
+ i.length !== 0 && e.push({
2243
+ id: typeof s.id == "string" && s.id.trim() ? s.id.trim() : `${Date.now()}-${Math.random().toString(16).slice(2)}`,
2244
+ title: typeof s.title == "string" && s.title.trim() ? s.title.trim() : "Untitled chat",
2245
+ savedAt: typeof s.savedAt == "number" && Number.isFinite(s.savedAt) ? s.savedAt : Date.now(),
2246
+ workspaceRoot: typeof s.workspaceRoot == "string" && s.workspaceRoot.trim() ? s.workspaceRoot.trim() : t,
2247
+ model: typeof s.model == "string" && s.model.trim() ? s.model.trim() : "gpt-5",
2248
+ permissionMode: s.permissionMode === "proceed-always" ? "proceed-always" : "verify-first",
2249
+ sandbox: s.sandbox === "read-only" || s.sandbox === "workspace-write" ? s.sandbox : "workspace-write",
2250
+ fontScale: typeof s.fontScale == "number" && Number.isFinite(s.fontScale) ? s.fontScale : 1,
2251
+ messages: i
2252
+ });
2253
+ }
2254
+ return e.sort((r, s) => s.savedAt - r.savedAt).slice(0, vr);
2255
+ }
2256
+ function jr() {
2257
+ const n = ve();
2258
+ if (!d.existsSync(n)) return [];
2259
+ try {
2260
+ const t = d.readFileSync(n, "utf8");
2261
+ if (!t.trim()) return [];
2262
+ const e = JSON.parse(t), r = e && typeof e == "object" && !Array.isArray(e) && "entries" in e ? e.entries : e;
2263
+ return gt(r);
2264
+ } catch (t) {
2265
+ return console.warn("[Barnaby] Failed to read persisted chat history:", _(t)), [];
2266
+ }
2267
+ }
2268
+ function Hr(n) {
2269
+ const t = ve(), e = h.dirname(t), r = gt(n), s = {
2270
+ version: 1,
2271
+ savedAt: Date.now(),
2272
+ entries: r
2273
+ };
2274
+ return d.mkdirSync(e, { recursive: !0 }), d.writeFileSync(t, JSON.stringify(s, null, 2), "utf8"), {
2275
+ ok: !0,
2276
+ count: r.length,
2277
+ path: t
2278
+ };
2279
+ }
2280
+ function Ur(n, t = {}) {
2281
+ const e = h.resolve(n);
2282
+ if (!d.existsSync(e)) throw new Error("Workspace path does not exist.");
2283
+ if (!d.statSync(e).isDirectory()) throw new Error("Workspace path is not a directory.");
2284
+ const r = !!t.includeHidden, s = !!t.includeNodeModules;
2285
+ let i = 0, o = !1;
2286
+ function a(c) {
2287
+ if (o) return [];
2288
+ const u = c ? we(e, c) : e;
2289
+ let l = [];
2290
+ try {
2291
+ l = d.readdirSync(u, { withFileTypes: !0 });
2292
+ } catch {
2293
+ return [];
2294
+ }
2295
+ const p = l.filter((g) => !r && g.name.startsWith(".") ? !1 : g.isDirectory() ? g.name === "node_modules" && !s ? !1 : !Sr.has(g.name) : g.isFile()).sort((g, x) => g.isDirectory() !== x.isDirectory() ? g.isDirectory() ? -1 : 1 : g.name.localeCompare(x.name)), m = [];
2296
+ for (const g of p) {
2297
+ if (o) break;
2298
+ if (i += 1, i > kr) {
2299
+ o = !0;
2300
+ break;
2301
+ }
2302
+ const x = j(c ? `${c}/${g.name}` : g.name);
2303
+ g.isDirectory() ? m.push({
2304
+ name: g.name,
2305
+ relativePath: x,
2306
+ type: "directory",
2307
+ children: a(x)
2308
+ }) : m.push({
2309
+ name: g.name,
2310
+ relativePath: x,
2311
+ type: "file"
2312
+ });
2313
+ }
2314
+ return m;
2315
+ }
2316
+ return { nodes: a(""), truncated: o };
2317
+ }
2318
+ function Br(n, t) {
2319
+ if (!(t != null && t.trim())) throw new Error("File path is required.");
2320
+ const e = we(n, j(t));
2321
+ if (!d.existsSync(e)) throw new Error("File does not exist.");
2322
+ const r = d.statSync(e);
2323
+ if (!r.isFile()) throw new Error("Path is not a file.");
2324
+ const s = Math.min(r.size, Ve), i = Buffer.alloc(s), o = d.openSync(e, "r");
2325
+ try {
2326
+ d.readSync(o, i, 0, s, 0);
2327
+ } finally {
2328
+ d.closeSync(o);
2329
+ }
2330
+ const a = i.includes(0);
2331
+ return {
2332
+ relativePath: j(t),
2333
+ size: r.size,
2334
+ truncated: r.size > Ve,
2335
+ binary: a,
2336
+ content: a ? "" : i.toString("utf8")
2337
+ };
2338
+ }
2339
+ function zr(n, t) {
2340
+ if (!(t != null && t.trim())) throw new Error("File path is required.");
2341
+ const e = j(t), r = we(n, e);
2342
+ if (!d.existsSync(r)) throw new Error("File does not exist.");
2343
+ const s = d.statSync(r);
2344
+ if (!s.isFile()) throw new Error("Path is not a file.");
2345
+ const i = d.readFileSync(r), o = i.includes(0);
2346
+ return {
2347
+ relativePath: e,
2348
+ size: s.size,
2349
+ binary: o,
2350
+ content: o ? "" : i.toString("utf8")
2351
+ };
2352
+ }
2353
+ function qr(n, t, e) {
2354
+ if (!(t != null && t.trim())) throw new Error("File path is required.");
2355
+ const r = j(t), s = we(n, r);
2356
+ d.mkdirSync(h.dirname(s), { recursive: !0 }), d.writeFileSync(s, e ?? "", "utf8");
2357
+ const i = d.statSync(s);
2358
+ return {
2359
+ relativePath: r,
2360
+ size: i.size
2361
+ };
2362
+ }
2363
+ async function Kr(n, t) {
2364
+ const e = h.resolve(n);
2365
+ if (!d.existsSync(e)) throw new Error("Workspace path does not exist.");
2366
+ if (!d.statSync(e).isDirectory()) throw new Error("Workspace path is not a directory.");
2367
+ const r = j(t || "untitled.txt"), s = h.join(e, r.split("/").filter(Boolean).join(h.sep)), i = L.getFocusedWindow() ?? k ?? L.getAllWindows()[0] ?? void 0, o = await me.showSaveDialog(i, {
2368
+ title: "Save file as",
2369
+ defaultPath: s
2370
+ });
2371
+ if (o.canceled || !o.filePath) return null;
2372
+ const a = lt(e, o.filePath);
2373
+ if (!a) throw new Error("Save As path must be a file inside the workspace root.");
2374
+ return a;
2375
+ }
2376
+ async function Jr(n) {
2377
+ const t = h.resolve(n);
2378
+ if (!d.existsSync(t)) throw new Error("Workspace path does not exist.");
2379
+ if (!d.statSync(t).isDirectory()) throw new Error("Workspace path is not a directory.");
2380
+ const e = L.getFocusedWindow() ?? k ?? L.getAllWindows()[0] ?? void 0, r = await me.showOpenDialog(e, {
2381
+ title: "Open file",
2382
+ defaultPath: t,
2383
+ properties: ["openFile"]
2384
+ });
2385
+ if (r.canceled || r.filePaths.length === 0) return null;
2386
+ const s = r.filePaths[0];
2387
+ return lt(t, s);
2388
+ }
2389
+ function Gr(n) {
2390
+ let t = "(detached HEAD)", e = 0, r = 0;
2391
+ const s = [];
2392
+ for (const c of n.split(/\r?\n/)) {
2393
+ if (!c.trim()) continue;
2394
+ if (c.startsWith("## ")) {
2395
+ const y = c.slice(3).trim();
2396
+ t = y.split("...")[0].trim().replace(/\s+\[.*\]$/, "") || t;
2397
+ const v = y.match(/ahead (\d+)/), S = y.match(/behind (\d+)/);
2398
+ e = v ? Number.parseInt(v[1], 10) : 0, r = S ? Number.parseInt(S[1], 10) : 0;
2399
+ continue;
2400
+ }
2401
+ const u = c.slice(0, 2), l = c.slice(3).trim();
2402
+ if (!l) continue;
2403
+ let p = j(l), m;
2404
+ if (l.includes(" -> ")) {
2405
+ const [y, A] = l.split(" -> ");
2406
+ m = j(y.trim()), p = j(A.trim());
2407
+ }
2408
+ const g = u[0] ?? " ", x = u[1] ?? " ", E = u === "??", w = !E && g !== " ", b = !E && x !== " ";
2409
+ s.push({
2410
+ relativePath: p,
2411
+ indexStatus: g,
2412
+ workingTreeStatus: x,
2413
+ staged: w,
2414
+ unstaged: b,
2415
+ untracked: E,
2416
+ renamedFrom: m
2417
+ });
2418
+ }
2419
+ const i = s.filter((c) => c.staged).length, o = s.filter((c) => c.unstaged).length, a = s.filter((c) => c.untracked).length;
2420
+ return {
2421
+ ok: !0,
2422
+ branch: t,
2423
+ ahead: e,
2424
+ behind: r,
2425
+ stagedCount: i,
2426
+ unstagedCount: o,
2427
+ untrackedCount: a,
2428
+ clean: s.length === 0,
2429
+ entries: s,
2430
+ checkedAt: Date.now()
2431
+ };
2432
+ }
2433
+ function _(n) {
2434
+ if (n && typeof n == "object") {
2435
+ const t = n.stderr;
2436
+ if (typeof t == "string" && t.trim()) return t.trim();
2437
+ }
2438
+ return n instanceof Error && n.message ? n.message : "Unknown error.";
2439
+ }
2440
+ function Vr(n) {
2441
+ const t = h.resolve(n);
2442
+ if (!d.existsSync(t)) throw new Error("Workspace path does not exist.");
2443
+ if (!d.statSync(t).isDirectory()) throw new Error("Workspace path is not a directory.");
2444
+ return t;
2445
+ }
2446
+ function Me(n) {
2447
+ return h.join(n, hr, fr);
2448
+ }
2449
+ function he(n) {
2450
+ try {
2451
+ const t = d.readFileSync(n, "utf8"), e = JSON.parse(t);
2452
+ return !e || typeof e != "object" || e.app !== "Barnaby" || e.version !== 1 || typeof e.instanceId != "string" || !e.instanceId.trim() || typeof e.pid != "number" || !Number.isFinite(e.pid) || e.pid <= 0 || typeof e.hostname != "string" || typeof e.workspaceRoot != "string" || !e.workspaceRoot.trim() || typeof e.acquiredAt != "number" || !Number.isFinite(e.acquiredAt) || typeof e.heartbeatAt != "number" || !Number.isFinite(e.heartbeatAt) ? null : {
2453
+ version: 1,
2454
+ app: "Barnaby",
2455
+ instanceId: e.instanceId,
2456
+ pid: e.pid,
2457
+ hostname: e.hostname,
2458
+ workspaceRoot: e.workspaceRoot,
2459
+ acquiredAt: e.acquiredAt,
2460
+ heartbeatAt: e.heartbeatAt
2461
+ };
2462
+ } catch {
2463
+ return null;
2464
+ }
2465
+ }
2466
+ function Xr(n) {
2467
+ if (!Number.isFinite(n) || n <= 0) return !1;
2468
+ if (n === process.pid) return !0;
2469
+ try {
2470
+ return process.kill(n, 0), !0;
2471
+ } catch (t) {
2472
+ return t.code !== "ESRCH";
2473
+ }
2474
+ }
2475
+ function ke(n) {
2476
+ return n.instanceId === ct && n.pid === process.pid;
2477
+ }
2478
+ function Yr(n) {
2479
+ return ke(n) ? !1 : !Number.isFinite(n.heartbeatAt) || Date.now() - n.heartbeatAt > gr ? !0 : !Xr(n.pid);
2480
+ }
2481
+ function Ie(n, t, e) {
2482
+ const r = Date.now();
2483
+ return {
2484
+ version: 1,
2485
+ app: "Barnaby",
2486
+ instanceId: ct,
2487
+ pid: process.pid,
2488
+ hostname: Q.hostname(),
2489
+ workspaceRoot: n,
2490
+ acquiredAt: t ?? r,
2491
+ heartbeatAt: e ?? r
2492
+ };
2493
+ }
2494
+ function ae(n, t, e) {
2495
+ d.mkdirSync(h.dirname(n), { recursive: !0 }), d.writeFileSync(n, `${JSON.stringify(t, null, 2)}
2496
+ `, {
2497
+ encoding: "utf8",
2498
+ flag: e === "exclusive" ? "wx" : "w"
2499
+ });
2500
+ }
2501
+ function Ze() {
2502
+ H || (H = setInterval(() => {
2503
+ const n = Date.now();
2504
+ for (const [t, e] of W) {
2505
+ const r = he(e.lockFilePath);
2506
+ if (r && !ke(r)) {
2507
+ W.delete(t);
2508
+ continue;
2509
+ }
2510
+ const s = Ie(t, e.acquiredAt, n);
2511
+ try {
2512
+ ae(e.lockFilePath, s, "overwrite");
2513
+ } catch {
2514
+ }
2515
+ }
2516
+ W.size === 0 && H && (clearInterval(H), H = null);
2517
+ }, mr), typeof H.unref == "function" && H.unref());
2518
+ }
2519
+ function Zr(n) {
2520
+ let t = "";
2521
+ try {
2522
+ t = Vr(n);
2523
+ } catch (o) {
2524
+ const a = h.resolve(n || ".");
2525
+ return {
2526
+ ok: !1,
2527
+ reason: "invalid-workspace",
2528
+ message: _(o),
2529
+ workspaceRoot: a,
2530
+ lockFilePath: Me(a),
2531
+ owner: null
2532
+ };
2533
+ }
2534
+ const e = Me(t), r = W.get(t);
2535
+ if (r) {
2536
+ const o = Ie(t, r.acquiredAt, Date.now());
2537
+ try {
2538
+ ae(e, o, "overwrite");
2539
+ } catch (a) {
2540
+ return {
2541
+ ok: !1,
2542
+ reason: "error",
2543
+ message: _(a),
2544
+ workspaceRoot: t,
2545
+ lockFilePath: e
2546
+ };
2547
+ }
2548
+ return {
2549
+ ok: !0,
2550
+ workspaceRoot: t,
2551
+ lockFilePath: e
2552
+ };
2553
+ }
2554
+ const s = Ie(t);
2555
+ try {
2556
+ return ae(e, s, "exclusive"), W.set(t, { lockFilePath: e, acquiredAt: s.acquiredAt }), Ze(), {
2557
+ ok: !0,
2558
+ workspaceRoot: t,
2559
+ lockFilePath: e
2560
+ };
2561
+ } catch (o) {
2562
+ if (o.code !== "EEXIST")
2563
+ return {
2564
+ ok: !1,
2565
+ reason: "error",
2566
+ message: _(o),
2567
+ workspaceRoot: t,
2568
+ lockFilePath: e
2569
+ };
2570
+ }
2571
+ const i = he(e);
2572
+ if (i && !Yr(i))
2573
+ return {
2574
+ ok: !1,
2575
+ reason: "in-use",
2576
+ message: "Workspace is already open in another Barnaby instance.",
2577
+ workspaceRoot: t,
2578
+ lockFilePath: e,
2579
+ owner: {
2580
+ pid: i.pid,
2581
+ hostname: i.hostname,
2582
+ acquiredAt: i.acquiredAt,
2583
+ heartbeatAt: i.heartbeatAt
2584
+ }
2585
+ };
2586
+ try {
2587
+ ae(e, s, "overwrite");
2588
+ const o = he(e);
2589
+ return !o || !ke(o) ? {
2590
+ ok: !1,
2591
+ reason: "in-use",
2592
+ message: "Workspace lock was claimed by another Barnaby instance.",
2593
+ workspaceRoot: t,
2594
+ lockFilePath: e,
2595
+ owner: o ? {
2596
+ pid: o.pid,
2597
+ hostname: o.hostname,
2598
+ acquiredAt: o.acquiredAt,
2599
+ heartbeatAt: o.heartbeatAt
2600
+ } : null
2601
+ } : (W.set(t, { lockFilePath: e, acquiredAt: o.acquiredAt }), Ze(), {
2602
+ ok: !0,
2603
+ workspaceRoot: t,
2604
+ lockFilePath: e
2605
+ });
2606
+ } catch (o) {
2607
+ return {
2608
+ ok: !1,
2609
+ reason: "error",
2610
+ message: _(o),
2611
+ workspaceRoot: t,
2612
+ lockFilePath: e,
2613
+ owner: i ? {
2614
+ pid: i.pid,
2615
+ hostname: i.hostname,
2616
+ acquiredAt: i.acquiredAt,
2617
+ heartbeatAt: i.heartbeatAt
2618
+ } : null
2619
+ };
2620
+ }
2621
+ }
2622
+ function yt(n) {
2623
+ var i;
2624
+ const t = h.resolve(n), e = ((i = W.get(t)) == null ? void 0 : i.lockFilePath) ?? Me(t);
2625
+ let r = !1;
2626
+ const s = he(e);
2627
+ if (s && ke(s))
2628
+ try {
2629
+ d.rmSync(e, { force: !0 }), r = !0;
2630
+ } catch {
2631
+ }
2632
+ return W.delete(t), W.size === 0 && H && (clearInterval(H), H = null), r;
2633
+ }
2634
+ function wt() {
2635
+ const n = [...W.keys()];
2636
+ for (const t of n)
2637
+ yt(t);
2638
+ }
2639
+ function vt(n, t) {
2640
+ if (process.platform === "win32") {
2641
+ const e = [n, ...t].map((r) => r.includes(" ") ? `"${r}"` : r).join(" ");
2642
+ return N(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", e], {
2643
+ windowsHide: !0,
2644
+ maxBuffer: 1024 * 1024
2645
+ });
2646
+ }
2647
+ return N(n, t, {
2648
+ windowsHide: !0,
2649
+ maxBuffer: 1024 * 1024
2650
+ });
2651
+ }
2652
+ async function Qr(n) {
2653
+ try {
2654
+ return await vt(n, ["--version"]), !0;
2655
+ } catch {
2656
+ return !1;
2657
+ }
2658
+ }
2659
+ async function en(n) {
2660
+ if ((n.type ?? (n.id === "openrouter" ? "api" : "cli")) === "api") {
2661
+ const i = pe(n.id), o = (n.apiBaseUrl ?? "https://openrouter.ai/api/v1").replace(/\/+$/, "");
2662
+ if (!i)
2663
+ return {
2664
+ provider: n.id,
2665
+ installed: !0,
2666
+ authenticated: !1,
2667
+ detail: "API key not configured. Add your key in Settings -> Connectivity.",
2668
+ checkedAt: Date.now()
2669
+ };
2670
+ try {
2671
+ const a = await fetch(`${o}/models`, {
2672
+ headers: {
2673
+ Authorization: `Bearer ${i}`,
2674
+ "HTTP-Referer": "https://barnaby.build",
2675
+ "X-Title": "Barnaby"
2676
+ },
2677
+ signal: AbortSignal.timeout(1e4)
2678
+ });
2679
+ if (a.ok)
2680
+ return {
2681
+ provider: n.id,
2682
+ installed: !0,
2683
+ authenticated: !0,
2684
+ detail: "API key is valid.",
2685
+ checkedAt: Date.now()
2686
+ };
2687
+ const c = await a.text().catch(() => "");
2688
+ return {
2689
+ provider: n.id,
2690
+ installed: !0,
2691
+ authenticated: !1,
2692
+ detail: `API check failed (${a.status}). ${c.slice(0, 200)}`.trim(),
2693
+ checkedAt: Date.now()
2694
+ };
2695
+ } catch (a) {
2696
+ return {
2697
+ provider: n.id,
2698
+ installed: !0,
2699
+ authenticated: !1,
2700
+ detail: _(a) || "API check failed.",
2701
+ checkedAt: Date.now()
2702
+ };
2703
+ }
2704
+ }
2705
+ const e = n.cliPath ?? n.cliCommand ?? "", r = (n.authCheckCommand ?? "--version").trim().split(/\s+/).filter(Boolean), s = n.id === "codex";
2706
+ try {
2707
+ const i = await vt(e, r), o = `${i.stdout ?? ""}
2708
+ ${i.stderr ?? ""}`.trim(), a = o.toLowerCase();
2709
+ let c;
2710
+ return s ? c = a.includes("logged in") && !a.includes("not logged in") : c = !0, {
2711
+ provider: n.id,
2712
+ installed: !0,
2713
+ authenticated: c,
2714
+ detail: o || (c ? "Logged in." : "Not logged in."),
2715
+ checkedAt: Date.now()
2716
+ };
2717
+ } catch (i) {
2718
+ const o = _(i), a = await Qr(e);
2719
+ return {
2720
+ provider: n.id,
2721
+ installed: a,
2722
+ authenticated: !1,
2723
+ detail: o || (a ? "Login required." : `${n.id} CLI not found.`),
2724
+ checkedAt: Date.now()
2725
+ };
2726
+ }
2727
+ }
2728
+ async function tn(n) {
2729
+ if ((n.type ?? (n.id === "openrouter" ? "api" : "cli")) === "api") {
2730
+ const r = n.loginUrl || "https://openrouter.ai/keys";
2731
+ return await z.openExternal(r), { started: !0, detail: `Opened ${n.id} key management page.` };
2732
+ }
2733
+ const e = n.loginCommand ?? n.cliCommand;
2734
+ return e ? process.platform === "win32" ? (await N(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "start", "", "cmd", "/k", e], {
2735
+ windowsHide: !0
2736
+ }), {
2737
+ started: !0,
2738
+ detail: `Opened terminal for ${n.id} login.`
2739
+ }) : (await N("sh", ["-lc", e], { windowsHide: !0 }), { started: !0, detail: `Launched ${n.id} login.` }) : { started: !1, detail: `No login command configured for ${n.id}.` };
2740
+ }
2741
+ async function rn(n) {
2742
+ const t = n.upgradePackage, e = n.upgradeCommand, r = t ? process.platform === "win32" ? `npm uninstall -g ${t} & npm install -g ${t}@latest` : `npm uninstall -g ${t}; npm install -g ${t}@latest` : e;
2743
+ if (!r)
2744
+ return { started: !1, detail: `No upgrade command configured for ${n.id}.` };
2745
+ if (process.platform === "win32")
2746
+ return await N(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "start", "", "cmd", "/k", r], {
2747
+ windowsHide: !0
2748
+ }), {
2749
+ started: !0,
2750
+ detail: `Opened terminal to upgrade ${n.id} CLI. Run the command shown, then close the window.`
2751
+ };
2752
+ if (process.platform === "darwin") {
2753
+ const s = r.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
2754
+ return await N("osascript", [
2755
+ "-e",
2756
+ `tell application "Terminal" to do script "${s}"`
2757
+ ]), {
2758
+ started: !0,
2759
+ detail: `Opened Terminal to upgrade ${n.id} CLI. Close the window when done.`
2760
+ };
2761
+ }
2762
+ return await N("sh", ["-lc", r], { windowsHide: !0 }), { started: !0, detail: `Ran ${n.id} CLI upgrade. Re-check connectivity.` };
2763
+ }
2764
+ const nn = "Output a JSON array of model IDs you support. Use names like gemini-2.5-flash, gemini-2.5-pro, gemini-3-pro-preview. Output only the JSON array, no markdown or other text.", sn = 'Output only a JSON array of model IDs from the Codex CLI /model menu. Example: ["gpt-5.3-codex","gpt-5.2-codex"]. No other text.';
2765
+ async function on() {
2766
+ return new Promise((t, e) => {
2767
+ var a, c, u;
2768
+ const r = ["exec", "--sandbox", "read-only", "--json", sn], s = process.platform === "win32" ? I("codex", r, {
2769
+ stdio: ["pipe", "pipe", "pipe"],
2770
+ windowsHide: !0
2771
+ }) : I("codex", r, { stdio: ["pipe", "pipe", "pipe"] });
2772
+ let i = "";
2773
+ (a = s.stdout) == null || a.setEncoding("utf8"), (c = s.stdout) == null || c.on("data", (l) => {
2774
+ i += l;
2775
+ }), (u = s.stderr) == null || u.on("data", () => {
2776
+ });
2777
+ const o = setTimeout(() => {
2778
+ s.kill("SIGTERM"), e(new Error("Codex CLI models query timed out"));
2779
+ }, 12e4);
2780
+ s.on("error", (l) => {
2781
+ clearTimeout(o), e(l);
2782
+ }), s.on("exit", (l, p) => {
2783
+ var m, g;
2784
+ clearTimeout(o);
2785
+ try {
2786
+ for (const x of i.split(`
2787
+ `)) {
2788
+ const E = x.trim();
2789
+ if (!E.startsWith('{"type":"item.completed"')) continue;
2790
+ const w = JSON.parse(E);
2791
+ if (((m = w.item) == null ? void 0 : m.type) !== "agent_message" || !((g = w.item) != null && g.text)) continue;
2792
+ let b = w.item.text.trim();
2793
+ const y = b.match(/```(?:json)?\s*([\s\S]*?)```/);
2794
+ y && (b = y[1].trim());
2795
+ const A = JSON.parse(b);
2796
+ if (!Array.isArray(A)) continue;
2797
+ const v = A.filter((S) => typeof S == "string" && S.length > 0).map((S) => ({
2798
+ id: S,
2799
+ displayName: S
2800
+ }));
2801
+ t(v);
2802
+ return;
2803
+ }
2804
+ t([]);
2805
+ } catch {
2806
+ t([]);
2807
+ }
2808
+ });
2809
+ });
2810
+ }
2811
+ async function an() {
2812
+ let n = await on().catch(() => []), t = [
2813
+ { id: "sonnet", displayName: "sonnet" },
2814
+ { id: "opus", displayName: "opus" },
2815
+ { id: "haiku", displayName: "haiku" }
2816
+ ], e = await kt().catch(() => []), r = await cn().catch(() => []);
2817
+ return r.length === 0 && (r = [{ id: "openrouter/auto", displayName: "openrouter/auto" }]), n.length === 0 && (n = [
2818
+ { id: "gpt-5.3-codex", displayName: "gpt-5.3-codex" },
2819
+ { id: "gpt-5.2-codex", displayName: "gpt-5.2-codex" },
2820
+ { id: "gpt-5.1-codex", displayName: "gpt-5.1-codex" },
2821
+ { id: "gpt-4o", displayName: "gpt-4o" },
2822
+ { id: "gpt-4o-mini", displayName: "gpt-4o-mini" },
2823
+ { id: "gpt-4-turbo", displayName: "gpt-4-turbo" }
2824
+ ]), e.length === 0 && (e = [{ id: "gemini-2.5-flash", displayName: "gemini-2.5-flash" }, { id: "gemini-2.5-pro", displayName: "gemini-2.5-pro" }]), { codex: n, claude: t, gemini: e, openrouter: r };
2825
+ }
2826
+ async function cn() {
2827
+ try {
2828
+ const n = await fetch("https://openrouter.ai/api/v1/models", { signal: AbortSignal.timeout(1e4) });
2829
+ if (!n.ok) return [];
2830
+ const t = await n.json(), r = (Array.isArray(t == null ? void 0 : t.data) ? t.data : []).filter((i) => typeof (i == null ? void 0 : i.id) == "string").map((i) => {
2831
+ var o, a;
2832
+ return {
2833
+ id: String(i.id),
2834
+ displayName: String(i.id),
2835
+ isFree: String(i == null ? void 0 : i.id).includes(":free") || ((o = i == null ? void 0 : i.pricing) == null ? void 0 : o.prompt) === "0" && ((a = i == null ? void 0 : i.pricing) == null ? void 0 : a.completion) === "0"
2836
+ };
2837
+ }), s = r.filter((i) => i.isFree).slice(0, 24);
2838
+ return s.length > 0 ? s.map(({ id: i, displayName: o }) => ({ id: i, displayName: o })) : r.slice(0, 24).map(({ id: i, displayName: o }) => ({ id: i, displayName: o }));
2839
+ } catch {
2840
+ return [];
2841
+ }
2842
+ }
2843
+ async function kt() {
2844
+ return new Promise((t, e) => {
2845
+ var a, c, u;
2846
+ const r = ["-o", "json", "-p", nn], s = process.platform === "win32" ? I(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "gemini", ...r], {
2847
+ stdio: ["pipe", "pipe", "pipe"],
2848
+ windowsHide: !0
2849
+ }) : I("gemini", r, { stdio: ["pipe", "pipe", "pipe"] });
2850
+ let i = "";
2851
+ (a = s.stdout) == null || a.setEncoding("utf8"), (c = s.stdout) == null || c.on("data", (l) => {
2852
+ i += l;
2853
+ }), (u = s.stderr) == null || u.on("data", () => {
2854
+ });
2855
+ const o = setTimeout(() => {
2856
+ s.kill("SIGTERM"), e(new Error("Gemini CLI models query timed out"));
2857
+ }, 45e3);
2858
+ s.on("error", (l) => {
2859
+ clearTimeout(o), e(l);
2860
+ }), s.on("exit", (l, p) => {
2861
+ var m;
2862
+ if (clearTimeout(o), l !== 0 && !p) {
2863
+ e(new Error(`Gemini CLI exited with code ${l}`));
2864
+ return;
2865
+ }
2866
+ try {
2867
+ const g = JSON.parse(i), x = (m = g == null ? void 0 : g.response) == null ? void 0 : m.trim();
2868
+ if (!x) {
2869
+ t([]);
2870
+ return;
2871
+ }
2872
+ let E = x;
2873
+ const w = x.match(/```(?:json)?\s*([\s\S]*?)```/);
2874
+ w && (E = w[1].trim());
2875
+ const b = JSON.parse(E);
2876
+ if (!Array.isArray(b)) {
2877
+ t([]);
2878
+ return;
2879
+ }
2880
+ const y = b.filter((A) => typeof A == "string" && A.length > 0).map((A) => ({
2881
+ id: A.replace(/^models\//, ""),
2882
+ displayName: A.replace(/^models\//, "")
2883
+ }));
2884
+ t(y);
2885
+ } catch {
2886
+ t([]);
2887
+ }
2888
+ });
2889
+ });
2890
+ }
2891
+ function ln(n) {
2892
+ const t = [], e = [], r = [], s = [];
2893
+ for (const l of n)
2894
+ l.untracked ? e.push(l.relativePath) : l.renamedFrom ? s.push({ from: l.renamedFrom, to: l.relativePath }) : l.indexStatus === "D" || l.workingTreeStatus === "D" ? r.push(l.relativePath) : l.indexStatus === "A" || l.indexStatus === "?" ? e.push(l.relativePath) : t.push(l.relativePath);
2895
+ const i = t.length + e.length + r.length + s.length, o = [];
2896
+ t.length && o.push(`${t.length} modified`), e.length && o.push(`${e.length} added`), r.length && o.push(`${r.length} deleted`), s.length && o.push(`${s.length} renamed`);
2897
+ const a = i > 0 ? `Commit workspace changes (${o.join(", ")})` : "Commit workspace changes", c = [];
2898
+ t.length && c.push("Modified:", ...t.map((l) => ` - ${l}`), ""), e.length && c.push("Added:", ...e.map((l) => ` - ${l}`), ""), r.length && c.push("Deleted:", ...r.map((l) => ` - ${l}`), ""), s.length && c.push("Renamed:", ...s.map((l) => ` - ${l.from} -> ${l.to}`), "");
2899
+ const u = c.join(`
2900
+ `).trim();
2901
+ return { subject: a, body: u || "No changes" };
2902
+ }
2903
+ async function Re(n, t) {
2904
+ try {
2905
+ const { stdout: e, stderr: r } = await N("git", ["-C", n, ...t], {
2906
+ windowsHide: !0,
2907
+ maxBuffer: 1048576
2908
+ });
2909
+ return { ok: !0, stdout: e == null ? void 0 : e.trim(), stderr: r == null ? void 0 : r.trim() };
2910
+ } catch (e) {
2911
+ const r = e && typeof e == "object" && "stderr" in e ? String(e.stderr ?? "") : "";
2912
+ return { ok: !1, error: (e instanceof Error ? e.message : "Unknown error") || r, stderr: r };
2913
+ }
2914
+ }
2915
+ async function je(n, t, e) {
2916
+ return new Promise((r) => {
2917
+ var a, c, u, l;
2918
+ const s = I(t, e, {
2919
+ cwd: n,
2920
+ shell: !0,
2921
+ stdio: ["ignore", "pipe", "pipe"],
2922
+ windowsHide: !0
2923
+ });
2924
+ let i = "", o = "";
2925
+ (a = s.stdout) == null || a.setEncoding("utf8"), (c = s.stdout) == null || c.on("data", (p) => {
2926
+ i += p;
2927
+ }), (u = s.stderr) == null || u.setEncoding("utf8"), (l = s.stderr) == null || l.on("data", (p) => {
2928
+ o += p;
2929
+ }), s.on("error", (p) => r({ ok: !1, error: p.message })), s.on("exit", (p) => {
2930
+ r(p === 0 ? { ok: !0, stdout: i, stderr: o } : { ok: !1, error: o || `Exit code ${p}`, stdout: i, stderr: o });
2931
+ });
2932
+ });
2933
+ }
2934
+ function bt(n) {
2935
+ if (!Array.isArray(n)) return [];
2936
+ const t = [];
2937
+ for (const e of n) {
2938
+ if (typeof e != "string") continue;
2939
+ const r = j(e).trim();
2940
+ if (!r || r.startsWith("/")) continue;
2941
+ const s = r.split("/").filter((i) => i && i !== "." && i !== "..").join("/");
2942
+ s && (t.includes(s) || t.push(s));
2943
+ }
2944
+ return t;
2945
+ }
2946
+ function dn(n, t) {
2947
+ if (t.length === 0)
2948
+ return {
2949
+ selectedEntries: n,
2950
+ pathspecs: [],
2951
+ hasSelection: !1
2952
+ };
2953
+ const e = new Map(n.map((i) => [i.relativePath, i])), r = [];
2954
+ for (const i of t) {
2955
+ const o = e.get(i);
2956
+ o && r.push(o);
2957
+ }
2958
+ const s = [];
2959
+ for (const i of r)
2960
+ s.includes(i.relativePath) || s.push(i.relativePath), i.renamedFrom && !s.includes(i.renamedFrom) && s.push(i.renamedFrom);
2961
+ return {
2962
+ selectedEntries: r,
2963
+ pathspecs: s,
2964
+ hasSelection: !0
2965
+ };
2966
+ }
2967
+ function un(n) {
2968
+ if (!n) return !1;
2969
+ const t = n.toLowerCase();
2970
+ return t.includes("nothing to commit") || t.includes("no changes");
2971
+ }
2972
+ async function St(n, t) {
2973
+ const e = h.resolve(n), r = await At(e);
2974
+ if (!r.ok || r.clean)
2975
+ return { ok: !1, error: r.clean ? "Nothing to commit." : r.error ?? "Cannot read git status." };
2976
+ const s = bt(t), i = dn(r.entries, s);
2977
+ if (i.hasSelection && i.selectedEntries.length === 0)
2978
+ return { ok: !1, error: "Selected files no longer have changes." };
2979
+ const o = i.selectedEntries, a = i.hasSelection ? ["add", "-A", "--", ...i.pathspecs] : ["add", "-A"], c = await Re(e, a);
2980
+ if (!c.ok) return { ok: !1, error: c.error ?? "git add failed" };
2981
+ const u = ln(o), l = ["commit", "-m", u.subject, "-m", u.body];
2982
+ i.hasSelection && l.push("--", ...i.pathspecs);
2983
+ const p = await Re(e, l);
2984
+ return p.ok ? { ok: !0 } : { ok: !1, error: p.error ?? "git commit failed" };
2985
+ }
2986
+ async function pn(n, t) {
2987
+ const e = h.resolve(n), r = bt(t);
2988
+ if (r.length > 0) {
2989
+ const i = await St(e, r);
2990
+ if (!i.ok && !un(i.error))
2991
+ return i;
2992
+ }
2993
+ const s = await Re(e, ["push"]);
2994
+ return { ok: s.ok, error: s.error };
2995
+ }
2996
+ async function hn(n, t) {
2997
+ var o;
2998
+ const e = h.resolve(n), r = h.join(e, "package.json");
2999
+ if (!d.existsSync(r)) return { ok: !1, error: "No package.json found." };
3000
+ const s = JSON.parse(d.readFileSync(r, "utf8"));
3001
+ if (!((o = s == null ? void 0 : s.scripts) != null && o.deploy)) return { ok: !1, error: "No deploy script in package.json." };
3002
+ const i = await je(e, "npm", ["run", "deploy"]);
3003
+ return { ok: i.ok, error: i.error };
3004
+ }
3005
+ async function fn(n, t) {
3006
+ var o;
3007
+ const e = h.resolve(n), r = h.join(e, "package.json");
3008
+ if (!d.existsSync(r)) return { ok: !1, error: "No package.json found." };
3009
+ const s = JSON.parse(d.readFileSync(r, "utf8"));
3010
+ if (!((o = s == null ? void 0 : s.scripts) != null && o.build)) return { ok: !1, error: "No build script in package.json." };
3011
+ const i = await je(e, "npm", ["run", "build"]);
3012
+ return { ok: i.ok, error: i.error };
3013
+ }
3014
+ async function mn(n, t) {
3015
+ const e = h.resolve(n), r = await je(e, "gh", ["workflow", "run", "release.yml", "-f", "releasable=true", "--ref", "main"]);
3016
+ return { ok: r.ok, error: r.error };
3017
+ }
3018
+ async function At(n) {
3019
+ const t = h.resolve(n), e = {
3020
+ branch: "(not a git repository)",
3021
+ ahead: 0,
3022
+ behind: 0,
3023
+ stagedCount: 0,
3024
+ unstagedCount: 0,
3025
+ untrackedCount: 0,
3026
+ clean: !0,
3027
+ entries: [],
3028
+ checkedAt: Date.now()
3029
+ };
3030
+ try {
3031
+ if (!(await N("git", ["-C", t, "rev-parse", "--is-inside-work-tree"], {
3032
+ windowsHide: !0,
3033
+ maxBuffer: 1048576
3034
+ })).stdout.trim().startsWith("true"))
3035
+ return { ok: !1, ...e, error: "This workspace is not inside a git repository." };
3036
+ } catch (r) {
3037
+ return { ok: !1, ...e, error: _(r) };
3038
+ }
3039
+ try {
3040
+ const r = await N("git", ["-C", t, "status", "--short", "--branch"], {
3041
+ windowsHide: !0,
3042
+ maxBuffer: 1048576
3043
+ });
3044
+ return Gr(r.stdout);
3045
+ } catch (r) {
3046
+ return { ok: !1, ...e, error: _(r) };
3047
+ }
3048
+ }
3049
+ function te(n, t) {
3050
+ k == null || k.webContents.send("agentorchestrator:event", { agentWindowId: n, evt: t }), k == null || k.webContents.send("fireharness:event", { agentWindowId: n, evt: t }), ir(n, t), (t == null ? void 0 : t.type) === "assistantCompleted" && or(n);
3051
+ }
3052
+ async function xt(n, t) {
3053
+ var o, a;
3054
+ const e = t.provider ?? "codex", r = M.get(n);
3055
+ if (r && (await r.close(), M.delete(n)), e === "gemini") {
3056
+ const c = new Pe();
3057
+ c.on("event", (l) => te(n, l));
3058
+ const u = await c.connect({
3059
+ model: t.model,
3060
+ cwd: t.cwd,
3061
+ initialHistory: t.initialHistory
3062
+ });
3063
+ return M.set(n, c), { client: c, result: u };
3064
+ }
3065
+ if (e === "claude") {
3066
+ const c = new Ht();
3067
+ c.on("event", (l) => te(n, l));
3068
+ const u = await c.connect({
3069
+ cwd: t.cwd,
3070
+ model: t.model,
3071
+ permissionMode: t.permissionMode,
3072
+ initialHistory: t.initialHistory
3073
+ });
3074
+ return M.set(n, c), { client: c, result: u };
3075
+ }
3076
+ if (e === "openrouter") {
3077
+ const c = new Bt();
3078
+ c.on("event", (p) => te(n, p));
3079
+ const u = pe("openrouter");
3080
+ if (!u) throw new Error("OpenRouter API key is missing. Open Settings -> Connectivity and add it.");
3081
+ const l = await c.connect({
3082
+ cwd: t.cwd,
3083
+ model: t.model,
3084
+ apiKey: u,
3085
+ baseUrl: (o = t.modelConfig) == null ? void 0 : o.openrouterBaseUrl,
3086
+ initialHistory: t.initialHistory
3087
+ });
3088
+ return M.set(n, c), { client: c, result: l };
3089
+ }
3090
+ if (e === "codex" && ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo"].includes(t.model)) {
3091
+ const l = new Vt();
3092
+ l.on("event", (g) => te(n, g));
3093
+ const p = pe("codex");
3094
+ if (!p) throw new Error("OpenAI API key is missing. Add it in Settings -> Connectivity (OpenAI card, API key).");
3095
+ const m = await l.connect({
3096
+ cwd: t.cwd,
3097
+ model: t.model,
3098
+ apiKey: p,
3099
+ baseUrl: ((a = t.modelConfig) == null ? void 0 : a.openaiBaseUrl) ?? "https://api.openai.com/v1",
3100
+ permissionMode: t.permissionMode,
3101
+ sandbox: t.sandbox,
3102
+ allowedCommandPrefixes: t.allowedCommandPrefixes,
3103
+ initialHistory: t.initialHistory
3104
+ });
3105
+ return M.set(n, l), { client: l, result: m };
3106
+ }
3107
+ const s = new Lt();
3108
+ s.on("event", (c) => {
3109
+ te(n, c), (c == null ? void 0 : c.type) === "status" && c.status === "closed" && M.delete(n);
3110
+ });
3111
+ const i = await s.connect(t);
3112
+ return M.set(n, s), { client: s, result: i };
3113
+ }
3114
+ async function Pt() {
3115
+ ge(), ye(), Ce = !1, re = !1, oe = !1, ue = !1, B = Er(), oe = !!B, oe ? ie = setTimeout(() => {
3116
+ re = !0, $e();
3117
+ }, br) : re = !0;
3118
+ const { width: n, height: t } = _t.getPrimaryDisplay().workAreaSize, e = Math.floor(n / 5), r = Math.floor(t * 0.9), s = X ? "(DEV)" : `(V${$.getVersion()})`;
3119
+ k = new L({
3120
+ title: `Barnaby ${s}`,
3121
+ icon: h.join(process.env.VITE_PUBLIC, "appicon.png"),
3122
+ show: !1,
3123
+ width: e,
3124
+ height: r,
3125
+ webPreferences: {
3126
+ preload: ot
3127
+ // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
3128
+ // nodeIntegration: true,
3129
+ // Consider using contextBridge.exposeInMainWorld
3130
+ // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
3131
+ // contextIsolation: false,
3132
+ }
3133
+ }), X ? (k.loadURL(X), k.webContents.openDevTools()) : k.loadFile(at), k.webContents.on("did-finish-load", () => {
3134
+ k == null || k.setTitle(`Barnaby ${s}`);
3135
+ }), k.once("ready-to-show", () => {
3136
+ Ce = !0, $e();
3137
+ }), k.webContents.setWindowOpenHandler(({ url: i }) => (i.startsWith("https:") && z.openExternal(i), { action: "deny" })), He();
3138
+ }
3139
+ $.whenReady().then(async () => {
3140
+ if (Pr()) {
3141
+ D("bare-electron-host-launch-blocked", { argv: process.argv }, "warn"), $.quit();
3142
+ return;
3143
+ }
3144
+ Wr(), D("app-start", { version: $.getVersion(), platform: process.platform, electron: process.versions.electron }), Tr(), await Pt(), k && (rr(k), nr(() => {
3145
+ for (const [n] of W) return n;
3146
+ return "";
3147
+ }), Qe($.getAppPath(), U).then(() => {
3148
+ k == null || k.webContents.send("barnaby:plugin-host:plugins-loaded");
3149
+ }).catch((n) => {
3150
+ console.error("[pluginHost] Initialization failed:", n);
3151
+ }));
3152
+ });
3153
+ $.on("window-all-closed", () => {
3154
+ k = null, ye(), ge(), wt(), De().catch(() => {
3155
+ });
3156
+ for (const n of M.values())
3157
+ n.close().catch(() => {
3158
+ });
3159
+ M.clear(), process.platform !== "darwin" && $.quit();
3160
+ });
3161
+ $.on("before-quit", () => {
3162
+ ye(), ge(), wt(), De().catch(() => {
3163
+ });
3164
+ for (const n of M.values())
3165
+ n.close().catch(() => {
3166
+ });
3167
+ M.clear();
3168
+ });
3169
+ $.on("activate", () => {
3170
+ const n = L.getAllWindows();
3171
+ n.length ? n[0].focus() : Pt();
3172
+ });
3173
+ f.handle("open-win", (n, t) => {
3174
+ const e = new L({
3175
+ webPreferences: {
3176
+ preload: ot,
3177
+ nodeIntegration: !0,
3178
+ contextIsolation: !1
3179
+ }
3180
+ });
3181
+ X ? e.loadURL(`${X}#${t}`) : e.loadFile(at, { hash: t });
3182
+ });
3183
+ f.handle("fireharness:connect", async (n, t) => {
3184
+ const { result: e } = await xt("default", t);
3185
+ return e;
3186
+ });
3187
+ f.handle("fireharness:sendMessage", async (n, t) => {
3188
+ const e = M.get("default");
3189
+ return e && await e.sendUserMessage(t), {};
3190
+ });
3191
+ f.handle("fireharness:interrupt", async () => {
3192
+ const n = M.get("default");
3193
+ return n && await n.interruptActiveTurn(), {};
3194
+ });
3195
+ f.handle("fireharness:disconnect", async () => {
3196
+ const n = M.get("default");
3197
+ return n ? (await n.close(), M.delete("default"), {}) : {};
3198
+ });
3199
+ f.handle("agentorchestrator:connect", async (n, t, e) => {
3200
+ const { result: r } = await xt(t, e);
3201
+ return r;
3202
+ });
3203
+ f.handle("agentorchestrator:sendMessage", async (n, t, e) => {
3204
+ const r = M.get(t);
3205
+ return r && await r.sendUserMessage(e), {};
3206
+ });
3207
+ function gn(n) {
3208
+ if (!n.length) return "";
3209
+ const t = n.filter((e) => e.role === "user" || e.role === "assistant").map((e) => `${e.role === "user" ? "User" : "Assistant"}:
3210
+ ${(e.content ?? "").trim()}`).filter((e) => e.length > 0).join(`
3211
+
3212
+ `);
3213
+ return t ? `Previous conversation:
3214
+
3215
+ ${t}
3216
+
3217
+ User continues: ` : "";
3218
+ }
3219
+ f.handle("agentorchestrator:sendMessageEx", async (n, t, e) => {
3220
+ const r = M.get(t);
3221
+ if (!r) return {};
3222
+ let s = typeof (e == null ? void 0 : e.text) == "string" ? e.text : "";
3223
+ const i = Array.isArray(e == null ? void 0 : e.imagePaths) ? e.imagePaths.filter((a) => typeof a == "string" && a.trim().length > 0) : [], o = Array.isArray(e == null ? void 0 : e.priorMessagesForContext) ? e.priorMessagesForContext : [];
3224
+ if (o.length > 0) {
3225
+ const a = gn(o.slice(-24));
3226
+ a && (s = a + s);
3227
+ }
3228
+ if (i.length > 0) {
3229
+ const a = r;
3230
+ if (typeof a.sendUserMessageWithImages != "function")
3231
+ throw new Error("Selected provider does not support image attachments in this app yet.");
3232
+ return await a.sendUserMessageWithImages(s, i), {};
3233
+ }
3234
+ return await r.sendUserMessage(s), {};
3235
+ });
3236
+ f.handle("agentorchestrator:loadChatHistory", async () => jr());
3237
+ f.handle("agentorchestrator:saveChatHistory", async (n, t) => Hr(t));
3238
+ f.handle("agentorchestrator:loadAppState", async () => $r());
3239
+ f.handle("agentorchestrator:saveAppState", async (n, t) => _r(t));
3240
+ f.handle("agentorchestrator:setWindowTheme", async (n, t) => {
3241
+ const e = t === "light" || t === "dark" || t === "system" ? t : "system";
3242
+ return Ae.themeSource = e, { ok: !0, themeSource: e, shouldUseDarkColors: Ae.shouldUseDarkColors };
3243
+ });
3244
+ f.handle("agentorchestrator:rendererReady", async () => (re = !0, $e(), { ok: !0 }));
3245
+ f.handle("agentorchestrator:getDiagnosticsInfo", async () => ht());
3246
+ f.handle("agentorchestrator:getLoadedPlugins", async () => {
3247
+ const n = lr();
3248
+ return Array.from(n.entries()).map(([t, e]) => ({
3249
+ pluginId: t,
3250
+ displayName: e.plugin.displayName,
3251
+ version: e.plugin.version,
3252
+ active: e.active
3253
+ }));
3254
+ });
3255
+ f.handle("agentorchestrator:openRuntimeLog", async () => Nr());
3256
+ f.handle("agentorchestrator:openDiagnosticsPath", async (n, t) => Rr(t));
3257
+ f.handle("agentorchestrator:readDiagnosticsFile", async (n, t) => Fr(t));
3258
+ f.handle("agentorchestrator:writeDiagnosticsFile", async (n, t, e) => Dr(t));
3259
+ f.handle("agentorchestrator:openExternalUrl", async (n, t) => {
3260
+ const e = typeof t == "string" ? t.trim() : "";
3261
+ if (!e) return { ok: !1, error: "URL is required." };
3262
+ let r;
3263
+ try {
3264
+ r = new URL(e);
3265
+ } catch {
3266
+ return { ok: !1, error: "Invalid URL." };
3267
+ }
3268
+ const s = r.protocol.toLowerCase();
3269
+ if (s !== "http:" && s !== "https:" && s !== "mailto:")
3270
+ return { ok: !1, error: `Unsupported URL protocol: ${s}` };
3271
+ try {
3272
+ return await z.openExternal(r.toString()), { ok: !0 };
3273
+ } catch (i) {
3274
+ return { ok: !1, error: _(i) };
3275
+ }
3276
+ });
3277
+ f.handle("agentorchestrator:getOrchestratorLicenseKeyState", async () => ({ hasKey: (Oe(U).licenseKey ?? "").trim().length > 0 }));
3278
+ f.handle("agentorchestrator:setOrchestratorLicenseKey", async (n, t) => {
3279
+ const e = typeof t == "string" ? t.trim() : "", r = Oe(U);
3280
+ return r.licenseKey = e || void 0, Xt(U, r), { ok: !0, hasKey: e.length > 0 };
3281
+ });
3282
+ f.handle("agentorchestrator:syncOrchestratorSettings", async (n, t) => {
3283
+ const e = t;
3284
+ if (!e || typeof e != "object" || Array.isArray(e)) return;
3285
+ const r = {};
3286
+ typeof e.orchestratorModel == "string" && (r.orchestratorModel = e.orchestratorModel), typeof e.workerProvider == "string" && (r.workerProvider = e.workerProvider), typeof e.workerModel == "string" && (r.workerModel = e.workerModel), typeof e.maxParallelPanels == "number" && e.maxParallelPanels >= 1 && e.maxParallelPanels <= 8 && (r.maxParallelPanels = e.maxParallelPanels), typeof e.maxTaskAttempts == "number" && e.maxTaskAttempts >= 1 && e.maxTaskAttempts <= 10 && (r.maxTaskAttempts = e.maxTaskAttempts), Zt(U, r);
3287
+ });
3288
+ f.handle("agentorchestrator:openPluginsFolder", async () => {
3289
+ const n = h.join(Q.homedir(), ".barnaby", "plugins");
3290
+ try {
3291
+ d.existsSync(n) || d.mkdirSync(n, { recursive: !0 });
3292
+ const t = await z.openPath(n);
3293
+ return t ? { ok: !1, error: t } : { ok: !0 };
3294
+ } catch (t) {
3295
+ return { ok: !1, error: _(t) };
3296
+ }
3297
+ });
3298
+ f.handle("agentorchestrator:installOrchestratorPlugin", async () => {
3299
+ const n = h.join(Q.homedir(), ".barnaby", "plugins");
3300
+ try {
3301
+ d.existsSync(n) || d.mkdirSync(n, { recursive: !0 });
3302
+ const t = h.join(n, "package.json");
3303
+ if (!d.existsSync(t)) {
3304
+ const { execSync: r } = await import("node:child_process");
3305
+ r("npm init -y", { cwd: n, stdio: "pipe" });
3306
+ }
3307
+ const { execSync: e } = await import("node:child_process");
3308
+ return e("npm install @barnaby.build/orchestrator", { cwd: n, stdio: "pipe" }), await De(), await Qe($.getAppPath(), U), k == null || k.webContents.send("barnaby:plugin-host:plugins-loaded"), { ok: !0 };
3309
+ } catch (t) {
3310
+ return { ok: !1, error: _(t) };
3311
+ }
3312
+ });
3313
+ f.handle("agentorchestrator:interrupt", async (n, t) => {
3314
+ const e = M.get(t);
3315
+ return e ? (await e.interruptActiveTurn(), {}) : {};
3316
+ });
3317
+ f.handle("agentorchestrator:disconnect", async (n, t) => {
3318
+ const e = M.get(t);
3319
+ return e ? (await e.close(), M.delete(t), {}) : {};
3320
+ });
3321
+ f.handle("agentorchestrator:openFolderDialog", async () => {
3322
+ const n = k ?? L.getFocusedWindow() ?? L.getAllWindows()[0] ?? void 0, t = await me.showOpenDialog(n, {
3323
+ properties: ["openDirectory"],
3324
+ title: "Select workspace folder"
3325
+ });
3326
+ return t.canceled || t.filePaths.length === 0 ? null : t.filePaths[0];
3327
+ });
3328
+ async function yn(n) {
3329
+ const t = h.resolve(n);
3330
+ try {
3331
+ if (process.platform === "win32") {
3332
+ const e = process.env.ComSpec ?? "cmd.exe";
3333
+ await N(e, ["/d", "/s", "/c", "start", "", "cmd", "/k", `cd /d "${t}"`], {
3334
+ windowsHide: !0
3335
+ });
3336
+ } else if (process.platform === "darwin") {
3337
+ const e = t.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3338
+ await N("osascript", [
3339
+ "-e",
3340
+ `tell application "Terminal" to do script "cd \\"${e}\\""`
3341
+ ]);
3342
+ } else {
3343
+ const e = I("gnome-terminal", ["--working-directory", t], { detached: !0, stdio: "ignore" });
3344
+ e.on("error", () => {
3345
+ I("xterm", ["-e", `cd "${t}" && exec ${process.env.SHELL ?? "bash"}`], {
3346
+ detached: !0,
3347
+ stdio: "ignore"
3348
+ }).unref();
3349
+ }), e.unref();
3350
+ }
3351
+ return { ok: !0 };
3352
+ } catch (e) {
3353
+ return { ok: !1, error: e instanceof Error ? e.message : String(e) };
3354
+ }
3355
+ }
3356
+ f.handle("agentorchestrator:openTerminalInWorkspace", async (n, t) => yn(t));
3357
+ f.handle("agentorchestrator:terminalSpawn", async (n, t) => {
3358
+ if (F) {
3359
+ try {
3360
+ F.kill();
3361
+ } catch {
3362
+ }
3363
+ F = null;
3364
+ }
3365
+ const e = ur();
3366
+ if (!e)
3367
+ return { ok: !1, error: "Terminal unavailable: node-pty not loaded. Rebuild with: npx electron-rebuild" };
3368
+ const r = process.env[process.platform === "win32" ? "COMSPEC" : "SHELL"] ?? (process.platform === "win32" ? "cmd.exe" : "/bin/bash"), s = h.resolve(t || process.env.HOME || process.env.USERPROFILE || process.cwd());
3369
+ try {
3370
+ return F = e.spawn(r, [], {
3371
+ name: "xterm-256color",
3372
+ cols: 80,
3373
+ rows: 24,
3374
+ cwd: s,
3375
+ env: process.env
3376
+ }), F.onData((i) => {
3377
+ k == null || k.webContents.send("agentorchestrator:terminalData", i);
3378
+ }), F.onExit(() => {
3379
+ F = null, k == null || k.webContents.send("agentorchestrator:terminalExit", {});
3380
+ }), { ok: !0 };
3381
+ } catch (i) {
3382
+ return F = null, { ok: !1, error: i instanceof Error ? i.message : String(i) };
3383
+ }
3384
+ });
3385
+ f.on("agentorchestrator:terminalWrite", (n, t) => {
3386
+ F && F.write(t);
3387
+ });
3388
+ f.handle("agentorchestrator:terminalResize", (n, t, e) => {
3389
+ F && F.resize(t, e);
3390
+ });
3391
+ f.handle("agentorchestrator:terminalDestroy", () => {
3392
+ if (F) {
3393
+ try {
3394
+ F.kill();
3395
+ } catch {
3396
+ }
3397
+ F = null;
3398
+ }
3399
+ });
3400
+ f.handle("agentorchestrator:writeWorkspaceConfig", async (n, t) => {
3401
+ const e = h.join(t, pr), r = { version: 1, agentorchestrator: !0 };
3402
+ return d.writeFileSync(e, JSON.stringify(r, null, 2), "utf8"), !0;
3403
+ });
3404
+ f.handle("agentorchestrator:claimWorkspace", async (n, t) => Zr(t));
3405
+ f.handle("agentorchestrator:releaseWorkspace", async (n, t) => t != null && t.trim() ? yt(t) : !1);
3406
+ f.handle("agentorchestrator:savePastedImage", async (n, t, e) => {
3407
+ const r = /^data:([^;]+);base64,(.+)$/.exec(String(t ?? ""));
3408
+ if (!r) throw new Error("Invalid image data");
3409
+ const s = r[1], i = r[2], o = (e && typeof e == "string" ? e : s).toLowerCase(), a = o.includes("jpeg") || o.includes("jpg") ? "jpg" : o.includes("webp") ? "webp" : o.includes("gif") ? "gif" : "png", c = h.join(Q.tmpdir(), "agentorchestrator", "pasted-images");
3410
+ d.mkdirSync(c, { recursive: !0 });
3411
+ const u = h.join(c, `paste-${Date.now()}-${Math.random().toString(16).slice(2)}.${a}`);
3412
+ return d.writeFileSync(u, Buffer.from(i, "base64")), { path: u, mimeType: o };
3413
+ });
3414
+ f.handle("agentorchestrator:listWorkspaceTree", async (n, t, e) => Ur(t, e));
3415
+ f.handle("agentorchestrator:readWorkspaceFile", async (n, t, e) => Br(t, e));
3416
+ f.handle("agentorchestrator:readWorkspaceTextFile", async (n, t, e) => zr(t, e));
3417
+ f.handle("agentorchestrator:writeWorkspaceFile", async (n, t, e, r) => qr(t, e, r));
3418
+ f.handle("agentorchestrator:pickWorkspaceSavePath", async (n, t, e) => Kr(t, e));
3419
+ f.handle("agentorchestrator:pickWorkspaceOpenPath", async (n, t) => Jr(t));
3420
+ f.handle("agentorchestrator:getGitStatus", async (n, t) => At(t));
3421
+ f.handle("agentorchestrator:gitCommit", async (n, t, e) => St(t, e));
3422
+ f.handle("agentorchestrator:gitPush", async (n, t, e) => pn(t, e));
3423
+ f.handle("agentorchestrator:gitDeploy", async (n, t, e) => hn(t));
3424
+ f.handle("agentorchestrator:gitBuild", async (n, t, e) => fn(t));
3425
+ f.handle("agentorchestrator:gitRelease", async (n, t, e) => mn(t));
3426
+ f.on("agentorchestrator:setRecentWorkspaces", (n, t) => {
3427
+ Ee = Array.isArray(t) ? t : [], He();
3428
+ });
3429
+ f.on("agentorchestrator:setEditorMenuState", (n, t) => {
3430
+ const e = !!t;
3431
+ de !== e && (de = e, He());
3432
+ });
3433
+ f.handle("agentorchestrator:getProviderAuthStatus", async (n, t) => en(t));
3434
+ f.handle("agentorchestrator:startProviderLogin", async (n, t) => tn(t));
3435
+ f.handle("agentorchestrator:upgradeProviderCli", async (n, t) => rn(t));
3436
+ f.handle("agentorchestrator:setProviderApiKey", async (n, t, e) => pt(t, e));
3437
+ f.handle("agentorchestrator:getProviderApiKeyState", async (n, t) => ({ hasKey: pe(t).length > 0 }));
3438
+ f.handle("agentorchestrator:importProviderApiKeyFromEnv", async (n, t) => Ir(t));
3439
+ f.handle("agentorchestrator:resetApplicationData", async () => {
3440
+ try {
3441
+ const n = $.getPath("userData"), t = h.join(n, Le), e = h.join(t, rt), r = h.join(t, tt), s = h.join(t, nt);
3442
+ d.existsSync(e) && d.unlinkSync(e), d.existsSync(r) && d.unlinkSync(r), d.existsSync(s) && d.unlinkSync(s);
3443
+ } catch (n) {
3444
+ console.error("Failed to reset application data:", n);
3445
+ }
3446
+ $.relaunch(), $.exit(0);
3447
+ });
3448
+ f.handle("agentorchestrator:getGeminiAvailableModels", async () => kt());
3449
+ f.handle("agentorchestrator:getAvailableModels", async () => an());
3450
+ f.handle("agentorchestrator:findInPage", async (n, t) => {
3451
+ const e = n.sender;
3452
+ !e || typeof t != "string" || !t.trim() || e.findInPage(t.trim(), { findNext: !1 });
3453
+ });
3454
+ f.handle("agentorchestrator:showContextMenu", async (n, t) => {
3455
+ const e = t === "input-selection" || t === "chat-selection" ? t : null;
3456
+ if (!e) return { ok: !1 };
3457
+ const r = e === "input-selection" ? [
3458
+ { label: "Undo", role: "undo" },
3459
+ { label: "Redo", role: "redo" },
3460
+ { type: "separator" },
3461
+ { label: "Cut", role: "cut" },
3462
+ { label: "Copy", role: "copy" },
3463
+ { label: "Paste", role: "paste" },
3464
+ { type: "separator" },
3465
+ { label: "Select All", role: "selectAll" }
3466
+ ] : [
3467
+ { label: "Copy", role: "copy" },
3468
+ { type: "separator" },
3469
+ { label: "Select All", role: "selectAll" }
3470
+ ], s = xe.buildFromTemplate(r), i = L.fromWebContents(n.sender) ?? L.getFocusedWindow() ?? L.getAllWindows()[0] ?? void 0;
3471
+ return !i || i.isDestroyed() ? { ok: !1 } : (s.popup({ window: i }), { ok: !0 });
3472
+ });
3473
+ function T(n, t) {
3474
+ const e = { action: n, ...t };
3475
+ k == null || k.webContents.send("agentorchestrator:menu", e), k == null || k.webContents.send("fireharness:menu", e);
3476
+ }
3477
+ function wn() {
3478
+ const n = process.env.VITE_PUBLIC ?? "", t = n ? h.join(n, "splash.png") : "";
3479
+ let e = "";
3480
+ try {
3481
+ t && d.existsSync(t) && (e = `data:image/png;base64,${d.readFileSync(t).toString("base64")}`);
3482
+ } catch (m) {
3483
+ D("about-splash-base64-failed", { splashImagePath: t, error: _(m) }, "warn");
3484
+ }
3485
+ const r = $.getVersion(), s = "Barnaby", i = "Barnaby is an autonomous agent desktop for developers. It orchestrates parallel agent loops directly through your local CLI subscriptions.", o = "No API keys, no middleman. Connect to Codex, Claude, and Gemini via your existing terminal sessions. Experience workspace-aware agents with flexible split layouts and intelligent provider routing.", a = "incendiosoftware@gmail.com", c = Ae.shouldUseDarkColors, u = {
3486
+ bg: c ? "#0b0b0b" : "#f5f5f5",
3487
+ text: c ? "#e0e0e0" : "#171717",
3488
+ h1: c ? "#ffffff" : "#0a0a0a",
3489
+ version: c ? "#888" : "#525252",
3490
+ description: c ? "#ffffff" : "#0a0a0a",
3491
+ blurb: c ? "#aaa" : "#404040",
3492
+ contact: c ? "#666" : "#737373",
3493
+ link: c ? "#4daafc" : "#2563eb",
3494
+ border: c ? "#222" : "#e5e5e5"
3495
+ }, l = `<!doctype html>
3496
+ <html lang="en">
3497
+ <head>
3498
+ <meta charset="utf-8" />
3499
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
3500
+ <title>About ${s}</title>
3501
+ <style>
3502
+ html, body {
3503
+ margin: 0;
3504
+ padding: 0;
3505
+ width: 100%;
3506
+ height: 100%;
3507
+ background: ${u.bg};
3508
+ color: ${u.text};
3509
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
3510
+ overflow: hidden;
3511
+ user-select: none;
3512
+ }
3513
+ .container {
3514
+ display: flex;
3515
+ flex-direction: column;
3516
+ align-items: center;
3517
+ justify-content: center;
3518
+ height: 100%;
3519
+ padding: 32px;
3520
+ text-align: center;
3521
+ }
3522
+ .splash-container {
3523
+ width: 320px;
3524
+ margin-bottom: 24px;
3525
+ }
3526
+ .splash-container img {
3527
+ width: 100%;
3528
+ height: auto;
3529
+ object-fit: contain;
3530
+ max-width: 300px;
3531
+ max-height: 300px;
3532
+ } h1 {
3533
+ margin: 0 0 4px 0;
3534
+ font-size: 24px;
3535
+ font-weight: 700;
3536
+ color: ${u.h1};
3537
+ }
3538
+ .version {
3539
+ color: ${u.version};
3540
+ font-size: 13px;
3541
+ margin-bottom: 24px;
3542
+ }
3543
+ .content {
3544
+ max-width: 440px;
3545
+ }
3546
+ .description {
3547
+ font-size: 16px;
3548
+ line-height: 1.5;
3549
+ margin-bottom: 12px;
3550
+ font-weight: 600;
3551
+ color: ${u.description};
3552
+ }
3553
+ .blurb {
3554
+ font-size: 14px;
3555
+ line-height: 1.5;
3556
+ color: ${u.blurb};
3557
+ margin-bottom: 32px;
3558
+ }
3559
+ .contact {
3560
+ font-size: 12px;
3561
+ color: ${u.contact};
3562
+ border-top: 1px solid ${u.border};
3563
+ padding-top: 16px;
3564
+ width: 100%;
3565
+ }
3566
+ .contact a {
3567
+ color: ${u.link};
3568
+ text-decoration: none;
3569
+ cursor: pointer;
3570
+ }
3571
+ </style>
3572
+ </head>
3573
+ <body>
3574
+ <div class="container">
3575
+ <div class="splash-container">
3576
+ <img src="${e}" alt="Barnaby Splash" />
3577
+ </div>
3578
+ <h1>${s}</h1>
3579
+ <div class="version">Version ${r}</div>
3580
+ <div class="content">
3581
+ <div class="description">${i}</div>
3582
+ <div class="blurb">${o}</div>
3583
+ </div>
3584
+ <div class="contact">
3585
+ Contact: <a href="mailto:${a}">${a}</a> | <a href="https://barnaby.build">barnaby.build</a>
3586
+ </div>
3587
+ </div>
3588
+ </body>
3589
+ </html>`, p = new L({
3590
+ width: 500,
3591
+ height: 540,
3592
+ resizable: !1,
3593
+ minimizable: !1,
3594
+ maximizable: !1,
3595
+ fullscreenable: !1,
3596
+ title: `About ${s}`,
3597
+ autoHideMenuBar: !0,
3598
+ backgroundColor: u.bg,
3599
+ parent: k ?? void 0,
3600
+ modal: !!k,
3601
+ show: !1,
3602
+ webPreferences: {
3603
+ nodeIntegration: !1,
3604
+ contextIsolation: !0
3605
+ }
3606
+ });
3607
+ p.setMenuBarVisibility(!1), p.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(l)}`), p.webContents.setWindowOpenHandler(({ url: m }) => ((m.startsWith("http:") || m.startsWith("https:") || m.startsWith("mailto:")) && z.openExternal(m), { action: "deny" })), p.once("ready-to-show", () => {
3608
+ p.show();
3609
+ });
3610
+ }
3611
+ function He() {
3612
+ const n = Ee.length > 0 ? Ee.slice(0, 10).map((e) => ({
3613
+ label: h.basename(e) || e,
3614
+ click: () => T("openWorkspace", { path: e })
3615
+ })) : [{ label: "(none)", enabled: !1 }], t = [
3616
+ {
3617
+ label: "File",
3618
+ submenu: [
3619
+ { label: "New Agent", accelerator: "CmdOrCtrl+Shift+N", click: () => T("newAgentWindow") },
3620
+ { label: "New Workspace", click: () => T("newWorkspace") },
3621
+ { label: "New File", accelerator: "CmdOrCtrl+N", click: () => T("newFile") },
3622
+ { type: "separator" },
3623
+ {
3624
+ label: "Open Agent",
3625
+ click: () => {
3626
+ Lr().then((e) => {
3627
+ !e.ok && e.error && me.showErrorBox("Open Agent", `Could not open agent history folder:
3628
+ ${e.error}`);
3629
+ });
3630
+ }
3631
+ },
3632
+ { label: "Open Workspace", click: () => T("openWorkspacePicker") },
3633
+ { label: "Open File", click: () => T("openFile") },
3634
+ { label: "Open Recent", submenu: n },
3635
+ { label: "Save", accelerator: "CmdOrCtrl+S", enabled: de, click: () => T("saveEditorFile") },
3636
+ { label: "Save As", accelerator: "CmdOrCtrl+Shift+S", enabled: de, click: () => T("saveEditorFileAs") },
3637
+ { type: "separator" },
3638
+ { label: "Close", accelerator: "CmdOrCtrl+W", click: () => T("closeFocused") },
3639
+ { label: "Close Workspace", click: () => T("closeWorkspace") },
3640
+ { label: "Exit", role: "quit" }
3641
+ ]
3642
+ },
3643
+ {
3644
+ label: "Edit",
3645
+ submenu: [
3646
+ { label: "Undo", role: "undo" },
3647
+ { label: "Redo", role: "redo" },
3648
+ { type: "separator" },
3649
+ { label: "Cut", role: "cut" },
3650
+ { label: "Copy", role: "copy" },
3651
+ { label: "Paste", role: "paste" },
3652
+ { label: "Find", accelerator: "CmdOrCtrl+F", click: () => T("findInPage") },
3653
+ { label: "Find in Files", accelerator: "CmdOrCtrl+Shift+F", click: () => T("findInFiles") },
3654
+ { type: "separator" },
3655
+ { label: "Connectivity", click: () => T("openConnectivity") },
3656
+ { label: "Models", click: () => T("openModelSetup") },
3657
+ { label: "Preferences", accelerator: "CmdOrCtrl+,", click: () => T("openPreferences") },
3658
+ { label: "Agents", click: () => T("openAgents") },
3659
+ { label: "Orchestrator", click: () => T("openOrchestrator") },
3660
+ { label: "Diagnostics", click: () => T("openDiagnostics") }
3661
+ ]
3662
+ },
3663
+ {
3664
+ label: "View",
3665
+ submenu: [
3666
+ {
3667
+ label: "Layout",
3668
+ submenu: [
3669
+ { label: "Tile Vertical (V)", click: () => T("layoutVertical") },
3670
+ { label: "Tile Horizontal (H)", click: () => T("layoutHorizontal") },
3671
+ { label: "Tile / Grid", click: () => T("layoutGrid") }
3672
+ ]
3673
+ },
3674
+ { label: "View Workspace Window", click: () => T("toggleWorkspaceWindow") },
3675
+ { label: "View Code Window", click: () => T("toggleCodeWindow") },
3676
+ { type: "separator" },
3677
+ { role: "reload" },
3678
+ { role: "toggleDevTools" },
3679
+ { type: "separator" },
3680
+ { label: "Reset Zoom", click: () => T("resetZoom") },
3681
+ { label: "Zoom In", click: () => T("zoomIn") },
3682
+ { label: "Zoom Out", click: () => T("zoomOut") },
3683
+ { type: "separator" },
3684
+ { role: "togglefullscreen" }
3685
+ ]
3686
+ },
3687
+ {
3688
+ label: "Help",
3689
+ submenu: [
3690
+ {
3691
+ label: "About Barnaby",
3692
+ click: () => {
3693
+ wn();
3694
+ }
3695
+ }
3696
+ ]
3697
+ }
3698
+ ];
3699
+ xe.setApplicationMenu(xe.buildFromTemplate(t));
3700
+ }
3701
+ export {
3702
+ _n as MAIN_DIST,
3703
+ it as RENDERER_DIST,
3704
+ X as VITE_DEV_SERVER_URL
3705
+ };