obsidian-zk 0.1.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.
Files changed (94) hide show
  1. package/README.md +226 -0
  2. package/dist/cli/index.d.ts +3 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +49 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/db/index.d.ts +49 -0
  7. package/dist/db/index.d.ts.map +1 -0
  8. package/dist/db/index.js +196 -0
  9. package/dist/db/index.js.map +1 -0
  10. package/dist/db/schema.d.ts +6 -0
  11. package/dist/db/schema.d.ts.map +1 -0
  12. package/dist/db/schema.js +37 -0
  13. package/dist/db/schema.js.map +1 -0
  14. package/dist/init/scaffold.d.ts +3 -0
  15. package/dist/init/scaffold.d.ts.map +1 -0
  16. package/dist/init/scaffold.js +122 -0
  17. package/dist/init/scaffold.js.map +1 -0
  18. package/dist/init/updater.d.ts +2 -0
  19. package/dist/init/updater.d.ts.map +1 -0
  20. package/dist/init/updater.js +75 -0
  21. package/dist/init/updater.js.map +1 -0
  22. package/dist/init/wizard.d.ts +7 -0
  23. package/dist/init/wizard.d.ts.map +1 -0
  24. package/dist/init/wizard.js +28 -0
  25. package/dist/init/wizard.js.map +1 -0
  26. package/dist/luhmann.d.ts +7 -0
  27. package/dist/luhmann.d.ts.map +1 -0
  28. package/dist/luhmann.js +63 -0
  29. package/dist/luhmann.js.map +1 -0
  30. package/dist/server/index.d.ts +2 -0
  31. package/dist/server/index.d.ts.map +1 -0
  32. package/dist/server/index.js +13 -0
  33. package/dist/server/index.js.map +1 -0
  34. package/dist/server/server.d.ts +6 -0
  35. package/dist/server/server.d.ts.map +1 -0
  36. package/dist/server/server.js +381 -0
  37. package/dist/server/server.js.map +1 -0
  38. package/dist/tools/analysis.d.ts +38 -0
  39. package/dist/tools/analysis.d.ts.map +1 -0
  40. package/dist/tools/analysis.js +44 -0
  41. package/dist/tools/analysis.js.map +1 -0
  42. package/dist/tools/capture.d.ts +16 -0
  43. package/dist/tools/capture.d.ts.map +1 -0
  44. package/dist/tools/capture.js +43 -0
  45. package/dist/tools/capture.js.map +1 -0
  46. package/dist/tools/index-mgmt.d.ts +15 -0
  47. package/dist/tools/index-mgmt.d.ts.map +1 -0
  48. package/dist/tools/index-mgmt.js +12 -0
  49. package/dist/tools/index-mgmt.js.map +1 -0
  50. package/dist/tools/literature.d.ts +30 -0
  51. package/dist/tools/literature.d.ts.map +1 -0
  52. package/dist/tools/literature.js +63 -0
  53. package/dist/tools/literature.js.map +1 -0
  54. package/dist/tools/manage.d.ts +60 -0
  55. package/dist/tools/manage.d.ts.map +1 -0
  56. package/dist/tools/manage.js +65 -0
  57. package/dist/tools/manage.js.map +1 -0
  58. package/dist/tools/permanent.d.ts +24 -0
  59. package/dist/tools/permanent.d.ts.map +1 -0
  60. package/dist/tools/permanent.js +74 -0
  61. package/dist/tools/permanent.js.map +1 -0
  62. package/dist/tools/search.d.ts +24 -0
  63. package/dist/tools/search.d.ts.map +1 -0
  64. package/dist/tools/search.js +50 -0
  65. package/dist/tools/search.js.map +1 -0
  66. package/dist/vault/parser.d.ts +14 -0
  67. package/dist/vault/parser.d.ts.map +1 -0
  68. package/dist/vault/parser.js +92 -0
  69. package/dist/vault/parser.js.map +1 -0
  70. package/dist/vault/scanner.d.ts +6 -0
  71. package/dist/vault/scanner.d.ts.map +1 -0
  72. package/dist/vault/scanner.js +44 -0
  73. package/dist/vault/scanner.js.map +1 -0
  74. package/dist/vault/writer.d.ts +6 -0
  75. package/dist/vault/writer.d.ts.map +1 -0
  76. package/dist/vault/writer.js +71 -0
  77. package/dist/vault/writer.js.map +1 -0
  78. package/package.json +33 -0
  79. package/templates/CLAUDE.md.template +59 -0
  80. package/templates/claude/agents/zk-analyzer.md +40 -0
  81. package/templates/claude/skills/zk-capture/SKILL.md +25 -0
  82. package/templates/claude/skills/zk-connect/SKILL.md +23 -0
  83. package/templates/claude/skills/zk-daily/SKILL.md +17 -0
  84. package/templates/claude/skills/zk-literature/SKILL.md +33 -0
  85. package/templates/claude/skills/zk-manage/SKILL.md +29 -0
  86. package/templates/claude/skills/zk-permanent/SKILL.md +30 -0
  87. package/templates/claude/skills/zk-promote/SKILL.md +30 -0
  88. package/templates/claude/skills/zk-reflect/SKILL.md +17 -0
  89. package/templates/claude/skills/zk-review/SKILL.md +22 -0
  90. package/templates/vault-folders/Templates/Fleeting Note.md +31 -0
  91. package/templates/vault-folders/Templates/Literature Note.md +61 -0
  92. package/templates/vault-folders/Templates/MOC.md +48 -0
  93. package/templates/vault-folders/Templates/Permanent Note.md +49 -0
  94. package/templates/vault-folders/Templates/Project Note.md +50 -0
package/README.md ADDED
@@ -0,0 +1,226 @@
1
+ # obsidian-zk — Obsidian Zettelkasten MCP Server
2
+
3
+ MCP server for AI-assisted Zettelkasten in Obsidian. Luhmann numbering, typed connections, SQLite metadata cache.
4
+
5
+ Works with [Claude Code](https://claude.ai/code) — exposes tools and prompts via [Model Context Protocol](https://modelcontextprotocol.io/).
6
+
7
+ ## What it does
8
+
9
+ - **CRUD** for fleeting, literature, and permanent notes with proper frontmatter
10
+ - **Luhmann numbering** — auto-generates `zk_id` with alternating numbers/letters (`1 → 1a → 1a1 → 1a1a`)
11
+ - **Connection search** — finds related notes by shared tags, keywords, link proximity
12
+ - **Vault analysis** — unprocessed notes, orphans, emerging theme clusters
13
+ - **MCP prompts** — guided workflows as slash commands (`/zk:capture`, `/zk:promote`, etc.)
14
+ - **SQLite index** — fast metadata queries without scanning files every time
15
+
16
+ No embeddings — Claude judges semantic relevance directly in context.
17
+
18
+ ## Quick start
19
+
20
+ ### 1. Install
21
+
22
+ ```bash
23
+ npx obsidian-zk init
24
+ ```
25
+
26
+ Interactive wizard:
27
+ - Detects or asks for vault path
28
+ - Creates folder structure (`1-Fleeting/`, `2-Literature/`, `3-Permanent/`, etc.)
29
+ - Copies note templates, skills, and agents into `.claude/`
30
+ - Creates `CLAUDE.md` with project instructions
31
+ - Sets up SQLite database in `.zk/`
32
+ - Configures MCP server in `.mcp.json`
33
+
34
+ ### 2. Use
35
+
36
+ Open vault directory in Claude Code:
37
+
38
+ ```bash
39
+ cd your-vault
40
+ claude
41
+ ```
42
+
43
+ The MCP server starts automatically. Use prompts:
44
+
45
+ | Command | What it does |
46
+ |---------|-------------|
47
+ | `/zk:capture` | Quick fleeting note from a thought |
48
+ | `/zk:literature` | Literature note from pasted source |
49
+ | `/zk:permanent` | Atomic permanent note with auto Luhmann ID |
50
+ | `/zk:promote` | Convert fleeting → permanent |
51
+ | `/zk:manage` | Edit/archive/delete by Luhmann number |
52
+ | `/zk:review` | Vault health report |
53
+ | `/zk:daily` | Morning briefing |
54
+ | `/zk:connect` | Find and create connections for a note |
55
+ | `/zk:reflect` | Deep reflection on vault themes |
56
+
57
+ ### 3. Update
58
+
59
+ After upgrading the package:
60
+
61
+ ```bash
62
+ npx obsidian-zk update
63
+ ```
64
+
65
+ Syncs skills/agents, runs DB migrations.
66
+
67
+ ## How it works
68
+
69
+ ```
70
+ Claude Code ←→ MCP Server (obsidian-zk serve) ←→ SQLite DB + Vault files
71
+
72
+ ├── Tools (zk_capture, zk_permanent, zk_find_connections, ...)
73
+ └── Prompts (/zk:capture, /zk:promote, /zk:review, ...)
74
+ ```
75
+
76
+ ### Architecture
77
+
78
+ | Component | Choice |
79
+ |-----------|--------|
80
+ | MCP SDK | `@modelcontextprotocol/sdk` (stdio transport) |
81
+ | Database | `better-sqlite3` — single `.zk/zettelkasten.db` file |
82
+ | Semantic search | Claude itself — no embeddings infra needed |
83
+ | Vault I/O | Node.js `fs` — direct file read/write |
84
+
85
+ ### MCP Tools
86
+
87
+ **CRUD:**
88
+ - `zk_capture` — create fleeting note
89
+ - `zk_literature` — create literature note
90
+ - `zk_permanent` — create permanent note with Luhmann ID
91
+ - `zk_manage` — edit/archive/delete by ID
92
+ - `zk_promote` — mark fleeting as processed
93
+
94
+ **Search & connections:**
95
+ - `zk_find_connections` — candidates by tags + links + keywords
96
+ - `zk_cluster_detect` — emerging themes without MOCs
97
+
98
+ **Analysis:**
99
+ - `zk_list` — filter notes by type/status/folder
100
+ - `zk_unprocessed` — notes needing processing
101
+ - `zk_orphans` — notes with no incoming links
102
+ - `zk_next_id` — next Luhmann ID
103
+ - `zk_find_by_id` — resolve ID → path
104
+ - `zk_list_ids` — all numbered notes
105
+ - `zk_review` — full vault health report
106
+
107
+ **Index:**
108
+ - `zk_reindex` — full vault re-scan
109
+ - `zk_status` — DB stats
110
+
111
+ ### Database schema
112
+
113
+ ```sql
114
+ CREATE TABLE notes (
115
+ path TEXT PRIMARY KEY,
116
+ title TEXT, zk_id TEXT, type TEXT, status TEXT,
117
+ folder TEXT, tags TEXT, summary TEXT,
118
+ created TEXT, modified TEXT, content_hash TEXT
119
+ );
120
+
121
+ CREATE TABLE links (
122
+ source TEXT, target TEXT, link_type TEXT,
123
+ PRIMARY KEY (source, target)
124
+ );
125
+ ```
126
+
127
+ Incremental indexing — compares `content_hash`, only updates changed files.
128
+
129
+ ## Zettelkasten method
130
+
131
+ ### Note types
132
+
133
+ | Folder | Type | Atomic? | Lifecycle |
134
+ |--------|------|---------|-----------|
135
+ | `1-Fleeting/` | Raw thoughts | No | unprocessed → processed |
136
+ | `2-Literature/` | Source summaries | Partial | unprocessed → processed |
137
+ | `3-Permanent/` | One idea per note | **Yes** | draft → finalized |
138
+ | `4-MOC/` | Topic indexes | No | — |
139
+ | `5-Projects/` | Active goals | No | active → completed |
140
+
141
+ ### Luhmann numbering
142
+
143
+ ```
144
+ 1, 2, 3 — independent threads
145
+ 1a, 1b — branches from 1
146
+ 1a1, 1a2 — sub-branches from 1a
147
+ ```
148
+
149
+ ### Connection types
150
+
151
+ - **Підтримує** (Supports) — reinforces another idea
152
+ - **Суперечить** (Contradicts) — challenges another idea
153
+ - **Розширює** (Extends) — builds upon another idea
154
+ - **Пов'язано** (Related) — topically connected
155
+
156
+ ### Workflow
157
+
158
+ ```
159
+ Thought → /zk:capture → Fleeting note
160
+ Source → /zk:literature → Literature note
161
+
162
+ /zk:promote (or /zk:permanent)
163
+
164
+ Permanent note (auto zk_id) ←→ connections
165
+
166
+ MOC (when 3+ related notes cluster)
167
+ ```
168
+
169
+ ## Development
170
+
171
+ ```bash
172
+ git clone https://github.com/user/obsidian-zk.git
173
+ cd obsidian-zk
174
+ npm install
175
+ npm run build # compile TypeScript
176
+ npm run dev # watch mode
177
+ ```
178
+
179
+ Test locally:
180
+
181
+ ```bash
182
+ # Start server against a test vault
183
+ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \
184
+ | node dist/cli/index.js serve --vault /path/to/vault
185
+
186
+ # Or configure in Claude Code
187
+ claude mcp add obsidian-zk -- node /path/to/obsidian-zk/dist/cli/index.js serve --vault .
188
+ ```
189
+
190
+ ### Project structure
191
+
192
+ ```
193
+ src/
194
+ ├── cli/index.ts # CLI: init, update, serve
195
+ ├── init/
196
+ │ ├── wizard.ts # Interactive setup
197
+ │ ├── scaffold.ts # Copy templates, create folders
198
+ │ └── updater.ts # Sync templates, run migrations
199
+ ├── server/
200
+ │ ├── index.ts # Stdio transport entry
201
+ │ └── server.ts # Tool + prompt registration
202
+ ├── vault/
203
+ │ ├── parser.ts # Frontmatter, wikilinks, body
204
+ │ ├── scanner.ts # File discovery
205
+ │ └── writer.ts # Note creation/editing
206
+ ├── db/
207
+ │ ├── schema.ts # SQLite schema
208
+ │ └── index.ts # DB connection + indexing
209
+ ├── tools/ # MCP tool implementations
210
+ └── luhmann.ts # ID generation + sorting
211
+ templates/ # Copied to user vault on init
212
+ ├── claude/skills/ # 9 SKILL.md files
213
+ ├── claude/agents/ # zk-analyzer agent
214
+ ├── vault-folders/ # Default folder structure + note templates
215
+ └── CLAUDE.md.template # Project instructions
216
+ ```
217
+
218
+ ## Requirements
219
+
220
+ - Node.js ≥ 18
221
+ - [Claude Code](https://claude.ai/code)
222
+ - [Obsidian](https://obsidian.md/) (for viewing/editing notes)
223
+
224
+ ## License
225
+
226
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entry: init, update, serve subcommands.
4
+ */
5
+ import { resolve } from "node:path";
6
+ const args = process.argv.slice(2);
7
+ const command = args[0];
8
+ async function main() {
9
+ switch (command) {
10
+ case "init": {
11
+ const { runWizard } = await import("../init/wizard.js");
12
+ const { scaffold } = await import("../init/scaffold.js");
13
+ const answers = await runWizard(process.cwd());
14
+ scaffold(answers);
15
+ break;
16
+ }
17
+ case "update": {
18
+ const { update } = await import("../init/updater.js");
19
+ const vaultFlag = args.indexOf("--vault");
20
+ const vaultPath = vaultFlag >= 0 ? args[vaultFlag + 1] : ".";
21
+ update(vaultPath);
22
+ break;
23
+ }
24
+ case "serve": {
25
+ const { startServer } = await import("../server/index.js");
26
+ const vaultFlag = args.indexOf("--vault");
27
+ const vaultPath = vaultFlag >= 0 ? args[vaultFlag + 1] : ".";
28
+ await startServer(resolve(vaultPath));
29
+ break;
30
+ }
31
+ default:
32
+ console.log(`obsidian-zk — Obsidian Zettelkasten MCP Server
33
+
34
+ Usage:
35
+ obsidian-zk init Interactive setup wizard
36
+ obsidian-zk update Sync templates & run migrations
37
+ obsidian-zk serve --vault . Start MCP server (called by Claude Code)
38
+
39
+ Options:
40
+ --vault PATH Vault path (default: current directory)
41
+ `);
42
+ process.exit(command ? 1 : 0);
43
+ }
44
+ }
45
+ main().catch((err) => {
46
+ console.error(err);
47
+ process.exit(1);
48
+ });
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,KAAK,UAAU,IAAI;IACjB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;YACxD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAC/C,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClB,MAAM;QACR,CAAC;QAED,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,MAAM,SAAS,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7D,MAAM,CAAC,SAAS,CAAC,CAAC;YAClB,MAAM;QACR,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,MAAM,SAAS,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7D,MAAM,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YACtC,MAAM;QACR,CAAC;QAED;YACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;CASjB,CAAC,CAAC;YACG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Database connection + indexing.
3
+ */
4
+ import Database from "better-sqlite3";
5
+ export declare class ZkDatabase {
6
+ db: Database.Database;
7
+ vaultRoot: string;
8
+ constructor(vaultRoot: string);
9
+ reindex(): {
10
+ added: number;
11
+ updated: number;
12
+ removed: number;
13
+ };
14
+ getNoteByPath(relPath: string): any;
15
+ getNoteById(zkId: string): any;
16
+ getNotesByType(type: string): any[];
17
+ getNotesByStatus(status: string): any[];
18
+ getNotesByFolder(folder: string): any[];
19
+ listNotes(filters: {
20
+ type?: string;
21
+ status?: string;
22
+ folder?: string;
23
+ }): any[];
24
+ getAllZkIds(): Map<string, {
25
+ path: string;
26
+ title: string;
27
+ }>;
28
+ getUnprocessed(type?: string): any[];
29
+ getOrphans(folder?: string): any[];
30
+ getLinksFrom(relPath: string): any[];
31
+ getLinksTo(title: string): any[];
32
+ findConnections(notePath: string): {
33
+ path: string;
34
+ title: string;
35
+ score: number;
36
+ reasons: string[];
37
+ summary: string;
38
+ type: string;
39
+ }[];
40
+ getStats(): {
41
+ total: any;
42
+ byType: any[];
43
+ byStatus: any[];
44
+ linkCount: any;
45
+ lastIndex: any;
46
+ };
47
+ close(): void;
48
+ }
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAQtC,qBAAa,UAAU;IACrB,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;gBAEN,SAAS,EAAE,MAAM;IAW7B,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IA6E9D,aAAa,CAAC,OAAO,EAAE,MAAM,GACkD,GAAG;IAGlF,WAAW,CAAC,IAAI,EAAE,MAAM,GACqD,GAAG;IAGhF,cAAc,CAAC,IAAI,EAAE,MAAM,GACiD,GAAG,EAAE;IAGjF,gBAAgB,CAAC,MAAM,EAAE,MAAM,GACiD,GAAG,EAAE;IAGrF,gBAAgB,CAAC,MAAM,EAAE,MAAM,GACiD,GAAG,EAAE;IAGrF,SAAS,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAOtB,GAAG,EAAE;IAGrD,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAO3D,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAKoB,GAAG,EAAE;IAGrD,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAUsB,GAAG,EAAE;IAGrD,YAAY,CAAC,OAAO,EAAE,MAAM,GACqD,GAAG,EAAE;IAGtF,UAAU,CAAC,KAAK,EAAE,MAAM,GACuD,GAAG,EAAE;IAGpF,eAAe,CAAC,QAAQ,EAAE,MAAM;cAQJ,MAAM;eAAS,MAAM;eAAS,MAAM;iBAAW,MAAM,EAAE;iBAAW,MAAM;cAAQ,MAAM;;IA2BlH,QAAQ;;;;;;;IASR,KAAK;CAGN"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Database connection + indexing.
3
+ */
4
+ import Database from "better-sqlite3";
5
+ import { createHash } from "node:crypto";
6
+ import { readFileSync, existsSync, mkdirSync } from "node:fs";
7
+ import { join, dirname, basename } from "node:path";
8
+ import { CREATE_TABLES, SCHEMA_VERSION } from "./schema.js";
9
+ import { scanVault } from "../vault/scanner.js";
10
+ import { parseFrontmatter, getBody, getTags, getWikilinks } from "../vault/parser.js";
11
+ export class ZkDatabase {
12
+ db;
13
+ vaultRoot;
14
+ constructor(vaultRoot) {
15
+ this.vaultRoot = vaultRoot;
16
+ const dbDir = join(vaultRoot, ".zk");
17
+ if (!existsSync(dbDir))
18
+ mkdirSync(dbDir, { recursive: true });
19
+ const dbPath = join(dbDir, "zettelkasten.db");
20
+ this.db = new Database(dbPath);
21
+ this.db.pragma("journal_mode = WAL");
22
+ this.db.exec(CREATE_TABLES);
23
+ this.db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run("schema_version", String(SCHEMA_VERSION));
24
+ }
25
+ reindex() {
26
+ const notes = scanVault(this.vaultRoot);
27
+ const currentPaths = new Set(notes.map((n) => n.relPath));
28
+ let added = 0, updated = 0, removed = 0;
29
+ // Remove deleted notes
30
+ const dbPaths = this.db.prepare("SELECT path FROM notes").all();
31
+ const removePaths = dbPaths.filter((r) => !currentPaths.has(r.path));
32
+ const deleteNote = this.db.prepare("DELETE FROM notes WHERE path = ?");
33
+ const deleteLinks = this.db.prepare("DELETE FROM links WHERE source = ?");
34
+ for (const { path } of removePaths) {
35
+ deleteNote.run(path);
36
+ deleteLinks.run(path);
37
+ removed++;
38
+ }
39
+ // Upsert notes
40
+ const getHash = this.db.prepare("SELECT content_hash FROM notes WHERE path = ?");
41
+ const upsert = this.db.prepare(`
42
+ INSERT OR REPLACE INTO notes (path, title, zk_id, type, status, folder, tags, summary, created, modified, content_hash)
43
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
44
+ `);
45
+ const insertLink = this.db.prepare("INSERT OR REPLACE INTO links (source, target, link_type) VALUES (?, ?, ?)");
46
+ const transaction = this.db.transaction(() => {
47
+ for (const note of notes) {
48
+ const fullPath = join(this.vaultRoot, note.relPath);
49
+ let content;
50
+ try {
51
+ content = readFileSync(fullPath, "utf-8");
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ const hash = createHash("md5").update(content).digest("hex");
57
+ const existing = getHash.get(note.relPath);
58
+ if (existing?.content_hash === hash)
59
+ continue;
60
+ const fm = parseFrontmatter(fullPath);
61
+ const body = getBody(fullPath);
62
+ const title = basename(note.relPath, ".md");
63
+ const folder = dirname(note.relPath).split("/")[0] || "";
64
+ const tags = getTags(fm);
65
+ const summary = body.trim().slice(0, 200);
66
+ upsert.run(note.relPath, title, fm.zk_id || null, fm.type || null, fm.status || null, folder, JSON.stringify(tags), summary, fm.date || null, fm.last_modified || null, hash);
67
+ // Update links
68
+ deleteLinks.run(note.relPath);
69
+ const wikilinks = getWikilinks(fullPath);
70
+ for (const target of wikilinks) {
71
+ insertLink.run(note.relPath, target, null);
72
+ }
73
+ if (existing)
74
+ updated++;
75
+ else
76
+ added++;
77
+ }
78
+ });
79
+ transaction();
80
+ this.db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run("last_index", new Date().toISOString());
81
+ return { added, updated, removed };
82
+ }
83
+ getNoteByPath(relPath) {
84
+ return this.db.prepare("SELECT * FROM notes WHERE path = ?").get(relPath);
85
+ }
86
+ getNoteById(zkId) {
87
+ return this.db.prepare("SELECT * FROM notes WHERE zk_id = ?").get(zkId);
88
+ }
89
+ getNotesByType(type) {
90
+ return this.db.prepare("SELECT * FROM notes WHERE type = ?").all(type);
91
+ }
92
+ getNotesByStatus(status) {
93
+ return this.db.prepare("SELECT * FROM notes WHERE status = ?").all(status);
94
+ }
95
+ getNotesByFolder(folder) {
96
+ return this.db.prepare("SELECT * FROM notes WHERE folder = ?").all(folder);
97
+ }
98
+ listNotes(filters) {
99
+ let sql = "SELECT * FROM notes WHERE 1=1";
100
+ const params = [];
101
+ if (filters.type) {
102
+ sql += " AND type = ?";
103
+ params.push(filters.type);
104
+ }
105
+ if (filters.status) {
106
+ sql += " AND status = ?";
107
+ params.push(filters.status);
108
+ }
109
+ if (filters.folder) {
110
+ sql += " AND folder = ?";
111
+ params.push(filters.folder);
112
+ }
113
+ sql += " ORDER BY path";
114
+ return this.db.prepare(sql).all(...params);
115
+ }
116
+ getAllZkIds() {
117
+ const rows = this.db.prepare("SELECT zk_id, path, title FROM notes WHERE zk_id IS NOT NULL AND zk_id != ''").all();
118
+ const map = new Map();
119
+ for (const r of rows)
120
+ map.set(r.zk_id, { path: r.path, title: r.title });
121
+ return map;
122
+ }
123
+ getUnprocessed(type) {
124
+ let sql = "SELECT * FROM notes WHERE status IN ('unprocessed', 'draft')";
125
+ const params = [];
126
+ if (type) {
127
+ sql += " AND type = ?";
128
+ params.push(type);
129
+ }
130
+ sql += " ORDER BY folder, path";
131
+ return this.db.prepare(sql).all(...params);
132
+ }
133
+ getOrphans(folder) {
134
+ // Notes with no incoming links
135
+ let sql = `
136
+ SELECT n.* FROM notes n
137
+ LEFT JOIN links l ON l.target = n.title
138
+ WHERE l.target IS NULL
139
+ `;
140
+ const params = [];
141
+ if (folder) {
142
+ sql += " AND n.folder = ?";
143
+ params.push(folder);
144
+ }
145
+ sql += " ORDER BY n.path";
146
+ return this.db.prepare(sql).all(...params);
147
+ }
148
+ getLinksFrom(relPath) {
149
+ return this.db.prepare("SELECT * FROM links WHERE source = ?").all(relPath);
150
+ }
151
+ getLinksTo(title) {
152
+ return this.db.prepare("SELECT * FROM links WHERE target = ?").all(title);
153
+ }
154
+ findConnections(notePath) {
155
+ const note = this.getNoteByPath(notePath);
156
+ if (!note)
157
+ return [];
158
+ const noteTags = JSON.parse(note.tags || "[]");
159
+ const noteTitle = note.title;
160
+ const existingLinks = new Set(this.getLinksFrom(notePath).map((l) => l.target));
161
+ const allNotes = this.db.prepare("SELECT * FROM notes WHERE path != ?").all(notePath);
162
+ const candidates = [];
163
+ for (const other of allNotes) {
164
+ if (existingLinks.has(other.title))
165
+ continue;
166
+ let score = 0;
167
+ const reasons = [];
168
+ // Shared tags
169
+ const otherTags = JSON.parse(other.tags || "[]");
170
+ const shared = noteTags.filter((t) => otherTags.includes(t));
171
+ score += shared.length * 2;
172
+ reasons.push(...shared.map((t) => `tag:${t}`));
173
+ // Keyword overlap in summary
174
+ const noteWords = new Set((note.summary || "").toLowerCase().match(/[а-яієїґa-z]{4,}/g) ?? []);
175
+ const otherWords = (other.summary || "").toLowerCase().match(/[а-яієїґa-z]{4,}/g) ?? [];
176
+ const kwMatches = otherWords.filter((w) => noteWords.has(w)).length;
177
+ score += kwMatches;
178
+ if (score >= 2) {
179
+ candidates.push({ path: other.path, title: other.title, score, reasons, summary: other.summary || "", type: other.type || "" });
180
+ }
181
+ }
182
+ return candidates.sort((a, b) => b.score - a.score).slice(0, 15);
183
+ }
184
+ getStats() {
185
+ const total = this.db.prepare("SELECT COUNT(*) as c FROM notes").get().c;
186
+ const byType = this.db.prepare("SELECT type, COUNT(*) as c FROM notes GROUP BY type").all();
187
+ const byStatus = this.db.prepare("SELECT status, COUNT(*) as c FROM notes GROUP BY status").all();
188
+ const linkCount = this.db.prepare("SELECT COUNT(*) as c FROM links").get().c;
189
+ const lastIndex = this.db.prepare("SELECT value FROM meta WHERE key = 'last_index'").get()?.value;
190
+ return { total, byType, byStatus, linkCount, lastIndex };
191
+ }
192
+ close() {
193
+ this.db.close();
194
+ }
195
+ }
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * SQLite schema + migrations.
3
+ */
4
+ export declare const SCHEMA_VERSION = 1;
5
+ export declare const CREATE_TABLES = "\nCREATE TABLE IF NOT EXISTS notes (\n path TEXT PRIMARY KEY,\n title TEXT,\n zk_id TEXT,\n type TEXT,\n status TEXT,\n folder TEXT,\n tags TEXT,\n summary TEXT,\n created TEXT,\n modified TEXT,\n content_hash TEXT\n);\n\nCREATE TABLE IF NOT EXISTS links (\n source TEXT NOT NULL,\n target TEXT NOT NULL,\n link_type TEXT,\n PRIMARY KEY (source, target)\n);\n\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_notes_type ON notes(type);\nCREATE INDEX IF NOT EXISTS idx_notes_status ON notes(status);\nCREATE INDEX IF NOT EXISTS idx_notes_zk_id ON notes(zk_id);\nCREATE INDEX IF NOT EXISTS idx_links_target ON links(target);\n";
6
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,eAAO,MAAM,aAAa,msBA+BzB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * SQLite schema + migrations.
3
+ */
4
+ export const SCHEMA_VERSION = 1;
5
+ export const CREATE_TABLES = `
6
+ CREATE TABLE IF NOT EXISTS notes (
7
+ path TEXT PRIMARY KEY,
8
+ title TEXT,
9
+ zk_id TEXT,
10
+ type TEXT,
11
+ status TEXT,
12
+ folder TEXT,
13
+ tags TEXT,
14
+ summary TEXT,
15
+ created TEXT,
16
+ modified TEXT,
17
+ content_hash TEXT
18
+ );
19
+
20
+ CREATE TABLE IF NOT EXISTS links (
21
+ source TEXT NOT NULL,
22
+ target TEXT NOT NULL,
23
+ link_type TEXT,
24
+ PRIMARY KEY (source, target)
25
+ );
26
+
27
+ CREATE TABLE IF NOT EXISTS meta (
28
+ key TEXT PRIMARY KEY,
29
+ value TEXT
30
+ );
31
+
32
+ CREATE INDEX IF NOT EXISTS idx_notes_type ON notes(type);
33
+ CREATE INDEX IF NOT EXISTS idx_notes_status ON notes(status);
34
+ CREATE INDEX IF NOT EXISTS idx_notes_zk_id ON notes(zk_id);
35
+ CREATE INDEX IF NOT EXISTS idx_links_target ON links(target);
36
+ `;
37
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B5B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WizardAnswers } from "./wizard.js";
2
+ export declare function scaffold(answers: WizardAnswers): void;
3
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/init/scaffold.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA4BjD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,aAAa,QA+F9C"}