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
package/dist/sessions.js DELETED
@@ -1,265 +0,0 @@
1
- import { readFileSync, mkdirSync, existsSync, readdirSync, unlinkSync, openSync, readSync, closeSync, statSync, } from "fs";
2
- import path from "path";
3
- import { randomUUID } from "crypto";
4
- import { atomicWriteFileSync } from "./tools/atomic-file.js";
5
- import { getConfigDir } from "./config.js";
6
- import { generateTitle } from "./title-gen.js";
7
- import { isSyntheticMessage } from "./synthetic.js";
8
- import { parseTaskState } from "./tools/todo.js";
9
- function getSessionsDir() {
10
- return path.join(getConfigDir(), "sessions");
11
- }
12
- /**
13
- * In-process per-session mutex serializing read-modify-write cycles
14
- * (load → append → run → save) so concurrent requests on the same session
15
- * cannot lose messages. Cross-process safety is NOT provided.
16
- */
17
- const sessionLocks = new Map();
18
- export async function withSessionLock(sessionId, fn) {
19
- if (!sessionId)
20
- return fn();
21
- const prev = sessionLocks.get(sessionId) ?? Promise.resolve();
22
- let release;
23
- const ours = new Promise((r) => {
24
- release = r;
25
- });
26
- const chained = prev.then(() => ours);
27
- sessionLocks.set(sessionId, chained);
28
- await prev;
29
- try {
30
- return await fn();
31
- }
32
- finally {
33
- release();
34
- if (sessionLocks.get(sessionId) === chained)
35
- sessionLocks.delete(sessionId);
36
- }
37
- }
38
- /** Session ids are UUIDs; a strict whitelist blocks path traversal via `/v1/sessions/..%2F..%2Fconfig`. */
39
- const SESSION_ID_RE = /^[a-zA-Z0-9_-]+$/;
40
- function sessionPath(id) {
41
- if (!SESSION_ID_RE.test(id))
42
- throw new Error(`invalid session id: ${id}`);
43
- return path.join(getSessionsDir(), `${id}.json`);
44
- }
45
- /** Session meta lives at the head of the JSON file, so only the first bytes are needed. */
46
- const META_READ_LIMIT = 64 * 1024;
47
- function readHead(file, limit) {
48
- const fd = openSync(file, "r");
49
- try {
50
- const buf = Buffer.alloc(Math.min(statSync(file).size, limit));
51
- if (buf.length === 0)
52
- return "";
53
- readSync(fd, buf, 0, buf.length, 0);
54
- return buf.toString("utf-8");
55
- }
56
- finally {
57
- closeSync(fd);
58
- }
59
- }
60
- /** Find the index of the `}` that closes the object opened at `start`, or -1. */
61
- function matchBrace(text, start) {
62
- let depth = 0;
63
- let inString = false;
64
- let escaped = false;
65
- for (let i = start; i < text.length; i++) {
66
- const ch = text[i];
67
- if (inString) {
68
- if (escaped)
69
- escaped = false;
70
- else if (ch === "\\")
71
- escaped = true;
72
- else if (ch === '"')
73
- inString = false;
74
- continue;
75
- }
76
- if (ch === '"')
77
- inString = true;
78
- else if (ch === "{")
79
- depth++;
80
- else if (ch === "}") {
81
- depth--;
82
- if (depth === 0)
83
- return i;
84
- }
85
- }
86
- return -1;
87
- }
88
- /** Extract the meta object from a (possibly truncated) session JSON head. */
89
- function parseMetaFromHead(head) {
90
- const key = head.indexOf('"meta"');
91
- if (key < 0)
92
- return null;
93
- const brace = head.indexOf("{", key);
94
- if (brace < 0)
95
- return null;
96
- const end = matchBrace(head, brace);
97
- if (end < 0)
98
- return null;
99
- try {
100
- return JSON.parse(head.slice(brace, end + 1));
101
- }
102
- catch {
103
- return null;
104
- }
105
- }
106
- function generateId() {
107
- return randomUUID();
108
- }
109
- function textOfContent(content) {
110
- if (typeof content === "string")
111
- return content;
112
- return content
113
- .map((p) => (p.type === "text" ? p.text : ""))
114
- .join(" ")
115
- .trim();
116
- }
117
- function deriveTitle(messages) {
118
- const first = messages.find((m) => m.role === "user");
119
- if (!first)
120
- return "Untitled";
121
- const text = textOfContent(first.content);
122
- return text.slice(0, 60) || "Untitled";
123
- }
124
- /** Convert binary image parts to data URLs so JSON serialization stays usable. */
125
- export function sanitizeForStorage(messages) {
126
- return messages
127
- .filter((msg) => !isSyntheticMessage(msg))
128
- .map((msg) => {
129
- if (!Array.isArray(msg.content))
130
- return msg;
131
- const content = msg.content.map((part) => {
132
- if (part.type !== "image" || part.image == null || typeof part.image === "string")
133
- return part;
134
- let buf = null;
135
- if (Buffer.isBuffer(part.image) || part.image instanceof Uint8Array) {
136
- buf = Buffer.isBuffer(part.image) ? part.image : Buffer.from(part.image);
137
- }
138
- else if (typeof part.image === "object" && !(part.image instanceof URL)) {
139
- const data = part.image.data;
140
- if (Buffer.isBuffer(data) || data instanceof Uint8Array) {
141
- buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
142
- }
143
- }
144
- if (!buf)
145
- return part;
146
- const mime = part.mimeType ?? "image/png";
147
- return { ...part, image: `data:${mime};base64,${buf.toString("base64")}` };
148
- });
149
- return { ...msg, content };
150
- });
151
- }
152
- export function saveSession(messages, existingId, title, created, taskState) {
153
- const dir = getSessionsDir();
154
- mkdirSync(dir, { recursive: true });
155
- const id = existingId && SESSION_ID_RE.test(existingId) ? existingId : generateId();
156
- const now = new Date().toISOString();
157
- const existingMeta = existingId ? readMeta(id) : null;
158
- const preservedState = taskState === undefined && existingId ? loadSession(id)?.taskState : undefined;
159
- const resolvedState = taskState ?? preservedState;
160
- const data = {
161
- meta: {
162
- id,
163
- title: title ?? existingMeta?.title ?? deriveTitle(messages),
164
- created: created ?? existingMeta?.created ?? now,
165
- updated: now,
166
- messageCount: messages.length,
167
- },
168
- ...(resolvedState ? { taskState: resolvedState } : {}),
169
- messages: sanitizeForStorage(messages),
170
- };
171
- atomicWriteFileSync(sessionPath(id), JSON.stringify(data, null, 2));
172
- return id;
173
- }
174
- /** Read only the meta head to recover the original created/title. */
175
- function readMeta(id) {
176
- const file = sessionPath(id);
177
- if (!existsSync(file))
178
- return null;
179
- try {
180
- return parseMetaFromHead(readHead(file, META_READ_LIMIT));
181
- }
182
- catch {
183
- return null;
184
- }
185
- }
186
- /** Save session with auto-generated title from LLM */
187
- export async function saveSessionWithTitle(messages, model, existingId) {
188
- let title = null;
189
- try {
190
- title = await generateTitle(model, messages);
191
- }
192
- catch { }
193
- return saveSession(messages, existingId, title ?? undefined);
194
- }
195
- export function loadSession(id) {
196
- if (!SESSION_ID_RE.test(id))
197
- return null;
198
- const file = sessionPath(id);
199
- if (!existsSync(file))
200
- return null;
201
- try {
202
- const data = JSON.parse(readFileSync(file, "utf-8"));
203
- const taskState = parseTaskState(data.taskState);
204
- return taskState ? { ...data, taskState } : data;
205
- }
206
- catch {
207
- return null;
208
- }
209
- }
210
- export function loadExecHistory(resumeSessionId) {
211
- if (!resumeSessionId)
212
- return { ok: true, messages: [], sessionId: undefined };
213
- const session = loadSession(resumeSessionId);
214
- if (!session)
215
- return { ok: false, error: `会话不存在: ${resumeSessionId}` };
216
- return { ok: true, messages: [...session.messages], sessionId: resumeSessionId, taskState: session.taskState };
217
- }
218
- export function listSessions() {
219
- const dir = getSessionsDir();
220
- if (!existsSync(dir))
221
- return [];
222
- return readdirSync(dir)
223
- .filter((f) => f.endsWith(".json"))
224
- .map((f) => {
225
- try {
226
- return parseMetaFromHead(readHead(path.join(dir, f), META_READ_LIMIT));
227
- }
228
- catch {
229
- return null;
230
- }
231
- })
232
- .filter((m) => m !== null)
233
- .sort((a, b) => b.updated.localeCompare(a.updated));
234
- }
235
- export function deleteSession(id) {
236
- if (!SESSION_ID_RE.test(id))
237
- return false;
238
- const file = sessionPath(id);
239
- if (!existsSync(file))
240
- return false;
241
- try {
242
- unlinkSync(file);
243
- return true;
244
- }
245
- catch {
246
- return false;
247
- }
248
- }
249
- export function renameSession(id, title) {
250
- if (!SESSION_ID_RE.test(id))
251
- return false;
252
- const file = sessionPath(id);
253
- if (!existsSync(file))
254
- return false;
255
- try {
256
- const data = JSON.parse(readFileSync(file, "utf-8"));
257
- data.meta.title = title;
258
- data.meta.updated = new Date().toISOString();
259
- atomicWriteFileSync(file, JSON.stringify(data, null, 2));
260
- return true;
261
- }
262
- catch {
263
- return false;
264
- }
265
- }