@nocville/npc 0.0.0-stage → 0.2.0
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/README.md +243 -2
- package/dist/cjs/cli.js +533 -0
- package/dist/cjs/core/api-key.js +69 -0
- package/dist/cjs/core/base-npc.js +160 -0
- package/dist/cjs/core/config.js +108 -0
- package/dist/cjs/core/event-npc.js +14 -0
- package/dist/cjs/core/logger.js +39 -0
- package/dist/cjs/core/polling-npc.js +65 -0
- package/dist/cjs/core/screen.js +28 -0
- package/dist/cjs/core/text.js +15 -0
- package/dist/cjs/core/thresholds.js +48 -0
- package/dist/cjs/core/types.js +10 -0
- package/dist/cjs/core/user-config.js +92 -0
- package/dist/cjs/doctor.js +130 -0
- package/dist/cjs/index.js +90 -0
- package/dist/cjs/npcs/agent-common/activity.js +291 -0
- package/dist/cjs/npcs/agent-common/git-stats.js +71 -0
- package/dist/cjs/npcs/agent-common/hook-runner.js +252 -0
- package/dist/cjs/npcs/agent-common/hook-settings.js +279 -0
- package/dist/cjs/npcs/agent-common/liveness.js +112 -0
- package/dist/cjs/npcs/agent-common/lock.js +99 -0
- package/dist/cjs/npcs/agent-common/runtime.js +154 -0
- package/dist/cjs/npcs/agent-common/session.js +390 -0
- package/dist/cjs/npcs/agent-common/shim.js +96 -0
- package/dist/cjs/npcs/agent-common/watchdog.js +149 -0
- package/dist/cjs/npcs/claude-code/defaults.js +20 -0
- package/dist/cjs/npcs/claude-code/hook-handler.js +139 -0
- package/dist/cjs/npcs/claude-code/index.js +104 -0
- package/dist/cjs/npcs/claude-code/setup.js +133 -0
- package/dist/cjs/npcs/claude-code/state-machine.js +130 -0
- package/dist/cjs/npcs/codex/defaults.js +32 -0
- package/dist/cjs/npcs/codex/hook-handler.js +116 -0
- package/dist/cjs/npcs/codex/index.js +92 -0
- package/dist/cjs/npcs/codex/rollout.js +246 -0
- package/dist/cjs/npcs/codex/setup.js +104 -0
- package/dist/cjs/npcs/codex/watcher.js +346 -0
- package/dist/cjs/npcs/cursor/defaults.js +15 -0
- package/dist/cjs/npcs/cursor/hook-handler.js +65 -0
- package/dist/cjs/npcs/cursor/index.js +72 -0
- package/dist/cjs/npcs/cursor/normalize.js +54 -0
- package/dist/cjs/npcs/cursor/setup.js +98 -0
- package/dist/cjs/npcs/gemini/defaults.js +15 -0
- package/dist/cjs/npcs/gemini/hook-handler.js +93 -0
- package/dist/cjs/npcs/gemini/index.js +69 -0
- package/dist/cjs/npcs/gemini/setup.js +98 -0
- package/dist/cjs/npcs/github-watcher/defaults.js +11 -0
- package/dist/cjs/npcs/github-watcher/format.js +21 -0
- package/dist/cjs/npcs/github-watcher/github-api.js +126 -0
- package/dist/cjs/npcs/github-watcher/index.js +148 -0
- package/dist/cjs/npcs/internet-connectivity/checks.js +92 -0
- package/dist/cjs/npcs/internet-connectivity/defaults.js +22 -0
- package/dist/cjs/npcs/internet-connectivity/index.js +251 -0
- package/dist/cjs/npcs/log-watcher/buffer.js +40 -0
- package/dist/cjs/npcs/log-watcher/defaults.js +12 -0
- package/dist/cjs/npcs/log-watcher/index.js +161 -0
- package/dist/cjs/npcs/log-watcher/tail.js +81 -0
- package/dist/cjs/npcs/process-watcher/defaults.js +9 -0
- package/dist/cjs/npcs/process-watcher/index.js +140 -0
- package/dist/cjs/npcs/process-watcher/process-scanner.js +114 -0
- package/dist/cjs/npcs/receptionist/defaults.js +9 -0
- package/dist/cjs/npcs/receptionist/index.js +120 -0
- package/dist/cjs/npcs/receptionist/weather.js +129 -0
- package/dist/cjs/npcs/system-monitor/collectors.js +68 -0
- package/dist/cjs/npcs/system-monitor/defaults.js +13 -0
- package/dist/cjs/npcs/system-monitor/index.js +105 -0
- package/dist/cjs/npcs/web-page-watcher/basic-mode.js +58 -0
- package/dist/cjs/npcs/web-page-watcher/capture.js +80 -0
- package/dist/cjs/npcs/web-page-watcher/defaults.js +31 -0
- package/dist/cjs/npcs/web-page-watcher/index.js +234 -0
- package/dist/cjs/npcs/web-page-watcher/pixelate.js +181 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +498 -0
- package/dist/core/api-key.d.ts +34 -0
- package/dist/core/api-key.js +64 -0
- package/dist/core/base-npc.d.ts +41 -0
- package/dist/core/base-npc.js +156 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.js +101 -0
- package/dist/core/event-npc.d.ts +8 -0
- package/dist/core/event-npc.js +10 -0
- package/dist/core/logger.d.ts +11 -0
- package/dist/core/logger.js +35 -0
- package/dist/core/polling-npc.d.ts +18 -0
- package/dist/core/polling-npc.js +61 -0
- package/dist/core/screen.d.ts +11 -0
- package/dist/core/screen.js +24 -0
- package/dist/core/text.d.ts +6 -0
- package/dist/core/text.js +12 -0
- package/dist/core/thresholds.d.ts +10 -0
- package/dist/core/thresholds.js +44 -0
- package/dist/core/types.d.ts +60 -0
- package/dist/core/types.js +7 -0
- package/dist/core/user-config.d.ts +43 -0
- package/dist/core/user-config.js +85 -0
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.js +126 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +25 -0
- package/dist/npcs/agent-common/activity.d.ts +42 -0
- package/dist/npcs/agent-common/activity.js +280 -0
- package/dist/npcs/agent-common/git-stats.d.ts +11 -0
- package/dist/npcs/agent-common/git-stats.js +67 -0
- package/dist/npcs/agent-common/hook-runner.d.ts +62 -0
- package/dist/npcs/agent-common/hook-runner.js +245 -0
- package/dist/npcs/agent-common/hook-settings.d.ts +75 -0
- package/dist/npcs/agent-common/hook-settings.js +265 -0
- package/dist/npcs/agent-common/liveness.d.ts +12 -0
- package/dist/npcs/agent-common/liveness.js +105 -0
- package/dist/npcs/agent-common/lock.d.ts +6 -0
- package/dist/npcs/agent-common/lock.js +95 -0
- package/dist/npcs/agent-common/runtime.d.ts +16 -0
- package/dist/npcs/agent-common/runtime.js +149 -0
- package/dist/npcs/agent-common/session.d.ts +184 -0
- package/dist/npcs/agent-common/session.js +368 -0
- package/dist/npcs/agent-common/shim.d.ts +4 -0
- package/dist/npcs/agent-common/shim.js +90 -0
- package/dist/npcs/agent-common/watchdog.d.ts +16 -0
- package/dist/npcs/agent-common/watchdog.js +144 -0
- package/dist/npcs/claude-code/defaults.d.ts +15 -0
- package/dist/npcs/claude-code/defaults.js +17 -0
- package/dist/npcs/claude-code/hook-handler.d.ts +40 -0
- package/dist/npcs/claude-code/hook-handler.js +131 -0
- package/dist/npcs/claude-code/index.d.ts +36 -0
- package/dist/npcs/claude-code/index.js +92 -0
- package/dist/npcs/claude-code/setup.d.ts +58 -0
- package/dist/npcs/claude-code/setup.js +121 -0
- package/dist/npcs/claude-code/state-machine.d.ts +28 -0
- package/dist/npcs/claude-code/state-machine.js +125 -0
- package/dist/npcs/codex/defaults.d.ts +24 -0
- package/dist/npcs/codex/defaults.js +28 -0
- package/dist/npcs/codex/hook-handler.d.ts +24 -0
- package/dist/npcs/codex/hook-handler.js +110 -0
- package/dist/npcs/codex/index.d.ts +21 -0
- package/dist/npcs/codex/index.js +76 -0
- package/dist/npcs/codex/rollout.d.ts +39 -0
- package/dist/npcs/codex/rollout.js +242 -0
- package/dist/npcs/codex/setup.d.ts +37 -0
- package/dist/npcs/codex/setup.js +96 -0
- package/dist/npcs/codex/watcher.d.ts +62 -0
- package/dist/npcs/codex/watcher.js +341 -0
- package/dist/npcs/cursor/defaults.d.ts +9 -0
- package/dist/npcs/cursor/defaults.js +11 -0
- package/dist/npcs/cursor/hook-handler.d.ts +8 -0
- package/dist/npcs/cursor/hook-handler.js +60 -0
- package/dist/npcs/cursor/index.d.ts +18 -0
- package/dist/npcs/cursor/index.js +57 -0
- package/dist/npcs/cursor/normalize.d.ts +6 -0
- package/dist/npcs/cursor/normalize.js +49 -0
- package/dist/npcs/cursor/setup.d.ts +29 -0
- package/dist/npcs/cursor/setup.js +90 -0
- package/dist/npcs/gemini/defaults.d.ts +9 -0
- package/dist/npcs/gemini/defaults.js +11 -0
- package/dist/npcs/gemini/hook-handler.d.ts +10 -0
- package/dist/npcs/gemini/hook-handler.js +87 -0
- package/dist/npcs/gemini/index.d.ts +17 -0
- package/dist/npcs/gemini/index.js +56 -0
- package/dist/npcs/gemini/setup.d.ts +29 -0
- package/dist/npcs/gemini/setup.js +90 -0
- package/dist/npcs/github-watcher/defaults.d.ts +8 -0
- package/dist/npcs/github-watcher/defaults.js +8 -0
- package/dist/npcs/github-watcher/format.d.ts +3 -0
- package/dist/npcs/github-watcher/format.js +18 -0
- package/dist/npcs/github-watcher/github-api.d.ts +55 -0
- package/dist/npcs/github-watcher/github-api.js +120 -0
- package/dist/npcs/github-watcher/index.d.ts +35 -0
- package/dist/npcs/github-watcher/index.js +144 -0
- package/dist/npcs/internet-connectivity/checks.d.ts +24 -0
- package/dist/npcs/internet-connectivity/checks.js +84 -0
- package/dist/npcs/internet-connectivity/defaults.d.ts +20 -0
- package/dist/npcs/internet-connectivity/defaults.js +19 -0
- package/dist/npcs/internet-connectivity/index.d.ts +55 -0
- package/dist/npcs/internet-connectivity/index.js +246 -0
- package/dist/npcs/log-watcher/buffer.d.ts +18 -0
- package/dist/npcs/log-watcher/buffer.js +34 -0
- package/dist/npcs/log-watcher/defaults.d.ts +9 -0
- package/dist/npcs/log-watcher/defaults.js +9 -0
- package/dist/npcs/log-watcher/index.d.ts +45 -0
- package/dist/npcs/log-watcher/index.js +157 -0
- package/dist/npcs/log-watcher/tail.d.ts +9 -0
- package/dist/npcs/log-watcher/tail.js +78 -0
- package/dist/npcs/process-watcher/defaults.d.ts +6 -0
- package/dist/npcs/process-watcher/defaults.js +6 -0
- package/dist/npcs/process-watcher/index.d.ts +26 -0
- package/dist/npcs/process-watcher/index.js +136 -0
- package/dist/npcs/process-watcher/process-scanner.d.ts +19 -0
- package/dist/npcs/process-watcher/process-scanner.js +110 -0
- package/dist/npcs/receptionist/defaults.d.ts +6 -0
- package/dist/npcs/receptionist/defaults.js +6 -0
- package/dist/npcs/receptionist/index.d.ts +29 -0
- package/dist/npcs/receptionist/index.js +116 -0
- package/dist/npcs/receptionist/weather.d.ts +37 -0
- package/dist/npcs/receptionist/weather.js +121 -0
- package/dist/npcs/system-monitor/collectors.d.ts +45 -0
- package/dist/npcs/system-monitor/collectors.js +60 -0
- package/dist/npcs/system-monitor/defaults.d.ts +7 -0
- package/dist/npcs/system-monitor/defaults.js +10 -0
- package/dist/npcs/system-monitor/index.d.ts +27 -0
- package/dist/npcs/system-monitor/index.js +101 -0
- package/dist/npcs/web-page-watcher/basic-mode.d.ts +16 -0
- package/dist/npcs/web-page-watcher/basic-mode.js +52 -0
- package/dist/npcs/web-page-watcher/capture.d.ts +49 -0
- package/dist/npcs/web-page-watcher/capture.js +75 -0
- package/dist/npcs/web-page-watcher/defaults.d.ts +19 -0
- package/dist/npcs/web-page-watcher/defaults.js +27 -0
- package/dist/npcs/web-page-watcher/index.d.ts +42 -0
- package/dist/npcs/web-page-watcher/index.js +230 -0
- package/dist/npcs/web-page-watcher/pixelate.d.ts +36 -0
- package/dist/npcs/web-page-watcher/pixelate.js +172 -0
- package/package.json +73 -3
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { PollingNPC } from '../../core/polling-npc.js';
|
|
2
|
+
import { DEFAULTS } from './defaults.js';
|
|
3
|
+
import { fetchWeather, geocodeLocation, autoGeo, formatClock, toFahrenheit } from './weather.js';
|
|
4
|
+
export class ReceptionistNPC extends PollingNPC {
|
|
5
|
+
explicitCoords;
|
|
6
|
+
location;
|
|
7
|
+
fahrenheit;
|
|
8
|
+
coords = null;
|
|
9
|
+
geoAttempted = false;
|
|
10
|
+
weather = null;
|
|
11
|
+
lastWeatherFetch = 0;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super({ ...config, pollInterval: config.pollInterval ?? DEFAULTS.pollInterval });
|
|
14
|
+
this.explicitCoords =
|
|
15
|
+
config.lat !== undefined && config.lon !== undefined
|
|
16
|
+
? { lat: config.lat, lon: config.lon }
|
|
17
|
+
: null;
|
|
18
|
+
this.location = config.location;
|
|
19
|
+
this.fahrenheit = config.fahrenheit ?? false;
|
|
20
|
+
}
|
|
21
|
+
get name() {
|
|
22
|
+
return 'receptionist';
|
|
23
|
+
}
|
|
24
|
+
get defaultDisplayName() {
|
|
25
|
+
return 'Reception';
|
|
26
|
+
}
|
|
27
|
+
get archetype() {
|
|
28
|
+
return 'custom';
|
|
29
|
+
}
|
|
30
|
+
get behavior() {
|
|
31
|
+
return {
|
|
32
|
+
greetPlayers: true,
|
|
33
|
+
patrol: { everyMinutes: [15, 30], stops: 5 },
|
|
34
|
+
idle: 'stay',
|
|
35
|
+
home: { near: 'entrance' },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
get companion() {
|
|
39
|
+
return {
|
|
40
|
+
screenType: 'welcome-sign',
|
|
41
|
+
size: { w: 2, h: 1 },
|
|
42
|
+
placement: 'adjacent-wall',
|
|
43
|
+
label: 'Welcome',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async collect() {
|
|
47
|
+
await this.refreshWeather();
|
|
48
|
+
const now = new Date();
|
|
49
|
+
const { day, date, time } = formatClock(now);
|
|
50
|
+
const values = [
|
|
51
|
+
{ label: 'time', value: time },
|
|
52
|
+
{ label: 'day', value: day },
|
|
53
|
+
{ label: 'date', value: date },
|
|
54
|
+
];
|
|
55
|
+
let message = `${day} ${time}`;
|
|
56
|
+
const metrics = { weather_ok: this.weather ? 1 : 0 };
|
|
57
|
+
if (this.weather) {
|
|
58
|
+
const temp = this.fahrenheit
|
|
59
|
+
? `${toFahrenheit(this.weather.tempC)}°F`
|
|
60
|
+
: `${this.weather.tempC}°C`;
|
|
61
|
+
message += ` • ${temp} ${this.weather.text}`;
|
|
62
|
+
values.push({ label: 'temp', value: temp }, { label: 'condition', value: this.weather.text }, { label: 'icon', value: this.weather.icon });
|
|
63
|
+
metrics['temp_c'] = this.weather.tempC;
|
|
64
|
+
metrics['weather_code'] = this.weather.code;
|
|
65
|
+
metrics['wind_kph'] = this.weather.windKph;
|
|
66
|
+
}
|
|
67
|
+
// The receptionist is a greeter/clock — it stays healthy even when weather
|
|
68
|
+
// is unavailable (degraded time-only mode).
|
|
69
|
+
return {
|
|
70
|
+
status: 'healthy',
|
|
71
|
+
mood: 'happy',
|
|
72
|
+
message,
|
|
73
|
+
screenData: { layout: 'welcome-sign', values },
|
|
74
|
+
metrics,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async refreshWeather() {
|
|
78
|
+
if (!this.coords) {
|
|
79
|
+
await this.resolveCoords();
|
|
80
|
+
}
|
|
81
|
+
if (!this.coords)
|
|
82
|
+
return;
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
if (this.weather && now - this.lastWeatherFetch < DEFAULTS.weatherRefreshMs)
|
|
85
|
+
return;
|
|
86
|
+
const w = await fetchWeather(this.coords, DEFAULTS.fetchTimeoutMs);
|
|
87
|
+
if (w) {
|
|
88
|
+
this.weather = w;
|
|
89
|
+
this.lastWeatherFetch = now;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async resolveCoords() {
|
|
93
|
+
if (this.explicitCoords) {
|
|
94
|
+
this.coords = this.explicitCoords;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Only attempt geocoding/geo-IP once per (failed) resolution to avoid
|
|
98
|
+
// hammering the keyless endpoints every poll.
|
|
99
|
+
if (this.geoAttempted)
|
|
100
|
+
return;
|
|
101
|
+
this.geoAttempted = true;
|
|
102
|
+
if (this.location) {
|
|
103
|
+
this.coords = await geocodeLocation(this.location, DEFAULTS.fetchTimeoutMs);
|
|
104
|
+
if (this.coords)
|
|
105
|
+
return;
|
|
106
|
+
this.logger.warn(`Could not geocode "${this.location}", falling back to IP geo`);
|
|
107
|
+
}
|
|
108
|
+
this.coords = await autoGeo(DEFAULTS.fetchTimeoutMs);
|
|
109
|
+
if (!this.coords) {
|
|
110
|
+
this.logger.warn('Weather geo unavailable — running in time-only mode');
|
|
111
|
+
// Allow a later retry.
|
|
112
|
+
this.geoAttempted = false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyless weather + geolocation via open-meteo, with ipapi.co IP fallback.
|
|
3
|
+
* All network helpers return null on failure so the receptionist can degrade
|
|
4
|
+
* to a time-only mode without erroring.
|
|
5
|
+
*/
|
|
6
|
+
export interface Coords {
|
|
7
|
+
lat: number;
|
|
8
|
+
lon: number;
|
|
9
|
+
label?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Weather {
|
|
12
|
+
tempC: number;
|
|
13
|
+
code: number;
|
|
14
|
+
text: string;
|
|
15
|
+
icon: string;
|
|
16
|
+
windKph: number;
|
|
17
|
+
}
|
|
18
|
+
/** Map a WMO weather code to display text + a renderer glyph keyword. */
|
|
19
|
+
export declare function describeWmo(code: number): {
|
|
20
|
+
text: string;
|
|
21
|
+
icon: string;
|
|
22
|
+
};
|
|
23
|
+
/** Resolve a place name to coordinates via the open-meteo geocoding API. */
|
|
24
|
+
export declare function geocodeLocation(name: string, timeoutMs?: number): Promise<Coords | null>;
|
|
25
|
+
/** Best-effort IP geolocation via ipapi.co (keyless). */
|
|
26
|
+
export declare function autoGeo(timeoutMs?: number): Promise<Coords | null>;
|
|
27
|
+
/** Fetch current temperature, weather code, and wind for coordinates. */
|
|
28
|
+
export declare function fetchWeather(coords: Coords, timeoutMs?: number): Promise<Weather | null>;
|
|
29
|
+
/** Convert Celsius to Fahrenheit, rounded. */
|
|
30
|
+
export declare function toFahrenheit(c: number): number;
|
|
31
|
+
/** Format a Date into day/date/time parts for the welcome sign. */
|
|
32
|
+
export declare function formatClock(d: Date): {
|
|
33
|
+
day: string;
|
|
34
|
+
date: string;
|
|
35
|
+
time: string;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=weather.d.ts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyless weather + geolocation via open-meteo, with ipapi.co IP fallback.
|
|
3
|
+
* All network helpers return null on failure so the receptionist can degrade
|
|
4
|
+
* to a time-only mode without erroring.
|
|
5
|
+
*/
|
|
6
|
+
// WMO weather-interpretation codes → human text + a glyph keyword the
|
|
7
|
+
// welcome-sign renderer understands (matched by /sun|clear|partly|rain|snow|storm|fog/).
|
|
8
|
+
const WMO = {
|
|
9
|
+
0: { text: 'Clear', icon: 'clear' },
|
|
10
|
+
1: { text: 'Mainly clear', icon: 'partly' },
|
|
11
|
+
2: { text: 'Partly cloudy', icon: 'partly' },
|
|
12
|
+
3: { text: 'Overcast', icon: 'cloud' },
|
|
13
|
+
45: { text: 'Fog', icon: 'fog' },
|
|
14
|
+
48: { text: 'Rime fog', icon: 'fog' },
|
|
15
|
+
51: { text: 'Light drizzle', icon: 'drizzle' },
|
|
16
|
+
53: { text: 'Drizzle', icon: 'drizzle' },
|
|
17
|
+
55: { text: 'Heavy drizzle', icon: 'drizzle' },
|
|
18
|
+
56: { text: 'Freezing drizzle', icon: 'drizzle' },
|
|
19
|
+
57: { text: 'Freezing drizzle', icon: 'drizzle' },
|
|
20
|
+
61: { text: 'Light rain', icon: 'rain' },
|
|
21
|
+
63: { text: 'Rain', icon: 'rain' },
|
|
22
|
+
65: { text: 'Heavy rain', icon: 'rain' },
|
|
23
|
+
66: { text: 'Freezing rain', icon: 'rain' },
|
|
24
|
+
67: { text: 'Freezing rain', icon: 'rain' },
|
|
25
|
+
71: { text: 'Light snow', icon: 'snow' },
|
|
26
|
+
73: { text: 'Snow', icon: 'snow' },
|
|
27
|
+
75: { text: 'Heavy snow', icon: 'snow' },
|
|
28
|
+
77: { text: 'Snow grains', icon: 'snow' },
|
|
29
|
+
80: { text: 'Rain showers', icon: 'shower' },
|
|
30
|
+
81: { text: 'Rain showers', icon: 'shower' },
|
|
31
|
+
82: { text: 'Violent showers', icon: 'shower' },
|
|
32
|
+
85: { text: 'Snow showers', icon: 'snow' },
|
|
33
|
+
86: { text: 'Snow showers', icon: 'snow' },
|
|
34
|
+
95: { text: 'Thunderstorm', icon: 'storm' },
|
|
35
|
+
96: { text: 'Thunderstorm', icon: 'storm' },
|
|
36
|
+
99: { text: 'Thunderstorm', icon: 'storm' },
|
|
37
|
+
};
|
|
38
|
+
/** Map a WMO weather code to display text + a renderer glyph keyword. */
|
|
39
|
+
export function describeWmo(code) {
|
|
40
|
+
return WMO[code] ?? { text: 'Unknown', icon: 'cloud' };
|
|
41
|
+
}
|
|
42
|
+
async function fetchJson(url, timeoutMs) {
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
45
|
+
try {
|
|
46
|
+
const res = await fetch(url, {
|
|
47
|
+
signal: controller.signal,
|
|
48
|
+
headers: { 'User-Agent': 'nocville-npc' },
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok)
|
|
51
|
+
return null;
|
|
52
|
+
return (await res.json());
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Resolve a place name to coordinates via the open-meteo geocoding API. */
|
|
62
|
+
export async function geocodeLocation(name, timeoutMs = 5000) {
|
|
63
|
+
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(name)}&count=1`;
|
|
64
|
+
const res = await fetchJson(url, timeoutMs);
|
|
65
|
+
const first = res?.['results']?.[0];
|
|
66
|
+
if (!first || typeof first['latitude'] !== 'number')
|
|
67
|
+
return null;
|
|
68
|
+
return {
|
|
69
|
+
lat: first['latitude'],
|
|
70
|
+
lon: first['longitude'],
|
|
71
|
+
label: first['name'] ?? name,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Best-effort IP geolocation via ipapi.co (keyless). */
|
|
75
|
+
export async function autoGeo(timeoutMs = 5000) {
|
|
76
|
+
const res = await fetchJson('https://ipapi.co/json/', timeoutMs);
|
|
77
|
+
if (!res || typeof res['latitude'] !== 'number')
|
|
78
|
+
return null;
|
|
79
|
+
return {
|
|
80
|
+
lat: res['latitude'],
|
|
81
|
+
lon: res['longitude'],
|
|
82
|
+
label: res['city'],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Fetch current temperature, weather code, and wind for coordinates. */
|
|
86
|
+
export async function fetchWeather(coords, timeoutMs = 5000) {
|
|
87
|
+
const url = `https://api.open-meteo.com/v1/forecast?latitude=${coords.lat}` +
|
|
88
|
+
`&longitude=${coords.lon}¤t=temperature_2m,weather_code,wind_speed_10m`;
|
|
89
|
+
const res = await fetchJson(url, timeoutMs);
|
|
90
|
+
const cur = res?.['current'];
|
|
91
|
+
if (!cur || typeof cur['temperature_2m'] !== 'number')
|
|
92
|
+
return null;
|
|
93
|
+
const code = Number(cur['weather_code'] ?? 0);
|
|
94
|
+
const { text, icon } = describeWmo(code);
|
|
95
|
+
return {
|
|
96
|
+
tempC: Math.round(cur['temperature_2m']),
|
|
97
|
+
code,
|
|
98
|
+
text,
|
|
99
|
+
icon,
|
|
100
|
+
windKph: Math.round(Number(cur['wind_speed_10m'] ?? 0)),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** Convert Celsius to Fahrenheit, rounded. */
|
|
104
|
+
export function toFahrenheit(c) {
|
|
105
|
+
return Math.round((c * 9) / 5 + 32);
|
|
106
|
+
}
|
|
107
|
+
const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
108
|
+
/** Format a Date into day/date/time parts for the welcome sign. */
|
|
109
|
+
export function formatClock(d) {
|
|
110
|
+
const day = DAYS[d.getDay()];
|
|
111
|
+
let h = d.getHours();
|
|
112
|
+
const m = d.getMinutes();
|
|
113
|
+
const ampm = h >= 12 ? 'PM' : 'AM';
|
|
114
|
+
h = h % 12;
|
|
115
|
+
if (h === 0)
|
|
116
|
+
h = 12;
|
|
117
|
+
const time = `${h}:${String(m).padStart(2, '0')} ${ampm}`;
|
|
118
|
+
const date = `${d.getMonth() + 1}/${d.getDate()}`;
|
|
119
|
+
return { day, date, time };
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=weather.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface CpuMetrics {
|
|
2
|
+
percent: number;
|
|
3
|
+
loadAvg1m: number;
|
|
4
|
+
}
|
|
5
|
+
export interface MemMetrics {
|
|
6
|
+
percent: number;
|
|
7
|
+
usedGb: number;
|
|
8
|
+
totalGb: number;
|
|
9
|
+
}
|
|
10
|
+
export interface DiskMetrics {
|
|
11
|
+
percent: number;
|
|
12
|
+
usedGb: number;
|
|
13
|
+
totalGb: number;
|
|
14
|
+
}
|
|
15
|
+
export interface CpuSampler {
|
|
16
|
+
/** Return CPU usage since the previous sample (or since boot on the first call). */
|
|
17
|
+
sample(): CpuMetrics;
|
|
18
|
+
}
|
|
19
|
+
interface CpuTimes {
|
|
20
|
+
user: number;
|
|
21
|
+
nice: number;
|
|
22
|
+
sys: number;
|
|
23
|
+
idle: number;
|
|
24
|
+
irq: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Stateful CPU sampler that computes usage from the delta between consecutive
|
|
28
|
+
* `os.cpus()` snapshots — no blocking sleep. The first sample reports usage
|
|
29
|
+
* since system boot; subsequent samples report usage since the previous call.
|
|
30
|
+
*
|
|
31
|
+
* `readCpus`/`readLoad` are injectable for testing.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createCpuSampler(readCpus?: () => Array<{
|
|
34
|
+
times: CpuTimes;
|
|
35
|
+
}>, readLoad?: () => number): CpuSampler;
|
|
36
|
+
/**
|
|
37
|
+
* Collect memory usage from OS.
|
|
38
|
+
*/
|
|
39
|
+
export declare function collectMemory(): MemMetrics;
|
|
40
|
+
/**
|
|
41
|
+
* Collect disk usage via fs.statfs (Node 18.15+).
|
|
42
|
+
*/
|
|
43
|
+
export declare function collectDisk(path: string): Promise<DiskMetrics>;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=collectors.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { promises as fsp } from 'node:fs';
|
|
3
|
+
function aggregate(cpus) {
|
|
4
|
+
let idle = 0;
|
|
5
|
+
let total = 0;
|
|
6
|
+
for (const cpu of cpus) {
|
|
7
|
+
const t = cpu.times;
|
|
8
|
+
idle += t.idle;
|
|
9
|
+
total += t.user + t.nice + t.sys + t.irq + t.idle;
|
|
10
|
+
}
|
|
11
|
+
return { idle, total };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Stateful CPU sampler that computes usage from the delta between consecutive
|
|
15
|
+
* `os.cpus()` snapshots — no blocking sleep. The first sample reports usage
|
|
16
|
+
* since system boot; subsequent samples report usage since the previous call.
|
|
17
|
+
*
|
|
18
|
+
* `readCpus`/`readLoad` are injectable for testing.
|
|
19
|
+
*/
|
|
20
|
+
export function createCpuSampler(readCpus = () => os.cpus(), readLoad = () => os.loadavg()[0] ?? 0) {
|
|
21
|
+
let prev = null;
|
|
22
|
+
return {
|
|
23
|
+
sample() {
|
|
24
|
+
const cur = aggregate(readCpus());
|
|
25
|
+
const loadAvg1m = Math.round(readLoad() * 100) / 100;
|
|
26
|
+
const base = prev ?? { idle: 0, total: 0 };
|
|
27
|
+
const idleDiff = cur.idle - base.idle;
|
|
28
|
+
const totalDiff = cur.total - base.total;
|
|
29
|
+
prev = cur;
|
|
30
|
+
const percent = totalDiff > 0 ? Math.round((1 - idleDiff / totalDiff) * 100) : 0;
|
|
31
|
+
return { percent, loadAvg1m };
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Collect memory usage from OS.
|
|
37
|
+
*/
|
|
38
|
+
export function collectMemory() {
|
|
39
|
+
const totalBytes = os.totalmem();
|
|
40
|
+
const freeBytes = os.freemem();
|
|
41
|
+
const usedBytes = totalBytes - freeBytes;
|
|
42
|
+
const totalGb = Math.round((totalBytes / 1024 ** 3) * 100) / 100;
|
|
43
|
+
const usedGb = Math.round((usedBytes / 1024 ** 3) * 100) / 100;
|
|
44
|
+
const percent = Math.round((usedBytes / totalBytes) * 100);
|
|
45
|
+
return { percent, usedGb, totalGb };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Collect disk usage via fs.statfs (Node 18.15+).
|
|
49
|
+
*/
|
|
50
|
+
export async function collectDisk(path) {
|
|
51
|
+
const stats = await fsp.statfs(path);
|
|
52
|
+
const totalBytes = stats.blocks * stats.bsize;
|
|
53
|
+
const freeBytes = stats.bavail * stats.bsize;
|
|
54
|
+
const usedBytes = totalBytes - freeBytes;
|
|
55
|
+
const totalGb = Math.round((totalBytes / 1024 ** 3) * 100) / 100;
|
|
56
|
+
const usedGb = Math.round((usedBytes / 1024 ** 3) * 100) / 100;
|
|
57
|
+
const percent = totalBytes > 0 ? Math.round((usedBytes / totalBytes) * 100) : 0;
|
|
58
|
+
return { percent, usedGb, totalGb };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=collectors.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const DEFAULTS = {
|
|
2
|
+
pollInterval: 15000,
|
|
3
|
+
diskPath: '/',
|
|
4
|
+
};
|
|
5
|
+
export const DEFAULT_THRESHOLDS = {
|
|
6
|
+
cpu: { warning: 75, critical: 90, direction: 'above' },
|
|
7
|
+
mem: { warning: 75, critical: 90, direction: 'above' },
|
|
8
|
+
disk: { warning: 75, critical: 90, direction: 'above' },
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PollingNPC } from '../../core/polling-npc.js';
|
|
2
|
+
import type { PollingNpcConfig } from '../../core/polling-npc.js';
|
|
3
|
+
import type { CollectedMetrics, ThresholdConfig, Archetype, BehaviorHints, CompanionDecl } from '../../core/types.js';
|
|
4
|
+
export interface SystemMonitorConfig extends PollingNpcConfig {
|
|
5
|
+
diskPath?: string;
|
|
6
|
+
cpuThreshold?: ThresholdConfig;
|
|
7
|
+
memThreshold?: ThresholdConfig;
|
|
8
|
+
diskThreshold?: ThresholdConfig;
|
|
9
|
+
}
|
|
10
|
+
export declare class SystemMonitorNPC extends PollingNPC {
|
|
11
|
+
private diskPath;
|
|
12
|
+
private cpuThreshold;
|
|
13
|
+
private memThreshold;
|
|
14
|
+
private diskThreshold;
|
|
15
|
+
private cpuSampler;
|
|
16
|
+
private cpuHistory;
|
|
17
|
+
private memHistory;
|
|
18
|
+
constructor(config: SystemMonitorConfig);
|
|
19
|
+
get name(): string;
|
|
20
|
+
protected get defaultDisplayName(): string;
|
|
21
|
+
get archetype(): Archetype;
|
|
22
|
+
get heartbeatSeconds(): number;
|
|
23
|
+
get behavior(): BehaviorHints;
|
|
24
|
+
get companion(): CompanionDecl;
|
|
25
|
+
protected collect(): Promise<CollectedMetrics>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { PollingNPC } from '../../core/polling-npc.js';
|
|
2
|
+
import { evaluateThreshold, worstStatus } from '../../core/thresholds.js';
|
|
3
|
+
import { statusColor, pushHistory } from '../../core/screen.js';
|
|
4
|
+
import { createCpuSampler, collectMemory, collectDisk } from './collectors.js';
|
|
5
|
+
import { DEFAULTS, DEFAULT_THRESHOLDS } from './defaults.js';
|
|
6
|
+
export class SystemMonitorNPC extends PollingNPC {
|
|
7
|
+
diskPath;
|
|
8
|
+
cpuThreshold;
|
|
9
|
+
memThreshold;
|
|
10
|
+
diskThreshold;
|
|
11
|
+
cpuSampler = createCpuSampler();
|
|
12
|
+
cpuHistory = [];
|
|
13
|
+
memHistory = [];
|
|
14
|
+
constructor(config) {
|
|
15
|
+
super({
|
|
16
|
+
...config,
|
|
17
|
+
pollInterval: config.pollInterval ?? DEFAULTS.pollInterval,
|
|
18
|
+
});
|
|
19
|
+
this.diskPath = config.diskPath ?? DEFAULTS.diskPath;
|
|
20
|
+
this.cpuThreshold = config.cpuThreshold ?? DEFAULT_THRESHOLDS['cpu'];
|
|
21
|
+
this.memThreshold = config.memThreshold ?? DEFAULT_THRESHOLDS['mem'];
|
|
22
|
+
this.diskThreshold = config.diskThreshold ?? DEFAULT_THRESHOLDS['disk'];
|
|
23
|
+
}
|
|
24
|
+
get name() {
|
|
25
|
+
return 'system-monitor';
|
|
26
|
+
}
|
|
27
|
+
get defaultDisplayName() {
|
|
28
|
+
return 'System Monitor';
|
|
29
|
+
}
|
|
30
|
+
get archetype() {
|
|
31
|
+
return 'service';
|
|
32
|
+
}
|
|
33
|
+
get heartbeatSeconds() {
|
|
34
|
+
return 30;
|
|
35
|
+
}
|
|
36
|
+
get behavior() {
|
|
37
|
+
return { idle: 'wander' };
|
|
38
|
+
}
|
|
39
|
+
get companion() {
|
|
40
|
+
return {
|
|
41
|
+
screenType: 'dashboard-wall',
|
|
42
|
+
size: { w: 2, h: 2 },
|
|
43
|
+
placement: 'adjacent-wall',
|
|
44
|
+
label: 'System',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async collect() {
|
|
48
|
+
const cpu = this.cpuSampler.sample();
|
|
49
|
+
const mem = collectMemory();
|
|
50
|
+
const disk = await collectDisk(this.diskPath);
|
|
51
|
+
const cpuStatus = evaluateThreshold(cpu.percent, this.cpuThreshold);
|
|
52
|
+
const memStatus = evaluateThreshold(mem.percent, this.memThreshold);
|
|
53
|
+
const diskStatus = evaluateThreshold(disk.percent, this.diskThreshold);
|
|
54
|
+
const status = worstStatus([cpuStatus, memStatus, diskStatus]);
|
|
55
|
+
const mood = status === 'critical'
|
|
56
|
+
? 'stressed'
|
|
57
|
+
: status === 'warning'
|
|
58
|
+
? 'concerned'
|
|
59
|
+
: 'happy';
|
|
60
|
+
pushHistory(this.cpuHistory, cpu.percent);
|
|
61
|
+
pushHistory(this.memHistory, mem.percent);
|
|
62
|
+
const screenData = {
|
|
63
|
+
layout: 'multi-metric',
|
|
64
|
+
values: [
|
|
65
|
+
{
|
|
66
|
+
label: 'CPU',
|
|
67
|
+
value: `${cpu.percent}%`,
|
|
68
|
+
color: statusColor(cpuStatus),
|
|
69
|
+
sparkline: [...this.cpuHistory],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'MEM',
|
|
73
|
+
value: `${mem.percent}%`,
|
|
74
|
+
color: statusColor(memStatus),
|
|
75
|
+
sparkline: [...this.memHistory],
|
|
76
|
+
},
|
|
77
|
+
{ label: 'DISK', value: `${disk.percent}%`, color: statusColor(diskStatus) },
|
|
78
|
+
{ label: 'LOAD', value: cpu.loadAvg1m.toFixed(2), color: 'gray' },
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
status,
|
|
83
|
+
mood,
|
|
84
|
+
message: `CPU: ${cpu.percent}% | Mem: ${mem.percent}% | Disk: ${disk.percent}%`,
|
|
85
|
+
screenData,
|
|
86
|
+
// When strained, go find a desk and get to work; otherwise wander.
|
|
87
|
+
behavior: status !== 'healthy' ? { busy: 'seek-desk' } : undefined,
|
|
88
|
+
metrics: {
|
|
89
|
+
cpu_percent: cpu.percent,
|
|
90
|
+
mem_percent: mem.percent,
|
|
91
|
+
mem_used_gb: mem.usedGb,
|
|
92
|
+
mem_total_gb: mem.totalGb,
|
|
93
|
+
disk_percent: disk.percent,
|
|
94
|
+
disk_used_gb: disk.usedGb,
|
|
95
|
+
disk_total_gb: disk.totalGb,
|
|
96
|
+
load_avg_1m: cpu.loadAvg1m,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Status } from '../../core/types.js';
|
|
2
|
+
export interface BasicCheck {
|
|
3
|
+
status: number;
|
|
4
|
+
title: string;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
timedOut: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Extract the <title> text from an HTML string (empty if none). */
|
|
9
|
+
export declare function extractTitle(html: string): string;
|
|
10
|
+
/** Map an HTTP status to NPC status: 2xx/3xx ok, 4xx/timeout warn, 5xx/refused crit. */
|
|
11
|
+
export declare function statusFromHttp(code: number, timedOut?: boolean): Status;
|
|
12
|
+
/** Fetch a page and extract HTTP status + <title> (basic, no browser). */
|
|
13
|
+
export declare function basicCheck(url: string, timeoutMs?: number): Promise<BasicCheck>;
|
|
14
|
+
/** Best-effort hostname for a URL, falling back to the raw string. */
|
|
15
|
+
export declare function hostnameOf(url: string): string;
|
|
16
|
+
//# sourceMappingURL=basic-mode.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Extract the <title> text from an HTML string (empty if none). */
|
|
2
|
+
export function extractTitle(html) {
|
|
3
|
+
const m = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
4
|
+
return m ? m[1].replace(/\s+/g, ' ').trim().slice(0, 80) : '';
|
|
5
|
+
}
|
|
6
|
+
/** Map an HTTP status to NPC status: 2xx/3xx ok, 4xx/timeout warn, 5xx/refused crit. */
|
|
7
|
+
export function statusFromHttp(code, timedOut = false) {
|
|
8
|
+
if (code >= 200 && code < 400)
|
|
9
|
+
return 'healthy';
|
|
10
|
+
if (code >= 400 && code < 500)
|
|
11
|
+
return 'warning';
|
|
12
|
+
if (code >= 500)
|
|
13
|
+
return 'critical';
|
|
14
|
+
return timedOut ? 'warning' : 'critical'; // 0 = network error
|
|
15
|
+
}
|
|
16
|
+
/** Fetch a page and extract HTTP status + <title> (basic, no browser). */
|
|
17
|
+
export async function basicCheck(url, timeoutMs = 8000) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch(url, {
|
|
22
|
+
signal: controller.signal,
|
|
23
|
+
headers: { 'User-Agent': 'nocville-npc' },
|
|
24
|
+
redirect: 'follow',
|
|
25
|
+
});
|
|
26
|
+
let title = '';
|
|
27
|
+
try {
|
|
28
|
+
title = extractTitle(await res.text());
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// body unavailable; leave title blank
|
|
32
|
+
}
|
|
33
|
+
return { status: res.status, title, ok: res.ok, timedOut: false };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const timedOut = err instanceof Error && err.name === 'AbortError';
|
|
37
|
+
return { status: 0, title: '', ok: false, timedOut };
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Best-effort hostname for a URL, falling back to the raw string. */
|
|
44
|
+
export function hostnameOf(url) {
|
|
45
|
+
try {
|
|
46
|
+
return new URL(url).hostname;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return url.slice(0, 40);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=basic-mode.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface PuppeteerViewport {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
deviceScaleFactor?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface PuppeteerResponse {
|
|
7
|
+
status(): number;
|
|
8
|
+
}
|
|
9
|
+
export interface PuppeteerPage {
|
|
10
|
+
setViewport(v: PuppeteerViewport): Promise<void>;
|
|
11
|
+
goto(url: string, opts?: {
|
|
12
|
+
waitUntil?: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}): Promise<PuppeteerResponse | null>;
|
|
15
|
+
screenshot(opts: {
|
|
16
|
+
type?: string;
|
|
17
|
+
fullPage?: boolean;
|
|
18
|
+
}): Promise<Buffer | Uint8Array>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface PuppeteerBrowser {
|
|
22
|
+
newPage(): Promise<PuppeteerPage>;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
/** puppeteer >= 20 exposes `connected`; older versions expose isConnected(). */
|
|
25
|
+
connected?: boolean;
|
|
26
|
+
isConnected?(): boolean;
|
|
27
|
+
on(event: string, cb: () => void): void;
|
|
28
|
+
}
|
|
29
|
+
export interface PuppeteerModule {
|
|
30
|
+
launch(opts: {
|
|
31
|
+
executablePath?: string;
|
|
32
|
+
headless?: boolean | 'new';
|
|
33
|
+
args?: string[];
|
|
34
|
+
}): Promise<PuppeteerBrowser>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Find a usable Chrome/Chromium executable: explicit path → CHROME_PATH env →
|
|
38
|
+
* platform-specific known locations (mac app bundles; `which` on linux).
|
|
39
|
+
*/
|
|
40
|
+
export declare function findChrome(explicit?: string): string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Load the optional `puppeteer-core` peer dependency without a static import,
|
|
43
|
+
* so the package builds and runs when it isn't installed. Returns null if the
|
|
44
|
+
* module is absent.
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadPuppeteer(): Promise<PuppeteerModule | null>;
|
|
47
|
+
/** True if the browser reports a live connection. */
|
|
48
|
+
export declare function browserConnected(browser: PuppeteerBrowser): boolean;
|
|
49
|
+
//# sourceMappingURL=capture.d.ts.map
|