@agentmeshhq/agent 0.1.11 → 0.1.12

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.
Files changed (47) hide show
  1. package/dist/__tests__/injector.test.d.ts +1 -0
  2. package/dist/__tests__/injector.test.js +26 -0
  3. package/dist/__tests__/injector.test.js.map +1 -0
  4. package/dist/cli/build.d.ts +6 -0
  5. package/dist/cli/build.js +111 -0
  6. package/dist/cli/build.js.map +1 -0
  7. package/dist/cli/deploy.d.ts +9 -0
  8. package/dist/cli/deploy.js +130 -0
  9. package/dist/cli/deploy.js.map +1 -0
  10. package/dist/cli/index.js +155 -0
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/cli/local.d.ts +9 -0
  13. package/dist/cli/local.js +139 -0
  14. package/dist/cli/local.js.map +1 -0
  15. package/dist/cli/migrate.d.ts +8 -0
  16. package/dist/cli/migrate.js +167 -0
  17. package/dist/cli/migrate.js.map +1 -0
  18. package/dist/cli/slack.d.ts +3 -0
  19. package/dist/cli/slack.js +57 -0
  20. package/dist/cli/slack.js.map +1 -0
  21. package/dist/cli/start.d.ts +4 -0
  22. package/dist/cli/start.js +5 -0
  23. package/dist/cli/start.js.map +1 -1
  24. package/dist/cli/test.d.ts +8 -0
  25. package/dist/cli/test.js +110 -0
  26. package/dist/cli/test.js.map +1 -0
  27. package/dist/core/daemon.d.ts +12 -0
  28. package/dist/core/daemon.js +96 -27
  29. package/dist/core/daemon.js.map +1 -1
  30. package/dist/core/injector.d.ts +6 -1
  31. package/dist/core/injector.js +64 -1
  32. package/dist/core/injector.js.map +1 -1
  33. package/dist/core/tmux.js +8 -10
  34. package/dist/core/tmux.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/__tests__/injector.test.ts +29 -0
  37. package/src/cli/build.ts +137 -0
  38. package/src/cli/deploy.ts +153 -0
  39. package/src/cli/index.ts +156 -0
  40. package/src/cli/local.ts +174 -0
  41. package/src/cli/migrate.ts +210 -0
  42. package/src/cli/slack.ts +69 -0
  43. package/src/cli/start.ts +8 -0
  44. package/src/cli/test.ts +141 -0
  45. package/src/core/daemon.ts +118 -35
  46. package/src/core/injector.ts +98 -1
  47. package/src/core/tmux.ts +9 -11
@@ -0,0 +1,153 @@
1
+ import { spawnSync, execSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import pc from "picocolors";
4
+
5
+ function findProjectRoot(): string {
6
+ let dir = process.cwd();
7
+ for (let i = 0; i < 10; i++) {
8
+ const scriptsDir = path.join(dir, "scripts");
9
+ const buildScript = path.join(scriptsDir, "build.sh");
10
+ try {
11
+ execSync(`test -f "${buildScript}"`, { stdio: "ignore" });
12
+ return dir;
13
+ } catch {
14
+ dir = path.dirname(dir);
15
+ }
16
+ }
17
+ throw new Error("Could not find AgentMesh project root. Make sure you're in the agentmesh repository.");
18
+ }
19
+
20
+ export type DeployEnvironment = "dev" | "staging" | "prod";
21
+
22
+ export interface DeployOptions {
23
+ environment: DeployEnvironment;
24
+ skipBuild?: boolean;
25
+ skipPush?: boolean;
26
+ skipTests?: boolean;
27
+ dryRun?: boolean;
28
+ }
29
+
30
+ export async function deploy(options: DeployOptions): Promise<void> {
31
+ const projectRoot = findProjectRoot();
32
+
33
+ console.log(pc.cyan(`Deploying to ${options.environment}...`));
34
+ console.log();
35
+
36
+ // Safety checks
37
+ if (options.environment === "prod") {
38
+ console.log(pc.red("WARNING: You are about to deploy to PRODUCTION"));
39
+ console.log(pc.yellow("Make sure all tests pass and staging deployment is verified."));
40
+ console.log();
41
+ console.log(pc.dim("Press Ctrl+C to cancel, or wait 10 seconds to continue..."));
42
+ await new Promise((resolve) => setTimeout(resolve, 10000));
43
+ console.log();
44
+ }
45
+
46
+ if (options.dryRun) {
47
+ console.log(pc.yellow("[DRY RUN] No actual deployment will be performed"));
48
+ console.log();
49
+ }
50
+
51
+ // Step 1: Build
52
+ if (!options.skipBuild) {
53
+ console.log(pc.bold("Step 1: Building..."));
54
+
55
+ const buildScript = path.join(projectRoot, "scripts", "build.sh");
56
+ const buildArgs = [buildScript, options.environment];
57
+
58
+ if (options.dryRun) {
59
+ console.log(pc.dim(`Would run: ${buildArgs.join(" ")}`));
60
+ } else {
61
+ const result = spawnSync("bash", buildArgs, {
62
+ cwd: projectRoot,
63
+ stdio: "inherit",
64
+ });
65
+
66
+ if (result.status !== 0) {
67
+ console.error(pc.red("Build failed. Aborting deployment."));
68
+ process.exit(1);
69
+ }
70
+ }
71
+ console.log();
72
+ } else {
73
+ console.log(pc.dim("Skipping build (--skip-build)"));
74
+ }
75
+
76
+ // Step 2: Push to registry
77
+ if (!options.skipPush) {
78
+ console.log(pc.bold("Step 2: Pushing to registry..."));
79
+
80
+ // Get the image tag from git commit
81
+ let tag: string;
82
+ try {
83
+ const commit = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
84
+ tag = `${options.environment}-${commit}`;
85
+ } catch {
86
+ console.error(pc.red("Failed to get git commit. Are you in a git repository?"));
87
+ process.exit(1);
88
+ }
89
+
90
+ const pushScript = path.join(projectRoot, "scripts", "push.sh");
91
+ const pushArgs = [pushScript, tag];
92
+
93
+ if (options.dryRun) {
94
+ console.log(pc.dim(`Would run: ${pushArgs.join(" ")}`));
95
+ } else {
96
+ const result = spawnSync("bash", pushArgs, {
97
+ cwd: projectRoot,
98
+ stdio: "inherit",
99
+ });
100
+
101
+ if (result.status !== 0) {
102
+ console.error(pc.red("Push failed. Aborting deployment."));
103
+ process.exit(1);
104
+ }
105
+ }
106
+ console.log();
107
+ } else {
108
+ console.log(pc.dim("Skipping push (--skip-push)"));
109
+ }
110
+
111
+ // Step 3: Deploy to server
112
+ console.log(pc.bold("Step 3: Deploying to server..."));
113
+
114
+ let tag: string;
115
+ try {
116
+ const commit = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
117
+ tag = `${options.environment}-${commit}`;
118
+ } catch {
119
+ console.error(pc.red("Failed to get git commit."));
120
+ process.exit(1);
121
+ }
122
+
123
+ const deployScript = path.join(projectRoot, "scripts", "deploy.sh");
124
+ const deployArgs = [deployScript, options.environment, tag];
125
+
126
+ if (options.dryRun) {
127
+ console.log(pc.dim(`Would run: ${deployArgs.join(" ")}`));
128
+ } else {
129
+ const result = spawnSync("bash", deployArgs, {
130
+ cwd: projectRoot,
131
+ stdio: "inherit",
132
+ });
133
+
134
+ if (result.status !== 0) {
135
+ console.error(pc.red("Deployment failed."));
136
+ process.exit(1);
137
+ }
138
+ }
139
+
140
+ console.log();
141
+ console.log(pc.green(`Successfully deployed to ${options.environment}!`));
142
+
143
+ // Show access info
144
+ const urls: Record<DeployEnvironment, string> = {
145
+ dev: "https://agentmeshhq.dev",
146
+ staging: "https://staging.agentmesh.ai",
147
+ prod: "https://agentmesh.ai",
148
+ };
149
+
150
+ console.log();
151
+ console.log(pc.bold("Access:"));
152
+ console.log(` URL: ${pc.cyan(urls[options.environment])}`);
153
+ }
package/src/cli/index.ts CHANGED
@@ -4,16 +4,22 @@ import { createRequire } from "node:module";
4
4
  import { Command } from "commander";
5
5
  import pc from "picocolors";
6
6
  import { attach } from "./attach.js";
7
+ import { build } from "./build.js";
7
8
  import { configCmd } from "./config.js";
8
9
  import { contextCmd } from "./context.js";
10
+ import { deploy } from "./deploy.js";
9
11
  import { init } from "./init.js";
10
12
  import { list } from "./list.js";
13
+ import { localUp, localDown, localStatus, localLogs } from "./local.js";
11
14
  import { logs } from "./logs.js";
15
+ import { migrate } from "./migrate.js";
12
16
  import { nudge } from "./nudge.js";
13
17
  import { restart } from "./restart.js";
18
+ import { slack } from "./slack.js";
14
19
  import { start } from "./start.js";
15
20
  import { status } from "./status.js";
16
21
  import { stop } from "./stop.js";
22
+ import { test } from "./test.js";
17
23
  import { token } from "./token.js";
18
24
  import { whoami } from "./whoami.js";
19
25
 
@@ -49,8 +55,14 @@ program
49
55
  .option("-f, --foreground", "Run in foreground (blocking)")
50
56
  .option("--no-context", "Start fresh without restoring previous context")
51
57
  .option("--auto-setup", "Auto-clone repository for project assignments")
58
+ .option("--serve", "Run opencode serve instead of tmux TUI (for Integration Service)")
59
+ .option("--serve-port <port>", "Port for opencode serve (default: 3001)", "3001")
52
60
  .action(async (options) => {
53
61
  try {
62
+ // Parse serve port as number
63
+ if (options.servePort) {
64
+ options.servePort = parseInt(options.servePort, 10);
65
+ }
54
66
  await start(options);
55
67
  } catch (error) {
56
68
  console.error(pc.red((error as Error).message));
@@ -209,4 +221,148 @@ program
209
221
  }
210
222
  });
211
223
 
224
+ program
225
+ .command("slack")
226
+ .description("Interact with Slack")
227
+ .argument("[action]", "Action: respond")
228
+ .argument("[channel]", "Slack channel ID")
229
+ .argument("[message]", "Message to send")
230
+ .option("-n, --name <name>", "Agent name (default: concierge)")
231
+ .action(async (action, channel, message, options) => {
232
+ try {
233
+ await slack(action || "help", channel, message, options);
234
+ } catch (error) {
235
+ console.error(pc.red((error as Error).message));
236
+ process.exit(1);
237
+ }
238
+ });
239
+
240
+ // Local development stack commands
241
+ const localCmd = program
242
+ .command("local")
243
+ .description("Manage local development stack (Postgres, Valkey, Hub)");
244
+
245
+ localCmd
246
+ .command("up")
247
+ .description("Start local development stack")
248
+ .option("--no-detach", "Run in foreground")
249
+ .action(async (options) => {
250
+ try {
251
+ await localUp({ detach: options.detach });
252
+ } catch (error) {
253
+ console.error(pc.red((error as Error).message));
254
+ process.exit(1);
255
+ }
256
+ });
257
+
258
+ localCmd
259
+ .command("down")
260
+ .description("Stop local development stack")
261
+ .action(async () => {
262
+ try {
263
+ await localDown();
264
+ } catch (error) {
265
+ console.error(pc.red((error as Error).message));
266
+ process.exit(1);
267
+ }
268
+ });
269
+
270
+ localCmd
271
+ .command("status")
272
+ .description("Show local stack status and ports")
273
+ .action(async () => {
274
+ try {
275
+ await localStatus();
276
+ } catch (error) {
277
+ console.error(pc.red((error as Error).message));
278
+ process.exit(1);
279
+ }
280
+ });
281
+
282
+ localCmd
283
+ .command("logs")
284
+ .description("View local stack logs")
285
+ .option("-f, --follow", "Follow log output")
286
+ .option("-s, --service <name>", "Specific service to show logs for")
287
+ .action(async (options) => {
288
+ try {
289
+ await localLogs({ follow: options.follow, service: options.service });
290
+ } catch (error) {
291
+ console.error(pc.red((error as Error).message));
292
+ process.exit(1);
293
+ }
294
+ });
295
+
296
+ // Build commands
297
+ program
298
+ .command("build")
299
+ .description("Build packages or Docker images")
300
+ .option("--docker", "Build Docker images instead of packages")
301
+ .option("-p, --package <name>", "Build specific package")
302
+ .option("--clean", "Clean build artifacts before building")
303
+ .action(async (options) => {
304
+ try {
305
+ await build(options);
306
+ } catch (error) {
307
+ console.error(pc.red((error as Error).message));
308
+ process.exit(1);
309
+ }
310
+ });
311
+
312
+ // Test commands
313
+ program
314
+ .command("test")
315
+ .description("Run tests")
316
+ .option("-p, --package <name>", "Test specific package")
317
+ .option("--e2e", "Run E2E tests")
318
+ .option("-w, --watch", "Watch mode")
319
+ .option("--coverage", "Generate coverage report")
320
+ .option("-u, --update-snapshots", "Update test snapshots")
321
+ .action(async (options) => {
322
+ try {
323
+ await test(options);
324
+ } catch (error) {
325
+ console.error(pc.red((error as Error).message));
326
+ process.exit(1);
327
+ }
328
+ });
329
+
330
+ // Migration commands
331
+ program
332
+ .command("migrate")
333
+ .description("Run database migrations")
334
+ .option("--dev", "Run against agentmeshhq.dev")
335
+ .option("--staging", "Run against staging")
336
+ .option("--generate", "Generate migration from schema changes")
337
+ .option("--status", "Show migration status")
338
+ .action(async (options) => {
339
+ try {
340
+ await migrate(options);
341
+ } catch (error) {
342
+ console.error(pc.red((error as Error).message));
343
+ process.exit(1);
344
+ }
345
+ });
346
+
347
+ // Deploy commands
348
+ program
349
+ .command("deploy")
350
+ .description("Deploy to environment")
351
+ .argument("<environment>", "Target environment: dev, staging, prod")
352
+ .option("--skip-build", "Skip build step")
353
+ .option("--skip-push", "Skip push to registry")
354
+ .option("--dry-run", "Show what would be done without executing")
355
+ .action(async (environment, options) => {
356
+ try {
357
+ if (!["dev", "staging", "prod"].includes(environment)) {
358
+ console.error(pc.red(`Invalid environment: ${environment}. Use: dev, staging, or prod`));
359
+ process.exit(1);
360
+ }
361
+ await deploy({ environment, ...options });
362
+ } catch (error) {
363
+ console.error(pc.red((error as Error).message));
364
+ process.exit(1);
365
+ }
366
+ });
367
+
212
368
  program.parse();
@@ -0,0 +1,174 @@
1
+ import { spawn, execSync, spawnSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import pc from "picocolors";
4
+
5
+ const COMPOSE_FILE = "docker/docker-compose.local.yml";
6
+
7
+ interface LocalStackPorts {
8
+ postgres: number;
9
+ valkey: number;
10
+ hub: number;
11
+ admin: number;
12
+ nginx: number;
13
+ }
14
+
15
+ function findProjectRoot(): string {
16
+ // Try to find the project root by looking for docker-compose files
17
+ let dir = process.cwd();
18
+ for (let i = 0; i < 10; i++) {
19
+ const composePath = path.join(dir, COMPOSE_FILE);
20
+ try {
21
+ execSync(`test -f "${composePath}"`, { stdio: "ignore" });
22
+ return dir;
23
+ } catch {
24
+ dir = path.dirname(dir);
25
+ }
26
+ }
27
+ throw new Error("Could not find AgentMesh project root. Make sure you're in the agentmesh repository.");
28
+ }
29
+
30
+ function getContainerStatus(containerName: string): { running: boolean; healthy: boolean; port?: string } {
31
+ try {
32
+ const result = execSync(
33
+ `docker inspect --format='{{.State.Running}}:{{.State.Health.Status}}' ${containerName} 2>/dev/null`,
34
+ { encoding: "utf-8" }
35
+ ).trim();
36
+ const [running, health] = result.split(":");
37
+ return {
38
+ running: running === "true",
39
+ healthy: health === "healthy",
40
+ };
41
+ } catch {
42
+ return { running: false, healthy: false };
43
+ }
44
+ }
45
+
46
+ function getContainerPort(containerName: string, internalPort: number): string | null {
47
+ try {
48
+ const result = execSync(
49
+ `docker port ${containerName} ${internalPort} 2>/dev/null | head -1`,
50
+ { encoding: "utf-8" }
51
+ ).trim();
52
+ // Format: 0.0.0.0:5432 -> 5432
53
+ const match = result.match(/:(\d+)$/);
54
+ return match ? match[1] : null;
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ export async function localUp(options: { detach?: boolean } = {}): Promise<void> {
61
+ const projectRoot = findProjectRoot();
62
+ const composePath = path.join(projectRoot, COMPOSE_FILE);
63
+
64
+ console.log(pc.cyan("Starting AgentMesh local development stack..."));
65
+ console.log();
66
+
67
+ const args = ["compose", "-f", composePath, "up"];
68
+ if (options.detach !== false) {
69
+ args.push("-d");
70
+ }
71
+ args.push("--build");
72
+
73
+ const result = spawnSync("docker", args, {
74
+ cwd: projectRoot,
75
+ stdio: "inherit",
76
+ });
77
+
78
+ if (result.status !== 0) {
79
+ console.error(pc.red("Failed to start local stack"));
80
+ process.exit(1);
81
+ }
82
+
83
+ if (options.detach !== false) {
84
+ console.log();
85
+ console.log(pc.green("Local stack started successfully!"));
86
+ console.log();
87
+ await localStatus();
88
+ }
89
+ }
90
+
91
+ export async function localDown(): Promise<void> {
92
+ const projectRoot = findProjectRoot();
93
+ const composePath = path.join(projectRoot, COMPOSE_FILE);
94
+
95
+ console.log(pc.cyan("Stopping AgentMesh local development stack..."));
96
+
97
+ const result = spawnSync("docker", ["compose", "-f", composePath, "down"], {
98
+ cwd: projectRoot,
99
+ stdio: "inherit",
100
+ });
101
+
102
+ if (result.status !== 0) {
103
+ console.error(pc.red("Failed to stop local stack"));
104
+ process.exit(1);
105
+ }
106
+
107
+ console.log(pc.green("Local stack stopped."));
108
+ }
109
+
110
+ export async function localStatus(): Promise<void> {
111
+ const services = [
112
+ { name: "postgres", container: "agentmesh_postgres", port: 5432 },
113
+ { name: "valkey", container: "agentmesh_valkey", port: 6379 },
114
+ { name: "hub-api", container: "agentmesh_hub_api", port: 3777 },
115
+ { name: "hub-worker", container: "agentmesh_hub_worker", port: null },
116
+ { name: "admin", container: "agentmesh_admin", port: 3778 },
117
+ { name: "nginx", container: "agentmesh_nginx", port: 80 },
118
+ ];
119
+
120
+ console.log(pc.bold("AgentMesh Local Stack Status"));
121
+ console.log();
122
+ console.log(pc.dim("Service".padEnd(15) + "Status".padEnd(12) + "Health".padEnd(10) + "Port"));
123
+ console.log(pc.dim("-".repeat(50)));
124
+
125
+ let anyRunning = false;
126
+
127
+ for (const service of services) {
128
+ const status = getContainerStatus(service.container);
129
+ const port = service.port ? getContainerPort(service.container, service.port) : null;
130
+
131
+ const statusText = status.running ? pc.green("running") : pc.dim("stopped");
132
+ const healthText = status.running
133
+ ? status.healthy
134
+ ? pc.green("healthy")
135
+ : pc.yellow("starting")
136
+ : pc.dim("-");
137
+ const portText = port ? pc.cyan(port) : pc.dim("-");
138
+
139
+ console.log(
140
+ `${service.name.padEnd(15)}${statusText.padEnd(20)}${healthText.padEnd(18)}${portText}`
141
+ );
142
+
143
+ if (status.running) anyRunning = true;
144
+ }
145
+
146
+ console.log();
147
+
148
+ if (anyRunning) {
149
+ const nginxPort = getContainerPort("agentmesh_nginx", 80) || "3000";
150
+ console.log(pc.bold("Access:"));
151
+ console.log(` Admin UI: ${pc.cyan(`http://localhost:${nginxPort}/admin`)}`);
152
+ console.log(` API: ${pc.cyan(`http://localhost:${nginxPort}/api`)}`);
153
+ console.log();
154
+ console.log(pc.bold("Commands:"));
155
+ console.log(` Stop: ${pc.cyan("agentmesh local down")}`);
156
+ console.log(` Logs: ${pc.cyan("docker compose -f docker/docker-compose.local.yml logs -f")}`);
157
+ } else {
158
+ console.log(pc.dim("No services running. Start with: agentmesh local up"));
159
+ }
160
+ }
161
+
162
+ export async function localLogs(options: { follow?: boolean; service?: string } = {}): Promise<void> {
163
+ const projectRoot = findProjectRoot();
164
+ const composePath = path.join(projectRoot, COMPOSE_FILE);
165
+
166
+ const args = ["compose", "-f", composePath, "logs"];
167
+ if (options.follow) args.push("-f");
168
+ if (options.service) args.push(options.service);
169
+
170
+ spawn("docker", args, {
171
+ cwd: projectRoot,
172
+ stdio: "inherit",
173
+ });
174
+ }