mini-coder 0.5.11 → 0.5.13
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/BENCHMARK.md +107 -0
- package/PROGRESS.md +4 -0
- package/README.md +66 -21
- package/assets/mc-claude-smart.png +0 -0
- package/assets/mc-gpt-smart.png +0 -0
- package/benchmark-baseline.sh +15 -0
- package/benchmark-loop.sh +19 -0
- package/bun.lock +265 -90
- package/package.json +8 -7
- package/skills-lock.json +15 -0
- package/src/agent.ts +20 -0
- package/src/cli.ts +2 -1
- package/src/headless.ts +152 -38
- package/src/index.ts +107 -143
- package/src/input.ts +13 -1
- package/src/mcp.ts +609 -0
- package/src/prompt.ts +10 -12
- package/src/session-message.ts +393 -0
- package/src/session.ts +102 -396
- package/src/settings.ts +218 -22
- package/src/shared.ts +39 -0
- package/src/skills.ts +12 -3
- package/src/submit.ts +20 -25
- package/src/text.ts +71 -0
- package/src/theme.ts +186 -3
- package/src/tool-common.ts +93 -0
- package/src/tool-grep.ts +606 -0
- package/src/tool-read.ts +313 -0
- package/src/tool-shell.ts +1001 -0
- package/src/tools.ts +190 -995
- package/src/ui/agent.ts +206 -110
- package/src/ui/commands.test.ts +489 -17
- package/src/ui/commands.ts +231 -55
- package/src/ui/conversation.test.ts +585 -0
- package/src/ui/conversation.ts +878 -455
- package/src/ui/help.ts +27 -11
- package/src/ui/input.test.ts +1 -43
- package/src/ui/runtime.ts +69 -0
- package/src/ui.ts +422 -185
- package/src/plugins.ts +0 -183
package/src/ui/commands.ts
CHANGED
|
@@ -17,22 +17,31 @@ import { getOAuthProviders } from "@mariozechner/pi-ai/oauth";
|
|
|
17
17
|
import { getErrorMessage } from "../errors.ts";
|
|
18
18
|
import type { AppState } from "../index.ts";
|
|
19
19
|
import { getAvailableModels, saveOAuthCredentials } from "../index.ts";
|
|
20
|
-
import { COMMANDS } from "../input.ts";
|
|
20
|
+
import { COMMANDS, SKILL_COMMAND } from "../input.ts";
|
|
21
|
+
import { connectMcpServer, disconnectMcpServer } from "../mcp.ts";
|
|
21
22
|
import {
|
|
22
|
-
|
|
23
|
-
computeStats,
|
|
23
|
+
clearConversationState,
|
|
24
24
|
forkSession,
|
|
25
25
|
listPromptHistory,
|
|
26
26
|
listSessions,
|
|
27
27
|
loadMessages,
|
|
28
|
+
replaceConversationState,
|
|
28
29
|
type SessionListEntry,
|
|
29
30
|
type UiInfoFormat,
|
|
30
31
|
undoLastTurn,
|
|
31
32
|
} from "../session.ts";
|
|
32
33
|
import { updateSettings } from "../settings.ts";
|
|
34
|
+
import { clearQueuedUserMessages } from "../submit.ts";
|
|
35
|
+
import { collapseWhitespace, truncateText } from "../text.ts";
|
|
33
36
|
import { getTodoItems } from "../tools.ts";
|
|
34
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
buildHelpText,
|
|
39
|
+
COMMAND_DESCRIPTIONS,
|
|
40
|
+
SKILL_REFERENCE_DESCRIPTION,
|
|
41
|
+
SKILL_REFERENCE_LABEL,
|
|
42
|
+
} from "./help.ts";
|
|
35
43
|
import { type ActiveOverlay, OVERLAY_MAX_VISIBLE } from "./overlay.ts";
|
|
44
|
+
import type { UiRenderPriority } from "./runtime.ts";
|
|
36
45
|
import { abbreviatePath } from "./status.ts";
|
|
37
46
|
|
|
38
47
|
/** Effort levels available for selection. */
|
|
@@ -45,9 +54,9 @@ const EFFORT_LEVELS: { label: string; value: ThinkingLevel }[] = [
|
|
|
45
54
|
|
|
46
55
|
/** Runtime hooks injected from the stateful UI module. */
|
|
47
56
|
interface UiCommandRuntime {
|
|
48
|
-
/** Open an overlay
|
|
57
|
+
/** Open an overlay. */
|
|
49
58
|
openOverlay: (overlay: ActiveOverlay) => void;
|
|
50
|
-
/** Dismiss the active overlay
|
|
59
|
+
/** Dismiss the active overlay. */
|
|
51
60
|
dismissOverlay: () => void;
|
|
52
61
|
/** Update the current input draft. */
|
|
53
62
|
setInputValue: (value: string) => void;
|
|
@@ -64,14 +73,30 @@ interface UiCommandRuntime {
|
|
|
64
73
|
) => void;
|
|
65
74
|
/** Re-enable stick-to-bottom behavior for the conversation log. */
|
|
66
75
|
scrollConversationToBottom: () => void;
|
|
67
|
-
/**
|
|
68
|
-
|
|
76
|
+
/** Schedule a UI re-render. */
|
|
77
|
+
requestRender: (priority?: UiRenderPriority) => void;
|
|
69
78
|
/** Reload prompt/session context at a boundary like `/new`. */
|
|
70
79
|
reloadPromptContext: (state: AppState) => Promise<void>;
|
|
71
80
|
/** Open a URL in the user's default browser. */
|
|
72
81
|
openInBrowser: (url: string) => void;
|
|
73
82
|
}
|
|
74
83
|
|
|
84
|
+
interface UiCommandDeps {
|
|
85
|
+
/** Connect a configured MCP server on demand. */
|
|
86
|
+
connectMcpServer: (
|
|
87
|
+
server: AppState["mcpServers"][number],
|
|
88
|
+
) => Promise<string[]>;
|
|
89
|
+
/** Disconnect an MCP server and clear its imported tools. */
|
|
90
|
+
disconnectMcpServer: (
|
|
91
|
+
server: AppState["mcpServers"][number],
|
|
92
|
+
) => Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const defaultUiCommandDeps: UiCommandDeps = {
|
|
96
|
+
connectMcpServer,
|
|
97
|
+
disconnectMcpServer,
|
|
98
|
+
};
|
|
99
|
+
|
|
75
100
|
/** Public command actions consumed by `ui.ts` and unit tests. */
|
|
76
101
|
interface UiCommandController {
|
|
77
102
|
/** Apply a model selection and persist it to settings. */
|
|
@@ -142,7 +167,7 @@ export function formatRelativeDate(date: Date, now = new Date()): string {
|
|
|
142
167
|
* @returns A single-line preview string.
|
|
143
168
|
*/
|
|
144
169
|
export function formatPromptHistoryPreview(text: string): string {
|
|
145
|
-
return text
|
|
170
|
+
return collapseWhitespace(text);
|
|
146
171
|
}
|
|
147
172
|
|
|
148
173
|
const HISTORY_PREVIEW_MAX_CHARS = 32;
|
|
@@ -150,26 +175,6 @@ const HISTORY_CWD_MAX_CHARS = 18;
|
|
|
150
175
|
const SESSION_PREVIEW_MAX_CHARS = 27;
|
|
151
176
|
const SESSION_MODEL_MAX_CHARS = 17;
|
|
152
177
|
|
|
153
|
-
function truncateTrailingText(text: string, maxChars: number): string {
|
|
154
|
-
if (text.length <= maxChars) {
|
|
155
|
-
return text;
|
|
156
|
-
}
|
|
157
|
-
if (maxChars <= 1) {
|
|
158
|
-
return "…";
|
|
159
|
-
}
|
|
160
|
-
return `${text.slice(0, maxChars - 1)}…`;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function truncateLeadingText(text: string, maxChars: number): string {
|
|
164
|
-
if (text.length <= maxChars) {
|
|
165
|
-
return text;
|
|
166
|
-
}
|
|
167
|
-
if (maxChars <= 1) {
|
|
168
|
-
return "…";
|
|
169
|
-
}
|
|
170
|
-
return `…${text.slice(text.length - (maxChars - 1))}`;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
178
|
/**
|
|
174
179
|
* Format a prompt-history row for the Select overlay.
|
|
175
180
|
*
|
|
@@ -183,13 +188,14 @@ export function formatPromptHistoryLabel(
|
|
|
183
188
|
cwd: string,
|
|
184
189
|
date: string,
|
|
185
190
|
): string {
|
|
186
|
-
const preview =
|
|
191
|
+
const preview = truncateText(
|
|
187
192
|
formatPromptHistoryPreview(text),
|
|
188
193
|
HISTORY_PREVIEW_MAX_CHARS,
|
|
189
194
|
);
|
|
190
|
-
const displayCwd =
|
|
195
|
+
const displayCwd = truncateText(
|
|
191
196
|
abbreviatePath(cwd),
|
|
192
197
|
HISTORY_CWD_MAX_CHARS,
|
|
198
|
+
"start",
|
|
193
199
|
);
|
|
194
200
|
return `${preview} · ${displayCwd} · ${date}`;
|
|
195
201
|
}
|
|
@@ -207,11 +213,11 @@ export function formatSessionLabel(
|
|
|
207
213
|
date: string,
|
|
208
214
|
isCurrent: boolean,
|
|
209
215
|
): string {
|
|
210
|
-
const preview =
|
|
216
|
+
const preview = truncateText(
|
|
211
217
|
session.firstUserPreview ?? "No messages yet",
|
|
212
218
|
SESSION_PREVIEW_MAX_CHARS,
|
|
213
219
|
);
|
|
214
|
-
const model =
|
|
220
|
+
const model = truncateText(
|
|
215
221
|
session.model ?? "no model",
|
|
216
222
|
SESSION_MODEL_MAX_CHARS,
|
|
217
223
|
);
|
|
@@ -229,14 +235,117 @@ interface OverlayItem {
|
|
|
229
235
|
filterText: string;
|
|
230
236
|
}
|
|
231
237
|
|
|
238
|
+
function formatSkillLabel(skill: AppState["skills"][number]): string {
|
|
239
|
+
return skill.description
|
|
240
|
+
? `${skill.name} · ${skill.description}`
|
|
241
|
+
: skill.name;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function formatToolCount(count: number): string {
|
|
245
|
+
return `${count} tool${count === 1 ? "" : "s"}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function formatMcpServerLabel(server: AppState["mcpServers"][number]): string {
|
|
249
|
+
return `${server.name} · ${server.enabled ? "on" : "off"} · ${formatToolCount(server.tools.length)}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function formatMcpToggleMessage(
|
|
253
|
+
server: AppState["mcpServers"][number],
|
|
254
|
+
toolCount: number,
|
|
255
|
+
): string {
|
|
256
|
+
const action = server.enabled ? "Enabled" : "Disabled";
|
|
257
|
+
const delta = `${server.enabled ? "+" : "-"}${toolCount}`;
|
|
258
|
+
const toolSuffix = toolCount === 1 ? "tool" : "tools";
|
|
259
|
+
return `${action} MCP server "${server.name}" (${delta} ${toolSuffix}).`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function isRepoLocalMcpServer(state: AppState, serverName: string): boolean {
|
|
263
|
+
return (
|
|
264
|
+
state.repoSettings.mcp?.servers?.some(
|
|
265
|
+
(entry) => entry.name === serverName,
|
|
266
|
+
) ?? false
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function persistMcpServerSettings(
|
|
271
|
+
state: AppState,
|
|
272
|
+
server: AppState["mcpServers"][number],
|
|
273
|
+
): void {
|
|
274
|
+
if (isRepoLocalMcpServer(state, server.name)) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
state.settings = updateSettings(state.settingsPath, {
|
|
279
|
+
mcp: {
|
|
280
|
+
servers: [
|
|
281
|
+
{
|
|
282
|
+
name: server.name,
|
|
283
|
+
url: server.url,
|
|
284
|
+
enabled: server.enabled,
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function toggleMcpServer(
|
|
292
|
+
server: AppState["mcpServers"][number],
|
|
293
|
+
state: AppState,
|
|
294
|
+
runtime: UiCommandRuntime,
|
|
295
|
+
deps: UiCommandDeps,
|
|
296
|
+
): Promise<void> {
|
|
297
|
+
try {
|
|
298
|
+
if (server.enabled) {
|
|
299
|
+
const toolCount = server.tools.length;
|
|
300
|
+
await deps.disconnectMcpServer(server);
|
|
301
|
+
server.enabled = false;
|
|
302
|
+
persistMcpServerSettings(state, server);
|
|
303
|
+
runtime.appendInfoMessage(
|
|
304
|
+
formatMcpToggleMessage(server, toolCount),
|
|
305
|
+
state,
|
|
306
|
+
);
|
|
307
|
+
runtime.requestRender("normal");
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const warnings = await deps.connectMcpServer(server);
|
|
312
|
+
if (!server.connected) {
|
|
313
|
+
for (const warning of warnings) {
|
|
314
|
+
runtime.appendInfoMessage(warning, state);
|
|
315
|
+
}
|
|
316
|
+
runtime.requestRender("normal");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
server.enabled = true;
|
|
321
|
+
persistMcpServerSettings(state, server);
|
|
322
|
+
runtime.appendInfoMessage(
|
|
323
|
+
formatMcpToggleMessage(server, server.tools.length),
|
|
324
|
+
state,
|
|
325
|
+
);
|
|
326
|
+
for (const warning of warnings) {
|
|
327
|
+
runtime.appendInfoMessage(warning, state);
|
|
328
|
+
}
|
|
329
|
+
runtime.requestRender("normal");
|
|
330
|
+
} catch (error) {
|
|
331
|
+
runtime.appendInfoMessage(
|
|
332
|
+
`MCP server "${server.name}": ${getErrorMessage(error)}`,
|
|
333
|
+
state,
|
|
334
|
+
);
|
|
335
|
+
runtime.requestRender("normal");
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
232
339
|
/**
|
|
233
340
|
* Create the UI command controller bound to the current UI runtime hooks.
|
|
234
341
|
*
|
|
235
342
|
* @param runtime - State mutation and rendering hooks owned by `ui.ts`.
|
|
343
|
+
* @param deps - Internal MCP command dependencies, mainly for tests.
|
|
236
344
|
* @returns Command actions for slash commands and overlays.
|
|
237
345
|
*/
|
|
238
346
|
export function createCommandController(
|
|
239
347
|
runtime: UiCommandRuntime,
|
|
348
|
+
deps: UiCommandDeps = defaultUiCommandDeps,
|
|
240
349
|
): UiCommandController {
|
|
241
350
|
const openSelectOverlay = (
|
|
242
351
|
state: AppState,
|
|
@@ -252,20 +361,52 @@ export function createCommandController(
|
|
|
252
361
|
focused: true,
|
|
253
362
|
highlightColor: state.theme.accentText,
|
|
254
363
|
onSelect,
|
|
364
|
+
onKeyPress: (key) => {
|
|
365
|
+
if (key === "escape") {
|
|
366
|
+
runtime.dismissOverlay();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
return false;
|
|
370
|
+
},
|
|
255
371
|
onBlur: runtime.dismissOverlay,
|
|
256
372
|
});
|
|
257
373
|
|
|
258
374
|
runtime.openOverlay({ select, title });
|
|
259
375
|
};
|
|
260
376
|
|
|
261
|
-
const
|
|
262
|
-
const items =
|
|
263
|
-
label:
|
|
264
|
-
value:
|
|
265
|
-
filterText:
|
|
377
|
+
const handleSkillCommand = (state: AppState): void => {
|
|
378
|
+
const items = state.skills.map((skill) => ({
|
|
379
|
+
label: formatSkillLabel(skill),
|
|
380
|
+
value: skill.name,
|
|
381
|
+
filterText: `${skill.name} ${skill.description ?? ""}`,
|
|
266
382
|
}));
|
|
267
383
|
|
|
268
|
-
|
|
384
|
+
openSelectOverlay(
|
|
385
|
+
state,
|
|
386
|
+
"Select a skill",
|
|
387
|
+
items,
|
|
388
|
+
"type to filter skills...",
|
|
389
|
+
(skillName) => {
|
|
390
|
+
runtime.setInputValue(`/${SKILL_COMMAND}:${skillName}`);
|
|
391
|
+
runtime.dismissOverlay();
|
|
392
|
+
},
|
|
393
|
+
);
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const showCommandAutocomplete = (state: AppState): void => {
|
|
397
|
+
const items: OverlayItem[] = [
|
|
398
|
+
...COMMANDS.map((command) => ({
|
|
399
|
+
label: `/${command} ${COMMAND_DESCRIPTIONS[command] ?? ""}`,
|
|
400
|
+
value: command,
|
|
401
|
+
filterText: command,
|
|
402
|
+
})),
|
|
403
|
+
{
|
|
404
|
+
label: `${SKILL_REFERENCE_LABEL} ${SKILL_REFERENCE_DESCRIPTION}`,
|
|
405
|
+
value: SKILL_COMMAND,
|
|
406
|
+
filterText: `${SKILL_COMMAND} ${SKILL_REFERENCE_LABEL}`,
|
|
407
|
+
},
|
|
408
|
+
];
|
|
409
|
+
|
|
269
410
|
openSelectOverlay(
|
|
270
411
|
state,
|
|
271
412
|
"Commands",
|
|
@@ -273,6 +414,12 @@ export function createCommandController(
|
|
|
273
414
|
"type to filter commands...",
|
|
274
415
|
(value) => {
|
|
275
416
|
runtime.dismissOverlay();
|
|
417
|
+
if (value === SKILL_COMMAND) {
|
|
418
|
+
handleSkillCommand(state);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
runtime.setInputValue("");
|
|
276
423
|
handleCommand(value, state);
|
|
277
424
|
},
|
|
278
425
|
);
|
|
@@ -393,17 +540,17 @@ export function createCommandController(
|
|
|
393
540
|
items,
|
|
394
541
|
"type to filter sessions...",
|
|
395
542
|
(sessionId) => {
|
|
543
|
+
clearQueuedUserMessages(state);
|
|
396
544
|
if (sessionId !== currentSessionId) {
|
|
397
545
|
const picked = sessions.find((session) => session.id === sessionId);
|
|
398
546
|
if (picked) {
|
|
399
547
|
state.session = picked;
|
|
400
|
-
state
|
|
401
|
-
state.stats = computeStats(state.messages);
|
|
402
|
-
state.contextTokens = computeContextTokens(state.messages);
|
|
548
|
+
replaceConversationState(state, loadMessages(state.db, picked.id));
|
|
403
549
|
runtime.scrollConversationToBottom();
|
|
404
550
|
}
|
|
405
551
|
}
|
|
406
552
|
runtime.dismissOverlay();
|
|
553
|
+
runtime.requestRender("normal");
|
|
407
554
|
},
|
|
408
555
|
);
|
|
409
556
|
};
|
|
@@ -412,13 +559,12 @@ export function createCommandController(
|
|
|
412
559
|
if (state.running) {
|
|
413
560
|
return;
|
|
414
561
|
}
|
|
562
|
+
clearQueuedUserMessages(state);
|
|
415
563
|
state.session = null;
|
|
416
|
-
state
|
|
417
|
-
state.stats = { totalInput: 0, totalOutput: 0, totalCost: 0 };
|
|
418
|
-
state.contextTokens = 0;
|
|
564
|
+
clearConversationState(state);
|
|
419
565
|
await runtime.reloadPromptContext(state);
|
|
420
566
|
runtime.scrollConversationToBottom();
|
|
421
|
-
runtime.
|
|
567
|
+
runtime.requestRender("normal");
|
|
422
568
|
};
|
|
423
569
|
|
|
424
570
|
const handleForkCommand = (state: AppState): void => {
|
|
@@ -427,13 +573,13 @@ export function createCommandController(
|
|
|
427
573
|
}
|
|
428
574
|
const forked = forkSession(state.db, state.session.id);
|
|
429
575
|
state.session = forked;
|
|
430
|
-
state
|
|
431
|
-
state.stats = computeStats(state.messages);
|
|
432
|
-
state.contextTokens = computeContextTokens(state.messages);
|
|
576
|
+
replaceConversationState(state, loadMessages(state.db, forked.id));
|
|
433
577
|
runtime.appendInfoMessage("Forked session.", state);
|
|
434
578
|
};
|
|
435
579
|
|
|
436
580
|
const handleUndoCommand = async (state: AppState): Promise<void> => {
|
|
581
|
+
clearQueuedUserMessages(state);
|
|
582
|
+
|
|
437
583
|
if (state.running && state.abortController) {
|
|
438
584
|
state.abortController.abort();
|
|
439
585
|
}
|
|
@@ -447,11 +593,9 @@ export function createCommandController(
|
|
|
447
593
|
}
|
|
448
594
|
const removed = undoLastTurn(state.db, state.session.id);
|
|
449
595
|
if (removed) {
|
|
450
|
-
state
|
|
451
|
-
state.stats = computeStats(state.messages);
|
|
452
|
-
state.contextTokens = computeContextTokens(state.messages);
|
|
596
|
+
replaceConversationState(state, loadMessages(state.db, state.session.id));
|
|
453
597
|
runtime.scrollConversationToBottom();
|
|
454
|
-
runtime.
|
|
598
|
+
runtime.requestRender("normal");
|
|
455
599
|
}
|
|
456
600
|
};
|
|
457
601
|
|
|
@@ -460,7 +604,6 @@ export function createCommandController(
|
|
|
460
604
|
state.settings = updateSettings(state.settingsPath, {
|
|
461
605
|
showReasoning: state.showReasoning,
|
|
462
606
|
});
|
|
463
|
-
runtime.render();
|
|
464
607
|
};
|
|
465
608
|
|
|
466
609
|
const handleVerboseCommand = (state: AppState): void => {
|
|
@@ -468,7 +611,34 @@ export function createCommandController(
|
|
|
468
611
|
state.settings = updateSettings(state.settingsPath, {
|
|
469
612
|
verbose: state.verbose,
|
|
470
613
|
});
|
|
471
|
-
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const handleMcpCommand = (state: AppState): void => {
|
|
617
|
+
if (state.mcpServers.length === 0) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const items = state.mcpServers.map((server) => ({
|
|
622
|
+
label: formatMcpServerLabel(server),
|
|
623
|
+
value: server.name,
|
|
624
|
+
filterText: `${server.name} ${server.url} ${server.enabled ? "on" : "off"}`,
|
|
625
|
+
}));
|
|
626
|
+
|
|
627
|
+
openSelectOverlay(
|
|
628
|
+
state,
|
|
629
|
+
"Toggle MCP servers",
|
|
630
|
+
items,
|
|
631
|
+
"type to filter MCP servers...",
|
|
632
|
+
(serverName) => {
|
|
633
|
+
const server = state.mcpServers.find(
|
|
634
|
+
(entry) => entry.name === serverName,
|
|
635
|
+
);
|
|
636
|
+
runtime.dismissOverlay();
|
|
637
|
+
if (server) {
|
|
638
|
+
void toggleMcpServer(server, state, runtime, deps);
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
);
|
|
472
642
|
};
|
|
473
643
|
|
|
474
644
|
const performLogin = async (
|
|
@@ -637,12 +807,18 @@ export function createCommandController(
|
|
|
637
807
|
case "verbose":
|
|
638
808
|
handleVerboseCommand(state);
|
|
639
809
|
return true;
|
|
810
|
+
case "mcp":
|
|
811
|
+
handleMcpCommand(state);
|
|
812
|
+
return true;
|
|
640
813
|
case "todo":
|
|
641
814
|
handleTodoCommand(state);
|
|
642
815
|
return true;
|
|
643
816
|
case "help":
|
|
644
817
|
handleHelpCommand(state);
|
|
645
818
|
return true;
|
|
819
|
+
case SKILL_COMMAND:
|
|
820
|
+
handleSkillCommand(state);
|
|
821
|
+
return true;
|
|
646
822
|
default:
|
|
647
823
|
return false;
|
|
648
824
|
}
|