swarmdo 1.4.8 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/helpers/statusline.cjs +7 -7
- package/README.md +3 -1
- package/package.json +5 -3
- package/v3/@swarmdo/cli/dist/src/commands/hooks.js +26 -24
- package/v3/@swarmdo/cli/dist/src/commands/index.js +4 -0
- package/v3/@swarmdo/cli/dist/src/commands/integrations.d.ts +14 -0
- package/v3/@swarmdo/cli/dist/src/commands/integrations.js +158 -0
- package/v3/@swarmdo/cli/dist/src/commands/memory.js +50 -1
- package/v3/@swarmdo/cli/dist/src/commands/providers.js +3 -0
- package/v3/@swarmdo/cli/dist/src/commands/release.d.ts +15 -0
- package/v3/@swarmdo/cli/dist/src/commands/release.js +224 -0
- package/v3/@swarmdo/cli/dist/src/commands/security.js +14 -0
- package/v3/@swarmdo/cli/dist/src/commands/transcript.js +82 -1
- package/v3/@swarmdo/cli/dist/src/commands/usage.js +80 -1
- package/v3/@swarmdo/cli/dist/src/config-lint/lint.js +11 -1
- package/v3/@swarmdo/cli/dist/src/init/statusline-generator.js +6 -6
- package/v3/@swarmdo/cli/dist/src/integrations/integrations.d.ts +54 -0
- package/v3/@swarmdo/cli/dist/src/integrations/integrations.js +162 -0
- package/v3/@swarmdo/cli/dist/src/mcp-tools/agent-execute-core.js +25 -3
- package/v3/@swarmdo/cli/dist/src/mcp-tools/agentdb-tools.js +8 -8
- package/v3/@swarmdo/cli/dist/src/memory/graph-edge-writer.d.ts +12 -0
- package/v3/@swarmdo/cli/dist/src/memory/graph-edge-writer.js +32 -1
- package/v3/@swarmdo/cli/dist/src/memory-vault/watch.d.ts +32 -0
- package/v3/@swarmdo/cli/dist/src/memory-vault/watch.js +66 -0
- package/v3/@swarmdo/cli/dist/src/providers/openrouter-config.d.ts +91 -0
- package/v3/@swarmdo/cli/dist/src/providers/openrouter-config.js +186 -0
- package/v3/@swarmdo/cli/dist/src/release/release.d.ts +72 -0
- package/v3/@swarmdo/cli/dist/src/release/release.js +86 -0
- package/v3/@swarmdo/cli/dist/src/resilience/backoff.d.ts +23 -0
- package/v3/@swarmdo/cli/dist/src/resilience/backoff.js +30 -0
- package/v3/@swarmdo/cli/dist/src/swarmvector/model-router.js +14 -0
- package/v3/@swarmdo/cli/dist/src/transcript/search.d.ts +39 -0
- package/v3/@swarmdo/cli/dist/src/transcript/search.js +67 -0
- package/v3/@swarmdo/cli/dist/src/usage/diff.d.ts +69 -0
- package/v3/@swarmdo/cli/dist/src/usage/diff.js +112 -0
- package/v3/@swarmdo/cli/package.json +4 -4
- 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/v3/vendor/agentdb/package.json +0 -1
- package/v3/vendor/agentic-flow/package.json +0 -1
- package/.claude/scheduled_tasks.lock +0 -1
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/__main__.cpython-314.pyc +0 -0
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/compress.cpython-314.pyc +0 -0
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/detect.cpython-314.pyc +0 -0
- package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/validate.cpython-314.pyc +0 -0
- 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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* release.ts — `swarmdo release [patch|minor|major|x.y.z]`
|
|
3
|
+
*
|
|
4
|
+
* One command for the whole proven release train: bump the version trio +
|
|
5
|
+
* lockfile, sync doc version strings, commit+push, build + stage the
|
|
6
|
+
* self-contained @swarmdo/cli, publish both packages, verify the registry,
|
|
7
|
+
* tag, and cut a GitHub release with `swarmdo changelog` notes.
|
|
8
|
+
*
|
|
9
|
+
* DRY-RUN BY DEFAULT — prints the exact plan; `--confirm` executes it
|
|
10
|
+
* step-by-step and stops on the first failure.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import * as os from 'node:os';
|
|
15
|
+
import { execFileSync } from 'node:child_process';
|
|
16
|
+
import { output } from '../output.js';
|
|
17
|
+
import { planRelease, renderStep } from '../release/release.js';
|
|
18
|
+
function repoRootFrom(cwd) {
|
|
19
|
+
try {
|
|
20
|
+
return execFileSync('git', ['rev-parse', '--show-toplevel'], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function bumpJson(file, version) {
|
|
27
|
+
const d = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
28
|
+
d.version = version;
|
|
29
|
+
fs.writeFileSync(file, JSON.stringify(d, null, 2) + '\n');
|
|
30
|
+
}
|
|
31
|
+
function bumpLock(file, version) {
|
|
32
|
+
const d = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
33
|
+
d.version = version;
|
|
34
|
+
if (d.packages && d.packages[''])
|
|
35
|
+
d.packages[''].version = version;
|
|
36
|
+
fs.writeFileSync(file, JSON.stringify(d, null, 2) + '\n');
|
|
37
|
+
}
|
|
38
|
+
/** Replace the previous version's known doc occurrences with the next. */
|
|
39
|
+
function syncDocs(root, files, current, next) {
|
|
40
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
41
|
+
const touched = [];
|
|
42
|
+
for (const rel of files) {
|
|
43
|
+
const abs = path.join(root, rel);
|
|
44
|
+
if (!fs.existsSync(abs))
|
|
45
|
+
continue;
|
|
46
|
+
const before = fs.readFileSync(abs, 'utf8');
|
|
47
|
+
let after = before;
|
|
48
|
+
// exact patterns used by every release since 1.4.x
|
|
49
|
+
after = after.replaceAll(`**Swarmdo v${current}** (`, `**Swarmdo v${next}** (`);
|
|
50
|
+
after = after.replace(new RegExp(`\\*\\*Swarmdo v${next.replace(/\./g, '\\.')}\\*\\* \\(\\d{4}-\\d{2}-\\d{2}\\)`), `**Swarmdo v${next}** (${today})`);
|
|
51
|
+
after = after.replaceAll(`swarmdo@${current}\` (umbrella), \`@swarmdo/cli@${current}\`, \`swarmdo-bridge@${current}\``, `swarmdo@${next}\` (umbrella), \`@swarmdo/cli@${next}\`, \`swarmdo-bridge@${next}\``);
|
|
52
|
+
after = after.replaceAll(`npx%20swarmdo-v${current}-cb3837`, `npx%20swarmdo-v${next}-cb3837`);
|
|
53
|
+
after = after.replaceAll(`"softwareVersion":"${current}"`, `"softwareVersion":"${next}"`);
|
|
54
|
+
after = after.replaceAll(`<span class="ver">v${current} · MIT</span>`, `<span class="ver">v${next} · MIT</span>`);
|
|
55
|
+
after = after.replaceAll(`▊ Swarmdo V${current} `, `▊ Swarmdo V${next} `);
|
|
56
|
+
if (after !== before) {
|
|
57
|
+
fs.writeFileSync(abs, after);
|
|
58
|
+
touched.push(rel);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return touched;
|
|
62
|
+
}
|
|
63
|
+
async function executePlan(plan, root) {
|
|
64
|
+
const run = (s) => {
|
|
65
|
+
output.writeln(output.dim(` $ ${s.cmd} ${s.args.join(' ')} (${path.relative(root, s.cwd) || '.'})`));
|
|
66
|
+
execFileSync(s.cmd, s.args, { cwd: s.cwd, stdio: 'inherit' });
|
|
67
|
+
};
|
|
68
|
+
for (const [i, step] of plan.steps.entries()) {
|
|
69
|
+
output.writeln(output.bold(`[${i + 1}/${plan.steps.length}] ${renderStep(step)}`));
|
|
70
|
+
switch (step.kind) {
|
|
71
|
+
case 'bump-json':
|
|
72
|
+
bumpJson(path.join(root, step.file), step.version);
|
|
73
|
+
break;
|
|
74
|
+
case 'bump-lock':
|
|
75
|
+
bumpLock(path.join(root, step.file), step.version);
|
|
76
|
+
break;
|
|
77
|
+
case 'sync-docs': {
|
|
78
|
+
const touched = syncDocs(root, step.files, plan.current, plan.next);
|
|
79
|
+
output.writeln(output.dim(` synced: ${touched.join(', ') || '(none)'}`));
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case 'exec':
|
|
83
|
+
run(step);
|
|
84
|
+
break;
|
|
85
|
+
case 'verify-npm': {
|
|
86
|
+
for (const pkg of step.packages) {
|
|
87
|
+
let seen = '';
|
|
88
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
89
|
+
try {
|
|
90
|
+
seen = execFileSync('npm', ['view', `${pkg}@latest`, 'version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
seen = '';
|
|
94
|
+
}
|
|
95
|
+
if (seen === step.version)
|
|
96
|
+
break;
|
|
97
|
+
execFileSync('sleep', ['3']);
|
|
98
|
+
}
|
|
99
|
+
if (seen !== step.version) {
|
|
100
|
+
output.printError(`${pkg}@latest is "${seen || '(unset)'}" — expected ${step.version}`);
|
|
101
|
+
return { success: false, exitCode: 1 };
|
|
102
|
+
}
|
|
103
|
+
output.writeln(output.dim(` ${pkg}@latest = ${seen} ✓`));
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case 'deploy-site': {
|
|
108
|
+
// user rule 2026-07-07: the live site ships with every release.
|
|
109
|
+
// Copy the working copy into the SwarmDo/swarmdo.com repo, push,
|
|
110
|
+
// and verify production actually serves the new version string.
|
|
111
|
+
const siteDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmdo-site-'));
|
|
112
|
+
execFileSync('gh', ['repo', 'clone', 'SwarmDo/swarmdo.com', siteDir, '--', '-q'], { stdio: 'inherit' });
|
|
113
|
+
fs.copyFileSync(path.join(root, 'website', 'index.html'), path.join(siteDir, 'index.html'));
|
|
114
|
+
const smap = path.join(siteDir, 'sitemap.xml');
|
|
115
|
+
if (fs.existsSync(smap)) {
|
|
116
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
117
|
+
fs.writeFileSync(smap, fs.readFileSync(smap, 'utf8').replace(/<lastmod>[^<]*<\/lastmod>/g, `<lastmod>${today}</lastmod>`));
|
|
118
|
+
}
|
|
119
|
+
const g = (args) => { execFileSync('git', args, { cwd: siteDir, stdio: 'inherit' }); };
|
|
120
|
+
g(['add', '-A']);
|
|
121
|
+
try {
|
|
122
|
+
g(['commit', '-m', `release: sync site for v${plan.next}\n\nCo-Authored-By: Swarmdo <maintainers@swarmdo.com>`]);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
output.writeln(output.dim(' site already in sync — nothing to commit'));
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
g(['push', 'origin', 'main']);
|
|
129
|
+
// poll production (GitHub Pages deploys in ~1min)
|
|
130
|
+
let live = false;
|
|
131
|
+
for (let i = 0; i < 30; i++) {
|
|
132
|
+
try {
|
|
133
|
+
const body = execFileSync('curl', ['-s', 'https://swarmdo.com'], { encoding: 'utf8' });
|
|
134
|
+
if (body.includes(`v${plan.next}`)) {
|
|
135
|
+
live = true;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch { /* transient */ }
|
|
140
|
+
execFileSync('sleep', ['10']);
|
|
141
|
+
}
|
|
142
|
+
if (!live) {
|
|
143
|
+
output.printError(`swarmdo.com is not serving v${plan.next} after 5min — check the Pages build`);
|
|
144
|
+
return { success: false, exitCode: 1 };
|
|
145
|
+
}
|
|
146
|
+
output.writeln(output.dim(` swarmdo.com serves v${plan.next} ✓`));
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'gh-release': {
|
|
150
|
+
const notes = path.join(os.tmpdir(), `swarmdo-relnotes-${process.pid}.md`);
|
|
151
|
+
const { changelogCommand } = await import('./changelog.js');
|
|
152
|
+
const r = await changelogCommand.action({ args: [], flags: { from: step.notesFrom, version: plan.tag, out: notes }, cwd: root, interactive: false });
|
|
153
|
+
if (r && r.success === false)
|
|
154
|
+
return { success: false, exitCode: 1 };
|
|
155
|
+
execFileSync('gh', ['release', 'create', plan.tag, '--title', `${plan.tag}`, '--notes-file', notes], { cwd: root, stdio: 'inherit' });
|
|
156
|
+
try {
|
|
157
|
+
fs.rmSync(notes, { force: true });
|
|
158
|
+
}
|
|
159
|
+
catch { /* best-effort */ }
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
output.printSuccess(`released ${plan.tag}`);
|
|
165
|
+
return { success: true, exitCode: 0 };
|
|
166
|
+
}
|
|
167
|
+
export const releaseCommand = {
|
|
168
|
+
name: 'release',
|
|
169
|
+
aliases: ['ship'],
|
|
170
|
+
description: 'Run the full release train: bump trio+docs, commit, build+stage, publish both npm packages, verify, tag, GitHub release — dry-run unless --confirm',
|
|
171
|
+
options: [
|
|
172
|
+
{ name: 'confirm', type: 'boolean', description: 'actually execute (default: print the plan)', default: false },
|
|
173
|
+
{ name: 'skip-publish', type: 'boolean', description: 'skip npm publish + registry verify steps', default: false },
|
|
174
|
+
{ name: 'skip-gh-release', type: 'boolean', description: 'skip the GitHub release step', default: false },
|
|
175
|
+
{ name: 'skip-site', type: 'boolean', description: 'skip the live-site deploy (docs-sync rule: only for zero-user-facing releases)', default: false },
|
|
176
|
+
{ name: 'json', type: 'boolean', description: 'print the plan as JSON', default: false },
|
|
177
|
+
],
|
|
178
|
+
examples: [
|
|
179
|
+
{ command: 'swarmdo release', description: 'Plan a patch release (dry-run)' },
|
|
180
|
+
{ command: 'swarmdo release minor --confirm', description: 'Execute a minor release end-to-end' },
|
|
181
|
+
{ command: 'swarmdo release 2.0.0 --skip-publish --confirm', description: 'Bump/tag/release 2.0.0 without publishing to npm' },
|
|
182
|
+
],
|
|
183
|
+
action: async (ctx) => {
|
|
184
|
+
const cwd = ctx.cwd || process.cwd();
|
|
185
|
+
const root = repoRootFrom(cwd);
|
|
186
|
+
if (!root) {
|
|
187
|
+
output.printError('not a git repository');
|
|
188
|
+
return { success: false, exitCode: 1 };
|
|
189
|
+
}
|
|
190
|
+
const trioHead = path.join(root, 'v3/@swarmdo/cli/package.json');
|
|
191
|
+
if (!fs.existsSync(trioHead)) {
|
|
192
|
+
output.printError('this does not look like the swarmdo repo (v3/@swarmdo/cli/package.json missing)');
|
|
193
|
+
return { success: false, exitCode: 1 };
|
|
194
|
+
}
|
|
195
|
+
const current = String(JSON.parse(fs.readFileSync(trioHead, 'utf8')).version ?? '');
|
|
196
|
+
let plan;
|
|
197
|
+
try {
|
|
198
|
+
plan = planRelease({
|
|
199
|
+
current,
|
|
200
|
+
bump: (ctx.args[0] || 'patch').toLowerCase(),
|
|
201
|
+
repoRoot: root,
|
|
202
|
+
skipPublish: ctx.flags['skip-publish'] === true,
|
|
203
|
+
skipGhRelease: ctx.flags['skip-gh-release'] === true,
|
|
204
|
+
skipSite: ctx.flags['skip-site'] === true,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
output.printError(e.message);
|
|
209
|
+
return { success: false, exitCode: 1 };
|
|
210
|
+
}
|
|
211
|
+
if (ctx.flags.json === true) {
|
|
212
|
+
output.printJson(plan);
|
|
213
|
+
return { success: true, data: plan };
|
|
214
|
+
}
|
|
215
|
+
if (ctx.flags.confirm !== true) {
|
|
216
|
+
output.writeln(output.bold(`Release plan ${plan.current} → ${plan.next}`) + output.dim(' (dry-run — re-run with --confirm to execute)'));
|
|
217
|
+
plan.steps.forEach((s, i) => output.writeln(` ${String(i + 1).padStart(2)}. ${renderStep(s)}`));
|
|
218
|
+
return { success: true, data: { dryRun: true, ...plan } };
|
|
219
|
+
}
|
|
220
|
+
return executePlan(plan, root);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
export default releaseCommand;
|
|
224
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { output } from '../output.js';
|
|
8
8
|
import { execSync } from 'node:child_process';
|
|
9
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
9
10
|
// Scan subcommand
|
|
10
11
|
const scanCommand = {
|
|
11
12
|
name: 'scan',
|
|
@@ -190,6 +191,19 @@ const scanCommand = {
|
|
|
190
191
|
scanCodeDir(path.resolve(target), scanDepth);
|
|
191
192
|
}
|
|
192
193
|
spinner.succeed('Scan complete');
|
|
194
|
+
// Persist the summary so the statusline (and future tooling) reflects
|
|
195
|
+
// real scans instead of the retired V3 CVE tracker (v1.4.17).
|
|
196
|
+
try {
|
|
197
|
+
const artifactDir = path.join(process.cwd(), '.swarmdo', 'security');
|
|
198
|
+
mkdirSync(artifactDir, { recursive: true });
|
|
199
|
+
writeFileSync(path.join(artifactDir, 'last-scan.json'), JSON.stringify({
|
|
200
|
+
scannedAt: new Date().toISOString(),
|
|
201
|
+
target, depth, type: scanType,
|
|
202
|
+
critical: criticalCount, high: highCount, medium: mediumCount, low: lowCount,
|
|
203
|
+
total: findings.length,
|
|
204
|
+
}, null, 2) + '\n');
|
|
205
|
+
}
|
|
206
|
+
catch { /* statusline signal is best-effort */ }
|
|
193
207
|
// Display results
|
|
194
208
|
output.writeln();
|
|
195
209
|
if (findings.length > 0) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* unit-tested; reuses the usage transcript infra).
|
|
10
10
|
*/
|
|
11
11
|
import * as fs from 'node:fs';
|
|
12
|
+
import { parseQuery, searchLines, rankMatches } from '../transcript/search.js';
|
|
12
13
|
import { output } from '../output.js';
|
|
13
14
|
import { listSessions, exportSession } from '../transcript/export.js';
|
|
14
15
|
function fmtAge(mtimeMs, nowMs) {
|
|
@@ -108,11 +109,91 @@ const exportCommand = {
|
|
|
108
109
|
return { success: true, data: { turns: res.turns, sessionId: res.sessionId } };
|
|
109
110
|
},
|
|
110
111
|
};
|
|
112
|
+
// Full-text search across session transcripts ("which session did I discuss X in?")
|
|
113
|
+
const searchCommand = {
|
|
114
|
+
name: 'search',
|
|
115
|
+
description: 'Search what you and Claude actually said across all session transcripts',
|
|
116
|
+
options: [
|
|
117
|
+
{ name: 'limit', short: 'n', type: 'number', description: 'sessions to show', default: 10 },
|
|
118
|
+
{ name: 'json', type: 'boolean', description: 'machine-readable output', default: false },
|
|
119
|
+
],
|
|
120
|
+
examples: [
|
|
121
|
+
{ command: 'swarmdo transcript search obsidian vault', description: 'Sessions mentioning both terms (AND)' },
|
|
122
|
+
{ command: 'swarmdo tx search "npm publish" -n 5', description: 'Top 5 sessions about npm publish' },
|
|
123
|
+
],
|
|
124
|
+
action: async (ctx) => {
|
|
125
|
+
const fs = await import('node:fs');
|
|
126
|
+
const { defaultClaudeProjectDirs, findTranscriptFiles } = await import('../usage/transcript-usage.js');
|
|
127
|
+
const { sessionIdFromFile } = await import('../transcript/export.js');
|
|
128
|
+
let terms;
|
|
129
|
+
try {
|
|
130
|
+
terms = parseQuery(ctx.args.slice(1).join(' '));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
output.printError('usage: swarmdo transcript search <terms…>');
|
|
134
|
+
return { success: false, exitCode: 1 };
|
|
135
|
+
}
|
|
136
|
+
const matches = [];
|
|
137
|
+
let scanned = 0;
|
|
138
|
+
for (const dir of defaultClaudeProjectDirs()) {
|
|
139
|
+
for (const { file, project } of findTranscriptFiles(dir)) {
|
|
140
|
+
scanned++;
|
|
141
|
+
let raw;
|
|
142
|
+
try {
|
|
143
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const lines = raw.split('\n').flatMap((l) => {
|
|
149
|
+
if (!l.trim())
|
|
150
|
+
return [];
|
|
151
|
+
try {
|
|
152
|
+
return [JSON.parse(l)];
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const { hits, snippets } = searchLines(lines, terms);
|
|
159
|
+
if (hits > 0) {
|
|
160
|
+
let mtimeMs = 0;
|
|
161
|
+
try {
|
|
162
|
+
mtimeMs = fs.statSync(file).mtimeMs;
|
|
163
|
+
}
|
|
164
|
+
catch { /* keep 0 */ }
|
|
165
|
+
matches.push({ sessionId: sessionIdFromFile(file), project, mtimeMs, hits, snippets });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const ranked = rankMatches(matches).slice(0, Number(ctx.flags.limit) || 10);
|
|
170
|
+
if (ctx.flags.json === true) {
|
|
171
|
+
output.printJson({ query: terms, scanned, matched: matches.length, sessions: ranked });
|
|
172
|
+
return { success: true, data: ranked };
|
|
173
|
+
}
|
|
174
|
+
if (ranked.length === 0) {
|
|
175
|
+
output.writeln(output.dim(`no sessions matched "${terms.join(' ')}" (${scanned} transcripts scanned)`));
|
|
176
|
+
return { success: true, exitCode: 0 };
|
|
177
|
+
}
|
|
178
|
+
output.writeln(output.bold(`${matches.length} session(s) match "${terms.join(' ')}"`) + output.dim(` — ${scanned} transcripts scanned`));
|
|
179
|
+
for (const m of ranked) {
|
|
180
|
+
const when = m.mtimeMs ? new Date(m.mtimeMs).toISOString().slice(0, 16).replace('T', ' ') : '?';
|
|
181
|
+
output.writeln('');
|
|
182
|
+
output.writeln(`${output.info(m.sessionId.slice(0, 8))} ${output.dim(when)} ${m.hits} hit${m.hits === 1 ? '' : 's'} ${output.dim(m.project)}`);
|
|
183
|
+
for (const sn of m.snippets) {
|
|
184
|
+
output.writeln(` ${sn.role === 'user' ? '👤' : '🤖'} ${sn.snippet}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
output.writeln('');
|
|
188
|
+
output.writeln(output.dim('open one: swarmdo transcript export -s <id-prefix>'));
|
|
189
|
+
return { success: true, data: ranked };
|
|
190
|
+
},
|
|
191
|
+
};
|
|
111
192
|
export const transcriptCommand = {
|
|
112
193
|
name: 'transcript',
|
|
113
194
|
aliases: ['tx'],
|
|
114
195
|
description: 'Export Claude Code sessions to readable Markdown (list/export)',
|
|
115
|
-
subcommands: [listCommand, exportCommand],
|
|
196
|
+
subcommands: [listCommand, exportCommand, searchCommand],
|
|
116
197
|
options: [],
|
|
117
198
|
examples: [
|
|
118
199
|
{ command: 'swarmdo transcript list', description: 'Recent sessions, newest first' },
|
|
@@ -17,6 +17,7 @@ import { aggregateBlocks, aggregateUsage, collectUsage, totalUsage, localDateKey
|
|
|
17
17
|
import { collectToolErrors } from '../usage/transcript-errors.js';
|
|
18
18
|
import { computeCacheStats } from '../usage/cache-stats.js';
|
|
19
19
|
import { evaluateGuard } from '../usage/spend-guard.js';
|
|
20
|
+
import { resolvePeriodPair, parseRange, diffPeriods, modelMovers } from '../usage/diff.js';
|
|
20
21
|
const VIEWS = {
|
|
21
22
|
daily: { dimension: 'day', label: 'Date' },
|
|
22
23
|
monthly: { dimension: 'month', label: 'Month' },
|
|
@@ -232,6 +233,79 @@ function runCacheView(ctx, collection) {
|
|
|
232
233
|
output.writeln(output.dim('"From cache" = share of input tokens served as cache reads (0.1x cost); higher is cheaper.'));
|
|
233
234
|
return { success: true, exitCode: 0 };
|
|
234
235
|
}
|
|
236
|
+
/** Diff view — compare two periods (day|week|month presets or explicit
|
|
237
|
+
* --a/--b YYYY-MM-DD:YYYY-MM-DD ranges): totals, deltas, per-model movers. */
|
|
238
|
+
function runDiffView(ctx, collection) {
|
|
239
|
+
const kind = (ctx.args[1] || 'week').toLowerCase();
|
|
240
|
+
let a;
|
|
241
|
+
let b;
|
|
242
|
+
try {
|
|
243
|
+
if (typeof ctx.flags.a === 'string' || typeof ctx.flags.b === 'string') {
|
|
244
|
+
if (typeof ctx.flags.a !== 'string' || typeof ctx.flags.b !== 'string') {
|
|
245
|
+
output.printError('explicit ranges need BOTH --a and --b (YYYY-MM-DD:YYYY-MM-DD)');
|
|
246
|
+
return { success: false, exitCode: 1 };
|
|
247
|
+
}
|
|
248
|
+
a = parseRange(ctx.flags.a, 'A');
|
|
249
|
+
b = parseRange(ctx.flags.b, 'B');
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
({ a, b } = resolvePeriodPair(kind, localDateKey(new Date())));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (e) {
|
|
256
|
+
output.printError(e.message);
|
|
257
|
+
return { success: false, exitCode: 1 };
|
|
258
|
+
}
|
|
259
|
+
const dayRows = aggregateUsage(collection.events, 'day').map((r) => ({ key: r.key, totals: r.totals }));
|
|
260
|
+
const report = diffPeriods(dayRows, a, b);
|
|
261
|
+
// per-(model, day) fold for the movers table
|
|
262
|
+
const md = new Map();
|
|
263
|
+
for (const e of collection.events) {
|
|
264
|
+
const k = `${e.model}\u0000${e.dateKey}`;
|
|
265
|
+
const row = md.get(k) ?? { key: e.model, day: e.dateKey, totals: { costUsd: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0 } };
|
|
266
|
+
row.totals.costUsd += e.costUsd;
|
|
267
|
+
row.totals.totalTokens += e.inputTokens + e.outputTokens + e.cacheWriteTokens + e.cacheReadTokens;
|
|
268
|
+
md.set(k, row);
|
|
269
|
+
}
|
|
270
|
+
const movers = modelMovers([...md.values()], a, b);
|
|
271
|
+
if (ctx.flags.json === true) {
|
|
272
|
+
output.printJson({ ...report, movers });
|
|
273
|
+
return { success: true, data: { ...report, movers } };
|
|
274
|
+
}
|
|
275
|
+
const pct = (m) => (m.pct === null ? 'new' : `${m.pct >= 0 ? '+' : ''}${Math.round(m.pct * 100)}%`);
|
|
276
|
+
const sign = (n, f) => `${n >= 0 ? '+' : '−'}${f(Math.abs(n))}`;
|
|
277
|
+
output.writeln(output.bold(`Usage diff ${a.label} vs ${b.label}`) + output.dim(` (${a.from}..${a.to} vs ${b.from}..${b.to})`));
|
|
278
|
+
output.printTable({
|
|
279
|
+
columns: [
|
|
280
|
+
{ key: 'metric', header: 'Metric', width: 14 },
|
|
281
|
+
{ key: 'a', header: a.label.slice(0, 14), width: 14, align: 'right' },
|
|
282
|
+
{ key: 'b', header: b.label.slice(0, 14), width: 14, align: 'right' },
|
|
283
|
+
{ key: 'delta', header: 'Δ', width: 14, align: 'right' },
|
|
284
|
+
{ key: 'pct', header: '%', width: 7, align: 'right' },
|
|
285
|
+
],
|
|
286
|
+
data: [
|
|
287
|
+
{ metric: 'Cost', a: fmtCost(report.cost.a), b: fmtCost(report.cost.b), delta: sign(report.cost.delta, fmtCost), pct: pct(report.cost) },
|
|
288
|
+
{ metric: 'Tokens', a: fmtInt(report.totalTokens.a), b: fmtInt(report.totalTokens.b), delta: sign(report.totalTokens.delta, fmtInt), pct: pct(report.totalTokens) },
|
|
289
|
+
{ metric: 'Output tok', a: fmtInt(report.outputTokens.a), b: fmtInt(report.outputTokens.b), delta: sign(report.outputTokens.delta, fmtInt), pct: pct(report.outputTokens) },
|
|
290
|
+
{ metric: 'Cache reads', a: fmtInt(report.cacheReadTokens.a), b: fmtInt(report.cacheReadTokens.b), delta: sign(report.cacheReadTokens.delta, fmtInt), pct: pct(report.cacheReadTokens) },
|
|
291
|
+
{ metric: 'Active days', a: String(report.activeDays.a), b: String(report.activeDays.b), delta: sign(report.activeDays.delta, String), pct: pct(report.activeDays) },
|
|
292
|
+
],
|
|
293
|
+
});
|
|
294
|
+
if (movers.length > 0) {
|
|
295
|
+
output.writeln(output.bold('Model movers') + output.dim(' (by |Δ cost|)'));
|
|
296
|
+
output.printTable({
|
|
297
|
+
columns: [
|
|
298
|
+
{ key: 'model', header: 'Model', width: 34 },
|
|
299
|
+
{ key: 'a', header: 'A', width: 12, align: 'right' },
|
|
300
|
+
{ key: 'b', header: 'B', width: 12, align: 'right' },
|
|
301
|
+
{ key: 'delta', header: 'Δ', width: 12, align: 'right' },
|
|
302
|
+
{ key: 'pct', header: '%', width: 7, align: 'right' },
|
|
303
|
+
],
|
|
304
|
+
data: movers.map((m) => ({ model: m.model, a: fmtCost(m.cost.a), b: fmtCost(m.cost.b), delta: sign(m.cost.delta, fmtCost), pct: pct(m.cost) })),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return { success: true, data: { ...report, movers } };
|
|
308
|
+
}
|
|
235
309
|
/** Build a threshold from a --flag or its SWARMDO_GUARD_* env fallback. */
|
|
236
310
|
function guardThreshold(ctx, flagKey, envKey, current, label, unit) {
|
|
237
311
|
const raw = ctx.flags[flagKey] ?? process.env[envKey];
|
|
@@ -330,9 +404,14 @@ async function run(ctx) {
|
|
|
330
404
|
const dirs = typeof dirFlag === 'string' ? [dirFlag] : Array.isArray(dirFlag) ? dirFlag.map(String) : undefined;
|
|
331
405
|
return runGuardView(ctx, collectUsage({ dirs }));
|
|
332
406
|
}
|
|
407
|
+
if (viewName === 'diff') {
|
|
408
|
+
const dirFlag = ctx.flags.dir;
|
|
409
|
+
const dirs = typeof dirFlag === 'string' ? [dirFlag] : Array.isArray(dirFlag) ? dirFlag.map(String) : undefined;
|
|
410
|
+
return runDiffView(ctx, collectUsage({ dirs }));
|
|
411
|
+
}
|
|
333
412
|
const view = VIEWS[viewName];
|
|
334
413
|
if (!view) {
|
|
335
|
-
output.writeln(output.error(`unknown view: ${viewName} (expected ${Object.keys(VIEWS).join('|')}|blocks|errors|cache|guard)`));
|
|
414
|
+
output.writeln(output.error(`unknown view: ${viewName} (expected ${Object.keys(VIEWS).join('|')}|blocks|errors|cache|guard|diff)`));
|
|
336
415
|
return { success: false, exitCode: 1 };
|
|
337
416
|
}
|
|
338
417
|
const since = typeof ctx.flags.since === 'string' ? ctx.flags.since : undefined;
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
const f = (file, severity, rule, message) => ({ file, severity, rule, message });
|
|
12
12
|
export const TOPOLOGIES = ['hierarchical', 'mesh', 'hierarchical-mesh', 'ring', 'star', 'hybrid', 'adaptive'];
|
|
13
13
|
export const MEMORY_BACKENDS = ['agentdb', 'sqlite', 'hybrid', 'memory'];
|
|
14
|
-
|
|
14
|
+
import { parseOpenRouterConfig } from '../providers/openrouter-config.js';
|
|
15
|
+
export const KNOWN_CONFIG_KEYS = ['topology', 'maxAgents', 'strategy', 'consensus', 'memory', 'memoryBackend', 'hnsw', 'neural', 'embeddings', 'providers', 'mcp', 'logging', 'daemon', 'hooks', 'version', 'openrouter', '$schema'];
|
|
15
16
|
export const HOOK_EVENTS = [
|
|
16
17
|
'PreToolUse', 'PostToolUse', 'UserPromptSubmit', 'Notification', 'Stop', 'SubagentStop',
|
|
17
18
|
'SessionStart', 'SessionEnd', 'PreCompact', 'TeammateIdle', 'TaskCompleted', 'PermissionDecision',
|
|
@@ -39,6 +40,15 @@ export function lintSwarmdoConfig(file, obj) {
|
|
|
39
40
|
for (const key of Object.keys(c)) {
|
|
40
41
|
if (!KNOWN_CONFIG_KEYS.includes(key))
|
|
41
42
|
out.push(f(file, 'warn', 'unknown-key', `unknown key "${key}" (known: ${KNOWN_CONFIG_KEYS.filter(k => k !== '$schema').join(', ')})`));
|
|
43
|
+
if (key === 'openrouter') {
|
|
44
|
+
// reuse the runtime parser so lint findings and runtime behavior can't drift
|
|
45
|
+
const { config: orCfg, warnings } = parseOpenRouterConfig(c.openrouter);
|
|
46
|
+
for (const w of warnings)
|
|
47
|
+
out.push(f(file, 'warn', 'openrouter-config', w));
|
|
48
|
+
if (orCfg.enabled && orCfg.models.length === 0 && !orCfg.defaultModel) {
|
|
49
|
+
out.push(f(file, 'warn', 'openrouter-config', 'openrouter.enabled=true but no valid models[] or defaultModel — swarms have nothing to select from'));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
53
|
if (c.topology !== undefined && !TOPOLOGIES.includes(String(c.topology))) {
|
|
44
54
|
out.push(f(file, 'error', 'bad-topology', `topology "${String(c.topology)}" is not one of: ${TOPOLOGIES.join(', ')}`));
|
|
@@ -384,7 +384,7 @@ function buildLocalFallback() {
|
|
|
384
384
|
return applyLocalOverlays({
|
|
385
385
|
user: { name: 'user', gitBranch: '', modelName: 'Claude Code' },
|
|
386
386
|
v3Progress: { domainsCompleted: 0, totalDomains: 5, dddProgress: 0, patternsLearned: 0, sessionsCompleted: 0 },
|
|
387
|
-
security: { status: 'NONE',
|
|
387
|
+
security: { status: 'NONE', critical: 0, high: 0, total: 0 },
|
|
388
388
|
swarm: { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false },
|
|
389
389
|
system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0, subAgents: 0 },
|
|
390
390
|
lastUpdated: new Date().toISOString(),
|
|
@@ -652,9 +652,9 @@ function generateStatusline() {
|
|
|
652
652
|
const intelligencePct = system.intelligencePct || 0;
|
|
653
653
|
const memoryMB = system.memoryMB || 0;
|
|
654
654
|
const subAgents = system.subAgents || 0;
|
|
655
|
-
const
|
|
656
|
-
const totalCves = security.totalCves || 0;
|
|
655
|
+
const secCritHigh = (security.critical || 0) + (security.high || 0);
|
|
657
656
|
const secStatus = security.status || 'NONE';
|
|
657
|
+
const secLabel = secStatus === 'VULN' ? 'sec ' + secCritHigh + '!' : secStatus === 'CLEAN' ? 'sec ✓' : secStatus === 'STALE' ? 'sec stale' : 'sec —';
|
|
658
658
|
const adrCount = adrs.count || 0;
|
|
659
659
|
const adrImpl = adrs.implemented || 0;
|
|
660
660
|
const hooksEnabled = hooks.enabled || 0;
|
|
@@ -720,8 +720,8 @@ function generateStatusline() {
|
|
|
720
720
|
// Line 2: Swarm + Hooks + CVE + Memory + Intelligence
|
|
721
721
|
const swarmInd = coordinationActive ? c.brightGreen + '◉' + c.reset : c.dim + '○' + c.reset;
|
|
722
722
|
const agentsColor = activeAgents > 0 ? c.brightGreen : c.red;
|
|
723
|
-
const secIcon = secStatus === 'CLEAN' ? '🟢' :
|
|
724
|
-
const secColor = secStatus === 'CLEAN' ? c.brightGreen :
|
|
723
|
+
const secIcon = secStatus === 'CLEAN' ? '🟢' : secStatus === 'STALE' ? '🟡' : (secStatus === 'NONE' ? '⚪' : '🔴');
|
|
724
|
+
const secColor = secStatus === 'CLEAN' ? c.brightGreen : secStatus === 'STALE' ? c.brightYellow : (secStatus === 'NONE' ? c.dim : c.brightRed);
|
|
725
725
|
const hooksColor = hooksEnabled > 0 ? c.brightGreen : c.dim;
|
|
726
726
|
const intellColor = intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
|
|
727
727
|
|
|
@@ -729,7 +729,7 @@ function generateStatusline() {
|
|
|
729
729
|
c.brightYellow + '🤖 Swarm' + c.reset + ' ' + swarmInd + ' [' + agentsColor + String(activeAgents).padStart(2) + c.reset + '/' + c.brightWhite + maxAgents + c.reset + '] ' +
|
|
730
730
|
c.brightPurple + '👥 ' + subAgents + c.reset + ' ' +
|
|
731
731
|
c.brightBlue + '🪝 ' + hooksColor + hooksEnabled + c.reset + '/' + c.brightWhite + hooksTotal + c.reset + ' ' +
|
|
732
|
-
secIcon + ' ' + secColor +
|
|
732
|
+
secIcon + ' ' + secColor + secLabel + c.reset + ' ' +
|
|
733
733
|
c.brightCyan + '💾 ' + memoryMB + 'MB' + c.reset + ' ' +
|
|
734
734
|
intellColor + '🧠 ' + String(intelligencePct).padStart(3) + '%' + c.reset
|
|
735
735
|
);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* integrations.ts — wire swarmdo into agent CLIs beyond Claude Code.
|
|
3
|
+
*
|
|
4
|
+
* Targets: OpenAI Codex CLI, GitHub Copilot CLI, pi. Two standards do the
|
|
5
|
+
* heavy lifting: AGENTS.md (the cross-agent instructions file all three
|
|
6
|
+
* read) and MCP (swarmdo already ships a stdio server — `swarmdo mcp
|
|
7
|
+
* start`). Each merge below is PURE (string/JSON in → out), additive, and
|
|
8
|
+
* idempotent, so the whole surface is unit-testable and re-running install
|
|
9
|
+
* never duplicates or clobbers.
|
|
10
|
+
*
|
|
11
|
+
* INVARIANT (do-not-break-Claude): nothing in this module produces content
|
|
12
|
+
* for `.claude/**`, `.mcp.json`, or `CLAUDE.md` — the Claude Code surfaces
|
|
13
|
+
* are owned by init/mcp-generator and are only ever READ for status here.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MCP_COMMAND = "npx";
|
|
16
|
+
export declare const MCP_ARGS: string[];
|
|
17
|
+
/** Codex CLI (~/.codex/config.toml): add the marked [mcp_servers.swarmdo]
|
|
18
|
+
* block when absent. Existing content — including a user's own hand-written
|
|
19
|
+
* swarmdo server — is left untouched. */
|
|
20
|
+
export declare function mergeCodexToml(existing: string | null): {
|
|
21
|
+
content: string;
|
|
22
|
+
changed: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Copilot CLI (~/.copilot/mcp-config.json): same mcpServers schema Claude
|
|
25
|
+
* uses. Adds the swarmdo entry when absent; other servers preserved. */
|
|
26
|
+
export declare function mergeCopilotMcpJson(existing: string | null): {
|
|
27
|
+
content: string;
|
|
28
|
+
changed: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** Cross-agent AGENTS.md for projects that don't have one. Existing files
|
|
31
|
+
* are never rewritten (report-only) — teams own their AGENTS.md. */
|
|
32
|
+
export declare function crossAgentAgentsMd(): string;
|
|
33
|
+
/** .github/copilot-instructions.md — Copilot reads this per-repo. Kept as a
|
|
34
|
+
* thin pointer so AGENTS.md stays the single source of truth. */
|
|
35
|
+
export declare function copilotInstructionsMd(): string;
|
|
36
|
+
export type IntegrationTarget = 'codex' | 'copilot' | 'pi' | 'claude';
|
|
37
|
+
export declare const INSTALLABLE: IntegrationTarget[];
|
|
38
|
+
export interface TargetStatus {
|
|
39
|
+
target: IntegrationTarget;
|
|
40
|
+
ok: boolean;
|
|
41
|
+
details: string[];
|
|
42
|
+
}
|
|
43
|
+
/** Pure status evaluation over pre-read file contents (null = absent). */
|
|
44
|
+
export declare function evaluateStatus(files: {
|
|
45
|
+
agentsMd: string | null;
|
|
46
|
+
codexToml: string | null;
|
|
47
|
+
copilotJson: string | null;
|
|
48
|
+
copilotInstructions: string | null;
|
|
49
|
+
claudeMcpJson: string | null;
|
|
50
|
+
/** ~/.claude.json — Claude Code's user-level config (claude mcp add) */
|
|
51
|
+
claudeUserJson?: string | null;
|
|
52
|
+
claudeDirExists: boolean;
|
|
53
|
+
}): TargetStatus[];
|
|
54
|
+
//# sourceMappingURL=integrations.d.ts.map
|