micro-models-agent 0.32.0 → 0.33.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 (2) hide show
  1. package/dist/main.js +907 -147
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2162,7 +2162,7 @@ var init_defaults = __esm(() => {
2162
2162
  init_config();
2163
2163
  DEFAULTS = {
2164
2164
  version: "2.0.0",
2165
- model: "qwen3.5-9b",
2165
+ model: "qwen/qwen3.5-9b",
2166
2166
  provider: {
2167
2167
  type: "openai-compat",
2168
2168
  baseUrl: "http://localhost:1234/v1",
@@ -2177,18 +2177,18 @@ var init_defaults = __esm(() => {
2177
2177
  },
2178
2178
  experts: {
2179
2179
  code: {
2180
- model: "qwen3.5-9b",
2180
+ model: "qwen/qwen3.5-9b",
2181
2181
  tool_tags: ["file", "code", "shell"],
2182
2182
  max_attempts: 3
2183
2183
  },
2184
- research: { model: "qwen3.5-9b", tool_tags: ["research"], max_attempts: 3 },
2184
+ research: { model: "qwen/qwen3.5-9b", tool_tags: ["research"], max_attempts: 3 },
2185
2185
  browser: {
2186
- model: "qwen3.5-9b",
2186
+ model: "qwen/qwen3.5-9b",
2187
2187
  tool_tags: ["browser", "vision"],
2188
2188
  max_attempts: 3
2189
2189
  },
2190
2190
  vision: {
2191
- model: "qwen3.5-9b",
2191
+ model: "qwen/qwen3.5-9b",
2192
2192
  tool_tags: ["browser", "vision", "file"],
2193
2193
  max_attempts: 2
2194
2194
  }
@@ -2458,7 +2458,7 @@ Command: {command}`,
2458
2458
  "plan.step_status": "Step {step}: {status}",
2459
2459
  "plan.no_active": "No active plan",
2460
2460
  "plan.step_not_found": "Step not found",
2461
- "plan.step_already_done": "Step {step} is already marked done. Stop re-marking it either continue with the next step or investigate why progress appears stuck.",
2461
+ "plan.step_already_done": "Step {step} is already done — nothing to do. Plan progress:",
2462
2462
  "plan.order_blocked": 'Cannot mark step {step} done: step {first} ("{desc}") is not finished yet. Complete earlier steps first, or mark step {first} status=skipped if it is not needed.',
2463
2463
  "plan.show_header": "Plan status:",
2464
2464
  "plan.show_empty": "(plan has no steps)",
@@ -3035,7 +3035,7 @@ var init_ru = __esm(() => {
3035
3035
  "plan.step_status": "Шаг {step}: {status}",
3036
3036
  "plan.no_active": "Нет активного плана",
3037
3037
  "plan.step_not_found": "Шаг не найден",
3038
- "plan.step_already_done": "Шаг {step} уже отмечен выполненным. Прекратите повторную отметку переходите к следующему шагу или выясните, почему прогресс заблокирован.",
3038
+ "plan.step_already_done": "Шаг {step} уже выполненничего делать не нужно. Прогресс плана:",
3039
3039
  "plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
3040
3040
  "plan.show_header": "Статус плана:",
3041
3041
  "plan.show_empty": "(в плане нет шагов)",
@@ -10435,6 +10435,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10435
10435
  this.abortController = new AbortController;
10436
10436
  let iteration = 0;
10437
10437
  let lastText = "";
10438
+ let lastModelText = "";
10438
10439
  let lastForcedCompactionIteration = -FORCED_COMPACTION_COOLDOWN;
10439
10440
  let hallucinationRetries = 0;
10440
10441
  let lastToolSignature = "";
@@ -10451,6 +10452,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10451
10452
  let emptyResponseExhausted = false;
10452
10453
  let auditFailed = false;
10453
10454
  let lastAuditSummary = "";
10455
+ let suppressRepetitionRetry = false;
10454
10456
  let repeatedToolCount = 0;
10455
10457
  const MAX_REPEATED_TOOL_CALLS = 2;
10456
10458
  const allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
@@ -10738,9 +10740,12 @@ ${taskReminder}</system-summary>`
10738
10740
  `));
10739
10741
  }
10740
10742
  }
10743
+ suppressRepetitionRetry = false;
10741
10744
  continue;
10742
10745
  }
10743
- hallucinationDetector.getConfidenceCheck().setPreviousResponse(lastText);
10746
+ hallucinationDetector.getConfidenceCheck().setPreviousResponse(lastModelText);
10747
+ if (textContent)
10748
+ lastModelText = textContent;
10744
10749
  const hallucinationResult = await hallucinationDetector.validate(textContent);
10745
10750
  if (hallucinationResult.status === "block") {
10746
10751
  logger.warn(`Response blocked: ${hallucinationResult.reason}`);
@@ -10772,30 +10777,45 @@ ${warnLine}
10772
10777
  lastText = textContent;
10773
10778
  break;
10774
10779
  }
10775
- if (hallucinationRetries >= MAX_HALLUCINATION_RETRIES) {
10776
- logger.warn(`Hallucination retries exhausted (${MAX_HALLUCINATION_RETRIES}), returning error`);
10777
- return {
10778
- success: false,
10779
- text: lastText,
10780
- error: t("error.response_blocked", {
10781
- reason: t("hall.max_retries_exhausted")
10782
- }),
10783
- iterationCount: iteration
10784
- };
10785
- }
10786
- hallucinationRetries++;
10787
- logger.warn(`Hallucination retry (${hallucinationRetries}/${MAX_HALLUCINATION_RETRIES}): ${hallucinationResult.reason}`);
10788
- if (textContent) {
10780
+ if (suppressRepetitionRetry && hallucinationResult.kind === "repetition") {
10781
+ suppressRepetitionRetry = false;
10782
+ logger.warn(`Audit-triggered re-answer repetition — not counted as hallucination retry`);
10783
+ const warnLine = `${t("hall.uncertainty_prefix").trim()} ${hallucinationResult.reason ?? ""}`;
10784
+ if (onMeta) {
10785
+ onMeta(`
10786
+ ${pc2.yellow(warnLine)}
10787
+ `);
10788
+ } else if (onChunk) {
10789
+ onChunk(`
10790
+ ${warnLine}
10791
+ `);
10792
+ }
10793
+ } else {
10794
+ if (hallucinationRetries >= MAX_HALLUCINATION_RETRIES) {
10795
+ logger.warn(`Hallucination retries exhausted (${MAX_HALLUCINATION_RETRIES}), returning error`);
10796
+ return {
10797
+ success: false,
10798
+ text: lastText,
10799
+ error: t("error.response_blocked", {
10800
+ reason: t("hall.max_retries_exhausted")
10801
+ }),
10802
+ iterationCount: iteration
10803
+ };
10804
+ }
10805
+ hallucinationRetries++;
10806
+ logger.warn(`Hallucination retry (${hallucinationRetries}/${MAX_HALLUCINATION_RETRIES}): ${hallucinationResult.reason}`);
10807
+ if (textContent) {
10808
+ contextManager.addMessage({
10809
+ role: "assistant",
10810
+ content: textContent
10811
+ });
10812
+ }
10789
10813
  contextManager.addMessage({
10790
- role: "assistant",
10791
- content: textContent
10814
+ role: "user",
10815
+ content: `<system-summary>[Retry context: ${hallucinationResult.reason}. Original task: "${input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`
10792
10816
  });
10817
+ continue;
10793
10818
  }
10794
- contextManager.addMessage({
10795
- role: "user",
10796
- content: `<system-summary>[Retry context: ${hallucinationResult.reason}. Original task: "${input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`
10797
- });
10798
- continue;
10799
10819
  }
10800
10820
  if (textContent) {
10801
10821
  contextManager.addMessage({ role: "assistant", content: textContent });
@@ -10847,6 +10867,7 @@ ${warnLine}
10847
10867
  auditFailed = true;
10848
10868
  break;
10849
10869
  }
10870
+ suppressRepetitionRetry = true;
10850
10871
  continue;
10851
10872
  }
10852
10873
  }
@@ -11296,13 +11317,18 @@ class ConfidenceCheck {
11296
11317
  }
11297
11318
  validate(response) {
11298
11319
  if (!response || response.length < MIN_CHARS) {
11299
- return { status: "retry", reason: t("hall.short_response") };
11320
+ return {
11321
+ status: "retry",
11322
+ kind: "short",
11323
+ reason: t("hall.short_response")
11324
+ };
11300
11325
  }
11301
11326
  const wordCount = response.split(/\s+/).filter(Boolean).length;
11302
11327
  const hasStructure = /```|^\s*[-*]\s|^\s*\d+\.\s|<[^>]+>/m.test(response);
11303
11328
  if (wordCount < MIN_WORDS && !hasStructure) {
11304
11329
  return {
11305
11330
  status: "warn",
11331
+ kind: "short",
11306
11332
  reason: t("hall.short_response")
11307
11333
  };
11308
11334
  }
@@ -11311,6 +11337,7 @@ class ConfidenceCheck {
11311
11337
  if (overlap > 0.5) {
11312
11338
  return {
11313
11339
  status: "retry",
11340
+ kind: "repetition",
11314
11341
  reason: t("hall.repetitive", { pct: Math.round(overlap * 100) })
11315
11342
  };
11316
11343
  }
@@ -11322,6 +11349,7 @@ class ConfidenceCheck {
11322
11349
  if (diversity < 0.25) {
11323
11350
  return {
11324
11351
  status: "warn",
11352
+ kind: "diversity",
11325
11353
  reason: t("hall.repetitive", {
11326
11354
  pct: Math.round((1 - diversity) * 100)
11327
11355
  })
@@ -11350,7 +11378,25 @@ function isJsMemberAccess(candidate) {
11350
11378
  const m = lower.match(/^([\w-]+)\./);
11351
11379
  return m !== null && JS_GLOBALS.has(m[1]);
11352
11380
  }
11353
- var JS_GLOBALS;
11381
+ function isFilePathLike(s) {
11382
+ const lower = s.toLowerCase();
11383
+ if (TECH_NAMES.has(lower))
11384
+ return false;
11385
+ if (!s.includes("/") && !s.includes("\\") && !/^\w+\.[a-z]{2,4}$/i.test(s))
11386
+ return false;
11387
+ if (isJsMemberAccess(s))
11388
+ return false;
11389
+ const ext = s.split(".").pop()?.toLowerCase() || "";
11390
+ return !NON_FILE_EXTENSIONS.has(ext);
11391
+ }
11392
+ function extractFileLikeTokens(text) {
11393
+ const matches = text.match(FILE_TOKEN_RE) || [];
11394
+ return [...new Set(matches.filter(isFilePathLike))];
11395
+ }
11396
+ function stripUrls(text) {
11397
+ return text.replace(/\bhttps?:\/\/[^\s"'<>]+/gi, " ");
11398
+ }
11399
+ var JS_GLOBALS, NON_FILE_EXTENSIONS, TECH_NAMES, FILE_TOKEN_RE;
11354
11400
  var init_js_identifiers = __esm(() => {
11355
11401
  JS_GLOBALS = new Set([
11356
11402
  "process",
@@ -11408,22 +11454,46 @@ var init_js_identifiers = __esm(() => {
11408
11454
  "deno",
11409
11455
  "node"
11410
11456
  ]);
11457
+ NON_FILE_EXTENSIONS = new Set([
11458
+ "com",
11459
+ "org",
11460
+ "net",
11461
+ "gov",
11462
+ "edu",
11463
+ "io",
11464
+ "dev",
11465
+ "app",
11466
+ "co",
11467
+ "ai",
11468
+ "ru",
11469
+ "de",
11470
+ "fr",
11471
+ "uk",
11472
+ "us",
11473
+ "es",
11474
+ "it",
11475
+ "jp",
11476
+ "cn",
11477
+ "br"
11478
+ ]);
11479
+ TECH_NAMES = new Set([
11480
+ "node.js",
11481
+ "react.js",
11482
+ "vue.js",
11483
+ "next.js",
11484
+ "angular.js",
11485
+ "express.js",
11486
+ "deno.js",
11487
+ "qwik.js",
11488
+ "svelte.js",
11489
+ "jquery.js"
11490
+ ]);
11491
+ FILE_TOKEN_RE = /\b(?:[a-zA-Z]:[\\/])?[\w./\\-]+\.[a-z]{2,6}\b/gi;
11411
11492
  });
11412
11493
 
11413
11494
  // src/modules/hallucination/factual.ts
11414
11495
  import { existsSync as existsSync22, readdirSync as readdirSync5 } from "fs";
11415
11496
  import { resolve as resolve12, isAbsolute as isAbsolute2, join as join13 } from "path";
11416
- function looksLikeFilePath(s) {
11417
- const lower = s.toLowerCase();
11418
- if (TECH_NAMES.has(lower))
11419
- return false;
11420
- if (!s.includes("/") && !s.includes("\\") && !s.match(/^\w+\.[a-z]{2,4}$/i))
11421
- return false;
11422
- if (isJsMemberAccess(s))
11423
- return false;
11424
- const ext = s.split(".").pop()?.toLowerCase() || "";
11425
- return !NON_FILE_EXTENSIONS.has(ext);
11426
- }
11427
11497
 
11428
11498
  class FactualCheck {
11429
11499
  baseDir;
@@ -11522,12 +11592,10 @@ class FactualCheck {
11522
11592
  return count;
11523
11593
  }
11524
11594
  extractFilePaths(text) {
11525
- const pattern = /\b(?:[a-zA-Z]:[\\/])?[\w./\\-]+\.[a-z]{2,6}\b/gi;
11526
- const matches = text.match(pattern) || [];
11527
- return [...new Set(matches)].filter(looksLikeFilePath);
11595
+ return extractFileLikeTokens(stripUrls(text));
11528
11596
  }
11529
11597
  }
11530
- var IGNORED_DIRS, NON_FILE_EXTENSIONS, TECH_NAMES;
11598
+ var IGNORED_DIRS;
11531
11599
  var init_factual = __esm(() => {
11532
11600
  init_i18n();
11533
11601
  init_js_identifiers();
@@ -11540,40 +11608,6 @@ var init_factual = __esm(() => {
11540
11608
  ".mma",
11541
11609
  "_testing"
11542
11610
  ]);
11543
- NON_FILE_EXTENSIONS = new Set([
11544
- "com",
11545
- "org",
11546
- "net",
11547
- "gov",
11548
- "edu",
11549
- "io",
11550
- "dev",
11551
- "app",
11552
- "co",
11553
- "ai",
11554
- "ru",
11555
- "de",
11556
- "fr",
11557
- "uk",
11558
- "us",
11559
- "es",
11560
- "it",
11561
- "jp",
11562
- "cn",
11563
- "br"
11564
- ]);
11565
- TECH_NAMES = new Set([
11566
- "node.js",
11567
- "react.js",
11568
- "vue.js",
11569
- "next.js",
11570
- "angular.js",
11571
- "express.js",
11572
- "deno.js",
11573
- "qwik.js",
11574
- "svelte.js",
11575
- "jquery.js"
11576
- ]);
11577
11611
  });
11578
11612
 
11579
11613
  // src/modules/hallucination/llm-judge.ts
@@ -15480,10 +15514,7 @@ class Auditor {
15480
15514
  }
15481
15515
  async audit(plan) {
15482
15516
  const allStepText = plan.steps.map((s) => s.description.replace(/\([^)]*\)/g, " ")).join(" ");
15483
- const fileMatches = allStepText.match(/\b[\w./-]+\.[a-z]+/gi) || [];
15484
- const uniqueFiles = [
15485
- ...new Set(fileMatches.filter((f) => !isJsMemberAccess(f)))
15486
- ];
15517
+ const uniqueFiles = extractFileLikeTokens(stripUrls(allStepText));
15487
15518
  const missingFiles = [];
15488
15519
  const existingFiles = [];
15489
15520
  for (const filePath of uniqueFiles) {
@@ -16031,11 +16062,15 @@ ${display}`,
16031
16062
  }
16032
16063
  const status = String(args.status || "done");
16033
16064
  if (status === "done" && target.status === "done") {
16065
+ const progress2 = this.tracker.getProgressString();
16066
+ const display2 = this.tracker.toPromptBlock();
16034
16067
  return {
16035
- success: false,
16036
- output: t("plan.step_already_done", {
16068
+ success: true,
16069
+ output: `${t("plan.step_already_done", {
16037
16070
  step: String(stepId)
16038
- })
16071
+ })}
16072
+ ${progress2}`,
16073
+ display: display2
16039
16074
  };
16040
16075
  }
16041
16076
  if (status === "done") {
@@ -19295,7 +19330,7 @@ async function runSetup(externalRl) {
19295
19330
  const idx = Math.max(0, Math.min(models.length - 1, (parseInt(choice) || 1) - 1));
19296
19331
  model = models[idx];
19297
19332
  } else {
19298
- model = await ask(rl, t("setup.model_name"), "qwen3.5-9b");
19333
+ model = await ask(rl, t("setup.model_name"), "qwen/qwen3.5-9b");
19299
19334
  }
19300
19335
  const connected = await withSpinner(t("setup.testing_spinner", { model }), () => testChat(apiBase, apiKey, model));
19301
19336
  if (connected) {
@@ -28583,7 +28618,697 @@ init_bootstrap();
28583
28618
 
28584
28619
  // src/cli/repl.ts
28585
28620
  init_colors();
28621
+ import * as readline3 from "readline";
28622
+
28623
+ // src/ui/line-editor.ts
28624
+ init_string_width();
28586
28625
  import * as readline2 from "readline";
28626
+
28627
+ // src/ui/line-math.ts
28628
+ init_string_width();
28629
+ var ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
28630
+ function stripAnsi2(s) {
28631
+ return s.replace(ANSI_RE, "");
28632
+ }
28633
+ function charLen(s) {
28634
+ return Array.from(s).length;
28635
+ }
28636
+ function wrapLine(line, width) {
28637
+ const w = width > 0 ? width : 80;
28638
+ const chars = Array.from(line);
28639
+ const rows = [];
28640
+ let start = 0;
28641
+ let cells = 0;
28642
+ for (let i = 0;i < chars.length; i++) {
28643
+ const ch = chars[i];
28644
+ if (ch === `
28645
+ `) {
28646
+ rows.push({ text: chars.slice(start, i).join(""), charStart: start });
28647
+ start = i + 1;
28648
+ cells = 0;
28649
+ continue;
28650
+ }
28651
+ const cw = stringWidth(ch);
28652
+ if (cells + cw > w && cells > 0) {
28653
+ rows.push({ text: chars.slice(start, i).join(""), charStart: start });
28654
+ start = i;
28655
+ cells = cw;
28656
+ } else {
28657
+ cells += cw;
28658
+ }
28659
+ }
28660
+ rows.push({ text: chars.slice(start).join(""), charStart: start });
28661
+ return rows;
28662
+ }
28663
+ function buildLayout(lines, width) {
28664
+ const rows = [];
28665
+ for (let b = 0;b < lines.length; b++) {
28666
+ for (const r of wrapLine(lines[b], width)) {
28667
+ rows.push({ bufRow: b, charStart: r.charStart, text: r.text });
28668
+ }
28669
+ }
28670
+ return rows;
28671
+ }
28672
+ function layoutIndexFor(rows, bufRow, col) {
28673
+ let idx = 0;
28674
+ for (let i = 0;i < rows.length; i++) {
28675
+ if (rows[i].bufRow === bufRow && rows[i].charStart <= col)
28676
+ idx = i;
28677
+ }
28678
+ return idx;
28679
+ }
28680
+ function visualColAt(rows, idx, col) {
28681
+ const r = rows[idx];
28682
+ const upTo = col - r.charStart;
28683
+ return stringWidth(Array.from(r.text).slice(0, upTo).join(""));
28684
+ }
28685
+ function charOffsetFor(rows, idx, visualCol) {
28686
+ const r = rows[idx];
28687
+ const chars = Array.from(r.text);
28688
+ let cells = 0;
28689
+ for (let i = 0;i < chars.length; i++) {
28690
+ const cw = stringWidth(chars[i]);
28691
+ if (cells + cw > visualCol)
28692
+ return r.charStart + i;
28693
+ cells += cw;
28694
+ }
28695
+ return r.charStart + chars.length;
28696
+ }
28697
+
28698
+ // src/ui/line-editor.ts
28699
+ class LineEditor {
28700
+ input;
28701
+ output;
28702
+ onKeyInput;
28703
+ promptStr;
28704
+ completer;
28705
+ history;
28706
+ historySize;
28707
+ lines = [""];
28708
+ row = 0;
28709
+ col = 0;
28710
+ historyIndex = -1;
28711
+ stash = null;
28712
+ isDone = false;
28713
+ isPaste = false;
28714
+ lastWasCR = false;
28715
+ questionCb = null;
28716
+ rawMode = false;
28717
+ listeners = {};
28718
+ constructor(opts) {
28719
+ this.input = opts.input;
28720
+ this.output = opts.output;
28721
+ this.promptStr = opts.prompt ?? "";
28722
+ this.completer = opts.completer;
28723
+ this.history = opts.history ?? [];
28724
+ this.historySize = opts.historySize ?? 50;
28725
+ if (this.history.length > this.historySize) {
28726
+ this.history = this.history.slice(-this.historySize);
28727
+ }
28728
+ if (this.input.isTTY) {
28729
+ this.rawMode = typeof this.input.setRawMode === "function";
28730
+ if (this.rawMode)
28731
+ this.input.setRawMode(true);
28732
+ this.enableTerminalProtocols();
28733
+ readline2.emitKeypressEvents(this.input);
28734
+ this.input.on("keypress", (str, key) => this.onKey(str, key));
28735
+ } else {
28736
+ this.input.on("data", (buf) => this.onData(buf));
28737
+ this.input.on("end", () => {
28738
+ const last = this.lines.join(`
28739
+ `);
28740
+ this.lines = [""];
28741
+ this.row = 0;
28742
+ this.col = 0;
28743
+ if (last)
28744
+ this.emitLine(last);
28745
+ this.emitClose();
28746
+ });
28747
+ }
28748
+ }
28749
+ on(event, listener) {
28750
+ if (event === "line") {
28751
+ this.listeners.line = listener;
28752
+ } else {
28753
+ this.listeners.close = listener;
28754
+ }
28755
+ return this;
28756
+ }
28757
+ setPrompt(prompt) {
28758
+ this.promptStr = prompt;
28759
+ if (this.input.isTTY)
28760
+ this.render();
28761
+ }
28762
+ prompt(_preserveCursor) {
28763
+ if (this.input.isTTY)
28764
+ this.render();
28765
+ }
28766
+ write(s) {
28767
+ this.insertText(s);
28768
+ }
28769
+ reset() {
28770
+ this.lines = [""];
28771
+ this.row = 0;
28772
+ this.col = 0;
28773
+ this.historyIndex = -1;
28774
+ this.stash = null;
28775
+ if (this.input.isTTY)
28776
+ this.render();
28777
+ }
28778
+ question(query, cb) {
28779
+ this.questionCb = cb;
28780
+ this.promptStr = query;
28781
+ this.lines = [""];
28782
+ this.row = 0;
28783
+ this.col = 0;
28784
+ if (this.input.isTTY)
28785
+ this.render();
28786
+ }
28787
+ close() {
28788
+ if (this.isDone)
28789
+ return;
28790
+ this.isDone = true;
28791
+ this.disableTerminalProtocols();
28792
+ if (this.rawMode && this.input.setRawMode) {
28793
+ this.input.setRawMode(false);
28794
+ }
28795
+ this.emitClose();
28796
+ }
28797
+ onData(buf) {
28798
+ if (this.isDone)
28799
+ return;
28800
+ let text = buf.toString("utf-8");
28801
+ text = text.replace(/\r\n/g, `
28802
+ `).replace(/\r/g, `
28803
+ `);
28804
+ const parts = text.split(`
28805
+ `);
28806
+ for (let i = 0;i < parts.length; i++) {
28807
+ if (i < parts.length - 1) {
28808
+ this.emitLine(parts[i]);
28809
+ this.lines = [""];
28810
+ this.row = 0;
28811
+ this.col = 0;
28812
+ } else if (parts[i]) {
28813
+ this.emitLine(parts[i]);
28814
+ this.lines = [""];
28815
+ this.row = 0;
28816
+ this.col = 0;
28817
+ }
28818
+ }
28819
+ }
28820
+ onKey(str, key) {
28821
+ if (this.isDone)
28822
+ return;
28823
+ if (this.onKeyInput && this.onKeyInput(str, key))
28824
+ return;
28825
+ const k = key;
28826
+ const name = k?.name ?? "undefined";
28827
+ const seq2 = k?.sequence ?? str ?? "";
28828
+ if (name === "undefined" && /^\x1b\[\d+(?:;\d+)?u$/.test(seq2)) {
28829
+ const m = seq2.match(/^\x1b\[(\d+)(?:;(\d+))?u$/);
28830
+ if (m && Number(m[1]) === 13 && Number(m[2] ?? 0) !== 0) {
28831
+ this.insertNewline();
28832
+ }
28833
+ return;
28834
+ }
28835
+ if (name === "paste-start" || seq2 === "\x1B[200~") {
28836
+ this.isPaste = true;
28837
+ return;
28838
+ }
28839
+ if (name === "paste-end" || seq2 === "\x1B[201~") {
28840
+ this.isPaste = false;
28841
+ this.render();
28842
+ return;
28843
+ }
28844
+ if (this.isPaste) {
28845
+ if (name === "return" || seq2 === "\r" || seq2 === `
28846
+ `) {
28847
+ this.insertText(`
28848
+ `);
28849
+ } else if (str) {
28850
+ this.insertText(str);
28851
+ }
28852
+ this.render();
28853
+ return;
28854
+ }
28855
+ if (name === "return" && (seq2 === "\x1B\r" || k.meta)) {
28856
+ this.insertNewline();
28857
+ return;
28858
+ }
28859
+ if (name === "undefined" && seq2 === "\x1B\r") {
28860
+ this.insertNewline();
28861
+ return;
28862
+ }
28863
+ if (k?.ctrl && name === "j") {
28864
+ this.insertNewline();
28865
+ return;
28866
+ }
28867
+ if (name === "escape")
28868
+ return;
28869
+ switch (name) {
28870
+ case "return":
28871
+ this.lastWasCR = true;
28872
+ this.submit();
28873
+ return;
28874
+ case "enter":
28875
+ if (this.lastWasCR) {
28876
+ this.lastWasCR = false;
28877
+ return;
28878
+ }
28879
+ this.insertNewline();
28880
+ return;
28881
+ case "backspace":
28882
+ this.lastWasCR = false;
28883
+ this.backspace();
28884
+ return;
28885
+ case "delete":
28886
+ this.lastWasCR = false;
28887
+ this.deleteForward();
28888
+ return;
28889
+ case "left":
28890
+ this.lastWasCR = false;
28891
+ this.moveLeft();
28892
+ return;
28893
+ case "right":
28894
+ this.lastWasCR = false;
28895
+ this.moveRight();
28896
+ return;
28897
+ case "up":
28898
+ this.lastWasCR = false;
28899
+ this.moveUp();
28900
+ return;
28901
+ case "down":
28902
+ this.lastWasCR = false;
28903
+ this.moveDown();
28904
+ return;
28905
+ case "home":
28906
+ this.lastWasCR = false;
28907
+ this.moveHome();
28908
+ return;
28909
+ case "end":
28910
+ this.lastWasCR = false;
28911
+ this.moveEnd();
28912
+ return;
28913
+ case "pageup":
28914
+ this.lastWasCR = false;
28915
+ this.moveToStart();
28916
+ return;
28917
+ case "pagedown":
28918
+ this.lastWasCR = false;
28919
+ this.moveToEnd();
28920
+ return;
28921
+ case "tab":
28922
+ this.lastWasCR = false;
28923
+ this.tabComplete();
28924
+ return;
28925
+ }
28926
+ if (k?.ctrl) {
28927
+ this.lastWasCR = false;
28928
+ switch (name) {
28929
+ case "c":
28930
+ this.ctrlC();
28931
+ return;
28932
+ case "d":
28933
+ this.ctrlD();
28934
+ return;
28935
+ case "a":
28936
+ this.moveHome();
28937
+ return;
28938
+ case "e":
28939
+ this.moveEnd();
28940
+ return;
28941
+ case "u":
28942
+ this.killToStart();
28943
+ return;
28944
+ case "k":
28945
+ this.killToEnd();
28946
+ return;
28947
+ case "w":
28948
+ this.killWordBefore();
28949
+ return;
28950
+ case "l":
28951
+ this.clearScreen();
28952
+ return;
28953
+ default:
28954
+ return;
28955
+ }
28956
+ }
28957
+ if (k?.meta) {
28958
+ this.lastWasCR = false;
28959
+ switch (name) {
28960
+ case "b":
28961
+ this.moveWordLeft();
28962
+ return;
28963
+ case "f":
28964
+ this.moveWordRight();
28965
+ return;
28966
+ case "d":
28967
+ this.killWordAfter();
28968
+ return;
28969
+ default:
28970
+ return;
28971
+ }
28972
+ }
28973
+ if (str && !/^[\u0000-\u001f\u007f]/.test(str)) {
28974
+ this.lastWasCR = false;
28975
+ this.insertText(str);
28976
+ }
28977
+ }
28978
+ submit() {
28979
+ if (this.questionCb) {
28980
+ const cb = this.questionCb;
28981
+ this.questionCb = null;
28982
+ const answer = this.lines.join(`
28983
+ `).trim();
28984
+ this.lines = [""];
28985
+ this.row = 0;
28986
+ this.col = 0;
28987
+ this.render();
28988
+ cb(answer);
28989
+ return;
28990
+ }
28991
+ const text = this.lines.join(`
28992
+ `);
28993
+ if (text.trim()) {
28994
+ this.history.push(text);
28995
+ if (this.history.length > this.historySize) {
28996
+ this.history = this.history.slice(-this.historySize);
28997
+ }
28998
+ }
28999
+ this.historyIndex = -1;
29000
+ this.stash = null;
29001
+ this.lines = [""];
29002
+ this.row = 0;
29003
+ this.col = 0;
29004
+ this.render();
29005
+ this.emitLine(text);
29006
+ }
29007
+ ctrlC() {
29008
+ this.lines = [""];
29009
+ this.row = 0;
29010
+ this.col = 0;
29011
+ this.render();
29012
+ process.emit("SIGINT");
29013
+ }
29014
+ ctrlD() {
29015
+ if (this.lines.length === 1 && this.lines[0] === "") {
29016
+ this.emitClose();
29017
+ } else {
29018
+ this.deleteForward();
29019
+ }
29020
+ }
29021
+ currentChars() {
29022
+ return Array.from(this.lines[this.row]);
29023
+ }
29024
+ setCurrentChars(chars) {
29025
+ this.lines[this.row] = chars.join("");
29026
+ }
29027
+ insertText(text) {
29028
+ const sanitized = text.replace(/\r\n/g, `
29029
+ `).replace(/\r/g, "");
29030
+ const chars = this.currentChars();
29031
+ const t2 = Array.from(sanitized);
29032
+ chars.splice(this.col, 0, ...t2);
29033
+ this.setCurrentChars(chars);
29034
+ this.col += t2.length;
29035
+ this.render();
29036
+ }
29037
+ insertNewline() {
29038
+ const chars = this.currentChars();
29039
+ const rest = chars.slice(this.col).join("");
29040
+ this.setCurrentChars(chars.slice(0, this.col));
29041
+ this.lines.splice(this.row + 1, 0, rest);
29042
+ this.row++;
29043
+ this.col = 0;
29044
+ this.render();
29045
+ }
29046
+ backspace() {
29047
+ const chars = this.currentChars();
29048
+ if (this.col > 0) {
29049
+ chars.splice(this.col - 1, 1);
29050
+ this.setCurrentChars(chars);
29051
+ this.col--;
29052
+ } else if (this.row > 0) {
29053
+ const prevLen = charLen(this.lines[this.row - 1]);
29054
+ this.lines[this.row - 1] = this.lines[this.row - 1] + this.lines[this.row];
29055
+ this.lines.splice(this.row, 1);
29056
+ this.row--;
29057
+ this.col = prevLen;
29058
+ }
29059
+ this.render();
29060
+ }
29061
+ deleteForward() {
29062
+ const chars = this.currentChars();
29063
+ if (this.col < chars.length) {
29064
+ chars.splice(this.col, 1);
29065
+ this.setCurrentChars(chars);
29066
+ } else if (this.row < this.lines.length - 1) {
29067
+ this.lines[this.row] = this.lines[this.row] + this.lines[this.row + 1];
29068
+ this.lines.splice(this.row + 1, 1);
29069
+ }
29070
+ this.render();
29071
+ }
29072
+ killToStart() {
29073
+ const chars = this.currentChars();
29074
+ this.setCurrentChars(chars.slice(this.col));
29075
+ this.col = 0;
29076
+ this.render();
29077
+ }
29078
+ killToEnd() {
29079
+ const chars = this.currentChars();
29080
+ this.setCurrentChars(chars.slice(0, this.col));
29081
+ this.render();
29082
+ }
29083
+ killWordBefore() {
29084
+ const chars = this.currentChars();
29085
+ let i = this.col;
29086
+ while (i > 0 && /\s/.test(chars[i - 1]))
29087
+ i--;
29088
+ while (i > 0 && !/\s/.test(chars[i - 1]))
29089
+ i--;
29090
+ chars.splice(i, this.col - i);
29091
+ this.setCurrentChars(chars);
29092
+ this.col = i;
29093
+ this.render();
29094
+ }
29095
+ killWordAfter() {
29096
+ const chars = this.currentChars();
29097
+ const n = chars.length;
29098
+ let i = this.col;
29099
+ while (i < n && /\s/.test(chars[i]))
29100
+ i++;
29101
+ while (i < n && !/\s/.test(chars[i]))
29102
+ i++;
29103
+ chars.splice(this.col, i - this.col);
29104
+ this.setCurrentChars(chars);
29105
+ this.render();
29106
+ }
29107
+ moveLeft() {
29108
+ if (this.col > 0) {
29109
+ this.col--;
29110
+ } else if (this.row > 0) {
29111
+ this.row--;
29112
+ this.col = charLen(this.lines[this.row]);
29113
+ }
29114
+ this.render();
29115
+ }
29116
+ moveRight() {
29117
+ if (this.col < charLen(this.lines[this.row])) {
29118
+ this.col++;
29119
+ } else if (this.row < this.lines.length - 1) {
29120
+ this.row++;
29121
+ this.col = 0;
29122
+ }
29123
+ this.render();
29124
+ }
29125
+ moveUp() {
29126
+ const layout = this.layout();
29127
+ const idx = layoutIndexFor(layout, this.row, this.col);
29128
+ const vcol = visualColAt(layout, idx, this.col);
29129
+ if (idx > 0) {
29130
+ const target = layout[idx - 1];
29131
+ this.row = target.bufRow;
29132
+ this.col = charOffsetFor(layout, idx - 1, vcol);
29133
+ this.render();
29134
+ } else {
29135
+ this.historyPrev();
29136
+ }
29137
+ }
29138
+ moveDown() {
29139
+ const layout = this.layout();
29140
+ const idx = layoutIndexFor(layout, this.row, this.col);
29141
+ const vcol = visualColAt(layout, idx, this.col);
29142
+ if (idx < layout.length - 1) {
29143
+ const target = layout[idx + 1];
29144
+ this.row = target.bufRow;
29145
+ this.col = charOffsetFor(layout, idx + 1, vcol);
29146
+ this.render();
29147
+ } else {
29148
+ this.historyNext();
29149
+ }
29150
+ }
29151
+ moveHome() {
29152
+ this.col = 0;
29153
+ this.render();
29154
+ }
29155
+ moveEnd() {
29156
+ this.col = charLen(this.lines[this.row]);
29157
+ this.render();
29158
+ }
29159
+ moveToStart() {
29160
+ this.row = 0;
29161
+ this.col = 0;
29162
+ this.render();
29163
+ }
29164
+ moveToEnd() {
29165
+ this.row = this.lines.length - 1;
29166
+ this.col = charLen(this.lines[this.row]);
29167
+ this.render();
29168
+ }
29169
+ moveWordLeft() {
29170
+ const chars = this.currentChars();
29171
+ let i = this.col;
29172
+ while (i > 0 && /\s/.test(chars[i - 1]))
29173
+ i--;
29174
+ while (i > 0 && !/\s/.test(chars[i - 1]))
29175
+ i--;
29176
+ this.col = i;
29177
+ this.render();
29178
+ }
29179
+ moveWordRight() {
29180
+ const chars = this.currentChars();
29181
+ const n = chars.length;
29182
+ let i = this.col;
29183
+ while (i < n && !/\s/.test(chars[i]))
29184
+ i++;
29185
+ while (i < n && /\s/.test(chars[i]))
29186
+ i++;
29187
+ this.col = i;
29188
+ this.render();
29189
+ }
29190
+ historyPrev() {
29191
+ if (this.history.length === 0)
29192
+ return;
29193
+ if (this.historyIndex === -1) {
29194
+ this.stash = {
29195
+ lines: this.lines.slice(),
29196
+ row: this.row,
29197
+ col: this.col
29198
+ };
29199
+ this.historyIndex = 0;
29200
+ } else if (this.historyIndex < this.history.length - 1) {
29201
+ this.historyIndex++;
29202
+ } else {
29203
+ return;
29204
+ }
29205
+ this.applyHistoryEntry();
29206
+ }
29207
+ historyNext() {
29208
+ if (this.historyIndex === -1)
29209
+ return;
29210
+ if (this.historyIndex > 0) {
29211
+ this.historyIndex--;
29212
+ this.applyHistoryEntry();
29213
+ } else if (this.stash) {
29214
+ this.lines = this.stash.lines.slice();
29215
+ this.row = this.stash.row;
29216
+ this.col = this.stash.col;
29217
+ this.historyIndex = -1;
29218
+ this.stash = null;
29219
+ this.render();
29220
+ }
29221
+ }
29222
+ applyHistoryEntry() {
29223
+ const entry = this.history[this.history.length - 1 - this.historyIndex];
29224
+ this.lines = entry.split(`
29225
+ `);
29226
+ if (this.lines.length === 0)
29227
+ this.lines = [""];
29228
+ this.row = this.lines.length - 1;
29229
+ this.col = charLen(this.lines[this.row]);
29230
+ this.render();
29231
+ }
29232
+ tabComplete() {
29233
+ if (!this.completer)
29234
+ return;
29235
+ const line = this.lines[this.row];
29236
+ const [matches, partial] = this.completer(line);
29237
+ if (matches.length === 0) {
29238
+ this.output.write("\x07");
29239
+ return;
29240
+ }
29241
+ if (matches.length === 1) {
29242
+ const from = line.lastIndexOf(partial);
29243
+ const head = line.slice(0, from);
29244
+ const tail = line.slice(from + partial.length);
29245
+ this.lines[this.row] = head + matches[0] + tail;
29246
+ this.col = charLen(head) + charLen(matches[0]);
29247
+ this.render();
29248
+ return;
29249
+ }
29250
+ const lines = matches.map((m) => " " + m);
29251
+ this.output.write(`\r
29252
+ ` + lines.join(`\r
29253
+ `) + `\r
29254
+ `);
29255
+ this.output.write(`\x1B[${lines.length + 1}A`);
29256
+ this.render();
29257
+ }
29258
+ clearScreen() {
29259
+ this.output.write("\x1B[2J\x1B[H");
29260
+ this.render();
29261
+ }
29262
+ columns() {
29263
+ return this.output.columns || 80;
29264
+ }
29265
+ layout() {
29266
+ return buildLayout(this.lines, this.columns());
29267
+ }
29268
+ render() {
29269
+ if (!this.input.isTTY || this.isDone)
29270
+ return;
29271
+ const layout = this.layout();
29272
+ const promptWidth = stringWidth(stripAnsi2(this.promptStr));
29273
+ const idx = layoutIndexFor(layout, this.row, this.col);
29274
+ const vcol = visualColAt(layout, idx, this.col);
29275
+ const rowsAfter = layout.length - idx - 1;
29276
+ const ccol = (idx === 0 ? promptWidth : 0) + vcol;
29277
+ const out = ["\r"];
29278
+ for (let i = 0;i < layout.length; i++) {
29279
+ out.push("\x1B[2K");
29280
+ if (i === 0)
29281
+ out.push(this.promptStr);
29282
+ out.push(layout[i].text);
29283
+ if (i < layout.length - 1)
29284
+ out.push(`\r
29285
+ `);
29286
+ }
29287
+ out.push("\x1B[J");
29288
+ if (rowsAfter > 0)
29289
+ out.push(`\x1B[${rowsAfter}A`);
29290
+ out.push("\r");
29291
+ if (ccol > 0)
29292
+ out.push(`\x1B[${ccol}C`);
29293
+ this.output.write(out.join(""));
29294
+ }
29295
+ enableTerminalProtocols() {
29296
+ this.output.write("\x1B[?2004h");
29297
+ this.output.write("\x1B[>1u");
29298
+ }
29299
+ disableTerminalProtocols() {
29300
+ this.output.write("\x1B[?2004l");
29301
+ this.output.write("\x1B[<u");
29302
+ }
29303
+ emitLine(line) {
29304
+ this.listeners.line?.(line);
29305
+ }
29306
+ emitClose() {
29307
+ this.listeners.close?.();
29308
+ }
29309
+ }
29310
+
29311
+ // src/cli/repl.ts
28587
29312
  import { existsSync as existsSync45, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
28588
29313
  import { join as join40, dirname as dirname13 } from "path";
28589
29314
  import { homedir as homedir17 } from "os";
@@ -28885,14 +29610,6 @@ class FormattingStream {
28885
29610
  return result;
28886
29611
  }
28887
29612
  }
28888
- function formatMarkdown(text) {
28889
- const lines = [];
28890
- const stream = new FormattingStream((l) => lines.push(l));
28891
- stream.write(text);
28892
- stream.flush();
28893
- return lines.join(`
28894
- `);
28895
- }
28896
29613
 
28897
29614
  // src/ui/renderer.ts
28898
29615
  init_spinner();
@@ -29145,6 +29862,7 @@ class Repl {
29145
29862
  baseDir;
29146
29863
  noAgentsMd;
29147
29864
  pendingClipboardImage = null;
29865
+ exitOnClose = false;
29148
29866
  rl;
29149
29867
  agent;
29150
29868
  config;
@@ -29152,9 +29870,10 @@ class Repl {
29152
29870
  skillsModule;
29153
29871
  pluginManager;
29154
29872
  logger;
29155
- constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger) {
29873
+ constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, exitOnClose) {
29156
29874
  this.agent = agent;
29157
29875
  this.config = config;
29876
+ this.exitOnClose = exitOnClose === true;
29158
29877
  this.sessionManager = sessionManager;
29159
29878
  this.skillsModule = skillsModule;
29160
29879
  this.pluginManager = pluginManager;
@@ -29164,7 +29883,19 @@ class Repl {
29164
29883
  this.noAgentsMd = noAgentsMd === true;
29165
29884
  this.historyPath = join40(homedir17(), ".mma", "repl-history");
29166
29885
  this.loadHistory();
29167
- this.rl = readline2.createInterface({
29886
+ this.rl = process.stdin.isTTY ? new LineEditor({
29887
+ input: process.stdin,
29888
+ output: process.stdout,
29889
+ prompt: pc2.cyan("> "),
29890
+ history: this.history,
29891
+ historySize: this.maxHistory,
29892
+ completer: (line) => {
29893
+ const [matches, partial] = this.completer.complete(line);
29894
+ if (matches.length > 0)
29895
+ return [matches, partial];
29896
+ return [[], line];
29897
+ }
29898
+ }) : readline3.createInterface({
29168
29899
  input: process.stdin,
29169
29900
  output: process.stdout,
29170
29901
  prompt: pc2.cyan("> "),
@@ -29281,46 +30012,22 @@ class Repl {
29281
30012
  });
29282
30013
  this.rl.on("close", () => {
29283
30014
  this.running = false;
30015
+ this.saveHistory();
30016
+ this.agent.shutdown();
30017
+ if (this.exitOnClose)
30018
+ process.exit(0);
29284
30019
  });
29285
- if (process.stdin.isTTY) {
29286
- readline2.emitKeypressEvents(process.stdin);
29287
- process.stdin.on("keypress", async (str, key) => {
29288
- if (key.name === "escape") {
29289
- const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
29290
- const now = Date.now();
29291
- const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
29292
- this.lastEscTime = now;
29293
- if (escBytes >= 2 || withinWindow) {
29294
- this.lastEscTime = 0;
29295
- if (this.agentRunning) {
29296
- process.stdout.write(pc2.yellow(`
29297
- ${t("repl.interrupt")}
29298
- `));
29299
- this.agent.shutdown();
29300
- }
29301
- }
29302
- return;
29303
- }
29304
- if (key.ctrl && key.name === "v" && !this.agentRunning) {
29305
- try {
29306
- const { readClipboardImage: readClipboardImage2, bufferToDataUrl: bufferToDataUrl2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
29307
- const clipBuf = await readClipboardImage2();
29308
- if (clipBuf) {
29309
- const { dataUrl } = await bufferToDataUrl2(clipBuf);
29310
- this.pendingClipboardImage = dataUrl;
29311
- const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
29312
- console.log(pc2.green(`
29313
- ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
29314
- this.rl.prompt();
29315
- } else {
29316
- console.log(pc2.yellow(`
29317
- ${t("image.clipboard_empty")}`));
29318
- this.rl.prompt();
29319
- }
29320
- } catch {}
29321
- }
30020
+ if (this.exitOnClose && !process.stdin.isTTY) {
30021
+ process.stdin.on("end", () => {
30022
+ this.running = false;
30023
+ this.saveHistory();
30024
+ this.agent.shutdown();
30025
+ process.exit(0);
29322
30026
  });
29323
30027
  }
30028
+ if (this.rl instanceof LineEditor) {
30029
+ this.rl.onKeyInput = (str, key) => this.handleSpecialKey(str, key);
30030
+ }
29324
30031
  let forceExitTimer = null;
29325
30032
  process.on("SIGINT", () => {
29326
30033
  if (this.agentRunning) {
@@ -29336,6 +30043,51 @@ ${t("image.clipboard_empty")}`));
29336
30043
  }
29337
30044
  });
29338
30045
  }
30046
+ handleSpecialKey(str, key) {
30047
+ if (key.name === "escape") {
30048
+ const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
30049
+ const now = Date.now();
30050
+ const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
30051
+ this.lastEscTime = now;
30052
+ if (escBytes >= 2 || withinWindow) {
30053
+ this.lastEscTime = 0;
30054
+ if (this.agentRunning) {
30055
+ process.stdout.write(pc2.yellow(`
30056
+ ${t("repl.interrupt")}
30057
+ `));
30058
+ this.agent.shutdown();
30059
+ }
30060
+ }
30061
+ return true;
30062
+ }
30063
+ if (key.ctrl && key.name === "v" && !this.agentRunning) {
30064
+ this.pasteClipboardImage();
30065
+ return true;
30066
+ }
30067
+ return false;
30068
+ }
30069
+ async pasteClipboardImage() {
30070
+ try {
30071
+ const { readClipboardImage: readClipboardImage2, bufferToDataUrl: bufferToDataUrl2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
30072
+ const clipBuf = await readClipboardImage2();
30073
+ if (clipBuf) {
30074
+ const { dataUrl } = await bufferToDataUrl2(clipBuf);
30075
+ this.pendingClipboardImage = dataUrl;
30076
+ const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
30077
+ console.log(pc2.green(`
30078
+ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
30079
+ if (this.rl instanceof LineEditor)
30080
+ this.rl.reset();
30081
+ this.rl.prompt();
30082
+ } else {
30083
+ console.log(pc2.yellow(`
30084
+ ${t("image.clipboard_empty")}`));
30085
+ if (this.rl instanceof LineEditor)
30086
+ this.rl.reset();
30087
+ this.rl.prompt();
30088
+ }
30089
+ } catch {}
30090
+ }
29339
30091
  isMultiLineInput(line) {
29340
30092
  if (line.endsWith("\\"))
29341
30093
  return true;
@@ -29361,6 +30113,8 @@ ${t("image.clipboard_empty")}`));
29361
30113
  this.pendingClipboardImage = null;
29362
30114
  }
29363
30115
  this.logger?.logREPL("user", input);
30116
+ if (this.rl instanceof LineEditor)
30117
+ this.rl.reset();
29364
30118
  process.stdout.write(`
29365
30119
  ` + pc2.green(t("repl.agent")));
29366
30120
  const renderer = new Renderer({
@@ -29552,6 +30306,21 @@ ${t("image.clipboard_empty")}`));
29552
30306
  }
29553
30307
  }
29554
30308
 
30309
+ // src/cli/run-result.ts
30310
+ init_i18n();
30311
+ init_colors();
30312
+ function printRunResult(result, flush) {
30313
+ flush();
30314
+ if (result.success) {
30315
+ if (!result.text) {
30316
+ console.log(pc2.yellow(t("cli.no_output")));
30317
+ }
30318
+ return 0;
30319
+ }
30320
+ console.error(`${t("error.prefix")}${result.error}`);
30321
+ return 1;
30322
+ }
30323
+
29555
30324
  // src/cli/main.ts
29556
30325
  init_setup();
29557
30326
  init_config2();
@@ -29784,18 +30553,9 @@ async function main() {
29784
30553
  }
29785
30554
  });
29786
30555
  renderer.flush();
29787
- if (result.success) {
29788
- if (!result.text) {
29789
- console.log(pc2.yellow(t("cli.no_output")));
29790
- }
29791
- } else {
29792
- console.error(`${t("error.prefix")}${result.error}`);
29793
- if (result.text) {
29794
- console.log(formatMarkdown(result.text));
29795
- }
29796
- process.exit(1);
29797
- }
30556
+ const exitCode = printRunResult(result, () => renderer.flush());
29798
30557
  agent.shutdown();
30558
+ process.exit(exitCode);
29799
30559
  } else {
29800
30560
  const configPath = join41(homedir18(), ".mma", "config.json");
29801
30561
  if (!existsSync46(configPath)) {
@@ -29858,7 +30618,7 @@ async function main() {
29858
30618
  logger
29859
30619
  } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
29860
30620
  startAutoUpdate(config);
29861
- const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger);
30621
+ const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger, true);
29862
30622
  repl.start();
29863
30623
  }
29864
30624
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {