@mrclrchtr/supi-web 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,73 +20,75 @@ After editing the source, run `/reload`.
20
20
 
21
21
  After install, pi gets three tools:
22
22
 
23
- - `web_fetch_md` fetch a web page and convert it to Markdown
24
- - `web_docs_search` — search Context7 for a library ID
25
- - `web_docs_fetch` fetch up-to-date documentation for a specific Context7 library
23
+ | Tool | Purpose |
24
+ |------|---------|
25
+ | `web_fetch_md` | Fetch a web page and convert it to clean Markdown for LLM ingestion |
26
+ | `web_docs_search` | Search Context7 for library IDs and metadata before fetching docs |
27
+ | `web_docs_fetch` | Fetch up-to-date documentation for a known Context7 library |
26
28
 
27
- ## Choose the right tool
29
+ ## `web_fetch_md`
28
30
 
29
- ### `web_fetch_md`
31
+ Fetches a public URL and returns clean Markdown.
30
32
 
31
- Use this for general web pages.
33
+ ### Parameters
32
34
 
33
- Important behavior:
35
+ | Parameter | Type | Required | Default | Description |
36
+ |-----------|------|----------|---------|-------------|
37
+ | `url` | string | ✓ | — | `http://` or `https://` URL to fetch |
38
+ | `output_mode` | `"auto"` \| `"inline"` \| `"file"` | — | `"auto"` | How to return the result |
39
+ | `abs_links` | boolean | — | `true` | Absolutize relative links and images |
40
+ | `timeout_ms` | number | — | `30000` | Fetch timeout in milliseconds |
34
41
 
35
- - accepts only real `http://` or `https://` URLs
36
- - defaults to `output_mode: auto`
37
- - returns Markdown inline when the result is at most **15,000 characters**
38
- - otherwise writes the Markdown to a temporary `.md` file and returns the file path
39
- - absolutizes links and image URLs by default
40
- - wraps plain-text responses as fenced code blocks instead of pretending they are prose
42
+ ### Output modes
41
43
 
42
- The fetch pipeline tries several strategies in order:
44
+ - **`auto`** returns Markdown inline if ≤15,000 characters; otherwise writes to a temporary file and returns the path
45
+ - **`inline`** — always returns Markdown inline
46
+ - **`file`** — always writes to a temporary file and returns the path
43
47
 
44
- 1. Markdown-aware content negotiation
45
- 2. content sniffing
46
- 3. sibling `.md` / `.markdown` probing
47
- 4. HTML fetch followed by Readability + Turndown conversion
48
+ ### Behavior
48
49
 
49
- ### `web_docs_search`
50
+ - Only accepts real `http://` or `https://` URLs
51
+ - Access-controlled pages (login, paywall) should be skipped — ask the user for an allowed source instead
52
+ - Plain-text responses are wrapped in fenced code blocks
53
+ - Links and images are absolutized by default; set `abs_links: false` to keep them relative
50
54
 
51
- Use this when you need a Context7 library ID first.
55
+ ## `web_docs_search`
52
56
 
53
- It returns a Markdown table of matching libraries with fields such as:
57
+ Searches Context7 for library IDs before fetching documentation.
54
58
 
55
- - ID
56
- - name
57
- - description
58
- - trust score
59
- - benchmark score
60
- - snippet count
61
- - versions
59
+ ### Parameters
62
60
 
63
- ### `web_docs_fetch`
61
+ | Parameter | Type | Required | Description |
62
+ |-----------|------|----------|-------------|
63
+ | `library_name` | string | ✓ | Library name to search for (e.g. `"react"`, `"next.js"`) |
64
+ | `query` | string | ✓ | What you're trying to do — used for relevance ranking |
64
65
 
65
- Use this when you already know the Context7 library ID and want current docs or snippets for a specific question.
66
+ Results return as a Markdown table with library ID, name, description, trust score, benchmark score, snippet count, and available versions.
66
67
 
67
- - `library_id` is required
68
- - `query` is required
69
- - `raw: true` returns JSON-serialized snippet objects instead of plain text Markdown
68
+ ## `web_docs_fetch`
70
69
 
71
- ## Context7 notes
70
+ Retrieves documentation context for a known Context7 library.
72
71
 
73
- `web_docs_search` and `web_docs_fetch` use Context7 through `@upstash/context7-sdk`.
72
+ ### Parameters
74
73
 
75
- If `CONTEXT7_API_KEY` is set, the SDK will use it automatically.
74
+ | Parameter | Type | Required | Default | Description |
75
+ |-----------|------|----------|---------|-------------|
76
+ | `library_id` | string | ✓ | — | Context7 library ID (e.g. `/facebook/react`, `/vercel/next.js`) |
77
+ | `query` | string | ✓ | — | Specific question about the library |
78
+ | `raw` | boolean | — | `false` | When `true`, returns JSON-serialized snippet objects instead of Markdown |
76
79
 
77
- ## Package surfaces
80
+ Default mode returns pre-formatted Markdown. Set `raw: true` when you need structured JSON for programmatic use.
78
81
 
79
- - `@mrclrchtr/supi-web/api` — conversion helpers, fetch helpers, and extension exports
80
- - `@mrclrchtr/supi-web/extension` — extension entrypoint that registers all three tools
82
+ ## Typical workflow
81
83
 
82
- ## Source
84
+ 1. **`web_docs_search`** — find the right library ID
85
+ 2. **Pick a `library_id`** from the results
86
+ 3. **`web_docs_fetch`** — retrieve focused, version-aware docs
83
87
 
84
- - `src/web.ts` `web_fetch_md`
85
- - `src/docs.ts` — `web_docs_search` and `web_docs_fetch`
86
- - `src/fetch.ts` HTTP fetching and negotiation
87
- - `src/convert.ts` — HTML-to-Markdown conversion
88
- - `src/context7-client.ts` Context7 client wrapper
89
- - `src/temp-file.ts` — temp-file output helper
90
- - `src/tool/web-fetch-md-guidance.ts` model-facing prompt surfaces for `web_fetch_md`
91
- - `src/tool/web-docs-search-guidance.ts` — model-facing prompt surfaces for `web_docs_search`
92
- - `src/tool/web-docs-fetch-guidance.ts` — model-facing prompt surfaces for `web_docs_fetch`
88
+ Skip step 1 if you already know the exact Context7 `library_id`.
89
+
90
+ ## Context7 API key
91
+
92
+ `web_docs_search` and `web_docs_fetch` use [Context7](https://context7.com/) through `@upstash/context7-sdk`.
93
+
94
+ If `CONTEXT7_API_KEY` is set in your environment, the SDK uses it automatically for higher rate limits. Without a key, the tools still work with lower defaults.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -49,6 +49,7 @@ export {
49
49
  redactDebugData,
50
50
  resetDebugRegistry,
51
51
  } from "./debug-registry.ts";
52
+ export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
52
53
  export type { KnownRootEntry } from "./project-roots.ts";
53
54
  export {
54
55
  buildKnownRootsMap,
@@ -63,6 +64,7 @@ export {
63
64
  sortRootsBySpecificity,
64
65
  walkProject,
65
66
  } from "./project-roots.ts";
67
+ export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
66
68
  export { getActiveBranchEntries } from "./session-utils.ts";
67
69
  export { registerSettingsCommand } from "./settings/settings-command.ts";
68
70
  export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
@@ -49,6 +49,7 @@ export {
49
49
  redactDebugData,
50
50
  resetDebugRegistry,
51
51
  } from "./debug-registry.ts";
52
+ export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
52
53
  export type { KnownRootEntry } from "./project-roots.ts";
53
54
  export {
54
55
  buildKnownRootsMap,
@@ -63,6 +64,7 @@ export {
63
64
  sortRootsBySpecificity,
64
65
  walkProject,
65
66
  } from "./project-roots.ts";
67
+ export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
66
68
  export { getActiveBranchEntries } from "./session-utils.ts";
67
69
  export { registerSettingsCommand } from "./settings/settings-command.ts";
68
70
  export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
@@ -0,0 +1,40 @@
1
+ import * as path from "node:path";
2
+
3
+ /** Strip pi's optional leading `@` file-path prefix from a tool input. */
4
+ export function stripToolPathPrefix(target: string): string {
5
+ return target.startsWith("@") ? target.slice(1) : target;
6
+ }
7
+
8
+ /**
9
+ * Resolve a tool-style file path from a session cwd.
10
+ *
11
+ * Built-in pi file tools accept a leading `@` prefix in path arguments, so
12
+ * shared SuPi path helpers normalize that prefix before resolving relative
13
+ * paths.
14
+ */
15
+ export function resolveToolPath(cwd: string, target: string): string {
16
+ return path.resolve(cwd, stripToolPathPrefix(target));
17
+ }
18
+
19
+ /** Convert a file path to a file:// URI. */
20
+ export function fileToUri(filePath: string): string {
21
+ const resolved = path.resolve(filePath);
22
+ if (process.platform === "win32") {
23
+ return `file:///${resolved.replace(/\\/g, "/")}`;
24
+ }
25
+ return `file://${resolved}`;
26
+ }
27
+
28
+ /** Convert a file:// URI to a file path. */
29
+ export function uriToFile(uri: string): string {
30
+ if (!uri.startsWith("file://")) return uri;
31
+ let filePath = decodeURIComponent(uri.slice(7));
32
+ if (
33
+ process.platform === "win32" &&
34
+ filePath.startsWith("/") &&
35
+ /^[A-Za-z]:/.test(filePath.slice(1))
36
+ ) {
37
+ filePath = filePath.slice(1);
38
+ }
39
+ return filePath;
40
+ }
@@ -5,8 +5,20 @@
5
5
  // Without this, each symlink path gets its own module copy and its own Map,
6
6
  // so registrations from one instance are invisible to consumers in another.
7
7
 
8
+ import * as path from "node:path";
9
+
8
10
  const SYMBOL_PREFIX = "@mrclrchtr/supi-core/";
9
11
 
12
+ function getGlobalRegistryMap<T>(name: string): Map<string, T> {
13
+ const key = Symbol.for(SYMBOL_PREFIX + name);
14
+ let map = (globalThis as Record<symbol, unknown>)[key] as Map<string, T> | undefined;
15
+ if (!map) {
16
+ map = new Map<string, T>();
17
+ (globalThis as Record<symbol, unknown>)[key] = map;
18
+ }
19
+ return map;
20
+ }
21
+
10
22
  /**
11
23
  * Create a named registry backed by `globalThis` + `Symbol.for`.
12
24
  *
@@ -18,16 +30,7 @@ const SYMBOL_PREFIX = "@mrclrchtr/supi-core/";
18
30
  * @returns An object with `register`, `getAll`, and `clear` functions.
19
31
  */
20
32
  export function createRegistry<T>(name: string) {
21
- const key = Symbol.for(SYMBOL_PREFIX + name);
22
-
23
- const getMap = (): Map<string, T> => {
24
- let map = (globalThis as Record<symbol, unknown>)[key] as Map<string, T> | undefined;
25
- if (!map) {
26
- map = new Map<string, T>();
27
- (globalThis as Record<symbol, unknown>)[key] = map;
28
- }
29
- return map;
30
- };
33
+ const getMap = (): Map<string, T> => getGlobalRegistryMap<T>(name);
31
34
 
32
35
  return {
33
36
  /**
@@ -52,3 +55,32 @@ export function createRegistry<T>(name: string) {
52
55
  },
53
56
  };
54
57
  }
58
+
59
+ /**
60
+ * Create a named session-state registry keyed by normalized cwd.
61
+ *
62
+ * This helper is intended for session-scoped runtime services that should be
63
+ * shared across duplicate jiti module instances while keeping package-specific
64
+ * state unions and convenience wrappers local to the calling package.
65
+ */
66
+ export function createSessionStateRegistry<TState>(name: string) {
67
+ const getMap = (): Map<string, TState> => getGlobalRegistryMap<TState>(name);
68
+ const normalizeCwd = (cwd: string): string => path.resolve(cwd);
69
+
70
+ return {
71
+ /** Get the current state for one session cwd. */
72
+ get: (cwd: string): TState | undefined => {
73
+ return getMap().get(normalizeCwd(cwd));
74
+ },
75
+
76
+ /** Store the current state for one session cwd. */
77
+ set: (cwd: string, state: TState): void => {
78
+ getMap().set(normalizeCwd(cwd), state);
79
+ },
80
+
81
+ /** Clear the current state for one session cwd. */
82
+ clear: (cwd: string): void => {
83
+ getMap().delete(normalizeCwd(cwd));
84
+ },
85
+ };
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-web",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "SuPi Web extension — fetch web pages as clean Markdown (web_fetch_md) and library docs via Context7 (web_docs_search, web_docs_fetch)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "@mozilla/readability": "^0.6.0",
26
26
  "turndown": "^7.2.0",
27
27
  "turndown-plugin-gfm": "^1.0.2",
28
- "@mrclrchtr/supi-core": "1.4.0"
28
+ "@mrclrchtr/supi-core": "1.6.0"
29
29
  },
30
30
  "bundledDependencies": [
31
31
  "@mrclrchtr/supi-core"