micro-models-agent 0.40.1 → 0.41.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 +180 -34
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2470,6 +2470,8 @@ Summary:
2470
2470
  Command: {command}`,
2471
2471
  "proc.promoted_hint": "Command still running after {ms} ms — moved to the background",
2472
2472
  "proc.manage_hint": "Check output: process_log id={id}. Stop it: process_kill id={id}. List all: process_list.",
2473
+ "proc.output_preview": `First output:
2474
+ {lines}`,
2473
2475
  "proc.none": "No background processes running.",
2474
2476
  "proc.not_found": "Process not found: {id}",
2475
2477
  "proc.killed": "Process {id} (PID {pid}) killed.",
@@ -2885,6 +2887,7 @@ Use this knowledge to answer the user's question.`,
2885
2887
  "ui.success_prefix": "✓ ",
2886
2888
  "ui.warning_prefix": "⚠ ",
2887
2889
  "ui.thinking": "Thinking…",
2890
+ "ui.step_context": "step {id}: {desc}",
2888
2891
  "indexer.map_header": "Project map",
2889
2892
  "indexer.top_directories": "Top directories",
2890
2893
  "indexer.files": "Files",
@@ -3100,6 +3103,8 @@ var init_ru = __esm(() => {
3100
3103
  Команда: {command}`,
3101
3104
  "proc.promoted_hint": "Команда всё ещё выполняется через {ms} мс — переведена в фоновый режим",
3102
3105
  "proc.manage_hint": "Проверить вывод: process_log id={id}. Остановить: process_kill id={id}. Список всех: process_list.",
3106
+ "proc.output_preview": `Первые строки вывода:
3107
+ {lines}`,
3103
3108
  "proc.none": "Фоновых процессов нет.",
3104
3109
  "proc.not_found": "Процесс не найден: {id}",
3105
3110
  "proc.killed": "Процесс {id} (PID {pid}) остановлен.",
@@ -3515,6 +3520,7 @@ var init_ru = __esm(() => {
3515
3520
  "ui.success_prefix": "✓ ",
3516
3521
  "ui.warning_prefix": "⚠ ",
3517
3522
  "ui.thinking": "Думаю…",
3523
+ "ui.step_context": "шаг {id}: {desc}",
3518
3524
  "indexer.map_header": "Карта проекта",
3519
3525
  "indexer.top_directories": "Основные директории",
3520
3526
  "indexer.files": "Файлы",
@@ -7657,7 +7663,7 @@ Hint: ${t("exec.npm_exec_hint")}`;
7657
7663
  }
7658
7664
  return output;
7659
7665
  }
7660
- var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, NPM_EXEC_RE, bashTool;
7666
+ var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, BG_OUTPUT_PREVIEW_LINES = 15, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, NPM_EXEC_RE, bashTool;
7661
7667
  var init_bash = __esm(() => {
7662
7668
  init_command_validator();
7663
7669
  init_audit_log();
@@ -7858,15 +7864,21 @@ Hint: "${originalFirstWord}" may not work on Windows. ${UNIX_TO_WIN_HINTS[origin
7858
7864
  return { success: code === 0, output: output2 };
7859
7865
  }
7860
7866
  const explicit = args.background === true;
7861
- const output = `${t("proc.started", {
7867
+ const preview = entry.log.filter((l) => l.trim() !== "").slice(0, BG_OUTPUT_PREVIEW_LINES).join(`
7868
+ `);
7869
+ let output = `${t("proc.started", {
7862
7870
  id: entry.id,
7863
7871
  pid: entry.pid,
7864
7872
  command
7865
7873
  })}${explicit ? "" : `
7866
- ${t("proc.promoted_hint", { ms: settleMs })}`}
7867
- ${t("proc.manage_hint", {
7868
- id: entry.id
7869
- })}`;
7874
+ ${t("proc.promoted_hint", { ms: settleMs })}`}`;
7875
+ if (preview) {
7876
+ output += `
7877
+
7878
+ ${t("proc.output_preview", { lines: preview })}`;
7879
+ }
7880
+ output += `
7881
+ ${t("proc.manage_hint", { id: entry.id })}`;
7870
7882
  if (securityConfig?.logCommands) {
7871
7883
  logBashCommand(ctx.sessionId, sanitizeCommandForLog(command), true, `Started in background: ${entry.id} (PID ${entry.pid})`);
7872
7884
  }
@@ -31555,8 +31567,8 @@ class LineEditor {
31555
31567
  }
31556
31568
 
31557
31569
  // src/cli/repl.ts
31558
- import { existsSync as existsSync52, readFileSync as readFileSync33, writeFileSync as writeFileSync17 } from "fs";
31559
- import { join as join46, dirname as dirname18 } from "path";
31570
+ import { existsSync as existsSync53, readFileSync as readFileSync34, writeFileSync as writeFileSync17 } from "fs";
31571
+ import { join as join47, dirname as dirname18 } from "path";
31560
31572
  import { homedir as homedir17 } from "os";
31561
31573
  import { fileURLToPath as fileURLToPath6 } from "url";
31562
31574
 
@@ -31965,13 +31977,14 @@ class Renderer {
31965
31977
  thinkingEnd() {
31966
31978
  this.spinner.stop();
31967
31979
  }
31968
- toolStart(tool, args) {
31980
+ toolStart(tool, args, stepContext) {
31969
31981
  this.endCard();
31970
31982
  this.spinner.stop();
31971
31983
  const summary = summarizeArgs2(args);
31984
+ const step = stepContext ? ` ${pc2.cyan(`← ${stepContext}`)}` : "";
31972
31985
  if (!this.rich) {
31973
31986
  this.out.write(`
31974
- ${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
31987
+ ${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
31975
31988
  `);
31976
31989
  return;
31977
31990
  }
@@ -31979,11 +31992,19 @@ ${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
31979
31992
  if (this.toolStyle === "inline") {
31980
31993
  const marker = toolMarker(tool);
31981
31994
  this.out.write(`
31982
- ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
31995
+ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
31983
31996
  `);
31984
31997
  return;
31985
31998
  }
31986
- this.spinner.start(`${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}`);
31999
+ this.spinner.start(`${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}`);
32000
+ }
32001
+ planBlock(lines) {
32002
+ this.endCard();
32003
+ this.spinner.stop();
32004
+ for (const line of lines) {
32005
+ this.out.write(`${line}
32006
+ `);
32007
+ }
31987
32008
  }
31988
32009
  toolEnd(_tool, duration, error, ctxDelta) {
31989
32010
  this.spinner.stop();
@@ -32111,13 +32132,118 @@ async function probeLspServers(config, baseDir, deps = {}) {
32111
32132
 
32112
32133
  // src/cli/repl.ts
32113
32134
  init_config();
32135
+
32136
+ // src/ui/plan-view.ts
32137
+ init_colors();
32138
+ init_js_identifiers();
32139
+ init_i18n();
32140
+ import { existsSync as existsSync52, readFileSync as readFileSync33 } from "fs";
32141
+ import { join as join46 } from "path";
32142
+ function readActivePlan(baseDir) {
32143
+ const p = join46(baseDir, ".mma", "plans", "active.json");
32144
+ if (!existsSync52(p))
32145
+ return null;
32146
+ try {
32147
+ const raw = readFileSync33(p, "utf-8");
32148
+ if (!raw.trim())
32149
+ return null;
32150
+ const parsed = JSON.parse(raw);
32151
+ if (!parsed || !Array.isArray(parsed.steps))
32152
+ return null;
32153
+ return {
32154
+ id: parsed.id || "plan",
32155
+ title: parsed.title || "Plan",
32156
+ steps: parsed.steps,
32157
+ createdAt: parsed.createdAt || new Date().toISOString(),
32158
+ baseDir: parsed.baseDir || baseDir,
32159
+ name: parsed.name
32160
+ };
32161
+ } catch {
32162
+ return null;
32163
+ }
32164
+ }
32165
+ function currentStepIndex(plan) {
32166
+ const idx = plan.steps.findIndex((s) => s.status !== "done" && s.status !== "skipped");
32167
+ return idx === -1 ? 0 : idx;
32168
+ }
32169
+ function stepMark(step) {
32170
+ switch (step.status) {
32171
+ case "done":
32172
+ return pc2.green("[x]");
32173
+ case "in_progress":
32174
+ return pc2.yellow("[*]");
32175
+ case "failed":
32176
+ return pc2.red("[!]");
32177
+ case "skipped":
32178
+ return pc2.dim("[-]");
32179
+ default:
32180
+ return pc2.dim("[ ]");
32181
+ }
32182
+ }
32183
+ function formatPlanChecklist(plan) {
32184
+ const done = plan.steps.filter((s) => s.status === "done" || s.status === "skipped").length;
32185
+ const total = plan.steps.length;
32186
+ const pct = total === 0 ? 0 : Math.round(done / total * 100);
32187
+ const cur = currentStepIndex(plan);
32188
+ const barLen = 15;
32189
+ const filled = Math.round(pct / 100 * barLen);
32190
+ const bar = pc2.green("█".repeat(filled)) + pc2.dim("░".repeat(barLen - filled));
32191
+ const title = plan.title.replace(/^\[\d+[^]]*\]\s*/, "");
32192
+ const lines = [
32193
+ `${pc2.cyan(`[${plan.id}]`)} ${pc2.bold(title)} ${bar} ${pc2.dim(`${done}/${total} ${pct}%`)}`
32194
+ ];
32195
+ for (let i = 0;i < plan.steps.length; i++) {
32196
+ const step = plan.steps[i];
32197
+ const active = i === cur;
32198
+ const desc = active ? pc2.yellow(step.description) : pc2.dim(step.description);
32199
+ lines.push(` ${stepMark(step)} ${step.id}. ${desc}`);
32200
+ for (const sub of step.subtasks ?? []) {
32201
+ lines.push(` ${sub.done ? pc2.green("[x]") : pc2.dim("[ ]")} ${sub.text}`);
32202
+ }
32203
+ }
32204
+ return lines;
32205
+ }
32206
+ var STRUCTURAL_TOOLS = new Set([
32207
+ "plan",
32208
+ "todo",
32209
+ "verify",
32210
+ "project_map",
32211
+ "lsp_check",
32212
+ "enable_tools"
32213
+ ]);
32214
+ function truncate3(s, max = 48) {
32215
+ return s.length > max ? `${s.slice(0, max - 1)}…` : s;
32216
+ }
32217
+ function stepContextForTool(plan, tool, args) {
32218
+ if (!plan || STRUCTURAL_TOOLS.has(tool))
32219
+ return null;
32220
+ const argStr = JSON.stringify(args);
32221
+ const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
32222
+ if (callPaths.length > 0) {
32223
+ for (const step2 of plan.steps) {
32224
+ if (step2.status === "done" || step2.status === "skipped")
32225
+ continue;
32226
+ const stepPaths = extractFileLikeTokens(stripUrls(step2.description)).map((p) => p.toLowerCase());
32227
+ if (stepPaths.length > 0 && stepPaths.some((s) => callPaths.some((c) => c.includes(s) || s.includes(c)))) {
32228
+ return t("ui.step_context", { id: step2.id, desc: truncate3(step2.description) });
32229
+ }
32230
+ }
32231
+ }
32232
+ const cur = currentStepIndex(plan);
32233
+ const step = plan.steps[cur];
32234
+ if (!step)
32235
+ return null;
32236
+ return t("ui.step_context", { id: step.id, desc: truncate3(step.description) });
32237
+ }
32238
+
32239
+ // src/cli/repl.ts
32114
32240
  function readVersion4() {
32115
32241
  const here = dirname18(fileURLToPath6(import.meta.url));
32116
- const candidates = [join46(here, "..", "..", "package.json"), join46(here, "..", "package.json")];
32242
+ const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
32117
32243
  for (const p of candidates) {
32118
- if (existsSync52(p)) {
32244
+ if (existsSync53(p)) {
32119
32245
  try {
32120
- const raw = JSON.parse(readFileSync33(p, "utf8"));
32246
+ const raw = JSON.parse(readFileSync34(p, "utf8"));
32121
32247
  if (raw.version)
32122
32248
  return raw.version;
32123
32249
  } catch {}
@@ -32158,6 +32284,8 @@ class Repl {
32158
32284
  noAgentsMd;
32159
32285
  pendingClipboardImage = null;
32160
32286
  exitOnClose = false;
32287
+ activePlan = null;
32288
+ lastPlanSig = "";
32161
32289
  rl;
32162
32290
  agent;
32163
32291
  config;
@@ -32173,10 +32301,10 @@ class Repl {
32173
32301
  this.skillsModule = skillsModule;
32174
32302
  this.pluginManager = pluginManager;
32175
32303
  this.logger = logger;
32176
- this.configDir = configDir || join46(homedir17(), ".mma");
32304
+ this.configDir = configDir || join47(homedir17(), ".mma");
32177
32305
  this.baseDir = baseDir || process.cwd();
32178
32306
  this.noAgentsMd = noAgentsMd === true;
32179
- this.historyPath = join46(homedir17(), ".mma", "repl-history");
32307
+ this.historyPath = join47(homedir17(), ".mma", "repl-history");
32180
32308
  this.loadHistory();
32181
32309
  this.rl = process.stdin.isTTY ? new LineEditor({
32182
32310
  input: process.stdin,
@@ -32209,9 +32337,9 @@ class Repl {
32209
32337
  this.setupListeners();
32210
32338
  }
32211
32339
  loadHistory() {
32212
- if (existsSync52(this.historyPath)) {
32340
+ if (existsSync53(this.historyPath)) {
32213
32341
  try {
32214
- const raw = readFileSync33(this.historyPath, "utf-8");
32342
+ const raw = readFileSync34(this.historyPath, "utf-8");
32215
32343
  this.history = raw.split(`
32216
32344
  `).filter(Boolean).slice(-this.maxHistory);
32217
32345
  } catch {
@@ -32410,11 +32538,15 @@ ${t("image.clipboard_empty")}`));
32410
32538
  spinner: this.config.ui?.spinner ?? true,
32411
32539
  toolStyle: this.config.ui?.toolStyle ?? "inline"
32412
32540
  });
32541
+ this.refreshActivePlan(renderer);
32413
32542
  const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
32414
32543
  if (ev.type === "start") {
32415
- renderer.toolStart(ev.tool, ev.args);
32544
+ renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args));
32416
32545
  } else {
32417
32546
  renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
32547
+ if (ev.tool === "plan" || ev.tool === "todo") {
32548
+ this.refreshActivePlan(renderer);
32549
+ }
32418
32550
  }
32419
32551
  }, (phase) => {
32420
32552
  if (phase === "thinking") {
@@ -32438,6 +32570,20 @@ ${t("image.clipboard_empty")}`));
32438
32570
  this.agentRunning = false;
32439
32571
  }
32440
32572
  }
32573
+ refreshActivePlan(renderer) {
32574
+ const plan = readActivePlan(this.baseDir);
32575
+ const sig = plan ? JSON.stringify(plan.steps.map((s) => `${s.id}:${s.status}`)) : "";
32576
+ if (!plan) {
32577
+ this.activePlan = null;
32578
+ this.lastPlanSig = "";
32579
+ return;
32580
+ }
32581
+ this.activePlan = plan;
32582
+ if (sig !== this.lastPlanSig) {
32583
+ this.lastPlanSig = sig;
32584
+ renderer.planBlock(formatPlanChecklist(plan));
32585
+ }
32586
+ }
32441
32587
  commands = new Map;
32442
32588
  registerCommand(cmd) {
32443
32589
  this.commands.set(cmd.name, cmd);
@@ -32570,11 +32716,11 @@ ${t("image.clipboard_empty")}`));
32570
32716
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
32571
32717
  } else {
32572
32718
  const agentsMdCandidates = [
32573
- join46(this.baseDir, "AGENTS.md"),
32574
- join46(this.baseDir, ".mma", "AGENTS.md"),
32575
- join46(this.configDir, "AGENTS.md")
32719
+ join47(this.baseDir, "AGENTS.md"),
32720
+ join47(this.baseDir, ".mma", "AGENTS.md"),
32721
+ join47(this.configDir, "AGENTS.md")
32576
32722
  ];
32577
- const foundAgents = agentsMdCandidates.filter((p) => existsSync52(p));
32723
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync53(p));
32578
32724
  if (foundAgents.length > 0) {
32579
32725
  for (const p of foundAgents) {
32580
32726
  row(t("repl.agents_label"), pc2.dim(p));
@@ -32585,7 +32731,7 @@ ${t("image.clipboard_empty")}`));
32585
32731
  }
32586
32732
  const meta = this.sessionManager?.getActiveMeta();
32587
32733
  if (meta) {
32588
- const sessionPath = join46(this.configDir, "sessions", meta.id);
32734
+ const sessionPath = join47(this.configDir, "sessions", meta.id);
32589
32735
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
32590
32736
  }
32591
32737
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -32645,8 +32791,8 @@ init_setup();
32645
32791
  init_config2();
32646
32792
  init_i18n();
32647
32793
  init_colors();
32648
- import { existsSync as existsSync53, readFileSync as readFileSync34 } from "fs";
32649
- import { join as join47, dirname as dirname19 } from "path";
32794
+ import { existsSync as existsSync54, readFileSync as readFileSync35 } from "fs";
32795
+ import { join as join48, dirname as dirname19 } from "path";
32650
32796
  import { homedir as homedir18 } from "os";
32651
32797
  import { fileURLToPath as fileURLToPath7 } from "url";
32652
32798
 
@@ -32750,11 +32896,11 @@ class UpdaterModule {
32750
32896
  // src/cli/main.ts
32751
32897
  function readVersion5() {
32752
32898
  const here = dirname19(fileURLToPath7(import.meta.url));
32753
- const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
32899
+ const candidates = [join48(here, "..", "..", "package.json"), join48(here, "..", "package.json")];
32754
32900
  for (const p of candidates) {
32755
- if (existsSync53(p)) {
32901
+ if (existsSync54(p)) {
32756
32902
  try {
32757
- const raw = JSON.parse(readFileSync34(p, "utf8"));
32903
+ const raw = JSON.parse(readFileSync35(p, "utf8"));
32758
32904
  if (raw.version)
32759
32905
  return raw.version;
32760
32906
  } catch {}
@@ -32837,15 +32983,15 @@ async function main() {
32837
32983
  await updater?.waitForIdle();
32838
32984
  process.exit(exitCode);
32839
32985
  } else {
32840
- const configPath = join47(homedir18(), ".mma", "config.json");
32841
- if (!existsSync53(configPath)) {
32986
+ const configPath = join48(homedir18(), ".mma", "config.json");
32987
+ if (!existsSync54(configPath)) {
32842
32988
  console.log(pc2.yellow(`
32843
32989
  ` + t("cli.first_run") + `
32844
32990
  `));
32845
32991
  const answers = await runSetup();
32846
32992
  const config2 = loadConfig({
32847
- configDir: join47(homedir18(), ".mma"),
32848
- projectConfigPath: projectDir ? join47(projectDir, ".mmrc") : join47(process.cwd(), ".mmrc")
32993
+ configDir: join48(homedir18(), ".mma"),
32994
+ projectConfigPath: projectDir ? join48(projectDir, ".mmrc") : join48(process.cwd(), ".mmrc")
32849
32995
  });
32850
32996
  config2.provider.type = answers.provider;
32851
32997
  config2.provider.baseUrl = answers.apiBase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.40.1",
3
+ "version": "0.41.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": {