aisnitch 0.2.20 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1,4 +1,739 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
13
+ import fs from "fs";
14
+ function hasDockerEnv() {
15
+ try {
16
+ fs.statSync("/.dockerenv");
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ function hasDockerCGroup() {
23
+ try {
24
+ return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ function isDocker() {
30
+ if (isDockerCached === void 0) {
31
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
32
+ }
33
+ return isDockerCached;
34
+ }
35
+ var isDockerCached;
36
+ var init_is_docker = __esm({
37
+ "node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js"() {
38
+ "use strict";
39
+ }
40
+ });
41
+
42
+ // node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
43
+ import fs2 from "fs";
44
+ function isInsideContainer() {
45
+ if (cachedResult === void 0) {
46
+ cachedResult = hasContainerEnv() || isDocker();
47
+ }
48
+ return cachedResult;
49
+ }
50
+ var cachedResult, hasContainerEnv;
51
+ var init_is_inside_container = __esm({
52
+ "node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js"() {
53
+ "use strict";
54
+ init_is_docker();
55
+ hasContainerEnv = () => {
56
+ try {
57
+ fs2.statSync("/run/.containerenv");
58
+ return true;
59
+ } catch {
60
+ return false;
61
+ }
62
+ };
63
+ }
64
+ });
65
+
66
+ // node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js
67
+ import process2 from "process";
68
+ import os from "os";
69
+ import fs3 from "fs";
70
+ var isWsl, is_wsl_default;
71
+ var init_is_wsl = __esm({
72
+ "node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js"() {
73
+ "use strict";
74
+ init_is_inside_container();
75
+ isWsl = () => {
76
+ if (process2.platform !== "linux") {
77
+ return false;
78
+ }
79
+ if (os.release().toLowerCase().includes("microsoft")) {
80
+ if (isInsideContainer()) {
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+ try {
86
+ if (fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
87
+ return !isInsideContainer();
88
+ }
89
+ } catch {
90
+ }
91
+ if (fs3.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs3.existsSync("/run/WSL")) {
92
+ return !isInsideContainer();
93
+ }
94
+ return false;
95
+ };
96
+ is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
97
+ }
98
+ });
99
+
100
+ // node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js
101
+ import process3 from "process";
102
+ import { Buffer as Buffer2 } from "buffer";
103
+ import { promisify as promisify15 } from "util";
104
+ import childProcess from "child_process";
105
+ import fs4, { constants as fsConstants } from "fs/promises";
106
+ var execFile15, powerShellPath, executePowerShell;
107
+ var init_powershell_utils = __esm({
108
+ "node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js"() {
109
+ "use strict";
110
+ execFile15 = promisify15(childProcess.execFile);
111
+ powerShellPath = () => `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
112
+ executePowerShell = async (command, options = {}) => {
113
+ const {
114
+ powerShellPath: psPath,
115
+ ...execFileOptions
116
+ } = options;
117
+ const encodedCommand = executePowerShell.encodeCommand(command);
118
+ return execFile15(
119
+ psPath ?? powerShellPath(),
120
+ [
121
+ ...executePowerShell.argumentsPrefix,
122
+ encodedCommand
123
+ ],
124
+ {
125
+ encoding: "utf8",
126
+ ...execFileOptions
127
+ }
128
+ );
129
+ };
130
+ executePowerShell.argumentsPrefix = [
131
+ "-NoProfile",
132
+ "-NonInteractive",
133
+ "-ExecutionPolicy",
134
+ "Bypass",
135
+ "-EncodedCommand"
136
+ ];
137
+ executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
138
+ executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
139
+ }
140
+ });
141
+
142
+ // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js
143
+ function parseMountPointFromConfig(content) {
144
+ for (const line of content.split("\n")) {
145
+ if (/^\s*#/.test(line)) {
146
+ continue;
147
+ }
148
+ const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
149
+ if (!match) {
150
+ continue;
151
+ }
152
+ return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
153
+ }
154
+ }
155
+ var init_utilities = __esm({
156
+ "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js"() {
157
+ "use strict";
158
+ }
159
+ });
160
+
161
+ // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
162
+ import { promisify as promisify16 } from "util";
163
+ import childProcess2 from "child_process";
164
+ import fs5, { constants as fsConstants2 } from "fs/promises";
165
+ var execFile16, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
166
+ var init_wsl_utils = __esm({
167
+ "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
168
+ "use strict";
169
+ init_is_wsl();
170
+ init_powershell_utils();
171
+ init_utilities();
172
+ init_is_wsl();
173
+ execFile16 = promisify16(childProcess2.execFile);
174
+ wslDrivesMountPoint = /* @__PURE__ */ (() => {
175
+ const defaultMountPoint = "/mnt/";
176
+ let mountPoint;
177
+ return async function() {
178
+ if (mountPoint) {
179
+ return mountPoint;
180
+ }
181
+ const configFilePath = "/etc/wsl.conf";
182
+ let isConfigFileExists = false;
183
+ try {
184
+ await fs5.access(configFilePath, fsConstants2.F_OK);
185
+ isConfigFileExists = true;
186
+ } catch {
187
+ }
188
+ if (!isConfigFileExists) {
189
+ return defaultMountPoint;
190
+ }
191
+ const configContent = await fs5.readFile(configFilePath, { encoding: "utf8" });
192
+ const parsedMountPoint = parseMountPointFromConfig(configContent);
193
+ if (parsedMountPoint === void 0) {
194
+ return defaultMountPoint;
195
+ }
196
+ mountPoint = parsedMountPoint;
197
+ mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
198
+ return mountPoint;
199
+ };
200
+ })();
201
+ powerShellPathFromWsl = async () => {
202
+ const mountPoint = await wslDrivesMountPoint();
203
+ return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
204
+ };
205
+ powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
206
+ canAccessPowerShell = async () => {
207
+ canAccessPowerShellPromise ??= (async () => {
208
+ try {
209
+ const psPath = await powerShellPath2();
210
+ await fs5.access(psPath, fsConstants2.X_OK);
211
+ return true;
212
+ } catch {
213
+ return false;
214
+ }
215
+ })();
216
+ return canAccessPowerShellPromise;
217
+ };
218
+ wslDefaultBrowser = async () => {
219
+ const psPath = await powerShellPath2();
220
+ const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
221
+ const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
222
+ return stdout.trim();
223
+ };
224
+ convertWslPathToWindows = async (path2) => {
225
+ if (/^[a-z]+:\/\//i.test(path2)) {
226
+ return path2;
227
+ }
228
+ try {
229
+ const { stdout } = await execFile16("wslpath", ["-aw", path2], { encoding: "utf8" });
230
+ return stdout.trim();
231
+ } catch {
232
+ return path2;
233
+ }
234
+ };
235
+ }
236
+ });
237
+
238
+ // node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
239
+ function defineLazyProperty(object, propertyName, valueGetter) {
240
+ const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
241
+ Object.defineProperty(object, propertyName, {
242
+ configurable: true,
243
+ enumerable: true,
244
+ get() {
245
+ const result = valueGetter();
246
+ define(result);
247
+ return result;
248
+ },
249
+ set(value) {
250
+ define(value);
251
+ }
252
+ });
253
+ return object;
254
+ }
255
+ var init_define_lazy_prop = __esm({
256
+ "node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js"() {
257
+ "use strict";
258
+ }
259
+ });
260
+
261
+ // node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
262
+ import { promisify as promisify17 } from "util";
263
+ import process4 from "process";
264
+ import { execFile as execFile17 } from "child_process";
265
+ async function defaultBrowserId() {
266
+ if (process4.platform !== "darwin") {
267
+ throw new Error("macOS only");
268
+ }
269
+ const { stdout } = await execFileAsync2("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
270
+ const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
271
+ const browserId = match?.groups.id ?? "com.apple.Safari";
272
+ if (browserId === "com.apple.safari") {
273
+ return "com.apple.Safari";
274
+ }
275
+ return browserId;
276
+ }
277
+ var execFileAsync2;
278
+ var init_default_browser_id = __esm({
279
+ "node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js"() {
280
+ "use strict";
281
+ execFileAsync2 = promisify17(execFile17);
282
+ }
283
+ });
284
+
285
+ // node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
286
+ import process5 from "process";
287
+ import { promisify as promisify18 } from "util";
288
+ import { execFile as execFile18, execFileSync } from "child_process";
289
+ async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
290
+ if (process5.platform !== "darwin") {
291
+ throw new Error("macOS only");
292
+ }
293
+ const outputArguments = humanReadableOutput ? [] : ["-ss"];
294
+ const execOptions = {};
295
+ if (signal) {
296
+ execOptions.signal = signal;
297
+ }
298
+ const { stdout } = await execFileAsync3("osascript", ["-e", script, outputArguments], execOptions);
299
+ return stdout.trim();
300
+ }
301
+ var execFileAsync3;
302
+ var init_run_applescript = __esm({
303
+ "node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js"() {
304
+ "use strict";
305
+ execFileAsync3 = promisify18(execFile18);
306
+ }
307
+ });
308
+
309
+ // node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
310
+ async function bundleName(bundleId) {
311
+ return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
312
+ tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
313
+ }
314
+ var init_bundle_name = __esm({
315
+ "node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js"() {
316
+ "use strict";
317
+ init_run_applescript();
318
+ }
319
+ });
320
+
321
+ // node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js
322
+ import { promisify as promisify19 } from "util";
323
+ import { execFile as execFile19 } from "child_process";
324
+ async function defaultBrowser(_execFileAsync = execFileAsync4) {
325
+ const { stdout } = await _execFileAsync("reg", [
326
+ "QUERY",
327
+ " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
328
+ "/v",
329
+ "ProgId"
330
+ ]);
331
+ const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
332
+ if (!match) {
333
+ throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
334
+ }
335
+ const { id } = match.groups;
336
+ const dotIndex = id.lastIndexOf(".");
337
+ const hyphenIndex = id.lastIndexOf("-");
338
+ const baseIdByDot = dotIndex === -1 ? void 0 : id.slice(0, dotIndex);
339
+ const baseIdByHyphen = hyphenIndex === -1 ? void 0 : id.slice(0, hyphenIndex);
340
+ return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
341
+ }
342
+ var execFileAsync4, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
343
+ var init_windows = __esm({
344
+ "node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js"() {
345
+ "use strict";
346
+ execFileAsync4 = promisify19(execFile19);
347
+ windowsBrowserProgIds = {
348
+ MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
349
+ // The missing `L` is correct.
350
+ MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
351
+ MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
352
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
353
+ ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
354
+ ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
355
+ ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
356
+ ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
357
+ BraveHTML: { name: "Brave", id: "com.brave.Browser" },
358
+ BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
359
+ BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
360
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
361
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
362
+ OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
363
+ VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
364
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
365
+ };
366
+ _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
367
+ UnknownBrowserError = class extends Error {
368
+ };
369
+ }
370
+ });
371
+
372
+ // node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js
373
+ import { promisify as promisify20 } from "util";
374
+ import process6 from "process";
375
+ import { execFile as execFile20 } from "child_process";
376
+ async function defaultBrowser2() {
377
+ if (process6.platform === "darwin") {
378
+ const id = await defaultBrowserId();
379
+ const name = await bundleName(id);
380
+ return { name, id };
381
+ }
382
+ if (process6.platform === "linux") {
383
+ const { stdout } = await execFileAsync5("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
384
+ const id = stdout.trim();
385
+ const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
386
+ return { name, id };
387
+ }
388
+ if (process6.platform === "win32") {
389
+ return defaultBrowser();
390
+ }
391
+ throw new Error("Only macOS, Linux, and Windows are supported");
392
+ }
393
+ var execFileAsync5, titleize;
394
+ var init_default_browser = __esm({
395
+ "node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js"() {
396
+ "use strict";
397
+ init_default_browser_id();
398
+ init_bundle_name();
399
+ init_windows();
400
+ init_windows();
401
+ execFileAsync5 = promisify20(execFile20);
402
+ titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
403
+ }
404
+ });
405
+
406
+ // node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js
407
+ import process7 from "process";
408
+ var isInSsh, is_in_ssh_default;
409
+ var init_is_in_ssh = __esm({
410
+ "node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js"() {
411
+ "use strict";
412
+ isInSsh = Boolean(process7.env.SSH_CONNECTION || process7.env.SSH_CLIENT || process7.env.SSH_TTY);
413
+ is_in_ssh_default = isInSsh;
414
+ }
415
+ });
416
+
417
+ // node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
418
+ var open_exports = {};
419
+ __export(open_exports, {
420
+ apps: () => apps,
421
+ default: () => open_default,
422
+ openApp: () => openApp
423
+ });
424
+ import process8 from "process";
425
+ import path from "path";
426
+ import { fileURLToPath } from "url";
427
+ import childProcess3 from "child_process";
428
+ import fs6, { constants as fsConstants3 } from "fs/promises";
429
+ function detectArchBinary(binary) {
430
+ if (typeof binary === "string" || Array.isArray(binary)) {
431
+ return binary;
432
+ }
433
+ const { [arch]: archBinary } = binary;
434
+ if (!archBinary) {
435
+ throw new Error(`${arch} is not supported`);
436
+ }
437
+ return archBinary;
438
+ }
439
+ function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
440
+ if (wsl && is_wsl_default) {
441
+ return detectArchBinary(wsl);
442
+ }
443
+ if (!platformBinary) {
444
+ throw new Error(`${platform} is not supported`);
445
+ }
446
+ return detectArchBinary(platformBinary);
447
+ }
448
+ var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
449
+ var init_open = __esm({
450
+ "node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
451
+ "use strict";
452
+ init_wsl_utils();
453
+ init_powershell_utils();
454
+ init_define_lazy_prop();
455
+ init_default_browser();
456
+ init_is_inside_container();
457
+ init_is_in_ssh();
458
+ fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
459
+ __dirname = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
460
+ localXdgOpenPath = path.join(__dirname, "xdg-open");
461
+ ({ platform, arch } = process8);
462
+ tryEachApp = async (apps2, opener) => {
463
+ if (apps2.length === 0) {
464
+ return;
465
+ }
466
+ const errors = [];
467
+ for (const app of apps2) {
468
+ try {
469
+ return await opener(app);
470
+ } catch (error) {
471
+ errors.push(error);
472
+ }
473
+ }
474
+ throw new AggregateError(errors, "Failed to open in all supported apps");
475
+ };
476
+ baseOpen = async (options) => {
477
+ options = {
478
+ wait: false,
479
+ background: false,
480
+ newInstance: false,
481
+ allowNonzeroExitCode: false,
482
+ ...options
483
+ };
484
+ const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
485
+ delete options[fallbackAttemptSymbol];
486
+ if (Array.isArray(options.app)) {
487
+ return tryEachApp(options.app, (singleApp) => baseOpen({
488
+ ...options,
489
+ app: singleApp,
490
+ [fallbackAttemptSymbol]: true
491
+ }));
492
+ }
493
+ let { name: app, arguments: appArguments = [] } = options.app ?? {};
494
+ appArguments = [...appArguments];
495
+ if (Array.isArray(app)) {
496
+ return tryEachApp(app, (appName) => baseOpen({
497
+ ...options,
498
+ app: {
499
+ name: appName,
500
+ arguments: appArguments
501
+ },
502
+ [fallbackAttemptSymbol]: true
503
+ }));
504
+ }
505
+ if (app === "browser" || app === "browserPrivate") {
506
+ const ids = {
507
+ "com.google.chrome": "chrome",
508
+ "google-chrome.desktop": "chrome",
509
+ "com.brave.browser": "brave",
510
+ "org.mozilla.firefox": "firefox",
511
+ "firefox.desktop": "firefox",
512
+ "com.microsoft.msedge": "edge",
513
+ "com.microsoft.edge": "edge",
514
+ "com.microsoft.edgemac": "edge",
515
+ "microsoft-edge.desktop": "edge",
516
+ "com.apple.safari": "safari"
517
+ };
518
+ const flags = {
519
+ chrome: "--incognito",
520
+ brave: "--incognito",
521
+ firefox: "--private-window",
522
+ edge: "--inPrivate"
523
+ // Safari doesn't support private mode via command line
524
+ };
525
+ let browser;
526
+ if (is_wsl_default) {
527
+ const progId = await wslDefaultBrowser();
528
+ const browserInfo = _windowsBrowserProgIdMap.get(progId);
529
+ browser = browserInfo ?? {};
530
+ } else {
531
+ browser = await defaultBrowser2();
532
+ }
533
+ if (browser.id in ids) {
534
+ const browserName = ids[browser.id.toLowerCase()];
535
+ if (app === "browserPrivate") {
536
+ if (browserName === "safari") {
537
+ throw new Error("Safari doesn't support opening in private mode via command line");
538
+ }
539
+ appArguments.push(flags[browserName]);
540
+ }
541
+ return baseOpen({
542
+ ...options,
543
+ app: {
544
+ name: apps[browserName],
545
+ arguments: appArguments
546
+ }
547
+ });
548
+ }
549
+ throw new Error(`${browser.name} is not supported as a default browser`);
550
+ }
551
+ let command;
552
+ const cliArguments = [];
553
+ const childProcessOptions = {};
554
+ let shouldUseWindowsInWsl = false;
555
+ if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
556
+ shouldUseWindowsInWsl = await canAccessPowerShell();
557
+ }
558
+ if (platform === "darwin") {
559
+ command = "open";
560
+ if (options.wait) {
561
+ cliArguments.push("--wait-apps");
562
+ }
563
+ if (options.background) {
564
+ cliArguments.push("--background");
565
+ }
566
+ if (options.newInstance) {
567
+ cliArguments.push("--new");
568
+ }
569
+ if (app) {
570
+ cliArguments.push("-a", app);
571
+ }
572
+ } else if (platform === "win32" || shouldUseWindowsInWsl) {
573
+ command = await powerShellPath2();
574
+ cliArguments.push(...executePowerShell.argumentsPrefix);
575
+ if (!is_wsl_default) {
576
+ childProcessOptions.windowsVerbatimArguments = true;
577
+ }
578
+ if (is_wsl_default && options.target) {
579
+ options.target = await convertWslPathToWindows(options.target);
580
+ }
581
+ const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
582
+ if (options.wait) {
583
+ encodedArguments.push("-Wait");
584
+ }
585
+ if (app) {
586
+ encodedArguments.push(executePowerShell.escapeArgument(app));
587
+ if (options.target) {
588
+ appArguments.push(options.target);
589
+ }
590
+ } else if (options.target) {
591
+ encodedArguments.push(executePowerShell.escapeArgument(options.target));
592
+ }
593
+ if (appArguments.length > 0) {
594
+ appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
595
+ encodedArguments.push("-ArgumentList", appArguments.join(","));
596
+ }
597
+ options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
598
+ if (!options.wait) {
599
+ childProcessOptions.stdio = "ignore";
600
+ }
601
+ } else {
602
+ if (app) {
603
+ command = app;
604
+ } else {
605
+ const isBundled = !__dirname || __dirname === "/";
606
+ let exeLocalXdgOpen = false;
607
+ try {
608
+ await fs6.access(localXdgOpenPath, fsConstants3.X_OK);
609
+ exeLocalXdgOpen = true;
610
+ } catch {
611
+ }
612
+ const useSystemXdgOpen = process8.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
613
+ command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
614
+ }
615
+ if (appArguments.length > 0) {
616
+ cliArguments.push(...appArguments);
617
+ }
618
+ if (!options.wait) {
619
+ childProcessOptions.stdio = "ignore";
620
+ childProcessOptions.detached = true;
621
+ }
622
+ }
623
+ if (platform === "darwin" && appArguments.length > 0) {
624
+ cliArguments.push("--args", ...appArguments);
625
+ }
626
+ if (options.target) {
627
+ cliArguments.push(options.target);
628
+ }
629
+ const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
630
+ if (options.wait) {
631
+ return new Promise((resolve2, reject) => {
632
+ subprocess.once("error", reject);
633
+ subprocess.once("close", (exitCode) => {
634
+ if (!options.allowNonzeroExitCode && exitCode !== 0) {
635
+ reject(new Error(`Exited with code ${exitCode}`));
636
+ return;
637
+ }
638
+ resolve2(subprocess);
639
+ });
640
+ });
641
+ }
642
+ if (isFallbackAttempt) {
643
+ return new Promise((resolve2, reject) => {
644
+ subprocess.once("error", reject);
645
+ subprocess.once("spawn", () => {
646
+ subprocess.once("close", (exitCode) => {
647
+ subprocess.off("error", reject);
648
+ if (exitCode !== 0) {
649
+ reject(new Error(`Exited with code ${exitCode}`));
650
+ return;
651
+ }
652
+ subprocess.unref();
653
+ resolve2(subprocess);
654
+ });
655
+ });
656
+ });
657
+ }
658
+ subprocess.unref();
659
+ return new Promise((resolve2, reject) => {
660
+ subprocess.once("error", reject);
661
+ subprocess.once("spawn", () => {
662
+ subprocess.off("error", reject);
663
+ resolve2(subprocess);
664
+ });
665
+ });
666
+ };
667
+ open = (target, options) => {
668
+ if (typeof target !== "string") {
669
+ throw new TypeError("Expected a `target`");
670
+ }
671
+ return baseOpen({
672
+ ...options,
673
+ target
674
+ });
675
+ };
676
+ openApp = (name, options) => {
677
+ if (typeof name !== "string" && !Array.isArray(name)) {
678
+ throw new TypeError("Expected a valid `name`");
679
+ }
680
+ const { arguments: appArguments = [] } = options ?? {};
681
+ if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) {
682
+ throw new TypeError("Expected `appArguments` as Array type");
683
+ }
684
+ return baseOpen({
685
+ ...options,
686
+ app: {
687
+ name,
688
+ arguments: appArguments
689
+ }
690
+ });
691
+ };
692
+ apps = {
693
+ browser: "browser",
694
+ browserPrivate: "browserPrivate"
695
+ };
696
+ defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
697
+ darwin: "google chrome",
698
+ win32: "chrome",
699
+ // `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap.
700
+ linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
701
+ }, {
702
+ wsl: {
703
+ ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
704
+ x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
705
+ }
706
+ }));
707
+ defineLazyProperty(apps, "brave", () => detectPlatformBinary({
708
+ darwin: "brave browser",
709
+ win32: "brave",
710
+ linux: ["brave-browser", "brave"]
711
+ }, {
712
+ wsl: {
713
+ ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
714
+ x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
715
+ }
716
+ }));
717
+ defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
718
+ darwin: "firefox",
719
+ win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
720
+ linux: "firefox"
721
+ }, {
722
+ wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
723
+ }));
724
+ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
725
+ darwin: "microsoft edge",
726
+ win32: "msedge",
727
+ linux: ["microsoft-edge", "microsoft-edge-dev"]
728
+ }, {
729
+ wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
730
+ }));
731
+ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
732
+ darwin: "Safari"
733
+ }));
734
+ open_default = open;
735
+ }
736
+ });
2
737
 
3
738
  // src/cli/index.ts
4
739
  import { CommanderError } from "commander";
@@ -8,7 +743,7 @@ import { Command, InvalidArgumentError } from "commander";
8
743
 
9
744
  // src/package-info.ts
10
745
  var AISNITCH_PACKAGE_NAME = "aisnitch";
11
- var AISNITCH_VERSION = "0.2.20";
746
+ var AISNITCH_VERSION = "0.2.22";
12
747
  var AISNITCH_DESCRIPTION = "Universal bridge for AI coding tool activity \u2014 capture, normalize, stream.";
13
748
 
14
749
  // src/core/events/schema.ts
@@ -49,6 +784,8 @@ var TOOL_NAMES = [
49
784
  "kiro",
50
785
  "augment-code",
51
786
  "mistral",
787
+ "zed",
788
+ "pi",
52
789
  "unknown"
53
790
  ];
54
791
  var ERROR_TYPES = [
@@ -96,6 +833,11 @@ var ToolInputSchema = z.strictObject({
96
833
  (value) => value.filePath !== void 0 || value.command !== void 0,
97
834
  "toolInput must include filePath or command"
98
835
  );
836
+ var ThinkingContentSchema = z.string().max(1e5).describe("Raw thinking/reasoning content from the AI model");
837
+ var ToolCallNameSchema = z.string().min(1).max(100).describe("Name of the tool being invoked (e.g., Edit, Bash, Grep)");
838
+ var FinalMessageSchema = z.string().max(5e4).describe("End-of-run summary or completion message");
839
+ var ToolResultSchema = z.string().max(1e4).describe("Tool execution result or output");
840
+ var MessageContentSchema = z.string().max(1e5).describe("Raw text content from AI messages");
99
841
  var ToolNameSchema = z.enum(TOOL_NAMES);
100
842
  var AISnitchEventTypeSchema = z.enum(AISNITCH_EVENT_TYPES);
101
843
  var ErrorTypeSchema = z.enum(ERROR_TYPES);
@@ -110,6 +852,9 @@ var EventDataSchema = z.strictObject({
110
852
  activeFile: z.string().min(1).max(4096).optional(),
111
853
  model: z.string().min(1).max(200).optional(),
112
854
  tokensUsed: z.number().int().min(0).optional(),
855
+ inputTokens: z.number().int().min(0).optional(),
856
+ outputTokens: z.number().int().min(0).optional(),
857
+ cachedTokens: z.number().int().min(0).optional(),
113
858
  errorMessage: z.string().min(1).max(1e4).optional(),
114
859
  errorType: ErrorTypeSchema.optional(),
115
860
  raw: z.record(z.string(), z.unknown()).optional(),
@@ -118,7 +863,13 @@ var EventDataSchema = z.strictObject({
118
863
  pid: z.number().int().positive().optional(),
119
864
  instanceId: z.string().min(1).max(255).optional(),
120
865
  instanceIndex: z.number().int().min(1).optional(),
121
- instanceTotal: z.number().int().min(1).optional()
866
+ instanceTotal: z.number().int().min(1).optional(),
867
+ // New fields for enhanced content capture
868
+ thinkingContent: ThinkingContentSchema.optional(),
869
+ toolCallName: ToolCallNameSchema.optional(),
870
+ finalMessage: FinalMessageSchema.optional(),
871
+ toolResult: ToolResultSchema.optional(),
872
+ messageContent: MessageContentSchema.optional()
122
873
  });
123
874
  var AISnitchEventSchema = z.strictObject({
124
875
  specversion: z.literal("1.0"),
@@ -923,8 +1674,8 @@ var ClaudeCodeSetup = class extends FileToolSetupBase {
923
1674
  return `${JSON.stringify(nextSettings, null, 2)}
924
1675
  `;
925
1676
  }
926
- getFileBackupPath(path) {
927
- return `${path}.bak`;
1677
+ getFileBackupPath(path2) {
1678
+ return `${path2}.bak`;
928
1679
  }
929
1680
  };
930
1681
  var OpenCodeSetup = class extends FileToolSetupBase {
@@ -1164,8 +1915,8 @@ var CopilotCLISetup = class {
1164
1915
  return `${JSON.stringify(nextConfig, null, 2)}
1165
1916
  `;
1166
1917
  }
1167
- getBackupPath(path) {
1168
- return `${path}.bak`;
1918
+ getBackupPath(path2) {
1919
+ return `${path2}.bak`;
1169
1920
  }
1170
1921
  };
1171
1922
  var OpenClawSetup = class {
@@ -1290,8 +2041,8 @@ var OpenClawSetup = class {
1290
2041
  return `${JSON.stringify(nextConfig, null, 2)}
1291
2042
  `;
1292
2043
  }
1293
- getBackupPath(path) {
1294
- return `${path}.bak`;
2044
+ getBackupPath(path2) {
2045
+ return `${path2}.bak`;
1295
2046
  }
1296
2047
  };
1297
2048
  async function createToolSetup(toolName, options = {}, dependencies = {}) {
@@ -2334,17 +3085,17 @@ async function isBinaryAvailable(binaryName) {
2334
3085
  return false;
2335
3086
  }
2336
3087
  }
2337
- async function fileExists(path) {
3088
+ async function fileExists(path2) {
2338
3089
  try {
2339
- await access(path, constants.F_OK);
3090
+ await access(path2, constants.F_OK);
2340
3091
  return true;
2341
3092
  } catch {
2342
3093
  return false;
2343
3094
  }
2344
3095
  }
2345
- async function readOptionalFile(path) {
3096
+ async function readOptionalFile(path2) {
2346
3097
  try {
2347
- return await readFile2(path, "utf8");
3098
+ return await readFile2(path2, "utf8");
2348
3099
  } catch (error) {
2349
3100
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2350
3101
  return null;
@@ -2355,14 +3106,14 @@ async function readOptionalFile(path) {
2355
3106
  function shellEscapeSingle(value) {
2356
3107
  return `'${value.replaceAll("'", `'"'"'`)}'`;
2357
3108
  }
2358
- async function restoreBackupOrRemove(path) {
2359
- const backupPath = `${path}.bak`;
3109
+ async function restoreBackupOrRemove(path2) {
3110
+ const backupPath = `${path2}.bak`;
2360
3111
  if (await fileExists(backupPath)) {
2361
- await copyFile(backupPath, path);
3112
+ await copyFile(backupPath, path2);
2362
3113
  await rm(backupPath, { force: true });
2363
3114
  return;
2364
3115
  }
2365
- await rm(path, { force: true });
3116
+ await rm(path2, { force: true });
2366
3117
  }
2367
3118
  function buildAiderNotificationCommand(options) {
2368
3119
  const cliArgs = [process.execPath, resolveCurrentCliEntryPath(), "aider-notify"];
@@ -2432,11 +3183,11 @@ function toConfigPathOptions(options) {
2432
3183
  // src/cli/runtime.ts
2433
3184
  import { execFile as execFileCallback14, spawn as spawnChildProcess2 } from "child_process";
2434
3185
  import { closeSync, openSync } from "fs";
2435
- import { mkdtemp, readFile as readFile14, rename, rm as rm4, writeFile as writeFile5 } from "fs/promises";
3186
+ import { mkdtemp, readFile as readFile15, rename, rm as rm4, writeFile as writeFile5 } from "fs/promises";
2436
3187
  import { createConnection as createConnection3 } from "net";
2437
3188
  import { tmpdir } from "os";
2438
- import { basename as basename11, join as join16 } from "path";
2439
- import { promisify as promisify14 } from "util";
3189
+ import { basename as basename12, join as join18 } from "path";
3190
+ import { promisify as promisify21 } from "util";
2440
3191
 
2441
3192
  // src/adapters/generic-pty.ts
2442
3193
  import { basename as basename3 } from "path";
@@ -2507,9 +3258,11 @@ var TOOL_BINARY_MAP = {
2507
3258
  "openhands": "openhands",
2508
3259
  "openclaw": "openclaw",
2509
3260
  "opencode": "opencode",
3261
+ "pi": "pi",
2510
3262
  "qwen-code": "qwen",
2511
3263
  "unknown": "unknown",
2512
- "windsurf": "windsurf"
3264
+ "windsurf": "windsurf",
3265
+ "zed": "zed"
2513
3266
  };
2514
3267
  var ContextDetector = class {
2515
3268
  cache = /* @__PURE__ */ new Map();
@@ -4370,7 +5123,7 @@ var UDSServer = class {
4370
5123
  };
4371
5124
 
4372
5125
  // src/core/engine/pipeline.ts
4373
- import { join as join13 } from "path";
5126
+ import { join as join15 } from "path";
4374
5127
  import { z as z4 } from "zod";
4375
5128
 
4376
5129
  // src/adapters/aider.ts
@@ -4477,20 +5230,29 @@ var BaseAdapter = class {
4477
5230
  });
4478
5231
  let published;
4479
5232
  try {
4480
- published = await this.publishEventImplementation(event, {
4481
- cwd: context.cwd,
4482
- env: context.env,
4483
- hookPayload: context.hookPayload,
4484
- pid: context.pid,
4485
- sessionId,
4486
- source: context.source,
4487
- transcriptPath: context.transcriptPath
5233
+ published = await SHARED_BREAKERS.adapterEmit.execute(async () => {
5234
+ return await this.publishEventImplementation(event, {
5235
+ cwd: context.cwd,
5236
+ env: context.env,
5237
+ hookPayload: context.hookPayload,
5238
+ pid: context.pid,
5239
+ sessionId,
5240
+ source: context.source,
5241
+ transcriptPath: context.transcriptPath
5242
+ });
4488
5243
  });
4489
5244
  } catch (error) {
4490
- logger.error(
4491
- { error, eventType: type, adapter: this.name, sessionId },
4492
- "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
4493
- );
5245
+ if (error instanceof Error && error.name === "CircuitOpenError") {
5246
+ logger.warn(
5247
+ { error, eventType: type, adapter: this.name },
5248
+ "\u{1F4D6} Adapter emit blocked by open circuit \u2014 event dropped"
5249
+ );
5250
+ } else {
5251
+ logger.error(
5252
+ { error, eventType: type, adapter: this.name, sessionId },
5253
+ "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
5254
+ );
5255
+ }
4494
5256
  published = false;
4495
5257
  }
4496
5258
  if (published) {
@@ -5504,7 +6266,11 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5504
6266
  return;
5505
6267
  }
5506
6268
  case "SessionEnd": {
5507
- await this.emitStateChange("session.end", sharedData, context);
6269
+ const finalMessage = extractFinalMessageFromPayload(payload);
6270
+ await this.emitStateChange("session.end", {
6271
+ ...sharedData,
6272
+ finalMessage
6273
+ }, context);
5508
6274
  return;
5509
6275
  }
5510
6276
  case "UserPromptSubmit":
@@ -5521,12 +6287,22 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5521
6287
  return;
5522
6288
  }
5523
6289
  case "PreToolUse": {
5524
- await this.emitStateChange("agent.tool_call", sharedData, context);
6290
+ const toolCallName = extractToolNameFromPayload(payload);
6291
+ await this.emitStateChange("agent.tool_call", {
6292
+ ...sharedData,
6293
+ toolCallName
6294
+ }, context);
5525
6295
  return;
5526
6296
  }
5527
6297
  case "PostToolUse": {
6298
+ const toolCallName = extractToolNameFromPayload(payload);
6299
+ const toolResult = extractToolResultFromPayload(payload);
5528
6300
  const emittedType = isClaudeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
5529
- await this.emitStateChange(emittedType, sharedData, context);
6301
+ await this.emitStateChange(emittedType, {
6302
+ ...sharedData,
6303
+ toolCallName,
6304
+ toolResult
6305
+ }, context);
5530
6306
  return;
5531
6307
  }
5532
6308
  case "PostToolUseFailure":
@@ -5711,7 +6487,7 @@ function extractClaudeTranscriptObservations(payload, transcriptPath) {
5711
6487
  });
5712
6488
  const contentParts = extractClaudeContentParts(payload);
5713
6489
  const model = getString(payload, "model") ?? getString(getRecord(payload.message), "model");
5714
- const tokensUsed = extractTokenUsage(payload);
6490
+ const tokens = extractTokenUsageDetailed(payload);
5715
6491
  const rawPayload = payload;
5716
6492
  const sharedContext = {
5717
6493
  // 📖 Pass process.env so terminal detection works from transcript path too
@@ -5724,25 +6500,57 @@ function extractClaudeTranscriptObservations(payload, transcriptPath) {
5724
6500
  const sharedData = {
5725
6501
  model,
5726
6502
  raw: rawPayload,
5727
- tokensUsed
6503
+ tokensUsed: tokens.total,
6504
+ inputTokens: tokens.input,
6505
+ outputTokens: tokens.output,
6506
+ cachedTokens: tokens.cached
5728
6507
  };
5729
6508
  const observations = [];
5730
6509
  if (contentParts.some((part) => part.type === "thinking")) {
6510
+ const thinkingParts = contentParts.filter((part) => part.type === "thinking");
6511
+ const thinkingText = thinkingParts.map((part) => {
6512
+ const text = part.text;
6513
+ return typeof text === "string" ? text : void 0;
6514
+ }).filter((text) => text !== void 0).join("\n");
5731
6515
  observations.push({
5732
6516
  context: sharedContext,
5733
- data: sharedData,
6517
+ data: {
6518
+ ...sharedData,
6519
+ thinkingContent: thinkingText.length > 0 ? thinkingText : void 0
6520
+ },
5734
6521
  type: "agent.thinking"
5735
6522
  });
5736
6523
  }
5737
6524
  if (contentParts.some(
5738
6525
  (part) => part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0
5739
6526
  )) {
6527
+ const messageTexts = contentParts.filter((part) => part.type === "text").map((part) => part.text).filter((text) => text.trim().length > 0);
6528
+ const messageContent = messageTexts.join("\n");
5740
6529
  observations.push({
5741
6530
  context: sharedContext,
5742
- data: sharedData,
6531
+ data: {
6532
+ ...sharedData,
6533
+ messageContent: messageContent.length > 0 ? messageContent : void 0
6534
+ },
5743
6535
  type: "agent.streaming"
5744
6536
  });
5745
6537
  }
6538
+ const toolUseParts = contentParts.filter(
6539
+ (part) => part.type === "tool_use" || part.type === "toolUse"
6540
+ );
6541
+ if (toolUseParts.length > 0) {
6542
+ const toolName = getString(toolUseParts[0], "name") ?? getString(toolUseParts[0], "tool");
6543
+ if (toolName) {
6544
+ observations.push({
6545
+ context: sharedContext,
6546
+ data: {
6547
+ ...sharedData,
6548
+ toolCallName: toolName
6549
+ },
6550
+ type: "agent.tool_call"
6551
+ });
6552
+ }
6553
+ }
5746
6554
  return observations;
5747
6555
  }
5748
6556
  function extractClaudeContentParts(payload) {
@@ -5753,23 +6561,28 @@ function extractClaudeContentParts(payload) {
5753
6561
  }
5754
6562
  return content.filter(isRecord2);
5755
6563
  }
5756
- function extractTokenUsage(payload) {
6564
+ function extractTokenUsageDetailed(payload) {
5757
6565
  const tokens = getNumber(payload, "tokens");
5758
6566
  if (tokens !== void 0) {
5759
- return tokens;
6567
+ return { total: tokens };
5760
6568
  }
5761
6569
  const usage = getRecord(payload.usage);
5762
6570
  if (!usage) {
5763
- return void 0;
6571
+ return {};
5764
6572
  }
5765
6573
  const totalTokens = getNumber(usage, "total_tokens");
5766
6574
  if (totalTokens !== void 0) {
5767
- return totalTokens;
6575
+ return {
6576
+ total: totalTokens,
6577
+ input: getNumber(usage, "input_tokens"),
6578
+ output: getNumber(usage, "output_tokens"),
6579
+ cached: getNumber(usage, "cached_tokens")
6580
+ };
5768
6581
  }
5769
6582
  const inputTokens = getNumber(usage, "input_tokens") ?? 0;
5770
6583
  const outputTokens = getNumber(usage, "output_tokens") ?? 0;
5771
6584
  const usageSum = inputTokens + outputTokens;
5772
- return usageSum > 0 ? usageSum : void 0;
6585
+ return usageSum > 0 ? { total: usageSum, input: inputTokens, output: outputTokens } : {};
5773
6586
  }
5774
6587
  function extractClaudeToolInput(payload) {
5775
6588
  const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);
@@ -5865,6 +6678,51 @@ function getString(payload, key) {
5865
6678
  const value = payload[key];
5866
6679
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
5867
6680
  }
6681
+ function extractToolNameFromPayload(payload) {
6682
+ const directToolName = getString(payload, "tool_name") ?? getString(payload, "toolName");
6683
+ if (directToolName) {
6684
+ return directToolName;
6685
+ }
6686
+ const toolUse = getRecord(payload.tool_use) ?? getRecord(payload.toolUse);
6687
+ if (toolUse) {
6688
+ return getString(toolUse, "name") ?? getString(toolUse, "tool");
6689
+ }
6690
+ const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);
6691
+ if (toolInput) {
6692
+ return getString(toolInput, "tool_name") ?? getString(toolInput, "type");
6693
+ }
6694
+ return void 0;
6695
+ }
6696
+ function extractToolResultFromPayload(payload) {
6697
+ const directResult = getString(payload, "result") ?? getString(payload, "output");
6698
+ if (directResult) {
6699
+ return directResult;
6700
+ }
6701
+ const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);
6702
+ if (toolResult) {
6703
+ return getString(toolResult, "content") ?? getString(toolResult, "output");
6704
+ }
6705
+ const errorField = getString(payload, "error") ?? getString(payload, "error_message");
6706
+ if (errorField) {
6707
+ return errorField;
6708
+ }
6709
+ return void 0;
6710
+ }
6711
+ function extractFinalMessageFromPayload(payload) {
6712
+ const directMessage = getString(payload, "final_message") ?? getString(payload, "finalMessage") ?? getString(payload, "summary") ?? getString(payload, "completion_message");
6713
+ if (directMessage) {
6714
+ return directMessage;
6715
+ }
6716
+ const result = getString(payload, "result") ?? getString(payload, "output") ?? getString(payload, "message");
6717
+ if (result) {
6718
+ return result;
6719
+ }
6720
+ const stats = getRecord(payload.stats);
6721
+ if (stats) {
6722
+ return getString(stats, "summary") ?? getString(stats, "completion_summary");
6723
+ }
6724
+ return void 0;
6725
+ }
5868
6726
 
5869
6727
  // src/adapters/copilot-cli.ts
5870
6728
  import { execFile as execFileCallback5 } from "child_process";
@@ -10828,7 +11686,17 @@ var OpenCodeAdapter = class extends BaseAdapter {
10828
11686
  project: extractOpenCodeProject(payload),
10829
11687
  raw: payload,
10830
11688
  toolInput: extractOpenCodeToolInput(payload),
10831
- toolName: extractOpenCodeToolName(payload)
11689
+ toolName: extractOpenCodeToolName(payload),
11690
+ // 📖 Extract token usage from payload (with input/output/cached breakdown)
11691
+ ...(() => {
11692
+ const tokens = extractOpenCodeTokens(payload);
11693
+ return {
11694
+ tokensUsed: tokens.total,
11695
+ inputTokens: tokens.inputTokens,
11696
+ outputTokens: tokens.outputTokens,
11697
+ cachedTokens: tokens.cachedTokens
11698
+ };
11699
+ })()
10832
11700
  };
10833
11701
  switch (eventType) {
10834
11702
  case "session.created": {
@@ -10838,7 +11706,11 @@ var OpenCodeAdapter = class extends BaseAdapter {
10838
11706
  return;
10839
11707
  }
10840
11708
  case "session.deleted": {
10841
- await this.emitStateChange("session.end", sharedData, context);
11709
+ const finalMessage = extractOpenCodeFinalMessage(payload);
11710
+ await this.emitStateChange("session.end", {
11711
+ ...sharedData,
11712
+ finalMessage
11713
+ }, context);
10842
11714
  return;
10843
11715
  }
10844
11716
  case "session.error": {
@@ -10853,9 +11725,21 @@ var OpenCodeAdapter = class extends BaseAdapter {
10853
11725
  await this.emitStateChange("agent.compact", sharedData, context);
10854
11726
  return;
10855
11727
  }
11728
+ case "thinking": {
11729
+ const thinkingContent = extractOpenCodeThinkingContent(payload);
11730
+ await this.emitStateChange("agent.thinking", {
11731
+ ...sharedData,
11732
+ thinkingContent
11733
+ }, context);
11734
+ return;
11735
+ }
10856
11736
  case "message.updated":
10857
11737
  case "message.part.updated": {
10858
- await this.emitStateChange("agent.streaming", sharedData, context);
11738
+ const messageContent = extractOpenCodeMessageContent(payload);
11739
+ await this.emitStateChange("agent.streaming", {
11740
+ ...sharedData,
11741
+ messageContent
11742
+ }, context);
10859
11743
  return;
10860
11744
  }
10861
11745
  case "permission.asked": {
@@ -10863,12 +11747,22 @@ var OpenCodeAdapter = class extends BaseAdapter {
10863
11747
  return;
10864
11748
  }
10865
11749
  case "tool.execute.before": {
10866
- await this.emitStateChange("agent.tool_call", sharedData, context);
11750
+ const toolCallName = extractOpenCodeToolName(payload);
11751
+ await this.emitStateChange("agent.tool_call", {
11752
+ ...sharedData,
11753
+ toolCallName
11754
+ }, context);
10867
11755
  return;
10868
11756
  }
10869
11757
  case "tool.execute.after": {
11758
+ const toolCallName = extractOpenCodeToolName(payload);
11759
+ const toolResult = extractOpenCodeToolResult(payload);
10870
11760
  const emittedType = isOpenCodeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
10871
- await this.emitStateChange(emittedType, sharedData, context);
11761
+ await this.emitStateChange(emittedType, {
11762
+ ...sharedData,
11763
+ toolCallName,
11764
+ toolResult
11765
+ }, context);
10872
11766
  return;
10873
11767
  }
10874
11768
  default: {
@@ -11035,9 +11929,599 @@ function getString10(payload, key) {
11035
11929
  const value = payload[key];
11036
11930
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
11037
11931
  }
11038
-
11039
- // src/adapters/registry.ts
11040
- var AdapterRegistry = class {
11932
+ function extractOpenCodeFinalMessage(payload) {
11933
+ const directMessage = getString10(payload, "final_message") ?? getString10(payload, "finalMessage") ?? getString10(payload, "summary") ?? getString10(payload, "completion_message");
11934
+ if (directMessage) {
11935
+ return directMessage;
11936
+ }
11937
+ const result = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(getRecord9(payload.properties), "result");
11938
+ if (result) {
11939
+ return result;
11940
+ }
11941
+ return void 0;
11942
+ }
11943
+ function extractOpenCodeToolResult(payload) {
11944
+ const directResult = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(payload, "toolResult");
11945
+ if (directResult) {
11946
+ return directResult;
11947
+ }
11948
+ const toolResult = getRecord9(payload.tool_result) ?? getRecord9(payload.toolResult);
11949
+ if (toolResult) {
11950
+ return getString10(toolResult, "content") ?? getString10(toolResult, "output");
11951
+ }
11952
+ const props = getRecord9(payload.properties);
11953
+ if (props) {
11954
+ const nestedResult = getRecord9(props.tool_result) ?? getRecord9(props.toolResult);
11955
+ if (nestedResult) {
11956
+ return getString10(nestedResult, "content") ?? getString10(nestedResult, "output");
11957
+ }
11958
+ }
11959
+ return void 0;
11960
+ }
11961
+ function extractOpenCodeMessageContent(payload) {
11962
+ const directMessage = getString10(payload, "text") ?? getString10(payload, "message") ?? getString10(payload, "content") ?? getString10(payload, "output");
11963
+ if (directMessage) {
11964
+ return directMessage;
11965
+ }
11966
+ const part = getRecord9(payload.part) ?? getRecord9(getRecord9(payload.properties)?.part);
11967
+ if (part) {
11968
+ return getString10(part, "text") ?? getString10(part, "content");
11969
+ }
11970
+ const props = getRecord9(payload.properties);
11971
+ if (props) {
11972
+ const message = getRecord9(props.message) ?? getRecord9(props.info);
11973
+ if (message) {
11974
+ return getString10(message, "text") ?? getString10(message, "content");
11975
+ }
11976
+ return getString10(props, "text") ?? getString10(props, "message");
11977
+ }
11978
+ return void 0;
11979
+ }
11980
+ function extractOpenCodeThinkingContent(payload) {
11981
+ const directThinking = getString10(payload, "thinking") ?? getString10(payload, "thinkingContent") ?? getString10(payload, "reasoning") ?? getString10(payload, "thought");
11982
+ if (directThinking) {
11983
+ return directThinking;
11984
+ }
11985
+ const props = getRecord9(payload.properties);
11986
+ if (props) {
11987
+ return getString10(props, "thinking") ?? getString10(props, "reasoning") ?? getString10(props, "thought");
11988
+ }
11989
+ return void 0;
11990
+ }
11991
+ function extractOpenCodeTokens(payload) {
11992
+ const directTokens = getNumber8(payload, "tokensUsed") ?? getNumber8(payload, "tokens");
11993
+ if (directTokens !== void 0) {
11994
+ return { total: directTokens };
11995
+ }
11996
+ const props = getRecord9(payload.properties);
11997
+ if (props) {
11998
+ const info = getRecord9(props.info);
11999
+ if (info) {
12000
+ const tokens = getRecord9(info.tokens);
12001
+ if (tokens) {
12002
+ const inputTokens = getNumber8(tokens, "input") ?? 0;
12003
+ const outputTokens = getNumber8(tokens, "output") ?? 0;
12004
+ const reasoningTokens = getNumber8(tokens, "reasoning") ?? 0;
12005
+ const total = inputTokens + outputTokens + reasoningTokens;
12006
+ return total > 0 ? {
12007
+ total,
12008
+ inputTokens,
12009
+ outputTokens,
12010
+ // reasoning tokens are often billed as cached on some providers
12011
+ cachedTokens: reasoningTokens
12012
+ } : {};
12013
+ }
12014
+ }
12015
+ const fallbackTokens = getNumber8(props, "tokensUsed") ?? getNumber8(props, "tokens");
12016
+ if (fallbackTokens !== void 0) {
12017
+ return { total: fallbackTokens };
12018
+ }
12019
+ }
12020
+ return {};
12021
+ }
12022
+
12023
+ // src/adapters/pi.ts
12024
+ import { execFile as execFile14 } from "child_process";
12025
+ import { join as join13 } from "path";
12026
+ import { promisify as promisify14 } from "util";
12027
+ var execFileAsync = promisify14(execFile14);
12028
+ var PiAdapter = class extends BaseAdapter {
12029
+ displayName = "Pi (MiniMax)";
12030
+ name = "pi";
12031
+ strategies = [
12032
+ "process-detect",
12033
+ "api-client",
12034
+ "log-watch"
12035
+ ];
12036
+ apiPort = 7890;
12037
+ logPath;
12038
+ poller = null;
12039
+ activePiSessions = /* @__PURE__ */ new Map();
12040
+ lastCheckedTime = 0;
12041
+ constructor(options) {
12042
+ super(options);
12043
+ this.logPath = join13(
12044
+ options.homeDirectory ?? process.env.HOME ?? "",
12045
+ ".pi",
12046
+ "agent.log"
12047
+ );
12048
+ }
12049
+ start() {
12050
+ if (this.getStatus().running) {
12051
+ return Promise.resolve();
12052
+ }
12053
+ this.setRunning(true);
12054
+ this.startPolling();
12055
+ logger.info({ adapter: this.name }, "Pi adapter started");
12056
+ return Promise.resolve();
12057
+ }
12058
+ stop() {
12059
+ if (this.poller !== null) {
12060
+ clearInterval(this.poller);
12061
+ this.poller = null;
12062
+ }
12063
+ this.setRunning(false);
12064
+ logger.info({ adapter: this.name }, "Pi adapter stopped");
12065
+ return Promise.resolve();
12066
+ }
12067
+ async handleHook(payload) {
12068
+ const normalized = this.parseNormalizedHookPayload(payload);
12069
+ if (normalized === null) {
12070
+ return;
12071
+ }
12072
+ const context = {
12073
+ cwd: normalized.cwd,
12074
+ pid: normalized.pid,
12075
+ sessionId: normalized.sessionId,
12076
+ source: "pi-hook"
12077
+ };
12078
+ const eventType = this.mapEventType(normalized.type ?? "");
12079
+ const eventData = this.buildEventData(eventType, normalized);
12080
+ await this.emit(eventType, eventData, context);
12081
+ }
12082
+ startPolling() {
12083
+ this.poller = setInterval(() => {
12084
+ void this.pollPiActivity();
12085
+ }, 2e3);
12086
+ }
12087
+ async pollPiActivity() {
12088
+ const running = await this.detectPiInstance();
12089
+ if (!running) {
12090
+ for (const [sessionId, activity] of this.activePiSessions) {
12091
+ if (activity.state !== "idle") {
12092
+ activity.state = "idle";
12093
+ await this.emitIdle(sessionId);
12094
+ }
12095
+ }
12096
+ return;
12097
+ }
12098
+ try {
12099
+ const response = await fetch(
12100
+ `http://127.0.0.1:${this.apiPort}/api/status`,
12101
+ {
12102
+ signal: AbortSignal.timeout(500)
12103
+ }
12104
+ );
12105
+ if (response.ok) {
12106
+ const data = await response.json();
12107
+ await this.processPiApiResponse(data);
12108
+ }
12109
+ } catch {
12110
+ await this.checkMiniMaxApi();
12111
+ }
12112
+ }
12113
+ async detectPiInstance() {
12114
+ try {
12115
+ const result = await execFileAsync("pgrep", ["-l", "pi|minimax"]);
12116
+ if (result.stdout.includes("pi") || result.stdout.includes("minimax")) {
12117
+ return true;
12118
+ }
12119
+ } catch {
12120
+ }
12121
+ try {
12122
+ const response = await fetch(
12123
+ `http://127.0.0.1:${this.apiPort}/health`,
12124
+ {
12125
+ signal: AbortSignal.timeout(200)
12126
+ }
12127
+ );
12128
+ if (response.ok) {
12129
+ return true;
12130
+ }
12131
+ } catch {
12132
+ }
12133
+ return false;
12134
+ }
12135
+ async checkMiniMaxApi() {
12136
+ try {
12137
+ const response = await fetch("http://127.0.0.1:3000/api/agent/status", {
12138
+ signal: AbortSignal.timeout(500)
12139
+ });
12140
+ if (response.ok) {
12141
+ const data = await response.json();
12142
+ await this.processPiApiResponse(data);
12143
+ }
12144
+ } catch {
12145
+ }
12146
+ }
12147
+ async processPiApiResponse(data) {
12148
+ const rawSession = data.sessionId ?? data.project ?? "default";
12149
+ const sessionId = `pi:${rawSession.replace(/[^a-zA-Z0-9-_]/g, "-")}`;
12150
+ let activity = this.activePiSessions.get(sessionId);
12151
+ if (!activity) {
12152
+ activity = { sessionId, state: "idle" };
12153
+ this.activePiSessions.set(sessionId, activity);
12154
+ await this.emitSessionStart(sessionId, data);
12155
+ }
12156
+ const rawState = data.state ?? "idle";
12157
+ const state = rawState;
12158
+ if (state !== activity.state) {
12159
+ switch (state) {
12160
+ case "thinking": {
12161
+ const rawThinking = data.thinking;
12162
+ if (rawThinking) {
12163
+ await this.emitThinking(sessionId, rawThinking);
12164
+ }
12165
+ break;
12166
+ }
12167
+ case "tool": {
12168
+ const rawFilePath = data.filePath;
12169
+ const rawCommand = data.command;
12170
+ const rawToolName = data.toolName ?? "unknown";
12171
+ await this.emitToolCall(
12172
+ sessionId,
12173
+ {
12174
+ filePath: rawFilePath ?? "",
12175
+ command: rawCommand ?? ""
12176
+ },
12177
+ rawToolName
12178
+ );
12179
+ break;
12180
+ }
12181
+ case "output": {
12182
+ const rawOutput = data.output;
12183
+ if (rawOutput) {
12184
+ await this.emitOutput(sessionId, rawOutput);
12185
+ }
12186
+ break;
12187
+ }
12188
+ case "error": {
12189
+ const rawError = data.error ?? "Unknown error";
12190
+ await this.emitError(sessionId, rawError);
12191
+ break;
12192
+ }
12193
+ case "idle":
12194
+ await this.emitIdle(sessionId);
12195
+ break;
12196
+ }
12197
+ activity.state = state;
12198
+ }
12199
+ }
12200
+ async emitSessionStart(sessionId, data) {
12201
+ const rawProject = data.project ?? "pi-project";
12202
+ const rawModel = data.model ?? "minimax/moonshot";
12203
+ const eventData = {
12204
+ state: "session.start",
12205
+ project: rawProject,
12206
+ model: rawModel,
12207
+ raw: data
12208
+ };
12209
+ await this.emit("session.start", eventData, { sessionId });
12210
+ }
12211
+ async emitThinking(sessionId, content) {
12212
+ if (!content) return;
12213
+ const eventData = {
12214
+ state: "agent.thinking",
12215
+ thinkingContent: content
12216
+ };
12217
+ await this.emit("agent.thinking", eventData, { sessionId });
12218
+ }
12219
+ async emitToolCall(sessionId, toolInput, toolName) {
12220
+ const eventData = {
12221
+ state: "agent.tool_call",
12222
+ toolCallName: toolName,
12223
+ toolInput,
12224
+ activeFile: toolInput.filePath
12225
+ };
12226
+ await this.emit("agent.tool_call", eventData, { sessionId });
12227
+ }
12228
+ async emitOutput(sessionId, content) {
12229
+ if (!content) return;
12230
+ const eventData = {
12231
+ state: "agent.streaming",
12232
+ messageContent: content
12233
+ };
12234
+ await this.emit("agent.streaming", eventData, { sessionId });
12235
+ }
12236
+ async emitError(sessionId, errorMessage) {
12237
+ const eventData = {
12238
+ state: "agent.error",
12239
+ errorMessage,
12240
+ errorType: "api_error"
12241
+ };
12242
+ await this.emit("agent.error", eventData, { sessionId });
12243
+ }
12244
+ async emitIdle(sessionId) {
12245
+ const eventData = {
12246
+ state: "agent.idle"
12247
+ };
12248
+ await this.emit("agent.idle", eventData, { sessionId });
12249
+ }
12250
+ mapEventType(type) {
12251
+ const mapping = {
12252
+ "session.start": "session.start",
12253
+ "session.end": "session.end",
12254
+ "task.start": "task.start",
12255
+ "task.complete": "task.complete",
12256
+ thinking: "agent.thinking",
12257
+ tool: "agent.tool_call",
12258
+ coding: "agent.coding",
12259
+ output: "agent.streaming",
12260
+ message: "agent.streaming",
12261
+ ask: "agent.asking_user",
12262
+ error: "agent.error",
12263
+ idle: "agent.idle",
12264
+ compact: "agent.compact"
12265
+ };
12266
+ return mapping[type] ?? "agent.streaming";
12267
+ }
12268
+ buildEventData(eventType, payload) {
12269
+ const data = payload.data ?? {};
12270
+ return {
12271
+ state: eventType,
12272
+ project: data.project,
12273
+ activeFile: data.activeFile,
12274
+ model: data.model,
12275
+ toolInput: data.toolInput,
12276
+ toolCallName: data.toolCallName,
12277
+ thinkingContent: data.thinkingContent,
12278
+ messageContent: data.messageContent,
12279
+ finalMessage: data.finalMessage,
12280
+ toolResult: data.toolResult,
12281
+ errorMessage: data.errorMessage,
12282
+ errorType: data.errorType,
12283
+ raw: data.raw
12284
+ };
12285
+ }
12286
+ };
12287
+
12288
+ // src/adapters/zed.ts
12289
+ import { readFile as readFile12 } from "fs/promises";
12290
+ import { basename as basename11, join as join14 } from "path";
12291
+ var ZedAdapter = class extends BaseAdapter {
12292
+ displayName = "Zed AI";
12293
+ name = "zed";
12294
+ strategies = [
12295
+ "process-detect",
12296
+ "api-client"
12297
+ ];
12298
+ logPaths;
12299
+ apiPort = 9876;
12300
+ pollIntervalMs;
12301
+ poller = null;
12302
+ lastEventTime = 0;
12303
+ activeZedSessions = /* @__PURE__ */ new Map();
12304
+ constructor(options) {
12305
+ super(options);
12306
+ this.pollIntervalMs = 2e3;
12307
+ this.logPaths = [
12308
+ join14(options.homeDirectory ?? process.env.HOME ?? "", ".config", "zed", "logs", "agent.log"),
12309
+ "/tmp/zed-agent.log"
12310
+ ];
12311
+ }
12312
+ start() {
12313
+ if (this.getStatus().running) {
12314
+ return Promise.resolve();
12315
+ }
12316
+ this.setRunning(true);
12317
+ this.startPolling();
12318
+ logger.info({ adapter: this.name }, "Zed adapter started");
12319
+ return Promise.resolve();
12320
+ }
12321
+ stop() {
12322
+ if (this.poller !== null) {
12323
+ clearInterval(this.poller);
12324
+ this.poller = null;
12325
+ }
12326
+ this.setRunning(false);
12327
+ logger.info({ adapter: this.name }, "Zed adapter stopped");
12328
+ return Promise.resolve();
12329
+ }
12330
+ async handleHook(payload) {
12331
+ const normalized = this.parseNormalizedHookPayload(payload);
12332
+ if (normalized === null) {
12333
+ return;
12334
+ }
12335
+ const context = {
12336
+ cwd: normalized.cwd,
12337
+ pid: normalized.pid,
12338
+ sessionId: normalized.sessionId,
12339
+ source: "zed-hook"
12340
+ };
12341
+ const eventType = this.mapEventType(normalized.type ?? "");
12342
+ const eventData = this.buildEventData(eventType, normalized);
12343
+ await this.emit(eventType, eventData, context);
12344
+ }
12345
+ startPolling() {
12346
+ this.poller = setInterval(() => {
12347
+ void this.pollZedStatus();
12348
+ }, this.pollIntervalMs);
12349
+ }
12350
+ async pollZedStatus() {
12351
+ try {
12352
+ const response = await fetch(`http://127.0.0.1:${this.apiPort}/api/agent/status`, {
12353
+ signal: AbortSignal.timeout(1e3)
12354
+ });
12355
+ if (response.ok) {
12356
+ const data = await response.json();
12357
+ if (data.sessionId && typeof data.sessionId === "string") {
12358
+ const sessionId = `zed:${data.sessionId}`;
12359
+ if (!this.activeZedSessions.has(sessionId)) {
12360
+ this.activeZedSessions.set(sessionId, sessionId);
12361
+ await this.emitSessionStart(sessionId, data);
12362
+ }
12363
+ if (data.state === "thinking" && this.lastEventTime < Date.now() - 5e3) {
12364
+ const rawThinking = data.thinking;
12365
+ if (rawThinking) {
12366
+ await this.emitThinking(sessionId, rawThinking);
12367
+ }
12368
+ } else if (data.state === "tool" && data.toolName) {
12369
+ const rawFilePath = data.filePath;
12370
+ const rawCommand = data.command;
12371
+ const rawToolName = data.toolName ?? "unknown";
12372
+ await this.emitToolCall(
12373
+ sessionId,
12374
+ {
12375
+ filePath: rawFilePath ?? "",
12376
+ command: rawCommand ?? ""
12377
+ },
12378
+ rawToolName
12379
+ );
12380
+ } else if (data.state === "idle") {
12381
+ await this.emitIdle(sessionId);
12382
+ }
12383
+ }
12384
+ }
12385
+ } catch {
12386
+ await this.checkLogFiles();
12387
+ }
12388
+ }
12389
+ async checkLogFiles() {
12390
+ for (const logPath of this.logPaths) {
12391
+ try {
12392
+ const content = await readFile12(logPath, "utf8");
12393
+ await this.parseLogContent(content);
12394
+ } catch {
12395
+ }
12396
+ }
12397
+ }
12398
+ async parseLogContent(content) {
12399
+ const lines = content.split("\n").filter((line) => line.trim());
12400
+ for (const line of lines) {
12401
+ if (this.lastEventTime > 0 && this.lastEventTime >= Date.now() - 2e3) {
12402
+ continue;
12403
+ }
12404
+ const event = this.extractZedEventFromLog(line);
12405
+ if (event) {
12406
+ await this.handleHook(event);
12407
+ this.lastEventTime = Date.now();
12408
+ }
12409
+ }
12410
+ }
12411
+ extractZedEventFromLog(line) {
12412
+ try {
12413
+ const parsed = JSON.parse(line);
12414
+ if (!parsed.type || typeof parsed.type !== "string") {
12415
+ return null;
12416
+ }
12417
+ const rawSessionId = parsed.sessionId;
12418
+ const rawWorkspace = parsed.workspace;
12419
+ const sessionId = rawSessionId ? rawSessionId : rawWorkspace ? `zed:${basename11(rawWorkspace)}` : `zed:${Date.now()}`;
12420
+ const rawCwd = parsed.cwd ?? rawWorkspace;
12421
+ return {
12422
+ type: parsed.type,
12423
+ sessionId,
12424
+ cwd: rawCwd,
12425
+ data: {
12426
+ project: parsed.project ?? rawWorkspace ? basename11(String(rawWorkspace)) : void 0,
12427
+ model: parsed.model,
12428
+ state: parsed.type,
12429
+ thinkingContent: parsed.thinking,
12430
+ toolCallName: parsed.toolName,
12431
+ toolInput: parsed.toolInput,
12432
+ messageContent: parsed.message ?? parsed.output,
12433
+ errorMessage: parsed.error,
12434
+ raw: parsed
12435
+ }
12436
+ };
12437
+ } catch {
12438
+ if (line.includes("[zed:agent]")) {
12439
+ const cleaned = line.replace(/^\[.*?\] \[.*?\] /, "");
12440
+ if (cleaned.includes("Thinking:")) {
12441
+ return { type: "thinking", thinkingContent: cleaned.replace("Thinking:", "").trim() };
12442
+ }
12443
+ if (cleaned.includes("Executing tool:")) {
12444
+ return { type: "tool", toolCallName: cleaned.replace("Executing tool:", "").trim() };
12445
+ }
12446
+ if (cleaned.includes("Error:")) {
12447
+ return { type: "error", errorMessage: cleaned.replace("Error:", "").trim() };
12448
+ }
12449
+ }
12450
+ return null;
12451
+ }
12452
+ }
12453
+ async emitSessionStart(sessionId, _data) {
12454
+ const eventData = {
12455
+ state: "session.start",
12456
+ project: sessionId.split(":")[1] ?? "unknown"
12457
+ };
12458
+ await this.emit("session.start", eventData, { sessionId });
12459
+ }
12460
+ async emitThinking(sessionId, content) {
12461
+ if (!content) return;
12462
+ const eventData = {
12463
+ state: "agent.thinking",
12464
+ thinkingContent: content
12465
+ };
12466
+ await this.emit("agent.thinking", eventData, { sessionId });
12467
+ this.lastEventTime = Date.now();
12468
+ }
12469
+ async emitToolCall(sessionId, toolInput, toolName) {
12470
+ const eventData = {
12471
+ state: "agent.tool_call",
12472
+ toolCallName: toolName,
12473
+ toolInput,
12474
+ activeFile: toolInput.filePath
12475
+ };
12476
+ await this.emit("agent.tool_call", eventData, { sessionId });
12477
+ this.lastEventTime = Date.now();
12478
+ }
12479
+ async emitIdle(sessionId) {
12480
+ const eventData = {
12481
+ state: "agent.idle"
12482
+ };
12483
+ await this.emit("agent.idle", eventData, { sessionId });
12484
+ }
12485
+ mapEventType(type) {
12486
+ const mapping = {
12487
+ "session.start": "session.start",
12488
+ "session.end": "session.end",
12489
+ "task.start": "task.start",
12490
+ "task.complete": "task.complete",
12491
+ thinking: "agent.thinking",
12492
+ tool: "agent.tool_call",
12493
+ coding: "agent.coding",
12494
+ output: "agent.streaming",
12495
+ message: "agent.streaming",
12496
+ ask: "agent.asking_user",
12497
+ error: "agent.error",
12498
+ idle: "agent.idle",
12499
+ compact: "agent.compact"
12500
+ };
12501
+ return mapping[type] ?? "agent.streaming";
12502
+ }
12503
+ buildEventData(eventType, payload) {
12504
+ const data = payload.data ?? {};
12505
+ return {
12506
+ state: eventType,
12507
+ project: data.project,
12508
+ activeFile: data.activeFile,
12509
+ model: data.model,
12510
+ toolInput: data.toolInput,
12511
+ toolCallName: data.toolCallName,
12512
+ thinkingContent: data.thinkingContent,
12513
+ messageContent: data.messageContent,
12514
+ finalMessage: data.finalMessage,
12515
+ toolResult: data.toolResult,
12516
+ errorMessage: data.errorMessage,
12517
+ errorType: data.errorType,
12518
+ raw: data.raw
12519
+ };
12520
+ }
12521
+ };
12522
+
12523
+ // src/adapters/registry.ts
12524
+ var AdapterRegistry = class {
11041
12525
  adapters = /* @__PURE__ */ new Map();
11042
12526
  /**
11043
12527
  * Registers one built-in or community adapter instance.
@@ -11119,7 +12603,9 @@ function createDefaultAdapters(options) {
11119
12603
  new KiloAdapter(options),
11120
12604
  new CodexAdapter(options),
11121
12605
  new OpenClawAdapter(options),
11122
- new OpenCodeAdapter(options)
12606
+ new OpenCodeAdapter(options),
12607
+ new PiAdapter(options),
12608
+ new ZedAdapter(options)
11123
12609
  ];
11124
12610
  }
11125
12611
 
@@ -11140,7 +12626,7 @@ function getSocketPath(aisnitchHomePath) {
11140
12626
  if (process.platform === "win32") {
11141
12627
  return "\\\\.\\pipe\\aisnitch.sock";
11142
12628
  }
11143
- return join13(aisnitchHomePath, "aisnitch.sock");
12629
+ return join15(aisnitchHomePath, "aisnitch.sock");
11144
12630
  }
11145
12631
  var Pipeline = class {
11146
12632
  eventBus = new EventBus();
@@ -11345,6 +12831,30 @@ var Pipeline = class {
11345
12831
  getEventBus() {
11346
12832
  return this.eventBus;
11347
12833
  }
12834
+ /**
12835
+ * Returns the adapter registry for graceful shutdown coordination.
12836
+ */
12837
+ getAdapterRegistry() {
12838
+ return this.adapterRegistry ?? void 0;
12839
+ }
12840
+ /**
12841
+ * Returns the HTTP receiver for graceful shutdown coordination.
12842
+ */
12843
+ getHttpReceiver() {
12844
+ return this.httpReceiver;
12845
+ }
12846
+ /**
12847
+ * Returns the UDS server for graceful shutdown coordination.
12848
+ */
12849
+ getUdsServer() {
12850
+ return this.udsServer;
12851
+ }
12852
+ /**
12853
+ * Returns the WebSocket server for graceful shutdown coordination.
12854
+ */
12855
+ getWsServer() {
12856
+ return this.wsServer;
12857
+ }
11348
12858
  getHealthSnapshot() {
11349
12859
  const status = this.getStatus();
11350
12860
  return {
@@ -11469,6 +12979,72 @@ var DEFAULT_TIMEOUTS = Object.freeze({
11469
12979
  pipelineStartup: 15e3
11470
12980
  });
11471
12981
 
12982
+ // src/core/graceful-shutdown.ts
12983
+ async function withShutdownTimeout(fn, timeoutMs, component) {
12984
+ if (timeoutMs <= 0) {
12985
+ await fn();
12986
+ return;
12987
+ }
12988
+ const timeoutPromise = new Promise((resolve2) => {
12989
+ setTimeout(() => {
12990
+ resolve2("timed_out");
12991
+ }, timeoutMs).unref();
12992
+ });
12993
+ const result = await Promise.race([
12994
+ fn().then(() => "completed"),
12995
+ timeoutPromise
12996
+ ]);
12997
+ if (result === "timed_out") {
12998
+ logger.warn(
12999
+ { component, timeoutMs },
13000
+ `Graceful shutdown exceeded ${timeoutMs}ms timeout \u2014 forcing through`
13001
+ );
13002
+ }
13003
+ }
13004
+ async function shutdownInOrder(components, timeouts, label) {
13005
+ const getTimeout = (key) => {
13006
+ return timeouts[key] ?? DEFAULT_TIMEOUTS.daemonShutdown;
13007
+ };
13008
+ const stopSafely = async (key, fn) => {
13009
+ const timeoutMs = getTimeout(key);
13010
+ try {
13011
+ await withShutdownTimeout(fn, timeoutMs, `${label}.${key}`);
13012
+ } catch (error) {
13013
+ logger.warn(
13014
+ { error, key, label },
13015
+ `Error during shutdown of ${key} \u2014 continuing with remaining components`
13016
+ );
13017
+ }
13018
+ };
13019
+ if (components.cleanupFns) {
13020
+ for (const cleanupFn of components.cleanupFns) {
13021
+ try {
13022
+ await withShutdownTimeout(
13023
+ async () => {
13024
+ const result = cleanupFn();
13025
+ if (result instanceof Promise) {
13026
+ await result;
13027
+ }
13028
+ },
13029
+ 1e3,
13030
+ `${label}.cleanup`
13031
+ );
13032
+ } catch (error) {
13033
+ logger.warn({ error, label }, "Cleanup function failed");
13034
+ }
13035
+ }
13036
+ }
13037
+ if (components.eventBus) {
13038
+ components.eventBus.unsubscribeAll();
13039
+ }
13040
+ await stopSafely("wsServer", () => components.wsServer.stop());
13041
+ await stopSafely("udsServer", () => components.udsServer.stop());
13042
+ await stopSafely("httpReceiver", () => components.httpReceiver.stop());
13043
+ if (components.adapterRegistry) {
13044
+ await stopSafely("adapterRegistry", () => components.adapterRegistry.stopAll());
13045
+ }
13046
+ }
13047
+
11472
13048
  // src/tui/index.tsx
11473
13049
  import { render } from "ink";
11474
13050
  import { withFullScreen } from "fullscreen-ink";
@@ -11672,9 +13248,11 @@ var TOOL_COLORS = {
11672
13248
  "openhands": "#facc15",
11673
13249
  "openclaw": "#ef4444",
11674
13250
  "opencode": "#10b981",
13251
+ "pi": "#1db954",
11675
13252
  "qwen-code": "#22c55e",
11676
13253
  "unknown": "#94a3b8",
11677
- "windsurf": "#a855f7"
13254
+ "windsurf": "#a855f7",
13255
+ "zed": "#e85d04"
11678
13256
  };
11679
13257
  var EVENT_COLORS = {
11680
13258
  "agent.asking_user": "#ef4444",
@@ -13428,10 +15006,10 @@ async function renderManagedTui(options) {
13428
15006
 
13429
15007
  // src/cli/pid.ts
13430
15008
  import { constants as constants3 } from "fs";
13431
- import { mkdir as mkdir3, readFile as readFile12, rm as rm3, stat as stat10, writeFile as writeFile3, access as access3 } from "fs/promises";
15009
+ import { mkdir as mkdir3, readFile as readFile13, rm as rm3, stat as stat10, writeFile as writeFile3, access as access3 } from "fs/promises";
13432
15010
  import { createConnection as createConnection2 } from "net";
13433
15011
  import { homedir as homedir4 } from "os";
13434
- import { dirname as dirname7, join as join14 } from "path";
15012
+ import { dirname as dirname7, join as join16 } from "path";
13435
15013
  import { z as z5 } from "zod";
13436
15014
  var DaemonStateSchema = z5.strictObject({
13437
15015
  pid: z5.number().int().positive(),
@@ -13446,7 +15024,7 @@ function getDefaultSocketPath(options) {
13446
15024
  if (process.platform === "win32") {
13447
15025
  return "\\\\.\\pipe\\aisnitch.sock";
13448
15026
  }
13449
- return join14(getAISnitchHomePath(options), "aisnitch.sock");
15027
+ return join16(getAISnitchHomePath(options), "aisnitch.sock");
13450
15028
  }
13451
15029
  async function cleanupSocketPathIfStale(socketPath) {
13452
15030
  if (process.platform === "win32") {
@@ -13481,16 +15059,16 @@ async function cleanupSocketPathIfStale(socketPath) {
13481
15059
  return true;
13482
15060
  }
13483
15061
  function getPidFilePath(options = {}) {
13484
- return join14(getAISnitchHomePath(options), "aisnitch.pid");
15062
+ return join16(getAISnitchHomePath(options), "aisnitch.pid");
13485
15063
  }
13486
15064
  function getDaemonStatePath(options = {}) {
13487
- return join14(getAISnitchHomePath(options), "daemon-state.json");
15065
+ return join16(getAISnitchHomePath(options), "daemon-state.json");
13488
15066
  }
13489
15067
  function getDaemonLogPath(options = {}) {
13490
- return join14(getAISnitchHomePath(options), "daemon.log");
15068
+ return join16(getAISnitchHomePath(options), "daemon.log");
13491
15069
  }
13492
15070
  function getLaunchAgentPath(options = {}) {
13493
- return join14(
15071
+ return join16(
13494
15072
  options.launchAgentHomeDirectory ?? homedir4(),
13495
15073
  "Library",
13496
15074
  "LaunchAgents",
@@ -13506,7 +15084,7 @@ async function writePid(pid, options = {}) {
13506
15084
  }
13507
15085
  async function readPid(options = {}) {
13508
15086
  try {
13509
- const rawPid = await readFile12(getPidFilePath(options), "utf8");
15087
+ const rawPid = await readFile13(getPidFilePath(options), "utf8");
13510
15088
  const parsedPid = Number.parseInt(rawPid.trim(), 10);
13511
15089
  if (!Number.isInteger(parsedPid) || parsedPid <= 0) {
13512
15090
  throw new Error("Invalid PID file contents.");
@@ -13536,7 +15114,7 @@ async function writeDaemonState(state, options = {}) {
13536
15114
  }
13537
15115
  async function readDaemonState(options = {}) {
13538
15116
  try {
13539
- const rawJson = await readFile12(getDaemonStatePath(options), "utf8");
15117
+ const rawJson = await readFile13(getDaemonStatePath(options), "utf8");
13540
15118
  const parsedJson = JSON.parse(rawJson);
13541
15119
  return DaemonStateSchema.parse(parsedJson);
13542
15120
  } catch (error) {
@@ -13604,9 +15182,9 @@ function getEffectiveCliConfigPath(options = {}) {
13604
15182
 
13605
15183
  // src/cli/auto-update.ts
13606
15184
  import { spawn as spawnChildProcess } from "child_process";
13607
- import { mkdir as mkdir4, readFile as readFile13, writeFile as writeFile4 } from "fs/promises";
15185
+ import { mkdir as mkdir4, readFile as readFile14, writeFile as writeFile4 } from "fs/promises";
13608
15186
  import { realpath } from "fs/promises";
13609
- import { join as join15 } from "path";
15187
+ import { join as join17 } from "path";
13610
15188
  var AUTO_UPDATE_STATE_FILE = "auto-update.json";
13611
15189
  var AUTO_UPDATE_LOG_FILE = "auto-update.log";
13612
15190
  function createAutoUpdateController(dependencies = {}) {
@@ -13621,7 +15199,7 @@ function createAutoUpdateController(dependencies = {}) {
13621
15199
  const args = resolveUpdateArgs(options.manager);
13622
15200
  const aisnitchHomePath = getAISnitchHomePath(pathOptions);
13623
15201
  await mkdir4(aisnitchHomePath, { recursive: true });
13624
- const logFilePath = join15(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
15202
+ const logFilePath = join17(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
13625
15203
  const startedAt = now().toISOString();
13626
15204
  await writeAutoUpdateState(
13627
15205
  {
@@ -13809,7 +15387,7 @@ function resolveUpdateArgs(manager) {
13809
15387
  async function readAutoUpdateState(options) {
13810
15388
  const statePath = getAutoUpdateStatePath(options);
13811
15389
  try {
13812
- const rawJson = await readFile13(statePath, "utf8");
15390
+ const rawJson = await readFile14(statePath, "utf8");
13813
15391
  return JSON.parse(rawJson);
13814
15392
  } catch (error) {
13815
15393
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -13829,7 +15407,7 @@ async function writeAutoUpdateState(state, options) {
13829
15407
  );
13830
15408
  }
13831
15409
  function getAutoUpdateStatePath(options) {
13832
- return join15(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
15410
+ return join17(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
13833
15411
  }
13834
15412
  function toPathOptions(options) {
13835
15413
  return {
@@ -13943,9 +15521,9 @@ function flattenValue(lines, currentPath, value) {
13943
15521
  }
13944
15522
  lines.push(formatLoggerField(currentPath, value, inferValueKind(value)));
13945
15523
  }
13946
- function formatLoggerField(path, value, kind) {
15524
+ function formatLoggerField(path2, value, kind) {
13947
15525
  const renderedValue = typeof value === "string" ? JSON.stringify(value) : value === null ? "null" : typeof value === "undefined" ? "undefined" : JSON.stringify(value);
13948
- return `${colorize(path, TUI_THEME.warning)} ${colorize("=", TUI_THEME.muted)} ${colorize(
15526
+ return `${colorize(path2, TUI_THEME.warning)} ${colorize("=", TUI_THEME.muted)} ${colorize(
13949
15527
  renderedValue,
13950
15528
  getValueColor(kind)
13951
15529
  )}`;
@@ -14020,7 +15598,8 @@ function isRecord13(value) {
14020
15598
  }
14021
15599
 
14022
15600
  // src/cli/runtime.ts
14023
- var execFile14 = promisify14(execFileCallback14);
15601
+ var openPromise = Promise.resolve().then(() => (init_open(), open_exports));
15602
+ var execFile21 = promisify21(execFileCallback14);
14024
15603
  var DAEMON_READY_TIMEOUT_MS = 4e3;
14025
15604
  var DAEMON_READY_POLL_INTERVAL_MS = 100;
14026
15605
  var DAEMON_STOP_TIMEOUT_MS = 4e3;
@@ -14036,7 +15615,7 @@ function createCliRuntime(dependencies = {}) {
14036
15615
  spawn: spawnImplementation
14037
15616
  });
14038
15617
  const execFileImplementation = dependencies.execFile ?? (async (file, args) => {
14039
- return await execFile14(file, [...args], {
15618
+ return await execFile21(file, [...args], {
14040
15619
  encoding: "utf8"
14041
15620
  });
14042
15621
  });
@@ -14211,7 +15790,7 @@ function createCliRuntime(dependencies = {}) {
14211
15790
  }
14212
15791
  async function readDaemonStartupFailure(pathOptions) {
14213
15792
  try {
14214
- const daemonLog = await readFile14(getDaemonLogPath(pathOptions), "utf8");
15793
+ const daemonLog = await readFile15(getDaemonLogPath(pathOptions), "utf8");
14215
15794
  const logLines = daemonLog.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
14216
15795
  const lastLine = logLines.at(-1);
14217
15796
  if (!lastLine) {
@@ -14309,22 +15888,35 @@ function createCliRuntime(dependencies = {}) {
14309
15888
  return;
14310
15889
  }
14311
15890
  shuttingDown = true;
14312
- try {
14313
- await pipeline.stop();
14314
- } finally {
14315
- if (daemonMode) {
14316
- const daemonPathOptions = toPathOptions2(options);
15891
+ const shutdownTimeouts = {
15892
+ adapterRegistry: DEFAULT_TIMEOUTS.adapterShutdown,
15893
+ httpReceiver: DEFAULT_TIMEOUTS.httpRequest,
15894
+ udsServer: DEFAULT_TIMEOUTS.fileOperation,
15895
+ wsServer: DEFAULT_TIMEOUTS.wsConnection,
15896
+ cleanupFns: 1e3
15897
+ };
15898
+ const components = {
15899
+ adapterRegistry: pipeline.getAdapterRegistry(),
15900
+ httpReceiver: pipeline.getHttpReceiver(),
15901
+ udsServer: pipeline.getUdsServer(),
15902
+ wsServer: pipeline.getWsServer(),
15903
+ eventBus: pipeline.getEventBus(),
15904
+ cleanupFns: daemonMode ? [async () => {
14317
15905
  await Promise.all([
14318
- removePid(daemonPathOptions),
14319
- removeDaemonState(daemonPathOptions)
15906
+ removePid(toPathOptions2(options)),
15907
+ removeDaemonState(toPathOptions2(options))
14320
15908
  ]);
14321
- }
14322
- }
14323
- if (!daemonMode) {
14324
- output.stdout(`AISnitch stopped after ${signal}.
15909
+ }] : []
15910
+ };
15911
+ try {
15912
+ await shutdownInOrder(components, shutdownTimeouts, "pipeline");
15913
+ } finally {
15914
+ if (!daemonMode) {
15915
+ output.stdout(`AISnitch stopped after ${signal}.
14325
15916
  `);
15917
+ }
15918
+ process.exit(exitCode);
14326
15919
  }
14327
- process.exit(exitCode);
14328
15920
  };
14329
15921
  if (daemonMode) {
14330
15922
  process.once("SIGTERM", () => {
@@ -14510,6 +16102,113 @@ function createCliRuntime(dependencies = {}) {
14510
16102
  }
14511
16103
  });
14512
16104
  }
16105
+ async function fullscreen(options) {
16106
+ const snapshot = await getStatusSnapshot(options);
16107
+ if (!snapshot.running && options.daemonMode) {
16108
+ output.stdout("Starting daemon...\n");
16109
+ await startDetachedDaemon(options);
16110
+ }
16111
+ if (!snapshot.running && !options.daemonMode) {
16112
+ throw new Error(
16113
+ "AISnitch daemon is not running. Start one with `aisnitch start --daemon` or use `aisnitch fs --daemon` to start and open the dashboard."
16114
+ );
16115
+ }
16116
+ for (let i = 0; i < 20; i++) {
16117
+ const health = await fetchHealth(snapshot.httpPort);
16118
+ if (health) break;
16119
+ await new Promise((resolve2) => setTimeout(resolve2, 200).unref());
16120
+ }
16121
+ const dashboardPort = options.dashboardPort ?? 5174;
16122
+ const dashboardUrl = `http://127.0.0.1:${dashboardPort}`;
16123
+ const distPath = join18(process.cwd(), "examples", "fullscreen-dashboard", "dist");
16124
+ output.stdout(`Starting dashboard server on port ${dashboardPort}...
16125
+ `);
16126
+ const viteProcess = spawnImplementation(process.execPath, [
16127
+ "-e",
16128
+ `
16129
+ import { createServer } from 'vite';
16130
+ import path from 'path';
16131
+
16132
+ const distPath = '${distPath}';
16133
+ const port = ${dashboardPort};
16134
+
16135
+ const server = await createServer({
16136
+ root: distPath,
16137
+ server: {
16138
+ port,
16139
+ strictPort: true,
16140
+ allowedHosts: true,
16141
+ },
16142
+ preview: {
16143
+ port,
16144
+ strictPort: true,
16145
+ },
16146
+ });
16147
+
16148
+ await server.listen();
16149
+ console.log('READY');
16150
+
16151
+ process.stdin.resume();
16152
+ `
16153
+ ], {
16154
+ cwd: distPath,
16155
+ stdio: ["pipe", "pipe", "pipe"]
16156
+ });
16157
+ let serverOutput = "";
16158
+ viteProcess.stdout?.on("data", (data) => {
16159
+ serverOutput += data.toString();
16160
+ });
16161
+ viteProcess.stderr?.on("data", (data) => {
16162
+ serverOutput += data.toString();
16163
+ });
16164
+ let serverReady = false;
16165
+ for (let i = 0; i < 100; i++) {
16166
+ await new Promise((resolve2) => setTimeout(resolve2, 100).unref());
16167
+ try {
16168
+ const response = await fetchImplementation(dashboardUrl);
16169
+ if (response.ok) {
16170
+ serverReady = true;
16171
+ break;
16172
+ }
16173
+ } catch {
16174
+ }
16175
+ if (!viteProcess.pid) break;
16176
+ }
16177
+ if (!serverReady) {
16178
+ output.stdout(`Server output: ${serverOutput}
16179
+ `);
16180
+ throw new Error("Failed to start dashboard server");
16181
+ }
16182
+ output.stdout(`Dashboard ready at ${dashboardUrl}
16183
+ `);
16184
+ if (!options.noBrowser) {
16185
+ output.stdout("Opening browser...\n");
16186
+ const openModule = await openPromise;
16187
+ await openModule.default(dashboardUrl);
16188
+ }
16189
+ output.stdout("Press Ctrl+C to stop\n");
16190
+ await new Promise((resolve2) => {
16191
+ const shutdown = () => {
16192
+ process.off("SIGINT", handleSigint);
16193
+ process.off("SIGTERM", handleSigterm);
16194
+ if (viteProcess.pid !== void 0) {
16195
+ try {
16196
+ process.kill(viteProcess.pid, "SIGTERM");
16197
+ } catch {
16198
+ }
16199
+ }
16200
+ resolve2();
16201
+ };
16202
+ const handleSigint = () => {
16203
+ shutdown();
16204
+ };
16205
+ const handleSigterm = () => {
16206
+ shutdown();
16207
+ };
16208
+ process.once("SIGINT", handleSigint);
16209
+ process.once("SIGTERM", handleSigterm);
16210
+ });
16211
+ }
14513
16212
  async function logger2(options) {
14514
16213
  const snapshot = await getStatusSnapshot(options);
14515
16214
  if (!snapshot.running) {
@@ -14581,7 +16280,7 @@ function createCliRuntime(dependencies = {}) {
14581
16280
  }
14582
16281
  const { config } = await loadEffectiveConfig(options);
14583
16282
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14584
- const ephemeralHomeDirectory = await mkdtemp(join16(tmpdir(), "aisnitch-mock-"));
16283
+ const ephemeralHomeDirectory = await mkdtemp(join18(tmpdir(), "aisnitch-mock-"));
14585
16284
  const ephemeralPipeline = new Pipeline();
14586
16285
  const status2 = await ephemeralPipeline.start({
14587
16286
  config: {
@@ -14665,7 +16364,7 @@ function createCliRuntime(dependencies = {}) {
14665
16364
  } else {
14666
16365
  const { config } = await loadEffectiveConfig(options);
14667
16366
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14668
- ephemeralHomeDirectory = await mkdtemp(join16(tmpdir(), "aisnitch-wrap-"));
16367
+ ephemeralHomeDirectory = await mkdtemp(join18(tmpdir(), "aisnitch-wrap-"));
14669
16368
  ephemeralPipeline = new Pipeline();
14670
16369
  await ephemeralPipeline.start({
14671
16370
  config: {
@@ -14740,7 +16439,7 @@ function createCliRuntime(dependencies = {}) {
14740
16439
  },
14741
16440
  pid: process.ppid > 1 ? process.ppid : void 0,
14742
16441
  source: "aisnitch://adapters/aider/notifications-command",
14743
- transcriptPath: join16(process.cwd(), ".aider.chat.history.md"),
16442
+ transcriptPath: join18(process.cwd(), ".aider.chat.history.md"),
14744
16443
  type: "agent.idle"
14745
16444
  }),
14746
16445
  headers: {
@@ -14801,6 +16500,7 @@ function createCliRuntime(dependencies = {}) {
14801
16500
  adapters,
14802
16501
  aiderNotify,
14803
16502
  attach,
16503
+ fullscreen,
14804
16504
  install,
14805
16505
  logger: logger2,
14806
16506
  mock,
@@ -14941,7 +16641,7 @@ function joinSocketPath(pathOptions) {
14941
16641
  }
14942
16642
  function resolveCliEntryPath() {
14943
16643
  const cliEntryPath = process.argv[1];
14944
- if (!cliEntryPath || basename11(cliEntryPath).length === 0) {
16644
+ if (!cliEntryPath || basename12(cliEntryPath).length === 0) {
14945
16645
  throw new Error("Unable to resolve the AISnitch CLI entry path.");
14946
16646
  }
14947
16647
  return cliEntryPath;
@@ -15012,6 +16712,9 @@ Examples:
15012
16712
  aisnitch start --daemon
15013
16713
  aisnitch start --view full-data
15014
16714
  aisnitch start --mock
16715
+ aisnitch fs
16716
+ aisnitch fs --daemon
16717
+ aisnitch fs --dashboard-port 8080
15015
16718
  aisnitch status
15016
16719
  aisnitch attach
15017
16720
  aisnitch attach --view full-data
@@ -15035,6 +16738,7 @@ Examples:
15035
16738
  addAdaptersCommand(program, runtime);
15036
16739
  addSetupCommand(program, runtime);
15037
16740
  addAttachCommand(program, runtime);
16741
+ addFullscreenCommand(program, runtime);
15038
16742
  addLoggerCommand(program, runtime);
15039
16743
  addMockCommand(program, runtime);
15040
16744
  addWrapCommand(program, runtime);
@@ -15167,6 +16871,23 @@ function addAttachCommand(program, runtime) {
15167
16871
  await runtime.attach(options);
15168
16872
  });
15169
16873
  }
16874
+ function addFullscreenCommand(program, runtime) {
16875
+ addCommonOptions(
16876
+ program.command("fs").description("Open the fullscreen web dashboard in browser (starts daemon if needed with --daemon)").alias("fullscreen").option(
16877
+ "--daemon",
16878
+ "Start the daemon automatically if not running"
16879
+ ).option(
16880
+ "--dashboard-port <port>",
16881
+ "Port for the dashboard server (default: 5174)",
16882
+ wrapOptionParser(parsePortOption)
16883
+ ).option(
16884
+ "--no-browser",
16885
+ "Start server without opening browser"
16886
+ )
16887
+ ).action(async (options) => {
16888
+ await runtime.fullscreen(options);
16889
+ });
16890
+ }
15170
16891
  function addWrapCommand(program, runtime) {
15171
16892
  addCommonOptions(
15172
16893
  program.command("wrap").description("Run a command inside a PTY while AISnitch observes its terminal activity").allowUnknownOption(true).argument("<command>", "Command to wrap").argument("[args...]", "Arguments forwarded to the wrapped command").option("--cwd <path>", "Run the wrapped command from a specific working directory")