agent-squad-cli 1.0.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/README.md +286 -0
- package/SKILL.md +209 -0
- package/assets/LOKI_WORK_LOG.md +41 -0
- package/assets/blog-why-your-ai-needs-a-team.md +86 -0
- package/assets/twitter-thread-agent-squad-launch.md +76 -0
- package/package.json +33 -0
- package/references/personalities.md +346 -0
- package/references/workflows.md +340 -0
- package/scripts/agent-squad +505 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* agent-squad — Manage teams of AI agents
|
|
4
|
+
*
|
|
5
|
+
* Usage: agent-squad <command> [options]
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
const SQUAD_DIR = path.join(process.env.HOME, '.config/agent-squad');
|
|
13
|
+
const CONFIG_FILE = path.join(SQUAD_DIR, 'config.json');
|
|
14
|
+
|
|
15
|
+
// Ensure squad directory exists
|
|
16
|
+
function ensureSquadDir() {
|
|
17
|
+
if (!fs.existsSync(SQUAD_DIR)) {
|
|
18
|
+
fs.mkdirSync(SQUAD_DIR, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Load or create config
|
|
23
|
+
function loadConfig() {
|
|
24
|
+
ensureSquadDir();
|
|
25
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
26
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
27
|
+
}
|
|
28
|
+
return { squads: [], activeSquad: null };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveConfig(config) {
|
|
32
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get squad path
|
|
36
|
+
function getSquadPath(name) {
|
|
37
|
+
return path.join(SQUAD_DIR, name);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Initialize new squad
|
|
41
|
+
function initSquad(name) {
|
|
42
|
+
const squadPath = getSquadPath(name);
|
|
43
|
+
|
|
44
|
+
if (fs.existsSync(squadPath)) {
|
|
45
|
+
console.error(`Squad "${name}" already exists.`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.mkdirSync(squadPath, { recursive: true });
|
|
50
|
+
fs.mkdirSync(path.join(squadPath, 'agents'), { recursive: true });
|
|
51
|
+
|
|
52
|
+
const squadConfig = {
|
|
53
|
+
name,
|
|
54
|
+
created: new Date().toISOString(),
|
|
55
|
+
taskSystem: null,
|
|
56
|
+
taskConfig: {}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(
|
|
60
|
+
path.join(squadPath, 'squad.json'),
|
|
61
|
+
JSON.stringify(squadConfig, null, 2)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Create default AGENTS.md
|
|
65
|
+
const agentsMd = `# AGENTS.md — ${name} Squad Operations
|
|
66
|
+
|
|
67
|
+
## Mission
|
|
68
|
+
|
|
69
|
+
[Define your squad's mission here]
|
|
70
|
+
|
|
71
|
+
## Communication Rules
|
|
72
|
+
|
|
73
|
+
1. All task discussion happens in the task system (Linear/Trello/etc)
|
|
74
|
+
2. Use @mentions to notify specific agents
|
|
75
|
+
3. When research is ready, @mention the writer
|
|
76
|
+
4. When draft is ready, @mention the lead
|
|
77
|
+
5. Lead reports to human when deliverables are ready
|
|
78
|
+
|
|
79
|
+
## File Conventions
|
|
80
|
+
|
|
81
|
+
- Research notes: \`research/YYYY-MM-DD-topic.md\`
|
|
82
|
+
- Drafts: \`drafts/YYYY-MM-DD-topic.md\`
|
|
83
|
+
- Published: \`published/YYYY-MM-DD-topic.md\`
|
|
84
|
+
|
|
85
|
+
## When to Escalate to Human
|
|
86
|
+
|
|
87
|
+
- Missing critical information
|
|
88
|
+
- Conflicting research findings
|
|
89
|
+
- Task blocked >24 hours
|
|
90
|
+
- Unclear requirements
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
fs.writeFileSync(path.join(squadPath, 'AGENTS.md'), agentsMd);
|
|
94
|
+
|
|
95
|
+
// Update global config
|
|
96
|
+
const config = loadConfig();
|
|
97
|
+
config.squads.push(name);
|
|
98
|
+
config.activeSquad = name;
|
|
99
|
+
saveConfig(config);
|
|
100
|
+
|
|
101
|
+
console.log(`✅ Squad "${name}" initialized`);
|
|
102
|
+
console.log(` Location: ${squadPath}`);
|
|
103
|
+
console.log(`\nNext steps:`);
|
|
104
|
+
console.log(` agent-squad add <agent-name> --role "Description"`);
|
|
105
|
+
console.log(` agent-squad config --tasks linear`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Add agent to squad
|
|
109
|
+
function addAgent(name, options) {
|
|
110
|
+
const config = loadConfig();
|
|
111
|
+
const squadName = config.activeSquad;
|
|
112
|
+
|
|
113
|
+
if (!squadName) {
|
|
114
|
+
console.error('No active squad. Run: agent-squad init <name>');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const squadPath = getSquadPath(squadName);
|
|
119
|
+
const agentPath = path.join(squadPath, 'agents', name);
|
|
120
|
+
|
|
121
|
+
if (fs.existsSync(agentPath)) {
|
|
122
|
+
console.error(`Agent "${name}" already exists in squad.`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fs.mkdirSync(agentPath, { recursive: true });
|
|
127
|
+
|
|
128
|
+
const role = options.role || 'General purpose agent';
|
|
129
|
+
const personality = options.personality || 'balanced';
|
|
130
|
+
const schedule = options.schedule || '*/15 * * * *';
|
|
131
|
+
const model = options.model || 'kimi-code';
|
|
132
|
+
|
|
133
|
+
// Create SOUL.md
|
|
134
|
+
const soulMd = generateSOUL(name, role, personality);
|
|
135
|
+
fs.writeFileSync(path.join(agentPath, 'SOUL.md'), soulMd);
|
|
136
|
+
|
|
137
|
+
// Copy AGENTS.md
|
|
138
|
+
fs.copyFileSync(
|
|
139
|
+
path.join(squadPath, 'AGENTS.md'),
|
|
140
|
+
path.join(agentPath, 'AGENTS.md')
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Create agent config
|
|
144
|
+
const agentConfig = {
|
|
145
|
+
name,
|
|
146
|
+
role,
|
|
147
|
+
personality,
|
|
148
|
+
schedule,
|
|
149
|
+
model,
|
|
150
|
+
sessionKey: `agent:${name}:main`,
|
|
151
|
+
enabled: false
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
fs.writeFileSync(
|
|
155
|
+
path.join(agentPath, 'config.json'),
|
|
156
|
+
JSON.stringify(agentConfig, null, 2)
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
console.log(`✅ Agent "${name}" added to squad "${squadName}"`);
|
|
160
|
+
console.log(` Session: ${agentConfig.sessionKey}`);
|
|
161
|
+
console.log(` Schedule: ${schedule}`);
|
|
162
|
+
console.log(`\nEdit personality: agent-squad edit ${name}`);
|
|
163
|
+
console.log(`Start heartbeats: agent-squad start`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Generate SOUL.md content
|
|
167
|
+
function generateSOUL(name, role, personality) {
|
|
168
|
+
const personalities = {
|
|
169
|
+
skeptical: `Skeptical and thorough. Questions assumptions. Finds edge cases.`,
|
|
170
|
+
creative: `Creative and exploratory. Generates novel ideas. Thinks outside the box.`,
|
|
171
|
+
analytical: `Analytical and precise. Data-driven. Focuses on accuracy.`,
|
|
172
|
+
balanced: `Balanced and practical. Adapts to the task at hand.`
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return `# SOUL.md — Who You Are
|
|
176
|
+
|
|
177
|
+
**Name:** ${name}
|
|
178
|
+
**Role:** ${role}
|
|
179
|
+
|
|
180
|
+
## Personality
|
|
181
|
+
${personalities[personality] || personalities.balanced}
|
|
182
|
+
|
|
183
|
+
## What You're Good At
|
|
184
|
+
- [Add specific strengths]
|
|
185
|
+
- [Add domain expertise]
|
|
186
|
+
- [Add preferred work style]
|
|
187
|
+
|
|
188
|
+
## What You Care About
|
|
189
|
+
- [Add values and priorities]
|
|
190
|
+
- [Add pet peeves or preferences]
|
|
191
|
+
|
|
192
|
+
## Your Tools
|
|
193
|
+
- Read the SKILL.md files for available tools
|
|
194
|
+
- Use tools appropriate to your role
|
|
195
|
+
|
|
196
|
+
## How You Work
|
|
197
|
+
1. Read AGENTS.md on every heartbeat
|
|
198
|
+
2. Check task system for assigned work
|
|
199
|
+
3. Do your work thoroughly
|
|
200
|
+
4. Post updates and @mention relevant agents
|
|
201
|
+
5. Report HEARTBEAT_OK if nothing to do
|
|
202
|
+
|
|
203
|
+
## Squad Context
|
|
204
|
+
You are part of a multi-agent squad. Coordinate via the shared task system.
|
|
205
|
+
Follow the communication rules in AGENTS.md.
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Edit agent SOUL.md
|
|
210
|
+
function editAgent(name) {
|
|
211
|
+
const config = loadConfig();
|
|
212
|
+
const squadName = config.activeSquad;
|
|
213
|
+
const editor = process.env.EDITOR || 'nano';
|
|
214
|
+
|
|
215
|
+
const soulPath = path.join(getSquadPath(squadName), 'agents', name, 'SOUL.md');
|
|
216
|
+
|
|
217
|
+
if (!fs.existsSync(soulPath)) {
|
|
218
|
+
console.error(`Agent "${name}" not found.`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
execSync(`${editor} "${soulPath}"`, { stdio: 'inherit' });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Configure task system
|
|
226
|
+
function configTaskSystem(system, options) {
|
|
227
|
+
const config = loadConfig();
|
|
228
|
+
const squadName = config.activeSquad;
|
|
229
|
+
|
|
230
|
+
if (!squadName) {
|
|
231
|
+
console.error('No active squad. Run: agent-squad init <name>');
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const squadPath = getSquadPath(squadName);
|
|
236
|
+
const squadConfig = JSON.parse(fs.readFileSync(path.join(squadPath, 'squad.json'), 'utf8'));
|
|
237
|
+
|
|
238
|
+
squadConfig.taskSystem = system;
|
|
239
|
+
squadConfig.taskConfig = options;
|
|
240
|
+
|
|
241
|
+
fs.writeFileSync(
|
|
242
|
+
path.join(squadPath, 'squad.json'),
|
|
243
|
+
JSON.stringify(squadConfig, null, 2)
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
console.log(`✅ Task system set to: ${system}`);
|
|
247
|
+
|
|
248
|
+
if (system === 'linear') {
|
|
249
|
+
console.log('\nMake sure you have:');
|
|
250
|
+
console.log(' - linear skill installed');
|
|
251
|
+
console.log(' - Linear API key configured');
|
|
252
|
+
console.log('\nUsage in SOUL.md:');
|
|
253
|
+
console.log(' linear issues --team "Your Team" | grep "Title"');
|
|
254
|
+
console.log(' linear issue:create --title "Task" --description "Details"');
|
|
255
|
+
} else if (system === 'trello') {
|
|
256
|
+
console.log('\nMake sure you have:');
|
|
257
|
+
console.log(' - trello skill installed');
|
|
258
|
+
console.log(' - Trello API key/token configured');
|
|
259
|
+
console.log('\nUsage in SOUL.md:');
|
|
260
|
+
console.log(' trello boards');
|
|
261
|
+
console.log(' trello board --board-id <id>');
|
|
262
|
+
console.log(' trello card:create --name "Task" --list-id <id>');
|
|
263
|
+
} else if (system === 'github') {
|
|
264
|
+
console.log('\nMake sure you have:');
|
|
265
|
+
console.log(' - github skill installed');
|
|
266
|
+
console.log(' - GitHub token configured');
|
|
267
|
+
console.log('\nUsage in SOUL.md:');
|
|
268
|
+
console.log(' github issue list --repo owner/repo');
|
|
269
|
+
console.log(' github issue:create --title "Task" --body "Details"');
|
|
270
|
+
} else if (system === 'file') {
|
|
271
|
+
console.log('\nFile-based task system:');
|
|
272
|
+
console.log(' Tasks stored in ~/.config/agent-squad/<squad>/tasks/');
|
|
273
|
+
console.log(' Markdown files with YAML frontmatter');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Start all heartbeats
|
|
278
|
+
function startHeartbeats() {
|
|
279
|
+
const config = loadConfig();
|
|
280
|
+
const squadName = config.activeSquad;
|
|
281
|
+
|
|
282
|
+
if (!squadName) {
|
|
283
|
+
console.error('No active squad.');
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const squadPath = getSquadPath(squadName);
|
|
288
|
+
const squadConfig = JSON.parse(fs.readFileSync(path.join(squadPath, 'squad.json'), 'utf8'));
|
|
289
|
+
const agentsPath = path.join(squadPath, 'agents');
|
|
290
|
+
|
|
291
|
+
if (!fs.existsSync(agentsPath)) {
|
|
292
|
+
console.error('No agents configured.');
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const agents = fs.readdirSync(agentsPath).filter(f => {
|
|
297
|
+
return fs.statSync(path.join(agentsPath, f)).isDirectory();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
console.log(`Starting heartbeats for ${agents.length} agents...\n`);
|
|
301
|
+
|
|
302
|
+
// Build task-system-specific guidance
|
|
303
|
+
let taskSystemGuidance = '';
|
|
304
|
+
if (squadConfig.taskSystem === 'linear') {
|
|
305
|
+
taskSystemGuidance = 'Use "linear issues" to check tasks. Post comments via Linear. Use labels for status.';
|
|
306
|
+
} else if (squadConfig.taskSystem === 'trello') {
|
|
307
|
+
taskSystemGuidance = 'Use "trello boards" to find boards. Check cards in lists. Post updates as comments. Move cards between lists for status.';
|
|
308
|
+
} else if (squadConfig.taskSystem === 'github') {
|
|
309
|
+
taskSystemGuidance = 'Use "github issue list" to check tasks. Post comments on issues. Use labels for status.';
|
|
310
|
+
} else {
|
|
311
|
+
taskSystemGuidance = 'Check the configured task system for assigned work.';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
for (const agent of agents) {
|
|
315
|
+
const agentConfig = JSON.parse(fs.readFileSync(
|
|
316
|
+
path.join(agentsPath, agent, 'config.json'),
|
|
317
|
+
'utf8'
|
|
318
|
+
));
|
|
319
|
+
|
|
320
|
+
if (agentConfig.enabled) {
|
|
321
|
+
console.log(` ⏭️ ${agent} (already enabled)`);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Build heartbeat message
|
|
326
|
+
const heartbeatMsg = `You are ${agentConfig.name}, ${agentConfig.role}. Read AGENTS.md and SOUL.md. ${taskSystemGuidance} Check for assigned work, @mentions, and activity. Do your work and post updates. If nothing needs attention, reply HEARTBEAT_OK.`;
|
|
327
|
+
|
|
328
|
+
// Add cron job via openclaw
|
|
329
|
+
try {
|
|
330
|
+
execSync(`openclaw cron add \\
|
|
331
|
+
--name "${squadName}-${agent}-heartbeat" \\
|
|
332
|
+
--cron "${agentConfig.schedule}" \\
|
|
333
|
+
--session "isolated" \\
|
|
334
|
+
--message "${heartbeatMsg}"`, { stdio: 'pipe' });
|
|
335
|
+
|
|
336
|
+
agentConfig.enabled = true;
|
|
337
|
+
fs.writeFileSync(
|
|
338
|
+
path.join(agentsPath, agent, 'config.json'),
|
|
339
|
+
JSON.stringify(agentConfig, null, 2)
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
console.log(` ✅ ${agent} — ${agentConfig.schedule}`);
|
|
343
|
+
} catch (err) {
|
|
344
|
+
console.log(` ❌ ${agent} — failed to add cron`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
console.log('\nHeartbeat cron jobs added.');
|
|
349
|
+
console.log('Agents will wake according to their schedules.');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Stop all heartbeats
|
|
353
|
+
function stopHeartbeats() {
|
|
354
|
+
const config = loadConfig();
|
|
355
|
+
const squadName = config.activeSquad;
|
|
356
|
+
|
|
357
|
+
if (!squadName) {
|
|
358
|
+
console.error('No active squad.');
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const squadPath = getSquadPath(squadName);
|
|
363
|
+
const agentsPath = path.join(squadPath, 'agents');
|
|
364
|
+
|
|
365
|
+
if (!fs.existsSync(agentsPath)) {
|
|
366
|
+
console.log('No agents configured.');
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const agents = fs.readdirSync(agentsPath).filter(f => {
|
|
371
|
+
return fs.statSync(path.join(agentsPath, f)).isDirectory();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log(`Stopping heartbeats for ${agents.length} agents...\n`);
|
|
375
|
+
|
|
376
|
+
for (const agent of agents) {
|
|
377
|
+
const agentConfigPath = path.join(agentsPath, agent, 'config.json');
|
|
378
|
+
const agentConfig = JSON.parse(fs.readFileSync(agentConfigPath, 'utf8'));
|
|
379
|
+
|
|
380
|
+
if (!agentConfig.enabled) {
|
|
381
|
+
console.log(` ⏭️ ${agent} (already disabled)`);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
execSync(`openclaw cron remove --name "${squadName}-${agent}-heartbeat"`, { stdio: 'pipe' });
|
|
387
|
+
|
|
388
|
+
agentConfig.enabled = false;
|
|
389
|
+
fs.writeFileSync(agentConfigPath, JSON.stringify(agentConfig, null, 2));
|
|
390
|
+
|
|
391
|
+
console.log(` ✅ ${agent} — stopped`);
|
|
392
|
+
} catch (err) {
|
|
393
|
+
console.log(` ❌ ${agent} — failed to remove cron`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
console.log('\nHeartbeat cron jobs removed.');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Show squad status
|
|
401
|
+
function showStatus() {
|
|
402
|
+
const config = loadConfig();
|
|
403
|
+
|
|
404
|
+
console.log('Agent Squad Status\n');
|
|
405
|
+
console.log(`Active Squad: ${config.activeSquad || '(none)'}`);
|
|
406
|
+
console.log(`All Squads: ${config.squads.join(', ') || '(none)'}`);
|
|
407
|
+
|
|
408
|
+
if (config.activeSquad) {
|
|
409
|
+
const squadPath = getSquadPath(config.activeSquad);
|
|
410
|
+
const squadConfig = JSON.parse(fs.readFileSync(
|
|
411
|
+
path.join(squadPath, 'squad.json'),
|
|
412
|
+
'utf8'
|
|
413
|
+
));
|
|
414
|
+
|
|
415
|
+
console.log(`\nTask System: ${squadConfig.taskSystem || '(not configured)'}`);
|
|
416
|
+
|
|
417
|
+
const agentsPath = path.join(squadPath, 'agents');
|
|
418
|
+
if (fs.existsSync(agentsPath)) {
|
|
419
|
+
const agents = fs.readdirSync(agentsPath).filter(f => {
|
|
420
|
+
return fs.statSync(path.join(agentsPath, f)).isDirectory();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
console.log(`\nAgents (${agents.length}):`);
|
|
424
|
+
for (const agent of agents) {
|
|
425
|
+
const agentConfig = JSON.parse(fs.readFileSync(
|
|
426
|
+
path.join(agentsPath, agent, 'config.json'),
|
|
427
|
+
'utf8'
|
|
428
|
+
));
|
|
429
|
+
const status = agentConfig.enabled ? '🟢' : '⚪';
|
|
430
|
+
console.log(` ${status} ${agent} — ${agentConfig.role} (${agentConfig.schedule})`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// CLI argument parsing
|
|
437
|
+
function parseArgs(args) {
|
|
438
|
+
const options = {};
|
|
439
|
+
const positional = [];
|
|
440
|
+
|
|
441
|
+
for (let i = 0; i < args.length; i++) {
|
|
442
|
+
if (args[i].startsWith('--')) {
|
|
443
|
+
const key = args[i].slice(2);
|
|
444
|
+
if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
|
|
445
|
+
options[key] = args[i + 1];
|
|
446
|
+
i++;
|
|
447
|
+
} else {
|
|
448
|
+
options[key] = true;
|
|
449
|
+
}
|
|
450
|
+
} else {
|
|
451
|
+
positional.push(args[i]);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return { command: positional[0], args: positional.slice(1), options };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Main
|
|
459
|
+
function main() {
|
|
460
|
+
const { command, args, options } = parseArgs(process.argv.slice(2));
|
|
461
|
+
|
|
462
|
+
switch (command) {
|
|
463
|
+
case 'init':
|
|
464
|
+
initSquad(args[0]);
|
|
465
|
+
break;
|
|
466
|
+
case 'add':
|
|
467
|
+
addAgent(args[0], options);
|
|
468
|
+
break;
|
|
469
|
+
case 'edit':
|
|
470
|
+
editAgent(args[0]);
|
|
471
|
+
break;
|
|
472
|
+
case 'config':
|
|
473
|
+
configTaskSystem(options.tasks, options);
|
|
474
|
+
break;
|
|
475
|
+
case 'start':
|
|
476
|
+
startHeartbeats();
|
|
477
|
+
break;
|
|
478
|
+
case 'stop':
|
|
479
|
+
stopHeartbeats();
|
|
480
|
+
break;
|
|
481
|
+
case 'status':
|
|
482
|
+
showStatus();
|
|
483
|
+
break;
|
|
484
|
+
default:
|
|
485
|
+
console.log('Agent Squad — Multi-agent orchestration for OpenClaw\n');
|
|
486
|
+
console.log('Commands:');
|
|
487
|
+
console.log(' init <name> Create new squad');
|
|
488
|
+
console.log(' add <name> [options] Add agent to squad');
|
|
489
|
+
console.log(' --role "Description"');
|
|
490
|
+
console.log(' --personality skeptical|creative|analytical');
|
|
491
|
+
console.log(' --schedule "*/15 * * * *"');
|
|
492
|
+
console.log(' edit <name> Edit agent SOUL.md');
|
|
493
|
+
console.log(' config --tasks <system> Configure task system');
|
|
494
|
+
console.log(' start Start all heartbeats');
|
|
495
|
+
console.log(' stop Stop all heartbeats');
|
|
496
|
+
console.log(' status Show squad status');
|
|
497
|
+
console.log('\nExample:');
|
|
498
|
+
console.log(' agent-squad init content-squad');
|
|
499
|
+
console.log(' agent-squad add researcher --role "Deep researcher"');
|
|
500
|
+
console.log(' agent-squad config --tasks linear');
|
|
501
|
+
console.log(' agent-squad start');
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
main();
|