swarmdo 1.54.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.
- package/.claude/helpers/statusline.cjs +17 -11
- package/README.md +4 -3
- package/package.json +1 -1
- package/v3/@swarmdo/cli/dist/src/command-usage/usage.d.ts +74 -0
- package/v3/@swarmdo/cli/dist/src/command-usage/usage.js +161 -0
- package/v3/@swarmdo/cli/dist/src/commands/commands.d.ts +19 -0
- package/v3/@swarmdo/cli/dist/src/commands/commands.js +107 -0
- package/v3/@swarmdo/cli/dist/src/commands/hooks.d.ts +26 -0
- package/v3/@swarmdo/cli/dist/src/commands/hooks.js +96 -24
- package/v3/@swarmdo/cli/dist/src/commands/index.js +7 -3
- package/v3/@swarmdo/cli/dist/src/commands/swarm.js +5 -0
- package/v3/@swarmdo/cli/dist/src/commands/usage.js +57 -1
- package/v3/@swarmdo/cli/dist/src/comms/store.d.ts +11 -1
- package/v3/@swarmdo/cli/dist/src/comms/store.js +16 -2
- package/v3/@swarmdo/cli/dist/src/init/statusline-generator.d.ts +1 -1
- package/v3/@swarmdo/cli/dist/src/init/statusline-generator.js +17 -11
- package/v3/@swarmdo/cli/dist/src/integrations/integrations.js +19 -8
- package/v3/@swarmdo/cli/dist/src/mcp-tools/comms-tools.js +4 -4
- package/v3/@swarmdo/cli/dist/src/mcp-tools/swarm-tools.js +2 -0
- package/v3/@swarmdo/cli/dist/src/usage/transcript-friction.d.ts +77 -0
- package/v3/@swarmdo/cli/dist/src/usage/transcript-friction.js +151 -0
- package/v3/@swarmdo/cli/package.json +1 -1
- package/v3/@swarmdo/cli-core/dist/src/index.js +1 -1
- package/v3/@swarmdo/codex/dist/cli.js +0 -0
- package/v3/@swarmdo/hooks/dist/cli/guidance-cli.js +0 -0
- package/v3/@swarmdo/hooks/dist/statusline/index.d.ts +3 -3
- package/v3/@swarmdo/hooks/dist/statusline/index.js +3 -3
- package/v3/@swarmdo/integration/dist/__tests__/agentic-flow-agent.test.js +4 -1
- package/v3/@swarmdo/neural/dist/flash-attention.d.ts +1 -1
- package/v3/@swarmdo/neural/dist/flash-attention.js +1 -1
- package/v3/@swarmdo/plugin-agent-federation/dist/plugin.js +1 -1
- package/v3/@swarmdo/plugin-agent-federation/dist/transport/midstream-aware-loader.js +2 -2
- package/v3/@swarmdo/providers/dist/swarmvector-provider.d.ts +1 -1
- package/v3/@swarmdo/providers/dist/swarmvector-provider.js +1 -1
- package/v3/@swarmdo/security/dist/input-validator.d.ts +6 -6
- package/v3/@swarmdo/shared/dist/hooks/safety/git-commit.js +1 -1
- package/v3/@swarmdo/shared/dist/mcp/transport/http.js +8 -1
- package/.claude/settings.local.json +0 -7
- package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.d.ts +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.d.ts +0 -138
- package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.js +0 -418
- package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.d.ts +0 -15
- package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.js +0 -240
- package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.d.ts +0 -7
- package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.js +0 -508
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.d.ts +0 -54
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.d.ts +0 -46
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.d.ts +0 -18
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.js +0 -28
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.d.ts +0 -5
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.d.ts +0 -35
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.d.ts +0 -11
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.d.ts +0 -9
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.d.ts +0 -5
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.d.ts +0 -12
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.d.ts +0 -19
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.js +0 -2
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.d.ts +0 -44
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.js +0 -117
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.d.ts +0 -70
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.js +0 -194
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.d.ts +0 -69
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.js +0 -139
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.d.ts +0 -34
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.js +0 -101
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.d.ts +0 -10
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.js +0 -10
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.d.ts +0 -64
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.js +0 -70
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.d.ts +0 -44
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.js +0 -79
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.d.ts +0 -37
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.js +0 -39
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.d.ts +0 -67
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.js +0 -58
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.d.ts +0 -45
- package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.js +0 -63
- package/v3/@swarmdo/plugin-iot-cognitum/dist/index.d.ts +0 -26
- package/v3/@swarmdo/plugin-iot-cognitum/dist/index.js +0 -17
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.d.ts +0 -51
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.js +0 -110
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.d.ts +0 -13
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.js +0 -25
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.d.ts +0 -11
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.js +0 -19
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.d.ts +0 -11
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.js +0 -27
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.d.ts +0 -6
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.js +0 -6
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.d.ts +0 -41
- package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.js +0 -64
- package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.d.ts +0 -8
- package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.js +0 -703
- package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.d.ts +0 -23
- package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.js +0 -239
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.d.ts +0 -17
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.js +0 -42
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.d.ts +0 -18
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.js +0 -45
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.d.ts +0 -19
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.js +0 -50
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.d.ts +0 -19
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.js +0 -47
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.d.ts +0 -17
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.js +0 -40
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.d.ts +0 -18
- package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.js +0 -51
- package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.d.ts +0 -214
- package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.js +0 -595
- package/v3/@swarmdo/testing/dist/fixtures/agents.d.ts +0 -76
- package/v3/@swarmdo/testing/dist/fixtures/agents.js +0 -158
- package/v3/@swarmdo/testing/dist/fixtures/configurations.d.ts +0 -157
- package/v3/@swarmdo/testing/dist/fixtures/configurations.js +0 -337
- package/v3/@swarmdo/testing/dist/fixtures/index.d.ts +0 -10
- package/v3/@swarmdo/testing/dist/fixtures/index.js +0 -17
- package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.d.ts +0 -329
- package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.js +0 -714
- package/v3/@swarmdo/testing/dist/fixtures/memory-entries.d.ts +0 -159
- package/v3/@swarmdo/testing/dist/fixtures/memory-entries.js +0 -262
- package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.d.ts +0 -290
- package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.js +0 -547
- package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.d.ts +0 -289
- package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.js +0 -534
- package/v3/@swarmdo/testing/dist/fixtures/tasks.d.ts +0 -106
- package/v3/@swarmdo/testing/dist/fixtures/tasks.js +0 -229
- package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.d.ts +0 -213
- package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.js +0 -435
- package/v3/@swarmdo/testing/dist/helpers/assertions.d.ts +0 -135
- package/v3/@swarmdo/testing/dist/helpers/assertions.js +0 -217
- package/v3/@swarmdo/testing/dist/helpers/create-mock.d.ts +0 -96
- package/v3/@swarmdo/testing/dist/helpers/create-mock.js +0 -164
- package/v3/@swarmdo/testing/dist/helpers/index.d.ts +0 -14
- package/v3/@swarmdo/testing/dist/helpers/index.js +0 -22
- package/v3/@swarmdo/testing/dist/helpers/mock-factory.d.ts +0 -323
- package/v3/@swarmdo/testing/dist/helpers/mock-factory.js +0 -350
- package/v3/@swarmdo/testing/dist/helpers/setup-teardown.d.ts +0 -271
- package/v3/@swarmdo/testing/dist/helpers/setup-teardown.js +0 -446
- package/v3/@swarmdo/testing/dist/helpers/swarm-instance.d.ts +0 -142
- package/v3/@swarmdo/testing/dist/helpers/swarm-instance.js +0 -205
- package/v3/@swarmdo/testing/dist/helpers/test-application.d.ts +0 -190
- package/v3/@swarmdo/testing/dist/helpers/test-application.js +0 -138
- package/v3/@swarmdo/testing/dist/helpers/test-utils.d.ts +0 -274
- package/v3/@swarmdo/testing/dist/helpers/test-utils.js +0 -456
- package/v3/@swarmdo/testing/dist/index.d.ts +0 -42
- package/v3/@swarmdo/testing/dist/index.js +0 -66
- package/v3/@swarmdo/testing/dist/mocks/index.d.ts +0 -8
- package/v3/@swarmdo/testing/dist/mocks/index.js +0 -10
- package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.d.ts +0 -206
- package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.js +0 -575
- package/v3/@swarmdo/testing/dist/mocks/mock-services.d.ts +0 -287
- package/v3/@swarmdo/testing/dist/mocks/mock-services.js +0 -563
- package/v3/@swarmdo/testing/dist/regression/api-contract.d.ts +0 -109
- package/v3/@swarmdo/testing/dist/regression/api-contract.js +0 -374
- package/v3/@swarmdo/testing/dist/regression/index.d.ts +0 -18
- package/v3/@swarmdo/testing/dist/regression/index.js +0 -18
- package/v3/@swarmdo/testing/dist/regression/integration-regression.d.ts +0 -67
- package/v3/@swarmdo/testing/dist/regression/integration-regression.js +0 -334
- package/v3/@swarmdo/testing/dist/regression/performance-baseline.d.ts +0 -106
- package/v3/@swarmdo/testing/dist/regression/performance-baseline.js +0 -268
- package/v3/@swarmdo/testing/dist/regression/regression-runner.d.ts +0 -124
- package/v3/@swarmdo/testing/dist/regression/regression-runner.js +0 -227
- package/v3/@swarmdo/testing/dist/regression/security-regression.d.ts +0 -73
- package/v3/@swarmdo/testing/dist/regression/security-regression.js +0 -258
- package/v3/@swarmdo/testing/dist/setup.d.ts +0 -43
- package/v3/@swarmdo/testing/dist/setup.js +0 -91
- package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.d.ts +0 -10
- package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.js +0 -433
- package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.d.ts +0 -10
- package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.js +0 -352
- package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.d.ts +0 -206
- package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.js +0 -839
- package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.d.ts +0 -10
- package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.js +0 -428
- package/v3/@swarmdo/testing/dist/v2-compat/index.d.ts +0 -38
- package/v3/@swarmdo/testing/dist/v2-compat/index.js +0 -41
- package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.d.ts +0 -10
- package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.js +0 -419
- package/v3/@swarmdo/testing/dist/v2-compat/report-generator.d.ts +0 -34
- package/v3/@swarmdo/testing/dist/v2-compat/report-generator.js +0 -372
|
@@ -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
|
-
|
|
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
|
|
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}
|
|
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
|
|
3927
|
-
const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.
|
|
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}
|
|
3932
|
-
`${c.
|
|
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} ` +
|
|
@@ -64,6 +64,10 @@ const commandLoaders = {
|
|
|
64
64
|
// — commits since your last working day, grouped by day with a diffstat.
|
|
65
65
|
standup: () => import('./standup.js'),
|
|
66
66
|
mine: () => import('./standup.js'), // alias via loader key
|
|
67
|
+
// Hot/cold/orphan USAGE report for authored .claude/ slash-commands + subagents
|
|
68
|
+
// — the "dead-code report" for the authoring surface (config lint validates it).
|
|
69
|
+
commands: () => import('./commands.js'),
|
|
70
|
+
slash: () => import('./commands.js'), // alias via loader key
|
|
67
71
|
// JUnit/TAP test-result parser (dorny/test-reporter demand) — raw results →
|
|
68
72
|
// failing test + file:line + message; the front-half of the test→fix loop.
|
|
69
73
|
testreport: () => import('./testreport.js'),
|
|
@@ -306,7 +310,7 @@ export async function getCommandsByCategory() {
|
|
|
306
310
|
// three slots from 'statusline' onward (completionsCmd received the
|
|
307
311
|
// statusline module, analyzeCmd received completions, …), scrambling the
|
|
308
312
|
// categorized help. Every load now has a named slot.
|
|
309
|
-
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, couplingCmd, ownershipCmd, hiddenCouplingCmd, testreportCmd, compactSnapshotCmd, standupCmd,] = await Promise.all([
|
|
313
|
+
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, couplingCmd, ownershipCmd, hiddenCouplingCmd, testreportCmd, compactSnapshotCmd, standupCmd, commandsUsageCmd,] = await Promise.all([
|
|
310
314
|
loadCommand('daemon'), loadCommand('doctor'), loadCommand('embeddings'), loadCommand('neural'),
|
|
311
315
|
loadCommand('performance'), loadCommand('security'), loadCommand('swarmvector'), loadCommand('hive-mind'),
|
|
312
316
|
loadCommand('config'), loadCommand('statusline'), loadCommand('compress'), loadCommand('efficiency'),
|
|
@@ -314,7 +318,7 @@ export async function getCommandsByCategory() {
|
|
|
314
318
|
loadCommand('analyze'), loadCommand('route'), loadCommand('progress'), loadCommand('providers'),
|
|
315
319
|
loadCommand('plugins'), loadCommand('deployment'), loadCommand('claims'), loadCommand('issues'),
|
|
316
320
|
loadCommand('update'), loadCommand('process'), loadCommand('guidance'), loadCommand('appliance'),
|
|
317
|
-
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'), loadCommand('coupling'), loadCommand('ownership'), loadCommand('hidden-coupling'), loadCommand('testreport'), loadCommand('compact-snapshot'), loadCommand('standup'),
|
|
321
|
+
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'), loadCommand('coupling'), loadCommand('ownership'), loadCommand('hidden-coupling'), loadCommand('testreport'), loadCommand('compact-snapshot'), loadCommand('standup'), loadCommand('commands'),
|
|
318
322
|
]);
|
|
319
323
|
return {
|
|
320
324
|
primary: [
|
|
@@ -333,7 +337,7 @@ export async function getCommandsByCategory() {
|
|
|
333
337
|
statuslineCmd, compressCmd, compactCmd, redactCmd, packCmd, envCmd, licenseCmd, sbomCmd, applyCmd, hotspotsCmd, affectedCmd, cyclesCmd, couplingCmd, ownershipCmd, hiddenCouplingCmd, testreportCmd, compactSnapshotCmd, efficiencyCmd,
|
|
334
338
|
].filter(Boolean),
|
|
335
339
|
analysis: [
|
|
336
|
-
analyzeCmd, routeCmd, progressCmd, usageCmd, hudCmd, codegraphCmd, standupCmd,
|
|
340
|
+
analyzeCmd, routeCmd, progressCmd, usageCmd, hudCmd, codegraphCmd, standupCmd, commandsUsageCmd,
|
|
337
341
|
].filter(Boolean),
|
|
338
342
|
management: [
|
|
339
343
|
providersCmd, pluginsCmd, deploymentCmd, claimsCmd,
|
|
@@ -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
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { output } from '../output.js';
|
|
16
16
|
import { aggregateBlocks, aggregateUsage, collectUsage, totalUsage, localDateKey, } from '../usage/transcript-usage.js';
|
|
17
17
|
import { collectToolErrors, delegationFromReport } from '../usage/transcript-errors.js';
|
|
18
|
+
import { collectFriction } from '../usage/transcript-friction.js';
|
|
18
19
|
import { computeCacheStats } from '../usage/cache-stats.js';
|
|
19
20
|
import { evaluateGuard } from '../usage/spend-guard.js';
|
|
20
21
|
import { resolvePeriodPair, parseRange, diffPeriods, modelMovers } from '../usage/diff.js';
|
|
@@ -201,6 +202,53 @@ function runErrorsView(ctx, report) {
|
|
|
201
202
|
}
|
|
202
203
|
return { success: true, exitCode: 0 };
|
|
203
204
|
}
|
|
205
|
+
/** Friction view — how often you interrupt Claude (ESC mid-turn), which tool was
|
|
206
|
+
* running when you did, and what KIND of errors dominate. The sniffly axes that
|
|
207
|
+
* `usage errors` (error rate) left on the table (#102). */
|
|
208
|
+
function runFrictionView(ctx, report) {
|
|
209
|
+
if (ctx.flags.json === true) {
|
|
210
|
+
output.writeln(JSON.stringify(report, null, 2));
|
|
211
|
+
return { success: true, exitCode: 0 };
|
|
212
|
+
}
|
|
213
|
+
const pct = (v) => `${(v * 100).toFixed(1)}%`;
|
|
214
|
+
if (ctx.flags.csv === true) {
|
|
215
|
+
// Category table export (parity with `usage --csv`).
|
|
216
|
+
const headers = ['category', 'count', 'share'];
|
|
217
|
+
const rows = report.categories.map((c) => [c.category, c.count, c.share.toFixed(4)]);
|
|
218
|
+
output.writeln(toCsv(headers, rows));
|
|
219
|
+
return { success: true, exitCode: 0 };
|
|
220
|
+
}
|
|
221
|
+
output.writeln(output.bold('Claude Code usage — friction'));
|
|
222
|
+
if (report.interruptions === 0 && report.totalErrors === 0) {
|
|
223
|
+
output.writeln(output.info(`no friction detected in ${report.filesScanned} transcript files`));
|
|
224
|
+
return { success: true, exitCode: 0 };
|
|
225
|
+
}
|
|
226
|
+
output.writeln(output.dim(`${report.filesScanned} files · ${fmtInt(report.interruptions)} interruption${report.interruptions === 1 ? '' : 's'} across ${fmtInt(report.assistantTurns)} assistant turns (${pct(report.interruptionRate)})`));
|
|
227
|
+
if (report.byTool.length > 0) {
|
|
228
|
+
output.writeln('');
|
|
229
|
+
output.writeln(output.bold('Interrupted while running'));
|
|
230
|
+
output.printTable({
|
|
231
|
+
columns: [
|
|
232
|
+
{ key: 'tool', header: 'Tool / context', width: 22 },
|
|
233
|
+
{ key: 'count', header: 'Interrupts', width: 12, align: 'right' },
|
|
234
|
+
],
|
|
235
|
+
data: report.byTool.slice(0, 15).map((t) => ({ tool: t.tool, count: fmtInt(t.interruptions) })),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
if (report.categories.length > 0) {
|
|
239
|
+
output.writeln('');
|
|
240
|
+
output.writeln(output.bold('Error categories') + output.dim(` (${fmtInt(report.totalErrors)} tool errors)`));
|
|
241
|
+
output.printTable({
|
|
242
|
+
columns: [
|
|
243
|
+
{ key: 'category', header: 'Category', width: 14 },
|
|
244
|
+
{ key: 'count', header: 'Count', width: 10, align: 'right' },
|
|
245
|
+
{ key: 'share', header: 'Share', width: 8, align: 'right' },
|
|
246
|
+
],
|
|
247
|
+
data: report.categories.map((c) => ({ category: c.category, count: fmtInt(c.count), share: pct(c.share) })),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return { success: true, exitCode: 0 };
|
|
251
|
+
}
|
|
204
252
|
/** Cache view — prompt-cache efficiency + $ saved by caching (the #1 cost lever). */
|
|
205
253
|
function runCacheView(ctx, collection) {
|
|
206
254
|
const stats = computeCacheStats(aggregateUsage(collection.events, 'model'));
|
|
@@ -547,6 +595,13 @@ async function run(ctx) {
|
|
|
547
595
|
const dirs = typeof dirFlag === 'string' ? [dirFlag] : Array.isArray(dirFlag) ? dirFlag.map(String) : undefined;
|
|
548
596
|
return runErrorsView(ctx, collectToolErrors({ dirs, since, until }));
|
|
549
597
|
}
|
|
598
|
+
if (viewName === 'friction') {
|
|
599
|
+
const since = typeof ctx.flags.since === 'string' ? ctx.flags.since : undefined;
|
|
600
|
+
const until = typeof ctx.flags.until === 'string' ? ctx.flags.until : undefined;
|
|
601
|
+
const dirFlag = ctx.flags.dir;
|
|
602
|
+
const dirs = typeof dirFlag === 'string' ? [dirFlag] : Array.isArray(dirFlag) ? dirFlag.map(String) : undefined;
|
|
603
|
+
return runFrictionView(ctx, collectFriction({ dirs, since, until }));
|
|
604
|
+
}
|
|
550
605
|
if (viewName === 'cache') {
|
|
551
606
|
const since = typeof ctx.flags.since === 'string' ? ctx.flags.since : undefined;
|
|
552
607
|
const until = typeof ctx.flags.until === 'string' ? ctx.flags.until : undefined;
|
|
@@ -574,7 +629,7 @@ async function run(ctx) {
|
|
|
574
629
|
}
|
|
575
630
|
const view = VIEWS[viewName];
|
|
576
631
|
if (!view) {
|
|
577
|
-
output.writeln(output.error(`unknown view: ${viewName} (expected ${Object.keys(VIEWS).join('|')}|blocks|errors|cache|guard|diff|reflect|limits)`));
|
|
632
|
+
output.writeln(output.error(`unknown view: ${viewName} (expected ${Object.keys(VIEWS).join('|')}|blocks|errors|friction|cache|guard|diff|reflect|limits)`));
|
|
578
633
|
return { success: false, exitCode: 1 };
|
|
579
634
|
}
|
|
580
635
|
const since = typeof ctx.flags.since === 'string' ? ctx.flags.since : undefined;
|
|
@@ -667,6 +722,7 @@ export const usageCommand = {
|
|
|
667
722
|
{ command: 'swarmdo usage projects --json', description: 'Per-project totals as JSON' },
|
|
668
723
|
{ command: 'swarmdo usage monthly --csv > usage.csv', description: 'Export monthly spend to CSV' },
|
|
669
724
|
{ command: 'swarmdo cost sessions --limit 10', description: 'Ten most expensive sessions (alias)' },
|
|
725
|
+
{ command: 'swarmdo usage friction', description: 'How often you interrupt Claude + which error kinds dominate' },
|
|
670
726
|
],
|
|
671
727
|
action: run,
|
|
672
728
|
};
|
|
@@ -14,7 +14,17 @@ export declare const RETENTION: {
|
|
|
14
14
|
export declare function storePath(cwd: string): string;
|
|
15
15
|
export declare function loadMailbox(cwd: string): Mailbox;
|
|
16
16
|
export declare function saveMailbox(cwd: string, box: Mailbox): void;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* This session's name, in precedence order:
|
|
19
|
+
* explicit override (flag/param)
|
|
20
|
+
* → $SWARMDO_SESSION (set by Claude Code)
|
|
21
|
+
* → $SWARMDO_AGENT (harness-neutral — Codex/Copilot/pi agents export this)
|
|
22
|
+
* → hostname → "me".
|
|
23
|
+
*
|
|
24
|
+
* The $SWARMDO_AGENT fallback lets a non-Claude agent declare a stable identity
|
|
25
|
+
* once (instead of passing `from`/`--self` on every call); without it, every
|
|
26
|
+
* agent on a host collapses to the shared hostname and direct addressing breaks.
|
|
27
|
+
*/
|
|
18
28
|
export declare function resolveSelf(flag?: unknown): string;
|
|
19
29
|
/** Crypto-strong message id. */
|
|
20
30
|
export declare function newMessageId(): string;
|
|
@@ -32,10 +32,24 @@ export function saveMailbox(cwd, box) {
|
|
|
32
32
|
mkdirSync(dirname(p), { recursive: true });
|
|
33
33
|
writeFileSync(p, JSON.stringify(box, null, 2) + '\n', 'utf-8');
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* This session's name, in precedence order:
|
|
37
|
+
* explicit override (flag/param)
|
|
38
|
+
* → $SWARMDO_SESSION (set by Claude Code)
|
|
39
|
+
* → $SWARMDO_AGENT (harness-neutral — Codex/Copilot/pi agents export this)
|
|
40
|
+
* → hostname → "me".
|
|
41
|
+
*
|
|
42
|
+
* The $SWARMDO_AGENT fallback lets a non-Claude agent declare a stable identity
|
|
43
|
+
* once (instead of passing `from`/`--self` on every call); without it, every
|
|
44
|
+
* agent on a host collapses to the shared hostname and direct addressing breaks.
|
|
45
|
+
*/
|
|
36
46
|
export function resolveSelf(flag) {
|
|
37
47
|
const f = typeof flag === 'string' ? flag.trim() : '';
|
|
38
|
-
return f ||
|
|
48
|
+
return (f ||
|
|
49
|
+
(process.env.SWARMDO_SESSION || '').trim() ||
|
|
50
|
+
(process.env.SWARMDO_AGENT || '').trim() ||
|
|
51
|
+
hostname() ||
|
|
52
|
+
'me');
|
|
39
53
|
}
|
|
40
54
|
/** Crypto-strong message id. */
|
|
41
55
|
export function newMessageId() {
|
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
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
|
*/
|
|
@@ -166,7 +166,7 @@ function resolveCliBin() {
|
|
|
166
166
|
];
|
|
167
167
|
try {
|
|
168
168
|
const binDir = path.dirname(process.execPath);
|
|
169
|
-
const globalModuleDirs = [path.join(binDir, '..', 'lib', 'node_modules'), path.join(binDir, 'node_modules')];
|
|
169
|
+
const globalModuleDirs = [path.join(binDir, '..', 'lib', 'node_modules'), path.join(binDir, 'node_modules'), '/opt/homebrew/lib/node_modules', '/usr/local/lib/node_modules'];
|
|
170
170
|
for (const prefix of [process.env.npm_config_prefix, process.env.PREFIX, path.join(home, '.npm-global')]) {
|
|
171
171
|
if (prefix) globalModuleDirs.push(path.join(prefix, 'lib', 'node_modules'));
|
|
172
172
|
}
|
|
@@ -209,6 +209,13 @@ function writeCache(data) {
|
|
|
209
209
|
* and only counted ADRs in v3/implementation/adrs/ (missed v3/docs/adr/).
|
|
210
210
|
*/
|
|
211
211
|
function getStatuslineData() {
|
|
212
|
+
// SWARMDO_STATUSLINE_NO_CLI: skip the CLI-delegation fork and render from local
|
|
213
|
+
// reads + stdin only. A cold render otherwise forks the hooks-statusline CLI
|
|
214
|
+
// (now more reachable via the global-node_modules probes below), and that fork
|
|
215
|
+
// can disturb the stdin cost payload; skipping it keeps renders fast, hermetic,
|
|
216
|
+
// and subprocess-free. Set by the statusline tests; usable by anyone who wants
|
|
217
|
+
// a no-fork statusline.
|
|
218
|
+
if (process.env.SWARMDO_STATUSLINE_NO_CLI) return buildLocalFallback();
|
|
212
219
|
const cached = readCache();
|
|
213
220
|
if (cached) return cached;
|
|
214
221
|
|
|
@@ -385,8 +392,8 @@ function buildLocalFallback() {
|
|
|
385
392
|
user: { name: 'user', gitBranch: '', modelName: 'Claude Code' },
|
|
386
393
|
v3Progress: { domainsCompleted: 0, totalDomains: 5, dddProgress: 0, patternsLearned: 0, sessionsCompleted: 0 },
|
|
387
394
|
security: { status: 'NONE', critical: 0, high: 0, total: 0 },
|
|
388
|
-
swarm: {
|
|
389
|
-
system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0
|
|
395
|
+
swarm: { activeSwarms: 0, activeAgents: 0, coordinationActive: false },
|
|
396
|
+
system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0 },
|
|
390
397
|
lastUpdated: new Date().toISOString(),
|
|
391
398
|
});
|
|
392
399
|
}
|
|
@@ -592,7 +599,7 @@ function getPkgVersion() {
|
|
|
592
599
|
// (bin/node_modules) layouts.
|
|
593
600
|
try {
|
|
594
601
|
const binDir = path.dirname(process.execPath);
|
|
595
|
-
const globalModuleDirs = [path.join(binDir, '..', 'lib', 'node_modules'), path.join(binDir, 'node_modules')];
|
|
602
|
+
const globalModuleDirs = [path.join(binDir, '..', 'lib', 'node_modules'), path.join(binDir, 'node_modules'), '/opt/homebrew/lib/node_modules', '/usr/local/lib/node_modules'];
|
|
596
603
|
// #2221 follow-up: a custom npm prefix (e.g. ~/.npm-global) is decoupled from
|
|
597
604
|
// the node binary location, so the binDir-derived probes above all miss. Also
|
|
598
605
|
// probe the npm prefix from the environment and the common ~/.npm-global default.
|
|
@@ -646,12 +653,11 @@ function generateStatusline() {
|
|
|
646
653
|
const totalDomains = progress.totalDomains || 5;
|
|
647
654
|
const dddProgress = progress.dddProgress || 0;
|
|
648
655
|
const patternsLearned = progress.patternsLearned || 0;
|
|
656
|
+
const activeSwarms = swarm.activeSwarms || 0;
|
|
649
657
|
const activeAgents = swarm.activeAgents || 0;
|
|
650
|
-
const maxAgents = swarm.maxAgents || CONFIG.maxAgents;
|
|
651
658
|
const coordinationActive = swarm.coordinationActive || false;
|
|
652
659
|
const intelligencePct = system.intelligencePct || 0;
|
|
653
660
|
const memoryMB = system.memoryMB || 0;
|
|
654
|
-
const subAgents = system.subAgents || 0;
|
|
655
661
|
const secCritHigh = (security.critical || 0) + (security.high || 0);
|
|
656
662
|
const secStatus = security.status || 'NONE';
|
|
657
663
|
const secLabel = secStatus === 'VULN' ? 'sec ' + secCritHigh + '!' : secStatus === 'CLEAN' ? 'sec ✓' : secStatus === 'STALE' ? 'sec stale' : 'sec —';
|
|
@@ -718,16 +724,16 @@ function generateStatusline() {
|
|
|
718
724
|
);
|
|
719
725
|
|
|
720
726
|
// Line 2: Swarm + Hooks + CVE + Memory + Intelligence
|
|
721
|
-
const
|
|
722
|
-
const agentsColor = activeAgents > 0 ? c.brightGreen : c.
|
|
727
|
+
const swarmsColor = activeSwarms > 0 ? c.brightGreen : c.dim;
|
|
728
|
+
const agentsColor = activeAgents > 0 ? c.brightGreen : c.dim;
|
|
723
729
|
const secIcon = secStatus === 'CLEAN' ? '🟢' : secStatus === 'STALE' ? '🟡' : (secStatus === 'NONE' ? '⚪' : '🔴');
|
|
724
730
|
const secColor = secStatus === 'CLEAN' ? c.brightGreen : secStatus === 'STALE' ? c.brightYellow : (secStatus === 'NONE' ? c.dim : c.brightRed);
|
|
725
731
|
const hooksColor = hooksEnabled > 0 ? c.brightGreen : c.dim;
|
|
726
732
|
const intellColor = intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
|
|
727
733
|
|
|
728
734
|
if (seg('swarm')) lines.push(
|
|
729
|
-
c.brightYellow + '
|
|
730
|
-
c.
|
|
735
|
+
c.brightYellow + '🐝 Swarms' + c.reset + ' ' + swarmsColor + activeSwarms + c.reset + ' ' +
|
|
736
|
+
c.brightYellow + '🤖 Agents' + c.reset + ' ' + agentsColor + activeAgents + c.reset + ' ' +
|
|
731
737
|
c.brightBlue + '🪝 ' + hooksColor + hooksEnabled + c.reset + '/' + c.brightWhite + hooksTotal + c.reset + ' ' +
|
|
732
738
|
secIcon + ' ' + secColor + secLabel + c.reset + ' ' +
|
|
733
739
|
c.brightCyan + '💾 ' + memoryMB + 'MB' + c.reset + ' ' +
|
|
@@ -63,23 +63,34 @@ export function crossAgentAgentsMd() {
|
|
|
63
63
|
## What swarmdo gives you
|
|
64
64
|
|
|
65
65
|
This project is wired to **swarmdo** — agent orchestration with persistent
|
|
66
|
-
vector memory, swarm coordination, and 300+ MCP tools.
|
|
66
|
+
vector memory, swarm coordination, cross-agent messaging, and 300+ MCP tools.
|
|
67
|
+
Everything below works the same from Codex, Copilot, pi, or a plain shell —
|
|
68
|
+
not just Claude Code.
|
|
67
69
|
|
|
68
|
-
- **MCP server**: \`swarmdo mcp start\` (stdio
|
|
69
|
-
\`swarmdo integrations install <your-cli>\` wires
|
|
70
|
-
\`memory_search\`, \`memory_store\`, \`swarm_init\`,
|
|
70
|
+
- **MCP server**: \`swarmdo mcp start\` (stdio; serves every tool by default).
|
|
71
|
+
If your CLI supports MCP, \`swarmdo integrations install <your-cli>\` wires
|
|
72
|
+
it. Key tools: \`memory_search\`, \`memory_store\`, \`swarm_init\`,
|
|
73
|
+
\`agent_spawn\`, \`comms_send\` / \`comms_inbox\` (message other agents),
|
|
74
|
+
\`hotspots\` / \`coupling\` / \`ownership\` (git-history analysis).
|
|
71
75
|
- **CLI**: \`npx swarmdo@latest <command>\` — \`memory search -q "topic"\`,
|
|
72
|
-
\`
|
|
76
|
+
\`comms send\` / \`comms inbox\`, \`standup\`, \`hotspots\`, \`coupling\`,
|
|
77
|
+
\`ownership\`, \`hidden-coupling\`, \`task\`, \`hud\`.
|
|
73
78
|
|
|
74
79
|
## Working agreement (any agent)
|
|
75
80
|
|
|
76
81
|
1. **Search memory BEFORE starting**: \`memory_search(query="task keywords")\`
|
|
77
82
|
— patterns with score > 0.7 are load-bearing precedent.
|
|
78
|
-
2. **
|
|
83
|
+
2. **Coordinate through the cross-tool mailbox**: announce the files you're
|
|
84
|
+
about to change with \`comms_send(to="all", message="…")\` and check
|
|
85
|
+
\`comms_inbox\` before overlapping work. Non-Claude agents: set a stable
|
|
86
|
+
identity with \`export SWARMDO_AGENT=<your-name>\` (or pass \`from\` /
|
|
87
|
+
\`--self\`) so replies address you — without it every agent on this host
|
|
88
|
+
shares the hostname identity.
|
|
89
|
+
3. **You are the executor** — swarmdo coordinates and remembers; it never
|
|
79
90
|
writes your code for you.
|
|
80
|
-
|
|
91
|
+
4. **Store what worked AFTER success**:
|
|
81
92
|
\`memory_store(key="pattern-…", value="what worked", namespace="patterns")\`.
|
|
82
|
-
|
|
93
|
+
5. Claude Code users: the same surfaces are namespaced under \`/sDo:\`
|
|
83
94
|
commands and \`/sdo-\` skills.
|
|
84
95
|
|
|
85
96
|
## Do not
|
|
@@ -12,7 +12,7 @@ import { loadMailbox, saveMailbox, resolveSelf, newMessageId, RETENTION } from '
|
|
|
12
12
|
export const commsTools = [
|
|
13
13
|
{
|
|
14
14
|
name: 'comms_send',
|
|
15
|
-
description: 'Send a message to another Claude Code
|
|
15
|
+
description: 'Send a message to another agent session — Claude Code, Codex, Copilot, pi, or any tool on the same repo (a cross-session/cross-tool mailbox). Address "all" to broadcast to every session. Use for multi-agent "multiplayer" coordination; delivery is via a shared file, not the network.',
|
|
16
16
|
category: 'comms',
|
|
17
17
|
inputSchema: {
|
|
18
18
|
type: 'object',
|
|
@@ -20,7 +20,7 @@ export const commsTools = [
|
|
|
20
20
|
to: { type: 'string', description: 'Recipient session name, or "all" to broadcast' },
|
|
21
21
|
message: { type: 'string', description: 'Message body' },
|
|
22
22
|
subject: { type: 'string', description: 'Optional subject line' },
|
|
23
|
-
from: { type: 'string', description: 'Sender name
|
|
23
|
+
from: { type: 'string', description: 'Sender name. Default: this session ($SWARMDO_SESSION, else $SWARMDO_AGENT, else hostname). Non-Claude agents should pass this (or export $SWARMDO_AGENT) so replies address them, not the shared hostname.' },
|
|
24
24
|
},
|
|
25
25
|
required: ['to', 'message'],
|
|
26
26
|
},
|
|
@@ -49,12 +49,12 @@ export const commsTools = [
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
name: 'comms_inbox',
|
|
52
|
-
description: 'List messages other sessions have sent to this
|
|
52
|
+
description: 'List messages other agent sessions (Claude Code, Codex, Copilot, pi, …) have sent to this one — a cross-session/cross-tool mailbox — newest first. Includes "all" broadcasts. Set markRead to acknowledge them.',
|
|
53
53
|
category: 'comms',
|
|
54
54
|
inputSchema: {
|
|
55
55
|
type: 'object',
|
|
56
56
|
properties: {
|
|
57
|
-
to: { type: 'string', description: 'Whose inbox (default: this session)' },
|
|
57
|
+
to: { type: 'string', description: 'Whose inbox (default: this session — $SWARMDO_SESSION, else $SWARMDO_AGENT, else hostname)' },
|
|
58
58
|
unreadOnly: { type: 'boolean', description: 'Only unread messages' },
|
|
59
59
|
from: { type: 'string', description: 'Only messages from this sender' },
|
|
60
60
|
since: { type: 'string', description: 'Only messages after this ISO-8601 timestamp' },
|
|
@@ -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) {
|