code-graph-context 2.14.1 → 3.0.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/dist/core/embeddings/natural-language-to-cypher.service.js +2 -4
- package/dist/mcp/constants.js +56 -228
- package/dist/mcp/handlers/swarm/abandon.handler.js +61 -0
- package/dist/mcp/handlers/swarm/advance.handler.js +78 -0
- package/dist/mcp/handlers/swarm/claim.handler.js +61 -0
- package/dist/mcp/handlers/swarm/index.js +5 -0
- package/dist/mcp/handlers/swarm/queries.js +140 -0
- package/dist/mcp/handlers/swarm/release.handler.js +41 -0
- package/dist/mcp/handlers/swarm-worker.handler.js +2 -13
- package/dist/mcp/tools/detect-dead-code.tool.js +33 -65
- package/dist/mcp/tools/detect-duplicate-code.tool.js +44 -53
- package/dist/mcp/tools/impact-analysis.tool.js +1 -1
- package/dist/mcp/tools/index.js +9 -9
- package/dist/mcp/tools/list-projects.tool.js +2 -2
- package/dist/mcp/tools/list-watchers.tool.js +2 -5
- package/dist/mcp/tools/natural-language-to-cypher.tool.js +2 -2
- package/dist/mcp/tools/parse-typescript-project.tool.js +7 -17
- package/dist/mcp/tools/search-codebase.tool.js +11 -26
- package/dist/mcp/tools/session-bookmark.tool.js +7 -11
- package/dist/mcp/tools/session-cleanup.tool.js +2 -6
- package/dist/mcp/tools/session-note.tool.js +6 -21
- package/dist/mcp/tools/session-recall.tool.js +293 -0
- package/dist/mcp/tools/session-save.tool.js +280 -0
- package/dist/mcp/tools/start-watch-project.tool.js +1 -1
- package/dist/mcp/tools/swarm-advance-task.tool.js +56 -0
- package/dist/mcp/tools/swarm-claim-task.tool.js +24 -388
- package/dist/mcp/tools/swarm-cleanup.tool.js +3 -7
- package/dist/mcp/tools/swarm-complete-task.tool.js +14 -17
- package/dist/mcp/tools/swarm-get-tasks.tool.js +8 -26
- package/dist/mcp/tools/swarm-message.tool.js +10 -25
- package/dist/mcp/tools/swarm-pheromone.tool.js +7 -25
- package/dist/mcp/tools/swarm-post-task.tool.js +7 -19
- package/dist/mcp/tools/swarm-release-task.tool.js +53 -0
- package/dist/mcp/tools/swarm-sense.tool.js +10 -30
- package/dist/mcp/tools/traverse-from-node.tool.js +19 -41
- package/dist/mcp/utils.js +41 -1
- package/package.json +1 -1
|
@@ -77,7 +77,7 @@ CONTAINS (file→declaration), HAS_MEMBER (class→method/property), HAS_PARAMET
|
|
|
77
77
|
try {
|
|
78
78
|
const content = fs.readFileSync(this.schemaPath, 'utf-8');
|
|
79
79
|
const schema = JSON.parse(content);
|
|
80
|
-
if (!schema
|
|
80
|
+
if (!schema?.nodeTypes) {
|
|
81
81
|
return 'No schema available.';
|
|
82
82
|
}
|
|
83
83
|
// Format node types with properties
|
|
@@ -93,9 +93,7 @@ CONTAINS (file→declaration), HAS_MEMBER (class→method/property), HAS_PARAMET
|
|
|
93
93
|
.join('\n') ?? 'none';
|
|
94
94
|
// Format semantic types
|
|
95
95
|
const semanticTypeList = schema.semanticTypes?.map((s) => s.type) ?? [];
|
|
96
|
-
const semTypeLines = schema.semanticTypes
|
|
97
|
-
?.map((s) => ` ${s.type} (on ${s.label}, ${s.count} nodes)`)
|
|
98
|
-
.join('\n') ?? 'none';
|
|
96
|
+
const semTypeLines = schema.semanticTypes?.map((s) => ` ${s.type} (on ${s.label}, ${s.count} nodes)`).join('\n') ?? 'none';
|
|
99
97
|
// Format common patterns
|
|
100
98
|
const patternLines = schema.commonPatterns
|
|
101
99
|
?.map((p) => ` (${p.from})-[:${p.relationship}]->(${p.to}) × ${p.count}`)
|
package/dist/mcp/constants.js
CHANGED
|
@@ -36,6 +36,8 @@ export const TOOL_NAMES = {
|
|
|
36
36
|
swarmCleanup: 'swarm_cleanup',
|
|
37
37
|
swarmPostTask: 'swarm_post_task',
|
|
38
38
|
swarmClaimTask: 'swarm_claim_task',
|
|
39
|
+
swarmReleaseTask: 'swarm_release_task',
|
|
40
|
+
swarmAdvanceTask: 'swarm_advance_task',
|
|
39
41
|
swarmCompleteTask: 'swarm_complete_task',
|
|
40
42
|
swarmGetTasks: 'swarm_get_tasks',
|
|
41
43
|
saveSessionBookmark: 'save_session_bookmark',
|
|
@@ -44,327 +46,153 @@ export const TOOL_NAMES = {
|
|
|
44
46
|
recallSessionNotes: 'recall_session_notes',
|
|
45
47
|
cleanupSession: 'cleanup_session',
|
|
46
48
|
swarmMessage: 'swarm_message',
|
|
49
|
+
sessionSave: 'session_save',
|
|
50
|
+
sessionRecall: 'session_recall',
|
|
47
51
|
};
|
|
48
52
|
// Tool Metadata
|
|
49
53
|
export const TOOL_METADATA = {
|
|
50
54
|
[TOOL_NAMES.hello]: {
|
|
51
55
|
title: 'Hello Tool',
|
|
52
|
-
description: '
|
|
56
|
+
description: 'Diagnostic tool. Use only to verify the MCP server is running.',
|
|
53
57
|
},
|
|
54
58
|
[TOOL_NAMES.searchCodebase]: {
|
|
55
59
|
title: 'Search Codebase',
|
|
56
|
-
description: `
|
|
60
|
+
description: `Primary tool for finding code. Use this first for any code exploration query. Combines semantic vector search with dependency graph traversal from the best match.
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Parameters:
|
|
61
|
-
- query: Natural language description of what you're looking for
|
|
62
|
-
- maxDepth (default: 3): Relationship hops to traverse
|
|
63
|
-
- includeCode (default: true): Set false for structure only
|
|
64
|
-
- snippetLength (default: 700): Code snippet length
|
|
65
|
-
- maxNodesPerChain (default: 5): Chains per depth level
|
|
66
|
-
|
|
67
|
-
If output too large: reduce maxDepth, set includeCode=false, or reduce snippetLength.`,
|
|
62
|
+
Returns normalized JSON with nodes map and relationship chains. If output too large: reduce maxDepth, set includeCode=false, or reduce snippetLength.`,
|
|
68
63
|
},
|
|
69
64
|
[TOOL_NAMES.naturalLanguageToCypher]: {
|
|
70
65
|
title: 'Natural Language to Cypher',
|
|
71
|
-
description: `
|
|
72
|
-
|
|
73
|
-
Use list_projects first to get project name.
|
|
66
|
+
description: `Advanced query tool. Use only when search_codebase cannot answer the question — aggregate queries ('how many services exist'), complex relationship patterns, or bulk property filtering. Requires OPENAI_API_KEY.
|
|
74
67
|
|
|
75
68
|
**Node types:** SourceFile, Class, Function, Method, Interface, Property, Parameter, Import, Export, Enum, TypeAlias
|
|
76
|
-
|
|
77
69
|
**Key relationships:** CONTAINS, HAS_MEMBER, HAS_PARAMETER, IMPORTS, EXTENDS, IMPLEMENTS, CALLS, TYPED_AS
|
|
78
|
-
|
|
79
|
-
**
|
|
80
|
-
|
|
81
|
-
**Tips:** Use concrete properties (filePath, name) not abstract concepts. Import nodes store file paths, not module names.`,
|
|
70
|
+
**NestJS:** Use semanticType property (e.g., semanticType='NestController'). Relationships: INJECTS, EXPOSES, MODULE_IMPORTS/PROVIDES/EXPORTS
|
|
71
|
+
**Tips:** Use concrete properties (filePath, name) not abstract concepts.`,
|
|
82
72
|
},
|
|
83
73
|
[TOOL_NAMES.traverseFromNode]: {
|
|
84
74
|
title: 'Traverse from Node',
|
|
85
|
-
description: `
|
|
75
|
+
description: `Follow-up exploration tool. Use after search_codebase when you have a specific node ID and want to explore its relationships in more depth or different directions.
|
|
86
76
|
|
|
87
|
-
|
|
88
|
-
- nodeId (required): Starting node ID
|
|
89
|
-
- maxDepth (default: 3): Relationship hops (1-10)
|
|
90
|
-
- includeCode (default: true): Set false for structure only
|
|
91
|
-
- summaryOnly: true for file paths and stats only
|
|
92
|
-
- maxNodesPerChain (default: 5): Chains per depth level
|
|
93
|
-
- maxTotalNodes: Cap unique nodes returned`,
|
|
77
|
+
Accepts nodeId or filePath as starting point. Set summaryOnly=true for file paths and stats only.`,
|
|
94
78
|
},
|
|
95
79
|
[TOOL_NAMES.parseTypescriptProject]: {
|
|
96
80
|
title: 'Parse TypeScript Project',
|
|
97
|
-
description: `Parse a TypeScript/NestJS project and build a code graph in Neo4j.
|
|
98
|
-
|
|
99
|
-
**IMPORTANT: Always use async mode for parsing:**
|
|
100
|
-
- Set async: true to avoid timeouts on large codebases
|
|
101
|
-
- Use check_parse_status to monitor progress
|
|
81
|
+
description: `Setup tool. Parse a TypeScript/NestJS project and build a code graph in Neo4j. Run once per project, then use search_codebase to query.
|
|
102
82
|
|
|
103
|
-
**
|
|
104
|
-
1. Call with async: true and projectPath
|
|
105
|
-
2. Note the returned jobId
|
|
106
|
-
3. Poll check_parse_status({ jobId }) until completed
|
|
107
|
-
4. Use list_projects to confirm the project was added
|
|
108
|
-
|
|
109
|
-
**Parameters:**
|
|
110
|
-
- projectPath (required): Absolute path to the project root
|
|
111
|
-
- async (recommended: true): Run parsing in background
|
|
112
|
-
- clearExisting: Set true to replace existing graph for this project
|
|
113
|
-
- projectId: Optional custom ID (auto-generated from path if omitted)
|
|
114
|
-
|
|
115
|
-
**Example:**
|
|
116
|
-
parse_typescript_project({ projectPath: "/path/to/project", async: true })
|
|
117
|
-
→ Returns jobId for polling`,
|
|
83
|
+
**Always use async mode:** set async=true, then poll check_parse_status with the returned jobId. Set clearExisting=true to replace an existing graph.`,
|
|
118
84
|
},
|
|
119
85
|
[TOOL_NAMES.testNeo4jConnection]: {
|
|
120
86
|
title: 'Test Neo4j Connection & APOC',
|
|
121
|
-
description: '
|
|
87
|
+
description: 'Diagnostic tool. Use only to verify Neo4j connectivity and APOC plugin availability.',
|
|
122
88
|
},
|
|
123
89
|
[TOOL_NAMES.impactAnalysis]: {
|
|
124
90
|
title: 'Impact Analysis',
|
|
125
|
-
description: `
|
|
126
|
-
|
|
127
|
-
**Before analyzing:**
|
|
128
|
-
Use list_projects to see available projects and get the project name.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
- Risk level (LOW/MEDIUM/HIGH/CRITICAL) based on dependency count and relationship types
|
|
132
|
-
- Direct dependents: nodes that directly reference the target
|
|
133
|
-
- Transitive dependents: nodes affected through dependency chains
|
|
134
|
-
- Affected files: list of files that would need review
|
|
135
|
-
- Critical paths: high-risk dependency chains
|
|
91
|
+
description: `Risk assessment tool. Use before modifying shared code to understand what depends on a node and the blast radius of changes.
|
|
136
92
|
|
|
137
|
-
|
|
138
|
-
- nodeId: Node ID from search_codebase or traverse_from_node results
|
|
139
|
-
- filePath: Alternative - analyze all exports from a file
|
|
140
|
-
- maxDepth: How far to trace transitive dependencies (default: 4)
|
|
141
|
-
|
|
142
|
-
Use this before refactoring to understand blast radius of changes.`,
|
|
93
|
+
Returns risk level (LOW/MEDIUM/HIGH/CRITICAL), direct and transitive dependents, affected files, and critical paths. Accepts nodeId or filePath.`,
|
|
143
94
|
},
|
|
144
95
|
[TOOL_NAMES.checkParseStatus]: {
|
|
145
96
|
title: 'Check Parse Status',
|
|
146
|
-
description: `
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
- Job status (pending/running/completed/failed)
|
|
150
|
-
- Progress: phase, files processed, chunks completed
|
|
151
|
-
- Nodes and edges imported so far
|
|
152
|
-
- Final result on completion or error message on failure
|
|
153
|
-
|
|
154
|
-
Use this to poll for progress when parsing large codebases asynchronously.`,
|
|
97
|
+
description: `Setup tool. Poll the status of an async parsing job started with parse_typescript_project. Returns job status, progress, and final result.`,
|
|
155
98
|
},
|
|
156
99
|
[TOOL_NAMES.listProjects]: {
|
|
157
100
|
title: 'List Projects',
|
|
158
|
-
description: `
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
- projectId: The full project ID (e.g., "proj_a1b2c3d4e5f6")
|
|
162
|
-
- name: Friendly project name from package.json (e.g., "backend")
|
|
163
|
-
- path: Full filesystem path to the project
|
|
164
|
-
- updatedAt: When the project was last parsed
|
|
165
|
-
|
|
166
|
-
Use the name or path in other tools instead of the cryptic projectId.`,
|
|
101
|
+
description: `Utility tool. Lists all parsed projects with IDs, names, and paths. Most tools accept project names or paths directly, so this is rarely needed.`,
|
|
167
102
|
},
|
|
168
103
|
[TOOL_NAMES.startWatchProject]: {
|
|
169
104
|
title: 'Start Watch Project',
|
|
170
|
-
description: `Watch project for .ts file changes and auto-update graph.
|
|
171
|
-
|
|
172
|
-
Parameters: projectPath (required), tsconfigPath (required), debounceMs (default: 1000ms).
|
|
173
|
-
|
|
174
|
-
Auto-excludes node_modules, dist, build, .git. Use list_watchers to see active, stop_watch_project to stop.`,
|
|
105
|
+
description: `File watcher tool. Watch a project for .ts file changes and auto-update the graph. Auto-excludes node_modules, dist, build, .git.`,
|
|
175
106
|
},
|
|
176
107
|
[TOOL_NAMES.stopWatchProject]: {
|
|
177
108
|
title: 'Stop Watch Project',
|
|
178
|
-
description: `Stop watching a project
|
|
109
|
+
description: `File watcher tool. Stop watching a project for file changes.`,
|
|
179
110
|
},
|
|
180
111
|
[TOOL_NAMES.listWatchers]: {
|
|
181
112
|
title: 'List Watchers',
|
|
182
|
-
description: `List active file watchers with status
|
|
113
|
+
description: `File watcher tool. List active file watchers with status and pending changes.`,
|
|
183
114
|
},
|
|
184
115
|
[TOOL_NAMES.detectDeadCode]: {
|
|
185
116
|
title: 'Detect Dead Code',
|
|
186
|
-
description: `Find unused exports, uncalled methods, orphan interfaces.
|
|
117
|
+
description: `Code quality tool. Find unused exports, uncalled methods, and orphan interfaces. Returns items with confidence scores grouped by type and category.
|
|
187
118
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Key parameters:
|
|
191
|
-
- projectId (required)
|
|
192
|
-
- filterCategory: library-export, ui-component, internal-unused, all (default: all)
|
|
193
|
-
- minConfidence: LOW/MEDIUM/HIGH (default: LOW)
|
|
194
|
-
- summaryOnly: true for stats only
|
|
195
|
-
- excludePatterns, excludeSemanticTypes: Additional exclusions
|
|
196
|
-
|
|
197
|
-
Auto-excludes NestJS entry points (controllers, modules, guards, etc.). Use filterCategory=internal-unused for actionable cleanup.`,
|
|
119
|
+
Auto-excludes NestJS entry points. Use filterCategory=internal-unused for actionable cleanup.`,
|
|
198
120
|
},
|
|
199
121
|
[TOOL_NAMES.detectDuplicateCode]: {
|
|
200
122
|
title: 'Detect Duplicate Code',
|
|
201
|
-
description: `Find duplicates using structural (AST hash) and semantic (embedding) analysis.
|
|
202
|
-
|
|
203
|
-
Parameters:
|
|
204
|
-
- projectId (required)
|
|
205
|
-
- type: structural, semantic, or all (default: all)
|
|
206
|
-
- minSimilarity: 0.5-1.0 (default: 0.80). 0.90+ = almost certain duplicates
|
|
207
|
-
- scope: methods, functions, classes, or all (default: all)
|
|
208
|
-
- summaryOnly: true for stats only
|
|
209
|
-
- includeCode: Include source snippets (default: false)`,
|
|
123
|
+
description: `Code quality tool. Find duplicates using structural (AST hash) and semantic (embedding) analysis. Returns grouped results with similarity scores.`,
|
|
210
124
|
},
|
|
211
125
|
[TOOL_NAMES.swarmPheromone]: {
|
|
212
126
|
title: 'Swarm Pheromone',
|
|
213
|
-
description: `Mark a code node with a pheromone
|
|
214
|
-
|
|
215
|
-
Workflow states (exploring/claiming/modifying/completed/blocked) are mutually exclusive per agent+node. Flag types (warning/proposal/needs_review/session_context) can coexist. Use remove:true to delete. Pheromones decay automatically.`,
|
|
127
|
+
description: `Swarm coordination tool. Mark a code node with a pheromone to signal activity. Workflow states (exploring/claiming/modifying/completed/blocked) are mutually exclusive per agent+node. Flag types (warning/proposal/needs_review/session_context) can coexist. Pheromones decay automatically.`,
|
|
216
128
|
},
|
|
217
129
|
[TOOL_NAMES.swarmSense]: {
|
|
218
130
|
title: 'Swarm Sense',
|
|
219
|
-
description: `Query active pheromones to see what other agents are doing. Filter by swarmId, types, nodeIds, agentIds.
|
|
220
|
-
|
|
221
|
-
Returns pheromones with current intensity after decay. minIntensity default: 0.3. Add includeStats:true for summary counts.`,
|
|
131
|
+
description: `Swarm coordination tool. Query active pheromones to see what other agents are doing. Filter by swarmId, types, nodeIds, agentIds. Returns pheromones with current intensity after decay.`,
|
|
222
132
|
},
|
|
223
133
|
[TOOL_NAMES.swarmCleanup]: {
|
|
224
134
|
title: 'Swarm Cleanup',
|
|
225
|
-
description: `Bulk delete pheromones, tasks, and messages
|
|
135
|
+
description: `Swarm orchestration tool. Bulk delete pheromones, tasks, and messages for a swarm or agent. Warning pheromones preserved by default. Use dryRun=true to preview.`,
|
|
226
136
|
},
|
|
227
137
|
[TOOL_NAMES.swarmPostTask]: {
|
|
228
138
|
title: 'Swarm Post Task',
|
|
229
|
-
description: `Post a task to the swarm queue.
|
|
230
|
-
|
|
231
|
-
Types: implement, refactor, fix, test, review, document, investigate, plan. Priority: critical, high, normal, low, backlog.
|
|
232
|
-
|
|
233
|
-
Use dependencies array for task ordering. Tasks with incomplete deps auto-block until ready.`,
|
|
139
|
+
description: `Swarm orchestration tool. Post a task to the swarm queue. Use dependencies array for task ordering — tasks with incomplete deps auto-block until ready.`,
|
|
234
140
|
},
|
|
235
141
|
[TOOL_NAMES.swarmClaimTask]: {
|
|
236
142
|
title: 'Swarm Claim Task',
|
|
237
|
-
description: `Claim a task from the
|
|
238
|
-
|
|
239
|
-
**Actions:** claim_and_start (default, recommended), claim, start, release, abandon, force_start
|
|
240
|
-
|
|
241
|
-
**Flow:** claim_and_start → do work → swarm_complete_task
|
|
143
|
+
description: `Swarm orchestration tool. Claim a task from the queue. Without taskId, claims highest-priority available task. Set startImmediately=false to claim without starting.
|
|
242
144
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
145
|
+
Flow: swarm_claim_task → do work → swarm_complete_task. Use swarm_release_task to give up work, swarm_advance_task for state transitions.`,
|
|
146
|
+
},
|
|
147
|
+
[TOOL_NAMES.swarmReleaseTask]: {
|
|
148
|
+
title: 'Swarm Release Task',
|
|
149
|
+
description: `Swarm orchestration tool. Release or abandon a claimed task. Use when an agent can no longer complete a task. Set trackAbandonment=true to record the abandonment for retry tracking.`,
|
|
150
|
+
},
|
|
151
|
+
[TOOL_NAMES.swarmAdvanceTask]: {
|
|
152
|
+
title: 'Swarm Advance Task',
|
|
153
|
+
description: `Swarm orchestration tool. Start or force-start a claimed task. Use after claiming with startImmediately=false, or set force=true to recover from a stuck claimed state.`,
|
|
246
154
|
},
|
|
247
155
|
[TOOL_NAMES.swarmCompleteTask]: {
|
|
248
156
|
title: 'Swarm Complete Task',
|
|
249
|
-
description: `Mark a task as completed, failed, or request review.
|
|
250
|
-
|
|
251
|
-
**Actions:** complete, fail, request_review, approve, reject, retry
|
|
252
|
-
|
|
253
|
-
Required: summary (for complete/request_review), reason (for fail), reviewerId (for approve/reject).
|
|
254
|
-
|
|
255
|
-
Complete unblocks dependent tasks. Failed tasks can be retried if retryable=true.`,
|
|
157
|
+
description: `Swarm orchestration tool. Mark a task as completed, failed, or request review. Completing unblocks dependent tasks. Failed tasks can be retried if retryable=true.`,
|
|
256
158
|
},
|
|
257
159
|
[TOOL_NAMES.swarmGetTasks]: {
|
|
258
160
|
title: 'Swarm Get Tasks',
|
|
259
|
-
description: `Query tasks with filters. Use taskId for single task, or filter by swarmId, statuses, types, claimedBy
|
|
260
|
-
|
|
261
|
-
Sort by: priority (default), created, updated. Add includeStats:true for aggregate counts.`,
|
|
161
|
+
description: `Swarm orchestration tool. Query tasks with filters. Use taskId for a single task, or filter by swarmId, statuses, types, claimedBy. Add includeStats=true for aggregate counts.`,
|
|
262
162
|
},
|
|
263
163
|
[TOOL_NAMES.saveSessionBookmark]: {
|
|
264
164
|
title: 'Save Session Bookmark',
|
|
265
|
-
description: `Save current
|
|
266
|
-
|
|
267
|
-
Records your working set (code node IDs), task context, findings, and next steps so a future session can resume exactly where you left off.
|
|
268
|
-
|
|
269
|
-
Parameters:
|
|
270
|
-
- projectId (required): Project ID, name, or path
|
|
271
|
-
- sessionId (required): Unique session/conversation ID for recovery
|
|
272
|
-
- agentId (required): Your agent identifier
|
|
273
|
-
- summary (required, min 10 chars): Brief description of current work state
|
|
274
|
-
- workingSetNodeIds (required): Code node IDs you are focused on
|
|
275
|
-
- taskContext (required): High-level task being worked on
|
|
276
|
-
- findings: Key discoveries or decisions made so far
|
|
277
|
-
- nextSteps: What to do next when resuming
|
|
278
|
-
- metadata: Additional structured data
|
|
279
|
-
|
|
280
|
-
Returns bookmarkId for use with restore_session_bookmark.`,
|
|
165
|
+
description: `Session persistence tool. Save current working set, task context, findings, and next steps as a bookmark for cross-session continuity. Use session_recall to resume.`,
|
|
281
166
|
},
|
|
282
167
|
[TOOL_NAMES.restoreSessionBookmark]: {
|
|
283
168
|
title: 'Restore Session Bookmark',
|
|
284
|
-
description: `Restore a previously saved
|
|
285
|
-
|
|
286
|
-
Retrieves the bookmark, fetches working set code nodes (with source), and returns any session notes. Use after conversation compaction or when resuming a task in a new session.
|
|
287
|
-
|
|
288
|
-
Parameters:
|
|
289
|
-
- projectId (required): Project ID, name, or path
|
|
290
|
-
- sessionId: Specific session to restore (latest bookmark if omitted)
|
|
291
|
-
- agentId: Filter by agent ID (any agent if omitted)
|
|
292
|
-
- includeCode (default: true): Include source code for working set nodes
|
|
293
|
-
- snippetLength (default: 500): Max characters per code snippet
|
|
294
|
-
|
|
295
|
-
Returns: bookmark data, working set nodes, session notes, and staleNodeIds (nodes no longer in graph after re-parse).`,
|
|
169
|
+
description: `Session persistence tool. Restore a previously saved bookmark to resume work. Returns bookmark data, working set nodes with source code, session notes, and stale node IDs.`,
|
|
296
170
|
},
|
|
297
171
|
[TOOL_NAMES.saveSessionNote]: {
|
|
298
172
|
title: 'Save Session Note',
|
|
299
|
-
description: `Save an observation, decision,
|
|
300
|
-
|
|
301
|
-
Notes survive session compaction and are recalled by restore_session_bookmark or recall_session_notes.
|
|
302
|
-
|
|
303
|
-
Parameters:
|
|
304
|
-
- projectId (required): Project ID, name, or path
|
|
305
|
-
- sessionId (required): Session/conversation identifier
|
|
306
|
-
- agentId (required): Your agent identifier
|
|
307
|
-
- topic (required, 3-100 chars): Short topic label
|
|
308
|
-
- content (required, min 10 chars): Full observation text
|
|
309
|
-
- category (required): architectural, bug, insight, decision, risk, or todo
|
|
310
|
-
- severity (default: info): info, warning, or critical
|
|
311
|
-
- aboutNodeIds: Code node IDs this note is about (creates [:ABOUT] links)
|
|
312
|
-
- expiresInHours: Auto-expire after N hours (omit for permanent)
|
|
313
|
-
|
|
314
|
-
Returns noteId, hasEmbedding (enables semantic recall), and expiresAt.`,
|
|
173
|
+
description: `Session persistence tool. Save an observation, decision, or risk as a durable note linked to code nodes. Notes survive session compaction and are searchable via session_recall.`,
|
|
315
174
|
},
|
|
316
175
|
[TOOL_NAMES.recallSessionNotes]: {
|
|
317
176
|
title: 'Recall Session Notes',
|
|
318
|
-
description: `Search and retrieve saved session notes.
|
|
319
|
-
|
|
320
|
-
Parameters:
|
|
321
|
-
- projectId (required): Project ID, name, or path
|
|
322
|
-
- query: Natural language search — triggers semantic vector search when provided
|
|
323
|
-
- category: Filter by architectural, bug, insight, decision, risk, todo
|
|
324
|
-
- severity: Filter by info, warning, or critical
|
|
325
|
-
- sessionId: Filter by session ID
|
|
326
|
-
- agentId: Filter by agent ID
|
|
327
|
-
- limit (default: 10, max: 50): Maximum notes to return
|
|
328
|
-
- minSimilarity (default: 0.3): Minimum similarity for vector search
|
|
329
|
-
|
|
330
|
-
Returns notes with topic, content, category, severity, relevance score (vector mode), and linked aboutNodes.`,
|
|
177
|
+
description: `Session persistence tool. Search and retrieve saved session notes. Provide query for semantic vector search, or filter by category/severity/sessionId/agentId.`,
|
|
331
178
|
},
|
|
332
179
|
[TOOL_NAMES.cleanupSession]: {
|
|
333
180
|
title: 'Cleanup Session',
|
|
334
|
-
description: `
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
- dryRun (default: false): Preview what would be deleted without deleting
|
|
344
|
-
|
|
345
|
-
Returns counts of deleted notes, bookmarks, and edges.`,
|
|
181
|
+
description: `Session persistence tool. Remove expired session notes and old bookmarks, keeping the most recent per session.`,
|
|
182
|
+
},
|
|
183
|
+
[TOOL_NAMES.sessionSave]: {
|
|
184
|
+
title: 'Session Save',
|
|
185
|
+
description: `Session persistence tool. Save session context — auto-detects bookmark vs note based on input. Provide workingSetNodeIds for a bookmark, topic+content for a note, or both for a bookmark with an attached note.`,
|
|
186
|
+
},
|
|
187
|
+
[TOOL_NAMES.sessionRecall]: {
|
|
188
|
+
title: 'Session Recall',
|
|
189
|
+
description: `Session persistence tool. Retrieve saved session context. Provide query for semantic note search, or sessionId to restore the latest bookmark and all notes for that session.`,
|
|
346
190
|
},
|
|
347
191
|
[TOOL_NAMES.swarmMessage]: {
|
|
348
192
|
title: 'Swarm Message',
|
|
349
|
-
description: `Direct agent-to-agent messaging
|
|
350
|
-
|
|
351
|
-
**Actions:**
|
|
352
|
-
- send: Post a message to a specific agent or broadcast to all agents in a swarm
|
|
353
|
-
- read: Retrieve unread messages (or all messages) for an agent
|
|
354
|
-
- acknowledge: Mark messages as read
|
|
355
|
-
|
|
356
|
-
**Categories:** blocked, conflict, finding, request, alert, handoff
|
|
357
|
-
|
|
358
|
-
**Key behavior:**
|
|
359
|
-
- Messages sent to a specific agent are delivered when that agent calls swarm_claim_task
|
|
360
|
-
- Broadcast messages (toAgentId omitted) are visible to all agents in the swarm
|
|
361
|
-
- Messages auto-expire after 4 hours (configurable via ttlMs)
|
|
362
|
-
- Use this for critical coordination signals that agents MUST see, not optional context
|
|
193
|
+
description: `Swarm coordination tool. Direct agent-to-agent messaging. Unlike pheromones (passive/decay-based), messages are explicit and delivered when agents claim tasks. Use for critical coordination signals.
|
|
363
194
|
|
|
364
|
-
|
|
365
|
-
- Agent finds a breaking type error: send alert to all
|
|
366
|
-
- Agent is blocked on a file another agent owns: send blocked to that agent
|
|
367
|
-
- Agent discovers context another agent needs: send finding to that agent`,
|
|
195
|
+
Actions: send (post or broadcast), read (retrieve), acknowledge (mark read). Categories: blocked, conflict, finding, request, alert, handoff.`,
|
|
368
196
|
},
|
|
369
197
|
};
|
|
370
198
|
// Default Values
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { GET_TASK_STATE_QUERY } from './queries.js';
|
|
2
|
+
/**
|
|
3
|
+
* Query to abandon a task — releases it with tracking for debugging.
|
|
4
|
+
* More explicit than release: tracks abandon history (count, previous claimant).
|
|
5
|
+
*/
|
|
6
|
+
const ABANDON_TASK_QUERY = `
|
|
7
|
+
MATCH (t:SwarmTask {id: $taskId, projectId: $projectId})
|
|
8
|
+
WHERE t.claimedBy = $agentId
|
|
9
|
+
AND t.status IN ['claimed', 'in_progress']
|
|
10
|
+
|
|
11
|
+
// Track abandon history
|
|
12
|
+
SET t.status = 'available',
|
|
13
|
+
t.previousClaimedBy = t.claimedBy,
|
|
14
|
+
t.claimedBy = null,
|
|
15
|
+
t.claimedAt = null,
|
|
16
|
+
t.startedAt = null,
|
|
17
|
+
t.updatedAt = timestamp(),
|
|
18
|
+
t.abandonedBy = $agentId,
|
|
19
|
+
t.abandonedAt = timestamp(),
|
|
20
|
+
t.abandonReason = $reason,
|
|
21
|
+
t.abandonCount = COALESCE(t.abandonCount, 0) + 1
|
|
22
|
+
|
|
23
|
+
RETURN t.id as id,
|
|
24
|
+
t.title as title,
|
|
25
|
+
t.status as status,
|
|
26
|
+
t.abandonCount as abandonCount,
|
|
27
|
+
t.abandonReason as abandonReason
|
|
28
|
+
`;
|
|
29
|
+
export class SwarmAbandonHandler {
|
|
30
|
+
neo4jService;
|
|
31
|
+
constructor(neo4jService) {
|
|
32
|
+
this.neo4jService = neo4jService;
|
|
33
|
+
}
|
|
34
|
+
async abandon(projectId, taskId, agentId, reason) {
|
|
35
|
+
const result = await this.neo4jService.run(ABANDON_TASK_QUERY, {
|
|
36
|
+
taskId,
|
|
37
|
+
projectId,
|
|
38
|
+
agentId,
|
|
39
|
+
reason: reason || 'No reason provided',
|
|
40
|
+
});
|
|
41
|
+
if (result.length === 0) {
|
|
42
|
+
const stateResult = await this.neo4jService.run(GET_TASK_STATE_QUERY, {
|
|
43
|
+
taskId,
|
|
44
|
+
projectId,
|
|
45
|
+
});
|
|
46
|
+
return { error: true, data: stateResult[0] };
|
|
47
|
+
}
|
|
48
|
+
const row = result[0];
|
|
49
|
+
const abandonCount = typeof row.abandonCount === 'object' ? row.abandonCount.toNumber() : row.abandonCount;
|
|
50
|
+
return {
|
|
51
|
+
error: false,
|
|
52
|
+
data: {
|
|
53
|
+
id: row.id,
|
|
54
|
+
title: row.title,
|
|
55
|
+
status: row.status,
|
|
56
|
+
abandonCount,
|
|
57
|
+
abandonReason: row.abandonReason,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { GET_TASK_STATE_QUERY } from './queries.js';
|
|
2
|
+
/**
|
|
3
|
+
* Query to start working on a claimed task (transition to in_progress)
|
|
4
|
+
*/
|
|
5
|
+
const START_TASK_QUERY = `
|
|
6
|
+
MATCH (t:SwarmTask {id: $taskId, projectId: $projectId})
|
|
7
|
+
WHERE t.status = 'claimed' AND t.claimedBy = $agentId
|
|
8
|
+
|
|
9
|
+
SET t.status = 'in_progress',
|
|
10
|
+
t.startedAt = timestamp(),
|
|
11
|
+
t.updatedAt = timestamp()
|
|
12
|
+
|
|
13
|
+
RETURN t.id as id,
|
|
14
|
+
t.status as status,
|
|
15
|
+
t.claimedBy as claimedBy,
|
|
16
|
+
t.startedAt as startedAt
|
|
17
|
+
`;
|
|
18
|
+
/**
|
|
19
|
+
* Query to force-start a task stuck in claimed state.
|
|
20
|
+
* Allows recovery when the normal start action fails.
|
|
21
|
+
*/
|
|
22
|
+
const FORCE_START_QUERY = `
|
|
23
|
+
MATCH (t:SwarmTask {id: $taskId, projectId: $projectId})
|
|
24
|
+
WHERE t.claimedBy = $agentId
|
|
25
|
+
AND t.status IN ['claimed', 'available']
|
|
26
|
+
|
|
27
|
+
SET t.status = 'in_progress',
|
|
28
|
+
t.claimedBy = $agentId,
|
|
29
|
+
t.claimedAt = COALESCE(t.claimedAt, timestamp()),
|
|
30
|
+
t.startedAt = timestamp(),
|
|
31
|
+
t.updatedAt = timestamp(),
|
|
32
|
+
t.forceStarted = true,
|
|
33
|
+
t.forceStartReason = $reason
|
|
34
|
+
|
|
35
|
+
RETURN t.id as id,
|
|
36
|
+
t.title as title,
|
|
37
|
+
t.status as status,
|
|
38
|
+
t.claimedBy as claimedBy,
|
|
39
|
+
t.startedAt as startedAt,
|
|
40
|
+
t.forceStarted as forceStarted
|
|
41
|
+
`;
|
|
42
|
+
export class SwarmAdvanceHandler {
|
|
43
|
+
neo4jService;
|
|
44
|
+
constructor(neo4jService) {
|
|
45
|
+
this.neo4jService = neo4jService;
|
|
46
|
+
}
|
|
47
|
+
async start(projectId, taskId, agentId) {
|
|
48
|
+
const result = await this.neo4jService.run(START_TASK_QUERY, {
|
|
49
|
+
taskId,
|
|
50
|
+
projectId,
|
|
51
|
+
agentId,
|
|
52
|
+
});
|
|
53
|
+
if (result.length === 0) {
|
|
54
|
+
const stateResult = await this.neo4jService.run(GET_TASK_STATE_QUERY, {
|
|
55
|
+
taskId,
|
|
56
|
+
projectId,
|
|
57
|
+
});
|
|
58
|
+
return { error: true, data: stateResult[0] };
|
|
59
|
+
}
|
|
60
|
+
return { error: false, data: result[0] };
|
|
61
|
+
}
|
|
62
|
+
async forceStart(projectId, taskId, agentId, reason) {
|
|
63
|
+
const result = await this.neo4jService.run(FORCE_START_QUERY, {
|
|
64
|
+
taskId,
|
|
65
|
+
projectId,
|
|
66
|
+
agentId,
|
|
67
|
+
reason: reason || 'Recovering from stuck state',
|
|
68
|
+
});
|
|
69
|
+
if (result.length === 0) {
|
|
70
|
+
const stateResult = await this.neo4jService.run(GET_TASK_STATE_QUERY, {
|
|
71
|
+
taskId,
|
|
72
|
+
projectId,
|
|
73
|
+
});
|
|
74
|
+
return { error: true, data: stateResult[0] };
|
|
75
|
+
}
|
|
76
|
+
return { error: false, data: result[0] };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TASK_PRIORITIES } from '../../tools/swarm-constants.js';
|
|
2
|
+
import { CLAIM_TASK_BY_ID_QUERY, CLAIM_NEXT_TASK_QUERY, GET_TASK_STATE_QUERY } from './queries.js';
|
|
3
|
+
/** Maximum retries when racing for a task */
|
|
4
|
+
const MAX_CLAIM_RETRIES = 3;
|
|
5
|
+
/** Delay between retries (ms) */
|
|
6
|
+
const RETRY_DELAY_BASE_MS = 50;
|
|
7
|
+
export class SwarmClaimHandler {
|
|
8
|
+
neo4jService;
|
|
9
|
+
constructor(neo4jService) {
|
|
10
|
+
this.neo4jService = neo4jService;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Claim a specific task by ID.
|
|
14
|
+
*/
|
|
15
|
+
async claimById(projectId, taskId, agentId, targetStatus) {
|
|
16
|
+
const result = await this.neo4jService.run(CLAIM_TASK_BY_ID_QUERY, {
|
|
17
|
+
taskId,
|
|
18
|
+
projectId,
|
|
19
|
+
agentId,
|
|
20
|
+
targetStatus,
|
|
21
|
+
});
|
|
22
|
+
if (result.length === 0) {
|
|
23
|
+
const stateResult = await this.neo4jService.run(GET_TASK_STATE_QUERY, {
|
|
24
|
+
taskId,
|
|
25
|
+
projectId,
|
|
26
|
+
});
|
|
27
|
+
return { error: true, data: stateResult[0], retryAttempts: 0 };
|
|
28
|
+
}
|
|
29
|
+
return { error: false, data: result[0], retryAttempts: 0 };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Auto-select and claim the highest priority available task.
|
|
33
|
+
* Includes retry logic with exponential backoff for race conditions.
|
|
34
|
+
*/
|
|
35
|
+
async claimNext(projectId, swarmId, agentId, targetStatus, filters) {
|
|
36
|
+
const minPriorityScore = filters?.minPriority ? TASK_PRIORITIES[filters.minPriority] : null;
|
|
37
|
+
let result = [];
|
|
38
|
+
let retryCount = 0;
|
|
39
|
+
while (retryCount < MAX_CLAIM_RETRIES) {
|
|
40
|
+
result = await this.neo4jService.run(CLAIM_NEXT_TASK_QUERY, {
|
|
41
|
+
projectId,
|
|
42
|
+
swarmId,
|
|
43
|
+
agentId,
|
|
44
|
+
types: filters?.types || null,
|
|
45
|
+
minPriority: minPriorityScore,
|
|
46
|
+
targetStatus,
|
|
47
|
+
});
|
|
48
|
+
if (result.length > 0) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
retryCount++;
|
|
52
|
+
if (retryCount < MAX_CLAIM_RETRIES) {
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_BASE_MS * Math.pow(2, retryCount - 1)));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (result.length === 0) {
|
|
57
|
+
return { error: false, data: null, retryAttempts: retryCount };
|
|
58
|
+
}
|
|
59
|
+
return { error: false, data: result[0], retryAttempts: retryCount };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SwarmClaimHandler } from './claim.handler.js';
|
|
2
|
+
export { SwarmReleaseHandler } from './release.handler.js';
|
|
3
|
+
export { SwarmAbandonHandler } from './abandon.handler.js';
|
|
4
|
+
export { SwarmAdvanceHandler } from './advance.handler.js';
|
|
5
|
+
export { GET_TASK_STATE_QUERY, CLAIM_TASK_BY_ID_QUERY, CLAIM_NEXT_TASK_QUERY } from './queries.js';
|