swarmdo 1.17.0 → 1.18.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.
@@ -515,7 +515,7 @@ function getCostFromStdin() {
515
515
  // misses, the displayed version is meaningful (matches what the user
516
516
  // installed), not a stale hard-coded string.
517
517
  function getPkgVersion() {
518
- let ver = '1.17.0';
518
+ let ver = '1.18.0';
519
519
  try {
520
520
  const home = os.homedir();
521
521
  const pkgPaths = [
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![swarmdo](swarmdo/assets/brand/logo-full.svg)](https://swarmdo.com)
4
4
 
5
- [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.17.0-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
5
+ [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.18.0-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
6
6
  [![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](https://github.com/SwarmDo/swarmdo/blob/main/LICENSE)
7
7
  [![Website](https://img.shields.io/badge/swarmdo.com-e2a33c?style=for-the-badge&logoColor=black)](https://swarmdo.com)
8
8
  [![Star on GitHub](https://img.shields.io/github/stars/SwarmDo/swarmdo?style=for-the-badge&logo=github&color=gold)](https://github.com/SwarmDo/swarmdo)
@@ -286,6 +286,7 @@ The recent release train added a full day-to-day operations layer around the swa
286
286
  | `swarmdo apply` | **A forgiving `git apply`** — apply a unified diff with fuzzy context matching, so an agent's patch lands even when line numbers have drifted or a context line is slightly off, and reports exactly which hunks couldn't. `--dry-run` to preview, `--fuzz N` to tolerate more drift. Also an MCP tool (`apply_patch`). Deterministic |
287
287
  | `swarmdo hotspots` | **Change-risk hotspots from git history** — rank files by churn × recency × author-spread to surface the technical debt worth refactoring or testing, answered from data instead of a guess. `--since 90d`, `--by risk\|churn\|commits\|authors`, `--top N`, `--format json`. Pairs with `codegraph`; also an MCP tool (`hotspots`). Deterministic |
288
288
  | `swarmdo affected` | **Run only the tests your change touches** — from a git diff, walk `codegraph`'s import graph to list every file (and test file) a change could break (reverse-dependency closure, nx/turbo/`jest --findRelatedTests` style). `--base main`, `--tests` (pipeable list), `--format json`. Also an MCP tool (`affected`). Deterministic |
289
+ | `swarmdo cycles` | **Find circular import dependencies** — an SCC scan over `codegraph`'s import graph surfaces the mutually-importing file groups (and self-imports) that cause temporal-dead-zone and `undefined`-export bugs, `madge --circular` style. `--ci` exits 1 on any cycle to gate a build; `--format json`. Also an MCP tool (`cycles`). Deterministic |
289
290
  | `swarmdo integrations` (alias `integrate`) | **Use swarmdo from Codex CLI, GitHub Copilot CLI, and pi** — one command wires AGENTS.md + each CLI's MCP config (idempotent, dry-run first, never touches your Claude Code setup) |
290
291
  | OpenRouter model pool | **Let swarms pick from any models you configure** — declare tier-mapped OpenRouter models in `swarmdo.config.json`; the router Thompson-samples among them per task and the execution layer dispatches the winner |
291
292
  | `swarmdo changelog` (alias `notes`) | **Release notes from conventional commits** — `--out NOTES.md` feeds `gh release create --notes-file` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmdo",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Swarmdo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `swarmdo cycles` — find circular import dependencies (madge --circular style).
3
+ *
4
+ * swarmdo cycles # report circular imports in the repo
5
+ * swarmdo cycles --ci # exit 1 if any cycle exists (gate a build)
6
+ * swarmdo cycles --format json
7
+ *
8
+ * Composes codegraph's import graph; the detection is a provably-correct SCC
9
+ * scan (../cycles/cycles.ts, pure + tested). This loads or builds the index.
10
+ */
11
+ import type { Command } from '../types.js';
12
+ export declare const cyclesCommand: Command;
13
+ export default cyclesCommand;
14
+ //# sourceMappingURL=cycles.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `swarmdo cycles` — find circular import dependencies (madge --circular style).
3
+ *
4
+ * swarmdo cycles # report circular imports in the repo
5
+ * swarmdo cycles --ci # exit 1 if any cycle exists (gate a build)
6
+ * swarmdo cycles --format json
7
+ *
8
+ * Composes codegraph's import graph; the detection is a provably-correct SCC
9
+ * scan (../cycles/cycles.ts, pure + tested). This loads or builds the index.
10
+ */
11
+ import { output } from '../output.js';
12
+ import { findCycles, formatCycles } from '../cycles/cycles.js';
13
+ import { loadIndex, scanRepo, saveIndex } from '../codegraph/store.js';
14
+ async function run(ctx) {
15
+ const root = ctx.cwd || process.cwd();
16
+ const asJson = ctx.flags.format === 'json';
17
+ const ci = ctx.flags.ci === true;
18
+ let index = loadIndex(root);
19
+ if (!index) {
20
+ index = scanRepo(root);
21
+ try {
22
+ saveIndex(root, index);
23
+ }
24
+ catch { /* read-only fs — index is in memory */ }
25
+ }
26
+ const res = findCycles(index);
27
+ const count = res.cycles.length + res.selfLoops.length;
28
+ if (asJson) {
29
+ process.stdout.write(JSON.stringify({ count, ...res }, null, 2) + '\n');
30
+ }
31
+ else {
32
+ output.writeln(formatCycles(res));
33
+ }
34
+ // In --ci mode, a cycle is a failure; otherwise report and succeed.
35
+ const code = ci && count > 0 ? 1 : 0;
36
+ return { success: code === 0, exitCode: code };
37
+ }
38
+ export const cyclesCommand = {
39
+ name: 'cycles',
40
+ description: 'Find circular import dependencies via the import graph (madge --circular style) — catch the TDZ/undefined-export bugs they cause',
41
+ options: [
42
+ { name: 'ci', description: 'exit 1 if any circular dependency exists (gate a build)', type: 'boolean' },
43
+ ],
44
+ examples: [
45
+ { command: 'swarmdo cycles', description: 'List circular imports in the repo' },
46
+ { command: 'swarmdo cycles --ci', description: 'Fail CI when a cycle is introduced' },
47
+ ],
48
+ action: run,
49
+ };
50
+ export default cyclesCommand;
51
+ //# sourceMappingURL=cycles.js.map
@@ -47,6 +47,9 @@ const commandLoaders = {
47
47
  // Affected-file/test set from a git diff (nx/turbo/jest --findRelatedTests
48
48
  // demand) — reverse-dependency closure over codegraph's import graph.
49
49
  affected: () => import('./affected.js'),
50
+ // Circular-import detector (madge --circular demand) — SCC scan over
51
+ // codegraph's import graph; catches TDZ/undefined-export bugs.
52
+ cycles: () => import('./cycles.js'),
50
53
  // Queryable exported-symbol index (codegraph demand) — where things are
51
54
  // defined without grep+read round-trips.
52
55
  codegraph: () => import('./codegraph.js'),
@@ -280,7 +283,7 @@ export async function getCommandsByCategory() {
280
283
  // three slots from 'statusline' onward (completionsCmd received the
281
284
  // statusline module, analyzeCmd received completions, …), scrambling the
282
285
  // categorized help. Every load now has a named slot.
283
- const [daemonCmd, doctorCmd, embeddingsCmd, neuralCmd, performanceCmd, securityCmd, swarmvectorCmd, hiveMindCmd, configCmd, statuslineCmd, compressCmd, efficiencyCmd, completionsCmd, migrateCmd, workflowCmd, analyzeCmd, routeCmd, progressCmd, providersCmd, pluginsCmd, deploymentCmd, claimsCmd, issuesCmd, updateCmd, processCmd, guidanceCmd, applianceCmd, cleanupCmd, autopilotCmd, demoCmd, usageCmd, repairCmd, hudCmd, compactCmd, codegraphCmd, redactCmd, packCmd, envCmd, licenseCmd, sbomCmd, applyCmd, hotspotsCmd, affectedCmd,] = await Promise.all([
286
+ const [daemonCmd, doctorCmd, embeddingsCmd, neuralCmd, performanceCmd, securityCmd, swarmvectorCmd, hiveMindCmd, configCmd, statuslineCmd, compressCmd, efficiencyCmd, completionsCmd, migrateCmd, workflowCmd, analyzeCmd, routeCmd, progressCmd, providersCmd, pluginsCmd, deploymentCmd, claimsCmd, issuesCmd, updateCmd, processCmd, guidanceCmd, applianceCmd, cleanupCmd, autopilotCmd, demoCmd, usageCmd, repairCmd, hudCmd, compactCmd, codegraphCmd, redactCmd, packCmd, envCmd, licenseCmd, sbomCmd, applyCmd, hotspotsCmd, affectedCmd, cyclesCmd,] = await Promise.all([
284
287
  loadCommand('daemon'), loadCommand('doctor'), loadCommand('embeddings'), loadCommand('neural'),
285
288
  loadCommand('performance'), loadCommand('security'), loadCommand('swarmvector'), loadCommand('hive-mind'),
286
289
  loadCommand('config'), loadCommand('statusline'), loadCommand('compress'), loadCommand('efficiency'),
@@ -288,7 +291,7 @@ export async function getCommandsByCategory() {
288
291
  loadCommand('analyze'), loadCommand('route'), loadCommand('progress'), loadCommand('providers'),
289
292
  loadCommand('plugins'), loadCommand('deployment'), loadCommand('claims'), loadCommand('issues'),
290
293
  loadCommand('update'), loadCommand('process'), loadCommand('guidance'), loadCommand('appliance'),
291
- loadCommand('cleanup'), loadCommand('autopilot'), loadCommand('demo'), loadCommand('usage'), loadCommand('repair'), loadCommand('hud'), loadCommand('compact'), loadCommand('codegraph'), loadCommand('redact'), loadCommand('pack'), loadCommand('env'), loadCommand('license'), loadCommand('sbom'), loadCommand('apply'), loadCommand('hotspots'), loadCommand('affected'),
294
+ loadCommand('cleanup'), loadCommand('autopilot'), loadCommand('demo'), loadCommand('usage'), loadCommand('repair'), loadCommand('hud'), loadCommand('compact'), loadCommand('codegraph'), loadCommand('redact'), loadCommand('pack'), loadCommand('env'), loadCommand('license'), loadCommand('sbom'), loadCommand('apply'), loadCommand('hotspots'), loadCommand('affected'), loadCommand('cycles'),
292
295
  ]);
293
296
  return {
294
297
  primary: [
@@ -304,7 +307,7 @@ export async function getCommandsByCategory() {
304
307
  utility: [
305
308
  configCmd, doctorCmd, daemonCmd, completionsCmd,
306
309
  migrateCmd, workflowCmd, demoCmd,
307
- statuslineCmd, compressCmd, compactCmd, redactCmd, packCmd, envCmd, licenseCmd, sbomCmd, applyCmd, hotspotsCmd, affectedCmd, efficiencyCmd,
310
+ statuslineCmd, compressCmd, compactCmd, redactCmd, packCmd, envCmd, licenseCmd, sbomCmd, applyCmd, hotspotsCmd, affectedCmd, cyclesCmd, efficiencyCmd,
308
311
  ].filter(Boolean),
309
312
  analysis: [
310
313
  analyzeCmd, routeCmd, progressCmd, usageCmd, hudCmd, codegraphCmd,
@@ -0,0 +1,37 @@
1
+ /**
2
+ * cycles.ts — detect circular import dependencies in codegraph's import graph.
3
+ *
4
+ * Circular imports are a real source of bugs: temporal-dead-zone errors,
5
+ * `undefined` exports at module-eval time, and brittle initialization order.
6
+ * `madge --circular` / dpdm / skott exist precisely to surface them. This finds
7
+ * them provably via Tarjan's strongly-connected-components: every SCC with more
8
+ * than one file is a set of mutually-cyclic modules, and a file that imports
9
+ * itself is a one-node cycle.
10
+ *
11
+ * Pure + deterministic (O(V+E), stable sort) — CodeIndex in, cycle groups out.
12
+ * The index load lives in ../commands/cycles.ts, so this is fixture-testable.
13
+ */
14
+ import type { CodeIndex } from '../codegraph/codegraph.js';
15
+ /** Build file → sorted list of internal (resolved) imports. Pure. */
16
+ export declare function buildAdjacency(index: CodeIndex): Map<string, string[]>;
17
+ /**
18
+ * Tarjan's SCC. Returns every strongly-connected component as a member list.
19
+ * Iterative (no recursion) so deep graphs don't overflow the stack. Deterministic:
20
+ * nodes are visited in sorted order and each component is returned sorted.
21
+ */
22
+ export declare function stronglyConnectedComponents(adj: Map<string, string[]>): string[][];
23
+ export interface CycleResult {
24
+ /** each group of ≥2 files that are mutually reachable (a real import cycle) */
25
+ cycles: string[][];
26
+ /** files that import themselves (one-node cycles) */
27
+ selfLoops: string[];
28
+ }
29
+ /**
30
+ * Circular-dependency groups from the import graph. A component is a cycle when
31
+ * it has ≥2 files (mutual reachability) or a single file with a self-edge.
32
+ * Deterministic: groups sorted by size desc then first member.
33
+ */
34
+ export declare function findCycles(index: CodeIndex): CycleResult;
35
+ /** Human-readable summary. Pure. */
36
+ export declare function formatCycles(res: CycleResult): string;
37
+ //# sourceMappingURL=cycles.d.ts.map
@@ -0,0 +1,132 @@
1
+ /**
2
+ * cycles.ts — detect circular import dependencies in codegraph's import graph.
3
+ *
4
+ * Circular imports are a real source of bugs: temporal-dead-zone errors,
5
+ * `undefined` exports at module-eval time, and brittle initialization order.
6
+ * `madge --circular` / dpdm / skott exist precisely to surface them. This finds
7
+ * them provably via Tarjan's strongly-connected-components: every SCC with more
8
+ * than one file is a set of mutually-cyclic modules, and a file that imports
9
+ * itself is a one-node cycle.
10
+ *
11
+ * Pure + deterministic (O(V+E), stable sort) — CodeIndex in, cycle groups out.
12
+ * The index load lives in ../commands/cycles.ts, so this is fixture-testable.
13
+ */
14
+ /** Build file → sorted list of internal (resolved) imports. Pure. */
15
+ export function buildAdjacency(index) {
16
+ const adj = new Map();
17
+ const ensure = (f) => {
18
+ let l = adj.get(f);
19
+ if (!l) {
20
+ l = [];
21
+ adj.set(f, l);
22
+ }
23
+ return l;
24
+ };
25
+ for (const e of index.imports) {
26
+ if (!e.resolved)
27
+ continue; // external — not part of internal cycles
28
+ const l = ensure(e.from);
29
+ if (!l.includes(e.resolved))
30
+ l.push(e.resolved);
31
+ ensure(e.resolved); // make sure the target is a node too
32
+ }
33
+ for (const l of adj.values())
34
+ l.sort();
35
+ return adj;
36
+ }
37
+ /**
38
+ * Tarjan's SCC. Returns every strongly-connected component as a member list.
39
+ * Iterative (no recursion) so deep graphs don't overflow the stack. Deterministic:
40
+ * nodes are visited in sorted order and each component is returned sorted.
41
+ */
42
+ export function stronglyConnectedComponents(adj) {
43
+ let idx = 0;
44
+ const index = new Map();
45
+ const low = new Map();
46
+ const onStack = new Set();
47
+ const stack = [];
48
+ const out = [];
49
+ const nodes = [...adj.keys()].sort();
50
+ for (const start of nodes) {
51
+ if (index.has(start))
52
+ continue;
53
+ // Iterative DFS with an explicit work stack of (node, next-child-index).
54
+ const work = [{ node: start, i: 0 }];
55
+ while (work.length > 0) {
56
+ const frame = work[work.length - 1];
57
+ const { node } = frame;
58
+ if (frame.i === 0) {
59
+ index.set(node, idx);
60
+ low.set(node, idx);
61
+ idx++;
62
+ stack.push(node);
63
+ onStack.add(node);
64
+ }
65
+ const children = adj.get(node) ?? [];
66
+ if (frame.i < children.length) {
67
+ const next = children[frame.i];
68
+ frame.i++;
69
+ if (!index.has(next)) {
70
+ work.push({ node: next, i: 0 });
71
+ }
72
+ else if (onStack.has(next)) {
73
+ low.set(node, Math.min(low.get(node), index.get(next)));
74
+ }
75
+ }
76
+ else {
77
+ // Done with node — if it's a root, pop its SCC.
78
+ if (low.get(node) === index.get(node)) {
79
+ const comp = [];
80
+ for (;;) {
81
+ const w = stack.pop();
82
+ onStack.delete(w);
83
+ comp.push(w);
84
+ if (w === node)
85
+ break;
86
+ }
87
+ out.push(comp.sort());
88
+ }
89
+ work.pop();
90
+ if (work.length > 0) {
91
+ const parent = work[work.length - 1].node;
92
+ low.set(parent, Math.min(low.get(parent), low.get(node)));
93
+ }
94
+ }
95
+ }
96
+ }
97
+ return out;
98
+ }
99
+ /**
100
+ * Circular-dependency groups from the import graph. A component is a cycle when
101
+ * it has ≥2 files (mutual reachability) or a single file with a self-edge.
102
+ * Deterministic: groups sorted by size desc then first member.
103
+ */
104
+ export function findCycles(index) {
105
+ const adj = buildAdjacency(index);
106
+ const selfLoops = [];
107
+ for (const [from, tos] of adj)
108
+ if (tos.includes(from))
109
+ selfLoops.push(from);
110
+ selfLoops.sort();
111
+ const cycles = stronglyConnectedComponents(adj)
112
+ .filter((c) => c.length >= 2)
113
+ .sort((a, b) => b.length - a.length || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
114
+ return { cycles, selfLoops };
115
+ }
116
+ /** Human-readable summary. Pure. */
117
+ export function formatCycles(res) {
118
+ if (res.cycles.length === 0 && res.selfLoops.length === 0)
119
+ return 'no circular imports found ✓';
120
+ const lines = [];
121
+ res.cycles.forEach((c, i) => {
122
+ lines.push(`cycle ${i + 1} (${c.length} files):`);
123
+ for (const f of c)
124
+ lines.push(` ${f}`);
125
+ });
126
+ for (const s of res.selfLoops)
127
+ lines.push(`self-import: ${s}`);
128
+ const n = res.cycles.length + res.selfLoops.length;
129
+ lines.push(`${n} circular ${n === 1 ? 'dependency' : 'dependencies'} found`);
130
+ return lines.join('\n');
131
+ }
132
+ //# sourceMappingURL=cycles.js.map
@@ -26,6 +26,7 @@ import { licenseTools } from './mcp-tools/license-tools.js';
26
26
  import { applyTools } from './mcp-tools/apply-tools.js';
27
27
  import { hotspotsTools } from './mcp-tools/hotspots-tools.js';
28
28
  import { affectedTools } from './mcp-tools/affected-tools.js';
29
+ import { cyclesTools } from './mcp-tools/cycles-tools.js';
29
30
  import { progressTools } from './mcp-tools/progress-tools.js';
30
31
  import { embeddingsTools } from './mcp-tools/embeddings-tools.js';
31
32
  import { claimsTools } from './mcp-tools/claims-tools.js';
@@ -116,6 +117,7 @@ const TOOL_GROUPS = {
116
117
  apply: () => applyTools,
117
118
  hotspots: () => hotspotsTools,
118
119
  affected: () => affectedTools,
120
+ cycles: () => cyclesTools,
119
121
  progress: () => progressTools,
120
122
  embeddings: () => embeddingsTools,
121
123
  claims: () => claimsTools,
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cycles MCP Tool
3
+ *
4
+ * Let an agent check for circular import dependencies before it commits — the
5
+ * TDZ/undefined-export bugs that `madge --circular` catches. Returns the cycle
6
+ * groups (and self-imports) found in the repo's import graph. Shares the pure
7
+ * SCC engine in ../cycles/cycles.ts; loads (or builds) the codegraph index.
8
+ */
9
+ import type { MCPTool } from './types.js';
10
+ export declare const cyclesTools: MCPTool[];
11
+ //# sourceMappingURL=cycles-tools.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Cycles MCP Tool
3
+ *
4
+ * Let an agent check for circular import dependencies before it commits — the
5
+ * TDZ/undefined-export bugs that `madge --circular` catches. Returns the cycle
6
+ * groups (and self-imports) found in the repo's import graph. Shares the pure
7
+ * SCC engine in ../cycles/cycles.ts; loads (or builds) the codegraph index.
8
+ */
9
+ import { findCycles } from '../cycles/cycles.js';
10
+ import { loadIndex, scanRepo } from '../codegraph/store.js';
11
+ const cyclesTool = {
12
+ name: 'cycles',
13
+ description: 'Find circular import dependencies in the repo via the import graph (madge --circular style). Returns the cyclic file groups — call this after wiring up modules to catch temporal-dead-zone / undefined-export bugs before they bite. Composes codegraph.',
14
+ category: 'cycles',
15
+ tags: ['imports', 'circular', 'graph', 'lint'],
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ path: { type: 'string', description: 'repo root to analyze (default cwd)' },
20
+ },
21
+ },
22
+ handler: async (params) => {
23
+ const root = typeof params.path === 'string' ? params.path : process.cwd();
24
+ const index = loadIndex(root) ?? scanRepo(root);
25
+ const res = findCycles(index);
26
+ return { count: res.cycles.length + res.selfLoops.length, ...res };
27
+ },
28
+ };
29
+ export const cyclesTools = [cyclesTool];
30
+ //# sourceMappingURL=cycles-tools.js.map
@@ -22,6 +22,7 @@ export { licenseTools } from './license-tools.js';
22
22
  export { applyTools } from './apply-tools.js';
23
23
  export { hotspotsTools } from './hotspots-tools.js';
24
24
  export { affectedTools } from './affected-tools.js';
25
+ export { cyclesTools } from './cycles-tools.js';
25
26
  export { progressTools } from './progress-tools.js';
26
27
  export { transferTools } from './transfer-tools.js';
27
28
  export { securityTools } from './security-tools.js';
@@ -21,6 +21,7 @@ export { licenseTools } from './license-tools.js';
21
21
  export { applyTools } from './apply-tools.js';
22
22
  export { hotspotsTools } from './hotspots-tools.js';
23
23
  export { affectedTools } from './affected-tools.js';
24
+ export { cyclesTools } from './cycles-tools.js';
24
25
  export { progressTools } from './progress-tools.js';
25
26
  export { transferTools } from './transfer-tools.js';
26
27
  export { securityTools } from './security-tools.js';
@@ -28,6 +28,7 @@ const LEAN_GROUPS = [
28
28
  'apply', // apply_patch — fuzzy unified-diff applier for agent edits
29
29
  'hotspots', // hotspots — git-history change-risk ranking ("where's the debt?")
30
30
  'affected', // affected — impacted files/tests from a change via the import graph
31
+ 'cycles', // cycles — circular-import detection via the import graph
31
32
  ];
32
33
  /** Balanced = lean + orchestration/session/system the average user reaches for. */
33
34
  const BALANCED_EXTRA = [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmdo/cli",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "description": "Swarmdo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",