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.
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __export = (target, all) => {
10
13
  for (var name in all)
11
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -28,6 +31,733 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
31
  ));
29
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
33
 
34
+ // node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
35
+ function hasDockerEnv() {
36
+ try {
37
+ import_node_fs4.default.statSync("/.dockerenv");
38
+ return true;
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ function hasDockerCGroup() {
44
+ try {
45
+ return import_node_fs4.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+ function isDocker() {
51
+ if (isDockerCached === void 0) {
52
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
53
+ }
54
+ return isDockerCached;
55
+ }
56
+ var import_node_fs4, isDockerCached;
57
+ var init_is_docker = __esm({
58
+ "node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js"() {
59
+ "use strict";
60
+ import_node_fs4 = __toESM(require("fs"), 1);
61
+ }
62
+ });
63
+
64
+ // node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
65
+ function isInsideContainer() {
66
+ if (cachedResult === void 0) {
67
+ cachedResult = hasContainerEnv() || isDocker();
68
+ }
69
+ return cachedResult;
70
+ }
71
+ var import_node_fs5, cachedResult, hasContainerEnv;
72
+ var init_is_inside_container = __esm({
73
+ "node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js"() {
74
+ "use strict";
75
+ import_node_fs5 = __toESM(require("fs"), 1);
76
+ init_is_docker();
77
+ hasContainerEnv = () => {
78
+ try {
79
+ import_node_fs5.default.statSync("/run/.containerenv");
80
+ return true;
81
+ } catch {
82
+ return false;
83
+ }
84
+ };
85
+ }
86
+ });
87
+
88
+ // node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js
89
+ var import_node_process, import_node_os5, import_node_fs6, isWsl, is_wsl_default;
90
+ var init_is_wsl = __esm({
91
+ "node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js"() {
92
+ "use strict";
93
+ import_node_process = __toESM(require("process"), 1);
94
+ import_node_os5 = __toESM(require("os"), 1);
95
+ import_node_fs6 = __toESM(require("fs"), 1);
96
+ init_is_inside_container();
97
+ isWsl = () => {
98
+ if (import_node_process.default.platform !== "linux") {
99
+ return false;
100
+ }
101
+ if (import_node_os5.default.release().toLowerCase().includes("microsoft")) {
102
+ if (isInsideContainer()) {
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+ try {
108
+ if (import_node_fs6.default.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
109
+ return !isInsideContainer();
110
+ }
111
+ } catch {
112
+ }
113
+ if (import_node_fs6.default.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || import_node_fs6.default.existsSync("/run/WSL")) {
114
+ return !isInsideContainer();
115
+ }
116
+ return false;
117
+ };
118
+ is_wsl_default = import_node_process.default.env.__IS_WSL_TEST__ ? isWsl : isWsl();
119
+ }
120
+ });
121
+
122
+ // node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js
123
+ var import_node_process2, import_node_buffer, import_node_util15, import_node_child_process16, import_promises19, execFile15, powerShellPath, executePowerShell;
124
+ var init_powershell_utils = __esm({
125
+ "node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js"() {
126
+ "use strict";
127
+ import_node_process2 = __toESM(require("process"), 1);
128
+ import_node_buffer = require("buffer");
129
+ import_node_util15 = require("util");
130
+ import_node_child_process16 = __toESM(require("child_process"), 1);
131
+ import_promises19 = __toESM(require("fs/promises"), 1);
132
+ execFile15 = (0, import_node_util15.promisify)(import_node_child_process16.default.execFile);
133
+ powerShellPath = () => `${import_node_process2.default.env.SYSTEMROOT || import_node_process2.default.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
134
+ executePowerShell = async (command, options = {}) => {
135
+ const {
136
+ powerShellPath: psPath,
137
+ ...execFileOptions
138
+ } = options;
139
+ const encodedCommand = executePowerShell.encodeCommand(command);
140
+ return execFile15(
141
+ psPath ?? powerShellPath(),
142
+ [
143
+ ...executePowerShell.argumentsPrefix,
144
+ encodedCommand
145
+ ],
146
+ {
147
+ encoding: "utf8",
148
+ ...execFileOptions
149
+ }
150
+ );
151
+ };
152
+ executePowerShell.argumentsPrefix = [
153
+ "-NoProfile",
154
+ "-NonInteractive",
155
+ "-ExecutionPolicy",
156
+ "Bypass",
157
+ "-EncodedCommand"
158
+ ];
159
+ executePowerShell.encodeCommand = (command) => import_node_buffer.Buffer.from(command, "utf16le").toString("base64");
160
+ executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
161
+ }
162
+ });
163
+
164
+ // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js
165
+ function parseMountPointFromConfig(content) {
166
+ for (const line of content.split("\n")) {
167
+ if (/^\s*#/.test(line)) {
168
+ continue;
169
+ }
170
+ const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
171
+ if (!match) {
172
+ continue;
173
+ }
174
+ return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
175
+ }
176
+ }
177
+ var init_utilities = __esm({
178
+ "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js"() {
179
+ "use strict";
180
+ }
181
+ });
182
+
183
+ // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
184
+ var import_node_util16, import_node_child_process17, import_promises20, execFile16, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
185
+ var init_wsl_utils = __esm({
186
+ "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
187
+ "use strict";
188
+ import_node_util16 = require("util");
189
+ import_node_child_process17 = __toESM(require("child_process"), 1);
190
+ import_promises20 = __toESM(require("fs/promises"), 1);
191
+ init_is_wsl();
192
+ init_powershell_utils();
193
+ init_utilities();
194
+ init_is_wsl();
195
+ execFile16 = (0, import_node_util16.promisify)(import_node_child_process17.default.execFile);
196
+ wslDrivesMountPoint = /* @__PURE__ */ (() => {
197
+ const defaultMountPoint = "/mnt/";
198
+ let mountPoint;
199
+ return async function() {
200
+ if (mountPoint) {
201
+ return mountPoint;
202
+ }
203
+ const configFilePath = "/etc/wsl.conf";
204
+ let isConfigFileExists = false;
205
+ try {
206
+ await import_promises20.default.access(configFilePath, import_promises20.constants.F_OK);
207
+ isConfigFileExists = true;
208
+ } catch {
209
+ }
210
+ if (!isConfigFileExists) {
211
+ return defaultMountPoint;
212
+ }
213
+ const configContent = await import_promises20.default.readFile(configFilePath, { encoding: "utf8" });
214
+ const parsedMountPoint = parseMountPointFromConfig(configContent);
215
+ if (parsedMountPoint === void 0) {
216
+ return defaultMountPoint;
217
+ }
218
+ mountPoint = parsedMountPoint;
219
+ mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
220
+ return mountPoint;
221
+ };
222
+ })();
223
+ powerShellPathFromWsl = async () => {
224
+ const mountPoint = await wslDrivesMountPoint();
225
+ return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
226
+ };
227
+ powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
228
+ canAccessPowerShell = async () => {
229
+ canAccessPowerShellPromise ??= (async () => {
230
+ try {
231
+ const psPath = await powerShellPath2();
232
+ await import_promises20.default.access(psPath, import_promises20.constants.X_OK);
233
+ return true;
234
+ } catch {
235
+ return false;
236
+ }
237
+ })();
238
+ return canAccessPowerShellPromise;
239
+ };
240
+ wslDefaultBrowser = async () => {
241
+ const psPath = await powerShellPath2();
242
+ const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
243
+ const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
244
+ return stdout.trim();
245
+ };
246
+ convertWslPathToWindows = async (path2) => {
247
+ if (/^[a-z]+:\/\//i.test(path2)) {
248
+ return path2;
249
+ }
250
+ try {
251
+ const { stdout } = await execFile16("wslpath", ["-aw", path2], { encoding: "utf8" });
252
+ return stdout.trim();
253
+ } catch {
254
+ return path2;
255
+ }
256
+ };
257
+ }
258
+ });
259
+
260
+ // node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
261
+ function defineLazyProperty(object, propertyName, valueGetter) {
262
+ const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
263
+ Object.defineProperty(object, propertyName, {
264
+ configurable: true,
265
+ enumerable: true,
266
+ get() {
267
+ const result = valueGetter();
268
+ define(result);
269
+ return result;
270
+ },
271
+ set(value) {
272
+ define(value);
273
+ }
274
+ });
275
+ return object;
276
+ }
277
+ var init_define_lazy_prop = __esm({
278
+ "node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js"() {
279
+ "use strict";
280
+ }
281
+ });
282
+
283
+ // node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
284
+ async function defaultBrowserId() {
285
+ if (import_node_process3.default.platform !== "darwin") {
286
+ throw new Error("macOS only");
287
+ }
288
+ const { stdout } = await execFileAsync2("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
289
+ const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
290
+ const browserId = match?.groups.id ?? "com.apple.Safari";
291
+ if (browserId === "com.apple.safari") {
292
+ return "com.apple.Safari";
293
+ }
294
+ return browserId;
295
+ }
296
+ var import_node_util17, import_node_process3, import_node_child_process18, execFileAsync2;
297
+ var init_default_browser_id = __esm({
298
+ "node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js"() {
299
+ "use strict";
300
+ import_node_util17 = require("util");
301
+ import_node_process3 = __toESM(require("process"), 1);
302
+ import_node_child_process18 = require("child_process");
303
+ execFileAsync2 = (0, import_node_util17.promisify)(import_node_child_process18.execFile);
304
+ }
305
+ });
306
+
307
+ // node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
308
+ async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
309
+ if (import_node_process4.default.platform !== "darwin") {
310
+ throw new Error("macOS only");
311
+ }
312
+ const outputArguments = humanReadableOutput ? [] : ["-ss"];
313
+ const execOptions = {};
314
+ if (signal) {
315
+ execOptions.signal = signal;
316
+ }
317
+ const { stdout } = await execFileAsync3("osascript", ["-e", script, outputArguments], execOptions);
318
+ return stdout.trim();
319
+ }
320
+ var import_node_process4, import_node_util18, import_node_child_process19, execFileAsync3;
321
+ var init_run_applescript = __esm({
322
+ "node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js"() {
323
+ "use strict";
324
+ import_node_process4 = __toESM(require("process"), 1);
325
+ import_node_util18 = require("util");
326
+ import_node_child_process19 = require("child_process");
327
+ execFileAsync3 = (0, import_node_util18.promisify)(import_node_child_process19.execFile);
328
+ }
329
+ });
330
+
331
+ // node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
332
+ async function bundleName(bundleId) {
333
+ return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
334
+ tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
335
+ }
336
+ var init_bundle_name = __esm({
337
+ "node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js"() {
338
+ "use strict";
339
+ init_run_applescript();
340
+ }
341
+ });
342
+
343
+ // node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js
344
+ async function defaultBrowser(_execFileAsync = execFileAsync4) {
345
+ const { stdout } = await _execFileAsync("reg", [
346
+ "QUERY",
347
+ " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
348
+ "/v",
349
+ "ProgId"
350
+ ]);
351
+ const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
352
+ if (!match) {
353
+ throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
354
+ }
355
+ const { id } = match.groups;
356
+ const dotIndex = id.lastIndexOf(".");
357
+ const hyphenIndex = id.lastIndexOf("-");
358
+ const baseIdByDot = dotIndex === -1 ? void 0 : id.slice(0, dotIndex);
359
+ const baseIdByHyphen = hyphenIndex === -1 ? void 0 : id.slice(0, hyphenIndex);
360
+ return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
361
+ }
362
+ var import_node_util19, import_node_child_process20, execFileAsync4, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
363
+ var init_windows = __esm({
364
+ "node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js"() {
365
+ "use strict";
366
+ import_node_util19 = require("util");
367
+ import_node_child_process20 = require("child_process");
368
+ execFileAsync4 = (0, import_node_util19.promisify)(import_node_child_process20.execFile);
369
+ windowsBrowserProgIds = {
370
+ MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
371
+ // The missing `L` is correct.
372
+ MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
373
+ MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
374
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
375
+ ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
376
+ ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
377
+ ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
378
+ ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
379
+ BraveHTML: { name: "Brave", id: "com.brave.Browser" },
380
+ BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
381
+ BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
382
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
383
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
384
+ OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
385
+ VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
386
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
387
+ };
388
+ _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
389
+ UnknownBrowserError = class extends Error {
390
+ };
391
+ }
392
+ });
393
+
394
+ // node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js
395
+ async function defaultBrowser2() {
396
+ if (import_node_process5.default.platform === "darwin") {
397
+ const id = await defaultBrowserId();
398
+ const name = await bundleName(id);
399
+ return { name, id };
400
+ }
401
+ if (import_node_process5.default.platform === "linux") {
402
+ const { stdout } = await execFileAsync5("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
403
+ const id = stdout.trim();
404
+ const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
405
+ return { name, id };
406
+ }
407
+ if (import_node_process5.default.platform === "win32") {
408
+ return defaultBrowser();
409
+ }
410
+ throw new Error("Only macOS, Linux, and Windows are supported");
411
+ }
412
+ var import_node_util20, import_node_process5, import_node_child_process21, execFileAsync5, titleize;
413
+ var init_default_browser = __esm({
414
+ "node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js"() {
415
+ "use strict";
416
+ import_node_util20 = require("util");
417
+ import_node_process5 = __toESM(require("process"), 1);
418
+ import_node_child_process21 = require("child_process");
419
+ init_default_browser_id();
420
+ init_bundle_name();
421
+ init_windows();
422
+ init_windows();
423
+ execFileAsync5 = (0, import_node_util20.promisify)(import_node_child_process21.execFile);
424
+ titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
425
+ }
426
+ });
427
+
428
+ // node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js
429
+ var import_node_process6, isInSsh, is_in_ssh_default;
430
+ var init_is_in_ssh = __esm({
431
+ "node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js"() {
432
+ "use strict";
433
+ import_node_process6 = __toESM(require("process"), 1);
434
+ isInSsh = Boolean(import_node_process6.default.env.SSH_CONNECTION || import_node_process6.default.env.SSH_CLIENT || import_node_process6.default.env.SSH_TTY);
435
+ is_in_ssh_default = isInSsh;
436
+ }
437
+ });
438
+
439
+ // node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
440
+ var open_exports = {};
441
+ __export(open_exports, {
442
+ apps: () => apps,
443
+ default: () => open_default,
444
+ openApp: () => openApp
445
+ });
446
+ function detectArchBinary(binary) {
447
+ if (typeof binary === "string" || Array.isArray(binary)) {
448
+ return binary;
449
+ }
450
+ const { [arch]: archBinary } = binary;
451
+ if (!archBinary) {
452
+ throw new Error(`${arch} is not supported`);
453
+ }
454
+ return archBinary;
455
+ }
456
+ function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
457
+ if (wsl && is_wsl_default) {
458
+ return detectArchBinary(wsl);
459
+ }
460
+ if (!platformBinary) {
461
+ throw new Error(`${platform} is not supported`);
462
+ }
463
+ return detectArchBinary(platformBinary);
464
+ }
465
+ var import_node_process7, import_node_path21, import_node_url, import_node_child_process22, import_promises21, import_meta, fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
466
+ var init_open = __esm({
467
+ "node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
468
+ "use strict";
469
+ import_node_process7 = __toESM(require("process"), 1);
470
+ import_node_path21 = __toESM(require("path"), 1);
471
+ import_node_url = require("url");
472
+ import_node_child_process22 = __toESM(require("child_process"), 1);
473
+ import_promises21 = __toESM(require("fs/promises"), 1);
474
+ init_wsl_utils();
475
+ init_powershell_utils();
476
+ init_define_lazy_prop();
477
+ init_default_browser();
478
+ init_is_inside_container();
479
+ init_is_in_ssh();
480
+ import_meta = {};
481
+ fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
482
+ __dirname = import_meta.url ? import_node_path21.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)) : "";
483
+ localXdgOpenPath = import_node_path21.default.join(__dirname, "xdg-open");
484
+ ({ platform, arch } = import_node_process7.default);
485
+ tryEachApp = async (apps2, opener) => {
486
+ if (apps2.length === 0) {
487
+ return;
488
+ }
489
+ const errors = [];
490
+ for (const app of apps2) {
491
+ try {
492
+ return await opener(app);
493
+ } catch (error) {
494
+ errors.push(error);
495
+ }
496
+ }
497
+ throw new AggregateError(errors, "Failed to open in all supported apps");
498
+ };
499
+ baseOpen = async (options) => {
500
+ options = {
501
+ wait: false,
502
+ background: false,
503
+ newInstance: false,
504
+ allowNonzeroExitCode: false,
505
+ ...options
506
+ };
507
+ const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
508
+ delete options[fallbackAttemptSymbol];
509
+ if (Array.isArray(options.app)) {
510
+ return tryEachApp(options.app, (singleApp) => baseOpen({
511
+ ...options,
512
+ app: singleApp,
513
+ [fallbackAttemptSymbol]: true
514
+ }));
515
+ }
516
+ let { name: app, arguments: appArguments = [] } = options.app ?? {};
517
+ appArguments = [...appArguments];
518
+ if (Array.isArray(app)) {
519
+ return tryEachApp(app, (appName) => baseOpen({
520
+ ...options,
521
+ app: {
522
+ name: appName,
523
+ arguments: appArguments
524
+ },
525
+ [fallbackAttemptSymbol]: true
526
+ }));
527
+ }
528
+ if (app === "browser" || app === "browserPrivate") {
529
+ const ids = {
530
+ "com.google.chrome": "chrome",
531
+ "google-chrome.desktop": "chrome",
532
+ "com.brave.browser": "brave",
533
+ "org.mozilla.firefox": "firefox",
534
+ "firefox.desktop": "firefox",
535
+ "com.microsoft.msedge": "edge",
536
+ "com.microsoft.edge": "edge",
537
+ "com.microsoft.edgemac": "edge",
538
+ "microsoft-edge.desktop": "edge",
539
+ "com.apple.safari": "safari"
540
+ };
541
+ const flags = {
542
+ chrome: "--incognito",
543
+ brave: "--incognito",
544
+ firefox: "--private-window",
545
+ edge: "--inPrivate"
546
+ // Safari doesn't support private mode via command line
547
+ };
548
+ let browser;
549
+ if (is_wsl_default) {
550
+ const progId = await wslDefaultBrowser();
551
+ const browserInfo = _windowsBrowserProgIdMap.get(progId);
552
+ browser = browserInfo ?? {};
553
+ } else {
554
+ browser = await defaultBrowser2();
555
+ }
556
+ if (browser.id in ids) {
557
+ const browserName = ids[browser.id.toLowerCase()];
558
+ if (app === "browserPrivate") {
559
+ if (browserName === "safari") {
560
+ throw new Error("Safari doesn't support opening in private mode via command line");
561
+ }
562
+ appArguments.push(flags[browserName]);
563
+ }
564
+ return baseOpen({
565
+ ...options,
566
+ app: {
567
+ name: apps[browserName],
568
+ arguments: appArguments
569
+ }
570
+ });
571
+ }
572
+ throw new Error(`${browser.name} is not supported as a default browser`);
573
+ }
574
+ let command;
575
+ const cliArguments = [];
576
+ const childProcessOptions = {};
577
+ let shouldUseWindowsInWsl = false;
578
+ if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
579
+ shouldUseWindowsInWsl = await canAccessPowerShell();
580
+ }
581
+ if (platform === "darwin") {
582
+ command = "open";
583
+ if (options.wait) {
584
+ cliArguments.push("--wait-apps");
585
+ }
586
+ if (options.background) {
587
+ cliArguments.push("--background");
588
+ }
589
+ if (options.newInstance) {
590
+ cliArguments.push("--new");
591
+ }
592
+ if (app) {
593
+ cliArguments.push("-a", app);
594
+ }
595
+ } else if (platform === "win32" || shouldUseWindowsInWsl) {
596
+ command = await powerShellPath2();
597
+ cliArguments.push(...executePowerShell.argumentsPrefix);
598
+ if (!is_wsl_default) {
599
+ childProcessOptions.windowsVerbatimArguments = true;
600
+ }
601
+ if (is_wsl_default && options.target) {
602
+ options.target = await convertWslPathToWindows(options.target);
603
+ }
604
+ const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
605
+ if (options.wait) {
606
+ encodedArguments.push("-Wait");
607
+ }
608
+ if (app) {
609
+ encodedArguments.push(executePowerShell.escapeArgument(app));
610
+ if (options.target) {
611
+ appArguments.push(options.target);
612
+ }
613
+ } else if (options.target) {
614
+ encodedArguments.push(executePowerShell.escapeArgument(options.target));
615
+ }
616
+ if (appArguments.length > 0) {
617
+ appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
618
+ encodedArguments.push("-ArgumentList", appArguments.join(","));
619
+ }
620
+ options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
621
+ if (!options.wait) {
622
+ childProcessOptions.stdio = "ignore";
623
+ }
624
+ } else {
625
+ if (app) {
626
+ command = app;
627
+ } else {
628
+ const isBundled = !__dirname || __dirname === "/";
629
+ let exeLocalXdgOpen = false;
630
+ try {
631
+ await import_promises21.default.access(localXdgOpenPath, import_promises21.constants.X_OK);
632
+ exeLocalXdgOpen = true;
633
+ } catch {
634
+ }
635
+ const useSystemXdgOpen = import_node_process7.default.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
636
+ command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
637
+ }
638
+ if (appArguments.length > 0) {
639
+ cliArguments.push(...appArguments);
640
+ }
641
+ if (!options.wait) {
642
+ childProcessOptions.stdio = "ignore";
643
+ childProcessOptions.detached = true;
644
+ }
645
+ }
646
+ if (platform === "darwin" && appArguments.length > 0) {
647
+ cliArguments.push("--args", ...appArguments);
648
+ }
649
+ if (options.target) {
650
+ cliArguments.push(options.target);
651
+ }
652
+ const subprocess = import_node_child_process22.default.spawn(command, cliArguments, childProcessOptions);
653
+ if (options.wait) {
654
+ return new Promise((resolve2, reject) => {
655
+ subprocess.once("error", reject);
656
+ subprocess.once("close", (exitCode) => {
657
+ if (!options.allowNonzeroExitCode && exitCode !== 0) {
658
+ reject(new Error(`Exited with code ${exitCode}`));
659
+ return;
660
+ }
661
+ resolve2(subprocess);
662
+ });
663
+ });
664
+ }
665
+ if (isFallbackAttempt) {
666
+ return new Promise((resolve2, reject) => {
667
+ subprocess.once("error", reject);
668
+ subprocess.once("spawn", () => {
669
+ subprocess.once("close", (exitCode) => {
670
+ subprocess.off("error", reject);
671
+ if (exitCode !== 0) {
672
+ reject(new Error(`Exited with code ${exitCode}`));
673
+ return;
674
+ }
675
+ subprocess.unref();
676
+ resolve2(subprocess);
677
+ });
678
+ });
679
+ });
680
+ }
681
+ subprocess.unref();
682
+ return new Promise((resolve2, reject) => {
683
+ subprocess.once("error", reject);
684
+ subprocess.once("spawn", () => {
685
+ subprocess.off("error", reject);
686
+ resolve2(subprocess);
687
+ });
688
+ });
689
+ };
690
+ open = (target, options) => {
691
+ if (typeof target !== "string") {
692
+ throw new TypeError("Expected a `target`");
693
+ }
694
+ return baseOpen({
695
+ ...options,
696
+ target
697
+ });
698
+ };
699
+ openApp = (name, options) => {
700
+ if (typeof name !== "string" && !Array.isArray(name)) {
701
+ throw new TypeError("Expected a valid `name`");
702
+ }
703
+ const { arguments: appArguments = [] } = options ?? {};
704
+ if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) {
705
+ throw new TypeError("Expected `appArguments` as Array type");
706
+ }
707
+ return baseOpen({
708
+ ...options,
709
+ app: {
710
+ name,
711
+ arguments: appArguments
712
+ }
713
+ });
714
+ };
715
+ apps = {
716
+ browser: "browser",
717
+ browserPrivate: "browserPrivate"
718
+ };
719
+ defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
720
+ darwin: "google chrome",
721
+ win32: "chrome",
722
+ // `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap.
723
+ linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
724
+ }, {
725
+ wsl: {
726
+ ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
727
+ x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
728
+ }
729
+ }));
730
+ defineLazyProperty(apps, "brave", () => detectPlatformBinary({
731
+ darwin: "brave browser",
732
+ win32: "brave",
733
+ linux: ["brave-browser", "brave"]
734
+ }, {
735
+ wsl: {
736
+ ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
737
+ x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
738
+ }
739
+ }));
740
+ defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
741
+ darwin: "firefox",
742
+ win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
743
+ linux: "firefox"
744
+ }, {
745
+ wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
746
+ }));
747
+ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
748
+ darwin: "microsoft edge",
749
+ win32: "msedge",
750
+ linux: ["microsoft-edge", "microsoft-edge-dev"]
751
+ }, {
752
+ wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
753
+ }));
754
+ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
755
+ darwin: "Safari"
756
+ }));
757
+ open_default = open;
758
+ }
759
+ });
760
+
31
761
  // src/cli/index.ts
32
762
  var cli_exports = {};
33
763
  __export(cli_exports, {
@@ -41,7 +771,7 @@ var import_commander = require("commander");
41
771
 
42
772
  // src/package-info.ts
43
773
  var AISNITCH_PACKAGE_NAME = "aisnitch";
44
- var AISNITCH_VERSION = "0.2.20";
774
+ var AISNITCH_VERSION = "0.2.22";
45
775
  var AISNITCH_DESCRIPTION = "Universal bridge for AI coding tool activity \u2014 capture, normalize, stream.";
46
776
 
47
777
  // src/core/events/schema.ts
@@ -82,6 +812,8 @@ var TOOL_NAMES = [
82
812
  "kiro",
83
813
  "augment-code",
84
814
  "mistral",
815
+ "zed",
816
+ "pi",
85
817
  "unknown"
86
818
  ];
87
819
  var ERROR_TYPES = [
@@ -129,6 +861,11 @@ var ToolInputSchema = import_zod.z.strictObject({
129
861
  (value) => value.filePath !== void 0 || value.command !== void 0,
130
862
  "toolInput must include filePath or command"
131
863
  );
864
+ var ThinkingContentSchema = import_zod.z.string().max(1e5).describe("Raw thinking/reasoning content from the AI model");
865
+ var ToolCallNameSchema = import_zod.z.string().min(1).max(100).describe("Name of the tool being invoked (e.g., Edit, Bash, Grep)");
866
+ var FinalMessageSchema = import_zod.z.string().max(5e4).describe("End-of-run summary or completion message");
867
+ var ToolResultSchema = import_zod.z.string().max(1e4).describe("Tool execution result or output");
868
+ var MessageContentSchema = import_zod.z.string().max(1e5).describe("Raw text content from AI messages");
132
869
  var ToolNameSchema = import_zod.z.enum(TOOL_NAMES);
133
870
  var AISnitchEventTypeSchema = import_zod.z.enum(AISNITCH_EVENT_TYPES);
134
871
  var ErrorTypeSchema = import_zod.z.enum(ERROR_TYPES);
@@ -143,6 +880,9 @@ var EventDataSchema = import_zod.z.strictObject({
143
880
  activeFile: import_zod.z.string().min(1).max(4096).optional(),
144
881
  model: import_zod.z.string().min(1).max(200).optional(),
145
882
  tokensUsed: import_zod.z.number().int().min(0).optional(),
883
+ inputTokens: import_zod.z.number().int().min(0).optional(),
884
+ outputTokens: import_zod.z.number().int().min(0).optional(),
885
+ cachedTokens: import_zod.z.number().int().min(0).optional(),
146
886
  errorMessage: import_zod.z.string().min(1).max(1e4).optional(),
147
887
  errorType: ErrorTypeSchema.optional(),
148
888
  raw: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
@@ -151,7 +891,13 @@ var EventDataSchema = import_zod.z.strictObject({
151
891
  pid: import_zod.z.number().int().positive().optional(),
152
892
  instanceId: import_zod.z.string().min(1).max(255).optional(),
153
893
  instanceIndex: import_zod.z.number().int().min(1).optional(),
154
- instanceTotal: import_zod.z.number().int().min(1).optional()
894
+ instanceTotal: import_zod.z.number().int().min(1).optional(),
895
+ // New fields for enhanced content capture
896
+ thinkingContent: ThinkingContentSchema.optional(),
897
+ toolCallName: ToolCallNameSchema.optional(),
898
+ finalMessage: FinalMessageSchema.optional(),
899
+ toolResult: ToolResultSchema.optional(),
900
+ messageContent: MessageContentSchema.optional()
155
901
  });
156
902
  var AISnitchEventSchema = import_zod.z.strictObject({
157
903
  specversion: import_zod.z.literal("1.0"),
@@ -956,8 +1702,8 @@ var ClaudeCodeSetup = class extends FileToolSetupBase {
956
1702
  return `${JSON.stringify(nextSettings, null, 2)}
957
1703
  `;
958
1704
  }
959
- getFileBackupPath(path) {
960
- return `${path}.bak`;
1705
+ getFileBackupPath(path2) {
1706
+ return `${path2}.bak`;
961
1707
  }
962
1708
  };
963
1709
  var OpenCodeSetup = class extends FileToolSetupBase {
@@ -1197,8 +1943,8 @@ var CopilotCLISetup = class {
1197
1943
  return `${JSON.stringify(nextConfig, null, 2)}
1198
1944
  `;
1199
1945
  }
1200
- getBackupPath(path) {
1201
- return `${path}.bak`;
1946
+ getBackupPath(path2) {
1947
+ return `${path2}.bak`;
1202
1948
  }
1203
1949
  };
1204
1950
  var OpenClawSetup = class {
@@ -1323,8 +2069,8 @@ var OpenClawSetup = class {
1323
2069
  return `${JSON.stringify(nextConfig, null, 2)}
1324
2070
  `;
1325
2071
  }
1326
- getBackupPath(path) {
1327
- return `${path}.bak`;
2072
+ getBackupPath(path2) {
2073
+ return `${path2}.bak`;
1328
2074
  }
1329
2075
  };
1330
2076
  async function createToolSetup(toolName, options = {}, dependencies = {}) {
@@ -2367,17 +3113,17 @@ async function isBinaryAvailable(binaryName) {
2367
3113
  return false;
2368
3114
  }
2369
3115
  }
2370
- async function fileExists(path) {
3116
+ async function fileExists(path2) {
2371
3117
  try {
2372
- await (0, import_promises2.access)(path, import_node_fs.constants.F_OK);
3118
+ await (0, import_promises2.access)(path2, import_node_fs.constants.F_OK);
2373
3119
  return true;
2374
3120
  } catch {
2375
3121
  return false;
2376
3122
  }
2377
3123
  }
2378
- async function readOptionalFile(path) {
3124
+ async function readOptionalFile(path2) {
2379
3125
  try {
2380
- return await (0, import_promises2.readFile)(path, "utf8");
3126
+ return await (0, import_promises2.readFile)(path2, "utf8");
2381
3127
  } catch (error) {
2382
3128
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2383
3129
  return null;
@@ -2388,14 +3134,14 @@ async function readOptionalFile(path) {
2388
3134
  function shellEscapeSingle(value) {
2389
3135
  return `'${value.replaceAll("'", `'"'"'`)}'`;
2390
3136
  }
2391
- async function restoreBackupOrRemove(path) {
2392
- const backupPath = `${path}.bak`;
3137
+ async function restoreBackupOrRemove(path2) {
3138
+ const backupPath = `${path2}.bak`;
2393
3139
  if (await fileExists(backupPath)) {
2394
- await (0, import_promises2.copyFile)(backupPath, path);
3140
+ await (0, import_promises2.copyFile)(backupPath, path2);
2395
3141
  await (0, import_promises2.rm)(backupPath, { force: true });
2396
3142
  return;
2397
3143
  }
2398
- await (0, import_promises2.rm)(path, { force: true });
3144
+ await (0, import_promises2.rm)(path2, { force: true });
2399
3145
  }
2400
3146
  function buildAiderNotificationCommand(options) {
2401
3147
  const cliArgs = [process.execPath, resolveCurrentCliEntryPath(), "aider-notify"];
@@ -2463,13 +3209,13 @@ function toConfigPathOptions(options) {
2463
3209
  }
2464
3210
 
2465
3211
  // src/cli/runtime.ts
2466
- var import_node_child_process15 = require("child_process");
2467
- var import_node_fs4 = require("fs");
2468
- var import_promises18 = require("fs/promises");
3212
+ var import_node_child_process23 = require("child_process");
3213
+ var import_node_fs7 = require("fs");
3214
+ var import_promises22 = require("fs/promises");
2469
3215
  var import_node_net4 = require("net");
2470
- var import_node_os5 = require("os");
2471
- var import_node_path19 = require("path");
2472
- var import_node_util14 = require("util");
3216
+ var import_node_os6 = require("os");
3217
+ var import_node_path22 = require("path");
3218
+ var import_node_util21 = require("util");
2473
3219
 
2474
3220
  // src/adapters/generic-pty.ts
2475
3221
  var import_node_path5 = require("path");
@@ -2540,9 +3286,11 @@ var TOOL_BINARY_MAP = {
2540
3286
  "openhands": "openhands",
2541
3287
  "openclaw": "openclaw",
2542
3288
  "opencode": "opencode",
3289
+ "pi": "pi",
2543
3290
  "qwen-code": "qwen",
2544
3291
  "unknown": "unknown",
2545
- "windsurf": "windsurf"
3292
+ "windsurf": "windsurf",
3293
+ "zed": "zed"
2546
3294
  };
2547
3295
  var ContextDetector = class {
2548
3296
  cache = /* @__PURE__ */ new Map();
@@ -4401,7 +5149,7 @@ var UDSServer = class {
4401
5149
  };
4402
5150
 
4403
5151
  // src/core/engine/pipeline.ts
4404
- var import_node_path16 = require("path");
5152
+ var import_node_path18 = require("path");
4405
5153
  var import_zod4 = require("zod");
4406
5154
 
4407
5155
  // src/adapters/aider.ts
@@ -4508,20 +5256,29 @@ var BaseAdapter = class {
4508
5256
  });
4509
5257
  let published;
4510
5258
  try {
4511
- published = await this.publishEventImplementation(event, {
4512
- cwd: context.cwd,
4513
- env: context.env,
4514
- hookPayload: context.hookPayload,
4515
- pid: context.pid,
4516
- sessionId,
4517
- source: context.source,
4518
- transcriptPath: context.transcriptPath
5259
+ published = await SHARED_BREAKERS.adapterEmit.execute(async () => {
5260
+ return await this.publishEventImplementation(event, {
5261
+ cwd: context.cwd,
5262
+ env: context.env,
5263
+ hookPayload: context.hookPayload,
5264
+ pid: context.pid,
5265
+ sessionId,
5266
+ source: context.source,
5267
+ transcriptPath: context.transcriptPath
5268
+ });
4519
5269
  });
4520
5270
  } catch (error) {
4521
- logger.error(
4522
- { error, eventType: type, adapter: this.name, sessionId },
4523
- "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
4524
- );
5271
+ if (error instanceof Error && error.name === "CircuitOpenError") {
5272
+ logger.warn(
5273
+ { error, eventType: type, adapter: this.name },
5274
+ "\u{1F4D6} Adapter emit blocked by open circuit \u2014 event dropped"
5275
+ );
5276
+ } else {
5277
+ logger.error(
5278
+ { error, eventType: type, adapter: this.name, sessionId },
5279
+ "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
5280
+ );
5281
+ }
4525
5282
  published = false;
4526
5283
  }
4527
5284
  if (published) {
@@ -5535,7 +6292,11 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5535
6292
  return;
5536
6293
  }
5537
6294
  case "SessionEnd": {
5538
- await this.emitStateChange("session.end", sharedData, context);
6295
+ const finalMessage = extractFinalMessageFromPayload(payload);
6296
+ await this.emitStateChange("session.end", {
6297
+ ...sharedData,
6298
+ finalMessage
6299
+ }, context);
5539
6300
  return;
5540
6301
  }
5541
6302
  case "UserPromptSubmit":
@@ -5552,12 +6313,22 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5552
6313
  return;
5553
6314
  }
5554
6315
  case "PreToolUse": {
5555
- await this.emitStateChange("agent.tool_call", sharedData, context);
6316
+ const toolCallName = extractToolNameFromPayload(payload);
6317
+ await this.emitStateChange("agent.tool_call", {
6318
+ ...sharedData,
6319
+ toolCallName
6320
+ }, context);
5556
6321
  return;
5557
6322
  }
5558
6323
  case "PostToolUse": {
6324
+ const toolCallName = extractToolNameFromPayload(payload);
6325
+ const toolResult = extractToolResultFromPayload(payload);
5559
6326
  const emittedType = isClaudeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
5560
- await this.emitStateChange(emittedType, sharedData, context);
6327
+ await this.emitStateChange(emittedType, {
6328
+ ...sharedData,
6329
+ toolCallName,
6330
+ toolResult
6331
+ }, context);
5561
6332
  return;
5562
6333
  }
5563
6334
  case "PostToolUseFailure":
@@ -5742,7 +6513,7 @@ function extractClaudeTranscriptObservations(payload, transcriptPath) {
5742
6513
  });
5743
6514
  const contentParts = extractClaudeContentParts(payload);
5744
6515
  const model = getString(payload, "model") ?? getString(getRecord(payload.message), "model");
5745
- const tokensUsed = extractTokenUsage(payload);
6516
+ const tokens = extractTokenUsageDetailed(payload);
5746
6517
  const rawPayload = payload;
5747
6518
  const sharedContext = {
5748
6519
  // 📖 Pass process.env so terminal detection works from transcript path too
@@ -5755,25 +6526,57 @@ function extractClaudeTranscriptObservations(payload, transcriptPath) {
5755
6526
  const sharedData = {
5756
6527
  model,
5757
6528
  raw: rawPayload,
5758
- tokensUsed
6529
+ tokensUsed: tokens.total,
6530
+ inputTokens: tokens.input,
6531
+ outputTokens: tokens.output,
6532
+ cachedTokens: tokens.cached
5759
6533
  };
5760
6534
  const observations = [];
5761
6535
  if (contentParts.some((part) => part.type === "thinking")) {
6536
+ const thinkingParts = contentParts.filter((part) => part.type === "thinking");
6537
+ const thinkingText = thinkingParts.map((part) => {
6538
+ const text = part.text;
6539
+ return typeof text === "string" ? text : void 0;
6540
+ }).filter((text) => text !== void 0).join("\n");
5762
6541
  observations.push({
5763
6542
  context: sharedContext,
5764
- data: sharedData,
6543
+ data: {
6544
+ ...sharedData,
6545
+ thinkingContent: thinkingText.length > 0 ? thinkingText : void 0
6546
+ },
5765
6547
  type: "agent.thinking"
5766
6548
  });
5767
6549
  }
5768
6550
  if (contentParts.some(
5769
6551
  (part) => part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0
5770
6552
  )) {
6553
+ const messageTexts = contentParts.filter((part) => part.type === "text").map((part) => part.text).filter((text) => text.trim().length > 0);
6554
+ const messageContent = messageTexts.join("\n");
5771
6555
  observations.push({
5772
6556
  context: sharedContext,
5773
- data: sharedData,
6557
+ data: {
6558
+ ...sharedData,
6559
+ messageContent: messageContent.length > 0 ? messageContent : void 0
6560
+ },
5774
6561
  type: "agent.streaming"
5775
6562
  });
5776
6563
  }
6564
+ const toolUseParts = contentParts.filter(
6565
+ (part) => part.type === "tool_use" || part.type === "toolUse"
6566
+ );
6567
+ if (toolUseParts.length > 0) {
6568
+ const toolName = getString(toolUseParts[0], "name") ?? getString(toolUseParts[0], "tool");
6569
+ if (toolName) {
6570
+ observations.push({
6571
+ context: sharedContext,
6572
+ data: {
6573
+ ...sharedData,
6574
+ toolCallName: toolName
6575
+ },
6576
+ type: "agent.tool_call"
6577
+ });
6578
+ }
6579
+ }
5777
6580
  return observations;
5778
6581
  }
5779
6582
  function extractClaudeContentParts(payload) {
@@ -5784,23 +6587,28 @@ function extractClaudeContentParts(payload) {
5784
6587
  }
5785
6588
  return content.filter(isRecord2);
5786
6589
  }
5787
- function extractTokenUsage(payload) {
6590
+ function extractTokenUsageDetailed(payload) {
5788
6591
  const tokens = getNumber(payload, "tokens");
5789
6592
  if (tokens !== void 0) {
5790
- return tokens;
6593
+ return { total: tokens };
5791
6594
  }
5792
6595
  const usage = getRecord(payload.usage);
5793
6596
  if (!usage) {
5794
- return void 0;
6597
+ return {};
5795
6598
  }
5796
6599
  const totalTokens = getNumber(usage, "total_tokens");
5797
6600
  if (totalTokens !== void 0) {
5798
- return totalTokens;
6601
+ return {
6602
+ total: totalTokens,
6603
+ input: getNumber(usage, "input_tokens"),
6604
+ output: getNumber(usage, "output_tokens"),
6605
+ cached: getNumber(usage, "cached_tokens")
6606
+ };
5799
6607
  }
5800
6608
  const inputTokens = getNumber(usage, "input_tokens") ?? 0;
5801
6609
  const outputTokens = getNumber(usage, "output_tokens") ?? 0;
5802
6610
  const usageSum = inputTokens + outputTokens;
5803
- return usageSum > 0 ? usageSum : void 0;
6611
+ return usageSum > 0 ? { total: usageSum, input: inputTokens, output: outputTokens } : {};
5804
6612
  }
5805
6613
  function extractClaudeToolInput(payload) {
5806
6614
  const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);
@@ -5896,6 +6704,51 @@ function getString(payload, key) {
5896
6704
  const value = payload[key];
5897
6705
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
5898
6706
  }
6707
+ function extractToolNameFromPayload(payload) {
6708
+ const directToolName = getString(payload, "tool_name") ?? getString(payload, "toolName");
6709
+ if (directToolName) {
6710
+ return directToolName;
6711
+ }
6712
+ const toolUse = getRecord(payload.tool_use) ?? getRecord(payload.toolUse);
6713
+ if (toolUse) {
6714
+ return getString(toolUse, "name") ?? getString(toolUse, "tool");
6715
+ }
6716
+ const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);
6717
+ if (toolInput) {
6718
+ return getString(toolInput, "tool_name") ?? getString(toolInput, "type");
6719
+ }
6720
+ return void 0;
6721
+ }
6722
+ function extractToolResultFromPayload(payload) {
6723
+ const directResult = getString(payload, "result") ?? getString(payload, "output");
6724
+ if (directResult) {
6725
+ return directResult;
6726
+ }
6727
+ const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);
6728
+ if (toolResult) {
6729
+ return getString(toolResult, "content") ?? getString(toolResult, "output");
6730
+ }
6731
+ const errorField = getString(payload, "error") ?? getString(payload, "error_message");
6732
+ if (errorField) {
6733
+ return errorField;
6734
+ }
6735
+ return void 0;
6736
+ }
6737
+ function extractFinalMessageFromPayload(payload) {
6738
+ const directMessage = getString(payload, "final_message") ?? getString(payload, "finalMessage") ?? getString(payload, "summary") ?? getString(payload, "completion_message");
6739
+ if (directMessage) {
6740
+ return directMessage;
6741
+ }
6742
+ const result = getString(payload, "result") ?? getString(payload, "output") ?? getString(payload, "message");
6743
+ if (result) {
6744
+ return result;
6745
+ }
6746
+ const stats = getRecord(payload.stats);
6747
+ if (stats) {
6748
+ return getString(stats, "summary") ?? getString(stats, "completion_summary");
6749
+ }
6750
+ return void 0;
6751
+ }
5899
6752
 
5900
6753
  // src/adapters/copilot-cli.ts
5901
6754
  var import_node_child_process5 = require("child_process");
@@ -10859,7 +11712,17 @@ var OpenCodeAdapter = class extends BaseAdapter {
10859
11712
  project: extractOpenCodeProject(payload),
10860
11713
  raw: payload,
10861
11714
  toolInput: extractOpenCodeToolInput(payload),
10862
- toolName: extractOpenCodeToolName(payload)
11715
+ toolName: extractOpenCodeToolName(payload),
11716
+ // 📖 Extract token usage from payload (with input/output/cached breakdown)
11717
+ ...(() => {
11718
+ const tokens = extractOpenCodeTokens(payload);
11719
+ return {
11720
+ tokensUsed: tokens.total,
11721
+ inputTokens: tokens.inputTokens,
11722
+ outputTokens: tokens.outputTokens,
11723
+ cachedTokens: tokens.cachedTokens
11724
+ };
11725
+ })()
10863
11726
  };
10864
11727
  switch (eventType) {
10865
11728
  case "session.created": {
@@ -10869,7 +11732,11 @@ var OpenCodeAdapter = class extends BaseAdapter {
10869
11732
  return;
10870
11733
  }
10871
11734
  case "session.deleted": {
10872
- await this.emitStateChange("session.end", sharedData, context);
11735
+ const finalMessage = extractOpenCodeFinalMessage(payload);
11736
+ await this.emitStateChange("session.end", {
11737
+ ...sharedData,
11738
+ finalMessage
11739
+ }, context);
10873
11740
  return;
10874
11741
  }
10875
11742
  case "session.error": {
@@ -10884,9 +11751,21 @@ var OpenCodeAdapter = class extends BaseAdapter {
10884
11751
  await this.emitStateChange("agent.compact", sharedData, context);
10885
11752
  return;
10886
11753
  }
11754
+ case "thinking": {
11755
+ const thinkingContent = extractOpenCodeThinkingContent(payload);
11756
+ await this.emitStateChange("agent.thinking", {
11757
+ ...sharedData,
11758
+ thinkingContent
11759
+ }, context);
11760
+ return;
11761
+ }
10887
11762
  case "message.updated":
10888
11763
  case "message.part.updated": {
10889
- await this.emitStateChange("agent.streaming", sharedData, context);
11764
+ const messageContent = extractOpenCodeMessageContent(payload);
11765
+ await this.emitStateChange("agent.streaming", {
11766
+ ...sharedData,
11767
+ messageContent
11768
+ }, context);
10890
11769
  return;
10891
11770
  }
10892
11771
  case "permission.asked": {
@@ -10894,12 +11773,22 @@ var OpenCodeAdapter = class extends BaseAdapter {
10894
11773
  return;
10895
11774
  }
10896
11775
  case "tool.execute.before": {
10897
- await this.emitStateChange("agent.tool_call", sharedData, context);
11776
+ const toolCallName = extractOpenCodeToolName(payload);
11777
+ await this.emitStateChange("agent.tool_call", {
11778
+ ...sharedData,
11779
+ toolCallName
11780
+ }, context);
10898
11781
  return;
10899
11782
  }
10900
11783
  case "tool.execute.after": {
11784
+ const toolCallName = extractOpenCodeToolName(payload);
11785
+ const toolResult = extractOpenCodeToolResult(payload);
10901
11786
  const emittedType = isOpenCodeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
10902
- await this.emitStateChange(emittedType, sharedData, context);
11787
+ await this.emitStateChange(emittedType, {
11788
+ ...sharedData,
11789
+ toolCallName,
11790
+ toolResult
11791
+ }, context);
10903
11792
  return;
10904
11793
  }
10905
11794
  default: {
@@ -11066,7 +11955,597 @@ function getString10(payload, key) {
11066
11955
  const value = payload[key];
11067
11956
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
11068
11957
  }
11069
-
11958
+ function extractOpenCodeFinalMessage(payload) {
11959
+ const directMessage = getString10(payload, "final_message") ?? getString10(payload, "finalMessage") ?? getString10(payload, "summary") ?? getString10(payload, "completion_message");
11960
+ if (directMessage) {
11961
+ return directMessage;
11962
+ }
11963
+ const result = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(getRecord9(payload.properties), "result");
11964
+ if (result) {
11965
+ return result;
11966
+ }
11967
+ return void 0;
11968
+ }
11969
+ function extractOpenCodeToolResult(payload) {
11970
+ const directResult = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(payload, "toolResult");
11971
+ if (directResult) {
11972
+ return directResult;
11973
+ }
11974
+ const toolResult = getRecord9(payload.tool_result) ?? getRecord9(payload.toolResult);
11975
+ if (toolResult) {
11976
+ return getString10(toolResult, "content") ?? getString10(toolResult, "output");
11977
+ }
11978
+ const props = getRecord9(payload.properties);
11979
+ if (props) {
11980
+ const nestedResult = getRecord9(props.tool_result) ?? getRecord9(props.toolResult);
11981
+ if (nestedResult) {
11982
+ return getString10(nestedResult, "content") ?? getString10(nestedResult, "output");
11983
+ }
11984
+ }
11985
+ return void 0;
11986
+ }
11987
+ function extractOpenCodeMessageContent(payload) {
11988
+ const directMessage = getString10(payload, "text") ?? getString10(payload, "message") ?? getString10(payload, "content") ?? getString10(payload, "output");
11989
+ if (directMessage) {
11990
+ return directMessage;
11991
+ }
11992
+ const part = getRecord9(payload.part) ?? getRecord9(getRecord9(payload.properties)?.part);
11993
+ if (part) {
11994
+ return getString10(part, "text") ?? getString10(part, "content");
11995
+ }
11996
+ const props = getRecord9(payload.properties);
11997
+ if (props) {
11998
+ const message = getRecord9(props.message) ?? getRecord9(props.info);
11999
+ if (message) {
12000
+ return getString10(message, "text") ?? getString10(message, "content");
12001
+ }
12002
+ return getString10(props, "text") ?? getString10(props, "message");
12003
+ }
12004
+ return void 0;
12005
+ }
12006
+ function extractOpenCodeThinkingContent(payload) {
12007
+ const directThinking = getString10(payload, "thinking") ?? getString10(payload, "thinkingContent") ?? getString10(payload, "reasoning") ?? getString10(payload, "thought");
12008
+ if (directThinking) {
12009
+ return directThinking;
12010
+ }
12011
+ const props = getRecord9(payload.properties);
12012
+ if (props) {
12013
+ return getString10(props, "thinking") ?? getString10(props, "reasoning") ?? getString10(props, "thought");
12014
+ }
12015
+ return void 0;
12016
+ }
12017
+ function extractOpenCodeTokens(payload) {
12018
+ const directTokens = getNumber8(payload, "tokensUsed") ?? getNumber8(payload, "tokens");
12019
+ if (directTokens !== void 0) {
12020
+ return { total: directTokens };
12021
+ }
12022
+ const props = getRecord9(payload.properties);
12023
+ if (props) {
12024
+ const info = getRecord9(props.info);
12025
+ if (info) {
12026
+ const tokens = getRecord9(info.tokens);
12027
+ if (tokens) {
12028
+ const inputTokens = getNumber8(tokens, "input") ?? 0;
12029
+ const outputTokens = getNumber8(tokens, "output") ?? 0;
12030
+ const reasoningTokens = getNumber8(tokens, "reasoning") ?? 0;
12031
+ const total = inputTokens + outputTokens + reasoningTokens;
12032
+ return total > 0 ? {
12033
+ total,
12034
+ inputTokens,
12035
+ outputTokens,
12036
+ // reasoning tokens are often billed as cached on some providers
12037
+ cachedTokens: reasoningTokens
12038
+ } : {};
12039
+ }
12040
+ }
12041
+ const fallbackTokens = getNumber8(props, "tokensUsed") ?? getNumber8(props, "tokens");
12042
+ if (fallbackTokens !== void 0) {
12043
+ return { total: fallbackTokens };
12044
+ }
12045
+ }
12046
+ return {};
12047
+ }
12048
+
12049
+ // src/adapters/pi.ts
12050
+ var import_node_child_process14 = require("child_process");
12051
+ var import_node_path16 = require("path");
12052
+ var import_node_util14 = require("util");
12053
+ var execFileAsync = (0, import_node_util14.promisify)(import_node_child_process14.execFile);
12054
+ var PiAdapter = class extends BaseAdapter {
12055
+ displayName = "Pi (MiniMax)";
12056
+ name = "pi";
12057
+ strategies = [
12058
+ "process-detect",
12059
+ "api-client",
12060
+ "log-watch"
12061
+ ];
12062
+ apiPort = 7890;
12063
+ logPath;
12064
+ poller = null;
12065
+ activePiSessions = /* @__PURE__ */ new Map();
12066
+ lastCheckedTime = 0;
12067
+ constructor(options) {
12068
+ super(options);
12069
+ this.logPath = (0, import_node_path16.join)(
12070
+ options.homeDirectory ?? process.env.HOME ?? "",
12071
+ ".pi",
12072
+ "agent.log"
12073
+ );
12074
+ }
12075
+ start() {
12076
+ if (this.getStatus().running) {
12077
+ return Promise.resolve();
12078
+ }
12079
+ this.setRunning(true);
12080
+ this.startPolling();
12081
+ logger.info({ adapter: this.name }, "Pi adapter started");
12082
+ return Promise.resolve();
12083
+ }
12084
+ stop() {
12085
+ if (this.poller !== null) {
12086
+ clearInterval(this.poller);
12087
+ this.poller = null;
12088
+ }
12089
+ this.setRunning(false);
12090
+ logger.info({ adapter: this.name }, "Pi adapter stopped");
12091
+ return Promise.resolve();
12092
+ }
12093
+ async handleHook(payload) {
12094
+ const normalized = this.parseNormalizedHookPayload(payload);
12095
+ if (normalized === null) {
12096
+ return;
12097
+ }
12098
+ const context = {
12099
+ cwd: normalized.cwd,
12100
+ pid: normalized.pid,
12101
+ sessionId: normalized.sessionId,
12102
+ source: "pi-hook"
12103
+ };
12104
+ const eventType = this.mapEventType(normalized.type ?? "");
12105
+ const eventData = this.buildEventData(eventType, normalized);
12106
+ await this.emit(eventType, eventData, context);
12107
+ }
12108
+ startPolling() {
12109
+ this.poller = setInterval(() => {
12110
+ void this.pollPiActivity();
12111
+ }, 2e3);
12112
+ }
12113
+ async pollPiActivity() {
12114
+ const running = await this.detectPiInstance();
12115
+ if (!running) {
12116
+ for (const [sessionId, activity] of this.activePiSessions) {
12117
+ if (activity.state !== "idle") {
12118
+ activity.state = "idle";
12119
+ await this.emitIdle(sessionId);
12120
+ }
12121
+ }
12122
+ return;
12123
+ }
12124
+ try {
12125
+ const response = await fetch(
12126
+ `http://127.0.0.1:${this.apiPort}/api/status`,
12127
+ {
12128
+ signal: AbortSignal.timeout(500)
12129
+ }
12130
+ );
12131
+ if (response.ok) {
12132
+ const data = await response.json();
12133
+ await this.processPiApiResponse(data);
12134
+ }
12135
+ } catch {
12136
+ await this.checkMiniMaxApi();
12137
+ }
12138
+ }
12139
+ async detectPiInstance() {
12140
+ try {
12141
+ const result = await execFileAsync("pgrep", ["-l", "pi|minimax"]);
12142
+ if (result.stdout.includes("pi") || result.stdout.includes("minimax")) {
12143
+ return true;
12144
+ }
12145
+ } catch {
12146
+ }
12147
+ try {
12148
+ const response = await fetch(
12149
+ `http://127.0.0.1:${this.apiPort}/health`,
12150
+ {
12151
+ signal: AbortSignal.timeout(200)
12152
+ }
12153
+ );
12154
+ if (response.ok) {
12155
+ return true;
12156
+ }
12157
+ } catch {
12158
+ }
12159
+ return false;
12160
+ }
12161
+ async checkMiniMaxApi() {
12162
+ try {
12163
+ const response = await fetch("http://127.0.0.1:3000/api/agent/status", {
12164
+ signal: AbortSignal.timeout(500)
12165
+ });
12166
+ if (response.ok) {
12167
+ const data = await response.json();
12168
+ await this.processPiApiResponse(data);
12169
+ }
12170
+ } catch {
12171
+ }
12172
+ }
12173
+ async processPiApiResponse(data) {
12174
+ const rawSession = data.sessionId ?? data.project ?? "default";
12175
+ const sessionId = `pi:${rawSession.replace(/[^a-zA-Z0-9-_]/g, "-")}`;
12176
+ let activity = this.activePiSessions.get(sessionId);
12177
+ if (!activity) {
12178
+ activity = { sessionId, state: "idle" };
12179
+ this.activePiSessions.set(sessionId, activity);
12180
+ await this.emitSessionStart(sessionId, data);
12181
+ }
12182
+ const rawState = data.state ?? "idle";
12183
+ const state = rawState;
12184
+ if (state !== activity.state) {
12185
+ switch (state) {
12186
+ case "thinking": {
12187
+ const rawThinking = data.thinking;
12188
+ if (rawThinking) {
12189
+ await this.emitThinking(sessionId, rawThinking);
12190
+ }
12191
+ break;
12192
+ }
12193
+ case "tool": {
12194
+ const rawFilePath = data.filePath;
12195
+ const rawCommand = data.command;
12196
+ const rawToolName = data.toolName ?? "unknown";
12197
+ await this.emitToolCall(
12198
+ sessionId,
12199
+ {
12200
+ filePath: rawFilePath ?? "",
12201
+ command: rawCommand ?? ""
12202
+ },
12203
+ rawToolName
12204
+ );
12205
+ break;
12206
+ }
12207
+ case "output": {
12208
+ const rawOutput = data.output;
12209
+ if (rawOutput) {
12210
+ await this.emitOutput(sessionId, rawOutput);
12211
+ }
12212
+ break;
12213
+ }
12214
+ case "error": {
12215
+ const rawError = data.error ?? "Unknown error";
12216
+ await this.emitError(sessionId, rawError);
12217
+ break;
12218
+ }
12219
+ case "idle":
12220
+ await this.emitIdle(sessionId);
12221
+ break;
12222
+ }
12223
+ activity.state = state;
12224
+ }
12225
+ }
12226
+ async emitSessionStart(sessionId, data) {
12227
+ const rawProject = data.project ?? "pi-project";
12228
+ const rawModel = data.model ?? "minimax/moonshot";
12229
+ const eventData = {
12230
+ state: "session.start",
12231
+ project: rawProject,
12232
+ model: rawModel,
12233
+ raw: data
12234
+ };
12235
+ await this.emit("session.start", eventData, { sessionId });
12236
+ }
12237
+ async emitThinking(sessionId, content) {
12238
+ if (!content) return;
12239
+ const eventData = {
12240
+ state: "agent.thinking",
12241
+ thinkingContent: content
12242
+ };
12243
+ await this.emit("agent.thinking", eventData, { sessionId });
12244
+ }
12245
+ async emitToolCall(sessionId, toolInput, toolName) {
12246
+ const eventData = {
12247
+ state: "agent.tool_call",
12248
+ toolCallName: toolName,
12249
+ toolInput,
12250
+ activeFile: toolInput.filePath
12251
+ };
12252
+ await this.emit("agent.tool_call", eventData, { sessionId });
12253
+ }
12254
+ async emitOutput(sessionId, content) {
12255
+ if (!content) return;
12256
+ const eventData = {
12257
+ state: "agent.streaming",
12258
+ messageContent: content
12259
+ };
12260
+ await this.emit("agent.streaming", eventData, { sessionId });
12261
+ }
12262
+ async emitError(sessionId, errorMessage) {
12263
+ const eventData = {
12264
+ state: "agent.error",
12265
+ errorMessage,
12266
+ errorType: "api_error"
12267
+ };
12268
+ await this.emit("agent.error", eventData, { sessionId });
12269
+ }
12270
+ async emitIdle(sessionId) {
12271
+ const eventData = {
12272
+ state: "agent.idle"
12273
+ };
12274
+ await this.emit("agent.idle", eventData, { sessionId });
12275
+ }
12276
+ mapEventType(type) {
12277
+ const mapping = {
12278
+ "session.start": "session.start",
12279
+ "session.end": "session.end",
12280
+ "task.start": "task.start",
12281
+ "task.complete": "task.complete",
12282
+ thinking: "agent.thinking",
12283
+ tool: "agent.tool_call",
12284
+ coding: "agent.coding",
12285
+ output: "agent.streaming",
12286
+ message: "agent.streaming",
12287
+ ask: "agent.asking_user",
12288
+ error: "agent.error",
12289
+ idle: "agent.idle",
12290
+ compact: "agent.compact"
12291
+ };
12292
+ return mapping[type] ?? "agent.streaming";
12293
+ }
12294
+ buildEventData(eventType, payload) {
12295
+ const data = payload.data ?? {};
12296
+ return {
12297
+ state: eventType,
12298
+ project: data.project,
12299
+ activeFile: data.activeFile,
12300
+ model: data.model,
12301
+ toolInput: data.toolInput,
12302
+ toolCallName: data.toolCallName,
12303
+ thinkingContent: data.thinkingContent,
12304
+ messageContent: data.messageContent,
12305
+ finalMessage: data.finalMessage,
12306
+ toolResult: data.toolResult,
12307
+ errorMessage: data.errorMessage,
12308
+ errorType: data.errorType,
12309
+ raw: data.raw
12310
+ };
12311
+ }
12312
+ };
12313
+
12314
+ // src/adapters/zed.ts
12315
+ var import_promises15 = require("fs/promises");
12316
+ var import_node_path17 = require("path");
12317
+ var ZedAdapter = class extends BaseAdapter {
12318
+ displayName = "Zed AI";
12319
+ name = "zed";
12320
+ strategies = [
12321
+ "process-detect",
12322
+ "api-client"
12323
+ ];
12324
+ logPaths;
12325
+ apiPort = 9876;
12326
+ pollIntervalMs;
12327
+ poller = null;
12328
+ lastEventTime = 0;
12329
+ activeZedSessions = /* @__PURE__ */ new Map();
12330
+ constructor(options) {
12331
+ super(options);
12332
+ this.pollIntervalMs = 2e3;
12333
+ this.logPaths = [
12334
+ (0, import_node_path17.join)(options.homeDirectory ?? process.env.HOME ?? "", ".config", "zed", "logs", "agent.log"),
12335
+ "/tmp/zed-agent.log"
12336
+ ];
12337
+ }
12338
+ start() {
12339
+ if (this.getStatus().running) {
12340
+ return Promise.resolve();
12341
+ }
12342
+ this.setRunning(true);
12343
+ this.startPolling();
12344
+ logger.info({ adapter: this.name }, "Zed adapter started");
12345
+ return Promise.resolve();
12346
+ }
12347
+ stop() {
12348
+ if (this.poller !== null) {
12349
+ clearInterval(this.poller);
12350
+ this.poller = null;
12351
+ }
12352
+ this.setRunning(false);
12353
+ logger.info({ adapter: this.name }, "Zed adapter stopped");
12354
+ return Promise.resolve();
12355
+ }
12356
+ async handleHook(payload) {
12357
+ const normalized = this.parseNormalizedHookPayload(payload);
12358
+ if (normalized === null) {
12359
+ return;
12360
+ }
12361
+ const context = {
12362
+ cwd: normalized.cwd,
12363
+ pid: normalized.pid,
12364
+ sessionId: normalized.sessionId,
12365
+ source: "zed-hook"
12366
+ };
12367
+ const eventType = this.mapEventType(normalized.type ?? "");
12368
+ const eventData = this.buildEventData(eventType, normalized);
12369
+ await this.emit(eventType, eventData, context);
12370
+ }
12371
+ startPolling() {
12372
+ this.poller = setInterval(() => {
12373
+ void this.pollZedStatus();
12374
+ }, this.pollIntervalMs);
12375
+ }
12376
+ async pollZedStatus() {
12377
+ try {
12378
+ const response = await fetch(`http://127.0.0.1:${this.apiPort}/api/agent/status`, {
12379
+ signal: AbortSignal.timeout(1e3)
12380
+ });
12381
+ if (response.ok) {
12382
+ const data = await response.json();
12383
+ if (data.sessionId && typeof data.sessionId === "string") {
12384
+ const sessionId = `zed:${data.sessionId}`;
12385
+ if (!this.activeZedSessions.has(sessionId)) {
12386
+ this.activeZedSessions.set(sessionId, sessionId);
12387
+ await this.emitSessionStart(sessionId, data);
12388
+ }
12389
+ if (data.state === "thinking" && this.lastEventTime < Date.now() - 5e3) {
12390
+ const rawThinking = data.thinking;
12391
+ if (rawThinking) {
12392
+ await this.emitThinking(sessionId, rawThinking);
12393
+ }
12394
+ } else if (data.state === "tool" && data.toolName) {
12395
+ const rawFilePath = data.filePath;
12396
+ const rawCommand = data.command;
12397
+ const rawToolName = data.toolName ?? "unknown";
12398
+ await this.emitToolCall(
12399
+ sessionId,
12400
+ {
12401
+ filePath: rawFilePath ?? "",
12402
+ command: rawCommand ?? ""
12403
+ },
12404
+ rawToolName
12405
+ );
12406
+ } else if (data.state === "idle") {
12407
+ await this.emitIdle(sessionId);
12408
+ }
12409
+ }
12410
+ }
12411
+ } catch {
12412
+ await this.checkLogFiles();
12413
+ }
12414
+ }
12415
+ async checkLogFiles() {
12416
+ for (const logPath of this.logPaths) {
12417
+ try {
12418
+ const content = await (0, import_promises15.readFile)(logPath, "utf8");
12419
+ await this.parseLogContent(content);
12420
+ } catch {
12421
+ }
12422
+ }
12423
+ }
12424
+ async parseLogContent(content) {
12425
+ const lines = content.split("\n").filter((line) => line.trim());
12426
+ for (const line of lines) {
12427
+ if (this.lastEventTime > 0 && this.lastEventTime >= Date.now() - 2e3) {
12428
+ continue;
12429
+ }
12430
+ const event = this.extractZedEventFromLog(line);
12431
+ if (event) {
12432
+ await this.handleHook(event);
12433
+ this.lastEventTime = Date.now();
12434
+ }
12435
+ }
12436
+ }
12437
+ extractZedEventFromLog(line) {
12438
+ try {
12439
+ const parsed = JSON.parse(line);
12440
+ if (!parsed.type || typeof parsed.type !== "string") {
12441
+ return null;
12442
+ }
12443
+ const rawSessionId = parsed.sessionId;
12444
+ const rawWorkspace = parsed.workspace;
12445
+ const sessionId = rawSessionId ? rawSessionId : rawWorkspace ? `zed:${(0, import_node_path17.basename)(rawWorkspace)}` : `zed:${Date.now()}`;
12446
+ const rawCwd = parsed.cwd ?? rawWorkspace;
12447
+ return {
12448
+ type: parsed.type,
12449
+ sessionId,
12450
+ cwd: rawCwd,
12451
+ data: {
12452
+ project: parsed.project ?? rawWorkspace ? (0, import_node_path17.basename)(String(rawWorkspace)) : void 0,
12453
+ model: parsed.model,
12454
+ state: parsed.type,
12455
+ thinkingContent: parsed.thinking,
12456
+ toolCallName: parsed.toolName,
12457
+ toolInput: parsed.toolInput,
12458
+ messageContent: parsed.message ?? parsed.output,
12459
+ errorMessage: parsed.error,
12460
+ raw: parsed
12461
+ }
12462
+ };
12463
+ } catch {
12464
+ if (line.includes("[zed:agent]")) {
12465
+ const cleaned = line.replace(/^\[.*?\] \[.*?\] /, "");
12466
+ if (cleaned.includes("Thinking:")) {
12467
+ return { type: "thinking", thinkingContent: cleaned.replace("Thinking:", "").trim() };
12468
+ }
12469
+ if (cleaned.includes("Executing tool:")) {
12470
+ return { type: "tool", toolCallName: cleaned.replace("Executing tool:", "").trim() };
12471
+ }
12472
+ if (cleaned.includes("Error:")) {
12473
+ return { type: "error", errorMessage: cleaned.replace("Error:", "").trim() };
12474
+ }
12475
+ }
12476
+ return null;
12477
+ }
12478
+ }
12479
+ async emitSessionStart(sessionId, _data) {
12480
+ const eventData = {
12481
+ state: "session.start",
12482
+ project: sessionId.split(":")[1] ?? "unknown"
12483
+ };
12484
+ await this.emit("session.start", eventData, { sessionId });
12485
+ }
12486
+ async emitThinking(sessionId, content) {
12487
+ if (!content) return;
12488
+ const eventData = {
12489
+ state: "agent.thinking",
12490
+ thinkingContent: content
12491
+ };
12492
+ await this.emit("agent.thinking", eventData, { sessionId });
12493
+ this.lastEventTime = Date.now();
12494
+ }
12495
+ async emitToolCall(sessionId, toolInput, toolName) {
12496
+ const eventData = {
12497
+ state: "agent.tool_call",
12498
+ toolCallName: toolName,
12499
+ toolInput,
12500
+ activeFile: toolInput.filePath
12501
+ };
12502
+ await this.emit("agent.tool_call", eventData, { sessionId });
12503
+ this.lastEventTime = Date.now();
12504
+ }
12505
+ async emitIdle(sessionId) {
12506
+ const eventData = {
12507
+ state: "agent.idle"
12508
+ };
12509
+ await this.emit("agent.idle", eventData, { sessionId });
12510
+ }
12511
+ mapEventType(type) {
12512
+ const mapping = {
12513
+ "session.start": "session.start",
12514
+ "session.end": "session.end",
12515
+ "task.start": "task.start",
12516
+ "task.complete": "task.complete",
12517
+ thinking: "agent.thinking",
12518
+ tool: "agent.tool_call",
12519
+ coding: "agent.coding",
12520
+ output: "agent.streaming",
12521
+ message: "agent.streaming",
12522
+ ask: "agent.asking_user",
12523
+ error: "agent.error",
12524
+ idle: "agent.idle",
12525
+ compact: "agent.compact"
12526
+ };
12527
+ return mapping[type] ?? "agent.streaming";
12528
+ }
12529
+ buildEventData(eventType, payload) {
12530
+ const data = payload.data ?? {};
12531
+ return {
12532
+ state: eventType,
12533
+ project: data.project,
12534
+ activeFile: data.activeFile,
12535
+ model: data.model,
12536
+ toolInput: data.toolInput,
12537
+ toolCallName: data.toolCallName,
12538
+ thinkingContent: data.thinkingContent,
12539
+ messageContent: data.messageContent,
12540
+ finalMessage: data.finalMessage,
12541
+ toolResult: data.toolResult,
12542
+ errorMessage: data.errorMessage,
12543
+ errorType: data.errorType,
12544
+ raw: data.raw
12545
+ };
12546
+ }
12547
+ };
12548
+
11070
12549
  // src/adapters/registry.ts
11071
12550
  var AdapterRegistry = class {
11072
12551
  adapters = /* @__PURE__ */ new Map();
@@ -11150,7 +12629,9 @@ function createDefaultAdapters(options) {
11150
12629
  new KiloAdapter(options),
11151
12630
  new CodexAdapter(options),
11152
12631
  new OpenClawAdapter(options),
11153
- new OpenCodeAdapter(options)
12632
+ new OpenCodeAdapter(options),
12633
+ new PiAdapter(options),
12634
+ new ZedAdapter(options)
11154
12635
  ];
11155
12636
  }
11156
12637
 
@@ -11171,7 +12652,7 @@ function getSocketPath(aisnitchHomePath) {
11171
12652
  if (process.platform === "win32") {
11172
12653
  return "\\\\.\\pipe\\aisnitch.sock";
11173
12654
  }
11174
- return (0, import_node_path16.join)(aisnitchHomePath, "aisnitch.sock");
12655
+ return (0, import_node_path18.join)(aisnitchHomePath, "aisnitch.sock");
11175
12656
  }
11176
12657
  var Pipeline = class {
11177
12658
  eventBus = new EventBus();
@@ -11376,6 +12857,30 @@ var Pipeline = class {
11376
12857
  getEventBus() {
11377
12858
  return this.eventBus;
11378
12859
  }
12860
+ /**
12861
+ * Returns the adapter registry for graceful shutdown coordination.
12862
+ */
12863
+ getAdapterRegistry() {
12864
+ return this.adapterRegistry ?? void 0;
12865
+ }
12866
+ /**
12867
+ * Returns the HTTP receiver for graceful shutdown coordination.
12868
+ */
12869
+ getHttpReceiver() {
12870
+ return this.httpReceiver;
12871
+ }
12872
+ /**
12873
+ * Returns the UDS server for graceful shutdown coordination.
12874
+ */
12875
+ getUdsServer() {
12876
+ return this.udsServer;
12877
+ }
12878
+ /**
12879
+ * Returns the WebSocket server for graceful shutdown coordination.
12880
+ */
12881
+ getWsServer() {
12882
+ return this.wsServer;
12883
+ }
11379
12884
  getHealthSnapshot() {
11380
12885
  const status = this.getStatus();
11381
12886
  return {
@@ -11500,6 +13005,72 @@ var DEFAULT_TIMEOUTS = Object.freeze({
11500
13005
  pipelineStartup: 15e3
11501
13006
  });
11502
13007
 
13008
+ // src/core/graceful-shutdown.ts
13009
+ async function withShutdownTimeout(fn, timeoutMs, component) {
13010
+ if (timeoutMs <= 0) {
13011
+ await fn();
13012
+ return;
13013
+ }
13014
+ const timeoutPromise = new Promise((resolve2) => {
13015
+ setTimeout(() => {
13016
+ resolve2("timed_out");
13017
+ }, timeoutMs).unref();
13018
+ });
13019
+ const result = await Promise.race([
13020
+ fn().then(() => "completed"),
13021
+ timeoutPromise
13022
+ ]);
13023
+ if (result === "timed_out") {
13024
+ logger.warn(
13025
+ { component, timeoutMs },
13026
+ `Graceful shutdown exceeded ${timeoutMs}ms timeout \u2014 forcing through`
13027
+ );
13028
+ }
13029
+ }
13030
+ async function shutdownInOrder(components, timeouts, label) {
13031
+ const getTimeout = (key) => {
13032
+ return timeouts[key] ?? DEFAULT_TIMEOUTS.daemonShutdown;
13033
+ };
13034
+ const stopSafely = async (key, fn) => {
13035
+ const timeoutMs = getTimeout(key);
13036
+ try {
13037
+ await withShutdownTimeout(fn, timeoutMs, `${label}.${key}`);
13038
+ } catch (error) {
13039
+ logger.warn(
13040
+ { error, key, label },
13041
+ `Error during shutdown of ${key} \u2014 continuing with remaining components`
13042
+ );
13043
+ }
13044
+ };
13045
+ if (components.cleanupFns) {
13046
+ for (const cleanupFn of components.cleanupFns) {
13047
+ try {
13048
+ await withShutdownTimeout(
13049
+ async () => {
13050
+ const result = cleanupFn();
13051
+ if (result instanceof Promise) {
13052
+ await result;
13053
+ }
13054
+ },
13055
+ 1e3,
13056
+ `${label}.cleanup`
13057
+ );
13058
+ } catch (error) {
13059
+ logger.warn({ error, label }, "Cleanup function failed");
13060
+ }
13061
+ }
13062
+ }
13063
+ if (components.eventBus) {
13064
+ components.eventBus.unsubscribeAll();
13065
+ }
13066
+ await stopSafely("wsServer", () => components.wsServer.stop());
13067
+ await stopSafely("udsServer", () => components.udsServer.stop());
13068
+ await stopSafely("httpReceiver", () => components.httpReceiver.stop());
13069
+ if (components.adapterRegistry) {
13070
+ await stopSafely("adapterRegistry", () => components.adapterRegistry.stopAll());
13071
+ }
13072
+ }
13073
+
11503
13074
  // src/tui/index.tsx
11504
13075
  var import_ink13 = require("ink");
11505
13076
  var import_fullscreen_ink = require("fullscreen-ink");
@@ -11703,9 +13274,11 @@ var TOOL_COLORS = {
11703
13274
  "openhands": "#facc15",
11704
13275
  "openclaw": "#ef4444",
11705
13276
  "opencode": "#10b981",
13277
+ "pi": "#1db954",
11706
13278
  "qwen-code": "#22c55e",
11707
13279
  "unknown": "#94a3b8",
11708
- "windsurf": "#a855f7"
13280
+ "windsurf": "#a855f7",
13281
+ "zed": "#e85d04"
11709
13282
  };
11710
13283
  var EVENT_COLORS = {
11711
13284
  "agent.asking_user": "#ef4444",
@@ -13459,10 +15032,10 @@ async function renderManagedTui(options) {
13459
15032
 
13460
15033
  // src/cli/pid.ts
13461
15034
  var import_node_fs3 = require("fs");
13462
- var import_promises15 = require("fs/promises");
15035
+ var import_promises16 = require("fs/promises");
13463
15036
  var import_node_net3 = require("net");
13464
15037
  var import_node_os4 = require("os");
13465
- var import_node_path17 = require("path");
15038
+ var import_node_path19 = require("path");
13466
15039
  var import_zod5 = require("zod");
13467
15040
  var DaemonStateSchema = import_zod5.z.strictObject({
13468
15041
  pid: import_zod5.z.number().int().positive(),
@@ -13477,14 +15050,14 @@ function getDefaultSocketPath(options) {
13477
15050
  if (process.platform === "win32") {
13478
15051
  return "\\\\.\\pipe\\aisnitch.sock";
13479
15052
  }
13480
- return (0, import_node_path17.join)(getAISnitchHomePath(options), "aisnitch.sock");
15053
+ return (0, import_node_path19.join)(getAISnitchHomePath(options), "aisnitch.sock");
13481
15054
  }
13482
15055
  async function cleanupSocketPathIfStale(socketPath) {
13483
15056
  if (process.platform === "win32") {
13484
15057
  return false;
13485
15058
  }
13486
15059
  try {
13487
- await (0, import_promises15.access)(socketPath, import_node_fs3.constants.F_OK);
15060
+ await (0, import_promises16.access)(socketPath, import_node_fs3.constants.F_OK);
13488
15061
  } catch (error) {
13489
15062
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
13490
15063
  return false;
@@ -13508,20 +15081,20 @@ async function cleanupSocketPathIfStale(socketPath) {
13508
15081
  if (!staleSocket) {
13509
15082
  return false;
13510
15083
  }
13511
- await (0, import_promises15.rm)(socketPath, { force: true });
15084
+ await (0, import_promises16.rm)(socketPath, { force: true });
13512
15085
  return true;
13513
15086
  }
13514
15087
  function getPidFilePath(options = {}) {
13515
- return (0, import_node_path17.join)(getAISnitchHomePath(options), "aisnitch.pid");
15088
+ return (0, import_node_path19.join)(getAISnitchHomePath(options), "aisnitch.pid");
13516
15089
  }
13517
15090
  function getDaemonStatePath(options = {}) {
13518
- return (0, import_node_path17.join)(getAISnitchHomePath(options), "daemon-state.json");
15091
+ return (0, import_node_path19.join)(getAISnitchHomePath(options), "daemon-state.json");
13519
15092
  }
13520
15093
  function getDaemonLogPath(options = {}) {
13521
- return (0, import_node_path17.join)(getAISnitchHomePath(options), "daemon.log");
15094
+ return (0, import_node_path19.join)(getAISnitchHomePath(options), "daemon.log");
13522
15095
  }
13523
15096
  function getLaunchAgentPath(options = {}) {
13524
- return (0, import_node_path17.join)(
15097
+ return (0, import_node_path19.join)(
13525
15098
  options.launchAgentHomeDirectory ?? (0, import_node_os4.homedir)(),
13526
15099
  "Library",
13527
15100
  "LaunchAgents",
@@ -13531,13 +15104,13 @@ function getLaunchAgentPath(options = {}) {
13531
15104
  async function writePid(pid, options = {}) {
13532
15105
  await ensureConfigDir(options);
13533
15106
  const pidFilePath = getPidFilePath(options);
13534
- await (0, import_promises15.writeFile)(pidFilePath, `${pid}
15107
+ await (0, import_promises16.writeFile)(pidFilePath, `${pid}
13535
15108
  `, "utf8");
13536
15109
  return pidFilePath;
13537
15110
  }
13538
15111
  async function readPid(options = {}) {
13539
15112
  try {
13540
- const rawPid = await (0, import_promises15.readFile)(getPidFilePath(options), "utf8");
15113
+ const rawPid = await (0, import_promises16.readFile)(getPidFilePath(options), "utf8");
13541
15114
  const parsedPid = Number.parseInt(rawPid.trim(), 10);
13542
15115
  if (!Number.isInteger(parsedPid) || parsedPid <= 0) {
13543
15116
  throw new Error("Invalid PID file contents.");
@@ -13551,13 +15124,13 @@ async function readPid(options = {}) {
13551
15124
  }
13552
15125
  }
13553
15126
  async function removePid(options = {}) {
13554
- await (0, import_promises15.rm)(getPidFilePath(options), { force: true });
15127
+ await (0, import_promises16.rm)(getPidFilePath(options), { force: true });
13555
15128
  }
13556
15129
  async function writeDaemonState(state, options = {}) {
13557
15130
  await ensureConfigDir(options);
13558
15131
  const daemonStatePath = getDaemonStatePath(options);
13559
15132
  const validatedState = DaemonStateSchema.parse(state);
13560
- await (0, import_promises15.writeFile)(
15133
+ await (0, import_promises16.writeFile)(
13561
15134
  daemonStatePath,
13562
15135
  `${JSON.stringify(validatedState, null, 2)}
13563
15136
  `,
@@ -13567,7 +15140,7 @@ async function writeDaemonState(state, options = {}) {
13567
15140
  }
13568
15141
  async function readDaemonState(options = {}) {
13569
15142
  try {
13570
- const rawJson = await (0, import_promises15.readFile)(getDaemonStatePath(options), "utf8");
15143
+ const rawJson = await (0, import_promises16.readFile)(getDaemonStatePath(options), "utf8");
13571
15144
  const parsedJson = JSON.parse(rawJson);
13572
15145
  return DaemonStateSchema.parse(parsedJson);
13573
15146
  } catch (error) {
@@ -13578,7 +15151,7 @@ async function readDaemonState(options = {}) {
13578
15151
  }
13579
15152
  }
13580
15153
  async function removeDaemonState(options = {}) {
13581
- await (0, import_promises15.rm)(getDaemonStatePath(options), { force: true });
15154
+ await (0, import_promises16.rm)(getDaemonStatePath(options), { force: true });
13582
15155
  }
13583
15156
  function isProcessRunning(pid) {
13584
15157
  try {
@@ -13614,13 +15187,13 @@ async function cleanupStaleDaemonFiles(options = {}) {
13614
15187
  }
13615
15188
  async function ensureLaunchAgentDir(options = {}) {
13616
15189
  const launchAgentPath = getLaunchAgentPath(options);
13617
- const directoryPath = (0, import_node_path17.dirname)(launchAgentPath);
13618
- await (0, import_promises15.mkdir)(directoryPath, { recursive: true });
15190
+ const directoryPath = (0, import_node_path19.dirname)(launchAgentPath);
15191
+ await (0, import_promises16.mkdir)(directoryPath, { recursive: true });
13619
15192
  return directoryPath;
13620
15193
  }
13621
15194
  async function getDaemonLogSize(options = {}) {
13622
15195
  try {
13623
- const logStats = await (0, import_promises15.stat)(getDaemonLogPath(options));
15196
+ const logStats = await (0, import_promises16.stat)(getDaemonLogPath(options));
13624
15197
  return logStats.size;
13625
15198
  } catch (error) {
13626
15199
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -13634,16 +15207,16 @@ function getEffectiveCliConfigPath(options = {}) {
13634
15207
  }
13635
15208
 
13636
15209
  // src/cli/auto-update.ts
13637
- var import_node_child_process14 = require("child_process");
13638
- var import_promises16 = require("fs/promises");
15210
+ var import_node_child_process15 = require("child_process");
13639
15211
  var import_promises17 = require("fs/promises");
13640
- var import_node_path18 = require("path");
15212
+ var import_promises18 = require("fs/promises");
15213
+ var import_node_path20 = require("path");
13641
15214
  var AUTO_UPDATE_STATE_FILE = "auto-update.json";
13642
15215
  var AUTO_UPDATE_LOG_FILE = "auto-update.log";
13643
15216
  function createAutoUpdateController(dependencies = {}) {
13644
15217
  const fetchImplementation = dependencies.fetch ?? globalThis.fetch;
13645
15218
  const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
13646
- const spawnImplementation = dependencies.spawn ?? import_node_child_process14.spawn;
15219
+ const spawnImplementation = dependencies.spawn ?? import_node_child_process15.spawn;
13647
15220
  return {
13648
15221
  runDetachedUpdate: async (options) => {
13649
15222
  const pathOptions = toPathOptions(options);
@@ -13651,8 +15224,8 @@ function createAutoUpdateController(dependencies = {}) {
13651
15224
  const command = resolveUpdateCommand(options.manager);
13652
15225
  const args = resolveUpdateArgs(options.manager);
13653
15226
  const aisnitchHomePath = getAISnitchHomePath(pathOptions);
13654
- await (0, import_promises16.mkdir)(aisnitchHomePath, { recursive: true });
13655
- const logFilePath = (0, import_node_path18.join)(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
15227
+ await (0, import_promises17.mkdir)(aisnitchHomePath, { recursive: true });
15228
+ const logFilePath = (0, import_node_path20.join)(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
13656
15229
  const startedAt = now().toISOString();
13657
15230
  await writeAutoUpdateState(
13658
15231
  {
@@ -13685,7 +15258,7 @@ function createAutoUpdateController(dependencies = {}) {
13685
15258
  });
13686
15259
  combinedLog += `[${now().toISOString()}] finished with code ${exitCode}
13687
15260
  `;
13688
- await (0, import_promises16.writeFile)(logFilePath, combinedLog, "utf8");
15261
+ await (0, import_promises17.writeFile)(logFilePath, combinedLog, "utf8");
13689
15262
  await writeAutoUpdateState(
13690
15263
  {
13691
15264
  attemptedVersion: options.latestVersion,
@@ -13776,7 +15349,7 @@ async function detectInstallManager(options) {
13776
15349
  }
13777
15350
  let resolvedCliPath = options.cliEntryPath;
13778
15351
  try {
13779
- resolvedCliPath = await (0, import_promises17.realpath)(options.cliEntryPath);
15352
+ resolvedCliPath = await (0, import_promises18.realpath)(options.cliEntryPath);
13780
15353
  } catch {
13781
15354
  }
13782
15355
  if (resolvedCliPath.includes("/Cellar/aisnitch/")) {
@@ -13840,7 +15413,7 @@ function resolveUpdateArgs(manager) {
13840
15413
  async function readAutoUpdateState(options) {
13841
15414
  const statePath = getAutoUpdateStatePath(options);
13842
15415
  try {
13843
- const rawJson = await (0, import_promises16.readFile)(statePath, "utf8");
15416
+ const rawJson = await (0, import_promises17.readFile)(statePath, "utf8");
13844
15417
  return JSON.parse(rawJson);
13845
15418
  } catch (error) {
13846
15419
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -13851,8 +15424,8 @@ async function readAutoUpdateState(options) {
13851
15424
  }
13852
15425
  async function writeAutoUpdateState(state, options) {
13853
15426
  const aisnitchHomePath = getAISnitchHomePath(options);
13854
- await (0, import_promises16.mkdir)(aisnitchHomePath, { recursive: true });
13855
- await (0, import_promises16.writeFile)(
15427
+ await (0, import_promises17.mkdir)(aisnitchHomePath, { recursive: true });
15428
+ await (0, import_promises17.writeFile)(
13856
15429
  getAutoUpdateStatePath(options),
13857
15430
  `${JSON.stringify(state, null, 2)}
13858
15431
  `,
@@ -13860,7 +15433,7 @@ async function writeAutoUpdateState(state, options) {
13860
15433
  );
13861
15434
  }
13862
15435
  function getAutoUpdateStatePath(options) {
13863
- return (0, import_node_path18.join)(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
15436
+ return (0, import_node_path20.join)(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
13864
15437
  }
13865
15438
  function toPathOptions(options) {
13866
15439
  return {
@@ -13974,9 +15547,9 @@ function flattenValue(lines, currentPath, value) {
13974
15547
  }
13975
15548
  lines.push(formatLoggerField(currentPath, value, inferValueKind(value)));
13976
15549
  }
13977
- function formatLoggerField(path, value, kind) {
15550
+ function formatLoggerField(path2, value, kind) {
13978
15551
  const renderedValue = typeof value === "string" ? JSON.stringify(value) : value === null ? "null" : typeof value === "undefined" ? "undefined" : JSON.stringify(value);
13979
- return `${colorize(path, TUI_THEME.warning)} ${colorize("=", TUI_THEME.muted)} ${colorize(
15552
+ return `${colorize(path2, TUI_THEME.warning)} ${colorize("=", TUI_THEME.muted)} ${colorize(
13980
15553
  renderedValue,
13981
15554
  getValueColor(kind)
13982
15555
  )}`;
@@ -14051,7 +15624,8 @@ function isRecord13(value) {
14051
15624
  }
14052
15625
 
14053
15626
  // src/cli/runtime.ts
14054
- var execFile14 = (0, import_node_util14.promisify)(import_node_child_process15.execFile);
15627
+ var openPromise = Promise.resolve().then(() => (init_open(), open_exports));
15628
+ var execFile21 = (0, import_node_util21.promisify)(import_node_child_process23.execFile);
14055
15629
  var DAEMON_READY_TIMEOUT_MS = 4e3;
14056
15630
  var DAEMON_READY_POLL_INTERVAL_MS = 100;
14057
15631
  var DAEMON_STOP_TIMEOUT_MS = 4e3;
@@ -14061,13 +15635,13 @@ function createCliRuntime(dependencies = {}) {
14061
15635
  const output = dependencies.output ?? createProcessOutput();
14062
15636
  const fetchImplementation = dependencies.fetch ?? globalThis.fetch;
14063
15637
  const renderManagedTuiImplementation = dependencies.renderManagedTui ?? renderManagedTui;
14064
- const spawnImplementation = dependencies.spawn ?? import_node_child_process15.spawn;
15638
+ const spawnImplementation = dependencies.spawn ?? import_node_child_process23.spawn;
14065
15639
  const autoUpdateController = createAutoUpdateController({
14066
15640
  fetch: fetchImplementation,
14067
15641
  spawn: spawnImplementation
14068
15642
  });
14069
15643
  const execFileImplementation = dependencies.execFile ?? (async (file, args) => {
14070
- return await execFile14(file, [...args], {
15644
+ return await execFile21(file, [...args], {
14071
15645
  encoding: "utf8"
14072
15646
  });
14073
15647
  });
@@ -14120,8 +15694,8 @@ function createCliRuntime(dependencies = {}) {
14120
15694
  await ensureConfigDir(daemonPathOptions);
14121
15695
  await rotateDaemonLogIfNeeded(daemonPathOptions);
14122
15696
  const daemonLogPath = getDaemonLogPath(daemonPathOptions);
14123
- const stdoutFd = (0, import_node_fs4.openSync)(daemonLogPath, "w");
14124
- const stderrFd = (0, import_node_fs4.openSync)(daemonLogPath, "a");
15697
+ const stdoutFd = (0, import_node_fs7.openSync)(daemonLogPath, "w");
15698
+ const stderrFd = (0, import_node_fs7.openSync)(daemonLogPath, "a");
14125
15699
  const cliEntryPath = resolveCliEntryPath();
14126
15700
  const daemonArgs = [cliEntryPath, "daemon-run", ...toDaemonArgv(options)];
14127
15701
  const child = spawnImplementation(process.execPath, daemonArgs, {
@@ -14133,8 +15707,8 @@ function createCliRuntime(dependencies = {}) {
14133
15707
  stdio: ["ignore", stdoutFd, stderrFd]
14134
15708
  });
14135
15709
  child.unref();
14136
- (0, import_node_fs4.closeSync)(stdoutFd);
14137
- (0, import_node_fs4.closeSync)(stderrFd);
15710
+ (0, import_node_fs7.closeSync)(stdoutFd);
15711
+ (0, import_node_fs7.closeSync)(stderrFd);
14138
15712
  if (child.pid === void 0) {
14139
15713
  throw new Error("Failed to obtain the AISnitch daemon PID.");
14140
15714
  }
@@ -14206,8 +15780,8 @@ function createCliRuntime(dependencies = {}) {
14206
15780
  if (logSize < DAEMON_LOG_MAX_BYTES) {
14207
15781
  return;
14208
15782
  }
14209
- await (0, import_promises18.rm)(backupPath, { force: true });
14210
- await (0, import_promises18.rename)(logFilePath, backupPath);
15783
+ await (0, import_promises22.rm)(backupPath, { force: true });
15784
+ await (0, import_promises22.rename)(logFilePath, backupPath);
14211
15785
  }
14212
15786
  async function waitForDaemonReady(pathOptions) {
14213
15787
  const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
@@ -14242,7 +15816,7 @@ function createCliRuntime(dependencies = {}) {
14242
15816
  }
14243
15817
  async function readDaemonStartupFailure(pathOptions) {
14244
15818
  try {
14245
- const daemonLog = await (0, import_promises18.readFile)(getDaemonLogPath(pathOptions), "utf8");
15819
+ const daemonLog = await (0, import_promises22.readFile)(getDaemonLogPath(pathOptions), "utf8");
14246
15820
  const logLines = daemonLog.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
14247
15821
  const lastLine = logLines.at(-1);
14248
15822
  if (!lastLine) {
@@ -14340,22 +15914,35 @@ function createCliRuntime(dependencies = {}) {
14340
15914
  return;
14341
15915
  }
14342
15916
  shuttingDown = true;
14343
- try {
14344
- await pipeline.stop();
14345
- } finally {
14346
- if (daemonMode) {
14347
- const daemonPathOptions = toPathOptions2(options);
15917
+ const shutdownTimeouts = {
15918
+ adapterRegistry: DEFAULT_TIMEOUTS.adapterShutdown,
15919
+ httpReceiver: DEFAULT_TIMEOUTS.httpRequest,
15920
+ udsServer: DEFAULT_TIMEOUTS.fileOperation,
15921
+ wsServer: DEFAULT_TIMEOUTS.wsConnection,
15922
+ cleanupFns: 1e3
15923
+ };
15924
+ const components = {
15925
+ adapterRegistry: pipeline.getAdapterRegistry(),
15926
+ httpReceiver: pipeline.getHttpReceiver(),
15927
+ udsServer: pipeline.getUdsServer(),
15928
+ wsServer: pipeline.getWsServer(),
15929
+ eventBus: pipeline.getEventBus(),
15930
+ cleanupFns: daemonMode ? [async () => {
14348
15931
  await Promise.all([
14349
- removePid(daemonPathOptions),
14350
- removeDaemonState(daemonPathOptions)
15932
+ removePid(toPathOptions2(options)),
15933
+ removeDaemonState(toPathOptions2(options))
14351
15934
  ]);
14352
- }
14353
- }
14354
- if (!daemonMode) {
14355
- output.stdout(`AISnitch stopped after ${signal}.
15935
+ }] : []
15936
+ };
15937
+ try {
15938
+ await shutdownInOrder(components, shutdownTimeouts, "pipeline");
15939
+ } finally {
15940
+ if (!daemonMode) {
15941
+ output.stdout(`AISnitch stopped after ${signal}.
14356
15942
  `);
15943
+ }
15944
+ process.exit(exitCode);
14357
15945
  }
14358
- process.exit(exitCode);
14359
15946
  };
14360
15947
  if (daemonMode) {
14361
15948
  process.once("SIGTERM", () => {
@@ -14541,6 +16128,113 @@ function createCliRuntime(dependencies = {}) {
14541
16128
  }
14542
16129
  });
14543
16130
  }
16131
+ async function fullscreen(options) {
16132
+ const snapshot = await getStatusSnapshot(options);
16133
+ if (!snapshot.running && options.daemonMode) {
16134
+ output.stdout("Starting daemon...\n");
16135
+ await startDetachedDaemon(options);
16136
+ }
16137
+ if (!snapshot.running && !options.daemonMode) {
16138
+ throw new Error(
16139
+ "AISnitch daemon is not running. Start one with `aisnitch start --daemon` or use `aisnitch fs --daemon` to start and open the dashboard."
16140
+ );
16141
+ }
16142
+ for (let i = 0; i < 20; i++) {
16143
+ const health = await fetchHealth(snapshot.httpPort);
16144
+ if (health) break;
16145
+ await new Promise((resolve2) => setTimeout(resolve2, 200).unref());
16146
+ }
16147
+ const dashboardPort = options.dashboardPort ?? 5174;
16148
+ const dashboardUrl = `http://127.0.0.1:${dashboardPort}`;
16149
+ const distPath = (0, import_node_path22.join)(process.cwd(), "examples", "fullscreen-dashboard", "dist");
16150
+ output.stdout(`Starting dashboard server on port ${dashboardPort}...
16151
+ `);
16152
+ const viteProcess = spawnImplementation(process.execPath, [
16153
+ "-e",
16154
+ `
16155
+ import { createServer } from 'vite';
16156
+ import path from 'path';
16157
+
16158
+ const distPath = '${distPath}';
16159
+ const port = ${dashboardPort};
16160
+
16161
+ const server = await createServer({
16162
+ root: distPath,
16163
+ server: {
16164
+ port,
16165
+ strictPort: true,
16166
+ allowedHosts: true,
16167
+ },
16168
+ preview: {
16169
+ port,
16170
+ strictPort: true,
16171
+ },
16172
+ });
16173
+
16174
+ await server.listen();
16175
+ console.log('READY');
16176
+
16177
+ process.stdin.resume();
16178
+ `
16179
+ ], {
16180
+ cwd: distPath,
16181
+ stdio: ["pipe", "pipe", "pipe"]
16182
+ });
16183
+ let serverOutput = "";
16184
+ viteProcess.stdout?.on("data", (data) => {
16185
+ serverOutput += data.toString();
16186
+ });
16187
+ viteProcess.stderr?.on("data", (data) => {
16188
+ serverOutput += data.toString();
16189
+ });
16190
+ let serverReady = false;
16191
+ for (let i = 0; i < 100; i++) {
16192
+ await new Promise((resolve2) => setTimeout(resolve2, 100).unref());
16193
+ try {
16194
+ const response = await fetchImplementation(dashboardUrl);
16195
+ if (response.ok) {
16196
+ serverReady = true;
16197
+ break;
16198
+ }
16199
+ } catch {
16200
+ }
16201
+ if (!viteProcess.pid) break;
16202
+ }
16203
+ if (!serverReady) {
16204
+ output.stdout(`Server output: ${serverOutput}
16205
+ `);
16206
+ throw new Error("Failed to start dashboard server");
16207
+ }
16208
+ output.stdout(`Dashboard ready at ${dashboardUrl}
16209
+ `);
16210
+ if (!options.noBrowser) {
16211
+ output.stdout("Opening browser...\n");
16212
+ const openModule = await openPromise;
16213
+ await openModule.default(dashboardUrl);
16214
+ }
16215
+ output.stdout("Press Ctrl+C to stop\n");
16216
+ await new Promise((resolve2) => {
16217
+ const shutdown = () => {
16218
+ process.off("SIGINT", handleSigint);
16219
+ process.off("SIGTERM", handleSigterm);
16220
+ if (viteProcess.pid !== void 0) {
16221
+ try {
16222
+ process.kill(viteProcess.pid, "SIGTERM");
16223
+ } catch {
16224
+ }
16225
+ }
16226
+ resolve2();
16227
+ };
16228
+ const handleSigint = () => {
16229
+ shutdown();
16230
+ };
16231
+ const handleSigterm = () => {
16232
+ shutdown();
16233
+ };
16234
+ process.once("SIGINT", handleSigint);
16235
+ process.once("SIGTERM", handleSigterm);
16236
+ });
16237
+ }
14544
16238
  async function logger2(options) {
14545
16239
  const snapshot = await getStatusSnapshot(options);
14546
16240
  if (!snapshot.running) {
@@ -14612,7 +16306,7 @@ function createCliRuntime(dependencies = {}) {
14612
16306
  }
14613
16307
  const { config } = await loadEffectiveConfig(options);
14614
16308
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14615
- const ephemeralHomeDirectory = await (0, import_promises18.mkdtemp)((0, import_node_path19.join)((0, import_node_os5.tmpdir)(), "aisnitch-mock-"));
16309
+ const ephemeralHomeDirectory = await (0, import_promises22.mkdtemp)((0, import_node_path22.join)((0, import_node_os6.tmpdir)(), "aisnitch-mock-"));
14616
16310
  const ephemeralPipeline = new Pipeline();
14617
16311
  const status2 = await ephemeralPipeline.start({
14618
16312
  config: {
@@ -14651,7 +16345,7 @@ function createCliRuntime(dependencies = {}) {
14651
16345
  } finally {
14652
16346
  await Promise.resolve(monitorClose());
14653
16347
  await ephemeralPipeline.stop();
14654
- await (0, import_promises18.rm)(ephemeralHomeDirectory, { force: true, recursive: true });
16348
+ await (0, import_promises22.rm)(ephemeralHomeDirectory, { force: true, recursive: true });
14655
16349
  }
14656
16350
  }
14657
16351
  async function install(options) {
@@ -14673,7 +16367,7 @@ function createCliRuntime(dependencies = {}) {
14673
16367
  await execFileImplementation("launchctl", ["bootout", domainTarget, launchAgentPath]);
14674
16368
  } catch {
14675
16369
  }
14676
- await (0, import_promises18.writeFile)(launchAgentPath, plistContents, "utf8");
16370
+ await (0, import_promises22.writeFile)(launchAgentPath, plistContents, "utf8");
14677
16371
  await execFileImplementation("launchctl", ["bootstrap", domainTarget, launchAgentPath]);
14678
16372
  output.stdout(`AISnitch LaunchAgent installed at ${launchAgentPath}
14679
16373
  `);
@@ -14696,7 +16390,7 @@ function createCliRuntime(dependencies = {}) {
14696
16390
  } else {
14697
16391
  const { config } = await loadEffectiveConfig(options);
14698
16392
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14699
- ephemeralHomeDirectory = await (0, import_promises18.mkdtemp)((0, import_node_path19.join)((0, import_node_os5.tmpdir)(), "aisnitch-wrap-"));
16393
+ ephemeralHomeDirectory = await (0, import_promises22.mkdtemp)((0, import_node_path22.join)((0, import_node_os6.tmpdir)(), "aisnitch-wrap-"));
14700
16394
  ephemeralPipeline = new Pipeline();
14701
16395
  await ephemeralPipeline.start({
14702
16396
  config: {
@@ -14751,7 +16445,7 @@ function createCliRuntime(dependencies = {}) {
14751
16445
  await ephemeralPipeline.stop();
14752
16446
  }
14753
16447
  if (ephemeralHomeDirectory !== null) {
14754
- await (0, import_promises18.rm)(ephemeralHomeDirectory, { force: true, recursive: true });
16448
+ await (0, import_promises22.rm)(ephemeralHomeDirectory, { force: true, recursive: true });
14755
16449
  }
14756
16450
  }
14757
16451
  process.exit(wrappedExitCode);
@@ -14771,7 +16465,7 @@ function createCliRuntime(dependencies = {}) {
14771
16465
  },
14772
16466
  pid: process.ppid > 1 ? process.ppid : void 0,
14773
16467
  source: "aisnitch://adapters/aider/notifications-command",
14774
- transcriptPath: (0, import_node_path19.join)(process.cwd(), ".aider.chat.history.md"),
16468
+ transcriptPath: (0, import_node_path22.join)(process.cwd(), ".aider.chat.history.md"),
14775
16469
  type: "agent.idle"
14776
16470
  }),
14777
16471
  headers: {
@@ -14793,7 +16487,7 @@ function createCliRuntime(dependencies = {}) {
14793
16487
  await execFileImplementation("launchctl", ["bootout", domainTarget, launchAgentPath]);
14794
16488
  } catch {
14795
16489
  }
14796
- await (0, import_promises18.rm)(launchAgentPath, { force: true });
16490
+ await (0, import_promises22.rm)(launchAgentPath, { force: true });
14797
16491
  output.stdout(`AISnitch LaunchAgent removed from ${launchAgentPath}
14798
16492
  `);
14799
16493
  }
@@ -14832,6 +16526,7 @@ function createCliRuntime(dependencies = {}) {
14832
16526
  adapters,
14833
16527
  aiderNotify,
14834
16528
  attach,
16529
+ fullscreen,
14835
16530
  install,
14836
16531
  logger: logger2,
14837
16532
  mock,
@@ -14972,7 +16667,7 @@ function joinSocketPath(pathOptions) {
14972
16667
  }
14973
16668
  function resolveCliEntryPath() {
14974
16669
  const cliEntryPath = process.argv[1];
14975
- if (!cliEntryPath || (0, import_node_path19.basename)(cliEntryPath).length === 0) {
16670
+ if (!cliEntryPath || (0, import_node_path22.basename)(cliEntryPath).length === 0) {
14976
16671
  throw new Error("Unable to resolve the AISnitch CLI entry path.");
14977
16672
  }
14978
16673
  return cliEntryPath;
@@ -15043,6 +16738,9 @@ Examples:
15043
16738
  aisnitch start --daemon
15044
16739
  aisnitch start --view full-data
15045
16740
  aisnitch start --mock
16741
+ aisnitch fs
16742
+ aisnitch fs --daemon
16743
+ aisnitch fs --dashboard-port 8080
15046
16744
  aisnitch status
15047
16745
  aisnitch attach
15048
16746
  aisnitch attach --view full-data
@@ -15066,6 +16764,7 @@ Examples:
15066
16764
  addAdaptersCommand(program, runtime);
15067
16765
  addSetupCommand(program, runtime);
15068
16766
  addAttachCommand(program, runtime);
16767
+ addFullscreenCommand(program, runtime);
15069
16768
  addLoggerCommand(program, runtime);
15070
16769
  addMockCommand(program, runtime);
15071
16770
  addWrapCommand(program, runtime);
@@ -15198,6 +16897,23 @@ function addAttachCommand(program, runtime) {
15198
16897
  await runtime.attach(options);
15199
16898
  });
15200
16899
  }
16900
+ function addFullscreenCommand(program, runtime) {
16901
+ addCommonOptions(
16902
+ program.command("fs").description("Open the fullscreen web dashboard in browser (starts daemon if needed with --daemon)").alias("fullscreen").option(
16903
+ "--daemon",
16904
+ "Start the daemon automatically if not running"
16905
+ ).option(
16906
+ "--dashboard-port <port>",
16907
+ "Port for the dashboard server (default: 5174)",
16908
+ wrapOptionParser(parsePortOption)
16909
+ ).option(
16910
+ "--no-browser",
16911
+ "Start server without opening browser"
16912
+ )
16913
+ ).action(async (options) => {
16914
+ await runtime.fullscreen(options);
16915
+ });
16916
+ }
15201
16917
  function addWrapCommand(program, runtime) {
15202
16918
  addCommonOptions(
15203
16919
  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")