@skillsmith/mcp-server 0.4.11 → 0.4.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/CHANGELOG.md +4 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/__tests__/tool-dispatch.envelope.test.d.ts +12 -0
- package/dist/src/__tests__/tool-dispatch.envelope.test.d.ts.map +1 -0
- package/dist/src/__tests__/tool-dispatch.envelope.test.js +205 -0
- package/dist/src/__tests__/tool-dispatch.envelope.test.js.map +1 -0
- package/dist/src/index.js +10 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/middleware/license.d.ts +6 -6
- package/dist/src/middleware/license.d.ts.map +1 -1
- package/dist/src/middleware/license.js +11 -8
- package/dist/src/middleware/license.js.map +1 -1
- package/dist/src/tool-dispatch.d.ts.map +1 -1
- package/dist/src/tool-dispatch.js +58 -19
- package/dist/src/tool-dispatch.js.map +1 -1
- package/dist/src/tools/analytics.d.ts +8 -8
- package/dist/src/tools/audit-tools.d.ts +6 -6
- package/dist/src/tools/compliance-tools.d.ts +2 -2
- package/dist/src/tools/install.d.ts +9 -3
- package/dist/src/tools/install.d.ts.map +1 -1
- package/dist/src/tools/install.js +52 -11
- package/dist/src/tools/install.js.map +1 -1
- package/dist/src/tools/install.test.d.ts +17 -0
- package/dist/src/tools/install.test.d.ts.map +1 -0
- package/dist/src/tools/install.test.js +237 -0
- package/dist/src/tools/install.test.js.map +1 -0
- package/dist/src/tools/integration-tools.d.ts +8 -8
- package/dist/src/tools/publish.types.d.ts +2 -2
- package/dist/src/tools/rbac-tools.d.ts +4 -4
- package/dist/src/tools/recommend.types.d.ts +3 -3
- package/dist/src/tools/registry-tools.d.ts +6 -6
- package/dist/src/tools/registry-tools.d.ts.map +1 -1
- package/dist/src/tools/registry-tools.js +42 -4
- package/dist/src/tools/registry-tools.js.map +1 -1
- package/dist/src/tools/skill-diff.d.ts +2 -2
- package/dist/src/tools/sso-tools.d.ts +2 -2
- package/dist/src/tools/suggest.d.ts +4 -4
- package/dist/src/tools/team-resolver.d.ts +29 -0
- package/dist/src/tools/team-resolver.d.ts.map +1 -0
- package/dist/src/tools/team-resolver.js +46 -0
- package/dist/src/tools/team-resolver.js.map +1 -0
- package/dist/src/tools/team-resolver.test.d.ts +6 -0
- package/dist/src/tools/team-resolver.test.d.ts.map +1 -0
- package/dist/src/tools/team-resolver.test.js +73 -0
- package/dist/src/tools/team-resolver.test.js.map +1 -0
- package/dist/src/tools/team-workspace.d.ts +18 -4
- package/dist/src/tools/team-workspace.d.ts.map +1 -1
- package/dist/src/tools/team-workspace.js +149 -75
- package/dist/src/tools/team-workspace.js.map +1 -1
- package/dist/src/tools/team-workspace.live.d.ts +34 -0
- package/dist/src/tools/team-workspace.live.d.ts.map +1 -0
- package/dist/src/tools/team-workspace.live.js +182 -0
- package/dist/src/tools/team-workspace.live.js.map +1 -0
- package/dist/src/tools/team-workspace.live.test.d.ts +10 -0
- package/dist/src/tools/team-workspace.live.test.d.ts.map +1 -0
- package/dist/src/tools/team-workspace.live.test.js +177 -0
- package/dist/src/tools/team-workspace.live.test.js.map +1 -0
- package/dist/src/tools/team-workspace.stub.d.ts.map +1 -1
- package/dist/src/tools/team-workspace.stub.js +3 -1
- package/dist/src/tools/team-workspace.stub.js.map +1 -1
- package/dist/src/tools/team-workspace.test.d.ts +1 -0
- package/dist/src/tools/team-workspace.test.d.ts.map +1 -1
- package/dist/src/tools/team-workspace.test.js +43 -1
- package/dist/src/tools/team-workspace.test.js.map +1 -1
- package/dist/src/tools/uninstall.d.ts +1 -1
- package/dist/src/validation.d.ts +64 -0
- package/dist/src/validation.d.ts.map +1 -0
- package/dist/src/validation.js +73 -0
- package/dist/src/validation.js.map +1 -0
- package/dist/src/validation.test.d.ts +6 -0
- package/dist/src/validation.test.d.ts.map +1 -0
- package/dist/src/validation.test.js +102 -0
- package/dist/src/validation.test.js.map +1 -0
- package/package.json +2 -2
- package/server.json +3 -7
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { isSupabaseConfigured } from '../supabase-client.js';
|
|
15
15
|
import { createStubService } from './team-workspace.stub.js';
|
|
16
|
+
import { createLiveService } from './team-workspace.live.js';
|
|
17
|
+
import { readLicenseKey } from './team-resolver.js';
|
|
16
18
|
// Re-export stub factory for external consumers and tests
|
|
17
19
|
export { createStubService } from './team-workspace.stub.js';
|
|
18
20
|
// ============================================================================
|
|
@@ -124,8 +126,14 @@ export function checkSharingPolicy(skillId, policy) {
|
|
|
124
126
|
}
|
|
125
127
|
return null;
|
|
126
128
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Module-level singleton. Picks the live Supabase-backed service when
|
|
131
|
+
* SUPABASE_URL + SUPABASE_ANON_KEY are configured; otherwise falls back
|
|
132
|
+
* to the in-memory stub (useful for tests and unauthenticated env).
|
|
133
|
+
*/
|
|
134
|
+
let service = isSupabaseConfigured()
|
|
135
|
+
? createLiveService()
|
|
136
|
+
: createStubService();
|
|
129
137
|
/** Replace the workspace service implementation (for testing or Supabase swap) */
|
|
130
138
|
export function setTeamWorkspaceService(svc) {
|
|
131
139
|
service = svc;
|
|
@@ -145,50 +153,80 @@ export function getTeamWorkspaceService() {
|
|
|
145
153
|
*/
|
|
146
154
|
export async function executeTeamWorkspace(input, _context) {
|
|
147
155
|
const dataSource = isSupabaseConfigured() ? 'live' : 'stub';
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
// SMI-4292: License key resolution order — explicit env, then anon fallback.
|
|
157
|
+
// In live mode, missing/invalid keys surface as typed errors (not stub data).
|
|
158
|
+
const licenseKey = readLicenseKey();
|
|
159
|
+
if (dataSource === 'live' && !licenseKey) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
dataSource,
|
|
163
|
+
error: 'SKILLSMITH_LICENSE_KEY is required for team workspace operations. ' +
|
|
164
|
+
'Set it in your MCP server config — shell exports do not reach MCP subprocesses.',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
let teamId;
|
|
168
|
+
try {
|
|
169
|
+
teamId = await service.resolveTeamId(licenseKey ?? '');
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
dataSource,
|
|
175
|
+
error: err instanceof Error ? err.message : 'Failed to resolve team from license key.',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// SMI-4312: Wrap service calls so missing service-role config or other
|
|
179
|
+
// live-mode errors surface as typed {success:false} results.
|
|
180
|
+
try {
|
|
181
|
+
switch (input.action) {
|
|
182
|
+
case 'create': {
|
|
183
|
+
if (!input.name) {
|
|
184
|
+
return { success: false, dataSource, error: 'Name is required for workspace creation.' };
|
|
185
|
+
}
|
|
186
|
+
const ws = await service.createWorkspace(teamId, input.name, input.description);
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
dataSource,
|
|
190
|
+
workspace: ws,
|
|
191
|
+
message: `Workspace "${ws.name}" created.`,
|
|
192
|
+
};
|
|
155
193
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
case 'list': {
|
|
165
|
-
const list = await service.listWorkspaces(teamId);
|
|
166
|
-
return {
|
|
167
|
-
success: true,
|
|
168
|
-
dataSource,
|
|
169
|
-
workspaces: list,
|
|
170
|
-
message: `Found ${list.length} workspace(s).`,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
case 'get': {
|
|
174
|
-
if (!input.workspaceId) {
|
|
175
|
-
return { success: false, dataSource, error: 'workspaceId is required for get.' };
|
|
194
|
+
case 'list': {
|
|
195
|
+
const list = await service.listWorkspaces(teamId);
|
|
196
|
+
return {
|
|
197
|
+
success: true,
|
|
198
|
+
dataSource,
|
|
199
|
+
workspaces: list,
|
|
200
|
+
message: `Found ${list.length} workspace(s).`,
|
|
201
|
+
};
|
|
176
202
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return { success:
|
|
203
|
+
case 'get': {
|
|
204
|
+
if (!input.workspaceId) {
|
|
205
|
+
return { success: false, dataSource, error: 'workspaceId is required for get.' };
|
|
206
|
+
}
|
|
207
|
+
const ws = await service.getWorkspace(teamId, input.workspaceId);
|
|
208
|
+
if (!ws)
|
|
209
|
+
return { success: false, dataSource, error: 'Workspace not found.' };
|
|
210
|
+
return { success: true, dataSource, workspace: ws };
|
|
211
|
+
}
|
|
212
|
+
case 'delete': {
|
|
213
|
+
if (!input.workspaceId) {
|
|
214
|
+
return { success: false, dataSource, error: 'workspaceId is required for delete.' };
|
|
215
|
+
}
|
|
216
|
+
const deleted = await service.deleteWorkspace(teamId, input.workspaceId);
|
|
217
|
+
if (!deleted)
|
|
218
|
+
return { success: false, dataSource, error: 'Workspace not found.' };
|
|
219
|
+
return { success: true, dataSource, message: 'Workspace deleted.' };
|
|
185
220
|
}
|
|
186
|
-
const deleted = await service.deleteWorkspace(teamId, input.workspaceId);
|
|
187
|
-
if (!deleted)
|
|
188
|
-
return { success: false, dataSource, error: 'Workspace not found.' };
|
|
189
|
-
return { success: true, dataSource, message: 'Workspace deleted.' };
|
|
190
221
|
}
|
|
191
222
|
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
dataSource,
|
|
227
|
+
error: err instanceof Error ? err.message : 'Workspace operation failed.',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
192
230
|
}
|
|
193
231
|
/**
|
|
194
232
|
* Execute a share_skill operation.
|
|
@@ -200,44 +238,80 @@ export async function executeTeamWorkspace(input, _context) {
|
|
|
200
238
|
*/
|
|
201
239
|
export async function executeShareSkill(input, _context) {
|
|
202
240
|
const dataSource = isSupabaseConfigured() ? 'live' : 'stub';
|
|
203
|
-
const licenseKey =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
241
|
+
const licenseKey = readLicenseKey();
|
|
242
|
+
if (dataSource === 'live' && !licenseKey) {
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
dataSource,
|
|
246
|
+
error: 'SKILLSMITH_LICENSE_KEY is required for skill-sharing operations. ' +
|
|
247
|
+
'Set it in your MCP server config — shell exports do not reach MCP subprocesses.',
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
let teamId;
|
|
251
|
+
try {
|
|
252
|
+
teamId = await service.resolveTeamId(licenseKey ?? '');
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
return {
|
|
256
|
+
success: false,
|
|
257
|
+
dataSource,
|
|
258
|
+
error: err instanceof Error ? err.message : 'Failed to resolve team from license key.',
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// SMI-4312: All service calls wrapped so thrown tenant-isolation errors
|
|
262
|
+
// (e.g. cross-team workspace access) surface as typed {success:false} results
|
|
263
|
+
// instead of propagating as unhandled exceptions.
|
|
264
|
+
try {
|
|
265
|
+
switch (input.action) {
|
|
266
|
+
case 'add': {
|
|
267
|
+
if (!input.skillId) {
|
|
268
|
+
return { success: false, dataSource, error: 'skillId is required for add.' };
|
|
269
|
+
}
|
|
270
|
+
// SMI-3898: Check sharing policy before adding
|
|
271
|
+
const settings = await service.getWorkspaceSettings(teamId, input.workspaceId);
|
|
272
|
+
const policyError = checkSharingPolicy(input.skillId, settings.sharing);
|
|
273
|
+
if (policyError) {
|
|
274
|
+
return { success: false, dataSource, error: policyError };
|
|
275
|
+
}
|
|
276
|
+
const skill = await service.addSkill(teamId, input.workspaceId, input.skillId);
|
|
277
|
+
return {
|
|
278
|
+
success: true,
|
|
279
|
+
dataSource,
|
|
280
|
+
skills: [skill],
|
|
281
|
+
message: `Skill "${input.skillId}" shared to workspace.`,
|
|
282
|
+
};
|
|
209
283
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
284
|
+
case 'remove': {
|
|
285
|
+
if (!input.skillId) {
|
|
286
|
+
return { success: false, dataSource, error: 'skillId is required for remove.' };
|
|
287
|
+
}
|
|
288
|
+
const removed = await service.removeSkill(teamId, input.workspaceId, input.skillId);
|
|
289
|
+
if (!removed) {
|
|
290
|
+
return { success: false, dataSource, error: 'Skill not found in workspace.' };
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
success: true,
|
|
294
|
+
dataSource,
|
|
295
|
+
message: `Skill "${input.skillId}" removed from workspace.`,
|
|
296
|
+
};
|
|
215
297
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
case 'remove': {
|
|
225
|
-
if (!input.skillId) {
|
|
226
|
-
return { success: false, dataSource, error: 'skillId is required for remove.' };
|
|
298
|
+
case 'list': {
|
|
299
|
+
const list = await service.listSkills(teamId, input.workspaceId);
|
|
300
|
+
return {
|
|
301
|
+
success: true,
|
|
302
|
+
dataSource,
|
|
303
|
+
skills: list,
|
|
304
|
+
message: `${list.length} shared skill(s).`,
|
|
305
|
+
};
|
|
227
306
|
}
|
|
228
|
-
const removed = await service.removeSkill(teamId, input.workspaceId, input.skillId);
|
|
229
|
-
if (!removed)
|
|
230
|
-
return { success: false, dataSource, error: 'Skill not found in workspace.' };
|
|
231
|
-
return {
|
|
232
|
-
success: true,
|
|
233
|
-
dataSource,
|
|
234
|
-
message: `Skill "${input.skillId}" removed from workspace.`,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
case 'list': {
|
|
238
|
-
const list = await service.listSkills(teamId, input.workspaceId);
|
|
239
|
-
return { success: true, dataSource, skills: list, message: `${list.length} shared skill(s).` };
|
|
240
307
|
}
|
|
241
308
|
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
return {
|
|
311
|
+
success: false,
|
|
312
|
+
dataSource,
|
|
313
|
+
error: err instanceof Error ? err.message : 'Share skill operation failed.',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
242
316
|
}
|
|
243
317
|
//# sourceMappingURL=team-workspace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-workspace.js","sourceRoot":"","sources":["../../../src/tools/team-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"team-workspace.js","sourceRoot":"","sources":["../../../src/tools/team-workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Live Supabase-backed TeamWorkspaceService
|
|
3
|
+
* @module @skillsmith/mcp-server/tools/team-workspace.live
|
|
4
|
+
* @see SMI-4292: Wave 5A — drops stub fallback when Supabase is configured.
|
|
5
|
+
* @see SMI-4312: Use service-role client for CRUD post license-key resolution.
|
|
6
|
+
*
|
|
7
|
+
* Uses the Supabase service-role client for all CRUD against
|
|
8
|
+
* `team_workspaces` and `workspace_skills`. Rationale: migration 071 RLS
|
|
9
|
+
* gates tenant access on `authenticated` role + `auth.uid()`, which the
|
|
10
|
+
* MCP subprocess does not carry (no user JWT, no browser cookie). The
|
|
11
|
+
* anon client can't satisfy those policies; service-role bypasses them.
|
|
12
|
+
* Tenant isolation is enforced in-query via explicit `team_id` filters on
|
|
13
|
+
* every request, plus a team-scoped workspace-existence check before any
|
|
14
|
+
* `workspace_skills` operation. See ADR-116.
|
|
15
|
+
*
|
|
16
|
+
* License-key → team_id resolution still uses the anon client + RPC
|
|
17
|
+
* (`resolve_team_from_license` is SECURITY DEFINER — see team-resolver.ts).
|
|
18
|
+
*
|
|
19
|
+
* All rows are returned in camelCase (Workspace shape); Supabase snake_case
|
|
20
|
+
* columns are mapped at the boundary so handlers stay schema-agnostic.
|
|
21
|
+
*/
|
|
22
|
+
import type { TeamWorkspaceService } from './team-workspace.js';
|
|
23
|
+
/**
|
|
24
|
+
* Create a live Supabase-backed TeamWorkspaceService.
|
|
25
|
+
* Call signals and teamId arguments from the handler are honoured; the
|
|
26
|
+
* service does NOT re-resolve team_id internally.
|
|
27
|
+
*
|
|
28
|
+
* Every DB call explicitly filters by `team_id = <resolved>` (for
|
|
29
|
+
* `team_workspaces`) or asserts workspace membership (for
|
|
30
|
+
* `workspace_skills`). Service-role bypasses RLS — tenant isolation
|
|
31
|
+
* lives here, not in the database.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createLiveService(): TeamWorkspaceService;
|
|
34
|
+
//# sourceMappingURL=team-workspace.live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-workspace.live.d.ts","sourceRoot":"","sources":["../../../src/tools/team-workspace.live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EACV,oBAAoB,EAIrB,MAAM,qBAAqB,CAAA;AA8G5B;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,oBAAoB,CAgGxD"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Live Supabase-backed TeamWorkspaceService
|
|
3
|
+
* @module @skillsmith/mcp-server/tools/team-workspace.live
|
|
4
|
+
* @see SMI-4292: Wave 5A — drops stub fallback when Supabase is configured.
|
|
5
|
+
* @see SMI-4312: Use service-role client for CRUD post license-key resolution.
|
|
6
|
+
*
|
|
7
|
+
* Uses the Supabase service-role client for all CRUD against
|
|
8
|
+
* `team_workspaces` and `workspace_skills`. Rationale: migration 071 RLS
|
|
9
|
+
* gates tenant access on `authenticated` role + `auth.uid()`, which the
|
|
10
|
+
* MCP subprocess does not carry (no user JWT, no browser cookie). The
|
|
11
|
+
* anon client can't satisfy those policies; service-role bypasses them.
|
|
12
|
+
* Tenant isolation is enforced in-query via explicit `team_id` filters on
|
|
13
|
+
* every request, plus a team-scoped workspace-existence check before any
|
|
14
|
+
* `workspace_skills` operation. See ADR-116.
|
|
15
|
+
*
|
|
16
|
+
* License-key → team_id resolution still uses the anon client + RPC
|
|
17
|
+
* (`resolve_team_from_license` is SECURITY DEFINER — see team-resolver.ts).
|
|
18
|
+
*
|
|
19
|
+
* All rows are returned in camelCase (Workspace shape); Supabase snake_case
|
|
20
|
+
* columns are mapped at the boundary so handlers stay schema-agnostic.
|
|
21
|
+
*/
|
|
22
|
+
import { getSupabaseAdminClient } from '../supabase-client.js';
|
|
23
|
+
import { resolveLicenseTeamId } from './team-resolver.js';
|
|
24
|
+
function mapWorkspace(row) {
|
|
25
|
+
return {
|
|
26
|
+
id: row.id,
|
|
27
|
+
name: row.name,
|
|
28
|
+
description: row.description,
|
|
29
|
+
teamId: row.team_id,
|
|
30
|
+
settings: row.settings ?? {},
|
|
31
|
+
createdAt: row.created_at,
|
|
32
|
+
updatedAt: row.updated_at,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function mapSharedSkill(row) {
|
|
36
|
+
return {
|
|
37
|
+
skillId: row.skill_id,
|
|
38
|
+
addedBy: row.added_by ?? 'unknown',
|
|
39
|
+
addedAt: row.added_at,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the Supabase service-role client. Throws a typed error if
|
|
44
|
+
* `SUPABASE_SERVICE_ROLE_KEY` is not configured on the MCP host —
|
|
45
|
+
* handlers surface this to the caller instead of leaking a 42501.
|
|
46
|
+
*/
|
|
47
|
+
async function getClient() {
|
|
48
|
+
try {
|
|
49
|
+
return (await getSupabaseAdminClient());
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : 'unknown error';
|
|
53
|
+
throw new Error(`Team workspace operations require SUPABASE_SERVICE_ROLE_KEY on the MCP host: ${message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Fetch a workspace by (teamId, workspaceId) and verify tenant scope.
|
|
58
|
+
* Returns null on miss or if the workspace belongs to a different team.
|
|
59
|
+
* Shared helper so sibling methods don't depend on a correctly-bound `this`.
|
|
60
|
+
*/
|
|
61
|
+
async function fetchTeamScopedWorkspace(client, teamId, workspaceId) {
|
|
62
|
+
const resp = await client
|
|
63
|
+
.from('team_workspaces')
|
|
64
|
+
.select()
|
|
65
|
+
.eq('id', workspaceId)
|
|
66
|
+
.eq('team_id', teamId)
|
|
67
|
+
.single();
|
|
68
|
+
if (resp.error || !resp.data)
|
|
69
|
+
return null;
|
|
70
|
+
return mapWorkspace(resp.data);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Assert the workspace exists AND belongs to the resolved `teamId`.
|
|
74
|
+
* Required before every `workspace_skills` CRUD because service-role
|
|
75
|
+
* bypasses RLS — the DB no longer cross-checks membership for us.
|
|
76
|
+
*/
|
|
77
|
+
async function assertWorkspaceInTeam(client, teamId, workspaceId) {
|
|
78
|
+
const workspace = await fetchTeamScopedWorkspace(client, teamId, workspaceId);
|
|
79
|
+
if (!workspace) {
|
|
80
|
+
throw new Error(`Workspace ${workspaceId} not found in team ${teamId}.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a live Supabase-backed TeamWorkspaceService.
|
|
85
|
+
* Call signals and teamId arguments from the handler are honoured; the
|
|
86
|
+
* service does NOT re-resolve team_id internally.
|
|
87
|
+
*
|
|
88
|
+
* Every DB call explicitly filters by `team_id = <resolved>` (for
|
|
89
|
+
* `team_workspaces`) or asserts workspace membership (for
|
|
90
|
+
* `workspace_skills`). Service-role bypasses RLS — tenant isolation
|
|
91
|
+
* lives here, not in the database.
|
|
92
|
+
*/
|
|
93
|
+
export function createLiveService() {
|
|
94
|
+
return {
|
|
95
|
+
async resolveTeamId(licenseKey) {
|
|
96
|
+
const teamId = await resolveLicenseTeamId(licenseKey);
|
|
97
|
+
if (!teamId) {
|
|
98
|
+
throw new Error('Unable to resolve team from license key. Ensure SKILLSMITH_LICENSE_KEY is set and corresponds to an active Team-tier subscription.');
|
|
99
|
+
}
|
|
100
|
+
return teamId;
|
|
101
|
+
},
|
|
102
|
+
async createWorkspace(teamId, name, description) {
|
|
103
|
+
const client = await getClient();
|
|
104
|
+
const resp = await client
|
|
105
|
+
.from('team_workspaces')
|
|
106
|
+
.insert({ team_id: teamId, name, description: description ?? null })
|
|
107
|
+
.select()
|
|
108
|
+
.single();
|
|
109
|
+
if (resp.error || !resp.data) {
|
|
110
|
+
throw new Error(`Failed to create workspace: ${resp.error?.message ?? 'unknown error'}`);
|
|
111
|
+
}
|
|
112
|
+
return mapWorkspace(resp.data);
|
|
113
|
+
},
|
|
114
|
+
async listWorkspaces(teamId) {
|
|
115
|
+
const client = await getClient();
|
|
116
|
+
const resp = await client.from('team_workspaces').select().eq('team_id', teamId);
|
|
117
|
+
if (resp.error) {
|
|
118
|
+
throw new Error(`Failed to list workspaces: ${resp.error.message ?? 'unknown error'}`);
|
|
119
|
+
}
|
|
120
|
+
return (resp.data ?? []).map(mapWorkspace);
|
|
121
|
+
},
|
|
122
|
+
async getWorkspace(teamId, workspaceId) {
|
|
123
|
+
const client = await getClient();
|
|
124
|
+
return fetchTeamScopedWorkspace(client, teamId, workspaceId);
|
|
125
|
+
},
|
|
126
|
+
async deleteWorkspace(teamId, workspaceId) {
|
|
127
|
+
const client = await getClient();
|
|
128
|
+
const resp = await client
|
|
129
|
+
.from('team_workspaces')
|
|
130
|
+
.delete()
|
|
131
|
+
.eq('id', workspaceId)
|
|
132
|
+
.eq('team_id', teamId);
|
|
133
|
+
if (resp.error)
|
|
134
|
+
return false;
|
|
135
|
+
// PostgREST returns affected rows in `data` when `returning=representation` (default)
|
|
136
|
+
return Array.isArray(resp.data) ? resp.data.length > 0 : true;
|
|
137
|
+
},
|
|
138
|
+
async addSkill(teamId, workspaceId, skillId) {
|
|
139
|
+
const client = await getClient();
|
|
140
|
+
await assertWorkspaceInTeam(client, teamId, workspaceId);
|
|
141
|
+
const resp = await client
|
|
142
|
+
.from('workspace_skills')
|
|
143
|
+
.insert({ workspace_id: workspaceId, skill_id: skillId })
|
|
144
|
+
.select()
|
|
145
|
+
.single();
|
|
146
|
+
if (resp.error || !resp.data) {
|
|
147
|
+
throw new Error(`Failed to add skill: ${resp.error?.message ?? 'unknown error'}`);
|
|
148
|
+
}
|
|
149
|
+
return mapSharedSkill(resp.data);
|
|
150
|
+
},
|
|
151
|
+
async removeSkill(teamId, workspaceId, skillId) {
|
|
152
|
+
const client = await getClient();
|
|
153
|
+
await assertWorkspaceInTeam(client, teamId, workspaceId);
|
|
154
|
+
const resp = await client
|
|
155
|
+
.from('workspace_skills')
|
|
156
|
+
.delete()
|
|
157
|
+
.eq('workspace_id', workspaceId)
|
|
158
|
+
.eq('skill_id', skillId);
|
|
159
|
+
if (resp.error)
|
|
160
|
+
return false;
|
|
161
|
+
return Array.isArray(resp.data) ? resp.data.length > 0 : true;
|
|
162
|
+
},
|
|
163
|
+
async listSkills(teamId, workspaceId) {
|
|
164
|
+
const client = await getClient();
|
|
165
|
+
await assertWorkspaceInTeam(client, teamId, workspaceId);
|
|
166
|
+
const resp = await client
|
|
167
|
+
.from('workspace_skills')
|
|
168
|
+
.select()
|
|
169
|
+
.eq('workspace_id', workspaceId);
|
|
170
|
+
if (resp.error) {
|
|
171
|
+
throw new Error(`Failed to list skills: ${resp.error.message ?? 'unknown error'}`);
|
|
172
|
+
}
|
|
173
|
+
return (resp.data ?? []).map(mapSharedSkill);
|
|
174
|
+
},
|
|
175
|
+
async getWorkspaceSettings(teamId, workspaceId) {
|
|
176
|
+
const client = await getClient();
|
|
177
|
+
const ws = await fetchTeamScopedWorkspace(client, teamId, workspaceId);
|
|
178
|
+
return ws?.settings ?? {};
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=team-workspace.live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-workspace.live.js","sourceRoot":"","sources":["../../../src/tools/team-workspace.live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AA4CzD,SAAS,YAAY,CAAC,GAAiB;IACrC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,MAAM,EAAE,GAAG,CAAC,OAAO;QACnB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;QAC5B,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAA;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAsB;IAC5C,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,OAAO,EAAE,GAAG,CAAC,QAAQ,IAAI,SAAS;QAClC,OAAO,EAAE,GAAG,CAAC,QAAQ;KACtB,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,SAAS;IACtB,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,sBAAsB,EAAE,CAA0B,CAAA;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;QACpE,MAAM,IAAI,KAAK,CACb,gFAAgF,OAAO,EAAE,CAC1F,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,wBAAwB,CACrC,MAA6B,EAC7B,MAAc,EACd,WAAmB;IAEnB,MAAM,IAAI,GAAG,MAAM,MAAM;SACtB,IAAI,CAAe,iBAAiB,CAAC;SACrC,MAAM,EAAE;SACR,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;SACrB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;SACrB,MAAM,EAAE,CAAA;IACX,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACzC,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAChC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,qBAAqB,CAClC,MAA6B,EAC7B,MAAc,EACd,WAAmB;IAEnB,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;IAC7E,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,aAAa,WAAW,sBAAsB,MAAM,GAAG,CAAC,CAAA;IAC1E,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,UAAkB;YACpC,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAA;YACrD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CACb,oIAAoI,CACrI,CAAA;YACH,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW;YAC7C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,IAAI,GAAG,MAAM,MAAM;iBACtB,IAAI,CAAe,iBAAiB,CAAC;iBACrC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,IAAI,IAAI,EAAE,CAAC;iBACnE,MAAM,EAAE;iBACR,MAAM,EAAE,CAAA;YACX,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;YAC1F,CAAC;YACD,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChC,CAAC;QAED,KAAK,CAAC,cAAc,CAAC,MAAM;YACzB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAe,iBAAiB,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YAC9F,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;YACxF,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC5C,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW;YACpC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,OAAO,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;QAC9D,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW;YACvC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,IAAI,GAAG,MAAM,MAAM;iBACtB,IAAI,CAAe,iBAAiB,CAAC;iBACrC,MAAM,EAAE;iBACR,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;iBACrB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YACxB,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAA;YAC5B,sFAAsF;YACtF,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC/D,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO;YACzC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;YACxD,MAAM,IAAI,GAAG,MAAM,MAAM;iBACtB,IAAI,CAAoB,kBAAkB,CAAC;iBAC3C,MAAM,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;iBACxD,MAAM,EAAE;iBACR,MAAM,EAAE,CAAA;YACX,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;YACnF,CAAC;YACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO;YAC5C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;YACxD,MAAM,IAAI,GAAG,MAAM,MAAM;iBACtB,IAAI,CAAoB,kBAAkB,CAAC;iBAC3C,MAAM,EAAE;iBACR,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC;iBAC/B,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;YAC1B,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAA;YAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC/D,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW;YAClC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;YACxD,MAAM,IAAI,GAAG,MAAM,MAAM;iBACtB,IAAI,CAAoB,kBAAkB,CAAC;iBAC3C,MAAM,EAAE;iBACR,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;YAClC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;YACpF,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QAC9C,CAAC;QAED,KAAK,CAAC,oBAAoB,CAAC,MAAM,EAAE,WAAW;YAC5C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,EAAE,GAAG,MAAM,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;YACtE,OAAO,EAAE,EAAE,QAAQ,IAAI,EAAE,CAAA;QAC3B,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Live-mode tests for team_workspace + share_skill MCP tools
|
|
3
|
+
* @see SMI-4312: service-role client post-resolution + cross-team hardening
|
|
4
|
+
*
|
|
5
|
+
* Kept in a sidecar so team-workspace.test.ts stays under the 500-line CI limit.
|
|
6
|
+
* Exercises the live Supabase-backed service by mocking `getSupabaseAdminClient`
|
|
7
|
+
* with a recording fake client.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=team-workspace.live.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-workspace.live.test.d.ts","sourceRoot":"","sources":["../../../src/tools/team-workspace.live.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|