@zosmaai/pi-llm-wiki 0.11.1 → 0.11.3
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/CHANGELOG.md +4 -0
- package/README.de.md +21 -2
- package/README.es.md +21 -2
- package/README.fr.md +21 -2
- package/README.hi.md +21 -2
- package/README.ja.md +21 -2
- package/README.ko.md +21 -2
- package/README.md +30 -2
- package/README.pt.md +21 -2
- package/README.ru.md +21 -2
- package/README.zh.md +21 -2
- package/dist/extensions/llm-wiki/lib/runtime.js +13 -1
- package/dist/extensions/llm-wiki/lib/tools.js +10 -7
- package/dist/mcp/index.js +57 -4
- package/dist/mcp/operations.js +39 -3
- package/docs/api.md +9 -1
- package/extensions/llm-wiki/lib/runtime.ts +13 -1
- package/extensions/llm-wiki/lib/tools.ts +10 -7
- package/mcp/index.ts +67 -3
- package/mcp/operations.ts +47 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
|
+
- **MCP server failed to start on `@modelcontextprotocol/server` 2.0.0** (Issue #128): `mcp/index.ts` imported `StdioServerTransport` from the package root, but SDK 2.0.0 (published 2026-07-27) moved that export to the `./stdio` subpath, so `node dist/mcp/index.js` died with `SyntaxError: The requested module '@modelcontextprotocol/server' does not provide an export named 'StdioServerTransport'` before the transport ever connected. The declared range `^2.0.0-alpha.2` is a caret range over a prerelease, so it permits `2.0.0`: every fresh consumer install resolved the stable SDK against the pre-stable import, while `pnpm-lock.yaml` pinned the `2.0.0-alpha.2` floor — so `test/mcp-package.test.ts`, which does spawn the published command and complete the stdio handshake, only ever exercised the alpha where the root export still existed. Fixed by importing `StdioServerTransport` from `@modelcontextprotocol/server/stdio` (the `./stdio` subpath does not exist in `2.0.0-alpha.2`, so the range, the lockfile and the import move together), raising the range to `^2.0.0`, and refreshing the lockfile so the existing smoke test now runs against the SDK consumers actually get.
|
|
7
|
+
- **Packaged MCP server was never exercised with consumer-resolved dependencies**: a new `packaged-mcp-consumer` CI job packs the tarball, installs it into a directory with **no lockfile**, prints the resolved SDK version, and runs `scripts/mcp-smoke.mjs` — the stdio handshake (`initialize` → `tools/list`) — against that install. This closes the whole class of failure behind Issue #128: a dependency range that resolves differently for consumers than for this repo's lockfile can no longer break the published server undetected.
|
|
8
|
+
- **README documented a standalone MCP command that ships no JavaScript** (Issue #129): all ten READMEs pointed MCP clients at `node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js`, but the published `mcp/` directory contains only TypeScript (`index.ts`, `exec.ts`, `operations.ts`), so the documented command failed with `MODULE_NOT_FOUND` — independently of any dependency-resolution problem. The runnable entry is `dist/mcp/index.js`, which the package's own `pi.mcpservers` manifest already declared correctly. Every README now documents that path and adds an `mcpServers` config block for `.mcp.json` / `claude_desktop_config.json` using **absolute** paths, because MCP clients spawn the command without a shell: a `~` in `args` or `env` is passed through literally and the server fails to start behind a generic connection error. A new `test/package-structure.test.ts` case derives the expected path from `pi.mcpservers` — the same command `test/mcp-package.test.ts` spawns and handshakes with — and asserts every documented `…/mcp/index.js` occurrence in every README resolves to it, so docs cannot drift from the runnable entry point again.
|
|
6
9
|
- **Authoritative activity history**: `meta/events.jsonl` is now documented as durable append-only extension state rather than rebuildable metadata. Missing or unreadable event sources warn and preserve existing Markdown logs while unrelated projections continue rebuilding.
|
|
7
10
|
- **Portable log privacy**: local-file capture events no longer duplicate caller-supplied filesystem paths into `events.jsonl` or OKF `wiki/log.md`; exact paths remain in extension-owned raw manifests.
|
|
8
11
|
- **Vault layout migration safety and packaging**: `scripts/migrate-llm-wiki.js` now runs on the minimum supported Node 18 runtime, accepts absolute or relative roots regardless of flag order, reserves the destination root atomically, uses no-clobber file moves, rejects destination collisions before moving data, and ships in the npm package. A durable journal records source hashes and completed moves so an interrupted migration resumes safely; file and directory durability boundaries are flushed before completion. Black-box tests cover paths with spaces, dry-run immutability, hash-preserving apply, idempotency, preflight/raced collisions, real subprocess `SIGKILL` recovery, doubled-layout recovery, packed-artifact contents, and packed execution on Node 18.
|
|
@@ -15,6 +18,7 @@
|
|
|
15
18
|
- **Personal wiki created at doubled path `~/.llm-wiki/.llm-wiki/…`**: `getPersonalWikiRoot()` returned the dot-dir itself (`~/.llm-wiki`) while `getVaultPaths()` then appended another `.llm-wiki/` segment, so the personal vault was written to `~/.llm-wiki/.llm-wiki/wiki/…`. Fixed by aligning `getPersonalWikiRoot()` with the same "root = parent of `.llm-wiki/`" contract used by project vaults. `WIKI_HOME` continues to override the parent.
|
|
16
19
|
|
|
17
20
|
### Added
|
|
21
|
+
- **`wiki_bootstrap` over MCP, so MCP-only clients can create a vault** (Issue #130): the README aims the standalone MCP server at Claude Code, Cursor and Windsurf — clients with no access to the Pi extension — yet all five MCP tools failed closed with `No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.`, naming a tool those clients did not have. Short of installing pi or hand-building the `.llm-wiki/` tree, there was no path to a working vault. `bootstrapVault()` is pure Node (`node:fs`, `node:path`, sibling lib modules) with no model and no credentials in play, so it is now exposed as a sixth MCP tool through a thin `bootstrapOperation` adapter, keeping Pi and MCP over one implementation. Bootstrap resolves its target with `getVaultPaths(WIKI_ROOT)` rather than the usual `resolveVaultPaths()`: resolution deliberately walks up to a parent vault and then falls back to the personal vault, which is right for reading and writing pages but would create the vault somewhere other than where the client pointed the server. There is no `root` parameter, so the server stays confined to its configured root, and `mode` accepts the same free-form `personal`/`company` string the Pi tool takes. Re-running is safe: an existing vault has its config updated and metadata rebuilt, and pages are untouched. The two guards on the MCP surface (`test/mcp-parity.test.ts` and `test/mcp-package.test.ts`) were deliberately widened from five tools to six, `scripts/mcp-smoke.mjs` now requires the tool on the packed artifact, and every README's MCP table lists it.
|
|
18
22
|
- **Visible wiki activity + background/reported mutations** (Issue #77): the wiki was effectively invisible — recall was appended only to the **system prompt**, the observe/retro reminder was sent with `display: false`, and the lone user-facing cue was a static status line. The wiki now surfaces what it does, and mutating work is pushed off the agent's critical path.
|
|
19
23
|
- **Visible surfaces**: a one-time **session notice** (`buildSessionNotice`) announces the full loop — retrieval (recall → `wiki_search` → `read`, all synchronous because the LLM consumes their output) and capture (`wiki_observe` → `wiki_retro`, background + reported); the periodic reminder is now `display: true` and names **both** capture tools (`buildReminderText`); and the status line becomes **recall-aware** (`🧠 LLM Wiki — recalled N page(s) for this task`) when auto-recall matches.
|
|
20
24
|
- **Background + reported principle**: only `wiki_search` / `read` / `wiki_recall` stay synchronous. Heavy mutations — `wiki_rebuild_meta`, `wiki_reindex_embeddings`, `wiki_lint` — now dispatch to the background runtime and **report a visible completion message** instead of blocking the turn; `wiki_ingest` gained a persistent completion report alongside its toast. New `Runtime.report()` / `Runtime.launchReported()` primitives and a `dispatchReported()` tool helper (with a synchronous fallback when no runtime is available, preserving prior behavior and unit tests).
|
package/README.de.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## Skill-Verhalten
|
package/README.es.md
CHANGED
|
@@ -330,10 +330,11 @@ Esto preserva tanto el **artefacto original** como una **vista extraída normali
|
|
|
330
330
|
|
|
331
331
|
Usa el wiki desde **cualquier herramienta compatible con MCP** — Claude Code, Cursor, Windsurf y otras.
|
|
332
332
|
|
|
333
|
-
El paquete incluye un servidor MCP independiente que expone
|
|
333
|
+
El paquete incluye un servidor MCP independiente que expone 6 herramientas de wiki por stdio:
|
|
334
334
|
|
|
335
335
|
| Herramienta | Descripción |
|
|
336
336
|
|-------------|-------------|
|
|
337
|
+
| `wiki_bootstrap` | Inicializa un nuevo vault de wiki con configuración, plantillas, esquema y metadatos |
|
|
337
338
|
| `wiki_recall` | Busca en el wiki páginas relevantes para la tarea |
|
|
338
339
|
| `wiki_search` | Búsqueda completa del registro |
|
|
339
340
|
| `wiki_status` | Estadísticas del wiki (conteos de páginas, desglose por tipo) |
|
|
@@ -347,11 +348,29 @@ El paquete incluye un servidor MCP independiente que expone 5 herramientas de wi
|
|
|
347
348
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
348
349
|
|
|
349
350
|
# Independiente con cualquier cliente MCP:
|
|
350
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
351
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
351
352
|
```
|
|
352
353
|
|
|
353
354
|
Establece `WIKI_ROOT` en el directorio de tu vault de wiki. Si no está establecido, el servidor lo detecta automáticamente desde el directorio de trabajo actual.
|
|
354
355
|
|
|
356
|
+
### Configuración del cliente
|
|
357
|
+
|
|
358
|
+
El mismo servidor como entrada en `.mcp.json` (Claude Code) o `claude_desktop_config.json`:
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"mcpServers": {
|
|
363
|
+
"llm-wiki": {
|
|
364
|
+
"command": "node",
|
|
365
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
366
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
> Los clientes MCP lanzan el comando **sin shell**, por lo que `~` nunca se expande. Un `~/my-wiki` en `args` o `env` se pasa literalmente y el servidor no arranca, algo que el cliente solo informa como un error de conexión genérico: usa rutas absolutas aquí. El fragmento de shell anterior sí funciona, porque tu shell expande `~` antes de que `node` lo reciba.
|
|
373
|
+
|
|
355
374
|
---
|
|
356
375
|
|
|
357
376
|
## Comportamiento de la Habilidad
|
package/README.fr.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## Comportement de la Compétence
|
package/README.hi.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## स्किल व्यवहार
|
package/README.ja.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## スキルの動作
|
package/README.ko.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## 스킬 동작
|
package/README.md
CHANGED
|
@@ -342,10 +342,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
342
342
|
|
|
343
343
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
344
344
|
|
|
345
|
-
The package ships a standalone MCP server exposing
|
|
345
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
346
346
|
|
|
347
347
|
| Tool | Description |
|
|
348
348
|
|------|-------------|
|
|
349
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
349
350
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
350
351
|
| `wiki_search` | Full registry search |
|
|
351
352
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -359,11 +360,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
359
360
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
360
361
|
|
|
361
362
|
# Standalone with any MCP client:
|
|
362
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
363
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
363
364
|
```
|
|
364
365
|
|
|
365
366
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
366
367
|
|
|
368
|
+
### Client configuration
|
|
369
|
+
|
|
370
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"mcpServers": {
|
|
375
|
+
"llm-wiki": {
|
|
376
|
+
"command": "node",
|
|
377
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
378
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
385
|
+
|
|
367
386
|
---
|
|
368
387
|
|
|
369
388
|
## Skill Behavior
|
|
@@ -462,6 +481,13 @@ Thanks to everyone who has contributed! This list is regenerated automatically b
|
|
|
462
481
|
<sub><b>James Fraser</b></sub>
|
|
463
482
|
</a>
|
|
464
483
|
</td>
|
|
484
|
+
<td align="center">
|
|
485
|
+
<a href="https://github.com/mkuhl">
|
|
486
|
+
<img src="https://avatars.githubusercontent.com/u/61073?v=4" width="64;" alt="mkuhl"/>
|
|
487
|
+
<br />
|
|
488
|
+
<sub><b>Mike P. Kuhl</b></sub>
|
|
489
|
+
</a>
|
|
490
|
+
</td>
|
|
465
491
|
<td align="center">
|
|
466
492
|
<a href="https://github.com/CelestialCreator">
|
|
467
493
|
<img src="https://avatars.githubusercontent.com/u/177931942?v=4" width="64;" alt="CelestialCreator"/>
|
|
@@ -490,6 +516,8 @@ Thanks to everyone who has contributed! This list is regenerated automatically b
|
|
|
490
516
|
<sub><b>Superdao</b></sub>
|
|
491
517
|
</a>
|
|
492
518
|
</td>
|
|
519
|
+
</tr>
|
|
520
|
+
<tr>
|
|
493
521
|
<td align="center">
|
|
494
522
|
<a href="https://github.com/mystery4f">
|
|
495
523
|
<img src="https://avatars.githubusercontent.com/u/40482524?v=4" width="64;" alt="mystery4f"/>
|
package/README.pt.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## Comportamento da Skill
|
package/README.ru.md
CHANGED
|
@@ -346,10 +346,11 @@ This preserves both the **original artifact** and a **normalized extracted view*
|
|
|
346
346
|
|
|
347
347
|
Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
|
|
348
348
|
|
|
349
|
-
The package ships a standalone MCP server exposing
|
|
349
|
+
The package ships a standalone MCP server exposing 6 wiki tools over stdio:
|
|
350
350
|
|
|
351
351
|
| Tool | Description |
|
|
352
352
|
|------|-------------|
|
|
353
|
+
| `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
|
|
353
354
|
| `wiki_recall` | Search wiki for task-relevant pages |
|
|
354
355
|
| `wiki_search` | Full registry search |
|
|
355
356
|
| `wiki_status` | Wiki stats (page counts, type breakdown) |
|
|
@@ -363,11 +364,29 @@ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
|
|
|
363
364
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
364
365
|
|
|
365
366
|
# Standalone with any MCP client:
|
|
366
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
367
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
367
368
|
```
|
|
368
369
|
|
|
369
370
|
Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
|
|
370
371
|
|
|
372
|
+
### Client configuration
|
|
373
|
+
|
|
374
|
+
The same server as an entry in `.mcp.json` (Claude Code) or `claude_desktop_config.json`:
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"llm-wiki": {
|
|
380
|
+
"command": "node",
|
|
381
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
382
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> MCP clients spawn the command **without a shell**, so `~` is never expanded. A `~/my-wiki` in `args` or `env` is passed through literally and the server fails to start, which the client reports only as a generic connection error — use absolute paths here. The shell snippet above is fine: your shell expands `~` before `node` sees it.
|
|
389
|
+
|
|
371
390
|
---
|
|
372
391
|
|
|
373
392
|
## Поведение навыка
|
package/README.zh.md
CHANGED
|
@@ -330,10 +330,11 @@ my-wiki/
|
|
|
330
330
|
|
|
331
331
|
从 **任何 MCP 兼容工具** 使用 wiki——Claude Code、Cursor、Windsurf 等。
|
|
332
332
|
|
|
333
|
-
包附带独立 MCP 服务器,通过 stdio 暴露
|
|
333
|
+
包附带独立 MCP 服务器,通过 stdio 暴露 6 个 wiki 工具:
|
|
334
334
|
|
|
335
335
|
| 工具 | 描述 |
|
|
336
336
|
|------|------|
|
|
337
|
+
| `wiki_bootstrap` | 用配置、模板、模式和元数据初始化新的 wiki vault |
|
|
337
338
|
| `wiki_recall` | 搜索 wiki 中与任务相关的页面 |
|
|
338
339
|
| `wiki_search` | 完整注册表搜索 |
|
|
339
340
|
| `wiki_status` | Wiki 统计(页面计数、类型分解) |
|
|
@@ -347,11 +348,29 @@ my-wiki/
|
|
|
347
348
|
pi install npm:@zosmaai/pi-llm-wiki
|
|
348
349
|
|
|
349
350
|
# 独立使用任何 MCP 客户端:
|
|
350
|
-
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
|
|
351
|
+
WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js
|
|
351
352
|
```
|
|
352
353
|
|
|
353
354
|
设置 `WIKI_ROOT` 为您的 wiki vault 目录。如果未设置,服务器从当前工作目录自动检测。
|
|
354
355
|
|
|
356
|
+
### 客户端配置
|
|
357
|
+
|
|
358
|
+
在 `.mcp.json`(Claude Code)或 `claude_desktop_config.json` 中配置同一个服务器:
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"mcpServers": {
|
|
363
|
+
"llm-wiki": {
|
|
364
|
+
"command": "node",
|
|
365
|
+
"args": ["/absolute/path/to/node_modules/@zosmaai/pi-llm-wiki/dist/mcp/index.js"],
|
|
366
|
+
"env": { "WIKI_ROOT": "/absolute/path/to/my-wiki" }
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
> MCP 客户端在**不经过 shell** 的情况下启动该命令,因此 `~` 不会被展开。`args` 或 `env` 中的 `~/my-wiki` 会被原样传递,服务器随即启动失败,而客户端只会报告一个笼统的连接错误——这里请使用绝对路径。上面的 shell 命令没有问题:`~` 由你的 shell 在 `node` 收到之前展开。
|
|
373
|
+
|
|
355
374
|
---
|
|
356
375
|
|
|
357
376
|
## 技能行为
|
|
@@ -143,9 +143,21 @@ export class Runtime {
|
|
|
143
143
|
*/
|
|
144
144
|
launchReported(ctx, label, work) {
|
|
145
145
|
return this.launchTask(ctx, label, async () => {
|
|
146
|
+
// Capture synchronously — after `await work()` the extension ctx may be
|
|
147
|
+
// a stale proxy (newSession/fork/switchSession/reload) and accessing
|
|
148
|
+
// ctx.hasUI or ctx.ui on it throws (see launchTask).
|
|
149
|
+
const hasUI = ctx.hasUI;
|
|
150
|
+
const ui = ctx.ui;
|
|
146
151
|
const summary = await work();
|
|
147
|
-
if (summary)
|
|
152
|
+
if (summary) {
|
|
153
|
+
// Instant completion feedback: the nextTurn report below is queued for
|
|
154
|
+
// the next user prompt, so without a toast a background task looks
|
|
155
|
+
// stuck. Mirrors the failure notification in launchTask and the
|
|
156
|
+
// success toast already used by wiki_ingest.
|
|
157
|
+
if (hasUI && ui)
|
|
158
|
+
ui.notify(summary.split("\n")[0].replace(/\*\*/g, ""), "info");
|
|
148
159
|
this.report(summary);
|
|
160
|
+
}
|
|
149
161
|
});
|
|
150
162
|
}
|
|
151
163
|
/**
|
|
@@ -694,7 +694,7 @@ export function registerWikiLint(pi, runtime) {
|
|
|
694
694
|
// run it in the background and report the health summary (issue #77).
|
|
695
695
|
return dispatchReported(runtime, ctx, {
|
|
696
696
|
label: `lint:${paths.root}`,
|
|
697
|
-
started: "\u{1F9F9} LLM Wiki: lint started in the background — the health report will be posted
|
|
697
|
+
started: "\u{1F9F9} LLM Wiki: lint started in the background — the health report will be posted with your next message.",
|
|
698
698
|
work: async () => runWikiLint(paths, params.auto_fix === true),
|
|
699
699
|
});
|
|
700
700
|
},
|
|
@@ -827,11 +827,14 @@ function runWikiLint(paths, autoFix) {
|
|
|
827
827
|
"",
|
|
828
828
|
].filter(Boolean);
|
|
829
829
|
const reportPath = autoFix ? join(paths.outputs, `lint-${fmtDate()}.md`) : undefined;
|
|
830
|
+
// The gap snapshot is generated discovery metadata consumed by wiki_status:
|
|
831
|
+
// persist it on every successful lint so status never reports a stale count.
|
|
832
|
+
// Corrective actions below (report, event, meta rebuild) stay autoFix-only.
|
|
833
|
+
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
834
|
+
gaps,
|
|
835
|
+
generated: new Date().toISOString(),
|
|
836
|
+
});
|
|
830
837
|
if (autoFix && reportPath) {
|
|
831
|
-
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
832
|
-
gaps,
|
|
833
|
-
generated: new Date().toISOString(),
|
|
834
|
-
});
|
|
835
838
|
mkdirSync(paths.outputs, { recursive: true });
|
|
836
839
|
writeFileSync(reportPath, `${reportLines.join("\n")}\n`, "utf8");
|
|
837
840
|
appendEvent(paths, {
|
|
@@ -954,7 +957,7 @@ export function registerWikiRebuildMeta(pi, runtime) {
|
|
|
954
957
|
// report on completion (issue #77).
|
|
955
958
|
return dispatchReported(runtime, ctx, {
|
|
956
959
|
label: `rebuild_meta:${paths.root}`,
|
|
957
|
-
started: "\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported
|
|
960
|
+
started: "\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported with your next message.",
|
|
958
961
|
work: async () => {
|
|
959
962
|
const result = rebuildMetadata(paths);
|
|
960
963
|
// No rebuild_meta event — rebuild is a projection, not an authoritative mutation
|
|
@@ -1027,7 +1030,7 @@ export function registerWikiReindexEmbeddings(pi, runtime) {
|
|
|
1027
1030
|
// report the stats on completion (issue #77).
|
|
1028
1031
|
return dispatchReported(runtime, ctx, {
|
|
1029
1032
|
label: `reindex_embeddings:${paths.root}`,
|
|
1030
|
-
started: `\u{1F9E0} LLM Wiki: embedding reindex started in the background (${embedder.model}) — stats will be reported
|
|
1033
|
+
started: `\u{1F9E0} LLM Wiki: embedding reindex started in the background (${embedder.model}) — stats will be reported with your next message.`,
|
|
1031
1034
|
details: { enabled: true, model: embedder.model },
|
|
1032
1035
|
work: async () => {
|
|
1033
1036
|
const stats = await reindexEmbeddings(paths, embedder, { force: params.force === true });
|
package/dist/mcp/index.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
|
-
import { McpServer
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
14
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
14
15
|
import * as z from "zod/v4";
|
|
15
|
-
import { resolveVaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
16
|
+
import { getVaultPaths, resolveVaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
16
17
|
import { createExecApi } from "./exec.js";
|
|
17
|
-
import { captureSourceOperation, recallOperation, retroOperation, searchOperation, statusOperation, } from "./operations.js";
|
|
18
|
+
import { bootstrapOperation, captureSourceOperation, recallOperation, retroOperation, searchOperation, statusOperation, } from "./operations.js";
|
|
18
19
|
const execApi = createExecApi();
|
|
19
20
|
// ─── Vault Detection ────────────────────────────────────
|
|
20
21
|
/** Resolve vault paths, same as Pi extension. */
|
|
@@ -22,6 +23,18 @@ function getPaths() {
|
|
|
22
23
|
const root = process.env.WIKI_ROOT || process.cwd();
|
|
23
24
|
return resolveVaultPaths(root);
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* The vault root this server was configured with, without resolution.
|
|
28
|
+
*
|
|
29
|
+
* `getPaths()` RESOLVES an existing vault: on a root that has none it walks up
|
|
30
|
+
* to a parent vault and then falls back to the personal vault. That is right
|
|
31
|
+
* for reading and writing pages, and wrong for creating one — bootstrap must
|
|
32
|
+
* create the vault where the client pointed the server, not wherever
|
|
33
|
+
* resolution lands. The Pi tool draws the same distinction.
|
|
34
|
+
*/
|
|
35
|
+
function getConfiguredPaths() {
|
|
36
|
+
return getVaultPaths(process.env.WIKI_ROOT || process.cwd());
|
|
37
|
+
}
|
|
25
38
|
function hasVault() {
|
|
26
39
|
const paths = getPaths();
|
|
27
40
|
return existsSync(join(paths.dotWiki, "config.json"));
|
|
@@ -31,9 +44,49 @@ const server = new McpServer({
|
|
|
31
44
|
name: "llm-wiki",
|
|
32
45
|
version: "1.0.0",
|
|
33
46
|
});
|
|
47
|
+
// ---- wiki_bootstrap ----
|
|
48
|
+
//
|
|
49
|
+
// Registered first, and the only tool not gated on an existing vault: the
|
|
50
|
+
// other five fail closed with a message naming this one, which an MCP-only
|
|
51
|
+
// client could not act on while it was extension-only (issue #130).
|
|
52
|
+
server.registerTool("wiki_bootstrap", {
|
|
53
|
+
description: "Create an LLM Wiki vault at this server's wiki root (WIKI_ROOT, or the working directory). Writes config, schema, templates and metadata scaffolding. Run this first when no vault exists; safe to re-run on an existing vault, where it updates the config and rebuilds metadata without touching pages.",
|
|
54
|
+
inputSchema: z.object({
|
|
55
|
+
topic: z.string().describe("Main topic of the wiki"),
|
|
56
|
+
mode: z.string().optional().describe("personal or company (default: personal)"),
|
|
57
|
+
}),
|
|
58
|
+
}, async ({ topic, mode }) => {
|
|
59
|
+
const paths = getConfiguredPaths();
|
|
60
|
+
const result = await bootstrapOperation(paths, { topic, mode });
|
|
61
|
+
if (!result.ok) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: `Vault error: ${result.diagnostics[0].message}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const warnings = result.diagnostics.map((d) => `⚠️ ${d.code}: ${d.message}`);
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: "text",
|
|
77
|
+
text: [
|
|
78
|
+
`${result.created ? "Wiki vault created" : "Wiki vault updated"} at ${paths.root}`,
|
|
79
|
+
"Structure: .llm-wiki/{raw,wiki,meta} plus config and WIKI_SCHEMA.md",
|
|
80
|
+
"Next: capture a source with wiki_capture_source, or save an insight with wiki_retro.",
|
|
81
|
+
...warnings,
|
|
82
|
+
].join("\n"),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
34
87
|
// ---- wiki_recall ----
|
|
35
88
|
server.registerTool("wiki_recall", {
|
|
36
|
-
description: "Search the wiki for pages relevant to a query. Returns matching page IDs, titles, types, and content previews.",
|
|
89
|
+
description: "Search the wiki for pages relevant to a query. Searches the resolved vault and the personal vault (~/.llm-wiki) together, deduplicated, with personal hits labelled. Returns matching page IDs, titles, types, and content previews.",
|
|
37
90
|
inputSchema: z.object({
|
|
38
91
|
query: z.string().describe("Search query — use the user's full request or key terms"),
|
|
39
92
|
max_results: z.number().optional().default(5).describe("Max results (default: 5, max: 10)"),
|
package/dist/mcp/operations.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* used by Pi tools. No operation parses YAML, scans files, scores
|
|
6
6
|
* registry entries, or builds page strings itself.
|
|
7
7
|
*/
|
|
8
|
+
import { bootstrapVault } from "../extensions/llm-wiki/lib/bootstrap.js";
|
|
8
9
|
import { rebuildMetadata } from "../extensions/llm-wiki/lib/metadata.js";
|
|
9
|
-
import {
|
|
10
|
+
import { searchWikiLayered } from "../extensions/llm-wiki/lib/recall.js";
|
|
10
11
|
import { saveInsight } from "../extensions/llm-wiki/lib/retro.js";
|
|
11
12
|
import { captureFile, captureText, captureUrl } from "../extensions/llm-wiki/lib/source-packet.js";
|
|
12
13
|
import { VaultWriteError, inspectVaultFormat, inspectWritableVault, } from "../extensions/llm-wiki/lib/vault-format.js";
|
|
@@ -19,9 +20,44 @@ function projectionOutcome(projection) {
|
|
|
19
20
|
diagnostics: projection.diagnostics.map(({ code, message }) => ({ code, message })),
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Shared bootstrap operation: create (or update) the vault at `paths`.
|
|
25
|
+
*
|
|
26
|
+
* This is the one operation that must work when no vault exists — every other
|
|
27
|
+
* one fails closed naming it. `bootstrapVault` is pure Node (`node:fs`,
|
|
28
|
+
* `node:path` and sibling lib modules), so it needs no model and no
|
|
29
|
+
* credentials, which is what makes it fit the MCP surface.
|
|
30
|
+
*
|
|
31
|
+
* A failed projection rebuild is reported as diagnostics alongside `ok: true`:
|
|
32
|
+
* the vault has been written to disk by then, and `wiki_lint` is the repair
|
|
33
|
+
* path, so failing the call outright would misreport what happened.
|
|
34
|
+
*/
|
|
35
|
+
export async function bootstrapOperation(paths, input) {
|
|
36
|
+
const result = bootstrapVault(paths, { topic: input.topic, mode: input.mode ?? "personal" });
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
diagnostics: result.diagnostics.map(({ code, message }) => ({ code, message })),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const projection = projectionOutcome(result.projection);
|
|
44
|
+
return {
|
|
45
|
+
ok: true,
|
|
46
|
+
created: result.created,
|
|
47
|
+
diagnostics: projection.ok ? [] : projection.diagnostics,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Shared recall operation: layered search plus vault diagnostics.
|
|
52
|
+
*
|
|
53
|
+
* Layering is the shared contract, not an extension-only feature: MCP clients
|
|
54
|
+
* get the same personal + project merge the Pi `wiki_recall` tool does.
|
|
55
|
+
* `searchWikiLayered` appends personal-vault hits, deduplicates by page ID and
|
|
56
|
+
* tags personal results with `vaultLabel`. It is a no-op when no personal vault
|
|
57
|
+
* exists, or when the resolved vault IS the personal vault.
|
|
58
|
+
*/
|
|
23
59
|
export async function recallOperation(paths, query, maxResults = 5) {
|
|
24
|
-
const results =
|
|
60
|
+
const results = searchWikiLayered(paths, query, maxResults);
|
|
25
61
|
const vaultState = inspectVaultFormat(paths);
|
|
26
62
|
return {
|
|
27
63
|
results,
|
package/docs/api.md
CHANGED
|
@@ -223,6 +223,10 @@ Deterministic health check of the wiki. Scans for orphan pages (no inbound links
|
|
|
223
223
|
(linked but not created), and contradiction markers. Optionally auto-creates stub pages for
|
|
224
224
|
knowledge gaps cited in two or more pages.
|
|
225
225
|
|
|
226
|
+
Runs **asynchronously**: the tool acknowledges immediately and scans off-thread. On completion a
|
|
227
|
+
UI toast fires instantly (when a UI is available) and the full health report is delivered with
|
|
228
|
+
the next user message.
|
|
229
|
+
|
|
226
230
|
**Parameters**
|
|
227
231
|
|
|
228
232
|
| Name | Type | Required | Description |
|
|
@@ -277,9 +281,13 @@ Health is `"⚠️ Warning"` when orphan count exceeds 5, `"🔴 Empty"` when th
|
|
|
277
281
|
|
|
278
282
|
## wiki_rebuild_meta
|
|
279
283
|
|
|
280
|
-
Force a full
|
|
284
|
+
Force a full rebuild of all generated metadata: `registry.json`, `backlinks.json`,
|
|
281
285
|
`index.md`, `log.md`. Use when metadata appears out of sync with actual wiki files.
|
|
282
286
|
|
|
287
|
+
Runs **asynchronously**: the tool acknowledges immediately and rebuilds off-thread. On completion
|
|
288
|
+
a UI toast fires instantly (when a UI is available) and the result is delivered with the next
|
|
289
|
+
user message.
|
|
290
|
+
|
|
283
291
|
If `meta/events.jsonl` is missing or unreadable, rebuild reports a warning and preserves existing log projections while continuing to rebuild registry, backlinks, and indexes. A present zero-byte event file is an intentional empty history.
|
|
284
292
|
|
|
285
293
|
**Parameters**
|
|
@@ -213,8 +213,20 @@ export class Runtime {
|
|
|
213
213
|
*/
|
|
214
214
|
launchReported(ctx: LaunchCtx, label: string, work: () => Promise<string | null>): Promise<void> {
|
|
215
215
|
return this.launchTask(ctx, label, async () => {
|
|
216
|
+
// Capture synchronously — after `await work()` the extension ctx may be
|
|
217
|
+
// a stale proxy (newSession/fork/switchSession/reload) and accessing
|
|
218
|
+
// ctx.hasUI or ctx.ui on it throws (see launchTask).
|
|
219
|
+
const hasUI = ctx.hasUI;
|
|
220
|
+
const ui = ctx.ui;
|
|
216
221
|
const summary = await work();
|
|
217
|
-
if (summary)
|
|
222
|
+
if (summary) {
|
|
223
|
+
// Instant completion feedback: the nextTurn report below is queued for
|
|
224
|
+
// the next user prompt, so without a toast a background task looks
|
|
225
|
+
// stuck. Mirrors the failure notification in launchTask and the
|
|
226
|
+
// success toast already used by wiki_ingest.
|
|
227
|
+
if (hasUI && ui) ui.notify(summary.split("\n")[0].replace(/\*\*/g, ""), "info");
|
|
228
|
+
this.report(summary);
|
|
229
|
+
}
|
|
218
230
|
});
|
|
219
231
|
}
|
|
220
232
|
|
|
@@ -821,7 +821,7 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
821
821
|
return dispatchReported(runtime, ctx as ToolCtx, {
|
|
822
822
|
label: `lint:${paths.root}`,
|
|
823
823
|
started:
|
|
824
|
-
"\u{1F9F9} LLM Wiki: lint started in the background — the health report will be posted
|
|
824
|
+
"\u{1F9F9} LLM Wiki: lint started in the background — the health report will be posted with your next message.",
|
|
825
825
|
work: async () => runWikiLint(paths, params.auto_fix === true),
|
|
826
826
|
});
|
|
827
827
|
},
|
|
@@ -962,11 +962,14 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
962
962
|
"",
|
|
963
963
|
].filter(Boolean);
|
|
964
964
|
const reportPath = autoFix ? join(paths.outputs, `lint-${fmtDate()}.md`) : undefined;
|
|
965
|
+
// The gap snapshot is generated discovery metadata consumed by wiki_status:
|
|
966
|
+
// persist it on every successful lint so status never reports a stale count.
|
|
967
|
+
// Corrective actions below (report, event, meta rebuild) stay autoFix-only.
|
|
968
|
+
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
969
|
+
gaps,
|
|
970
|
+
generated: new Date().toISOString(),
|
|
971
|
+
});
|
|
965
972
|
if (autoFix && reportPath) {
|
|
966
|
-
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
967
|
-
gaps,
|
|
968
|
-
generated: new Date().toISOString(),
|
|
969
|
-
});
|
|
970
973
|
mkdirSync(paths.outputs, { recursive: true });
|
|
971
974
|
writeFileSync(reportPath, `${reportLines.join("\n")}\n`, "utf8");
|
|
972
975
|
appendEvent(paths, {
|
|
@@ -1106,7 +1109,7 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1106
1109
|
return dispatchReported(runtime, ctx as ToolCtx, {
|
|
1107
1110
|
label: `rebuild_meta:${paths.root}`,
|
|
1108
1111
|
started:
|
|
1109
|
-
"\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported
|
|
1112
|
+
"\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported with your next message.",
|
|
1110
1113
|
work: async () => {
|
|
1111
1114
|
const result = rebuildMetadata(paths);
|
|
1112
1115
|
// No rebuild_meta event — rebuild is a projection, not an authoritative mutation
|
|
@@ -1187,7 +1190,7 @@ export function registerWikiReindexEmbeddings(pi: ExtensionAPI, runtime?: Runtim
|
|
|
1187
1190
|
// report the stats on completion (issue #77).
|
|
1188
1191
|
return dispatchReported(runtime, ctx as ToolCtx, {
|
|
1189
1192
|
label: `reindex_embeddings:${paths.root}`,
|
|
1190
|
-
started: `\u{1F9E0} LLM Wiki: embedding reindex started in the background (${embedder.model}) — stats will be reported
|
|
1193
|
+
started: `\u{1F9E0} LLM Wiki: embedding reindex started in the background (${embedder.model}) — stats will be reported with your next message.`,
|
|
1191
1194
|
details: { enabled: true, model: embedder.model },
|
|
1192
1195
|
work: async () => {
|
|
1193
1196
|
const stats = await reindexEmbeddings(paths, embedder, { force: params.force === true });
|
package/mcp/index.ts
CHANGED
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
import { existsSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
15
|
-
import { McpServer
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
16
17
|
import * as z from "zod/v4";
|
|
17
|
-
import { resolveVaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
18
|
+
import { getVaultPaths, resolveVaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
18
19
|
import { createExecApi } from "./exec.js";
|
|
19
20
|
import {
|
|
21
|
+
bootstrapOperation,
|
|
20
22
|
captureSourceOperation,
|
|
21
23
|
recallOperation,
|
|
22
24
|
retroOperation,
|
|
@@ -34,6 +36,19 @@ function getPaths(): ReturnType<typeof resolveVaultPaths> {
|
|
|
34
36
|
return resolveVaultPaths(root);
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The vault root this server was configured with, without resolution.
|
|
41
|
+
*
|
|
42
|
+
* `getPaths()` RESOLVES an existing vault: on a root that has none it walks up
|
|
43
|
+
* to a parent vault and then falls back to the personal vault. That is right
|
|
44
|
+
* for reading and writing pages, and wrong for creating one — bootstrap must
|
|
45
|
+
* create the vault where the client pointed the server, not wherever
|
|
46
|
+
* resolution lands. The Pi tool draws the same distinction.
|
|
47
|
+
*/
|
|
48
|
+
function getConfiguredPaths(): ReturnType<typeof getVaultPaths> {
|
|
49
|
+
return getVaultPaths(process.env.WIKI_ROOT || process.cwd());
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
function hasVault(): boolean {
|
|
38
53
|
const paths = getPaths();
|
|
39
54
|
return existsSync(join(paths.dotWiki, "config.json"));
|
|
@@ -46,13 +61,62 @@ const server = new McpServer({
|
|
|
46
61
|
version: "1.0.0",
|
|
47
62
|
});
|
|
48
63
|
|
|
64
|
+
// ---- wiki_bootstrap ----
|
|
65
|
+
//
|
|
66
|
+
// Registered first, and the only tool not gated on an existing vault: the
|
|
67
|
+
// other five fail closed with a message naming this one, which an MCP-only
|
|
68
|
+
// client could not act on while it was extension-only (issue #130).
|
|
69
|
+
|
|
70
|
+
server.registerTool(
|
|
71
|
+
"wiki_bootstrap",
|
|
72
|
+
{
|
|
73
|
+
description:
|
|
74
|
+
"Create an LLM Wiki vault at this server's wiki root (WIKI_ROOT, or the working directory). Writes config, schema, templates and metadata scaffolding. Run this first when no vault exists; safe to re-run on an existing vault, where it updates the config and rebuilds metadata without touching pages.",
|
|
75
|
+
inputSchema: z.object({
|
|
76
|
+
topic: z.string().describe("Main topic of the wiki"),
|
|
77
|
+
mode: z.string().optional().describe("personal or company (default: personal)"),
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
async ({ topic, mode }) => {
|
|
81
|
+
const paths = getConfiguredPaths();
|
|
82
|
+
const result = await bootstrapOperation(paths, { topic, mode });
|
|
83
|
+
|
|
84
|
+
if (!result.ok) {
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text" as const,
|
|
89
|
+
text: `Vault error: ${result.diagnostics[0].message}`,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const warnings = result.diagnostics.map((d) => `⚠️ ${d.code}: ${d.message}`);
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text" as const,
|
|
101
|
+
text: [
|
|
102
|
+
`${result.created ? "Wiki vault created" : "Wiki vault updated"} at ${paths.root}`,
|
|
103
|
+
"Structure: .llm-wiki/{raw,wiki,meta} plus config and WIKI_SCHEMA.md",
|
|
104
|
+
"Next: capture a source with wiki_capture_source, or save an insight with wiki_retro.",
|
|
105
|
+
...warnings,
|
|
106
|
+
].join("\n"),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
49
113
|
// ---- wiki_recall ----
|
|
50
114
|
|
|
51
115
|
server.registerTool(
|
|
52
116
|
"wiki_recall",
|
|
53
117
|
{
|
|
54
118
|
description:
|
|
55
|
-
"Search the wiki for pages relevant to a query. Returns matching page IDs, titles, types, and content previews.",
|
|
119
|
+
"Search the wiki for pages relevant to a query. Searches the resolved vault and the personal vault (~/.llm-wiki) together, deduplicated, with personal hits labelled. Returns matching page IDs, titles, types, and content previews.",
|
|
56
120
|
inputSchema: z.object({
|
|
57
121
|
query: z.string().describe("Search query — use the user's full request or key terms"),
|
|
58
122
|
max_results: z.number().optional().default(5).describe("Max results (default: 5, max: 10)"),
|
package/mcp/operations.ts
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import { bootstrapVault } from "../extensions/llm-wiki/lib/bootstrap.js";
|
|
10
11
|
import { type ProjectionResult, rebuildMetadata } from "../extensions/llm-wiki/lib/metadata.js";
|
|
11
|
-
import {
|
|
12
|
+
import { type RecallResult, searchWikiLayered } from "../extensions/llm-wiki/lib/recall.js";
|
|
12
13
|
import { saveInsight } from "../extensions/llm-wiki/lib/retro.js";
|
|
13
14
|
import { captureFile, captureText, captureUrl } from "../extensions/llm-wiki/lib/source-packet.js";
|
|
14
15
|
import type { VaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
@@ -30,16 +31,58 @@ function projectionOutcome(
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Shared bootstrap operation: create (or update) the vault at `paths`.
|
|
36
|
+
*
|
|
37
|
+
* This is the one operation that must work when no vault exists — every other
|
|
38
|
+
* one fails closed naming it. `bootstrapVault` is pure Node (`node:fs`,
|
|
39
|
+
* `node:path` and sibling lib modules), so it needs no model and no
|
|
40
|
+
* credentials, which is what makes it fit the MCP surface.
|
|
41
|
+
*
|
|
42
|
+
* A failed projection rebuild is reported as diagnostics alongside `ok: true`:
|
|
43
|
+
* the vault has been written to disk by then, and `wiki_lint` is the repair
|
|
44
|
+
* path, so failing the call outright would misreport what happened.
|
|
45
|
+
*/
|
|
46
|
+
export async function bootstrapOperation(
|
|
47
|
+
paths: VaultPaths,
|
|
48
|
+
input: { topic: string; mode?: string },
|
|
49
|
+
): Promise<
|
|
50
|
+
| { ok: true; created: boolean; diagnostics: Array<{ code: string; message: string }> }
|
|
51
|
+
| { ok: false; diagnostics: Array<{ code: string; message: string }> }
|
|
52
|
+
> {
|
|
53
|
+
const result = bootstrapVault(paths, { topic: input.topic, mode: input.mode ?? "personal" });
|
|
54
|
+
if (!result.ok) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
diagnostics: result.diagnostics.map(({ code, message }) => ({ code, message })),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const projection = projectionOutcome(result.projection);
|
|
61
|
+
return {
|
|
62
|
+
ok: true,
|
|
63
|
+
created: result.created,
|
|
64
|
+
diagnostics: projection.ok ? [] : projection.diagnostics,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Shared recall operation: layered search plus vault diagnostics.
|
|
70
|
+
*
|
|
71
|
+
* Layering is the shared contract, not an extension-only feature: MCP clients
|
|
72
|
+
* get the same personal + project merge the Pi `wiki_recall` tool does.
|
|
73
|
+
* `searchWikiLayered` appends personal-vault hits, deduplicates by page ID and
|
|
74
|
+
* tags personal results with `vaultLabel`. It is a no-op when no personal vault
|
|
75
|
+
* exists, or when the resolved vault IS the personal vault.
|
|
76
|
+
*/
|
|
34
77
|
export async function recallOperation(
|
|
35
78
|
paths: VaultPaths,
|
|
36
79
|
query: string,
|
|
37
80
|
maxResults = 5,
|
|
38
81
|
): Promise<{
|
|
39
|
-
results:
|
|
82
|
+
results: RecallResult[];
|
|
40
83
|
diagnostics: Array<{ code: string; message: string }>;
|
|
41
84
|
}> {
|
|
42
|
-
const results =
|
|
85
|
+
const results = searchWikiLayered(paths, query, maxResults);
|
|
43
86
|
const vaultState = inspectVaultFormat(paths);
|
|
44
87
|
return {
|
|
45
88
|
results,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zosmaai/pi-llm-wiki",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "Self-maintaining LLM Wiki for Pi — Karpathy-pattern knowledge base with immutable source capture, automated ingestion, search, linting, and Obsidian-compatible vault. auto-updating personal & company wiki.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@cfworker/json-schema": "^4.1.1",
|
|
76
|
-
"@modelcontextprotocol/server": "^2.0.0
|
|
76
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
77
77
|
"mdast-util-from-markdown": "^2.0.3",
|
|
78
78
|
"node-html-markdown": "^2.0.0",
|
|
79
79
|
"yaml": "^2.9.0",
|