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.
Files changed (115) hide show
  1. package/agent.config.template.json +30 -30
  2. package/package.json +52 -52
  3. package/public/assets/index-CcBNCz6h.css +1 -1
  4. package/public/assets/index-D9QHMG8k.js +1 -0
  5. package/public/assets/index-H-8HDl46.js +1 -1
  6. package/public/assets/index-YodeiCia.css +1 -0
  7. package/public/assets/index-legacy-DWtNM8y7.js +41 -0
  8. package/public/assets/museum-map-CwVDA2z1.svg +4182 -0
  9. package/public/assets/polyfills-legacy-DyVYWHbW.js +4 -0
  10. package/public/index.html +7 -2
  11. package/public/templates/custom08/elements/back-button.svg +20 -0
  12. package/public/templates/custom08/elements/base-map-background.svg +37 -0
  13. package/public/templates/custom08/elements/base-map.svg +1191 -0
  14. package/public/templates/custom08/elements/gallery-1-2-3-info-panel.svg +236 -0
  15. package/public/templates/custom08/elements/gallery-4-5-6-7-info-panel.svg +266 -0
  16. package/public/templates/custom08/elements/gallery-8-9-info-panel.svg +274 -0
  17. package/public/templates/custom08/elements/gallery-labels/_nav-map-styles.css +554 -0
  18. package/public/templates/custom08/elements/gallery-labels/_styles.css +556 -0
  19. package/public/templates/custom08/elements/gallery-labels/gallery-1.svg +35 -0
  20. package/public/templates/custom08/elements/gallery-labels/gallery-2.svg +34 -0
  21. package/public/templates/custom08/elements/gallery-labels/gallery-3.svg +34 -0
  22. package/public/templates/custom08/elements/gallery-labels/gallery-4.svg +37 -0
  23. package/public/templates/custom08/elements/gallery-labels/gallery-5.svg +34 -0
  24. package/public/templates/custom08/elements/gallery-labels/gallery-6.svg +34 -0
  25. package/public/templates/custom08/elements/gallery-labels/gallery-7.svg +34 -0
  26. package/public/templates/custom08/elements/gallery-labels/gallery-8.svg +37 -0
  27. package/public/templates/custom08/elements/gallery-labels/gallery-9.svg +34 -0
  28. package/public/templates/custom08/elements/hand-hint.png +0 -0
  29. package/public/templates/custom08/elements/idle-screen-bg.svg +5 -0
  30. package/public/templates/custom08/elements/idle-screen-map.svg +627 -0
  31. package/public/templates/custom08/elements/idle-screen-text.svg +350 -0
  32. package/public/templates/custom08/elements/key-map-1.svg +986 -0
  33. package/public/templates/custom08/elements/key-map-2.svg +1018 -0
  34. package/public/templates/custom08/elements/key-map-3.svg +1019 -0
  35. package/public/templates/custom08/elements/key-map-combined.svg +1001 -0
  36. package/public/templates/custom08/elements/map-highlight-marker.svg +11 -0
  37. package/public/templates/custom08/elements/map-pin-marker.svg +15 -0
  38. package/public/templates/custom08/elements/map-teardrop-star-marker.svg +13 -0
  39. package/public/templates/custom08/elements/nav-circle-galleries-1-3.svg +21 -0
  40. package/public/templates/custom08/elements/nav-circle-galleries-4-7.svg +24 -0
  41. package/public/templates/custom08/elements/nav-circle-galleries-8-9.svg +20 -0
  42. package/public/templates/custom08/elements/section1-map.svg +1435 -0
  43. package/public/templates/custom08/elements/section2-map.svg +1724 -0
  44. package/public/templates/custom08/elements/section3-map.svg +1295 -0
  45. package/public/templates/custom08/fonts/CabinetGrotesk-Variable.ttf +0 -0
  46. package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.23.12_PM.png +0 -0
  47. package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.23.56_PM.png +0 -0
  48. package/public/templates/custom08/images/highlights/Screenshot_2026-03-05_at_7.24.24_PM.png +0 -0
  49. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.31.58_PM.jpg +0 -0
  50. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.11_PM.jpg +0 -0
  51. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.36_PM.jpg +0 -0
  52. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.48_PM.jpg +0 -0
  53. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.32.59_PM.jpg +0 -0
  54. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.15_PM.jpg +0 -0
  55. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.27_PM.jpg +0 -0
  56. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.34_PM.jpg +0 -0
  57. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.42_PM.jpg +0 -0
  58. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.50_PM.jpg +0 -0
  59. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.33.58_PM.jpg +0 -0
  60. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.04_PM.jpg +0 -0
  61. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.11_PM.jpg +0 -0
  62. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.20_PM.jpg +0 -0
  63. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.34.57_PM.jpg +0 -0
  64. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.03_PM.jpg +0 -0
  65. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.16_PM.jpg +0 -0
  66. package/public/templates/custom08/images/highlights/Screenshot_2026-03-24_at_11.35.23_PM.jpg +0 -0
  67. package/public/templates/custom08/images/highlights/prologue-highlight.png +0 -0
  68. package/scripts/guardian.ps1 +75 -75
  69. package/scripts/install-linux.sh +134 -134
  70. package/scripts/install-rpi.sh +117 -117
  71. package/scripts/install-windows.ps1 +513 -512
  72. package/scripts/launch-kiosk.vbs +101 -101
  73. package/scripts/lightman-agent.logrotate +12 -12
  74. package/scripts/lightman-agent.service +38 -38
  75. package/scripts/lightman-shell.bat +107 -107
  76. package/scripts/reinstall-windows.ps1 +26 -26
  77. package/scripts/restore-desktop.ps1 +32 -32
  78. package/scripts/setup.ps1 +116 -116
  79. package/scripts/setup.sh +115 -115
  80. package/scripts/sync-display.mjs +20 -0
  81. package/scripts/uninstall-linux.sh +50 -50
  82. package/scripts/uninstall-windows.ps1 +54 -54
  83. package/src/commands/display.ts +177 -177
  84. package/src/commands/kiosk.ts +113 -113
  85. package/src/commands/maintenance.ts +106 -106
  86. package/src/commands/network.ts +129 -129
  87. package/src/commands/power.ts +163 -163
  88. package/src/commands/rpi.ts +45 -45
  89. package/src/commands/screenshot.ts +166 -166
  90. package/src/commands/serial.ts +17 -17
  91. package/src/commands/update.ts +124 -124
  92. package/src/index.ts +652 -652
  93. package/src/lib/config.ts +69 -69
  94. package/src/lib/identity.ts +40 -40
  95. package/src/lib/logger.ts +137 -137
  96. package/src/lib/platform.ts +10 -10
  97. package/src/lib/rpi.ts +180 -180
  98. package/src/lib/screens.ts +128 -128
  99. package/src/lib/types.ts +176 -176
  100. package/src/services/commands.ts +107 -107
  101. package/src/services/health.ts +161 -161
  102. package/src/services/kiosk.ts +384 -384
  103. package/src/services/localEvents.ts +60 -60
  104. package/src/services/logForwarder.ts +72 -72
  105. package/src/services/multiScreenKiosk.ts +324 -324
  106. package/src/services/oscBridge.ts +186 -186
  107. package/src/services/powerScheduler.ts +260 -260
  108. package/src/services/provisioning.ts +120 -120
  109. package/src/services/serialBridge.ts +230 -230
  110. package/src/services/serviceLauncher.ts +183 -183
  111. package/src/services/staticServer.ts +226 -226
  112. package/src/services/updater.ts +249 -249
  113. package/src/services/watchdog.ts +310 -310
  114. package/src/services/websocket.ts +152 -152
  115. package/tsconfig.json +28 -28
@@ -1,120 +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
-
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
- }
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
+ }