min-agent 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -2
- package/dist/agent.js +36 -22
- package/dist/cli/commands/chat.js +3 -0
- package/dist/cli/commands/exec.js +3 -0
- package/dist/cli/commands/index.js +22 -5
- package/dist/cli/commands/memory.js +33 -15
- package/dist/cli/commands/think.js +12 -0
- package/dist/cli/commands/write-config.js +22 -0
- package/dist/cli/option-helpers.js +13 -1
- package/dist/cli/program.js +50 -13
- package/dist/code-mode.js +1 -1
- package/dist/config.js +41 -0
- package/dist/context-window.js +8 -28
- package/dist/memory-cli.js +33 -0
- package/dist/memory.js +127 -46
- package/dist/model-catalog.js +285 -0
- package/dist/permission-cli.js +1 -4
- package/dist/provider.js +4 -1
- package/dist/reasoning-stream.js +158 -0
- package/dist/sandbox-cli.js +1 -4
- package/dist/scope.js +23 -0
- package/dist/serve/common.js +22 -1
- package/dist/serve/routes-chat.js +21 -1
- package/dist/serve/routes-memory.js +31 -2
- package/dist/serve/routes-meta.js +34 -6
- package/dist/think-cli.js +36 -0
- package/dist/thinking-wire.js +228 -0
- package/dist/thinking.js +142 -0
- package/dist/token-display.js +10 -7
- package/dist/tools/todo.js +22 -8
- package/dist/tui/App.js +36 -8
- package/dist/tui/InputBar.js +109 -36
- package/dist/tui/MessageList.js +53 -22
- package/dist/tui/StatusBar.js +7 -3
- package/dist/tui/ThinkPicker.js +77 -0
- package/dist/tui/bracketed-paste.js +37 -0
- package/dist/tui/caret-pos.js +10 -8
- package/dist/tui/index.js +7 -1
- package/dist/tui/layout.js +17 -0
- package/dist/tui/overlay-input.js +12 -0
- package/dist/tui/paste-draft.js +173 -0
- package/dist/tui/selection.js +8 -2
- package/dist/tui/slash-commands.js +18 -1
- package/dist/tui/slash-handler.js +61 -17
- package/dist/tui/text-width.js +6 -6
- package/dist/tui-chat.js +63 -7
- package/docs/API.md +50 -4
- package/docs/superpowers/plans/2026-08-23-input-paste-attachments.md +475 -0
- package/docs/superpowers/plans/2026-08-23-thinking-wire-profile.md +450 -0
- package/docs/superpowers/specs/2026-08-23-input-paste-attachments-design.md +174 -0
- package/docs/superpowers/specs/2026-08-23-thinking-wire-profile-design.md +140 -0
- package/package.json +1 -1
- package/skills/self-config/SKILL.md +5 -4
- package/skills/self-config/reference.md +10 -5
package/README.md
CHANGED
|
@@ -67,6 +67,8 @@ Type `/` to open a command menu. Use **↑ / ↓** to recall previous messages.
|
|
|
67
67
|
| `/model` | Switch model |
|
|
68
68
|
| `/provider` | Switch provider |
|
|
69
69
|
| `/plan` | Toggle plan mode (look, don't touch) |
|
|
70
|
+
| `/think` | Choose thinking intensity |
|
|
71
|
+
| `/memory` | Turn memory on/off, or save a note |
|
|
70
72
|
| `/undo` | Undo the last turn |
|
|
71
73
|
| `/diff` | Show file changes made so far |
|
|
72
74
|
| `/sessions` | List or switch sessions |
|
|
@@ -77,7 +79,7 @@ Type `/` to open a command menu. Use **↑ / ↓** to recall previous messages.
|
|
|
77
79
|
| `/help` | Show all commands |
|
|
78
80
|
| `/exit` | Exit |
|
|
79
81
|
|
|
80
|
-
Shortcuts: **Ctrl+C** clears the input (press twice to exit) · **Ctrl+B** selects text to copy · mouse drag-select also copies on release.
|
|
82
|
+
Shortcuts: **Ctrl+C** clears the input (press twice to exit) · **Ctrl+V** pastes an image · a multi-line paste becomes a snippet · **Ctrl+B** selects text to copy · mouse drag-select also copies on release · click a tool or thinking block to expand or collapse it.
|
|
81
83
|
|
|
82
84
|
## Staying in Control
|
|
83
85
|
|
|
@@ -98,6 +100,19 @@ min-agent sandbox off # No restriction (default)
|
|
|
98
100
|
min-agent sandbox workspace # Only allow changes inside the current folder
|
|
99
101
|
```
|
|
100
102
|
|
|
103
|
+
## Memory
|
|
104
|
+
|
|
105
|
+
Remembered notes are off by default. Turn them on when you want facts to persist across sessions:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
min-agent memory # Show the switch and stored notes
|
|
109
|
+
min-agent memory on # Turn memory on (writes config)
|
|
110
|
+
min-agent --memory on # Same; with a message, this session only
|
|
111
|
+
min-agent memory add "prefer bun"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
In chat, `/memory on` or `/memory off` toggles it; `/memory` lists notes; `/memory some text` saves one.
|
|
115
|
+
|
|
101
116
|
## Configuration
|
|
102
117
|
|
|
103
118
|
Run `min-agent setup` for a guided setup — this is the easiest way to add or switch AI providers.
|
|
@@ -170,6 +185,8 @@ min-agent --provider anthropic "你的消息"
|
|
|
170
185
|
| `/model` | 切换模型 |
|
|
171
186
|
| `/provider` | 切换服务商 |
|
|
172
187
|
| `/plan` | 切换"计划模式"(只看不改) |
|
|
188
|
+
| `/think` | 选择思考强度 |
|
|
189
|
+
| `/memory` | 开关记忆,或保存一条 |
|
|
173
190
|
| `/undo` | 撤销上一轮操作 |
|
|
174
191
|
| `/diff` | 查看当前已产生的文件改动 |
|
|
175
192
|
| `/sessions` | 查看或切换会话 |
|
|
@@ -180,7 +197,7 @@ min-agent --provider anthropic "你的消息"
|
|
|
180
197
|
| `/help` | 查看全部命令 |
|
|
181
198
|
| `/exit` | 退出 |
|
|
182
199
|
|
|
183
|
-
快捷键:**Ctrl+C** 清空输入框(连按两次退出)· **Ctrl+B** 选中文本以复制 ·
|
|
200
|
+
快捷键:**Ctrl+C** 清空输入框(连按两次退出)· **Ctrl+V** 粘贴图片 · 多行粘贴会收成片段 · **Ctrl+B** 选中文本以复制 · 也支持鼠标拖拽选中并自动复制 · 点击工具或思考块可展开或收起。
|
|
184
201
|
|
|
185
202
|
## 掌控风险
|
|
186
203
|
|
|
@@ -201,6 +218,19 @@ min-agent sandbox off # 不限制(默认)
|
|
|
201
218
|
min-agent sandbox workspace # 仅允许修改当前项目文件夹内的内容
|
|
202
219
|
```
|
|
203
220
|
|
|
221
|
+
## 记忆
|
|
222
|
+
|
|
223
|
+
跨会话记忆默认关闭。需要记住偏好或项目约定时再打开:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
min-agent memory # 查看开关与已保存内容
|
|
227
|
+
min-agent memory on # 开启记忆(写入配置)
|
|
228
|
+
min-agent --memory on # 同上;若同时带消息则只对本轮生效
|
|
229
|
+
min-agent memory add "prefer bun"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
对话里用 `/memory on` 或 `/memory off` 开关;`/memory` 查看;`/memory 一段话` 保存一条。
|
|
233
|
+
|
|
204
234
|
## 配置
|
|
205
235
|
|
|
206
236
|
运行 `min-agent setup` 即可通过引导式流程完成配置,这是添加或切换 AI 服务商最简单的方式。
|
package/dist/agent.js
CHANGED
|
@@ -10,7 +10,8 @@ import { scanProject, buildCodeSystemPrompt } from "./code-mode.js";
|
|
|
10
10
|
import { initMcp, shutdownMcp, getMcpTools, getMcpCatalogTools, getMcpReadOnlyToolIds } from "./mcp.js";
|
|
11
11
|
import { discoverSkills, attachSkills, collectLoadedSkillNames } from "./skills.js";
|
|
12
12
|
import { loadInstructions } from "./instructions.js";
|
|
13
|
-
import {
|
|
13
|
+
import { resolveThinkingRequest, thinkingRequestStore } from "./thinking.js";
|
|
14
|
+
import { getMemorySystemPrompt, getMemoryTools, isMemoryEnabled } from "./memory.js";
|
|
14
15
|
import { needsCompaction, compactMessages, estimateTokens, estimateStringTokens, estimateOverheadTokens, TokenTracker, COMPACTION_RATIO, PRUNE_PRESSURE_RATIO, PRUNE_TARGET_RATIO, applyToolPrune, pruneToolOutputs, } from "./compaction.js";
|
|
15
16
|
import { loadPluginTools, getPluginReadOnlyIds } from "./plugins.js";
|
|
16
17
|
import { MarkdownRenderer } from "./markdown.js";
|
|
@@ -90,14 +91,6 @@ function printInitReady() {
|
|
|
90
91
|
const { dim, reset } = DIM_STYLE;
|
|
91
92
|
console.log(`${dim}✓ 就绪${reset}`);
|
|
92
93
|
}
|
|
93
|
-
/** Stream thinking to stderr (dim). Set MIN_AGENT_SHOW_THINKING=0 to hide. */
|
|
94
|
-
function writeThinkingDelta(text) {
|
|
95
|
-
if (!text)
|
|
96
|
-
return;
|
|
97
|
-
if (process.env.MIN_AGENT_SHOW_THINKING === "0" || process.env.MIN_AGENT_SHOW_THINKING === "false")
|
|
98
|
-
return;
|
|
99
|
-
process.stderr.write(`${DIM_STYLE.dim}${text}${DIM_STYLE.reset}`);
|
|
100
|
-
}
|
|
101
94
|
export function loadImageParts(imagePaths, notify) {
|
|
102
95
|
const parts = [];
|
|
103
96
|
for (const imgPath of imagePaths) {
|
|
@@ -222,12 +215,12 @@ export function pushTurn(messages, assistantText, toolCalls, toolResults) {
|
|
|
222
215
|
* once per run avoids re-reading plugin manifests and re-wrapping MCP tools on
|
|
223
216
|
* every continue.
|
|
224
217
|
*/
|
|
225
|
-
async function buildRunTools(modelId, abortSignal, planMode, tracker, taskState, subAgent) {
|
|
218
|
+
async function buildRunTools(modelId, abortSignal, planMode, tracker, taskState, subAgent, memory) {
|
|
226
219
|
const builtinTools = createTools();
|
|
227
220
|
builtinTools.todo = createTodoTool({ store: taskState });
|
|
228
221
|
const mcpTools = getMcpTools();
|
|
229
222
|
const catalogTools = getMcpCatalogTools();
|
|
230
|
-
const memoryTools = getMemoryTools();
|
|
223
|
+
const memoryTools = isMemoryEnabled(memory) ? getMemoryTools() : {};
|
|
231
224
|
const pluginTools = await loadPluginTools();
|
|
232
225
|
const allTools = {
|
|
233
226
|
...builtinTools,
|
|
@@ -262,15 +255,15 @@ async function buildRunTools(modelId, abortSignal, planMode, tracker, taskState,
|
|
|
262
255
|
}
|
|
263
256
|
return allTools;
|
|
264
257
|
}
|
|
265
|
-
function buildIterationPrompts(allTools, messages, taskState, loopGuard) {
|
|
258
|
+
function buildIterationPrompts(allTools, messages, taskState, loopGuard, memory) {
|
|
266
259
|
const skillsPrompt = attachSkills(allTools, collectLoadedSkillNames(messages));
|
|
267
260
|
return {
|
|
268
261
|
stable: [skillsPrompt].filter((s) => s.length > 0),
|
|
269
|
-
volatile: [getMemorySystemPrompt(), formatTaskStatePrompt(taskState), loopGuard.promptHint()].filter((s) => s.length > 0),
|
|
262
|
+
volatile: [getMemorySystemPrompt(memory), formatTaskStatePrompt(taskState), loopGuard.promptHint()].filter((s) => s.length > 0),
|
|
270
263
|
};
|
|
271
264
|
}
|
|
272
265
|
/** Ephemeral per-request message carrying the volatile prompt sections. */
|
|
273
|
-
export const SESSION_STATE_HEADER = "## Session state (
|
|
266
|
+
export const SESSION_STATE_HEADER = "## Session state (reference only — not a to-do list, not part of the conversation)";
|
|
274
267
|
function sessionStateMessage(volatile) {
|
|
275
268
|
if (volatile.length === 0)
|
|
276
269
|
return null;
|
|
@@ -518,7 +511,7 @@ async function runOnceCoreLoop(messages, systemPrompt, modelId, abortSignal, cal
|
|
|
518
511
|
const allTools = await buildRunTools(modelId, abortSignal, options?.planMode ?? false, tracker, taskState, {
|
|
519
512
|
loopGuard,
|
|
520
513
|
shouldStop: () => checkBudget() || overTurnBudget(totalSteps),
|
|
521
|
-
});
|
|
514
|
+
}, options?.memory);
|
|
522
515
|
const finish = async (opts) => {
|
|
523
516
|
log("info", `run end steps=${totalSteps} continues=${continues} tokens_in=${lastUsage?.inputTokens ?? 0} tokens_out=${lastUsage?.outputTokens ?? 0}`);
|
|
524
517
|
endRunLog();
|
|
@@ -592,6 +585,12 @@ async function runOnceCoreLoop(messages, systemPrompt, modelId, abortSignal, cal
|
|
|
592
585
|
temperature,
|
|
593
586
|
maxTokens,
|
|
594
587
|
topP,
|
|
588
|
+
thinking: options?.thinking,
|
|
589
|
+
memory: options?.memory,
|
|
590
|
+
providerType: (options?.providerName
|
|
591
|
+
? cfg.providers?.find((p) => p.name === options.providerName)
|
|
592
|
+
: getActiveProvider(cfg))?.type,
|
|
593
|
+
modelId,
|
|
595
594
|
checkBudget,
|
|
596
595
|
overTurnBudget: (stepsInPass) => overTurnBudget(totalSteps + stepsInPass),
|
|
597
596
|
pruneBudget,
|
|
@@ -795,6 +794,7 @@ class StreamRenderer {
|
|
|
795
794
|
thinkingSplit = new ThinkingBodySplitter();
|
|
796
795
|
xmlSplit = new XmlSearchSplitter();
|
|
797
796
|
rawText = "";
|
|
797
|
+
thinkingOpen = false;
|
|
798
798
|
constructor(cbs, interactive) {
|
|
799
799
|
this.cbs = cbs;
|
|
800
800
|
this.interactive = interactive;
|
|
@@ -802,10 +802,17 @@ class StreamRenderer {
|
|
|
802
802
|
emitThinking(t) {
|
|
803
803
|
if (!t)
|
|
804
804
|
return;
|
|
805
|
-
if (this.cbs.onThinkingDelta)
|
|
805
|
+
if (this.cbs.onThinkingDelta) {
|
|
806
806
|
invokeCallback(this.cbs.onThinkingDelta, t);
|
|
807
|
-
|
|
808
|
-
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
if (process.env.MIN_AGENT_SHOW_THINKING === "0" || process.env.MIN_AGENT_SHOW_THINKING === "false")
|
|
810
|
+
return;
|
|
811
|
+
if (!this.thinkingOpen) {
|
|
812
|
+
this.thinkingOpen = true;
|
|
813
|
+
process.stderr.write(`\n${DIM_STYLE.dim}💭 思考${DIM_STYLE.reset}\n`);
|
|
814
|
+
}
|
|
815
|
+
process.stderr.write(`${DIM_STYLE.dim}${t}${DIM_STYLE.reset}`);
|
|
809
816
|
}
|
|
810
817
|
emitDisplay(delta) {
|
|
811
818
|
try {
|
|
@@ -1132,8 +1139,9 @@ class InnerStreamMachine {
|
|
|
1132
1139
|
this.totalUsage = event.totalUsage;
|
|
1133
1140
|
return false;
|
|
1134
1141
|
case "reasoning-delta": {
|
|
1135
|
-
|
|
1136
|
-
|
|
1142
|
+
const text = typeof event.text === "string" ? event.text : "";
|
|
1143
|
+
if (text)
|
|
1144
|
+
this.renderer.feedReasoning(text);
|
|
1137
1145
|
return false;
|
|
1138
1146
|
}
|
|
1139
1147
|
case "text-delta": {
|
|
@@ -1277,7 +1285,7 @@ async function runInnerStream(params) {
|
|
|
1277
1285
|
let result;
|
|
1278
1286
|
try {
|
|
1279
1287
|
machine.attachAbort();
|
|
1280
|
-
const prompts = buildIterationPrompts(params.allTools, params.messages, params.taskState, params.loopGuard);
|
|
1288
|
+
const prompts = buildIterationPrompts(params.allTools, params.messages, params.taskState, params.loopGuard, params.memory);
|
|
1281
1289
|
const system = [params.systemPrompt, ...prompts.stable].join("\n\n");
|
|
1282
1290
|
applyToolPrune(params.messages, params.pruneBudget());
|
|
1283
1291
|
// Volatile state rides along as a trailing message so the cached prefix
|
|
@@ -1287,7 +1295,12 @@ async function runInnerStream(params) {
|
|
|
1287
1295
|
params.overhead.tokens =
|
|
1288
1296
|
estimateOverheadTokens(system, params.allTools) +
|
|
1289
1297
|
(stateMessage ? estimateOverheadTokens(String(stateMessage.content)) : 0);
|
|
1290
|
-
|
|
1298
|
+
const thinking = resolveThinkingRequest({
|
|
1299
|
+
runOverride: params.thinking,
|
|
1300
|
+
providerType: params.providerType,
|
|
1301
|
+
modelId: params.modelId,
|
|
1302
|
+
});
|
|
1303
|
+
const startStream = () => streamText({
|
|
1291
1304
|
model: params.model,
|
|
1292
1305
|
system,
|
|
1293
1306
|
messages: requestMessages,
|
|
@@ -1305,6 +1318,7 @@ async function runInnerStream(params) {
|
|
|
1305
1318
|
machine.onStepError(error);
|
|
1306
1319
|
},
|
|
1307
1320
|
});
|
|
1321
|
+
result = thinkingRequestStore.run(thinking, startStream);
|
|
1308
1322
|
for await (const event of result.fullStream) {
|
|
1309
1323
|
if (await machine.handleEvent(event))
|
|
1310
1324
|
break;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { startTuiSession } from "./shared.js";
|
|
2
|
+
import { applySessionOverrides, applySessionRuntimeOverrides } from "../program.js";
|
|
2
3
|
export async function runChat(promptTokens, opts) {
|
|
4
|
+
applySessionOverrides(opts);
|
|
5
|
+
await applySessionRuntimeOverrides(opts);
|
|
3
6
|
await startTuiSession({
|
|
4
7
|
model: opts.model,
|
|
5
8
|
provider: opts.provider,
|
|
@@ -2,10 +2,13 @@ import { runAgent } from "../../agent.js";
|
|
|
2
2
|
import { isConfigured } from "../../config.js";
|
|
3
3
|
import { resolveExecPrompt } from "../exec-prompt.js";
|
|
4
4
|
import { CliError } from "../errors.js";
|
|
5
|
+
import { applySessionOverrides, applySessionRuntimeOverrides } from "../program.js";
|
|
5
6
|
export async function runExec(messageTokens, opts) {
|
|
6
7
|
if (!isConfigured()) {
|
|
7
8
|
throw new CliError("Not configured.", { hint: "Run: min-agent setup" });
|
|
8
9
|
}
|
|
10
|
+
applySessionOverrides(opts);
|
|
11
|
+
await applySessionRuntimeOverrides(opts);
|
|
9
12
|
const stdinIsTty = Boolean(process.stdin.isTTY);
|
|
10
13
|
const joined = messageTokens.join(" ");
|
|
11
14
|
const shouldReadStdin = joined === "-" || !stdinIsTty;
|
|
@@ -7,16 +7,17 @@ import { runExec } from "./exec.js";
|
|
|
7
7
|
import { runServeCommand } from "./serve.js";
|
|
8
8
|
import { runSandboxCommand } from "./sandbox.js";
|
|
9
9
|
import { runPermissionCommand } from "./permission.js";
|
|
10
|
+
import { runThinkCommand } from "./think.js";
|
|
10
11
|
import { runInitCommand } from "./init.js";
|
|
11
12
|
import { runRulesShow, runRulesEdit } from "./rules.js";
|
|
12
13
|
import { runUpdateCommand } from "./update.js";
|
|
13
14
|
import { runHistoryList, runHistoryDelete, runHistoryRename, runHistoryExport } from "./history.js";
|
|
14
|
-
import { runMemoryList, runMemoryAdd, runMemorySearch, runMemoryDelete } from "./memory.js";
|
|
15
|
+
import { runMemoryList, runMemoryAdd, runMemorySearch, runMemoryDelete, runMemoryMode } from "./memory.js";
|
|
15
16
|
import { runMcpAdd, runMcpRemove, runMcpList, runMcpInfo, runMcpCheck, runMcpToggle, } from "./mcp.js";
|
|
16
17
|
import { runSkillsList, runSkillsInfo, runSkillsToggle, runSkillsNew } from "./skills.js";
|
|
17
18
|
/**
|
|
18
19
|
* All `--project`/`--global`/`--model`/`--provider`/`--resume`/`--image`/`--sandbox`/
|
|
19
|
-
* `--network`/`--permission` flags live on the root `program` (see addSessionOptions),
|
|
20
|
+
* `--network`/`--permission`/`--think`/`--memory` flags live on the root `program` (see addSessionOptions),
|
|
20
21
|
* so they can appear before or after a subcommand name. Subcommands read them via
|
|
21
22
|
* `program.opts<SessionOptions>()` instead of re-declaring the same options — commander
|
|
22
23
|
* resolves options against the first command in the chain that declares them, so a
|
|
@@ -55,10 +56,18 @@ export function registerCommands(program) {
|
|
|
55
56
|
const rules = program.command("rules").description("Show or edit instruction rules");
|
|
56
57
|
rules.action(runRulesShow);
|
|
57
58
|
rules.command("edit").description("Edit the global rules file").action(runRulesEdit);
|
|
58
|
-
const memory = program.command("memory").description("
|
|
59
|
-
memory.
|
|
59
|
+
const memory = program.command("memory").description("Show or set memory, and manage saved memories");
|
|
60
|
+
memory.argument("[state]", "on or off");
|
|
61
|
+
memory.action(async (state) => {
|
|
60
62
|
const opts = rootOpts();
|
|
61
|
-
|
|
63
|
+
const scope = opts.project ? "project" : opts.global ? "global" : undefined;
|
|
64
|
+
if (await runMemoryMode(state, scope, opts.memory))
|
|
65
|
+
return;
|
|
66
|
+
if (state && state !== "list") {
|
|
67
|
+
const { CliError } = await import("../errors.js");
|
|
68
|
+
throw new CliError("Usage: min-agent memory [on|off|list|add|search|delete] [--project|--global]");
|
|
69
|
+
}
|
|
70
|
+
await runMemoryList(scope);
|
|
62
71
|
});
|
|
63
72
|
memory
|
|
64
73
|
.command("add")
|
|
@@ -108,6 +117,14 @@ export function registerCommands(program) {
|
|
|
108
117
|
const opts = rootOpts();
|
|
109
118
|
await runPermissionCommand(mode ? [mode] : [], opts, opts);
|
|
110
119
|
});
|
|
120
|
+
program
|
|
121
|
+
.command("think")
|
|
122
|
+
.description("Show or set thinking intensity (uses --project/--global)")
|
|
123
|
+
.argument("[level]", "off, low, medium, high, or max")
|
|
124
|
+
.action(async (level) => {
|
|
125
|
+
const opts = rootOpts();
|
|
126
|
+
await runThinkCommand(level ? [level] : [], opts, opts);
|
|
127
|
+
});
|
|
111
128
|
// --- Integrations --------------------------------------------------------
|
|
112
129
|
const mcp = program.command("mcp").description("Manage MCP servers");
|
|
113
130
|
mcp
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { loadMemories, addMemory, deleteMemory, searchMemories, defaultMemoryScope, } from "../../memory.js";
|
|
1
|
+
import { loadMemories, addMemory, deleteMemory, searchMemories, defaultMemoryScope, formatMemoryLine, parseMemoryMode, resolveMemoryMode, memoryModeLabel, memorySourceLabel, isMemoryEnabled, } from "../../memory.js";
|
|
2
|
+
import { runMemoryCli } from "../../memory-cli.js";
|
|
2
3
|
import { CliError } from "../errors.js";
|
|
3
4
|
function printList(which) {
|
|
4
5
|
const memories = loadMemories(which);
|
|
@@ -8,23 +9,42 @@ function printList(which) {
|
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
10
11
|
console.log(`${label} (${memories.length}):`);
|
|
11
|
-
for (
|
|
12
|
-
|
|
13
|
-
const tags = m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
|
|
14
|
-
const date = m.created.split("T")[0];
|
|
15
|
-
console.log(` #${i + 1}: ${m.content}${tags} (${date})`);
|
|
12
|
+
for (const line of memories.map((m, i) => formatMemoryLine(m, i, { date: true }))) {
|
|
13
|
+
console.log(line);
|
|
16
14
|
}
|
|
17
15
|
}
|
|
16
|
+
export async function runMemoryMode(state, scope, flagMode) {
|
|
17
|
+
if (!state && flagMode === undefined)
|
|
18
|
+
return false;
|
|
19
|
+
if (state && state !== "list" && !parseMemoryMode(state))
|
|
20
|
+
return false;
|
|
21
|
+
if (state === "list")
|
|
22
|
+
return false;
|
|
23
|
+
const result = runMemoryCli({
|
|
24
|
+
positionals: state ? [state] : [],
|
|
25
|
+
flagMode,
|
|
26
|
+
scope,
|
|
27
|
+
});
|
|
28
|
+
console.log(result.lines.join("\n"));
|
|
29
|
+
if (!result.ok)
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
18
33
|
export async function runMemoryList(scope) {
|
|
34
|
+
const { memory, source } = resolveMemoryMode();
|
|
35
|
+
console.log(`Current memory: ${memoryModeLabel(memory)} (${memorySourceLabel(source)})`);
|
|
19
36
|
if (!scope && loadMemories("project").length === 0 && loadMemories("global").length === 0) {
|
|
20
37
|
console.log("No memories stored.");
|
|
21
|
-
|
|
38
|
+
if (!isMemoryEnabled())
|
|
39
|
+
console.log("Turn on with: min-agent memory on");
|
|
22
40
|
console.log('Or add manually: min-agent memory add "prefer TypeScript over JavaScript"');
|
|
23
41
|
return;
|
|
24
42
|
}
|
|
25
43
|
const scopes = scope ? [scope] : ["project", "global"];
|
|
26
44
|
for (const s of scopes)
|
|
27
45
|
printList(s);
|
|
46
|
+
if (!isMemoryEnabled())
|
|
47
|
+
console.log("Memories are stored but not used in chat until you run: min-agent memory on");
|
|
28
48
|
}
|
|
29
49
|
export async function runMemoryAdd(textTokens, scope) {
|
|
30
50
|
const text = textTokens.join(" ");
|
|
@@ -32,20 +52,18 @@ export async function runMemoryAdd(textTokens, scope) {
|
|
|
32
52
|
throw new CliError("Usage: min-agent memory add <text> [--project|--global]");
|
|
33
53
|
const resolved = scope ?? defaultMemoryScope();
|
|
34
54
|
addMemory(text, [], resolved);
|
|
35
|
-
|
|
55
|
+
const hint = isMemoryEnabled() ? "" : " (memory is off — turn on with: min-agent memory on)";
|
|
56
|
+
console.log(`✓ ${resolved === "project" ? "Project" : "Global"} memory saved: "${text}"${hint}`);
|
|
36
57
|
}
|
|
37
58
|
export async function runMemorySearch(queryTokens, scope) {
|
|
38
59
|
const query = queryTokens.join(" ");
|
|
39
60
|
if (!query)
|
|
40
61
|
throw new CliError("Usage: min-agent memory search <query> [--project|--global]");
|
|
41
62
|
const scopes = scope ? [scope] : ["project", "global"];
|
|
42
|
-
const lines =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
lines.push(` [${s}] #${m.index + 1}: ${m.content}${tags}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
63
|
+
const lines = scopes.flatMap((s) => searchMemories(query, s).map((m) => {
|
|
64
|
+
const tags = m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
|
|
65
|
+
return ` [${s}] #${m.index + 1}: ${m.content}${tags}`;
|
|
66
|
+
}));
|
|
49
67
|
if (lines.length === 0) {
|
|
50
68
|
console.log(`No memories matching "${query}"`);
|
|
51
69
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { runThinkCli } from "../../think-cli.js";
|
|
2
|
+
export async function runThinkCommand(args, opts, parentOpts) {
|
|
3
|
+
const scope = opts.project ? "project" : opts.global ? "global" : undefined;
|
|
4
|
+
const result = runThinkCli({
|
|
5
|
+
positionals: args,
|
|
6
|
+
flagEffort: parentOpts.think,
|
|
7
|
+
scope,
|
|
8
|
+
});
|
|
9
|
+
console.log(result.lines.join("\n"));
|
|
10
|
+
if (!result.ok)
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { runSandboxCli } from "../../sandbox-cli.js";
|
|
2
2
|
import { runPermissionCli } from "../../permission-cli.js";
|
|
3
|
+
import { runThinkCli } from "../../think-cli.js";
|
|
4
|
+
import { runMemoryCli } from "../../memory-cli.js";
|
|
3
5
|
export async function runWriteConfig(input) {
|
|
4
6
|
const lines = [];
|
|
5
7
|
let ok = true;
|
|
@@ -24,6 +26,26 @@ export async function runWriteConfig(input) {
|
|
|
24
26
|
if (!result.ok)
|
|
25
27
|
ok = false;
|
|
26
28
|
}
|
|
29
|
+
if (input.think !== undefined) {
|
|
30
|
+
const result = runThinkCli({
|
|
31
|
+
positionals: [],
|
|
32
|
+
flagEffort: input.think,
|
|
33
|
+
scope: input.scope,
|
|
34
|
+
});
|
|
35
|
+
lines.push(...result.lines);
|
|
36
|
+
if (!result.ok)
|
|
37
|
+
ok = false;
|
|
38
|
+
}
|
|
39
|
+
if (input.memory !== undefined) {
|
|
40
|
+
const result = runMemoryCli({
|
|
41
|
+
positionals: [],
|
|
42
|
+
flagMode: input.memory,
|
|
43
|
+
scope: input.scope,
|
|
44
|
+
});
|
|
45
|
+
lines.push(...result.lines);
|
|
46
|
+
if (!result.ok)
|
|
47
|
+
ok = false;
|
|
48
|
+
}
|
|
27
49
|
console.log(lines.join("\n"));
|
|
28
50
|
if (!ok)
|
|
29
51
|
process.exitCode = 1;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from "commander";
|
|
2
2
|
import { parseNetworkPolicy, parseSandboxMode } from "../sandbox.js";
|
|
3
|
-
import { parsePermissionMode } from "../config.js";
|
|
3
|
+
import { parsePermissionMode, parseThinkingEffort, parseMemoryMode, } from "../config.js";
|
|
4
4
|
import { userError } from "./errors.js";
|
|
5
5
|
/** Reusable --project / --global mutually exclusive scope selector. */
|
|
6
6
|
export function scopeOptions() {
|
|
@@ -35,6 +35,18 @@ export function parsePermissionModeArg(value) {
|
|
|
35
35
|
throw userError(`Invalid --permission value: "${value}"`, "use one of: ask, accept-edits, allow-all");
|
|
36
36
|
return parsed;
|
|
37
37
|
}
|
|
38
|
+
export function parseThinkingEffortArg(value) {
|
|
39
|
+
const parsed = parseThinkingEffort(value);
|
|
40
|
+
if (!parsed)
|
|
41
|
+
throw userError(`Invalid --think value: "${value}"`, "use one of: off, low, medium, high, max");
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
export function parseMemoryModeArg(value) {
|
|
45
|
+
const parsed = parseMemoryMode(value);
|
|
46
|
+
if (!parsed)
|
|
47
|
+
throw userError(`Invalid --memory value: "${value}"`, "use one of: on, off");
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
38
50
|
export function parsePortArg(value) {
|
|
39
51
|
const n = Number.parseInt(value, 10);
|
|
40
52
|
if (!Number.isFinite(n) || n <= 0 || n > 65535) {
|
package/dist/cli/program.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Option } from "commander";
|
|
2
2
|
import { setAutoApprove } from "../confirm.js";
|
|
3
3
|
import { CliError, formatCliError, exitCodeFor } from "./errors.js";
|
|
4
|
-
import { parseNetworkPolicyArg, parsePermissionModeArg, parseSandboxModeArg } from "./option-helpers.js";
|
|
4
|
+
import { parseNetworkPolicyArg, parsePermissionModeArg, parseSandboxModeArg, parseThinkingEffortArg, parseMemoryModeArg, } from "./option-helpers.js";
|
|
5
5
|
import { localVersion } from "../updater.js";
|
|
6
6
|
function collectImage(value, previous) {
|
|
7
7
|
return [...previous, value];
|
|
@@ -16,8 +16,10 @@ export function addSessionOptions(cmd) {
|
|
|
16
16
|
.addOption(new Option("--sandbox <mode>", "Isolation mode (off, workspace, strict)").argParser(parseSandboxModeArg))
|
|
17
17
|
.addOption(new Option("--network <policy>", "Network policy (allow, deny)").argParser(parseNetworkPolicyArg))
|
|
18
18
|
.addOption(new Option("--permission <mode>", "Confirmation mode (ask, accept-edits, allow-all)").argParser(parsePermissionModeArg))
|
|
19
|
-
.
|
|
20
|
-
.
|
|
19
|
+
.addOption(new Option("--think <level>", "Thinking intensity (off, low, medium, high, max)").argParser(parseThinkingEffortArg))
|
|
20
|
+
.addOption(new Option("--memory <mode>", "Memory across sessions (on, off; default off)").argParser(parseMemoryModeArg))
|
|
21
|
+
.option("--project", "Write --permission/--sandbox/--think/--memory to this repo's config")
|
|
22
|
+
.option("--global", "Write --permission/--sandbox/--think/--memory to the global config")
|
|
21
23
|
.option("-y, --yes", "This session only: same as --permission allow-all");
|
|
22
24
|
}
|
|
23
25
|
export function buildProgram() {
|
|
@@ -49,10 +51,12 @@ Setup & config:
|
|
|
49
51
|
min-agent init Initialize .min-agent/ in current directory
|
|
50
52
|
min-agent models List available models
|
|
51
53
|
min-agent rules [edit] Show or edit instruction rules
|
|
52
|
-
min-agent memory
|
|
54
|
+
min-agent memory [on|off] Show or set memory (off by default)
|
|
55
|
+
min-agent memory <add|search|delete> Manage saved memories
|
|
53
56
|
min-agent sandbox [off|workspace|strict] Show or set isolation mode
|
|
54
57
|
min-agent sandbox network <allow|deny> Show or set network policy
|
|
55
58
|
min-agent permission [ask|accept-edits|allow-all] Show or set confirmation mode
|
|
59
|
+
min-agent think [off|low|medium|high|max] Show or set thinking intensity
|
|
56
60
|
|
|
57
61
|
Integrations:
|
|
58
62
|
min-agent mcp <list|add|remove|info|check|enable|disable> Manage MCP servers
|
|
@@ -68,6 +72,17 @@ Confirmation modes (default: ask; independent of isolation):
|
|
|
68
72
|
accept-edits Auto-approve file writes; still prompt for dangerous commands
|
|
69
73
|
allow-all Auto-approve everything
|
|
70
74
|
|
|
75
|
+
Thinking intensity (default: medium):
|
|
76
|
+
off Disable thinking
|
|
77
|
+
low Light reasoning
|
|
78
|
+
medium Standard reasoning
|
|
79
|
+
high Strong reasoning
|
|
80
|
+
max Highest reasoning
|
|
81
|
+
|
|
82
|
+
Memory (default: off):
|
|
83
|
+
off Do not inject memories or expose memory tools
|
|
84
|
+
on Remember facts across sessions
|
|
85
|
+
|
|
71
86
|
Isolation modes (default: off; independent of confirmation):
|
|
72
87
|
off No sandboxing
|
|
73
88
|
workspace Restrict file writes to the project workspace
|
|
@@ -87,6 +102,8 @@ Examples:
|
|
|
87
102
|
min-agent exec --resume <id> "continue"
|
|
88
103
|
min-agent --resume <id>
|
|
89
104
|
min-agent --permission ask
|
|
105
|
+
min-agent --think max
|
|
106
|
+
min-agent --memory on
|
|
90
107
|
min-agent serve --port 8787
|
|
91
108
|
min-agent update
|
|
92
109
|
min-agent rules edit
|
|
@@ -100,6 +117,27 @@ export function applySessionOverrides(opts) {
|
|
|
100
117
|
if (opts.yes)
|
|
101
118
|
setAutoApprove(true);
|
|
102
119
|
}
|
|
120
|
+
export async function applySessionRuntimeOverrides(opts) {
|
|
121
|
+
if (opts.sandbox !== undefined || opts.network !== undefined) {
|
|
122
|
+
const { setSandboxOverride } = await import("../sandbox.js");
|
|
123
|
+
if (opts.sandbox !== undefined)
|
|
124
|
+
setSandboxOverride({ mode: opts.sandbox });
|
|
125
|
+
if (opts.network !== undefined)
|
|
126
|
+
setSandboxOverride({ network: opts.network });
|
|
127
|
+
}
|
|
128
|
+
if (opts.permission !== undefined) {
|
|
129
|
+
const { setPermissionOverride } = await import("../confirm.js");
|
|
130
|
+
setPermissionOverride(opts.permission);
|
|
131
|
+
}
|
|
132
|
+
if (opts.think !== undefined) {
|
|
133
|
+
const { setThinkingOverride } = await import("../thinking.js");
|
|
134
|
+
setThinkingOverride(opts.think);
|
|
135
|
+
}
|
|
136
|
+
if (opts.memory !== undefined) {
|
|
137
|
+
const { setMemoryOverride } = await import("../memory.js");
|
|
138
|
+
setMemoryOverride(opts.memory);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
103
141
|
export function hasSessionIntent(opts, prompt) {
|
|
104
142
|
return (prompt.length > 0 || Boolean(opts.resume) || opts.image.length > 0 || Boolean(opts.model) || Boolean(opts.provider));
|
|
105
143
|
}
|
|
@@ -117,27 +155,26 @@ export function extractUnknownOptionErrors(positionals) {
|
|
|
117
155
|
}
|
|
118
156
|
async function runRootAction(promptTokens, opts) {
|
|
119
157
|
applySessionOverrides(opts);
|
|
120
|
-
const { setSandboxOverride } = await import("../sandbox.js");
|
|
121
|
-
const { setPermissionOverride } = await import("../confirm.js");
|
|
122
158
|
const { rest, errors } = extractUnknownOptionErrors(promptTokens);
|
|
123
159
|
const sessionIntent = hasSessionIntent(opts, rest);
|
|
124
|
-
const wantsConfigWrite = opts.sandbox !== undefined ||
|
|
160
|
+
const wantsConfigWrite = opts.sandbox !== undefined ||
|
|
161
|
+
opts.network !== undefined ||
|
|
162
|
+
opts.permission !== undefined ||
|
|
163
|
+
opts.think !== undefined ||
|
|
164
|
+
opts.memory !== undefined;
|
|
125
165
|
if (wantsConfigWrite && !sessionIntent) {
|
|
126
166
|
const { runWriteConfig } = await import("./commands/write-config.js");
|
|
127
167
|
await runWriteConfig({
|
|
128
168
|
sandbox: opts.sandbox,
|
|
129
169
|
network: opts.network,
|
|
130
170
|
permission: opts.permission,
|
|
171
|
+
think: opts.think,
|
|
172
|
+
memory: opts.memory,
|
|
131
173
|
scope: opts.project ? "project" : opts.global ? "global" : undefined,
|
|
132
174
|
});
|
|
133
175
|
return;
|
|
134
176
|
}
|
|
135
|
-
|
|
136
|
-
setSandboxOverride({ mode: opts.sandbox });
|
|
137
|
-
if (opts.network !== undefined)
|
|
138
|
-
setSandboxOverride({ network: opts.network });
|
|
139
|
-
if (opts.permission !== undefined)
|
|
140
|
-
setPermissionOverride(opts.permission);
|
|
177
|
+
await applySessionRuntimeOverrides(opts);
|
|
141
178
|
if (errors.length > 0) {
|
|
142
179
|
console.error(errors[0]);
|
|
143
180
|
process.exitCode = 1;
|
package/dist/code-mode.js
CHANGED
|
@@ -149,7 +149,7 @@ export function buildCodeSystemPrompt(project, instructions) {
|
|
|
149
149
|
"- When the user asks to configure, install, or manage MCP servers, skills, rules, memory, permission, sandbox, providers, plugins, or other min-agent settings, follow the built-in `self-config` skill (already loaded). If its instructions are missing, load it with the skill tool before making changes.",
|
|
150
150
|
"",
|
|
151
151
|
"# Workflow",
|
|
152
|
-
"- For greetings, thanks, or general chat with no concrete task, reply directly — do not call any tools. The Project Structure below already covers the basics; do not re-explore the codebase just to answer a greeting.",
|
|
152
|
+
"- For greetings, thanks, or general chat with no concrete task, reply directly — do not call any tools. Memories and session state are not a reason to start work; only the current user message is. The Project Structure below already covers the basics; do not re-explore the codebase just to answer a greeting.",
|
|
153
153
|
"- Use search tools (grep, glob) to understand the codebase before making changes, only once the user gives a concrete task.",
|
|
154
154
|
"- Use the search_web tool for live web search. Never emit XML tags such as <web_search>.",
|
|
155
155
|
"- After a few targeted web searches and fetching the best sources, stop researching and produce the requested output.",
|