memorix 1.1.7 → 1.1.9
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 +22 -0
- package/CLAUDE.md +6 -1
- package/README.md +21 -0
- package/README.zh-CN.md +21 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +852 -214
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/index.html +201 -201
- package/dist/dashboard/static/style.css +3584 -3584
- package/dist/index.js +129 -62
- package/dist/index.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +22 -0
- package/dist/memcode-runtime/package.json +4 -4
- package/dist/sdk.js +129 -62
- package/dist/sdk.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +18 -0
- package/docs/API_REFERENCE.md +2 -0
- package/docs/CONFIGURATION.md +18 -0
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/SETUP.md +10 -0
- package/docs/dev-log/progress.txt +23 -30
- package/package.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/agent-integrations.ts +623 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +255 -255
- package/src/cli/commands/codegraph.ts +4 -0
- package/src/cli/commands/config-get.ts +9 -2
- package/src/cli/commands/doctor.ts +26 -0
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +66 -66
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +73 -73
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +96 -96
- package/src/cli/commands/message.ts +121 -121
- package/src/cli/commands/poll.ts +70 -70
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +132 -132
- package/src/cli/commands/repair.ts +60 -0
- package/src/cli/commands/retention.ts +108 -108
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/setup.ts +3 -3
- package/src/cli/commands/skills.ts +123 -123
- package/src/cli/commands/task.ts +192 -192
- package/src/cli/commands/transfer.ts +73 -73
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Panels.tsx +632 -632
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +742 -742
- package/src/cli/tui/data.ts +547 -547
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/theme.ts +178 -178
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/auto-context.ts +6 -0
- package/src/codegraph/context-pack.ts +7 -6
- package/src/codegraph/exclude.ts +47 -0
- package/src/codegraph/lite-provider.ts +5 -24
- package/src/codegraph/project-context.ts +13 -15
- package/src/compact/token-budget.ts +74 -74
- package/src/config/behavior.ts +59 -59
- package/src/config/resolved-config.ts +6 -0
- package/src/config/toml-loader.ts +4 -0
- package/src/config/yaml-loader.ts +7 -0
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/static/index.html +201 -201
- package/src/dashboard/static/style.css +3584 -3584
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/git/noise-filter.ts +210 -210
- package/src/hooks/installers/index.ts +4 -4
- package/src/hooks/official-skills.ts +1 -1
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +2 -2
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +107 -107
- package/src/memory/consolidation.ts +302 -302
- package/src/memory/disclosure-policy.ts +141 -141
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +433 -433
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +523 -523
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +380 -380
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/verify-gate.ts +219 -219
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +327 -327
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/server.ts +3 -0
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/file-lock.ts +100 -100
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/obs-store.ts +255 -255
- package/src/store/orama-store.ts +15 -8
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/session-store.ts +259 -259
- package/src/store/sqlite-store.ts +339 -339
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +167 -167
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/wiki/generator.ts +237 -237
- package/src/wiki/knowledge-graph.ts +334 -334
- package/src/wiki/types.ts +85 -85
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
|
@@ -1,212 +1,212 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON Persistence Helpers — Migration / Export / Debug Only
|
|
3
|
-
*
|
|
4
|
-
* These functions read/write JSON/JSONL files for one-time migration
|
|
5
|
-
* from legacy storage formats into SQLite, or for export/import and debug.
|
|
6
|
-
*
|
|
7
|
-
* NOT used as runtime canonical store — SQLite is the sole canonical backend.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { promises as fs } from 'node:fs';
|
|
11
|
-
import path from 'node:path';
|
|
12
|
-
import { atomicWriteFile } from './file-lock.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Get the file path for the knowledge graph JSONL file.
|
|
16
|
-
* (MCP-compatible format, same as official Memory Server)
|
|
17
|
-
*/
|
|
18
|
-
export function getGraphFilePath(projectDir: string): string {
|
|
19
|
-
return path.join(projectDir, 'graph.jsonl');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Save the knowledge graph in JSONL format (MCP-compatible).
|
|
24
|
-
* Each line is a JSON object with type: "entity" or "relation".
|
|
25
|
-
*
|
|
26
|
-
* Format adopted from MCP Official Memory Server.
|
|
27
|
-
*/
|
|
28
|
-
export async function saveGraphJsonl(
|
|
29
|
-
projectDir: string,
|
|
30
|
-
entities: Array<{ name: string; entityType: string; observations: string[] }>,
|
|
31
|
-
relations: Array<{ from: string; to: string; relationType: string }>,
|
|
32
|
-
): Promise<void> {
|
|
33
|
-
const lines = [
|
|
34
|
-
...entities.map((e) =>
|
|
35
|
-
JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations }),
|
|
36
|
-
),
|
|
37
|
-
...relations.map((r) =>
|
|
38
|
-
JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType }),
|
|
39
|
-
),
|
|
40
|
-
];
|
|
41
|
-
await atomicWriteFile(getGraphFilePath(projectDir), lines.join('\n'));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Load the knowledge graph from JSONL format.
|
|
46
|
-
*/
|
|
47
|
-
export async function loadGraphJsonl(
|
|
48
|
-
projectDir: string,
|
|
49
|
-
): Promise<{
|
|
50
|
-
entities: Array<{ name: string; entityType: string; observations: string[] }>;
|
|
51
|
-
relations: Array<{ from: string; to: string; relationType: string }>;
|
|
52
|
-
}> {
|
|
53
|
-
const filePath = getGraphFilePath(projectDir);
|
|
54
|
-
try {
|
|
55
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
56
|
-
const lines = data.split('\n').filter((line) => line.trim() !== '');
|
|
57
|
-
return lines.reduce(
|
|
58
|
-
(graph, line) => {
|
|
59
|
-
const item = JSON.parse(line);
|
|
60
|
-
if (item.type === 'entity') {
|
|
61
|
-
graph.entities.push({
|
|
62
|
-
name: item.name,
|
|
63
|
-
entityType: item.entityType,
|
|
64
|
-
observations: item.observations,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
if (item.type === 'relation') {
|
|
68
|
-
graph.relations.push({
|
|
69
|
-
from: item.from,
|
|
70
|
-
to: item.to,
|
|
71
|
-
relationType: item.relationType,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return graph;
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
entities: [] as Array<{ name: string; entityType: string; observations: string[] }>,
|
|
78
|
-
relations: [] as Array<{ from: string; to: string; relationType: string }>
|
|
79
|
-
},
|
|
80
|
-
);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
83
|
-
return { entities: [], relations: [] };
|
|
84
|
-
}
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Save observation data as JSON (for Orama restore / export).
|
|
91
|
-
*/
|
|
92
|
-
export async function saveObservationsJson(
|
|
93
|
-
projectDir: string,
|
|
94
|
-
observations: unknown[],
|
|
95
|
-
): Promise<void> {
|
|
96
|
-
const filePath = path.join(projectDir, 'observations.json');
|
|
97
|
-
await atomicWriteFile(filePath, JSON.stringify(observations, null, 2));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Load observation data from JSON.
|
|
102
|
-
*/
|
|
103
|
-
export async function loadObservationsJson(projectDir: string): Promise<unknown[]> {
|
|
104
|
-
const filePath = path.join(projectDir, 'observations.json');
|
|
105
|
-
try {
|
|
106
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
107
|
-
return JSON.parse(data);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Save the next observation ID counter (legacy JSON format).
|
|
118
|
-
*/
|
|
119
|
-
export async function saveIdCounter(projectDir: string, nextId: number): Promise<void> {
|
|
120
|
-
const filePath = path.join(projectDir, 'counter.json');
|
|
121
|
-
await atomicWriteFile(filePath, JSON.stringify({ nextId }));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Load the next observation ID counter (legacy JSON format).
|
|
126
|
-
* For runtime use, prefer the SQLite meta table via SqliteBackend.
|
|
127
|
-
*/
|
|
128
|
-
export async function loadIdCounter(projectDir: string): Promise<number> {
|
|
129
|
-
const filePath = path.join(projectDir, 'counter.json');
|
|
130
|
-
try {
|
|
131
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
132
|
-
return JSON.parse(data).nextId ?? 1;
|
|
133
|
-
} catch {
|
|
134
|
-
return 1;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Save mini-skills data as JSON (migration source only).
|
|
140
|
-
*/
|
|
141
|
-
export async function saveMiniSkillsJson(
|
|
142
|
-
projectDir: string,
|
|
143
|
-
skills: unknown[],
|
|
144
|
-
): Promise<void> {
|
|
145
|
-
const filePath = path.join(projectDir, 'mini-skills.json');
|
|
146
|
-
await atomicWriteFile(filePath, JSON.stringify(skills, null, 2));
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Load mini-skills data from JSON (migration source only).
|
|
151
|
-
*/
|
|
152
|
-
export async function loadMiniSkillsJson(projectDir: string): Promise<unknown[]> {
|
|
153
|
-
const filePath = path.join(projectDir, 'mini-skills.json');
|
|
154
|
-
try {
|
|
155
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
156
|
-
const parsed = JSON.parse(data);
|
|
157
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
158
|
-
} catch (error) {
|
|
159
|
-
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
160
|
-
return [];
|
|
161
|
-
}
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Load the mini-skills ID counter (legacy JSON format).
|
|
168
|
-
*/
|
|
169
|
-
export async function loadMiniSkillsCounter(projectDir: string): Promise<number> {
|
|
170
|
-
const filePath = path.join(projectDir, 'mini-skills-counter.json');
|
|
171
|
-
try {
|
|
172
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
173
|
-
return JSON.parse(data).nextId ?? 1;
|
|
174
|
-
} catch {
|
|
175
|
-
return 1;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Save the mini-skills ID counter (legacy JSON format).
|
|
181
|
-
*/
|
|
182
|
-
export async function saveMiniSkillsCounter(projectDir: string, nextId: number): Promise<void> {
|
|
183
|
-
const filePath = path.join(projectDir, 'mini-skills-counter.json');
|
|
184
|
-
await atomicWriteFile(filePath, JSON.stringify({ nextId }));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Save sessions data as JSON (migration source only).
|
|
189
|
-
*/
|
|
190
|
-
export async function saveSessionsJson(
|
|
191
|
-
projectDir: string,
|
|
192
|
-
sessions: unknown[],
|
|
193
|
-
): Promise<void> {
|
|
194
|
-
const filePath = path.join(projectDir, 'sessions.json');
|
|
195
|
-
await atomicWriteFile(filePath, JSON.stringify(sessions, null, 2));
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Load sessions data from JSON (migration source only).
|
|
200
|
-
*/
|
|
201
|
-
export async function loadSessionsJson(projectDir: string): Promise<unknown[]> {
|
|
202
|
-
const filePath = path.join(projectDir, 'sessions.json');
|
|
203
|
-
try {
|
|
204
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
205
|
-
return JSON.parse(data);
|
|
206
|
-
} catch (error) {
|
|
207
|
-
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
208
|
-
return [];
|
|
209
|
-
}
|
|
210
|
-
throw error;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* JSON Persistence Helpers — Migration / Export / Debug Only
|
|
3
|
+
*
|
|
4
|
+
* These functions read/write JSON/JSONL files for one-time migration
|
|
5
|
+
* from legacy storage formats into SQLite, or for export/import and debug.
|
|
6
|
+
*
|
|
7
|
+
* NOT used as runtime canonical store — SQLite is the sole canonical backend.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { promises as fs } from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { atomicWriteFile } from './file-lock.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the file path for the knowledge graph JSONL file.
|
|
16
|
+
* (MCP-compatible format, same as official Memory Server)
|
|
17
|
+
*/
|
|
18
|
+
export function getGraphFilePath(projectDir: string): string {
|
|
19
|
+
return path.join(projectDir, 'graph.jsonl');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Save the knowledge graph in JSONL format (MCP-compatible).
|
|
24
|
+
* Each line is a JSON object with type: "entity" or "relation".
|
|
25
|
+
*
|
|
26
|
+
* Format adopted from MCP Official Memory Server.
|
|
27
|
+
*/
|
|
28
|
+
export async function saveGraphJsonl(
|
|
29
|
+
projectDir: string,
|
|
30
|
+
entities: Array<{ name: string; entityType: string; observations: string[] }>,
|
|
31
|
+
relations: Array<{ from: string; to: string; relationType: string }>,
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
const lines = [
|
|
34
|
+
...entities.map((e) =>
|
|
35
|
+
JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations }),
|
|
36
|
+
),
|
|
37
|
+
...relations.map((r) =>
|
|
38
|
+
JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType }),
|
|
39
|
+
),
|
|
40
|
+
];
|
|
41
|
+
await atomicWriteFile(getGraphFilePath(projectDir), lines.join('\n'));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Load the knowledge graph from JSONL format.
|
|
46
|
+
*/
|
|
47
|
+
export async function loadGraphJsonl(
|
|
48
|
+
projectDir: string,
|
|
49
|
+
): Promise<{
|
|
50
|
+
entities: Array<{ name: string; entityType: string; observations: string[] }>;
|
|
51
|
+
relations: Array<{ from: string; to: string; relationType: string }>;
|
|
52
|
+
}> {
|
|
53
|
+
const filePath = getGraphFilePath(projectDir);
|
|
54
|
+
try {
|
|
55
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
56
|
+
const lines = data.split('\n').filter((line) => line.trim() !== '');
|
|
57
|
+
return lines.reduce(
|
|
58
|
+
(graph, line) => {
|
|
59
|
+
const item = JSON.parse(line);
|
|
60
|
+
if (item.type === 'entity') {
|
|
61
|
+
graph.entities.push({
|
|
62
|
+
name: item.name,
|
|
63
|
+
entityType: item.entityType,
|
|
64
|
+
observations: item.observations,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (item.type === 'relation') {
|
|
68
|
+
graph.relations.push({
|
|
69
|
+
from: item.from,
|
|
70
|
+
to: item.to,
|
|
71
|
+
relationType: item.relationType,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return graph;
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
entities: [] as Array<{ name: string; entityType: string; observations: string[] }>,
|
|
78
|
+
relations: [] as Array<{ from: string; to: string; relationType: string }>
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
83
|
+
return { entities: [], relations: [] };
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Save observation data as JSON (for Orama restore / export).
|
|
91
|
+
*/
|
|
92
|
+
export async function saveObservationsJson(
|
|
93
|
+
projectDir: string,
|
|
94
|
+
observations: unknown[],
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
const filePath = path.join(projectDir, 'observations.json');
|
|
97
|
+
await atomicWriteFile(filePath, JSON.stringify(observations, null, 2));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Load observation data from JSON.
|
|
102
|
+
*/
|
|
103
|
+
export async function loadObservationsJson(projectDir: string): Promise<unknown[]> {
|
|
104
|
+
const filePath = path.join(projectDir, 'observations.json');
|
|
105
|
+
try {
|
|
106
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
107
|
+
return JSON.parse(data);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Save the next observation ID counter (legacy JSON format).
|
|
118
|
+
*/
|
|
119
|
+
export async function saveIdCounter(projectDir: string, nextId: number): Promise<void> {
|
|
120
|
+
const filePath = path.join(projectDir, 'counter.json');
|
|
121
|
+
await atomicWriteFile(filePath, JSON.stringify({ nextId }));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Load the next observation ID counter (legacy JSON format).
|
|
126
|
+
* For runtime use, prefer the SQLite meta table via SqliteBackend.
|
|
127
|
+
*/
|
|
128
|
+
export async function loadIdCounter(projectDir: string): Promise<number> {
|
|
129
|
+
const filePath = path.join(projectDir, 'counter.json');
|
|
130
|
+
try {
|
|
131
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
132
|
+
return JSON.parse(data).nextId ?? 1;
|
|
133
|
+
} catch {
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Save mini-skills data as JSON (migration source only).
|
|
140
|
+
*/
|
|
141
|
+
export async function saveMiniSkillsJson(
|
|
142
|
+
projectDir: string,
|
|
143
|
+
skills: unknown[],
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
const filePath = path.join(projectDir, 'mini-skills.json');
|
|
146
|
+
await atomicWriteFile(filePath, JSON.stringify(skills, null, 2));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Load mini-skills data from JSON (migration source only).
|
|
151
|
+
*/
|
|
152
|
+
export async function loadMiniSkillsJson(projectDir: string): Promise<unknown[]> {
|
|
153
|
+
const filePath = path.join(projectDir, 'mini-skills.json');
|
|
154
|
+
try {
|
|
155
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
156
|
+
const parsed = JSON.parse(data);
|
|
157
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Load the mini-skills ID counter (legacy JSON format).
|
|
168
|
+
*/
|
|
169
|
+
export async function loadMiniSkillsCounter(projectDir: string): Promise<number> {
|
|
170
|
+
const filePath = path.join(projectDir, 'mini-skills-counter.json');
|
|
171
|
+
try {
|
|
172
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
173
|
+
return JSON.parse(data).nextId ?? 1;
|
|
174
|
+
} catch {
|
|
175
|
+
return 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Save the mini-skills ID counter (legacy JSON format).
|
|
181
|
+
*/
|
|
182
|
+
export async function saveMiniSkillsCounter(projectDir: string, nextId: number): Promise<void> {
|
|
183
|
+
const filePath = path.join(projectDir, 'mini-skills-counter.json');
|
|
184
|
+
await atomicWriteFile(filePath, JSON.stringify({ nextId }));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Save sessions data as JSON (migration source only).
|
|
189
|
+
*/
|
|
190
|
+
export async function saveSessionsJson(
|
|
191
|
+
projectDir: string,
|
|
192
|
+
sessions: unknown[],
|
|
193
|
+
): Promise<void> {
|
|
194
|
+
const filePath = path.join(projectDir, 'sessions.json');
|
|
195
|
+
await atomicWriteFile(filePath, JSON.stringify(sessions, null, 2));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Load sessions data from JSON (migration source only).
|
|
200
|
+
*/
|
|
201
|
+
export async function loadSessionsJson(projectDir: string): Promise<unknown[]> {
|
|
202
|
+
const filePath = path.join(projectDir, 'sessions.json');
|
|
203
|
+
try {
|
|
204
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
205
|
+
return JSON.parse(data);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|