mocode-ai 1.5.0 → 1.5.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/dist/i18n/index.js +14 -6
- package/dist/llm/index.js +114 -2
- package/dist/llm/providers/anthropic.js +6 -0
- package/dist/llm/stream-interrupt.js +24 -0
- package/dist/repl/commands.js +1 -0
- package/docs/usage.md +344 -0
- package/package.json +4 -2
package/dist/i18n/index.js
CHANGED
|
@@ -225,6 +225,7 @@ const zhCN = {
|
|
|
225
225
|
'repl.llmTimeoutError': '请求超时:模型服务响应过慢。可重试,或输入 /model switch 换一个模型。',
|
|
226
226
|
'repl.llmNetworkError': '网络错误:无法连接 {base}。检查网络连接,或输入 /model 核对 baseURL 配置。',
|
|
227
227
|
'repl.llmContextError': '上下文超长:输入 /compact 压缩会话后重试。',
|
|
228
|
+
'repl.llmServerError': '模型服务端在生成中途中断(错误来自响应流内部,非 HTTP 层)。该轮未写入会话历史,直接重发即可;若反复出现,用 /model switch 换模型或 /compact 压缩会话。',
|
|
228
229
|
'permission.path': '路径: {value}',
|
|
229
230
|
'permission.command': '命令: {value}',
|
|
230
231
|
'permission.task': '任务: {value}',
|
|
@@ -553,6 +554,7 @@ const en = {
|
|
|
553
554
|
'repl.llmTimeoutError': 'Request timed out: the model service responded too slowly. Retry, or run /model switch to use another model.',
|
|
554
555
|
'repl.llmNetworkError': 'Network error: cannot reach {base}. Check your connection, or run /model to verify the baseURL.',
|
|
555
556
|
'repl.llmContextError': 'Context too long: run /compact to compress the session, then retry.',
|
|
557
|
+
'repl.llmServerError': 'The model backend aborted mid-stream (the error came from inside the response stream). This turn was not written to session history — just resend it. If it repeats, run /model switch or /compact.',
|
|
556
558
|
'permission.path': 'Path: {value}',
|
|
557
559
|
'permission.command': 'Command: {value}',
|
|
558
560
|
'permission.task': 'Task: {value}',
|
|
@@ -658,7 +660,13 @@ const resources = {
|
|
|
658
660
|
'zh-CN': zhCN,
|
|
659
661
|
en,
|
|
660
662
|
};
|
|
661
|
-
|
|
663
|
+
/**
|
|
664
|
+
* 未显式配置语言时的默认值。刻意固定为 en 而**不**探测系统 locale:
|
|
665
|
+
* 中文 Windows 的 `Intl.DateTimeFormat().resolvedOptions().locale` 为 zh-CN,
|
|
666
|
+
* 会让新装用户一开就是中文界面。要中文须显式 /language zh-CN 或 MOCODE_LANGUAGE=zh-CN。
|
|
667
|
+
*/
|
|
668
|
+
export const DEFAULT_LANGUAGE = 'en';
|
|
669
|
+
let currentLanguage = DEFAULT_LANGUAGE;
|
|
662
670
|
export function normalizeLanguage(value) {
|
|
663
671
|
const normalized = value?.trim().toLowerCase().replace('_', '-');
|
|
664
672
|
if (!normalized)
|
|
@@ -669,12 +677,12 @@ export function normalizeLanguage(value) {
|
|
|
669
677
|
return 'en';
|
|
670
678
|
return null;
|
|
671
679
|
}
|
|
680
|
+
/**
|
|
681
|
+
* 解析生效语言:只认显式配置(MOCODE_LANGUAGE / ~/.mocode/config / 项目级 config),
|
|
682
|
+
* 无法识别或未配置时落 DEFAULT_LANGUAGE(en)。不再回退系统 locale。
|
|
683
|
+
*/
|
|
672
684
|
export function detectLanguage(preferred) {
|
|
673
|
-
|
|
674
|
-
if (explicit)
|
|
675
|
-
return explicit;
|
|
676
|
-
const system = normalizeLanguage(process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || Intl.DateTimeFormat().resolvedOptions().locale);
|
|
677
|
-
return system ?? 'zh-CN';
|
|
685
|
+
return normalizeLanguage(preferred) ?? DEFAULT_LANGUAGE;
|
|
678
686
|
}
|
|
679
687
|
export function setLanguage(language) {
|
|
680
688
|
currentLanguage = language;
|
package/dist/llm/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getPlanDisabledTools, getProfileDisabledTools } from '../tools/constant
|
|
|
5
5
|
import { imageSizeFromDataUrl } from '../attachments/image.js';
|
|
6
6
|
import { ThinkTagFilter } from './think-filter.js';
|
|
7
7
|
import { sanitizeToolSchemas } from './tool-schema.js';
|
|
8
|
+
import { isMarkedStreamInterrupted } from './stream-interrupt.js';
|
|
8
9
|
import { defaultAnthropicFetch, anthropicChatOnce } from './providers/anthropic.js';
|
|
9
10
|
import { registerModelProvider, getModelProvider, listModelProviders } from './provider.js';
|
|
10
11
|
// 强制关闭第三方调试日志泄漏:openai SDK 在 process.env.DEBUG === 'true' 时用裸
|
|
@@ -29,6 +30,12 @@ const RETRY_MAX_ATTEMPTS = 10;
|
|
|
29
30
|
const RETRY_BASE_MS = 1000;
|
|
30
31
|
const RETRY_MAX_MS = 30000;
|
|
31
32
|
const RETRY_JITTER = 0.2;
|
|
33
|
+
/**
|
|
34
|
+
* 「流中途故障」(见 isStreamInterruptedError)单独的重试预算,不共享 HTTP 层的 10 次。
|
|
35
|
+
* 这类错误绝大多数是推理后端瞬时故障,重试两次足够;若它其实是永久故障,10 次指数退避
|
|
36
|
+
* (封顶 30s)会让用户干等近两分钟,代价远大于收益。
|
|
37
|
+
*/
|
|
38
|
+
const STREAM_RETRY_MAX_ATTEMPTS = 2;
|
|
32
39
|
/**
|
|
33
40
|
* 流式响应里出现的推理模型自创 `think` 标签(DeepSeek R1 / Qwen3 / 部分自训模型):
|
|
34
41
|
* 与 OpenAI 兼容协议的独立 `reasoning_content` 字段不同,这些模型把 thinking 直接嵌进 content
|
|
@@ -130,6 +137,77 @@ export function isRetryableError(err, signal) {
|
|
|
130
137
|
}
|
|
131
138
|
return false;
|
|
132
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* 「传输/协议层的流中断」判据:连接被掐断、响应提前结束、cause 里藏着 errno。
|
|
142
|
+
*
|
|
143
|
+
* 实测(Node 22 + openai SDK + 服务端 destroy socket):HTTP 200 建连并已吐出 chunk 后
|
|
144
|
+
* 连接被掐,抛的是 `Error: Premature close`(code `ERR_STREAM_PREMATURE_CLOSE`)——
|
|
145
|
+
* 既不是 APIError 也没有 status,`isRetryableError` 一条都不命中。网关超时、NAT 回收、
|
|
146
|
+
* 推理进程 OOM 被杀、k8s pod 重启都属于这一类,是线上最常见的「半路断流」。
|
|
147
|
+
*
|
|
148
|
+
* undici 还会把底层 errno 藏在 `cause` 里(`TypeError: fetch failed` → cause
|
|
149
|
+
* `SocketError: other side closed` / `read ECONNRESET`),只看顶层必然漏,故沿 cause 链找。
|
|
150
|
+
*/
|
|
151
|
+
const STREAM_BREAK_CODES = new Set([
|
|
152
|
+
'ERR_STREAM_PREMATURE_CLOSE',
|
|
153
|
+
'ERR_STREAM_DESTROYED',
|
|
154
|
+
'ERR_STREAM_UNABLE_TO_PIPE',
|
|
155
|
+
'ERR_HTTP2_STREAM_CANCEL',
|
|
156
|
+
'UND_ERR_SOCKET',
|
|
157
|
+
'ECONNRESET',
|
|
158
|
+
'ECONNABORTED',
|
|
159
|
+
'EPIPE',
|
|
160
|
+
'ETIMEDOUT',
|
|
161
|
+
'ERR_SOCKET_CONNECTION_TIMEOUT',
|
|
162
|
+
]);
|
|
163
|
+
const STREAM_BREAK_MESSAGE = /premature close|other side closed|socket hang up|\bterminated\b|stream (?:closed|ended) (?:prematurely|unexpectedly)|econnreset|econnaborted/i;
|
|
164
|
+
/** 沿 cause 链(≤3 层)找「连接被掐断」的信号;命中即认为响应流非正常结束。 */
|
|
165
|
+
function hasStreamBreakSignal(err, depth = 0) {
|
|
166
|
+
if (!err || typeof err !== 'object' || depth > 3)
|
|
167
|
+
return false;
|
|
168
|
+
const e = err;
|
|
169
|
+
if (typeof e.code === 'string' && STREAM_BREAK_CODES.has(e.code))
|
|
170
|
+
return true;
|
|
171
|
+
if (typeof e.message === 'string' && STREAM_BREAK_MESSAGE.test(e.message))
|
|
172
|
+
return true;
|
|
173
|
+
return hasStreamBreakSignal(e.cause, depth + 1);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 判定「服务端在响应流中途报错 / 流被中途掐断」——HTTP 层已建连并开始流式返回(状态码 200),
|
|
177
|
+
* 失败发生在流内部。两条命中路径:
|
|
178
|
+
*
|
|
179
|
+
* ① **SSE error chunk**:SDK 的两条流内抛错路径(node_modules/openai/streaming.mjs:41 / :57)
|
|
180
|
+
* 都构造 `new APIError(undefined, data.error, …)`:status 为 undefined,code/message 取自
|
|
181
|
+
* 负载,例如 DashScope 的 `ClientError` + `Backend buffer overflow.`。
|
|
182
|
+
* ② **传输层断流**:见 hasStreamBreakSignal;或 provider 显式打了标记
|
|
183
|
+
* (`providers/anthropic.ts` 的 SSE `event: error`,由 markStreamInterrupted 标注)。
|
|
184
|
+
*
|
|
185
|
+
* 为什么要单独识别:isRetryableError 只认 status(429 / 5xx)、Node errno 白名单与 timeout 字样,
|
|
186
|
+
* 这三类都不沾 → 被当成「不可重试的客户端请求错」一次即抛,整轮 run 直接终止。但它们的真实语义
|
|
187
|
+
* 是「服务端/链路在生成到一半时挂了」,属瞬时故障,重试是正确处置(已实测同一会话更大 prompt 可成功)。
|
|
188
|
+
*
|
|
189
|
+
* 只认 APIError 本身,不认子类:APIConnectionError / APIConnectionTimeoutError 已由
|
|
190
|
+
* isRetryableError 的 name 分支覆盖,而 APIUserAbortError 是用户中断、绝不能重试。
|
|
191
|
+
* 判据用构造器名而非 instanceof:同进程若存在 openai 的多份模块实例(ESM/CJS 混载),
|
|
192
|
+
* instanceof 会失配。
|
|
193
|
+
*
|
|
194
|
+
* 注意:这里只判定「类别」;能否真的重试还要看调用方的「本次尝试零产出」前提。
|
|
195
|
+
*/
|
|
196
|
+
export function isStreamInterruptedError(err) {
|
|
197
|
+
if (!err || typeof err !== 'object')
|
|
198
|
+
return false;
|
|
199
|
+
const e = err;
|
|
200
|
+
if (e.name === 'AbortError' || e.name === 'APIUserAbortError')
|
|
201
|
+
return false;
|
|
202
|
+
if (isMarkedStreamInterrupted(err))
|
|
203
|
+
return true;
|
|
204
|
+
// 有 HTTP 状态码 = 建连阶段失败,交由 isRetryableError 既有规则处理。
|
|
205
|
+
if (typeof e.status === 'number')
|
|
206
|
+
return false;
|
|
207
|
+
if ((e.constructor?.name ?? '') === 'APIError')
|
|
208
|
+
return true;
|
|
209
|
+
return hasStreamBreakSignal(err);
|
|
210
|
+
}
|
|
133
211
|
/**
|
|
134
212
|
* 判定一次失败是否是「请求上下文超长」(后端实测拒绝了我们的 prompt)。
|
|
135
213
|
*
|
|
@@ -187,6 +265,13 @@ export function classifyChatError(msg) {
|
|
|
187
265
|
if (/\benotfound\b|\beconnrefused\b|\beai_again\b|getaddrinfo|fetch failed|network error|certificate/.test(m) ||
|
|
188
266
|
/无法连接|网络(?:错误|异常|不可用)|域名解析/.test(msg))
|
|
189
267
|
return 'network';
|
|
268
|
+
// 服务端在生成中途故障(流内报错,无 HTTP 状态码):推理后端崩溃 / 网关缓冲溢出等瞬时故障。
|
|
269
|
+
// 已实测 DashScope compatible-mode 会回 `code=ClientError` + `message="Backend buffer overflow."`。
|
|
270
|
+
// 走到这里说明重试预算已用尽(或已有半截输出不能重试),给「直接重发」的引导而非裸报错。
|
|
271
|
+
if (/backend\s+buffer|buffer\s+overflow|engine\s+(?:crash|error|failed|aborted)|internal\s+server\s+error|server\s+(?:overloaded|busy|unavailable)/.test(m) ||
|
|
272
|
+
/premature close|other side closed/.test(m) ||
|
|
273
|
+
/后端.{0,10}(?:溢出|崩溃|异常)|服务(?:端|器)(?:内部)?(?:错误|异常|繁忙|不可用)/.test(msg))
|
|
274
|
+
return 'server';
|
|
190
275
|
return null;
|
|
191
276
|
}
|
|
192
277
|
/** 从 OpenAI APIError.headers 解析 Retry-After(秒);不支持或缺失返回 undefined。封顶 RETRY_MAX_MS。 */
|
|
@@ -352,23 +437,50 @@ toolsOverride) {
|
|
|
352
437
|
}
|
|
353
438
|
async function chatWithRuntime(runtime, messages, handlers, signal, toolsOverride) {
|
|
354
439
|
let lastErr;
|
|
440
|
+
// 本次尝试是否已向调用方产出过内容(可见文本 / 工具名)。用于判断「流中途故障可否安全重试」:
|
|
441
|
+
// 重试会从请求头重放,已流出并显示在内容区的半截文本会再写一遍(history 因异常未落,倒是不脏)。
|
|
442
|
+
// 用包装 handler 而非改各 provider 内部,OpenAI / Anthropic 两条路径统一生效。
|
|
443
|
+
let producedOutput = false;
|
|
444
|
+
const guardedHandlers = {
|
|
445
|
+
...handlers,
|
|
446
|
+
onText: (text) => {
|
|
447
|
+
producedOutput = true;
|
|
448
|
+
handlers.onText?.(text);
|
|
449
|
+
},
|
|
450
|
+
onToolCall: (name) => {
|
|
451
|
+
producedOutput = true;
|
|
452
|
+
handlers.onToolCall?.(name);
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
// 流中途故障用独立计数,避免与 HTTP 层共享 10 次预算(理由见 STREAM_RETRY_MAX_ATTEMPTS)。
|
|
456
|
+
let streamRetries = 0;
|
|
355
457
|
for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {
|
|
356
458
|
if (signal?.aborted) {
|
|
357
459
|
throw new DOMException('This operation was aborted', 'AbortError');
|
|
358
460
|
}
|
|
461
|
+
producedOutput = false;
|
|
359
462
|
try {
|
|
360
463
|
const provider = getModelProvider(runtime.config.provider);
|
|
361
464
|
if (!provider) {
|
|
362
465
|
// 未注册的 provider:给出可用名单,避免悄悄落到错误实现。
|
|
363
466
|
throw new Error(`未知的 LLM provider "${runtime.config.provider}";已注册:${listModelProviders().join(', ') || '(空)'}`);
|
|
364
467
|
}
|
|
365
|
-
return await provider.chatOnce(messages,
|
|
468
|
+
return await provider.chatOnce(messages, guardedHandlers, signal, toolsOverride, runtime);
|
|
366
469
|
}
|
|
367
470
|
catch (err) {
|
|
368
471
|
lastErr = err;
|
|
369
|
-
|
|
472
|
+
// 流中途故障的额外可重试窗口:仅当本次尝试零产出(否则重试会重放半截文本)、用户没有中断、
|
|
473
|
+
// 且未超它的独立预算。HTTP 层规则(isRetryableError)保持原样,两条判定取并集。
|
|
474
|
+
// 用户中断必须显式排除:undici 在 abort 时也可能抛「连接被掐断」形态的错,只看错误本身会误判。
|
|
475
|
+
const streamRetryable = !signal?.aborted &&
|
|
476
|
+
isStreamInterruptedError(err) &&
|
|
477
|
+
!producedOutput &&
|
|
478
|
+
streamRetries < STREAM_RETRY_MAX_ATTEMPTS;
|
|
479
|
+
if (attempt >= RETRY_MAX_ATTEMPTS || (!isRetryableError(err, signal) && !streamRetryable)) {
|
|
370
480
|
throw err;
|
|
371
481
|
}
|
|
482
|
+
if (streamRetryable)
|
|
483
|
+
streamRetries++;
|
|
372
484
|
const wait = computeBackoff(attempt, getRetryAfterMs(err));
|
|
373
485
|
const retry = {
|
|
374
486
|
attempt,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { config, getActiveModel } from '../../config/index.js';
|
|
2
|
+
import { markStreamInterrupted } from '../stream-interrupt.js';
|
|
2
3
|
let fetchImplOverride = null;
|
|
3
4
|
/** 仅供单测注入;生产路径使用 Node 18+ 全局 fetch。 */
|
|
4
5
|
export function __setAnthropicFetchImpl(impl) {
|
|
@@ -292,6 +293,11 @@ export async function anthropicChatOnce(messages, handlers, signal, tools, runti
|
|
|
292
293
|
const error = event.error;
|
|
293
294
|
const thrown = new Error(typeof error?.message === 'string' ? error.message : 'Anthropic stream error');
|
|
294
295
|
thrown.name = typeof error?.type === 'string' ? error.type : 'AnthropicStreamError';
|
|
296
|
+
// 打「流中途中断」标记:HTTP 层已 200 建连说明请求本身被接受了,流内报错必然是服务端侧
|
|
297
|
+
// (overloaded_error / api_error 等瞬时故障)。没有这个标记,它就是个无 status 的普通
|
|
298
|
+
// Error → isRetryableError 一条都不命中 → 整轮 run 直接终止、一次都不重试。
|
|
299
|
+
// 真正的重试门槛由 chatWithRuntime 的「本次尝试零产出」前提把关。
|
|
300
|
+
markStreamInterrupted(thrown);
|
|
295
301
|
throw thrown;
|
|
296
302
|
}
|
|
297
303
|
if (type === 'message_start') {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「流中途被打断」的显式标记。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:能否安全重试取决于「错误是否发生在响应流**里面**」(HTTP 层已 200 建连),
|
|
5
|
+
* 而这类错误的判定只能由**抛错方**知道 —— OpenAI 兼容路径是 SDK 造的 status-less `APIError`,
|
|
6
|
+
* Anthropic 路径是 SSE `event: error`(一个 name 被设成供应商错误类型的普通 Error)。
|
|
7
|
+
* 与其在 transport 层猜 vendor 的错误名,不如让 provider 在抛错时打标。
|
|
8
|
+
*
|
|
9
|
+
* 独立成 leaf 模块(零 import):`llm/index.ts` 与 `llm/providers/*.ts` 都要用它,
|
|
10
|
+
* 而 providers 只对 index 做 type-only import(见 provider.ts 头注),放 index 会成环。
|
|
11
|
+
*
|
|
12
|
+
* 只标记「错误类别」,不代表可以无条件重试:调用方仍必须叠加「本次尝试零产出」前提
|
|
13
|
+
* (见 chatWithRuntime 的 producedOutput),否则重试会在内容区重放半截文本。
|
|
14
|
+
*/
|
|
15
|
+
const interrupted = new WeakSet();
|
|
16
|
+
/** 由 provider 在「响应流内部报错」时调用,标记该错误为可重试的流中断。 */
|
|
17
|
+
export function markStreamInterrupted(err) {
|
|
18
|
+
if (err && typeof err === 'object')
|
|
19
|
+
interrupted.add(err);
|
|
20
|
+
}
|
|
21
|
+
/** 该错误是否被标记为流中途中断。 */
|
|
22
|
+
export function isMarkedStreamInterrupted(err) {
|
|
23
|
+
return !!err && typeof err === 'object' && interrupted.has(err);
|
|
24
|
+
}
|
package/dist/repl/commands.js
CHANGED
|
@@ -148,6 +148,7 @@ export const LLM_ERROR_HINT_KEYS = {
|
|
|
148
148
|
timeout: 'repl.llmTimeoutError',
|
|
149
149
|
network: 'repl.llmNetworkError',
|
|
150
150
|
context: 'repl.llmContextError',
|
|
151
|
+
server: 'repl.llmServerError',
|
|
151
152
|
};
|
|
152
153
|
/** /help 的分组:按使用场景归组,组内保持菜单树顺序。未列入的顶层命令兜底进「其他」。 */
|
|
153
154
|
export const HELP_GROUPS = [
|
package/docs/usage.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# MoCode 使用指南
|
|
2
|
+
|
|
3
|
+
> 面向首次使用和日常开发的菜单式帮助。命令在全屏 TUI 中输入;输入 `/` 可打开并筛选命令菜单。
|
|
4
|
+
|
|
5
|
+
## 帮助菜单
|
|
6
|
+
|
|
7
|
+
| 入口 | 适用场景 |
|
|
8
|
+
| ---------------------------------- | -------------------------------------------- |
|
|
9
|
+
| [01 快速开始](#快速开始) | 安装、配置并启动第一个会话 |
|
|
10
|
+
| [02 日常对话](#日常对话) | 把需求交给 Agent,控制执行范围 |
|
|
11
|
+
| [03 命令行](#命令行) | 新建、恢复会话和设置沙箱根目录 |
|
|
12
|
+
| [04 TUI 命令菜单](#tui-命令菜单) | 在会话内管理配置、上下文、文件与界面 |
|
|
13
|
+
| [05 PLAN / AUTO](#plan--auto-模式) | 先调研规划,或直接执行 |
|
|
14
|
+
| [06 会话与回滚](#会话与回滚) | 恢复历史、中断任务、撤销文件变更 |
|
|
15
|
+
| [07 项目上下文](#项目上下文) | `AGENTS.md` 与 Skills |
|
|
16
|
+
| [08 配置参考](#配置参考) | 配置优先级和常用环境变量 |
|
|
17
|
+
| [09 常见问题](#常见问题) | 连不上模型、工具不调用、上下文过长等 |
|
|
18
|
+
| [10 输入框快捷键](#输入框快捷键) | 输入框内的所有键盘快捷键、命令菜单与鼠标操作 |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 快速开始
|
|
23
|
+
|
|
24
|
+
**1. 安装 Node.js 18 或更高版本,然后安装 MoCode:**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g mocode-ai
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
不想全局安装时,直接运行 `npx mocode-ai`。
|
|
31
|
+
|
|
32
|
+
**2. 配置一个支持 OpenAI 风格 function calling 的模型:**
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
mocode config
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
向导会写入全局配置 `~/.mocode/config`。也可以先运行 `mocode`,再在 TUI 输入 `/model` 配置。
|
|
39
|
+
|
|
40
|
+
**3. 在目标项目目录启动:**
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mocode
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
例如:`cd your-project` 后再运行 `mocode`。Agent 的默认文件操作范围就是启动目录。
|
|
47
|
+
|
|
48
|
+
**4. 用一个可验证的目标开始:**
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
请先阅读 README 和 package.json,告诉我如何启动项目;不要修改文件。
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
确认连通后,再给出明确的开发目标,例如“为登录接口补充参数校验,并运行相关验证”。
|
|
55
|
+
|
|
56
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
57
|
+
|
|
58
|
+
## 日常对话
|
|
59
|
+
|
|
60
|
+
MoCode 会在“思考 → 调用工具 → 观察结果 → 再思考”的循环中自主推进任务。把**目标、约束和验证要求**放在一条消息里,效果最好:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
检查支付模块的重试逻辑,找出可能重复扣款的路径;先给我一个只读分析和修复计划,未经确认不要改文件。
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
实用提示:
|
|
67
|
+
|
|
68
|
+
- 先说明是否允许修改、是否允许执行命令,以及希望运行的验证。
|
|
69
|
+
- 对陌生项目,可先用 `/plan`,或直接要求“只读分析,不修改文件”。
|
|
70
|
+
- 任务运行中可按 `Ctrl+C` 打断当前轮次;不会留下半完成的工具调用。
|
|
71
|
+
- 在复杂任务中,Agent 可能维护 `.mocode/sessions/<session-id>/notes.md` 记录计划、发现与未决问题。
|
|
72
|
+
|
|
73
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
74
|
+
|
|
75
|
+
## 命令行
|
|
76
|
+
|
|
77
|
+
| 命令 | 说明 |
|
|
78
|
+
| ------------------------------ | ------------------------------------------- |
|
|
79
|
+
| `mocode` | 在当前目录开启新会话。 |
|
|
80
|
+
| `mocode config` | 运行模型配置向导,写入 `~/.mocode/config`。 |
|
|
81
|
+
| `mocode --resume` | 列出已保存会话。 |
|
|
82
|
+
| `mocode --resume <id>` | 恢复指定会话。 |
|
|
83
|
+
| `mocode --sandbox-root <path>` | 覆盖本次运行的文件操作沙箱根目录。 |
|
|
84
|
+
| `npx mocode-ai` | 无需全局安装,直接运行。 |
|
|
85
|
+
|
|
86
|
+
从源码开发时使用 `npm start`;它直接通过 `tsx` 运行源码,不会执行发布版的后台更新检查。修改 TypeScript 后请重启该命令。
|
|
87
|
+
|
|
88
|
+
> `--sandbox-root` 的优先级高于 `SANDBOX_ROOT`;没有设置时,沙箱根目录为当前工作目录。
|
|
89
|
+
|
|
90
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
91
|
+
|
|
92
|
+
## TUI 命令菜单
|
|
93
|
+
|
|
94
|
+
输入 `/` 打开下拉菜单,继续输入可筛选,`Esc` 取消。以下命令均在 TUI 中执行。
|
|
95
|
+
|
|
96
|
+
### 会话、上下文与界面
|
|
97
|
+
|
|
98
|
+
| 命令 | 作用 |
|
|
99
|
+
| -------------------------- | ---------------------------------------------------- |
|
|
100
|
+
| `/exit`、`/quit` | 退出 MoCode。 |
|
|
101
|
+
| `/clear` | 清空会话历史并清屏,保留系统提示。 |
|
|
102
|
+
| `/context` | 查看 token 与消息数的上下文使用情况。 |
|
|
103
|
+
| `/compact [focus]` | 压缩旧历史;可附焦点,例如 `/compact 保留接口约定`。 |
|
|
104
|
+
| `/compact --force [focus]` | 即使可压缩内容很少也强制压缩早期对话。 |
|
|
105
|
+
| `/resume` | 在最近会话中选择并恢复。 |
|
|
106
|
+
| `/sessions` | 浏览全部已保存会话。 |
|
|
107
|
+
| `/rollback` | 选择一个轮次,按文件决定保留或撤销其快照中的改动。 |
|
|
108
|
+
| `/theme [name]` | 选择或直接切换颜色主题。 |
|
|
109
|
+
|
|
110
|
+
### 模型、输入与工具能力
|
|
111
|
+
|
|
112
|
+
| 命令 | 作用 |
|
|
113
|
+
| ------------------------- | ---------------------------------------------------------------- |
|
|
114
|
+
| `/model` | 交互设置 Base URL、API Key、模型和上下文窗口;立即生效并持久化。 |
|
|
115
|
+
| `/skills` | 列出已发现的 Skills。 |
|
|
116
|
+
| `/image <path>` | 将本地图片附加到下一条消息。 |
|
|
117
|
+
| `/image list` | 查看待发送图片。 |
|
|
118
|
+
| `/image clear` | 清除待发送图片。 |
|
|
119
|
+
| `/fe on/off/status` | 允许或硬禁用 `browser-debug` / `desktop-observe` 自动路由。 |
|
|
120
|
+
| `/cu on/off/status` | 允许或硬禁用高危 `computer-control` 自动路由。 |
|
|
121
|
+
| `/subagent on/off/status` | 允许或硬禁用 `orchestration` 自动路由。 |
|
|
122
|
+
| `/mcp on/off/status` | 管理 MCP 连接生命周期及其动态工具簇。 |
|
|
123
|
+
| `/pet` | 打开或断开可选桌宠窗口。 |
|
|
124
|
+
| `/pet skin` | 为已运行的桌宠选择皮肤。 |
|
|
125
|
+
| `/pet quit` | 完全关闭桌宠进程。 |
|
|
126
|
+
|
|
127
|
+
### 记忆与项目上下文
|
|
128
|
+
|
|
129
|
+
| 命令 | 作用 |
|
|
130
|
+
| ------------------------------ | ------------------------------------------------------------------- |
|
|
131
|
+
| `/init` | 让 Agent 扫描项目,生成或刷新 `AGENTS.md` 项目记忆。 |
|
|
132
|
+
| `/memory` | 查看跨会话长期记忆的索引。 |
|
|
133
|
+
| `/memory_switch on/off/status` | 同时管理 memory 自动路由 gate 与 Memory Index;下一真实用户轮生效。 |
|
|
134
|
+
| `/memory_status` | 分别查看 memory route gate 与 Memory Index / 反思状态。 |
|
|
135
|
+
| `/reflect` | 手动触发一次后台记忆反思。 |
|
|
136
|
+
|
|
137
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
138
|
+
|
|
139
|
+
## PLAN / AUTO 模式
|
|
140
|
+
|
|
141
|
+
| 模式 | 适用情况 | 能力 |
|
|
142
|
+
| -------- | ------------------------------------ | ------------------------------------------------------------------------------ |
|
|
143
|
+
| **PLAN** | 先理解代码、评估风险、产出可审阅方案 | 只读调研与规划;不写文件、不执行命令、不派生子 Agent。 |
|
|
144
|
+
| **AUTO** | 需求明确,允许自主完成实现与验证 | 每轮由 LLM router 选择最小充分工具簇;能力不足时主模型可在下一 step 单向扩容。 |
|
|
145
|
+
|
|
146
|
+
- `/plan` 切换到 PLAN 模式。它适合“先分析、不要改动”的任务。
|
|
147
|
+
- `/auto` 切回 AUTO 模式,允许执行方案。
|
|
148
|
+
- 在支持的终端中,`Shift+Tab` 也可切换到 PLAN;若输入法或终端吞掉该按键,使用 `/plan` 即可。
|
|
149
|
+
|
|
150
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
151
|
+
|
|
152
|
+
## 会话与回滚
|
|
153
|
+
|
|
154
|
+
每轮对话会自动保存。启动时可用 `mocode --resume` 查找会话,或在 TUI 用 `/resume` 选择最近会话;需要浏览更久以前的历史时使用 `/sessions`。
|
|
155
|
+
|
|
156
|
+
文件修改前会按轮次创建快照。使用 `/rollback` 选中目标轮次后,可逐文件决定**保留**或**撤销**。从旧会话恢复但没有相应快照的改动无法通过该功能撤销;重要改动仍建议放在 Git 版本控制下。
|
|
157
|
+
|
|
158
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
159
|
+
|
|
160
|
+
## 项目上下文
|
|
161
|
+
|
|
162
|
+
MoCode 通过 `AGENTS.md` 与 Skills 理解项目:
|
|
163
|
+
|
|
164
|
+
| 功能 | 默认状态 | 内容与操作 |
|
|
165
|
+
| --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
166
|
+
| **`AGENTS.md`** | 按文件存在情况加载 | 每轮自动加载的 Markdown 项目记忆(同时覆盖静态文件结构、命令清单与项目约定/坑点)。用 `/init` 生成初稿,随后可手工维护。 |
|
|
167
|
+
| **Skills** | 按需加载 | 通过 `use_skill` 工具按需加载的额外能力。详见 `~/.mocode/skills/` 与 `.mocode/skills/`。 |
|
|
168
|
+
|
|
169
|
+
Skills 则是可复用的任务说明。MoCode 默认扫描:
|
|
170
|
+
|
|
171
|
+
- `~/.claude/skills/`
|
|
172
|
+
- `~/.mocode/skills/`
|
|
173
|
+
- `<项目目录>/.mocode/skills/`
|
|
174
|
+
|
|
175
|
+
每个 Skill 是带 frontmatter 的 `<名称>/SKILL.md`。系统先加载其 `description`,任务相关时再加载完整内容。用 `SKILLS_DIRS` 可覆盖默认扫描目录;Windows 用 `;` 分隔多个路径,macOS/Linux 用 `:`。
|
|
176
|
+
|
|
177
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
178
|
+
|
|
179
|
+
## MCP 与浏览器能力
|
|
180
|
+
|
|
181
|
+
MCP 和浏览器相关能力是可选扩展,不影响基本的文件编辑与命令执行。使用前先确认:
|
|
182
|
+
|
|
183
|
+
- MCP:在配置文件中设置 MCP 服务后,使用 `/mcp status` 查看连接状态,使用 `/mcp on` 或 `/mcp off` 管理运行时连接;不同 MCP 服务的配置格式以对应服务文档为准。
|
|
184
|
+
- 浏览器:`browser` 默认只访问本机 `http/https` 地址;需要访问远程站点时显式设置 `MOCODE_BROWSER_ALLOW_REMOTE=true`。首次使用前安装 Chromium:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npx playwright install chromium
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
- `dev_server` 会执行你提供的启动命令,风险等级与 `run_command` 相同;它需要确认,不要把不可信字符串直接作为启动命令传入。
|
|
191
|
+
- PLAN 模式禁用浏览器和 `dev_server`;切换到 AUTO 后才允许 Agent 使用这些能力。
|
|
192
|
+
- 退出 MoCode 时,已登记的开发服务器会被清理,浏览器会话也会关闭;如果进程是外部启动的,请自行检查并停止。
|
|
193
|
+
|
|
194
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
195
|
+
|
|
196
|
+
## 安全边界与已知限制
|
|
197
|
+
|
|
198
|
+
MoCode 可以读写项目文件并执行命令,使用前请把它当作一个需要监督的自动化开发工具:
|
|
199
|
+
|
|
200
|
+
- 默认沙箱根目录是启动目录;可用 `--sandbox-root <path>` 或 `SANDBOX_ROOT` 缩小文件操作范围。沙箱限制不等于操作系统级隔离,仍应避免在包含敏感文件的目录中运行。
|
|
201
|
+
- `safe`、`confirm`、`dangerous` 是工具风险等级。看到确认提示时,请核对命令、路径和参数,而不是只按回车。
|
|
202
|
+
- API Key 只放在 `~/.mocode/config`、项目级配置或 shell 环境变量中,不要提交到 Git,也不要粘贴到对话内容里。
|
|
203
|
+
- 回滚依赖每轮快照;从没有对应快照的旧会话恢复时,不能保证通过 `/rollback` 撤销外部产生的改动。重要项目仍建议使用 Git 提交或工作树备份。
|
|
204
|
+
- Agent 不会因为任务结束而自动运行完整测试或构建,也不会强制追加一轮验证。需要验证时,在任务中明确要求它运行哪些命令,并自行检查结果。
|
|
205
|
+
- 当前模型需要支持 OpenAI 风格 function calling;只支持普通文本生成的模型无法可靠使用工具。
|
|
206
|
+
|
|
207
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
208
|
+
|
|
209
|
+
## 常见问题
|
|
210
|
+
|
|
211
|
+
### 配置加载优先级
|
|
212
|
+
|
|
213
|
+
以下来源从低到高覆盖;已在 shell 中设置的环境变量始终最高优先级:
|
|
214
|
+
|
|
215
|
+
1. `<当前目录>/.env`(兼容旧用法)
|
|
216
|
+
2. `~/.mocode/config`(`mocode config` 与 `/model` 写入的位置)
|
|
217
|
+
3. `<当前目录>/.mocode/config`(项目级覆盖)
|
|
218
|
+
4. Shell 环境变量
|
|
219
|
+
|
|
220
|
+
最小配置:
|
|
221
|
+
|
|
222
|
+
```env
|
|
223
|
+
LLM_BASE_URL=https://api.example.com/v1
|
|
224
|
+
LLM_API_KEY=your-api-key
|
|
225
|
+
LLM_MODEL=your-model-name
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
模型必须支持 **OpenAI 风格的 function calling**,否则 MoCode 无法可靠调用工具。
|
|
229
|
+
|
|
230
|
+
### 常用环境变量
|
|
231
|
+
|
|
232
|
+
| 变量 | 用途 | 默认值 |
|
|
233
|
+
| ------------------------------- | --------------------------------------------------------------------------- | ------------------------ |
|
|
234
|
+
| `CONTEXT_WINDOW_TOKENS` | 模型实际上下文窗口大小。 | `256000` |
|
|
235
|
+
| `MAX_TOKENS` | 单次回复最大 token 数。 | 不限制 |
|
|
236
|
+
| `AUTO_COMPACT` | 上下文自动压缩开关;开启时统一在 80% 占用触发。 | `true` |
|
|
237
|
+
| `MAX_STEPS` | 每轮 Agent 工具循环的最大步数。 | `200` |
|
|
238
|
+
| `SUB_AGENT_MAX_STEPS` | 子 Agent 默认最大步数。 | `50` |
|
|
239
|
+
| `SANDBOX_ROOT` | 文件操作与命令工作目录的沙箱根。 | 当前工作目录 |
|
|
240
|
+
| `MOCODE_SUBAGENT_ENABLED` | 设 `false` 硬禁用 `orchestration`;unset/`true` 允许按需路由。 | 未设置 |
|
|
241
|
+
| `MOCODE_FRONTEND_TOOLS_ENABLED` | 设 `false` 硬禁用 browser/desktop 路由簇;unset/`true` 允许。 | 未设置 |
|
|
242
|
+
| `MOCODE_COMPUTER_USE_ENABLED` | 设 `false` 硬禁用高危 `computer-control`;unset/`true` 允许明确意图时路由。 | 未设置 |
|
|
243
|
+
| `MEMORY_ENABLED` | 设 `false` 硬禁用 memory 簇;`true` 还会启用 Memory Index。 | 未设置 |
|
|
244
|
+
| `MOCODE_THEME` | TUI 颜色主题。 | `default` |
|
|
245
|
+
| `ANYSEARCH_API_KEY` | 可选联网搜索 API Key。 | 未设置时使用匿名免费额度 |
|
|
246
|
+
|
|
247
|
+
完整注释示例见仓库根目录的 [`.env.example`](../.env.example)。
|
|
248
|
+
|
|
249
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
250
|
+
|
|
251
|
+
## 输入框快捷键
|
|
252
|
+
|
|
253
|
+
在 TUI 底部的输入框内,几乎所有编辑都通过键盘完成。下表覆盖当前版本支持的全部快捷键;若与你的终端有冲突(例如某些终端把 `Ctrl+Backspace` 当作普通退格),以终端实际发送为准。
|
|
254
|
+
|
|
255
|
+
### 光标移动
|
|
256
|
+
|
|
257
|
+
| 按键 | 作用 |
|
|
258
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
259
|
+
| `←` / `→` | 左 / 右移动一个字符;已到行首或行尾时跨到上一行 / 下一行 |
|
|
260
|
+
| `↑` / `↓` | 多行输入时上下移动一行;已在首行 / 末行且未打开命令菜单时,改为**滚动内容区**(每格 3 行,等同鼠标滚轮) |
|
|
261
|
+
| `Home` / `Ctrl+A` / `Ctrl+Q` | 跳到当前行行首 |
|
|
262
|
+
| `End` / `Ctrl+E` | 跳到当前行行尾(`Ctrl+Q` 与 `Ctrl+E` 在键盘顶行相邻,构成左右对称的行首/行尾对) |
|
|
263
|
+
|
|
264
|
+
### 编辑与删除
|
|
265
|
+
|
|
266
|
+
| 按键 | 作用 |
|
|
267
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
268
|
+
| `Backspace` | 删除光标前一个字符;在行首时并入上一行;光标紧贴粘贴块时删除整个粘贴块 |
|
|
269
|
+
| `Delete` | 删除光标后一个字符;在行尾时并入下一行 |
|
|
270
|
+
| `Ctrl+U` | 删除从行首到光标处的所有内容 |
|
|
271
|
+
| `Ctrl+K` | 删除从光标到行尾的所有内容;在行尾时并入下一行 |
|
|
272
|
+
|
|
273
|
+
### 撤销清空
|
|
274
|
+
|
|
275
|
+
| 按键 | 作用 |
|
|
276
|
+
| -------- | ------------------------------------------------------------------------------ |
|
|
277
|
+
| `Ctrl+Z` | 撤销一次 `Ctrl+C` 造成的输入框清空(单次:仅还原清空前的内容,再次按下无效果) |
|
|
278
|
+
|
|
279
|
+
### 换行、发送与会话控制
|
|
280
|
+
|
|
281
|
+
| 按键 | 作用 |
|
|
282
|
+
| ----------------------------------------------------- | ------------------------------------------------------- |
|
|
283
|
+
| `Enter` | 发送消息,开始一轮 Agent 执行 |
|
|
284
|
+
| `Ctrl+J` / `Ctrl+Enter` / `Alt+Enter` / `Shift+Enter` | 在输入框内插入换行,用于编写多行消息(不直接发送) |
|
|
285
|
+
| `Ctrl+C` | 输入框**有内容**时清空输入框;**空**输入框时退出 MoCode |
|
|
286
|
+
| `Ctrl+D` | 输入框为空时退出 MoCode;有内容时忽略 |
|
|
287
|
+
|
|
288
|
+
> 提示:`Ctrl+C` 在 Agent **运行中**用于中断当前轮次(见[日常对话](#日常对话)),在输入框**空闲**时用于清空——两者行为不同。
|
|
289
|
+
|
|
290
|
+
### 滚动内容区(输入框聚焦时也可使用)
|
|
291
|
+
|
|
292
|
+
| 按键 | 作用 |
|
|
293
|
+
| -------- | ------------- |
|
|
294
|
+
| `PgUp` | 向上翻一页 |
|
|
295
|
+
| `PgDn` | 向下翻一页 |
|
|
296
|
+
| `Ctrl+↑` | 向上滚动 5 行 |
|
|
297
|
+
| `Ctrl+↓` | 向下滚动 5 行 |
|
|
298
|
+
|
|
299
|
+
### 命令菜单与补全
|
|
300
|
+
|
|
301
|
+
| 按键 | 作用 |
|
|
302
|
+
| --------- | ---------------------------------------------- |
|
|
303
|
+
| `/` | 进入命令菜单,继续输入可筛选命令 |
|
|
304
|
+
| `↑` / `↓` | 菜单打开时在候选间移动 |
|
|
305
|
+
| `Tab` | 选中当前高亮项并补全(例如 `/model` 的子命令) |
|
|
306
|
+
| `Esc` | 处于子菜单时回到上一级;否则关闭菜单 |
|
|
307
|
+
|
|
308
|
+
### 模式切换
|
|
309
|
+
|
|
310
|
+
| 按键 | 作用 |
|
|
311
|
+
| ----------- | -------------------------------------------------------------------- |
|
|
312
|
+
| `Shift+Tab` | 在 PLAN / AUTO 模式之间切换(若终端吞掉该键,改用 `/plan`、`/auto`) |
|
|
313
|
+
|
|
314
|
+
### 粘贴
|
|
315
|
+
|
|
316
|
+
- 直接 `Ctrl+V`(或中键 / 右键,取决于终端)粘贴大段文本或多行内容时,MoCode 会识别为粘贴:整段作为**不可编辑的粘贴块**一次性插入,提交时还原为原文。这避免逐字符触发编辑,也防止超长文本卡顿。
|
|
317
|
+
- **连续粘贴会生成多个独立的粘贴块**(如 `[📋 121 行 · 2.7K 字符][📋 121 行 · 2.7K 字符]` 紧邻),每个块互不影响,不会把新内容并入旧块。
|
|
318
|
+
- **两个粘贴块之间的文字是可编辑的**:在块之间敲的字、回退、插入都正常生效;在块前按 `Backspace` 删除该块、在块后按 `Delete` 删除下一块。
|
|
319
|
+
- 短小的单行粘贴(≤8 行且 ≤200 字符)会当作普通可编辑文本插入,不生成块。
|
|
320
|
+
|
|
321
|
+
[↑ 返回帮助菜单](#帮助菜单)
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 常见问题
|
|
326
|
+
|
|
327
|
+
**启动后无法回复,或提示未配置模型**
|
|
328
|
+
运行 `mocode config` 或 TUI 中的 `/model`,检查 `LLM_BASE_URL`、`LLM_API_KEY`、`LLM_MODEL` 三项。若 shell 中设置了同名变量,它会覆盖配置文件值。
|
|
329
|
+
|
|
330
|
+
**Agent 不调用工具**
|
|
331
|
+
确认模型和后端支持 OpenAI 风格 function calling;纯文本聊天模型无法可靠执行工具调用。
|
|
332
|
+
|
|
333
|
+
**Agent 操作了错误目录,或文件被沙箱拒绝**
|
|
334
|
+
在正确项目目录启动 `mocode`,或明确设置 `--sandbox-root <path>` / `SANDBOX_ROOT`。沙箱会拒绝越界相对路径、沙箱外绝对路径和符号链接逃逸。
|
|
335
|
+
|
|
336
|
+
**上下文快满了**
|
|
337
|
+
使用 `/context` 查看用量,使用 `/compact` 压缩;也可以缩小任务、明确焦点,或将 `CONTEXT_WINDOW_TOKENS` 设置为模型真实窗口。
|
|
338
|
+
|
|
339
|
+
**联网搜索失败或限流**
|
|
340
|
+
可设置 `ANYSEARCH_API_KEY` 使用自己的额度;不设置时会使用匿名免费额度并受 IP 限流。
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
还需要定位具体能力时,可从 [帮助菜单](#帮助菜单) 返回,或在 TUI 输入 `/` 查看当前版本实际提供的命令。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mocode-ai",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "终端编码 agent:LLM + tool-call 循环 + 流式输出(含思考)+ 25 个工具,接任意 OpenAI 兼容后端。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"bin",
|
|
13
|
-
"README.md"
|
|
13
|
+
"README.md",
|
|
14
|
+
"README.zh-CN.md",
|
|
15
|
+
"docs/usage.md"
|
|
14
16
|
],
|
|
15
17
|
"workspaces": [
|
|
16
18
|
"packages/*"
|