@menteeai/menteeswe 0.1.17 → 0.1.19
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 +97 -19
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -426,7 +426,9 @@ function formatEvent(event) {
|
|
|
426
426
|
const output = typeof event.data?.output === "string" ? event.data.output.trim() : "";
|
|
427
427
|
const firstLine = (output.split("\n")[0] ?? event.message ?? "").slice(0, 160);
|
|
428
428
|
const color = success ? CATEGORY_COLOR[TOOL_CATEGORY[tool] ?? "other"] : chalk.red;
|
|
429
|
-
|
|
429
|
+
const resultChars = typeof event.data?.resultChars === "number" ? event.data.resultChars : 0;
|
|
430
|
+
const sizeNote = resultChars > 0 ? chalk.dim(` \xB7 ~${(resultChars / 4 / 1e3).toFixed(1)}k tok`) : "";
|
|
431
|
+
return color(` ${success ? "\u2713" : "\u2717"} ${firstLine}`) + sizeNote;
|
|
430
432
|
}
|
|
431
433
|
case "approval":
|
|
432
434
|
return chalk.magenta(`\u{1F510} Asking permission to use ${event.message ?? "tool"}...`);
|
|
@@ -692,7 +694,7 @@ var init_prompts = __esm({
|
|
|
692
694
|
// src/agent/conversation.ts
|
|
693
695
|
import fs9 from "fs";
|
|
694
696
|
import path8 from "path";
|
|
695
|
-
import
|
|
697
|
+
import crypto3 from "crypto";
|
|
696
698
|
import os3 from "os";
|
|
697
699
|
function sessionsDir() {
|
|
698
700
|
const dir = path8.join(os3.homedir(), ".mentee", "sessions");
|
|
@@ -700,7 +702,7 @@ function sessionsDir() {
|
|
|
700
702
|
return dir;
|
|
701
703
|
}
|
|
702
704
|
function sessionFile(cwd) {
|
|
703
|
-
const hash =
|
|
705
|
+
const hash = crypto3.createHash("sha1").update(cwd).digest("hex").slice(0, 16);
|
|
704
706
|
return path8.join(sessionsDir(), `${hash}.json`);
|
|
705
707
|
}
|
|
706
708
|
function loadConversation(cwd, limit = 12) {
|
|
@@ -745,6 +747,43 @@ Assistant: ${t.response.trim()}
|
|
|
745
747
|
}
|
|
746
748
|
return [header, ...blocks, ""].join("\n");
|
|
747
749
|
}
|
|
750
|
+
function recentFile(cwd) {
|
|
751
|
+
const hash = crypto3.createHash("sha1").update(cwd).digest("hex").slice(0, 16);
|
|
752
|
+
return path8.join(sessionsDir(), `${hash}.files.json`);
|
|
753
|
+
}
|
|
754
|
+
function saveRecentFiles(cwd, reads, writes) {
|
|
755
|
+
try {
|
|
756
|
+
let prev = { reads: [], writes: [] };
|
|
757
|
+
try {
|
|
758
|
+
const parsed = JSON.parse(fs9.readFileSync(recentFile(cwd), "utf8"));
|
|
759
|
+
if (parsed && Array.isArray(parsed.reads) && Array.isArray(parsed.writes)) prev = parsed;
|
|
760
|
+
} catch {
|
|
761
|
+
}
|
|
762
|
+
const merge = (known, fresh) => [.../* @__PURE__ */ new Set([...fresh, ...known])].slice(0, 15);
|
|
763
|
+
fs9.writeFileSync(
|
|
764
|
+
recentFile(cwd),
|
|
765
|
+
JSON.stringify({ reads: merge(prev.reads, reads), writes: merge(prev.writes, writes) }, null, 2)
|
|
766
|
+
);
|
|
767
|
+
} catch {
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function formatRecentFiles(cwd) {
|
|
771
|
+
try {
|
|
772
|
+
const parsed = JSON.parse(fs9.readFileSync(recentFile(cwd), "utf8"));
|
|
773
|
+
const writes = (parsed.writes ?? []).slice(0, 10);
|
|
774
|
+
const reads = (parsed.reads ?? []).filter((f) => !writes.includes(f)).slice(0, 10);
|
|
775
|
+
if (reads.length === 0 && writes.length === 0) return "";
|
|
776
|
+
const lines = ["# Known files from earlier tasks in this project"];
|
|
777
|
+
if (writes.length > 0) lines.push(`Modified recently: ${writes.join(", ")}`);
|
|
778
|
+
if (reads.length > 0) lines.push(`Read recently: ${reads.join(", ")}`);
|
|
779
|
+
lines.push(
|
|
780
|
+
"Reuse this knowledge \u2014 do not re-search or re-read these files unless you suspect they changed. If you read a file earlier and it is unchanged, you may apply_patch directly."
|
|
781
|
+
);
|
|
782
|
+
return lines.join("\n");
|
|
783
|
+
} catch {
|
|
784
|
+
return "";
|
|
785
|
+
}
|
|
786
|
+
}
|
|
748
787
|
var init_conversation = __esm({
|
|
749
788
|
"src/agent/conversation.ts"() {
|
|
750
789
|
"use strict";
|
|
@@ -759,6 +798,7 @@ function createAgentState(task, maxIterations) {
|
|
|
759
798
|
iteration: 0,
|
|
760
799
|
maxIterations,
|
|
761
800
|
modifiedFiles: [],
|
|
801
|
+
readFiles: [],
|
|
762
802
|
commandsRun: [],
|
|
763
803
|
errors: [],
|
|
764
804
|
lastErrorSignature: null,
|
|
@@ -869,7 +909,8 @@ async function runVerification(tools, ctx, bus, state, cwd) {
|
|
|
869
909
|
bus.emit("tool_completed", `verify \xB7 ${tool.name}`, {
|
|
870
910
|
tool: tool.name,
|
|
871
911
|
success: res.success,
|
|
872
|
-
output: res.output.slice(0, 2e3)
|
|
912
|
+
output: res.output.slice(0, 2e3),
|
|
913
|
+
resultChars: res.output.length
|
|
873
914
|
});
|
|
874
915
|
combined += `${tool.name}: ${res.output}
|
|
875
916
|
`;
|
|
@@ -895,7 +936,10 @@ async function runAgent(options) {
|
|
|
895
936
|
} = options;
|
|
896
937
|
const state = createAgentState(task, maxIterations);
|
|
897
938
|
const prior = formatConversationContext(cwd);
|
|
898
|
-
const
|
|
939
|
+
const knownFiles = formatRecentFiles(cwd);
|
|
940
|
+
const system = buildSystemPrompt(cwd) + (knownFiles ? `
|
|
941
|
+
|
|
942
|
+
${knownFiles}` : "") + (prior ? `
|
|
899
943
|
|
|
900
944
|
${prior}
|
|
901
945
|
|
|
@@ -907,6 +951,7 @@ ${systemExtra}` : "");
|
|
|
907
951
|
const toolCtx = {
|
|
908
952
|
cwd,
|
|
909
953
|
approval,
|
|
954
|
+
fileState: /* @__PURE__ */ new Map(),
|
|
910
955
|
emit: (type, message, data) => {
|
|
911
956
|
bus.emit(type, message, data);
|
|
912
957
|
}
|
|
@@ -958,6 +1003,7 @@ ${systemExtra}` : "");
|
|
|
958
1003
|
bus.emit("error", message + hint);
|
|
959
1004
|
finalText = `Model request failed: ${message}`;
|
|
960
1005
|
appendTurn(cwd, task, finalText);
|
|
1006
|
+
saveRecentFiles(cwd, state.readFiles, state.modifiedFiles);
|
|
961
1007
|
bus.emit("task_completed", finalText.slice(0, 400), {
|
|
962
1008
|
success: false,
|
|
963
1009
|
finalText,
|
|
@@ -1011,7 +1057,7 @@ ${systemExtra}` : "");
|
|
|
1011
1057
|
messages.push({
|
|
1012
1058
|
role: "user",
|
|
1013
1059
|
content: `SYSTEM NOTE: Verification failed.
|
|
1014
|
-
${verdict.output}
|
|
1060
|
+
${verdict.output.slice(0, 2e3)}
|
|
1015
1061
|
Investigate the root cause, fix it, then finish with a final answer.`
|
|
1016
1062
|
});
|
|
1017
1063
|
sawFinish = false;
|
|
@@ -1106,7 +1152,8 @@ Investigate the root cause, fix it, then finish with a final answer.`
|
|
|
1106
1152
|
bus.emit("tool_completed", toolCallPreview(call), {
|
|
1107
1153
|
tool: tool.name,
|
|
1108
1154
|
success: result.success,
|
|
1109
|
-
output: result.output.slice(0, 2e3)
|
|
1155
|
+
output: result.output.slice(0, 2e3),
|
|
1156
|
+
resultChars: result.output.length
|
|
1110
1157
|
});
|
|
1111
1158
|
if (tool.name === "apply_patch" && result.success && result.data?.kind === "patch") {
|
|
1112
1159
|
bus.emit("patch", void 0, {
|
|
@@ -1117,7 +1164,10 @@ Investigate the root cause, fix it, then finish with a final answer.`
|
|
|
1117
1164
|
}
|
|
1118
1165
|
const readHeader = result.success && tool.name === "read_file" ? result.output.split("\n")[0] ?? "" : "";
|
|
1119
1166
|
const readRel = readHeader ? normalizeRel(readHeader.replace(/\s+\(\d+ lines\)\s*$/, "").trim()) : "";
|
|
1120
|
-
if (readRel)
|
|
1167
|
+
if (readRel) {
|
|
1168
|
+
readMsgIndex.set(readRel, messages.length);
|
|
1169
|
+
if (!state.readFiles.includes(readRel) && state.readFiles.length < 20) state.readFiles.push(readRel);
|
|
1170
|
+
}
|
|
1121
1171
|
if ((tool.name === "apply_patch" || tool.name === "write_file") && result.success) {
|
|
1122
1172
|
const patchedRel = normalizeRel(
|
|
1123
1173
|
typeof result.data?.path === "string" && result.data.path ? result.data.path : typeof args.path === "string" ? args.path : ""
|
|
@@ -1135,10 +1185,11 @@ Investigate the root cause, fix it, then finish with a final answer.`
|
|
|
1135
1185
|
}
|
|
1136
1186
|
}
|
|
1137
1187
|
}
|
|
1188
|
+
const { text: historyOutput } = truncateOutput(result.output, MAX_RESULT_HISTORY_CHARS);
|
|
1138
1189
|
messages.push({
|
|
1139
1190
|
role: "tool",
|
|
1140
1191
|
tool_call_id: call.id,
|
|
1141
|
-
content:
|
|
1192
|
+
content: historyOutput
|
|
1142
1193
|
});
|
|
1143
1194
|
}
|
|
1144
1195
|
if (signal?.aborted) {
|
|
@@ -1155,7 +1206,10 @@ Investigate the root cause, fix it, then finish with a final answer.`
|
|
|
1155
1206
|
bus.emit("warning", finalText);
|
|
1156
1207
|
}
|
|
1157
1208
|
const success = sawFinish && state.errors.length === 0;
|
|
1158
|
-
if (finalText && !signal?.aborted)
|
|
1209
|
+
if (finalText && !signal?.aborted) {
|
|
1210
|
+
appendTurn(cwd, task, finalText);
|
|
1211
|
+
saveRecentFiles(cwd, state.readFiles, state.modifiedFiles);
|
|
1212
|
+
}
|
|
1159
1213
|
bus.emit("task_completed", finalText.slice(0, 400), {
|
|
1160
1214
|
success,
|
|
1161
1215
|
finalText,
|
|
@@ -1168,7 +1222,7 @@ Investigate the root cause, fix it, then finish with a final answer.`
|
|
|
1168
1222
|
});
|
|
1169
1223
|
return { success, finalText, state };
|
|
1170
1224
|
}
|
|
1171
|
-
var MAX_CONTEXT_CHARS, RATE_LIMIT_MAX_ATTEMPTS, MAX_VERIFY, EDIT_TOOLS, KEEP_RECENT_TOOL;
|
|
1225
|
+
var MAX_CONTEXT_CHARS, MAX_RESULT_HISTORY_CHARS, RATE_LIMIT_MAX_ATTEMPTS, MAX_VERIFY, EDIT_TOOLS, KEEP_RECENT_TOOL;
|
|
1172
1226
|
var init_loop = __esm({
|
|
1173
1227
|
"src/agent/loop.ts"() {
|
|
1174
1228
|
"use strict";
|
|
@@ -1178,6 +1232,7 @@ var init_loop = __esm({
|
|
|
1178
1232
|
init_base();
|
|
1179
1233
|
init_testing();
|
|
1180
1234
|
MAX_CONTEXT_CHARS = 4e4;
|
|
1235
|
+
MAX_RESULT_HISTORY_CHARS = 12e3;
|
|
1181
1236
|
RATE_LIMIT_MAX_ATTEMPTS = 8;
|
|
1182
1237
|
MAX_VERIFY = 3;
|
|
1183
1238
|
EDIT_TOOLS = /* @__PURE__ */ new Set(["apply_patch", "write_file", "move_path"]);
|
|
@@ -1189,7 +1244,7 @@ var init_loop = __esm({
|
|
|
1189
1244
|
var version;
|
|
1190
1245
|
var init_package = __esm({
|
|
1191
1246
|
"package.json"() {
|
|
1192
|
-
version = "0.1.
|
|
1247
|
+
version = "0.1.19";
|
|
1193
1248
|
}
|
|
1194
1249
|
});
|
|
1195
1250
|
|
|
@@ -1552,7 +1607,7 @@ function App(props) {
|
|
|
1552
1607
|
const [toolHistory, setToolHistory] = useState3([]);
|
|
1553
1608
|
const [inspectorIndex, setInspectorIndex] = useState3(null);
|
|
1554
1609
|
const [detailsOpen, setDetailsOpen] = useState3(false);
|
|
1555
|
-
const [showDetails, setShowDetails] = useState3(
|
|
1610
|
+
const [showDetails, setShowDetails] = useState3(true);
|
|
1556
1611
|
const [thinkingText, setThinkingText] = useState3("");
|
|
1557
1612
|
const [phase, setPhase] = useState3("");
|
|
1558
1613
|
const [showEdits, setShowEdits] = useState3(true);
|
|
@@ -2363,6 +2418,10 @@ function createProvider(provider, config, modelOverride) {
|
|
|
2363
2418
|
init_base();
|
|
2364
2419
|
import fs2 from "fs";
|
|
2365
2420
|
import path2 from "path";
|
|
2421
|
+
import crypto from "crypto";
|
|
2422
|
+
function contentHash(content) {
|
|
2423
|
+
return crypto.createHash("sha1").update(content).digest("hex").slice(0, 12);
|
|
2424
|
+
}
|
|
2366
2425
|
function resolveWithinWorkspace(cwd, target) {
|
|
2367
2426
|
const resolved = path2.resolve(cwd, target);
|
|
2368
2427
|
const normalizedCwd = path2.resolve(cwd);
|
|
@@ -2497,9 +2556,16 @@ var readFile = {
|
|
|
2497
2556
|
if (start > lines.length) {
|
|
2498
2557
|
return {
|
|
2499
2558
|
success: false,
|
|
2500
|
-
output: `start_line ${start} is beyond end of file (${lines.length} lines)
|
|
2559
|
+
output: `READ_RANGE_INVALID: start_line ${start} is beyond end of file (total_lines ${lines.length}). Valid range: 1-${lines.length}. Recovery: retry read_file with start_line <= ${Math.max(1, lines.length)} or omit the range.`
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
if (Number.isNaN(end) || end < start) {
|
|
2563
|
+
return {
|
|
2564
|
+
success: false,
|
|
2565
|
+
output: `READ_RANGE_INVALID: end_line (${args.end_line}) is before start_line (${start}). Valid range: 1-${lines.length}. Recovery: retry with end_line >= start_line.`
|
|
2501
2566
|
};
|
|
2502
2567
|
}
|
|
2568
|
+
ctx.fileState?.set(filePath, contentHash(content));
|
|
2503
2569
|
const slice = lines.slice(start - 1, end).map((line, i) => `${start + i}: ${line}`);
|
|
2504
2570
|
const { text, truncated } = truncateOutput(slice.join("\n"), 12e3);
|
|
2505
2571
|
const note = end < lines.length ? `
|
|
@@ -2529,6 +2595,7 @@ var writeFile = {
|
|
|
2529
2595
|
const content = requireString(args, "content");
|
|
2530
2596
|
fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
2531
2597
|
fs2.writeFileSync(filePath, content, "utf8");
|
|
2598
|
+
ctx.fileState?.set(filePath, contentHash(content));
|
|
2532
2599
|
return {
|
|
2533
2600
|
success: true,
|
|
2534
2601
|
output: `Wrote ${Buffer.byteLength(content, "utf8")} bytes to ${relativeToWorkspace(ctx.cwd, filePath)}`
|
|
@@ -2561,6 +2628,16 @@ var applyPatch = {
|
|
|
2561
2628
|
if (oldString === newString) {
|
|
2562
2629
|
return { success: false, output: "old_string and new_string are identical; nothing to change." };
|
|
2563
2630
|
}
|
|
2631
|
+
const relPath = relativeToWorkspace(ctx.cwd, filePath);
|
|
2632
|
+
const totalLines = content.split(/\r?\n/).length;
|
|
2633
|
+
const currentHash = contentHash(content);
|
|
2634
|
+
const knownHash = ctx.fileState?.get(filePath);
|
|
2635
|
+
if (knownHash && knownHash !== currentHash) {
|
|
2636
|
+
return {
|
|
2637
|
+
success: false,
|
|
2638
|
+
output: `FILE_CHANGED: ${relPath} changed since it was last read (expected hash ${knownHash}, current ${currentHash}, total_lines ${totalLines}). Recovery: read_file ${relPath} again, then retry apply_patch against the current text.`
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2564
2641
|
const tryMatch = (c, o, n) => {
|
|
2565
2642
|
const occ = c.split(o).length - 1;
|
|
2566
2643
|
return occ === 1 ? c.replace(o, n) : null;
|
|
@@ -2590,15 +2667,16 @@ var applyPatch = {
|
|
|
2590
2667
|
if (occ === 0) {
|
|
2591
2668
|
return {
|
|
2592
2669
|
success: false,
|
|
2593
|
-
output:
|
|
2670
|
+
output: `PATCH_FAILED: old_string not found in ${relPath} (total_lines ${totalLines}, hash ${currentHash}). Recovery: read_file ${relPath} (or the relevant line range) and copy the exact text including whitespace, then retry. Do not guess.`
|
|
2594
2671
|
};
|
|
2595
2672
|
}
|
|
2596
2673
|
return {
|
|
2597
2674
|
success: false,
|
|
2598
|
-
output: `old_string occurs ${occ} times.
|
|
2675
|
+
output: `PATCH_FAILED: old_string occurs ${occ} times in ${relPath}. Recovery: include more surrounding lines to make it unique, then retry.`
|
|
2599
2676
|
};
|
|
2600
2677
|
}
|
|
2601
2678
|
fs2.writeFileSync(filePath, updated, "utf8");
|
|
2679
|
+
ctx.fileState?.set(filePath, contentHash(updated));
|
|
2602
2680
|
const removed = oldString.split(/\r?\n/).length;
|
|
2603
2681
|
const added = newString.split(/\r?\n/).length;
|
|
2604
2682
|
return {
|
|
@@ -3169,12 +3247,12 @@ init_config();
|
|
|
3169
3247
|
init_base();
|
|
3170
3248
|
import fs5 from "fs";
|
|
3171
3249
|
import path5 from "path";
|
|
3172
|
-
import
|
|
3250
|
+
import crypto2 from "crypto";
|
|
3173
3251
|
function memoryDir() {
|
|
3174
3252
|
return path5.join(configDir(), "memory");
|
|
3175
3253
|
}
|
|
3176
3254
|
function memoryFile(cwd) {
|
|
3177
|
-
const key =
|
|
3255
|
+
const key = crypto2.createHash("sha1").update(path5.resolve(cwd)).digest("hex").slice(0, 16);
|
|
3178
3256
|
return path5.join(memoryDir(), `${key}.json`);
|
|
3179
3257
|
}
|
|
3180
3258
|
function load(cwd) {
|
|
@@ -3216,7 +3294,7 @@ var memoryTool = {
|
|
|
3216
3294
|
}
|
|
3217
3295
|
const topic = firstString(args, "topic") ?? "";
|
|
3218
3296
|
const entry = {
|
|
3219
|
-
id:
|
|
3297
|
+
id: crypto2.randomBytes(4).toString("hex"),
|
|
3220
3298
|
topic,
|
|
3221
3299
|
content: content.trim(),
|
|
3222
3300
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@menteeai/menteeswe",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
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",
|