pi-smart-voice-notify 0.5.3 → 0.5.4
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/CHANGELOG.md +13 -0
- package/README.md +11 -5
- package/package.json +81 -74
- package/src/abortable-command.ts +31 -1
- package/src/config-store.ts +61 -10
- package/src/index.ts +2 -2
- package/src/linux.ts +23 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.5.4] - 2026-06-22
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Added a command allowlist to `runAbortableCommand` so non-allowlisted executables are rejected before spawning, preventing arbitrary command injection.
|
|
9
|
+
- Replaced dynamic string-based command spawning in Linux helpers with a typed `LinuxCommandName` union and dedicated `spawnLinuxCommand` switch.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Added `postinstall` hook that runs `patch-vulnerable-deps.mjs` when installed under `.pi/agent/extensions/`.
|
|
13
|
+
- Pinned `protobufjs` 7.6.3, `ws` 8.21.0, and `uuid` 11.1.1 via npm `overrides` to resolve known vulnerabilities.
|
|
14
|
+
- Added `@earendil-works/pi-coding-agent` as a devDependency for type-checking.
|
|
15
|
+
- Updated README badge styling to for-the-badge, added platform badge and ko-fi support button.
|
|
16
|
+
- Added `config-store-env-override` test to the test script.
|
|
17
|
+
|
|
5
18
|
## [0.5.3] - 2026-06-16
|
|
6
19
|
|
|
7
20
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# pi-smart-voice-notify
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/pi-smart-voice-notify)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[]()
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
[](https://ko-fi.com/Y8Y01PSSVR)
|
|
8
10
|
|
|
11
|
+
Windows-optimized smart notification extension for the Pi coding agent.
|
|
12
|
+
**pi-smart-voice-notify** monitors Pi session and tool events to alert you via **multi-engine TTS**, **sound playback**, **desktop toast notifications**, and optional **webhook/AI-assisted messaging** when the agent requires your attention.
|
|
9
13
|
<img width="1360" height="752" alt="image" src="https://github.com/user-attachments/assets/c215a7fe-31b4-4bc4-a89e-992a4847819d" />
|
|
10
14
|
|
|
15
|
+
</div>
|
|
11
16
|
|
|
12
17
|
## Features
|
|
13
18
|
|
|
@@ -99,6 +104,7 @@ Configuration is stored at:
|
|
|
99
104
|
```text
|
|
100
105
|
Default global path: ~/.pi/agent/extensions/pi-smart-voice-notify/config.json
|
|
101
106
|
Actual global path: $PI_CODING_AGENT_DIR/extensions/pi-smart-voice-notify/config.json when PI_CODING_AGENT_DIR is set
|
|
107
|
+
Local config path: <repo>/.pi/extensions/pi-smart-voice-notify/config.json
|
|
102
108
|
```
|
|
103
109
|
|
|
104
110
|
A starter template is provided in `config/config.example.json`. On startup, the extension creates `config.json` with defaults if missing.
|
|
@@ -302,4 +308,4 @@ npm run check # build + test
|
|
|
302
308
|
|
|
303
309
|
## License
|
|
304
310
|
|
|
305
|
-
MIT
|
|
311
|
+
[MIT](LICENSE)
|
package/package.json
CHANGED
|
@@ -1,74 +1,81 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-smart-voice-notify",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Windows-optimized smart voice, sound, and desktop notifications for Pi coding agent.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./index.ts"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"index.ts",
|
|
12
|
-
"src",
|
|
13
|
-
"config/config.example.json",
|
|
14
|
-
"assets",
|
|
15
|
-
"README.md",
|
|
16
|
-
"CHANGELOG.md",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "npx --yes -p typescript@5.7.3 -p @types/node@20.17.57 tsc -p tsconfig.json --noEmit",
|
|
21
|
-
"lint": "npm run build",
|
|
22
|
-
"test": "node --experimental-strip-types --test test/abortable-command.test.ts test/reminder-playback.test.ts test/permission-forwarding-watcher.test.ts test/sound-theme.test.ts test/webhook.test.ts test/linux.test.ts test/index.test.ts test/tts.test.ts",
|
|
23
|
-
"check": "npm run build && npm run test"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"pi",
|
|
28
|
-
"pi
|
|
29
|
-
"pi-
|
|
30
|
-
"coding-agent",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"@earendil-works/pi-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-smart-voice-notify",
|
|
3
|
+
"version": "0.5.4",
|
|
4
|
+
"description": "Windows-optimized smart voice, sound, and desktop notifications for Pi coding agent.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.ts",
|
|
12
|
+
"src",
|
|
13
|
+
"config/config.example.json",
|
|
14
|
+
"assets",
|
|
15
|
+
"README.md",
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "npx --yes -p typescript@5.7.3 -p @types/node@20.17.57 tsc -p tsconfig.json --noEmit",
|
|
21
|
+
"lint": "npm run build",
|
|
22
|
+
"test": "node --experimental-strip-types --test test/config-store.test.ts test/config-store-no-global.test.ts test/config-store-env-override.test.ts test/abortable-command.test.ts test/reminder-playback.test.ts test/permission-forwarding-watcher.test.ts test/sound-theme.test.ts test/webhook.test.ts test/linux.test.ts test/index.test.ts test/tts.test.ts",
|
|
23
|
+
"check": "npm run build && npm run test",
|
|
24
|
+
"postinstall": "node -e \"const fs=require('fs'),cp=require('child_process'),p=require('path');const cwd=process.cwd();const normalized=cwd.split(p.sep).join('/');if(!normalized.includes('/.pi/agent/extensions/'))process.exit(0);const s=p.resolve(cwd,'../../scripts/patch-vulnerable-deps.mjs');if(!fs.existsSync(s))process.exit(0);const r=cp.spawnSync(process.execPath,[s,'--target',cwd,'--quiet'],{stdio:'inherit'});process.exit(r.status||0)\""
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"pi-package",
|
|
28
|
+
"pi",
|
|
29
|
+
"pi-extension",
|
|
30
|
+
"pi-coding-agent",
|
|
31
|
+
"coding-agent",
|
|
32
|
+
"voice-notify",
|
|
33
|
+
"desktop-notification",
|
|
34
|
+
"notifications",
|
|
35
|
+
"voice",
|
|
36
|
+
"audio",
|
|
37
|
+
"text-to-speech",
|
|
38
|
+
"tts",
|
|
39
|
+
"windows",
|
|
40
|
+
"linux",
|
|
41
|
+
"macos"
|
|
42
|
+
],
|
|
43
|
+
"author": "MasuRii",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/MasuRii/pi-smart-voice-notify.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/MasuRii/pi-smart-voice-notify#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/MasuRii/pi-smart-voice-notify/issues"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=24"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"pi": {
|
|
60
|
+
"extensions": [
|
|
61
|
+
"./index.ts"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0 || ^0.79.0",
|
|
66
|
+
"@earendil-works/pi-tui": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0 || ^0.79.0"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"node-notifier": "^10.0.1",
|
|
70
|
+
"undici": "^8.5.0"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/node": "25.9.3",
|
|
74
|
+
"@earendil-works/pi-coding-agent": "^0.79.7"
|
|
75
|
+
},
|
|
76
|
+
"overrides": {
|
|
77
|
+
"protobufjs": "7.6.3",
|
|
78
|
+
"ws": "8.21.0",
|
|
79
|
+
"uuid": "11.1.1"
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/abortable-command.ts
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
|
|
4
|
+
const ALLOWED_ABORTABLE_COMMANDS = new Set([
|
|
5
|
+
"aplay",
|
|
6
|
+
"edge-tts",
|
|
7
|
+
"espeak-ng",
|
|
8
|
+
"ffplay",
|
|
9
|
+
"gdbus",
|
|
10
|
+
"paplay",
|
|
11
|
+
"powershell",
|
|
12
|
+
"powershell.exe",
|
|
13
|
+
"swaymsg",
|
|
14
|
+
"where",
|
|
15
|
+
"which",
|
|
16
|
+
"xdotool",
|
|
17
|
+
"xprop",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
function normalizeCommandName(command: string): string {
|
|
21
|
+
return basename(command).trim().toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isAllowedAbortableCommand(command: string): boolean {
|
|
25
|
+
const normalized = normalizeCommandName(command);
|
|
26
|
+
const nodeExecutable = normalizeCommandName(process.execPath);
|
|
27
|
+
return normalized === nodeExecutable || ALLOWED_ABORTABLE_COMMANDS.has(normalized);
|
|
28
|
+
}
|
|
2
29
|
|
|
3
30
|
export interface AbortableCommandOptions {
|
|
4
31
|
timeoutMs?: number;
|
|
@@ -55,6 +82,9 @@ export async function runAbortableCommand(
|
|
|
55
82
|
if (!Array.isArray(args)) {
|
|
56
83
|
throw new Error("runAbortableCommand: args must be an array of strings");
|
|
57
84
|
}
|
|
85
|
+
if (!isAllowedAbortableCommand(normalizedCommand)) {
|
|
86
|
+
throw new Error(`runAbortableCommand: command is not allowlisted: ${normalizedCommand}`);
|
|
87
|
+
}
|
|
58
88
|
|
|
59
89
|
const commandLabel = buildCommandString(normalizedCommand, args);
|
|
60
90
|
if (options.signal?.aborted) {
|
|
@@ -69,7 +99,7 @@ export async function runAbortableCommand(
|
|
|
69
99
|
}
|
|
70
100
|
|
|
71
101
|
return await new Promise<AbortableCommandResult>((resolve) => {
|
|
72
|
-
const child = spawn(normalizedCommand, [...args], {
|
|
102
|
+
const child = spawn(normalizedCommand, [...args], { // nosemgrep: javascript.lang.security.detect-child-process.detect-child-process -- normalizedCommand is checked against ALLOWED_ABORTABLE_COMMANDS (plus the current Node executable for tests) before spawn; args are passed as an array with shell disabled.
|
|
73
103
|
env: options.env ?? process.env,
|
|
74
104
|
cwd: options.cwd,
|
|
75
105
|
});
|
package/src/config-store.ts
CHANGED
|
@@ -16,6 +16,11 @@ export const EXTENSION_ID = "pi-smart-voice-notify";
|
|
|
16
16
|
export const STATUS_KEY = "smart-voice-notify";
|
|
17
17
|
export const CONFIG_DIR = join(resolvePiAgentDir(), "extensions", EXTENSION_ID);
|
|
18
18
|
export const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
19
|
+
|
|
20
|
+
/** Project-local override config: <projectRoot>/.pi/extensions/<id>/config.json (read-only). */
|
|
21
|
+
export function resolveProjectConfigPath(projectRoot: string): string {
|
|
22
|
+
return join(projectRoot, ".pi", "extensions", EXTENSION_ID, "config.json");
|
|
23
|
+
}
|
|
19
24
|
export const DEBUG_DIR = join(CONFIG_DIR, "debug");
|
|
20
25
|
export const DEBUG_LOG_PATH = join(DEBUG_DIR, `${EXTENSION_ID}.log`);
|
|
21
26
|
|
|
@@ -979,28 +984,74 @@ export function ensureDebugDirectory(): void {
|
|
|
979
984
|
}
|
|
980
985
|
}
|
|
981
986
|
|
|
982
|
-
|
|
987
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
988
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/** Deep-merge `override` onto `base`. Nested objects merge; arrays and scalars replace. */
|
|
992
|
+
export function deepMergeConfigRecords(
|
|
993
|
+
base: Record<string, unknown>,
|
|
994
|
+
override: Record<string, unknown>,
|
|
995
|
+
): Record<string, unknown> {
|
|
996
|
+
const result: Record<string, unknown> = { ...base };
|
|
997
|
+
for (const [key, value] of Object.entries(override)) {
|
|
998
|
+
const existing = result[key];
|
|
999
|
+
result[key] = isPlainObject(existing) && isPlainObject(value)
|
|
1000
|
+
? deepMergeConfigRecords(existing, value)
|
|
1001
|
+
: value;
|
|
1002
|
+
}
|
|
1003
|
+
return result;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
function readConfigRecord(path: string): Record<string, unknown> | null {
|
|
1007
|
+
if (!existsSync(path)) {
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
return toRecord(JSON.parse(readFileSync(path, "utf-8")) as unknown);
|
|
1012
|
+
} catch {
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/** Load and self-heal the global config file, returning its raw record. */
|
|
1018
|
+
function loadGlobalConfigRecord(): Record<string, unknown> {
|
|
983
1019
|
ensureConfigDirectory();
|
|
1020
|
+
const defaultsSerialized = `${JSON.stringify(DEFAULT_CONFIG, null, 2)}\n`;
|
|
984
1021
|
if (!existsSync(CONFIG_PATH)) {
|
|
985
|
-
writeFileSync(CONFIG_PATH,
|
|
986
|
-
return
|
|
1022
|
+
writeFileSync(CONFIG_PATH, defaultsSerialized, "utf-8");
|
|
1023
|
+
return toRecord(JSON.parse(defaultsSerialized));
|
|
987
1024
|
}
|
|
988
1025
|
|
|
989
1026
|
try {
|
|
990
1027
|
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
991
1028
|
const parsed = JSON.parse(raw) as unknown;
|
|
992
|
-
const
|
|
993
|
-
const validation = validateConfig(normalized);
|
|
994
|
-
const serialized = `${JSON.stringify(validation.config, null, 2)}\n`;
|
|
1029
|
+
const serialized = `${JSON.stringify(validateConfig(normalizeConfig(parsed)).config, null, 2)}\n`;
|
|
995
1030
|
if (raw !== serialized) {
|
|
996
1031
|
writeFileSync(CONFIG_PATH, serialized, "utf-8");
|
|
997
1032
|
}
|
|
998
|
-
|
|
999
|
-
return validateConfig(runtimeConfig).config;
|
|
1033
|
+
return toRecord(parsed);
|
|
1000
1034
|
} catch {
|
|
1001
|
-
writeFileSync(CONFIG_PATH,
|
|
1002
|
-
return
|
|
1035
|
+
writeFileSync(CONFIG_PATH, defaultsSerialized, "utf-8");
|
|
1036
|
+
return toRecord(JSON.parse(defaultsSerialized));
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Read the effective config. When `projectRoot` is given and a project config
|
|
1042
|
+
* exists, it deep-merges over the global config; environment variables still
|
|
1043
|
+
* override both. The project file is read-only — only the global file is healed.
|
|
1044
|
+
*/
|
|
1045
|
+
export function readConfigFromDisk(projectRoot?: string): VoiceNotifyConfig {
|
|
1046
|
+
let record = loadGlobalConfigRecord();
|
|
1047
|
+
if (projectRoot) {
|
|
1048
|
+
const projectRecord = readConfigRecord(resolveProjectConfigPath(projectRoot));
|
|
1049
|
+
if (projectRecord) {
|
|
1050
|
+
record = deepMergeConfigRecords(record, projectRecord);
|
|
1051
|
+
}
|
|
1003
1052
|
}
|
|
1053
|
+
const runtimeConfig = applyEnvironmentOverrides(validateConfig(normalizeConfig(record)).config);
|
|
1054
|
+
return validateConfig(runtimeConfig).config;
|
|
1004
1055
|
}
|
|
1005
1056
|
|
|
1006
1057
|
export function writeConfigToDisk(config: VoiceNotifyConfig): void {
|
package/src/index.ts
CHANGED
|
@@ -1814,7 +1814,7 @@ export default function smartVoiceNotifyExtension(
|
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
1816
|
if (subcommand === "reload") {
|
|
1817
|
-
config = readConfig();
|
|
1817
|
+
config = readConfig(ctx.cwd);
|
|
1818
1818
|
refreshIntegratedServiceConfig();
|
|
1819
1819
|
await syncPermissionForwardingWatcher();
|
|
1820
1820
|
refreshQuestionToolAvailability();
|
|
@@ -1880,7 +1880,7 @@ export default function smartVoiceNotifyExtension(
|
|
|
1880
1880
|
shutdownRequested = false;
|
|
1881
1881
|
shutdownPromise = null;
|
|
1882
1882
|
cancelPendingAgentErrorNotification("session_start");
|
|
1883
|
-
config = readConfig();
|
|
1883
|
+
config = readConfig(ctx.cwd);
|
|
1884
1884
|
refreshIntegratedServiceConfig();
|
|
1885
1885
|
activeSessionContext = ctx;
|
|
1886
1886
|
await syncPermissionForwardingWatcher();
|
package/src/linux.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
const DEFAULT_TIMEOUT_MS = 8_000;
|
|
12
12
|
const DEFAULT_AUDIO_TIMEOUT_MS = 20_000;
|
|
13
13
|
type DebugLog = (message: string) => void;
|
|
14
|
+
type LinuxCommandName = "xset" | "gdbus" | "pactl" | "amixer" | "paplay" | "aplay" | "xprintidle";
|
|
14
15
|
|
|
15
16
|
function createDebugLog(options?: LinuxUtilsOptions): DebugLog {
|
|
16
17
|
return options?.debugLog ?? (() => {});
|
|
@@ -23,13 +24,32 @@ function buildCommandString(command: string, args: string[]): string {
|
|
|
23
24
|
return `${command} ${args.join(" ")}`;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
function spawnLinuxCommand(command: LinuxCommandName, args: string[]) {
|
|
28
|
+
switch (command) {
|
|
29
|
+
case "xset":
|
|
30
|
+
return spawn("xset", args, { env: process.env });
|
|
31
|
+
case "gdbus":
|
|
32
|
+
return spawn("gdbus", args, { env: process.env });
|
|
33
|
+
case "pactl":
|
|
34
|
+
return spawn("pactl", args, { env: process.env });
|
|
35
|
+
case "amixer":
|
|
36
|
+
return spawn("amixer", args, { env: process.env });
|
|
37
|
+
case "paplay":
|
|
38
|
+
return spawn("paplay", args, { env: process.env });
|
|
39
|
+
case "aplay":
|
|
40
|
+
return spawn("aplay", args, { env: process.env });
|
|
41
|
+
case "xprintidle":
|
|
42
|
+
return spawn("xprintidle", args, { env: process.env });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
26
46
|
async function runSpawnCommand(
|
|
27
|
-
command:
|
|
47
|
+
command: LinuxCommandName,
|
|
28
48
|
args: string[],
|
|
29
49
|
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
30
50
|
): Promise<LinuxCommandResult> {
|
|
31
51
|
return await new Promise<LinuxCommandResult>((resolve) => {
|
|
32
|
-
const child =
|
|
52
|
+
const child = spawnLinuxCommand(command, args);
|
|
33
53
|
const fullCommand = buildCommandString(command, args);
|
|
34
54
|
let stdout = "";
|
|
35
55
|
let stderr = "";
|
|
@@ -139,7 +159,7 @@ export async function wakeMonitor(options: LinuxUtilsOptions = {}): Promise<bool
|
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
const session = detectLinuxSession();
|
|
142
|
-
const wakeCommands = [
|
|
162
|
+
const wakeCommands: Array<{ name: string; command: LinuxCommandName; args: string[] }> = [
|
|
143
163
|
{
|
|
144
164
|
name: "xset",
|
|
145
165
|
command: "xset",
|