@openlines/opl-pi-sht 0.1.14
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 +191 -0
- package/configs/opl-browser.json.sample +8 -0
- package/configs/opl-footer.json +48 -0
- package/configs/opl-footer.json.sample +48 -0
- package/configs/opl-input.json +22 -0
- package/configs/opl-input.json.sample +22 -0
- package/configs/opl-modes.json +291 -0
- package/configs/opl-modes.json.sample +285 -0
- package/configs/opl-simplebench.json +8 -0
- package/configs/opl-simplebench.json.sample +8 -0
- package/configs/opl-todo.json +12 -0
- package/configs/opl-todo.json.sample +12 -0
- package/configs/opl-webaccess.json +31 -0
- package/configs/opl-webaccess.json.sample +31 -0
- package/extensions/opl-browser/README.md +83 -0
- package/extensions/opl-browser/browser.ts +185 -0
- package/extensions/opl-browser/config.ts +37 -0
- package/extensions/opl-browser/index.ts +89 -0
- package/extensions/opl-browser/package-lock.json +60 -0
- package/extensions/opl-browser/package.json +10 -0
- package/extensions/opl-ctxtrim/README.md +78 -0
- package/extensions/opl-ctxtrim/index.ts +151 -0
- package/extensions/opl-footer/README.md +193 -0
- package/extensions/opl-footer/config.ts +91 -0
- package/extensions/opl-footer/git-status.ts +170 -0
- package/extensions/opl-footer/icons.ts +49 -0
- package/extensions/opl-footer/index.ts +368 -0
- package/extensions/opl-footer/segments/caveman.ts +25 -0
- package/extensions/opl-footer/segments/chat-mode.ts +24 -0
- package/extensions/opl-footer/segments/context.ts +92 -0
- package/extensions/opl-footer/segments/cost.ts +25 -0
- package/extensions/opl-footer/segments/git.ts +47 -0
- package/extensions/opl-footer/segments/helpers.ts +18 -0
- package/extensions/opl-footer/segments/index.ts +51 -0
- package/extensions/opl-footer/segments/mode-switcher.ts +24 -0
- package/extensions/opl-footer/segments/model.ts +22 -0
- package/extensions/opl-footer/segments/path.ts +34 -0
- package/extensions/opl-footer/segments/pi.ts +11 -0
- package/extensions/opl-footer/segments/plan-mode.ts +24 -0
- package/extensions/opl-footer/segments/separator.ts +9 -0
- package/extensions/opl-footer/segments/session-stats.ts +82 -0
- package/extensions/opl-footer/segments/thinking.ts +51 -0
- package/extensions/opl-footer/segments/tokens.ts +66 -0
- package/extensions/opl-footer/theme.ts +113 -0
- package/extensions/opl-footer/types.ts +172 -0
- package/extensions/opl-init/README.md +23 -0
- package/extensions/opl-init/index.ts +451 -0
- package/extensions/opl-input/README.md +83 -0
- package/extensions/opl-input/config.ts +137 -0
- package/extensions/opl-input/index.ts +284 -0
- package/extensions/opl-input/mode-style.ts +38 -0
- package/extensions/opl-input/utils.ts +378 -0
- package/extensions/opl-modes/README.md +132 -0
- package/extensions/opl-modes/config.ts +473 -0
- package/extensions/opl-modes/index.ts +1081 -0
- package/extensions/opl-modes/menus.ts +60 -0
- package/extensions/opl-modes/state.ts +152 -0
- package/extensions/opl-modes/types.ts +164 -0
- package/extensions/opl-modes/utils.ts +138 -0
- package/extensions/opl-questionnaire/README.md +26 -0
- package/extensions/opl-questionnaire/index.ts +445 -0
- package/extensions/opl-questionnaire/types.ts +55 -0
- package/extensions/opl-simplebench/README.md +242 -0
- package/extensions/opl-simplebench/artifact.ts +41 -0
- package/extensions/opl-simplebench/benchmark.ts +873 -0
- package/extensions/opl-simplebench/coding.ts +282 -0
- package/extensions/opl-simplebench/index.ts +203 -0
- package/extensions/opl-simplebench/llama-server.ts +290 -0
- package/extensions/opl-simplebench/metrics.ts +73 -0
- package/extensions/opl-simplebench/report.ts +46 -0
- package/extensions/opl-simplebench/research.ts +200 -0
- package/extensions/opl-simplebench/scoring.ts +48 -0
- package/extensions/opl-simplebench/tests.ts +39 -0
- package/extensions/opl-simplebench/types.ts +6 -0
- package/extensions/opl-simplebench/util/config.ts +170 -0
- package/extensions/opl-simplebench/util/debug.ts +32 -0
- package/extensions/opl-simplebench/util/format.ts +402 -0
- package/extensions/opl-simplebench/util/providers.ts +841 -0
- package/extensions/opl-todo/README.md +43 -0
- package/extensions/opl-todo/config.ts +71 -0
- package/extensions/opl-todo/index.ts +415 -0
- package/extensions/opl-webaccess/README.md +47 -0
- package/extensions/opl-webaccess/config.ts +55 -0
- package/extensions/opl-webaccess/extract.ts +83 -0
- package/extensions/opl-webaccess/index.ts +232 -0
- package/extensions/opl-webaccess/package-lock.json +345 -0
- package/extensions/opl-webaccess/package.json +18 -0
- package/extensions/opl-webaccess/pdf.ts +8 -0
- package/extensions/opl-webaccess/providers/ddgs.ts +72 -0
- package/extensions/opl-webaccess/providers/exa.ts +74 -0
- package/extensions/opl-webaccess/providers/gemini.ts +60 -0
- package/extensions/opl-webaccess/providers/searxng.ts +86 -0
- package/extensions/opl-webaccess/providers/tavily.ts +60 -0
- package/extensions/opl-webaccess/search.ts +36 -0
- package/extensions/opl-webaccess/storage.ts +51 -0
- package/extensions/opl-webaccess/turndown.d.ts +1 -0
- package/extensions/opl-webaccess/types.ts +26 -0
- package/extensions/opl-webaccess/utils.ts +28 -0
- package/package.json +55 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Readability } from "@mozilla/readability";
|
|
2
|
+
import { parseHTML } from "linkedom";
|
|
3
|
+
import TurndownService from "turndown";
|
|
4
|
+
import { extractPdfBuffer } from "./pdf.js";
|
|
5
|
+
import { errorMessage, isAbortError, isPdfUrl, isPdfContentType } from "./utils.js";
|
|
6
|
+
import type { ExtractedContent } from "./types.js";
|
|
7
|
+
|
|
8
|
+
const CONCURRENT_LIMIT = 3;
|
|
9
|
+
|
|
10
|
+
const td = new TurndownService({
|
|
11
|
+
headingStyle: "atx",
|
|
12
|
+
codeBlockStyle: "fenced",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export async function fetchAllContent(
|
|
16
|
+
urls: string[],
|
|
17
|
+
signal?: AbortSignal
|
|
18
|
+
): Promise<ExtractedContent[]> {
|
|
19
|
+
const results: ExtractedContent[] = [];
|
|
20
|
+
for (let i = 0; i < urls.length; i += CONCURRENT_LIMIT) {
|
|
21
|
+
if (signal?.aborted) break;
|
|
22
|
+
const batch = urls.slice(i, i + CONCURRENT_LIMIT);
|
|
23
|
+
const batchResults = await Promise.all(batch.map((url) => fetchOne(url, signal)));
|
|
24
|
+
results.push(...batchResults);
|
|
25
|
+
}
|
|
26
|
+
return results;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function fetchOne(url: string, signal?: AbortSignal): Promise<ExtractedContent> {
|
|
30
|
+
try {
|
|
31
|
+
const response = await fetch(url, {
|
|
32
|
+
signal,
|
|
33
|
+
headers: {
|
|
34
|
+
"User-Agent": "Mozilla/5.0 (compatible; pi-web-access/1.0)",
|
|
35
|
+
Accept: "text/html,application/xhtml+xml,application/pdf,*/*",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
return { url, title: "", content: "", error: `HTTP ${response.status}: ${url}` };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
44
|
+
|
|
45
|
+
if (isPdfUrl(url) || isPdfContentType(contentType)) {
|
|
46
|
+
const buffer = await response.arrayBuffer();
|
|
47
|
+
const content = await extractPdfBuffer(buffer);
|
|
48
|
+
return { url, title: url, content, error: null };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const isHtml =
|
|
52
|
+
contentType.includes("text/html") || contentType.includes("application/xhtml");
|
|
53
|
+
|
|
54
|
+
const body = await response.text();
|
|
55
|
+
|
|
56
|
+
if (!isHtml) {
|
|
57
|
+
// Plain text, markdown, JSON, etc. — return as-is
|
|
58
|
+
return { url, title: "", content: body, error: null };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { document } = parseHTML(body);
|
|
62
|
+
let article = null;
|
|
63
|
+
try {
|
|
64
|
+
article = new Readability(document as unknown as Document).parse();
|
|
65
|
+
} catch {
|
|
66
|
+
// Readability failed — fall back to raw turndown
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!article?.content) {
|
|
70
|
+
return { url, title: "", content: td.turndown(body), error: null };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
url,
|
|
75
|
+
title: article.title ?? "",
|
|
76
|
+
content: td.turndown(article.content),
|
|
77
|
+
error: null,
|
|
78
|
+
};
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (isAbortError(err)) return { url, title: "", content: "", error: "Aborted" };
|
|
81
|
+
return { url, title: "", content: "", error: errorMessage(err) };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { searchWeb } from "./search.js";
|
|
4
|
+
import { fetchAllContent } from "./extract.js";
|
|
5
|
+
import {
|
|
6
|
+
generateId,
|
|
7
|
+
storeResult,
|
|
8
|
+
getResult,
|
|
9
|
+
persistResult,
|
|
10
|
+
restoreFromSession,
|
|
11
|
+
MAX_CONTENT_CHARS,
|
|
12
|
+
} from "./storage.js";
|
|
13
|
+
import { truncate, errorMessage } from "./utils.js";
|
|
14
|
+
import type { StoredData } from "./types.js";
|
|
15
|
+
|
|
16
|
+
export default function (pi: ExtensionAPI) {
|
|
17
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
18
|
+
restoreFromSession(ctx);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// ── web_search ────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
pi.registerTool({
|
|
24
|
+
name: "web_search",
|
|
25
|
+
label: "Web Search",
|
|
26
|
+
description:
|
|
27
|
+
"Search the web using the configured search provider (gemini, tavily, ddgs, searxng, or exa). Returns a synthesized answer with source citations. Provider is set in ~/.pi/agent/configs/opl-webaccess.json. Use queries (plural) to run multiple searches in parallel.",
|
|
28
|
+
parameters: Type.Object({
|
|
29
|
+
query: Type.Optional(Type.String({ description: "Single search query" })),
|
|
30
|
+
queries: Type.Optional(
|
|
31
|
+
Type.Array(Type.String(), { description: "Multiple search queries run in parallel" })
|
|
32
|
+
),
|
|
33
|
+
}),
|
|
34
|
+
async execute(_toolCallId, params, signal) {
|
|
35
|
+
const queryList = params.queries ?? (params.query ? [params.query] : null);
|
|
36
|
+
if (!queryList?.length) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: "Error: provide either query or queries." }],
|
|
39
|
+
isError: true,
|
|
40
|
+
details: {} as Record<string, unknown>,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let results;
|
|
45
|
+
try {
|
|
46
|
+
results = await Promise.all(queryList.map((q) => searchWeb(q, signal)));
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: `Error: ${errorMessage(err)}` }],
|
|
50
|
+
isError: true,
|
|
51
|
+
details: {} as Record<string, unknown>,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const id = generateId();
|
|
56
|
+
const data: StoredData = { id, type: "search", timestamp: Date.now(), queries: results };
|
|
57
|
+
storeResult(id, data);
|
|
58
|
+
persistResult(pi, data);
|
|
59
|
+
|
|
60
|
+
const sections = results.map((r) => {
|
|
61
|
+
if (r.error) return `## Query: "${r.query}"\n\nError: ${r.error}`;
|
|
62
|
+
const sources =
|
|
63
|
+
r.results.length > 0
|
|
64
|
+
? "\n\n**Sources:**\n" +
|
|
65
|
+
r.results.map((s, i) => `${i + 1}. [${s.title}](${s.url})`).join("\n")
|
|
66
|
+
: "";
|
|
67
|
+
return `## Query: "${r.query}"\n\n${r.answer}${sources}`;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const body = truncate(sections.join("\n\n---\n\n"), MAX_CONTENT_CHARS);
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text: `${body}\n\n*responseId: ${id}*` }],
|
|
73
|
+
details: { responseId: id, queryCount: results.length },
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// ── fetch_content ─────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
pi.registerTool({
|
|
81
|
+
name: "fetch_content",
|
|
82
|
+
label: "Fetch Content",
|
|
83
|
+
description:
|
|
84
|
+
"Fetch one or more URLs and extract readable content as markdown. Supports regular web pages and PDFs. No API key required. Use urls (plural) for multiple URLs.",
|
|
85
|
+
parameters: Type.Object({
|
|
86
|
+
url: Type.Optional(Type.String({ description: "Single URL to fetch" })),
|
|
87
|
+
urls: Type.Optional(
|
|
88
|
+
Type.Array(Type.String(), { description: "Multiple URLs to fetch in parallel (max 3 at a time)" })
|
|
89
|
+
),
|
|
90
|
+
}),
|
|
91
|
+
async execute(_toolCallId, params, signal) {
|
|
92
|
+
const urlList = params.urls ?? (params.url ? [params.url] : null);
|
|
93
|
+
if (!urlList?.length) {
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: "Error: provide either url or urls." }],
|
|
96
|
+
isError: true,
|
|
97
|
+
details: {} as Record<string, unknown>,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let results;
|
|
102
|
+
try {
|
|
103
|
+
results = await fetchAllContent(urlList, signal);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: `Error: ${errorMessage(err)}` }],
|
|
107
|
+
isError: true,
|
|
108
|
+
details: {} as Record<string, unknown>,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const id = generateId();
|
|
113
|
+
const data: StoredData = { id, type: "fetch", timestamp: Date.now(), urls: results };
|
|
114
|
+
storeResult(id, data);
|
|
115
|
+
persistResult(pi, data);
|
|
116
|
+
|
|
117
|
+
const sections = results.map((r) => {
|
|
118
|
+
if (r.error) return `## ${r.url}\n\nError: ${r.error}`;
|
|
119
|
+
const title = r.title ? `**${r.title}**\n\n` : "";
|
|
120
|
+
return `## ${r.url}\n\n${title}${r.content}`;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const body = truncate(sections.join("\n\n---\n\n"), MAX_CONTENT_CHARS);
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: `${body}\n\n*responseId: ${id}*` }],
|
|
126
|
+
details: { responseId: id, urlCount: results.length },
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ── get_search_content ────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
pi.registerTool({
|
|
134
|
+
name: "get_search_content",
|
|
135
|
+
label: "Get Search Content",
|
|
136
|
+
description:
|
|
137
|
+
"Retrieve full stored content from a previous web_search or fetch_content call. Use when content was truncated in the original response.",
|
|
138
|
+
parameters: Type.Object({
|
|
139
|
+
responseId: Type.String({
|
|
140
|
+
description: "The responseId returned by web_search or fetch_content",
|
|
141
|
+
}),
|
|
142
|
+
queryIndex: Type.Optional(
|
|
143
|
+
Type.Number({ description: "Index of the query to retrieve (web_search, default: 0)" })
|
|
144
|
+
),
|
|
145
|
+
urlIndex: Type.Optional(
|
|
146
|
+
Type.Number({ description: "Index of the URL to retrieve (fetch_content, default: 0)" })
|
|
147
|
+
),
|
|
148
|
+
url: Type.Optional(
|
|
149
|
+
Type.String({ description: "Retrieve content for a specific URL (fetch_content)" })
|
|
150
|
+
),
|
|
151
|
+
}),
|
|
152
|
+
async execute(_toolCallId, params) {
|
|
153
|
+
const data = getResult(params.responseId);
|
|
154
|
+
if (!data) {
|
|
155
|
+
return {
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: `No stored content found for responseId: ${params.responseId}. Results expire after 1 hour or when a new session starts.`,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
isError: true,
|
|
163
|
+
details: {} as Record<string, unknown>,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (data.type === "search") {
|
|
168
|
+
const idx = params.queryIndex ?? 0;
|
|
169
|
+
const result = data.queries?.[idx];
|
|
170
|
+
if (!result) {
|
|
171
|
+
return {
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: `No query at index ${idx}. This response has ${data.queries?.length ?? 0} quer${data.queries?.length === 1 ? "y" : "ies"}.`,
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
isError: true,
|
|
179
|
+
details: {} as Record<string, unknown>,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const sources =
|
|
183
|
+
result.results.length > 0
|
|
184
|
+
? "\n\n**Sources:**\n" +
|
|
185
|
+
result.results.map((s, i) => `${i + 1}. [${s.title}](${s.url})`).join("\n")
|
|
186
|
+
: "";
|
|
187
|
+
return {
|
|
188
|
+
content: [{ type: "text", text: `## Query: "${result.query}"\n\n${result.answer}${sources}` }],
|
|
189
|
+
details: { responseId: params.responseId },
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (data.type === "fetch") {
|
|
194
|
+
const result =
|
|
195
|
+
params.url != null
|
|
196
|
+
? data.urls?.find((u) => u.url === params.url)
|
|
197
|
+
: data.urls?.[params.urlIndex ?? 0];
|
|
198
|
+
|
|
199
|
+
if (!result) {
|
|
200
|
+
return {
|
|
201
|
+
content: [
|
|
202
|
+
{
|
|
203
|
+
type: "text",
|
|
204
|
+
text: `No URL found. This response has ${data.urls?.length ?? 0} URL(s).`,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
isError: true,
|
|
208
|
+
details: {} as Record<string, unknown>,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (result.error) {
|
|
212
|
+
return {
|
|
213
|
+
content: [{ type: "text", text: `Error fetching ${result.url}: ${result.error}` }],
|
|
214
|
+
isError: true,
|
|
215
|
+
details: {} as Record<string, unknown>,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const title = result.title ? `**${result.title}**\n\n` : "";
|
|
219
|
+
return {
|
|
220
|
+
content: [{ type: "text", text: `## ${result.url}\n\n${title}${result.content}` }],
|
|
221
|
+
details: { responseId: params.responseId },
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
content: [{ type: "text", text: "Unknown result type." }],
|
|
227
|
+
isError: true,
|
|
228
|
+
details: {},
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opl-webaccess",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "opl-webaccess",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@mozilla/readability": "^0.6.0",
|
|
13
|
+
"linkedom": "^0.18.13",
|
|
14
|
+
"turndown": "^7.2.4",
|
|
15
|
+
"unpdf": "^1.8.0"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"node_modules/@mixmark-io/domino": {
|
|
19
|
+
"version": "2.2.0",
|
|
20
|
+
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
|
|
21
|
+
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==",
|
|
22
|
+
"license": "BSD-2-Clause"
|
|
23
|
+
},
|
|
24
|
+
"node_modules/@mozilla/readability": {
|
|
25
|
+
"version": "0.6.0",
|
|
26
|
+
"resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz",
|
|
27
|
+
"integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==",
|
|
28
|
+
"license": "Apache-2.0",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=14.0.0"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"node_modules/boolbase": {
|
|
34
|
+
"version": "2.0.0",
|
|
35
|
+
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-2.0.0.tgz",
|
|
36
|
+
"integrity": "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==",
|
|
37
|
+
"license": "ISC",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.19.0"
|
|
40
|
+
},
|
|
41
|
+
"funding": {
|
|
42
|
+
"type": "github",
|
|
43
|
+
"url": "https://github.com/sponsors/fb55"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"node_modules/css-select": {
|
|
47
|
+
"version": "7.0.0",
|
|
48
|
+
"resolved": "https://registry.npmjs.org/css-select/-/css-select-7.0.0.tgz",
|
|
49
|
+
"integrity": "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==",
|
|
50
|
+
"license": "BSD-2-Clause",
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"boolbase": "^2.0.0",
|
|
53
|
+
"css-what": "^8.0.0",
|
|
54
|
+
"domhandler": "^6.0.1",
|
|
55
|
+
"domutils": "^4.0.2",
|
|
56
|
+
"nth-check": "^3.0.1"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=20.19.0"
|
|
60
|
+
},
|
|
61
|
+
"funding": {
|
|
62
|
+
"type": "github",
|
|
63
|
+
"url": "https://github.com/sponsors/fb55"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"node_modules/css-what": {
|
|
67
|
+
"version": "8.0.0",
|
|
68
|
+
"resolved": "https://registry.npmjs.org/css-what/-/css-what-8.0.0.tgz",
|
|
69
|
+
"integrity": "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==",
|
|
70
|
+
"license": "BSD-2-Clause",
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=20.19.0"
|
|
73
|
+
},
|
|
74
|
+
"funding": {
|
|
75
|
+
"type": "github",
|
|
76
|
+
"url": "https://github.com/sponsors/fb55"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"node_modules/cssom": {
|
|
80
|
+
"version": "0.5.0",
|
|
81
|
+
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
|
|
82
|
+
"integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
|
|
83
|
+
"license": "MIT"
|
|
84
|
+
},
|
|
85
|
+
"node_modules/dom-serializer": {
|
|
86
|
+
"version": "3.1.1",
|
|
87
|
+
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz",
|
|
88
|
+
"integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==",
|
|
89
|
+
"license": "MIT",
|
|
90
|
+
"dependencies": {
|
|
91
|
+
"domelementtype": "^3.0.0",
|
|
92
|
+
"domhandler": "^6.0.0",
|
|
93
|
+
"entities": "^8.0.0"
|
|
94
|
+
},
|
|
95
|
+
"engines": {
|
|
96
|
+
"node": ">=20.19.0"
|
|
97
|
+
},
|
|
98
|
+
"funding": {
|
|
99
|
+
"type": "github",
|
|
100
|
+
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"node_modules/domelementtype": {
|
|
104
|
+
"version": "3.0.0",
|
|
105
|
+
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz",
|
|
106
|
+
"integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==",
|
|
107
|
+
"funding": [
|
|
108
|
+
{
|
|
109
|
+
"type": "github",
|
|
110
|
+
"url": "https://github.com/sponsors/fb55"
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"license": "BSD-2-Clause",
|
|
114
|
+
"engines": {
|
|
115
|
+
"node": ">=20.19.0"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"node_modules/domhandler": {
|
|
119
|
+
"version": "6.0.1",
|
|
120
|
+
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz",
|
|
121
|
+
"integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==",
|
|
122
|
+
"license": "BSD-2-Clause",
|
|
123
|
+
"dependencies": {
|
|
124
|
+
"domelementtype": "^3.0.0"
|
|
125
|
+
},
|
|
126
|
+
"engines": {
|
|
127
|
+
"node": ">=20.19.0"
|
|
128
|
+
},
|
|
129
|
+
"funding": {
|
|
130
|
+
"type": "github",
|
|
131
|
+
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"node_modules/domutils": {
|
|
135
|
+
"version": "4.0.2",
|
|
136
|
+
"resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz",
|
|
137
|
+
"integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==",
|
|
138
|
+
"license": "BSD-2-Clause",
|
|
139
|
+
"dependencies": {
|
|
140
|
+
"dom-serializer": "^3.0.0",
|
|
141
|
+
"domelementtype": "^3.0.0",
|
|
142
|
+
"domhandler": "^6.0.0"
|
|
143
|
+
},
|
|
144
|
+
"engines": {
|
|
145
|
+
"node": ">=20.19.0"
|
|
146
|
+
},
|
|
147
|
+
"funding": {
|
|
148
|
+
"type": "github",
|
|
149
|
+
"url": "https://github.com/fb55/domutils?sponsor=1"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"node_modules/entities": {
|
|
153
|
+
"version": "8.0.0",
|
|
154
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
|
|
155
|
+
"integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
|
|
156
|
+
"license": "BSD-2-Clause",
|
|
157
|
+
"engines": {
|
|
158
|
+
"node": ">=20.19.0"
|
|
159
|
+
},
|
|
160
|
+
"funding": {
|
|
161
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"node_modules/html-escaper": {
|
|
165
|
+
"version": "3.0.3",
|
|
166
|
+
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz",
|
|
167
|
+
"integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==",
|
|
168
|
+
"license": "MIT"
|
|
169
|
+
},
|
|
170
|
+
"node_modules/htmlparser2": {
|
|
171
|
+
"version": "10.1.0",
|
|
172
|
+
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
|
173
|
+
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
|
174
|
+
"funding": [
|
|
175
|
+
"https://github.com/fb55/htmlparser2?sponsor=1",
|
|
176
|
+
{
|
|
177
|
+
"type": "github",
|
|
178
|
+
"url": "https://github.com/sponsors/fb55"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
"license": "MIT",
|
|
182
|
+
"dependencies": {
|
|
183
|
+
"domelementtype": "^2.3.0",
|
|
184
|
+
"domhandler": "^5.0.3",
|
|
185
|
+
"domutils": "^3.2.2",
|
|
186
|
+
"entities": "^7.0.1"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"node_modules/htmlparser2/node_modules/dom-serializer": {
|
|
190
|
+
"version": "2.0.0",
|
|
191
|
+
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
|
192
|
+
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
|
193
|
+
"license": "MIT",
|
|
194
|
+
"dependencies": {
|
|
195
|
+
"domelementtype": "^2.3.0",
|
|
196
|
+
"domhandler": "^5.0.2",
|
|
197
|
+
"entities": "^4.2.0"
|
|
198
|
+
},
|
|
199
|
+
"funding": {
|
|
200
|
+
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"node_modules/htmlparser2/node_modules/dom-serializer/node_modules/entities": {
|
|
204
|
+
"version": "4.5.0",
|
|
205
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
|
206
|
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
|
207
|
+
"license": "BSD-2-Clause",
|
|
208
|
+
"engines": {
|
|
209
|
+
"node": ">=0.12"
|
|
210
|
+
},
|
|
211
|
+
"funding": {
|
|
212
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"node_modules/htmlparser2/node_modules/domelementtype": {
|
|
216
|
+
"version": "2.3.0",
|
|
217
|
+
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
|
218
|
+
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
|
219
|
+
"funding": [
|
|
220
|
+
{
|
|
221
|
+
"type": "github",
|
|
222
|
+
"url": "https://github.com/sponsors/fb55"
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
"license": "BSD-2-Clause"
|
|
226
|
+
},
|
|
227
|
+
"node_modules/htmlparser2/node_modules/domhandler": {
|
|
228
|
+
"version": "5.0.3",
|
|
229
|
+
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
|
230
|
+
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
|
231
|
+
"license": "BSD-2-Clause",
|
|
232
|
+
"dependencies": {
|
|
233
|
+
"domelementtype": "^2.3.0"
|
|
234
|
+
},
|
|
235
|
+
"engines": {
|
|
236
|
+
"node": ">= 4"
|
|
237
|
+
},
|
|
238
|
+
"funding": {
|
|
239
|
+
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"node_modules/htmlparser2/node_modules/domutils": {
|
|
243
|
+
"version": "3.2.2",
|
|
244
|
+
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
|
245
|
+
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
|
246
|
+
"license": "BSD-2-Clause",
|
|
247
|
+
"dependencies": {
|
|
248
|
+
"dom-serializer": "^2.0.0",
|
|
249
|
+
"domelementtype": "^2.3.0",
|
|
250
|
+
"domhandler": "^5.0.3"
|
|
251
|
+
},
|
|
252
|
+
"funding": {
|
|
253
|
+
"url": "https://github.com/fb55/domutils?sponsor=1"
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"node_modules/htmlparser2/node_modules/entities": {
|
|
257
|
+
"version": "7.0.1",
|
|
258
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
|
259
|
+
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
|
260
|
+
"license": "BSD-2-Clause",
|
|
261
|
+
"engines": {
|
|
262
|
+
"node": ">=0.12"
|
|
263
|
+
},
|
|
264
|
+
"funding": {
|
|
265
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"node_modules/linkedom": {
|
|
269
|
+
"version": "0.18.13",
|
|
270
|
+
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.13.tgz",
|
|
271
|
+
"integrity": "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw==",
|
|
272
|
+
"license": "ISC",
|
|
273
|
+
"dependencies": {
|
|
274
|
+
"css-select": "^7.0.0",
|
|
275
|
+
"cssom": "^0.5.0",
|
|
276
|
+
"html-escaper": "^3.0.3",
|
|
277
|
+
"htmlparser2": "^10.1.0",
|
|
278
|
+
"uhyphen": "^0.2.0"
|
|
279
|
+
},
|
|
280
|
+
"engines": {
|
|
281
|
+
"node": ">=16"
|
|
282
|
+
},
|
|
283
|
+
"peerDependencies": {
|
|
284
|
+
"canvas": ">= 2"
|
|
285
|
+
},
|
|
286
|
+
"peerDependenciesMeta": {
|
|
287
|
+
"canvas": {
|
|
288
|
+
"optional": true
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
"node_modules/nth-check": {
|
|
293
|
+
"version": "3.0.1",
|
|
294
|
+
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-3.0.1.tgz",
|
|
295
|
+
"integrity": "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==",
|
|
296
|
+
"license": "BSD-2-Clause",
|
|
297
|
+
"dependencies": {
|
|
298
|
+
"boolbase": "^2.0.0"
|
|
299
|
+
},
|
|
300
|
+
"engines": {
|
|
301
|
+
"node": ">=20.19.0"
|
|
302
|
+
},
|
|
303
|
+
"funding": {
|
|
304
|
+
"type": "github",
|
|
305
|
+
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"node_modules/turndown": {
|
|
309
|
+
"version": "7.2.4",
|
|
310
|
+
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz",
|
|
311
|
+
"integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==",
|
|
312
|
+
"license": "MIT",
|
|
313
|
+
"dependencies": {
|
|
314
|
+
"@mixmark-io/domino": "^2.2.0"
|
|
315
|
+
},
|
|
316
|
+
"engines": {
|
|
317
|
+
"node": ">=18",
|
|
318
|
+
"npm": ">=9"
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"node_modules/uhyphen": {
|
|
322
|
+
"version": "0.2.0",
|
|
323
|
+
"resolved": "https://registry.npmjs.org/uhyphen/-/uhyphen-0.2.0.tgz",
|
|
324
|
+
"integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==",
|
|
325
|
+
"license": "ISC"
|
|
326
|
+
},
|
|
327
|
+
"node_modules/unpdf": {
|
|
328
|
+
"version": "1.8.0",
|
|
329
|
+
"resolved": "https://registry.npmjs.org/unpdf/-/unpdf-1.8.0.tgz",
|
|
330
|
+
"integrity": "sha512-jQlkckbe5nKxRHQdbvo9IKHlU6Cjq00UlxxB8lrCIxvS2o5IbAL1wM+4a1Yc3+BIohg9p5AsoaftwO+G4Aq/qQ==",
|
|
331
|
+
"license": "MIT",
|
|
332
|
+
"engines": {
|
|
333
|
+
"node": ">=22"
|
|
334
|
+
},
|
|
335
|
+
"peerDependencies": {
|
|
336
|
+
"@napi-rs/canvas": "^0.1.69 || ^1.0.0"
|
|
337
|
+
},
|
|
338
|
+
"peerDependenciesMeta": {
|
|
339
|
+
"@napi-rs/canvas": {
|
|
340
|
+
"optional": true
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opl-webaccess",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Web search and content extraction for pi. Search the web via Gemini AI, fetch and read web pages, and extract text from PDFs — all from within the agent.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@mozilla/readability": "^0.6.0",
|
|
14
|
+
"linkedom": "^0.18.13",
|
|
15
|
+
"turndown": "^7.2.4",
|
|
16
|
+
"unpdf": "^1.8.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { errorMessage } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
export async function extractPdfBuffer(buffer: ArrayBuffer): Promise<string> {
|
|
4
|
+
const { getDocumentProxy, extractText } = await import("unpdf");
|
|
5
|
+
const pdf = await getDocumentProxy(new Uint8Array(buffer));
|
|
6
|
+
const { text } = await extractText(pdf, { mergePages: true });
|
|
7
|
+
return text ?? "";
|
|
8
|
+
}
|