swarmdo 1.58.1 → 1.58.6

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.
@@ -331,8 +331,8 @@ function buildLocalFallback() {
331
331
  user: { name: 'user', gitBranch: '', modelName: 'Claude Code' },
332
332
  v3Progress: { domainsCompleted: 0, totalDomains: 5, dddProgress: 0, patternsLearned: 0, sessionsCompleted: 0 },
333
333
  security: { status: 'NONE', critical: 0, high: 0, total: 0 },
334
- swarm: { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false },
335
- system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0, subAgents: 0 },
334
+ swarm: { activeSwarms: 0, activeAgents: 0, coordinationActive: false },
335
+ system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0 },
336
336
  lastUpdated: new Date().toISOString(),
337
337
  });
338
338
  }
@@ -522,7 +522,7 @@ function getCostFromStdin() {
522
522
  // misses, the displayed version is meaningful (matches what the user
523
523
  // installed), not a stale hard-coded string.
524
524
  function getPkgVersion() {
525
- let ver = '1.58.0';
525
+ let ver = '1.58.4';
526
526
  try {
527
527
  const home = os.homedir();
528
528
  const pkgPaths = [
@@ -592,12 +592,11 @@ function generateStatusline() {
592
592
  const totalDomains = progress.totalDomains || 5;
593
593
  const dddProgress = progress.dddProgress || 0;
594
594
  const patternsLearned = progress.patternsLearned || 0;
595
+ const activeSwarms = swarm.activeSwarms || 0;
595
596
  const activeAgents = swarm.activeAgents || 0;
596
- const maxAgents = swarm.maxAgents || CONFIG.maxAgents;
597
597
  const coordinationActive = swarm.coordinationActive || false;
598
598
  const intelligencePct = system.intelligencePct || 0;
599
599
  const memoryMB = system.memoryMB || 0;
600
- const subAgents = system.subAgents || 0;
601
600
  const secCritHigh = (security.critical || 0) + (security.high || 0);
602
601
  const secStatus = security.status || 'NONE';
603
602
  const secLabel = secStatus === 'VULN' ? 'sec ' + secCritHigh + '!' : secStatus === 'CLEAN' ? 'sec ✓' : secStatus === 'STALE' ? 'sec stale' : 'sec —';
@@ -664,16 +663,16 @@ function generateStatusline() {
664
663
  );
665
664
 
666
665
  // Line 2: Swarm + Hooks + CVE + Memory + Intelligence
667
- const swarmInd = coordinationActive ? c.brightGreen + '◉' + c.reset : c.dim + '○' + c.reset;
668
- const agentsColor = activeAgents > 0 ? c.brightGreen : c.red;
666
+ const swarmsColor = activeSwarms > 0 ? c.brightGreen : c.dim;
667
+ const agentsColor = activeAgents > 0 ? c.brightGreen : c.dim;
669
668
  const secIcon = secStatus === 'CLEAN' ? '🟢' : secStatus === 'STALE' ? '🟡' : (secStatus === 'NONE' ? '⚪' : '🔴');
670
669
  const secColor = secStatus === 'CLEAN' ? c.brightGreen : secStatus === 'STALE' ? c.brightYellow : (secStatus === 'NONE' ? c.dim : c.brightRed);
671
670
  const hooksColor = hooksEnabled > 0 ? c.brightGreen : c.dim;
672
671
  const intellColor = intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
673
672
 
674
673
  if (seg('swarm')) lines.push(
675
- c.brightYellow + '🤖 Swarm' + c.reset + ' ' + swarmInd + ' [' + agentsColor + String(activeAgents).padStart(2) + c.reset + '/' + c.brightWhite + maxAgents + c.reset + '] ' +
676
- c.brightPurple + '👥 ' + subAgents + c.reset + ' ' +
674
+ c.brightYellow + '🐝 Swarms' + c.reset + ' ' + swarmsColor + activeSwarms + c.reset + ' ' +
675
+ c.brightYellow + '🤖 Agents' + c.reset + ' ' + agentsColor + activeAgents + c.reset + ' ' +
677
676
  c.brightBlue + '🪝 ' + hooksColor + hooksEnabled + c.reset + '/' + c.brightWhite + hooksTotal + c.reset + ' ' +
678
677
  secIcon + ' ' + secColor + secLabel + c.reset + ' ' +
679
678
  c.brightCyan + '💾 ' + memoryMB + 'MB' + c.reset + ' ' +
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.58.1-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.58.6-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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmdo",
3
- "version": "1.58.1",
3
+ "version": "1.58.6",
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",
@@ -3,6 +3,32 @@
3
3
  * Self-learning hooks system for intelligent workflow automation
4
4
  */
5
5
  import type { Command } from '../types.js';
6
+ /**
7
+ * Live swarm + agent counts for the statusline (`🐝 Swarms N 🤖 Agents M`).
8
+ * These are two distinct numbers, read from two canonical registries:
9
+ * - agents: `.swarmdo/agents/store.json` + the hive `.swarmdo/agents.json`
10
+ * (what `agent_spawn`, `swarm_init`, `agent bridge register`, and hive-mind
11
+ * workers write) — every non-terminated agent is counted.
12
+ * - swarms: `.swarmdo/swarm/swarm-state.json` — every `status: 'running'`
13
+ * swarm whose host process is still alive; dead-pid / >24h-stale orphans are
14
+ * skipped read-only (mirrors reconcileOrphanSwarms without persisting).
15
+ *
16
+ * The agent count replaces the old `ps aux | grep -c agentic-flow` heuristic,
17
+ * which (a) was blind to in-process agents — Claude Code Task-tool subagents and
18
+ * bridged agents never appear as a separate `agentic-flow` OS process — so the
19
+ * count never moved when a swarm spun up, and (b) false-positived on any process
20
+ * whose args merely mention "agentic-flow" (a grep, an open editor buffer, the
21
+ * ONNX embedder), showing phantom agents when none were running.
22
+ *
23
+ * No `maxAgents` denominator is reported: swarm size is never enforced at spawn
24
+ * time (the config value is an advisory hint feeding an internal [1,50]
25
+ * backstop), so a `[N/max]` gauge would imply a live cap that does not exist.
26
+ */
27
+ export declare function computeSwarmStatus(cwd?: string): {
28
+ activeSwarms: number;
29
+ activeAgents: number;
30
+ coordinationActive: boolean;
31
+ };
6
32
  export declare const hooksCommand: Command;
7
33
  export default hooksCommand;
8
34
  //# sourceMappingURL=hooks.d.ts.map
@@ -11,6 +11,94 @@ import { join } from 'node:path';
11
11
  import { bridgeSearchEntries } from '../memory/memory-bridge.js';
12
12
  import { selectInjectionMemories, mapSearchResultsToCandidates, extractPromptFromPayload, } from '../memory-inject/select.js';
13
13
  import { classifyCommand, extractBashCommand, denyOutput } from '../hooks-recipe/command-guard.js';
14
+ // Read-only liveness probe (does not persist). Mirrors swarm-tools' isPidAlive
15
+ // so the statusline never counts a swarm whose host process has exited.
16
+ function statuslinePidAlive(pid) {
17
+ try {
18
+ process.kill(pid, 0);
19
+ return true;
20
+ }
21
+ catch (e) {
22
+ return e.code === 'EPERM';
23
+ }
24
+ }
25
+ /**
26
+ * Live swarm + agent counts for the statusline (`🐝 Swarms N 🤖 Agents M`).
27
+ * These are two distinct numbers, read from two canonical registries:
28
+ * - agents: `.swarmdo/agents/store.json` + the hive `.swarmdo/agents.json`
29
+ * (what `agent_spawn`, `swarm_init`, `agent bridge register`, and hive-mind
30
+ * workers write) — every non-terminated agent is counted.
31
+ * - swarms: `.swarmdo/swarm/swarm-state.json` — every `status: 'running'`
32
+ * swarm whose host process is still alive; dead-pid / >24h-stale orphans are
33
+ * skipped read-only (mirrors reconcileOrphanSwarms without persisting).
34
+ *
35
+ * The agent count replaces the old `ps aux | grep -c agentic-flow` heuristic,
36
+ * which (a) was blind to in-process agents — Claude Code Task-tool subagents and
37
+ * bridged agents never appear as a separate `agentic-flow` OS process — so the
38
+ * count never moved when a swarm spun up, and (b) false-positived on any process
39
+ * whose args merely mention "agentic-flow" (a grep, an open editor buffer, the
40
+ * ONNX embedder), showing phantom agents when none were running.
41
+ *
42
+ * No `maxAgents` denominator is reported: swarm size is never enforced at spawn
43
+ * time (the config value is an advisory hint feeding an internal [1,50]
44
+ * backstop), so a `[N/max]` gauge would imply a live cap that does not exist.
45
+ */
46
+ export function computeSwarmStatus(cwd = process.cwd()) {
47
+ const agents = {};
48
+ // Both stores hold a { agents: { <id>: { status } } } map; merge them.
49
+ for (const rel of [['.swarmdo', 'agents', 'store.json'], ['.swarmdo', 'agents.json']]) {
50
+ try {
51
+ const p = join(cwd, ...rel);
52
+ if (existsSync(p)) {
53
+ const data = JSON.parse(readFileSync(p, 'utf-8'));
54
+ if (data && data.agents && typeof data.agents === 'object') {
55
+ Object.assign(agents, data.agents);
56
+ }
57
+ }
58
+ }
59
+ catch {
60
+ // unreadable/corrupt store — skip it, count what we can
61
+ }
62
+ }
63
+ let activeAgents = 0;
64
+ for (const id of Object.keys(agents)) {
65
+ if (agents[id] && agents[id].status !== 'terminated')
66
+ activeAgents++;
67
+ }
68
+ // Active swarms — running, non-orphaned entries in swarm-state.json.
69
+ let activeSwarms = 0;
70
+ try {
71
+ const sp = join(cwd, '.swarmdo', 'swarm', 'swarm-state.json');
72
+ if (existsSync(sp)) {
73
+ const store = JSON.parse(readFileSync(sp, 'utf-8'));
74
+ const swarms = store && store.swarms && typeof store.swarms === 'object' ? store.swarms : {};
75
+ const ORPHAN_TTL_MS = 24 * 60 * 60 * 1000;
76
+ const nowMs = Date.now();
77
+ for (const s of Object.values(swarms)) {
78
+ if (!s || s.status !== 'running')
79
+ continue;
80
+ if (typeof s.pid === 'number') {
81
+ if (!statuslinePidAlive(s.pid))
82
+ continue; // host process gone → orphan
83
+ }
84
+ else if (s.updatedAt) {
85
+ const ageMs = nowMs - new Date(s.updatedAt).getTime();
86
+ if (Number.isFinite(ageMs) && ageMs > ORPHAN_TTL_MS)
87
+ continue; // heartbeat stale
88
+ }
89
+ activeSwarms++;
90
+ }
91
+ }
92
+ }
93
+ catch {
94
+ // unreadable/corrupt swarm store — count 0
95
+ }
96
+ return {
97
+ activeSwarms,
98
+ activeAgents,
99
+ coordinationActive: activeSwarms > 0 || activeAgents > 0,
100
+ };
101
+ }
14
102
  /**
15
103
  * #1686 — `?? 0` only defaults null/undefined; NaN slips through and
16
104
  * surfaces as `"NaN"` (or earlier crashed `.toFixed`) in the metrics
@@ -3613,29 +3701,13 @@ const statuslineCommand = {
3613
3701
  // no scan has ever run — nothing is "pending", there is just no data
3614
3702
  return { status: 'NONE', critical: 0, high: 0, total: 0, scannedAt: null };
3615
3703
  }
3616
- // Get swarm status
3704
+ // Get swarm status from the canonical agent registry (not `ps | grep agentic-flow`).
3617
3705
  function getSwarmStatus() {
3618
- let activeAgents = 0;
3619
- let coordinationActive = false;
3620
- const maxAgents = 15;
3621
- const isWindows = process.platform === 'win32';
3622
- try {
3623
- const psCmd = isWindows
3624
- ? 'tasklist /FI "IMAGENAME eq node.exe" /NH 2>NUL | find /c /v "" 2>NUL || echo 0'
3625
- : 'ps aux 2>/dev/null | grep -c agentic-flow || echo "0"';
3626
- const ps = execSync(psCmd, { encoding: 'utf-8', timeout: 3000 });
3627
- activeAgents = Math.max(0, parseInt(ps.trim()) - 1);
3628
- coordinationActive = activeAgents > 0;
3629
- }
3630
- catch {
3631
- // ps/tasklist unavailable or timed out — report zero
3632
- }
3633
- return { activeAgents, maxAgents, coordinationActive };
3706
+ return computeSwarmStatus(process.cwd());
3634
3707
  }
3635
3708
  // Get system metrics
3636
3709
  function getSystemMetrics() {
3637
3710
  let memoryMB = 0;
3638
- let subAgents = 0;
3639
3711
  const learning = getLearningStats();
3640
3712
  try {
3641
3713
  memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
@@ -3697,7 +3769,7 @@ const statuslineCommand = {
3697
3769
  intelligencePct = Math.min(100, maturityScore);
3698
3770
  }
3699
3771
  const contextPct = Math.min(100, Math.floor(learning.sessions * 5));
3700
- return { memoryMB, contextPct, intelligencePct, subAgents };
3772
+ return { memoryMB, contextPct, intelligencePct };
3701
3773
  }
3702
3774
  // Get user info
3703
3775
  function getUserInfo() {
@@ -3751,7 +3823,7 @@ const statuslineCommand = {
3751
3823
  const terminalCols = process.stdout.columns ?? 80;
3752
3824
  const autoCompact = !ctx.flags.full && terminalCols < COMPACT_WIDTH_THRESHOLD;
3753
3825
  if (ctx.flags.compact || autoCompact) {
3754
- const line = `DDD:${progress.domainsCompleted}/${progress.totalDomains} Sec:${security.status} Swarm:${swarm.activeAgents}/${swarm.maxAgents} Ctx:${system.contextPct}% Int:${system.intelligencePct}%`;
3826
+ const line = `DDD:${progress.domainsCompleted}/${progress.totalDomains} Sec:${security.status} Swarms:${swarm.activeSwarms} Agents:${swarm.activeAgents} Ctx:${system.contextPct}% Int:${system.intelligencePct}%`;
3755
3827
  output.writeln(line);
3756
3828
  return { success: true, data: statusData };
3757
3829
  }
@@ -3923,13 +3995,13 @@ const statuslineCommand = {
3923
3995
  const line1 = `${c.brightCyan}🏗️ DDD Domains${c.reset} ${progressBar(progress.domainsCompleted, progress.totalDomains)} ` +
3924
3996
  `${domainsColor}${progress.domainsCompleted}${c.reset}/${c.brightWhite}${progress.totalDomains}${c.reset} ` +
3925
3997
  perfIndicator;
3926
- const swarmIndicator = swarm.coordinationActive ? `${c.brightGreen}◉${c.reset}` : `${c.dim}○${c.reset}`;
3927
- const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
3998
+ const swarmsColor = swarm.activeSwarms > 0 ? c.brightGreen : c.dim;
3999
+ const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.dim;
3928
4000
  const securityIcon = security.status === 'CLEAN' ? '🟢' : security.status === 'STALE' ? '🟡' : security.status === 'NONE' ? '⚪' : '🔴';
3929
4001
  const securityColor = security.status === 'CLEAN' ? c.brightGreen : security.status === 'STALE' ? c.brightYellow : security.status === 'NONE' ? c.dim : c.brightRed;
3930
4002
  const hooksColor = hooksStats.enabled > 0 ? c.brightGreen : c.dim;
3931
- const line2 = `${c.brightYellow}🤖 Swarm${c.reset} ${swarmIndicator} [${agentsColor}${String(swarm.activeAgents).padStart(2)}${c.reset}/${c.brightWhite}${swarm.maxAgents}${c.reset}] ` +
3932
- `${c.brightPurple}👥 ${system.subAgents}${c.reset} ` +
4003
+ const line2 = `${c.brightYellow}🐝 Swarms${c.reset} ${swarmsColor}${swarm.activeSwarms}${c.reset} ` +
4004
+ `${c.brightYellow}🤖 Agents${c.reset} ${agentsColor}${swarm.activeAgents}${c.reset} ` +
3933
4005
  `${c.brightBlue}🪝 ${hooksColor}${hooksStats.enabled}${c.reset}/${c.brightWhite}${hooksStats.total}${c.reset} ` +
3934
4006
  `${securityIcon} ${securityColor}sec ${security.status === 'VULN' ? (security.critical + security.high) + '!' : security.status === 'CLEAN' ? '✓' : security.status === 'STALE' ? 'stale' : '—'}${c.reset} ` +
3935
4007
  `${c.brightCyan}💾 ${system.memoryMB}MB${c.reset} ` +
@@ -355,6 +355,9 @@ const initCommand = {
355
355
  const result = await callMCPTool('swarm_init', {
356
356
  topology: topology,
357
357
  maxAgents,
358
+ // A one-shot CLI process is not a lasting host — create a persistent
359
+ // (pid-less) swarm so it isn't reaped the instant `swarm init` exits.
360
+ persistent: true,
358
361
  config: {
359
362
  communicationProtocol: 'message-bus',
360
363
  consensusMechanism: 'majority',
@@ -520,6 +523,7 @@ const startCommand = {
520
523
  topology: 'hierarchical',
521
524
  maxAgents: totalAgents,
522
525
  strategy: strategy === 'development' ? 'specialized' : strategy,
526
+ persistent: true, // CLI process is ephemeral — pid-less swarm survives exit
523
527
  });
524
528
  spinner.succeed('Swarm initialized via MCP');
525
529
  }
@@ -818,6 +822,7 @@ const coordinateCommand = {
818
822
  topology: 'hierarchical-mesh',
819
823
  maxAgents: agentCount,
820
824
  strategy: 'specialized',
825
+ persistent: true, // CLI process is ephemeral — pid-less swarm survives exit
821
826
  });
822
827
  output.printSuccess(`Swarm coordination initialized with ${agentCount} agent slots via MCP`);
823
828
  }
@@ -16,7 +16,7 @@ import type { InitOptions } from './types.js';
16
16
  * ▊ Swarmdo V3.6 ● user │ ⎇ branch │ Opus 4.7
17
17
  * ─────────────────────────────────────────────────────
18
18
  * 🏗️ DDD Domains [●●○○○] 2/5 ⚡ HNSW 150x
19
- * 🤖 Swarm [ 5/15] 👥 2 🪝 10/17 🟢 CVE 3/3 💾 4MB 🧠 63%
19
+ * 🐝 Swarms 1 🤖 Agents 5 🪝 10/17 🟢 CVE 3/3 💾 4MB 🧠 63%
20
20
  * 🔧 Architecture ADRs ●71% │ DDD ● 13% │ Security ●CLEAN
21
21
  * 📊 AgentDB Vectors ●3104⚡ │ Size 216KB │ Tests ●6 (~24 cases) │ MCP ●1/1
22
22
  */
@@ -53,7 +53,7 @@ const BAKED_CLI_VERSION = readBakedCliVersion();
53
53
  * ▊ Swarmdo V3.6 ● user │ ⎇ branch │ Opus 4.7
54
54
  * ─────────────────────────────────────────────────────
55
55
  * 🏗️ DDD Domains [●●○○○] 2/5 ⚡ HNSW 150x
56
- * 🤖 Swarm [ 5/15] 👥 2 🪝 10/17 🟢 CVE 3/3 💾 4MB 🧠 63%
56
+ * 🐝 Swarms 1 🤖 Agents 5 🪝 10/17 🟢 CVE 3/3 💾 4MB 🧠 63%
57
57
  * 🔧 Architecture ADRs ●71% │ DDD ● 13% │ Security ●CLEAN
58
58
  * 📊 AgentDB Vectors ●3104⚡ │ Size 216KB │ Tests ●6 (~24 cases) │ MCP ●1/1
59
59
  */
@@ -392,8 +392,8 @@ function buildLocalFallback() {
392
392
  user: { name: 'user', gitBranch: '', modelName: 'Claude Code' },
393
393
  v3Progress: { domainsCompleted: 0, totalDomains: 5, dddProgress: 0, patternsLearned: 0, sessionsCompleted: 0 },
394
394
  security: { status: 'NONE', critical: 0, high: 0, total: 0 },
395
- swarm: { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false },
396
- system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0, subAgents: 0 },
395
+ swarm: { activeSwarms: 0, activeAgents: 0, coordinationActive: false },
396
+ system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0 },
397
397
  lastUpdated: new Date().toISOString(),
398
398
  });
399
399
  }
@@ -653,12 +653,11 @@ function generateStatusline() {
653
653
  const totalDomains = progress.totalDomains || 5;
654
654
  const dddProgress = progress.dddProgress || 0;
655
655
  const patternsLearned = progress.patternsLearned || 0;
656
+ const activeSwarms = swarm.activeSwarms || 0;
656
657
  const activeAgents = swarm.activeAgents || 0;
657
- const maxAgents = swarm.maxAgents || CONFIG.maxAgents;
658
658
  const coordinationActive = swarm.coordinationActive || false;
659
659
  const intelligencePct = system.intelligencePct || 0;
660
660
  const memoryMB = system.memoryMB || 0;
661
- const subAgents = system.subAgents || 0;
662
661
  const secCritHigh = (security.critical || 0) + (security.high || 0);
663
662
  const secStatus = security.status || 'NONE';
664
663
  const secLabel = secStatus === 'VULN' ? 'sec ' + secCritHigh + '!' : secStatus === 'CLEAN' ? 'sec ✓' : secStatus === 'STALE' ? 'sec stale' : 'sec —';
@@ -725,16 +724,16 @@ function generateStatusline() {
725
724
  );
726
725
 
727
726
  // Line 2: Swarm + Hooks + CVE + Memory + Intelligence
728
- const swarmInd = coordinationActive ? c.brightGreen + '◉' + c.reset : c.dim + '○' + c.reset;
729
- const agentsColor = activeAgents > 0 ? c.brightGreen : c.red;
727
+ const swarmsColor = activeSwarms > 0 ? c.brightGreen : c.dim;
728
+ const agentsColor = activeAgents > 0 ? c.brightGreen : c.dim;
730
729
  const secIcon = secStatus === 'CLEAN' ? '🟢' : secStatus === 'STALE' ? '🟡' : (secStatus === 'NONE' ? '⚪' : '🔴');
731
730
  const secColor = secStatus === 'CLEAN' ? c.brightGreen : secStatus === 'STALE' ? c.brightYellow : (secStatus === 'NONE' ? c.dim : c.brightRed);
732
731
  const hooksColor = hooksEnabled > 0 ? c.brightGreen : c.dim;
733
732
  const intellColor = intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
734
733
 
735
734
  if (seg('swarm')) lines.push(
736
- c.brightYellow + '🤖 Swarm' + c.reset + ' ' + swarmInd + ' [' + agentsColor + String(activeAgents).padStart(2) + c.reset + '/' + c.brightWhite + maxAgents + c.reset + '] ' +
737
- c.brightPurple + '👥 ' + subAgents + c.reset + ' ' +
735
+ c.brightYellow + '🐝 Swarms' + c.reset + ' ' + swarmsColor + activeSwarms + c.reset + ' ' +
736
+ c.brightYellow + '🤖 Agents' + c.reset + ' ' + agentsColor + activeAgents + c.reset + ' ' +
738
737
  c.brightBlue + '🪝 ' + hooksColor + hooksEnabled + c.reset + '/' + c.brightWhite + hooksTotal + c.reset + ' ' +
739
738
  secIcon + ' ' + secColor + secLabel + c.reset + ' ' +
740
739
  c.brightCyan + '💾 ' + memoryMB + 'MB' + c.reset + ' ' +
@@ -179,6 +179,7 @@ export const swarmTools = [
179
179
  maxAgents: { type: 'number', description: 'Maximum number of agents (1-50)' },
180
180
  strategy: { type: 'string', description: 'Agent strategy (specialized, balanced, adaptive)' },
181
181
  config: { type: 'object', description: 'Additional swarm configuration' },
182
+ persistent: { type: 'boolean', description: 'Create a persistent (pid-less) swarm that survives the creating process — set by the CLI, whose process is ephemeral. Reaped by the 24h idle-TTL instead of on-exit. Leave unset from a long-lived host (MCP server/daemon) so a dead host is reaped promptly.' },
182
183
  },
183
184
  },
184
185
  handler: async (input) => {
@@ -201,6 +202,7 @@ export const swarmTools = [
201
202
  maxAgents: input.maxAgents,
202
203
  strategy,
203
204
  config: (input.config || {}),
205
+ persistent: input.persistent,
204
206
  });
205
207
  }
206
208
  catch (e) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmdo/cli",
3
- "version": "1.58.1",
3
+ "version": "1.58.6",
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",