@datasynx/agentic-ai-cartography 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -33
- package/dist/bookmarks-VS56KVCO.js +25 -0
- package/dist/chunk-CJ2PITFA.js +785 -0
- package/dist/chunk-CJ2PITFA.js.map +1 -0
- package/dist/chunk-D6SRSLBF.js +48 -0
- package/dist/{chunk-WJR63RWY.js → chunk-J6FDZ6HZ.js} +11 -2
- package/dist/chunk-J6FDZ6HZ.js.map +1 -0
- package/dist/chunk-UGSNG3QJ.js +49 -0
- package/dist/chunk-UGSNG3QJ.js.map +1 -0
- package/dist/chunk-W7YE6AAH.js +1516 -0
- package/dist/chunk-W7YE6AAH.js.map +1 -0
- package/dist/cli.js +133 -664
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +60115 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +734 -0
- package/dist/index.d.ts +363 -7
- package/dist/index.js +1462 -161
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +33 -0
- package/dist/mcp-bin.js.map +1 -0
- package/dist/onnxruntime_binding-6Q6HXASN.node +0 -0
- package/dist/onnxruntime_binding-EKZT2NRK.node +0 -0
- package/dist/onnxruntime_binding-P6S7V3CI.node +0 -0
- package/dist/onnxruntime_binding-PJNNIIUO.node +0 -0
- package/dist/onnxruntime_binding-UN6SPTQK.node +0 -0
- package/dist/sdk-A6NLO3DJ.js +12294 -0
- package/dist/sdk-A6NLO3DJ.js.map +1 -0
- package/dist/sdk-G5D4WQZ4.js +12293 -0
- package/dist/sdk-G5D4WQZ4.js.map +1 -0
- package/dist/sdk-QSTAREST.js +4869 -0
- package/dist/sdk-QSTAREST.js.map +1 -0
- package/dist/sqlite-vec-EZN67B2V.js +40 -0
- package/dist/sqlite-vec-EZN67B2V.js.map +1 -0
- package/dist/sqlite-vec-UK5YYE5T.js +39 -0
- package/dist/sqlite-vec-UK5YYE5T.js.map +1 -0
- package/dist/transformers.node-BTYUTJK5.js +42884 -0
- package/dist/transformers.node-BTYUTJK5.js.map +1 -0
- package/dist/transformers.node-J6PRTTOX.js +42883 -0
- package/dist/transformers.node-J6PRTTOX.js.map +1 -0
- package/dist/{types-54623ALF.js → types-JG27FR3E.js} +5 -2
- package/dist/types-JG27FR3E.js.map +1 -0
- package/package.json +51 -16
- package/server.json +28 -0
- package/dist/bookmarks-BWNVQGPG.js +0 -14
- package/dist/chunk-QKNYI3SU.js +0 -459
- package/dist/chunk-QKNYI3SU.js.map +0 -1
- package/dist/chunk-WJR63RWY.js.map +0 -1
- /package/dist/{bookmarks-BWNVQGPG.js.map → bookmarks-VS56KVCO.js.map} +0 -0
- /package/dist/{types-54623ALF.js.map → chunk-D6SRSLBF.js.map} +0 -0
|
@@ -0,0 +1,785 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/bookmarks.ts
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import { existsSync as existsSync2, readFileSync, readdirSync, copyFileSync, statSync, unlinkSync } from "fs";
|
|
6
|
+
import { join as join2 } from "path";
|
|
7
|
+
|
|
8
|
+
// src/platform.ts
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
|
+
|
|
14
|
+
// src/allowlist.ts
|
|
15
|
+
var READONLY_BINARIES = /* @__PURE__ */ new Set([
|
|
16
|
+
// shell & text utilities
|
|
17
|
+
"echo",
|
|
18
|
+
"printf",
|
|
19
|
+
"true",
|
|
20
|
+
"false",
|
|
21
|
+
"test",
|
|
22
|
+
"cat",
|
|
23
|
+
"head",
|
|
24
|
+
"tail",
|
|
25
|
+
"grep",
|
|
26
|
+
"egrep",
|
|
27
|
+
"fgrep",
|
|
28
|
+
"awk",
|
|
29
|
+
"sed",
|
|
30
|
+
"cut",
|
|
31
|
+
"sort",
|
|
32
|
+
"uniq",
|
|
33
|
+
"wc",
|
|
34
|
+
"tr",
|
|
35
|
+
"xargs",
|
|
36
|
+
"tee",
|
|
37
|
+
"ls",
|
|
38
|
+
"find",
|
|
39
|
+
"which",
|
|
40
|
+
"command",
|
|
41
|
+
"type",
|
|
42
|
+
"basename",
|
|
43
|
+
"dirname",
|
|
44
|
+
"realpath",
|
|
45
|
+
"readlink",
|
|
46
|
+
"stat",
|
|
47
|
+
"file",
|
|
48
|
+
"printenv",
|
|
49
|
+
"date",
|
|
50
|
+
"hostname",
|
|
51
|
+
"uname",
|
|
52
|
+
"whoami",
|
|
53
|
+
"id",
|
|
54
|
+
"pwd",
|
|
55
|
+
"expr",
|
|
56
|
+
"seq",
|
|
57
|
+
"tac",
|
|
58
|
+
"rev",
|
|
59
|
+
"column",
|
|
60
|
+
"paste",
|
|
61
|
+
// network & process inspection (read-only)
|
|
62
|
+
"ss",
|
|
63
|
+
"netstat",
|
|
64
|
+
"lsof",
|
|
65
|
+
"ps",
|
|
66
|
+
"ip",
|
|
67
|
+
"ifconfig",
|
|
68
|
+
"arp",
|
|
69
|
+
"dig",
|
|
70
|
+
"nslookup",
|
|
71
|
+
"host",
|
|
72
|
+
// database clients (read-only usage is enforced separately for risky verbs)
|
|
73
|
+
"psql",
|
|
74
|
+
"mysql",
|
|
75
|
+
"mysqladmin",
|
|
76
|
+
"mongosh",
|
|
77
|
+
"redis-cli",
|
|
78
|
+
"sqlite3",
|
|
79
|
+
"pg_lsclusters",
|
|
80
|
+
"clickhouse-client",
|
|
81
|
+
// macOS
|
|
82
|
+
"mdfind"
|
|
83
|
+
]);
|
|
84
|
+
var CONDITIONAL_BINARIES = /* @__PURE__ */ new Set(["tee"]);
|
|
85
|
+
var PKG_MANAGERS = /* @__PURE__ */ new Set(["dpkg", "rpm", "snap", "flatpak", "brew", "winget", "choco", "scoop", "apt-cache"]);
|
|
86
|
+
var MUTATING_PKG = /^(install|uninstall|reinstall|remove|purge|erase|upgrade|update|add|delete|pin|enable|disable|-i|--install|-r|--remove|-P|--purge|-e|--erase|-U|--upgrade|-F|--freshen)$/i;
|
|
87
|
+
var COMMAND_RUNNERS = /* @__PURE__ */ new Set(["xargs", "env", "nice", "nohup", "timeout", "time", "stdbuf", "watch", "sudo"]);
|
|
88
|
+
var DANGEROUS_PS = /\b(Remove-Item|Remove-ItemProperty|Move-Item|Copy-Item|Rename-Item|New-Item|New-Service|Set-Content|Add-Content|Clear-Content|Out-File|Set-ItemProperty|Set-Service|Stop-Process|Stop-Service|Start-Service|Restart-Service|Stop-Computer|Restart-Computer|Format-Volume|Clear-Disk|Remove-\w+|Uninstall-\w+|Install-\w+|Set-\w+|New-\w+|Start-\w+|Stop-\w+|Restart-\w+|Invoke-Expression|iex|Invoke-WebRequest|Invoke-RestMethod|Invoke-Command|Start-Process|Register-\w+|Unregister-\w+|Disable-\w+|Enable-\w+|Reset-\w+|del|rmdir|rd)\b/i;
|
|
89
|
+
var DANGEROUS_POSIX = /\b(rm|rmdir|mv|dd|mkfs|chmod|chown|chgrp|kill|killall|pkill|reboot|shutdown|poweroff|halt|truncate|shred|fdisk|parted)\b/i;
|
|
90
|
+
var SUBCOMMAND_RULES = {
|
|
91
|
+
kubectl: (t) => allowFirstVerb(t, ["get", "describe", "top", "logs", "explain", "config", "version", "cluster-info", "api-resources", "api-versions", "auth"]),
|
|
92
|
+
docker: (t) => allowFirstVerb(t, ["ps", "images", "inspect", "version", "info", "logs", "stats", "top", "port", "history", "diff", "system", "context", "volume", "network", "image", "container"]) && !hasMutatingDockerVerb(t),
|
|
93
|
+
podman: (t) => SUBCOMMAND_RULES["docker"](t),
|
|
94
|
+
helm: (t) => allowFirstVerb(t, ["list", "ls", "status", "get", "show", "history", "version", "repo", "search", "env"]),
|
|
95
|
+
systemctl: (t) => allowFirstVerb(t, ["status", "show", "list-units", "list-unit-files", "list-sockets", "list-timers", "list-dependencies", "is-active", "is-enabled", "is-failed", "cat", "get-default", "show-environment"]),
|
|
96
|
+
service: (t) => t.some((x) => /^status$/i.test(x)),
|
|
97
|
+
// cloud CLIs: read-only actions only — must contain a read verb, never a mutating one
|
|
98
|
+
aws: (t) => containsAwsReadAction(t) && !hasMutatingCloudVerb(t),
|
|
99
|
+
gcloud: (t) => (hasToken(t, ["list", "describe"]) || isInfoOnly(t)) && !hasMutatingCloudVerb(t),
|
|
100
|
+
az: (t) => (hasToken(t, ["list", "show"]) || isInfoOnly(t)) && !hasMutatingCloudVerb(t),
|
|
101
|
+
// version control (read-only verbs only)
|
|
102
|
+
git: (t) => allowFirstVerb(t, ["status", "log", "show", "diff", "branch", "remote", "config", "rev-parse", "ls-files", "ls-remote", "describe", "tag", "shortlog", "cat-file", "symbolic-ref"]),
|
|
103
|
+
gh: (t) => allowFirstVerb(t, ["repo", "pr", "issue", "release", "api", "auth", "status"]) && hasToken(t, ["list", "view", "status", "get"])
|
|
104
|
+
};
|
|
105
|
+
var FETCH_RULES = {
|
|
106
|
+
curl: (t) => !t.some((x) => /^-X$/i.test(x) || /^--request$/i.test(x) || /^-[dF]$/.test(x) || /^--data/i.test(x) || /^--form$/i.test(x) || /^-[oO]$/.test(x) || /^--output$/i.test(x) || /^--upload-file$/i.test(x)),
|
|
107
|
+
wget: (t) => !t.some((x) => /^-O$/.test(x) || /^--output-document/i.test(x) || /^--post-data/i.test(x) || /^--method/i.test(x) || /^-i$/.test(x))
|
|
108
|
+
};
|
|
109
|
+
var READONLY_PS_VERBS = /* @__PURE__ */ new Set([
|
|
110
|
+
"get",
|
|
111
|
+
"select",
|
|
112
|
+
"where",
|
|
113
|
+
"measure",
|
|
114
|
+
"sort",
|
|
115
|
+
"format",
|
|
116
|
+
"out",
|
|
117
|
+
"convertto",
|
|
118
|
+
"convertfrom",
|
|
119
|
+
"compare",
|
|
120
|
+
"test",
|
|
121
|
+
"resolve",
|
|
122
|
+
"split",
|
|
123
|
+
"join",
|
|
124
|
+
"group",
|
|
125
|
+
"foreach",
|
|
126
|
+
"write",
|
|
127
|
+
"read",
|
|
128
|
+
"show",
|
|
129
|
+
"find",
|
|
130
|
+
"search",
|
|
131
|
+
"tee"
|
|
132
|
+
]);
|
|
133
|
+
var READONLY_PS_BARE = /* @__PURE__ */ new Set(["where", "select", "sort", "foreach", "ft", "fl", "gci", "gc", "gm", "gps", "gsv", "echo", "write-host", "write-output"]);
|
|
134
|
+
function allowFirstVerb(tokens, verbs) {
|
|
135
|
+
const verb = tokens.find((t) => !t.startsWith("-"));
|
|
136
|
+
return verb !== void 0 && verbs.includes(verb.toLowerCase());
|
|
137
|
+
}
|
|
138
|
+
function hasToken(tokens, any) {
|
|
139
|
+
const lower = tokens.map((t) => t.toLowerCase());
|
|
140
|
+
return any.some((a) => lower.includes(a));
|
|
141
|
+
}
|
|
142
|
+
function isInfoOnly(tokens) {
|
|
143
|
+
return hasToken(tokens, ["config", "account", "version", "info"]);
|
|
144
|
+
}
|
|
145
|
+
var MUTATING_CLOUD = /^(create|delete|update|put|set|add|remove|deploy|run|start|stop|restart|reboot|terminate|modify|attach|detach|associate|disassociate|enable|disable|invoke|exec|apply|destroy|scale|patch|register|deregister|import|copy|move|rename|reset|rotate|revoke|grant)([-_].*)?$/i;
|
|
146
|
+
function hasMutatingCloudVerb(tokens) {
|
|
147
|
+
return tokens.some((t) => !t.startsWith("-") && MUTATING_CLOUD.test(t));
|
|
148
|
+
}
|
|
149
|
+
function containsAwsReadAction(tokens) {
|
|
150
|
+
return tokens.some((t) => /^(describe|list|get|lookup|search|scan|view|ls)[-_a-z0-9]*$/i.test(t) || t.toLowerCase() === "ls");
|
|
151
|
+
}
|
|
152
|
+
function hasMutatingDockerVerb(tokens) {
|
|
153
|
+
return tokens.some((t) => /^(run|rm|rmi|exec|build|push|pull|start|stop|kill|create|commit|cp|save|load|tag|login|logout|prune|kill|restart|pause|unpause|rename|update|export|import)$/i.test(t));
|
|
154
|
+
}
|
|
155
|
+
function splitSegments(cmd) {
|
|
156
|
+
const segments = [];
|
|
157
|
+
let buf = "";
|
|
158
|
+
let quote = null;
|
|
159
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
160
|
+
const c = cmd[i];
|
|
161
|
+
const next = cmd[i + 1];
|
|
162
|
+
if (quote) {
|
|
163
|
+
buf += c;
|
|
164
|
+
if (c === quote) quote = null;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (c === '"' || c === "'") {
|
|
168
|
+
quote = c;
|
|
169
|
+
buf += c;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (c === "|" && next === "|" || c === "&" && next === "&") {
|
|
173
|
+
segments.push(buf);
|
|
174
|
+
buf = "";
|
|
175
|
+
i++;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (c === "|" || c === ";" || c === "\n") {
|
|
179
|
+
segments.push(buf);
|
|
180
|
+
buf = "";
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
buf += c;
|
|
184
|
+
}
|
|
185
|
+
segments.push(buf);
|
|
186
|
+
return segments.map((s) => s.trim()).filter(Boolean);
|
|
187
|
+
}
|
|
188
|
+
function tokenize(segment) {
|
|
189
|
+
const tokens = [];
|
|
190
|
+
let buf = "";
|
|
191
|
+
let quote = null;
|
|
192
|
+
let started = false;
|
|
193
|
+
const push = () => {
|
|
194
|
+
if (started) {
|
|
195
|
+
tokens.push(buf);
|
|
196
|
+
buf = "";
|
|
197
|
+
started = false;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
for (let i = 0; i < segment.length; i++) {
|
|
201
|
+
const c = segment[i];
|
|
202
|
+
if (quote) {
|
|
203
|
+
if (c === quote) quote = null;
|
|
204
|
+
else buf += c;
|
|
205
|
+
started = true;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (c === '"' || c === "'") {
|
|
209
|
+
quote = c;
|
|
210
|
+
started = true;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (c === " " || c === " ") {
|
|
214
|
+
push();
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
buf += c;
|
|
218
|
+
started = true;
|
|
219
|
+
}
|
|
220
|
+
push();
|
|
221
|
+
return tokens;
|
|
222
|
+
}
|
|
223
|
+
function baseName(executable) {
|
|
224
|
+
const noPath = executable.split(/[\\/]/).pop() ?? executable;
|
|
225
|
+
return noPath.toLowerCase();
|
|
226
|
+
}
|
|
227
|
+
function findIsReadOnly(rest) {
|
|
228
|
+
return !rest.some((t) => /^-(exec|execdir|ok|okdir|delete|fprintf|fprint|fls)$/i.test(t));
|
|
229
|
+
}
|
|
230
|
+
function awkSedIsReadOnly(exe, rest) {
|
|
231
|
+
const program = rest.join(" ");
|
|
232
|
+
if (exe === "awk") return !/\bsystem\s*\(/.test(program) && !/\|\s*["']/.test(program) && !/print\s*>/.test(program);
|
|
233
|
+
return !/(^|;|\{|\s)e\b/.test(program) && !/s[^\s]*\/[a-z]*e[a-z]*\b/i.test(program) && !/\bw\s+\S/.test(program);
|
|
234
|
+
}
|
|
235
|
+
function isWriteRedirect(segment) {
|
|
236
|
+
const stripped = segment.replace(/\d?>>?\s*\/dev\/null/g, "").replace(/\d?>\s*&\s*\d/g, "").replace(/\d?>\s*\$null/gi, "");
|
|
237
|
+
return /(^|[^0-9&])>>?/.test(stripped);
|
|
238
|
+
}
|
|
239
|
+
function checkReadOnly(command, opts = {}) {
|
|
240
|
+
const cmd = command.trim();
|
|
241
|
+
if (!cmd) return { allowed: false, reason: "empty command" };
|
|
242
|
+
if (opts.shell === "powershell") {
|
|
243
|
+
if (isWriteRedirect(cmd)) return { allowed: false, reason: "file-writing redirect is not allowed" };
|
|
244
|
+
if (DANGEROUS_PS.test(cmd)) return { allowed: false, reason: "mutating PowerShell cmdlet is not allowed" };
|
|
245
|
+
if (DANGEROUS_POSIX.test(cmd)) return { allowed: false, reason: "destructive command is not allowed" };
|
|
246
|
+
return { allowed: true };
|
|
247
|
+
}
|
|
248
|
+
if (/\$\(|`/.test(cmd)) return { allowed: false, reason: "command substitution is not allowed" };
|
|
249
|
+
if (isWriteRedirect(cmd)) return { allowed: false, reason: "file-writing redirect is not allowed" };
|
|
250
|
+
for (const segment of splitSegments(cmd)) {
|
|
251
|
+
const r = checkSegment(segment);
|
|
252
|
+
if (!r.allowed) return r;
|
|
253
|
+
}
|
|
254
|
+
return { allowed: true };
|
|
255
|
+
}
|
|
256
|
+
function checkSegment(segment) {
|
|
257
|
+
let tokens = tokenize(segment).filter((t) => !/^[A-Za-z_][A-Za-z0-9_]*=/.test(t)).filter((t) => t !== "{" && t !== "}" && t !== "(" && t !== ")");
|
|
258
|
+
if (tokens.length === 0) return { allowed: true };
|
|
259
|
+
let exe = baseName(tokens[0]);
|
|
260
|
+
let rest = tokens.slice(1);
|
|
261
|
+
while (COMMAND_RUNNERS.has(exe)) {
|
|
262
|
+
const inner = [];
|
|
263
|
+
let i = 0;
|
|
264
|
+
for (; i < rest.length; i++) {
|
|
265
|
+
const t = rest[i];
|
|
266
|
+
if (t.startsWith("-")) {
|
|
267
|
+
if (/^-(I|n|L|P|d|s|E|u|g)$/.test(t)) i++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
inner.push(...rest.slice(i));
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
if (inner.length === 0) return { allowed: true };
|
|
274
|
+
exe = baseName(inner[0]);
|
|
275
|
+
rest = inner.slice(1);
|
|
276
|
+
}
|
|
277
|
+
if (exe === "find") {
|
|
278
|
+
if (!findIsReadOnly(rest)) return { allowed: false, reason: "find: -exec/-delete is not allowed" };
|
|
279
|
+
return { allowed: true };
|
|
280
|
+
}
|
|
281
|
+
if (exe === "awk" || exe === "sed") {
|
|
282
|
+
if (!awkSedIsReadOnly(exe, rest)) return { allowed: false, reason: `${exe}: program may not shell out or write files` };
|
|
283
|
+
return { allowed: true };
|
|
284
|
+
}
|
|
285
|
+
if (PKG_MANAGERS.has(exe)) {
|
|
286
|
+
if (rest.some((t) => MUTATING_PKG.test(t))) return { allowed: false, reason: `${exe}: only list/query sub-commands are allowed` };
|
|
287
|
+
return { allowed: true };
|
|
288
|
+
}
|
|
289
|
+
if (FETCH_RULES[exe]) {
|
|
290
|
+
if (!FETCH_RULES[exe](rest)) return { allowed: false, reason: `${exe}: only read-only GET requests are allowed` };
|
|
291
|
+
return { allowed: true };
|
|
292
|
+
}
|
|
293
|
+
if (SUBCOMMAND_RULES[exe]) {
|
|
294
|
+
if (!SUBCOMMAND_RULES[exe](rest)) return { allowed: false, reason: `${exe}: sub-command is not read-only` };
|
|
295
|
+
return { allowed: true };
|
|
296
|
+
}
|
|
297
|
+
if (CONDITIONAL_BINARIES.has(exe)) {
|
|
298
|
+
if (rest.some((t) => !t.startsWith("-") && t !== "/dev/null")) return { allowed: false, reason: "tee may only write to /dev/null" };
|
|
299
|
+
return { allowed: true };
|
|
300
|
+
}
|
|
301
|
+
if (READONLY_BINARIES.has(exe)) return { allowed: true };
|
|
302
|
+
if (READONLY_PS_BARE.has(exe)) return { allowed: true };
|
|
303
|
+
if (exe.includes("-") && /^[a-z]+-[a-z]/.test(exe)) {
|
|
304
|
+
const verb = exe.split("-")[0];
|
|
305
|
+
if (READONLY_PS_VERBS.has(verb)) return { allowed: true };
|
|
306
|
+
return { allowed: false, reason: `PowerShell cmdlet not read-only: ${exe}` };
|
|
307
|
+
}
|
|
308
|
+
return { allowed: false, reason: `command not on read-only allowlist: ${exe}` };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/logger.ts
|
|
312
|
+
var verboseMode = false;
|
|
313
|
+
function setVerbose(v) {
|
|
314
|
+
verboseMode = v;
|
|
315
|
+
}
|
|
316
|
+
function log(level, message, context) {
|
|
317
|
+
if (level === "DEBUG" && !verboseMode) return;
|
|
318
|
+
const entry = {
|
|
319
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
320
|
+
level,
|
|
321
|
+
message,
|
|
322
|
+
...context && Object.keys(context).length > 0 ? { context } : {}
|
|
323
|
+
};
|
|
324
|
+
process.stderr.write(JSON.stringify(entry) + "\n");
|
|
325
|
+
}
|
|
326
|
+
function logDebug(message, context) {
|
|
327
|
+
log("DEBUG", message, context);
|
|
328
|
+
}
|
|
329
|
+
function logInfo(message, context) {
|
|
330
|
+
log("INFO", message, context);
|
|
331
|
+
}
|
|
332
|
+
function logWarn(message, context) {
|
|
333
|
+
log("WARN", message, context);
|
|
334
|
+
}
|
|
335
|
+
function logError(message, context) {
|
|
336
|
+
log("ERROR", message, context);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/platform.ts
|
|
340
|
+
var PLATFORM = process.platform;
|
|
341
|
+
var IS_WIN = PLATFORM === "win32";
|
|
342
|
+
var IS_MAC = PLATFORM === "darwin";
|
|
343
|
+
var IS_LINUX = PLATFORM === "linux";
|
|
344
|
+
var HOME = homedir();
|
|
345
|
+
function platformShell() {
|
|
346
|
+
if (!IS_WIN) return "/bin/sh";
|
|
347
|
+
try {
|
|
348
|
+
execSync("pwsh -Version", { stdio: "pipe", timeout: 3e3 });
|
|
349
|
+
return "pwsh";
|
|
350
|
+
} catch {
|
|
351
|
+
return "powershell.exe";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
var _shell;
|
|
355
|
+
function getShell() {
|
|
356
|
+
if (!_shell) _shell = platformShell();
|
|
357
|
+
return _shell;
|
|
358
|
+
}
|
|
359
|
+
var SAFE_ENV_KEYS = [
|
|
360
|
+
"PATH",
|
|
361
|
+
"HOME",
|
|
362
|
+
"USER",
|
|
363
|
+
"LANG",
|
|
364
|
+
"LC_ALL",
|
|
365
|
+
"TERM",
|
|
366
|
+
"SHELL",
|
|
367
|
+
"USERPROFILE",
|
|
368
|
+
"LOCALAPPDATA",
|
|
369
|
+
"APPDATA",
|
|
370
|
+
"PROGRAMFILES",
|
|
371
|
+
"XDG_CONFIG_HOME",
|
|
372
|
+
"XDG_DATA_HOME",
|
|
373
|
+
"XDG_RUNTIME_DIR",
|
|
374
|
+
"AWS_DEFAULT_REGION",
|
|
375
|
+
"AWS_PROFILE",
|
|
376
|
+
"AWS_CONFIG_FILE",
|
|
377
|
+
"KUBECONFIG",
|
|
378
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
379
|
+
"AZURE_CONFIG_DIR"
|
|
380
|
+
];
|
|
381
|
+
function safeEnv() {
|
|
382
|
+
const env = {};
|
|
383
|
+
for (const key of SAFE_ENV_KEYS) {
|
|
384
|
+
if (process.env[key]) env[key] = process.env[key];
|
|
385
|
+
}
|
|
386
|
+
return env;
|
|
387
|
+
}
|
|
388
|
+
function run(cmd, opts = {}) {
|
|
389
|
+
const policy = checkReadOnly(cmd, { shell: IS_WIN ? "powershell" : "posix" });
|
|
390
|
+
if (!policy.allowed) {
|
|
391
|
+
logWarn(`Blocked non-read-only command: ${policy.reason}`);
|
|
392
|
+
return "";
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
return execSync(cmd, {
|
|
396
|
+
stdio: "pipe",
|
|
397
|
+
timeout: opts.timeout ?? 1e4,
|
|
398
|
+
shell: getShell(),
|
|
399
|
+
env: opts.env ?? safeEnv()
|
|
400
|
+
}).toString().trim();
|
|
401
|
+
} catch {
|
|
402
|
+
return "";
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function commandExists(cmd) {
|
|
406
|
+
if (IS_WIN) {
|
|
407
|
+
const r = run(`Get-Command ${cmd} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source`, { timeout: 5e3 });
|
|
408
|
+
return r;
|
|
409
|
+
}
|
|
410
|
+
return run(`which ${cmd} 2>/dev/null`);
|
|
411
|
+
}
|
|
412
|
+
function userDataDir() {
|
|
413
|
+
if (IS_WIN) return process.env.APPDATA ?? join(HOME, "AppData", "Roaming");
|
|
414
|
+
if (IS_MAC) return join(HOME, "Library", "Application Support");
|
|
415
|
+
return process.env.XDG_DATA_HOME ?? join(HOME, ".local", "share");
|
|
416
|
+
}
|
|
417
|
+
function browserBasePaths() {
|
|
418
|
+
if (IS_WIN) {
|
|
419
|
+
const local = process.env.LOCALAPPDATA ?? join(HOME, "AppData", "Local");
|
|
420
|
+
return {
|
|
421
|
+
chrome: join(local, "Google", "Chrome", "User Data"),
|
|
422
|
+
chromium: join(local, "Chromium", "User Data"),
|
|
423
|
+
edge: join(local, "Microsoft", "Edge", "User Data"),
|
|
424
|
+
brave: join(local, "BraveSoftware", "Brave-Browser", "User Data"),
|
|
425
|
+
vivaldi: join(local, "Vivaldi", "User Data"),
|
|
426
|
+
opera: join(userDataDir(), "Opera Software", "Opera Stable")
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
if (IS_MAC) {
|
|
430
|
+
const lib = join(HOME, "Library", "Application Support");
|
|
431
|
+
return {
|
|
432
|
+
chrome: join(lib, "Google", "Chrome"),
|
|
433
|
+
chromium: join(lib, "Chromium"),
|
|
434
|
+
edge: join(lib, "Microsoft Edge"),
|
|
435
|
+
brave: join(lib, "BraveSoftware", "Brave-Browser"),
|
|
436
|
+
vivaldi: join(lib, "Vivaldi"),
|
|
437
|
+
opera: join(lib, "com.operasoftware.Opera")
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
chrome: join(HOME, ".config", "google-chrome"),
|
|
442
|
+
chromium: join(HOME, ".config", "chromium"),
|
|
443
|
+
edge: join(HOME, ".config", "microsoft-edge"),
|
|
444
|
+
brave: join(HOME, ".config", "BraveSoftware", "Brave-Browser"),
|
|
445
|
+
vivaldi: join(HOME, ".config", "vivaldi"),
|
|
446
|
+
opera: join(HOME, ".config", "opera")
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function firefoxBaseDirs() {
|
|
450
|
+
if (IS_WIN) {
|
|
451
|
+
const roaming = process.env.APPDATA ?? join(HOME, "AppData", "Roaming");
|
|
452
|
+
return [join(roaming, "Mozilla", "Firefox", "Profiles")];
|
|
453
|
+
}
|
|
454
|
+
if (IS_MAC) {
|
|
455
|
+
return [join(HOME, "Library", "Application Support", "Firefox", "Profiles")];
|
|
456
|
+
}
|
|
457
|
+
return [
|
|
458
|
+
join(HOME, ".mozilla", "firefox"),
|
|
459
|
+
join(HOME, "snap", "firefox", "common", ".mozilla", "firefox"),
|
|
460
|
+
join(HOME, ".var", "app", "org.mozilla.firefox", ".mozilla", "firefox")
|
|
461
|
+
];
|
|
462
|
+
}
|
|
463
|
+
function dbScanDirs() {
|
|
464
|
+
const dirs = [];
|
|
465
|
+
if (IS_WIN) {
|
|
466
|
+
const local = process.env.LOCALAPPDATA ?? join(HOME, "AppData", "Local");
|
|
467
|
+
const roaming = process.env.APPDATA ?? join(HOME, "AppData", "Roaming");
|
|
468
|
+
dirs.push(local, roaming);
|
|
469
|
+
const pd = join(HOME, "AppData", "Local", "Programs");
|
|
470
|
+
if (existsSync(pd)) dirs.push(pd);
|
|
471
|
+
} else if (IS_MAC) {
|
|
472
|
+
dirs.push(join(HOME, "Library", "Application Support"));
|
|
473
|
+
if (existsSync("/var/lib")) dirs.push("/var/lib");
|
|
474
|
+
} else {
|
|
475
|
+
const configDir = join(HOME, ".config");
|
|
476
|
+
const dataDir = join(HOME, ".local", "share");
|
|
477
|
+
if (existsSync(configDir)) dirs.push(configDir);
|
|
478
|
+
if (existsSync(dataDir)) dirs.push(dataDir);
|
|
479
|
+
if (existsSync("/var/lib")) dirs.push("/var/lib");
|
|
480
|
+
}
|
|
481
|
+
return dirs.filter((d) => existsSync(d));
|
|
482
|
+
}
|
|
483
|
+
function findFiles(dirs, patterns, maxDepth, limit) {
|
|
484
|
+
if (dirs.length === 0) return "";
|
|
485
|
+
if (IS_WIN) {
|
|
486
|
+
const includes = patterns.map((p) => `'${p}'`).join(",");
|
|
487
|
+
const pathList = dirs.map((d) => `'${d}'`).join(",");
|
|
488
|
+
return run(
|
|
489
|
+
`Get-ChildItem -Path ${pathList} -Recurse -Depth ${maxDepth} -Include ${includes} -ErrorAction SilentlyContinue | Select-Object -First ${limit} -ExpandProperty FullName`,
|
|
490
|
+
{ timeout: 15e3 }
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
const nameArgs = patterns.map((p) => `-name "${p}"`).join(" -o ");
|
|
494
|
+
const findCmds = dirs.map((d) => `find "${d}" -maxdepth ${maxDepth} \\( ${nameArgs} \\) 2>/dev/null`).join("; ");
|
|
495
|
+
return run(`{ ${findCmds}; } | head -${limit}`, { timeout: 15e3 });
|
|
496
|
+
}
|
|
497
|
+
function scanListeningPorts() {
|
|
498
|
+
if (IS_WIN) {
|
|
499
|
+
return run(
|
|
500
|
+
`Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; "$($_.LocalAddress):$($_.LocalPort) PID=$($_.OwningProcess) $($p.ProcessName)" } | Sort-Object -Unique`,
|
|
501
|
+
{ timeout: 15e3 }
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
if (IS_MAC) {
|
|
505
|
+
return run("sudo lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null || lsof -iTCP -sTCP:LISTEN -n -P 2>/dev/null", { timeout: 15e3 });
|
|
506
|
+
}
|
|
507
|
+
return run("ss -tlnp 2>/dev/null", { timeout: 1e4 });
|
|
508
|
+
}
|
|
509
|
+
function scanWindowsPrograms() {
|
|
510
|
+
if (!IS_WIN) return "";
|
|
511
|
+
return run(
|
|
512
|
+
`$paths = @('HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*','HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*','HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'); Get-ItemProperty $paths -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName } | Select-Object -Property DisplayName, Publisher, DisplayVersion | Sort-Object DisplayName | Format-Table -AutoSize | Out-String -Width 300`,
|
|
513
|
+
{ timeout: 2e4 }
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
function scanWindowsDbServices() {
|
|
517
|
+
if (!IS_WIN) return "";
|
|
518
|
+
return run(
|
|
519
|
+
`Get-Service | Where-Object { $_.Name -match 'postgres|mysql|mariadb|mongo|redis|MSSQL|elastic|clickhouse|cassandra' } | Select-Object Name, DisplayName, Status, StartType | Format-Table -AutoSize`,
|
|
520
|
+
{ timeout: 1e4 }
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// src/bookmarks.ts
|
|
525
|
+
function cleanupTempFiles() {
|
|
526
|
+
let cleaned = 0;
|
|
527
|
+
const tmp = tmpdir();
|
|
528
|
+
try {
|
|
529
|
+
for (const f of readdirSync(tmp)) {
|
|
530
|
+
if (f.startsWith("cartograph_") && f.endsWith(".sqlite")) {
|
|
531
|
+
try {
|
|
532
|
+
unlinkSync(join2(tmp, f));
|
|
533
|
+
cleaned++;
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
} catch {
|
|
539
|
+
}
|
|
540
|
+
return cleaned;
|
|
541
|
+
}
|
|
542
|
+
function extractHost(rawUrl, source) {
|
|
543
|
+
try {
|
|
544
|
+
const u = new URL(rawUrl);
|
|
545
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return null;
|
|
546
|
+
const protocol = u.protocol === "https:" ? "https" : "http";
|
|
547
|
+
const port = u.port ? parseInt(u.port, 10) : protocol === "https" ? 443 : 80;
|
|
548
|
+
const hostname = u.hostname.toLowerCase();
|
|
549
|
+
if (!hostname || hostname === "localhost" || hostname === "127.0.0.1") return null;
|
|
550
|
+
return { hostname, port, protocol, source };
|
|
551
|
+
} catch {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function walkChrome(node, source, out) {
|
|
556
|
+
if (node.type === "url" && node.url) {
|
|
557
|
+
const h = extractHost(node.url, source);
|
|
558
|
+
if (h) out.push(h);
|
|
559
|
+
}
|
|
560
|
+
if (node.children) {
|
|
561
|
+
for (const child of node.children) walkChrome(child, source, out);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function readChromeLike(filePath, source) {
|
|
565
|
+
if (!existsSync2(filePath)) return [];
|
|
566
|
+
try {
|
|
567
|
+
const raw = JSON.parse(readFileSync(filePath, "utf8"));
|
|
568
|
+
const out = [];
|
|
569
|
+
for (const root of Object.values(raw.roots)) {
|
|
570
|
+
if (root) walkChrome(root, source, out);
|
|
571
|
+
}
|
|
572
|
+
return out;
|
|
573
|
+
} catch {
|
|
574
|
+
return [];
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async function queryBrowserDb(srcPath, tmpPrefix, query) {
|
|
578
|
+
if (!existsSync2(srcPath)) return [];
|
|
579
|
+
const tmp = join2(tmpdir(), `cartograph_${tmpPrefix}_${Date.now()}.sqlite`);
|
|
580
|
+
try {
|
|
581
|
+
copyFileSync(srcPath, tmp);
|
|
582
|
+
const { default: Database } = await import("better-sqlite3");
|
|
583
|
+
const db = new Database(tmp, { readonly: true, fileMustExist: true });
|
|
584
|
+
try {
|
|
585
|
+
return db.prepare(query).all();
|
|
586
|
+
} finally {
|
|
587
|
+
db.close();
|
|
588
|
+
}
|
|
589
|
+
} catch {
|
|
590
|
+
return [];
|
|
591
|
+
} finally {
|
|
592
|
+
try {
|
|
593
|
+
unlinkSync(tmp);
|
|
594
|
+
} catch {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
async function readFirefoxBookmarks(profileDir) {
|
|
599
|
+
const rows = await queryBrowserDb(
|
|
600
|
+
join2(profileDir, "places.sqlite"),
|
|
601
|
+
"ff_bm",
|
|
602
|
+
`SELECT DISTINCT p.url FROM moz_places p
|
|
603
|
+
JOIN moz_bookmarks b ON b.fk = p.id
|
|
604
|
+
WHERE b.type = 1 AND p.url NOT LIKE 'place:%' LIMIT 3000`
|
|
605
|
+
);
|
|
606
|
+
return rows.map((r) => extractHost(r.url, "firefox")).filter((h) => h !== null);
|
|
607
|
+
}
|
|
608
|
+
async function readFirefoxHistory(profileDir) {
|
|
609
|
+
const rows = await queryBrowserDb(
|
|
610
|
+
join2(profileDir, "places.sqlite"),
|
|
611
|
+
"ff_hist",
|
|
612
|
+
`SELECT url, visit_count FROM moz_places
|
|
613
|
+
WHERE url NOT LIKE 'place:%' AND visit_count > 0
|
|
614
|
+
ORDER BY visit_count DESC LIMIT 5000`
|
|
615
|
+
);
|
|
616
|
+
return rows.map((r) => {
|
|
617
|
+
const h = extractHost(r.url, "firefox");
|
|
618
|
+
return h ? { ...h, visitCount: r.visit_count } : null;
|
|
619
|
+
}).filter((h) => h !== null);
|
|
620
|
+
}
|
|
621
|
+
async function readChromiumHistory(historyPath, source) {
|
|
622
|
+
const rows = await queryBrowserDb(
|
|
623
|
+
historyPath,
|
|
624
|
+
"ch_hist",
|
|
625
|
+
`SELECT url, visit_count FROM urls
|
|
626
|
+
WHERE hidden = 0 AND visit_count > 0
|
|
627
|
+
ORDER BY visit_count DESC LIMIT 5000`
|
|
628
|
+
);
|
|
629
|
+
return rows.map((r) => {
|
|
630
|
+
const h = extractHost(r.url, source);
|
|
631
|
+
return h ? { ...h, visitCount: r.visit_count } : null;
|
|
632
|
+
}).filter((h) => h !== null);
|
|
633
|
+
}
|
|
634
|
+
var IS_LINUX2 = !IS_MAC && !IS_WIN;
|
|
635
|
+
function chromeLikePaths(base) {
|
|
636
|
+
const paths = [];
|
|
637
|
+
const defaultPath = join2(base, "Default", "Bookmarks");
|
|
638
|
+
if (existsSync2(defaultPath)) paths.push(defaultPath);
|
|
639
|
+
if (existsSync2(base)) {
|
|
640
|
+
try {
|
|
641
|
+
for (const entry of readdirSync(base)) {
|
|
642
|
+
if (entry.startsWith("Profile ")) {
|
|
643
|
+
const p = join2(base, entry, "Bookmarks");
|
|
644
|
+
if (existsSync2(p)) paths.push(p);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return paths;
|
|
651
|
+
}
|
|
652
|
+
function chromeLikeHistoryPaths(base) {
|
|
653
|
+
const paths = [];
|
|
654
|
+
const defaultPath = join2(base, "Default", "History");
|
|
655
|
+
if (existsSync2(defaultPath)) paths.push(defaultPath);
|
|
656
|
+
if (existsSync2(base)) {
|
|
657
|
+
try {
|
|
658
|
+
for (const entry of readdirSync(base)) {
|
|
659
|
+
if (entry.startsWith("Profile ")) {
|
|
660
|
+
const p = join2(base, entry, "History");
|
|
661
|
+
if (existsSync2(p)) paths.push(p);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
} catch {
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return paths;
|
|
668
|
+
}
|
|
669
|
+
var BROWSER_BASES = browserBasePaths();
|
|
670
|
+
var CHROME_BASE = BROWSER_BASES.chrome;
|
|
671
|
+
var CHROMIUM_BASE = BROWSER_BASES.chromium;
|
|
672
|
+
var EDGE_BASE = BROWSER_BASES.edge;
|
|
673
|
+
var BRAVE_BASE = BROWSER_BASES.brave;
|
|
674
|
+
var VIVALDI_BASE = BROWSER_BASES.vivaldi;
|
|
675
|
+
var OPERA_BASE = BROWSER_BASES.opera;
|
|
676
|
+
var CHROMIUM_SNAP_BASE = join2(HOME, "snap", "chromium", "common", "chromium");
|
|
677
|
+
var CHROMIUM_FLATPAK_BASE = join2(HOME, ".var", "app", "org.chromium.Chromium", "config", "chromium");
|
|
678
|
+
var CHROME_FLATPAK_BASE = join2(HOME, ".var", "app", "com.google.Chrome", "config", "google-chrome");
|
|
679
|
+
var BRAVE_FLATPAK_BASE = join2(HOME, ".var", "app", "com.brave.Browser", "config", "BraveSoftware", "Brave-Browser");
|
|
680
|
+
var EDGE_FLATPAK_BASE = join2(HOME, ".var", "app", "com.microsoft.Edge", "config", "microsoft-edge");
|
|
681
|
+
function firefoxProfileDirs() {
|
|
682
|
+
const bases = firefoxBaseDirs();
|
|
683
|
+
const dirs = [];
|
|
684
|
+
for (const base of bases) {
|
|
685
|
+
if (!existsSync2(base)) continue;
|
|
686
|
+
try {
|
|
687
|
+
for (const d of readdirSync(base)) {
|
|
688
|
+
const full = join2(base, d);
|
|
689
|
+
try {
|
|
690
|
+
if (statSync(full).isDirectory() && existsSync2(join2(full, "places.sqlite"))) {
|
|
691
|
+
dirs.push(full);
|
|
692
|
+
}
|
|
693
|
+
} catch {
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
} catch {
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return dirs;
|
|
700
|
+
}
|
|
701
|
+
async function scanAllBookmarks() {
|
|
702
|
+
const all = [];
|
|
703
|
+
for (const p of chromeLikePaths(CHROME_BASE)) all.push(...readChromeLike(p, "chrome"));
|
|
704
|
+
for (const p of chromeLikePaths(CHROMIUM_BASE)) all.push(...readChromeLike(p, "chromium"));
|
|
705
|
+
for (const p of chromeLikePaths(EDGE_BASE)) all.push(...readChromeLike(p, "edge"));
|
|
706
|
+
for (const p of chromeLikePaths(BRAVE_BASE)) all.push(...readChromeLike(p, "brave"));
|
|
707
|
+
for (const p of chromeLikePaths(VIVALDI_BASE)) all.push(...readChromeLike(p, "vivaldi"));
|
|
708
|
+
for (const p of chromeLikePaths(OPERA_BASE)) all.push(...readChromeLike(p, "opera"));
|
|
709
|
+
if (IS_LINUX2) {
|
|
710
|
+
for (const p of chromeLikePaths(CHROMIUM_SNAP_BASE)) all.push(...readChromeLike(p, "chromium-snap"));
|
|
711
|
+
for (const p of chromeLikePaths(CHROMIUM_FLATPAK_BASE)) all.push(...readChromeLike(p, "chromium-flatpak"));
|
|
712
|
+
for (const p of chromeLikePaths(CHROME_FLATPAK_BASE)) all.push(...readChromeLike(p, "chrome-flatpak"));
|
|
713
|
+
for (const p of chromeLikePaths(BRAVE_FLATPAK_BASE)) all.push(...readChromeLike(p, "brave-flatpak"));
|
|
714
|
+
for (const p of chromeLikePaths(EDGE_FLATPAK_BASE)) all.push(...readChromeLike(p, "edge-flatpak"));
|
|
715
|
+
}
|
|
716
|
+
for (const dir of firefoxProfileDirs()) {
|
|
717
|
+
all.push(...await readFirefoxBookmarks(dir));
|
|
718
|
+
}
|
|
719
|
+
const seen = /* @__PURE__ */ new Set();
|
|
720
|
+
return all.filter((h) => {
|
|
721
|
+
if (seen.has(h.hostname)) return false;
|
|
722
|
+
seen.add(h.hostname);
|
|
723
|
+
return true;
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
async function scanAllHistory() {
|
|
727
|
+
const all = [];
|
|
728
|
+
for (const p of chromeLikeHistoryPaths(CHROME_BASE)) all.push(...await readChromiumHistory(p, "chrome"));
|
|
729
|
+
for (const p of chromeLikeHistoryPaths(CHROMIUM_BASE)) all.push(...await readChromiumHistory(p, "chromium"));
|
|
730
|
+
for (const p of chromeLikeHistoryPaths(EDGE_BASE)) all.push(...await readChromiumHistory(p, "edge"));
|
|
731
|
+
for (const p of chromeLikeHistoryPaths(BRAVE_BASE)) all.push(...await readChromiumHistory(p, "brave"));
|
|
732
|
+
for (const p of chromeLikeHistoryPaths(VIVALDI_BASE)) all.push(...await readChromiumHistory(p, "vivaldi"));
|
|
733
|
+
for (const p of chromeLikeHistoryPaths(OPERA_BASE)) all.push(...await readChromiumHistory(p, "opera"));
|
|
734
|
+
if (IS_LINUX2) {
|
|
735
|
+
for (const p of chromeLikeHistoryPaths(CHROMIUM_SNAP_BASE)) all.push(...await readChromiumHistory(p, "chromium-snap"));
|
|
736
|
+
for (const p of chromeLikeHistoryPaths(CHROMIUM_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "chromium-flatpak"));
|
|
737
|
+
for (const p of chromeLikeHistoryPaths(CHROME_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "chrome-flatpak"));
|
|
738
|
+
for (const p of chromeLikeHistoryPaths(BRAVE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "brave-flatpak"));
|
|
739
|
+
for (const p of chromeLikeHistoryPaths(EDGE_FLATPAK_BASE)) all.push(...await readChromiumHistory(p, "edge-flatpak"));
|
|
740
|
+
}
|
|
741
|
+
for (const dir of firefoxProfileDirs()) {
|
|
742
|
+
all.push(...await readFirefoxHistory(dir));
|
|
743
|
+
}
|
|
744
|
+
const byHost = /* @__PURE__ */ new Map();
|
|
745
|
+
for (const h of all) {
|
|
746
|
+
const existing = byHost.get(h.hostname);
|
|
747
|
+
if (existing) {
|
|
748
|
+
existing.visitCount += h.visitCount;
|
|
749
|
+
} else {
|
|
750
|
+
byHost.set(h.hostname, { ...h });
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return [...byHost.values()].sort((a, b) => b.visitCount - a.visitCount);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
export {
|
|
757
|
+
checkReadOnly,
|
|
758
|
+
setVerbose,
|
|
759
|
+
logDebug,
|
|
760
|
+
logInfo,
|
|
761
|
+
logWarn,
|
|
762
|
+
logError,
|
|
763
|
+
PLATFORM,
|
|
764
|
+
IS_WIN,
|
|
765
|
+
IS_MAC,
|
|
766
|
+
IS_LINUX,
|
|
767
|
+
HOME,
|
|
768
|
+
run,
|
|
769
|
+
commandExists,
|
|
770
|
+
dbScanDirs,
|
|
771
|
+
findFiles,
|
|
772
|
+
scanListeningPorts,
|
|
773
|
+
scanWindowsPrograms,
|
|
774
|
+
scanWindowsDbServices,
|
|
775
|
+
cleanupTempFiles,
|
|
776
|
+
extractHost,
|
|
777
|
+
walkChrome,
|
|
778
|
+
readChromeLike,
|
|
779
|
+
readFirefoxHistory,
|
|
780
|
+
chromeLikePaths,
|
|
781
|
+
chromeLikeHistoryPaths,
|
|
782
|
+
scanAllBookmarks,
|
|
783
|
+
scanAllHistory
|
|
784
|
+
};
|
|
785
|
+
//# sourceMappingURL=chunk-CJ2PITFA.js.map
|