lightman-agent 1.0.4 → 1.0.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/agent.config.template.json +30 -30
- package/package.json +52 -52
- package/public/assets/index-CcBNCz6h.css +1 -1
- package/public/assets/index-D9QHMG8k.js +1 -0
- package/public/assets/index-H-8HDl46.js +1 -1
- package/public/assets/index-YodeiCia.css +1 -0
- package/public/assets/index-legacy-DWtNM8y7.js +41 -0
- package/public/assets/museum-map-CwVDA2z1.svg +4182 -0
- package/public/assets/polyfills-legacy-DyVYWHbW.js +4 -0
- package/public/index.html +7 -2
- package/public/templates/custom08/elements/back-button.svg +20 -0
- package/public/templates/custom08/elements/base-map-background.svg +37 -0
- package/public/templates/custom08/elements/base-map.svg +1191 -0
- package/public/templates/custom08/elements/gallery-1-2-3-info-panel.svg +236 -0
- package/public/templates/custom08/elements/gallery-4-5-6-7-info-panel.svg +266 -0
- package/public/templates/custom08/elements/gallery-8-9-info-panel.svg +274 -0
- package/public/templates/custom08/elements/gallery-labels/_nav-map-styles.css +554 -0
- package/public/templates/custom08/elements/gallery-labels/_styles.css +556 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-1.svg +35 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-2.svg +34 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-3.svg +34 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-4.svg +37 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-5.svg +34 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-6.svg +34 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-7.svg +34 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-8.svg +37 -0
- package/public/templates/custom08/elements/gallery-labels/gallery-9.svg +34 -0
- package/public/templates/custom08/elements/hand-hint.png +0 -0
- package/public/templates/custom08/elements/idle-screen-bg.svg +5 -0
- package/public/templates/custom08/elements/idle-screen-map.svg +627 -0
- package/public/templates/custom08/elements/idle-screen-text.svg +350 -0
- package/public/templates/custom08/elements/key-map-1.svg +986 -0
- package/public/templates/custom08/elements/key-map-2.svg +1018 -0
- package/public/templates/custom08/elements/key-map-3.svg +1019 -0
- package/public/templates/custom08/elements/key-map-combined.svg +1001 -0
- package/public/templates/custom08/elements/map-highlight-marker.svg +11 -0
- package/public/templates/custom08/elements/map-pin-marker.svg +15 -0
- package/public/templates/custom08/elements/map-teardrop-star-marker.svg +13 -0
- package/public/templates/custom08/elements/nav-circle-galleries-1-3.svg +21 -0
- package/public/templates/custom08/elements/nav-circle-galleries-4-7.svg +24 -0
- package/public/templates/custom08/elements/nav-circle-galleries-8-9.svg +20 -0
- package/public/templates/custom08/elements/section1-map.svg +1435 -0
- package/public/templates/custom08/elements/section2-map.svg +1724 -0
- package/public/templates/custom08/elements/section3-map.svg +1295 -0
- package/public/templates/custom08/fonts/CabinetGrotesk-Variable.ttf +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.23.12_PM.png +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.23.56_PM.png +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.24.24_PM.png +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.31.58_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.11_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.36_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.48_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.59_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.15_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.27_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.34_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.42_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.50_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.58_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.04_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.11_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.20_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.57_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.03_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.16_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.23_PM.jpg +0 -0
- package/public/templates/custom08/images/highlights/prologue-highlight.png +0 -0
- package/scripts/guardian.ps1 +75 -75
- package/scripts/install-linux.sh +134 -134
- package/scripts/install-rpi.sh +117 -117
- package/scripts/install-windows.ps1 +513 -512
- package/scripts/launch-kiosk.vbs +101 -101
- package/scripts/lightman-agent.logrotate +12 -12
- package/scripts/lightman-agent.service +38 -38
- package/scripts/lightman-shell.bat +107 -107
- package/scripts/reinstall-windows.ps1 +26 -26
- package/scripts/restore-desktop.ps1 +32 -32
- package/scripts/setup.ps1 +116 -116
- package/scripts/setup.sh +115 -115
- package/scripts/sync-display.mjs +20 -0
- package/scripts/uninstall-linux.sh +50 -50
- package/scripts/uninstall-windows.ps1 +54 -54
- package/src/commands/display.ts +177 -177
- package/src/commands/kiosk.ts +113 -113
- package/src/commands/maintenance.ts +106 -106
- package/src/commands/network.ts +129 -129
- package/src/commands/power.ts +163 -163
- package/src/commands/rpi.ts +45 -45
- package/src/commands/screenshot.ts +166 -166
- package/src/commands/serial.ts +17 -17
- package/src/commands/update.ts +124 -124
- package/src/index.ts +652 -652
- package/src/lib/config.ts +69 -69
- package/src/lib/identity.ts +40 -40
- package/src/lib/logger.ts +137 -137
- package/src/lib/platform.ts +10 -10
- package/src/lib/rpi.ts +180 -180
- package/src/lib/screens.ts +128 -128
- package/src/lib/types.ts +176 -176
- package/src/services/commands.ts +107 -107
- package/src/services/health.ts +161 -161
- package/src/services/kiosk.ts +384 -384
- package/src/services/localEvents.ts +60 -60
- package/src/services/logForwarder.ts +72 -72
- package/src/services/multiScreenKiosk.ts +324 -324
- package/src/services/oscBridge.ts +186 -186
- package/src/services/powerScheduler.ts +260 -260
- package/src/services/provisioning.ts +120 -120
- package/src/services/serialBridge.ts +230 -230
- package/src/services/serviceLauncher.ts +183 -183
- package/src/services/staticServer.ts +226 -226
- package/src/services/updater.ts +249 -249
- package/src/services/watchdog.ts +310 -310
- package/src/services/websocket.ts +152 -152
- package/tsconfig.json +28 -28
package/src/commands/update.ts
CHANGED
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { Logger } from '../lib/logger.js';
|
|
3
|
-
import type { Updater } from '../services/updater.js';
|
|
4
|
-
import type { WsClient } from '../services/websocket.js';
|
|
5
|
-
import type { CommandHandler } from '../lib/types.js';
|
|
6
|
-
|
|
7
|
-
type RegisterFn = (name: string, handler: CommandHandler) => void;
|
|
8
|
-
|
|
9
|
-
// --- Zod Schemas ---
|
|
10
|
-
const UpdateArgsSchema = z.object({
|
|
11
|
-
url: z.string().url().refine(
|
|
12
|
-
(val) => {
|
|
13
|
-
try {
|
|
14
|
-
const parsed = new URL(val);
|
|
15
|
-
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
{ message: 'Only http/https URLs are supported' }
|
|
21
|
-
),
|
|
22
|
-
version: z.string().min(1),
|
|
23
|
-
checksum: z.string().regex(/^[a-f0-9]{64}$/i, 'Invalid checksum format (expected SHA256 hex)'),
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
export function registerUpdateCommands(
|
|
27
|
-
register: RegisterFn,
|
|
28
|
-
updater: Updater,
|
|
29
|
-
wsClient: WsClient,
|
|
30
|
-
logger: Logger
|
|
31
|
-
): void {
|
|
32
|
-
/**
|
|
33
|
-
* agent:update — Download, verify, install an update, then restart.
|
|
34
|
-
* Args: { url: string, version: string, checksum: string }
|
|
35
|
-
*/
|
|
36
|
-
register('agent:update', async (args) => {
|
|
37
|
-
const parsed = UpdateArgsSchema.safeParse(args ?? {});
|
|
38
|
-
if (!parsed.success) {
|
|
39
|
-
const issues = parsed.error.issues;
|
|
40
|
-
const urlIssue = issues.find((i) => i.path.includes('url'));
|
|
41
|
-
const checksumIssue = issues.find((i) => i.path.includes('checksum'));
|
|
42
|
-
|
|
43
|
-
if (urlIssue && urlIssue.code === 'invalid_string') {
|
|
44
|
-
throw new Error('Invalid URL');
|
|
45
|
-
}
|
|
46
|
-
if (urlIssue && urlIssue.message === 'Only http/https URLs are supported') {
|
|
47
|
-
throw new Error('Only http/https URLs are supported');
|
|
48
|
-
}
|
|
49
|
-
if (checksumIssue) {
|
|
50
|
-
throw new Error('Invalid checksum format (expected SHA256 hex)');
|
|
51
|
-
}
|
|
52
|
-
throw new Error('Missing required args: url, version, checksum');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const { url, version, checksum } = parsed.data;
|
|
56
|
-
|
|
57
|
-
// Send status update
|
|
58
|
-
const sendStatus = (phase: string, detail?: Record<string, unknown>) => {
|
|
59
|
-
wsClient.send({
|
|
60
|
-
type: 'agent:update_status',
|
|
61
|
-
payload: { phase, version, ...detail },
|
|
62
|
-
timestamp: Date.now(),
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
sendStatus('downloading');
|
|
68
|
-
const filePath = await updater.download(url);
|
|
69
|
-
|
|
70
|
-
sendStatus('verifying');
|
|
71
|
-
const valid = await updater.verify(filePath, checksum);
|
|
72
|
-
if (!valid) {
|
|
73
|
-
sendStatus('error', { error: 'Checksum verification failed' });
|
|
74
|
-
throw new Error('Checksum verification failed');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
sendStatus('installing');
|
|
78
|
-
await updater.install(filePath, version);
|
|
79
|
-
|
|
80
|
-
// Clean old downloads
|
|
81
|
-
updater.cleanDownloads();
|
|
82
|
-
|
|
83
|
-
sendStatus('restarting');
|
|
84
|
-
logger.info(`Update to v${version} complete. Restarting...`);
|
|
85
|
-
|
|
86
|
-
// Delay restart to allow result to be sent
|
|
87
|
-
setTimeout(() => process.exit(0), 2000);
|
|
88
|
-
|
|
89
|
-
return { success: true, version, restarting: true };
|
|
90
|
-
} catch (err) {
|
|
91
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
92
|
-
sendStatus('error', { error: message });
|
|
93
|
-
logger.error(`Update failed: ${message}`);
|
|
94
|
-
throw new Error(`Update failed: ${message}`);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* agent:rollback — Rollback to the previous backup version.
|
|
100
|
-
*/
|
|
101
|
-
register('agent:rollback', async () => {
|
|
102
|
-
try {
|
|
103
|
-
await updater.rollback();
|
|
104
|
-
logger.info('Rollback complete. Restarting...');
|
|
105
|
-
|
|
106
|
-
// Delay restart to allow result to be sent
|
|
107
|
-
setTimeout(() => process.exit(0), 2000);
|
|
108
|
-
|
|
109
|
-
return { success: true, restarting: true };
|
|
110
|
-
} catch (err) {
|
|
111
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
112
|
-
logger.error(`Rollback failed: ${message}`);
|
|
113
|
-
throw new Error(`Rollback failed: ${message}`);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* agent:update-status — Get current update status.
|
|
119
|
-
*/
|
|
120
|
-
register('agent:update-status', async () => {
|
|
121
|
-
const status = updater.getStatus();
|
|
122
|
-
return { ...status } as Record<string, unknown>;
|
|
123
|
-
});
|
|
124
|
-
}
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Logger } from '../lib/logger.js';
|
|
3
|
+
import type { Updater } from '../services/updater.js';
|
|
4
|
+
import type { WsClient } from '../services/websocket.js';
|
|
5
|
+
import type { CommandHandler } from '../lib/types.js';
|
|
6
|
+
|
|
7
|
+
type RegisterFn = (name: string, handler: CommandHandler) => void;
|
|
8
|
+
|
|
9
|
+
// --- Zod Schemas ---
|
|
10
|
+
const UpdateArgsSchema = z.object({
|
|
11
|
+
url: z.string().url().refine(
|
|
12
|
+
(val) => {
|
|
13
|
+
try {
|
|
14
|
+
const parsed = new URL(val);
|
|
15
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{ message: 'Only http/https URLs are supported' }
|
|
21
|
+
),
|
|
22
|
+
version: z.string().min(1),
|
|
23
|
+
checksum: z.string().regex(/^[a-f0-9]{64}$/i, 'Invalid checksum format (expected SHA256 hex)'),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export function registerUpdateCommands(
|
|
27
|
+
register: RegisterFn,
|
|
28
|
+
updater: Updater,
|
|
29
|
+
wsClient: WsClient,
|
|
30
|
+
logger: Logger
|
|
31
|
+
): void {
|
|
32
|
+
/**
|
|
33
|
+
* agent:update — Download, verify, install an update, then restart.
|
|
34
|
+
* Args: { url: string, version: string, checksum: string }
|
|
35
|
+
*/
|
|
36
|
+
register('agent:update', async (args) => {
|
|
37
|
+
const parsed = UpdateArgsSchema.safeParse(args ?? {});
|
|
38
|
+
if (!parsed.success) {
|
|
39
|
+
const issues = parsed.error.issues;
|
|
40
|
+
const urlIssue = issues.find((i) => i.path.includes('url'));
|
|
41
|
+
const checksumIssue = issues.find((i) => i.path.includes('checksum'));
|
|
42
|
+
|
|
43
|
+
if (urlIssue && urlIssue.code === 'invalid_string') {
|
|
44
|
+
throw new Error('Invalid URL');
|
|
45
|
+
}
|
|
46
|
+
if (urlIssue && urlIssue.message === 'Only http/https URLs are supported') {
|
|
47
|
+
throw new Error('Only http/https URLs are supported');
|
|
48
|
+
}
|
|
49
|
+
if (checksumIssue) {
|
|
50
|
+
throw new Error('Invalid checksum format (expected SHA256 hex)');
|
|
51
|
+
}
|
|
52
|
+
throw new Error('Missing required args: url, version, checksum');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const { url, version, checksum } = parsed.data;
|
|
56
|
+
|
|
57
|
+
// Send status update
|
|
58
|
+
const sendStatus = (phase: string, detail?: Record<string, unknown>) => {
|
|
59
|
+
wsClient.send({
|
|
60
|
+
type: 'agent:update_status',
|
|
61
|
+
payload: { phase, version, ...detail },
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
sendStatus('downloading');
|
|
68
|
+
const filePath = await updater.download(url);
|
|
69
|
+
|
|
70
|
+
sendStatus('verifying');
|
|
71
|
+
const valid = await updater.verify(filePath, checksum);
|
|
72
|
+
if (!valid) {
|
|
73
|
+
sendStatus('error', { error: 'Checksum verification failed' });
|
|
74
|
+
throw new Error('Checksum verification failed');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
sendStatus('installing');
|
|
78
|
+
await updater.install(filePath, version);
|
|
79
|
+
|
|
80
|
+
// Clean old downloads
|
|
81
|
+
updater.cleanDownloads();
|
|
82
|
+
|
|
83
|
+
sendStatus('restarting');
|
|
84
|
+
logger.info(`Update to v${version} complete. Restarting...`);
|
|
85
|
+
|
|
86
|
+
// Delay restart to allow result to be sent
|
|
87
|
+
setTimeout(() => process.exit(0), 2000);
|
|
88
|
+
|
|
89
|
+
return { success: true, version, restarting: true };
|
|
90
|
+
} catch (err) {
|
|
91
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
92
|
+
sendStatus('error', { error: message });
|
|
93
|
+
logger.error(`Update failed: ${message}`);
|
|
94
|
+
throw new Error(`Update failed: ${message}`);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* agent:rollback — Rollback to the previous backup version.
|
|
100
|
+
*/
|
|
101
|
+
register('agent:rollback', async () => {
|
|
102
|
+
try {
|
|
103
|
+
await updater.rollback();
|
|
104
|
+
logger.info('Rollback complete. Restarting...');
|
|
105
|
+
|
|
106
|
+
// Delay restart to allow result to be sent
|
|
107
|
+
setTimeout(() => process.exit(0), 2000);
|
|
108
|
+
|
|
109
|
+
return { success: true, restarting: true };
|
|
110
|
+
} catch (err) {
|
|
111
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
112
|
+
logger.error(`Rollback failed: ${message}`);
|
|
113
|
+
throw new Error(`Rollback failed: ${message}`);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* agent:update-status — Get current update status.
|
|
119
|
+
*/
|
|
120
|
+
register('agent:update-status', async () => {
|
|
121
|
+
const status = updater.getStatus();
|
|
122
|
+
return { ...status } as Record<string, unknown>;
|
|
123
|
+
});
|
|
124
|
+
}
|