@monoes/monobrowse 1.0.11 → 1.0.12
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/dist/src/__tests__/adapters.test.js +5 -2
- package/dist/src/__tests__/adapters.test.js.map +1 -1
- package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
- package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
- package/dist/src/__tests__/box-model.test.js +9 -5
- package/dist/src/__tests__/box-model.test.js.map +1 -1
- package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
- package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
- package/dist/src/__tests__/browser-launch.test.js +17 -10
- package/dist/src/__tests__/browser-launch.test.js.map +1 -1
- package/dist/src/__tests__/cdp-client.test.js +9 -3
- package/dist/src/__tests__/cdp-client.test.js.map +1 -1
- package/dist/src/__tests__/close-browser.test.d.ts +13 -0
- package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
- package/dist/src/__tests__/close-browser.test.js +5 -5
- package/dist/src/__tests__/close-browser.test.js.map +1 -1
- package/dist/src/__tests__/console-log.test.js +17 -6
- package/dist/src/__tests__/console-log.test.js.map +1 -1
- package/dist/src/__tests__/find.test.js +26 -6
- package/dist/src/__tests__/find.test.js.map +1 -1
- package/dist/src/__tests__/frame-command.test.js +9 -3
- package/dist/src/__tests__/frame-command.test.js.map +1 -1
- package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
- package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
- package/dist/src/__tests__/output.test.js +1 -1
- package/dist/src/__tests__/output.test.js.map +1 -1
- package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
- package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
- package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
- package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
- package/dist/src/__tests__/ref-cache.test.js +18 -10
- package/dist/src/__tests__/ref-cache.test.js.map +1 -1
- package/dist/src/__tests__/session-state.test.d.ts +8 -0
- package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
- package/dist/src/__tests__/session-state.test.js +10 -10
- package/dist/src/__tests__/session-state.test.js.map +1 -1
- package/dist/src/__tests__/snapshot.test.js +44 -14
- package/dist/src/__tests__/snapshot.test.js.map +1 -1
- package/dist/src/__tests__/storage-eval.test.js +14 -6
- package/dist/src/__tests__/storage-eval.test.js.map +1 -1
- package/dist/src/__tests__/tabs.test.js +25 -9
- package/dist/src/__tests__/tabs.test.js.map +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
- package/dist/src/browser/action-builder/analyzer.js +25 -9
- package/dist/src/browser/action-builder/analyzer.js.map +1 -1
- package/dist/src/browser/action-builder/types.d.ts.map +1 -1
- package/dist/src/browser/actions.d.ts +1 -1
- package/dist/src/browser/actions.d.ts.map +1 -1
- package/dist/src/browser/actions.js +16 -6
- package/dist/src/browser/actions.js.map +1 -1
- package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
- package/dist/src/browser/adapters/gemini.js.map +1 -1
- package/dist/src/browser/adapters/google.d.ts.map +1 -1
- package/dist/src/browser/adapters/google.js.map +1 -1
- package/dist/src/browser/adapters/index.d.ts.map +1 -1
- package/dist/src/browser/adapters/index.js +3 -3
- package/dist/src/browser/adapters/index.js.map +1 -1
- package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
- package/dist/src/browser/adapters/instagram.js.map +1 -1
- package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
- package/dist/src/browser/adapters/linkedin.js.map +1 -1
- package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
- package/dist/src/browser/adapters/microsoft.js.map +1 -1
- package/dist/src/browser/adapters/x.d.ts.map +1 -1
- package/dist/src/browser/adapters/x.js.map +1 -1
- package/dist/src/browser/browser.d.ts +30 -0
- package/dist/src/browser/browser.d.ts.map +1 -1
- package/dist/src/browser/browser.js +122 -15
- package/dist/src/browser/browser.js.map +1 -1
- package/dist/src/browser/cdp.d.ts.map +1 -1
- package/dist/src/browser/cdp.js +21 -8
- package/dist/src/browser/cdp.js.map +1 -1
- package/dist/src/browser/console-log.d.ts.map +1 -1
- package/dist/src/browser/console-log.js +2 -2
- package/dist/src/browser/console-log.js.map +1 -1
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +29 -19
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +153 -165
- package/dist/src/browser/dialog.d.ts.map +1 -1
- package/dist/src/browser/dialog.js +3 -1
- package/dist/src/browser/dialog.js.map +1 -1
- package/dist/src/browser/emulation.d.ts.map +1 -1
- package/dist/src/browser/emulation.js +21 -6
- package/dist/src/browser/emulation.js.map +1 -1
- package/dist/src/browser/find.d.ts +4 -4
- package/dist/src/browser/find.d.ts.map +1 -1
- package/dist/src/browser/find.js +14 -6
- package/dist/src/browser/find.js.map +1 -1
- package/dist/src/browser/har.d.ts.map +1 -1
- package/dist/src/browser/har.js +14 -7
- package/dist/src/browser/har.js.map +1 -1
- package/dist/src/browser/index.d.ts +16 -16
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +16 -16
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/browser/network.d.ts.map +1 -1
- package/dist/src/browser/network.js +14 -4
- package/dist/src/browser/network.js.map +1 -1
- package/dist/src/browser/pdf.d.ts.map +1 -1
- package/dist/src/browser/pdf.js +3 -3
- package/dist/src/browser/pdf.js.map +1 -1
- package/dist/src/browser/profiler.d.ts.map +1 -1
- package/dist/src/browser/profiler.js +10 -5
- package/dist/src/browser/profiler.js.map +1 -1
- package/dist/src/browser/record.d.ts +1 -1
- package/dist/src/browser/record.d.ts.map +1 -1
- package/dist/src/browser/record.js +18 -7
- package/dist/src/browser/record.js.map +1 -1
- package/dist/src/browser/ref-cache.d.ts.map +1 -1
- package/dist/src/browser/ref-cache.js +9 -4
- package/dist/src/browser/ref-cache.js.map +1 -1
- package/dist/src/browser/screenshot.d.ts.map +1 -1
- package/dist/src/browser/screenshot.js +11 -7
- package/dist/src/browser/screenshot.js.map +1 -1
- package/dist/src/browser/session.d.ts +1 -1
- package/dist/src/browser/session.d.ts.map +1 -1
- package/dist/src/browser/session.js +27 -8
- package/dist/src/browser/session.js.map +1 -1
- package/dist/src/browser/snapshot.d.ts +1 -1
- package/dist/src/browser/snapshot.d.ts.map +1 -1
- package/dist/src/browser/snapshot.js +8 -4
- package/dist/src/browser/snapshot.js.map +1 -1
- package/dist/src/browser/storage.d.ts.map +1 -1
- package/dist/src/browser/storage.js.map +1 -1
- package/dist/src/browser/tabs.d.ts.map +1 -1
- package/dist/src/browser/tabs.js +9 -3
- package/dist/src/browser/tabs.js.map +1 -1
- package/dist/src/browser/trace.d.ts.map +1 -1
- package/dist/src/browser/trace.js +3 -3
- package/dist/src/browser/trace.js.map +1 -1
- package/dist/src/browser/types.d.ts.map +1 -1
- package/dist/src/browser/types.js +23 -4
- package/dist/src/browser/types.js.map +1 -1
- package/dist/src/browser/vitals.d.ts.map +1 -1
- package/dist/src/browser/vitals.js +1 -1
- package/dist/src/browser/vitals.js.map +1 -1
- package/dist/src/browser/wait.d.ts.map +1 -1
- package/dist/src/browser/wait.js +11 -5
- package/dist/src/browser/wait.js.map +1 -1
- package/dist/src/cli/action.d.ts.map +1 -1
- package/dist/src/cli/action.js +14 -11
- package/dist/src/cli/action.js.map +1 -1
- package/dist/src/cli/commands.d.ts.map +1 -1
- package/dist/src/cli/commands.js +453 -159
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/output.js +5 -5
- package/dist/src/cli/output.js.map +1 -1
- package/dist/src/cli/platform.d.ts.map +1 -1
- package/dist/src/cli/platform.js +15 -11
- package/dist/src/cli/platform.js.map +1 -1
- package/dist/src/cli/types.d.ts +1 -1
- package/dist/src/cli/types.d.ts.map +1 -1
- package/dist/src/cli.js +21 -9
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/__tests__/adapters.test.ts +15 -8
- package/src/__tests__/batch-eval-parsing.test.ts +4 -2
- package/src/__tests__/box-model.test.ts +9 -5
- package/src/__tests__/browser-launch.test.ts +26 -15
- package/src/__tests__/cdp-client.test.ts +25 -9
- package/src/__tests__/close-browser.test.ts +11 -6
- package/src/__tests__/console-log.test.ts +36 -13
- package/src/__tests__/find.test.ts +58 -20
- package/src/__tests__/frame-command.test.ts +12 -6
- package/src/__tests__/open-url-navigate-error.test.ts +2 -4
- package/src/__tests__/output.test.ts +1 -1
- package/src/__tests__/reap-idle-browser.test.ts +276 -0
- package/src/__tests__/ref-cache.test.ts +25 -12
- package/src/__tests__/session-state.test.ts +40 -28
- package/src/__tests__/snapshot.test.ts +60 -21
- package/src/__tests__/storage-eval.test.ts +30 -16
- package/src/__tests__/tabs.test.ts +26 -10
- package/src/browser/action-builder/analyzer.ts +39 -15
- package/src/browser/action-builder/types.ts +45 -8
- package/src/browser/actions.ts +288 -123
- package/src/browser/adapters/gemini.ts +7 -3
- package/src/browser/adapters/google.ts +5 -3
- package/src/browser/adapters/index.ts +5 -4
- package/src/browser/adapters/instagram.ts +4 -2
- package/src/browser/adapters/linkedin.ts +4 -2
- package/src/browser/adapters/microsoft.ts +9 -5
- package/src/browser/adapters/x.ts +7 -3
- package/src/browser/browser.ts +188 -42
- package/src/browser/cdp.ts +43 -11
- package/src/browser/console-log.ts +24 -7
- package/src/browser/dashboard/server.ts +44 -25
- package/src/browser/dashboard/ui.html +153 -165
- package/src/browser/dialog.ts +25 -8
- package/src/browser/emulation.ts +86 -36
- package/src/browser/find.ts +110 -47
- package/src/browser/har.ts +58 -26
- package/src/browser/index.ts +16 -16
- package/src/browser/network.ts +147 -46
- package/src/browser/pdf.ts +4 -4
- package/src/browser/profiler.ts +23 -10
- package/src/browser/record.ts +38 -19
- package/src/browser/ref-cache.ts +38 -17
- package/src/browser/screenshot.ts +58 -32
- package/src/browser/session.ts +51 -18
- package/src/browser/snapshot.ts +34 -20
- package/src/browser/storage.ts +73 -17
- package/src/browser/tabs.ts +29 -17
- package/src/browser/trace.ts +14 -10
- package/src/browser/types.ts +23 -4
- package/src/browser/vitals.ts +33 -16
- package/src/browser/wait.ts +47 -21
- package/src/cli/action.ts +52 -21
- package/src/cli/commands.ts +1093 -385
- package/src/cli/output.ts +5 -5
- package/src/cli/platform.ts +44 -23
- package/src/cli/types.ts +1 -1
- package/src/cli.ts +34 -18
- package/src/index.ts +2 -2
|
@@ -33,7 +33,10 @@ function errorsFor(sessionId: string): PageError[] {
|
|
|
33
33
|
export function setupConsoleCapture(client: CdpClient, sessionId: string): void {
|
|
34
34
|
// Remove stale listeners from any prior connection on this sessionId
|
|
35
35
|
const prevOffs = _consoleListeners.get(sessionId);
|
|
36
|
-
if (prevOffs) {
|
|
36
|
+
if (prevOffs) {
|
|
37
|
+
for (const off of prevOffs) off();
|
|
38
|
+
_consoleListeners.delete(sessionId);
|
|
39
|
+
}
|
|
37
40
|
|
|
38
41
|
_consoleMessages.set(sessionId, []);
|
|
39
42
|
_pageErrors.set(sessionId, []);
|
|
@@ -52,7 +55,12 @@ export function setupConsoleCapture(client: CdpClient, sessionId: string): void
|
|
|
52
55
|
|
|
53
56
|
const off2 = client.on('Log.entryAdded', (params, sid) => {
|
|
54
57
|
if (sid !== sessionId) return;
|
|
55
|
-
const entry = params.entry as {
|
|
58
|
+
const entry = params.entry as {
|
|
59
|
+
level?: string;
|
|
60
|
+
text?: string;
|
|
61
|
+
url?: string;
|
|
62
|
+
lineNumber?: number;
|
|
63
|
+
};
|
|
56
64
|
// CDP uses 'warning' but ConsoleMessage type uses 'warn'
|
|
57
65
|
const rawLevel = entry.level === 'warning' ? 'warn' : entry.level;
|
|
58
66
|
messagesFor(sessionId).push({
|
|
@@ -92,29 +100,38 @@ export async function enableConsoleCapture(client: CdpClient, sessionId: string)
|
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
export function getConsoleMessages(sessionId?: string): ConsoleMessage[] {
|
|
95
|
-
if (sessionId) return [...
|
|
103
|
+
if (sessionId) return [...messagesFor(sessionId)];
|
|
96
104
|
// Fallback: return all messages across all sessions (legacy callers)
|
|
97
105
|
return [..._consoleMessages.values()].flat();
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
export function clearConsoleMessages(sessionId?: string): void {
|
|
101
|
-
if (sessionId) {
|
|
109
|
+
if (sessionId) {
|
|
110
|
+
_consoleMessages.set(sessionId, []);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
102
113
|
_consoleMessages.clear();
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
export function getPageErrors(sessionId?: string): PageError[] {
|
|
106
|
-
if (sessionId) return [...
|
|
117
|
+
if (sessionId) return [...errorsFor(sessionId)];
|
|
107
118
|
return [..._pageErrors.values()].flat();
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
export function clearPageErrors(sessionId?: string): void {
|
|
111
|
-
if (sessionId) {
|
|
122
|
+
if (sessionId) {
|
|
123
|
+
_pageErrors.set(sessionId, []);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
112
126
|
_pageErrors.clear();
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
export function teardownConsoleCapture(sessionId: string): void {
|
|
116
130
|
const offs = _consoleListeners.get(sessionId);
|
|
117
|
-
if (offs) {
|
|
131
|
+
if (offs) {
|
|
132
|
+
for (const off of offs) off();
|
|
133
|
+
_consoleListeners.delete(sessionId);
|
|
134
|
+
}
|
|
118
135
|
_consoleMessages.delete(sessionId);
|
|
119
136
|
_pageErrors.delete(sessionId);
|
|
120
137
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { createServer, IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
3
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
4
|
-
import { join, dirname } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { homedir } from 'node:os';
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { createServer, type IncomingMessage } from 'node:http';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
9
|
|
|
10
10
|
export interface StepEvent {
|
|
11
11
|
type: string;
|
|
@@ -23,10 +23,12 @@ export interface RunRecord {
|
|
|
23
23
|
|
|
24
24
|
const RUNS_FILE = join(homedir(), '.monomind', 'browse-runs.json');
|
|
25
25
|
|
|
26
|
-
function
|
|
26
|
+
function _readBody(req: IncomingMessage): Promise<string> {
|
|
27
27
|
return new Promise((resolve, reject) => {
|
|
28
28
|
let body = '';
|
|
29
|
-
req.on('data', (chunk: Buffer) => {
|
|
29
|
+
req.on('data', (chunk: Buffer) => {
|
|
30
|
+
body += chunk.toString();
|
|
31
|
+
});
|
|
30
32
|
req.on('end', () => resolve(body));
|
|
31
33
|
req.on('error', reject);
|
|
32
34
|
});
|
|
@@ -36,13 +38,15 @@ async function loadPersistedRuns(): Promise<RunRecord[]> {
|
|
|
36
38
|
if (!existsSync(RUNS_FILE)) return [];
|
|
37
39
|
try {
|
|
38
40
|
return JSON.parse(await readFile(RUNS_FILE, 'utf-8')) as RunRecord[];
|
|
39
|
-
} catch {
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const _require = createRequire(import.meta.url);
|
|
43
47
|
|
|
44
48
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
45
|
-
const DEFAULT_PORT = parseInt(process.env
|
|
49
|
+
const DEFAULT_PORT = parseInt(process.env.MONOBROWSE_DASHBOARD_PORT ?? '4242', 10);
|
|
46
50
|
const MAX_RUN_HISTORY = 50;
|
|
47
51
|
|
|
48
52
|
export interface DashboardServer {
|
|
@@ -67,7 +71,9 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
67
71
|
try {
|
|
68
72
|
const authFileDir = join(homedir(), '.monomind');
|
|
69
73
|
mkdirSync(authFileDir, { recursive: true });
|
|
70
|
-
writeFileSync(join(authFileDir, 'monobrowse-dashboard-token'), dashboardAuthValue, {
|
|
74
|
+
writeFileSync(join(authFileDir, 'monobrowse-dashboard-token'), dashboardAuthValue, {
|
|
75
|
+
mode: 0o600,
|
|
76
|
+
});
|
|
71
77
|
} catch {
|
|
72
78
|
// best-effort: if we can't persist the token, mutating routes still
|
|
73
79
|
// enforce it in-memory — trusted callers just won't be able to read it.
|
|
@@ -114,8 +120,8 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
114
120
|
|
|
115
121
|
if (url === '/runs' && req.method === 'GET') {
|
|
116
122
|
const persisted = await loadPersistedRuns().catch(() => [] as RunRecord[]);
|
|
117
|
-
const seen = new Set(runHistory.map(r => r.id));
|
|
118
|
-
const merged = [...runHistory, ...persisted.filter(r => !seen.has(r.id))]
|
|
123
|
+
const seen = new Set(runHistory.map((r) => r.id));
|
|
124
|
+
const merged = [...runHistory, ...persisted.filter((r) => !seen.has(r.id))]
|
|
119
125
|
.sort((a, b) => b.startedAt - a.startedAt)
|
|
120
126
|
.slice(0, MAX_RUN_HISTORY);
|
|
121
127
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -130,7 +136,8 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
130
136
|
// every non-GET/HEAD route; GET/SSE reads stay open on the loopback baseline.
|
|
131
137
|
if (url.startsWith('/stop/') && req.method === 'POST') {
|
|
132
138
|
const parsedAuth = new URL(url, 'http://localhost');
|
|
133
|
-
const suppliedAuth =
|
|
139
|
+
const suppliedAuth =
|
|
140
|
+
req.headers['x-monobrowse-token'] || parsedAuth.searchParams.get('token') || '';
|
|
134
141
|
if (suppliedAuth !== dashboardAuthValue) {
|
|
135
142
|
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
136
143
|
res.end(JSON.stringify({ error: 'Unauthorized: missing or invalid auth token' }));
|
|
@@ -144,18 +151,26 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
const parsed = new URL(url, 'http://localhost');
|
|
147
|
-
if (
|
|
154
|
+
if (
|
|
155
|
+
parsed.pathname === '/events' &&
|
|
156
|
+
(req.method === 'GET' || req.method === 'HEAD') &&
|
|
157
|
+
!WebSocketServer
|
|
158
|
+
) {
|
|
148
159
|
// SSE fallback when ws not available
|
|
149
160
|
const subscribedDir = parsed.searchParams.get('dir') ?? null;
|
|
150
161
|
res.writeHead(200, {
|
|
151
162
|
'Content-Type': 'text/event-stream',
|
|
152
163
|
'Cache-Control': 'no-cache',
|
|
153
|
-
|
|
164
|
+
Connection: 'keep-alive',
|
|
154
165
|
});
|
|
155
166
|
res.write(`data: ${JSON.stringify({ type: 'connected' })}\n\n`);
|
|
156
167
|
clientDirs.set(res, subscribedDir);
|
|
157
168
|
const heartbeat = setInterval(() => {
|
|
158
|
-
try {
|
|
169
|
+
try {
|
|
170
|
+
res.write(': keep-alive\n\n');
|
|
171
|
+
} catch {
|
|
172
|
+
clearInterval(heartbeat);
|
|
173
|
+
}
|
|
159
174
|
}, 30_000);
|
|
160
175
|
req.on('close', () => {
|
|
161
176
|
clearInterval(heartbeat);
|
|
@@ -176,8 +191,8 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
176
191
|
const subscribedDir = upgradeParsed.searchParams.get('dir') ?? null;
|
|
177
192
|
clientDirs.set(ws, subscribedDir);
|
|
178
193
|
const persisted = await loadPersistedRuns().catch(() => [] as RunRecord[]);
|
|
179
|
-
const seen = new Set(runHistory.map(r => r.id));
|
|
180
|
-
const merged = [...runHistory, ...persisted.filter(r => !seen.has(r.id))]
|
|
194
|
+
const seen = new Set(runHistory.map((r) => r.id));
|
|
195
|
+
const merged = [...runHistory, ...persisted.filter((r) => !seen.has(r.id))]
|
|
181
196
|
.sort((a, b) => b.startedAt - a.startedAt)
|
|
182
197
|
.slice(0, MAX_RUN_HISTORY);
|
|
183
198
|
ws.send(JSON.stringify({ type: 'history', runs: merged }));
|
|
@@ -205,7 +220,11 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
205
220
|
function broadcast(event: StepEvent): void {
|
|
206
221
|
const msg = JSON.stringify(event);
|
|
207
222
|
for (const [client, subscribedDir] of clientDirs) {
|
|
208
|
-
if (
|
|
223
|
+
if (
|
|
224
|
+
subscribedDir !== null &&
|
|
225
|
+
event.projectDir !== undefined &&
|
|
226
|
+
subscribedDir !== event.projectDir
|
|
227
|
+
) {
|
|
209
228
|
continue;
|
|
210
229
|
}
|
|
211
230
|
try {
|
|
@@ -221,7 +240,7 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
221
240
|
}
|
|
222
241
|
|
|
223
242
|
function addRunRecord(record: RunRecord): void {
|
|
224
|
-
const idx = runHistory.findIndex(r => r.id === record.id);
|
|
243
|
+
const idx = runHistory.findIndex((r) => r.id === record.id);
|
|
225
244
|
if (idx >= 0) {
|
|
226
245
|
runHistory[idx] = record;
|
|
227
246
|
} else {
|
|
@@ -229,9 +248,9 @@ export function startDashboard(port = DEFAULT_PORT): DashboardServer {
|
|
|
229
248
|
if (runHistory.length > MAX_RUN_HISTORY) runHistory.pop();
|
|
230
249
|
}
|
|
231
250
|
const dir = join(homedir(), '.monomind');
|
|
232
|
-
mkdir(dir, { recursive: true })
|
|
233
|
-
writeFile(RUNS_FILE, JSON.stringify(runHistory, null, 2))
|
|
234
|
-
|
|
251
|
+
mkdir(dir, { recursive: true })
|
|
252
|
+
.then(() => writeFile(RUNS_FILE, JSON.stringify(runHistory, null, 2)))
|
|
253
|
+
.catch(() => {});
|
|
235
254
|
}
|
|
236
255
|
|
|
237
256
|
function isStopRequested(runId: string): boolean {
|