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/src/api-client.js CHANGED
@@ -26,23 +26,28 @@ const apiClient = axios.create({
26
26
  }
27
27
  });
28
28
 
29
- // Log API requests in debug mode
30
- apiClient.interceptors.request.use(request => {
31
- console.error(`API Request: ${request.method.toUpperCase()} ${request.url}`);
32
- return request;
33
- });
34
-
35
- // Log API responses in debug mode
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
- console.error(`API Response: ${response.status} ${response.statusText}`);
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, valid, and not revoked.');
44
- console.error('If you are still using the old API_TOKEN, please generate a USER_API_TOKEN from the agent-planner UI.');
45
- } else {
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 response = await apiClient.get(`/plans/${planId}/nodes`);
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/plan/${planId}`);
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('/tokens');
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('/tokens', tokenData);
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(`/tokens/${tokenId}`);
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
- axiosInstance // Export for direct API calls
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
  };