mocode-ai 1.2.7 → 1.2.9

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 (129) hide show
  1. package/dist/agent/core.js +126 -43
  2. package/dist/config/index.js +31 -6
  3. package/dist/config/presets.js +36 -1
  4. package/dist/context/budget.js +5 -16
  5. package/dist/llm/index.js +42 -4
  6. package/dist/repl/index.js +57 -13
  7. package/dist/session/compact.js +329 -40
  8. package/dist/session/notes.js +63 -0
  9. package/dist/session/scheduler.js +5 -9
  10. package/dist/tools/constants.js +21 -0
  11. package/package.json +1 -1
  12. package/dist/__trace_manual_test__.js +0 -1
  13. package/dist/agent/core.d.ts +0 -112
  14. package/dist/agent/index.d.ts +0 -19
  15. package/dist/agent/mode.d.ts +0 -29
  16. package/dist/agent/retry-classifier.js +0 -64
  17. package/dist/agent/spawn.d.ts +0 -36
  18. package/dist/attachments/image.d.ts +0 -22
  19. package/dist/commands/config.d.ts +0 -8
  20. package/dist/commands/skill.js +0 -230
  21. package/dist/config/file.d.ts +0 -23
  22. package/dist/config/index.d.ts +0 -114
  23. package/dist/config/presets.d.ts +0 -57
  24. package/dist/context/budget.d.ts +0 -79
  25. package/dist/context/classifier.d.ts +0 -14
  26. package/dist/context/encoders/_util.d.ts +0 -11
  27. package/dist/context/encoders/code.d.ts +0 -2
  28. package/dist/context/encoders/doc.d.ts +0 -14
  29. package/dist/context/encoders/graph.d.ts +0 -11
  30. package/dist/context/encoders/graph.js +0 -81
  31. package/dist/context/encoders/index.d.ts +0 -2
  32. package/dist/context/encoders/log.d.ts +0 -2
  33. package/dist/context/encoders/log.js +0 -2
  34. package/dist/context/encoders/memory.d.ts +0 -2
  35. package/dist/context/encoders/passthrough.d.ts +0 -11
  36. package/dist/context/encoders/search.d.ts +0 -2
  37. package/dist/context/encoders/summary.d.ts +0 -12
  38. package/dist/context/encoders/table.d.ts +0 -2
  39. package/dist/context/encoders/tree.d.ts +0 -2
  40. package/dist/context/index.d.ts +0 -6
  41. package/dist/context/lifecycle.d.ts +0 -51
  42. package/dist/context/pipeline.d.ts +0 -9
  43. package/dist/context/registry.d.ts +0 -9
  44. package/dist/context/relevance.d.ts +0 -65
  45. package/dist/context/types.d.ts +0 -36
  46. package/dist/foo.js +0 -28
  47. package/dist/foo.test.js +0 -12
  48. package/dist/index.d.ts +0 -1
  49. package/dist/llm/capabilities.d.ts +0 -19
  50. package/dist/llm/index.d.ts +0 -111
  51. package/dist/memory/discover.d.ts +0 -15
  52. package/dist/memory/index.d.ts +0 -13
  53. package/dist/memory/reflect.d.ts +0 -34
  54. package/dist/memory/store.d.ts +0 -124
  55. package/dist/pet/bridge.d.ts +0 -73
  56. package/dist/pet/protocol.d.ts +0 -83
  57. package/dist/pet/state.d.ts +0 -28
  58. package/dist/plan/active.d.ts +0 -23
  59. package/dist/plan/active.js +0 -45
  60. package/dist/plan/index.d.ts +0 -13
  61. package/dist/plan/index.js +0 -33
  62. package/dist/plan/state.d.ts +0 -2
  63. package/dist/plan/state.js +0 -11
  64. package/dist/plan/store.d.ts +0 -78
  65. package/dist/plan/store.js +0 -429
  66. package/dist/project-skill/index.js +0 -95
  67. package/dist/project-skill/initializer.js +0 -178
  68. package/dist/project-snapshot/index.js +0 -85
  69. package/dist/project-snapshot/llm-snapshot.js +0 -150
  70. package/dist/project-snapshot/static-files.js +0 -87
  71. package/dist/repl/index.d.ts +0 -22
  72. package/dist/rollback/index.d.ts +0 -79
  73. package/dist/sandbox/command.d.ts +0 -3
  74. package/dist/sandbox/index.d.ts +0 -4
  75. package/dist/sandbox/jail.d.ts +0 -17
  76. package/dist/sandbox/policy.d.ts +0 -21
  77. package/dist/sandbox/root.d.ts +0 -5
  78. package/dist/session/compact.d.ts +0 -92
  79. package/dist/session/index.d.ts +0 -13
  80. package/dist/session/notes-plan.js +0 -41
  81. package/dist/session/persist.d.ts +0 -30
  82. package/dist/session/scheduler.d.ts +0 -53
  83. package/dist/skills/discover.d.ts +0 -33
  84. package/dist/skills/index.d.ts +0 -13
  85. package/dist/skills/skill-eval.js +0 -345
  86. package/dist/skills/skill-improve.js +0 -221
  87. package/dist/skills/stats.js +0 -102
  88. package/dist/tools/builtins/apply-patch.js +0 -174
  89. package/dist/tools/builtins/ask-human.d.ts +0 -9
  90. package/dist/tools/builtins/codegraph.d.ts +0 -2
  91. package/dist/tools/builtins/codegraph.js +0 -128
  92. package/dist/tools/builtins/edit-file.d.ts +0 -2
  93. package/dist/tools/builtins/glob.d.ts +0 -2
  94. package/dist/tools/builtins/grep.d.ts +0 -2
  95. package/dist/tools/builtins/index.d.ts +0 -2
  96. package/dist/tools/builtins/memory-forget.d.ts +0 -2
  97. package/dist/tools/builtins/memory-list.d.ts +0 -2
  98. package/dist/tools/builtins/memory-save.d.ts +0 -2
  99. package/dist/tools/builtins/memory-search.d.ts +0 -2
  100. package/dist/tools/builtins/memory-update.d.ts +0 -2
  101. package/dist/tools/builtins/project-skill-update.js +0 -102
  102. package/dist/tools/builtins/read-file.d.ts +0 -2
  103. package/dist/tools/builtins/run-command.d.ts +0 -2
  104. package/dist/tools/builtins/switch-mode.d.ts +0 -2
  105. package/dist/tools/builtins/switch-mode.js +0 -44
  106. package/dist/tools/builtins/task.d.ts +0 -2
  107. package/dist/tools/builtins/todolist.d.ts +0 -2
  108. package/dist/tools/builtins/todolist.js +0 -411
  109. package/dist/tools/builtins/use-skill.d.ts +0 -2
  110. package/dist/tools/builtins/web-fetch.d.ts +0 -2
  111. package/dist/tools/builtins/web-search.d.ts +0 -2
  112. package/dist/tools/builtins/write-file.d.ts +0 -2
  113. package/dist/tools/constants.d.ts +0 -52
  114. package/dist/tools/registry.d.ts +0 -18
  115. package/dist/tools/retry.js +0 -137
  116. package/dist/tools/types.d.ts +0 -42
  117. package/dist/ui/batch.d.ts +0 -67
  118. package/dist/ui/clipboard.d.ts +0 -9
  119. package/dist/ui/content.d.ts +0 -55
  120. package/dist/ui/diff.d.ts +0 -34
  121. package/dist/ui/intervention.d.ts +0 -46
  122. package/dist/ui/layout.d.ts +0 -225
  123. package/dist/ui/markdown.d.ts +0 -46
  124. package/dist/ui/mouse.d.ts +0 -29
  125. package/dist/ui/prompt.d.ts +0 -61
  126. package/dist/ui/render.d.ts +0 -60
  127. package/dist/ui/spinner.d.ts +0 -26
  128. package/dist/ui/theme.d.ts +0 -47
  129. package/dist/ui/thinking.js +0 -80
@@ -1,112 +0,0 @@
1
- import type OpenAI from 'openai';
2
- import { type ChatMessage, type ChatUsage, type ToolCallRef } from '../llm/index.js';
3
- /** 解析工具 arguments JSON;非法或空返 null(调用方据此降级到普通 preview)。 */
4
- declare function parseArgs(raw: string): Record<string, unknown> | null;
5
- /** 只读工具集:一轮多个时,连续的只读工具成组 Promise.all 并行(无副作用、互不依赖)。 */
6
- declare const READ_TOOL_NAMES: Set<string>;
7
- /** mutation 工具:写盘 + 在 executeTool 内记回滚 before 快照,必须串行保快照序。 */
8
- declare const isMutationTool: (name: string) => boolean;
9
- /** 工具调用 ● 头所需信息(交给 hooks 渲染;core 不直接写屏)。 */
10
- export interface ToolCallView {
11
- name: string;
12
- arguments: string;
13
- id: string;
14
- }
15
- /** mutation 执行前读旧内容供 diff:write_file 取整文件旧内容(不存在→null=新建),
16
- * edit_file 取 old_string 起始行号(供 diff 显示真实文件行号)。读不到则 diff 退化为相对行号。
17
- * 非 mutation 或参数非法返 { preWriteOld: null, editStartLine: 1 }。失败不阻断。 */
18
- declare function readDiffContext(tc: ToolCallRef, parsed: Record<string, unknown> | null): {
19
- preWriteOld: string | null;
20
- editStartLine: number;
21
- };
22
- /**
23
- * agent 循环的展示副作用接缝。主 agent 注入 TUI 渲染实现;子 agent 注入静默/摘要实现。
24
- * 所有方法可选——core 对 undefined hooks 安全跳过。
25
- */
26
- export interface AgentHooks {
27
- /** 流式正文增量(主 agent:走 markdown 渲染写内容区)。 */
28
- onText?: (delta: string) => void;
29
- /** 模型开始生成某 tool_call 的参数(主 agent:补换行 + 启「生成中」spinner)。 */
30
- onToolCall?: (name: string) => void;
31
- /** 每步开始,spinner 启「思考中」(主 agent:spinner.start)。 */
32
- onStepStart?: () => void;
33
- /** chat 返回后停 spinner(主 agent:spinner.stop)。 */
34
- onChatDone?: () => void;
35
- /** 流式正文末尾补换行(若 onToolCall 已补则 no-op);防 ● 行黏在正文行尾。 */
36
- onTextEnd?: () => void;
37
- /** 工具调用 ● 头渲染(主 agent:工具名 + 参数摘要)。 */
38
- onToolHeader?: (tc: ToolCallRef) => void;
39
- /** 启「执行 工具」spinner(主 agent:spinner.start)。 */
40
- onToolStart?: (name: string) => void;
41
- /** 工具执行完停 spinner(主 agent:spinner.stop)。 */
42
- onToolDone?: () => void;
43
- /** 工具结果渲染(主 agent:mutation 走 diff 块;其余走一行 preview)。 */
44
- onToolResult?: (tc: ToolCallRef, output: string, parsed: Record<string, unknown> | null, preWriteOld: string | null, editStartLine: number) => void;
45
- /** 工具步末尾补一空行(与下一轮思考/正文分隔)。 */
46
- onToolBatchEnd?: () => void;
47
- /** 无回复提示(模型既无文本也无工具调用)。 */
48
- onNoReply?: () => void;
49
- /** 达到最大步数提示。 */
50
- onMaxSteps?: () => void;
51
- /** 中断还原:停 spinner + 补换行 + (已中断)提示 + history 还原 + 模式还原。 */
52
- onAbort?: () => void;
53
- /** 跑完(正常/达上限)在回复末尾打耗时摘要行;中断不调。
54
- * usage 是本轮 chat 调用累计的 token 用量(未开启 include_usage 或全失败时为 undefined)。 */
55
- onDone?: (elapsedMs: number, usage?: ChatUsage) => void;
56
- }
57
- /** runAgentCore 的运行选项。 */
58
- export interface AgentRunOptions {
59
- history: ChatMessage[];
60
- /** 纯文本字符串,或多模态 parts 数组(OpenAI content 数组,text + image_url)。 */
61
- userInput: string | ContentPart[];
62
- signal?: AbortSignal;
63
- /** 每步 chat() 返回后回调:repl 据此重算并重画状态行 context 用量条。 */
64
- onContextUpdate?: () => void;
65
- hooks: AgentHooks;
66
- /** 步数上限;缺省 = config.maxSteps。子 agent 可传更低值。 */
67
- maxSteps?: number;
68
- /** 工具 schema 覆盖;plan 模式传 planChatTools(只读子集)。子 agent 可传受限子集。
69
- * 缺省 = 按 getAgentMode() 自动选(auto=全量 / plan=只读)。 */
70
- toolsOverride?: OpenAI.Chat.Completions.ChatCompletionTool[];
71
- /** 跳过回滚快照记录(子 agent 逻辑隔离用)。true = 本 agent 的 write_file/edit_file 改动
72
- * 不进主回滚链,主 /rollback 不撤销。透传给 executeTool。 */
73
- skipRollback?: boolean;
74
- }
75
- /** OpenAI content array 的子集(text + image_url);repl 构造 user 多模态消息用。 */
76
- export type ContentPart = {
77
- type: 'text';
78
- text: string;
79
- } | {
80
- type: 'image_url';
81
- image_url: {
82
- url: string;
83
- detail?: 'auto' | 'low' | 'high';
84
- };
85
- };
86
- /** runAgentCore 的运行结果。 */
87
- export interface AgentRunResult {
88
- /** 正常完毕 / 达上限 true;中断 false。 */
89
- completed: boolean;
90
- /** 最终 assistant 文本回复(content);无回复或中断为 null。 */
91
- finalText: string | null;
92
- /** 本轮累计 token 用量(各 chat 步 prompt+completion 之和);后端不开 include_usage 或全失败则 undefined。 */
93
- usage?: ChatUsage;
94
- }
95
- /**
96
- * agent 核心循环(纯逻辑):
97
- * 流式调 LLM(经 hooks.onText 实时渲染)→ 有 tool_calls 就分组执行并回灌
98
- * → 否则流式正文即最终回复。history 在调用间持久,由调用方持有。
99
- * 步前经 session/maybeCompact 自动压缩(接近窗口上限时三层压缩);
100
- * 工具结果进 history 前经 Context Optimization Pipeline(optimizeToolResult:类型化编码 + 长度裁剪)。
101
- *
102
- * 中断语义:signal 经 executeTool(name, args, signal) 串进工具;run_command/web_fetch 等 abort 即时杀
103
- * (树杀子进程 / 取消 fetch),循环顶 if(signal.aborted) 兜底还原。不会留下未配对的 tool_call_id。
104
- * abort 时 history 还原到本 turn 前(savedHistory 浅拷贝),模式还原,调 hooks.onAbort。
105
- *
106
- * 所有展示副作用经 hooks 注入;core 自身不直接调 layout / spinner(不依赖 ui/layout.ts)。
107
- * 但 core 仍依赖 ui/render.ts 的纯函数(summarizeToolCall / truncateDisplay / fmtElapsed)——
108
- * 这些是纯字符串格式化,无副作用,共享安全。
109
- */
110
- export declare function runAgentCore(opts: AgentRunOptions): Promise<AgentRunResult>;
111
- export { parseArgs, readDiffContext, isMutationTool, READ_TOOL_NAMES };
112
- export type { ChatMessage, ToolCallRef, ChatUsage } from '../llm/index.js';
@@ -1,19 +0,0 @@
1
- import type { ChatMessage } from '../llm/index.js';
2
- import { type AgentRunResult, type ContentPart } from './core.js';
3
- /**
4
- * agent 核心循环(主 agent,TUI 渲染版):
5
- * 流式调 LLM(onText 实时写内容区)→ 有 tool_calls 就执行并回灌
6
- * → 否则流式正文即最终回复。history 在调用间持久,由 REPL 持有。
7
- * 步前经 session/maybeCompact 自动压缩(接近窗口上限时三层压缩);
8
- * 工具结果进 history 前经 capToolResultForHistory 裁到单条上限。
9
- *
10
- * 所有正文写经 layout.contentWrite(保证落在内容区、跟踪续写位、底栏不被顶);
11
- * spinner 经 onFrame 回调刷状态行(layout.drawStatusBar),等待时内容区静止、底栏转圈。
12
- * 思考期间不写思考内容,只让 spinner 持续转「思考中…」(首个正文 / tool_call token 到达才停)。
13
- *
14
- * 循环逻辑委托 runAgentCore;本函数只注入 TUI 渲染 hooks(layout + spinner + diff + 回滚轮次)。
15
- * 开新轮次(beginTurn)在入口调——core 不依赖 rollback,回滚轮次是主 agent 的展示副作用。
16
- */
17
- export declare function runAgent(history: ChatMessage[], userInput: string | ContentPart[], signal?: AbortSignal,
18
- /** 每步 chat() 返回后回调:repl 据此重算并重画状态行 context 用量条(运行中实时刷新,不冻结在轮首)。 */
19
- onContextUpdate?: () => void): Promise<AgentRunResult>;
@@ -1,29 +0,0 @@
1
- /**
2
- * agent 模式的共享状态(零依赖纯叶子)。
3
- *
4
- * 把 `agentMode` 从 repl 的模块变量提到这里,让三方都能用、且不破坏依赖单向:
5
- * - `tools/builtins/switch-mode.ts` 写它(setAgentMode)——LLM 在 agent 循环里自切 plan↔auto。
6
- * - `agent/index.ts` 每步读它(getAgentMode)——决定 chat() 用全量 chatTools 还是 planChatTools 只读子集,
7
- * 以及串行分支的 plan 防御 backstop。这样 LLM 中途切模式后,下一次 chat() 立即看到新工具集。
8
- * - `repl/index.ts` 读写它 + 注册 onModeChange 监听器(做 applyMode 重写 history[0] + refreshStatusBase
9
- * 刷状态行 modeTag)。
10
- *
11
- * 依赖方向无环:本模块不 import 任何业务模块。`agent/index → tools/registry → tools/builtins/switch-mode
12
- * → agent/mode` 链终点是本叶子,不回到 agent/index。`tools → agent/mode` 与既有 `tools → ui`(ask-human)、
13
- * `tools → rollback`(registry)同性质——都是引叶子。
14
- *
15
- * listener 同步触发:setAgentMode 在变更模式后同步调 listener(无 async)。switch_mode 工具在 executeTool
16
- * 内调 setAgentMode → listener 同步 applyMode(重写 history[0])+ refreshStatusBase;execute 返回字符串后,
17
- * agent 串行分支继续,下一步 chat() 读到新模式 + 新系统提示,一致。
18
- */
19
- export type AgentMode = 'auto' | 'plan';
20
- /** 当前 agent 模式。auto=全工具执行;plan=只读探查 + 产出计划(写盘/命令/记忆写入工具被 schema 剔除)。 */
21
- export declare function getAgentMode(): AgentMode;
22
- /**
23
- * 设置 agent 模式。同模式 no-op(不触发 listener)。变更时同步触发 onModeChange 注册的监听器
24
- * (repl 在 startRepl 注册:applyMode 重写 history[0] + refreshStatusBase 刷状态行)。
25
- * 返回之前的模式,供调用方(如 runAgent 中断恢复)还原。
26
- */
27
- export declare function setAgentMode(m: AgentMode): AgentMode;
28
- /** 注册模式变更监听器(单一,后注册覆盖先注册)。repl 在 startRepl 启动时注册一次。 */
29
- export declare function onModeChange(cb: (m: AgentMode) => void): void;
@@ -1,64 +0,0 @@
1
- // RETRY-01: 错误反思分类器。
2
- //
3
- // 在 tools/retry.ts 之上叠加一层"反思"语义:把每个 ToolOutcomeCode 映射到
4
- // 一个 ErrorCategory,供 (a) PROMPT 反思 prompt 注入、(b) QUAL-01 trace 指标。
5
- //
6
- // 设计要点:
7
- // - 纯映射函数,无副作用 → 易测,易扩展(新 code → 改一处)。
8
- // - 6 类对齐路线图 L163:`TRANSIENT_RATE_LIMIT` / `TRANSIENT_TIMEOUT` /
9
- // `INVALID_ARGUMENTS` / `PERMISSION_DENIED` / `CONFLICT` / `UNKNOWN_FAILURE`。
10
- // - 提供"反思指针"模板(reflectionHint),与 PROMPT-01 hard rule
11
- // / PROMPT-02 checklist 共用同一套"先想清楚再动"语言,避免新造话。
12
- // - 不**决策**重试与否(`shouldRetry` 在 tools/retry.ts 已经稳定;本次不动),
13
- // 只**注解**每个错误"该反思什么"。
14
- /** code → category 的稳定映射。fixture 直接断言(避免漏改)。 */
15
- const CODE_TO_CATEGORY = {
16
- OK: 'UNKNOWN_FAILURE', // OK 不该走到这里;归 UNKNOWN 是为了编译期不漏。
17
- // rate-limit / timeout / network
18
- TIMEOUT: 'TRANSIENT_TIMEOUT',
19
- HTTP_ERROR: 'TRANSIENT_RATE_LIMIT', // 4xx/5xx 中除 408/429 之外的 5xx 视为 rate-limit 语义
20
- NETWORK_ERROR: 'TRANSIENT_TIMEOUT', // 网络层错(ECONNRESET 等)→ 与 timeout 同类反思
21
- // 参数 / schema(模型自己改,不是 retry 自己改)
22
- INVALID_JSON: 'INVALID_ARGUMENTS',
23
- INVALID_ARGUMENTS: 'INVALID_ARGUMENTS',
24
- INVALID_TOOL_SCHEMA: 'INVALID_ARGUMENTS',
25
- UNKNOWN_TOOL: 'INVALID_ARGUMENTS', // 调用了不存在的工具 → 模型改 tool name
26
- // 权限 / 沙箱 / 模式(永久拒绝)
27
- SANDBOX_DENIED: 'PERMISSION_DENIED',
28
- PERMISSION_DENIED: 'PERMISSION_DENIED',
29
- TOOL_DISABLED: 'PERMISSION_DENIED',
30
- MODE_DENIED: 'PERMISSION_DENIED',
31
- ABORTED: 'PERMISSION_DENIED', // 用户主动 abort,与 permission 同类(无 retry 价值)
32
- // 冲突 / 写失败(retry 之前必须重新读)
33
- EDIT_CONFLICT: 'CONFLICT',
34
- CHANGE_CONFLICT: 'CONFLICT',
35
- PATCH_INVALID: 'CONFLICT',
36
- POSTCONDITION_FAILED: 'CONFLICT',
37
- PROCESS_FAILED: 'CONFLICT',
38
- // 兜底
39
- EXECUTION_ERROR: 'UNKNOWN_FAILURE',
40
- MCP_ERROR: 'UNKNOWN_FAILURE',
41
- };
42
- export function classifyError(code) {
43
- return CODE_TO_CATEGORY[code];
44
- }
45
- /** 反思指针:每类错误给 LLM 一句"反思什么"的话。 */
46
- const REFLECTION_HINTS = {
47
- TRANSIENT_RATE_LIMIT: 'The remote is throttling or returned 5xx. Re-running the same call with identical arguments is unlikely to help — wait, downgrade call frequency, or reduce request size; do not retry the same args in tight loop.',
48
- TRANSIENT_TIMEOUT: 'A network or process timeout occurred. Re-running the same call may help once, but if it fails again with identical args, the path/host/argument is wrong; switch tool, reduce scope, or ask the user.',
49
- INVALID_ARGUMENTS: 'The tool rejected the call shape (JSON / schema / unknown tool). Read the tool description again and fix the arguments yourself; do not resend the same call and do not retry automatically — only the model can fix argument shape.',
50
- PERMISSION_DENIED: 'The call was denied (sandbox / permission / disabled / mode). Retry will not help; surface the constraint to the user and ask for guidance or a permission grant.',
51
- CONFLICT: 'A write/patch conflicted with the on-disk state. Do not resend the same args; re-read the file or change target, then re-derive the diff. If the conflict is structural, the plan itself is wrong — go back to the spec.',
52
- UNKNOWN_FAILURE: 'An unclassified error occurred. Do not retry blindly; capture the message, re-read the tool description, and decide whether the same call with a smaller scope or a different tool is appropriate. If unsure, ask the user.',
53
- };
54
- export function reflectionHint(category) {
55
- return REFLECTION_HINTS[category];
56
- }
57
- /**
58
- * 一站式:对 ToolOutcome 给出"反思 category + 反思 hint"。
59
- * 调用方一般是 tools/retry.ts 的 onRetry hook,把 hint 注入 retry 提示尾部。
60
- */
61
- export function reflectOn(code) {
62
- const category = classifyError(code);
63
- return { category, hint: reflectionHint(category) };
64
- }
@@ -1,36 +0,0 @@
1
- /** 子 agent 运行选项。 */
2
- export interface SpawnOptions {
3
- /** 子任务指令(作为子 agent 的 user 消息)。 */
4
- prompt: string;
5
- /** 附加系统提示(角色/约束),拼在 SUBAGENT_SUFFIX 后。 */
6
- systemPromptSuffix?: string;
7
- /** 允许的工具名白名单(可选)。无 = 全量工具;给则从 chatTools 过滤。 */
8
- tools?: string[];
9
- /** 步数上限(可选,默认 config.subAgentMaxSteps ?? 50)。 */
10
- maxSteps?: number;
11
- /** 主 agent 的 abort signal(可选)。透传给子 runAgentCore → chat/executeTool,
12
- * 主 Ctrl+C 树杀子 agent(chat 流式 abort + run_command/web_fetch 即时取消)。 */
13
- signal?: AbortSignal;
14
- }
15
- /** 子 agent 运行结果。 */
16
- export interface SpawnResult {
17
- /** 子 agent 最终文本回复;中断或无回复为 null。 */
18
- summary: string | null;
19
- /** 正常完毕 true;中断 false。 */
20
- completed: boolean;
21
- /** 子 agent 中间过程的人类可读日志(工具调用 + 结果摘要 + 流式正文片段)。主 agent 通常不看,调试用。 */
22
- transcript: string;
23
- }
24
- /**
25
- * 派生一个子 agent 执行独立子任务。
26
- *
27
- * 行为:
28
- * - 构造独立 history:[{system: 主系统提示 + SUBAGENT_SUFFIX + 自定义后缀}, {user: prompt}]
29
- * - 工具子集:按 opts.tools 白名单过滤 chatTools;无白名单 = 全量。
30
- * - 静默 hooks:流式正文 / 工具头 / 结果缓冲到 transcript;不写主屏(layout)。
31
- * - 返回 { summary, completed, transcript }。summary 给 task 工具回灌主 history。
32
- *
33
- * 中断:opts.signal 透传给子 runAgentCore——主 Ctrl+C 树杀子 agent(chat abort + 工具 abort)。
34
- * 子 agent 跑在主 signal 下,主 abort 即子 abort;子 agent 的 abortRestore 还原子 history + 模式。
35
- */
36
- export declare function spawnAgent(opts: SpawnOptions): Promise<SpawnResult>;
@@ -1,22 +0,0 @@
1
- export type ImageMime = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp';
2
- export interface ImageAttachment {
3
- id: string;
4
- path: string;
5
- name: string;
6
- bytes: number;
7
- mime: ImageMime;
8
- dataUrl: string;
9
- }
10
- export declare const MAX_INLINE_BYTES_DEFAULT: number;
11
- export declare function detectMime(p: string): ImageMime | null;
12
- export declare function renderChip(att: ImageAttachment): string;
13
- export type LoadImageResult = {
14
- ok: true;
15
- att: ImageAttachment;
16
- } | {
17
- ok: false;
18
- reason: string;
19
- };
20
- export declare function loadImageAttachment(input: string, opts: {
21
- maxBytes: number;
22
- }): Promise<LoadImageResult>;
@@ -1,8 +0,0 @@
1
- /**
2
- * 首跑配置向导:交互填 LLM_BASE_URL / LLM_API_KEY / LLM_MODEL,写 ~/.mocode/config。
3
- * 只交互三键、保留文件里其它键(MAX_TOKENS / CONTEXT_WINDOW_TOKENS / MOCODE_THEME 等)。
4
- * prompt 全纯文本(readline 光标按字符算,不能含 ANSI)。
5
- * 由 index.ts 在 `mocode config` 时动态加载,故不 import config/index.ts(避免触发 config 单例初始化 / loadEnvFiles,
6
- * 直接退出);只 import config/file.ts(纯 I/O 叶子,无 env 校验 / process.exit)。
7
- */
8
- export declare function runConfigWizard(): Promise<void>;
@@ -1,230 +0,0 @@
1
- // `mocode skill` CLI 子命令(skill 自进化 Phase 0/1 的用户入口)。
2
- //
3
- // mocode skill eval <name> [--runs N] [--threshold x] [--timeout ms]
4
- // 触发评测:对 <skill-dir>/evals/trigger.json 的每条 query 跑单轮 agent,
5
- // 统计 use_skill/run_skill 触发率,输出 PASS/FAIL 报告并落盘 JSON。
6
- //
7
- // mocode skill improve <name> [--runs N] [--threshold x] [--iterations N]
8
- // [--holdout x] [--timeout ms] [--apply]
9
- // description 进化循环:train/holdout 切分 + LLM 提案 + 接受门,默认 dry-run
10
- // 只打印最佳 description;--apply 才写回 SKILL.md(写前显式确认;非 TTY 拒绝)。
11
- //
12
- // mocode skill usage [name]
13
- // 展示使用台账(Phase 0):按 skill 的调用次数/成功率/最近失败。
14
- //
15
- // 由 index.ts 在 `mocode skill …` 时动态加载(与 mocode config 同模式):
16
- // 此时才引入 config 单例(LLM 配置)+ agent 依赖图,缺 LLM 配置时给友好报错而非崩。
17
- // 纯打印/非 TUI:本进程不进 alt screen,输出走 stdout。
18
- import * as readline from 'node:readline';
19
- import path from 'node:path';
20
- import { config, isModelConfigured } from '../config/index.js';
21
- import { listSkills } from '../skills/index.js';
22
- import { loadSkillForEval, loadTriggerEvalSet, triggerEvalTemplate, triggerEvalPath, runTriggerEval, renderTriggerReport, saveTriggerReport, validateEvalParams, } from '../skills/skill-eval.js';
23
- import { runImproveLoop, applyImprovedDescription } from '../skills/skill-improve.js';
24
- import { loadSkillUsage, aggregateSkillStats, skillStatsPath } from '../skills/stats.js';
25
- function usage() {
26
- console.log(`mocode skill — skill 自进化(触发评测 / description 进化 / 使用台账)
27
-
28
- 用法:
29
- mocode skill eval <name> [选项] 触发评测(需要 <skill-dir>/evals/trigger.json)
30
- mocode skill improve <name> [选项] description 进化循环(默认 dry-run)
31
- mocode skill usage [name] 展示使用台账
32
-
33
- eval 选项:
34
- --runs <n> 每 query 运行次数(默认 3;1..10)
35
- --threshold <x> 触发率判定阈值(默认 0.5;>0 且 ≤1)
36
- --timeout <ms> 单 query 超时(默认 60000)
37
-
38
- improve 选项:
39
- --runs <n> 同 eval(默认 3)
40
- --threshold <x> 同 eval(默认 0.5)
41
- --iterations <n> 迭代上限(默认 5)
42
- --holdout <x> holdout 比例(默认 0.4;0 禁用)
43
- --timeout <ms> 单 query 超时(默认 60000)
44
- --apply 把最佳 description 写回 SKILL.md(默认 dry-run,仅打印)
45
-
46
- eval 集格式(<skill-dir>/evals/trigger.json,非空数组):
47
- [
48
- { "query": "应该触发该 skill 的真实请求", "should_trigger": true },
49
- { "query": "不应触发的相近请求", "should_trigger": false }
50
- ]
51
-
52
- 注: 进化对象仅限 ~/.mocode/skills 与 <cwd>/.mocode/skills 下的 skill(内置 skill 不可进化)。
53
- 没有 evals/trigger.json 的 skill 只能 eval 前手工补建,improve 一律拒绝(没验证门不优化)。`);
54
- }
55
- function numArg(args, name, fallback) {
56
- const i = args.indexOf(name);
57
- if (i === -1 || i + 1 >= args.length)
58
- return fallback;
59
- const v = Number(args[i + 1]);
60
- if (!Number.isFinite(v) || v <= 0) {
61
- throw new Error(`${name} 需要正数: ${args[i + 1]}`);
62
- }
63
- return v;
64
- }
65
- function parseCommon(args) {
66
- const runs = Math.round(numArg(args, '--runs', 3));
67
- const threshold = numArg(args, '--threshold', 0.5);
68
- const timeoutMs = Math.round(numArg(args, '--timeout', 60_000));
69
- const err = validateEvalParams(runs, threshold);
70
- if (err)
71
- throw new Error(err);
72
- return { runs, threshold, timeoutMs };
73
- }
74
- function requireModel() {
75
- if (!isModelConfigured()) {
76
- console.error('未配置 LLM(缺 LLM_BASE_URL / LLM_API_KEY)。先运行 `mocode config` 或设置环境变量。');
77
- process.exit(1);
78
- }
79
- }
80
- /** 定位 eval 集;缺失时打印模板并退出(不猜、不自动建)。 */
81
- function requireEvalSet(skillName) {
82
- const skill = loadSkillForEval(skillName);
83
- const cases = loadTriggerEvalSet(skill);
84
- if (!cases) {
85
- console.error(`未找到触发评测集: ${path.relative(process.cwd(), triggerEvalPath(skill))}`);
86
- console.error('手工创建该文件(格式):');
87
- console.error(triggerEvalTemplate(skill));
88
- process.exit(1);
89
- }
90
- return { skill, cases };
91
- }
92
- async function evalCommand(args) {
93
- const rest = args.slice();
94
- const name = rest.find((a) => !a.startsWith('--'));
95
- if (!name)
96
- throw new Error('缺少 skill 名。见: mocode skill eval --help');
97
- requireModel();
98
- const { skill, cases } = requireEvalSet(name);
99
- const { runs, threshold, timeoutMs } = parseCommon(rest);
100
- console.log(`评测 skill "${skill.name}" — ${cases.length} 条 query × ${runs} 次,模型 ${config.model}\n`);
101
- const startedAt = Date.now();
102
- const report = await runTriggerEval(skill, skill.description, cases, runs, threshold, {
103
- timeoutMs,
104
- onProgress: (_d, _t, line) => process.stdout.write(line + '\n'),
105
- });
106
- const saved = saveTriggerReport(report);
107
- console.log(`\n${renderTriggerReport(report, { runsPerQuery: runs, threshold })}`);
108
- console.log(`\n耗时 ${((Date.now() - startedAt) / 1000).toFixed(1)}s,结果已存: ${path.relative(process.cwd(), saved)}`);
109
- if (report.summary.passed < report.summary.total) {
110
- console.log('存在失败项。可用 `mocode skill improve ' + skill.name + '` 尝试自动优化 description(dry-run)。');
111
- process.exitCode = 1;
112
- }
113
- }
114
- function confirmApply(skillName) {
115
- if (!process.stdin.isTTY) {
116
- // 非 TTY fail closed:自动落盘必须有人在场。
117
- console.error('非 TTY 环境拒绝 --apply 自动落盘。请在终端运行,或手工编辑 SKILL.md 的 description。');
118
- process.exit(1);
119
- }
120
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
121
- return new Promise((resolve) => {
122
- rl.question(`确认把新 description 写回 skill "${skillName}" 的 SKILL.md?(y/N) `, (ans) => {
123
- rl.close();
124
- resolve(ans.trim().toLowerCase() === 'y' || ans.trim().toLowerCase() === 'yes');
125
- });
126
- });
127
- }
128
- async function improveCommand(args) {
129
- const rest = args.slice();
130
- const name = rest.find((a) => !a.startsWith('--'));
131
- if (!name)
132
- throw new Error('缺少 skill 名。见: mocode skill improve --help');
133
- requireModel();
134
- const { skill, cases } = requireEvalSet(name);
135
- const { runs, threshold, timeoutMs } = parseCommon(rest);
136
- const iterations = Math.round(numArg(rest, '--iterations', 5));
137
- const holdout = (() => {
138
- const i = rest.indexOf('--holdout');
139
- const v = i === -1 ? 0.4 : Number(rest[i + 1]);
140
- if (i !== -1 && (!Number.isFinite(v) || v < 0 || v > 0.9))
141
- throw new Error('--holdout 需要 0..0.9 的数');
142
- return v;
143
- })();
144
- const apply = rest.includes('--apply');
145
- console.log(`进化 skill "${skill.name}" — ${cases.length} 条 query,train/holdout=${1 - holdout}/${holdout},${apply ? '将写回(--apply)' : 'dry-run(不落盘)'}\n`);
146
- const result = await runImproveLoop(skill, cases, {
147
- maxIterations: iterations,
148
- runsPerQuery: runs,
149
- threshold,
150
- holdout,
151
- timeoutMs,
152
- onIteration: (_i, _max, line) => console.log(line),
153
- });
154
- console.log('');
155
- if (!result.improved) {
156
- console.log(`没有更优的 description(原 description 已是最佳或循环未产出改进)。`);
157
- console.log(`原: ${result.originalDescription}`);
158
- return;
159
- }
160
- console.log(`原 description: ${result.originalDescription}`);
161
- console.log(`新 description: ${result.bestDescription}`);
162
- if (apply) {
163
- const ok = await confirmApply(skill.name);
164
- if (!ok) {
165
- console.log('已取消写回(dry-run 结果见上,可手工应用)。');
166
- return;
167
- }
168
- applyImprovedDescription(skill, result.bestDescription);
169
- console.log(`已写回: ${skill.skillMdPath}`);
170
- console.log('提示: 内容哈希已变更,project 级 skill 下次 run_skill 会重新要求信任确认。');
171
- }
172
- else {
173
- console.log('dry-run:未写文件。确认满意后加 --apply 重跑,或直接手工把新 description 写进 SKILL.md。');
174
- }
175
- }
176
- function usageCommand(args) {
177
- const filter = args.find((a) => !a.startsWith('--'));
178
- const records = loadSkillUsage();
179
- const summaries = aggregateSkillStats(records);
180
- const list = filter ? summaries.filter((s) => s.skill === filter) : summaries;
181
- if (list.length === 0) {
182
- console.log(`(台账为空: ${path.relative(process.cwd(), skillStatsPath())})`);
183
- console.log('台账在模型调用 use_skill / run_skill 时自动记录,跑几个会话后这里有数。');
184
- return;
185
- }
186
- for (const s of list) {
187
- const rate = s.runSuccessRate === null ? '' : ` run 成功率 ${(s.runSuccessRate * 100).toFixed(0)}%`;
188
- console.log(`${s.skill} ×${s.total}(use ${s.uses} / run ${s.runs})${rate} 最近 ${s.lastUsedAt}`);
189
- if (s.lastFailure) {
190
- console.log(` 最近失败: ${s.lastFailure.status}${s.lastFailure.code ? ` (${s.lastFailure.code})` : ''} @ ${s.lastFailure.ts}`);
191
- }
192
- }
193
- }
194
- export async function runSkillCommand(args) {
195
- const sub = args[0];
196
- if (!sub || sub === '--help' || sub === '-h' || sub === 'help') {
197
- usage();
198
- return;
199
- }
200
- try {
201
- if (sub === 'eval')
202
- await evalCommand(args.slice(1));
203
- else if (sub === 'improve')
204
- await improveCommand(args.slice(1));
205
- else if (sub === 'usage')
206
- usageCommand(args.slice(1));
207
- else {
208
- console.error(`未知子命令 "${sub}"。`);
209
- usage();
210
- process.exitCode = 1;
211
- }
212
- }
213
- catch (e) {
214
- const msg = e instanceof Error ? e.message : String(e);
215
- if (/aborted/i.test(msg)) {
216
- console.error('\n已中断。');
217
- process.exitCode = 130;
218
- }
219
- else {
220
- console.error(`错误: ${msg}`);
221
- process.exitCode = 1;
222
- }
223
- }
224
- }
225
- // 供 index.ts 判断子命令名集合(避免它 parse 我们的参数)。
226
- export const SKILL_SUBCOMMANDS = ['eval', 'improve', 'usage', 'help', '--help', '-h'];
227
- // listSkills 在 eval/improve 未命中时供报错文案复用(保持与 /skills 一致的名字集)。
228
- export function listSkillNames() {
229
- return listSkills().map((s) => s.name);
230
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * ~/.mocode/config 全局 dotenv 配置的读写叶子(纯 node:fs / node:os / node:path + dotenv)。
3
- *
4
- * 独立于 `config/index.ts`——**不**触发 config 单例初始化 / loadEnvFiles,故 `commands/config.ts`
5
- * (首跑向导,刻意不 import config/index.ts)与 `repl/index.ts`(`/theme` 持久化)都能安全共享。
6
- * 主题等 UI 偏好走 `updateConfigKey` 单键写;向导多键一次性写走 `writeConfigKeys`。
7
- */
8
- /** ~/.mocode/config:全局配置(与 ~/.mocode/skills 同目录,任意终端 / 任意目录生效)。 */
9
- export declare const CONFIG_PATH: string;
10
- /** 读已有配置(没有则空对象),用于回填默认值与保留其它键。 */
11
- export declare function readConfigFile(): Record<string, string>;
12
- /**
13
- * 读-合并-写:把 entries 覆盖进 ~/.mocode/config,保留文件里其它键。
14
- * mkdirSync 兜底(首跑无 ~/.mocode)。不吞 I/O 异常——向导路径让其抛(与历史行为一致);
15
- * UI 偏好路径用 `updateConfigKey`(自带 try/catch 静默)。
16
- */
17
- export declare function writeConfigKeys(entries: Record<string, string>): void;
18
- /**
19
- * 单键持久化(主题等 UI 偏好):写失败静默——下次启动读不到则回退默认,不阻断 REPL。
20
- * 注意:shell env 设了同名键时,`config/index.ts` 的 loadEnvFiles 只 backfill undefined 的
21
- * process.env,故文件写对**下次启动**可能被 shell 盖——调用方据此给 dim 警告。
22
- */
23
- export declare function updateConfigKey(key: string, value: string): void;