agent-planner-mcp 0.3.1 → 0.5.1
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/AGENT_GUIDE.md +257 -0
- package/LICENSE +21 -0
- package/README.md +128 -247
- package/SKILL.md +438 -0
- package/package.json +24 -7
- package/src/api-client.js +506 -115
- package/src/index.js +60 -27
- package/src/integrations/search-integration.js +3 -5
- package/src/server-http.js +569 -0
- package/src/session-manager.js +223 -0
- package/src/setup.js +1 -1
- package/src/tools/search-wrapper.js +12 -6
- package/src/tools.js +1983 -159
- package/claude-code/AUTONOMOUS_EXECUTION_GUIDE.md +0 -335
- package/claude-code/commands/README.md +0 -112
- package/claude-code/commands/create-plan.md +0 -174
- package/claude-code/commands/execute-plan.md +0 -202
- package/claude-code/commands/plan-status.md +0 -145
- package/claude-code/settings.template.json +0 -12
package/src/api-client.js
CHANGED
|
@@ -26,23 +26,28 @@ const apiClient = axios.create({
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
// Log API requests in
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
// Log API requests only in development mode
|
|
30
|
+
if (process.env.NODE_ENV === 'development') {
|
|
31
|
+
apiClient.interceptors.request.use(request => {
|
|
32
|
+
console.error(`API Request: ${request.method.toUpperCase()} ${request.url}`);
|
|
33
|
+
return request;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Handle API responses - log details only in development, always handle auth errors helpfully
|
|
36
38
|
apiClient.interceptors.response.use(
|
|
37
39
|
response => {
|
|
38
|
-
|
|
40
|
+
if (process.env.NODE_ENV === 'development') {
|
|
41
|
+
console.error(`API Response: ${response.status} ${response.statusText}`);
|
|
42
|
+
}
|
|
39
43
|
return response;
|
|
40
44
|
},
|
|
41
45
|
error => {
|
|
46
|
+
// Always log auth errors helpfully (but not the token itself)
|
|
42
47
|
if (error.response && error.response.status === 401) {
|
|
43
|
-
console.error('API Error: Authentication failed (401). Please check that your USER_API_TOKEN is correct
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
console.error('API Error: Authentication failed (401). Please check that your USER_API_TOKEN is correct and not revoked.');
|
|
49
|
+
} else if (process.env.NODE_ENV === 'development') {
|
|
50
|
+
// Only log other errors in development
|
|
46
51
|
console.error('API Error:', error.response ? error.response.data : error.message);
|
|
47
52
|
}
|
|
48
53
|
return Promise.reject(error);
|
|
@@ -100,6 +105,30 @@ const plans = {
|
|
|
100
105
|
*/
|
|
101
106
|
deletePlan: async (planId) => {
|
|
102
107
|
await apiClient.delete(`/plans/${planId}`);
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Update plan visibility (make public or private)
|
|
112
|
+
* @param {string} planId - Plan ID
|
|
113
|
+
* @param {Object} visibilityData - Visibility settings
|
|
114
|
+
* @param {string} visibilityData.visibility - 'public' or 'private'
|
|
115
|
+
* @param {string} [visibilityData.github_repo_owner] - GitHub repo owner (for public plans)
|
|
116
|
+
* @param {string} [visibilityData.github_repo_name] - GitHub repo name (for public plans)
|
|
117
|
+
* @returns {Promise<Object>} - Updated plan with visibility info
|
|
118
|
+
*/
|
|
119
|
+
updateVisibility: async (planId, visibilityData) => {
|
|
120
|
+
const response = await apiClient.put(`/plans/${planId}/visibility`, visibilityData);
|
|
121
|
+
return response.data;
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get a public plan (no authentication required in browser, but API token needed for MCP)
|
|
126
|
+
* @param {string} planId - Plan ID
|
|
127
|
+
* @returns {Promise<Object>} - Public plan details
|
|
128
|
+
*/
|
|
129
|
+
getPublicPlan: async (planId) => {
|
|
130
|
+
const response = await apiClient.get(`/plans/${planId}/public`);
|
|
131
|
+
return response.data;
|
|
103
132
|
}
|
|
104
133
|
};
|
|
105
134
|
|
|
@@ -110,10 +139,18 @@ const nodes = {
|
|
|
110
139
|
/**
|
|
111
140
|
* Get nodes for a plan
|
|
112
141
|
* @param {string} planId - Plan ID
|
|
142
|
+
* @param {Object} options - Optional query parameters
|
|
143
|
+
* @param {boolean} options.include_details - Include full node details (default: false)
|
|
113
144
|
* @returns {Promise<Array>} - List of nodes
|
|
114
145
|
*/
|
|
115
|
-
getNodes: async (planId) => {
|
|
116
|
-
const
|
|
146
|
+
getNodes: async (planId, options = {}) => {
|
|
147
|
+
const params = new URLSearchParams();
|
|
148
|
+
if (options.include_details) {
|
|
149
|
+
params.append('include_details', 'true');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const queryString = params.toString() ? `?${params.toString()}` : '';
|
|
153
|
+
const response = await apiClient.get(`/plans/${planId}/nodes${queryString}`);
|
|
117
154
|
return response.data;
|
|
118
155
|
},
|
|
119
156
|
|
|
@@ -171,6 +208,21 @@ const nodes = {
|
|
|
171
208
|
*/
|
|
172
209
|
deleteNode: async (planId, nodeId) => {
|
|
173
210
|
await apiClient.delete(`/plans/${planId}/nodes/${nodeId}`);
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
claimTask: async (planId, nodeId, agentId = 'mcp-agent', ttlMinutes = 30) => {
|
|
214
|
+
const response = await apiClient.post(`/plans/${planId}/nodes/${nodeId}/claim`, { agent_id: agentId, ttl_minutes: ttlMinutes });
|
|
215
|
+
return response.data;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
releaseTask: async (planId, nodeId, agentId = 'mcp-agent') => {
|
|
219
|
+
const response = await apiClient.delete(`/plans/${planId}/nodes/${nodeId}/claim`, { data: { agent_id: agentId } });
|
|
220
|
+
return response.data;
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
getTaskClaim: async (planId, nodeId) => {
|
|
224
|
+
const response = await apiClient.get(`/plans/${planId}/nodes/${nodeId}/claim`);
|
|
225
|
+
return response.data;
|
|
174
226
|
}
|
|
175
227
|
};
|
|
176
228
|
|
|
@@ -230,101 +282,6 @@ const logs = {
|
|
|
230
282
|
}
|
|
231
283
|
};
|
|
232
284
|
|
|
233
|
-
/**
|
|
234
|
-
* Artifact-related API functions
|
|
235
|
-
*/
|
|
236
|
-
const artifacts = {
|
|
237
|
-
/**
|
|
238
|
-
* Get artifacts for a node
|
|
239
|
-
* @param {string} planId - Plan ID
|
|
240
|
-
* @param {string} nodeId - Node ID
|
|
241
|
-
* @returns {Promise<Array>} - List of artifacts
|
|
242
|
-
*/
|
|
243
|
-
getArtifacts: async (planId, nodeId) => {
|
|
244
|
-
const response = await apiClient.get(`/plans/${planId}/nodes/${nodeId}/artifacts`);
|
|
245
|
-
return response.data;
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Get a specific artifact by ID
|
|
250
|
-
* @param {string} planId - Plan ID
|
|
251
|
-
* @param {string} nodeId - Node ID
|
|
252
|
-
* @param {string} artifactId - Artifact ID
|
|
253
|
-
* @returns {Promise<Object>} - Artifact details
|
|
254
|
-
*/
|
|
255
|
-
getArtifact: async (planId, nodeId, artifactId) => {
|
|
256
|
-
const response = await apiClient.get(`/plans/${planId}/nodes/${nodeId}/artifacts/${artifactId}`);
|
|
257
|
-
return response.data;
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Get the content of an artifact
|
|
262
|
-
* @param {string} planId - Plan ID
|
|
263
|
-
* @param {string} nodeId - Node ID
|
|
264
|
-
* @param {string} artifactId - Artifact ID
|
|
265
|
-
* @returns {Promise<string>} - Artifact content
|
|
266
|
-
*/
|
|
267
|
-
getArtifactContent: async (planId, nodeId, artifactId) => {
|
|
268
|
-
try {
|
|
269
|
-
// First, get artifact details to check the URL
|
|
270
|
-
const artifact = await artifacts.getArtifact(planId, nodeId, artifactId);
|
|
271
|
-
|
|
272
|
-
// If the artifact has a URL, fetch the content
|
|
273
|
-
if (artifact.url) {
|
|
274
|
-
try {
|
|
275
|
-
// For local file paths, use fs instead of HTTP request
|
|
276
|
-
if (artifact.url.startsWith('/') && !artifact.url.startsWith('/api/')) {
|
|
277
|
-
const fs = require('fs').promises;
|
|
278
|
-
try {
|
|
279
|
-
// Read the file directly from the filesystem
|
|
280
|
-
const content = await fs.readFile(artifact.url, 'utf8');
|
|
281
|
-
return content;
|
|
282
|
-
} catch (fsError) {
|
|
283
|
-
console.error('Error reading artifact file:', fsError);
|
|
284
|
-
throw new Error(`Cannot read file at ${artifact.url}: ${fsError.message}`);
|
|
285
|
-
}
|
|
286
|
-
} else {
|
|
287
|
-
// For internal URLs (API routes), append to base URL
|
|
288
|
-
const contentUrl = artifact.url.startsWith('/api/')
|
|
289
|
-
? `${apiClient.defaults.baseURL}${artifact.url}`
|
|
290
|
-
: artifact.url;
|
|
291
|
-
|
|
292
|
-
const contentResponse = await axios.get(contentUrl, {
|
|
293
|
-
headers: {
|
|
294
|
-
'Authorization': apiClient.defaults.headers['Authorization'],
|
|
295
|
-
'Accept': artifact.content_type || 'text/plain'
|
|
296
|
-
},
|
|
297
|
-
responseType: 'text'
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
return contentResponse.data;
|
|
301
|
-
}
|
|
302
|
-
} catch (fetchError) {
|
|
303
|
-
console.error('Error fetching artifact content:', fetchError);
|
|
304
|
-
throw new Error(`Failed to fetch artifact content: ${fetchError.message}`);
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
throw new Error('Artifact does not have a content URL');
|
|
308
|
-
}
|
|
309
|
-
} catch (error) {
|
|
310
|
-
console.error('Error fetching artifact content:', error);
|
|
311
|
-
throw error;
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Add an artifact to a node
|
|
317
|
-
* @param {string} planId - Plan ID
|
|
318
|
-
* @param {string} nodeId - Node ID
|
|
319
|
-
* @param {Object} artifactData - Artifact data
|
|
320
|
-
* @returns {Promise<Object>} - Created artifact
|
|
321
|
-
*/
|
|
322
|
-
addArtifact: async (planId, nodeId, artifactData) => {
|
|
323
|
-
const response = await apiClient.post(`/plans/${planId}/nodes/${nodeId}/artifacts`, artifactData);
|
|
324
|
-
return response.data;
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
285
|
/**
|
|
329
286
|
* Activity-related API functions
|
|
330
287
|
*/
|
|
@@ -335,7 +292,7 @@ const activity = {
|
|
|
335
292
|
* @returns {Promise<Array>} - Activity feed
|
|
336
293
|
*/
|
|
337
294
|
getPlanActivity: async (planId) => {
|
|
338
|
-
const response = await apiClient.get(`/activity/
|
|
295
|
+
const response = await apiClient.get(`/activity/plans/${planId}/activity`);
|
|
339
296
|
return response.data;
|
|
340
297
|
},
|
|
341
298
|
|
|
@@ -344,7 +301,7 @@ const activity = {
|
|
|
344
301
|
* @returns {Promise<Array>} - Activity feed
|
|
345
302
|
*/
|
|
346
303
|
getGlobalActivity: async () => {
|
|
347
|
-
const response = await apiClient.get('/activity');
|
|
304
|
+
const response = await apiClient.get('/activity/feed');
|
|
348
305
|
return response.data;
|
|
349
306
|
}
|
|
350
307
|
};
|
|
@@ -499,7 +456,7 @@ const tokens = {
|
|
|
499
456
|
* @returns {Promise<Array>} - List of API tokens
|
|
500
457
|
*/
|
|
501
458
|
getTokens: async () => {
|
|
502
|
-
const response = await apiClient.get('/
|
|
459
|
+
const response = await apiClient.get('/auth/token');
|
|
503
460
|
return response.data;
|
|
504
461
|
},
|
|
505
462
|
|
|
@@ -509,7 +466,7 @@ const tokens = {
|
|
|
509
466
|
* @returns {Promise<Object>} - Created token
|
|
510
467
|
*/
|
|
511
468
|
createToken: async (tokenData) => {
|
|
512
|
-
const response = await apiClient.post('/
|
|
469
|
+
const response = await apiClient.post('/auth/token', tokenData);
|
|
513
470
|
return response.data;
|
|
514
471
|
},
|
|
515
472
|
|
|
@@ -519,10 +476,439 @@ const tokens = {
|
|
|
519
476
|
* @returns {Promise<void>}
|
|
520
477
|
*/
|
|
521
478
|
revokeToken: async (tokenId) => {
|
|
522
|
-
await apiClient.delete(`/
|
|
479
|
+
await apiClient.delete(`/auth/token/${tokenId}`);
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Organization API functions
|
|
485
|
+
*/
|
|
486
|
+
const organizations = {
|
|
487
|
+
list: async () => {
|
|
488
|
+
const response = await apiClient.get('/organizations');
|
|
489
|
+
return response.data.organizations || response.data;
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
get: async (orgId) => {
|
|
493
|
+
const response = await apiClient.get(`/organizations/${orgId}`);
|
|
494
|
+
return response.data;
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
create: async (data) => {
|
|
498
|
+
const response = await apiClient.post('/organizations', data);
|
|
499
|
+
return response.data;
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
update: async (orgId, data) => {
|
|
503
|
+
const response = await apiClient.put(`/organizations/${orgId}`, data);
|
|
504
|
+
return response.data;
|
|
505
|
+
},
|
|
506
|
+
|
|
507
|
+
delete: async (orgId) => {
|
|
508
|
+
const response = await apiClient.delete(`/organizations/${orgId}`);
|
|
509
|
+
return response.data;
|
|
510
|
+
},
|
|
511
|
+
|
|
512
|
+
listMembers: async (orgId) => {
|
|
513
|
+
const response = await apiClient.get(`/organizations/${orgId}/members`);
|
|
514
|
+
return response.data.members || response.data;
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
addMember: async (orgId, data) => {
|
|
518
|
+
const response = await apiClient.post(`/organizations/${orgId}/members`, data);
|
|
519
|
+
return response.data;
|
|
520
|
+
},
|
|
521
|
+
|
|
522
|
+
removeMember: async (orgId, memberId) => {
|
|
523
|
+
const response = await apiClient.delete(`/organizations/${orgId}/members/${memberId}`);
|
|
524
|
+
return response.data;
|
|
523
525
|
}
|
|
524
526
|
};
|
|
525
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Goals API functions
|
|
530
|
+
*/
|
|
531
|
+
const goals = {
|
|
532
|
+
list: async (filters = {}) => {
|
|
533
|
+
const params = new URLSearchParams();
|
|
534
|
+
if (filters.organization_id) params.append('organization_id', filters.organization_id);
|
|
535
|
+
if (filters.status) params.append('status', filters.status);
|
|
536
|
+
const response = await apiClient.get(`/goals?${params.toString()}`);
|
|
537
|
+
return response.data.goals || response.data;
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
get: async (goalId) => {
|
|
541
|
+
const response = await apiClient.get(`/goals/${goalId}`);
|
|
542
|
+
return response.data;
|
|
543
|
+
},
|
|
544
|
+
|
|
545
|
+
create: async (data) => {
|
|
546
|
+
const response = await apiClient.post('/goals', data);
|
|
547
|
+
return response.data;
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
update: async (goalId, data) => {
|
|
551
|
+
const response = await apiClient.put(`/goals/${goalId}`, data);
|
|
552
|
+
return response.data;
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
updateMetrics: async (goalId, metrics) => {
|
|
556
|
+
const response = await apiClient.put(`/goals/${goalId}/metrics`, { metrics });
|
|
557
|
+
return response.data;
|
|
558
|
+
},
|
|
559
|
+
|
|
560
|
+
delete: async (goalId) => {
|
|
561
|
+
const response = await apiClient.delete(`/goals/${goalId}`);
|
|
562
|
+
return response.data;
|
|
563
|
+
},
|
|
564
|
+
|
|
565
|
+
linkPlan: async (goalId, planId) => {
|
|
566
|
+
const response = await apiClient.post(`/goals/${goalId}/plans/${planId}`);
|
|
567
|
+
return response.data;
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
unlinkPlan: async (goalId, planId) => {
|
|
571
|
+
const response = await apiClient.delete(`/goals/${goalId}/plans/${planId}`);
|
|
572
|
+
return response.data;
|
|
573
|
+
},
|
|
574
|
+
|
|
575
|
+
// v2 goal-dependency endpoints
|
|
576
|
+
getPath: async (goalId, maxDepth) => {
|
|
577
|
+
const params = maxDepth ? `?max_depth=${maxDepth}` : '';
|
|
578
|
+
const response = await apiClient.get(`/goals/v2/${goalId}/path${params}`);
|
|
579
|
+
return response.data;
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
getProgress: async (goalId) => {
|
|
583
|
+
const response = await apiClient.get(`/goals/v2/${goalId}/progress`);
|
|
584
|
+
return response.data;
|
|
585
|
+
},
|
|
586
|
+
|
|
587
|
+
listAchievers: async (goalId) => {
|
|
588
|
+
const response = await apiClient.get(`/goals/v2/${goalId}/achievers`);
|
|
589
|
+
return response.data;
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
addAchiever: async (goalId, sourceNodeId, weight) => {
|
|
593
|
+
const response = await apiClient.post(`/goals/v2/${goalId}/achievers`, {
|
|
594
|
+
source_node_id: sourceNodeId,
|
|
595
|
+
weight: weight ?? 1,
|
|
596
|
+
});
|
|
597
|
+
return response.data;
|
|
598
|
+
},
|
|
599
|
+
|
|
600
|
+
removeAchiever: async (goalId, depId) => {
|
|
601
|
+
const response = await apiClient.delete(`/goals/v2/${goalId}/achievers/${depId}`);
|
|
602
|
+
return response.data;
|
|
603
|
+
},
|
|
604
|
+
|
|
605
|
+
getKnowledgeGaps: async (goalId) => {
|
|
606
|
+
const response = await apiClient.get(`/goals/v2/${goalId}/knowledge-gaps`);
|
|
607
|
+
return response.data;
|
|
608
|
+
},
|
|
609
|
+
|
|
610
|
+
getDashboard: async () => {
|
|
611
|
+
const response = await apiClient.get('/goals/v2/dashboard');
|
|
612
|
+
return response.data;
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Agent Context API functions (leaf-up context loading)
|
|
618
|
+
*/
|
|
619
|
+
const context = {
|
|
620
|
+
/**
|
|
621
|
+
* Get focused context for a specific node (task/phase)
|
|
622
|
+
* Traverses from node up to root, including goals, org, and knowledge
|
|
623
|
+
* @param {string} nodeId - Node ID
|
|
624
|
+
* @param {Object} options - Options (include_knowledge, include_siblings)
|
|
625
|
+
* @returns {Promise<Object>} - Agent context
|
|
626
|
+
*/
|
|
627
|
+
getNodeContext: async (nodeId, options = {}) => {
|
|
628
|
+
const params = new URLSearchParams({ node_id: nodeId });
|
|
629
|
+
if (options.include_knowledge !== undefined) {
|
|
630
|
+
params.append('include_knowledge', options.include_knowledge);
|
|
631
|
+
}
|
|
632
|
+
if (options.include_siblings !== undefined) {
|
|
633
|
+
params.append('include_siblings', options.include_siblings);
|
|
634
|
+
}
|
|
635
|
+
const response = await apiClient.get(`/context?${params.toString()}`);
|
|
636
|
+
return response.data;
|
|
637
|
+
},
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Get plan-level context (overview, not full tree)
|
|
641
|
+
* @param {string} planId - Plan ID
|
|
642
|
+
* @param {Object} options - Options (include_knowledge)
|
|
643
|
+
* @returns {Promise<Object>} - Plan context
|
|
644
|
+
*/
|
|
645
|
+
getPlanContext: async (planId, options = {}) => {
|
|
646
|
+
const params = new URLSearchParams({ plan_id: planId });
|
|
647
|
+
if (options.include_knowledge !== undefined) {
|
|
648
|
+
params.append('include_knowledge', options.include_knowledge);
|
|
649
|
+
}
|
|
650
|
+
const response = await apiClient.get(`/context/plan?${params.toString()}`);
|
|
651
|
+
return response.data;
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Graphiti Knowledge Graph API functions (proxied through AgentPlanner API)
|
|
657
|
+
*/
|
|
658
|
+
const graphiti = {
|
|
659
|
+
/**
|
|
660
|
+
* Get Graphiti status
|
|
661
|
+
* GET /knowledge/graphiti/status
|
|
662
|
+
*/
|
|
663
|
+
getStatus: async () => {
|
|
664
|
+
const response = await apiClient.get('/knowledge/graphiti/status');
|
|
665
|
+
return response.data;
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Add a knowledge episode to Graphiti
|
|
670
|
+
* POST /knowledge/episodes
|
|
671
|
+
*/
|
|
672
|
+
addEpisode: async (data) => {
|
|
673
|
+
const response = await apiClient.post('/knowledge/episodes', data);
|
|
674
|
+
return response.data;
|
|
675
|
+
},
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Search knowledge in Graphiti temporal graph
|
|
679
|
+
* POST /knowledge/graph-search
|
|
680
|
+
*/
|
|
681
|
+
graphSearch: async (data) => {
|
|
682
|
+
const response = await apiClient.post('/knowledge/graph-search', data);
|
|
683
|
+
return response.data;
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Search entities in Graphiti
|
|
688
|
+
* POST /knowledge/entities
|
|
689
|
+
*/
|
|
690
|
+
searchEntities: async (data) => {
|
|
691
|
+
const response = await apiClient.post('/knowledge/entities', data);
|
|
692
|
+
return response.data;
|
|
693
|
+
},
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Detect contradictions in knowledge
|
|
697
|
+
* POST /knowledge/contradictions
|
|
698
|
+
*/
|
|
699
|
+
detectContradictions: async (data) => {
|
|
700
|
+
const response = await apiClient.post('/knowledge/contradictions', data);
|
|
701
|
+
return response.data;
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Get recent episodes from Graphiti
|
|
706
|
+
* GET /knowledge/episodes
|
|
707
|
+
*/
|
|
708
|
+
getEpisodes: async ({ max_episodes = 20 } = {}) => {
|
|
709
|
+
const response = await apiClient.get('/knowledge/episodes', { params: { max_episodes } });
|
|
710
|
+
return response.data;
|
|
711
|
+
},
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Delete an episode from Graphiti
|
|
715
|
+
* DELETE /knowledge/episodes/:episodeId
|
|
716
|
+
*/
|
|
717
|
+
deleteEpisode: async (episodeId) => {
|
|
718
|
+
const response = await apiClient.delete(`/knowledge/episodes/${episodeId}`);
|
|
719
|
+
return response.data;
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
// ─── Dependencies (cross-plan & external) ─────────────────────
|
|
724
|
+
const dependencies = {
|
|
725
|
+
/**
|
|
726
|
+
* Create a cross-plan dependency edge
|
|
727
|
+
* POST /dependencies/cross-plan
|
|
728
|
+
*/
|
|
729
|
+
createCrossPlan: async (data) => {
|
|
730
|
+
const response = await apiClient.post('/dependencies/cross-plan', data);
|
|
731
|
+
return response.data;
|
|
732
|
+
},
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* List cross-plan dependency edges between plans
|
|
736
|
+
* GET /dependencies/cross-plan?plan_ids=id1,id2
|
|
737
|
+
*/
|
|
738
|
+
listCrossPlan: async (planIds) => {
|
|
739
|
+
const response = await apiClient.get('/dependencies/cross-plan', {
|
|
740
|
+
params: { plan_ids: planIds.join(',') },
|
|
741
|
+
});
|
|
742
|
+
return response.data;
|
|
743
|
+
},
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Create an external dependency node (and optionally a blocking edge)
|
|
747
|
+
* POST /dependencies/external
|
|
748
|
+
*/
|
|
749
|
+
createExternal: async (data) => {
|
|
750
|
+
const response = await apiClient.post('/dependencies/external', data);
|
|
751
|
+
return response.data;
|
|
752
|
+
},
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Create an API client bound to a specific token.
|
|
757
|
+
* Used by the HTTP MCP server to create per-session clients.
|
|
758
|
+
* @param {string} token - API token or JWT
|
|
759
|
+
* @returns {Object} - API client modules (plans, nodes, etc.)
|
|
760
|
+
*/
|
|
761
|
+
function createApiClient(token) {
|
|
762
|
+
const scheme = getAuthScheme(token);
|
|
763
|
+
const client = axios.create({
|
|
764
|
+
baseURL: process.env.API_URL || 'http://localhost:3000',
|
|
765
|
+
headers: {
|
|
766
|
+
'Content-Type': 'application/json',
|
|
767
|
+
'Authorization': token ? `${scheme} ${token}` : undefined
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// Reuse the same interceptors
|
|
772
|
+
if (process.env.NODE_ENV === 'development') {
|
|
773
|
+
client.interceptors.request.use(request => {
|
|
774
|
+
console.error(`API Request: ${request.method.toUpperCase()} ${request.url}`);
|
|
775
|
+
return request;
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
client.interceptors.response.use(
|
|
779
|
+
response => response,
|
|
780
|
+
error => {
|
|
781
|
+
if (error.response && error.response.status === 401) {
|
|
782
|
+
console.error('API Error: Authentication failed (401).');
|
|
783
|
+
}
|
|
784
|
+
return Promise.reject(error);
|
|
785
|
+
}
|
|
786
|
+
);
|
|
787
|
+
|
|
788
|
+
// Build the same module structure using the per-session client
|
|
789
|
+
return {
|
|
790
|
+
plans: {
|
|
791
|
+
getPlans: async () => (await client.get('/plans')).data,
|
|
792
|
+
getPlan: async (planId) => (await client.get(`/plans/${planId}`)).data,
|
|
793
|
+
createPlan: async (planData) => (await client.post('/plans', planData)).data,
|
|
794
|
+
updatePlan: async (planId, planData) => (await client.put(`/plans/${planId}`, planData)).data,
|
|
795
|
+
deletePlan: async (planId) => await client.delete(`/plans/${planId}`),
|
|
796
|
+
updateVisibility: async (planId, data) => (await client.put(`/plans/${planId}/visibility`, data)).data,
|
|
797
|
+
getPublicPlan: async (planId) => (await client.get(`/plans/${planId}/public`)).data,
|
|
798
|
+
},
|
|
799
|
+
nodes: {
|
|
800
|
+
getNodes: async (planId, options = {}) => {
|
|
801
|
+
const params = new URLSearchParams();
|
|
802
|
+
if (options.include_details) params.append('include_details', 'true');
|
|
803
|
+
const qs = params.toString() ? `?${params.toString()}` : '';
|
|
804
|
+
return (await client.get(`/plans/${planId}/nodes${qs}`)).data;
|
|
805
|
+
},
|
|
806
|
+
getNode: async (planId, nodeId) => (await client.get(`/plans/${planId}/nodes/${nodeId}`)).data,
|
|
807
|
+
createNode: async (planId, nodeData) => (await client.post(`/plans/${planId}/nodes`, nodeData)).data,
|
|
808
|
+
updateNode: async (planId, nodeId, nodeData) => (await client.put(`/plans/${planId}/nodes/${nodeId}`, nodeData)).data,
|
|
809
|
+
updateNodeStatus: async (planId, nodeId, status) => (await client.put(`/plans/${planId}/nodes/${nodeId}/status`, { status })).data,
|
|
810
|
+
deleteNode: async (planId, nodeId) => await client.delete(`/plans/${planId}/nodes/${nodeId}`),
|
|
811
|
+
claimTask: async (planId, nodeId, agentId = 'mcp-agent', ttlMinutes = 30) => (await client.post(`/plans/${planId}/nodes/${nodeId}/claim`, { agent_id: agentId, ttl_minutes: ttlMinutes })).data,
|
|
812
|
+
releaseTask: async (planId, nodeId, agentId = 'mcp-agent') => (await client.delete(`/plans/${planId}/nodes/${nodeId}/claim`, { data: { agent_id: agentId } })).data,
|
|
813
|
+
getTaskClaim: async (planId, nodeId) => (await client.get(`/plans/${planId}/nodes/${nodeId}/claim`)).data,
|
|
814
|
+
},
|
|
815
|
+
comments: {
|
|
816
|
+
getComments: async (planId, nodeId) => (await client.get(`/plans/${planId}/nodes/${nodeId}/comments`)).data,
|
|
817
|
+
addComment: async (planId, nodeId, data) => (await client.post(`/plans/${planId}/nodes/${nodeId}/comments`, data)).data,
|
|
818
|
+
},
|
|
819
|
+
logs: {
|
|
820
|
+
getLogs: async (planId, nodeId) => (await client.get(`/plans/${planId}/nodes/${nodeId}/logs`)).data,
|
|
821
|
+
addLogEntry: async (planId, nodeId, data) => (await client.post(`/plans/${planId}/nodes/${nodeId}/log`, data)).data,
|
|
822
|
+
},
|
|
823
|
+
activity: {
|
|
824
|
+
getPlanActivity: async (planId) => (await client.get(`/activity/plans/${planId}/activity`)).data,
|
|
825
|
+
getGlobalActivity: async () => (await client.get('/activity/feed')).data,
|
|
826
|
+
},
|
|
827
|
+
search: {
|
|
828
|
+
searchPlan: async (planId, query) => {
|
|
829
|
+
try {
|
|
830
|
+
return (await client.get(`/search/plan/${planId}`, { params: { query } })).data;
|
|
831
|
+
} catch (error) {
|
|
832
|
+
return { results: [], count: 0, query };
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
globalSearch: async (query) => {
|
|
836
|
+
try {
|
|
837
|
+
return (await client.get('/search', { params: { query } })).data;
|
|
838
|
+
} catch (error) {
|
|
839
|
+
return { results: [], count: 0, query };
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
},
|
|
843
|
+
tokens: {
|
|
844
|
+
getTokens: async () => (await client.get('/auth/token')).data,
|
|
845
|
+
createToken: async (data) => (await client.post('/auth/token', data)).data,
|
|
846
|
+
revokeToken: async (tokenId) => await client.delete(`/auth/token/${tokenId}`),
|
|
847
|
+
},
|
|
848
|
+
organizations: {
|
|
849
|
+
list: async () => { const r = await client.get('/organizations'); return r.data.organizations || r.data; },
|
|
850
|
+
get: async (orgId) => (await client.get(`/organizations/${orgId}`)).data,
|
|
851
|
+
create: async (data) => (await client.post('/organizations', data)).data,
|
|
852
|
+
update: async (orgId, data) => (await client.put(`/organizations/${orgId}`, data)).data,
|
|
853
|
+
delete: async (orgId) => (await client.delete(`/organizations/${orgId}`)).data,
|
|
854
|
+
listMembers: async (orgId) => { const r = await client.get(`/organizations/${orgId}/members`); return r.data.members || r.data; },
|
|
855
|
+
addMember: async (orgId, data) => (await client.post(`/organizations/${orgId}/members`, data)).data,
|
|
856
|
+
removeMember: async (orgId, memberId) => (await client.delete(`/organizations/${orgId}/members/${memberId}`)).data,
|
|
857
|
+
},
|
|
858
|
+
goals: {
|
|
859
|
+
list: async (filters = {}) => {
|
|
860
|
+
const params = new URLSearchParams();
|
|
861
|
+
if (filters.organization_id) params.append('organization_id', filters.organization_id);
|
|
862
|
+
if (filters.status) params.append('status', filters.status);
|
|
863
|
+
const r = await client.get(`/goals?${params.toString()}`);
|
|
864
|
+
return r.data.goals || r.data;
|
|
865
|
+
},
|
|
866
|
+
get: async (goalId) => (await client.get(`/goals/${goalId}`)).data,
|
|
867
|
+
create: async (data) => (await client.post('/goals', data)).data,
|
|
868
|
+
update: async (goalId, data) => (await client.put(`/goals/${goalId}`, data)).data,
|
|
869
|
+
updateMetrics: async (goalId, metrics) => (await client.put(`/goals/${goalId}/metrics`, { metrics })).data,
|
|
870
|
+
delete: async (goalId) => (await client.delete(`/goals/${goalId}`)).data,
|
|
871
|
+
linkPlan: async (goalId, planId) => (await client.post(`/goals/${goalId}/plans/${planId}`)).data,
|
|
872
|
+
unlinkPlan: async (goalId, planId) => (await client.delete(`/goals/${goalId}/plans/${planId}`)).data,
|
|
873
|
+
getPath: async (goalId, maxDepth) => { const p = maxDepth ? `?max_depth=${maxDepth}` : ''; return (await client.get(`/goals/v2/${goalId}/path${p}`)).data; },
|
|
874
|
+
getProgress: async (goalId) => (await client.get(`/goals/v2/${goalId}/progress`)).data,
|
|
875
|
+
listAchievers: async (goalId) => (await client.get(`/goals/v2/${goalId}/achievers`)).data,
|
|
876
|
+
addAchiever: async (goalId, sourceNodeId, weight) => (await client.post(`/goals/v2/${goalId}/achievers`, { source_node_id: sourceNodeId, weight: weight ?? 1 })).data,
|
|
877
|
+
removeAchiever: async (goalId, depId) => (await client.delete(`/goals/v2/${goalId}/achievers/${depId}`)).data,
|
|
878
|
+
getKnowledgeGaps: async (goalId) => (await client.get(`/goals/v2/${goalId}/knowledge-gaps`)).data,
|
|
879
|
+
getDashboard: async () => (await client.get('/goals/v2/dashboard')).data,
|
|
880
|
+
},
|
|
881
|
+
context: {
|
|
882
|
+
getNodeContext: async (nodeId, options = {}) => {
|
|
883
|
+
const params = new URLSearchParams({ node_id: nodeId });
|
|
884
|
+
if (options.include_knowledge !== undefined) params.append('include_knowledge', options.include_knowledge);
|
|
885
|
+
if (options.include_siblings !== undefined) params.append('include_siblings', options.include_siblings);
|
|
886
|
+
return (await client.get(`/context?${params.toString()}`)).data;
|
|
887
|
+
},
|
|
888
|
+
getPlanContext: async (planId, options = {}) => {
|
|
889
|
+
const params = new URLSearchParams({ plan_id: planId });
|
|
890
|
+
if (options.include_knowledge !== undefined) params.append('include_knowledge', options.include_knowledge);
|
|
891
|
+
return (await client.get(`/context/plan?${params.toString()}`)).data;
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
graphiti: {
|
|
895
|
+
getStatus: async () => (await client.get('/knowledge/graphiti/status')).data,
|
|
896
|
+
addEpisode: async (data) => (await client.post('/knowledge/episodes', data)).data,
|
|
897
|
+
graphSearch: async (data) => (await client.post('/knowledge/graph-search', data)).data,
|
|
898
|
+
searchEntities: async (data) => (await client.post('/knowledge/entities', data)).data,
|
|
899
|
+
detectContradictions: async (data) => (await client.post('/knowledge/contradictions', data)).data,
|
|
900
|
+
getEpisodes: async ({ max_episodes = 20 } = {}) => (await client.get('/knowledge/episodes', { params: { max_episodes } })).data,
|
|
901
|
+
deleteEpisode: async (episodeId) => (await client.delete(`/knowledge/episodes/${episodeId}`)).data,
|
|
902
|
+
},
|
|
903
|
+
dependencies: {
|
|
904
|
+
createCrossPlan: async (data) => (await client.post('/dependencies/cross-plan', data)).data,
|
|
905
|
+
listCrossPlan: async (planIds) => (await client.get('/dependencies/cross-plan', { params: { plan_ids: planIds.join(',') } })).data,
|
|
906
|
+
createExternal: async (data) => (await client.post('/dependencies/external', data)).data,
|
|
907
|
+
},
|
|
908
|
+
axiosInstance: client,
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
|
|
526
912
|
// Export API client functions
|
|
527
913
|
// Export the axios instance for direct use
|
|
528
914
|
const axiosInstance = apiClient;
|
|
@@ -532,9 +918,14 @@ module.exports = {
|
|
|
532
918
|
nodes,
|
|
533
919
|
comments,
|
|
534
920
|
logs,
|
|
535
|
-
artifacts,
|
|
536
921
|
activity,
|
|
537
922
|
search,
|
|
538
923
|
tokens,
|
|
539
|
-
|
|
924
|
+
organizations,
|
|
925
|
+
goals,
|
|
926
|
+
context,
|
|
927
|
+
graphiti,
|
|
928
|
+
dependencies,
|
|
929
|
+
axiosInstance, // Export for direct API calls
|
|
930
|
+
createApiClient // Factory for per-session clients (HTTP mode)
|
|
540
931
|
};
|