memorix 1.4.3 → 1.4.5

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 (158) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +20 -6
  3. package/README.zh-CN.md +16 -3
  4. package/TEAM.md +86 -86
  5. package/assets/star-history-dark.svg +8 -8
  6. package/assets/star-history-light.svg +8 -8
  7. package/assets/star-history.json +16 -2
  8. package/dist/cli/index.js +539 -233
  9. package/dist/cli/memcode.js +0 -0
  10. package/dist/index.js +72 -15
  11. package/dist/maintenance-runner.js +9 -7
  12. package/dist/media-audio-runner.js +9 -7
  13. package/dist/media-video-runner.js +9 -7
  14. package/dist/memcode/index.js +9 -7
  15. package/dist/memcode-runtime/CHANGELOG.md +34 -0
  16. package/dist/sdk.js +71 -14
  17. package/dist/types.d.ts +1 -1
  18. package/dist/vector-backfill-runner.js +9 -7
  19. package/docs/AGENT_OPERATOR_PLAYBOOK.md +6 -5
  20. package/docs/API_REFERENCE.md +9 -5
  21. package/docs/CONFIGURATION.md +15 -5
  22. package/docs/DESIGN_DECISIONS.md +357 -357
  23. package/docs/DEVELOPMENT.md +2 -2
  24. package/docs/INTEGRATIONS.md +9 -2
  25. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +4 -3
  26. package/docs/MEMCODE.md +1 -1
  27. package/docs/MODULES.md +1 -1
  28. package/docs/README.md +1 -1
  29. package/docs/SETUP.md +12 -4
  30. package/docs/hooks-architecture.md +2 -1
  31. package/llms-full.txt +7 -6
  32. package/llms.txt +2 -2
  33. package/package.json +1 -1
  34. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  35. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  36. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  37. package/plugins/copilot/memorix/plugin.json +1 -1
  38. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  39. package/plugins/omp/memorix/package.json +1 -1
  40. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  41. package/plugins/pi/memorix/package.json +1 -1
  42. package/server.json +2 -2
  43. package/src/audit/index.ts +156 -156
  44. package/src/cli/commands/agent-integrations.ts +7 -1
  45. package/src/cli/commands/audit-list.ts +89 -89
  46. package/src/cli/commands/formation.ts +48 -48
  47. package/src/cli/commands/git-hook-install.ts +111 -111
  48. package/src/cli/commands/handoff.ts +54 -54
  49. package/src/cli/commands/hooks-install.ts +2 -0
  50. package/src/cli/commands/hooks-preview.ts +5 -0
  51. package/src/cli/commands/hooks-status.ts +63 -63
  52. package/src/cli/commands/ingest.ts +44 -44
  53. package/src/cli/commands/integrate-shared.ts +15 -15
  54. package/src/cli/commands/integrate.ts +2 -0
  55. package/src/cli/commands/lock.ts +82 -82
  56. package/src/cli/commands/media-image.ts +27 -0
  57. package/src/cli/commands/media.ts +8 -1
  58. package/src/cli/commands/memory.ts +44 -34
  59. package/src/cli/commands/message.ts +104 -104
  60. package/src/cli/commands/operator-shared.ts +62 -18
  61. package/src/cli/commands/poll.ts +58 -58
  62. package/src/cli/commands/purge-all-memory.ts +85 -85
  63. package/src/cli/commands/purge-project-memory.ts +83 -83
  64. package/src/cli/commands/reasoning.ts +118 -118
  65. package/src/cli/commands/setup.ts +57 -2
  66. package/src/cli/commands/skills.ts +114 -114
  67. package/src/cli/commands/task.ts +167 -167
  68. package/src/cli/commands/transfer.ts +47 -47
  69. package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
  70. package/src/cli/commands/uninstall.ts +20 -0
  71. package/src/cli/tui/ChatView.tsx +234 -234
  72. package/src/cli/tui/CommandBar.tsx +312 -312
  73. package/src/cli/tui/ContextRail.tsx +118 -118
  74. package/src/cli/tui/HeaderBar.tsx +72 -72
  75. package/src/cli/tui/LogoBanner.tsx +51 -51
  76. package/src/cli/tui/Sidebar.tsx +179 -179
  77. package/src/cli/tui/index.ts +41 -41
  78. package/src/cli/tui/markdown-render.tsx +371 -371
  79. package/src/cli/tui/use-mouse.ts +157 -157
  80. package/src/cli/tui/useNavigation.ts +56 -56
  81. package/src/cli/version.ts +7 -7
  82. package/src/cli/workbench.ts +1 -1
  83. package/src/dashboard/project-classification.ts +64 -64
  84. package/src/git/hooks-path.ts +85 -85
  85. package/src/hooks/installers/index.ts +43 -2
  86. package/src/hooks/pattern-detector.ts +173 -173
  87. package/src/hooks/significance-filter.ts +250 -250
  88. package/src/hooks/types.ts +2 -0
  89. package/src/integrations/registry.ts +9 -0
  90. package/src/llm/memory-manager.ts +328 -328
  91. package/src/llm/provider.ts +885 -885
  92. package/src/llm/quality.ts +248 -248
  93. package/src/media/minimax.ts +9 -1
  94. package/src/memory/attribution-guard.ts +249 -249
  95. package/src/memory/disclosure-policy.ts +135 -135
  96. package/src/memory/entity-extractor.ts +197 -197
  97. package/src/memory/formation/evaluate.ts +217 -217
  98. package/src/memory/formation/extract.ts +361 -361
  99. package/src/memory/formation/index.ts +417 -417
  100. package/src/memory/formation/resolve.ts +344 -344
  101. package/src/memory/formation/types.ts +315 -315
  102. package/src/memory/freshness.ts +122 -122
  103. package/src/memory/graph.ts +197 -197
  104. package/src/memory/refs.ts +94 -94
  105. package/src/memory/secret-filter.ts +79 -79
  106. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  107. package/src/orchestrate/adapters/claude.ts +111 -111
  108. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  109. package/src/orchestrate/adapters/codex.ts +41 -41
  110. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  111. package/src/orchestrate/adapters/gemini.ts +42 -42
  112. package/src/orchestrate/adapters/index.ts +73 -73
  113. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  114. package/src/orchestrate/adapters/opencode.ts +47 -47
  115. package/src/orchestrate/adapters/types.ts +77 -77
  116. package/src/orchestrate/capability-router.ts +284 -284
  117. package/src/orchestrate/context-compact.ts +188 -188
  118. package/src/orchestrate/cost-tracker.ts +219 -219
  119. package/src/orchestrate/error-recovery.ts +191 -191
  120. package/src/orchestrate/evidence.ts +140 -140
  121. package/src/orchestrate/ledger.ts +110 -110
  122. package/src/orchestrate/memorix-bridge.ts +343 -343
  123. package/src/orchestrate/output-budget.ts +80 -80
  124. package/src/orchestrate/permission.ts +152 -152
  125. package/src/orchestrate/pipeline-trace.ts +131 -131
  126. package/src/orchestrate/prompt-builder.ts +155 -155
  127. package/src/orchestrate/ring-buffer.ts +37 -37
  128. package/src/orchestrate/task-graph.ts +389 -389
  129. package/src/project/aliases.ts +374 -374
  130. package/src/rules/adapters/trae.ts +56 -56
  131. package/src/rules/syncer.ts +235 -235
  132. package/src/search/query-expansion.ts +52 -52
  133. package/src/server/formation-timeout.ts +27 -27
  134. package/src/server.ts +23 -1
  135. package/src/skills/mini-skills.ts +386 -386
  136. package/src/store/chat-store.ts +119 -119
  137. package/src/store/graph-store.ts +249 -249
  138. package/src/store/mini-skill-store.ts +349 -349
  139. package/src/store/persistence-json.ts +212 -212
  140. package/src/store/persistence.ts +291 -291
  141. package/src/store/project-affinity.ts +195 -195
  142. package/src/team/event-bus.ts +76 -76
  143. package/src/team/file-locks.ts +173 -173
  144. package/src/team/handoff.ts +161 -161
  145. package/src/team/messages.ts +203 -203
  146. package/src/team/poll.ts +132 -132
  147. package/src/team/tasks.ts +211 -211
  148. package/src/types.ts +1 -1
  149. package/src/workspace/mcp-adapters/codex.ts +191 -191
  150. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  151. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  152. package/src/workspace/mcp-adapters/dsh.ts +147 -0
  153. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  154. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  155. package/src/workspace/mcp-adapters/trae.ts +134 -134
  156. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  157. package/src/workspace/sanitizer.ts +60 -60
  158. package/dist/memcode-runtime/docs/images/exy.png +0 -0
@@ -1,156 +1,156 @@
1
- /**
2
- * Audit Module - Track Memorix-written files
3
- *
4
- * Records all files written by Memorix to distinguish them from
5
- * project-native files. Provides audit trail for cleanup and rollback.
6
- */
7
-
8
- import * as fs from 'node:fs/promises';
9
- import * as path from 'node:path';
10
- import { homedir } from 'node:os';
11
-
12
- function getAuditFilePath(): string {
13
- return process.env.MEMORIX_AUDIT_FILE || path.join(homedir(), '.memorix', 'audit.json');
14
- }
15
-
16
- export interface AuditEntry {
17
- type: 'hook' | 'rule' | 'other';
18
- agent?: string;
19
- path: string;
20
- createdAt: string;
21
- }
22
-
23
- export interface ProjectAudit {
24
- projectRoot: string;
25
- installedAt: string;
26
- entries: AuditEntry[];
27
- }
28
-
29
- export interface AuditData {
30
- version: string;
31
- projects: Record<string, ProjectAudit>;
32
- }
33
-
34
- /**
35
- * Load audit data from disk.
36
- */
37
- export async function loadAudit(): Promise<AuditData> {
38
- try {
39
- const content = await fs.readFile(getAuditFilePath(), 'utf-8');
40
- return JSON.parse(content) as AuditData;
41
- } catch {
42
- // No audit file yet
43
- return {
44
- version: '1.0.0',
45
- projects: {},
46
- };
47
- }
48
- }
49
-
50
- /**
51
- * Save audit data to disk.
52
- */
53
- export async function saveAudit(data: AuditData): Promise<void> {
54
- const auditFile = getAuditFilePath();
55
- const dir = path.dirname(auditFile);
56
- await fs.mkdir(dir, { recursive: true });
57
- await fs.writeFile(auditFile, JSON.stringify(data, null, 2), 'utf-8');
58
- }
59
-
60
- /**
61
- * Get project ID from project root via .git detection.
62
- */
63
- export function getProjectId(projectRoot: string): string {
64
- try {
65
- const { detectProject } = require('../project/detector.js');
66
- const project = detectProject(projectRoot);
67
- if (project) return project.id;
68
- } catch { /* fallback below */ }
69
- const normalized = projectRoot.replace(/\\/g, '/');
70
- return `untracked/${normalized}`;
71
- }
72
-
73
- /**
74
- * Record a file written by Memorix.
75
- */
76
- export async function recordFile(
77
- projectRoot: string,
78
- type: AuditEntry['type'],
79
- filePath: string,
80
- agent?: string,
81
- ): Promise<void> {
82
- const data = await loadAudit();
83
- const projectId = getProjectId(projectRoot);
84
-
85
- if (!data.projects[projectId]) {
86
- data.projects[projectId] = {
87
- projectRoot,
88
- installedAt: new Date().toISOString(),
89
- entries: [],
90
- };
91
- }
92
-
93
- // Check if entry already exists
94
- const existingIndex = data.projects[projectId].entries.findIndex(
95
- (e) => e.path === filePath
96
- );
97
-
98
- if (existingIndex === -1) {
99
- data.projects[projectId].entries.push({
100
- type,
101
- agent,
102
- path: filePath,
103
- createdAt: new Date().toISOString(),
104
- });
105
- }
106
-
107
- await saveAudit(data);
108
- }
109
-
110
- /**
111
- * Get all files written by Memorix for a project.
112
- */
113
- export async function getProjectFiles(projectRoot: string): Promise<AuditEntry[]> {
114
- const data = await loadAudit();
115
- const projectId = getProjectId(projectRoot);
116
- return data.projects[projectId]?.entries || [];
117
- }
118
-
119
- /**
120
- * Remove a file from audit (when uninstalled).
121
- */
122
- export async function removeFile(projectRoot: string, filePath: string): Promise<void> {
123
- const data = await loadAudit();
124
- const projectId = getProjectId(projectRoot);
125
-
126
- if (!data.projects[projectId]) return;
127
-
128
- data.projects[projectId].entries = data.projects[projectId].entries.filter(
129
- (e) => e.path !== filePath
130
- );
131
-
132
- // If no entries left, remove the project
133
- if (data.projects[projectId].entries.length === 0) {
134
- delete data.projects[projectId];
135
- }
136
-
137
- await saveAudit(data);
138
- }
139
-
140
- /**
141
- * Get all audit entries across all projects.
142
- */
143
- export async function getAllAuditEntries(): Promise<
144
- Array<{ projectId: string; entry: AuditEntry }>
145
- > {
146
- const data = await loadAudit();
147
- const entries: Array<{ projectId: string; entry: AuditEntry }> = [];
148
-
149
- for (const [projectId, project] of Object.entries(data.projects)) {
150
- for (const entry of project.entries) {
151
- entries.push({ projectId, entry });
152
- }
153
- }
154
-
155
- return entries;
156
- }
1
+ /**
2
+ * Audit Module - Track Memorix-written files
3
+ *
4
+ * Records all files written by Memorix to distinguish them from
5
+ * project-native files. Provides audit trail for cleanup and rollback.
6
+ */
7
+
8
+ import * as fs from 'node:fs/promises';
9
+ import * as path from 'node:path';
10
+ import { homedir } from 'node:os';
11
+
12
+ function getAuditFilePath(): string {
13
+ return process.env.MEMORIX_AUDIT_FILE || path.join(homedir(), '.memorix', 'audit.json');
14
+ }
15
+
16
+ export interface AuditEntry {
17
+ type: 'hook' | 'rule' | 'other';
18
+ agent?: string;
19
+ path: string;
20
+ createdAt: string;
21
+ }
22
+
23
+ export interface ProjectAudit {
24
+ projectRoot: string;
25
+ installedAt: string;
26
+ entries: AuditEntry[];
27
+ }
28
+
29
+ export interface AuditData {
30
+ version: string;
31
+ projects: Record<string, ProjectAudit>;
32
+ }
33
+
34
+ /**
35
+ * Load audit data from disk.
36
+ */
37
+ export async function loadAudit(): Promise<AuditData> {
38
+ try {
39
+ const content = await fs.readFile(getAuditFilePath(), 'utf-8');
40
+ return JSON.parse(content) as AuditData;
41
+ } catch {
42
+ // No audit file yet
43
+ return {
44
+ version: '1.0.0',
45
+ projects: {},
46
+ };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Save audit data to disk.
52
+ */
53
+ export async function saveAudit(data: AuditData): Promise<void> {
54
+ const auditFile = getAuditFilePath();
55
+ const dir = path.dirname(auditFile);
56
+ await fs.mkdir(dir, { recursive: true });
57
+ await fs.writeFile(auditFile, JSON.stringify(data, null, 2), 'utf-8');
58
+ }
59
+
60
+ /**
61
+ * Get project ID from project root via .git detection.
62
+ */
63
+ export function getProjectId(projectRoot: string): string {
64
+ try {
65
+ const { detectProject } = require('../project/detector.js');
66
+ const project = detectProject(projectRoot);
67
+ if (project) return project.id;
68
+ } catch { /* fallback below */ }
69
+ const normalized = projectRoot.replace(/\\/g, '/');
70
+ return `untracked/${normalized}`;
71
+ }
72
+
73
+ /**
74
+ * Record a file written by Memorix.
75
+ */
76
+ export async function recordFile(
77
+ projectRoot: string,
78
+ type: AuditEntry['type'],
79
+ filePath: string,
80
+ agent?: string,
81
+ ): Promise<void> {
82
+ const data = await loadAudit();
83
+ const projectId = getProjectId(projectRoot);
84
+
85
+ if (!data.projects[projectId]) {
86
+ data.projects[projectId] = {
87
+ projectRoot,
88
+ installedAt: new Date().toISOString(),
89
+ entries: [],
90
+ };
91
+ }
92
+
93
+ // Check if entry already exists
94
+ const existingIndex = data.projects[projectId].entries.findIndex(
95
+ (e) => e.path === filePath
96
+ );
97
+
98
+ if (existingIndex === -1) {
99
+ data.projects[projectId].entries.push({
100
+ type,
101
+ agent,
102
+ path: filePath,
103
+ createdAt: new Date().toISOString(),
104
+ });
105
+ }
106
+
107
+ await saveAudit(data);
108
+ }
109
+
110
+ /**
111
+ * Get all files written by Memorix for a project.
112
+ */
113
+ export async function getProjectFiles(projectRoot: string): Promise<AuditEntry[]> {
114
+ const data = await loadAudit();
115
+ const projectId = getProjectId(projectRoot);
116
+ return data.projects[projectId]?.entries || [];
117
+ }
118
+
119
+ /**
120
+ * Remove a file from audit (when uninstalled).
121
+ */
122
+ export async function removeFile(projectRoot: string, filePath: string): Promise<void> {
123
+ const data = await loadAudit();
124
+ const projectId = getProjectId(projectRoot);
125
+
126
+ if (!data.projects[projectId]) return;
127
+
128
+ data.projects[projectId].entries = data.projects[projectId].entries.filter(
129
+ (e) => e.path !== filePath
130
+ );
131
+
132
+ // If no entries left, remove the project
133
+ if (data.projects[projectId].entries.length === 0) {
134
+ delete data.projects[projectId];
135
+ }
136
+
137
+ await saveAudit(data);
138
+ }
139
+
140
+ /**
141
+ * Get all audit entries across all projects.
142
+ */
143
+ export async function getAllAuditEntries(): Promise<
144
+ Array<{ projectId: string; entry: AuditEntry }>
145
+ > {
146
+ const data = await loadAudit();
147
+ const entries: Array<{ projectId: string; entry: AuditEntry }> = [];
148
+
149
+ for (const [projectId, project] of Object.entries(data.projects)) {
150
+ for (const entry of project.entries) {
151
+ entries.push({ projectId, entry });
152
+ }
153
+ }
154
+
155
+ return entries;
156
+ }
@@ -124,6 +124,7 @@ const GUIDANCE_AGENTS = new Set<AgentName>([
124
124
  'kiro',
125
125
  'opencode',
126
126
  'trae',
127
+ 'dsh',
127
128
  ]);
128
129
 
129
130
  const CODEX_PLUGIN_NAME = 'memorix';
@@ -787,7 +788,12 @@ async function inspectMcp(agent: AgentName, projectRoot: string, scope: AgentInt
787
788
  }
788
789
 
789
790
  const configPath = adapter.getConfigPath(targetScope === 'project' ? projectRoot : undefined);
790
- if (targetScope === 'global' && configPath === adapter.getConfigPath(projectRoot)) continue;
791
+ if (targetScope === 'global' && configPath === adapter.getConfigPath(projectRoot) && scope === 'all') {
792
+ // User-level-only adapters (Trae, DSH) resolve one path for every
793
+ // scope. Deduplicate only when the project iteration also runs;
794
+ // an explicit global-only scope must still inspect the shared path.
795
+ continue;
796
+ }
791
797
 
792
798
  if (!existsSync(configPath)) {
793
799
  checks.push({
@@ -1,89 +1,89 @@
1
- /**
2
- * CLI Command: memorix audit list
3
- *
4
- * List all files written by Memorix (audit trail).
5
- */
6
-
7
- import { defineCommand } from 'citty';
8
- import * as p from '@clack/prompts';
9
-
10
- export default defineCommand({
11
- meta: {
12
- name: 'list',
13
- description: 'List Memorix-written files (audit trail)',
14
- },
15
- args: {
16
- project: {
17
- type: 'string',
18
- description: 'Filter by project (optional)',
19
- required: false,
20
- },
21
- },
22
- run: async ({ args }) => {
23
- const { getAllAuditEntries, getProjectId } = await import('../../audit/index.js');
24
- const os = await import('node:os');
25
- let cwd: string;
26
- try {
27
- cwd = process.cwd();
28
- } catch {
29
- cwd = os.homedir();
30
- console.log(`[WARN] Could not access current directory, using home: ${cwd}`);
31
- }
32
-
33
- p.intro('Memorix Audit Trail');
34
-
35
- const allEntries = await getAllAuditEntries();
36
-
37
- if (allEntries.length === 0) {
38
- console.log('No Memorix-written files found.');
39
- p.outro('Audit trail is empty.');
40
- return;
41
- }
42
-
43
- // Filter by project if specified
44
- let entries = allEntries;
45
- if (args.project) {
46
- const targetProjectId = getProjectId(args.project);
47
- entries = allEntries.filter((e) => e.projectId === targetProjectId);
48
- }
49
-
50
- if (entries.length === 0) {
51
- console.log('No Memorix-written files found for this project.');
52
- p.outro('Audit trail is empty for this project.');
53
- return;
54
- }
55
-
56
- // Group by project
57
- const byProject: Record<string, Array<{ entry: import('../../audit/index.js').AuditEntry }>> = {};
58
- for (const { projectId, entry } of entries) {
59
- if (!byProject[projectId]) {
60
- byProject[projectId] = [];
61
- }
62
- byProject[projectId].push({ entry });
63
- }
64
-
65
- // Display by project
66
- console.log('');
67
- for (const [projectId, items] of Object.entries(byProject)) {
68
- console.log(`Project: ${projectId}`);
69
- console.log('');
70
-
71
- for (const { entry } of items) {
72
- const icon = entry.type === 'hook' ? '[HOOK]' : '[TASK]';
73
- const agent = entry.agent ? ` (${entry.agent})` : '';
74
- console.log(`${icon} ${entry.path}${agent}`);
75
- console.log(` Created: ${entry.createdAt}`);
76
- console.log('');
77
- }
78
- }
79
-
80
- // Summary
81
- const hookCount = entries.filter((e) => e.entry.type === 'hook').length;
82
- const ruleCount = entries.filter((e) => e.entry.type === 'rule').length;
83
- const projectCount = new Set(entries.map((e) => e.projectId)).size;
84
-
85
- p.note(`${projectCount} projects, ${hookCount} hooks, ${ruleCount} rules`);
86
-
87
- p.outro('Audit trail complete.');
88
- },
89
- });
1
+ /**
2
+ * CLI Command: memorix audit list
3
+ *
4
+ * List all files written by Memorix (audit trail).
5
+ */
6
+
7
+ import { defineCommand } from 'citty';
8
+ import * as p from '@clack/prompts';
9
+
10
+ export default defineCommand({
11
+ meta: {
12
+ name: 'list',
13
+ description: 'List Memorix-written files (audit trail)',
14
+ },
15
+ args: {
16
+ project: {
17
+ type: 'string',
18
+ description: 'Filter by project (optional)',
19
+ required: false,
20
+ },
21
+ },
22
+ run: async ({ args }) => {
23
+ const { getAllAuditEntries, getProjectId } = await import('../../audit/index.js');
24
+ const os = await import('node:os');
25
+ let cwd: string;
26
+ try {
27
+ cwd = process.cwd();
28
+ } catch {
29
+ cwd = os.homedir();
30
+ console.log(`[WARN] Could not access current directory, using home: ${cwd}`);
31
+ }
32
+
33
+ p.intro('Memorix Audit Trail');
34
+
35
+ const allEntries = await getAllAuditEntries();
36
+
37
+ if (allEntries.length === 0) {
38
+ console.log('No Memorix-written files found.');
39
+ p.outro('Audit trail is empty.');
40
+ return;
41
+ }
42
+
43
+ // Filter by project if specified
44
+ let entries = allEntries;
45
+ if (args.project) {
46
+ const targetProjectId = getProjectId(args.project);
47
+ entries = allEntries.filter((e) => e.projectId === targetProjectId);
48
+ }
49
+
50
+ if (entries.length === 0) {
51
+ console.log('No Memorix-written files found for this project.');
52
+ p.outro('Audit trail is empty for this project.');
53
+ return;
54
+ }
55
+
56
+ // Group by project
57
+ const byProject: Record<string, Array<{ entry: import('../../audit/index.js').AuditEntry }>> = {};
58
+ for (const { projectId, entry } of entries) {
59
+ if (!byProject[projectId]) {
60
+ byProject[projectId] = [];
61
+ }
62
+ byProject[projectId].push({ entry });
63
+ }
64
+
65
+ // Display by project
66
+ console.log('');
67
+ for (const [projectId, items] of Object.entries(byProject)) {
68
+ console.log(`Project: ${projectId}`);
69
+ console.log('');
70
+
71
+ for (const { entry } of items) {
72
+ const icon = entry.type === 'hook' ? '[HOOK]' : '[TASK]';
73
+ const agent = entry.agent ? ` (${entry.agent})` : '';
74
+ console.log(`${icon} ${entry.path}${agent}`);
75
+ console.log(` Created: ${entry.createdAt}`);
76
+ console.log('');
77
+ }
78
+ }
79
+
80
+ // Summary
81
+ const hookCount = entries.filter((e) => e.entry.type === 'hook').length;
82
+ const ruleCount = entries.filter((e) => e.entry.type === 'rule').length;
83
+ const projectCount = new Set(entries.map((e) => e.projectId)).size;
84
+
85
+ p.note(`${projectCount} projects, ${hookCount} hooks, ${ruleCount} rules`);
86
+
87
+ p.outro('Audit trail complete.');
88
+ },
89
+ });
@@ -1,48 +1,48 @@
1
- import { defineCommand } from 'citty';
2
- import { getBeforeAfterMetrics, getMetricsSummary } from '../../memory/formation/index.js';
3
- import { emitError, emitResult } from './operator-shared.js';
4
-
5
- export default defineCommand({
6
- meta: {
7
- name: 'formation',
8
- description: 'Inspect Memory Formation Pipeline runtime metrics',
9
- },
10
- args: {
11
- json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
12
- },
13
- run: async ({ args }) => {
14
- const action = (args._ as string[])?.[0] || '';
15
- const asJson = !!args.json;
16
-
17
- try {
18
- switch (action) {
19
- case 'metrics': {
20
- const summary = getMetricsSummary();
21
- const beforeAfter = getBeforeAfterMetrics();
22
- emitResult(
23
- { summary, beforeAfter },
24
- summary.total === 0
25
- ? 'Formation Pipeline: No metrics collected yet.'
26
- : [
27
- 'Formation Pipeline Metrics',
28
- `- Total observations processed: ${summary.total}`,
29
- `- Average value score: ${summary.avgValueScore.toFixed(3)}`,
30
- `- Average processing time: ${summary.avgDurationMs.toFixed(1)}ms`,
31
- ].join('\n'),
32
- asJson,
33
- );
34
- return;
35
- }
36
-
37
- default:
38
- console.log('Memorix Formation Commands');
39
- console.log('');
40
- console.log('Usage:');
41
- console.log(' memorix formation metrics');
42
- }
43
- } catch (error) {
44
- emitError(error instanceof Error ? error.message : String(error), asJson);
45
- }
46
- },
47
- });
48
-
1
+ import { defineCommand } from 'citty';
2
+ import { getBeforeAfterMetrics, getMetricsSummary } from '../../memory/formation/index.js';
3
+ import { emitError, emitResult } from './operator-shared.js';
4
+
5
+ export default defineCommand({
6
+ meta: {
7
+ name: 'formation',
8
+ description: 'Inspect Memory Formation Pipeline runtime metrics',
9
+ },
10
+ args: {
11
+ json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
12
+ },
13
+ run: async ({ args }) => {
14
+ const action = (args._ as string[])?.[0] || '';
15
+ const asJson = !!args.json;
16
+
17
+ try {
18
+ switch (action) {
19
+ case 'metrics': {
20
+ const summary = getMetricsSummary();
21
+ const beforeAfter = getBeforeAfterMetrics();
22
+ emitResult(
23
+ { summary, beforeAfter },
24
+ summary.total === 0
25
+ ? 'Formation Pipeline: No metrics collected yet.'
26
+ : [
27
+ 'Formation Pipeline Metrics',
28
+ `- Total observations processed: ${summary.total}`,
29
+ `- Average value score: ${summary.avgValueScore.toFixed(3)}`,
30
+ `- Average processing time: ${summary.avgDurationMs.toFixed(1)}ms`,
31
+ ].join('\n'),
32
+ asJson,
33
+ );
34
+ return;
35
+ }
36
+
37
+ default:
38
+ console.log('Memorix Formation Commands');
39
+ console.log('');
40
+ console.log('Usage:');
41
+ console.log(' memorix formation metrics');
42
+ }
43
+ } catch (error) {
44
+ emitError(error instanceof Error ? error.message : String(error), asJson);
45
+ }
46
+ },
47
+ });
48
+