devsmind-mcp 2.3.0 → 2.4.0
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/README.md +2 -2
- package/dist/cli/init.js +9 -0
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/integrations/memory.js +2 -1
- package/dist/cli/integrations/memory.js.map +1 -1
- package/dist/cli/prune.js +4 -3
- package/dist/cli/prune.js.map +1 -1
- package/dist/cli/rule.js +14 -35
- package/dist/cli/rule.js.map +1 -1
- package/dist/db/analyze.js +7 -3
- package/dist/db/analyze.js.map +1 -1
- package/dist/db/database.d.ts +44 -0
- package/dist/db/database.js +197 -21
- package/dist/db/database.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +297 -62
- package/dist/mcp/server.js.map +1 -1
- package/dist/utils/ast.d.ts +98 -0
- package/dist/utils/ast.js +262 -10
- package/dist/utils/ast.js.map +1 -1
- package/dist/utils/edit.d.ts +41 -0
- package/dist/utils/edit.js +163 -0
- package/dist/utils/edit.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.writeFileAtomic = writeFileAtomic;
|
|
37
|
+
exports.createFileWithContent = createFileWithContent;
|
|
38
|
+
exports.replaceTextInFile = replaceTextInFile;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
/**
|
|
42
|
+
* Write via temp file + rename, so a reader never observes a half-written source file and a
|
|
43
|
+
* failed write leaves the original intact.
|
|
44
|
+
*/
|
|
45
|
+
function writeFileAtomic(filePath, content) {
|
|
46
|
+
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
47
|
+
try {
|
|
48
|
+
fs.writeFileSync(tmp, content, 'utf-8');
|
|
49
|
+
fs.renameSync(tmp, filePath);
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
try {
|
|
53
|
+
if (fs.existsSync(tmp))
|
|
54
|
+
fs.unlinkSync(tmp);
|
|
55
|
+
}
|
|
56
|
+
catch { /* ignore */ }
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a file that does not exist yet, with its parent directories.
|
|
62
|
+
*
|
|
63
|
+
* Reported in the same shape as a replacement — one range spanning the whole file, against an
|
|
64
|
+
* empty "before" — so a new file's contents trace exactly like any other edit, and every symbol
|
|
65
|
+
* in it is new by construction. That keeps creating a file from being a special case the caller
|
|
66
|
+
* has to route somewhere else.
|
|
67
|
+
*/
|
|
68
|
+
function createFileWithContent(filePath, content) {
|
|
69
|
+
if (fs.existsSync(filePath)) {
|
|
70
|
+
return { ok: false, error: `${path.basename(filePath)} already exists — pass the exact old_string you want to replace inside it.` };
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
74
|
+
writeFileAtomic(filePath, content);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
return { ok: false, error: `could not create ${filePath}: ${e?.message || e}` };
|
|
78
|
+
}
|
|
79
|
+
return { ok: true, replacements: 1, ranges: [{ start: 0, end: content.length }], before: '', created: true };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Exact-match text replacement — the fallback for files no parser can address by symbol
|
|
83
|
+
* (stylesheets, markup, config, and every non-TS/JS language).
|
|
84
|
+
*
|
|
85
|
+
* Deliberately mirrors the semantics of a standard editor edit tool, including the
|
|
86
|
+
* single-occurrence requirement: a caller that meant one site and matched three would
|
|
87
|
+
* otherwise silently corrupt two of them. `replaceAll` opts out of that check explicitly.
|
|
88
|
+
*/
|
|
89
|
+
function replaceTextInFile(filePath, oldString, newString, replaceAll = false) {
|
|
90
|
+
if (oldString === newString) {
|
|
91
|
+
return { ok: false, error: 'old_string and new_string are identical — nothing to do.' };
|
|
92
|
+
}
|
|
93
|
+
let original;
|
|
94
|
+
try {
|
|
95
|
+
original = fs.readFileSync(filePath, 'utf-8');
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
return { ok: false, error: `could not read ${filePath}: ${e?.message || e}` };
|
|
99
|
+
}
|
|
100
|
+
// An empty needle matches at every position and would advance the scan by zero — the loop
|
|
101
|
+
// below would never terminate. Reserve it for the one case it can mean unambiguously: the
|
|
102
|
+
// file exists but is genuinely empty, so "replace nothing" and "replace everything" coincide
|
|
103
|
+
// and there is no other way to address that content. Any other file gets a real error instead
|
|
104
|
+
// of hanging, and is told to supply the actual text to replace.
|
|
105
|
+
if (oldString === '') {
|
|
106
|
+
if (original.length === 0) {
|
|
107
|
+
try {
|
|
108
|
+
writeFileAtomic(filePath, newString);
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
return { ok: false, error: `write failed: ${e?.message || e}` };
|
|
112
|
+
}
|
|
113
|
+
return { ok: true, replacements: 1, ranges: [{ start: 0, end: newString.length }], before: '' };
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
error: 'old_string is empty, but this file already exists and has content. An empty old_string only means "create this file" (or populate an EMPTY one); to change an existing non-empty file, give the exact text to replace.'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Count occurrences without regex, so the needle is never interpreted as a pattern.
|
|
121
|
+
let count = 0;
|
|
122
|
+
for (let i = original.indexOf(oldString); i !== -1; i = original.indexOf(oldString, i + oldString.length)) {
|
|
123
|
+
count++;
|
|
124
|
+
if (!replaceAll && count > 1)
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (count === 0) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
error: 'old_string was not found in the file. It must match the file byte-for-byte, including indentation. Re-read the file and copy the exact text.'
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (count > 1 && !replaceAll) {
|
|
134
|
+
return {
|
|
135
|
+
ok: false,
|
|
136
|
+
error: `old_string matches more than one place in the file — nothing was written. Include surrounding lines to make it unique, or pass replace_all: true if every occurrence should change.`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Built by hand rather than via replace()/split-join, so each replacement's span in the NEW
|
|
140
|
+
// content is known exactly — later replacements shift as earlier ones change length, and
|
|
141
|
+
// only accumulating as we go accounts for that.
|
|
142
|
+
const ranges = [];
|
|
143
|
+
let updated = '';
|
|
144
|
+
let cursor = 0;
|
|
145
|
+
for (let i = original.indexOf(oldString); i !== -1; i = original.indexOf(oldString, cursor)) {
|
|
146
|
+
updated += original.slice(cursor, i);
|
|
147
|
+
const start = updated.length;
|
|
148
|
+
updated += newString;
|
|
149
|
+
ranges.push({ start, end: updated.length });
|
|
150
|
+
cursor = i + oldString.length;
|
|
151
|
+
if (!replaceAll)
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
updated += original.slice(cursor);
|
|
155
|
+
try {
|
|
156
|
+
writeFileAtomic(filePath, updated);
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
return { ok: false, error: `write failed: ${e?.message || e}` };
|
|
160
|
+
}
|
|
161
|
+
return { ok: true, replacements: ranges.length, ranges, before: original };
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/utils/edit.ts"],"names":[],"mappings":"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"}
|