lumina-wiki 1.5.0 → 1.6.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 +86 -1
- package/README.md +198 -2
- package/README.vi.md +13 -2
- package/README.zh.md +13 -2
- package/package.json +1 -1
- package/src/installer/commands.js +24 -19
- package/src/installer/prompts.js +20 -3
- package/src/scripts/discover-runner.mjs +91 -15
- package/src/scripts/external-ids.mjs +40 -4
- package/src/scripts/lib/watchlist-config.mjs +57 -4
- package/src/scripts/schemas.mjs +4 -2
- package/src/skills/core/ingest/references/step-01-draft.md +22 -7
- package/src/skills/packs/research/discover/SKILL.md +2 -1
- package/src/skills/packs/research/discover/references/source-modes.md +9 -1
- package/src/skills/packs/research/setup/SKILL.md +7 -0
- package/src/skills/packs/research/watch-run/SKILL.md +104 -0
- package/src/skills/packs/research/watchlist/SKILL.md +12 -4
- package/src/templates/README.md +1 -1
- package/src/templates/README.vi.md +1 -1
- package/src/templates/README.zh.md +1 -1
- package/src/templates/_lumina/schema/lumi-help.csv +1 -0
- package/src/templates/_lumina/scripts/scheduler-samples/cron-daily.sh +44 -0
- package/src/tools/_cache.py +37 -6
- package/src/tools/fetch_pdf.py +169 -10
- package/src/tools/id_utils.py +99 -3
- package/src/tools/init_discovery.py +60 -4
- package/src/tools/requirements.txt +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,90 @@
|
|
|
3
3
|
All notable changes to Lumina-Wiki are documented here.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [1.6.0] - 2026-05-15
|
|
9
|
+
|
|
10
|
+
### Added — Multi-provider PDF resolution + RSS / Atom feeds (research pack)
|
|
11
|
+
|
|
12
|
+
- **OpenAlex fetcher** activated as the metadata anchor across the new ladder
|
|
13
|
+
(Phase 1–2). `external_ids.openalex` namespace now persists Work IDs
|
|
14
|
+
(`^W\d+$`).
|
|
15
|
+
- **`fetch_unpaywall.py`** — DOI → best OA PDF URL. Requires
|
|
16
|
+
`UNPAYWALL_EMAIL` (free email-of-record).
|
|
17
|
+
- **`fetch_core.py`** — CORE search + download-url. Optional
|
|
18
|
+
`CORE_API_KEY`; ladder skips CORE on 429 and warns once.
|
|
19
|
+
- **`resolve_pdf.py`** — 2-layer orchestrator. Layer A always runs OpenAlex
|
|
20
|
+
(cross-walks DOI ↔ arXiv ↔ OpenAlex). Layer B is a stop-on-first-200 PDF
|
|
21
|
+
ladder: `oa_url → unpaywall → core → arxiv`. Each provider attempt is
|
|
22
|
+
logged to stderr; the final shape carries `external_ids`, `sources[]`,
|
|
23
|
+
`pdf_path`, and `status` (`ok` | `metadata_only` | `failed`).
|
|
24
|
+
- **`fetch_rss.py`** — RSS / Atom poller with etag caching, defusedxml-based
|
|
25
|
+
XXE rejection, per-feed state files under `_lumina/_state/feeds/<id>.json`,
|
|
26
|
+
spill-aware `max_new` cap, and 5000-entry / 90-day `last_seen_guids`
|
|
27
|
+
eviction.
|
|
28
|
+
- **Watchlist `type: feed`** items extend `_lumina/config/watchlist.yml`
|
|
29
|
+
additively. v1 files without `type` keep validating (defaults to
|
|
30
|
+
`topic`). Feed URLs are gated to `^https://` and rejected if they start
|
|
31
|
+
with `--` (flag-injection defense-in-depth).
|
|
32
|
+
- **`/lumi-research-watch-run`** skill orchestrates a single pass over the
|
|
33
|
+
consolidated watchlist (topics + feeds). User owns scheduling — three
|
|
34
|
+
patterns documented (cron, launchd, Task Scheduler).
|
|
35
|
+
- **`cron-daily.sh` wrapper** ships under
|
|
36
|
+
`_lumina/scripts/scheduler-samples/`. Inert until the user wires it into
|
|
37
|
+
their scheduler. Sets `umask 077`, `chmod 600` on the log,
|
|
38
|
+
rotates at 1 MB.
|
|
39
|
+
- **`extract_ids_from_text()`** in `id_utils.py` — reusable free-text
|
|
40
|
+
identifier harvester for feed entry titles / summaries / link hrefs.
|
|
41
|
+
|
|
42
|
+
### Added — Project governance
|
|
43
|
+
|
|
44
|
+
- `CONTRIBUTING.md` at the repo root: workflow checklists for adding skills,
|
|
45
|
+
fetchers, schema changes, installer changes, and entry-point stubs; the
|
|
46
|
+
trilingual user-docs convention; CI gates; exit-code contract; and a section
|
|
47
|
+
specifically scoped to AI-agent contributors that points at
|
|
48
|
+
`docs/project-context.md`, `CLAUDE.md`, and `docs/DEVELOPMENT.md` as
|
|
49
|
+
load-bearing context.
|
|
50
|
+
- `CODE_OF_CONDUCT.md` at the repo root: Contributor Covenant v2.1, contact
|
|
51
|
+
`tronghieu.luu@gmail.com`. Linked from `CONTRIBUTING.md` §2.
|
|
52
|
+
- `SECURITY.md` at the repo root: supported-versions table, private
|
|
53
|
+
reporting channels (GitHub Private Vulnerability Reporting + email),
|
|
54
|
+
in-scope / out-of-scope surfaces, severity bands, and coordinated
|
|
55
|
+
disclosure expectations.
|
|
56
|
+
- `.github/PULL_REQUEST_TEMPLATE.md`: per-change-type checklists that
|
|
57
|
+
mirror `CONTRIBUTING.md` §5 (skill / fetcher / schema / installer),
|
|
58
|
+
trilingual docs checkpoint, and a rule-deviation prompt.
|
|
59
|
+
|
|
60
|
+
### Security
|
|
61
|
+
|
|
62
|
+
- **SSRF guard** (`_safe_url`) on every PDF candidate URL: rejects RFC1918,
|
|
63
|
+
loopback, link-local, multicast, cloud-metadata (169.254.169.254).
|
|
64
|
+
Re-validated post-redirect.
|
|
65
|
+
- **`fetch_pdf.py` mid-stream size cap** (`MAX_PDF_BYTES = 100 MiB`) — a
|
|
66
|
+
malicious endpoint that lies about Content-Length now aborts mid-download
|
|
67
|
+
and cleans up `.tmp`.
|
|
68
|
+
- **DOI filename hashing** — DOIs are hashed to a 16-char SHA-256 prefix on
|
|
69
|
+
disk to neutralize Windows-reserved-name collisions (CON, PRN, AUX, NUL).
|
|
70
|
+
- **XXE pre-parse** — every RSS / Atom body is run through
|
|
71
|
+
`defusedxml.ElementTree.fromstring` before feedparser sees it; DOCTYPE /
|
|
72
|
+
billion-laughs payloads are rejected without state mutation.
|
|
73
|
+
|
|
74
|
+
### Requirements
|
|
75
|
+
|
|
76
|
+
- New optional env vars: `UNPAYWALL_EMAIL`, `CORE_API_KEY`. Both gracefully
|
|
77
|
+
skip (ladder continues) when unset.
|
|
78
|
+
- `requirements.txt` adds `feedparser>=6.0` (research pack only).
|
|
79
|
+
|
|
80
|
+
### Backwards compatibility
|
|
81
|
+
|
|
82
|
+
- `external_ids.openalex` is additive — existing pages continue to validate.
|
|
83
|
+
- `sources[]` is additive — entries without an entry stay valid.
|
|
84
|
+
`ns/value` fields drop silently if either is missing or invalid (same
|
|
85
|
+
forgiveness model as the existing `url` field).
|
|
86
|
+
- Watchlist v1 (no `type` field) still validates and runs unchanged.
|
|
87
|
+
- `fetch_pdf.py` CLI is stable; new helpers (`_safe_url`, `head_check`,
|
|
88
|
+
`MAX_PDF_BYTES`) are additions only.
|
|
89
|
+
|
|
6
90
|
## [1.5.0] - 2026-05-10
|
|
7
91
|
|
|
8
92
|
### Added — Learning Pack: `/lumi-learning-reflect` self-reflection skill (PRs #16, #17)
|
|
@@ -398,7 +482,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
398
482
|
|
|
399
483
|
---
|
|
400
484
|
|
|
401
|
-
[Unreleased]: https://github.com/tronghieu/lumina-wiki/compare/v1.
|
|
485
|
+
[Unreleased]: https://github.com/tronghieu/lumina-wiki/compare/v1.5.0...HEAD
|
|
486
|
+
[1.5.0]: https://github.com/tronghieu/lumina-wiki/compare/v1.4.0...v1.5.0
|
|
402
487
|
[1.4.0]: https://github.com/tronghieu/lumina-wiki/compare/v1.3.0...v1.4.0
|
|
403
488
|
[1.3.0]: https://github.com/tronghieu/lumina-wiki/compare/v1.2.0...v1.3.0
|
|
404
489
|
[1.2.0]: https://github.com/tronghieu/lumina-wiki/compare/v1.1.0...v1.2.0
|
package/README.md
CHANGED
|
@@ -184,6 +184,7 @@ These are the commands you can use when chatting with your AI agent.
|
|
|
184
184
|
| | `/lumi-research-prefill` | Seed foundational concepts to avoid duplicates. |
|
|
185
185
|
| | `/lumi-research-topic` | Create a topic page at `wiki/topics/<slug>.md` by gathering related concepts and sources already in your wiki. The AI proposes what to include and you confirm before anything is written. Use this after several `/lumi-ingest` runs when you want to give a theme its own page. |
|
|
186
186
|
| | `/lumi-research-setup` | Help configure API keys for research tools. |
|
|
187
|
+
| | `/lumi-research-watch-run` | Run one scheduled-discovery pass over your watchlist (topics + RSS / Atom feeds). Polls only when you ask. |
|
|
187
188
|
| **Reading** | `/lumi-reading-chapter-ingest` | Ingest a book chapter by chapter. |
|
|
188
189
|
| | `/lumi-reading-character-track` | Track characters and their relationships in a story. |
|
|
189
190
|
| | `/lumi-reading-theme-map` | Identify and map themes in a narrative. |
|
|
@@ -204,8 +205,8 @@ Lumina-Wiki is evolving rapidly. Here is our user-facing roadmap:
|
|
|
204
205
|
- [x] **Multilingual setup:** Choose English, Vietnamese, or Chinese as your primary language during install. *(shipped in v1.2)*
|
|
205
206
|
- [x] **Native DOCX, RTF & EPUB ingestion:** Pull Word, Rich Text, and EPUB books straight into your wiki via the research pack. *(shipped in v1.x)*
|
|
206
207
|
- [x] **Improved CI/CD:** Native support for Bun and Node 22 environments. *(shipped in v1.2)*
|
|
207
|
-
- [
|
|
208
|
-
- [
|
|
208
|
+
- [x] **Global Source Expansion:** Direct integration with OpenAlex, CORE, and Unpaywall for reliable DOI-to-PDF resolution. *(shipped in v1.6)*
|
|
209
|
+
- [x] **RSS & Blog Monitoring:** Automatically surface new papers from your favorite lab blogs and journals via `type: feed` watchlist items. *(shipped in v1.6)*
|
|
209
210
|
- [ ] **Advanced Paper Ranking:** See influence scores and quality signals for your research papers.
|
|
210
211
|
|
|
211
212
|
**Long-term (Deep Research & Integration)**
|
|
@@ -250,3 +251,198 @@ npm run test:all
|
|
|
250
251
|
- [简体中文 (Chinese)](README.zh.md)
|
|
251
252
|
|
|
252
253
|
**License:** [MIT](LICENSE) © Lưu Trọng Hiếu.
|
|
254
|
+
|
|
255
|
+
<!-- lumina:schema -->
|
|
256
|
+
|
|
257
|
+
## Roles
|
|
258
|
+
|
|
259
|
+
You are the wiki maintainer. The user curates sources, asks questions, and directs analysis. You do everything else: read, summarize, connect pages, file notes, run health checks, and keep the wiki coherent. You write the wiki; the user reads it.
|
|
260
|
+
|
|
261
|
+
Always communicate with the user in **English**. Always write wiki pages in **English**.
|
|
262
|
+
|
|
263
|
+
### User Communication
|
|
264
|
+
|
|
265
|
+
- Default to a clear, everyday style suitable for most users. You are a helpful knowledge assistant, not a software engineer explaining implementation details.
|
|
266
|
+
- Use **English** for every conversational message. Do not mix languages unless quoting source text, file names, commands, or proper nouns.
|
|
267
|
+
- Translate workflow terms into the user's language. If a source uses an important domain term, write the translated term first and put the original term in parentheses on first use.
|
|
268
|
+
- Speak to non-technical users. Use short, natural sentences. Say what the user gets, what changed, what needs attention, or what decision is needed; keep internal tool details quiet unless the user asks.
|
|
269
|
+
- Prefer plain phrases such as "checking links", "checking against the source", "saving the page", and "I found something to review" over tool-centric words like lint, schema, frontmatter, checkpoint, verify, or JSON in user-facing messages.
|
|
270
|
+
- If technical detail is necessary, give the plain-language meaning first, then the technical term in parentheses.
|
|
271
|
+
- Ask the user only when their judgment is needed: approving a draft, choosing between ambiguous sources, allowing an overwrite/restart, handling source-check findings, accepting lower confidence, or deciding how to fix an issue the tools cannot fix safely.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Repository Layout
|
|
276
|
+
|
|
277
|
+
Keep this mental map in immediate context:
|
|
278
|
+
|
|
279
|
+
### `wiki/` is the main product surface
|
|
280
|
+
|
|
281
|
+
- `wiki/index.md` — catalog of all wiki pages, updated on every ingest
|
|
282
|
+
- `wiki/log.md` — append-only activity log
|
|
283
|
+
- `wiki/concepts/` — reusable knowledge structure
|
|
284
|
+
- `wiki/sources/` — per-source summaries (papers, articles, books, podcasts, notes)
|
|
285
|
+
- `wiki/people/` — people referenced across sources
|
|
286
|
+
- `wiki/summary/` — area-level syntheses
|
|
287
|
+
- `wiki/outputs/` — generated artifacts (comparisons, exports)
|
|
288
|
+
- `wiki/graph/` — derived state; never edit manually
|
|
289
|
+
|
|
290
|
+
### `raw/` is user-owned
|
|
291
|
+
|
|
292
|
+
- `raw/sources/` — `.pdf`, `.tex`, `.html`, `.md`, transcripts, anything ingested
|
|
293
|
+
- `raw/notes/` — user's own markdown notes
|
|
294
|
+
- `raw/assets/` — images and binary attachments
|
|
295
|
+
- `raw/tmp/` — sidecar files generated by skills (transient; do not store canonical sources here)
|
|
296
|
+
- `raw/download/<resource>/` — full-text artifacts auto-fetched by skills, partitioned by source
|
|
297
|
+
(e.g. `raw/download/arxiv/2604.03501v2.pdf`, `raw/download/doi/<doi>.pdf`).
|
|
298
|
+
Permanent agent-writable zone — keep separate from `raw/sources/` (human-curated).
|
|
299
|
+
|
|
300
|
+
**Rule:** never modify or delete an existing file under `raw/`. Files added by the user are authoritative and immutable to the agent. New files may only be *added*, only by a skill that documents this behavior, and only into `raw/tmp/`, `raw/download/`. Every other path under `raw/` is read-only.
|
|
301
|
+
|
|
302
|
+
### `.agents/` is the skill source of truth
|
|
303
|
+
|
|
304
|
+
- `.agents/skills/lumi-*/` — installed skills (flat, one directory per skill)
|
|
305
|
+
|
|
306
|
+
### `_lumina/` is the installer-managed sidecar
|
|
307
|
+
|
|
308
|
+
- `_lumina/config/lumina.config.yaml` — workspace config; editable
|
|
309
|
+
- `_lumina/schema/` — deeper reference docs; open when this file points you there
|
|
310
|
+
- `_lumina/scripts/` — Node engine (`wiki.mjs`, `lint.mjs`, `reset.mjs`, `schemas.mjs`)
|
|
311
|
+
- `_lumina/tools/` — Python tools (always: `extract_pdf.py`, `fetch_pdf.py`, `requirements.txt`)
|
|
312
|
+
- `_lumina/_state/` — installer/skill checkpoint state; gitignored
|
|
313
|
+
- `_lumina/manifest.json` — installer state; never edit by hand
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Page Types
|
|
318
|
+
|
|
319
|
+
Every wiki page has a defined type, frontmatter, and section structure. **Open `_lumina/schema/page-templates.md` before drafting a new page or repairing an existing one** — it has the full templates and required frontmatter fields.
|
|
320
|
+
|
|
321
|
+
| Type | Directory | Purpose |
|
|
322
|
+
|------------|---------------|----------------------------------------------------------------------|
|
|
323
|
+
| Source | `sources/` | Per-document summary: key claims, evidence, takeaways, questions |
|
|
324
|
+
| Concept | `concepts/` | Cross-source idea or technique with variants and comparisons |
|
|
325
|
+
| Person | `people/` | Profile of a referenced person with key sources and relationships |
|
|
326
|
+
| Summary | `summary/` | Area-level synthesis spanning multiple sources and concepts |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Link Syntax
|
|
331
|
+
|
|
332
|
+
All internal links use Obsidian wikilinks:
|
|
333
|
+
|
|
334
|
+
```markdown
|
|
335
|
+
[[slug]] — link to any page in this wiki
|
|
336
|
+
[[chain-of-thought]] — links to concepts/chain-of-thought.md
|
|
337
|
+
[[1984-orwell]] — links to sources/1984-orwell.md
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Slug rule**: lowercase, hyphen-separated, no spaces, no diacritics.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Cross-Reference Rules (Bidirectional Links)
|
|
345
|
+
|
|
346
|
+
When you write a forward link, **always write the reverse link in the same operation**. This is the heart of why the wiki compounds. Skipping it leaves the graph half-built.
|
|
347
|
+
|
|
348
|
+
| Forward action | Required reverse action |
|
|
349
|
+
|---------------------------------------------|---------------------------------------------|
|
|
350
|
+
| `sources/A` writes `Related: [[concept-B]]` | `concepts/B` appends A to `Key sources` |
|
|
351
|
+
| `sources/A` writes `[[person-C]]` | `people/C` appends A to `Key sources` |
|
|
352
|
+
| `concepts/K` writes `[[source-E]]` | `sources/E` appends K to `Related concepts`|
|
|
353
|
+
| `summary/S` writes `[[concept-K]]` | `concepts/K` appends S to `Mentioned in` |
|
|
354
|
+
|
|
355
|
+
### Exemptions (mode: `exempt-only`, default)
|
|
356
|
+
|
|
357
|
+
Some links are intentionally one-way. Defaults:
|
|
358
|
+
|
|
359
|
+
- **`outputs/**`** — ephemeral artifacts
|
|
360
|
+
- **External URLs** (`*://*`) — out of wiki scope
|
|
361
|
+
|
|
362
|
+
Anything outside an exemption glob must be bidirectional.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Log Format
|
|
367
|
+
|
|
368
|
+
Append-only. One line per skill invocation. Format:
|
|
369
|
+
|
|
370
|
+
```markdown
|
|
371
|
+
## [YYYY-MM-DD] skill | details
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
`grep "^## \[" wiki/log.md | tail -10` gives you recent activity.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Graph
|
|
379
|
+
|
|
380
|
+
`wiki/graph/edges.jsonl` and `wiki/graph/citations.jsonl` are auto-generated. Never edit manually. The full set of edge types lives in `_lumina/scripts/schemas.mjs` — open it when you need to pick a type or check what is allowed.
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Constraints (Non-Negotiable)
|
|
385
|
+
|
|
386
|
+
- **`raw/` is user-owned**: never modify or delete existing files; additions only via the two named paths above.
|
|
387
|
+
- **`graph/` is auto-generated**: only modify via the graph rebuild step.
|
|
388
|
+
- **Bidirectional links are mandatory**: forward link and reverse link in the same operation.
|
|
389
|
+
- **`index.md` updated on every ingest**: every new page must be cataloged immediately.
|
|
390
|
+
- **`log.md` is append-only**: never rewrite history.
|
|
391
|
+
- **Skill flags are user-owned**: never invent, flip, or drop a flag based on repo state alone. If the user omitted a parameter, only fill it in when the skill explicitly documents a default; otherwise ask.
|
|
392
|
+
- **No silent overwrites**: preserve sections marked with `<!-- user-edited -->` comment.
|
|
393
|
+
- **Cite when uncertain**: link the source explicitly for low-confidence claims.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Skills
|
|
398
|
+
|
|
399
|
+
Skills live in `.agents/skills/` and are invoked via slash commands. Active install recorded in `_lumina/manifest.json`.
|
|
400
|
+
|
|
401
|
+
### Core skills (always present)
|
|
402
|
+
|
|
403
|
+
| Skill | Trigger | What it does |
|
|
404
|
+
|---------------|---------------|-------------------------------------------------------|
|
|
405
|
+
| `/lumi-init` | manual, first | Bootstrap wiki from existing `raw/` content |
|
|
406
|
+
| `/lumi-ingest` | manual | Read a source and write a wiki page. It asks you to review the draft, then continues on its own unless something needs your judgment |
|
|
407
|
+
| `/lumi-ask` | manual | Query wiki, synthesize answer, optionally file page |
|
|
408
|
+
| `/lumi-edit` | manual | Add/remove/revise wiki content per user request |
|
|
409
|
+
| `/lumi-check` | manual/weekly | Lint: broken links, orphans, missing reverse links |
|
|
410
|
+
| `/lumi-reset` | manual | Scoped destructive cleanup |
|
|
411
|
+
| `/lumi-verify` | manual | Check that wiki pages match the sources they cite; reports suspicious statements for the user to review; never auto-edits |
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Tooling Conventions
|
|
417
|
+
|
|
418
|
+
- **`_lumina/scripts/lint.mjs`** — pure-Node markdown linter, runs offline.
|
|
419
|
+
- **`_lumina/scripts/wiki.mjs`** — wiki engine (frontmatter, graph mutation, slug, log).
|
|
420
|
+
- **`_lumina/scripts/reset.mjs`** — scoped destructive reset.
|
|
421
|
+
- **`_lumina/tools/extract_pdf.py`** — PDF text extractor (pypdf-based); used by `/lumi-ingest` and `/lumi-reading-chapter-ingest` when the host IDE cannot read PDFs natively.
|
|
422
|
+
- **`_lumina/tools/fetch_pdf.py`** — URL → `raw/download/<resource>/` PDF downloader (streaming, atomic, idempotent); used by `/lumi-ingest` Mode B when the input is a URL or paper identifier.
|
|
423
|
+
- **`_lumina/tools/requirements.txt`** — Python dependencies for bundled tools. Run `pip install -r _lumina/tools/requirements.txt` when a tool reports a missing package.
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## How To Use This Wiki (For New LLM Sessions)
|
|
428
|
+
|
|
429
|
+
1. Read this file (you are doing it now).
|
|
430
|
+
2. Read `wiki/index.md` to learn what already exists.
|
|
431
|
+
3. Read `wiki/log.md`'s last 20 entries to learn what happened recently.
|
|
432
|
+
4. When the user invokes a skill, read the skill's `SKILL.md` first.
|
|
433
|
+
5. When in doubt about page structure, open `_lumina/schema/page-templates.md`.
|
|
434
|
+
6. When in doubt about scope, ask the user — never silently expand it.
|
|
435
|
+
|
|
436
|
+
The wiki is a long-running collaboration. Maintain it patiently.
|
|
437
|
+
|
|
438
|
+
<!-- /lumina:schema -->
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Contributors
|
|
443
|
+
|
|
444
|
+
Thanks to everyone who has contributed to Lumina Wiki!
|
|
445
|
+
|
|
446
|
+
[](https://github.com/tronghieu/lumina-wiki/graphs/contributors)
|
|
447
|
+
|
|
448
|
+
**Want to contribute?** Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started — bug reports, new skills, tool integrations, and translations are all welcome.
|
package/README.vi.md
CHANGED
|
@@ -184,6 +184,7 @@ Xem [Hướng dẫn Nâng cao](docs/user-guide/advanced-qmd.vi.md) để biết
|
|
|
184
184
|
| | `/lumi-research-prefill` | Tạo trước các khái niệm nền tảng để tránh trùng lặp. |
|
|
185
185
|
| | `/lumi-research-topic` | Gom các khái niệm và nguồn liên quan trong wiki thành một trang chủ đề tại `wiki/topics/<slug>.md`. AI đề xuất danh sách để bạn xem và xác nhận trước khi trang được tạo. Dùng sau khi đã nạp nhiều tài liệu và muốn tổng hợp một nhóm ý tưởng thành trang riêng. |
|
|
186
186
|
| | `/lumi-research-setup` | Giúp cấu hình API key cho các công cụ nghiên cứu. |
|
|
187
|
+
| | `/lumi-research-watch-run` | Chạy một lượt khám phá theo lịch dựa trên watchlist (chủ đề + nguồn RSS / Atom). Chỉ chạy khi bạn yêu cầu. |
|
|
187
188
|
| **Reading** | `/lumi-reading-chapter-ingest`| Nạp kiến thức sách theo từng chương. |
|
|
188
189
|
| | `/lumi-reading-character-track`| Theo dõi các nhân vật và mối quan hệ của họ trong truyện. |
|
|
189
190
|
| | `/lumi-reading-theme-map` | Xác định và lập bản đồ các chủ đề trong một câu chuyện. |
|
|
@@ -204,8 +205,8 @@ Lumina-Wiki đang phát triển nhanh chóng. Dưới đây là lộ trình hư
|
|
|
204
205
|
- [x] **Cài đặt đa ngôn ngữ:** Chọn Tiếng Anh, Tiếng Việt hoặc Tiếng Trung làm ngôn ngữ chính khi cài đặt. *(đã phát hành trong v1.2)*
|
|
205
206
|
- [x] **Nạp DOCX, RTF & EPUB native:** Đưa thẳng file Word, Rich Text và sách EPUB vào wiki qua research pack. *(đã phát hành trong v1.x)*
|
|
206
207
|
- [x] **Cải thiện CI/CD:** Hỗ trợ chính thức cho môi trường Bun và Node 22. *(đã phát hành trong v1.2)*
|
|
207
|
-
- [
|
|
208
|
-
- [
|
|
208
|
+
- [x] **Mở rộng nguồn dữ liệu toàn cầu:** Tích hợp trực tiếp với OpenAlex, CORE và Unpaywall để tra cứu DOI-to-PDF đáng tin cậy. *(ra mắt trong v1.6)*
|
|
209
|
+
- [x] **Theo dõi RSS & Blog:** Tự động phát hiện bài báo mới từ các blog phòng thí nghiệm và tạp chí yêu thích qua các mục `type: feed` trong watchlist. *(ra mắt trong v1.6)*
|
|
209
210
|
- [ ] **Xếp hạng bài báo nâng cao:** Xem điểm số ảnh hưởng và tín hiệu chất lượng cho các nghiên cứu của bạn.
|
|
210
211
|
|
|
211
212
|
**Dài hạn (Nghiên cứu sâu & Tích hợp)**
|
|
@@ -249,3 +250,13 @@ npm run test:all
|
|
|
249
250
|
- [简体中文 (Tiếng Trung)](README.zh.md)
|
|
250
251
|
|
|
251
252
|
**Giấy phép:** [MIT](LICENSE) © Lưu Trọng Hiếu.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Người đóng góp
|
|
257
|
+
|
|
258
|
+
Cảm ơn tất cả những người đã đóng góp cho Lumina Wiki!
|
|
259
|
+
|
|
260
|
+
[](https://github.com/tronghieu/lumina-wiki/graphs/contributors)
|
|
261
|
+
|
|
262
|
+
**Muốn đóng góp?** Đọc [CONTRIBUTING.md](CONTRIBUTING.md) để bắt đầu — báo lỗi, thêm skill mới, tích hợp công cụ, hay dịch thuật đều được chào đón.
|
package/README.zh.md
CHANGED
|
@@ -185,6 +185,7 @@ npx skills add https://github.com/tobi/qmd --skill qmd
|
|
|
185
185
|
| | `/lumi-research-prefill` | 预先生成基础概念,避免重复。 |
|
|
186
186
|
| | `/lumi-research-topic` | 把 wiki 中已有的相关概念和来源汇聚成一个主题页,保存在 `wiki/topics/<slug>.md`。AI 会提议收录哪些内容,由你确认后再生成页面。多次 `/lumi-ingest` 之后,用它把一组相关想法整理成独立的主题页。 |
|
|
187
187
|
| | `/lumi-research-setup` | 帮助配置研究工具的 API key。 |
|
|
188
|
+
| | `/lumi-research-watch-run` | 基于 watchlist 运行一次计划式发现(主题 + RSS / Atom 源)。仅在你要求时才运行。 |
|
|
188
189
|
| **Reading** | `/lumi-reading-chapter-ingest`| 按章节导入书籍知识。 |
|
|
189
190
|
| | `/lumi-reading-character-track`| 追踪故事中的角色及其关系。 |
|
|
190
191
|
| | `/lumi-reading-theme-map` | 识别并映射故事主题。 |
|
|
@@ -205,8 +206,8 @@ Lumina-Wiki 正在快速演进。这是我们的用户路线图:
|
|
|
205
206
|
- [x] **多语言安装:** 安装时可选英文、越南文或中文作为主语言。*(v1.2 已发布)*
|
|
206
207
|
- [x] **原生 DOCX、RTF 与 EPUB 导入:** 通过 research pack 将 Word、Rich Text 与 EPUB 电子书直接导入维基。*(v1.x 已发布)*
|
|
207
208
|
- [x] **改进的 CI/CD:** 正式支持 Bun 和 Node 22 环境。*(v1.2 已发布)*
|
|
208
|
-
- [
|
|
209
|
-
- [
|
|
209
|
+
- [x] **全球数据源扩展:** 直接集成 OpenAlex、CORE 和 Unpaywall,实现可靠的 DOI-to-PDF 解析。*(在 v1.6 中发布)*
|
|
210
|
+
- [x] **RSS 与博客监控:** 通过 watchlist 中的 `type: feed` 项,自动从您喜爱的实验室博客和期刊中发现新论文。*(在 v1.6 中发布)*
|
|
210
211
|
- [ ] **高级论文排名:** 查看研究论文的影响力评分和质量信号。
|
|
211
212
|
|
|
212
213
|
**长期计划(深度研究与集成)**
|
|
@@ -251,3 +252,13 @@ npm run test:all
|
|
|
251
252
|
- [Tiếng Việt(越南语)](README.vi.md)
|
|
252
253
|
|
|
253
254
|
**许可:** [MIT](LICENSE) © Lưu Trọng Hiếu.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 贡献者
|
|
259
|
+
|
|
260
|
+
感谢所有为 Lumina Wiki 做出贡献的人!
|
|
261
|
+
|
|
262
|
+
[](https://github.com/tronghieu/lumina-wiki/graphs/contributors)
|
|
263
|
+
|
|
264
|
+
**想要贡献?** 请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 开始参与——欢迎提交 Bug 报告、新 skill、工具集成以及翻译。
|
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": "1.
|
|
4
|
+
"version": "1.6.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",
|
|
@@ -952,26 +952,25 @@ function buildIdeStub(target, vars) {
|
|
|
952
952
|
async function copyScripts(projectRoot) {
|
|
953
953
|
const destDir = join(projectRoot, '_lumina', 'scripts');
|
|
954
954
|
const scriptFiles = ['wiki.mjs', 'lint.mjs', 'reset.mjs', 'schemas.mjs', 'discover-runner.mjs', 'external-ids.mjs', 'parse-ids.mjs', 'merge-ids.mjs', 'build-source.mjs'];
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const dest = join(destDir, file);
|
|
955
|
+
// Parallel: each copy is independent; destDir is created earlier.
|
|
956
|
+
await Promise.all(scriptFiles.map(async file => {
|
|
958
957
|
try {
|
|
959
|
-
await copyFile(
|
|
958
|
+
await copyFile(join(SCRIPTS_DIR, file), join(destDir, file));
|
|
960
959
|
} catch (_) {
|
|
961
960
|
// Scripts may not exist yet (P4+ work); skip gracefully
|
|
962
961
|
}
|
|
963
|
-
}
|
|
962
|
+
}));
|
|
963
|
+
// Ensure the lib subdir once, then parallelize the file copies.
|
|
964
|
+
const libDir = join(destDir, 'lib');
|
|
965
|
+
await ensureDir(libDir);
|
|
964
966
|
const libFiles = ['watchlist-config.mjs', 'discovery-state.mjs'];
|
|
965
|
-
|
|
966
|
-
const src = join(SCRIPTS_DIR, 'lib', file);
|
|
967
|
-
const dest = join(destDir, 'lib', file);
|
|
967
|
+
await Promise.all(libFiles.map(async file => {
|
|
968
968
|
try {
|
|
969
|
-
await
|
|
970
|
-
await copyFile(src, dest);
|
|
969
|
+
await copyFile(join(SCRIPTS_DIR, 'lib', file), join(libDir, file));
|
|
971
970
|
} catch (_) {
|
|
972
971
|
// Script libs may not exist yet; skip gracefully
|
|
973
972
|
}
|
|
974
|
-
}
|
|
973
|
+
}));
|
|
975
974
|
}
|
|
976
975
|
|
|
977
976
|
async function copyChangelog(projectRoot) {
|
|
@@ -1052,6 +1051,7 @@ function getSkillDefs(packs) {
|
|
|
1052
1051
|
{ name: 'setup', canonicalId: 'lumi-research-setup', displayName: '/lumi-research-setup' },
|
|
1053
1052
|
{ name: 'topic', canonicalId: 'lumi-research-topic', displayName: '/lumi-research-topic' },
|
|
1054
1053
|
{ name: 'watchlist', canonicalId: 'lumi-research-watchlist', displayName: '/lumi-research-watchlist' },
|
|
1054
|
+
{ name: 'watch-run', canonicalId: 'lumi-research-watch-run', displayName: '/lumi-research-watch-run' },
|
|
1055
1055
|
];
|
|
1056
1056
|
for (const s of researchSkills) {
|
|
1057
1057
|
defs.push({ ...s, pack: 'research', srcPackPath: 'packs/research' });
|
|
@@ -1086,19 +1086,22 @@ async function copyTools(projectRoot, { research }) {
|
|
|
1086
1086
|
const destDir = join(projectRoot, '_lumina', 'tools');
|
|
1087
1087
|
const coreTools = ['extract_pdf.py', 'fetch_pdf.py', 'id_utils.py'];
|
|
1088
1088
|
const researchTools = [
|
|
1089
|
-
'_env.py', 'discover.py', 'init_discovery.py', 'prepare_source.py',
|
|
1089
|
+
'_env.py', '_cache.py', 'discover.py', 'init_discovery.py', 'prepare_source.py',
|
|
1090
1090
|
'fetch_arxiv.py', 'fetch_wikipedia.py', 'fetch_s2.py', 'fetch_deepxiv.py',
|
|
1091
|
+
'fetch_openalex.py', 'fetch_unpaywall.py', 'fetch_core.py', 'resolve_pdf.py',
|
|
1092
|
+
'fetch_rss.py',
|
|
1091
1093
|
];
|
|
1092
1094
|
const toolFiles = research ? [...coreTools, ...researchTools] : coreTools;
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1095
|
+
// Parallelize: each copy is independent and destDir already exists.
|
|
1096
|
+
// Sequential awaits were the main Windows cold-start regression in v1.4
|
|
1097
|
+
// (~30 ms per file × 14 files dominates on NTFS + Defender).
|
|
1098
|
+
await Promise.all(toolFiles.map(async file => {
|
|
1096
1099
|
try {
|
|
1097
|
-
await copyFile(
|
|
1100
|
+
await copyFile(join(TOOLS_DIR, file), join(destDir, file));
|
|
1098
1101
|
} catch (_) {
|
|
1099
1102
|
// Tool not yet authored; skip
|
|
1100
1103
|
}
|
|
1101
|
-
}
|
|
1104
|
+
}));
|
|
1102
1105
|
try {
|
|
1103
1106
|
await copyFile(join(TOOLS_DIR, 'requirements.txt'), join(destDir, 'requirements.txt'));
|
|
1104
1107
|
} catch (_) {
|
|
@@ -1110,7 +1113,9 @@ async function renderSchemaDocs(projectRoot, templateVars) {
|
|
|
1110
1113
|
const schemaDir = join(projectRoot, '_lumina', 'schema');
|
|
1111
1114
|
const schemaDocs = ['page-templates.md', 'cross-reference-packs.md', 'graph-packs.md', 'lumi-help.csv', 'lumi-help-runbook.md'];
|
|
1112
1115
|
|
|
1113
|
-
|
|
1116
|
+
// Parallel render + atomicWrite. Each doc is independent; schemaDir is
|
|
1117
|
+
// already created by the dirsToCreate loop in installCommand.
|
|
1118
|
+
await Promise.all(schemaDocs.map(async doc => {
|
|
1114
1119
|
const templatePath = join(TEMPLATES_DIR, '_lumina', 'schema', doc);
|
|
1115
1120
|
const destPath = join(schemaDir, doc);
|
|
1116
1121
|
let content;
|
|
@@ -1121,7 +1126,7 @@ async function renderSchemaDocs(projectRoot, templateVars) {
|
|
|
1121
1126
|
content = `# ${doc}\n\n_This file is managed by the Lumina installer._\n`;
|
|
1122
1127
|
}
|
|
1123
1128
|
await atomicWrite(destPath, content);
|
|
1124
|
-
}
|
|
1129
|
+
}));
|
|
1125
1130
|
}
|
|
1126
1131
|
|
|
1127
1132
|
async function renderEnvExample(projectRoot) {
|
package/src/installer/prompts.js
CHANGED
|
@@ -151,7 +151,7 @@ export function buildPromptList(existingManifest, defaultLocale = 'en') {
|
|
|
151
151
|
* @param {Function} [opts.t] - Locale translator function.
|
|
152
152
|
* @returns {Promise<InstallAnswers>}
|
|
153
153
|
*/
|
|
154
|
-
export async function runInstallPrompts({ acceptDefaults = false, cwd = process.cwd(), existingManifest = null, defaultLocale = 'en', t = null } = {}) {
|
|
154
|
+
export async function runInstallPrompts({ acceptDefaults = false, cwd = process.cwd(), existingManifest = null, defaultLocale = 'en', t: initialT = null } = {}) {
|
|
155
155
|
if (acceptDefaults) {
|
|
156
156
|
const loc = existingManifest?.locale ?? defaultLocale;
|
|
157
157
|
return defaultAnswers(cwd, loc);
|
|
@@ -159,6 +159,11 @@ export async function runInstallPrompts({ acceptDefaults = false, cwd = process.
|
|
|
159
159
|
|
|
160
160
|
const { intro, outro, text, multiselect, select, confirm, isCancel, cancel } = await getClack();
|
|
161
161
|
|
|
162
|
+
// t starts as whatever the caller passed (may be null on fresh install where
|
|
163
|
+
// locale is unknown). After Prompt 0 selects the locale, we rebind t to the
|
|
164
|
+
// user-chosen locale so prompts 1-5 are localized.
|
|
165
|
+
let t = initialT;
|
|
166
|
+
|
|
162
167
|
// t may not be available yet at intro time (locale not yet selected);
|
|
163
168
|
// use hardcoded EN for intro — this is the chicken-and-egg prompt.
|
|
164
169
|
intro('Lumina Wiki Installer');
|
|
@@ -179,14 +184,26 @@ export async function runInstallPrompts({ acceptDefaults = false, cwd = process.
|
|
|
179
184
|
const locale = localeRaw;
|
|
180
185
|
const langDefault = LOCALE_LANGUAGE_NAME[locale] ?? 'English';
|
|
181
186
|
|
|
187
|
+
// Rebind t to the just-selected locale so the remaining prompts render in
|
|
188
|
+
// the user's chosen language. Without this, prompts 1-5 silently fall back
|
|
189
|
+
// to EN literals even when the user picked vi/zh at Prompt 0.
|
|
190
|
+
try {
|
|
191
|
+
const { loadLocale } = await import('./locales.js');
|
|
192
|
+
const localeMod = await loadLocale(locale);
|
|
193
|
+
t = localeMod.t;
|
|
194
|
+
} catch {
|
|
195
|
+
// Keep whatever t we had (possibly null → EN literals); never block install.
|
|
196
|
+
}
|
|
197
|
+
|
|
182
198
|
// Interactive locale-switch confirmation (Phase 5 §60-63):
|
|
183
199
|
// If user picks a locale different from the installed one on an upgrade,
|
|
184
200
|
// require explicit confirmation before destructively rewriting README.md
|
|
185
201
|
// and IDE stubs. Default N — protects user content.
|
|
186
202
|
if (existingManifest?.locale && existingManifest.locale !== locale) {
|
|
187
203
|
const proceed = await confirm({
|
|
188
|
-
// Use trilingual literal —
|
|
189
|
-
//
|
|
204
|
+
// Use trilingual literal — user is mid-switch, so both old and new
|
|
205
|
+
// locales are relevant context. t() is available here but intentionally
|
|
206
|
+
// not used so the warning is legible in either locale.
|
|
190
207
|
message: `Locale change ${existingManifest.locale} -> ${locale} will rewrite README.md and IDE stubs in the new locale. Outside-schema edits are preserved. Continue?`,
|
|
191
208
|
initialValue: false,
|
|
192
209
|
});
|