mocode-ai 0.4.7 → 0.4.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.
- package/dist/agent/core.d.ts +112 -0
- package/dist/agent/core.js +51 -11
- package/dist/agent/index.d.ts +19 -0
- package/dist/agent/mode.d.ts +29 -0
- package/dist/agent/spawn.d.ts +36 -0
- package/dist/attachments/image.d.ts +22 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/config/file.d.ts +23 -0
- package/dist/config/index.d.ts +114 -0
- package/dist/config/index.js +48 -1
- package/dist/config/presets.d.ts +57 -0
- package/dist/context/budget.d.ts +79 -0
- package/dist/context/classifier.d.ts +14 -0
- package/dist/context/encoders/_util.d.ts +11 -0
- package/dist/context/encoders/code.d.ts +2 -0
- package/dist/context/encoders/doc.d.ts +14 -0
- package/dist/context/encoders/graph.d.ts +11 -0
- package/dist/context/encoders/index.d.ts +2 -0
- package/dist/context/encoders/log.d.ts +2 -0
- package/dist/context/encoders/memory.d.ts +2 -0
- package/dist/context/encoders/passthrough.d.ts +11 -0
- package/dist/context/encoders/search.d.ts +2 -0
- package/dist/context/encoders/summary.d.ts +12 -0
- package/dist/context/encoders/table.d.ts +2 -0
- package/dist/context/encoders/tree.d.ts +2 -0
- package/dist/context/index.d.ts +6 -0
- package/dist/context/lifecycle.d.ts +51 -0
- package/dist/context/pipeline.d.ts +9 -0
- package/dist/context/registry.d.ts +9 -0
- package/dist/context/relevance.d.ts +65 -0
- package/dist/context/types.d.ts +36 -0
- package/dist/index.d.ts +1 -0
- package/dist/llm/capabilities.d.ts +19 -0
- package/dist/llm/index.d.ts +111 -0
- package/dist/memory/discover.d.ts +15 -0
- package/dist/memory/index.d.ts +13 -0
- package/dist/memory/reflect.d.ts +34 -0
- package/dist/memory/store.d.ts +124 -0
- package/dist/permissions/index.js +138 -0
- package/dist/pet/bridge.d.ts +73 -0
- package/dist/pet/protocol.d.ts +83 -0
- package/dist/pet/state.d.ts +28 -0
- package/dist/plan/active.d.ts +23 -0
- package/dist/plan/index.d.ts +13 -0
- package/dist/plan/state.d.ts +2 -0
- package/dist/plan/store.d.ts +78 -0
- package/dist/project-skill/index.js +129 -0
- package/dist/project-skill/initializer.js +179 -0
- package/dist/project-snapshot/index.js +177 -0
- package/dist/project-snapshot/static-files.js +87 -0
- package/dist/repl/index.d.ts +22 -0
- package/dist/repl/index.js +159 -1
- package/dist/rollback/index.d.ts +79 -0
- package/dist/sandbox/command.d.ts +3 -0
- package/dist/sandbox/index.d.ts +4 -0
- package/dist/sandbox/jail.d.ts +17 -0
- package/dist/sandbox/policy.d.ts +21 -0
- package/dist/sandbox/root.d.ts +5 -0
- package/dist/session/compact.d.ts +92 -0
- package/dist/session/drop.d.ts +19 -0
- package/dist/session/index.d.ts +13 -0
- package/dist/session/persist.d.ts +30 -0
- package/dist/session/scheduler.d.ts +53 -0
- package/dist/skills/discover.d.ts +33 -0
- package/dist/skills/index.d.ts +13 -0
- package/dist/tools/builtins/ask-human.d.ts +9 -0
- package/dist/tools/builtins/codegraph.d.ts +2 -0
- package/dist/tools/builtins/codegraph.js +17 -4
- package/dist/tools/builtins/drop-context.d.ts +18 -0
- package/dist/tools/builtins/edit-file.d.ts +2 -0
- package/dist/tools/builtins/edit-file.js +1 -0
- package/dist/tools/builtins/glob.d.ts +2 -0
- package/dist/tools/builtins/grep.d.ts +2 -0
- package/dist/tools/builtins/index.d.ts +2 -0
- package/dist/tools/builtins/index.js +7 -0
- package/dist/tools/builtins/memory-forget.d.ts +2 -0
- package/dist/tools/builtins/memory-forget.js +1 -0
- package/dist/tools/builtins/memory-list.d.ts +2 -0
- package/dist/tools/builtins/memory-save.d.ts +2 -0
- package/dist/tools/builtins/memory-save.js +1 -0
- package/dist/tools/builtins/memory-search.d.ts +2 -0
- package/dist/tools/builtins/memory-update.d.ts +2 -0
- package/dist/tools/builtins/memory-update.js +1 -0
- package/dist/tools/builtins/project-skill-update.js +73 -0
- package/dist/tools/builtins/read-file.d.ts +2 -0
- package/dist/tools/builtins/read-file.js +17 -1
- package/dist/tools/builtins/run-command.d.ts +2 -0
- package/dist/tools/builtins/run-command.js +1 -0
- package/dist/tools/builtins/switch-mode.d.ts +2 -0
- package/dist/tools/builtins/task.d.ts +2 -0
- package/dist/tools/builtins/task.js +1 -0
- package/dist/tools/builtins/todolist.d.ts +2 -0
- package/dist/tools/builtins/use-skill.d.ts +2 -0
- package/dist/tools/builtins/web-fetch.d.ts +2 -0
- package/dist/tools/builtins/web-search.d.ts +2 -0
- package/dist/tools/builtins/web-search.js +12 -1
- package/dist/tools/builtins/write-file.d.ts +2 -0
- package/dist/tools/builtins/write-file.js +1 -0
- package/dist/tools/constants.d.ts +52 -0
- package/dist/tools/registry.d.ts +18 -0
- package/dist/tools/types.d.ts +42 -0
- package/dist/ui/batch.d.ts +67 -0
- package/dist/ui/clipboard.d.ts +9 -0
- package/dist/ui/content.d.ts +55 -0
- package/dist/ui/content.js +14 -3
- package/dist/ui/diff.d.ts +34 -0
- package/dist/ui/diff.js +15 -24
- package/dist/ui/intervention.d.ts +46 -0
- package/dist/ui/layout.d.ts +225 -0
- package/dist/ui/layout.js +10 -0
- package/dist/ui/markdown.d.ts +46 -0
- package/dist/ui/mouse.d.ts +29 -0
- package/dist/ui/prompt.d.ts +61 -0
- package/dist/ui/render.d.ts +60 -0
- package/dist/ui/spinner.d.ts +26 -0
- package/dist/ui/theme.d.ts +47 -0
- package/dist/updater/index.d.ts +22 -0
- package/package.json +1 -1
package/dist/repl/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import readline from 'node:readline/promises';
|
|
2
2
|
import { emitKeypressEvents } from 'node:readline';
|
|
3
3
|
import { stdin, stdout } from 'node:process';
|
|
4
|
-
import { config, updateModelConfig, isModelConfigured, updateMemoryConfig, isMemoryEnabled, buildBasePrompt, getPlanModeSuffix, } from '../config/index.js';
|
|
4
|
+
import { config, updateModelConfig, isModelConfigured, updateMemoryConfig, isMemoryEnabled, isProjectSkillEnabled, updateProjectSkillConfig, buildBasePrompt, getPlanModeSuffix, } from '../config/index.js';
|
|
5
5
|
import { updateConfigKey, writeConfigKeys, CONFIG_PATH } from '../config/file.js';
|
|
6
6
|
import { deletePreset, getPreset, isValidPresetName, listPresets, migrateCurrentToPreset, savePreset, } from '../config/presets.js';
|
|
7
7
|
import { runAgent } from '../agent/index.js';
|
|
@@ -24,6 +24,7 @@ import { listTurns, planRollback, applyRollback, persistSnapshots, loadSnapshots
|
|
|
24
24
|
import { listSkills, effectiveSystemPrompt, } from '../skills/index.js';
|
|
25
25
|
import { buildMemorySection, buildMemoryIndexSection, kickoffReflection, drainMemoryBackground, getLastReflectResult, clearLastReflectResult, snapshotTranscript, formatReflectResult, loadAll, } from '../memory/index.js';
|
|
26
26
|
import { buildActivePlanSection, onActivePlanChange, hasActivePlan, getActivePlanSummary, } from '../plan/index.js';
|
|
27
|
+
import { buildSnapshot as buildProjectSnapshot } from '../project-snapshot/index.js';
|
|
27
28
|
/**
|
|
28
29
|
* readline 的 prompt 必须是纯文本(无 ANSI):readline 按字符数算光标位置,
|
|
29
30
|
* 颜色码会让光标错位、编辑时漂移。颜色只用在直接 stdout.write 的横幅 / 工具行 / 回复。
|
|
@@ -41,6 +42,7 @@ const SLASH_COMMANDS = [
|
|
|
41
42
|
{ name: '/rollback', desc: '菜单选轮次回滚(↑↓·Enter)' },
|
|
42
43
|
{ name: '/memory', desc: '记忆库:条目计数与近期索引(关闭时提示先开 /memory_switch)' },
|
|
43
44
|
{ name: '/memory_switch', desc: '切换记忆子系统开关(无参=切换;/on 或 /off 显式;持久化 MEMORY_ENABLED)' },
|
|
45
|
+
{ name: '/project_skill', desc: '项目专属 Skill 开关 + 查看/初始化(无参=切换;/on·/off·/view·/init)' },
|
|
44
46
|
{ name: '/memory_status', desc: '查看记忆子系统当前开关与原理' },
|
|
45
47
|
{ name: '/reflect', desc: '手动触发后台记忆反思 pass(需先开启记忆)' },
|
|
46
48
|
{ name: '/init', desc: '扫描项目生成 MOCODE.md 项目记忆(需先开启记忆)' },
|
|
@@ -49,6 +51,7 @@ const SLASH_COMMANDS = [
|
|
|
49
51
|
{ name: '/model switch', desc: '↑↓·Enter 在已配置预设间切换' },
|
|
50
52
|
{ name: '/model list', desc: '列出已经配置的模型' },
|
|
51
53
|
{ name: '/model delete <name>', desc: '删除已配置的模型' },
|
|
54
|
+
{ name: '/refresh_snapshot', desc: '刷新项目快照(重新扫描静态文件,更新缓存)' },
|
|
52
55
|
{ name: '/plan', desc: '切到 plan 模式(只读探查+产出计划)' },
|
|
53
56
|
{ name: '/auto', desc: '切回 auto 模式(全工具执行)' },
|
|
54
57
|
{ name: '/pet', desc: '开关桌宠(独立悬浮窗,展示 agent 状态动画)' },
|
|
@@ -175,6 +178,8 @@ function runningStateFor(cmd) {
|
|
|
175
178
|
return { status: '回滚', placeholder: '选择轮次…' };
|
|
176
179
|
case '/init':
|
|
177
180
|
return { status: '初始化', placeholder: '生成 MOCODE.md…' };
|
|
181
|
+
case '/refresh_snapshot':
|
|
182
|
+
return { status: '刷新快照', placeholder: '扫描项目文件中…' };
|
|
178
183
|
case '/plan':
|
|
179
184
|
return { status: '切 plan', placeholder: '…' };
|
|
180
185
|
case '/auto':
|
|
@@ -191,6 +196,8 @@ function runningStateFor(cmd) {
|
|
|
191
196
|
return { status: '切记忆开关', placeholder: '切换中…' };
|
|
192
197
|
case '/memory_status':
|
|
193
198
|
return { status: '查记忆状态', placeholder: '…' };
|
|
199
|
+
case '/project_skill':
|
|
200
|
+
return { status: '项目 Skill', placeholder: '处理中…' };
|
|
194
201
|
default:
|
|
195
202
|
// 输入框留空(运行中可 typeahead 打字,dim 回显);运行状态由内联 spinner 承载(思考中/执行…),
|
|
196
203
|
// 状态行只显走时——故常态 status 留空,不塞「处理」这种与内联重复的泛标签。
|
|
@@ -538,6 +545,14 @@ export async function startRepl(initialHistory, sessionId, updateNotice = null,
|
|
|
538
545
|
// 沙箱根:文件操作边界。优先级 --sandbox-root > SANDBOX_ROOT env > process.cwd()。
|
|
539
546
|
// 纯边界记录(不 chdir),jail.ts 内部 resolve。子 agent 同进程继承全局 root。
|
|
540
547
|
setSandboxRoot(sandboxRootOverride ?? config.sandboxRoot ?? process.cwd());
|
|
548
|
+
// 项目快照:sandboxRoot 设定后立即构建/加载(同步,小文件几十 ms)。
|
|
549
|
+
// 构建失败不阻断 REPL:snapshot 内部 catch 所有异常,此处再兜一层。
|
|
550
|
+
if (config.projectSnapshotEnabled) {
|
|
551
|
+
try {
|
|
552
|
+
buildProjectSnapshot();
|
|
553
|
+
}
|
|
554
|
+
catch { /* ignore */ }
|
|
555
|
+
}
|
|
541
556
|
// 构造系统提示:auto 用 base;plan 在 base 后追加按当前开关现拼的 plan suffix。
|
|
542
557
|
// 切模式时 applyMode 重算 history[0](history[0] 恒 system,compaction 保它,不破坏)。
|
|
543
558
|
// 活跃 plan 摘要拼在 memory 段后(systemPrompt 的尾段),todo 工具变更后 listener 重写 history[0]。
|
|
@@ -1135,6 +1150,31 @@ export async function startRepl(initialHistory, sessionId, updateNotice = null,
|
|
|
1135
1150
|
}
|
|
1136
1151
|
continue;
|
|
1137
1152
|
}
|
|
1153
|
+
if (line === '/refresh_snapshot') {
|
|
1154
|
+
if (!config.projectSnapshotEnabled) {
|
|
1155
|
+
layout.contentWrite(`${ui.dim}(项目快照功能已关闭,MOCODE_PROJECT_SNAPSHOT=false)${ui.reset}\n`);
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
// buildProjectSnapshot 是同步操作(扫顶层小文件,几十 ms),不需要 spinner
|
|
1159
|
+
try {
|
|
1160
|
+
const snap = buildProjectSnapshot();
|
|
1161
|
+
const fileCount = Object.keys(snap.files).length;
|
|
1162
|
+
const moduleCount = snap.structure.modules.length;
|
|
1163
|
+
const configCount = snap.structure.configFiles.length;
|
|
1164
|
+
layout.contentWrite(`${ui.cyan}✓ 项目快照已刷新${ui.reset}: ${fileCount} 个静态文件 · ${moduleCount} 个模块 · ${configCount} 个配置文件\n`);
|
|
1165
|
+
layout.contentWrite(`${ui.dim}文件: ${Object.keys(snap.files).join(', ')}${ui.reset}\n`);
|
|
1166
|
+
layout.contentWrite(`${ui.dim}模块: ${snap.structure.modules.join(', ')}${ui.reset}\n`);
|
|
1167
|
+
// 刷新 history[0]:buildSnapshotSection 内部 loadSnapshot() 会拿到新快照,
|
|
1168
|
+
// buildSystemMessage 重新拼 system prompt,快照段落就更新了。
|
|
1169
|
+
history[0] = { role: 'system', content: buildSystemMessage(getAgentMode() === 'plan') };
|
|
1170
|
+
layout.contentWrite(`${ui.dim}(system prompt 已同步刷新)${ui.reset}\n`);
|
|
1171
|
+
}
|
|
1172
|
+
catch (e) {
|
|
1173
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1174
|
+
layout.contentWrite(`${ui.red}[错误]${ui.reset} 刷新快照失败: ${msg}\n`);
|
|
1175
|
+
}
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1138
1178
|
if (line === '/sessions') {
|
|
1139
1179
|
// /sessions:浏览全部已保存会话(慢路径,readdir+全量 JSON.parse,目录 N 大时会有可感知卡顿)。
|
|
1140
1180
|
// 默认走 /resume(仅最近 10 条,瞬开);要翻历史续接更早的会话才用这条。
|
|
@@ -1665,6 +1705,124 @@ export async function startRepl(initialHistory, sessionId, updateNotice = null,
|
|
|
1665
1705
|
}
|
|
1666
1706
|
continue;
|
|
1667
1707
|
}
|
|
1708
|
+
if (line === '/project_skill' ||
|
|
1709
|
+
line.startsWith('/project_skill ')) {
|
|
1710
|
+
// /project_skill — 项目专属 Skill 总开关 + 查看/编辑。
|
|
1711
|
+
// 用法:
|
|
1712
|
+
// /project_skill 切换 on/off
|
|
1713
|
+
// /project_skill on|off 显式开关
|
|
1714
|
+
// /project_skill view 查看当前内容
|
|
1715
|
+
// /project_skill edit 打开编辑器修改
|
|
1716
|
+
try {
|
|
1717
|
+
const arg = line.startsWith('/project_skill ')
|
|
1718
|
+
? line.slice('/project_skill '.length).trim().toLowerCase()
|
|
1719
|
+
: '';
|
|
1720
|
+
// /project_skill view — 查看当前内容
|
|
1721
|
+
if (arg === 'view') {
|
|
1722
|
+
const enabled = isProjectSkillEnabled();
|
|
1723
|
+
layout.contentWrite(`${ui.cyan}项目专属 Skill:${ui.reset} ${enabled ? `${ui.green}开启` : `${ui.yellow}关闭`}${ui.reset}\n`);
|
|
1724
|
+
if (enabled) {
|
|
1725
|
+
const { readProjectSkill } = await import('../project-skill/index.js');
|
|
1726
|
+
const content = readProjectSkill();
|
|
1727
|
+
if (content) {
|
|
1728
|
+
layout.contentWrite(`${ui.dim}--- 内容 ---${ui.reset}\n${content}\n${ui.dim}--- 结束 ---${ui.reset}\n`);
|
|
1729
|
+
}
|
|
1730
|
+
else {
|
|
1731
|
+
layout.contentWrite(`${ui.dim}(尚未创建,可用 /project_skill init 生成初始内容)${ui.reset}\n`);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
else {
|
|
1735
|
+
layout.contentWrite(`${ui.dim}(功能已关闭,用 /project_skill on 开启)${ui.reset}\n`);
|
|
1736
|
+
}
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
// /project_skill init — 扫描项目并生成/优化 skill
|
|
1740
|
+
if (arg === 'init') {
|
|
1741
|
+
if (!isProjectSkillEnabled()) {
|
|
1742
|
+
layout.contentWrite(`${ui.yellow}⚠ 项目专属 Skill 尚未开启${ui.reset},请先运行 ${ui.cyan}/project_skill on${ui.reset}\n`);
|
|
1743
|
+
continue;
|
|
1744
|
+
}
|
|
1745
|
+
const { readProjectSkill, writeProjectSkill } = await import('../project-skill/index.js');
|
|
1746
|
+
const existing = readProjectSkill();
|
|
1747
|
+
if (existing) {
|
|
1748
|
+
layout.contentWrite(`${ui.cyan}⏳ 正在深度探索项目并优化现有 skill...${ui.reset}\n`);
|
|
1749
|
+
}
|
|
1750
|
+
else {
|
|
1751
|
+
layout.contentWrite(`${ui.cyan}⏳ 正在深度探索项目(子 agent 将使用工具扫描代码、架构、配置等)...${ui.reset}\n`);
|
|
1752
|
+
}
|
|
1753
|
+
layout.contentWrite(`${ui.dim}提示: 按 Ctrl+C 可中断${ui.reset}\n\n`);
|
|
1754
|
+
// 派生子 agent 深度探索项目
|
|
1755
|
+
const { generateInitialSkill } = await import('../project-skill/initializer.js');
|
|
1756
|
+
const result = await generateInitialSkill(existing ?? undefined, currentAbort?.signal);
|
|
1757
|
+
// 显示探索过程日志
|
|
1758
|
+
if (result.transcript) {
|
|
1759
|
+
layout.contentWrite(`${ui.dim}--- 探索过程 ---${ui.reset}\n`);
|
|
1760
|
+
layout.contentWrite(result.transcript);
|
|
1761
|
+
layout.contentWrite(`${ui.dim}--- 探索结束 ---${ui.reset}\n\n`);
|
|
1762
|
+
}
|
|
1763
|
+
if (result.ok && result.content) {
|
|
1764
|
+
const writeResult = writeProjectSkill(result.content);
|
|
1765
|
+
if (writeResult.ok) {
|
|
1766
|
+
layout.contentWrite(`${ui.green}✓ 项目 Skill 已生成${ui.reset}\n`);
|
|
1767
|
+
layout.contentWrite(`${ui.dim}内容预览:${ui.reset}\n${result.content.slice(0, 500)}${result.content.length > 500 ? '...' : ''}\n`);
|
|
1768
|
+
layout.contentWrite(`\n${ui.dim}文件: ${ui.cyan}.mocode/project-skill.md${ui.reset} (${result.content.length} 字符)\n`);
|
|
1769
|
+
layout.contentWrite(`${ui.dim}下次启动时会自动注入到系统提示词。Agent 也会在开发过程中持续更新。${ui.reset}\n`);
|
|
1770
|
+
layout.contentWrite(`${ui.dim}提示: 可用 ${ui.cyan}/project_skill view${ui.reset} 查看完整内容,或手动编辑文件完善。${ui.dim}${ui.reset}\n`);
|
|
1771
|
+
}
|
|
1772
|
+
else {
|
|
1773
|
+
layout.contentWrite(`${ui.red}✗ 写入失败:${ui.reset} ${writeResult.error}\n`);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
else {
|
|
1777
|
+
layout.contentWrite(`${ui.red}✗ 探索失败:${ui.reset} ${result.error}\n`);
|
|
1778
|
+
if (result.transcript) {
|
|
1779
|
+
layout.contentWrite(`${ui.dim}子 agent 输出了部分内容(见上方),但未能生成完整的 skill 文档。${ui.reset}\n`);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
continue;
|
|
1783
|
+
}
|
|
1784
|
+
// 开关切换
|
|
1785
|
+
let nextEnabled;
|
|
1786
|
+
if (arg === '') {
|
|
1787
|
+
nextEnabled = !isProjectSkillEnabled();
|
|
1788
|
+
}
|
|
1789
|
+
else if (['on', 'true', '1', 'yes', 'y', 'enable', 'enabled'].includes(arg)) {
|
|
1790
|
+
nextEnabled = true;
|
|
1791
|
+
}
|
|
1792
|
+
else if (['off', 'false', '0', 'no', 'n', 'disable', 'disabled'].includes(arg)) {
|
|
1793
|
+
nextEnabled = false;
|
|
1794
|
+
}
|
|
1795
|
+
else {
|
|
1796
|
+
layout.contentWrite(`${ui.yellow}/project_skill 用法:${ui.reset}\n` +
|
|
1797
|
+
` /project_skill 切换(开↔关)\n` +
|
|
1798
|
+
` /project_skill on|off 显式设值\n` +
|
|
1799
|
+
` /project_skill view 查看当前内容\n` +
|
|
1800
|
+
` /project_skill init 扫描项目生成/优化 skill(可重复运行)\n`);
|
|
1801
|
+
continue;
|
|
1802
|
+
}
|
|
1803
|
+
const prev = isProjectSkillEnabled();
|
|
1804
|
+
if (nextEnabled === prev) {
|
|
1805
|
+
layout.contentWrite(`${ui.dim}(已是 ${nextEnabled ? '开启' : '关闭'},未变更 — 持久化字段未写入)${ui.reset}\n`);
|
|
1806
|
+
continue;
|
|
1807
|
+
}
|
|
1808
|
+
updateProjectSkillConfig(nextEnabled);
|
|
1809
|
+
updateConfigKey('MOCODE_PROJECT_SKILL', nextEnabled ? 'true' : 'false');
|
|
1810
|
+
const note = nextEnabled
|
|
1811
|
+
? `${ui.green}已开启项目专属 Skill${ui.reset} — project_skill_update 工具进入工具表;` +
|
|
1812
|
+
`项目 Skill 内容会在下次拼 system message 时注入。工具表快照需重启 REPL 才完整刷新。`
|
|
1813
|
+
: `${ui.yellow}已关闭项目专属 Skill${ui.reset} — project_skill_update 工具将在下次拼 system message 时从工具表过滤;` +
|
|
1814
|
+
`项目 Skill 内容不再注入。重启 REPL 后工具表完全不出现。`;
|
|
1815
|
+
layout.contentWrite(`${note}\n`);
|
|
1816
|
+
layout.contentWrite(`${ui.dim}(写入 ${CONFIG_PATH}:MOCODE_PROJECT_SKILL=${nextEnabled ? 'true' : 'false'};${ui.reset}` +
|
|
1817
|
+
(process.env.MOCODE_PROJECT_SKILL
|
|
1818
|
+
? `${ui.dim}同 session shell 未 export,文件写入即时生效)${ui.reset}\n`
|
|
1819
|
+
: `${ui.dim}下次启动仍生效)${ui.reset}\n`));
|
|
1820
|
+
}
|
|
1821
|
+
catch (e) {
|
|
1822
|
+
layout.contentWrite(`${ui.red}/project_skill 失败:${ui.reset} ${e.message}\n`);
|
|
1823
|
+
}
|
|
1824
|
+
continue;
|
|
1825
|
+
}
|
|
1668
1826
|
const bubbleRows = input.length + 2 + pendingAttachments.length; // N 行 message + 2 行尾随空(含 \n\n 留下的 open current 行) + 每附件 1 行
|
|
1669
1827
|
const shouldCommit = await awaitPendingRecall(input, pendingAttachments.length, placeholder);
|
|
1670
1828
|
if (!shouldCommit) {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ChatMessage } from '../llm/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 回滚子系统:`/rollback` 菜单(↑/↓)选轮次 → 选中第 X 轮 = 删该轮及之后 + 预填该轮 user 输入(仿 Claude Code
|
|
4
|
+
* rewind,Enter 重新跑);撤销被删轮次的文件改动(逐个「保留/撤销」询问)。
|
|
5
|
+
*
|
|
6
|
+
* 语义:选中下标 picked(0-based,= 第 picked+1 轮)→ `planRollback(picked)` 保 1..picked(删 picked+1 轮及之后),
|
|
7
|
+
* 预填 userTexts[picked](= 第 picked+1 轮 user 输入)。**不是**保 1..picked+1——选中第 X 轮即"从第 X 轮重跑"。
|
|
8
|
+
*
|
|
9
|
+
* 撤销方案 = 落盘快照(不用 git):write_file/edit_file 执行前由 executeTool 调
|
|
10
|
+
* recordMutation,把 before 内容存入快照(按轮次 turnId 打标)。回滚到第 n 轮时,
|
|
11
|
+
* 对每条选「撤销」的路径,恢复 turnId > cutoffTurnId 的最小 turnId 快照的 before
|
|
12
|
+
* (= 所选轮末状态;before===null = 当时不存在 → 删文件)。同文件多轮改动也能
|
|
13
|
+
* 精确回到所选轮边界,不误伤更早轮次。
|
|
14
|
+
*
|
|
15
|
+
* 快照 + 轮次日志随 saveSession 落盘到 <sessionDir>/<id>.snapshots.json,/resume 读回
|
|
16
|
+
* → 重启后仍可撤销。叶子模块:运行时只依赖 config(+ node:fs/path);ChatMessage
|
|
17
|
+
* 用 import type 擦除,不拉 llm 运行时;不反向依赖任何业务。
|
|
18
|
+
*
|
|
19
|
+
* v1 偏离 / 局限:
|
|
20
|
+
* - 撤销粒度 = 路径(非逐条 tool_call)——快照只能整路径回到轮末,无法只撤一条 edit。
|
|
21
|
+
* - run_command 不撤销(shell 可任意改文件,无法跟踪)。
|
|
22
|
+
* - 跨 /resume 后若文件被外部改过,恢复会用 before 覆盖(边缘情况,不处理)。
|
|
23
|
+
* - 快照文件随大文件多次改动膨胀;/clear 重置;日后可按「turn 已不可回滚」裁剪。
|
|
24
|
+
*/
|
|
25
|
+
export interface Turn {
|
|
26
|
+
turnId: number;
|
|
27
|
+
firstLine: string;
|
|
28
|
+
}
|
|
29
|
+
export interface Snapshot {
|
|
30
|
+
turnId: number;
|
|
31
|
+
path: string;
|
|
32
|
+
before: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface FileChange {
|
|
35
|
+
path: string;
|
|
36
|
+
ops: string[];
|
|
37
|
+
snapshotAvailable: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface RollbackPlan {
|
|
40
|
+
n: number;
|
|
41
|
+
cutoffIndex: number;
|
|
42
|
+
cutoffTurnId: number;
|
|
43
|
+
changes: FileChange[];
|
|
44
|
+
}
|
|
45
|
+
/** agent:runAgent 入口调——开新轮次。firstLine 已由调用方截断到 40。 */
|
|
46
|
+
export declare function beginTurn(firstLine: string): void;
|
|
47
|
+
/** tools/registry:write_file/edit_file 执行前调——记 before 快照(在 tool.execute 之前读)。 */
|
|
48
|
+
export declare function recordMutation(p: string): void;
|
|
49
|
+
/** 列出当前可回滚的轮次(1-based 序号由调用方显示)。 */
|
|
50
|
+
export declare function listTurns(): Turn[];
|
|
51
|
+
/**
|
|
52
|
+
* 规划回滚到第 n 轮(1-based):算截断点 + 被删轮次里涉及的文件改动(按 path 去重)。
|
|
53
|
+
* 调用方据 changes 逐 path 问保留 / 撤销;snapshotAvailable=false 的项无法撤销。
|
|
54
|
+
*/
|
|
55
|
+
export declare function planRollback(n: number, history: ChatMessage[]): RollbackPlan;
|
|
56
|
+
/**
|
|
57
|
+
* 执行回滚:原地截断 history 到 cutoffIndex + 按选择恢复文件 + 裁剪 turns/snapshots。
|
|
58
|
+
* revertPaths 为选「撤销」的相对路径集合。返回删除消息数 + 撤销文件列表。
|
|
59
|
+
*/
|
|
60
|
+
export declare function applyRollback(plan: RollbackPlan, history: ChatMessage[], revertPaths: Set<string>): {
|
|
61
|
+
deletedMsgs: number;
|
|
62
|
+
revertedFiles: string[];
|
|
63
|
+
};
|
|
64
|
+
/** compact 摘要成功后调:按存活轮次数裁剪(M = 新 history 里 user 消息数)。 */
|
|
65
|
+
export declare function pruneAfterCompaction(history: ChatMessage[]): void;
|
|
66
|
+
/** /clear 调:清空全部状态。 */
|
|
67
|
+
export declare function resetState(): void;
|
|
68
|
+
/**
|
|
69
|
+
* 无 snapshots 文件时(/resume 旧会话)从 history 重建 turns(扫 user 消息,1..M,
|
|
70
|
+
* 无快照 → 那些轮次的文件改动不可撤销)。turnIdCounter = M,后续新轮次从 M+1 续。
|
|
71
|
+
*/
|
|
72
|
+
export declare function rebuildFromHistory(history: ChatMessage[]): void;
|
|
73
|
+
/** 随 saveSession 调:把 turns + snapshots 落盘(turns 为空则跳过,不写空文件)。 */
|
|
74
|
+
export declare function persistSnapshots(id: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* /resume / --resume 加载会话后调:读回 turns + snapshots。成功返 true(状态已覆盖);
|
|
77
|
+
* 失败 / 无文件返 false,调用方应改调 rebuildFromHistory(history) 兜底。
|
|
78
|
+
*/
|
|
79
|
+
export declare function loadSnapshots(id: string): boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { getSandboxRoot, setSandboxRoot } from './root.js';
|
|
2
|
+
export { jailResolve, jailGlobPattern, isInsideRoot } from './jail.js';
|
|
3
|
+
export { filterEnv, isCommandDenied } from './command.js';
|
|
4
|
+
export { SANDBOX_EXEMPT_TOOLS, SANDBOX_PATH_TOOLS, enforceSandbox, } from './policy.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* abs 是否在沙箱根内(含 == 根)。win32 下两边 toLowerCase 再比(node 的 path.relative 不做
|
|
3
|
+
* 大小写无关比较,盘符大小写差异会误判出圈)。**不做 realpath**——用于 glob/grep 结果后置过滤;
|
|
4
|
+
* 越界软链的拦挡靠 jailResolve 的 realpath。
|
|
5
|
+
*/
|
|
6
|
+
export declare function isInsideRoot(abs: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* 把输入路径解析为沙箱根内的绝对路径;越界(../、绝对外圈、符号链接出圈)抛错。
|
|
9
|
+
* 供 enforceSandbox 重写 args.path(读/写/改)、readDiffContext 预读旧内容用。
|
|
10
|
+
* 同步:realpathSync 仅做 fs 元数据查询(微秒级),与既有 readFileSync/existsSync 用法一致。
|
|
11
|
+
*/
|
|
12
|
+
export declare function jailResolve(input: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* glob pattern 校验:拒绝对路径(平台相关的 isAbsolute)与含 `..` 段的 pattern。
|
|
15
|
+
* 返 null = 通过;返 string = 拒绝原因。形如 *.ts 的正常 pattern 放行。
|
|
16
|
+
*/
|
|
17
|
+
export declare function jailGlobPattern(pattern: string): string | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 豁免 cwd 牢笼的工具:
|
|
3
|
+
* - memory_*:操作 ~/.mocode 与 <cwd>/.mocode(CLAUDE.md 明确不进回滚、在外圈),本就该在外圈
|
|
4
|
+
* - use_skill:读 ~/.claude/skills、~/.mocode/skills、<cwd>/.mocode/skills,部分在外圈
|
|
5
|
+
* - web_*:跨网络,非文件路径
|
|
6
|
+
* - ask_human / switch_mode:无文件路径
|
|
7
|
+
* - codegraph:只读 cwd 下 .codegraph/ 索引(只读、不写盘)
|
|
8
|
+
* - task:派生子 agent,继承全局 root(子 agent 同进程天然共享 getSandboxRoot)
|
|
9
|
+
*/
|
|
10
|
+
export declare const SANDBOX_EXEMPT_TOOLS: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* 路径类工具:enforceSandbox 集中把 args.path 重写为牢内绝对路径(默认安全;工具内
|
|
13
|
+
* resolve(absolutePath) 原样返回)。**新加带 path 参数的工具须列入此集**,否则不会被牢笼挡。
|
|
14
|
+
*/
|
|
15
|
+
export declare const SANDBOX_PATH_TOOLS: Set<string>;
|
|
16
|
+
/**
|
|
17
|
+
* 工具执行前的沙箱校验。返 string = 拒绝(直接喂 LLM,不执行);返 null = 放行(可能已重写 args.path)。
|
|
18
|
+
* **不抛**——契约对齐「调度器永不抛错、永远返回字符串」(tools/registry.ts executeTool)。
|
|
19
|
+
* run_command 不在此处理(cwd / env / denylist 在其站点)。
|
|
20
|
+
*/
|
|
21
|
+
export declare function enforceSandbox(name: string, args: Record<string, unknown>): string | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** 当前沙箱根(绝对路径)。未初始化返 null,调用方 ?? process.cwd() 兜底(防御)。 */
|
|
2
|
+
export declare function getSandboxRoot(): string | null;
|
|
3
|
+
/** 设置沙箱根。repl startRepl 启动时调一次(默认 process.cwd();--sandbox-root / SANDBOX_ROOT 可覆盖)。
|
|
4
|
+
* 返回之前的值,供未来 save/restore(子 agent worktree 隔离)用。 */
|
|
5
|
+
export declare function setSandboxRoot(root: string | null): string | null;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type ChatMessage, type ChatUsage } from '../llm/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 上下文压缩子系统(参考 Claude Code 的 auto-compact):
|
|
4
|
+
* 三层 —— ① push-time 单条上限(见 capToolResultForHistory,在 agent push 时调用)
|
|
5
|
+
* ② 微压缩:旧工具结果原地截短(保 tool_call_id,无 LLM 调用)
|
|
6
|
+
* ③ 摘要:旧的非工具消息由一次 chat() 压成一条 role:'system' 摘要(index 1)
|
|
7
|
+
*
|
|
8
|
+
* 不变量:
|
|
9
|
+
* - 原地修改:用 history.length=0; push(...) 重建,repl 持有同一引用。
|
|
10
|
+
* - tool_call_id 配对:按完整 group(assistant+其后连续 tool)切,永不劈开;
|
|
11
|
+
* 微压缩只改 .content 不删消息。
|
|
12
|
+
* - history[0] 永远是当前 systemPrompt;摘要插 index 1。
|
|
13
|
+
*/
|
|
14
|
+
export interface CompactOptions {
|
|
15
|
+
window: number;
|
|
16
|
+
threshold: number;
|
|
17
|
+
/** 手动 /compact 的聚焦指令,会拼进摘要 prompt。 */
|
|
18
|
+
focus?: string;
|
|
19
|
+
/** 可注入的摘要器(测试用);缺省调 chat()。 */
|
|
20
|
+
summarize?: (older: ChatMessage[], focus?: string) => Promise<string | null>;
|
|
21
|
+
/** 手动触发(repl /compact)开关:强制走 microcompact/summarize,绕过 autoCompact 阈。
|
|
22
|
+
* 设为 true 后,即便无 ROI 触发(history 不超/totalOver=false)也压——对齐用户拍板的"真·强制"。
|
|
23
|
+
* force:在 manual 基础上再绕过「oldGroups 空 → 直接 noop」的硬边界,允许降 keepBudget 强压。
|
|
24
|
+
* 默认 manual=false / force=false(自动路径行为完全不变)。 */
|
|
25
|
+
manual?: boolean;
|
|
26
|
+
force?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface CompactResult {
|
|
29
|
+
compacted: boolean;
|
|
30
|
+
summarized: boolean;
|
|
31
|
+
estimateBefore: number;
|
|
32
|
+
estimateAfter: number;
|
|
33
|
+
reason: 'noop-empty' | 'noop-protected' | 'noop-ml-only' | 'noop-shrunk-too-large' | 'noop-noold-noop' | 'microcompact' | 'summarize';
|
|
34
|
+
/** 调试字段:保护区占比(0-1),供 /compact 显示"为什么没压"。force 时降 keepBudget 后可能更小。 */
|
|
35
|
+
protectedRatio?: number;
|
|
36
|
+
/** 调试字段:旧区可压组数,供 UI 显示。 */
|
|
37
|
+
oldGroupCount?: number;
|
|
38
|
+
}
|
|
39
|
+
/** 跨模块共享的上下文状态:agent 写 lastUsage,compact 写 lastEstimate,repl 的 /context 读。
|
|
40
|
+
* scheduler.ts 写最近一次调度日志(可选,repl 可读不到时 no-op)。 */
|
|
41
|
+
export declare const contextState: {
|
|
42
|
+
lastUsage?: ChatUsage;
|
|
43
|
+
lastEstimate: number;
|
|
44
|
+
schedulerLog?: import('./scheduler.js').SchedulerRunLog;
|
|
45
|
+
};
|
|
46
|
+
/** 中截:text 太长时保 head + 标记 + tail,总长 ≤ max。 */
|
|
47
|
+
export declare function truncateMid(text: string, max: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* push-time 第一层:工具结果进 history 前裁到 MAX_HISTORY_RESULT。
|
|
50
|
+
* 显示层(summarizeToolResult)仍用原 output,不受影响。
|
|
51
|
+
*/
|
|
52
|
+
export declare function capToolResultForHistory(name: string, output: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* 把多模态 content 拍平成纯文本(供摘要 transcript 用):text parts 拼接;image_url parts
|
|
55
|
+
* 替换为 `[图片已剥离: <mime>]` stub,避免 base64 进摘要 prompt(LLM 看到也无意义,反而撑爆 token)。
|
|
56
|
+
* 其它情况(string / 其它形状)原样返回。
|
|
57
|
+
*/
|
|
58
|
+
export declare function stripImagesForSummary(m: ChatMessage): ChatMessage;
|
|
59
|
+
/**
|
|
60
|
+
* 压缩 history(原地)。手动 /compact 与自动 maybeCompact 都走这里。
|
|
61
|
+
* 不检查阈值——调用方(maybeCompact)决定是否调;/compact 直接调以强制压缩。
|
|
62
|
+
*/
|
|
63
|
+
export declare function compactHistory(history: ChatMessage[], opts: CompactOptions): Promise<CompactResult>;
|
|
64
|
+
/**
|
|
65
|
+
* 自动压缩门槛:agent 每步调 chat() 前调用。
|
|
66
|
+
* 用全量启发式估算(始终可用、安全侧、无 stale-usage 问题);超阈则压缩。
|
|
67
|
+
*
|
|
68
|
+
* 升级到 Budget Scheduler:可传 `report: BudgetReport`。传了就**按 ROI 调度**:
|
|
69
|
+
* - 只有当 `report.layers.history.overBudget` 或 `report.totalOver` 时才压;
|
|
70
|
+
* - 冷工具超(Cold Tool ROI 最低)→ 不压 history,留给调度器的 cold tools 路径处理。
|
|
71
|
+
* 这样 cold tools 路径(L1 中截 / L2 relevance / L3 age stub)能先动,history
|
|
72
|
+
* 摘要(最贵)只在 cold tools 解不开时才触发。
|
|
73
|
+
*
|
|
74
|
+
* 不传 report 时退化为原行为:仅看总占用是否超 `compactThreshold * window`——
|
|
75
|
+
* 兼容老调用方(子 agent / 测试直接调时),零行为变化。
|
|
76
|
+
*
|
|
77
|
+
* manual 选项(repl /compact 用):true 时旁路 autoCompact 开关与 ROI 阈,
|
|
78
|
+
* 强制走 compactHistory(manual/force 参数透传)。返 CompactResult 给 caller 文案展示。
|
|
79
|
+
* 默认 manual=false 自动路径完全不变。
|
|
80
|
+
*/
|
|
81
|
+
export declare function maybeCompact(history: ChatMessage[], report?: {
|
|
82
|
+
layers: {
|
|
83
|
+
history: {
|
|
84
|
+
overBudget: boolean;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
totalOver: boolean;
|
|
88
|
+
}, manualOpts?: {
|
|
89
|
+
manual?: boolean;
|
|
90
|
+
force?: boolean;
|
|
91
|
+
focus?: string;
|
|
92
|
+
}): Promise<CompactResult | void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChatMessage } from '../llm/index.js';
|
|
2
|
+
import { estimateTokens } from '../llm/index.js';
|
|
3
|
+
import type { DropContextFilter, DropContextResult } from '../tools/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* 剔除历史里命中的旧 tool 结果(原地修改 history)。
|
|
6
|
+
*
|
|
7
|
+
* 筛选(各维度 AND 组合):
|
|
8
|
+
* - toolNames:只剔除这些工具名的结果(空 = 不限)
|
|
9
|
+
* - contains:只剔除内容包含所有这些词(AND、大小写不敏感)的结果(空 = 不限)
|
|
10
|
+
*
|
|
11
|
+
* 保护:history[0](system)+ 当前轮(最后一个 user 及其之后)永不剔除。
|
|
12
|
+
* 已是存根的 tool 消息(含「已剔除」标记)不重复剔除(幂等)。
|
|
13
|
+
*
|
|
14
|
+
* 永不抛错;无匹配返 dropped=0。
|
|
15
|
+
*/
|
|
16
|
+
export declare function dropContextFromHistory(history: ChatMessage[], filter: DropContextFilter): DropContextResult;
|
|
17
|
+
/** 给 drop_context 工具结果格式化人类可读摘要(回灌给 agent)。 */
|
|
18
|
+
export declare function formatDropResult(r: DropContextResult): string;
|
|
19
|
+
export { estimateTokens };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session/ 入口:上下文压缩 + 会话落盘。
|
|
3
|
+
* - compact.ts:三层压缩(push-time 上限 / 微压缩 / 摘要)+ 自动门槛
|
|
4
|
+
* - persist.ts:history 序列化到磁盘 + --resume / /resume
|
|
5
|
+
* 依赖方向:session → {llm(摘要复用 chat), config, ui};llm 不反向依赖 session。
|
|
6
|
+
*/
|
|
7
|
+
export { compactHistory, maybeCompact, capToolResultForHistory, truncateMid, contextState, } from './compact.js';
|
|
8
|
+
export type { CompactOptions, CompactResult } from './compact.js';
|
|
9
|
+
export { runScheduler, manualCompact, createBudgetScheduler, } from './scheduler.js';
|
|
10
|
+
export type { BudgetScheduler, SchedulerRunLog } from './scheduler.js';
|
|
11
|
+
export { dropContextFromHistory, formatDropResult, } from './drop.js';
|
|
12
|
+
export { newSessionId, saveSession, loadSession, listSessions, sessionDir, } from './persist.js';
|
|
13
|
+
export type { SessionMeta, SessionRecord } from './persist.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChatMessage } from '../llm/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 会话落盘:把 history 序列化到 <cwd>/.mocode/sessions/<id>.json,支持 --resume / /resume。
|
|
4
|
+
* session = 「这次对话说了啥」;与 memory/(跨会话长期事实)区分。
|
|
5
|
+
* 同步 fs(小文件,匹配 config 的同步风格);任何读/解析失败都返 null,不抛。
|
|
6
|
+
*/
|
|
7
|
+
export interface SessionMeta {
|
|
8
|
+
id: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
model: string;
|
|
11
|
+
firstUser: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionRecord extends SessionMeta {
|
|
14
|
+
history: ChatMessage[];
|
|
15
|
+
}
|
|
16
|
+
/** 会话目录(确保存在)。 */
|
|
17
|
+
export declare function sessionDir(): string;
|
|
18
|
+
/** 新会话 id:YYYYMMDD-HHmmss(运行时 Date 可用)。 */
|
|
19
|
+
export declare function newSessionId(): string;
|
|
20
|
+
/** 保存会话到磁盘(history.length<=1 时跳过写盘,只返 meta)。 */
|
|
21
|
+
export declare function saveSession(history: ChatMessage[], id: string): SessionMeta;
|
|
22
|
+
/** 加载会话;不存在 / 损坏返 null(不抛)。 */
|
|
23
|
+
export declare function loadSession(id: string): SessionRecord | null;
|
|
24
|
+
/** 列出最近会话,按 createdAt 降序。损坏文件跳过。
|
|
25
|
+
* - limit?: 仅返回前 N 条。会话文件名是 YYYYMMDD-HHmmss.json,字典序=时间序;
|
|
26
|
+
* 先按文件名降序取前 N,再只解析这 N 个文件(history 大字段全部跳过不读),避免
|
|
27
|
+
* /resume 在 sessions 目录堆了几百个文件时 readdirSync + 全量 JSON.parse 慢。
|
|
28
|
+
* - 不传 limit 时读全部(向后兼容,供裸 --resume 列全表用)。
|
|
29
|
+
*/
|
|
30
|
+
export declare function listSessions(limit?: number): SessionMeta[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { evaluateBudget, scheduleActions, formatReport, type BudgetReport, type ScheduleAction } from '../context/budget.js';
|
|
2
|
+
import type { ChatMessage } from '../llm/index.js';
|
|
3
|
+
/** 一次调度的执行日志(供 /context 命令显示与调试)。 */
|
|
4
|
+
export interface SchedulerRunLog {
|
|
5
|
+
step: number;
|
|
6
|
+
report: BudgetReport;
|
|
7
|
+
actions: ScheduleAction[];
|
|
8
|
+
/** 实际触发的闸('compact_history' 调过 maybeCompact → true;其它已在 push-time 自动跑)。 */
|
|
9
|
+
compactHistoryCalled: boolean;
|
|
10
|
+
ts: number;
|
|
11
|
+
}
|
|
12
|
+
/** Scheduler 实例状态:压一份最近日志,方便 /context 看到上一次决策。 */
|
|
13
|
+
export interface BudgetScheduler {
|
|
14
|
+
observePush: (history: ChatMessage[], idx: number) => void;
|
|
15
|
+
runStep: (history: ChatMessage[], step: number) => Promise<void>;
|
|
16
|
+
/** 暴露最近一次决策(供 /context)。 */
|
|
17
|
+
lastRunLog: SchedulerRunLog | null;
|
|
18
|
+
}
|
|
19
|
+
/** compact_history action 的执行明细(供 repl 文案展示"为什么没压")。 */
|
|
20
|
+
export interface CompactHistoryDetail {
|
|
21
|
+
reason: 'microcompact' | 'summarize' | 'noop-empty' | 'noop-protected' | 'noop-ml-only' | 'noop-shrunk-too-large' | 'noop-noold-noop';
|
|
22
|
+
estimateBefore: number;
|
|
23
|
+
estimateAfter: number;
|
|
24
|
+
/** 保护区占比 0-1(系统 + 当前轮 / 总 history)。 */
|
|
25
|
+
protectedRatio?: number;
|
|
26
|
+
/** 旧区可压组数。 */
|
|
27
|
+
oldGroupCount?: number;
|
|
28
|
+
/** focus 透传。 */
|
|
29
|
+
focus?: string;
|
|
30
|
+
}
|
|
31
|
+
/** 创建 runAgentCore 闭包持有的 scheduler(每次 agent 启动一个新实例)。
|
|
32
|
+
* observePush 当前只是占位:真正 L1/L2/L3 已由 cap / pruner / lifecycle 在 push 时跑;
|
|
33
|
+
* 保留接口为后续「调度器注入 hotBoundary 给 lifecycle」演进留接缝。 */
|
|
34
|
+
export declare function createBudgetScheduler(): BudgetScheduler;
|
|
35
|
+
/** 便捷:agent/core.ts 不需要每次 createBudgetScheduler,直接 runScheduler(history, step)。 */
|
|
36
|
+
export declare function runScheduler(history: ChatMessage[], step: number): Promise<void>;
|
|
37
|
+
/** 手动 /compact 入口(repl):与自动路径完全一致——五区 ROI 调度,但 history 摘要强制执行。
|
|
38
|
+
* 即便 layers.history.overBudget=false 或 totalOver=false,manual 仍产 compact_history action
|
|
39
|
+
* 把 focus 透传给 LLM 摘要 prompt。其它 ROI 决策(cold tools / cap hot / warn)按 scheduleActions 走。
|
|
40
|
+
*
|
|
41
|
+
* 关系:runScheduler 是「自动触发」,manualCompact 是「用户显式触发」,二者共享 scheduleActions。
|
|
42
|
+
*
|
|
43
|
+
* force=true:即便 oldGroups 空(history 全在保护区)也强行把早期消息降级压一次。
|
|
44
|
+
* 适合"history 太长,自动阈值从未触发,但用户想强制压"的场景。
|
|
45
|
+
*
|
|
46
|
+
* 退化:config.contextBudget === false 时直接调 compactHistory(history, { focus }),与改造前等价。
|
|
47
|
+
* 返回 SchedulerRunLog + compactDetail 字段,供 repl 文案展示"为什么没压"。 */
|
|
48
|
+
export declare function manualCompact(history: ChatMessage[], focus?: string, opts?: {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
}): Promise<SchedulerRunLog & {
|
|
51
|
+
compactDetail?: CompactHistoryDetail;
|
|
52
|
+
}>;
|
|
53
|
+
export { evaluateBudget, scheduleActions, formatReport };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface Skill {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
license?: string;
|
|
6
|
+
dir: string;
|
|
7
|
+
skillMdPath: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 解析 skill 目录列表。
|
|
11
|
+
* env SKILLS_DIRS 设则覆盖默认(用 path.delimiter 切分,与 PATH 同语义:
|
|
12
|
+
* win32 用 ';',POSIX 用 ':',规避盘符冒号问题);未设则默认三目录,
|
|
13
|
+
* 按优先级升序(低→高):~/.claude/skills → ~/.mocode/skills → <cwd>/.mocode/skills。
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveSkillsDirs(): string[];
|
|
16
|
+
/**
|
|
17
|
+
* 极简 YAML frontmatter 解析(不引入 yaml 依赖)。
|
|
18
|
+
* 仅支持单行键值:按首个冒号切 key/value,trim,去首尾配对引号。
|
|
19
|
+
* 不支持块标量(| / >)与多行值——v1 限制(skill 的 description 实际多为单行)。
|
|
20
|
+
*
|
|
21
|
+
* 返回 { meta, body }:无 frontmatter 时 meta 为空、body 为原文。
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseFrontmatter(content: string): {
|
|
24
|
+
meta: Record<string, string>;
|
|
25
|
+
body: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* 扫描所有 skill 目录,解析 frontmatter,按目录优先级去重。
|
|
29
|
+
* 同步 fs + 全程静默容错(目录不存在 / 读失败 / 解析失败 → 跳过,不抛),
|
|
30
|
+
* 风格对齐 src/session/persist.ts。按 resolveSkillsDirs 升序遍历,
|
|
31
|
+
* Map.set 后设覆盖先设 → 项目级优先。
|
|
32
|
+
*/
|
|
33
|
+
export declare function discoverSkills(): Skill[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Skill } from './discover.js';
|
|
2
|
+
export type { Skill };
|
|
3
|
+
/** 已发现的 skill 列表(懒加载,首次调用触发扫描;启动期 repl 调一次)。 */
|
|
4
|
+
export declare function listSkills(): Skill[];
|
|
5
|
+
/**
|
|
6
|
+
* 读取某 skill 的 SKILL.md 正文(去掉 frontmatter)。
|
|
7
|
+
* 纯函数:找不到 / 读失败返 null(错误字符串交给调用方工具层生成)。
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSkillBody(name: string): string | null;
|
|
10
|
+
/** 拼进系统提示的 skill 段;无 skill 返空串(零行为变化)。 */
|
|
11
|
+
export declare function buildSkillsSection(): string;
|
|
12
|
+
/** base 系统提示 + skill 段;无 skill 时 === base。 */
|
|
13
|
+
export declare function effectiveSystemPrompt(base: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Tool } from '../types.js';
|
|
2
|
+
/** 单个选项:label 是选项本身,detail 是选它意味着什么/取舍(可选)。 */
|
|
3
|
+
export interface ChoiceOption {
|
|
4
|
+
label: string;
|
|
5
|
+
detail?: string;
|
|
6
|
+
}
|
|
7
|
+
/** 公开以便 check-ask-human-options.ts 单元测试。 */
|
|
8
|
+
export declare function coerceOptions(raw: unknown): ChoiceOption[];
|
|
9
|
+
export declare const askHumanTool: Tool;
|