memorix 1.5.1 → 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.
Files changed (122) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +3 -3
  3. package/README.zh-CN.md +3 -3
  4. package/TEAM.md +86 -86
  5. package/dist/cli/index.js +243 -42
  6. package/dist/cli/memcode.js +0 -0
  7. package/dist/index.js +167 -20
  8. package/dist/maintenance-runner.js +5 -4
  9. package/dist/media-audio-runner.js +5 -4
  10. package/dist/media-video-runner.js +5 -4
  11. package/dist/memcode-runtime/CHANGELOG.md +23 -0
  12. package/dist/sdk.js +166 -19
  13. package/dist/vector-backfill-runner.js +5 -4
  14. package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
  15. package/docs/API_REFERENCE.md +1 -1
  16. package/docs/DESIGN_DECISIONS.md +357 -357
  17. package/docs/DEVELOPMENT.md +5 -3
  18. package/package.json +1 -1
  19. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  20. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  21. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  22. package/plugins/copilot/memorix/plugin.json +1 -1
  23. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  24. package/plugins/omp/memorix/package.json +1 -1
  25. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  26. package/plugins/pi/memorix/package.json +1 -1
  27. package/server.json +2 -2
  28. package/src/audit/index.ts +156 -156
  29. package/src/cli/commands/codegraph.ts +48 -5
  30. package/src/cli/commands/context.ts +20 -4
  31. package/src/cli/commands/formation.ts +48 -48
  32. package/src/cli/commands/git-hook-install.ts +111 -111
  33. package/src/cli/commands/handoff.ts +54 -54
  34. package/src/cli/commands/hooks-status.ts +63 -63
  35. package/src/cli/commands/ingest.ts +44 -44
  36. package/src/cli/commands/integrate-shared.ts +15 -15
  37. package/src/cli/commands/lock.ts +82 -82
  38. package/src/cli/commands/message.ts +104 -104
  39. package/src/cli/commands/poll.ts +58 -58
  40. package/src/cli/commands/reasoning.ts +118 -118
  41. package/src/cli/commands/resume.ts +4 -0
  42. package/src/cli/commands/skills.ts +114 -114
  43. package/src/cli/commands/task.ts +167 -167
  44. package/src/cli/commands/transfer.ts +47 -47
  45. package/src/cli/index.ts +406 -406
  46. package/src/cli/tui/ChatView.tsx +234 -234
  47. package/src/cli/tui/CommandBar.tsx +312 -312
  48. package/src/cli/tui/ContextRail.tsx +118 -118
  49. package/src/cli/tui/HeaderBar.tsx +72 -72
  50. package/src/cli/tui/LogoBanner.tsx +51 -51
  51. package/src/cli/tui/index.ts +41 -41
  52. package/src/cli/version.ts +7 -7
  53. package/src/cli/workbench.ts +1 -1
  54. package/src/codegraph/auto-context.ts +4 -1
  55. package/src/codegraph/context-pack.ts +3 -1
  56. package/src/codegraph/external-provider.ts +93 -0
  57. package/src/dashboard/project-classification.ts +64 -64
  58. package/src/git/hooks-path.ts +85 -85
  59. package/src/hooks/installers/index.ts +1 -1
  60. package/src/hooks/official-skills.ts +3 -3
  61. package/src/hooks/pattern-detector.ts +173 -173
  62. package/src/hooks/rules/memorix-agent-rules.md +1 -1
  63. package/src/hooks/significance-filter.ts +250 -250
  64. package/src/knowledge/context-receipt.ts +41 -0
  65. package/src/knowledge/workflows.ts +6 -3
  66. package/src/knowledge/workset.ts +56 -2
  67. package/src/llm/memory-manager.ts +328 -328
  68. package/src/llm/quality.ts +248 -248
  69. package/src/memory/attribution-guard.ts +249 -249
  70. package/src/memory/disclosure-policy.ts +135 -135
  71. package/src/memory/entity-extractor.ts +197 -197
  72. package/src/memory/formation/evaluate.ts +217 -217
  73. package/src/memory/freshness.ts +122 -122
  74. package/src/memory/graph.ts +197 -197
  75. package/src/memory/refs.ts +94 -94
  76. package/src/memory/secret-filter.ts +79 -79
  77. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  78. package/src/orchestrate/adapters/claude.ts +111 -111
  79. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  80. package/src/orchestrate/adapters/codex.ts +41 -41
  81. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  82. package/src/orchestrate/adapters/gemini.ts +42 -42
  83. package/src/orchestrate/adapters/index.ts +73 -73
  84. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  85. package/src/orchestrate/adapters/opencode.ts +47 -47
  86. package/src/orchestrate/adapters/types.ts +77 -77
  87. package/src/orchestrate/capability-router.ts +284 -284
  88. package/src/orchestrate/cost-tracker.ts +219 -219
  89. package/src/orchestrate/error-recovery.ts +191 -191
  90. package/src/orchestrate/evidence.ts +140 -140
  91. package/src/orchestrate/ledger.ts +110 -110
  92. package/src/orchestrate/memorix-bridge.ts +343 -343
  93. package/src/orchestrate/output-budget.ts +80 -80
  94. package/src/orchestrate/permission.ts +152 -152
  95. package/src/orchestrate/pipeline-trace.ts +131 -131
  96. package/src/orchestrate/prompt-builder.ts +155 -155
  97. package/src/orchestrate/ring-buffer.ts +37 -37
  98. package/src/orchestrate/task-graph.ts +389 -389
  99. package/src/project/aliases.ts +374 -374
  100. package/src/rules/adapters/trae.ts +56 -56
  101. package/src/rules/syncer.ts +235 -235
  102. package/src/search/query-expansion.ts +52 -52
  103. package/src/server/formation-timeout.ts +27 -27
  104. package/src/server.ts +15 -3
  105. package/src/skills/mini-skills.ts +386 -386
  106. package/src/store/chat-store.ts +119 -119
  107. package/src/store/graph-store.ts +249 -249
  108. package/src/store/mini-skill-store.ts +349 -349
  109. package/src/store/persistence-json.ts +212 -212
  110. package/src/store/persistence.ts +291 -291
  111. package/src/store/project-affinity.ts +195 -195
  112. package/src/team/event-bus.ts +76 -76
  113. package/src/team/handoff.ts +161 -161
  114. package/src/team/poll.ts +132 -132
  115. package/src/workspace/mcp-adapters/codex.ts +191 -191
  116. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  117. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  118. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  119. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  120. package/src/workspace/mcp-adapters/trae.ts +134 -134
  121. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  122. package/src/workspace/sanitizer.ts +60 -60
@@ -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
+ }