swarmlancer-cli 0.5.1 → 0.5.2

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/app.js CHANGED
@@ -19,7 +19,7 @@ import { MessageScreen } from "./screens/message.js";
19
19
  import { screenProfiles } from "./screening.js";
20
20
  let terminal;
21
21
  let tui;
22
- let runningAgentId; // tracks which agent is online (⚡)
22
+ let runningAgentId;
23
23
  function setScreen(component) {
24
24
  tui.clear();
25
25
  tui.addChild(component);
@@ -48,7 +48,6 @@ function confirm(question) {
48
48
  // ── Silent setup ──────────────────────────────────────────
49
49
  async function silentSetup() {
50
50
  migrateLegacyAgent();
51
- // Auto-login if not logged in
52
51
  const config = getConfig();
53
52
  if (!config.token) {
54
53
  try {
@@ -69,12 +68,7 @@ function askName(title, subtitle, current = "") {
69
68
  function editInstructions(agent) {
70
69
  return new Promise((resolve) => {
71
70
  const screen = new AgentEditorScreen(tui, agent.instructions);
72
- screen.onSave = async (newContent) => {
73
- agent.instructions = newContent;
74
- saveAgent(agent);
75
- await showMessage("Saved", ["Agent instructions updated."], "success");
76
- resolve();
77
- };
71
+ screen.onSave = async (c) => { agent.instructions = c; saveAgent(agent); resolve(); };
78
72
  screen.onCancel = () => resolve();
79
73
  setScreen(screen);
80
74
  });
@@ -82,12 +76,7 @@ function editInstructions(agent) {
82
76
  function editLimits(agent) {
83
77
  return new Promise((resolve) => {
84
78
  const screen = new SettingsScreen(tui, agent.limits);
85
- screen.onSave = async (newLimits) => {
86
- agent.limits = newLimits;
87
- saveAgent(agent);
88
- await showMessage("Saved", ["Agent limits updated."], "success");
89
- resolve();
90
- };
79
+ screen.onSave = async (l) => { agent.limits = l; saveAgent(agent); resolve(); };
91
80
  screen.onCancel = () => resolve();
92
81
  setScreen(screen);
93
82
  });
@@ -95,12 +84,7 @@ function editLimits(agent) {
95
84
  function editDiscovery(agent) {
96
85
  return new Promise((resolve) => {
97
86
  const screen = new DiscoverySettingsScreen(tui, agent.discovery);
98
- screen.onSave = async (newSettings) => {
99
- agent.discovery = newSettings;
100
- saveAgent(agent);
101
- await showMessage("Saved", ["Discovery settings updated."], "success");
102
- resolve();
103
- };
87
+ screen.onSave = async (s) => { agent.discovery = s; saveAgent(agent); resolve(); };
104
88
  screen.onCancel = () => resolve();
105
89
  setScreen(screen);
106
90
  });
@@ -109,15 +93,14 @@ function editModel(agent) {
109
93
  return new Promise(async (resolve) => {
110
94
  const models = getAvailableModels();
111
95
  if (models.length === 0) {
112
- await showMessage("No models", ["No provider API keys configured.", "Add one in Swarm → Providers."], "error");
96
+ await showMessage("No models", ["No provider API keys configured.", "Add one in Manage → Providers."], "error");
113
97
  resolve();
114
98
  return;
115
99
  }
116
100
  const screen = new ModelPickerScreen(tui, models);
117
- screen.onSelect = async (model) => {
118
- agent.modelPattern = `${model.provider}/${model.id}`;
101
+ screen.onSelect = async (m) => {
102
+ agent.modelPattern = `${m.provider}/${m.id}`;
119
103
  saveAgent(agent);
120
- await showMessage("Model selected", [`${model.provider}/${model.id}`], "success");
121
104
  resolve();
122
105
  };
123
106
  screen.onCancel = () => resolve();
@@ -132,27 +115,29 @@ function pickAgent() {
132
115
  return Promise.resolve(agents[0]);
133
116
  return new Promise((resolve) => {
134
117
  const screen = new AgentPickerScreen(tui, agents);
135
- screen.onSelect = (agent) => resolve(agent);
118
+ screen.onSelect = (a) => resolve(a);
136
119
  screen.onCancel = () => resolve(null);
137
120
  setScreen(screen);
138
121
  });
139
122
  }
140
123
  // ── Agent config ──────────────────────────────────────────
141
124
  async function runAgentConfig(agentId) {
125
+ let idx = 0;
142
126
  while (true) {
143
127
  const agent = getAgent(agentId);
144
128
  if (!agent)
145
129
  return;
146
130
  const action = await new Promise((resolve) => {
147
- const screen = new AgentConfigScreen(tui, agent);
148
- screen.onAction = resolve;
131
+ const screen = new AgentConfigScreen(tui, agent, idx);
132
+ screen.onAction = (a, i) => resolve({ action: a, index: i });
149
133
  setScreen(screen);
150
134
  });
151
- switch (action) {
135
+ idx = action.index >= 0 ? action.index : idx;
136
+ switch (action.action) {
152
137
  case "edit-name": {
153
- const newName = await askName("Rename Agent", "Enter a new name.", agent.name);
154
- if (newName) {
155
- agent.name = newName;
138
+ const n = await askName("Rename Agent", "Enter a new name.", agent.name);
139
+ if (n) {
140
+ agent.name = n;
156
141
  saveAgent(agent);
157
142
  }
158
143
  break;
@@ -181,33 +166,9 @@ async function runAgentConfig(agentId) {
181
166
  }
182
167
  }
183
168
  }
184
- // ── Swarm screen ──────────────────────────────────────────
185
- async function runManageTop() {
186
- while (true) {
187
- const action = await new Promise((resolve) => {
188
- const items = [
189
- { value: "swarm", label: "Swarm", description: "" },
190
- { value: "providers", label: "Providers", description: "" },
191
- ];
192
- const screen = new MenuScreen(tui, "Manage", items);
193
- screen.onSelect = (v) => resolve(v);
194
- screen.onBack = () => resolve(null);
195
- setScreen(screen);
196
- });
197
- if (!action)
198
- return;
199
- switch (action) {
200
- case "swarm":
201
- await runSwarm();
202
- break;
203
- case "providers":
204
- await runProviders();
205
- break;
206
- }
207
- }
208
- }
209
- // ── Manage screen ─────────────────────────────────────────
169
+ // ── Manage → Swarm (agents) ──────────────────────────────
210
170
  async function runSwarm() {
171
+ let idx = 0;
211
172
  while (true) {
212
173
  const agents = getAgents();
213
174
  const items = [
@@ -216,54 +177,49 @@ async function runSwarm() {
216
177
  for (const agent of agents) {
217
178
  const isRunning = agent.id === runningAgentId;
218
179
  const suffix = isRunning ? " [⚡]" : "";
219
- items.push({
220
- value: agent.id,
221
- label: `${agent.name}${suffix}`,
222
- description: "",
223
- });
180
+ items.push({ value: agent.id, label: `${agent.name}${suffix}`, description: "" });
224
181
  }
225
- const action = await new Promise((resolve) => {
226
- const screen = new MenuScreen(tui, "Swarm", items);
227
- screen.onSelect = (v) => resolve(v);
228
- screen.onBack = () => resolve(null);
182
+ const result = await new Promise((resolve) => {
183
+ const screen = new MenuScreen(tui, "Swarm", items, idx);
184
+ screen.onSelect = (v, i) => resolve({ value: v, index: i });
185
+ screen.onBack = () => resolve({ value: null, index: idx });
229
186
  setScreen(screen);
230
187
  });
231
- if (!action)
188
+ if (!result.value)
232
189
  return;
233
- if (action === "__create__") {
190
+ idx = result.index;
191
+ if (result.value === "__create__") {
234
192
  const name = await askName("New Agent", "Give your agent a name.");
235
193
  if (name) {
236
- const agent = createAgent(name);
237
- await runAgentConfig(agent.id);
194
+ const a = createAgent(name);
195
+ await runAgentConfig(a.id);
238
196
  }
239
197
  }
240
198
  else {
241
- await runAgentConfig(action);
199
+ await runAgentConfig(result.value);
242
200
  }
243
201
  }
244
202
  }
245
- // ── Providers screen ──────────────────────────────────────
203
+ // ── Manage → Providers ────────────────────────────────────
246
204
  async function runProviders() {
205
+ let idx = 0;
247
206
  while (true) {
248
207
  const items = PROVIDERS.map((p) => {
249
208
  const loggedIn = isProviderAuthenticated(p.id);
250
209
  const prefix = loggedIn ? "→ " : " ";
251
210
  const suffix = loggedIn ? " ✓ logged in" : "";
252
- return {
253
- value: p.id,
254
- label: `${prefix}${p.label}${suffix}`,
255
- description: "",
256
- };
211
+ return { value: p.id, label: `${prefix}${p.label}${suffix}`, description: "" };
257
212
  });
258
- const action = await new Promise((resolve) => {
259
- const screen = new MenuScreen(tui, "Providers", items);
260
- screen.onSelect = (v) => resolve(v);
261
- screen.onBack = () => resolve(null);
213
+ const result = await new Promise((resolve) => {
214
+ const screen = new MenuScreen(tui, "Providers", items, idx);
215
+ screen.onSelect = (v, i) => resolve({ value: v, index: i });
216
+ screen.onBack = () => resolve({ value: null, index: idx });
262
217
  setScreen(screen);
263
218
  });
264
- if (!action)
219
+ if (!result.value)
265
220
  return;
266
- const provider = PROVIDERS.find((p) => p.id === action);
221
+ idx = result.index;
222
+ const provider = PROVIDERS.find((p) => p.id === result.value);
267
223
  if (!provider)
268
224
  continue;
269
225
  if (!provider.keyBased) {
@@ -277,6 +233,33 @@ async function runProviders() {
277
233
  }
278
234
  }
279
235
  }
236
+ // ── Manage (top) ──────────────────────────────────────────
237
+ async function runManageTop() {
238
+ let idx = 0;
239
+ while (true) {
240
+ const result = await new Promise((resolve) => {
241
+ const items = [
242
+ { value: "swarm", label: "Swarm", description: "" },
243
+ { value: "providers", label: "Providers", description: "" },
244
+ ];
245
+ const screen = new MenuScreen(tui, "Manage", items, idx);
246
+ screen.onSelect = (v, i) => resolve({ value: v, index: i });
247
+ screen.onBack = () => resolve({ value: null, index: idx });
248
+ setScreen(screen);
249
+ });
250
+ if (!result.value)
251
+ return;
252
+ idx = result.index;
253
+ switch (result.value) {
254
+ case "swarm":
255
+ await runSwarm();
256
+ break;
257
+ case "providers":
258
+ await runProviders();
259
+ break;
260
+ }
261
+ }
262
+ }
280
263
  // ── Go online ─────────────────────────────────────────────
281
264
  async function fetchCandidates(discovery) {
282
265
  const config = getConfig();
@@ -309,7 +292,7 @@ async function goOnline() {
309
292
  return;
310
293
  const resolved = resolveModel(agent.modelPattern);
311
294
  if (!resolved) {
312
- await showMessage("No model", ["No provider API keys configured.", "Add one in Swarm → Providers."], "error");
295
+ await showMessage("No model", ["No provider API keys configured.", "Add one in Manage → Providers."], "error");
313
296
  return;
314
297
  }
315
298
  setActiveModel(resolved.provider, resolved.model);
@@ -317,19 +300,16 @@ async function goOnline() {
317
300
  runningAgentId = agent.id;
318
301
  const modelInfo = { provider: resolved.provider, id: resolved.model, name: resolved.model };
319
302
  const config = getConfig();
320
- const discovery = agent.discovery;
321
- const limits = agent.limits;
322
303
  const screen = new AgentRunningScreen(tui, modelInfo, config.serverUrl, agent.name);
323
304
  const done = new Promise((resolve) => {
324
305
  screen.onStop = () => { stopAgent(); runningAgentId = undefined; resolve(); };
325
306
  });
326
307
  setScreen(screen);
327
308
  const log = (line) => screen.addLog(line);
328
- startAgent(limits, agent.id, agent.name, log);
329
- // Discovery
309
+ startAgent(agent.limits, agent.id, agent.name, log);
330
310
  screen.setStatus("discovering candidates...");
331
311
  try {
332
- const candidates = await fetchCandidates(discovery);
312
+ const candidates = await fetchCandidates(agent.discovery);
333
313
  if (candidates.length === 0) {
334
314
  log(colors.gray("No candidates match your discovery filters."));
335
315
  screen.setStatus("waiting for conversations...");
@@ -337,14 +317,14 @@ async function goOnline() {
337
317
  else {
338
318
  log(colors.lime(`📡 Found ${candidates.length} candidates, screening...`));
339
319
  screen.setStatus(`screening ${candidates.length} profiles...`);
340
- const results = await screenProfiles(candidates, agent.instructions, "", discovery.matchThreshold, discovery.maxScreenPerSession, (screened, total, result) => {
341
- const icon = result.score >= discovery.matchThreshold ? colors.lime("✓") : colors.gray("⊘");
342
- const scoreStr = result.score >= discovery.matchThreshold
320
+ const results = await screenProfiles(candidates, agent.instructions, "", agent.discovery.matchThreshold, agent.discovery.maxScreenPerSession, (screened, total, result) => {
321
+ const icon = result.score >= agent.discovery.matchThreshold ? colors.lime("✓") : colors.gray("⊘");
322
+ const scoreStr = result.score >= agent.discovery.matchThreshold
343
323
  ? colors.lime(`${result.score}/10`) : colors.gray(`${result.score}/10`);
344
324
  log(` ${icon} @${result.profile.githubUsername} ${scoreStr} — ${colors.gray(result.reason)}`);
345
325
  screen.setStatus(`screening ${screened}/${total}...`);
346
326
  });
347
- const matches = results.filter((r) => r.score >= discovery.matchThreshold);
327
+ const matches = results.filter((r) => r.score >= agent.discovery.matchThreshold);
348
328
  log("");
349
329
  if (matches.length === 0) {
350
330
  log(colors.lime("No strong matches. Waiting for incoming conversations..."));
@@ -358,8 +338,8 @@ async function goOnline() {
358
338
  }
359
339
  log(colors.lime(` 🤝 @${match.profile.githubUsername} (${match.score}/10)`));
360
340
  sendToServer({ type: "start_conversation", withUserId: match.profile.id });
361
- if (limits.cooldownSeconds > 0)
362
- await new Promise((r) => setTimeout(r, limits.cooldownSeconds * 1000));
341
+ if (agent.limits.cooldownSeconds > 0)
342
+ await new Promise((r) => setTimeout(r, agent.limits.cooldownSeconds * 1000));
363
343
  }
364
344
  }
365
345
  screen.setStatus(`${matches.length} matches • waiting for conversations...`);
@@ -373,13 +353,15 @@ async function goOnline() {
373
353
  }
374
354
  // ── Dashboard loop ────────────────────────────────────────
375
355
  async function runDashboard() {
356
+ let idx = 0;
376
357
  while (true) {
377
- const action = await new Promise((resolve) => {
378
- const dashboard = new DashboardScreen(tui);
379
- dashboard.onAction = resolve;
358
+ const result = await new Promise((resolve) => {
359
+ const dashboard = new DashboardScreen(tui, idx);
360
+ dashboard.onAction = (a, i) => resolve({ action: a, index: i });
380
361
  setScreen(dashboard);
381
362
  });
382
- switch (action) {
363
+ idx = result.index;
364
+ switch (result.action) {
383
365
  case "start": {
384
366
  const sure = await confirm("Go online?");
385
367
  if (sure)
@@ -6,8 +6,8 @@ export declare class AgentConfigScreen implements Component {
6
6
  private container;
7
7
  private selectList;
8
8
  private tui;
9
- onAction?: (action: AgentConfigAction) => void;
10
- constructor(tui: TUI, agent: AgentProfile);
9
+ onAction?: (action: AgentConfigAction, index: number) => void;
10
+ constructor(tui: TUI, agent: AgentProfile, initialIndex?: number);
11
11
  handleInput(data: string): void;
12
12
  render(width: number): string[];
13
13
  invalidate(): void;
@@ -1,15 +1,16 @@
1
- import { Container, Text, Spacer, SelectList, truncateToWidth, } from "@mariozechner/pi-tui";
1
+ import { Container, Text, Spacer, SelectList, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
2
  import { colors, theme } from "../theme.js";
3
+ import { BannerComponent } from "./banner.js";
3
4
  export class AgentConfigScreen {
4
5
  container;
5
6
  selectList;
6
7
  tui;
7
8
  onAction;
8
- constructor(tui, agent) {
9
+ constructor(tui, agent, initialIndex = 0) {
9
10
  this.tui = tui;
10
11
  this.container = new Container();
11
- this.container.addChild(new Spacer(1));
12
- this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
12
+ // Banner
13
+ this.container.addChild(new BannerComponent());
13
14
  this.container.addChild(new Text(theme.title(` Agent: ${agent.name}`), 1, 0));
14
15
  this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
15
16
  this.container.addChild(new Spacer(1));
@@ -42,15 +43,28 @@ export class AgentConfigScreen {
42
43
  scrollInfo: (t) => colors.gray(t),
43
44
  noMatch: (t) => colors.gray(t),
44
45
  });
46
+ if (initialIndex > 0) {
47
+ this.selectList.setSelectedIndex(initialIndex);
48
+ }
45
49
  this.selectList.onSelect = (item) => {
46
- this.onAction?.(item.value);
50
+ const idx = items.findIndex((i) => i.value === item.value);
51
+ this.onAction?.(item.value, idx);
47
52
  };
48
- this.selectList.onCancel = () => this.onAction?.("back");
53
+ this.selectList.onCancel = () => this.onAction?.("back", -1);
49
54
  this.container.addChild(this.selectList);
50
55
  this.container.addChild(new Spacer(1));
51
- this.container.addChild(new Text(colors.gray(" ↑↓ navigate • enter select • esc back"), 1, 0));
56
+ this.container.addChild(new Text(colors.gray(" ↑↓ navigate • →/enter select • ←/esc back"), 1, 0));
52
57
  }
53
58
  handleInput(data) {
59
+ if (matchesKey(data, Key.left)) {
60
+ this.onAction?.("back", -1);
61
+ return;
62
+ }
63
+ if (matchesKey(data, Key.right)) {
64
+ this.selectList.handleInput("\r");
65
+ this.tui.requestRender();
66
+ return;
67
+ }
54
68
  this.selectList.handleInput(data);
55
69
  this.tui.requestRender();
56
70
  }
@@ -5,8 +5,8 @@ export declare class DashboardScreen implements Component {
5
5
  private container;
6
6
  private selectList;
7
7
  private tui;
8
- onAction?: (action: DashboardAction) => void;
9
- constructor(tui: TUI);
8
+ onAction?: (action: DashboardAction, index: number) => void;
9
+ constructor(tui: TUI, initialIndex?: number);
10
10
  handleInput(data: string): void;
11
11
  render(width: number): string[];
12
12
  invalidate(): void;
@@ -11,7 +11,7 @@ export class DashboardScreen {
11
11
  selectList;
12
12
  tui;
13
13
  onAction;
14
- constructor(tui) {
14
+ constructor(tui, initialIndex = 0) {
15
15
  this.tui = tui;
16
16
  this.container = new Container();
17
17
  this.container.addChild(new BannerComponent());
@@ -22,8 +22,12 @@ export class DashboardScreen {
22
22
  scrollInfo: (t) => colors.gray(t),
23
23
  noMatch: (t) => colors.gray(t),
24
24
  });
25
+ if (initialIndex > 0) {
26
+ this.selectList.setSelectedIndex(initialIndex);
27
+ }
25
28
  this.selectList.onSelect = (item) => {
26
- this.onAction?.(item.value);
29
+ const idx = MENU_ITEMS.findIndex((i) => i.value === item.value);
30
+ this.onAction?.(item.value, idx);
27
31
  };
28
32
  this.container.addChild(this.selectList);
29
33
  this.container.addChild(new Spacer(1));
@@ -31,7 +35,7 @@ export class DashboardScreen {
31
35
  }
32
36
  handleInput(data) {
33
37
  if (matchesKey(data, "q")) {
34
- this.onAction?.("exit");
38
+ this.onAction?.("exit", 2);
35
39
  return;
36
40
  }
37
41
  if (matchesKey(data, Key.right)) {
@@ -1,16 +1,17 @@
1
1
  import { type SelectItem, type Component } from "@mariozechner/pi-tui";
2
2
  import type { TUI } from "@mariozechner/pi-tui";
3
3
  /**
4
- * Reusable menu screen with title, items, and left/right/enter/esc navigation.
4
+ * Reusable menu screen with banner, title, items, and left/right/enter/esc navigation.
5
5
  * Enter or Right = select, Left or Esc = back.
6
6
  */
7
7
  export declare class MenuScreen implements Component {
8
8
  private container;
9
9
  private selectList;
10
10
  private tui;
11
- onSelect?: (value: string) => void;
11
+ private items;
12
+ onSelect?: (value: string, index: number) => void;
12
13
  onBack?: () => void;
13
- constructor(tui: TUI, title: string, items: SelectItem[], subtitle?: string);
14
+ constructor(tui: TUI, title: string, items: SelectItem[], initialIndex?: number);
14
15
  handleInput(data: string): void;
15
16
  render(width: number): string[];
16
17
  invalidate(): void;
@@ -1,24 +1,24 @@
1
1
  import { Container, Text, Spacer, SelectList, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
2
  import { colors, theme } from "../theme.js";
3
+ import { BannerComponent } from "./banner.js";
3
4
  /**
4
- * Reusable menu screen with title, items, and left/right/enter/esc navigation.
5
+ * Reusable menu screen with banner, title, items, and left/right/enter/esc navigation.
5
6
  * Enter or Right = select, Left or Esc = back.
6
7
  */
7
8
  export class MenuScreen {
8
9
  container;
9
10
  selectList;
10
11
  tui;
12
+ items;
11
13
  onSelect;
12
14
  onBack;
13
- constructor(tui, title, items, subtitle) {
15
+ constructor(tui, title, items, initialIndex = 0) {
14
16
  this.tui = tui;
17
+ this.items = items;
15
18
  this.container = new Container();
16
- this.container.addChild(new Spacer(1));
17
- this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
19
+ // Banner always shown
20
+ this.container.addChild(new BannerComponent());
18
21
  this.container.addChild(new Text(theme.title(` ${title}`), 1, 0));
19
- if (subtitle) {
20
- this.container.addChild(new Text(colors.gray(` ${subtitle}`), 1, 0));
21
- }
22
22
  this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
23
23
  this.container.addChild(new Spacer(1));
24
24
  this.selectList = new SelectList(items, Math.min(items.length, 15), {
@@ -28,21 +28,24 @@ export class MenuScreen {
28
28
  scrollInfo: (t) => colors.gray(t),
29
29
  noMatch: (t) => colors.gray(t),
30
30
  });
31
- this.selectList.onSelect = (item) => this.onSelect?.(item.value);
31
+ if (initialIndex > 0) {
32
+ this.selectList.setSelectedIndex(initialIndex);
33
+ }
34
+ this.selectList.onSelect = (item) => {
35
+ const idx = this.items.findIndex((i) => i.value === item.value);
36
+ this.onSelect?.(item.value, idx);
37
+ };
32
38
  this.selectList.onCancel = () => this.onBack?.();
33
39
  this.container.addChild(this.selectList);
34
40
  this.container.addChild(new Spacer(1));
35
41
  this.container.addChild(new Text(colors.gray(" ↑↓ navigate • →/enter select • ←/esc back"), 1, 0));
36
42
  }
37
43
  handleInput(data) {
38
- // Right arrow = enter
39
44
  if (matchesKey(data, Key.right)) {
40
- // Simulate enter by triggering current selection
41
45
  this.selectList.handleInput("\r");
42
46
  this.tui.requestRender();
43
47
  return;
44
48
  }
45
- // Left arrow = back
46
49
  if (matchesKey(data, Key.left)) {
47
50
  this.onBack?.();
48
51
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmlancer-cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Swarmlancer CLI — let the swarm begin. Connect your AI agent to a network of other agents.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",