@coreyuan/vector-mind 1.0.49 → 1.0.53

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 (123) hide show
  1. package/README.md +67 -61
  2. package/dist/activity-log.d.ts +19 -0
  3. package/dist/activity-log.js +106 -0
  4. package/dist/activity-log.js.map +1 -0
  5. package/dist/builtin-conventions.d.ts +2 -1
  6. package/dist/builtin-conventions.js +5 -0
  7. package/dist/builtin-conventions.js.map +1 -1
  8. package/dist/config.d.ts +28 -0
  9. package/dist/config.js +189 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/database-runtime.d.ts +54 -0
  12. package/dist/database-runtime.js +512 -0
  13. package/dist/database-runtime.js.map +1 -0
  14. package/dist/development-warnings.d.ts +93 -0
  15. package/dist/development-warnings.js +589 -0
  16. package/dist/development-warnings.js.map +1 -0
  17. package/dist/file-indexing.d.ts +22 -0
  18. package/dist/file-indexing.js +243 -0
  19. package/dist/file-indexing.js.map +1 -0
  20. package/dist/fix-patterns.d.ts +58 -0
  21. package/dist/fix-patterns.js +347 -0
  22. package/dist/fix-patterns.js.map +1 -0
  23. package/dist/grep.d.ts +64 -0
  24. package/dist/grep.js +475 -0
  25. package/dist/grep.js.map +1 -0
  26. package/dist/index.js +167 -7279
  27. package/dist/index.js.map +1 -1
  28. package/dist/large-file-split.d.ts +29 -0
  29. package/dist/large-file-split.js +146 -0
  30. package/dist/large-file-split.js.map +1 -0
  31. package/dist/memory-maintenance.d.ts +80 -0
  32. package/dist/memory-maintenance.js +537 -0
  33. package/dist/memory-maintenance.js.map +1 -0
  34. package/dist/memory-mutations.d.ts +23 -0
  35. package/dist/memory-mutations.js +83 -0
  36. package/dist/memory-mutations.js.map +1 -0
  37. package/dist/memory-recall.d.ts +93 -0
  38. package/dist/memory-recall.js +801 -0
  39. package/dist/memory-recall.js.map +1 -0
  40. package/dist/operation-scope.d.ts +63 -0
  41. package/dist/operation-scope.js +438 -0
  42. package/dist/operation-scope.js.map +1 -0
  43. package/dist/path-filters.d.ts +1 -0
  44. package/dist/path-filters.js +27 -0
  45. package/dist/path-filters.js.map +1 -0
  46. package/dist/path-rules.d.ts +12 -0
  47. package/dist/path-rules.js +208 -0
  48. package/dist/path-rules.js.map +1 -0
  49. package/dist/pending-changes.d.ts +22 -0
  50. package/dist/pending-changes.js +166 -0
  51. package/dist/pending-changes.js.map +1 -0
  52. package/dist/project-files.d.ts +66 -0
  53. package/dist/project-files.js +215 -0
  54. package/dist/project-files.js.map +1 -0
  55. package/dist/root.d.ts +15 -0
  56. package/dist/root.js +191 -0
  57. package/dist/root.js.map +1 -0
  58. package/dist/rtk-tools.d.ts +20 -0
  59. package/dist/rtk-tools.js +318 -0
  60. package/dist/rtk-tools.js.map +1 -0
  61. package/dist/server-instructions.d.ts +1 -0
  62. package/dist/server-instructions.js +92 -0
  63. package/dist/server-instructions.js.map +1 -0
  64. package/dist/symbols.d.ts +2 -0
  65. package/dist/symbols.js +159 -0
  66. package/dist/symbols.js.map +1 -0
  67. package/dist/token-savings.d.ts +40 -0
  68. package/dist/token-savings.js +50 -0
  69. package/dist/token-savings.js.map +1 -0
  70. package/dist/tool-catalog.d.ts +18 -0
  71. package/dist/tool-catalog.js +249 -0
  72. package/dist/tool-catalog.js.map +1 -0
  73. package/dist/tool-handlers/context-recovery.d.ts +6 -0
  74. package/dist/tool-handlers/context-recovery.js +319 -0
  75. package/dist/tool-handlers/context-recovery.js.map +1 -0
  76. package/dist/tool-handlers/context.d.ts +34 -0
  77. package/dist/tool-handlers/context.js +2 -0
  78. package/dist/tool-handlers/context.js.map +1 -0
  79. package/dist/tool-handlers/diagnostics.d.ts +8 -0
  80. package/dist/tool-handlers/diagnostics.js +114 -0
  81. package/dist/tool-handlers/diagnostics.js.map +1 -0
  82. package/dist/tool-handlers/files.d.ts +8 -0
  83. package/dist/tool-handlers/files.js +493 -0
  84. package/dist/tool-handlers/files.js.map +1 -0
  85. package/dist/tool-handlers/large-files.d.ts +4 -0
  86. package/dist/tool-handlers/large-files.js +139 -0
  87. package/dist/tool-handlers/large-files.js.map +1 -0
  88. package/dist/tool-handlers/maintenance.d.ts +4 -0
  89. package/dist/tool-handlers/maintenance.js +160 -0
  90. package/dist/tool-handlers/maintenance.js.map +1 -0
  91. package/dist/tool-handlers/memory-diagnostics.d.ts +5 -0
  92. package/dist/tool-handlers/memory-diagnostics.js +558 -0
  93. package/dist/tool-handlers/memory-diagnostics.js.map +1 -0
  94. package/dist/tool-handlers/memory.d.ts +6 -0
  95. package/dist/tool-handlers/memory.js +352 -0
  96. package/dist/tool-handlers/memory.js.map +1 -0
  97. package/dist/tool-handlers/notes-decisions.d.ts +7 -0
  98. package/dist/tool-handlers/notes-decisions.js +169 -0
  99. package/dist/tool-handlers/notes-decisions.js.map +1 -0
  100. package/dist/tool-handlers/operations.d.ts +4 -0
  101. package/dist/tool-handlers/operations.js +62 -0
  102. package/dist/tool-handlers/operations.js.map +1 -0
  103. package/dist/tool-handlers/requirements.d.ts +7 -0
  104. package/dist/tool-handlers/requirements.js +399 -0
  105. package/dist/tool-handlers/requirements.js.map +1 -0
  106. package/dist/tool-handlers.d.ts +4 -0
  107. package/dist/tool-handlers.js +107 -0
  108. package/dist/tool-handlers.js.map +1 -0
  109. package/dist/tool-output.d.ts +266 -0
  110. package/dist/tool-output.js +328 -0
  111. package/dist/tool-output.js.map +1 -0
  112. package/dist/tool-schemas.d.ts +460 -0
  113. package/dist/tool-schemas.js +350 -0
  114. package/dist/tool-schemas.js.map +1 -0
  115. package/dist/types.d.ts +61 -0
  116. package/dist/types.js +2 -0
  117. package/dist/types.js.map +1 -0
  118. package/docs/capability-matrix.md +43 -0
  119. package/package.json +11 -10
  120. package/skills/vector-mind-autopilot/SKILL.md +173 -0
  121. package/skills/vector-mind-autopilot/references/claude-desktop-mcp-config.json +9 -0
  122. package/skills/vector-mind-autopilot/references/claude-project-instructions.md +51 -0
  123. package/skills/vector-mind-autopilot/references/universal-system-prompt.md +81 -0
@@ -0,0 +1,243 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { INDEX_MAX_CODE_BYTES, INDEX_MAX_DOC_BYTES, INDEX_SKIP_MINIFIED, PENDING_FLUSH_MS, PENDING_PRUNE_EVERY, } from "./config.js";
4
+ import { getContentChunkKind, isContentIndexableFile, isSymbolIndexableFile, looksLikeGeneratedFile, looksLikeMinifiedBundle, shouldIgnorePath, } from "./path-rules.js";
5
+ import { extractSymbols } from "./symbols.js";
6
+ import { logActivity } from "./activity-log.js";
7
+ import { safeJson } from "./tool-output.js";
8
+ let fileIndexingContext = null;
9
+ const pendingChangeBuffer = new Map();
10
+ let pendingChangeFlushTimer = null;
11
+ let pendingEventsSincePrune = 0;
12
+ export function configureFileIndexing(context) {
13
+ fileIndexingContext = context;
14
+ }
15
+ function requireFileIndexingContext() {
16
+ if (!fileIndexingContext)
17
+ throw new Error("[VectorMind] file indexing context is not configured");
18
+ return fileIndexingContext;
19
+ }
20
+ function hasDb() {
21
+ return !!requireFileIndexingContext().getDb();
22
+ }
23
+ function getDb() {
24
+ const db = requireFileIndexingContext().getDb();
25
+ if (!db)
26
+ throw new Error("[VectorMind] database is not initialized");
27
+ return db;
28
+ }
29
+ function getProjectRoot() {
30
+ return requireFileIndexingContext().getProjectRoot();
31
+ }
32
+ function normalizeToDbPath(inputPath) {
33
+ return requireFileIndexingContext().normalizeToDbPath(inputPath);
34
+ }
35
+ function getIndexFileSymbolsTx() {
36
+ return requireFileIndexingContext().getIndexFileSymbolsTx();
37
+ }
38
+ function getDeleteFileChunkItemsStatement() {
39
+ return requireFileIndexingContext().getDeleteFileChunkItemsStatement();
40
+ }
41
+ function getInsertMemoryItemStatement() {
42
+ return requireFileIndexingContext().getInsertMemoryItemStatement();
43
+ }
44
+ function getUpsertPendingChangeStatement() {
45
+ return requireFileIndexingContext().getUpsertPendingChangeStatement();
46
+ }
47
+ function getDeleteSymbolsForFileStatement() {
48
+ return requireFileIndexingContext().getDeleteSymbolsForFileStatement();
49
+ }
50
+ function sha256Hex(input) {
51
+ return requireFileIndexingContext().sha256Hex(input);
52
+ }
53
+ function prunePendingChanges() {
54
+ requireFileIndexingContext().prunePendingChanges();
55
+ }
56
+ function chunkTextByLines(content, opts) {
57
+ const lines = content.split(/\r?\n/);
58
+ if (lines.length === 0)
59
+ return [];
60
+ const chunks = [];
61
+ let startLine = 1;
62
+ let currentLines = [];
63
+ let currentChars = 0;
64
+ for (let idx = 0; idx < lines.length; idx++) {
65
+ const line = lines[idx];
66
+ const nextChars = currentChars + line.length + 1;
67
+ const nextLines = currentLines.length + 1;
68
+ if (currentLines.length > 0 && (nextChars > opts.maxChars || nextLines > opts.maxLines)) {
69
+ const endLine = startLine + currentLines.length - 1;
70
+ chunks.push({ startLine, endLine, content: currentLines.join("\n") });
71
+ startLine = idx + 1;
72
+ currentLines = [];
73
+ currentChars = 0;
74
+ }
75
+ currentLines.push(line);
76
+ currentChars += line.length + 1;
77
+ }
78
+ if (currentLines.length > 0) {
79
+ const endLine = startLine + currentLines.length - 1;
80
+ chunks.push({ startLine, endLine, content: currentLines.join("\n") });
81
+ }
82
+ return chunks;
83
+ }
84
+ function indexFileContentChunks(dbFilePath, absPath, content) {
85
+ const kind = getContentChunkKind(absPath);
86
+ if (!kind)
87
+ return 0;
88
+ const opts = kind === "code_chunk"
89
+ ? { maxChars: 10_000, maxLines: 200 }
90
+ : { maxChars: 14_000, maxLines: 260 };
91
+ const chunks = chunkTextByLines(content, opts);
92
+ const ext = path.extname(absPath).toLowerCase();
93
+ const metadata = safeJson({ ext });
94
+ const tx = getDb().transaction(() => {
95
+ getDeleteFileChunkItemsStatement().run(dbFilePath);
96
+ for (const chunk of chunks) {
97
+ const title = `${dbFilePath}#L${chunk.startLine}-L${chunk.endLine}`;
98
+ const contentHash = sha256Hex(chunk.content);
99
+ getInsertMemoryItemStatement().run(kind, title, chunk.content, dbFilePath, chunk.startLine, chunk.endLine, null, metadata, contentHash);
100
+ }
101
+ });
102
+ try {
103
+ tx();
104
+ }
105
+ catch (err) {
106
+ console.error("[vectormind] failed to index file chunks:", dbFilePath, err);
107
+ }
108
+ return chunks.length;
109
+ }
110
+ export function flushPendingChangeBuffer() {
111
+ if (!hasDb())
112
+ return;
113
+ if (pendingChangeFlushTimer) {
114
+ clearTimeout(pendingChangeFlushTimer);
115
+ pendingChangeFlushTimer = null;
116
+ }
117
+ if (!pendingChangeBuffer.size)
118
+ return;
119
+ const entries = Array.from(pendingChangeBuffer.entries());
120
+ pendingChangeBuffer.clear();
121
+ try {
122
+ const tx = getDb().transaction(() => {
123
+ for (const [filePath, event] of entries) {
124
+ getUpsertPendingChangeStatement().run(filePath, event);
125
+ }
126
+ });
127
+ tx();
128
+ }
129
+ catch (err) {
130
+ console.error("[vectormind] failed to flush pending change buffer:", err);
131
+ }
132
+ logActivity("pending_flush", {
133
+ entries: entries.length,
134
+ sample: entries.slice(0, 10).map(([file_path, last_event]) => ({ file_path, last_event })),
135
+ });
136
+ pendingEventsSincePrune += entries.length;
137
+ if (pendingEventsSincePrune >= PENDING_PRUNE_EVERY) {
138
+ pendingEventsSincePrune = 0;
139
+ prunePendingChanges();
140
+ }
141
+ }
142
+ export function recordPendingChange(absPath, event) {
143
+ if (shouldIgnorePath(absPath, getProjectRoot()))
144
+ return;
145
+ const track = isSymbolIndexableFile(absPath) || isContentIndexableFile(absPath);
146
+ if (!track)
147
+ return;
148
+ const filePath = normalizeToDbPath(absPath);
149
+ pendingChangeBuffer.set(filePath, event);
150
+ if (pendingChangeFlushTimer)
151
+ return;
152
+ if (PENDING_FLUSH_MS === 0) {
153
+ flushPendingChangeBuffer();
154
+ return;
155
+ }
156
+ pendingChangeFlushTimer = setTimeout(flushPendingChangeBuffer, PENDING_FLUSH_MS);
157
+ }
158
+ export function indexFile(absPath, reason) {
159
+ if (shouldIgnorePath(absPath, getProjectRoot()))
160
+ return;
161
+ const indexSymbols = isSymbolIndexableFile(absPath);
162
+ const indexContent = isContentIndexableFile(absPath);
163
+ if (!indexSymbols && !indexContent)
164
+ return;
165
+ const kind = getContentChunkKind(absPath);
166
+ if (!kind)
167
+ return;
168
+ let stat;
169
+ try {
170
+ stat = fs.statSync(absPath);
171
+ }
172
+ catch {
173
+ return;
174
+ }
175
+ if (!stat.isFile())
176
+ return;
177
+ const maxBytes = kind === "code_chunk" ? INDEX_MAX_CODE_BYTES : INDEX_MAX_DOC_BYTES;
178
+ if (maxBytes > 0 && stat.size > maxBytes)
179
+ return;
180
+ let content;
181
+ try {
182
+ content = fs.readFileSync(absPath, "utf8");
183
+ }
184
+ catch {
185
+ return;
186
+ }
187
+ if (content.includes("\u0000"))
188
+ return;
189
+ const ext = path.extname(absPath).toLowerCase();
190
+ const filePath = normalizeToDbPath(absPath);
191
+ if (INDEX_SKIP_MINIFIED &&
192
+ kind === "code_chunk" &&
193
+ (ext === ".js" || ext === ".mjs" || ext === ".cjs" || ext === ".css") &&
194
+ looksLikeMinifiedBundle(content)) {
195
+ logActivity("index_skip", { file_path: filePath, reason: "minified_bundle", bytes: stat.size });
196
+ return;
197
+ }
198
+ if (kind === "code_chunk" && stat.size >= 20_000 && looksLikeGeneratedFile(content)) {
199
+ logActivity("index_skip", { file_path: filePath, reason: "generated_file", bytes: stat.size });
200
+ return;
201
+ }
202
+ let symbolCount = 0;
203
+ let chunkCount = 0;
204
+ if (indexSymbols) {
205
+ const symbols = extractSymbols(absPath, content);
206
+ symbolCount = symbols.length;
207
+ try {
208
+ getIndexFileSymbolsTx()?.(filePath, symbols);
209
+ }
210
+ catch (err) {
211
+ console.error("[vectormind] failed to index symbols:", filePath, err);
212
+ }
213
+ }
214
+ if (indexContent) {
215
+ chunkCount = indexFileContentChunks(filePath, absPath, content);
216
+ }
217
+ logActivity("index_file", {
218
+ file_path: filePath,
219
+ reason,
220
+ symbols: symbolCount,
221
+ chunks: chunkCount,
222
+ bytes: stat.size,
223
+ });
224
+ }
225
+ export function removeFileIndexes(absPath) {
226
+ if (shouldIgnorePath(absPath, getProjectRoot()))
227
+ return;
228
+ const filePath = normalizeToDbPath(absPath);
229
+ try {
230
+ getDeleteSymbolsForFileStatement().run(filePath);
231
+ }
232
+ catch (err) {
233
+ console.error("[vectormind] failed to remove symbols:", filePath, err);
234
+ }
235
+ try {
236
+ getDeleteFileChunkItemsStatement().run(filePath);
237
+ }
238
+ catch (err) {
239
+ console.error("[vectormind] failed to remove file chunks:", filePath, err);
240
+ }
241
+ logActivity("remove_file", { file_path: filePath });
242
+ }
243
+ //# sourceMappingURL=file-indexing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-indexing.js","sourceRoot":"","sources":["../src/file-indexing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { ToolHandlerContext } from "./tool-handlers/context.js";
2
+ import type { MemoryItemRow, RequirementRow } from "./types.js";
3
+ export type FixPatternInput = {
4
+ symptom: string;
5
+ root_cause: string;
6
+ invariant: string;
7
+ applies_when?: string[];
8
+ avoid_regression?: string[];
9
+ verification?: string[];
10
+ verification_gaps?: string[];
11
+ };
12
+ export type FixPatternMatchInput = {
13
+ intent?: string;
14
+ files?: string[];
15
+ planned_changes?: Array<{
16
+ file?: string;
17
+ change?: string;
18
+ requirement_refs?: string[];
19
+ }>;
20
+ requirement?: RequirementRow | null;
21
+ limit?: number;
22
+ candidateLimit?: number;
23
+ };
24
+ export type RelevantFixPattern = {
25
+ memory_id: number;
26
+ symptom: string;
27
+ root_cause: string;
28
+ invariant: string;
29
+ applies_when: string[];
30
+ avoid_regression: string[];
31
+ relevance_score: number;
32
+ reason: string;
33
+ updated_at: string;
34
+ };
35
+ export type FixPatternQualitySignals = {
36
+ advisory_only: true;
37
+ does_not_control_model_reasoning: true;
38
+ does_not_control_host_runtime: true;
39
+ does_not_replace_model_judgment: true;
40
+ does_not_change_ok_or_safe_to_edit: true;
41
+ does_not_expand_requirement_scope: true;
42
+ relevant_fix_patterns: RelevantFixPattern[];
43
+ note: string;
44
+ };
45
+ export declare function normalizeFixPattern(input: FixPatternInput): FixPatternInput;
46
+ export declare function buildFixPatternContent(pattern: FixPatternInput, intent: string, files: string[]): string;
47
+ export declare function buildFixPatternMetadata(args: {
48
+ pattern: FixPatternInput;
49
+ intent: string;
50
+ files: string[];
51
+ requirement_id: number;
52
+ source_change_ids: number[];
53
+ verification?: string[];
54
+ verification_gaps?: string[];
55
+ }): string | null;
56
+ export declare function fixPatternFromRow(row: MemoryItemRow): FixPatternInput | null;
57
+ export declare function collectRelevantFixPatterns(context: ToolHandlerContext, input: FixPatternMatchInput): RelevantFixPattern[];
58
+ export declare function buildFixPatternQualitySignals(relevant: RelevantFixPattern[]): FixPatternQualitySignals;
@@ -0,0 +1,347 @@
1
+ import { isHiddenFromDefaultRecall, parseMetadataJson } from "./memory-recall.js";
2
+ import { oneLine, safeJson } from "./tool-output.js";
3
+ const STOPWORDS = new Set([
4
+ "a",
5
+ "an",
6
+ "and",
7
+ "are",
8
+ "as",
9
+ "at",
10
+ "be",
11
+ "by",
12
+ "for",
13
+ "from",
14
+ "has",
15
+ "have",
16
+ "if",
17
+ "in",
18
+ "into",
19
+ "is",
20
+ "it",
21
+ "its",
22
+ "of",
23
+ "on",
24
+ "or",
25
+ "that",
26
+ "the",
27
+ "this",
28
+ "to",
29
+ "with",
30
+ "add",
31
+ "change",
32
+ "changed",
33
+ "changing",
34
+ "fix",
35
+ "path",
36
+ "paths",
37
+ "refresh",
38
+ "smoke",
39
+ "test",
40
+ "update",
41
+ ]);
42
+ const GENERIC_PATH_SEGMENTS = new Set([
43
+ "src",
44
+ "lib",
45
+ "app",
46
+ "core",
47
+ "test",
48
+ "tests",
49
+ "spec",
50
+ "specs",
51
+ "ts",
52
+ "tsx",
53
+ "js",
54
+ "jsx",
55
+ "mjs",
56
+ "cjs",
57
+ "rs",
58
+ "go",
59
+ "py",
60
+ "cs",
61
+ "java",
62
+ "kt",
63
+ "php",
64
+ "rb",
65
+ "md",
66
+ ]);
67
+ function normalizeText(input) {
68
+ return (input ?? "").normalize("NFKC").toLowerCase();
69
+ }
70
+ function cleanList(values, limit = 8) {
71
+ if (!Array.isArray(values))
72
+ return [];
73
+ const result = [];
74
+ for (const raw of values) {
75
+ if (typeof raw !== "string")
76
+ continue;
77
+ const value = raw.replace(/\s+/g, " ").trim();
78
+ if (!value)
79
+ continue;
80
+ result.push(value);
81
+ if (result.length >= limit)
82
+ break;
83
+ }
84
+ return result;
85
+ }
86
+ export function normalizeFixPattern(input) {
87
+ return {
88
+ symptom: input.symptom.replace(/\s+/g, " ").trim(),
89
+ root_cause: input.root_cause.replace(/\s+/g, " ").trim(),
90
+ invariant: input.invariant.replace(/\s+/g, " ").trim(),
91
+ applies_when: cleanList(input.applies_when),
92
+ avoid_regression: cleanList(input.avoid_regression),
93
+ verification: cleanList(input.verification),
94
+ verification_gaps: cleanList(input.verification_gaps),
95
+ };
96
+ }
97
+ export function buildFixPatternContent(pattern, intent, files) {
98
+ const p = normalizeFixPattern(pattern);
99
+ const lines = [
100
+ "Fix pattern advisory memory.",
101
+ "",
102
+ `Symptom: ${p.symptom}`,
103
+ `Root cause: ${p.root_cause}`,
104
+ `Invariant: ${p.invariant}`,
105
+ ];
106
+ if (p.applies_when?.length) {
107
+ lines.push("", "Applies when:");
108
+ for (const item of p.applies_when)
109
+ lines.push(`- ${item}`);
110
+ }
111
+ if (p.avoid_regression?.length) {
112
+ lines.push("", "Avoid regression:");
113
+ for (const item of p.avoid_regression)
114
+ lines.push(`- ${item}`);
115
+ }
116
+ if (p.verification?.length) {
117
+ lines.push("", "Verified:");
118
+ for (const item of p.verification)
119
+ lines.push(`- ${item}`);
120
+ }
121
+ if (p.verification_gaps?.length) {
122
+ lines.push("", "Verification gaps:");
123
+ for (const item of p.verification_gaps)
124
+ lines.push(`- ${item}`);
125
+ }
126
+ if (files.length) {
127
+ lines.push("", "Source files:");
128
+ for (const file of files.slice(0, 20))
129
+ lines.push(`- ${file}`);
130
+ }
131
+ lines.push("", `Source change intent: ${intent}`);
132
+ lines.push("", "Boundary: advisory quality signal only; do not expand the current requirement scope based only on this memory.");
133
+ return lines.join("\n");
134
+ }
135
+ export function buildFixPatternMetadata(args) {
136
+ const pattern = normalizeFixPattern({
137
+ ...args.pattern,
138
+ verification: args.pattern.verification?.length ? args.pattern.verification : args.verification,
139
+ verification_gaps: args.pattern.verification_gaps?.length
140
+ ? args.pattern.verification_gaps
141
+ : args.verification_gaps,
142
+ });
143
+ return safeJson({
144
+ status: "current",
145
+ memory_type: "fix_pattern",
146
+ advisory_only: true,
147
+ does_not_control_model_reasoning: true,
148
+ does_not_control_host_runtime: true,
149
+ does_not_replace_model_judgment: true,
150
+ does_not_change_ok_or_safe_to_edit: true,
151
+ does_not_expand_requirement_scope: true,
152
+ requirement_id: args.requirement_id,
153
+ source_change_ids: args.source_change_ids,
154
+ source_files: args.files,
155
+ source_intent_preview: oneLine(args.intent, 240),
156
+ fix_pattern: pattern,
157
+ });
158
+ }
159
+ function extractTokens(raw) {
160
+ const text = normalizeText(raw);
161
+ const tokens = new Set();
162
+ for (const token of text.match(/[a-z0-9_./:@#-]{2,}/g) ?? []) {
163
+ if (!STOPWORDS.has(token))
164
+ tokens.add(token);
165
+ for (const part of token.split(/[^a-z0-9]+/).filter((p) => p.length >= 2)) {
166
+ if (!STOPWORDS.has(part))
167
+ tokens.add(part);
168
+ }
169
+ }
170
+ for (const seq of text.match(/\p{Script=Han}+/gu) ?? []) {
171
+ if (seq.length >= 2 && seq.length <= 18)
172
+ tokens.add(seq);
173
+ for (const n of [2, 3, 4]) {
174
+ if (seq.length < n)
175
+ continue;
176
+ for (let i = 0; i <= seq.length - n; i++)
177
+ tokens.add(seq.slice(i, i + n));
178
+ }
179
+ }
180
+ return Array.from(tokens)
181
+ .filter((token) => token.length >= 2 && !STOPWORDS.has(token))
182
+ .sort((a, b) => b.length - a.length)
183
+ .slice(0, 80);
184
+ }
185
+ function pathSegments(paths) {
186
+ const result = new Set();
187
+ for (const path of paths) {
188
+ const normalized = normalizeText(path).replaceAll("\\", "/");
189
+ for (const part of normalized.split(/[/.#:_-]+/)) {
190
+ if (part.length >= 2 && !STOPWORDS.has(part) && !GENERIC_PATH_SEGMENTS.has(part))
191
+ result.add(part);
192
+ }
193
+ if (normalized && normalized.split("/").length > 1)
194
+ result.add(normalized);
195
+ }
196
+ return result;
197
+ }
198
+ function recencyWeight(updatedAt) {
199
+ const t = Date.parse(updatedAt.endsWith("Z") ? updatedAt : `${updatedAt}Z`);
200
+ if (!Number.isFinite(t))
201
+ return 0;
202
+ const ageDays = Math.max(0, (Date.now() - t) / 86_400_000);
203
+ if (ageDays <= 2)
204
+ return 1.2;
205
+ if (ageDays <= 14)
206
+ return 0.7;
207
+ if (ageDays <= 60)
208
+ return 0.35;
209
+ return 0;
210
+ }
211
+ export function fixPatternFromRow(row) {
212
+ const meta = parseMetadataJson(row.metadata_json);
213
+ const raw = meta.fix_pattern;
214
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
215
+ return null;
216
+ const obj = raw;
217
+ if (typeof obj.symptom !== "string" ||
218
+ typeof obj.root_cause !== "string" ||
219
+ typeof obj.invariant !== "string") {
220
+ return null;
221
+ }
222
+ return normalizeFixPattern({
223
+ symptom: obj.symptom,
224
+ root_cause: obj.root_cause,
225
+ invariant: obj.invariant,
226
+ applies_when: cleanList(obj.applies_when),
227
+ avoid_regression: cleanList(obj.avoid_regression),
228
+ verification: cleanList(obj.verification),
229
+ verification_gaps: cleanList(obj.verification_gaps),
230
+ });
231
+ }
232
+ function matchInputText(input) {
233
+ const planned = (input.planned_changes ?? [])
234
+ .map((change) => `${change.change ?? ""} ${(change.requirement_refs ?? []).join(" ")}`)
235
+ .join("\n");
236
+ return [
237
+ input.intent ?? "",
238
+ planned,
239
+ input.intent || input.files?.length || planned ? "" : input.requirement?.title ?? "",
240
+ input.intent || input.files?.length || planned ? "" : input.requirement?.context_data ?? "",
241
+ ].join("\n");
242
+ }
243
+ function rowText(row, pattern) {
244
+ const meta = parseMetadataJson(row.metadata_json);
245
+ const sourceFiles = cleanList(meta.source_files, 40);
246
+ return [
247
+ row.title ?? "",
248
+ row.content,
249
+ pattern.symptom,
250
+ pattern.root_cause,
251
+ pattern.invariant,
252
+ pattern.applies_when?.join("\n") ?? "",
253
+ pattern.avoid_regression?.join("\n") ?? "",
254
+ ].join("\n");
255
+ }
256
+ function scoreFixPattern(row, pattern, input) {
257
+ const inputText = matchInputText(input);
258
+ const queryTokens = extractTokens(inputText);
259
+ if (!queryTokens.length)
260
+ return { score: 0, reasonParts: [] };
261
+ const rowNormalized = normalizeText(rowText(row, pattern));
262
+ let tokenMatches = 0;
263
+ let score = 0;
264
+ for (const token of queryTokens) {
265
+ if (!rowNormalized.includes(token))
266
+ continue;
267
+ tokenMatches += 1;
268
+ score += Math.min(3.2, Math.max(0.8, token.length / 3));
269
+ }
270
+ const inputPaths = pathSegments(input.files ?? []);
271
+ const meta = parseMetadataJson(row.metadata_json);
272
+ const sourceFiles = cleanList(meta.source_files, 40);
273
+ const sourcePathSegments = pathSegments(sourceFiles);
274
+ let pathMatches = 0;
275
+ for (const segment of inputPaths) {
276
+ if (sourcePathSegments.has(segment))
277
+ pathMatches += 1;
278
+ }
279
+ if (pathMatches)
280
+ score += Math.min(8, pathMatches * 2.2);
281
+ if (tokenMatches >= Math.min(3, queryTokens.length))
282
+ score += 2;
283
+ score += recencyWeight(row.updated_at);
284
+ const reasonParts = [];
285
+ if (tokenMatches)
286
+ reasonParts.push(`${tokenMatches} text tokens`);
287
+ if (pathMatches)
288
+ reasonParts.push(`${pathMatches} path terms`);
289
+ if (row.updated_at)
290
+ reasonParts.push("recentness considered");
291
+ return { score, reasonParts };
292
+ }
293
+ export function collectRelevantFixPatterns(context, input) {
294
+ const text = matchInputText(input).trim();
295
+ if (!text)
296
+ return [];
297
+ const limit = Math.max(0, Math.min(3, input.limit ?? 3));
298
+ if (limit <= 0)
299
+ return [];
300
+ const candidateLimit = Math.max(limit, Math.min(50, input.candidateLimit ?? 50));
301
+ const rows = context
302
+ .getDb()
303
+ .prepare(`SELECT id, kind, title, content, file_path, start_line, end_line, req_id, metadata_json, content_hash, created_at, updated_at
304
+ FROM memory_items
305
+ WHERE kind = 'fix_pattern'
306
+ ORDER BY updated_at DESC, id DESC
307
+ LIMIT ?`)
308
+ .all(candidateLimit);
309
+ const matches = rows
310
+ .filter((row) => !isHiddenFromDefaultRecall(row))
311
+ .map((row) => {
312
+ const pattern = fixPatternFromRow(row);
313
+ if (!pattern)
314
+ return null;
315
+ const { score, reasonParts } = scoreFixPattern(row, pattern, input);
316
+ if (score < 11)
317
+ return null;
318
+ return {
319
+ memory_id: row.id,
320
+ symptom: pattern.symptom,
321
+ root_cause: pattern.root_cause,
322
+ invariant: pattern.invariant,
323
+ applies_when: pattern.applies_when ?? [],
324
+ avoid_regression: pattern.avoid_regression ?? [],
325
+ relevance_score: Number(score.toFixed(2)),
326
+ reason: `Matched current intent/files against prior explicit fix_pattern memory (${reasonParts.join(", ") || "lexical overlap"}). Advisory only; do not expand current requirement scope from this signal.`,
327
+ updated_at: row.updated_at,
328
+ };
329
+ })
330
+ .filter((item) => item !== null)
331
+ .sort((a, b) => b.relevance_score - a.relevance_score || b.memory_id - a.memory_id)
332
+ .slice(0, limit);
333
+ return matches;
334
+ }
335
+ export function buildFixPatternQualitySignals(relevant) {
336
+ return {
337
+ advisory_only: true,
338
+ does_not_control_model_reasoning: true,
339
+ does_not_control_host_runtime: true,
340
+ does_not_replace_model_judgment: true,
341
+ does_not_change_ok_or_safe_to_edit: true,
342
+ does_not_expand_requirement_scope: true,
343
+ relevant_fix_patterns: relevant,
344
+ note: "Fix pattern matches are historical quality reminders only. They must not block work, change ok/safe flags, control host execution, or expand the current requirement scope.",
345
+ };
346
+ }
347
+ //# sourceMappingURL=fix-patterns.js.map