@hasna/browser 0.4.7 → 0.4.8
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/mcp/index.js +477 -234
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -11297,7 +11297,7 @@ function buildRowRefs(rows, method, totalRows, rowCount) {
|
|
|
11297
11297
|
row: index,
|
|
11298
11298
|
text,
|
|
11299
11299
|
visible: method === "dom" ? true : index >= firstVisibleRow,
|
|
11300
|
-
selector: method === "dom" ? `#takumi-tui-dom-root [data-row="${index}"]` : undefined
|
|
11300
|
+
selector: method === "dom" ? `#takumi-tui-dom-root .takumi-tui-dom-row[data-row="${index}"]` : undefined
|
|
11301
11301
|
};
|
|
11302
11302
|
});
|
|
11303
11303
|
return refs;
|
|
@@ -11505,7 +11505,7 @@ async function readDomMirrorState(page) {
|
|
|
11505
11505
|
const runtime = window.__takumiTuiDomRenderer;
|
|
11506
11506
|
if (runtime?.sync)
|
|
11507
11507
|
return runtime.sync();
|
|
11508
|
-
const rowEls = Array.from(document.querySelectorAll("#takumi-tui-dom-root
|
|
11508
|
+
const rowEls = Array.from(document.querySelectorAll("#takumi-tui-dom-root .takumi-tui-dom-row"));
|
|
11509
11509
|
const rows = rowEls.map((row) => row.getAttribute("aria-label") ?? row.textContent ?? "");
|
|
11510
11510
|
const term = window.term ?? window.terminal;
|
|
11511
11511
|
const active = term?.buffer?.active;
|
|
@@ -11528,17 +11528,14 @@ function isDomMethod(method) {
|
|
|
11528
11528
|
return method === "dom";
|
|
11529
11529
|
}
|
|
11530
11530
|
async function withTimeout(label, operation, timeoutMs = DEFAULT_TOOL_TIMEOUT_MS) {
|
|
11531
|
-
let
|
|
11532
|
-
const
|
|
11533
|
-
|
|
11534
|
-
|
|
11531
|
+
let timer;
|
|
11532
|
+
const timeout = new Promise((_, reject) => {
|
|
11533
|
+
timer = setTimeout(() => {
|
|
11534
|
+
reject(new BrowserError(`${label} timed out after ${timeoutMs}ms \u2014 ttyd/playwright connection may be unhealthy. Try closing and re-opening the session.`, "TUI_TIMEOUT"));
|
|
11535
|
+
}, timeoutMs);
|
|
11536
|
+
});
|
|
11535
11537
|
try {
|
|
11536
|
-
return await operation();
|
|
11537
|
-
} catch (err) {
|
|
11538
|
-
if (timedOut) {
|
|
11539
|
-
throw new BrowserError(`${label} timed out after ${timeoutMs}ms \u2014 ttyd/playwright connection may be unhealthy. Try closing and re-opening the session.`, "TUI_TIMEOUT");
|
|
11540
|
-
}
|
|
11541
|
-
throw err;
|
|
11538
|
+
return await Promise.race([operation(), timeout]);
|
|
11542
11539
|
} finally {
|
|
11543
11540
|
clearTimeout(timer);
|
|
11544
11541
|
}
|
|
@@ -11808,7 +11805,7 @@ async function waitForTerminalText(page, text, timeoutMs = 30000, method = "buff
|
|
|
11808
11805
|
return { found: true, elapsed_ms: Date.now() - start, stuck: false };
|
|
11809
11806
|
await new Promise((r) => setTimeout(r, 250));
|
|
11810
11807
|
}
|
|
11811
|
-
return { found: false, elapsed_ms:
|
|
11808
|
+
return { found: false, elapsed_ms: Date.now() - start, stuck: false };
|
|
11812
11809
|
}
|
|
11813
11810
|
async function closeTui(session) {
|
|
11814
11811
|
await destroyDomRenderer(session.page);
|
|
@@ -11921,6 +11918,23 @@ var init_selector = __esm(() => {
|
|
|
11921
11918
|
};
|
|
11922
11919
|
});
|
|
11923
11920
|
|
|
11921
|
+
// src/lib/tui-recording.ts
|
|
11922
|
+
function trackTuiRecording(sessionId, intervalId) {
|
|
11923
|
+
stopTuiRecording(sessionId);
|
|
11924
|
+
recordingIntervals.set(sessionId, intervalId);
|
|
11925
|
+
}
|
|
11926
|
+
function stopTuiRecording(sessionId) {
|
|
11927
|
+
const intervalId = recordingIntervals.get(sessionId);
|
|
11928
|
+
if (!intervalId)
|
|
11929
|
+
return;
|
|
11930
|
+
clearInterval(intervalId);
|
|
11931
|
+
recordingIntervals.delete(sessionId);
|
|
11932
|
+
}
|
|
11933
|
+
var recordingIntervals;
|
|
11934
|
+
var init_tui_recording = __esm(() => {
|
|
11935
|
+
recordingIntervals = new Map;
|
|
11936
|
+
});
|
|
11937
|
+
|
|
11924
11938
|
// src/db/network-log.ts
|
|
11925
11939
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
11926
11940
|
function logRequest(data) {
|
|
@@ -12136,7 +12150,9 @@ async function applyStealthPatches(page) {
|
|
|
12136
12150
|
"User-Agent": REALISTIC_USER_AGENT
|
|
12137
12151
|
});
|
|
12138
12152
|
}
|
|
12139
|
-
var REALISTIC_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", STEALTH_SCRIPT
|
|
12153
|
+
var REALISTIC_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", STEALTH_SCRIPT;
|
|
12154
|
+
var init_stealth = __esm(() => {
|
|
12155
|
+
STEALTH_SCRIPT = `
|
|
12140
12156
|
// \u2500\u2500 1. Remove navigator.webdriver flag \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
12141
12157
|
Object.defineProperty(navigator, 'webdriver', {
|
|
12142
12158
|
get: () => false,
|
|
@@ -12184,8 +12200,14 @@ if (!window.chrome.runtime) {
|
|
|
12184
12200
|
id: undefined,
|
|
12185
12201
|
};
|
|
12186
12202
|
}
|
|
12203
|
+
|
|
12204
|
+
// \u2500\u2500 5. Override navigator.userAgent to match HTTP header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
12205
|
+
Object.defineProperty(navigator, 'userAgent', {
|
|
12206
|
+
get: () => "${REALISTIC_USER_AGENT}",
|
|
12207
|
+
configurable: true,
|
|
12208
|
+
});
|
|
12187
12209
|
`;
|
|
12188
|
-
|
|
12210
|
+
});
|
|
12189
12211
|
|
|
12190
12212
|
// src/lib/dialogs.ts
|
|
12191
12213
|
var exports_dialogs = {};
|
|
@@ -13249,6 +13271,29 @@ __export(exports_session, {
|
|
|
13249
13271
|
function createBunProxy(view) {
|
|
13250
13272
|
return view;
|
|
13251
13273
|
}
|
|
13274
|
+
function attachPlaywrightListeners(page, sessionId, cleanups, opts = {}) {
|
|
13275
|
+
if (opts.captureNetwork !== false) {
|
|
13276
|
+
try {
|
|
13277
|
+
cleanups.push(enableNetworkLogging(page, sessionId));
|
|
13278
|
+
} catch {}
|
|
13279
|
+
}
|
|
13280
|
+
if (opts.captureConsole !== false) {
|
|
13281
|
+
try {
|
|
13282
|
+
cleanups.push(enableConsoleCapture(page, sessionId));
|
|
13283
|
+
} catch {}
|
|
13284
|
+
}
|
|
13285
|
+
try {
|
|
13286
|
+
cleanups.push(setupDialogHandler(page, sessionId));
|
|
13287
|
+
} catch {}
|
|
13288
|
+
}
|
|
13289
|
+
function detachPlaywrightListeners(cleanups) {
|
|
13290
|
+
while (cleanups.length > 1) {
|
|
13291
|
+
const cleanup = cleanups.pop();
|
|
13292
|
+
try {
|
|
13293
|
+
cleanup?.();
|
|
13294
|
+
} catch {}
|
|
13295
|
+
}
|
|
13296
|
+
}
|
|
13252
13297
|
async function createSession2(opts = {}) {
|
|
13253
13298
|
if (opts.cdpUrl) {
|
|
13254
13299
|
const { connectToExistingBrowser: connectToExistingBrowser2 } = await Promise.resolve().then(() => (init_cdp(), exports_cdp));
|
|
@@ -13286,9 +13331,11 @@ async function createSession2(opts = {}) {
|
|
|
13286
13331
|
let browser = null;
|
|
13287
13332
|
let bunView = null;
|
|
13288
13333
|
let page;
|
|
13334
|
+
let actualEngine = resolvedEngine;
|
|
13289
13335
|
if (resolvedEngine === "bun") {
|
|
13290
13336
|
if (!isBunWebViewAvailable()) {
|
|
13291
13337
|
console.warn("[browser] Bun.WebView requested but not available \u2014 falling back to playwright. Run: bun upgrade --canary");
|
|
13338
|
+
actualEngine = "playwright";
|
|
13292
13339
|
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13293
13340
|
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13294
13341
|
} else {
|
|
@@ -13308,9 +13355,11 @@ async function createSession2(opts = {}) {
|
|
|
13308
13355
|
}
|
|
13309
13356
|
if (!bunWorks) {
|
|
13310
13357
|
console.warn("[browser] Bun.WebView exists but Chrome not available \u2014 falling back to playwright");
|
|
13358
|
+
actualEngine = "playwright";
|
|
13311
13359
|
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13312
13360
|
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13313
13361
|
} else {
|
|
13362
|
+
actualEngine = "bun";
|
|
13314
13363
|
bunView = testView;
|
|
13315
13364
|
if (opts.stealth) {}
|
|
13316
13365
|
page = createBunProxy(bunView);
|
|
@@ -13340,19 +13389,10 @@ async function createSession2(opts = {}) {
|
|
|
13340
13389
|
});
|
|
13341
13390
|
const cleanups2 = [];
|
|
13342
13391
|
cleanups2.push(() => closeTui(tuiSess));
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
}
|
|
13348
|
-
if (opts.captureConsole !== false) {
|
|
13349
|
-
try {
|
|
13350
|
-
cleanups2.push(enableConsoleCapture(page, session2.id));
|
|
13351
|
-
} catch {}
|
|
13352
|
-
}
|
|
13353
|
-
try {
|
|
13354
|
-
cleanups2.push(setupDialogHandler(page, session2.id));
|
|
13355
|
-
} catch {}
|
|
13392
|
+
attachPlaywrightListeners(page, session2.id, cleanups2, {
|
|
13393
|
+
captureNetwork: opts.captureNetwork,
|
|
13394
|
+
captureConsole: opts.captureConsole
|
|
13395
|
+
});
|
|
13356
13396
|
handles.set(session2.id, { browser, bunView: null, tuiSession: tuiSess, page, engine: "tui", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false, startUrl: opts.startUrl ?? "bash" });
|
|
13357
13397
|
return { session: session2, page };
|
|
13358
13398
|
} else {
|
|
@@ -13382,7 +13422,7 @@ async function createSession2(opts = {}) {
|
|
|
13382
13422
|
}
|
|
13383
13423
|
})() : undefined);
|
|
13384
13424
|
const session = createSession({
|
|
13385
|
-
engine:
|
|
13425
|
+
engine: actualEngine,
|
|
13386
13426
|
projectId: opts.projectId,
|
|
13387
13427
|
agentId: opts.agentId,
|
|
13388
13428
|
startUrl: opts.startUrl,
|
|
@@ -13395,37 +13435,12 @@ async function createSession2(opts = {}) {
|
|
|
13395
13435
|
}
|
|
13396
13436
|
const cleanups = [];
|
|
13397
13437
|
if (!bunView) {
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
}
|
|
13403
|
-
if (opts.captureConsole !== false) {
|
|
13404
|
-
try {
|
|
13405
|
-
cleanups.push(enableConsoleCapture(page, session.id));
|
|
13406
|
-
} catch {}
|
|
13407
|
-
}
|
|
13408
|
-
try {
|
|
13409
|
-
cleanups.push(setupDialogHandler(page, session.id));
|
|
13410
|
-
} catch {}
|
|
13411
|
-
} else {
|
|
13412
|
-
if (opts.captureConsole !== false) {
|
|
13413
|
-
try {
|
|
13414
|
-
const { logConsoleMessage: logConsoleMessage2 } = await Promise.resolve().then(() => (init_console_log(), exports_console_log));
|
|
13415
|
-
await bunView.addInitScript(`
|
|
13416
|
-
(() => {
|
|
13417
|
-
const orig = { log: console.log, warn: console.warn, error: console.error, debug: console.debug, info: console.info };
|
|
13418
|
-
['log','warn','error','debug','info'].forEach(level => {
|
|
13419
|
-
console[level] = (...args) => {
|
|
13420
|
-
orig[level](...args);
|
|
13421
|
-
};
|
|
13422
|
-
});
|
|
13423
|
-
})()
|
|
13424
|
-
`);
|
|
13425
|
-
} catch {}
|
|
13426
|
-
}
|
|
13438
|
+
attachPlaywrightListeners(page, session.id, cleanups, {
|
|
13439
|
+
captureNetwork: opts.captureNetwork,
|
|
13440
|
+
captureConsole: opts.captureConsole
|
|
13441
|
+
});
|
|
13427
13442
|
}
|
|
13428
|
-
handles.set(session.id, { browser, bunView, tuiSession: null, page, engine:
|
|
13443
|
+
handles.set(session.id, { browser, bunView, tuiSession: null, page, engine: actualEngine, cleanups, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false, startUrl: opts.startUrl ?? "" });
|
|
13429
13444
|
if (opts.startUrl) {
|
|
13430
13445
|
try {
|
|
13431
13446
|
if (bunView) {
|
|
@@ -13458,7 +13473,8 @@ function getSessionBunView(sessionId) {
|
|
|
13458
13473
|
return handles.get(sessionId)?.bunView ?? null;
|
|
13459
13474
|
}
|
|
13460
13475
|
function isBunSession(sessionId) {
|
|
13461
|
-
|
|
13476
|
+
const handle = handles.get(sessionId);
|
|
13477
|
+
return handle?.engine === "bun" && handle.bunView !== null;
|
|
13462
13478
|
}
|
|
13463
13479
|
function getSessionBrowser(sessionId) {
|
|
13464
13480
|
const handle = handles.get(sessionId);
|
|
@@ -13484,11 +13500,16 @@ function setSessionTui(sessionId, tuiSess) {
|
|
|
13484
13500
|
const handle = handles.get(sessionId);
|
|
13485
13501
|
if (!handle)
|
|
13486
13502
|
throw new SessionNotFoundError(sessionId);
|
|
13503
|
+
detachPlaywrightListeners(handle.cleanups);
|
|
13487
13504
|
handle.tuiSession = tuiSess;
|
|
13488
13505
|
handle.page = tuiSess.page;
|
|
13489
13506
|
if (tuiSess.browser !== handle.browser) {
|
|
13490
13507
|
handle.browser = tuiSess.browser;
|
|
13491
13508
|
}
|
|
13509
|
+
attachPlaywrightListeners(tuiSess.page, sessionId, handle.cleanups, {
|
|
13510
|
+
captureNetwork: true,
|
|
13511
|
+
captureConsole: true
|
|
13512
|
+
});
|
|
13492
13513
|
handle.lastActivity = Date.now();
|
|
13493
13514
|
}
|
|
13494
13515
|
function getSessionCommand(sessionId) {
|
|
@@ -13504,9 +13525,12 @@ async function closeSession2(sessionId) {
|
|
|
13504
13525
|
const handle = handles.get(sessionId);
|
|
13505
13526
|
try {
|
|
13506
13527
|
if (handle) {
|
|
13528
|
+
if (handle.engine === "tui") {
|
|
13529
|
+
stopTuiRecording(sessionId);
|
|
13530
|
+
}
|
|
13507
13531
|
for (const cleanup of handle.cleanups) {
|
|
13508
13532
|
try {
|
|
13509
|
-
cleanup();
|
|
13533
|
+
await cleanup();
|
|
13510
13534
|
} catch {}
|
|
13511
13535
|
}
|
|
13512
13536
|
if (handle.bunView) {
|
|
@@ -13618,6 +13642,7 @@ var init_session = __esm(() => {
|
|
|
13618
13642
|
init_bun_webview();
|
|
13619
13643
|
init_selector();
|
|
13620
13644
|
init_tui();
|
|
13645
|
+
init_tui_recording();
|
|
13621
13646
|
init_network();
|
|
13622
13647
|
init_console();
|
|
13623
13648
|
init_stealth();
|
|
@@ -20245,10 +20270,17 @@ __export(exports_gallery, {
|
|
|
20245
20270
|
createEntry: () => createEntry
|
|
20246
20271
|
});
|
|
20247
20272
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
20273
|
+
import { join as join9, resolve, relative as relative2, isAbsolute } from "path";
|
|
20248
20274
|
function validateDataPath(filePath) {
|
|
20249
20275
|
if (filePath.includes("..")) {
|
|
20250
20276
|
throw new Error(`File path must not contain '..': ${filePath}`);
|
|
20251
20277
|
}
|
|
20278
|
+
const dataDir = resolve(getDataDir2());
|
|
20279
|
+
const resolved = resolve(isAbsolute(filePath) ? filePath : join9(dataDir, filePath));
|
|
20280
|
+
const rel = relative2(dataDir, resolved);
|
|
20281
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
20282
|
+
throw new Error(`File path must be within data directory: ${filePath}`);
|
|
20283
|
+
}
|
|
20252
20284
|
return filePath;
|
|
20253
20285
|
}
|
|
20254
20286
|
function deserialize(row) {
|
|
@@ -20266,7 +20298,13 @@ function deserialize(row) {
|
|
|
20266
20298
|
original_size_bytes: row.original_size_bytes ?? undefined,
|
|
20267
20299
|
compressed_size_bytes: row.compressed_size_bytes ?? undefined,
|
|
20268
20300
|
compression_ratio: row.compression_ratio ?? undefined,
|
|
20269
|
-
tags:
|
|
20301
|
+
tags: (() => {
|
|
20302
|
+
try {
|
|
20303
|
+
return JSON.parse(row.tags);
|
|
20304
|
+
} catch {
|
|
20305
|
+
return [];
|
|
20306
|
+
}
|
|
20307
|
+
})(),
|
|
20270
20308
|
notes: row.notes ?? undefined,
|
|
20271
20309
|
is_favorite: row.is_favorite === 1,
|
|
20272
20310
|
created_at: row.created_at
|
|
@@ -20456,6 +20494,7 @@ var exports_recorder = {};
|
|
|
20456
20494
|
__export(exports_recorder, {
|
|
20457
20495
|
stopRecording: () => stopRecording,
|
|
20458
20496
|
startRecording: () => startRecording,
|
|
20497
|
+
resetRecorderState: () => resetRecorderState,
|
|
20459
20498
|
replayRecording: () => replayRecording,
|
|
20460
20499
|
recordStep: () => recordStep,
|
|
20461
20500
|
listRecordings: () => listRecordings,
|
|
@@ -20463,6 +20502,14 @@ __export(exports_recorder, {
|
|
|
20463
20502
|
exportRecording: () => exportRecording,
|
|
20464
20503
|
attachPageListeners: () => attachPageListeners
|
|
20465
20504
|
});
|
|
20505
|
+
function resetRecorderState() {
|
|
20506
|
+
for (const active of activeRecordings.values()) {
|
|
20507
|
+
try {
|
|
20508
|
+
active.cleanup();
|
|
20509
|
+
} catch {}
|
|
20510
|
+
}
|
|
20511
|
+
activeRecordings.clear();
|
|
20512
|
+
}
|
|
20466
20513
|
function startRecording(sessionId, name, startUrl) {
|
|
20467
20514
|
const steps = [];
|
|
20468
20515
|
const recording = createRecording({ name, start_url: startUrl, steps });
|
|
@@ -20747,9 +20794,9 @@ var exports_gallery_diff = {};
|
|
|
20747
20794
|
__export(exports_gallery_diff, {
|
|
20748
20795
|
diffImages: () => diffImages
|
|
20749
20796
|
});
|
|
20750
|
-
import { join as
|
|
20797
|
+
import { join as join12 } from "path";
|
|
20751
20798
|
import { mkdirSync as mkdirSync9 } from "fs";
|
|
20752
|
-
async function diffImages(path1, path2) {
|
|
20799
|
+
async function diffImages(path1, path2, threshold = 10) {
|
|
20753
20800
|
const img1 = import_sharp2.default(path1);
|
|
20754
20801
|
const img2 = import_sharp2.default(path2);
|
|
20755
20802
|
const [meta1, meta2] = await Promise.all([img1.metadata(), img2.metadata()]);
|
|
@@ -20768,7 +20815,7 @@ async function diffImages(path1, path2) {
|
|
|
20768
20815
|
const dg = Math.abs(raw1[i + 1] - raw2[i + 1]);
|
|
20769
20816
|
const db = Math.abs(raw1[i + 2] - raw2[i + 2]);
|
|
20770
20817
|
const diff = (dr + dg + db) / 3;
|
|
20771
|
-
if (diff >
|
|
20818
|
+
if (diff > threshold) {
|
|
20772
20819
|
changedPixels++;
|
|
20773
20820
|
diffBuffer[i] = 255;
|
|
20774
20821
|
diffBuffer[i + 1] = 0;
|
|
@@ -20780,9 +20827,9 @@ async function diffImages(path1, path2) {
|
|
|
20780
20827
|
}
|
|
20781
20828
|
}
|
|
20782
20829
|
const dataDir = getDataDir2();
|
|
20783
|
-
const diffDir =
|
|
20830
|
+
const diffDir = join12(dataDir, "diffs");
|
|
20784
20831
|
mkdirSync9(diffDir, { recursive: true });
|
|
20785
|
-
const diffPath =
|
|
20832
|
+
const diffPath = join12(diffDir, `diff-${Date.now()}.webp`);
|
|
20786
20833
|
const diffImageBuffer = await import_sharp2.default(diffBuffer, { raw: { width: w, height: h, channels } }).webp({ quality: 85 }).toBuffer();
|
|
20787
20834
|
await Bun.write(diffPath, diffImageBuffer);
|
|
20788
20835
|
return {
|
|
@@ -20809,21 +20856,21 @@ __export(exports_profiles, {
|
|
|
20809
20856
|
applyProfile: () => applyProfile
|
|
20810
20857
|
});
|
|
20811
20858
|
import { mkdirSync as mkdirSync11, existsSync as existsSync9, readdirSync as readdirSync7, rmSync, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
20812
|
-
import { join as
|
|
20859
|
+
import { join as join14 } from "path";
|
|
20813
20860
|
function getProfilesDir() {
|
|
20814
20861
|
const dataDir = getDataDir2();
|
|
20815
|
-
const dir =
|
|
20862
|
+
const dir = join14(dataDir, "profiles");
|
|
20816
20863
|
mkdirSync11(dir, { recursive: true });
|
|
20817
20864
|
return dir;
|
|
20818
20865
|
}
|
|
20819
20866
|
function getProfileDir2(name) {
|
|
20820
|
-
return
|
|
20867
|
+
return join14(getProfilesDir(), name);
|
|
20821
20868
|
}
|
|
20822
20869
|
async function saveProfile(page, name) {
|
|
20823
20870
|
const dir = getProfileDir2(name);
|
|
20824
20871
|
mkdirSync11(dir, { recursive: true });
|
|
20825
20872
|
const cookies = await page.context().cookies();
|
|
20826
|
-
writeFileSync3(
|
|
20873
|
+
writeFileSync3(join14(dir, "cookies.json"), JSON.stringify(cookies, null, 2));
|
|
20827
20874
|
let localStorage2 = {};
|
|
20828
20875
|
try {
|
|
20829
20876
|
localStorage2 = await page.evaluate(() => {
|
|
@@ -20835,11 +20882,11 @@ async function saveProfile(page, name) {
|
|
|
20835
20882
|
return result;
|
|
20836
20883
|
});
|
|
20837
20884
|
} catch {}
|
|
20838
|
-
writeFileSync3(
|
|
20885
|
+
writeFileSync3(join14(dir, "storage.json"), JSON.stringify(localStorage2, null, 2));
|
|
20839
20886
|
const savedAt = new Date().toISOString();
|
|
20840
20887
|
const url = page.url();
|
|
20841
20888
|
const meta = { saved_at: savedAt, url };
|
|
20842
|
-
writeFileSync3(
|
|
20889
|
+
writeFileSync3(join14(dir, "meta.json"), JSON.stringify(meta, null, 2));
|
|
20843
20890
|
return {
|
|
20844
20891
|
name,
|
|
20845
20892
|
saved_at: savedAt,
|
|
@@ -20853,9 +20900,9 @@ function loadProfile(name) {
|
|
|
20853
20900
|
if (!existsSync9(dir)) {
|
|
20854
20901
|
throw new Error(`Profile not found: ${name}`);
|
|
20855
20902
|
}
|
|
20856
|
-
const cookiesPath =
|
|
20857
|
-
const storagePath =
|
|
20858
|
-
const metaPath2 =
|
|
20903
|
+
const cookiesPath = join14(dir, "cookies.json");
|
|
20904
|
+
const storagePath = join14(dir, "storage.json");
|
|
20905
|
+
const metaPath2 = join14(dir, "meta.json");
|
|
20859
20906
|
const cookies = existsSync9(cookiesPath) ? JSON.parse(readFileSync3(cookiesPath, "utf8")) : [];
|
|
20860
20907
|
const localStorage2 = existsSync9(storagePath) ? JSON.parse(readFileSync3(storagePath, "utf8")) : {};
|
|
20861
20908
|
let savedAt = new Date().toISOString();
|
|
@@ -20896,24 +20943,24 @@ function listProfiles() {
|
|
|
20896
20943
|
if (!entry.isDirectory())
|
|
20897
20944
|
continue;
|
|
20898
20945
|
const name = entry.name;
|
|
20899
|
-
const profileDir =
|
|
20946
|
+
const profileDir = join14(dir, name);
|
|
20900
20947
|
let savedAt = "";
|
|
20901
20948
|
let url;
|
|
20902
20949
|
let cookieCount = 0;
|
|
20903
20950
|
let storageKeyCount = 0;
|
|
20904
20951
|
try {
|
|
20905
|
-
const metaPath2 =
|
|
20952
|
+
const metaPath2 = join14(profileDir, "meta.json");
|
|
20906
20953
|
if (existsSync9(metaPath2)) {
|
|
20907
20954
|
const meta = JSON.parse(readFileSync3(metaPath2, "utf8"));
|
|
20908
20955
|
savedAt = meta.saved_at ?? "";
|
|
20909
20956
|
url = meta.url;
|
|
20910
20957
|
}
|
|
20911
|
-
const cookiesPath =
|
|
20958
|
+
const cookiesPath = join14(profileDir, "cookies.json");
|
|
20912
20959
|
if (existsSync9(cookiesPath)) {
|
|
20913
20960
|
const cookies = JSON.parse(readFileSync3(cookiesPath, "utf8"));
|
|
20914
20961
|
cookieCount = Array.isArray(cookies) ? cookies.length : 0;
|
|
20915
20962
|
}
|
|
20916
|
-
const storagePath =
|
|
20963
|
+
const storagePath = join14(profileDir, "storage.json");
|
|
20917
20964
|
if (existsSync9(storagePath)) {
|
|
20918
20965
|
const storage = JSON.parse(readFileSync3(storagePath, "utf8"));
|
|
20919
20966
|
storageKeyCount = Object.keys(storage).length;
|
|
@@ -21550,7 +21597,7 @@ __export(exports_dist, {
|
|
|
21550
21597
|
AGENT_TARGETS: () => AGENT_TARGETS
|
|
21551
21598
|
});
|
|
21552
21599
|
import { existsSync as existsSync10, readFileSync as readFileSync4, readdirSync as readdirSync8 } from "fs";
|
|
21553
|
-
import { join as
|
|
21600
|
+
import { join as join15 } from "path";
|
|
21554
21601
|
import { homedir as homedir8 } from "os";
|
|
21555
21602
|
import { existsSync as existsSync22, cpSync, mkdirSync as mkdirSync12, writeFileSync as writeFileSync4, rmSync as rmSync2, readdirSync as readdirSync22, statSync as statSync3, readFileSync as readFileSync22, accessSync, constants } from "fs";
|
|
21556
21603
|
import { join as join22, dirname as dirname2 } from "path";
|
|
@@ -21600,7 +21647,7 @@ function discoverSkillsInDir(dir) {
|
|
|
21600
21647
|
for (const entry of entries) {
|
|
21601
21648
|
if (!entry.isDirectory())
|
|
21602
21649
|
continue;
|
|
21603
|
-
const skillMdPath =
|
|
21650
|
+
const skillMdPath = join15(dir, entry.name, "SKILL.md");
|
|
21604
21651
|
if (!existsSync10(skillMdPath))
|
|
21605
21652
|
continue;
|
|
21606
21653
|
let content;
|
|
@@ -21631,11 +21678,11 @@ function loadRegistry(cwd) {
|
|
|
21631
21678
|
return _registryCache;
|
|
21632
21679
|
}
|
|
21633
21680
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
21634
|
-
const globalCustomNew = discoverSkillsInDir(
|
|
21635
|
-
const globalCustomOld = discoverSkillsInDir(
|
|
21681
|
+
const globalCustomNew = discoverSkillsInDir(join15(homedir8(), ".hasna", "skills", "custom"));
|
|
21682
|
+
const globalCustomOld = discoverSkillsInDir(join15(homedir8(), ".skills"));
|
|
21636
21683
|
const oldNames = new Set(globalCustomNew.map((s) => s.name));
|
|
21637
21684
|
const globalCustom = [...globalCustomNew, ...globalCustomOld.filter((s) => !oldNames.has(s.name))];
|
|
21638
|
-
const projectCustom = discoverSkillsInDir(
|
|
21685
|
+
const projectCustom = discoverSkillsInDir(join15(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
21639
21686
|
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
21640
21687
|
const filtered = official.filter((s) => !customNames.has(s.name));
|
|
21641
21688
|
_registryCache = [...filtered, ...globalCustom, ...projectCustom];
|
|
@@ -23999,13 +24046,14 @@ var init_dist2 = __esm(() => {
|
|
|
23999
24046
|
// src/lib/auth.ts
|
|
24000
24047
|
var exports_auth = {};
|
|
24001
24048
|
__export(exports_auth, {
|
|
24049
|
+
lookupCredentials: () => lookupCredentials,
|
|
24002
24050
|
loginWithCredentials: () => loginWithCredentials,
|
|
24003
24051
|
getCredentials: () => getCredentials
|
|
24004
24052
|
});
|
|
24005
24053
|
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "fs";
|
|
24006
|
-
import { join as
|
|
24054
|
+
import { join as join16 } from "path";
|
|
24007
24055
|
import { homedir as homedir9 } from "os";
|
|
24008
|
-
async function
|
|
24056
|
+
async function lookupCredentials(service) {
|
|
24009
24057
|
try {
|
|
24010
24058
|
const secretsVaultPath = process.env["BROWSER_SECRETS_VAULT_PATH"];
|
|
24011
24059
|
if (secretsVaultPath) {
|
|
@@ -24013,11 +24061,14 @@ async function getCredentials(service) {
|
|
|
24013
24061
|
const email = getSecret(`${service}_email`) ?? getSecret(`${service}_username`) ?? getSecret(`${service}_login`);
|
|
24014
24062
|
const password = getSecret(`${service}_password`) ?? getSecret(`${service}_pass`);
|
|
24015
24063
|
if (email?.value && password?.value) {
|
|
24016
|
-
return {
|
|
24064
|
+
return {
|
|
24065
|
+
credential: { email: email.value, password: password.value },
|
|
24066
|
+
method: "secrets_vault"
|
|
24067
|
+
};
|
|
24017
24068
|
}
|
|
24018
24069
|
}
|
|
24019
24070
|
} catch {}
|
|
24020
|
-
const secretsPath =
|
|
24071
|
+
const secretsPath = join16(homedir9(), ".secrets");
|
|
24021
24072
|
if (existsSync11(secretsPath)) {
|
|
24022
24073
|
let content;
|
|
24023
24074
|
try {
|
|
@@ -24036,27 +24087,33 @@ async function getCredentials(service) {
|
|
|
24036
24087
|
}
|
|
24037
24088
|
const email = vars[`${prefix}_EMAIL`] ?? vars[`${prefix}_USERNAME`];
|
|
24038
24089
|
const password = vars[`${prefix}_PASSWORD`];
|
|
24039
|
-
if (email && password)
|
|
24040
|
-
return { email, password };
|
|
24090
|
+
if (email && password) {
|
|
24091
|
+
return { credential: { email, password }, method: "env_file" };
|
|
24092
|
+
}
|
|
24041
24093
|
}
|
|
24042
24094
|
const envPrefix = service.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
24043
24095
|
const envEmail = process.env[`${envPrefix}_EMAIL`] ?? process.env[`${envPrefix}_USERNAME`];
|
|
24044
24096
|
const envPass = process.env[`${envPrefix}_PASSWORD`];
|
|
24045
|
-
if (envEmail && envPass)
|
|
24046
|
-
return { email: envEmail, password: envPass };
|
|
24047
|
-
|
|
24097
|
+
if (envEmail && envPass) {
|
|
24098
|
+
return { credential: { email: envEmail, password: envPass }, method: "process_env" };
|
|
24099
|
+
}
|
|
24100
|
+
return { credential: null, method: "not_found" };
|
|
24101
|
+
}
|
|
24102
|
+
async function getCredentials(service) {
|
|
24103
|
+
return (await lookupCredentials(service)).credential;
|
|
24048
24104
|
}
|
|
24049
24105
|
async function loginWithCredentials(page, credentials, opts) {
|
|
24050
|
-
const { fillForm: fillForm2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
24106
|
+
const { fillForm: fillForm2, waitForText: waitForText2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
24051
24107
|
const { saveProfile: saveProfile2 } = await Promise.resolve().then(() => (init_profiles(), exports_profiles));
|
|
24052
24108
|
try {
|
|
24053
24109
|
if (opts?.loginUrl) {
|
|
24054
24110
|
await page.goto(opts.loginUrl, { waitUntil: "domcontentloaded" });
|
|
24055
24111
|
await new Promise((r) => setTimeout(r, 500));
|
|
24056
24112
|
}
|
|
24113
|
+
const urlBefore = page.url();
|
|
24057
24114
|
const emailSel = opts?.emailSelector ?? 'input[type="email"], input[name="email"], input[id*="email"], input[placeholder*="email" i]';
|
|
24058
24115
|
const passSel = opts?.passwordSelector ?? 'input[type="password"]';
|
|
24059
|
-
const submitSel = opts?.submitSelector ?? 'button[type="submit"], input[type="submit"]
|
|
24116
|
+
const submitSel = opts?.submitSelector ?? 'button[type="submit"], input[type="submit"]';
|
|
24060
24117
|
const fields = {};
|
|
24061
24118
|
if (credentials.email)
|
|
24062
24119
|
fields[emailSel] = credentials.email;
|
|
@@ -24065,10 +24122,38 @@ async function loginWithCredentials(page, credentials, opts) {
|
|
|
24065
24122
|
if (credentials.password)
|
|
24066
24123
|
fields[passSel] = credentials.password;
|
|
24067
24124
|
const fillResult = await fillForm2(page, fields, submitSel);
|
|
24068
|
-
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24125
|
+
if (fillResult.errors.some((e) => e.startsWith("submit("))) {
|
|
24126
|
+
try {
|
|
24127
|
+
await page.getByRole("button", { name: /sign in|log in|login|submit/i }).first().click({ timeout: 5000 });
|
|
24128
|
+
} catch {
|
|
24129
|
+
try {
|
|
24130
|
+
await page.locator('input[type="submit"]').first().click({ timeout: 3000 });
|
|
24131
|
+
} catch {}
|
|
24132
|
+
}
|
|
24133
|
+
}
|
|
24134
|
+
const successPattern = opts?.waitForText ?? "dashboard|profile|account|welcome|signed in|logout";
|
|
24135
|
+
const patterns = successPattern.split("|").map((p) => p.trim()).filter(Boolean);
|
|
24136
|
+
let logged_in = false;
|
|
24137
|
+
for (const pattern of patterns) {
|
|
24138
|
+
try {
|
|
24139
|
+
await waitForText2(page, pattern, { timeout: 5000 });
|
|
24140
|
+
logged_in = fillResult.errors.length === 0;
|
|
24141
|
+
break;
|
|
24142
|
+
} catch {}
|
|
24143
|
+
}
|
|
24144
|
+
if (!logged_in) {
|
|
24145
|
+
await page.waitForLoadState("domcontentloaded").catch(() => {});
|
|
24146
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
24147
|
+
const currentUrl2 = page.url();
|
|
24148
|
+
const bodyText = await page.evaluate(() => document.body?.innerText?.toLowerCase() ?? "").catch(() => "");
|
|
24149
|
+
const urlChanged = currentUrl2 !== urlBefore;
|
|
24150
|
+
const textMatch = patterns.some((p) => {
|
|
24151
|
+
const needle = p.toLowerCase();
|
|
24152
|
+
return bodyText.includes(needle) || currentUrl2.toLowerCase().includes(needle);
|
|
24153
|
+
});
|
|
24154
|
+
logged_in = fillResult.errors.length === 0 && (urlChanged || textMatch);
|
|
24155
|
+
}
|
|
24156
|
+
const currentUrl = page.url();
|
|
24072
24157
|
let profile_saved = false;
|
|
24073
24158
|
if (opts?.saveProfile && logged_in) {
|
|
24074
24159
|
try {
|
|
@@ -24080,14 +24165,14 @@ async function loginWithCredentials(page, credentials, opts) {
|
|
|
24080
24165
|
logged_in,
|
|
24081
24166
|
redirect_url: currentUrl,
|
|
24082
24167
|
profile_saved,
|
|
24083
|
-
method: "secrets_vault"
|
|
24168
|
+
method: opts?.method ?? "secrets_vault"
|
|
24084
24169
|
};
|
|
24085
24170
|
} catch (err2) {
|
|
24086
24171
|
return {
|
|
24087
24172
|
logged_in: false,
|
|
24088
24173
|
redirect_url: "",
|
|
24089
24174
|
profile_saved: false,
|
|
24090
|
-
method: "not_found",
|
|
24175
|
+
method: opts?.method ?? "not_found",
|
|
24091
24176
|
error: err2 instanceof Error ? err2.message : String(err2)
|
|
24092
24177
|
};
|
|
24093
24178
|
}
|
|
@@ -24194,11 +24279,11 @@ var init_skills_runner = __esm(() => {
|
|
|
24194
24279
|
},
|
|
24195
24280
|
login: async (page, params) => {
|
|
24196
24281
|
const { service, login_url } = params;
|
|
24197
|
-
const {
|
|
24198
|
-
const creds = await
|
|
24282
|
+
const { lookupCredentials: lookupCredentials2, loginWithCredentials: loginWithCredentials2 } = await Promise.resolve().then(() => (init_auth(), exports_auth));
|
|
24283
|
+
const { credential: creds, method } = await lookupCredentials2(service);
|
|
24199
24284
|
if (!creds)
|
|
24200
24285
|
return { logged_in: false, error: `No credentials found for ${service}` };
|
|
24201
|
-
const result = await loginWithCredentials2(page, creds, { loginUrl: login_url, saveProfile: service });
|
|
24286
|
+
const result = await loginWithCredentials2(page, creds, { loginUrl: login_url, saveProfile: service, method });
|
|
24202
24287
|
return result;
|
|
24203
24288
|
},
|
|
24204
24289
|
"extract-text": async (page, params) => {
|
|
@@ -24789,16 +24874,16 @@ function listRuns(scriptId) {
|
|
|
24789
24874
|
}
|
|
24790
24875
|
function migrateJsonScripts() {
|
|
24791
24876
|
const { existsSync: existsSync12, readdirSync: readdirSync4, readFileSync: readFileSync7 } = __require("fs");
|
|
24792
|
-
const { join:
|
|
24877
|
+
const { join: join17 } = __require("path");
|
|
24793
24878
|
const { getDataDir: getDataDir4 } = (init_schema(), __toCommonJS(exports_schema));
|
|
24794
|
-
const dir =
|
|
24879
|
+
const dir = join17(getDataDir4(), "scripts");
|
|
24795
24880
|
if (!existsSync12(dir))
|
|
24796
24881
|
return 0;
|
|
24797
24882
|
const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
|
|
24798
24883
|
let migrated = 0;
|
|
24799
24884
|
for (const file of files) {
|
|
24800
24885
|
try {
|
|
24801
|
-
const raw = JSON.parse(readFileSync7(
|
|
24886
|
+
const raw = JSON.parse(readFileSync7(join17(dir, file), "utf8"));
|
|
24802
24887
|
if (!raw.name || !raw.steps)
|
|
24803
24888
|
continue;
|
|
24804
24889
|
if (getScriptByName(raw.name))
|
|
@@ -24851,7 +24936,7 @@ var init_scripts = __esm(() => {
|
|
|
24851
24936
|
});
|
|
24852
24937
|
|
|
24853
24938
|
// src/lib/ai-inference.ts
|
|
24854
|
-
function
|
|
24939
|
+
function resolve2(opts) {
|
|
24855
24940
|
if (opts?.model && ALIASES[opts.model])
|
|
24856
24941
|
return ALIASES[opts.model];
|
|
24857
24942
|
if (opts?.provider && opts?.model)
|
|
@@ -24861,7 +24946,7 @@ function resolve(opts) {
|
|
|
24861
24946
|
return ALIASES.fast;
|
|
24862
24947
|
}
|
|
24863
24948
|
async function infer(prompt, opts) {
|
|
24864
|
-
const { provider, model } =
|
|
24949
|
+
const { provider, model } = resolve2(opts);
|
|
24865
24950
|
const maxTokens = opts?.maxTokens ?? 1024;
|
|
24866
24951
|
if (provider === "anthropic") {
|
|
24867
24952
|
const apiKey2 = process.env["ANTHROPIC_API_KEY"];
|
|
@@ -25252,7 +25337,7 @@ __export(exports_datasets, {
|
|
|
25252
25337
|
});
|
|
25253
25338
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
25254
25339
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync13 } from "fs";
|
|
25255
|
-
import { join as
|
|
25340
|
+
import { join as join17 } from "path";
|
|
25256
25341
|
function saveDataset(data) {
|
|
25257
25342
|
const db = getDatabase();
|
|
25258
25343
|
const id = randomUUID15();
|
|
@@ -25290,10 +25375,10 @@ function exportDataset(name, format) {
|
|
|
25290
25375
|
const dataset = getDatasetByName(name);
|
|
25291
25376
|
if (!dataset)
|
|
25292
25377
|
throw new Error(`Dataset '${name}' not found`);
|
|
25293
|
-
const dir =
|
|
25378
|
+
const dir = join17(getDataDir2(), "exports");
|
|
25294
25379
|
mkdirSync13(dir, { recursive: true });
|
|
25295
25380
|
const filename = `${name}.${format}`;
|
|
25296
|
-
const path =
|
|
25381
|
+
const path = join17(dir, filename);
|
|
25297
25382
|
if (format === "csv") {
|
|
25298
25383
|
const rows = dataset.data;
|
|
25299
25384
|
if (rows.length === 0) {
|
|
@@ -25441,7 +25526,7 @@ import {
|
|
|
25441
25526
|
copyFileSync as copyFileSync6
|
|
25442
25527
|
} from "fs";
|
|
25443
25528
|
import { homedir as homedir10 } from "os";
|
|
25444
|
-
import { join as
|
|
25529
|
+
import { join as join18, relative as relative3 } from "path";
|
|
25445
25530
|
import { existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
25446
25531
|
import { homedir as homedir23 } from "os";
|
|
25447
25532
|
import { join as join23 } from "path";
|
|
@@ -25453,7 +25538,7 @@ import { join as join43 } from "path";
|
|
|
25453
25538
|
import { join as join62, dirname as dirname3 } from "path";
|
|
25454
25539
|
import { homedir as homedir52, platform as platform2 } from "os";
|
|
25455
25540
|
import { existsSync as existsSync43, mkdirSync as mkdirSync33, cpSync as cpSync2 } from "fs";
|
|
25456
|
-
import { dirname as dirname23, join as join53, resolve as
|
|
25541
|
+
import { dirname as dirname23, join as join53, resolve as resolve3 } from "path";
|
|
25457
25542
|
import { existsSync as existsSync62, mkdirSync as mkdirSync52, readFileSync as readFileSync23, readdirSync as readdirSync33, writeFileSync as writeFileSync23, unlinkSync as unlinkSync3, cpSync as cpSync22 } from "fs";
|
|
25458
25543
|
import { homedir as homedir62 } from "os";
|
|
25459
25544
|
import { basename as basename2, dirname as dirname32, join as join72, resolve as resolve22 } from "path";
|
|
@@ -26279,13 +26364,13 @@ function custom3(check, _params = {}, fatal) {
|
|
|
26279
26364
|
return ZodAny3.create();
|
|
26280
26365
|
}
|
|
26281
26366
|
function getDataDir4(serviceName) {
|
|
26282
|
-
const dir =
|
|
26367
|
+
const dir = join18(HASNA_DIR2, serviceName);
|
|
26283
26368
|
mkdirSync14(dir, { recursive: true });
|
|
26284
26369
|
return dir;
|
|
26285
26370
|
}
|
|
26286
26371
|
function getDbPath2(serviceName) {
|
|
26287
26372
|
const dir = getDataDir4(serviceName);
|
|
26288
|
-
return
|
|
26373
|
+
return join18(dir, `${serviceName}.db`);
|
|
26289
26374
|
}
|
|
26290
26375
|
function getConfigDir2() {
|
|
26291
26376
|
return CONFIG_DIR3;
|
|
@@ -26504,7 +26589,7 @@ function isInMemoryDb(path) {
|
|
|
26504
26589
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
26505
26590
|
}
|
|
26506
26591
|
function findNearestMementosDb(startDir) {
|
|
26507
|
-
let dir =
|
|
26592
|
+
let dir = resolve3(startDir);
|
|
26508
26593
|
while (true) {
|
|
26509
26594
|
const candidate = join53(dir, ".mementos", "mementos.db");
|
|
26510
26595
|
if (existsSync43(candidate))
|
|
@@ -26517,7 +26602,7 @@ function findNearestMementosDb(startDir) {
|
|
|
26517
26602
|
return null;
|
|
26518
26603
|
}
|
|
26519
26604
|
function findGitRoot(startDir) {
|
|
26520
|
-
let dir =
|
|
26605
|
+
let dir = resolve3(startDir);
|
|
26521
26606
|
while (true) {
|
|
26522
26607
|
if (existsSync43(join53(dir, ".git")))
|
|
26523
26608
|
return dir;
|
|
@@ -26559,7 +26644,7 @@ function getDbPath22() {
|
|
|
26559
26644
|
function ensureDir2(filePath) {
|
|
26560
26645
|
if (isInMemoryDb(filePath))
|
|
26561
26646
|
return;
|
|
26562
|
-
const dir = dirname23(
|
|
26647
|
+
const dir = dirname23(resolve3(filePath));
|
|
26563
26648
|
if (!existsSync43(dir)) {
|
|
26564
26649
|
mkdirSync33(dir, { recursive: true });
|
|
26565
26650
|
}
|
|
@@ -32797,7 +32882,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
32797
32882
|
function parse(stream, callback) {
|
|
32798
32883
|
const parser = new parser_1.Parser;
|
|
32799
32884
|
stream.on("data", (buffer) => parser.parse(buffer, callback));
|
|
32800
|
-
return new Promise((
|
|
32885
|
+
return new Promise((resolve4) => stream.on("end", () => resolve4()));
|
|
32801
32886
|
}
|
|
32802
32887
|
exports.parse = parse;
|
|
32803
32888
|
});
|
|
@@ -33462,12 +33547,12 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
33462
33547
|
this._connect(callback);
|
|
33463
33548
|
return;
|
|
33464
33549
|
}
|
|
33465
|
-
return new this._Promise((
|
|
33550
|
+
return new this._Promise((resolve4, reject) => {
|
|
33466
33551
|
this._connect((error) => {
|
|
33467
33552
|
if (error) {
|
|
33468
33553
|
reject(error);
|
|
33469
33554
|
} else {
|
|
33470
|
-
|
|
33555
|
+
resolve4(this);
|
|
33471
33556
|
}
|
|
33472
33557
|
});
|
|
33473
33558
|
});
|
|
@@ -33799,8 +33884,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
33799
33884
|
readTimeout = config.query_timeout || this.connectionParameters.query_timeout;
|
|
33800
33885
|
query = new Query3(config, values, callback);
|
|
33801
33886
|
if (!query.callback) {
|
|
33802
|
-
result = new this._Promise((
|
|
33803
|
-
query.callback = (err2, res) => err2 ? reject(err2) :
|
|
33887
|
+
result = new this._Promise((resolve4, reject) => {
|
|
33888
|
+
query.callback = (err2, res) => err2 ? reject(err2) : resolve4(res);
|
|
33804
33889
|
}).catch((err2) => {
|
|
33805
33890
|
Error.captureStackTrace(err2);
|
|
33806
33891
|
throw err2;
|
|
@@ -33875,8 +33960,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
33875
33960
|
if (cb) {
|
|
33876
33961
|
this.connection.once("end", cb);
|
|
33877
33962
|
} else {
|
|
33878
|
-
return new this._Promise((
|
|
33879
|
-
this.connection.once("end",
|
|
33963
|
+
return new this._Promise((resolve4) => {
|
|
33964
|
+
this.connection.once("end", resolve4);
|
|
33880
33965
|
});
|
|
33881
33966
|
}
|
|
33882
33967
|
}
|
|
@@ -33921,8 +34006,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
33921
34006
|
const cb = function(err2, client) {
|
|
33922
34007
|
err2 ? rej(err2) : res(client);
|
|
33923
34008
|
};
|
|
33924
|
-
const result = new Promise2(function(
|
|
33925
|
-
res =
|
|
34009
|
+
const result = new Promise2(function(resolve4, reject) {
|
|
34010
|
+
res = resolve4;
|
|
33926
34011
|
rej = reject;
|
|
33927
34012
|
}).catch((err2) => {
|
|
33928
34013
|
Error.captureStackTrace(err2);
|
|
@@ -33983,7 +34068,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
33983
34068
|
if (typeof Promise2.try === "function") {
|
|
33984
34069
|
return Promise2.try(f);
|
|
33985
34070
|
}
|
|
33986
|
-
return new Promise2((
|
|
34071
|
+
return new Promise2((resolve4) => resolve4(f()));
|
|
33987
34072
|
}
|
|
33988
34073
|
_isFull() {
|
|
33989
34074
|
return this._clients.length >= this.options.max;
|
|
@@ -34357,8 +34442,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
34357
34442
|
NativeQuery.prototype._getPromise = function() {
|
|
34358
34443
|
if (this._promise)
|
|
34359
34444
|
return this._promise;
|
|
34360
|
-
this._promise = new Promise(function(
|
|
34361
|
-
this._once("end",
|
|
34445
|
+
this._promise = new Promise(function(resolve4, reject) {
|
|
34446
|
+
this._once("end", resolve4);
|
|
34362
34447
|
this._once("error", reject);
|
|
34363
34448
|
}.bind(this));
|
|
34364
34449
|
return this._promise;
|
|
@@ -34532,12 +34617,12 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
34532
34617
|
this._connect(callback);
|
|
34533
34618
|
return;
|
|
34534
34619
|
}
|
|
34535
|
-
return new this._Promise((
|
|
34620
|
+
return new this._Promise((resolve4, reject) => {
|
|
34536
34621
|
this._connect((error) => {
|
|
34537
34622
|
if (error) {
|
|
34538
34623
|
reject(error);
|
|
34539
34624
|
} else {
|
|
34540
|
-
|
|
34625
|
+
resolve4(this);
|
|
34541
34626
|
}
|
|
34542
34627
|
});
|
|
34543
34628
|
});
|
|
@@ -34561,8 +34646,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
34561
34646
|
query = new NativeQuery(config, values, callback);
|
|
34562
34647
|
if (!query.callback) {
|
|
34563
34648
|
let resolveOut, rejectOut;
|
|
34564
|
-
result = new this._Promise((
|
|
34565
|
-
resolveOut =
|
|
34649
|
+
result = new this._Promise((resolve4, reject) => {
|
|
34650
|
+
resolveOut = resolve4;
|
|
34566
34651
|
rejectOut = reject;
|
|
34567
34652
|
}).catch((err2) => {
|
|
34568
34653
|
Error.captureStackTrace(err2);
|
|
@@ -34620,8 +34705,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
34620
34705
|
}
|
|
34621
34706
|
let result;
|
|
34622
34707
|
if (!cb) {
|
|
34623
|
-
result = new this._Promise(function(
|
|
34624
|
-
cb = (err2) => err2 ? reject(err2) :
|
|
34708
|
+
result = new this._Promise(function(resolve4, reject) {
|
|
34709
|
+
cb = (err2) => err2 ? reject(err2) : resolve4();
|
|
34625
34710
|
});
|
|
34626
34711
|
}
|
|
34627
34712
|
this.native.end(function() {
|
|
@@ -37909,7 +37994,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
37909
37994
|
init_external2();
|
|
37910
37995
|
});
|
|
37911
37996
|
init_dotfile2 = __esm22(() => {
|
|
37912
|
-
HASNA_DIR2 =
|
|
37997
|
+
HASNA_DIR2 = join18(homedir10(), ".hasna");
|
|
37913
37998
|
});
|
|
37914
37999
|
exports_config2 = {};
|
|
37915
38000
|
__export22(exports_config2, {
|
|
@@ -39485,7 +39570,7 @@ import {
|
|
|
39485
39570
|
copyFileSync as copyFileSync7
|
|
39486
39571
|
} from "fs";
|
|
39487
39572
|
import { homedir as homedir11 } from "os";
|
|
39488
|
-
import { join as
|
|
39573
|
+
import { join as join19, relative as relative4 } from "path";
|
|
39489
39574
|
import { existsSync as existsSync24, mkdirSync as mkdirSync24, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
39490
39575
|
import { homedir as homedir24 } from "os";
|
|
39491
39576
|
import { join as join24 } from "path";
|
|
@@ -40328,13 +40413,13 @@ function custom4(check, _params = {}, fatal) {
|
|
|
40328
40413
|
return ZodAny4.create();
|
|
40329
40414
|
}
|
|
40330
40415
|
function getDataDir5(serviceName) {
|
|
40331
|
-
const dir =
|
|
40416
|
+
const dir = join19(HASNA_DIR3, serviceName);
|
|
40332
40417
|
mkdirSync15(dir, { recursive: true });
|
|
40333
40418
|
return dir;
|
|
40334
40419
|
}
|
|
40335
40420
|
function getDbPath3(serviceName) {
|
|
40336
40421
|
const dir = getDataDir5(serviceName);
|
|
40337
|
-
return
|
|
40422
|
+
return join19(dir, `${serviceName}.db`);
|
|
40338
40423
|
}
|
|
40339
40424
|
function getConfigDir3() {
|
|
40340
40425
|
return CONFIG_DIR5;
|
|
@@ -45793,7 +45878,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
45793
45878
|
function parse(stream, callback) {
|
|
45794
45879
|
const parser = new parser_1.Parser;
|
|
45795
45880
|
stream.on("data", (buffer) => parser.parse(buffer, callback));
|
|
45796
|
-
return new Promise((
|
|
45881
|
+
return new Promise((resolve4) => stream.on("end", () => resolve4()));
|
|
45797
45882
|
}
|
|
45798
45883
|
exports.parse = parse;
|
|
45799
45884
|
});
|
|
@@ -46458,12 +46543,12 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
46458
46543
|
this._connect(callback);
|
|
46459
46544
|
return;
|
|
46460
46545
|
}
|
|
46461
|
-
return new this._Promise((
|
|
46546
|
+
return new this._Promise((resolve4, reject) => {
|
|
46462
46547
|
this._connect((error) => {
|
|
46463
46548
|
if (error) {
|
|
46464
46549
|
reject(error);
|
|
46465
46550
|
} else {
|
|
46466
|
-
|
|
46551
|
+
resolve4(this);
|
|
46467
46552
|
}
|
|
46468
46553
|
});
|
|
46469
46554
|
});
|
|
@@ -46795,8 +46880,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
46795
46880
|
readTimeout = config.query_timeout || this.connectionParameters.query_timeout;
|
|
46796
46881
|
query = new Query4(config, values, callback);
|
|
46797
46882
|
if (!query.callback) {
|
|
46798
|
-
result = new this._Promise((
|
|
46799
|
-
query.callback = (err2, res) => err2 ? reject(err2) :
|
|
46883
|
+
result = new this._Promise((resolve4, reject) => {
|
|
46884
|
+
query.callback = (err2, res) => err2 ? reject(err2) : resolve4(res);
|
|
46800
46885
|
}).catch((err2) => {
|
|
46801
46886
|
Error.captureStackTrace(err2);
|
|
46802
46887
|
throw err2;
|
|
@@ -46871,8 +46956,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
46871
46956
|
if (cb) {
|
|
46872
46957
|
this.connection.once("end", cb);
|
|
46873
46958
|
} else {
|
|
46874
|
-
return new this._Promise((
|
|
46875
|
-
this.connection.once("end",
|
|
46959
|
+
return new this._Promise((resolve4) => {
|
|
46960
|
+
this.connection.once("end", resolve4);
|
|
46876
46961
|
});
|
|
46877
46962
|
}
|
|
46878
46963
|
}
|
|
@@ -46917,8 +47002,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
46917
47002
|
const cb = function(err2, client) {
|
|
46918
47003
|
err2 ? rej(err2) : res(client);
|
|
46919
47004
|
};
|
|
46920
|
-
const result = new Promise2(function(
|
|
46921
|
-
res =
|
|
47005
|
+
const result = new Promise2(function(resolve4, reject) {
|
|
47006
|
+
res = resolve4;
|
|
46922
47007
|
rej = reject;
|
|
46923
47008
|
}).catch((err2) => {
|
|
46924
47009
|
Error.captureStackTrace(err2);
|
|
@@ -46979,7 +47064,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
46979
47064
|
if (typeof Promise2.try === "function") {
|
|
46980
47065
|
return Promise2.try(f);
|
|
46981
47066
|
}
|
|
46982
|
-
return new Promise2((
|
|
47067
|
+
return new Promise2((resolve4) => resolve4(f()));
|
|
46983
47068
|
}
|
|
46984
47069
|
_isFull() {
|
|
46985
47070
|
return this._clients.length >= this.options.max;
|
|
@@ -47353,8 +47438,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
47353
47438
|
NativeQuery.prototype._getPromise = function() {
|
|
47354
47439
|
if (this._promise)
|
|
47355
47440
|
return this._promise;
|
|
47356
|
-
this._promise = new Promise(function(
|
|
47357
|
-
this._once("end",
|
|
47441
|
+
this._promise = new Promise(function(resolve4, reject) {
|
|
47442
|
+
this._once("end", resolve4);
|
|
47358
47443
|
this._once("error", reject);
|
|
47359
47444
|
}.bind(this));
|
|
47360
47445
|
return this._promise;
|
|
@@ -47528,12 +47613,12 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
47528
47613
|
this._connect(callback);
|
|
47529
47614
|
return;
|
|
47530
47615
|
}
|
|
47531
|
-
return new this._Promise((
|
|
47616
|
+
return new this._Promise((resolve4, reject) => {
|
|
47532
47617
|
this._connect((error) => {
|
|
47533
47618
|
if (error) {
|
|
47534
47619
|
reject(error);
|
|
47535
47620
|
} else {
|
|
47536
|
-
|
|
47621
|
+
resolve4(this);
|
|
47537
47622
|
}
|
|
47538
47623
|
});
|
|
47539
47624
|
});
|
|
@@ -47557,8 +47642,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
47557
47642
|
query = new NativeQuery(config, values, callback);
|
|
47558
47643
|
if (!query.callback) {
|
|
47559
47644
|
let resolveOut, rejectOut;
|
|
47560
|
-
result = new this._Promise((
|
|
47561
|
-
resolveOut =
|
|
47645
|
+
result = new this._Promise((resolve4, reject) => {
|
|
47646
|
+
resolveOut = resolve4;
|
|
47562
47647
|
rejectOut = reject;
|
|
47563
47648
|
}).catch((err2) => {
|
|
47564
47649
|
Error.captureStackTrace(err2);
|
|
@@ -47616,8 +47701,8 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
47616
47701
|
}
|
|
47617
47702
|
let result;
|
|
47618
47703
|
if (!cb) {
|
|
47619
|
-
result = new this._Promise(function(
|
|
47620
|
-
cb = (err2) => err2 ? reject(err2) :
|
|
47704
|
+
result = new this._Promise(function(resolve4, reject) {
|
|
47705
|
+
cb = (err2) => err2 ? reject(err2) : resolve4();
|
|
47621
47706
|
});
|
|
47622
47707
|
}
|
|
47623
47708
|
this.native.end(function() {
|
|
@@ -50905,7 +50990,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
50905
50990
|
init_external3();
|
|
50906
50991
|
});
|
|
50907
50992
|
init_dotfile3 = __esm23(() => {
|
|
50908
|
-
HASNA_DIR3 =
|
|
50993
|
+
HASNA_DIR3 = join19(homedir11(), ".hasna");
|
|
50909
50994
|
});
|
|
50910
50995
|
exports_config3 = {};
|
|
50911
50996
|
__export23(exports_config3, {
|
|
@@ -52667,14 +52752,14 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
52667
52752
|
var thenableResult = result;
|
|
52668
52753
|
var wasAwaited = false;
|
|
52669
52754
|
var thenable = {
|
|
52670
|
-
then: function(
|
|
52755
|
+
then: function(resolve4, reject) {
|
|
52671
52756
|
wasAwaited = true;
|
|
52672
52757
|
thenableResult.then(function(returnValue2) {
|
|
52673
52758
|
popActScope(prevActScopeDepth);
|
|
52674
52759
|
if (actScopeDepth === 0) {
|
|
52675
|
-
recursivelyFlushAsyncActWork(returnValue2,
|
|
52760
|
+
recursivelyFlushAsyncActWork(returnValue2, resolve4, reject);
|
|
52676
52761
|
} else {
|
|
52677
|
-
|
|
52762
|
+
resolve4(returnValue2);
|
|
52678
52763
|
}
|
|
52679
52764
|
}, function(error2) {
|
|
52680
52765
|
popActScope(prevActScopeDepth);
|
|
@@ -52703,20 +52788,20 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
52703
52788
|
ReactCurrentActQueue.current = null;
|
|
52704
52789
|
}
|
|
52705
52790
|
var _thenable = {
|
|
52706
|
-
then: function(
|
|
52791
|
+
then: function(resolve4, reject) {
|
|
52707
52792
|
if (ReactCurrentActQueue.current === null) {
|
|
52708
52793
|
ReactCurrentActQueue.current = [];
|
|
52709
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
52794
|
+
recursivelyFlushAsyncActWork(returnValue, resolve4, reject);
|
|
52710
52795
|
} else {
|
|
52711
|
-
|
|
52796
|
+
resolve4(returnValue);
|
|
52712
52797
|
}
|
|
52713
52798
|
}
|
|
52714
52799
|
};
|
|
52715
52800
|
return _thenable;
|
|
52716
52801
|
} else {
|
|
52717
52802
|
var _thenable2 = {
|
|
52718
|
-
then: function(
|
|
52719
|
-
|
|
52803
|
+
then: function(resolve4, reject) {
|
|
52804
|
+
resolve4(returnValue);
|
|
52720
52805
|
}
|
|
52721
52806
|
};
|
|
52722
52807
|
return _thenable2;
|
|
@@ -52732,7 +52817,7 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
52732
52817
|
actScopeDepth = prevActScopeDepth;
|
|
52733
52818
|
}
|
|
52734
52819
|
}
|
|
52735
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
52820
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve4, reject) {
|
|
52736
52821
|
{
|
|
52737
52822
|
var queue = ReactCurrentActQueue.current;
|
|
52738
52823
|
if (queue !== null) {
|
|
@@ -52741,16 +52826,16 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
52741
52826
|
enqueueTask(function() {
|
|
52742
52827
|
if (queue.length === 0) {
|
|
52743
52828
|
ReactCurrentActQueue.current = null;
|
|
52744
|
-
|
|
52829
|
+
resolve4(returnValue);
|
|
52745
52830
|
} else {
|
|
52746
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
52831
|
+
recursivelyFlushAsyncActWork(returnValue, resolve4, reject);
|
|
52747
52832
|
}
|
|
52748
52833
|
});
|
|
52749
52834
|
} catch (error2) {
|
|
52750
52835
|
reject(error2);
|
|
52751
52836
|
}
|
|
52752
52837
|
} else {
|
|
52753
|
-
|
|
52838
|
+
resolve4(returnValue);
|
|
52754
52839
|
}
|
|
52755
52840
|
}
|
|
52756
52841
|
}
|
|
@@ -53670,7 +53755,7 @@ __export(exports_dist4, {
|
|
|
53670
53755
|
import { hostname as osHostname, platform as osPlatform } from "os";
|
|
53671
53756
|
import { Database as Database4 } from "bun:sqlite";
|
|
53672
53757
|
import { existsSync as existsSync14, mkdirSync as mkdirSync16 } from "fs";
|
|
53673
|
-
import { dirname as dirname5, join as
|
|
53758
|
+
import { dirname as dirname5, join as join20, resolve as resolve4 } from "path";
|
|
53674
53759
|
import { existsSync as existsSync35 } from "fs";
|
|
53675
53760
|
import { join as join35 } from "path";
|
|
53676
53761
|
import { existsSync as existsSync25, mkdirSync as mkdirSync25, readFileSync as readFileSync10, readdirSync as readdirSync11, statSync as statSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
@@ -53691,7 +53776,7 @@ import {
|
|
|
53691
53776
|
copyFileSync as copyFileSync8
|
|
53692
53777
|
} from "fs";
|
|
53693
53778
|
import { homedir as homedir25 } from "os";
|
|
53694
|
-
import { join as join74, relative as
|
|
53779
|
+
import { join as join74, relative as relative5 } from "path";
|
|
53695
53780
|
import { existsSync as existsSync222, mkdirSync as mkdirSync222, readFileSync as readFileSync45, writeFileSync as writeFileSync43 } from "fs";
|
|
53696
53781
|
import { homedir as homedir222 } from "os";
|
|
53697
53782
|
import { join as join222 } from "path";
|
|
@@ -54149,9 +54234,9 @@ function isInMemoryDb2(path) {
|
|
|
54149
54234
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
54150
54235
|
}
|
|
54151
54236
|
function findNearestTodosDb(startDir) {
|
|
54152
|
-
let dir =
|
|
54237
|
+
let dir = resolve4(startDir);
|
|
54153
54238
|
while (true) {
|
|
54154
|
-
const candidate =
|
|
54239
|
+
const candidate = join20(dir, ".todos", "todos.db");
|
|
54155
54240
|
if (existsSync14(candidate))
|
|
54156
54241
|
return candidate;
|
|
54157
54242
|
const parent = dirname5(dir);
|
|
@@ -54162,9 +54247,9 @@ function findNearestTodosDb(startDir) {
|
|
|
54162
54247
|
return null;
|
|
54163
54248
|
}
|
|
54164
54249
|
function findGitRoot2(startDir) {
|
|
54165
|
-
let dir =
|
|
54250
|
+
let dir = resolve4(startDir);
|
|
54166
54251
|
while (true) {
|
|
54167
|
-
if (existsSync14(
|
|
54252
|
+
if (existsSync14(join20(dir, ".git")))
|
|
54168
54253
|
return dir;
|
|
54169
54254
|
const parent = dirname5(dir);
|
|
54170
54255
|
if (parent === dir)
|
|
@@ -54187,12 +54272,12 @@ function getDbPath4() {
|
|
|
54187
54272
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
54188
54273
|
const gitRoot = findGitRoot2(cwd);
|
|
54189
54274
|
if (gitRoot) {
|
|
54190
|
-
return
|
|
54275
|
+
return join20(gitRoot, ".todos", "todos.db");
|
|
54191
54276
|
}
|
|
54192
54277
|
}
|
|
54193
54278
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
54194
|
-
const newPath =
|
|
54195
|
-
const legacyPath =
|
|
54279
|
+
const newPath = join20(home, ".hasna", "todos", "todos.db");
|
|
54280
|
+
const legacyPath = join20(home, ".todos", "todos.db");
|
|
54196
54281
|
if (!existsSync14(newPath) && existsSync14(legacyPath)) {
|
|
54197
54282
|
return legacyPath;
|
|
54198
54283
|
}
|
|
@@ -54201,7 +54286,7 @@ function getDbPath4() {
|
|
|
54201
54286
|
function ensureDir3(filePath) {
|
|
54202
54287
|
if (isInMemoryDb2(filePath))
|
|
54203
54288
|
return;
|
|
54204
|
-
const dir = dirname5(
|
|
54289
|
+
const dir = dirname5(resolve4(filePath));
|
|
54205
54290
|
if (!existsSync14(dir)) {
|
|
54206
54291
|
mkdirSync16(dir, { recursive: true });
|
|
54207
54292
|
}
|
|
@@ -70827,7 +70912,7 @@ init_dist();
|
|
|
70827
70912
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
70828
70913
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
70829
70914
|
import { readFileSync as readFileSync11 } from "fs";
|
|
70830
|
-
import { join as
|
|
70915
|
+
import { join as join21 } from "path";
|
|
70831
70916
|
|
|
70832
70917
|
// node_modules/zod/v3/external.js
|
|
70833
70918
|
var exports_external2 = {};
|
|
@@ -74812,12 +74897,12 @@ init_types2();
|
|
|
74812
74897
|
init_gallery();
|
|
74813
74898
|
init_schema();
|
|
74814
74899
|
var import_sharp = __toESM(require_lib3(), 1);
|
|
74815
|
-
import { join as
|
|
74900
|
+
import { join as join10 } from "path";
|
|
74816
74901
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
74817
74902
|
function getScreenshotDir(projectId) {
|
|
74818
|
-
const base =
|
|
74903
|
+
const base = join10(getDataDir2(), "screenshots");
|
|
74819
74904
|
const date = new Date().toISOString().split("T")[0];
|
|
74820
|
-
const dir = projectId ?
|
|
74905
|
+
const dir = projectId ? join10(base, projectId, date) : join10(base, date);
|
|
74821
74906
|
mkdirSync7(dir, { recursive: true });
|
|
74822
74907
|
return dir;
|
|
74823
74908
|
}
|
|
@@ -74833,7 +74918,7 @@ async function compressBuffer(raw, format, quality, maxWidth) {
|
|
|
74833
74918
|
}
|
|
74834
74919
|
}
|
|
74835
74920
|
async function generateThumbnail(raw, dir, stem) {
|
|
74836
|
-
const thumbPath =
|
|
74921
|
+
const thumbPath = join10(dir, `${stem}.thumb.webp`);
|
|
74837
74922
|
const thumbBuffer = await import_sharp.default(raw).resize({ width: 200, withoutEnlargement: true }).webp({ quality: 70, effort: 3 }).toBuffer();
|
|
74838
74923
|
await Bun.write(thumbPath, thumbBuffer);
|
|
74839
74924
|
return { path: thumbPath, base64: thumbBuffer.toString("base64") };
|
|
@@ -74901,7 +74986,7 @@ async function takeScreenshot(page, opts) {
|
|
|
74901
74986
|
const compressedSizeBytes = finalBuffer.length;
|
|
74902
74987
|
const compressionRatio = originalSizeBytes > 0 ? compressedSizeBytes / originalSizeBytes : 1;
|
|
74903
74988
|
const ext = format;
|
|
74904
|
-
const screenshotPath = opts?.path ??
|
|
74989
|
+
const screenshotPath = opts?.path ?? join10(dir, `${stem}.${ext}`);
|
|
74905
74990
|
await Bun.write(screenshotPath, finalBuffer);
|
|
74906
74991
|
let thumbnailPath;
|
|
74907
74992
|
let thumbnailBase64;
|
|
@@ -74961,12 +75046,12 @@ async function takeScreenshot(page, opts) {
|
|
|
74961
75046
|
}
|
|
74962
75047
|
async function generatePDF(page, opts) {
|
|
74963
75048
|
try {
|
|
74964
|
-
const base =
|
|
75049
|
+
const base = join10(getDataDir2(), "pdfs");
|
|
74965
75050
|
const date = new Date().toISOString().split("T")[0];
|
|
74966
|
-
const dir = opts?.projectId ?
|
|
75051
|
+
const dir = opts?.projectId ? join10(base, opts.projectId, date) : join10(base, date);
|
|
74967
75052
|
mkdirSync7(dir, { recursive: true });
|
|
74968
75053
|
const timestamp = Date.now();
|
|
74969
|
-
const pdfPath = opts?.path ??
|
|
75054
|
+
const pdfPath = opts?.path ?? join10(dir, `${timestamp}.pdf`);
|
|
74970
75055
|
const buffer = await page.pdf({
|
|
74971
75056
|
path: pdfPath,
|
|
74972
75057
|
format: opts?.format ?? "A4",
|
|
@@ -75218,11 +75303,11 @@ init_gallery();
|
|
|
75218
75303
|
// src/lib/downloads.ts
|
|
75219
75304
|
init_schema();
|
|
75220
75305
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
75221
|
-
import { join as
|
|
75306
|
+
import { join as join11, basename, extname } from "path";
|
|
75222
75307
|
import { mkdirSync as mkdirSync8, existsSync as existsSync7, readdirSync as readdirSync6, statSync as statSync2, unlinkSync as unlinkSync2, copyFileSync as copyFileSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
|
|
75223
75308
|
function getDownloadsDir(sessionId) {
|
|
75224
|
-
const base =
|
|
75225
|
-
const dir = sessionId ?
|
|
75309
|
+
const base = join11(getDataDir2(), "downloads");
|
|
75310
|
+
const dir = sessionId ? join11(base, sessionId) : base;
|
|
75226
75311
|
mkdirSync8(dir, { recursive: true });
|
|
75227
75312
|
return dir;
|
|
75228
75313
|
}
|
|
@@ -75235,7 +75320,7 @@ function saveToDownloads(buffer, filename, opts) {
|
|
|
75235
75320
|
const ext = extname(filename) || "";
|
|
75236
75321
|
const stem = basename(filename, ext);
|
|
75237
75322
|
const uniqueName = `${stem}-${id.slice(0, 8)}${ext}`;
|
|
75238
|
-
const filePath =
|
|
75323
|
+
const filePath = join11(dir, uniqueName);
|
|
75239
75324
|
writeFileSync2(filePath, buffer);
|
|
75240
75325
|
const meta = {
|
|
75241
75326
|
id,
|
|
@@ -75270,7 +75355,7 @@ function listDownloads(sessionId) {
|
|
|
75270
75355
|
for (const entry of entries) {
|
|
75271
75356
|
if (entry.endsWith(".meta.json"))
|
|
75272
75357
|
continue;
|
|
75273
|
-
const full =
|
|
75358
|
+
const full = join11(d, entry);
|
|
75274
75359
|
const stat = statSync2(full);
|
|
75275
75360
|
if (stat.isDirectory()) {
|
|
75276
75361
|
scanDir(full);
|
|
@@ -75359,7 +75444,7 @@ init_snapshot();
|
|
|
75359
75444
|
|
|
75360
75445
|
// src/lib/files-integration.ts
|
|
75361
75446
|
init_schema();
|
|
75362
|
-
import { join as
|
|
75447
|
+
import { join as join13 } from "path";
|
|
75363
75448
|
import { mkdirSync as mkdirSync10, copyFileSync as copyFileSync4 } from "fs";
|
|
75364
75449
|
async function persistFile(localPath, opts) {
|
|
75365
75450
|
try {
|
|
@@ -75371,10 +75456,10 @@ async function persistFile(localPath, opts) {
|
|
|
75371
75456
|
} catch {}
|
|
75372
75457
|
const dataDir = getDataDir2();
|
|
75373
75458
|
const date = new Date().toISOString().split("T")[0];
|
|
75374
|
-
const dir =
|
|
75459
|
+
const dir = join13(dataDir, "persistent", date);
|
|
75375
75460
|
mkdirSync10(dir, { recursive: true });
|
|
75376
75461
|
const filename = localPath.split("/").pop() ?? "file";
|
|
75377
|
-
const targetPath =
|
|
75462
|
+
const targetPath = join13(dir, filename);
|
|
75378
75463
|
copyFileSync4(localPath, targetPath);
|
|
75379
75464
|
return {
|
|
75380
75465
|
id: `local-${Date.now()}`,
|
|
@@ -76117,7 +76202,7 @@ function register2(server) {
|
|
|
76117
76202
|
page.on("response", onResponse);
|
|
76118
76203
|
page.on("requestfailed", onFailed);
|
|
76119
76204
|
try {
|
|
76120
|
-
await new Promise((
|
|
76205
|
+
await new Promise((resolve2, reject) => {
|
|
76121
76206
|
const check = () => {
|
|
76122
76207
|
const now = Date.now();
|
|
76123
76208
|
if (now - t0 > timeout) {
|
|
@@ -76125,7 +76210,7 @@ function register2(server) {
|
|
|
76125
76210
|
return;
|
|
76126
76211
|
}
|
|
76127
76212
|
if (pending === 0 && now - lastActivity >= idle_time) {
|
|
76128
|
-
|
|
76213
|
+
resolve2();
|
|
76129
76214
|
return;
|
|
76130
76215
|
}
|
|
76131
76216
|
setTimeout(check, 100);
|
|
@@ -76647,7 +76732,7 @@ function register3(server) {
|
|
|
76647
76732
|
await new Promise((r) => setTimeout(r, wait_ms));
|
|
76648
76733
|
const ss2 = await takeScreenshot(page, { maxWidth: 1280, compress: true, track: false });
|
|
76649
76734
|
const { diffImages: diffImages2 } = await Promise.resolve().then(() => (init_gallery_diff(), exports_gallery_diff));
|
|
76650
|
-
const diff = await diffImages2(ss1.path, ss2.path);
|
|
76735
|
+
const diff = await diffImages2(ss1.path, ss2.path, threshold);
|
|
76651
76736
|
logEvent(sid, "diff", { url1, url2, changed_percent: diff.changed_percent });
|
|
76652
76737
|
return json({
|
|
76653
76738
|
url1,
|
|
@@ -77623,13 +77708,14 @@ function registerIntegrationAndMeta(server) {
|
|
|
77623
77708
|
try {
|
|
77624
77709
|
const sid = resolveSessionId(session_id);
|
|
77625
77710
|
const page = getSessionPage(sid);
|
|
77626
|
-
const {
|
|
77627
|
-
const creds = await
|
|
77711
|
+
const { lookupCredentials: lookupCredentials2, loginWithCredentials: loginWithCredentials2 } = await Promise.resolve().then(() => (init_auth(), exports_auth));
|
|
77712
|
+
const { credential: creds, method } = await lookupCredentials2(service);
|
|
77628
77713
|
if (!creds)
|
|
77629
77714
|
return err(new Error(`No credentials found for '${service}'. Add them: secrets set ${service}_email yourlogin && secrets set ${service}_password yourpass`));
|
|
77630
77715
|
const result = await loginWithCredentials2(page, creds, {
|
|
77631
77716
|
loginUrl: login_url,
|
|
77632
|
-
saveProfile: save_profile ? service : undefined
|
|
77717
|
+
saveProfile: save_profile ? service : undefined,
|
|
77718
|
+
method
|
|
77633
77719
|
});
|
|
77634
77720
|
return json(result);
|
|
77635
77721
|
} catch (e) {
|
|
@@ -77994,6 +78080,7 @@ function register8(server) {
|
|
|
77994
78080
|
// src/mcp/tui.ts
|
|
77995
78081
|
init_tui();
|
|
77996
78082
|
init_session();
|
|
78083
|
+
init_tui_recording();
|
|
77997
78084
|
var DEFAULT_TOOL_TIMEOUT_MS2 = 15000;
|
|
77998
78085
|
var RECONNECT_ON_STUCK = true;
|
|
77999
78086
|
var KEY_MAP = {
|
|
@@ -78048,7 +78135,11 @@ function assertTuiSession(sessionId) {
|
|
|
78048
78135
|
}
|
|
78049
78136
|
}
|
|
78050
78137
|
function getTuiSession(sessionId) {
|
|
78051
|
-
|
|
78138
|
+
const session = getSessionTuiSession(sessionId);
|
|
78139
|
+
if (!session) {
|
|
78140
|
+
throw new Error(`TUI session handle missing for session ${sessionId}. Close and re-open with engine="tui".`);
|
|
78141
|
+
}
|
|
78142
|
+
return session;
|
|
78052
78143
|
}
|
|
78053
78144
|
function getTuiMeta(sessionId) {
|
|
78054
78145
|
const session = getTuiSession(sessionId);
|
|
@@ -78095,19 +78186,19 @@ async function withTuiHealth(sessionId, operation, options = {}) {
|
|
|
78095
78186
|
} else if (!health.healthy) {
|
|
78096
78187
|
throw Object.assign(new Error(`TUI session is unhealthy: ${health.reason}. Close and reopen the session.`), { code: "TUI_UNHEALTHY" });
|
|
78097
78188
|
}
|
|
78098
|
-
let
|
|
78099
|
-
const
|
|
78100
|
-
|
|
78101
|
-
}, timeoutMs);
|
|
78102
|
-
try {
|
|
78103
|
-
return await operation(page, session);
|
|
78104
|
-
} catch (error) {
|
|
78105
|
-
if (timedOut) {
|
|
78189
|
+
let timer;
|
|
78190
|
+
const timeout = new Promise((_, reject) => {
|
|
78191
|
+
timer = setTimeout(() => {
|
|
78106
78192
|
const err2 = new Error(`${operationName} timed out after ${timeoutMs}ms \u2014 ttyd/playwright connection may be unhealthy. Status: ${health.healthy ? "was healthy before op" : "was already unhealthy"}. Try closing and re-opening the session.`);
|
|
78107
78193
|
Object.assign(err2, { code: "TUI_TIMEOUT" });
|
|
78108
|
-
|
|
78109
|
-
}
|
|
78110
|
-
|
|
78194
|
+
reject(err2);
|
|
78195
|
+
}, timeoutMs);
|
|
78196
|
+
});
|
|
78197
|
+
try {
|
|
78198
|
+
return await Promise.race([
|
|
78199
|
+
operation(page, session),
|
|
78200
|
+
timeout
|
|
78201
|
+
]);
|
|
78111
78202
|
} finally {
|
|
78112
78203
|
clearTimeout(timer);
|
|
78113
78204
|
}
|
|
@@ -78406,6 +78497,7 @@ CONDITION SYNTAX:
|
|
|
78406
78497
|
}, interval_ms)
|
|
78407
78498
|
};
|
|
78408
78499
|
activeRecordings2.set(sid, recording);
|
|
78500
|
+
trackTuiRecording(sid, recording.intervalId);
|
|
78409
78501
|
return json({
|
|
78410
78502
|
recording: true,
|
|
78411
78503
|
session_id: sid,
|
|
@@ -78425,6 +78517,7 @@ CONDITION SYNTAX:
|
|
|
78425
78517
|
if (!recording)
|
|
78426
78518
|
return err(new Error("No active recording for this session"));
|
|
78427
78519
|
clearInterval(recording.intervalId);
|
|
78520
|
+
stopTuiRecording(sid);
|
|
78428
78521
|
activeRecordings2.delete(sid);
|
|
78429
78522
|
const duration = (Date.now() - recording.startTime) / 1000;
|
|
78430
78523
|
const header = {
|
|
@@ -78471,20 +78564,170 @@ CONDITION SYNTAX:
|
|
|
78471
78564
|
});
|
|
78472
78565
|
}
|
|
78473
78566
|
|
|
78567
|
+
// src/mcp/http.ts
|
|
78568
|
+
import { createServer } from "http";
|
|
78569
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
78570
|
+
var MCP_HTTP_SERVICE_NAME = "browser";
|
|
78571
|
+
var DEFAULT_MCP_HTTP_PORT = 8802;
|
|
78572
|
+
function isHttpMode(argv = process.argv, env = process.env) {
|
|
78573
|
+
return argv.includes("--http") || env.MCP_HTTP === "1";
|
|
78574
|
+
}
|
|
78575
|
+
function resolveMcpHttpPort(argv = process.argv, env = process.env) {
|
|
78576
|
+
const portIdx = argv.indexOf("--port");
|
|
78577
|
+
if (portIdx !== -1 && argv[portIdx + 1]) {
|
|
78578
|
+
return parsePort(argv[portIdx + 1], "--port");
|
|
78579
|
+
}
|
|
78580
|
+
if (env.MCP_HTTP_PORT) {
|
|
78581
|
+
return parsePort(env.MCP_HTTP_PORT, "MCP_HTTP_PORT");
|
|
78582
|
+
}
|
|
78583
|
+
return DEFAULT_MCP_HTTP_PORT;
|
|
78584
|
+
}
|
|
78585
|
+
function parsePort(raw, source) {
|
|
78586
|
+
const parsed = Number(raw);
|
|
78587
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
|
|
78588
|
+
throw new Error(`Invalid ${source} value "${raw}". Expected 0-65535.`);
|
|
78589
|
+
}
|
|
78590
|
+
return parsed;
|
|
78591
|
+
}
|
|
78592
|
+
async function readJsonBody(req) {
|
|
78593
|
+
const chunks = [];
|
|
78594
|
+
for await (const chunk of req) {
|
|
78595
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
78596
|
+
}
|
|
78597
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
78598
|
+
if (!text)
|
|
78599
|
+
return;
|
|
78600
|
+
return JSON.parse(text);
|
|
78601
|
+
}
|
|
78602
|
+
async function startMcpHttpServer(buildServer, options) {
|
|
78603
|
+
const host = options?.host ?? "127.0.0.1";
|
|
78604
|
+
const requestedPort = options?.port ?? resolveMcpHttpPort();
|
|
78605
|
+
const serviceName = options?.serviceName ?? MCP_HTTP_SERVICE_NAME;
|
|
78606
|
+
const httpServer = createServer(async (req, res) => {
|
|
78607
|
+
try {
|
|
78608
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
78609
|
+
if (req.method === "GET" && url.pathname === "/health") {
|
|
78610
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
78611
|
+
res.end(JSON.stringify({ status: "ok", name: serviceName }));
|
|
78612
|
+
return;
|
|
78613
|
+
}
|
|
78614
|
+
if (url.pathname !== "/mcp") {
|
|
78615
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
78616
|
+
res.end("Not Found");
|
|
78617
|
+
return;
|
|
78618
|
+
}
|
|
78619
|
+
const server = buildServer();
|
|
78620
|
+
const transport = new StreamableHTTPServerTransport({
|
|
78621
|
+
sessionIdGenerator: undefined
|
|
78622
|
+
});
|
|
78623
|
+
await server.connect(transport);
|
|
78624
|
+
let parsedBody;
|
|
78625
|
+
if (req.method === "POST") {
|
|
78626
|
+
parsedBody = await readJsonBody(req);
|
|
78627
|
+
}
|
|
78628
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
78629
|
+
res.on("close", () => {
|
|
78630
|
+
transport.close();
|
|
78631
|
+
server.close();
|
|
78632
|
+
});
|
|
78633
|
+
} catch (error) {
|
|
78634
|
+
console.error(`[${serviceName}-mcp] HTTP error:`, error);
|
|
78635
|
+
if (!res.headersSent) {
|
|
78636
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
78637
|
+
res.end(JSON.stringify({
|
|
78638
|
+
jsonrpc: "2.0",
|
|
78639
|
+
error: { code: -32603, message: "Internal server error" },
|
|
78640
|
+
id: null
|
|
78641
|
+
}));
|
|
78642
|
+
}
|
|
78643
|
+
}
|
|
78644
|
+
});
|
|
78645
|
+
await new Promise((resolve5, reject) => {
|
|
78646
|
+
httpServer.once("error", reject);
|
|
78647
|
+
httpServer.listen(requestedPort, host, () => resolve5());
|
|
78648
|
+
});
|
|
78649
|
+
const addr = httpServer.address();
|
|
78650
|
+
const port = typeof addr === "object" && addr ? addr.port : requestedPort;
|
|
78651
|
+
console.error(`[${serviceName}-mcp] Streamable HTTP listening on http://${host}:${port}/mcp`);
|
|
78652
|
+
return {
|
|
78653
|
+
port,
|
|
78654
|
+
host,
|
|
78655
|
+
close: () => new Promise((resolve5, reject) => {
|
|
78656
|
+
httpServer.close((err2) => err2 ? reject(err2) : resolve5());
|
|
78657
|
+
})
|
|
78658
|
+
};
|
|
78659
|
+
}
|
|
78660
|
+
|
|
78474
78661
|
// src/mcp/index.ts
|
|
78475
|
-
var _pkg = JSON.parse(readFileSync11(
|
|
78476
|
-
|
|
78477
|
-
|
|
78478
|
-
|
|
78479
|
-
|
|
78480
|
-
|
|
78481
|
-
|
|
78482
|
-
|
|
78483
|
-
|
|
78484
|
-
|
|
78485
|
-
|
|
78486
|
-
|
|
78487
|
-
|
|
78488
|
-
|
|
78489
|
-
|
|
78490
|
-
|
|
78662
|
+
var _pkg = JSON.parse(readFileSync11(join21(import.meta.dir, "../../package.json"), "utf8"));
|
|
78663
|
+
function buildServer() {
|
|
78664
|
+
const server = new McpServer2({
|
|
78665
|
+
name: "@hasna/browser",
|
|
78666
|
+
version: _pkg.version
|
|
78667
|
+
});
|
|
78668
|
+
register(server);
|
|
78669
|
+
register2(server);
|
|
78670
|
+
register3(server);
|
|
78671
|
+
register4(server);
|
|
78672
|
+
register8(server);
|
|
78673
|
+
register9(server);
|
|
78674
|
+
registerCloudTools(server, "browser");
|
|
78675
|
+
return server;
|
|
78676
|
+
}
|
|
78677
|
+
function hasFlag(...flags) {
|
|
78678
|
+
return process.argv.some((arg) => flags.includes(arg));
|
|
78679
|
+
}
|
|
78680
|
+
function printHelp() {
|
|
78681
|
+
process.stdout.write(`Usage: browser-mcp [options]
|
|
78682
|
+
|
|
78683
|
+
Browser MCP server (stdio transport by default)
|
|
78684
|
+
|
|
78685
|
+
Options:
|
|
78686
|
+
--http Serve MCP over Streamable HTTP (127.0.0.1)
|
|
78687
|
+
--port <number> HTTP port (default: 8802, env: MCP_HTTP_PORT)
|
|
78688
|
+
-h, --help Show help
|
|
78689
|
+
-V, --version Show version
|
|
78690
|
+
`);
|
|
78691
|
+
}
|
|
78692
|
+
async function logStartup(server) {
|
|
78693
|
+
const startupToolCount = Object.keys(server._registeredTools ?? {}).length;
|
|
78694
|
+
const { getDataDir: getDataDir7 } = await Promise.resolve().then(() => (init_schema(), exports_schema));
|
|
78695
|
+
console.error(`@hasna/browser v${_pkg.version} \u2014 ${startupToolCount} tools | data: ${getDataDir7()}`);
|
|
78696
|
+
}
|
|
78697
|
+
async function main() {
|
|
78698
|
+
if (hasFlag("--help", "-h")) {
|
|
78699
|
+
printHelp();
|
|
78700
|
+
return;
|
|
78701
|
+
}
|
|
78702
|
+
if (hasFlag("--version", "-V")) {
|
|
78703
|
+
process.stdout.write(`${_pkg.version}
|
|
78704
|
+
`);
|
|
78705
|
+
return;
|
|
78706
|
+
}
|
|
78707
|
+
if (isHttpMode()) {
|
|
78708
|
+
const handle = await startMcpHttpServer(buildServer, {
|
|
78709
|
+
port: resolveMcpHttpPort()
|
|
78710
|
+
});
|
|
78711
|
+
await logStartup(buildServer());
|
|
78712
|
+
process.on("SIGINT", () => {
|
|
78713
|
+
handle.close().finally(() => process.exit(0));
|
|
78714
|
+
});
|
|
78715
|
+
process.on("SIGTERM", () => {
|
|
78716
|
+
handle.close().finally(() => process.exit(0));
|
|
78717
|
+
});
|
|
78718
|
+
return;
|
|
78719
|
+
}
|
|
78720
|
+
const server = buildServer();
|
|
78721
|
+
await logStartup(server);
|
|
78722
|
+
const transport = new StdioServerTransport;
|
|
78723
|
+
await server.connect(transport);
|
|
78724
|
+
}
|
|
78725
|
+
if (import.meta.main) {
|
|
78726
|
+
main().catch((error) => {
|
|
78727
|
+
console.error("MCP server error:", error);
|
|
78728
|
+
process.exit(1);
|
|
78729
|
+
});
|
|
78730
|
+
}
|
|
78731
|
+
export {
|
|
78732
|
+
buildServer
|
|
78733
|
+
};
|