min-agent 0.5.0 → 0.6.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 (156) hide show
  1. package/README.md +32 -18
  2. package/dist/cli.js +538 -12
  3. package/docs/API.md +25 -8
  4. package/package.json +6 -6
  5. package/skills/self-config/SKILL.md +7 -3
  6. package/skills/self-config/reference.md +8 -4
  7. package/dist/agent.js +0 -1342
  8. package/dist/assistant-stream.js +0 -131
  9. package/dist/cli/commands/chat.js +0 -13
  10. package/dist/cli/commands/exec.js +0 -35
  11. package/dist/cli/commands/history.js +0 -58
  12. package/dist/cli/commands/index.js +0 -241
  13. package/dist/cli/commands/init.js +0 -18
  14. package/dist/cli/commands/mcp.js +0 -173
  15. package/dist/cli/commands/memory.js +0 -87
  16. package/dist/cli/commands/models.js +0 -21
  17. package/dist/cli/commands/permission.js +0 -12
  18. package/dist/cli/commands/rules.js +0 -33
  19. package/dist/cli/commands/sandbox.js +0 -13
  20. package/dist/cli/commands/serve.js +0 -9
  21. package/dist/cli/commands/setup.js +0 -4
  22. package/dist/cli/commands/shared.js +0 -16
  23. package/dist/cli/commands/skills.js +0 -119
  24. package/dist/cli/commands/think.js +0 -12
  25. package/dist/cli/commands/update.js +0 -7
  26. package/dist/cli/commands/write-config.js +0 -52
  27. package/dist/cli/errors.js +0 -36
  28. package/dist/cli/exec-prompt.js +0 -26
  29. package/dist/cli/option-helpers.js +0 -65
  30. package/dist/cli/program.js +0 -217
  31. package/dist/clipboard.js +0 -142
  32. package/dist/code-mode.js +0 -184
  33. package/dist/compaction.js +0 -644
  34. package/dist/config.js +0 -470
  35. package/dist/confirm.js +0 -172
  36. package/dist/context-window.js +0 -246
  37. package/dist/doom-loop.js +0 -278
  38. package/dist/fetch-timeout.js +0 -152
  39. package/dist/http-approvals.js +0 -60
  40. package/dist/http.js +0 -119
  41. package/dist/instructions.js +0 -196
  42. package/dist/logger.js +0 -95
  43. package/dist/markdown.js +0 -259
  44. package/dist/mcp.js +0 -1036
  45. package/dist/memory-cli.js +0 -33
  46. package/dist/memory.js +0 -295
  47. package/dist/model-catalog.js +0 -285
  48. package/dist/output.js +0 -76
  49. package/dist/paste-handler.js +0 -41
  50. package/dist/permission-cli.js +0 -40
  51. package/dist/plugins.js +0 -131
  52. package/dist/pricing.js +0 -119
  53. package/dist/provider.js +0 -63
  54. package/dist/question-format.js +0 -60
  55. package/dist/reasoning-stream.js +0 -158
  56. package/dist/sandbox-cli.js +0 -79
  57. package/dist/sandbox.js +0 -403
  58. package/dist/save-throttle.js +0 -45
  59. package/dist/scope.js +0 -23
  60. package/dist/serve/common.js +0 -425
  61. package/dist/serve/routes-chat.js +0 -367
  62. package/dist/serve/routes-mcp.js +0 -212
  63. package/dist/serve/routes-memory.js +0 -95
  64. package/dist/serve/routes-meta.js +0 -233
  65. package/dist/serve/routes-sessions.js +0 -61
  66. package/dist/serve/routes-skills.js +0 -70
  67. package/dist/serve.js +0 -138
  68. package/dist/sessions.js +0 -265
  69. package/dist/skills.js +0 -599
  70. package/dist/structured-output.js +0 -29
  71. package/dist/synthetic.js +0 -7
  72. package/dist/think-cli.js +0 -36
  73. package/dist/thinking-wire.js +0 -228
  74. package/dist/thinking.js +0 -142
  75. package/dist/title-gen.js +0 -55
  76. package/dist/token-display.js +0 -39
  77. package/dist/tool-display.js +0 -178
  78. package/dist/tool-output.js +0 -126
  79. package/dist/tools/apply_patch.js +0 -265
  80. package/dist/tools/atomic-file.js +0 -35
  81. package/dist/tools/backend.js +0 -61
  82. package/dist/tools/bash.js +0 -231
  83. package/dist/tools/code_search.js +0 -98
  84. package/dist/tools/edit.js +0 -68
  85. package/dist/tools/explore.js +0 -232
  86. package/dist/tools/glob.js +0 -40
  87. package/dist/tools/grep.js +0 -174
  88. package/dist/tools/index.js +0 -34
  89. package/dist/tools/question.js +0 -54
  90. package/dist/tools/read.js +0 -109
  91. package/dist/tools/search-searxng.js +0 -223
  92. package/dist/tools/search-serper.js +0 -189
  93. package/dist/tools/task.js +0 -165
  94. package/dist/tools/todo.js +0 -213
  95. package/dist/tools/web_fetch.js +0 -195
  96. package/dist/tools/web_search.js +0 -228
  97. package/dist/tools/write.js +0 -55
  98. package/dist/tui/App.js +0 -126
  99. package/dist/tui/ConfirmBar.js +0 -66
  100. package/dist/tui/InputBar.js +0 -616
  101. package/dist/tui/MessageList.js +0 -718
  102. package/dist/tui/ModelPicker.js +0 -113
  103. package/dist/tui/QuestionBar.js +0 -136
  104. package/dist/tui/SessionPicker.js +0 -79
  105. package/dist/tui/Spinner.js +0 -6
  106. package/dist/tui/StatusBar.js +0 -22
  107. package/dist/tui/ThinkPicker.js +0 -77
  108. package/dist/tui/agent-runner.js +0 -223
  109. package/dist/tui/bracketed-paste.js +0 -37
  110. package/dist/tui/caret-pos.js +0 -179
  111. package/dist/tui/caret.js +0 -69
  112. package/dist/tui/click-count.js +0 -13
  113. package/dist/tui/diff-view.js +0 -61
  114. package/dist/tui/drag-state.js +0 -49
  115. package/dist/tui/hydrate.js +0 -129
  116. package/dist/tui/index.js +0 -258
  117. package/dist/tui/input-history.js +0 -125
  118. package/dist/tui/layout.js +0 -105
  119. package/dist/tui/mouse.js +0 -46
  120. package/dist/tui/overlay-input.js +0 -12
  121. package/dist/tui/paste-draft.js +0 -173
  122. package/dist/tui/prompt-queue.js +0 -24
  123. package/dist/tui/selection.js +0 -232
  124. package/dist/tui/session-switch.js +0 -28
  125. package/dist/tui/slash-commands.js +0 -123
  126. package/dist/tui/slash-handler.js +0 -589
  127. package/dist/tui/text-width.js +0 -113
  128. package/dist/tui/theme.js +0 -12
  129. package/dist/tui/token-info.js +0 -7
  130. package/dist/tui/tool-children.js +0 -19
  131. package/dist/tui/types.js +0 -1
  132. package/dist/tui/undo-stack.js +0 -14
  133. package/dist/tui/use-sgr-mouse.js +0 -29
  134. package/dist/tui-chat.js +0 -456
  135. package/dist/updater.js +0 -116
  136. package/dist/xml-search.js +0 -194
  137. package/docs/superpowers/plans/2026-08-16-batch1-tui-improvements.md +0 -1510
  138. package/docs/superpowers/plans/2026-08-16-batch2-cli-tools-api.md +0 -2105
  139. package/docs/superpowers/plans/2026-08-16-batch3-config-engineering.md +0 -1595
  140. package/docs/superpowers/plans/2026-08-16-input-caret.md +0 -782
  141. package/docs/superpowers/plans/2026-08-20-tui-completeness.md +0 -873
  142. package/docs/superpowers/plans/2026-08-20-unified-tui-default.md +0 -631
  143. package/docs/superpowers/plans/2026-08-23-input-paste-attachments.md +0 -475
  144. package/docs/superpowers/plans/2026-08-23-thinking-wire-profile.md +0 -450
  145. package/docs/superpowers/specs/2026-08-16-batch1-tui-improvements-design.md +0 -183
  146. package/docs/superpowers/specs/2026-08-16-batch2-cli-tools-api-design.md +0 -220
  147. package/docs/superpowers/specs/2026-08-16-batch3-config-engineering-design.md +0 -196
  148. package/docs/superpowers/specs/2026-08-16-input-caret-design.md +0 -63
  149. package/docs/superpowers/specs/2026-08-17-mouse-selection-design.md +0 -116
  150. package/docs/superpowers/specs/2026-08-20-config-http-alignment-design.md +0 -47
  151. package/docs/superpowers/specs/2026-08-20-mcp-plugins-alignment-design.md +0 -37
  152. package/docs/superpowers/specs/2026-08-20-sandbox-permissions-design.md +0 -68
  153. package/docs/superpowers/specs/2026-08-20-tui-completeness-design.md +0 -273
  154. package/docs/superpowers/specs/2026-08-20-unified-tui-default-design.md +0 -165
  155. package/docs/superpowers/specs/2026-08-23-input-paste-attachments-design.md +0 -174
  156. package/docs/superpowers/specs/2026-08-23-thinking-wire-profile-design.md +0 -140
@@ -1,217 +0,0 @@
1
- import { Command, Option } from "commander";
2
- import { setAutoApprove } from "../confirm.js";
3
- import { CliError, formatCliError, exitCodeFor } from "./errors.js";
4
- import { parseNetworkPolicyArg, parsePermissionModeArg, parseSandboxModeArg, parseThinkingEffortArg, parseMemoryModeArg, } from "./option-helpers.js";
5
- import { localVersion } from "../updater.js";
6
- function collectImage(value, previous) {
7
- return [...previous, value];
8
- }
9
- /** Options shared across the root command and `exec` (session-affecting flags). */
10
- export function addSessionOptions(cmd) {
11
- return cmd
12
- .option("-m, --model <model>", "Override model for this request")
13
- .option("--provider <name>", "Use a specific configured provider")
14
- .option("--resume <id>", "Resume a previous session by id")
15
- .option("-i, --image <path>", "Attach an image (repeatable)", collectImage, [])
16
- .addOption(new Option("--sandbox <mode>", "Isolation mode (off, workspace, strict)").argParser(parseSandboxModeArg))
17
- .addOption(new Option("--network <policy>", "Network policy (allow, deny)").argParser(parseNetworkPolicyArg))
18
- .addOption(new Option("--permission <mode>", "Confirmation mode (ask, accept-edits, allow-all)").argParser(parsePermissionModeArg))
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")
23
- .option("-y, --yes", "This session only: same as --permission allow-all");
24
- }
25
- export function buildProgram() {
26
- const program = new Command("min-agent");
27
- program
28
- .description("min-agent - Minimal AI coding agent")
29
- .version(localVersion(), "-v, --version", "Show version number")
30
- .helpOption("-h, --help", "Show help")
31
- .allowUnknownOption()
32
- .enablePositionalOptions()
33
- .configureOutput({
34
- writeErr: (str) => process.stderr.write(str),
35
- outputError: (str) => process.stderr.write(str),
36
- })
37
- .exitOverride();
38
- addSessionOptions(program);
39
- program.argument("[prompt...]", "Prompt to send in an interactive session");
40
- program.addHelpText("after", `
41
- Session:
42
- min-agent Start interactive session
43
- min-agent <message> Start interactive session and send message
44
- min-agent --resume <id> Resume a previous interactive session
45
- min-agent chat | code Same as interactive session (compat)
46
- min-agent exec <message> Run one message non-interactively
47
- min-agent exec --resume <id> <msg> Continue a saved exec session
48
-
49
- Setup & config:
50
- min-agent setup Configure providers (interactively)
51
- min-agent init Initialize .min-agent/ in current directory
52
- min-agent models List available models
53
- min-agent rules [edit] Show or edit instruction rules
54
- min-agent memory [on|off] Show or set memory (off by default)
55
- min-agent memory <add|search|delete> Manage saved memories
56
- min-agent sandbox [off|workspace|strict] Show or set isolation mode
57
- min-agent sandbox network <allow|deny> Show or set network policy
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
60
-
61
- Integrations:
62
- min-agent mcp <list|add|remove|info|check|enable|disable> Manage MCP servers
63
- min-agent skills <list|info|new|enable|disable> Manage skills
64
-
65
- Operations:
66
- min-agent serve [--host H] [--port P] Start the HTTP API (see docs/API.md)
67
- min-agent history [delete|rename|export] Manage saved sessions
68
- min-agent update Upgrade to the latest npm release
69
-
70
- Confirmation modes (default: ask; independent of isolation):
71
- ask Prompt before dangerous operations
72
- accept-edits Auto-approve file writes; still prompt for dangerous commands
73
- allow-all Auto-approve everything
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
-
86
- Isolation modes (default: off; independent of confirmation):
87
- off No sandboxing
88
- workspace Restrict file writes to the project workspace
89
- strict Restrict file writes and deny risky commands
90
- Env: MIN_AGENT_SANDBOX, MIN_AGENT_SANDBOX_NETWORK
91
-
92
- Rules (loaded as system instructions):
93
- Global: ~/.min-agent/rules.md
94
- Project: ./AGENTS.md or ./RULES.md or ./.min-agent/AGENTS.md
95
- Config: "instructions" array in ~/.min-agent/config.json
96
-
97
- Examples:
98
- min-agent setup
99
- min-agent
100
- min-agent "hello"
101
- min-agent exec "hello"
102
- min-agent exec --resume <id> "continue"
103
- min-agent --resume <id>
104
- min-agent --permission ask
105
- min-agent --think max
106
- min-agent --memory on
107
- min-agent serve --port 8787
108
- min-agent update
109
- min-agent rules edit
110
- min-agent mcp add filesystem npx -y @modelcontextprotocol/server-filesystem /tmp
111
- min-agent mcp add remote --url https://example.com/mcp --token "$TOKEN"
112
- `);
113
- return program;
114
- }
115
- /** Apply --yes/-y for this process. Sandbox/permission overrides are applied per-invocation-kind. */
116
- export function applySessionOverrides(opts) {
117
- if (opts.yes)
118
- setAutoApprove(true);
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
- }
141
- export function hasSessionIntent(opts, prompt) {
142
- return (prompt.length > 0 || Boolean(opts.resume) || opts.image.length > 0 || Boolean(opts.model) || Boolean(opts.provider));
143
- }
144
- /** Extract `--unknown` style tokens left over in positionals (from allowUnknownOption) as errors. */
145
- export function extractUnknownOptionErrors(positionals) {
146
- const rest = [];
147
- const errors = [];
148
- for (const p of positionals) {
149
- if (p.startsWith("--"))
150
- errors.push(`Unknown option: ${p}`);
151
- else
152
- rest.push(p);
153
- }
154
- return { rest, errors };
155
- }
156
- async function runRootAction(promptTokens, opts) {
157
- applySessionOverrides(opts);
158
- const { rest, errors } = extractUnknownOptionErrors(promptTokens);
159
- const sessionIntent = hasSessionIntent(opts, rest);
160
- const wantsConfigWrite = opts.sandbox !== undefined ||
161
- opts.network !== undefined ||
162
- opts.permission !== undefined ||
163
- opts.think !== undefined ||
164
- opts.memory !== undefined;
165
- if (wantsConfigWrite && !sessionIntent) {
166
- const { runWriteConfig } = await import("./commands/write-config.js");
167
- await runWriteConfig({
168
- sandbox: opts.sandbox,
169
- network: opts.network,
170
- permission: opts.permission,
171
- think: opts.think,
172
- memory: opts.memory,
173
- scope: opts.project ? "project" : opts.global ? "global" : undefined,
174
- });
175
- return;
176
- }
177
- await applySessionRuntimeOverrides(opts);
178
- if (errors.length > 0) {
179
- console.error(errors[0]);
180
- process.exitCode = 1;
181
- return;
182
- }
183
- const { startTuiSession } = await import("./commands/shared.js");
184
- await startTuiSession({
185
- model: opts.model,
186
- provider: opts.provider,
187
- resume: opts.resume,
188
- images: opts.image,
189
- positionals: rest,
190
- });
191
- }
192
- export async function runProgram(argv, registerCommands) {
193
- const program = buildProgram();
194
- program.action((promptTokens, opts) => runRootAction(promptTokens, opts));
195
- registerCommands(program);
196
- try {
197
- await program.parseAsync(argv, { from: "user" });
198
- }
199
- catch (err) {
200
- if (err instanceof CliError) {
201
- console.error(formatCliError(err));
202
- process.exitCode = exitCodeFor(err);
203
- return;
204
- }
205
- // Commander throws a CommanderError for --help/--version and for its own
206
- // usage errors; those already printed output and set process.exitCode.
207
- if (isCommanderExit(err)) {
208
- process.exitCode = err.exitCode;
209
- return;
210
- }
211
- console.error(formatCliError(err));
212
- process.exitCode = 2;
213
- }
214
- }
215
- function isCommanderExit(err) {
216
- return typeof err === "object" && err !== null && "exitCode" in err && "code" in err;
217
- }
package/dist/clipboard.js DELETED
@@ -1,142 +0,0 @@
1
- import { execSync } from "child_process";
2
- import { readFileSync, unlinkSync } from "fs";
3
- import path from "path";
4
- import os from "os";
5
- function readTmpImage(tmpFile) {
6
- const data = readFileSync(tmpFile);
7
- try {
8
- unlinkSync(tmpFile);
9
- }
10
- catch { }
11
- return data.length > 0 ? data : null;
12
- }
13
- function tmpImagePath() {
14
- return path.join(os.tmpdir(), `min-agent-paste-${Date.now()}.png`);
15
- }
16
- export function getClipboardImage() {
17
- switch (process.platform) {
18
- case "darwin":
19
- return getClipboardImageMac();
20
- case "linux":
21
- return getClipboardImageLinux();
22
- case "win32":
23
- return getClipboardImageWindows();
24
- default:
25
- return null;
26
- }
27
- }
28
- /** Write plain text to the system clipboard. False on failure (silent). */
29
- export function writeClipboard(text) {
30
- switch (process.platform) {
31
- case "darwin":
32
- try {
33
- execSync("pbcopy", { input: text, stdio: "pipe" });
34
- return true;
35
- }
36
- catch {
37
- return false;
38
- }
39
- case "linux": {
40
- try {
41
- execSync("xclip -selection clipboard", { input: text, stdio: "pipe" });
42
- return true;
43
- }
44
- catch { }
45
- try {
46
- execSync("xsel --clipboard --input", { input: text, stdio: "pipe" });
47
- return true;
48
- }
49
- catch { }
50
- return false;
51
- }
52
- case "win32":
53
- try {
54
- execSync('powershell -NoProfile -Command "Set-Clipboard -Value ([Console]::In.ReadToEnd())"', {
55
- input: text,
56
- stdio: "pipe",
57
- });
58
- return true;
59
- }
60
- catch {
61
- return false;
62
- }
63
- default:
64
- return false;
65
- }
66
- }
67
- function getClipboardImageMac() {
68
- const tmpFile = tmpImagePath();
69
- try {
70
- // Try pngpaste first (brew install pngpaste)
71
- execSync(`pngpaste "${tmpFile}" 2>/dev/null`, { stdio: "pipe" });
72
- const data = readTmpImage(tmpFile);
73
- if (data)
74
- return { data, mimeType: "image/png" };
75
- }
76
- catch { }
77
- try {
78
- // Fallback: osascript to save clipboard image
79
- const script = `
80
- set tmpFile to POSIX file "${tmpFile}"
81
- try
82
- set imgData to the clipboard as «class PNGf»
83
- set fp to open for access tmpFile with write permission
84
- write imgData to fp
85
- close access fp
86
- return "ok"
87
- on error
88
- return "no_image"
89
- end try
90
- `;
91
- const result = execSync(`osascript -e '${script.replace(/'/g, "'\\''")}'`, { encoding: "utf-8" }).trim();
92
- if (result === "ok") {
93
- const data = readTmpImage(tmpFile);
94
- if (data)
95
- return { data, mimeType: "image/png" };
96
- }
97
- }
98
- catch { }
99
- return null;
100
- }
101
- function getClipboardImageLinux() {
102
- try {
103
- // xclip
104
- const data = execSync("xclip -selection clipboard -t image/png -o 2>/dev/null", {
105
- maxBuffer: 10 * 1024 * 1024,
106
- });
107
- if (data.length > 0)
108
- return { data, mimeType: "image/png" };
109
- }
110
- catch { }
111
- try {
112
- // xsel fallback
113
- const data = execSync("xsel --clipboard --output 2>/dev/null", {
114
- maxBuffer: 10 * 1024 * 1024,
115
- });
116
- // Check if it's actually image data (PNG magic bytes)
117
- if (data.length > 8 && data[0] === 0x89 && data[1] === 0x50) {
118
- return { data, mimeType: "image/png" };
119
- }
120
- }
121
- catch { }
122
- return null;
123
- }
124
- function getClipboardImageWindows() {
125
- const tmpFile = tmpImagePath();
126
- try {
127
- const ps = `
128
- Add-Type -AssemblyName System.Windows.Forms
129
- $img = [System.Windows.Forms.Clipboard]::GetImage()
130
- if ($img) { $img.Save('${tmpFile.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' }
131
- else { Write-Output 'no_image' }
132
- `;
133
- const result = execSync(`powershell -NoProfile -Command "${ps}"`, { encoding: "utf-8" }).trim();
134
- if (result === "ok") {
135
- const data = readTmpImage(tmpFile);
136
- if (data)
137
- return { data, mimeType: "image/png" };
138
- }
139
- }
140
- catch { }
141
- return null;
142
- }
package/dist/code-mode.js DELETED
@@ -1,184 +0,0 @@
1
- import { execSync } from "child_process";
2
- import { existsSync, readFileSync, readdirSync, statSync } from "fs";
3
- import path from "path";
4
- export function scanProject() {
5
- const cwd = process.cwd();
6
- const isGitRepo = existsSync(path.join(cwd, ".git"));
7
- let branch;
8
- if (isGitRepo) {
9
- try {
10
- branch = execSync("git branch --show-current", { encoding: "utf-8", cwd, timeout: 5000 }).trim();
11
- }
12
- catch { }
13
- }
14
- const languages = [];
15
- const configFiles = [];
16
- const entryFiles = [];
17
- // Detect by config files (lockfiles first so they win over package.json)
18
- const checks = [
19
- { file: "bun.lock", lang: "TypeScript/JavaScript", pm: "bun" },
20
- { file: "yarn.lock", lang: "TypeScript/JavaScript", pm: "yarn" },
21
- { file: "pnpm-lock.yaml", lang: "TypeScript/JavaScript", pm: "pnpm" },
22
- { file: "package.json", lang: "TypeScript/JavaScript", pm: "npm" },
23
- { file: "tsconfig.json", lang: "TypeScript" },
24
- { file: "Cargo.toml", lang: "Rust", pm: "cargo" },
25
- { file: "go.mod", lang: "Go" },
26
- { file: "pyproject.toml", lang: "Python", pm: "pip/uv" },
27
- { file: "requirements.txt", lang: "Python", pm: "pip" },
28
- { file: "Gemfile", lang: "Ruby", pm: "bundler" },
29
- { file: "pom.xml", lang: "Java", pm: "maven" },
30
- { file: "build.gradle", lang: "Java/Kotlin", pm: "gradle" },
31
- { file: "composer.json", lang: "PHP", pm: "composer" },
32
- { file: "Makefile", lang: "" },
33
- { file: "Dockerfile", lang: "" },
34
- ];
35
- let packageManager;
36
- let framework;
37
- for (const check of checks) {
38
- if (existsSync(path.join(cwd, check.file))) {
39
- configFiles.push(check.file);
40
- if (check.lang && !languages.includes(check.lang))
41
- languages.push(check.lang);
42
- if (check.pm && !packageManager)
43
- packageManager = check.pm;
44
- }
45
- }
46
- // Detect framework from package.json
47
- if (existsSync(path.join(cwd, "package.json"))) {
48
- try {
49
- const pkg = JSON.parse(readFileSync(path.join(cwd, "package.json"), "utf-8"));
50
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
51
- if (allDeps.next)
52
- framework = "Next.js";
53
- else if (allDeps.nuxt)
54
- framework = "Nuxt";
55
- else if (allDeps["@angular/core"])
56
- framework = "Angular";
57
- else if (allDeps.vue)
58
- framework = "Vue";
59
- else if (allDeps.react)
60
- framework = "React";
61
- else if (allDeps.svelte)
62
- framework = "Svelte";
63
- else if (allDeps.express)
64
- framework = "Express";
65
- else if (allDeps.fastify)
66
- framework = "Fastify";
67
- else if (allDeps.hono)
68
- framework = "Hono";
69
- else if (allDeps.effect)
70
- framework = "Effect";
71
- }
72
- catch { }
73
- }
74
- // Find entry files
75
- const entryPatterns = [
76
- "src/index.ts",
77
- "src/index.js",
78
- "src/main.ts",
79
- "src/main.js",
80
- "src/app.ts",
81
- "src/app.js",
82
- "index.ts",
83
- "index.js",
84
- "main.ts",
85
- "main.js",
86
- "app.ts",
87
- "app.js",
88
- "src/lib.rs",
89
- "main.go",
90
- "main.py",
91
- "app.py",
92
- ];
93
- for (const p of entryPatterns) {
94
- if (existsSync(path.join(cwd, p)))
95
- entryFiles.push(p);
96
- }
97
- // Build summary
98
- const parts = [];
99
- parts.push(`Directory: ${cwd}`);
100
- if (isGitRepo)
101
- parts.push(`Git: yes (branch: ${branch ?? "unknown"})`);
102
- if (languages.length)
103
- parts.push(`Languages: ${languages.join(", ")}`);
104
- if (framework)
105
- parts.push(`Framework: ${framework}`);
106
- if (packageManager)
107
- parts.push(`Package manager: ${packageManager}`);
108
- if (configFiles.length)
109
- parts.push(`Config files: ${configFiles.join(", ")}`);
110
- if (entryFiles.length)
111
- parts.push(`Entry points: ${entryFiles.join(", ")}`);
112
- // List top-level directory structure
113
- try {
114
- const items = readdirSync(cwd)
115
- .filter((f) => !f.startsWith(".") || f === ".env.example")
116
- .filter((f) => f !== "node_modules" && f !== ".git")
117
- .slice(0, 30)
118
- .map((f) => {
119
- const stat = statSync(path.join(cwd, f));
120
- return stat.isDirectory() ? `${f}/` : f;
121
- });
122
- parts.push(`Structure: ${items.join(", ")}`);
123
- }
124
- catch { }
125
- return {
126
- directory: cwd,
127
- isGitRepo,
128
- branch,
129
- languages,
130
- framework,
131
- packageManager,
132
- entryFiles,
133
- configFiles,
134
- summary: parts.join("\n"),
135
- };
136
- }
137
- export function buildCodeSystemPrompt(project, instructions) {
138
- const parts = [
139
- "You are an expert AI coding assistant. You help users with software engineering tasks including writing code, debugging, refactoring, and architecture decisions.",
140
- "",
141
- "# Principles",
142
- "- Be concise and direct. Minimize output tokens while maintaining quality.",
143
- "- NEVER add comments to code unless asked. Write self-documenting code.",
144
- "- Follow existing code conventions in the project. Mimic style, libraries, and patterns.",
145
- "- NEVER assume a library is available — check package.json/Cargo.toml/etc first.",
146
- "- Prefer editing existing files over creating new ones.",
147
- "- After making changes, run lint/typecheck/build if available.",
148
- "- NEVER commit unless explicitly asked.",
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
- "",
151
- "# Workflow",
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
- "- Use search tools (grep, glob) to understand the codebase before making changes, only once the user gives a concrete task.",
154
- "- Use the search_web tool for live web search. Never emit XML tags such as <web_search>.",
155
- "- After a few targeted web searches and fetching the best sources, stop researching and produce the requested output.",
156
- "- Do not keep searching for completeness, extra models, or slightly better numbers. Mark uncertain dates or scores as estimates and move on.",
157
- "- If the user asked for a file or other artifact, write it as soon as the required fields can be filled. Then stop.",
158
- "- Use the edit tool for precise changes instead of rewriting entire files.",
159
- "- When fixing bugs: read the relevant code, understand the issue, fix it, verify.",
160
- "- When adding features: explore existing patterns first, then implement consistently.",
161
- "- Run tests after changes when a test command is available.",
162
- "",
163
- "# Environment",
164
- `<env>`,
165
- ` Working directory: ${project.directory}`,
166
- ` Git repo: ${project.isGitRepo ? `yes (branch: ${project.branch ?? "unknown"})` : "no"}`,
167
- ` Platform: ${process.platform}`,
168
- ` Date: ${new Date().toDateString()}`,
169
- project.languages.length ? ` Languages: ${project.languages.join(", ")}` : "",
170
- project.framework ? ` Framework: ${project.framework}` : "",
171
- project.packageManager ? ` Package manager: ${project.packageManager}` : "",
172
- `</env>`,
173
- "",
174
- "# Project Structure",
175
- "```",
176
- project.summary,
177
- "```",
178
- ].filter(Boolean);
179
- if (instructions.length > 0) {
180
- parts.push("", "# User Instructions", "");
181
- parts.push(...instructions);
182
- }
183
- return parts.join("\n");
184
- }