pi-vault-mind 0.9.0 → 0.9.2

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.
@@ -33,7 +33,8 @@ const VM_USAGE = [
33
33
  " /vm collection select Select active collection",
34
34
  " /vm collection list List configured collections",
35
35
  " /vm collection create Create a new collection (wizard)",
36
- " /vm collection reindex Rebuild FTS + vector indexes (replaces old /qmd-index)",
36
+ " /vm collection reindex Rebuild FTS + vector indexes",
37
+ " /vm index [--all] [--reembed] [--remote] Index collections (alias: reindex)",
37
38
  " /vm discover-schema Infer schema from a JSONL file",
38
39
  " /vm injector create Create a new injector (wizard)",
39
40
  " /vm context enable|disable Enable/disable pi-context integration",
@@ -647,7 +648,7 @@ const handleReindex = async (args, ctx, pi) => {
647
648
  lines.unshift("**Reindex Report:**", "");
648
649
  lines.push("", rebuildEmbeddings
649
650
  ? "Entries will be re-embedded with current embedding model on next append."
650
- : "Use /vm reindex --reembed to regenerate embeddings after model switch.");
651
+ : "Use /vm index --reembed to regenerate embeddings after model switch.");
651
652
  ctx.ui.notify(lines.join("\n"), "info");
652
653
  };
653
654
  // ── /vm embedding ──────────────────────────────────────────────────────────
@@ -1561,7 +1562,7 @@ const handleToken = (args, ctx) => {
1561
1562
  // ── Main /vm command ───────────────────────────────────────────────────────
1562
1563
  export const registerCommands = (pi) => {
1563
1564
  pi.registerCommand("vm", {
1564
- description: "pi-vault-mind: manage collections, embedding, reindexing, and config.",
1565
+ description: "pi-vault-mind: manage collections, embedding, indexing, and config.",
1565
1566
  getArgumentCompletions: (_prefix) => {
1566
1567
  const words = _prefix.trim().split(/\s+/);
1567
1568
  const top = [
@@ -1582,6 +1583,8 @@ export const registerCommands = (pi) => {
1582
1583
  "personalize",
1583
1584
  "setup",
1584
1585
  "token",
1586
+ "index",
1587
+ "reindex",
1585
1588
  ];
1586
1589
  if (words.length === 1 || (words.length === 2 && words[1] === "")) {
1587
1590
  return top
@@ -1690,6 +1693,9 @@ export const registerCommands = (pi) => {
1690
1693
  return handleSetup(rest, ctx, pi);
1691
1694
  case "token":
1692
1695
  return handleToken(rest, ctx);
1696
+ case "index":
1697
+ case "reindex":
1698
+ return handleReindex(rest, ctx, pi);
1693
1699
  default:
1694
1700
  ctx.ui.notify(VM_USAGE, "info");
1695
1701
  }
package/dist/src/index.js CHANGED
@@ -37,7 +37,12 @@ export default function (pi) {
37
37
  * during extension loading — the runtime must be initialized first. */
38
38
  pi.on("session_start", async (_event, ctx) => {
39
39
  updateActiveCollectionWidget(ctx);
40
- enableACM(pi);
40
+ /* Only enable ACM when this session has a vault configured */
41
+ const sessionCfg = loadConfig(ctx.cwd);
42
+ const piCtxCfg = sessionCfg.extensionCompatibility?.["pi-context"];
43
+ if (piCtxCfg?.enabled && piCtxCfg?.autoEnableAcm !== false) {
44
+ enableACM(pi);
45
+ }
41
46
  /* register shortcut */
42
47
  pi.registerShortcut("ctrl+alt+l", {
43
48
  description: "Select Active Collection",
@@ -8,10 +8,10 @@ const ONBOARDING_PLUGIN_REQUIREMENTS = [
8
8
  id: "obsidian42-brat",
9
9
  label: "BRAT (Beta Reviewer's Auto-update Tester)",
10
10
  required: true,
11
- reason: "required to install obsidian-pi-vault-mind (not yet in community registry)",
11
+ reason: "required to install vault-mind plugin (not yet in community registry)",
12
12
  },
13
13
  {
14
- id: "obsidian-pi-vault-mind",
14
+ id: "vault-mind",
15
15
  label: "Vault Mind plugin",
16
16
  required: true,
17
17
  reason: "native setup/status/chat UI and local bridge controls",
@@ -67,7 +67,7 @@ const formatExecError = (err) => {
67
67
  }
68
68
  return err instanceof Error ? err.message : String(err);
69
69
  };
70
- const BRAT_REPO = "kylebrodeur/obsidian-pi-vault-mind";
70
+ const BRAT_REPO = "kylebrodeur/obsidian-vault-mind";
71
71
  const installViaBrat = () => {
72
72
  try {
73
73
  execFileSync("obsidian", ["eval", `app.plugins.getPlugin("obsidian42-brat").addPlugin("${BRAT_REPO}")`], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
@@ -79,7 +79,7 @@ const installViaBrat = () => {
79
79
  };
80
80
  const installObsidianPlugin = (pluginId) => {
81
81
  // vault-mind plugin must be installed via BRAT (not in community registry)
82
- if (pluginId === "obsidian-pi-vault-mind") {
82
+ if (pluginId === "vault-mind") {
83
83
  return installViaBrat();
84
84
  }
85
85
  try {
@@ -94,14 +94,14 @@ const installObsidianPlugin = (pluginId) => {
94
94
  }
95
95
  };
96
96
  export const buildPluginInstallGuidance = (plugins) => {
97
- const bratPlugins = plugins.filter((p) => p.id === "obsidian-pi-vault-mind");
98
- const registryPlugins = plugins.filter((p) => p.id !== "obsidian-pi-vault-mind");
97
+ const bratPlugins = plugins.filter((p) => p.id === "vault-mind");
98
+ const registryPlugins = plugins.filter((p) => p.id !== "vault-mind");
99
99
  const lines = ["Install missing Obsidian plugins:", ""];
100
100
  if (registryPlugins.length > 0) {
101
101
  lines.push("CLI (when Obsidian CLI is available):", ...registryPlugins.map((plugin) => ` obsidian plugin:install id=${plugin.id} enable`), "", "Deep links (open each URI):", ...registryPlugins.map((plugin) => ` obsidian://show-plugin?id=${encodeURIComponent(plugin.id)}`), "", "GUI fallback: Obsidian → Settings → Community plugins → Browse");
102
102
  }
103
103
  if (bratPlugins.length > 0) {
104
- lines.push("", "Via BRAT (not yet in community registry):", ` Settings → BRAT → "Add Beta plugin" → ${BRAT_REPO}`, ` Or CLI: obsidian eval 'app.plugins.getPlugin("obsidian42-brat").addPlugin("${BRAT_REPO}")'`);
104
+ lines.push("", "Via BRAT (not yet in community registry):", ` Settings → BRAT → "Add Beta plugin" → ${BRAT_REPO}`, ` Or CLI: obsidian eval code='await app.plugins.getPlugin("obsidian42-brat").addPlugin("${BRAT_REPO}")'`);
105
105
  }
106
106
  return lines.join("\n");
107
107
  };
@@ -408,6 +408,41 @@ export const setupWizard = async (ctx, cliArgs) => {
408
408
  }
409
409
  // ── Step 1.5: Obsidian plugin readiness ────────────────────────────────
410
410
  await runPluginOnboarding(ctx, vaultPath);
411
+ // ── Step 1.6: Pi skills ────────────────────────────────────────────────
412
+ const installSkills = await ctx.ui.confirm("Pi skills", "Install recommended Obsidian skills for agents? (obsidian-markdown, obsidian-bases, json-canvas, obsidian-cli, defuddle)");
413
+ if (installSkills) {
414
+ try {
415
+ execFileSync("npx", [
416
+ "-y",
417
+ "skills",
418
+ "add",
419
+ "https://github.com/kepano/obsidian-skills",
420
+ "--skill",
421
+ "obsidian-markdown",
422
+ "--skill",
423
+ "obsidian-bases",
424
+ "--skill",
425
+ "json-canvas",
426
+ "--skill",
427
+ "obsidian-cli",
428
+ "--skill",
429
+ "defuddle",
430
+ "-g",
431
+ "-a",
432
+ "pi",
433
+ "--copy",
434
+ "-y",
435
+ ], {
436
+ encoding: "utf-8",
437
+ stdio: ["ignore", "pipe", "pipe"],
438
+ env: { ...process.env, DISABLE_TELEMETRY: "1" },
439
+ });
440
+ ctx.ui.notify("✅ Pi skills installed.", "info");
441
+ }
442
+ catch (err) {
443
+ ctx.ui.notify(`⚠️ Skill install failed: ${formatExecError(err)}\nInstall manually: see INSTALL.md §Layer 2`, "warning");
444
+ }
445
+ }
411
446
  // ── Step 2: Embedding config ──────────────────────────────────────────
412
447
  let remoteUrl = "";
413
448
  let localUrl = "";
@@ -529,22 +564,30 @@ export const setupWizard = async (ctx, cliArgs) => {
529
564
  };
530
565
  config.vaultMind.graph = config.vaultMind.graph || { enabled: true, canvasSync: true };
531
566
  config.vaultMind.ftsEnabled = config.vaultMind.ftsEnabled !== false;
532
- config.extensionCompatibility = config.extensionCompatibility || {};
533
- config.extensionCompatibility["pi-context"] = {
567
+ const dir = path.dirname(getGlobalConfigPath());
568
+ if (!fs.existsSync(dir))
569
+ fs.mkdirSync(dir, { recursive: true });
570
+ fs.writeFileSync(getGlobalConfigPath(), `${JSON.stringify(config, null, 2)}\n`, "utf-8");
571
+ // Write extension compatibility to the PROJECT config (not global)
572
+ // so pi-context settings are scoped to this vault, not every session.
573
+ const projectCfgPath = path.join(vaultPath, "pi-vault-mind.config.json");
574
+ const projectCfg = fs.existsSync(projectCfgPath)
575
+ ? JSON.parse(fs.readFileSync(projectCfgPath, "utf-8"))
576
+ : {};
577
+ projectCfg.extensionCompatibility = projectCfg.extensionCompatibility || {};
578
+ projectCfg.extensionCompatibility["pi-context"] = {
534
579
  tagPatterns: [],
535
580
  enhanceInjectors: false,
536
581
  autoEnableAcm: true,
537
582
  indexContextEvents: true,
538
- ...(config.extensionCompatibility["pi-context"] || {}),
583
+ ...(projectCfg.extensionCompatibility["pi-context"] || {}),
539
584
  enabled: enableContextAutomation,
540
585
  };
541
- const dir = path.dirname(getGlobalConfigPath());
542
- if (!fs.existsSync(dir))
543
- fs.mkdirSync(dir, { recursive: true });
544
- fs.writeFileSync(getGlobalConfigPath(), `${JSON.stringify(config, null, 2)}\n`, "utf-8");
586
+ fs.writeFileSync(projectCfgPath, `${JSON.stringify(projectCfg, null, 2)}\n`, "utf-8");
545
587
  ctx.ui.notify([
546
- "✅ Global config written!",
547
- ` ${getGlobalConfigPath()}`,
588
+ "✅ Config written!",
589
+ ` Global: ${getGlobalConfigPath()}`,
590
+ ` Project: ${projectCfgPath}`,
548
591
  "",
549
592
  ` Vault: ${vaultPath}`,
550
593
  ` Remote: ${remoteUrl || "none"}`,
@@ -555,13 +598,6 @@ export const setupWizard = async (ctx, cliArgs) => {
555
598
  "",
556
599
  "Next: /vm watcher start (or restart pi for auto-start)",
557
600
  ].join("\n"), "info");
558
- if (remoteUrl?.includes("modal.run")) {
559
- ctx.ui.notify([
560
- "Modal token reminder:",
561
- "- /vm remote token",
562
- "- ./scripts/fetch-modal-token.sh --write",
563
- ].join("\n"), "info");
564
- }
565
601
  };
566
602
  /**
567
603
  * Interactive Modal embedding configuration + "Test connection" action.
@@ -54,7 +54,7 @@ describe("setupWizard plugin onboarding helpers", () => {
54
54
  const guidance = buildPluginInstallGuidance(getMissingOnboardingPlugins(vault));
55
55
  assert.match(guidance, /obsidian plugin:install id=obsidian42-brat enable/);
56
56
  assert.match(guidance, /obsidian plugin:install id=actions-uri enable/);
57
- assert.match(guidance, /BRAT.*kylebrodeur\/obsidian-pi-vault-mind/);
57
+ assert.match(guidance, /BRAT.*kylebrodeur\/obsidian-vault-mind/);
58
58
  fs.rmSync(vault, { recursive: true, force: true });
59
59
  });
60
60
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-vault-mind",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
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",
@@ -10,6 +10,7 @@
10
10
  "agents",
11
11
  "skills",
12
12
  "scripts",
13
+ "pi-vault-mind.config.example.json",
13
14
  "CHANGELOG.md",
14
15
  "README.md",
15
16
  "LICENSE"
@@ -0,0 +1,43 @@
1
+ {
2
+ "version": 2,
3
+ "collections": {
4
+ "main": {
5
+ "path": "collections/main.jsonl",
6
+ "schema": ["id", "domain", "source", "fact", "tag", "artifact"],
7
+ "dedupField": "fact"
8
+ },
9
+ "pending": {
10
+ "path": "collections/pending.jsonl",
11
+ "schema": "main"
12
+ },
13
+ "context_events": {
14
+ "path": "collections/context_events.jsonl",
15
+ "schema": ["id", "type", "session_entry_id", "content", "timestamp", "tags"],
16
+ "dedupField": "id"
17
+ }
18
+ },
19
+ "injectors": [],
20
+ "vaultMind": {
21
+ "dataDir": ".lancedb",
22
+ "embedding": {
23
+ "localUrl": "http://127.0.0.1:11434",
24
+ "useTransformers": true
25
+ },
26
+ "graph": {
27
+ "enabled": true,
28
+ "canvasSync": false
29
+ },
30
+ "ftsEnabled": true,
31
+ "httpPort": 11435,
32
+ "autoIndex": false
33
+ },
34
+ "extensionCompatibility": {
35
+ "pi-context": {
36
+ "enabled": true,
37
+ "tagPatterns": [],
38
+ "enhanceInjectors": false,
39
+ "autoEnableAcm": true,
40
+ "indexContextEvents": true
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/publish-obsidian-plugin.sh
3
+ #
4
+ # Publishes the Obsidian plugin from packages/obsidian/ to the separate
5
+ # kylebrodeur/obsidian-vault-mind repo and creates a GitHub release.
6
+ #
7
+ # Usage:
8
+ # ./scripts/publish-obsidian-plugin.sh [version]
9
+ #
10
+ # If version is omitted, reads from packages/obsidian/manifest.json.
11
+ # Requires: gh (GitHub CLI), git, jq
12
+
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
16
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
17
+ PLUGIN_DIR="$REPO_ROOT/packages/obsidian"
18
+ TARGET_REPO="kylebrodeur/obsidian-vault-mind"
19
+
20
+ # Get version from manifest or argument
21
+ VERSION="${1:-$(jq -r .version "$PLUGIN_DIR/manifest.json")}"
22
+ echo "Publishing vault-mind plugin v$VERSION"
23
+
24
+ # Verify required files exist
25
+ for f in main.js manifest.json styles.css; do
26
+ if [ ! -f "$PLUGIN_DIR/$f" ]; then
27
+ echo "ERROR: $PLUGIN_DIR/$f not found. Run the plugin build first."
28
+ exit 1
29
+ fi
30
+ done
31
+
32
+ # Clone the target repo into a temp dir
33
+ TMPDIR="$(mktemp -d)"
34
+ trap 'rm -rf "$TMPDIR"' EXIT
35
+
36
+ if [ -n "${GH_TOKEN:-}" ]; then
37
+ git clone "https://x-access-token:${GH_TOKEN}@github.com/$TARGET_REPO.git" "$TMPDIR/repo" --depth 1
38
+ else
39
+ git clone "git@github.com:$TARGET_REPO.git" "$TMPDIR/repo" --depth 1
40
+ fi
41
+ cd "$TMPDIR/repo"
42
+
43
+ # Copy built assets
44
+ cp "$PLUGIN_DIR/main.js" .
45
+ cp "$PLUGIN_DIR/manifest.json" .
46
+ cp "$PLUGIN_DIR/styles.css" .
47
+ cp "$PLUGIN_DIR/versions.json" .
48
+ cp "$PLUGIN_DIR/README.md" .
49
+
50
+ # Commit and push if anything changed
51
+ if git diff --quiet && git diff --cached --quiet; then
52
+ echo "No changes to plugin files."
53
+ else
54
+ git add -A
55
+ git commit -m "release: v$VERSION"
56
+ git push origin main
57
+ echo "Pushed updated plugin files to $TARGET_REPO"
58
+ fi
59
+
60
+ # Create release with assets (tag = version, no 'v' prefix per Obsidian convention)
61
+ if gh release view "$VERSION" --repo "$TARGET_REPO" >/dev/null 2>&1; then
62
+ echo "Release $VERSION already exists, skipping."
63
+ else
64
+ gh release create "$VERSION" \
65
+ main.js \
66
+ manifest.json \
67
+ styles.css \
68
+ --repo "$TARGET_REPO" \
69
+ --title "v$VERSION" \
70
+ --notes "Release v$VERSION of the Vault Mind Obsidian plugin.
71
+
72
+ Install via BRAT: add \`kylebrodeur/obsidian-vault-mind\` as a beta plugin.
73
+ Or download assets and extract to \`.obsidian/plugins/vault-mind/\`."
74
+ echo "Created release $VERSION on $TARGET_REPO"
75
+ fi
76
+
77
+ echo "Done."