@hasna/skills 0.5.0 → 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/README.md +44 -0
- package/bin/index.js +927 -393
- package/bin/mcp.js +409 -110
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/workspace-selection.d.ts +11 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +337 -123
- package/dist/lib/remote-auth.d.ts +15 -9
- package/dist/lib/remote-client.d.ts +11 -0
- package/dist/lib/remote-workspace-selection.d.ts +58 -0
- package/dist/lib/workspace-profile.d.ts +49 -0
- package/dist/sdk/index.d.ts +3 -0
- package/dist/sdk/index.js +281 -67
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10254,12 +10254,106 @@ function primitiveHaystack(primitive) {
|
|
|
10254
10254
|
function clone(value) {
|
|
10255
10255
|
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
10256
10256
|
}
|
|
10257
|
+
// src/lib/remote-workspace-selection.ts
|
|
10258
|
+
var record = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
10259
|
+
var uuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v);
|
|
10260
|
+
var text = (v, max = 1024) => typeof v === "string" && !!v.trim() && v.length <= max && !/[\p{Cc}\p{Cs}\u2028\u2029]/u.test(v);
|
|
10261
|
+
var role = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v);
|
|
10262
|
+
var invalidWorkspaceResult = "The server returned an invalid workspace selection result.";
|
|
10263
|
+
|
|
10264
|
+
class WorkspaceContextInputError extends Error {
|
|
10265
|
+
constructor() {
|
|
10266
|
+
super("Provide the observed user ID and exact lowercase membership ID.");
|
|
10267
|
+
this.name = "WorkspaceContextInputError";
|
|
10268
|
+
}
|
|
10269
|
+
}
|
|
10270
|
+
|
|
10271
|
+
class WorkspaceIdentityMismatchError extends Error {
|
|
10272
|
+
constructor() {
|
|
10273
|
+
super("The verified account does not match the requested workspace context.");
|
|
10274
|
+
this.name = "WorkspaceIdentityMismatchError";
|
|
10275
|
+
}
|
|
10276
|
+
}
|
|
10277
|
+
function workspaceExpectedUserId(value) {
|
|
10278
|
+
if (!uuid(value))
|
|
10279
|
+
throw new WorkspaceContextInputError;
|
|
10280
|
+
return value;
|
|
10281
|
+
}
|
|
10282
|
+
function workspaceContext(value) {
|
|
10283
|
+
if (!record(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid(value.userId) || !uuid(value.membershipId))
|
|
10284
|
+
throw new WorkspaceContextInputError;
|
|
10285
|
+
return { userId: value.userId, membershipId: value.membershipId };
|
|
10286
|
+
}
|
|
10287
|
+
function invalid() {
|
|
10288
|
+
throw new Error(invalidWorkspaceResult);
|
|
10289
|
+
}
|
|
10290
|
+
function organization(v) {
|
|
10291
|
+
if (!record(v) || !uuid(v.id) || !text(v.slug) || !text(v.name))
|
|
10292
|
+
return invalid();
|
|
10293
|
+
return { id: v.id, slug: v.slug, name: v.name };
|
|
10294
|
+
}
|
|
10295
|
+
function parseAccountWorkspaces(value) {
|
|
10296
|
+
if (!record(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
|
|
10297
|
+
return invalid();
|
|
10298
|
+
const workspaces = value.workspaces.map((v) => {
|
|
10299
|
+
if (!record(v) || !uuid(v.membershipId) || !role(v.role) || typeof v.current !== "boolean")
|
|
10300
|
+
return invalid();
|
|
10301
|
+
return { membershipId: v.membershipId, organization: organization(v.organization), role: v.role, current: v.current };
|
|
10302
|
+
});
|
|
10303
|
+
if (workspaces.filter((w) => w.current).length !== 1 || new Set(workspaces.map((w) => w.membershipId)).size !== workspaces.length || new Set(workspaces.map((w) => w.organization.id)).size !== workspaces.length)
|
|
10304
|
+
return invalid();
|
|
10305
|
+
return { workspaces };
|
|
10306
|
+
}
|
|
10307
|
+
function parseWorkspaceIdentity(value, expectedUserId) {
|
|
10308
|
+
if (!record(value))
|
|
10309
|
+
return invalid();
|
|
10310
|
+
const user = value.user;
|
|
10311
|
+
if (!record(user) || !uuid(user.id) || !uuid(user.membershipId) || !text(user.email, 320) || !(user.displayName === null || text(user.displayName)) || !role(user.role))
|
|
10312
|
+
return invalid();
|
|
10313
|
+
if (user.id !== expectedUserId)
|
|
10314
|
+
throw new WorkspaceIdentityMismatchError;
|
|
10315
|
+
return { user: { id: user.id, membershipId: user.membershipId, email: user.email, displayName: user.displayName, role: user.role }, organization: organization(value.organization) };
|
|
10316
|
+
}
|
|
10317
|
+
function sessionToken(value) {
|
|
10318
|
+
if (typeof value !== "string" || !value || value.length > 8192 || /[^\x21-\x7e]/.test(value) || value.startsWith("sk_"))
|
|
10319
|
+
return invalid();
|
|
10320
|
+
return value;
|
|
10321
|
+
}
|
|
10322
|
+
function parseWorkspaceSession(value, expected) {
|
|
10323
|
+
const identity = parseWorkspaceIdentity(value, expected.userId);
|
|
10324
|
+
if (identity.user.membershipId !== expected.membershipId)
|
|
10325
|
+
throw new WorkspaceIdentityMismatchError;
|
|
10326
|
+
return { token: sessionToken(value.token), ...identity };
|
|
10327
|
+
}
|
|
10328
|
+
function parseWorkspaceLogin(value, expectedUserId) {
|
|
10329
|
+
const user = record(value) && value.user;
|
|
10330
|
+
if (!record(value) || !record(user) || !uuid(user.id))
|
|
10331
|
+
return invalid();
|
|
10332
|
+
if (expectedUserId !== undefined && user.id !== expectedUserId)
|
|
10333
|
+
throw new WorkspaceIdentityMismatchError;
|
|
10334
|
+
return { token: sessionToken(value.token), userId: user.id };
|
|
10335
|
+
}
|
|
10336
|
+
var workspaceSelectionFailures = {
|
|
10337
|
+
INVALID_WORKSPACE_SELECTION: [400, "Provide only the exact membership ID from your workspace list."],
|
|
10338
|
+
SESSION_EXPIRED: [401, "Sign in again before selecting a workspace."],
|
|
10339
|
+
ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
|
|
10340
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "Interactive sign-in is required to select a workspace."],
|
|
10341
|
+
WORKSPACE_UNAVAILABLE: [404, "Workspace is unavailable. Refresh your workspace list."],
|
|
10342
|
+
WORKSPACE_BUSY: [503, "Workspace is busy. Refresh before retrying."]
|
|
10343
|
+
};
|
|
10344
|
+
function workspaceSelectionFailure(value, status) {
|
|
10345
|
+
if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
|
|
10346
|
+
return null;
|
|
10347
|
+
const code = value.code;
|
|
10348
|
+
return workspaceSelectionFailures[code][0] === status ? code : null;
|
|
10349
|
+
}
|
|
10350
|
+
|
|
10257
10351
|
// src/lib/remote-workspace.ts
|
|
10258
|
-
var
|
|
10352
|
+
var record2 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
10259
10353
|
var cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value);
|
|
10260
|
-
var
|
|
10354
|
+
var uuid2 = (value) => typeof value === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(value);
|
|
10261
10355
|
function workspaceMembersQuery(options = {}) {
|
|
10262
|
-
if (!
|
|
10356
|
+
if (!record2(options) || Object.keys(options).some((key) => key !== "limit" && key !== "cursor") || options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100) || options.cursor !== undefined && !cursor(options.cursor))
|
|
10263
10357
|
throw new Error("Use a roster limit from 1 to 100 and an unchanged continuation cursor.");
|
|
10264
10358
|
const query = new URLSearchParams;
|
|
10265
10359
|
if (options.limit !== undefined)
|
|
@@ -10275,7 +10369,7 @@ function timestamp(value) {
|
|
|
10275
10369
|
return Number.isFinite(time) && new Date(time).toISOString().slice(0, 23) === value.slice(0, 23);
|
|
10276
10370
|
}
|
|
10277
10371
|
function parseMember(row, fail) {
|
|
10278
|
-
if (!
|
|
10372
|
+
if (!record2(row) || !uuid2(row.membershipId) || !uuid2(row.userId) || typeof row.email !== "string" || !row.email || !(row.displayName === null || typeof row.displayName === "string") || !isRole(row.role) || !timestamp(row.createdAt))
|
|
10279
10373
|
return fail();
|
|
10280
10374
|
return {
|
|
10281
10375
|
membershipId: row.membershipId,
|
|
@@ -10295,12 +10389,12 @@ class WorkspaceMemberInputError extends Error {
|
|
|
10295
10389
|
}
|
|
10296
10390
|
}
|
|
10297
10391
|
function mutationInput(membershipId, input, roleChange) {
|
|
10298
|
-
if (typeof membershipId !== "string" || !
|
|
10392
|
+
if (typeof membershipId !== "string" || !uuid2(membershipId) || membershipId !== membershipId.toLowerCase() || !record2(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
|
|
10299
10393
|
throw new WorkspaceMemberInputError;
|
|
10300
|
-
const expectedRole = input.expectedRole,
|
|
10301
|
-
if (!isRole(expectedRole) || roleChange && !isRole(
|
|
10394
|
+
const expectedRole = input.expectedRole, role2 = roleChange ? input.role : undefined;
|
|
10395
|
+
if (!isRole(expectedRole) || roleChange && !isRole(role2))
|
|
10302
10396
|
throw new WorkspaceMemberInputError;
|
|
10303
|
-
return { membershipId, role, expectedRole };
|
|
10397
|
+
return { membershipId, role: role2, expectedRole };
|
|
10304
10398
|
}
|
|
10305
10399
|
function workspaceMemberRoleInput(membershipId, input) {
|
|
10306
10400
|
const value = mutationInput(membershipId, input, true);
|
|
@@ -10311,19 +10405,19 @@ function workspaceMemberRemovalInput(membershipId, input) {
|
|
|
10311
10405
|
return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
|
|
10312
10406
|
}
|
|
10313
10407
|
var invalidMemberResult = "The server returned an invalid workspace member result. Refresh the roster before another action.";
|
|
10314
|
-
function parseWorkspaceMemberRoleResult(value, membershipId,
|
|
10408
|
+
function parseWorkspaceMemberRoleResult(value, membershipId, role2) {
|
|
10315
10409
|
const fail = () => {
|
|
10316
10410
|
throw new Error(invalidMemberResult);
|
|
10317
10411
|
};
|
|
10318
|
-
if (!
|
|
10412
|
+
if (!record2(value) || !uuid2(value.organizationId) || typeof value.changed !== "boolean")
|
|
10319
10413
|
return fail();
|
|
10320
10414
|
const member = parseMember(value.member, fail);
|
|
10321
|
-
if (member.membershipId !== membershipId || member.role !==
|
|
10415
|
+
if (member.membershipId !== membershipId || member.role !== role2)
|
|
10322
10416
|
return fail();
|
|
10323
10417
|
return { organizationId: value.organizationId, member, changed: value.changed };
|
|
10324
10418
|
}
|
|
10325
10419
|
function parseWorkspaceMemberRemovalResult(value, membershipId) {
|
|
10326
|
-
if (!
|
|
10420
|
+
if (!record2(value) || !uuid2(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
|
|
10327
10421
|
throw new Error(invalidMemberResult);
|
|
10328
10422
|
return { organizationId: value.organizationId, membershipId, removed: true, alreadyRemoved: value.alreadyRemoved };
|
|
10329
10423
|
}
|
|
@@ -10340,7 +10434,7 @@ var workspaceMemberFailures = {
|
|
|
10340
10434
|
MEMBERSHIP_BUSY: [503, "Membership is busy. Refresh the roster before another action."]
|
|
10341
10435
|
};
|
|
10342
10436
|
function workspaceMemberFailure(value, status) {
|
|
10343
|
-
if (!
|
|
10437
|
+
if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
|
|
10344
10438
|
return null;
|
|
10345
10439
|
const code = value.code;
|
|
10346
10440
|
return workspaceMemberFailures[code][0] === status ? code : null;
|
|
@@ -10349,7 +10443,7 @@ function parseWorkspaceMembersPage(value) {
|
|
|
10349
10443
|
const fail = () => {
|
|
10350
10444
|
throw new Error("The server returned an invalid workspace roster.");
|
|
10351
10445
|
};
|
|
10352
|
-
if (!
|
|
10446
|
+
if (!record2(value) || !uuid2(value.organizationId) || !Array.isArray(value.members) || value.members.length > 100 || !(value.nextCursor === null || cursor(value.nextCursor)) || !value.members.length && value.nextCursor !== null)
|
|
10353
10447
|
return fail();
|
|
10354
10448
|
const members = value.members.map((row) => parseMember(row, fail));
|
|
10355
10449
|
if (new Set(members.map((row) => row.membershipId)).size !== members.length)
|
|
@@ -10364,44 +10458,44 @@ function getApiUrl(action, env = process.env, options = {}) {
|
|
|
10364
10458
|
// src/lib/remote-run-contract.ts
|
|
10365
10459
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
10366
10460
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
10367
|
-
const
|
|
10461
|
+
const record3 = isRecord3(payload) ? payload : {};
|
|
10368
10462
|
return {
|
|
10369
10463
|
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
10370
|
-
...pickString(
|
|
10371
|
-
skill: pickStringValue(
|
|
10372
|
-
...pickString(
|
|
10373
|
-
...pickString(
|
|
10374
|
-
...pickNumber(
|
|
10375
|
-
...pickString(
|
|
10376
|
-
...pickString(
|
|
10377
|
-
...pickString(
|
|
10378
|
-
...pickString(
|
|
10379
|
-
...pickNumber(
|
|
10380
|
-
...pickString(
|
|
10381
|
-
...hasOwn(
|
|
10382
|
-
...pickString(
|
|
10383
|
-
...pickString(
|
|
10384
|
-
...pickString(
|
|
10385
|
-
...pickString(
|
|
10386
|
-
...hasOwn(
|
|
10464
|
+
...pickString(record3, "id"),
|
|
10465
|
+
skill: pickStringValue(record3, "skill") ?? fallbackSkill,
|
|
10466
|
+
...pickString(record3, "requestedSlug"),
|
|
10467
|
+
...pickString(record3, "status"),
|
|
10468
|
+
...pickNumber(record3, "exitCode"),
|
|
10469
|
+
...pickString(record3, "correlationId"),
|
|
10470
|
+
...pickString(record3, "createdAt"),
|
|
10471
|
+
...pickString(record3, "startedAt"),
|
|
10472
|
+
...pickString(record3, "completedAt"),
|
|
10473
|
+
...pickNumber(record3, "durationMs"),
|
|
10474
|
+
...pickString(record3, "outputType"),
|
|
10475
|
+
...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
|
|
10476
|
+
...pickString(record3, "errorCode"),
|
|
10477
|
+
...pickString(record3, "errorMessage"),
|
|
10478
|
+
...pickString(record3, "error"),
|
|
10479
|
+
...pickString(record3, "code"),
|
|
10480
|
+
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
10387
10481
|
};
|
|
10388
10482
|
}
|
|
10389
10483
|
function isRecord3(value) {
|
|
10390
10484
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
10391
10485
|
}
|
|
10392
|
-
function hasOwn(
|
|
10393
|
-
return Object.prototype.hasOwnProperty.call(
|
|
10486
|
+
function hasOwn(record3, key) {
|
|
10487
|
+
return Object.prototype.hasOwnProperty.call(record3, key);
|
|
10394
10488
|
}
|
|
10395
|
-
function pickString(
|
|
10396
|
-
const value = pickStringValue(
|
|
10489
|
+
function pickString(record3, key) {
|
|
10490
|
+
const value = pickStringValue(record3, key);
|
|
10397
10491
|
return value === undefined ? {} : { [key]: value };
|
|
10398
10492
|
}
|
|
10399
|
-
function pickStringValue(
|
|
10400
|
-
const value =
|
|
10493
|
+
function pickStringValue(record3, key) {
|
|
10494
|
+
const value = record3[key];
|
|
10401
10495
|
return typeof value === "string" ? value : undefined;
|
|
10402
10496
|
}
|
|
10403
|
-
function pickNumber(
|
|
10404
|
-
const value =
|
|
10497
|
+
function pickNumber(record3, key) {
|
|
10498
|
+
const value = record3[key];
|
|
10405
10499
|
return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
|
|
10406
10500
|
}
|
|
10407
10501
|
|
|
@@ -10564,11 +10658,11 @@ function parseUpdatedProfile(value) {
|
|
|
10564
10658
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
10565
10659
|
}
|
|
10566
10660
|
function parseUpdatedWorkspace(value) {
|
|
10567
|
-
const
|
|
10568
|
-
if (!isRecord4(
|
|
10661
|
+
const organization2 = isRecord4(value) && value.organization;
|
|
10662
|
+
if (!isRecord4(organization2) || !string(organization2.id) || !string(organization2.slug) || !string(organization2.name)) {
|
|
10569
10663
|
throw new Error("The server returned an invalid workspace.");
|
|
10570
10664
|
}
|
|
10571
|
-
return { organization: { id:
|
|
10665
|
+
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
10572
10666
|
}
|
|
10573
10667
|
|
|
10574
10668
|
// src/lib/remote-client.ts
|
|
@@ -10606,6 +10700,16 @@ class RemoteWorkspaceMemberError extends RemoteRequestError {
|
|
|
10606
10700
|
}
|
|
10607
10701
|
}
|
|
10608
10702
|
|
|
10703
|
+
class RemoteWorkspaceSelectionError extends RemoteRequestError {
|
|
10704
|
+
code;
|
|
10705
|
+
constructor(path, code) {
|
|
10706
|
+
super(path, workspaceSelectionFailures[code][0]);
|
|
10707
|
+
this.code = code;
|
|
10708
|
+
this.name = "RemoteWorkspaceSelectionError";
|
|
10709
|
+
this.message = workspaceSelectionFailures[code][1];
|
|
10710
|
+
}
|
|
10711
|
+
}
|
|
10712
|
+
|
|
10609
10713
|
class RemoteCapabilityUnavailableError extends RemoteRequestError {
|
|
10610
10714
|
code = "SUBSCRIPTION_CHECKOUT_UNAVAILABLE";
|
|
10611
10715
|
constructor() {
|
|
@@ -10627,6 +10731,7 @@ class RemoteSkillsClient {
|
|
|
10627
10731
|
return fetch(`${this.apiUrl}${path}`, {
|
|
10628
10732
|
...options,
|
|
10629
10733
|
redirect: "error",
|
|
10734
|
+
credentials: "omit",
|
|
10630
10735
|
signal: options?.signal ?? AbortSignal.timeout(15000),
|
|
10631
10736
|
headers: {
|
|
10632
10737
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -10733,6 +10838,65 @@ class RemoteSkillsClient {
|
|
|
10733
10838
|
async getIdentity() {
|
|
10734
10839
|
return (await this.requestNewRoute("/api/auth/whoami")).json();
|
|
10735
10840
|
}
|
|
10841
|
+
async listAccountWorkspaces(expectedUserId) {
|
|
10842
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
10843
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
10844
|
+
let identity;
|
|
10845
|
+
if (expected !== undefined) {
|
|
10846
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
10847
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
10848
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces", "INTERACTIVE_SESSION_REQUIRED");
|
|
10849
|
+
identity = parseWorkspaceIdentity(value, expected);
|
|
10850
|
+
}
|
|
10851
|
+
const result = parseAccountWorkspaces(await connection.requestWorkspaceSelection("/api/v1/account/workspaces"));
|
|
10852
|
+
const current = result.workspaces.find((workspace) => workspace.current);
|
|
10853
|
+
if (identity && (current.membershipId !== identity.user.membershipId || current.organization.id !== identity.organization.id))
|
|
10854
|
+
throw new WorkspaceIdentityMismatchError;
|
|
10855
|
+
return result;
|
|
10856
|
+
}
|
|
10857
|
+
async switchWorkspace(context) {
|
|
10858
|
+
const target = workspaceContext(context);
|
|
10859
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
10860
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
10861
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
10862
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
10863
|
+
parseWorkspaceIdentity(value, target.userId);
|
|
10864
|
+
const selected = parseWorkspaceSession(await connection.requestWorkspaceSelection("/api/v1/account/workspaces/switch", {
|
|
10865
|
+
method: "POST",
|
|
10866
|
+
body: JSON.stringify({ membershipId: target.membershipId })
|
|
10867
|
+
}), target);
|
|
10868
|
+
const verified = await new RemoteSkillsClient(selected.token, connection.apiUrl).requestWorkspaceSelection("/api/auth/whoami");
|
|
10869
|
+
if (!verified || typeof verified !== "object" || verified.authMethod !== "jwt")
|
|
10870
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
10871
|
+
const identity = parseWorkspaceIdentity(verified, target.userId);
|
|
10872
|
+
if (identity.user.membershipId !== target.membershipId || identity.organization.id !== selected.organization.id)
|
|
10873
|
+
throw new WorkspaceIdentityMismatchError;
|
|
10874
|
+
return { token: selected.token, ...identity };
|
|
10875
|
+
}
|
|
10876
|
+
async requestWorkspaceSelection(path, options) {
|
|
10877
|
+
let response;
|
|
10878
|
+
try {
|
|
10879
|
+
response = await this.request(path, { ...options, credentials: "omit" });
|
|
10880
|
+
} catch {
|
|
10881
|
+
throw new Error("Unable to reach the Skills workspace API.");
|
|
10882
|
+
}
|
|
10883
|
+
let value;
|
|
10884
|
+
try {
|
|
10885
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 1024 * 1024 : 4096)));
|
|
10886
|
+
} catch {
|
|
10887
|
+
if (response.ok)
|
|
10888
|
+
throw new Error(invalidWorkspaceResult);
|
|
10889
|
+
}
|
|
10890
|
+
if (!response.ok) {
|
|
10891
|
+
const code = workspaceSelectionFailure(value, response.status);
|
|
10892
|
+
if (code)
|
|
10893
|
+
throw new RemoteWorkspaceSelectionError(path, code);
|
|
10894
|
+
if (response.status === 404 || response.status === 405)
|
|
10895
|
+
throw new RemoteRouteUnsupportedError(path, response.status, this.apiUrl);
|
|
10896
|
+
throw new RemoteRequestError(path, response.status);
|
|
10897
|
+
}
|
|
10898
|
+
return value;
|
|
10899
|
+
}
|
|
10736
10900
|
async updateProfile(input) {
|
|
10737
10901
|
const body = customerNamePatch(input, "displayName");
|
|
10738
10902
|
return parseUpdatedProfile(await (await this.requestNewRoute("/api/v1/account/profile", { method: "PATCH", body: JSON.stringify(body) })).json());
|
|
@@ -11035,13 +11199,13 @@ class RemoteSkillsClient {
|
|
|
11035
11199
|
return normalizeUpdatedSincePage(await response.json());
|
|
11036
11200
|
}
|
|
11037
11201
|
}
|
|
11038
|
-
function requireOptionalString(
|
|
11039
|
-
if (
|
|
11202
|
+
function requireOptionalString(record3, field) {
|
|
11203
|
+
if (record3[field] === undefined)
|
|
11040
11204
|
return;
|
|
11041
|
-
if (typeof
|
|
11205
|
+
if (typeof record3[field] !== "string") {
|
|
11042
11206
|
throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
|
|
11043
11207
|
}
|
|
11044
|
-
return
|
|
11208
|
+
return record3[field];
|
|
11045
11209
|
}
|
|
11046
11210
|
var INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
11047
11211
|
function isVersionRecord(value) {
|
|
@@ -11064,19 +11228,19 @@ function normalizePin(entry) {
|
|
|
11064
11228
|
if (!entry || typeof entry !== "object") {
|
|
11065
11229
|
throw new Error("Remote pin payload did not match the expected contract (expected an object)");
|
|
11066
11230
|
}
|
|
11067
|
-
const
|
|
11068
|
-
const slug = typeof
|
|
11231
|
+
const record3 = entry;
|
|
11232
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
11069
11233
|
if (!slug) {
|
|
11070
11234
|
throw new Error("Remote pin payload did not match the expected contract (missing slug)");
|
|
11071
11235
|
}
|
|
11072
11236
|
let metadata;
|
|
11073
|
-
if (
|
|
11074
|
-
if (!
|
|
11237
|
+
if (record3.metadata !== undefined) {
|
|
11238
|
+
if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
|
|
11075
11239
|
throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
|
|
11076
11240
|
}
|
|
11077
|
-
metadata =
|
|
11241
|
+
metadata = record3.metadata;
|
|
11078
11242
|
}
|
|
11079
|
-
const pinnedAt = requireOptionalString(
|
|
11243
|
+
const pinnedAt = requireOptionalString(record3, "pinnedAt");
|
|
11080
11244
|
return {
|
|
11081
11245
|
slug,
|
|
11082
11246
|
...pinnedAt !== undefined ? { pinnedAt } : {},
|
|
@@ -11093,16 +11257,16 @@ function normalizeSkillSummary(entry) {
|
|
|
11093
11257
|
if (!entry || typeof entry !== "object") {
|
|
11094
11258
|
throw new Error("Remote skill payload did not match the expected contract (expected an object)");
|
|
11095
11259
|
}
|
|
11096
|
-
const
|
|
11097
|
-
const slug = typeof
|
|
11260
|
+
const record3 = entry;
|
|
11261
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
11098
11262
|
if (!slug) {
|
|
11099
11263
|
throw new Error("Remote skill payload did not match the expected contract (missing slug)");
|
|
11100
11264
|
}
|
|
11101
11265
|
return {
|
|
11102
11266
|
slug,
|
|
11103
|
-
...requireOptionalString(
|
|
11104
|
-
...requireOptionalString(
|
|
11105
|
-
...requireOptionalString(
|
|
11267
|
+
...requireOptionalString(record3, "name") !== undefined ? { name: requireOptionalString(record3, "name") } : {},
|
|
11268
|
+
...requireOptionalString(record3, "version") !== undefined ? { version: requireOptionalString(record3, "version") } : {},
|
|
11269
|
+
...requireOptionalString(record3, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record3, "updatedAt") } : {}
|
|
11106
11270
|
};
|
|
11107
11271
|
}
|
|
11108
11272
|
function normalizeSkillSummaryList(payload) {
|
|
@@ -11155,12 +11319,12 @@ function normalizeUpdatedSincePage(payload) {
|
|
|
11155
11319
|
if (!payload || typeof payload !== "object") {
|
|
11156
11320
|
throw new Error("Updated-since payload did not match the expected contract (expected an object)");
|
|
11157
11321
|
}
|
|
11158
|
-
const
|
|
11159
|
-
if (!Array.isArray(
|
|
11322
|
+
const record3 = payload;
|
|
11323
|
+
if (!Array.isArray(record3.skills)) {
|
|
11160
11324
|
throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
|
|
11161
11325
|
}
|
|
11162
|
-
const skills =
|
|
11163
|
-
const nextCursor =
|
|
11326
|
+
const skills = record3.skills.map(normalizeSkillSummary);
|
|
11327
|
+
const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
|
|
11164
11328
|
if (nextCursor !== null && typeof nextCursor !== "string") {
|
|
11165
11329
|
throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
|
|
11166
11330
|
}
|
|
@@ -11397,8 +11561,8 @@ function revisionIdOf(content) {
|
|
|
11397
11561
|
});
|
|
11398
11562
|
return createHash4("sha256").update(canonical).digest("hex");
|
|
11399
11563
|
}
|
|
11400
|
-
function revisionIdOfRecord(
|
|
11401
|
-
return revisionIdOf(
|
|
11564
|
+
function revisionIdOfRecord(record3) {
|
|
11565
|
+
return revisionIdOf(record3);
|
|
11402
11566
|
}
|
|
11403
11567
|
|
|
11404
11568
|
// src/lib/skill-bundle.ts
|
|
@@ -12105,16 +12269,16 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
12105
12269
|
}
|
|
12106
12270
|
return { path: target, created };
|
|
12107
12271
|
}
|
|
12108
|
-
function writePullMarker(dir,
|
|
12272
|
+
function writePullMarker(dir, record3) {
|
|
12109
12273
|
const marker = {
|
|
12110
12274
|
managedBy: "@hasna/skills",
|
|
12111
|
-
skill:
|
|
12112
|
-
source:
|
|
12113
|
-
...
|
|
12114
|
-
...
|
|
12115
|
-
...
|
|
12116
|
-
...
|
|
12117
|
-
...
|
|
12275
|
+
skill: record3.skill,
|
|
12276
|
+
source: record3.source ?? "pull",
|
|
12277
|
+
...record3.version ? { version: record3.version } : {},
|
|
12278
|
+
...record3.contentHash ? { contentHash: record3.contentHash } : {},
|
|
12279
|
+
...record3.sourceCommit ? { sourceCommit: record3.sourceCommit } : {},
|
|
12280
|
+
...record3.signature ? { signature: record3.signature } : {},
|
|
12281
|
+
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
12118
12282
|
syncedAt: new Date().toISOString()
|
|
12119
12283
|
};
|
|
12120
12284
|
writeFileSync8(join17(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
@@ -12129,19 +12293,19 @@ async function safeMeta(client, slug) {
|
|
|
12129
12293
|
}
|
|
12130
12294
|
if (!raw || typeof raw !== "object")
|
|
12131
12295
|
return null;
|
|
12132
|
-
const
|
|
12133
|
-
const kind =
|
|
12134
|
-
const tags = Array.isArray(
|
|
12296
|
+
const record3 = raw;
|
|
12297
|
+
const kind = record3.kind === "instruction" || record3.kind === "executable" ? record3.kind : undefined;
|
|
12298
|
+
const tags = Array.isArray(record3.tags) ? record3.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
|
|
12135
12299
|
return {
|
|
12136
|
-
...str(
|
|
12137
|
-
...str(
|
|
12138
|
-
...str(
|
|
12300
|
+
...str(record3.displayName) ? { displayName: str(record3.displayName) } : {},
|
|
12301
|
+
...str(record3.description) ? { description: str(record3.description) } : {},
|
|
12302
|
+
...str(record3.category) ? { category: str(record3.category) } : {},
|
|
12139
12303
|
...tags && tags.length ? { tags } : {},
|
|
12140
|
-
...str(
|
|
12304
|
+
...str(record3.version) ? { version: str(record3.version) } : {},
|
|
12141
12305
|
...kind ? { kind } : {},
|
|
12142
|
-
...REVISION_ID_PATTERN.test(str(
|
|
12143
|
-
...typeof
|
|
12144
|
-
...str(
|
|
12306
|
+
...REVISION_ID_PATTERN.test(str(record3.revisionId) ?? "") ? { revisionId: str(record3.revisionId) } : {},
|
|
12307
|
+
...typeof record3.skillMd === "string" && record3.skillMd.length > 0 ? { skillMd: record3.skillMd } : {},
|
|
12308
|
+
...str(record3.publishedSource) ? { publishedSource: str(record3.publishedSource) } : {}
|
|
12145
12309
|
};
|
|
12146
12310
|
}
|
|
12147
12311
|
function pickCorpusOptions(options) {
|
|
@@ -12150,8 +12314,8 @@ function pickCorpusOptions(options) {
|
|
|
12150
12314
|
function extractSlug(entry) {
|
|
12151
12315
|
if (!entry || typeof entry !== "object")
|
|
12152
12316
|
return;
|
|
12153
|
-
const
|
|
12154
|
-
return str(
|
|
12317
|
+
const record3 = entry;
|
|
12318
|
+
return str(record3.slug) ?? str(record3.name);
|
|
12155
12319
|
}
|
|
12156
12320
|
function dedupe(values) {
|
|
12157
12321
|
return [...new Set(values)];
|
|
@@ -12277,7 +12441,7 @@ import { dirname as dirname7, relative as relative4 } from "path";
|
|
|
12277
12441
|
// package.json
|
|
12278
12442
|
var package_default = {
|
|
12279
12443
|
name: "@hasna/skills",
|
|
12280
|
-
version: "0.5.
|
|
12444
|
+
version: "0.5.1",
|
|
12281
12445
|
description: "Skills library for AI coding agents",
|
|
12282
12446
|
type: "module",
|
|
12283
12447
|
bin: {
|
|
@@ -13788,7 +13952,7 @@ class SkillsPostgresSyncStore {
|
|
|
13788
13952
|
}
|
|
13789
13953
|
async upsertRecords(records) {
|
|
13790
13954
|
let count = 0;
|
|
13791
|
-
for (const
|
|
13955
|
+
for (const record3 of records) {
|
|
13792
13956
|
await this.client.query([
|
|
13793
13957
|
"INSERT INTO skills_sync_records",
|
|
13794
13958
|
"(scope, kind, id, updated_at, deleted_at, source, payload)",
|
|
@@ -13799,13 +13963,13 @@ class SkillsPostgresSyncStore {
|
|
|
13799
13963
|
"source = EXCLUDED.source,",
|
|
13800
13964
|
"payload = EXCLUDED.payload"
|
|
13801
13965
|
].join(" "), [
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
JSON.stringify(
|
|
13966
|
+
record3.scope,
|
|
13967
|
+
record3.kind,
|
|
13968
|
+
record3.id,
|
|
13969
|
+
record3.updatedAt,
|
|
13970
|
+
record3.deletedAt ?? null,
|
|
13971
|
+
record3.source ?? null,
|
|
13972
|
+
JSON.stringify(record3.payload)
|
|
13809
13973
|
]);
|
|
13810
13974
|
count += 1;
|
|
13811
13975
|
}
|
|
@@ -14784,13 +14948,13 @@ async function requestAuthApi(instance, path, options) {
|
|
|
14784
14948
|
apiUrl: safeUrl
|
|
14785
14949
|
});
|
|
14786
14950
|
}
|
|
14787
|
-
const
|
|
14788
|
-
const body =
|
|
14951
|
+
const text2 = await res.text();
|
|
14952
|
+
const body = text2 ? parseJsonBody(text2) : {};
|
|
14789
14953
|
if (!res.ok) {
|
|
14790
|
-
const
|
|
14791
|
-
const detail = typeof
|
|
14792
|
-
const error = typeof
|
|
14793
|
-
const code = typeof
|
|
14954
|
+
const record3 = isRecord5(body) ? body : {};
|
|
14955
|
+
const detail = typeof record3.detail === "string" ? record3.detail : undefined;
|
|
14956
|
+
const error = typeof record3.error === "string" ? record3.error : undefined;
|
|
14957
|
+
const code = typeof record3.code === "string" ? record3.code : undefined;
|
|
14794
14958
|
throw new HostedApiError(detail || error || `${res.status} ${res.statusText}`, {
|
|
14795
14959
|
status: res.status,
|
|
14796
14960
|
code,
|
|
@@ -14801,15 +14965,15 @@ async function requestAuthApi(instance, path, options) {
|
|
|
14801
14965
|
}
|
|
14802
14966
|
return body;
|
|
14803
14967
|
}
|
|
14804
|
-
function parseJsonBody(
|
|
14968
|
+
function parseJsonBody(text2) {
|
|
14805
14969
|
try {
|
|
14806
|
-
return JSON.parse(
|
|
14970
|
+
return JSON.parse(text2);
|
|
14807
14971
|
} catch {
|
|
14808
|
-
return { detail: condenseErrorBody(
|
|
14972
|
+
return { detail: condenseErrorBody(text2) };
|
|
14809
14973
|
}
|
|
14810
14974
|
}
|
|
14811
|
-
function condenseErrorBody(
|
|
14812
|
-
const stripped = /<[a-z!/]/i.test(
|
|
14975
|
+
function condenseErrorBody(text2) {
|
|
14976
|
+
const stripped = /<[a-z!/]/i.test(text2) ? text2.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text2;
|
|
14813
14977
|
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
14814
14978
|
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
14815
14979
|
return collapsed;
|
|
@@ -14836,7 +15000,12 @@ class RemoteSkillsAuthClient {
|
|
|
14836
15000
|
pollDevice(deviceCode) {
|
|
14837
15001
|
return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
|
|
14838
15002
|
}
|
|
14839
|
-
async sessionClient(email, code) {
|
|
15003
|
+
async sessionClient(email, code, context) {
|
|
15004
|
+
if (context !== undefined) {
|
|
15005
|
+
const target = workspaceContext(context), apiOrigin2 = this.apiOrigin;
|
|
15006
|
+
const session = await this.switchWorkspace(email, code, target);
|
|
15007
|
+
return new RemoteSkillsClient(session.token, apiOrigin2);
|
|
15008
|
+
}
|
|
14840
15009
|
const apiOrigin = this.apiOrigin;
|
|
14841
15010
|
if (!email.includes("@") || !/^\d{6}$/.test(code))
|
|
14842
15011
|
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
@@ -14845,34 +15014,76 @@ class RemoteSkillsAuthClient {
|
|
|
14845
15014
|
throw new Error("The server did not return an authorized account session");
|
|
14846
15015
|
return new RemoteSkillsClient(login.token, apiOrigin);
|
|
14847
15016
|
}
|
|
14848
|
-
async
|
|
14849
|
-
|
|
15017
|
+
async listAccountWorkspaces(email, code, expectedUserId) {
|
|
15018
|
+
const login = await this.workspaceLogin(email, code, expectedUserId);
|
|
15019
|
+
const result = await new RemoteSkillsClient(login.token, login.apiOrigin).listAccountWorkspaces(login.userId);
|
|
15020
|
+
return { userId: login.userId, ...result };
|
|
14850
15021
|
}
|
|
14851
|
-
async
|
|
14852
|
-
|
|
15022
|
+
async switchWorkspace(email, code, context) {
|
|
15023
|
+
const target = workspaceContext(context);
|
|
15024
|
+
const login = await this.workspaceLogin(email, code, target.userId);
|
|
15025
|
+
return new RemoteSkillsClient(login.token, login.apiOrigin).switchWorkspace(target);
|
|
14853
15026
|
}
|
|
14854
|
-
async
|
|
14855
|
-
|
|
15027
|
+
async workspaceLogin(email, code, expectedUserId) {
|
|
15028
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
15029
|
+
const apiOrigin = this.apiOrigin;
|
|
15030
|
+
if (typeof email !== "string" || !email.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
|
|
15031
|
+
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
15032
|
+
let response;
|
|
15033
|
+
try {
|
|
15034
|
+
response = await fetch(`${apiOrigin}/api/auth/verify`, {
|
|
15035
|
+
method: "POST",
|
|
15036
|
+
redirect: "error",
|
|
15037
|
+
credentials: "omit",
|
|
15038
|
+
signal: AbortSignal.timeout(15000),
|
|
15039
|
+
headers: { "Content-Type": "application/json" },
|
|
15040
|
+
body: JSON.stringify({ email, code })
|
|
15041
|
+
});
|
|
15042
|
+
} catch {
|
|
15043
|
+
throw new HostedApiError("Unable to verify the Skills account.");
|
|
15044
|
+
}
|
|
15045
|
+
if (!response.ok) {
|
|
15046
|
+
response.body?.cancel().catch(() => {});
|
|
15047
|
+
throw new HostedApiError("Unable to verify the Skills account.", { status: response.status });
|
|
15048
|
+
}
|
|
15049
|
+
let value;
|
|
15050
|
+
try {
|
|
15051
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, 64 * 1024)));
|
|
15052
|
+
} catch {
|
|
15053
|
+
throw new HostedApiError("The server returned an invalid account verification result.");
|
|
15054
|
+
}
|
|
15055
|
+
return { ...parseWorkspaceLogin(value, expected), apiOrigin };
|
|
15056
|
+
}
|
|
15057
|
+
async createApiKey(email, code, name, scopes, context) {
|
|
15058
|
+
const capturedScopes = scopes === undefined ? undefined : [...scopes];
|
|
15059
|
+
return (await this.sessionClient(email, code, context)).createApiKey(name, capturedScopes);
|
|
15060
|
+
}
|
|
15061
|
+
async listApiKeys(email, code, context) {
|
|
15062
|
+
return (await this.sessionClient(email, code, context)).listApiKeys();
|
|
14856
15063
|
}
|
|
14857
|
-
async
|
|
14858
|
-
|
|
14859
|
-
return (await this.sessionClient(email, code)).updateProfile(input);
|
|
15064
|
+
async revokeApiKey(email, code, keyId, context) {
|
|
15065
|
+
return (await this.sessionClient(email, code, context)).revokeApiKey(keyId);
|
|
14860
15066
|
}
|
|
14861
|
-
async
|
|
14862
|
-
customerNamePatch(input, "
|
|
14863
|
-
return (await this.sessionClient(email, code)).
|
|
15067
|
+
async updateProfile(email, code, input, context) {
|
|
15068
|
+
const body = customerNamePatch(input, "displayName");
|
|
15069
|
+
return (await this.sessionClient(email, code, context)).updateProfile({ displayName: body.displayName });
|
|
15070
|
+
}
|
|
15071
|
+
async updateCurrentWorkspace(email, code, input, context) {
|
|
15072
|
+
const body = customerNamePatch(input, "name");
|
|
15073
|
+
return (await this.sessionClient(email, code, context)).updateCurrentWorkspace({ name: body.name });
|
|
14864
15074
|
}
|
|
14865
|
-
async listWorkspaceMembers(email, code, options = {}) {
|
|
15075
|
+
async listWorkspaceMembers(email, code, options = {}, context) {
|
|
14866
15076
|
workspaceMembersQuery(options);
|
|
14867
|
-
|
|
15077
|
+
const captured = { ...options };
|
|
15078
|
+
return (await this.sessionClient(email, code, context)).listWorkspaceMembers(captured);
|
|
14868
15079
|
}
|
|
14869
|
-
async setWorkspaceMemberRole(email, code, membershipId, input) {
|
|
15080
|
+
async setWorkspaceMemberRole(email, code, membershipId, input, context) {
|
|
14870
15081
|
const captured = workspaceMemberRoleInput(membershipId, input);
|
|
14871
|
-
return (await this.sessionClient(email, code)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
15082
|
+
return (await this.sessionClient(email, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
14872
15083
|
}
|
|
14873
|
-
async removeWorkspaceMember(email, code, membershipId, input) {
|
|
15084
|
+
async removeWorkspaceMember(email, code, membershipId, input, context) {
|
|
14874
15085
|
const captured = workspaceMemberRemovalInput(membershipId, input);
|
|
14875
|
-
return (await this.sessionClient(email, code)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
15086
|
+
return (await this.sessionClient(email, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
14876
15087
|
}
|
|
14877
15088
|
request(path, options) {
|
|
14878
15089
|
if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
|
|
@@ -15062,6 +15273,8 @@ export {
|
|
|
15062
15273
|
agentGlobalSkillsDir,
|
|
15063
15274
|
addSchedule,
|
|
15064
15275
|
adaptSkillMdForAgent,
|
|
15276
|
+
WorkspaceIdentityMismatchError,
|
|
15277
|
+
WorkspaceContextInputError,
|
|
15065
15278
|
TOOL_PRIMITIVE_SCHEMA_VERSION,
|
|
15066
15279
|
TOOL_PRIMITIVES,
|
|
15067
15280
|
StationSnapshotError,
|
|
@@ -15093,6 +15306,7 @@ export {
|
|
|
15093
15306
|
SKILLS_API_KEY_ENV_KEYS,
|
|
15094
15307
|
SKILLS_API_KEY_ENV,
|
|
15095
15308
|
SKILLS,
|
|
15309
|
+
RemoteWorkspaceSelectionError,
|
|
15096
15310
|
RemoteWorkspaceMemberError,
|
|
15097
15311
|
RemoteSkillsClient,
|
|
15098
15312
|
RemoteSkillsAuthClient,
|