@praesidia/neurogent 0.1.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/chunk-JBDXA3BS.js +214 -0
- package/dist/chunk-VPHKQCPP.js +49 -0
- package/dist/chunk-ZC65T52L.js +255 -0
- package/dist/chunk-ZTZVL6N5.js +108 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +519 -0
- package/dist/index-BW9fPh3v.d.ts +372 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +385 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.js +8 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.js +889 -0
- package/examples/dev-trio-openai.yaml +42 -0
- package/examples/dev-trio.yaml +42 -0
- package/examples/full-team.yaml +170 -0
- package/examples/marketing-team.yaml +190 -0
- package/examples/solo-researcher.yaml +27 -0
- package/package.json +65 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
compileToAgentCard,
|
|
4
|
+
createAgentServer,
|
|
5
|
+
parseAgentConfig
|
|
6
|
+
} from "../chunk-JBDXA3BS.js";
|
|
7
|
+
import {
|
|
8
|
+
ShellYamlSchema
|
|
9
|
+
} from "../chunk-VPHKQCPP.js";
|
|
10
|
+
import {
|
|
11
|
+
clearRuntime,
|
|
12
|
+
loadRuntime,
|
|
13
|
+
pingAgent,
|
|
14
|
+
saveRuntime
|
|
15
|
+
} from "../chunk-ZC65T52L.js";
|
|
16
|
+
|
|
17
|
+
// src/cli/index.ts
|
|
18
|
+
import { Command as Command9 } from "commander";
|
|
19
|
+
|
|
20
|
+
// src/cli/commands/init.ts
|
|
21
|
+
import { Command } from "commander";
|
|
22
|
+
import fs from "fs-extra";
|
|
23
|
+
import * as path from "path";
|
|
24
|
+
import chalk from "chalk";
|
|
25
|
+
import { fileURLToPath } from "url";
|
|
26
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
var __dirname = path.dirname(__filename);
|
|
28
|
+
var initCommand = new Command("init").description("Scaffold a new Neuro agent project").argument("<project-name>", "Name of the project directory").option("--template <template>", "Template to use", "ts-basic").action(async (projectName, options) => {
|
|
29
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
30
|
+
const templateDir = path.resolve(__dirname, "../../../templates", options.template);
|
|
31
|
+
console.log(chalk.blue(`[Neuro] Initializing agent ${projectName} using template ${options.template}...`));
|
|
32
|
+
try {
|
|
33
|
+
if (fs.existsSync(targetDir)) {
|
|
34
|
+
console.error(chalk.red(`Error: Directory ${projectName} already exists.`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
await fs.ensureDir(targetDir);
|
|
38
|
+
if (fs.existsSync(templateDir)) {
|
|
39
|
+
await fs.copy(templateDir, targetDir);
|
|
40
|
+
} else {
|
|
41
|
+
console.warn(chalk.yellow("Template dir not found, scaffolding bare minimum for demonstration."));
|
|
42
|
+
await fs.writeFile(path.join(targetDir, "neuro.agent.yaml"), `name: ${projectName}\\nversion: 1.0.0\\ndescription: An A2A agent\\nauthor: Acme\\nlicense: MIT\\ncapabilities: [\\"chat\\"]\\nmodel:\\n provider: dummy\\n name: default`);
|
|
43
|
+
await fs.mkdirp(path.join(targetDir, "src"));
|
|
44
|
+
await fs.writeFile(path.join(targetDir, "src/index.ts"), `import { createAgent } from '@praesidia/neuro';\\n\\nconst agent = createAgent({ config: './neuro.agent.yaml' });\\nagent.start();\\n`);
|
|
45
|
+
await fs.writeFile(path.join(targetDir, "package.json"), JSON.stringify({ name: projectName, type: "module", scripts: { dev: "tsx src/index.ts" } }, null, 2));
|
|
46
|
+
}
|
|
47
|
+
console.log(chalk.green(`\\nSuccess! Created ${projectName} at ${targetDir}`));
|
|
48
|
+
console.log(`\\nNext steps:\\n cd ${projectName}\\n pnpm install\\n pnpm dev`);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(chalk.red(`Initialization failed: ${err.message}`));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// src/cli/commands/dev.ts
|
|
56
|
+
import { Command as Command2 } from "commander";
|
|
57
|
+
import chalk2 from "chalk";
|
|
58
|
+
import { spawn } from "child_process";
|
|
59
|
+
import * as path2 from "path";
|
|
60
|
+
import * as fs2 from "fs";
|
|
61
|
+
var devCommand = new Command2("dev").description("Start local A2A server with hot reload").option("--port <port>", "Port to listen on", "8080").action(async (options) => {
|
|
62
|
+
console.log(chalk2.blue(`[Neuro] Starting dev server on port ${options.port}...`));
|
|
63
|
+
const entryPath = path2.resolve(process.cwd(), "src/index.ts");
|
|
64
|
+
if (!fs2.existsSync(entryPath)) {
|
|
65
|
+
console.error(chalk2.red(`Error: entry file not found at ${entryPath}`));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const runner = spawn("npx", ["tsx", "watch", "src/index.ts"], {
|
|
69
|
+
stdio: "inherit",
|
|
70
|
+
env: { ...process.env, PORT: options.port }
|
|
71
|
+
});
|
|
72
|
+
runner.on("close", (code) => {
|
|
73
|
+
console.log(chalk2.yellow(`[Neuro] Dev server exited with code ${code}`));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/cli/commands/build.ts
|
|
78
|
+
import { Command as Command3 } from "commander";
|
|
79
|
+
import * as fs3 from "fs-extra";
|
|
80
|
+
import * as path3 from "path";
|
|
81
|
+
import * as crypto from "crypto";
|
|
82
|
+
import chalk3 from "chalk";
|
|
83
|
+
var buildCommand = new Command3("build").description("Validate config and generate AgentCard").option("--out-dir <dir>", "Output directory", "dist").action(async (options) => {
|
|
84
|
+
console.log(chalk3.blue("[Neuro] Building AgentCard..."));
|
|
85
|
+
const configPath = path3.resolve(process.cwd(), "neuro.agent.yaml");
|
|
86
|
+
if (!fs3.existsSync(configPath)) {
|
|
87
|
+
console.error(chalk3.red(`Error: Could not find neuro.agent.yaml at ${configPath}`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const rawYaml = await fs3.readFile(configPath, "utf-8");
|
|
92
|
+
const config = parseAgentConfig(rawYaml);
|
|
93
|
+
let policyHash;
|
|
94
|
+
const policyPath = path3.resolve(process.cwd(), "praesidia.policy.yaml");
|
|
95
|
+
if (fs3.existsSync(policyPath)) {
|
|
96
|
+
const policyContent = await fs3.readFile(policyPath, "utf-8");
|
|
97
|
+
policyHash = crypto.createHash("sha256").update(policyContent).digest("hex");
|
|
98
|
+
console.log(chalk3.dim(`[Neuro] Policy hash (sha256): ${policyHash}`));
|
|
99
|
+
}
|
|
100
|
+
const agentCard = compileToAgentCard(config, policyHash);
|
|
101
|
+
const outDir = path3.resolve(process.cwd(), options.outDir);
|
|
102
|
+
await fs3.ensureDir(path3.join(outDir, ".well-known"));
|
|
103
|
+
const outPath = path3.join(outDir, ".well-known", "agent.json");
|
|
104
|
+
await fs3.writeFile(outPath, JSON.stringify(agentCard, null, 2));
|
|
105
|
+
console.log(chalk3.green(`
|
|
106
|
+
\u2713 AgentCard \u2192 ${outPath}`));
|
|
107
|
+
console.log(chalk3.dim(` name: ${config.name} version: ${config.version} capabilities: ${config.capabilities.join(", ")}`));
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(chalk3.red(`Build failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// src/cli/commands/deploy.ts
|
|
115
|
+
import { Command as Command4 } from "commander";
|
|
116
|
+
import fs4 from "fs-extra";
|
|
117
|
+
import * as path4 from "path";
|
|
118
|
+
import chalk4 from "chalk";
|
|
119
|
+
var deployCommand = new Command4("deploy").description("Generate production Docker artifacts for your Neuro agent").option("-c, --config <path>", "Path to neuro.agent.yaml", "neuro.agent.yaml").option("-p, --port <port>", "Port the agent listens on", "8080").option("--compose", "Also generate a docker-compose.yml").action(async (options) => {
|
|
120
|
+
const configPath = path4.resolve(process.cwd(), options.config);
|
|
121
|
+
if (!fs4.existsSync(configPath)) {
|
|
122
|
+
console.error(chalk4.red(`Error: config not found at ${configPath}`));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
let config;
|
|
126
|
+
try {
|
|
127
|
+
const rawYaml = await fs4.readFile(configPath, "utf-8");
|
|
128
|
+
config = parseAgentConfig(rawYaml);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error(chalk4.red(`Failed to parse config: ${err instanceof Error ? err.message : String(err)}`));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
const imageName = config.name.toLowerCase().replace(/\s+/g, "-");
|
|
134
|
+
const port = options.port;
|
|
135
|
+
const dockerfile = `# syntax=docker/dockerfile:1
|
|
136
|
+
# \u2500\u2500 Stage 1: build \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
137
|
+
FROM node:20-alpine AS builder
|
|
138
|
+
|
|
139
|
+
WORKDIR /app
|
|
140
|
+
|
|
141
|
+
COPY package*.json ./
|
|
142
|
+
RUN npm ci --ignore-scripts
|
|
143
|
+
|
|
144
|
+
COPY tsconfig*.json ./
|
|
145
|
+
COPY src ./src
|
|
146
|
+
COPY neuro.agent.yaml ./
|
|
147
|
+
|
|
148
|
+
RUN npm run build
|
|
149
|
+
|
|
150
|
+
# \u2500\u2500 Stage 2: runtime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
151
|
+
FROM node:20-alpine AS runtime
|
|
152
|
+
|
|
153
|
+
ENV NODE_ENV=production
|
|
154
|
+
ENV PORT=${port}
|
|
155
|
+
|
|
156
|
+
WORKDIR /app
|
|
157
|
+
|
|
158
|
+
COPY package*.json ./
|
|
159
|
+
RUN npm ci --omit=dev --ignore-scripts
|
|
160
|
+
|
|
161
|
+
COPY --from=builder /app/dist ./dist
|
|
162
|
+
COPY neuro.agent.yaml ./
|
|
163
|
+
|
|
164
|
+
EXPOSE ${port}
|
|
165
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \\
|
|
166
|
+
CMD wget -qO- http://localhost:${port}/.well-known/agent.json || exit 1
|
|
167
|
+
|
|
168
|
+
CMD ["node", "dist/index.js"]
|
|
169
|
+
`;
|
|
170
|
+
const dockerignore = `node_modules
|
|
171
|
+
dist
|
|
172
|
+
.neuro
|
|
173
|
+
*.log
|
|
174
|
+
.env
|
|
175
|
+
.env.*
|
|
176
|
+
!.env.example
|
|
177
|
+
.git
|
|
178
|
+
.gitignore
|
|
179
|
+
README.md
|
|
180
|
+
`;
|
|
181
|
+
const compose = `services:
|
|
182
|
+
${imageName}:
|
|
183
|
+
build: .
|
|
184
|
+
image: ${imageName}:latest
|
|
185
|
+
ports:
|
|
186
|
+
- "${port}:${port}"
|
|
187
|
+
environment:
|
|
188
|
+
- NODE_ENV=production
|
|
189
|
+
- PORT=${port}
|
|
190
|
+
# Add your provider key:
|
|
191
|
+
# - OPENAI_API_KEY=\${OPENAI_API_KEY}
|
|
192
|
+
# - ANTHROPIC_API_KEY=\${ANTHROPIC_API_KEY}
|
|
193
|
+
restart: unless-stopped
|
|
194
|
+
healthcheck:
|
|
195
|
+
test: ["CMD", "wget", "-qO-", "http://localhost:${port}/.well-known/agent.json"]
|
|
196
|
+
interval: 30s
|
|
197
|
+
timeout: 5s
|
|
198
|
+
retries: 3
|
|
199
|
+
`;
|
|
200
|
+
const cwd = process.cwd();
|
|
201
|
+
await fs4.writeFile(path4.join(cwd, "Dockerfile"), dockerfile);
|
|
202
|
+
console.log(chalk4.green(`\u2713 Dockerfile`));
|
|
203
|
+
await fs4.writeFile(path4.join(cwd, ".dockerignore"), dockerignore);
|
|
204
|
+
console.log(chalk4.green(`\u2713 .dockerignore`));
|
|
205
|
+
if (options.compose) {
|
|
206
|
+
await fs4.writeFile(path4.join(cwd, "docker-compose.yml"), compose);
|
|
207
|
+
console.log(chalk4.green(`\u2713 docker-compose.yml`));
|
|
208
|
+
}
|
|
209
|
+
console.log(chalk4.blue(`
|
|
210
|
+
[Neuro] Artifacts generated for ${chalk4.bold(config.name)} v${config.version}
|
|
211
|
+
`));
|
|
212
|
+
console.log("Build and run:");
|
|
213
|
+
console.log(chalk4.dim(` docker build -t ${imageName} .`));
|
|
214
|
+
console.log(chalk4.dim(` docker run -p ${port}:${port} -e OPENAI_API_KEY=sk-... ${imageName}`));
|
|
215
|
+
if (options.compose) {
|
|
216
|
+
console.log("\nOr with Compose:");
|
|
217
|
+
console.log(chalk4.dim(` docker compose up --build`));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// src/cli/commands/register.ts
|
|
222
|
+
import { Command as Command5 } from "commander";
|
|
223
|
+
import fs5 from "fs-extra";
|
|
224
|
+
import * as path5 from "path";
|
|
225
|
+
import chalk5 from "chalk";
|
|
226
|
+
var registerCommand = new Command5("register").description("Publish your AgentCard to an A2A directory registry").option("-c, --config <path>", "Path to neuro.agent.yaml", "neuro.agent.yaml").option("-r, --registry <url>", "A2A registry base URL", "https://registry.a2a.dev").option("--dry-run", "Validate and print the AgentCard without publishing").action(async (options) => {
|
|
227
|
+
const configPath = path5.resolve(process.cwd(), options.config);
|
|
228
|
+
if (!fs5.existsSync(configPath)) {
|
|
229
|
+
console.error(chalk5.red(`Error: config not found at ${configPath}`));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
let config;
|
|
233
|
+
try {
|
|
234
|
+
const rawYaml = await fs5.readFile(configPath, "utf-8");
|
|
235
|
+
config = parseAgentConfig(rawYaml);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.error(chalk5.red(`Failed to parse config: ${err instanceof Error ? err.message : String(err)}`));
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
const distCardPath = path5.resolve(process.cwd(), "dist", ".well-known", "agent.json");
|
|
241
|
+
let agentCard;
|
|
242
|
+
if (fs5.existsSync(distCardPath)) {
|
|
243
|
+
agentCard = await fs5.readJson(distCardPath);
|
|
244
|
+
console.log(chalk5.dim(`[Neuro] Using built AgentCard from ${distCardPath}`));
|
|
245
|
+
} else {
|
|
246
|
+
agentCard = compileToAgentCard(config);
|
|
247
|
+
console.log(chalk5.yellow("[Neuro] No dist/ found \u2014 run `neuro build` first for production. Using compiled card."));
|
|
248
|
+
}
|
|
249
|
+
console.log(chalk5.blue(`
|
|
250
|
+
[Neuro] AgentCard for ${chalk5.bold(config.name)}:`));
|
|
251
|
+
console.log(chalk5.dim(JSON.stringify(agentCard, null, 2)));
|
|
252
|
+
if (options.dryRun) {
|
|
253
|
+
console.log(chalk5.cyan("\n[Neuro] Dry run complete. No data was sent."));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const registryUrl = options.registry.replace(/\/$/, "");
|
|
257
|
+
const publishUrl = `${registryUrl}/api/v1/agents/publish`;
|
|
258
|
+
console.log(chalk5.blue(`
|
|
259
|
+
[Neuro] Publishing to ${publishUrl}...`));
|
|
260
|
+
let responseData;
|
|
261
|
+
try {
|
|
262
|
+
const res = await fetch(publishUrl, {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: { "Content-Type": "application/json" },
|
|
265
|
+
body: JSON.stringify(agentCard),
|
|
266
|
+
signal: AbortSignal.timeout(15e3)
|
|
267
|
+
});
|
|
268
|
+
if (!res.ok) {
|
|
269
|
+
const body = await res.text();
|
|
270
|
+
throw new Error(`Registry returned ${res.status}: ${body}`);
|
|
271
|
+
}
|
|
272
|
+
responseData = await res.json();
|
|
273
|
+
} catch (err) {
|
|
274
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
275
|
+
console.error(chalk5.red(`
|
|
276
|
+
[Neuro] Registration failed: ${msg}`));
|
|
277
|
+
console.error(chalk5.dim("Tip: Use --dry-run to validate your AgentCard without publishing."));
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
const neuroDir = path5.resolve(process.cwd(), ".neuro");
|
|
281
|
+
const registrationPath = path5.join(neuroDir, "registration.json");
|
|
282
|
+
await fs5.ensureDir(neuroDir);
|
|
283
|
+
const record = {
|
|
284
|
+
agentName: config.name,
|
|
285
|
+
registry: registryUrl,
|
|
286
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
287
|
+
agentCardUrl: `${registryUrl}/agents/${config.name.toLowerCase().replace(/\s+/g, "-")}`,
|
|
288
|
+
raw: responseData
|
|
289
|
+
};
|
|
290
|
+
await fs5.writeJson(registrationPath, record, { spaces: 2 });
|
|
291
|
+
console.log(chalk5.green(`
|
|
292
|
+
\u2713 ${config.name} registered successfully.`));
|
|
293
|
+
console.log(` Registry: ${chalk5.cyan(registryUrl)}`);
|
|
294
|
+
console.log(` AgentCard: ${chalk5.cyan(record.agentCardUrl)}`);
|
|
295
|
+
console.log(chalk5.dim(` Registration saved to ${registrationPath}`));
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// src/cli/commands/start.ts
|
|
299
|
+
import { Command as Command6 } from "commander";
|
|
300
|
+
import * as fs6 from "fs";
|
|
301
|
+
import * as path6 from "path";
|
|
302
|
+
import * as yaml from "js-yaml";
|
|
303
|
+
import chalk6 from "chalk";
|
|
304
|
+
var CONFIG_SEARCH = ["neurogent-shell.yaml", "neurogent-shell.yml", ".neurogent-shell.yaml"];
|
|
305
|
+
function findConfig(explicit) {
|
|
306
|
+
if (explicit) {
|
|
307
|
+
const resolved = path6.resolve(explicit);
|
|
308
|
+
if (!fs6.existsSync(resolved)) throw new Error(`Config not found: ${resolved}`);
|
|
309
|
+
return resolved;
|
|
310
|
+
}
|
|
311
|
+
for (const name of CONFIG_SEARCH) {
|
|
312
|
+
const resolved = path6.resolve(name);
|
|
313
|
+
if (fs6.existsSync(resolved)) return resolved;
|
|
314
|
+
}
|
|
315
|
+
throw new Error("No config found. Use --config <file> or create neurogent-shell.yaml");
|
|
316
|
+
}
|
|
317
|
+
var startCommand = new Command6("start").description("Start persistent ZeroClaw agent servers from a config file").option("-c, --config <path>", "Path to YAML config file").option("-p, --base-port <number>", "Starting port (default: 4100)", "4100").action(async (opts) => {
|
|
318
|
+
const basePort = parseInt(opts.basePort, 10);
|
|
319
|
+
let configPath;
|
|
320
|
+
try {
|
|
321
|
+
configPath = findConfig(opts.config);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
console.error(chalk6.red(err.message));
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
const raw = yaml.load(fs6.readFileSync(configPath, "utf-8"));
|
|
327
|
+
const validated = ShellYamlSchema.parse(raw);
|
|
328
|
+
const globalModel = validated.model ? {
|
|
329
|
+
provider: validated.model.provider,
|
|
330
|
+
name: validated.model.name,
|
|
331
|
+
maxTokens: validated.model.max_tokens,
|
|
332
|
+
temperature: validated.model.temperature,
|
|
333
|
+
baseUrl: validated.model.base_url
|
|
334
|
+
} : void 0;
|
|
335
|
+
const agents = validated.agents.map((a) => ({
|
|
336
|
+
id: a.id,
|
|
337
|
+
name: a.name,
|
|
338
|
+
role: a.role,
|
|
339
|
+
emoji: a.emoji,
|
|
340
|
+
inkColor: a.color,
|
|
341
|
+
expertise: a.expertise,
|
|
342
|
+
systemPrompt: a.system_prompt,
|
|
343
|
+
model: a.model ? {
|
|
344
|
+
provider: a.model.provider,
|
|
345
|
+
name: a.model.name,
|
|
346
|
+
maxTokens: a.model.max_tokens,
|
|
347
|
+
temperature: a.model.temperature,
|
|
348
|
+
baseUrl: a.model.base_url
|
|
349
|
+
} : void 0
|
|
350
|
+
}));
|
|
351
|
+
console.log(chalk6.magenta("\n Neurogent ZeroClaw Runtime\n"));
|
|
352
|
+
console.log(chalk6.gray(` Config : ${configPath}`));
|
|
353
|
+
console.log(chalk6.gray(` Agents : ${agents.length}
|
|
354
|
+
`));
|
|
355
|
+
clearRuntime();
|
|
356
|
+
const servers = [];
|
|
357
|
+
const registration = {
|
|
358
|
+
agents: [],
|
|
359
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
360
|
+
};
|
|
361
|
+
for (let i = 0; i < agents.length; i++) {
|
|
362
|
+
const agent = agents[i];
|
|
363
|
+
const port = basePort + i;
|
|
364
|
+
const server = createAgentServer(agent, port, globalModel);
|
|
365
|
+
servers.push(server);
|
|
366
|
+
try {
|
|
367
|
+
const instance = await server.start();
|
|
368
|
+
registration.agents.push({
|
|
369
|
+
id: agent.id,
|
|
370
|
+
name: agent.name,
|
|
371
|
+
url: instance.url,
|
|
372
|
+
port,
|
|
373
|
+
pid: process.pid,
|
|
374
|
+
startedAt: instance.startedAt
|
|
375
|
+
});
|
|
376
|
+
console.log(
|
|
377
|
+
chalk6.green(" \u2713") + chalk6.white(` ${agent.emoji} ${agent.name.padEnd(14)}`) + chalk6.gray(` \u2192 `) + chalk6.cyan(`http://localhost:${port}`)
|
|
378
|
+
);
|
|
379
|
+
} catch (err) {
|
|
380
|
+
console.error(chalk6.red(` \u2717 ${agent.name}: ${err.message}`));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
saveRuntime(registration);
|
|
384
|
+
console.log(chalk6.gray("\n Runtime saved to .neurogent/runtime.json"));
|
|
385
|
+
console.log(chalk6.magenta("\n Agents are live. Press Ctrl+C to stop.\n"));
|
|
386
|
+
const stop = () => {
|
|
387
|
+
console.log(chalk6.yellow("\n Stopping agents..."));
|
|
388
|
+
servers.forEach((s) => s.stop());
|
|
389
|
+
clearRuntime();
|
|
390
|
+
console.log(chalk6.gray(" Runtime cleared. Goodbye.\n"));
|
|
391
|
+
process.exit(0);
|
|
392
|
+
};
|
|
393
|
+
process.on("SIGINT", stop);
|
|
394
|
+
process.on("SIGTERM", stop);
|
|
395
|
+
await new Promise(() => {
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// src/cli/commands/connect.ts
|
|
400
|
+
import { Command as Command7 } from "commander";
|
|
401
|
+
import chalk7 from "chalk";
|
|
402
|
+
var connectCommand = new Command7("connect").description("Connect the shell to a remote ZeroClaw agent server").option("-u, --url <url>", "Base URL of the ZeroClaw server (e.g. http://my-server:4100)").option("-a, --agent <id>", "Agent ID to connect (default: connect to all)").option("--clear", "Remove the remote connection and fall back to local LLM").action(async (opts) => {
|
|
403
|
+
if (opts.clear) {
|
|
404
|
+
clearRuntime();
|
|
405
|
+
console.log(chalk7.yellow(" Remote connection cleared. Shell will use local LLM.\n"));
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (!opts.url) {
|
|
409
|
+
console.error(chalk7.red(" Error: --url is required\n"));
|
|
410
|
+
console.log(chalk7.gray(" Example: neurogent connect --url http://my-server:4100\n"));
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
const url = opts.url.replace(/\/$/, "");
|
|
414
|
+
console.log(chalk7.magenta("\n Checking connection...\n"));
|
|
415
|
+
const health = await pingAgent(url);
|
|
416
|
+
if (!health.alive) {
|
|
417
|
+
console.error(chalk7.red(` Cannot reach ${url}: ${health.error}`));
|
|
418
|
+
console.log(chalk7.gray(" Make sure the remote server is running: neurogent start\n"));
|
|
419
|
+
process.exit(1);
|
|
420
|
+
}
|
|
421
|
+
console.log(chalk7.green(` Connected to: ${health.agent ?? "ZeroClaw"} (uptime ${health.uptime}s)`));
|
|
422
|
+
const runtime = loadRuntime() ?? { agents: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
423
|
+
if (opts.agent) {
|
|
424
|
+
const existing = runtime.agents.find((a) => a.id === opts.agent);
|
|
425
|
+
if (existing) {
|
|
426
|
+
existing.url = url;
|
|
427
|
+
} else {
|
|
428
|
+
runtime.agents.push({
|
|
429
|
+
id: opts.agent,
|
|
430
|
+
name: opts.agent,
|
|
431
|
+
url,
|
|
432
|
+
port: parseInt(new URL(url).port || "80", 10),
|
|
433
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
console.log(chalk7.cyan(`
|
|
437
|
+
Agent "${opts.agent}" \u2192 ${url}`));
|
|
438
|
+
} else {
|
|
439
|
+
const wildcardIdx = runtime.agents.findIndex((a) => a.id === "*");
|
|
440
|
+
const entry = {
|
|
441
|
+
id: "*",
|
|
442
|
+
name: "remote",
|
|
443
|
+
url,
|
|
444
|
+
port: parseInt(new URL(url).port || "80", 10),
|
|
445
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
446
|
+
};
|
|
447
|
+
if (wildcardIdx >= 0) {
|
|
448
|
+
runtime.agents[wildcardIdx] = entry;
|
|
449
|
+
} else {
|
|
450
|
+
runtime.agents.unshift(entry);
|
|
451
|
+
}
|
|
452
|
+
console.log(chalk7.cyan(`
|
|
453
|
+
All agents \u2192 ${url}`));
|
|
454
|
+
}
|
|
455
|
+
saveRuntime(runtime);
|
|
456
|
+
console.log(chalk7.gray(" Saved to .neurogent/runtime.json"));
|
|
457
|
+
console.log(chalk7.magenta("\n Launch the shell to use the remote backend:\n"));
|
|
458
|
+
console.log(chalk7.white(" neurogent shell\n"));
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// src/cli/commands/status.ts
|
|
462
|
+
import { Command as Command8 } from "commander";
|
|
463
|
+
import chalk8 from "chalk";
|
|
464
|
+
async function printStatus() {
|
|
465
|
+
const runtime = loadRuntime();
|
|
466
|
+
if (!runtime || runtime.agents.length === 0) {
|
|
467
|
+
console.log(chalk8.yellow("\n No agents registered.\n"));
|
|
468
|
+
console.log(chalk8.gray(" Start agents: neurogent start --config <file>"));
|
|
469
|
+
console.log(chalk8.gray(" Connect remote: neurogent connect --url <url>\n"));
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
console.log(chalk8.magenta("\n Neurogent Agent Status\n"));
|
|
473
|
+
console.log(
|
|
474
|
+
chalk8.gray(" " + "AGENT".padEnd(16) + "URL".padEnd(28) + "STATUS".padEnd(10) + "UPTIME")
|
|
475
|
+
);
|
|
476
|
+
console.log(chalk8.gray(" " + "\u2500".repeat(64)));
|
|
477
|
+
const checks = runtime.agents.map(async (agent) => {
|
|
478
|
+
const health = await pingAgent(agent.url);
|
|
479
|
+
const status = health.alive ? chalk8.green("\u25CF online") : chalk8.red("\u25CB offline");
|
|
480
|
+
const uptime = health.alive && health.uptime !== void 0 ? chalk8.gray(`${health.uptime}s`) : chalk8.gray("\u2014");
|
|
481
|
+
const name = agent.id === "*" ? chalk8.gray("(wildcard)") : chalk8.white(agent.name);
|
|
482
|
+
console.log(
|
|
483
|
+
` ${"\u{1F916} " + (agent.id === "*" ? "*".padEnd(13) : agent.name.padEnd(13))}${chalk8.cyan(agent.url.padEnd(28))}${status.padEnd(10)}` + uptime
|
|
484
|
+
);
|
|
485
|
+
});
|
|
486
|
+
await Promise.all(checks);
|
|
487
|
+
const started = new Date(runtime.startedAt).toLocaleTimeString();
|
|
488
|
+
console.log(chalk8.gray(`
|
|
489
|
+
Runtime started at ${started}
|
|
490
|
+
`));
|
|
491
|
+
}
|
|
492
|
+
var statusCommand = new Command8("status").description("Show health status of all registered ZeroClaw agents").option("-w, --watch", "Refresh every 3 seconds").action(async (opts) => {
|
|
493
|
+
await printStatus();
|
|
494
|
+
if (opts.watch) {
|
|
495
|
+
const interval = setInterval(async () => {
|
|
496
|
+
process.stdout.write("\x1B[2J\x1B[0f");
|
|
497
|
+
await printStatus();
|
|
498
|
+
}, 3e3);
|
|
499
|
+
process.on("SIGINT", () => {
|
|
500
|
+
clearInterval(interval);
|
|
501
|
+
process.exit(0);
|
|
502
|
+
});
|
|
503
|
+
await new Promise(() => {
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// src/cli/index.ts
|
|
509
|
+
var program = new Command9();
|
|
510
|
+
program.name("neurogent").description("A CLI for creating and managing A2A compliant Neuro agents").version("0.3.0");
|
|
511
|
+
program.addCommand(initCommand);
|
|
512
|
+
program.addCommand(devCommand);
|
|
513
|
+
program.addCommand(buildCommand);
|
|
514
|
+
program.addCommand(deployCommand);
|
|
515
|
+
program.addCommand(registerCommand);
|
|
516
|
+
program.addCommand(startCommand);
|
|
517
|
+
program.addCommand(connectCommand);
|
|
518
|
+
program.addCommand(statusCommand);
|
|
519
|
+
program.parse(process.argv);
|