@neurcode-ai/cli 0.9.48 → 0.9.50

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 (78) hide show
  1. package/dist/commands/fix.d.ts +13 -0
  2. package/dist/commands/fix.d.ts.map +1 -0
  3. package/dist/commands/fix.js +785 -0
  4. package/dist/commands/fix.js.map +1 -0
  5. package/dist/commands/generate.d.ts +7 -0
  6. package/dist/commands/generate.d.ts.map +1 -0
  7. package/dist/commands/generate.js +132 -0
  8. package/dist/commands/generate.js.map +1 -0
  9. package/dist/commands/patch-apply.d.ts +7 -0
  10. package/dist/commands/patch-apply.d.ts.map +1 -0
  11. package/dist/commands/patch-apply.js +85 -0
  12. package/dist/commands/patch-apply.js.map +1 -0
  13. package/dist/commands/plan-show.d.ts +6 -0
  14. package/dist/commands/plan-show.d.ts.map +1 -0
  15. package/dist/commands/plan-show.js +33 -0
  16. package/dist/commands/plan-show.js.map +1 -0
  17. package/dist/commands/start-intent.d.ts +6 -0
  18. package/dist/commands/start-intent.d.ts.map +1 -0
  19. package/dist/commands/start-intent.js +80 -0
  20. package/dist/commands/start-intent.js.map +1 -0
  21. package/dist/commands/verify.d.ts.map +1 -1
  22. package/dist/commands/verify.js +703 -186
  23. package/dist/commands/verify.js.map +1 -1
  24. package/dist/context-engine/graph.d.ts +6 -0
  25. package/dist/context-engine/graph.d.ts.map +1 -0
  26. package/dist/context-engine/graph.js +55 -0
  27. package/dist/context-engine/graph.js.map +1 -0
  28. package/dist/context-engine/index.d.ts +14 -0
  29. package/dist/context-engine/index.d.ts.map +1 -0
  30. package/dist/context-engine/index.js +26 -0
  31. package/dist/context-engine/index.js.map +1 -0
  32. package/dist/context-engine/scanner.d.ts +6 -0
  33. package/dist/context-engine/scanner.d.ts.map +1 -0
  34. package/dist/context-engine/scanner.js +62 -0
  35. package/dist/context-engine/scanner.js.map +1 -0
  36. package/dist/context-engine/scorer.d.ts +9 -0
  37. package/dist/context-engine/scorer.d.ts.map +1 -0
  38. package/dist/context-engine/scorer.js +112 -0
  39. package/dist/context-engine/scorer.js.map +1 -0
  40. package/dist/context-engine/suggestions.d.ts +12 -0
  41. package/dist/context-engine/suggestions.d.ts.map +1 -0
  42. package/dist/context-engine/suggestions.js +22 -0
  43. package/dist/context-engine/suggestions.js.map +1 -0
  44. package/dist/index.js +129 -55
  45. package/dist/index.js.map +1 -1
  46. package/dist/mcp/context-injector.d.ts +45 -0
  47. package/dist/mcp/context-injector.d.ts.map +1 -0
  48. package/dist/mcp/context-injector.js +587 -0
  49. package/dist/mcp/context-injector.js.map +1 -0
  50. package/dist/mcp/proximity.d.ts +3 -0
  51. package/dist/mcp/proximity.d.ts.map +1 -0
  52. package/dist/mcp/proximity.js +135 -0
  53. package/dist/mcp/proximity.js.map +1 -0
  54. package/dist/patch-engine/diff.d.ts +12 -0
  55. package/dist/patch-engine/diff.d.ts.map +1 -0
  56. package/dist/patch-engine/diff.js +74 -0
  57. package/dist/patch-engine/diff.js.map +1 -0
  58. package/dist/patch-engine/generator.d.ts +13 -0
  59. package/dist/patch-engine/generator.d.ts.map +1 -0
  60. package/dist/patch-engine/generator.js +51 -0
  61. package/dist/patch-engine/generator.js.map +1 -0
  62. package/dist/patch-engine/index.d.ts +47 -0
  63. package/dist/patch-engine/index.d.ts.map +1 -0
  64. package/dist/patch-engine/index.js +182 -0
  65. package/dist/patch-engine/index.js.map +1 -0
  66. package/dist/patch-engine/patterns.d.ts +4 -0
  67. package/dist/patch-engine/patterns.d.ts.map +1 -0
  68. package/dist/patch-engine/patterns.js +99 -0
  69. package/dist/patch-engine/patterns.js.map +1 -0
  70. package/dist/utils/git.d.ts +8 -0
  71. package/dist/utils/git.d.ts.map +1 -1
  72. package/dist/utils/git.js +55 -0
  73. package/dist/utils/git.js.map +1 -1
  74. package/dist/utils/plan-sync.d.ts +34 -0
  75. package/dist/utils/plan-sync.d.ts.map +1 -0
  76. package/dist/utils/plan-sync.js +265 -0
  77. package/dist/utils/plan-sync.js.map +1 -0
  78. package/package.json +1 -1
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractRequestedFilePathsFromPrompt = extractRequestedFilePathsFromPrompt;
4
+ exports.findClosestAllowedFile = findClosestAllowedFile;
5
+ const FILE_PATH_PATTERN = /(?:^|[\s([{"'])((?:[A-Za-z0-9_.-]+\/)+(?:[A-Za-z0-9_.-]+\.(?:tsx|ts|jsx|js|mjs|cjs|json|tf|py|go|java|rs|md)))/g;
6
+ const BACKTICK_PATTERN = /`([^`]+)`/g;
7
+ const NOISE_TOKENS = new Set([
8
+ 'src',
9
+ 'app',
10
+ 'apps',
11
+ 'lib',
12
+ 'libs',
13
+ 'package',
14
+ 'packages',
15
+ 'module',
16
+ 'modules',
17
+ 'index',
18
+ 'main',
19
+ 'test',
20
+ 'tests',
21
+ 'spec',
22
+ 'ts',
23
+ 'tsx',
24
+ 'js',
25
+ 'jsx',
26
+ 'mjs',
27
+ 'cjs',
28
+ 'json',
29
+ 'tf',
30
+ 'py',
31
+ 'go',
32
+ 'java',
33
+ 'rs',
34
+ 'md',
35
+ ]);
36
+ function normalizePath(value) {
37
+ return value.replace(/\\/g, '/').replace(/^\.\//, '').trim();
38
+ }
39
+ function isLikelyFilePath(value) {
40
+ const normalized = normalizePath(value);
41
+ if (!normalized || !normalized.includes('/'))
42
+ return false;
43
+ return /\.[A-Za-z0-9]+$/.test(normalized);
44
+ }
45
+ function splitTokens(value) {
46
+ const normalized = value
47
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
48
+ .replace(/[^A-Za-z0-9]+/g, ' ')
49
+ .trim()
50
+ .toLowerCase();
51
+ if (!normalized)
52
+ return [];
53
+ return normalized
54
+ .split(/\s+/)
55
+ .filter((token) => Boolean(token) && !NOISE_TOKENS.has(token));
56
+ }
57
+ function fileNameFromPath(pathValue) {
58
+ const normalized = normalizePath(pathValue);
59
+ const segments = normalized.split('/');
60
+ const fileName = segments[segments.length - 1] || normalized;
61
+ return fileName.replace(/\.[^.]+$/, '');
62
+ }
63
+ function directorySegments(pathValue) {
64
+ const normalized = normalizePath(pathValue);
65
+ const segments = normalized.split('/').filter(Boolean);
66
+ return segments.slice(0, -1);
67
+ }
68
+ function extractRequestedFilePathsFromPrompt(prompt, maxItems = 3) {
69
+ const output = [];
70
+ const seen = new Set();
71
+ const limitedMax = Math.max(1, Math.floor(maxItems));
72
+ const pushCandidate = (candidateRaw) => {
73
+ const candidate = normalizePath(candidateRaw.replace(/[),.;:'"]+$/g, ''));
74
+ if (!isLikelyFilePath(candidate))
75
+ return;
76
+ if (seen.has(candidate))
77
+ return;
78
+ seen.add(candidate);
79
+ output.push(candidate);
80
+ };
81
+ let match;
82
+ while ((match = BACKTICK_PATTERN.exec(prompt)) !== null) {
83
+ if (output.length >= limitedMax)
84
+ break;
85
+ pushCandidate(match[1] || '');
86
+ }
87
+ while ((match = FILE_PATH_PATTERN.exec(prompt)) !== null) {
88
+ if (output.length >= limitedMax)
89
+ break;
90
+ pushCandidate(match[1] || '');
91
+ }
92
+ return output.slice(0, limitedMax);
93
+ }
94
+ function findClosestAllowedFile(requestedPath, allowedFiles) {
95
+ const normalizedRequested = normalizePath(requestedPath);
96
+ if (!normalizedRequested || !Array.isArray(allowedFiles) || allowedFiles.length === 0) {
97
+ return null;
98
+ }
99
+ const requestedDirs = directorySegments(normalizedRequested);
100
+ const requestedNameTokens = splitTokens(fileNameFromPath(normalizedRequested));
101
+ const requestedAllTokens = splitTokens(normalizedRequested);
102
+ let bestPath = null;
103
+ let bestScore = 0;
104
+ let bestHasSignal = false;
105
+ for (const candidateRaw of allowedFiles) {
106
+ const candidate = normalizePath(candidateRaw);
107
+ if (!candidate)
108
+ continue;
109
+ const candidateDirs = directorySegments(candidate);
110
+ const candidateNameTokens = splitTokens(fileNameFromPath(candidate));
111
+ const candidateAllTokens = splitTokens(candidate);
112
+ let sharedDirPrefix = 0;
113
+ while (sharedDirPrefix < requestedDirs.length &&
114
+ sharedDirPrefix < candidateDirs.length &&
115
+ requestedDirs[sharedDirPrefix] === candidateDirs[sharedDirPrefix]) {
116
+ sharedDirPrefix += 1;
117
+ }
118
+ const requestedNameSet = new Set(requestedNameTokens);
119
+ const requestedAllSet = new Set(requestedAllTokens);
120
+ const nameOverlap = candidateNameTokens.filter((token) => requestedNameSet.has(token)).length;
121
+ const allOverlap = candidateAllTokens.filter((token) => requestedAllSet.has(token)).length;
122
+ const hasSignal = sharedDirPrefix > 0 || nameOverlap > 0 || allOverlap >= 2;
123
+ const score = (sharedDirPrefix * 8) + (nameOverlap * 6) + (allOverlap * 2);
124
+ if (score > bestScore) {
125
+ bestScore = score;
126
+ bestPath = candidate;
127
+ bestHasSignal = hasSignal;
128
+ }
129
+ }
130
+ if (!bestHasSignal || bestScore <= 0) {
131
+ return null;
132
+ }
133
+ return bestPath;
134
+ }
135
+ //# sourceMappingURL=proximity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proximity.js","sourceRoot":"","sources":["../../src/mcp/proximity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Generate a minimal unified diff for a single-hunk change.
3
+ *
4
+ * Handles three cases without external libraries:
5
+ * - 1→1 replacement (db_in_ui)
6
+ * - 0→1 insertion (missing_validation: comment inserted before a line)
7
+ * - 1→0 deletion (todo_fixme: comment line removed)
8
+ *
9
+ * Returns an empty string when original === updated.
10
+ */
11
+ export declare function generateUnifiedDiff(filePath: string, original: string, updated: string): string;
12
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/patch-engine/diff.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CAwER"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateUnifiedDiff = generateUnifiedDiff;
4
+ const CONTEXT_LINES = 3;
5
+ /**
6
+ * Generate a minimal unified diff for a single-hunk change.
7
+ *
8
+ * Handles three cases without external libraries:
9
+ * - 1→1 replacement (db_in_ui)
10
+ * - 0→1 insertion (missing_validation: comment inserted before a line)
11
+ * - 1→0 deletion (todo_fixme: comment line removed)
12
+ *
13
+ * Returns an empty string when original === updated.
14
+ */
15
+ function generateUnifiedDiff(filePath, original, updated) {
16
+ if (original === updated)
17
+ return '';
18
+ const origLines = original.split('\n');
19
+ const newLines = updated.split('\n');
20
+ // ── Forward scan: find first line that differs ──────────────────────────
21
+ let firstDiff = 0;
22
+ while (firstDiff < origLines.length &&
23
+ firstDiff < newLines.length &&
24
+ origLines[firstDiff] === newLines[firstDiff]) {
25
+ firstDiff++;
26
+ }
27
+ // ── Backward scan: find last differing line in each file ─────────────────
28
+ // Use `>=` so the scan can match lines at exactly firstDiff:
29
+ // - Deletion: lastDiffNew drops to firstDiff-1 (no added lines)
30
+ // - Insertion: lastDiffOrig drops to firstDiff-1 (no removed lines)
31
+ // - Replacement: both stop at firstDiff (the differing line)
32
+ // Safety: at firstDiff the forward scan guaranteed origLines[firstDiff] != newLines[firstDiff],
33
+ // so the equality check naturally stops the loop before both go below firstDiff.
34
+ let lastDiffOrig = origLines.length - 1;
35
+ let lastDiffNew = newLines.length - 1;
36
+ while (lastDiffOrig >= firstDiff &&
37
+ lastDiffNew >= firstDiff &&
38
+ origLines[lastDiffOrig] === newLines[lastDiffNew]) {
39
+ lastDiffOrig--;
40
+ lastDiffNew--;
41
+ }
42
+ // ── Context window ───────────────────────────────────────────────────────
43
+ const contextStart = Math.max(0, firstDiff - CONTEXT_LINES);
44
+ const contextEndOrig = Math.min(origLines.length - 1, lastDiffOrig + CONTEXT_LINES);
45
+ const contextEndNew = Math.min(newLines.length - 1, lastDiffNew + CONTEXT_LINES);
46
+ // Hunk header line counts (unified diff convention: 1-indexed, inclusive)
47
+ const oldStartLine = contextStart + 1;
48
+ const oldCount = contextEndOrig - contextStart + 1;
49
+ const newStartLine = contextStart + 1;
50
+ const newCount = contextEndNew - contextStart + 1;
51
+ const out = [
52
+ `--- a/${filePath}`,
53
+ `+++ b/${filePath}`,
54
+ `@@ -${oldStartLine},${oldCount} +${newStartLine},${newCount} @@`,
55
+ ];
56
+ // Context lines before the change
57
+ for (let i = contextStart; i < firstDiff; i++) {
58
+ out.push(` ${origLines[i]}`);
59
+ }
60
+ // Removed lines (empty range when lastDiffOrig < firstDiff = pure insertion)
61
+ for (let i = firstDiff; i <= lastDiffOrig; i++) {
62
+ out.push(`-${origLines[i]}`);
63
+ }
64
+ // Added lines (empty range when lastDiffNew < firstDiff = pure deletion)
65
+ for (let i = firstDiff; i <= lastDiffNew; i++) {
66
+ out.push(`+${newLines[i]}`);
67
+ }
68
+ // Context lines after the change (taken from orig; content is identical in new)
69
+ for (let i = lastDiffOrig + 1; i <= contextEndOrig; i++) {
70
+ out.push(` ${origLines[i]}`);
71
+ }
72
+ return out.join('\n');
73
+ }
74
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/patch-engine/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type PatternKind } from './patterns';
2
+ export type PatchInput = {
3
+ filePath: string;
4
+ issue: string;
5
+ policy: string;
6
+ fileContent: string;
7
+ patternKind: PatternKind;
8
+ };
9
+ export type PatchResult = {
10
+ updatedContent: string;
11
+ } | null;
12
+ export declare function generatePatch(input: PatchInput): PatchResult;
13
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/patch-engine/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,IAAI,CAAC;AAgCT,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAqB5D"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generatePatch = generatePatch;
4
+ const patterns_1 = require("./patterns");
5
+ function leadingWhitespace(line) {
6
+ return line.match(/^(\s*)/)?.[1] ?? '';
7
+ }
8
+ // Replace the matched DB call line with a service-layer redirect comment.
9
+ function applyDbAccessFix(lines, lineIndex) {
10
+ const indent = leadingWhitespace(lines[lineIndex]);
11
+ const updated = [...lines];
12
+ updated[lineIndex] = `${indent}// [NEURCODE] Move to service layer — replace direct DB call with a service method`;
13
+ return updated;
14
+ }
15
+ // Insert a validation reminder line immediately before the req.body/params/query access.
16
+ function applyValidationFix(lines, lineIndex) {
17
+ const indent = leadingWhitespace(lines[lineIndex]);
18
+ const comment = `${indent}// [NEURCODE] Add validation — e.g. const { error } = schema.validate(req.body); ` +
19
+ `if (error) return res.status(400).json({ error: error.message });`;
20
+ const updated = [...lines];
21
+ updated.splice(lineIndex, 0, comment);
22
+ return updated;
23
+ }
24
+ // Remove the TODO/FIXME comment line entirely.
25
+ function applyTodoRemoval(lines, lineIndex) {
26
+ const updated = [...lines];
27
+ updated.splice(lineIndex, 1);
28
+ return updated;
29
+ }
30
+ function generatePatch(input) {
31
+ const lines = input.fileContent.split('\n');
32
+ const lineIndex = (0, patterns_1.detectPattern)(input.fileContent, input.patternKind);
33
+ if (lineIndex === null)
34
+ return null;
35
+ let updatedLines;
36
+ switch (input.patternKind) {
37
+ case 'db_in_ui':
38
+ updatedLines = applyDbAccessFix(lines, lineIndex);
39
+ break;
40
+ case 'missing_validation':
41
+ updatedLines = applyValidationFix(lines, lineIndex);
42
+ break;
43
+ case 'todo_fixme':
44
+ updatedLines = applyTodoRemoval(lines, lineIndex);
45
+ break;
46
+ default:
47
+ return null;
48
+ }
49
+ return { updatedContent: updatedLines.join('\n') };
50
+ }
51
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/patch-engine/generator.ts"],"names":[],"mappings":";;AA4CA,sCAqBC;AAjED,yCAA6D;AAc7D,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,0EAA0E;AAC1E,SAAS,gBAAgB,CAAC,KAAe,EAAE,SAAiB;IAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,SAAS,CAAC,GAAG,GAAG,MAAM,oFAAoF,CAAC;IACnH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yFAAyF;AACzF,SAAS,kBAAkB,CAAC,KAAe,EAAE,SAAiB;IAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GACX,GAAG,MAAM,mFAAmF;QAC5F,mEAAmE,CAAC;IACtE,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+CAA+C;AAC/C,SAAS,gBAAgB,CAAC,KAAe,EAAE,SAAiB;IAC1D,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC7B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,aAAa,CAAC,KAAiB;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAA,wBAAa,EAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IACtE,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEpC,IAAI,YAAsB,CAAC;IAC3B,QAAQ,KAAK,CAAC,WAAW,EAAE,CAAC;QAC1B,KAAK,UAAU;YACb,YAAY,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YAClD,MAAM;QACR,KAAK,oBAAoB;YACvB,YAAY,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACpD,MAAM;QACR,KAAK,YAAY;YACf,YAAY,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YAClD,MAAM;QACR;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { type PatternKind } from './patterns';
2
+ export type { PatternKind };
3
+ export type PatchConfidence = 'high' | 'medium' | 'low';
4
+ export type SuggestionPatch = {
5
+ file: string;
6
+ diff: string;
7
+ patchConfidence: PatchConfidence;
8
+ };
9
+ /**
10
+ * Apply a unified diff (as produced by generateUnifiedDiff) to fileContent.
11
+ *
12
+ * Parses the single-hunk diff format, verifies every context and removal line
13
+ * matches the current file, then reconstructs the updated content.
14
+ *
15
+ * Returns null when:
16
+ * - no hunk header found
17
+ * - a context or removal line does not match current file content (file changed)
18
+ */
19
+ export declare function applyUnifiedDiff(fileContent: string, diff: string): string | null;
20
+ /**
21
+ * Detect the first matching patchable pattern in fileContent and return the
22
+ * updated content. Tries patterns in priority order: db_in_ui → missing_validation
23
+ * → todo_fixme. Validates safety before returning.
24
+ *
25
+ * Used by `neurcode patch --file` to apply a patch without needing suggestion metadata.
26
+ */
27
+ export declare function applyFirstMatchingPatch(filePath: string, fileContent: string): {
28
+ updatedContent: string;
29
+ patternKind: PatternKind;
30
+ patchConfidence: PatchConfidence;
31
+ } | null;
32
+ /**
33
+ * Given a fix suggestion and the current content of suggestion.file,
34
+ * attempts to generate a deterministic, safety-validated code patch.
35
+ *
36
+ * Returns null when:
37
+ * - the violation type has no patchable pattern
38
+ * - the pattern is not found in the file content
39
+ * - the generated patch produces no diff
40
+ * - the patch fails the safety gate (isPatchSafe)
41
+ */
42
+ export declare function generatePatchForSuggestion(suggestion: {
43
+ file: string;
44
+ issue: string;
45
+ policy: string;
46
+ }, fileContent: string): SuggestionPatch | null;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patch-engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAIjE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAqCF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiEjF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAC;IAAC,eAAe,EAAE,eAAe,CAAA;CAAE,GAAG,IAAI,CA0B/F;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3D,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,IAAI,CAuBxB"}
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyUnifiedDiff = applyUnifiedDiff;
4
+ exports.applyFirstMatchingPatch = applyFirstMatchingPatch;
5
+ exports.generatePatchForSuggestion = generatePatchForSuggestion;
6
+ const patterns_1 = require("./patterns");
7
+ const generator_1 = require("./generator");
8
+ const diff_1 = require("./diff");
9
+ // Patterns that must appear in original content for a patch to be considered safe.
10
+ const PATCHABLE_PATTERN_RE = /db\.(query|execute|run|find[A-Za-z]*)\b|prisma\.\w+\.\w+\b|new\s+Pool\s*\(|knex\s*\(|TODO|FIXME|\bvalidat/i;
11
+ /**
12
+ * A patch is safe when:
13
+ * - updated content is non-empty
14
+ * - the diff is non-empty (something actually changed)
15
+ * - total added + removed lines ≤ 5 (not a full-file rewrite)
16
+ * - the original file contains at least one recognizable patchable pattern
17
+ */
18
+ function isPatchSafe(original, updated) {
19
+ if (!updated || !updated.trim())
20
+ return false;
21
+ const diff = (0, diff_1.generateUnifiedDiff)('', original, updated);
22
+ if (!diff)
23
+ return false;
24
+ let changed = 0;
25
+ for (const line of diff.split('\n')) {
26
+ if (line.startsWith('-') && !line.startsWith('---'))
27
+ changed++;
28
+ if (line.startsWith('+') && !line.startsWith('+++'))
29
+ changed++;
30
+ }
31
+ if (changed > 5)
32
+ return false;
33
+ if (!PATCHABLE_PATTERN_RE.test(original))
34
+ return false;
35
+ return true;
36
+ }
37
+ function scorePatchConfidence(kind) {
38
+ if (kind === 'db_in_ui')
39
+ return 'high';
40
+ if (kind === 'missing_validation')
41
+ return 'medium';
42
+ return 'low'; // todo_fixme — simple removal, lowest confidence
43
+ }
44
+ /**
45
+ * Apply a unified diff (as produced by generateUnifiedDiff) to fileContent.
46
+ *
47
+ * Parses the single-hunk diff format, verifies every context and removal line
48
+ * matches the current file, then reconstructs the updated content.
49
+ *
50
+ * Returns null when:
51
+ * - no hunk header found
52
+ * - a context or removal line does not match current file content (file changed)
53
+ */
54
+ function applyUnifiedDiff(fileContent, diff) {
55
+ if (!diff)
56
+ return null;
57
+ const diffLines = diff.split('\n');
58
+ // Locate the hunk header (skip --- / +++ file headers)
59
+ let hunkIdx = -1;
60
+ for (let i = 0; i < diffLines.length; i++) {
61
+ if (diffLines[i].startsWith('@@')) {
62
+ hunkIdx = i;
63
+ break;
64
+ }
65
+ }
66
+ if (hunkIdx === -1)
67
+ return null;
68
+ // Parse @@ -oldStart[,oldCount] +newStart[,newCount] @@
69
+ const match = diffLines[hunkIdx].match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
70
+ if (!match)
71
+ return null;
72
+ // Diff uses 1-indexed lines; convert to 0-indexed
73
+ const origStart = parseInt(match[1], 10) - 1;
74
+ const origLines = fileContent.split('\n');
75
+ const output = [];
76
+ // Lines before the hunk are copied unchanged
77
+ for (let i = 0; i < origStart; i++) {
78
+ output.push(origLines[i] ?? '');
79
+ }
80
+ let origIdx = origStart;
81
+ for (let i = hunkIdx + 1; i < diffLines.length; i++) {
82
+ const line = diffLines[i];
83
+ // A trailing empty string from split('\n') signals end of diff
84
+ if (line.length === 0 && i === diffLines.length - 1)
85
+ break;
86
+ const prefix = line[0];
87
+ const content = line.slice(1);
88
+ if (prefix === ' ') {
89
+ // Context: must match current file — abort on mismatch (file changed)
90
+ if (origIdx >= origLines.length || origLines[origIdx] !== content)
91
+ return null;
92
+ output.push(content);
93
+ origIdx++;
94
+ }
95
+ else if (prefix === '-') {
96
+ // Removal: must match current file — abort on mismatch
97
+ if (origIdx >= origLines.length || origLines[origIdx] !== content)
98
+ return null;
99
+ origIdx++; // consume original line without adding to output
100
+ }
101
+ else if (prefix === '+') {
102
+ // Addition: inject into output without consuming original
103
+ output.push(content);
104
+ }
105
+ else {
106
+ break; // unexpected prefix — stop hunk processing
107
+ }
108
+ }
109
+ // Copy remaining original lines after the hunk
110
+ while (origIdx < origLines.length) {
111
+ output.push(origLines[origIdx]);
112
+ origIdx++;
113
+ }
114
+ return output.join('\n');
115
+ }
116
+ /**
117
+ * Detect the first matching patchable pattern in fileContent and return the
118
+ * updated content. Tries patterns in priority order: db_in_ui → missing_validation
119
+ * → todo_fixme. Validates safety before returning.
120
+ *
121
+ * Used by `neurcode patch --file` to apply a patch without needing suggestion metadata.
122
+ */
123
+ function applyFirstMatchingPatch(filePath, fileContent) {
124
+ const kinds = ['db_in_ui', 'missing_validation', 'todo_fixme'];
125
+ for (const kind of kinds) {
126
+ const result = (0, generator_1.generatePatch)({
127
+ filePath,
128
+ issue: '',
129
+ policy: '',
130
+ fileContent,
131
+ patternKind: kind,
132
+ });
133
+ if (!result)
134
+ continue;
135
+ const diff = (0, diff_1.generateUnifiedDiff)(filePath, fileContent, result.updatedContent);
136
+ if (!diff)
137
+ continue;
138
+ if (!isPatchSafe(fileContent, result.updatedContent))
139
+ continue;
140
+ return {
141
+ updatedContent: result.updatedContent,
142
+ patternKind: kind,
143
+ patchConfidence: scorePatchConfidence(kind),
144
+ };
145
+ }
146
+ return null;
147
+ }
148
+ /**
149
+ * Given a fix suggestion and the current content of suggestion.file,
150
+ * attempts to generate a deterministic, safety-validated code patch.
151
+ *
152
+ * Returns null when:
153
+ * - the violation type has no patchable pattern
154
+ * - the pattern is not found in the file content
155
+ * - the generated patch produces no diff
156
+ * - the patch fails the safety gate (isPatchSafe)
157
+ */
158
+ function generatePatchForSuggestion(suggestion, fileContent) {
159
+ const kind = (0, patterns_1.classifyViolation)(suggestion.issue, suggestion.policy);
160
+ if (!kind)
161
+ return null;
162
+ const result = (0, generator_1.generatePatch)({
163
+ filePath: suggestion.file,
164
+ issue: suggestion.issue,
165
+ policy: suggestion.policy,
166
+ fileContent,
167
+ patternKind: kind,
168
+ });
169
+ if (!result)
170
+ return null;
171
+ const diff = (0, diff_1.generateUnifiedDiff)(suggestion.file, fileContent, result.updatedContent);
172
+ if (!diff)
173
+ return null;
174
+ if (!isPatchSafe(fileContent, result.updatedContent))
175
+ return null;
176
+ return {
177
+ file: suggestion.file,
178
+ diff,
179
+ patchConfidence: scorePatchConfidence(kind),
180
+ };
181
+ }
182
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patch-engine/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type PatternKind = 'db_in_ui' | 'missing_validation' | 'todo_fixme';
2
+ export declare function classifyViolation(issue: string, policy: string): PatternKind | null;
3
+ export declare function detectPattern(content: string, kind: PatternKind): number | null;
4
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/patch-engine/patterns.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,oBAAoB,GAAG,YAAY,CAAC;AAM3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAsBnF;AA2ED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAO/E"}