@datasynx/agentic-ai-cartography 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readFirefoxHistory,
4
+ scanAllBookmarks,
5
+ scanAllHistory
6
+ } from "./chunk-2VIAXA5T.js";
7
+ export {
8
+ readFirefoxHistory,
9
+ scanAllBookmarks,
10
+ scanAllHistory
11
+ };
12
+ //# sourceMappingURL=bookmarks-ITLW7U5D.js.map
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bookmarks.ts
4
+ import { homedir, tmpdir } from "os";
5
+ import { existsSync, readFileSync, readdirSync, copyFileSync, statSync } from "fs";
6
+ import { join } from "path";
7
+ function extractHost(rawUrl, source) {
8
+ try {
9
+ const u = new URL(rawUrl);
10
+ if (u.protocol !== "http:" && u.protocol !== "https:") return null;
11
+ const protocol = u.protocol === "https:" ? "https" : "http";
12
+ const port = u.port ? parseInt(u.port, 10) : protocol === "https" ? 443 : 80;
13
+ const hostname = u.hostname.toLowerCase();
14
+ if (!hostname || hostname === "localhost" || hostname === "127.0.0.1") return null;
15
+ return { hostname, port, protocol, source };
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ function walkChrome(node, source, out) {
21
+ if (node.type === "url" && node.url) {
22
+ const h = extractHost(node.url, source);
23
+ if (h) out.push(h);
24
+ }
25
+ if (node.children) {
26
+ for (const child of node.children) walkChrome(child, source, out);
27
+ }
28
+ }
29
+ function readChromeLike(filePath, source) {
30
+ if (!existsSync(filePath)) return [];
31
+ try {
32
+ const raw = JSON.parse(readFileSync(filePath, "utf8"));
33
+ const out = [];
34
+ for (const root of Object.values(raw.roots)) {
35
+ if (root) walkChrome(root, source, out);
36
+ }
37
+ return out;
38
+ } catch {
39
+ return [];
40
+ }
41
+ }
42
+ async function readFirefoxBookmarks(profileDir) {
43
+ const src = join(profileDir, "places.sqlite");
44
+ if (!existsSync(src)) return [];
45
+ const tmp = join(tmpdir(), `cartograph_ff_bm_${Date.now()}.sqlite`);
46
+ try {
47
+ copyFileSync(src, tmp);
48
+ const { default: Database } = await import("better-sqlite3");
49
+ const db = new Database(tmp, { readonly: true, fileMustExist: true });
50
+ const rows = db.prepare(`
51
+ SELECT DISTINCT p.url
52
+ FROM moz_places p
53
+ JOIN moz_bookmarks b ON b.fk = p.id
54
+ WHERE b.type = 1 AND p.url NOT LIKE 'place:%'
55
+ LIMIT 3000
56
+ `).all();
57
+ db.close();
58
+ return rows.map((r) => extractHost(r.url, "firefox")).filter((h) => h !== null);
59
+ } catch {
60
+ return [];
61
+ } finally {
62
+ try {
63
+ (await import("fs")).unlinkSync(tmp);
64
+ } catch {
65
+ }
66
+ }
67
+ }
68
+ async function readFirefoxHistory(profileDir) {
69
+ const src = join(profileDir, "places.sqlite");
70
+ if (!existsSync(src)) return [];
71
+ const tmp = join(tmpdir(), `cartograph_ff_hist_${Date.now()}.sqlite`);
72
+ try {
73
+ copyFileSync(src, tmp);
74
+ const { default: Database } = await import("better-sqlite3");
75
+ const db = new Database(tmp, { readonly: true, fileMustExist: true });
76
+ const rows = db.prepare(`
77
+ SELECT url, visit_count
78
+ FROM moz_places
79
+ WHERE url NOT LIKE 'place:%'
80
+ AND visit_count > 0
81
+ ORDER BY visit_count DESC
82
+ LIMIT 5000
83
+ `).all();
84
+ db.close();
85
+ return rows.map((r) => {
86
+ const h = extractHost(r.url, "firefox");
87
+ if (!h) return null;
88
+ return { ...h, visitCount: r.visit_count };
89
+ }).filter((h) => h !== null);
90
+ } catch {
91
+ return [];
92
+ } finally {
93
+ try {
94
+ (await import("fs")).unlinkSync(tmp);
95
+ } catch {
96
+ }
97
+ }
98
+ }
99
+ async function readChromiumHistory(historyPath, source) {
100
+ if (!existsSync(historyPath)) return [];
101
+ const tmp = join(tmpdir(), `cartograph_ch_hist_${Date.now()}.sqlite`);
102
+ try {
103
+ copyFileSync(historyPath, tmp);
104
+ const { default: Database } = await import("better-sqlite3");
105
+ const db = new Database(tmp, { readonly: true, fileMustExist: true });
106
+ const rows = db.prepare(`
107
+ SELECT url, visit_count
108
+ FROM urls
109
+ WHERE hidden = 0
110
+ AND visit_count > 0
111
+ ORDER BY visit_count DESC
112
+ LIMIT 5000
113
+ `).all();
114
+ db.close();
115
+ return rows.map((r) => {
116
+ const h = extractHost(r.url, source);
117
+ if (!h) return null;
118
+ return { ...h, visitCount: r.visit_count };
119
+ }).filter((h) => h !== null);
120
+ } catch {
121
+ return [];
122
+ } finally {
123
+ try {
124
+ (await import("fs")).unlinkSync(tmp);
125
+ } catch {
126
+ }
127
+ }
128
+ }
129
+ var HOME = homedir();
130
+ var IS_MAC = process.platform === "darwin";
131
+ function chromeLikePaths(base) {
132
+ const paths = [];
133
+ const defaultPath = join(base, "Default", "Bookmarks");
134
+ if (existsSync(defaultPath)) paths.push(defaultPath);
135
+ if (existsSync(base)) {
136
+ try {
137
+ for (const entry of readdirSync(base)) {
138
+ if (entry.startsWith("Profile ")) {
139
+ const p = join(base, entry, "Bookmarks");
140
+ if (existsSync(p)) paths.push(p);
141
+ }
142
+ }
143
+ } catch {
144
+ }
145
+ }
146
+ return paths;
147
+ }
148
+ function chromeLikeHistoryPaths(base) {
149
+ const paths = [];
150
+ const defaultPath = join(base, "Default", "History");
151
+ if (existsSync(defaultPath)) paths.push(defaultPath);
152
+ if (existsSync(base)) {
153
+ try {
154
+ for (const entry of readdirSync(base)) {
155
+ if (entry.startsWith("Profile ")) {
156
+ const p = join(base, entry, "History");
157
+ if (existsSync(p)) paths.push(p);
158
+ }
159
+ }
160
+ } catch {
161
+ }
162
+ }
163
+ return paths;
164
+ }
165
+ var CHROME_BASE = IS_MAC ? `${HOME}/Library/Application Support/Google/Chrome` : `${HOME}/.config/google-chrome`;
166
+ var CHROMIUM_BASE = IS_MAC ? `${HOME}/Library/Application Support/Chromium` : `${HOME}/.config/chromium`;
167
+ var CHROMIUM_SNAP_BASE = `${HOME}/snap/chromium/common/chromium`;
168
+ var CHROMIUM_FLATPAK_BASE = `${HOME}/.var/app/org.chromium.Chromium/config/chromium`;
169
+ var CHROME_FLATPAK_BASE = `${HOME}/.var/app/com.google.Chrome/config/google-chrome`;
170
+ var BRAVE_FLATPAK_BASE = `${HOME}/.var/app/com.brave.Browser/config/BraveSoftware/Brave-Browser`;
171
+ var EDGE_FLATPAK_BASE = `${HOME}/.var/app/com.microsoft.Edge/config/microsoft-edge`;
172
+ var FIREFOX_SNAP_BASE = `${HOME}/snap/firefox/common/.mozilla/firefox`;
173
+ var FIREFOX_FLATPAK_BASE = `${HOME}/.var/app/org.mozilla.firefox/.mozilla/firefox`;
174
+ var EDGE_BASE = IS_MAC ? `${HOME}/Library/Application Support/Microsoft Edge` : `${HOME}/.config/microsoft-edge`;
175
+ var BRAVE_BASE = IS_MAC ? `${HOME}/Library/Application Support/BraveSoftware/Brave-Browser` : `${HOME}/.config/BraveSoftware/Brave-Browser`;
176
+ var VIVALDI_BASE = IS_MAC ? `${HOME}/Library/Application Support/Vivaldi` : `${HOME}/.config/vivaldi`;
177
+ var OPERA_BASE = IS_MAC ? `${HOME}/Library/Application Support/com.operasoftware.Opera` : `${HOME}/.config/opera`;
178
+ function firefoxProfileDirs() {
179
+ const bases = IS_MAC ? [`${HOME}/Library/Application Support/Firefox/Profiles`] : [`${HOME}/.mozilla/firefox`, FIREFOX_SNAP_BASE, FIREFOX_FLATPAK_BASE];
180
+ const dirs = [];
181
+ for (const base of bases) {
182
+ if (!existsSync(base)) continue;
183
+ try {
184
+ for (const d of readdirSync(base)) {
185
+ const full = join(base, d);
186
+ try {
187
+ if (statSync(full).isDirectory() && existsSync(join(full, "places.sqlite"))) {
188
+ dirs.push(full);
189
+ }
190
+ } catch {
191
+ }
192
+ }
193
+ } catch {
194
+ }
195
+ }
196
+ return dirs;
197
+ }
198
+ async function scanAllBookmarks() {
199
+ const all = [];
200
+ for (const p of chromeLikePaths(CHROME_BASE)) all.push(...readChromeLike(p, "chrome"));
201
+ for (const p of chromeLikePaths(CHROMIUM_BASE)) all.push(...readChromeLike(p, "chromium"));
202
+ for (const p of chromeLikePaths(EDGE_BASE)) all.push(...readChromeLike(p, "edge"));
203
+ for (const p of chromeLikePaths(BRAVE_BASE)) all.push(...readChromeLike(p, "brave"));
204
+ for (const p of chromeLikePaths(VIVALDI_BASE)) all.push(...readChromeLike(p, "vivaldi"));
205
+ for (const p of chromeLikePaths(OPERA_BASE)) all.push(...readChromeLike(p, "opera"));
206
+ if (!IS_MAC) {
207
+ for (const p of chromeLikePaths(CHROMIUM_SNAP_BASE)) all.push(...readChromeLike(p, "chromium-snap"));
208
+ for (const p of chromeLikePaths(CHROMIUM_FLATPAK_BASE)) all.push(...readChromeLike(p, "chromium-flatpak"));
209
+ for (const p of chromeLikePaths(CHROME_FLATPAK_BASE)) all.push(...readChromeLike(p, "chrome-flatpak"));
210
+ for (const p of chromeLikePaths(BRAVE_FLATPAK_BASE)) all.push(...readChromeLike(p, "brave-flatpak"));
211
+ for (const p of chromeLikePaths(EDGE_FLATPAK_BASE)) all.push(...readChromeLike(p, "edge-flatpak"));
212
+ }
213
+ for (const dir of firefoxProfileDirs()) {
214
+ all.push(...await readFirefoxBookmarks(dir));
215
+ }
216
+ const seen = /* @__PURE__ */ new Set();
217
+ return all.filter((h) => {
218
+ if (seen.has(h.hostname)) return false;
219
+ seen.add(h.hostname);
220
+ return true;
221
+ });
222
+ }
223
+ async function scanAllHistory() {
224
+ const all = [];
225
+ for (const p of chromeLikeHistoryPaths(CHROME_BASE)) all.push(...await readChromiumHistory(p, "chrome"));
226
+ for (const p of chromeLikeHistoryPaths(CHROMIUM_BASE)) all.push(...await readChromiumHistory(p, "chromium"));
227
+ for (const p of chromeLikeHistoryPaths(EDGE_BASE)) all.push(...await readChromiumHistory(p, "edge"));
228
+ for (const p of chromeLikeHistoryPaths(BRAVE_BASE)) all.push(...await readChromiumHistory(p, "brave"));
229
+ for (const p of chromeLikeHistoryPaths(VIVALDI_BASE)) all.push(...await readChromiumHistory(p, "vivaldi"));
230
+ for (const p of chromeLikeHistoryPaths(OPERA_BASE)) all.push(...await readChromiumHistory(p, "opera"));
231
+ if (!IS_MAC) {
232
+ for (const p of chromeLikeHistoryPaths(CHROMIUM_SNAP_BASE)) all.push(...await readChromiumHistory(p, "chromium-snap"));
233
+ for (const p of chromeLikeHistoryPaths(CHROMIUM_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "chromium-flatpak"));
234
+ for (const p of chromeLikeHistoryPaths(CHROME_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "chrome-flatpak"));
235
+ for (const p of chromeLikeHistoryPaths(BRAVE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "brave-flatpak"));
236
+ for (const p of chromeLikeHistoryPaths(EDGE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "edge-flatpak"));
237
+ }
238
+ for (const dir of firefoxProfileDirs()) {
239
+ all.push(...await readFirefoxHistory(dir));
240
+ }
241
+ const byHost = /* @__PURE__ */ new Map();
242
+ for (const h of all) {
243
+ const existing = byHost.get(h.hostname);
244
+ if (existing) {
245
+ existing.visitCount += h.visitCount;
246
+ } else {
247
+ byHost.set(h.hostname, { ...h });
248
+ }
249
+ }
250
+ return [...byHost.values()].sort((a, b) => b.visitCount - a.visitCount);
251
+ }
252
+
253
+ export {
254
+ readFirefoxHistory,
255
+ scanAllBookmarks,
256
+ scanAllHistory
257
+ };
258
+ //# sourceMappingURL=chunk-2VIAXA5T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bookmarks.ts"],"sourcesContent":["import { homedir, tmpdir } from 'node:os';\nimport { existsSync, readFileSync, readdirSync, copyFileSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface BookmarkHost {\n hostname: string;\n port: number;\n protocol: 'http' | 'https';\n source: string;\n}\n\nexport interface HistoryHost extends BookmarkHost {\n visitCount: number;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction extractHost(rawUrl: string, source: string): BookmarkHost | null {\n try {\n const u = new URL(rawUrl);\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null;\n const protocol = u.protocol === 'https:' ? 'https' as const : 'http' as const;\n // Strip: no paths, no params, no credentials — hostname only\n const port = u.port ? parseInt(u.port, 10) : (protocol === 'https' ? 443 : 80);\n const hostname = u.hostname.toLowerCase();\n if (!hostname || hostname === 'localhost' || hostname === '127.0.0.1') return null;\n return { hostname, port, protocol, source };\n } catch {\n return null;\n }\n}\n\n// Chrome/Edge/Brave JSON format\ninterface ChromeNode {\n type?: string;\n url?: string;\n children?: ChromeNode[];\n}\n\nfunction walkChrome(node: ChromeNode, source: string, out: BookmarkHost[]): void {\n if (node.type === 'url' && node.url) {\n const h = extractHost(node.url, source);\n if (h) out.push(h);\n }\n if (node.children) {\n for (const child of node.children) walkChrome(child, source, out);\n }\n}\n\nfunction readChromeLike(filePath: string, source: string): BookmarkHost[] {\n if (!existsSync(filePath)) return [];\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf8')) as {\n roots: Record<string, ChromeNode>;\n };\n const out: BookmarkHost[] = [];\n for (const root of Object.values(raw.roots)) {\n if (root) walkChrome(root, source, out);\n }\n return out;\n } catch {\n return [];\n }\n}\n\nasync function readFirefoxBookmarks(profileDir: string): Promise<BookmarkHost[]> {\n const src = join(profileDir, 'places.sqlite');\n if (!existsSync(src)) return [];\n const tmp = join(tmpdir(), `cartograph_ff_bm_${Date.now()}.sqlite`);\n try {\n copyFileSync(src, tmp);\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(tmp, { readonly: true, fileMustExist: true });\n const rows = db.prepare(`\n SELECT DISTINCT p.url\n FROM moz_places p\n JOIN moz_bookmarks b ON b.fk = p.id\n WHERE b.type = 1 AND p.url NOT LIKE 'place:%'\n LIMIT 3000\n `).all() as { url: string }[];\n db.close();\n return rows.map(r => extractHost(r.url, 'firefox')).filter((h): h is BookmarkHost => h !== null);\n } catch {\n return [];\n } finally {\n try { (await import('node:fs')).unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n\nexport async function readFirefoxHistory(profileDir: string): Promise<HistoryHost[]> {\n const src = join(profileDir, 'places.sqlite');\n if (!existsSync(src)) return [];\n const tmp = join(tmpdir(), `cartograph_ff_hist_${Date.now()}.sqlite`);\n try {\n copyFileSync(src, tmp);\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(tmp, { readonly: true, fileMustExist: true });\n const rows = db.prepare(`\n SELECT url, visit_count\n FROM moz_places\n WHERE url NOT LIKE 'place:%'\n AND visit_count > 0\n ORDER BY visit_count DESC\n LIMIT 5000\n `).all() as { url: string; visit_count: number }[];\n db.close();\n return rows\n .map(r => {\n const h = extractHost(r.url, 'firefox');\n if (!h) return null;\n return { ...h, visitCount: r.visit_count };\n })\n .filter((h): h is HistoryHost => h !== null);\n } catch {\n return [];\n } finally {\n try { (await import('node:fs')).unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n\nasync function readChromiumHistory(historyPath: string, source: string): Promise<HistoryHost[]> {\n if (!existsSync(historyPath)) return [];\n const tmp = join(tmpdir(), `cartograph_ch_hist_${Date.now()}.sqlite`);\n try {\n copyFileSync(historyPath, tmp);\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(tmp, { readonly: true, fileMustExist: true });\n const rows = db.prepare(`\n SELECT url, visit_count\n FROM urls\n WHERE hidden = 0\n AND visit_count > 0\n ORDER BY visit_count DESC\n LIMIT 5000\n `).all() as { url: string; visit_count: number }[];\n db.close();\n return rows\n .map(r => {\n const h = extractHost(r.url, source);\n if (!h) return null;\n return { ...h, visitCount: r.visit_count };\n })\n .filter((h): h is HistoryHost => h !== null);\n } catch {\n return [];\n } finally {\n try { (await import('node:fs')).unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n\n// ── Platform paths ────────────────────────────────────────────────────────────\n\nconst HOME = homedir();\nconst IS_MAC = process.platform === 'darwin';\n\n// Browser bookmark file paths (multiple profiles supported)\nfunction chromeLikePaths(base: string): string[] {\n const paths: string[] = [];\n const defaultPath = join(base, 'Default', 'Bookmarks');\n if (existsSync(defaultPath)) paths.push(defaultPath);\n // Also check Profile 1, Profile 2, etc.\n if (existsSync(base)) {\n try {\n for (const entry of readdirSync(base)) {\n if (entry.startsWith('Profile ')) {\n const p = join(base, entry, 'Bookmarks');\n if (existsSync(p)) paths.push(p);\n }\n }\n } catch { /* ignore */ }\n }\n return paths;\n}\n\nfunction chromeLikeHistoryPaths(base: string): string[] {\n const paths: string[] = [];\n const defaultPath = join(base, 'Default', 'History');\n if (existsSync(defaultPath)) paths.push(defaultPath);\n if (existsSync(base)) {\n try {\n for (const entry of readdirSync(base)) {\n if (entry.startsWith('Profile ')) {\n const p = join(base, entry, 'History');\n if (existsSync(p)) paths.push(p);\n }\n }\n } catch { /* ignore */ }\n }\n return paths;\n}\n\nconst CHROME_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/Google/Chrome`\n : `${HOME}/.config/google-chrome`;\n\nconst CHROMIUM_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/Chromium`\n : `${HOME}/.config/chromium`;\n\n// Snap / Flatpak variants (Linux only)\nconst CHROMIUM_SNAP_BASE = `${HOME}/snap/chromium/common/chromium`;\nconst CHROMIUM_FLATPAK_BASE = `${HOME}/.var/app/org.chromium.Chromium/config/chromium`;\nconst CHROME_FLATPAK_BASE = `${HOME}/.var/app/com.google.Chrome/config/google-chrome`;\nconst BRAVE_FLATPAK_BASE = `${HOME}/.var/app/com.brave.Browser/config/BraveSoftware/Brave-Browser`;\nconst EDGE_FLATPAK_BASE = `${HOME}/.var/app/com.microsoft.Edge/config/microsoft-edge`;\nconst FIREFOX_SNAP_BASE = `${HOME}/snap/firefox/common/.mozilla/firefox`;\nconst FIREFOX_FLATPAK_BASE = `${HOME}/.var/app/org.mozilla.firefox/.mozilla/firefox`;\n\nconst EDGE_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/Microsoft Edge`\n : `${HOME}/.config/microsoft-edge`;\n\nconst BRAVE_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/BraveSoftware/Brave-Browser`\n : `${HOME}/.config/BraveSoftware/Brave-Browser`;\n\nconst VIVALDI_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/Vivaldi`\n : `${HOME}/.config/vivaldi`;\n\nconst OPERA_BASE = IS_MAC\n ? `${HOME}/Library/Application Support/com.operasoftware.Opera`\n : `${HOME}/.config/opera`;\n\nfunction firefoxProfileDirs(): string[] {\n const bases = IS_MAC\n ? [`${HOME}/Library/Application Support/Firefox/Profiles`]\n : [`${HOME}/.mozilla/firefox`, FIREFOX_SNAP_BASE, FIREFOX_FLATPAK_BASE];\n\n const dirs: string[] = [];\n for (const base of bases) {\n if (!existsSync(base)) continue;\n try {\n for (const d of readdirSync(base)) {\n const full = join(base, d);\n try {\n if (statSync(full).isDirectory() && existsSync(join(full, 'places.sqlite'))) {\n dirs.push(full);\n }\n } catch { /* ignore */ }\n }\n } catch { /* ignore */ }\n }\n return dirs;\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport async function scanAllBookmarks(): Promise<BookmarkHost[]> {\n const all: BookmarkHost[] = [];\n\n // Standard browser paths\n for (const p of chromeLikePaths(CHROME_BASE)) all.push(...readChromeLike(p, 'chrome'));\n for (const p of chromeLikePaths(CHROMIUM_BASE)) all.push(...readChromeLike(p, 'chromium'));\n for (const p of chromeLikePaths(EDGE_BASE)) all.push(...readChromeLike(p, 'edge'));\n for (const p of chromeLikePaths(BRAVE_BASE)) all.push(...readChromeLike(p, 'brave'));\n for (const p of chromeLikePaths(VIVALDI_BASE)) all.push(...readChromeLike(p, 'vivaldi'));\n for (const p of chromeLikePaths(OPERA_BASE)) all.push(...readChromeLike(p, 'opera'));\n\n // Snap / Flatpak paths (Linux)\n if (!IS_MAC) {\n for (const p of chromeLikePaths(CHROMIUM_SNAP_BASE)) all.push(...readChromeLike(p, 'chromium-snap'));\n for (const p of chromeLikePaths(CHROMIUM_FLATPAK_BASE)) all.push(...readChromeLike(p, 'chromium-flatpak'));\n for (const p of chromeLikePaths(CHROME_FLATPAK_BASE)) all.push(...readChromeLike(p, 'chrome-flatpak'));\n for (const p of chromeLikePaths(BRAVE_FLATPAK_BASE)) all.push(...readChromeLike(p, 'brave-flatpak'));\n for (const p of chromeLikePaths(EDGE_FLATPAK_BASE)) all.push(...readChromeLike(p, 'edge-flatpak'));\n }\n\n // Firefox: standard + snap + flatpak\n for (const dir of firefoxProfileDirs()) {\n all.push(...await readFirefoxBookmarks(dir));\n }\n\n // Deduplicate by hostname\n const seen = new Set<string>();\n return all.filter(h => {\n if (seen.has(h.hostname)) return false;\n seen.add(h.hostname);\n return true;\n });\n}\n\nexport async function scanAllHistory(): Promise<HistoryHost[]> {\n const all: HistoryHost[] = [];\n\n // Standard browser paths\n for (const p of chromeLikeHistoryPaths(CHROME_BASE)) all.push(...await readChromiumHistory(p, 'chrome'));\n for (const p of chromeLikeHistoryPaths(CHROMIUM_BASE)) all.push(...await readChromiumHistory(p, 'chromium'));\n for (const p of chromeLikeHistoryPaths(EDGE_BASE)) all.push(...await readChromiumHistory(p, 'edge'));\n for (const p of chromeLikeHistoryPaths(BRAVE_BASE)) all.push(...await readChromiumHistory(p, 'brave'));\n for (const p of chromeLikeHistoryPaths(VIVALDI_BASE)) all.push(...await readChromiumHistory(p, 'vivaldi'));\n for (const p of chromeLikeHistoryPaths(OPERA_BASE)) all.push(...await readChromiumHistory(p, 'opera'));\n\n // Snap / Flatpak paths (Linux)\n if (!IS_MAC) {\n for (const p of chromeLikeHistoryPaths(CHROMIUM_SNAP_BASE)) all.push(...await readChromiumHistory(p, 'chromium-snap'));\n for (const p of chromeLikeHistoryPaths(CHROMIUM_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, 'chromium-flatpak'));\n for (const p of chromeLikeHistoryPaths(CHROME_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, 'chrome-flatpak'));\n for (const p of chromeLikeHistoryPaths(BRAVE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, 'brave-flatpak'));\n for (const p of chromeLikeHistoryPaths(EDGE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, 'edge-flatpak'));\n }\n\n // Firefox: standard + snap + flatpak\n for (const dir of firefoxProfileDirs()) {\n all.push(...await readFirefoxHistory(dir));\n }\n\n // Deduplicate by hostname, summing visit counts\n const byHost = new Map<string, HistoryHost>();\n for (const h of all) {\n const existing = byHost.get(h.hostname);\n if (existing) {\n existing.visitCount += h.visitCount;\n } else {\n byHost.set(h.hostname, { ...h });\n }\n }\n\n // Sort by visit count descending\n return [...byHost.values()].sort((a, b) => b.visitCount - a.visitCount);\n}\n"],"mappings":"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","names":[]}