arcie 0.1.9 → 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/_tsup-dts-rollup.d.ts +49 -0
- package/dist/{build-TWNCPXBU.js → build-GKOF7N76.js} +2 -2
- package/dist/{chunk-4WSILP75.js → chunk-3R65GQAE.js} +5 -4
- package/dist/{chunk-4WSILP75.js.map → chunk-3R65GQAE.js.map} +1 -1
- package/dist/{chunk-KVSX4MLK.js → chunk-XZPC3JSU.js} +59 -2
- package/dist/chunk-XZPC3JSU.js.map +1 -0
- package/dist/cli/index.js +7 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{dev-KO2CRPG3.js → dev-XBXOVOVE.js} +193 -41
- package/dist/dev-XBXOVOVE.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{init-Y7VNAVF7.js → init-BQK2LLTM.js} +11 -24
- package/dist/init-BQK2LLTM.js.map +1 -0
- package/dist/runner/index.js +2 -2
- package/package.json +1 -1
- package/templates/web-chat/app/api/agents/route.ts +37 -0
- package/templates/web-chat/app/api/chat/route.ts +10 -2
- package/templates/web-chat/components/agent-picker.tsx +102 -0
- package/templates/web-chat/components/chat.tsx +42 -2
- package/templates/web-chat/components/input-bar.tsx +4 -0
- package/dist/chunk-KVSX4MLK.js.map +0 -1
- package/dist/dev-KO2CRPG3.js.map +0 -1
- package/dist/init-Y7VNAVF7.js.map +0 -1
- /package/dist/{build-TWNCPXBU.js.map → build-GKOF7N76.js.map} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/loader.ts
|
|
2
2
|
import { readFileSync, existsSync, readdirSync, statSync } from "fs";
|
|
3
3
|
import { resolve, basename, extname } from "path";
|
|
4
|
+
var PRIMARY_AGENT_ID = "agent";
|
|
4
5
|
async function loadAgent(agentDir) {
|
|
5
6
|
const absDir = resolve(process.cwd(), agentDir);
|
|
6
7
|
if (!existsSync(absDir)) {
|
|
@@ -29,6 +30,7 @@ async function loadAgent(agentDir) {
|
|
|
29
30
|
const session = await loadSessionConfig(absDir);
|
|
30
31
|
const policy = await loadPolicyConfig(absDir);
|
|
31
32
|
return {
|
|
33
|
+
id: PRIMARY_AGENT_ID,
|
|
32
34
|
agentDir: absDir,
|
|
33
35
|
manifest: {
|
|
34
36
|
config,
|
|
@@ -45,6 +47,42 @@ async function loadAgent(agentDir) {
|
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
49
|
}
|
|
50
|
+
async function loadInlineAgent(agentDir, id) {
|
|
51
|
+
const absDir = resolve(process.cwd(), agentDir);
|
|
52
|
+
const filePath = resolve(absDir, `${id}.ts`);
|
|
53
|
+
if (!existsSync(filePath)) {
|
|
54
|
+
throw new Error(`Agent not found: ${filePath}`);
|
|
55
|
+
}
|
|
56
|
+
let mod;
|
|
57
|
+
try {
|
|
58
|
+
mod = await import(filePath);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
throw new Error(`Failed to load ${id}.ts: ${err.message}`);
|
|
61
|
+
}
|
|
62
|
+
const config = mod.default;
|
|
63
|
+
if (!config) {
|
|
64
|
+
throw new Error(`${id}.ts must default-export a defineAgent({...}) result`);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
id,
|
|
68
|
+
agentDir: absDir,
|
|
69
|
+
manifest: {
|
|
70
|
+
config,
|
|
71
|
+
instructions: config.instructions ?? "You are a helpful AI agent.",
|
|
72
|
+
tools: config.tools ?? {},
|
|
73
|
+
skills: {},
|
|
74
|
+
hooks: {},
|
|
75
|
+
channels: {},
|
|
76
|
+
connections: {},
|
|
77
|
+
schedules: {},
|
|
78
|
+
subagents: {}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function loadAgentById(agentDir, id) {
|
|
83
|
+
if (id === PRIMARY_AGENT_ID) return loadAgent(agentDir);
|
|
84
|
+
return loadInlineAgent(agentDir, id);
|
|
85
|
+
}
|
|
48
86
|
async function loadSubagents(agentDir) {
|
|
49
87
|
const dirPath = resolve(agentDir, "subagents");
|
|
50
88
|
if (!existsSync(dirPath)) return {};
|
|
@@ -79,6 +117,23 @@ async function loadSubagents(agentDir) {
|
|
|
79
117
|
}
|
|
80
118
|
return result;
|
|
81
119
|
}
|
|
120
|
+
function discoverAgents(agentDir) {
|
|
121
|
+
const absDir = resolve(process.cwd(), agentDir);
|
|
122
|
+
if (!existsSync(absDir)) return [];
|
|
123
|
+
const results = [];
|
|
124
|
+
const primaryPath = resolve(absDir, "agent.ts");
|
|
125
|
+
if (existsSync(primaryPath)) {
|
|
126
|
+
results.push({ id: PRIMARY_AGENT_ID, filePath: primaryPath });
|
|
127
|
+
}
|
|
128
|
+
for (const entry of readdirSync(absDir, { withFileTypes: true })) {
|
|
129
|
+
if (!entry.isFile()) continue;
|
|
130
|
+
if (entry.name === "agent.ts") continue;
|
|
131
|
+
if (!entry.name.endsWith(".ts")) continue;
|
|
132
|
+
const id = entry.name.replace(/\.ts$/, "");
|
|
133
|
+
results.push({ id, filePath: resolve(absDir, entry.name) });
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
82
137
|
function loadInstructionsFile(agentDir) {
|
|
83
138
|
const mdPath = resolve(agentDir, "instructions.md");
|
|
84
139
|
if (existsSync(mdPath)) {
|
|
@@ -134,6 +189,8 @@ async function loadPolicyConfig(agentDir) {
|
|
|
134
189
|
}
|
|
135
190
|
|
|
136
191
|
export {
|
|
137
|
-
loadAgent
|
|
192
|
+
loadAgent,
|
|
193
|
+
loadAgentById,
|
|
194
|
+
discoverAgents
|
|
138
195
|
};
|
|
139
|
-
//# sourceMappingURL=chunk-
|
|
196
|
+
//# sourceMappingURL=chunk-XZPC3JSU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/loader.ts"],"sourcesContent":["import { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { resolve, basename, extname } from \"node:path\";\nimport type {\n AgentManifest,\n AgentConfig,\n ToolConfig,\n SkillConfig,\n HookConfig,\n ChannelConfig,\n ConnectionConfig,\n ScheduleConfig,\n SessionConfig,\n PolicyConfig,\n SubagentManifest,\n} from \"./types\";\n\nexport interface LoadedAgent {\n manifest: AgentManifest;\n agentDir: string;\n /** Stable identifier for this agent within the project. `\"agent\"` for the primary. */\n id: string;\n}\n\nexport const PRIMARY_AGENT_ID = \"agent\";\n\nexport async function loadAgent(agentDir: string): Promise<LoadedAgent> {\n const absDir = resolve(process.cwd(), agentDir);\n\n if (!existsSync(absDir)) {\n throw new Error(`Agent directory not found: ${absDir}`);\n }\n\n const agentFile = resolve(absDir, \"agent.ts\");\n let config: AgentConfig = { model: \"gpt-4o\" };\n\n if (existsSync(agentFile)) {\n try {\n const mod = await import(agentFile);\n if (mod.default) {\n config = { ...config, ...mod.default };\n }\n } catch (err) {\n console.warn(`[arcie] Failed to load agent.ts: ${(err as Error).message}. Using defaults.`);\n }\n }\n\n const instructions = loadInstructionsFile(absDir);\n const tools = await loadDirectory<ToolConfig>(absDir, \"tools\");\n const skills = await loadDirectory<SkillConfig>(absDir, \"skills\");\n const hooks = await loadDirectory<HookConfig>(absDir, \"hooks\");\n const channels = await loadDirectory<ChannelConfig>(absDir, \"channels\");\n const connections = await loadDirectory<ConnectionConfig>(absDir, \"connections\");\n const schedules = await loadDirectory<ScheduleConfig>(absDir, \"schedules\");\n const subagents = await loadSubagents(absDir);\n const session = await loadSessionConfig(absDir);\n const policy = await loadPolicyConfig(absDir);\n\n return {\n id: PRIMARY_AGENT_ID,\n agentDir: absDir,\n manifest: {\n config,\n instructions,\n tools,\n skills,\n hooks,\n channels,\n connections,\n schedules,\n subagents,\n session: session ?? undefined,\n policy: policy ?? undefined,\n },\n };\n}\n\n/**\n * Loads an inline top-level agent — a single `.ts` file at the root of the\n * agent directory (e.g. `agent/researcher.ts`). Inline agents own their\n * tools + instructions inside the file's `defineAgent({...})` call; sibling\n * `tools/`, `subagents/`, `instructions.md` are not traversed. This is the\n * self-contained path for adding multiple top-level agents without carving\n * out a directory per one.\n */\nexport async function loadInlineAgent(agentDir: string, id: string): Promise<LoadedAgent> {\n const absDir = resolve(process.cwd(), agentDir);\n const filePath = resolve(absDir, `${id}.ts`);\n if (!existsSync(filePath)) {\n throw new Error(`Agent not found: ${filePath}`);\n }\n\n let mod: { default?: AgentConfig };\n try {\n mod = await import(filePath);\n } catch (err) {\n throw new Error(`Failed to load ${id}.ts: ${(err as Error).message}`);\n }\n const config = mod.default;\n if (!config) {\n throw new Error(`${id}.ts must default-export a defineAgent({...}) result`);\n }\n\n return {\n id,\n agentDir: absDir,\n manifest: {\n config,\n instructions: config.instructions ?? \"You are a helpful AI agent.\",\n tools: config.tools ?? {},\n skills: {},\n hooks: {},\n channels: {},\n connections: {},\n schedules: {},\n subagents: {},\n },\n };\n}\n\n/**\n * Dispatches to `loadAgent` for the primary (`agent`) or `loadInlineAgent`\n * for any additional top-level `.ts` file. Runners and the HTTP server use\n * this so callers don't need to know the discovery mechanics.\n */\nexport async function loadAgentById(agentDir: string, id: string): Promise<LoadedAgent> {\n if (id === PRIMARY_AGENT_ID) return loadAgent(agentDir);\n return loadInlineAgent(agentDir, id);\n}\n\n/**\n * Loads each `subagents/<id>/` directory as a self-contained child agent.\n * Unlike the other slots, subagents are *directories* (not flat files): every\n * one is a mini-agent with its own config, instructions, tools, and skills.\n * A subagent must declare a `description` so the orchestrator knows when to\n * delegate to it — a missing one is a hard authoring error.\n */\nasync function loadSubagents(\n agentDir: string\n): Promise<Record<string, SubagentManifest>> {\n const dirPath = resolve(agentDir, \"subagents\");\n if (!existsSync(dirPath)) return {};\n\n const result: Record<string, SubagentManifest> = {};\n\n for (const entry of readdirSync(dirPath, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) continue;\n const id = entry.name;\n const subDir = resolve(dirPath, id);\n\n const agentFile = resolve(subDir, \"agent.ts\");\n if (!existsSync(agentFile)) {\n throw new Error(`Subagent \"${id}\" is missing agent.ts`);\n }\n\n let mod: { default?: AgentConfig };\n try {\n mod = await import(agentFile);\n } catch (err) {\n throw new Error(`Failed to load subagent \"${id}\": ${(err as Error).message}`);\n }\n\n const config = mod.default;\n if (!config) {\n throw new Error(`Subagent \"${id}\" agent.ts must have a default export`);\n }\n if (!config.description) {\n throw new Error(`Subagent \"${id}\" must declare a description in agent.ts`);\n }\n\n result[id] = {\n config,\n instructions: loadInstructionsFile(subDir),\n tools: await loadDirectory<ToolConfig>(subDir, \"tools\"),\n skills: await loadDirectory<SkillConfig>(subDir, \"skills\"),\n };\n }\n\n return result;\n}\n\n/**\n * Discovers every top-level agent under `agentDir`: the primary (`agent.ts`)\n * plus any sibling `.ts` file at the same depth. Directory-based subagents\n * (under `subagents/`) are not included here — those belong to the agent\n * that owns them.\n */\nexport function discoverAgents(agentDir: string): Array<{ id: string; filePath: string }> {\n const absDir = resolve(process.cwd(), agentDir);\n if (!existsSync(absDir)) return [];\n const results: Array<{ id: string; filePath: string }> = [];\n const primaryPath = resolve(absDir, \"agent.ts\");\n if (existsSync(primaryPath)) {\n results.push({ id: PRIMARY_AGENT_ID, filePath: primaryPath });\n }\n for (const entry of readdirSync(absDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n if (entry.name === \"agent.ts\") continue;\n if (!entry.name.endsWith(\".ts\")) continue;\n const id = entry.name.replace(/\\.ts$/, \"\");\n results.push({ id, filePath: resolve(absDir, entry.name) });\n }\n return results;\n}\n\nfunction loadInstructionsFile(agentDir: string): string {\n const mdPath = resolve(agentDir, \"instructions.md\");\n if (existsSync(mdPath)) {\n return readFileSync(mdPath, \"utf-8\");\n }\n return \"You are a helpful AI agent.\";\n}\n\nasync function loadDirectory<T>(\n agentDir: string,\n dirName: string\n): Promise<Record<string, T>> {\n const dirPath = resolve(agentDir, dirName);\n if (!existsSync(dirPath)) return {};\n\n const entries = readdirSync(dirPath).filter(\n (f) => !f.startsWith(\".\") && (f.endsWith(\".ts\") || f.endsWith(\".js\"))\n );\n\n const result: Record<string, T> = {};\n\n for (const entry of entries) {\n const name = basename(entry, extname(entry));\n const filePath = resolve(dirPath, entry);\n\n if (statSync(filePath).isFile()) {\n try {\n const mod = await import(filePath);\n if (mod.default) {\n result[name] = mod.default;\n }\n } catch {\n // skip unloadable files\n }\n }\n }\n\n return result;\n}\n\nasync function loadSessionConfig(agentDir: string): Promise<SessionConfig | null> {\n const tsPath = resolve(agentDir, \"sessions\", \"config.ts\");\n if (existsSync(tsPath)) {\n try {\n const mod = await import(tsPath);\n return mod.default ?? null;\n } catch {\n return null;\n }\n }\n return null;\n}\n\nasync function loadPolicyConfig(agentDir: string): Promise<PolicyConfig | null> {\n const tsPath = resolve(agentDir, \"policies\", \"index.ts\");\n if (existsSync(tsPath)) {\n try {\n const mod = await import(tsPath);\n return mod.default ?? null;\n } catch {\n return null;\n }\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/index.js
CHANGED
|
@@ -105,11 +105,11 @@ function createCliProgram(logger) {
|
|
|
105
105
|
});
|
|
106
106
|
program.command("init [target]").description("Create a new arcie agent, or add one to an existing project directory.").option("--template <name>", "Template to use (default, agent-only)", "default").option("-y, --yes", "Accepted for compatibility; has no effect").action(async (target, options) => {
|
|
107
107
|
if (options.yes) logger.error("warning: --yes has no effect for arcie init.");
|
|
108
|
-
const { initCommand } = await import("../init-
|
|
108
|
+
const { initCommand } = await import("../init-BQK2LLTM.js");
|
|
109
109
|
await initCommand(target, { template: options.template });
|
|
110
110
|
});
|
|
111
111
|
program.command("build").description("Compile the agent for production.").option("--agent-dir <path>", "Path to agent directory", "agent").option("--out-dir <path>", "Output directory", ".arcie").action(async (options) => {
|
|
112
|
-
const { buildCommand } = await import("../build-
|
|
112
|
+
const { buildCommand } = await import("../build-GKOF7N76.js");
|
|
113
113
|
await buildCommand(options);
|
|
114
114
|
logger.log(
|
|
115
115
|
renderCliTaggedLine(theme, {
|
|
@@ -139,12 +139,14 @@ function createCliProgram(logger) {
|
|
|
139
139
|
"--context-size <tokens>",
|
|
140
140
|
"Model context window size, shown as a usage percentage",
|
|
141
141
|
parseContextSizeOption
|
|
142
|
-
).option("--logs <mode>", "Which logs to show: all | stderr | none", parseLogsMode).action(async (options) => {
|
|
143
|
-
const { devCommand } = await import("../dev-
|
|
142
|
+
).option("--logs <mode>", "Which logs to show: all | stderr | none", parseLogsMode).option("--no-web", "Do not auto-start the channels/web/ dev server").option("--no-open", "Do not auto-open the browser at the web channel URL").action(async (options) => {
|
|
143
|
+
const { devCommand } = await import("../dev-XBXOVOVE.js");
|
|
144
144
|
await devCommand({
|
|
145
145
|
port: String(options.port ?? 3e3),
|
|
146
146
|
agentDir: options.agentDir,
|
|
147
|
-
input: options.ui === false ? false : Boolean(options.input)
|
|
147
|
+
input: options.ui === false ? false : Boolean(options.input),
|
|
148
|
+
noWeb: options.web === false,
|
|
149
|
+
noOpen: options.open === false
|
|
148
150
|
});
|
|
149
151
|
});
|
|
150
152
|
return program;
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve as resolvePath } from \"node:path\";\nimport { Command, CommanderError, InvalidArgumentError } from \"commander\";\nimport { arcieCliBanner, version } from \"./banner\";\nimport { createCliTheme, renderCliTaggedLine } from \"./ui/output\";\n\ninterface CliLogger {\n error(message: string): void;\n log(message: string): void;\n}\n\nconst DISPLAY_MODES = new Set([\"full\", \"collapsed\", \"auto-collapsed\", \"hidden\"]);\nconst STATS_MODES = new Set([\"tokens\", \"tokensPerSecond\"]);\nconst LOG_MODES = new Set([\"all\", \"stderr\", \"none\"]);\n\ntype TerminalPartDisplayMode = \"full\" | \"collapsed\" | \"auto-collapsed\" | \"hidden\";\ntype AssistantResponseStatsMode = \"tokens\" | \"tokensPerSecond\";\ntype LogDisplayMode = \"all\" | \"stderr\" | \"none\";\n\nfunction parsePortOption(value: string): number {\n if (!/^-?\\d+$/.test(value)) {\n throw new InvalidArgumentError(`Expected a numeric port, received \"${value}\".`);\n }\n const port = Number(value);\n if (port < 0 || port > 65_535) {\n throw new InvalidArgumentError(`Expected a port between 0 and 65535, received \"${value}\".`);\n }\n return port;\n}\n\nfunction parseDisplayMode(value: string): TerminalPartDisplayMode {\n if (!DISPLAY_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...DISPLAY_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as TerminalPartDisplayMode;\n}\n\nfunction parseStatsMode(value: string): AssistantResponseStatsMode {\n if (!STATS_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...STATS_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as AssistantResponseStatsMode;\n}\n\nfunction parseLogsMode(value: string): LogDisplayMode {\n if (!LOG_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...LOG_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as LogDisplayMode;\n}\n\nfunction parseContextSizeOption(value: string): number {\n const size = Number(value);\n if (!Number.isFinite(size) || size <= 0) {\n throw new InvalidArgumentError(`Expected a positive number, received \"${value}\".`);\n }\n return size;\n}\n\nfunction shouldPrintCliBootBanner(actionCommand: Command): boolean {\n const name = actionCommand.name();\n return name === \"info\" || name === \"dev\" || name === \"init\";\n}\n\nfunction createCliProgram(logger: CliLogger): Command {\n const program = new Command();\n const theme = createCliTheme();\n\n program\n .name(\"arcie\")\n .description(\"arcie — the electronic line, build agents at the speed of light\")\n .version(version())\n .showHelpAfterError()\n .exitOverride()\n .hook(\"preAction\", (_program, actionCommand) => {\n if (shouldPrintCliBootBanner(actionCommand)) {\n logger.log(arcieCliBanner());\n }\n })\n .configureOutput({\n writeErr: (message) => logger.error(message.trimEnd()),\n writeOut: (message) => logger.log(message.trimEnd()),\n });\n\n const channels = program\n .command(\"channels\")\n .description(\"Manage channels for the current agent (web UI, HTTP, etc.).\");\n\n channels\n .command(\"add <kind>\")\n .description(\"Scaffold a channel (currently supports: web).\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \".\")\n .action(async (kind: string, options: { agentDir: string }) => {\n if (kind !== \"web\") {\n logger.error(`unknown channel kind: ${kind}. supported: web`);\n process.exit(1);\n }\n const agentDir = resolvePath(process.cwd(), options.agentDir);\n const { scaffoldWebChat } = await import(\"./scaffold-web-chat\");\n try {\n const result = scaffoldWebChat(agentDir);\n if (result.alreadyExisted) {\n logger.error(`channels/web already exists at ${result.targetPath}`);\n process.exit(1);\n }\n logger.log(\n renderCliTaggedLine(theme, {\n message: `scaffolded ${result.targetPath}`,\n tag: \"channels\",\n tone: \"success\",\n }),\n );\n logger.log(\n renderCliTaggedLine(theme, {\n message: \"cd into it, then: npm install && cp .env.local.example .env.local && npm run dev\",\n tag: \"next\",\n tone: \"info\",\n }),\n );\n } catch (err) {\n logger.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n program\n .command(\"init [target]\")\n .description(\"Create a new arcie agent, or add one to an existing project directory.\")\n .option(\"--template <name>\", \"Template to use (default, agent-only)\", \"default\")\n .option(\"-y, --yes\", \"Accepted for compatibility; has no effect\")\n .action(async (target: string | undefined, options: { template: string; yes?: boolean }) => {\n if (options.yes) logger.error(\"warning: --yes has no effect for arcie init.\");\n const { initCommand } = await import(\"./init\");\n await initCommand(target, { template: options.template });\n });\n\n program\n .command(\"build\")\n .description(\"Compile the agent for production.\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \"agent\")\n .option(\"--out-dir <path>\", \"Output directory\", \".arcie\")\n .action(async (options: { agentDir: string; outDir: string }) => {\n const { buildCommand } = await import(\"./build\");\n await buildCommand(options);\n logger.log(\n renderCliTaggedLine(theme, {\n message: `output at ${options.outDir}`,\n tag: \"build\",\n tone: \"success\",\n }),\n );\n });\n\n program\n .command(\"dev\")\n .description(\"Start the arcie development server or attach an interactive UI.\")\n .option(\"-p, --port <port>\", \"Port to listen on\", parsePortOption, 3000)\n .option(\"--host <host>\", \"Host interface to bind\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \"agent\")\n .option(\"--input <text>\", \"Pre-fill the prompt input, or start onboarding with /model\")\n .option(\"--no-ui\", \"Start the server without an interactive UI\")\n .option(\"--name <name>\", \"Title shown in the terminal UI (defaults to the app folder name)\")\n .option(\n \"--tools <mode>\",\n \"How tool calls render: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--reasoning <mode>\",\n \"How reasoning renders: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--subagents <mode>\",\n \"How subagent sections render: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--assistant-response-stats <mode>\",\n \"Assistant header statistic: tokens | tokensPerSecond\",\n parseStatsMode,\n )\n .option(\n \"--context-size <tokens>\",\n \"Model context window size, shown as a usage percentage\",\n parseContextSizeOption,\n )\n .option(\"--logs <mode>\", \"Which logs to show: all | stderr | none\", parseLogsMode)\n .action(async (options) => {\n const { devCommand } = await import(\"./dev\");\n await devCommand({\n port: String(options.port ?? 3000),\n agentDir: options.agentDir,\n input: options.ui === false ? false : Boolean(options.input) || options.ui !== false,\n });\n });\n\n return program;\n}\n\nconst KNOWN_COMMANDS = new Set([\"channels\", \"init\", \"build\", \"dev\", \"help\"]);\n\nfunction resolveArgv(argv: readonly string[]): string[] {\n if (argv.length === 0) return [\"dev\"];\n const first = argv[0]!;\n if (first === \"-h\" || first === \"--help\" || first === \"-V\" || first === \"--version\") {\n return [...argv];\n }\n if (first.startsWith(\"-\")) return [...argv];\n if (KNOWN_COMMANDS.has(first)) return [...argv];\n // Bare positional like `arcie my-agent` — treat as `arcie init my-agent`.\n return [\"init\", ...argv];\n}\n\nexport async function runCli(\n argv: string[] = process.argv.slice(2),\n logger: CliLogger = console,\n): Promise<void> {\n const program = createCliProgram(logger);\n const input = resolveArgv(argv);\n\n try {\n await program.parseAsync(input, { from: \"user\" });\n } catch (error) {\n if (error instanceof CommanderError) {\n if (error.exitCode === 0) return;\n throw new Error(error.message);\n }\n throw error;\n }\n}\n\nrunCli().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve as resolvePath } from \"node:path\";\nimport { Command, CommanderError, InvalidArgumentError } from \"commander\";\nimport { arcieCliBanner, version } from \"./banner\";\nimport { createCliTheme, renderCliTaggedLine } from \"./ui/output\";\n\ninterface CliLogger {\n error(message: string): void;\n log(message: string): void;\n}\n\nconst DISPLAY_MODES = new Set([\"full\", \"collapsed\", \"auto-collapsed\", \"hidden\"]);\nconst STATS_MODES = new Set([\"tokens\", \"tokensPerSecond\"]);\nconst LOG_MODES = new Set([\"all\", \"stderr\", \"none\"]);\n\ntype TerminalPartDisplayMode = \"full\" | \"collapsed\" | \"auto-collapsed\" | \"hidden\";\ntype AssistantResponseStatsMode = \"tokens\" | \"tokensPerSecond\";\ntype LogDisplayMode = \"all\" | \"stderr\" | \"none\";\n\nfunction parsePortOption(value: string): number {\n if (!/^-?\\d+$/.test(value)) {\n throw new InvalidArgumentError(`Expected a numeric port, received \"${value}\".`);\n }\n const port = Number(value);\n if (port < 0 || port > 65_535) {\n throw new InvalidArgumentError(`Expected a port between 0 and 65535, received \"${value}\".`);\n }\n return port;\n}\n\nfunction parseDisplayMode(value: string): TerminalPartDisplayMode {\n if (!DISPLAY_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...DISPLAY_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as TerminalPartDisplayMode;\n}\n\nfunction parseStatsMode(value: string): AssistantResponseStatsMode {\n if (!STATS_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...STATS_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as AssistantResponseStatsMode;\n}\n\nfunction parseLogsMode(value: string): LogDisplayMode {\n if (!LOG_MODES.has(value)) {\n throw new InvalidArgumentError(\n `Expected one of ${[...LOG_MODES].join(\", \")}, received \"${value}\".`,\n );\n }\n return value as LogDisplayMode;\n}\n\nfunction parseContextSizeOption(value: string): number {\n const size = Number(value);\n if (!Number.isFinite(size) || size <= 0) {\n throw new InvalidArgumentError(`Expected a positive number, received \"${value}\".`);\n }\n return size;\n}\n\nfunction shouldPrintCliBootBanner(actionCommand: Command): boolean {\n const name = actionCommand.name();\n return name === \"info\" || name === \"dev\" || name === \"init\";\n}\n\nfunction createCliProgram(logger: CliLogger): Command {\n const program = new Command();\n const theme = createCliTheme();\n\n program\n .name(\"arcie\")\n .description(\"arcie — the electronic line, build agents at the speed of light\")\n .version(version())\n .showHelpAfterError()\n .exitOverride()\n .hook(\"preAction\", (_program, actionCommand) => {\n if (shouldPrintCliBootBanner(actionCommand)) {\n logger.log(arcieCliBanner());\n }\n })\n .configureOutput({\n writeErr: (message) => logger.error(message.trimEnd()),\n writeOut: (message) => logger.log(message.trimEnd()),\n });\n\n const channels = program\n .command(\"channels\")\n .description(\"Manage channels for the current agent (web UI, HTTP, etc.).\");\n\n channels\n .command(\"add <kind>\")\n .description(\"Scaffold a channel (currently supports: web).\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \".\")\n .action(async (kind: string, options: { agentDir: string }) => {\n if (kind !== \"web\") {\n logger.error(`unknown channel kind: ${kind}. supported: web`);\n process.exit(1);\n }\n const agentDir = resolvePath(process.cwd(), options.agentDir);\n const { scaffoldWebChat } = await import(\"./scaffold-web-chat\");\n try {\n const result = scaffoldWebChat(agentDir);\n if (result.alreadyExisted) {\n logger.error(`channels/web already exists at ${result.targetPath}`);\n process.exit(1);\n }\n logger.log(\n renderCliTaggedLine(theme, {\n message: `scaffolded ${result.targetPath}`,\n tag: \"channels\",\n tone: \"success\",\n }),\n );\n logger.log(\n renderCliTaggedLine(theme, {\n message: \"cd into it, then: npm install && cp .env.local.example .env.local && npm run dev\",\n tag: \"next\",\n tone: \"info\",\n }),\n );\n } catch (err) {\n logger.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n program\n .command(\"init [target]\")\n .description(\"Create a new arcie agent, or add one to an existing project directory.\")\n .option(\"--template <name>\", \"Template to use (default, agent-only)\", \"default\")\n .option(\"-y, --yes\", \"Accepted for compatibility; has no effect\")\n .action(async (target: string | undefined, options: { template: string; yes?: boolean }) => {\n if (options.yes) logger.error(\"warning: --yes has no effect for arcie init.\");\n const { initCommand } = await import(\"./init\");\n await initCommand(target, { template: options.template });\n });\n\n program\n .command(\"build\")\n .description(\"Compile the agent for production.\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \"agent\")\n .option(\"--out-dir <path>\", \"Output directory\", \".arcie\")\n .action(async (options: { agentDir: string; outDir: string }) => {\n const { buildCommand } = await import(\"./build\");\n await buildCommand(options);\n logger.log(\n renderCliTaggedLine(theme, {\n message: `output at ${options.outDir}`,\n tag: \"build\",\n tone: \"success\",\n }),\n );\n });\n\n program\n .command(\"dev\")\n .description(\"Start the arcie development server or attach an interactive UI.\")\n .option(\"-p, --port <port>\", \"Port to listen on\", parsePortOption, 3000)\n .option(\"--host <host>\", \"Host interface to bind\")\n .option(\"--agent-dir <path>\", \"Path to agent directory\", \"agent\")\n .option(\"--input <text>\", \"Pre-fill the prompt input, or start onboarding with /model\")\n .option(\"--no-ui\", \"Start the server without an interactive UI\")\n .option(\"--name <name>\", \"Title shown in the terminal UI (defaults to the app folder name)\")\n .option(\n \"--tools <mode>\",\n \"How tool calls render: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--reasoning <mode>\",\n \"How reasoning renders: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--subagents <mode>\",\n \"How subagent sections render: full | collapsed | auto-collapsed | hidden\",\n parseDisplayMode,\n )\n .option(\n \"--assistant-response-stats <mode>\",\n \"Assistant header statistic: tokens | tokensPerSecond\",\n parseStatsMode,\n )\n .option(\n \"--context-size <tokens>\",\n \"Model context window size, shown as a usage percentage\",\n parseContextSizeOption,\n )\n .option(\"--logs <mode>\", \"Which logs to show: all | stderr | none\", parseLogsMode)\n .option(\"--no-web\", \"Do not auto-start the channels/web/ dev server\")\n .option(\"--no-open\", \"Do not auto-open the browser at the web channel URL\")\n .action(async (options) => {\n const { devCommand } = await import(\"./dev\");\n await devCommand({\n port: String(options.port ?? 3000),\n agentDir: options.agentDir,\n input: options.ui === false ? false : Boolean(options.input),\n noWeb: options.web === false,\n noOpen: options.open === false,\n });\n });\n\n return program;\n}\n\nconst KNOWN_COMMANDS = new Set([\"channels\", \"init\", \"build\", \"dev\", \"help\"]);\n\nfunction resolveArgv(argv: readonly string[]): string[] {\n if (argv.length === 0) return [\"dev\"];\n const first = argv[0]!;\n if (first === \"-h\" || first === \"--help\" || first === \"-V\" || first === \"--version\") {\n return [...argv];\n }\n if (first.startsWith(\"-\")) return [...argv];\n if (KNOWN_COMMANDS.has(first)) return [...argv];\n // Bare positional like `arcie my-agent` — treat as `arcie init my-agent`.\n return [\"init\", ...argv];\n}\n\nexport async function runCli(\n argv: string[] = process.argv.slice(2),\n logger: CliLogger = console,\n): Promise<void> {\n const program = createCliProgram(logger);\n const input = resolveArgv(argv);\n\n try {\n await program.parseAsync(input, { from: \"user\" });\n } catch (error) {\n if (error instanceof CommanderError) {\n if (error.exitCode === 0) return;\n throw new Error(error.message);\n }\n throw error;\n }\n}\n\nrunCli().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
} from "./chunk-SGWQZZ2A.js";
|
|
26
26
|
import {
|
|
27
27
|
streamAgent
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-3R65GQAE.js";
|
|
29
29
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
discoverAgents,
|
|
31
|
+
loadAgent,
|
|
32
|
+
loadAgentById
|
|
33
|
+
} from "./chunk-XZPC3JSU.js";
|
|
32
34
|
import {
|
|
33
35
|
discoverAgent
|
|
34
36
|
} from "./chunk-6XETPLIF.js";
|
|
@@ -36,8 +38,10 @@ import "./chunk-QE46QFID.js";
|
|
|
36
38
|
import "./chunk-PHTJLJOV.js";
|
|
37
39
|
|
|
38
40
|
// src/cli/dev.ts
|
|
41
|
+
import { spawn } from "child_process";
|
|
39
42
|
import { createServer } from "http";
|
|
40
|
-
import {
|
|
43
|
+
import { existsSync as existsSync2 } from "fs";
|
|
44
|
+
import { join as join2, resolve } from "path";
|
|
41
45
|
|
|
42
46
|
// src/cli/tui/renderer/start-block-chat.ts
|
|
43
47
|
import { watch } from "fs";
|
|
@@ -2128,42 +2132,165 @@ async function listenWithFallback(server, startPort) {
|
|
|
2128
2132
|
`Could not find a free port in ${startPort}..${startPort + MAX_PORT_ATTEMPTS - 1}`
|
|
2129
2133
|
);
|
|
2130
2134
|
}
|
|
2135
|
+
function isPortFree(port) {
|
|
2136
|
+
return new Promise((resolve2) => {
|
|
2137
|
+
const probe = createServer();
|
|
2138
|
+
probe.once("error", () => resolve2(false));
|
|
2139
|
+
probe.once("listening", () => {
|
|
2140
|
+
probe.close(() => resolve2(true));
|
|
2141
|
+
});
|
|
2142
|
+
probe.listen(port);
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
async function findFreePort(startPort, maxAttempts = MAX_PORT_ATTEMPTS) {
|
|
2146
|
+
for (let offset = 0; offset < maxAttempts; offset += 1) {
|
|
2147
|
+
const port = startPort + offset;
|
|
2148
|
+
if (await isPortFree(port)) return port;
|
|
2149
|
+
}
|
|
2150
|
+
throw new Error(`No free port in ${startPort}..${startPort + maxAttempts - 1}`);
|
|
2151
|
+
}
|
|
2152
|
+
function openBrowser(url) {
|
|
2153
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
2154
|
+
try {
|
|
2155
|
+
const child = spawn(command, [url], {
|
|
2156
|
+
detached: true,
|
|
2157
|
+
stdio: "ignore",
|
|
2158
|
+
shell: process.platform === "win32"
|
|
2159
|
+
});
|
|
2160
|
+
child.unref();
|
|
2161
|
+
} catch {
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
async function waitForHttp(url, timeoutMs = 3e4) {
|
|
2165
|
+
const deadline = Date.now() + timeoutMs;
|
|
2166
|
+
while (Date.now() < deadline) {
|
|
2167
|
+
try {
|
|
2168
|
+
const res = await fetch(url, { method: "GET" });
|
|
2169
|
+
if (res.status < 500) return true;
|
|
2170
|
+
} catch {
|
|
2171
|
+
}
|
|
2172
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2173
|
+
}
|
|
2174
|
+
return false;
|
|
2175
|
+
}
|
|
2176
|
+
async function installWebDeps(webDir) {
|
|
2177
|
+
return new Promise((resolve2) => {
|
|
2178
|
+
const child = spawn("npm", ["install", "--no-fund", "--no-audit"], {
|
|
2179
|
+
cwd: webDir,
|
|
2180
|
+
stdio: "ignore"
|
|
2181
|
+
});
|
|
2182
|
+
child.once("exit", (code) => resolve2(code === 0));
|
|
2183
|
+
child.once("error", () => resolve2(false));
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
async function startWebChannel(agentDir, arcieUrl, webPort) {
|
|
2187
|
+
const webDir = join2(agentDir, "channels", "web");
|
|
2188
|
+
if (!existsSync2(join2(webDir, "package.json"))) return void 0;
|
|
2189
|
+
if (!existsSync2(join2(webDir, "node_modules"))) {
|
|
2190
|
+
console.log(` ${dimmed(`web installing channels/web deps (first run)\u2026`)}`);
|
|
2191
|
+
const installed = await installWebDeps(webDir);
|
|
2192
|
+
if (!installed) {
|
|
2193
|
+
console.log();
|
|
2194
|
+
console.log(` ${grey("\u26A0")} channels/web install failed \u2014 try manually:`);
|
|
2195
|
+
console.log(` ${dimmed(` cd ${webDir} && npm install`)}`);
|
|
2196
|
+
console.log();
|
|
2197
|
+
return void 0;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
const child = spawn("npm", ["run", "dev", "--", "--port", String(webPort)], {
|
|
2201
|
+
cwd: webDir,
|
|
2202
|
+
env: { ...process.env, ARCIE_URL: arcieUrl },
|
|
2203
|
+
stdio: "ignore",
|
|
2204
|
+
detached: false
|
|
2205
|
+
});
|
|
2206
|
+
const url = `http://localhost:${webPort}`;
|
|
2207
|
+
const ready = await waitForHttp(url, 45e3);
|
|
2208
|
+
if (!ready) {
|
|
2209
|
+
console.log();
|
|
2210
|
+
console.log(` ${grey("\u26A0")} channels/web didn't come up within 45s`);
|
|
2211
|
+
child.kill();
|
|
2212
|
+
return void 0;
|
|
2213
|
+
}
|
|
2214
|
+
return { url, process: child };
|
|
2215
|
+
}
|
|
2131
2216
|
async function devCommand(options) {
|
|
2132
2217
|
const agentDirPath = resolve(process.cwd(), options.agentDir);
|
|
2133
2218
|
const requestedPort = parseInt(options.port, 10);
|
|
2219
|
+
const streamTurn = async (res, body, agentId) => {
|
|
2220
|
+
try {
|
|
2221
|
+
const { message, stream } = JSON.parse(body);
|
|
2222
|
+
if (typeof message !== "string" || message.length === 0) {
|
|
2223
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2224
|
+
res.end(JSON.stringify({ error: "message is required" }));
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
if (stream) {
|
|
2228
|
+
res.writeHead(200, {
|
|
2229
|
+
"Content-Type": "application/x-ndjson",
|
|
2230
|
+
"Cache-Control": "no-cache",
|
|
2231
|
+
Connection: "keep-alive"
|
|
2232
|
+
});
|
|
2233
|
+
const runOpts = agentId !== void 0 ? { agentId } : {};
|
|
2234
|
+
for await (const event of streamAgent(agentDirPath, message, runOpts)) {
|
|
2235
|
+
res.write(JSON.stringify(event) + "\n");
|
|
2236
|
+
}
|
|
2237
|
+
res.end();
|
|
2238
|
+
} else {
|
|
2239
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2240
|
+
const runOpts = agentId !== void 0 ? { agentId } : {};
|
|
2241
|
+
for await (const _event of streamAgent(agentDirPath, message, runOpts)) {
|
|
2242
|
+
}
|
|
2243
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
2244
|
+
}
|
|
2245
|
+
} catch (err) {
|
|
2246
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2247
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
const listAgents = async () => {
|
|
2251
|
+
const discovered = discoverAgents(agentDirPath);
|
|
2252
|
+
const summaries = await Promise.all(
|
|
2253
|
+
discovered.map(async ({ id }) => {
|
|
2254
|
+
try {
|
|
2255
|
+
const loaded = await loadAgentById(agentDirPath, id);
|
|
2256
|
+
const { config } = loaded.manifest;
|
|
2257
|
+
return {
|
|
2258
|
+
id,
|
|
2259
|
+
name: config.name ?? id,
|
|
2260
|
+
model: config.model,
|
|
2261
|
+
description: config.description ?? ""
|
|
2262
|
+
};
|
|
2263
|
+
} catch {
|
|
2264
|
+
return { id, name: id, model: "", description: "" };
|
|
2265
|
+
}
|
|
2266
|
+
})
|
|
2267
|
+
);
|
|
2268
|
+
return summaries;
|
|
2269
|
+
};
|
|
2134
2270
|
const server = createServer(async (req, res) => {
|
|
2135
|
-
if (await handleSessionsRequest(req, res))
|
|
2271
|
+
if (await handleSessionsRequest(req, res)) return;
|
|
2272
|
+
const method = req.method ?? "GET";
|
|
2273
|
+
const url = req.url ?? "/";
|
|
2274
|
+
if (method === "GET" && url === "/agents") {
|
|
2275
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2276
|
+
res.end(JSON.stringify(await listAgents()));
|
|
2136
2277
|
return;
|
|
2137
2278
|
}
|
|
2138
|
-
|
|
2279
|
+
const agentsMatch = url.match(/^\/agents\/([^/?]+)(?:\?.*)?$/);
|
|
2280
|
+
if (method === "POST" && agentsMatch !== null) {
|
|
2139
2281
|
let body = "";
|
|
2140
2282
|
for await (const chunk of req) body += chunk;
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
if (stream) {
|
|
2144
|
-
res.writeHead(200, {
|
|
2145
|
-
"Content-Type": "application/x-ndjson",
|
|
2146
|
-
"Cache-Control": "no-cache",
|
|
2147
|
-
Connection: "keep-alive"
|
|
2148
|
-
});
|
|
2149
|
-
for await (const event of streamAgent(agentDirPath, message)) {
|
|
2150
|
-
res.write(JSON.stringify(event) + "\n");
|
|
2151
|
-
}
|
|
2152
|
-
res.end();
|
|
2153
|
-
} else {
|
|
2154
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2155
|
-
for await (const _event of streamAgent(agentDirPath, message)) {
|
|
2156
|
-
}
|
|
2157
|
-
res.end(JSON.stringify({ status: "ok" }));
|
|
2158
|
-
}
|
|
2159
|
-
} catch (err) {
|
|
2160
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2161
|
-
res.end(JSON.stringify({ error: String(err) }));
|
|
2162
|
-
}
|
|
2163
|
-
} else {
|
|
2164
|
-
res.writeHead(404);
|
|
2165
|
-
res.end("Not found");
|
|
2283
|
+
await streamTurn(res, body, decodeURIComponent(agentsMatch[1]));
|
|
2284
|
+
return;
|
|
2166
2285
|
}
|
|
2286
|
+
if (method === "POST" && url === "/") {
|
|
2287
|
+
let body = "";
|
|
2288
|
+
for await (const chunk of req) body += chunk;
|
|
2289
|
+
await streamTurn(res, body, void 0);
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
res.writeHead(404);
|
|
2293
|
+
res.end("Not found");
|
|
2167
2294
|
});
|
|
2168
2295
|
let boundPort;
|
|
2169
2296
|
try {
|
|
@@ -2200,25 +2327,50 @@ async function devCommand(options) {
|
|
|
2200
2327
|
);
|
|
2201
2328
|
console.log();
|
|
2202
2329
|
}
|
|
2203
|
-
console.log(` ${dimmed(`http://localhost:${boundPort}`)}`);
|
|
2204
|
-
console.log();
|
|
2205
|
-
console.log(` ${dimmed(`$ curl -X POST http://localhost:${boundPort} \\`)}`);
|
|
2206
|
-
console.log(` ${dimmed(` -H "Content-Type: application/json" \\`)}`);
|
|
2207
|
-
console.log(` ${dimmed(` -d '{"message": "hello"}'`)}`);
|
|
2208
|
-
console.log();
|
|
2330
|
+
console.log(` ${dimmed(`agent http://localhost:${boundPort}`)}`);
|
|
2209
2331
|
const missing = checkProviderKeys(agent.manifest.config.model);
|
|
2210
2332
|
if (missing.length > 0) {
|
|
2333
|
+
console.log();
|
|
2211
2334
|
console.log(` ${grey("\u26A0")} Missing API keys: ${missing.join(", ")}`);
|
|
2212
2335
|
console.log(` ${dimmed(" Set them in .env.local or your environment")}`);
|
|
2213
|
-
console.log();
|
|
2214
2336
|
}
|
|
2215
2337
|
} catch {
|
|
2216
2338
|
console.log(` ${agentDirPath}`);
|
|
2217
2339
|
console.log();
|
|
2218
|
-
console.log(` ${dimmed(`http://localhost:${boundPort}`)}`);
|
|
2219
|
-
|
|
2340
|
+
console.log(` ${dimmed(`agent http://localhost:${boundPort}`)}`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
let webChannel;
|
|
2344
|
+
if (!options.input && options.noWeb !== true) {
|
|
2345
|
+
const webDir = join2(agentDirPath, "channels", "web");
|
|
2346
|
+
if (existsSync2(webDir)) {
|
|
2347
|
+
try {
|
|
2348
|
+
const webPort = await findFreePort(3001);
|
|
2349
|
+
console.log(` ${dimmed(`web starting on http://localhost:${webPort}\u2026`)}`);
|
|
2350
|
+
webChannel = await startWebChannel(agentDirPath, `http://localhost:${boundPort}`, webPort);
|
|
2351
|
+
if (webChannel !== void 0) {
|
|
2352
|
+
console.log(` ${dimmed(`web http://localhost:${webPort}`)}`);
|
|
2353
|
+
if (options.noOpen !== true) openBrowser(webChannel.url);
|
|
2354
|
+
}
|
|
2355
|
+
} catch (err) {
|
|
2356
|
+
console.log(
|
|
2357
|
+
` ${grey("\u26A0")} could not start web channel: ${err instanceof Error ? err.message : String(err)}`
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2220
2360
|
}
|
|
2221
2361
|
}
|
|
2362
|
+
if (!options.input) {
|
|
2363
|
+
console.log();
|
|
2364
|
+
console.log(` ${dimmed("Ctrl+C to stop")}`);
|
|
2365
|
+
console.log();
|
|
2366
|
+
}
|
|
2367
|
+
const shutdown = () => {
|
|
2368
|
+
if (webChannel !== void 0) webChannel.process.kill();
|
|
2369
|
+
server.close();
|
|
2370
|
+
process.exit(0);
|
|
2371
|
+
};
|
|
2372
|
+
process.once("SIGINT", shutdown);
|
|
2373
|
+
process.once("SIGTERM", shutdown);
|
|
2222
2374
|
if (options.input) {
|
|
2223
2375
|
void startBlockChat({ agentDir: agentDirPath });
|
|
2224
2376
|
}
|
|
@@ -2226,4 +2378,4 @@ async function devCommand(options) {
|
|
|
2226
2378
|
export {
|
|
2227
2379
|
devCommand
|
|
2228
2380
|
};
|
|
2229
|
-
//# sourceMappingURL=dev-
|
|
2381
|
+
//# sourceMappingURL=dev-XBXOVOVE.js.map
|