lumina-wiki 0.4.0 → 0.7.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 +139 -0
- package/README.md +52 -0
- package/README.vi.md +52 -0
- package/README.zh.md +52 -0
- package/package.json +4 -3
- package/src/installer/commands.js +108 -6
- package/src/installer/manifest.js +73 -1
- package/src/installer/template-engine.js +3 -1
- package/src/scripts/lint.mjs +132 -6
- package/src/scripts/schemas.mjs +4 -0
- package/src/scripts/wiki.mjs +150 -4
- package/src/skills/core/check/SKILL.md +7 -2
- package/src/skills/core/ingest/SKILL.md +49 -0
- package/src/skills/core/ingest/references/dedup-policy.md +30 -0
- package/src/skills/core/migrate-legacy/SKILL.md +348 -0
- package/src/skills/packs/research/discover/SKILL.md +38 -9
- package/src/skills/packs/research/prefill/SKILL.md +71 -2
- package/src/templates/_lumina/schema/page-templates.md +1 -0
- package/src/tools/fetch_wikipedia.py +10 -1
- package/src/tools/init_discovery.py +34 -10
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Lumina-Wiki are documented here.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- `/lumi-migrate-legacy` core skill — LLM-driven backfill of provenance/confidence
|
|
10
|
+
- `CHANGELOG.md` shipped to `_lumina/CHANGELOG.md` for skill consumption
|
|
11
|
+
- Post-upgrade installer banner with lint summary (errors/warnings) when version bumps
|
|
12
|
+
- Manifest `schemaVersion` bump 1 → 2 with `legacyMigrationNeeded` flag
|
|
13
|
+
|
|
14
|
+
### Migration
|
|
15
|
+
- Upgrades from <0.6 set `legacyMigrationNeeded: true` in manifest. Run `/lumi-migrate-legacy` or `wiki.mjs migrate --add-defaults` to backfill `provenance` and `confidence` fields on existing sources/concepts.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [0.6.0] - 2026-05-03
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Schema: `provenance` field (required enum: `replayable|partial|missing`) on source nodes
|
|
23
|
+
- Schema: `confidence` field (optional float 0–1) on source and concept nodes
|
|
24
|
+
- Lint check L11: warns when `confidence` is missing on sources/concepts
|
|
25
|
+
- Lint `--summary` flag outputs stable JSON shape `{ by_check: { L01..L11 } }` for machine consumption
|
|
26
|
+
- `wiki.mjs`: 8-hex `session_id` segment in log entries; `LUMINA_SESSION_ID` env override for multi-write correlation
|
|
27
|
+
- Installer `migrateManifest` helper for forward-compatible `schemaVersion` upgrades (1→1 no-op today, ready for 1→2)
|
|
28
|
+
- Skills: provenance/confidence rubric added to `/lumi-ingest`, `/lumi-discover`, `/lumi-prefill`
|
|
29
|
+
- ROADMAP: v1.0 `/lumi-verify` pass planned (3 stages: grounding A wiki↔raw, drift B raw↔URL, external C wiki↔web)
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- CI: enumerate test files explicitly; use `fileURLToPath` for CLI path resolution
|
|
33
|
+
- CI: quote test globs for Windows; install `requests` for Python tests
|
|
34
|
+
- CI: spawn `npm.cmd` via shell on Windows
|
|
35
|
+
- Scripts: resolve `reset.mjs` and `wiki.mjs` paths with `fileURLToPath`
|
|
36
|
+
- Tools: strip Windows-illegal characters from discovery source IDs
|
|
37
|
+
- Docs: recommend `qmd` skill for local search across all README language files
|
|
38
|
+
|
|
39
|
+
### Migration
|
|
40
|
+
- Sources need `provenance` (required) added; concepts and sources may add `confidence` (optional).
|
|
41
|
+
- Run `wiki.mjs migrate --add-defaults` for deterministic backfill (sets `provenance: missing`, omits `confidence`), or `/lumi-migrate-legacy` (v0.7+) for LLM-driven backfill.
|
|
42
|
+
- `log.md` entries now include `session:<8hex>` segment — backward-compatible parser; no migration needed for existing log entries.
|
|
43
|
+
- `lint --summary` JSON shape is stable from this version forward; scripts consuming raw lint output should migrate to `--summary`.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## [0.5.0] - 2026-05-03
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
- Foundation aliases in wiki: named aliases for foundation nodes enable cross-skill deduplication
|
|
51
|
+
- `wiki.mjs resolve-alias` command for alias lookup
|
|
52
|
+
- Research: `/lumi-prefill` handles Wikipedia disambiguation pages and title collisions gracefully
|
|
53
|
+
- Research: `/lumi-discover` surfaces entry purpose field and deduplicates ingested papers; logs discovery phases
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- `wiki.mjs resolve-alias` no-match error now unwrapped to correct stderr format
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
- Policy: cross-model review framed around bundled infra, not bias — second-model review is user choice, not blocked
|
|
60
|
+
|
|
61
|
+
### Migration
|
|
62
|
+
- No schema changes. No migration needed.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## [0.4.0] - 2026-05-02
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
- GEMINI.md agent entry-point stub for Gemini IDE targets
|
|
70
|
+
- README restructured into multi-language files; skill names updated throughout
|
|
71
|
+
- Obsidian vault setup documented across all language READMEs; agent entry-point stubs excluded from vault
|
|
72
|
+
- Contributor guide added (`docs/`)
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
- Skill `canonicalId` values namespaced with pack prefix (e.g. `research:lumi-discover`)
|
|
76
|
+
- Installer: BMAD-style directory prompt; `project_name` auto-derived from directory
|
|
77
|
+
- Installer: broadened Codex target; added `qwen` and `iflow` CLI targets
|
|
78
|
+
- Installer: yellow LUMINA WIKI banner shown on install
|
|
79
|
+
|
|
80
|
+
### Migration
|
|
81
|
+
- If referencing skill `canonicalId` values in custom tooling, update to pack-prefixed form (e.g. `lumi-discover` → `research:lumi-discover`). Skill filenames and slash-command names are unchanged.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## [0.3.0] - 2026-05-02
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
- `extract_pdf.py` shipped as core PDF extractor for all installs (no opt-in required)
|
|
89
|
+
|
|
90
|
+
### Migration
|
|
91
|
+
- No schema or API changes. No migration needed.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## [0.2.0] - 2026-05-02
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
- Full installer with pack system (`core`, `research`, `reading`)
|
|
99
|
+
- CI matrix and package readiness checks (`ci:idempotency`, `ci:package`)
|
|
100
|
+
- Agent context files: `CLAUDE.md`, `AGENTS.md`, dev guide, sandbox helper
|
|
101
|
+
- `.gitignore` for `node_modules`, `__pycache__`, `.env`, editor files
|
|
102
|
+
- Skills output flattened to `.agents/skills/lumi-*` layout
|
|
103
|
+
- Installer: yellow LUMINA WIKI banner, 5-prompt flow, 3-file manifest
|
|
104
|
+
- README: badges, language links, end-user docs
|
|
105
|
+
- Tagline: "Where Knowledge Starts to Glow"
|
|
106
|
+
- ROADMAP: v1 daily-fetch and v2 source/ranking expansion plans
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
- `.agents/skills/` output renamed from nested layout to flat `lumi-*` prefix
|
|
110
|
+
|
|
111
|
+
### Migration
|
|
112
|
+
- Fresh install from v0.1: re-run `npx lumina-wiki install --yes`. Existing `raw/` and `wiki/` content is preserved.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## [0.1.0] - 2026-05-01
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
- Initial npm package scaffold
|
|
120
|
+
- Core scripts: `wiki.mjs` (graph/frontmatter engine), `lint.mjs` (9 checks), `reset.mjs`, `schemas.mjs`
|
|
121
|
+
- 14 skills locked: 6 core (`/lumi-init`, `/lumi-ingest`, `/lumi-ask`, `/lumi-edit`, `/lumi-check`, `/lumi-reset`), 4 research, 4 reading
|
|
122
|
+
- Installer entry point `bin/lumina.js` (ESM, lazy imports, <300 ms cold start)
|
|
123
|
+
- Atomic write discipline (`atomicWrite` with `fd.datasync()` + rename) throughout
|
|
124
|
+
- `safePath()` path validation rejecting `..`, absolute paths, Windows drive letters
|
|
125
|
+
- Bidirectional link enforcement; `raw/` read-only except `raw/tmp/` and `raw/discovered/`
|
|
126
|
+
- PRD, architecture docs, and v0.1 quick-spec
|
|
127
|
+
|
|
128
|
+
### Migration
|
|
129
|
+
- First release. No prior version to migrate from.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
[Unreleased]: https://github.com/tronghieu/lumina-wiki/compare/v0.6.0...HEAD
|
|
134
|
+
[0.6.0]: https://github.com/tronghieu/lumina-wiki/compare/v0.5.0...v0.6.0
|
|
135
|
+
[0.5.0]: https://github.com/tronghieu/lumina-wiki/compare/v0.4.0...v0.5.0
|
|
136
|
+
[0.4.0]: https://github.com/tronghieu/lumina-wiki/compare/v0.3.0...v0.4.0
|
|
137
|
+
[0.3.0]: https://github.com/tronghieu/lumina-wiki/compare/v0.2.0...v0.3.0
|
|
138
|
+
[0.2.0]: https://github.com/tronghieu/lumina-wiki/compare/v0.1.0...v0.2.0
|
|
139
|
+
[0.1.0]: https://github.com/tronghieu/lumina-wiki/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -66,6 +66,37 @@ If you installed the `research` pack, some skills need API keys to search online
|
|
|
66
66
|
|
|
67
67
|
The agent will guide you through an interactive setup to save your keys to a local `.env` file.
|
|
68
68
|
|
|
69
|
+
### **Step 3 (Upgrades): Migrate Legacy Wiki Entries**
|
|
70
|
+
|
|
71
|
+
If you are **re-installing Lumina-Wiki on a project that already has a `wiki/` from an earlier version**, run the installer the same way:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx lumina-wiki install
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The installer detects the version bump and updates scripts, schemas, and skills atomically. **Your wiki content (`wiki/`, `raw/`, `log.md`) is never modified by the installer.** When the installer finds frontmatter fields added by newer versions but missing on older entries, it prints a `[warn]` banner with the count and the next step.
|
|
78
|
+
|
|
79
|
+
You then have two ways to backfill:
|
|
80
|
+
|
|
81
|
+
**Option A — LLM-driven (recommended):** Open your AI chat and run:
|
|
82
|
+
|
|
83
|
+
> **You:**
|
|
84
|
+
> `/lumi-migrate-legacy`
|
|
85
|
+
|
|
86
|
+
The skill reads `_lumina/CHANGELOG.md` to learn which fields each version added, runs `lint --json` to find affected entries, and infers per-entry values (e.g. `provenance: replayable | partial | missing`, `confidence: high | medium | low | unverified`) from `raw/` snapshots, citation edges, and entry metadata. Idempotent — safe to run multiple times.
|
|
87
|
+
|
|
88
|
+
**Option B — Quick deterministic backfill:** From your terminal:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
node _lumina/scripts/wiki.mjs migrate --add-defaults
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This applies conservative defaults (`provenance: missing`, `confidence: unverified`) to every entry that lacks them. Lint goes green immediately, but values are placeholders — you can refine later with Option A or by editing entries by hand.
|
|
95
|
+
|
|
96
|
+
You can combine: run Option B first for a clean lint, then Option A when you want higher-quality values. Both write atomically and leave a trail in `wiki/log.md`.
|
|
97
|
+
|
|
98
|
+
For the full list of schema changes per version, see [`CHANGELOG.md`](CHANGELOG.md) or the local copy at `_lumina/CHANGELOG.md` after install.
|
|
99
|
+
|
|
69
100
|
## 3. Your First Commands (Core Skills)
|
|
70
101
|
|
|
71
102
|
Interact with your wiki using these commands in your AI chat interface (Gemini CLI, Claude, etc.).
|
|
@@ -136,6 +167,27 @@ Lumina creates a workspace with a clear purpose for each directory.
|
|
|
136
167
|
|
|
137
168
|
> The `wiki/graph/` folder contains `edges.jsonl` and `citations.jsonl` (machine-readable data files, not markdown). Excluding it keeps the graph view clean.
|
|
138
169
|
|
|
170
|
+
### **Local Search with qmd (Optional)**
|
|
171
|
+
|
|
172
|
+
As your wiki grows, you may want faster full-text search than `index.md` plus `grep` can offer. We recommend [qmd](https://github.com/tobi/qmd) — a local, on-device search engine for markdown files with hybrid BM25/vector search and LLM re-ranking. It pairs nicely with Lumina-Wiki and your AI agent.
|
|
173
|
+
|
|
174
|
+
**How to wire it into your agent:**
|
|
175
|
+
|
|
176
|
+
1. Install qmd following the instructions in its repo, then index the project root so it sees both `wiki/` and `raw/`.
|
|
177
|
+
2. **CLI route** — your agent can call `qmd <query>` via `Bash`. Just mention in your prompts that the command is available.
|
|
178
|
+
3. **MCP route (handy for Claude Code, Codex, Cursor)** — register qmd's MCP server in your IDE's MCP config. The agent picks it up as a native tool and can call it from `/lumi-ask` or any follow-up.
|
|
179
|
+
4. Re-index after `/lumi-ingest` (manually or via a hook) so new pages become searchable.
|
|
180
|
+
|
|
181
|
+
qmd sits alongside `index.md` and the wiki graph — a fast retrieval layer that feeds your agent better candidates before it reads pages in full.
|
|
182
|
+
|
|
183
|
+
**Bonus — tobi's official qmd skill.** tobi also publishes a dedicated skill that teaches your agent how to use qmd effectively (when to pick `lex` vs `vec` vs `hyde`, how to write `intent` to disambiguate, lex syntax for phrases and exclusions). If your IDE supports the skill format, you can install it with:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx skills add https://github.com/tobi/qmd --skill qmd
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
We recommend reading [the skill page on skills.sh](https://skills.sh/tobi/qmd/qmd) first to see exactly what it adds.
|
|
190
|
+
|
|
139
191
|
---
|
|
140
192
|
|
|
141
193
|
## 5. Available Skills and Tools (v0.1)
|
package/README.vi.md
CHANGED
|
@@ -64,6 +64,37 @@ Nếu bạn đã cài đặt gói `research`, một số kỹ năng sẽ cần A
|
|
|
64
64
|
|
|
65
65
|
Agent sẽ hướng dẫn bạn qua một quy trình cài đặt tương tác để lưu các key của bạn vào file `.env` cục bộ.
|
|
66
66
|
|
|
67
|
+
### **Bước 3 (Khi nâng cấp): Migrate các entry wiki cũ**
|
|
68
|
+
|
|
69
|
+
Nếu bạn **cài lại Lumina-Wiki trên một dự án đã có sẵn `wiki/` từ phiên bản trước**, chạy installer như bình thường:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx lumina-wiki install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Installer phát hiện version mới và cập nhật scripts, schemas, skills atomically. **Nội dung wiki của bạn (`wiki/`, `raw/`, `log.md`) không bị installer chỉnh sửa.** Khi installer thấy các trường frontmatter mới được thêm bởi version mới nhưng thiếu trên các entry cũ, nó sẽ in banner `[warn]` kèm số lượng và bước tiếp theo.
|
|
76
|
+
|
|
77
|
+
Bạn có hai cách để backfill:
|
|
78
|
+
|
|
79
|
+
**Cách A — LLM-driven (khuyến nghị):** Mở chat AI và chạy:
|
|
80
|
+
|
|
81
|
+
> **Bạn:**
|
|
82
|
+
> `/lumi-migrate-legacy`
|
|
83
|
+
|
|
84
|
+
Skill đọc `_lumina/CHANGELOG.md` để biết phiên bản nào thêm trường gì, chạy `lint --json` để tìm entry bị ảnh hưởng, và infer giá trị cho từng entry (ví dụ: `provenance: replayable | partial | missing`, `confidence: high | medium | low | unverified`) dựa trên snapshot trong `raw/`, citation edges, và metadata. Idempotent — chạy lại nhiều lần vẫn an toàn.
|
|
85
|
+
|
|
86
|
+
**Cách B — Backfill nhanh, deterministic:** Từ terminal:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
node _lumina/scripts/wiki.mjs migrate --add-defaults
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Lệnh này gán default bảo thủ (`provenance: missing`, `confidence: unverified`) cho mọi entry còn thiếu. Lint xanh ngay, nhưng giá trị chỉ là placeholder — bạn có thể tinh chỉnh sau bằng Cách A hoặc sửa tay.
|
|
93
|
+
|
|
94
|
+
Có thể kết hợp: chạy Cách B trước để lint xanh, sau đó Cách A khi muốn giá trị chính xác hơn. Cả hai đều atomic và để lại trail trong `wiki/log.md`.
|
|
95
|
+
|
|
96
|
+
Xem [`CHANGELOG.md`](CHANGELOG.md) hoặc bản local `_lumina/CHANGELOG.md` sau khi cài để biết toàn bộ thay đổi schema theo version.
|
|
97
|
+
|
|
67
98
|
## 3. Các lệnh đầu tiên của bạn (Kỹ năng cốt lõi)
|
|
68
99
|
|
|
69
100
|
Tương tác với wiki của bạn bằng cách sử dụng các lệnh này trong giao diện trò chuyện với AI Agent (ví dụ: Gemini CLI, Claude, v.v.).
|
|
@@ -134,6 +165,27 @@ Lumina tạo ra một không gian làm việc với mục đích rõ ràng cho t
|
|
|
134
165
|
|
|
135
166
|
> Thư mục `wiki/graph/` chứa `edges.jsonl` và `citations.jsonl` (dữ liệu máy đọc, không phải markdown). Exclude thư mục này giúp graph view không bị nhiễu.
|
|
136
167
|
|
|
168
|
+
### **Tìm kiếm cục bộ với qmd (Tùy chọn)**
|
|
169
|
+
|
|
170
|
+
Khi wiki của bạn lớn dần, bạn có thể muốn tìm kiếm full-text nhanh hơn so với `index.md` + `grep`. Chúng tôi gợi ý [qmd](https://github.com/tobi/qmd) — một search engine chạy hoàn toàn local trên file markdown, kết hợp BM25, vector search và LLM re-ranking. qmd phối hợp rất hợp với Lumina-Wiki và AI Agent của bạn.
|
|
171
|
+
|
|
172
|
+
**Cách tích hợp với AI Agent:**
|
|
173
|
+
|
|
174
|
+
1. Cài qmd theo hướng dẫn trong repo của nó, sau đó index thư mục gốc của project để qmd thấy cả `wiki/` lẫn `raw/`.
|
|
175
|
+
2. **Qua CLI** — agent có thể gọi `qmd <query>` bằng `Bash`. Chỉ cần nhắc trong prompt rằng câu lệnh này đã sẵn sàng.
|
|
176
|
+
3. **Qua MCP (rất tiện cho Claude Code, Codex, Cursor)** — đăng ký MCP server của qmd vào file cấu hình MCP của IDE. Agent sẽ nhận nó như một tool gốc và có thể gọi từ `/lumi-ask` hay câu hỏi tiếp theo.
|
|
177
|
+
4. Re-index sau mỗi lần `/lumi-ingest` (thủ công hoặc qua hook) để các trang mới có thể tìm được.
|
|
178
|
+
|
|
179
|
+
qmd đứng song song với `index.md` và wiki graph — một lớp truy xuất nhanh giúp agent có candidate tốt hơn trước khi đọc đầy đủ từng trang.
|
|
180
|
+
|
|
181
|
+
**Tuỳ chọn thêm — skill chính thức của tobi cho qmd.** tobi cũng phát hành một skill chuyên dụng, dạy agent cách dùng qmd hiệu quả (khi nào chọn `lex` vs `vec` vs `hyde`, cách viết `intent` để khử nhập nhằng, cú pháp lex cho phrase và exclude). Nếu IDE của bạn hỗ trợ định dạng skill, bạn có thể cài bằng:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npx skills add https://github.com/tobi/qmd --skill qmd
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Khuyến khích đọc [trang skill trên skills.sh](https://skills.sh/tobi/qmd/qmd) trước để xem chính xác skill này bổ sung những gì.
|
|
188
|
+
|
|
137
189
|
---
|
|
138
190
|
|
|
139
191
|
## 5. Các Kỹ năng và Công cụ có sẵn (v0.1)
|
package/README.zh.md
CHANGED
|
@@ -64,6 +64,37 @@ npx lumina-wiki install
|
|
|
64
64
|
|
|
65
65
|
Agent 将引导您通过交互式设置将密钥保存到本地 `.env` 文件中。
|
|
66
66
|
|
|
67
|
+
### **第三步(升级时):迁移旧版 Wiki 条目**
|
|
68
|
+
|
|
69
|
+
如果您**在已经有 `wiki/` 的旧项目上重新安装 Lumina-Wiki**,照常运行安装器:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx lumina-wiki install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
安装器检测到版本升级后会原子性地更新 scripts、schemas 和 skills。**您的 wiki 内容(`wiki/`、`raw/`、`log.md`)不会被安装器修改。** 当安装器发现新版本添加的 frontmatter 字段在旧条目中缺失时,会打印 `[warn]` 横幅,显示数量和下一步操作。
|
|
76
|
+
|
|
77
|
+
您有两种方式进行回填:
|
|
78
|
+
|
|
79
|
+
**方案 A — LLM 驱动(推荐):** 打开 AI 聊天并运行:
|
|
80
|
+
|
|
81
|
+
> **您:**
|
|
82
|
+
> `/lumi-migrate-legacy`
|
|
83
|
+
|
|
84
|
+
该技能读取 `_lumina/CHANGELOG.md` 了解每个版本添加了哪些字段,运行 `lint --json` 找出受影响的条目,并基于 `raw/` 快照、引用边和条目元数据为每个条目推断合适的值(例如 `provenance: replayable | partial | missing`,`confidence: high | medium | low | unverified`)。幂等 — 多次运行也是安全的。
|
|
85
|
+
|
|
86
|
+
**方案 B — 快速确定性回填:** 从终端运行:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
node _lumina/scripts/wiki.mjs migrate --add-defaults
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
此命令为所有缺失字段的条目设置保守的默认值(`provenance: missing`,`confidence: unverified`)。lint 立即变绿,但值只是占位符 — 您可以稍后通过方案 A 或手动编辑来优化。
|
|
93
|
+
|
|
94
|
+
您可以组合使用:先运行方案 B 让 lint 变绿,需要更准确的值时再运行方案 A。两种方式都是原子写入并在 `wiki/log.md` 留下记录。
|
|
95
|
+
|
|
96
|
+
完整的版本 schema 变更列表请见 [`CHANGELOG.md`](CHANGELOG.md) 或安装后的本地副本 `_lumina/CHANGELOG.md`。
|
|
97
|
+
|
|
67
98
|
## 3. 常用指令(核心技能 Core Skills)
|
|
68
99
|
|
|
69
100
|
在您的 AI 聊天界面(Gemini CLI, Claude 等)中使用这些指令与维基进行交互。
|
|
@@ -134,6 +165,27 @@ Lumina 创建的工作区为每个目录都设定了明确的用途。
|
|
|
134
165
|
|
|
135
166
|
> `wiki/graph/` 文件夹包含 `edges.jsonl` 和 `citations.jsonl`(机器可读数据文件,非 Markdown)。排除该文件夹可保持图谱视图整洁。
|
|
136
167
|
|
|
168
|
+
### **使用 qmd 进行本地搜索(可选)**
|
|
169
|
+
|
|
170
|
+
随着您的 Wiki 不断增长,您可能希望获得比 `index.md` + `grep` 更快的全文搜索体验。我们推荐 [qmd](https://github.com/tobi/qmd) —— 一个完全本地、设备上的 Markdown 搜索引擎,结合 BM25、向量搜索和 LLM 重排序。qmd 与 Lumina-Wiki 和您的 AI Agent 配合得非常顺畅。
|
|
171
|
+
|
|
172
|
+
**如何与 AI Agent 集成:**
|
|
173
|
+
|
|
174
|
+
1. 按照 qmd 仓库中的说明安装,然后对项目根目录建立索引,使 qmd 能同时看到 `wiki/` 和 `raw/`。
|
|
175
|
+
2. **CLI 方式** — Agent 可以通过 `Bash` 调用 `qmd <query>`。只需在提示中提及该命令已可用。
|
|
176
|
+
3. **MCP 方式(在 Claude Code、Codex、Cursor 中很方便)** — 在 IDE 的 MCP 配置中注册 qmd 的 MCP 服务器。Agent 会将其识别为原生工具,可以从 `/lumi-ask` 或后续提问中调用。
|
|
177
|
+
4. 在每次 `/lumi-ingest` 后重新索引(手动或通过 hook),让新页面可被搜索到。
|
|
178
|
+
|
|
179
|
+
qmd 与 `index.md` 和 wiki 图谱并行工作 —— 作为一个快速检索层,在 Agent 完整阅读页面之前为它提供更好的候选结果。
|
|
180
|
+
|
|
181
|
+
**额外推荐 —— tobi 的官方 qmd skill。** tobi 还发布了一个专用 skill,教您的 Agent 如何高效使用 qmd(何时选择 `lex` vs `vec` vs `hyde`、如何编写 `intent` 进行消歧、lex 短语与排除项语法)。如果您的 IDE 支持 skill 格式,可以通过以下命令安装:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npx skills add https://github.com/tobi/qmd --skill qmd
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
建议先阅读 [skills.sh 上的 skill 页面](https://skills.sh/tobi/qmd/qmd),了解它具体添加了什么。
|
|
188
|
+
|
|
137
189
|
---
|
|
138
190
|
|
|
139
191
|
## 5. 可用技能与工具 (v0.1)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "lumina-wiki",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "Domain-agnostic, multi-IDE wiki scaffolder — Karpathy's LLM-Wiki vision, cross-platform and pack-based.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"llm-wiki",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"src/tools/fetch_s2.py",
|
|
56
56
|
"src/tools/fetch_deepxiv.py",
|
|
57
57
|
"src/tools/requirements.txt",
|
|
58
|
+
"CHANGELOG.md",
|
|
58
59
|
"README.md",
|
|
59
60
|
"LICENSE"
|
|
60
61
|
],
|
|
@@ -71,8 +72,8 @@
|
|
|
71
72
|
"devDependencies": {},
|
|
72
73
|
"scripts": {
|
|
73
74
|
"test": "npm run test:installer",
|
|
74
|
-
"test:installer": "node --test src/installer
|
|
75
|
-
"test:scripts": "node --test src/scripts
|
|
75
|
+
"test:installer": "node --test src/installer/commands.test.js src/installer/fs.test.js src/installer/manifest.test.js src/installer/template-engine.test.js src/installer/update-check.test.js",
|
|
76
|
+
"test:scripts": "node --test src/scripts/lint.test.mjs src/scripts/reset.test.mjs src/scripts/wiki.test.mjs",
|
|
76
77
|
"test:python": "python3 -m pytest src/tools/tests -q",
|
|
77
78
|
"test:all": "npm run test:installer && npm run test:scripts && npm run test:python",
|
|
78
79
|
"test:fs": "node --test src/installer/fs.test.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { readFile, writeFile, rename, unlink, rm, access, copyFile } from 'node:fs/promises';
|
|
18
18
|
import { join, resolve, relative, dirname, basename } from 'node:path';
|
|
19
19
|
import { constants as fsConstants } from 'node:fs';
|
|
20
|
+
import { spawnSync } from 'node:child_process';
|
|
20
21
|
import { createRequire } from 'node:module';
|
|
21
22
|
import { fileURLToPath } from 'node:url';
|
|
22
23
|
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
import {
|
|
32
33
|
readManifest,
|
|
33
34
|
writeManifest,
|
|
35
|
+
migrateManifest,
|
|
34
36
|
readSkillsManifest,
|
|
35
37
|
writeSkillsManifest,
|
|
36
38
|
readFilesManifest,
|
|
@@ -223,6 +225,9 @@ export async function installCommand(opts = {}) {
|
|
|
223
225
|
// 8. Copy scripts
|
|
224
226
|
await copyScripts(projectRoot);
|
|
225
227
|
|
|
228
|
+
// 8.5. Copy CHANGELOG.md so /lumi-migrate-legacy can read it offline
|
|
229
|
+
await copyChangelog(projectRoot);
|
|
230
|
+
|
|
226
231
|
// 9. Copy skills
|
|
227
232
|
const skillRows = await copySkills(projectRoot, packs);
|
|
228
233
|
|
|
@@ -259,7 +264,13 @@ export async function installCommand(opts = {}) {
|
|
|
259
264
|
|
|
260
265
|
// 17. Write three state files atomically
|
|
261
266
|
const now = new Date().toISOString();
|
|
267
|
+
// Run schema migrations on the existing manifest first so flags like
|
|
268
|
+
// legacyMigrationNeeded are preserved into the final write.
|
|
269
|
+
const migrated = existingManifest
|
|
270
|
+
? migrateManifest(existingManifest, MANIFEST_SCHEMA_VERSION)
|
|
271
|
+
: {};
|
|
262
272
|
const manifest = {
|
|
273
|
+
...migrated,
|
|
263
274
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
264
275
|
packageVersion: PKG.version,
|
|
265
276
|
installedAt: existingManifest?.installedAt ?? now,
|
|
@@ -280,6 +291,16 @@ export async function installCommand(opts = {}) {
|
|
|
280
291
|
await writeSkillsManifest(projectRoot, skillRows);
|
|
281
292
|
await writeFilesManifest(projectRoot, fileRows);
|
|
282
293
|
|
|
294
|
+
// 17.5. Post-upgrade: spawn lint --summary, print banner if findings exist
|
|
295
|
+
if (isUpgrade && existingManifest.packageVersion !== PKG.version) {
|
|
296
|
+
await printPostUpgradeBanner({
|
|
297
|
+
projectRoot,
|
|
298
|
+
fromVersion: existingManifest.packageVersion,
|
|
299
|
+
toVersion: PKG.version,
|
|
300
|
+
colors,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
283
304
|
// 18. Print summary
|
|
284
305
|
console.log('');
|
|
285
306
|
console.log(colors.green('[done] Lumina Wiki installed successfully.'));
|
|
@@ -395,6 +416,76 @@ export async function versionCommand(opts = {}) {
|
|
|
395
416
|
// Internal helpers
|
|
396
417
|
// ---------------------------------------------------------------------------
|
|
397
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Run lint --summary in the project root and, if findings exist, print a
|
|
421
|
+
* post-upgrade banner to stderr.
|
|
422
|
+
*
|
|
423
|
+
* @param {object} opts
|
|
424
|
+
* @param {string} opts.projectRoot
|
|
425
|
+
* @param {string} opts.fromVersion
|
|
426
|
+
* @param {string} opts.toVersion
|
|
427
|
+
* @param {object} opts.colors
|
|
428
|
+
*/
|
|
429
|
+
export async function printPostUpgradeBanner({ projectRoot, fromVersion, toVersion, colors }) {
|
|
430
|
+
let summary;
|
|
431
|
+
try {
|
|
432
|
+
const lintScript = join(projectRoot, '_lumina', 'scripts', 'lint.mjs');
|
|
433
|
+
const result = spawnSync(
|
|
434
|
+
process.execPath,
|
|
435
|
+
[lintScript, '--summary'],
|
|
436
|
+
{ cwd: projectRoot, encoding: 'utf8', timeout: 30000 },
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
// Exit codes: 0 = clean, 1 = findings. Anything else (crash / ENOENT) → skip.
|
|
440
|
+
if (result.error || (result.status !== 0 && result.status !== 1)) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
summary = JSON.parse(result.stdout.trim());
|
|
446
|
+
} catch {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
} catch {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const { errors = 0, warnings = 0 } = summary;
|
|
454
|
+
if (errors === 0 && warnings === 0) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const banner = [
|
|
459
|
+
'',
|
|
460
|
+
colors.yellow(`[warn] Lumina upgraded v${fromVersion} -> v${toVersion} — schema gap detected:`),
|
|
461
|
+
colors.yellow(` ${errors} error(s), ${warnings} warning(s) across legacy entries.`),
|
|
462
|
+
'',
|
|
463
|
+
' Quick fix (deterministic):',
|
|
464
|
+
' node _lumina/scripts/wiki.mjs migrate --add-defaults',
|
|
465
|
+
'',
|
|
466
|
+
' Smart fix (LLM-driven, recommended):',
|
|
467
|
+
' /lumi-migrate-legacy',
|
|
468
|
+
'',
|
|
469
|
+
' Both are idempotent. See _lumina/CHANGELOG.md for details.',
|
|
470
|
+
'',
|
|
471
|
+
].join('\n');
|
|
472
|
+
|
|
473
|
+
process.stderr.write(banner + '\n');
|
|
474
|
+
|
|
475
|
+
// Spawn-and-forget: append upgrade log entry (ignore failures, e.g., wiki/ missing)
|
|
476
|
+
try {
|
|
477
|
+
const wikiScript = join(projectRoot, '_lumina', 'scripts', 'wiki.mjs');
|
|
478
|
+
const logMsg = `upgrade v${fromVersion}->v${toVersion}: ${errors} errors, ${warnings} warnings — run /lumi-migrate-legacy`;
|
|
479
|
+
spawnSync(
|
|
480
|
+
process.execPath,
|
|
481
|
+
[wikiScript, 'log', 'installer', logMsg],
|
|
482
|
+
{ cwd: projectRoot, encoding: 'utf8', timeout: 10000 },
|
|
483
|
+
);
|
|
484
|
+
} catch {
|
|
485
|
+
// Ignore: wiki/ may not exist for incomplete installs
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
398
489
|
async function readAnswersFromConfig(projectRoot, existingManifest) {
|
|
399
490
|
// Try reading lumina.config.yaml for stored answers
|
|
400
491
|
try {
|
|
@@ -690,6 +781,16 @@ async function copyScripts(projectRoot) {
|
|
|
690
781
|
}
|
|
691
782
|
}
|
|
692
783
|
|
|
784
|
+
async function copyChangelog(projectRoot) {
|
|
785
|
+
const src = join(PACKAGE_ROOT, 'CHANGELOG.md');
|
|
786
|
+
const dest = join(projectRoot, '_lumina', 'CHANGELOG.md');
|
|
787
|
+
try {
|
|
788
|
+
await copyFile(src, dest);
|
|
789
|
+
} catch (_) {
|
|
790
|
+
// CHANGELOG may not exist in older snapshots; skip gracefully
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
693
794
|
async function copySkills(projectRoot, packs) {
|
|
694
795
|
const skillRows = [];
|
|
695
796
|
const skillDefs = getSkillDefs(packs);
|
|
@@ -735,12 +836,13 @@ function getSkillDefs(packs) {
|
|
|
735
836
|
|
|
736
837
|
if (packs.includes('core')) {
|
|
737
838
|
const coreSkills = [
|
|
738
|
-
{ name: 'init',
|
|
739
|
-
{ name: 'ingest',
|
|
740
|
-
{ name: 'ask',
|
|
741
|
-
{ name: 'edit',
|
|
742
|
-
{ name: 'check',
|
|
743
|
-
{ name: 'reset',
|
|
839
|
+
{ name: 'init', canonicalId: 'lumi-init', displayName: '/lumi-init' },
|
|
840
|
+
{ name: 'ingest', canonicalId: 'lumi-ingest', displayName: '/lumi-ingest' },
|
|
841
|
+
{ name: 'ask', canonicalId: 'lumi-ask', displayName: '/lumi-ask' },
|
|
842
|
+
{ name: 'edit', canonicalId: 'lumi-edit', displayName: '/lumi-edit' },
|
|
843
|
+
{ name: 'check', canonicalId: 'lumi-check', displayName: '/lumi-check' },
|
|
844
|
+
{ name: 'reset', canonicalId: 'lumi-reset', displayName: '/lumi-reset' },
|
|
845
|
+
{ name: 'migrate-legacy', canonicalId: 'lumi-migrate-legacy', displayName: '/lumi-migrate-legacy' },
|
|
744
846
|
];
|
|
745
847
|
for (const s of coreSkills) {
|
|
746
848
|
defs.push({ ...s, pack: 'core', srcPackPath: 'core' });
|
|
@@ -19,7 +19,7 @@ import { atomicWrite, ensureDir } from './fs.js';
|
|
|
19
19
|
// Constants
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
|
|
22
|
-
export const MANIFEST_SCHEMA_VERSION =
|
|
22
|
+
export const MANIFEST_SCHEMA_VERSION = 2;
|
|
23
23
|
|
|
24
24
|
export const SKILLS_CSV_HEADER = 'canonical_id,display_name,pack,source,relative_path,target_link_path,version';
|
|
25
25
|
export const FILES_CSV_HEADER = 'relative_path,sha256,source_pack,installed_version';
|
|
@@ -274,6 +274,78 @@ export async function writeFilesManifest(projectRoot, rows) {
|
|
|
274
274
|
await atomicWrite(csvPath, serializeCsv(rows, cols));
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// Manifest migration
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Migration registry shape (for future entries):
|
|
283
|
+
*
|
|
284
|
+
* const MIGRATIONS = {
|
|
285
|
+
* '1->2': (m) => ({ ...m, newField: 'default' }),
|
|
286
|
+
* '2->3': (m) => { ... return updatedManifest; },
|
|
287
|
+
* };
|
|
288
|
+
*
|
|
289
|
+
* To add a migration from version N to N+1:
|
|
290
|
+
* 1. Bump MANIFEST_SCHEMA_VERSION to N+1.
|
|
291
|
+
* 2. Add `'N->N+1': (m) => { ...transform... }` to MIGRATIONS.
|
|
292
|
+
* 3. The loop below will apply it automatically.
|
|
293
|
+
*/
|
|
294
|
+
const MIGRATIONS = {
|
|
295
|
+
'1->2': (m) => ({ ...m, legacyMigrationNeeded: true }),
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Migrate a manifest object to the target schema version.
|
|
300
|
+
*
|
|
301
|
+
* - If `manifest.schemaVersion === targetVersion` — no-op, returns manifest unchanged.
|
|
302
|
+
* - If `manifest.schemaVersion` is missing (legacy install) — sets it to 1 and returns.
|
|
303
|
+
* - If `manifest.schemaVersion > targetVersion` — throws (downgrade not supported, code 3).
|
|
304
|
+
* - If `manifest.schemaVersion < targetVersion` — applies registered migrations in order.
|
|
305
|
+
*
|
|
306
|
+
* @param {object} manifest - Parsed manifest object (may lack schemaVersion).
|
|
307
|
+
* @param {number} targetVersion - The schema version to migrate to.
|
|
308
|
+
* @returns {object} - The migrated manifest (new object if changed).
|
|
309
|
+
*/
|
|
310
|
+
export function migrateManifest(manifest, targetVersion) {
|
|
311
|
+
// Legacy install: schemaVersion was not recorded before this constant existed.
|
|
312
|
+
if (manifest.schemaVersion === undefined || manifest.schemaVersion === null) {
|
|
313
|
+
return { ...manifest, schemaVersion: 1 };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const current = manifest.schemaVersion;
|
|
317
|
+
|
|
318
|
+
if (current === targetVersion) {
|
|
319
|
+
return manifest;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (current > targetVersion) {
|
|
323
|
+
const err = new Error(
|
|
324
|
+
`Manifest schemaVersion ${current} is newer than installer target ${targetVersion}. ` +
|
|
325
|
+
'Downgrade is not supported. Update lumina-wiki to the latest version.',
|
|
326
|
+
);
|
|
327
|
+
err.code = 3;
|
|
328
|
+
throw err;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Apply migrations step-by-step (current → current+1 → … → targetVersion).
|
|
332
|
+
let m = manifest;
|
|
333
|
+
for (let v = current; v < targetVersion; v++) {
|
|
334
|
+
const key = `${v}->${v + 1}`;
|
|
335
|
+
const migrate = MIGRATIONS[key];
|
|
336
|
+
if (!migrate) {
|
|
337
|
+
const err = new Error(
|
|
338
|
+
`No migration found for schemaVersion ${key}. ` +
|
|
339
|
+
'This is an internal error — please file an issue.',
|
|
340
|
+
);
|
|
341
|
+
err.code = 3;
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
344
|
+
m = { ...migrate(m), schemaVersion: v + 1 };
|
|
345
|
+
}
|
|
346
|
+
return m;
|
|
347
|
+
}
|
|
348
|
+
|
|
277
349
|
// ---------------------------------------------------------------------------
|
|
278
350
|
// State file paths helper
|
|
279
351
|
// ---------------------------------------------------------------------------
|
|
@@ -124,6 +124,8 @@ export function renderReadme(template, variables, purpose = '') {
|
|
|
124
124
|
return [
|
|
125
125
|
titleLine,
|
|
126
126
|
'',
|
|
127
|
+
'## Project Purpose',
|
|
128
|
+
'',
|
|
127
129
|
purposeText,
|
|
128
130
|
'',
|
|
129
131
|
'<!-- lumina:schema -->',
|
|
@@ -140,7 +142,7 @@ export function renderReadme(template, variables, purpose = '') {
|
|
|
140
142
|
// Find end of title block (first non-empty, non-H1 line before marker)
|
|
141
143
|
let insertIdx = schemaMarkerIdx;
|
|
142
144
|
// Insert purpose region before schema marker
|
|
143
|
-
const purposeLines = ['', purposeText, ''];
|
|
145
|
+
const purposeLines = ['', '## Project Purpose', '', purposeText, ''];
|
|
144
146
|
lines.splice(insertIdx, 0, ...purposeLines);
|
|
145
147
|
|
|
146
148
|
return lines.join('\n');
|