memorix 1.2.1 → 1.2.2

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 (199) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +14 -2
  3. package/README.zh-CN.md +14 -2
  4. package/TEAM.md +86 -86
  5. package/dist/cli/index.js +15407 -13779
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/index.js +1321 -529
  8. package/dist/index.js.map +1 -1
  9. package/dist/maintenance-runner.d.ts +1 -1
  10. package/dist/maintenance-runner.js +8458 -8087
  11. package/dist/maintenance-runner.js.map +1 -1
  12. package/dist/memcode-runtime/CHANGELOG.md +16 -0
  13. package/dist/sdk.d.ts +7 -2
  14. package/dist/sdk.js +1349 -535
  15. package/dist/sdk.js.map +1 -1
  16. package/dist/types.d.ts +49 -1
  17. package/dist/types.js.map +1 -1
  18. package/docs/1.2.2-MEMORY-CONTROL-PLANE.md +434 -0
  19. package/docs/AGENT_OPERATOR_PLAYBOOK.md +4 -0
  20. package/docs/API_REFERENCE.md +24 -4
  21. package/docs/DESIGN_DECISIONS.md +357 -357
  22. package/docs/README.md +1 -1
  23. package/docs/dev-log/progress.txt +91 -11
  24. package/package.json +1 -1
  25. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  26. package/src/audit/index.ts +156 -156
  27. package/src/cli/command-guide.ts +192 -0
  28. package/src/cli/commands/audit-list.ts +89 -89
  29. package/src/cli/commands/audit.ts +9 -4
  30. package/src/cli/commands/background.ts +659 -659
  31. package/src/cli/commands/cleanup.ts +5 -1
  32. package/src/cli/commands/codegraph.ts +15 -5
  33. package/src/cli/commands/context.ts +3 -2
  34. package/src/cli/commands/doctor.ts +4 -2
  35. package/src/cli/commands/explain.ts +9 -3
  36. package/src/cli/commands/formation.ts +48 -48
  37. package/src/cli/commands/git-hook-install.ts +111 -111
  38. package/src/cli/commands/handoff.ts +75 -61
  39. package/src/cli/commands/hooks-status.ts +63 -63
  40. package/src/cli/commands/identity.ts +116 -0
  41. package/src/cli/commands/ingest-commit.ts +153 -153
  42. package/src/cli/commands/ingest-image.ts +71 -69
  43. package/src/cli/commands/ingest-log.ts +180 -180
  44. package/src/cli/commands/ingest.ts +44 -44
  45. package/src/cli/commands/integrate-shared.ts +15 -15
  46. package/src/cli/commands/lock.ts +93 -92
  47. package/src/cli/commands/memory.ts +58 -21
  48. package/src/cli/commands/message.ts +123 -118
  49. package/src/cli/commands/operator-shared.ts +98 -3
  50. package/src/cli/commands/poll.ts +74 -64
  51. package/src/cli/commands/purge-all-memory.ts +85 -85
  52. package/src/cli/commands/purge-project-memory.ts +83 -83
  53. package/src/cli/commands/reasoning.ts +135 -121
  54. package/src/cli/commands/retention.ts +9 -4
  55. package/src/cli/commands/serve-http.ts +8 -2
  56. package/src/cli/commands/serve-shared.ts +118 -118
  57. package/src/cli/commands/session.ts +29 -3
  58. package/src/cli/commands/skills.ts +124 -119
  59. package/src/cli/commands/status.ts +4 -3
  60. package/src/cli/commands/task.ts +193 -184
  61. package/src/cli/commands/team.ts +14 -10
  62. package/src/cli/commands/transfer.ts +108 -55
  63. package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
  64. package/src/cli/identity.ts +89 -0
  65. package/src/cli/index.ts +96 -19
  66. package/src/cli/invocation.ts +115 -0
  67. package/src/cli/tui/ChatView.tsx +234 -234
  68. package/src/cli/tui/CommandBar.tsx +312 -312
  69. package/src/cli/tui/ContextRail.tsx +118 -118
  70. package/src/cli/tui/HeaderBar.tsx +72 -72
  71. package/src/cli/tui/LogoBanner.tsx +51 -51
  72. package/src/cli/tui/Sidebar.tsx +179 -179
  73. package/src/cli/tui/chat-service.ts +41 -18
  74. package/src/cli/tui/data.ts +23 -44
  75. package/src/cli/tui/index.ts +41 -41
  76. package/src/cli/tui/markdown-render.tsx +371 -371
  77. package/src/cli/tui/operator-context.ts +60 -0
  78. package/src/cli/tui/use-mouse.ts +157 -157
  79. package/src/cli/tui/useNavigation.ts +56 -56
  80. package/src/cli/tui/views/MemoryView.tsx +10 -8
  81. package/src/cli/update-checker.ts +211 -211
  82. package/src/cli/version.ts +7 -7
  83. package/src/cli/workbench.ts +1 -1
  84. package/src/codegraph/auto-context.ts +31 -2
  85. package/src/codegraph/context-pack.ts +1 -0
  86. package/src/codegraph/project-context.ts +2 -0
  87. package/src/compact/engine.ts +26 -10
  88. package/src/compact/index-format.ts +25 -2
  89. package/src/compact/token-budget.ts +74 -74
  90. package/src/dashboard/project-classification.ts +64 -64
  91. package/src/dashboard/server.ts +46 -9
  92. package/src/embedding/fastembed-provider.ts +142 -142
  93. package/src/embedding/transformers-provider.ts +111 -111
  94. package/src/git/extractor.ts +209 -209
  95. package/src/git/hooks-path.ts +85 -85
  96. package/src/hooks/admission.ts +117 -0
  97. package/src/hooks/handler.ts +98 -91
  98. package/src/hooks/pattern-detector.ts +173 -173
  99. package/src/hooks/significance-filter.ts +250 -250
  100. package/src/knowledge/context-assembly.ts +97 -0
  101. package/src/knowledge/workset.ts +179 -10
  102. package/src/llm/memory-manager.ts +328 -328
  103. package/src/llm/provider.ts +885 -885
  104. package/src/llm/quality.ts +248 -248
  105. package/src/memory/admission.ts +57 -0
  106. package/src/memory/attribution-guard.ts +249 -249
  107. package/src/memory/consolidation.ts +13 -2
  108. package/src/memory/disclosure-policy.ts +140 -135
  109. package/src/memory/entity-extractor.ts +197 -197
  110. package/src/memory/export-import.ts +11 -3
  111. package/src/memory/formation/evaluate.ts +217 -217
  112. package/src/memory/formation/extract.ts +361 -361
  113. package/src/memory/formation/index.ts +417 -417
  114. package/src/memory/formation/resolve.ts +344 -344
  115. package/src/memory/formation/types.ts +315 -315
  116. package/src/memory/freshness.ts +122 -122
  117. package/src/memory/graph-context.ts +8 -2
  118. package/src/memory/graph.ts +197 -197
  119. package/src/memory/observations.ts +162 -4
  120. package/src/memory/quality-audit.ts +2 -0
  121. package/src/memory/refs.ts +94 -94
  122. package/src/memory/retention.ts +22 -2
  123. package/src/memory/secret-filter.ts +79 -79
  124. package/src/memory/session.ts +5 -2
  125. package/src/memory/visibility.ts +80 -0
  126. package/src/multimodal/image-loader.ts +143 -143
  127. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  128. package/src/orchestrate/adapters/claude.ts +111 -111
  129. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  130. package/src/orchestrate/adapters/codex.ts +41 -41
  131. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  132. package/src/orchestrate/adapters/gemini.ts +42 -42
  133. package/src/orchestrate/adapters/index.ts +73 -73
  134. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  135. package/src/orchestrate/adapters/opencode.ts +47 -47
  136. package/src/orchestrate/adapters/spawn-helper.ts +286 -286
  137. package/src/orchestrate/adapters/types.ts +77 -77
  138. package/src/orchestrate/capability-router.ts +284 -284
  139. package/src/orchestrate/context-compact.ts +188 -188
  140. package/src/orchestrate/cost-tracker.ts +219 -219
  141. package/src/orchestrate/error-recovery.ts +191 -191
  142. package/src/orchestrate/evidence.ts +140 -140
  143. package/src/orchestrate/ledger.ts +110 -110
  144. package/src/orchestrate/memorix-bridge.ts +378 -340
  145. package/src/orchestrate/output-budget.ts +80 -80
  146. package/src/orchestrate/permission.ts +152 -152
  147. package/src/orchestrate/pipeline-trace.ts +131 -131
  148. package/src/orchestrate/prompt-builder.ts +155 -155
  149. package/src/orchestrate/ring-buffer.ts +37 -37
  150. package/src/orchestrate/task-graph.ts +389 -389
  151. package/src/orchestrate/worktree.ts +232 -232
  152. package/src/project/aliases.ts +374 -374
  153. package/src/project/detector.ts +268 -268
  154. package/src/rules/adapters/claude-code.ts +99 -99
  155. package/src/rules/adapters/codex.ts +97 -97
  156. package/src/rules/adapters/copilot.ts +124 -124
  157. package/src/rules/adapters/cursor.ts +114 -114
  158. package/src/rules/adapters/kiro.ts +126 -126
  159. package/src/rules/adapters/trae.ts +56 -56
  160. package/src/rules/adapters/windsurf.ts +83 -83
  161. package/src/rules/syncer.ts +235 -235
  162. package/src/runtime/control-plane-maintenance.ts +1 -0
  163. package/src/runtime/isolated-maintenance.ts +1 -0
  164. package/src/runtime/lifecycle.ts +18 -0
  165. package/src/runtime/maintenance-jobs.ts +1 -0
  166. package/src/runtime/maintenance-runner.ts +2 -0
  167. package/src/runtime/project-maintenance.ts +89 -0
  168. package/src/sdk.ts +334 -304
  169. package/src/search/intent-detector.ts +289 -289
  170. package/src/search/query-expansion.ts +52 -52
  171. package/src/server/formation-timeout.ts +27 -27
  172. package/src/server.ts +260 -81
  173. package/src/skills/mini-skills.ts +386 -386
  174. package/src/store/chat-store.ts +119 -119
  175. package/src/store/graph-store.ts +249 -249
  176. package/src/store/mini-skill-store.ts +349 -349
  177. package/src/store/orama-store.ts +61 -6
  178. package/src/store/persistence-json.ts +212 -212
  179. package/src/store/persistence.ts +291 -291
  180. package/src/store/project-affinity.ts +195 -195
  181. package/src/store/sqlite-db.ts +23 -1
  182. package/src/store/sqlite-store.ts +12 -2
  183. package/src/team/event-bus.ts +76 -76
  184. package/src/team/file-locks.ts +173 -173
  185. package/src/team/handoff.ts +168 -161
  186. package/src/team/messages.ts +203 -203
  187. package/src/team/poll.ts +132 -132
  188. package/src/team/tasks.ts +211 -211
  189. package/src/types.ts +51 -0
  190. package/src/wiki/generator.ts +2 -0
  191. package/src/workspace/mcp-adapters/codex.ts +191 -191
  192. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  193. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  194. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  195. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  196. package/src/workspace/mcp-adapters/trae.ts +134 -134
  197. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  198. package/src/workspace/sanitizer.ts +60 -60
  199. package/src/workspace/workflow-sync.ts +131 -131
package/docs/README.md CHANGED
@@ -87,7 +87,7 @@ The public docs are organized by user intent:
87
87
  | 1.2 task-shaped evidence selection | [1.2 Workset Retrieval](1.2.0-WORKSET-RETRIEVAL.md) |
88
88
  | 1.2 non-blocking refresh and maintenance contract | [1.2 Dynamic Lifecycle](1.2.0-DYNAMIC-LIFECYCLE.md) |
89
89
  | 1.2 honest Lite and optional semantic CodeGraph provider contract | [1.2 Provider Quality](1.2.0-PROVIDER-QUALITY.md) |
90
- | Active 1.2 multi-dimensional memory work | [1.2.0 Development Charter](1.2.0-DEVELOPMENT-CHARTER.md) |
90
+ | Active context-control work | [1.2.2 Memory Control Plane](1.2.2-MEMORY-CONTROL-PLANE.md) |
91
91
  | Historical cloud sync and multi-agent research | [CLOUD_SYNC_AND_MULTI_AGENT_RESEARCH.md](CLOUD_SYNC_AND_MULTI_AGENT_RESEARCH.md) |
92
92
  | Known issues and old roadmap notes | [KNOWN_ISSUES_AND_ROADMAP.md](KNOWN_ISSUES_AND_ROADMAP.md) |
93
93
 
@@ -4,15 +4,15 @@
4
4
  > older notes when they conflict.
5
5
 
6
6
  ## Current State
7
- - Phase: 1.2 release validation and publication
8
- - Branch: `codex/1.2.0-multidimensional-memory`
9
- - Last updated: 2026-07-18
10
- - Released baseline: `memorix@1.1.13`, tag `v1.1.13`, PR #129 merged as
11
- `7e8077f`.
12
- - Goal: turn Memorix from a useful narrative-memory layer into a task-ready
13
- working-context layer where code state, change evidence, verification,
14
- source-backed project knowledge, workflows, and durable decisions are ranked
15
- together.
7
+ - Phase: 1.2.2 memory-control-plane admission and visibility implementation
8
+ - Branch: `codex/1.2.2-memory-control-plane`
9
+ - Last updated: 2026-07-25
10
+ - Released baseline: `memorix@1.2.1`, tag `v1.2.1`, `origin/main` at
11
+ `1b5bf7f`.
12
+ - Goal: make the 1.2 multi-dimensional evidence layer behave as one bounded,
13
+ explainable control plane. A task Workset, hook handoff, lifecycle refresh,
14
+ and provider capability result must share evidence qualification, delivery
15
+ budgets, and privacy-safe receipts.
16
16
 
17
17
  ## 1.1.13 Closeout
18
18
  - Codex setup now stamps plugin versions and doctor distinguishes bundle,
@@ -102,7 +102,7 @@
102
102
  - The compiled CLI was smoke-tested in an isolated Git project through init,
103
103
  compile, apply, and lint with a source-backed claim.
104
104
 
105
- ## 1.2 Delivery Complete, Release Checks In Progress
105
+ ## 1.2 Delivery Complete, Released As 1.2.1
106
106
  - Phase 4 added canonical Markdown workflows, safe adapter preview/apply, import,
107
107
  selection, and verification receipts. Agent instruction files are render
108
108
  targets, not the workflow source of truth.
@@ -123,4 +123,84 @@
123
123
  - Release audit also incorporated #130 before publication: the optional SQLite
124
124
  runtime now uses the Node-26-compatible `better-sqlite3` 12.x line, with a
125
125
  dedicated Node 26 CI smoke that opens an in-memory database.
126
- - Remaining remote gates: GitHub CI, npm publish, tag, and GitHub release.
126
+ - The release was completed as `memorix@1.2.1`. Its next development line is
127
+ [1.2.2 Memory Control Plane](../1.2.2-MEMORY-CONTROL-PLANE.md), which
128
+ consolidates these capabilities instead of adding another disconnected
129
+ memory feature.
130
+
131
+ ## 1.2.2 Control Plane
132
+ - `TaskWorkset` already has bounded rendering and source-aware claims, but
133
+ SessionStart handoff and legacy context surfaces need one shared admission,
134
+ budget, and receipt contract.
135
+ - First implementation slice complete: the shared `ContextReceipt` records
136
+ delivery target, selected source ids/kinds, trust/freshness, exact budget
137
+ omissions, queued refreshes, and Workset selection time without entering the
138
+ agent prompt. Project Context, Context Pack, and full SessionStart injection
139
+ now carry the same delivery-target semantics; `memorix explain` exposes the
140
+ receipt in text and JSON.
141
+ - Budget selection now keeps a knowledge page dependent on a Claim out of the
142
+ prompt when its qualifying Claim could not fit. The receipt records both as
143
+ withheld instead of presenting an orphaned page path as usable knowledge.
144
+ - Phase 3 admission slice complete: automatic observations now persist an
145
+ `ephemeral`, `candidate`, or `qualified` state and a reason. Hooks and the
146
+ internal orchestrator capture concrete evidence as candidates, keep routine
147
+ success/telemetry ephemeral, and drop low-signal activity without writing it.
148
+ Automatic capture stays quiet in the host agent.
149
+ - A deduplicated `observation-qualify` maintenance job runs after CodeGraph
150
+ refresh. It requires a scan no older than the capture and at least one
151
+ current code reference before upgrading a candidate. Qualification does not
152
+ create a Claim; explicit saves and Git remain the Claim boundary.
153
+ - Auto Project Context, automatic session L1 delivery, Wiki/Knowledge Graph
154
+ compilation, and graph-context packets exclude candidates and ephemeral
155
+ traces. Ordinary search prefers qualified material, while explicit lookup
156
+ can still inspect pending evidence.
157
+ - Pending automatic evidence is also excluded from automatic consolidation so
158
+ a later qualification can still inspect its original source grain. Retention
159
+ explanations no longer describe an unqualified `core` candidate as immune.
160
+ - Actor and visibility enforcement is now one policy shared by MCP retrieval,
161
+ auto context, CLI/TUI, dashboards, knowledge/graph projections, and scoped
162
+ maintenance. Legacy observations remain project-visible; new records may be
163
+ `project`, `team`, or `personal` with an explicit creator and recipients.
164
+ Missing identity never grants private or team visibility.
165
+ - Automatic hooks and orchestrator traces begin personal. A verified hook
166
+ candidate may become project evidence only when qualification proves a
167
+ current code reference. Targeted handoffs are readable by sender and
168
+ recipient but writable only by sender; broadcasts require an active project
169
+ team member.
170
+ - Automatic orchestration lesson lookup is explicitly project-scoped, so its
171
+ prompt injection cannot read personal or team-scoped records.
172
+ - Topic-key writes now check mutation scope before storage, and the
173
+ project-attribution guard receives only memories visible to its current
174
+ reader. This closes both guessed-key overwrite and cross-project existence
175
+ hints without hiding historical project knowledge after upgrade.
176
+ - The embedded SDK remains project-visible when unbound. CLI and the local TUI
177
+ now share the same explicit actor reader: an unbound terminal sees project
178
+ memory only, while `memorix identity join|use` (or one-shot `--as`) grants
179
+ only that active project member's personal/team visibility and coordination
180
+ ergonomics. `identity clear` returns to project scope; private evidence
181
+ cannot be promoted into shared skills or generated project skills.
182
+ - CLI control-plane ergonomics now include `--cwd`, kebab-case flag aliases,
183
+ action-oriented namespace help, explicit `memorix workbench`, and
184
+ file/stdin transfer import/export. Root memory aliases use the same
185
+ canonical command paths as `memorix memory`; CLI and MCP exports are filtered
186
+ by the same active reader so an unbound backup cannot contain private/team
187
+ observations.
188
+ - Direct CLI and foreground Code Memory refreshes now enqueue qualification as
189
+ well as claim requalification, and they register the local project target
190
+ needed by the isolated control-plane worker. The host hook path persists its
191
+ candidate before scheduling a refresh, avoiding a fast-worker race where a
192
+ scan could predate the capture.
193
+ - Compiled-artifact smoke: an isolated Codex `PostToolUse` hook returned only
194
+ `continue: true`, stored a `candidate`, and the isolated background control
195
+ plane upgraded it to `qualified` after a real Code Memory scan with one
196
+ current reference. Embeddings were deliberately disabled for this
197
+ deterministic local smoke. The full test suite, TypeScript check, and
198
+ production build also passed after the admission policy was reconciled with
199
+ OpenCode's concise technical response events.
200
+ - #135 remains a contributor-owned session-handoff candidate for the bounded
201
+ `HandoffPacket` phase. It is not copied or silently replaced.
202
+ - #133/#134 remain open pending an official provider-capability layer and a
203
+ safe agent-facing media path. The existing OpenRouter text embedding path is
204
+ the supported baseline.
205
+ - See [1.2.2 Memory Control Plane](../1.2.2-MEMORY-CONTROL-PLANE.md) for
206
+ phases, acceptance gates, non-goals, and release criteria.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Shared workspace memory for Codex and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -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
+ }
@@ -0,0 +1,192 @@
1
+ export interface CliCommandGuide {
2
+ summary: string;
3
+ usage: string[];
4
+ notes?: string[];
5
+ }
6
+
7
+ const GUIDES: Record<string, CliCommandGuide> = {
8
+ memory: {
9
+ summary: 'Store, search, inspect, resolve, consolidate, and promote project memory.',
10
+ usage: [
11
+ 'memorix memory search --query "timeout regression" [--limit 10]',
12
+ 'memorix memory store --text "..." [--title "..."] [--visibility project|personal|team]',
13
+ 'memorix memory detail --id 42',
14
+ 'memorix memory recent [--limit 10]',
15
+ 'memorix memory resolve --ids 42,43 [--status resolved|archived]',
16
+ 'memorix memory consolidate --action preview|execute',
17
+ 'memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]',
18
+ ],
19
+ notes: ['Personal and team visibility require `memorix identity join` or `memorix identity use` first.'],
20
+ },
21
+ identity: {
22
+ summary: 'Select the active local actor for private memory and coordination commands.',
23
+ usage: [
24
+ 'memorix identity status',
25
+ 'memorix identity join --agent-type codex [--name codex-main --instance-id local]',
26
+ 'memorix identity use --agent-id <id>',
27
+ 'memorix identity clear',
28
+ ],
29
+ notes: ['Without an identity, CLI reads and writes only project-visible memory.'],
30
+ },
31
+ session: {
32
+ summary: 'Start, end, and inspect coding sessions. Coordination remains opt-in.',
33
+ usage: [
34
+ 'memorix session start --agent codex',
35
+ 'memorix session start --agent codex --agent-type codex --join-team --use',
36
+ 'memorix session end --session-id <id> [--summary "..."]',
37
+ 'memorix session context [--limit 3]',
38
+ ],
39
+ },
40
+ context: {
41
+ summary: 'Build the bounded task Workset used to resume or begin real work.',
42
+ usage: ['memorix context --task "continue the release fix" [--refresh auto|always|never]'],
43
+ },
44
+ explain: {
45
+ summary: 'Show why a task context contains its current facts and memory evidence.',
46
+ usage: ['memorix explain [--refresh auto|always|never]'],
47
+ },
48
+ codegraph: {
49
+ summary: 'Refresh local code-state snapshots and assemble task-specific code context.',
50
+ usage: [
51
+ 'memorix codegraph status',
52
+ 'memorix codegraph refresh',
53
+ 'memorix codegraph context-pack --task "trace the auth flow" [--limit 20]',
54
+ ],
55
+ },
56
+ knowledge: {
57
+ summary: 'Manage the reviewed, source-backed Knowledge Workspace and project workflows.',
58
+ usage: [
59
+ 'memorix knowledge init [--mode local|versioned]',
60
+ 'memorix knowledge status',
61
+ 'memorix knowledge compile',
62
+ 'memorix knowledge lint',
63
+ 'memorix knowledge workflow list',
64
+ ],
65
+ },
66
+ reasoning: {
67
+ summary: 'Capture and retrieve engineering decision rationale.',
68
+ usage: [
69
+ 'memorix reasoning store --entity auth --decision "Use SQLite" --rationale "..."',
70
+ 'memorix reasoning search --query "why sqlite" [--scope project|global]',
71
+ ],
72
+ },
73
+ retention: {
74
+ summary: 'Inspect retention state and archive records that are eligible under the current scope.',
75
+ usage: [
76
+ 'memorix retention status',
77
+ 'memorix retention stale',
78
+ 'memorix retention archive',
79
+ ],
80
+ },
81
+ transfer: {
82
+ summary: 'Create or restore explicit project memory snapshots for backup and automation.',
83
+ usage: [
84
+ 'memorix transfer export --format json --out ./.memorix-export.json',
85
+ 'memorix transfer import --file ./.memorix-export.json',
86
+ 'memorix transfer import --stdin',
87
+ ],
88
+ },
89
+ team: {
90
+ summary: 'Manage explicit multi-agent coordination state for the current project.',
91
+ usage: [
92
+ 'memorix team join --agent-type codex [--name codex-main]',
93
+ 'memorix team status [--all]',
94
+ 'memorix team leave [--agent-id <id>]',
95
+ ],
96
+ },
97
+ task: {
98
+ summary: 'Create and progress coordination tasks. An active CLI identity fills agentId automatically.',
99
+ usage: [
100
+ 'memorix task create --description "Review release evidence"',
101
+ 'memorix task claim --task-id <id>',
102
+ 'memorix task complete --task-id <id> --result "Verified"',
103
+ 'memorix task list [--available]',
104
+ ],
105
+ },
106
+ message: {
107
+ summary: 'Send and read coordination messages. An active CLI identity fills the sender automatically.',
108
+ usage: [
109
+ 'memorix message send --to <agent-id> --type info --content "..."',
110
+ 'memorix message broadcast --type announcement --content "..."',
111
+ 'memorix message inbox [--mark-read]',
112
+ ],
113
+ },
114
+ lock: {
115
+ summary: 'Use advisory file locks to reduce overlapping edits between agents.',
116
+ usage: [
117
+ 'memorix lock lock --file src/server.ts',
118
+ 'memorix lock unlock --file src/server.ts',
119
+ 'memorix lock status [--file src/server.ts]',
120
+ ],
121
+ },
122
+ handoff: {
123
+ summary: 'Create durable, targeted or team-visible handoff artifacts.',
124
+ usage: ['memorix handoff send --summary "..." --context "..." [--to-agent-id <id>]'],
125
+ },
126
+ poll: {
127
+ summary: 'Return a compact coordination snapshot for the active CLI identity.',
128
+ usage: ['memorix poll [--mark-inbox-read]'],
129
+ },
130
+ audit: {
131
+ summary: 'Inspect quality, attribution, and recorded audit evidence.',
132
+ usage: ['memorix audit memory', 'memorix audit project [--threshold 2]', 'memorix audit list'],
133
+ },
134
+ skills: {
135
+ summary: 'Inspect and generate project skills from project-visible memory evidence.',
136
+ usage: ['memorix skills list', 'memorix skills generate [--write --target codex]', 'memorix skills show --name <skill>'],
137
+ },
138
+ sync: {
139
+ summary: 'Synchronize agent rules and workspace artifacts through explicit routes.',
140
+ usage: ['memorix sync rules --action status', 'memorix sync workspace --action scan'],
141
+ },
142
+ ingest: {
143
+ summary: 'Ingest Git and image evidence into project memory.',
144
+ usage: ['memorix ingest commit [--ref HEAD]', 'memorix ingest log [--count 10]', 'memorix ingest image --path ./diagram.png'],
145
+ },
146
+ workbench: {
147
+ summary: 'Open the interactive terminal memory control plane.',
148
+ usage: ['memorix workbench'],
149
+ },
150
+ };
151
+
152
+ export function commandGuideNames(): string[] {
153
+ return Object.keys(GUIDES).sort();
154
+ }
155
+
156
+ export function renderCliGuide(command?: string): string {
157
+ const normalized = command?.trim().toLowerCase();
158
+ if (normalized && GUIDES[normalized]) {
159
+ const guide = GUIDES[normalized];
160
+ return [
161
+ `Memorix ${normalized}`,
162
+ '',
163
+ guide.summary,
164
+ '',
165
+ 'Usage:',
166
+ ...guide.usage.map((line) => ` ${line}`),
167
+ ...(guide.notes?.length ? ['', ...guide.notes.map((line) => `Note: ${line}`)] : []),
168
+ '',
169
+ 'Project/actor options: --cwd <git-project> --as <active-agent-id>. Operator commands accept --json.',
170
+ ].join('\n');
171
+ }
172
+
173
+ return [
174
+ 'Memorix CLI',
175
+ '',
176
+ 'Use `memorix <command> --help` for an action-oriented guide.',
177
+ '',
178
+ `Command groups: ${commandGuideNames().join(', ')}`,
179
+ '',
180
+ 'Global options: --cwd <git-project> --as <active-agent-id>',
181
+ 'Compatibility: camelCase flags remain supported; kebab-case flags are accepted too.',
182
+ ].join('\n');
183
+ }
184
+
185
+ /** Render manual action help before Citty consumes `--help` as flag metadata. */
186
+ export function printCliGuideForHelp(argv: string[] = process.argv.slice(2)): boolean {
187
+ const [command, ...rest] = argv;
188
+ if (!command || !GUIDES[command.toLowerCase()]) return false;
189
+ if (!rest.includes('--help') && !rest.includes('-h')) return false;
190
+ console.log(renderCliGuide(command));
191
+ return true;
192
+ }