mocode-ai 1.2.4 → 1.2.6
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 +6 -6
- package/README.zh-CN.md +4 -4
- package/dist/agent/core.js +9 -9
- package/dist/config/index.js +78 -13
- package/dist/context/classifier.js +1 -0
- package/dist/context/encoders/table.js +1 -1
- package/dist/i18n/index.js +4 -4
- package/dist/llm/index.js +0 -1
- package/dist/memory/discover.js +8 -8
- package/dist/memory/graph.js +409 -0
- package/dist/memory/index.js +5 -3
- package/dist/memory/reflect.js +25 -6
- package/dist/repl/index.js +14 -14
- package/dist/sandbox/policy.js +1 -1
- package/dist/session/notes.js +233 -0
- package/dist/skills/runner.js +0 -1
- package/dist/tools/builtins/index.js +9 -1
- package/dist/tools/builtins/memory-graph.js +118 -0
- package/dist/tools/builtins/memory-save.js +42 -5
- package/dist/tools/builtins/memory-search.js +26 -5
- package/dist/tools/builtins/note-append.js +103 -0
- package/dist/tools/constants.js +6 -0
- package/dist/tools/registry.js +13 -4
- package/dist/ui/diff.js +1 -1
- package/dist/ui/layout.js +3 -3
- package/dist/ui/render.js +7 -1
- package/dist/ui/theme.js +11 -11
- package/package.json +3 -2
package/dist/tools/registry.js
CHANGED
|
@@ -11,6 +11,11 @@ import { isToolErrorOutput } from './result.js';
|
|
|
11
11
|
*/
|
|
12
12
|
const extensions = new Map();
|
|
13
13
|
export const tools = [...builtinTools];
|
|
14
|
+
/** 名字 → 工具 的 O(1) 索引,与 tools 数组在每次 rebuild 时同步重建;findTool 走此索引。 */
|
|
15
|
+
let toolIndex = buildToolIndex(tools);
|
|
16
|
+
function buildToolIndex(list) {
|
|
17
|
+
return new Map(list.map((tool) => [tool.name, tool]));
|
|
18
|
+
}
|
|
14
19
|
export function registerToolsExtension(sourceOrAdditions, maybeAdditions) {
|
|
15
20
|
const source = typeof sourceOrAdditions === 'string' ? sourceOrAdditions : 'external';
|
|
16
21
|
const additions = typeof sourceOrAdditions === 'string' ? (maybeAdditions ?? []) : sourceOrAdditions;
|
|
@@ -35,13 +40,14 @@ function rebuildTools() {
|
|
|
35
40
|
next.push(tool);
|
|
36
41
|
}
|
|
37
42
|
tools.splice(0, tools.length, ...next);
|
|
43
|
+
toolIndex = buildToolIndex(next);
|
|
38
44
|
}
|
|
39
45
|
const DEFAULT_CAPABILITIES = Object.freeze({
|
|
40
46
|
effect: 'unknown',
|
|
41
47
|
concurrency: 'serial',
|
|
42
48
|
});
|
|
43
49
|
export function findTool(name) {
|
|
44
|
-
return
|
|
50
|
+
return toolIndex.get(name);
|
|
45
51
|
}
|
|
46
52
|
/** 缺少声明或找不到工具时返回保守能力,绝不把未知扩展并发执行。 */
|
|
47
53
|
export function getToolCapabilities(toolOrName) {
|
|
@@ -58,10 +64,13 @@ export function getToolResourceKeys(toolOrName, args) {
|
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
/** resource-locked write 是可生成文件 diff/按路径记 rollback 的文件 mutation。 */
|
|
61
|
-
export function
|
|
62
|
-
const capabilities = getToolCapabilities(name);
|
|
67
|
+
export function isFileMutationCapabilities(capabilities) {
|
|
63
68
|
return capabilities.effect === 'write' && capabilities.concurrency === 'resource-locked';
|
|
64
69
|
}
|
|
70
|
+
/** 按工具名判定(兼容入口);热路径请直接复用已解析的 capabilities 走 isFileMutationCapabilities。 */
|
|
71
|
+
export function isFileMutationTool(name) {
|
|
72
|
+
return isFileMutationCapabilities(getToolCapabilities(name));
|
|
73
|
+
}
|
|
65
74
|
function isStructuredOutcome(value) {
|
|
66
75
|
return typeof value === 'object' && value !== null &&
|
|
67
76
|
typeof value.status === 'string' && typeof value.code === 'string' &&
|
|
@@ -144,7 +153,7 @@ async function executeToolOnce(tool, args, signal, opts) {
|
|
|
144
153
|
mutationVersionBefore = mutationBefore.version;
|
|
145
154
|
// Transactional tools own their full write-set capture inside ChangeSet commit.
|
|
146
155
|
const pathCapture = !capabilities.delegatesResourceLocks &&
|
|
147
|
-
|
|
156
|
+
isFileMutationCapabilities(capabilities) && typeof args.path === 'string' && args.path
|
|
148
157
|
? beginPathMutation(args.path)
|
|
149
158
|
: null;
|
|
150
159
|
capturedPath = pathCapture?.path;
|
package/dist/ui/diff.js
CHANGED
|
@@ -254,7 +254,7 @@ export function renderFileChange(opts) {
|
|
|
254
254
|
/** 头行 + 计数行 + 正文(折叠 + 截断 + 行号),每行尾 \n。 */
|
|
255
255
|
function renderBody(head, counts, items, padW, startLine, lang) {
|
|
256
256
|
const lines = [head, counts];
|
|
257
|
-
const metaPrefix = `${BODY_INDENT}
|
|
257
|
+
const metaPrefix = `${BODY_INDENT}`; // 与正文行左对齐(batch 展开时还会再加外层 indent,避免双重缩进导致提示行突兀)
|
|
258
258
|
let oldLine = startLine;
|
|
259
259
|
let newLine = startLine;
|
|
260
260
|
let shown = 0;
|
package/dist/ui/layout.js
CHANGED
|
@@ -1361,8 +1361,8 @@ function composeSpinnerLine(status, cols) {
|
|
|
1361
1361
|
leadW = 1 + 1 + displayWidth(status.status) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
1362
1362
|
}
|
|
1363
1363
|
else if (spinning) {
|
|
1364
|
-
// 运行态心跳帧(流式输出中):帧 +
|
|
1365
|
-
const label = '生成中';
|
|
1364
|
+
// 运行态心跳帧(流式输出中 / 命令态如 /rollback /compact /resume):帧 + 状态文字(优先)或生成中(兜底) + 走时
|
|
1365
|
+
const label = status.status || '生成中';
|
|
1366
1366
|
const ePart = elapsed ? ` ${ui.dim}${elapsed}${ui.reset}` : '';
|
|
1367
1367
|
lead = `${ui.bold}${ui.accent}${RUNNING_FRAMES[runningFrame]}${ui.reset} ${ui.dim}${label}${ui.reset}${ePart}`;
|
|
1368
1368
|
leadW = 1 + 1 + displayWidth(label) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
@@ -1936,7 +1936,7 @@ function renderDimInputRow(prompt, text, placeholder, cols) {
|
|
|
1936
1936
|
/**
|
|
1937
1937
|
* 单行运行态滑窗:以光标为中心,向左右扩展填满 contentW-1(留 1 cell 给光标),
|
|
1938
1938
|
* 返回可见子串与光标在子串内的显示列。保证光标恒可见,且不软折行(运行态输入框恒单行,
|
|
1939
|
-
* 不触发 setRegion/ED
|
|
1939
|
+
* 不触发 setRegion/ED,避免流式期间底栏抖动)。
|
|
1940
1940
|
*/
|
|
1941
1941
|
function windowSingleLine(text, cursor, contentW) {
|
|
1942
1942
|
const n = text.length;
|
package/dist/ui/render.js
CHANGED
|
@@ -2,7 +2,13 @@ import { stdout } from 'node:process';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { ui } from './theme.js';
|
|
4
4
|
import { t } from '../i18n/index.js';
|
|
5
|
-
|
|
5
|
+
let VERSION = '0.0.0';
|
|
6
|
+
try {
|
|
7
|
+
VERSION = createRequire(import.meta.url)('../../package.json').version;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// 非标准布局(测试编译产物、自定义打包)不含 package.json:版本号回落,不阻断模块加载。
|
|
11
|
+
}
|
|
6
12
|
/**
|
|
7
13
|
* 清空整屏 + 滚动缓冲(向上滚动可见的历史输出),光标归位。
|
|
8
14
|
* 进入会话时调用,让终端只剩当前 agent 对话。非 TTY 时空操作。
|
package/dist/ui/theme.js
CHANGED
|
@@ -29,7 +29,7 @@ const DEFAULT = {
|
|
|
29
29
|
brightCyan: '\x1B[38;2;86;182;194m',
|
|
30
30
|
brightMagenta: '\x1B[38;2;198;120;221m',
|
|
31
31
|
accent: '\x1B[38;2;86;182;194m', // 与 cyan 同源(One Dark):logo/标题/输入框顶线/选中项统一承载
|
|
32
|
-
userBg: '\x1B[48;2;
|
|
32
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
33
33
|
// diff 行底色:One Dark bg #282c34 上加 ~14% 亮度的对应色,够辨识但不刺眼
|
|
34
34
|
addBg: '\x1B[48;2;44;62;42m', // 偏暗绿(One Dark green(152,195,121)暗化)
|
|
35
35
|
delBg: '\x1B[48;2;62;38;42m', // 偏暗红(One Dark red(224,108,117)暗化)
|
|
@@ -54,7 +54,7 @@ const THEMES = {
|
|
|
54
54
|
brightCyan: '\x1B[38;2;42;161;152m',
|
|
55
55
|
brightMagenta: '\x1B[38;2;108;113;196m',
|
|
56
56
|
accent: '\x1B[38;2;38;139;210m', // Solarized blue:浅底下更醒目的强调
|
|
57
|
-
userBg: '\x1B[48;2;
|
|
57
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
58
58
|
// diff 行底色:Solarized Light base2(238,232,213)上贴同色族浅 tint,
|
|
59
59
|
// 比直接用 base1 更柔,跟深 fg(red/green)对比充足
|
|
60
60
|
addBg: '\x1B[48;2;220;235;205m',
|
|
@@ -72,7 +72,7 @@ const THEMES = {
|
|
|
72
72
|
brightCyan: '\x1B[38;2;147;161;161m',
|
|
73
73
|
brightMagenta: '\x1B[38;2;108;113;196m',
|
|
74
74
|
accent: '\x1B[38;2;42;161;152m', // Solarized cyan(深底版):暗底上跳出
|
|
75
|
-
userBg: '\x1B[48;2;
|
|
75
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
76
76
|
// diff 行底色:Solarized Dark base03(0,43,54)上加对应色族暗 tint
|
|
77
77
|
addBg: '\x1B[48;2;20;50;38m',
|
|
78
78
|
delBg: '\x1B[48;2;55;30;30m',
|
|
@@ -89,7 +89,7 @@ const THEMES = {
|
|
|
89
89
|
brightCyan: '\x1B[38;2;142;192;124m',
|
|
90
90
|
brightMagenta: '\x1B[38;2;211;134;155m',
|
|
91
91
|
accent: '\x1B[38;2;250;189;47m', // Gruvbox yellow(主题色)
|
|
92
|
-
userBg: '\x1B[48;2;
|
|
92
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
93
93
|
// diff 行底色:Gruvbox dark bg(40,40,40)上贴暗 bg0_a 风格
|
|
94
94
|
addBg: '\x1B[48;2;40;55;30m',
|
|
95
95
|
delBg: '\x1B[48;2;70;35;30m',
|
|
@@ -106,7 +106,7 @@ const THEMES = {
|
|
|
106
106
|
brightCyan: '\x1B[38;2;136;192;208m',
|
|
107
107
|
brightMagenta: '\x1B[38;2;180;142;173m',
|
|
108
108
|
accent: '\x1B[38;2;136;192;208m', // Nord 浅冰蓝(主题色)
|
|
109
|
-
userBg: '\x1B[48;2;
|
|
109
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
110
110
|
// diff 行底色:Nord polar night(46,52,64)上贴对应色族暗 tint
|
|
111
111
|
addBg: '\x1B[48;2;46;66;52m',
|
|
112
112
|
delBg: '\x1B[48;2;72;46;52m',
|
|
@@ -126,7 +126,7 @@ const THEMES = {
|
|
|
126
126
|
brightCyan: '\x1B[38;2;160;220;220m',
|
|
127
127
|
brightMagenta: '\x1B[38;2;245;165;215m',
|
|
128
128
|
accent: '\x1B[38;2;255;170;60m', // 南瓜橙(主题主色:logo/标题/输入框顶线/选中项)
|
|
129
|
-
userBg: '\x1B[48;2;
|
|
129
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
130
130
|
// diff 行底色:暖深棕底上贴对应色族暗 tint,跟 fg 配对柔和可辨
|
|
131
131
|
addBg: '\x1B[48;2;55;70;35m',
|
|
132
132
|
delBg: '\x1B[48;2;78;42;32m',
|
|
@@ -145,7 +145,7 @@ const THEMES = {
|
|
|
145
145
|
brightCyan: '\x1B[38;2;170;220;220m',
|
|
146
146
|
brightMagenta: '\x1B[38;2;250;160;200m',
|
|
147
147
|
accent: '\x1B[38;2;230;90;150m', // 玫粉(主题主色)
|
|
148
|
-
userBg: '\x1B[48;2;
|
|
148
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
149
149
|
// diff 行底色:深紫底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏紫红
|
|
150
150
|
addBg: '\x1B[48;2;50;60;42m',
|
|
151
151
|
delBg: '\x1B[48;2;75;40;52m',
|
|
@@ -164,7 +164,7 @@ const THEMES = {
|
|
|
164
164
|
brightCyan: '\x1B[38;2;140;230;210m',
|
|
165
165
|
brightMagenta: '\x1B[38;2;210;170;230m',
|
|
166
166
|
accent: '\x1B[38;2;80;210;140m', // 翡翠绿(主题主色)
|
|
167
|
-
userBg: '\x1B[48;2;
|
|
167
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
168
168
|
// diff 行底色:深绿底贴对应色族暗 tint,绿暗化偏深绿、红暗化偏暗红
|
|
169
169
|
addBg: '\x1B[48;2;30;55;40m',
|
|
170
170
|
delBg: '\x1B[48;2;60;40;40m',
|
|
@@ -183,7 +183,7 @@ const THEMES = {
|
|
|
183
183
|
brightCyan: '\x1B[38;2;170;210;200m',
|
|
184
184
|
brightMagenta: '\x1B[38;2;240;180;210m',
|
|
185
185
|
accent: '\x1B[38;2;255;200;80m', // 琥珀金黄(主题主色)
|
|
186
|
-
userBg: '\x1B[48;2;
|
|
186
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
187
187
|
// diff 行底色:深棕底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏暗棕红
|
|
188
188
|
addBg: '\x1B[48;2;50;55;25m',
|
|
189
189
|
delBg: '\x1B[48;2;70;40;28m',
|
|
@@ -202,7 +202,7 @@ const THEMES = {
|
|
|
202
202
|
brightCyan: '\x1B[38;2;180;230;230m',
|
|
203
203
|
brightMagenta: '\x1B[38;2;210;180;250m',
|
|
204
204
|
accent: '\x1B[38;2;180;150;230m', // 薰衣草紫(主题主色)
|
|
205
|
-
userBg: '\x1B[48;2;
|
|
205
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
206
206
|
// diff 行底色:深紫底贴对应色族暗 tint,绿暗化偏冷绿、红暗化偏冷紫红
|
|
207
207
|
addBg: '\x1B[48;2;38;46;42m',
|
|
208
208
|
delBg: '\x1B[48;2;60;40;55m',
|
|
@@ -221,7 +221,7 @@ const THEMES = {
|
|
|
221
221
|
brightCyan: '\x1B[38;2;170;225;215m',
|
|
222
222
|
brightMagenta: '\x1B[38;2;250;170;210m',
|
|
223
223
|
accent: '\x1B[38;2;255;120;100m', // 珊瑚红(主题主色)
|
|
224
|
-
userBg: '\x1B[48;2;
|
|
224
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
225
225
|
// diff 行底色:深棕红底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏暗棕红
|
|
226
226
|
addBg: '\x1B[48;2;50;55;30m',
|
|
227
227
|
delBg: '\x1B[48;2;75;32;30m',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mocode-ai",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "终端编码 agent:LLM + tool-call 循环 + 流式输出(含思考)+ 16 个工具,接任意 OpenAI 兼容后端。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "tsx src/index.ts",
|
|
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
|
+
"typecheck": "tsc --noEmit && tsc -p tests/tsconfig.json && tsc -p evals/tsconfig.json",
|
|
25
26
|
"eval:smoke": "tsx evals/smoke.ts && tsx evals/coding/smoke.ts",
|
|
26
27
|
"eval:coding": "tsx evals/coding/runner.ts",
|
|
27
28
|
"eval:coding:list": "tsx evals/coding/runner.ts --list",
|