pi-vault-mind 0.16.6 → 0.16.7
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 +23 -0
- package/README.md +10 -35
- package/dist/src/server.js +9 -8
- package/dist/test/personalize.test.js +8 -8
- package/dist/test/rest-vm.test.js +16 -9
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.7 / 0.6.10 — 2026-07-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Obsidian Markdown lifecycle.** Assistant Markdown renders through Obsidian's native renderer, renderer components unload on panel close or remount, stale asynchronous opens cannot remount a closed panel, and deferred message fills cannot hijack a replacement message placeholder.
|
|
8
|
+
- **Generated sandbox constants.** Root builds now format the sandbox extension-package catalog they regenerate, so the release build cannot invalidate the sandbox verification suite.
|
|
9
|
+
- **Repository-only documentation.** Removed the obsolete MkDocs configuration, GitHub Pages deployment workflow, publication badges, and generated-site instructions while retaining maintained Markdown documentation in the repository.
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
|
|
13
|
+
- Added focused regressions for Markdown cleanup ownership, direct remount disposal, close-during-refresh cancellation, and deferred placeholder isolation.
|
|
14
|
+
|
|
15
|
+
## 0.6.9 — 2026-07-18
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **First-run personalization recovery.** The configured-vault onboarding card now retains its active personalization state until durable runtime status confirms completion, including when the prompt acknowledgement fails or a permission request is pending. The chat feed and composer remain correctly gated until then.
|
|
20
|
+
- **Portable model selection.** The shared panel contract now passes opaque model IDs end-to-end; the Obsidian adapter resolves each ID to Pi's provider/model RPC payload internally, preserving IDs that contain `/` or `:`.
|
|
21
|
+
|
|
22
|
+
### Tests
|
|
23
|
+
|
|
24
|
+
- Added focused regressions for acknowledgement failure, pending permission delivery, re-entry protection, and exact model-ID selection ordering.
|
|
25
|
+
|
|
3
26
|
## 0.16.6 / 0.6.8 — 2026-07-18
|
|
4
27
|
|
|
5
28
|
### Fixed
|
package/README.md
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/pi-vault-mind)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/mariozechner/pi)
|
|
6
|
-
[](https://kylebrodeur.github.io/pi-vault-mind/)
|
|
7
|
-
[](https://github.com/kylebrodeur/pi-vault-mind/actions/workflows/docs.yml)
|
|
8
6
|
|
|
9
7
|
Passive Obsidian vault extension for the [pi](https://github.com/mariozechner/pi) agent ecosystem. Watches `@agent` markers in your vault, dispatches forked subagents, and stores results in LanceDB with vector + FTS + graph. Multi-agent "Drop & Forget" workflow.
|
|
10
8
|
|
|
@@ -363,19 +361,16 @@ Edit `pi-vault-mind.config.json` to match your domain:
|
|
|
363
361
|
|
|
364
362
|
## Documentation
|
|
365
363
|
|
|
366
|
-
|
|
367
|
-
> The links below point to the source files in this repository.
|
|
364
|
+
Documentation is maintained directly in this repository.
|
|
368
365
|
|
|
369
366
|
### Getting started
|
|
370
367
|
|
|
371
368
|
| Doc | Description |
|
|
372
369
|
|---|---|
|
|
373
|
-
| [
|
|
374
|
-
| [
|
|
375
|
-
| [
|
|
376
|
-
| [
|
|
377
|
-
| [docs/getting-started/CLI_ONLY_WALKTHROUGH.md](docs/getting-started/CLI_ONLY_WALKTHROUGH.md) | Same setup + daily commands, entirely CLI — no Obsidian plugin required |
|
|
378
|
-
| [docs/getting-started/WALKTHROUGH_PROMPT.md](docs/getting-started/WALKTHROUGH_PROMPT.md) | Paste-into-pi guided setup with checkpoints between phases |
|
|
370
|
+
| [Install playbook](docs/_reference/reference_archive/getting-started/INSTALL.md) | Canonical install procedure for the extension, skills, Obsidian plugin, configuration, and external CLIs |
|
|
371
|
+
| [Getting started](docs/_reference/reference_archive/getting-started/GETTING_STARTED.md) | End-to-end setup and daily “drop and forget” workflow |
|
|
372
|
+
| [CLI-only walkthrough](docs/_reference/reference_archive/getting-started/CLI_ONLY_WALKTHROUGH.md) | Setup and daily commands without the Obsidian plugin |
|
|
373
|
+
| [ReturnVape walkthrough](docs/getting-started/WALKTHROUGH.md) | Current guided Obsidian test-vault procedure |
|
|
379
374
|
|
|
380
375
|
### Architecture & design
|
|
381
376
|
|
|
@@ -384,8 +379,6 @@ Edit `pi-vault-mind.config.json` to match your domain:
|
|
|
384
379
|
| [docs/architecture/AGENTS.md](docs/architecture/AGENTS.md) | Agent Roster and Multi-Agent Architecture ("Fork & Review" model) |
|
|
385
380
|
| [docs/architecture/EXTENSION_WIRING.md](docs/architecture/EXTENSION_WIRING.md) | Extension dependencies, runtime wiring, auto-install patterns |
|
|
386
381
|
| [docs/architecture/DISPATCHER_SPEC.md](docs/architecture/DISPATCHER_SPEC.md) | Technical spec for the passive file-watcher and subagent routing — incl. the "Fork & Dispatch" rationale and thread resume |
|
|
387
|
-
| [docs/architecture/AGENTS.md](docs/architecture/AGENTS.md) | Agent roster + the Miner's "Drop & Forget" ingestion pipeline |
|
|
388
|
-
| [docs/integrations/OBSIDIAN_SETUP.md](docs/integrations/OBSIDIAN_SETUP.md) | Recommended Obsidian vault structure, plugins, and CLI |
|
|
389
382
|
|
|
390
383
|
### Modal embedding service (local integration done)
|
|
391
384
|
|
|
@@ -401,8 +394,6 @@ full design.
|
|
|
401
394
|
| Doc | Description |
|
|
402
395
|
|---|---|
|
|
403
396
|
| [docs/integrations/MODAL_EMBEDDING.md](docs/integrations/MODAL_EMBEDDING.md) | Design of record: ADRs, HTTP contract, sync protocol, roadmap for the cloud embedding service |
|
|
404
|
-
| [docs/plans/modal-embedding-plan.md](docs/plans/modal-embedding-plan.md) | **Consolidated plan & next steps** — phases, owners, status, decision gate (in repo, not on the docs site) |
|
|
405
|
-
| [docs/plans/embedding-open-questions.md](docs/plans/embedding-open-questions.md) | Embedding-strategy decision log (decided + open questions) |
|
|
406
397
|
| [modal/](modal/) | The deployable Modal app: embedding service + bulk worker + sync + dataset generator |
|
|
407
398
|
| [eval/](eval/) | Retrieval eval harness + labeled benchmark datasets for picking the canonical model |
|
|
408
399
|
|
|
@@ -412,17 +403,10 @@ full design.
|
|
|
412
403
|
|---|---|
|
|
413
404
|
| [skills/vault-mind/SKILL.md](skills/vault-mind/SKILL.md) | The Manager skill — what pi auto-loads about this extension |
|
|
414
405
|
| [docs/CHANGELOG.md](docs/CHANGELOG.md) | Version history (rename from `pi-knowledge-store` to `pi-vault-mind` was v0.7.0) |
|
|
415
|
-
| [
|
|
416
|
-
| [
|
|
417
|
-
| [
|
|
418
|
-
| [
|
|
419
|
-
|
|
420
|
-
### Testing
|
|
421
|
-
|
|
422
|
-
| Doc | Description |
|
|
423
|
-
|---|---|
|
|
424
|
-
| [docs/testing/TESTING.md](docs/testing/TESTING.md) | Test plan for agent / human / HITL personas, regression suite |
|
|
425
|
-
| [docs/testing/E2E_MANUAL_TEST.md](docs/testing/E2E_MANUAL_TEST.md) | Manual end-to-end verification procedure (watcher → dispatch → vault) |
|
|
406
|
+
| [Tools reference](docs/_reference/reference_archive/tools.md) | Registered Vault Mind tools, parameters, and return shapes |
|
|
407
|
+
| [Commands reference](docs/_reference/reference_archive/commands.md) | Full `/vm` slash command tree |
|
|
408
|
+
| [Configuration reference](docs/_reference/reference_archive/configuration.md) | Complete `pi-vault-mind.config.json` schema |
|
|
409
|
+
| [Skill manifest](docs/_reference/reference_archive/skill.md) | Bundled skills and their trigger phrases |
|
|
426
410
|
|
|
427
411
|
### Development
|
|
428
412
|
|
|
@@ -430,22 +414,13 @@ full design.
|
|
|
430
414
|
|---|---|
|
|
431
415
|
| [docs/development/CONTRIBUTING.md](docs/development/CONTRIBUTING.md) | Dev setup, testing, and commit conventions |
|
|
432
416
|
| [docs/development/PUBLISHING.md](docs/development/PUBLISHING.md) | How to publish this extension to npm |
|
|
433
|
-
| [docs/development/FUTURE_WORK.md](docs/development/FUTURE_WORK.md) | Roadmap — codegraph integration, pagination, TUI rendering, etc. |
|
|
434
|
-
|
|
435
|
-
### Research
|
|
436
|
-
|
|
437
|
-
| Doc | Description |
|
|
438
|
-
|---|---|
|
|
439
|
-
| [docs/research/COMPETITOR_COMPARISON.md](docs/research/COMPETITOR_COMPARISON.md) | Tier 1/2/3 comparison vs. other Obsidian-LLM tools (22 competitors) |
|
|
440
|
-
| [docs/research/naming-decisions.md](docs/research/naming-decisions.md) | Historical record of the 2026-06-06 decision to name the project `pi-vault-mind` |
|
|
441
|
-
| [docs/research/obsidian-links-reviewed.csv](docs/research/obsidian-links-reviewed.csv) | Curated subset of starred Obsidian repos with adoption verdicts |
|
|
442
417
|
|
|
443
418
|
### Archive
|
|
444
419
|
|
|
445
420
|
| Doc | Description |
|
|
446
421
|
|---|---|
|
|
447
422
|
| [docs/_archive/](docs/_archive/) | Historical docs kept for context (e.g. the `pi-knowledge-store` → `pi-vault-mind` rename audit) |
|
|
448
|
-
| [docs/_archive/legacy-audit.md](docs/_archive/legacy-audit.md) | The 2026-06-08 legacy-terminology audit (139 findings, 13 blockers) and its resolution log. Resolved 2026-06-09
|
|
423
|
+
| [docs/_archive/legacy-audit.md](docs/_archive/legacy-audit.md) | The 2026-06-08 legacy-terminology audit (139 findings, 13 blockers) and its resolution log. Resolved 2026-06-09 and archived 2026-06-16. |
|
|
449
424
|
|
|
450
425
|
## Contributing
|
|
451
426
|
|
package/dist/src/server.js
CHANGED
|
@@ -1637,30 +1637,32 @@ async function handleVmSearch(req, res, serverState, overrideBody) {
|
|
|
1637
1637
|
res.end(JSON.stringify({ error: `Unknown mode: ${mode}` }));
|
|
1638
1638
|
return;
|
|
1639
1639
|
}
|
|
1640
|
+
const sources = Array.isArray(body.sources) ? body.sources : ["vault"];
|
|
1641
|
+
const includeVault = sources.includes("vault");
|
|
1640
1642
|
try {
|
|
1641
|
-
let results;
|
|
1643
|
+
let results = [];
|
|
1642
1644
|
let relations;
|
|
1643
1645
|
let message;
|
|
1644
|
-
if (resolvedMode === "hybrid") {
|
|
1646
|
+
if (includeVault && resolvedMode === "hybrid") {
|
|
1645
1647
|
results = await searchHybridRanked(cfg.vaultMind.dataDir, collection, query, limit, cfg.vaultMind, identity);
|
|
1646
1648
|
}
|
|
1647
|
-
else if (resolvedMode === "semantic") {
|
|
1649
|
+
else if (includeVault && resolvedMode === "semantic") {
|
|
1648
1650
|
results = await searchHybrid(cfg.vaultMind.dataDir, collection, query, limit, cfg.vaultMind, identity);
|
|
1649
1651
|
}
|
|
1650
|
-
else if (resolvedMode === "fts") {
|
|
1652
|
+
else if (includeVault && resolvedMode === "fts") {
|
|
1651
1653
|
results = await searchFts(cfg.vaultMind.dataDir, collection, query, limit, cfg.vaultMind, identity);
|
|
1652
1654
|
}
|
|
1653
|
-
else if (resolvedMode === "graph") {
|
|
1655
|
+
else if (includeVault && resolvedMode === "graph") {
|
|
1654
1656
|
const depth = body.depth ?? 1;
|
|
1655
1657
|
const norm = normalizeGraphResult(await queryGraph(cfg.vaultMind.dataDir, cfg.vaultMind, entity, depth, identity));
|
|
1656
1658
|
results = norm.hits;
|
|
1657
1659
|
relations = norm.relations;
|
|
1658
1660
|
message = norm.message;
|
|
1659
1661
|
}
|
|
1660
|
-
else if (resolvedMode === "vault") {
|
|
1662
|
+
else if (includeVault && resolvedMode === "vault") {
|
|
1661
1663
|
results = await searchVaultNative(vaultPath, query, limit, body.tags);
|
|
1662
1664
|
}
|
|
1663
|
-
else {
|
|
1665
|
+
else if (includeVault) {
|
|
1664
1666
|
// mode === "full"
|
|
1665
1667
|
const depth = body.depth ?? 1;
|
|
1666
1668
|
const [hybrid, semantic, fts, graph, vault] = await Promise.all([
|
|
@@ -1709,7 +1711,6 @@ async function handleVmSearch(req, res, serverState, overrideBody) {
|
|
|
1709
1711
|
addResults(vault, "vault");
|
|
1710
1712
|
results = merged.slice(0, limit);
|
|
1711
1713
|
}
|
|
1712
|
-
const sources = Array.isArray(body.sources) ? body.sources : ["vault"];
|
|
1713
1714
|
if (sources.includes("sessions")) {
|
|
1714
1715
|
results = [...results, ...searchSessions(resolveSessionsDir(), query, limit)];
|
|
1715
1716
|
}
|
|
@@ -192,19 +192,19 @@ describe("personalize", () => {
|
|
|
192
192
|
// AGENTS.md was never created, so rejection means it still does not exist.
|
|
193
193
|
assert.equal(fs.existsSync(path.join(testDir, "AGENTS.md")), false);
|
|
194
194
|
});
|
|
195
|
-
it("persists a completion marker even when all suggestions are rejected
|
|
195
|
+
it("persists a completion marker even when all suggestions are rejected", async () => {
|
|
196
196
|
const { runPersonalize } = await import("../src/personalize.js");
|
|
197
197
|
const pi = makePi(JSON.stringify({
|
|
198
198
|
commentary: "No changes needed.",
|
|
199
199
|
files: [
|
|
200
|
-
{ path: ".pi/agent/system.md", action: "
|
|
201
|
-
{ path: "AGENTS.md", action: "
|
|
200
|
+
{ path: ".pi/agent/system.md", action: "create", content: "# System" },
|
|
201
|
+
{ path: "AGENTS.md", action: "create", content: "# Agents" },
|
|
202
202
|
],
|
|
203
203
|
}));
|
|
204
|
-
const ctx = makeCtx(testDir, []);
|
|
204
|
+
const ctx = makeCtx(testDir, [false, false]);
|
|
205
205
|
await runPersonalize(ctx, pi);
|
|
206
206
|
const markerPath = path.join(testDir, ".vault-mind", "personalized.json");
|
|
207
|
-
assert.ok(fs.existsSync(markerPath), "runPersonalize must write a durable completion marker after the flow finishes, even when every
|
|
207
|
+
assert.ok(fs.existsSync(markerPath), "runPersonalize must write a durable completion marker after the flow finishes, even when the user rejects every actionable suggestion");
|
|
208
208
|
const marker = JSON.parse(fs.readFileSync(markerPath, "utf-8"));
|
|
209
209
|
assert.strictEqual(marker.completed, true);
|
|
210
210
|
assert.ok(typeof marker.completedAt === "string");
|
|
@@ -229,11 +229,11 @@ describe("personalize", () => {
|
|
|
229
229
|
const pi = makePi(JSON.stringify({
|
|
230
230
|
commentary: "No changes needed.",
|
|
231
231
|
files: [
|
|
232
|
-
{ path: ".pi/agent/system.md", action: "
|
|
233
|
-
{ path: "AGENTS.md", action: "
|
|
232
|
+
{ path: ".pi/agent/system.md", action: "create", content: "# System" },
|
|
233
|
+
{ path: "AGENTS.md", action: "create", content: "# Agents" },
|
|
234
234
|
],
|
|
235
235
|
}));
|
|
236
|
-
const ctx = makeCtx(testDir, []);
|
|
236
|
+
const ctx = makeCtx(testDir, [false, false]);
|
|
237
237
|
const result = await runPersonalize(ctx, pi);
|
|
238
238
|
assert.ok(result, "runPersonalize must return a result, not void");
|
|
239
239
|
assert.strictEqual(result.completed, true, "all-rejected personalization must resolve as a successful completion");
|
|
@@ -4,6 +4,7 @@ import * as os from "node:os";
|
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { after, before, describe, it } from "node:test";
|
|
6
6
|
import { _resetAuthCache } from "../src/auth.js";
|
|
7
|
+
import { resetConnection } from "../src/lance.js";
|
|
7
8
|
import { fakePi, fetchJson, makeVault, startTestServer, TEST_TOKEN, } from "./helpers/server.js";
|
|
8
9
|
const envVar = "PVM_API_TOKEN";
|
|
9
10
|
describe("REST vm routes", () => {
|
|
@@ -265,8 +266,8 @@ describe("REST vm routes", () => {
|
|
|
265
266
|
assert.ok(Array.isArray(d.sources), "sources should be echoed");
|
|
266
267
|
}
|
|
267
268
|
});
|
|
268
|
-
it("POST /vm/search with
|
|
269
|
-
// Seed a temp sessions dir
|
|
269
|
+
it("POST /vm/search with only sessions succeeds without an available vault index", async () => {
|
|
270
|
+
// Seed a temp sessions dir while the configured LanceDB index remains unavailable.
|
|
270
271
|
const tmpSessions = fs.mkdtempSync(path.join(os.tmpdir(), "pvm-rest-sessions-"));
|
|
271
272
|
const slugDir = path.join(tmpSessions, "--test--");
|
|
272
273
|
fs.mkdirSync(slugDir, { recursive: true });
|
|
@@ -284,18 +285,24 @@ describe("REST vm routes", () => {
|
|
|
284
285
|
const savedDir = process.env.PI_SESSIONS_DIR;
|
|
285
286
|
try {
|
|
286
287
|
process.env.PI_SESSIONS_DIR = tmpSessions;
|
|
288
|
+
resetConnection();
|
|
289
|
+
const vaultIndexPath = path.join(vaultPath, ".lancedb");
|
|
290
|
+
fs.rmSync(vaultIndexPath, { recursive: true, force: true });
|
|
291
|
+
assert.equal(fs.existsSync(vaultIndexPath), false, "the vault index fixture must be absent");
|
|
287
292
|
const { status, body } = await fetchJson(port, "POST", "/vm/search", {
|
|
288
|
-
body: { query: "searchtestquery", mode: "
|
|
293
|
+
body: { query: "searchtestquery", mode: "hybrid", sources: ["sessions"] },
|
|
289
294
|
token: TEST_TOKEN,
|
|
290
295
|
});
|
|
291
|
-
assert.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
assert.equal(status, 200, "sessions-only search must not initialize or query the vault index");
|
|
297
|
+
assert.equal(fs.existsSync(vaultIndexPath), false, "sessions-only search must leave the unavailable vault index untouched");
|
|
298
|
+
const d = body;
|
|
299
|
+
assert.deepEqual(d.sources, ["sessions"], "the response must preserve the isolated source");
|
|
300
|
+
const hits = d.hits;
|
|
301
|
+
assert.ok(hits.length > 0, "sessions-only search should return the seeded session hit");
|
|
302
|
+
assert.ok(hits.every((hit) => hit._source === "session"), "sessions-only search must not merge vault hits");
|
|
297
303
|
}
|
|
298
304
|
finally {
|
|
305
|
+
resetConnection();
|
|
299
306
|
if (savedDir === undefined)
|
|
300
307
|
delete process.env.PI_SESSIONS_DIR;
|
|
301
308
|
else
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-vault-mind",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.7",
|
|
4
4
|
"description": "Passive Obsidian vault extension for pi. Watches @agent markers, dispatches forked subagents (Miner, Broadcaster, Heavy-Lifter), stores in LanceDB with vector + FTS + graph. Multi-agent 'Drop & Forget' workflow for the pi agent ecosystem.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"scripts": {
|
|
65
65
|
"prepare": "husky",
|
|
66
66
|
"check": "biome check --write . && tsc --noEmit",
|
|
67
|
-
"generate-constants": "node scripts/generate-extension-packages-json.mjs && node scripts/generate-config-keys-json.mjs && biome check --write extension-packages.json config-keys.json packages/obsidian/src/extension-packages.json packages/obsidian/src/config-keys.json",
|
|
67
|
+
"generate-constants": "node scripts/generate-extension-packages-json.mjs && node scripts/generate-config-keys-json.mjs && biome check --write extension-packages.json config-keys.json packages/obsidian/src/extension-packages.json packages/obsidian/src/config-keys.json packages/obsidian-ui/src/extension-packages.json",
|
|
68
68
|
"build": "npm run generate-constants && tsc && tsc -p tsconfig.test.json",
|
|
69
69
|
"dev": "tsc --watch",
|
|
70
70
|
"test": "node --test \"dist/test/**/*.test.js\"",
|