@ytspar/sweetlink 1.13.0 → 1.15.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 +294 -40
- package/claude-skills/screenshot/SKILL.md +141 -20
- package/dist/cli/outputSchemas.d.ts +16 -0
- package/dist/cli/outputSchemas.d.ts.map +1 -1
- package/dist/cli/outputSchemas.js +33 -0
- package/dist/cli/outputSchemas.js.map +1 -1
- package/dist/cli/sweetlink-dev.js +0 -0
- package/dist/cli/sweetlink.js +639 -11
- package/dist/cli/sweetlink.js.map +1 -1
- package/dist/daemon/browser.d.ts +58 -0
- package/dist/daemon/browser.d.ts.map +1 -0
- package/dist/daemon/browser.js +172 -0
- package/dist/daemon/browser.js.map +1 -0
- package/dist/daemon/client.d.ts +34 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +139 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/cursor.d.ts +15 -0
- package/dist/daemon/cursor.d.ts.map +1 -0
- package/dist/daemon/cursor.js +76 -0
- package/dist/daemon/cursor.js.map +1 -0
- package/dist/daemon/demo.d.ts +68 -0
- package/dist/daemon/demo.d.ts.map +1 -0
- package/dist/daemon/demo.js +247 -0
- package/dist/daemon/demo.js.map +1 -0
- package/dist/daemon/devices.d.ts +39 -0
- package/dist/daemon/devices.d.ts.map +1 -0
- package/dist/daemon/devices.js +101 -0
- package/dist/daemon/devices.js.map +1 -0
- package/dist/daemon/diff.d.ts +20 -0
- package/dist/daemon/diff.d.ts.map +1 -0
- package/dist/daemon/diff.js +181 -0
- package/dist/daemon/diff.js.map +1 -0
- package/dist/daemon/errorPatterns.d.ts +17 -0
- package/dist/daemon/errorPatterns.d.ts.map +1 -0
- package/dist/daemon/errorPatterns.js +81 -0
- package/dist/daemon/errorPatterns.js.map +1 -0
- package/dist/daemon/evidence.d.ts +29 -0
- package/dist/daemon/evidence.d.ts.map +1 -0
- package/dist/daemon/evidence.js +131 -0
- package/dist/daemon/evidence.js.map +1 -0
- package/dist/daemon/index.d.ts +10 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +102 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/listeners.d.ts +55 -0
- package/dist/daemon/listeners.d.ts.map +1 -0
- package/dist/daemon/listeners.js +129 -0
- package/dist/daemon/listeners.js.map +1 -0
- package/dist/daemon/recording.d.ts +54 -0
- package/dist/daemon/recording.d.ts.map +1 -0
- package/dist/daemon/recording.js +216 -0
- package/dist/daemon/recording.js.map +1 -0
- package/dist/daemon/refs.d.ts +70 -0
- package/dist/daemon/refs.d.ts.map +1 -0
- package/dist/daemon/refs.js +185 -0
- package/dist/daemon/refs.js.map +1 -0
- package/dist/daemon/ringBuffer.d.ts +26 -0
- package/dist/daemon/ringBuffer.d.ts.map +1 -0
- package/dist/daemon/ringBuffer.js +54 -0
- package/dist/daemon/ringBuffer.js.map +1 -0
- package/dist/daemon/server.d.ts +23 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +585 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/session.d.ts +47 -0
- package/dist/daemon/session.d.ts.map +1 -0
- package/dist/daemon/session.js +8 -0
- package/dist/daemon/session.js.map +1 -0
- package/dist/daemon/stateFile.d.ts +56 -0
- package/dist/daemon/stateFile.d.ts.map +1 -0
- package/dist/daemon/stateFile.js +178 -0
- package/dist/daemon/stateFile.js.map +1 -0
- package/dist/daemon/summary.d.ts +28 -0
- package/dist/daemon/summary.d.ts.map +1 -0
- package/dist/daemon/summary.js +152 -0
- package/dist/daemon/summary.js.map +1 -0
- package/dist/daemon/types.d.ts +72 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +28 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/daemon/viewer.d.ts +24 -0
- package/dist/daemon/viewer.d.ts.map +1 -0
- package/dist/daemon/viewer.js +567 -0
- package/dist/daemon/viewer.js.map +1 -0
- package/dist/daemon/visualDiff.d.ts +34 -0
- package/dist/daemon/visualDiff.d.ts.map +1 -0
- package/dist/daemon/visualDiff.js +80 -0
- package/dist/daemon/visualDiff.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +173 -0
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +19 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +13 -0
- package/dist/vite.js.map +1 -1
- package/package.json +20 -12
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon HTTP Server
|
|
3
|
+
*
|
|
4
|
+
* Localhost-only HTTP server with bearer token auth.
|
|
5
|
+
* Routes POST requests to /api/{action} and dispatches to handlers.
|
|
6
|
+
* Manages idle timer for auto-shutdown.
|
|
7
|
+
*/
|
|
8
|
+
import { createServer } from 'http';
|
|
9
|
+
import { closeBrowser, getBrowserInstance, getPage, initBrowser, takeResponsiveScreenshots, takeScreenshot } from './browser.js';
|
|
10
|
+
import { annotateScreenshot, diffSnapshots } from './diff.js';
|
|
11
|
+
import { takeDeviceScreenshots } from './devices.js';
|
|
12
|
+
import { consoleBuffer, dialogBuffer, formatConsoleEntries, formatNetworkEntries, getErrorCount, getWarningCount, networkBuffer, } from './listeners.js';
|
|
13
|
+
import { getRecordingPage, getRecordingStatus, isRecording, logAction, startRecording, stopRecording } from './recording.js';
|
|
14
|
+
import { detectServerErrors } from './errorPatterns.js';
|
|
15
|
+
import { generateSummary } from './summary.js';
|
|
16
|
+
import { generateViewer } from './viewer.js';
|
|
17
|
+
import { visualDiff } from './visualDiff.js';
|
|
18
|
+
import { buildRefMap, checkRefStale, formatRefMap, getBaseline, getCurrentRefMap, resolveRef, setBaseline, } from './refs.js';
|
|
19
|
+
import { DAEMON_IDLE_TIMEOUT_MS, DEFAULT_RESPONSIVE_VIEWPORTS } from './types.js';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// State
|
|
22
|
+
// ============================================================================
|
|
23
|
+
let httpServer = null;
|
|
24
|
+
let idleTimer = null;
|
|
25
|
+
let shutdownCallback = null;
|
|
26
|
+
let daemonPort = null;
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Idle Timer
|
|
29
|
+
// ============================================================================
|
|
30
|
+
function resetIdleTimer() {
|
|
31
|
+
if (idleTimer)
|
|
32
|
+
clearTimeout(idleTimer);
|
|
33
|
+
idleTimer = setTimeout(() => {
|
|
34
|
+
console.error('[Daemon] Idle timeout reached. Shutting down...');
|
|
35
|
+
shutdown();
|
|
36
|
+
}, DAEMON_IDLE_TIMEOUT_MS);
|
|
37
|
+
}
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Action Handlers
|
|
40
|
+
// ============================================================================
|
|
41
|
+
async function handlePing() {
|
|
42
|
+
return { ok: true, data: { pong: true, timestamp: Date.now() } };
|
|
43
|
+
}
|
|
44
|
+
async function handleShutdown() {
|
|
45
|
+
// Schedule shutdown after response is sent
|
|
46
|
+
setTimeout(() => shutdown(), 100);
|
|
47
|
+
return { ok: true, data: { message: 'Daemon shutting down' } };
|
|
48
|
+
}
|
|
49
|
+
async function handleScreenshot(params, url) {
|
|
50
|
+
await initBrowser(url);
|
|
51
|
+
const { buffer, width, height } = await takeScreenshot({
|
|
52
|
+
selector: params.selector,
|
|
53
|
+
fullPage: params.fullPage,
|
|
54
|
+
viewport: params.viewport,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
data: {
|
|
59
|
+
screenshot: buffer.toString('base64'),
|
|
60
|
+
width,
|
|
61
|
+
height,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function handleResponsiveScreenshot(params, url) {
|
|
66
|
+
await initBrowser(url);
|
|
67
|
+
const viewports = params.viewports ?? DEFAULT_RESPONSIVE_VIEWPORTS;
|
|
68
|
+
const results = await takeResponsiveScreenshots({
|
|
69
|
+
viewports,
|
|
70
|
+
fullPage: params.fullPage,
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
data: {
|
|
75
|
+
screenshots: results.map((r) => ({
|
|
76
|
+
width: r.width,
|
|
77
|
+
height: r.height,
|
|
78
|
+
screenshot: r.buffer.toString('base64'),
|
|
79
|
+
label: r.label,
|
|
80
|
+
})),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// Ref System Handlers
|
|
86
|
+
// ============================================================================
|
|
87
|
+
async function handleSnapshot(params, url) {
|
|
88
|
+
await initBrowser(url);
|
|
89
|
+
const recPage = getRecordingPage();
|
|
90
|
+
const page = recPage ?? getPage();
|
|
91
|
+
const interactive = params.interactive;
|
|
92
|
+
const diff = params.diff;
|
|
93
|
+
const annotate = params.annotate;
|
|
94
|
+
// If diffing, we need the baseline before taking new snapshot
|
|
95
|
+
const baseline = diff ? getBaseline() : null;
|
|
96
|
+
const resolved = await buildRefMap(page, { interactive: interactive !== false });
|
|
97
|
+
// Handle diff mode
|
|
98
|
+
if (diff) {
|
|
99
|
+
if (!baseline) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
error: 'No baseline snapshot to diff against. Run `snapshot` first, then make changes, then `snapshot -D`.',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const diffText = diffSnapshots(baseline, resolved);
|
|
106
|
+
setBaseline(); // Update baseline for next diff
|
|
107
|
+
return {
|
|
108
|
+
ok: true,
|
|
109
|
+
data: {
|
|
110
|
+
diff: diffText,
|
|
111
|
+
tree: formatRefMap(resolved),
|
|
112
|
+
refs: resolved.entries,
|
|
113
|
+
count: resolved.entries.length,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Handle annotated screenshot mode
|
|
118
|
+
if (annotate) {
|
|
119
|
+
const currentRefs = getCurrentRefMap();
|
|
120
|
+
if (!currentRefs || currentRefs.entries.length === 0) {
|
|
121
|
+
return { ok: false, error: 'No refs to annotate. Run `snapshot -i` first.' };
|
|
122
|
+
}
|
|
123
|
+
const buffer = await annotateScreenshot(page, currentRefs);
|
|
124
|
+
setBaseline();
|
|
125
|
+
return {
|
|
126
|
+
ok: true,
|
|
127
|
+
data: {
|
|
128
|
+
screenshot: buffer.toString('base64'),
|
|
129
|
+
tree: formatRefMap(resolved),
|
|
130
|
+
refs: resolved.entries,
|
|
131
|
+
count: resolved.entries.length,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Default: set as baseline for future diffs
|
|
136
|
+
setBaseline();
|
|
137
|
+
return {
|
|
138
|
+
ok: true,
|
|
139
|
+
data: {
|
|
140
|
+
tree: formatRefMap(resolved),
|
|
141
|
+
refs: resolved.entries,
|
|
142
|
+
count: resolved.entries.length,
|
|
143
|
+
rawSnapshot: resolved.rawSnapshot,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function handleClickRef(params, url) {
|
|
148
|
+
await initBrowser(url);
|
|
149
|
+
// Use recording page if recording, otherwise main page
|
|
150
|
+
const recPage = getRecordingPage();
|
|
151
|
+
const page = recPage ?? getPage();
|
|
152
|
+
const ref = params.ref;
|
|
153
|
+
if (!ref)
|
|
154
|
+
return { ok: false, error: 'Missing ref parameter' };
|
|
155
|
+
const stale = await checkRefStale(page, ref);
|
|
156
|
+
if (stale) {
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: `Ref ${ref} is stale — element no longer exists. Run \`snapshot\` to get fresh refs.`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const locator = resolveRef(page, ref);
|
|
163
|
+
const box = await locator.boundingBox();
|
|
164
|
+
await locator.click();
|
|
165
|
+
// Log action if recording
|
|
166
|
+
if (isRecording()) {
|
|
167
|
+
await logAction('click', [ref], page, box ?? undefined);
|
|
168
|
+
}
|
|
169
|
+
return { ok: true, data: { clicked: ref } };
|
|
170
|
+
}
|
|
171
|
+
async function handleFillRef(params, url) {
|
|
172
|
+
await initBrowser(url);
|
|
173
|
+
const recPage = getRecordingPage();
|
|
174
|
+
const page = recPage ?? getPage();
|
|
175
|
+
const ref = params.ref;
|
|
176
|
+
const value = params.value;
|
|
177
|
+
if (!ref)
|
|
178
|
+
return { ok: false, error: 'Missing ref parameter' };
|
|
179
|
+
if (value === undefined)
|
|
180
|
+
return { ok: false, error: 'Missing value parameter' };
|
|
181
|
+
const stale = await checkRefStale(page, ref);
|
|
182
|
+
if (stale) {
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
error: `Ref ${ref} is stale — element no longer exists. Run \`snapshot\` to get fresh refs.`,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const locator = resolveRef(page, ref);
|
|
189
|
+
const box = await locator.boundingBox();
|
|
190
|
+
await locator.fill(value);
|
|
191
|
+
if (isRecording()) {
|
|
192
|
+
await logAction('fill', [ref, value], page, box ?? undefined);
|
|
193
|
+
}
|
|
194
|
+
return { ok: true, data: { filled: ref, value } };
|
|
195
|
+
}
|
|
196
|
+
async function handleHoverRef(params, url) {
|
|
197
|
+
await initBrowser(url);
|
|
198
|
+
const page = getPage();
|
|
199
|
+
const ref = params.ref;
|
|
200
|
+
if (!ref)
|
|
201
|
+
return { ok: false, error: 'Missing ref parameter' };
|
|
202
|
+
const stale = await checkRefStale(page, ref);
|
|
203
|
+
if (stale) {
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
error: `Ref ${ref} is stale — element no longer exists. Run \`snapshot\` to get fresh refs.`,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const locator = resolveRef(page, ref);
|
|
210
|
+
await locator.hover();
|
|
211
|
+
return { ok: true, data: { hovered: ref } };
|
|
212
|
+
}
|
|
213
|
+
async function handlePressKey(params, url) {
|
|
214
|
+
await initBrowser(url);
|
|
215
|
+
const page = getPage();
|
|
216
|
+
const key = params.key;
|
|
217
|
+
if (!key)
|
|
218
|
+
return { ok: false, error: 'Missing key parameter' };
|
|
219
|
+
await page.keyboard.press(key);
|
|
220
|
+
return { ok: true, data: { pressed: key } };
|
|
221
|
+
}
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Ring Buffer Handlers
|
|
224
|
+
// ============================================================================
|
|
225
|
+
async function handleConsoleRead(params) {
|
|
226
|
+
const errorsOnly = params.errors;
|
|
227
|
+
const last = params.last;
|
|
228
|
+
let entries = errorsOnly
|
|
229
|
+
? consoleBuffer.filter((e) => e.level === 'error')
|
|
230
|
+
: consoleBuffer.toArray();
|
|
231
|
+
if (last) {
|
|
232
|
+
entries = entries.slice(-last);
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
ok: true,
|
|
236
|
+
data: {
|
|
237
|
+
entries,
|
|
238
|
+
formatted: formatConsoleEntries(entries),
|
|
239
|
+
total: consoleBuffer.size,
|
|
240
|
+
errorCount: getErrorCount(),
|
|
241
|
+
warningCount: getWarningCount(),
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async function handleNetworkRead(params) {
|
|
246
|
+
const failedOnly = params.failed;
|
|
247
|
+
const last = params.last;
|
|
248
|
+
let entries = failedOnly
|
|
249
|
+
? networkBuffer.filter((e) => e.status >= 400 || e.status === 0)
|
|
250
|
+
: networkBuffer.toArray();
|
|
251
|
+
if (last) {
|
|
252
|
+
entries = entries.slice(-last);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
data: {
|
|
257
|
+
entries,
|
|
258
|
+
formatted: formatNetworkEntries(entries),
|
|
259
|
+
total: networkBuffer.size,
|
|
260
|
+
failedCount: networkBuffer.filter((e) => e.status >= 400 || e.status === 0).length,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async function handleDialogRead() {
|
|
265
|
+
const entries = dialogBuffer.toArray();
|
|
266
|
+
return {
|
|
267
|
+
ok: true,
|
|
268
|
+
data: { entries, total: dialogBuffer.size },
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async function handleScreenshotDevices(params, url) {
|
|
272
|
+
await initBrowser(url);
|
|
273
|
+
const page = getPage();
|
|
274
|
+
const devices = params.devices;
|
|
275
|
+
if (!devices || devices.length === 0) {
|
|
276
|
+
return { ok: false, error: 'Missing devices parameter' };
|
|
277
|
+
}
|
|
278
|
+
const results = await takeDeviceScreenshots(page, devices, {
|
|
279
|
+
fullPage: params.fullPage,
|
|
280
|
+
});
|
|
281
|
+
return {
|
|
282
|
+
ok: true,
|
|
283
|
+
data: {
|
|
284
|
+
screenshots: results.map((r) => ({
|
|
285
|
+
device: r.device.name,
|
|
286
|
+
width: r.device.viewport.width,
|
|
287
|
+
height: r.device.viewport.height,
|
|
288
|
+
screenshot: r.buffer.toString('base64'),
|
|
289
|
+
})),
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
async function handleRecordStart(url) {
|
|
294
|
+
await initBrowser(url);
|
|
295
|
+
const browser = getBrowserInstance();
|
|
296
|
+
const result = await startRecording(browser, url, '.sweetlink');
|
|
297
|
+
return { ok: true, data: { sessionId: result.sessionId } };
|
|
298
|
+
}
|
|
299
|
+
async function handleRecordStop() {
|
|
300
|
+
const manifest = await stopRecording();
|
|
301
|
+
if (!manifest) {
|
|
302
|
+
return { ok: false, error: 'No recording in progress' };
|
|
303
|
+
}
|
|
304
|
+
// Auto-generate viewer HTML + summary report
|
|
305
|
+
const sessionDir = `.sweetlink/${manifest.sessionId}`;
|
|
306
|
+
let viewerPath;
|
|
307
|
+
let summaryPath;
|
|
308
|
+
try {
|
|
309
|
+
const consoleLogs = consoleBuffer.toArray();
|
|
310
|
+
const networkLogs = networkBuffer.toArray();
|
|
311
|
+
viewerPath = await generateViewer(manifest, {
|
|
312
|
+
sessionDir,
|
|
313
|
+
consoleEntries: consoleLogs,
|
|
314
|
+
networkEntries: networkLogs,
|
|
315
|
+
});
|
|
316
|
+
// Generate SUMMARY.md
|
|
317
|
+
const { promises: fsp } = await import('fs');
|
|
318
|
+
// Detect server errors from console log messages
|
|
319
|
+
const consoleText = consoleLogs.map(e => e.message).join('\n');
|
|
320
|
+
const serverErrors = detectServerErrors(consoleText);
|
|
321
|
+
if (serverErrors.length > 0) {
|
|
322
|
+
manifest.errors.server = serverErrors.length;
|
|
323
|
+
}
|
|
324
|
+
const summaryMd = generateSummary({
|
|
325
|
+
manifest,
|
|
326
|
+
consoleEntries: consoleLogs,
|
|
327
|
+
networkEntries: networkLogs,
|
|
328
|
+
serverErrors: serverErrors.map(e => ({
|
|
329
|
+
source: 'server',
|
|
330
|
+
message: e.line,
|
|
331
|
+
timestamp: Date.now(),
|
|
332
|
+
code: e.language,
|
|
333
|
+
})),
|
|
334
|
+
gitBranch: manifest.gitBranch,
|
|
335
|
+
gitCommit: manifest.gitCommit,
|
|
336
|
+
});
|
|
337
|
+
summaryPath = `${sessionDir}/SUMMARY.md`;
|
|
338
|
+
await fsp.writeFile(summaryPath, summaryMd, 'utf-8');
|
|
339
|
+
console.error(`[Daemon] Summary saved: ${summaryPath}`);
|
|
340
|
+
}
|
|
341
|
+
catch (e) {
|
|
342
|
+
console.error('[Daemon] Report generation error:', e);
|
|
343
|
+
}
|
|
344
|
+
// Include a browser-accessible URL for the viewer
|
|
345
|
+
const viewerUrl = manifest.sessionId && daemonPort ? `http://127.0.0.1:${daemonPort}/viewer/${manifest.sessionId}` : undefined;
|
|
346
|
+
return { ok: true, data: { manifest, viewerPath, viewerUrl, summaryPath } };
|
|
347
|
+
}
|
|
348
|
+
async function handleRecordStatus() {
|
|
349
|
+
const status = getRecordingStatus();
|
|
350
|
+
return { ok: true, data: status };
|
|
351
|
+
}
|
|
352
|
+
async function handleGenerateViewer(params) {
|
|
353
|
+
const sessionDir = params.sessionDir;
|
|
354
|
+
const outputPath = params.outputPath;
|
|
355
|
+
if (!sessionDir)
|
|
356
|
+
return { ok: false, error: 'Missing sessionDir parameter' };
|
|
357
|
+
try {
|
|
358
|
+
const { promises: fsp } = await import('fs');
|
|
359
|
+
const manifestRaw = await fsp.readFile(`${sessionDir}/sweetlink-session.json`, 'utf-8');
|
|
360
|
+
const manifest = JSON.parse(manifestRaw);
|
|
361
|
+
const viewerPath = await generateViewer(manifest, {
|
|
362
|
+
sessionDir,
|
|
363
|
+
outputPath,
|
|
364
|
+
consoleEntries: consoleBuffer.toArray(),
|
|
365
|
+
networkEntries: networkBuffer.toArray(),
|
|
366
|
+
});
|
|
367
|
+
return { ok: true, data: { viewerPath } };
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
return { ok: false, error: `Failed to generate viewer: ${error instanceof Error ? error.message : error}` };
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async function handleVisualDiff(params) {
|
|
374
|
+
const baseline = params.baseline;
|
|
375
|
+
const current = params.current;
|
|
376
|
+
const threshold = params.threshold;
|
|
377
|
+
if (!baseline || !current) {
|
|
378
|
+
return { ok: false, error: 'Missing baseline or current parameter (base64 encoded PNG)' };
|
|
379
|
+
}
|
|
380
|
+
const baselineBuffer = Buffer.from(baseline, 'base64');
|
|
381
|
+
const currentBuffer = Buffer.from(current, 'base64');
|
|
382
|
+
const result = await visualDiff(baselineBuffer, currentBuffer, { threshold });
|
|
383
|
+
return {
|
|
384
|
+
ok: true,
|
|
385
|
+
data: {
|
|
386
|
+
mismatchPercentage: result.mismatchPercentage,
|
|
387
|
+
mismatchCount: result.mismatchCount,
|
|
388
|
+
totalPixels: result.totalPixels,
|
|
389
|
+
pass: result.pass,
|
|
390
|
+
},
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
// ============================================================================
|
|
394
|
+
// Request Handling
|
|
395
|
+
// ============================================================================
|
|
396
|
+
async function handleRequest(action, params, url) {
|
|
397
|
+
switch (action) {
|
|
398
|
+
case 'ping':
|
|
399
|
+
return handlePing();
|
|
400
|
+
case 'shutdown':
|
|
401
|
+
return handleShutdown();
|
|
402
|
+
case 'screenshot':
|
|
403
|
+
return handleScreenshot(params, url);
|
|
404
|
+
case 'screenshot-responsive':
|
|
405
|
+
return handleResponsiveScreenshot(params, url);
|
|
406
|
+
case 'snapshot':
|
|
407
|
+
return handleSnapshot(params, url);
|
|
408
|
+
case 'click-ref':
|
|
409
|
+
return handleClickRef(params, url);
|
|
410
|
+
case 'fill-ref':
|
|
411
|
+
return handleFillRef(params, url);
|
|
412
|
+
case 'hover-ref':
|
|
413
|
+
return handleHoverRef(params, url);
|
|
414
|
+
case 'press-key':
|
|
415
|
+
return handlePressKey(params, url);
|
|
416
|
+
case 'console-read':
|
|
417
|
+
return handleConsoleRead(params);
|
|
418
|
+
case 'network-read':
|
|
419
|
+
return handleNetworkRead(params);
|
|
420
|
+
case 'dialog-read':
|
|
421
|
+
return handleDialogRead();
|
|
422
|
+
case 'screenshot-devices':
|
|
423
|
+
return handleScreenshotDevices(params, url);
|
|
424
|
+
case 'visual-diff':
|
|
425
|
+
return handleVisualDiff(params);
|
|
426
|
+
case 'record-start':
|
|
427
|
+
return handleRecordStart(url);
|
|
428
|
+
case 'record-stop':
|
|
429
|
+
return handleRecordStop();
|
|
430
|
+
case 'record-status':
|
|
431
|
+
return handleRecordStatus();
|
|
432
|
+
case 'generate-viewer':
|
|
433
|
+
return handleGenerateViewer(params);
|
|
434
|
+
default:
|
|
435
|
+
return { ok: false, error: `Unknown action: ${action}` };
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function readBody(req) {
|
|
439
|
+
return new Promise((resolve, reject) => {
|
|
440
|
+
const chunks = [];
|
|
441
|
+
let size = 0;
|
|
442
|
+
const MAX_BODY = 10 * 1024 * 1024; // 10MB max (visual-diff sends two screenshots)
|
|
443
|
+
req.on('data', (chunk) => {
|
|
444
|
+
size += chunk.length;
|
|
445
|
+
if (size > MAX_BODY) {
|
|
446
|
+
req.destroy();
|
|
447
|
+
reject(new Error('Request body too large'));
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
chunks.push(chunk);
|
|
451
|
+
});
|
|
452
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
453
|
+
req.on('error', reject);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
function sendJson(res, status, body) {
|
|
457
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
458
|
+
res.end(JSON.stringify(body));
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Start the daemon HTTP server.
|
|
462
|
+
* Binds to 127.0.0.1 (localhost only) on the specified port.
|
|
463
|
+
*/
|
|
464
|
+
export function startServer(options) {
|
|
465
|
+
return new Promise((resolve, reject) => {
|
|
466
|
+
shutdownCallback = options.onShutdown;
|
|
467
|
+
daemonPort = options.port;
|
|
468
|
+
httpServer = createServer(async (req, res) => {
|
|
469
|
+
// CORS preflight
|
|
470
|
+
if (req.method === 'OPTIONS') {
|
|
471
|
+
res.writeHead(204, {
|
|
472
|
+
'Access-Control-Allow-Origin': '*',
|
|
473
|
+
'Access-Control-Allow-Methods': 'POST',
|
|
474
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
475
|
+
});
|
|
476
|
+
res.end();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
// Serve viewer HTML via GET (no auth required — localhost only)
|
|
480
|
+
if (req.method === 'GET') {
|
|
481
|
+
const urlPath = req.url ?? '/';
|
|
482
|
+
const viewerMatch = urlPath.match(/^\/viewer\/([a-z0-9-]+)$/);
|
|
483
|
+
if (viewerMatch) {
|
|
484
|
+
const sid = viewerMatch[1];
|
|
485
|
+
try {
|
|
486
|
+
const { promises: fsp } = await import('fs');
|
|
487
|
+
const viewerHtml = await fsp.readFile(`.sweetlink/${sid}/viewer.html`, 'utf-8');
|
|
488
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
489
|
+
res.end(viewerHtml);
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
493
|
+
res.end('Viewer not found');
|
|
494
|
+
}
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
// GET /viewers — list available sessions
|
|
498
|
+
if (urlPath === '/viewers') {
|
|
499
|
+
try {
|
|
500
|
+
const { promises: fsp } = await import('fs');
|
|
501
|
+
const entries = await fsp.readdir('.sweetlink', { withFileTypes: true });
|
|
502
|
+
const sessions = entries
|
|
503
|
+
.filter(e => e.isDirectory() && e.name.startsWith('session-'))
|
|
504
|
+
.map(e => e.name)
|
|
505
|
+
.sort()
|
|
506
|
+
.reverse();
|
|
507
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
508
|
+
res.end(JSON.stringify({ sessions, daemonPort: options.port }));
|
|
509
|
+
}
|
|
510
|
+
catch {
|
|
511
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
512
|
+
res.end(JSON.stringify({ sessions: [] }));
|
|
513
|
+
}
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
sendJson(res, 404, { ok: false, error: 'Not found' });
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
// Only accept POST for API
|
|
520
|
+
if (req.method !== 'POST') {
|
|
521
|
+
sendJson(res, 405, { ok: false, error: 'Method not allowed' });
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
// Validate bearer token
|
|
525
|
+
const auth = req.headers.authorization;
|
|
526
|
+
if (!auth || auth !== `Bearer ${options.token}`) {
|
|
527
|
+
sendJson(res, 401, { ok: false, error: 'Unauthorized' });
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
// Parse action from URL path: /api/{action}
|
|
531
|
+
const urlPath = req.url ?? '/';
|
|
532
|
+
const match = urlPath.match(/^\/api\/([a-z-]+)$/);
|
|
533
|
+
if (!match) {
|
|
534
|
+
sendJson(res, 404, { ok: false, error: 'Not found' });
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const action = match[1];
|
|
538
|
+
// Reset idle timer on every valid request
|
|
539
|
+
resetIdleTimer();
|
|
540
|
+
try {
|
|
541
|
+
const body = await readBody(req);
|
|
542
|
+
const parsed = body ? JSON.parse(body) : {};
|
|
543
|
+
const params = parsed.params ?? {};
|
|
544
|
+
const response = await handleRequest(action, params, options.url);
|
|
545
|
+
sendJson(res, response.ok ? 200 : 400, response);
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
549
|
+
console.error('[Daemon] Request error:', message);
|
|
550
|
+
sendJson(res, 500, { ok: false, error: message });
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
httpServer.on('error', (error) => {
|
|
554
|
+
if (error.code === 'EADDRINUSE') {
|
|
555
|
+
reject(new Error(`Port ${options.port} is in use`));
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
reject(error);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
// Bind to localhost only
|
|
562
|
+
httpServer.listen(options.port, '127.0.0.1', () => {
|
|
563
|
+
console.error(`[Daemon] HTTP server listening on http://127.0.0.1:${options.port}`);
|
|
564
|
+
resetIdleTimer();
|
|
565
|
+
resolve();
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Shut down the daemon: close browser, close HTTP server, call shutdown callback.
|
|
571
|
+
*/
|
|
572
|
+
export async function shutdown() {
|
|
573
|
+
console.error('[Daemon] Shutting down...');
|
|
574
|
+
if (idleTimer) {
|
|
575
|
+
clearTimeout(idleTimer);
|
|
576
|
+
idleTimer = null;
|
|
577
|
+
}
|
|
578
|
+
await closeBrowser();
|
|
579
|
+
if (httpServer) {
|
|
580
|
+
httpServer.close();
|
|
581
|
+
httpServer = null;
|
|
582
|
+
}
|
|
583
|
+
shutdownCallback?.();
|
|
584
|
+
}
|
|
585
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manifest
|
|
3
|
+
*
|
|
4
|
+
* Machine-readable session description for viewer generation,
|
|
5
|
+
* report generation, and PR evidence upload.
|
|
6
|
+
*/
|
|
7
|
+
export interface ActionEntry {
|
|
8
|
+
/** Seconds since session start */
|
|
9
|
+
timestamp: number;
|
|
10
|
+
/** Command name (click, fill, snapshot, screenshot, etc.) */
|
|
11
|
+
action: string;
|
|
12
|
+
/** Command arguments */
|
|
13
|
+
args: string[];
|
|
14
|
+
/** Duration of the action in ms */
|
|
15
|
+
duration: number;
|
|
16
|
+
/** Bounding box of the target element (if applicable) */
|
|
17
|
+
boundingBox?: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
/** Screenshot filename taken at this action */
|
|
24
|
+
screenshot?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface SessionManifest {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
/** Target app URL that was recorded */
|
|
29
|
+
url?: string;
|
|
30
|
+
/** Git branch at time of recording */
|
|
31
|
+
gitBranch?: string;
|
|
32
|
+
/** Git commit SHA at time of recording */
|
|
33
|
+
gitCommit?: string;
|
|
34
|
+
startedAt: string;
|
|
35
|
+
endedAt: string;
|
|
36
|
+
/** Duration in seconds */
|
|
37
|
+
duration: number;
|
|
38
|
+
commands: ActionEntry[];
|
|
39
|
+
screenshots: string[];
|
|
40
|
+
video?: string;
|
|
41
|
+
errors: {
|
|
42
|
+
console: number;
|
|
43
|
+
network: number;
|
|
44
|
+
server: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/daemon/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,WAAW,CAAC,EAAE;QACZ,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH"}
|