mcp-searchable 1.0.2

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 ADDED
@@ -0,0 +1,312 @@
1
+ # TypeScript Bootstrap Template
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![Node.js CI](https://github.com/templ-project/typescript/actions/workflows/ci.yml/badge.svg)](https://github.com/templ-project/typescript/actions/workflows/ci.yml)
5
+ [![Contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/templ-project/typescript/issues)
6
+
7
+ > A modern TypeScript project template with ESM, testing, linting, and quality tools built-in.
8
+
9
+ - [TypeScript Bootstrap Template](#typescript-bootstrap-template)
10
+ - [Quick Start](#quick-start)
11
+ - [Bootstrap Options](#bootstrap-options)
12
+ - [What's Included](#whats-included)
13
+ - [Common Commands](#common-commands)
14
+ - [Using npm](#using-npm)
15
+ - [Using mise tasks (Recommended)](#using-taskfile-recommended)
16
+ - [Requirements](#requirements)
17
+ - [Setup Development Environment](#setup-development-environment)
18
+ - [Project Structure](#project-structure)
19
+ - [Building](#building)
20
+ - [Testing](#testing)
21
+ - [Code Quality](#code-quality)
22
+ - [Pre-commit Hooks](#pre-commit-hooks)
23
+ - [Configuration](#configuration)
24
+ - [Using as a Library](#using-as-a-library)
25
+ - [CI/CD Pipeline](#cicd-pipeline)
26
+ - [License](#license)
27
+ - [Support](#support)
28
+
29
+ ## Quick Start
30
+
31
+ **Bootstrap a new project:**
32
+
33
+ ```bash
34
+ npx --yes --package=github:templ-project/typescript bootstrap ./my-project
35
+ cd my-project
36
+ npm install
37
+ npm test
38
+ ```
39
+
40
+ That's it! You now have a fully configured TypeScript project.
41
+
42
+ ## MCP Search Providers
43
+
44
+ The `web_search` MCP tool supports multiple providers via the optional `provider` argument:
45
+
46
+ - `duckduckgo` (default)
47
+ - `google` (Google Custom Search JSON API)
48
+ - `bing` (Bing Web Search API)
49
+ - `brave` (Brave Search API)
50
+
51
+ ### Tool input
52
+
53
+ ```json
54
+ {
55
+ "query": "model context protocol",
56
+ "provider": "google",
57
+ "limit": 5
58
+ }
59
+ ```
60
+
61
+ ### Required environment variables
62
+
63
+ - `GOOGLE_API_KEY` and `GOOGLE_CSE_ID` for `provider=google`
64
+ - `BING_API_KEY` for `provider=bing`
65
+ - `BRAVE_API_KEY` for `provider=brave`
66
+
67
+ Optional:
68
+
69
+ - `BING_API_ENDPOINT` (override default Bing endpoint)
70
+
71
+ You can copy `.env.example` and fill in your provider keys.
72
+
73
+ ### Bootstrap Options
74
+
75
+ ```bash
76
+ # Bootstrap with only ESM and CJS builds (no browser builds)
77
+ npx --yes --package=github:templ-project/typescript bootstrap --target esm,cjs ./my-project
78
+
79
+ # Bootstrap as part of a monorepo (removes .husky, .github)
80
+ npx --yes --package=github:templ-project/typescript bootstrap --part-of-monorepo ./packages/my-lib
81
+
82
+ # Show all available options
83
+ npx --yes --package=github:templ-project/typescript bootstrap --help
84
+ ```
85
+
86
+ See [.npx-install/README.md](.npx-install/README.md) for detailed bootstrap documentation.
87
+
88
+ ## What's Included
89
+
90
+ | Feature | Tool | Description |
91
+ | ----------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------- |
92
+ | **Language** | [TypeScript 5.9](https://www.typescriptlang.org/) | Type-safe JavaScript |
93
+ | **Runtime** | [Node.js 22+](https://nodejs.org/) | Modern JavaScript runtime |
94
+ | **Execution** | [tsx](https://github.com/privatenumber/tsx) | TypeScript execution without build |
95
+ | **Module System** | ESM | Native ES Modules |
96
+ | **Build System** | [tsc](https://www.typescriptlang.org/) + [esbuild](https://esbuild.github.io/) | Type-check + fast bundling |
97
+ | **Test Framework** | [Vitest](https://vitest.dev/) | Fast unit testing with V8 coverage |
98
+ | **Linting** | [ESLint](https://eslint.org/) | Code quality with TypeScript rules |
99
+ | **Formatting** | [Prettier](https://prettier.io/) | Consistent code formatting |
100
+ | **Documentation** | [MkDocs](https://www.mkdocs.org/) + [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) | Project documentation site |
101
+ | **Task Runner** | [mise tasks](https://mise.jdx.dev/tasks/) | Modern build automation |
102
+ | **Tool Management** | [mise](https://mise.jdx.dev/) | Isolated development environment |
103
+ | **Pre-commit Hooks** | [Husky](https://typicode.github.io/husky/) + [lint-staged](https://github.com/okonet/lint-staged) | Automatic validation |
104
+ | **Duplicate Detection** | [jscpd](https://github.com/kucherenko/jscpd) | Copy-paste detector |
105
+ | **CI/CD** | GitHub Actions | Multi-platform testing & releases |
106
+
107
+ ## Common Commands
108
+
109
+ ### Using npm
110
+
111
+ ```bash
112
+ npm start # Run the app (via tsx)
113
+ npm test # Run tests
114
+ npm run test:coverage # Run tests with coverage
115
+ npm run lint # Lint and auto-fix
116
+ npm run format # Format code with Prettier
117
+ npm run build # Build for production
118
+ npm run docs # Build MkDocs site (strict)
119
+ npm run validate # Run all quality checks
120
+ ```
121
+
122
+ ### Using mise tasks (Recommended)
123
+
124
+ ```bash
125
+ # === Development ===
126
+ mise run run # Run the application (via node)
127
+ mise run format # Format all code (Prettier)
128
+ mise run format:check # Check formatting without fixing
129
+ mise run lint # Lint all code (ESLint + TypeScript)
130
+ mise run lint:check # Check all without fixing
131
+ mise run duplicate-check # Check for duplicate code
132
+ mise run docs # Build MkDocs site (strict)
133
+ mise run docs:serve # Serve documentation locally
134
+ mise run deps:sync # Install all dependencies (mise, npm)
135
+ mise run deps:refresh # Update all dependencies
136
+ mise run deps:clean # Remove all dependencies
137
+ ```
138
+
139
+ ## Requirements
140
+
141
+ - [mise](https://mise.jdx.dev/) - Tool version management (installs everything else)
142
+
143
+ **Automatically installed via mise:**
144
+
145
+ - Node.js 22+
146
+ - Python 3.11+ (for helper scripts)
147
+ - ShellCheck (shell script linting)
148
+ - PowerShell Core (cross-platform PowerShell)
149
+
150
+ ## Setup Development Environment
151
+
152
+ ```bash
153
+ # Install mise (if not already installed)
154
+ # Linux/macOS:
155
+ curl https://mise.run | sh
156
+
157
+ # Windows (PowerShell):
158
+ winget install jdx.mise
159
+ # or: choco install mise
160
+
161
+ # Install project tools and node modules
162
+
163
+
164
+ # Clone and setup
165
+ git clone https://github.com/templ-project/typescript.git my-project
166
+ cd my-project
167
+
168
+ # Install all dependencies
169
+ mise run deps:sync
170
+
171
+ # Verify setup
172
+ mise run validate
173
+ ```
174
+
175
+ ## Project Structure
176
+
177
+ ```text
178
+ ├── .github/
179
+ │ └── workflows/ # CI/CD pipelines
180
+ ├── .husky/ # Git hooks
181
+ ├── .scripts/ # Build/lint helper scripts
182
+
183
+ ├── src/
184
+ │ ├── index.ts # Main entry point
185
+ │ └── lib/
186
+ │ ├── greeter.ts # Example module with TypeScript types
187
+ │ └── greeter.spec.ts # Unit tests (co-located)
188
+ ├── dist/ # Build output (gitignored)
189
+ ├── docs/ # MkDocs source pages
190
+ ├── mise.toml # Configuration and tasks
191
+ ├── .mise.toml # Tool versions & hooks
192
+ ├── package.json # Node.js dependencies
193
+ ├── tsconfig.json # TypeScript configuration
194
+ ├── vitest.config.ts # Test configuration
195
+ ├── eslint.config.mjs # ESLint configuration
196
+ ├── prettier.config.mjs # Prettier configuration
197
+ └── mkdocs.yml # MkDocs configuration
198
+ ```
199
+
200
+ ## Building
201
+
202
+ The template uses a two-step build process:
203
+
204
+ 1. **tsc** - Type-checks and emits declaration files (`.d.ts`)
205
+ 2. **esbuild** - Bundles for multiple targets
206
+
207
+ ```bash
208
+ npm run build
209
+ # or: npm run build
210
+ ```
211
+
212
+ Outputs:
213
+
214
+ - `dist/index.js` - Node.js ESM build artifact
215
+ - `dist/index.d.ts` - TypeScript declaration file
216
+
217
+ ## Testing
218
+
219
+ Tests are co-located with source files using the `.spec.ts` suffix:
220
+
221
+ ```typescript
222
+ // src/lib/greeter.spec.ts
223
+ import { describe, it, expect } from "vitest";
224
+ import { hello } from "./greeter";
225
+
226
+ describe("hello", () => {
227
+ it("returns greeting", () => {
228
+ expect(hello("World")).toBe("Hello, World!");
229
+ });
230
+ });
231
+ ```
232
+
233
+ Run tests:
234
+
235
+ ```bash
236
+ npm run test # Run all tests
237
+ npm run test:coverage # Run with coverage report
238
+ ```
239
+
240
+ ## Code Quality
241
+
242
+ ### Pre-commit Hooks
243
+
244
+ Every commit is validated with:
245
+
246
+ - Code formatting (Prettier)
247
+ - Linting (ESLint)
248
+ - Type checking (TypeScript)
249
+ - Unit tests (Vitest)
250
+
251
+ CI runs additional checks:
252
+
253
+ - Test coverage
254
+ - Duplicate code detection
255
+ - License compliance
256
+
257
+ Configure hooks in:
258
+
259
+ - `.husky/pre-commit` - Hook script
260
+ - `.lintstagedrc.yml` - File patterns and commands
261
+
262
+ ## Configuration
263
+
264
+ All configuration uses shared packages for consistency:
265
+
266
+ | File | Purpose |
267
+ | --------------------- | ----------------------------------------------------- |
268
+ | `.mise.toml` | Tool versions (Node, Python, ShellCheck) |
269
+ | `mise.toml` | Configuration and tasks |
270
+ | `tsconfig.json` | TypeScript config (extends `@templ-project/tsconfig`) |
271
+ | `eslint.config.mjs` | ESLint config (uses `@templ-project/eslint`) |
272
+ | `prettier.config.mjs` | Prettier config (uses `@templ-project/prettier`) |
273
+ | `vitest.config.ts` | Vitest test configuration |
274
+ | `mkdocs.yml` | MkDocs site navigation and theme settings |
275
+ | `.jscpd.json` | Duplicate detection settings |
276
+ | `.licensee.json` | License compliance settings |
277
+
278
+ ## Using as a Library
279
+
280
+ ```typescript
281
+ // ES Modules (recommended)
282
+ import { hello, Greeter } from "@templ-project/typescript-template";
283
+
284
+ const greeting = hello("World");
285
+ console.log(greeting); // "Hello, World!"
286
+ ```
287
+
288
+ ```javascript
289
+ // ESM from built output
290
+ import { hello } from "./dist/index.js";
291
+ ```
292
+
293
+ ## CI/CD Pipeline
294
+
295
+ The GitHub Actions pipeline runs on **Linux, macOS, and Windows**:
296
+
297
+ | Workflow | Trigger | Jobs |
298
+ | ---------------- | ----------------------- | ---------------------------------- |
299
+ | `ci.yml` | Push/PR to main/develop | Matrix orchestrator |
300
+ | `ci.quality.yml` | Called by ci.yml | lint, test, build, duplicate-check |
301
+ | `ci.version.yml` | Push to main | Semantic version bump |
302
+ | `ci.release.yml` | After version bump | Create GitHub release |
303
+
304
+ ## License
305
+
306
+ MIT © [Templ Project](https://github.com/templ-project)
307
+
308
+ ## Support
309
+
310
+ - [Report Issues](https://github.com/templ-project/typescript/issues)
311
+ - [Read the Docs](https://github.com/templ-project/typescript#readme)
312
+ - [Star on GitHub](https://github.com/templ-project/typescript)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
+ import { WebStorage } from './lib/storage.js';
6
+ import { OllamaAskProvider } from './lib/web-ask.js';
7
+ import { WebFetcher } from './lib/web-fetch.js';
8
+ import { createSearchProvider } from './lib/web-search.js';
9
+ const SEARCH_PROVIDERS = ['duckduckgo', 'google', 'bing', 'brave'];
10
+ const webFetcher = new WebFetcher();
11
+ const webStorage = new WebStorage('.web_stash.db');
12
+ const askProvider = new OllamaAskProvider(webStorage);
13
+ const server = new Server({
14
+ name: 'smart-web-extraction',
15
+ version: '1.0.0',
16
+ }, {
17
+ capabilities: {
18
+ tools: {},
19
+ },
20
+ });
21
+ const SearchInputSchema = {
22
+ type: 'object',
23
+ properties: {
24
+ query: { type: 'string', description: 'Search query' },
25
+ provider: {
26
+ type: 'string',
27
+ enum: SEARCH_PROVIDERS,
28
+ description: 'Search provider (default: duckduckgo)',
29
+ },
30
+ limit: { type: 'number', description: 'Max results (default: 5)' },
31
+ },
32
+ required: ['query'],
33
+ };
34
+ function parseRequiredString(value, fieldName) {
35
+ if (typeof value !== 'string') {
36
+ throw new Error(`Invalid ${fieldName}: expected a string`);
37
+ }
38
+ const normalized = value.trim();
39
+ if (!normalized) {
40
+ throw new Error(`Invalid ${fieldName}: cannot be empty`);
41
+ }
42
+ return normalized;
43
+ }
44
+ function parseOptionalPositiveLimit(value, defaultValue) {
45
+ if (value === undefined) {
46
+ return defaultValue;
47
+ }
48
+ if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
49
+ throw new Error('Invalid limit: expected a positive integer');
50
+ }
51
+ return value;
52
+ }
53
+ function parseProvider(value) {
54
+ if (value === undefined) {
55
+ return 'duckduckgo';
56
+ }
57
+ if (typeof value !== 'string') {
58
+ throw new Error('Invalid provider: expected a string');
59
+ }
60
+ const provider = value.trim();
61
+ if (!SEARCH_PROVIDERS.includes(provider)) {
62
+ throw new Error(`Invalid provider: ${provider}. Supported providers: ${SEARCH_PROVIDERS.join(', ')}`);
63
+ }
64
+ return provider;
65
+ }
66
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
67
+ return {
68
+ tools: [
69
+ {
70
+ name: 'web_search',
71
+ description: 'Search the web using supported providers (DuckDuckGo, Google, Bing, Brave).',
72
+ inputSchema: SearchInputSchema,
73
+ },
74
+ {
75
+ name: 'web_fetch',
76
+ description: 'Fetch and extract markdown content from a URL.',
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ url: { type: 'string', description: 'URL to fetch' },
81
+ },
82
+ required: ['url'],
83
+ },
84
+ },
85
+ {
86
+ name: 'web_stash',
87
+ description: 'Store markdown content into local SQLite database.',
88
+ inputSchema: {
89
+ type: 'object',
90
+ properties: {
91
+ url: { type: 'string', description: 'Source URL' },
92
+ title: { type: 'string', description: 'Title of the page' },
93
+ content: { type: 'string', description: 'Markdown content' },
94
+ },
95
+ required: ['url', 'title', 'content'],
96
+ },
97
+ },
98
+ {
99
+ name: 'web_grep',
100
+ description: 'Search stashed web pages using FTS5.',
101
+ inputSchema: SearchInputSchema,
102
+ },
103
+ {
104
+ name: 'web_ask',
105
+ description: 'Ask a question using a local Ollama model and context from stashed web pages.',
106
+ inputSchema: {
107
+ type: 'object',
108
+ properties: {
109
+ question: { type: 'string', description: 'The question to ask' },
110
+ limit: { type: 'number', description: 'Number of sources to retrieve (default: 3)' },
111
+ },
112
+ required: ['question'],
113
+ },
114
+ },
115
+ ],
116
+ };
117
+ });
118
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
119
+ const { name, arguments: args } = request.params;
120
+ try {
121
+ switch (name) {
122
+ case 'web_search': {
123
+ const query = parseRequiredString(args?.query, 'query');
124
+ const provider = parseProvider(args?.provider);
125
+ const limit = parseOptionalPositiveLimit(args?.limit, 5);
126
+ const searchProvider = createSearchProvider(provider);
127
+ const results = await searchProvider.search(query, limit);
128
+ return {
129
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
130
+ };
131
+ }
132
+ case 'web_fetch': {
133
+ const url = parseRequiredString(args?.url, 'url');
134
+ const result = await webFetcher.fetch(url);
135
+ return {
136
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
137
+ };
138
+ }
139
+ case 'web_stash': {
140
+ const url = parseRequiredString(args?.url, 'url');
141
+ const title = parseRequiredString(args?.title, 'title');
142
+ const content = parseRequiredString(args?.content, 'content');
143
+ webStorage.stash({ url, title, content });
144
+ return {
145
+ content: [{ type: 'text', text: `Successfully stashed ${url}` }],
146
+ };
147
+ }
148
+ case 'web_grep': {
149
+ const query = parseRequiredString(args?.query, 'query');
150
+ const limit = parseOptionalPositiveLimit(args?.limit, 5);
151
+ const results = webStorage.grep(query, limit);
152
+ return {
153
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
154
+ };
155
+ }
156
+ case 'web_ask': {
157
+ const question = parseRequiredString(args?.question, 'question');
158
+ const limit = parseOptionalPositiveLimit(args?.limit, 3);
159
+ const result = await askProvider.ask(question, limit);
160
+ return {
161
+ content: [{ type: 'text', text: `Answer:\n${result.answer}\n\nSources:\n${result.contextUrls.join('\n')}` }],
162
+ };
163
+ }
164
+ default:
165
+ throw new Error(`Unknown tool: ${name}`);
166
+ }
167
+ }
168
+ catch (error) {
169
+ const err = error;
170
+ return {
171
+ content: [{ type: 'text', text: `Error executing tool ${name}: ${err.message}` }],
172
+ isError: true,
173
+ };
174
+ }
175
+ });
176
+ async function run() {
177
+ const transport = new StdioServerTransport();
178
+ await server.connect(transport);
179
+ console.error('Smart Web Extraction MCP Server running on stdio');
180
+ }
181
+ run().catch((error) => {
182
+ console.error('Fatal error running server:', error);
183
+ process.exit(1);
184
+ });
185
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { WebFetchResult } from './web-fetch.js';
2
+ export interface GrepResult {
3
+ url: string;
4
+ title: string;
5
+ snippet: string;
6
+ rank: number;
7
+ }
8
+ export declare class WebStorage {
9
+ private db;
10
+ constructor(dbPath?: string);
11
+ private initSchema;
12
+ stash(page: WebFetchResult): void;
13
+ grep(query: string, limit?: number): GrepResult[];
14
+ getPage(url: string): WebFetchResult | null;
15
+ close(): void;
16
+ }
17
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAe;gBAEb,MAAM,GAAE,MAAmB;IAKvC,OAAO,CAAC,UAAU;IA0ClB,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAsBjC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IA+BrD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IA2B3C,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,105 @@
1
+ import Database from 'better-sqlite3';
2
+ export class WebStorage {
3
+ db;
4
+ constructor(dbPath = ':memory:') {
5
+ this.db = new Database(dbPath);
6
+ this.initSchema();
7
+ }
8
+ initSchema() {
9
+ this.db.exec(`
10
+ CREATE TABLE IF NOT EXISTS pages (
11
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
12
+ url TEXT UNIQUE NOT NULL,
13
+ title TEXT,
14
+ content TEXT NOT NULL,
15
+ excerpt TEXT,
16
+ site_name TEXT,
17
+ created_at INTEGER NOT NULL
18
+ );
19
+ `);
20
+ this.db.exec(`
21
+ CREATE VIRTUAL TABLE IF NOT EXISTS pages_fts USING fts5(
22
+ title,
23
+ content,
24
+ content='pages',
25
+ content_rowid='id'
26
+ );
27
+ `);
28
+ this.db.exec(`
29
+ CREATE TRIGGER IF NOT EXISTS pages_ai AFTER INSERT ON pages BEGIN
30
+ INSERT INTO pages_fts(rowid, title, content) VALUES (new.id, new.title, new.content);
31
+ END;
32
+
33
+ CREATE TRIGGER IF NOT EXISTS pages_ad AFTER DELETE ON pages BEGIN
34
+ INSERT INTO pages_fts(pages_fts, rowid, title, content) VALUES('delete', old.id, old.title, old.content);
35
+ END;
36
+
37
+ CREATE TRIGGER IF NOT EXISTS pages_au AFTER UPDATE ON pages BEGIN
38
+ INSERT INTO pages_fts(pages_fts, rowid, title, content) VALUES('delete', old.id, old.title, old.content);
39
+ INSERT INTO pages_fts(rowid, title, content) VALUES (new.id, new.title, new.content);
40
+ END;
41
+ `);
42
+ }
43
+ stash(page) {
44
+ const stmt = this.db.prepare(`
45
+ INSERT INTO pages (url, title, content, excerpt, site_name, created_at)
46
+ VALUES (@url, @title, @content, @excerpt, @siteName, @createdAt)
47
+ ON CONFLICT(url) DO UPDATE SET
48
+ title = excluded.title,
49
+ content = excluded.content,
50
+ excerpt = excluded.excerpt,
51
+ site_name = excluded.site_name,
52
+ created_at = excluded.created_at
53
+ `);
54
+ stmt.run({
55
+ url: page.url,
56
+ title: page.title,
57
+ content: page.content,
58
+ excerpt: page.excerpt || null,
59
+ siteName: page.siteName || null,
60
+ createdAt: Date.now(),
61
+ });
62
+ }
63
+ grep(query, limit = 10) {
64
+ const stmt = this.db.prepare(`
65
+ SELECT
66
+ pages.url,
67
+ pages.title,
68
+ snippet(pages_fts, 1, '<b>', '</b>', '...', 64) as snippet,
69
+ pages_fts.rank
70
+ FROM pages_fts
71
+ JOIN pages ON pages.id = pages_fts.rowid
72
+ WHERE pages_fts MATCH @query
73
+ ORDER BY pages_fts.rank
74
+ LIMIT @limit
75
+ `);
76
+ const rows = stmt.all({ query, limit });
77
+ return rows.map((row) => ({
78
+ url: row.url,
79
+ title: row.title,
80
+ snippet: row.snippet,
81
+ rank: row.rank,
82
+ }));
83
+ }
84
+ getPage(url) {
85
+ const stmt = this.db.prepare(`
86
+ SELECT url, title, content, excerpt, site_name as siteName
87
+ FROM pages
88
+ WHERE url = @url
89
+ `);
90
+ const row = stmt.get({ url });
91
+ if (!row)
92
+ return null;
93
+ return {
94
+ url: row.url,
95
+ title: row.title,
96
+ content: row.content,
97
+ excerpt: row.excerpt,
98
+ siteName: row.siteName,
99
+ };
100
+ }
101
+ close() {
102
+ this.db.close();
103
+ }
104
+ }
105
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAWtC,MAAM,OAAO,UAAU;IACb,EAAE,CAAe;IAEzB,YAAY,SAAiB,UAAU;QACrC,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAEhB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;KAUZ,CAAC,CAAC;QAIH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;KAOZ,CAAC,CAAC;QAGH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;KAaZ,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAoB;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;KAS5B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC;YACP,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;YAC/B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,QAAgB,EAAE;QAGpC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;KAW5B,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAKpC,CAAC;QAEH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC,CAAC,CAAC;IACN,CAAC;IAED,OAAO,CAAC,GAAW;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;KAI5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAQf,CAAC;QACd,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,OAAO;YACL,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import { WebStorage } from './storage.js';
2
+ export interface AskResult {
3
+ answer: string;
4
+ contextUrls: string[];
5
+ }
6
+ export declare class OllamaAskProvider {
7
+ private storage;
8
+ private ollamaUrl;
9
+ private model;
10
+ constructor(storage: WebStorage, ollamaUrl?: string, model?: string);
11
+ ask(question: string, limit?: number): Promise<AskResult>;
12
+ }
13
+ //# sourceMappingURL=web-ask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-ask.d.ts","sourceRoot":"","sources":["../../src/lib/web-ask.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAc,MAAM,cAAc,CAAC;AAEtD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,KAAK;gBAFL,OAAO,EAAE,UAAU,EACnB,SAAS,GAAE,MAA2D,EACtE,KAAK,GAAE,MAA6C;IAGxD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,SAAS,CAAC;CAiFnE"}