micro-models-agent 0.56.1 → 0.56.3

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 (3) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/main.js +221 -100
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to Micro Models Agent (MMA) will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.56.1] - 2026-08-27
8
+
9
+ ### Added
10
+ - **CLI**: `mma changelog` command — show latest changelog entry or diff between versions (`--from <version>`)
11
+ - **Updater**: show changelog after auto-update install (`updater.installed` message includes new version's changelog)
12
+ - **Docs**: `CHANGELOG.md` included in npm package (visible via `npm info micro-models-agent`)
13
+ - **Docs**: rule to maintain changelog in `AGENTS.md`
14
+
7
15
  ## [0.56.0] - 2026-08-27
8
16
 
9
17
  ### Added
package/dist/main.js CHANGED
@@ -3126,8 +3126,12 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3126
3126
  "updater.check_error": "[updater] update check failed: {error}",
3127
3127
  "updater.available": "[updater] Update available: {current} → {latest}. Run `npm install -g micro-models-agent` to upgrade.",
3128
3128
  "updater.installing": "[updater] Installing {latest} globally (current: {current})…",
3129
- "updater.installed": "[updater] Installed {latest}. Restart MMA to use it (was {current}).",
3129
+ "updater.installed": `[updater] Installed {latest}. Restart MMA to use it (was {current}).
3130
+ {changelog}`,
3130
3131
  "updater.install_failed": "[updater] Failed to install {latest}: {error}. Update manually with `npm install -g micro-models-agent`.",
3132
+ "cli.changelog_title": "Changelog (micro-models-agent@{version}):",
3133
+ "cli.changelog_not_found": "Changelog not found for this installation.",
3134
+ "cli.changelog_range": "Changes since {from}:",
3131
3135
  "tools.enable_no_tags": 'enable_tools requires at least one tag in the "tags" array.',
3132
3136
  "tools.enable_no_executor": "Tool executor is not available — cannot enumerate enabled tools.",
3133
3137
  "tools.enable_already_active": "Tool tags already active: {tags}.",
@@ -3889,8 +3893,12 @@ var init_ru = __esm(() => {
3889
3893
  "updater.check_error": "[updater] Ошибка проверки обновления: {error}",
3890
3894
  "updater.available": "[updater] Доступно обновление: {current} → {latest}. Выполните `npm install -g micro-models-agent` для обновления.",
3891
3895
  "updater.installing": "[updater] Установка {latest} глобально (текущая: {current})…",
3892
- "updater.installed": "[updater] Установлена {latest}. Перезапустите MMA для применения (была {current}).",
3896
+ "updater.installed": `[updater] Установлена {latest}. Перезапустите MMA для применения (была {current}).
3897
+ {changelog}`,
3893
3898
  "updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`.",
3899
+ "cli.changelog_title": "Список изменений (micro-models-agent@{version}):",
3900
+ "cli.changelog_not_found": "Changelog не найден для этой установки.",
3901
+ "cli.changelog_range": "Изменения с версии {from}:",
3894
3902
  "tools.enable_no_tags": 'enable_tools требует хотя бы один тег в массиве "tags".',
3895
3903
  "tools.enable_no_executor": "Исполнитель тулов недоступен — невозможно перечислить включённые тулы.",
3896
3904
  "tools.enable_already_active": "Теги тулов уже активны: {tags}.",
@@ -33408,8 +33416,8 @@ var init_scenarios = __esm(() => {
33408
33416
  });
33409
33417
 
33410
33418
  // src/modules/certification/loader.ts
33411
- import { existsSync as existsSync51, readdirSync as readdirSync17, readFileSync as readFileSync32 } from "fs";
33412
- import { join as join44 } from "path";
33419
+ import { existsSync as existsSync52, readdirSync as readdirSync17, readFileSync as readFileSync33 } from "fs";
33420
+ import { join as join45 } from "path";
33413
33421
  function validateScenario(s) {
33414
33422
  const errors2 = [];
33415
33423
  const isSkip = s.mode === "skip";
@@ -33461,12 +33469,12 @@ function loadScenarios(userDir) {
33461
33469
  else
33462
33470
  scenarios.push(s);
33463
33471
  }
33464
- if (userDir && existsSync51(userDir)) {
33472
+ if (userDir && existsSync52(userDir)) {
33465
33473
  for (const file of readdirSync17(userDir)) {
33466
33474
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
33467
33475
  continue;
33468
33476
  try {
33469
- const raw = readFileSync32(join44(userDir, file), "utf-8");
33477
+ const raw = readFileSync33(join45(userDir, file), "utf-8");
33470
33478
  const data = $parse(raw);
33471
33479
  const parsed = normalizeScenario(data, file);
33472
33480
  const errs = validateScenario(parsed);
@@ -33529,8 +33537,8 @@ var init_loader3 = __esm(() => {
33529
33537
  });
33530
33538
 
33531
33539
  // src/modules/certification/fact-checker.ts
33532
- import { existsSync as existsSync52, readFileSync as readFileSync33, statSync as statSync9 } from "fs";
33533
- import { join as join45 } from "path";
33540
+ import { existsSync as existsSync53, readFileSync as readFileSync34, statSync as statSync9 } from "fs";
33541
+ import { join as join46 } from "path";
33534
33542
  function checkSandbox(sandboxDir, checks, exitCode, output) {
33535
33543
  const failures = [];
33536
33544
  for (const check of checks) {
@@ -33547,16 +33555,16 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33547
33555
  case "outputContains":
33548
33556
  return output.includes(check.text);
33549
33557
  case "fileExists":
33550
- return isFile(join45(sandboxDir, check.path));
33558
+ return isFile(join46(sandboxDir, check.path));
33551
33559
  case "fileNotExists":
33552
- return !existsSync52(join45(sandboxDir, check.path));
33560
+ return !existsSync53(join46(sandboxDir, check.path));
33553
33561
  case "dirExists":
33554
- return isDir(join45(sandboxDir, check.path));
33562
+ return isDir(join46(sandboxDir, check.path));
33555
33563
  case "fileContent": {
33556
- const abs = join45(sandboxDir, check.path);
33564
+ const abs = join46(sandboxDir, check.path);
33557
33565
  if (!isFile(abs))
33558
33566
  return false;
33559
- const content = readFileSync33(abs, "utf-8");
33567
+ const content = readFileSync34(abs, "utf-8");
33560
33568
  if (check.contains !== undefined)
33561
33569
  return content.includes(check.contains);
33562
33570
  if (check.equals !== undefined)
@@ -33564,10 +33572,10 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33564
33572
  return false;
33565
33573
  }
33566
33574
  case "fileRegex": {
33567
- const abs = join45(sandboxDir, check.path);
33575
+ const abs = join46(sandboxDir, check.path);
33568
33576
  if (!isFile(abs))
33569
33577
  return false;
33570
- return new RegExp(check.pattern).test(readFileSync33(abs, "utf-8"));
33578
+ return new RegExp(check.pattern).test(readFileSync34(abs, "utf-8"));
33571
33579
  }
33572
33580
  default:
33573
33581
  return false;
@@ -33575,14 +33583,14 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33575
33583
  }
33576
33584
  function isFile(p) {
33577
33585
  try {
33578
- return existsSync52(p) && statSync9(p).isFile();
33586
+ return existsSync53(p) && statSync9(p).isFile();
33579
33587
  } catch {
33580
33588
  return false;
33581
33589
  }
33582
33590
  }
33583
33591
  function isDir(p) {
33584
33592
  try {
33585
- return existsSync52(p) && statSync9(p).isDirectory();
33593
+ return existsSync53(p) && statSync9(p).isDirectory();
33586
33594
  } catch {
33587
33595
  return false;
33588
33596
  }
@@ -33613,8 +33621,8 @@ var init_fact_checker = () => {};
33613
33621
 
33614
33622
  // src/modules/certification/runner.ts
33615
33623
  import { spawn as spawn10 } from "child_process";
33616
- import { existsSync as existsSync53, mkdirSync as mkdirSync20, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync34 } from "fs";
33617
- import { join as join46, resolve as resolve23, dirname as dirname19, relative as relative7 } from "path";
33624
+ import { existsSync as existsSync54, mkdirSync as mkdirSync20, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync35 } from "fs";
33625
+ import { join as join47, resolve as resolve23, dirname as dirname20, relative as relative7 } from "path";
33618
33626
  async function runScenario(scenario, opts) {
33619
33627
  if (scenario.mode === "skip") {
33620
33628
  return {
@@ -33634,7 +33642,7 @@ async function runScenario(scenario, opts) {
33634
33642
  let firstError;
33635
33643
  let lastFailedSandbox;
33636
33644
  for (let i = 1;i <= reps; i++) {
33637
- const sandbox = join46(opts.sandboxBase, `run-${scenario.id}-${i}`);
33645
+ const sandbox = join47(opts.sandboxBase, `run-${scenario.id}-${i}`);
33638
33646
  let failures = [];
33639
33647
  let exitCode = -1;
33640
33648
  let output = "";
@@ -33658,9 +33666,9 @@ async function runScenario(scenario, opts) {
33658
33666
  env3.MMA_PROVIDER_APIKEY = opts.providerKey;
33659
33667
  if (scenario.config && opts.baseConfig) {
33660
33668
  const merged = deepMergeAny(opts.baseConfig, scenario.config);
33661
- const certConfigDir = join46(sandbox, ".mma");
33669
+ const certConfigDir = join47(sandbox, ".mma");
33662
33670
  mkdirSync20(certConfigDir, { recursive: true });
33663
- writeFileSync20(join46(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
33671
+ writeFileSync20(join47(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
33664
33672
  env3.MMA_CONFIG_DIR = certConfigDir;
33665
33673
  }
33666
33674
  const res = await runner(env3, opts.mmaRoot, args, timeoutMs);
@@ -33707,12 +33715,12 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
33707
33715
  rmSync4(sandbox, { recursive: true, force: true });
33708
33716
  mkdirSync20(sandbox, { recursive: true });
33709
33717
  for (const f of scenario.fixtures ?? []) {
33710
- const src = join46(mmaRoot, f.source);
33711
- if (!existsSync53(src)) {
33718
+ const src = join47(mmaRoot, f.source);
33719
+ if (!existsSync54(src)) {
33712
33720
  throw new Error(`fixture missing: ${f.source}`);
33713
33721
  }
33714
- const dest = join46(sandbox, f.dest);
33715
- mkdirSync20(dirname19(dest), { recursive: true });
33722
+ const dest = join47(sandbox, f.dest);
33723
+ mkdirSync20(dirname20(dest), { recursive: true });
33716
33724
  cpSync2(src, dest);
33717
33725
  }
33718
33726
  }
@@ -33724,10 +33732,10 @@ function collectDiagnostics(sandbox) {
33724
33732
  } else {
33725
33733
  lines.push(" Files created: (none)");
33726
33734
  }
33727
- const planPath = join46(sandbox, ".mma", "plans", "active.json");
33728
- if (existsSync53(planPath)) {
33735
+ const planPath = join47(sandbox, ".mma", "plans", "active.json");
33736
+ if (existsSync54(planPath)) {
33729
33737
  try {
33730
- const plan = JSON.parse(readFileSync34(planPath, "utf-8"));
33738
+ const plan = JSON.parse(readFileSync35(planPath, "utf-8"));
33731
33739
  const steps = plan.steps ?? [];
33732
33740
  const done = steps.filter((s) => s.status === "done").length;
33733
33741
  const pending = steps.filter((s) => s.status === "pending" || s.status === "in_progress");
@@ -33746,7 +33754,7 @@ function listFiles(dir, root) {
33746
33754
  for (const entry of readdirSync18(dir, { withFileTypes: true })) {
33747
33755
  if (entry.name === ".mma")
33748
33756
  continue;
33749
- const abs = join46(dir, entry.name);
33757
+ const abs = join47(dir, entry.name);
33750
33758
  const rel = toForwardSlash(relative7(root, abs));
33751
33759
  if (entry.isDirectory()) {
33752
33760
  result.push(...listFiles(abs, root));
@@ -33758,15 +33766,15 @@ function listFiles(dir, root) {
33758
33766
  return result;
33759
33767
  }
33760
33768
  function resolveMmaEntry(mmaRoot) {
33761
- const dev = join46(mmaRoot, "src", "cli", "main.ts");
33762
- if (existsSync53(dev))
33769
+ const dev = join47(mmaRoot, "src", "cli", "main.ts");
33770
+ if (existsSync54(dev))
33763
33771
  return dev;
33764
- return join46(mmaRoot, "dist", "main.js");
33772
+ return join47(mmaRoot, "dist", "main.js");
33765
33773
  }
33766
33774
  function findMmaRoot(fromDir) {
33767
33775
  const candidates = [resolve23(fromDir, "..", "..", ".."), resolve23(fromDir, "..")];
33768
33776
  for (const c of candidates) {
33769
- if (existsSync53(join46(c, "package.json")))
33777
+ if (existsSync54(join47(c, "package.json")))
33770
33778
  return c;
33771
33779
  }
33772
33780
  return process.cwd();
@@ -33834,15 +33842,15 @@ __export(exports_cli, {
33834
33842
  certList: () => certList
33835
33843
  });
33836
33844
  import { rmSync as rmSync5, writeFileSync as writeFileSync21 } from "fs";
33837
- import { join as join47, dirname as dirname20 } from "path";
33845
+ import { join as join48, dirname as dirname21 } from "path";
33838
33846
  import { fileURLToPath as fileURLToPath5 } from "url";
33839
- import { existsSync as existsSync54, readFileSync as readFileSync35 } from "fs";
33847
+ import { existsSync as existsSync55, readFileSync as readFileSync36 } from "fs";
33840
33848
  function readVersion() {
33841
- const candidates = [join47(MMA_ROOT, "package.json")];
33849
+ const candidates = [join48(MMA_ROOT, "package.json")];
33842
33850
  for (const p of candidates) {
33843
- if (existsSync54(p)) {
33851
+ if (existsSync55(p)) {
33844
33852
  try {
33845
- const raw = JSON.parse(readFileSync35(p, "utf-8"));
33853
+ const raw = JSON.parse(readFileSync36(p, "utf-8"));
33846
33854
  if (raw.version)
33847
33855
  return raw.version;
33848
33856
  } catch {}
@@ -33855,7 +33863,7 @@ function parseTags(s) {
33855
33863
  }
33856
33864
  async function certify(opts) {
33857
33865
  const providerUrl = opts.providerUrl || opts.config.provider.baseUrl;
33858
- const { scenarios, errors: errors2 } = loadScenarios(join47(opts.projectDir, ".mma", "certification", "scenarios"));
33866
+ const { scenarios, errors: errors2 } = loadScenarios(join48(opts.projectDir, ".mma", "certification", "scenarios"));
33859
33867
  for (const e of errors2)
33860
33868
  console.error(pc2.yellow(` ${e}`));
33861
33869
  let selected = filterByTags(scenarios, opts.tags);
@@ -33886,7 +33894,7 @@ async function certify(opts) {
33886
33894
  return;
33887
33895
  }
33888
33896
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
33889
- const sandboxBase = join47(process.cwd(), ".mma", "certification");
33897
+ const sandboxBase = join48(process.cwd(), ".mma", "certification");
33890
33898
  const results = [];
33891
33899
  const total = selected.length;
33892
33900
  let idx = 0;
@@ -34019,10 +34027,10 @@ function printResults(results) {
34019
34027
  }
34020
34028
  }
34021
34029
  function writeReport(entry, projectDir) {
34022
- const reportDir = join47(projectDir, "certification");
34030
+ const reportDir = join48(projectDir, "certification");
34023
34031
  const ts = entry.certifiedAt.replace(/[:.]/g, "-").slice(0, 19);
34024
34032
  const filename = `report-${entry.model.replace(/[/\\:]/g, "_")}-${ts}.json`;
34025
- const reportPath = join47(reportDir, filename);
34033
+ const reportPath = join48(reportDir, filename);
34026
34034
  const report = {
34027
34035
  model: entry.model,
34028
34036
  providerUrl: entry.providerUrl,
@@ -34055,7 +34063,7 @@ var init_cli = __esm(() => {
34055
34063
  init_loader3();
34056
34064
  init_runner2();
34057
34065
  init_manifest();
34058
- HERE = dirname20(fileURLToPath5(import.meta.url));
34066
+ HERE = dirname21(fileURLToPath5(import.meta.url));
34059
34067
  MMA_ROOT = findMmaRoot(HERE);
34060
34068
  });
34061
34069
 
@@ -34065,8 +34073,8 @@ __export(exports_repl_commands, {
34065
34073
  registerAllCommands: () => registerAllCommands,
34066
34074
  COMMAND_GROUPS: () => COMMAND_GROUPS
34067
34075
  });
34068
- import { join as join49, dirname as dirname22 } from "path";
34069
- import { existsSync as existsSync56 } from "fs";
34076
+ import { join as join50, dirname as dirname23 } from "path";
34077
+ import { existsSync as existsSync57 } from "fs";
34070
34078
  function registerAllCommands(ctx) {
34071
34079
  registerBuiltinCommands(ctx);
34072
34080
  registerMmaCommands(ctx);
@@ -34123,7 +34131,7 @@ function registerMmaCommands(ctx) {
34123
34131
  }
34124
34132
  try {
34125
34133
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
34126
- const { existsSync: existsSync57 } = await import("fs");
34134
+ const { existsSync: existsSync58 } = await import("fs");
34127
34135
  const { resolve: resolve24 } = await import("path");
34128
34136
  let dataUrl;
34129
34137
  let label;
@@ -34143,7 +34151,7 @@ function registerMmaCommands(ctx) {
34143
34151
  label = source;
34144
34152
  } else {
34145
34153
  const absPath = resolve24(process.cwd(), source);
34146
- if (!existsSync57(absPath)) {
34154
+ if (!existsSync58(absPath)) {
34147
34155
  console.log(pc2.red(t("image.not_found", { path: source })));
34148
34156
  return;
34149
34157
  }
@@ -34246,7 +34254,7 @@ function registerMmaCommands(ctx) {
34246
34254
  console.log(pc2.yellow(t("repl.wizard_running")));
34247
34255
  await ctx.withExclusiveInput(async () => {
34248
34256
  const answers = await runSetup(ctx.rl);
34249
- const configPath = join49(ctx.configDir, "config.json");
34257
+ const configPath = join50(ctx.configDir, "config.json");
34250
34258
  ctx.config.provider.type = answers.provider;
34251
34259
  ctx.config.provider.baseUrl = answers.apiBase;
34252
34260
  ctx.config.provider.apiKey = answers.apiKey;
@@ -34254,7 +34262,7 @@ function registerMmaCommands(ctx) {
34254
34262
  ctx.config.contextWindow = answers.contextWindow;
34255
34263
  ctx.config.maxToolIterations = answers.maxToolIterations;
34256
34264
  ctx.config.locale = answers.locale;
34257
- saveConfig(ctx.config, configPath, dirname22(configPath));
34265
+ saveConfig(ctx.config, configPath, dirname23(configPath));
34258
34266
  await ctx.agent.reconfigure(ctx.config);
34259
34267
  console.log(pc2.green(t("cli.config_saved")));
34260
34268
  });
@@ -34368,8 +34376,8 @@ function registerMmaCommands(ctx) {
34368
34376
  return;
34369
34377
  }
34370
34378
  ctx.config.model = name;
34371
- const configPath = join49(ctx.configDir, "config.json");
34372
- saveConfig(ctx.config, configPath, dirname22(configPath));
34379
+ const configPath = join50(ctx.configDir, "config.json");
34380
+ saveConfig(ctx.config, configPath, dirname23(configPath));
34373
34381
  await ctx.agent.reconfigure(ctx.config);
34374
34382
  console.log(pc2.green(t("repl.model_set", { name })));
34375
34383
  return;
@@ -34393,8 +34401,8 @@ function registerMmaCommands(ctx) {
34393
34401
  return;
34394
34402
  }
34395
34403
  ctx.config.contextWindow = size;
34396
- const configPath = join49(ctx.configDir, "config.json");
34397
- saveConfig(ctx.config, configPath, dirname22(configPath));
34404
+ const configPath = join50(ctx.configDir, "config.json");
34405
+ saveConfig(ctx.config, configPath, dirname23(configPath));
34398
34406
  await ctx.agent.reconfigure(ctx.config);
34399
34407
  console.log(pc2.green(t("cli.context_set", { size })));
34400
34408
  }
@@ -34408,10 +34416,10 @@ function registerMmaCommands(ctx) {
34408
34416
  if (ctx.sessionManager && ctx.config.session.autoSave) {}
34409
34417
  ctx.agent.shutdown();
34410
34418
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
34411
- const { join: join50 } = await import("path");
34419
+ const { join: join51 } = await import("path");
34412
34420
  const configDir = ctx.configDir;
34413
34421
  const baseDir = ctx.baseDir;
34414
- const projectConfigPath = join50(baseDir, ".mmrc");
34422
+ const projectConfigPath = join51(baseDir, ".mmrc");
34415
34423
  const { config: freshConfig } = loadConfig2({ configDir, projectConfigPath });
34416
34424
  Object.assign(ctx.config, freshConfig);
34417
34425
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -34765,21 +34773,21 @@ async function runConfigMigrate(ctx) {
34765
34773
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
34766
34774
  const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_config2(), exports_config));
34767
34775
  const configDir = ctx.configDir;
34768
- const configPath = join49(configDir, "config.json");
34776
+ const configPath = join50(configDir, "config.json");
34769
34777
  if (hasDomainFiles3(configDir)) {
34770
34778
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
34771
34779
  return;
34772
34780
  }
34773
- if (!existsSync56(configPath)) {
34781
+ if (!existsSync57(configPath)) {
34774
34782
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
34775
34783
  return;
34776
34784
  }
34777
34785
  console.log(t("config.migrate_start"));
34778
- const { config } = loadCfg({ configDir, projectConfigPath: join49(configDir, ".mmrc") });
34786
+ const { config } = loadCfg({ configDir, projectConfigPath: join50(configDir, ".mmrc") });
34779
34787
  saveConfig(config, configPath, configDir);
34780
34788
  const { renameSync: renameSync4, readdirSync: readdirSync19 } = await import("fs");
34781
34789
  renameSync4(configPath, configPath + ".bak");
34782
- const domainFiles = readdirSync19(join49(configDir, "config")).filter((f) => f.endsWith(".json"));
34790
+ const domainFiles = readdirSync19(join50(configDir, "config")).filter((f) => f.endsWith(".json"));
34783
34791
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
34784
34792
  }
34785
34793
  var version2, COMMAND_GROUPS;
@@ -34839,9 +34847,9 @@ init_config2();
34839
34847
  init_setup();
34840
34848
  init_i18n();
34841
34849
  init_colors();
34842
- import { join as join48, dirname as dirname21 } from "path";
34850
+ import { join as join49, dirname as dirname22 } from "path";
34843
34851
  import { homedir as homedir16 } from "os";
34844
- import { existsSync as existsSync55 } from "fs";
34852
+ import { existsSync as existsSync56 } from "fs";
34845
34853
 
34846
34854
  // src/cli/security-commands.ts
34847
34855
  init_bootstrap();
@@ -35472,12 +35480,92 @@ function createPluginCommand(program2) {
35472
35480
  // src/cli/commands.ts
35473
35481
  init_presets();
35474
35482
  init_version();
35483
+
35484
+ // src/modules/updater/changelog-reader.ts
35485
+ import { readFileSync as readFileSync32, existsSync as existsSync51 } from "fs";
35486
+ import { dirname as dirname19, join as join44 } from "path";
35487
+ function readChangelog(packageName) {
35488
+ try {
35489
+ let dir = dirname19(import.meta.url);
35490
+ if (dir.startsWith("file://")) {
35491
+ dir = decodeURIComponent(dir.slice(7));
35492
+ }
35493
+ for (let i = 0;i < 10; i++) {
35494
+ const pkgPath = join44(dir, "package.json");
35495
+ if (existsSync51(pkgPath)) {
35496
+ const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
35497
+ if (pkg.name === packageName) {
35498
+ const changelogPath = join44(dir, "CHANGELOG.md");
35499
+ if (existsSync51(changelogPath)) {
35500
+ return readFileSync32(changelogPath, "utf-8");
35501
+ }
35502
+ return null;
35503
+ }
35504
+ }
35505
+ dir = dirname19(dir);
35506
+ }
35507
+ return null;
35508
+ } catch {
35509
+ return null;
35510
+ }
35511
+ }
35512
+ function extractChangelogRange(changelog, fromVersion, toVersion) {
35513
+ const lines = changelog.split(`
35514
+ `);
35515
+ const sections = [];
35516
+ let capturing = false;
35517
+ let foundFrom = false;
35518
+ for (const line of lines) {
35519
+ const match = line.match(/^## \[(\d+\.\d+\.\d+)\]/);
35520
+ if (match) {
35521
+ const ver = match[1];
35522
+ if (ver === fromVersion) {
35523
+ foundFrom = true;
35524
+ break;
35525
+ }
35526
+ if (capturing) {
35527
+ sections.push("");
35528
+ }
35529
+ capturing = true;
35530
+ }
35531
+ if (capturing) {
35532
+ sections.push(line);
35533
+ }
35534
+ }
35535
+ if (!foundFrom)
35536
+ return null;
35537
+ return sections.length > 0 ? sections.join(`
35538
+ `).trim() : null;
35539
+ }
35540
+ function extractLatestChangelog(changelog) {
35541
+ const lines = changelog.split(`
35542
+ `);
35543
+ const sections = [];
35544
+ let capturing = false;
35545
+ let found = false;
35546
+ for (const line of lines) {
35547
+ const match = line.match(/^## \[(\d+\.\d+\.\d+)\]/);
35548
+ if (match) {
35549
+ if (found)
35550
+ break;
35551
+ capturing = true;
35552
+ found = true;
35553
+ }
35554
+ if (capturing) {
35555
+ sections.push(line);
35556
+ }
35557
+ }
35558
+ return sections.length > 0 ? sections.join(`
35559
+ `).trim() : null;
35560
+ }
35561
+
35562
+ // src/cli/commands.ts
35475
35563
  var version = readMmaVersion();
35476
35564
  function createProgram() {
35477
35565
  const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json")).option("--reasoning <level>", t("cli.reasoning_level"), "auto");
35478
35566
  program2.command("init").description(t("cli.init")).action(async () => {
35479
35567
  const answers = await runSetup();
35480
- const configPath = join48(homedir16(), ".mma", "config.json");
35568
+ const configPath = join49(homedir16(), ".mma", "config.json");
35481
35569
  const { config } = await bootstrap();
35482
35570
  config.provider.type = answers.provider;
35483
35571
  config.provider.baseUrl = answers.apiBase;
@@ -35517,12 +35605,12 @@ function createProgram() {
35517
35605
  config.security.paths.denied = [];
35518
35606
  }
35519
35607
  }
35520
- saveConfig(config, configPath, dirname21(configPath));
35608
+ saveConfig(config, configPath, dirname22(configPath));
35521
35609
  console.log(t("cli.config_saved"));
35522
35610
  });
35523
35611
  const configCmd = program2.command("config").description(t("cli.manage_config"));
35524
35612
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
35525
- const configPath = join48(homedir16(), ".mma", "config.json");
35613
+ const configPath = join49(homedir16(), ".mma", "config.json");
35526
35614
  const { config } = await bootstrap();
35527
35615
  const keys = key.split(".");
35528
35616
  let obj = config;
@@ -35542,7 +35630,7 @@ function createProgram() {
35542
35630
  obj[lastKey] = parseFloat(value);
35543
35631
  else
35544
35632
  obj[lastKey] = value;
35545
- saveConfig(config, configPath, dirname21(configPath));
35633
+ saveConfig(config, configPath, dirname22(configPath));
35546
35634
  console.log(t("cli.set_done", { key, value }));
35547
35635
  });
35548
35636
  configCmd.command("show").description(t("cli.show_config")).action(async () => {
@@ -35552,24 +35640,24 @@ function createProgram() {
35552
35640
  configCmd.command("migrate").description(t("cli.migrate_config")).action(async () => {
35553
35641
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
35554
35642
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
35555
- const configDir = join48(homedir16(), ".mma");
35556
- const configPath = join48(configDir, "config.json");
35643
+ const configDir = join49(homedir16(), ".mma");
35644
+ const configPath = join49(configDir, "config.json");
35557
35645
  if (hasDomainFiles3(configDir)) {
35558
35646
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
35559
35647
  return;
35560
35648
  }
35561
- if (!existsSync55(configPath)) {
35649
+ if (!existsSync56(configPath)) {
35562
35650
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
35563
35651
  return;
35564
35652
  }
35565
35653
  console.log(t("config.migrate_start"));
35566
- const { config } = loadConfig2({ configDir, projectConfigPath: join48(configDir, ".mmrc") });
35654
+ const { config } = loadConfig2({ configDir, projectConfigPath: join49(configDir, ".mmrc") });
35567
35655
  saveConfig(config, configPath, configDir);
35568
35656
  const bakPath = configPath + ".bak";
35569
35657
  const { renameSync: renameSync4 } = await import("fs");
35570
35658
  renameSync4(configPath, bakPath);
35571
35659
  const { readdirSync: readdirSync19 } = await import("fs");
35572
- const domainFiles = readdirSync19(join48(configDir, "config")).filter((f) => f.endsWith(".json"));
35660
+ const domainFiles = readdirSync19(join49(configDir, "config")).filter((f) => f.endsWith(".json"));
35573
35661
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
35574
35662
  });
35575
35663
  const model = program2.command("model").description(t("cli.manage_models"));
@@ -35609,10 +35697,10 @@ function createProgram() {
35609
35697
  console.log(t("cli.model_hint"));
35610
35698
  });
35611
35699
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
35612
- const configPath = join48(homedir16(), ".mma", "config.json");
35700
+ const configPath = join49(homedir16(), ".mma", "config.json");
35613
35701
  const { config } = await bootstrap();
35614
35702
  config.model = name;
35615
- saveConfig(config, configPath, dirname21(configPath));
35703
+ saveConfig(config, configPath, dirname22(configPath));
35616
35704
  console.log(t("cli.model_set", { name }));
35617
35705
  });
35618
35706
  model.command("certify").argument("<name>", "Model name").option("--provider-url <url>", t("cli.cert_provider_url")).option("--provider-key <key>", t("cli.cert_provider_key")).option("--context-window <n>", t("cli.cert_context_window")).option("--tags <tags>", t("cli.cert_tags"), "core").option("--scenarios <ids>", t("cli.cert_scenarios")).option("--timeout <ms>", t("cli.cert_timeout")).option("--reps <n>", t("cli.cert_reps")).option("--force", t("cli.cert_force")).option("--clean", t("cli.cert_clean")).description(t("cli.certify")).action(async (name, cmdOpts) => {
@@ -35648,7 +35736,7 @@ function createProgram() {
35648
35736
  await uncertify2(name, config, process.cwd());
35649
35737
  });
35650
35738
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
35651
- const configPath = join48(homedir16(), ".mma", "config.json");
35739
+ const configPath = join49(homedir16(), ".mma", "config.json");
35652
35740
  const { config } = await bootstrap();
35653
35741
  const contextWindow = parseInt(size, 10);
35654
35742
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -35656,7 +35744,7 @@ function createProgram() {
35656
35744
  return;
35657
35745
  }
35658
35746
  config.contextWindow = contextWindow;
35659
- saveConfig(config, configPath, dirname21(configPath));
35747
+ saveConfig(config, configPath, dirname22(configPath));
35660
35748
  console.log(t("cli.context_set", { size: contextWindow }));
35661
35749
  });
35662
35750
  const provider = program2.command("provider").description(t("cli.manage_providers"));
@@ -35694,7 +35782,7 @@ function createProgram() {
35694
35782
  console.log(t("cli.base_url"), config.provider.baseUrl);
35695
35783
  });
35696
35784
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
35697
- const configPath = join48(homedir16(), ".mma", "config.json");
35785
+ const configPath = join49(homedir16(), ".mma", "config.json");
35698
35786
  const { config, agent } = await bootstrap();
35699
35787
  if (config.provider.entries && config.provider.entries.length > 0) {
35700
35788
  try {
@@ -35710,14 +35798,14 @@ function createProgram() {
35710
35798
  if (baseUrl) {
35711
35799
  config.provider.baseUrl = baseUrl;
35712
35800
  }
35713
- saveConfig(config, configPath, dirname21(configPath));
35801
+ saveConfig(config, configPath, dirname22(configPath));
35714
35802
  console.log(t("cli.provider_set", { name }));
35715
35803
  if (baseUrl) {
35716
35804
  console.log(t("cli.provider_base_hint", { baseUrl }));
35717
35805
  }
35718
35806
  });
35719
35807
  provider.command("add").argument("<name>", "Provider type or label").option("--url <url>", "Base URL").option("--key <key>", "API key").option("--priority <n>", "Fallback priority (lower = tried first)").option("--context-window <n>", "Context window override for this entry").option("--rpm <n>", "Max requests per minute for this entry").option("--parallel <n>", "Max parallel tasks for this entry").description(t("cli.add_provider")).action(async (name, opts) => {
35720
- const configPath = join48(homedir16(), ".mma", "config.json");
35808
+ const configPath = join49(homedir16(), ".mma", "config.json");
35721
35809
  const { config } = await bootstrap();
35722
35810
  const entries = Array.isArray(config.provider.entries) ? config.provider.entries : [];
35723
35811
  if (entries.length === 0) {
@@ -35749,7 +35837,7 @@ function createProgram() {
35749
35837
  });
35750
35838
  config.provider.entries = entries;
35751
35839
  config.provider.active = config.provider.active || config.provider.type;
35752
- saveConfig(config, configPath, dirname21(configPath));
35840
+ saveConfig(config, configPath, dirname22(configPath));
35753
35841
  console.log(pc2.green(t("cli.provider_added", { name })));
35754
35842
  console.log(t("cli.provider_switch_hint"));
35755
35843
  });
@@ -35790,6 +35878,30 @@ function createProgram() {
35790
35878
  });
35791
35879
  createSecurityCommand(program2);
35792
35880
  createPluginCommand(program2);
35881
+ program2.command("changelog").description(t("cli.changelog_title", { version })).option("--from <version>", t("cli.changelog_range", { from: "..." })).action((opts) => {
35882
+ const changelog = readChangelog("micro-models-agent");
35883
+ if (!changelog) {
35884
+ console.log(pc2.yellow(t("cli.changelog_not_found")));
35885
+ return;
35886
+ }
35887
+ if (opts.from) {
35888
+ const range = extractChangelogRange(changelog, opts.from, version);
35889
+ if (!range) {
35890
+ console.log(pc2.yellow(t("cli.changelog_not_found")));
35891
+ return;
35892
+ }
35893
+ console.log(pc2.cyan(t("cli.changelog_range", { from: opts.from })));
35894
+ console.log(range);
35895
+ } else {
35896
+ const latest = extractLatestChangelog(changelog);
35897
+ if (!latest) {
35898
+ console.log(pc2.yellow(t("cli.changelog_not_found")));
35899
+ return;
35900
+ }
35901
+ console.log(pc2.cyan(t("cli.changelog_title", { version })));
35902
+ console.log(latest);
35903
+ }
35904
+ });
35793
35905
  program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
35794
35906
  return program2;
35795
35907
  }
@@ -36667,8 +36779,8 @@ class LineEditor {
36667
36779
  }
36668
36780
 
36669
36781
  // src/cli/repl.ts
36670
- import { existsSync as existsSync57, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "fs";
36671
- import { join as join50 } from "path";
36782
+ import { existsSync as existsSync58, readFileSync as readFileSync39, writeFileSync as writeFileSync22 } from "fs";
36783
+ import { join as join51 } from "path";
36672
36784
  import { homedir as homedir17 } from "os";
36673
36785
 
36674
36786
  // src/cli/completer.ts
@@ -37495,10 +37607,10 @@ class Repl {
37495
37607
  this.envReport = envReport;
37496
37608
  this.execModule = execModule;
37497
37609
  this.slog = new SessionLogger(sessionManager, logger4);
37498
- this.configDir = configDir || join50(homedir17(), ".mma");
37610
+ this.configDir = configDir || join51(homedir17(), ".mma");
37499
37611
  this.baseDir = baseDir || process.cwd();
37500
37612
  this.noAgentsMd = noAgentsMd === true;
37501
- this.historyPath = historyPath ?? join50(homedir17(), ".mma", "repl-history");
37613
+ this.historyPath = historyPath ?? join51(homedir17(), ".mma", "repl-history");
37502
37614
  this.loadHistory();
37503
37615
  this.rl = process.stdin.isTTY ? new LineEditor({
37504
37616
  input: process.stdin,
@@ -37550,9 +37662,9 @@ class Repl {
37550
37662
  }));
37551
37663
  }
37552
37664
  loadHistory() {
37553
- if (existsSync57(this.historyPath)) {
37665
+ if (existsSync58(this.historyPath)) {
37554
37666
  try {
37555
- const raw = readFileSync38(this.historyPath, "utf-8");
37667
+ const raw = readFileSync39(this.historyPath, "utf-8");
37556
37668
  this.history = raw.split(`
37557
37669
  `).filter(Boolean).slice(-this.maxHistory);
37558
37670
  } catch {
@@ -37950,11 +38062,11 @@ ${t("image.clipboard_empty")}`));
37950
38062
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
37951
38063
  } else {
37952
38064
  const agentsMdCandidates = [
37953
- join50(this.baseDir, "AGENTS.md"),
37954
- join50(this.baseDir, ".mma", "AGENTS.md"),
37955
- join50(this.configDir, "AGENTS.md")
38065
+ join51(this.baseDir, "AGENTS.md"),
38066
+ join51(this.baseDir, ".mma", "AGENTS.md"),
38067
+ join51(this.configDir, "AGENTS.md")
37956
38068
  ];
37957
- const foundAgents = agentsMdCandidates.filter((p) => existsSync57(p));
38069
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync58(p));
37958
38070
  if (foundAgents.length > 0) {
37959
38071
  for (const p of foundAgents) {
37960
38072
  row(t("repl.agents_label"), pc2.dim(p));
@@ -37965,7 +38077,7 @@ ${t("image.clipboard_empty")}`));
37965
38077
  }
37966
38078
  const meta = this.sessionManager?.getActiveMeta();
37967
38079
  if (meta) {
37968
- const sessionPath = join50(this.configDir, "sessions", meta.id);
38080
+ const sessionPath = join51(this.configDir, "sessions", meta.id);
37969
38081
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
37970
38082
  }
37971
38083
  const isTty2 = process.stdout.isTTY === true;
@@ -38080,8 +38192,8 @@ init_setup();
38080
38192
  init_config2();
38081
38193
  init_i18n();
38082
38194
  init_colors();
38083
- import { existsSync as existsSync58 } from "fs";
38084
- import { join as join52, dirname as dirname23 } from "path";
38195
+ import { existsSync as existsSync59 } from "fs";
38196
+ import { join as join53, dirname as dirname24 } from "path";
38085
38197
  import { homedir as homedir19 } from "os";
38086
38198
 
38087
38199
  // src/modules/updater/index.ts
@@ -38165,7 +38277,16 @@ class UpdaterModule {
38165
38277
  }));
38166
38278
  const install = await this.updater.install(result.latest);
38167
38279
  if (install.success) {
38168
- this.logger.info(t("updater.installed", { current: result.current, latest: result.latest }));
38280
+ const changelog = readChangelog("micro-models-agent");
38281
+ const latestEntry = changelog ? extractLatestChangelog(changelog) : null;
38282
+ const changelogBlock = latestEntry ? pc2.cyan(`
38283
+ ${t("cli.changelog_title", { version: result.latest })}
38284
+ `) + latestEntry : "";
38285
+ this.logger.info(t("updater.installed", {
38286
+ current: result.current,
38287
+ latest: result.latest,
38288
+ changelog: changelogBlock
38289
+ }));
38169
38290
  } else {
38170
38291
  this.logger.warn(t("updater.install_failed", {
38171
38292
  current: result.current,
@@ -38186,9 +38307,9 @@ init_environment();
38186
38307
  init_data_sanitizer();
38187
38308
  init_i18n();
38188
38309
  import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync21 } from "fs";
38189
- import { join as join51 } from "path";
38310
+ import { join as join52 } from "path";
38190
38311
  import { homedir as homedir18 } from "os";
38191
- var CRASH_LOG_DIR = join51(homedir18(), ".mma", "logs");
38312
+ var CRASH_LOG_DIR = join52(homedir18(), ".mma", "logs");
38192
38313
  var CRASH_LOG_FILE = "crash.jsonl";
38193
38314
  function formatCrashEntry(type2, err) {
38194
38315
  const message = err instanceof Error ? err.message : String(err);
@@ -38204,7 +38325,7 @@ function formatCrashEntry(type2, err) {
38204
38325
  function writeCrashEntry(dir, entry) {
38205
38326
  try {
38206
38327
  mkdirSync21(dir, { recursive: true });
38207
- appendFileSync7(join51(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
38328
+ appendFileSync7(join52(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
38208
38329
  `, "utf-8");
38209
38330
  } catch {}
38210
38331
  }
@@ -38313,9 +38434,9 @@ async function main() {
38313
38434
  await updater?.waitForIdle();
38314
38435
  process.exit(exitCode);
38315
38436
  } else {
38316
- const mmaDir = join52(homedir19(), ".mma");
38317
- const legacyConfigPath = join52(mmaDir, "config.json");
38318
- let hasAnyConfig = existsSync58(legacyConfigPath);
38437
+ const mmaDir = join53(homedir19(), ".mma");
38438
+ const legacyConfigPath = join53(mmaDir, "config.json");
38439
+ let hasAnyConfig = existsSync59(legacyConfigPath);
38319
38440
  if (!hasAnyConfig) {
38320
38441
  try {
38321
38442
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
@@ -38378,7 +38499,7 @@ async function main() {
38378
38499
  config.security.paths.denied = [];
38379
38500
  }
38380
38501
  }
38381
- saveConfig(config, legacyConfigPath, dirname23(legacyConfigPath));
38502
+ saveConfig(config, legacyConfigPath, dirname24(legacyConfigPath));
38382
38503
  await agent.reconfigure(config);
38383
38504
  }
38384
38505
  startAutoUpdate(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.56.1",
3
+ "version": "0.56.3",
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": {