micro-models-agent 0.41.0 → 0.41.2
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.
- package/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +9 -19
- package/dist/cli/completer.js +36 -37
- package/dist/cli/index.js +2 -2
- package/dist/cli/main.js +48 -23
- package/dist/cli/plugin-commands.js +36 -0
- package/dist/cli/repl-commands.js +40 -12
- package/dist/cli/repl.js +217 -87
- package/dist/cli/run-result.js +22 -0
- package/dist/cli/security-commands.js +5 -7
- package/dist/cli/setup.js +8 -26
- package/dist/config/config.js +52 -5
- package/dist/config/defaults.js +29 -5
- package/dist/config/experts.js +1 -1
- package/dist/config/index.js +3 -3
- package/dist/config/security.js +3 -10
- package/dist/core/agent-moe.js +2 -10
- package/dist/core/agent.js +273 -82
- package/dist/core/bootstrap.js +80 -13
- package/dist/core/index.js +2 -2
- package/dist/core/prompt-builder.js +23 -2
- package/dist/core/session-logger.js +46 -4
- package/dist/core/version.js +24 -0
- package/dist/i18n/en.json +75 -2
- package/dist/i18n/ru.json +74 -1
- package/dist/index.js +1 -1
- package/dist/llm/image-utils.js +4 -5
- package/dist/llm/index.js +4 -4
- package/dist/llm/model-loader.js +6 -6
- package/dist/llm/openai-compat.js +40 -34
- package/dist/llm/orchestrator.js +33 -29
- package/dist/llm/response.js +9 -9
- package/dist/logger/app-logger.js +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/main.js +1111 -954
- package/dist/migration/backup.js +13 -13
- package/dist/migration/detect.js +11 -11
- package/dist/migration/index.js +2 -2
- package/dist/modules/artifacts/store.js +61 -0
- package/dist/modules/browser/actions.js +34 -4
- package/dist/modules/browser/bridge-client.js +199 -0
- package/dist/modules/browser/bridge-path.js +10 -0
- package/dist/modules/browser/bridge-server.mjs +202 -202
- package/dist/modules/browser/cookie-store.js +6 -6
- package/dist/modules/browser/driver.js +136 -0
- package/dist/modules/browser/index.js +7 -5
- package/dist/modules/browser/module.js +8 -7
- package/dist/modules/browser/session.js +87 -84
- package/dist/modules/browser/snapshot.js +92 -58
- package/dist/modules/browser/types.js +4 -1
- package/dist/modules/certification/cli.js +2 -4
- package/dist/modules/certification/fact-checker.js +1 -3
- package/dist/modules/certification/loader.js +3 -9
- package/dist/modules/certification/runner.js +1 -4
- package/dist/modules/context/chunk-query.js +100 -0
- package/dist/modules/context/fact-extractor.js +162 -0
- package/dist/modules/context/history.js +15 -0
- package/dist/modules/context/index.js +1 -1
- package/dist/modules/context/manager.js +160 -86
- package/dist/modules/execution/audit-runners.js +152 -0
- package/dist/modules/execution/auditor.js +177 -25
- package/dist/modules/execution/execution-plugin.js +272 -0
- package/dist/modules/execution/module.js +201 -544
- package/dist/modules/execution/moe-executor.js +25 -0
- package/dist/modules/execution/plan-store.js +1 -3
- package/dist/modules/execution/plan-tool.js +508 -0
- package/dist/modules/execution/plan-validator.js +10 -10
- package/dist/modules/execution/planner.js +6 -1
- package/dist/modules/execution/stuck-detector.js +173 -10
- package/dist/modules/execution/verifier.js +86 -42
- package/dist/modules/execution/windows-commands.js +41 -0
- package/dist/modules/hallucination/confidence.js +8 -1
- package/dist/modules/hallucination/detector.js +2 -5
- package/dist/modules/hallucination/factual.js +3 -64
- package/dist/modules/hallucination/index.js +1 -1
- package/dist/modules/hallucination/js-identifiers.js +190 -0
- package/dist/modules/hallucination/llm-judge.js +1 -3
- package/dist/modules/indexer/cache.js +9 -7
- package/dist/modules/indexer/index.js +3 -3
- package/dist/modules/indexer/module.js +95 -42
- package/dist/modules/indexer/project-profile.js +183 -0
- package/dist/modules/indexer/walker.js +17 -17
- package/dist/modules/lsp/check-tool.js +58 -0
- package/dist/modules/lsp/client.js +74 -31
- package/dist/modules/lsp/command.js +60 -0
- package/dist/modules/lsp/config.js +87 -33
- package/dist/modules/lsp/index.js +3 -3
- package/dist/modules/lsp/module.js +185 -21
- package/dist/modules/lsp/probe.js +76 -0
- package/dist/modules/lsp/project-root.js +32 -0
- package/dist/modules/lsp/startup-check.js +141 -0
- package/dist/modules/mcp/module.js +2 -6
- package/dist/modules/memory/index.js +1 -1
- package/dist/modules/memory/module.js +71 -23
- package/dist/modules/memory/search.js +11 -9
- package/dist/modules/memory/store.js +13 -13
- package/dist/modules/pipelines/engine.js +10 -10
- package/dist/modules/pipelines/index.js +3 -3
- package/dist/modules/pipelines/parser.js +17 -14
- package/dist/modules/pipelines/template.js +1 -1
- package/dist/modules/plugins/builtin/lint-on-write.js +21 -16
- package/dist/modules/plugins/builtin/notify.js +3 -2
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/loader.js +59 -17
- package/dist/modules/plugins/manager.js +73 -17
- package/dist/modules/processes/detect.js +34 -0
- package/dist/modules/processes/index.js +1 -1
- package/dist/modules/processes/registry.js +135 -46
- package/dist/modules/registry.js +4 -2
- package/dist/modules/security/audit-notifier.js +39 -39
- package/dist/modules/security/command-validator.js +2 -8
- package/dist/modules/security/data-sanitizer.js +1 -9
- package/dist/modules/security/encryption.js +58 -56
- package/dist/modules/security/network-validator.js +1 -9
- package/dist/modules/security/path-validator.js +1 -3
- package/dist/modules/security/security-policies.js +3 -19
- package/dist/modules/security/session-encryption.js +1 -1
- package/dist/modules/security/session-isolation.js +8 -8
- package/dist/modules/session/index.js +3 -3
- package/dist/modules/session/module.js +5 -5
- package/dist/modules/session/store.js +3 -9
- package/dist/modules/skills/matcher.js +27 -0
- package/dist/modules/skills/module.js +1 -2
- package/dist/modules/updater/checker.js +70 -6
- package/dist/modules/updater/index.js +2 -1
- package/dist/modules/updater/module.js +116 -0
- package/dist/modules/user-profile/compressor.js +2 -2
- package/dist/modules/user-profile/index.js +1 -1
- package/dist/modules/user-profile/profile.js +9 -9
- package/dist/tools/attach-image.js +1 -1
- package/dist/tools/bash.js +178 -19
- package/dist/tools/browser.js +46 -29
- package/dist/tools/chunk-query.js +99 -0
- package/dist/tools/download-file.js +116 -0
- package/dist/tools/enable-tools.js +58 -0
- package/dist/tools/executor.js +4 -5
- package/dist/tools/file-info.js +13 -12
- package/dist/tools/filter-tools.js +9 -2
- package/dist/tools/glob-tool.js +11 -11
- package/dist/tools/grep-tool.js +1 -3
- package/dist/tools/hidden-tools-block.js +37 -0
- package/dist/tools/index.js +13 -2
- package/dist/tools/list-dir.js +18 -17
- package/dist/tools/load-skill.js +1 -3
- package/dist/tools/path-utils.js +4 -4
- package/dist/tools/pipeline-run.js +25 -25
- package/dist/tools/process-kill.js +11 -11
- package/dist/tools/process-list.js +20 -22
- package/dist/tools/process-log.js +22 -18
- package/dist/tools/question.js +1 -3
- package/dist/tools/read-file.js +10 -2
- package/dist/tools/recall.js +44 -37
- package/dist/tools/registry.js +15 -4
- package/dist/tools/remember.js +29 -29
- package/dist/tools/scope-check.js +9 -9
- package/dist/tools/subagent.js +54 -9
- package/dist/tools/user-input.js +1 -1
- package/dist/tools/web-browse.js +3 -3
- package/dist/tools/web-fetch.js +3 -3
- package/dist/tools/web-search.js +3 -3
- package/dist/tools/write-file.js +1 -3
- package/dist/ui/box.js +1 -5
- package/dist/ui/index.js +6 -6
- package/dist/ui/line-editor.js +703 -0
- package/dist/ui/line-math.js +69 -0
- package/dist/ui/md-formatter.js +33 -33
- package/dist/ui/output.js +5 -5
- package/dist/ui/plan-view.js +103 -0
- package/dist/ui/renderer.js +15 -10
- package/dist/ui/table.js +1 -1
- package/package.json +48 -48
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import stringWidth from "string-width";
|
|
2
|
+
const ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
3
|
+
export function stripAnsi(s) {
|
|
4
|
+
return s.replace(ANSI_RE, "");
|
|
5
|
+
}
|
|
6
|
+
export function charLen(s) {
|
|
7
|
+
return Array.from(s).length;
|
|
8
|
+
}
|
|
9
|
+
export function wrapLine(line, width) {
|
|
10
|
+
const w = width > 0 ? width : 80;
|
|
11
|
+
const chars = Array.from(line);
|
|
12
|
+
const rows = [];
|
|
13
|
+
let start = 0;
|
|
14
|
+
let cells = 0;
|
|
15
|
+
for (let i = 0; i < chars.length; i++) {
|
|
16
|
+
const ch = chars[i];
|
|
17
|
+
if (ch === "\n") {
|
|
18
|
+
rows.push({ text: chars.slice(start, i).join(""), charStart: start });
|
|
19
|
+
start = i + 1;
|
|
20
|
+
cells = 0;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const cw = stringWidth(ch);
|
|
24
|
+
if (cells + cw > w && cells > 0) {
|
|
25
|
+
rows.push({ text: chars.slice(start, i).join(""), charStart: start });
|
|
26
|
+
start = i;
|
|
27
|
+
cells = cw;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
cells += cw;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
rows.push({ text: chars.slice(start).join(""), charStart: start });
|
|
34
|
+
return rows;
|
|
35
|
+
}
|
|
36
|
+
export function buildLayout(lines, width) {
|
|
37
|
+
const rows = [];
|
|
38
|
+
for (let b = 0; b < lines.length; b++) {
|
|
39
|
+
for (const r of wrapLine(lines[b], width)) {
|
|
40
|
+
rows.push({ bufRow: b, charStart: r.charStart, text: r.text });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return rows;
|
|
44
|
+
}
|
|
45
|
+
export function layoutIndexFor(rows, bufRow, col) {
|
|
46
|
+
let idx = 0;
|
|
47
|
+
for (let i = 0; i < rows.length; i++) {
|
|
48
|
+
if (rows[i].bufRow === bufRow && rows[i].charStart <= col)
|
|
49
|
+
idx = i;
|
|
50
|
+
}
|
|
51
|
+
return idx;
|
|
52
|
+
}
|
|
53
|
+
export function visualColAt(rows, idx, col) {
|
|
54
|
+
const r = rows[idx];
|
|
55
|
+
const upTo = col - r.charStart;
|
|
56
|
+
return stringWidth(Array.from(r.text).slice(0, upTo).join(""));
|
|
57
|
+
}
|
|
58
|
+
export function charOffsetFor(rows, idx, visualCol) {
|
|
59
|
+
const r = rows[idx];
|
|
60
|
+
const chars = Array.from(r.text);
|
|
61
|
+
let cells = 0;
|
|
62
|
+
for (let i = 0; i < chars.length; i++) {
|
|
63
|
+
const cw = stringWidth(chars[i]);
|
|
64
|
+
if (cells + cw > visualCol)
|
|
65
|
+
return r.charStart + i;
|
|
66
|
+
cells += cw;
|
|
67
|
+
}
|
|
68
|
+
return r.charStart + chars.length;
|
|
69
|
+
}
|
package/dist/ui/md-formatter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { pc } from
|
|
2
|
-
import { t } from
|
|
3
|
-
import { formatTable, getTerminalWidth } from
|
|
1
|
+
import { pc } from "./colors";
|
|
2
|
+
import { t } from "../i18n/index";
|
|
3
|
+
import { formatTable, getTerminalWidth } from "./table";
|
|
4
4
|
const KW = /\b(import|export|from|const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|new|class|extends|implements|interface|type|enum|namespace|module|declare|abstract|async|await|yield|throw|try|catch|finally|typeof|instanceof|in|of|as|is|keyof|readonly|static|private|public|protected|get|set|constructor|this|super|void|never|any|unknown|boolean|string|number|symbol|object|true|false|null|undefined|default)\b/g;
|
|
5
5
|
const STRING = /('[^']*'|"[^"]*"|`[^`]*`)/g;
|
|
6
6
|
const COMMENT = /(\/\/[^\n]*|\/\*[\s\S]*?\*\/|#[^\n]*)/g;
|
|
@@ -8,21 +8,21 @@ const NUMBER = /\b(\d+\.?\d*)\b/g;
|
|
|
8
8
|
const TAG = /<\/?([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9-]*)/g;
|
|
9
9
|
const ATTR = /\b([a-zA-Z-]+=)"([^"]*)"/g;
|
|
10
10
|
function highlight(code, lang) {
|
|
11
|
-
if (lang ===
|
|
11
|
+
if (lang === "html" || lang === "xml" || lang === "svg") {
|
|
12
12
|
code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
|
|
13
|
-
code = code.replace(ATTR, (_m, attr, val) => pc.yellow(attr) +
|
|
14
|
-
code = code.replace(TAG, (_m, tag) =>
|
|
13
|
+
code = code.replace(ATTR, (_m, attr, val) => pc.yellow(attr) + "=" + pc.green('"' + val + '"'));
|
|
14
|
+
code = code.replace(TAG, (_m, tag) => "<" + pc.cyan(tag));
|
|
15
15
|
}
|
|
16
|
-
else if (lang ===
|
|
16
|
+
else if (lang === "css" || lang === "scss" || lang === "less") {
|
|
17
17
|
code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
|
|
18
18
|
code = code.replace(STRING, (m) => pc.green(m));
|
|
19
19
|
code = code.replace(NUMBER, (m) => pc.yellow(m));
|
|
20
20
|
}
|
|
21
|
-
else if (lang ===
|
|
21
|
+
else if (lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh") {
|
|
22
22
|
code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
|
|
23
23
|
code = code.replace(STRING, (m) => pc.green(m));
|
|
24
24
|
}
|
|
25
|
-
else if (lang ===
|
|
25
|
+
else if (lang === "json") {
|
|
26
26
|
code = code.replace(STRING, (m) => pc.green(m));
|
|
27
27
|
code = code.replace(NUMBER, (m) => pc.yellow(m));
|
|
28
28
|
}
|
|
@@ -37,7 +37,7 @@ function highlight(code, lang) {
|
|
|
37
37
|
}
|
|
38
38
|
function isTableRow(line) {
|
|
39
39
|
const trimmed = line.trim();
|
|
40
|
-
if (!trimmed.startsWith(
|
|
40
|
+
if (!trimmed.startsWith("|"))
|
|
41
41
|
return false;
|
|
42
42
|
const pipes = trimmed.match(/\|/g);
|
|
43
43
|
return (pipes?.length ?? 0) >= 2;
|
|
@@ -46,9 +46,9 @@ function isHorizontalRule(line) {
|
|
|
46
46
|
return /^(-{3,}|\*{3,}|_{3,})\s*$/.test(line.trim());
|
|
47
47
|
}
|
|
48
48
|
export class FormattingStream {
|
|
49
|
-
buffer =
|
|
49
|
+
buffer = "";
|
|
50
50
|
inCodeBlock = false;
|
|
51
|
-
codeLang =
|
|
51
|
+
codeLang = "";
|
|
52
52
|
codeLines = [];
|
|
53
53
|
tableBuffer = [];
|
|
54
54
|
onWrite;
|
|
@@ -60,7 +60,7 @@ export class FormattingStream {
|
|
|
60
60
|
write(chunk) {
|
|
61
61
|
this.buffer += chunk;
|
|
62
62
|
let idx;
|
|
63
|
-
while ((idx = this.buffer.indexOf(
|
|
63
|
+
while ((idx = this.buffer.indexOf("\n")) !== -1) {
|
|
64
64
|
const line = this.buffer.slice(0, idx);
|
|
65
65
|
this.buffer = this.buffer.slice(idx + 1);
|
|
66
66
|
this.processLine(line);
|
|
@@ -75,8 +75,8 @@ export class FormattingStream {
|
|
|
75
75
|
}
|
|
76
76
|
if (this.buffer.length > 0) {
|
|
77
77
|
const line = this.buffer;
|
|
78
|
-
this.buffer =
|
|
79
|
-
if (line.trim() ===
|
|
78
|
+
this.buffer = "";
|
|
79
|
+
if (line.trim() === "```" || line.trim().startsWith("```")) {
|
|
80
80
|
if (this.codeLines.length > 0) {
|
|
81
81
|
this.emitCodeBlock();
|
|
82
82
|
}
|
|
@@ -86,7 +86,7 @@ export class FormattingStream {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
processLine(line) {
|
|
89
|
-
if (line.trim() ===
|
|
89
|
+
if (line.trim() === "```" || line.trim().startsWith("```")) {
|
|
90
90
|
if (this.inCodeBlock) {
|
|
91
91
|
this.emitCodeBlock();
|
|
92
92
|
}
|
|
@@ -128,18 +128,18 @@ export class FormattingStream {
|
|
|
128
128
|
emitCodeBlock() {
|
|
129
129
|
this.inCodeBlock = false;
|
|
130
130
|
if (this.codeLines.length > 0) {
|
|
131
|
-
const code = this.codeLines.join(
|
|
131
|
+
const code = this.codeLines.join("\n");
|
|
132
132
|
const highlighted = highlight(code, this.codeLang);
|
|
133
|
-
const lang = this.codeLang ? ` ${this.codeLang} ` :
|
|
134
|
-
const top = pc.dim(`┌─${lang}${
|
|
133
|
+
const lang = this.codeLang ? ` ${this.codeLang} ` : " ";
|
|
134
|
+
const top = pc.dim(`┌─${lang}${"─".repeat(Math.max(0, this.width - 3 - lang.length))}┐`);
|
|
135
135
|
this.onWrite(top);
|
|
136
|
-
for (const l of highlighted.split(
|
|
137
|
-
this.onWrite(pc.dim(
|
|
136
|
+
for (const l of highlighted.split("\n")) {
|
|
137
|
+
this.onWrite(pc.dim("│ ") + l);
|
|
138
138
|
}
|
|
139
|
-
this.onWrite(pc.dim(`└${
|
|
139
|
+
this.onWrite(pc.dim(`└${"─".repeat(Math.max(0, this.width - 1))}┘`));
|
|
140
140
|
}
|
|
141
141
|
this.codeLines = [];
|
|
142
|
-
this.codeLang =
|
|
142
|
+
this.codeLang = "";
|
|
143
143
|
}
|
|
144
144
|
formatLine(line) {
|
|
145
145
|
let result = line;
|
|
@@ -152,18 +152,18 @@ export class FormattingStream {
|
|
|
152
152
|
return pc.cyan(pc.bold(content));
|
|
153
153
|
}
|
|
154
154
|
if (isHorizontalRule(result)) {
|
|
155
|
-
return pc.dim(
|
|
155
|
+
return pc.dim("─".repeat(Math.max(0, Math.min(this.width, 60))));
|
|
156
156
|
}
|
|
157
157
|
const quote = result.match(/^(>+)\s?(.*)$/);
|
|
158
158
|
if (quote) {
|
|
159
159
|
const depth = Math.min(quote[1].length, 4);
|
|
160
|
-
const marker = pc.dim(
|
|
160
|
+
const marker = pc.dim("▍".repeat(depth));
|
|
161
161
|
return `${marker} ${this.formatInline(quote[2])}`;
|
|
162
162
|
}
|
|
163
163
|
const checkbox = result.match(/^[-*]\s+\[([ xX])\]\s+(.+)$/);
|
|
164
164
|
if (checkbox) {
|
|
165
|
-
const checked = checkbox[1].toLowerCase() ===
|
|
166
|
-
const mark = checked ? pc.green(
|
|
165
|
+
const checked = checkbox[1].toLowerCase() === "x";
|
|
166
|
+
const mark = checked ? pc.green("✓") : pc.dim("☐");
|
|
167
167
|
return ` ${mark} ${this.formatInline(checkbox[2])}`;
|
|
168
168
|
}
|
|
169
169
|
const ordered = result.match(/^(\d+)[.)]\s+(.+)$/);
|
|
@@ -172,7 +172,7 @@ export class FormattingStream {
|
|
|
172
172
|
}
|
|
173
173
|
const bullet = result.match(/^[-*]\s+(.+)$/);
|
|
174
174
|
if (bullet) {
|
|
175
|
-
return ` ${pc.dim(
|
|
175
|
+
return ` ${pc.dim("•")} ${this.formatInline(bullet[1])}`;
|
|
176
176
|
}
|
|
177
177
|
return this.formatInline(result);
|
|
178
178
|
}
|
|
@@ -187,7 +187,7 @@ export class FormattingStream {
|
|
|
187
187
|
result = result.replace(/\*([^*]+)\*/g, (_, s) => pc.italic(s));
|
|
188
188
|
result = result.replace(/(^|\s)_([^_\n]+)_(?=\s|$)/g, (_m, pre, s) => pre + pc.italic(s));
|
|
189
189
|
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) => {
|
|
190
|
-
const short = url.length > 80 ? url.slice(0, 77) +
|
|
190
|
+
const short = url.length > 80 ? url.slice(0, 77) + "…" : url;
|
|
191
191
|
return `${pc.cyan(label)} ${pc.dim(`(${short})`)}`;
|
|
192
192
|
});
|
|
193
193
|
result = result.replace(/\u0000(\d+)\u0000/g, (_m, i) => codeSpans[Number(i)]);
|
|
@@ -199,14 +199,14 @@ export function formatMarkdown(text) {
|
|
|
199
199
|
const stream = new FormattingStream((l) => lines.push(l));
|
|
200
200
|
stream.write(text);
|
|
201
201
|
stream.flush();
|
|
202
|
-
return lines.join(
|
|
202
|
+
return lines.join("\n");
|
|
203
203
|
}
|
|
204
204
|
export function formatError(text) {
|
|
205
|
-
return pc.red(pc.bold(t(
|
|
205
|
+
return pc.red(pc.bold(t("ui.error_prefix")) + text);
|
|
206
206
|
}
|
|
207
207
|
export function formatSuccess(text) {
|
|
208
|
-
return pc.green(pc.bold(t(
|
|
208
|
+
return pc.green(pc.bold(t("ui.success_prefix")) + text);
|
|
209
209
|
}
|
|
210
210
|
export function formatWarning(text) {
|
|
211
|
-
return pc.yellow(pc.bold(t(
|
|
211
|
+
return pc.yellow(pc.bold(t("ui.warning_prefix")) + text);
|
|
212
212
|
}
|
package/dist/ui/output.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { formatMarkdown, formatError, formatSuccess, formatWarning } from
|
|
1
|
+
import { formatMarkdown, formatError, formatSuccess, formatWarning } from "./md-formatter";
|
|
2
2
|
export function writeOutput(text) {
|
|
3
|
-
process.stdout.write(formatMarkdown(text) +
|
|
3
|
+
process.stdout.write(formatMarkdown(text) + "\n");
|
|
4
4
|
}
|
|
5
5
|
export function writeError(text) {
|
|
6
|
-
process.stderr.write(formatError(text) +
|
|
6
|
+
process.stderr.write(formatError(text) + "\n");
|
|
7
7
|
}
|
|
8
8
|
export function writeSuccess(text) {
|
|
9
|
-
process.stdout.write(formatSuccess(text) +
|
|
9
|
+
process.stdout.write(formatSuccess(text) + "\n");
|
|
10
10
|
}
|
|
11
11
|
export function writeWarning(text) {
|
|
12
|
-
process.stdout.write(formatWarning(text) +
|
|
12
|
+
process.stdout.write(formatWarning(text) + "\n");
|
|
13
13
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { pc } from "./colors";
|
|
4
|
+
import { extractFileLikeTokens, stripUrls } from "../modules/hallucination/js-identifiers";
|
|
5
|
+
import { t } from "../i18n/index";
|
|
6
|
+
export function readActivePlan(baseDir) {
|
|
7
|
+
const p = join(baseDir, ".mma", "plans", "active.json");
|
|
8
|
+
if (!existsSync(p))
|
|
9
|
+
return null;
|
|
10
|
+
try {
|
|
11
|
+
const raw = readFileSync(p, "utf-8");
|
|
12
|
+
if (!raw.trim())
|
|
13
|
+
return null;
|
|
14
|
+
const parsed = JSON.parse(raw);
|
|
15
|
+
if (!parsed || !Array.isArray(parsed.steps))
|
|
16
|
+
return null;
|
|
17
|
+
return {
|
|
18
|
+
id: parsed.id || "plan",
|
|
19
|
+
title: parsed.title || "Plan",
|
|
20
|
+
steps: parsed.steps,
|
|
21
|
+
createdAt: parsed.createdAt || new Date().toISOString(),
|
|
22
|
+
baseDir: parsed.baseDir || baseDir,
|
|
23
|
+
name: parsed.name,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function currentStepIndex(plan) {
|
|
31
|
+
const idx = plan.steps.findIndex((s) => s.status !== "done" && s.status !== "skipped");
|
|
32
|
+
return idx === -1 ? 0 : idx;
|
|
33
|
+
}
|
|
34
|
+
function stepMark(step) {
|
|
35
|
+
switch (step.status) {
|
|
36
|
+
case "done":
|
|
37
|
+
return pc.green("[x]");
|
|
38
|
+
case "in_progress":
|
|
39
|
+
return pc.yellow("[*]");
|
|
40
|
+
case "failed":
|
|
41
|
+
return pc.red("[!]");
|
|
42
|
+
case "skipped":
|
|
43
|
+
return pc.dim("[-]");
|
|
44
|
+
default:
|
|
45
|
+
return pc.dim("[ ]");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function formatPlanChecklist(plan) {
|
|
49
|
+
const done = plan.steps.filter((s) => s.status === "done" || s.status === "skipped").length;
|
|
50
|
+
const total = plan.steps.length;
|
|
51
|
+
const pct = total === 0 ? 0 : Math.round((done / total) * 100);
|
|
52
|
+
const cur = currentStepIndex(plan);
|
|
53
|
+
const barLen = 15;
|
|
54
|
+
const filled = Math.round((pct / 100) * barLen);
|
|
55
|
+
const bar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
|
|
56
|
+
const title = plan.title.replace(/^\[\d+[^]]*\]\s*/, "");
|
|
57
|
+
const lines = [
|
|
58
|
+
`${pc.cyan(`[${plan.id}]`)} ${pc.bold(title)} ${bar} ${pc.dim(`${done}/${total} ${pct}%`)}`,
|
|
59
|
+
];
|
|
60
|
+
for (let i = 0; i < plan.steps.length; i++) {
|
|
61
|
+
const step = plan.steps[i];
|
|
62
|
+
const active = i === cur;
|
|
63
|
+
const desc = active ? pc.yellow(step.description) : pc.dim(step.description);
|
|
64
|
+
lines.push(` ${stepMark(step)} ${step.id}. ${desc}`);
|
|
65
|
+
for (const sub of step.subtasks ?? []) {
|
|
66
|
+
lines.push(` ${sub.done ? pc.green("[x]") : pc.dim("[ ]")} ${sub.text}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return lines;
|
|
70
|
+
}
|
|
71
|
+
const STRUCTURAL_TOOLS = new Set([
|
|
72
|
+
"plan",
|
|
73
|
+
"todo",
|
|
74
|
+
"verify",
|
|
75
|
+
"project_map",
|
|
76
|
+
"lsp_check",
|
|
77
|
+
"enable_tools",
|
|
78
|
+
]);
|
|
79
|
+
function truncate(s, max = 48) {
|
|
80
|
+
return s.length > max ? `${s.slice(0, max - 1)}…` : s;
|
|
81
|
+
}
|
|
82
|
+
export function stepContextForTool(plan, tool, args) {
|
|
83
|
+
if (!plan || STRUCTURAL_TOOLS.has(tool))
|
|
84
|
+
return null;
|
|
85
|
+
const argStr = JSON.stringify(args);
|
|
86
|
+
const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
|
|
87
|
+
if (callPaths.length > 0) {
|
|
88
|
+
for (const step of plan.steps) {
|
|
89
|
+
if (step.status === "done" || step.status === "skipped")
|
|
90
|
+
continue;
|
|
91
|
+
const stepPaths = extractFileLikeTokens(stripUrls(step.description)).map((p) => p.toLowerCase());
|
|
92
|
+
if (stepPaths.length > 0 &&
|
|
93
|
+
stepPaths.some((s) => callPaths.some((c) => c.includes(s) || s.includes(c)))) {
|
|
94
|
+
return t("ui.step_context", { id: step.id, desc: truncate(step.description) });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const cur = currentStepIndex(plan);
|
|
99
|
+
const step = plan.steps[cur];
|
|
100
|
+
if (!step)
|
|
101
|
+
return null;
|
|
102
|
+
return t("ui.step_context", { id: step.id, desc: truncate(step.description) });
|
|
103
|
+
}
|
package/dist/ui/renderer.js
CHANGED
|
@@ -118,29 +118,36 @@ export class Renderer {
|
|
|
118
118
|
thinkingEnd() {
|
|
119
119
|
this.spinner.stop();
|
|
120
120
|
}
|
|
121
|
-
toolStart(tool, args) {
|
|
121
|
+
toolStart(tool, args, stepContext) {
|
|
122
122
|
this.endCard();
|
|
123
123
|
this.spinner.stop();
|
|
124
124
|
const summary = summarizeArgs(args);
|
|
125
|
+
const step = stepContext ? ` ${pc.cyan(`← ${stepContext}`)}` : "";
|
|
125
126
|
if (!this.rich) {
|
|
126
|
-
this.out.write(`\n${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}\n`);
|
|
127
|
+
this.out.write(`\n${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}${step}\n`);
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
this.card = { tool, args, body: [], start: Date.now() };
|
|
130
131
|
if (this.toolStyle === "inline") {
|
|
131
132
|
const marker = toolMarker(tool);
|
|
132
|
-
this.out.write(`\n${pc.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}\n`);
|
|
133
|
+
this.out.write(`\n${pc.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}${step}\n`);
|
|
133
134
|
return;
|
|
134
135
|
}
|
|
135
|
-
this.spinner.start(`${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}`);
|
|
136
|
+
this.spinner.start(`${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}${step}`);
|
|
137
|
+
}
|
|
138
|
+
/** Live plan checklist — prints the plan block as-is (already colored). */
|
|
139
|
+
planBlock(lines) {
|
|
140
|
+
this.endCard();
|
|
141
|
+
this.spinner.stop();
|
|
142
|
+
for (const line of lines) {
|
|
143
|
+
this.out.write(`${line}\n`);
|
|
144
|
+
}
|
|
136
145
|
}
|
|
137
146
|
toolEnd(_tool, duration, error, ctxDelta) {
|
|
138
147
|
this.spinner.stop();
|
|
139
148
|
if (!this.rich) {
|
|
140
149
|
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
141
|
-
const deltaStr = ctxDelta > 0
|
|
142
|
-
? pc.green(`+${ctxDelta}`)
|
|
143
|
-
: pc.yellow(`${ctxDelta} ↓`);
|
|
150
|
+
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
144
151
|
this.out.write(`${pc.dim("ctx")} ${deltaStr}\n`);
|
|
145
152
|
}
|
|
146
153
|
return;
|
|
@@ -151,9 +158,7 @@ export class Renderer {
|
|
|
151
158
|
const marker = error ? pc.red("✗") : pc.green("✓");
|
|
152
159
|
let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
|
|
153
160
|
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
154
|
-
const deltaStr = ctxDelta > 0
|
|
155
|
-
? pc.green(`+${ctxDelta}`)
|
|
156
|
-
: pc.yellow(`${ctxDelta} ↓`);
|
|
161
|
+
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
157
162
|
footer += ` ${pc.dim("ctx")} ${deltaStr}`;
|
|
158
163
|
}
|
|
159
164
|
if (this.toolStyle === "inline") {
|
package/dist/ui/table.js
CHANGED
|
@@ -106,7 +106,7 @@ export function formatTable(tableLines, opts = {}) {
|
|
|
106
106
|
for (let c = 0; c < columnCount; c++) {
|
|
107
107
|
const raw = row[c] ?? "";
|
|
108
108
|
const cell = truncate(raw, widths[c]);
|
|
109
|
-
const a = isHeader && align[c] === undefined ? "center" : align[c] ?? "left";
|
|
109
|
+
const a = isHeader && align[c] === undefined ? "center" : (align[c] ?? "left");
|
|
110
110
|
cells.push(pad(cell, widths[c], a));
|
|
111
111
|
}
|
|
112
112
|
const content = cells.map((c) => pc.dim("│ ") + c).join("") + pc.dim("│");
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "micro-models-agent",
|
|
3
|
-
"version": "0.41.
|
|
4
|
-
"description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"mma": "bin/mma.mjs"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/",
|
|
11
|
-
"bin/"
|
|
12
|
-
],
|
|
13
|
-
"engines": {
|
|
14
|
-
"node": ">=20"
|
|
15
|
-
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"mma": "bun run src/cli/main.ts",
|
|
18
|
-
"build": "bun run build:tsc && bun run build:copy-assets",
|
|
19
|
-
"build:tsc": "tsc -p tsconfig.build.json",
|
|
20
|
-
"build:copy-assets": "bun run scripts/copy-assets.ts",
|
|
21
|
-
"build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
|
|
22
|
-
"build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
|
|
23
|
-
"build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
|
|
24
|
-
"dev": "bun --watch src/cli/main.ts",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
26
|
-
"test": "bun test",
|
|
27
|
-
"test:watch": "bun test --watch",
|
|
28
|
-
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
29
|
-
"format": "prettier --write \"src/**/*.{ts,js,mjs,json}\" \"tests/**/*.{ts,js,json}\" \"scripts/**/*.ts\" \"*.{ts,json}\"",
|
|
30
|
-
"format:check": "prettier --check \"src/**/*.{ts,js,mjs,json}\" \"tests/**/*.{ts,js,json}\" \"scripts/**/*.ts\" \"*.{ts,json}\""
|
|
31
|
-
},
|
|
32
|
-
"dependencies": {
|
|
33
|
-
"commander": "^12.0.0",
|
|
34
|
-
"js-tiktoken": "^1.0.0",
|
|
35
|
-
"jsonrepair": "^3.15.0",
|
|
36
|
-
"picocolors": "^1.1.1",
|
|
37
|
-
"playwright": "^1.62.0",
|
|
38
|
-
"string-width": "^8.2.2",
|
|
39
|
-
"yaml": "^2.9.0"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@types/bun": "^1.3.14",
|
|
43
|
-
"@types/node": "^22.20.1",
|
|
44
|
-
"prettier": "^3.9.6",
|
|
45
|
-
"typescript": "^5.9.3",
|
|
46
|
-
"vitest": "^4.1.10"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "micro-models-agent",
|
|
3
|
+
"version": "0.41.2",
|
|
4
|
+
"description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mma": "bin/mma.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"bin/"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"mma": "bun run src/cli/main.ts",
|
|
18
|
+
"build": "bun run build:tsc && bun run build:copy-assets",
|
|
19
|
+
"build:tsc": "tsc -p tsconfig.build.json",
|
|
20
|
+
"build:copy-assets": "bun run scripts/copy-assets.ts",
|
|
21
|
+
"build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
|
|
22
|
+
"build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
|
|
23
|
+
"build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
|
|
24
|
+
"dev": "bun --watch src/cli/main.ts",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"test:watch": "bun test --watch",
|
|
28
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
29
|
+
"format": "prettier --write \"src/**/*.{ts,js,mjs,json}\" \"tests/**/*.{ts,js,json}\" \"scripts/**/*.ts\" \"*.{ts,json}\"",
|
|
30
|
+
"format:check": "prettier --check \"src/**/*.{ts,js,mjs,json}\" \"tests/**/*.{ts,js,json}\" \"scripts/**/*.ts\" \"*.{ts,json}\""
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"commander": "^12.0.0",
|
|
34
|
+
"js-tiktoken": "^1.0.0",
|
|
35
|
+
"jsonrepair": "^3.15.0",
|
|
36
|
+
"picocolors": "^1.1.1",
|
|
37
|
+
"playwright": "^1.62.0",
|
|
38
|
+
"string-width": "^8.2.2",
|
|
39
|
+
"yaml": "^2.9.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/bun": "^1.3.14",
|
|
43
|
+
"@types/node": "^22.20.1",
|
|
44
|
+
"prettier": "^3.9.6",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"vitest": "^4.1.10"
|
|
47
|
+
}
|
|
48
|
+
}
|