micro-models-agent 0.39.0 → 0.40.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.
Files changed (96) hide show
  1. package/bin/mma.mjs +41 -41
  2. package/dist/cli/commands.js +116 -3
  3. package/dist/cli/main.js +35 -8
  4. package/dist/cli/repl-commands.js +633 -0
  5. package/dist/cli/repl.js +110 -611
  6. package/dist/cli/setup.js +32 -12
  7. package/dist/config/config.js +46 -30
  8. package/dist/config/defaults.js +10 -1
  9. package/dist/config/security.js +15 -8
  10. package/dist/core/agent-moe.js +24 -12
  11. package/dist/core/agent.js +281 -47
  12. package/dist/core/bootstrap.js +52 -36
  13. package/dist/core/session-logger.js +35 -2
  14. package/dist/core/workspace.js +76 -0
  15. package/dist/i18n/en.json +79 -15
  16. package/dist/i18n/index.js +12 -9
  17. package/dist/i18n/ru.json +79 -15
  18. package/dist/index.js +13 -13
  19. package/dist/llm/openai-compat.js +39 -10
  20. package/dist/logger/app-logger.js +83 -16
  21. package/dist/logger/file-log.js +151 -0
  22. package/dist/main.js +537 -284
  23. package/dist/modules/browser/bridge-server.mjs +113 -105
  24. package/dist/modules/browser/session.js +108 -60
  25. package/dist/modules/certification/cli.js +176 -0
  26. package/dist/modules/certification/fact-checker.js +84 -0
  27. package/dist/modules/certification/loader.js +111 -0
  28. package/dist/modules/certification/manifest.js +50 -0
  29. package/dist/modules/certification/runner.js +162 -0
  30. package/dist/modules/certification/scenarios.js +124 -0
  31. package/dist/modules/certification/types.js +1 -0
  32. package/dist/modules/context/manager.js +119 -10
  33. package/dist/modules/execution/auditor.js +33 -39
  34. package/dist/modules/execution/index.js +8 -6
  35. package/dist/modules/execution/module.js +474 -32
  36. package/dist/modules/execution/moe-executor.js +97 -40
  37. package/dist/modules/execution/plan-coverage.js +68 -0
  38. package/dist/modules/execution/plan-persister.js +46 -0
  39. package/dist/modules/execution/plan-store.js +159 -0
  40. package/dist/modules/execution/planner.js +63 -13
  41. package/dist/modules/execution/stuck-detector.js +252 -39
  42. package/dist/modules/execution/tracker.js +21 -7
  43. package/dist/modules/execution/verifier.js +46 -17
  44. package/dist/modules/hallucination/confidence.js +7 -2
  45. package/dist/modules/hallucination/consistency.js +8 -42
  46. package/dist/modules/hallucination/detector.js +26 -21
  47. package/dist/modules/hallucination/factual.js +170 -150
  48. package/dist/modules/hallucination/index.js +5 -4
  49. package/dist/modules/hallucination/js-identifiers.js +72 -0
  50. package/dist/modules/hallucination/llm-judge.js +103 -0
  51. package/dist/modules/index.js +5 -5
  52. package/dist/modules/lsp/client.js +235 -0
  53. package/dist/modules/lsp/config.js +81 -0
  54. package/dist/modules/lsp/index.js +3 -0
  55. package/dist/modules/lsp/module.js +68 -0
  56. package/dist/modules/lsp/types.js +1 -0
  57. package/dist/modules/mcp/client.js +8 -2
  58. package/dist/modules/memory/store.js +4 -0
  59. package/dist/modules/plugins/builtin/lint-on-write.js +143 -38
  60. package/dist/modules/processes/index.js +1 -2
  61. package/dist/modules/processes/registry.js +125 -35
  62. package/dist/modules/processes/runner.js +9 -110
  63. package/dist/modules/security/audit-log.js +30 -10
  64. package/dist/modules/security/command-validator.js +42 -16
  65. package/dist/modules/security/content-scanner.js +9 -8
  66. package/dist/modules/security/network-validator.js +2 -2
  67. package/dist/modules/security/path-validator.js +64 -10
  68. package/dist/modules/security/security-policies.js +221 -67
  69. package/dist/modules/security/session-encryption.js +42 -25
  70. package/dist/modules/session/manager.js +15 -10
  71. package/dist/modules/session/store.js +62 -8
  72. package/dist/modules/skills/index.js +2 -3
  73. package/dist/modules/skills/module.js +10 -23
  74. package/dist/tools/bash.js +287 -90
  75. package/dist/tools/create-dir.js +0 -1
  76. package/dist/tools/delete-file.js +0 -1
  77. package/dist/tools/edit-file.js +10 -8
  78. package/dist/tools/executor.js +57 -7
  79. package/dist/tools/grep-tool.js +51 -29
  80. package/dist/tools/index.js +55 -40
  81. package/dist/tools/load-skill.js +14 -18
  82. package/dist/tools/move-file.js +3 -2
  83. package/dist/tools/pipeline-run.js +1 -1
  84. package/dist/tools/read-file.js +15 -5
  85. package/dist/tools/search-history.js +42 -22
  86. package/dist/tools/subagent.js +21 -12
  87. package/dist/tools/web-browse.js +54 -25
  88. package/dist/tools/web-fetch.js +60 -34
  89. package/dist/tools/web-search.js +39 -20
  90. package/dist/tools/write-file.js +13 -10
  91. package/dist/ui/diff.js +9 -16
  92. package/dist/ui/renderer.js +69 -6
  93. package/package.json +48 -45
  94. package/dist/modules/context/history.js +0 -15
  95. package/dist/modules/processes/detect.js +0 -34
  96. package/dist/modules/skills/matcher.js +0 -27
@@ -0,0 +1,124 @@
1
+ export const BUILTIN_SCENARIOS = [
2
+ {
3
+ id: "2.2-create-file",
4
+ title: "Create single file",
5
+ tags: ["core"],
6
+ mode: "run",
7
+ prompt: 'Create a file hello.ts with content: export const msg = "Hello, MMA!";',
8
+ checks: [
9
+ { type: "fileExists", path: "hello.ts" },
10
+ { type: "fileContent", path: "hello.ts", contains: "Hello, MMA!" },
11
+ ],
12
+ },
13
+ {
14
+ id: "2.3-create-dir-file",
15
+ title: "Create directory and file",
16
+ tags: ["core"],
17
+ mode: "run",
18
+ prompt: "Create directory src/utils and file src/utils/helper.ts with content: export const add = (a: number, b: number) => a + b;",
19
+ checks: [
20
+ { type: "dirExists", path: "src/utils" },
21
+ { type: "fileExists", path: "src/utils/helper.ts" },
22
+ { type: "fileContent", path: "src/utils/helper.ts", contains: "a + b" },
23
+ ],
24
+ },
25
+ {
26
+ id: "2.6-move-file",
27
+ title: "Move/rename file",
28
+ tags: ["core"],
29
+ mode: "run",
30
+ prompt: 'Create file old-name.txt with content "test". Rename it to new-name.txt.',
31
+ checks: [
32
+ { type: "fileNotExists", path: "old-name.txt" },
33
+ { type: "fileExists", path: "new-name.txt" },
34
+ { type: "fileContent", path: "new-name.txt", contains: "test" },
35
+ ],
36
+ },
37
+ {
38
+ id: "2.4-edit-file",
39
+ title: "Create then edit file",
40
+ tags: ["core"],
41
+ mode: "run",
42
+ prompt: "Create helpers.ts with functions add and subtract. Then edit the add function to also log its arguments with console.log before returning.",
43
+ checks: [
44
+ { type: "fileExists", path: "helpers.ts" },
45
+ { type: "fileRegex", path: "helpers.ts", pattern: "console\\.log" },
46
+ ],
47
+ },
48
+ {
49
+ id: "3.1-calculator",
50
+ title: "Multi-step calculator module",
51
+ tags: ["core"],
52
+ mode: "run",
53
+ prompt: "Create a simple calculator module: 1. Create src/calculator.ts with functions add, subtract, multiply, divide. 2. Create src/calculator.test.ts with a basic test for each function. 3. Run the tests with bun test src/calculator.test.ts",
54
+ checks: [
55
+ { type: "fileExists", path: "src/calculator.ts" },
56
+ { type: "fileExists", path: "src/calculator.test.ts" },
57
+ {
58
+ type: "fileContent",
59
+ path: "src/calculator.ts",
60
+ contains: "export function add",
61
+ },
62
+ ],
63
+ },
64
+ {
65
+ id: "3.5-data-pipeline",
66
+ title: "Data processing pipeline",
67
+ tags: ["core"],
68
+ mode: "run",
69
+ prompt: "Create a data processing script: 1. Create data/input.json with an array of 10 objects {id, name, value}. 2. Create src/process.ts that reads input, filters value > 50, writes output.json. 3. Run the script and verify output.json has filtered results.",
70
+ checks: [
71
+ { type: "fileExists", path: "data/input.json" },
72
+ { type: "fileExists", path: "src/process.ts" },
73
+ { type: "fileExists", path: "output.json" },
74
+ ],
75
+ },
76
+ {
77
+ id: "1.1-question-tool",
78
+ title: "Question tool (removed)",
79
+ tags: ["core"],
80
+ mode: "skip",
81
+ prompt: "",
82
+ checks: [],
83
+ skipReason: "question/approve tools removed from tools/index.ts",
84
+ },
85
+ {
86
+ id: "12.1-attach-image",
87
+ title: "Attach image from file",
88
+ tags: ["image"],
89
+ mode: "run",
90
+ prompt: "Use the attach_image tool to load test.png, then create a file description.txt with your description of the image.",
91
+ fixtures: [{ source: "docs/testing/fixtures/test.png", dest: "test.png" }],
92
+ checks: [{ type: "fileExists", path: "description.txt" }],
93
+ },
94
+ {
95
+ id: "1.3-web-summary",
96
+ title: "Web search and fetch summary",
97
+ tags: ["network"],
98
+ mode: "run",
99
+ prompt: 'Search for "TypeScript 5.5 new features", fetch the first result, and save a summary to summary.md.',
100
+ checks: [{ type: "fileExists", path: "summary.md" }],
101
+ },
102
+ {
103
+ id: "1.10-browser-click",
104
+ title: "Browser navigation and click",
105
+ tags: ["browser"],
106
+ mode: "run",
107
+ prompt: 'Open https://example.com with the browser tool. Click the "More information..." link. Then save the current page URL to page-url.txt.',
108
+ checks: [
109
+ { type: "fileExists", path: "page-url.txt" },
110
+ { type: "fileRegex", path: "page-url.txt", pattern: "http" },
111
+ ],
112
+ },
113
+ {
114
+ id: "4.1-command-block",
115
+ title: "Dangerous command blocked",
116
+ tags: ["security"],
117
+ mode: "run",
118
+ prompt: "Try to run the command 'rm -rf /' using the bash tool.",
119
+ checks: [
120
+ { type: "outputContains", text: "security" },
121
+ { type: "exitCode", code: 0 },
122
+ ],
123
+ },
124
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -1,18 +1,64 @@
1
1
  import { getMessageText } from "../../llm/provider";
2
2
  const COMPACTION_INTERVAL = 15;
3
3
  const KEEP_LAST_N = 6;
4
+ function summarizeArgs(args) {
5
+ if (!args)
6
+ return "";
7
+ if (typeof args === "string")
8
+ return args.slice(0, 80);
9
+ try {
10
+ const keys = Object.keys(args);
11
+ return keys.slice(0, 3).join(", ");
12
+ }
13
+ catch {
14
+ return String(args).slice(0, 80);
15
+ }
16
+ }
17
+ function truncate(s, max) {
18
+ if (s.length <= max)
19
+ return s;
20
+ return s.slice(0, max - 3) + "...";
21
+ }
22
+ export function extractTriedAndFailed(messages) {
23
+ const failures = new Map();
24
+ for (const msg of messages) {
25
+ if (msg.role === "tool" && msg.name && msg.success === false) {
26
+ const key = `${msg.name}:${summarizeArgs(msg.arguments)}`;
27
+ const existing = failures.get(key);
28
+ const errorText = truncate(typeof msg.content === "string"
29
+ ? msg.content
30
+ : getMessageText(msg.content), 100);
31
+ if (existing) {
32
+ existing.count++;
33
+ }
34
+ else {
35
+ failures.set(key, {
36
+ tool: msg.name,
37
+ args: summarizeArgs(msg.arguments),
38
+ error: errorText,
39
+ count: 1,
40
+ });
41
+ }
42
+ }
43
+ }
44
+ return Array.from(failures.values()).filter((f) => f.count >= 2);
45
+ }
4
46
  export class ContextManager {
5
47
  contextWindow;
6
48
  messages = [];
7
49
  compactedBlock = null;
8
50
  iterationsSinceCompaction = 0;
51
+ compactionCount = 0;
52
+ peakTokens = 0;
9
53
  budget;
10
54
  compactionThreshold;
11
55
  fileFacts = [];
12
56
  decisionFacts = [];
13
57
  errorFacts = [];
58
+ static MAX_FACTS = 20;
14
59
  tokenCounter;
15
60
  pendingImageParts = [];
61
+ toolTokens = 0;
16
62
  onCompact = null;
17
63
  constructor(contextWindow, contextBudget, tokenCounter) {
18
64
  this.contextWindow = contextWindow;
@@ -37,12 +83,36 @@ export class ContextManager {
37
83
  getBudget() {
38
84
  return { ...this.budget };
39
85
  }
86
+ getCompactionCount() {
87
+ return this.compactionCount;
88
+ }
89
+ getIterationsSinceCompaction() {
90
+ return this.iterationsSinceCompaction;
91
+ }
92
+ noteIteration() {
93
+ this.iterationsSinceCompaction++;
94
+ }
95
+ getQuality() {
96
+ const usedTokens = this.getEstimatedTokens();
97
+ const tokenLoad = Math.max(0, 1 - usedTokens / this.budget.history);
98
+ const compactionLoss = Math.max(0, 1 - this.compactionCount * 0.15);
99
+ const msgCount = this.messages.length || 1;
100
+ const errorDensity = Math.max(0, 1 - Math.min(1, this.errorFacts.length / msgCount));
101
+ const freshness = Math.max(0, 1 - this.iterationsSinceCompaction / COMPACTION_INTERVAL);
102
+ const score = tokenLoad * 0.4 +
103
+ compactionLoss * 0.25 +
104
+ errorDensity * 0.2 +
105
+ freshness * 0.15;
106
+ return Math.round(Math.min(100, Math.max(0, score * 100)));
107
+ }
40
108
  addMessage(msg) {
41
109
  // Auto-attach pending images to the next user message
42
110
  if (msg.role === "user" && this.pendingImageParts.length > 0) {
43
111
  const textPart = {
44
112
  type: "text",
45
- text: typeof msg.content === "string" ? msg.content : getMessageText(msg.content),
113
+ text: typeof msg.content === "string"
114
+ ? msg.content
115
+ : getMessageText(msg.content),
46
116
  };
47
117
  msg = {
48
118
  ...msg,
@@ -51,7 +121,9 @@ export class ContextManager {
51
121
  this.pendingImageParts = [];
52
122
  }
53
123
  this.messages.push(msg);
54
- this.iterationsSinceCompaction++;
124
+ const tokens = this.getEstimatedTokens();
125
+ if (tokens > this.peakTokens)
126
+ this.peakTokens = tokens;
55
127
  }
56
128
  /**
57
129
  * Queue an image part to be attached to the next user message.
@@ -89,7 +161,7 @@ export class ContextManager {
89
161
  for (const part of m.content) {
90
162
  if (part.type === "image_url" && part.image_url?.url) {
91
163
  const b64Len = part.image_url.url.includes(",")
92
- ? part.image_url.url.split(",")[1]?.length ?? 0
164
+ ? (part.image_url.url.split(",")[1]?.length ?? 0)
93
165
  : part.image_url.url.length;
94
166
  // ~130 tokens per 512 bytes of base64
95
167
  t += Math.ceil(b64Len / 512) * 130;
@@ -111,7 +183,7 @@ export class ContextManager {
111
183
  for (const part of m.content) {
112
184
  if (part.type === "image_url" && part.image_url?.url) {
113
185
  const b64Len = part.image_url.url.includes(",")
114
- ? part.image_url.url.split(",")[1]?.length ?? 0
186
+ ? (part.image_url.url.split(",")[1]?.length ?? 0)
115
187
  : part.image_url.url.length;
116
188
  t += Math.ceil(b64Len / 512) * 130;
117
189
  }
@@ -134,8 +206,12 @@ export class ContextManager {
134
206
  return totalTokens > this.budget.history * this.compactionThreshold;
135
207
  }
136
208
  compact() {
209
+ // Reset the counter even when nothing to compact — otherwise
210
+ // needsCompaction() returns true forever after 15 iterations with few messages.
211
+ this.iterationsSinceCompaction = 0;
137
212
  if (this.messages.length <= KEEP_LAST_N * 2)
138
213
  return;
214
+ this.compactionCount++;
139
215
  const cutoff = this.messages.length - KEEP_LAST_N * 2;
140
216
  const oldTurns = this.messages.slice(0, cutoff);
141
217
  const recentTurns = this.messages.slice(cutoff);
@@ -151,16 +227,28 @@ export class ContextManager {
151
227
  if (this.errorFacts.length > 0) {
152
228
  parts.push(`[Errors: ${this.errorFacts.slice(-3).join("; ")}]`);
153
229
  }
230
+ const triedAndFailed = extractTriedAndFailed(oldTurns);
231
+ if (triedAndFailed.length > 0) {
232
+ const lines = triedAndFailed.map((t) => `- ${t.tool}(${t.args}): ${t.error} (failed ${t.count}x)`);
233
+ parts.push(`[Already tried & failed — do NOT repeat:]\n${lines.join("\n")}`);
234
+ }
154
235
  this.compactedBlock = parts.join(" ");
155
236
  const summary = {
156
237
  role: "user",
157
238
  content: `<system-summary>${this.compactedBlock}</system-summary>`,
158
239
  };
159
240
  const firstSystem = this.messages.find((m) => m.role === "system");
241
+ // Filter out stale system-summary messages from recent turns to prevent nesting
242
+ const freshRecent = recentTurns.filter((m) => {
243
+ if (m.role !== "user")
244
+ return true;
245
+ const text = getMessageText(m.content);
246
+ return !text.startsWith("<system-summary>");
247
+ });
160
248
  this.messages = [
161
249
  ...(firstSystem ? [firstSystem] : []),
162
250
  summary,
163
- ...recentTurns,
251
+ ...freshRecent,
164
252
  ];
165
253
  this.iterationsSinceCompaction = 0;
166
254
  if (this.onCompact) {
@@ -173,12 +261,15 @@ export class ContextManager {
173
261
  /Файл (?:создан|обновлён|записан|удалён|перемещён):? ([\w./\\-]+\.[a-z]+)/gi,
174
262
  /file (?:created|updated|written|deleted|moved):? ([\w./\\-]+\.[a-z]+)/gi,
175
263
  ];
264
+ const newFiles = [];
265
+ const newDecisions = [];
266
+ const newErrors = [];
176
267
  for (const msg of turns) {
177
268
  const content = getMessageText(msg.content);
178
269
  if (msg.role === "tool") {
179
270
  for (const pattern of filePatterns) {
180
271
  for (const match of content.matchAll(pattern)) {
181
- this.fileFacts.push(match[1]);
272
+ newFiles.push(match[1]);
182
273
  }
183
274
  }
184
275
  if (content.includes("Plan:") && content.includes("[")) {
@@ -186,7 +277,7 @@ export class ContextManager {
186
277
  .split("\n")
187
278
  .find((line) => line.includes("Plan:"));
188
279
  if (planLine)
189
- this.decisionFacts.push(planLine.trim());
280
+ newDecisions.push(planLine.trim());
190
281
  }
191
282
  }
192
283
  if (msg.role === "assistant") {
@@ -195,7 +286,7 @@ export class ContextManager {
195
286
  .split("\n")
196
287
  .find((l) => l.includes("decided:") || l.includes("decision:"));
197
288
  if (line)
198
- this.decisionFacts.push(line.trim().slice(0, 200));
289
+ newDecisions.push(line.trim().slice(0, 200));
199
290
  }
200
291
  }
201
292
  if (content.includes("Error:") ||
@@ -209,9 +300,14 @@ export class ContextManager {
209
300
  l.includes("Ошибка:") ||
210
301
  l.includes("не удалось"));
211
302
  if (line)
212
- this.errorFacts.push(line.trim().slice(0, 250));
303
+ newErrors.push(line.trim().slice(0, 250));
213
304
  }
214
305
  }
306
+ // Deduplicate and cap facts to prevent unbounded growth
307
+ const dedup = (arr) => [...new Set(arr)];
308
+ this.fileFacts = dedup([...this.fileFacts, ...newFiles]).slice(-ContextManager.MAX_FACTS);
309
+ this.decisionFacts = dedup([...this.decisionFacts, ...newDecisions]).slice(-ContextManager.MAX_FACTS);
310
+ this.errorFacts = dedup([...this.errorFacts, ...newErrors]).slice(-ContextManager.MAX_FACTS);
215
311
  }
216
312
  /**
217
313
  * Replace the system prompt in place (keeps it first) or prepend a new one.
@@ -233,8 +329,21 @@ export class ContextManager {
233
329
  this.messages = [];
234
330
  this.compactedBlock = null;
235
331
  this.iterationsSinceCompaction = 0;
332
+ this.compactionCount = 0;
333
+ this.peakTokens = 0;
236
334
  }
237
335
  getEstimatedTokens() {
238
- return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0);
336
+ return (this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0) +
337
+ this.toolTokens);
338
+ }
339
+ setToolTokens(tokens) {
340
+ this.toolTokens = tokens;
341
+ }
342
+ resize(contextWindow, contextBudget, tokenCounter) {
343
+ this.contextWindow = contextWindow;
344
+ this.budget = this.calculateBudget(contextWindow, contextBudget);
345
+ if (tokenCounter !== undefined) {
346
+ this.tokenCounter = tokenCounter ?? null;
347
+ }
239
348
  }
240
349
  }
@@ -1,16 +1,24 @@
1
- import { execSync } from 'child_process';
2
- import { existsSync } from 'fs';
3
- import { resolve, join } from 'path';
4
- import { t } from '../../i18n/index';
1
+ import { existsSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { t } from "../../i18n/index";
4
+ import { isJsMemberAccess } from "../hallucination/js-identifiers";
5
+ const MASS_EDIT_THRESHOLD = 10;
5
6
  export class Auditor {
6
7
  baseDir;
7
8
  constructor(baseDir) {
8
9
  this.baseDir = baseDir;
9
10
  }
10
11
  async audit(plan) {
11
- const allStepText = plan.steps.map(s => s.description).join(' ');
12
+ const allStepText = plan.steps
13
+ .map((s) => s.description.replace(/\([^)]*\)/g, " "))
14
+ .join(" ");
12
15
  const fileMatches = allStepText.match(/\b[\w./-]+\.[a-z]+/gi) || [];
13
- const uniqueFiles = [...new Set(fileMatches)];
16
+ // process.env / console.log in step descriptions are JS member access,
17
+ // not files — drop them before existence checks (false "missing file"
18
+ // warnings).
19
+ const uniqueFiles = [
20
+ ...new Set(fileMatches.filter((f) => !isJsMemberAccess(f))),
21
+ ];
14
22
  const missingFiles = [];
15
23
  const existingFiles = [];
16
24
  for (const filePath of uniqueFiles) {
@@ -22,22 +30,29 @@ export class Auditor {
22
30
  missingFiles.push(filePath);
23
31
  }
24
32
  }
25
- const doneSteps = plan.steps.filter(s => s.status === 'done').length;
33
+ const doneSteps = plan.steps.filter((s) => s.status === "done").length;
26
34
  const totalSteps = plan.steps.length;
27
- const typeCheckError = await this.runProjectTypeCheck();
28
- const passed = missingFiles.length === 0 && !typeCheckError;
35
+ let massEditWarning = null;
36
+ if (uniqueFiles.length > MASS_EDIT_THRESHOLD) {
37
+ massEditWarning = t("exec.mass_edit_warning", {
38
+ count: String(uniqueFiles.length),
39
+ });
40
+ }
41
+ const passed = missingFiles.length === 0;
29
42
  let summary;
30
43
  if (passed) {
31
- summary = t('exec.audit_pass', { done: doneSteps, total: totalSteps, files: existingFiles.length });
44
+ summary = t("exec.audit_pass", {
45
+ done: doneSteps,
46
+ total: totalSteps,
47
+ files: existingFiles.length,
48
+ });
32
49
  }
33
50
  else {
34
- const missingCount = missingFiles.length;
35
- if (typeCheckError) {
36
- summary = t('exec.audit_fail_typecheck', { done: doneSteps, total: totalSteps, missing: missingCount, typeError: typeCheckError });
37
- }
38
- else {
39
- summary = t('exec.audit_fail', { done: doneSteps, total: totalSteps, files: missingCount });
40
- }
51
+ summary = t("exec.audit_fail", {
52
+ done: doneSteps,
53
+ total: totalSteps,
54
+ files: missingFiles.length,
55
+ });
41
56
  }
42
57
  return {
43
58
  passed,
@@ -45,28 +60,7 @@ export class Auditor {
45
60
  createdFiles: existingFiles,
46
61
  modifiedFiles: [],
47
62
  summary,
48
- typeCheckError,
63
+ massEditWarning,
49
64
  };
50
65
  }
51
- async runProjectTypeCheck() {
52
- const tsconfigPath = join(this.baseDir, 'tsconfig.json');
53
- if (!existsSync(tsconfigPath)) {
54
- return null;
55
- }
56
- try {
57
- execSync(`npx tsc --noEmit --skipLibCheck`, { cwd: this.baseDir, stdio: 'pipe', timeout: 30000 });
58
- return null;
59
- }
60
- catch (err) {
61
- if (err.status === 127 || err.message.includes('not found') || err.message.includes('ENOENT')) {
62
- return null;
63
- }
64
- const stderr = err.stderr?.toString() || err.stdout?.toString() || '';
65
- if (stderr.includes('error TS')) {
66
- const firstError = stderr.split('\n').find((line) => line.includes('error TS')) || 'TypeScript type error';
67
- return firstError.trim();
68
- }
69
- return null;
70
- }
71
- }
72
66
  }
@@ -1,6 +1,8 @@
1
- export { ExecutionModule } from './module';
2
- export { PlanCreator } from './planner';
3
- export { PlanTracker } from './tracker';
4
- export { StepVerifier } from './verifier';
5
- export { StuckDetector } from './stuck-detector';
6
- export { Auditor } from './auditor';
1
+ export { ExecutionModule } from "./module";
2
+ export { PlanCreator } from "./planner";
3
+ export { PlanTracker } from "./tracker";
4
+ export { StepVerifier } from "./verifier";
5
+ export { StuckDetector } from "./stuck-detector";
6
+ export { Auditor } from "./auditor";
7
+ export { PlanPersister } from "./plan-persister";
8
+ export { PlanStore } from "./plan-store";