@swarp/cli 0.0.1-rc.17

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/bin/swarp.mjs ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+ import { runInit } from '../src/init/index.mjs';
3
+ import { auditConfigs } from '../src/generator/audit.mjs';
4
+ import { generateRunnerConfig } from '../src/generator/generate.mjs';
5
+ import { FlySpriteAdapter } from '../src/runtimes/fly-sprites.mjs';
6
+ import { loadConfig } from '../src/config.mjs';
7
+ import { startMcpServer } from '../src/mcp-server/index.mjs';
8
+
9
+ const args = process.argv.slice(2);
10
+ const [cmd, ...rest] = args;
11
+
12
+ function usage() {
13
+ console.log(`Usage: swarp <command> [options]
14
+
15
+ Commands:
16
+ init Initialize a new SWARP project
17
+ serve Start the MCP server (stdio transport)
18
+ generate [agents-dir] Generate runner configs from agent.yaml files
19
+ audit [agents-dir] Audit agent.yaml files for schema errors
20
+ certs generate Generate mTLS CA, router, and agent keypairs
21
+ certs rotate <name> Rotate cert for a named agent
22
+ deploy <agent> Deploy a specific agent sprite
23
+ deploy --all Deploy all agents
24
+ status [agent] Show agent status via gRPC
25
+
26
+ Environment variables:
27
+ SWARP_SPRITES_TOKEN Required for deploy commands
28
+ `);
29
+ }
30
+
31
+ async function main() {
32
+ if (!cmd || cmd === '--help' || cmd === '-h') {
33
+ usage();
34
+ process.exit(0);
35
+ }
36
+
37
+ if (cmd === 'init') {
38
+ await runInit();
39
+ return;
40
+ }
41
+
42
+ if (cmd === 'serve') {
43
+ await startMcpServer();
44
+ return;
45
+ }
46
+
47
+ if (cmd === 'generate') {
48
+ const agentsDir = rest[0] || 'agents';
49
+ await generateRunnerConfig(agentsDir);
50
+
51
+ // Regenerate SKILL.md from current agent configs
52
+ const { generateSkill } = await import('../src/skill/generate.mjs');
53
+ const { resolve, join } = await import('node:path');
54
+ const { writeFileSync, mkdirSync } = await import('node:fs');
55
+ const routerUrl = config?.router_url || 'your-router.fly.dev:50051';
56
+ const skillContent = generateSkill({ agentsDir: resolve(agentsDir), routerUrl });
57
+ const skillPath = join(process.cwd(), '.claude', 'skills', 'swarp', 'SKILL.md');
58
+ mkdirSync(join(process.cwd(), '.claude', 'skills', 'swarp'), { recursive: true });
59
+ writeFileSync(skillPath, skillContent, 'utf8');
60
+ console.log(`Updated ${skillPath}`);
61
+ return;
62
+ }
63
+
64
+ if (cmd === 'audit') {
65
+ const agentsDir = rest[0] || 'agents';
66
+ const results = await auditConfigs(agentsDir);
67
+ let hasErrors = false;
68
+ for (const result of results) {
69
+ console.log(`\n=== ${result.agent} ===`);
70
+ for (const c of result.checks) {
71
+ const icon = c.status === 'pass' ? '\u2713' : c.status === 'fail' ? '\u2717' : '\u25cb';
72
+ const sev = c.severity === 'error' ? 'ERR' : 'WRN';
73
+ console.log(` ${icon} [${sev}] ${c.name}: ${c.message}`);
74
+ if (c.status === 'fail' && c.severity === 'error') hasErrors = true;
75
+ }
76
+ }
77
+ console.log(`\nAudited ${results.length} agent(s).`);
78
+ process.exit(hasErrors ? 1 : 0);
79
+ }
80
+
81
+ if (cmd === 'certs') {
82
+ const [subCmd, ...certArgs] = rest;
83
+ if (subCmd === 'generate') {
84
+ const { generateCerts } = await import('../src/certs/generate.mjs');
85
+ await generateCerts(certArgs[0] || 'certs');
86
+ return;
87
+ }
88
+ if (subCmd === 'rotate') {
89
+ const name = certArgs[0];
90
+ if (!name) {
91
+ console.error('Error: certs rotate requires an agent name');
92
+ process.exit(1);
93
+ }
94
+ const { rotateCert } = await import('../src/certs/generate.mjs');
95
+ await rotateCert(name, certArgs[1] || 'certs');
96
+ return;
97
+ }
98
+ console.error(`Unknown certs subcommand: ${subCmd}`);
99
+ usage();
100
+ process.exit(1);
101
+ }
102
+
103
+ if (cmd === 'deploy') {
104
+ const token = process.env.SWARP_SPRITES_TOKEN;
105
+ if (!token) {
106
+ console.error('Error: SWARP_SPRITES_TOKEN env var is required for deploy');
107
+ process.exit(1);
108
+ }
109
+
110
+ const config = loadConfig('.swarp.json');
111
+ const adapter = new FlySpriteAdapter(token);
112
+
113
+ if (rest[0] === '--all') {
114
+ const { auditConfigs } = await import('../src/generator/audit.mjs');
115
+ const { readFileSync, readdirSync, existsSync } = await import('node:fs');
116
+ const { resolve, join } = await import('node:path');
117
+ const yaml = (await import('js-yaml')).default;
118
+
119
+ const agentsDir = resolve(config.agents_dir || 'agents');
120
+ const entries = readdirSync(agentsDir, { withFileTypes: true });
121
+ for (const entry of entries) {
122
+ if (!entry.isDirectory()) continue;
123
+ const yamlPath = join(agentsDir, entry.name, 'agent.yaml');
124
+ if (!existsSync(yamlPath)) continue;
125
+ const agentConfig = yaml.load(readFileSync(yamlPath, 'utf-8'));
126
+ console.log(`Deploying ${agentConfig.name}...`);
127
+ await adapter.createAgent(agentConfig.name, agentConfig);
128
+ console.log(` Done: ${agentConfig.name}`);
129
+ }
130
+ return;
131
+ }
132
+
133
+ const agentName = rest[0];
134
+ if (!agentName) {
135
+ console.error('Error: deploy requires an agent name or --all');
136
+ process.exit(1);
137
+ }
138
+
139
+ const { readFileSync, existsSync } = await import('node:fs');
140
+ const { resolve, join } = await import('node:path');
141
+ const yaml = (await import('js-yaml')).default;
142
+
143
+ const agentsDir = resolve(config.agents_dir || 'agents');
144
+ const yamlPath = join(agentsDir, agentName, 'agent.yaml');
145
+ if (!existsSync(yamlPath)) {
146
+ console.error(`Error: agent.yaml not found at ${yamlPath}`);
147
+ process.exit(1);
148
+ }
149
+ const agentConfig = yaml.load(readFileSync(yamlPath, 'utf-8'));
150
+ console.log(`Deploying ${agentName}...`);
151
+ await adapter.createAgent(agentName, agentConfig);
152
+ console.log(` Done: ${agentName}`);
153
+ return;
154
+ }
155
+
156
+ if (cmd === 'status') {
157
+ const config = loadConfig('.swarp.json');
158
+ const { DispatchClient } = await import('../src/mcp-server/dispatch.mjs');
159
+ const client = new DispatchClient(config.router_url);
160
+
161
+ const agentName = rest[0];
162
+ if (agentName) {
163
+ const status = await client.getAgentStatus(agentName);
164
+ console.log(JSON.stringify(status, null, 2));
165
+ } else {
166
+ const { agents } = await client.listAgents();
167
+ for (const agent of agents) {
168
+ const onlineStr = agent.online ? 'online' : 'offline';
169
+ console.log(`${agent.name} (${onlineStr}) — ${agent.modes?.length ?? 0} mode(s)`);
170
+ }
171
+ }
172
+ return;
173
+ }
174
+
175
+ console.error(`Unknown command: ${cmd}`);
176
+ usage();
177
+ process.exit(1);
178
+ }
179
+
180
+ main().catch((err) => {
181
+ console.error('Error:', err.message);
182
+ process.exit(1);
183
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@swarp/cli",
3
+ "version": "0.0.1-rc.17",
4
+ "description": "SWARP agent orchestration platform — CLI, MCP server, generator",
5
+ "type": "module",
6
+ "bin": {
7
+ "swarp": "./bin/swarp.mjs"
8
+ },
9
+ "exports": {
10
+ "./mcp-server": "./src/mcp-server/index.mjs",
11
+ "./dispatch": "./src/mcp-server/dispatch.mjs",
12
+ "./generator/schema": "./src/generator/schema.mjs",
13
+ "./generator/audit": "./src/generator/audit.mjs",
14
+ "./generator/generate": "./src/generator/generate.mjs",
15
+ "./runtimes/fly-sprites": "./src/runtimes/fly-sprites.mjs"
16
+ },
17
+ "files": [
18
+ "bin/",
19
+ "src/",
20
+ "proto/"
21
+ ],
22
+ "scripts": {
23
+ "prepack": "mkdir -p proto/swarp/v1 && cp ../proto/swarp/v1/swarp.proto proto/swarp/v1/",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest"
26
+ },
27
+ "dependencies": {
28
+ "@grpc/grpc-js": "^1.11.0",
29
+ "@grpc/proto-loader": "^0.7.13",
30
+ "@modelcontextprotocol/sdk": "^1.0.0",
31
+ "js-yaml": "^4.1.0",
32
+ "zod": "^3.23.8"
33
+ },
34
+ "devDependencies": {
35
+ "vitest": "^2.0.0"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/dl3consulting/monorepo.git",
40
+ "directory": "apps/swarp/npm"
41
+ },
42
+ "engines": {
43
+ "node": ">=20.0.0"
44
+ }
45
+ }
@@ -0,0 +1,157 @@
1
+ syntax = "proto3";
2
+ package swarp.v1;
3
+
4
+ option go_package = "github.com/dl3consulting/swarp/gen/go/swarp/v1;swarpv1";
5
+
6
+ // Router <-> Sprite communication
7
+ service AgentRunnerService {
8
+ rpc Dispatch(DispatchRequest) returns (stream DispatchResponse);
9
+ rpc GetStatus(GetStatusRequest) returns (GetStatusResponse);
10
+ rpc GetHealth(GetHealthRequest) returns (GetHealthResponse);
11
+ }
12
+
13
+ // Sprite -> Router registration
14
+ service AgentRegistryService {
15
+ rpc Register(RegisterRequest) returns (RegisterResponse);
16
+ }
17
+
18
+ // Plugin/MCP -> Router communication
19
+ // Plugins must implement DispatchTask. ListAgents, CancelTask, GetAgentStatus are optional.
20
+ service AgentDispatchService {
21
+ rpc DispatchTask(DispatchTaskRequest) returns (stream DispatchTaskResponse);
22
+ rpc ListAgents(ListAgentsRequest) returns (ListAgentsResponse);
23
+ rpc CancelTask(CancelTaskRequest) returns (CancelTaskResponse);
24
+ rpc GetAgentStatus(GetAgentStatusRequest) returns (GetAgentStatusResponse);
25
+ }
26
+
27
+ message RegisterRequest {
28
+ string name = 1;
29
+ string address = 2;
30
+ repeated ModeInfo modes = 3;
31
+ string version = 4;
32
+ }
33
+
34
+ message RegisterResponse {
35
+ bool accepted = 1;
36
+ }
37
+
38
+ message DispatchRequest {
39
+ string mode = 1;
40
+ map<string, string> params = 2;
41
+ string session_id = 3;
42
+ int32 remaining_budget = 4;
43
+ }
44
+
45
+ message DispatchTaskRequest {
46
+ string agent = 1;
47
+
48
+ oneof dispatch {
49
+ StructuredDispatch structured = 2;
50
+ string raw_text = 3;
51
+ }
52
+
53
+ string callback_id = 4;
54
+ string session_id = 5;
55
+ int32 remaining_budget = 6;
56
+ }
57
+
58
+ message DispatchResponse {
59
+ AgentEvent event = 1;
60
+ }
61
+
62
+ message DispatchTaskResponse {
63
+ AgentEvent event = 1;
64
+ }
65
+
66
+ message StructuredDispatch {
67
+ string mode = 1;
68
+ map<string, string> params = 2;
69
+ }
70
+
71
+ message AgentEvent {
72
+ enum EventType {
73
+ EVENT_TYPE_UNSPECIFIED = 0;
74
+ EVENT_TYPE_THINKING = 1;
75
+ EVENT_TYPE_TOOL_USE = 2;
76
+ EVENT_TYPE_DONE = 3;
77
+ EVENT_TYPE_ERROR = 4;
78
+ }
79
+ EventType type = 1;
80
+ string text = 2;
81
+ string task_id = 3;
82
+ string session_id = 4;
83
+ TaskResult result = 5;
84
+ int64 timestamp = 6;
85
+ }
86
+
87
+ message TaskResult {
88
+ string status = 1;
89
+ string summary = 2;
90
+ map<string, string> structured = 3;
91
+ CostInfo cost = 4;
92
+ repeated string notify = 5;
93
+ }
94
+
95
+ message CostInfo {
96
+ double usd = 1;
97
+ int32 turns = 2;
98
+ int64 duration_ms = 3;
99
+ }
100
+
101
+ message GetStatusRequest {}
102
+
103
+ message GetStatusResponse {
104
+ string status = 1;
105
+ string task_id = 2;
106
+ string mode = 3;
107
+ string session_id = 4;
108
+ TaskResult result = 5;
109
+ string last_output = 6;
110
+ }
111
+
112
+ message GetHealthRequest {}
113
+
114
+ message GetHealthResponse {
115
+ bool up = 1;
116
+ bool has_task = 2;
117
+ }
118
+
119
+ message CancelTaskRequest {
120
+ string task_id = 1;
121
+ }
122
+
123
+ message CancelTaskResponse {
124
+ string status = 1;
125
+ }
126
+
127
+ message ListAgentsRequest {}
128
+
129
+ message ListAgentsResponse {
130
+ repeated AgentInfo agents = 1;
131
+ }
132
+
133
+ message AgentInfo {
134
+ string name = 1;
135
+ string display_name = 2;
136
+ string role = 3;
137
+ repeated ModeInfo modes = 4;
138
+ bool online = 5;
139
+ }
140
+
141
+ message ModeInfo {
142
+ string name = 1;
143
+ string description = 2;
144
+ string model = 3;
145
+ int32 max_turns = 4;
146
+ }
147
+
148
+ message GetAgentStatusRequest {
149
+ string agent = 1;
150
+ }
151
+
152
+ message GetAgentStatusResponse {
153
+ bool up = 1;
154
+ string status = 2;
155
+ string mode = 3;
156
+ CostInfo last_cost = 4;
157
+ }