@archon-claw/cli 0.1.0 → 0.2.0

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/cli.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { fileURLToPath } from "url";
3
3
  import path from "path";
4
- import { readFileSync } from "fs";
4
+ import { readFileSync, readdirSync, statSync } from "fs";
5
5
  import dotenv from "dotenv";
6
6
  import { Command } from "commander";
7
7
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
8
  import { loadAgentConfig } from "./config.js";
9
9
  import { createServer } from "./server.js";
10
- import { initSessionStore } from "./session.js";
10
+ import { SessionStore } from "./session.js";
11
11
  import { startDev } from "./dev.js";
12
12
  import { runToolTests, formatResults } from "./test-runner.js";
13
13
  import { runEvals } from "./eval/runner.js";
14
- import { scaffoldAgent, scaffoldWorkspace } from "./scaffold.js";
14
+ import { scaffoldAgent, scaffoldWorkspace, updateSkills } from "./scaffold.js";
15
15
  const pkg = JSON.parse(readFileSync(path.resolve(__dirname, "../package.json"), "utf-8"));
16
16
  const program = new Command();
17
17
  program
@@ -31,15 +31,42 @@ program
31
31
  .action(() => {
32
32
  console.log("Starting agent...");
33
33
  });
34
+ /** Scan a directory for agent subdirectories and load them all */
35
+ async function loadAgentsFromDir(agentsDir) {
36
+ const absDir = path.resolve(agentsDir);
37
+ const entries = readdirSync(absDir);
38
+ const agents = new Map();
39
+ for (const name of entries) {
40
+ const fullPath = path.join(absDir, name);
41
+ if (!statSync(fullPath).isDirectory())
42
+ continue;
43
+ // Skip hidden dirs and common non-agent dirs
44
+ if (name.startsWith(".") || name === "node_modules")
45
+ continue;
46
+ try {
47
+ const config = await loadAgentConfig(fullPath);
48
+ const sessions = new SessionStore(fullPath);
49
+ await sessions.init();
50
+ agents.set(name, { config, sessions });
51
+ }
52
+ catch (err) {
53
+ console.warn(`[warn] Skipping "${name}": ${err instanceof Error ? err.message : err}`);
54
+ }
55
+ }
56
+ if (agents.size === 0) {
57
+ throw new Error(`No valid agents found in ${absDir}`);
58
+ }
59
+ return agents;
60
+ }
34
61
  program
35
62
  .command("dev")
36
63
  .description("Start dev server with hot-reload for agent development")
37
- .argument("<agent-dir>", "Path to agent directory")
64
+ .requiredOption("--agents-dir <path>", "Path to directory containing agent subdirectories")
38
65
  .option("-p, --port <port>", "Server port", "5100")
39
66
  .option("--no-open", "Don't auto-open browser")
40
- .action(async (agentDir, opts) => {
67
+ .action(async (opts) => {
41
68
  try {
42
- await startDev(agentDir, {
69
+ await startDev(opts.agentsDir, {
43
70
  port: parseInt(opts.port, 10),
44
71
  open: opts.open,
45
72
  });
@@ -52,28 +79,28 @@ program
52
79
  program
53
80
  .command("start")
54
81
  .description("Start an agent HTTP server")
55
- .argument("<agent-dir>", "Path to agent directory")
82
+ .requiredOption("--agents-dir <path>", "Path to directory containing agent subdirectories")
56
83
  .option("-p, --port <port>", "Server port", "5100")
57
- .action(async (agentDir, opts) => {
84
+ .action(async (opts) => {
58
85
  try {
59
- const config = await loadAgentConfig(agentDir);
60
- await initSessionStore(agentDir);
86
+ const agents = await loadAgentsFromDir(opts.agentsDir);
61
87
  const port = parseInt(opts.port, 10);
62
- console.log(`Agent loaded:`);
63
- console.log(` Model: ${config.model.provider}/${config.model.model}`);
64
- console.log(` Tools: ${config.tools.map((t) => t.name).join(", ")}`);
65
- if (config.mcpManager) {
66
- const servers = config.mcpManager.getServerNames();
67
- console.log(` MCP servers: ${servers.join(", ")}`);
88
+ console.log("Agents loaded:");
89
+ for (const [id, entry] of agents) {
90
+ const { config } = entry;
91
+ const mcpCount = config.mcpManager ? config.mcpManager.getServerNames().length : 0;
92
+ console.log(` [${id}] Model: ${config.model.provider}/${config.model.model}` +
93
+ ` Tools: ${config.tools.length}` +
94
+ (mcpCount > 0 ? ` MCP: ${mcpCount} servers` : "") +
95
+ ` Skills: ${Object.keys(config.skills).length}`);
68
96
  }
69
- console.log(` Skills: ${Object.keys(config.skills).join(", ") || "(none)"}`);
70
- console.log(` System prompt: ${config.systemPrompt.length} chars`);
71
- const server = createServer(config, port);
97
+ const server = createServer(agents, port);
72
98
  const shutdown = async () => {
73
99
  console.log("\nShutting down...");
74
- await config.mcpManager?.shutdown();
100
+ for (const [, entry] of agents) {
101
+ await entry.config.mcpManager?.shutdown();
102
+ }
75
103
  server.close(() => process.exit(0));
76
- // Force exit if server hasn't closed within 3s
77
104
  setTimeout(() => process.exit(1), 3000).unref();
78
105
  };
79
106
  process.on("SIGINT", shutdown);
@@ -132,11 +159,40 @@ program
132
159
  });
133
160
  program
134
161
  .command("init")
135
- .description("Initialise an agent workspace with shared .claude/ skills")
136
- .argument("[dir]", "Directory to initialise", "./agents")
137
- .action(async (dir) => {
162
+ .description("Initialise an agent workspace project")
163
+ .argument("[dir]", "Directory to initialise")
164
+ .option("--install", "Automatically install npm dependencies")
165
+ .action(async (dir, opts) => {
138
166
  try {
139
- await scaffoldWorkspace(dir);
167
+ const { intro, text, confirm, isCancel, outro } = await import("@clack/prompts");
168
+ intro("archon-claw init");
169
+ if (!dir) {
170
+ const name = await text({
171
+ message: "Project name",
172
+ placeholder: "my-ai-agent",
173
+ validate: (v) => {
174
+ if (!v?.trim())
175
+ return "Project name is required";
176
+ if (!/^[a-z0-9._-]+$/i.test(v))
177
+ return "Invalid directory name";
178
+ },
179
+ });
180
+ if (isCancel(name)) {
181
+ outro("Cancelled");
182
+ return;
183
+ }
184
+ dir = name;
185
+ }
186
+ if (opts.install === undefined) {
187
+ const install = await confirm({ message: "Install dependencies?" });
188
+ if (isCancel(install)) {
189
+ outro("Cancelled");
190
+ return;
191
+ }
192
+ opts.install = install;
193
+ }
194
+ await scaffoldWorkspace(dir, { install: opts.install });
195
+ outro("Done!");
140
196
  }
141
197
  catch (err) {
142
198
  console.error(err instanceof Error ? err.message : err);
@@ -144,13 +200,49 @@ program
144
200
  }
145
201
  });
146
202
  program
147
- .command("create")
203
+ .command("create-agent")
148
204
  .description("Create a new agent project")
149
- .argument("<agent-name>", "Name of the agent (used as directory name)")
205
+ .argument("[agent-name]", "Name of the agent (used as directory name)")
150
206
  .option("-d, --dir <path>", "Parent directory for the agent", "./agents")
151
207
  .action(async (agentName, opts) => {
152
208
  try {
153
- await scaffoldAgent(agentName, opts.dir);
209
+ if (!agentName) {
210
+ const { intro, text, isCancel, outro } = await import("@clack/prompts");
211
+ intro("archon-claw create");
212
+ const name = await text({
213
+ message: "Agent name",
214
+ placeholder: "my-agent",
215
+ validate: (v) => {
216
+ if (!v?.trim())
217
+ return "Agent name is required";
218
+ if (!/^[a-z0-9._-]+$/i.test(v))
219
+ return "Invalid directory name";
220
+ },
221
+ });
222
+ if (isCancel(name)) {
223
+ outro("Cancelled");
224
+ return;
225
+ }
226
+ agentName = name;
227
+ await scaffoldAgent(agentName, opts.dir);
228
+ outro("Done!");
229
+ }
230
+ else {
231
+ await scaffoldAgent(agentName, opts.dir);
232
+ }
233
+ }
234
+ catch (err) {
235
+ console.error(err instanceof Error ? err.message : err);
236
+ process.exit(1);
237
+ }
238
+ });
239
+ program
240
+ .command("update-skills")
241
+ .description("Update skills to the latest version bundled with @archon-claw/cli")
242
+ .argument("[dir]", "Workspace directory", ".")
243
+ .action(async (dir) => {
244
+ try {
245
+ await updateSkills(dir);
154
246
  }
155
247
  catch (err) {
156
248
  console.error(err instanceof Error ? err.message : err);
package/dist/dev.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import http from "node:http";
2
2
  import { type FSWatcher } from "chokidar";
3
- import type { AgentConfig } from "./types.js";
3
+ import { type AgentEntry } from "./server.js";
4
4
  export interface DevOptions {
5
5
  port: number;
6
6
  open: boolean;
@@ -8,13 +8,13 @@ export interface DevOptions {
8
8
  /** Returned by startDev for cleanup and testing */
9
9
  export interface DevHandle {
10
10
  server: http.Server;
11
- watcher: FSWatcher;
12
- /** Current config reference (mutable via reload) */
13
- getConfig(): AgentConfig;
14
- /** Manually trigger config reload */
15
- reload(changedFiles?: string[]): Promise<void>;
11
+ watchers: FSWatcher[];
12
+ /** Current agents map (mutable via reload) */
13
+ getAgents(): Map<string, AgentEntry>;
14
+ /** Manually trigger config reload for a specific agent */
15
+ reloadAgent(agentId: string, changedFiles?: string[]): Promise<void>;
16
16
  /** Graceful shutdown */
17
17
  close(): Promise<void>;
18
18
  }
19
- export declare function startDev(agentDir: string, opts: DevOptions): Promise<DevHandle>;
20
- export declare function printBanner(config: AgentConfig, port: number, absDir: string): void;
19
+ export declare function startDev(agentsDir: string, opts: DevOptions): Promise<DevHandle>;
20
+ export declare function printBanner(agents: Map<string, AgentEntry>, port: number, absDir: string): void;
package/dist/dev.js CHANGED
@@ -1,70 +1,115 @@
1
1
  import path from "node:path";
2
+ import { readdirSync, statSync } from "node:fs";
2
3
  import { watch } from "chokidar";
3
4
  import open from "open";
4
5
  import { loadAgentConfig } from "./config.js";
5
6
  import { createServer } from "./server.js";
6
- import { initSessionStore } from "./session.js";
7
- export async function startDev(agentDir, opts) {
8
- const absDir = path.resolve(agentDir);
9
- // Initial load
10
- let currentConfig = await loadAgentConfig(absDir);
11
- await initSessionStore(absDir);
12
- // Start server with getter — every request reads latest config
13
- const server = createServer(() => currentConfig, opts.port);
14
- printBanner(currentConfig, opts.port, absDir);
7
+ import { SessionStore } from "./session.js";
8
+ /** Scan agents-dir for valid agent subdirectories */
9
+ function scanAgentDirs(agentsDir) {
10
+ const results = [];
11
+ for (const name of readdirSync(agentsDir)) {
12
+ const fullPath = path.join(agentsDir, name);
13
+ if (!statSync(fullPath).isDirectory())
14
+ continue;
15
+ if (name.startsWith(".") || name === "node_modules")
16
+ continue;
17
+ results.push({ id: name, path: fullPath });
18
+ }
19
+ return results;
20
+ }
21
+ export async function startDev(agentsDir, opts) {
22
+ const absDir = path.resolve(agentsDir);
23
+ const agentDirs = scanAgentDirs(absDir);
24
+ if (agentDirs.length === 0) {
25
+ throw new Error(`No agent directories found in ${absDir}`);
26
+ }
27
+ // Initial load of all agents
28
+ const currentAgents = new Map();
29
+ for (const { id, path: agentPath } of agentDirs) {
30
+ try {
31
+ const config = await loadAgentConfig(agentPath);
32
+ const sessions = new SessionStore(agentPath);
33
+ await sessions.init();
34
+ currentAgents.set(id, { config, sessions });
35
+ }
36
+ catch (err) {
37
+ console.warn(`[dev] Skipping "${id}": ${err instanceof Error ? err.message : err}`);
38
+ }
39
+ }
40
+ if (currentAgents.size === 0) {
41
+ throw new Error(`No valid agents found in ${absDir}`);
42
+ }
43
+ // Start server with getter — every request reads latest agents
44
+ const server = createServer(() => currentAgents, opts.port);
45
+ printBanner(currentAgents, opts.port, absDir);
15
46
  // Open browser (skip in SSH)
16
47
  if (opts.open && !process.env.SSH_CLIENT && !process.env.SSH_TTY) {
17
48
  open(`http://localhost:${opts.port}`).catch(() => { });
18
49
  }
19
- // Reload logic
20
- let reloadInFlight = false;
21
- async function reload(changedFiles) {
22
- if (reloadInFlight)
50
+ // Per-agent reload logic
51
+ const reloadInFlight = new Set();
52
+ async function reloadAgent(agentId, changedFiles) {
53
+ if (reloadInFlight.has(agentId))
54
+ return;
55
+ reloadInFlight.add(agentId);
56
+ const agentEntry = agentDirs.find((d) => d.id === agentId);
57
+ if (!agentEntry) {
58
+ reloadInFlight.delete(agentId);
23
59
  return;
24
- reloadInFlight = true;
60
+ }
25
61
  const ts = new Date().toLocaleTimeString();
26
62
  if (changedFiles?.length) {
27
- const relFiles = changedFiles.map((f) => path.relative(absDir, f));
28
- console.log(`\n[dev] ${ts} Changed: ${relFiles.join(", ")}`);
63
+ const relFiles = changedFiles.map((f) => path.relative(agentEntry.path, f));
64
+ console.log(`\n[dev] ${ts} [${agentId}] Changed: ${relFiles.join(", ")}`);
29
65
  }
30
66
  try {
31
- // Shutdown old MCP connections before reloading
32
- await currentConfig.mcpManager?.shutdown();
33
- const newConfig = await loadAgentConfig(absDir);
34
- currentConfig = newConfig;
35
- console.log(`[dev] ${ts} Reloaded \u2713` +
67
+ const existing = currentAgents.get(agentId);
68
+ await existing?.config.mcpManager?.shutdown();
69
+ const newConfig = await loadAgentConfig(agentEntry.path);
70
+ const sessions = existing?.sessions ?? new SessionStore(agentEntry.path);
71
+ if (!existing)
72
+ await sessions.init();
73
+ currentAgents.set(agentId, { config: newConfig, sessions });
74
+ console.log(`[dev] ${ts} [${agentId}] Reloaded \u2713` +
36
75
  ` (tools: ${newConfig.tools.length}, skills: ${Object.keys(newConfig.skills).length})`);
37
76
  }
38
77
  catch (err) {
39
- console.error(`[dev] ${ts} Reload failed: ${err instanceof Error ? err.message : err}`);
78
+ console.error(`[dev] ${ts} [${agentId}] Reload failed: ${err instanceof Error ? err.message : err}`);
40
79
  console.error(`[dev] Continuing with previous valid configuration`);
41
80
  }
42
81
  finally {
43
- reloadInFlight = false;
82
+ reloadInFlight.delete(agentId);
44
83
  }
45
84
  }
46
- // Watch agent directory
47
- const watcher = watch(absDir, {
48
- ignored: [
49
- "**/sessions/**",
50
- "**/node_modules/**",
51
- "**/eval-results/**",
52
- "**/.DS_Store",
53
- ],
54
- ignoreInitial: true,
55
- });
56
- let debounceTimer = null;
57
- let pendingFiles = [];
58
- watcher.on("all", (_event, filePath) => {
59
- pendingFiles.push(filePath);
60
- if (debounceTimer)
61
- clearTimeout(debounceTimer);
62
- debounceTimer = setTimeout(async () => {
63
- const files = [...pendingFiles];
64
- pendingFiles = [];
65
- await reload(files);
66
- }, 100);
67
- });
85
+ // Watch each agent directory
86
+ const watchers = [];
87
+ for (const { id, path: agentPath } of agentDirs) {
88
+ if (!currentAgents.has(id))
89
+ continue; // Skip agents that failed to load
90
+ const watcher = watch(agentPath, {
91
+ ignored: [
92
+ "**/sessions/**",
93
+ "**/node_modules/**",
94
+ "**/eval-results/**",
95
+ "**/.DS_Store",
96
+ ],
97
+ ignoreInitial: true,
98
+ });
99
+ let debounceTimer = null;
100
+ let pendingFiles = [];
101
+ watcher.on("all", (_event, filePath) => {
102
+ pendingFiles.push(filePath);
103
+ if (debounceTimer)
104
+ clearTimeout(debounceTimer);
105
+ debounceTimer = setTimeout(async () => {
106
+ const files = [...pendingFiles];
107
+ pendingFiles = [];
108
+ await reloadAgent(id, files);
109
+ }, 100);
110
+ });
111
+ watchers.push(watcher);
112
+ }
68
113
  // Graceful shutdown
69
114
  const shutdown = async () => {
70
115
  console.log("\nShutting down...");
@@ -76,40 +121,44 @@ export async function startDev(agentDir, opts) {
76
121
  async function close() {
77
122
  process.removeListener("SIGINT", shutdown);
78
123
  process.removeListener("SIGTERM", shutdown);
79
- if (debounceTimer)
80
- clearTimeout(debounceTimer);
81
- await watcher.close();
82
- await currentConfig.mcpManager?.shutdown();
124
+ for (const watcher of watchers) {
125
+ await watcher.close();
126
+ }
127
+ for (const [, entry] of currentAgents) {
128
+ await entry.config.mcpManager?.shutdown();
129
+ }
83
130
  await new Promise((resolve) => server.close(() => resolve()));
84
131
  }
85
132
  return {
86
133
  server,
87
- watcher,
88
- getConfig: () => currentConfig,
89
- reload,
134
+ watchers,
135
+ getAgents: () => currentAgents,
136
+ reloadAgent,
90
137
  close,
91
138
  };
92
139
  }
93
- export function printBanner(config, port, absDir) {
94
- const mcpCount = config.mcpManager
95
- ? config.tools.length -
96
- config.tools.filter((t) => config.toolImpls.has(t.name) &&
97
- !t.name.includes("__")).length
98
- : 0;
99
- const localCount = config.tools.length - mcpCount;
140
+ export function printBanner(agents, port, absDir) {
100
141
  const lines = [
101
142
  "",
102
143
  " archon-claw dev",
103
144
  "",
104
- ` Agent: ${path.relative(process.cwd(), absDir)}`,
105
- ` Model: ${config.model.provider}/${config.model.model}`,
106
- ` Tools: ${localCount}${mcpCount > 0 ? ` (+ ${mcpCount} from MCP)` : ""}`,
107
- ` Skills: ${Object.keys(config.skills).length}`,
108
- ` URL: http://localhost:${port}`,
109
- "",
110
- " Watching for changes...",
145
+ ` Agents dir: ${path.relative(process.cwd(), absDir)}`,
111
146
  "",
112
147
  ];
148
+ for (const [id, entry] of agents) {
149
+ const { config } = entry;
150
+ const mcpCount = config.mcpManager
151
+ ? config.mcpManager.getServerNames().length
152
+ : 0;
153
+ lines.push(` [${id}] ${config.model.provider}/${config.model.model}` +
154
+ ` tools: ${config.tools.length}${mcpCount > 0 ? ` (+${mcpCount} mcp)` : ""}` +
155
+ ` skills: ${Object.keys(config.skills).length}`);
156
+ }
157
+ lines.push("");
158
+ lines.push(` URL: http://localhost:${port}`);
159
+ lines.push("");
160
+ lines.push(" Watching for changes...");
161
+ lines.push("");
113
162
  const maxLen = Math.max(...lines.map((l) => l.length));
114
163
  const top = "\u250C" + "\u2500".repeat(maxLen + 1) + "\u2510";
115
164
  const bot = "\u2514" + "\u2500".repeat(maxLen + 1) + "\u2518";
@@ -0,0 +1,5 @@
1
+ import type http from "node:http";
2
+ import type { AgentEntry } from "./server.js";
3
+ type AgentMap = Map<string, AgentEntry>;
4
+ export declare function handleMcpRequest(agents: AgentMap, req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
5
+ export {};
@@ -0,0 +1,106 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
+ import { z } from "zod";
4
+ import { runAgentLoop } from "./agent.js";
5
+ function setupTools(server, agents) {
6
+ server.registerTool("list_agents", {
7
+ description: "List available agents",
8
+ }, async () => {
9
+ const list = [...agents.entries()].map(([id, entry]) => ({
10
+ id,
11
+ toolCount: entry.config.tools.length,
12
+ skillCount: Object.keys(entry.config.skills).length,
13
+ }));
14
+ return { content: [{ type: "text", text: JSON.stringify(list, null, 2) }] };
15
+ });
16
+ server.registerTool("chat", {
17
+ description: "Send a message to an agent and get a response. Only server-side tools are available; client/host tools are excluded.",
18
+ inputSchema: z.object({
19
+ agent: z.string().describe("Agent ID"),
20
+ message: z.string().describe("User message"),
21
+ sessionId: z.string().optional().describe("Session ID for conversation continuity"),
22
+ context: z.record(z.unknown()).optional().describe("Additional context passed to the agent system prompt"),
23
+ }),
24
+ }, async ({ agent, message, sessionId, context }) => {
25
+ const entry = agents.get(agent);
26
+ if (!entry) {
27
+ return { content: [{ type: "text", text: `Agent not found: ${agent}` }], isError: true };
28
+ }
29
+ const { config, sessions } = entry;
30
+ // Filter to server-side tools only (client/host tools can't execute without a browser)
31
+ const serverTools = config.tools.filter(t => (t.execution_target ?? "server") === "server");
32
+ const filteredConfig = { ...config, tools: serverTools };
33
+ const session = await sessions.getOrCreate(sessionId);
34
+ const texts = [];
35
+ try {
36
+ await runAgentLoop(filteredConfig, session, message, (event) => {
37
+ if (event.type === "text")
38
+ texts.push(event.content);
39
+ }, context);
40
+ }
41
+ catch (err) {
42
+ await sessions.save(session);
43
+ return {
44
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
45
+ isError: true,
46
+ };
47
+ }
48
+ await sessions.save(session);
49
+ return {
50
+ content: [{ type: "text", text: texts.join("") }],
51
+ structuredContent: { response: texts.join(""), sessionId: session.id },
52
+ };
53
+ });
54
+ server.registerTool("list_sessions", {
55
+ description: "List chat sessions for an agent",
56
+ inputSchema: z.object({
57
+ agent: z.string().describe("Agent ID"),
58
+ }),
59
+ }, async ({ agent }) => {
60
+ const entry = agents.get(agent);
61
+ if (!entry) {
62
+ return { content: [{ type: "text", text: `Agent not found: ${agent}` }], isError: true };
63
+ }
64
+ const all = await entry.sessions.list();
65
+ const list = all.map((s) => {
66
+ const firstUser = s.messages.find((m) => m.role === "user");
67
+ const title = firstUser
68
+ ? firstUser.content.slice(0, 50) + (firstUser.content.length > 50 ? "..." : "")
69
+ : undefined;
70
+ return { id: s.id, title, messageCount: s.messages.length, createdAt: s.createdAt, updatedAt: s.updatedAt };
71
+ }).sort((a, b) => b.updatedAt - a.updatedAt);
72
+ return { content: [{ type: "text", text: JSON.stringify(list, null, 2) }] };
73
+ });
74
+ server.registerTool("get_session", {
75
+ description: "Get session details and message history",
76
+ inputSchema: z.object({
77
+ agent: z.string().describe("Agent ID"),
78
+ sessionId: z.string().describe("Session ID"),
79
+ }),
80
+ }, async ({ agent, sessionId }) => {
81
+ const entry = agents.get(agent);
82
+ if (!entry) {
83
+ return { content: [{ type: "text", text: `Agent not found: ${agent}` }], isError: true };
84
+ }
85
+ const session = await entry.sessions.get(sessionId);
86
+ if (!session) {
87
+ return { content: [{ type: "text", text: "Session not found" }], isError: true };
88
+ }
89
+ return { content: [{ type: "text", text: JSON.stringify(session, null, 2) }] };
90
+ });
91
+ }
92
+ export async function handleMcpRequest(agents, req, res) {
93
+ const server = new McpServer({ name: "archon-claw", version: "1.0.0" });
94
+ setupTools(server, agents);
95
+ const transport = new StreamableHTTPServerTransport({
96
+ sessionIdGenerator: undefined,
97
+ enableJsonResponse: true,
98
+ });
99
+ try {
100
+ await server.connect(transport);
101
+ await transport.handleRequest(req, res);
102
+ }
103
+ finally {
104
+ await server.close();
105
+ }
106
+ }