@zabaca/lattice 1.0.2 → 1.0.4
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/commands/entity-extract.md +1 -1
- package/commands/graph-sync.md +7 -7
- package/commands/research.md +6 -6
- package/dist/main.js +50 -2
- package/package.json +1 -1
|
@@ -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.,
|
|
86
|
+
(e.g., `~/.lattice/docs/claude-code/file.md` -> `topic: claude-code`)
|
|
87
87
|
|
|
88
88
|
Frontmatter template:
|
|
89
89
|
```yaml
|
package/commands/graph-sync.md
CHANGED
|
@@ -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
|
|
package/commands/research.md
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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**
|
|
149
|
+
**1. Create** `~/.lattice/docs/{topic-name}/{research-filename}.md` with content template above
|
|
150
150
|
|
|
151
|
-
**2. Update**
|
|
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
|
@@ -844,11 +844,35 @@ class GraphService {
|
|
|
844
844
|
connecting = null;
|
|
845
845
|
vectorIndexes = new Set;
|
|
846
846
|
embeddingDimensions;
|
|
847
|
+
signalHandlersRegistered = false;
|
|
847
848
|
constructor(configService) {
|
|
848
849
|
this.configService = configService;
|
|
849
850
|
ensureLatticeHome();
|
|
850
851
|
this.dbPath = getDatabasePath();
|
|
851
852
|
this.embeddingDimensions = this.configService.get("EMBEDDING_DIMENSIONS") || 512;
|
|
853
|
+
this.registerSignalHandlers();
|
|
854
|
+
}
|
|
855
|
+
registerSignalHandlers() {
|
|
856
|
+
if (this.signalHandlersRegistered)
|
|
857
|
+
return;
|
|
858
|
+
this.signalHandlersRegistered = true;
|
|
859
|
+
const gracefulShutdown = async (signal) => {
|
|
860
|
+
this.logger.log(`Received ${signal}, checkpointing before exit...`);
|
|
861
|
+
try {
|
|
862
|
+
await this.checkpoint();
|
|
863
|
+
await this.disconnect();
|
|
864
|
+
} catch (error) {
|
|
865
|
+
this.logger.error(`Error during graceful shutdown: ${error instanceof Error ? error.message : String(error)}`);
|
|
866
|
+
}
|
|
867
|
+
process.exit(0);
|
|
868
|
+
};
|
|
869
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
870
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
871
|
+
process.on("beforeExit", async () => {
|
|
872
|
+
if (this.connection) {
|
|
873
|
+
await this.checkpoint();
|
|
874
|
+
}
|
|
875
|
+
});
|
|
852
876
|
}
|
|
853
877
|
async onModuleDestroy() {
|
|
854
878
|
await this.disconnect();
|
|
@@ -874,7 +898,7 @@ class GraphService {
|
|
|
874
898
|
}
|
|
875
899
|
async connect() {
|
|
876
900
|
try {
|
|
877
|
-
this.instance = await DuckDBInstance.create(
|
|
901
|
+
this.instance = await DuckDBInstance.create(":memory:", {
|
|
878
902
|
allow_unsigned_extensions: "true"
|
|
879
903
|
});
|
|
880
904
|
this.connection = await this.instance.connect();
|
|
@@ -888,8 +912,10 @@ class GraphService {
|
|
|
888
912
|
} catch (e) {
|
|
889
913
|
this.logger.warn(`DuckPGQ extension not available: ${e instanceof Error ? e.message : String(e)}`);
|
|
890
914
|
}
|
|
915
|
+
await this.connection.run(`ATTACH '${this.dbPath}' AS lattice (READ_WRITE);`);
|
|
916
|
+
await this.connection.run("USE lattice;");
|
|
891
917
|
await this.initializeSchema();
|
|
892
|
-
this.logger.log(`Connected to DuckDB at ${this.dbPath}`);
|
|
918
|
+
this.logger.log(`Connected to DuckDB (in-memory + ATTACH) at ${this.dbPath}`);
|
|
893
919
|
} catch (error) {
|
|
894
920
|
this.connection = null;
|
|
895
921
|
this.instance = null;
|
|
@@ -899,6 +925,7 @@ class GraphService {
|
|
|
899
925
|
}
|
|
900
926
|
async disconnect() {
|
|
901
927
|
if (this.connection) {
|
|
928
|
+
await this.checkpoint();
|
|
902
929
|
this.connection.closeSync();
|
|
903
930
|
this.connection = null;
|
|
904
931
|
this.logger.log("Disconnected from DuckDB");
|
|
@@ -907,6 +934,17 @@ class GraphService {
|
|
|
907
934
|
this.instance = null;
|
|
908
935
|
}
|
|
909
936
|
}
|
|
937
|
+
async checkpoint() {
|
|
938
|
+
if (!this.connection) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
await this.connection.run("CHECKPOINT;");
|
|
943
|
+
this.logger.debug("Checkpoint completed");
|
|
944
|
+
} catch (error) {
|
|
945
|
+
this.logger.warn(`Checkpoint failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
910
948
|
async initializeSchema() {
|
|
911
949
|
if (!this.connection) {
|
|
912
950
|
throw new Error("Cannot initialize schema: not connected");
|
|
@@ -2037,10 +2075,13 @@ class SyncService {
|
|
|
2037
2075
|
}
|
|
2038
2076
|
if (!options.dryRun) {
|
|
2039
2077
|
result.entityEmbeddingsGenerated = await this.syncEntities(uniqueEntities, options);
|
|
2078
|
+
await this.graph.checkpoint();
|
|
2040
2079
|
if (options.verbose) {
|
|
2041
2080
|
this.logger.log(`Synced ${uniqueEntities.size} entities, generated ${result.entityEmbeddingsGenerated} embeddings`);
|
|
2042
2081
|
}
|
|
2043
2082
|
}
|
|
2083
|
+
const CHECKPOINT_BATCH_SIZE = 10;
|
|
2084
|
+
let processedCount = 0;
|
|
2044
2085
|
for (const change of changes) {
|
|
2045
2086
|
try {
|
|
2046
2087
|
const doc = docsByPath.get(change.path);
|
|
@@ -2063,12 +2104,19 @@ class SyncService {
|
|
|
2063
2104
|
if (change.embeddingGenerated) {
|
|
2064
2105
|
result.embeddingsGenerated++;
|
|
2065
2106
|
}
|
|
2107
|
+
processedCount++;
|
|
2108
|
+
if (!options.dryRun && processedCount % CHECKPOINT_BATCH_SIZE === 0) {
|
|
2109
|
+
await this.graph.checkpoint();
|
|
2110
|
+
}
|
|
2066
2111
|
} catch (error) {
|
|
2067
2112
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2068
2113
|
result.errors.push({ path: change.path, error: errorMessage });
|
|
2069
2114
|
this.logger.warn(`Error processing ${change.path}: ${errorMessage}`);
|
|
2070
2115
|
}
|
|
2071
2116
|
}
|
|
2117
|
+
if (!options.dryRun && processedCount > 0) {
|
|
2118
|
+
await this.graph.checkpoint();
|
|
2119
|
+
}
|
|
2072
2120
|
if (!options.dryRun) {
|
|
2073
2121
|
await this.manifest.save();
|
|
2074
2122
|
}
|