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.
Files changed (54) hide show
  1. package/README.md +32 -2
  2. package/dist/agent.js +36 -22
  3. package/dist/cli/commands/chat.js +3 -0
  4. package/dist/cli/commands/exec.js +3 -0
  5. package/dist/cli/commands/index.js +22 -5
  6. package/dist/cli/commands/memory.js +33 -15
  7. package/dist/cli/commands/think.js +12 -0
  8. package/dist/cli/commands/write-config.js +22 -0
  9. package/dist/cli/option-helpers.js +13 -1
  10. package/dist/cli/program.js +50 -13
  11. package/dist/code-mode.js +1 -1
  12. package/dist/config.js +41 -0
  13. package/dist/context-window.js +8 -28
  14. package/dist/memory-cli.js +33 -0
  15. package/dist/memory.js +127 -46
  16. package/dist/model-catalog.js +285 -0
  17. package/dist/permission-cli.js +1 -4
  18. package/dist/provider.js +4 -1
  19. package/dist/reasoning-stream.js +158 -0
  20. package/dist/sandbox-cli.js +1 -4
  21. package/dist/scope.js +23 -0
  22. package/dist/serve/common.js +22 -1
  23. package/dist/serve/routes-chat.js +21 -1
  24. package/dist/serve/routes-memory.js +31 -2
  25. package/dist/serve/routes-meta.js +34 -6
  26. package/dist/think-cli.js +36 -0
  27. package/dist/thinking-wire.js +228 -0
  28. package/dist/thinking.js +142 -0
  29. package/dist/token-display.js +10 -7
  30. package/dist/tools/todo.js +22 -8
  31. package/dist/tui/App.js +36 -8
  32. package/dist/tui/InputBar.js +109 -36
  33. package/dist/tui/MessageList.js +53 -22
  34. package/dist/tui/StatusBar.js +7 -3
  35. package/dist/tui/ThinkPicker.js +77 -0
  36. package/dist/tui/bracketed-paste.js +37 -0
  37. package/dist/tui/caret-pos.js +10 -8
  38. package/dist/tui/index.js +7 -1
  39. package/dist/tui/layout.js +17 -0
  40. package/dist/tui/overlay-input.js +12 -0
  41. package/dist/tui/paste-draft.js +173 -0
  42. package/dist/tui/selection.js +8 -2
  43. package/dist/tui/slash-commands.js +18 -1
  44. package/dist/tui/slash-handler.js +61 -17
  45. package/dist/tui/text-width.js +6 -6
  46. package/dist/tui-chat.js +63 -7
  47. package/docs/API.md +50 -4
  48. package/docs/superpowers/plans/2026-08-23-input-paste-attachments.md +475 -0
  49. package/docs/superpowers/plans/2026-08-23-thinking-wire-profile.md +450 -0
  50. package/docs/superpowers/specs/2026-08-23-input-paste-attachments-design.md +174 -0
  51. package/docs/superpowers/specs/2026-08-23-thinking-wire-profile-design.md +140 -0
  52. package/package.json +1 -1
  53. package/skills/self-config/SKILL.md +5 -4
  54. 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 { getMemorySystemPrompt, getMemoryTools } from "./memory.js";
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 (current, not part of the conversation)";
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
- else
808
- writeThinkingDelta(t);
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
- if (event.text)
1136
- this.renderer.feedReasoning(event.text);
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
- result = streamText({
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("Manage saved memories (uses --project/--global)");
59
- memory.action(async () => {
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
- await runMemoryList(opts.project ? "project" : opts.global ? "global" : undefined);
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 (let i = 0; i < memories.length; i++) {
12
- const m = memories[i];
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
- console.log("The agent will automatically save memories during conversations.");
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
- console.log(`✓ ${resolved === "project" ? "Project" : "Global"} memory saved: "${text}"`);
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
- for (const s of scopes) {
44
- for (const m of searchMemories(query, s)) {
45
- const tags = m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
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) {
@@ -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
- .option("--project", "Write --permission/--sandbox to this repo's config")
20
- .option("--global", "Write --permission/--sandbox to the global config")
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 <add|search|delete|list> Manage saved memories
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 || opts.network !== undefined || opts.permission !== 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
- if (opts.sandbox !== undefined)
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.",