@menteeai/menteeswe 0.1.12 → 0.1.13
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/dist/cli.js +261 -154
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -194,6 +194,154 @@ var init_exec = __esm({
|
|
|
194
194
|
}
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
// src/tools/testing.ts
|
|
198
|
+
import fs4 from "fs";
|
|
199
|
+
import path4 from "path";
|
|
200
|
+
function readPackageJson(cwd) {
|
|
201
|
+
try {
|
|
202
|
+
return JSON.parse(fs4.readFileSync(path4.join(cwd, "package.json"), "utf8"));
|
|
203
|
+
} catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function readTextIfExists(cwd, file) {
|
|
208
|
+
try {
|
|
209
|
+
return fs4.readFileSync(path4.join(cwd, file), "utf8");
|
|
210
|
+
} catch {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function fileExists(cwd, file) {
|
|
215
|
+
try {
|
|
216
|
+
return fs4.existsSync(path4.join(cwd, file));
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function detectTestCommand(cwd) {
|
|
222
|
+
const pkg = readPackageJson(cwd);
|
|
223
|
+
const testScript = pkg && typeof pkg.scripts?.test === "string" ? pkg.scripts.test : null;
|
|
224
|
+
if (testScript && !/error|no test specified/i.test(testScript)) {
|
|
225
|
+
return "npm test";
|
|
226
|
+
}
|
|
227
|
+
if (fileExists(cwd, "pytest.ini") || fileExists(cwd, "tests")) return "pytest -q";
|
|
228
|
+
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
229
|
+
if (pyproject && /\[tool\.pytest/.test(pyproject)) return "pytest -q";
|
|
230
|
+
if (fileExists(cwd, "go.mod")) return "go test ./...";
|
|
231
|
+
if (fileExists(cwd, "Cargo.toml")) return "cargo test";
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
function detectLintCommand(cwd) {
|
|
235
|
+
if (fileExists(cwd, "eslint.config.js") || fileExists(cwd, "eslint.config.mjs") || fileExists(cwd, ".eslintrc.json") || fileExists(cwd, ".eslintrc.js")) {
|
|
236
|
+
return "npx --no-install eslint .";
|
|
237
|
+
}
|
|
238
|
+
if (fileExists(cwd, "biome.json")) return "npx --no-install biome check .";
|
|
239
|
+
if (fileExists(cwd, ".ruff.toml") || fileExists(cwd, "ruff.toml")) return "ruff check .";
|
|
240
|
+
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
241
|
+
if (pyproject && /\[tool\.ruff/.test(pyproject)) return "ruff check .";
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
function detectTypecheckCommand(cwd) {
|
|
245
|
+
if (fileExists(cwd, "tsconfig.json")) return "npx --no-install tsc --noEmit";
|
|
246
|
+
if (fileExists(cwd, "mypy.ini")) return "python -m mypy .";
|
|
247
|
+
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
248
|
+
if (pyproject && /\[tool\.mypy/.test(pyproject)) return "python -m mypy .";
|
|
249
|
+
if (fileExists(cwd, "go.mod")) return "go vet ./...";
|
|
250
|
+
if (fileExists(cwd, "Cargo.toml")) return "cargo check";
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
function makeRunnerTool(config) {
|
|
254
|
+
return {
|
|
255
|
+
name: config.name,
|
|
256
|
+
description: config.description,
|
|
257
|
+
risk: "safe",
|
|
258
|
+
timeoutMs: DEFAULT_TIMEOUT_MS2,
|
|
259
|
+
parameters: {
|
|
260
|
+
type: "object",
|
|
261
|
+
properties: {
|
|
262
|
+
command: {
|
|
263
|
+
type: "string",
|
|
264
|
+
description: "Exact command to run. If omitted, the project type is auto-detected."
|
|
265
|
+
},
|
|
266
|
+
timeout_ms: { type: "number", description: `Timeout in ms. Defaults to ${DEFAULT_TIMEOUT_MS2}.` }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
async execute(args, ctx) {
|
|
270
|
+
let command = firstString(args, "command");
|
|
271
|
+
if (!command) {
|
|
272
|
+
command = config.detect(ctx.cwd) ?? void 0;
|
|
273
|
+
if (!command) {
|
|
274
|
+
return {
|
|
275
|
+
success: false,
|
|
276
|
+
output: `Could not auto-detect a command for this project. ${config.fallbackHint} Use the command argument to run one explicitly.`
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const timeoutMs = Math.min(6e5, firstNumber(args, "timeout_ms") ?? DEFAULT_TIMEOUT_MS2);
|
|
281
|
+
const outcome = await runShellCommand(command, ctx.cwd, timeoutMs);
|
|
282
|
+
const formatted = formatOutcome(outcome);
|
|
283
|
+
return { success: formatted.success, output: formatted.output, truncated: formatted.truncated };
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
var DEFAULT_TIMEOUT_MS2, runTests, runLinter, runTypecheck, inspectEnv;
|
|
288
|
+
var init_testing = __esm({
|
|
289
|
+
"src/tools/testing.ts"() {
|
|
290
|
+
"use strict";
|
|
291
|
+
init_base();
|
|
292
|
+
init_exec();
|
|
293
|
+
DEFAULT_TIMEOUT_MS2 = 18e4;
|
|
294
|
+
runTests = makeRunnerTool({
|
|
295
|
+
name: "run_tests",
|
|
296
|
+
description: "Run the project test suite. Auto-detects npm test / pytest / go test / cargo test from the project files, or run an exact command. Use this to verify changes.",
|
|
297
|
+
detect: detectTestCommand,
|
|
298
|
+
fallbackHint: "No test runner found (looked for package.json scripts.test, pytest, go, cargo)."
|
|
299
|
+
});
|
|
300
|
+
runLinter = makeRunnerTool({
|
|
301
|
+
name: "run_linter",
|
|
302
|
+
description: "Run the project linter (eslint / biome / ruff auto-detected).",
|
|
303
|
+
detect: detectLintCommand,
|
|
304
|
+
fallbackHint: "No linter config found (looked for eslint, biome, ruff)."
|
|
305
|
+
});
|
|
306
|
+
runTypecheck = makeRunnerTool({
|
|
307
|
+
name: "run_typecheck",
|
|
308
|
+
description: "Run static type checking (tsc --noEmit / mypy / go vet / cargo check auto-detected).",
|
|
309
|
+
detect: detectTypecheckCommand,
|
|
310
|
+
fallbackHint: "No typechecker config found (looked for tsconfig.json, mypy, go, cargo)."
|
|
311
|
+
});
|
|
312
|
+
inspectEnv = {
|
|
313
|
+
name: "inspect_env",
|
|
314
|
+
description: "Inspect the environment: OS info, and which toolchains are installed with versions (node, npm, python, pip, git). Use this to adapt commands to the machine.",
|
|
315
|
+
risk: "safe",
|
|
316
|
+
parameters: { type: "object", properties: {} },
|
|
317
|
+
async execute(_args, ctx) {
|
|
318
|
+
const lines = [
|
|
319
|
+
`os: ${process.platform} ${process.version} ${process.arch}`,
|
|
320
|
+
`workspace: ${ctx.cwd}`
|
|
321
|
+
];
|
|
322
|
+
const probes = [
|
|
323
|
+
["node", "node --version"],
|
|
324
|
+
["npm", "npm --version"],
|
|
325
|
+
["npx", "npx --version"],
|
|
326
|
+
["python", "python --version"],
|
|
327
|
+
["pip", "pip --version"],
|
|
328
|
+
["git", "git --version"],
|
|
329
|
+
["docker", "docker --version"]
|
|
330
|
+
];
|
|
331
|
+
const results = await Promise.all(
|
|
332
|
+
probes.map(async ([label, probe]) => {
|
|
333
|
+
const outcome = await runShellCommand(probe, ctx.cwd, 8e3);
|
|
334
|
+
const version2 = `${outcome.stdout} ${outcome.stderr}`.trim().split("\n")[0] ?? "";
|
|
335
|
+
return `${label}: ${outcome.exitCode === 0 ? version2 || "installed (version unknown)" : "not available"}`;
|
|
336
|
+
})
|
|
337
|
+
);
|
|
338
|
+
lines.push(...results);
|
|
339
|
+
return { success: true, output: lines.join("\n") };
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
197
345
|
// src/events.ts
|
|
198
346
|
var EventBus;
|
|
199
347
|
var init_events = __esm({
|
|
@@ -635,6 +783,7 @@ function createAgentState(task, maxIterations) {
|
|
|
635
783
|
sameErrorCount: 0,
|
|
636
784
|
totalToolCalls: 0,
|
|
637
785
|
readCount: 0,
|
|
786
|
+
verifyAttempts: 0,
|
|
638
787
|
usage: { inputTokens: 0, outputTokens: 0, modelRequests: 0 },
|
|
639
788
|
startedAt: Date.now()
|
|
640
789
|
};
|
|
@@ -724,6 +873,31 @@ function trimOldToolResults(messages) {
|
|
|
724
873
|
message.content = `\u27E8prior tool output trimmed: ${head}\u2026 (${content.length} chars)\u27E9`;
|
|
725
874
|
}
|
|
726
875
|
}
|
|
876
|
+
async function runVerification(tools, ctx, bus, state, cwd) {
|
|
877
|
+
const checks = [
|
|
878
|
+
{ tool: tools.get("run_typecheck"), detect: detectTypecheckCommand },
|
|
879
|
+
{ tool: tools.get("run_tests"), detect: detectTestCommand }
|
|
880
|
+
];
|
|
881
|
+
let combined = "";
|
|
882
|
+
for (const { tool, detect } of checks) {
|
|
883
|
+
if (!tool) continue;
|
|
884
|
+
if (!detect(cwd)) continue;
|
|
885
|
+
bus.emit("tool_started", `verify \xB7 ${tool.name}`, { tool: tool.name });
|
|
886
|
+
const res = await tool.execute({}, ctx);
|
|
887
|
+
bus.emit("tool_completed", `verify \xB7 ${tool.name}`, {
|
|
888
|
+
tool: tool.name,
|
|
889
|
+
success: res.success,
|
|
890
|
+
output: res.output.slice(0, 2e3)
|
|
891
|
+
});
|
|
892
|
+
combined += `${tool.name}: ${res.output}
|
|
893
|
+
`;
|
|
894
|
+
if (!res.success) {
|
|
895
|
+
state.errors.push(res.output.slice(0, 500));
|
|
896
|
+
return { ok: false, output: combined };
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return { ok: true, output: combined };
|
|
900
|
+
}
|
|
727
901
|
async function runAgent(options) {
|
|
728
902
|
const {
|
|
729
903
|
task,
|
|
@@ -756,7 +930,12 @@ ${systemExtra}` : "");
|
|
|
756
930
|
}
|
|
757
931
|
};
|
|
758
932
|
const messages = [{ role: "user", content: task }];
|
|
933
|
+
const setPhase = (p) => {
|
|
934
|
+
state.phase = p;
|
|
935
|
+
bus.emit("phase", p);
|
|
936
|
+
};
|
|
759
937
|
bus.emit("task_started", task, { provider: provider.name, model: model ?? provider.defaultModel });
|
|
938
|
+
setPhase("EXPLORATION");
|
|
760
939
|
let finalText = "";
|
|
761
940
|
let sawFinish = false;
|
|
762
941
|
while (state.iteration < maxIterations) {
|
|
@@ -828,6 +1007,27 @@ ${systemExtra}` : "");
|
|
|
828
1007
|
if (response.toolCalls.length === 0) {
|
|
829
1008
|
finalText = response.content ?? "";
|
|
830
1009
|
sawFinish = true;
|
|
1010
|
+
if (state.modifiedFiles.length > 0 && state.verifyAttempts < MAX_VERIFY) {
|
|
1011
|
+
setPhase("VALIDATION");
|
|
1012
|
+
const verdict = await runVerification(tools, toolCtx, bus, state, cwd);
|
|
1013
|
+
if (!verdict.ok) {
|
|
1014
|
+
state.verifyAttempts += 1;
|
|
1015
|
+
if (state.verifyAttempts >= MAX_VERIFY) {
|
|
1016
|
+
bus.emit("warning", "Verification failed after multiple attempts; finishing with the issue reported.");
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
setPhase("DEBUGGING");
|
|
1020
|
+
messages.push({
|
|
1021
|
+
role: "user",
|
|
1022
|
+
content: `SYSTEM NOTE: Verification failed.
|
|
1023
|
+
${verdict.output}
|
|
1024
|
+
Investigate the root cause, fix it, then finish with a final answer.`
|
|
1025
|
+
});
|
|
1026
|
+
sawFinish = false;
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
setPhase("REVIEW");
|
|
1030
|
+
}
|
|
831
1031
|
break;
|
|
832
1032
|
}
|
|
833
1033
|
messages.push({
|
|
@@ -859,6 +1059,7 @@ ${systemExtra}` : "");
|
|
|
859
1059
|
});
|
|
860
1060
|
continue;
|
|
861
1061
|
}
|
|
1062
|
+
if (EDIT_TOOLS.has(tool.name) && state.phase === "EXPLORATION") setPhase("IMPLEMENTATION");
|
|
862
1063
|
bus.emit("tool_started", toolCallPreview(call), { tool: tool.name, args });
|
|
863
1064
|
const risk = tool.dynamicRisk ? tool.dynamicRisk(args) : tool.risk;
|
|
864
1065
|
let approved = true;
|
|
@@ -969,7 +1170,7 @@ ${systemExtra}` : "");
|
|
|
969
1170
|
});
|
|
970
1171
|
return { success, finalText, state };
|
|
971
1172
|
}
|
|
972
|
-
var MAX_CONTEXT_CHARS, READ_BUDGET, RATE_LIMIT_MAX_ATTEMPTS, KEEP_RECENT_TOOL;
|
|
1173
|
+
var MAX_CONTEXT_CHARS, READ_BUDGET, RATE_LIMIT_MAX_ATTEMPTS, MAX_VERIFY, EDIT_TOOLS, KEEP_RECENT_TOOL;
|
|
973
1174
|
var init_loop = __esm({
|
|
974
1175
|
"src/agent/loop.ts"() {
|
|
975
1176
|
"use strict";
|
|
@@ -977,9 +1178,12 @@ var init_loop = __esm({
|
|
|
977
1178
|
init_conversation();
|
|
978
1179
|
init_state();
|
|
979
1180
|
init_base();
|
|
1181
|
+
init_testing();
|
|
980
1182
|
MAX_CONTEXT_CHARS = 7e4;
|
|
981
1183
|
READ_BUDGET = 6;
|
|
982
1184
|
RATE_LIMIT_MAX_ATTEMPTS = 8;
|
|
1185
|
+
MAX_VERIFY = 3;
|
|
1186
|
+
EDIT_TOOLS = /* @__PURE__ */ new Set(["apply_patch", "write_file", "move_path"]);
|
|
983
1187
|
KEEP_RECENT_TOOL = 4;
|
|
984
1188
|
}
|
|
985
1189
|
});
|
|
@@ -988,7 +1192,7 @@ var init_loop = __esm({
|
|
|
988
1192
|
var version;
|
|
989
1193
|
var init_package = __esm({
|
|
990
1194
|
"package.json"() {
|
|
991
|
-
version = "0.1.
|
|
1195
|
+
version = "0.1.13";
|
|
992
1196
|
}
|
|
993
1197
|
});
|
|
994
1198
|
|
|
@@ -1354,6 +1558,7 @@ function App(props) {
|
|
|
1354
1558
|
const [showDetails, setShowDetails] = useState3(false);
|
|
1355
1559
|
const [thinkingText, setThinkingText] = useState3("");
|
|
1356
1560
|
const [currentEdit, setCurrentEdit] = useState3(null);
|
|
1561
|
+
const [phase, setPhase] = useState3("");
|
|
1357
1562
|
const finalTextRef = useRef(null);
|
|
1358
1563
|
const pendingTool = useRef(null);
|
|
1359
1564
|
const counter = useRef(0);
|
|
@@ -1374,6 +1579,10 @@ function App(props) {
|
|
|
1374
1579
|
if (delta) setThinkingText((prev) => (prev + delta).slice(-4e3));
|
|
1375
1580
|
return;
|
|
1376
1581
|
}
|
|
1582
|
+
if (event.type === "phase") {
|
|
1583
|
+
setPhase(event.message ?? "");
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1377
1586
|
if (event.type === "model_request" || event.type === "task_completed") {
|
|
1378
1587
|
setThinkingText("");
|
|
1379
1588
|
}
|
|
@@ -1767,7 +1976,11 @@ function App(props) {
|
|
|
1767
1976
|
SPINNER_FRAMES[frame],
|
|
1768
1977
|
" "
|
|
1769
1978
|
] }),
|
|
1770
|
-
/* @__PURE__ */
|
|
1979
|
+
/* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
1980
|
+
"agent ",
|
|
1981
|
+
PHASE_LABEL[phase] ?? "working",
|
|
1982
|
+
"\u2026 (Ctrl+C to exit)"
|
|
1983
|
+
] })
|
|
1771
1984
|
] }),
|
|
1772
1985
|
thinkingText ? /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
1773
1986
|
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u{1F4AD} " }),
|
|
@@ -1789,7 +2002,7 @@ function App(props) {
|
|
|
1789
2002
|
] })
|
|
1790
2003
|
] });
|
|
1791
2004
|
}
|
|
1792
|
-
var SPINNER_FRAMES, PROVIDER_NAMES, PROVIDER_DESCRIPTIONS, BANNER;
|
|
2005
|
+
var SPINNER_FRAMES, PHASE_LABEL, PROVIDER_NAMES, PROVIDER_DESCRIPTIONS, BANNER;
|
|
1793
2006
|
var init_App = __esm({
|
|
1794
2007
|
"src/tui/App.tsx"() {
|
|
1795
2008
|
"use strict";
|
|
@@ -1808,6 +2021,16 @@ var init_App = __esm({
|
|
|
1808
2021
|
init_KeyDialog();
|
|
1809
2022
|
init_package();
|
|
1810
2023
|
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2024
|
+
PHASE_LABEL = {
|
|
2025
|
+
INITIALIZATION: "starting",
|
|
2026
|
+
EXPLORATION: "exploring",
|
|
2027
|
+
PLANNING: "planning",
|
|
2028
|
+
IMPLEMENTATION: "implementing",
|
|
2029
|
+
VALIDATION: "verifying",
|
|
2030
|
+
DEBUGGING: "debugging",
|
|
2031
|
+
REVIEW: "reviewing",
|
|
2032
|
+
COMPLETION: "finalizing"
|
|
2033
|
+
};
|
|
1811
2034
|
PROVIDER_NAMES = ["kimi", "glm", "zai", "zai-coding", "openrouter", "nvidia", "mock"];
|
|
1812
2035
|
PROVIDER_DESCRIPTIONS = {
|
|
1813
2036
|
kimi: "Moonshot \xB7 api.moonshot.ai",
|
|
@@ -2324,20 +2547,43 @@ var applyPatch = {
|
|
|
2324
2547
|
if (oldString === newString) {
|
|
2325
2548
|
return { success: false, output: "old_string and new_string are identical; nothing to change." };
|
|
2326
2549
|
}
|
|
2327
|
-
const
|
|
2328
|
-
|
|
2329
|
-
return
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2550
|
+
const tryMatch = (c, o, n) => {
|
|
2551
|
+
const occ = c.split(o).length - 1;
|
|
2552
|
+
return occ === 1 ? c.replace(o, n) : null;
|
|
2553
|
+
};
|
|
2554
|
+
let updated = tryMatch(content, oldString, newString);
|
|
2555
|
+
let note = "";
|
|
2556
|
+
if (updated === null) {
|
|
2557
|
+
const lfContent = content.replace(/\r\n/g, "\n");
|
|
2558
|
+
const lfOld = oldString.replace(/\r\n/g, "\n");
|
|
2559
|
+
const lfNew = newString.replace(/\r\n/g, "\n");
|
|
2560
|
+
const lfUpdated = tryMatch(lfContent, lfOld, lfNew);
|
|
2561
|
+
if (lfUpdated !== null) {
|
|
2562
|
+
updated = lfUpdated;
|
|
2563
|
+
note = " (applied after normalizing CRLF \u2192 LF line endings)";
|
|
2564
|
+
}
|
|
2333
2565
|
}
|
|
2334
|
-
if (
|
|
2566
|
+
if (updated === null) {
|
|
2567
|
+
const strip = (s) => s.split("\n").map((l) => l.replace(/\s+$/, "")).join("\n");
|
|
2568
|
+
const sUpdated = tryMatch(strip(content), strip(oldString), strip(newString));
|
|
2569
|
+
if (sUpdated !== null) {
|
|
2570
|
+
updated = sUpdated;
|
|
2571
|
+
note = " (applied after trimming trailing whitespace to match)";
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
if (updated === null) {
|
|
2575
|
+
const occ = content.split(oldString).length - 1;
|
|
2576
|
+
if (occ === 0) {
|
|
2577
|
+
return {
|
|
2578
|
+
success: false,
|
|
2579
|
+
output: "old_string not found in file. Read the file again and copy the exact text, including whitespace."
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2335
2582
|
return {
|
|
2336
2583
|
success: false,
|
|
2337
|
-
output: `old_string occurs ${
|
|
2584
|
+
output: `old_string occurs ${occ} times. Include more surrounding lines to make it unique.`
|
|
2338
2585
|
};
|
|
2339
2586
|
}
|
|
2340
|
-
const updated = content.replace(oldString, newString);
|
|
2341
2587
|
fs2.writeFileSync(filePath, updated, "utf8");
|
|
2342
2588
|
const removed = oldString.split(/\r?\n/).length;
|
|
2343
2589
|
const added = newString.split(/\r?\n/).length;
|
|
@@ -2901,147 +3147,8 @@ var executeCommand = {
|
|
|
2901
3147
|
}
|
|
2902
3148
|
};
|
|
2903
3149
|
|
|
2904
|
-
// src/tools/
|
|
2905
|
-
|
|
2906
|
-
init_exec();
|
|
2907
|
-
import fs4 from "fs";
|
|
2908
|
-
import path4 from "path";
|
|
2909
|
-
var DEFAULT_TIMEOUT_MS2 = 18e4;
|
|
2910
|
-
function readPackageJson(cwd) {
|
|
2911
|
-
try {
|
|
2912
|
-
return JSON.parse(fs4.readFileSync(path4.join(cwd, "package.json"), "utf8"));
|
|
2913
|
-
} catch {
|
|
2914
|
-
return null;
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
function readTextIfExists(cwd, file) {
|
|
2918
|
-
try {
|
|
2919
|
-
return fs4.readFileSync(path4.join(cwd, file), "utf8");
|
|
2920
|
-
} catch {
|
|
2921
|
-
return null;
|
|
2922
|
-
}
|
|
2923
|
-
}
|
|
2924
|
-
function fileExists(cwd, file) {
|
|
2925
|
-
try {
|
|
2926
|
-
return fs4.existsSync(path4.join(cwd, file));
|
|
2927
|
-
} catch {
|
|
2928
|
-
return false;
|
|
2929
|
-
}
|
|
2930
|
-
}
|
|
2931
|
-
function detectTestCommand(cwd) {
|
|
2932
|
-
const pkg = readPackageJson(cwd);
|
|
2933
|
-
const testScript = pkg && typeof pkg.scripts?.test === "string" ? pkg.scripts.test : null;
|
|
2934
|
-
if (testScript && !/error|no test specified/i.test(testScript)) {
|
|
2935
|
-
return "npm test";
|
|
2936
|
-
}
|
|
2937
|
-
if (fileExists(cwd, "pytest.ini") || fileExists(cwd, "tests")) return "pytest -q";
|
|
2938
|
-
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
2939
|
-
if (pyproject && /\[tool\.pytest/.test(pyproject)) return "pytest -q";
|
|
2940
|
-
if (fileExists(cwd, "go.mod")) return "go test ./...";
|
|
2941
|
-
if (fileExists(cwd, "Cargo.toml")) return "cargo test";
|
|
2942
|
-
return null;
|
|
2943
|
-
}
|
|
2944
|
-
function detectLintCommand(cwd) {
|
|
2945
|
-
if (fileExists(cwd, "eslint.config.js") || fileExists(cwd, "eslint.config.mjs") || fileExists(cwd, ".eslintrc.json") || fileExists(cwd, ".eslintrc.js")) {
|
|
2946
|
-
return "npx --no-install eslint .";
|
|
2947
|
-
}
|
|
2948
|
-
if (fileExists(cwd, "biome.json")) return "npx --no-install biome check .";
|
|
2949
|
-
if (fileExists(cwd, ".ruff.toml") || fileExists(cwd, "ruff.toml")) return "ruff check .";
|
|
2950
|
-
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
2951
|
-
if (pyproject && /\[tool\.ruff/.test(pyproject)) return "ruff check .";
|
|
2952
|
-
return null;
|
|
2953
|
-
}
|
|
2954
|
-
function detectTypecheckCommand(cwd) {
|
|
2955
|
-
if (fileExists(cwd, "tsconfig.json")) return "npx --no-install tsc --noEmit";
|
|
2956
|
-
if (fileExists(cwd, "mypy.ini")) return "python -m mypy .";
|
|
2957
|
-
const pyproject = readTextIfExists(cwd, "pyproject.toml");
|
|
2958
|
-
if (pyproject && /\[tool\.mypy/.test(pyproject)) return "python -m mypy .";
|
|
2959
|
-
if (fileExists(cwd, "go.mod")) return "go vet ./...";
|
|
2960
|
-
if (fileExists(cwd, "Cargo.toml")) return "cargo check";
|
|
2961
|
-
return null;
|
|
2962
|
-
}
|
|
2963
|
-
function makeRunnerTool(config) {
|
|
2964
|
-
return {
|
|
2965
|
-
name: config.name,
|
|
2966
|
-
description: config.description,
|
|
2967
|
-
risk: "safe",
|
|
2968
|
-
timeoutMs: DEFAULT_TIMEOUT_MS2,
|
|
2969
|
-
parameters: {
|
|
2970
|
-
type: "object",
|
|
2971
|
-
properties: {
|
|
2972
|
-
command: {
|
|
2973
|
-
type: "string",
|
|
2974
|
-
description: "Exact command to run. If omitted, the project type is auto-detected."
|
|
2975
|
-
},
|
|
2976
|
-
timeout_ms: { type: "number", description: `Timeout in ms. Defaults to ${DEFAULT_TIMEOUT_MS2}.` }
|
|
2977
|
-
}
|
|
2978
|
-
},
|
|
2979
|
-
async execute(args, ctx) {
|
|
2980
|
-
let command = firstString(args, "command");
|
|
2981
|
-
if (!command) {
|
|
2982
|
-
command = config.detect(ctx.cwd) ?? void 0;
|
|
2983
|
-
if (!command) {
|
|
2984
|
-
return {
|
|
2985
|
-
success: false,
|
|
2986
|
-
output: `Could not auto-detect a command for this project. ${config.fallbackHint} Use the command argument to run one explicitly.`
|
|
2987
|
-
};
|
|
2988
|
-
}
|
|
2989
|
-
}
|
|
2990
|
-
const timeoutMs = Math.min(6e5, firstNumber(args, "timeout_ms") ?? DEFAULT_TIMEOUT_MS2);
|
|
2991
|
-
const outcome = await runShellCommand(command, ctx.cwd, timeoutMs);
|
|
2992
|
-
const formatted = formatOutcome(outcome);
|
|
2993
|
-
return { success: formatted.success, output: formatted.output, truncated: formatted.truncated };
|
|
2994
|
-
}
|
|
2995
|
-
};
|
|
2996
|
-
}
|
|
2997
|
-
var runTests = makeRunnerTool({
|
|
2998
|
-
name: "run_tests",
|
|
2999
|
-
description: "Run the project test suite. Auto-detects npm test / pytest / go test / cargo test from the project files, or run an exact command. Use this to verify changes.",
|
|
3000
|
-
detect: detectTestCommand,
|
|
3001
|
-
fallbackHint: "No test runner found (looked for package.json scripts.test, pytest, go, cargo)."
|
|
3002
|
-
});
|
|
3003
|
-
var runLinter = makeRunnerTool({
|
|
3004
|
-
name: "run_linter",
|
|
3005
|
-
description: "Run the project linter (eslint / biome / ruff auto-detected).",
|
|
3006
|
-
detect: detectLintCommand,
|
|
3007
|
-
fallbackHint: "No linter config found (looked for eslint, biome, ruff)."
|
|
3008
|
-
});
|
|
3009
|
-
var runTypecheck = makeRunnerTool({
|
|
3010
|
-
name: "run_typecheck",
|
|
3011
|
-
description: "Run static type checking (tsc --noEmit / mypy / go vet / cargo check auto-detected).",
|
|
3012
|
-
detect: detectTypecheckCommand,
|
|
3013
|
-
fallbackHint: "No typechecker config found (looked for tsconfig.json, mypy, go, cargo)."
|
|
3014
|
-
});
|
|
3015
|
-
var inspectEnv = {
|
|
3016
|
-
name: "inspect_env",
|
|
3017
|
-
description: "Inspect the environment: OS info, and which toolchains are installed with versions (node, npm, python, pip, git). Use this to adapt commands to the machine.",
|
|
3018
|
-
risk: "safe",
|
|
3019
|
-
parameters: { type: "object", properties: {} },
|
|
3020
|
-
async execute(_args, ctx) {
|
|
3021
|
-
const lines = [
|
|
3022
|
-
`os: ${process.platform} ${process.version} ${process.arch}`,
|
|
3023
|
-
`workspace: ${ctx.cwd}`
|
|
3024
|
-
];
|
|
3025
|
-
const probes = [
|
|
3026
|
-
["node", "node --version"],
|
|
3027
|
-
["npm", "npm --version"],
|
|
3028
|
-
["npx", "npx --version"],
|
|
3029
|
-
["python", "python --version"],
|
|
3030
|
-
["pip", "pip --version"],
|
|
3031
|
-
["git", "git --version"],
|
|
3032
|
-
["docker", "docker --version"]
|
|
3033
|
-
];
|
|
3034
|
-
const results = await Promise.all(
|
|
3035
|
-
probes.map(async ([label, probe]) => {
|
|
3036
|
-
const outcome = await runShellCommand(probe, ctx.cwd, 8e3);
|
|
3037
|
-
const version2 = `${outcome.stdout} ${outcome.stderr}`.trim().split("\n")[0] ?? "";
|
|
3038
|
-
return `${label}: ${outcome.exitCode === 0 ? version2 || "installed (version unknown)" : "not available"}`;
|
|
3039
|
-
})
|
|
3040
|
-
);
|
|
3041
|
-
lines.push(...results);
|
|
3042
|
-
return { success: true, output: lines.join("\n") };
|
|
3043
|
-
}
|
|
3044
|
-
};
|
|
3150
|
+
// src/tools/registry.ts
|
|
3151
|
+
init_testing();
|
|
3045
3152
|
|
|
3046
3153
|
// src/tools/memory.ts
|
|
3047
3154
|
init_config();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@menteeai/menteeswe",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "MenteE SWE — a model-agnostic autonomous software-engineering agent CLI. Bring your own intelligence: Kimi, GLM/Z.ai, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|