@hraness/wordcell 0.20.0-bootstrap.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/LICENSE +21 -0
- package/README.md +749 -0
- package/dist/agent-context.js +35 -0
- package/dist/agent-guide-audit.js +18 -0
- package/dist/attachments.js +19 -0
- package/dist/authoring.js +33 -0
- package/dist/benchmark.js +19 -0
- package/dist/capture.js +49 -0
- package/dist/cli.js +57 -0
- package/dist/clip/acquire.js +57 -0
- package/dist/clip/args.js +21 -0
- package/dist/clip/bounded-byte-buffer.js +9 -0
- package/dist/clip/browser-profiles.js +17 -0
- package/dist/clip/bundle-reader.js +11 -0
- package/dist/clip/cli.js +27 -0
- package/dist/clip/cookies.js +21 -0
- package/dist/clip/defuddle-worker.js +84 -0
- package/dist/clip/doctor.js +32 -0
- package/dist/clip/jobs.js +784 -0
- package/dist/clip/network-proxy.js +9 -0
- package/dist/clip/network.js +28 -0
- package/dist/clip/persist.js +30 -0
- package/dist/clip/refresh.js +11 -0
- package/dist/clip/terminal.js +11 -0
- package/dist/evaluation-builder.js +12238 -0
- package/dist/evaluation-kb.js +26 -0
- package/dist/evaluation.js +35 -0
- package/dist/git.js +39 -0
- package/dist/graph.js +41 -0
- package/dist/index-054mb7d3.js +1974 -0
- package/dist/index-06c9ctr6.js +738 -0
- package/dist/index-180zbkkt.js +2480 -0
- package/dist/index-1gwbassd.js +743 -0
- package/dist/index-1xxnjn0d.js +171 -0
- package/dist/index-23z4zxgg.js +119 -0
- package/dist/index-2gv8y733.js +432 -0
- package/dist/index-3ehtt59c.js +199 -0
- package/dist/index-3rm7cz6h.js +373 -0
- package/dist/index-48pz4jpc.js +392 -0
- package/dist/index-4j3tt0c3.js +234 -0
- package/dist/index-5n05se68.js +307 -0
- package/dist/index-5vwpzb5a.js +764 -0
- package/dist/index-6jcz0m1c.js +712 -0
- package/dist/index-6sw24nvv.js +1189 -0
- package/dist/index-8a08v6x8.js +56 -0
- package/dist/index-adx6khj5.js +488 -0
- package/dist/index-b88v3vtm.js +805 -0
- package/dist/index-bcknqxrq.js +1943 -0
- package/dist/index-bs0yf4pp.js +711 -0
- package/dist/index-by0pbant.js +827 -0
- package/dist/index-d13v9ckt.js +150 -0
- package/dist/index-dfag79p7.js +370 -0
- package/dist/index-e4fagfjz.js +44 -0
- package/dist/index-e5fbsywq.js +658 -0
- package/dist/index-ekpwvbra.js +1070 -0
- package/dist/index-f984hw45.js +927 -0
- package/dist/index-gh719d91.js +63 -0
- package/dist/index-h170byqw.js +371 -0
- package/dist/index-hgve9rh2.js +2046 -0
- package/dist/index-hya40gb2.js +474 -0
- package/dist/index-j4zgmzjr.js +152 -0
- package/dist/index-m7et4rz4.js +966 -0
- package/dist/index-mxxxytys.js +1254 -0
- package/dist/index-n05s3wsb.js +2728 -0
- package/dist/index-nd6nynv2.js +1162 -0
- package/dist/index-npg9z1a4.js +431 -0
- package/dist/index-pj501bh1.js +140 -0
- package/dist/index-rdd5f7jj.js +70 -0
- package/dist/index-sy0zety7.js +3630 -0
- package/dist/index-tkpxp48t.js +1166 -0
- package/dist/index-w2zc0vwa.js +571 -0
- package/dist/index-why54q5p.js +462 -0
- package/dist/index-x3fthpsc.js +585 -0
- package/dist/index-x6m57nfc.js +1041 -0
- package/dist/index.js +784 -0
- package/dist/kb-alias.js +55 -0
- package/dist/navigation.js +13 -0
- package/dist/pdf.js +85 -0
- package/dist/percolate.js +44 -0
- package/dist/portfolio.js +77 -0
- package/dist/query.js +29 -0
- package/dist/repository-memory.js +60 -0
- package/dist/sdk.js +36 -0
- package/dist/search-rules.js +34 -0
- package/dist/search.js +22 -0
- package/dist/semantic.js +39 -0
- package/dist/source-inbox.js +17 -0
- package/dist/untrusted-content.js +32 -0
- package/dist/url-intelligence.js +74 -0
- package/dist/workflow.js +23 -0
- package/dist/workflows/decision-context.js +20 -0
- package/dist/workflows/explain-change.js +8 -0
- package/dist/workflows/index.js +28 -0
- package/dist/workflows/plan-radar.js +10 -0
- package/package.json +421 -0
- package/skills/wordcell/AGENTS.md +22 -0
- package/skills/wordcell/SKILL.md +91 -0
- package/skills/wordcell/agents/openai.yaml +4 -0
- package/skills/wordcell/references/companion-skills.md +96 -0
- package/skills/wordcell/references/customize.md +123 -0
- package/skills/wordcell/references/pdf-review.md +51 -0
- package/skills/wordcell/references/percolate.md +176 -0
- package/skills/wordcell/references/plan-structure.md +105 -0
- package/skills/wordcell/references/plan.md +115 -0
- package/skills/wordcell/references/query.md +252 -0
- package/skills/wordcell/references/refresh.md +133 -0
- package/skills/wordcell/references/save-pdf.md +125 -0
- package/skills/wordcell/references/save-url.md +178 -0
- package/skills/wordcell/references/url-authentication.md +75 -0
- package/skills/wordcell/references/url-platforms.md +25 -0
- package/skills/wordcell/templates/companion-skill.template.md +57 -0
- package/src/agent-context.ts +1241 -0
- package/src/agent-guide-audit.ts +750 -0
- package/src/attachments.ts +723 -0
- package/src/authoring-model.ts +798 -0
- package/src/authoring-platform.ts +549 -0
- package/src/authoring-program.ts +278 -0
- package/src/authoring-runtime.ts +54 -0
- package/src/authoring.ts +75 -0
- package/src/benchmark.ts +362 -0
- package/src/capture.ts +68 -0
- package/src/cli-program.ts +3662 -0
- package/src/cli.ts +6 -0
- package/src/clip/acquire.ts +1273 -0
- package/src/clip/archive-today.ts +402 -0
- package/src/clip/args.ts +423 -0
- package/src/clip/assets.ts +262 -0
- package/src/clip/bounded-byte-buffer.ts +75 -0
- package/src/clip/browser-profiles.ts +372 -0
- package/src/clip/bundle-reader.ts +608 -0
- package/src/clip/capture.ts +1054 -0
- package/src/clip/cli.ts +181 -0
- package/src/clip/cookies.ts +512 -0
- package/src/clip/doctor.ts +1110 -0
- package/src/clip/extract.ts +868 -0
- package/src/clip/jobs.ts +959 -0
- package/src/clip/lib.ts +861 -0
- package/src/clip/media.ts +1474 -0
- package/src/clip/metadata-search-tool/Cargo.lock +2498 -0
- package/src/clip/metadata-search-tool/Cargo.toml +18 -0
- package/src/clip/metadata-search-tool/runner.ts +685 -0
- package/src/clip/metadata-search-tool/src/main.rs +389 -0
- package/src/clip/metadata-search.ts +687 -0
- package/src/clip/network-proxy.ts +627 -0
- package/src/clip/network.ts +950 -0
- package/src/clip/package-root.ts +54 -0
- package/src/clip/persist.ts +1472 -0
- package/src/clip/platforms.ts +1824 -0
- package/src/clip/refresh.ts +197 -0
- package/src/clip/structured.ts +432 -0
- package/src/clip/terminal.ts +197 -0
- package/src/clip/url-intelligence.ts +581 -0
- package/src/clip/url-metadata-backfill.ts +616 -0
- package/src/clip/url-metadata-cli.ts +251 -0
- package/src/clip/url-metadata.ts +1397 -0
- package/src/evaluation-analysis-v2.ts +1440 -0
- package/src/evaluation-builder.ts +2539 -0
- package/src/evaluation-corpus-authoring.ts +2052 -0
- package/src/evaluation-evidence.ts +1147 -0
- package/src/evaluation-execution-v2.ts +426 -0
- package/src/evaluation-implementation.ts +131 -0
- package/src/evaluation-kb-closure.ts +1430 -0
- package/src/evaluation-kb-runner-v2.ts +735 -0
- package/src/evaluation-kb-v2.ts +2567 -0
- package/src/evaluation-kb.ts +1018 -0
- package/src/evaluation-measurement-v2.ts +1462 -0
- package/src/evaluation-packing-v2.ts +452 -0
- package/src/evaluation-redaction.ts +28 -0
- package/src/evaluation-v2.ts +3857 -0
- package/src/evaluation.ts +1220 -0
- package/src/git.ts +1276 -0
- package/src/graph.ts +1494 -0
- package/src/index.ts +21 -0
- package/src/init.ts +123 -0
- package/src/kb-alias.ts +14 -0
- package/src/navigation.ts +277 -0
- package/src/note-lock.ts +529 -0
- package/src/oh-adoption.ts +444 -0
- package/src/pdf/args.ts +202 -0
- package/src/pdf/capture.ts +298 -0
- package/src/pdf/cli.ts +159 -0
- package/src/pdf/extract.ts +303 -0
- package/src/pdf/layout.ts +618 -0
- package/src/pdf/markdown.ts +154 -0
- package/src/pdf/model.ts +234 -0
- package/src/pdf/ocr.ts +190 -0
- package/src/pdf/persist.ts +314 -0
- package/src/pdf/source.ts +135 -0
- package/src/pdf/tools.ts +146 -0
- package/src/pdf.ts +92 -0
- package/src/percolate.ts +1948 -0
- package/src/portfolio-audit.ts +574 -0
- package/src/portfolio-identity.ts +162 -0
- package/src/portfolio-registry.ts +473 -0
- package/src/portfolio.ts +765 -0
- package/src/query.ts +646 -0
- package/src/repository-memory.ts +1150 -0
- package/src/sdk.ts +1452 -0
- package/src/search-rules.ts +712 -0
- package/src/search.ts +710 -0
- package/src/semantic-runtime.ts +1139 -0
- package/src/semantic.ts +2480 -0
- package/src/source-inbox.ts +232 -0
- package/src/untrusted-content.ts +401 -0
- package/src/url-intelligence.ts +104 -0
- package/src/vault.ts +636 -0
- package/src/workflow-model.ts +444 -0
- package/src/workflow-platform.ts +74 -0
- package/src/workflow-program.ts +183 -0
- package/src/workflow-runtime.ts +51 -0
- package/src/workflow.ts +23 -0
- package/src/workflows/decision-context.ts +81 -0
- package/src/workflows/explain-change.ts +73 -0
- package/src/workflows/index.ts +3 -0
- package/src/workflows/plan-radar.ts +101 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/navigation.ts
|
|
3
|
+
var MAX_NAVIGATION_INDEXED_CONNECTIONS = 1e5;
|
|
4
|
+
var MAX_NAVIGATION_RETURNED_CONNECTIONS = 1e4;
|
|
5
|
+
|
|
6
|
+
class NavigationBudgetError extends RangeError {
|
|
7
|
+
kind;
|
|
8
|
+
limit;
|
|
9
|
+
constructor(kind, limit, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "NavigationBudgetError";
|
|
12
|
+
this.kind = kind;
|
|
13
|
+
this.limit = limit;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function checkedDepth(value) {
|
|
17
|
+
const depth = value ?? 1;
|
|
18
|
+
if (!Number.isSafeInteger(depth) || depth < 1 || depth > 10) {
|
|
19
|
+
throw new RangeError("Link depth must be an integer from 1 through 10.");
|
|
20
|
+
}
|
|
21
|
+
return depth;
|
|
22
|
+
}
|
|
23
|
+
function checkedLimit(value) {
|
|
24
|
+
const limit = value ?? 50;
|
|
25
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1000) {
|
|
26
|
+
throw new RangeError("Link result limit must be an integer from 1 through 1000.");
|
|
27
|
+
}
|
|
28
|
+
return limit;
|
|
29
|
+
}
|
|
30
|
+
function connectionNode(note, connection, distance) {
|
|
31
|
+
return {
|
|
32
|
+
id: note.id,
|
|
33
|
+
path: note.path,
|
|
34
|
+
title: note.title,
|
|
35
|
+
distance,
|
|
36
|
+
inboundContextualCount: connection?.inboundContextualCount ?? 0,
|
|
37
|
+
outboundContextualCount: connection?.outboundContextualCount ?? 0,
|
|
38
|
+
inboundRelationCount: connection?.inboundRelationCount ?? 0,
|
|
39
|
+
outboundRelationCount: connection?.outboundRelationCount ?? 0
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function edgeKey(edge) {
|
|
43
|
+
return `${edge.source}\x00${edge.target}\x00${edge.line}`;
|
|
44
|
+
}
|
|
45
|
+
function relationKey(relation) {
|
|
46
|
+
return `${relation.source}\x00${relation.predicate}\x00${relation.target}`;
|
|
47
|
+
}
|
|
48
|
+
function compareTraversalCandidates(left, right) {
|
|
49
|
+
return left.source.localeCompare(right.source) || left.target.localeCompare(right.target) || left.kind.localeCompare(right.kind) || (left.kind === "relation" && right.kind === "relation" ? left.relation.predicate.localeCompare(right.relation.predicate) : 0) || left.line - right.line;
|
|
50
|
+
}
|
|
51
|
+
function addCandidate(candidates, path, candidate) {
|
|
52
|
+
const existing = candidates.get(path) ?? [];
|
|
53
|
+
existing.push(candidate);
|
|
54
|
+
candidates.set(path, existing);
|
|
55
|
+
}
|
|
56
|
+
function candidateKey(candidate) {
|
|
57
|
+
return candidate.kind === "link" ? `link\x00${edgeKey(candidate.edge)}` : `relation\x00${relationKey(candidate.relation)}`;
|
|
58
|
+
}
|
|
59
|
+
function checkedConnections(analysis) {
|
|
60
|
+
const authoredRelations = analysis.authoredRelations ?? [];
|
|
61
|
+
const connectionCount = analysis.contextualLinks.length + authoredRelations.length;
|
|
62
|
+
if (connectionCount > MAX_NAVIGATION_INDEXED_CONNECTIONS) {
|
|
63
|
+
throw new NavigationBudgetError("connection-work-limit", MAX_NAVIGATION_INDEXED_CONNECTIONS, `Link navigation exceeds the ${MAX_NAVIGATION_INDEXED_CONNECTIONS} ` + "contextual-link and authored-relation observation limit.");
|
|
64
|
+
}
|
|
65
|
+
return authoredRelations;
|
|
66
|
+
}
|
|
67
|
+
function returnedConnectionLimit(nodeLimit) {
|
|
68
|
+
return Math.min(MAX_NAVIGATION_RETURNED_CONNECTIONS, nodeLimit ** 2);
|
|
69
|
+
}
|
|
70
|
+
function navigateLinks(notes, analysis, start, options = {}) {
|
|
71
|
+
const direction = options.direction ?? "both";
|
|
72
|
+
const depth = checkedDepth(options.depth);
|
|
73
|
+
const limit = checkedLimit(options.limit);
|
|
74
|
+
const authoredRelations = checkedConnections(analysis);
|
|
75
|
+
const notesByPath = new Map(notes.map((note) => [note.path, note]));
|
|
76
|
+
const notesById = new Map(notes.map((note) => [note.id, note]));
|
|
77
|
+
const connectionsById = new Map(analysis.noteConnections.map((connection) => [connection.id, connection]));
|
|
78
|
+
const inbound = new Map;
|
|
79
|
+
const outbound = new Map;
|
|
80
|
+
for (const edge of analysis.contextualLinks) {
|
|
81
|
+
const candidate = {
|
|
82
|
+
kind: "link",
|
|
83
|
+
source: edge.source,
|
|
84
|
+
target: edge.target,
|
|
85
|
+
line: edge.line,
|
|
86
|
+
edge
|
|
87
|
+
};
|
|
88
|
+
addCandidate(inbound, edge.target, candidate);
|
|
89
|
+
addCandidate(outbound, edge.source, candidate);
|
|
90
|
+
}
|
|
91
|
+
for (const relation of authoredRelations) {
|
|
92
|
+
const source = notesById.get(relation.source)?.path;
|
|
93
|
+
const target = notesById.get(relation.target)?.path;
|
|
94
|
+
if (source === undefined || target === undefined)
|
|
95
|
+
continue;
|
|
96
|
+
const candidate = {
|
|
97
|
+
kind: "relation",
|
|
98
|
+
source,
|
|
99
|
+
target,
|
|
100
|
+
line: relation.provenance.line,
|
|
101
|
+
relation
|
|
102
|
+
};
|
|
103
|
+
addCandidate(inbound, target, candidate);
|
|
104
|
+
addCandidate(outbound, source, candidate);
|
|
105
|
+
}
|
|
106
|
+
const distanceByPath = new Map([[start.path, 0]]);
|
|
107
|
+
let frontier = [start.path];
|
|
108
|
+
let truncated = false;
|
|
109
|
+
const selectedCandidates = new Map;
|
|
110
|
+
for (let distance = 0;distance < depth && frontier.length > 0; distance += 1) {
|
|
111
|
+
const next = new Set;
|
|
112
|
+
for (const path of frontier.toSorted()) {
|
|
113
|
+
const candidates = [
|
|
114
|
+
...direction === "out" || direction === "both" ? outbound.get(path) ?? [] : [],
|
|
115
|
+
...direction === "in" || direction === "both" ? inbound.get(path) ?? [] : []
|
|
116
|
+
].toSorted(compareTraversalCandidates);
|
|
117
|
+
for (const candidate of candidates) {
|
|
118
|
+
const neighborPath = candidate.source === path ? candidate.target : candidate.source;
|
|
119
|
+
if (!notesByPath.has(neighborPath))
|
|
120
|
+
continue;
|
|
121
|
+
if (distanceByPath.has(neighborPath)) {
|
|
122
|
+
selectedCandidates.set(candidateKey(candidate), candidate);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (distanceByPath.size >= limit) {
|
|
126
|
+
truncated = true;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
selectedCandidates.set(candidateKey(candidate), candidate);
|
|
130
|
+
distanceByPath.set(neighborPath, distance + 1);
|
|
131
|
+
next.add(neighborPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
frontier = [...next];
|
|
135
|
+
}
|
|
136
|
+
const nodes = [...distanceByPath].map(([path, distance]) => {
|
|
137
|
+
const note = notesByPath.get(path);
|
|
138
|
+
return note === undefined ? null : connectionNode(note, connectionsById.get(note.id), distance);
|
|
139
|
+
}).filter((node) => node !== null).toSorted((left, right) => left.distance - right.distance || left.path.localeCompare(right.path));
|
|
140
|
+
const sortedCandidates = [...selectedCandidates.values()].toSorted(compareTraversalCandidates);
|
|
141
|
+
const connectionLimit = returnedConnectionLimit(limit);
|
|
142
|
+
if (sortedCandidates.length > connectionLimit)
|
|
143
|
+
truncated = true;
|
|
144
|
+
const returnedCandidates = sortedCandidates.slice(0, connectionLimit);
|
|
145
|
+
const edges = returnedCandidates.filter((candidate) => candidate.kind === "link").map(({ edge }) => edge).toSorted((left, right) => left.source.localeCompare(right.source) || left.target.localeCompare(right.target) || left.line - right.line);
|
|
146
|
+
const relations = returnedCandidates.filter((candidate) => candidate.kind === "relation").map(({ relation }) => relation).toSorted((left, right) => left.source.localeCompare(right.source) || left.predicate.localeCompare(right.predicate) || left.target.localeCompare(right.target) || left.provenance.line - right.provenance.line);
|
|
147
|
+
return { note: start.path, direction, depth, limit, truncated, nodes, edges, relations };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { MAX_NAVIGATION_INDEXED_CONNECTIONS, MAX_NAVIGATION_RETURNED_CONNECTIONS, NavigationBudgetError, navigateLinks };
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/clip/args.ts
|
|
3
|
+
var captureModes = ["auto", "http", "browser", "file"];
|
|
4
|
+
var captureScopes = ["auto", "page", "thread", "comments"];
|
|
5
|
+
var mediaModes = ["none", "images", "all"];
|
|
6
|
+
var evidenceModes = ["none", "source", "screenshot", "all"];
|
|
7
|
+
var cookieSources = ["chrome", "arc", "brave", "chromium", "edge", "firefox", "safari"];
|
|
8
|
+
function captureUrl(options) {
|
|
9
|
+
if (options.url === null)
|
|
10
|
+
throw new Error("the current browser target has not resolved its URL yet");
|
|
11
|
+
return options.url;
|
|
12
|
+
}
|
|
13
|
+
var DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
|
|
14
|
+
var defaults = {
|
|
15
|
+
timeoutMs: 30000,
|
|
16
|
+
maxItems: 500,
|
|
17
|
+
maxDepth: 16,
|
|
18
|
+
maxHtmlBytes: 25 * 1024 * 1024,
|
|
19
|
+
maxAssetBytes: 100 * 1024 * 1024,
|
|
20
|
+
maxTotalAssetBytes: 500 * 1024 * 1024
|
|
21
|
+
};
|
|
22
|
+
var valueOptions = new Set([
|
|
23
|
+
"--mode",
|
|
24
|
+
"--scope",
|
|
25
|
+
"--media",
|
|
26
|
+
"--evidence",
|
|
27
|
+
"--html",
|
|
28
|
+
"--output",
|
|
29
|
+
"--browser-profile",
|
|
30
|
+
"--cdp",
|
|
31
|
+
"--cookie-profile",
|
|
32
|
+
"--cookies-file",
|
|
33
|
+
"--user-agent",
|
|
34
|
+
"--cookie-source",
|
|
35
|
+
"--timeout-ms",
|
|
36
|
+
"--max-items",
|
|
37
|
+
"--max-depth",
|
|
38
|
+
"--max-html-bytes",
|
|
39
|
+
"--max-asset-bytes",
|
|
40
|
+
"--max-total-asset-bytes"
|
|
41
|
+
]);
|
|
42
|
+
function enumValue(value, values, label) {
|
|
43
|
+
const match = values.find((candidate) => candidate === value);
|
|
44
|
+
return match === undefined ? { ok: false, message: `${label} must be one of ${values.join(", ")}` } : { ok: true, value: match };
|
|
45
|
+
}
|
|
46
|
+
function positiveInteger(value, label, maximum) {
|
|
47
|
+
if (!/^\d+$/.test(value))
|
|
48
|
+
return `${label} must be a positive integer`;
|
|
49
|
+
const parsed = Number(value);
|
|
50
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > maximum) {
|
|
51
|
+
return `${label} must be between 1 and ${maximum}`;
|
|
52
|
+
}
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
function byteSize(value, label) {
|
|
56
|
+
const match = /^(\d+)(b|kb|mb|gb)?$/i.exec(value);
|
|
57
|
+
if (match === null || match[1] === undefined) {
|
|
58
|
+
return `${label} must be an integer byte size such as 500000, 25mb, or 1gb`;
|
|
59
|
+
}
|
|
60
|
+
const amount = Number(match[1]);
|
|
61
|
+
const unit = (match[2] ?? "b").toLowerCase();
|
|
62
|
+
const multiplier = unit === "gb" ? 1024 ** 3 : unit === "mb" ? 1024 ** 2 : unit === "kb" ? 1024 : 1;
|
|
63
|
+
const parsed = amount * multiplier;
|
|
64
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 8 * 1024 ** 3) {
|
|
65
|
+
return `${label} must be between 1 byte and 8gb`;
|
|
66
|
+
}
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
function readOptionValue(args, index, flag) {
|
|
70
|
+
const value = args[index + 1];
|
|
71
|
+
return value === undefined || value.startsWith("--") ? { ok: false, message: `${flag} requires a value` } : value;
|
|
72
|
+
}
|
|
73
|
+
function parseUrl(value, label = "URL") {
|
|
74
|
+
if (value.length > 64 * 1024)
|
|
75
|
+
return `${label} exceeds the 65536 code-unit safety limit`;
|
|
76
|
+
try {
|
|
77
|
+
const url = new URL(value);
|
|
78
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
79
|
+
return `${label} must use http or https`;
|
|
80
|
+
if (url.username !== "" || url.password !== "") {
|
|
81
|
+
return `${label} must not contain embedded credentials; use --cookies-file or a browser session`;
|
|
82
|
+
}
|
|
83
|
+
return url;
|
|
84
|
+
} catch {
|
|
85
|
+
return `${label} is not a valid URL`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function parseArguments(rawArgs, environment = {}) {
|
|
89
|
+
if (rawArgs.length === 0 || rawArgs[0] === "help" || rawArgs[0] === "--help" || rawArgs[0] === "-h") {
|
|
90
|
+
return { ok: true, value: { command: "help" } };
|
|
91
|
+
}
|
|
92
|
+
const first = rawArgs[0];
|
|
93
|
+
if (first === "doctor" || first === "adapters") {
|
|
94
|
+
const extra = rawArgs.slice(1);
|
|
95
|
+
if (extra.some((value) => value !== "--json")) {
|
|
96
|
+
return { ok: false, message: `${first} only accepts --json` };
|
|
97
|
+
}
|
|
98
|
+
return { ok: true, value: { command: first, json: extra.includes("--json") } };
|
|
99
|
+
}
|
|
100
|
+
let command = "capture";
|
|
101
|
+
let cursor = 0;
|
|
102
|
+
if (first === "capture" || first === "inspect") {
|
|
103
|
+
command = first;
|
|
104
|
+
cursor += 1;
|
|
105
|
+
}
|
|
106
|
+
const positional = [];
|
|
107
|
+
let mode = "auto";
|
|
108
|
+
let scope = "auto";
|
|
109
|
+
let media = command === "inspect" ? "none" : "images";
|
|
110
|
+
let evidence = "none";
|
|
111
|
+
let mediaExplicit = false;
|
|
112
|
+
let evidenceExplicit = false;
|
|
113
|
+
let htmlFile;
|
|
114
|
+
let outputBase = environment.KB_CLIP_OUTPUT ?? "kb/articles";
|
|
115
|
+
let force = false;
|
|
116
|
+
let stdout = command === "inspect";
|
|
117
|
+
let stdoutExplicit = false;
|
|
118
|
+
let json = false;
|
|
119
|
+
let quiet = false;
|
|
120
|
+
let browserProfile;
|
|
121
|
+
let browserLive = false;
|
|
122
|
+
let cdp;
|
|
123
|
+
const selectedCookieSources = [];
|
|
124
|
+
let cookieProfile;
|
|
125
|
+
let cookiesFile;
|
|
126
|
+
let timeoutMs = defaults.timeoutMs;
|
|
127
|
+
let maxItems = defaults.maxItems;
|
|
128
|
+
let maxDepth = defaults.maxDepth;
|
|
129
|
+
let maxHtmlBytes = defaults.maxHtmlBytes;
|
|
130
|
+
let maxAssetBytes = defaults.maxAssetBytes;
|
|
131
|
+
let maxTotalAssetBytes = defaults.maxTotalAssetBytes;
|
|
132
|
+
let allowPrivateNetwork = false;
|
|
133
|
+
let userAgent = environment.KB_CLIP_USER_AGENT ?? DEFAULT_USER_AGENT;
|
|
134
|
+
for (;cursor < rawArgs.length; cursor += 1) {
|
|
135
|
+
const argument = rawArgs[cursor];
|
|
136
|
+
if (argument === undefined)
|
|
137
|
+
continue;
|
|
138
|
+
if (!argument.startsWith("--")) {
|
|
139
|
+
positional.push(argument);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (argument === "--force")
|
|
143
|
+
force = true;
|
|
144
|
+
else if (argument === "--stdout") {
|
|
145
|
+
stdout = true;
|
|
146
|
+
stdoutExplicit = true;
|
|
147
|
+
} else if (argument === "--json")
|
|
148
|
+
json = true;
|
|
149
|
+
else if (argument === "--quiet")
|
|
150
|
+
quiet = true;
|
|
151
|
+
else if (argument === "--browser-live")
|
|
152
|
+
browserLive = true;
|
|
153
|
+
else if (argument === "--allow-private-network")
|
|
154
|
+
allowPrivateNetwork = true;
|
|
155
|
+
else {
|
|
156
|
+
if (!valueOptions.has(argument))
|
|
157
|
+
return { ok: false, message: `unknown option: ${argument}` };
|
|
158
|
+
const value = readOptionValue(rawArgs, cursor, argument);
|
|
159
|
+
if (typeof value !== "string")
|
|
160
|
+
return value;
|
|
161
|
+
cursor += 1;
|
|
162
|
+
if (argument === "--mode") {
|
|
163
|
+
const parsed = enumValue(value, captureModes, "--mode");
|
|
164
|
+
if (!parsed.ok)
|
|
165
|
+
return { ok: false, message: parsed.message };
|
|
166
|
+
mode = parsed.value;
|
|
167
|
+
} else if (argument === "--scope") {
|
|
168
|
+
const parsed = enumValue(value, captureScopes, "--scope");
|
|
169
|
+
if (!parsed.ok)
|
|
170
|
+
return { ok: false, message: parsed.message };
|
|
171
|
+
scope = parsed.value;
|
|
172
|
+
} else if (argument === "--media") {
|
|
173
|
+
const parsed = enumValue(value, mediaModes, "--media");
|
|
174
|
+
if (!parsed.ok)
|
|
175
|
+
return { ok: false, message: parsed.message };
|
|
176
|
+
media = parsed.value;
|
|
177
|
+
mediaExplicit = true;
|
|
178
|
+
} else if (argument === "--evidence") {
|
|
179
|
+
const parsed = enumValue(value, evidenceModes, "--evidence");
|
|
180
|
+
if (!parsed.ok)
|
|
181
|
+
return { ok: false, message: parsed.message };
|
|
182
|
+
evidence = parsed.value;
|
|
183
|
+
evidenceExplicit = true;
|
|
184
|
+
} else if (argument === "--html")
|
|
185
|
+
htmlFile = value;
|
|
186
|
+
else if (argument === "--output")
|
|
187
|
+
outputBase = value;
|
|
188
|
+
else if (argument === "--browser-profile")
|
|
189
|
+
browserProfile = value;
|
|
190
|
+
else if (argument === "--cdp") {
|
|
191
|
+
const parsed = positiveInteger(value, "--cdp", 65535);
|
|
192
|
+
if (typeof parsed === "string") {
|
|
193
|
+
return { ok: false, message: "--cdp accepts only a local remote-debugging port between 1 and 65535" };
|
|
194
|
+
}
|
|
195
|
+
cdp = String(parsed);
|
|
196
|
+
} else if (argument === "--cookie-profile")
|
|
197
|
+
cookieProfile = value;
|
|
198
|
+
else if (argument === "--cookies-file")
|
|
199
|
+
cookiesFile = value;
|
|
200
|
+
else if (argument === "--user-agent")
|
|
201
|
+
userAgent = value;
|
|
202
|
+
else if (argument === "--cookie-source") {
|
|
203
|
+
const parsed = enumValue(value, cookieSources, "--cookie-source");
|
|
204
|
+
if (!parsed.ok)
|
|
205
|
+
return { ok: false, message: parsed.message };
|
|
206
|
+
selectedCookieSources.push(parsed.value);
|
|
207
|
+
} else if (argument === "--timeout-ms") {
|
|
208
|
+
const parsed = positiveInteger(value, argument, 10 * 60000);
|
|
209
|
+
if (typeof parsed === "string")
|
|
210
|
+
return { ok: false, message: parsed };
|
|
211
|
+
timeoutMs = parsed;
|
|
212
|
+
} else if (argument === "--max-items") {
|
|
213
|
+
const parsed = positiveInteger(value, argument, 1e4);
|
|
214
|
+
if (typeof parsed === "string")
|
|
215
|
+
return { ok: false, message: parsed };
|
|
216
|
+
maxItems = parsed;
|
|
217
|
+
} else if (argument === "--max-depth") {
|
|
218
|
+
const parsed = positiveInteger(value, argument, 64);
|
|
219
|
+
if (typeof parsed === "string")
|
|
220
|
+
return { ok: false, message: parsed };
|
|
221
|
+
maxDepth = parsed;
|
|
222
|
+
} else if (argument === "--max-html-bytes") {
|
|
223
|
+
const parsed = byteSize(value, argument);
|
|
224
|
+
if (typeof parsed === "string")
|
|
225
|
+
return { ok: false, message: parsed };
|
|
226
|
+
maxHtmlBytes = parsed;
|
|
227
|
+
} else if (argument === "--max-asset-bytes") {
|
|
228
|
+
const parsed = byteSize(value, argument);
|
|
229
|
+
if (typeof parsed === "string")
|
|
230
|
+
return { ok: false, message: parsed };
|
|
231
|
+
maxAssetBytes = parsed;
|
|
232
|
+
} else if (argument === "--max-total-asset-bytes") {
|
|
233
|
+
const parsed = byteSize(value, argument);
|
|
234
|
+
if (typeof parsed === "string")
|
|
235
|
+
return { ok: false, message: parsed };
|
|
236
|
+
maxTotalAssetBytes = parsed;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (positional.length === 0)
|
|
241
|
+
return { ok: false, message: `${command} requires a URL or current` };
|
|
242
|
+
if (positional.length > 2)
|
|
243
|
+
return { ok: false, message: `${command} accepts one URL/current target and one optional slug` };
|
|
244
|
+
const currentTab = positional[0] === "current";
|
|
245
|
+
const parsedUrl = currentTab ? null : parseUrl(positional[0] ?? "");
|
|
246
|
+
if (typeof parsedUrl === "string")
|
|
247
|
+
return { ok: false, message: parsedUrl };
|
|
248
|
+
if (mode === "file" && htmlFile === undefined)
|
|
249
|
+
return { ok: false, message: "--mode file requires --html <path|->" };
|
|
250
|
+
if (htmlFile !== undefined && mode !== "auto" && mode !== "file") {
|
|
251
|
+
return { ok: false, message: "--html can only be used with --mode auto or --mode file" };
|
|
252
|
+
}
|
|
253
|
+
if (browserLive && browserProfile !== undefined) {
|
|
254
|
+
return { ok: false, message: "--browser-live and --browser-profile are mutually exclusive" };
|
|
255
|
+
}
|
|
256
|
+
if (cdp !== undefined && (browserLive || browserProfile !== undefined)) {
|
|
257
|
+
return { ok: false, message: "--cdp cannot be combined with --browser-live or --browser-profile" };
|
|
258
|
+
}
|
|
259
|
+
if (currentTab && browserProfile !== undefined) {
|
|
260
|
+
return { ok: false, message: "the current target attaches with --browser-live or --cdp; it cannot use --browser-profile" };
|
|
261
|
+
}
|
|
262
|
+
if (currentTab && !browserLive && cdp === undefined) {
|
|
263
|
+
return { ok: false, message: "the current target requires --browser-live or --cdp <loopback-port>" };
|
|
264
|
+
}
|
|
265
|
+
const hasBrowserSelection = browserLive || cdp !== undefined || browserProfile !== undefined;
|
|
266
|
+
if (hasBrowserSelection && (mode === "http" || mode === "file" || htmlFile !== undefined)) {
|
|
267
|
+
return { ok: false, message: "browser selection requires --mode auto or --mode browser and cannot be combined with --html" };
|
|
268
|
+
}
|
|
269
|
+
if ((evidence === "screenshot" || evidence === "all") && (mode === "http" || mode === "file" || htmlFile !== undefined)) {
|
|
270
|
+
return { ok: false, message: "screenshot evidence requires --mode auto or --mode browser" };
|
|
271
|
+
}
|
|
272
|
+
if (selectedCookieSources.length > 1) {
|
|
273
|
+
return { ok: false, message: "select at most one --cookie-source so profile and media behavior stay unambiguous" };
|
|
274
|
+
}
|
|
275
|
+
if (selectedCookieSources.length > 0 && cookiesFile !== undefined) {
|
|
276
|
+
return { ok: false, message: "--cookie-source and --cookies-file are mutually exclusive authentication sources" };
|
|
277
|
+
}
|
|
278
|
+
if (cookieProfile !== undefined && selectedCookieSources.length === 0) {
|
|
279
|
+
return { ok: false, message: "--cookie-profile requires at least one --cookie-source" };
|
|
280
|
+
}
|
|
281
|
+
if (maxTotalAssetBytes < maxAssetBytes) {
|
|
282
|
+
return { ok: false, message: "--max-total-asset-bytes cannot be smaller than --max-asset-bytes" };
|
|
283
|
+
}
|
|
284
|
+
if (stdoutExplicit && json)
|
|
285
|
+
return { ok: false, message: "--stdout and --json cannot be combined" };
|
|
286
|
+
if (stdout && force)
|
|
287
|
+
return { ok: false, message: "--stdout and --force cannot be combined" };
|
|
288
|
+
if (command === "inspect" && media !== "none") {
|
|
289
|
+
return { ok: false, message: "inspect does not persist media; use capture or pass --media none" };
|
|
290
|
+
}
|
|
291
|
+
if (command === "inspect" && evidence !== "none") {
|
|
292
|
+
return { ok: false, message: "inspect does not persist evidence; use capture or pass --evidence none" };
|
|
293
|
+
}
|
|
294
|
+
if (stdout && mediaExplicit && media !== "none") {
|
|
295
|
+
return { ok: false, message: "--stdout does not persist media; use capture without --stdout or pass --media none" };
|
|
296
|
+
}
|
|
297
|
+
if (stdout && evidenceExplicit && evidence !== "none") {
|
|
298
|
+
return { ok: false, message: "--stdout does not persist evidence; use capture without --stdout or pass --evidence none" };
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
ok: true,
|
|
302
|
+
value: {
|
|
303
|
+
command,
|
|
304
|
+
url: parsedUrl,
|
|
305
|
+
currentTab,
|
|
306
|
+
slug: positional[1],
|
|
307
|
+
mode: htmlFile === undefined ? currentTab ? "browser" : mode : "file",
|
|
308
|
+
scope,
|
|
309
|
+
media: stdout ? "none" : media,
|
|
310
|
+
evidence: stdout ? "none" : evidence,
|
|
311
|
+
htmlFile,
|
|
312
|
+
outputBase,
|
|
313
|
+
force,
|
|
314
|
+
stdout,
|
|
315
|
+
json,
|
|
316
|
+
quiet,
|
|
317
|
+
browserProfile,
|
|
318
|
+
browserLive,
|
|
319
|
+
cdp,
|
|
320
|
+
cookieSources: selectedCookieSources,
|
|
321
|
+
cookieProfile,
|
|
322
|
+
cookiesFile,
|
|
323
|
+
timeoutMs,
|
|
324
|
+
maxItems,
|
|
325
|
+
maxDepth,
|
|
326
|
+
maxHtmlBytes,
|
|
327
|
+
maxAssetBytes,
|
|
328
|
+
maxTotalAssetBytes,
|
|
329
|
+
allowPrivateNetwork,
|
|
330
|
+
userAgent
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
var usage = `Usage:
|
|
335
|
+
wordcell clip <url> [slug] [options]
|
|
336
|
+
wordcell clip current [slug] --browser-live [options]
|
|
337
|
+
wordcell clip current [slug] --cdp <loopback-port> [options]
|
|
338
|
+
wordcell clip capture <url> [slug] [options]
|
|
339
|
+
wordcell clip inspect <url> [options]
|
|
340
|
+
wordcell doctor [--json]
|
|
341
|
+
wordcell adapters [--json]
|
|
342
|
+
|
|
343
|
+
Capture options:
|
|
344
|
+
--mode auto|http|browser|file Acquisition strategy (default: auto)
|
|
345
|
+
--scope auto|page|thread|comments Content scope (default: platform-aware)
|
|
346
|
+
--html <path|-> Parse saved/rendered HTML; - reads stdin
|
|
347
|
+
--browser-profile <name|path> Use a signed-in or persistent Chrome profile
|
|
348
|
+
--browser-live Attach to a live Chrome session
|
|
349
|
+
--cdp <loopback-port> Attach to a local CDP-capable browser
|
|
350
|
+
--cookie-source <browser> chrome|arc|brave|chromium|edge|firefox|safari
|
|
351
|
+
--cookie-profile <name|path> Browser profile; Safari expects a Cookies.binarycookies path
|
|
352
|
+
--cookies-file <path> Cookie-Editor JSON/base64, Netscape, Cookie header, or cURL input
|
|
353
|
+
--media none|images|all Localize images or all supported media
|
|
354
|
+
--evidence none|source|screenshot|all
|
|
355
|
+
--output <directory> Output base (default: kb/articles)
|
|
356
|
+
--stdout Print Markdown without writing a clip
|
|
357
|
+
--json Print a machine-readable result summary
|
|
358
|
+
--force Atomically replace an existing clip
|
|
359
|
+
--timeout-ms <n> Per-request/process/extraction timeout
|
|
360
|
+
--max-items <n> Bound comments/thread items (default: 500)
|
|
361
|
+
--max-depth <n> Bound nested replies (default: 16)
|
|
362
|
+
--max-html-bytes <size> HTML cap (default: 25mb)
|
|
363
|
+
--max-asset-bytes <size> Per-asset cap (default: 100mb)
|
|
364
|
+
--max-total-asset-bytes <size> Total asset cap (default: 500mb)
|
|
365
|
+
--allow-private-network Permit private targets in every network lane
|
|
366
|
+
--user-agent <value> Override the browser-like user agent
|
|
367
|
+
--quiet Suppress progress output
|
|
368
|
+
`;
|
|
369
|
+
|
|
370
|
+
export { captureModes, captureScopes, mediaModes, evidenceModes, cookieSources, captureUrl, parseArguments, usage };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
defineWorkflow
|
|
4
|
+
} from "./index-h170byqw.js";
|
|
5
|
+
|
|
6
|
+
// src/workflows/explain-change.ts
|
|
7
|
+
var explainChangeWorkflow = defineWorkflow({
|
|
8
|
+
id: "explain-change",
|
|
9
|
+
nodes: [
|
|
10
|
+
{
|
|
11
|
+
id: "rationale",
|
|
12
|
+
resource: "qmd",
|
|
13
|
+
run: ({ input, kb }) => kb.search({
|
|
14
|
+
query: input.query,
|
|
15
|
+
history: false,
|
|
16
|
+
...input.resultLimit === undefined ? {} : { limit: input.resultLimit }
|
|
17
|
+
})
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "evolution",
|
|
21
|
+
resource: "git",
|
|
22
|
+
run: ({ input, kb }) => kb.searchHistory({
|
|
23
|
+
query: input.historyQuery ?? input.query,
|
|
24
|
+
...input.historyLimit === undefined ? {} : { limit: input.historyLimit }
|
|
25
|
+
})
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "neighborhood",
|
|
29
|
+
run: ({ input, kb }) => input.note === undefined ? null : kb.links(input.note, { direction: "both", depth: 1, limit: 20 })
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "assemble",
|
|
33
|
+
needs: ["rationale", "evolution", "neighborhood"],
|
|
34
|
+
run: ({ result }) => ({
|
|
35
|
+
rationale: result("rationale"),
|
|
36
|
+
evolution: result("evolution"),
|
|
37
|
+
neighborhood: result("neighborhood")
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
output: "assemble"
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export { explainChangeWorkflow };
|