@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,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
|
|
24
|
-
|
|
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(
|
|
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
|
-
|
|
50
|
-
await mkdir(
|
|
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
|
-
|
|
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,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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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 {};
|
package/dist/commands/create.js
CHANGED
|
@@ -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
|
|
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;
|
package/dist/commands/edit.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
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
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
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
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -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 {
|
|
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(
|
|
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
|
-
//
|
|
137
|
-
const
|
|
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
|
-
|
|
140
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
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
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
29
|
-
"@townco/secret": "0.1.
|
|
30
|
-
"@townco/ui": "0.1.
|
|
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>;
|