lightman-agent 1.0.18 → 1.0.20

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.
Files changed (52) hide show
  1. package/agent.config.json +22 -23
  2. package/agent.config.template.json +30 -31
  3. package/bin/cms-agent.js +291 -291
  4. package/package.json +1 -1
  5. package/public/assets/index-CcBNCz6h.css +1 -1
  6. package/public/assets/index-D9QHMG8k.js +1 -1
  7. package/public/assets/index-H-8HDl46.js +1 -1
  8. package/public/assets/index-YodeiCia.css +1 -1
  9. package/public/assets/index-legacy-DWtNM8y7.js +41 -41
  10. package/public/assets/polyfills-legacy-DyVYWHbW.js +4 -4
  11. package/scripts/guardian.ps1 +50 -124
  12. package/scripts/install-windows.ps1 +28 -120
  13. package/scripts/lightman-agent.logrotate +12 -12
  14. package/scripts/lightman-agent.service +38 -38
  15. package/scripts/reinstall-windows.ps1 +26 -26
  16. package/scripts/restore-desktop.ps1 +32 -32
  17. package/scripts/setup.ps1 +17 -22
  18. package/scripts/sync-display.mjs +20 -20
  19. package/scripts/uninstall-windows.ps1 +54 -54
  20. package/src/commands/display.ts +177 -177
  21. package/src/commands/kiosk.ts +113 -113
  22. package/src/commands/maintenance.ts +106 -106
  23. package/src/commands/network.ts +129 -129
  24. package/src/commands/power.ts +163 -163
  25. package/src/commands/rpi.ts +45 -45
  26. package/src/commands/screenshot.ts +166 -166
  27. package/src/commands/serial.ts +17 -17
  28. package/src/commands/update.ts +124 -124
  29. package/src/index.ts +173 -90
  30. package/src/lib/config.ts +2 -3
  31. package/src/lib/identity.ts +40 -40
  32. package/src/lib/logger.ts +137 -137
  33. package/src/lib/platform.ts +10 -10
  34. package/src/lib/rpi.ts +180 -180
  35. package/src/lib/screenMap.ts +135 -0
  36. package/src/lib/screens.ts +128 -128
  37. package/src/lib/types.ts +176 -177
  38. package/src/services/commands.ts +107 -107
  39. package/src/services/health.ts +161 -161
  40. package/src/services/localEvents.ts +60 -60
  41. package/src/services/logForwarder.ts +72 -72
  42. package/src/services/multiScreenKiosk.ts +116 -83
  43. package/src/services/oscBridge.ts +186 -186
  44. package/src/services/powerScheduler.ts +260 -260
  45. package/src/services/provisioning.ts +120 -122
  46. package/src/services/serialBridge.ts +230 -230
  47. package/src/services/serviceLauncher.ts +183 -183
  48. package/src/services/staticServer.ts +226 -226
  49. package/src/services/updater.ts +249 -249
  50. package/src/services/watchdog.ts +310 -310
  51. package/src/services/websocket.ts +152 -152
  52. package/tsconfig.json +28 -28
@@ -1,122 +1,120 @@
1
- import { z } from 'zod';
2
- import type { AgentConfig, Identity } from '../lib/types.js';
3
- import { readIdentity, writeIdentity } from '../lib/identity.js';
4
- import type { Logger } from '../lib/logger.js';
5
-
6
- const provisionResponseSchema = z.object({
7
- deviceId: z.string().uuid(),
8
- apiKey: z.string().min(1),
9
- });
10
-
11
- interface ProvisionResult {
12
- identity: Identity;
13
- fromCache: boolean;
14
- }
15
-
16
- /**
17
- * Provision the agent: check for cached identity, otherwise call CMS provisioning endpoints.
18
- * If pairing is required, polls until admin approves (with timeout).
19
- */
20
- export async function provision(
21
- config: AgentConfig,
22
- logger: Logger
23
- ): Promise<ProvisionResult> {
24
- // Check for cached identity first
25
- const cached = readIdentity(config.identityFile);
26
- if (cached) {
27
- logger.info('Using cached identity', { deviceId: cached.deviceId });
28
- return { identity: cached, fromCache: true };
29
- }
30
-
31
- logger.info(`Provisioning device: ${config.deviceSlug}`);
32
-
33
- const baseUrl = `${config.serverUrl}/api/devices/provision/${encodeURIComponent(config.deviceSlug)}`;
34
-
35
- // Step 1: Request provisioning
36
- const res = await fetch(baseUrl);
37
- if (!res.ok) {
38
- const body = await res.text();
39
- throw new Error(`Provision request failed (${res.status}): ${body}`);
40
- }
41
-
42
- const data = await res.json() as Record<string, unknown>;
43
-
44
- // Auto-provisioned (IP match)
45
- if (data.deviceId && data.apiKey) {
46
- const parsed = provisionResponseSchema.safeParse(data);
47
- if (!parsed.success) {
48
- throw new Error('Invalid provision response: ' + parsed.error.message);
49
- }
50
- const identity: Identity = {
51
- deviceId: parsed.data.deviceId,
52
- apiKey: parsed.data.apiKey,
53
- };
54
- writeIdentity(config.identityFile, identity);
55
- logger.info('Auto-provisioned', { deviceId: identity.deviceId });
56
- return { identity, fromCache: false };
57
- }
58
-
59
- // Pairing required — display code and poll
60
- if (data.requiresPairing && data.code) {
61
- const code = data.code as string;
62
- logger.warn(`Pairing required. Enter code in admin UI: ${code}`);
63
- logger.info('Waiting for admin to approve pairing...');
64
- const pairingTimeoutMs = Math.max(0, config.pairingTimeoutSeconds ?? 900) * 1000;
65
-
66
- const identity = await pollForPairing(
67
- `${baseUrl}/status?code=${encodeURIComponent(code)}`,
68
- logger,
69
- pairingTimeoutMs
70
- );
71
-
72
- writeIdentity(config.identityFile, identity);
73
- logger.info('Pairing complete', { deviceId: identity.deviceId });
74
- return { identity, fromCache: false };
75
- }
76
-
77
- throw new Error('Unexpected provision response: ' + JSON.stringify(data));
78
- }
79
-
80
- async function pollForPairing(
81
- statusUrl: string,
82
- logger: Logger,
83
- timeoutMs = 600_000,
84
- intervalMs = 5_000
85
- ): Promise<Identity> {
86
- const deadline = timeoutMs <= 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
87
-
88
- while (Date.now() < deadline) {
89
- await sleep(intervalMs);
90
-
91
- try {
92
- const res = await fetch(statusUrl);
93
- if (!res.ok) {
94
- logger.warn(`Pairing poll failed (${res.status}), retrying...`);
95
- continue;
96
- }
97
-
98
- const data = await res.json() as Record<string, unknown>;
99
-
100
- if (data.deviceId && data.apiKey) {
101
- const parsed = provisionResponseSchema.safeParse(data);
102
- if (!parsed.success) {
103
- throw new Error('Invalid pairing response: ' + parsed.error.message);
104
- }
105
- return {
106
- deviceId: parsed.data.deviceId,
107
- apiKey: parsed.data.apiKey,
108
- };
109
- }
110
-
111
- logger.debug('Pairing not yet complete, polling again...');
112
- } catch (err) {
113
- logger.warn('Pairing poll error, retrying...', err);
114
- }
115
- }
116
-
117
- throw new Error('Pairing timed out after ' + (timeoutMs / 1000) + 's');
118
- }
119
-
120
- function sleep(ms: number): Promise<void> {
121
- return new Promise((resolve) => setTimeout(resolve, ms));
122
- }
1
+ import { z } from 'zod';
2
+ import type { AgentConfig, Identity } from '../lib/types.js';
3
+ import { readIdentity, writeIdentity } from '../lib/identity.js';
4
+ import type { Logger } from '../lib/logger.js';
5
+
6
+ const provisionResponseSchema = z.object({
7
+ deviceId: z.string().uuid(),
8
+ apiKey: z.string().min(1),
9
+ });
10
+
11
+ interface ProvisionResult {
12
+ identity: Identity;
13
+ fromCache: boolean;
14
+ }
15
+
16
+ /**
17
+ * Provision the agent: check for cached identity, otherwise call CMS provisioning endpoints.
18
+ * If pairing is required, polls until admin approves (with timeout).
19
+ */
20
+ export async function provision(
21
+ config: AgentConfig,
22
+ logger: Logger
23
+ ): Promise<ProvisionResult> {
24
+ // Check for cached identity first
25
+ const cached = readIdentity(config.identityFile);
26
+ if (cached) {
27
+ logger.info('Using cached identity', { deviceId: cached.deviceId });
28
+ return { identity: cached, fromCache: true };
29
+ }
30
+
31
+ logger.info(`Provisioning device: ${config.deviceSlug}`);
32
+
33
+ const baseUrl = `${config.serverUrl}/api/devices/provision/${encodeURIComponent(config.deviceSlug)}`;
34
+
35
+ // Step 1: Request provisioning
36
+ const res = await fetch(baseUrl);
37
+ if (!res.ok) {
38
+ const body = await res.text();
39
+ throw new Error(`Provision request failed (${res.status}): ${body}`);
40
+ }
41
+
42
+ const data = await res.json() as Record<string, unknown>;
43
+
44
+ // Auto-provisioned (IP match)
45
+ if (data.deviceId && data.apiKey) {
46
+ const parsed = provisionResponseSchema.safeParse(data);
47
+ if (!parsed.success) {
48
+ throw new Error('Invalid provision response: ' + parsed.error.message);
49
+ }
50
+ const identity: Identity = {
51
+ deviceId: parsed.data.deviceId,
52
+ apiKey: parsed.data.apiKey,
53
+ };
54
+ writeIdentity(config.identityFile, identity);
55
+ logger.info('Auto-provisioned', { deviceId: identity.deviceId });
56
+ return { identity, fromCache: false };
57
+ }
58
+
59
+ // Pairing required — display code and poll
60
+ if (data.requiresPairing && data.code) {
61
+ const code = data.code as string;
62
+ logger.warn(`Pairing required. Enter code in admin UI: ${code}`);
63
+ logger.info('Waiting for admin to approve pairing...');
64
+
65
+ const identity = await pollForPairing(
66
+ `${baseUrl}/status?code=${encodeURIComponent(code)}`,
67
+ logger
68
+ );
69
+
70
+ writeIdentity(config.identityFile, identity);
71
+ logger.info('Pairing complete', { deviceId: identity.deviceId });
72
+ return { identity, fromCache: false };
73
+ }
74
+
75
+ throw new Error('Unexpected provision response: ' + JSON.stringify(data));
76
+ }
77
+
78
+ async function pollForPairing(
79
+ statusUrl: string,
80
+ logger: Logger,
81
+ timeoutMs = 600_000,
82
+ intervalMs = 5_000
83
+ ): Promise<Identity> {
84
+ const deadline = Date.now() + timeoutMs;
85
+
86
+ while (Date.now() < deadline) {
87
+ await sleep(intervalMs);
88
+
89
+ try {
90
+ const res = await fetch(statusUrl);
91
+ if (!res.ok) {
92
+ logger.warn(`Pairing poll failed (${res.status}), retrying...`);
93
+ continue;
94
+ }
95
+
96
+ const data = await res.json() as Record<string, unknown>;
97
+
98
+ if (data.deviceId && data.apiKey) {
99
+ const parsed = provisionResponseSchema.safeParse(data);
100
+ if (!parsed.success) {
101
+ throw new Error('Invalid pairing response: ' + parsed.error.message);
102
+ }
103
+ return {
104
+ deviceId: parsed.data.deviceId,
105
+ apiKey: parsed.data.apiKey,
106
+ };
107
+ }
108
+
109
+ logger.debug('Pairing not yet complete, polling again...');
110
+ } catch (err) {
111
+ logger.warn('Pairing poll error, retrying...', err);
112
+ }
113
+ }
114
+
115
+ throw new Error('Pairing timed out after ' + (timeoutMs / 1000) + 's');
116
+ }
117
+
118
+ function sleep(ms: number): Promise<void> {
119
+ return new Promise((resolve) => setTimeout(resolve, ms));
120
+ }