@zabaca/lattice 1.0.1 → 1.0.3

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.
@@ -83,7 +83,7 @@ The goal is to ensure entities reflect the document's CURRENT state, not preserv
83
83
  - Preserve existing fields like `created`, `status`, `topic` (but update `updated` date)
84
84
  - **Replace** the `summary`, `entities` and `relationships` sections entirely
85
85
  - If no topic field exists, derive it from the directory name
86
- (e.g., `docs/claude-code/file.md` -> `topic: claude-code`)
86
+ (e.g., `~/.lattice/docs/claude-code/file.md` -> `topic: claude-code`)
87
87
 
88
88
  Frontmatter template:
89
89
  ```yaml
@@ -3,7 +3,7 @@ description: Extract entities from modified docs and sync to graph
3
3
  model: sonnet
4
4
  ---
5
5
 
6
- Identify modified documents, extract entities from them, and sync to the knowledge graph.
6
+ Identify modified documents in `~/.lattice/docs/`, extract entities from them, and sync to the knowledge graph.
7
7
 
8
8
  ## Process
9
9
 
@@ -38,16 +38,16 @@ For each new or updated document identified:
38
38
  Task(
39
39
  subagent_type="general-purpose",
40
40
  model="haiku",
41
- prompt="Use /entity-extract docs/topic/document.md to extract entities. Follow all instructions and report completion."
41
+ prompt="Use /entity-extract ~/.lattice/docs/topic/document.md to extract entities. Follow all instructions and report completion."
42
42
  )
43
43
  ```
44
44
 
45
45
  **For multiple documents, launch agents in parallel:**
46
46
  ```
47
47
  // In a single message, launch multiple Task tool calls:
48
- Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract docs/topic-a/README.md ...")
49
- Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract docs/topic-b/notes.md ...")
50
- Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract docs/topic-c/README.md ...")
48
+ Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract ~/.lattice/docs/topic-a/README.md ...")
49
+ Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract ~/.lattice/docs/topic-b/notes.md ...")
50
+ Task(subagent_type="general-purpose", model="haiku", prompt="/entity-extract ~/.lattice/docs/topic-c/README.md ...")
51
51
  ```
52
52
 
53
53
  This is much faster than sequential execution for multiple documents.
@@ -87,15 +87,15 @@ Summarize what was processed:
87
87
 
88
88
  Processed 3 documents:
89
89
 
90
- 1. docs/american-holidays/README.md
90
+ 1. ~/.lattice/docs/american-holidays/README.md
91
91
  - 4 entities extracted
92
92
  - 3 relationships defined
93
93
 
94
- 2. docs/american-holidays/thanksgiving-vs-christmas.md
94
+ 2. ~/.lattice/docs/american-holidays/thanksgiving-vs-christmas.md
95
95
  - 8 entities extracted
96
96
  - 5 relationships defined
97
97
 
98
- 3. docs/bun-nestjs/notes.md
98
+ 3. ~/.lattice/docs/bun-nestjs/notes.md
99
99
  - 5 entities extracted
100
100
  - 4 relationships defined
101
101
 
@@ -65,7 +65,7 @@ If user wants new research:
65
65
  ### Step 6: Determine Topic and Filename
66
66
 
67
67
  **Identify the topic directory:**
68
- - Check if a relevant `docs/{topic-name}/` directory already exists
68
+ - Check if a relevant `~/.lattice/docs/{topic-name}/` directory already exists
69
69
  - If not, derive a new topic name from the query (kebab-case)
70
70
 
71
71
  **Derive the research filename:**
@@ -89,7 +89,7 @@ Auto-derive from the specific focus of the query:
89
89
 
90
90
  Create TWO files:
91
91
 
92
- **1. `docs/{topic-name}/README.md`** (index):
92
+ **1. `~/.lattice/docs/{topic-name}/README.md`** (index):
93
93
  ```markdown
94
94
  ---
95
95
  created: [TODAY'S DATE]
@@ -115,7 +115,7 @@ Brief description of what this topic covers.
115
115
  - [Related Topic](../related-topic/)
116
116
  ```
117
117
 
118
- **2. `docs/{topic-name}/{research-filename}.md`** (content):
118
+ **2. `~/.lattice/docs/{topic-name}/{research-filename}.md`** (content):
119
119
  ```markdown
120
120
  ---
121
121
  created: [TODAY'S DATE]
@@ -146,9 +146,9 @@ What this research addresses.
146
146
 
147
147
  #### For EXISTING Topics (directory exists)
148
148
 
149
- **1. Create** `docs/{topic-name}/{research-filename}.md` with content template above
149
+ **1. Create** `~/.lattice/docs/{topic-name}/{research-filename}.md` with content template above
150
150
 
151
- **2. Update** `docs/{topic-name}/README.md`:
151
+ **2. Update** `~/.lattice/docs/{topic-name}/README.md`:
152
152
  - Add new row to the Documents table
153
153
  - Update the `updated` date in frontmatter
154
154
 
@@ -173,7 +173,7 @@ After creating files, confirm:
173
173
  ## File Structure Standard
174
174
 
175
175
  ```
176
- docs/{topic-name}/
176
+ ~/.lattice/docs/{topic-name}/
177
177
  ├── README.md # Index: links to docs, brief overview
178
178
  ├── {research-1}.md # Specific research
179
179
  ├── {research-2}.md # Additional research
package/dist/main.js CHANGED
@@ -24,12 +24,52 @@ import { Module as Module5 } from "@nestjs/common";
24
24
  import { ConfigModule as ConfigModule2 } from "@nestjs/config";
25
25
 
26
26
  // src/commands/init.command.ts
27
+ import { existsSync as existsSync2, writeFileSync } from "fs";
27
28
  import * as fs from "fs/promises";
28
- import { homedir } from "os";
29
+ import { homedir as homedir2 } from "os";
29
30
  import * as path from "path";
30
31
  import { fileURLToPath } from "url";
31
32
  import { Injectable } from "@nestjs/common";
32
33
  import { Command, CommandRunner, Option } from "nest-commander";
34
+
35
+ // src/utils/paths.ts
36
+ import { existsSync, mkdirSync } from "fs";
37
+ import { homedir } from "os";
38
+ import { join } from "path";
39
+ var latticeHomeOverride = null;
40
+ function getLatticeHomeInternal() {
41
+ if (latticeHomeOverride) {
42
+ return latticeHomeOverride;
43
+ }
44
+ return join(homedir(), ".lattice");
45
+ }
46
+ function getLatticeHome() {
47
+ return getLatticeHomeInternal();
48
+ }
49
+ function getDocsPath() {
50
+ return join(getLatticeHomeInternal(), "docs");
51
+ }
52
+ function getDatabasePath() {
53
+ return join(getLatticeHomeInternal(), "lattice.duckdb");
54
+ }
55
+ function getManifestPath() {
56
+ return join(getLatticeHomeInternal(), ".sync-manifest.json");
57
+ }
58
+ function getEnvPath() {
59
+ return join(getLatticeHomeInternal(), ".env");
60
+ }
61
+ function ensureLatticeHome() {
62
+ const home = getLatticeHomeInternal();
63
+ if (!existsSync(home)) {
64
+ mkdirSync(home, { recursive: true });
65
+ }
66
+ const docsPath = getDocsPath();
67
+ if (!existsSync(docsPath)) {
68
+ mkdirSync(docsPath, { recursive: true });
69
+ }
70
+ }
71
+
72
+ // src/commands/init.command.ts
33
73
  var __filename2 = fileURLToPath(import.meta.url);
34
74
  var __dirname2 = path.dirname(__filename2);
35
75
  var COMMANDS = ["research.md", "graph-sync.md", "entity-extract.md"];
@@ -37,7 +77,20 @@ var COMMANDS = ["research.md", "graph-sync.md", "entity-extract.md"];
37
77
  class InitCommand extends CommandRunner {
38
78
  async run(_inputs, options) {
39
79
  try {
40
- const targetDir = options.global ? path.join(homedir(), ".claude", "commands") : path.join(process.cwd(), ".claude", "commands");
80
+ ensureLatticeHome();
81
+ const envPath = getEnvPath();
82
+ if (!existsSync2(envPath)) {
83
+ writeFileSync(envPath, `# Lattice Configuration
84
+ # Get your API key from: https://www.voyageai.com/
85
+
86
+ VOYAGE_API_KEY=
87
+ `);
88
+ }
89
+ console.log(`\u2705 Lattice home directory: ${getLatticeHome()}`);
90
+ console.log(` Documents: ${getDocsPath()}`);
91
+ console.log(` Config: ${envPath}`);
92
+ console.log();
93
+ const targetDir = options.global ? path.join(homedir2(), ".claude", "commands") : path.join(process.cwd(), ".claude", "commands");
41
94
  let commandsSourceDir = path.resolve(__dirname2, "..", "commands");
42
95
  try {
43
96
  await fs.access(commandsSourceDir);
@@ -97,7 +150,10 @@ class InitCommand extends CommandRunner {
97
150
  console.log();
98
151
  if (!options.global) {
99
152
  console.log("\uD83D\uDCA1 Tip: Use 'lattice init --global' to install for all projects");
153
+ console.log();
100
154
  }
155
+ console.log(`\u26A0\uFE0F Add your Voyage API key to: ${getEnvPath()}`);
156
+ console.log();
101
157
  process.exit(0);
102
158
  } catch (error) {
103
159
  console.error("Error:", error instanceof Error ? error.message : String(error));
@@ -134,31 +190,13 @@ import { Injectable as Injectable3 } from "@nestjs/common";
134
190
  // src/sync/document-parser.service.ts
135
191
  import { createHash } from "crypto";
136
192
  import { readFile as readFile2 } from "fs/promises";
137
- import { resolve as resolve2 } from "path";
138
193
  import { Injectable as Injectable2, Logger } from "@nestjs/common";
139
194
  import { glob } from "glob";
140
195
 
141
- // src/schemas/config.schemas.ts
142
- import { z } from "zod";
143
- var DuckDBConfigSchema = z.object({
144
- dbPath: z.string().optional(),
145
- embeddingDimensions: z.coerce.number().int().positive().default(512)
146
- });
147
- var EmbeddingConfigSchema = z.object({
148
- provider: z.enum(["openai", "voyage", "nomic", "mock"]).default("voyage"),
149
- apiKey: z.string().optional(),
150
- model: z.string().min(1).default("voyage-3.5-lite"),
151
- dimensions: z.coerce.number().int().positive().default(512)
152
- });
153
- var DocsConfigSchema = z.object({
154
- projectRoot: z.string().default(process.cwd()),
155
- docsPath: z.string().default("docs")
156
- });
157
-
158
196
  // src/utils/frontmatter.ts
159
197
  import matter from "gray-matter";
160
- import { z as z2 } from "zod";
161
- var EntityTypeSchema = z2.enum([
198
+ import { z } from "zod";
199
+ var EntityTypeSchema = z.enum([
162
200
  "Topic",
163
201
  "Technology",
164
202
  "Concept",
@@ -168,20 +206,20 @@ var EntityTypeSchema = z2.enum([
168
206
  "Organization",
169
207
  "Document"
170
208
  ]);
171
- var RelationTypeSchema = z2.enum(["REFERENCES"]);
172
- var EntitySchema = z2.object({
173
- name: z2.string().min(1),
209
+ var RelationTypeSchema = z.enum(["REFERENCES"]);
210
+ var EntitySchema = z.object({
211
+ name: z.string().min(1),
174
212
  type: EntityTypeSchema,
175
- description: z2.string().optional()
213
+ description: z.string().optional()
176
214
  });
177
- var RelationshipSchema = z2.object({
178
- source: z2.string().min(1),
215
+ var RelationshipSchema = z.object({
216
+ source: z.string().min(1),
179
217
  relation: RelationTypeSchema,
180
- target: z2.string().min(1)
218
+ target: z.string().min(1)
181
219
  });
182
- var GraphMetadataSchema = z2.object({
183
- importance: z2.enum(["high", "medium", "low"]).optional(),
184
- domain: z2.string().optional()
220
+ var GraphMetadataSchema = z.object({
221
+ importance: z.enum(["high", "medium", "low"]).optional(),
222
+ domain: z.string().optional()
185
223
  });
186
224
  var validateDateFormat = (dateStr) => {
187
225
  const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
@@ -201,15 +239,15 @@ var validateDateFormat = (dateStr) => {
201
239
  }
202
240
  return day <= daysInMonth[month - 1];
203
241
  };
204
- var FrontmatterSchema = z2.object({
205
- created: z2.string().refine(validateDateFormat, "Date must be in YYYY-MM-DD format"),
206
- updated: z2.string().refine(validateDateFormat, "Date must be in YYYY-MM-DD format"),
207
- status: z2.enum(["draft", "ongoing", "complete"]).optional(),
208
- topic: z2.string().optional(),
209
- tags: z2.array(z2.string()).optional(),
210
- summary: z2.string().optional(),
211
- entities: z2.array(EntitySchema).optional(),
212
- relationships: z2.array(RelationshipSchema).optional(),
242
+ var FrontmatterSchema = z.object({
243
+ created: z.string().refine(validateDateFormat, "Date must be in YYYY-MM-DD format"),
244
+ updated: z.string().refine(validateDateFormat, "Date must be in YYYY-MM-DD format"),
245
+ status: z.enum(["draft", "ongoing", "complete"]).optional(),
246
+ topic: z.string().optional(),
247
+ tags: z.array(z.string()).optional(),
248
+ summary: z.string().optional(),
249
+ entities: z.array(EntitySchema).optional(),
250
+ relationships: z.array(RelationshipSchema).optional(),
213
251
  graph: GraphMetadataSchema.optional()
214
252
  }).passthrough();
215
253
  function parseFrontmatter(content) {
@@ -256,15 +294,8 @@ class DocumentParserService {
256
294
  logger = new Logger(DocumentParserService.name);
257
295
  docsPath;
258
296
  constructor() {
259
- const config = DocsConfigSchema.parse({
260
- projectRoot: process.env.PROJECT_ROOT,
261
- docsPath: process.env.DOCS_PATH
262
- });
263
- if (config.docsPath.startsWith("/")) {
264
- this.docsPath = config.docsPath;
265
- } else {
266
- this.docsPath = resolve2(config.projectRoot, config.docsPath);
267
- }
297
+ ensureLatticeHome();
298
+ this.docsPath = getDocsPath();
268
299
  }
269
300
  getDocsPath() {
270
301
  return this.docsPath;
@@ -542,6 +573,18 @@ import { Command as Command3, CommandRunner as CommandRunner3, Option as Option2
542
573
  import { Injectable as Injectable5, Logger as Logger2 } from "@nestjs/common";
543
574
  import { ConfigService } from "@nestjs/config";
544
575
 
576
+ // src/schemas/config.schemas.ts
577
+ import { z as z2 } from "zod";
578
+ var DuckDBConfigSchema = z2.object({
579
+ embeddingDimensions: z2.coerce.number().int().positive().default(512)
580
+ });
581
+ var EmbeddingConfigSchema = z2.object({
582
+ provider: z2.enum(["openai", "voyage", "nomic", "mock"]).default("voyage"),
583
+ apiKey: z2.string().optional(),
584
+ model: z2.string().min(1).default("voyage-3.5-lite"),
585
+ dimensions: z2.coerce.number().int().positive().default(512)
586
+ });
587
+
545
588
  // src/embedding/embedding.types.ts
546
589
  var DEFAULT_EMBEDDING_CONFIG = {
547
590
  provider: "voyage",
@@ -789,6 +832,7 @@ EmbeddingService = __legacyDecorateClassTS([
789
832
  ], EmbeddingService);
790
833
 
791
834
  // src/graph/graph.service.ts
835
+ import { existsSync as existsSync3, unlinkSync } from "fs";
792
836
  import { DuckDBInstance } from "@duckdb/node-api";
793
837
  import { Injectable as Injectable6, Logger as Logger3 } from "@nestjs/common";
794
838
  import { ConfigService as ConfigService2 } from "@nestjs/config";
@@ -803,7 +847,8 @@ class GraphService {
803
847
  embeddingDimensions;
804
848
  constructor(configService) {
805
849
  this.configService = configService;
806
- this.dbPath = this.configService.get("DUCKDB_PATH") || "./.lattice.duckdb";
850
+ ensureLatticeHome();
851
+ this.dbPath = getDatabasePath();
807
852
  this.embeddingDimensions = this.configService.get("EMBEDDING_DIMENSIONS") || 512;
808
853
  }
809
854
  async onModuleDestroy() {
@@ -830,6 +875,11 @@ class GraphService {
830
875
  }
831
876
  async connect() {
832
877
  try {
878
+ const walPath = `${this.dbPath}.wal`;
879
+ if (existsSync3(walPath)) {
880
+ this.logger.warn(`Removing WAL file to prevent HNSW index replay failure`);
881
+ unlinkSync(walPath);
882
+ }
833
883
  this.instance = await DuckDBInstance.create(this.dbPath, {
834
884
  allow_unsigned_extensions: "true"
835
885
  });
@@ -855,6 +905,11 @@ class GraphService {
855
905
  }
856
906
  async disconnect() {
857
907
  if (this.connection) {
908
+ try {
909
+ await this.connection.run("CHECKPOINT;");
910
+ } catch {
911
+ this.logger.debug("Checkpoint failed during disconnect");
912
+ }
858
913
  this.connection.closeSync();
859
914
  this.connection = null;
860
915
  this.logger.log("Disconnected from DuckDB");
@@ -1329,9 +1384,8 @@ import { Command as Command4, CommandRunner as CommandRunner4, Option as Option3
1329
1384
 
1330
1385
  // src/sync/manifest.service.ts
1331
1386
  import { createHash as createHash2 } from "crypto";
1332
- import { existsSync } from "fs";
1387
+ import { existsSync as existsSync4 } from "fs";
1333
1388
  import { readFile as readFile3, writeFile } from "fs/promises";
1334
- import { resolve as resolve3 } from "path";
1335
1389
  import { Injectable as Injectable8 } from "@nestjs/common";
1336
1390
 
1337
1391
  // src/schemas/manifest.schemas.ts
@@ -1350,23 +1404,15 @@ var SyncManifestSchema = z4.object({
1350
1404
  });
1351
1405
 
1352
1406
  // src/sync/manifest.service.ts
1353
- function getProjectRoot() {
1354
- if (process.env.PROJECT_ROOT) {
1355
- return process.env.PROJECT_ROOT;
1356
- }
1357
- return process.cwd();
1358
- }
1359
-
1360
1407
  class ManifestService {
1361
1408
  manifestPath;
1362
1409
  manifest = null;
1363
1410
  constructor() {
1364
- const docsPath = process.env.DOCS_PATH || "docs";
1365
- this.manifestPath = resolve3(getProjectRoot(), docsPath, ".sync-manifest.json");
1411
+ this.manifestPath = getManifestPath();
1366
1412
  }
1367
1413
  async load() {
1368
1414
  try {
1369
- if (existsSync(this.manifestPath)) {
1415
+ if (existsSync4(this.manifestPath)) {
1370
1416
  const content = await readFile3(this.manifestPath, "utf-8");
1371
1417
  this.manifest = SyncManifestSchema.parse(JSON.parse(content));
1372
1418
  } else {
@@ -1852,16 +1898,16 @@ CascadeService = __legacyDecorateClassTS([
1852
1898
  ], CascadeService);
1853
1899
 
1854
1900
  // src/sync/path-resolver.service.ts
1855
- import { existsSync as existsSync2 } from "fs";
1856
- import { isAbsolute, resolve as resolve4 } from "path";
1901
+ import { existsSync as existsSync5 } from "fs";
1902
+ import { isAbsolute, resolve as resolve2 } from "path";
1857
1903
  import { Injectable as Injectable10 } from "@nestjs/common";
1858
1904
  class PathResolverService {
1859
- parser;
1860
- constructor(parser) {
1861
- this.parser = parser;
1905
+ docsPath;
1906
+ constructor() {
1907
+ this.docsPath = getDocsPath();
1862
1908
  }
1863
1909
  getDocsPath() {
1864
- return this.parser.getDocsPath();
1910
+ return this.docsPath;
1865
1911
  }
1866
1912
  resolveDocPath(userPath, options = {}) {
1867
1913
  const { requireExists = true, requireInDocs = true } = options;
@@ -1869,28 +1915,12 @@ class PathResolverService {
1869
1915
  if (isAbsolute(userPath)) {
1870
1916
  resolvedPath = userPath;
1871
1917
  } else {
1872
- const fromCwd = resolve4(process.cwd(), userPath);
1873
- const fromDocs = resolve4(this.getDocsPath(), userPath);
1874
- const docsPrefix = "docs/";
1875
- const strippedFromDocs = userPath.startsWith(docsPrefix) ? resolve4(this.getDocsPath(), userPath.slice(docsPrefix.length)) : null;
1876
- if (this.isUnderDocs(fromCwd) && existsSync2(fromCwd)) {
1877
- resolvedPath = fromCwd;
1878
- } else if (strippedFromDocs && existsSync2(strippedFromDocs)) {
1879
- resolvedPath = strippedFromDocs;
1880
- } else if (existsSync2(fromDocs)) {
1881
- resolvedPath = fromDocs;
1882
- } else if (this.isUnderDocs(fromCwd)) {
1883
- resolvedPath = fromCwd;
1884
- } else if (strippedFromDocs) {
1885
- resolvedPath = strippedFromDocs;
1886
- } else {
1887
- resolvedPath = fromDocs;
1888
- }
1918
+ resolvedPath = resolve2(this.docsPath, userPath);
1889
1919
  }
1890
1920
  if (requireInDocs && !this.isUnderDocs(resolvedPath)) {
1891
- throw new Error(`Path "${userPath}" resolves to "${resolvedPath}" which is outside the docs directory (${this.getDocsPath()})`);
1921
+ throw new Error(`Path "${userPath}" resolves to "${resolvedPath}" which is outside the docs directory (${this.docsPath})`);
1892
1922
  }
1893
- if (requireExists && !existsSync2(resolvedPath)) {
1923
+ if (requireExists && !existsSync5(resolvedPath)) {
1894
1924
  throw new Error(`Path "${userPath}" does not exist (resolved to: ${resolvedPath})`);
1895
1925
  }
1896
1926
  return resolvedPath;
@@ -1914,9 +1944,7 @@ class PathResolverService {
1914
1944
  }
1915
1945
  PathResolverService = __legacyDecorateClassTS([
1916
1946
  Injectable10(),
1917
- __legacyMetadataTS("design:paramtypes", [
1918
- typeof DocumentParserService === "undefined" ? Object : DocumentParserService
1919
- ])
1947
+ __legacyMetadataTS("design:paramtypes", [])
1920
1948
  ], PathResolverService);
1921
1949
 
1922
1950
  // src/sync/sync.service.ts
@@ -2419,7 +2447,7 @@ StatusCommand = __legacyDecorateClassTS([
2419
2447
  ], StatusCommand);
2420
2448
  // src/commands/sync.command.ts
2421
2449
  import { watch } from "fs";
2422
- import { join as join2 } from "path";
2450
+ import { join as join3 } from "path";
2423
2451
  import { Injectable as Injectable13 } from "@nestjs/common";
2424
2452
  import { Command as Command5, CommandRunner as CommandRunner5, Option as Option4 } from "nest-commander";
2425
2453
  class SyncCommand extends CommandRunner5 {
@@ -2545,7 +2573,7 @@ class SyncCommand extends CommandRunner5 {
2545
2573
  `);
2546
2574
  this.watcher = watch(docsPath, { recursive: true }, (event, filename) => {
2547
2575
  if (filename?.endsWith(".md")) {
2548
- const fullPath = join2(docsPath, filename);
2576
+ const fullPath = join3(docsPath, filename);
2549
2577
  trackedFiles.add(fullPath);
2550
2578
  debouncedSync();
2551
2579
  }
@@ -2920,7 +2948,8 @@ AppModule = __legacyDecorateClassTS([
2920
2948
  Module5({
2921
2949
  imports: [
2922
2950
  ConfigModule2.forRoot({
2923
- isGlobal: true
2951
+ isGlobal: true,
2952
+ envFilePath: getEnvPath()
2924
2953
  }),
2925
2954
  GraphModule,
2926
2955
  SyncModule,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zabaca/lattice",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Human-initiated, AI-powered knowledge graph for markdown documentation",
5
5
  "type": "module",
6
6
  "bin": {