@hasna/skills 0.5.0 → 0.5.2
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 +72 -1
- package/bin/index.js +1083 -388
- package/bin/mcp.js +521 -110
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/workspace-leave.d.ts +2 -0
- package/dist/cli/commands/workspace-selection.d.ts +11 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +427 -123
- package/dist/lib/remote-auth.d.ts +18 -9
- package/dist/lib/remote-client.d.ts +14 -0
- package/dist/lib/remote-workspace-leave.d.ts +52 -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 +5 -0
- package/dist/sdk/index.js +371 -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.2",
|
|
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() {
|
|
@@ -49145,6 +49235,75 @@ var init_remote_workspace = __esm(() => {
|
|
|
49145
49235
|
};
|
|
49146
49236
|
});
|
|
49147
49237
|
|
|
49238
|
+
// src/lib/remote-workspace-leave.ts
|
|
49239
|
+
function workspaceLeaveInput(context, input) {
|
|
49240
|
+
const target = workspaceContext(context);
|
|
49241
|
+
if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).sort().join(",") !== "confirm,expectedRole" || input.confirm !== true)
|
|
49242
|
+
throw new WorkspaceLeaveInputError;
|
|
49243
|
+
const captured = workspaceMemberRemovalInput(target.membershipId, { expectedRole: input.expectedRole });
|
|
49244
|
+
return {
|
|
49245
|
+
context: target,
|
|
49246
|
+
input: { expectedRole: captured.body.expectedRole, confirm: true },
|
|
49247
|
+
body: { membershipId: target.membershipId, expectedRole: captured.body.expectedRole }
|
|
49248
|
+
};
|
|
49249
|
+
}
|
|
49250
|
+
function workspaceLeaveFailure(value, status) {
|
|
49251
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
49252
|
+
return null;
|
|
49253
|
+
const code = value.code;
|
|
49254
|
+
return typeof code === "string" && Object.hasOwn(workspaceLeaveFailures, code) && workspaceLeaveFailures[code][0] === status ? code : null;
|
|
49255
|
+
}
|
|
49256
|
+
function parseWorkspaceLeaveResult(value, membershipId, organizationId) {
|
|
49257
|
+
const row = value;
|
|
49258
|
+
if (!row || typeof row !== "object" || Array.isArray(row) || row.membershipId !== membershipId || row.organizationId !== organizationId || row.removed !== true || row.signInRequired !== true)
|
|
49259
|
+
throw new RemoteWorkspaceLeaveUnconfirmedError;
|
|
49260
|
+
return { membershipId, organizationId, removed: true, signInRequired: true };
|
|
49261
|
+
}
|
|
49262
|
+
function workspaceLeaveProfileContext(membershipId, userId, profile) {
|
|
49263
|
+
const observed = profile === undefined ? undefined : workspaceContext(profile);
|
|
49264
|
+
const target = workspaceContext({ userId: userId ?? observed?.userId, membershipId });
|
|
49265
|
+
if (observed && (observed.userId !== target.userId || observed.membershipId !== target.membershipId))
|
|
49266
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49267
|
+
return target;
|
|
49268
|
+
}
|
|
49269
|
+
var WorkspaceLeaveInputError, workspaceLeaveFailures, RemoteWorkspaceLeaveError, RemoteWorkspaceLeaveUnconfirmedError;
|
|
49270
|
+
var init_remote_workspace_leave = __esm(() => {
|
|
49271
|
+
init_remote_workspace_selection();
|
|
49272
|
+
init_remote_workspace();
|
|
49273
|
+
WorkspaceLeaveInputError = class WorkspaceLeaveInputError extends Error {
|
|
49274
|
+
constructor() {
|
|
49275
|
+
super("Confirm leaving the exact observed user and membership with its expected role.");
|
|
49276
|
+
this.name = "WorkspaceLeaveInputError";
|
|
49277
|
+
}
|
|
49278
|
+
};
|
|
49279
|
+
workspaceLeaveFailures = {
|
|
49280
|
+
INVALID_REQUEST: [400, "Provide the exact current membership and expected role."],
|
|
49281
|
+
ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
|
|
49282
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "Fresh interactive sign-in is required to leave a workspace."],
|
|
49283
|
+
MEMBERSHIP_ROLE_CHANGED: [409, "Your role changed. Sign in and inspect the workspace before leaving."],
|
|
49284
|
+
LAST_OWNER_REQUIRED: [409, "The workspace must retain another active owner."],
|
|
49285
|
+
LAST_WORKSPACE_REQUIRED: [409, "Another available workspace is required before leaving."],
|
|
49286
|
+
MEMBERSHIP_BUSY: [503, "Membership is busy. Inspect the workspace before another leave action."]
|
|
49287
|
+
};
|
|
49288
|
+
RemoteWorkspaceLeaveError = class RemoteWorkspaceLeaveError extends Error {
|
|
49289
|
+
code;
|
|
49290
|
+
status;
|
|
49291
|
+
constructor(code) {
|
|
49292
|
+
super(workspaceLeaveFailures[code][1]);
|
|
49293
|
+
this.code = code;
|
|
49294
|
+
this.name = "RemoteWorkspaceLeaveError";
|
|
49295
|
+
this.status = workspaceLeaveFailures[code][0];
|
|
49296
|
+
}
|
|
49297
|
+
};
|
|
49298
|
+
RemoteWorkspaceLeaveUnconfirmedError = class RemoteWorkspaceLeaveUnconfirmedError extends Error {
|
|
49299
|
+
code = "WORKSPACE_LEAVE_UNCONFIRMED";
|
|
49300
|
+
constructor() {
|
|
49301
|
+
super("The leave outcome is unconfirmed. Sign in again and inspect available memberships before another action. Do not retry automatically; saved credentials are unchanged.");
|
|
49302
|
+
this.name = "RemoteWorkspaceLeaveUnconfirmedError";
|
|
49303
|
+
}
|
|
49304
|
+
};
|
|
49305
|
+
});
|
|
49306
|
+
|
|
49148
49307
|
// src/lib/auth-store.ts
|
|
49149
49308
|
import { chmodSync, existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync12, renameSync as renameSync4, statSync as statSync9, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
|
|
49150
49309
|
import { basename as basename4, dirname as dirname6, join as join18 } from "path";
|
|
@@ -49163,14 +49322,14 @@ function readIdentity(env3 = process.env) {
|
|
|
49163
49322
|
const parsed = JSON.parse(readFileSync12(getIdentityFilePath(env3), "utf-8"));
|
|
49164
49323
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
49165
49324
|
return {};
|
|
49166
|
-
const
|
|
49325
|
+
const record3 = parsed;
|
|
49167
49326
|
const selected = resolveSkillsApiOrigin(env3)?.origin;
|
|
49168
|
-
const bound = typeof
|
|
49327
|
+
const bound = typeof record3.apiUrl === "string" ? record3.apiUrl : readCredentialValue(SKILLS_BOUND_API_URL, env3) ?? readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills");
|
|
49169
49328
|
if (selected && normalizeSkillsApiOrigin(bound) !== selected)
|
|
49170
49329
|
return {};
|
|
49171
49330
|
const identity2 = {};
|
|
49172
49331
|
for (const field of ["email", "orgId", "orgSlug", "userId"]) {
|
|
49173
|
-
const value =
|
|
49332
|
+
const value = record3[field];
|
|
49174
49333
|
if (typeof value === "string" && value.length > 0)
|
|
49175
49334
|
identity2[field] = value;
|
|
49176
49335
|
}
|
|
@@ -49319,44 +49478,44 @@ var init_auth_store = __esm(() => {
|
|
|
49319
49478
|
|
|
49320
49479
|
// src/lib/remote-run-contract.ts
|
|
49321
49480
|
function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
|
|
49322
|
-
const
|
|
49481
|
+
const record3 = isRecord3(payload) ? payload : {};
|
|
49323
49482
|
return {
|
|
49324
49483
|
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(
|
|
49484
|
+
...pickString(record3, "id"),
|
|
49485
|
+
skill: pickStringValue(record3, "skill") ?? fallbackSkill,
|
|
49486
|
+
...pickString(record3, "requestedSlug"),
|
|
49487
|
+
...pickString(record3, "status"),
|
|
49488
|
+
...pickNumber(record3, "exitCode"),
|
|
49489
|
+
...pickString(record3, "correlationId"),
|
|
49490
|
+
...pickString(record3, "createdAt"),
|
|
49491
|
+
...pickString(record3, "startedAt"),
|
|
49492
|
+
...pickString(record3, "completedAt"),
|
|
49493
|
+
...pickNumber(record3, "durationMs"),
|
|
49494
|
+
...pickString(record3, "outputType"),
|
|
49495
|
+
...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
|
|
49496
|
+
...pickString(record3, "errorCode"),
|
|
49497
|
+
...pickString(record3, "errorMessage"),
|
|
49498
|
+
...pickString(record3, "error"),
|
|
49499
|
+
...pickString(record3, "code"),
|
|
49500
|
+
...hasOwn(record3, "details") ? { details: record3.details } : {}
|
|
49342
49501
|
};
|
|
49343
49502
|
}
|
|
49344
49503
|
function isRecord3(value) {
|
|
49345
49504
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
49346
49505
|
}
|
|
49347
|
-
function hasOwn(
|
|
49348
|
-
return Object.prototype.hasOwnProperty.call(
|
|
49506
|
+
function hasOwn(record3, key) {
|
|
49507
|
+
return Object.prototype.hasOwnProperty.call(record3, key);
|
|
49349
49508
|
}
|
|
49350
|
-
function pickString(
|
|
49351
|
-
const value = pickStringValue(
|
|
49509
|
+
function pickString(record3, key) {
|
|
49510
|
+
const value = pickStringValue(record3, key);
|
|
49352
49511
|
return value === undefined ? {} : { [key]: value };
|
|
49353
49512
|
}
|
|
49354
|
-
function pickStringValue(
|
|
49355
|
-
const value =
|
|
49513
|
+
function pickStringValue(record3, key) {
|
|
49514
|
+
const value = record3[key];
|
|
49356
49515
|
return typeof value === "string" ? value : undefined;
|
|
49357
49516
|
}
|
|
49358
|
-
function pickNumber(
|
|
49359
|
-
const value =
|
|
49517
|
+
function pickNumber(record3, key) {
|
|
49518
|
+
const value = record3[key];
|
|
49360
49519
|
return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
|
|
49361
49520
|
}
|
|
49362
49521
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
@@ -49548,11 +49707,11 @@ function parseUpdatedProfile(value) {
|
|
|
49548
49707
|
return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
|
|
49549
49708
|
}
|
|
49550
49709
|
function parseUpdatedWorkspace(value) {
|
|
49551
|
-
const
|
|
49552
|
-
if (!isRecord4(
|
|
49710
|
+
const organization2 = isRecord4(value) && value.organization;
|
|
49711
|
+
if (!isRecord4(organization2) || !string(organization2.id) || !string(organization2.slug) || !string(organization2.name)) {
|
|
49553
49712
|
throw new Error("The server returned an invalid workspace.");
|
|
49554
49713
|
}
|
|
49555
|
-
return { organization: { id:
|
|
49714
|
+
return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
|
|
49556
49715
|
}
|
|
49557
49716
|
|
|
49558
49717
|
// src/lib/remote-client.ts
|
|
@@ -49560,6 +49719,7 @@ var exports_remote_client = {};
|
|
|
49560
49719
|
__export(exports_remote_client, {
|
|
49561
49720
|
createRemoteSkillsClientReadOnly: () => createRemoteSkillsClientReadOnly,
|
|
49562
49721
|
createRemoteSkillsClient: () => createRemoteSkillsClient,
|
|
49722
|
+
RemoteWorkspaceSelectionError: () => RemoteWorkspaceSelectionError,
|
|
49563
49723
|
RemoteWorkspaceMemberError: () => RemoteWorkspaceMemberError,
|
|
49564
49724
|
RemoteSkillsClient: () => RemoteSkillsClient,
|
|
49565
49725
|
RemoteRouteUnsupportedError: () => RemoteRouteUnsupportedError,
|
|
@@ -49579,6 +49739,7 @@ class RemoteSkillsClient {
|
|
|
49579
49739
|
return fetch(`${this.apiUrl}${path}`, {
|
|
49580
49740
|
...options,
|
|
49581
49741
|
redirect: "error",
|
|
49742
|
+
credentials: "omit",
|
|
49582
49743
|
signal: options?.signal ?? AbortSignal.timeout(15000),
|
|
49583
49744
|
headers: {
|
|
49584
49745
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -49685,6 +49846,65 @@ class RemoteSkillsClient {
|
|
|
49685
49846
|
async getIdentity() {
|
|
49686
49847
|
return (await this.requestNewRoute("/api/auth/whoami")).json();
|
|
49687
49848
|
}
|
|
49849
|
+
async listAccountWorkspaces(expectedUserId) {
|
|
49850
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
49851
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
49852
|
+
let identity2;
|
|
49853
|
+
if (expected !== undefined) {
|
|
49854
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
49855
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
49856
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces", "INTERACTIVE_SESSION_REQUIRED");
|
|
49857
|
+
identity2 = parseWorkspaceIdentity(value, expected);
|
|
49858
|
+
}
|
|
49859
|
+
const result2 = parseAccountWorkspaces(await connection.requestWorkspaceSelection("/api/v1/account/workspaces"));
|
|
49860
|
+
const current = result2.workspaces.find((workspace) => workspace.current);
|
|
49861
|
+
if (identity2 && (current.membershipId !== identity2.user.membershipId || current.organization.id !== identity2.organization.id))
|
|
49862
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49863
|
+
return result2;
|
|
49864
|
+
}
|
|
49865
|
+
async switchWorkspace(context) {
|
|
49866
|
+
const target = workspaceContext(context);
|
|
49867
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
49868
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
49869
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
49870
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
49871
|
+
parseWorkspaceIdentity(value, target.userId);
|
|
49872
|
+
const selected = parseWorkspaceSession(await connection.requestWorkspaceSelection("/api/v1/account/workspaces/switch", {
|
|
49873
|
+
method: "POST",
|
|
49874
|
+
body: JSON.stringify({ membershipId: target.membershipId })
|
|
49875
|
+
}), target);
|
|
49876
|
+
const verified = await new RemoteSkillsClient(selected.token, connection.apiUrl).requestWorkspaceSelection("/api/auth/whoami");
|
|
49877
|
+
if (!verified || typeof verified !== "object" || verified.authMethod !== "jwt")
|
|
49878
|
+
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
49879
|
+
const identity2 = parseWorkspaceIdentity(verified, target.userId);
|
|
49880
|
+
if (identity2.user.membershipId !== target.membershipId || identity2.organization.id !== selected.organization.id)
|
|
49881
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49882
|
+
return { token: selected.token, ...identity2 };
|
|
49883
|
+
}
|
|
49884
|
+
async requestWorkspaceSelection(path, options) {
|
|
49885
|
+
let response;
|
|
49886
|
+
try {
|
|
49887
|
+
response = await this.request(path, { ...options, credentials: "omit" });
|
|
49888
|
+
} catch {
|
|
49889
|
+
throw new Error("Unable to reach the Skills workspace API.");
|
|
49890
|
+
}
|
|
49891
|
+
let value;
|
|
49892
|
+
try {
|
|
49893
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 1024 * 1024 : 4096)));
|
|
49894
|
+
} catch {
|
|
49895
|
+
if (response.ok)
|
|
49896
|
+
throw new Error(invalidWorkspaceResult);
|
|
49897
|
+
}
|
|
49898
|
+
if (!response.ok) {
|
|
49899
|
+
const code = workspaceSelectionFailure(value, response.status);
|
|
49900
|
+
if (code)
|
|
49901
|
+
throw new RemoteWorkspaceSelectionError(path, code);
|
|
49902
|
+
if (response.status === 404 || response.status === 405)
|
|
49903
|
+
throw new RemoteRouteUnsupportedError(path, response.status, this.apiUrl);
|
|
49904
|
+
throw new RemoteRequestError(path, response.status);
|
|
49905
|
+
}
|
|
49906
|
+
return value;
|
|
49907
|
+
}
|
|
49688
49908
|
async updateProfile(input) {
|
|
49689
49909
|
const body = customerNamePatch(input, "displayName");
|
|
49690
49910
|
return parseUpdatedProfile(await (await this.requestNewRoute("/api/v1/account/profile", { method: "PATCH", body: JSON.stringify(body) })).json());
|
|
@@ -49737,6 +49957,30 @@ class RemoteSkillsClient {
|
|
|
49737
49957
|
}
|
|
49738
49958
|
return value;
|
|
49739
49959
|
}
|
|
49960
|
+
async leaveWorkspace(context, input) {
|
|
49961
|
+
const captured = workspaceLeaveInput(context, input);
|
|
49962
|
+
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
49963
|
+
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
49964
|
+
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
49965
|
+
throw new RemoteWorkspaceLeaveError("INTERACTIVE_SESSION_REQUIRED");
|
|
49966
|
+
const identity2 = parseWorkspaceIdentity(value, captured.context.userId);
|
|
49967
|
+
if (identity2.user.membershipId !== captured.context.membershipId)
|
|
49968
|
+
throw new WorkspaceIdentityMismatchError;
|
|
49969
|
+
let response, body;
|
|
49970
|
+
try {
|
|
49971
|
+
response = await connection.request("/api/v1/account/workspaces/leave", { method: "POST", body: JSON.stringify(captured.body) });
|
|
49972
|
+
body = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, 4096)));
|
|
49973
|
+
} catch {
|
|
49974
|
+
throw new RemoteWorkspaceLeaveUnconfirmedError;
|
|
49975
|
+
}
|
|
49976
|
+
if (!response.ok) {
|
|
49977
|
+
const code = workspaceLeaveFailure(body, response.status);
|
|
49978
|
+
if (code)
|
|
49979
|
+
throw new RemoteWorkspaceLeaveError(code);
|
|
49980
|
+
throw new RemoteWorkspaceLeaveUnconfirmedError;
|
|
49981
|
+
}
|
|
49982
|
+
return parseWorkspaceLeaveResult(body, captured.context.membershipId, identity2.organization.id);
|
|
49983
|
+
}
|
|
49740
49984
|
async listApiKeys() {
|
|
49741
49985
|
return this.arrayResponse("/api/auth/keys");
|
|
49742
49986
|
}
|
|
@@ -49987,13 +50231,13 @@ class RemoteSkillsClient {
|
|
|
49987
50231
|
return normalizeUpdatedSincePage(await response.json());
|
|
49988
50232
|
}
|
|
49989
50233
|
}
|
|
49990
|
-
function requireOptionalString(
|
|
49991
|
-
if (
|
|
50234
|
+
function requireOptionalString(record3, field) {
|
|
50235
|
+
if (record3[field] === undefined)
|
|
49992
50236
|
return;
|
|
49993
|
-
if (typeof
|
|
50237
|
+
if (typeof record3[field] !== "string") {
|
|
49994
50238
|
throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
|
|
49995
50239
|
}
|
|
49996
|
-
return
|
|
50240
|
+
return record3[field];
|
|
49997
50241
|
}
|
|
49998
50242
|
function isVersionRecord(value) {
|
|
49999
50243
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -50015,19 +50259,19 @@ function normalizePin(entry) {
|
|
|
50015
50259
|
if (!entry || typeof entry !== "object") {
|
|
50016
50260
|
throw new Error("Remote pin payload did not match the expected contract (expected an object)");
|
|
50017
50261
|
}
|
|
50018
|
-
const
|
|
50019
|
-
const slug = typeof
|
|
50262
|
+
const record3 = entry;
|
|
50263
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
50020
50264
|
if (!slug) {
|
|
50021
50265
|
throw new Error("Remote pin payload did not match the expected contract (missing slug)");
|
|
50022
50266
|
}
|
|
50023
50267
|
let metadata;
|
|
50024
|
-
if (
|
|
50025
|
-
if (!
|
|
50268
|
+
if (record3.metadata !== undefined) {
|
|
50269
|
+
if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
|
|
50026
50270
|
throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
|
|
50027
50271
|
}
|
|
50028
|
-
metadata =
|
|
50272
|
+
metadata = record3.metadata;
|
|
50029
50273
|
}
|
|
50030
|
-
const pinnedAt = requireOptionalString(
|
|
50274
|
+
const pinnedAt = requireOptionalString(record3, "pinnedAt");
|
|
50031
50275
|
return {
|
|
50032
50276
|
slug,
|
|
50033
50277
|
...pinnedAt !== undefined ? { pinnedAt } : {},
|
|
@@ -50044,16 +50288,16 @@ function normalizeSkillSummary(entry) {
|
|
|
50044
50288
|
if (!entry || typeof entry !== "object") {
|
|
50045
50289
|
throw new Error("Remote skill payload did not match the expected contract (expected an object)");
|
|
50046
50290
|
}
|
|
50047
|
-
const
|
|
50048
|
-
const slug = typeof
|
|
50291
|
+
const record3 = entry;
|
|
50292
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
50049
50293
|
if (!slug) {
|
|
50050
50294
|
throw new Error("Remote skill payload did not match the expected contract (missing slug)");
|
|
50051
50295
|
}
|
|
50052
50296
|
return {
|
|
50053
50297
|
slug,
|
|
50054
|
-
...requireOptionalString(
|
|
50055
|
-
...requireOptionalString(
|
|
50056
|
-
...requireOptionalString(
|
|
50298
|
+
...requireOptionalString(record3, "name") !== undefined ? { name: requireOptionalString(record3, "name") } : {},
|
|
50299
|
+
...requireOptionalString(record3, "version") !== undefined ? { version: requireOptionalString(record3, "version") } : {},
|
|
50300
|
+
...requireOptionalString(record3, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record3, "updatedAt") } : {}
|
|
50057
50301
|
};
|
|
50058
50302
|
}
|
|
50059
50303
|
function normalizeSkillSummaryList(payload) {
|
|
@@ -50106,12 +50350,12 @@ function normalizeUpdatedSincePage(payload) {
|
|
|
50106
50350
|
if (!payload || typeof payload !== "object") {
|
|
50107
50351
|
throw new Error("Updated-since payload did not match the expected contract (expected an object)");
|
|
50108
50352
|
}
|
|
50109
|
-
const
|
|
50110
|
-
if (!Array.isArray(
|
|
50353
|
+
const record3 = payload;
|
|
50354
|
+
if (!Array.isArray(record3.skills)) {
|
|
50111
50355
|
throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
|
|
50112
50356
|
}
|
|
50113
|
-
const skills =
|
|
50114
|
-
const nextCursor =
|
|
50357
|
+
const skills = record3.skills.map(normalizeSkillSummary);
|
|
50358
|
+
const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
|
|
50115
50359
|
if (nextCursor !== null && typeof nextCursor !== "string") {
|
|
50116
50360
|
throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
|
|
50117
50361
|
}
|
|
@@ -50124,8 +50368,10 @@ async function createRemoteSkillsClient(env3 = process.env) {
|
|
|
50124
50368
|
function createRemoteSkillsClientReadOnly(env3 = process.env) {
|
|
50125
50369
|
return createRemoteSkillsClient(env3);
|
|
50126
50370
|
}
|
|
50127
|
-
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
50371
|
+
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
50128
50372
|
var init_remote_client = __esm(() => {
|
|
50373
|
+
init_remote_workspace_leave();
|
|
50374
|
+
init_remote_workspace_selection();
|
|
50129
50375
|
init_remote_workspace();
|
|
50130
50376
|
init_remote_workspace();
|
|
50131
50377
|
init_auth_store();
|
|
@@ -50163,6 +50409,15 @@ var init_remote_client = __esm(() => {
|
|
|
50163
50409
|
this.message = workspaceMemberFailures[code][1];
|
|
50164
50410
|
}
|
|
50165
50411
|
};
|
|
50412
|
+
RemoteWorkspaceSelectionError = class RemoteWorkspaceSelectionError extends RemoteRequestError {
|
|
50413
|
+
code;
|
|
50414
|
+
constructor(path, code) {
|
|
50415
|
+
super(path, workspaceSelectionFailures[code][0]);
|
|
50416
|
+
this.code = code;
|
|
50417
|
+
this.name = "RemoteWorkspaceSelectionError";
|
|
50418
|
+
this.message = workspaceSelectionFailures[code][1];
|
|
50419
|
+
}
|
|
50420
|
+
};
|
|
50166
50421
|
RemoteCapabilityUnavailableError = class RemoteCapabilityUnavailableError extends RemoteRequestError {
|
|
50167
50422
|
code = "SUBSCRIPTION_CHECKOUT_UNAVAILABLE";
|
|
50168
50423
|
constructor() {
|
|
@@ -50891,16 +51146,16 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
50891
51146
|
}
|
|
50892
51147
|
return { path: target, created };
|
|
50893
51148
|
}
|
|
50894
|
-
function writePullMarker(dir,
|
|
51149
|
+
function writePullMarker(dir, record3) {
|
|
50895
51150
|
const marker = {
|
|
50896
51151
|
managedBy: "@hasna/skills",
|
|
50897
|
-
skill:
|
|
50898
|
-
source:
|
|
50899
|
-
...
|
|
50900
|
-
...
|
|
50901
|
-
...
|
|
50902
|
-
...
|
|
50903
|
-
...
|
|
51152
|
+
skill: record3.skill,
|
|
51153
|
+
source: record3.source ?? "pull",
|
|
51154
|
+
...record3.version ? { version: record3.version } : {},
|
|
51155
|
+
...record3.contentHash ? { contentHash: record3.contentHash } : {},
|
|
51156
|
+
...record3.sourceCommit ? { sourceCommit: record3.sourceCommit } : {},
|
|
51157
|
+
...record3.signature ? { signature: record3.signature } : {},
|
|
51158
|
+
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
50904
51159
|
syncedAt: new Date().toISOString()
|
|
50905
51160
|
};
|
|
50906
51161
|
writeFileSync8(join20(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
@@ -50915,19 +51170,19 @@ async function safeMeta(client, slug) {
|
|
|
50915
51170
|
}
|
|
50916
51171
|
if (!raw || typeof raw !== "object")
|
|
50917
51172
|
return null;
|
|
50918
|
-
const
|
|
50919
|
-
const kind =
|
|
50920
|
-
const tags = Array.isArray(
|
|
51173
|
+
const record3 = raw;
|
|
51174
|
+
const kind = record3.kind === "instruction" || record3.kind === "executable" ? record3.kind : undefined;
|
|
51175
|
+
const tags = Array.isArray(record3.tags) ? record3.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
|
|
50921
51176
|
return {
|
|
50922
|
-
...str(
|
|
50923
|
-
...str(
|
|
50924
|
-
...str(
|
|
51177
|
+
...str(record3.displayName) ? { displayName: str(record3.displayName) } : {},
|
|
51178
|
+
...str(record3.description) ? { description: str(record3.description) } : {},
|
|
51179
|
+
...str(record3.category) ? { category: str(record3.category) } : {},
|
|
50925
51180
|
...tags && tags.length ? { tags } : {},
|
|
50926
|
-
...str(
|
|
51181
|
+
...str(record3.version) ? { version: str(record3.version) } : {},
|
|
50927
51182
|
...kind ? { kind } : {},
|
|
50928
|
-
...REVISION_ID_PATTERN.test(str(
|
|
50929
|
-
...typeof
|
|
50930
|
-
...str(
|
|
51183
|
+
...REVISION_ID_PATTERN.test(str(record3.revisionId) ?? "") ? { revisionId: str(record3.revisionId) } : {},
|
|
51184
|
+
...typeof record3.skillMd === "string" && record3.skillMd.length > 0 ? { skillMd: record3.skillMd } : {},
|
|
51185
|
+
...str(record3.publishedSource) ? { publishedSource: str(record3.publishedSource) } : {}
|
|
50931
51186
|
};
|
|
50932
51187
|
}
|
|
50933
51188
|
function pickCorpusOptions(options) {
|
|
@@ -50936,8 +51191,8 @@ function pickCorpusOptions(options) {
|
|
|
50936
51191
|
function extractSlug(entry) {
|
|
50937
51192
|
if (!entry || typeof entry !== "object")
|
|
50938
51193
|
return;
|
|
50939
|
-
const
|
|
50940
|
-
return str(
|
|
51194
|
+
const record3 = entry;
|
|
51195
|
+
return str(record3.slug) ?? str(record3.name);
|
|
50941
51196
|
}
|
|
50942
51197
|
function dedupe(values2) {
|
|
50943
51198
|
return [...new Set(values2)];
|
|
@@ -51210,17 +51465,17 @@ var init_install = __esm(() => {
|
|
|
51210
51465
|
|
|
51211
51466
|
// src/lib/compact-output.ts
|
|
51212
51467
|
function truncateText(value, maxChars = 96) {
|
|
51213
|
-
const
|
|
51214
|
-
if (
|
|
51215
|
-
return
|
|
51216
|
-
return `${
|
|
51468
|
+
const text2 = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
51469
|
+
if (text2.length <= maxChars)
|
|
51470
|
+
return text2;
|
|
51471
|
+
return `${text2.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
51217
51472
|
}
|
|
51218
51473
|
function previewText(value, maxChars = DEFAULT_PREVIEW_CHARS) {
|
|
51219
|
-
const
|
|
51474
|
+
const text2 = String(value ?? "");
|
|
51220
51475
|
return {
|
|
51221
|
-
text:
|
|
51222
|
-
length:
|
|
51223
|
-
truncated:
|
|
51476
|
+
text: text2.length > maxChars ? `${text2.slice(0, Math.max(0, maxChars - 3))}...` : text2,
|
|
51477
|
+
length: text2.length,
|
|
51478
|
+
truncated: text2.length > maxChars
|
|
51224
51479
|
};
|
|
51225
51480
|
}
|
|
51226
51481
|
function parsePageLimit(value, fallback, options = {}) {
|
|
@@ -51339,10 +51594,10 @@ function handleBrowseError(error) {
|
|
|
51339
51594
|
process.exitCode = 1;
|
|
51340
51595
|
}
|
|
51341
51596
|
async function writeJson(value, space) {
|
|
51342
|
-
const
|
|
51597
|
+
const text2 = `${JSON.stringify(value, null, space)}
|
|
51343
51598
|
`;
|
|
51344
51599
|
await new Promise((resolve3, reject2) => {
|
|
51345
|
-
process.stdout.write(
|
|
51600
|
+
process.stdout.write(text2, (error) => {
|
|
51346
51601
|
if (error)
|
|
51347
51602
|
reject2(error);
|
|
51348
51603
|
else
|
|
@@ -52049,12 +52304,12 @@ function generateSkillMd(name) {
|
|
|
52049
52304
|
`) + `
|
|
52050
52305
|
`;
|
|
52051
52306
|
}
|
|
52052
|
-
function extractEnvVars(
|
|
52307
|
+
function extractEnvVars(text2) {
|
|
52053
52308
|
const envVars = new Set;
|
|
52054
52309
|
for (const pattern of [ENV_VAR_PATTERN, GENERIC_ENV_PATTERN]) {
|
|
52055
52310
|
pattern.lastIndex = 0;
|
|
52056
52311
|
let match;
|
|
52057
|
-
while ((match = pattern.exec(
|
|
52312
|
+
while ((match = pattern.exec(text2)) !== null) {
|
|
52058
52313
|
envVars.add(match[1]);
|
|
52059
52314
|
}
|
|
52060
52315
|
}
|
|
@@ -53260,8 +53515,8 @@ function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
|
53260
53515
|
const dir = join24(appDir, ROLLBACK_DIRNAME);
|
|
53261
53516
|
mkdirSync9(dir, { recursive: true });
|
|
53262
53517
|
const file = join24(dir, `${mode}-${Date.now()}.json`);
|
|
53263
|
-
const
|
|
53264
|
-
writeFileSync10(file, `${JSON.stringify(
|
|
53518
|
+
const record3 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
53519
|
+
writeFileSync10(file, `${JSON.stringify(record3, null, 2)}
|
|
53265
53520
|
`);
|
|
53266
53521
|
return file;
|
|
53267
53522
|
}
|
|
@@ -53568,10 +53823,10 @@ function setEnvAssignment(path, assignment) {
|
|
|
53568
53823
|
}
|
|
53569
53824
|
let prepared = initial2;
|
|
53570
53825
|
if (previous) {
|
|
53571
|
-
const original = readFileSync20(descriptor),
|
|
53572
|
-
if (!Buffer.from(
|
|
53826
|
+
const original = readFileSync20(descriptor), text2 = original.toString("utf8");
|
|
53827
|
+
if (!Buffer.from(text2, "utf8").equals(original))
|
|
53573
53828
|
throw new EnvAssignmentError(INVALID_LAYOUT);
|
|
53574
|
-
prepared = prepareEnvAssignment(assignment,
|
|
53829
|
+
prepared = prepareEnvAssignment(assignment, text2);
|
|
53575
53830
|
}
|
|
53576
53831
|
const bytes = Buffer.from(prepared.content, "utf8");
|
|
53577
53832
|
let written = 0;
|
|
@@ -54139,7 +54394,7 @@ function createSkillRun(params, targetDir = process.cwd()) {
|
|
|
54139
54394
|
mkdirSync10(logsDir, { recursive: true });
|
|
54140
54395
|
mkdirSync10(exportDir, { recursive: true });
|
|
54141
54396
|
mkdirSync10(join27(root, "tmp"), { recursive: true });
|
|
54142
|
-
const
|
|
54397
|
+
const record3 = {
|
|
54143
54398
|
id,
|
|
54144
54399
|
skill: skillName,
|
|
54145
54400
|
status: params.status ?? "running",
|
|
@@ -54157,10 +54412,10 @@ function createSkillRun(params, targetDir = process.cwd()) {
|
|
|
54157
54412
|
logsDir: toProjectRelative(targetDir, logsDir)
|
|
54158
54413
|
}
|
|
54159
54414
|
};
|
|
54160
|
-
const context = { targetDir, runDir, exportDir, logsDir, record:
|
|
54415
|
+
const context = { targetDir, runDir, exportDir, logsDir, record: record3 };
|
|
54161
54416
|
writeRunRecord(context);
|
|
54162
54417
|
writeArtifactsManifest(context, []);
|
|
54163
|
-
appendRunEvent(context, "created", { status:
|
|
54418
|
+
appendRunEvent(context, "created", { status: record3.status });
|
|
54164
54419
|
return context;
|
|
54165
54420
|
}
|
|
54166
54421
|
function completeSkillRun(context, patch) {
|
|
@@ -54210,9 +54465,9 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
54210
54465
|
if (!statSync14(dayDir).isDirectory())
|
|
54211
54466
|
continue;
|
|
54212
54467
|
for (const runId of readdirSync13(dayDir).sort().reverse()) {
|
|
54213
|
-
const
|
|
54214
|
-
if (
|
|
54215
|
-
records.push(
|
|
54468
|
+
const record3 = readRunRecord(join27(dayDir, runId));
|
|
54469
|
+
if (record3)
|
|
54470
|
+
records.push(record3);
|
|
54216
54471
|
if (records.length >= limit)
|
|
54217
54472
|
return records;
|
|
54218
54473
|
}
|
|
@@ -54224,9 +54479,9 @@ function findSkillRun(runId, targetDir = process.cwd()) {
|
|
|
54224
54479
|
if (!existsSync25(runsRoot))
|
|
54225
54480
|
return null;
|
|
54226
54481
|
for (const day of readdirSync13(runsRoot)) {
|
|
54227
|
-
const
|
|
54228
|
-
if (
|
|
54229
|
-
return
|
|
54482
|
+
const record3 = readRunRecord(join27(runsRoot, day, runId));
|
|
54483
|
+
if (record3)
|
|
54484
|
+
return record3;
|
|
54230
54485
|
}
|
|
54231
54486
|
return null;
|
|
54232
54487
|
}
|
|
@@ -55062,7 +55317,7 @@ function datetime(args) {
|
|
|
55062
55317
|
const timeRegex2 = `${time2}(?:${opts.join("|")})`;
|
|
55063
55318
|
return new RegExp(`^${dateSource}T(?:${timeRegex2})$`);
|
|
55064
55319
|
}
|
|
55065
|
-
var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid,
|
|
55320
|
+
var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid, uuid3 = (version) => {
|
|
55066
55321
|
if (!version)
|
|
55067
55322
|
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
55323
|
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 +56111,9 @@ var init_schemas = __esm(() => {
|
|
|
55856
56111
|
const v = versionMap[def.version];
|
|
55857
56112
|
if (v === undefined)
|
|
55858
56113
|
throw new Error(`Invalid UUID version: "${def.version}"`);
|
|
55859
|
-
def.pattern ?? (def.pattern =
|
|
56114
|
+
def.pattern ?? (def.pattern = uuid3(v));
|
|
55860
56115
|
} else
|
|
55861
|
-
def.pattern ?? (def.pattern =
|
|
56116
|
+
def.pattern ?? (def.pattern = uuid3());
|
|
55862
56117
|
$ZodStringFormat.init(inst, def);
|
|
55863
56118
|
});
|
|
55864
56119
|
$ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => {
|
|
@@ -58338,7 +58593,7 @@ function intersection2(left, right) {
|
|
|
58338
58593
|
right
|
|
58339
58594
|
});
|
|
58340
58595
|
}
|
|
58341
|
-
function
|
|
58596
|
+
function record3(keyType, valueType, params) {
|
|
58342
58597
|
return new ZodRecord2({
|
|
58343
58598
|
type: "record",
|
|
58344
58599
|
keyType,
|
|
@@ -59039,7 +59294,7 @@ var init_types2 = __esm(() => {
|
|
|
59039
59294
|
});
|
|
59040
59295
|
FormElicitationCapabilitySchema = intersection2(object2({
|
|
59041
59296
|
applyDefaults: boolean2().optional()
|
|
59042
|
-
}),
|
|
59297
|
+
}), record3(string3(), unknown()));
|
|
59043
59298
|
ElicitationCapabilitySchema = preprocess((value) => {
|
|
59044
59299
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
59045
59300
|
if (Object.keys(value).length === 0) {
|
|
@@ -59050,7 +59305,7 @@ var init_types2 = __esm(() => {
|
|
|
59050
59305
|
}, intersection2(object2({
|
|
59051
59306
|
form: FormElicitationCapabilitySchema.optional(),
|
|
59052
59307
|
url: AssertObjectSchema.optional()
|
|
59053
|
-
}),
|
|
59308
|
+
}), record3(string3(), unknown()).optional()));
|
|
59054
59309
|
ClientTasksCapabilitySchema = looseObject({
|
|
59055
59310
|
list: AssertObjectSchema.optional(),
|
|
59056
59311
|
cancel: AssertObjectSchema.optional(),
|
|
@@ -59073,7 +59328,7 @@ var init_types2 = __esm(() => {
|
|
|
59073
59328
|
}).optional()
|
|
59074
59329
|
});
|
|
59075
59330
|
ClientCapabilitiesSchema = object2({
|
|
59076
|
-
experimental:
|
|
59331
|
+
experimental: record3(string3(), AssertObjectSchema).optional(),
|
|
59077
59332
|
sampling: object2({
|
|
59078
59333
|
context: AssertObjectSchema.optional(),
|
|
59079
59334
|
tools: AssertObjectSchema.optional()
|
|
@@ -59083,7 +59338,7 @@ var init_types2 = __esm(() => {
|
|
|
59083
59338
|
listChanged: boolean2().optional()
|
|
59084
59339
|
}).optional(),
|
|
59085
59340
|
tasks: ClientTasksCapabilitySchema.optional(),
|
|
59086
|
-
extensions:
|
|
59341
|
+
extensions: record3(string3(), AssertObjectSchema).optional()
|
|
59087
59342
|
});
|
|
59088
59343
|
InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
59089
59344
|
protocolVersion: string3(),
|
|
@@ -59095,7 +59350,7 @@ var init_types2 = __esm(() => {
|
|
|
59095
59350
|
params: InitializeRequestParamsSchema
|
|
59096
59351
|
});
|
|
59097
59352
|
ServerCapabilitiesSchema = object2({
|
|
59098
|
-
experimental:
|
|
59353
|
+
experimental: record3(string3(), AssertObjectSchema).optional(),
|
|
59099
59354
|
logging: AssertObjectSchema.optional(),
|
|
59100
59355
|
completions: AssertObjectSchema.optional(),
|
|
59101
59356
|
prompts: object2({
|
|
@@ -59109,7 +59364,7 @@ var init_types2 = __esm(() => {
|
|
|
59109
59364
|
listChanged: boolean2().optional()
|
|
59110
59365
|
}).optional(),
|
|
59111
59366
|
tasks: ServerTasksCapabilitySchema.optional(),
|
|
59112
|
-
extensions:
|
|
59367
|
+
extensions: record3(string3(), AssertObjectSchema).optional()
|
|
59113
59368
|
});
|
|
59114
59369
|
InitializeResultSchema = ResultSchema.extend({
|
|
59115
59370
|
protocolVersion: string3(),
|
|
@@ -59196,7 +59451,7 @@ var init_types2 = __esm(() => {
|
|
|
59196
59451
|
ResourceContentsSchema = object2({
|
|
59197
59452
|
uri: string3(),
|
|
59198
59453
|
mimeType: optional(string3()),
|
|
59199
|
-
_meta:
|
|
59454
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59200
59455
|
});
|
|
59201
59456
|
TextResourceContentsSchema = ResourceContentsSchema.extend({
|
|
59202
59457
|
text: string3()
|
|
@@ -59301,7 +59556,7 @@ var init_types2 = __esm(() => {
|
|
|
59301
59556
|
});
|
|
59302
59557
|
GetPromptRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
59303
59558
|
name: string3(),
|
|
59304
|
-
arguments:
|
|
59559
|
+
arguments: record3(string3(), string3()).optional()
|
|
59305
59560
|
});
|
|
59306
59561
|
GetPromptRequestSchema = RequestSchema.extend({
|
|
59307
59562
|
method: literal("prompts/get"),
|
|
@@ -59311,34 +59566,34 @@ var init_types2 = __esm(() => {
|
|
|
59311
59566
|
type: literal("text"),
|
|
59312
59567
|
text: string3(),
|
|
59313
59568
|
annotations: AnnotationsSchema.optional(),
|
|
59314
|
-
_meta:
|
|
59569
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59315
59570
|
});
|
|
59316
59571
|
ImageContentSchema = object2({
|
|
59317
59572
|
type: literal("image"),
|
|
59318
59573
|
data: Base64Schema,
|
|
59319
59574
|
mimeType: string3(),
|
|
59320
59575
|
annotations: AnnotationsSchema.optional(),
|
|
59321
|
-
_meta:
|
|
59576
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59322
59577
|
});
|
|
59323
59578
|
AudioContentSchema = object2({
|
|
59324
59579
|
type: literal("audio"),
|
|
59325
59580
|
data: Base64Schema,
|
|
59326
59581
|
mimeType: string3(),
|
|
59327
59582
|
annotations: AnnotationsSchema.optional(),
|
|
59328
|
-
_meta:
|
|
59583
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59329
59584
|
});
|
|
59330
59585
|
ToolUseContentSchema = object2({
|
|
59331
59586
|
type: literal("tool_use"),
|
|
59332
59587
|
name: string3(),
|
|
59333
59588
|
id: string3(),
|
|
59334
|
-
input:
|
|
59335
|
-
_meta:
|
|
59589
|
+
input: record3(string3(), unknown()),
|
|
59590
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59336
59591
|
});
|
|
59337
59592
|
EmbeddedResourceSchema = object2({
|
|
59338
59593
|
type: literal("resource"),
|
|
59339
59594
|
resource: union2([TextResourceContentsSchema, BlobResourceContentsSchema]),
|
|
59340
59595
|
annotations: AnnotationsSchema.optional(),
|
|
59341
|
-
_meta:
|
|
59596
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59342
59597
|
});
|
|
59343
59598
|
ResourceLinkSchema = ResourceSchema.extend({
|
|
59344
59599
|
type: literal("resource_link")
|
|
@@ -59378,17 +59633,17 @@ var init_types2 = __esm(() => {
|
|
|
59378
59633
|
description: string3().optional(),
|
|
59379
59634
|
inputSchema: object2({
|
|
59380
59635
|
type: literal("object"),
|
|
59381
|
-
properties:
|
|
59636
|
+
properties: record3(string3(), AssertObjectSchema).optional(),
|
|
59382
59637
|
required: array(string3()).optional()
|
|
59383
59638
|
}).catchall(unknown()),
|
|
59384
59639
|
outputSchema: object2({
|
|
59385
59640
|
type: literal("object"),
|
|
59386
|
-
properties:
|
|
59641
|
+
properties: record3(string3(), AssertObjectSchema).optional(),
|
|
59387
59642
|
required: array(string3()).optional()
|
|
59388
59643
|
}).catchall(unknown()).optional(),
|
|
59389
59644
|
annotations: ToolAnnotationsSchema.optional(),
|
|
59390
59645
|
execution: ToolExecutionSchema.optional(),
|
|
59391
|
-
_meta:
|
|
59646
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59392
59647
|
});
|
|
59393
59648
|
ListToolsRequestSchema = PaginatedRequestSchema.extend({
|
|
59394
59649
|
method: literal("tools/list")
|
|
@@ -59398,7 +59653,7 @@ var init_types2 = __esm(() => {
|
|
|
59398
59653
|
});
|
|
59399
59654
|
CallToolResultSchema = ResultSchema.extend({
|
|
59400
59655
|
content: array(ContentBlockSchema).default([]),
|
|
59401
|
-
structuredContent:
|
|
59656
|
+
structuredContent: record3(string3(), unknown()).optional(),
|
|
59402
59657
|
isError: boolean2().optional()
|
|
59403
59658
|
});
|
|
59404
59659
|
CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({
|
|
@@ -59406,7 +59661,7 @@ var init_types2 = __esm(() => {
|
|
|
59406
59661
|
}));
|
|
59407
59662
|
CallToolRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
59408
59663
|
name: string3(),
|
|
59409
|
-
arguments:
|
|
59664
|
+
arguments: record3(string3(), unknown()).optional()
|
|
59410
59665
|
});
|
|
59411
59666
|
CallToolRequestSchema = RequestSchema.extend({
|
|
59412
59667
|
method: literal("tools/call"),
|
|
@@ -59455,7 +59710,7 @@ var init_types2 = __esm(() => {
|
|
|
59455
59710
|
content: array(ContentBlockSchema).default([]),
|
|
59456
59711
|
structuredContent: object2({}).loose().optional(),
|
|
59457
59712
|
isError: boolean2().optional(),
|
|
59458
|
-
_meta:
|
|
59713
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59459
59714
|
});
|
|
59460
59715
|
SamplingContentSchema = discriminatedUnion("type", [TextContentSchema, ImageContentSchema, AudioContentSchema]);
|
|
59461
59716
|
SamplingMessageContentBlockSchema = discriminatedUnion("type", [
|
|
@@ -59468,7 +59723,7 @@ var init_types2 = __esm(() => {
|
|
|
59468
59723
|
SamplingMessageSchema = object2({
|
|
59469
59724
|
role: RoleSchema,
|
|
59470
59725
|
content: union2([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)]),
|
|
59471
|
-
_meta:
|
|
59726
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59472
59727
|
});
|
|
59473
59728
|
CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
59474
59729
|
messages: array(SamplingMessageSchema),
|
|
@@ -59581,7 +59836,7 @@ var init_types2 = __esm(() => {
|
|
|
59581
59836
|
message: string3(),
|
|
59582
59837
|
requestedSchema: object2({
|
|
59583
59838
|
type: literal("object"),
|
|
59584
|
-
properties:
|
|
59839
|
+
properties: record3(string3(), PrimitiveSchemaDefinitionSchema),
|
|
59585
59840
|
required: array(string3()).optional()
|
|
59586
59841
|
})
|
|
59587
59842
|
});
|
|
@@ -59605,7 +59860,7 @@ var init_types2 = __esm(() => {
|
|
|
59605
59860
|
});
|
|
59606
59861
|
ElicitResultSchema = ResultSchema.extend({
|
|
59607
59862
|
action: _enum(["accept", "decline", "cancel"]),
|
|
59608
|
-
content: preprocess((val) => val === null ? undefined : val,
|
|
59863
|
+
content: preprocess((val) => val === null ? undefined : val, record3(string3(), union2([string3(), number2(), boolean2(), array(string3())])).optional())
|
|
59609
59864
|
});
|
|
59610
59865
|
ResourceTemplateReferenceSchema = object2({
|
|
59611
59866
|
type: literal("ref/resource"),
|
|
@@ -59622,7 +59877,7 @@ var init_types2 = __esm(() => {
|
|
|
59622
59877
|
value: string3()
|
|
59623
59878
|
}),
|
|
59624
59879
|
context: object2({
|
|
59625
|
-
arguments:
|
|
59880
|
+
arguments: record3(string3(), string3()).optional()
|
|
59626
59881
|
}).optional()
|
|
59627
59882
|
});
|
|
59628
59883
|
CompleteRequestSchema = RequestSchema.extend({
|
|
@@ -59639,7 +59894,7 @@ var init_types2 = __esm(() => {
|
|
|
59639
59894
|
RootSchema = object2({
|
|
59640
59895
|
uri: string3().startsWith("file://"),
|
|
59641
59896
|
name: string3().optional(),
|
|
59642
|
-
_meta:
|
|
59897
|
+
_meta: record3(string3(), unknown()).optional()
|
|
59643
59898
|
});
|
|
59644
59899
|
ListRootsRequestSchema = RequestSchema.extend({
|
|
59645
59900
|
method: literal("roots/list"),
|
|
@@ -66892,7 +67147,7 @@ var require_core = __commonJS((exports) => {
|
|
|
66892
67147
|
errorsText(errors4 = this.errors, { separator = ", ", dataVar = "data" } = {}) {
|
|
66893
67148
|
if (!errors4 || errors4.length === 0)
|
|
66894
67149
|
return "No errors";
|
|
66895
|
-
return errors4.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((
|
|
67150
|
+
return errors4.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text2, msg) => text2 + separator + msg);
|
|
66896
67151
|
}
|
|
66897
67152
|
$dataMetaSchema(metaSchema, keywordsJsonPointers) {
|
|
66898
67153
|
const rules = this.RULES.all;
|
|
@@ -67303,8 +67558,8 @@ var require_multipleOf = __commonJS((exports) => {
|
|
|
67303
67558
|
const { gen, data, schemaCode, it } = cxt;
|
|
67304
67559
|
const prec = it.opts.multipleOfPrecision;
|
|
67305
67560
|
const res = gen.let("res");
|
|
67306
|
-
const
|
|
67307
|
-
cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${
|
|
67561
|
+
const invalid2 = prec ? (0, codegen_1._)`Math.abs(Math.round(${res}) - ${res}) > 1e-${prec}` : (0, codegen_1._)`${res} !== parseInt(${res})`;
|
|
67562
|
+
cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${invalid2}))`);
|
|
67308
67563
|
}
|
|
67309
67564
|
};
|
|
67310
67565
|
exports.default = def;
|
|
@@ -73400,13 +73655,13 @@ async function requestAuthApi(instance, path, options) {
|
|
|
73400
73655
|
apiUrl: safeUrl
|
|
73401
73656
|
});
|
|
73402
73657
|
}
|
|
73403
|
-
const
|
|
73404
|
-
const body =
|
|
73658
|
+
const text2 = await res.text();
|
|
73659
|
+
const body = text2 ? parseJsonBody(text2) : {};
|
|
73405
73660
|
if (!res.ok) {
|
|
73406
|
-
const
|
|
73407
|
-
const detail = typeof
|
|
73408
|
-
const error2 = typeof
|
|
73409
|
-
const code = typeof
|
|
73661
|
+
const record5 = isRecord5(body) ? body : {};
|
|
73662
|
+
const detail = typeof record5.detail === "string" ? record5.detail : undefined;
|
|
73663
|
+
const error2 = typeof record5.error === "string" ? record5.error : undefined;
|
|
73664
|
+
const code = typeof record5.code === "string" ? record5.code : undefined;
|
|
73410
73665
|
throw new HostedApiError(detail || error2 || `${res.status} ${res.statusText}`, {
|
|
73411
73666
|
status: res.status,
|
|
73412
73667
|
code,
|
|
@@ -73417,15 +73672,15 @@ async function requestAuthApi(instance, path, options) {
|
|
|
73417
73672
|
}
|
|
73418
73673
|
return body;
|
|
73419
73674
|
}
|
|
73420
|
-
function parseJsonBody(
|
|
73675
|
+
function parseJsonBody(text2) {
|
|
73421
73676
|
try {
|
|
73422
|
-
return JSON.parse(
|
|
73677
|
+
return JSON.parse(text2);
|
|
73423
73678
|
} catch {
|
|
73424
|
-
return { detail: condenseErrorBody(
|
|
73679
|
+
return { detail: condenseErrorBody(text2) };
|
|
73425
73680
|
}
|
|
73426
73681
|
}
|
|
73427
|
-
function condenseErrorBody(
|
|
73428
|
-
const stripped = /<[a-z!/]/i.test(
|
|
73682
|
+
function condenseErrorBody(text2) {
|
|
73683
|
+
const stripped = /<[a-z!/]/i.test(text2) ? text2.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text2;
|
|
73429
73684
|
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
73430
73685
|
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
73431
73686
|
return collapsed;
|
|
@@ -73452,7 +73707,12 @@ class RemoteSkillsAuthClient {
|
|
|
73452
73707
|
pollDevice(deviceCode) {
|
|
73453
73708
|
return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
|
|
73454
73709
|
}
|
|
73455
|
-
async sessionClient(email2, code) {
|
|
73710
|
+
async sessionClient(email2, code, context) {
|
|
73711
|
+
if (context !== undefined) {
|
|
73712
|
+
const target = workspaceContext(context), apiOrigin2 = this.apiOrigin;
|
|
73713
|
+
const session = await this.switchWorkspace(email2, code, target);
|
|
73714
|
+
return new RemoteSkillsClient(session.token, apiOrigin2);
|
|
73715
|
+
}
|
|
73456
73716
|
const apiOrigin = this.apiOrigin;
|
|
73457
73717
|
if (!email2.includes("@") || !/^\d{6}$/.test(code))
|
|
73458
73718
|
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
@@ -73461,34 +73721,80 @@ class RemoteSkillsAuthClient {
|
|
|
73461
73721
|
throw new Error("The server did not return an authorized account session");
|
|
73462
73722
|
return new RemoteSkillsClient(login.token, apiOrigin);
|
|
73463
73723
|
}
|
|
73464
|
-
async
|
|
73465
|
-
|
|
73724
|
+
async listAccountWorkspaces(email2, code, expectedUserId) {
|
|
73725
|
+
const login = await this.workspaceLogin(email2, code, expectedUserId);
|
|
73726
|
+
const result2 = await new RemoteSkillsClient(login.token, login.apiOrigin).listAccountWorkspaces(login.userId);
|
|
73727
|
+
return { userId: login.userId, ...result2 };
|
|
73728
|
+
}
|
|
73729
|
+
async switchWorkspace(email2, code, context) {
|
|
73730
|
+
const target = workspaceContext(context);
|
|
73731
|
+
const login = await this.workspaceLogin(email2, code, target.userId);
|
|
73732
|
+
return new RemoteSkillsClient(login.token, login.apiOrigin).switchWorkspace(target);
|
|
73733
|
+
}
|
|
73734
|
+
async workspaceLogin(email2, code, expectedUserId) {
|
|
73735
|
+
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
73736
|
+
const apiOrigin = this.apiOrigin;
|
|
73737
|
+
if (typeof email2 !== "string" || !email2.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
|
|
73738
|
+
throw new Error("Fresh email and six-digit verification code are required to manage this account");
|
|
73739
|
+
let response;
|
|
73740
|
+
try {
|
|
73741
|
+
response = await fetch(`${apiOrigin}/api/auth/verify`, {
|
|
73742
|
+
method: "POST",
|
|
73743
|
+
redirect: "error",
|
|
73744
|
+
credentials: "omit",
|
|
73745
|
+
signal: AbortSignal.timeout(15000),
|
|
73746
|
+
headers: { "Content-Type": "application/json" },
|
|
73747
|
+
body: JSON.stringify({ email: email2, code })
|
|
73748
|
+
});
|
|
73749
|
+
} catch {
|
|
73750
|
+
throw new HostedApiError("Unable to verify the Skills account.");
|
|
73751
|
+
}
|
|
73752
|
+
if (!response.ok) {
|
|
73753
|
+
response.body?.cancel().catch(() => {});
|
|
73754
|
+
throw new HostedApiError("Unable to verify the Skills account.", { status: response.status });
|
|
73755
|
+
}
|
|
73756
|
+
let value;
|
|
73757
|
+
try {
|
|
73758
|
+
value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, 64 * 1024)));
|
|
73759
|
+
} catch {
|
|
73760
|
+
throw new HostedApiError("The server returned an invalid account verification result.");
|
|
73761
|
+
}
|
|
73762
|
+
return { ...parseWorkspaceLogin(value, expected), apiOrigin };
|
|
73466
73763
|
}
|
|
73467
|
-
async
|
|
73468
|
-
|
|
73764
|
+
async createApiKey(email2, code, name, scopes, context) {
|
|
73765
|
+
const capturedScopes = scopes === undefined ? undefined : [...scopes];
|
|
73766
|
+
return (await this.sessionClient(email2, code, context)).createApiKey(name, capturedScopes);
|
|
73469
73767
|
}
|
|
73470
|
-
async
|
|
73471
|
-
return (await this.sessionClient(email2, code)).
|
|
73768
|
+
async listApiKeys(email2, code, context) {
|
|
73769
|
+
return (await this.sessionClient(email2, code, context)).listApiKeys();
|
|
73472
73770
|
}
|
|
73473
|
-
async
|
|
73474
|
-
|
|
73475
|
-
return (await this.sessionClient(email2, code)).updateProfile(input);
|
|
73771
|
+
async revokeApiKey(email2, code, keyId, context) {
|
|
73772
|
+
return (await this.sessionClient(email2, code, context)).revokeApiKey(keyId);
|
|
73476
73773
|
}
|
|
73477
|
-
async
|
|
73478
|
-
customerNamePatch(input, "
|
|
73479
|
-
return (await this.sessionClient(email2, code)).
|
|
73774
|
+
async updateProfile(email2, code, input, context) {
|
|
73775
|
+
const body = customerNamePatch(input, "displayName");
|
|
73776
|
+
return (await this.sessionClient(email2, code, context)).updateProfile({ displayName: body.displayName });
|
|
73480
73777
|
}
|
|
73481
|
-
async
|
|
73778
|
+
async updateCurrentWorkspace(email2, code, input, context) {
|
|
73779
|
+
const body = customerNamePatch(input, "name");
|
|
73780
|
+
return (await this.sessionClient(email2, code, context)).updateCurrentWorkspace({ name: body.name });
|
|
73781
|
+
}
|
|
73782
|
+
async listWorkspaceMembers(email2, code, options = {}, context) {
|
|
73482
73783
|
workspaceMembersQuery(options);
|
|
73483
|
-
|
|
73784
|
+
const captured = { ...options };
|
|
73785
|
+
return (await this.sessionClient(email2, code, context)).listWorkspaceMembers(captured);
|
|
73484
73786
|
}
|
|
73485
|
-
async setWorkspaceMemberRole(email2, code, membershipId, input) {
|
|
73787
|
+
async setWorkspaceMemberRole(email2, code, membershipId, input, context) {
|
|
73486
73788
|
const captured = workspaceMemberRoleInput(membershipId, input);
|
|
73487
|
-
return (await this.sessionClient(email2, code)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
73789
|
+
return (await this.sessionClient(email2, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
|
|
73790
|
+
}
|
|
73791
|
+
async leaveWorkspace(email2, code, context, input) {
|
|
73792
|
+
const captured = workspaceLeaveInput(context, input);
|
|
73793
|
+
return (await this.sessionClient(email2, code, captured.context)).leaveWorkspace(captured.context, captured.input);
|
|
73488
73794
|
}
|
|
73489
|
-
async removeWorkspaceMember(email2, code, membershipId, input) {
|
|
73795
|
+
async removeWorkspaceMember(email2, code, membershipId, input, context) {
|
|
73490
73796
|
const captured = workspaceMemberRemovalInput(membershipId, input);
|
|
73491
|
-
return (await this.sessionClient(email2, code)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
73797
|
+
return (await this.sessionClient(email2, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
|
|
73492
73798
|
}
|
|
73493
73799
|
request(path, options) {
|
|
73494
73800
|
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 +73804,9 @@ class RemoteSkillsAuthClient {
|
|
|
73498
73804
|
}
|
|
73499
73805
|
var MAX_ERROR_DETAIL_LENGTH = 200, HostedApiError;
|
|
73500
73806
|
var init_remote_auth = __esm(() => {
|
|
73807
|
+
init_remote_workspace_leave();
|
|
73808
|
+
init_remote_workspace_selection();
|
|
73809
|
+
init_remote_files();
|
|
73501
73810
|
init_remote_workspace();
|
|
73502
73811
|
init_remote_workspace();
|
|
73503
73812
|
init_remote_client();
|
|
@@ -73520,6 +73829,224 @@ var init_remote_auth = __esm(() => {
|
|
|
73520
73829
|
};
|
|
73521
73830
|
});
|
|
73522
73831
|
|
|
73832
|
+
// src/lib/workspace-profile.ts
|
|
73833
|
+
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";
|
|
73834
|
+
import { dirname as dirname10, join as join32 } from "path";
|
|
73835
|
+
function stat(path) {
|
|
73836
|
+
try {
|
|
73837
|
+
return lstatSync6(path);
|
|
73838
|
+
} catch (error2) {
|
|
73839
|
+
if (error2.code === "ENOENT")
|
|
73840
|
+
return null;
|
|
73841
|
+
throw error2;
|
|
73842
|
+
}
|
|
73843
|
+
}
|
|
73844
|
+
function safeText(file) {
|
|
73845
|
+
if (stat(file) === null)
|
|
73846
|
+
return null;
|
|
73847
|
+
const fd = openSync4(file, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
73848
|
+
try {
|
|
73849
|
+
const s = fstatSync4(fd);
|
|
73850
|
+
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
73851
|
+
return fail2("The selected profile must use bounded owner-only regular files.");
|
|
73852
|
+
return readFileSync25(fd, "utf8");
|
|
73853
|
+
} finally {
|
|
73854
|
+
closeSync4(fd);
|
|
73855
|
+
}
|
|
73856
|
+
}
|
|
73857
|
+
function checkIdentityMetadata(file, identity2) {
|
|
73858
|
+
const text2 = safeText(file);
|
|
73859
|
+
if (text2 === null)
|
|
73860
|
+
return;
|
|
73861
|
+
let value;
|
|
73862
|
+
try {
|
|
73863
|
+
value = JSON.parse(text2);
|
|
73864
|
+
} catch {
|
|
73865
|
+
return fail2("The profile identity metadata is invalid. Sign in again before managing this workspace.");
|
|
73866
|
+
}
|
|
73867
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
73868
|
+
return fail2("The profile identity metadata is invalid.");
|
|
73869
|
+
for (const [key, expected] of Object.entries({ userId: identity2.user.id, orgId: identity2.organization.id })) {
|
|
73870
|
+
if (value[key] !== undefined && value[key] !== expected)
|
|
73871
|
+
return fail2("The profile identity metadata does not match its authenticated key. Sign in again before managing this workspace.");
|
|
73872
|
+
}
|
|
73873
|
+
}
|
|
73874
|
+
async function keyIdentity(key, origin) {
|
|
73875
|
+
const value = await new RemoteSkillsClient(key, origin).getIdentity();
|
|
73876
|
+
if (value.authMethod !== "api_key")
|
|
73877
|
+
return fail2("The selected credential is not a workspace API key.");
|
|
73878
|
+
const user = value.user;
|
|
73879
|
+
return parseWorkspaceIdentity(value, workspaceExpectedUserId(user?.id));
|
|
73880
|
+
}
|
|
73881
|
+
function prepareProfileWorkspace(action, source = process.env) {
|
|
73882
|
+
const env3 = { ...source }, origin = getApiUrl(action, env3), profile = selectedSkillsProfile(env3);
|
|
73883
|
+
const unchanged2 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
|
|
73884
|
+
return { origin, async resolve() {
|
|
73885
|
+
unchanged2();
|
|
73886
|
+
if (!profile)
|
|
73887
|
+
return { origin, context: undefined, unchanged: unchanged2 };
|
|
73888
|
+
const connection = await resolveSkillsConnection(env3);
|
|
73889
|
+
if (!connection || connection.apiOrigin !== origin)
|
|
73890
|
+
return fail2("The selected profile has no usable credential for this server.");
|
|
73891
|
+
const identity2 = await keyIdentity(connection.apiKey, origin);
|
|
73892
|
+
checkIdentityMetadata(getIdentityFilePath(env3), identity2);
|
|
73893
|
+
unchanged2();
|
|
73894
|
+
const context = { userId: identity2.user.id, membershipId: identity2.user.membershipId };
|
|
73895
|
+
return { origin, context, unchanged: unchanged2 };
|
|
73896
|
+
} };
|
|
73897
|
+
}
|
|
73898
|
+
async function captureProfileWorkspace(action, source = process.env) {
|
|
73899
|
+
return prepareProfileWorkspace(action, source).resolve();
|
|
73900
|
+
}
|
|
73901
|
+
async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
73902
|
+
workspaceExpectedUserId(membershipId);
|
|
73903
|
+
const env3 = { ...source }, profile = selectedSkillsProfile(env3);
|
|
73904
|
+
if (!profile)
|
|
73905
|
+
return fail2("Workspace login requires an explicit HASNA_PROFILE name.");
|
|
73906
|
+
if (["HASNA_SKILLS_API_KEY_OVERRIDE", "HASNA_SKILLS_API_KEY_REF", "HASNA_SKILLS_API_KEY", "SKILLS_API_KEY"].some((name) => env3[name]?.trim()))
|
|
73907
|
+
return fail2("Clear injected API keys before enrolling a named workspace profile.");
|
|
73908
|
+
const origin = getApiUrl("Sign in to a workspace", env3);
|
|
73909
|
+
const file = getAuthFilePath(env3), identityFile = getIdentityFilePath(env3);
|
|
73910
|
+
const paths = [...new Set([...skillsProfileCredentialFiles(env3), file, identityFile])];
|
|
73911
|
+
const unchangedFiles = captureSkillsCredentialFiles(paths);
|
|
73912
|
+
const old = safeText(file), oldIdentity = safeText(identityFile);
|
|
73913
|
+
const managed = new Set(["HASNA_SKILLS_API_KEY", "SKILLS_API_KEY", "HASNA_SKILLS_API_URL", "SKILLS_API_URL", "HASNA_SKILLS_BOUND_API_URL"]);
|
|
73914
|
+
const lines = (old ?? "").split(/\r?\n/).filter((line) => !managed.has(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line)?.[1] ?? ""));
|
|
73915
|
+
const credentialBody = (key) => [...lines.filter(Boolean), `HASNA_SKILLS_API_KEY=${key}`, `HASNA_SKILLS_API_URL=${origin}`, `HASNA_SKILLS_BOUND_API_URL=${origin}`, ""].join(`
|
|
73916
|
+
`);
|
|
73917
|
+
if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
|
|
73918
|
+
return fail2("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
|
|
73919
|
+
const parents = [];
|
|
73920
|
+
for (let path = dirname10(file);; path = dirname10(path)) {
|
|
73921
|
+
const before2 = stat(path);
|
|
73922
|
+
if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
|
|
73923
|
+
return fail2("The profile directory must not be a symbolic link.");
|
|
73924
|
+
parents.push([path, before2]);
|
|
73925
|
+
if (path === dirname10(path))
|
|
73926
|
+
break;
|
|
73927
|
+
}
|
|
73928
|
+
const unchanged2 = () => {
|
|
73929
|
+
unchangedFiles();
|
|
73930
|
+
for (const [path, before2] of parents) {
|
|
73931
|
+
const now3 = stat(path);
|
|
73932
|
+
if (!before2 ? now3 !== null : !now3 || !now3.isDirectory() || before2.dev !== now3.dev || before2.ino !== now3.ino)
|
|
73933
|
+
changed();
|
|
73934
|
+
}
|
|
73935
|
+
};
|
|
73936
|
+
let expected;
|
|
73937
|
+
try {
|
|
73938
|
+
const connection = await resolveSkillsConnection(env3);
|
|
73939
|
+
if (connection) {
|
|
73940
|
+
if (connection.apiKeyTier !== "profile" || connection.apiOrigin !== origin)
|
|
73941
|
+
return fail2("Workspace login must resolve only the explicitly named profile.");
|
|
73942
|
+
expected = await keyIdentity(connection.apiKey, origin);
|
|
73943
|
+
checkIdentityMetadata(identityFile, expected);
|
|
73944
|
+
}
|
|
73945
|
+
} catch (error2) {
|
|
73946
|
+
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))))
|
|
73947
|
+
throw error2;
|
|
73948
|
+
}
|
|
73949
|
+
unchanged2();
|
|
73950
|
+
return {
|
|
73951
|
+
profile,
|
|
73952
|
+
origin,
|
|
73953
|
+
async complete(email2, code) {
|
|
73954
|
+
unchanged2();
|
|
73955
|
+
if (!email2.includes("@") || !/^\d{6}$/.test(code))
|
|
73956
|
+
return fail2("A fresh email and six-digit verification code are required.");
|
|
73957
|
+
if (expected && expected.user.email.toLowerCase() !== email2.toLowerCase())
|
|
73958
|
+
return fail2("This profile belongs to another account. Use a different profile or ordinary replacement login.");
|
|
73959
|
+
let issued = false;
|
|
73960
|
+
try {
|
|
73961
|
+
const result2 = await new RemoteSkillsAuthClient(origin).verifyCode(email2, code);
|
|
73962
|
+
const login = parseWorkspaceLogin(result2, expected?.user.id);
|
|
73963
|
+
if (result2.firstLogin === true)
|
|
73964
|
+
return fail2("This sign-in created a new account using the server signup policy. Finish ordinary account login before enrolling a workspace profile.");
|
|
73965
|
+
const session = await new RemoteSkillsClient(login.token, origin).switchWorkspace({ userId: login.userId, membershipId });
|
|
73966
|
+
if (session.user.email.toLowerCase() !== email2.toLowerCase())
|
|
73967
|
+
return fail2("The verified account does not match the requested email.");
|
|
73968
|
+
if (session.user.role === "viewer")
|
|
73969
|
+
return fail2("Viewer memberships cannot enroll API keys.");
|
|
73970
|
+
unchanged2();
|
|
73971
|
+
issued = true;
|
|
73972
|
+
const created = await new RemoteSkillsClient(session.token, origin).createApiKey("cli");
|
|
73973
|
+
const verified = await keyIdentity(created.key, origin);
|
|
73974
|
+
if (verified.user.id !== session.user.id || verified.user.membershipId !== membershipId || verified.organization.id !== session.organization.id)
|
|
73975
|
+
return fail2("The issued key does not match the selected workspace.");
|
|
73976
|
+
unchanged2();
|
|
73977
|
+
if (!created.key.trim() || /[^\x21-\x7e]/.test(created.key) || created.key.length > 8192)
|
|
73978
|
+
return fail2("The server returned an invalid API key.");
|
|
73979
|
+
const body = credentialBody(created.key);
|
|
73980
|
+
if (Buffer.byteLength(body, "utf8") > 65536)
|
|
73981
|
+
return fail2("The new profile exceeds the credential reader size limit.");
|
|
73982
|
+
const identity2 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
|
|
73983
|
+
`;
|
|
73984
|
+
mkdirSync14(dirname10(file), { recursive: true, mode: 448 });
|
|
73985
|
+
const temp = mkdtempSync4(join32(dirname10(file), ".workspace-login-"));
|
|
73986
|
+
let identityInstalled = false;
|
|
73987
|
+
try {
|
|
73988
|
+
writeFileSync14(join32(temp, "credentials"), body, { mode: 384, flag: "wx" });
|
|
73989
|
+
writeFileSync14(join32(temp, "identity"), identity2, { mode: 384, flag: "wx" });
|
|
73990
|
+
unchangedFiles();
|
|
73991
|
+
for (const [path, before2] of parents) {
|
|
73992
|
+
const now3 = stat(path);
|
|
73993
|
+
if (!now3 || !now3.isDirectory() || now3.isSymbolicLink() || before2 && (before2.dev !== now3.dev || before2.ino !== now3.ino))
|
|
73994
|
+
changed();
|
|
73995
|
+
if (!before2 && now3 && ((now3.mode & 63) !== 0 || process.getuid && now3.uid !== process.getuid()))
|
|
73996
|
+
changed();
|
|
73997
|
+
}
|
|
73998
|
+
renameSync6(join32(temp, "identity"), identityFile);
|
|
73999
|
+
identityInstalled = true;
|
|
74000
|
+
renameSync6(join32(temp, "credentials"), file);
|
|
74001
|
+
} catch (error2) {
|
|
74002
|
+
if (identityInstalled) {
|
|
74003
|
+
if (oldIdentity === null)
|
|
74004
|
+
rmSync7(identityFile, { force: true });
|
|
74005
|
+
else {
|
|
74006
|
+
writeFileSync14(join32(temp, "restore"), oldIdentity, { mode: 384, flag: "wx" });
|
|
74007
|
+
renameSync6(join32(temp, "restore"), identityFile);
|
|
74008
|
+
}
|
|
74009
|
+
}
|
|
74010
|
+
throw error2;
|
|
74011
|
+
} finally {
|
|
74012
|
+
rmSync7(temp, { recursive: true, force: true });
|
|
74013
|
+
}
|
|
74014
|
+
return {
|
|
74015
|
+
status: "authenticated",
|
|
74016
|
+
profile,
|
|
74017
|
+
apiUrl: origin,
|
|
74018
|
+
userId: verified.user.id,
|
|
74019
|
+
email: verified.user.email,
|
|
74020
|
+
membershipId,
|
|
74021
|
+
organization: verified.organization.slug,
|
|
74022
|
+
organizationId: verified.organization.id,
|
|
74023
|
+
role: verified.user.role,
|
|
74024
|
+
keyCreated: true
|
|
74025
|
+
};
|
|
74026
|
+
} catch (error2) {
|
|
74027
|
+
if (issued)
|
|
74028
|
+
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.");
|
|
74029
|
+
if (error2 instanceof WorkspaceProfileError)
|
|
74030
|
+
throw error2;
|
|
74031
|
+
return fail2("Unable to verify and select the workspace. Check the account, membership, selected server and fresh code. No enrollment key was requested.");
|
|
74032
|
+
}
|
|
74033
|
+
}
|
|
74034
|
+
};
|
|
74035
|
+
}
|
|
74036
|
+
var WorkspaceProfileError, fail2 = (message) => {
|
|
74037
|
+
throw new WorkspaceProfileError(message);
|
|
74038
|
+
}, changed = () => fail2("The selected profile changed during sign-in. No credential was saved; retry with a stable profile.");
|
|
74039
|
+
var init_workspace_profile = __esm(() => {
|
|
74040
|
+
init_auth_store();
|
|
74041
|
+
init_fleet_credentials();
|
|
74042
|
+
init_instance_credentials();
|
|
74043
|
+
init_remote_client();
|
|
74044
|
+
init_remote_auth();
|
|
74045
|
+
init_remote_workspace_selection();
|
|
74046
|
+
WorkspaceProfileError = class WorkspaceProfileError extends Error {
|
|
74047
|
+
};
|
|
74048
|
+
});
|
|
74049
|
+
|
|
73523
74050
|
// src/mcp/remote-customer-tools.ts
|
|
73524
74051
|
function registerRemoteCustomerTools(server) {
|
|
73525
74052
|
const memberRole = exports_external.enum(["owner", "admin", "member", "viewer"]);
|
|
@@ -73529,13 +74056,25 @@ function registerRemoteCustomerTools(server) {
|
|
|
73529
74056
|
email: exports_external.string().email(),
|
|
73530
74057
|
code: exports_external.string().regex(/^\d{6}$/)
|
|
73531
74058
|
};
|
|
74059
|
+
server.registerTool("leave_workspace", {
|
|
74060
|
+
title: "Leave Current Workspace",
|
|
74061
|
+
description: "Leave exactly the observed user and membership with confirm=true and fresh verification. The server enforces last-owner and last-workspace safeguards. Sign in again afterwards; no automatic retry or saved-profile deletion.",
|
|
74062
|
+
annotations: { destructiveHint: true, idempotentHint: false, readOnlyHint: false },
|
|
74063
|
+
inputSchema: exports_external.object({ ...memberInput, userId: memberInput.membershipId, confirm: exports_external.literal(true) }).strict()
|
|
74064
|
+
}, async ({ membershipId, userId, expectedRole, email: email2, code, confirm }) => {
|
|
74065
|
+
try {
|
|
74066
|
+
return mcpJson(await freshAccount("Leave workspace", (client, context) => client.leaveWorkspace(email2, code, workspaceLeaveProfileContext(membershipId, userId, context), { expectedRole, confirm })));
|
|
74067
|
+
} catch (error2) {
|
|
74068
|
+
return error2 instanceof RemoteWorkspaceLeaveError || error2 instanceof RemoteWorkspaceLeaveUnconfirmedError ? mcpError(error2.code, error2.message) : mcpError("WORKSPACE_LEAVE_UNCONFIRMED", "Leaving could not be confirmed. Check the selected profile and exact membership, sign in again and inspect available workspaces before another action. Do not retry automatically; saved credentials are unchanged.");
|
|
74069
|
+
}
|
|
74070
|
+
});
|
|
73532
74071
|
server.registerTool("set_workspace_member_role", {
|
|
73533
74072
|
title: "Set Current Workspace Member Role",
|
|
73534
74073
|
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
74074
|
inputSchema: exports_external.object({ ...memberInput, role: memberRole }).strict()
|
|
73536
|
-
}, async ({ membershipId, role, expectedRole, email: email2, code }) => {
|
|
74075
|
+
}, async ({ membershipId, role: role2, expectedRole, email: email2, code }) => {
|
|
73537
74076
|
try {
|
|
73538
|
-
return mcpJson(await
|
|
74077
|
+
return mcpJson(await freshAccount("Set workspace member role", (client, context) => client.setWorkspaceMemberRole(email2, code, membershipId, { role: role2, expectedRole }, context)));
|
|
73539
74078
|
} catch (error2) {
|
|
73540
74079
|
return memberError(error2);
|
|
73541
74080
|
}
|
|
@@ -73546,7 +74085,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73546
74085
|
inputSchema: exports_external.object(memberInput).strict()
|
|
73547
74086
|
}, async ({ membershipId, expectedRole, email: email2, code }) => {
|
|
73548
74087
|
try {
|
|
73549
|
-
return mcpJson(await
|
|
74088
|
+
return mcpJson(await freshAccount("Remove workspace member", (client, context) => client.removeWorkspaceMember(email2, code, membershipId, { expectedRole }, context)));
|
|
73550
74089
|
} catch (error2) {
|
|
73551
74090
|
return memberError(error2);
|
|
73552
74091
|
}
|
|
@@ -73562,7 +74101,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73562
74101
|
}).strict()
|
|
73563
74102
|
}, async ({ email: email2, code, limit, cursor: cursor2 }) => {
|
|
73564
74103
|
try {
|
|
73565
|
-
return mcpJson(await
|
|
74104
|
+
return mcpJson(await freshAccount("List workspace members", (client, context) => client.listWorkspaceMembers(email2, code, { limit, cursor: cursor2 }, context)));
|
|
73566
74105
|
} catch {
|
|
73567
74106
|
return mcpError("WORKSPACE_MEMBERS_FAILED", "Unable to list workspace members. Check the selected server, owner/admin permissions, pagination and fresh verification code.");
|
|
73568
74107
|
}
|
|
@@ -73574,8 +74113,7 @@ function registerRemoteCustomerTools(server) {
|
|
|
73574
74113
|
inputSchema: exports_external.object({ name: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }).strict()
|
|
73575
74114
|
}, async ({ name, email: email2, code }) => {
|
|
73576
74115
|
try {
|
|
73577
|
-
|
|
73578
|
-
return mcpJson(kind === "profile" ? await client.updateProfile(email2, code, { displayName: name }) : await client.updateCurrentWorkspace(email2, code, { name }));
|
|
74116
|
+
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
74117
|
} catch {
|
|
73580
74118
|
return mcpError("NAME_UPDATE_FAILED", "Unable to update the name. Check the selected server, name, permissions and fresh verification code.");
|
|
73581
74119
|
}
|
|
@@ -73597,9 +74135,9 @@ function registerRemoteCustomerTools(server) {
|
|
|
73597
74135
|
inputSchema: { email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
73598
74136
|
}, async ({ email: email2, code }) => {
|
|
73599
74137
|
try {
|
|
73600
|
-
return mcpJson(await
|
|
73601
|
-
} catch
|
|
73602
|
-
return mcpError("KEY_LIST_FAILED",
|
|
74138
|
+
return mcpJson(await freshAccount("List API keys", (client, context) => client.listApiKeys(email2, code, context)));
|
|
74139
|
+
} catch {
|
|
74140
|
+
return mcpError("KEY_LIST_FAILED", "Unable to list API keys. Check the selected profile, server, account and fresh verification code.");
|
|
73603
74141
|
}
|
|
73604
74142
|
});
|
|
73605
74143
|
server.registerTool("revoke_api_key", {
|
|
@@ -73608,9 +74146,9 @@ function registerRemoteCustomerTools(server) {
|
|
|
73608
74146
|
inputSchema: { key_id: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
73609
74147
|
}, async ({ key_id, email: email2, code }) => {
|
|
73610
74148
|
try {
|
|
73611
|
-
return mcpJson(await
|
|
73612
|
-
} catch
|
|
73613
|
-
return mcpError("KEY_REVOKE_FAILED",
|
|
74149
|
+
return mcpJson(await freshAccount("Revoke API key", (client, context) => client.revokeApiKey(email2, code, key_id, context)));
|
|
74150
|
+
} catch {
|
|
74151
|
+
return mcpError("KEY_REVOKE_FAILED", "Unable to revoke this API key. Check the selected profile, key, account and fresh verification code.");
|
|
73614
74152
|
}
|
|
73615
74153
|
});
|
|
73616
74154
|
server.registerTool("create_api_key", {
|
|
@@ -73618,10 +74156,11 @@ function registerRemoteCustomerTools(server) {
|
|
|
73618
74156
|
description: "Create an API key using fresh email OTP reauthentication; returns its secret once. A stored API key cannot grant this authority.",
|
|
73619
74157
|
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
74158
|
}, async ({ name, email: email2, code, scopes }) => {
|
|
74159
|
+
const capturedScopes = scopes === undefined ? undefined : [...scopes];
|
|
73621
74160
|
try {
|
|
73622
|
-
return mcpJson(await
|
|
73623
|
-
} catch
|
|
73624
|
-
return mcpError("KEY_CREATION_FAILED",
|
|
74161
|
+
return mcpJson(await freshAccount("Create API key", (client, context) => client.createApiKey(email2, code, name, capturedScopes, context)));
|
|
74162
|
+
} catch {
|
|
74163
|
+
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
74164
|
}
|
|
73626
74165
|
});
|
|
73627
74166
|
server.registerTool("quote_skill", {
|
|
@@ -73655,12 +74194,18 @@ async function callRemote(action) {
|
|
|
73655
74194
|
return mcpError("REMOTE_REQUEST_FAILED", error2 instanceof Error ? error2.message : "Skills server request failed");
|
|
73656
74195
|
}
|
|
73657
74196
|
}
|
|
74197
|
+
async function freshAccount(action, operation) {
|
|
74198
|
+
const target = await captureProfileWorkspace(action);
|
|
74199
|
+
target.unchanged();
|
|
74200
|
+
return operation(new RemoteSkillsAuthClient(target.origin), target.context);
|
|
74201
|
+
}
|
|
73658
74202
|
var init_remote_customer_tools = __esm(() => {
|
|
73659
74203
|
init_zod();
|
|
73660
74204
|
init_remote_auth();
|
|
73661
|
-
|
|
74205
|
+
init_workspace_profile();
|
|
73662
74206
|
init_remote_customer_operations();
|
|
73663
74207
|
init_remote_client();
|
|
74208
|
+
init_remote_workspace_leave();
|
|
73664
74209
|
init_helpers();
|
|
73665
74210
|
});
|
|
73666
74211
|
|
|
@@ -74106,9 +74651,9 @@ var init_mcp2 = __esm(() => {
|
|
|
74106
74651
|
});
|
|
74107
74652
|
|
|
74108
74653
|
// src/cli/commands/runtime-mcp.ts
|
|
74109
|
-
import { existsSync as existsSync30, mkdirSync as
|
|
74654
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync15, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "fs";
|
|
74110
74655
|
import { homedir as homedir7 } from "os";
|
|
74111
|
-
import { dirname as
|
|
74656
|
+
import { dirname as dirname11, join as join33 } from "path";
|
|
74112
74657
|
async function handleMcp(options) {
|
|
74113
74658
|
if (options.register) {
|
|
74114
74659
|
let agents;
|
|
@@ -74151,24 +74696,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
74151
74696
|
case "codex":
|
|
74152
74697
|
return registerCodexMcp(command);
|
|
74153
74698
|
case "gemini":
|
|
74154
|
-
return registerJsonMcpServer(agent,
|
|
74699
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".gemini", "settings.json"), "mcpServers", {
|
|
74155
74700
|
command,
|
|
74156
74701
|
args: []
|
|
74157
74702
|
});
|
|
74158
74703
|
case "pi":
|
|
74159
|
-
return registerJsonMcpServer(agent,
|
|
74704
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
74160
74705
|
command,
|
|
74161
74706
|
args: []
|
|
74162
74707
|
});
|
|
74163
74708
|
case "opencode":
|
|
74164
74709
|
return registerOpenCodeMcp(command);
|
|
74165
74710
|
case "cursor":
|
|
74166
|
-
return registerJsonMcpServer(agent,
|
|
74711
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".cursor", "mcp.json"), "mcpServers", {
|
|
74167
74712
|
command,
|
|
74168
74713
|
args: []
|
|
74169
74714
|
});
|
|
74170
74715
|
case "windsurf":
|
|
74171
|
-
return registerJsonMcpServer(agent,
|
|
74716
|
+
return registerJsonMcpServer(agent, join33(homedir7(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
74172
74717
|
command,
|
|
74173
74718
|
args: []
|
|
74174
74719
|
});
|
|
@@ -74191,7 +74736,7 @@ async function registerClaudeMcp(command) {
|
|
|
74191
74736
|
if (exitCode === 0) {
|
|
74192
74737
|
return { agent: "claude", success: true, command: cliCommand };
|
|
74193
74738
|
}
|
|
74194
|
-
const fallback = registerJsonMcpServer("claude",
|
|
74739
|
+
const fallback = registerJsonMcpServer("claude", join33(homedir7(), ".claude", ".mcp.json"), "mcpServers", {
|
|
74195
74740
|
command,
|
|
74196
74741
|
args: []
|
|
74197
74742
|
});
|
|
@@ -74201,7 +74746,7 @@ async function registerClaudeMcp(command) {
|
|
|
74201
74746
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
74202
74747
|
};
|
|
74203
74748
|
} catch (err) {
|
|
74204
|
-
const fallback = registerJsonMcpServer("claude",
|
|
74749
|
+
const fallback = registerJsonMcpServer("claude", join33(homedir7(), ".claude", ".mcp.json"), "mcpServers", {
|
|
74205
74750
|
command,
|
|
74206
74751
|
args: []
|
|
74207
74752
|
});
|
|
@@ -74213,11 +74758,11 @@ async function registerClaudeMcp(command) {
|
|
|
74213
74758
|
}
|
|
74214
74759
|
}
|
|
74215
74760
|
function registerCodexMcp(command) {
|
|
74216
|
-
const path =
|
|
74761
|
+
const path = join33(homedir7(), ".codex", "config.toml");
|
|
74217
74762
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
74218
74763
|
command = ${JSON.stringify(command)}`;
|
|
74219
74764
|
try {
|
|
74220
|
-
const current = existsSync30(path) ?
|
|
74765
|
+
const current = existsSync30(path) ? readFileSync26(path, "utf-8") : "";
|
|
74221
74766
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
74222
74767
|
return { agent: "codex", success: true, path, config: config2 };
|
|
74223
74768
|
} catch (err) {
|
|
@@ -74225,7 +74770,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
74225
74770
|
}
|
|
74226
74771
|
}
|
|
74227
74772
|
function registerOpenCodeMcp(command) {
|
|
74228
|
-
const path =
|
|
74773
|
+
const path = join33(homedir7(), ".config", "opencode", "opencode.json");
|
|
74229
74774
|
const config2 = JSON.stringify({
|
|
74230
74775
|
$schema: "https://opencode.ai/config.json",
|
|
74231
74776
|
mcp: {
|
|
@@ -74269,7 +74814,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
74269
74814
|
function readJsonObject2(path) {
|
|
74270
74815
|
if (!existsSync30(path))
|
|
74271
74816
|
return {};
|
|
74272
|
-
const raw =
|
|
74817
|
+
const raw = readFileSync26(path, "utf-8").trim();
|
|
74273
74818
|
if (!raw)
|
|
74274
74819
|
return {};
|
|
74275
74820
|
const parsed = JSON.parse(raw);
|
|
@@ -74282,8 +74827,8 @@ function writeJsonObject(path, data) {
|
|
|
74282
74827
|
`);
|
|
74283
74828
|
}
|
|
74284
74829
|
function writeTextFile(path, content) {
|
|
74285
|
-
|
|
74286
|
-
|
|
74830
|
+
mkdirSync15(dirname11(path), { recursive: true });
|
|
74831
|
+
writeFileSync15(path, content.endsWith(`
|
|
74287
74832
|
`) ? content : `${content}
|
|
74288
74833
|
`);
|
|
74289
74834
|
}
|
|
@@ -74313,7 +74858,7 @@ function findCommandOnPath(command) {
|
|
|
74313
74858
|
for (const dir of pathValue.split(":")) {
|
|
74314
74859
|
if (!dir)
|
|
74315
74860
|
continue;
|
|
74316
|
-
const candidate =
|
|
74861
|
+
const candidate = join33(dir, command);
|
|
74317
74862
|
if (existsSync30(candidate))
|
|
74318
74863
|
return candidate;
|
|
74319
74864
|
}
|
|
@@ -74375,8 +74920,8 @@ var exports_runtime = {};
|
|
|
74375
74920
|
__export(exports_runtime, {
|
|
74376
74921
|
registerRuntime: () => registerRuntime
|
|
74377
74922
|
});
|
|
74378
|
-
import { lstatSync as
|
|
74379
|
-
import { basename as basename5, isAbsolute as isAbsolute4, join as
|
|
74923
|
+
import { lstatSync as lstatSync7, mkdirSync as mkdirSync16, readFileSync as readFileSync27, realpathSync as realpathSync2, writeFileSync as writeFileSync16 } from "fs";
|
|
74924
|
+
import { basename as basename5, isAbsolute as isAbsolute4, join as join34 } from "path";
|
|
74380
74925
|
import { createInterface } from "readline";
|
|
74381
74926
|
function registerRuntime(parent) {
|
|
74382
74927
|
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 +75195,10 @@ async function handleRun(name, args2, options) {
|
|
|
74650
75195
|
try {
|
|
74651
75196
|
parsePollingOptions(options);
|
|
74652
75197
|
inputFiles = (options.file ?? []).map((path) => {
|
|
74653
|
-
const info =
|
|
75198
|
+
const info = lstatSync7(path);
|
|
74654
75199
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
74655
75200
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
74656
|
-
return { name: basename5(path), bytes: new Uint8Array(
|
|
75201
|
+
return { name: basename5(path), bytes: new Uint8Array(readFileSync27(path)) };
|
|
74657
75202
|
});
|
|
74658
75203
|
describeRemoteFiles(inputFiles);
|
|
74659
75204
|
client = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
|
|
@@ -75024,7 +75569,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
75024
75569
|
const canonicalSkill = typeof remoteRun.skill === "string" ? remoteRun.skill : "remote";
|
|
75025
75570
|
const requestedSkill = typeof remoteRun.requestedSlug === "string" && remoteRun.requestedSlug.trim() ? remoteRun.requestedSlug : canonicalSkill;
|
|
75026
75571
|
const exportDir = getRunExportDir(runId, requestedSkill);
|
|
75027
|
-
|
|
75572
|
+
mkdirSync16(exportDir, { recursive: true });
|
|
75028
75573
|
const downloaded = [];
|
|
75029
75574
|
for (const artifact of artifacts) {
|
|
75030
75575
|
const artifactId = String(artifact.id || "");
|
|
@@ -75032,9 +75577,9 @@ async function handleExportsDownload(runId, options) {
|
|
|
75032
75577
|
continue;
|
|
75033
75578
|
const verified = await client.getVerifiedRunArtifact(runId, artifactId);
|
|
75034
75579
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
75035
|
-
const outputPath =
|
|
75580
|
+
const outputPath = join34(exportDir, relativePath);
|
|
75036
75581
|
ensureSafeExportParent(exportDir, relativePath);
|
|
75037
|
-
|
|
75582
|
+
writeFileSync16(outputPath, verified.bytes, { flag: "wx", mode: 384 });
|
|
75038
75583
|
downloaded.push({ id: artifactId, path: outputPath, byteSize: verified.byteSize });
|
|
75039
75584
|
}
|
|
75040
75585
|
const payload = {
|
|
@@ -75071,14 +75616,14 @@ function ensureSafeExportParent(root, relativePath) {
|
|
|
75071
75616
|
let parent = root;
|
|
75072
75617
|
for (const part of ["", ...parts]) {
|
|
75073
75618
|
if (part)
|
|
75074
|
-
parent =
|
|
75619
|
+
parent = join34(parent, part);
|
|
75075
75620
|
try {
|
|
75076
|
-
if (!
|
|
75621
|
+
if (!lstatSync7(parent).isDirectory() || lstatSync7(parent).isSymbolicLink())
|
|
75077
75622
|
throw new Error("Unsafe artifact directory");
|
|
75078
75623
|
} catch (error2) {
|
|
75079
75624
|
if (error2.code !== "ENOENT")
|
|
75080
75625
|
throw error2;
|
|
75081
|
-
|
|
75626
|
+
mkdirSync16(parent, { mode: 448 });
|
|
75082
75627
|
}
|
|
75083
75628
|
}
|
|
75084
75629
|
}
|
|
@@ -75416,7 +75961,7 @@ var init_completion = __esm(() => {
|
|
|
75416
75961
|
// src/lib/portable-snapshot-filter.ts
|
|
75417
75962
|
import { readdirSync as readdirSync16, statSync as statSync17 } from "fs";
|
|
75418
75963
|
import { homedir as homedir8 } from "os";
|
|
75419
|
-
import { join as
|
|
75964
|
+
import { join as join35, sep as sep3 } from "path";
|
|
75420
75965
|
function isExcludedSkillFileName(fileName) {
|
|
75421
75966
|
if (EXCLUDE_FILE_NAMES.has(fileName)) {
|
|
75422
75967
|
return true;
|
|
@@ -75439,16 +75984,16 @@ function isPortableWithinSkill(relativeParts) {
|
|
|
75439
75984
|
function homePathFor(definition, homesRoot) {
|
|
75440
75985
|
const home = homesRoot ?? homedir8();
|
|
75441
75986
|
if (definition.subClass === "skills" || definition.subClass === "custom") {
|
|
75442
|
-
return
|
|
75987
|
+
return join35(skillsDataRootForHome(home), definition.name);
|
|
75443
75988
|
}
|
|
75444
75989
|
if (definition.agent === "opencode") {
|
|
75445
|
-
return
|
|
75990
|
+
return join35(home, ".config", "opencode", "skills");
|
|
75446
75991
|
}
|
|
75447
|
-
return
|
|
75992
|
+
return join35(home, `.${definition.agent}`, "skills");
|
|
75448
75993
|
}
|
|
75449
75994
|
function destinationFor(definition, stationId, relativePath) {
|
|
75450
|
-
const category = definition.subClass === "agent-homes" ?
|
|
75451
|
-
return
|
|
75995
|
+
const category = definition.subClass === "agent-homes" ? join35("agent-homes", definition.agent ?? "") : definition.name;
|
|
75996
|
+
return join35("resources", stationId, "skills", category, ...relativePath.split(sep3));
|
|
75452
75997
|
}
|
|
75453
75998
|
function walkEntries(absoluteRoot) {
|
|
75454
75999
|
let entries;
|
|
@@ -75459,7 +76004,7 @@ function walkEntries(absoluteRoot) {
|
|
|
75459
76004
|
}
|
|
75460
76005
|
const output = [];
|
|
75461
76006
|
for (const entry of entries) {
|
|
75462
|
-
const childFull =
|
|
76007
|
+
const childFull = join35(absoluteRoot, entry.name);
|
|
75463
76008
|
if (entry.isSymbolicLink()) {
|
|
75464
76009
|
output.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
|
|
75465
76010
|
continue;
|
|
@@ -75470,7 +76015,7 @@ function walkEntries(absoluteRoot) {
|
|
|
75470
76015
|
}
|
|
75471
76016
|
const nested = walkEntries(childFull);
|
|
75472
76017
|
for (const item of nested) {
|
|
75473
|
-
output.push({ ...item, relativePath:
|
|
76018
|
+
output.push({ ...item, relativePath: join35(entry.name, item.relativePath) });
|
|
75474
76019
|
}
|
|
75475
76020
|
continue;
|
|
75476
76021
|
}
|
|
@@ -75566,19 +76111,19 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
75566
76111
|
import { createHash as createHash7 } from "crypto";
|
|
75567
76112
|
import {
|
|
75568
76113
|
copyFileSync as copyFileSync2,
|
|
75569
|
-
mkdirSync as
|
|
75570
|
-
readFileSync as
|
|
76114
|
+
mkdirSync as mkdirSync17,
|
|
76115
|
+
readFileSync as readFileSync28,
|
|
75571
76116
|
statSync as statSync18,
|
|
75572
|
-
writeFileSync as
|
|
76117
|
+
writeFileSync as writeFileSync17
|
|
75573
76118
|
} from "fs";
|
|
75574
|
-
import { dirname as
|
|
76119
|
+
import { dirname as dirname13, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve3, sep as sep4 } from "path";
|
|
75575
76120
|
function validateStationId(stationId) {
|
|
75576
76121
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
75577
76122
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
75578
76123
|
}
|
|
75579
76124
|
}
|
|
75580
76125
|
function sha256File(filePath) {
|
|
75581
|
-
return createHash7("sha256").update(
|
|
76126
|
+
return createHash7("sha256").update(readFileSync28(filePath)).digest("hex");
|
|
75582
76127
|
}
|
|
75583
76128
|
function scanHome(definition, homesRoot) {
|
|
75584
76129
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -75699,7 +76244,7 @@ function writeStationSnapshot(options) {
|
|
|
75699
76244
|
let written = 0;
|
|
75700
76245
|
for (const plan of untouched) {
|
|
75701
76246
|
const destination = resolve3(repoRoot, plan.destination);
|
|
75702
|
-
|
|
76247
|
+
mkdirSync17(dirname13(destination), { recursive: true });
|
|
75703
76248
|
copyFileSync2(plan.source.fullPath, destination);
|
|
75704
76249
|
written += 1;
|
|
75705
76250
|
}
|
|
@@ -75718,8 +76263,8 @@ function writeStationSnapshot(options) {
|
|
|
75718
76263
|
files: manifestFiles
|
|
75719
76264
|
};
|
|
75720
76265
|
const manifestPath = resolve3(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
75721
|
-
|
|
75722
|
-
|
|
76266
|
+
mkdirSync17(dirname13(manifestPath), { recursive: true });
|
|
76267
|
+
writeFileSync17(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
75723
76268
|
`);
|
|
75724
76269
|
return {
|
|
75725
76270
|
...base2,
|
|
@@ -75751,7 +76296,7 @@ __export(exports_create_sync_config, {
|
|
|
75751
76296
|
registerCreateSync: () => registerCreateSync
|
|
75752
76297
|
});
|
|
75753
76298
|
import { existsSync as existsSync31 } from "fs";
|
|
75754
|
-
import { join as
|
|
76299
|
+
import { join as join36 } from "path";
|
|
75755
76300
|
function registerCreateSync(parent) {
|
|
75756
76301
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
75757
76302
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -75857,7 +76402,7 @@ function handleCreate(name, options) {
|
|
|
75857
76402
|
console.log(source_default.green(`\u2713 Created custom skill '${result2.name}' at ${result2.path}`));
|
|
75858
76403
|
console.log(source_default.dim(` Category: ${result2.manifest.category}`));
|
|
75859
76404
|
console.log(source_default.dim(` Tags: ${result2.manifest.tags?.join(", ")}`));
|
|
75860
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
76405
|
+
console.log(` ${source_default.cyan("Edit:")} ${join36(result2.path, "src", "index.ts")}`);
|
|
75861
76406
|
console.log(` ${source_default.cyan("Run:")} skills run ${result2.name} --help`);
|
|
75862
76407
|
}
|
|
75863
76408
|
} catch (error2) {
|
|
@@ -76136,27 +76681,27 @@ var init_create_sync_config = __esm(() => {
|
|
|
76136
76681
|
import { createHash as createHash8 } from "crypto";
|
|
76137
76682
|
import {
|
|
76138
76683
|
copyFileSync as copyFileSync3,
|
|
76139
|
-
mkdirSync as
|
|
76684
|
+
mkdirSync as mkdirSync18,
|
|
76140
76685
|
readdirSync as readdirSync17,
|
|
76141
|
-
readFileSync as
|
|
76686
|
+
readFileSync as readFileSync29,
|
|
76142
76687
|
statSync as statSync19,
|
|
76143
|
-
writeFileSync as
|
|
76688
|
+
writeFileSync as writeFileSync18
|
|
76144
76689
|
} from "fs";
|
|
76145
|
-
import { dirname as
|
|
76146
|
-
function
|
|
76690
|
+
import { dirname as dirname14, join as join37, resolve as resolve4, sep as sep5 } from "path";
|
|
76691
|
+
function fail3(code, message, detail = []) {
|
|
76147
76692
|
throw new StationSnapshotError(code, message, detail);
|
|
76148
76693
|
}
|
|
76149
76694
|
function snapshotRootFor(repoRoot, stationId) {
|
|
76150
|
-
return
|
|
76695
|
+
return join37(repoRoot, "resources", stationId, "skills");
|
|
76151
76696
|
}
|
|
76152
76697
|
function readSnapshotManifest(repoRoot, stationId) {
|
|
76153
76698
|
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
76154
|
-
const manifestPath =
|
|
76699
|
+
const manifestPath = join37(snapshotRoot, "sync-manifest.json");
|
|
76155
76700
|
let manifest;
|
|
76156
76701
|
try {
|
|
76157
|
-
manifest = JSON.parse(
|
|
76702
|
+
manifest = JSON.parse(readFileSync29(manifestPath, "utf8"));
|
|
76158
76703
|
} catch (error2) {
|
|
76159
|
-
|
|
76704
|
+
fail3("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error2.message}`);
|
|
76160
76705
|
}
|
|
76161
76706
|
const sourceSnapshotSha = sha256File(manifestPath);
|
|
76162
76707
|
return { manifest, manifestPath, sourceSnapshotSha };
|
|
@@ -76178,7 +76723,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76178
76723
|
const hashMismatches = [];
|
|
76179
76724
|
const skippedByRule = [];
|
|
76180
76725
|
for (const agent of SYNC_AGENTS) {
|
|
76181
|
-
const agentRoot =
|
|
76726
|
+
const agentRoot = join37(snapshotRoot, "agent-homes", agent);
|
|
76182
76727
|
let identEntries;
|
|
76183
76728
|
try {
|
|
76184
76729
|
identEntries = readdirSync17(agentRoot, { withFileTypes: true });
|
|
@@ -76189,7 +76734,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76189
76734
|
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
76190
76735
|
continue;
|
|
76191
76736
|
}
|
|
76192
|
-
const identRoot =
|
|
76737
|
+
const identRoot = join37(agentRoot, identEntry.name);
|
|
76193
76738
|
const entries = walkEntries(identRoot);
|
|
76194
76739
|
for (const entry of entries) {
|
|
76195
76740
|
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep5)];
|
|
@@ -76263,10 +76808,10 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76263
76808
|
}
|
|
76264
76809
|
}
|
|
76265
76810
|
if (symlinks.length > 0) {
|
|
76266
|
-
|
|
76811
|
+
fail3("SYMLINKS_REFUSED", `${symlinks.length} symlink(s) inside the snapshot; symlinks are refused (fail closed)`);
|
|
76267
76812
|
}
|
|
76268
76813
|
if (hashMismatches.length > 0) {
|
|
76269
|
-
|
|
76814
|
+
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
76815
|
}
|
|
76271
76816
|
const byIdent = new Map;
|
|
76272
76817
|
for (const candidate of candidates) {
|
|
@@ -76290,7 +76835,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
76290
76835
|
for (const copy of copies) {
|
|
76291
76836
|
let isStub = false;
|
|
76292
76837
|
try {
|
|
76293
|
-
isStub = isPointerSkillMd(
|
|
76838
|
+
isStub = isPointerSkillMd(readFileSync29(copy.fullPath, "utf8"));
|
|
76294
76839
|
} catch {
|
|
76295
76840
|
isStub = false;
|
|
76296
76841
|
}
|
|
@@ -76374,7 +76919,7 @@ function writeStationHydration(options) {
|
|
|
76374
76919
|
const toWrite = [];
|
|
76375
76920
|
for (const skill of plan.winners) {
|
|
76376
76921
|
for (const file of skill.files) {
|
|
76377
|
-
const destination =
|
|
76922
|
+
const destination = join37(cacheRoot, skill.ident, file.withinIdent);
|
|
76378
76923
|
const digest = sha256File(file.winner.fullPath);
|
|
76379
76924
|
let existingDigest = null;
|
|
76380
76925
|
try {
|
|
@@ -76391,11 +76936,11 @@ function writeStationHydration(options) {
|
|
|
76391
76936
|
}
|
|
76392
76937
|
}
|
|
76393
76938
|
if (conflicts.length > 0) {
|
|
76394
|
-
|
|
76939
|
+
fail3("CONFLICT", `${conflicts.length} conflict(s); terminal non-acceptance, nothing written`, conflicts);
|
|
76395
76940
|
}
|
|
76396
76941
|
let written = 0;
|
|
76397
76942
|
for (const entry of toWrite) {
|
|
76398
|
-
|
|
76943
|
+
mkdirSync18(dirname14(entry.destination), { recursive: true });
|
|
76399
76944
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
76400
76945
|
written += 1;
|
|
76401
76946
|
}
|
|
@@ -76416,9 +76961,9 @@ function writeStationHydration(options) {
|
|
|
76416
76961
|
},
|
|
76417
76962
|
skills: resultSkills
|
|
76418
76963
|
};
|
|
76419
|
-
const hydrationManifestPath =
|
|
76420
|
-
|
|
76421
|
-
|
|
76964
|
+
const hydrationManifestPath = join37(dirname14(cacheRoot), `hydration-${options.stationId}.json`);
|
|
76965
|
+
mkdirSync18(dirname14(hydrationManifestPath), { recursive: true });
|
|
76966
|
+
writeFileSync18(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
76422
76967
|
`);
|
|
76423
76968
|
return {
|
|
76424
76969
|
...base2,
|
|
@@ -76846,8 +77391,8 @@ var init_schedule = __esm(() => {
|
|
|
76846
77391
|
});
|
|
76847
77392
|
|
|
76848
77393
|
// src/lib/registry-sync.ts
|
|
76849
|
-
import { mkdirSync as
|
|
76850
|
-
import { dirname as
|
|
77394
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync19 } from "fs";
|
|
77395
|
+
import { dirname as dirname15, relative as relative6 } from "path";
|
|
76851
77396
|
function createRegistrySyncArtifact(options = {}) {
|
|
76852
77397
|
const profile = options.profile ?? "all";
|
|
76853
77398
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -76904,8 +77449,8 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
76904
77449
|
};
|
|
76905
77450
|
}
|
|
76906
77451
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
76907
|
-
|
|
76908
|
-
|
|
77452
|
+
mkdirSync19(dirname15(path), { recursive: true });
|
|
77453
|
+
writeFileSync19(path, `${JSON.stringify(artifact, null, 2)}
|
|
76909
77454
|
`);
|
|
76910
77455
|
}
|
|
76911
77456
|
function buildDocs(name) {
|
|
@@ -76935,10 +77480,10 @@ function registerRegistry(parent) {
|
|
|
76935
77480
|
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
77481
|
}
|
|
76937
77482
|
async function writeJson2(value, space) {
|
|
76938
|
-
const
|
|
77483
|
+
const text2 = `${JSON.stringify(value, null, space)}
|
|
76939
77484
|
`;
|
|
76940
77485
|
await new Promise((resolve5, reject2) => {
|
|
76941
|
-
process.stdout.write(
|
|
77486
|
+
process.stdout.write(text2, (error2) => {
|
|
76942
77487
|
if (error2)
|
|
76943
77488
|
reject2(error2);
|
|
76944
77489
|
else
|
|
@@ -76970,10 +77515,10 @@ async function handleRegistrySync(options) {
|
|
|
76970
77515
|
await writeJson2(artifact, 2);
|
|
76971
77516
|
return;
|
|
76972
77517
|
}
|
|
76973
|
-
const
|
|
77518
|
+
const invalid2 = artifact.summary.invalidSkillCount ?? "not checked";
|
|
76974
77519
|
console.log(source_default.green(`Registry sync artifact written to ${options.output}`));
|
|
76975
77520
|
console.log(source_default.dim(` Skills: ${artifact.summary.skillCount}`));
|
|
76976
|
-
console.log(source_default.dim(` Invalid: ${
|
|
77521
|
+
console.log(source_default.dim(` Invalid: ${invalid2}`));
|
|
76977
77522
|
}
|
|
76978
77523
|
function registerPull(parent) {
|
|
76979
77524
|
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 +77623,9 @@ __export(exports_publish, {
|
|
|
77078
77623
|
PushSkillError: () => PushSkillError
|
|
77079
77624
|
});
|
|
77080
77625
|
import { execFileSync } from "child_process";
|
|
77081
|
-
import { existsSync as existsSync32, readFileSync as
|
|
77626
|
+
import { existsSync as existsSync32, readFileSync as readFileSync30 } from "fs";
|
|
77082
77627
|
import { hostname as hostname2 } from "os";
|
|
77083
|
-
import { join as
|
|
77628
|
+
import { join as join38 } from "path";
|
|
77084
77629
|
function registerPublish(parent) {
|
|
77085
77630
|
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
77631
|
try {
|
|
@@ -77127,8 +77672,8 @@ async function pushSkill(name, options = {}) {
|
|
|
77127
77672
|
}
|
|
77128
77673
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
77129
77674
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
77130
|
-
const skillMdPath =
|
|
77131
|
-
const skillMd = existsSync32(skillMdPath) ?
|
|
77675
|
+
const skillMdPath = join38(skill.path, "SKILL.md");
|
|
77676
|
+
const skillMd = existsSync32(skillMdPath) ? readFileSync30(skillMdPath, "utf-8") : undefined;
|
|
77132
77677
|
const base2 = {
|
|
77133
77678
|
slug: skill.name,
|
|
77134
77679
|
path: skill.path,
|
|
@@ -77193,21 +77738,21 @@ async function readPublishRevision(client, slug) {
|
|
|
77193
77738
|
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
77739
|
}
|
|
77195
77740
|
const body = lookup.body;
|
|
77196
|
-
const
|
|
77197
|
-
const nestedError =
|
|
77198
|
-
const code = typeof
|
|
77741
|
+
const record5 = body !== null && typeof body === "object" && !Array.isArray(body) ? body : undefined;
|
|
77742
|
+
const nestedError = record5?.error;
|
|
77743
|
+
const code = typeof record5?.code === "string" ? record5.code : nestedError !== null && typeof nestedError === "object" && !Array.isArray(nestedError) ? nestedError.code : undefined;
|
|
77199
77744
|
if (lookup.status === 404 && code === "SKILL_NOT_FOUND")
|
|
77200
77745
|
return;
|
|
77201
77746
|
if (lookup.status < 200 || lookup.status >= 300) {
|
|
77202
77747
|
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
77748
|
}
|
|
77204
|
-
const revision =
|
|
77205
|
-
if (
|
|
77206
|
-
if (
|
|
77749
|
+
const revision = record5?.revisionId;
|
|
77750
|
+
if (record5?.publicationState === "catalogue-only") {
|
|
77751
|
+
if (record5.name === slug && (record5.slug === undefined || record5.slug === slug) && revision === null)
|
|
77207
77752
|
return;
|
|
77208
77753
|
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
77754
|
}
|
|
77210
|
-
if (
|
|
77755
|
+
if (record5?.slug !== slug || typeof revision !== "string" || revision.length === 0 || revision !== revision.trim() || !/^[\x21-\x7e]+$/.test(revision)) {
|
|
77211
77756
|
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
77757
|
}
|
|
77213
77758
|
return revision;
|
|
@@ -77310,13 +77855,13 @@ Dry run: '${result2.slug}' would be published
|
|
|
77310
77855
|
console.log("");
|
|
77311
77856
|
}
|
|
77312
77857
|
async function readBody(response) {
|
|
77313
|
-
const
|
|
77314
|
-
if (!
|
|
77858
|
+
const text2 = await response.text();
|
|
77859
|
+
if (!text2.trim())
|
|
77315
77860
|
return null;
|
|
77316
77861
|
try {
|
|
77317
|
-
return JSON.parse(
|
|
77862
|
+
return JSON.parse(text2);
|
|
77318
77863
|
} catch {
|
|
77319
|
-
return
|
|
77864
|
+
return text2;
|
|
77320
77865
|
}
|
|
77321
77866
|
}
|
|
77322
77867
|
function describeError(payload) {
|
|
@@ -77349,6 +77894,152 @@ var init_publish = __esm(() => {
|
|
|
77349
77894
|
};
|
|
77350
77895
|
});
|
|
77351
77896
|
|
|
77897
|
+
// src/cli/commands/customer-verification.ts
|
|
77898
|
+
import { emitKeypressEvents } from "readline";
|
|
77899
|
+
async function readCode() {
|
|
77900
|
+
if (process.stdin.isTTY)
|
|
77901
|
+
throw new NameInputError("Pipe a fresh six-digit verification code when using --code-stdin.");
|
|
77902
|
+
let text2 = "";
|
|
77903
|
+
for await (const chunk2 of process.stdin) {
|
|
77904
|
+
text2 += chunk2.toString();
|
|
77905
|
+
if (text2.length > 32)
|
|
77906
|
+
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77907
|
+
}
|
|
77908
|
+
const code = text2.trim();
|
|
77909
|
+
if (!/^\d{6}$/.test(code))
|
|
77910
|
+
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
77911
|
+
return code;
|
|
77912
|
+
}
|
|
77913
|
+
function promptCode() {
|
|
77914
|
+
const { stdin, stderr: output } = process;
|
|
77915
|
+
const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
|
|
77916
|
+
return new Promise((resolve5) => {
|
|
77917
|
+
let value = "", settled = false;
|
|
77918
|
+
const finish = (answer) => {
|
|
77919
|
+
if (settled)
|
|
77920
|
+
return;
|
|
77921
|
+
settled = true;
|
|
77922
|
+
clearTimeout(timer);
|
|
77923
|
+
stdin.off("keypress", keypress);
|
|
77924
|
+
stdin.off("end", cancel);
|
|
77925
|
+
process.off("SIGINT", cancel);
|
|
77926
|
+
stdin.setRawMode(wasRaw);
|
|
77927
|
+
if (wasFlowing !== true)
|
|
77928
|
+
stdin.pause();
|
|
77929
|
+
output.write(`
|
|
77930
|
+
`);
|
|
77931
|
+
if (answer === null)
|
|
77932
|
+
process.exitCode = 130;
|
|
77933
|
+
resolve5(answer);
|
|
77934
|
+
};
|
|
77935
|
+
const cancel = () => finish(null);
|
|
77936
|
+
const keypress = (text2, key) => {
|
|
77937
|
+
if (key.ctrl && ["c", "d"].includes(key.name ?? "") || key.name === "escape")
|
|
77938
|
+
return cancel();
|
|
77939
|
+
if (key.name === "return" || key.name === "enter") {
|
|
77940
|
+
if (value.length === 6)
|
|
77941
|
+
return finish(value);
|
|
77942
|
+
output.write(`
|
|
77943
|
+
Enter all six digits: `);
|
|
77944
|
+
value = "";
|
|
77945
|
+
return;
|
|
77946
|
+
}
|
|
77947
|
+
if (key.name === "backspace") {
|
|
77948
|
+
if (value) {
|
|
77949
|
+
value = value.slice(0, -1);
|
|
77950
|
+
output.write("\b \b");
|
|
77951
|
+
}
|
|
77952
|
+
} else if (/^[0-9]$/.test(text2) && value.length < 6) {
|
|
77953
|
+
value += text2;
|
|
77954
|
+
output.write("*");
|
|
77955
|
+
}
|
|
77956
|
+
};
|
|
77957
|
+
const timer = setTimeout(cancel, 5 * 60 * 1000);
|
|
77958
|
+
emitKeypressEvents(stdin);
|
|
77959
|
+
stdin.setRawMode(true);
|
|
77960
|
+
stdin.on("keypress", keypress);
|
|
77961
|
+
stdin.once("end", cancel);
|
|
77962
|
+
process.once("SIGINT", cancel);
|
|
77963
|
+
output.write("Enter the six-digit code sent to your email: ");
|
|
77964
|
+
stdin.resume();
|
|
77965
|
+
});
|
|
77966
|
+
}
|
|
77967
|
+
var NameInputError;
|
|
77968
|
+
var init_customer_verification = __esm(() => {
|
|
77969
|
+
NameInputError = class NameInputError extends Error {
|
|
77970
|
+
};
|
|
77971
|
+
});
|
|
77972
|
+
|
|
77973
|
+
// src/cli/commands/workspace-selection.ts
|
|
77974
|
+
async function codeFor(client, options) {
|
|
77975
|
+
if (!options.email?.includes("@"))
|
|
77976
|
+
throw new NameInputError("Provide the account email with --email.");
|
|
77977
|
+
if (options.codeStdin)
|
|
77978
|
+
return readCode();
|
|
77979
|
+
if (options.json || !process.stdin.isTTY || !process.stderr.isTTY)
|
|
77980
|
+
throw new NameInputError("Use --code-stdin with a fresh verification code for noninteractive requests.");
|
|
77981
|
+
await client.requestCode(options.email);
|
|
77982
|
+
return promptCode();
|
|
77983
|
+
}
|
|
77984
|
+
function errorResult(error2, json) {
|
|
77985
|
+
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.";
|
|
77986
|
+
if (json)
|
|
77987
|
+
console.log(JSON.stringify({ error: message }));
|
|
77988
|
+
else
|
|
77989
|
+
console.error(message);
|
|
77990
|
+
process.exitCode = 1;
|
|
77991
|
+
}
|
|
77992
|
+
function registerWorkspaceListCommand(workspace) {
|
|
77993
|
+
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) => {
|
|
77994
|
+
try {
|
|
77995
|
+
const origin = getApiUrl("Discover workspaces", { ...process.env });
|
|
77996
|
+
const client = new RemoteSkillsAuthClient(origin);
|
|
77997
|
+
const code = await codeFor(client, options);
|
|
77998
|
+
if (code === null)
|
|
77999
|
+
return;
|
|
78000
|
+
const result2 = await client.listAccountWorkspaces(options.email, code);
|
|
78001
|
+
if (options.json)
|
|
78002
|
+
console.log(JSON.stringify({ apiUrl: origin, ...result2 }));
|
|
78003
|
+
else {
|
|
78004
|
+
console.log(`Account: ${result2.userId}
|
|
78005
|
+
API: ${origin}`);
|
|
78006
|
+
for (const entry of result2.workspaces)
|
|
78007
|
+
console.log(`${entry.current ? "*" : " "} ${entry.organization.name} ${entry.role} ${entry.membershipId}`);
|
|
78008
|
+
console.log("* Initial sign-in workspace. Enroll a named profile with auth login --membership-id <id>.");
|
|
78009
|
+
}
|
|
78010
|
+
} catch (error2) {
|
|
78011
|
+
errorResult(error2, options.json);
|
|
78012
|
+
}
|
|
78013
|
+
});
|
|
78014
|
+
}
|
|
78015
|
+
async function loginWorkspace(options) {
|
|
78016
|
+
try {
|
|
78017
|
+
const enrollment = await prepareWorkspaceEnrollment(options.membershipId);
|
|
78018
|
+
const code = await codeFor(new RemoteSkillsAuthClient(enrollment.origin), options);
|
|
78019
|
+
if (code === null)
|
|
78020
|
+
return;
|
|
78021
|
+
const result2 = await enrollment.complete(options.email, code);
|
|
78022
|
+
if (options.json)
|
|
78023
|
+
console.log(JSON.stringify(result2));
|
|
78024
|
+
else
|
|
78025
|
+
console.log(`Signed in as ${result2.email}
|
|
78026
|
+
Profile: ${result2.profile}
|
|
78027
|
+
API: ${result2.apiUrl}
|
|
78028
|
+
Workspace: ${result2.organization} (${result2.organizationId})
|
|
78029
|
+
Membership: ${result2.membershipId}
|
|
78030
|
+
Role: ${result2.role}
|
|
78031
|
+
One workspace key saved. Use HASNA_PROFILE=${result2.profile} for subsequent commands.`);
|
|
78032
|
+
} catch (error2) {
|
|
78033
|
+
errorResult(error2, options.json);
|
|
78034
|
+
}
|
|
78035
|
+
}
|
|
78036
|
+
var init_workspace_selection = __esm(() => {
|
|
78037
|
+
init_auth_store();
|
|
78038
|
+
init_remote_auth();
|
|
78039
|
+
init_workspace_profile();
|
|
78040
|
+
init_customer_verification();
|
|
78041
|
+
});
|
|
78042
|
+
|
|
77352
78043
|
// src/cli/commands/auth.ts
|
|
77353
78044
|
var exports_auth = {};
|
|
77354
78045
|
__export(exports_auth, {
|
|
@@ -77434,13 +78125,13 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
|
77434
78125
|
const root = recordField(live) ?? {};
|
|
77435
78126
|
const data = recordField(root.data);
|
|
77436
78127
|
const user = recordField(root.user) ?? recordField(data?.user);
|
|
77437
|
-
const
|
|
78128
|
+
const organization2 = recordField(root.organization) ?? recordField(root.org) ?? recordField(data?.organization);
|
|
77438
78129
|
const email2 = stringField2(user?.email) ?? cached2?.email;
|
|
77439
|
-
const orgSlug = stringField2(
|
|
77440
|
-
const orgName = stringField2(
|
|
78130
|
+
const orgSlug = stringField2(organization2?.slug) ?? cached2?.orgSlug;
|
|
78131
|
+
const orgName = stringField2(organization2?.name);
|
|
77441
78132
|
const userId = stringField2(user?.id) ?? cached2?.userId;
|
|
77442
|
-
const orgId = stringField2(
|
|
77443
|
-
const
|
|
78133
|
+
const orgId = stringField2(organization2?.id) ?? cached2?.orgId;
|
|
78134
|
+
const role2 = stringField2(user?.role);
|
|
77444
78135
|
return {
|
|
77445
78136
|
status: "authenticated",
|
|
77446
78137
|
authSource,
|
|
@@ -77450,7 +78141,7 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
|
77450
78141
|
...orgName ? { organizationName: orgName } : {},
|
|
77451
78142
|
...userId ? { userId } : {},
|
|
77452
78143
|
...orgId ? { orgId } : {},
|
|
77453
|
-
...
|
|
78144
|
+
...role2 ? { role: role2 } : {}
|
|
77454
78145
|
};
|
|
77455
78146
|
}
|
|
77456
78147
|
function printWhoami(payload) {
|
|
@@ -77748,15 +78439,19 @@ function registerAuth(parent) {
|
|
|
77748
78439
|
const keys2 = auth.command("keys").description("Manage API keys on the configured instance");
|
|
77749
78440
|
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
78441
|
try {
|
|
77751
|
-
|
|
78442
|
+
const target = await captureProfileWorkspace("List API keys");
|
|
78443
|
+
target.unchanged();
|
|
78444
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(target.origin).listApiKeys(options.email, options.code, target.context), null, 2));
|
|
77752
78445
|
} catch (error2) {
|
|
77753
78446
|
writeCommandError(error2, "Failed to list API keys", options.json);
|
|
77754
78447
|
}
|
|
77755
78448
|
});
|
|
77756
78449
|
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
78450
|
try {
|
|
77758
|
-
const
|
|
77759
|
-
const
|
|
78451
|
+
const target = await captureProfileWorkspace("Create API key");
|
|
78452
|
+
const client = new RemoteSkillsAuthClient(target.origin);
|
|
78453
|
+
target.unchanged();
|
|
78454
|
+
const created = await client.createApiKey(options.email, options.code, name, options.scope.length ? options.scope : undefined, target.context);
|
|
77760
78455
|
console.log(JSON.stringify(created, null, 2));
|
|
77761
78456
|
} catch (error2) {
|
|
77762
78457
|
writeCommandError(error2, "Failed to create API key", options.json);
|
|
@@ -77764,12 +78459,26 @@ function registerAuth(parent) {
|
|
|
77764
78459
|
});
|
|
77765
78460
|
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
78461
|
try {
|
|
77767
|
-
|
|
78462
|
+
const target = await captureProfileWorkspace("Revoke API key");
|
|
78463
|
+
target.unchanged();
|
|
78464
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(target.origin).revokeApiKey(options.email, options.code, id, target.context), null, 2));
|
|
77768
78465
|
} catch (error2) {
|
|
77769
78466
|
writeCommandError(error2, "Failed to revoke API key", options.json);
|
|
77770
78467
|
}
|
|
77771
78468
|
});
|
|
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) => {
|
|
78469
|
+
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) => {
|
|
78470
|
+
if (options.membershipId !== undefined) {
|
|
78471
|
+
if (options.apiKey || options.device || options.code || options.poll) {
|
|
78472
|
+
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);
|
|
78473
|
+
return;
|
|
78474
|
+
}
|
|
78475
|
+
await loginWorkspace({ ...options, membershipId: options.membershipId });
|
|
78476
|
+
return;
|
|
78477
|
+
}
|
|
78478
|
+
if (options.codeStdin) {
|
|
78479
|
+
writeCommandError(new Error("--code-stdin requires --membership-id for this login flow."), "Invalid login options", options.json);
|
|
78480
|
+
return;
|
|
78481
|
+
}
|
|
77773
78482
|
if (options.apiKey) {
|
|
77774
78483
|
await doApiKeyLogin(options.apiKey, options.json);
|
|
77775
78484
|
return;
|
|
@@ -77877,6 +78586,8 @@ function registerAuth(parent) {
|
|
|
77877
78586
|
}
|
|
77878
78587
|
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS, CONFIG_HINT_STATUSES;
|
|
77879
78588
|
var init_auth = __esm(() => {
|
|
78589
|
+
init_workspace_selection();
|
|
78590
|
+
init_workspace_profile();
|
|
77880
78591
|
init_source();
|
|
77881
78592
|
init_auth_store();
|
|
77882
78593
|
init_fleet_credentials();
|
|
@@ -77886,80 +78597,51 @@ var init_auth = __esm(() => {
|
|
|
77886
78597
|
CONFIG_HINT_STATUSES = new Set([401, 403, 404, 405, 501]);
|
|
77887
78598
|
});
|
|
77888
78599
|
|
|
77889
|
-
// src/cli/commands/
|
|
77890
|
-
|
|
77891
|
-
|
|
77892
|
-
|
|
77893
|
-
|
|
77894
|
-
|
|
77895
|
-
|
|
77896
|
-
|
|
77897
|
-
|
|
77898
|
-
|
|
77899
|
-
|
|
77900
|
-
|
|
77901
|
-
|
|
77902
|
-
|
|
77903
|
-
|
|
77904
|
-
|
|
77905
|
-
|
|
77906
|
-
|
|
77907
|
-
|
|
77908
|
-
|
|
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("*");
|
|
78600
|
+
// src/cli/commands/workspace-leave.ts
|
|
78601
|
+
function registerWorkspaceLeaveCommand(workspace) {
|
|
78602
|
+
workspace.command("leave <membership-id>").allowExcessArguments(false).description("Leave exactly this membership after fresh verification; saved profiles stay unchanged").requiredOption("--expected-role <role>", "Observed role: owner, admin, member or viewer").requiredOption("--email <email>", "Account email for fresh verification").requiredOption("--confirm", "Confirm losing access through this membership and signing in again").option("--user-id <id>", "Observed user ID; required without a named workspace profile").option("--code-stdin", "Read a previously requested six-digit verification code from stdin").option("--json", "Output the confirmed result as JSON").action(async (membershipId, options) => {
|
|
78603
|
+
try {
|
|
78604
|
+
if (options.confirm !== true)
|
|
78605
|
+
throw new WorkspaceLeaveInputError;
|
|
78606
|
+
const pending = prepareProfileWorkspace("Leave workspace");
|
|
78607
|
+
const target = await pending.resolve();
|
|
78608
|
+
const captured = workspaceLeaveInput(workspaceLeaveProfileContext(membershipId, options.userId, target.context), { expectedRole: options.expectedRole, confirm: true });
|
|
78609
|
+
if (!options.email.includes("@"))
|
|
78610
|
+
throw new NameInputError("Provide the verified account email.");
|
|
78611
|
+
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
78612
|
+
throw new NameInputError("Use --code-stdin with a fresh verification code for noninteractive leave actions.");
|
|
78613
|
+
const client = new RemoteSkillsAuthClient(target.origin);
|
|
78614
|
+
let code;
|
|
78615
|
+
if (options.codeStdin)
|
|
78616
|
+
code = await readCode();
|
|
78617
|
+
else {
|
|
78618
|
+
await client.requestCode(options.email);
|
|
78619
|
+
code = await promptCode();
|
|
77947
78620
|
}
|
|
77948
|
-
|
|
77949
|
-
|
|
77950
|
-
|
|
77951
|
-
|
|
77952
|
-
|
|
77953
|
-
|
|
77954
|
-
|
|
77955
|
-
|
|
77956
|
-
|
|
78621
|
+
if (code === null)
|
|
78622
|
+
return;
|
|
78623
|
+
target.unchanged();
|
|
78624
|
+
const result2 = await client.leaveWorkspace(options.email, code, captured.context, captured.input);
|
|
78625
|
+
if (options.json)
|
|
78626
|
+
console.log(JSON.stringify(result2));
|
|
78627
|
+
else
|
|
78628
|
+
console.log("Workspace membership left. Sign in again to an available workspace. Saved credentials are unchanged; this membership's credentials no longer grant access.");
|
|
78629
|
+
} catch (error2) {
|
|
78630
|
+
const known = error2 instanceof RemoteWorkspaceLeaveError || error2 instanceof RemoteWorkspaceLeaveUnconfirmedError;
|
|
78631
|
+
const message = known || error2 instanceof WorkspaceLeaveInputError || error2 instanceof NameInputError ? error2.message : "Leaving could not be confirmed. Check the selected profile and exact membership, sign in again and inspect available workspaces before another action. Do not retry automatically; saved credentials are unchanged.";
|
|
78632
|
+
if (options.json)
|
|
78633
|
+
console.log(JSON.stringify({ error: message, ...known ? { code: error2.code } : {} }));
|
|
78634
|
+
else
|
|
78635
|
+
console.error(message);
|
|
78636
|
+
process.exitCode = 1;
|
|
78637
|
+
}
|
|
77957
78638
|
});
|
|
77958
78639
|
}
|
|
77959
|
-
var
|
|
77960
|
-
|
|
77961
|
-
|
|
77962
|
-
|
|
78640
|
+
var init_workspace_leave = __esm(() => {
|
|
78641
|
+
init_workspace_profile();
|
|
78642
|
+
init_remote_auth();
|
|
78643
|
+
init_remote_workspace_leave();
|
|
78644
|
+
init_customer_verification();
|
|
77963
78645
|
});
|
|
77964
78646
|
|
|
77965
78647
|
// src/cli/commands/workspace-members.ts
|
|
@@ -77970,7 +78652,8 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
77970
78652
|
throw new NameInputError("Use a roster limit from 1 to 100.");
|
|
77971
78653
|
const page = { limit: options.limit === undefined ? undefined : Number(options.limit), cursor: options.cursor };
|
|
77972
78654
|
workspaceMembersQuery(page);
|
|
77973
|
-
const
|
|
78655
|
+
const pending = prepareProfileWorkspace("List workspace members");
|
|
78656
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
77974
78657
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
77975
78658
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive roster requests.");
|
|
77976
78659
|
let code;
|
|
@@ -77982,16 +78665,18 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
77982
78665
|
}
|
|
77983
78666
|
if (code === null)
|
|
77984
78667
|
return;
|
|
77985
|
-
const
|
|
78668
|
+
const target = await pending.resolve();
|
|
78669
|
+
target.unchanged();
|
|
78670
|
+
const result2 = await client.listWorkspaceMembers(options.email, code, page, target.context);
|
|
77986
78671
|
if (options.json)
|
|
77987
78672
|
console.log(JSON.stringify(result2));
|
|
77988
78673
|
else {
|
|
77989
|
-
const
|
|
78674
|
+
const text2 = (value) => value.replace(/[\p{Cc}\p{Cs}\u2028\u2029]/gu, " ");
|
|
77990
78675
|
console.log(`Workspace: ${result2.organizationId}`);
|
|
77991
78676
|
if (!result2.members.length)
|
|
77992
78677
|
console.log("No members in this page.");
|
|
77993
78678
|
for (const member of result2.members)
|
|
77994
|
-
console.log(`${
|
|
78679
|
+
console.log(`${text2(member.email)} ${member.role} ${text2(member.displayName ?? "")} ${member.membershipId} ${member.createdAt}`);
|
|
77995
78680
|
if (result2.nextCursor !== null)
|
|
77996
78681
|
console.log(`Next cursor: ${result2.nextCursor}`);
|
|
77997
78682
|
}
|
|
@@ -78007,7 +78692,7 @@ function registerWorkspaceMembersCommand(workspace) {
|
|
|
78007
78692
|
});
|
|
78008
78693
|
}
|
|
78009
78694
|
var init_workspace_members = __esm(() => {
|
|
78010
|
-
|
|
78695
|
+
init_workspace_profile();
|
|
78011
78696
|
init_remote_auth();
|
|
78012
78697
|
init_remote_workspace();
|
|
78013
78698
|
init_customer_verification();
|
|
@@ -78023,7 +78708,8 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78023
78708
|
command.action(async (membershipId, options) => {
|
|
78024
78709
|
try {
|
|
78025
78710
|
const captured = action === "role" ? { kind: "role", ...workspaceMemberRoleInput(membershipId, { role: options.role, expectedRole: options.expectedRole }) } : { kind: "remove", ...workspaceMemberRemovalInput(membershipId, { expectedRole: options.expectedRole }) };
|
|
78026
|
-
const
|
|
78711
|
+
const pending = prepareProfileWorkspace("Manage workspace member");
|
|
78712
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
78027
78713
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
78028
78714
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive member actions.");
|
|
78029
78715
|
let code;
|
|
@@ -78035,14 +78721,16 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78035
78721
|
}
|
|
78036
78722
|
if (code === null)
|
|
78037
78723
|
return;
|
|
78724
|
+
const target = await pending.resolve();
|
|
78725
|
+
target.unchanged();
|
|
78038
78726
|
if (captured.kind === "role") {
|
|
78039
|
-
const result2 = await client.setWorkspaceMemberRole(options.email, code, captured.membershipId, captured.body);
|
|
78727
|
+
const result2 = await client.setWorkspaceMemberRole(options.email, code, captured.membershipId, captured.body, target.context);
|
|
78040
78728
|
if (options.json)
|
|
78041
78729
|
console.log(JSON.stringify(result2));
|
|
78042
78730
|
else
|
|
78043
78731
|
console.log(result2.changed ? `Member role changed to ${result2.member.role}.` : `Member already has role ${result2.member.role}.`);
|
|
78044
78732
|
} else {
|
|
78045
|
-
const result2 = await client.removeWorkspaceMember(options.email, code, captured.membershipId, captured.body);
|
|
78733
|
+
const result2 = await client.removeWorkspaceMember(options.email, code, captured.membershipId, captured.body, target.context);
|
|
78046
78734
|
if (options.json)
|
|
78047
78735
|
console.log(JSON.stringify(result2));
|
|
78048
78736
|
else
|
|
@@ -78062,7 +78750,7 @@ function registerWorkspaceMemberMutationCommands(workspace) {
|
|
|
78062
78750
|
}
|
|
78063
78751
|
}
|
|
78064
78752
|
var init_workspace_member_mutations = __esm(() => {
|
|
78065
|
-
|
|
78753
|
+
init_workspace_profile();
|
|
78066
78754
|
init_remote_auth();
|
|
78067
78755
|
init_remote_client();
|
|
78068
78756
|
init_remote_workspace();
|
|
@@ -78077,8 +78765,10 @@ __export(exports_customer_profile, {
|
|
|
78077
78765
|
function registerCustomerProfileCommands(program2) {
|
|
78078
78766
|
const account = program2.command("account").description("Manage your account on the selected Skills server");
|
|
78079
78767
|
const workspace = program2.command("workspace").description("Manage the current workspace on the selected Skills server");
|
|
78768
|
+
registerWorkspaceListCommand(workspace);
|
|
78080
78769
|
registerWorkspaceMembersCommand(workspace);
|
|
78081
78770
|
registerWorkspaceMemberMutationCommands(workspace);
|
|
78771
|
+
registerWorkspaceLeaveCommand(workspace);
|
|
78082
78772
|
const commands = [
|
|
78083
78773
|
{ kind: "account", command: account.command("update") },
|
|
78084
78774
|
{ kind: "workspace", command: workspace.command("update") }
|
|
@@ -78086,7 +78776,8 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78086
78776
|
for (const { kind, command } of commands) {
|
|
78087
78777
|
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
78778
|
try {
|
|
78089
|
-
const
|
|
78779
|
+
const pending = prepareProfileWorkspace(`Update ${kind} name`);
|
|
78780
|
+
const client = new RemoteSkillsAuthClient(pending.origin);
|
|
78090
78781
|
customerNamePatch(kind === "account" ? { displayName: options.displayName } : { name: options.name }, kind === "account" ? "displayName" : "name");
|
|
78091
78782
|
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY)) {
|
|
78092
78783
|
throw new NameInputError("Use --code-stdin with a fresh verification code for JSON or noninteractive updates.");
|
|
@@ -78100,7 +78791,9 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78100
78791
|
}
|
|
78101
78792
|
if (code === null)
|
|
78102
78793
|
return;
|
|
78103
|
-
const
|
|
78794
|
+
const target = await pending.resolve();
|
|
78795
|
+
target.unchanged();
|
|
78796
|
+
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
78797
|
if (options.json)
|
|
78105
78798
|
console.log(JSON.stringify(result2));
|
|
78106
78799
|
else
|
|
@@ -78118,9 +78811,11 @@ function registerCustomerProfileCommands(program2) {
|
|
|
78118
78811
|
}
|
|
78119
78812
|
}
|
|
78120
78813
|
var init_customer_profile = __esm(() => {
|
|
78121
|
-
|
|
78814
|
+
init_workspace_profile();
|
|
78815
|
+
init_workspace_selection();
|
|
78122
78816
|
init_remote_auth();
|
|
78123
78817
|
init_customer_verification();
|
|
78818
|
+
init_workspace_leave();
|
|
78124
78819
|
init_workspace_members();
|
|
78125
78820
|
init_workspace_member_mutations();
|
|
78126
78821
|
});
|
|
@@ -78265,8 +78960,8 @@ var init_storage = __esm(() => {
|
|
|
78265
78960
|
});
|
|
78266
78961
|
|
|
78267
78962
|
// src/lib/registry-reconcile.ts
|
|
78268
|
-
import { existsSync as existsSync33, readFileSync as
|
|
78269
|
-
import { join as
|
|
78963
|
+
import { existsSync as existsSync33, readFileSync as readFileSync31, statSync as statSync20, writeFileSync as writeFileSync20 } from "fs";
|
|
78964
|
+
import { join as join39 } from "path";
|
|
78270
78965
|
function isDirectory2(path) {
|
|
78271
78966
|
try {
|
|
78272
78967
|
return statSync20(path).isDirectory();
|
|
@@ -78277,15 +78972,15 @@ function isDirectory2(path) {
|
|
|
78277
78972
|
function migrationNeeded(options) {
|
|
78278
78973
|
if (options.rootDir)
|
|
78279
78974
|
return false;
|
|
78280
|
-
const appDir = options.homeDir ?
|
|
78281
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
78975
|
+
const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
78976
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join39(appDir, SKILLS_CACHE_DIRNAME)));
|
|
78282
78977
|
}
|
|
78283
78978
|
function readBaseline(skillDir) {
|
|
78284
|
-
const markerPath =
|
|
78979
|
+
const markerPath = join39(skillDir, PULL_MARKER_FILE);
|
|
78285
78980
|
if (!existsSync33(markerPath))
|
|
78286
78981
|
return;
|
|
78287
78982
|
try {
|
|
78288
|
-
const marker = JSON.parse(
|
|
78983
|
+
const marker = JSON.parse(readFileSync31(markerPath, "utf-8"));
|
|
78289
78984
|
if (!isSkillsOwnershipMarker(marker))
|
|
78290
78985
|
return;
|
|
78291
78986
|
return {
|
|
@@ -78297,11 +78992,11 @@ function readBaseline(skillDir) {
|
|
|
78297
78992
|
}
|
|
78298
78993
|
}
|
|
78299
78994
|
function readCursor(root) {
|
|
78300
|
-
const path =
|
|
78995
|
+
const path = join39(root, SYNC_CURSOR_FILE);
|
|
78301
78996
|
if (!existsSync33(path))
|
|
78302
78997
|
return { runCount: 0 };
|
|
78303
78998
|
try {
|
|
78304
|
-
const cursor2 = JSON.parse(
|
|
78999
|
+
const cursor2 = JSON.parse(readFileSync31(path, "utf-8"));
|
|
78305
79000
|
return { runCount: typeof cursor2.runCount === "number" ? cursor2.runCount : 0 };
|
|
78306
79001
|
} catch {
|
|
78307
79002
|
return { runCount: 0 };
|
|
@@ -78310,21 +79005,21 @@ function readCursor(root) {
|
|
|
78310
79005
|
function resolveCorpusRootReadOnly(options) {
|
|
78311
79006
|
if (options.rootDir)
|
|
78312
79007
|
return { root: options.rootDir, migrationPending: false };
|
|
78313
|
-
const appDir = options.homeDir ?
|
|
78314
|
-
const cache3 =
|
|
79008
|
+
const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
79009
|
+
const cache3 = join39(appDir, SKILLS_CACHE_DIRNAME);
|
|
78315
79010
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
78316
79011
|
return { root: cache3, migrationPending: false };
|
|
78317
79012
|
}
|
|
78318
|
-
return { root:
|
|
79013
|
+
return { root: join39(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
78319
79014
|
}
|
|
78320
|
-
function remoteRowToSkill(
|
|
78321
|
-
const slug = typeof
|
|
79015
|
+
function remoteRowToSkill(record5) {
|
|
79016
|
+
const slug = typeof record5.slug === "string" ? record5.slug : typeof record5.name === "string" ? record5.name : undefined;
|
|
78322
79017
|
if (!slug)
|
|
78323
79018
|
return;
|
|
78324
79019
|
return {
|
|
78325
79020
|
slug,
|
|
78326
|
-
version: typeof
|
|
78327
|
-
sha256: typeof
|
|
79021
|
+
version: typeof record5.version === "string" ? record5.version : undefined,
|
|
79022
|
+
sha256: typeof record5.bundleSha256 === "string" && record5.bundleSha256 ? record5.bundleSha256 : undefined
|
|
78328
79023
|
};
|
|
78329
79024
|
}
|
|
78330
79025
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
@@ -78449,7 +79144,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78449
79144
|
for (const slug of allSlugs) {
|
|
78450
79145
|
const local = locals.get(slug);
|
|
78451
79146
|
const remote = remotes.get(slug);
|
|
78452
|
-
const baseline = local ? readBaseline(
|
|
79147
|
+
const baseline = local ? readBaseline(join39(root, slug)) : undefined;
|
|
78453
79148
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
78454
79149
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
78455
79150
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -78508,7 +79203,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78508
79203
|
try {
|
|
78509
79204
|
await pushSkill(slug, { rootDir: root, client });
|
|
78510
79205
|
const pushed = locals.get(slug);
|
|
78511
|
-
writePullMarker(
|
|
79206
|
+
writePullMarker(join39(root, slug), {
|
|
78512
79207
|
skill: slug,
|
|
78513
79208
|
...pushed?.version ? { version: pushed.version } : {},
|
|
78514
79209
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -78580,7 +79275,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
78580
79275
|
runCount: readCursor(root).runCount + 1,
|
|
78581
79276
|
summary
|
|
78582
79277
|
};
|
|
78583
|
-
|
|
79278
|
+
writeFileSync20(join39(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
78584
79279
|
`);
|
|
78585
79280
|
return {
|
|
78586
79281
|
corpusRoot: root,
|