@menteeai/menteeswe 0.1.19 → 0.1.20

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 (2) hide show
  1. package/dist/cli.js +84 -29
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -751,39 +751,93 @@ function recentFile(cwd) {
751
751
  const hash = crypto3.createHash("sha1").update(cwd).digest("hex").slice(0, 16);
752
752
  return path8.join(sessionsDir(), `${hash}.files.json`);
753
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 {
754
+ function fileHash(content) {
755
+ return crypto3.createHash("sha1").update(content).digest("hex").slice(0, 12);
756
+ }
757
+ function normalizeRecords(value) {
758
+ if (!Array.isArray(value)) return [];
759
+ const out = [];
760
+ for (const item of value) {
761
+ if (typeof item === "string") out.push({ path: item });
762
+ else if (item && typeof item === "object" && typeof item.path === "string") {
763
+ out.push(item);
761
764
  }
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
765
  }
766
+ return out;
769
767
  }
770
- function formatRecentFiles(cwd) {
768
+ function loadRecentFiles(cwd) {
771
769
  try {
772
770
  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."
771
+ return { reads: normalizeRecords(parsed.reads), writes: normalizeRecords(parsed.writes) };
772
+ } catch {
773
+ return { reads: [], writes: [] };
774
+ }
775
+ }
776
+ function saveRecentFiles(cwd, reads, writes, hashes) {
777
+ try {
778
+ const prev = loadRecentFiles(cwd);
779
+ const absHash = (rel) => hashes?.get(path8.resolve(cwd, rel));
780
+ const merge = (known, fresh) => {
781
+ const byPath = /* @__PURE__ */ new Map();
782
+ for (const rel of fresh) {
783
+ byPath.set(rel, { path: rel, hash: absHash(rel) });
784
+ }
785
+ for (const rec of known) {
786
+ if (!byPath.has(rec.path)) byPath.set(rec.path, rec);
787
+ }
788
+ return [...byPath.values()].slice(0, 15);
789
+ };
790
+ fs9.writeFileSync(
791
+ recentFile(cwd),
792
+ JSON.stringify({ reads: merge(prev.reads, reads), writes: merge(prev.writes, writes) }, null, 2)
781
793
  );
782
- return lines.join("\n");
783
794
  } catch {
784
- return "";
785
795
  }
786
796
  }
797
+ function formatRecentFiles(cwd, prewarm) {
798
+ const stored = loadRecentFiles(cwd);
799
+ if (stored.reads.length === 0 && stored.writes.length === 0) return "";
800
+ const verify = (records) => {
801
+ const unchanged = [];
802
+ const changed = [];
803
+ const legacy = [];
804
+ for (const rec of records.slice(0, 15)) {
805
+ if (!rec.hash) {
806
+ legacy.push(rec);
807
+ continue;
808
+ }
809
+ try {
810
+ const content = fs9.readFileSync(path8.resolve(cwd, rec.path), "utf8");
811
+ const current = fileHash(content);
812
+ if (current === rec.hash) {
813
+ unchanged.push(rec);
814
+ prewarm?.set(path8.resolve(cwd, rec.path), current);
815
+ } else {
816
+ changed.push(rec);
817
+ }
818
+ } catch {
819
+ changed.push(rec);
820
+ }
821
+ }
822
+ return { unchanged, changed, legacy };
823
+ };
824
+ const w = verify(stored.writes);
825
+ const writePaths = new Set(stored.writes.map((r2) => r2.path));
826
+ const r = verify(stored.reads.filter((rec) => !writePaths.has(rec.path)));
827
+ const lines = ["# Known files from earlier tasks in this project"];
828
+ const join = (list) => list.map((rec) => rec.path).join(", ");
829
+ if (w.unchanged.length > 0) lines.push(`Modified recently, verified unchanged on disk: ${join(w.unchanged)}`);
830
+ if (r.unchanged.length > 0) lines.push(`Read recently, verified unchanged on disk: ${join(r.unchanged)}`);
831
+ const stale = [...w.changed, ...r.changed];
832
+ if (stale.length > 0) lines.push(`Changed (or missing) on disk since then \u2014 re-read before editing: ${join(stale)}`);
833
+ for (const rec of [...w.legacy, ...r.legacy]) {
834
+ lines.push(`Known from earlier tasks (state unknown): ${rec.path}`);
835
+ }
836
+ lines.push(
837
+ "For files verified unchanged you may apply_patch directly without re-reading; the harness validates the hash and will tell you if the file changed. Do not re-search or re-read verified files unless needed."
838
+ );
839
+ return lines.join("\n");
840
+ }
787
841
  var init_conversation = __esm({
788
842
  "src/agent/conversation.ts"() {
789
843
  "use strict";
@@ -935,8 +989,9 @@ async function runAgent(options) {
935
989
  signal
936
990
  } = options;
937
991
  const state = createAgentState(task, maxIterations);
992
+ const fileState = /* @__PURE__ */ new Map();
938
993
  const prior = formatConversationContext(cwd);
939
- const knownFiles = formatRecentFiles(cwd);
994
+ const knownFiles = formatRecentFiles(cwd, fileState);
940
995
  const system = buildSystemPrompt(cwd) + (knownFiles ? `
941
996
 
942
997
  ${knownFiles}` : "") + (prior ? `
@@ -951,7 +1006,7 @@ ${systemExtra}` : "");
951
1006
  const toolCtx = {
952
1007
  cwd,
953
1008
  approval,
954
- fileState: /* @__PURE__ */ new Map(),
1009
+ fileState,
955
1010
  emit: (type, message, data) => {
956
1011
  bus.emit(type, message, data);
957
1012
  }
@@ -1003,7 +1058,7 @@ ${systemExtra}` : "");
1003
1058
  bus.emit("error", message + hint);
1004
1059
  finalText = `Model request failed: ${message}`;
1005
1060
  appendTurn(cwd, task, finalText);
1006
- saveRecentFiles(cwd, state.readFiles, state.modifiedFiles);
1061
+ saveRecentFiles(cwd, state.readFiles, state.modifiedFiles, fileState);
1007
1062
  bus.emit("task_completed", finalText.slice(0, 400), {
1008
1063
  success: false,
1009
1064
  finalText,
@@ -1208,7 +1263,7 @@ Investigate the root cause, fix it, then finish with a final answer.`
1208
1263
  const success = sawFinish && state.errors.length === 0;
1209
1264
  if (finalText && !signal?.aborted) {
1210
1265
  appendTurn(cwd, task, finalText);
1211
- saveRecentFiles(cwd, state.readFiles, state.modifiedFiles);
1266
+ saveRecentFiles(cwd, state.readFiles, state.modifiedFiles, fileState);
1212
1267
  }
1213
1268
  bus.emit("task_completed", finalText.slice(0, 400), {
1214
1269
  success,
@@ -1244,7 +1299,7 @@ var init_loop = __esm({
1244
1299
  var version;
1245
1300
  var init_package = __esm({
1246
1301
  "package.json"() {
1247
- version = "0.1.19";
1302
+ version = "0.1.20";
1248
1303
  }
1249
1304
  });
1250
1305
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@menteeai/menteeswe",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
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",