pi-vault-mind 0.14.2 → 0.15.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/CHANGELOG.md +70 -0
- package/README.md +1 -0
- package/dist/src/agent-queue.js +11 -2
- package/dist/src/auth.d.ts +10 -10
- package/dist/src/auth.js +14 -18
- package/dist/src/autosync.js +1 -1
- package/dist/src/commands.d.ts +9 -3
- package/dist/src/commands.js +179 -44
- package/dist/src/discover-schema.js +4 -4
- package/dist/src/events.js +6 -9
- package/dist/src/index.js +10 -23
- package/dist/src/modal-config.d.ts +21 -4
- package/dist/src/modal-config.js +28 -7
- package/dist/src/model-router.d.ts +27 -0
- package/dist/src/model-router.js +67 -0
- package/dist/src/personalize.js +17 -3
- package/dist/src/server.d.ts +1 -1
- package/dist/src/server.js +34 -46
- package/dist/src/settings-ui.d.ts +1 -1
- package/dist/src/settings-ui.js +24 -30
- package/dist/src/sync.d.ts +3 -3
- package/dist/src/sync.js +16 -12
- package/dist/src/tools.js +3 -3
- package/dist/src/types.d.ts +23 -0
- package/dist/src/utils.d.ts +66 -5
- package/dist/src/utils.js +164 -25
- package/dist/src/vault-writer.js +4 -1
- package/dist/src/vm-handlers.js +3 -3
- package/dist/src/watcher.js +2 -2
- package/dist/test/auth.test.js +28 -30
- package/dist/test/bridge-identity.test.js +3 -1
- package/dist/test/discover-schema.test.js +8 -5
- package/dist/test/dispatch.test.js +6 -2
- package/dist/test/index.test.js +4 -2
- package/dist/test/modal-config.test.js +8 -8
- package/dist/test/model-router.test.js +99 -0
- package/dist/test/rest-queue.test.js +15 -16
- package/dist/test/rest-setup.test.js +12 -14
- package/dist/test/rest-vm.test.js +12 -15
- package/dist/test/server-ws.test.js +22 -19
- package/dist/test/settings-ui.test.js +66 -3
- package/dist/test/sync.test.js +10 -11
- package/dist/test/tombstone.test.js +7 -9
- package/dist/test/vault-tools.test.js +7 -9
- package/package.json +97 -90
- package/pi-vault-mind.config.example.json +15 -1
- package/scripts/check-deps.sh +0 -0
- package/scripts/e2e-ws.mjs +3 -2
- package/scripts/fetch-modal-token.sh +4 -3
- package/scripts/pi-session-query +0 -0
- package/scripts/publish-obsidian-plugin.sh +0 -0
- package/scripts/reset-test-vault.sh +2 -2
- package/scripts/setup-test-config.sh +0 -0
- package/scripts/setup-vault-pi.sh +29 -7
- package/scripts/vault-pi.sh +12 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 0.15.0 / 0.6.4 — 2026-07-06
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- **`/vm setup` now scaffolds `.vault-mind/.pi/model-router.json`** with tuned
|
|
9
|
+
primary/fallback model defaults, extracted verbatim from the Obsidian
|
|
10
|
+
plugin's `scaffoldModelRouterConfig`/`defaultModelRouterChoices` into a new
|
|
11
|
+
`src/model-router.ts` — previously only the plugin's init flow produced
|
|
12
|
+
this file, so a CLI-only setup got no model-router config at all.
|
|
13
|
+
- **`scripts/setup-vault-pi.sh` now installs `pi-model-discovery` and
|
|
14
|
+
`pi-model-router`** alongside `pi-vault-mind`/`pi-context`, matching the
|
|
15
|
+
plugin's install list (previously missing both, so a CLI-only setup never
|
|
16
|
+
got model discovery or routing installed).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Vault isolation** — all pi-vault-mind config, token, and written artifacts now live under `<vault>/.vault-mind/`. The global `~/.pi/agent/vault-mind.config.json` layer is dropped; config is single-layer, vault-local. Legacy config/token is auto-migrated on first session_start (idempotent).
|
|
21
|
+
- **Config consolidation** — `loadConfig` reads only `<vault>/.vault-mind/vault-mind.config.json`; `findConfig` returns a single project path. `getGlobalConfigPath`/`getGlobalConfigDir` removed.
|
|
22
|
+
- **Token env** — `PVM_API_TOKEN` dotenv file moved from `~/.pi/agent/vault-mind.env` to `<vault>/.vault-mind/vault-mind.env`. `auth.ts`, `modal-config.ts`, `commands.ts`, and `settings-ui.ts` all resolve via `getTokenEnvPath(cwd)`.
|
|
23
|
+
- **Framework agent dir** — launch scripts now use `<vault>/.vault-mind/.pi/agent` (relocated from `<vault>/.pi/agent`). `resolveAgentDir(cwd)` honors `PI_CODING_AGENT_DIR` via the SDK.
|
|
24
|
+
- **ACM gate** — auto-ACM now fires only when `isVaultMindReady` is true (config exists + embedding configured), not on any vault with a global config.
|
|
25
|
+
- **Configurable file paths** — `graph.canvasPath`, `files.queue`, `files.serverState`, `files.manualDispatch` in config; `resolveVaultFile` resolves them with defaults under `.vault-mind/`.
|
|
26
|
+
- **Per-vault Modal collection prefix** — `vaults.default.collectionPrefix` (auto-derived from vault slug) isolates server-side Modal tables across vaults sharing a deployment. Local LanceDB tables stay unprefixed.
|
|
27
|
+
- **`/vm setup` consolidation** — now runs `migrateLegacyState` → `setupWizard` → merge-safe scaffold → optional `runPersonalize`. `/vm init` is deprecated (still works, shows notice).
|
|
28
|
+
- **`/vm doctor`** — new command reporting resolved paths, readiness, token source, model-router status, and PASS/WARN for vault isolation.
|
|
29
|
+
- **`GET /vault-mind/paths`** — new auth-gated HTTP endpoint returning absolute + vault-relative paths with `exists` flags.
|
|
30
|
+
- **gitignore** — `.vault-mind/*` + `!.vault-mind/vault-mind.config.json` keeps the hand-tuned config tracked while ignoring local state.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Config write-target bugs** — `vm_configure`, `discover_schema`, and the
|
|
35
|
+
`POST /vm/init` HTTP handler's scaffold-if-missing path all still wrote to
|
|
36
|
+
the vault-root `pi-vault-mind.config.json` (a path `loadConfig` no longer
|
|
37
|
+
reads) instead of `.vault-mind/vault-mind.config.json`. Fixed to use
|
|
38
|
+
`getConfigPath(cwd)` uniformly.
|
|
39
|
+
- **Stale user/dev-facing config paths** — the "no vaults configured" notify
|
|
40
|
+
string (`commands.ts`), the `discover_schema` tool's prompt guidelines, and
|
|
41
|
+
a `server.ts` doc-comment all still told the reader to edit the retired
|
|
42
|
+
`pi-vault-mind.config.json` instead of `.vault-mind/vault-mind.config.json`.
|
|
43
|
+
- **`/vm setup` CLI-mode arg parsing** — when `--vault` was the first flag
|
|
44
|
+
(exactly the form documented in `CLI_ONLY_WALKTHROUGH.md`), its leading
|
|
45
|
+
`--` was never stripped by the tokenizer, so `cliArgs.vault` was silently
|
|
46
|
+
never set and `vaults.default.path` was left empty. Fixed the split to
|
|
47
|
+
normalize the leading `--` before tokenizing.
|
|
48
|
+
|
|
49
|
+
### Removed
|
|
50
|
+
|
|
51
|
+
- Dead `events.ts` hidden `/acm` sendMessage path (never enabled compaction).
|
|
52
|
+
- `handleVaultMindConfig` HTTP response no longer splits `.global`/`.project` (single `config` key).
|
|
53
|
+
|
|
54
|
+
### Plugin (`packages/obsidian/`)
|
|
55
|
+
|
|
56
|
+
- **Isolation parity with the extension** — `resolvePluginAgentDir(vaultPath)`
|
|
57
|
+
now resolves `<vault>/.vault-mind/.pi/agent`, threaded through `main.ts`
|
|
58
|
+
(init flow, config paths, hasExtensions checks, token/1Password flow),
|
|
59
|
+
`model-router-config.ts` (models.json + model-router.json paths),
|
|
60
|
+
`pi-config-reader.ts`, `chat-tab.ts`, `status-tab.ts`, and `panel.ts`.
|
|
61
|
+
- **`.vault-mind/vault-mind.config.json`** — `config.ts`'s `readExtensionConfig`
|
|
62
|
+
now reads the single vault-scoped config (previously read the removed
|
|
63
|
+
global `~/.pi/agent/vault-mind.config.json` + vault-root
|
|
64
|
+
`pi-vault-mind.config.json`).
|
|
65
|
+
- **`.env.1pass` relocated to `.vault-mind/.env.1pass`**, with `--op-env`
|
|
66
|
+
wired into every pi launch site (`PiConnection` in `chat-tab.ts`, the TUI
|
|
67
|
+
launcher in `status-tab.ts`, and `scripts/vault-pi.sh`/`setup-vault-pi.sh`) —
|
|
68
|
+
gated on the file existing AND `pi-1password` being installed, since
|
|
69
|
+
`--op-env` is a flag `pi-1password` registers; passing it unconditionally
|
|
70
|
+
would make `pi` reject the whole invocation with "Unknown option" when the
|
|
71
|
+
extension isn't installed.
|
|
72
|
+
|
|
3
73
|
## 0.5.1 — 2026-06-28
|
|
4
74
|
|
|
5
75
|
### Fixed
|
package/README.md
CHANGED
|
@@ -375,6 +375,7 @@ Edit `pi-vault-mind.config.json` to match your domain:
|
|
|
375
375
|
| [docs/getting-started/NEW_VAULT_WALKTHROUGH.md](docs/getting-started/NEW_VAULT_WALKTHROUGH.md) | **Fresh Mac → new vault → Modal → sync → verified**, one linear path (incl. multi-vault storage isolation) |
|
|
376
376
|
| [docs/getting-started/INSTALL.md](docs/getting-started/INSTALL.md) | **Canonical install playbook** — all 5 layers (pi ext, skills, Obsidian, config, external CLIs) |
|
|
377
377
|
| [docs/getting-started/GETTING_STARTED.md](docs/getting-started/GETTING_STARTED.md) | End-to-end workflow + daily "drop & forget" usage |
|
|
378
|
+
| [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
379
|
| [docs/getting-started/WALKTHROUGH_PROMPT.md](docs/getting-started/WALKTHROUGH_PROMPT.md) | Paste-into-pi guided setup with checkpoints between phases |
|
|
379
380
|
|
|
380
381
|
### Architecture & design
|
package/dist/src/agent-queue.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import * as fs from "node:fs";
|
|
14
14
|
import * as path from "node:path";
|
|
15
|
+
import { loadConfig, resolveVaultFile } from "./utils.js";
|
|
15
16
|
const queueSubscribers = new Set();
|
|
16
17
|
/** Subscribe to queue events. Returns an unsubscribe function. */
|
|
17
18
|
export const subscribeQueue = (cb) => {
|
|
@@ -35,8 +36,16 @@ const eventTypeFor = (status, prev) => {
|
|
|
35
36
|
return "job-completed";
|
|
36
37
|
return "job-updated";
|
|
37
38
|
};
|
|
38
|
-
|
|
39
|
-
const
|
|
39
|
+
/** Per-vault queue path, resolved from config once and memoized. */
|
|
40
|
+
const queuePathCache = new Map();
|
|
41
|
+
const queuePath = (vaultPath) => {
|
|
42
|
+
const cached = queuePathCache.get(vaultPath);
|
|
43
|
+
if (cached)
|
|
44
|
+
return cached;
|
|
45
|
+
const resolved = path.join(vaultPath, resolveVaultFile(loadConfig(vaultPath).vaultMind, "queue"));
|
|
46
|
+
queuePathCache.set(vaultPath, resolved);
|
|
47
|
+
return resolved;
|
|
48
|
+
};
|
|
40
49
|
const ensureQueueDir = (vaultPath) => {
|
|
41
50
|
const dir = path.dirname(queuePath(vaultPath));
|
|
42
51
|
if (!fs.existsSync(dir)) {
|
package/dist/src/auth.d.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Token resolution order:
|
|
5
5
|
* 1. `process.env.PVM_API_TOKEN`
|
|
6
|
-
* 2. `<
|
|
6
|
+
* 2. `<vault>/.vault-mind/vault-mind.env` (key=value, # comments)
|
|
7
7
|
* 3. `vaultMind.embedding.modal.apiToken` in the loaded config
|
|
8
8
|
*
|
|
9
9
|
* Returns `null` if no token is configured (auth is off until set).
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* dotenv file is
|
|
13
|
-
*
|
|
11
|
+
* The token env path is resolved from the vault cwd via `getTokenEnvPath`;
|
|
12
|
+
* `chmod 600` on the dotenv file is best-effort and a no-op on win32 (the file
|
|
13
|
+
* system doesn't honor POSIX modes there).
|
|
14
14
|
*/
|
|
15
15
|
import type { UniversalConfig } from "./types.js";
|
|
16
16
|
/** Resolve the bearer token. `cfg` is optional; pass the loaded config to fall back to it. */
|
|
@@ -58,16 +58,16 @@ export declare const setToken: (value: string) => void;
|
|
|
58
58
|
export declare const clearToken: () => void;
|
|
59
59
|
/**
|
|
60
60
|
* Revoke a role-specific bearer token by removing `PVM_TOKEN_<IDENTITY>`
|
|
61
|
-
* from
|
|
62
|
-
* Returns `true` if the variable was found and removed.
|
|
61
|
+
* from `<vault>/.vault-mind/vault-mind.env`. Preserves all other lines and
|
|
62
|
+
* comments. Returns `true` if the variable was found and removed.
|
|
63
63
|
*/
|
|
64
64
|
export declare const revokeToken: (identity: string) => boolean;
|
|
65
65
|
/**
|
|
66
66
|
* Generate a fresh 32-byte base64url token, persist it to
|
|
67
|
-
* `<
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* `<vault>/.vault-mind/vault-mind.env` (replacing any existing `PVM_API_TOKEN`
|
|
68
|
+
* line while preserving all other lines and comments), create the directory +
|
|
69
|
+
* file if missing, apply `chmod 600` (best-effort; no-op on win32), update the
|
|
70
|
+
* in-process cache, and return the new token.
|
|
71
71
|
*
|
|
72
72
|
* **Env-var precedence note:** if `PVM_API_TOKEN` is exported as an environment
|
|
73
73
|
* variable it takes precedence over the dotenv file at resolution time, so the
|
package/dist/src/auth.js
CHANGED
|
@@ -3,28 +3,24 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Token resolution order:
|
|
5
5
|
* 1. `process.env.PVM_API_TOKEN`
|
|
6
|
-
* 2. `<
|
|
6
|
+
* 2. `<vault>/.vault-mind/vault-mind.env` (key=value, # comments)
|
|
7
7
|
* 3. `vaultMind.embedding.modal.apiToken` in the loaded config
|
|
8
8
|
*
|
|
9
9
|
* Returns `null` if no token is configured (auth is off until set).
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* dotenv file is
|
|
13
|
-
*
|
|
11
|
+
* The token env path is resolved from the vault cwd via `getTokenEnvPath`;
|
|
12
|
+
* `chmod 600` on the dotenv file is best-effort and a no-op on win32 (the file
|
|
13
|
+
* system doesn't honor POSIX modes there).
|
|
14
14
|
*/
|
|
15
15
|
import * as crypto from "node:crypto";
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
|
-
import * as os from "node:os";
|
|
18
17
|
import * as path from "node:path";
|
|
18
|
+
import { getTokenEnvPath } from "./utils.js";
|
|
19
19
|
const ENV_VAR = "PVM_API_TOKEN";
|
|
20
|
-
const DOTENV_REL = path.join(".pi", "agent", "vault-mind.env");
|
|
21
20
|
/** Cached token resolution. The cache is invalidated by `setToken` / `clearToken`. */
|
|
22
21
|
let cached = null;
|
|
23
22
|
const readDotenvToken = () => {
|
|
24
|
-
const
|
|
25
|
-
if (!home)
|
|
26
|
-
return null;
|
|
27
|
-
const p = path.join(home, DOTENV_REL);
|
|
23
|
+
const p = getTokenEnvPath(process.cwd());
|
|
28
24
|
try {
|
|
29
25
|
const text = fs.readFileSync(p, "utf-8");
|
|
30
26
|
for (const line of text.split(/\r?\n/)) {
|
|
@@ -149,12 +145,12 @@ export const clearToken = () => {
|
|
|
149
145
|
};
|
|
150
146
|
/**
|
|
151
147
|
* Revoke a role-specific bearer token by removing `PVM_TOKEN_<IDENTITY>`
|
|
152
|
-
* from
|
|
153
|
-
* Returns `true` if the variable was found and removed.
|
|
148
|
+
* from `<vault>/.vault-mind/vault-mind.env`. Preserves all other lines and
|
|
149
|
+
* comments. Returns `true` if the variable was found and removed.
|
|
154
150
|
*/
|
|
155
151
|
export const revokeToken = (identity) => {
|
|
156
152
|
const varName = `PVM_TOKEN_${identity.toUpperCase()}`;
|
|
157
|
-
const dotenvPath =
|
|
153
|
+
const dotenvPath = getTokenEnvPath(process.cwd());
|
|
158
154
|
let lines = [];
|
|
159
155
|
try {
|
|
160
156
|
lines = fs.readFileSync(dotenvPath, "utf-8").split(/\r?\n/);
|
|
@@ -183,10 +179,10 @@ export const revokeToken = (identity) => {
|
|
|
183
179
|
};
|
|
184
180
|
/**
|
|
185
181
|
* Generate a fresh 32-byte base64url token, persist it to
|
|
186
|
-
* `<
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
182
|
+
* `<vault>/.vault-mind/vault-mind.env` (replacing any existing `PVM_API_TOKEN`
|
|
183
|
+
* line while preserving all other lines and comments), create the directory +
|
|
184
|
+
* file if missing, apply `chmod 600` (best-effort; no-op on win32), update the
|
|
185
|
+
* in-process cache, and return the new token.
|
|
190
186
|
*
|
|
191
187
|
* **Env-var precedence note:** if `PVM_API_TOKEN` is exported as an environment
|
|
192
188
|
* variable it takes precedence over the dotenv file at resolution time, so the
|
|
@@ -195,7 +191,7 @@ export const revokeToken = (identity) => {
|
|
|
195
191
|
*/
|
|
196
192
|
export const rotateToken = () => {
|
|
197
193
|
const newToken = crypto.randomBytes(32).toString("base64url");
|
|
198
|
-
const dotenvPath =
|
|
194
|
+
const dotenvPath = getTokenEnvPath(process.cwd());
|
|
199
195
|
const dir = path.dirname(dotenvPath);
|
|
200
196
|
if (!fs.existsSync(dir))
|
|
201
197
|
fs.mkdirSync(dir, { recursive: true });
|
package/dist/src/autosync.js
CHANGED
|
@@ -27,7 +27,7 @@ export const startAutoSync = (intervalMs = 300_000) => {
|
|
|
27
27
|
return; // nothing to sync
|
|
28
28
|
const ms = sync.autoSyncIntervalMs ?? intervalMs;
|
|
29
29
|
void ms; // cadence is fixed at start; tick honors config toggle
|
|
30
|
-
await syncAll(cfg);
|
|
30
|
+
await syncAll(cfg, process.cwd());
|
|
31
31
|
console.log("[pi-vault-mind] auto-sync tick complete");
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
package/dist/src/commands.d.ts
CHANGED
|
@@ -5,8 +5,10 @@ export declare const selectActiveCollection: (ctx: ExtensionContext) => Promise<
|
|
|
5
5
|
/**
|
|
6
6
|
* Vault-root `.gitignore` entries that keep pi-vault-mind compatible with
|
|
7
7
|
* `obsidian-git` (and, transitively, Obsidian Sync setups that also back up via
|
|
8
|
-
* git)
|
|
9
|
-
* never be committed
|
|
8
|
+
* git). The `.vault-mind/` directory holds local state (token, index, framework
|
|
9
|
+
* dir) that must never be committed, EXCEPT the hand-tuned config file, which is
|
|
10
|
+
* re-included via a `!` negation. The LanceDB index is a large, per-device,
|
|
11
|
+
* rebuildable binary; Obsidian's workspace UI state churns constantly. See
|
|
10
12
|
* docs/OBSIDIAN_SETUP.md §6.
|
|
11
13
|
*/
|
|
12
14
|
export declare const GITIGNORE_ENTRIES: string[];
|
|
@@ -15,9 +17,13 @@ export declare const GITIGNORE_ENTRIES: string[];
|
|
|
15
17
|
* (`null` if absent). Pure — does no I/O — so it is unit-testable. Creates the
|
|
16
18
|
* file when missing, appends only the entries that aren't already present
|
|
17
19
|
* (line-exact match, trimmed), and skips when everything is covered.
|
|
20
|
+
*
|
|
21
|
+
* A bare `.vault-mind/` directory exclude would block the per-file config
|
|
22
|
+
* negation (git cannot re-include a file inside an ignored directory), so when
|
|
23
|
+
* one is present it is rewritten to `.vault-mind/*` and the whole file returned.
|
|
18
24
|
*/
|
|
19
25
|
export declare const planGitignore: (existing: string | null) => {
|
|
20
|
-
action: "create" | "append" | "skip";
|
|
26
|
+
action: "create" | "append" | "rewrite" | "skip";
|
|
21
27
|
content: string;
|
|
22
28
|
};
|
|
23
29
|
export declare const watcherState: import("./watcher.js").WatcherState;
|