swarmdo 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -515,7 +515,7 @@ function getCostFromStdin() {
515
515
  // misses, the displayed version is meaningful (matches what the user
516
516
  // installed), not a stale hard-coded string.
517
517
  function getPkgVersion() {
518
- let ver = '1.7.0';
518
+ let ver = '1.8.0';
519
519
  try {
520
520
  const home = os.homedir();
521
521
  const pkgPaths = [
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![swarmdo](swarmdo/assets/swarmdo-banner.svg)](https://swarmdo.com)
4
4
 
5
- [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.7.0-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
5
+ [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.8.0-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
6
6
  [![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](https://github.com/SwarmDo/swarmdo/blob/main/LICENSE)
7
7
  [![Website](https://img.shields.io/badge/swarmdo.com-e2a33c?style=for-the-badge&logoColor=black)](https://swarmdo.com)
8
8
  [![Star on GitHub](https://img.shields.io/github/stars/SwarmDo/swarmdo?style=for-the-badge&logo=github&color=gold)](https://github.com/SwarmDo/swarmdo)
@@ -277,7 +277,7 @@ The recent release train added a full day-to-day operations layer around the swa
277
277
  | `swarmdo worktree` (alias `wt`) | **Parallel-agent isolation** on git worktrees — add / list / diff / merge / remove |
278
278
  | `swarmdo transcript` (alias `tx`) | **Export any Claude Code session** to clean markdown — system noise stripped, ready to share; `transcript search <query>` full-text-searches every session |
279
279
  | `swarmdo compact` | **Compress noisy command output** before it reaches an LLM — strip ANSI, collapse repeats, fold `node_modules` stack frames, window long logs. `npm test 2>&1 \| swarmdo compact` or `swarmdo compact -- npm test` (exit code propagates). Deterministic, zero tokens |
280
- | `swarmdo codegraph` (alias `cg`) | **Queryable symbol index** — `codegraph index` scans TS/JS for exported symbols; `query <name>` (with `--fuzzy`/`--kind`) and `file <path>` answer "where is X defined / what does this file export" from `.swarm/codegraph.json` instead of grep+read round-trips. 1,750 symbols across 289 files in <1s |
280
+ | `swarmdo codegraph` (alias `cg`) | **Queryable symbol index** — `codegraph index` scans TS/JS for exported symbols; `query <name>` (with `--fuzzy`/`--kind`) and `file <path>` answer "where is X defined / what does this file export" from `.swarm/codegraph.json` instead of grep+read round-trips. 1,750 symbols across 289 files in <1s. Also exposed as MCP tools (`codegraph_query`/`file`/`index`/`stats`) so agents query the index in-session |
281
281
  | `swarmdo integrations` (alias `integrate`) | **Use swarmdo from Codex CLI, GitHub Copilot CLI, and pi** — one command wires AGENTS.md + each CLI's MCP config (idempotent, dry-run first, never touches your Claude Code setup) |
282
282
  | OpenRouter model pool | **Let swarms pick from any models you configure** — declare tier-mapped OpenRouter models in `swarmdo.config.json`; the router Thompson-samples among them per task and the execution layer dispatches the winner |
283
283
  | `swarmdo changelog` (alias `notes`) | **Release notes from conventional commits** — `--out NOTES.md` feeds `gh release create --notes-file` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmdo",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Swarmdo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,19 @@
1
+ /**
2
+ * store.ts — the filesystem layer for codegraph: walk the tree, read sources,
3
+ * build the index (via the pure engine), and persist/load .swarm/codegraph.json.
4
+ * Shared by the `codegraph` CLI command and the codegraph MCP tools so the
5
+ * scan/persist behaviour can't drift between them.
6
+ */
7
+ import { type CodeIndex } from './codegraph.js';
8
+ export declare const INDEX_REL: string;
9
+ /** Recursively collect source files under `root`, skipping vendor/build dirs and .d.ts. */
10
+ export declare function walkSourceFiles(root: string): string[];
11
+ export declare function indexPath(root: string): string;
12
+ /** Scan a repo (or a subpath of it) and build the index. `root` is the repo
13
+ * root used for relative paths; `scanRoot` (default = root) is where to walk. */
14
+ export declare function scanRepo(root: string, scanRoot?: string): CodeIndex;
15
+ /** Persist the index to .swarm/codegraph.json under `root`. */
16
+ export declare function saveIndex(root: string, index: CodeIndex): void;
17
+ /** Load the persisted index, or null if none/unreadable. */
18
+ export declare function loadIndex(root: string): CodeIndex | null;
19
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,80 @@
1
+ /**
2
+ * store.ts — the filesystem layer for codegraph: walk the tree, read sources,
3
+ * build the index (via the pure engine), and persist/load .swarm/codegraph.json.
4
+ * Shared by the `codegraph` CLI command and the codegraph MCP tools so the
5
+ * scan/persist behaviour can't drift between them.
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { buildIndex } from './codegraph.js';
10
+ export const INDEX_REL = path.join('.swarm', 'codegraph.json');
11
+ const SOURCE_EXT = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']);
12
+ const SKIP_DIRS = new Set([
13
+ 'node_modules', '.git', '.swarm', 'dist', 'dist-standalone', 'build',
14
+ 'coverage', '.next', '.turbo', 'out', 'vendor', '.cache',
15
+ ]);
16
+ /** Recursively collect source files under `root`, skipping vendor/build dirs and .d.ts. */
17
+ export function walkSourceFiles(root) {
18
+ const found = [];
19
+ const stack = [root];
20
+ while (stack.length) {
21
+ const dir = stack.pop();
22
+ let entries;
23
+ try {
24
+ entries = fs.readdirSync(dir, { withFileTypes: true });
25
+ }
26
+ catch {
27
+ continue;
28
+ }
29
+ for (const e of entries) {
30
+ const full = path.join(dir, e.name);
31
+ if (e.isDirectory()) {
32
+ if (SKIP_DIRS.has(e.name))
33
+ continue;
34
+ stack.push(full);
35
+ }
36
+ else if (e.isFile()) {
37
+ const ext = path.extname(e.name);
38
+ if (SOURCE_EXT.has(ext) && !e.name.endsWith('.d.ts'))
39
+ found.push(full);
40
+ }
41
+ }
42
+ }
43
+ return found;
44
+ }
45
+ function safeRead(abs) {
46
+ try {
47
+ return fs.readFileSync(abs, 'utf8');
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ export function indexPath(root) {
54
+ return path.join(root, INDEX_REL);
55
+ }
56
+ /** Scan a repo (or a subpath of it) and build the index. `root` is the repo
57
+ * root used for relative paths; `scanRoot` (default = root) is where to walk. */
58
+ export function scanRepo(root, scanRoot = root) {
59
+ const files = walkSourceFiles(scanRoot);
60
+ const read = files
61
+ .map((abs) => ({ file: path.relative(root, abs), source: safeRead(abs) }))
62
+ .filter((f) => f.source !== null);
63
+ return buildIndex(read);
64
+ }
65
+ /** Persist the index to .swarm/codegraph.json under `root`. */
66
+ export function saveIndex(root, index) {
67
+ const p = indexPath(root);
68
+ fs.mkdirSync(path.dirname(p), { recursive: true });
69
+ fs.writeFileSync(p, JSON.stringify(index));
70
+ }
71
+ /** Load the persisted index, or null if none/unreadable. */
72
+ export function loadIndex(root) {
73
+ try {
74
+ return JSON.parse(fs.readFileSync(indexPath(root), 'utf8'));
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ //# sourceMappingURL=store.js.map
@@ -11,59 +11,10 @@
11
11
  * Engine (../codegraph/codegraph.ts) is pure + tested; this layer does the fs
12
12
  * walk and JSON persistence. MVP: exported top-level symbols in TS/JS.
13
13
  */
14
- import * as fs from 'node:fs';
15
14
  import * as path from 'node:path';
16
15
  import { output } from '../output.js';
17
- import { buildIndex, queryIndex, symbolsInFile, indexStats, } from '../codegraph/codegraph.js';
18
- const INDEX_REL = path.join('.swarm', 'codegraph.json');
19
- const SOURCE_EXT = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']);
20
- const SKIP_DIRS = new Set([
21
- 'node_modules', '.git', '.swarm', 'dist', 'dist-standalone', 'build',
22
- 'coverage', '.next', '.turbo', 'out', 'vendor', '.cache',
23
- ]);
24
- function walkSourceFiles(root) {
25
- const found = [];
26
- const stack = [root];
27
- while (stack.length) {
28
- const dir = stack.pop();
29
- let entries;
30
- try {
31
- entries = fs.readdirSync(dir, { withFileTypes: true });
32
- }
33
- catch {
34
- continue;
35
- }
36
- for (const e of entries) {
37
- if (e.name.startsWith('.') && e.name !== '.') {
38
- if (e.isDirectory() && SKIP_DIRS.has(e.name))
39
- continue;
40
- }
41
- const full = path.join(dir, e.name);
42
- if (e.isDirectory()) {
43
- if (SKIP_DIRS.has(e.name))
44
- continue;
45
- stack.push(full);
46
- }
47
- else if (e.isFile()) {
48
- const ext = path.extname(e.name);
49
- if (SOURCE_EXT.has(ext) && !e.name.endsWith('.d.ts'))
50
- found.push(full);
51
- }
52
- }
53
- }
54
- return found;
55
- }
56
- function indexPath(root) {
57
- return path.join(root, INDEX_REL);
58
- }
59
- function loadIndex(root) {
60
- try {
61
- return JSON.parse(fs.readFileSync(indexPath(root), 'utf8'));
62
- }
63
- catch {
64
- return null;
65
- }
66
- }
16
+ import { queryIndex, symbolsInFile, indexStats, } from '../codegraph/codegraph.js';
17
+ import { INDEX_REL, scanRepo, saveIndex, loadIndex } from '../codegraph/store.js';
67
18
  function fmtSymbol(s) {
68
19
  return `${s.file}:${s.line} ${output.dim(`[${s.kind}]`)} ${s.signature}`;
69
20
  }
@@ -76,12 +27,8 @@ const indexCommand = {
76
27
  action: async (ctx) => {
77
28
  const root = ctx.cwd || process.cwd();
78
29
  const scanRoot = ctx.args[0] ? path.resolve(root, ctx.args[0]) : root;
79
- const files = walkSourceFiles(scanRoot);
80
- const read = files.map((abs) => ({ file: path.relative(root, abs), source: safeRead(abs) }));
81
- const index = buildIndex(read.filter((f) => f.source !== null));
82
- const dir = path.dirname(indexPath(root));
83
- fs.mkdirSync(dir, { recursive: true });
84
- fs.writeFileSync(indexPath(root), JSON.stringify(index));
30
+ const index = scanRepo(root, scanRoot);
31
+ saveIndex(root, index);
85
32
  const stats = indexStats(index);
86
33
  if (ctx.flags.json === true) {
87
34
  output.printJson({ ...stats, path: INDEX_REL });
@@ -92,14 +39,6 @@ const indexCommand = {
92
39
  return { success: true, exitCode: 0 };
93
40
  },
94
41
  };
95
- function safeRead(abs) {
96
- try {
97
- return fs.readFileSync(abs, 'utf8');
98
- }
99
- catch {
100
- return null;
101
- }
102
- }
103
42
  const queryCommand = {
104
43
  name: 'query',
105
44
  aliases: ['q'],
@@ -19,6 +19,7 @@ import { sessionTools } from './mcp-tools/session-tools.js';
19
19
  import { hiveMindTools } from './mcp-tools/hive-mind-tools.js';
20
20
  import { workflowTools } from './mcp-tools/workflow-tools.js';
21
21
  import { analyzeTools } from './mcp-tools/analyze-tools.js';
22
+ import { codegraphTools } from './mcp-tools/codegraph-tools.js';
22
23
  import { progressTools } from './mcp-tools/progress-tools.js';
23
24
  import { embeddingsTools } from './mcp-tools/embeddings-tools.js';
24
25
  import { claimsTools } from './mcp-tools/claims-tools.js';
@@ -102,6 +103,7 @@ const TOOL_GROUPS = {
102
103
  'hive-mind': () => hiveMindTools,
103
104
  workflow: () => workflowTools,
104
105
  analyze: () => analyzeTools,
106
+ codegraph: () => codegraphTools,
105
107
  progress: () => progressTools,
106
108
  embeddings: () => embeddingsTools,
107
109
  claims: () => claimsTools,
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Codegraph MCP Tools
3
+ *
4
+ * Make the exported-symbol index (see ../codegraph) agent-native: an agent can
5
+ * ask "where is X defined?" / "what does file Y export?" in-session via MCP
6
+ * instead of shelling out to `swarmdo codegraph` or grep+read. Reads the same
7
+ * .swarm/codegraph.json the CLI writes (shared fs layer in codegraph/store.ts).
8
+ */
9
+ import type { MCPTool } from './types.js';
10
+ export declare const codegraphTools: MCPTool[];
11
+ //# sourceMappingURL=codegraph-tools.d.ts.map
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Codegraph MCP Tools
3
+ *
4
+ * Make the exported-symbol index (see ../codegraph) agent-native: an agent can
5
+ * ask "where is X defined?" / "what does file Y export?" in-session via MCP
6
+ * instead of shelling out to `swarmdo codegraph` or grep+read. Reads the same
7
+ * .swarm/codegraph.json the CLI writes (shared fs layer in codegraph/store.ts).
8
+ */
9
+ import { queryIndex, symbolsInFile, indexStats } from '../codegraph/codegraph.js';
10
+ import { INDEX_REL, scanRepo, saveIndex, loadIndex } from '../codegraph/store.js';
11
+ const KINDS = ['function', 'class', 'interface', 'type', 'const', 'enum', 'default'];
12
+ /** Resolve the repo root for scan/load. Params may override; default = cwd. */
13
+ function rootOf(params) {
14
+ const p = params.root;
15
+ return typeof p === 'string' && p ? p : process.cwd();
16
+ }
17
+ const codegraphIndexTool = {
18
+ name: 'codegraph_index',
19
+ description: 'Scan the codebase for exported symbols and persist a queryable index to .swarm/codegraph.json. Run this once before codegraph_query/codegraph_file (or when files have changed). Use instead of a manual grep sweep when you want a structured symbol map.',
20
+ category: 'codegraph',
21
+ tags: ['code', 'symbols', 'index', 'navigation'],
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {
25
+ root: { type: 'string', description: 'Repo root (default: current working directory)' },
26
+ path: { type: 'string', description: 'Subpath to scan, relative to root (default: whole repo)' },
27
+ },
28
+ },
29
+ handler: async (params) => {
30
+ const root = rootOf(params);
31
+ const scanRoot = typeof params.path === 'string' && params.path ? `${root}/${params.path}` : root;
32
+ try {
33
+ const index = scanRepo(root, scanRoot);
34
+ saveIndex(root, index);
35
+ return { ok: true, indexPath: INDEX_REL, ...indexStats(index) };
36
+ }
37
+ catch (e) {
38
+ return { error: true, message: e instanceof Error ? e.message : String(e) };
39
+ }
40
+ },
41
+ };
42
+ const codegraphQueryTool = {
43
+ name: 'codegraph_query',
44
+ description: 'Find where a symbol is defined by name — returns file, line, kind, and signature. Prefer this over grep for "where is X defined": it hits a prebuilt index (no file reads) and disambiguates by kind. Requires a prior codegraph_index. Use fuzzy for substring/partial names.',
45
+ category: 'codegraph',
46
+ tags: ['code', 'symbols', 'query', 'navigation'],
47
+ inputSchema: {
48
+ type: 'object',
49
+ properties: {
50
+ name: { type: 'string', description: 'Symbol name to find' },
51
+ fuzzy: { type: 'boolean', description: 'Substring, case-insensitive match instead of exact', default: false },
52
+ kind: { type: 'string', description: `Restrict to one kind: ${KINDS.join(', ')}`, enum: KINDS },
53
+ root: { type: 'string', description: 'Repo root (default: current working directory)' },
54
+ },
55
+ required: ['name'],
56
+ },
57
+ handler: async (params) => {
58
+ const root = rootOf(params);
59
+ const name = params.name;
60
+ if (typeof name !== 'string' || !name)
61
+ return { error: true, message: 'name is required' };
62
+ const index = loadIndex(root);
63
+ if (!index)
64
+ return { error: true, message: 'no index — run codegraph_index first' };
65
+ const hits = queryIndex(index, name, {
66
+ fuzzy: params.fuzzy === true,
67
+ kind: params.kind,
68
+ });
69
+ return { count: hits.length, symbols: hits };
70
+ },
71
+ };
72
+ const codegraphFileTool = {
73
+ name: 'codegraph_file',
74
+ description: 'List the symbols a specific file exports (name, line, kind) from the index — a fast "what does this module expose?" without reading the file. Requires a prior codegraph_index.',
75
+ category: 'codegraph',
76
+ tags: ['code', 'symbols', 'file', 'navigation'],
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ file: { type: 'string', description: 'Repo-relative file path (as indexed, e.g. src/index.ts)' },
81
+ root: { type: 'string', description: 'Repo root (default: current working directory)' },
82
+ },
83
+ required: ['file'],
84
+ },
85
+ handler: async (params) => {
86
+ const root = rootOf(params);
87
+ const file = params.file;
88
+ if (typeof file !== 'string' || !file)
89
+ return { error: true, message: 'file is required' };
90
+ const index = loadIndex(root);
91
+ if (!index)
92
+ return { error: true, message: 'no index — run codegraph_index first' };
93
+ const hits = symbolsInFile(index, file);
94
+ return { file, count: hits.length, symbols: hits };
95
+ },
96
+ };
97
+ const codegraphStatsTool = {
98
+ name: 'codegraph_stats',
99
+ description: 'Summary of the current symbol index: file count, symbol count, and a breakdown by kind. Requires a prior codegraph_index.',
100
+ category: 'codegraph',
101
+ tags: ['code', 'symbols', 'stats'],
102
+ inputSchema: {
103
+ type: 'object',
104
+ properties: {
105
+ root: { type: 'string', description: 'Repo root (default: current working directory)' },
106
+ },
107
+ },
108
+ handler: async (params) => {
109
+ const root = rootOf(params);
110
+ const index = loadIndex(root);
111
+ if (!index)
112
+ return { error: true, message: 'no index — run codegraph_index first' };
113
+ return indexStats(index);
114
+ },
115
+ };
116
+ export const codegraphTools = [
117
+ codegraphIndexTool,
118
+ codegraphQueryTool,
119
+ codegraphFileTool,
120
+ codegraphStatsTool,
121
+ ];
122
+ //# sourceMappingURL=codegraph-tools.js.map
@@ -15,6 +15,7 @@ export { hiveMindTools } from './hive-mind-tools.js';
15
15
  export { workflowTools } from './workflow-tools.js';
16
16
  export { coverageRouterTools } from '../swarmvector/coverage-tools.js';
17
17
  export { analyzeTools } from './analyze-tools.js';
18
+ export { codegraphTools } from './codegraph-tools.js';
18
19
  export { progressTools } from './progress-tools.js';
19
20
  export { transferTools } from './transfer-tools.js';
20
21
  export { securityTools } from './security-tools.js';
@@ -14,6 +14,7 @@ export { hiveMindTools } from './hive-mind-tools.js';
14
14
  export { workflowTools } from './workflow-tools.js';
15
15
  export { coverageRouterTools } from '../swarmvector/coverage-tools.js';
16
16
  export { analyzeTools } from './analyze-tools.js';
17
+ export { codegraphTools } from './codegraph-tools.js';
17
18
  export { progressTools } from './progress-tools.js';
18
19
  export { transferTools } from './transfer-tools.js';
19
20
  export { securityTools } from './security-tools.js';
@@ -22,6 +22,7 @@ const LEAN_GROUPS = [
22
22
  'hooks', // hooks_route / pre-task / post-edit / codemod ...
23
23
  'agentdb', // agentdb pattern store/search
24
24
  'embeddings', // embeddings_generate / search / compare
25
+ 'codegraph', // codegraph_query / file / index — "where is X defined?"
25
26
  ];
26
27
  /** Balanced = lean + orchestration/session/system the average user reaches for. */
27
28
  const BALANCED_EXTRA = [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmdo/cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "type": "module",
5
5
  "description": "Swarmdo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",