pi-vault-mind 0.16.32 → 0.16.33

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.33 — 2026-08-29
4
+
5
+ ### Added
6
+
7
+ - **Content-writing-system runtime.** `pvm setup` now installs the private `content-writing-system` Pi package (`git:git@github.com:kylebrodeur/content-writing-system`) as a required extension, registering both its skill and the `/check-writing` command in the vault-local agent. Requires git/SSH access to the repository at setup time.
8
+
9
+ ### Changed
10
+
11
+ - **Idempotent extension install.** `pvm setup` now reads the vault-local `settings.json` and skips extensions already present at the recorded spec (including pinned versions), reinstalling only missing specs or changed version pins. Repeated `pvm setup` / `--resources-only` runs no longer re-clone or re-fetch unchanged extensions.
12
+
3
13
  ## 0.16.32 — 2026-08-28
4
14
 
5
15
  ### Changed
@@ -14,6 +14,7 @@ const requiredExtensions = [
14
14
  "npm:@kylebrodeur/pi-model-router",
15
15
  "npm:@juicesharp/rpiv-todo@2.7.1",
16
16
  "npm:pi-subagents@0.58.0",
17
+ "git:git@github.com:kylebrodeur/content-writing-system",
17
18
  ];
18
19
  const runtimeSkills = [
19
20
  "obsidian-cli",
@@ -124,7 +125,7 @@ fs.appendFileSync(process.env.PVM_TEST_UV_LOG, JSON.stringify(process.argv.slice
124
125
  assert.ok(fs.existsSync(path.join(nlmSkillDir, "references", ref)), `nlm-skill reference missing: ${ref}`);
125
126
  }
126
127
  assert.doesNotMatch(result.stdout + result.stderr, /NOISY INSTALL/);
127
- assert.match(result.stdout, /\[6\/6\] npm:pi-subagents@0\.58\.0 \.\.\. done/);
128
+ assert.match(result.stdout, /\[7\/7\] git:git@github\.com:kylebrodeur\/content-writing-system \.\.\. done/);
128
129
  assert.match(result.stdout, /Curated skills \(5\)/);
129
130
  });
130
131
  it("removes package paths that escape the vault-local agent directory", () => {
@@ -191,6 +192,28 @@ if (args[0] === "install" && args[1] === "npm:pi-context") {
191
192
  assert.ok(fs.existsSync(path.join(vaultPath, ".vault-mind", ".pi", "agent", "skills", skill, "SKILL.md")));
192
193
  }
193
194
  });
195
+ it("skips extensions already present in the vault settings", () => {
196
+ const agentDir = path.join(vaultPath, ".vault-mind", ".pi", "agent");
197
+ fs.mkdirSync(agentDir, { recursive: true });
198
+ fs.writeFileSync(path.join(agentDir, "settings.json"), `${JSON.stringify({
199
+ packages: ["npm:pi-vault-mind", "npm:pi-context", "npm:pi-subagents@0.58.0"],
200
+ })}\n`);
201
+ const result = runSetup(["--resources-only", vaultPath]);
202
+ assert.equal(result.status, 0, result.stderr || result.stdout);
203
+ const installed = installedExtensions();
204
+ for (const present of ["npm:pi-vault-mind", "npm:pi-context", "npm:pi-subagents@0.58.0"]) {
205
+ assert.ok(!installed.includes(present), `expected ${present} to be skipped`);
206
+ }
207
+ for (const missing of [
208
+ "npm:@kylebrodeur/pi-model-discovery",
209
+ "npm:@kylebrodeur/pi-model-router",
210
+ "npm:@juicesharp/rpiv-todo@2.7.1",
211
+ "git:git@github.com:kylebrodeur/content-writing-system",
212
+ ]) {
213
+ assert.ok(installed.includes(missing), `expected ${missing} to be installed`);
214
+ }
215
+ assert.match(result.stdout, /npm:pi-subagents@0\.58\.0 \.\.\. already installed/);
216
+ });
194
217
  it("preserves customized configuration across repeated full setup", () => {
195
218
  const first = runSetup([vaultPath]);
196
219
  assert.equal(first.status, 0, first.stderr || first.stdout);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-vault-mind",
3
- "version": "0.16.32",
3
+ "version": "0.16.33",
4
4
  "packageManager": "pnpm@10.34.5",
5
5
  "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.",
6
6
  "main": "dist/index.js",
@@ -5,7 +5,8 @@
5
5
  "npm:@kylebrodeur/pi-model-discovery",
6
6
  "npm:@kylebrodeur/pi-model-router",
7
7
  "npm:@juicesharp/rpiv-todo@2.7.1",
8
- "npm:pi-subagents@0.58.0"
8
+ "npm:pi-subagents@0.58.0",
9
+ "git:git@github.com:kylebrodeur/content-writing-system"
9
10
  ],
10
11
  "optional": ["npm:pi-1password"]
11
12
  }
@@ -158,6 +158,21 @@ function removeStaleExtensions(agentDir) {
158
158
  for (const extension of STALE_EXTENSIONS) removeStaleExtension(extension, agentDir);
159
159
  }
160
160
 
161
+ function readInstalledPackages(agentDir) {
162
+ const settingsPath = path.join(agentDir, "settings.json");
163
+ try {
164
+ const settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
165
+ if (!Array.isArray(settings.packages)) return new Set();
166
+ return new Set(
167
+ settings.packages
168
+ .map((entry) => (typeof entry === "string" ? entry : entry?.source))
169
+ .filter((source) => typeof source === "string")
170
+ );
171
+ } catch {
172
+ return new Set();
173
+ }
174
+ }
175
+
161
176
  function installExtensions(agentDir) {
162
177
  const manifest = readExtensionManifest();
163
178
  const extensions = [...manifest.required];
@@ -168,8 +183,13 @@ function installExtensions(agentDir) {
168
183
  }
169
184
  }
170
185
 
186
+ const installed = readInstalledPackages(agentDir);
171
187
  console.log(`==> Pi extensions (${extensions.length})`);
172
188
  for (const [index, extension] of extensions.entries()) {
189
+ if (installed.has(extension)) {
190
+ console.log(` [${index + 1}/${extensions.length}] ${extension} ... already installed`);
191
+ continue;
192
+ }
173
193
  installExtension(extension, agentDir, index + 1, extensions.length);
174
194
  }
175
195
  }