@zosmaai/pi-llm-wiki 0.7.4 → 0.8.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 +9 -0
- package/extensions/llm-wiki/index.ts +17 -0
- package/extensions/llm-wiki/lib/utils.ts +73 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Fixed
|
|
6
|
+
- **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.
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- **`migrateDoubledPersonalVault()`** helper (`extensions/llm-wiki/lib/utils.ts`): Idempotent, in-place flatten of any vault that was already written to the broken doubled layout. Moves entries from `<root>/.llm-wiki/.llm-wiki/*` up to `<root>/.llm-wiki/*`, preserves outer entries on collision, removes the inner dir only when fully drained. Returns `null` when the layout is already correct, so it is safe to call on every session start.
|
|
10
|
+
- **Auto-migration on `session_start`**: The extension now runs `migrateDoubledPersonalVault()` on the personal wiki at every session start. Existing broken vaults are flattened the next time the user opens or reloads pi — no manual step required. A one-line status message is shown when a flatten actually happens; otherwise the check is silent.
|
|
11
|
+
- **`scripts/migrate-llm-wiki.js --fix-doubled`** flag: Manual recovery for arbitrary roots (`--fix-doubled ~/`, `--fix-doubled /some/project`). Supports `--dry-run` and `--force`.
|
|
12
|
+
- **9 regression tests** (`test/personal-wiki-paths.test.ts`): pin `getPersonalWikiRoot()` to the parent-of-dotdir contract, exercise `WIKI_HOME`, and verify the migration helper across no-op, idempotent, and collision paths.
|
|
13
|
+
|
|
5
14
|
## [0.7.0] - 2026-05-13
|
|
6
15
|
|
|
7
16
|
### Added
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
ensureVaultStructure,
|
|
26
26
|
fmtDate,
|
|
27
27
|
getVaultPaths,
|
|
28
|
+
migrateDoubledPersonalVault,
|
|
28
29
|
resolveVaultPaths,
|
|
29
30
|
writeJson,
|
|
30
31
|
} from "./lib/utils.js";
|
|
@@ -70,6 +71,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
70
71
|
let needsTopicInference = false;
|
|
71
72
|
|
|
72
73
|
pi.on("session_start", async (_event, ctx) => {
|
|
74
|
+
// One-shot recovery for vaults created with the broken personal-root
|
|
75
|
+
// (~/.llm-wiki/.llm-wiki/… doubled layout). Runs on every session start
|
|
76
|
+
// because it is a cheap existence-check no-op when the layout is correct.
|
|
77
|
+
try {
|
|
78
|
+
const migration = migrateDoubledPersonalVault();
|
|
79
|
+
if (migration && migration.moved.length > 0) {
|
|
80
|
+
ctx.ui.setStatus(
|
|
81
|
+
"llm-wiki",
|
|
82
|
+
`🧠 Personal wiki layout fixed: flattened ${migration.moved.length} entries out of ${migration.from} (see CHANGELOG)`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// Never let migration crash session start.
|
|
87
|
+
console.warn(`[llm-wiki] doubled-dotdir migration skipped: ${(err as Error).message}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
73
90
|
const paths = resolveVaultPaths(process.cwd());
|
|
74
91
|
if (!existsSync(join(paths.dotWiki, "config.json"))) {
|
|
75
92
|
// Silently create the wiki vault — no UI prompts
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
renameSync,
|
|
7
|
+
rmdirSync,
|
|
8
|
+
statSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from "node:fs";
|
|
2
11
|
import { homedir } from "node:os";
|
|
3
12
|
import { dirname, join, resolve } from "node:path";
|
|
4
13
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
@@ -33,11 +42,24 @@ export function detectVaultFormat(dir: string): VaultFormat {
|
|
|
33
42
|
return "none";
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Get the personal wiki root directory.
|
|
47
|
+
*
|
|
48
|
+
* The "root" follows the same contract as project wikis: it is the directory
|
|
49
|
+
* that *contains* the `.llm-wiki/` dot-dir, NOT the dot-dir itself.
|
|
50
|
+
* So the personal vault lives at `<root>/.llm-wiki/`.
|
|
51
|
+
*
|
|
52
|
+
* Default root: `homedir()` → personal vault at `~/.llm-wiki/`.
|
|
53
|
+
* Override: `WIKI_HOME` env var → personal vault at `$WIKI_HOME/.llm-wiki/`.
|
|
54
|
+
*
|
|
55
|
+
* NOTE: Previously this returned `~/.llm-wiki` (the dot-dir itself), which
|
|
56
|
+
* caused `getVaultPaths()` to compose paths like `~/.llm-wiki/.llm-wiki/raw`.
|
|
57
|
+
* See `migrateDoubledPersonalVault()` for the one-shot recovery.
|
|
58
|
+
*/
|
|
37
59
|
export function getPersonalWikiRoot(): string {
|
|
38
60
|
const envWiki = process.env.WIKI_HOME;
|
|
39
61
|
if (envWiki) return envWiki;
|
|
40
|
-
return
|
|
62
|
+
return homedir();
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
/** Get VaultPaths for the personal wiki. */
|
|
@@ -45,6 +67,54 @@ export function getPersonalWikiPaths(): VaultPaths {
|
|
|
45
67
|
return getVaultPaths(getPersonalWikiRoot());
|
|
46
68
|
}
|
|
47
69
|
|
|
70
|
+
/**
|
|
71
|
+
* One-shot, idempotent migration for vaults that were created with the broken
|
|
72
|
+
* `getPersonalWikiRoot()` (returned the dot-dir itself, so `getVaultPaths()`
|
|
73
|
+
* composed `<root>/.llm-wiki/.llm-wiki/...`).
|
|
74
|
+
*
|
|
75
|
+
* Detects a doubled layout at `<root>/.llm-wiki/.llm-wiki/config.json` and
|
|
76
|
+
* flattens it up by one level. Safe to call on every session start: if the
|
|
77
|
+
* doubled sentinel is absent, this is a no-op.
|
|
78
|
+
*
|
|
79
|
+
* Returns a description of the action taken (or `null` if no migration was
|
|
80
|
+
* needed) so callers can surface a one-line status message.
|
|
81
|
+
*/
|
|
82
|
+
export function migrateDoubledPersonalVault(
|
|
83
|
+
parentRoot: string = getPersonalWikiRoot(),
|
|
84
|
+
): { moved: string[]; from: string; to: string; skipped: string[] } | null {
|
|
85
|
+
const outerDotWiki = join(parentRoot, ".llm-wiki");
|
|
86
|
+
const innerDotWiki = join(outerDotWiki, ".llm-wiki");
|
|
87
|
+
const innerSentinel = join(innerDotWiki, "config.json");
|
|
88
|
+
|
|
89
|
+
if (!existsSync(innerSentinel)) return null;
|
|
90
|
+
|
|
91
|
+
const moved: string[] = [];
|
|
92
|
+
const skipped: string[] = [];
|
|
93
|
+
|
|
94
|
+
for (const entry of readdirSync(innerDotWiki)) {
|
|
95
|
+
const src = join(innerDotWiki, entry);
|
|
96
|
+
const dest = join(outerDotWiki, entry);
|
|
97
|
+
if (existsSync(dest)) {
|
|
98
|
+
// Collision — leave the inner copy in place rather than clobber.
|
|
99
|
+
skipped.push(entry);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
renameSync(src, dest);
|
|
103
|
+
moved.push(entry);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Only remove the inner dir if it is fully drained.
|
|
107
|
+
if (skipped.length === 0) {
|
|
108
|
+
try {
|
|
109
|
+
rmdirSync(innerDotWiki);
|
|
110
|
+
} catch {
|
|
111
|
+
// Leave behind if something raced us; harmless.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { moved, from: innerDotWiki, to: outerDotWiki, skipped };
|
|
116
|
+
}
|
|
117
|
+
|
|
48
118
|
/**
|
|
49
119
|
* Check if a vault is the personal wiki location.
|
|
50
120
|
* Used in layered recall to avoid double-counting.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zosmaai/pi-llm-wiki",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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",
|