@townco/cli 0.1.85 → 0.1.87

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.
@@ -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,6 +0,0 @@
1
- interface ToolAddProps {
2
- name?: string;
3
- }
4
- declare function ToolAddApp({ name: initialName }: ToolAddProps): import("react/jsx-runtime").JSX.Element | null;
5
- export default ToolAddApp;
6
- export declare function runToolAdd(props?: ToolAddProps): Promise<void>;
@@ -1,349 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { getAgentPath, listAgents } from "@townco/agent/storage";
6
- import { MultiSelect } from "@townco/ui/tui";
7
- import { Box, render, Text, useApp, useInput } from "ink";
8
- import TextInput from "ink-text-input";
9
- import { useEffect, useState } from "react";
10
- import { openInEditor } from "../lib/editor-utils";
11
- import { ensureToolsDir, getToolsDir, saveToolConfig, toolConfigExists, } from "../lib/tool-storage";
12
- // ============================================================================
13
- // Helper Functions
14
- // ============================================================================
15
- /**
16
- * Normalize a tool name to kebab-case for use as a filename
17
- */
18
- function normalizeToolName(name) {
19
- return name
20
- .trim()
21
- .toLowerCase()
22
- .replace(/[^a-z0-9]+/g, "-")
23
- .replace(/^-+|-+$/g, "");
24
- }
25
- /**
26
- * Convert kebab-case or snake_case to camelCase for function names
27
- */
28
- function toCamelCase(str) {
29
- return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase());
30
- }
31
- /**
32
- * Convert a name to snake_case for the tool name export
33
- */
34
- function toSnakeCase(str) {
35
- return str
36
- .trim()
37
- .toLowerCase()
38
- .replace(/[^a-z0-9]+/g, "_")
39
- .replace(/^_+|_+$/g, "");
40
- }
41
- /**
42
- * Generate the stub template content
43
- */
44
- function generateStubTemplate(toolName) {
45
- const snakeCaseName = toolName ? toSnakeCase(toolName) : "tool_name";
46
- const camelCaseName = toolName ? toCamelCase(toolName) : "toolName";
47
- const description = toolName
48
- ? `Describe what ${toolName} does here`
49
- : "Describe what your tool does here";
50
- return `// biome-ignore lint/suspicious/noExplicitAny: .
51
- export const schema = (z: any) =>
52
- z.object({
53
- // Define your input parameters here
54
- // Example: message: z.string().describe("The message to process"),
55
- input: z.string().optional(),
56
- });
57
-
58
- export const name = "${snakeCaseName}";
59
- export const description = "${description}";
60
-
61
- export default function ${camelCaseName}(_input: unknown) {
62
- // TODO: Implement your tool logic here
63
-
64
- return "result";
65
- }
66
- `;
67
- }
68
- function TextInputStage({ title, value, onChange, onSubmit, onCancel, placeholder, }) {
69
- useInput((_input, key) => {
70
- if (key.escape) {
71
- onCancel();
72
- }
73
- });
74
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: title }) }), _jsxs(Box, { children: [_jsxs(Text, { children: [">", " "] }), _jsx(TextInput, { value: value, onChange: onChange, onSubmit: onSubmit, ...(placeholder && { placeholder }) })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter: Continue \u2022 Esc: Back" }) })] }));
75
- }
76
- function NameInputStage({ value, onChange, onNext, onBack, }) {
77
- const [localError, setLocalError] = useState(null);
78
- const handleSubmit = () => {
79
- const trimmed = value.trim();
80
- if (!trimmed) {
81
- return;
82
- }
83
- // Check for duplicate
84
- if (toolConfigExists(trimmed)) {
85
- setLocalError(`Tool "${trimmed}" already exists`);
86
- return;
87
- }
88
- onNext(trimmed);
89
- };
90
- const handleChange = (newValue) => {
91
- if (localError) {
92
- setLocalError(null);
93
- }
94
- onChange(newValue);
95
- };
96
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(TextInputStage, { title: "Enter tool name:", value: value, onChange: handleChange, onSubmit: handleSubmit, onCancel: onBack, placeholder: "my-custom-tool" }), localError && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u274C ", localError] }) }))] }));
97
- }
98
- function NoAgentsMessage({ onNext }) {
99
- useEffect(() => {
100
- const timer = setTimeout(() => {
101
- onNext();
102
- }, 1000);
103
- return () => clearTimeout(timer);
104
- }, [onNext]);
105
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "No agents found. Tool will be saved globally." }), _jsx(Text, { dimColor: true, children: "You can attach it to agents later." })] }));
106
- }
107
- function AgentSelectionStage({ selectedAgents, onSelectedAgentsChange, onNext, onBack, }) {
108
- const [availableAgents, setAvailableAgents] = useState([]);
109
- const [isLoading, setIsLoading] = useState(true);
110
- useEffect(() => {
111
- // Fetch available agents
112
- const fetchAgents = async () => {
113
- try {
114
- const agents = await listAgents();
115
- setAvailableAgents(agents);
116
- }
117
- catch (error) {
118
- console.error("Error fetching agents:", error);
119
- setAvailableAgents([]);
120
- }
121
- finally {
122
- setIsLoading(false);
123
- }
124
- };
125
- fetchAgents();
126
- }, []);
127
- // If still loading, show loading message
128
- if (isLoading) {
129
- return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { children: "Loading agents..." }) }));
130
- }
131
- // If no agents available, show info message and auto-proceed
132
- if (availableAgents.length === 0) {
133
- return _jsx(NoAgentsMessage, { onNext: onNext });
134
- }
135
- // Show agent selection UI
136
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Register tool with agents (optional):" }) }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: "Select which agents should have access to this tool." }), _jsx(Text, { dimColor: true, children: "You can skip this step and register agents later." })] }), _jsx(MultiSelect, { options: availableAgents.map((agent) => ({
137
- label: agent,
138
- value: agent,
139
- })), selected: selectedAgents, onChange: onSelectedAgentsChange, onSubmit: onNext, onCancel: onBack })] }));
140
- }
141
- function DoneStage({ config, status, error, attachedAgents }) {
142
- const { exit } = useApp();
143
- useEffect(() => {
144
- if (status === "done") {
145
- setImmediate(() => {
146
- exit();
147
- });
148
- }
149
- }, [status, exit]);
150
- if (status === "saving") {
151
- return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { children: "\u23F3 Saving tool configuration..." }) }));
152
- }
153
- if (status === "error") {
154
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "\u274C Error saving tool" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: error }) })] }));
155
- }
156
- if (status === "done") {
157
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", children: "\u2705 Tool saved successfully!" }), _jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { dimColor: true, children: ["Name: ", config.name] }), _jsxs(Text, { dimColor: true, children: ["Path: ", config.path] })] }), attachedAgents.length > 0 && (_jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(Text, { dimColor: true, children: ["Registered with agents: ", attachedAgents.join(", ")] }) }))] }));
158
- }
159
- return null;
160
- }
161
- // ============================================================================
162
- // Main Component
163
- // ============================================================================
164
- function ToolAddApp({ name: initialName }) {
165
- const { exit } = useApp();
166
- const [stage, setStage] = useState("name");
167
- const [config, setConfig] = useState({});
168
- const [nameInput, setNameInput] = useState(initialName || "");
169
- const [saveStatus, setSaveStatus] = useState("pending");
170
- const [saveError, setSaveError] = useState(null);
171
- const [selectedAgents, setSelectedAgents] = useState([]);
172
- const [tempFilePath, setTempFilePath] = useState(null);
173
- const [editorOpened, setEditorOpened] = useState(false);
174
- // On mount, create temp file and open editor
175
- useEffect(() => {
176
- if (editorOpened)
177
- return;
178
- const setupAndOpenEditor = async () => {
179
- try {
180
- // Generate temp file path
181
- const tempFile = join(tmpdir(), `town-tool-${Date.now()}.ts`);
182
- setTempFilePath(tempFile);
183
- // Generate and write stub template
184
- const stubContent = generateStubTemplate(initialName);
185
- writeFileSync(tempFile, stubContent, "utf-8");
186
- // Open in editor
187
- await openInEditor({ filePath: tempFile });
188
- // After editor closes, move to name input stage
189
- setEditorOpened(true);
190
- }
191
- catch (error) {
192
- setSaveStatus("error");
193
- setSaveError(`Failed to open editor: ${error instanceof Error ? error.message : String(error)}`);
194
- setStage("done");
195
- }
196
- };
197
- setupAndOpenEditor();
198
- }, [initialName, editorOpened]);
199
- const handleSave = (toolName, agentsToAttach) => {
200
- setSaveStatus("saving");
201
- try {
202
- if (!tempFilePath) {
203
- setSaveStatus("error");
204
- setSaveError("Temp file path not found");
205
- return;
206
- }
207
- // Check if temp file still exists
208
- if (!existsSync(tempFilePath)) {
209
- setSaveStatus("error");
210
- setSaveError("Temp file was deleted");
211
- return;
212
- }
213
- // Read the edited content
214
- const editedContent = readFileSync(tempFilePath, "utf-8");
215
- // Ensure tools directory exists
216
- ensureToolsDir();
217
- // Normalize the tool name for the filename
218
- const normalizedName = normalizeToolName(toolName);
219
- const toolsDir = getToolsDir();
220
- const targetPath = join(toolsDir, `${normalizedName}.ts`);
221
- // Write the edited content to the target path
222
- try {
223
- writeFileSync(targetPath, editedContent, "utf-8");
224
- }
225
- catch (error) {
226
- setSaveStatus("error");
227
- setSaveError(`Failed to save file: ${error instanceof Error ? error.message : String(error)}`);
228
- return;
229
- }
230
- // Create tool config
231
- const toolConfig = {
232
- name: toolName,
233
- path: targetPath,
234
- };
235
- // Save to global tool storage
236
- saveToolConfig(toolConfig);
237
- // Update selected agents
238
- for (const agentName of agentsToAttach) {
239
- try {
240
- const agentPath = getAgentPath(agentName);
241
- const agentJsonPath = join(agentPath, "agent.json");
242
- // Read existing agent.json
243
- const agentJsonContent = readFileSync(agentJsonPath, "utf-8");
244
- const agentDef = JSON.parse(agentJsonContent);
245
- // Add tool to tools array (create array if doesn't exist)
246
- if (!agentDef.tools) {
247
- agentDef.tools = [];
248
- }
249
- // Create custom tool object
250
- const customTool = {
251
- type: "custom",
252
- modulePath: targetPath,
253
- };
254
- // Check if this tool is already in the agent's config
255
- const existingIndex = agentDef.tools.findIndex((tool) => typeof tool === "object" &&
256
- tool !== null &&
257
- "type" in tool &&
258
- tool.type === "custom" &&
259
- "modulePath" in tool &&
260
- tool.modulePath === targetPath);
261
- if (existingIndex >= 0) {
262
- // Update existing config
263
- agentDef.tools[existingIndex] = customTool;
264
- }
265
- else {
266
- // Add new config
267
- agentDef.tools.push(customTool);
268
- }
269
- // Write back to agent.json
270
- writeFileSync(agentJsonPath, JSON.stringify(agentDef, null, 2));
271
- }
272
- catch (error) {
273
- console.error(`Error updating agent ${agentName}:`, error);
274
- // Continue with other agents even if one fails
275
- }
276
- }
277
- // Clean up temp file
278
- try {
279
- unlinkSync(tempFilePath);
280
- }
281
- catch (_error) {
282
- // Ignore cleanup errors
283
- }
284
- setConfig(toolConfig);
285
- setSaveStatus("done");
286
- }
287
- catch (error) {
288
- setSaveStatus("error");
289
- setSaveError(error instanceof Error ? error.message : "Unknown error occurred");
290
- }
291
- };
292
- // Wait for editor to open and close before showing UI
293
- if (!editorOpened) {
294
- return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { children: "Opening editor..." }) }));
295
- }
296
- // If there was an error during editor setup, show done stage with error
297
- if (saveStatus === "error" && stage === "done") {
298
- return (_jsx(DoneStage, { config: config, status: saveStatus, error: saveError, attachedAgents: selectedAgents }));
299
- }
300
- // Name input stage
301
- if (stage === "name") {
302
- return (_jsx(NameInputStage, { value: nameInput, onChange: setNameInput, onNext: (name) => {
303
- setConfig({ ...config, name });
304
- setStage("agentSelection");
305
- }, onBack: () => {
306
- // Clean up temp file
307
- if (tempFilePath) {
308
- try {
309
- unlinkSync(tempFilePath);
310
- }
311
- catch (_error) {
312
- // Ignore cleanup errors
313
- }
314
- }
315
- exit();
316
- } }));
317
- }
318
- // Agent selection stage
319
- if (stage === "agentSelection") {
320
- return (_jsx(AgentSelectionStage, { selectedAgents: selectedAgents, onSelectedAgentsChange: setSelectedAgents, onNext: () => {
321
- if (!config.name) {
322
- setSaveStatus("error");
323
- setSaveError("Tool name is required");
324
- setStage("done");
325
- return;
326
- }
327
- handleSave(config.name, selectedAgents);
328
- setStage("done");
329
- }, onBack: () => setStage("name") }));
330
- }
331
- // Done stage
332
- if (stage === "done") {
333
- return (_jsx(DoneStage, { config: config, status: saveStatus, error: saveError, attachedAgents: selectedAgents }));
334
- }
335
- return null;
336
- }
337
- // ============================================================================
338
- // Export and Runner
339
- // ============================================================================
340
- export default ToolAddApp;
341
- export async function runToolAdd(props = {}) {
342
- // Set stdin to raw mode to capture input
343
- if (process.stdin.isTTY) {
344
- process.stdin.setRawMode(true);
345
- }
346
- const { waitUntilExit } = render(_jsx(ToolAddApp, { ...props }));
347
- // Wait for the app to exit before returning
348
- await waitUntilExit();
349
- }
@@ -1,3 +0,0 @@
1
- declare function ToolListApp(): import("react/jsx-runtime").JSX.Element;
2
- export default ToolListApp;
3
- export declare function runToolList(): Promise<void>;
@@ -1,61 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, render, Text, useApp, useInput } from "ink";
3
- import { useEffect, useState } from "react";
4
- import { listToolConfigs } from "../lib/tool-storage";
5
- // ============================================================================
6
- // Main Component
7
- // ============================================================================
8
- function ToolListApp() {
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 = listToolConfigs();
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 tools..." }) }));
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 tools" }) }), _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 tools configured" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Add one with: town tool 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 Tools (", 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: _jsxs(Text, { children: ["Path: ", config.path] }) })] }, config.name))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use `town tool add` to add a tool" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter or Q to exit" }) })] }));
46
- }
47
- // ============================================================================
48
- // Export and Runner
49
- // ============================================================================
50
- export default ToolListApp;
51
- export async function runToolList() {
52
- const { waitUntilExit, clear } = render(_jsx(ToolListApp, {}));
53
- try {
54
- await waitUntilExit();
55
- }
56
- finally {
57
- clear();
58
- // Ensure cursor is visible
59
- process.stdout.write("\x1B[?25h");
60
- }
61
- }
@@ -1,7 +0,0 @@
1
- interface ToolAddProps {
2
- name?: string;
3
- path?: string;
4
- }
5
- declare function ToolAddApp({ name: initialName, path: initialPath }: ToolAddProps): import("react/jsx-runtime").JSX.Element | null;
6
- export default ToolAddApp;
7
- export declare function runToolRegister(props?: ToolAddProps): Promise<void>;