lightman-agent 1.0.21 → 1.0.23
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/bin/cms-agent.js +39 -60
- package/package.json +1 -1
- package/scripts/guardian.ps1 +25 -6
- package/scripts/install-linux.sh +4 -4
- package/scripts/install-windows.ps1 +159 -51
- package/scripts/launch-kiosk.vbs +23 -7
- package/scripts/lightman-shell.bat +30 -9
- package/scripts/setup.ps1 +25 -9
- package/scripts/setup.sh +4 -4
- package/src/index.ts +142 -142
- package/src/lib/screenMap.ts +135 -135
- package/src/services/multiScreenKiosk.ts +356 -356
package/src/lib/screenMap.ts
CHANGED
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
import type { DetectedScreen } from './screens.js';
|
|
2
|
-
import type { ScreenMapping } from './types.js';
|
|
3
|
-
|
|
4
|
-
export type ScreenMapMode = 'none' | 'explicit' | 'explicit+autofill' | 'auto';
|
|
5
|
-
|
|
6
|
-
export interface ResolveScreenMapInput {
|
|
7
|
-
requestedScreenMap: ScreenMapping[];
|
|
8
|
-
detectedScreens: DetectedScreen[];
|
|
9
|
-
totalScreens?: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ResolveScreenMapResult {
|
|
13
|
-
screenMap: ScreenMapping[];
|
|
14
|
-
mode: ScreenMapMode;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function resolveScreenMap(input: ResolveScreenMapInput): ResolveScreenMapResult {
|
|
18
|
-
const requested = (input.requestedScreenMap || []).map((m) => ({
|
|
19
|
-
hardwareId: String(m.hardwareId || '').trim(),
|
|
20
|
-
url: String(m.url || ''),
|
|
21
|
-
label: m.label,
|
|
22
|
-
}));
|
|
23
|
-
const detected = [...(input.detectedScreens || [])].sort((a, b) => a.index - b.index);
|
|
24
|
-
const targetCount = Math.max(requested.length, normalizePositiveInt(input.totalScreens));
|
|
25
|
-
|
|
26
|
-
if (targetCount === 0) {
|
|
27
|
-
return { screenMap: [], mode: 'none' };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const explicitByIndex = new Map<number, string>();
|
|
31
|
-
const reservedForExplicit = new Set<string>();
|
|
32
|
-
for (let idx = 0; idx < targetCount; idx++) {
|
|
33
|
-
const requestedId = requested[idx]?.hardwareId || '';
|
|
34
|
-
if (!requestedId) continue;
|
|
35
|
-
const resolved = resolveDetectedScreen(requestedId, detected);
|
|
36
|
-
if (!resolved) continue;
|
|
37
|
-
const key = toKey(resolved.hardwareId);
|
|
38
|
-
if (reservedForExplicit.has(key)) continue;
|
|
39
|
-
explicitByIndex.set(idx, resolved.hardwareId);
|
|
40
|
-
reservedForExplicit.add(key);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const used = new Set<string>();
|
|
44
|
-
const screenMap: ScreenMapping[] = [];
|
|
45
|
-
let explicitEntries = 0;
|
|
46
|
-
let autofilledEntries = 0;
|
|
47
|
-
|
|
48
|
-
for (let idx = 0; idx < targetCount; idx++) {
|
|
49
|
-
const requestedEntry = requested[idx];
|
|
50
|
-
const requestedId = requestedEntry?.hardwareId || '';
|
|
51
|
-
const requestedUrl = requestedEntry?.url || '';
|
|
52
|
-
const requestedLabel = requestedEntry?.label;
|
|
53
|
-
|
|
54
|
-
let finalHardwareId = requestedId;
|
|
55
|
-
const explicitResolved = explicitByIndex.get(idx);
|
|
56
|
-
if (explicitResolved) {
|
|
57
|
-
explicitEntries++;
|
|
58
|
-
finalHardwareId = explicitResolved;
|
|
59
|
-
} else if (requestedId) {
|
|
60
|
-
explicitEntries++;
|
|
61
|
-
const fallbackPreferred = detected.find((s) => (
|
|
62
|
-
!used.has(toKey(s.hardwareId)) && !reservedForExplicit.has(toKey(s.hardwareId))
|
|
63
|
-
));
|
|
64
|
-
const fallbackAny = fallbackPreferred || detected.find((s) => !used.has(toKey(s.hardwareId)));
|
|
65
|
-
if (fallbackAny) {
|
|
66
|
-
finalHardwareId = fallbackAny.hardwareId;
|
|
67
|
-
autofilledEntries++;
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
const fallbackPreferred = detected.find((s) => (
|
|
71
|
-
!used.has(toKey(s.hardwareId)) && !reservedForExplicit.has(toKey(s.hardwareId))
|
|
72
|
-
));
|
|
73
|
-
const fallbackAny = fallbackPreferred || detected.find((s) => !used.has(toKey(s.hardwareId)));
|
|
74
|
-
if (fallbackAny) {
|
|
75
|
-
finalHardwareId = fallbackAny.hardwareId;
|
|
76
|
-
autofilledEntries++;
|
|
77
|
-
} else {
|
|
78
|
-
finalHardwareId = '';
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (finalHardwareId) {
|
|
83
|
-
used.add(toKey(finalHardwareId));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const entry: ScreenMapping = {
|
|
87
|
-
hardwareId: finalHardwareId,
|
|
88
|
-
url: requestedUrl,
|
|
89
|
-
};
|
|
90
|
-
if (requestedLabel) {
|
|
91
|
-
entry.label = requestedLabel;
|
|
92
|
-
}
|
|
93
|
-
screenMap.push(entry);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
screenMap,
|
|
98
|
-
mode: inferMode(explicitEntries, autofilledEntries),
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function resolveDetectedScreen(id: string, detectedScreens: DetectedScreen[]): DetectedScreen | undefined {
|
|
103
|
-
const requested = String(id || '').trim();
|
|
104
|
-
if (!requested) return undefined;
|
|
105
|
-
|
|
106
|
-
const direct = detectedScreens.find((s) => toKey(s.hardwareId) === toKey(requested));
|
|
107
|
-
if (direct) return direct;
|
|
108
|
-
|
|
109
|
-
if (/^\d+$/.test(requested)) {
|
|
110
|
-
const suffix = 'DISPLAY' + requested;
|
|
111
|
-
return detectedScreens.find((s) => {
|
|
112
|
-
const hw = s.hardwareId.toUpperCase();
|
|
113
|
-
return hw.endsWith(suffix) && (hw.length === suffix.length || hw[hw.length - suffix.length - 1] === '\\');
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function normalizePositiveInt(value: number | undefined): number {
|
|
121
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) return 0;
|
|
122
|
-
const n = Math.floor(value);
|
|
123
|
-
return n > 0 ? n : 0;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function inferMode(explicitEntries: number, autofilledEntries: number): ScreenMapMode {
|
|
127
|
-
if (explicitEntries === 0 && autofilledEntries === 0) return 'none';
|
|
128
|
-
if (explicitEntries === 0 && autofilledEntries > 0) return 'auto';
|
|
129
|
-
if (autofilledEntries > 0) return 'explicit+autofill';
|
|
130
|
-
return 'explicit';
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function toKey(hardwareId: string): string {
|
|
134
|
-
return hardwareId.toUpperCase();
|
|
135
|
-
}
|
|
1
|
+
import type { DetectedScreen } from './screens.js';
|
|
2
|
+
import type { ScreenMapping } from './types.js';
|
|
3
|
+
|
|
4
|
+
export type ScreenMapMode = 'none' | 'explicit' | 'explicit+autofill' | 'auto';
|
|
5
|
+
|
|
6
|
+
export interface ResolveScreenMapInput {
|
|
7
|
+
requestedScreenMap: ScreenMapping[];
|
|
8
|
+
detectedScreens: DetectedScreen[];
|
|
9
|
+
totalScreens?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ResolveScreenMapResult {
|
|
13
|
+
screenMap: ScreenMapping[];
|
|
14
|
+
mode: ScreenMapMode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function resolveScreenMap(input: ResolveScreenMapInput): ResolveScreenMapResult {
|
|
18
|
+
const requested = (input.requestedScreenMap || []).map((m) => ({
|
|
19
|
+
hardwareId: String(m.hardwareId || '').trim(),
|
|
20
|
+
url: String(m.url || ''),
|
|
21
|
+
label: m.label,
|
|
22
|
+
}));
|
|
23
|
+
const detected = [...(input.detectedScreens || [])].sort((a, b) => a.index - b.index);
|
|
24
|
+
const targetCount = Math.max(requested.length, normalizePositiveInt(input.totalScreens));
|
|
25
|
+
|
|
26
|
+
if (targetCount === 0) {
|
|
27
|
+
return { screenMap: [], mode: 'none' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const explicitByIndex = new Map<number, string>();
|
|
31
|
+
const reservedForExplicit = new Set<string>();
|
|
32
|
+
for (let idx = 0; idx < targetCount; idx++) {
|
|
33
|
+
const requestedId = requested[idx]?.hardwareId || '';
|
|
34
|
+
if (!requestedId) continue;
|
|
35
|
+
const resolved = resolveDetectedScreen(requestedId, detected);
|
|
36
|
+
if (!resolved) continue;
|
|
37
|
+
const key = toKey(resolved.hardwareId);
|
|
38
|
+
if (reservedForExplicit.has(key)) continue;
|
|
39
|
+
explicitByIndex.set(idx, resolved.hardwareId);
|
|
40
|
+
reservedForExplicit.add(key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const used = new Set<string>();
|
|
44
|
+
const screenMap: ScreenMapping[] = [];
|
|
45
|
+
let explicitEntries = 0;
|
|
46
|
+
let autofilledEntries = 0;
|
|
47
|
+
|
|
48
|
+
for (let idx = 0; idx < targetCount; idx++) {
|
|
49
|
+
const requestedEntry = requested[idx];
|
|
50
|
+
const requestedId = requestedEntry?.hardwareId || '';
|
|
51
|
+
const requestedUrl = requestedEntry?.url || '';
|
|
52
|
+
const requestedLabel = requestedEntry?.label;
|
|
53
|
+
|
|
54
|
+
let finalHardwareId = requestedId;
|
|
55
|
+
const explicitResolved = explicitByIndex.get(idx);
|
|
56
|
+
if (explicitResolved) {
|
|
57
|
+
explicitEntries++;
|
|
58
|
+
finalHardwareId = explicitResolved;
|
|
59
|
+
} else if (requestedId) {
|
|
60
|
+
explicitEntries++;
|
|
61
|
+
const fallbackPreferred = detected.find((s) => (
|
|
62
|
+
!used.has(toKey(s.hardwareId)) && !reservedForExplicit.has(toKey(s.hardwareId))
|
|
63
|
+
));
|
|
64
|
+
const fallbackAny = fallbackPreferred || detected.find((s) => !used.has(toKey(s.hardwareId)));
|
|
65
|
+
if (fallbackAny) {
|
|
66
|
+
finalHardwareId = fallbackAny.hardwareId;
|
|
67
|
+
autofilledEntries++;
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
const fallbackPreferred = detected.find((s) => (
|
|
71
|
+
!used.has(toKey(s.hardwareId)) && !reservedForExplicit.has(toKey(s.hardwareId))
|
|
72
|
+
));
|
|
73
|
+
const fallbackAny = fallbackPreferred || detected.find((s) => !used.has(toKey(s.hardwareId)));
|
|
74
|
+
if (fallbackAny) {
|
|
75
|
+
finalHardwareId = fallbackAny.hardwareId;
|
|
76
|
+
autofilledEntries++;
|
|
77
|
+
} else {
|
|
78
|
+
finalHardwareId = '';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (finalHardwareId) {
|
|
83
|
+
used.add(toKey(finalHardwareId));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const entry: ScreenMapping = {
|
|
87
|
+
hardwareId: finalHardwareId,
|
|
88
|
+
url: requestedUrl,
|
|
89
|
+
};
|
|
90
|
+
if (requestedLabel) {
|
|
91
|
+
entry.label = requestedLabel;
|
|
92
|
+
}
|
|
93
|
+
screenMap.push(entry);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
screenMap,
|
|
98
|
+
mode: inferMode(explicitEntries, autofilledEntries),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function resolveDetectedScreen(id: string, detectedScreens: DetectedScreen[]): DetectedScreen | undefined {
|
|
103
|
+
const requested = String(id || '').trim();
|
|
104
|
+
if (!requested) return undefined;
|
|
105
|
+
|
|
106
|
+
const direct = detectedScreens.find((s) => toKey(s.hardwareId) === toKey(requested));
|
|
107
|
+
if (direct) return direct;
|
|
108
|
+
|
|
109
|
+
if (/^\d+$/.test(requested)) {
|
|
110
|
+
const suffix = 'DISPLAY' + requested;
|
|
111
|
+
return detectedScreens.find((s) => {
|
|
112
|
+
const hw = s.hardwareId.toUpperCase();
|
|
113
|
+
return hw.endsWith(suffix) && (hw.length === suffix.length || hw[hw.length - suffix.length - 1] === '\\');
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function normalizePositiveInt(value: number | undefined): number {
|
|
121
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) return 0;
|
|
122
|
+
const n = Math.floor(value);
|
|
123
|
+
return n > 0 ? n : 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function inferMode(explicitEntries: number, autofilledEntries: number): ScreenMapMode {
|
|
127
|
+
if (explicitEntries === 0 && autofilledEntries === 0) return 'none';
|
|
128
|
+
if (explicitEntries === 0 && autofilledEntries > 0) return 'auto';
|
|
129
|
+
if (autofilledEntries > 0) return 'explicit+autofill';
|
|
130
|
+
return 'explicit';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function toKey(hardwareId: string): string {
|
|
134
|
+
return hardwareId.toUpperCase();
|
|
135
|
+
}
|