@datasynx/agentic-ai-cartography 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # 🗺️ Datasynx Cartography
4
4
 
5
- **AI-powered Infrastructure Cartography & SOP Generation**
5
+ **AI-powered Infrastructure Discovery & Agentic AI Cartography**
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@datasynx/agentic-ai-cartography?style=flat-square&color=CB3837&logo=npm&logoColor=white)](https://www.npmjs.com/package/@datasynx/agentic-ai-cartography)
8
8
  [![npm downloads](https://img.shields.io/npm/dm/@datasynx/agentic-ai-cartography?style=flat-square&color=CB3837&logo=npm&logoColor=white)](https://www.npmjs.com/package/@datasynx/agentic-ai-cartography)
@@ -3,10 +3,10 @@ import {
3
3
  readFirefoxHistory,
4
4
  scanAllBookmarks,
5
5
  scanAllHistory
6
- } from "./chunk-PVFDCPPW.js";
6
+ } from "./chunk-3NVQ3ND6.js";
7
7
  export {
8
8
  readFirefoxHistory,
9
9
  scanAllBookmarks,
10
10
  scanAllHistory
11
11
  };
12
- //# sourceMappingURL=bookmarks-KKS4M37J.js.map
12
+ //# sourceMappingURL=bookmarks-72CDYAHD.js.map
@@ -147,13 +147,6 @@ function scanWindowsDbServices() {
147
147
  { timeout: 1e4 }
148
148
  );
149
149
  }
150
- function fileUrl(absPath) {
151
- if (IS_WIN) {
152
- const normalized = absPath.replace(/\\/g, "/");
153
- return `file:///${normalized}`;
154
- }
155
- return `file://${absPath}`;
156
- }
157
150
 
158
151
  // src/bookmarks.ts
159
152
  function extractHost(rawUrl, source) {
@@ -412,9 +405,8 @@ export {
412
405
  findFiles,
413
406
  scanWindowsPrograms,
414
407
  scanWindowsDbServices,
415
- fileUrl,
416
408
  readFirefoxHistory,
417
409
  scanAllBookmarks,
418
410
  scanAllHistory
419
411
  };
420
- //# sourceMappingURL=chunk-PVFDCPPW.js.map
412
+ //# sourceMappingURL=chunk-3NVQ3ND6.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bookmarks.ts","../src/platform.ts"],"sourcesContent":["import { tmpdir } from 'node:os';\nimport { existsSync, readFileSync, readdirSync, copyFileSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { HOME, IS_WIN, IS_MAC, browserBasePaths, firefoxBaseDirs } from './platform.js';\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// Uses centralized platform.ts for Linux/macOS/Windows browser base paths.\n\nconst IS_LINUX = !IS_MAC && !IS_WIN;\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\n// Get browser bases from centralized platform module\nconst BROWSER_BASES = browserBasePaths();\n\nconst CHROME_BASE = BROWSER_BASES.chrome;\nconst CHROMIUM_BASE = BROWSER_BASES.chromium;\nconst EDGE_BASE = BROWSER_BASES.edge;\nconst BRAVE_BASE = BROWSER_BASES.brave;\nconst VIVALDI_BASE = BROWSER_BASES.vivaldi;\nconst OPERA_BASE = BROWSER_BASES.opera;\n\n// Snap / Flatpak variants (Linux only)\nconst CHROMIUM_SNAP_BASE = join(HOME, 'snap', 'chromium', 'common', 'chromium');\nconst CHROMIUM_FLATPAK_BASE = join(HOME, '.var', 'app', 'org.chromium.Chromium', 'config', 'chromium');\nconst CHROME_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.google.Chrome', 'config', 'google-chrome');\nconst BRAVE_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.brave.Browser', 'config', 'BraveSoftware', 'Brave-Browser');\nconst EDGE_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.microsoft.Edge', 'config', 'microsoft-edge');\n\nfunction firefoxProfileDirs(): string[] {\n const bases = firefoxBaseDirs();\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 only — not macOS, not Windows)\n if (IS_LINUX) {\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 only — not macOS, not Windows)\n if (IS_LINUX) {\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","/**\n * Cross-platform utilities for Linux, macOS, and Windows.\n * Centralizes all OS-specific logic so scanning tools work everywhere.\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\n\n// ── Platform detection ───────────────────────────────────────────────────────\n\nexport type Platform = 'linux' | 'darwin' | 'win32';\n\nexport const PLATFORM: Platform = process.platform as Platform;\nexport const IS_WIN = PLATFORM === 'win32';\nexport const IS_MAC = PLATFORM === 'darwin';\nexport const IS_LINUX = PLATFORM === 'linux';\nexport const HOME = homedir();\n\n// ── Shell selection ──────────────────────────────────────────────────────────\n\n/**\n * Returns the correct shell for execSync on each platform.\n * - Windows: PowerShell (pwsh if available, otherwise powershell.exe)\n * - macOS/Linux: /bin/sh\n */\nexport function platformShell(): string {\n if (!IS_WIN) return '/bin/sh';\n // Prefer pwsh (PowerShell 7+) over powershell.exe (5.1)\n try {\n execSync('pwsh -Version', { stdio: 'pipe', timeout: 3000 });\n return 'pwsh';\n } catch {\n return 'powershell.exe';\n }\n}\n\n/** Cached shell value (computed once) */\nlet _shell: string | undefined;\nexport function getShell(): string {\n if (!_shell) _shell = platformShell();\n return _shell;\n}\n\n// ── Cross-platform command runner ────────────────────────────────────────────\n\nexport interface RunOptions {\n timeout?: number;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Run a shell command, returning stdout as string. Returns '' on error.\n * Automatically uses the correct shell for the platform.\n */\nexport function run(cmd: string, opts: RunOptions = {}): string {\n try {\n return execSync(cmd, {\n stdio: 'pipe',\n timeout: opts.timeout ?? 10_000,\n shell: getShell(),\n env: opts.env,\n }).toString().trim();\n } catch {\n return '';\n }\n}\n\n// ── Command existence check (cross-platform `which`) ─────────────────────────\n\n/**\n * Check if a command exists. Returns its path or '' if not found.\n * - Unix: `which <cmd>`\n * - Windows: `Get-Command <cmd>` via PowerShell\n */\nexport function commandExists(cmd: string): string {\n if (IS_WIN) {\n const r = run(`Get-Command ${cmd} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source`, { timeout: 5000 });\n return r;\n }\n return run(`which ${cmd} 2>/dev/null`);\n}\n\n// ── Null device ──────────────────────────────────────────────────────────────\n\nexport const NULL_DEV = IS_WIN ? 'NUL' : '/dev/null';\n\n// ── App data directories ─────────────────────────────────────────────────────\n\n/** Returns the platform-specific user app data directory */\nexport function appDataDir(): string {\n if (IS_WIN) return process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n if (IS_MAC) return join(HOME, 'Library', 'Application Support');\n return process.env.XDG_CONFIG_HOME ?? join(HOME, '.config');\n}\n\n/** Returns the platform-specific user data directory (broader than config) */\nexport function userDataDir(): string {\n if (IS_WIN) return process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n if (IS_MAC) return join(HOME, 'Library', 'Application Support');\n return process.env.XDG_DATA_HOME ?? join(HOME, '.local', 'share');\n}\n\n// ── Browser profile base paths (Chromium-based) ──────────────────────────────\n\nexport interface BrowserPaths {\n chrome: string;\n chromium: string;\n edge: string;\n brave: string;\n vivaldi: string;\n opera: string;\n}\n\nexport function browserBasePaths(): BrowserPaths {\n if (IS_WIN) {\n const local = process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n return {\n chrome: join(local, 'Google', 'Chrome', 'User Data'),\n chromium: join(local, 'Chromium', 'User Data'),\n edge: join(local, 'Microsoft', 'Edge', 'User Data'),\n brave: join(local, 'BraveSoftware', 'Brave-Browser', 'User Data'),\n vivaldi: join(local, 'Vivaldi', 'User Data'),\n opera: join(userDataDir(), 'Opera Software', 'Opera Stable'),\n };\n }\n if (IS_MAC) {\n const lib = join(HOME, 'Library', 'Application Support');\n return {\n chrome: join(lib, 'Google', 'Chrome'),\n chromium: join(lib, 'Chromium'),\n edge: join(lib, 'Microsoft Edge'),\n brave: join(lib, 'BraveSoftware', 'Brave-Browser'),\n vivaldi: join(lib, 'Vivaldi'),\n opera: join(lib, 'com.operasoftware.Opera'),\n };\n }\n // Linux\n return {\n chrome: join(HOME, '.config', 'google-chrome'),\n chromium: join(HOME, '.config', 'chromium'),\n edge: join(HOME, '.config', 'microsoft-edge'),\n brave: join(HOME, '.config', 'BraveSoftware', 'Brave-Browser'),\n vivaldi: join(HOME, '.config', 'vivaldi'),\n opera: join(HOME, '.config', 'opera'),\n };\n}\n\n/** Firefox profile parent directories per platform */\nexport function firefoxBaseDirs(): string[] {\n if (IS_WIN) {\n const roaming = process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n return [join(roaming, 'Mozilla', 'Firefox', 'Profiles')];\n }\n if (IS_MAC) {\n return [join(HOME, 'Library', 'Application Support', 'Firefox', 'Profiles')];\n }\n // Linux: standard + snap + flatpak\n return [\n join(HOME, '.mozilla', 'firefox'),\n join(HOME, 'snap', 'firefox', 'common', '.mozilla', 'firefox'),\n join(HOME, '.var', 'app', 'org.mozilla.firefox', '.mozilla', 'firefox'),\n ];\n}\n\n// ── Database scan directories ────────────────────────────────────────────────\n\n/** Returns directories to search for SQLite/DB files per platform */\nexport function dbScanDirs(): string[] {\n const dirs: string[] = [];\n if (IS_WIN) {\n const local = process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n const roaming = process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n dirs.push(local, roaming);\n const pd = join(HOME, 'AppData', 'Local', 'Programs');\n if (existsSync(pd)) dirs.push(pd);\n } else if (IS_MAC) {\n dirs.push(join(HOME, 'Library', 'Application Support'));\n if (existsSync('/var/lib')) dirs.push('/var/lib');\n } else {\n const configDir = join(HOME, '.config');\n const dataDir = join(HOME, '.local', 'share');\n if (existsSync(configDir)) dirs.push(configDir);\n if (existsSync(dataDir)) dirs.push(dataDir);\n if (existsSync('/var/lib')) dirs.push('/var/lib');\n }\n return dirs.filter(d => existsSync(d));\n}\n\n// ── File search (cross-platform find) ────────────────────────────────────────\n\n/**\n * Search for files matching glob patterns in given directories.\n * - Unix: `find` command\n * - Windows: PowerShell `Get-ChildItem`\n */\nexport function findFiles(dirs: string[], patterns: string[], maxDepth: number, limit: number): string {\n if (dirs.length === 0) return '';\n if (IS_WIN) {\n const includes = patterns.map(p => `'${p}'`).join(',');\n const pathList = dirs.map(d => `'${d}'`).join(',');\n return run(\n `Get-ChildItem -Path ${pathList} -Recurse -Depth ${maxDepth} -Include ${includes} -ErrorAction SilentlyContinue | Select-Object -First ${limit} -ExpandProperty FullName`,\n { timeout: 15_000 },\n );\n }\n const nameArgs = patterns.map(p => `-name \"${p}\"`).join(' -o ');\n const findCmds = dirs.map(d => `find \"${d}\" -maxdepth ${maxDepth} \\\\( ${nameArgs} \\\\) 2>/dev/null`).join('; ');\n return run(`{ ${findCmds}; } | head -${limit}`, { timeout: 15_000 });\n}\n\n// ── Network scanning ─────────────────────────────────────────────────────────\n\n/** Get all listening TCP ports and the processes behind them */\nexport function scanListeningPorts(): string {\n if (IS_WIN) {\n // PowerShell: Get-NetTCPConnection for listening ports + owning process\n return run(\n `Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | ` +\n `ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; ` +\n `\"$($_.LocalAddress):$($_.LocalPort) PID=$($_.OwningProcess) $($p.ProcessName)\" } | ` +\n `Sort-Object -Unique`,\n { timeout: 15_000 },\n );\n }\n if (IS_MAC) {\n // macOS: lsof is the most reliable way (ss not available)\n return run('sudo lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null || lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null', { timeout: 15_000 });\n }\n // Linux: ss is the standard tool\n return run('ss -tlnp 2>/dev/null', { timeout: 10_000 });\n}\n\n/** Get running processes (cross-platform) */\nexport function scanProcesses(): string {\n if (IS_WIN) {\n return run(\n `Get-Process | Select-Object -Property Id, ProcessName, Path | Format-Table -AutoSize | Out-String -Width 200`,\n { timeout: 15_000 },\n );\n }\n return run('ps aux 2>/dev/null', { timeout: 10_000 });\n}\n\n// ── Windows-specific: installed programs ─────────────────────────────────────\n\n/** Scan Windows registry for installed programs */\nexport function scanWindowsPrograms(): string {\n if (!IS_WIN) return '';\n return run(\n `$paths = @(` +\n `'HKLM:\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*',` +\n `'HKLM:\\\\Software\\\\Wow6432Node\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*',` +\n `'HKCU:\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*'` +\n `); Get-ItemProperty $paths -ErrorAction SilentlyContinue | ` +\n `Where-Object { $_.DisplayName } | ` +\n `Select-Object -Property DisplayName, Publisher, DisplayVersion | ` +\n `Sort-Object DisplayName | ` +\n `Format-Table -AutoSize | Out-String -Width 300`,\n { timeout: 20_000 },\n );\n}\n\n/** Scan Windows services for database engines */\nexport function scanWindowsDbServices(): string {\n if (!IS_WIN) return '';\n return run(\n `Get-Service | Where-Object { ` +\n `$_.Name -match 'postgres|mysql|mariadb|mongo|redis|MSSQL|elastic|clickhouse|cassandra' ` +\n `} | Select-Object Name, DisplayName, Status, StartType | Format-Table -AutoSize`,\n { timeout: 10_000 },\n );\n}\n\n// ── file:// URL helper ───────────────────────────────────────────────────────\n\n/** Generate a correct file:// URL for the current platform */\nexport function fileUrl(absPath: string): string {\n if (IS_WIN) {\n // Windows: file:///C:/Users/... (forward slashes, triple slash)\n const normalized = absPath.replace(/\\\\/g, '/');\n return `file:///${normalized}`;\n }\n return `file://${absPath}`;\n}\n"],"mappings":";;;AAAA,SAAS,cAAc;AACvB,SAAS,cAAAA,aAAY,cAAc,aAAa,cAAc,gBAAgB;AAC9E,SAAS,QAAAC,aAAY;;;ACGrB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAMpB,IAAM,WAAqB,QAAQ;AACnC,IAAM,SAAS,aAAa;AAC5B,IAAM,SAAS,aAAa;AAC5B,IAAM,WAAW,aAAa;AAC9B,IAAM,OAAO,QAAQ;AASrB,SAAS,gBAAwB;AACtC,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI;AACF,aAAS,iBAAiB,EAAE,OAAO,QAAQ,SAAS,IAAK,CAAC;AAC1D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,IAAI;AACG,SAAS,WAAmB;AACjC,MAAI,CAAC,OAAQ,UAAS,cAAc;AACpC,SAAO;AACT;AAaO,SAAS,IAAI,KAAa,OAAmB,CAAC,GAAW;AAC9D,MAAI;AACF,WAAO,SAAS,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,SAAS,KAAK,WAAW;AAAA,MACzB,OAAO,SAAS;AAAA,MAChB,KAAK,KAAK;AAAA,IACZ,CAAC,EAAE,SAAS,EAAE,KAAK;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,SAAS,cAAc,KAAqB;AACjD,MAAI,QAAQ;AACV,UAAM,IAAI,IAAI,eAAe,GAAG,yEAAyE,EAAE,SAAS,IAAK,CAAC;AAC1H,WAAO;AAAA,EACT;AACA,SAAO,IAAI,SAAS,GAAG,cAAc;AACvC;AAgBO,SAAS,cAAsB;AACpC,MAAI,OAAQ,QAAO,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AACzE,MAAI,OAAQ,QAAO,KAAK,MAAM,WAAW,qBAAqB;AAC9D,SAAO,QAAQ,IAAI,iBAAiB,KAAK,MAAM,UAAU,OAAO;AAClE;AAaO,SAAS,mBAAiC;AAC/C,MAAI,QAAQ;AACV,UAAM,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,MAAM,WAAW,OAAO;AACvE,WAAO;AAAA,MACL,QAAU,KAAK,OAAO,UAAU,UAAU,WAAW;AAAA,MACrD,UAAU,KAAK,OAAO,YAAY,WAAW;AAAA,MAC7C,MAAU,KAAK,OAAO,aAAa,QAAQ,WAAW;AAAA,MACtD,OAAU,KAAK,OAAO,iBAAiB,iBAAiB,WAAW;AAAA,MACnE,SAAU,KAAK,OAAO,WAAW,WAAW;AAAA,MAC5C,OAAU,KAAK,YAAY,GAAG,kBAAkB,cAAc;AAAA,IAChE;AAAA,EACF;AACA,MAAI,QAAQ;AACV,UAAM,MAAM,KAAK,MAAM,WAAW,qBAAqB;AACvD,WAAO;AAAA,MACL,QAAU,KAAK,KAAK,UAAU,QAAQ;AAAA,MACtC,UAAU,KAAK,KAAK,UAAU;AAAA,MAC9B,MAAU,KAAK,KAAK,gBAAgB;AAAA,MACpC,OAAU,KAAK,KAAK,iBAAiB,eAAe;AAAA,MACpD,SAAU,KAAK,KAAK,SAAS;AAAA,MAC7B,OAAU,KAAK,KAAK,yBAAyB;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAU,KAAK,MAAM,WAAW,eAAe;AAAA,IAC/C,UAAU,KAAK,MAAM,WAAW,UAAU;AAAA,IAC1C,MAAU,KAAK,MAAM,WAAW,gBAAgB;AAAA,IAChD,OAAU,KAAK,MAAM,WAAW,iBAAiB,eAAe;AAAA,IAChE,SAAU,KAAK,MAAM,WAAW,SAAS;AAAA,IACzC,OAAU,KAAK,MAAM,WAAW,OAAO;AAAA,EACzC;AACF;AAGO,SAAS,kBAA4B;AAC1C,MAAI,QAAQ;AACV,UAAM,UAAU,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AACtE,WAAO,CAAC,KAAK,SAAS,WAAW,WAAW,UAAU,CAAC;AAAA,EACzD;AACA,MAAI,QAAQ;AACV,WAAO,CAAC,KAAK,MAAM,WAAW,uBAAuB,WAAW,UAAU,CAAC;AAAA,EAC7E;AAEA,SAAO;AAAA,IACL,KAAK,MAAM,YAAY,SAAS;AAAA,IAChC,KAAK,MAAM,QAAQ,WAAW,UAAU,YAAY,SAAS;AAAA,IAC7D,KAAK,MAAM,QAAQ,OAAO,uBAAuB,YAAY,SAAS;AAAA,EACxE;AACF;AAKO,SAAS,aAAuB;AACrC,QAAM,OAAiB,CAAC;AACxB,MAAI,QAAQ;AACV,UAAM,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,MAAM,WAAW,OAAO;AACvE,UAAM,UAAU,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AACtE,SAAK,KAAK,OAAO,OAAO;AACxB,UAAM,KAAK,KAAK,MAAM,WAAW,SAAS,UAAU;AACpD,QAAI,WAAW,EAAE,EAAG,MAAK,KAAK,EAAE;AAAA,EAClC,WAAW,QAAQ;AACjB,SAAK,KAAK,KAAK,MAAM,WAAW,qBAAqB,CAAC;AACtD,QAAI,WAAW,UAAU,EAAG,MAAK,KAAK,UAAU;AAAA,EAClD,OAAO;AACL,UAAM,YAAY,KAAK,MAAM,SAAS;AACtC,UAAM,UAAU,KAAK,MAAM,UAAU,OAAO;AAC5C,QAAI,WAAW,SAAS,EAAG,MAAK,KAAK,SAAS;AAC9C,QAAI,WAAW,OAAO,EAAG,MAAK,KAAK,OAAO;AAC1C,QAAI,WAAW,UAAU,EAAG,MAAK,KAAK,UAAU;AAAA,EAClD;AACA,SAAO,KAAK,OAAO,OAAK,WAAW,CAAC,CAAC;AACvC;AASO,SAAS,UAAU,MAAgB,UAAoB,UAAkB,OAAuB;AACrG,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI,QAAQ;AACV,UAAM,WAAW,SAAS,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG;AACrD,UAAM,WAAW,KAAK,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG;AACjD,WAAO;AAAA,MACL,uBAAuB,QAAQ,oBAAoB,QAAQ,aAAa,QAAQ,yDAAyD,KAAK;AAAA,MAC9I,EAAE,SAAS,KAAO;AAAA,IACpB;AAAA,EACF;AACA,QAAM,WAAW,SAAS,IAAI,OAAK,UAAU,CAAC,GAAG,EAAE,KAAK,MAAM;AAC9D,QAAM,WAAW,KAAK,IAAI,OAAK,SAAS,CAAC,eAAe,QAAQ,QAAQ,QAAQ,kBAAkB,EAAE,KAAK,IAAI;AAC7G,SAAO,IAAI,KAAK,QAAQ,eAAe,KAAK,IAAI,EAAE,SAAS,KAAO,CAAC;AACrE;AAsCO,SAAS,sBAA8B;AAC5C,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO;AAAA,IACL;AAAA,IASA,EAAE,SAAS,IAAO;AAAA,EACpB;AACF;AAGO,SAAS,wBAAgC;AAC9C,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO;AAAA,IACL;AAAA,IAGA,EAAE,SAAS,IAAO;AAAA,EACpB;AACF;AAKO,SAAS,QAAQ,SAAyB;AAC/C,MAAI,QAAQ;AAEV,UAAM,aAAa,QAAQ,QAAQ,OAAO,GAAG;AAC7C,WAAO,WAAW,UAAU;AAAA,EAC9B;AACA,SAAO,UAAU,OAAO;AAC1B;;;ADzQA,SAAS,YAAY,QAAgB,QAAqC;AACxE,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,MAAM;AACxB,QAAI,EAAE,aAAa,WAAW,EAAE,aAAa,SAAU,QAAO;AAC9D,UAAM,WAAW,EAAE,aAAa,WAAW,UAAmB;AAE9D,UAAM,OAAO,EAAE,OAAO,SAAS,EAAE,MAAM,EAAE,IAAK,aAAa,UAAU,MAAM;AAC3E,UAAM,WAAW,EAAE,SAAS,YAAY;AACxC,QAAI,CAAC,YAAY,aAAa,eAAe,aAAa,YAAa,QAAO;AAC9E,WAAO,EAAE,UAAU,MAAM,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,SAAS,WAAW,MAAkB,QAAgB,KAA2B;AAC/E,MAAI,KAAK,SAAS,SAAS,KAAK,KAAK;AACnC,UAAM,IAAI,YAAY,KAAK,KAAK,MAAM;AACtC,QAAI,EAAG,KAAI,KAAK,CAAC;AAAA,EACnB;AACA,MAAI,KAAK,UAAU;AACjB,eAAW,SAAS,KAAK,SAAU,YAAW,OAAO,QAAQ,GAAG;AAAA,EAClE;AACF;AAEA,SAAS,eAAe,UAAkB,QAAgC;AACxE,MAAI,CAACC,YAAW,QAAQ,EAAG,QAAO,CAAC;AACnC,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC;AAGrD,UAAM,MAAsB,CAAC;AAC7B,eAAW,QAAQ,OAAO,OAAO,IAAI,KAAK,GAAG;AAC3C,UAAI,KAAM,YAAW,MAAM,QAAQ,GAAG;AAAA,IACxC;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,qBAAqB,YAA6C;AAC/E,QAAM,MAAMC,MAAK,YAAY,eAAe;AAC5C,MAAI,CAACD,YAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,QAAM,MAAMC,MAAK,OAAO,GAAG,oBAAoB,KAAK,IAAI,CAAC,SAAS;AAClE,MAAI;AACF,iBAAa,KAAK,GAAG;AACrB,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,OAAO,gBAAgB;AAC3D,UAAM,KAAK,IAAI,SAAS,KAAK,EAAE,UAAU,MAAM,eAAe,KAAK,CAAC;AACpE,UAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAMvB,EAAE,IAAI;AACP,OAAG,MAAM;AACT,WAAO,KAAK,IAAI,OAAK,YAAY,EAAE,KAAK,SAAS,CAAC,EAAE,OAAO,CAAC,MAAyB,MAAM,IAAI;AAAA,EACjG,QAAQ;AACN,WAAO,CAAC;AAAA,EACV,UAAE;AACA,QAAI;AAAE,OAAC,MAAM,OAAO,IAAS,GAAG,WAAW,GAAG;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAC1E;AACF;AAEA,eAAsB,mBAAmB,YAA4C;AACnF,QAAM,MAAMA,MAAK,YAAY,eAAe;AAC5C,MAAI,CAACD,YAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,QAAM,MAAMC,MAAK,OAAO,GAAG,sBAAsB,KAAK,IAAI,CAAC,SAAS;AACpE,MAAI;AACF,iBAAa,KAAK,GAAG;AACrB,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,OAAO,gBAAgB;AAC3D,UAAM,KAAK,IAAI,SAAS,KAAK,EAAE,UAAU,MAAM,eAAe,KAAK,CAAC;AACpE,UAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAOvB,EAAE,IAAI;AACP,OAAG,MAAM;AACT,WAAO,KACJ,IAAI,OAAK;AACR,YAAM,IAAI,YAAY,EAAE,KAAK,SAAS;AACtC,UAAI,CAAC,EAAG,QAAO;AACf,aAAO,EAAE,GAAG,GAAG,YAAY,EAAE,YAAY;AAAA,IAC3C,CAAC,EACA,OAAO,CAAC,MAAwB,MAAM,IAAI;AAAA,EAC/C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV,UAAE;AACA,QAAI;AAAE,OAAC,MAAM,OAAO,IAAS,GAAG,WAAW,GAAG;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAC1E;AACF;AAEA,eAAe,oBAAoB,aAAqB,QAAwC;AAC9F,MAAI,CAACD,YAAW,WAAW,EAAG,QAAO,CAAC;AACtC,QAAM,MAAMC,MAAK,OAAO,GAAG,sBAAsB,KAAK,IAAI,CAAC,SAAS;AACpE,MAAI;AACF,iBAAa,aAAa,GAAG;AAC7B,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,OAAO,gBAAgB;AAC3D,UAAM,KAAK,IAAI,SAAS,KAAK,EAAE,UAAU,MAAM,eAAe,KAAK,CAAC;AACpE,UAAM,OAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAOvB,EAAE,IAAI;AACP,OAAG,MAAM;AACT,WAAO,KACJ,IAAI,OAAK;AACR,YAAM,IAAI,YAAY,EAAE,KAAK,MAAM;AACnC,UAAI,CAAC,EAAG,QAAO;AACf,aAAO,EAAE,GAAG,GAAG,YAAY,EAAE,YAAY;AAAA,IAC3C,CAAC,EACA,OAAO,CAAC,MAAwB,MAAM,IAAI;AAAA,EAC/C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV,UAAE;AACA,QAAI;AAAE,OAAC,MAAM,OAAO,IAAS,GAAG,WAAW,GAAG;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAC1E;AACF;AAKA,IAAMC,YAAW,CAAC,UAAU,CAAC;AAG7B,SAAS,gBAAgB,MAAwB;AAC/C,QAAM,QAAkB,CAAC;AACzB,QAAM,cAAcD,MAAK,MAAM,WAAW,WAAW;AACrD,MAAID,YAAW,WAAW,EAAG,OAAM,KAAK,WAAW;AAEnD,MAAIA,YAAW,IAAI,GAAG;AACpB,QAAI;AACF,iBAAW,SAAS,YAAY,IAAI,GAAG;AACrC,YAAI,MAAM,WAAW,UAAU,GAAG;AAChC,gBAAM,IAAIC,MAAK,MAAM,OAAO,WAAW;AACvC,cAAID,YAAW,CAAC,EAAG,OAAM,KAAK,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAAe;AAAA,EACzB;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,MAAwB;AACtD,QAAM,QAAkB,CAAC;AACzB,QAAM,cAAcC,MAAK,MAAM,WAAW,SAAS;AACnD,MAAID,YAAW,WAAW,EAAG,OAAM,KAAK,WAAW;AACnD,MAAIA,YAAW,IAAI,GAAG;AACpB,QAAI;AACF,iBAAW,SAAS,YAAY,IAAI,GAAG;AACrC,YAAI,MAAM,WAAW,UAAU,GAAG;AAChC,gBAAM,IAAIC,MAAK,MAAM,OAAO,SAAS;AACrC,cAAID,YAAW,CAAC,EAAG,OAAM,KAAK,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAAe;AAAA,EACzB;AACA,SAAO;AACT;AAGA,IAAM,gBAAgB,iBAAiB;AAEvC,IAAM,cAAc,cAAc;AAClC,IAAM,gBAAgB,cAAc;AACpC,IAAM,YAAY,cAAc;AAChC,IAAM,aAAa,cAAc;AACjC,IAAM,eAAe,cAAc;AACnC,IAAM,aAAa,cAAc;AAGjC,IAAM,qBAAqBC,MAAK,MAAM,QAAQ,YAAY,UAAU,UAAU;AAC9E,IAAM,wBAAwBA,MAAK,MAAM,QAAQ,OAAO,yBAAyB,UAAU,UAAU;AACrG,IAAM,sBAAsBA,MAAK,MAAM,QAAQ,OAAO,qBAAqB,UAAU,eAAe;AACpG,IAAM,qBAAqBA,MAAK,MAAM,QAAQ,OAAO,qBAAqB,UAAU,iBAAiB,eAAe;AACpH,IAAM,oBAAoBA,MAAK,MAAM,QAAQ,OAAO,sBAAsB,UAAU,gBAAgB;AAEpG,SAAS,qBAA+B;AACtC,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,OAAiB,CAAC;AACxB,aAAW,QAAQ,OAAO;AACxB,QAAI,CAACD,YAAW,IAAI,EAAG;AACvB,QAAI;AACF,iBAAW,KAAK,YAAY,IAAI,GAAG;AACjC,cAAM,OAAOC,MAAK,MAAM,CAAC;AACzB,YAAI;AACF,cAAI,SAAS,IAAI,EAAE,YAAY,KAAKD,YAAWC,MAAK,MAAM,eAAe,CAAC,GAAG;AAC3E,iBAAK,KAAK,IAAI;AAAA,UAChB;AAAA,QACF,QAAQ;AAAA,QAAe;AAAA,MACzB;AAAA,IACF,QAAQ;AAAA,IAAe;AAAA,EACzB;AACA,SAAO;AACT;AAIA,eAAsB,mBAA4C;AAChE,QAAM,MAAsB,CAAC;AAG7B,aAAW,KAAK,gBAAgB,WAAW,EAAK,KAAI,KAAK,GAAG,eAAe,GAAG,QAAQ,CAAC;AACvF,aAAW,KAAK,gBAAgB,aAAa,EAAG,KAAI,KAAK,GAAG,eAAe,GAAG,UAAU,CAAC;AACzF,aAAW,KAAK,gBAAgB,SAAS,EAAO,KAAI,KAAK,GAAG,eAAe,GAAG,MAAM,CAAC;AACrF,aAAW,KAAK,gBAAgB,UAAU,EAAM,KAAI,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC;AACtF,aAAW,KAAK,gBAAgB,YAAY,EAAI,KAAI,KAAK,GAAG,eAAe,GAAG,SAAS,CAAC;AACxF,aAAW,KAAK,gBAAgB,UAAU,EAAM,KAAI,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC;AAGtF,MAAIC,WAAU;AACZ,eAAW,KAAK,gBAAgB,kBAAkB,EAAM,KAAI,KAAK,GAAG,eAAe,GAAG,eAAe,CAAC;AACtG,eAAW,KAAK,gBAAgB,qBAAqB,EAAG,KAAI,KAAK,GAAG,eAAe,GAAG,kBAAkB,CAAC;AACzG,eAAW,KAAK,gBAAgB,mBAAmB,EAAK,KAAI,KAAK,GAAG,eAAe,GAAG,gBAAgB,CAAC;AACvG,eAAW,KAAK,gBAAgB,kBAAkB,EAAM,KAAI,KAAK,GAAG,eAAe,GAAG,eAAe,CAAC;AACtG,eAAW,KAAK,gBAAgB,iBAAiB,EAAO,KAAI,KAAK,GAAG,eAAe,GAAG,cAAc,CAAC;AAAA,EACvG;AAGA,aAAW,OAAO,mBAAmB,GAAG;AACtC,QAAI,KAAK,GAAG,MAAM,qBAAqB,GAAG,CAAC;AAAA,EAC7C;AAGA,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO,IAAI,OAAO,OAAK;AACrB,QAAI,KAAK,IAAI,EAAE,QAAQ,EAAG,QAAO;AACjC,SAAK,IAAI,EAAE,QAAQ;AACnB,WAAO;AAAA,EACT,CAAC;AACH;AAEA,eAAsB,iBAAyC;AAC7D,QAAM,MAAqB,CAAC;AAG5B,aAAW,KAAK,uBAAuB,WAAW,EAAK,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AACzG,aAAW,KAAK,uBAAuB,aAAa,EAAG,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAC3G,aAAW,KAAK,uBAAuB,SAAS,EAAO,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACvG,aAAW,KAAK,uBAAuB,UAAU,EAAM,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,OAAO,CAAC;AACxG,aAAW,KAAK,uBAAuB,YAAY,EAAI,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAC1G,aAAW,KAAK,uBAAuB,UAAU,EAAM,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAGxG,MAAIA,WAAU;AACZ,eAAW,KAAK,uBAAuB,kBAAkB,EAAM,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,eAAe,CAAC;AACxH,eAAW,KAAK,uBAAuB,qBAAqB,EAAG,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AAC3H,eAAW,KAAK,uBAAuB,mBAAmB,EAAK,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AACzH,eAAW,KAAK,uBAAuB,kBAAkB,EAAM,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,eAAe,CAAC;AACxH,eAAW,KAAK,uBAAuB,iBAAiB,EAAO,KAAI,KAAK,GAAG,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAAA,EACzH;AAGA,aAAW,OAAO,mBAAmB,GAAG;AACtC,QAAI,KAAK,GAAG,MAAM,mBAAmB,GAAG,CAAC;AAAA,EAC3C;AAGA,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,KAAK,KAAK;AACnB,UAAM,WAAW,OAAO,IAAI,EAAE,QAAQ;AACtC,QAAI,UAAU;AACZ,eAAS,cAAc,EAAE;AAAA,IAC3B,OAAO;AACL,aAAO,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AAAA,IACjC;AAAA,EACF;AAGA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AACxE;","names":["existsSync","join","existsSync","join","IS_LINUX"]}
1
+ {"version":3,"sources":["../src/bookmarks.ts","../src/platform.ts"],"sourcesContent":["import { tmpdir } from 'node:os';\nimport { existsSync, readFileSync, readdirSync, copyFileSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { HOME, IS_WIN, IS_MAC, browserBasePaths, firefoxBaseDirs } from './platform.js';\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// Uses centralized platform.ts for Linux/macOS/Windows browser base paths.\n\nconst IS_LINUX = !IS_MAC && !IS_WIN;\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\n// Get browser bases from centralized platform module\nconst BROWSER_BASES = browserBasePaths();\n\nconst CHROME_BASE = BROWSER_BASES.chrome;\nconst CHROMIUM_BASE = BROWSER_BASES.chromium;\nconst EDGE_BASE = BROWSER_BASES.edge;\nconst BRAVE_BASE = BROWSER_BASES.brave;\nconst VIVALDI_BASE = BROWSER_BASES.vivaldi;\nconst OPERA_BASE = BROWSER_BASES.opera;\n\n// Snap / Flatpak variants (Linux only)\nconst CHROMIUM_SNAP_BASE = join(HOME, 'snap', 'chromium', 'common', 'chromium');\nconst CHROMIUM_FLATPAK_BASE = join(HOME, '.var', 'app', 'org.chromium.Chromium', 'config', 'chromium');\nconst CHROME_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.google.Chrome', 'config', 'google-chrome');\nconst BRAVE_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.brave.Browser', 'config', 'BraveSoftware', 'Brave-Browser');\nconst EDGE_FLATPAK_BASE = join(HOME, '.var', 'app', 'com.microsoft.Edge', 'config', 'microsoft-edge');\n\nfunction firefoxProfileDirs(): string[] {\n const bases = firefoxBaseDirs();\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 only — not macOS, not Windows)\n if (IS_LINUX) {\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 only — not macOS, not Windows)\n if (IS_LINUX) {\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","/**\n * Cross-platform utilities for Linux, macOS, and Windows.\n * Centralizes all OS-specific logic so scanning tools work everywhere.\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\n\n// ── Platform detection ───────────────────────────────────────────────────────\n\nexport type Platform = 'linux' | 'darwin' | 'win32';\n\nexport const PLATFORM: Platform = process.platform as Platform;\nexport const IS_WIN = PLATFORM === 'win32';\nexport const IS_MAC = PLATFORM === 'darwin';\nexport const IS_LINUX = PLATFORM === 'linux';\nexport const HOME = homedir();\n\n// ── Shell selection ──────────────────────────────────────────────────────────\n\n/**\n * Returns the correct shell for execSync on each platform.\n * - Windows: PowerShell (pwsh if available, otherwise powershell.exe)\n * - macOS/Linux: /bin/sh\n */\nexport function platformShell(): string {\n if (!IS_WIN) return '/bin/sh';\n // Prefer pwsh (PowerShell 7+) over powershell.exe (5.1)\n try {\n execSync('pwsh -Version', { stdio: 'pipe', timeout: 3000 });\n return 'pwsh';\n } catch {\n return 'powershell.exe';\n }\n}\n\n/** Cached shell value (computed once) */\nlet _shell: string | undefined;\nexport function getShell(): string {\n if (!_shell) _shell = platformShell();\n return _shell;\n}\n\n// ── Cross-platform command runner ────────────────────────────────────────────\n\nexport interface RunOptions {\n timeout?: number;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Run a shell command, returning stdout as string. Returns '' on error.\n * Automatically uses the correct shell for the platform.\n */\nexport function run(cmd: string, opts: RunOptions = {}): string {\n try {\n return execSync(cmd, {\n stdio: 'pipe',\n timeout: opts.timeout ?? 10_000,\n shell: getShell(),\n env: opts.env,\n }).toString().trim();\n } catch {\n return '';\n }\n}\n\n// ── Command existence check (cross-platform `which`) ─────────────────────────\n\n/**\n * Check if a command exists. Returns its path or '' if not found.\n * - Unix: `which <cmd>`\n * - Windows: `Get-Command <cmd>` via PowerShell\n */\nexport function commandExists(cmd: string): string {\n if (IS_WIN) {\n const r = run(`Get-Command ${cmd} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source`, { timeout: 5000 });\n return r;\n }\n return run(`which ${cmd} 2>/dev/null`);\n}\n\n// ── Null device ──────────────────────────────────────────────────────────────\n\nexport const NULL_DEV = IS_WIN ? 'NUL' : '/dev/null';\n\n// ── App data directories ─────────────────────────────────────────────────────\n\n/** Returns the platform-specific user app data directory */\nexport function appDataDir(): string {\n if (IS_WIN) return process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n if (IS_MAC) return join(HOME, 'Library', 'Application Support');\n return process.env.XDG_CONFIG_HOME ?? join(HOME, '.config');\n}\n\n/** Returns the platform-specific user data directory (broader than config) */\nexport function userDataDir(): string {\n if (IS_WIN) return process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n if (IS_MAC) return join(HOME, 'Library', 'Application Support');\n return process.env.XDG_DATA_HOME ?? join(HOME, '.local', 'share');\n}\n\n// ── Browser profile base paths (Chromium-based) ──────────────────────────────\n\nexport interface BrowserPaths {\n chrome: string;\n chromium: string;\n edge: string;\n brave: string;\n vivaldi: string;\n opera: string;\n}\n\nexport function browserBasePaths(): BrowserPaths {\n if (IS_WIN) {\n const local = process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n return {\n chrome: join(local, 'Google', 'Chrome', 'User Data'),\n chromium: join(local, 'Chromium', 'User Data'),\n edge: join(local, 'Microsoft', 'Edge', 'User Data'),\n brave: join(local, 'BraveSoftware', 'Brave-Browser', 'User Data'),\n vivaldi: join(local, 'Vivaldi', 'User Data'),\n opera: join(userDataDir(), 'Opera Software', 'Opera Stable'),\n };\n }\n if (IS_MAC) {\n const lib = join(HOME, 'Library', 'Application Support');\n return {\n chrome: join(lib, 'Google', 'Chrome'),\n chromium: join(lib, 'Chromium'),\n edge: join(lib, 'Microsoft Edge'),\n brave: join(lib, 'BraveSoftware', 'Brave-Browser'),\n vivaldi: join(lib, 'Vivaldi'),\n opera: join(lib, 'com.operasoftware.Opera'),\n };\n }\n // Linux\n return {\n chrome: join(HOME, '.config', 'google-chrome'),\n chromium: join(HOME, '.config', 'chromium'),\n edge: join(HOME, '.config', 'microsoft-edge'),\n brave: join(HOME, '.config', 'BraveSoftware', 'Brave-Browser'),\n vivaldi: join(HOME, '.config', 'vivaldi'),\n opera: join(HOME, '.config', 'opera'),\n };\n}\n\n/** Firefox profile parent directories per platform */\nexport function firefoxBaseDirs(): string[] {\n if (IS_WIN) {\n const roaming = process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n return [join(roaming, 'Mozilla', 'Firefox', 'Profiles')];\n }\n if (IS_MAC) {\n return [join(HOME, 'Library', 'Application Support', 'Firefox', 'Profiles')];\n }\n // Linux: standard + snap + flatpak\n return [\n join(HOME, '.mozilla', 'firefox'),\n join(HOME, 'snap', 'firefox', 'common', '.mozilla', 'firefox'),\n join(HOME, '.var', 'app', 'org.mozilla.firefox', '.mozilla', 'firefox'),\n ];\n}\n\n// ── Database scan directories ────────────────────────────────────────────────\n\n/** Returns directories to search for SQLite/DB files per platform */\nexport function dbScanDirs(): string[] {\n const dirs: string[] = [];\n if (IS_WIN) {\n const local = process.env.LOCALAPPDATA ?? join(HOME, 'AppData', 'Local');\n const roaming = process.env.APPDATA ?? join(HOME, 'AppData', 'Roaming');\n dirs.push(local, roaming);\n const pd = join(HOME, 'AppData', 'Local', 'Programs');\n if (existsSync(pd)) dirs.push(pd);\n } else if (IS_MAC) {\n dirs.push(join(HOME, 'Library', 'Application Support'));\n if (existsSync('/var/lib')) dirs.push('/var/lib');\n } else {\n const configDir = join(HOME, '.config');\n const dataDir = join(HOME, '.local', 'share');\n if (existsSync(configDir)) dirs.push(configDir);\n if (existsSync(dataDir)) dirs.push(dataDir);\n if (existsSync('/var/lib')) dirs.push('/var/lib');\n }\n return dirs.filter(d => existsSync(d));\n}\n\n// ── File search (cross-platform find) ────────────────────────────────────────\n\n/**\n * Search for files matching glob patterns in given directories.\n * - Unix: `find` command\n * - Windows: PowerShell `Get-ChildItem`\n */\nexport function findFiles(dirs: string[], patterns: string[], maxDepth: number, limit: number): string {\n if (dirs.length === 0) return '';\n if (IS_WIN) {\n const includes = patterns.map(p => `'${p}'`).join(',');\n const pathList = dirs.map(d => `'${d}'`).join(',');\n return run(\n `Get-ChildItem -Path ${pathList} -Recurse -Depth ${maxDepth} -Include ${includes} -ErrorAction SilentlyContinue | Select-Object -First ${limit} -ExpandProperty FullName`,\n { timeout: 15_000 },\n );\n }\n const nameArgs = patterns.map(p => `-name \"${p}\"`).join(' -o ');\n const findCmds = dirs.map(d => `find \"${d}\" -maxdepth ${maxDepth} \\\\( ${nameArgs} \\\\) 2>/dev/null`).join('; ');\n return run(`{ ${findCmds}; } | head -${limit}`, { timeout: 15_000 });\n}\n\n// ── Network scanning ─────────────────────────────────────────────────────────\n\n/** Get all listening TCP ports and the processes behind them */\nexport function scanListeningPorts(): string {\n if (IS_WIN) {\n // PowerShell: Get-NetTCPConnection for listening ports + owning process\n return run(\n `Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | ` +\n `ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; ` +\n `\"$($_.LocalAddress):$($_.LocalPort) PID=$($_.OwningProcess) $($p.ProcessName)\" } | ` +\n `Sort-Object -Unique`,\n { timeout: 15_000 },\n );\n }\n if (IS_MAC) {\n // macOS: lsof is the most reliable way (ss not available)\n return run('sudo lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null || lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null', { timeout: 15_000 });\n }\n // Linux: ss is the standard tool\n return run('ss -tlnp 2>/dev/null', { timeout: 10_000 });\n}\n\n/** Get running processes (cross-platform) */\nexport function scanProcesses(): string {\n if (IS_WIN) {\n return run(\n `Get-Process | Select-Object -Property Id, ProcessName, Path | Format-Table -AutoSize | Out-String -Width 200`,\n { timeout: 15_000 },\n );\n }\n return run('ps aux 2>/dev/null', { timeout: 10_000 });\n}\n\n// ── Windows-specific: installed programs ─────────────────────────────────────\n\n/** Scan Windows registry for installed programs */\nexport function scanWindowsPrograms(): string {\n if (!IS_WIN) return '';\n return run(\n `$paths = @(` +\n `'HKLM:\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*',` +\n `'HKLM:\\\\Software\\\\Wow6432Node\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*',` +\n `'HKCU:\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\*'` +\n `); Get-ItemProperty $paths -ErrorAction SilentlyContinue | ` +\n `Where-Object { $_.DisplayName } | ` +\n `Select-Object -Property DisplayName, Publisher, DisplayVersion | ` +\n `Sort-Object DisplayName | ` +\n `Format-Table -AutoSize | Out-String -Width 300`,\n { timeout: 20_000 },\n );\n}\n\n/** Scan Windows services for database engines */\nexport function scanWindowsDbServices(): string {\n if (!IS_WIN) return '';\n return run(\n `Get-Service | Where-Object { ` +\n `$_.Name -match 'postgres|mysql|mariadb|mongo|redis|MSSQL|elastic|clickhouse|cassandra' ` +\n `} | Select-Object Name, DisplayName, Status, StartType | Format-Table -AutoSize`,\n { timeout: 10_000 },\n );\n}\n\n// ── file:// URL helper ───────────────────────────────────────────────────────\n\n/** Generate a correct file:// URL for the current platform */\nexport function fileUrl(absPath: string): string {\n if (IS_WIN) {\n // Windows: file:///C:/Users/... (forward slashes, triple slash)\n const normalized = absPath.replace(/\\\\/g, '/');\n return `file:///${normalized}`;\n }\n return `file://${absPath}`;\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","join","IS_LINUX"]}
package/dist/cli.js CHANGED
@@ -15,14 +15,13 @@ import {
15
15
  PLATFORM,
16
16
  commandExists,
17
17
  dbScanDirs,
18
- fileUrl,
19
18
  findFiles,
20
19
  run,
21
20
  scanAllBookmarks,
22
21
  scanAllHistory,
23
22
  scanWindowsDbServices,
24
23
  scanWindowsPrograms
25
- } from "./chunk-PVFDCPPW.js";
24
+ } from "./chunk-3NVQ3ND6.js";
26
25
 
27
26
  // src/cli.ts
28
27
  import { Command } from "commander";
@@ -2837,23 +2836,18 @@ function exportAll(db, sessionId, outputDir, formats = ["mermaid", "json", "yaml
2837
2836
  const edges = db.getEdges(sessionId);
2838
2837
  const jgfPath = join2(outputDir, "cartography-graph.jgf.json");
2839
2838
  writeFileSync(jgfPath, exportJGF(nodes, edges));
2840
- process.stderr.write("\u2713 cartography-graph.jgf.json\n");
2841
2839
  if (formats.includes("mermaid")) {
2842
2840
  writeFileSync(join2(outputDir, "topology.mermaid"), generateTopologyMermaid(nodes, edges));
2843
2841
  writeFileSync(join2(outputDir, "dependencies.mermaid"), generateDependencyMermaid(nodes, edges));
2844
- process.stderr.write("\u2713 topology.mermaid, dependencies.mermaid\n");
2845
2842
  }
2846
2843
  if (formats.includes("json")) {
2847
2844
  writeFileSync(join2(outputDir, "catalog.json"), exportJSON(db, sessionId));
2848
- process.stderr.write("\u2713 catalog.json\n");
2849
2845
  }
2850
2846
  if (formats.includes("yaml")) {
2851
2847
  writeFileSync(join2(outputDir, "catalog-info.yaml"), exportBackstageYAML(nodes, edges));
2852
- process.stderr.write("\u2713 catalog-info.yaml\n");
2853
2848
  }
2854
2849
  if (formats.includes("html") || formats.includes("map") || formats.includes("discovery")) {
2855
2850
  writeFileSync(join2(outputDir, "discovery.html"), exportDiscoveryApp(nodes, edges));
2856
- process.stderr.write("\u2713 discovery.html\n");
2857
2851
  }
2858
2852
  if (formats.includes("sops")) {
2859
2853
  const sops = db.getSOPs(sessionId);
@@ -2863,10 +2857,6 @@ function exportAll(db, sessionId, outputDir, formats = ["mermaid", "json", "yaml
2863
2857
  const wfFilename = `workflow-${sop.workflowId.substring(0, 8)}.mermaid`;
2864
2858
  writeFileSync(join2(outputDir, "workflows", wfFilename), generateWorkflowMermaid(sop));
2865
2859
  }
2866
- if (sops.length > 0) {
2867
- process.stderr.write(`\u2713 ${sops.length} SOPs + workflow diagrams
2868
- `);
2869
- }
2870
2860
  }
2871
2861
  }
2872
2862
 
@@ -2886,7 +2876,7 @@ function main() {
2886
2876
  const program = new Command();
2887
2877
  const CMD = "datasynx-cartography";
2888
2878
  const VERSION = "0.7.0";
2889
- program.name(CMD).description("AI-powered Infrastructure Cartography & SOP Generation").version(VERSION);
2879
+ program.name(CMD).description("AI-powered Infrastructure Discovery & Agentic AI Cartography").version(VERSION);
2890
2880
  program.command("discover").description("Scan and map your infrastructure").option("--entry <hosts...>", "Entry points", ["localhost"]).option("--depth <n>", "Max crawl depth", "8").option("--max-turns <n>", "Max agent turns", "50").option("--model <m>", "Agent model", "claude-sonnet-4-5-20250929").option("--org <name>", "Organization name (for Backstage)").option("-o, --output <dir>", "Output directory", "./datasynx-output").option("--db <path>", "DB path").option("-v, --verbose", "Show agent reasoning", false).action(async (opts) => {
2891
2881
  checkPrerequisites();
2892
2882
  const config = defaultConfig({
@@ -3095,12 +3085,11 @@ function main() {
3095
3085
  `);
3096
3086
  }
3097
3087
  }
3098
- exportAll(db, sessionId, config.outputDir);
3099
- const osc8 = (url, label) => `\x1B]8;;${url}\x1B\\${label}\x1B]8;;\x1B\\`;
3088
+ exportAll(db, sessionId, config.outputDir, ["discovery"]);
3100
3089
  const discoveryPath = resolve(config.outputDir, "discovery.html");
3101
3090
  w("\n");
3102
3091
  if (existsSync2(discoveryPath)) {
3103
- w(` ${green("\u2192")} ${osc8(fileUrl(discoveryPath), bold("Open discovery.html"))} ${dim("\u2190 Map + Topology")}
3092
+ w(` ${green("\u2713")} ${bold("discovery.html")} ${dim("\u2190 Enterprise Map")}
3104
3093
  `);
3105
3094
  }
3106
3095
  w("\n");
@@ -3143,9 +3132,9 @@ function main() {
3143
3132
  w(` ${green(bold("\u2713"))} Total now: ${bold(String(followupStats.nodes))} nodes, ${bold(String(followupStats.edges))} edges
3144
3133
  `);
3145
3134
  w("\n");
3146
- exportAll(db, sessionId, config.outputDir);
3135
+ exportAll(db, sessionId, config.outputDir, ["discovery"]);
3147
3136
  if (existsSync2(discoveryPath)) {
3148
- w(` ${green("\u2192")} ${osc8(`file://${discoveryPath}`, bold("discovery.html updated"))}
3137
+ w(` ${green("\u2713")} ${bold("discovery.html updated")}
3149
3138
  `);
3150
3139
  }
3151
3140
  w("\n");
@@ -3383,7 +3372,7 @@ ${infraSummary.substring(0, 12e3)}`;
3383
3372
  const platformName = IS_WIN ? "Windows" : IS_MAC ? "macOS" : "Linux";
3384
3373
  out("\n");
3385
3374
  out(b(" DATASYNX CARTOGRAPHY") + " " + dim("v" + VERSION) + "\n");
3386
- out(dim(" AI-powered Infrastructure Cartography & SOP Generation\n"));
3375
+ out(dim(" AI-powered Infrastructure Discovery & Agentic AI Cartography\n"));
3387
3376
  out(dim(` Platform: ${platformName}
3388
3377
  `));
3389
3378
  out("\n");
@@ -3437,13 +3426,7 @@ ${infraSummary.substring(0, 12e3)}`;
3437
3426
  out("\n");
3438
3427
  out(dim(" Output:\n"));
3439
3428
  out(dim(" datasynx-output/\n"));
3440
- out(dim(" catalog.json Machine-readable full dump\n"));
3441
- out(dim(" catalog-info.yaml Backstage service catalog\n"));
3442
- out(dim(" topology.mermaid Infrastructure topology (graph TB)\n"));
3443
- out(dim(" dependencies.mermaid Service dependencies (graph LR)\n"));
3444
- out(dim(" discovery.html Enterprise discovery frontend (Map + Topology)\n"));
3445
- out(dim(" sops/ Generated SOPs as Markdown\n"));
3446
- out(dim(" workflows/ Workflow flowcharts as Mermaid\n"));
3429
+ out(dim(" discovery.html Enterprise Map\n"));
3447
3430
  out("\n");
3448
3431
  line();
3449
3432
  out(b(cyan(" ANALYSIS & EXPORT\n")));
@@ -3511,7 +3494,7 @@ ${infraSummary.substring(0, 12e3)}`;
3511
3494
  out("\n");
3512
3495
  });
3513
3496
  program.command("bookmarks").description("View all browser bookmarks (Chrome, Chromium, Edge, Brave, Vivaldi, Opera, Firefox)").action(async () => {
3514
- const { scanAllBookmarks: scanAllBookmarks2 } = await import("./bookmarks-KKS4M37J.js");
3497
+ const { scanAllBookmarks: scanAllBookmarks2 } = await import("./bookmarks-72CDYAHD.js");
3515
3498
  const out = (s) => process.stdout.write(s);
3516
3499
  process.stderr.write(" Scanning bookmarks...\n\n");
3517
3500
  const hosts = await scanAllBookmarks2();
@@ -3785,7 +3768,7 @@ ${infraSummary.substring(0, 12e3)}`;
3785
3768
  o(_c(" |___/ ") + "\n");
3786
3769
  o("\n");
3787
3770
  o(_b(" Cartography") + " " + _d("v" + VERSION) + "\n");
3788
- o(_d(" AI-powered Infrastructure Discovery & SOP Generation\n"));
3771
+ o(_d(" AI-powered Infrastructure Discovery & Agentic AI Cartography\n"));
3789
3772
  o(_d(" Built on Claude Agent SDK\n"));
3790
3773
  o("\n");
3791
3774
  if (process.argv.length <= 2) {