@townco/cli 0.1.22 → 0.1.24
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/dist/commands/configure.js +22 -14
- package/dist/commands/create-project.d.ts +7 -0
- package/dist/commands/create-project.js +22 -0
- package/dist/commands/create.d.ts +7 -5
- package/dist/commands/create.js +11 -8
- package/dist/commands/edit.js +17 -7
- package/dist/commands/run.js +24 -11
- package/dist/index.js +80 -41
- package/package.json +5 -5
- package/dist/commands/mcp-add.d.ts +0 -14
- package/dist/commands/mcp-add.js +0 -494
- package/dist/commands/mcp-list.d.ts +0 -3
- package/dist/commands/mcp-list.js +0 -63
- package/dist/commands/mcp-remove.d.ts +0 -3
- package/dist/commands/mcp-remove.js +0 -120
- package/dist/lib/mcp-storage.d.ts +0 -32
- package/dist/lib/mcp-storage.js +0 -111
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { SingleSelect } from "@townco/ui/tui";
|
|
3
|
-
import { Box, render, Text } from "ink";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import { deleteMCPConfig, getMCPSummary, listMCPConfigs, } from "../lib/mcp-storage";
|
|
6
|
-
// ============================================================================
|
|
7
|
-
// Main Component
|
|
8
|
-
// ============================================================================
|
|
9
|
-
function MCPRemoveApp() {
|
|
10
|
-
const [stage, setStage] = useState("loading");
|
|
11
|
-
const [configs, setConfigs] = useState([]);
|
|
12
|
-
const [selectedName, setSelectedName] = useState(null);
|
|
13
|
-
const [selectedConfig, setSelectedConfig] = useState(null);
|
|
14
|
-
const [errorMessage, setErrorMessage] = useState("");
|
|
15
|
-
// Load configs on mount
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
function loadConfigs() {
|
|
18
|
-
try {
|
|
19
|
-
const configList = listMCPConfigs();
|
|
20
|
-
setConfigs(configList);
|
|
21
|
-
setStage(configList.length > 0 ? "select" : "error");
|
|
22
|
-
if (configList.length === 0) {
|
|
23
|
-
setErrorMessage("No MCP servers configured");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
28
|
-
setErrorMessage(errorMsg);
|
|
29
|
-
setStage("error");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
loadConfigs();
|
|
33
|
-
}, []);
|
|
34
|
-
// Handle removal
|
|
35
|
-
const handleRemove = () => {
|
|
36
|
-
if (!selectedName)
|
|
37
|
-
return;
|
|
38
|
-
setStage("removing");
|
|
39
|
-
try {
|
|
40
|
-
const success = deleteMCPConfig(selectedName);
|
|
41
|
-
if (success) {
|
|
42
|
-
setStage("done");
|
|
43
|
-
// Exit immediately
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
throw new Error("Failed to delete MCP config");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
52
|
-
setErrorMessage(errorMsg);
|
|
53
|
-
setStage("error");
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
if (stage === "loading") {
|
|
57
|
-
return (_jsx(Box, { children: _jsx(Text, { children: "Loading MCP servers..." }) }));
|
|
58
|
-
}
|
|
59
|
-
if (stage === "error") {
|
|
60
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "red", children: "\u274C Error" }) }), _jsx(Box, { children: _jsx(Text, { children: errorMessage }) })] }));
|
|
61
|
-
}
|
|
62
|
-
if (stage === "select") {
|
|
63
|
-
const options = configs.map((config) => ({
|
|
64
|
-
label: config.name,
|
|
65
|
-
value: config.name,
|
|
66
|
-
description: getMCPSummary(config),
|
|
67
|
-
}));
|
|
68
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Select MCP server to remove" }) }), _jsx(SingleSelect, { options: options, selected: selectedName, onChange: setSelectedName, onSubmit: (name) => {
|
|
69
|
-
const found = configs.find((c) => c.name === name);
|
|
70
|
-
if (found) {
|
|
71
|
-
setSelectedName(name);
|
|
72
|
-
setSelectedConfig(found);
|
|
73
|
-
setStage("confirm");
|
|
74
|
-
}
|
|
75
|
-
}, onCancel: () => process.exit(0) })] }));
|
|
76
|
-
}
|
|
77
|
-
if (stage === "confirm") {
|
|
78
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Confirm removal" }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Are you sure you want to remove:", " ", _jsx(Text, { bold: true, children: selectedConfig?.name })] }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: getMCPSummary(selectedConfig) }) }), _jsx(SingleSelect, { options: [
|
|
79
|
-
{
|
|
80
|
-
label: "Yes, remove it",
|
|
81
|
-
value: "yes",
|
|
82
|
-
description: "Permanently delete this MCP server configuration",
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
label: "No, cancel",
|
|
86
|
-
value: "no",
|
|
87
|
-
description: "Go back to selection",
|
|
88
|
-
},
|
|
89
|
-
], selected: null, onChange: () => { }, onSubmit: (choice) => {
|
|
90
|
-
if (choice === "yes") {
|
|
91
|
-
handleRemove();
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
setStage("select");
|
|
95
|
-
}
|
|
96
|
-
}, onCancel: () => setStage("select") })] }));
|
|
97
|
-
}
|
|
98
|
-
if (stage === "removing") {
|
|
99
|
-
return (_jsx(Box, { children: _jsx(Text, { children: "\uD83D\uDDD1\uFE0F Removing MCP server..." }) }));
|
|
100
|
-
}
|
|
101
|
-
if (stage === "done") {
|
|
102
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "green", children: "\u2705 MCP server removed successfully" }) }), _jsx(Box, { children: _jsxs(Text, { children: ["Removed: ", _jsx(Text, { bold: true, children: selectedConfig?.name })] }) })] }));
|
|
103
|
-
}
|
|
104
|
-
return _jsxs(Text, { children: ["Unknown stage: ", stage] });
|
|
105
|
-
}
|
|
106
|
-
// ============================================================================
|
|
107
|
-
// Export and Runner
|
|
108
|
-
// ============================================================================
|
|
109
|
-
export default MCPRemoveApp;
|
|
110
|
-
export async function runMCPRemove() {
|
|
111
|
-
const { waitUntilExit, clear } = render(_jsx(MCPRemoveApp, {}));
|
|
112
|
-
try {
|
|
113
|
-
await waitUntilExit();
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
clear();
|
|
117
|
-
// Ensure cursor is visible
|
|
118
|
-
process.stdout.write("\x1B[?25h");
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export type MCPConfig = {
|
|
2
|
-
name: string;
|
|
3
|
-
transport: "stdio" | "http";
|
|
4
|
-
command?: string;
|
|
5
|
-
args?: string[];
|
|
6
|
-
url?: string;
|
|
7
|
-
headers?: Record<string, string>;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Save an MCP config to the store
|
|
11
|
-
*/
|
|
12
|
-
export declare function saveMCPConfig(config: MCPConfig): void;
|
|
13
|
-
/**
|
|
14
|
-
* Load an MCP config by name
|
|
15
|
-
*/
|
|
16
|
-
export declare function loadMCPConfig(name: string): MCPConfig | null;
|
|
17
|
-
/**
|
|
18
|
-
* Delete an MCP config by name
|
|
19
|
-
*/
|
|
20
|
-
export declare function deleteMCPConfig(name: string): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* List all MCP configs
|
|
23
|
-
*/
|
|
24
|
-
export declare function listMCPConfigs(): MCPConfig[];
|
|
25
|
-
/**
|
|
26
|
-
* Check if an MCP config exists
|
|
27
|
-
*/
|
|
28
|
-
export declare function mcpConfigExists(name: string): boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Get a summary of an MCP config for display
|
|
31
|
-
*/
|
|
32
|
-
export declare function getMCPSummary(config: MCPConfig): string;
|
package/dist/lib/mcp-storage.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
// ============================================================================
|
|
5
|
-
// Constants
|
|
6
|
-
// ============================================================================
|
|
7
|
-
const TOWN_CONFIG_DIR = join(homedir(), ".config", "town");
|
|
8
|
-
const MCPS_FILE = join(TOWN_CONFIG_DIR, "mcps.json");
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// Helper Functions
|
|
11
|
-
// ============================================================================
|
|
12
|
-
/**
|
|
13
|
-
* Ensure the config directory exists
|
|
14
|
-
*/
|
|
15
|
-
function ensureConfigDir() {
|
|
16
|
-
if (!existsSync(TOWN_CONFIG_DIR)) {
|
|
17
|
-
mkdirSync(TOWN_CONFIG_DIR, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Load all MCP configs from the JSON file
|
|
22
|
-
*/
|
|
23
|
-
function loadStore() {
|
|
24
|
-
ensureConfigDir();
|
|
25
|
-
if (!existsSync(MCPS_FILE)) {
|
|
26
|
-
return {};
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const content = readFileSync(MCPS_FILE, "utf-8");
|
|
30
|
-
return JSON.parse(content);
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
throw new Error(`Failed to load MCP configs: ${error instanceof Error ? error.message : String(error)}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Save all MCP configs to the JSON file
|
|
38
|
-
*/
|
|
39
|
-
function saveStore(store) {
|
|
40
|
-
ensureConfigDir();
|
|
41
|
-
try {
|
|
42
|
-
const content = JSON.stringify(store, null, 2);
|
|
43
|
-
writeFileSync(MCPS_FILE, content, "utf-8");
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
throw new Error(`Failed to save MCP configs: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Public API
|
|
51
|
-
// ============================================================================
|
|
52
|
-
/**
|
|
53
|
-
* Save an MCP config to the store
|
|
54
|
-
*/
|
|
55
|
-
export function saveMCPConfig(config) {
|
|
56
|
-
const store = loadStore();
|
|
57
|
-
store[config.name] = config;
|
|
58
|
-
saveStore(store);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Load an MCP config by name
|
|
62
|
-
*/
|
|
63
|
-
export function loadMCPConfig(name) {
|
|
64
|
-
const store = loadStore();
|
|
65
|
-
return store[name] || null;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Delete an MCP config by name
|
|
69
|
-
*/
|
|
70
|
-
export function deleteMCPConfig(name) {
|
|
71
|
-
const store = loadStore();
|
|
72
|
-
if (store[name]) {
|
|
73
|
-
delete store[name];
|
|
74
|
-
saveStore(store);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* List all MCP configs
|
|
81
|
-
*/
|
|
82
|
-
export function listMCPConfigs() {
|
|
83
|
-
const store = loadStore();
|
|
84
|
-
return Object.values(store).sort((a, b) => a.name.localeCompare(b.name));
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Check if an MCP config exists
|
|
88
|
-
*/
|
|
89
|
-
export function mcpConfigExists(name) {
|
|
90
|
-
const store = loadStore();
|
|
91
|
-
return name in store;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get a summary of an MCP config for display
|
|
95
|
-
*/
|
|
96
|
-
export function getMCPSummary(config) {
|
|
97
|
-
if (config.transport === "http") {
|
|
98
|
-
const parts = [`HTTP: ${config.url}`];
|
|
99
|
-
if (config.headers && Object.keys(config.headers).length > 0) {
|
|
100
|
-
parts.push(`(${Object.keys(config.headers).length} header${Object.keys(config.headers).length === 1 ? "" : "s"})`);
|
|
101
|
-
}
|
|
102
|
-
return parts.join(" ");
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
const parts = [`Stdio: ${config.command}`];
|
|
106
|
-
if (config.args && config.args.length > 0) {
|
|
107
|
-
parts.push(`[${config.args.join(" ")}]`);
|
|
108
|
-
}
|
|
109
|
-
return parts.join(" ");
|
|
110
|
-
}
|
|
111
|
-
}
|