@inferencesh/sdk 0.6.10 → 0.6.12
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/README.md +1 -1
- package/dist/agent/actions.js +3 -3
- package/dist/agent/actions.test.js +6 -0
- package/dist/api/agents.d.ts +10 -0
- package/dist/api/agents.js +17 -3
- package/dist/api/agents.test.js +215 -0
- package/dist/api/api-keys.d.ts +24 -0
- package/dist/api/api-keys.js +26 -0
- package/dist/api/api-keys.test.d.ts +1 -0
- package/dist/api/api-keys.test.js +44 -0
- package/dist/api/apps.js +1 -1
- package/dist/api/apps.test.js +71 -3
- package/dist/api/chats.d.ts +14 -0
- package/dist/api/chats.js +18 -0
- package/dist/api/chats.test.js +52 -0
- package/dist/api/engines.d.ts +12 -0
- package/dist/api/engines.js +18 -0
- package/dist/api/engines.test.js +78 -0
- package/dist/api/files.test.js +183 -0
- package/dist/api/flow-runs.test.js +42 -0
- package/dist/api/flows.d.ts +4 -0
- package/dist/api/flows.js +6 -0
- package/dist/api/flows.test.js +75 -0
- package/dist/api/integrations.d.ts +41 -0
- package/dist/api/integrations.js +56 -0
- package/dist/api/integrations.test.d.ts +1 -0
- package/dist/api/integrations.test.js +109 -0
- package/dist/api/knowledge.d.ts +112 -0
- package/dist/api/knowledge.js +163 -0
- package/dist/api/knowledge.test.d.ts +1 -0
- package/dist/api/knowledge.test.js +94 -0
- package/dist/api/mcp-servers.d.ts +45 -0
- package/dist/api/mcp-servers.js +62 -0
- package/dist/api/mcp-servers.test.d.ts +1 -0
- package/dist/api/mcp-servers.test.js +64 -0
- package/dist/api/projects.d.ts +29 -0
- package/dist/api/projects.js +38 -0
- package/dist/api/projects.test.d.ts +1 -0
- package/dist/api/projects.test.js +52 -0
- package/dist/api/search.d.ts +21 -0
- package/dist/api/search.js +20 -0
- package/dist/api/search.test.d.ts +1 -0
- package/dist/api/search.test.js +39 -0
- package/dist/api/secrets.d.ts +29 -0
- package/dist/api/secrets.js +38 -0
- package/dist/api/secrets.test.d.ts +1 -0
- package/dist/api/secrets.test.js +61 -0
- package/dist/api/tasks.d.ts +13 -1
- package/dist/api/tasks.js +18 -0
- package/dist/api/tasks.test.js +134 -0
- package/dist/api/teams.d.ts +71 -0
- package/dist/api/teams.js +92 -0
- package/dist/api/teams.test.d.ts +1 -0
- package/dist/api/teams.test.js +79 -0
- package/dist/http/client.d.ts +5 -0
- package/dist/http/client.js +42 -23
- package/dist/http/client.test.js +245 -0
- package/dist/http/errors.test.js +13 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +25 -0
- package/dist/tool-builder.test.js +11 -1
- package/dist/types.d.ts +110 -5
- package/dist/types.js +58 -2
- package/package.json +4 -4
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { IntegrationsAPI } from './integrations';
|
|
3
|
+
import { IntegrationProviderGoogleSA } from '../types';
|
|
4
|
+
const mockFetch = jest.fn();
|
|
5
|
+
global.fetch = mockFetch;
|
|
6
|
+
function mockJsonResponse(body) {
|
|
7
|
+
mockFetch.mockResolvedValueOnce({
|
|
8
|
+
ok: true,
|
|
9
|
+
status: 200,
|
|
10
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
describe('IntegrationsAPI', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
const api = () => new IntegrationsAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
18
|
+
it('should POST /integrations/list for list()', async () => {
|
|
19
|
+
const page = { items: [{ provider: 'slack' }], next_cursor: null };
|
|
20
|
+
mockJsonResponse(page);
|
|
21
|
+
const result = await api().list();
|
|
22
|
+
expect(result).toEqual(page);
|
|
23
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
24
|
+
expect(url).toContain('/integrations/list');
|
|
25
|
+
expect(init.method).toBe('POST');
|
|
26
|
+
});
|
|
27
|
+
it('should GET /integrations/available for listAvailable()', async () => {
|
|
28
|
+
const available = [{ provider: 'github' }];
|
|
29
|
+
mockJsonResponse(available);
|
|
30
|
+
const result = await api().listAvailable();
|
|
31
|
+
expect(result).toEqual(available);
|
|
32
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
33
|
+
expect(url).toContain('/integrations/available');
|
|
34
|
+
expect(init.method).toBe('GET');
|
|
35
|
+
});
|
|
36
|
+
it('should POST /integrations for connect()', async () => {
|
|
37
|
+
const payload = { provider: 'slack', config: { token: 'xoxb-123' } };
|
|
38
|
+
const response = { integration: { provider: 'slack' }, redirect_url: null };
|
|
39
|
+
mockJsonResponse(response);
|
|
40
|
+
const result = await api().connect(payload);
|
|
41
|
+
expect(result).toEqual(response);
|
|
42
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
43
|
+
expect(url).toContain('/integrations');
|
|
44
|
+
expect(init.method).toBe('POST');
|
|
45
|
+
expect(JSON.parse(init.body)).toEqual(payload);
|
|
46
|
+
});
|
|
47
|
+
it('should GET /integrations/{provider} for get()', async () => {
|
|
48
|
+
const integration = { provider: 'slack', status: 'connected' };
|
|
49
|
+
mockJsonResponse(integration);
|
|
50
|
+
const result = await api().get('slack');
|
|
51
|
+
expect(result).toEqual(integration);
|
|
52
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
53
|
+
expect(url).toContain('/integrations/slack');
|
|
54
|
+
expect(init.method).toBe('GET');
|
|
55
|
+
});
|
|
56
|
+
it('should DELETE /integrations/{provider} for disconnect()', async () => {
|
|
57
|
+
mockJsonResponse(null);
|
|
58
|
+
await api().disconnect('slack');
|
|
59
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
60
|
+
expect(url).toContain('/integrations/slack');
|
|
61
|
+
expect(init.method).toBe('DELETE');
|
|
62
|
+
});
|
|
63
|
+
it('should GET /integrations/configs for getConfigs()', async () => {
|
|
64
|
+
const configs = [{ provider: 'github', scopes: ['repo'] }];
|
|
65
|
+
mockJsonResponse(configs);
|
|
66
|
+
const result = await api().getConfigs();
|
|
67
|
+
expect(result).toEqual(configs);
|
|
68
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
69
|
+
expect(url).toContain('/integrations/configs');
|
|
70
|
+
expect(init.method).toBe('GET');
|
|
71
|
+
});
|
|
72
|
+
it('should GET /integrations/capabilities for getCapabilities()', async () => {
|
|
73
|
+
const capabilities = { slack: ['post_message'] };
|
|
74
|
+
mockJsonResponse(capabilities);
|
|
75
|
+
const result = await api().getCapabilities();
|
|
76
|
+
expect(result).toEqual(capabilities);
|
|
77
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
78
|
+
expect(url).toContain('/integrations/capabilities');
|
|
79
|
+
expect(init.method).toBe('GET');
|
|
80
|
+
});
|
|
81
|
+
it('should POST typed integration requirements with secrets and scopes for checkRequirements()', async () => {
|
|
82
|
+
const payload = {
|
|
83
|
+
integrations: [
|
|
84
|
+
{
|
|
85
|
+
key: IntegrationProviderGoogleSA,
|
|
86
|
+
secrets: ['GOOGLE_SA_JSON'],
|
|
87
|
+
scopes: ['https://www.googleapis.com/auth/calendar'],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
const response = {
|
|
92
|
+
satisfied: false,
|
|
93
|
+
errors: [
|
|
94
|
+
{
|
|
95
|
+
type: 'scope',
|
|
96
|
+
message: 'Missing calendar scope',
|
|
97
|
+
action: { type: 'add_scopes', provider: IntegrationProviderGoogleSA, scopes: ['https://www.googleapis.com/auth/calendar'] },
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
mockJsonResponse(response);
|
|
102
|
+
const result = await api().checkRequirements(payload);
|
|
103
|
+
expect(result).toEqual(response);
|
|
104
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
105
|
+
expect(url).toContain('/integrations/check');
|
|
106
|
+
expect(init.method).toBe('POST');
|
|
107
|
+
expect(JSON.parse(init.body)).toEqual(payload);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { KnowledgeDTO, KnowledgeVersionDTO, KnowledgeCreateRequest, SkillDTO, SkillVersionDTO, CursorListRequest, CursorListResponse, PublicSkillStoreDTO } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Knowledge API
|
|
5
|
+
*/
|
|
6
|
+
export declare class KnowledgeAPI {
|
|
7
|
+
private readonly http;
|
|
8
|
+
constructor(http: HttpClient);
|
|
9
|
+
/**
|
|
10
|
+
* List knowledge entries with cursor-based pagination
|
|
11
|
+
*/
|
|
12
|
+
list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<KnowledgeDTO>>;
|
|
13
|
+
/**
|
|
14
|
+
* Get a knowledge entry by ID
|
|
15
|
+
*/
|
|
16
|
+
get(id: string): Promise<KnowledgeDTO>;
|
|
17
|
+
/**
|
|
18
|
+
* Get a knowledge entry by namespace/name
|
|
19
|
+
*/
|
|
20
|
+
getByName(namespace: string, name: string): Promise<KnowledgeDTO>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a knowledge entry
|
|
23
|
+
*/
|
|
24
|
+
create(data: KnowledgeCreateRequest): Promise<KnowledgeDTO>;
|
|
25
|
+
/**
|
|
26
|
+
* Update a knowledge entry
|
|
27
|
+
*/
|
|
28
|
+
update(id: string, data: Partial<KnowledgeDTO>): Promise<KnowledgeDTO>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete a knowledge entry
|
|
31
|
+
*/
|
|
32
|
+
delete(id: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* List knowledge versions
|
|
35
|
+
*/
|
|
36
|
+
listVersions(id: string, params?: Partial<CursorListRequest>): Promise<CursorListResponse<KnowledgeVersionDTO>>;
|
|
37
|
+
/**
|
|
38
|
+
* Get a specific version
|
|
39
|
+
*/
|
|
40
|
+
getVersion(id: string, versionId: string): Promise<KnowledgeVersionDTO>;
|
|
41
|
+
/**
|
|
42
|
+
* Transfer ownership
|
|
43
|
+
*/
|
|
44
|
+
transferOwnership(id: string, newTeamId: string): Promise<KnowledgeDTO>;
|
|
45
|
+
/**
|
|
46
|
+
* Update visibility
|
|
47
|
+
*/
|
|
48
|
+
updateVisibility(id: string, visibility: string): Promise<KnowledgeDTO>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Skills API
|
|
52
|
+
*/
|
|
53
|
+
export declare class SkillsAPI {
|
|
54
|
+
private readonly http;
|
|
55
|
+
constructor(http: HttpClient);
|
|
56
|
+
/**
|
|
57
|
+
* List skills with cursor-based pagination
|
|
58
|
+
*/
|
|
59
|
+
list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<SkillDTO>>;
|
|
60
|
+
/**
|
|
61
|
+
* Get a skill by ID
|
|
62
|
+
*/
|
|
63
|
+
get(id: string): Promise<SkillDTO>;
|
|
64
|
+
/**
|
|
65
|
+
* Get a skill by namespace/name
|
|
66
|
+
*/
|
|
67
|
+
getByName(namespace: string, name: string): Promise<SkillDTO>;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve a skill (store + GitHub fallback)
|
|
70
|
+
*/
|
|
71
|
+
resolve(ref: string, skill?: string): Promise<unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Create/publish a skill
|
|
74
|
+
*/
|
|
75
|
+
create(data: Partial<SkillDTO>): Promise<SkillDTO>;
|
|
76
|
+
/**
|
|
77
|
+
* Update a skill
|
|
78
|
+
*/
|
|
79
|
+
update(id: string, data: Partial<SkillDTO>): Promise<SkillDTO>;
|
|
80
|
+
/**
|
|
81
|
+
* Delete a skill
|
|
82
|
+
*/
|
|
83
|
+
delete(id: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* List skill versions
|
|
86
|
+
*/
|
|
87
|
+
listVersions(id: string, params?: Partial<CursorListRequest>): Promise<CursorListResponse<SkillVersionDTO>>;
|
|
88
|
+
/**
|
|
89
|
+
* Get a specific skill version
|
|
90
|
+
*/
|
|
91
|
+
getVersion(id: string, versionId: string): Promise<SkillVersionDTO>;
|
|
92
|
+
/**
|
|
93
|
+
* Download a skill
|
|
94
|
+
*/
|
|
95
|
+
download(namespace: string, name: string): Promise<unknown>;
|
|
96
|
+
/**
|
|
97
|
+
* Get skill content
|
|
98
|
+
*/
|
|
99
|
+
getContent(namespace: string, name: string): Promise<unknown>;
|
|
100
|
+
/**
|
|
101
|
+
* Transfer ownership
|
|
102
|
+
*/
|
|
103
|
+
transferOwnership(id: string, newTeamId: string): Promise<SkillDTO>;
|
|
104
|
+
/**
|
|
105
|
+
* Update visibility
|
|
106
|
+
*/
|
|
107
|
+
updateVisibility(id: string, visibility: string): Promise<SkillDTO>;
|
|
108
|
+
/**
|
|
109
|
+
* List skills in the public store
|
|
110
|
+
*/
|
|
111
|
+
listStore(params?: Partial<CursorListRequest>): Promise<CursorListResponse<PublicSkillStoreDTO>>;
|
|
112
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge API
|
|
3
|
+
*/
|
|
4
|
+
export class KnowledgeAPI {
|
|
5
|
+
constructor(http) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* List knowledge entries with cursor-based pagination
|
|
10
|
+
*/
|
|
11
|
+
async list(params) {
|
|
12
|
+
return this.http.request('post', '/knowledge/list', { data: params });
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get a knowledge entry by ID
|
|
16
|
+
*/
|
|
17
|
+
async get(id) {
|
|
18
|
+
return this.http.request('get', `/knowledge/${id}`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get a knowledge entry by namespace/name
|
|
22
|
+
*/
|
|
23
|
+
async getByName(namespace, name) {
|
|
24
|
+
return this.http.request('get', `/knowledge/${namespace}/${name}`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a knowledge entry
|
|
28
|
+
*/
|
|
29
|
+
async create(data) {
|
|
30
|
+
return this.http.request('post', '/knowledge', { data });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Update a knowledge entry
|
|
34
|
+
*/
|
|
35
|
+
async update(id, data) {
|
|
36
|
+
return this.http.request('post', `/knowledge/${id}`, { data });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Delete a knowledge entry
|
|
40
|
+
*/
|
|
41
|
+
async delete(id) {
|
|
42
|
+
return this.http.request('delete', `/knowledge/${id}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* List knowledge versions
|
|
46
|
+
*/
|
|
47
|
+
async listVersions(id, params) {
|
|
48
|
+
return this.http.request('post', `/knowledge/${id}/versions/list`, { data: params });
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get a specific version
|
|
52
|
+
*/
|
|
53
|
+
async getVersion(id, versionId) {
|
|
54
|
+
return this.http.request('get', `/knowledge/${id}/versions/${versionId}`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Transfer ownership
|
|
58
|
+
*/
|
|
59
|
+
async transferOwnership(id, newTeamId) {
|
|
60
|
+
return this.http.request('post', `/knowledge/${id}/transfer`, { data: { team_id: newTeamId } });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Update visibility
|
|
64
|
+
*/
|
|
65
|
+
async updateVisibility(id, visibility) {
|
|
66
|
+
return this.http.request('post', `/knowledge/${id}/visibility`, { data: { visibility } });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Skills API
|
|
71
|
+
*/
|
|
72
|
+
export class SkillsAPI {
|
|
73
|
+
constructor(http) {
|
|
74
|
+
this.http = http;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* List skills with cursor-based pagination
|
|
78
|
+
*/
|
|
79
|
+
async list(params) {
|
|
80
|
+
return this.http.request('post', '/skills/list', { data: params });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get a skill by ID
|
|
84
|
+
*/
|
|
85
|
+
async get(id) {
|
|
86
|
+
return this.http.request('get', `/skills/${id}`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get a skill by namespace/name
|
|
90
|
+
*/
|
|
91
|
+
async getByName(namespace, name) {
|
|
92
|
+
return this.http.request('get', `/skills/${namespace}/${name}`);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolve a skill (store + GitHub fallback)
|
|
96
|
+
*/
|
|
97
|
+
async resolve(ref, skill) {
|
|
98
|
+
const params = { ref };
|
|
99
|
+
if (skill)
|
|
100
|
+
params.skill = skill;
|
|
101
|
+
return this.http.request('get', '/skills/resolve', { params });
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Create/publish a skill
|
|
105
|
+
*/
|
|
106
|
+
async create(data) {
|
|
107
|
+
return this.http.request('post', '/skills', { data });
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Update a skill
|
|
111
|
+
*/
|
|
112
|
+
async update(id, data) {
|
|
113
|
+
return this.http.request('post', `/skills/${id}`, { data });
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Delete a skill
|
|
117
|
+
*/
|
|
118
|
+
async delete(id) {
|
|
119
|
+
return this.http.request('delete', `/skills/${id}`);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* List skill versions
|
|
123
|
+
*/
|
|
124
|
+
async listVersions(id, params) {
|
|
125
|
+
return this.http.request('post', `/skills/${id}/versions/list`, { data: params });
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get a specific skill version
|
|
129
|
+
*/
|
|
130
|
+
async getVersion(id, versionId) {
|
|
131
|
+
return this.http.request('get', `/skills/${id}/versions/${versionId}`);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Download a skill
|
|
135
|
+
*/
|
|
136
|
+
async download(namespace, name) {
|
|
137
|
+
return this.http.request('get', `/skills/${namespace}/${name}/download`);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get skill content
|
|
141
|
+
*/
|
|
142
|
+
async getContent(namespace, name) {
|
|
143
|
+
return this.http.request('get', `/skills/${namespace}/${name}/content`);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Transfer ownership
|
|
147
|
+
*/
|
|
148
|
+
async transferOwnership(id, newTeamId) {
|
|
149
|
+
return this.http.request('post', `/skills/${id}/transfer`, { data: { team_id: newTeamId } });
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Update visibility
|
|
153
|
+
*/
|
|
154
|
+
async updateVisibility(id, visibility) {
|
|
155
|
+
return this.http.request('post', `/skills/${id}/visibility`, { data: { visibility } });
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* List skills in the public store
|
|
159
|
+
*/
|
|
160
|
+
async listStore(params) {
|
|
161
|
+
return this.http.request('post', '/store/skills/list', { data: params });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { KnowledgeAPI, SkillsAPI } from './knowledge';
|
|
3
|
+
const mockFetch = jest.fn();
|
|
4
|
+
global.fetch = mockFetch;
|
|
5
|
+
function mockJsonResponse(body) {
|
|
6
|
+
mockFetch.mockResolvedValueOnce({
|
|
7
|
+
ok: true,
|
|
8
|
+
status: 200,
|
|
9
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
describe('KnowledgeAPI', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
const api = () => new KnowledgeAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
17
|
+
it('should POST /knowledge/list for list()', async () => {
|
|
18
|
+
const page = { items: [{ id: 'know-1' }], next_cursor: null };
|
|
19
|
+
mockJsonResponse(page);
|
|
20
|
+
const result = await api().list();
|
|
21
|
+
expect(result).toEqual(page);
|
|
22
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
23
|
+
expect(url).toContain('/knowledge/list');
|
|
24
|
+
expect(init.method).toBe('POST');
|
|
25
|
+
});
|
|
26
|
+
it('should GET /knowledge/{namespace}/{name} for getByName()', async () => {
|
|
27
|
+
const entry = { id: 'know-1', namespace: 'acme', name: 'docs' };
|
|
28
|
+
mockJsonResponse(entry);
|
|
29
|
+
const result = await api().getByName('acme', 'docs');
|
|
30
|
+
expect(result).toEqual(entry);
|
|
31
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
32
|
+
expect(url).toContain('/knowledge/acme/docs');
|
|
33
|
+
expect(init.method).toBe('GET');
|
|
34
|
+
});
|
|
35
|
+
it('should POST /knowledge for create()', async () => {
|
|
36
|
+
const payload = { namespace: 'acme', name: 'docs', content: 'hello' };
|
|
37
|
+
const entry = { id: 'know-new', ...payload };
|
|
38
|
+
mockJsonResponse(entry);
|
|
39
|
+
const result = await api().create(payload);
|
|
40
|
+
expect(result).toEqual(entry);
|
|
41
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
42
|
+
expect(url).toContain('/knowledge');
|
|
43
|
+
expect(init.method).toBe('POST');
|
|
44
|
+
});
|
|
45
|
+
it('should POST team_id for transferOwnership()', async () => {
|
|
46
|
+
const entry = { id: 'know-1' };
|
|
47
|
+
mockJsonResponse(entry);
|
|
48
|
+
await api().transferOwnership('know-1', 'team-5');
|
|
49
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
50
|
+
expect(url).toContain('/knowledge/know-1/transfer');
|
|
51
|
+
expect(JSON.parse(init.body)).toEqual({ team_id: 'team-5' });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('SkillsAPI', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
jest.clearAllMocks();
|
|
57
|
+
});
|
|
58
|
+
const api = () => new SkillsAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
59
|
+
it('should GET /skills/resolve with ref param for resolve()', async () => {
|
|
60
|
+
const resolved = { ref: 'acme/skill@v1', content: '{}' };
|
|
61
|
+
mockJsonResponse(resolved);
|
|
62
|
+
const result = await api().resolve('acme/skill@v1', 'main');
|
|
63
|
+
expect(result).toEqual(resolved);
|
|
64
|
+
const [url] = mockFetch.mock.calls[0];
|
|
65
|
+
expect(url).toContain('/skills/resolve');
|
|
66
|
+
expect(url).toContain('ref=acme');
|
|
67
|
+
expect(url).toContain('skill=main');
|
|
68
|
+
});
|
|
69
|
+
it('should GET /skills/{namespace}/{name} for getByName()', async () => {
|
|
70
|
+
const skill = { id: 'skill-1', namespace: 'acme', name: 'research' };
|
|
71
|
+
mockJsonResponse(skill);
|
|
72
|
+
const result = await api().getByName('acme', 'research');
|
|
73
|
+
expect(result).toEqual(skill);
|
|
74
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
75
|
+
expect(url).toContain('/skills/acme/research');
|
|
76
|
+
expect(init.method).toBe('GET');
|
|
77
|
+
});
|
|
78
|
+
it('should GET /skills/{namespace}/{name}/download for download()', async () => {
|
|
79
|
+
mockJsonResponse({ url: 'https://cdn.example.com/skill.zip' });
|
|
80
|
+
await api().download('acme', 'research');
|
|
81
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
82
|
+
expect(url).toContain('/skills/acme/research/download');
|
|
83
|
+
expect(init.method).toBe('GET');
|
|
84
|
+
});
|
|
85
|
+
it('should POST /store/skills/list for listStore()', async () => {
|
|
86
|
+
const page = { items: [{ namespace: 'public', name: 'starter' }], next_cursor: null };
|
|
87
|
+
mockJsonResponse(page);
|
|
88
|
+
const result = await api().listStore();
|
|
89
|
+
expect(result).toEqual(page);
|
|
90
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
91
|
+
expect(url).toContain('/store/skills/list');
|
|
92
|
+
expect(init.method).toBe('POST');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { MCPServerDTO, CursorListRequest, CursorListResponse } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* MCP Servers API
|
|
5
|
+
*/
|
|
6
|
+
export declare class MCPServersAPI {
|
|
7
|
+
private readonly http;
|
|
8
|
+
constructor(http: HttpClient);
|
|
9
|
+
/**
|
|
10
|
+
* List public MCP servers
|
|
11
|
+
*/
|
|
12
|
+
list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<MCPServerDTO>>;
|
|
13
|
+
/**
|
|
14
|
+
* Get an MCP server by slug
|
|
15
|
+
*/
|
|
16
|
+
get(slug: string): Promise<MCPServerDTO>;
|
|
17
|
+
/**
|
|
18
|
+
* List tools for an MCP server
|
|
19
|
+
*/
|
|
20
|
+
listTools(slug: string): Promise<unknown[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Call a tool on an MCP server
|
|
23
|
+
*/
|
|
24
|
+
callTool(slug: string, tool: string, input: unknown): Promise<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* List user's own MCP servers
|
|
27
|
+
*/
|
|
28
|
+
listOwned(params?: Partial<CursorListRequest>): Promise<CursorListResponse<MCPServerDTO>>;
|
|
29
|
+
/**
|
|
30
|
+
* Get a user's MCP server by ID
|
|
31
|
+
*/
|
|
32
|
+
getOwned(id: string): Promise<MCPServerDTO>;
|
|
33
|
+
/**
|
|
34
|
+
* Create an MCP server
|
|
35
|
+
*/
|
|
36
|
+
create(data: Partial<MCPServerDTO>): Promise<MCPServerDTO>;
|
|
37
|
+
/**
|
|
38
|
+
* Update an MCP server
|
|
39
|
+
*/
|
|
40
|
+
update(id: string, data: Partial<MCPServerDTO>): Promise<MCPServerDTO>;
|
|
41
|
+
/**
|
|
42
|
+
* Delete an MCP server
|
|
43
|
+
*/
|
|
44
|
+
delete(id: string): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Servers API
|
|
3
|
+
*/
|
|
4
|
+
export class MCPServersAPI {
|
|
5
|
+
constructor(http) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* List public MCP servers
|
|
10
|
+
*/
|
|
11
|
+
async list(params) {
|
|
12
|
+
return this.http.request('post', '/mcps/list', { data: params });
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get an MCP server by slug
|
|
16
|
+
*/
|
|
17
|
+
async get(slug) {
|
|
18
|
+
return this.http.request('get', `/mcps/${slug}`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* List tools for an MCP server
|
|
22
|
+
*/
|
|
23
|
+
async listTools(slug) {
|
|
24
|
+
return this.http.request('get', `/mcps/${slug}/tools`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Call a tool on an MCP server
|
|
28
|
+
*/
|
|
29
|
+
async callTool(slug, tool, input) {
|
|
30
|
+
return this.http.request('post', `/mcps/${slug}/tools/${tool}`, { data: input });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* List user's own MCP servers
|
|
34
|
+
*/
|
|
35
|
+
async listOwned(params) {
|
|
36
|
+
return this.http.request('post', '/mcp-servers/list', { data: params });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get a user's MCP server by ID
|
|
40
|
+
*/
|
|
41
|
+
async getOwned(id) {
|
|
42
|
+
return this.http.request('get', `/mcp-servers/${id}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create an MCP server
|
|
46
|
+
*/
|
|
47
|
+
async create(data) {
|
|
48
|
+
return this.http.request('post', '/mcp-servers', { data });
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Update an MCP server
|
|
52
|
+
*/
|
|
53
|
+
async update(id, data) {
|
|
54
|
+
return this.http.request('put', `/mcp-servers/${id}`, { data });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Delete an MCP server
|
|
58
|
+
*/
|
|
59
|
+
async delete(id) {
|
|
60
|
+
return this.http.request('delete', `/mcp-servers/${id}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { MCPServersAPI } from './mcp-servers';
|
|
3
|
+
const mockFetch = jest.fn();
|
|
4
|
+
global.fetch = mockFetch;
|
|
5
|
+
function mockJsonResponse(body) {
|
|
6
|
+
mockFetch.mockResolvedValueOnce({
|
|
7
|
+
ok: true,
|
|
8
|
+
status: 200,
|
|
9
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
describe('MCPServersAPI', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
const api = () => new MCPServersAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
17
|
+
it('should POST /mcps/list for list()', async () => {
|
|
18
|
+
const page = { items: [{ slug: 'filesystem' }], next_cursor: null };
|
|
19
|
+
mockJsonResponse(page);
|
|
20
|
+
const result = await api().list();
|
|
21
|
+
expect(result).toEqual(page);
|
|
22
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
23
|
+
expect(url).toContain('/mcps/list');
|
|
24
|
+
expect(init.method).toBe('POST');
|
|
25
|
+
});
|
|
26
|
+
it('should GET /mcps/{slug}/tools for listTools()', async () => {
|
|
27
|
+
const tools = [{ name: 'read_file' }];
|
|
28
|
+
mockJsonResponse(tools);
|
|
29
|
+
const result = await api().listTools('filesystem');
|
|
30
|
+
expect(result).toEqual(tools);
|
|
31
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
32
|
+
expect(url).toContain('/mcps/filesystem/tools');
|
|
33
|
+
expect(init.method).toBe('GET');
|
|
34
|
+
});
|
|
35
|
+
it('should POST /mcps/{slug}/tools/{tool} for callTool()', async () => {
|
|
36
|
+
const input = { path: '/tmp/test.txt' };
|
|
37
|
+
const output = { content: 'hello' };
|
|
38
|
+
mockJsonResponse(output);
|
|
39
|
+
const result = await api().callTool('filesystem', 'read_file', input);
|
|
40
|
+
expect(result).toEqual(output);
|
|
41
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
42
|
+
expect(url).toContain('/mcps/filesystem/tools/read_file');
|
|
43
|
+
expect(init.method).toBe('POST');
|
|
44
|
+
expect(JSON.parse(init.body)).toEqual(input);
|
|
45
|
+
});
|
|
46
|
+
it('should POST /mcp-servers for create()', async () => {
|
|
47
|
+
const payload = { name: 'My MCP', slug: 'my-mcp' };
|
|
48
|
+
const server = { id: 'mcp-1', ...payload };
|
|
49
|
+
mockJsonResponse(server);
|
|
50
|
+
const result = await api().create(payload);
|
|
51
|
+
expect(result).toEqual(server);
|
|
52
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
53
|
+
expect(url).toContain('/mcp-servers');
|
|
54
|
+
expect(init.method).toBe('POST');
|
|
55
|
+
});
|
|
56
|
+
it('should PUT /mcp-servers/{id} for update()', async () => {
|
|
57
|
+
const server = { id: 'mcp-1', name: 'Updated MCP' };
|
|
58
|
+
mockJsonResponse(server);
|
|
59
|
+
await api().update('mcp-1', { name: 'Updated MCP' });
|
|
60
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
61
|
+
expect(url).toContain('/mcp-servers/mcp-1');
|
|
62
|
+
expect(init.method).toBe('PUT');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { HttpClient } from '../http/client';
|
|
2
|
+
import { ProjectDTO, CursorListRequest, CursorListResponse } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Projects API
|
|
5
|
+
*/
|
|
6
|
+
export declare class ProjectsAPI {
|
|
7
|
+
private readonly http;
|
|
8
|
+
constructor(http: HttpClient);
|
|
9
|
+
/**
|
|
10
|
+
* List projects with cursor-based pagination
|
|
11
|
+
*/
|
|
12
|
+
list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<ProjectDTO>>;
|
|
13
|
+
/**
|
|
14
|
+
* Get a project by ID
|
|
15
|
+
*/
|
|
16
|
+
get(id: string): Promise<ProjectDTO>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a project
|
|
19
|
+
*/
|
|
20
|
+
create(data: Partial<ProjectDTO>): Promise<ProjectDTO>;
|
|
21
|
+
/**
|
|
22
|
+
* Update a project
|
|
23
|
+
*/
|
|
24
|
+
update(id: string, data: Partial<ProjectDTO>): Promise<ProjectDTO>;
|
|
25
|
+
/**
|
|
26
|
+
* Delete a project
|
|
27
|
+
*/
|
|
28
|
+
delete(id: string): Promise<void>;
|
|
29
|
+
}
|