memorix 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/CLAUDE.md +6 -1
- package/README.md +21 -0
- package/README.zh-CN.md +21 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +852 -214
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/index.html +201 -201
- package/dist/dashboard/static/style.css +3584 -3584
- package/dist/index.js +129 -62
- package/dist/index.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +22 -0
- package/dist/memcode-runtime/package.json +4 -4
- package/dist/sdk.js +129 -62
- package/dist/sdk.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +18 -0
- package/docs/API_REFERENCE.md +2 -0
- package/docs/CONFIGURATION.md +18 -0
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/SETUP.md +10 -0
- package/docs/dev-log/progress.txt +23 -30
- package/package.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/agent-integrations.ts +623 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +255 -255
- package/src/cli/commands/codegraph.ts +4 -0
- package/src/cli/commands/config-get.ts +9 -2
- package/src/cli/commands/doctor.ts +26 -0
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +66 -66
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +73 -73
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +96 -96
- package/src/cli/commands/message.ts +121 -121
- package/src/cli/commands/poll.ts +70 -70
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +132 -132
- package/src/cli/commands/repair.ts +60 -0
- package/src/cli/commands/retention.ts +108 -108
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/setup.ts +3 -3
- package/src/cli/commands/skills.ts +123 -123
- package/src/cli/commands/task.ts +192 -192
- package/src/cli/commands/transfer.ts +73 -73
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Panels.tsx +632 -632
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +742 -742
- package/src/cli/tui/data.ts +547 -547
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/theme.ts +178 -178
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/auto-context.ts +6 -0
- package/src/codegraph/context-pack.ts +7 -6
- package/src/codegraph/exclude.ts +47 -0
- package/src/codegraph/lite-provider.ts +5 -24
- package/src/codegraph/project-context.ts +13 -15
- package/src/compact/token-budget.ts +74 -74
- package/src/config/behavior.ts +59 -59
- package/src/config/resolved-config.ts +6 -0
- package/src/config/toml-loader.ts +4 -0
- package/src/config/yaml-loader.ts +7 -0
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/static/index.html +201 -201
- package/src/dashboard/static/style.css +3584 -3584
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/git/noise-filter.ts +210 -210
- package/src/hooks/installers/index.ts +4 -4
- package/src/hooks/official-skills.ts +1 -1
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +2 -2
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +107 -107
- package/src/memory/consolidation.ts +302 -302
- package/src/memory/disclosure-policy.ts +141 -141
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +433 -433
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +523 -523
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +380 -380
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/verify-gate.ts +219 -219
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +327 -327
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/server.ts +3 -0
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/file-lock.ts +100 -100
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/obs-store.ts +255 -255
- package/src/store/orama-store.ts +15 -8
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/session-store.ts +259 -259
- package/src/store/sqlite-store.ts +339 -339
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +167 -167
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/wiki/generator.ts +237 -237
- package/src/wiki/knowledge-graph.ts +334 -334
- package/src/wiki/types.ts +85 -85
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
package/src/git/noise-filter.ts
CHANGED
|
@@ -1,210 +1,210 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Git Commit Noise Filter
|
|
3
|
-
*
|
|
4
|
-
* Filters out low-value commits that would dilute memory quality.
|
|
5
|
-
* Codex identified this as the #1 priority for Git-Memory maturity:
|
|
6
|
-
* "Not every commit is worth becoming a long-term memory."
|
|
7
|
-
*
|
|
8
|
-
* Built-in heuristics (no LLM needed):
|
|
9
|
-
* - Merge commit detection
|
|
10
|
-
* - Low-signal commit message patterns (typo, format, bump, lint, etc.)
|
|
11
|
-
* - File-only commits (only lockfiles, generated files, etc.)
|
|
12
|
-
*
|
|
13
|
-
* All thresholds are configurable via memorix.yml `git` section.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { CommitInfo } from './extractor.js';
|
|
17
|
-
|
|
18
|
-
// ─── Types ───
|
|
19
|
-
|
|
20
|
-
export interface NoiseFilterConfig {
|
|
21
|
-
/** Skip merge commits entirely (default: true) */
|
|
22
|
-
skipMergeCommits?: boolean;
|
|
23
|
-
/** File glob patterns to exclude (default: lockfiles, generated files) */
|
|
24
|
-
excludePatterns?: string[];
|
|
25
|
-
/** Additional commit message patterns to skip (regex strings) */
|
|
26
|
-
noiseKeywords?: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FilterResult {
|
|
30
|
-
/** Whether this commit should be skipped */
|
|
31
|
-
skip: boolean;
|
|
32
|
-
/** Human-readable reason for skipping */
|
|
33
|
-
reason?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ─── Built-in Noise Patterns ───
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Commit message patterns that indicate low-value commits.
|
|
40
|
-
* These are checked case-insensitively against the full subject line.
|
|
41
|
-
*/
|
|
42
|
-
const NOISE_MESSAGE_PATTERNS: { pattern: RegExp; reason: string }[] = [
|
|
43
|
-
// Typo / formatting
|
|
44
|
-
{ pattern: /^fix(?:ed)?\s*typo/i, reason: 'typo fix' },
|
|
45
|
-
{ pattern: /^typo\b/i, reason: 'typo fix' },
|
|
46
|
-
{ pattern: /^(?:fix|correct)\s*(?:spelling|grammar|whitespace|indent)/i, reason: 'formatting fix' },
|
|
47
|
-
{ pattern: /^(?:format|lint|prettier|eslint|style)\b/i, reason: 'code formatting' },
|
|
48
|
-
{ pattern: /^(?:auto-?format|code\s*style)/i, reason: 'auto-formatting' },
|
|
49
|
-
|
|
50
|
-
// Lockfile / dependency bumps
|
|
51
|
-
{ pattern: /^(?:chore|build)?\(?deps?\)?[:/]?\s*(?:bump|update|upgrade)\b/i, reason: 'dependency bump' },
|
|
52
|
-
{ pattern: /^bump\s+\S+\s+(?:from|to)\b/i, reason: 'dependency bump' },
|
|
53
|
-
{ pattern: /^(?:yarn|npm|pnpm)\s+(?:lock|update)\b/i, reason: 'lockfile update' },
|
|
54
|
-
{ pattern: /^update\s+(?:lock|yarn\.lock|package-lock)/i, reason: 'lockfile update' },
|
|
55
|
-
|
|
56
|
-
// Merge noise
|
|
57
|
-
{ pattern: /^Merge\s+(?:branch|pull\s+request|remote)/i, reason: 'merge commit' },
|
|
58
|
-
{ pattern: /^Merge\s+\S+\s+into\s+\S+/i, reason: 'merge commit' },
|
|
59
|
-
|
|
60
|
-
// WIP / temporary
|
|
61
|
-
{ pattern: /^wip\b/i, reason: 'work in progress' },
|
|
62
|
-
{ pattern: /^(?:temp|tmp|todo|fixme|hack)\b/i, reason: 'temporary commit' },
|
|
63
|
-
{ pattern: /^(?:save|saving|checkpoint|backup)\b/i, reason: 'checkpoint commit' },
|
|
64
|
-
|
|
65
|
-
// Empty / trivial
|
|
66
|
-
{ pattern: /^(?:initial\s+commit|first\s+commit|init)\s*$/i, reason: 'initial commit (no content)' },
|
|
67
|
-
{ pattern: /^\.$/i, reason: 'empty message' },
|
|
68
|
-
{ pattern: /^(?:update|change|fix|edit|modify)\s*$/i, reason: 'non-descriptive message' },
|
|
69
|
-
|
|
70
|
-
// CI automation
|
|
71
|
-
{ pattern: /^\[(?:ci|cd)\s+skip\]/i, reason: 'CI skip marker' },
|
|
72
|
-
|
|
73
|
-
// Generated
|
|
74
|
-
{ pattern: /^(?:auto-?generated|generated\s+by)\b/i, reason: 'auto-generated' },
|
|
75
|
-
];
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* File patterns that indicate a commit is "lockfile-only" or "generated-only".
|
|
79
|
-
* If ALL changed files match these patterns, the commit is considered noise.
|
|
80
|
-
*/
|
|
81
|
-
const NOISE_FILE_PATTERNS: RegExp[] = [
|
|
82
|
-
/^package-lock\.json$/,
|
|
83
|
-
/^yarn\.lock$/,
|
|
84
|
-
/^pnpm-lock\.yaml$/,
|
|
85
|
-
/^Gemfile\.lock$/,
|
|
86
|
-
/^Cargo\.lock$/,
|
|
87
|
-
/^poetry\.lock$/,
|
|
88
|
-
/^composer\.lock$/,
|
|
89
|
-
/^go\.sum$/,
|
|
90
|
-
/\.min\.(js|css)$/,
|
|
91
|
-
/\.map$/, // source maps
|
|
92
|
-
/^dist\//, // build output
|
|
93
|
-
/^build\//, // build output
|
|
94
|
-
/^\.DS_Store$/,
|
|
95
|
-
/^Thumbs\.db$/,
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
// ─── Filter Logic ───
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Check if a commit is a merge commit (has 2+ parents).
|
|
102
|
-
*/
|
|
103
|
-
function isMergeCommit(commit: CommitInfo): boolean {
|
|
104
|
-
// Merge commits typically have a subject starting with "Merge"
|
|
105
|
-
return /^Merge\s+/i.test(commit.subject);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Check if ALL changed files match noise file patterns.
|
|
110
|
-
* (Commit that only touches lockfiles/generated files.)
|
|
111
|
-
*/
|
|
112
|
-
function isAllFilesNoise(files: string[], extraPatterns?: string[]): boolean {
|
|
113
|
-
if (files.length === 0) return false;
|
|
114
|
-
|
|
115
|
-
const allPatterns = [...NOISE_FILE_PATTERNS];
|
|
116
|
-
if (extraPatterns) {
|
|
117
|
-
for (const p of extraPatterns) {
|
|
118
|
-
try {
|
|
119
|
-
// Convert glob-like patterns to regex: *.lock → \.lock$, dist/* → ^dist\/
|
|
120
|
-
const escaped = p
|
|
121
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
122
|
-
.replace(/\*/g, '.*')
|
|
123
|
-
.replace(/\?/g, '.');
|
|
124
|
-
allPatterns.push(new RegExp(escaped));
|
|
125
|
-
} catch { /* invalid pattern — skip */ }
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return files.every(file =>
|
|
130
|
-
allPatterns.some(pattern => pattern.test(file)),
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Determine if a commit should be filtered out as noise.
|
|
136
|
-
*
|
|
137
|
-
* @param commit - The commit to evaluate
|
|
138
|
-
* @param config - Optional config overrides from memorix.yml git section
|
|
139
|
-
* @returns FilterResult with skip=true if the commit should be skipped
|
|
140
|
-
*/
|
|
141
|
-
export function shouldFilterCommit(
|
|
142
|
-
commit: CommitInfo,
|
|
143
|
-
config?: NoiseFilterConfig,
|
|
144
|
-
): FilterResult {
|
|
145
|
-
const skipMerge = config?.skipMergeCommits ?? true;
|
|
146
|
-
|
|
147
|
-
// 1. Merge commits
|
|
148
|
-
if (skipMerge && isMergeCommit(commit)) {
|
|
149
|
-
return { skip: true, reason: 'merge commit (git.skipMergeCommits: true)' };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 2. Built-in message pattern matching
|
|
153
|
-
for (const { pattern, reason } of NOISE_MESSAGE_PATTERNS) {
|
|
154
|
-
if (pattern.test(commit.subject)) {
|
|
155
|
-
return { skip: true, reason: `noise pattern: ${reason}` };
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// 3. User-defined noise keywords from memorix.yml
|
|
160
|
-
if (config?.noiseKeywords) {
|
|
161
|
-
for (const keyword of config.noiseKeywords) {
|
|
162
|
-
try {
|
|
163
|
-
const re = new RegExp(keyword, 'i');
|
|
164
|
-
if (re.test(commit.subject) || re.test(commit.body)) {
|
|
165
|
-
return { skip: true, reason: `user noise pattern: ${keyword}` };
|
|
166
|
-
}
|
|
167
|
-
} catch { /* invalid regex — skip */ }
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// 4. All-noise-files check (lockfile-only, generated-only commits)
|
|
172
|
-
if (commit.filesChanged.length > 0 && isAllFilesNoise(commit.filesChanged, config?.excludePatterns)) {
|
|
173
|
-
return { skip: true, reason: 'all changed files are lockfiles/generated files' };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// 5. Extremely small commits with non-descriptive messages
|
|
177
|
-
// (e.g., single-character change with vague subject)
|
|
178
|
-
if (
|
|
179
|
-
commit.insertions + commit.deletions <= 2 &&
|
|
180
|
-
commit.subject.length < 15 &&
|
|
181
|
-
!/\b(fix|feat|refactor|security|break)/i.test(commit.subject)
|
|
182
|
-
) {
|
|
183
|
-
return { skip: true, reason: 'trivial change with non-descriptive message' };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return { skip: false };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Filter an array of commits, returning only signal-worthy ones.
|
|
191
|
-
* Returns both kept and skipped with reasons (for CLI reporting).
|
|
192
|
-
*/
|
|
193
|
-
export function filterCommits(
|
|
194
|
-
commits: CommitInfo[],
|
|
195
|
-
config?: NoiseFilterConfig,
|
|
196
|
-
): { kept: CommitInfo[]; skipped: { commit: CommitInfo; reason: string }[] } {
|
|
197
|
-
const kept: CommitInfo[] = [];
|
|
198
|
-
const skipped: { commit: CommitInfo; reason: string }[] = [];
|
|
199
|
-
|
|
200
|
-
for (const commit of commits) {
|
|
201
|
-
const result = shouldFilterCommit(commit, config);
|
|
202
|
-
if (result.skip) {
|
|
203
|
-
skipped.push({ commit, reason: result.reason! });
|
|
204
|
-
} else {
|
|
205
|
-
kept.push(commit);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return { kept, skipped };
|
|
210
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Git Commit Noise Filter
|
|
3
|
+
*
|
|
4
|
+
* Filters out low-value commits that would dilute memory quality.
|
|
5
|
+
* Codex identified this as the #1 priority for Git-Memory maturity:
|
|
6
|
+
* "Not every commit is worth becoming a long-term memory."
|
|
7
|
+
*
|
|
8
|
+
* Built-in heuristics (no LLM needed):
|
|
9
|
+
* - Merge commit detection
|
|
10
|
+
* - Low-signal commit message patterns (typo, format, bump, lint, etc.)
|
|
11
|
+
* - File-only commits (only lockfiles, generated files, etc.)
|
|
12
|
+
*
|
|
13
|
+
* All thresholds are configurable via memorix.yml `git` section.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { CommitInfo } from './extractor.js';
|
|
17
|
+
|
|
18
|
+
// ─── Types ───
|
|
19
|
+
|
|
20
|
+
export interface NoiseFilterConfig {
|
|
21
|
+
/** Skip merge commits entirely (default: true) */
|
|
22
|
+
skipMergeCommits?: boolean;
|
|
23
|
+
/** File glob patterns to exclude (default: lockfiles, generated files) */
|
|
24
|
+
excludePatterns?: string[];
|
|
25
|
+
/** Additional commit message patterns to skip (regex strings) */
|
|
26
|
+
noiseKeywords?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface FilterResult {
|
|
30
|
+
/** Whether this commit should be skipped */
|
|
31
|
+
skip: boolean;
|
|
32
|
+
/** Human-readable reason for skipping */
|
|
33
|
+
reason?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ─── Built-in Noise Patterns ───
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Commit message patterns that indicate low-value commits.
|
|
40
|
+
* These are checked case-insensitively against the full subject line.
|
|
41
|
+
*/
|
|
42
|
+
const NOISE_MESSAGE_PATTERNS: { pattern: RegExp; reason: string }[] = [
|
|
43
|
+
// Typo / formatting
|
|
44
|
+
{ pattern: /^fix(?:ed)?\s*typo/i, reason: 'typo fix' },
|
|
45
|
+
{ pattern: /^typo\b/i, reason: 'typo fix' },
|
|
46
|
+
{ pattern: /^(?:fix|correct)\s*(?:spelling|grammar|whitespace|indent)/i, reason: 'formatting fix' },
|
|
47
|
+
{ pattern: /^(?:format|lint|prettier|eslint|style)\b/i, reason: 'code formatting' },
|
|
48
|
+
{ pattern: /^(?:auto-?format|code\s*style)/i, reason: 'auto-formatting' },
|
|
49
|
+
|
|
50
|
+
// Lockfile / dependency bumps
|
|
51
|
+
{ pattern: /^(?:chore|build)?\(?deps?\)?[:/]?\s*(?:bump|update|upgrade)\b/i, reason: 'dependency bump' },
|
|
52
|
+
{ pattern: /^bump\s+\S+\s+(?:from|to)\b/i, reason: 'dependency bump' },
|
|
53
|
+
{ pattern: /^(?:yarn|npm|pnpm)\s+(?:lock|update)\b/i, reason: 'lockfile update' },
|
|
54
|
+
{ pattern: /^update\s+(?:lock|yarn\.lock|package-lock)/i, reason: 'lockfile update' },
|
|
55
|
+
|
|
56
|
+
// Merge noise
|
|
57
|
+
{ pattern: /^Merge\s+(?:branch|pull\s+request|remote)/i, reason: 'merge commit' },
|
|
58
|
+
{ pattern: /^Merge\s+\S+\s+into\s+\S+/i, reason: 'merge commit' },
|
|
59
|
+
|
|
60
|
+
// WIP / temporary
|
|
61
|
+
{ pattern: /^wip\b/i, reason: 'work in progress' },
|
|
62
|
+
{ pattern: /^(?:temp|tmp|todo|fixme|hack)\b/i, reason: 'temporary commit' },
|
|
63
|
+
{ pattern: /^(?:save|saving|checkpoint|backup)\b/i, reason: 'checkpoint commit' },
|
|
64
|
+
|
|
65
|
+
// Empty / trivial
|
|
66
|
+
{ pattern: /^(?:initial\s+commit|first\s+commit|init)\s*$/i, reason: 'initial commit (no content)' },
|
|
67
|
+
{ pattern: /^\.$/i, reason: 'empty message' },
|
|
68
|
+
{ pattern: /^(?:update|change|fix|edit|modify)\s*$/i, reason: 'non-descriptive message' },
|
|
69
|
+
|
|
70
|
+
// CI automation
|
|
71
|
+
{ pattern: /^\[(?:ci|cd)\s+skip\]/i, reason: 'CI skip marker' },
|
|
72
|
+
|
|
73
|
+
// Generated
|
|
74
|
+
{ pattern: /^(?:auto-?generated|generated\s+by)\b/i, reason: 'auto-generated' },
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* File patterns that indicate a commit is "lockfile-only" or "generated-only".
|
|
79
|
+
* If ALL changed files match these patterns, the commit is considered noise.
|
|
80
|
+
*/
|
|
81
|
+
const NOISE_FILE_PATTERNS: RegExp[] = [
|
|
82
|
+
/^package-lock\.json$/,
|
|
83
|
+
/^yarn\.lock$/,
|
|
84
|
+
/^pnpm-lock\.yaml$/,
|
|
85
|
+
/^Gemfile\.lock$/,
|
|
86
|
+
/^Cargo\.lock$/,
|
|
87
|
+
/^poetry\.lock$/,
|
|
88
|
+
/^composer\.lock$/,
|
|
89
|
+
/^go\.sum$/,
|
|
90
|
+
/\.min\.(js|css)$/,
|
|
91
|
+
/\.map$/, // source maps
|
|
92
|
+
/^dist\//, // build output
|
|
93
|
+
/^build\//, // build output
|
|
94
|
+
/^\.DS_Store$/,
|
|
95
|
+
/^Thumbs\.db$/,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// ─── Filter Logic ───
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if a commit is a merge commit (has 2+ parents).
|
|
102
|
+
*/
|
|
103
|
+
function isMergeCommit(commit: CommitInfo): boolean {
|
|
104
|
+
// Merge commits typically have a subject starting with "Merge"
|
|
105
|
+
return /^Merge\s+/i.test(commit.subject);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if ALL changed files match noise file patterns.
|
|
110
|
+
* (Commit that only touches lockfiles/generated files.)
|
|
111
|
+
*/
|
|
112
|
+
function isAllFilesNoise(files: string[], extraPatterns?: string[]): boolean {
|
|
113
|
+
if (files.length === 0) return false;
|
|
114
|
+
|
|
115
|
+
const allPatterns = [...NOISE_FILE_PATTERNS];
|
|
116
|
+
if (extraPatterns) {
|
|
117
|
+
for (const p of extraPatterns) {
|
|
118
|
+
try {
|
|
119
|
+
// Convert glob-like patterns to regex: *.lock → \.lock$, dist/* → ^dist\/
|
|
120
|
+
const escaped = p
|
|
121
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
122
|
+
.replace(/\*/g, '.*')
|
|
123
|
+
.replace(/\?/g, '.');
|
|
124
|
+
allPatterns.push(new RegExp(escaped));
|
|
125
|
+
} catch { /* invalid pattern — skip */ }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return files.every(file =>
|
|
130
|
+
allPatterns.some(pattern => pattern.test(file)),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Determine if a commit should be filtered out as noise.
|
|
136
|
+
*
|
|
137
|
+
* @param commit - The commit to evaluate
|
|
138
|
+
* @param config - Optional config overrides from memorix.yml git section
|
|
139
|
+
* @returns FilterResult with skip=true if the commit should be skipped
|
|
140
|
+
*/
|
|
141
|
+
export function shouldFilterCommit(
|
|
142
|
+
commit: CommitInfo,
|
|
143
|
+
config?: NoiseFilterConfig,
|
|
144
|
+
): FilterResult {
|
|
145
|
+
const skipMerge = config?.skipMergeCommits ?? true;
|
|
146
|
+
|
|
147
|
+
// 1. Merge commits
|
|
148
|
+
if (skipMerge && isMergeCommit(commit)) {
|
|
149
|
+
return { skip: true, reason: 'merge commit (git.skipMergeCommits: true)' };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 2. Built-in message pattern matching
|
|
153
|
+
for (const { pattern, reason } of NOISE_MESSAGE_PATTERNS) {
|
|
154
|
+
if (pattern.test(commit.subject)) {
|
|
155
|
+
return { skip: true, reason: `noise pattern: ${reason}` };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 3. User-defined noise keywords from memorix.yml
|
|
160
|
+
if (config?.noiseKeywords) {
|
|
161
|
+
for (const keyword of config.noiseKeywords) {
|
|
162
|
+
try {
|
|
163
|
+
const re = new RegExp(keyword, 'i');
|
|
164
|
+
if (re.test(commit.subject) || re.test(commit.body)) {
|
|
165
|
+
return { skip: true, reason: `user noise pattern: ${keyword}` };
|
|
166
|
+
}
|
|
167
|
+
} catch { /* invalid regex — skip */ }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 4. All-noise-files check (lockfile-only, generated-only commits)
|
|
172
|
+
if (commit.filesChanged.length > 0 && isAllFilesNoise(commit.filesChanged, config?.excludePatterns)) {
|
|
173
|
+
return { skip: true, reason: 'all changed files are lockfiles/generated files' };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 5. Extremely small commits with non-descriptive messages
|
|
177
|
+
// (e.g., single-character change with vague subject)
|
|
178
|
+
if (
|
|
179
|
+
commit.insertions + commit.deletions <= 2 &&
|
|
180
|
+
commit.subject.length < 15 &&
|
|
181
|
+
!/\b(fix|feat|refactor|security|break)/i.test(commit.subject)
|
|
182
|
+
) {
|
|
183
|
+
return { skip: true, reason: 'trivial change with non-descriptive message' };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return { skip: false };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Filter an array of commits, returning only signal-worthy ones.
|
|
191
|
+
* Returns both kept and skipped with reasons (for CLI reporting).
|
|
192
|
+
*/
|
|
193
|
+
export function filterCommits(
|
|
194
|
+
commits: CommitInfo[],
|
|
195
|
+
config?: NoiseFilterConfig,
|
|
196
|
+
): { kept: CommitInfo[]; skipped: { commit: CommitInfo; reason: string }[] } {
|
|
197
|
+
const kept: CommitInfo[] = [];
|
|
198
|
+
const skipped: { commit: CommitInfo; reason: string }[] = [];
|
|
199
|
+
|
|
200
|
+
for (const commit of commits) {
|
|
201
|
+
const result = shouldFilterCommit(commit, config);
|
|
202
|
+
if (result.skip) {
|
|
203
|
+
skipped.push({ commit, reason: result.reason! });
|
|
204
|
+
} else {
|
|
205
|
+
kept.push(commit);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return { kept, skipped };
|
|
210
|
+
}
|
|
@@ -642,7 +642,7 @@ export function getGlobalConfigPath(agent: AgentName): string {
|
|
|
642
642
|
}
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
function getAgentRulesPath(agent: AgentName, root: string, global = false): string {
|
|
645
|
+
export function getAgentRulesPath(agent: AgentName, root: string, global = false): string {
|
|
646
646
|
if (global) {
|
|
647
647
|
switch (agent) {
|
|
648
648
|
case 'windsurf':
|
|
@@ -1153,8 +1153,8 @@ function getAgentRulesContent(agent?: AgentName, scope: 'project' | 'global' = '
|
|
|
1153
1153
|
? '# Memorix — Memory Tools for Active Workspaces'
|
|
1154
1154
|
: '# Memorix — Project Memory Tools';
|
|
1155
1155
|
const intro = scope === 'global'
|
|
1156
|
-
? 'Use Memorix when the active workspace has Memorix tools available and prior context would materially help. Do not assume every workspace is configured for Memorix.'
|
|
1157
|
-
: 'This repository is configured to use Memorix for persistent cross-session memory.
|
|
1156
|
+
? 'Use Memorix when the active workspace has Memorix tools available and prior context would materially help. For non-trivial coding work, Memory Autopilot is the default entry point before local progress notes or broad file exploration. Do not assume every workspace is configured for Memorix.'
|
|
1157
|
+
: 'This repository is configured to use Memorix for persistent cross-session memory. For non-trivial coding work, Memory Autopilot is the default entry point before local progress notes or broad file exploration.';
|
|
1158
1158
|
|
|
1159
1159
|
if (agent === 'windsurf') {
|
|
1160
1160
|
frontmatter = '---\ntrigger: always_on\n---\n\n';
|
|
@@ -1169,7 +1169,7 @@ function getAgentRulesContent(agent?: AgentName, scope: 'project' | 'global' = '
|
|
|
1169
1169
|
'',
|
|
1170
1170
|
'## Start with Memory Autopilot',
|
|
1171
1171
|
'',
|
|
1172
|
-
`
|
|
1172
|
+
`Default first step for non-trivial coding work: call \x60memorix_project_context\x60 with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
1173
1173
|
'',
|
|
1174
1174
|
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select \x60memorix_project_context\x60 first. Run \x60memorix context --task "<task>"\x60 only after MCP is unavailable, disabled, or not discoverable, and pass the user\'s real task text. Do not skip memory, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
1175
1175
|
'',
|
|
@@ -42,7 +42,7 @@ export const OFFICIAL_MEMORIX_SKILLS: OfficialMemorixSkill[] = [
|
|
|
42
42
|
'',
|
|
43
43
|
'## Search Rules',
|
|
44
44
|
'',
|
|
45
|
-
'-
|
|
45
|
+
'- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user\'s actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.',
|
|
46
46
|
'- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client\'s tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.',
|
|
47
47
|
'- Run `memorix context --task "<task>"` from the shell only after MCP is unavailable, disabled, or not discoverable, and pass the user\'s real task text. Do not skip memory, wait indefinitely on `pending`, or hand-write tool-call syntax.',
|
|
48
48
|
'- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer.',
|