@mohak34/opencode-notifier 0.1.30-beta.4 → 0.1.30-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +67 -208
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3728,7 +3728,7 @@ var require_node_notifier = __commonJS((exports, module) => {
|
|
|
3728
3728
|
|
|
3729
3729
|
// src/index.ts
|
|
3730
3730
|
import { basename } from "path";
|
|
3731
|
-
import { readFileSync as
|
|
3731
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3732
3732
|
|
|
3733
3733
|
// src/config.ts
|
|
3734
3734
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -4222,49 +4222,6 @@ function runCommand2(config, event, message, sessionTitle, projectName, timestam
|
|
|
4222
4222
|
|
|
4223
4223
|
// src/focus.ts
|
|
4224
4224
|
import { execSync } from "child_process";
|
|
4225
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
4226
|
-
var TERMINAL_MAP = {
|
|
4227
|
-
ghostty: { name: "Ghostty", macProcessNames: ["Ghostty", "ghostty"] },
|
|
4228
|
-
kitty: { name: "kitty", macProcessNames: ["kitty"] },
|
|
4229
|
-
alacritty: { name: "Alacritty", macProcessNames: ["Alacritty", "alacritty"] },
|
|
4230
|
-
wezterm: { name: "WezTerm", macProcessNames: ["WezTerm", "wezterm-gui"] },
|
|
4231
|
-
apple_terminal: { name: "Terminal", macProcessNames: ["Terminal"] },
|
|
4232
|
-
iterm: { name: "iTerm2", macProcessNames: ["iTerm2", "iTerm"] },
|
|
4233
|
-
warp: { name: "Warp", macProcessNames: ["Warp"] },
|
|
4234
|
-
vscode: { name: "VS Code", macProcessNames: ["Code", "Code - Insiders", "Cursor", "cursor"] },
|
|
4235
|
-
windows_terminal: { name: "Windows Terminal", macProcessNames: [] },
|
|
4236
|
-
tmux: { name: "tmux", macProcessNames: [] }
|
|
4237
|
-
};
|
|
4238
|
-
var cachedTerminal = undefined;
|
|
4239
|
-
function detectTerminal() {
|
|
4240
|
-
if (cachedTerminal !== undefined)
|
|
4241
|
-
return cachedTerminal;
|
|
4242
|
-
const env = process.env;
|
|
4243
|
-
let result = null;
|
|
4244
|
-
if (env.GHOSTTY_RESOURCES_DIR) {
|
|
4245
|
-
result = TERMINAL_MAP.ghostty;
|
|
4246
|
-
} else if (env.KITTY_PID) {
|
|
4247
|
-
result = TERMINAL_MAP.kitty;
|
|
4248
|
-
} else if (env.ALACRITTY_SOCKET || env.ALACRITTY_LOG) {
|
|
4249
|
-
result = TERMINAL_MAP.alacritty;
|
|
4250
|
-
} else if (env.WEZTERM_EXECUTABLE) {
|
|
4251
|
-
result = TERMINAL_MAP.wezterm;
|
|
4252
|
-
} else if (env.WT_SESSION) {
|
|
4253
|
-
result = TERMINAL_MAP.windows_terminal;
|
|
4254
|
-
} else if (env.VSCODE_PID || env.TERM_PROGRAM === "vscode") {
|
|
4255
|
-
result = TERMINAL_MAP.vscode;
|
|
4256
|
-
} else if (env.TERM_PROGRAM === "Apple_Terminal") {
|
|
4257
|
-
result = TERMINAL_MAP.apple_terminal;
|
|
4258
|
-
} else if (env.TERM_PROGRAM === "iTerm.app") {
|
|
4259
|
-
result = TERMINAL_MAP.iterm;
|
|
4260
|
-
} else if (env.TERM_PROGRAM === "WarpTerminal") {
|
|
4261
|
-
result = TERMINAL_MAP.warp;
|
|
4262
|
-
} else if (env.TMUX || env.TERM_PROGRAM === "tmux") {
|
|
4263
|
-
result = TERMINAL_MAP.tmux;
|
|
4264
|
-
}
|
|
4265
|
-
cachedTerminal = result;
|
|
4266
|
-
return result;
|
|
4267
|
-
}
|
|
4268
4225
|
function execWithTimeout(command, timeoutMs = 500) {
|
|
4269
4226
|
try {
|
|
4270
4227
|
return execSync(command, { timeout: timeoutMs, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
@@ -4272,205 +4229,107 @@ function execWithTimeout(command, timeoutMs = 500) {
|
|
|
4272
4229
|
return null;
|
|
4273
4230
|
}
|
|
4274
4231
|
}
|
|
4275
|
-
function
|
|
4276
|
-
const frontApp = execWithTimeout(`osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true'`);
|
|
4277
|
-
if (!frontApp)
|
|
4278
|
-
return false;
|
|
4279
|
-
return terminal.macProcessNames.some((name) => name.toLowerCase() === frontApp.toLowerCase());
|
|
4280
|
-
}
|
|
4281
|
-
function getParentPid(pid) {
|
|
4282
|
-
try {
|
|
4283
|
-
const stat = readFileSync2(`/proc/${pid}/stat`, "utf-8");
|
|
4284
|
-
const closingParen = stat.lastIndexOf(")");
|
|
4285
|
-
if (closingParen === -1)
|
|
4286
|
-
return null;
|
|
4287
|
-
const fields = stat.slice(closingParen + 2).split(" ");
|
|
4288
|
-
const ppid = parseInt(fields[1], 10);
|
|
4289
|
-
return Number.isFinite(ppid) ? ppid : null;
|
|
4290
|
-
} catch {
|
|
4291
|
-
return null;
|
|
4292
|
-
}
|
|
4293
|
-
}
|
|
4294
|
-
function getProcessTreeRoot() {
|
|
4295
|
-
if (process.env.TMUX) {
|
|
4296
|
-
const clientPidStr = execWithTimeout("tmux display-message -p '#{client_pid}'");
|
|
4297
|
-
if (clientPidStr) {
|
|
4298
|
-
const clientPid = parseInt(clientPidStr, 10);
|
|
4299
|
-
if (Number.isFinite(clientPid) && clientPid > 0)
|
|
4300
|
-
return clientPid;
|
|
4301
|
-
}
|
|
4302
|
-
}
|
|
4303
|
-
return process.pid;
|
|
4304
|
-
}
|
|
4305
|
-
function isPidAncestorOfProcess(targetPid, startPid) {
|
|
4306
|
-
let currentPid = startPid;
|
|
4307
|
-
for (let depth = 0;depth < 20; depth++) {
|
|
4308
|
-
if (currentPid === targetPid)
|
|
4309
|
-
return true;
|
|
4310
|
-
if (currentPid <= 1)
|
|
4311
|
-
return false;
|
|
4312
|
-
const ppid = getParentPid(currentPid);
|
|
4313
|
-
if (ppid === null)
|
|
4314
|
-
return false;
|
|
4315
|
-
currentPid = ppid;
|
|
4316
|
-
}
|
|
4317
|
-
return false;
|
|
4318
|
-
}
|
|
4319
|
-
function isFocusedWindowOurs(windowPid) {
|
|
4320
|
-
return isPidAncestorOfProcess(windowPid, getProcessTreeRoot());
|
|
4321
|
-
}
|
|
4322
|
-
var tmuxPane = process.env.TMUX_PANE ?? null;
|
|
4323
|
-
function isTmuxPaneActive() {
|
|
4324
|
-
if (!tmuxPane)
|
|
4325
|
-
return true;
|
|
4326
|
-
const result = execWithTimeout(`tmux display-message -t ${tmuxPane} -p '#{window_active} #{pane_active}'`);
|
|
4327
|
-
if (!result)
|
|
4328
|
-
return false;
|
|
4329
|
-
const [windowActive, paneActive] = result.split(" ");
|
|
4330
|
-
return windowActive === "1" && paneActive === "1";
|
|
4331
|
-
}
|
|
4332
|
-
function isLinuxX11Focused() {
|
|
4333
|
-
const pidStr = execWithTimeout("xdotool getactivewindow getwindowpid");
|
|
4334
|
-
if (!pidStr)
|
|
4335
|
-
return false;
|
|
4336
|
-
const pid = parseInt(pidStr, 10);
|
|
4337
|
-
if (!Number.isFinite(pid) || pid <= 0)
|
|
4338
|
-
return false;
|
|
4339
|
-
return isFocusedWindowOurs(pid);
|
|
4340
|
-
}
|
|
4341
|
-
function isHyprlandFocused() {
|
|
4232
|
+
function getHyprlandActiveWindowId() {
|
|
4342
4233
|
const output = execWithTimeout("hyprctl activewindow -j");
|
|
4343
4234
|
if (!output)
|
|
4344
|
-
return
|
|
4235
|
+
return null;
|
|
4345
4236
|
try {
|
|
4346
4237
|
const data = JSON.parse(output);
|
|
4347
|
-
|
|
4348
|
-
if (typeof pid !== "number" || pid <= 0)
|
|
4349
|
-
return false;
|
|
4350
|
-
return isFocusedWindowOurs(pid);
|
|
4238
|
+
return typeof data?.address === "string" ? data.address : null;
|
|
4351
4239
|
} catch {
|
|
4352
|
-
return
|
|
4353
|
-
}
|
|
4354
|
-
}
|
|
4355
|
-
function isSwayFocused() {
|
|
4356
|
-
const output = execWithTimeout("swaymsg -t get_tree", 1000);
|
|
4357
|
-
if (!output)
|
|
4358
|
-
return false;
|
|
4359
|
-
try {
|
|
4360
|
-
const tree = JSON.parse(output);
|
|
4361
|
-
const pid = findFocusedPid(tree);
|
|
4362
|
-
if (pid === null)
|
|
4363
|
-
return false;
|
|
4364
|
-
return isFocusedWindowOurs(pid);
|
|
4365
|
-
} catch {
|
|
4366
|
-
return false;
|
|
4240
|
+
return null;
|
|
4367
4241
|
}
|
|
4368
4242
|
}
|
|
4369
|
-
function
|
|
4370
|
-
if (node.focused === true && typeof node.
|
|
4371
|
-
return node.
|
|
4243
|
+
function findFocusedWindowId(node) {
|
|
4244
|
+
if (node.focused === true && typeof node.id === "number") {
|
|
4245
|
+
return String(node.id);
|
|
4372
4246
|
}
|
|
4373
4247
|
if (Array.isArray(node.nodes)) {
|
|
4374
4248
|
for (const child of node.nodes) {
|
|
4375
|
-
const
|
|
4376
|
-
if (
|
|
4377
|
-
return
|
|
4249
|
+
const id = findFocusedWindowId(child);
|
|
4250
|
+
if (id !== null)
|
|
4251
|
+
return id;
|
|
4378
4252
|
}
|
|
4379
4253
|
}
|
|
4380
4254
|
if (Array.isArray(node.floating_nodes)) {
|
|
4381
4255
|
for (const child of node.floating_nodes) {
|
|
4382
|
-
const
|
|
4383
|
-
if (
|
|
4384
|
-
return
|
|
4256
|
+
const id = findFocusedWindowId(child);
|
|
4257
|
+
if (id !== null)
|
|
4258
|
+
return id;
|
|
4385
4259
|
}
|
|
4386
4260
|
}
|
|
4387
4261
|
return null;
|
|
4388
4262
|
}
|
|
4389
|
-
function
|
|
4390
|
-
const
|
|
4391
|
-
if (!
|
|
4392
|
-
return
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
return
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
return isFocusedWindowOurs(pid);
|
|
4263
|
+
function getSwayActiveWindowId() {
|
|
4264
|
+
const output = execWithTimeout("swaymsg -t get_tree", 1000);
|
|
4265
|
+
if (!output)
|
|
4266
|
+
return null;
|
|
4267
|
+
try {
|
|
4268
|
+
const tree = JSON.parse(output);
|
|
4269
|
+
return findFocusedWindowId(tree);
|
|
4270
|
+
} catch {
|
|
4271
|
+
return null;
|
|
4272
|
+
}
|
|
4400
4273
|
}
|
|
4401
|
-
function
|
|
4274
|
+
function getLinuxWaylandActiveWindowId() {
|
|
4402
4275
|
const env = process.env;
|
|
4403
|
-
if (env.HYPRLAND_INSTANCE_SIGNATURE)
|
|
4404
|
-
return
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
return isKDEWaylandFocused();
|
|
4411
|
-
}
|
|
4412
|
-
return false;
|
|
4276
|
+
if (env.HYPRLAND_INSTANCE_SIGNATURE)
|
|
4277
|
+
return getHyprlandActiveWindowId();
|
|
4278
|
+
if (env.SWAYSOCK)
|
|
4279
|
+
return getSwayActiveWindowId();
|
|
4280
|
+
if (env.KDE_SESSION_VERSION)
|
|
4281
|
+
return execWithTimeout("kdotool getactivewindow");
|
|
4282
|
+
return null;
|
|
4413
4283
|
}
|
|
4414
|
-
function
|
|
4284
|
+
function getWindowsActiveWindowId() {
|
|
4415
4285
|
const script = `
|
|
4416
4286
|
Add-Type @"
|
|
4417
4287
|
using System;
|
|
4418
4288
|
using System.Runtime.InteropServices;
|
|
4419
4289
|
public class FocusHelper {
|
|
4420
4290
|
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
|
4421
|
-
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint pid);
|
|
4422
4291
|
}
|
|
4423
4292
|
"@
|
|
4424
4293
|
$hwnd = [FocusHelper]::GetForegroundWindow()
|
|
4425
|
-
$
|
|
4426
|
-
[void][FocusHelper]::GetWindowThreadProcessId($hwnd, [ref]$pid)
|
|
4427
|
-
Write-Output $pid
|
|
4294
|
+
Write-Output $hwnd
|
|
4428
4295
|
`.trim().replace(/\n/g, "; ");
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
const
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
return false;
|
|
4445
|
-
currentPid = parseInt(parentPidStr, 10);
|
|
4446
|
-
if (!Number.isFinite(currentPid))
|
|
4447
|
-
return false;
|
|
4296
|
+
return execWithTimeout(`powershell -NoProfile -Command "${script}"`, 1000);
|
|
4297
|
+
}
|
|
4298
|
+
function getMacOSActiveWindowId() {
|
|
4299
|
+
return execWithTimeout(`osascript -e 'tell application "System Events" to return id of window 1 of (first application process whose frontmost is true)'`);
|
|
4300
|
+
}
|
|
4301
|
+
function getActiveWindowId() {
|
|
4302
|
+
const platform3 = process.platform;
|
|
4303
|
+
if (platform3 === "darwin")
|
|
4304
|
+
return getMacOSActiveWindowId();
|
|
4305
|
+
if (platform3 === "linux") {
|
|
4306
|
+
if (process.env.WAYLAND_DISPLAY)
|
|
4307
|
+
return getLinuxWaylandActiveWindowId();
|
|
4308
|
+
if (process.env.DISPLAY)
|
|
4309
|
+
return execWithTimeout("xdotool getactivewindow");
|
|
4310
|
+
return null;
|
|
4448
4311
|
}
|
|
4449
|
-
|
|
4312
|
+
if (platform3 === "win32")
|
|
4313
|
+
return getWindowsActiveWindowId();
|
|
4314
|
+
return null;
|
|
4315
|
+
}
|
|
4316
|
+
var cachedWindowId = getActiveWindowId();
|
|
4317
|
+
var tmuxPane = process.env.TMUX_PANE ?? null;
|
|
4318
|
+
function isTmuxPaneActive() {
|
|
4319
|
+
if (!tmuxPane)
|
|
4320
|
+
return true;
|
|
4321
|
+
const result = execWithTimeout(`tmux display-message -t ${tmuxPane} -p '#{session_attached} #{window_active} #{pane_active}'`);
|
|
4322
|
+
if (!result)
|
|
4323
|
+
return false;
|
|
4324
|
+
const [sessionAttached, windowActive, paneActive] = result.split(" ");
|
|
4325
|
+
return sessionAttached === "1" && windowActive === "1" && paneActive === "1";
|
|
4450
4326
|
}
|
|
4451
4327
|
function isTerminalFocused() {
|
|
4452
4328
|
try {
|
|
4453
|
-
|
|
4454
|
-
let windowFocused = false;
|
|
4455
|
-
if (platform3 === "darwin") {
|
|
4456
|
-
const terminal = detectTerminal();
|
|
4457
|
-
if (!terminal || terminal.macProcessNames.length === 0)
|
|
4458
|
-
return false;
|
|
4459
|
-
windowFocused = isMacOSFocused(terminal);
|
|
4460
|
-
} else if (platform3 === "linux") {
|
|
4461
|
-
if (process.env.WAYLAND_DISPLAY) {
|
|
4462
|
-
windowFocused = isLinuxWaylandFocused();
|
|
4463
|
-
} else if (process.env.DISPLAY) {
|
|
4464
|
-
windowFocused = isLinuxX11Focused();
|
|
4465
|
-
} else {
|
|
4466
|
-
return false;
|
|
4467
|
-
}
|
|
4468
|
-
} else if (platform3 === "win32") {
|
|
4469
|
-
windowFocused = isWindowsFocused();
|
|
4470
|
-
} else {
|
|
4329
|
+
if (!cachedWindowId)
|
|
4471
4330
|
return false;
|
|
4472
|
-
|
|
4473
|
-
if (
|
|
4331
|
+
const currentId = getActiveWindowId();
|
|
4332
|
+
if (currentId !== cachedWindowId)
|
|
4474
4333
|
return false;
|
|
4475
4334
|
if (process.env.TMUX)
|
|
4476
4335
|
return isTmuxPaneActive();
|
|
@@ -4489,7 +4348,7 @@ var sessionLastBusyAt = new Map;
|
|
|
4489
4348
|
var globalTurnCount = null;
|
|
4490
4349
|
function loadTurnCount() {
|
|
4491
4350
|
try {
|
|
4492
|
-
const content =
|
|
4351
|
+
const content = readFileSync2(getStatePath(), "utf-8");
|
|
4493
4352
|
const state = JSON.parse(content);
|
|
4494
4353
|
if (typeof state.turn === "number" && Number.isFinite(state.turn) && state.turn >= 0) {
|
|
4495
4354
|
return state.turn;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mohak34/opencode-notifier",
|
|
3
|
-
"version": "0.1.30-beta.
|
|
3
|
+
"version": "0.1.30-beta.6",
|
|
4
4
|
"description": "OpenCode plugin that sends system notifications and plays sounds when permission is needed, generation completes, or errors occur",
|
|
5
5
|
"author": "mohak34",
|
|
6
6
|
"license": "MIT",
|