@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/bin/index.js
CHANGED
|
@@ -36860,7 +36860,7 @@ var package_default;
|
|
|
36860
36860
|
var init_package = __esm(() => {
|
|
36861
36861
|
package_default = {
|
|
36862
36862
|
name: "@hasna/skills",
|
|
36863
|
-
version: "0.5.
|
|
36863
|
+
version: "0.5.1",
|
|
36864
36864
|
description: "Skills library for AI coding agents",
|
|
36865
36865
|
type: "module",
|
|
36866
36866
|
bin: {
|
|
@@ -49045,9 +49045,99 @@ var init_read_access = __esm(() => {
|
|
|
49045
49045
|
init_remote_registry();
|
|
49046
49046
|
});
|
|
49047
49047
|
|
|
49048
|
+
// src/lib/remote-workspace-selection.ts
|
|
49049
|
+
function workspaceExpectedUserId(value) {
|
|
49050
|
+
if (!uuid(value))
|
|
49051
|
+
throw new WorkspaceContextInputError;
|
|
49052
|
+
return value;
|
|
49053
|
+
}
|
|
49054
|
+
function workspaceContext(value) {
|
|
49055
|
+
if (!record(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid(value.userId) || !uuid(value.membershipId))
|
|
49056
|
+
throw new WorkspaceContextInputError;
|
|
49057
|
+
return { userId: value.userId, membershipId: value.membershipId };
|
|
49058
|
+
}
|
|
49059
|
+
function invalid() {
|
|
49060
|
+
throw new Error(invalidWorkspaceResult);
|
|
49061
|
+
}
|
|
49062
|
+
function organization(v) {
|
|
49063
|
+
if (!record(v) || !uuid(v.id) || !text(v.slug) || !text(v.name))
|
|
49064
|
+
return invalid();
|
|
49065
|
+
return { id: v.id, slug: v.slug, name: v.name };
|
|
49066
|
+
}
|
|
49067
|
+
function parseAccountWorkspaces(value) {
|
|
49068
|
+
if (!record(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
|
|
49069
|
+
return invalid();
|
|
49070
|
+
const workspaces = value.workspaces.map((v) => {
|
|
49071
|
+
if (!record(v) || !uuid(v.membershipId) || !role(v.role) || typeof v.current !== "boolean")
|
|
49072
|
+
return invalid();
|
|
49073
|
+
return { membershipId: v.membershipId, organization: organization(v.organization), role: v.role, current: v.current };
|
|
49074
|
+
});
|
|
49075
|
+
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)
|
|
49076
|
+
return invalid();
|
|
49077
|
+
return { workspaces };
|
|
49078
|
+
}
|
|
49079
|
+
function parseWorkspaceIdentity(value, expectedUserId) {
|
|
49080
|
+
if (!record(value))
|
|
49081
|
+
return invalid();
|
|
49082
|
+
const user = value.user;
|
|
49083
|
+
if (!record(user) || !uuid(user.id) || !uuid(user.membershipId) || !text(user.email, 320) || !(user.displayName === null || text(user.displayName)) || !role(user.role))
|
|
49084
|
+
return invalid();
|
|
49085
|
+
if (user.id !== expectedUserId)
|
|
49086
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49087
|
+
return { user: { id: user.id, membershipId: user.membershipId, email: user.email, displayName: user.displayName, role: user.role }, organization: organization(value.organization) };
|
|
49088
|
+
}
|
|
49089
|
+
function sessionToken(value) {
|
|
49090
|
+
if (typeof value !== "string" || !value || value.length > 8192 || /[^\x21-\x7e]/.test(value) || value.startsWith("sk_"))
|
|
49091
|
+
return invalid();
|
|
49092
|
+
return value;
|
|
49093
|
+
}
|
|
49094
|
+
function parseWorkspaceSession(value, expected) {
|
|
49095
|
+
const identity2 = parseWorkspaceIdentity(value, expected.userId);
|
|
49096
|
+
if (identity2.user.membershipId !== expected.membershipId)
|
|
49097
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49098
|
+
return { token: sessionToken(value.token), ...identity2 };
|
|
49099
|
+
}
|
|
49100
|
+
function parseWorkspaceLogin(value, expectedUserId) {
|
|
49101
|
+
const user = record(value) && value.user;
|
|
49102
|
+
if (!record(value) || !record(user) || !uuid(user.id))
|
|
49103
|
+
return invalid();
|
|
49104
|
+
if (expectedUserId !== undefined && user.id !== expectedUserId)
|
|
49105
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49106
|
+
return { token: sessionToken(value.token), userId: user.id };
|
|
49107
|
+
}
|
|
49108
|
+
function workspaceSelectionFailure(value, status) {
|
|
49109
|
+
if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
|
|
49110
|
+
return null;
|
|
49111
|
+
const code = value.code;
|
|
49112
|
+
return workspaceSelectionFailures[code][0] === status ? code : null;
|
|
49113
|
+
}
|
|
49114
|
+
var record = (v) => !!v && typeof v === "object" && !Array.isArray(v), 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), text = (v, max2 = 1024) => typeof v === "string" && !!v.trim() && v.length <= max2 && !/[\p{Cc}\p{Cs}\u2028\u2029]/u.test(v), role = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v), invalidWorkspaceResult = "The server returned an invalid workspace selection result.", WorkspaceContextInputError, WorkspaceIdentityMismatchError, workspaceSelectionFailures;
|
|
49115
|
+
var init_remote_workspace_selection = __esm(() => {
|
|
49116
|
+
WorkspaceContextInputError = class WorkspaceContextInputError extends Error {
|
|
49117
|
+
constructor() {
|
|
49118
|
+
super("Provide the observed user ID and exact lowercase membership ID.");
|
|
49119
|
+
this.name = "WorkspaceContextInputError";
|
|
49120
|
+
}
|
|
49121
|
+
};
|
|
49122
|
+
WorkspaceIdentityMismatchError = class WorkspaceIdentityMismatchError extends Error {
|
|
49123
|
+
constructor() {
|
|
49124
|
+
super("The verified account does not match the requested workspace context.");
|
|
49125
|
+
this.name = "WorkspaceIdentityMismatchError";
|
|
49126
|
+
}
|
|
49127
|
+
};
|
|
49128
|
+
workspaceSelectionFailures = {
|
|
49129
|
+
INVALID_WORKSPACE_SELECTION: [400, "Provide only the exact membership ID from your workspace list."],
|
|
49130
|
+
SESSION_EXPIRED: [401, "Sign in again before selecting a workspace."],
|
|
49131
|
+
ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
|
|
49132
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "Interactive sign-in is required to select a workspace."],
|
|
49133
|
+
WORKSPACE_UNAVAILABLE: [404, "Workspace is unavailable. Refresh your workspace list."],
|
|
49134
|
+
WORKSPACE_BUSY: [503, "Workspace is busy. Refresh before retrying."]
|
|
49135
|
+
};
|
|
49136
|
+
});
|
|
49137
|
+
|
|
49048
49138
|
// src/lib/remote-workspace.ts
|
|
49049
49139
|
function workspaceMembersQuery(options = {}) {
|
|
49050
|
-
if (!
|
|
49140
|
+
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))
|
|
49051
49141
|
throw new Error("Use a roster limit from 1 to 100 and an unchanged continuation cursor.");
|
|
49052
49142
|
const query = new URLSearchParams;
|
|
49053
49143
|
if (options.limit !== undefined)
|
|
@@ -49063,7 +49153,7 @@ function timestamp(value) {
|
|
|
49063
49153
|
return Number.isFinite(time) && new Date(time).toISOString().slice(0, 23) === value.slice(0, 23);
|
|
49064
49154
|
}
|
|
49065
49155
|
function parseMember(row, fail2) {
|
|
49066
|
-
if (!
|
|
49156
|
+
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))
|
|
49067
49157
|
return fail2();
|
|
49068
49158
|
return {
|
|
49069
49159
|
membershipId: row.membershipId,
|
|
@@ -49075,12 +49165,12 @@ function parseMember(row, fail2) {
|
|
|
49075
49165
|
};
|
|
49076
49166
|
}
|
|
49077
49167
|
function mutationInput(membershipId, input, roleChange) {
|
|
49078
|
-
if (typeof membershipId !== "string" || !
|
|
49168
|
+
if (typeof membershipId !== "string" || !uuid2(membershipId) || membershipId !== membershipId.toLowerCase() || !record2(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
|
|
49079
49169
|
throw new WorkspaceMemberInputError;
|
|
49080
|
-
const expectedRole = input.expectedRole,
|
|
49081
|
-
if (!isRole(expectedRole) || roleChange && !isRole(
|
|
49170
|
+
const expectedRole = input.expectedRole, role2 = roleChange ? input.role : undefined;
|
|
49171
|
+
if (!isRole(expectedRole) || roleChange && !isRole(role2))
|
|
49082
49172
|
throw new WorkspaceMemberInputError;
|
|
49083
|
-
return { membershipId, role, expectedRole };
|
|
49173
|
+
return { membershipId, role: role2, expectedRole };
|
|
49084
49174
|
}
|
|
49085
49175
|
function workspaceMemberRoleInput(membershipId, input) {
|
|
49086
49176
|
const value = mutationInput(membershipId, input, true);
|
|
@@ -49090,24 +49180,24 @@ function workspaceMemberRemovalInput(membershipId, input) {
|
|
|
49090
49180
|
const value = mutationInput(membershipId, input, false);
|
|
49091
49181
|
return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
|
|
49092
49182
|
}
|
|
49093
|
-
function parseWorkspaceMemberRoleResult(value, membershipId,
|
|
49183
|
+
function parseWorkspaceMemberRoleResult(value, membershipId, role2) {
|
|
49094
49184
|
const fail2 = () => {
|
|
49095
49185
|
throw new Error(invalidMemberResult);
|
|
49096
49186
|
};
|
|
49097
|
-
if (!
|
|
49187
|
+
if (!record2(value) || !uuid2(value.organizationId) || typeof value.changed !== "boolean")
|
|
49098
49188
|
return fail2();
|
|
49099
49189
|
const member = parseMember(value.member, fail2);
|
|
49100
|
-
if (member.membershipId !== membershipId || member.role !==
|
|
49190
|
+
if (member.membershipId !== membershipId || member.role !== role2)
|
|
49101
49191
|
return fail2();
|
|
49102
49192
|
return { organizationId: value.organizationId, member, changed: value.changed };
|
|
49103
49193
|
}
|
|
49104
49194
|
function parseWorkspaceMemberRemovalResult(value, membershipId) {
|
|
49105
|
-
if (!
|
|
49195
|
+
if (!record2(value) || !uuid2(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
|
|
49106
49196
|
throw new Error(invalidMemberResult);
|
|
49107
49197
|
return { organizationId: value.organizationId, membershipId, removed: true, alreadyRemoved: value.alreadyRemoved };
|
|
49108
49198
|
}
|
|
49109
49199
|
function workspaceMemberFailure(value, status) {
|
|
49110
|
-
if (!
|
|
49200
|
+
if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
|
|
49111
49201
|
return null;
|
|
49112
49202
|
const code = value.code;
|
|
49113
49203
|
return workspaceMemberFailures[code][0] === status ? code : null;
|
|
@@ -49116,14 +49206,14 @@ function parseWorkspaceMembersPage(value) {
|
|
|
49116
49206
|
const fail2 = () => {
|
|
49117
49207
|
throw new Error("The server returned an invalid workspace roster.");
|
|
49118
49208
|
};
|
|
49119
|
-
if (!
|
|
49209
|
+
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)
|
|
49120
49210
|
return fail2();
|
|
49121
49211
|
const members = value.members.map((row) => parseMember(row, fail2));
|
|
49122
49212
|
if (new Set(members.map((row) => row.membershipId)).size !== members.length)
|
|
49123
49213
|
return fail2();
|
|
49124
49214
|
return { organizationId: value.organizationId, members, nextCursor: value.nextCursor };
|
|
49125
49215
|
}
|
|
49126
|
-
var
|
|
49216
|
+
var record2 = (value) => !!value && typeof value === "object" && !Array.isArray(value), cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value), 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), isRole = (value) => typeof value === "string" && ["owner", "admin", "member", "viewer"].includes(value), WorkspaceMemberInputError, invalidMemberResult = "The server returned an invalid workspace member result. Refresh the roster before another action.", workspaceMemberFailures;
|
|
49127
49217
|
var init_remote_workspace = __esm(() => {
|
|
49128
49218
|
WorkspaceMemberInputError = class WorkspaceMemberInputError extends Error {
|
|
49129
49219
|
constructor() {
|
|
@@ -49163,14 +49253,14 @@ function readIdentity(env3 = process.env) {
|
|
|
49163
49253
|
const parsed = JSON.parse(readFileSync12(getIdentityFilePath(env3), "utf-8"));
|
|
49164
49254
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
49165
49255
|
return {};
|
|
49166
|
-
const
|
|
49256
|
+
const record3 = parsed;
|
|
49167
49257
|
const selected = resolveSkillsApiOrigin(env3)?.origin;
|
|
49168
|
-
const bound = typeof
|
|
49258
|
+
const bound = typeof record3.apiUrl === "string" ? record3.apiUrl : readCredentialValue(SKILLS_BOUND_API_URL, env3) ?? readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills");
|
|
49169
49259
|
if (selected && normalizeSkillsApiOrigin(bound) !== selected)
|
|
49170
49260
|
return {};
|
|
49171
49261
|
const identity2 = {};
|
|
49172
49262
|
for (const field of ["email", "orgId", "orgSlug", "userId"]) {
|
|
49173
|
-
const value =
|
|
49263
|
+
const value = record3[field];
|
|
49174
49264
|
if (typeof value === "string" && value.length > 0)
|
|
49175
49265
|
identity2[field] = value;
|
|
49176
49266
|
}
|
|
@@ -49319,44 +49409,44 @@ var init_auth_store = __esm(() => {
|
|
|
49319
49409
|
|
|
49320
49410
|
// src/lib/remote-run-contract.ts
|
|
49321
49411
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
49322
|
-
const
|
|
49412
|
+
const record3 = isRecord3(payload) ? payload : {};
|
|
49323
49413
|
return {
|
|
49324
49414
|
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
49325
|
-
...pickString(
|
|
49326
|
-
skill: pickStringValue(
|
|
49327
|
-
...pickString(
|
|
49328
|
-
...pickString(
|
|
49329
|
-
...pickNumber(
|
|
49330
|
-
...pickString(
|
|
49331
|
-
...pickString(
|
|
49332
|
-
...pickString(
|
|
49333
|
-
...pickString(
|
|
49334
|
-
...pickNumber(
|
|
49335
|
-
...pickString(
|
|
49336
|
-
...hasOwn(
|
|
49337
|
-
...pickString(
|
|
49338
|
-
...pickString(
|
|
49339
|
-
...pickString(
|
|
49340
|
-
...pickString(
|
|
49341
|
-
...hasOwn(
|
|
49415
|
+
...pickString(record3, "id"),
|
|
49416
|
+
skill: pickStringValue(record3, "skill") ?? fallbackSkill,
|
|
49417
|
+
...pickString(record3, "requestedSlug"),
|
|
49418
|
+
...pickString(record3, "status"),
|
|
49419
|
+
...pickNumber(record3, "exitCode"),
|
|
49420
|
+
...pickString(record3, "correlationId"),
|
|
49421
|
+
...pickString(record3, "createdAt"),
|
|
49422
|
+
...pickString(record3, "startedAt"),
|
|
49423
|
+
...pickString(record3, "completedAt"),
|
|
49424
|
+
...pickNumber(record3, "durationMs"),
|
|
49425
|
+
...pickString(record3, "outputType"),
|
|
49426
|
+
...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
|
|
49427
|
+
...pickString(record3, "errorCode"),
|
|
49428
|
+
...pickString(record3, "errorMessage"),
|
|
49429
|
+
...pickString(record3, "error"),
|
|
49430
|
+
...pickString(record3, "code"),
|
|
49431
|
+
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
49342
49432
|
};
|
|
49343
49433
|
}
|
|
49344
49434
|
function isRecord3(value) {
|
|
49345
49435
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
49346
49436
|
}
|
|
49347
|
-
function hasOwn(
|
|
49348
|
-
return Object.prototype.hasOwnProperty.call(
|
|
49437
|
+
function hasOwn(record3, key) {
|
|
49438
|
+
return Object.prototype.hasOwnProperty.call(record3, key);
|
|
49349
49439
|
}
|
|
49350
|
-
function pickString(
|
|
49351
|
-
const value = pickStringValue(
|
|
49440
|
+
function pickString(record3, key) {
|
|
49441
|
+
const value = pickStringValue(record3, key);
|
|
49352
49442
|
return value === undefined ? {} : { [key]: value };
|
|
49353
49443
|
}
|
|
49354
|
-
function pickStringValue(
|
|
49355
|
-
const value =
|
|
49444
|
+
function pickStringValue(record3, key) {
|
|
49445
|
+
const value = record3[key];
|
|
49356
49446
|
return typeof value === "string" ? value : undefined;
|
|
49357
49447
|
}
|
|
49358
|
-
function pickNumber(
|
|
49359
|
-
const value =
|
|
49448
|
+
function pickNumber(record3, key) {
|
|
49449
|
+
const value = record3[key];
|
|
49360
49450
|
return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
|
|
49361
49451
|
}
|
|
49362
49452
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
@@ -49548,11 +49638,11 @@ function parseUpdatedProfile(value) {
|
|
|
49548
49638
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
49549
49639
|
}
|
|
49550
49640
|
function parseUpdatedWorkspace(value) {
|
|
49551
|
-
const
|
|
49552
|
-
if (!isRecord4(
|
|
49641
|
+
const organization2 = isRecord4(value) && value.organization;
|
|
49642
|
+
if (!isRecord4(organization2) || !string(organization2.id) || !string(organization2.slug) || !string(organization2.name)) {
|
|
49553
49643
|
throw new Error("The server returned an invalid workspace.");
|
|
49554
49644
|
}
|
|
49555
|
-
return { organization: { id:
|
|
49645
|
+
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
49556
49646
|
}
|
|
49557
49647
|
|
|
49558
49648
|
// src/lib/remote-client.ts
|
|
@@ -49560,6 +49650,7 @@ var exports_remote_client = {};
|
|
|
49560
49650
|
__export(exports_remote_client, {
|
|
49561
49651
|
createRemoteSkillsClientReadOnly: () => createRemoteSkillsClientReadOnly,
|
|
49562
49652
|
createRemoteSkillsClient: () => createRemoteSkillsClient,
|
|
49653
|
+
RemoteWorkspaceSelectionError: () => RemoteWorkspaceSelectionError,
|
|
49563
49654
|
RemoteWorkspaceMemberError: () => RemoteWorkspaceMemberError,
|
|
49564
49655
|
RemoteSkillsClient: () => RemoteSkillsClient,
|
|
49565
49656
|
RemoteRouteUnsupportedError: () => RemoteRouteUnsupportedError,
|
|
@@ -49579,6 +49670,7 @@ class RemoteSkillsClient {
|
|
|
49579
49670
|
return fetch(`${this.apiUrl}${path}`, {
|
|
49580
49671
|
...options,
|
|
49581
49672
|
redirect: "error",
|
|
49673
|
+
credentials: "omit",
|
|
49582
49674
|
signal: options?.signal ?? AbortSignal.timeout(15000),
|
|
49583
49675
|
headers: {
|
|
49584
49676
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -49685,6 +49777,65 @@ class RemoteSkillsClient {
|
|
|
49685
49777
|
async getIdentity() {
|
|
49686
49778
|
return (await this.requestNewRoute("/api/auth/whoami")).json();
|
|
49687
49779
|
}
|
|
49780
|
+
async listAccountWorkspaces(expectedUserId) {
|
|
49781
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
49782
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
49783
|
+
let identity2;
|
|
49784
|
+
if (expected !== undefined) {
|
|
49785
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
49786
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
49787
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces", "INTERACTIVE_SESSION_REQUIRED");
|
|
49788
|
+
identity2 = parseWorkspaceIdentity(value, expected);
|
|
49789
|
+
}
|
|
49790
|
+
const result2 = parseAccountWorkspaces(await connection.requestWorkspaceSelection("/api/v1/account/workspaces"));
|
|
49791
|
+
const current = result2.workspaces.find((workspace) => workspace.current);
|
|
49792
|
+
if (identity2 && (current.membershipId !== identity2.user.membershipId || current.organization.id !== identity2.organization.id))
|
|
49793
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49794
|
+
return result2;
|
|
49795
|
+
}
|
|
49796
|
+
async switchWorkspace(context) {
|
|
49797
|
+
const target = workspaceContext(context);
|
|
49798
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
49799
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
49800
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
49801
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
49802
|
+
parseWorkspaceIdentity(value, target.userId);
|
|
49803
|
+
const selected = parseWorkspaceSession(await connection.requestWorkspaceSelection("/api/v1/account/workspaces/switch", {
|
|
49804
|
+
method: "POST",
|
|
49805
|
+
body: JSON.stringify({ membershipId: target.membershipId })
|
|
49806
|
+
}), target);
|
|
49807
|
+
const verified = await new RemoteSkillsClient(selected.token, connection.apiUrl).requestWorkspaceSelection("/api/auth/whoami");
|
|
49808
|
+
if (!verified || typeof verified !== "object" || verified.authMethod !== "jwt")
|
|
49809
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
49810
|
+
const identity2 = parseWorkspaceIdentity(verified, target.userId);
|
|
49811
|
+
if (identity2.user.membershipId !== target.membershipId || identity2.organization.id !== selected.organization.id)
|
|
49812
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49813
|
+
return { token: selected.token, ...identity2 };
|
|
49814
|
+
}
|
|
49815
|
+
async requestWorkspaceSelection(path, options) {
|
|
49816
|
+
let response;
|
|
49817
|
+
try {
|
|
49818
|
+
response = await this.request(path, { ...options, credentials: "omit" });
|
|
49819
|
+
} catch {
|
|
49820
|
+
throw new Error("Unable to reach the Skills workspace API.");
|
|
49821
|
+
}
|
|
49822
|
+
let value;
|
|
49823
|
+
try {
|
|
49824
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 1024 * 1024 : 4096)));
|
|
49825
|
+
} catch {
|
|
49826
|
+
if (response.ok)
|
|
49827
|
+
throw new Error(invalidWorkspaceResult);
|
|
49828
|
+
}
|
|
49829
|
+
if (!response.ok) {
|
|
49830
|
+
const code = workspaceSelectionFailure(value, response.status);
|
|
49831
|
+
if (code)
|
|
49832
|
+
throw new RemoteWorkspaceSelectionError(path, code);
|
|
49833
|
+
if (response.status === 404 || response.status === 405)
|
|
49834
|
+
throw new RemoteRouteUnsupportedError(path, response.status, this.apiUrl);
|
|
49835
|
+
throw new RemoteRequestError(path, response.status);
|
|
49836
|
+
}
|
|
49837
|
+
return value;
|
|
49838
|
+
}
|
|
49688
49839
|
async updateProfile(input) {
|
|
49689
49840
|
const body = customerNamePatch(input, "displayName");
|
|
49690
49841
|
return parseUpdatedProfile(await (await this.requestNewRoute("/api/v1/account/profile", { method: "PATCH", body: JSON.stringify(body) })).json());
|
|
@@ -49987,13 +50138,13 @@ class RemoteSkillsClient {
|
|
|
49987
50138
|
return normalizeUpdatedSincePage(await response.json());
|
|
49988
50139
|
}
|
|
49989
50140
|
}
|
|
49990
|
-
function requireOptionalString(
|
|
49991
|
-
if (
|
|
50141
|
+
function requireOptionalString(record3, field) {
|
|
50142
|
+
if (record3[field] === undefined)
|
|
49992
50143
|
return;
|
|
49993
|
-
if (typeof
|
|
50144
|
+
if (typeof record3[field] !== "string") {
|
|
49994
50145
|
throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
|
|
49995
50146
|
}
|
|
49996
|
-
return
|
|
50147
|
+
return record3[field];
|
|
49997
50148
|
}
|
|
49998
50149
|
function isVersionRecord(value) {
|
|
49999
50150
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -50015,19 +50166,19 @@ function normalizePin(entry) {
|
|
|
50015
50166
|
if (!entry || typeof entry !== "object") {
|
|
50016
50167
|
throw new Error("Remote pin payload did not match the expected contract (expected an object)");
|
|
50017
50168
|
}
|
|
50018
|
-
const
|
|
50019
|
-
const slug = typeof
|
|
50169
|
+
const record3 = entry;
|
|
50170
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
50020
50171
|
if (!slug) {
|
|
50021
50172
|
throw new Error("Remote pin payload did not match the expected contract (missing slug)");
|
|
50022
50173
|
}
|
|
50023
50174
|
let metadata;
|
|
50024
|
-
if (
|
|
50025
|
-
if (!
|
|
50175
|
+
if (record3.metadata !== undefined) {
|
|
50176
|
+
if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
|
|
50026
50177
|
throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
|
|
50027
50178
|
}
|
|
50028
|
-
metadata =
|
|
50179
|
+
metadata = record3.metadata;
|
|
50029
50180
|
}
|
|
50030
|
-
const pinnedAt = requireOptionalString(
|
|
50181
|
+
const pinnedAt = requireOptionalString(record3, "pinnedAt");
|
|
50031
50182
|
return {
|
|
50032
50183
|
slug,
|
|
50033
50184
|
...pinnedAt !== undefined ? { pinnedAt } : {},
|
|
@@ -50044,16 +50195,16 @@ function normalizeSkillSummary(entry) {
|
|
|
50044
50195
|
if (!entry || typeof entry !== "object") {
|
|
50045
50196
|
throw new Error("Remote skill payload did not match the expected contract (expected an object)");
|
|
50046
50197
|
}
|
|
50047
|
-
const
|
|
50048
|
-
const slug = typeof
|
|
50198
|
+
const record3 = entry;
|
|
50199
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
50049
50200
|
if (!slug) {
|
|
50050
50201
|
throw new Error("Remote skill payload did not match the expected contract (missing slug)");
|
|
50051
50202
|
}
|
|
50052
50203
|
return {
|
|
50053
50204
|
slug,
|
|
50054
|
-
...requireOptionalString(
|
|
50055
|
-
...requireOptionalString(
|
|
50056
|
-
...requireOptionalString(
|
|
50205
|
+
...requireOptionalString(record3, "name") !== undefined ? { name: requireOptionalString(record3, "name") } : {},
|
|
50206
|
+
...requireOptionalString(record3, "version") !== undefined ? { version: requireOptionalString(record3, "version") } : {},
|
|
50207
|
+
...requireOptionalString(record3, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record3, "updatedAt") } : {}
|
|
50057
50208
|
};
|
|
50058
50209
|
}
|
|
50059
50210
|
function normalizeSkillSummaryList(payload) {
|
|
@@ -50106,12 +50257,12 @@ function normalizeUpdatedSincePage(payload) {
|
|
|
50106
50257
|
if (!payload || typeof payload !== "object") {
|
|
50107
50258
|
throw new Error("Updated-since payload did not match the expected contract (expected an object)");
|
|
50108
50259
|
}
|
|
50109
|
-
const
|
|
50110
|
-
if (!Array.isArray(
|
|
50260
|
+
const record3 = payload;
|
|
50261
|
+
if (!Array.isArray(record3.skills)) {
|
|
50111
50262
|
throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
|
|
50112
50263
|
}
|
|
50113
|
-
const skills =
|
|
50114
|
-
const nextCursor =
|
|
50264
|
+
const skills = record3.skills.map(normalizeSkillSummary);
|
|
50265
|
+
const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
|
|
50115
50266
|
if (nextCursor !== null && typeof nextCursor !== "string") {
|
|
50116
50267
|
throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
|
|
50117
50268
|
}
|
|
@@ -50124,8 +50275,9 @@ async function createRemoteSkillsClient(env3 = process.env) {
|
|
|
50124
50275
|
function createRemoteSkillsClientReadOnly(env3 = process.env) {
|
|
50125
50276
|
return createRemoteSkillsClient(env3);
|
|
50126
50277
|
}
|
|
50127
|
-
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
50278
|
+
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
50128
50279
|
var init_remote_client = __esm(() => {
|
|
50280
|
+
init_remote_workspace_selection();
|
|
50129
50281
|
init_remote_workspace();
|
|
50130
50282
|
init_remote_workspace();
|
|
50131
50283
|
init_auth_store();
|
|
@@ -50163,6 +50315,15 @@ var init_remote_client = __esm(() => {
|
|
|
50163
50315
|
this.message = workspaceMemberFailures[code][1];
|
|
50164
50316
|
}
|
|
50165
50317
|
};
|
|
50318
|
+
RemoteWorkspaceSelectionError = class RemoteWorkspaceSelectionError extends RemoteRequestError {
|
|
50319
|
+
code;
|
|
50320
|
+
constructor(path, code) {
|
|
50321
|
+
super(path, workspaceSelectionFailures[code][0]);
|
|
50322
|
+
this.code = code;
|
|
50323
|
+
this.name = "RemoteWorkspaceSelectionError";
|
|
50324
|
+
this.message = workspaceSelectionFailures[code][1];
|
|
50325
|
+
}
|
|
50326
|
+
};
|
|
50166
50327
|
RemoteCapabilityUnavailableError = class RemoteCapabilityUnavailableError extends RemoteRequestError {
|
|
50167
50328
|
code = "SUBSCRIPTION_CHECKOUT_UNAVAILABLE";
|
|
50168
50329
|
constructor() {
|
|
@@ -50891,16 +51052,16 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
50891
51052
|
}
|
|
50892
51053
|
return { path: target, created };
|
|
50893
51054
|
}
|
|
50894
|
-
function writePullMarker(dir,
|
|
51055
|
+
function writePullMarker(dir, record3) {
|
|
50895
51056
|
const marker = {
|
|
50896
51057
|
managedBy: "@hasna/skills",
|
|
50897
|
-
skill:
|
|
50898
|
-
source:
|
|
50899
|
-
...
|
|
50900
|
-
...
|
|
50901
|
-
...
|
|
50902
|
-
...
|
|
50903
|
-
...
|
|
51058
|
+
skill: record3.skill,
|
|
51059
|
+
source: record3.source ?? "pull",
|
|
51060
|
+
...record3.version ? { version: record3.version } : {},
|
|
51061
|
+
...record3.contentHash ? { contentHash: record3.contentHash } : {},
|
|
51062
|
+
...record3.sourceCommit ? { sourceCommit: record3.sourceCommit } : {},
|
|
51063
|
+
...record3.signature ? { signature: record3.signature } : {},
|
|
51064
|
+
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
50904
51065
|
syncedAt: new Date().toISOString()
|
|
50905
51066
|
};
|
|
50906
51067
|
writeFileSync8(join20(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
@@ -50915,19 +51076,19 @@ async function safeMeta(client, slug) {
|
|
|
50915
51076
|
}
|
|
50916
51077
|
if (!raw || typeof raw !== "object")
|
|
50917
51078
|
return null;
|
|
50918
|
-
const
|
|
50919
|
-
const kind =
|
|
50920
|
-
const tags = Array.isArray(
|
|
51079
|
+
const record3 = raw;
|
|
51080
|
+
const kind = record3.kind === "instruction" || record3.kind === "executable" ? record3.kind : undefined;
|
|
51081
|
+
const tags = Array.isArray(record3.tags) ? record3.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
|
|
50921
51082
|
return {
|
|
50922
|
-
...str(
|
|
50923
|
-
...str(
|
|
50924
|
-
...str(
|
|
51083
|
+
...str(record3.displayName) ? { displayName: str(record3.displayName) } : {},
|
|
51084
|
+
...str(record3.description) ? { description: str(record3.description) } : {},
|
|
51085
|
+
...str(record3.category) ? { category: str(record3.category) } : {},
|
|
50925
51086
|
...tags && tags.length ? { tags } : {},
|
|
50926
|
-
...str(
|
|
51087
|
+
...str(record3.version) ? { version: str(record3.version) } : {},
|
|
50927
51088
|
...kind ? { kind } : {},
|
|
50928
|
-
...REVISION_ID_PATTERN.test(str(
|
|
50929
|
-
...typeof
|
|
50930
|
-
...str(
|
|
51089
|
+
...REVISION_ID_PATTERN.test(str(record3.revisionId) ?? "") ? { revisionId: str(record3.revisionId) } : {},
|
|
51090
|
+
...typeof record3.skillMd === "string" && record3.skillMd.length > 0 ? { skillMd: record3.skillMd } : {},
|
|
51091
|
+
...str(record3.publishedSource) ? { publishedSource: str(record3.publishedSource) } : {}
|
|
50931
51092
|
};
|
|
50932
51093
|
}
|
|
50933
51094
|
function pickCorpusOptions(options) {
|
|
@@ -50936,8 +51097,8 @@ function pickCorpusOptions(options) {
|
|
|
50936
51097
|
function extractSlug(entry) {
|
|
50937
51098
|
if (!entry || typeof entry !== "object")
|
|
50938
51099
|
return;
|
|
50939
|
-
const
|
|
50940
|
-
return str(
|
|
51100
|
+
const record3 = entry;
|
|
51101
|
+
return str(record3.slug) ?? str(record3.name);
|
|
50941
51102
|
}
|
|
50942
51103
|
function dedupe(values2) {
|
|
50943
51104
|
return [...new Set(values2)];
|
|
@@ -51210,17 +51371,17 @@ var init_install = __esm(() => {
|
|
|
51210
51371
|
|
|
51211
51372
|
// src/lib/compact-output.ts
|
|
51212
51373
|
function truncateText(value, maxChars = 96) {
|
|
51213
|
-
const
|
|
51214
|
-
if (
|
|
51215
|
-
return
|
|
51216
|
-
return `${
|
|
51374
|
+
const text2 = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
51375
|
+
if (text2.length <= maxChars)
|
|
51376
|
+
return text2;
|
|
51377
|
+
return `${text2.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
51217
51378
|
}
|
|
51218
51379
|
function previewText(value, maxChars = DEFAULT_PREVIEW_CHARS) {
|
|
51219
|
-
const
|
|
51380
|
+
const text2 = String(value ?? "");
|
|
51220
51381
|
return {
|
|
51221
|
-
text:
|
|
51222
|
-
length:
|
|
51223
|
-
truncated:
|
|
51382
|
+
text: text2.length > maxChars ? `${text2.slice(0, Math.max(0, maxChars - 3))}...` : text2,
|
|
51383
|
+
length: text2.length,
|
|
51384
|
+
truncated: text2.length > maxChars
|
|
51224
51385
|
};
|
|
51225
51386
|
}
|
|
51226
51387
|
function parsePageLimit(value, fallback, options = {}) {
|
|
@@ -51339,10 +51500,10 @@ function handleBrowseError(error) {
|
|
|
51339
51500
|
process.exitCode = 1;
|
|
51340
51501
|
}
|
|
51341
51502
|
async function writeJson(value, space) {
|
|
51342
|
-
const
|
|
51503
|
+
const text2 = `${JSON.stringify(value, null, space)}
|
|
51343
51504
|
`;
|
|
51344
51505
|
await new Promise((resolve3, reject2) => {
|
|
51345
|
-
process.stdout.write(
|
|
51506
|
+
process.stdout.write(text2, (error) => {
|
|
51346
51507
|
if (error)
|
|
51347
51508
|
reject2(error);
|
|
51348
51509
|
else
|
|
@@ -52049,12 +52210,12 @@ function generateSkillMd(name) {
|
|
|
52049
52210
|
`) + `
|
|
52050
52211
|
`;
|
|
52051
52212
|
}
|
|
52052
|
-
function extractEnvVars(
|
|
52213
|
+
function extractEnvVars(text2) {
|
|
52053
52214
|
const envVars = new Set;
|
|
52054
52215
|
for (const pattern of [ENV_VAR_PATTERN, GENERIC_ENV_PATTERN]) {
|
|
52055
52216
|
pattern.lastIndex = 0;
|
|
52056
52217
|
let match;
|
|
52057
|
-
while ((match = pattern.exec(
|
|
52218
|
+
while ((match = pattern.exec(text2)) !== null) {
|
|
52058
52219
|
envVars.add(match[1]);
|
|
52059
52220
|
}
|
|
52060
52221
|
}
|
|
@@ -53260,8 +53421,8 @@ function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
|
53260
53421
|
const dir = join24(appDir, ROLLBACK_DIRNAME);
|
|
53261
53422
|
mkdirSync9(dir, { recursive: true });
|
|
53262
53423
|
const file = join24(dir, `${mode}-${Date.now()}.json`);
|
|
53263
|
-
const
|
|
53264
|
-
writeFileSync10(file, `${JSON.stringify(
|
|
53424
|
+
const record3 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
53425
|
+
writeFileSync10(file, `${JSON.stringify(record3, null, 2)}
|
|
53265
53426
|
`);
|
|
53266
53427
|
return file;
|
|
53267
53428
|
}
|
|
@@ -53568,10 +53729,10 @@ function setEnvAssignment(path, assignment) {
|
|
|
53568
53729
|
}
|
|
53569
53730
|
let prepared = initial2;
|
|
53570
53731
|
if (previous) {
|
|
53571
|
-
const original = readFileSync20(descriptor),
|
|
53572
|
-
if (!Buffer.from(
|
|
53732
|
+
const original = readFileSync20(descriptor), text2 = original.toString("utf8");
|
|
53733
|
+
if (!Buffer.from(text2, "utf8").equals(original))
|
|
53573
53734
|
throw new EnvAssignmentError(INVALID_LAYOUT);
|
|
53574
|
-
prepared = prepareEnvAssignment(assignment,
|
|
53735
|
+
prepared = prepareEnvAssignment(assignment, text2);
|
|
53575
53736
|
}
|
|
53576
53737
|
const bytes = Buffer.from(prepared.content, "utf8");
|
|
53577
53738
|
let written = 0;
|
|
@@ -54139,7 +54300,7 @@ function createSkillRun(params, targetDir = process.cwd()) {
|
|
|
54139
54300
|
mkdirSync10(logsDir, { recursive: true });
|
|
54140
54301
|
mkdirSync10(exportDir, { recursive: true });
|
|
54141
54302
|
mkdirSync10(join27(root, "tmp"), { recursive: true });
|
|
54142
|
-
const
|
|
54303
|
+
const record3 = {
|
|
54143
54304
|
id,
|
|
54144
54305
|
skill: skillName,
|
|
54145
54306
|
status: params.status ?? "running",
|
|
@@ -54157,10 +54318,10 @@ function createSkillRun(params, targetDir = process.cwd()) {
|
|
|
54157
54318
|
logsDir: toProjectRelative(targetDir, logsDir)
|
|
54158
54319
|
}
|
|
54159
54320
|
};
|
|
54160
|
-
const context = { targetDir, runDir, exportDir, logsDir, record:
|
|
54321
|
+
const context = { targetDir, runDir, exportDir, logsDir, record: record3 };
|
|
54161
54322
|
writeRunRecord(context);
|
|
54162
54323
|
writeArtifactsManifest(context, []);
|
|
54163
|
-
appendRunEvent(context, "created", { status:
|
|
54324
|
+
appendRunEvent(context, "created", { status: record3.status });
|
|
54164
54325
|
return context;
|
|
54165
54326
|
}
|
|
54166
54327
|
function completeSkillRun(context, patch) {
|
|
@@ -54210,9 +54371,9 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
54210
54371
|
if (!statSync14(dayDir).isDirectory())
|
|
54211
54372
|
continue;
|
|
54212
54373
|
for (const runId of readdirSync13(dayDir).sort().reverse()) {
|
|
54213
|
-
const
|
|
54214
|
-
if (
|
|
54215
|
-
records.push(
|
|
54374
|
+
const record3 = readRunRecord(join27(dayDir, runId));
|
|
54375
|
+
if (record3)
|
|
54376
|
+
records.push(record3);
|
|
54216
54377
|
if (records.length >= limit)
|
|
54217
54378
|
return records;
|
|
54218
54379
|
}
|
|
@@ -54224,9 +54385,9 @@ function findSkillRun(runId, targetDir = process.cwd()) {
|
|
|
54224
54385
|
if (!existsSync25(runsRoot))
|
|
54225
54386
|
return null;
|
|
54226
54387
|
for (const day of readdirSync13(runsRoot)) {
|
|
54227
|
-
const
|
|
54228
|
-
if (
|
|
54229
|
-
return
|
|
54388
|
+
const record3 = readRunRecord(join27(runsRoot, day, runId));
|
|
54389
|
+
if (record3)
|
|
54390
|
+
return record3;
|
|
54230
54391
|
}
|
|
54231
54392
|
return null;
|
|
54232
54393
|
}
|
|
@@ -55062,7 +55223,7 @@ function datetime(args) {
|
|
|
55062
55223
|
const timeRegex2 = `${time2}(?:${opts.join("|")})`;
|
|
55063
55224
|
return new RegExp(`^${dateSource}T(?:${timeRegex2})$`);
|
|
55064
55225
|
}
|
|
55065
|
-
var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid,
|
|
55226
|
+
var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid, uuid3 = (version) => {
|
|
55066
55227
|
if (!version)
|
|
55067
55228
|
return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$/;
|
|
55068
55229
|
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
@@ -55856,9 +56017,9 @@ var init_schemas = __esm(() => {
|
|
|
55856
56017
|
const v = versionMap[def.version];
|
|
55857
56018
|
if (v === undefined)
|
|
55858
56019
|
throw new Error(`Invalid UUID version: "${def.version}"`);
|
|
55859
|
-
def.pattern ?? (def.pattern =
|
|
56020
|
+
def.pattern ?? (def.pattern = uuid3(v));
|
|
55860
56021
|
} else
|
|
55861
|
-
def.pattern ?? (def.pattern =
|
|
56022
|
+
def.pattern ?? (def.pattern = uuid3());
|
|
55862
56023
|
$ZodStringFormat.init(inst, def);
|
|
55863
56024
|
});
|
|
55864
56025
|
$ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => {
|
|
@@ -58338,7 +58499,7 @@ function intersection2(left, right) {
|
|
|
58338
58499
|
right
|
|
58339
58500
|
});
|
|
58340
58501
|
}
|
|
58341
|
-
function
|
|
58502
|
+
function record3(keyType, valueType, params) {
|
|
58342
58503
|
return new ZodRecord2({
|
|
58343
58504
|
type: "record",
|
|
58344
58505
|
keyType,
|
|
@@ -59039,7 +59200,7 @@ var init_types2 = __esm(() => {
|
|
|
59039
59200
|
});
|
|
59040
59201
|
FormElicitationCapabilitySchema = intersection2(object2({
|
|
59041
59202
|
applyDefaults: boolean2().optional()
|
|
59042
|
-
}),
|
|
59203
|
+
}), record3(string3(), unknown()));
|
|
59043
59204
|
ElicitationCapabilitySchema = preprocess((value) => {
|
|
59044
59205
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
59045
59206
|
if (Object.keys(value).length === 0) {
|
|
@@ -59050,7 +59211,7 @@ var init_types2 = __esm(() => {
|
|
|
59050
59211
|
}, intersection2(object2({
|
|
59051
59212
|
form: FormElicitationCapabilitySchema.optional(),
|
|
59052
59213
|
url: AssertObjectSchema.optional()
|
|
59053
|
-
}),
|
|
59214
|
+
}), record3(string3(), unknown()).optional()));
|
|
59054
59215
|
ClientTasksCapabilitySchema = looseObject({
|
|
59055
59216
|
list: AssertObjectSchema.optional(),
|
|
59056
59217
|
cancel: AssertObjectSchema.optional(),
|
|
@@ -59073,7 +59234,7 @@ var init_types2 = __esm(() => {
|
|
|
59073
59234
|
}).optional()
|
|
59074
59235
|
});
|
|
59075
59236
|
ClientCapabilitiesSchema = object2({
|
|
59076
|
-
experimental:
|
|
59237
|
+
experimental: record3(string3(), AssertObjectSchema).optional(),
|
|
59077
59238
|
sampling: object2({
|
|
59078
59239
|
context: AssertObjectSchema.optional(),
|
|
59079
59240
|
tools: AssertObjectSchema.optional()
|
|
@@ -59083,7 +59244,7 @@ var init_types2 = __esm(() => {
|
|
|
59083
59244
|
listChanged: boolean2().optional()
|
|
59084
59245
|
}).optional(),
|
|
59085
59246
|
tasks: ClientTasksCapabilitySchema.optional(),
|
|
59086
|
-
extensions:
|
|
59247
|
+
extensions: record3(string3(), AssertObjectSchema).optional()
|
|
59087
59248
|
});
|
|
59088
59249
|
InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
59089
59250
|
protocolVersion: string3(),
|
|
@@ -59095,7 +59256,7 @@ var init_types2 = __esm(() => {
|
|
|
59095
59256
|
params: InitializeRequestParamsSchema
|
|
59096
59257
|
});
|
|
59097
59258
|
ServerCapabilitiesSchema = object2({
|
|
59098
|
-
experimental:
|
|
59259
|
+
experimental: record3(string3(), AssertObjectSchema).optional(),
|
|
59099
59260
|
logging: AssertObjectSchema.optional(),
|
|
59100
59261
|
completions: AssertObjectSchema.optional(),
|
|
59101
59262
|
prompts: object2({
|
|
@@ -59109,7 +59270,7 @@ var init_types2 = __esm(() => {
|
|
|
59109
59270
|
listChanged: boolean2().optional()
|
|
59110
59271
|
}).optional(),
|
|
59111
59272
|
tasks: ServerTasksCapabilitySchema.optional(),
|
|
59112
|
-
extensions:
|
|
59273
|
+
extensions: record3(string3(), AssertObjectSchema).optional()
|
|
59113
59274
|
});
|
|
59114
59275
|
InitializeResultSchema = ResultSchema.extend({
|
|
59115
59276
|
protocolVersion: string3(),
|
|
@@ -59196,7 +59357,7 @@ var init_types2 = __esm(() => {
|
|
|
59196
59357
|
ResourceContentsSchema = object2({
|
|
59197
59358
|
uri: string3(),
|
|
59198
59359
|
mimeType: optional(string3()),
|
|
59199
|
-
_meta:
|
|
59360
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59200
59361
|
});
|
|
59201
59362
|
TextResourceContentsSchema = ResourceContentsSchema.extend({
|
|
59202
59363
|
text: string3()
|
|
@@ -59301,7 +59462,7 @@ var init_types2 = __esm(() => {
|
|
|
59301
59462
|
});
|
|
59302
59463
|
GetPromptRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
59303
59464
|
name: string3(),
|
|
59304
|
-
arguments:
|
|
59465
|
+
arguments: record3(string3(), string3()).optional()
|
|
59305
59466
|
});
|
|
59306
59467
|
GetPromptRequestSchema = RequestSchema.extend({
|
|
59307
59468
|
method: literal("prompts/get"),
|
|
@@ -59311,34 +59472,34 @@ var init_types2 = __esm(() => {
|
|
|
59311
59472
|
type: literal("text"),
|
|
59312
59473
|
text: string3(),
|
|
59313
59474
|
annotations: AnnotationsSchema.optional(),
|
|
59314
|
-
_meta:
|
|
59475
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59315
59476
|
});
|
|
59316
59477
|
ImageContentSchema = object2({
|
|
59317
59478
|
type: literal("image"),
|
|
59318
59479
|
data: Base64Schema,
|
|
59319
59480
|
mimeType: string3(),
|
|
59320
59481
|
annotations: AnnotationsSchema.optional(),
|
|
59321
|
-
_meta:
|
|
59482
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59322
59483
|
});
|
|
59323
59484
|
AudioContentSchema = object2({
|
|
59324
59485
|
type: literal("audio"),
|
|
59325
59486
|
data: Base64Schema,
|
|
59326
59487
|
mimeType: string3(),
|
|
59327
59488
|
annotations: AnnotationsSchema.optional(),
|
|
59328
|
-
_meta:
|
|
59489
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59329
59490
|
});
|
|
59330
59491
|
ToolUseContentSchema = object2({
|
|
59331
59492
|
type: literal("tool_use"),
|
|
59332
59493
|
name: string3(),
|
|
59333
59494
|
id: string3(),
|
|
59334
|
-
input:
|
|
59335
|
-
_meta:
|
|
59495
|
+
input: record3(string3(), unknown()),
|
|
59496
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59336
59497
|
});
|
|
59337
59498
|
EmbeddedResourceSchema = object2({
|
|
59338
59499
|
type: literal("resource"),
|
|
59339
59500
|
resource: union2([TextResourceContentsSchema, BlobResourceContentsSchema]),
|
|
59340
59501
|
annotations: AnnotationsSchema.optional(),
|
|
59341
|
-
_meta:
|
|
59502
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59342
59503
|
});
|
|
59343
59504
|
ResourceLinkSchema = ResourceSchema.extend({
|
|
59344
59505
|
type: literal("resource_link")
|
|
@@ -59378,17 +59539,17 @@ var init_types2 = __esm(() => {
|
|
|
59378
59539
|
description: string3().optional(),
|
|
59379
59540
|
inputSchema: object2({
|
|
59380
59541
|
type: literal("object"),
|
|
59381
|
-
properties:
|
|
59542
|
+
properties: record3(string3(), AssertObjectSchema).optional(),
|
|
59382
59543
|
required: array(string3()).optional()
|
|
59383
59544
|
}).catchall(unknown()),
|
|
59384
59545
|
outputSchema: object2({
|
|
59385
59546
|
type: literal("object"),
|
|
59386
|
-
properties:
|
|
59547
|
+
properties: record3(string3(), AssertObjectSchema).optional(),
|
|
59387
59548
|
required: array(string3()).optional()
|
|
59388
59549
|
}).catchall(unknown()).optional(),
|
|
59389
59550
|
annotations: ToolAnnotationsSchema.optional(),
|
|
59390
59551
|
execution: ToolExecutionSchema.optional(),
|
|
59391
|
-
_meta:
|
|
59552
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59392
59553
|
});
|
|
59393
59554
|
ListToolsRequestSchema = PaginatedRequestSchema.extend({
|
|
59394
59555
|
method: literal("tools/list")
|
|
@@ -59398,7 +59559,7 @@ var init_types2 = __esm(() => {
|
|
|
59398
59559
|
});
|
|
59399
59560
|
CallToolResultSchema = ResultSchema.extend({
|
|
59400
59561
|
content: array(ContentBlockSchema).default([]),
|
|
59401
|
-
structuredContent:
|
|
59562
|
+
structuredContent: record3(string3(), unknown()).optional(),
|
|
59402
59563
|
isError: boolean2().optional()
|
|
59403
59564
|
});
|
|
59404
59565
|
CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({
|
|
@@ -59406,7 +59567,7 @@ var init_types2 = __esm(() => {
|
|
|
59406
59567
|
}));
|
|
59407
59568
|
CallToolRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
59408
59569
|
name: string3(),
|
|
59409
|
-
arguments:
|
|
59570
|
+
arguments: record3(string3(), unknown()).optional()
|
|
59410
59571
|
});
|
|
59411
59572
|
CallToolRequestSchema = RequestSchema.extend({
|
|
59412
59573
|
method: literal("tools/call"),
|
|
@@ -59455,7 +59616,7 @@ var init_types2 = __esm(() => {
|
|
|
59455
59616
|
content: array(ContentBlockSchema).default([]),
|
|
59456
59617
|
structuredContent: object2({}).loose().optional(),
|
|
59457
59618
|
isError: boolean2().optional(),
|
|
59458
|
-
_meta:
|
|
59619
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59459
59620
|
});
|
|
59460
59621
|
SamplingContentSchema = discriminatedUnion("type", [TextContentSchema, ImageContentSchema, AudioContentSchema]);
|
|
59461
59622
|
SamplingMessageContentBlockSchema = discriminatedUnion("type", [
|
|
@@ -59468,7 +59629,7 @@ var init_types2 = __esm(() => {
|
|
|
59468
59629
|
SamplingMessageSchema = object2({
|
|
59469
59630
|
role: RoleSchema,
|
|
59470
59631
|
content: union2([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)]),
|
|
59471
|
-
_meta:
|
|
59632
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59472
59633
|
});
|
|
59473
59634
|
CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
59474
59635
|
messages: array(SamplingMessageSchema),
|
|
@@ -59581,7 +59742,7 @@ var init_types2 = __esm(() => {
|
|
|
59581
59742
|
message: string3(),
|
|
59582
59743
|
requestedSchema: object2({
|
|
59583
59744
|
type: literal("object"),
|
|
59584
|
-
properties:
|
|
59745
|
+
properties: record3(string3(), PrimitiveSchemaDefinitionSchema),
|
|
59585
59746
|
required: array(string3()).optional()
|
|
59586
59747
|
})
|
|
59587
59748
|
});
|
|
@@ -59605,7 +59766,7 @@ var init_types2 = __esm(() => {
|
|
|
59605
59766
|
});
|
|
59606
59767
|
ElicitResultSchema = ResultSchema.extend({
|
|
59607
59768
|
action: _enum(["accept", "decline", "cancel"]),
|
|
59608
|
-
content: preprocess((val) => val === null ? undefined : val,
|
|
59769
|
+
content: preprocess((val) => val === null ? undefined : val, record3(string3(), union2([string3(), number2(), boolean2(), array(string3())])).optional())
|
|
59609
59770
|
});
|
|
59610
59771
|
ResourceTemplateReferenceSchema = object2({
|
|
59611
59772
|
type: literal("ref/resource"),
|
|
@@ -59622,7 +59783,7 @@ var init_types2 = __esm(() => {
|
|
|
59622
59783
|
value: string3()
|
|
59623
59784
|
}),
|
|
59624
59785
|
context: object2({
|
|
59625
|
-
arguments:
|
|
59786
|
+
arguments: record3(string3(), string3()).optional()
|
|
59626
59787
|
}).optional()
|
|
59627
59788
|
});
|
|
59628
59789
|
CompleteRequestSchema = RequestSchema.extend({
|
|
@@ -59639,7 +59800,7 @@ var init_types2 = __esm(() => {
|
|
|
59639
59800
|
RootSchema = object2({
|
|
59640
59801
|
uri: string3().startsWith("file://"),
|
|
59641
59802
|
name: string3().optional(),
|
|
59642
|
-
_meta:
|
|
59803
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59643
59804
|
});
|
|
59644
59805
|
ListRootsRequestSchema = RequestSchema.extend({
|
|
59645
59806
|
method: literal("roots/list"),
|
|
@@ -66892,7 +67053,7 @@ var require_core = __commonJS((exports) => {
|
|
|
66892
67053
|
errorsText(errors4 = this.errors, { separator = ", ", dataVar = "data" } = {}) {
|
|
66893
67054
|
if (!errors4 || errors4.length === 0)
|
|
66894
67055
|
return "No errors";
|
|
66895
|
-
return errors4.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((
|
|
67056
|
+
return errors4.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text2, msg) => text2 + separator + msg);
|
|
66896
67057
|
}
|
|
66897
67058
|
$dataMetaSchema(metaSchema, keywordsJsonPointers) {
|
|
66898
67059
|
const rules = this.RULES.all;
|
|
@@ -67303,8 +67464,8 @@ var require_multipleOf = __commonJS((exports) => {
|
|
|
67303
67464
|
const { gen, data, schemaCode, it } = cxt;
|
|
67304
67465
|
const prec = it.opts.multipleOfPrecision;
|
|
67305
67466
|
const res = gen.let("res");
|
|
67306
|
-
const
|
|
67307
|
-
cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${
|
|
67467
|
+
const invalid2 = prec ? (0, codegen_1._)`Math.abs(Math.round(${res}) - ${res}) > 1e-${prec}` : (0, codegen_1._)`${res} !== parseInt(${res})`;
|
|
67468
|
+
cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${invalid2}))`);
|
|
67308
67469
|
}
|
|
67309
67470
|
};
|
|
67310
67471
|
exports.default = def;
|
|
@@ -73400,13 +73561,13 @@ async function requestAuthApi(instance, path, options) {
|
|
|
73400
73561
|
apiUrl: safeUrl
|
|
73401
73562
|
});
|
|
73402
73563
|
}
|
|
73403
|
-
const
|
|
73404
|
-
const body =
|
|
73564
|
+
const text2 = await res.text();
|
|
73565
|
+
const body = text2 ? parseJsonBody(text2) : {};
|
|
73405
73566
|
if (!res.ok) {
|
|
73406
|
-
const
|
|
73407
|
-
const detail = typeof
|
|
73408
|
-
const error2 = typeof
|
|
73409
|
-
const code = typeof
|
|
73567
|
+
const record5 = isRecord5(body) ? body : {};
|
|
73568
|
+
const detail = typeof record5.detail === "string" ? record5.detail : undefined;
|
|
73569
|
+
const error2 = typeof record5.error === "string" ? record5.error : undefined;
|
|
73570
|
+
const code = typeof record5.code === "string" ? record5.code : undefined;
|
|
73410
73571
|
throw new HostedApiError(detail || error2 || `${res.status} ${res.statusText}`, {
|
|
73411
73572
|
status: res.status,
|
|
73412
73573
|
code,
|
|
@@ -73417,15 +73578,15 @@ async function requestAuthApi(instance, path, options) {
|
|
|
73417
73578
|
}
|
|
73418
73579
|
return body;
|
|
73419
73580
|
}
|
|
73420
|
-
function parseJsonBody(
|
|
73581
|
+
function parseJsonBody(text2) {
|
|
73421
73582
|
try {
|
|
73422
|
-
return JSON.parse(
|
|
73583
|
+
return JSON.parse(text2);
|
|
73423
73584
|
} catch {
|
|
73424
|
-
return { detail: condenseErrorBody(
|
|
73585
|
+
return { detail: condenseErrorBody(text2) };
|
|
73425
73586
|
}
|
|
73426
73587
|
}
|
|
73427
|
-
function condenseErrorBody(
|
|
73428
|
-
const stripped = /<[a-z!/]/i.test(
|
|
73588
|
+
function condenseErrorBody(text2) {
|
|
73589
|
+
const stripped = /<[a-z!/]/i.test(text2) ? text2.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text2;
|
|
73429
73590
|
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
73430
73591
|
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
73431
73592
|
return collapsed;
|
|
@@ -73452,7 +73613,12 @@ class RemoteSkillsAuthClient {
|
|
|
73452
73613
|
pollDevice(deviceCode) {
|
|
73453
73614
|
return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
|
|
73454
73615
|
}
|
|
73455
|
-
async sessionClient(email2, code) {
|
|
73616
|
+
async sessionClient(email2, code, context) {
|
|
73617
|
+
if (context !== undefined) {
|
|
73618
|
+
const target = workspaceContext(context), apiOrigin2 = this.apiOrigin;
|
|
73619
|
+
const session = await this.switchWorkspace(email2, code, target);
|
|
73620
|
+
return new RemoteSkillsClient(session.token, apiOrigin2);
|
|
73621
|
+
}
|
|
73456
73622
|
const apiOrigin = this.apiOrigin;
|
|
73457
73623
|
if (!email2.includes("@") || !/^\d{6}$/.test(code))
|
|
73458
73624
|
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
@@ -73461,34 +73627,76 @@ class RemoteSkillsAuthClient {
|
|
|
73461
73627
|
throw new Error("The server did not return an authorized account session");
|
|
73462
73628
|
return new RemoteSkillsClient(login.token, apiOrigin);
|
|
73463
73629
|
}
|
|
73464
|
-
async
|
|
73465
|
-
|
|
73630
|
+
async listAccountWorkspaces(email2, code, expectedUserId) {
|
|
73631
|
+
const login = await this.workspaceLogin(email2, code, expectedUserId);
|
|
73632
|
+
const result2 = await new RemoteSkillsClient(login.token, login.apiOrigin).listAccountWorkspaces(login.userId);
|
|
73633
|
+
return { userId: login.userId, ...result2 };
|
|
73466
73634
|
}
|
|
73467
|
-
async
|
|
73468
|
-
|
|
73635
|
+
async switchWorkspace(email2, code, context) {
|
|
73636
|
+
const target = workspaceContext(context);
|
|
73637
|
+
const login = await this.workspaceLogin(email2, code, target.userId);
|
|
73638
|
+
return new RemoteSkillsClient(login.token, login.apiOrigin).switchWorkspace(target);
|
|
73639
|
+
}
|
|
73640
|
+
async workspaceLogin(email2, code, expectedUserId) {
|
|
73641
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
73642
|
+
const apiOrigin = this.apiOrigin;
|
|
73643
|
+
if (typeof email2 !== "string" || !email2.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
|
|
73644
|
+
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
73645
|
+
let response;
|
|
73646
|
+
try {
|
|
73647
|
+
response = await fetch(`${apiOrigin}/api/auth/verify`, {
|
|
73648
|
+
method: "POST",
|
|
73649
|
+
redirect: "error",
|
|
73650
|
+
credentials: "omit",
|
|
73651
|
+
signal: AbortSignal.timeout(15000),
|
|
73652
|
+
headers: { "Content-Type": "application/json" },
|
|
73653
|
+
body: JSON.stringify({ email: email2, code })
|
|
73654
|
+
});
|
|
73655
|
+
} catch {
|
|
73656
|
+
throw new HostedApiError("Unable to verify the Skills account.");
|
|
73657
|
+
}
|
|
73658
|
+
if (!response.ok) {
|
|
73659
|
+
response.body?.cancel().catch(() => {});
|
|
73660
|
+
throw new HostedApiError("Unable to verify the Skills account.", { status: response.status });
|
|
73661
|
+
}
|
|
73662
|
+
let value;
|
|
73663
|
+
try {
|
|
73664
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, 64 * 1024)));
|
|
73665
|
+
} catch {
|
|
73666
|
+
throw new HostedApiError("The server returned an invalid account verification result.");
|
|
73667
|
+
}
|
|
73668
|
+
return { ...parseWorkspaceLogin(value, expected), apiOrigin };
|
|
73469
73669
|
}
|
|
73470
|
-
async
|
|
73471
|
-
|
|
73670
|
+
async createApiKey(email2, code, name, scopes, context) {
|
|
73671
|
+
const capturedScopes = scopes === undefined ? undefined : [...scopes];
|
|
73672
|
+
return (await this.sessionClient(email2, code, context)).createApiKey(name, capturedScopes);
|
|
73472
73673
|
}
|
|
73473
|
-
async
|
|
73474
|
-
|
|
73475
|
-
return (await this.sessionClient(email2, code)).updateProfile(input);
|
|
73674
|
+
async listApiKeys(email2, code, context) {
|
|
73675
|
+
return (await this.sessionClient(email2, code, context)).listApiKeys();
|
|
73476
73676
|
}
|
|
73477
|
-
async
|
|
73478
|
-
|
|
73479
|
-
return (await this.sessionClient(email2, code)).updateCurrentWorkspace(input);
|
|
73677
|
+
async revokeApiKey(email2, code, keyId, context) {
|
|
73678
|
+
return (await this.sessionClient(email2, code, context)).revokeApiKey(keyId);
|
|
73480
73679
|
}
|
|
73481
|
-
async
|
|
73680
|
+
async updateProfile(email2, code, input, context) {
|
|
73681
|
+
const body = customerNamePatch(input, "displayName");
|
|
73682
|
+
return (await this.sessionClient(email2, code, context)).updateProfile({ displayName: body.displayName });
|
|
73683
|
+
}
|
|
73684
|
+
async updateCurrentWorkspace(email2, code, input, context) {
|
|
73685
|
+
const body = customerNamePatch(input, "name");
|
|
73686
|
+
return (await this.sessionClient(email2, code, context)).updateCurrentWorkspace({ name: body.name });
|
|
73687
|
+
}
|
|
73688
|
+
async listWorkspaceMembers(email2, code, options = {}, context) {
|
|
73482
73689
|
workspaceMembersQuery(options);
|
|
73483
|
-
|
|
73690
|
+
const captured = { ...options };
|
|
73691
|
+
return (await this.sessionClient(email2, code, context)).listWorkspaceMembers(captured);
|
|
73484
73692
|
}
|
|
73485
|
-
async setWorkspaceMemberRole(email2, code, membershipId, input) {
|
|
73693
|
+
async setWorkspaceMemberRole(email2, code, membershipId, input, context) {
|
|
73486
73694
|
const captured = workspaceMemberRoleInput(membershipId, input);
|
|
73487
|
-
return (await this.sessionClient(email2, code)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
73695
|
+
return (await this.sessionClient(email2, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
73488
73696
|
}
|
|
73489
|
-
async removeWorkspaceMember(email2, code, membershipId, input) {
|
|
73697
|
+
async removeWorkspaceMember(email2, code, membershipId, input, context) {
|
|
73490
73698
|
const captured = workspaceMemberRemovalInput(membershipId, input);
|
|
73491
|
-
return (await this.sessionClient(email2, code)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
73699
|
+
return (await this.sessionClient(email2, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
73492
73700
|
}
|
|
73493
73701
|
request(path, options) {
|
|
73494
73702
|
if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
|
|
@@ -73498,6 +73706,8 @@ class RemoteSkillsAuthClient {
|
|
|
73498
73706
|
}
|
|
73499
73707
|
var MAX_ERROR_DETAIL_LENGTH = 200, HostedApiError;
|
|
73500
73708
|
var init_remote_auth = __esm(() => {
|
|
73709
|
+
init_remote_workspace_selection();
|
|
73710
|
+
init_remote_files();
|
|
73501
73711
|
init_remote_workspace();
|
|
73502
73712
|
init_remote_workspace();
|
|
73503
73713
|
init_remote_client();
|
|
@@ -73520,6 +73730,224 @@ var init_remote_auth = __esm(() => {
|
|
|
73520
73730
|
};
|
|
73521
73731
|
});
|
|
73522
73732
|
|
|
73733
|
+
// src/lib/workspace-profile.ts
|
|
73734
|
+
import { constants as constants4, closeSync as closeSync4, fstatSync as fstatSync4, lstatSync as lstatSync6, mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4, openSync as openSync4, readFileSync as readFileSync25, renameSync as renameSync6, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "fs";
|
|
73735
|
+
import { dirname as dirname10, join as join32 } from "path";
|
|
73736
|
+
function stat(path) {
|
|
73737
|
+
try {
|
|
73738
|
+
return lstatSync6(path);
|
|
73739
|
+
} catch (error2) {
|
|
73740
|
+
if (error2.code === "ENOENT")
|
|
73741
|
+
return null;
|
|
73742
|
+
throw error2;
|
|
73743
|
+
}
|
|
73744
|
+
}
|
|
73745
|
+
function safeText(file) {
|
|
73746
|
+
if (stat(file) === null)
|
|
73747
|
+
return null;
|
|
73748
|
+
const fd = openSync4(file, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
73749
|
+
try {
|
|
73750
|
+
const s = fstatSync4(fd);
|
|
73751
|
+
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
73752
|
+
return fail2("The selected profile must use bounded owner-only regular files.");
|
|
73753
|
+
return readFileSync25(fd, "utf8");
|
|
73754
|
+
} finally {
|
|
73755
|
+
closeSync4(fd);
|
|
73756
|
+
}
|
|
73757
|
+
}
|
|
73758
|
+
function checkIdentityMetadata(file, identity2) {
|
|
73759
|
+
const text2 = safeText(file);
|
|
73760
|
+
if (text2 === null)
|
|
73761
|
+
return;
|
|
73762
|
+
let value;
|
|
73763
|
+
try {
|
|
73764
|
+
value = JSON.parse(text2);
|
|
73765
|
+
} catch {
|
|
73766
|
+
return fail2("The profile identity metadata is invalid. Sign in again before managing this workspace.");
|
|
73767
|
+
}
|
|
73768
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
73769
|
+
return fail2("The profile identity metadata is invalid.");
|
|
73770
|
+
for (const [key, expected] of Object.entries({ userId: identity2.user.id, orgId: identity2.organization.id })) {
|
|
73771
|
+
if (value[key] !== undefined && value[key] !== expected)
|
|
73772
|
+
return fail2("The profile identity metadata does not match its authenticated key. Sign in again before managing this workspace.");
|
|
73773
|
+
}
|
|
73774
|
+
}
|
|
73775
|
+
async function keyIdentity(key, origin) {
|
|
73776
|
+
const value = await new RemoteSkillsClient(key, origin).getIdentity();
|
|
73777
|
+
if (value.authMethod !== "api_key")
|
|
73778
|
+
return fail2("The selected credential is not a workspace API key.");
|
|
73779
|
+
const user = value.user;
|
|
73780
|
+
return parseWorkspaceIdentity(value, workspaceExpectedUserId(user?.id));
|
|
73781
|
+
}
|
|
73782
|
+
function prepareProfileWorkspace(action, source = process.env) {
|
|
73783
|
+
const env3 = { ...source }, origin = getApiUrl(action, env3), profile = selectedSkillsProfile(env3);
|
|
73784
|
+
const unchanged2 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
|
|
73785
|
+
return { origin, async resolve() {
|
|
73786
|
+
unchanged2();
|
|
73787
|
+
if (!profile)
|
|
73788
|
+
return { origin, context: undefined, unchanged: unchanged2 };
|
|
73789
|
+
const connection = await resolveSkillsConnection(env3);
|
|
73790
|
+
if (!connection || connection.apiOrigin !== origin)
|
|
73791
|
+
return fail2("The selected profile has no usable credential for this server.");
|
|
73792
|
+
const identity2 = await keyIdentity(connection.apiKey, origin);
|
|
73793
|
+
checkIdentityMetadata(getIdentityFilePath(env3), identity2);
|
|
73794
|
+
unchanged2();
|
|
73795
|
+
const context = { userId: identity2.user.id, membershipId: identity2.user.membershipId };
|
|
73796
|
+
return { origin, context, unchanged: unchanged2 };
|
|
73797
|
+
} };
|
|
73798
|
+
}
|
|
73799
|
+
async function captureProfileWorkspace(action, source = process.env) {
|
|
73800
|
+
return prepareProfileWorkspace(action, source).resolve();
|
|
73801
|
+
}
|
|
73802
|
+
async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
73803
|
+
workspaceExpectedUserId(membershipId);
|
|
73804
|
+
const env3 = { ...source }, profile = selectedSkillsProfile(env3);
|
|
73805
|
+
if (!profile)
|
|
73806
|
+
return fail2("Workspace login requires an explicit HASNA_PROFILE name.");
|
|
73807
|
+
if (["HASNA_SKILLS_API_KEY_OVERRIDE", "HASNA_SKILLS_API_KEY_REF", "HASNA_SKILLS_API_KEY", "SKILLS_API_KEY"].some((name) => env3[name]?.trim()))
|
|
73808
|
+
return fail2("Clear injected API keys before enrolling a named workspace profile.");
|
|
73809
|
+
const origin = getApiUrl("Sign in to a workspace", env3);
|
|
73810
|
+
const file = getAuthFilePath(env3), identityFile = getIdentityFilePath(env3);
|
|
73811
|
+
const paths = [...new Set([...skillsProfileCredentialFiles(env3), file, identityFile])];
|
|
73812
|
+
const unchangedFiles = captureSkillsCredentialFiles(paths);
|
|
73813
|
+
const old = safeText(file), oldIdentity = safeText(identityFile);
|
|
73814
|
+
const managed = new Set(["HASNA_SKILLS_API_KEY", "SKILLS_API_KEY", "HASNA_SKILLS_API_URL", "SKILLS_API_URL", "HASNA_SKILLS_BOUND_API_URL"]);
|
|
73815
|
+
const lines = (old ?? "").split(/\r?\n/).filter((line) => !managed.has(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line)?.[1] ?? ""));
|
|
73816
|
+
const credentialBody = (key) => [...lines.filter(Boolean), `HASNA_SKILLS_API_KEY=${key}`, `HASNA_SKILLS_API_URL=${origin}`, `HASNA_SKILLS_BOUND_API_URL=${origin}`, ""].join(`
|
|
73817
|
+
`);
|
|
73818
|
+
if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
|
|
73819
|
+
return fail2("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
|
|
73820
|
+
const parents = [];
|
|
73821
|
+
for (let path = dirname10(file);; path = dirname10(path)) {
|
|
73822
|
+
const before2 = stat(path);
|
|
73823
|
+
if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
|
|
73824
|
+
return fail2("The profile directory must not be a symbolic link.");
|
|
73825
|
+
parents.push([path, before2]);
|
|
73826
|
+
if (path === dirname10(path))
|
|
73827
|
+
break;
|
|
73828
|
+
}
|
|
73829
|
+
const unchanged2 = () => {
|
|
73830
|
+
unchangedFiles();
|
|
73831
|
+
for (const [path, before2] of parents) {
|
|
73832
|
+
const now3 = stat(path);
|
|
73833
|
+
if (!before2 ? now3 !== null : !now3 || !now3.isDirectory() || before2.dev !== now3.dev || before2.ino !== now3.ino)
|
|
73834
|
+
changed();
|
|
73835
|
+
}
|
|
73836
|
+
};
|
|
73837
|
+
let expected;
|
|
73838
|
+
try {
|
|
73839
|
+
const connection = await resolveSkillsConnection(env3);
|
|
73840
|
+
if (connection) {
|
|
73841
|
+
if (connection.apiKeyTier !== "profile" || connection.apiOrigin !== origin)
|
|
73842
|
+
return fail2("Workspace login must resolve only the explicitly named profile.");
|
|
73843
|
+
expected = await keyIdentity(connection.apiKey, origin);
|
|
73844
|
+
checkIdentityMetadata(identityFile, expected);
|
|
73845
|
+
}
|
|
73846
|
+
} catch (error2) {
|
|
73847
|
+
if (!(error2 instanceof SkillsFleetCredentialError && error2.code === "MISSING_API_CREDENTIAL" && (old === null || !/^\s*(?:export\s+)?(?:HASNA_SKILLS_API_KEY|SKILLS_API_KEY)\s*=/m.test(old))))
|
|
73848
|
+
throw error2;
|
|
73849
|
+
}
|
|
73850
|
+
unchanged2();
|
|
73851
|
+
return {
|
|
73852
|
+
profile,
|
|
73853
|
+
origin,
|
|
73854
|
+
async complete(email2, code) {
|
|
73855
|
+
unchanged2();
|
|
73856
|
+
if (!email2.includes("@") || !/^\d{6}$/.test(code))
|
|
73857
|
+
return fail2("A fresh email and six-digit verification code are required.");
|
|
73858
|
+
if (expected && expected.user.email.toLowerCase() !== email2.toLowerCase())
|
|
73859
|
+
return fail2("This profile belongs to another account. Use a different profile or ordinary replacement login.");
|
|
73860
|
+
let issued = false;
|
|
73861
|
+
try {
|
|
73862
|
+
const result2 = await new RemoteSkillsAuthClient(origin).verifyCode(email2, code);
|
|
73863
|
+
const login = parseWorkspaceLogin(result2, expected?.user.id);
|
|
73864
|
+
if (result2.firstLogin === true)
|
|
73865
|
+
return fail2("This sign-in created a new account using the server signup policy. Finish ordinary account login before enrolling a workspace profile.");
|
|
73866
|
+
const session = await new RemoteSkillsClient(login.token, origin).switchWorkspace({ userId: login.userId, membershipId });
|
|
73867
|
+
if (session.user.email.toLowerCase() !== email2.toLowerCase())
|
|
73868
|
+
return fail2("The verified account does not match the requested email.");
|
|
73869
|
+
if (session.user.role === "viewer")
|
|
73870
|
+
return fail2("Viewer memberships cannot enroll API keys.");
|
|
73871
|
+
unchanged2();
|
|
73872
|
+
issued = true;
|
|
73873
|
+
const created = await new RemoteSkillsClient(session.token, origin).createApiKey("cli");
|
|
73874
|
+
const verified = await keyIdentity(created.key, origin);
|
|
73875
|
+
if (verified.user.id !== session.user.id || verified.user.membershipId !== membershipId || verified.organization.id !== session.organization.id)
|
|
73876
|
+
return fail2("The issued key does not match the selected workspace.");
|
|
73877
|
+
unchanged2();
|
|
73878
|
+
if (!created.key.trim() || /[^\x21-\x7e]/.test(created.key) || created.key.length > 8192)
|
|
73879
|
+
return fail2("The server returned an invalid API key.");
|
|
73880
|
+
const body = credentialBody(created.key);
|
|
73881
|
+
if (Buffer.byteLength(body, "utf8") > 65536)
|
|
73882
|
+
return fail2("The new profile exceeds the credential reader size limit.");
|
|
73883
|
+
const identity2 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
|
|
73884
|
+
`;
|
|
73885
|
+
mkdirSync14(dirname10(file), { recursive: true, mode: 448 });
|
|
73886
|
+
const temp = mkdtempSync4(join32(dirname10(file), ".workspace-login-"));
|
|
73887
|
+
let identityInstalled = false;
|
|
73888
|
+
try {
|
|
73889
|
+
writeFileSync14(join32(temp, "credentials"), body, { mode: 384, flag: "wx" });
|
|
73890
|
+
writeFileSync14(join32(temp, "identity"), identity2, { mode: 384, flag: "wx" });
|
|
73891
|
+
unchangedFiles();
|
|
73892
|
+
for (const [path, before2] of parents) {
|
|
73893
|
+
const now3 = stat(path);
|
|
73894
|
+
if (!now3 || !now3.isDirectory() || now3.isSymbolicLink() || before2 && (before2.dev !== now3.dev || before2.ino !== now3.ino))
|
|
73895
|
+
changed();
|
|
73896
|
+
if (!before2 && now3 && ((now3.mode & 63) !== 0 || process.getuid && now3.uid !== process.getuid()))
|
|
73897
|
+
changed();
|
|
73898
|
+
}
|
|
73899
|
+
renameSync6(join32(temp, "identity"), identityFile);
|
|
73900
|
+
identityInstalled = true;
|
|
73901
|
+
renameSync6(join32(temp, "credentials"), file);
|
|
73902
|
+
} catch (error2) {
|
|
73903
|
+
if (identityInstalled) {
|
|
73904
|
+
if (oldIdentity === null)
|
|
73905
|
+
rmSync7(identityFile, { force: true });
|
|
73906
|
+
else {
|
|
73907
|
+
writeFileSync14(join32(temp, "restore"), oldIdentity, { mode: 384, flag: "wx" });
|
|
73908
|
+
renameSync6(join32(temp, "restore"), identityFile);
|
|
73909
|
+
}
|
|
73910
|
+
}
|
|
73911
|
+
throw error2;
|
|
73912
|
+
} finally {
|
|
73913
|
+
rmSync7(temp, { recursive: true, force: true });
|
|
73914
|
+
}
|
|
73915
|
+
return {
|
|
73916
|
+
status: "authenticated",
|
|
73917
|
+
profile,
|
|
73918
|
+
apiUrl: origin,
|
|
73919
|
+
userId: verified.user.id,
|
|
73920
|
+
email: verified.user.email,
|
|
73921
|
+
membershipId,
|
|
73922
|
+
organization: verified.organization.slug,
|
|
73923
|
+
organizationId: verified.organization.id,
|
|
73924
|
+
role: verified.user.role,
|
|
73925
|
+
keyCreated: true
|
|
73926
|
+
};
|
|
73927
|
+
} catch (error2) {
|
|
73928
|
+
if (issued)
|
|
73929
|
+
return fail2("Workspace key issuance was attempted, but enrollment could not be confirmed. Inspect the selected profile and workspace keys before retrying; do not retry automatically.");
|
|
73930
|
+
if (error2 instanceof WorkspaceProfileError)
|
|
73931
|
+
throw error2;
|
|
73932
|
+
return fail2("Unable to verify and select the workspace. Check the account, membership, selected server and fresh code. No enrollment key was requested.");
|
|
73933
|
+
}
|
|
73934
|
+
}
|
|
73935
|
+
};
|
|
73936
|
+
}
|
|
73937
|
+
var WorkspaceProfileError, fail2 = (message) => {
|
|
73938
|
+
throw new WorkspaceProfileError(message);
|
|
73939
|
+
}, changed = () => fail2("The selected profile changed during sign-in. No credential was saved; retry with a stable profile.");
|
|
73940
|
+
var init_workspace_profile = __esm(() => {
|
|
73941
|
+
init_auth_store();
|
|
73942
|
+
init_fleet_credentials();
|
|
73943
|
+
init_instance_credentials();
|
|
73944
|
+
init_remote_client();
|
|
73945
|
+
init_remote_auth();
|
|
73946
|
+
init_remote_workspace_selection();
|
|
73947
|
+
WorkspaceProfileError = class WorkspaceProfileError extends Error {
|
|
73948
|
+
};
|
|
73949
|
+
});
|
|
73950
|
+
|
|
73523
73951
|
// src/mcp/remote-customer-tools.ts
|
|
73524
73952
|
function registerRemoteCustomerTools(server) {
|
|
73525
73953
|
const memberRole = exports_external.enum(["owner", "admin", "member", "viewer"]);
|
|
@@ -73533,9 +73961,9 @@ function registerRemoteCustomerTools(server) {
|
|
|
73533
73961
|
title: "Set Current Workspace Member Role",
|
|
73534
73962
|
description: "Change exactly this membership incarnation with its observed expectedRole and fresh verification. The server enforces owner/admin policy. No automatic refresh or retry; saved credentials stay unchanged.",
|
|
73535
73963
|
inputSchema: exports_external.object({ ...memberInput, role: memberRole }).strict()
|
|
73536
|
-
}, async ({ membershipId, role, expectedRole, email: email2, code }) => {
|
|
73964
|
+
}, async ({ membershipId, role: role2, expectedRole, email: email2, code }) => {
|
|
73537
73965
|
try {
|
|
73538
|
-
return mcpJson(await
|
|
73966
|
+
return mcpJson(await freshAccount("Set workspace member role", (client, context) => client.setWorkspaceMemberRole(email2, code, membershipId, { role: role2, expectedRole }, context)));
|
|
73539
73967
|
} catch (error2) {
|
|
73540
73968
|
return memberError(error2);
|
|
73541
73969
|
}
|
|
@@ -73546,7 +73974,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73546
73974
|
inputSchema: exports_external.object(memberInput).strict()
|
|
73547
73975
|
}, async ({ membershipId, expectedRole, email: email2, code }) => {
|
|
73548
73976
|
try {
|
|
73549
|
-
return mcpJson(await
|
|
73977
|
+
return mcpJson(await freshAccount("Remove workspace member", (client, context) => client.removeWorkspaceMember(email2, code, membershipId, { expectedRole }, context)));
|
|
73550
73978
|
} catch (error2) {
|
|
73551
73979
|
return memberError(error2);
|
|
73552
73980
|
}
|
|
@@ -73562,7 +73990,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73562
73990
|
}).strict()
|
|
73563
73991
|
}, async ({ email: email2, code, limit, cursor: cursor2 }) => {
|
|
73564
73992
|
try {
|
|
73565
|
-
return mcpJson(await
|
|
73993
|
+
return mcpJson(await freshAccount("List workspace members", (client, context) => client.listWorkspaceMembers(email2, code, { limit, cursor: cursor2 }, context)));
|
|
73566
73994
|
} catch {
|
|
73567
73995
|
return mcpError("WORKSPACE_MEMBERS_FAILED", "Unable to list workspace members. Check the selected server, owner/admin permissions, pagination and fresh verification code.");
|
|
73568
73996
|
}
|
|
@@ -73574,8 +74002,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73574
74002
|
inputSchema: exports_external.object({ name: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }).strict()
|
|
73575
74003
|
}, async ({ name, email: email2, code }) => {
|
|
73576
74004
|
try {
|
|
73577
|
-
|
|
73578
|
-
return mcpJson(kind === "profile" ? await client.updateProfile(email2, code, { displayName: name }) : await client.updateCurrentWorkspace(email2, code, { name }));
|
|
74005
|
+
return mcpJson(await freshAccount("Update customer name", async (client, context) => kind === "profile" ? client.updateProfile(email2, code, { displayName: name }, context) : client.updateCurrentWorkspace(email2, code, { name }, context)));
|
|
73579
74006
|
} catch {
|
|
73580
74007
|
return mcpError("NAME_UPDATE_FAILED", "Unable to update the name. Check the selected server, name, permissions and fresh verification code.");
|
|
73581
74008
|
}
|
|
@@ -73597,9 +74024,9 @@ function registerRemoteCustomerTools(server) {
|
|
|
73597
74024
|
inputSchema: { email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
73598
74025
|
}, async ({ email: email2, code }) => {
|
|
73599
74026
|
try {
|
|
73600
|
-
return mcpJson(await
|
|
73601
|
-
} catch
|
|
73602
|
-
return mcpError("KEY_LIST_FAILED",
|
|
74027
|
+
return mcpJson(await freshAccount("List API keys", (client, context) => client.listApiKeys(email2, code, context)));
|
|
74028
|
+
} catch {
|
|
74029
|
+
return mcpError("KEY_LIST_FAILED", "Unable to list API keys. Check the selected profile, server, account and fresh verification code.");
|
|
73603
74030
|
}
|
|
73604
74031
|
});
|
|
73605
74032
|
server.registerTool("revoke_api_key", {
|
|
@@ -73608,9 +74035,9 @@ function registerRemoteCustomerTools(server) {
|
|
|
73608
74035
|
inputSchema: { key_id: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
73609
74036
|
}, async ({ key_id, email: email2, code }) => {
|
|
73610
74037
|
try {
|
|
73611
|
-
return mcpJson(await
|
|
73612
|
-
} catch
|
|
73613
|
-
return mcpError("KEY_REVOKE_FAILED",
|
|
74038
|
+
return mcpJson(await freshAccount("Revoke API key", (client, context) => client.revokeApiKey(email2, code, key_id, context)));
|
|
74039
|
+
} catch {
|
|
74040
|
+
return mcpError("KEY_REVOKE_FAILED", "Unable to revoke this API key. Check the selected profile, key, account and fresh verification code.");
|
|
73614
74041
|
}
|
|
73615
74042
|
});
|
|
73616
74043
|
server.registerTool("create_api_key", {
|
|
@@ -73618,10 +74045,11 @@ function registerRemoteCustomerTools(server) {
|
|
|
73618
74045
|
description: "Create an API key using fresh email OTP reauthentication; returns its secret once. A stored API key cannot grant this authority.",
|
|
73619
74046
|
inputSchema: { name: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/), scopes: exports_external.array(exports_external.string()).optional() }
|
|
73620
74047
|
}, async ({ name, email: email2, code, scopes }) => {
|
|
74048
|
+
const capturedScopes = scopes === undefined ? undefined : [...scopes];
|
|
73621
74049
|
try {
|
|
73622
|
-
return mcpJson(await
|
|
73623
|
-
} catch
|
|
73624
|
-
return mcpError("KEY_CREATION_FAILED",
|
|
74050
|
+
return mcpJson(await freshAccount("Create API key", (client, context) => client.createApiKey(email2, code, name, capturedScopes, context)));
|
|
74051
|
+
} catch {
|
|
74052
|
+
return mcpError("KEY_CREATION_FAILED", "API key creation could not be confirmed. Check the selected profile and workspace keys before retrying; a lost response may still have created a key.");
|
|
73625
74053
|
}
|
|
73626
74054
|
});
|
|
73627
74055
|
server.registerTool("quote_skill", {
|
|
@@ -73655,10 +74083,15 @@ async function callRemote(action) {
|
|
|
73655
74083
|
return mcpError("REMOTE_REQUEST_FAILED", error2 instanceof Error ? error2.message : "Skills server request failed");
|
|
73656
74084
|
}
|
|
73657
74085
|
}
|
|
74086
|
+
async function freshAccount(action, operation) {
|
|
74087
|
+
const target = await captureProfileWorkspace(action);
|
|
74088
|
+
target.unchanged();
|
|
74089
|
+
return operation(new RemoteSkillsAuthClient(target.origin), target.context);
|
|
74090
|
+
}
|
|
73658
74091
|
var init_remote_customer_tools = __esm(() => {
|
|
73659
74092
|
init_zod();
|
|
73660
74093
|
init_remote_auth();
|
|
73661
|
-
|
|
74094
|
+
init_workspace_profile();
|
|
73662
74095
|
init_remote_customer_operations();
|
|
73663
74096
|
init_remote_client();
|
|
73664
74097
|
init_helpers();
|
|
@@ -74106,9 +74539,9 @@ var init_mcp2 = __esm(() => {
|
|
|
74106
74539
|
});
|
|
74107
74540
|
|
|
74108
74541
|
// src/cli/commands/runtime-mcp.ts
|
|
74109
|
-
import { existsSync as existsSync30, mkdirSync as
|
|
74542
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync15, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
|
|
74110
74543
|
import { homedir as homedir7 } from "os";
|
|
74111
|
-
import { dirname as
|
|
74544
|
+
import { dirname as dirname11, join as join33 } from "path";
|
|
74112
74545
|
async function handleMcp(options) {
|
|
74113
74546
|
if (options.register) {
|
|
74114
74547
|
let agents;
|
|
@@ -74151,24 +74584,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
74151
74584
|
case "codex":
|
|
74152
74585
|
return registerCodexMcp(command);
|
|
74153
74586
|
case "gemini":
|
|
74154
|
-
return registerJsonMcpServer(agent,
|
|
74587
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".gemini", "settings.json"), "mcpServers", {
|
|
74155
74588
|
command,
|
|
74156
74589
|
args: []
|
|
74157
74590
|
});
|
|
74158
74591
|
case "pi":
|
|
74159
|
-
return registerJsonMcpServer(agent,
|
|
74592
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
74160
74593
|
command,
|
|
74161
74594
|
args: []
|
|
74162
74595
|
});
|
|
74163
74596
|
case "opencode":
|
|
74164
74597
|
return registerOpenCodeMcp(command);
|
|
74165
74598
|
case "cursor":
|
|
74166
|
-
return registerJsonMcpServer(agent,
|
|
74599
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".cursor", "mcp.json"), "mcpServers", {
|
|
74167
74600
|
command,
|
|
74168
74601
|
args: []
|
|
74169
74602
|
});
|
|
74170
74603
|
case "windsurf":
|
|
74171
|
-
return registerJsonMcpServer(agent,
|
|
74604
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
74172
74605
|
command,
|
|
74173
74606
|
args: []
|
|
74174
74607
|
});
|
|
@@ -74191,7 +74624,7 @@ async function registerClaudeMcp(command) {
|
|
|
74191
74624
|
if (exitCode === 0) {
|
|
74192
74625
|
return { agent: "claude", success: true, command: cliCommand };
|
|
74193
74626
|
}
|
|
74194
|
-
const fallback = registerJsonMcpServer("claude",
|
|
74627
|
+
const fallback = registerJsonMcpServer("claude", join33(homedir7(), ".claude", ".mcp.json"), "mcpServers", {
|
|
74195
74628
|
command,
|
|
74196
74629
|
args: []
|
|
74197
74630
|
});
|
|
@@ -74201,7 +74634,7 @@ async function registerClaudeMcp(command) {
|
|
|
74201
74634
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
74202
74635
|
};
|
|
74203
74636
|
} catch (err) {
|
|
74204
|
-
const fallback = registerJsonMcpServer("claude",
|
|
74637
|
+
const fallback = registerJsonMcpServer("claude", join33(homedir7(), ".claude", ".mcp.json"), "mcpServers", {
|
|
74205
74638
|
command,
|
|
74206
74639
|
args: []
|
|
74207
74640
|
});
|
|
@@ -74213,11 +74646,11 @@ async function registerClaudeMcp(command) {
|
|
|
74213
74646
|
}
|
|
74214
74647
|
}
|
|
74215
74648
|
function registerCodexMcp(command) {
|
|
74216
|
-
const path =
|
|
74649
|
+
const path = join33(homedir7(), ".codex", "config.toml");
|
|
74217
74650
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
74218
74651
|
command = ${JSON.stringify(command)}`;
|
|
74219
74652
|
try {
|
|
74220
|
-
const current = existsSync30(path) ?
|
|
74653
|
+
const current = existsSync30(path) ? readFileSync26(path, "utf-8") : "";
|
|
74221
74654
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
74222
74655
|
return { agent: "codex", success: true, path, config: config2 };
|
|
74223
74656
|
} catch (err) {
|
|
@@ -74225,7 +74658,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
74225
74658
|
}
|
|
74226
74659
|
}
|
|
74227
74660
|
function registerOpenCodeMcp(command) {
|
|
74228
|
-
const path =
|
|
74661
|
+
const path = join33(homedir7(), ".config", "opencode", "opencode.json");
|
|
74229
74662
|
const config2 = JSON.stringify({
|
|
74230
74663
|
$schema: "https://opencode.ai/config.json",
|
|
74231
74664
|
mcp: {
|
|
@@ -74269,7 +74702,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
74269
74702
|
function readJsonObject2(path) {
|
|
74270
74703
|
if (!existsSync30(path))
|
|
74271
74704
|
return {};
|
|
74272
|
-
const raw =
|
|
74705
|
+
const raw = readFileSync26(path, "utf-8").trim();
|
|
74273
74706
|
if (!raw)
|
|
74274
74707
|
return {};
|
|
74275
74708
|
const parsed = JSON.parse(raw);
|
|
@@ -74282,8 +74715,8 @@ function writeJsonObject(path, data) {
|
|
|
74282
74715
|
`);
|
|
74283
74716
|
}
|
|
74284
74717
|
function writeTextFile(path, content) {
|
|
74285
|
-
|
|
74286
|
-
|
|
74718
|
+
mkdirSync15(dirname11(path), { recursive: true });
|
|
74719
|
+
writeFileSync15(path, content.endsWith(`
|
|
74287
74720
|
`) ? content : `${content}
|
|
74288
74721
|
`);
|
|
74289
74722
|
}
|
|
@@ -74313,7 +74746,7 @@ function findCommandOnPath(command) {
|
|
|
74313
74746
|
for (const dir of pathValue.split(":")) {
|
|
74314
74747
|
if (!dir)
|
|
74315
74748
|
continue;
|
|
74316
|
-
const candidate =
|
|
74749
|
+
const candidate = join33(dir, command);
|
|
74317
74750
|
if (existsSync30(candidate))
|
|
74318
74751
|
return candidate;
|
|
74319
74752
|
}
|
|
@@ -74375,8 +74808,8 @@ var exports_runtime = {};
|
|
|
74375
74808
|
__export(exports_runtime, {
|
|
74376
74809
|
registerRuntime: () => registerRuntime
|
|
74377
74810
|
});
|
|
74378
|
-
import { lstatSync as
|
|
74379
|
-
import { basename as basename5, isAbsolute as isAbsolute4, join as
|
|
74811
|
+
import { lstatSync as lstatSync7, mkdirSync as mkdirSync16, readFileSync as readFileSync27, realpathSync as realpathSync2, writeFileSync as writeFileSync16 } from "fs";
|
|
74812
|
+
import { basename as basename5, isAbsolute as isAbsolute4, join as join34 } from "path";
|
|
74380
74813
|
import { createInterface } from "readline";
|
|
74381
74814
|
function registerRuntime(parent) {
|
|
74382
74815
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
@@ -74650,10 +75083,10 @@ async function handleRun(name, args2, options) {
|
|
|
74650
75083
|
try {
|
|
74651
75084
|
parsePollingOptions(options);
|
|
74652
75085
|
inputFiles = (options.file ?? []).map((path) => {
|
|
74653
|
-
const info =
|
|
75086
|
+
const info = lstatSync7(path);
|
|
74654
75087
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
74655
75088
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
74656
|
-
return { name: basename5(path), bytes: new Uint8Array(
|
|
75089
|
+
return { name: basename5(path), bytes: new Uint8Array(readFileSync27(path)) };
|
|
74657
75090
|
});
|
|
74658
75091
|
describeRemoteFiles(inputFiles);
|
|
74659
75092
|
client = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
|
|
@@ -75024,7 +75457,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
75024
75457
|
const canonicalSkill = typeof remoteRun.skill === "string" ? remoteRun.skill : "remote";
|
|
75025
75458
|
const requestedSkill = typeof remoteRun.requestedSlug === "string" && remoteRun.requestedSlug.trim() ? remoteRun.requestedSlug : canonicalSkill;
|
|
75026
75459
|
const exportDir = getRunExportDir(runId, requestedSkill);
|
|
75027
|
-
|
|
75460
|
+
mkdirSync16(exportDir, { recursive: true });
|
|
75028
75461
|
const downloaded = [];
|
|
75029
75462
|
for (const artifact of artifacts) {
|
|
75030
75463
|
const artifactId = String(artifact.id || "");
|
|
@@ -75032,9 +75465,9 @@ async function handleExportsDownload(runId, options) {
|
|
|
75032
75465
|
continue;
|
|
75033
75466
|
const verified = await client.getVerifiedRunArtifact(runId, artifactId);
|
|
75034
75467
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
75035
|
-
const outputPath =
|
|
75468
|
+
const outputPath = join34(exportDir, relativePath);
|
|
75036
75469
|
ensureSafeExportParent(exportDir, relativePath);
|
|
75037
|
-
|
|
75470
|
+
writeFileSync16(outputPath, verified.bytes, { flag: "wx", mode: 384 });
|
|
75038
75471
|
downloaded.push({ id: artifactId, path: outputPath, byteSize: verified.byteSize });
|
|
75039
75472
|
}
|
|
75040
75473
|
const payload = {
|
|
@@ -75071,14 +75504,14 @@ function ensureSafeExportParent(root, relativePath) {
|
|
|
75071
75504
|
let parent = root;
|
|
75072
75505
|
for (const part of ["", ...parts]) {
|
|
75073
75506
|
if (part)
|
|
75074
|
-
parent =
|
|
75507
|
+
parent = join34(parent, part);
|
|
75075
75508
|
try {
|
|
75076
|
-
if (!
|
|
75509
|
+
if (!lstatSync7(parent).isDirectory() || lstatSync7(parent).isSymbolicLink())
|
|
75077
75510
|
throw new Error("Unsafe artifact directory");
|
|
75078
75511
|
} catch (error2) {
|
|
75079
75512
|
if (error2.code !== "ENOENT")
|
|
75080
75513
|
throw error2;
|
|
75081
|
-
|
|
75514
|
+
mkdirSync16(parent, { mode: 448 });
|
|
75082
75515
|
}
|
|
75083
75516
|
}
|
|
75084
75517
|
}
|
|
@@ -75416,7 +75849,7 @@ var init_completion = __esm(() => {
|
|
|
75416
75849
|
// src/lib/portable-snapshot-filter.ts
|
|
75417
75850
|
import { readdirSync as readdirSync16, statSync as statSync17 } from "fs";
|
|
75418
75851
|
import { homedir as homedir8 } from "os";
|
|
75419
|
-
import { join as
|
|
75852
|
+
import { join as join35, sep as sep3 } from "path";
|
|
75420
75853
|
function isExcludedSkillFileName(fileName) {
|
|
75421
75854
|
if (EXCLUDE_FILE_NAMES.has(fileName)) {
|
|
75422
75855
|
return true;
|
|
@@ -75439,16 +75872,16 @@ function isPortableWithinSkill(relativeParts) {
|
|
|
75439
75872
|
function homePathFor(definition, homesRoot) {
|
|
75440
75873
|
const home = homesRoot ?? homedir8();
|
|
75441
75874
|
if (definition.subClass === "skills" || definition.subClass === "custom") {
|
|
75442
|
-
return
|
|
75875
|
+
return join35(skillsDataRootForHome(home), definition.name);
|
|
75443
75876
|
}
|
|
75444
75877
|
if (definition.agent === "opencode") {
|
|
75445
|
-
return
|
|
75878
|
+
return join35(home, ".config", "opencode", "skills");
|
|
75446
75879
|
}
|
|
75447
|
-
return
|
|
75880
|
+
return join35(home, `.${definition.agent}`, "skills");
|
|
75448
75881
|
}
|
|
75449
75882
|
function destinationFor(definition, stationId, relativePath) {
|
|
75450
|
-
const category = definition.subClass === "agent-homes" ?
|
|
75451
|
-
return
|
|
75883
|
+
const category = definition.subClass === "agent-homes" ? join35("agent-homes", definition.agent ?? "") : definition.name;
|
|
75884
|
+
return join35("resources", stationId, "skills", category, ...relativePath.split(sep3));
|
|
75452
75885
|
}
|
|
75453
75886
|
function walkEntries(absoluteRoot) {
|
|
75454
75887
|
let entries;
|
|
@@ -75459,7 +75892,7 @@ function walkEntries(absoluteRoot) {
|
|
|
75459
75892
|
}
|
|
75460
75893
|
const output = [];
|
|
75461
75894
|
for (const entry of entries) {
|
|
75462
|
-
const childFull =
|
|
75895
|
+
const childFull = join35(absoluteRoot, entry.name);
|
|
75463
75896
|
if (entry.isSymbolicLink()) {
|
|
75464
75897
|
output.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
|
|
75465
75898
|
continue;
|
|
@@ -75470,7 +75903,7 @@ function walkEntries(absoluteRoot) {
|
|
|
75470
75903
|
}
|
|
75471
75904
|
const nested = walkEntries(childFull);
|
|
75472
75905
|
for (const item of nested) {
|
|
75473
|
-
output.push({ ...item, relativePath:
|
|
75906
|
+
output.push({ ...item, relativePath: join35(entry.name, item.relativePath) });
|
|
75474
75907
|
}
|
|
75475
75908
|
continue;
|
|
75476
75909
|
}
|
|
@@ -75566,19 +75999,19 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
75566
75999
|
import { createHash as createHash7 } from "crypto";
|
|
75567
76000
|
import {
|
|
75568
76001
|
copyFileSync as copyFileSync2,
|
|
75569
|
-
mkdirSync as
|
|
75570
|
-
readFileSync as
|
|
76002
|
+
mkdirSync as mkdirSync17,
|
|
76003
|
+
readFileSync as readFileSync28,
|
|
75571
76004
|
statSync as statSync18,
|
|
75572
|
-
writeFileSync as
|
|
76005
|
+
writeFileSync as writeFileSync17
|
|
75573
76006
|
} from "fs";
|
|
75574
|
-
import { dirname as
|
|
76007
|
+
import { dirname as dirname13, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve3, sep as sep4 } from "path";
|
|
75575
76008
|
function validateStationId(stationId) {
|
|
75576
76009
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
75577
76010
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
75578
76011
|
}
|
|
75579
76012
|
}
|
|
75580
76013
|
function sha256File(filePath) {
|
|
75581
|
-
return createHash7("sha256").update(
|
|
76014
|
+
return createHash7("sha256").update(readFileSync28(filePath)).digest("hex");
|
|
75582
76015
|
}
|
|
75583
76016
|
function scanHome(definition, homesRoot) {
|
|
75584
76017
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -75699,7 +76132,7 @@ function writeStationSnapshot(options) {
|
|
|
75699
76132
|
let written = 0;
|
|
75700
76133
|
for (const plan of untouched) {
|
|
75701
76134
|
const destination = resolve3(repoRoot, plan.destination);
|
|
75702
|
-
|
|
76135
|
+
mkdirSync17(dirname13(destination), { recursive: true });
|
|
75703
76136
|
copyFileSync2(plan.source.fullPath, destination);
|
|
75704
76137
|
written += 1;
|
|
75705
76138
|
}
|
|
@@ -75718,8 +76151,8 @@ function writeStationSnapshot(options) {
|
|
|
75718
76151
|
files: manifestFiles
|
|
75719
76152
|
};
|
|
75720
76153
|
const manifestPath = resolve3(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
75721
|
-
|
|
75722
|
-
|
|
76154
|
+
mkdirSync17(dirname13(manifestPath), { recursive: true });
|
|
76155
|
+
writeFileSync17(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
75723
76156
|
`);
|
|
75724
76157
|
return {
|
|
75725
76158
|
...base2,
|
|
@@ -75751,7 +76184,7 @@ __export(exports_create_sync_config, {
|
|
|
75751
76184
|
registerCreateSync: () => registerCreateSync
|
|
75752
76185
|
});
|
|
75753
76186
|
import { existsSync as existsSync31 } from "fs";
|
|
75754
|
-
import { join as
|
|
76187
|
+
import { join as join36 } from "path";
|
|
75755
76188
|
function registerCreateSync(parent) {
|
|
75756
76189
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
75757
76190
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -75857,7 +76290,7 @@ function handleCreate(name, options) {
|
|
|
75857
76290
|
console.log(source_default.green(`\u2713 Created custom skill '${result2.name}' at ${result2.path}`));
|
|
75858
76291
|
console.log(source_default.dim(` Category: ${result2.manifest.category}`));
|
|
75859
76292
|
console.log(source_default.dim(` Tags: ${result2.manifest.tags?.join(", ")}`));
|
|
75860
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
76293
|
+
console.log(` ${source_default.cyan("Edit:")} ${join36(result2.path, "src", "index.ts")}`);
|
|
75861
76294
|
console.log(` ${source_default.cyan("Run:")} skills run ${result2.name} --help`);
|
|
75862
76295
|
}
|
|
75863
76296
|
} catch (error2) {
|
|
@@ -76136,27 +76569,27 @@ var init_create_sync_config = __esm(() => {
|
|
|
76136
76569
|
import { createHash as createHash8 } from "crypto";
|
|
76137
76570
|
import {
|
|
76138
76571
|
copyFileSync as copyFileSync3,
|
|
76139
|
-
mkdirSync as
|
|
76572
|
+
mkdirSync as mkdirSync18,
|
|
76140
76573
|
readdirSync as readdirSync17,
|
|
76141
|
-
readFileSync as
|
|
76574
|
+
readFileSync as readFileSync29,
|
|
76142
76575
|
statSync as statSync19,
|
|
76143
|
-
writeFileSync as
|
|
76576
|
+
writeFileSync as writeFileSync18
|
|
76144
76577
|
} from "fs";
|
|
76145
|
-
import { dirname as
|
|
76146
|
-
function
|
|
76578
|
+
import { dirname as dirname14, join as join37, resolve as resolve4, sep as sep5 } from "path";
|
|
76579
|
+
function fail3(code, message, detail = []) {
|
|
76147
76580
|
throw new StationSnapshotError(code, message, detail);
|
|
76148
76581
|
}
|
|
76149
76582
|
function snapshotRootFor(repoRoot, stationId) {
|
|
76150
|
-
return
|
|
76583
|
+
return join37(repoRoot, "resources", stationId, "skills");
|
|
76151
76584
|
}
|
|
76152
76585
|
function readSnapshotManifest(repoRoot, stationId) {
|
|
76153
76586
|
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
76154
|
-
const manifestPath =
|
|
76587
|
+
const manifestPath = join37(snapshotRoot, "sync-manifest.json");
|
|
76155
76588
|
let manifest;
|
|
76156
76589
|
try {
|
|
76157
|
-
manifest = JSON.parse(
|
|
76590
|
+
manifest = JSON.parse(readFileSync29(manifestPath, "utf8"));
|
|
76158
76591
|
} catch (error2) {
|
|
76159
|
-
|
|
76592
|
+
fail3("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error2.message}`);
|
|
76160
76593
|
}
|
|
76161
76594
|
const sourceSnapshotSha = sha256File(manifestPath);
|
|
76162
76595
|
return { manifest, manifestPath, sourceSnapshotSha };
|
|
@@ -76178,7 +76611,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76178
76611
|
const hashMismatches = [];
|
|
76179
76612
|
const skippedByRule = [];
|
|
76180
76613
|
for (const agent of SYNC_AGENTS) {
|
|
76181
|
-
const agentRoot =
|
|
76614
|
+
const agentRoot = join37(snapshotRoot, "agent-homes", agent);
|
|
76182
76615
|
let identEntries;
|
|
76183
76616
|
try {
|
|
76184
76617
|
identEntries = readdirSync17(agentRoot, { withFileTypes: true });
|
|
@@ -76189,7 +76622,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76189
76622
|
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
76190
76623
|
continue;
|
|
76191
76624
|
}
|
|
76192
|
-
const identRoot =
|
|
76625
|
+
const identRoot = join37(agentRoot, identEntry.name);
|
|
76193
76626
|
const entries = walkEntries(identRoot);
|
|
76194
76627
|
for (const entry of entries) {
|
|
76195
76628
|
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep5)];
|
|
@@ -76263,10 +76696,10 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76263
76696
|
}
|
|
76264
76697
|
}
|
|
76265
76698
|
if (symlinks.length > 0) {
|
|
76266
|
-
|
|
76699
|
+
fail3("SYMLINKS_REFUSED", `${symlinks.length} symlink(s) inside the snapshot; symlinks are refused (fail closed)`);
|
|
76267
76700
|
}
|
|
76268
76701
|
if (hashMismatches.length > 0) {
|
|
76269
|
-
|
|
76702
|
+
fail3("MANIFEST_HASH_MISMATCH", `${hashMismatches.length} snapshot file(s) no longer match their sync-manifest sha256; ` + "stale or tampered content is refused (fail closed), nothing written \u2014 re-run sync to refresh the manifest", hashMismatches.map((mismatch) => `agent-homes/${mismatch.agent}/${mismatch.ident}/${mismatch.relativePath}`));
|
|
76270
76703
|
}
|
|
76271
76704
|
const byIdent = new Map;
|
|
76272
76705
|
for (const candidate of candidates) {
|
|
@@ -76290,7 +76723,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76290
76723
|
for (const copy of copies) {
|
|
76291
76724
|
let isStub = false;
|
|
76292
76725
|
try {
|
|
76293
|
-
isStub = isPointerSkillMd(
|
|
76726
|
+
isStub = isPointerSkillMd(readFileSync29(copy.fullPath, "utf8"));
|
|
76294
76727
|
} catch {
|
|
76295
76728
|
isStub = false;
|
|
76296
76729
|
}
|
|
@@ -76374,7 +76807,7 @@ function writeStationHydration(options) {
|
|
|
76374
76807
|
const toWrite = [];
|
|
76375
76808
|
for (const skill of plan.winners) {
|
|
76376
76809
|
for (const file of skill.files) {
|
|
76377
|
-
const destination =
|
|
76810
|
+
const destination = join37(cacheRoot, skill.ident, file.withinIdent);
|
|
76378
76811
|
const digest = sha256File(file.winner.fullPath);
|
|
76379
76812
|
let existingDigest = null;
|
|
76380
76813
|
try {
|
|
@@ -76391,11 +76824,11 @@ function writeStationHydration(options) {
|
|
|
76391
76824
|
}
|
|
76392
76825
|
}
|
|
76393
76826
|
if (conflicts.length > 0) {
|
|
76394
|
-
|
|
76827
|
+
fail3("CONFLICT", `${conflicts.length} conflict(s); terminal non-acceptance, nothing written`, conflicts);
|
|
76395
76828
|
}
|
|
76396
76829
|
let written = 0;
|
|
76397
76830
|
for (const entry of toWrite) {
|
|
76398
|
-
|
|
76831
|
+
mkdirSync18(dirname14(entry.destination), { recursive: true });
|
|
76399
76832
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
76400
76833
|
written += 1;
|
|
76401
76834
|
}
|
|
@@ -76416,9 +76849,9 @@ function writeStationHydration(options) {
|
|
|
76416
76849
|
},
|
|
76417
76850
|
skills: resultSkills
|
|
76418
76851
|
};
|
|
76419
|
-
const hydrationManifestPath =
|
|
76420
|
-
|
|
76421
|
-
|
|
76852
|
+
const hydrationManifestPath = join37(dirname14(cacheRoot), `hydration-${options.stationId}.json`);
|
|
76853
|
+
mkdirSync18(dirname14(hydrationManifestPath), { recursive: true });
|
|
76854
|
+
writeFileSync18(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
76422
76855
|
`);
|
|
76423
76856
|
return {
|
|
76424
76857
|
...base2,
|
|
@@ -76846,8 +77279,8 @@ var init_schedule = __esm(() => {
|
|
|
76846
77279
|
});
|
|
76847
77280
|
|
|
76848
77281
|
// src/lib/registry-sync.ts
|
|
76849
|
-
import { mkdirSync as
|
|
76850
|
-
import { dirname as
|
|
77282
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync19 } from "fs";
|
|
77283
|
+
import { dirname as dirname15, relative as relative6 } from "path";
|
|
76851
77284
|
function createRegistrySyncArtifact(options = {}) {
|
|
76852
77285
|
const profile = options.profile ?? "all";
|
|
76853
77286
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -76904,8 +77337,8 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
76904
77337
|
};
|
|
76905
77338
|
}
|
|
76906
77339
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
76907
|
-
|
|
76908
|
-
|
|
77340
|
+
mkdirSync19(dirname15(path), { recursive: true });
|
|
77341
|
+
writeFileSync19(path, `${JSON.stringify(artifact, null, 2)}
|
|
76909
77342
|
`);
|
|
76910
77343
|
}
|
|
76911
77344
|
function buildDocs(name) {
|
|
@@ -76935,10 +77368,10 @@ function registerRegistry(parent) {
|
|
|
76935
77368
|
registry2.command("sync").description("Generate a deterministic registry sync artifact").option("--profile <profile>", "Registry profile: basic or all", "all").option("--output <path>", "Write artifact to a JSON file").option("--no-docs", "Exclude skill documentation content").option("--no-requirements", "Exclude extracted skill requirements").option("--no-validation", "Exclude validation results").option("--json", "Print artifact JSON to stdout", false).action((options) => handleRegistrySync(options));
|
|
76936
77369
|
}
|
|
76937
77370
|
async function writeJson2(value, space) {
|
|
76938
|
-
const
|
|
77371
|
+
const text2 = `${JSON.stringify(value, null, space)}
|
|
76939
77372
|
`;
|
|
76940
77373
|
await new Promise((resolve5, reject2) => {
|
|
76941
|
-
process.stdout.write(
|
|
77374
|
+
process.stdout.write(text2, (error2) => {
|
|
76942
77375
|
if (error2)
|
|
76943
77376
|
reject2(error2);
|
|
76944
77377
|
else
|
|
@@ -76970,10 +77403,10 @@ async function handleRegistrySync(options) {
|
|
|
76970
77403
|
await writeJson2(artifact, 2);
|
|
76971
77404
|
return;
|
|
76972
77405
|
}
|
|
76973
|
-
const
|
|
77406
|
+
const invalid2 = artifact.summary.invalidSkillCount ?? "not checked";
|
|
76974
77407
|
console.log(source_default.green(`Registry sync artifact written to ${options.output}`));
|
|
76975
77408
|
console.log(source_default.dim(` Skills: ${artifact.summary.skillCount}`));
|
|
76976
|
-
console.log(source_default.dim(` Invalid: ${
|
|
77409
|
+
console.log(source_default.dim(` Invalid: ${invalid2}`));
|
|
76977
77410
|
}
|
|
76978
77411
|
function registerPull(parent) {
|
|
76979
77412
|
parent.command("pull").argument("[names...]", "Skills to pull from the configured instance (name or name@version)").option("--all", "Pull every skill the instance serves", false).option("--for-machine", "Prepare this machine with the instance's full catalog (implies --all)", false).option("--json", "Output results as JSON", false).description("Fetch skills from the configured Skills instance into this machine's corpus").action(async (names, options) => {
|
|
@@ -77078,9 +77511,9 @@ __export(exports_publish, {
|
|
|
77078
77511
|
PushSkillError: () => PushSkillError
|
|
77079
77512
|
});
|
|
77080
77513
|
import { execFileSync } from "child_process";
|
|
77081
|
-
import { existsSync as existsSync32, readFileSync as
|
|
77514
|
+
import { existsSync as existsSync32, readFileSync as readFileSync30 } from "fs";
|
|
77082
77515
|
import { hostname as hostname2 } from "os";
|
|
77083
|
-
import { join as
|
|
77516
|
+
import { join as join38 } from "path";
|
|
77084
77517
|
function registerPublish(parent) {
|
|
77085
77518
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--force-new-version", "If name@version already exists with different content, publish as the next patch version", false).option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
77086
77519
|
try {
|
|
@@ -77127,8 +77560,8 @@ async function pushSkill(name, options = {}) {
|
|
|
77127
77560
|
}
|
|
77128
77561
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
77129
77562
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
77130
|
-
const skillMdPath =
|
|
77131
|
-
const skillMd = existsSync32(skillMdPath) ?
|
|
77563
|
+
const skillMdPath = join38(skill.path, "SKILL.md");
|
|
77564
|
+
const skillMd = existsSync32(skillMdPath) ? readFileSync30(skillMdPath, "utf-8") : undefined;
|
|
77132
77565
|
const base2 = {
|
|
77133
77566
|
slug: skill.name,
|
|
77134
77567
|
path: skill.path,
|
|
@@ -77193,21 +77626,21 @@ async function readPublishRevision(client, slug) {
|
|
|
77193
77626
|
throw new PushSkillError("Publishing was refused because the current skill revision could not be verified.", ["Check the configured instance and connection, then retry the push. No upload was attempted."]);
|
|
77194
77627
|
}
|
|
77195
77628
|
const body = lookup.body;
|
|
77196
|
-
const
|
|
77197
|
-
const nestedError =
|
|
77198
|
-
const code = typeof
|
|
77629
|
+
const record5 = body !== null && typeof body === "object" && !Array.isArray(body) ? body : undefined;
|
|
77630
|
+
const nestedError = record5?.error;
|
|
77631
|
+
const code = typeof record5?.code === "string" ? record5.code : nestedError !== null && typeof nestedError === "object" && !Array.isArray(nestedError) ? nestedError.code : undefined;
|
|
77199
77632
|
if (lookup.status === 404 && code === "SKILL_NOT_FOUND")
|
|
77200
77633
|
return;
|
|
77201
77634
|
if (lookup.status < 200 || lookup.status >= 300) {
|
|
77202
77635
|
throw new PushSkillError(`Publishing was refused because the current skill lookup failed: HTTP ${lookup.status}.`, ["Only an explicit SKILL_NOT_FOUND response establishes an initial publish. Check access and server compatibility before retrying."]);
|
|
77203
77636
|
}
|
|
77204
|
-
const revision =
|
|
77205
|
-
if (
|
|
77206
|
-
if (
|
|
77637
|
+
const revision = record5?.revisionId;
|
|
77638
|
+
if (record5?.publicationState === "catalogue-only") {
|
|
77639
|
+
if (record5.name === slug && (record5.slug === undefined || record5.slug === slug) && revision === null)
|
|
77207
77640
|
return;
|
|
77208
77641
|
throw new PushSkillError("Publishing was refused because the catalogue-only response had contradictory identity or revision state.", ["Check the configured instance and server compatibility. No upload was attempted."]);
|
|
77209
77642
|
}
|
|
77210
|
-
if (
|
|
77643
|
+
if (record5?.slug !== slug || typeof revision !== "string" || revision.length === 0 || revision !== revision.trim() || !/^[\x21-\x7e]+$/.test(revision)) {
|
|
77211
77644
|
throw new PushSkillError("Publishing was refused because the current skill response did not contain a matching slug and valid revision.", ["Check the configured instance and server compatibility. No upload was attempted."]);
|
|
77212
77645
|
}
|
|
77213
77646
|
return revision;
|
|
@@ -77310,13 +77743,13 @@ Dry run: '${result2.slug}' would be published
|
|
|
77310
77743
|
console.log("");
|
|
77311
77744
|
}
|
|
77312
77745
|
async function readBody(response) {
|
|
77313
|
-
const
|
|
77314
|
-
if (!
|
|
77746
|
+
const text2 = await response.text();
|
|
77747
|
+
if (!text2.trim())
|
|
77315
77748
|
return null;
|
|
77316
77749
|
try {
|
|
77317
|
-
return JSON.parse(
|
|
77750
|
+
return JSON.parse(text2);
|
|
77318
77751
|
} catch {
|
|
77319
|
-
return
|
|
77752
|
+
return text2;
|
|
77320
77753
|
}
|
|
77321
77754
|
}
|
|
77322
77755
|
function describeError(payload) {
|
|
@@ -77349,6 +77782,152 @@ var init_publish = __esm(() => {
|
|
|
77349
77782
|
};
|
|
77350
77783
|
});
|
|
77351
77784
|
|
|
77785
|
+
// src/cli/commands/customer-verification.ts
|
|
77786
|
+
import { emitKeypressEvents } from "readline";
|
|
77787
|
+
async function readCode() {
|
|
77788
|
+
if (process.stdin.isTTY)
|
|
77789
|
+
throw new NameInputError("Pipe a fresh six-digit verification code when using --code-stdin.");
|
|
77790
|
+
let text2 = "";
|
|
77791
|
+
for await (const chunk2 of process.stdin) {
|
|
77792
|
+
text2 += chunk2.toString();
|
|
77793
|
+
if (text2.length > 32)
|
|
77794
|
+
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77795
|
+
}
|
|
77796
|
+
const code = text2.trim();
|
|
77797
|
+
if (!/^\d{6}$/.test(code))
|
|
77798
|
+
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77799
|
+
return code;
|
|
77800
|
+
}
|
|
77801
|
+
function promptCode() {
|
|
77802
|
+
const { stdin, stderr: output } = process;
|
|
77803
|
+
const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
|
|
77804
|
+
return new Promise((resolve5) => {
|
|
77805
|
+
let value = "", settled = false;
|
|
77806
|
+
const finish = (answer) => {
|
|
77807
|
+
if (settled)
|
|
77808
|
+
return;
|
|
77809
|
+
settled = true;
|
|
77810
|
+
clearTimeout(timer);
|
|
77811
|
+
stdin.off("keypress", keypress);
|
|
77812
|
+
stdin.off("end", cancel);
|
|
77813
|
+
process.off("SIGINT", cancel);
|
|
77814
|
+
stdin.setRawMode(wasRaw);
|
|
77815
|
+
if (wasFlowing !== true)
|
|
77816
|
+
stdin.pause();
|
|
77817
|
+
output.write(`
|
|
77818
|
+
`);
|
|
77819
|
+
if (answer === null)
|
|
77820
|
+
process.exitCode = 130;
|
|
77821
|
+
resolve5(answer);
|
|
77822
|
+
};
|
|
77823
|
+
const cancel = () => finish(null);
|
|
77824
|
+
const keypress = (text2, key) => {
|
|
77825
|
+
if (key.ctrl && ["c", "d"].includes(key.name ?? "") || key.name === "escape")
|
|
77826
|
+
return cancel();
|
|
77827
|
+
if (key.name === "return" || key.name === "enter") {
|
|
77828
|
+
if (value.length === 6)
|
|
77829
|
+
return finish(value);
|
|
77830
|
+
output.write(`
|
|
77831
|
+
Enter all six digits: `);
|
|
77832
|
+
value = "";
|
|
77833
|
+
return;
|
|
77834
|
+
}
|
|
77835
|
+
if (key.name === "backspace") {
|
|
77836
|
+
if (value) {
|
|
77837
|
+
value = value.slice(0, -1);
|
|
77838
|
+
output.write("\b \b");
|
|
77839
|
+
}
|
|
77840
|
+
} else if (/^[0-9]$/.test(text2) && value.length < 6) {
|
|
77841
|
+
value += text2;
|
|
77842
|
+
output.write("*");
|
|
77843
|
+
}
|
|
77844
|
+
};
|
|
77845
|
+
const timer = setTimeout(cancel, 5 * 60 * 1000);
|
|
77846
|
+
emitKeypressEvents(stdin);
|
|
77847
|
+
stdin.setRawMode(true);
|
|
77848
|
+
stdin.on("keypress", keypress);
|
|
77849
|
+
stdin.once("end", cancel);
|
|
77850
|
+
process.once("SIGINT", cancel);
|
|
77851
|
+
output.write("Enter the six-digit code sent to your email: ");
|
|
77852
|
+
stdin.resume();
|
|
77853
|
+
});
|
|
77854
|
+
}
|
|
77855
|
+
var NameInputError;
|
|
77856
|
+
var init_customer_verification = __esm(() => {
|
|
77857
|
+
NameInputError = class NameInputError extends Error {
|
|
77858
|
+
};
|
|
77859
|
+
});
|
|
77860
|
+
|
|
77861
|
+
// src/cli/commands/workspace-selection.ts
|
|
77862
|
+
async function codeFor(client, options) {
|
|
77863
|
+
if (!options.email?.includes("@"))
|
|
77864
|
+
throw new NameInputError("Provide the account email with --email.");
|
|
77865
|
+
if (options.codeStdin)
|
|
77866
|
+
return readCode();
|
|
77867
|
+
if (options.json || !process.stdin.isTTY || !process.stderr.isTTY)
|
|
77868
|
+
throw new NameInputError("Use --code-stdin with a fresh verification code for noninteractive requests.");
|
|
77869
|
+
await client.requestCode(options.email);
|
|
77870
|
+
return promptCode();
|
|
77871
|
+
}
|
|
77872
|
+
function errorResult(error2, json) {
|
|
77873
|
+
const message = error2 instanceof NameInputError || error2 instanceof WorkspaceProfileError ? error2.message : "Unable to complete workspace sign-in. Check the selected server, profile, account and fresh verification code.";
|
|
77874
|
+
if (json)
|
|
77875
|
+
console.log(JSON.stringify({ error: message }));
|
|
77876
|
+
else
|
|
77877
|
+
console.error(message);
|
|
77878
|
+
process.exitCode = 1;
|
|
77879
|
+
}
|
|
77880
|
+
function registerWorkspaceListCommand(workspace) {
|
|
77881
|
+
workspace.command("list").allowExcessArguments(false).description("Discover eligible workspaces with fresh sign-in; no credentials are saved").requiredOption("--email <email>", "Account email for fresh verification").option("--code-stdin", "Read a previously requested six-digit verification code from stdin").option("--json", "Output safe workspace identities as JSON").action(async (options) => {
|
|
77882
|
+
try {
|
|
77883
|
+
const origin = getApiUrl("Discover workspaces", { ...process.env });
|
|
77884
|
+
const client = new RemoteSkillsAuthClient(origin);
|
|
77885
|
+
const code = await codeFor(client, options);
|
|
77886
|
+
if (code === null)
|
|
77887
|
+
return;
|
|
77888
|
+
const result2 = await client.listAccountWorkspaces(options.email, code);
|
|
77889
|
+
if (options.json)
|
|
77890
|
+
console.log(JSON.stringify({ apiUrl: origin, ...result2 }));
|
|
77891
|
+
else {
|
|
77892
|
+
console.log(`Account: ${result2.userId}
|
|
77893
|
+
API: ${origin}`);
|
|
77894
|
+
for (const entry of result2.workspaces)
|
|
77895
|
+
console.log(`${entry.current ? "*" : " "} ${entry.organization.name} ${entry.role} ${entry.membershipId}`);
|
|
77896
|
+
console.log("* Initial sign-in workspace. Enroll a named profile with auth login --membership-id <id>.");
|
|
77897
|
+
}
|
|
77898
|
+
} catch (error2) {
|
|
77899
|
+
errorResult(error2, options.json);
|
|
77900
|
+
}
|
|
77901
|
+
});
|
|
77902
|
+
}
|
|
77903
|
+
async function loginWorkspace(options) {
|
|
77904
|
+
try {
|
|
77905
|
+
const enrollment = await prepareWorkspaceEnrollment(options.membershipId);
|
|
77906
|
+
const code = await codeFor(new RemoteSkillsAuthClient(enrollment.origin), options);
|
|
77907
|
+
if (code === null)
|
|
77908
|
+
return;
|
|
77909
|
+
const result2 = await enrollment.complete(options.email, code);
|
|
77910
|
+
if (options.json)
|
|
77911
|
+
console.log(JSON.stringify(result2));
|
|
77912
|
+
else
|
|
77913
|
+
console.log(`Signed in as ${result2.email}
|
|
77914
|
+
Profile: ${result2.profile}
|
|
77915
|
+
API: ${result2.apiUrl}
|
|
77916
|
+
Workspace: ${result2.organization} (${result2.organizationId})
|
|
77917
|
+
Membership: ${result2.membershipId}
|
|
77918
|
+
Role: ${result2.role}
|
|
77919
|
+
One workspace key saved. Use HASNA_PROFILE=${result2.profile} for subsequent commands.`);
|
|
77920
|
+
} catch (error2) {
|
|
77921
|
+
errorResult(error2, options.json);
|
|
77922
|
+
}
|
|
77923
|
+
}
|
|
77924
|
+
var init_workspace_selection = __esm(() => {
|
|
77925
|
+
init_auth_store();
|
|
77926
|
+
init_remote_auth();
|
|
77927
|
+
init_workspace_profile();
|
|
77928
|
+
init_customer_verification();
|
|
77929
|
+
});
|
|
77930
|
+
|
|
77352
77931
|
// src/cli/commands/auth.ts
|
|
77353
77932
|
var exports_auth = {};
|
|
77354
77933
|
__export(exports_auth, {
|
|
@@ -77434,13 +78013,13 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
|
77434
78013
|
const root = recordField(live) ?? {};
|
|
77435
78014
|
const data = recordField(root.data);
|
|
77436
78015
|
const user = recordField(root.user) ?? recordField(data?.user);
|
|
77437
|
-
const
|
|
78016
|
+
const organization2 = recordField(root.organization) ?? recordField(root.org) ?? recordField(data?.organization);
|
|
77438
78017
|
const email2 = stringField2(user?.email) ?? cached2?.email;
|
|
77439
|
-
const orgSlug = stringField2(
|
|
77440
|
-
const orgName = stringField2(
|
|
78018
|
+
const orgSlug = stringField2(organization2?.slug) ?? cached2?.orgSlug;
|
|
78019
|
+
const orgName = stringField2(organization2?.name);
|
|
77441
78020
|
const userId = stringField2(user?.id) ?? cached2?.userId;
|
|
77442
|
-
const orgId = stringField2(
|
|
77443
|
-
const
|
|
78021
|
+
const orgId = stringField2(organization2?.id) ?? cached2?.orgId;
|
|
78022
|
+
const role2 = stringField2(user?.role);
|
|
77444
78023
|
return {
|
|
77445
78024
|
status: "authenticated",
|
|
77446
78025
|
authSource,
|
|
@@ -77450,7 +78029,7 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
|
77450
78029
|
...orgName ? { organizationName: orgName } : {},
|
|
77451
78030
|
...userId ? { userId } : {},
|
|
77452
78031
|
...orgId ? { orgId } : {},
|
|
77453
|
-
...
|
|
78032
|
+
...role2 ? { role: role2 } : {}
|
|
77454
78033
|
};
|
|
77455
78034
|
}
|
|
77456
78035
|
function printWhoami(payload) {
|
|
@@ -77748,15 +78327,19 @@ function registerAuth(parent) {
|
|
|
77748
78327
|
const keys2 = auth.command("keys").description("Manage API keys on the configured instance");
|
|
77749
78328
|
keys2.command("list").option("--json", "Output as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").action(async (options) => {
|
|
77750
78329
|
try {
|
|
77751
|
-
|
|
78330
|
+
const target = await captureProfileWorkspace("List API keys");
|
|
78331
|
+
target.unchanged();
|
|
78332
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(target.origin).listApiKeys(options.email, options.code, target.context), null, 2));
|
|
77752
78333
|
} catch (error2) {
|
|
77753
78334
|
writeCommandError(error2, "Failed to list API keys", options.json);
|
|
77754
78335
|
}
|
|
77755
78336
|
});
|
|
77756
78337
|
keys2.command("create").argument("<name>").option("--scope <scope>", "Limit key scope (repeatable)", (value, all) => [...all, value], []).option("--json", "Output the newly created key as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").description("Create a key; the returned secret is shown once and must be stored securely").action(async (name, options) => {
|
|
77757
78338
|
try {
|
|
77758
|
-
const
|
|
77759
|
-
const
|
|
78339
|
+
const target = await captureProfileWorkspace("Create API key");
|
|
78340
|
+
const client = new RemoteSkillsAuthClient(target.origin);
|
|
78341
|
+
target.unchanged();
|
|
78342
|
+
const created = await client.createApiKey(options.email, options.code, name, options.scope.length ? options.scope : undefined, target.context);
|
|
77760
78343
|
console.log(JSON.stringify(created, null, 2));
|
|
77761
78344
|
} catch (error2) {
|
|
77762
78345
|
writeCommandError(error2, "Failed to create API key", options.json);
|
|
@@ -77764,12 +78347,26 @@ function registerAuth(parent) {
|
|
|
77764
78347
|
});
|
|
77765
78348
|
keys2.command("revoke").argument("<key-id>").option("--json", "Output as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").action(async (id, options) => {
|
|
77766
78349
|
try {
|
|
77767
|
-
|
|
78350
|
+
const target = await captureProfileWorkspace("Revoke API key");
|
|
78351
|
+
target.unchanged();
|
|
78352
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(target.origin).revokeApiKey(options.email, options.code, id, target.context), null, 2));
|
|
77768
78353
|
} catch (error2) {
|
|
77769
78354
|
writeCommandError(error2, "Failed to revoke API key", options.json);
|
|
77770
78355
|
}
|
|
77771
78356
|
});
|
|
77772
|
-
auth.command("login").description("Sign in with browser/device code or email code").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").option("--api-key <key>", "Verify and store an API key").option("--device", "Use browser/device-code login", false).option("--no-open", "Do not open a browser for device-code login").option("--poll", "Poll until browser authentication completes in non-interactive mode", false).option("--poll-timeout-ms <ms>", "Maximum time to wait for device-code login").option("--json", "Output result as JSON", false).action(async (options) => {
|
|
78357
|
+
auth.command("login").description("Sign in with browser/device code or email code").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").option("--membership-id <id>", "Enroll an exact workspace membership into an explicit HASNA_PROFILE").option("--code-stdin", "Read a fresh six-digit code for workspace enrollment from stdin").option("--api-key <key>", "Verify and store an API key").option("--device", "Use browser/device-code login", false).option("--no-open", "Do not open a browser for device-code login").option("--poll", "Poll until browser authentication completes in non-interactive mode", false).option("--poll-timeout-ms <ms>", "Maximum time to wait for device-code login").option("--json", "Output result as JSON", false).action(async (options) => {
|
|
78358
|
+
if (options.membershipId !== undefined) {
|
|
78359
|
+
if (options.apiKey || options.device || options.code || options.poll) {
|
|
78360
|
+
writeCommandError(new Error("Workspace login uses email and --code-stdin; do not combine it with device, API key or --code login."), "Invalid login options", options.json);
|
|
78361
|
+
return;
|
|
78362
|
+
}
|
|
78363
|
+
await loginWorkspace({ ...options, membershipId: options.membershipId });
|
|
78364
|
+
return;
|
|
78365
|
+
}
|
|
78366
|
+
if (options.codeStdin) {
|
|
78367
|
+
writeCommandError(new Error("--code-stdin requires --membership-id for this login flow."), "Invalid login options", options.json);
|
|
78368
|
+
return;
|
|
78369
|
+
}
|
|
77773
78370
|
if (options.apiKey) {
|
|
77774
78371
|
await doApiKeyLogin(options.apiKey, options.json);
|
|
77775
78372
|
return;
|
|
@@ -77877,6 +78474,8 @@ function registerAuth(parent) {
|
|
|
77877
78474
|
}
|
|
77878
78475
|
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS, CONFIG_HINT_STATUSES;
|
|
77879
78476
|
var init_auth = __esm(() => {
|
|
78477
|
+
init_workspace_selection();
|
|
78478
|
+
init_workspace_profile();
|
|
77880
78479
|
init_source();
|
|
77881
78480
|
init_auth_store();
|
|
77882
78481
|
init_fleet_credentials();
|
|
@@ -77886,82 +78485,6 @@ var init_auth = __esm(() => {
|
|
|
77886
78485
|
CONFIG_HINT_STATUSES = new Set([401, 403, 404, 405, 501]);
|
|
77887
78486
|
});
|
|
77888
78487
|
|
|
77889
|
-
// src/cli/commands/customer-verification.ts
|
|
77890
|
-
import { emitKeypressEvents } from "readline";
|
|
77891
|
-
async function readCode() {
|
|
77892
|
-
if (process.stdin.isTTY)
|
|
77893
|
-
throw new NameInputError("Pipe a fresh six-digit verification code when using --code-stdin.");
|
|
77894
|
-
let text = "";
|
|
77895
|
-
for await (const chunk2 of process.stdin) {
|
|
77896
|
-
text += chunk2.toString();
|
|
77897
|
-
if (text.length > 32)
|
|
77898
|
-
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77899
|
-
}
|
|
77900
|
-
const code = text.trim();
|
|
77901
|
-
if (!/^\d{6}$/.test(code))
|
|
77902
|
-
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77903
|
-
return code;
|
|
77904
|
-
}
|
|
77905
|
-
function promptCode() {
|
|
77906
|
-
const { stdin, stderr: output } = process;
|
|
77907
|
-
const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
|
|
77908
|
-
return new Promise((resolve5) => {
|
|
77909
|
-
let value = "", settled = false;
|
|
77910
|
-
const finish = (answer) => {
|
|
77911
|
-
if (settled)
|
|
77912
|
-
return;
|
|
77913
|
-
settled = true;
|
|
77914
|
-
clearTimeout(timer);
|
|
77915
|
-
stdin.off("keypress", keypress);
|
|
77916
|
-
stdin.off("end", cancel);
|
|
77917
|
-
process.off("SIGINT", cancel);
|
|
77918
|
-
stdin.setRawMode(wasRaw);
|
|
77919
|
-
if (wasFlowing !== true)
|
|
77920
|
-
stdin.pause();
|
|
77921
|
-
output.write(`
|
|
77922
|
-
`);
|
|
77923
|
-
if (answer === null)
|
|
77924
|
-
process.exitCode = 130;
|
|
77925
|
-
resolve5(answer);
|
|
77926
|
-
};
|
|
77927
|
-
const cancel = () => finish(null);
|
|
77928
|
-
const keypress = (text, key) => {
|
|
77929
|
-
if (key.ctrl && ["c", "d"].includes(key.name ?? "") || key.name === "escape")
|
|
77930
|
-
return cancel();
|
|
77931
|
-
if (key.name === "return" || key.name === "enter") {
|
|
77932
|
-
if (value.length === 6)
|
|
77933
|
-
return finish(value);
|
|
77934
|
-
output.write(`
|
|
77935
|
-
Enter all six digits: `);
|
|
77936
|
-
value = "";
|
|
77937
|
-
return;
|
|
77938
|
-
}
|
|
77939
|
-
if (key.name === "backspace") {
|
|
77940
|
-
if (value) {
|
|
77941
|
-
value = value.slice(0, -1);
|
|
77942
|
-
output.write("\b \b");
|
|
77943
|
-
}
|
|
77944
|
-
} else if (/^[0-9]$/.test(text) && value.length < 6) {
|
|
77945
|
-
value += text;
|
|
77946
|
-
output.write("*");
|
|
77947
|
-
}
|
|
77948
|
-
};
|
|
77949
|
-
const timer = setTimeout(cancel, 5 * 60 * 1000);
|
|
77950
|
-
emitKeypressEvents(stdin);
|
|
77951
|
-
stdin.setRawMode(true);
|
|
77952
|
-
stdin.on("keypress", keypress);
|
|
77953
|
-
stdin.once("end", cancel);
|
|
77954
|
-
process.once("SIGINT", cancel);
|
|
77955
|
-
output.write("Enter the six-digit code sent to your email: ");
|
|
77956
|
-
stdin.resume();
|
|
77957
|
-
});
|
|
77958
|
-
}
|
|
77959
|
-
var NameInputError;
|
|
77960
|
-
var init_customer_verification = __esm(() => {
|
|
77961
|
-
NameInputError = class NameInputError extends Error {
|
|
77962
|
-
};
|
|
77963
|
-
});
|
|
77964
|
-
|
|
77965
78488
|
// src/cli/commands/workspace-members.ts
|
|
77966
78489
|
function registerWorkspaceMembersCommand(workspace) {
|
|
77967
78490
|
workspace.command("members").allowExcessArguments(false).description("List the current workspace roster with fresh owner/admin verification").requiredOption("--email <email>", "Account email for fresh verification").option("--code-stdin", "Read a previously requested six-digit verification code from stdin").option("--limit <count>", "Page size from 1 to 100 (server default: 50)").option("--cursor <cursor>", "Unchanged nextCursor from the preceding page").option("--json", "Output the complete page as JSON").action(async (options) => {
|
|
@@ -77970,7 +78493,8 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
77970
78493
|
throw new NameInputError("Use a roster limit from 1 to 100.");
|
|
77971
78494
|
const page = { limit: options.limit === undefined ? undefined : Number(options.limit), cursor: options.cursor };
|
|
77972
78495
|
workspaceMembersQuery(page);
|
|
77973
|
-
const
|
|
78496
|
+
const pending = prepareProfileWorkspace("List workspace members");
|
|
78497
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
77974
78498
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
77975
78499
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive roster requests.");
|
|
77976
78500
|
let code;
|
|
@@ -77982,16 +78506,18 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
77982
78506
|
}
|
|
77983
78507
|
if (code === null)
|
|
77984
78508
|
return;
|
|
77985
|
-
const
|
|
78509
|
+
const target = await pending.resolve();
|
|
78510
|
+
target.unchanged();
|
|
78511
|
+
const result2 = await client.listWorkspaceMembers(options.email, code, page, target.context);
|
|
77986
78512
|
if (options.json)
|
|
77987
78513
|
console.log(JSON.stringify(result2));
|
|
77988
78514
|
else {
|
|
77989
|
-
const
|
|
78515
|
+
const text2 = (value) => value.replace(/[\p{Cc}\p{Cs}\u2028\u2029]/gu, " ");
|
|
77990
78516
|
console.log(`Workspace: ${result2.organizationId}`);
|
|
77991
78517
|
if (!result2.members.length)
|
|
77992
78518
|
console.log("No members in this page.");
|
|
77993
78519
|
for (const member of result2.members)
|
|
77994
|
-
console.log(`${
|
|
78520
|
+
console.log(`${text2(member.email)} ${member.role} ${text2(member.displayName ?? "")} ${member.membershipId} ${member.createdAt}`);
|
|
77995
78521
|
if (result2.nextCursor !== null)
|
|
77996
78522
|
console.log(`Next cursor: ${result2.nextCursor}`);
|
|
77997
78523
|
}
|
|
@@ -78007,7 +78533,7 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
78007
78533
|
});
|
|
78008
78534
|
}
|
|
78009
78535
|
var init_workspace_members = __esm(() => {
|
|
78010
|
-
|
|
78536
|
+
init_workspace_profile();
|
|
78011
78537
|
init_remote_auth();
|
|
78012
78538
|
init_remote_workspace();
|
|
78013
78539
|
init_customer_verification();
|
|
@@ -78023,7 +78549,8 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78023
78549
|
command.action(async (membershipId, options) => {
|
|
78024
78550
|
try {
|
|
78025
78551
|
const captured = action === "role" ? { kind: "role", ...workspaceMemberRoleInput(membershipId, { role: options.role, expectedRole: options.expectedRole }) } : { kind: "remove", ...workspaceMemberRemovalInput(membershipId, { expectedRole: options.expectedRole }) };
|
|
78026
|
-
const
|
|
78552
|
+
const pending = prepareProfileWorkspace("Manage workspace member");
|
|
78553
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
78027
78554
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
78028
78555
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive member actions.");
|
|
78029
78556
|
let code;
|
|
@@ -78035,14 +78562,16 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78035
78562
|
}
|
|
78036
78563
|
if (code === null)
|
|
78037
78564
|
return;
|
|
78565
|
+
const target = await pending.resolve();
|
|
78566
|
+
target.unchanged();
|
|
78038
78567
|
if (captured.kind === "role") {
|
|
78039
|
-
const result2 = await client.setWorkspaceMemberRole(options.email, code, captured.membershipId, captured.body);
|
|
78568
|
+
const result2 = await client.setWorkspaceMemberRole(options.email, code, captured.membershipId, captured.body, target.context);
|
|
78040
78569
|
if (options.json)
|
|
78041
78570
|
console.log(JSON.stringify(result2));
|
|
78042
78571
|
else
|
|
78043
78572
|
console.log(result2.changed ? `Member role changed to ${result2.member.role}.` : `Member already has role ${result2.member.role}.`);
|
|
78044
78573
|
} else {
|
|
78045
|
-
const result2 = await client.removeWorkspaceMember(options.email, code, captured.membershipId, captured.body);
|
|
78574
|
+
const result2 = await client.removeWorkspaceMember(options.email, code, captured.membershipId, captured.body, target.context);
|
|
78046
78575
|
if (options.json)
|
|
78047
78576
|
console.log(JSON.stringify(result2));
|
|
78048
78577
|
else
|
|
@@ -78062,7 +78591,7 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78062
78591
|
}
|
|
78063
78592
|
}
|
|
78064
78593
|
var init_workspace_member_mutations = __esm(() => {
|
|
78065
|
-
|
|
78594
|
+
init_workspace_profile();
|
|
78066
78595
|
init_remote_auth();
|
|
78067
78596
|
init_remote_client();
|
|
78068
78597
|
init_remote_workspace();
|
|
@@ -78077,6 +78606,7 @@ __export(exports_customer_profile, {
|
|
|
78077
78606
|
function registerCustomerProfileCommands(program2) {
|
|
78078
78607
|
const account = program2.command("account").description("Manage your account on the selected Skills server");
|
|
78079
78608
|
const workspace = program2.command("workspace").description("Manage the current workspace on the selected Skills server");
|
|
78609
|
+
registerWorkspaceListCommand(workspace);
|
|
78080
78610
|
registerWorkspaceMembersCommand(workspace);
|
|
78081
78611
|
registerWorkspaceMemberMutationCommands(workspace);
|
|
78082
78612
|
const commands = [
|
|
@@ -78086,7 +78616,8 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78086
78616
|
for (const { kind, command } of commands) {
|
|
78087
78617
|
command.allowExcessArguments(false).description(kind === "account" ? "Update your display name with fresh email verification" : "Update the current workspace name as an owner or admin").requiredOption(kind === "account" ? "--display-name <name>" : "--name <name>", "New name (1\u2013100 characters)").requiredOption("--email <email>", "Account email for fresh verification").option("--code-stdin", "Read a previously requested six-digit verification code from stdin").option("--json", "Output JSON").action(async (options) => {
|
|
78088
78618
|
try {
|
|
78089
|
-
const
|
|
78619
|
+
const pending = prepareProfileWorkspace(`Update ${kind} name`);
|
|
78620
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
78090
78621
|
customerNamePatch(kind === "account" ? { displayName: options.displayName } : { name: options.name }, kind === "account" ? "displayName" : "name");
|
|
78091
78622
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY)) {
|
|
78092
78623
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive updates.");
|
|
@@ -78100,7 +78631,9 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78100
78631
|
}
|
|
78101
78632
|
if (code === null)
|
|
78102
78633
|
return;
|
|
78103
|
-
const
|
|
78634
|
+
const target = await pending.resolve();
|
|
78635
|
+
target.unchanged();
|
|
78636
|
+
const result2 = kind === "account" ? await client.updateProfile(options.email, code, { displayName: options.displayName }, target.context) : await client.updateCurrentWorkspace(options.email, code, { name: options.name }, target.context);
|
|
78104
78637
|
if (options.json)
|
|
78105
78638
|
console.log(JSON.stringify(result2));
|
|
78106
78639
|
else
|
|
@@ -78118,7 +78651,8 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78118
78651
|
}
|
|
78119
78652
|
}
|
|
78120
78653
|
var init_customer_profile = __esm(() => {
|
|
78121
|
-
|
|
78654
|
+
init_workspace_profile();
|
|
78655
|
+
init_workspace_selection();
|
|
78122
78656
|
init_remote_auth();
|
|
78123
78657
|
init_customer_verification();
|
|
78124
78658
|
init_workspace_members();
|
|
@@ -78265,8 +78799,8 @@ var init_storage = __esm(() => {
|
|
|
78265
78799
|
});
|
|
78266
78800
|
|
|
78267
78801
|
// src/lib/registry-reconcile.ts
|
|
78268
|
-
import { existsSync as existsSync33, readFileSync as
|
|
78269
|
-
import { join as
|
|
78802
|
+
import { existsSync as existsSync33, readFileSync as readFileSync31, statSync as statSync20, writeFileSync as writeFileSync20 } from "fs";
|
|
78803
|
+
import { join as join39 } from "path";
|
|
78270
78804
|
function isDirectory2(path) {
|
|
78271
78805
|
try {
|
|
78272
78806
|
return statSync20(path).isDirectory();
|
|
@@ -78277,15 +78811,15 @@ function isDirectory2(path) {
|
|
|
78277
78811
|
function migrationNeeded(options) {
|
|
78278
78812
|
if (options.rootDir)
|
|
78279
78813
|
return false;
|
|
78280
|
-
const appDir = options.homeDir ?
|
|
78281
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
78814
|
+
const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
78815
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join39(appDir, SKILLS_CACHE_DIRNAME)));
|
|
78282
78816
|
}
|
|
78283
78817
|
function readBaseline(skillDir) {
|
|
78284
|
-
const markerPath =
|
|
78818
|
+
const markerPath = join39(skillDir, PULL_MARKER_FILE);
|
|
78285
78819
|
if (!existsSync33(markerPath))
|
|
78286
78820
|
return;
|
|
78287
78821
|
try {
|
|
78288
|
-
const marker = JSON.parse(
|
|
78822
|
+
const marker = JSON.parse(readFileSync31(markerPath, "utf-8"));
|
|
78289
78823
|
if (!isSkillsOwnershipMarker(marker))
|
|
78290
78824
|
return;
|
|
78291
78825
|
return {
|
|
@@ -78297,11 +78831,11 @@ function readBaseline(skillDir) {
|
|
|
78297
78831
|
}
|
|
78298
78832
|
}
|
|
78299
78833
|
function readCursor(root) {
|
|
78300
|
-
const path =
|
|
78834
|
+
const path = join39(root, SYNC_CURSOR_FILE);
|
|
78301
78835
|
if (!existsSync33(path))
|
|
78302
78836
|
return { runCount: 0 };
|
|
78303
78837
|
try {
|
|
78304
|
-
const cursor2 = JSON.parse(
|
|
78838
|
+
const cursor2 = JSON.parse(readFileSync31(path, "utf-8"));
|
|
78305
78839
|
return { runCount: typeof cursor2.runCount === "number" ? cursor2.runCount : 0 };
|
|
78306
78840
|
} catch {
|
|
78307
78841
|
return { runCount: 0 };
|
|
@@ -78310,21 +78844,21 @@ function readCursor(root) {
|
|
|
78310
78844
|
function resolveCorpusRootReadOnly(options) {
|
|
78311
78845
|
if (options.rootDir)
|
|
78312
78846
|
return { root: options.rootDir, migrationPending: false };
|
|
78313
|
-
const appDir = options.homeDir ?
|
|
78314
|
-
const cache3 =
|
|
78847
|
+
const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
78848
|
+
const cache3 = join39(appDir, SKILLS_CACHE_DIRNAME);
|
|
78315
78849
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
78316
78850
|
return { root: cache3, migrationPending: false };
|
|
78317
78851
|
}
|
|
78318
|
-
return { root:
|
|
78852
|
+
return { root: join39(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
78319
78853
|
}
|
|
78320
|
-
function remoteRowToSkill(
|
|
78321
|
-
const slug = typeof
|
|
78854
|
+
function remoteRowToSkill(record5) {
|
|
78855
|
+
const slug = typeof record5.slug === "string" ? record5.slug : typeof record5.name === "string" ? record5.name : undefined;
|
|
78322
78856
|
if (!slug)
|
|
78323
78857
|
return;
|
|
78324
78858
|
return {
|
|
78325
78859
|
slug,
|
|
78326
|
-
version: typeof
|
|
78327
|
-
sha256: typeof
|
|
78860
|
+
version: typeof record5.version === "string" ? record5.version : undefined,
|
|
78861
|
+
sha256: typeof record5.bundleSha256 === "string" && record5.bundleSha256 ? record5.bundleSha256 : undefined
|
|
78328
78862
|
};
|
|
78329
78863
|
}
|
|
78330
78864
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
@@ -78449,7 +78983,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78449
78983
|
for (const slug of allSlugs) {
|
|
78450
78984
|
const local = locals.get(slug);
|
|
78451
78985
|
const remote = remotes.get(slug);
|
|
78452
|
-
const baseline = local ? readBaseline(
|
|
78986
|
+
const baseline = local ? readBaseline(join39(root, slug)) : undefined;
|
|
78453
78987
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
78454
78988
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
78455
78989
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -78508,7 +79042,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78508
79042
|
try {
|
|
78509
79043
|
await pushSkill(slug, { rootDir: root, client });
|
|
78510
79044
|
const pushed = locals.get(slug);
|
|
78511
|
-
writePullMarker(
|
|
79045
|
+
writePullMarker(join39(root, slug), {
|
|
78512
79046
|
skill: slug,
|
|
78513
79047
|
...pushed?.version ? { version: pushed.version } : {},
|
|
78514
79048
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -78580,7 +79114,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78580
79114
|
runCount: readCursor(root).runCount + 1,
|
|
78581
79115
|
summary
|
|
78582
79116
|
};
|
|
78583
|
-
|
|
79117
|
+
writeFileSync20(join39(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
78584
79118
|
`);
|
|
78585
79119
|
return {
|
|
78586
79120
|
corpusRoot: root,
|