mocode-ai 1.3.9 → 1.4.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.
- package/README.md +78 -70
- package/README.zh-CN.md +81 -73
- package/bin/mocode-agent-host.js +1 -1
- package/dist/agent/core.js +226 -293
- package/dist/agent/index.js +14 -10
- package/dist/agent/mode.js +3 -3
- package/dist/agent/runtime-context.js +45 -0
- package/dist/agent/spawn.js +101 -86
- package/dist/agent/tool-helpers.js +134 -0
- package/dist/agent/trace-state.js +118 -0
- package/dist/agents/coordinator.js +6 -1
- package/dist/changeset/index.js +9 -8
- package/dist/config/index.js +109 -77
- package/dist/config/presets.js +3 -1
- package/dist/config/profiles.js +125 -0
- package/dist/context/age-aware.js +2 -4
- package/dist/context/artifacts.js +6 -13
- package/dist/context/budget.js +6 -8
- package/dist/context/classifier.js +1 -2
- package/dist/context/encoders/code.js +2 -6
- package/dist/context/encoders/command.js +1 -3
- package/dist/context/encoders/search.js +1 -3
- package/dist/context/index.js +1 -1
- package/dist/context/lifecycle.js +5 -3
- package/dist/context/pipeline.js +1 -1
- package/dist/context/relevance.js +2 -4
- package/dist/context/token-calibration.js +13 -18
- package/dist/host/stdio.js +73 -12
- package/dist/i18n/index.js +96 -44
- package/dist/index.js +1 -1
- package/dist/llm/index.js +39 -23
- package/dist/llm/provider.js +23 -0
- package/dist/llm/providers/anthropic.js +12 -18
- package/dist/llm/tool-schema.js +48 -0
- package/dist/mcp/client.js +70 -25
- package/dist/mcp/config.js +1 -3
- package/dist/mcp/index.js +3 -1
- package/dist/memory/reflect.js +3 -6
- package/dist/memory/store.js +10 -12
- package/dist/permissions/index.js +66 -22
- package/dist/pet/bridge.js +2 -2
- package/dist/repl/commands/appearance.js +72 -0
- package/dist/repl/commands/compact.js +114 -0
- package/dist/repl/commands/context.js +17 -0
- package/dist/repl/commands/image.js +71 -0
- package/dist/repl/commands/memory.js +51 -0
- package/dist/repl/commands/mode.js +47 -0
- package/dist/repl/commands/model.js +435 -0
- package/dist/repl/commands/pet.js +70 -0
- package/dist/repl/commands/registry.js +46 -0
- package/dist/repl/commands/session.js +102 -0
- package/dist/repl/commands/skill.js +95 -0
- package/dist/repl/commands/system.js +202 -0
- package/dist/repl/commands/tool-group.js +233 -0
- package/dist/repl/commands/types.js +4 -0
- package/dist/repl/commands.js +324 -0
- package/dist/repl/index.js +5 -2577
- package/dist/repl/message-format.js +151 -0
- package/dist/repl/running-input.js +147 -0
- package/dist/repl/runtime.js +816 -0
- package/dist/repl/status-bar.js +161 -0
- package/dist/rollback/index.js +44 -14
- package/dist/runtime/browser-manager.js +1 -1
- package/dist/runtime/dev-server-manager.js +1 -1
- package/dist/runtime/input-injector.js +313 -0
- package/dist/runtime/screen-capture.js +89 -0
- package/dist/runtime/screen-pipeline.js +223 -0
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/policy.js +8 -2
- package/dist/session/compact.js +22 -34
- package/dist/session/index.js +2 -2
- package/dist/session/notes.js +39 -5
- package/dist/session/persist.js +14 -8
- package/dist/session/scheduler.js +3 -4
- package/dist/session/trace-metrics.js +6 -3
- package/dist/skills/activation.js +10 -5
- package/dist/skills/discover.js +5 -17
- package/dist/skills/index.js +1 -1
- package/dist/skills/runner.js +28 -44
- package/dist/skills/toolmap.js +5 -2
- package/dist/tools/builtins/browser.js +17 -3
- package/dist/tools/builtins/computer.js +322 -0
- package/dist/tools/builtins/dev-server.js +1 -3
- package/dist/tools/builtins/edit-file.js +21 -7
- package/dist/tools/builtins/grep.js +1 -1
- package/dist/tools/builtins/index.js +28 -25
- package/dist/tools/builtins/memory-forget.js +1 -1
- package/dist/tools/builtins/memory-graph.js +4 -7
- package/dist/tools/builtins/memory-list.js +2 -6
- package/dist/tools/builtins/memory-save.js +8 -2
- package/dist/tools/builtins/memory-search.js +4 -4
- package/dist/tools/builtins/note-append.js +14 -3
- package/dist/tools/builtins/plan-update.js +40 -9
- package/dist/tools/builtins/run-command.js +8 -8
- package/dist/tools/builtins/screenshot.js +11 -87
- package/dist/tools/builtins/task.js +29 -40
- package/dist/tools/builtins/use-skill.js +1 -1
- package/dist/tools/builtins/view-image.js +5 -3
- package/dist/tools/builtins/web-fetch.js +1 -3
- package/dist/tools/builtins/web-search.js +3 -7
- package/dist/tools/builtins/write-file.js +4 -2
- package/dist/tools/constants.js +50 -37
- package/dist/tools/policy.js +221 -0
- package/dist/tools/registry.js +40 -19
- package/dist/tools/resource-lock.js +4 -2
- package/dist/tools/router.js +143 -0
- package/dist/tools/validation.js +6 -5
- package/dist/ui/batch.js +63 -23
- package/dist/ui/clipboard.js +17 -5
- package/dist/ui/content.js +166 -13
- package/dist/ui/diff.js +61 -19
- package/dist/ui/fuzzy.js +35 -2
- package/dist/ui/intervention.js +2 -4
- package/dist/ui/layout-internal/content-write.js +587 -0
- package/dist/ui/layout-internal/core.js +590 -0
- package/dist/ui/layout-internal/input-paint.js +365 -0
- package/dist/ui/layout-internal/screen.js +128 -0
- package/dist/ui/layout-internal/scroll.js +152 -0
- package/dist/ui/layout-internal/selection.js +229 -0
- package/dist/ui/layout-internal/state.js +82 -0
- package/dist/ui/layout-internal/statusbar.js +351 -0
- package/dist/ui/layout-types.js +1 -0
- package/dist/ui/layout.js +3 -2288
- package/dist/ui/markdown.js +10 -2
- package/dist/ui/prompt-internal/editor.js +945 -0
- package/dist/ui/prompt-internal/paste.js +52 -0
- package/dist/ui/prompt-internal/pickers.js +519 -0
- package/dist/ui/prompt-internal/types.js +1 -0
- package/dist/ui/prompt.js +4 -1506
- package/dist/ui/render.js +87 -2
- package/dist/verification/affected.js +11 -5
- package/dist/verification/discovery.js +1 -3
- package/dist/verification/profile.js +11 -3
- package/package.json +11 -2
package/dist/ui/render.js
CHANGED
|
@@ -128,6 +128,79 @@ export function visColToCharCol(str, visCol) {
|
|
|
128
128
|
}
|
|
129
129
|
return i;
|
|
130
130
|
}
|
|
131
|
+
function flattenedOffset(lines, point) {
|
|
132
|
+
const line = Math.max(0, Math.min(point.line, Math.max(0, lines.length - 1)));
|
|
133
|
+
let offset = 0;
|
|
134
|
+
for (let i = 0; i < line; i++)
|
|
135
|
+
offset += stripAnsi(lines[i]).length;
|
|
136
|
+
const plain = stripAnsi(lines[line] ?? '');
|
|
137
|
+
return offset + visColToCharCol(plain, point.col);
|
|
138
|
+
}
|
|
139
|
+
function pointAtFlattenedOffset(lines, offset, preferNextAtBoundary) {
|
|
140
|
+
if (lines.length === 0)
|
|
141
|
+
return { line: 0, col: 0 };
|
|
142
|
+
let remaining = Math.max(0, offset);
|
|
143
|
+
for (let line = 0; line < lines.length; line++) {
|
|
144
|
+
const plain = stripAnsi(lines[line]);
|
|
145
|
+
if (remaining < plain.length ||
|
|
146
|
+
(remaining === plain.length && (!preferNextAtBoundary || line === lines.length - 1))) {
|
|
147
|
+
return { line, col: displayWidth(plain.slice(0, remaining)) };
|
|
148
|
+
}
|
|
149
|
+
remaining -= plain.length;
|
|
150
|
+
}
|
|
151
|
+
const last = stripAnsi(lines[lines.length - 1]);
|
|
152
|
+
return { line: lines.length - 1, col: displayWidth(last) };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 同一段文本重新软折行后迁移一个“物理行 + 显示列”端点。
|
|
156
|
+
*
|
|
157
|
+
* 常规段落在去 ANSI、去物理换行后文本完全一致,直接按 UTF-16 边界精确迁移;列表、
|
|
158
|
+
* 引用等可能因续行缩进导致扁平文本不同,此时退化为“非空白字符序号 + 尾随空白数”映射,
|
|
159
|
+
* 使端点仍跟随同一个内容字符,而不是按物理行比例漂移。
|
|
160
|
+
*/
|
|
161
|
+
export function remapWrappedPoint(oldLines, newLines, point) {
|
|
162
|
+
if (newLines.length === 0)
|
|
163
|
+
return { line: 0, col: 0 };
|
|
164
|
+
const oldPlain = oldLines.map(stripAnsi);
|
|
165
|
+
const newPlain = newLines.map(stripAnsi);
|
|
166
|
+
const oldFlat = oldPlain.join('');
|
|
167
|
+
const newFlat = newPlain.join('');
|
|
168
|
+
const oldOffset = flattenedOffset(oldLines, point);
|
|
169
|
+
const preferNext = point.line > 0 && point.col === 0;
|
|
170
|
+
if (oldFlat === newFlat) {
|
|
171
|
+
return pointAtFlattenedOffset(newLines, Math.min(oldOffset, newFlat.length), preferNext);
|
|
172
|
+
}
|
|
173
|
+
const prefix = oldFlat.slice(0, oldOffset);
|
|
174
|
+
let contentChars = 0;
|
|
175
|
+
let trailingWhitespace = 0;
|
|
176
|
+
for (const ch of prefix) {
|
|
177
|
+
if (/\s/u.test(ch))
|
|
178
|
+
trailingWhitespace++;
|
|
179
|
+
else {
|
|
180
|
+
contentChars++;
|
|
181
|
+
trailingWhitespace = 0;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
let seen = 0;
|
|
185
|
+
let mappedOffset = 0;
|
|
186
|
+
while (mappedOffset < newFlat.length && seen < contentChars) {
|
|
187
|
+
const cp = newFlat.codePointAt(mappedOffset) ?? 0;
|
|
188
|
+
const ch = String.fromCodePoint(cp);
|
|
189
|
+
mappedOffset += ch.length;
|
|
190
|
+
if (!/\s/u.test(ch))
|
|
191
|
+
seen++;
|
|
192
|
+
}
|
|
193
|
+
let spaces = 0;
|
|
194
|
+
while (mappedOffset < newFlat.length && spaces < trailingWhitespace) {
|
|
195
|
+
const cp = newFlat.codePointAt(mappedOffset) ?? 0;
|
|
196
|
+
const ch = String.fromCodePoint(cp);
|
|
197
|
+
if (!/\s/u.test(ch))
|
|
198
|
+
break;
|
|
199
|
+
mappedOffset += ch.length;
|
|
200
|
+
spaces++;
|
|
201
|
+
}
|
|
202
|
+
return pointAtFlattenedOffset(newLines, mappedOffset, preferNext);
|
|
203
|
+
}
|
|
131
204
|
/** 带色串的可见显示宽度(先去 ANSI 再按 displayWidth 度量)。 */
|
|
132
205
|
export function ansiDisplayWidth(s) {
|
|
133
206
|
return displayWidth(stripAnsi(s));
|
|
@@ -142,6 +215,19 @@ export function padEndAnsi(str, width) {
|
|
|
142
215
|
const w = ansiDisplayWidth(str);
|
|
143
216
|
return w >= width ? str : str + ' '.repeat(width - w);
|
|
144
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* 用指定背景色把 ANSI 行补到目标宽度。
|
|
220
|
+
*
|
|
221
|
+
* 普通 padEndAnsi 会把空格追加在行末 reset 之后,视觉上仍是终端原底色;这里重新开启
|
|
222
|
+
* background 再补空格,供用户消息气泡在终端放宽后动态延伸到底。原串不改写,避免破坏
|
|
223
|
+
* 行内前景色或已有 reset;补段自身闭合,保证下一行不继承背景。
|
|
224
|
+
*/
|
|
225
|
+
export function padEndAnsiBackground(str, width, background, reset = '\x1B[0m') {
|
|
226
|
+
const w = ansiDisplayWidth(str);
|
|
227
|
+
if (w >= width)
|
|
228
|
+
return str;
|
|
229
|
+
return `${str}${background}${' '.repeat(width - w)}${reset}`;
|
|
230
|
+
}
|
|
145
231
|
/** 带色串按可见宽度截断(保留中间 ANSI 码,超出末尾加 …,补 reset 防 … 继承颜色)。 */
|
|
146
232
|
export function truncateAnsi(str, width) {
|
|
147
233
|
if (ansiDisplayWidth(str) <= width)
|
|
@@ -236,7 +322,6 @@ export function wrapByDisplayWidth(text, width) {
|
|
|
236
322
|
out.push(cur);
|
|
237
323
|
return out;
|
|
238
324
|
}
|
|
239
|
-
const BOX_W = 60; // 内容区显示宽度(logo 区 + 信息区)
|
|
240
325
|
const MARGIN = ' '; // 盒外左缩进
|
|
241
326
|
// ── MoCode 块字符 logo(4 行,neofetch 风)──
|
|
242
327
|
const LOGO_W = 35; // logo 区显示宽度
|
|
@@ -316,7 +401,7 @@ export function summarizeToolCall(name, argsRaw) {
|
|
|
316
401
|
const args = tryParse(argsRaw);
|
|
317
402
|
if (!args)
|
|
318
403
|
return truncateDisplay(argsRaw, 80);
|
|
319
|
-
const s = (k) => typeof args[k] === 'string' ? args[k] : '';
|
|
404
|
+
const s = (k) => (typeof args[k] === 'string' ? args[k] : '');
|
|
320
405
|
switch (name) {
|
|
321
406
|
case 'read_file':
|
|
322
407
|
case 'write_file':
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
const isWindows = process.platform === 'win32';
|
|
3
3
|
const ROOT_CONFIG_NAMES = new Set([
|
|
4
|
-
'package.json',
|
|
5
|
-
'
|
|
4
|
+
'package.json',
|
|
5
|
+
'pnpm-workspace.yaml',
|
|
6
|
+
'pnpm-workspace.yml',
|
|
7
|
+
'package-lock.json',
|
|
8
|
+
'pnpm-lock.yaml',
|
|
9
|
+
'yarn.lock',
|
|
10
|
+
'bun.lock',
|
|
11
|
+
'bun.lockb',
|
|
6
12
|
]);
|
|
7
13
|
function comparisonKey(value) {
|
|
8
14
|
const resolved = path.resolve(value);
|
|
@@ -76,9 +82,9 @@ function addReason(selections, packageProfile, reason) {
|
|
|
76
82
|
selected = { package: packageProfile, reasons: [] };
|
|
77
83
|
selections.set(key, selected);
|
|
78
84
|
}
|
|
79
|
-
if (!selected.reasons.some((item) => item.kind === reason.kind
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
if (!selected.reasons.some((item) => item.kind === reason.kind &&
|
|
86
|
+
item.changedPath === reason.changedPath &&
|
|
87
|
+
item.sourcePackage === reason.sourcePackage)) {
|
|
82
88
|
selected.reasons.push(reason);
|
|
83
89
|
}
|
|
84
90
|
}
|
|
@@ -21,9 +21,7 @@ function commandFor(profile, packageProfile, script) {
|
|
|
21
21
|
}
|
|
22
22
|
/** Discover every available V3 command in increasing-cost order. */
|
|
23
23
|
export function discoverPackageValidationCommands(profile, packageProfile) {
|
|
24
|
-
return LAYERED_ORDER
|
|
25
|
-
.filter((script) => typeof packageProfile.scripts[script] === 'string')
|
|
26
|
-
.map((script) => commandFor(profile, packageProfile, script));
|
|
24
|
+
return LAYERED_ORDER.filter((script) => typeof packageProfile.scripts[script] === 'string').map((script) => commandFor(profile, packageProfile, script));
|
|
27
25
|
}
|
|
28
26
|
/** Compatibility API retained for callers that intentionally want one command. */
|
|
29
27
|
export function discoverPackageValidationCommand(profile, packageProfile) {
|
|
@@ -3,8 +3,14 @@ import path from 'node:path';
|
|
|
3
3
|
import fg from 'fast-glob';
|
|
4
4
|
const cache = new Map();
|
|
5
5
|
const ROOT_INPUTS = [
|
|
6
|
-
'package.json',
|
|
7
|
-
'
|
|
6
|
+
'package.json',
|
|
7
|
+
'pnpm-workspace.yaml',
|
|
8
|
+
'pnpm-workspace.yml',
|
|
9
|
+
'package-lock.json',
|
|
10
|
+
'pnpm-lock.yaml',
|
|
11
|
+
'yarn.lock',
|
|
12
|
+
'bun.lock',
|
|
13
|
+
'bun.lockb',
|
|
8
14
|
];
|
|
9
15
|
const SOURCE_DIRS = ['src', 'lib', 'app'];
|
|
10
16
|
const TEST_DIRS = ['test', 'tests', '__tests__', 'spec', 'src/test', 'src/tests', 'src/__tests__'];
|
|
@@ -134,7 +140,9 @@ function discoverConfigPaths(root, patterns) {
|
|
|
134
140
|
return uniqueSorted(fg.sync(patterns, { cwd: root, ...GLOB_OPTIONS }).map((item) => path.resolve(item)));
|
|
135
141
|
}
|
|
136
142
|
function existingDirectories(root, relativePaths) {
|
|
137
|
-
return relativePaths
|
|
143
|
+
return relativePaths
|
|
144
|
+
.map((item) => path.resolve(root, item))
|
|
145
|
+
.filter((item) => {
|
|
138
146
|
try {
|
|
139
147
|
return statSync(item).isDirectory();
|
|
140
148
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mocode-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "终端编码 agent:LLM + tool-call 循环 + 流式输出(含思考)+ 16 个工具,接任意 OpenAI 兼容后端。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"build": "tsc -p tsconfig.build.json",
|
|
24
24
|
"test": "tsc -p tsconfig.test-build.json && node --test --experimental-test-isolation=none \"dist-tests/tests/*.test.js\"",
|
|
25
25
|
"typecheck": "tsc --noEmit && tsc -p tests/tsconfig.json && tsc -p evals/tsconfig.json",
|
|
26
|
+
"lint": "eslint .",
|
|
27
|
+
"lint:check": "eslint .",
|
|
28
|
+
"lint:fix": "eslint . --fix",
|
|
29
|
+
"format": "prettier --write .",
|
|
30
|
+
"format:check": "prettier --check .",
|
|
26
31
|
"eval:smoke": "tsx evals/smoke.ts && tsx evals/coding/smoke.ts && tsx evals/work-discipline.ts",
|
|
27
32
|
"eval:coding": "tsx evals/coding/runner.ts",
|
|
28
33
|
"eval:coding:list": "tsx evals/coding/runner.ts --list",
|
|
@@ -40,9 +45,13 @@
|
|
|
40
45
|
"devDependencies": {
|
|
41
46
|
"@types/node": "^22.0.0",
|
|
42
47
|
"@types/ws": "8.5.13",
|
|
48
|
+
"eslint": "^9.39.5",
|
|
43
49
|
"fast-check": "3.23.1",
|
|
50
|
+
"globals": "^15.15.0",
|
|
51
|
+
"prettier": "3.6.2",
|
|
44
52
|
"tsx": "^4.0.0",
|
|
45
|
-
"typescript": "^5.0.0"
|
|
53
|
+
"typescript": "^5.0.0",
|
|
54
|
+
"typescript-eslint": "^8.69.0"
|
|
46
55
|
},
|
|
47
56
|
"repository": {
|
|
48
57
|
"type": "git",
|