@townco/cli 0.1.11 → 0.1.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/README.md +66 -0
- package/dist/commands/create.d.ts +6 -5
- package/dist/commands/create.js +12 -78
- package/dist/commands/mcp-add.d.ts +5 -10
- package/dist/commands/mcp-list.js +47 -174
- package/dist/commands/run.d.ts +4 -4
- package/dist/commands/tool-add.d.ts +6 -0
- package/dist/commands/tool-add.js +349 -0
- package/dist/commands/tool-list.d.ts +3 -0
- package/dist/commands/tool-list.js +61 -0
- package/dist/commands/tool-register.d.ts +7 -0
- package/dist/commands/tool-register.js +291 -0
- package/dist/commands/tool-remove.d.ts +3 -0
- package/dist/commands/tool-remove.js +202 -0
- package/dist/index.js +37 -2
- package/dist/lib/editor-utils.d.ts +15 -0
- package/dist/lib/editor-utils.js +112 -0
- package/dist/lib/mcp-storage.d.ts +5 -5
- package/dist/lib/mcp-storage.js +48 -50
- package/dist/lib/tool-storage.d.ts +32 -0
- package/dist/lib/tool-storage.js +107 -0
- package/package.json +6 -6
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Town CLI
|
|
2
|
+
|
|
3
|
+
Run AI agents from the command line.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @townco/cli configure # Set up API keys
|
|
9
|
+
npx @townco/cli create
|
|
10
|
+
npx @townco/cli run my-agent # Run in terminal (TUI)
|
|
11
|
+
npx @townco/cli run my-agent --gui # Run with web interface
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
### `create [name]` - Create an agent
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @townco/cli create # Interactive wizard
|
|
20
|
+
npx @townco/cli create --name my-agent # With name
|
|
21
|
+
npx @townco/cli create \
|
|
22
|
+
--name my-agent \
|
|
23
|
+
--model claude-sonnet-4-5-20250929 \
|
|
24
|
+
--tools web_search,todo_write \
|
|
25
|
+
--system-prompt "You are a helpful assistant"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### `list` - List all agents
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @townco/cli list
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `configure` - Set up API keys
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @townco/cli configure
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Sets `ANTHROPIC_API_KEY`, `EXA_API_KEY`, etc. in `~/.config/town/.env`
|
|
41
|
+
|
|
42
|
+
### `run <name>` - Run an agent
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx @townco/cli run my-agent # TUI mode (default)
|
|
46
|
+
npx @townco/cli run my-agent --gui # Web interface
|
|
47
|
+
npx @townco/cli run my-agent --http # HTTP API server
|
|
48
|
+
npx @townco/cli run my-agent --http --port 8080
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `delete <name>` - Delete an agent
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx @townco/cli delete my-agent
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Models
|
|
58
|
+
|
|
59
|
+
- `claude-sonnet-4-5-20250929` - Latest (recommended)
|
|
60
|
+
- `claude-opus-4-20250514` - Most capable
|
|
61
|
+
- `claude-3-5-haiku-20241022` - Fastest
|
|
62
|
+
|
|
63
|
+
## Tools
|
|
64
|
+
|
|
65
|
+
- `todo_write` - Task management
|
|
66
|
+
- `web_search` - Web search (requires EXA_API_KEY)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
interface CreateCommandProps {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
name?: string;
|
|
3
|
+
model?: string;
|
|
4
|
+
tools?: readonly string[];
|
|
5
|
+
systemPrompt?: string;
|
|
6
|
+
overwrite?: boolean;
|
|
7
7
|
}
|
|
8
8
|
export declare function createCommand(props: CreateCommandProps): Promise<void>;
|
|
9
|
+
export {};
|
package/dist/commands/create.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
2
|
import { scaffoldAgent } from "@townco/agent/scaffold";
|
|
7
3
|
import { InputBox, MultiSelect, SingleSelect } from "@townco/ui/tui";
|
|
8
4
|
import { Box, render, Text, useInput } from "ink";
|
|
9
5
|
import TextInput from "ink-text-input";
|
|
10
6
|
import { useEffect, useState } from "react";
|
|
7
|
+
import { openInEditor } from "../lib/editor-utils";
|
|
11
8
|
const AVAILABLE_MODELS = [
|
|
12
9
|
{
|
|
13
10
|
label: "Claude Sonnet 4.5",
|
|
@@ -55,70 +52,6 @@ function NameInput({ nameInput, setNameInput, onSubmit }) {
|
|
|
55
52
|
});
|
|
56
53
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Enter agent name:" }) }), _jsxs(Box, { children: [_jsxs(Text, { children: [">", " "] }), _jsx(TextInput, { value: nameInput, onChange: setNameInput, onSubmit: onSubmit })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter: Continue \u2022 Esc: Cancel" }) })] }));
|
|
57
54
|
}
|
|
58
|
-
async function openEditor(initialContent) {
|
|
59
|
-
const tempFile = join(tmpdir(), `agent-prompt-${Date.now()}.txt`);
|
|
60
|
-
try {
|
|
61
|
-
// Write initial content
|
|
62
|
-
writeFileSync(tempFile, initialContent, "utf-8");
|
|
63
|
-
// Try $EDITOR first
|
|
64
|
-
const editor = process.env.EDITOR;
|
|
65
|
-
if (editor) {
|
|
66
|
-
try {
|
|
67
|
-
await new Promise((resolve, reject) => {
|
|
68
|
-
const child = spawn(editor, [tempFile], {
|
|
69
|
-
stdio: "inherit",
|
|
70
|
-
});
|
|
71
|
-
child.on("close", (code) => {
|
|
72
|
-
if (code === 0)
|
|
73
|
-
resolve();
|
|
74
|
-
else
|
|
75
|
-
reject(new Error(`Editor exited with code ${code}`));
|
|
76
|
-
});
|
|
77
|
-
child.on("error", reject);
|
|
78
|
-
});
|
|
79
|
-
const content = readFileSync(tempFile, "utf-8");
|
|
80
|
-
unlinkSync(tempFile);
|
|
81
|
-
return content;
|
|
82
|
-
}
|
|
83
|
-
catch (_error) {
|
|
84
|
-
// Fall through to try 'code'
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
// Try 'code' (VS Code) as fallback
|
|
88
|
-
try {
|
|
89
|
-
await new Promise((resolve, reject) => {
|
|
90
|
-
const child = spawn("code", ["--wait", tempFile], {
|
|
91
|
-
stdio: "inherit",
|
|
92
|
-
});
|
|
93
|
-
child.on("close", (code) => {
|
|
94
|
-
if (code === 0)
|
|
95
|
-
resolve();
|
|
96
|
-
else
|
|
97
|
-
reject(new Error(`Code exited with code ${code}`));
|
|
98
|
-
});
|
|
99
|
-
child.on("error", reject);
|
|
100
|
-
});
|
|
101
|
-
const content = readFileSync(tempFile, "utf-8");
|
|
102
|
-
unlinkSync(tempFile);
|
|
103
|
-
return content;
|
|
104
|
-
}
|
|
105
|
-
catch (_error) {
|
|
106
|
-
// Clean up and return null to signal fallback to inline
|
|
107
|
-
unlinkSync(tempFile);
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (_error) {
|
|
112
|
-
// Clean up temp file if it exists
|
|
113
|
-
try {
|
|
114
|
-
unlinkSync(tempFile);
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
// Ignore cleanup errors
|
|
118
|
-
}
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
55
|
function CreateApp({ name: initialName, model: initialModel, tools: initialTools, systemPrompt: initialSystemPrompt, overwrite = false, }) {
|
|
123
56
|
// Determine the starting stage based on what's provided
|
|
124
57
|
const determineInitialStage = () => {
|
|
@@ -150,13 +83,14 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
|
|
|
150
83
|
const [agentPath, setAgentPath] = useState(null);
|
|
151
84
|
// Handle opening editor when systemPrompt stage is entered from review
|
|
152
85
|
useEffect(() => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
86
|
+
(async () => {
|
|
87
|
+
if (stage === "systemPrompt" &&
|
|
88
|
+
isEditingFromReview &&
|
|
89
|
+
!isEditingPrompt &&
|
|
90
|
+
promptEditMode === null) {
|
|
91
|
+
// Trigger editor opening
|
|
92
|
+
setIsEditingPrompt(true);
|
|
93
|
+
const editorContent = await openInEditor(agentDef.systemPrompt || "You are a helpful assistant.");
|
|
160
94
|
if (editorContent !== null) {
|
|
161
95
|
// Editor worked
|
|
162
96
|
setAgentDef({ ...agentDef, systemPrompt: editorContent });
|
|
@@ -170,8 +104,8 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
|
|
|
170
104
|
setIsEditingPrompt(false);
|
|
171
105
|
setSystemPromptInput(agentDef.systemPrompt || "You are a helpful assistant.");
|
|
172
106
|
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
107
|
+
}
|
|
108
|
+
})();
|
|
175
109
|
}, [stage, isEditingFromReview, isEditingPrompt, promptEditMode, agentDef]);
|
|
176
110
|
// Handle scaffolding when entering "done" stage
|
|
177
111
|
useEffect(() => {
|
|
@@ -271,7 +205,7 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
|
|
|
271
205
|
setStage("systemPrompt");
|
|
272
206
|
// Attempt to open editor
|
|
273
207
|
setIsEditingPrompt(true);
|
|
274
|
-
const editorContent = await
|
|
208
|
+
const editorContent = await openInEditor(agentDef.systemPrompt || "You are a helpful assistant.");
|
|
275
209
|
if (editorContent !== null) {
|
|
276
210
|
// Editor worked
|
|
277
211
|
setAgentDef({ ...agentDef, systemPrompt: editorContent });
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
interface MCPAddProps {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
name?: string;
|
|
3
|
+
url?: string;
|
|
4
|
+
command?: string;
|
|
5
|
+
args?: readonly string[];
|
|
6
6
|
}
|
|
7
|
-
declare function MCPAddApp({
|
|
8
|
-
name: initialName,
|
|
9
|
-
url: initialUrl,
|
|
10
|
-
command: initialCommand,
|
|
11
|
-
args: initialArgs,
|
|
12
|
-
}: MCPAddProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
declare function MCPAddApp({ name: initialName, url: initialUrl, command: initialCommand, args: initialArgs, }: MCPAddProps): import("react/jsx-runtime").JSX.Element | null;
|
|
13
8
|
export default MCPAddApp;
|
|
14
9
|
export declare function runMCPAdd(props?: MCPAddProps): Promise<void>;
|
|
@@ -1,188 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
2
|
import { Box, render, Text, useApp, useInput } from "ink";
|
|
2
3
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { listMCPConfigs } from "../lib/mcp-storage";
|
|
5
|
-
|
|
6
5
|
// ============================================================================
|
|
7
6
|
// Main Component
|
|
8
7
|
// ============================================================================
|
|
9
8
|
function MCPListApp() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
bold: true,
|
|
48
|
-
color: "red",
|
|
49
|
-
children: "\u274C Error loading MCP servers",
|
|
50
|
-
}),
|
|
51
|
-
}),
|
|
52
|
-
_jsx(Box, {
|
|
53
|
-
marginBottom: 1,
|
|
54
|
-
children: _jsx(Text, { children: result.error }),
|
|
55
|
-
}),
|
|
56
|
-
_jsx(Box, {
|
|
57
|
-
children: _jsx(Text, {
|
|
58
|
-
dimColor: true,
|
|
59
|
-
children: "Press Enter or Q to exit",
|
|
60
|
-
}),
|
|
61
|
-
}),
|
|
62
|
-
],
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
if (!result || result.configs.length === 0) {
|
|
66
|
-
return _jsxs(Box, {
|
|
67
|
-
flexDirection: "column",
|
|
68
|
-
children: [
|
|
69
|
-
_jsx(Box, {
|
|
70
|
-
marginBottom: 1,
|
|
71
|
-
children: _jsx(Text, {
|
|
72
|
-
bold: true,
|
|
73
|
-
children: "No MCP servers configured",
|
|
74
|
-
}),
|
|
75
|
-
}),
|
|
76
|
-
_jsx(Box, {
|
|
77
|
-
marginBottom: 1,
|
|
78
|
-
children: _jsx(Text, {
|
|
79
|
-
dimColor: true,
|
|
80
|
-
children: "Add one with: town mcp add",
|
|
81
|
-
}),
|
|
82
|
-
}),
|
|
83
|
-
_jsx(Box, {
|
|
84
|
-
children: _jsx(Text, {
|
|
85
|
-
dimColor: true,
|
|
86
|
-
children: "Press Enter or Q to exit",
|
|
87
|
-
}),
|
|
88
|
-
}),
|
|
89
|
-
],
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return _jsxs(Box, {
|
|
93
|
-
flexDirection: "column",
|
|
94
|
-
children: [
|
|
95
|
-
_jsx(Box, {
|
|
96
|
-
marginBottom: 1,
|
|
97
|
-
children: _jsxs(Text, {
|
|
98
|
-
bold: true,
|
|
99
|
-
children: ["Configured MCP Servers (", result.configs.length, ")"],
|
|
100
|
-
}),
|
|
101
|
-
}),
|
|
102
|
-
result.configs.map((config, index) =>
|
|
103
|
-
_jsxs(
|
|
104
|
-
Box,
|
|
105
|
-
{
|
|
106
|
-
flexDirection: "column",
|
|
107
|
-
marginBottom: 1,
|
|
108
|
-
children: [
|
|
109
|
-
_jsx(Box, {
|
|
110
|
-
children: _jsxs(Text, {
|
|
111
|
-
bold: true,
|
|
112
|
-
color: "cyan",
|
|
113
|
-
children: [index + 1, ". ", config.name],
|
|
114
|
-
}),
|
|
115
|
-
}),
|
|
116
|
-
_jsx(Box, {
|
|
117
|
-
paddingLeft: 3,
|
|
118
|
-
children:
|
|
119
|
-
config.transport === "http"
|
|
120
|
-
? _jsxs(Box, {
|
|
121
|
-
flexDirection: "column",
|
|
122
|
-
children: [
|
|
123
|
-
_jsxs(Text, {
|
|
124
|
-
children: [
|
|
125
|
-
"Transport: ",
|
|
126
|
-
_jsx(Text, { color: "green", children: "HTTP" }),
|
|
127
|
-
],
|
|
128
|
-
}),
|
|
129
|
-
_jsxs(Text, { children: ["URL: ", config.url] }),
|
|
130
|
-
],
|
|
131
|
-
})
|
|
132
|
-
: _jsxs(Box, {
|
|
133
|
-
flexDirection: "column",
|
|
134
|
-
children: [
|
|
135
|
-
_jsxs(Text, {
|
|
136
|
-
children: [
|
|
137
|
-
"Transport: ",
|
|
138
|
-
_jsx(Text, { color: "blue", children: "stdio" }),
|
|
139
|
-
],
|
|
140
|
-
}),
|
|
141
|
-
_jsxs(Text, {
|
|
142
|
-
children: ["Command: ", config.command],
|
|
143
|
-
}),
|
|
144
|
-
config.args &&
|
|
145
|
-
config.args.length > 0 &&
|
|
146
|
-
_jsxs(Text, {
|
|
147
|
-
children: ["Args: ", config.args.join(" ")],
|
|
148
|
-
}),
|
|
149
|
-
],
|
|
150
|
-
}),
|
|
151
|
-
}),
|
|
152
|
-
],
|
|
153
|
-
},
|
|
154
|
-
config.name,
|
|
155
|
-
),
|
|
156
|
-
),
|
|
157
|
-
_jsx(Box, {
|
|
158
|
-
marginTop: 1,
|
|
159
|
-
children: _jsx(Text, {
|
|
160
|
-
dimColor: true,
|
|
161
|
-
children:
|
|
162
|
-
"Use `town mcp remove` to remove a server or `town mcp add` to add one",
|
|
163
|
-
}),
|
|
164
|
-
}),
|
|
165
|
-
_jsx(Box, {
|
|
166
|
-
marginTop: 1,
|
|
167
|
-
children: _jsx(Text, {
|
|
168
|
-
dimColor: true,
|
|
169
|
-
children: "Press Enter or Q to exit",
|
|
170
|
-
}),
|
|
171
|
-
}),
|
|
172
|
-
],
|
|
173
|
-
});
|
|
9
|
+
const [result, setResult] = useState(null);
|
|
10
|
+
const [loading, setLoading] = useState(true);
|
|
11
|
+
const { exit } = useApp();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
function loadConfigs() {
|
|
14
|
+
try {
|
|
15
|
+
const configs = listMCPConfigs();
|
|
16
|
+
setResult({ configs });
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
20
|
+
setResult({ configs: [], error: errorMsg });
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
setLoading(false);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
loadConfigs();
|
|
27
|
+
}, []);
|
|
28
|
+
// Exit on any key press when not loading
|
|
29
|
+
useInput((_input, key) => {
|
|
30
|
+
if (!loading) {
|
|
31
|
+
if (key.return || key.escape || _input === "q") {
|
|
32
|
+
exit();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (loading) {
|
|
37
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading MCP servers..." }) }));
|
|
38
|
+
}
|
|
39
|
+
if (result?.error) {
|
|
40
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "red", children: "\u274C Error loading MCP servers" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: result.error }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Press Enter or Q to exit" }) })] }));
|
|
41
|
+
}
|
|
42
|
+
if (!result || result.configs.length === 0) {
|
|
43
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "No MCP servers configured" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Add one with: town mcp add" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Press Enter or Q to exit" }) })] }));
|
|
44
|
+
}
|
|
45
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { bold: true, children: ["Configured MCP Servers (", result.configs.length, ")"] }) }), result.configs.map((config, index) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: "cyan", children: [index + 1, ". ", config.name] }) }), _jsx(Box, { paddingLeft: 3, children: config.transport === "http" ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: ["Transport: ", _jsx(Text, { color: "green", children: "HTTP" })] }), _jsxs(Text, { children: ["URL: ", config.url] })] })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: ["Transport: ", _jsx(Text, { color: "blue", children: "stdio" })] }), _jsxs(Text, { children: ["Command: ", config.command] }), config.args && config.args.length > 0 && (_jsxs(Text, { children: ["Args: ", config.args.join(" ")] }))] })) })] }, config.name))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use `town mcp remove` to remove a server or `town mcp add` to add one" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter or Q to exit" }) })] }));
|
|
174
46
|
}
|
|
175
47
|
// ============================================================================
|
|
176
48
|
// Export and Runner
|
|
177
49
|
// ============================================================================
|
|
178
50
|
export default MCPListApp;
|
|
179
51
|
export async function runMCPList() {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
52
|
+
const { waitUntilExit, clear } = render(_jsx(MCPListApp, {}));
|
|
53
|
+
try {
|
|
54
|
+
await waitUntilExit();
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
clear();
|
|
58
|
+
// Ensure cursor is visible
|
|
59
|
+
process.stdout.write("\x1B[?25h");
|
|
60
|
+
}
|
|
188
61
|
}
|
package/dist/commands/run.d.ts
CHANGED