memorix 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/TEAM.md +86 -86
- package/dist/cli/index.js +5199 -4726
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +428 -49
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +97 -18
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +27 -0
- package/dist/sdk.js +428 -49
- package/dist/sdk.js.map +1 -1
- package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +86 -0
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +13 -1
- package/docs/API_REFERENCE.md +13 -3
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/dev-log/progress.txt +60 -9
- package/package.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/capability-map.ts +1 -1
- package/src/cli/command-guide.ts +4 -1
- package/src/cli/commands/agent-integrations.ts +5 -1
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/codegraph.ts +1 -1
- package/src/cli/commands/context.ts +9 -1
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +54 -54
- 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 +66 -66
- 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 +82 -82
- package/src/cli/commands/message.ts +104 -104
- package/src/cli/commands/poll.ts +58 -58
- 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 +118 -118
- package/src/cli/commands/resume.ts +31 -0
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/session.ts +15 -7
- package/src/cli/commands/skills.ts +114 -114
- package/src/cli/commands/task.ts +167 -167
- package/src/cli/commands/transfer.ts +47 -47
- 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/Sidebar.tsx +179 -179
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/session-service.ts +3 -2
- 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 +54 -1
- package/src/codegraph/task-lens.ts +29 -0
- package/src/compact/token-budget.ts +89 -74
- package/src/config/toml-loader.ts +9 -5
- package/src/dashboard/project-classification.ts +64 -64
- 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/hooks/handler.ts +127 -66
- package/src/hooks/installers/index.ts +5 -4
- package/src/hooks/official-skills.ts +6 -4
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +9 -7
- package/src/hooks/significance-filter.ts +250 -250
- package/src/knowledge/context-assembly.ts +4 -1
- package/src/knowledge/workset.ts +89 -1
- 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/disclosure-policy.ts +135 -135
- 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/secret-filter.ts +79 -79
- package/src/memory/session.ts +158 -9
- 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 +343 -343
- 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/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 +299 -299
- 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 +144 -10
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/bun-sqlite-compat.ts +118 -15
- package/src/store/chat-store.ts +119 -119
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- 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/sqlite-db.ts +3 -3
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +161 -161
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- 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
|
@@ -4,15 +4,66 @@
|
|
|
4
4
|
> older notes when they conflict.
|
|
5
5
|
|
|
6
6
|
## Current State
|
|
7
|
-
- Phase: 1.2.
|
|
8
|
-
- Branch: `codex/1.2.
|
|
9
|
-
- Last updated: 2026-07-
|
|
10
|
-
- Released baseline: `memorix@1.2.
|
|
11
|
-
`
|
|
12
|
-
- Goal: make the
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
- Phase: 1.2.4 persistent memory delivery release candidate
|
|
8
|
+
- Branch: `codex/1.2.4-persistent-memory-delivery`
|
|
9
|
+
- Last updated: 2026-07-26
|
|
10
|
+
- Released baseline: `memorix@1.2.3`, tag `v1.2.3`, `origin/main` at
|
|
11
|
+
`03ceb6d`.
|
|
12
|
+
- Goal: make the existing persistent memory layer deliver useful prior work
|
|
13
|
+
naturally across MCP and CLI without turning ordinary tasks into historical
|
|
14
|
+
context dumps.
|
|
15
|
+
|
|
16
|
+
## 1.2.4 Persistent Memory Delivery
|
|
17
|
+
- Continuation is now a bounded delivery projection over existing sessions and
|
|
18
|
+
durable observations, not a second handoff database. `TaskWorkset` keeps its
|
|
19
|
+
task lens (`bugfix`, `feature`, and so on) while independently recognizing a
|
|
20
|
+
continuation request.
|
|
21
|
+
- A continuation Workset includes at most the latest meaningful completed
|
|
22
|
+
session summary plus three readable durable memory anchors. Each item is
|
|
23
|
+
visible in the existing `ContextReceipt`; ordinary tasks do not receive it.
|
|
24
|
+
- `memorix resume "<task>"` is the CLI-equivalent continuation entry. The
|
|
25
|
+
existing MCP `memorix_project_context` receives the same behavior from the
|
|
26
|
+
user's task text, so the micro MCP profile stays at seven tools.
|
|
27
|
+
- Setup-generated rules now use a single fallback call when MCP is genuinely
|
|
28
|
+
unavailable: `memorix resume` for prior work or `memorix context` for new
|
|
29
|
+
work. They explicitly forbid help probing, command enumeration, and broad
|
|
30
|
+
search loops before the first brief.
|
|
31
|
+
- The visibility reader is carried into continuation retrieval, preserving
|
|
32
|
+
project aliases while failing closed for other agents' personal memory.
|
|
33
|
+
- Continuation text preserves whole technical identifiers instead of emitting a
|
|
34
|
+
misleading partial token. MCP Project Context also establishes a short-lived
|
|
35
|
+
delivery boundary: a follow-up search/detail request does not re-send an
|
|
36
|
+
already represented record unless the caller names a missing fact or the user
|
|
37
|
+
explicitly asks for the underlying detail.
|
|
38
|
+
- A read-only or "do not modify files" Autopilot task blocks `memorix_store`
|
|
39
|
+
by default. The only override is an explicit user request to persist a
|
|
40
|
+
record, represented by `overrideReadOnly: true`.
|
|
41
|
+
- A real Codex user-path smoke, in a fresh Git fixture seeded only through the
|
|
42
|
+
public CLI, made one natural-language continuation request. Codex received
|
|
43
|
+
the bounded brief, used one specific Context Pack expansion, was stopped
|
|
44
|
+
from re-reading already-covered memory, made no `memorix_store` write, and
|
|
45
|
+
returned the correct read-only next step.
|
|
46
|
+
- Completed local gates: TypeScript check, production build, focused
|
|
47
|
+
continuation/hook/CLI regressions, and the full suite (`237` files / `2677`
|
|
48
|
+
tests). A fresh packed install with optional native dependencies omitted used
|
|
49
|
+
Node SQLite to persist the same `memorix.db`; CLI resume retained
|
|
50
|
+
`AUTH_REFRESH_V2`; the micro MCP package surface exposed exactly seven tools
|
|
51
|
+
and enforced duplicate-retrieval plus read-only-write boundaries; and an
|
|
52
|
+
isolated Codex global setup wrote/activated the versioned Personal-marketplace
|
|
53
|
+
plugin with the matching skill guidance. Pending release gates: CI and
|
|
54
|
+
publish.
|
|
55
|
+
|
|
56
|
+
## 1.2.3 Session Context Visibility Hotfix
|
|
57
|
+
- A real installed-package CLI smoke found that a second coordination identity
|
|
58
|
+
could receive the first identity's personal observation in automatic session
|
|
59
|
+
context. The root cause was a reader-less core session-context call.
|
|
60
|
+
- `getSessionContext()` now accepts an `ObservationReader`; CLI, MCP, and TUI
|
|
61
|
+
session entry points pass their resolved caller identity. Alias-backed
|
|
62
|
+
project-visible records remain readable, while personal/team records fail
|
|
63
|
+
closed.
|
|
64
|
+
- Graph-neighbor routing is omitted whenever a reader is present because graph
|
|
65
|
+
relations are not yet visibility-scoped. Core, CLI, MCP, and alias regression
|
|
66
|
+
tests cover the boundary.
|
|
16
67
|
|
|
17
68
|
## 1.1.13 Closeout
|
|
18
69
|
- Codex setup now stamps plugin versions and doctor distinguishes bundle,
|
package/package.json
CHANGED
package/src/audit/index.ts
CHANGED
|
@@ -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
|
+
}
|
|
@@ -3,7 +3,7 @@ export const CLI_NATIVE_PARITY: Record<string, string> = Object.freeze({
|
|
|
3
3
|
memorix_search: 'memorix memory search',
|
|
4
4
|
memorix_detail: 'memorix memory detail',
|
|
5
5
|
memorix_graph_context: 'memorix memory graph-context',
|
|
6
|
-
memorix_project_context: 'memorix context',
|
|
6
|
+
memorix_project_context: 'memorix context|resume',
|
|
7
7
|
memorix_context_pack: 'memorix codegraph context-pack',
|
|
8
8
|
memorix_codegraph_status: 'memorix codegraph status',
|
|
9
9
|
memorix_knowledge: 'memorix knowledge init|status|compile|lint|apply|workflow',
|
package/src/cli/command-guide.ts
CHANGED
|
@@ -39,7 +39,10 @@ const GUIDES: Record<string, CliCommandGuide> = {
|
|
|
39
39
|
},
|
|
40
40
|
context: {
|
|
41
41
|
summary: 'Build the bounded task Workset used to resume or begin real work.',
|
|
42
|
-
usage: [
|
|
42
|
+
usage: [
|
|
43
|
+
'memorix context "continue the release fix" [--refresh auto|always|never]',
|
|
44
|
+
'memorix resume "continue the release fix" [--refresh auto|always|never]',
|
|
45
|
+
],
|
|
43
46
|
},
|
|
44
47
|
explain: {
|
|
45
48
|
summary: 'Show why a task context contains its current facts and memory evidence.',
|
|
@@ -776,7 +776,11 @@ function isCurrentGuidance(content: string): boolean {
|
|
|
776
776
|
return (
|
|
777
777
|
content.includes('Memory Autopilot') &&
|
|
778
778
|
content.includes('Default first step for non-trivial coding work') &&
|
|
779
|
-
content.includes('memorix_project_context')
|
|
779
|
+
content.includes('memorix_project_context') &&
|
|
780
|
+
content.includes('memorix resume') &&
|
|
781
|
+
content.includes('Continuation fallback is mandatory') &&
|
|
782
|
+
content.includes('Do not call more Memorix retrieval tools') &&
|
|
783
|
+
content.includes('read-only work')
|
|
780
784
|
);
|
|
781
785
|
}
|
|
782
786
|
|
|
@@ -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
|
+
});
|