@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.
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
3
  import { join } from "node:path";
4
+ import { isInsideTownProject } from "@townco/agent/storage";
5
5
  import inquirer from "inquirer";
6
6
  const ENV_KEYS = [
7
7
  {
@@ -20,14 +20,20 @@ const ENV_KEYS = [
20
20
  required: false,
21
21
  },
22
22
  ];
23
- function getConfigDir() {
24
- return join(homedir(), ".config", "town");
23
+ async function getProjectRoot() {
24
+ const projectRoot = await isInsideTownProject();
25
+ if (projectRoot === null) {
26
+ console.error("āŒ Error: Not inside a Town project.");
27
+ console.error("\nRun `town create --init <path>` to initialize a project first.");
28
+ process.exit(1);
29
+ }
30
+ return projectRoot;
25
31
  }
26
- function getEnvFilePath() {
27
- return join(getConfigDir(), ".env");
32
+ function getEnvFilePath(projectRoot) {
33
+ return join(projectRoot, ".env");
28
34
  }
29
- async function loadExistingEnv() {
30
- const envPath = getEnvFilePath();
35
+ async function loadExistingEnv(projectRoot) {
36
+ const envPath = getEnvFilePath(projectRoot);
31
37
  if (!existsSync(envPath)) {
32
38
  return {};
33
39
  }
@@ -45,9 +51,9 @@ async function loadExistingEnv() {
45
51
  }
46
52
  return config;
47
53
  }
48
- async function saveEnv(config) {
49
- const configDir = getConfigDir();
50
- await mkdir(configDir, { recursive: true });
54
+ async function saveEnv(config, projectRoot) {
55
+ // Ensure project root exists (it should, but just to be safe)
56
+ await mkdir(projectRoot, { recursive: true });
51
57
  const lines = [
52
58
  "# Town CLI Configuration",
53
59
  "# Environment variables for Town agents",
@@ -61,11 +67,13 @@ async function saveEnv(config) {
61
67
  lines.push("");
62
68
  }
63
69
  }
64
- await writeFile(getEnvFilePath(), lines.join("\n"), "utf-8");
70
+ await writeFile(getEnvFilePath(projectRoot), lines.join("\n"), "utf-8");
65
71
  }
66
72
  export async function configureCommand() {
67
73
  console.log("šŸ”§ Town Configuration\n");
68
- const existingConfig = await loadExistingEnv();
74
+ // Get project root (will error and exit if not in a project)
75
+ const projectRoot = await getProjectRoot();
76
+ const existingConfig = await loadExistingEnv(projectRoot);
69
77
  const hasExisting = Object.keys(existingConfig).length > 0;
70
78
  if (hasExisting) {
71
79
  console.log("Found existing configuration:\n");
@@ -140,7 +148,7 @@ export async function configureCommand() {
140
148
  }
141
149
  }
142
150
  // Save configuration
143
- await saveEnv(newConfig);
144
- console.log(`\nāœ… Configuration saved to ${getEnvFilePath()}`);
151
+ await saveEnv(newConfig, projectRoot);
152
+ console.log(`\nāœ… Configuration saved to ${getEnvFilePath(projectRoot)}`);
145
153
  console.log("\nThese environment variables will be automatically loaded when running agents.");
146
154
  }
@@ -0,0 +1,7 @@
1
+ export interface CreateProjectCommandProps {
2
+ path?: string;
3
+ }
4
+ /**
5
+ * Create a new standalone project with agents and tools
6
+ */
7
+ export declare function createProjectCommand(props?: CreateProjectCommandProps): Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { resolve } from "node:path";
2
+ import { scaffoldProject } from "@townco/agent/scaffold";
3
+ /**
4
+ * Create a new standalone project with agents and tools
5
+ */
6
+ export async function createProjectCommand(props = {}) {
7
+ const { path = process.cwd() } = props;
8
+ // Resolve the path to absolute
9
+ const projectPath = resolve(path);
10
+ console.log(`Creating new Town agents project at: ${projectPath}`);
11
+ const result = await scaffoldProject({
12
+ path: projectPath,
13
+ });
14
+ if (result.success) {
15
+ console.log("\nāœ“ Project created successfully!");
16
+ console.log(`\nProject path: ${result.path}`);
17
+ }
18
+ else {
19
+ console.error(`\nāœ— Error creating project: ${result.error}`);
20
+ process.exit(1);
21
+ }
22
+ }
@@ -1,8 +1,10 @@
1
1
  interface CreateCommandProps {
2
- name?: string;
3
- model?: string;
4
- tools?: readonly string[];
5
- systemPrompt?: string;
6
- overwrite?: boolean;
2
+ name?: string;
3
+ model?: string;
4
+ tools?: readonly string[];
5
+ systemPrompt?: string;
6
+ overwrite?: boolean;
7
+ agentsDir: string;
7
8
  }
8
9
  export declare function createCommand(props: CreateCommandProps): Promise<void>;
10
+ export {};
@@ -52,7 +52,7 @@ function NameInput({ nameInput, setNameInput, onSubmit }) {
52
52
  });
53
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" }) })] }));
54
54
  }
55
- function CreateApp({ name: initialName, model: initialModel, tools: initialTools, systemPrompt: initialSystemPrompt, overwrite = false, }) {
55
+ function CreateApp({ name: initialName, model: initialModel, tools: initialTools, systemPrompt: initialSystemPrompt, overwrite = false, agentsDir, }) {
56
56
  // Determine the starting stage based on what's provided
57
57
  const determineInitialStage = () => {
58
58
  if (!initialName)
@@ -119,14 +119,17 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
119
119
  }
120
120
  const name = agentDef.name;
121
121
  const model = agentDef.model;
122
+ const definition = {
123
+ model,
124
+ systemPrompt: agentDef.systemPrompt || null,
125
+ tools: agentDef.tools || [],
126
+ };
127
+ // Create agent in project
122
128
  scaffoldAgent({
123
129
  name,
124
- definition: {
125
- model,
126
- systemPrompt: agentDef.systemPrompt || null,
127
- tools: agentDef.tools || [],
128
- },
130
+ definition,
129
131
  overwrite,
132
+ agentsDir,
130
133
  }).then((result) => {
131
134
  if (result.success) {
132
135
  setScaffoldStatus("done");
@@ -142,7 +145,7 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
142
145
  }
143
146
  });
144
147
  }
145
- }, [stage, scaffoldStatus, agentDef, overwrite]);
148
+ }, [stage, scaffoldStatus, agentDef, overwrite, agentsDir]);
146
149
  // Name stage
147
150
  if (stage === "name") {
148
151
  return (_jsx(NameInput, { nameInput: nameInput, setNameInput: setNameInput, onSubmit: () => {
@@ -294,7 +297,7 @@ function CreateApp({ name: initialName, model: initialModel, tools: initialTools
294
297
  }
295
298
  if (scaffoldStatus === "done") {
296
299
  const modelLabel = agentDef.model?.replace("claude-", "") || "";
297
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Agent created successfully!" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "\u25CF" }), " ", _jsx(Text, { bold: true, children: agentDef.name })] }), _jsxs(Text, { dimColor: true, children: [" Model: ", modelLabel] }), agentDef.tools && agentDef.tools.length > 0 && (_jsxs(Text, { dimColor: true, children: [" Tools: ", agentDef.tools.join(", ")] })), _jsxs(Text, { dimColor: true, children: [" Path: ", agentPath] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Run an agent with: town run ", agentDef.name] }), _jsx(Text, { dimColor: true, children: "TUI mode (default), --gui for web interface, --http for API server" })] })] }));
300
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Agent created successfully!" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "\u25CF" }), " ", _jsx(Text, { bold: true, children: agentDef.name })] }), _jsxs(Text, { dimColor: true, children: [" Model: ", modelLabel] }), agentDef.tools && agentDef.tools.length > 0 && (_jsxs(Text, { dimColor: true, children: [" Tools: ", agentDef.tools.join(", ")] })), _jsxs(Text, { dimColor: true, children: [" Path: ", agentPath] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Run agent: bun agents/", agentDef.name, "/index.ts stdio"] }), _jsxs(Text, { dimColor: true, children: ["GUI: cd agents/", agentDef.name, "/gui && bun run dev"] }), _jsxs(Text, { dimColor: true, children: ["TUI: cd agents/", agentDef.name, "/tui && bun start"] })] })] }));
298
301
  }
299
302
  }
300
303
  return null;
@@ -1,10 +1,9 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { agentExists, getAgentPath } from "@townco/agent/storage";
3
+ import { isInsideTownProject } from "@townco/agent/storage";
4
4
  import { createCommand } from "./create.js";
5
- async function loadAgentConfig(name) {
5
+ async function loadAgentConfig(name, agentPath) {
6
6
  try {
7
- const agentPath = getAgentPath(name);
8
7
  const indexPath = join(agentPath, "index.ts");
9
8
  const content = await readFile(indexPath, "utf-8");
10
9
  // Parse model
@@ -55,15 +54,25 @@ async function loadAgentConfig(name) {
55
54
  }
56
55
  }
57
56
  export async function editCommand(name) {
58
- // Check if agent exists
59
- const exists = await agentExists(name);
60
- if (!exists) {
57
+ // Check if we're inside a Town project
58
+ const projectRoot = await isInsideTownProject();
59
+ if (projectRoot === null) {
60
+ console.error("Error: Not inside a Town project.\n\n" +
61
+ "Please run 'town edit' inside a project directory.");
62
+ process.exit(1);
63
+ }
64
+ const agentPath = join(projectRoot, "agents", name);
65
+ // Check if the agent exists
66
+ try {
67
+ await readFile(join(agentPath, "agent.json"), "utf-8");
68
+ }
69
+ catch {
61
70
  console.error(`Error: Agent "${name}" not found.`);
62
71
  console.log('\nCreate an agent with "town create" or list agents with "town list"');
63
72
  process.exit(1);
64
73
  }
65
74
  // Load existing config
66
- const config = await loadAgentConfig(name);
75
+ const config = await loadAgentConfig(name, agentPath);
67
76
  if (!config) {
68
77
  console.error(`Error: Failed to load agent configuration for "${name}".`);
69
78
  process.exit(1);
@@ -78,5 +87,6 @@ export async function editCommand(name) {
78
87
  systemPrompt: config.systemPrompt,
79
88
  }),
80
89
  overwrite: true,
90
+ agentsDir: join(projectRoot, "agents"),
81
91
  });
82
92
  }
@@ -2,9 +2,8 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { spawn } from "node:child_process";
3
3
  import { existsSync } from "node:fs";
4
4
  import { readFile } from "node:fs/promises";
5
- import { homedir } from "node:os";
6
5
  import { join } from "node:path";
7
- import { agentExists, getAgentPath } from "@townco/agent/storage";
6
+ import { isInsideTownProject } from "@townco/agent/storage";
8
7
  import { createLogger } from "@townco/agent/utils";
9
8
  import { AcpClient } from "@townco/ui";
10
9
  import { ChatView } from "@townco/ui/tui";
@@ -100,10 +99,11 @@ function GuiRunner({ agentProcess, guiProcess, agentPort, agentPath, logger, onE
100
99
  ], [agentProcess, guiProcess, agentPort]);
101
100
  return (_jsx(TabbedOutput, { processes: processes, logsDir: join(agentPath, ".logs"), onExit: onExit, onPortDetected: handlePortDetected }));
102
101
  }
103
- async function loadEnvVars(logger) {
104
- const envPath = join(homedir(), ".config", "town", ".env");
102
+ async function loadEnvVars(projectRoot, logger) {
103
+ const envPath = join(projectRoot, ".env");
105
104
  const envVars = {};
106
105
  if (!existsSync(envPath)) {
106
+ logger?.debug("No .env file found in project root", { path: envPath });
107
107
  return envVars;
108
108
  }
109
109
  try {
@@ -133,16 +133,29 @@ async function loadEnvVars(logger) {
133
133
  }
134
134
  export async function runCommand(options) {
135
135
  const { name, http = false, gui = false, port = 3100 } = options;
136
- // Load environment variables from ~/.config/town/.env
137
- const configEnvVars = await loadEnvVars();
136
+ // Check if we're inside a Town project
137
+ const projectRoot = await isInsideTownProject();
138
+ if (projectRoot === null) {
139
+ console.error("Error: Not inside a Town project.");
140
+ console.log('\nPlease run "town run" inside a project directory, or run:\n' +
141
+ " town create --init <path>\n" +
142
+ "to create a project.");
143
+ process.exit(1);
144
+ }
145
+ // Load environment variables from project .env
146
+ const configEnvVars = await loadEnvVars(projectRoot);
147
+ // Resolve agent path within the project
148
+ const agentPath = join(projectRoot, "agents", name);
138
149
  // Check if agent exists
139
- const exists = await agentExists(name);
140
- if (!exists) {
150
+ try {
151
+ const { stat } = await import("node:fs/promises");
152
+ await stat(agentPath);
153
+ }
154
+ catch {
141
155
  console.error(`Error: Agent "${name}" not found.`);
142
156
  console.log('\nCreate an agent with "town create" or list agents with "town list"');
143
157
  process.exit(1);
144
158
  }
145
- const agentPath = getAgentPath(name);
146
159
  const binPath = join(agentPath, "bin.ts");
147
160
  // Create logger with agent directory as logs location
148
161
  const logger = createLogger("cli", "debug", {
@@ -200,8 +213,8 @@ export async function runCommand(options) {
200
213
  PORT: availablePort.toString(),
201
214
  },
202
215
  });
203
- // Start the GUI dev server
204
- const guiProcess = spawn("bun", ["run", "dev"], {
216
+ // Start the GUI dev server (no package.json, run vite directly)
217
+ const guiProcess = spawn("bunx", ["vite"], {
205
218
  cwd: guiPath,
206
219
  stdio: ["ignore", "pipe", "pipe"], // Pipe stdout/stderr for capture
207
220
  env: {
package/dist/index.js CHANGED
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env bun
2
+ import { join } from "node:path";
2
3
  import { argument, command, constant, flag, multiple, object, option, optional, or, } from "@optique/core";
3
4
  import { message } from "@optique/core/message";
4
5
  import { integer, string } from "@optique/core/valueparser";
5
6
  import { run } from "@optique/run";
7
+ import { initForClaudeCode } from "@townco/agent/scaffold";
8
+ import { isInsideTownProject } from "@townco/agent/storage";
6
9
  import { createSecret, deleteSecret, genenv, listSecrets, } from "@townco/secret";
7
10
  import inquirer from "inquirer";
8
11
  import { match } from "ts-pattern";
9
12
  import { configureCommand } from "./commands/configure.js";
10
13
  import { createCommand } from "./commands/create.js";
14
+ import { createProjectCommand } from "./commands/create-project.js";
11
15
  import { deleteCommand } from "./commands/delete.js";
12
16
  import { editCommand } from "./commands/edit.js";
13
17
  import { listCommand } from "./commands/list.js";
14
- import { runMCPAdd } from "./commands/mcp-add.js";
15
- import { runMCPList } from "./commands/mcp-list.js";
16
- import { runMCPRemove } from "./commands/mcp-remove.js";
17
18
  import { runCommand } from "./commands/run.js";
18
19
  import { runToolAdd } from "./commands/tool-add.js";
19
20
  import { runToolList } from "./commands/tool-list.js";
@@ -41,7 +42,11 @@ const parser = or(command("deploy", constant("deploy"), { brief: message `Deploy
41
42
  model: optional(option("-m", "--model", string())),
42
43
  tools: multiple(option("-t", "--tool", string())),
43
44
  systemPrompt: optional(option("-p", "--prompt", string())),
44
- }), { brief: message `Create a new agent.` }), command("list", constant("list"), { brief: message `List all agents.` }), command("run", object({
45
+ init: optional(option("--init", string())),
46
+ claude: optional(flag("--claude")),
47
+ }), {
48
+ brief: message `Create a new agent or project (with --init <path>). Use --claude to add Claude Code integration.`,
49
+ }), command("list", constant("list"), { brief: message `List all agents.` }), command("run", object({
45
50
  command: constant("run"),
46
51
  name: argument(string({ metavar: "NAME" })),
47
52
  http: optional(flag("--http")),
@@ -53,20 +58,7 @@ const parser = or(command("deploy", constant("deploy"), { brief: message `Deploy
53
58
  }), { brief: message `Edit an agent.` }), command("delete", object({
54
59
  command: constant("delete"),
55
60
  name: argument(string({ metavar: "NAME" })),
56
- }), { brief: message `Delete an agent.` }), command("mcp", object({
57
- command: constant("mcp"),
58
- subcommand: or(command("add", object({
59
- action: constant("add"),
60
- name: optional(option("-n", "--name", string())),
61
- url: optional(option("-u", "--url", string())),
62
- command: optional(option("-c", "--command", string())),
63
- args: multiple(option("-a", "--arg", string())),
64
- }), { brief: message `Add a new MCP server.` }), command("list", constant("list"), {
65
- brief: message `List all configured MCP servers.`,
66
- }), command("remove", constant("remove"), {
67
- brief: message `Remove an MCP server.`,
68
- })),
69
- }), { brief: message `Manage MCP (Model Context Protocol) servers.` }), command("tool", object({
61
+ }), { brief: message `Delete an agent.` }), command("tool", object({
70
62
  command: constant("tool"),
71
63
  subcommand: or(command("add", object({
72
64
  action: constant("add"),
@@ -109,15 +101,76 @@ async function main(parser, meta) {
109
101
  .with("configure", async () => {
110
102
  await configureCommand();
111
103
  })
112
- .with({ command: "create" }, async ({ name, model, tools, systemPrompt }) => {
113
- // Create command starts a long-running Ink session
114
- // Only pass defined properties to satisfy exactOptionalPropertyTypes
115
- await createCommand({
116
- ...(name !== undefined && { name }),
117
- ...(model !== undefined && { model }),
118
- ...(tools.length > 0 && { tools }),
119
- ...(systemPrompt !== undefined && { systemPrompt }),
120
- });
104
+ .with({ command: "create" }, async ({ name, model, tools, systemPrompt, init, claude }) => {
105
+ // Handle --claude flag (initialize .claude in existing project)
106
+ if (claude === true) {
107
+ if (init !== null && init !== undefined) {
108
+ console.error("Error: --claude flag is redundant with --init (projects include .claude by default)");
109
+ process.exit(1);
110
+ }
111
+ // Check if we're in a Town project
112
+ const projectRoot = await isInsideTownProject();
113
+ if (projectRoot === null) {
114
+ console.error("Error: Not inside a Town project. Use 'town create --init <path>' to create a new project.");
115
+ process.exit(1);
116
+ }
117
+ // Initialize .claude directory only
118
+ await initForClaudeCode(projectRoot);
119
+ console.log("\nāœ“ Claude Code workspace initialized successfully!");
120
+ return;
121
+ }
122
+ // Check if --init flag is present for project scaffolding
123
+ if (init !== null && init !== undefined) {
124
+ // Project mode - scaffold a standalone project
125
+ await createProjectCommand({
126
+ path: init,
127
+ });
128
+ }
129
+ else {
130
+ // Check if we're inside a Town project
131
+ const projectRoot = await isInsideTownProject();
132
+ if (projectRoot === null) {
133
+ // Not in a project - prompt user to initialize
134
+ const answer = await inquirer.prompt([
135
+ {
136
+ type: "confirm",
137
+ name: "initProject",
138
+ message: "Not inside a Town project. Initialize project in current directory?",
139
+ default: true,
140
+ },
141
+ ]);
142
+ if (answer.initProject) {
143
+ // Initialize project first
144
+ await createProjectCommand({ path: process.cwd() });
145
+ // Then create agent
146
+ await createCommand({
147
+ ...(name !== undefined && { name }),
148
+ ...(model !== undefined && { model }),
149
+ ...(tools.length > 0 && { tools }),
150
+ ...(systemPrompt !== undefined && { systemPrompt }),
151
+ agentsDir: join(process.cwd(), "agents"),
152
+ });
153
+ }
154
+ else {
155
+ // User declined
156
+ console.log("\nPlease run 'town create' inside a project directory, or run:\n" +
157
+ " town create --init <path>\n" +
158
+ "to create a project.");
159
+ process.exit(1);
160
+ }
161
+ }
162
+ else {
163
+ // Agent mode - create agent in existing project
164
+ // Create command starts a long-running Ink session
165
+ await createCommand({
166
+ ...(name !== undefined && { name }),
167
+ ...(model !== undefined && { model }),
168
+ ...(tools.length > 0 && { tools }),
169
+ ...(systemPrompt !== undefined && { systemPrompt }),
170
+ agentsDir: join(projectRoot, "agents"),
171
+ });
172
+ }
173
+ }
121
174
  })
122
175
  .with("list", async () => {
123
176
  await listCommand();
@@ -138,20 +191,6 @@ async function main(parser, meta) {
138
191
  })
139
192
  .with({ command: "delete" }, async ({ name }) => {
140
193
  await deleteCommand(name);
141
- })
142
- .with({ command: "mcp" }, async ({ subcommand }) => {
143
- await match(subcommand)
144
- .with({ action: "add" }, async ({ name, url, command, args }) => {
145
- await runMCPAdd({
146
- ...(name !== undefined && { name }),
147
- ...(url !== undefined && { url }),
148
- ...(command !== undefined && { command }),
149
- ...(args.length > 0 && { args }),
150
- });
151
- })
152
- .with("list", async () => await runMCPList())
153
- .with("remove", async () => await runMCPRemove())
154
- .exhaustive();
155
194
  })
156
195
  .with({ command: "tool" }, async ({ subcommand }) => {
157
196
  await match(subcommand)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@townco/cli",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "town": "./dist/index.js"
@@ -18,16 +18,16 @@
18
18
  "build": "tsc"
19
19
  },
20
20
  "devDependencies": {
21
- "@townco/tsconfig": "0.1.14",
21
+ "@townco/tsconfig": "0.1.16",
22
22
  "@types/bun": "^1.3.1",
23
23
  "@types/react": "^19.2.2"
24
24
  },
25
25
  "dependencies": {
26
26
  "@optique/core": "^0.6.2",
27
27
  "@optique/run": "^0.6.2",
28
- "@townco/agent": "0.1.22",
29
- "@townco/secret": "0.1.17",
30
- "@townco/ui": "0.1.17",
28
+ "@townco/agent": "0.1.24",
29
+ "@townco/secret": "0.1.19",
30
+ "@townco/ui": "0.1.19",
31
31
  "@types/inquirer": "^9.0.9",
32
32
  "ink": "^6.4.0",
33
33
  "ink-text-input": "^6.0.0",
@@ -1,14 +0,0 @@
1
- interface MCPAddProps {
2
- name?: string;
3
- url?: string;
4
- command?: string;
5
- args?: readonly string[];
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;
13
- export default MCPAddApp;
14
- export declare function runMCPAdd(props?: MCPAddProps): Promise<void>;